libs/web: add list(...) datatype for space separated lists of arbritary datatypes
[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-Z0-9]+$") or
146            val:match("^[a-zA-Z0-9][a-zA-Z0-9%-%.]*[a-zA-Z0-9]$")
147         ) then
148                 return true
149         end
150         return false
151 end
152
153 function host(val)
154         return hostname(val) or ipaddr(val)
155 end
156
157 function network(val)
158         return uciname(val) or host(val)
159 end
160
161 function wpakey(val)
162         if #val == 64 then
163                 return (val:match("^[a-fA-F0-9]+$") ~= nil)
164         else
165                 return (#val >= 8) and (#val <= 63)
166         end
167 end
168
169 function wepkey(val)
170         if val:sub(1, 2) == "s:" then
171                 val = val:sub(3)
172         end
173
174         if (#val == 10) or (#val == 26) then
175                 return (val:match("^[a-fA-F0-9]+$") ~= nil)
176         else
177                 return (#val == 5) or (#val == 13)
178         end
179 end
180
181 function string(val)
182         return true             -- Everything qualifies as valid string
183 end
184
185 function directory( val, seen )
186         local s = fs.stat(val)
187         seen = seen or { }
188
189         if s and not seen[s.ino] then
190                 seen[s.ino] = true
191                 if s.type == "dir" then
192                         return true
193                 elseif s.type == "lnk" then
194                         return directory( fs.readlink(val), seen )
195                 end
196         end
197
198         return false
199 end
200
201 function file( val, seen )
202         local s = fs.stat(val)
203         seen = seen or { }
204
205         if s and not seen[s.ino] then
206                 seen[s.ino] = true
207                 if s.type == "reg" then
208                         return true
209                 elseif s.type == "lnk" then
210                         return file( fs.readlink(val), seen )
211                 end
212         end
213
214         return false
215 end
216
217 function device( val, seen )
218         local s = fs.stat(val)
219         seen = seen or { }
220
221         if s and not seen[s.ino] then
222                 seen[s.ino] = true
223                 if s.type == "chr" or s.type == "blk" then
224                         return true
225                 elseif s.type == "lnk" then
226                         return device( fs.readlink(val), seen )
227                 end
228         end
229
230         return false
231 end
232
233 function uciname(val)
234         return (val:match("^[a-zA-Z0-9_]+$") ~= nil)
235 end
236
237 function neg_network_ip4addr(val)
238         if type(v) == "string" then
239                 v = v:gsub("^%s*!", "")
240                 return (uciname(v) or ip4addr(v))
241         end     
242 end
243
244 function range(val, min, max)
245         val = tonumber(val)
246         min = tonumber(min)
247         max = tonumber(max)
248
249         if val ~= nil and min ~= nil and max ~= nil then
250                 return ((val >= min) and (val <= max))
251         end
252
253         return false
254 end
255
256 function min(val, min)
257         val = tonumber(val)
258         min = tonumber(min)
259
260         if val ~= nil and min ~= nil then
261                 return (val >= min)
262         end
263
264         return false
265 end
266
267 function max(val, max)
268         val = tonumber(val)
269         max = tonumber(max)
270
271         if val ~= nil and max ~= nil then
272                 return (val <= max)
273         end
274
275         return false
276 end
277
278 function neg(val, what)
279         if what and type(_M[what]) == "function" then
280                 return _M[what](val:gsub("^%s*!%s*", ""))
281         end
282
283         return false
284 end
285
286 function list(val, what, ...)
287         if type(val) == "string" and what and type(_M[what]) == "function" then
288                 for val in val:gmatch("%S+") do
289                         if not _M[what](val, ...) then
290                                 return false
291                         end
292                 end
293
294                 return true
295         end
296
297         return false
298 end