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