This file is indexed.

/usr/share/doc/mlton/cm2mlb/cm2mlb.sml is in mlton-doc 20100608-5.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  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
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
(*
 * Author: Matthew Fluet (mfluet@acm.org) 
 *
 * This requires that you have SML/NJ installed.
 * It works with SML/NJ 110.47 and may require changes to work with other
 * versions, since it depends on the CM structure.
 *
 * cm2mlb takes a ".cm" file and prints on stdout a corresponding ".mlb".
 *
 * To use from the REPL, do the following:
 * CM2MLB.cm2mlb {defines = ["MLton"],
 *                maps = [],
 *                sources = "sources.cm",
 *                out = TextIO.stdOut}
 *
 * Before using from the shell, you must do the following, where <smlnj> is
 * the root directory of the SML/NJ installation.  You may need to be root in
 * order to do these.
 * 1. From the SML/NJ REPL:
 *      CM.make "cm2mlb.cm";
 *      CM2MLB.export ();
 * 2. ln -s <smlnj>/bin/.run-sml <smlnj>/bin/cm2mlb
 * 3. mv cm2mlb.x86-linux <smlnj>/bin/.heap
 *
 * Once it is installed, the usage is as follows:
 *   cm2mlb [-Dsym ...] [-map file] sources.cm
 *
 * -Dsym can be used to define CM preprocessor symbols.
 * -map file can be used to add cm2mlb mappings.
 *)

structure CM2MLB :
sig
   val cm2mlb : {defines: string list,
                 maps: string list,
                 out: TextIO.outstream,
                 sources: string} -> unit
   val main: string * string list -> OS.Process.status
   val export : unit -> unit
end =
struct
   structure PG = PortableGraph

   fun message s = TextIO.output (TextIO.stdErr, s ^ "\n")
   fun die msg =
      (message ("Error: " ^ msg)
       ; OS.Process.exit OS.Process.failure)

   structure CM =
      struct
         open CM

         structure Graph =
            struct
               val graph = fn src =>
                  (Graph.graph src)
                  handle _ => NONE
            end
      end

   structure AnchorMap =
      struct

         fun make (file : string) =
            if OS.FileSys.access (file, [OS.FileSys.A_READ])
               then 
                  let
                     val lines =
                        let
                           val f = TextIO.openIn file
                        in
                           let
                              fun loop lines =
                                 case TextIO.inputLine f of
                                    NONE => List.rev lines
                                  | SOME l => loop (l::lines)
                           in
                              loop []
                              before TextIO.closeIn f
                           end handle e => (TextIO.closeIn f; raise e)
                        end handle _ => []
                  in
                     List.mapPartial
                     (fn line =>
                      if CharVector.all Char.isSpace line
                         then NONE
                         else 
                            case String.tokens Char.isSpace line of
                               [cmAnchor, mlbPath] => 
                                  SOME {cmAnchor = cmAnchor, mlbPath = mlbPath}
                             | _ =>  die (concat ["strange cm->mlb mapping: ", 
                                                  file, ":: ", line]))
                     lines
                  end
               else []

         val default = make "cm2mlb-map"
      end

   fun cm2mlb {defines, maps, out, sources} =
      let
         (* Define preprocessor symbols *)
         val _ = 
            List.app 
            (fn sym => (#set (CM.symval sym)) (SOME 1))
            defines
         val _ = (#set CM.Control.verbose) false
         val _ = (#set CM.Control.warn_obsolete) false
         val _ = Control.printWarnings := false

         val _ =
            if OS.FileSys.access (sources, [OS.FileSys.A_READ])
               then ()
               else die (concat ["file not found: ", sources])
         val {dir, file = sources} = OS.Path.splitDirFile sources
         val () = if dir <> "" then OS.FileSys.chDir dir else ()

         local
            val anchorMap =
               List.concat
               ((List.map AnchorMap.make maps) @
                [AnchorMap.default])

            fun peekAnchorMap cmAnchor' =
               case List.find (fn {cmAnchor, ...} => cmAnchor = cmAnchor') anchorMap of
                  NONE => NONE
                | SOME {mlbPath, ...} => SOME mlbPath
         in
            val peekAnchorMap = peekAnchorMap
         end
      in
         case CM.Graph.graph sources of
            SOME {graph as PG.GRAPH {imports, ...}, imports = importLibs, nativesrc} =>
               let
                  val imports =
                     ListPair.map
                     (fn (bid, cmLib) =>
                      let
                         val cmLibDescr = CM.Library.descr cmLib
                         val cmLibOSString = CM.Library.osstring cmLib

                         fun mlbLibDef () =
                            let
                               val {base, ext} = OS.Path.splitBaseExt cmLibOSString
                               val mlbLib = OS.Path.joinBaseExt {base = base, ext = SOME "mlb"}
                            in
                               mlbLib
                            end

                         fun doitAnchoredPath arcs =
                            let
                               fun loop (prefix, suffix) =
                                  if List.null prefix 
                                     then concat ["(* ", cmLibDescr, " =??=> *) ", mlbLibDef ()]
                                     else case peekAnchorMap (String.concatWith "/" (List.rev prefix)) of
                                             SOME mlbPath =>
                                                concat ["(* ", cmLibDescr, " ====> *) ", mlbPath ^ suffix]
                                           | NONE =>
                                                let
                                                   val suffix =
                                                      if suffix = ""
                                                         then OS.Path.joinBaseExt
                                                              {base = #base (OS.Path.splitBaseExt (List.hd prefix)),
                                                               ext = SOME "mlb"}
                                                         else (List.hd prefix) ^ suffix
                                                in
                                                   loop (List.tl prefix, "/" ^ suffix)
                                                end
                            in
                               loop (List.rev arcs, "")
                            end

                         val mlbLib =
                            if String.sub (cmLibDescr, 0) = #"$"
                               then case String.fields (fn #"/" => true | _ => false) cmLibDescr of
                                       "$" :: (arcs as (arc0 :: _)) => 
                                          doitAnchoredPath (("$" ^ arc0) :: arcs)
                                     | arc0 :: arcs =>
                                          let
                                             val arc0 =
                                                case CharVector.findi (fn (_, #"(") => true | _ => false) arc0 of
                                                   SOME (i, _) => 
                                                      String.extract (arc0, i + 2, SOME (String.size arc0 - i - 3))
                                                 | NONE => arc0
                                          in 
                                             doitAnchoredPath (arc0 :: arcs)
                                          end
                                     | arcs => doitAnchoredPath arcs
                               else concat ["(* ", cmLibOSString, " ===> *) ", mlbLibDef ()]
                      in
                         concat 
                         ["  basis ", bid, " = \n",
                          "    bas\n",
                          "      ", mlbLib, "\n",
                          "    end\n"]
                      end)
                     (imports, importLibs)
               in
                  TextIO.output (out, "local\n");
                  List.app (fn s => TextIO.output (out, s)) imports;
                  TextIO.output (out, "in\n");
                  GenMLB.gen {graph = graph,
                              nativesrc = nativesrc,
                              importprefix = fn _ => "",
                              exportprefix = "",
                              outstream = out};
                  TextIO.output (out, "end\n")
               end
          | NONE => die ("CM.Graph.graph " ^ sources ^ " failed") 
      end

   fun usage msg =
      (message "Usage: cm2mlb [-Dsym ...] [-map file] sources.cm"
       ; die msg)

   fun main (_, args) =
      let
         val defines = ref ["MLton"]
         val maps = ref []
         fun loop args = 
            case args of
               [file] =>
                  cm2mlb {defines = !defines,
                          maps = !maps,
                          out = TextIO.stdOut,
                          sources = file}
             | flag :: args =>
                  if String.isPrefix "-D" flag
                     then
                        (defines := String.extract (flag, 2, NONE) :: !defines
                         ; loop args)
                  else if "-map" = flag
                     then case args of
                            file :: args => (maps := file :: !maps
                                             ; loop args)
                          | _ => usage "missing map file"
                  else usage (String.concat ["invalid flag ", flag])
             | _ => usage "wrong number of arguments"
      in
         loop args handle e => die (concat ["cm2mlb failed: ", General.exnMessage e])
         ; OS.Process.success
      end

   fun export () =
      SMLofNJ.exportFn
      ("cm2mlb", main)
end