787bc66f90636c0c6c0e8e5f275a6cea2753017d
[project/luci.git] / modules / luci-base / luasrc / util.lua
1 -- Copyright 2008 Steven Barth <steven@midlink.org>
2 -- Licensed to the public under the Apache License 2.0.
3
4 local io = require "io"
5 local math = require "math"
6 local table = require "table"
7 local debug = require "debug"
8 local ldebug = require "luci.debug"
9 local string = require "string"
10 local coroutine = require "coroutine"
11 local tparser = require "luci.template.parser"
12 local json = require "luci.jsonc"
13
14 local _ubus = require "ubus"
15 local _ubus_connection = nil
16
17 local getmetatable, setmetatable = getmetatable, setmetatable
18 local rawget, rawset, unpack = rawget, rawset, unpack
19 local tostring, type, assert = tostring, type, assert
20 local ipairs, pairs, next, loadstring = ipairs, pairs, next, loadstring
21 local require, pcall, xpcall = require, pcall, xpcall
22 local collectgarbage, get_memory_limit = collectgarbage, get_memory_limit
23
24 module "luci.util"
25
26 --
27 -- Pythonic string formatting extension
28 --
29 getmetatable("").__mod = function(a, b)
30 if not b then
31 return a
32 elseif type(b) == "table" then
33 for k, _ in pairs(b) do if type(b[k]) == "userdata" then b[k] = tostring(b[k]) end end
34 return a:format(unpack(b))
35 else
36 if type(b) == "userdata" then b = tostring(b) end
37 return a:format(b)
38 end
39 end
40
41
42 --
43 -- Class helper routines
44 --
45
46 -- Instantiates a class
47 local function _instantiate(class, ...)
48 local inst = setmetatable({}, {__index = class})
49
50 if inst.__init__ then
51 inst:__init__(...)
52 end
53
54 return inst
55 end
56
57 -- The class object can be instantiated by calling itself.
58 -- Any class functions or shared parameters can be attached to this object.
59 -- Attaching a table to the class object makes this table shared between
60 -- all instances of this class. For object parameters use the __init__ function.
61 -- Classes can inherit member functions and values from a base class.
62 -- Class can be instantiated by calling them. All parameters will be passed
63 -- to the __init__ function of this class - if such a function exists.
64 -- The __init__ function must be used to set any object parameters that are not shared
65 -- with other objects of this class. Any return values will be ignored.
66 function class(base)
67 return setmetatable({}, {
68 __call = _instantiate,
69 __index = base
70 })
71 end
72
73 function instanceof(object, class)
74 local meta = getmetatable(object)
75 while meta and meta.__index do
76 if meta.__index == class then
77 return true
78 end
79 meta = getmetatable(meta.__index)
80 end
81 return false
82 end
83
84
85 --
86 -- Scope manipulation routines
87 --
88
89 local tl_meta = {
90 __mode = "k",
91
92 __index = function(self, key)
93 local t = rawget(self, coxpt[coroutine.running()]
94 or coroutine.running() or 0)
95 return t and t[key]
96 end,
97
98 __newindex = function(self, key, value)
99 local c = coxpt[coroutine.running()] or coroutine.running() or 0
100 local r = rawget(self, c)
101 if not r then
102 rawset(self, c, { [key] = value })
103 else
104 r[key] = value
105 end
106 end
107 }
108
109 -- the current active coroutine. A thread local store is private a table object
110 -- whose values can't be accessed from outside of the running coroutine.
111 function threadlocal(tbl)
112 return setmetatable(tbl or {}, tl_meta)
113 end
114
115
116 --
117 -- Debugging routines
118 --
119
120 function perror(obj)
121 return io.stderr:write(tostring(obj) .. "\n")
122 end
123
124 function dumptable(t, maxdepth, i, seen)
125 i = i or 0
126 seen = seen or setmetatable({}, {__mode="k"})
127
128 for k,v in pairs(t) do
129 perror(string.rep("\t", i) .. tostring(k) .. "\t" .. tostring(v))
130 if type(v) == "table" and (not maxdepth or i < maxdepth) then
131 if not seen[v] then
132 seen[v] = true
133 dumptable(v, maxdepth, i+1, seen)
134 else
135 perror(string.rep("\t", i) .. "*** RECURSION ***")
136 end
137 end
138 end
139 end
140
141
142 --
143 -- String and data manipulation routines
144 --
145
146 function pcdata(value)
147 return value and tparser.pcdata(tostring(value))
148 end
149
150 function striptags(value)
151 return value and tparser.striptags(tostring(value))
152 end
153
154 -- containing the resulting substrings. The optional max parameter specifies
155 -- the number of bytes to process, regardless of the actual length of the given
156 -- string. The optional last parameter, regex, specifies whether the separator
157 -- sequence is interpreted as regular expression.
158 -- pattern as regular expression (optional, default is false)
159 function split(str, pat, max, regex)
160 pat = pat or "\n"
161 max = max or #str
162
163 local t = {}
164 local c = 1
165
166 if #str == 0 then
167 return {""}
168 end
169
170 if #pat == 0 then
171 return nil
172 end
173
174 if max == 0 then
175 return str
176 end
177
178 repeat
179 local s, e = str:find(pat, c, not regex)
180 max = max - 1
181 if s and max < 0 then
182 t[#t+1] = str:sub(c)
183 else
184 t[#t+1] = str:sub(c, s and s - 1)
185 end
186 c = e and e + 1 or #str + 1
187 until not s or max < 0
188
189 return t
190 end
191
192 function trim(str)
193 return (str:gsub("^%s*(.-)%s*$", "%1"))
194 end
195
196 function cmatch(str, pat)
197 local count = 0
198 for _ in str:gmatch(pat) do count = count + 1 end
199 return count
200 end
201
202 -- one token per invocation, the tokens are separated by whitespace. If the
203 -- input value is a table, it is transformed into a string first. A nil value
204 -- will result in a valid interator which aborts with the first invocation.
205 function imatch(v)
206 if type(v) == "table" then
207 local k = nil
208 return function()
209 k = next(v, k)
210 return v[k]
211 end
212
213 elseif type(v) == "number" or type(v) == "boolean" then
214 local x = true
215 return function()
216 if x then
217 x = false
218 return tostring(v)
219 end
220 end
221
222 elseif type(v) == "userdata" or type(v) == "string" then
223 return tostring(v):gmatch("%S+")
224 end
225
226 return function() end
227 end
228
229 -- value or 0 if the unit is unknown. Upper- or lower case is irrelevant.
230 -- Recognized units are:
231 -- o "y" - one year (60*60*24*366)
232 -- o "m" - one month (60*60*24*31)
233 -- o "w" - one week (60*60*24*7)
234 -- o "d" - one day (60*60*24)
235 -- o "h" - one hour (60*60)
236 -- o "min" - one minute (60)
237 -- o "kb" - one kilobyte (1024)
238 -- o "mb" - one megabyte (1024*1024)
239 -- o "gb" - one gigabyte (1024*1024*1024)
240 -- o "kib" - one si kilobyte (1000)
241 -- o "mib" - one si megabyte (1000*1000)
242 -- o "gib" - one si gigabyte (1000*1000*1000)
243 function parse_units(ustr)
244
245 local val = 0
246
247 -- unit map
248 local map = {
249 -- date stuff
250 y = 60 * 60 * 24 * 366,
251 m = 60 * 60 * 24 * 31,
252 w = 60 * 60 * 24 * 7,
253 d = 60 * 60 * 24,
254 h = 60 * 60,
255 min = 60,
256
257 -- storage sizes
258 kb = 1024,
259 mb = 1024 * 1024,
260 gb = 1024 * 1024 * 1024,
261
262 -- storage sizes (si)
263 kib = 1000,
264 mib = 1000 * 1000,
265 gib = 1000 * 1000 * 1000
266 }
267
268 -- parse input string
269 for spec in ustr:lower():gmatch("[0-9%.]+[a-zA-Z]*") do
270
271 local num = spec:gsub("[^0-9%.]+$","")
272 local spn = spec:gsub("^[0-9%.]+", "")
273
274 if map[spn] or map[spn:sub(1,1)] then
275 val = val + num * ( map[spn] or map[spn:sub(1,1)] )
276 else
277 val = val + num
278 end
279 end
280
281
282 return val
283 end
284
285 -- also register functions above in the central string class for convenience
286 string.pcdata = pcdata
287 string.striptags = striptags
288 string.split = split
289 string.trim = trim
290 string.cmatch = cmatch
291 string.parse_units = parse_units
292
293
294 function append(src, ...)
295 for i, a in ipairs({...}) do
296 if type(a) == "table" then
297 for j, v in ipairs(a) do
298 src[#src+1] = v
299 end
300 else
301 src[#src+1] = a
302 end
303 end
304 return src
305 end
306
307 function combine(...)
308 return append({}, ...)
309 end
310
311 function contains(table, value)
312 for k, v in pairs(table) do
313 if value == v then
314 return k
315 end
316 end
317 return false
318 end
319
320 -- Both table are - in fact - merged together.
321 function update(t, updates)
322 for k, v in pairs(updates) do
323 t[k] = v
324 end
325 end
326
327 function keys(t)
328 local keys = { }
329 if t then
330 for k, _ in kspairs(t) do
331 keys[#keys+1] = k
332 end
333 end
334 return keys
335 end
336
337 function clone(object, deep)
338 local copy = {}
339
340 for k, v in pairs(object) do
341 if deep and type(v) == "table" then
342 v = clone(v, deep)
343 end
344 copy[k] = v
345 end
346
347 return setmetatable(copy, getmetatable(object))
348 end
349
350
351 function dtable()
352 return setmetatable({}, { __index =
353 function(tbl, key)
354 return rawget(tbl, key)
355 or rawget(rawset(tbl, key, dtable()), key)
356 end
357 })
358 end
359
360
361 -- Serialize the contents of a table value.
362 function _serialize_table(t, seen)
363 assert(not seen[t], "Recursion detected.")
364 seen[t] = true
365
366 local data = ""
367 local idata = ""
368 local ilen = 0
369
370 for k, v in pairs(t) do
371 if type(k) ~= "number" or k < 1 or math.floor(k) ~= k or ( k - #t ) > 3 then
372 k = serialize_data(k, seen)
373 v = serialize_data(v, seen)
374 data = data .. ( #data > 0 and ", " or "" ) ..
375 '[' .. k .. '] = ' .. v
376 elseif k > ilen then
377 ilen = k
378 end
379 end
380
381 for i = 1, ilen do
382 local v = serialize_data(t[i], seen)
383 idata = idata .. ( #idata > 0 and ", " or "" ) .. v
384 end
385
386 return idata .. ( #data > 0 and #idata > 0 and ", " or "" ) .. data
387 end
388
389 -- with loadstring().
390 function serialize_data(val, seen)
391 seen = seen or setmetatable({}, {__mode="k"})
392
393 if val == nil then
394 return "nil"
395 elseif type(val) == "number" then
396 return val
397 elseif type(val) == "string" then
398 return "%q" % val
399 elseif type(val) == "boolean" then
400 return val and "true" or "false"
401 elseif type(val) == "function" then
402 return "loadstring(%q)" % get_bytecode(val)
403 elseif type(val) == "table" then
404 return "{ " .. _serialize_table(val, seen) .. " }"
405 else
406 return '"[unhandled data type:' .. type(val) .. ']"'
407 end
408 end
409
410 function restore_data(str)
411 return loadstring("return " .. str)()
412 end
413
414
415 --
416 -- Byte code manipulation routines
417 --
418
419 -- will be stripped before it is returned.
420 function get_bytecode(val)
421 local code
422
423 if type(val) == "function" then
424 code = string.dump(val)
425 else
426 code = string.dump( loadstring( "return " .. serialize_data(val) ) )
427 end
428
429 return code -- and strip_bytecode(code)
430 end
431
432 -- numbers and debugging numbers will be discarded. Original version by
433 -- Peter Cawley (http://lua-users.org/lists/lua-l/2008-02/msg01158.html)
434 function strip_bytecode(code)
435 local version, format, endian, int, size, ins, num, lnum = code:byte(5, 12)
436 local subint
437 if endian == 1 then
438 subint = function(code, i, l)
439 local val = 0
440 for n = l, 1, -1 do
441 val = val * 256 + code:byte(i + n - 1)
442 end
443 return val, i + l
444 end
445 else
446 subint = function(code, i, l)
447 local val = 0
448 for n = 1, l, 1 do
449 val = val * 256 + code:byte(i + n - 1)
450 end
451 return val, i + l
452 end
453 end
454
455 local function strip_function(code)
456 local count, offset = subint(code, 1, size)
457 local stripped = { string.rep("\0", size) }
458 local dirty = offset + count
459 offset = offset + count + int * 2 + 4
460 offset = offset + int + subint(code, offset, int) * ins
461 count, offset = subint(code, offset, int)
462 for n = 1, count do
463 local t
464 t, offset = subint(code, offset, 1)
465 if t == 1 then
466 offset = offset + 1
467 elseif t == 4 then
468 offset = offset + size + subint(code, offset, size)
469 elseif t == 3 then
470 offset = offset + num
471 elseif t == 254 or t == 9 then
472 offset = offset + lnum
473 end
474 end
475 count, offset = subint(code, offset, int)
476 stripped[#stripped+1] = code:sub(dirty, offset - 1)
477 for n = 1, count do
478 local proto, off = strip_function(code:sub(offset, -1))
479 stripped[#stripped+1] = proto
480 offset = offset + off - 1
481 end
482 offset = offset + subint(code, offset, int) * int + int
483 count, offset = subint(code, offset, int)
484 for n = 1, count do
485 offset = offset + subint(code, offset, size) + size + int * 2
486 end
487 count, offset = subint(code, offset, int)
488 for n = 1, count do
489 offset = offset + subint(code, offset, size) + size
490 end
491 stripped[#stripped+1] = string.rep("\0", int * 3)
492 return table.concat(stripped), offset
493 end
494
495 return code:sub(1,12) .. strip_function(code:sub(13,-1))
496 end
497
498
499 --
500 -- Sorting iterator functions
501 --
502
503 function _sortiter( t, f )
504 local keys = { }
505
506 local k, v
507 for k, v in pairs(t) do
508 keys[#keys+1] = k
509 end
510
511 local _pos = 0
512
513 table.sort( keys, f )
514
515 return function()
516 _pos = _pos + 1
517 if _pos <= #keys then
518 return keys[_pos], t[keys[_pos]], _pos
519 end
520 end
521 end
522
523 -- the provided callback function.
524 function spairs(t,f)
525 return _sortiter( t, f )
526 end
527
528 -- The table pairs are sorted by key.
529 function kspairs(t)
530 return _sortiter( t )
531 end
532
533 -- The table pairs are sorted by value.
534 function vspairs(t)
535 return _sortiter( t, function (a,b) return t[a] < t[b] end )
536 end
537
538
539 --
540 -- System utility functions
541 --
542
543 function bigendian()
544 return string.byte(string.dump(function() end), 7) == 0
545 end
546
547 function exec(command)
548 local pp = io.popen(command)
549 local data = pp:read("*a")
550 pp:close()
551
552 return data
553 end
554
555 function execi(command)
556 local pp = io.popen(command)
557
558 return pp and function()
559 local line = pp:read()
560
561 if not line then
562 pp:close()
563 end
564
565 return line
566 end
567 end
568
569 -- Deprecated
570 function execl(command)
571 local pp = io.popen(command)
572 local line = ""
573 local data = {}
574
575 while true do
576 line = pp:read()
577 if (line == nil) then break end
578 data[#data+1] = line
579 end
580 pp:close()
581
582 return data
583 end
584
585 function ubus(object, method, data)
586 if not _ubus_connection then
587 _ubus_connection = _ubus.connect()
588 assert(_ubus_connection, "Unable to establish ubus connection")
589 end
590
591 if object and method then
592 if type(data) ~= "table" then
593 data = { }
594 end
595 return _ubus_connection:call(object, method, data)
596 elseif object then
597 return _ubus_connection:signatures(object)
598 else
599 return _ubus_connection:objects()
600 end
601 end
602
603 function serialize_json(x, cb)
604 local js = json.stringify(x)
605 if type(cb) == "function" then
606 cb(js)
607 else
608 return js
609 end
610 end
611
612
613 function libpath()
614 return require "nixio.fs".dirname(ldebug.__file__)
615 end
616
617
618 --
619 -- Coroutine safe xpcall and pcall versions modified for Luci
620 -- original version:
621 -- coxpcall 1.13 - Copyright 2005 - Kepler Project (www.keplerproject.org)
622 --
623 -- Copyright © 2005 Kepler Project.
624 -- Permission is hereby granted, free of charge, to any person obtaining a
625 -- copy of this software and associated documentation files (the "Software"),
626 -- to deal in the Software without restriction, including without limitation
627 -- the rights to use, copy, modify, merge, publish, distribute, sublicense,
628 -- and/or sell copies of the Software, and to permit persons to whom the
629 -- Software is furnished to do so, subject to the following conditions:
630 --
631 -- The above copyright notice and this permission notice shall be
632 -- included in all copies or substantial portions of the Software.
633 --
634 -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
635 -- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
636 -- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
637 -- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
638 -- DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
639 -- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
640 -- OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
641
642 local performResume, handleReturnValue
643 local oldpcall, oldxpcall = pcall, xpcall
644 coxpt = {}
645 setmetatable(coxpt, {__mode = "kv"})
646
647 -- Identity function for copcall
648 local function copcall_id(trace, ...)
649 return ...
650 end
651
652 -- values of either the function or the error handler
653 function coxpcall(f, err, ...)
654 local res, co = oldpcall(coroutine.create, f)
655 if not res then
656 local params = {...}
657 local newf = function() return f(unpack(params)) end
658 co = coroutine.create(newf)
659 end
660 local c = coroutine.running()
661 coxpt[co] = coxpt[c] or c or 0
662
663 return performResume(err, co, ...)
664 end
665
666 -- values of the function or the error object
667 function copcall(f, ...)
668 return coxpcall(f, copcall_id, ...)
669 end
670
671 -- Handle return value of protected call
672 function handleReturnValue(err, co, status, ...)
673 if not status then
674 return false, err(debug.traceback(co, (...)), ...)
675 end
676
677 if coroutine.status(co) ~= 'suspended' then
678 return true, ...
679 end
680
681 return performResume(err, co, coroutine.yield(...))
682 end
683
684 -- Resume execution of protected function call
685 function performResume(err, co, ...)
686 return handleReturnValue(err, co, coroutine.resume(co, ...))
687 end