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 module("luci.util", package.seeall)
30 -- Lua simplified Python-style OO class support emulation
34 local create = function(class, ...)
36 setmetatable(inst, {__index = class})
39 local stat, err = copcall(inst.__init__, inst, ...)
48 local classmeta = {__call = create}
51 classmeta.__index = base
54 setmetatable(class, classmeta)
59 -- Clones an object (deep on-demand)
60 function clone(object, deep)
63 for k, v in pairs(object) do
64 if deep and type(v) == "table" then
70 setmetatable(copy, getmetatable(object))
76 -- Combines two or more numerically indexed tables into one
79 for i, a in ipairs(arg) do
80 for j, v in ipairs(a) do
81 table.insert(result, v)
88 -- Checks whether a table has an object "value" in it
89 function contains(table, value)
90 for k,v in pairs(table) do
99 -- Dumps and strips a Lua-Function
101 local d = string.dump(f)
102 return d and strip_bytecode(d)
106 -- Dumps a table to stdout (useful for testing and debugging)
107 function dumptable(t, i)
109 for k,v in pairs(t) do
110 print(string.rep("\t", i) .. tostring(k), tostring(v))
111 if type(v) == "table" then
118 -- Escapes all occurences of c in s
119 function escape(s, c)
121 return s:gsub(c, "\\" .. c)
125 -- Populate obj in the scope of f as key
126 function extfenv(f, key, obj)
127 local scope = getfenv(f)
132 -- Checks whether an object is an instanceof class
133 function instanceof(object, class)
134 local meta = getmetatable(object)
135 while meta and meta.__index do
136 if meta.__index == class then
139 meta = getmetatable(meta.__index)
145 -- Creates valid XML PCDATA from a string
146 function pcdata(value)
147 value = value:gsub("&", "&")
148 value = value:gsub('"', """)
149 value = value:gsub("'", "'")
150 value = value:gsub("<", "<")
151 return value:gsub(">", ">")
155 -- Returns an error message to stdout
157 io.stderr:write(tostring(obj) .. "\n")
161 -- Resets the scope of f doing a shallow copy of its scope into a new table
163 setfenv(f, clone(getfenv(f)))
167 -- Splits a string into an array
168 function split(str, pat, max, regex)
188 local s, e = str:find(pat, c, not regex)
189 table.insert(t, str:sub(c, s and s - 1))
191 c = e and e + 1 or #str + 1
192 until not s or max < 0
198 -- Strips lua bytecode
199 -- Original version by Peter Cawley (http://lua-users.org/lists/lua-l/2008-02/msg01158.html)
200 function strip_bytecode(dump)
201 local version, format, endian, int, size, ins, num, lnum = dump:byte(5, 12)
204 subint = function(dump, i, l)
207 val = val * 256 + dump:byte(i + n - 1)
212 subint = function(dump, i, l)
215 val = val * 256 + dump:byte(i + n - 1)
222 strip_function = function(dump)
223 local count, offset = subint(dump, 1, size)
224 local stripped, dirty = string.rep("\0", size), offset + count
225 offset = offset + count + int * 2 + 4
226 offset = offset + int + subint(dump, offset, int) * ins
227 count, offset = subint(dump, offset, int)
230 t, offset = subint(dump, offset, 1)
234 offset = offset + size + subint(dump, offset, size)
236 offset = offset + num
238 offset = offset + lnum
241 count, offset = subint(dump, offset, int)
242 stripped = stripped .. dump:sub(dirty, offset - 1)
244 local proto, off = strip_function(dump:sub(offset, -1))
245 stripped, offset = stripped .. proto, offset + off - 1
247 offset = offset + subint(dump, offset, int) * int + int
248 count, offset = subint(dump, offset, int)
250 offset = offset + subint(dump, offset, size) + size + int * 2
252 count, offset = subint(dump, offset, int)
254 offset = offset + subint(dump, offset, size) + size
256 stripped = stripped .. string.rep("\0", int * 3)
257 return stripped, offset
260 return dump:sub(1,12) .. strip_function(dump:sub(13,-1))
264 -- Creates a new threadlocal store
265 function threadlocal()
268 local function get(self, key)
269 local c = coroutine.running()
270 local thread = coxpt[c] or c or 0
271 if not rawget(self, thread) then
274 return rawget(self, thread)[key]
277 local function set(self, key, value)
278 local c = coroutine.running()
279 local thread = coxpt[c] or c or 0
280 if not rawget(self, thread) then
281 rawset(self, thread, {})
283 rawget(self, thread)[key] = value
285 -- Avoid memory leaks by removing abandoned stores
286 for k, v in pairs(self) do
287 if type(k) == "thread" and coroutine.status(k) == "dead" then
293 setmetatable(tbl, {__index = get, __newindex = set})
299 -- Removes whitespace from beginning and end of a string
301 local s = str:gsub("^%s*(.-)%s*$", "%1")
306 -- Updates given table with new values
307 function update(t, updates)
308 for k, v in pairs(updates) do
314 -- Updates the scope of f with "extscope"
315 function updfenv(f, extscope)
316 update(getfenv(f), extscope)
320 -- Parse units from a string and return integer value
321 function parse_units(ustr)
328 y = 60 * 60 * 24 * 366,
329 m = 60 * 60 * 24 * 31,
330 w = 60 * 60 * 24 * 7,
338 gb = 1024 * 1024 * 1024,
340 -- storage sizes (si)
343 gib = 1000 * 1000 * 1000
346 -- parse input string
347 for spec in ustr:lower():gmatch("[0-9%.]+[a-zA-Z]*") do
349 local num = spec:gsub("[^0-9%.]+$","")
350 local spn = spec:gsub("^[0-9%.]+", "")
352 if map[spn] or map[spn:sub(1,1)] then
353 val = val + num * ( map[spn] or map[spn:sub(1,1)] )
364 -- Provide various sorting iterators
365 function _sortiter( t, f )
368 for k, v in pairs(t) do
369 table.insert( keys, k )
373 local _len = table.getn( keys )
375 table.sort( keys, f )
380 return keys[_pos], t[keys[_pos]]
385 -- Return key, value pairs sorted by provided callback function
387 return _sortiter( t, f )
390 -- Return key, value pairs sorted by keys
392 return _sortiter( t )
395 -- Return key, value pairs sorted by values
397 return _sortiter( t, function (a,b) return t[a] < t[b] end )
401 -- Coroutine safe xpcall and pcall versions modified for Luci
403 -- coxpcall 1.13 - Copyright 2005 - Kepler Project (www.keplerproject.org)
404 local performResume, handleReturnValue
405 local oldpcall, oldxpcall = pcall, xpcall
408 function handleReturnValue(err, co, status, ...)
410 return false, err(debug.traceback(co, (...)), ...)
412 if coroutine.status(co) == 'suspended' then
413 return performResume(err, co, coroutine.yield(...))
419 function performResume(err, co, ...)
420 return handleReturnValue(err, co, coroutine.resume(co, ...))
423 function coxpcall(f, err, ...)
424 local res, co = oldpcall(coroutine.create, f)
427 local newf = function() return f(unpack(params)) end
428 co = coroutine.create(newf)
430 local c = coroutine.running()
431 coxpt[co] = coxpt[c] or c or 0
432 return performResume(err, co, ...)
435 local function id(trace, ...)
439 function copcall(f, ...)
440 return coxpcall(f, id, ...)