libs/web: introduce recursive expression support for datatypes, introduce "or" and...
[project/luci.git] / libs / web / luasrc / cbi / datatypes.lua
1 --[[
2
3 LuCI - Configuration Bind Interface - Datatype Tests
4 (c) 2010 Jo-Philipp Wich <xm@subsignal.org>
5
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12 $Id$
13
14 ]]--
15
16 local fs = require "nixio.fs"
17 local ip = require "luci.ip"
18 local math = require "math"
19 local util = require "luci.util"
20 local tonumber, type, unpack, select = tonumber, type, unpack, select
21
22
23 module "luci.cbi.datatypes"
24
25
26 _M['or'] = function(v, ...)
27 local i
28 for i = 1, select('#', ...), 2 do
29 local f = select(i, ...)
30 local a = select(i+1, ...)
31 if type(f) ~= "function" then
32 print("COMP", f, v)
33 if f == v then
34 return true
35 end
36 i = i - 1
37 elseif f(v, unpack(a)) then
38 return true
39 end
40 end
41 return false
42 end
43
44 _M['and'] = function(v, ...)
45 local i
46 for i = 1, select('#', ...), 2 do
47 local f = select(i, ...)
48 local a = select(i+1, ...)
49 if type(f) ~= "function" then
50 if f ~= v then
51 return false
52 end
53 i = i - 1
54 elseif not f(v, unpack(a)) then
55 return false
56 end
57 end
58 return true
59 end
60
61 function neg(v, ...)
62 return _M['or'](v:gsub("^%s*!%s*", ""), ...)
63 end
64
65 function list(v, subvalidator, subargs)
66 if type(subvalidator) ~= "function" then
67 return false
68 end
69 local token
70 for token in v:gmatch("%S+") do
71 if not subvalidator(token, unpack(subargs)) then
72 return false
73 end
74 end
75 return true
76 end
77
78 function bool(val)
79 if val == "1" or val == "yes" or val == "on" or val == "true" then
80 return true
81 elseif val == "0" or val == "no" or val == "off" or val == "false" then
82 return true
83 elseif val == "" or val == nil then
84 return true
85 end
86
87 return false
88 end
89
90 function uinteger(val)
91 local n = tonumber(val)
92 if n ~= nil and math.floor(n) == n and n >= 0 then
93 return true
94 end
95
96 return false
97 end
98
99 function integer(val)
100 local n = tonumber(val)
101 if n ~= nil and math.floor(n) == n then
102 return true
103 end
104
105 return false
106 end
107
108 function ufloat(val)
109 local n = tonumber(val)
110 return ( n ~= nil and n >= 0 )
111 end
112
113 function float(val)
114 return ( tonumber(val) ~= nil )
115 end
116
117 function ipaddr(val)
118 return ip4addr(val) or ip6addr(val)
119 end
120
121 function ip4addr(val)
122 if val then
123 return ip.IPv4(val) and true or false
124 end
125
126 return false
127 end
128
129 function ip4prefix(val)
130 val = tonumber(val)
131 return ( val and val >= 0 and val <= 32 )
132 end
133
134 function ip6addr(val)
135 if val then
136 return ip.IPv6(val) and true or false
137 end
138
139 return false
140 end
141
142 function ip6prefix(val)
143 val = tonumber(val)
144 return ( val and val >= 0 and val <= 128 )
145 end
146
147 function port(val)
148 val = tonumber(val)
149 return ( val and val >= 0 and val <= 65535 )
150 end
151
152 function portrange(val)
153 local p1, p2 = val:match("^(%d+)%-(%d+)$")
154 if p1 and p2 and port(p1) and port(p2) then
155 return true
156 else
157 return port(val)
158 end
159 end
160
161 function macaddr(val)
162 if val and val:match(
163 "^[a-fA-F0-9]+:[a-fA-F0-9]+:[a-fA-F0-9]+:" ..
164 "[a-fA-F0-9]+:[a-fA-F0-9]+:[a-fA-F0-9]+$"
165 ) then
166 local parts = util.split( val, ":" )
167
168 for i = 1,6 do
169 parts[i] = tonumber( parts[i], 16 )
170 if parts[i] < 0 or parts[i] > 255 then
171 return false
172 end
173 end
174
175 return true
176 end
177
178 return false
179 end
180
181 function hostname(val)
182 if val and (#val < 254) and (
183 val:match("^[a-zA-Z]+$") or
184 (val:match("^[a-zA-Z0-9][a-zA-Z0-9%-%.]*[a-zA-Z0-9]$") and
185 val:match("[^0-9%.]"))
186 ) then
187 return true
188 end
189 return false
190 end
191
192 function host(val)
193 return hostname(val) or ipaddr(val)
194 end
195
196 function network(val)
197 return uciname(val) or host(val)
198 end
199
200 function wpakey(val)
201 if #val == 64 then
202 return (val:match("^[a-fA-F0-9]+$") ~= nil)
203 else
204 return (#val >= 8) and (#val <= 63)
205 end
206 end
207
208 function wepkey(val)
209 if val:sub(1, 2) == "s:" then
210 val = val:sub(3)
211 end
212
213 if (#val == 10) or (#val == 26) then
214 return (val:match("^[a-fA-F0-9]+$") ~= nil)
215 else
216 return (#val == 5) or (#val == 13)
217 end
218 end
219
220 function string(val)
221 return true -- Everything qualifies as valid string
222 end
223
224 function directory( val, seen )
225 local s = fs.stat(val)
226 seen = seen or { }
227
228 if s and not seen[s.ino] then
229 seen[s.ino] = true
230 if s.type == "dir" then
231 return true
232 elseif s.type == "lnk" then
233 return directory( fs.readlink(val), seen )
234 end
235 end
236
237 return false
238 end
239
240 function file( val, seen )
241 local s = fs.stat(val)
242 seen = seen or { }
243
244 if s and not seen[s.ino] then
245 seen[s.ino] = true
246 if s.type == "reg" then
247 return true
248 elseif s.type == "lnk" then
249 return file( fs.readlink(val), seen )
250 end
251 end
252
253 return false
254 end
255
256 function device( val, seen )
257 local s = fs.stat(val)
258 seen = seen or { }
259
260 if s and not seen[s.ino] then
261 seen[s.ino] = true
262 if s.type == "chr" or s.type == "blk" then
263 return true
264 elseif s.type == "lnk" then
265 return device( fs.readlink(val), seen )
266 end
267 end
268
269 return false
270 end
271
272 function uciname(val)
273 return (val:match("^[a-zA-Z0-9_]+$") ~= nil)
274 end
275
276 function range(val, min, max)
277 val = tonumber(val)
278 min = tonumber(min)
279 max = tonumber(max)
280
281 if val ~= nil and min ~= nil and max ~= nil then
282 return ((val >= min) and (val <= max))
283 end
284
285 return false
286 end
287
288 function min(val, min)
289 val = tonumber(val)
290 min = tonumber(min)
291
292 if val ~= nil and min ~= nil then
293 return (val >= min)
294 end
295
296 return false
297 end
298
299 function max(val, max)
300 val = tonumber(val)
301 max = tonumber(max)
302
303 if val ~= nil and max ~= nil then
304 return (val <= max)
305 end
306
307 return false
308 end