337
|
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 |