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