package ocp-index

  1. Overview
  2. Docs

Source file dunextract.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
(**************************************************************************)
(*                                                                        *)
(*  Copyright 2021 OCamlPro                                               *)
(*                                                                        *)
(*  All rights reserved.  This file is distributed under the terms of     *)
(*  the Lesser GNU Public License version 3.0.                            *)
(*                                                                        *)
(*  This software is distributed in the hope that it will be useful,      *)
(*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *)
(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *)
(*  Lesser GNU General Public License for more details.                   *)
(*                                                                        *)
(**************************************************************************)

type sexp = A of string | T of sexp list

let atom str i =
  let rec escaped j =
    if j >= String.length str then j
    else match str.[j] with
      | '"' -> j+1
      | '\\' -> escaped (j+2)
      | _ -> escaped (j+1)
  in
  let rec unescaped j =
    if j >= String.length str then j
    else match str.[j] with
    | ' ' | '\n' | '\t' | '\r' | '(' | ')' -> j
    | '\\' -> unescaped (j+2)
    | _ -> unescaped (j+1)
  in
  let j = match str.[i] with
    | '"' -> escaped (i+1)
    | _ -> unescaped (i+1)
  in
  j, String.sub str i (j - i)

let rec sexp_parse str i =
  if i >= String.length str then i, []
  else
    match str.[i] with
    | ' ' | '\n' | '\t' | '\r' -> sexp_parse str (i+1)
    | '(' ->
        let i, t1 = sexp_parse str (i+1) in
        let i, t = sexp_parse str i in
        i, T t1 :: t
    | ')' -> i+1, []
    | ';' ->
        let i =
          try String.index_from str (i+1) '\n' + 1
          with Not_found -> String.length str
        in
        sexp_parse str i
    | _ ->
        let i, a = atom str i in
        let i, t = sexp_parse str i in
        i, A a :: t

let rec cut_list a acc = function
  | x :: r -> if x = a then acc, r else cut_list a (x::acc) r
  | [] -> acc, []

let module_eq name = function
  | A n -> IndexMisc.capitalize n = name
  | _ -> false

let list_find_opt f l = try Some (List.find f l) with Not_found -> None

let rec get_lib_name modname = function
  | T (A "library" :: t) :: r ->
      if List.mem (T [A "wrapped"; A "false"]) t then get_lib_name modname r
      else
        let libname =
          match
            list_find_opt (function T (A "name" :: _) -> true | _ -> false) t
          with
          | Some (T [_; A name]) -> name
          | _ ->
              match
                list_find_opt
                  (function T (A "public_name" :: _) -> true | _ -> false) t
              with
              | Some (T [_; A name]) ->
                  List.hd (List.rev (IndexMisc.string_split '.' name))
              | _ -> ""
        in
        (match
           list_find_opt (function T ( A "modules" :: _) -> true | _ -> false) t
         with
         | None -> Some libname
         | Some (T (_ :: ms)) ->
             let inc, exc = cut_list (A "\\") [] ms in
             if not (List.exists (module_eq modname) exc) &&
                List.exists (fun n -> module_eq modname n || n = A ":standard")
                  inc
             then Some libname
             else get_lib_name modname r
         | Some _ -> assert false)
  | _ :: r -> get_lib_name modname r
  | [] -> None

let string_of_channel ic =
  let n = 4096 in
  let s = Bytes.create n in
  let b = Buffer.create 1024 in
  let rec iter ic b s =
    let nread =
      try input ic s 0 n
      with End_of_file -> 0 in
    if nread > 0 then (
      Buffer.add_subbytes b s 0 nread;
      iter ic b s
    ) in
  iter ic b s;
  Buffer.contents b

let read_dune dir =
  try
    let ic = open_in (Filename.concat dir "dune") in
    let s = string_of_channel ic in
    let r = sexp_parse s 0 in
    close_in ic;
    Some r
  with Sys_error _ -> None

let rm_ext f = try Filename.chop_extension f with Invalid_argument _ -> f

let get_libname file =
  let modname =
    IndexMisc.capitalize (Filename.(basename (rm_ext file)))
  in
  match read_dune (Filename.dirname file) with
  | Some (_, sexp) -> get_lib_name modname sexp
  | None -> None
OCaml

Innovation. Community. Security.