We have SRV resolving \o/
[prosody.git] / util / ztact.lua
1
2
3 -- public domain 20080410 lua@ztact.com
4
5
6 pcall (require, 'lfs')      -- lfs may not be installed/necessary.
7 pcall (require, 'pozix')    -- pozix may not be installed/necessary.
8
9
10 local getfenv, ipairs, next, pairs, pcall, require, select, tostring, type =
11       getfenv, ipairs, next, pairs, pcall, require, select, tostring, type
12 local unpack, xpcall =
13       unpack, xpcall
14
15 local io, lfs, os, string, table, pozix = io, lfs, os, string, table, pozix
16
17 local assert, print = assert, print
18
19 local error             = error
20
21
22 module ((...) or 'ztact')    ------------------------------------- module ztact
23
24
25 -- dir -------------------------------------------------------------------- dir
26
27
28 function dir (path)    -- - - - - - - - - - - - - - - - - - - - - - - - - - dir
29   local it = lfs.dir (path)
30   return function ()
31     repeat
32       local dir = it ()
33       if dir ~= '.' and dir ~= '..' then  return dir  end
34     until not dir
35     end  end
36
37
38 function is_file (path)    -- - - - - - - - - - - - - - - - - -  is_file (path)
39   local mode = lfs.attributes (path, 'mode')
40   return mode == 'file' and path
41   end
42
43
44 -- network byte ordering -------------------------------- network byte ordering
45
46
47 function htons (word)    -- - - - - - - - - - - - - - - - - - - - - - - - htons
48   return (word-word%0x100)/0x100, word%0x100
49   end
50
51
52 -- pcall2 -------------------------------------------------------------- pcall2
53
54
55 getfenv ().pcall = pcall    -- store the original pcall as ztact.pcall
56
57
58 local argc, argv, errorhandler, pcall2_f
59
60
61 local function _pcall2 ()    -- - - - - - - - - - - - - - - - - - - - - _pcall2
62   local tmpv = argv
63   argv = nil
64   return pcall2_f (unpack (tmpv, 1, argc))
65   end
66
67
68 function seterrorhandler (func)    -- - - - - - - - - - - - - - seterrorhandler
69   errorhandler = func
70   end
71
72
73 function pcall2 (f, ...)    -- - - - - - - - - - - - - - - - - - - - - - pcall2
74
75   pcall2_f = f
76   argc = select ('#', ...)
77   argv = { ... }
78
79   if not errorhandler then
80     local debug = require ('debug')
81     errorhandler = debug.traceback
82     end
83
84   return xpcall (_pcall2, errorhandler)
85   end
86
87
88 function append (t, ...)    -- - - - - - - - - - - - - - - - - - - - - - append
89   local insert = table.insert
90   for i,v in ipairs {...} do
91     insert (t, v)
92     end  end
93
94
95 function print_r (d, indent)    -- - - - - - - - - - - - - - - - - - -  print_r
96   local rep = string.rep ('  ', indent or 0)
97   if type (d) == 'table' then
98     for k,v in pairs (d) do
99       if type (v) == 'table' then
100         io.write (rep, k, '\n')
101         print_r (v, (indent or 0) + 1)
102       else  io.write (rep, k, ' = ', tostring (v), '\n')  end
103       end
104   else  io.write (d, '\n')  end
105   end
106
107
108 function tohex (s)    -- - - - - - - - - - - - - - - - - - - - - - - - -  tohex
109   return string.format (string.rep ('%02x ', #s), string.byte (s, 1, #s))
110   end
111
112
113 function tostring_r (d, indent, tab0)    -- - - - - - - - - - - - -  tostring_r
114
115   tab1 = tab0 or {}
116   local rep = string.rep ('  ', indent or 0)
117   if type (d) == 'table' then
118     for k,v in pairs (d) do
119       if type (v) == 'table' then
120         append (tab1, rep, k, '\n')
121         tostring_r (v, (indent or 0) + 1, tab1)
122       else  append (tab1, rep, k, ' = ', tostring (v), '\n')  end
123       end
124   else  append (tab1, d, '\n')  end
125
126   if not tab0 then  return table.concat (tab1)  end
127   end
128
129
130 -- queue manipulation -------------------------------------- queue manipulation
131
132
133 -- Possible queue states.  1 (i.e. queue.p[1]) is head of queue.
134 --
135 -- 1..2
136 -- 3..4  1..2
137 -- 3..4  1..2  5..6
138 -- 1..2        5..6
139 --             1..2
140
141
142 local function print_queue (queue, ...)    -- - - - - - - - - - - - print_queue
143   for i=1,10 do  io.write ((queue[i]   or '.')..' ')  end
144   io.write ('\t')
145   for i=1,6  do  io.write ((queue.p[i] or '.')..' ')  end
146   print (...)
147   end
148
149
150 function dequeue (queue)    -- - - - - - - - - - - - - - - - - - - - -  dequeue
151
152   local p = queue.p
153   if not p and queue[1] then  queue.p = { 1, #queue }  p = queue.p  end
154
155   if not p[1] then  return nil  end
156
157   local element = queue[p[1]]
158   queue[p[1]] = nil
159
160   if p[1] < p[2] then  p[1] = p[1] + 1
161
162   elseif p[4] then  p[1], p[2], p[3], p[4]  =  p[3], p[4], nil, nil
163
164   elseif p[5] then  p[1], p[2], p[5], p[6]  =  p[5], p[6], nil, nil
165
166   else  p[1], p[2]  =  nil, nil  end
167
168   print_queue (queue, '  de '..element)
169   return element
170   end
171
172
173 function enqueue (queue, element)    -- - - - - - - - - - - - - - - - - enqueue
174
175   local p = queue.p
176   if not p then  queue.p = {}  p = queue.p  end
177
178   if p[5] then    -- p3..p4 p1..p2 p5..p6
179     p[6] = p[6]+1
180     queue[p[6]] = element
181
182   elseif p[3] then    -- p3..p4 p1..p2
183
184     if p[4]+1 < p[1] then
185       p[4] = p[4] + 1
186       queue[p[4]] = element
187
188     else
189       p[5] = p[2]+1
190       p[6], queue[p[5]] = p[5], element
191       end
192
193   elseif p[1] then    -- p1..p2
194     if p[1] == 1 then
195       p[2] = p[2] + 1
196       queue[p[2]] = element
197
198     else
199         p[3], p[4], queue[1] = 1, 1, element
200         end
201
202   else    -- empty queue
203     p[1], p[2], queue[1] = 1, 1, element
204     end
205
206   print_queue (queue, '     '..element)
207   end
208
209
210 local function test_queue ()
211   t = {}
212   enqueue (t, 1)
213   enqueue (t, 2)
214   enqueue (t, 3)
215   enqueue (t, 4)
216   enqueue (t, 5)
217   dequeue (t)
218   dequeue (t)
219   enqueue (t, 6)
220   enqueue (t, 7)
221   enqueue (t, 8)
222   enqueue (t, 9)
223   dequeue (t)
224   dequeue (t)
225   dequeue (t)
226   dequeue (t)
227   enqueue (t, 'a')
228   dequeue (t)
229   enqueue (t, 'b')
230   enqueue (t, 'c')
231   dequeue (t)
232   dequeue (t)
233   dequeue (t)
234   dequeue (t)
235   dequeue (t)
236   enqueue (t, 'd')
237   dequeue (t)
238   dequeue (t)
239   dequeue (t)
240   end
241
242
243 -- test_queue ()
244
245
246 function queue_len (queue)
247   end
248
249
250 function queue_peek (queue)
251   end
252
253
254 -- tree manipulation ---------------------------------------- tree manipulation
255
256
257 function set (parent, ...)    --- - - - - - - - - - - - - - - - - - - - - - set
258
259   -- print ('set', ...)
260
261   local len = select ('#', ...)
262   local key, value = select (len-1, ...)
263   local cutpoint, cutkey
264
265   for i=1,len-2 do
266
267     local key = select (i, ...)
268     local child = parent[key]
269
270     if value == nil then
271       if child == nil then  return
272       elseif next (child, next (child)) then  cutpoint = nil  cutkey = nil
273       elseif cutpoint == nil then  cutpoint = parent  cutkey = key  end
274
275     elseif child == nil then  child = {}  parent[key] = child  end
276
277     parent = child
278     end
279
280   if value == nil and cutpoint then  cutpoint[cutkey] = nil
281   else  parent[key] = value  return value  end
282   end
283
284
285 function get (parent, ...)    --- - - - - - - - - - - - - - - - - - - - - - get
286   local len = select ('#', ...)
287   for i=1,len do
288     parent = parent[select (i, ...)]
289     if parent == nil then  break  end
290     end
291   return parent
292   end
293
294
295 -- misc ------------------------------------------------------------------ misc
296
297
298 function find (path, ...)    --------------------------------------------- find
299
300   local dirs, operators = { path }, {...}
301   for operator in ivalues (operators) do
302     if not operator (path) then  break  end  end
303
304   while next (dirs) do
305     local parent = table.remove (dirs)
306     for child in assert (pozix.opendir (parent)) do
307       if  child  and  child ~= '.'  and  child ~= '..'  then
308         local path = parent..'/'..child
309         if pozix.stat (path, 'is_dir') then  table.insert (dirs, path)  end
310         for operator in ivalues (operators) do
311           if not operator (path) then  break  end  end
312         end  end  end  end
313
314
315 function ivalues (t)    ----------------------------------------------- ivalues
316   local i = 0
317   return function ()  if t[i+1] then  i = i + 1  return t[i]  end  end
318   end
319
320
321 function lson_encode (mixed, f, indent, indents)    --------------- lson_encode
322
323
324   local capture
325   if not f then
326     capture = {}
327     f = function (s)  append (capture, s)  end
328     end
329
330   indent = indent or 0
331   indents = indents or {}
332   indents[indent] = indents[indent] or string.rep (' ', 2*indent)
333
334   local type = type (mixed)
335
336   if type == 'number' then f (mixed)
337
338   else if type == 'string' then f (string.format ('%q', mixed))
339
340   else if type == 'table' then
341     f ('{')
342     for k,v in pairs (mixed) do
343       f ('\n')
344       f (indents[indent])
345       f ('[')  f (lson_encode (k))  f ('] = ')
346       lson_encode (v, f, indent+1, indents)
347       f (',')
348       end 
349     f (' }')
350     end  end  end
351
352   if capture then  return table.concat (capture)  end
353   end
354
355
356 function timestamp (time)    ---------------------------------------- timestamp
357   return os.date ('%Y%m%d.%H%M%S', time)
358   end
359
360
361 function values (t)    ------------------------------------------------- values
362   local k, v
363   return function ()  k, v = next (t, k)  return v  end
364   end