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