From 9405a2a6be701ee92ad0ffbe15d069bdae2cf850 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 26 Feb 2007 20:04:04 +0000 Subject: Integrate basic UCI config file validation support Needs more testing and validation is not enforced yet Code contributed by Fraunhofer Fokus SVN-Revision: 6391 --- package/base-files/files/lib/config/parse_spec.awk | 255 +++++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 package/base-files/files/lib/config/parse_spec.awk (limited to 'package/base-files/files/lib/config/parse_spec.awk') diff --git a/package/base-files/files/lib/config/parse_spec.awk b/package/base-files/files/lib/config/parse_spec.awk new file mode 100644 index 0000000000..5eabc5ac95 --- /dev/null +++ b/package/base-files/files/lib/config/parse_spec.awk @@ -0,0 +1,255 @@ +# AWK file for parsing uci specification files +# +# Copyright (C) 2006 by Fokus Fraunhofer +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# +# general: unfortunately, the development was done using gawk providing +# a different match() functions than e.g. mawk on debian systems +# - therefore, the script was changed to run on most awk's +# - even things like [:space:] are not used +# +# - script parses the config section definition contained in one +# specification file +# global variables: +# * section - contains the current config section name +# * var - contains the name of the current config option +# * type - contains the type of the current config option +# * required - contains the requirements of the current config option +# * optional - contains the optional scope of the current config option +# * vars[] - array, contains the name of all config options valid within +# a certain config section, format: csv +# +# XXX todo: more than one config option with the same in different section +# will clash for the following tables +# * types[] - contains the type of a config option +# * reqs[] - contains the requirements of a config option +# * opts[] - contains the optional scope of a config option +# +BEGIN { + section_count=1 + section = "" + simple_types = "int|ip|netmask|string|wep|hostname|mac|port|ports|wpapsk" +} + +# function print_specification +# - prints all information about the created tables containing the +# specification +function print_specification() { + for (section in vars) { + printf("%s\n",section); + split(vars[section],arr,",") + for (idx in arr) { + printf("\t%s[%s]",arr[idx],types[section "_" arr[idx]]); + if (length(reqs[section "_" arr[idx]])) { + if (reqs[section "_" arr[idx]]==1) { + printf(",req"); + }else{ + printf(", req(%s)", reqs[section "_" arr[idx]]); + } + } + if (length(opts[section "_" arr[idx]])) { + printf(", opt(%s)", opts[section "_" arr[idx]]); + } + printf("\n"); + } + } +} + + +function reset_option() { + # just set global variables parsed on one line back to defaults + var = "" + type = "" + required = "" + optional = "" + found = 0 +} + +function store_option() { + # save all information about a config option parsed from the spec file + # to the relevant tables for future use + + # first check minimum requirements for storing information + if (!length(section)) { + print STDERR "line " NR ": section definition missing" + exit 1 + } + if (!length(var)) { + print STDERR "line " NR ": invalid config option name" + exit 1 + } + if (!length(type)) { + print STDERR "line " NR ": invalid config option type" + exit 1 + } + + # add config options to the names of options available for this + # section + if (exists[section]!=1) { + section_names[section_count] = section + section_count++ + exists[section] = 1 + vars[section] = var + } else { + vars[section] = vars[section] "," var + } + + # save the type, the requirements and the optional scope of the + # config option + types[section "_" var] = type + reqs[section "_" var] = required + opts[section "_" var] = optional +} + +/^declare -x|^export/ { + sub(/^declare -x /,"") + sub(/^export /,"") + split($0,arr,"=") + val=substr(arr[2],2,length(arr[2])-2) + ENVIRON[arr[1]] = val + next +} + +# main parsing function +# this is done in one function block to allow multiple semicolon separated +# definitions on one line +{ + # replace leading/trailing white space + gsub("^[ \t\n]+",""); + gsub("[ \t\n]+$",""); + + # comments are removed + # XXX todo: check for quoted comments?? + if (match($0,/[^#]*/)) { + rest=substr($0,RSTART,RLENGTH) + } else { + rest=$0 + } + + # match the config section "
{" + if (match(rest,/^[^ \t\n{]+[ \t\n]*\{/)) { + match(rest,/^[^ \t\n{]+/) + section = substr(rest,RSTART,RLENGTH) + rest=substr($0,RSTART+RLENGTH); + match(rest,/[ \t\n]*\{/) + rest=substr(rest,RSTART+RLENGTH) + # check for array indication + if (match(section,/\[[ \t\n]*\]/)) { + section=substr(section,1,RSTART-1) + multiple[section] = 1 + } else { + multiple[section] = 0 + } + } + + reset_option() + + # parse the remaing line as long as there is something to parse + while (rest ~ "[^ \t\n}]+") { + found = 0 + + # get option name and option type + # first, check for "simple" datatype definitions + if (match(rest,"[^: \t\n]+[ \t\n]*:[ \t\n]*(" \ + simple_types ")")){ + match(rest,"[^: \t\n]+") + var=substr(rest,RSTART,RLENGTH) + rest=substr(rest,RSTART+RLENGTH) + match(rest,"[ \t\n]*:[ \t\n]*") + rest=substr(rest,RSTART+RLENGTH) + match(rest,"(" simple_types ")") + type=substr(rest,RSTART,RLENGTH) + rest = substr(rest,RSTART+RLENGTH) + found = 1 + # next, check for enum definitions + } else if (match(rest,/[^: \t\n]+[ \t\n]*:[ \t\n]*enum\([^\)]+\)/ )) { + match(rest,"[^: \t\n]+") + var=substr(rest,RSTART,RLENGTH) + rest=substr(rest,RSTART+RLENGTH) + match(rest,/[ \t\n]*:[ \t\n]*enum\(/) + rest=substr(rest,RSTART+RLENGTH) + match(rest,/[^\)]+/) + type="enum," substr(rest,RSTART,RLENGTH) + rest = substr(rest,RSTART+RLENGTH+1) + found=1 + } + + # after the name and the type, + # get the option requirements/scope + if (match(rest,/[^,]*,[ \t\n]*required\[[^]]+\]/)) { + match(rest,"[^,]*") + save=substr(rest,RSTART,RLENGTH) + rest=substr(rest,RSTART+RLENGTH) + match(rest,/,[ \t\n]*required\[/); + rest=substr(rest,RSTART+RLENGTH) + match(rest,/[^]]+\]/) + required=substr(rest,RSTART,RLENGTH-1) + save=save substr(rest,RSTART+RLENGTH) + rest=save + found=1 + } else if (match(rest,/[^,]*,[ \t\n]*required/)) { + match(rest,"[^,]*") + save=substr(rest,RSTART,RLENGTH) + rest=substr(rest,RSTART+RLENGTH) + match(rest,",[ \t\n]*required"); + rest=substr(rest,RSTART+RLENGTH) + required=1 + save=save substr(rest,RSTART+RLENGTH) + rest=save + found=1 + } + if (match(rest,/[^,]*,[ \t\n]*optional\[[^]]+\]/)) { + match(rest,"[^,]*") + save=substr(rest,RSTART,RLENGTH) + rest=substr(rest,RSTART+RLENGTH) + match(rest,/,[ \t\n]*optional\[/); + rest=substr(rest,RSTART+RLENGTH) + match(rest,/[^]]+\]/) + optional=substr(rest,RSTART,RLENGTH-1) + save=save substr(rest,RSTART+RLENGTH) + rest=save + found=1 + } + + # if the remaining line contains a semicolon, complete the + # specification of the config options + if (match(rest, "^[ \t\n]*;(.*)")) { + match(rest,"^[ \t\n]*;") + rest=substr(rest,RSTART+RLENGTH) + if (found==1) { + store_option() + } + reset_option() + + # if nothing matched on this line, clear the rest + } else if (!found) { + rest = "" + } + } + + # after the line is pared, store the configuration option in the + # table if any has been defined + if (length(var)) { + store_option() + reset_option() + } + # close the section if the line contained a closing section bracket, + # XXX todo: check if this has to be done more intelligent + if ($0 ~ /\}/) { + section="" + } +} -- cgit v1.2.3