256 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Awk
		
	
	
	
	
	
			
		
		
	
	
			256 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Awk
		
	
	
	
	
	
| # 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=""
 | |
| 	}
 | |
| }
 | 
