Better checking of Block arguments
[hcoop/zz_old/domtool.git] / src / util.sml
CommitLineData
182a2654
AC
1(*
2Domtool (http://hcoop.sf.net/)
3Copyright (C) 2004 Adam Chlipala
4
5This program is free software; you can redistribute it and/or
6modify it under the terms of the GNU General Public License
7as published by the Free Software Foundation; either version 2
8of the License, or (at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18*)
19
20(* Utility functions *)
21
22structure Util :> UTIL =
23struct
24 fun impLoop next stop body init =
25 let
26 fun loop state =
27 let
28 val v = next ()
29 in
30 if stop v then
31 ()
32 else
33 loop (body (v, state))
34 end
35 in
36 loop init
37 end
38
182a2654
AC
39 fun ioOptLoop next body init =
40 let
41 fun loop state =
42 case next () of
43 NONE => ()
44 | SOME v => loop (body (v, state))
45 in
46 loop init
47 end
48
d1c1f370
AC
49 fun ioOptLoopFold next body init =
50 let
51 fun loop state =
52 case next () of
53 NONE => state
54 | SOME v => loop (body (v, state))
55 in
56 loop init
57 end
58
182a2654
AC
59 fun isIdent ch = Char.isLower ch orelse Char.isDigit ch
60
05060d16
AC
61 fun isInt s = Int.fromString s <> NONE
62
5958a619 63 fun isNat s = CharVector.all Char.isDigit s
05060d16
AC
64
65 fun chop s = String.substring (s, 0, size s - 1)
66
182a2654 67 fun validHost s =
c6544086
AC
68 size s > 0 andalso size s < 30
69 andalso CharVector.all (fn ch => isIdent ch orelse ch = #"-") s
70 andalso CharVector.exists (fn ch => not (Char.isDigit ch)) s
4d3abed7 71
036701c8 72 fun validHostUC s =
c6544086
AC
73 size s > 0 andalso size s < 30
74 andalso CharVector.all (fn ch => Char.isAlphaNum ch orelse ch = #"-") s
75 andalso CharVector.exists (fn ch => not (Char.isDigit ch)) s
036701c8 76
4d3abed7
AC
77 fun validVhostFilename s =
78 case String.fields (fn ch => ch = #".") s of
79 [s] => validHost s
80 | [s, "ssl"] => validHost s
81 | _ => false
82
182a2654
AC
83 fun validDomain s =
84 size s > 0 andalso size s < 100 andalso List.all validHost (String.fields (fn ch => ch = #".") s)
85
036701c8
AC
86 fun validDomainUC s =
87 size s > 0 andalso size s < 100 andalso List.all validHostUC (String.fields (fn ch => ch = #".") s)
88
368cc49c
AC
89 fun validLocation s =
90 size s > 0 andalso size s < 1000 andalso CharVector.all
91 (fn ch => Char.isAlphaNum ch
92 orelse ch = #"-"
93 orelse ch = #"_"
94 orelse ch = #"."
95 orelse ch = #"/") s
96
1dd685ff
AC
97 fun validDomainId s =
98 case String.fields (fn ch => ch = #"_") s of
99 [_] => validDomain s
100 | [host, rest] =>
101 (validHost host andalso case String.tokens (fn ch => ch = #".") rest of
102 "ssl" :: rest => List.all validHost rest
103 | _ => false)
104 | _ => false
105
182a2654 106 fun validUser s =
4d3abed7 107 size s > 0 andalso size s < 50 andalso CharVector.all
182a2654 108 (fn ch => isIdent ch orelse ch = #"." orelse ch = #"_" orelse ch = #"-" orelse ch = #"+")
4d3abed7 109 s
182a2654 110
05060d16 111 fun validEmailUser s =
4d3abed7 112 size s > 0 andalso size s < 50 andalso CharVector.all
05060d16 113 (fn ch => Char.isAlphaNum ch orelse ch = #"." orelse ch = #"_" orelse ch = #"-" orelse ch = #"+")
4d3abed7 114 s
182a2654
AC
115 fun validEmail s =
116 (case String.fields (fn ch => ch = #"@") s of
05060d16 117 [user, host] => validEmailUser user andalso validDomain host
182a2654
AC
118 | _ => false)
119
120 fun isTmp s =
4d3abed7 121 CharVector.exists (fn ch => ch = #"#" orelse ch = #"~") s
182a2654
AC
122
123 fun validIp s =
124 (case map Int.fromString (String.fields (fn ch => ch = #".") s) of
125 [SOME n1, SOME n2, SOME n3, SOME n4] =>
126 n1 >= 0 andalso n1 < 256 andalso n2 >= 0 andalso n2 < 256 andalso n3 >= 0 andalso n3 < 256 andalso n4 >= 0 andalso n4 < 256
127 | _ => false)
128
129 fun trimLast s =
130 if size s = 0 then
131 s
132 else
133 String.substring (s, 0, size s - 1)
134
135 fun toDir s =
136 foldr (fn (a, s) => s ^ "/" ^ a) "" (String.tokens (fn ch => ch = #".") s)
137
138 fun checkPath (paths, path) =
139 StringSet.exists (fn pref => path = pref orelse (size path >= size pref + 2 andalso substring (path, 0, size pref) = pref
140 andalso String.sub (path, size pref) = #"/")) paths
141 andalso List.all (fn s => s <> "..") (String.fields (fn ch => ch = #"/") path)
502a9148
AC
142 andalso CharVector.all (fn ch => Char.isAlphaNum ch orelse ch = #"." orelse ch = #"/"
143 orelse ch = #"-" orelse ch = #"_") path
182a2654
AC
144
145 fun resolveAddr (vars, s) =
146 if validIp s then
147 s
148 else
149 (case StringMap.find (vars, s) of
150 NONE => ""
151 | SOME v =>
152 if validIp v then
153 v
154 else
155 "")
156
157 fun resolveDomain (vars, s) =
158 if validDomain s then
159 s
160 else
161 (case StringMap.find (vars, s) of
162 NONE => ""
163 | SOME v =>
164 if validDomain v then
165 v
166 else
167 "")
874b616a
AC
168
169 fun enrichSetFromFile (fname, set) =
170 let
171 open TextIO
172 val uid = Posix.ProcEnv.wordToUid (SysWord.fromInt Config.uid)
173 in
174 if Posix.FileSys.access (fname, []) then
175 (if Posix.FileSys.ST.uid (Posix.FileSys.stat fname) = uid then
176 let
177 val vf = openIn fname
178
179 fun loop set =
180 let
181 val line = inputLine vf
182 in
183 case line of
184 NONE => set
185 | SOME "CLEAR\n" => loop StringSet.empty
186 | SOME line =>
187 (case String.tokens Char.isSpace line of
188 [item] => loop (StringSet.add (set, item))
189 | _ => loop set)
190 end
191 in
192 loop set
193 before TextIO.closeIn vf
194 end
195 else
f6883eac 196 (print (fname ^ ": wrong owner to be used\n");
874b616a
AC
197 set))
198 else
199 set
200 end
4471dd55 201
d1c1f370
AC
202 fun enrichMapFromFile (fname, map) =
203 let
204 open TextIO
205 val uid = Posix.ProcEnv.wordToUid (SysWord.fromInt Config.uid)
206 in
207 if Posix.FileSys.access (fname, []) then
208 (if Posix.FileSys.ST.uid (Posix.FileSys.stat fname) = uid then
209 let
210 val vf = openIn fname
211
212 fun loop map =
213 let
214 val line = inputLine vf
215 in
216 case line of
217 NONE => map
218 | SOME "CLEAR\n" => loop StringMap.empty
219 | SOME line =>
220 (case String.tokens Char.isSpace line of
221 [key, value] => loop (StringMap.insert (map, key, value))
222 | [] => loop map
223 | _ => (print (fname ^ ": invalid line: " ^ line);
224 loop map))
225 end
226 in
227 loop map
228 before TextIO.closeIn vf
229 end
230 else
231 (print (fname ^ ": wrong owner to be used");
232 map))
233 else
234 map
235 end
236
4471dd55
AC
237 fun merge (L1 : ('a * int) list, L2 : ('a * int) list) acc =
238 case (L1, L2) of
239 (_, []) => List.revAppend (acc, L1)
240 | ([], _) => List.revAppend (acc, L2)
241 | (n1::t1, n2::t2) =>
242 if #2 n1 > #2 n2 then
243 merge (t1, L2) (n1 :: acc)
244 else
245 merge (L1, t2) (n2 :: acc)
246
247 fun split n L acc =
248 if n <= 0 then
249 (acc, L)
250 else
251 case L of
252 [] => (acc, [])
253 | h::t => split (n-1) t (h::acc)
254
255 fun mergeSort L =
256 case L of
257 [] => L
258 | [a] => L
259 | _ =>
260 let
261 val mid = length L div 2
262 val (L1, L2) = split mid L []
263 in
264 merge (mergeSort L1, mergeSort L2) []
265 end
5958a619
AC
266
267 fun member (x, L) = List.exists (fn y => y = x) L
182a2654
AC
268end
269