2 * Dynamic web page generation
with Standard ML
3 * Copyright (C
) 2003 Adam Chlipala
5 * This library is free software
; you can redistribute it
and/or
6 * modify it under the terms
of the GNU Lesser General Public
7 * License
as published by the Free Software Foundation
; either
8 * version
2.1 of the License
, or (at your option
) any later version
.
10 * This library is distributed
in the hope that it will be useful
,
11 * but WITHOUT ANY WARRANTY
; without even the implied warranty
of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE
. See the GNU
13 * Lesser General Public License for more details
.
15 * You should have received a copy
of the GNU Lesser General Public
16 * License along
with this library
; if not
, write to the Free Software
17 * Foundation
, Inc
., 59 Temple Place
, Suite
330, Boston
, MA
02111-1307 USA
20 (* Common convenience stuff to
open in several places
*)
25 exception Format
of string
27 fun error (pos
, msg
) = (ErrorMsg
.error pos msg
;
30 fun error
' (pos
, msg
) = ErrorMsg
.error pos msg
32 type 'a map
= 'a StringMap
.map
34 val insert
= StringMap
.insert
35 fun contains x
= isSome (StringMap
.find x
)
37 fun lookup (D
, v
, pos
) =
38 (case StringMap
.find (D
, v
) of
39 NONE
=> error (pos
, "Unbound tycon " ^ v
)
42 type 'a nmap
= 'a IntBinaryMap
.map
44 val ninsert
= IntBinaryMap
.insert
45 fun ncontains x
= isSome (IntBinaryMap
.find x
)
47 fun nlookup (D
, v
, pos
) =
48 (case IntBinaryMap
.find (D
, v
) of
49 NONE
=> error (pos
, "BAD: Unbound tyname or tvname " ^
Int.toString v
)
54 fun indexAfter (str
, i
, ch
) =
60 else if String.sub(str
, i
) = ch
then
68 fun indexDoubleAfter (str
, i
, ch
) =
74 else if String.sub(str
, i
) = ch
andalso String.sub(str
, i
+1) = ch
then
82 fun index (str
, ch
) = indexAfter (str
, 0, ch
)
84 fun strLower str
= String.implode (map
Char.toLower (String.explode str
))
91 if Char.isSpace ch
then
97 String.implode (rev (killFront (rev (killFront (String.explode str
)))))
100 fun copyFile (src
, dst
) =
105 val inf
= TextIO.openIn src
106 val outf
= TextIO.openOut dst
109 (case TextIO.inputLine inf
of
111 | SOME line
=> (TextIO.output (outf
, line
);
119 fun writeToFile (fname
, txt
) =
121 val outf
= TextIO.openOut fname
123 TextIO.output (outf
, txt
);
127 fun readFromFile fname
=
129 val inf
= TextIO.openIn fname
131 (case TextIO.inputLine inf
of
132 NONE
=> String.concat (rev acc
)
133 | SOME line
=> read (line
::acc
))
136 before TextIO.closeIn inf
140 fun listToString (f
, F
, L
) [] = ""
141 |
listToString (f
, F
, L
) [id
] = F ^ f id ^ L
142 |
listToString (f
, F
, L
) (h
::t
) = foldl (fn (id
, s
) => s ^
", " ^ f id
) (F ^ f h
) t ^ L
144 fun idListToString (F
, L
) list
= listToString (fn x
=> x
, F
, L
) list
146 val stringListToString
= idListToString ("[", "]")
150 fun decode (L
, acc
) =
152 [] => String.implode (rev acc
)
153 | #
"+"::L
=> decode (L
, #
" "::acc
)
155 (case StringCvt.scanString (Int.scan
StringCvt.HEX
) (str MS ^ str LS
) of
156 NONE
=> decode (L
, LS
::MS
:: #
"%"::acc
)
157 | SOME n
=> decode (L
, chr n
:: acc
))
158 | ch
::L
=> decode (L
, ch
::acc
))
160 decode (String.explode s
, [])
172 if Char.isAlphaNum ch
orelse ch
= #
"_" orelse ch
= #
"." orelse ch
= #
"-" then
174 else if ch
= #
" " then
177 "%" ^
pad (Int.fmt
StringCvt.HEX (ord ch
), 2)
179 String.concat (map
xch (String.explode s
))
182 fun stoiOpt s
= Int.fromString s
184 (case Int.fromString s
of
185 NONE
=> raise Format s
189 "-" ^
Int.toString (~n
)
193 fun storOpt s
= Real.fromString s
195 (case Real.fromString s
of
196 NONE
=> raise Format s
200 "-" ^
Real.toString (~r
)
206 fun xch #
"<" = "<"
209 | xch #
"\"" = """
212 foldr
op^
"" (map
xch (String.explode s
))
217 fun xch #
"<" = "<"
220 | xch #
"\"" = """
221 | xch #
"\n" = "<br />"
224 foldr
op^
"" (map
xch (String.explode s
))
227 fun killLf s
= String.implode (List.filter (fn ch
=> ch
<> #
"\r") (String.explode s
))