1
0
mirror of https://github.com/elua/elua.git synced 2025-01-08 20:56:17 +08:00
elua/config/attributes.lua
Bogdan Marinescu 400ab5bee5 Support for multiple SD cards added in the configurator
Documentation updated.
2013-05-25 14:18:32 +03:00

222 lines
8.6 KiB
Lua

-- Attributes are used by various parts of the board description
-- system (for example configs and components)
module( ..., package.seeall )
local ct = require "constants"
local sf = string.format
-- Validator for a 'choice' attribute
-- Returns the value if OK, (false, errmsg) for error
-- Needs: attrvals - list of permitted values for this attribute
local function _validate_choice( adesc, aname, aval, elname, sectname )
aval = tostring( aval ):lower()
for k, v in pairs( adesc.attrvals ) do
if v == aval then return v end
end
return false, sf( "invalid value '%s' for attribute '%s' of element '%s' in section '%s'", aval, aname, elname, sectname )
end
-- Validator for a 'number' attribute
-- Returns the value if OK, (false, errmsg) for error
-- Needs: attrtype - the number type ('int' or 'float')
-- attrmin - minimum value (no minimum check will be performed if not specified)
-- attrmax - maximum value (no maximum check will be performed if not specified)
-- allow_string - allows this number to also be a string
local function _validate_number( adesc, aname, _aval, elname, sectname )
local aval = tonumber( _aval )
if not aval then
if type( _aval ) == "string" and adesc.allow_string then
return _aval
else
return false, sf( "value of attribute '%s' for element '%s' in section '%s' must be a number", aname, elname, sectname ) end
end
if adesc.attrtype == 'int' and math.floor( aval ) ~= aval then
return false, sf( "value of attribute '%s' for element '%s' in section '%s' must be an integer", aname, elname, sectname )
end
local minval = adesc.attrmin or aval
local maxval = adesc.attrmax or aval
if aval < minval then
return false, sf( "value of attribute '%s' for element '%s' in section '%s' must be larger than '%s'", aname, elname, sectname, tostring( minval ) )
end
if aval > maxval then
return false, sf( "value of attribute '%s' for element '%s' in section '%s' must be smaller than '%s'", aname, elname, sectname, tostring( maxval ) )
end
return aval
end
-- Validator for a log2 number attribute
-- Works like number, but additionaly checks that the value is a power of 2
-- Also changes the attribute value to its log2
local function _validate_log2( adesc, aname, aval, elname, sectname )
local res, err = _validate_number( adesc, aname, aval, elname, sectname )
if not res then return res, err end
if adesc.allow_string and not tonumber( res ) and type( res ) == "string" then return res end
if aval <= 0 then
return false, sf( "value of attribute '%s' for element '%s' in section '%s' must be larger than 0", aname, elname, sectname )
end
local thelog = math.log( res ) / math.log( 2 )
if thelog ~= math.floor( thelog ) then
return false, sf( "value of attribute '%s' for element '%s' in section '%s' must be a power of 2", aname, elname, sectname )
end
return thelog
end
-- Validator for a string attribute
-- Return the string if OK, (false, errmsg) for error
-- Needs: attrmaxsize - maximum size of the string
local function _validate_string( adesc, aname, aval, elname, sectname )
if type( aval ) ~= "string" then
return false, sf( "value of attribute '%s' for element '%s' in section '%s' must be a string", aname, elname, sectname )
end
maxsize = adesc.attrmaxsize or math.huge
if #aval > maxsize then
return false, sf( "value of attribute '%s' for element '%s' in section '%s' must be less than %d chars in length", aname, elname, sectname, maxsize )
end
return aval
end
-- Validator for an IP attribute
-- Return the IP as a table of numbers if OK, (false, errmsg) for error
local function _validate_ip( adesc, aname, aval, elname, sectname )
if type( aval ) == "string" then -- transform this to table
if aval:sub( -1, -1 ) ~= "." then aval = aval .. "." end -- add a final dot to make parsing easier
local t = {}
for w in aval:gmatch( "(%w+)%." ) do t[ #t + 1 ] = tonumber( w ) end
aval = t
elseif type( aval ) ~= "table" then
return false, sf( "attribute '%s' of element '%s' in section '%s' must be a string or a table", aname, elname, sectname )
end
if #aval ~= 4 then return false, sf( "invalid IP for attribute '%s' of element '%s' in section '%s'", aname, elname, sectname ) end
for i = 1, 4 do
local e = aval[ i ]
if type( e ) ~= "number" or math.floor( e ) ~= e or e < 0 or e > 255 then
return false, sf( "invalid IP for attribute '%s' of element '%s' in section '%s'", aname, elname, sectname )
end
end
return aval
end
-- Builds a validator with the given array element checker
local function build_validator( realvname )
return function( adesc, aname, aval, elname, sectname )
if not adesc.is_array then return realvname( adesc, aname, aval, elname, sectname ) end
if type( aval ) ~= "table" then
if adesc.allow_single then
aval = { aval }
else
return false, sf( "value of attribute '%s' for element '%s' in section '%s' must be an array", aname, elname, sectname )
end
end
for i = 1, #aval do
local res, err = realvname( adesc, aname, aval[ i ], elname, sectname )
if not res then
return false, sf( "error at index %d: %s", i, err )
else
aval[ i ] = res
end
end
return aval
end
end
local validate_number = build_validator( _validate_number )
local validate_choice = build_validator( _validate_choice )
local validate_log2 = build_validator( _validate_log2 )
local validate_string = build_validator( _validate_string )
local validate_ip = build_validator( _validate_ip )
-- Composite validator: run each validator in turn
local function composite_validator( adesc, aname, aval, elname, sectname )
for _, onedesc in pairs( adesc.attrs ) do
onedesc.is_array, onedesc.allow_single = adesc.is_array, onedesc.allow_single
local res, err = onedesc.validator( onedesc, aname, aval, elname, sectname )
if res then return res end
end
return false, sf( "Invalid value '%s' for attribute '%s' of element '%s' in section '%s'", tostring( aval ), aname, elname, sectname )
end
-------------------------------------------------------------------------------
-- Public interface
-- Returns a new choice attribute with the given possible values
function choice_attr( macro, values, default )
return { macro = macro, default = default, validator = validate_choice, attrvals = values }
end
-- Returns a new timer attribute with the given macro and default (systmr if not specified)
function timer_attr( macro, default )
default = default or 'systmr'
local t = choice_attr( macro, utils.table_keys( ct.timer_values ), default )
t.is_timer, t.mapping = true, ct.timer_values
return t
end
-- Returns a new integer number attribute with the given limits
function int_attr( macro, minv, maxv, default )
return { macro = macro, default = default, validator = validate_number, attrtype = 'int', attrmin = minv, attrmax = maxv, allow_string = true }
end
-- Returns a new UART attribute
function uart_attr( macro, default )
local t = choice_attr( macro, utils.table_keys( ct.uart_values ), default )
t.is_uart, t.mapping = true, ct.uart_values
return t
end
-- Returns a new integer number attribute with the given limits
-- The generated value will be the integer's base 2 logarithm
function int_log2_attr( macro, minv, maxv, default )
local t = int_attr( macro, minv, maxv, default )
t.validator = validate_log2
return t
end
-- Returns a new flow control attribute
function flow_control_attr( macro, default )
default = default or 'none'
local t = choice_attr( macro, utils.table_keys( ct.uart_flow ), default )
t.mapping = ct.uart_flow
return t
end
-- Returns a new string attribute
function string_attr( macro, maxsize, default )
return { macro = macro, default = default, validator = validate_string, attrmaxsize = maxsize }
end
-- Returns a new IP attribute
function ip_attr( macro, default )
return { macro = macro, default = default, validator = validate_ip, is_ip = true }
end
-- Returns a new combined attribute
function combine_attr( macro, attrs )
return { macro = macro, validator = composite_validator, attrs = attrs }
end
-- Make the given attribute optional
function make_optional( attr )
attr.optional = true
return attr
end
-- Mark the given attribute as an array of element of the same type
function array_of( attr, allow_single )
attr.is_array = true
attr.allow_single = allow_single
return attr
end
-- Bypass the validator of a given attribute
function dont_validate( attr )
attr.validator = function( adesc, aname, aval, elname, sectname ) return aval end
return attr
end
-- Removes the string option from the given number attribute
function nostr( attr )
attr.allow_string = false
return attr
end