9f5a3eb1bfde8971185ad516f23942586cb97db6
[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 ip4addr(val)
70         if val then
71                 return ip.IPv4(val) and true or false
72         end
73
74         return false
75 end
76
77 function ip4prefix(val)
78         val = tonumber(val)
79         return ( val and val >= 0 and val <= 32 )
80 end
81
82 function ip6addr(val)
83         if val then
84                 return ip.IPv6(val) and true or false
85         end
86
87         return false
88 end
89
90 function ip6prefix(val)
91         val = tonumber(val)
92         return ( val and val >= 0 and val <= 128 )
93 end
94
95 function port(val)
96         val = tonumber(val)
97         return ( val and val >= 0 and val <= 65535 )
98 end
99
100 function portrange(val)
101         local p1, p2 = val:match("^(%d+)%-(%d+)$")
102         if p1 and p2 and port(p1) and port(p2) then
103                 return true
104         else
105                 return port(val)
106         end
107 end
108
109 function macaddr(val)
110         if val and val:match(
111                 "^[a-fA-F0-9]+:[a-fA-F0-9]+:[a-fA-F0-9]+:" ..
112                  "[a-fA-F0-9]+:[a-fA-F0-9]+:[a-fA-F0-9]+$"
113         ) then
114                 local parts = util.split( val, ":" )
115
116                 for i = 1,6 do
117                         parts[i] = tonumber( parts[i], 16 )
118                         if parts[i] < 0 or parts[i] > 255 then
119                                 return false
120                         end
121                 end
122
123                 return true
124         end
125
126         return false
127 end
128
129 function hostname(val)
130         if val and (#val < 254) and (
131            val:match("^[a-zA-Z]+$") or
132            (val:match("^[a-zA-Z0-9][a-zA-Z0-9%-%.]*[a-zA-Z0-9]$") and
133             val:match("[^0-9%.]"))
134         ) then
135                 return true
136         end
137         return false
138 end
139
140 function host(val)
141         return hostname(val) or ipaddr(val)
142 end
143
144 function network(val)
145         return uciname(val) or host(val)
146 end
147
148 function wpakey(val)
149         if #val == 64 then
150                 return (val:match("^[a-fA-F0-9]+$") ~= nil)
151         else
152                 return (#val >= 8) and (#val <= 63)
153         end
154 end
155
156 function wepkey(val)
157         if val:sub(1, 2) == "s:" then
158                 val = val:sub(3)
159         end
160
161         if (#val == 10) or (#val == 26) then
162                 return (val:match("^[a-fA-F0-9]+$") ~= nil)
163         else
164                 return (#val == 5) or (#val == 13)
165         end
166 end
167
168 function string(val)
169         return true             -- Everything qualifies as valid string
170 end
171
172 function directory( val, seen )
173         local s = fs.stat(val)
174         seen = seen or { }
175
176         if s and not seen[s.ino] then
177                 seen[s.ino] = true
178                 if s.type == "dir" then
179                         return true
180                 elseif s.type == "lnk" then
181                         return directory( fs.readlink(val), seen )
182                 end
183         end
184
185         return false
186 end
187
188 function file( val, seen )
189         local s = fs.stat(val)
190         seen = seen or { }
191
192         if s and not seen[s.ino] then
193                 seen[s.ino] = true
194                 if s.type == "reg" then
195                         return true
196                 elseif s.type == "lnk" then
197                         return file( fs.readlink(val), seen )
198                 end
199         end
200
201         return false
202 end
203
204 function device( val, seen )
205         local s = fs.stat(val)
206         seen = seen or { }
207
208         if s and not seen[s.ino] then
209                 seen[s.ino] = true
210                 if s.type == "chr" or s.type == "blk" then
211                         return true
212                 elseif s.type == "lnk" then
213                         return device( fs.readlink(val), seen )
214                 end
215         end
216
217         return false
218 end
219
220 function uciname(val)
221         return (val:match("^[a-zA-Z0-9_]+$") ~= nil)
222 end
223
224 function range(val, min, max)
225         val = tonumber(val)
226         min = tonumber(min)
227         max = tonumber(max)
228
229         if val ~= nil and min ~= nil and max ~= nil then
230                 return ((val >= min) and (val <= max))
231         end
232
233         return false
234 end
235
236 function min(val, min)
237         val = tonumber(val)
238         min = tonumber(min)
239
240         if val ~= nil and min ~= nil then
241                 return (val >= min)
242         end
243
244         return false
245 end
246
247 function max(val, max)
248         val = tonumber(val)
249         max = tonumber(max)
250
251         if val ~= nil and max ~= nil then
252                 return (val <= max)
253         end
254
255         return false
256 end
257
258 function neg(val, what)
259         if what and type(_M[what]) == "function" then
260                 return _M[what](val:gsub("^%s*!%s*", ""))
261         end
262
263         return false
264 end
265
266 function list(val, what, ...)
267         if type(val) == "string" and what and type(_M[what]) == "function" then
268                 for val in val:gmatch("%S+") do
269                         if not _M[what](val, ...) then
270                                 return false
271                         end
272                 end
273
274                 return true
275         end
276
277         return false
278 end