# AWK file for parsing uci specification files # # Copyright (C) 2006 by Fokus Fraunhofer <carsten.tittel@fokus.fraunhofer.de> # # 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 "<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="" } }