]]--
--- LuCI utility functions.
+--- LuCI utility functions.
module("luci.util", package.seeall)
--
-- Class helper routines
--
---- Creates a Class object (Python-style object model)
--- Creates a new class object which can be instantiated by calling itself.
+--- Create a Class object (Python-style object model).
+-- The class object can be instantiated by calling itself.
-- Any class functions or shared parameters can be attached to this object.
-- Attaching a table to the class object makes this table shared between
-- all instances of this class. For object parameters use the __init__ function.
-- String and data manipulation routines
--
---- Escapes all occurences of the given character in given string.
+--- Escapes all occurrences of the given character in given string.
-- @param s String value containing unescaped characters
-- @param c String value with character to escape (optional, defaults to "\")
--- @return String value with each occurence of character escaped with "\"
+-- @return String value with each occurrence of character escaped with "\"
function escape(s, c)
c = c or "\\"
return s:gsub(c, "\\" .. c)
return value:gsub(">", ">")
end
---- Splits given string on a defined seperator sequence and return a table
+--- Splits given string on a defined separator sequence and return a table
-- containing the resulting substrings. The optional max parameter specifies
-- the number of bytes to process, regardless of the actual length of the given
--- string. The optional last parameter, regex, sepcifies whether the separator
+-- string. The optional last parameter, regex, specifies whether the separator
-- sequence is interpreted as regular expression.
-- @param str String value containing the data to split up
-- @param pat String with separator pattern (optional, defaults to "\n")
--- @param max Num of bytes to process (optional, default is string length)
--- @param regexp Boolean indicating whether to interprete the separator
+-- @param max Maximum times to split (optional)
+-- @param regex Boolean indicating whether to interpret the separator
-- pattern as regular expression (optional, default is false)
-- @return Table containing the resulting substrings
function split(str, pat, max, regex)
end
--- Parse certain units from the given string and return the canonical integer
--- value or 0 if the unit is unknown. Upper- or lowercase is irrelevant.
+-- value or 0 if the unit is unknown. Upper- or lower case is irrelevant.
-- Recognized units are:
-- o "y" - one year (60*60*24*366)
-- o "m" - one month (60*60*24*31)
--- Combines two or more numerically indexed tables into one.
-- @param tbl1 Table value to combine
-- @param tbl2 Table value to combine
--- @param tblN More values to combine
+-- @param ... More tables to combine
-- @return Table value containing all values of given tables
function combine(...)
local result = {}
return copy
end
--- Test whether the given table value is a numerically indexed table.
-function _is_numeric_table(t)
- local k = pairs(t)(t)
- return ( tonumber(k) ~= nil )
+
+--- Create a dynamic table which automatically creates subtables.
+-- @return Dynamic Table
+function dtable()
+ return setmetatable({}, { __index =
+ function(tbl, key)
+ return rawget(tbl, key)
+ or rawget(rawset(tbl, key, dtable()), key)
+ end
+ })
end
+
-- Serialize the contents of a table value.
function _serialize_table(t)
local data = ""
- if _is_numeric_table(t) then
- for i, v in ipairs(t) do
- v = serialize_data(v)
- data = data .. ( #data > 0 and ", " or "" ) .. v
- end
- else
- for k, v in pairs(t) do
- k = serialize_data(k)
- v = serialize_data(v)
- data = data .. ( #data > 0 and "; " or "" ) ..
- '[' .. k .. '] = ' .. v
- end
+ for k, v in pairs(t) do
+ k = serialize_data(k)
+ v = serialize_data(v)
+ data = data .. ( #data > 0 and ", " or "" ) ..
+ '[' .. k .. '] = ' .. v
end
return data
end
if val == nil then
return "nil"
elseif type(val) == "number" then
- return tostring(val)
+ return val
elseif type(val) == "string" then
- val = val:gsub("\\", "\\\\")
- :gsub("\r", "\\r")
- :gsub("\n", "\\n")
- :gsub('"','\\"')
- return '"' .. val .. '"'
+ return string.format("%q", val)
+ elseif type(val) == "boolean" then
+ return val and "true" or "false"
+ elseif type(val) == "function" then
+ return string.format("loadstring(%q)", get_bytecode(val))
elseif type(val) == "table" then
return "{ " .. _serialize_table(val) .. " }"
else
--
--- Return the current runtime bytecode of the given data. The byte code
--- will be stripped before it is returned if the given value is a function.
+-- will be stripped before it is returned.
-- @param val Value to return as bytecode
-- @return String value containing the bytecode of the given data
function get_bytecode(val)
+ local code
+
if type(val) == "function" then
- local code = string.dump(val)
- return code and strip_bytecode(code)
+ code = string.dump(val)
else
- return string.dump( loadstring( "return " .. serialize_data(val) ) )
+ code = string.dump( loadstring( "return " .. serialize_data(val) ) )
end
+
+ return code and strip_bytecode(code)
end
--- Strips unnescessary lua bytecode from given string. Information like line
end
+--
+-- System utility functions
+--
+
+--- Test whether the current system is operating in big endian mode.
+-- @return Boolean value indicating whether system is big endian
+function bigendian()
+ return string.byte(string.dump(function() end), 7) == 0
+end
+
+--- Execute given commandline and gather stdout.
+-- @param command String containing command to execute
+-- @return String containing the command's stdout
+function exec(command)
+ local pp = io.popen(command)
+ local data = pp:read("*a")
+ pp:close()
+
+ return data
+end
+
+--- Return a line-buffered iterator over the output of given command.
+-- @param command String containing the command to execute
+-- @return Iterator
+function execi(command)
+ local pp = io.popen(command)
+
+ return pp and function()
+ local line = pp:read()
+
+ if not line then
+ pp:close()
+ end
+
+ return line
+ end
+end
+
+-- Deprecated
+function execl(command)
+ local pp = io.popen(command)
+ local line = ""
+ local data = {}
+
+ while true do
+ line = pp:read()
+ if (line == nil) then break end
+ table.insert(data, line)
+ end
+ pp:close()
+
+ return data
+end
+
+--- Returns the absolute path to LuCI base directory.
+-- @return String containing the directory path
+function libpath()
+ return luci.fs.dirname(require("luci.debug").__file__)
+end
+
+
--
-- Coroutine safe xpcall and pcall versions modified for Luci
-- original version:
-- coxpcall 1.13 - Copyright 2005 - Kepler Project (www.keplerproject.org)
--
+-- Copyright © 2005 Kepler Project.
+-- Permission is hereby granted, free of charge, to any person obtaining a
+-- copy of this software and associated documentation files (the "Software"),
+-- to deal in the Software without restriction, including without limitation
+-- the rights to use, copy, modify, merge, publish, distribute, sublicense,
+-- and/or sell copies of the Software, and to permit persons to whom the
+-- Software is furnished to do so, subject to the following conditions:
+--
+-- The above copyright notice and this permission notice shall be
+-- included in all copies or substantial portions of the Software.
+--
+-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+-- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+-- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+-- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+-- DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+-- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+-- OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
local performResume, handleReturnValue
local oldpcall, oldxpcall = pcall, xpcall