package ocp-ocamlres

  1. Overview
  2. Docs

Source file oCamlResRegistry.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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
(* Registration of (sub)formats for use from the command line *)

(* This file is part of ocp-ocamlres - formats & subformats registry
 * (C) 2013 OCamlPro - Benjamin CANOU
 *
 * ocp-ocamlres is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3.0 of the License, or (at your option) any later
 * version, with linking exception.
 *
 * ocp-ocamlres 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 LICENSE file for more details *)

open OCamlResFormats
open OCamlResSubFormats

module SM = Map.Make (String)

(*-- Formats registry ---------------------------------------------*)

module type Format = sig
  val output : string OCamlRes.Res.root -> unit
  val info : string
  val options : (Arg.key * Arg.spec * Arg.doc) list
end

let formats : (module Format) SM.t ref = ref SM.empty

let register_format name (format : (module Format)) =
  formats := SM.add name format !formats

let find_format name : (module Format) = SM.find name !formats

let formats () = !formats

(*-- SubFormats registry ------------------------------------------*)

module type SubFormat = sig
  include SubFormat
  val info : string
  val options : (Arg.key * Arg.spec * Arg.doc) list
end

let subformats : (module SubFormat) SM.t ref = ref SM.empty

let register_subformat name m =
  let module M = (val m : SubFormat) in
  subformats := SM.add name m !subformats

let find_subformat name = SM.find name !subformats

let subformats () = !subformats

(*-- Predefined Subformats -----------------------------------------*)

module Raw = struct
  include OCamlResSubFormats.Raw
  let info = "raw file contents as a string"
  let options = []
end

module Int = struct
  include OCamlResSubFormats.Int
  let info = "for files containing only an integer"
  let options = []
end

module Lines = struct
  include OCamlResSubFormats.Lines
  let info = "splits the input into lines"
  let options = []
end

let _ =
  register_subformat "raw" (module Raw : SubFormat) ;
  register_subformat "int" (module Int : SubFormat);
  register_subformat "lines" (module Lines : SubFormat)

(*-- Predefined Formats -------------------------------------------*)

module PredefOptions = struct
  let width = ref 80
  let subformats = ref SM.empty
  let output_file = ref None
  let add_ext, add_mod =
    (* ugly hackery to work around Arg,Tuple's behaviour *)
    let r_ext = ref None and r_mod = ref None in
    let update () =
      match !r_ext, !r_mod with
      | None, _ | _, None -> ()
      | Some e, Some r ->
        r_ext := None ;
        r_mod := None ;
        try
          subformats := SM.add e (find_subformat r) !subformats
        with Not_found ->
          Printf.eprintf "Subformat %s not found.\n%!" r ;
          exit 1
    in
    ((fun e -> r_ext := Some e ; update ()),
     (fun m -> r_mod := Some m ; update ()))

  let options =
    [ "-width", Arg.Set_int width,
      "set the maximum chars per line of generated code" ;
      "-subformat", Arg.(Tuple [ String add_ext ; String add_mod ]),
      "\"ext\" \"subformat\"&\
       preprocess files ending by \"ext\" with \"subformat\"" ;
      "-o", Arg.String (fun f -> output_file := Some f),
      "\"file name\"&\
       print in a file instead of stdout"]
end

module ExtensionDispatcherSubFormat = struct
  let find_subformat (dirs, name) =
    (try match name with
       | Some (name, Some ext) -> SM.find ext !PredefOptions.subformats
       | _ -> raise Not_found
     with Not_found -> (module Raw))

  type t = string
  let from_raw path data = data
  let to_raw path data = data

  let pprint path data =
    let module SF = (val find_subformat path) in
    SF.pprint path (SF.from_raw path data)
  let pprint_header path data =
    let module SF = (val find_subformat path) in
    SF.pprint_footer path (SF.from_raw path data)
  let pprint_footer path data =
    let module SF = (val find_subformat path) in
    SF.pprint_footer path (SF.from_raw path data)

  let name path data =
    let module SF = (val find_subformat path) in
    SF.name path (SF.from_raw path data)
  let type_name path data =
    let module SF = (val find_subformat path) in
    SF.type_name path (SF.from_raw path data)
  let mod_name path data =
    let module SF = (val find_subformat path) in
    SF.mod_name path (SF.from_raw path data)
end

let disclaimer = "(* This file has been generated by ocp-ocamlres *)\n"

module OCaml = struct
  module F = OCamlResFormats.OCaml (ExtensionDispatcherSubFormat)
  let options = PredefOptions.options
  let info = "produces static ocaml bindings (modules for dirs, values for files)"
  let output root =
    match !PredefOptions.output_file with
    | None ->
      let out_channel = stdout in
      let params = F.({ width = !PredefOptions.width ; out_channel }) in
      F.output params root
    | Some fn ->
      let out_channel = open_out fn in
      let params = F.({ width = !PredefOptions.width ; out_channel }) in
      output_string out_channel disclaimer ;
      F.output params root ;
      close_out out_channel
end

module Tree (Params : sig val variants : bool val info : string end) = struct
  let use_variants = ref true
  module F = OCamlResFormats.Res (ExtensionDispatcherSubFormat)
  let options =
    PredefOptions.options
    @ [ "-no-variants", Arg.Clear use_variants,
        "use a plain sum type instead of polymorphic variants" ;]
  let info = Params.info
  let output root =
    let use_variants_for_leaves = !use_variants
    and use_variants_for_nodes = Params.variants
    and width = !PredefOptions.width in
    match !PredefOptions.output_file with
    | None ->
      let out_channel = stdout in
      let params = F.({ width ; out_channel ;
                        use_variants_for_nodes ;
                        use_variants_for_leaves }) in
      F.output params root
    | Some fn ->
      let out_channel = open_out fn in
      let params = F.({ width ; out_channel ;
                        use_variants_for_nodes ;
                        use_variants_for_leaves }) in
      output_string out_channel disclaimer ;
      F.output params root ;
      close_out out_channel
end

module Res = Tree (struct
    let variants = false
    let info = "produces the OCaml source representation \
                of the OCamlRes tree"
  end)

module Variants = Tree (struct
    let variants = true
    let info = "produces the OCaml source representation \
                of the resource tree using polymorphic variant type\n\
                ([ `File of (* depends *) | `Dir of 'a list ] as 'a)"
  end)

module Files = struct
  module F = OCamlResFormats.Files (OCamlResSubFormats.Raw)
  let base_output_dir = ref "."
  let info = "reproduces the original files"
  let options = [
    "-output-dir", Arg.Set_string base_output_dir,
    "\"dir\"&set the base output directory (defaults to \".\")"]
  let output root =
    let params = F.({ base_output_dir = !base_output_dir }) in
    F.output params root
end

let _ =
  register_format "ocaml" (module OCaml : Format) ;
  register_format "ocamlres" (module Res : Format) ;
  register_format "variants" (module Variants : Format) ;
  register_format "files" (module Files : Format)
OCaml

Innovation. Community. Security.