2 Domtool (http
://hcoop
.sf
.net
/)
3 Copyright (C
) 2004 Adam Chlipala
5 This program is free software
; you can redistribute it
and/or
6 modify it under the terms
of the GNU General Public License
7 as published by the Free Software Foundation
; either version
2
8 of the License
, or (at your option
) any later version
.
10 This program 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
13 GNU General Public License for more details
.
15 You should have received a copy
of the GNU General Public License
16 along
with this program
; if not
, write to the Free Software
17 Foundation
, Inc
., 59 Temple Place
- Suite
330, Boston
, MA
02111-1307, USA
.
20 (* Utility functions
*)
22 structure Util
:> UTIL
=
24 fun impLoop next stop body init
=
33 loop (body (v
, state
))
39 fun ioOptLoop next body init
=
44 | SOME v
=> loop (body (v
, state
))
49 fun ioOptLoopFold next body init
=
54 | SOME v
=> loop (body (v
, state
))
59 fun isIdent ch
= Char.isLower ch
orelse Char.isDigit ch
61 fun isInt s
= Int.fromString s
<> NONE
64 case Int.fromString s
of
68 fun chop s
= String.substring (s
, 0, size s
- 1)
71 size s
> 0 andalso size s
< 20 andalso CharVector
.all (fn ch
=> isIdent ch
orelse ch
= #
"-") s
73 fun validVhostFilename s
=
74 case String.fields (fn ch
=> ch
= #
".") s
of
76 |
[s
, "ssl"] => validHost s
80 size s
> 0 andalso size s
< 100 andalso List.all
validHost (String.fields (fn ch
=> ch
= #
".") s
)
83 case String.fields (fn ch
=> ch
= #
"_") s
of
86 (validHost host
andalso case String.tokens (fn ch
=> ch
= #
".") rest
of
87 "ssl" :: rest
=> List.all validHost rest
92 size s
> 0 andalso size s
< 50 andalso CharVector
.all
93 (fn ch
=> isIdent ch
orelse ch
= #
"." orelse ch
= #
"_" orelse ch
= #
"-" orelse ch
= #
"+")
96 fun validEmailUser s
=
97 size s
> 0 andalso size s
< 50 andalso CharVector
.all
98 (fn ch
=> Char.isAlphaNum ch
orelse ch
= #
"." orelse ch
= #
"_" orelse ch
= #
"-" orelse ch
= #
"+")
101 (case String.fields (fn ch
=> ch
= #
"@") s
of
102 [user
, host
] => validEmailUser user
andalso validDomain host
106 CharVector
.exists (fn ch
=> ch
= #
"#" orelse ch
= #
"~") s
109 (case map
Int.fromString (String.fields (fn ch
=> ch
= #
".") s
) of
110 [SOME n1
, SOME n2
, SOME n3
, SOME n4
] =>
111 n1
>= 0 andalso n1
< 256 andalso n2
>= 0 andalso n2
< 256 andalso n3
>= 0 andalso n3
< 256 andalso n4
>= 0 andalso n4
< 256
118 String.substring (s
, 0, size s
- 1)
121 foldr (fn (a
, s
) => s ^
"/" ^ a
) "" (String.tokens (fn ch
=> ch
= #
".") s
)
123 fun checkPath (paths
, path
) =
124 StringSet
.exists (fn pref
=> path
= pref
orelse (size path
>= size pref
+ 2 andalso substring (path
, 0, size pref
) = pref
125 andalso String.sub (path
, size pref
) = #
"/")) paths
126 andalso List.all (fn s
=> s
<> "..") (String.fields (fn ch
=> ch
= #
"/") path
)
128 fun resolveAddr (vars
, s
) =
132 (case StringMap
.find (vars
, s
) of
140 fun resolveDomain (vars
, s
) =
141 if validDomain s
then
144 (case StringMap
.find (vars
, s
) of
147 if validDomain v
then
152 fun enrichSetFromFile (fname
, set
) =
155 val uid
= Posix
.ProcEnv
.wordToUid (SysWord
.fromInt Config
.uid
)
157 if Posix
.FileSys
.access (fname
, []) then
158 (if Posix
.FileSys
.ST
.uid (Posix
.FileSys
.stat fname
) = uid
then
160 val vf
= openIn fname
164 val line
= inputLine vf
168 | SOME
"CLEAR\n" => loop StringSet
.empty
170 (case String.tokens
Char.isSpace line
of
171 [item
] => loop (StringSet
.add (set
, item
))
176 before TextIO.closeIn vf
179 (print (fname ^
": wrong owner to be used");
185 fun enrichMapFromFile (fname
, map
) =
188 val uid
= Posix
.ProcEnv
.wordToUid (SysWord
.fromInt Config
.uid
)
190 if Posix
.FileSys
.access (fname
, []) then
191 (if Posix
.FileSys
.ST
.uid (Posix
.FileSys
.stat fname
) = uid
then
193 val vf
= openIn fname
197 val line
= inputLine vf
201 | SOME
"CLEAR\n" => loop StringMap
.empty
203 (case String.tokens
Char.isSpace line
of
204 [key
, value
] => loop (StringMap
.insert (map
, key
, value
))
206 | _
=> (print (fname ^
": invalid line: " ^ line
);
211 before TextIO.closeIn vf
214 (print (fname ^
": wrong owner to be used");
220 fun merge (L1
: ('a
* int) list
, L2
: ('a
* int) list
) acc
=
222 (_
, []) => List.revAppend (acc
, L1
)
223 |
([], _
) => List.revAppend (acc
, L2
)
224 |
(n1
::t1
, n2
::t2
) =>
225 if #
2 n1
> #
2 n2
then
226 merge (t1
, L2
) (n1
:: acc
)
228 merge (L1
, t2
) (n2
:: acc
)
236 | h
::t
=> split (n
-1) t (h
::acc
)
244 val mid
= length L
div 2
245 val (L1
, L2
) = split mid L
[]
247 merge (mergeSort L1
, mergeSort L2
) []