5 Several common useful Lua functions
11 Copyright 2008 Steven Barth <steven@midlink.org>
13 Licensed under the Apache License, Version 2.0 (the "License");
14 you may not use this file except in compliance with the License.
15 You may obtain a copy of the License at
17 http://www.apache.org/licenses/LICENSE-2.0
19 Unless required by applicable law or agreed to in writing, software
20 distributed under the License is distributed on an "AS IS" BASIS,
21 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 See the License for the specific language governing permissions and
23 limitations under the License.
27 local io = require "io"
28 local math = require "math"
29 local table = require "table"
30 local debug = require "debug"
31 local ldebug = require "luci.debug"
32 local string = require "string"
33 local coroutine = require "coroutine"
35 local getmetatable, setmetatable = getmetatable, setmetatable
36 local rawget, rawset, unpack = rawget, rawset, unpack
37 local tostring, type, assert = tostring, type, assert
38 local ipairs, pairs, loadstring = ipairs, pairs, loadstring
39 local require, pcall, xpcall = require, pcall, xpcall
40 local collectgarbage, get_memory_limit = collectgarbage, get_memory_limit
42 --- LuCI utility functions.
46 -- Pythonic string formatting extension
48 getmetatable("").__mod = function(a, b)
51 elseif type(b) == "table" then
52 return a:format(unpack(b))
60 -- Class helper routines
63 -- Instantiates a class
64 local function _instantiate(class, ...)
65 local inst = setmetatable({}, {__index = class})
74 --- Create a Class object (Python-style object model).
75 -- The class object can be instantiated by calling itself.
76 -- Any class functions or shared parameters can be attached to this object.
77 -- Attaching a table to the class object makes this table shared between
78 -- all instances of this class. For object parameters use the __init__ function.
79 -- Classes can inherit member functions and values from a base class.
80 -- Class can be instantiated by calling them. All parameters will be passed
81 -- to the __init__ function of this class - if such a function exists.
82 -- The __init__ function must be used to set any object parameters that are not shared
83 -- with other objects of this class. Any return values will be ignored.
84 -- @param base The base class to inherit from (optional)
85 -- @return A class object
89 return setmetatable({}, {
90 __call = _instantiate,
95 --- Test whether the given object is an instance of the given class.
96 -- @param object Object instance
97 -- @param class Class object to test against
98 -- @return Boolean indicating whether the object is an instance
101 function instanceof(object, class)
102 local meta = getmetatable(object)
103 while meta and meta.__index do
104 if meta.__index == class then
107 meta = getmetatable(meta.__index)
114 -- Scope manipulation routines
120 __index = function(self, key)
121 local t = rawget(self, coxpt[coroutine.running()]
122 or coroutine.running() or 0)
126 __newindex = function(self, key, value)
127 local c = coxpt[coroutine.running()] or coroutine.running() or 0
128 if not rawget(self, c) then
129 rawset(self, c, { [key] = value })
131 rawget(self, c)[key] = value
136 --- Create a new or get an already existing thread local store associated with
137 -- the current active coroutine. A thread local store is private a table object
138 -- whose values can't be accessed from outside of the running coroutine.
139 -- @return Table value representing the corresponding thread local store
140 function threadlocal(tbl)
141 return setmetatable(tbl or {}, tl_meta)
146 -- Debugging routines
149 --- Write given object to stderr.
150 -- @param obj Value to write to stderr
151 -- @return Boolean indicating whether the write operation was successful
153 return io.stderr:write(tostring(obj) .. "\n")
156 --- Recursively dumps a table to stdout, useful for testing and debugging.
157 -- @param t Table value to dump
158 -- @param maxdepth Maximum depth
159 -- @return Always nil
160 function dumptable(t, maxdepth, i, seen)
162 seen = seen or setmetatable({}, {__mode="k"})
164 for k,v in pairs(t) do
165 perror(string.rep("\t", i) .. tostring(k) .. "\t" .. tostring(v))
166 if type(v) == "table" and (not maxdepth or i < maxdepth) then
169 dumptable(v, maxdepth, i+1, seen)
171 perror(string.rep("\t", i) .. "*** RECURSION ***")
179 -- String and data manipulation routines
182 --- Escapes all occurrences of the given character in given string.
183 -- @param s String value containing unescaped characters
184 -- @param c String value with character to escape (optional, defaults to "\")
185 -- @return String value with each occurrence of character escaped with "\"
186 function escape(s, c)
188 return s:gsub(c, "\\" .. c)
191 --- Create valid XML PCDATA from given string.
192 -- @param value String value containing the data to escape
193 -- @return String value containing the escaped data
194 local function _pcdata_repl(c)
195 local i = string.byte(c)
197 if ( i >= 0x00 and i <= 0x08 ) or ( i >= 0x0B and i <= 0x0C ) or
198 ( i >= 0x0E and i <= 0x1F ) or ( i == 0x7F )
202 elseif ( i == 0x26 ) or ( i == 0x27 ) or ( i == 0x22 ) or
203 ( i == 0x3C ) or ( i == 0x3E )
205 return string.format("&#%i;", i)
211 function pcdata(value)
212 return value and tostring(value):gsub("[&\"'<>%c]", _pcdata_repl)
215 --- Strip HTML tags from given string.
216 -- @param value String containing the HTML text
217 -- @return String with HTML tags stripped of
218 function striptags(s)
219 return pcdata(tostring(s):gsub("</?[A-Za-z][A-Za-z0-9:_%-]*[^>]*>", " "):gsub("%s+", " "))
222 --- Splits given string on a defined separator sequence and return a table
223 -- containing the resulting substrings. The optional max parameter specifies
224 -- the number of bytes to process, regardless of the actual length of the given
225 -- string. The optional last parameter, regex, specifies whether the separator
226 -- sequence is interpreted as regular expression.
227 -- @param str String value containing the data to split up
228 -- @param pat String with separator pattern (optional, defaults to "\n")
229 -- @param max Maximum times to split (optional)
230 -- @param regex Boolean indicating whether to interpret the separator
231 -- pattern as regular expression (optional, default is false)
232 -- @return Table containing the resulting substrings
233 function split(str, pat, max, regex)
253 local s, e = str:find(pat, c, not regex)
255 if s and max < 0 then
258 t[#t+1] = str:sub(c, s and s - 1)
260 c = e and e + 1 or #str + 1
261 until not s or max < 0
266 --- Remove leading and trailing whitespace from given string value.
267 -- @param str String value containing whitespace padded data
268 -- @return String value with leading and trailing space removed
270 return (str:gsub("^%s*(.-)%s*$", "%1"))
273 --- Count the occurences of given substring in given string.
274 -- @param str String to search in
275 -- @param pattern String containing pattern to find
276 -- @return Number of found occurences
277 function cmatch(str, pat)
279 for _ in str:gmatch(pat) do count = count + 1 end
283 --- Parse certain units from the given string and return the canonical integer
284 -- value or 0 if the unit is unknown. Upper- or lower case is irrelevant.
285 -- Recognized units are:
286 -- o "y" - one year (60*60*24*366)
287 -- o "m" - one month (60*60*24*31)
288 -- o "w" - one week (60*60*24*7)
289 -- o "d" - one day (60*60*24)
290 -- o "h" - one hour (60*60)
291 -- o "min" - one minute (60)
292 -- o "kb" - one kilobyte (1024)
293 -- o "mb" - one megabyte (1024*1024)
294 -- o "gb" - one gigabyte (1024*1024*1024)
295 -- o "kib" - one si kilobyte (1000)
296 -- o "mib" - one si megabyte (1000*1000)
297 -- o "gib" - one si gigabyte (1000*1000*1000)
298 -- @param ustr String containing a numerical value with trailing unit
299 -- @return Number containing the canonical value
300 function parse_units(ustr)
307 y = 60 * 60 * 24 * 366,
308 m = 60 * 60 * 24 * 31,
309 w = 60 * 60 * 24 * 7,
317 gb = 1024 * 1024 * 1024,
319 -- storage sizes (si)
322 gib = 1000 * 1000 * 1000
325 -- parse input string
326 for spec in ustr:lower():gmatch("[0-9%.]+[a-zA-Z]*") do
328 local num = spec:gsub("[^0-9%.]+$","")
329 local spn = spec:gsub("^[0-9%.]+", "")
331 if map[spn] or map[spn:sub(1,1)] then
332 val = val + num * ( map[spn] or map[spn:sub(1,1)] )
342 -- also register functions above in the central string class for convenience
343 string.escape = escape
344 string.pcdata = pcdata
345 string.striptags = striptags
348 string.cmatch = cmatch
349 string.parse_units = parse_units
352 --- Appends numerically indexed tables or single objects to a given table.
353 -- @param src Target table
354 -- @param ... Objects to insert
355 -- @return Target table
356 function append(src, ...)
357 for i, a in ipairs({...}) do
358 if type(a) == "table" then
359 for j, v in ipairs(a) do
369 --- Combines two or more numerically indexed tables and single objects into one table.
370 -- @param tbl1 Table value to combine
371 -- @param tbl2 Table value to combine
372 -- @param ... More tables to combine
373 -- @return Table value containing all values of given tables
374 function combine(...)
375 return append({}, ...)
378 --- Checks whether the given table contains the given value.
379 -- @param table Table value
380 -- @param value Value to search within the given table
381 -- @return Boolean indicating whether the given value occurs within table
382 function contains(table, value)
383 for k, v in pairs(table) do
391 --- Update values in given table with the values from the second given table.
392 -- Both table are - in fact - merged together.
393 -- @param t Table which should be updated
394 -- @param updates Table containing the values to update
395 -- @return Always nil
396 function update(t, updates)
397 for k, v in pairs(updates) do
402 --- Retrieve all keys of given associative table.
403 -- @param t Table to extract keys from
404 -- @return Sorted table containing the keys
408 for k, _ in kspairs(t) do
415 --- Clones the given object and return it's copy.
416 -- @param object Table value to clone
417 -- @param deep Boolean indicating whether to do recursive cloning
418 -- @return Cloned table value
419 function clone(object, deep)
422 for k, v in pairs(object) do
423 if deep and type(v) == "table" then
429 return setmetatable(copy, getmetatable(object))
433 --- Create a dynamic table which automatically creates subtables.
434 -- @return Dynamic Table
436 return setmetatable({}, { __index =
438 return rawget(tbl, key)
439 or rawget(rawset(tbl, key, dtable()), key)
445 -- Serialize the contents of a table value.
446 function _serialize_table(t, seen)
447 assert(not seen[t], "Recursion detected.")
454 for k, v in pairs(t) do
455 if type(k) ~= "number" or k < 1 or math.floor(k) ~= k or ( k - #t ) > 3 then
456 k = serialize_data(k, seen)
457 v = serialize_data(v, seen)
458 data = data .. ( #data > 0 and ", " or "" ) ..
459 '[' .. k .. '] = ' .. v
466 local v = serialize_data(t[i], seen)
467 idata = idata .. ( #idata > 0 and ", " or "" ) .. v
470 return idata .. ( #data > 0 and #idata > 0 and ", " or "" ) .. data
473 --- Recursively serialize given data to lua code, suitable for restoring
474 -- with loadstring().
475 -- @param val Value containing the data to serialize
476 -- @return String value containing the serialized code
479 function serialize_data(val, seen)
480 seen = seen or setmetatable({}, {__mode="k"})
484 elseif type(val) == "number" then
486 elseif type(val) == "string" then
488 elseif type(val) == "boolean" then
489 return val and "true" or "false"
490 elseif type(val) == "function" then
491 return "loadstring(%q)" % get_bytecode(val)
492 elseif type(val) == "table" then
493 return "{ " .. _serialize_table(val, seen) .. " }"
495 return '"[unhandled data type:' .. type(val) .. ']"'
499 --- Restore data previously serialized with serialize_data().
500 -- @param str String containing the data to restore
501 -- @return Value containing the restored data structure
502 -- @see serialize_data
504 function restore_data(str)
505 return loadstring("return " .. str)()
510 -- Byte code manipulation routines
513 --- Return the current runtime bytecode of the given data. The byte code
514 -- will be stripped before it is returned.
515 -- @param val Value to return as bytecode
516 -- @return String value containing the bytecode of the given data
517 function get_bytecode(val)
520 if type(val) == "function" then
521 code = string.dump(val)
523 code = string.dump( loadstring( "return " .. serialize_data(val) ) )
526 return code and strip_bytecode(code)
529 --- Strips unnescessary lua bytecode from given string. Information like line
530 -- numbers and debugging numbers will be discarded. Original version by
531 -- Peter Cawley (http://lua-users.org/lists/lua-l/2008-02/msg01158.html)
532 -- @param code String value containing the original lua byte code
533 -- @return String value containing the stripped lua byte code
534 function strip_bytecode(code)
535 local version, format, endian, int, size, ins, num, lnum = code:byte(5, 12)
538 subint = function(code, i, l)
541 val = val * 256 + code:byte(i + n - 1)
546 subint = function(code, i, l)
549 val = val * 256 + code:byte(i + n - 1)
555 local function strip_function(code)
556 local count, offset = subint(code, 1, size)
557 local stripped = { string.rep("\0", size) }
558 local dirty = offset + count
559 offset = offset + count + int * 2 + 4
560 offset = offset + int + subint(code, offset, int) * ins
561 count, offset = subint(code, offset, int)
564 t, offset = subint(code, offset, 1)
568 offset = offset + size + subint(code, offset, size)
570 offset = offset + num
571 elseif t == 254 or t == 9 then
572 offset = offset + lnum
575 count, offset = subint(code, offset, int)
576 stripped[#stripped+1] = code:sub(dirty, offset - 1)
578 local proto, off = strip_function(code:sub(offset, -1))
579 stripped[#stripped+1] = proto
580 offset = offset + off - 1
582 offset = offset + subint(code, offset, int) * int + int
583 count, offset = subint(code, offset, int)
585 offset = offset + subint(code, offset, size) + size + int * 2
587 count, offset = subint(code, offset, int)
589 offset = offset + subint(code, offset, size) + size
591 stripped[#stripped+1] = string.rep("\0", int * 3)
592 return table.concat(stripped), offset
595 return code:sub(1,12) .. strip_function(code:sub(13,-1))
600 -- Sorting iterator functions
603 function _sortiter( t, f )
606 for k, v in pairs(t) do
612 table.sort( keys, f )
616 if _pos <= #keys then
617 return keys[_pos], t[keys[_pos]]
622 --- Return a key, value iterator which returns the values sorted according to
623 -- the provided callback function.
624 -- @param t The table to iterate
625 -- @param f A callback function to decide the order of elements
626 -- @return Function value containing the corresponding iterator
628 return _sortiter( t, f )
631 --- Return a key, value iterator for the given table.
632 -- The table pairs are sorted by key.
633 -- @param t The table to iterate
634 -- @return Function value containing the corresponding iterator
636 return _sortiter( t )
639 --- Return a key, value iterator for the given table.
640 -- The table pairs are sorted by value.
641 -- @param t The table to iterate
642 -- @return Function value containing the corresponding iterator
644 return _sortiter( t, function (a,b) return t[a] < t[b] end )
649 -- System utility functions
652 --- Test whether the current system is operating in big endian mode.
653 -- @return Boolean value indicating whether system is big endian
655 return string.byte(string.dump(function() end), 7) == 0
658 --- Execute given commandline and gather stdout.
659 -- @param command String containing command to execute
660 -- @return String containing the command's stdout
661 function exec(command)
662 local pp = io.popen(command)
663 local data = pp:read("*a")
669 --- Return a line-buffered iterator over the output of given command.
670 -- @param command String containing the command to execute
672 function execi(command)
673 local pp = io.popen(command)
675 return pp and function()
676 local line = pp:read()
687 function execl(command)
688 local pp = io.popen(command)
694 if (line == nil) then break end
702 --- Returns the absolute path to LuCI base directory.
703 -- @return String containing the directory path
705 return require "nixio.fs".dirname(ldebug.__file__)
710 -- Coroutine safe xpcall and pcall versions modified for Luci
712 -- coxpcall 1.13 - Copyright 2005 - Kepler Project (www.keplerproject.org)
714 -- Copyright © 2005 Kepler Project.
715 -- Permission is hereby granted, free of charge, to any person obtaining a
716 -- copy of this software and associated documentation files (the "Software"),
717 -- to deal in the Software without restriction, including without limitation
718 -- the rights to use, copy, modify, merge, publish, distribute, sublicense,
719 -- and/or sell copies of the Software, and to permit persons to whom the
720 -- Software is furnished to do so, subject to the following conditions:
722 -- The above copyright notice and this permission notice shall be
723 -- included in all copies or substantial portions of the Software.
725 -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
726 -- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
727 -- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
728 -- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
729 -- DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
730 -- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
731 -- OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
733 local performResume, handleReturnValue
734 local oldpcall, oldxpcall = pcall, xpcall
736 setmetatable(coxpt, {__mode = "kv"})
738 -- Identity function for copcall
739 local function copcall_id(trace, ...)
743 --- This is a coroutine-safe drop-in replacement for Lua's "xpcall"-function
744 -- @param f Lua function to be called protected
745 -- @param err Custom error handler
746 -- @param ... Parameters passed to the function
747 -- @return A boolean whether the function call succeeded and the return
748 -- values of either the function or the error handler
749 function coxpcall(f, err, ...)
750 local res, co = oldpcall(coroutine.create, f)
753 local newf = function() return f(unpack(params)) end
754 co = coroutine.create(newf)
756 local c = coroutine.running()
757 coxpt[co] = coxpt[c] or c or 0
759 return performResume(err, co, ...)
762 --- This is a coroutine-safe drop-in replacement for Lua's "pcall"-function
763 -- @param f Lua function to be called protected
764 -- @param ... Parameters passed to the function
765 -- @return A boolean whether the function call succeeded and the returns
766 -- values of the function or the error object
767 function copcall(f, ...)
768 return coxpcall(f, copcall_id, ...)
771 -- Handle return value of protected call
772 function handleReturnValue(err, co, status, arg1, arg2, arg3, arg4, arg5)
774 return false, err(debug.traceback(co, arg1), arg1, arg2, arg3, arg4, arg5)
777 if coroutine.status(co) ~= 'suspended' then
778 return true, arg1, arg2, arg3, arg4, arg5
781 return performResume(err, co, coroutine.yield(arg1, arg2, arg3, arg4, arg5))
784 -- Resume execution of protected function call
785 function performResume(err, co, arg1, arg2, arg3, arg4, arg5)
786 return handleReturnValue(err, co, coroutine.resume(co, arg1, arg2, arg3, arg4, arg5))