summaryrefslogtreecommitdiff
path: root/package/base-files/files/lib/config/parse_spec.awk
blob: 5eabc5ac95b8cdf0b7dd5b47bf325ce872a9054e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
# 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=""
	}
}