0a30b163a4b0cb61a314d69813a2ae3373529f90
[project/luci.git] / libs / core / luasrc / util.lua
1 --[[
2 LuCI - Utility library
3
4 Description:
5 Several common useful Lua functions
6
7 FileId:
8 $Id$
9
10 License:
11 Copyright 2008 Steven Barth <steven@midlink.org>
12
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
16
17 http://www.apache.org/licenses/LICENSE-2.0
18
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.
24
25 ]]--
26
27 module("luci.util", package.seeall)
28
29
30 -- Lua simplified Python-style OO class support emulation
31 function class(base)
32 local class = {}
33
34 local create = function(class, ...)
35 local inst = {}
36 setmetatable(inst, {__index = class})
37
38 if inst.__init__ then
39 local stat, err = pcall(inst.__init__, inst, ...)
40 if not stat then
41 error(err)
42 end
43 end
44
45 return inst
46 end
47
48 local classmeta = {__call = create}
49
50 if base then
51 classmeta.__index = base
52 end
53
54 setmetatable(class, classmeta)
55 return class
56 end
57
58
59 -- Clones an object (deep on-demand)
60 function clone(object, deep)
61 local copy = {}
62
63 for k, v in pairs(object) do
64 if deep and type(v) == "table" then
65 v = clone(v, deep)
66 end
67 copy[k] = v
68 end
69
70 setmetatable(copy, getmetatable(object))
71
72 return copy
73 end
74
75
76 -- Combines two or more numerically indexed tables into one
77 function combine(...)
78 local result = {}
79 for i, a in ipairs(arg) do
80 for j, v in ipairs(a) do
81 table.insert(result, v)
82 end
83 end
84 return result
85 end
86
87
88 -- Checks whether a table has an object "value" in it
89 function contains(table, value)
90 for k,v in pairs(table) do
91 if value == v then
92 return true
93 end
94 end
95 return false
96 end
97
98
99 -- Dumps and strips a Lua-Function
100 function dump(f)
101 local d = string.dump(f)
102 return d and strip_bytecode(d)
103 end
104
105
106 -- Dumps a table to stdout (useful for testing and debugging)
107 function dumptable(t, i)
108 i = i or 0
109 for k,v in pairs(t) do
110 print(string.rep("\t", i) .. k, v)
111 if type(v) == "table" then
112 dumptable(v, i+1)
113 end
114 end
115 end
116
117
118 -- Escapes all occurences of c in s
119 function escape(s, c)
120 c = c or "\\"
121 return s:gsub(c, "\\" .. c)
122 end
123
124
125 -- Populate obj in the scope of f as key
126 function extfenv(f, key, obj)
127 local scope = getfenv(f)
128 scope[key] = obj
129 end
130
131
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
137 return true
138 end
139 meta = getmetatable(meta.__index)
140 end
141 return false
142 end
143
144
145 -- Creates valid XML PCDATA from a string
146 function pcdata(value)
147 value = value:gsub("&", "&amp;")
148 value = value:gsub('"', "&quot;")
149 value = value:gsub("'", "&apos;")
150 value = value:gsub("<", "&lt;")
151 return value:gsub(">", "&gt;")
152 end
153
154
155 -- Resets the scope of f doing a shallow copy of its scope into a new table
156 function resfenv(f)
157 setfenv(f, clone(getfenv(f)))
158 end
159
160
161 -- Splits a string into an array
162 function split(str, pat, max, regex)
163 pat = pat or "\n"
164 max = max or #str
165
166 local t = {}
167 local c = 1
168
169 if #str == 0 then
170 return {""}
171 end
172
173 if #pat == 0 then
174 return nil
175 end
176
177 if max == 0 then
178 return str
179 end
180
181 repeat
182 local s, e = str:find(pat, c, not regex)
183 table.insert(t, str:sub(c, s and s - 1))
184 max = max - 1
185 c = e and e + 1 or #str + 1
186 until not s or max < 0
187
188 return t
189 end
190
191
192 -- Bytecode stripping function by Peter Cawley from http://lua-users.org/lists/lua-l/2008-02/msg01158.html
193 function strip_bytecode(dump)
194 local version, format, endian, int, size, ins, num = dump:byte(5, 11)
195 local subint
196 if endian == 1 then
197 subint = function(dump, i, l)
198 local val = 0
199 for n = l, 1, -1 do
200 val = val * 256 + dump:byte(i + n - 1)
201 end
202 return val, i + l
203 end
204 else
205 subint = function(dump, i, l)
206 local val = 0
207 for n = 1, l, 1 do
208 val = val * 256 + dump:byte(i + n - 1)
209 end
210 return val, i + l
211 end
212 end
213
214 local strip_function
215 strip_function = function(dump)
216 local count, offset = subint(dump, 1, size)
217 local stripped, dirty = string.rep("\0", size), offset + count
218 offset = offset + count + int * 2 + 4
219 offset = offset + int + subint(dump, offset, int) * ins
220 count, offset = subint(dump, offset, int)
221 for n = 1, count do
222 local t
223 t, offset = subint(dump, offset, 1)
224 if t == 1 then
225 offset = offset + 1
226 elseif t == 4 then
227 offset = offset + size + subint(dump, offset, size)
228 elseif t == 3 then
229 offset = offset + num
230 end
231 end
232 count, offset = subint(dump, offset, int)
233 stripped = stripped .. dump:sub(dirty, offset - 1)
234 for n = 1, count do
235 local proto, off = strip_function(dump:sub(offset, -1))
236 stripped, offset = stripped .. proto, offset + off - 1
237 end
238 offset = offset + subint(dump, offset, int) * int + int
239 count, offset = subint(dump, offset, int)
240 for n = 1, count do
241 offset = offset + subint(dump, offset, size) + size + int * 2
242 end
243 count, offset = subint(dump, offset, int)
244 for n = 1, count do
245 offset = offset + subint(dump, offset, size) + size
246 end
247 stripped = stripped .. string.rep("\0", int * 3)
248 return stripped, offset
249 end
250
251 return dump:sub(1,12) .. strip_function(dump:sub(13,-1))
252 end
253
254
255 -- Removes whitespace from beginning and end of a string
256 function trim(str)
257 local s = str:gsub("^%s*(.-)%s*$", "%1")
258 return s
259 end
260
261
262 -- Updates given table with new values
263 function update(t, updates)
264 for k, v in pairs(updates) do
265 t[k] = v
266 end
267 end
268
269
270 -- Updates the scope of f with "extscope"
271 function updfenv(f, extscope)
272 update(getfenv(f), extscope)
273 end
274
275
276 -- Validates a variable
277 function validate(value, cast_number, cast_int)
278 if cast_number or cast_int then
279 value = tonumber(value)
280 end
281
282 if cast_int and value and not(value % 1 == 0) then
283 value = nil
284 end
285
286 return value
287 end