xref: /minix3/external/bsd/dhcp/dist/common/parse.c (revision 83ee113ee0d94f3844d44065af2311604e9a30ad)
1*83ee113eSDavid van Moolenbroek /*	$NetBSD: parse.c,v 1.1.1.3 2014/07/12 11:57:41 spz Exp $	*/
2*83ee113eSDavid van Moolenbroek /* parse.c
3*83ee113eSDavid van Moolenbroek 
4*83ee113eSDavid van Moolenbroek    Common parser code for dhcpd and dhclient. */
5*83ee113eSDavid van Moolenbroek 
6*83ee113eSDavid van Moolenbroek /*
7*83ee113eSDavid van Moolenbroek  * Copyright (c) 2004-2014 by Internet Systems Consortium, Inc. ("ISC")
8*83ee113eSDavid van Moolenbroek  * Copyright (c) 1995-2003 by Internet Software Consortium
9*83ee113eSDavid van Moolenbroek  *
10*83ee113eSDavid van Moolenbroek  * Permission to use, copy, modify, and distribute this software for any
11*83ee113eSDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the above
12*83ee113eSDavid van Moolenbroek  * copyright notice and this permission notice appear in all copies.
13*83ee113eSDavid van Moolenbroek  *
14*83ee113eSDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15*83ee113eSDavid van Moolenbroek  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16*83ee113eSDavid van Moolenbroek  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
17*83ee113eSDavid van Moolenbroek  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18*83ee113eSDavid van Moolenbroek  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19*83ee113eSDavid van Moolenbroek  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20*83ee113eSDavid van Moolenbroek  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21*83ee113eSDavid van Moolenbroek  *
22*83ee113eSDavid van Moolenbroek  *   Internet Systems Consortium, Inc.
23*83ee113eSDavid van Moolenbroek  *   950 Charter Street
24*83ee113eSDavid van Moolenbroek  *   Redwood City, CA 94063
25*83ee113eSDavid van Moolenbroek  *   <info@isc.org>
26*83ee113eSDavid van Moolenbroek  *   https://www.isc.org/
27*83ee113eSDavid van Moolenbroek  *
28*83ee113eSDavid van Moolenbroek  */
29*83ee113eSDavid van Moolenbroek 
30*83ee113eSDavid van Moolenbroek #include <sys/cdefs.h>
31*83ee113eSDavid van Moolenbroek __RCSID("$NetBSD: parse.c,v 1.1.1.3 2014/07/12 11:57:41 spz Exp $");
32*83ee113eSDavid van Moolenbroek 
33*83ee113eSDavid van Moolenbroek #include "dhcpd.h"
34*83ee113eSDavid van Moolenbroek #include <syslog.h>
35*83ee113eSDavid van Moolenbroek 
36*83ee113eSDavid van Moolenbroek /* Enumerations can be specified in option formats, and are used for
37*83ee113eSDavid van Moolenbroek    parsing, so we define the routines that manage them here. */
38*83ee113eSDavid van Moolenbroek 
39*83ee113eSDavid van Moolenbroek struct enumeration *enumerations;
40*83ee113eSDavid van Moolenbroek 
add_enumeration(struct enumeration * enumeration)41*83ee113eSDavid van Moolenbroek void add_enumeration (struct enumeration *enumeration)
42*83ee113eSDavid van Moolenbroek {
43*83ee113eSDavid van Moolenbroek 	enumeration -> next = enumerations;
44*83ee113eSDavid van Moolenbroek 	enumerations = enumeration;
45*83ee113eSDavid van Moolenbroek }
46*83ee113eSDavid van Moolenbroek 
find_enumeration(const char * name,int length)47*83ee113eSDavid van Moolenbroek struct enumeration *find_enumeration (const char *name, int length)
48*83ee113eSDavid van Moolenbroek {
49*83ee113eSDavid van Moolenbroek 	struct enumeration *e;
50*83ee113eSDavid van Moolenbroek 
51*83ee113eSDavid van Moolenbroek 	for (e = enumerations; e; e = e -> next)
52*83ee113eSDavid van Moolenbroek 		if (strlen (e -> name) == length &&
53*83ee113eSDavid van Moolenbroek 		    !memcmp (e -> name, name, (unsigned)length))
54*83ee113eSDavid van Moolenbroek 			return e;
55*83ee113eSDavid van Moolenbroek 	return (struct enumeration *)0;
56*83ee113eSDavid van Moolenbroek }
57*83ee113eSDavid van Moolenbroek 
find_enumeration_value(const char * name,int length,unsigned * widthp,const char * value)58*83ee113eSDavid van Moolenbroek struct enumeration_value *find_enumeration_value (const char *name,
59*83ee113eSDavid van Moolenbroek 						  int length,
60*83ee113eSDavid van Moolenbroek 						  unsigned *widthp,
61*83ee113eSDavid van Moolenbroek 						  const char *value)
62*83ee113eSDavid van Moolenbroek {
63*83ee113eSDavid van Moolenbroek 	struct enumeration *e;
64*83ee113eSDavid van Moolenbroek 	int i;
65*83ee113eSDavid van Moolenbroek 
66*83ee113eSDavid van Moolenbroek 	e = find_enumeration (name, length);
67*83ee113eSDavid van Moolenbroek 	if (e) {
68*83ee113eSDavid van Moolenbroek 		if (widthp != NULL)
69*83ee113eSDavid van Moolenbroek 			*widthp = e->width;
70*83ee113eSDavid van Moolenbroek 		for (i = 0; e -> values [i].name; i++) {
71*83ee113eSDavid van Moolenbroek 			if (!strcmp (value, e -> values [i].name))
72*83ee113eSDavid van Moolenbroek 				return &e -> values [i];
73*83ee113eSDavid van Moolenbroek 		}
74*83ee113eSDavid van Moolenbroek 	}
75*83ee113eSDavid van Moolenbroek 	return (struct enumeration_value *)0;
76*83ee113eSDavid van Moolenbroek }
77*83ee113eSDavid van Moolenbroek 
78*83ee113eSDavid van Moolenbroek /* Skip to the semicolon ending the current statement.   If we encounter
79*83ee113eSDavid van Moolenbroek    braces, the matching closing brace terminates the statement.   If we
80*83ee113eSDavid van Moolenbroek    encounter a right brace but haven't encountered a left brace, return
81*83ee113eSDavid van Moolenbroek    leaving the brace in the token buffer for the caller.   If we see a
82*83ee113eSDavid van Moolenbroek    semicolon and haven't seen a left brace, return.   This lets us skip
83*83ee113eSDavid van Moolenbroek    over:
84*83ee113eSDavid van Moolenbroek 
85*83ee113eSDavid van Moolenbroek    	statement;
86*83ee113eSDavid van Moolenbroek 	statement foo bar { }
87*83ee113eSDavid van Moolenbroek 	statement foo bar { statement { } }
88*83ee113eSDavid van Moolenbroek 	statement}
89*83ee113eSDavid van Moolenbroek 
90*83ee113eSDavid van Moolenbroek 	...et cetera. */
91*83ee113eSDavid van Moolenbroek 
skip_to_semi(cfile)92*83ee113eSDavid van Moolenbroek void skip_to_semi (cfile)
93*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
94*83ee113eSDavid van Moolenbroek {
95*83ee113eSDavid van Moolenbroek 	skip_to_rbrace (cfile, 0);
96*83ee113eSDavid van Moolenbroek }
97*83ee113eSDavid van Moolenbroek 
skip_to_rbrace(cfile,brace_count)98*83ee113eSDavid van Moolenbroek void skip_to_rbrace (cfile, brace_count)
99*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
100*83ee113eSDavid van Moolenbroek 	int brace_count;
101*83ee113eSDavid van Moolenbroek {
102*83ee113eSDavid van Moolenbroek 	enum dhcp_token token;
103*83ee113eSDavid van Moolenbroek 	const char *val;
104*83ee113eSDavid van Moolenbroek 
105*83ee113eSDavid van Moolenbroek #if defined (DEBUG_TOKEN)
106*83ee113eSDavid van Moolenbroek 	log_error ("skip_to_rbrace: %d\n", brace_count);
107*83ee113eSDavid van Moolenbroek #endif
108*83ee113eSDavid van Moolenbroek 	do {
109*83ee113eSDavid van Moolenbroek 		token = peek_token (&val, (unsigned *)0, cfile);
110*83ee113eSDavid van Moolenbroek 		if (token == RBRACE) {
111*83ee113eSDavid van Moolenbroek 			skip_token(&val, (unsigned *)0, cfile);
112*83ee113eSDavid van Moolenbroek 			if (brace_count) {
113*83ee113eSDavid van Moolenbroek 				if (!--brace_count)
114*83ee113eSDavid van Moolenbroek 					return;
115*83ee113eSDavid van Moolenbroek 			} else
116*83ee113eSDavid van Moolenbroek 				return;
117*83ee113eSDavid van Moolenbroek 		} else if (token == LBRACE) {
118*83ee113eSDavid van Moolenbroek 			brace_count++;
119*83ee113eSDavid van Moolenbroek 		} else if (token == SEMI && !brace_count) {
120*83ee113eSDavid van Moolenbroek 			skip_token(&val, (unsigned *)0, cfile);
121*83ee113eSDavid van Moolenbroek 			return;
122*83ee113eSDavid van Moolenbroek 		} else if (token == EOL) {
123*83ee113eSDavid van Moolenbroek 			/* EOL only happens when parsing /etc/resolv.conf,
124*83ee113eSDavid van Moolenbroek 			   and we treat it like a semicolon because the
125*83ee113eSDavid van Moolenbroek 			   resolv.conf file is line-oriented. */
126*83ee113eSDavid van Moolenbroek 			skip_token(&val, (unsigned *)0, cfile);
127*83ee113eSDavid van Moolenbroek 			return;
128*83ee113eSDavid van Moolenbroek 		}
129*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
130*83ee113eSDavid van Moolenbroek 	} while (token != END_OF_FILE);
131*83ee113eSDavid van Moolenbroek }
132*83ee113eSDavid van Moolenbroek 
parse_semi(cfile)133*83ee113eSDavid van Moolenbroek int parse_semi (cfile)
134*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
135*83ee113eSDavid van Moolenbroek {
136*83ee113eSDavid van Moolenbroek 	enum dhcp_token token;
137*83ee113eSDavid van Moolenbroek 	const char *val;
138*83ee113eSDavid van Moolenbroek 
139*83ee113eSDavid van Moolenbroek 	token = next_token (&val, (unsigned *)0, cfile);
140*83ee113eSDavid van Moolenbroek 	if (token != SEMI) {
141*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "semicolon expected.");
142*83ee113eSDavid van Moolenbroek 		skip_to_semi (cfile);
143*83ee113eSDavid van Moolenbroek 		return 0;
144*83ee113eSDavid van Moolenbroek 	}
145*83ee113eSDavid van Moolenbroek 	return 1;
146*83ee113eSDavid van Moolenbroek }
147*83ee113eSDavid van Moolenbroek 
148*83ee113eSDavid van Moolenbroek /* string-parameter :== STRING SEMI */
149*83ee113eSDavid van Moolenbroek 
parse_string(cfile,sptr,lptr)150*83ee113eSDavid van Moolenbroek int parse_string (cfile, sptr, lptr)
151*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
152*83ee113eSDavid van Moolenbroek 	char **sptr;
153*83ee113eSDavid van Moolenbroek 	unsigned *lptr;
154*83ee113eSDavid van Moolenbroek {
155*83ee113eSDavid van Moolenbroek 	const char *val;
156*83ee113eSDavid van Moolenbroek 	enum dhcp_token token;
157*83ee113eSDavid van Moolenbroek 	char *s;
158*83ee113eSDavid van Moolenbroek 	unsigned len;
159*83ee113eSDavid van Moolenbroek 
160*83ee113eSDavid van Moolenbroek 	token = next_token (&val, &len, cfile);
161*83ee113eSDavid van Moolenbroek 	if (token != STRING) {
162*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "expecting a string");
163*83ee113eSDavid van Moolenbroek 		skip_to_semi (cfile);
164*83ee113eSDavid van Moolenbroek 		return 0;
165*83ee113eSDavid van Moolenbroek 	}
166*83ee113eSDavid van Moolenbroek 	s = (char *)dmalloc (len + 1, MDL);
167*83ee113eSDavid van Moolenbroek 	if (!s)
168*83ee113eSDavid van Moolenbroek 		log_fatal ("no memory for string %s.", val);
169*83ee113eSDavid van Moolenbroek 	memcpy (s, val, len + 1);
170*83ee113eSDavid van Moolenbroek 
171*83ee113eSDavid van Moolenbroek 	if (!parse_semi (cfile)) {
172*83ee113eSDavid van Moolenbroek 		dfree (s, MDL);
173*83ee113eSDavid van Moolenbroek 		return 0;
174*83ee113eSDavid van Moolenbroek 	}
175*83ee113eSDavid van Moolenbroek 	if (sptr)
176*83ee113eSDavid van Moolenbroek 		*sptr = s;
177*83ee113eSDavid van Moolenbroek 	else
178*83ee113eSDavid van Moolenbroek 		dfree (s, MDL);
179*83ee113eSDavid van Moolenbroek 	if (lptr)
180*83ee113eSDavid van Moolenbroek 		*lptr = len;
181*83ee113eSDavid van Moolenbroek 	return 1;
182*83ee113eSDavid van Moolenbroek }
183*83ee113eSDavid van Moolenbroek 
184*83ee113eSDavid van Moolenbroek /*
185*83ee113eSDavid van Moolenbroek  * hostname :== IDENTIFIER
186*83ee113eSDavid van Moolenbroek  *		| IDENTIFIER DOT
187*83ee113eSDavid van Moolenbroek  *		| hostname DOT IDENTIFIER
188*83ee113eSDavid van Moolenbroek  */
189*83ee113eSDavid van Moolenbroek 
parse_host_name(cfile)190*83ee113eSDavid van Moolenbroek char *parse_host_name (cfile)
191*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
192*83ee113eSDavid van Moolenbroek {
193*83ee113eSDavid van Moolenbroek 	const char *val;
194*83ee113eSDavid van Moolenbroek 	enum dhcp_token token;
195*83ee113eSDavid van Moolenbroek 	unsigned len = 0;
196*83ee113eSDavid van Moolenbroek 	char *s;
197*83ee113eSDavid van Moolenbroek 	char *t;
198*83ee113eSDavid van Moolenbroek 	pair c = (pair)0;
199*83ee113eSDavid van Moolenbroek 	int ltid = 0;
200*83ee113eSDavid van Moolenbroek 
201*83ee113eSDavid van Moolenbroek 	/* Read a dotted hostname... */
202*83ee113eSDavid van Moolenbroek 	do {
203*83ee113eSDavid van Moolenbroek 		/* Read a token, which should be an identifier. */
204*83ee113eSDavid van Moolenbroek 		token = peek_token (&val, (unsigned *)0, cfile);
205*83ee113eSDavid van Moolenbroek 		if (!is_identifier (token) && token != NUMBER)
206*83ee113eSDavid van Moolenbroek 			break;
207*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
208*83ee113eSDavid van Moolenbroek 
209*83ee113eSDavid van Moolenbroek 		/* Store this identifier... */
210*83ee113eSDavid van Moolenbroek 		if (!(s = (char *)dmalloc (strlen (val) + 1, MDL)))
211*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate temp space for hostname.");
212*83ee113eSDavid van Moolenbroek 		strcpy (s, val);
213*83ee113eSDavid van Moolenbroek 		c = cons ((caddr_t)s, c);
214*83ee113eSDavid van Moolenbroek 		len += strlen (s) + 1;
215*83ee113eSDavid van Moolenbroek 		/* Look for a dot; if it's there, keep going, otherwise
216*83ee113eSDavid van Moolenbroek 		   we're done. */
217*83ee113eSDavid van Moolenbroek 		token = peek_token (&val, (unsigned *)0, cfile);
218*83ee113eSDavid van Moolenbroek 		if (token == DOT) {
219*83ee113eSDavid van Moolenbroek 			token = next_token (&val, (unsigned *)0, cfile);
220*83ee113eSDavid van Moolenbroek 			ltid = 1;
221*83ee113eSDavid van Moolenbroek 		} else
222*83ee113eSDavid van Moolenbroek 			ltid = 0;
223*83ee113eSDavid van Moolenbroek 	} while (token == DOT);
224*83ee113eSDavid van Moolenbroek 
225*83ee113eSDavid van Moolenbroek 	/* Should be at least one token. */
226*83ee113eSDavid van Moolenbroek 	if (!len)
227*83ee113eSDavid van Moolenbroek 		return (char *)0;
228*83ee113eSDavid van Moolenbroek 
229*83ee113eSDavid van Moolenbroek 	/* Assemble the hostname together into a string. */
230*83ee113eSDavid van Moolenbroek 	if (!(s = (char *)dmalloc (len + ltid, MDL)))
231*83ee113eSDavid van Moolenbroek 		log_fatal ("can't allocate space for hostname.");
232*83ee113eSDavid van Moolenbroek 	t = s + len + ltid;
233*83ee113eSDavid van Moolenbroek 	*--t = 0;
234*83ee113eSDavid van Moolenbroek 	if (ltid)
235*83ee113eSDavid van Moolenbroek 		*--t = '.';
236*83ee113eSDavid van Moolenbroek 	while (c) {
237*83ee113eSDavid van Moolenbroek 		pair cdr = c -> cdr;
238*83ee113eSDavid van Moolenbroek 		unsigned l = strlen ((char *)(c -> car));
239*83ee113eSDavid van Moolenbroek 		t -= l;
240*83ee113eSDavid van Moolenbroek 		memcpy (t, (char *)(c -> car), l);
241*83ee113eSDavid van Moolenbroek 		/* Free up temp space. */
242*83ee113eSDavid van Moolenbroek 		dfree (c -> car, MDL);
243*83ee113eSDavid van Moolenbroek 		dfree (c, MDL);
244*83ee113eSDavid van Moolenbroek 		c = cdr;
245*83ee113eSDavid van Moolenbroek 		if (t != s)
246*83ee113eSDavid van Moolenbroek 			*--t = '.';
247*83ee113eSDavid van Moolenbroek 	}
248*83ee113eSDavid van Moolenbroek 	return s;
249*83ee113eSDavid van Moolenbroek }
250*83ee113eSDavid van Moolenbroek 
251*83ee113eSDavid van Moolenbroek /* ip-addr-or-hostname :== ip-address | hostname
252*83ee113eSDavid van Moolenbroek    ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER
253*83ee113eSDavid van Moolenbroek 
254*83ee113eSDavid van Moolenbroek    Parse an ip address or a hostname.   If uniform is zero, put in
255*83ee113eSDavid van Moolenbroek    an expr_substring node to limit hostnames that evaluate to more
256*83ee113eSDavid van Moolenbroek    than one IP address.
257*83ee113eSDavid van Moolenbroek 
258*83ee113eSDavid van Moolenbroek    Note that RFC1123 permits hostnames to consist of all digits,
259*83ee113eSDavid van Moolenbroek    making it difficult to quickly disambiguate them from ip addresses.
260*83ee113eSDavid van Moolenbroek */
261*83ee113eSDavid van Moolenbroek 
parse_ip_addr_or_hostname(expr,cfile,uniform)262*83ee113eSDavid van Moolenbroek int parse_ip_addr_or_hostname (expr, cfile, uniform)
263*83ee113eSDavid van Moolenbroek 	struct expression **expr;
264*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
265*83ee113eSDavid van Moolenbroek 	int uniform;
266*83ee113eSDavid van Moolenbroek {
267*83ee113eSDavid van Moolenbroek 	const char *val;
268*83ee113eSDavid van Moolenbroek 	enum dhcp_token token;
269*83ee113eSDavid van Moolenbroek 	unsigned char addr [4];
270*83ee113eSDavid van Moolenbroek 	unsigned len = sizeof addr;
271*83ee113eSDavid van Moolenbroek 	char *name;
272*83ee113eSDavid van Moolenbroek 	struct expression *x = (struct expression *)0;
273*83ee113eSDavid van Moolenbroek 	int ipaddr = 0;
274*83ee113eSDavid van Moolenbroek 
275*83ee113eSDavid van Moolenbroek 	token = peek_token (&val, (unsigned *)0, cfile);
276*83ee113eSDavid van Moolenbroek 
277*83ee113eSDavid van Moolenbroek 	if (token == NUMBER) {
278*83ee113eSDavid van Moolenbroek 		/*
279*83ee113eSDavid van Moolenbroek 		 * a hostname may be numeric, but domain names must
280*83ee113eSDavid van Moolenbroek 		 * start with a letter, so we can disambiguate by
281*83ee113eSDavid van Moolenbroek 		 * looking ahead a few tokens.  we save the parse
282*83ee113eSDavid van Moolenbroek 		 * context first, and restore it after we know what
283*83ee113eSDavid van Moolenbroek 		 * we're dealing with.
284*83ee113eSDavid van Moolenbroek 		 */
285*83ee113eSDavid van Moolenbroek 		save_parse_state(cfile);
286*83ee113eSDavid van Moolenbroek 		skip_token(NULL, NULL, cfile);
287*83ee113eSDavid van Moolenbroek 		if (next_token(NULL, NULL, cfile) == DOT &&
288*83ee113eSDavid van Moolenbroek 		    next_token(NULL, NULL, cfile) == NUMBER)
289*83ee113eSDavid van Moolenbroek 			ipaddr = 1;
290*83ee113eSDavid van Moolenbroek 		restore_parse_state(cfile);
291*83ee113eSDavid van Moolenbroek 
292*83ee113eSDavid van Moolenbroek 		if (ipaddr &&
293*83ee113eSDavid van Moolenbroek 		    parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
294*83ee113eSDavid van Moolenbroek 			return make_const_data (expr, addr, len, 0, 1, MDL);
295*83ee113eSDavid van Moolenbroek 
296*83ee113eSDavid van Moolenbroek 	}
297*83ee113eSDavid van Moolenbroek 
298*83ee113eSDavid van Moolenbroek 	if (is_identifier (token) || token == NUMBER) {
299*83ee113eSDavid van Moolenbroek 		name = parse_host_name (cfile);
300*83ee113eSDavid van Moolenbroek 		if (!name)
301*83ee113eSDavid van Moolenbroek 			return 0;
302*83ee113eSDavid van Moolenbroek 		if (!make_host_lookup (expr, name)) {
303*83ee113eSDavid van Moolenbroek 			dfree(name, MDL);
304*83ee113eSDavid van Moolenbroek 			return 0;
305*83ee113eSDavid van Moolenbroek 		}
306*83ee113eSDavid van Moolenbroek 		dfree(name, MDL);
307*83ee113eSDavid van Moolenbroek 		if (!uniform) {
308*83ee113eSDavid van Moolenbroek 			if (!make_limit (&x, *expr, 4))
309*83ee113eSDavid van Moolenbroek 				return 0;
310*83ee113eSDavid van Moolenbroek 			expression_dereference (expr, MDL);
311*83ee113eSDavid van Moolenbroek 			*expr = x;
312*83ee113eSDavid van Moolenbroek 		}
313*83ee113eSDavid van Moolenbroek 	} else {
314*83ee113eSDavid van Moolenbroek 		if (token != RBRACE && token != LBRACE)
315*83ee113eSDavid van Moolenbroek 			token = next_token (&val, (unsigned *)0, cfile);
316*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "%s (%d): expecting IP address or hostname",
317*83ee113eSDavid van Moolenbroek 			    val, token);
318*83ee113eSDavid van Moolenbroek 		if (token != SEMI)
319*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
320*83ee113eSDavid van Moolenbroek 		return 0;
321*83ee113eSDavid van Moolenbroek 	}
322*83ee113eSDavid van Moolenbroek 
323*83ee113eSDavid van Moolenbroek 	return 1;
324*83ee113eSDavid van Moolenbroek }
325*83ee113eSDavid van Moolenbroek 
326*83ee113eSDavid van Moolenbroek /*
327*83ee113eSDavid van Moolenbroek  * ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER
328*83ee113eSDavid van Moolenbroek  */
329*83ee113eSDavid van Moolenbroek 
parse_ip_addr(cfile,addr)330*83ee113eSDavid van Moolenbroek int parse_ip_addr (cfile, addr)
331*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
332*83ee113eSDavid van Moolenbroek 	struct iaddr *addr;
333*83ee113eSDavid van Moolenbroek {
334*83ee113eSDavid van Moolenbroek 	addr -> len = 4;
335*83ee113eSDavid van Moolenbroek 	if (parse_numeric_aggregate (cfile, addr -> iabuf,
336*83ee113eSDavid van Moolenbroek 				     &addr -> len, DOT, 10, 8))
337*83ee113eSDavid van Moolenbroek 		return 1;
338*83ee113eSDavid van Moolenbroek 	return 0;
339*83ee113eSDavid van Moolenbroek }
340*83ee113eSDavid van Moolenbroek 
341*83ee113eSDavid van Moolenbroek /*
342*83ee113eSDavid van Moolenbroek  * Return true if every character in the string is hexadecimal.
343*83ee113eSDavid van Moolenbroek  */
344*83ee113eSDavid van Moolenbroek static int
is_hex_string(const char * s)345*83ee113eSDavid van Moolenbroek is_hex_string(const char *s) {
346*83ee113eSDavid van Moolenbroek 	while (*s != '\0') {
347*83ee113eSDavid van Moolenbroek 		if (!isxdigit((int)*s)) {
348*83ee113eSDavid van Moolenbroek 			return 0;
349*83ee113eSDavid van Moolenbroek 		}
350*83ee113eSDavid van Moolenbroek 		s++;
351*83ee113eSDavid van Moolenbroek 	}
352*83ee113eSDavid van Moolenbroek 	return 1;
353*83ee113eSDavid van Moolenbroek }
354*83ee113eSDavid van Moolenbroek 
355*83ee113eSDavid van Moolenbroek /*
356*83ee113eSDavid van Moolenbroek  * ip-address6 :== (complicated set of rules)
357*83ee113eSDavid van Moolenbroek  *
358*83ee113eSDavid van Moolenbroek  * See section 2.2 of RFC 1884 for details.
359*83ee113eSDavid van Moolenbroek  *
360*83ee113eSDavid van Moolenbroek  * We are lazy for this. We pull numbers, names, colons, and dots
361*83ee113eSDavid van Moolenbroek  * together and then throw the resulting string at the inet_pton()
362*83ee113eSDavid van Moolenbroek  * function.
363*83ee113eSDavid van Moolenbroek  */
364*83ee113eSDavid van Moolenbroek 
365*83ee113eSDavid van Moolenbroek int
parse_ip6_addr(struct parse * cfile,struct iaddr * addr)366*83ee113eSDavid van Moolenbroek parse_ip6_addr(struct parse *cfile, struct iaddr *addr) {
367*83ee113eSDavid van Moolenbroek 	enum dhcp_token token;
368*83ee113eSDavid van Moolenbroek 	const char *val;
369*83ee113eSDavid van Moolenbroek 	int val_len;
370*83ee113eSDavid van Moolenbroek 
371*83ee113eSDavid van Moolenbroek 	char v6[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
372*83ee113eSDavid van Moolenbroek 	int v6_len;
373*83ee113eSDavid van Moolenbroek 
374*83ee113eSDavid van Moolenbroek 	/*
375*83ee113eSDavid van Moolenbroek 	 * First token is non-raw. This way we eat any whitespace before
376*83ee113eSDavid van Moolenbroek 	 * our IPv6 address begins, like one would expect.
377*83ee113eSDavid van Moolenbroek 	 */
378*83ee113eSDavid van Moolenbroek 	token = peek_token(&val, NULL, cfile);
379*83ee113eSDavid van Moolenbroek 
380*83ee113eSDavid van Moolenbroek 	/*
381*83ee113eSDavid van Moolenbroek 	 * Gather symbols.
382*83ee113eSDavid van Moolenbroek 	 */
383*83ee113eSDavid van Moolenbroek 	v6_len = 0;
384*83ee113eSDavid van Moolenbroek 	for (;;) {
385*83ee113eSDavid van Moolenbroek 		if ((((token == NAME) || (token == NUMBER_OR_NAME)) &&
386*83ee113eSDavid van Moolenbroek 		     is_hex_string(val)) ||
387*83ee113eSDavid van Moolenbroek 		    (token == NUMBER) ||
388*83ee113eSDavid van Moolenbroek 		    (token == DOT) ||
389*83ee113eSDavid van Moolenbroek 		    (token == COLON)) {
390*83ee113eSDavid van Moolenbroek 
391*83ee113eSDavid van Moolenbroek 			next_raw_token(&val, NULL, cfile);
392*83ee113eSDavid van Moolenbroek 			val_len = strlen(val);
393*83ee113eSDavid van Moolenbroek 			if ((v6_len + val_len) >= sizeof(v6)) {
394*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "Invalid IPv6 address.");
395*83ee113eSDavid van Moolenbroek 				skip_to_semi(cfile);
396*83ee113eSDavid van Moolenbroek 				return 0;
397*83ee113eSDavid van Moolenbroek 			}
398*83ee113eSDavid van Moolenbroek 			memcpy(v6+v6_len, val, val_len);
399*83ee113eSDavid van Moolenbroek 			v6_len += val_len;
400*83ee113eSDavid van Moolenbroek 
401*83ee113eSDavid van Moolenbroek 		} else {
402*83ee113eSDavid van Moolenbroek 			break;
403*83ee113eSDavid van Moolenbroek 		}
404*83ee113eSDavid van Moolenbroek 		token = peek_raw_token(&val, NULL, cfile);
405*83ee113eSDavid van Moolenbroek 	}
406*83ee113eSDavid van Moolenbroek 	v6[v6_len] = '\0';
407*83ee113eSDavid van Moolenbroek 
408*83ee113eSDavid van Moolenbroek 	/*
409*83ee113eSDavid van Moolenbroek 	 * Use inet_pton() for actual work.
410*83ee113eSDavid van Moolenbroek 	 */
411*83ee113eSDavid van Moolenbroek 	if (inet_pton(AF_INET6, v6, addr->iabuf) <= 0) {
412*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "Invalid IPv6 address.");
413*83ee113eSDavid van Moolenbroek 		skip_to_semi(cfile);
414*83ee113eSDavid van Moolenbroek 		return 0;
415*83ee113eSDavid van Moolenbroek 	}
416*83ee113eSDavid van Moolenbroek 	addr->len = 16;
417*83ee113eSDavid van Moolenbroek 	return 1;
418*83ee113eSDavid van Moolenbroek }
419*83ee113eSDavid van Moolenbroek 
420*83ee113eSDavid van Moolenbroek /*
421*83ee113eSDavid van Moolenbroek  * Same as parse_ip6_addr() above, but returns the value in the
422*83ee113eSDavid van Moolenbroek  * expression rather than in an address structure.
423*83ee113eSDavid van Moolenbroek  */
424*83ee113eSDavid van Moolenbroek int
parse_ip6_addr_expr(struct expression ** expr,struct parse * cfile)425*83ee113eSDavid van Moolenbroek parse_ip6_addr_expr(struct expression **expr,
426*83ee113eSDavid van Moolenbroek 		    struct parse *cfile) {
427*83ee113eSDavid van Moolenbroek 	struct iaddr addr;
428*83ee113eSDavid van Moolenbroek 
429*83ee113eSDavid van Moolenbroek 	if (!parse_ip6_addr(cfile, &addr)) {
430*83ee113eSDavid van Moolenbroek 		return 0;
431*83ee113eSDavid van Moolenbroek 	}
432*83ee113eSDavid van Moolenbroek 	return make_const_data(expr, addr.iabuf, addr.len, 0, 1, MDL);
433*83ee113eSDavid van Moolenbroek }
434*83ee113eSDavid van Moolenbroek 
435*83ee113eSDavid van Moolenbroek /*
436*83ee113eSDavid van Moolenbroek  * ip6-prefix :== ip6-address "/" NUMBER
437*83ee113eSDavid van Moolenbroek  */
438*83ee113eSDavid van Moolenbroek int
parse_ip6_prefix(struct parse * cfile,struct iaddr * addr,u_int8_t * plen)439*83ee113eSDavid van Moolenbroek parse_ip6_prefix(struct parse *cfile, struct iaddr *addr, u_int8_t *plen) {
440*83ee113eSDavid van Moolenbroek 	enum dhcp_token token;
441*83ee113eSDavid van Moolenbroek 	const char *val;
442*83ee113eSDavid van Moolenbroek 	int n;
443*83ee113eSDavid van Moolenbroek 
444*83ee113eSDavid van Moolenbroek 	if (!parse_ip6_addr(cfile, addr)) {
445*83ee113eSDavid van Moolenbroek 		return 0;
446*83ee113eSDavid van Moolenbroek 	}
447*83ee113eSDavid van Moolenbroek 	token = next_token(&val, NULL, cfile);
448*83ee113eSDavid van Moolenbroek 	if (token != SLASH) {
449*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "Slash expected.");
450*83ee113eSDavid van Moolenbroek 		if (token != SEMI)
451*83ee113eSDavid van Moolenbroek 			skip_to_semi(cfile);
452*83ee113eSDavid van Moolenbroek 		return 0;
453*83ee113eSDavid van Moolenbroek 	}
454*83ee113eSDavid van Moolenbroek 	token = next_token(&val, NULL, cfile);
455*83ee113eSDavid van Moolenbroek 	if (token != NUMBER) {
456*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "Number expected.");
457*83ee113eSDavid van Moolenbroek 		if (token != SEMI)
458*83ee113eSDavid van Moolenbroek 			skip_to_semi(cfile);
459*83ee113eSDavid van Moolenbroek 		return 0;
460*83ee113eSDavid van Moolenbroek 	}
461*83ee113eSDavid van Moolenbroek 	n = atoi(val);
462*83ee113eSDavid van Moolenbroek 	if ((n < 0) || (n > 128)) {
463*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "Invalid IPv6 prefix length.");
464*83ee113eSDavid van Moolenbroek 		skip_to_semi(cfile);
465*83ee113eSDavid van Moolenbroek 		return 0;
466*83ee113eSDavid van Moolenbroek 	}
467*83ee113eSDavid van Moolenbroek 	if (!is_cidr_mask_valid(addr, n)) {
468*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "network mask too short.");
469*83ee113eSDavid van Moolenbroek 		skip_to_semi(cfile);
470*83ee113eSDavid van Moolenbroek 		return 0;
471*83ee113eSDavid van Moolenbroek 	}
472*83ee113eSDavid van Moolenbroek 	*plen = n;
473*83ee113eSDavid van Moolenbroek 	return 1;
474*83ee113eSDavid van Moolenbroek }
475*83ee113eSDavid van Moolenbroek 
476*83ee113eSDavid van Moolenbroek /*
477*83ee113eSDavid van Moolenbroek  * ip-address-with-subnet :== ip-address |
478*83ee113eSDavid van Moolenbroek  *                          ip-address "/" NUMBER
479*83ee113eSDavid van Moolenbroek  */
480*83ee113eSDavid van Moolenbroek 
481*83ee113eSDavid van Moolenbroek int
parse_ip_addr_with_subnet(cfile,match)482*83ee113eSDavid van Moolenbroek parse_ip_addr_with_subnet(cfile, match)
483*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
484*83ee113eSDavid van Moolenbroek 	struct iaddrmatch *match;
485*83ee113eSDavid van Moolenbroek {
486*83ee113eSDavid van Moolenbroek 	const char *val, *orig;
487*83ee113eSDavid van Moolenbroek 	enum dhcp_token token;
488*83ee113eSDavid van Moolenbroek 	int prefixlen;
489*83ee113eSDavid van Moolenbroek 	int fflen;
490*83ee113eSDavid van Moolenbroek 	unsigned char newval, warnmask=0;
491*83ee113eSDavid van Moolenbroek 
492*83ee113eSDavid van Moolenbroek 	if (parse_ip_addr(cfile, &match->addr)) {
493*83ee113eSDavid van Moolenbroek 		/* default to host mask */
494*83ee113eSDavid van Moolenbroek 		prefixlen = match->addr.len * 8;
495*83ee113eSDavid van Moolenbroek 
496*83ee113eSDavid van Moolenbroek 		token = peek_token(&val, NULL, cfile);
497*83ee113eSDavid van Moolenbroek 
498*83ee113eSDavid van Moolenbroek 		if (token == SLASH) {
499*83ee113eSDavid van Moolenbroek 			skip_token(&val, NULL, cfile);
500*83ee113eSDavid van Moolenbroek 			token = next_token(&val, NULL, cfile);
501*83ee113eSDavid van Moolenbroek 
502*83ee113eSDavid van Moolenbroek 			if (token != NUMBER) {
503*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "Invalid CIDR prefix length:"
504*83ee113eSDavid van Moolenbroek 						  " expecting a number.");
505*83ee113eSDavid van Moolenbroek 				return 0;
506*83ee113eSDavid van Moolenbroek 			}
507*83ee113eSDavid van Moolenbroek 
508*83ee113eSDavid van Moolenbroek 			prefixlen = atoi(val);
509*83ee113eSDavid van Moolenbroek 
510*83ee113eSDavid van Moolenbroek 			if (prefixlen < 0 ||
511*83ee113eSDavid van Moolenbroek 			    prefixlen > (match->addr.len * 8)) {
512*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "subnet prefix is out of "
513*83ee113eSDavid van Moolenbroek 						  "range [0..%d].",
514*83ee113eSDavid van Moolenbroek 						  match->addr.len * 8);
515*83ee113eSDavid van Moolenbroek 				return 0;
516*83ee113eSDavid van Moolenbroek 			}
517*83ee113eSDavid van Moolenbroek 		}
518*83ee113eSDavid van Moolenbroek 
519*83ee113eSDavid van Moolenbroek 		/* construct a suitable mask field */
520*83ee113eSDavid van Moolenbroek 
521*83ee113eSDavid van Moolenbroek 		/* copy length */
522*83ee113eSDavid van Moolenbroek 		match->mask.len = match->addr.len;
523*83ee113eSDavid van Moolenbroek 
524*83ee113eSDavid van Moolenbroek 		/* count of 0xff bytes in mask */
525*83ee113eSDavid van Moolenbroek 		fflen = prefixlen / 8;
526*83ee113eSDavid van Moolenbroek 
527*83ee113eSDavid van Moolenbroek 		/* set leading mask */
528*83ee113eSDavid van Moolenbroek 		memset(match->mask.iabuf, 0xff, fflen);
529*83ee113eSDavid van Moolenbroek 
530*83ee113eSDavid van Moolenbroek 		/* set zeroes */
531*83ee113eSDavid van Moolenbroek 		if (fflen < match->mask.len) {
532*83ee113eSDavid van Moolenbroek 			match->mask.iabuf[fflen] =
533*83ee113eSDavid van Moolenbroek 			    "\x00\x80\xc0\xe0\xf0\xf8\xfc\xfe"[prefixlen % 8];
534*83ee113eSDavid van Moolenbroek 
535*83ee113eSDavid van Moolenbroek 			memset(match->mask.iabuf+fflen+1, 0x00,
536*83ee113eSDavid van Moolenbroek 			       match->mask.len - fflen - 1);
537*83ee113eSDavid van Moolenbroek 
538*83ee113eSDavid van Moolenbroek 			/* AND-out insignificant bits from supplied netmask. */
539*83ee113eSDavid van Moolenbroek 			orig = piaddr(match->addr);
540*83ee113eSDavid van Moolenbroek 			do {
541*83ee113eSDavid van Moolenbroek 				newval = match->addr.iabuf[fflen] &
542*83ee113eSDavid van Moolenbroek 					 match->mask.iabuf[fflen];
543*83ee113eSDavid van Moolenbroek 
544*83ee113eSDavid van Moolenbroek 				if (newval != match->addr.iabuf[fflen]) {
545*83ee113eSDavid van Moolenbroek 					warnmask = 1;
546*83ee113eSDavid van Moolenbroek 					match->addr.iabuf[fflen] = newval;
547*83ee113eSDavid van Moolenbroek 				}
548*83ee113eSDavid van Moolenbroek 			} while (++fflen < match->mask.len);
549*83ee113eSDavid van Moolenbroek 
550*83ee113eSDavid van Moolenbroek 			if (warnmask) {
551*83ee113eSDavid van Moolenbroek 				log_error("Warning: Extraneous bits removed "
552*83ee113eSDavid van Moolenbroek 					  "in address component of %s/%d.",
553*83ee113eSDavid van Moolenbroek 					  orig, prefixlen);
554*83ee113eSDavid van Moolenbroek 				log_error("New value: %s/%d.",
555*83ee113eSDavid van Moolenbroek 					  piaddr(match->addr), prefixlen);
556*83ee113eSDavid van Moolenbroek 			}
557*83ee113eSDavid van Moolenbroek 		}
558*83ee113eSDavid van Moolenbroek 
559*83ee113eSDavid van Moolenbroek 		return 1;
560*83ee113eSDavid van Moolenbroek 	}
561*83ee113eSDavid van Moolenbroek 
562*83ee113eSDavid van Moolenbroek 	parse_warn(cfile,
563*83ee113eSDavid van Moolenbroek 		   "expecting ip-address or ip-address/prefixlen");
564*83ee113eSDavid van Moolenbroek 
565*83ee113eSDavid van Moolenbroek 	return 0;  /* let caller pick up pieces */
566*83ee113eSDavid van Moolenbroek }
567*83ee113eSDavid van Moolenbroek 
568*83ee113eSDavid van Moolenbroek /*
569*83ee113eSDavid van Moolenbroek  * hardware-parameter :== HARDWARE hardware-type colon-separated-hex-list SEMI
570*83ee113eSDavid van Moolenbroek  * hardware-type :== ETHERNET | TOKEN_RING | TOKEN_FDDI | INFINIBAND
571*83ee113eSDavid van Moolenbroek  * Note that INFINIBAND may not be useful for some items, such as classification
572*83ee113eSDavid van Moolenbroek  * as the hardware address won't always be available.
573*83ee113eSDavid van Moolenbroek  */
574*83ee113eSDavid van Moolenbroek 
parse_hardware_param(cfile,hardware)575*83ee113eSDavid van Moolenbroek void parse_hardware_param (cfile, hardware)
576*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
577*83ee113eSDavid van Moolenbroek 	struct hardware *hardware;
578*83ee113eSDavid van Moolenbroek {
579*83ee113eSDavid van Moolenbroek 	const char *val;
580*83ee113eSDavid van Moolenbroek 	enum dhcp_token token;
581*83ee113eSDavid van Moolenbroek 	unsigned hlen;
582*83ee113eSDavid van Moolenbroek 	unsigned char *t;
583*83ee113eSDavid van Moolenbroek 
584*83ee113eSDavid van Moolenbroek 	token = next_token(&val, NULL, cfile);
585*83ee113eSDavid van Moolenbroek 	switch (token) {
586*83ee113eSDavid van Moolenbroek 	      case ETHERNET:
587*83ee113eSDavid van Moolenbroek 		hardware->hbuf[0] = HTYPE_ETHER;
588*83ee113eSDavid van Moolenbroek 		break;
589*83ee113eSDavid van Moolenbroek 	      case TOKEN_RING:
590*83ee113eSDavid van Moolenbroek 		hardware->hbuf[0] = HTYPE_IEEE802;
591*83ee113eSDavid van Moolenbroek 		break;
592*83ee113eSDavid van Moolenbroek 	      case TOKEN_FDDI:
593*83ee113eSDavid van Moolenbroek 		hardware->hbuf[0] = HTYPE_FDDI;
594*83ee113eSDavid van Moolenbroek 		break;
595*83ee113eSDavid van Moolenbroek 	      case TOKEN_INFINIBAND:
596*83ee113eSDavid van Moolenbroek 		hardware->hbuf[0] = HTYPE_INFINIBAND;
597*83ee113eSDavid van Moolenbroek 		break;
598*83ee113eSDavid van Moolenbroek 	      default:
599*83ee113eSDavid van Moolenbroek 		if (!strncmp(val, "unknown-", 8)) {
600*83ee113eSDavid van Moolenbroek 			hardware->hbuf[0] = atoi(&val[8]);
601*83ee113eSDavid van Moolenbroek 		} else {
602*83ee113eSDavid van Moolenbroek 			parse_warn(cfile,
603*83ee113eSDavid van Moolenbroek 				   "expecting a network hardware type");
604*83ee113eSDavid van Moolenbroek 			skip_to_semi(cfile);
605*83ee113eSDavid van Moolenbroek 
606*83ee113eSDavid van Moolenbroek 			return;
607*83ee113eSDavid van Moolenbroek 		}
608*83ee113eSDavid van Moolenbroek 	}
609*83ee113eSDavid van Moolenbroek 
610*83ee113eSDavid van Moolenbroek 	/* Parse the hardware address information.   Technically,
611*83ee113eSDavid van Moolenbroek 	   it would make a lot of sense to restrict the length of the
612*83ee113eSDavid van Moolenbroek 	   data we'll accept here to the length of a particular hardware
613*83ee113eSDavid van Moolenbroek 	   address type.   Unfortunately, there are some broken clients
614*83ee113eSDavid van Moolenbroek 	   out there that put bogus data in the chaddr buffer, and we accept
615*83ee113eSDavid van Moolenbroek 	   that data in the lease file rather than simply failing on such
616*83ee113eSDavid van Moolenbroek 	   clients.   Yuck. */
617*83ee113eSDavid van Moolenbroek 	hlen = 0;
618*83ee113eSDavid van Moolenbroek 	token = peek_token(&val, NULL, cfile);
619*83ee113eSDavid van Moolenbroek 	if (token == SEMI) {
620*83ee113eSDavid van Moolenbroek 		hardware->hlen = 1;
621*83ee113eSDavid van Moolenbroek 		goto out;
622*83ee113eSDavid van Moolenbroek 	}
623*83ee113eSDavid van Moolenbroek 	t = parse_numeric_aggregate(cfile, NULL, &hlen, COLON, 16, 8);
624*83ee113eSDavid van Moolenbroek 	if (t == NULL) {
625*83ee113eSDavid van Moolenbroek 		hardware->hlen = 1;
626*83ee113eSDavid van Moolenbroek 		return;
627*83ee113eSDavid van Moolenbroek 	}
628*83ee113eSDavid van Moolenbroek 	if (hlen + 1 > sizeof(hardware->hbuf)) {
629*83ee113eSDavid van Moolenbroek 		dfree(t, MDL);
630*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "hardware address too long");
631*83ee113eSDavid van Moolenbroek 	} else {
632*83ee113eSDavid van Moolenbroek 		hardware->hlen = hlen + 1;
633*83ee113eSDavid van Moolenbroek 		memcpy((unsigned char *)&hardware->hbuf[1], t, hlen);
634*83ee113eSDavid van Moolenbroek 		if (hlen + 1 < sizeof(hardware->hbuf))
635*83ee113eSDavid van Moolenbroek 			memset(&hardware->hbuf[hlen + 1], 0,
636*83ee113eSDavid van Moolenbroek 			       (sizeof(hardware->hbuf)) - hlen - 1);
637*83ee113eSDavid van Moolenbroek 		dfree(t, MDL);
638*83ee113eSDavid van Moolenbroek 	}
639*83ee113eSDavid van Moolenbroek 
640*83ee113eSDavid van Moolenbroek       out:
641*83ee113eSDavid van Moolenbroek 	token = next_token(&val, NULL, cfile);
642*83ee113eSDavid van Moolenbroek 	if (token != SEMI) {
643*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "expecting semicolon.");
644*83ee113eSDavid van Moolenbroek 		skip_to_semi(cfile);
645*83ee113eSDavid van Moolenbroek 	}
646*83ee113eSDavid van Moolenbroek }
647*83ee113eSDavid van Moolenbroek 
648*83ee113eSDavid van Moolenbroek /* lease-time :== NUMBER SEMI */
649*83ee113eSDavid van Moolenbroek 
parse_lease_time(cfile,timep)650*83ee113eSDavid van Moolenbroek void parse_lease_time (cfile, timep)
651*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
652*83ee113eSDavid van Moolenbroek 	TIME *timep;
653*83ee113eSDavid van Moolenbroek {
654*83ee113eSDavid van Moolenbroek 	const char *val;
655*83ee113eSDavid van Moolenbroek 	enum dhcp_token token;
656*83ee113eSDavid van Moolenbroek 	u_int32_t num;
657*83ee113eSDavid van Moolenbroek 
658*83ee113eSDavid van Moolenbroek 	token = next_token (&val, (unsigned *)0, cfile);
659*83ee113eSDavid van Moolenbroek 	if (token != NUMBER) {
660*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "Expecting numeric lease time");
661*83ee113eSDavid van Moolenbroek 		skip_to_semi (cfile);
662*83ee113eSDavid van Moolenbroek 		return;
663*83ee113eSDavid van Moolenbroek 	}
664*83ee113eSDavid van Moolenbroek 	convert_num(cfile, (unsigned char *)&num, val, 10, 32);
665*83ee113eSDavid van Moolenbroek 	/* Unswap the number - convert_num returns stuff in NBO. */
666*83ee113eSDavid van Moolenbroek 	*timep = ntohl(num);
667*83ee113eSDavid van Moolenbroek 
668*83ee113eSDavid van Moolenbroek 	parse_semi (cfile);
669*83ee113eSDavid van Moolenbroek }
670*83ee113eSDavid van Moolenbroek 
671*83ee113eSDavid van Moolenbroek /* No BNF for numeric aggregates - that's defined by the caller.  What
672*83ee113eSDavid van Moolenbroek    this function does is to parse a sequence of numbers separated by
673*83ee113eSDavid van Moolenbroek    the token specified in separator.  If max is zero, any number of
674*83ee113eSDavid van Moolenbroek    numbers will be parsed; otherwise, exactly max numbers are
675*83ee113eSDavid van Moolenbroek    expected.  Base and size tell us how to internalize the numbers
676*83ee113eSDavid van Moolenbroek    once they've been tokenized.
677*83ee113eSDavid van Moolenbroek 
678*83ee113eSDavid van Moolenbroek    buf - A pointer to space to return the parsed value, if it is null
679*83ee113eSDavid van Moolenbroek    then the function will allocate space for the return.
680*83ee113eSDavid van Moolenbroek 
681*83ee113eSDavid van Moolenbroek    max - The maximum number of items to store.  If zero there is no
682*83ee113eSDavid van Moolenbroek    maximum.  When buf is null and the function needs to allocate space
683*83ee113eSDavid van Moolenbroek    it will do an allocation of max size at the beginning if max is non
684*83ee113eSDavid van Moolenbroek    zero.  If max is zero then the allocation will be done later, after
685*83ee113eSDavid van Moolenbroek    the function has determined the size necessary for the incoming
686*83ee113eSDavid van Moolenbroek    string.
687*83ee113eSDavid van Moolenbroek 
688*83ee113eSDavid van Moolenbroek    returns NULL on errors or a pointer to the value string on success.
689*83ee113eSDavid van Moolenbroek    The pointer will either be buf if it was non-NULL or newly allocated
690*83ee113eSDavid van Moolenbroek    space if buf was NULL
691*83ee113eSDavid van Moolenbroek  */
692*83ee113eSDavid van Moolenbroek 
693*83ee113eSDavid van Moolenbroek 
parse_numeric_aggregate(cfile,buf,max,separator,base,size)694*83ee113eSDavid van Moolenbroek unsigned char *parse_numeric_aggregate (cfile, buf,
695*83ee113eSDavid van Moolenbroek 					max, separator, base, size)
696*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
697*83ee113eSDavid van Moolenbroek 	unsigned char *buf;
698*83ee113eSDavid van Moolenbroek 	unsigned *max;
699*83ee113eSDavid van Moolenbroek 	int separator;
700*83ee113eSDavid van Moolenbroek 	int base;
701*83ee113eSDavid van Moolenbroek 	unsigned size;
702*83ee113eSDavid van Moolenbroek {
703*83ee113eSDavid van Moolenbroek 	const char *val;
704*83ee113eSDavid van Moolenbroek 	enum dhcp_token token;
705*83ee113eSDavid van Moolenbroek 	unsigned char *bufp = buf, *s, *t;
706*83ee113eSDavid van Moolenbroek 	unsigned count = 0;
707*83ee113eSDavid van Moolenbroek 	pair c = (pair)0;
708*83ee113eSDavid van Moolenbroek 
709*83ee113eSDavid van Moolenbroek 	if (!bufp && *max) {
710*83ee113eSDavid van Moolenbroek 		bufp = (unsigned char *)dmalloc (*max * size / 8, MDL);
711*83ee113eSDavid van Moolenbroek 		if (!bufp)
712*83ee113eSDavid van Moolenbroek 			log_fatal ("no space for numeric aggregate");
713*83ee113eSDavid van Moolenbroek 	}
714*83ee113eSDavid van Moolenbroek 	s = bufp;
715*83ee113eSDavid van Moolenbroek 
716*83ee113eSDavid van Moolenbroek 	do {
717*83ee113eSDavid van Moolenbroek 		if (count) {
718*83ee113eSDavid van Moolenbroek 			token = peek_token (&val, (unsigned *)0, cfile);
719*83ee113eSDavid van Moolenbroek 			if (token != separator) {
720*83ee113eSDavid van Moolenbroek 				if (!*max)
721*83ee113eSDavid van Moolenbroek 					break;
722*83ee113eSDavid van Moolenbroek 				if (token != RBRACE && token != LBRACE)
723*83ee113eSDavid van Moolenbroek 					token = next_token (&val,
724*83ee113eSDavid van Moolenbroek 							    (unsigned *)0,
725*83ee113eSDavid van Moolenbroek 							    cfile);
726*83ee113eSDavid van Moolenbroek 				parse_warn (cfile, "too few numbers.");
727*83ee113eSDavid van Moolenbroek 				if (token != SEMI)
728*83ee113eSDavid van Moolenbroek 					skip_to_semi (cfile);
729*83ee113eSDavid van Moolenbroek 				/* free bufp if it was allocated */
730*83ee113eSDavid van Moolenbroek 				if ((bufp != NULL) && (bufp != buf))
731*83ee113eSDavid van Moolenbroek 					dfree(bufp, MDL);
732*83ee113eSDavid van Moolenbroek 				return (unsigned char *)0;
733*83ee113eSDavid van Moolenbroek 			}
734*83ee113eSDavid van Moolenbroek 			skip_token(&val, (unsigned *)0, cfile);
735*83ee113eSDavid van Moolenbroek 		}
736*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
737*83ee113eSDavid van Moolenbroek 
738*83ee113eSDavid van Moolenbroek 		if (token == END_OF_FILE) {
739*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "unexpected end of file");
740*83ee113eSDavid van Moolenbroek 			break;
741*83ee113eSDavid van Moolenbroek 		}
742*83ee113eSDavid van Moolenbroek 
743*83ee113eSDavid van Moolenbroek 		/* Allow NUMBER_OR_NAME if base is 16. */
744*83ee113eSDavid van Moolenbroek 		if (token != NUMBER &&
745*83ee113eSDavid van Moolenbroek 		    (base != 16 || token != NUMBER_OR_NAME)) {
746*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "expecting numeric value.");
747*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
748*83ee113eSDavid van Moolenbroek 			/* free bufp if it was allocated */
749*83ee113eSDavid van Moolenbroek 			if ((bufp != NULL) && (bufp != buf))
750*83ee113eSDavid van Moolenbroek 				dfree(bufp, MDL);
751*83ee113eSDavid van Moolenbroek 			/* free any linked numbers we may have allocated */
752*83ee113eSDavid van Moolenbroek 			while (c) {
753*83ee113eSDavid van Moolenbroek 				pair cdr = c->cdr;
754*83ee113eSDavid van Moolenbroek 				dfree(c->car, MDL);
755*83ee113eSDavid van Moolenbroek 				dfree(c, MDL);
756*83ee113eSDavid van Moolenbroek 				c = cdr;
757*83ee113eSDavid van Moolenbroek 			}
758*83ee113eSDavid van Moolenbroek 			return (NULL);
759*83ee113eSDavid van Moolenbroek 		}
760*83ee113eSDavid van Moolenbroek 		/* If we can, convert the number now; otherwise, build
761*83ee113eSDavid van Moolenbroek 		   a linked list of all the numbers. */
762*83ee113eSDavid van Moolenbroek 		if (s) {
763*83ee113eSDavid van Moolenbroek 			convert_num (cfile, s, val, base, size);
764*83ee113eSDavid van Moolenbroek 			s += size / 8;
765*83ee113eSDavid van Moolenbroek 		} else {
766*83ee113eSDavid van Moolenbroek 			t = (unsigned char *)dmalloc (strlen (val) + 1, MDL);
767*83ee113eSDavid van Moolenbroek 			if (!t)
768*83ee113eSDavid van Moolenbroek 				log_fatal ("no temp space for number.");
769*83ee113eSDavid van Moolenbroek 			strcpy ((char *)t, val);
770*83ee113eSDavid van Moolenbroek 			c = cons ((caddr_t)t, c);
771*83ee113eSDavid van Moolenbroek 		}
772*83ee113eSDavid van Moolenbroek 	} while (++count != *max);
773*83ee113eSDavid van Moolenbroek 
774*83ee113eSDavid van Moolenbroek 	/* If we had to cons up a list, convert it now. */
775*83ee113eSDavid van Moolenbroek 	if (c) {
776*83ee113eSDavid van Moolenbroek 		/*
777*83ee113eSDavid van Moolenbroek 		 * No need to cleanup bufp, to get here we didn't allocate
778*83ee113eSDavid van Moolenbroek 		 * bufp above
779*83ee113eSDavid van Moolenbroek 		 */
780*83ee113eSDavid van Moolenbroek 		bufp = (unsigned char *)dmalloc (count * size / 8, MDL);
781*83ee113eSDavid van Moolenbroek 		if (!bufp)
782*83ee113eSDavid van Moolenbroek 			log_fatal ("no space for numeric aggregate.");
783*83ee113eSDavid van Moolenbroek 		s = bufp + count - size / 8;
784*83ee113eSDavid van Moolenbroek 		*max = count;
785*83ee113eSDavid van Moolenbroek 	}
786*83ee113eSDavid van Moolenbroek 	while (c) {
787*83ee113eSDavid van Moolenbroek 		pair cdr = c -> cdr;
788*83ee113eSDavid van Moolenbroek 		convert_num (cfile, s, (char *)(c -> car), base, size);
789*83ee113eSDavid van Moolenbroek 		s -= size / 8;
790*83ee113eSDavid van Moolenbroek 		/* Free up temp space. */
791*83ee113eSDavid van Moolenbroek 		dfree (c -> car, MDL);
792*83ee113eSDavid van Moolenbroek 		dfree (c, MDL);
793*83ee113eSDavid van Moolenbroek 		c = cdr;
794*83ee113eSDavid van Moolenbroek 	}
795*83ee113eSDavid van Moolenbroek 	return bufp;
796*83ee113eSDavid van Moolenbroek }
797*83ee113eSDavid van Moolenbroek 
convert_num(cfile,buf,str,base,size)798*83ee113eSDavid van Moolenbroek void convert_num (cfile, buf, str, base, size)
799*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
800*83ee113eSDavid van Moolenbroek 	unsigned char *buf;
801*83ee113eSDavid van Moolenbroek 	const char *str;
802*83ee113eSDavid van Moolenbroek 	int base;
803*83ee113eSDavid van Moolenbroek 	unsigned size;
804*83ee113eSDavid van Moolenbroek {
805*83ee113eSDavid van Moolenbroek 	const unsigned char *ptr = (const unsigned char *)str;
806*83ee113eSDavid van Moolenbroek 	int negative = 0;
807*83ee113eSDavid van Moolenbroek 	u_int32_t val = 0;
808*83ee113eSDavid van Moolenbroek 	int tval;
809*83ee113eSDavid van Moolenbroek 	int max;
810*83ee113eSDavid van Moolenbroek 
811*83ee113eSDavid van Moolenbroek 	if (*ptr == '-') {
812*83ee113eSDavid van Moolenbroek 		negative = 1;
813*83ee113eSDavid van Moolenbroek 		++ptr;
814*83ee113eSDavid van Moolenbroek 	}
815*83ee113eSDavid van Moolenbroek 
816*83ee113eSDavid van Moolenbroek 	/* If base wasn't specified, figure it out from the data. */
817*83ee113eSDavid van Moolenbroek 	if (!base) {
818*83ee113eSDavid van Moolenbroek 		if (ptr [0] == '0') {
819*83ee113eSDavid van Moolenbroek 			if (ptr [1] == 'x') {
820*83ee113eSDavid van Moolenbroek 				base = 16;
821*83ee113eSDavid van Moolenbroek 				ptr += 2;
822*83ee113eSDavid van Moolenbroek 			} else if (isascii (ptr [1]) && isdigit (ptr [1])) {
823*83ee113eSDavid van Moolenbroek 				base = 8;
824*83ee113eSDavid van Moolenbroek 				ptr += 1;
825*83ee113eSDavid van Moolenbroek 			} else {
826*83ee113eSDavid van Moolenbroek 				base = 10;
827*83ee113eSDavid van Moolenbroek 			}
828*83ee113eSDavid van Moolenbroek 		} else {
829*83ee113eSDavid van Moolenbroek 			base = 10;
830*83ee113eSDavid van Moolenbroek 		}
831*83ee113eSDavid van Moolenbroek 	}
832*83ee113eSDavid van Moolenbroek 
833*83ee113eSDavid van Moolenbroek 	do {
834*83ee113eSDavid van Moolenbroek 		tval = *ptr++;
835*83ee113eSDavid van Moolenbroek 		/* XXX assumes ASCII... */
836*83ee113eSDavid van Moolenbroek 		if (tval >= 'a')
837*83ee113eSDavid van Moolenbroek 			tval = tval - 'a' + 10;
838*83ee113eSDavid van Moolenbroek 		else if (tval >= 'A')
839*83ee113eSDavid van Moolenbroek 			tval = tval - 'A' + 10;
840*83ee113eSDavid van Moolenbroek 		else if (tval >= '0')
841*83ee113eSDavid van Moolenbroek 			tval -= '0';
842*83ee113eSDavid van Moolenbroek 		else {
843*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "Bogus number: %s.", str);
844*83ee113eSDavid van Moolenbroek 			break;
845*83ee113eSDavid van Moolenbroek 		}
846*83ee113eSDavid van Moolenbroek 		if (tval >= base) {
847*83ee113eSDavid van Moolenbroek 			parse_warn (cfile,
848*83ee113eSDavid van Moolenbroek 				    "Bogus number %s: digit %d not in base %d",
849*83ee113eSDavid van Moolenbroek 				    str, tval, base);
850*83ee113eSDavid van Moolenbroek 			break;
851*83ee113eSDavid van Moolenbroek 		}
852*83ee113eSDavid van Moolenbroek 		val = val * base + tval;
853*83ee113eSDavid van Moolenbroek 	} while (*ptr);
854*83ee113eSDavid van Moolenbroek 
855*83ee113eSDavid van Moolenbroek 	if (negative)
856*83ee113eSDavid van Moolenbroek 		max = (1 << (size - 1));
857*83ee113eSDavid van Moolenbroek 	else
858*83ee113eSDavid van Moolenbroek 		max = (1 << (size - 1)) + ((1 << (size - 1)) - 1);
859*83ee113eSDavid van Moolenbroek 	if (val > max) {
860*83ee113eSDavid van Moolenbroek 		switch (base) {
861*83ee113eSDavid van Moolenbroek 		      case 8:
862*83ee113eSDavid van Moolenbroek 			parse_warn (cfile,
863*83ee113eSDavid van Moolenbroek 				    "%s%lo exceeds max (%d) for precision.",
864*83ee113eSDavid van Moolenbroek 				    negative ? "-" : "",
865*83ee113eSDavid van Moolenbroek 				    (unsigned long)val, max);
866*83ee113eSDavid van Moolenbroek 			break;
867*83ee113eSDavid van Moolenbroek 		      case 16:
868*83ee113eSDavid van Moolenbroek 			parse_warn (cfile,
869*83ee113eSDavid van Moolenbroek 				    "%s%lx exceeds max (%d) for precision.",
870*83ee113eSDavid van Moolenbroek 				    negative ? "-" : "",
871*83ee113eSDavid van Moolenbroek 				    (unsigned long)val, max);
872*83ee113eSDavid van Moolenbroek 			break;
873*83ee113eSDavid van Moolenbroek 		      default:
874*83ee113eSDavid van Moolenbroek 			parse_warn (cfile,
875*83ee113eSDavid van Moolenbroek 				    "%s%lu exceeds max (%d) for precision.",
876*83ee113eSDavid van Moolenbroek 				    negative ? "-" : "",
877*83ee113eSDavid van Moolenbroek 				    (unsigned long)val, max);
878*83ee113eSDavid van Moolenbroek 			break;
879*83ee113eSDavid van Moolenbroek 		}
880*83ee113eSDavid van Moolenbroek 	}
881*83ee113eSDavid van Moolenbroek 
882*83ee113eSDavid van Moolenbroek 	if (negative) {
883*83ee113eSDavid van Moolenbroek 		switch (size) {
884*83ee113eSDavid van Moolenbroek 		      case 8:
885*83ee113eSDavid van Moolenbroek 			*buf = -(unsigned long)val;
886*83ee113eSDavid van Moolenbroek 			break;
887*83ee113eSDavid van Moolenbroek 		      case 16:
888*83ee113eSDavid van Moolenbroek 			putShort (buf, -(long)val);
889*83ee113eSDavid van Moolenbroek 			break;
890*83ee113eSDavid van Moolenbroek 		      case 32:
891*83ee113eSDavid van Moolenbroek 			putLong (buf, -(long)val);
892*83ee113eSDavid van Moolenbroek 			break;
893*83ee113eSDavid van Moolenbroek 		      default:
894*83ee113eSDavid van Moolenbroek 			parse_warn (cfile,
895*83ee113eSDavid van Moolenbroek 				    "Unexpected integer size: %d\n", size);
896*83ee113eSDavid van Moolenbroek 			break;
897*83ee113eSDavid van Moolenbroek 		}
898*83ee113eSDavid van Moolenbroek 	} else {
899*83ee113eSDavid van Moolenbroek 		switch (size) {
900*83ee113eSDavid van Moolenbroek 		      case 8:
901*83ee113eSDavid van Moolenbroek 			*buf = (u_int8_t)val;
902*83ee113eSDavid van Moolenbroek 			break;
903*83ee113eSDavid van Moolenbroek 		      case 16:
904*83ee113eSDavid van Moolenbroek 			putUShort (buf, (u_int16_t)val);
905*83ee113eSDavid van Moolenbroek 			break;
906*83ee113eSDavid van Moolenbroek 		      case 32:
907*83ee113eSDavid van Moolenbroek 			putULong (buf, val);
908*83ee113eSDavid van Moolenbroek 			break;
909*83ee113eSDavid van Moolenbroek 		      default:
910*83ee113eSDavid van Moolenbroek 			parse_warn (cfile,
911*83ee113eSDavid van Moolenbroek 				    "Unexpected integer size: %d\n", size);
912*83ee113eSDavid van Moolenbroek 			break;
913*83ee113eSDavid van Moolenbroek 		}
914*83ee113eSDavid van Moolenbroek 	}
915*83ee113eSDavid van Moolenbroek }
916*83ee113eSDavid van Moolenbroek 
917*83ee113eSDavid van Moolenbroek /*
918*83ee113eSDavid van Moolenbroek  * date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER
919*83ee113eSDavid van Moolenbroek  *		NUMBER COLON NUMBER COLON NUMBER |
920*83ee113eSDavid van Moolenbroek  *          NUMBER NUMBER SLASH NUMBER SLASH NUMBER
921*83ee113eSDavid van Moolenbroek  *		NUMBER COLON NUMBER COLON NUMBER NUMBER |
922*83ee113eSDavid van Moolenbroek  *          EPOCH NUMBER |
923*83ee113eSDavid van Moolenbroek  *	    NEVER
924*83ee113eSDavid van Moolenbroek  *
925*83ee113eSDavid van Moolenbroek  * Dates are stored in UTC or with a timezone offset; first number is day
926*83ee113eSDavid van Moolenbroek  * of week; next is year/month/day; next is hours:minutes:seconds on a
927*83ee113eSDavid van Moolenbroek  * 24-hour clock, followed by the timezone offset in seconds, which is
928*83ee113eSDavid van Moolenbroek  * optional.
929*83ee113eSDavid van Moolenbroek  */
930*83ee113eSDavid van Moolenbroek 
931*83ee113eSDavid van Moolenbroek /*
932*83ee113eSDavid van Moolenbroek  * just parse the date
933*83ee113eSDavid van Moolenbroek  * any trailing semi must be consumed by the caller of this routine
934*83ee113eSDavid van Moolenbroek  */
935*83ee113eSDavid van Moolenbroek TIME
parse_date_core(cfile)936*83ee113eSDavid van Moolenbroek parse_date_core(cfile)
937*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
938*83ee113eSDavid van Moolenbroek {
939*83ee113eSDavid van Moolenbroek 	int guess;
940*83ee113eSDavid van Moolenbroek 	int tzoff, year, mon, mday, hour, min, sec;
941*83ee113eSDavid van Moolenbroek 	const char *val;
942*83ee113eSDavid van Moolenbroek 	enum dhcp_token token;
943*83ee113eSDavid van Moolenbroek 	static int months[11] = { 31, 59, 90, 120, 151, 181,
944*83ee113eSDavid van Moolenbroek 				  212, 243, 273, 304, 334 };
945*83ee113eSDavid van Moolenbroek 
946*83ee113eSDavid van Moolenbroek 	/* "never", "epoch" or day of week */
947*83ee113eSDavid van Moolenbroek 	token = peek_token(&val, NULL, cfile);
948*83ee113eSDavid van Moolenbroek 	if (token == NEVER) {
949*83ee113eSDavid van Moolenbroek 		skip_token(&val, NULL, cfile); /* consume NEVER */
950*83ee113eSDavid van Moolenbroek 		return(MAX_TIME);
951*83ee113eSDavid van Moolenbroek 	}
952*83ee113eSDavid van Moolenbroek 
953*83ee113eSDavid van Moolenbroek 	/* This indicates 'local' time format. */
954*83ee113eSDavid van Moolenbroek 	if (token == EPOCH) {
955*83ee113eSDavid van Moolenbroek 		skip_token(&val, NULL, cfile); /* consume EPOCH */
956*83ee113eSDavid van Moolenbroek 		token = peek_token(&val, NULL, cfile);
957*83ee113eSDavid van Moolenbroek 
958*83ee113eSDavid van Moolenbroek 		if (token != NUMBER) {
959*83ee113eSDavid van Moolenbroek 			if (token != SEMI)
960*83ee113eSDavid van Moolenbroek 				skip_token(&val, NULL, cfile);
961*83ee113eSDavid van Moolenbroek 			parse_warn(cfile, "Seconds since epoch expected.");
962*83ee113eSDavid van Moolenbroek 			return((TIME)0);
963*83ee113eSDavid van Moolenbroek 		}
964*83ee113eSDavid van Moolenbroek 
965*83ee113eSDavid van Moolenbroek 		skip_token(&val, NULL, cfile); /* consume number */
966*83ee113eSDavid van Moolenbroek 		guess = atoi(val);
967*83ee113eSDavid van Moolenbroek 
968*83ee113eSDavid van Moolenbroek 		return((TIME)guess);
969*83ee113eSDavid van Moolenbroek 	}
970*83ee113eSDavid van Moolenbroek 
971*83ee113eSDavid van Moolenbroek 	if (token != NUMBER) {
972*83ee113eSDavid van Moolenbroek 		if (token != SEMI)
973*83ee113eSDavid van Moolenbroek 			skip_token(&val, NULL, cfile);
974*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "numeric day of week expected.");
975*83ee113eSDavid van Moolenbroek 		return((TIME)0);
976*83ee113eSDavid van Moolenbroek 	}
977*83ee113eSDavid van Moolenbroek 	skip_token(&val, NULL, cfile); /* consume day of week */
978*83ee113eSDavid van Moolenbroek         /* we are not using this for anything */
979*83ee113eSDavid van Moolenbroek 
980*83ee113eSDavid van Moolenbroek 	/* Year... */
981*83ee113eSDavid van Moolenbroek 	token = peek_token(&val, NULL, cfile);
982*83ee113eSDavid van Moolenbroek 	if (token != NUMBER) {
983*83ee113eSDavid van Moolenbroek 		if (token != SEMI)
984*83ee113eSDavid van Moolenbroek 			skip_token(&val, NULL, cfile);
985*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "numeric year expected.");
986*83ee113eSDavid van Moolenbroek 		return((TIME)0);
987*83ee113eSDavid van Moolenbroek 	}
988*83ee113eSDavid van Moolenbroek 	skip_token(&val, NULL, cfile); /* consume year */
989*83ee113eSDavid van Moolenbroek 
990*83ee113eSDavid van Moolenbroek 	/* Note: the following is not a Y2K bug - it's a Y1.9K bug.   Until
991*83ee113eSDavid van Moolenbroek 	   somebody invents a time machine, I think we can safely disregard
992*83ee113eSDavid van Moolenbroek 	   it.   This actually works around a stupid Y2K bug that was present
993*83ee113eSDavid van Moolenbroek 	   in a very early beta release of dhcpd. */
994*83ee113eSDavid van Moolenbroek 	year = atoi(val);
995*83ee113eSDavid van Moolenbroek 	if (year > 1900)
996*83ee113eSDavid van Moolenbroek 		year -= 1900;
997*83ee113eSDavid van Moolenbroek 
998*83ee113eSDavid van Moolenbroek 	/* Slash separating year from month... */
999*83ee113eSDavid van Moolenbroek 	token = peek_token(&val, NULL, cfile);
1000*83ee113eSDavid van Moolenbroek 	if (token != SLASH) {
1001*83ee113eSDavid van Moolenbroek 		if (token != SEMI)
1002*83ee113eSDavid van Moolenbroek 			skip_token(&val, NULL, cfile);
1003*83ee113eSDavid van Moolenbroek 		parse_warn(cfile,
1004*83ee113eSDavid van Moolenbroek 			   "expected slash separating year from month.");
1005*83ee113eSDavid van Moolenbroek 		return((TIME)0);
1006*83ee113eSDavid van Moolenbroek 	}
1007*83ee113eSDavid van Moolenbroek 	skip_token(&val, NULL, cfile); /* consume SLASH */
1008*83ee113eSDavid van Moolenbroek 
1009*83ee113eSDavid van Moolenbroek 	/* Month... */
1010*83ee113eSDavid van Moolenbroek 	token = peek_token(&val, NULL, cfile);
1011*83ee113eSDavid van Moolenbroek 	if (token != NUMBER) {
1012*83ee113eSDavid van Moolenbroek 		if (token != SEMI)
1013*83ee113eSDavid van Moolenbroek 			skip_token(&val, NULL, cfile);
1014*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "numeric month expected.");
1015*83ee113eSDavid van Moolenbroek 		return((TIME)0);
1016*83ee113eSDavid van Moolenbroek 	}
1017*83ee113eSDavid van Moolenbroek 	skip_token(&val, NULL, cfile); /* consume month */
1018*83ee113eSDavid van Moolenbroek 	mon = atoi(val) - 1;
1019*83ee113eSDavid van Moolenbroek 
1020*83ee113eSDavid van Moolenbroek 	/* Slash separating month from day... */
1021*83ee113eSDavid van Moolenbroek 	token = peek_token(&val, NULL, cfile);
1022*83ee113eSDavid van Moolenbroek 	if (token != SLASH) {
1023*83ee113eSDavid van Moolenbroek 		if (token != SEMI)
1024*83ee113eSDavid van Moolenbroek 			skip_token(&val, NULL, cfile);
1025*83ee113eSDavid van Moolenbroek 		parse_warn(cfile,
1026*83ee113eSDavid van Moolenbroek 			   "expected slash separating month from day.");
1027*83ee113eSDavid van Moolenbroek 		return((TIME)0);
1028*83ee113eSDavid van Moolenbroek 	}
1029*83ee113eSDavid van Moolenbroek 	skip_token(&val, NULL, cfile); /* consume SLASH */
1030*83ee113eSDavid van Moolenbroek 
1031*83ee113eSDavid van Moolenbroek 	/* Day of month... */
1032*83ee113eSDavid van Moolenbroek 	token = peek_token(&val, NULL, cfile);
1033*83ee113eSDavid van Moolenbroek 	if (token != NUMBER) {
1034*83ee113eSDavid van Moolenbroek 		if (token != SEMI)
1035*83ee113eSDavid van Moolenbroek 			skip_token(&val, NULL, cfile);
1036*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "numeric day of month expected.");
1037*83ee113eSDavid van Moolenbroek 		return((TIME)0);
1038*83ee113eSDavid van Moolenbroek 	}
1039*83ee113eSDavid van Moolenbroek 	skip_token(&val, NULL, cfile); /* consume day of month */
1040*83ee113eSDavid van Moolenbroek 	mday = atoi(val);
1041*83ee113eSDavid van Moolenbroek 
1042*83ee113eSDavid van Moolenbroek 	/* Hour... */
1043*83ee113eSDavid van Moolenbroek 	token = peek_token(&val, NULL, cfile);
1044*83ee113eSDavid van Moolenbroek 	if (token != NUMBER) {
1045*83ee113eSDavid van Moolenbroek 		if (token != SEMI)
1046*83ee113eSDavid van Moolenbroek 			skip_token(&val, NULL, cfile);
1047*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "numeric hour expected.");
1048*83ee113eSDavid van Moolenbroek 		return((TIME)0);
1049*83ee113eSDavid van Moolenbroek 	}
1050*83ee113eSDavid van Moolenbroek 	skip_token(&val, NULL, cfile); /* consume hour */
1051*83ee113eSDavid van Moolenbroek 	hour = atoi(val);
1052*83ee113eSDavid van Moolenbroek 
1053*83ee113eSDavid van Moolenbroek 	/* Colon separating hour from minute... */
1054*83ee113eSDavid van Moolenbroek 	token = peek_token(&val, NULL, cfile);
1055*83ee113eSDavid van Moolenbroek 	if (token != COLON) {
1056*83ee113eSDavid van Moolenbroek 		if (token != SEMI)
1057*83ee113eSDavid van Moolenbroek 			skip_token(&val, NULL, cfile);
1058*83ee113eSDavid van Moolenbroek 		parse_warn(cfile,
1059*83ee113eSDavid van Moolenbroek 			   "expected colon separating hour from minute.");
1060*83ee113eSDavid van Moolenbroek 		return((TIME)0);
1061*83ee113eSDavid van Moolenbroek 	}
1062*83ee113eSDavid van Moolenbroek 	skip_token(&val, NULL, cfile); /* consume colon */
1063*83ee113eSDavid van Moolenbroek 
1064*83ee113eSDavid van Moolenbroek 	/* Minute... */
1065*83ee113eSDavid van Moolenbroek 	token = peek_token(&val, NULL, cfile);
1066*83ee113eSDavid van Moolenbroek 	if (token != NUMBER) {
1067*83ee113eSDavid van Moolenbroek 		if (token != SEMI)
1068*83ee113eSDavid van Moolenbroek 			skip_token(&val, NULL, cfile);
1069*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "numeric minute expected.");
1070*83ee113eSDavid van Moolenbroek 		return((TIME)0);
1071*83ee113eSDavid van Moolenbroek 	}
1072*83ee113eSDavid van Moolenbroek 	skip_token(&val, NULL, cfile); /* consume minute */
1073*83ee113eSDavid van Moolenbroek 	min = atoi(val);
1074*83ee113eSDavid van Moolenbroek 
1075*83ee113eSDavid van Moolenbroek 	/* Colon separating minute from second... */
1076*83ee113eSDavid van Moolenbroek 	token = peek_token(&val, NULL, cfile);
1077*83ee113eSDavid van Moolenbroek 	if (token != COLON) {
1078*83ee113eSDavid van Moolenbroek 		if (token != SEMI)
1079*83ee113eSDavid van Moolenbroek 			skip_token(&val, NULL, cfile);
1080*83ee113eSDavid van Moolenbroek 		parse_warn(cfile,
1081*83ee113eSDavid van Moolenbroek 			   "expected colon separating minute from second.");
1082*83ee113eSDavid van Moolenbroek 		return((TIME)0);
1083*83ee113eSDavid van Moolenbroek 	}
1084*83ee113eSDavid van Moolenbroek 	skip_token(&val, NULL, cfile); /* consume colon */
1085*83ee113eSDavid van Moolenbroek 
1086*83ee113eSDavid van Moolenbroek 	/* Second... */
1087*83ee113eSDavid van Moolenbroek 	token = peek_token(&val, NULL, cfile);
1088*83ee113eSDavid van Moolenbroek 	if (token != NUMBER) {
1089*83ee113eSDavid van Moolenbroek 		if (token != SEMI)
1090*83ee113eSDavid van Moolenbroek 			skip_token(&val, NULL, cfile);
1091*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "numeric second expected.");
1092*83ee113eSDavid van Moolenbroek 		return((TIME)0);
1093*83ee113eSDavid van Moolenbroek 	}
1094*83ee113eSDavid van Moolenbroek 	skip_token(&val, NULL, cfile); /* consume second */
1095*83ee113eSDavid van Moolenbroek 	sec = atoi(val);
1096*83ee113eSDavid van Moolenbroek 
1097*83ee113eSDavid van Moolenbroek 	tzoff = 0;
1098*83ee113eSDavid van Moolenbroek 	token = peek_token(&val, NULL, cfile);
1099*83ee113eSDavid van Moolenbroek 	if (token == NUMBER) {
1100*83ee113eSDavid van Moolenbroek 		skip_token(&val, NULL, cfile); /* consume tzoff */
1101*83ee113eSDavid van Moolenbroek 		tzoff = atoi(val);
1102*83ee113eSDavid van Moolenbroek 	} else if (token != SEMI) {
1103*83ee113eSDavid van Moolenbroek 		skip_token(&val, NULL, cfile);
1104*83ee113eSDavid van Moolenbroek 		parse_warn(cfile,
1105*83ee113eSDavid van Moolenbroek 			   "Time zone offset or semicolon expected.");
1106*83ee113eSDavid van Moolenbroek 		return((TIME)0);
1107*83ee113eSDavid van Moolenbroek 	}
1108*83ee113eSDavid van Moolenbroek 
1109*83ee113eSDavid van Moolenbroek 	/* Guess the time value... */
1110*83ee113eSDavid van Moolenbroek 	guess = ((((((365 * (year - 70) +	/* Days in years since '70 */
1111*83ee113eSDavid van Moolenbroek 		      (year - 69) / 4 +		/* Leap days since '70 */
1112*83ee113eSDavid van Moolenbroek 		      (mon			/* Days in months this year */
1113*83ee113eSDavid van Moolenbroek 		       ? months [mon - 1]
1114*83ee113eSDavid van Moolenbroek 		       : 0) +
1115*83ee113eSDavid van Moolenbroek 		      (mon > 1 &&		/* Leap day this year */
1116*83ee113eSDavid van Moolenbroek 		       !((year - 72) & 3)) +
1117*83ee113eSDavid van Moolenbroek 		      mday - 1) * 24) +		/* Day of month */
1118*83ee113eSDavid van Moolenbroek 		    hour) * 60) +
1119*83ee113eSDavid van Moolenbroek 		  min) * 60) + sec + tzoff;
1120*83ee113eSDavid van Moolenbroek 
1121*83ee113eSDavid van Moolenbroek 	/* This guess could be wrong because of leap seconds or other
1122*83ee113eSDavid van Moolenbroek 	   weirdness we don't know about that the system does.   For
1123*83ee113eSDavid van Moolenbroek 	   now, we're just going to accept the guess, but at some point
1124*83ee113eSDavid van Moolenbroek 	   it might be nice to do a successive approximation here to
1125*83ee113eSDavid van Moolenbroek 	   get an exact value.   Even if the error is small, if the
1126*83ee113eSDavid van Moolenbroek 	   server is restarted frequently (and thus the lease database
1127*83ee113eSDavid van Moolenbroek 	   is reread), the error could accumulate into something
1128*83ee113eSDavid van Moolenbroek 	   significant. */
1129*83ee113eSDavid van Moolenbroek 
1130*83ee113eSDavid van Moolenbroek 	return((TIME)guess);
1131*83ee113eSDavid van Moolenbroek }
1132*83ee113eSDavid van Moolenbroek 
1133*83ee113eSDavid van Moolenbroek /*
1134*83ee113eSDavid van Moolenbroek  * Wrapper to consume the semicolon after the date
1135*83ee113eSDavid van Moolenbroek  * :== date semi
1136*83ee113eSDavid van Moolenbroek  */
1137*83ee113eSDavid van Moolenbroek 
1138*83ee113eSDavid van Moolenbroek TIME
parse_date(cfile)1139*83ee113eSDavid van Moolenbroek parse_date(cfile)
1140*83ee113eSDavid van Moolenbroek        struct parse *cfile;
1141*83ee113eSDavid van Moolenbroek {
1142*83ee113eSDavid van Moolenbroek        TIME guess;
1143*83ee113eSDavid van Moolenbroek        guess = parse_date_core(cfile);
1144*83ee113eSDavid van Moolenbroek 
1145*83ee113eSDavid van Moolenbroek        /* Make sure the date ends in a semicolon... */
1146*83ee113eSDavid van Moolenbroek        if (!parse_semi(cfile))
1147*83ee113eSDavid van Moolenbroek 	       return((TIME)0);
1148*83ee113eSDavid van Moolenbroek        return(guess);
1149*83ee113eSDavid van Moolenbroek }
1150*83ee113eSDavid van Moolenbroek 
1151*83ee113eSDavid van Moolenbroek 
1152*83ee113eSDavid van Moolenbroek 
1153*83ee113eSDavid van Moolenbroek /*
1154*83ee113eSDavid van Moolenbroek  * option-name :== IDENTIFIER |
1155*83ee113eSDavid van Moolenbroek  		   IDENTIFIER . IDENTIFIER
1156*83ee113eSDavid van Moolenbroek  */
1157*83ee113eSDavid van Moolenbroek 
1158*83ee113eSDavid van Moolenbroek isc_result_t
parse_option_name(cfile,allocate,known,opt)1159*83ee113eSDavid van Moolenbroek parse_option_name (cfile, allocate, known, opt)
1160*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
1161*83ee113eSDavid van Moolenbroek 	int allocate;
1162*83ee113eSDavid van Moolenbroek 	int *known;
1163*83ee113eSDavid van Moolenbroek 	struct option **opt;
1164*83ee113eSDavid van Moolenbroek {
1165*83ee113eSDavid van Moolenbroek 	const char *val;
1166*83ee113eSDavid van Moolenbroek 	enum dhcp_token token;
1167*83ee113eSDavid van Moolenbroek 	char *uname;
1168*83ee113eSDavid van Moolenbroek 	struct universe *universe;
1169*83ee113eSDavid van Moolenbroek 	struct option *option;
1170*83ee113eSDavid van Moolenbroek 	unsigned code;
1171*83ee113eSDavid van Moolenbroek 
1172*83ee113eSDavid van Moolenbroek 	if (opt == NULL)
1173*83ee113eSDavid van Moolenbroek 		return DHCP_R_INVALIDARG;
1174*83ee113eSDavid van Moolenbroek 
1175*83ee113eSDavid van Moolenbroek 	token = next_token (&val, (unsigned *)0, cfile);
1176*83ee113eSDavid van Moolenbroek 	if (!is_identifier (token)) {
1177*83ee113eSDavid van Moolenbroek 		parse_warn (cfile,
1178*83ee113eSDavid van Moolenbroek 			    "expecting identifier after option keyword.");
1179*83ee113eSDavid van Moolenbroek 		if (token != SEMI)
1180*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
1181*83ee113eSDavid van Moolenbroek 		return DHCP_R_BADPARSE;
1182*83ee113eSDavid van Moolenbroek 	}
1183*83ee113eSDavid van Moolenbroek 	uname = dmalloc (strlen (val) + 1, MDL);
1184*83ee113eSDavid van Moolenbroek 	if (!uname)
1185*83ee113eSDavid van Moolenbroek 		log_fatal ("no memory for uname information.");
1186*83ee113eSDavid van Moolenbroek 	strcpy (uname, val);
1187*83ee113eSDavid van Moolenbroek 	token = peek_token (&val, (unsigned *)0, cfile);
1188*83ee113eSDavid van Moolenbroek 	if (token == DOT) {
1189*83ee113eSDavid van Moolenbroek 		/* Go ahead and take the DOT token... */
1190*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
1191*83ee113eSDavid van Moolenbroek 
1192*83ee113eSDavid van Moolenbroek 		/* The next token should be an identifier... */
1193*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
1194*83ee113eSDavid van Moolenbroek 		if (!is_identifier (token)) {
1195*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "expecting identifier after '.'");
1196*83ee113eSDavid van Moolenbroek 			if (token != SEMI)
1197*83ee113eSDavid van Moolenbroek 				skip_to_semi (cfile);
1198*83ee113eSDavid van Moolenbroek 			return DHCP_R_BADPARSE;
1199*83ee113eSDavid van Moolenbroek 		}
1200*83ee113eSDavid van Moolenbroek 
1201*83ee113eSDavid van Moolenbroek 		/* Look up the option name hash table for the specified
1202*83ee113eSDavid van Moolenbroek 		   uname. */
1203*83ee113eSDavid van Moolenbroek 		universe = (struct universe *)0;
1204*83ee113eSDavid van Moolenbroek 		if (!universe_hash_lookup (&universe, universe_hash,
1205*83ee113eSDavid van Moolenbroek 					   uname, 0, MDL)) {
1206*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "no option space named %s.", uname);
1207*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
1208*83ee113eSDavid van Moolenbroek 			return ISC_R_NOTFOUND;
1209*83ee113eSDavid van Moolenbroek 		}
1210*83ee113eSDavid van Moolenbroek 	} else {
1211*83ee113eSDavid van Moolenbroek 		/* Use the default hash table, which contains all the
1212*83ee113eSDavid van Moolenbroek 		   standard dhcp option names. */
1213*83ee113eSDavid van Moolenbroek 		val = uname;
1214*83ee113eSDavid van Moolenbroek 		universe = &dhcp_universe;
1215*83ee113eSDavid van Moolenbroek 	}
1216*83ee113eSDavid van Moolenbroek 
1217*83ee113eSDavid van Moolenbroek 	/* Look up the actual option info... */
1218*83ee113eSDavid van Moolenbroek 	option_name_hash_lookup(opt, universe->name_hash, val, 0, MDL);
1219*83ee113eSDavid van Moolenbroek 	option = *opt;
1220*83ee113eSDavid van Moolenbroek 
1221*83ee113eSDavid van Moolenbroek 	/* If we didn't get an option structure, it's an undefined option. */
1222*83ee113eSDavid van Moolenbroek 	if (option) {
1223*83ee113eSDavid van Moolenbroek 		if (known)
1224*83ee113eSDavid van Moolenbroek 			*known = 1;
1225*83ee113eSDavid van Moolenbroek 	/* If the option name is of the form unknown-[decimal], use
1226*83ee113eSDavid van Moolenbroek 	 * the trailing decimal value to find the option definition.
1227*83ee113eSDavid van Moolenbroek 	 * If there is no definition, construct one.  This is to
1228*83ee113eSDavid van Moolenbroek 	 * support legacy use of unknown options in config files or
1229*83ee113eSDavid van Moolenbroek 	 * lease databases.
1230*83ee113eSDavid van Moolenbroek 	 */
1231*83ee113eSDavid van Moolenbroek 	} else if (strncasecmp(val, "unknown-", 8) == 0) {
1232*83ee113eSDavid van Moolenbroek 		code = atoi(val+8);
1233*83ee113eSDavid van Moolenbroek 
1234*83ee113eSDavid van Moolenbroek 		/* Option code 0 is always illegal for us, thanks
1235*83ee113eSDavid van Moolenbroek 		 * to the option decoder.
1236*83ee113eSDavid van Moolenbroek 		 */
1237*83ee113eSDavid van Moolenbroek 		if (code == 0 || code == universe->end) {
1238*83ee113eSDavid van Moolenbroek 			parse_warn(cfile, "Option codes 0 and %u are illegal "
1239*83ee113eSDavid van Moolenbroek 					  "in the %s space.", universe->end,
1240*83ee113eSDavid van Moolenbroek 					  universe->name);
1241*83ee113eSDavid van Moolenbroek 			skip_to_semi(cfile);
1242*83ee113eSDavid van Moolenbroek 			dfree(uname, MDL);
1243*83ee113eSDavid van Moolenbroek 			return ISC_R_FAILURE;
1244*83ee113eSDavid van Moolenbroek 		}
1245*83ee113eSDavid van Moolenbroek 
1246*83ee113eSDavid van Moolenbroek 		/* It's odd to think of unknown option codes as
1247*83ee113eSDavid van Moolenbroek 		 * being known, but this means we know what the
1248*83ee113eSDavid van Moolenbroek 		 * parsed name is talking about.
1249*83ee113eSDavid van Moolenbroek 		 */
1250*83ee113eSDavid van Moolenbroek 		if (known)
1251*83ee113eSDavid van Moolenbroek 			*known = 1;
1252*83ee113eSDavid van Moolenbroek 
1253*83ee113eSDavid van Moolenbroek 		option_code_hash_lookup(opt, universe->code_hash,
1254*83ee113eSDavid van Moolenbroek 					&code, 0, MDL);
1255*83ee113eSDavid van Moolenbroek 		option = *opt;
1256*83ee113eSDavid van Moolenbroek 
1257*83ee113eSDavid van Moolenbroek 		/* If we did not find an option of that code,
1258*83ee113eSDavid van Moolenbroek 		 * manufacture an unknown-xxx option definition.
1259*83ee113eSDavid van Moolenbroek 		 * Its single reference will ensure that it is
1260*83ee113eSDavid van Moolenbroek 		 * deleted once the option is recycled out of
1261*83ee113eSDavid van Moolenbroek 		 * existence (by the parent).
1262*83ee113eSDavid van Moolenbroek 		 */
1263*83ee113eSDavid van Moolenbroek 		if (option == NULL) {
1264*83ee113eSDavid van Moolenbroek 			option = new_option(val, MDL);
1265*83ee113eSDavid van Moolenbroek 			option->universe = universe;
1266*83ee113eSDavid van Moolenbroek 			option->code = code;
1267*83ee113eSDavid van Moolenbroek 			option->format = default_option_format;
1268*83ee113eSDavid van Moolenbroek 			option_reference(opt, option, MDL);
1269*83ee113eSDavid van Moolenbroek 		} else
1270*83ee113eSDavid van Moolenbroek 			log_info("option %s has been redefined as option %s.  "
1271*83ee113eSDavid van Moolenbroek 				 "Please update your configs if neccessary.",
1272*83ee113eSDavid van Moolenbroek 				 val, option->name);
1273*83ee113eSDavid van Moolenbroek 	/* If we've been told to allocate, that means that this
1274*83ee113eSDavid van Moolenbroek 	 * (might) be an option code definition, so we'll create
1275*83ee113eSDavid van Moolenbroek 	 * an option structure and return it for the parent to
1276*83ee113eSDavid van Moolenbroek 	 * decide.
1277*83ee113eSDavid van Moolenbroek 	 */
1278*83ee113eSDavid van Moolenbroek 	} else if (allocate) {
1279*83ee113eSDavid van Moolenbroek 		option = new_option(val, MDL);
1280*83ee113eSDavid van Moolenbroek 		option -> universe = universe;
1281*83ee113eSDavid van Moolenbroek 		option_reference(opt, option, MDL);
1282*83ee113eSDavid van Moolenbroek 	} else {
1283*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "no option named %s in space %s",
1284*83ee113eSDavid van Moolenbroek 			   val, universe->name);
1285*83ee113eSDavid van Moolenbroek 		skip_to_semi (cfile);
1286*83ee113eSDavid van Moolenbroek 		dfree(uname, MDL);
1287*83ee113eSDavid van Moolenbroek 		return ISC_R_NOTFOUND;
1288*83ee113eSDavid van Moolenbroek 	}
1289*83ee113eSDavid van Moolenbroek 
1290*83ee113eSDavid van Moolenbroek 	/* Free the initial identifier token. */
1291*83ee113eSDavid van Moolenbroek 	dfree (uname, MDL);
1292*83ee113eSDavid van Moolenbroek 	return ISC_R_SUCCESS;
1293*83ee113eSDavid van Moolenbroek }
1294*83ee113eSDavid van Moolenbroek 
1295*83ee113eSDavid van Moolenbroek /* IDENTIFIER [WIDTHS] SEMI
1296*83ee113eSDavid van Moolenbroek  *   WIDTHS ~= LENGTH WIDTH NUMBER
1297*83ee113eSDavid van Moolenbroek  *             CODE WIDTH NUMBER
1298*83ee113eSDavid van Moolenbroek  */
1299*83ee113eSDavid van Moolenbroek 
parse_option_space_decl(cfile)1300*83ee113eSDavid van Moolenbroek void parse_option_space_decl (cfile)
1301*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
1302*83ee113eSDavid van Moolenbroek {
1303*83ee113eSDavid van Moolenbroek 	int token;
1304*83ee113eSDavid van Moolenbroek 	const char *val;
1305*83ee113eSDavid van Moolenbroek 	struct universe **ua, *nu;
1306*83ee113eSDavid van Moolenbroek 	char *nu_name;
1307*83ee113eSDavid van Moolenbroek 	int tsize=1, lsize=1, hsize = 0;
1308*83ee113eSDavid van Moolenbroek 
1309*83ee113eSDavid van Moolenbroek 	skip_token(&val, (unsigned *)0, cfile);  /* Discard the SPACE token,
1310*83ee113eSDavid van Moolenbroek 						     which was checked by the
1311*83ee113eSDavid van Moolenbroek 						     caller. */
1312*83ee113eSDavid van Moolenbroek 	token = next_token (&val, (unsigned *)0, cfile);
1313*83ee113eSDavid van Moolenbroek 	if (!is_identifier (token)) {
1314*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "expecting identifier.");
1315*83ee113eSDavid van Moolenbroek 		skip_to_semi (cfile);
1316*83ee113eSDavid van Moolenbroek 		return;
1317*83ee113eSDavid van Moolenbroek 	}
1318*83ee113eSDavid van Moolenbroek 	nu = new_universe (MDL);
1319*83ee113eSDavid van Moolenbroek 	if (!nu)
1320*83ee113eSDavid van Moolenbroek 		log_fatal ("No memory for new option space.");
1321*83ee113eSDavid van Moolenbroek 
1322*83ee113eSDavid van Moolenbroek 	/* Set up the server option universe... */
1323*83ee113eSDavid van Moolenbroek 	nu_name = dmalloc (strlen (val) + 1, MDL);
1324*83ee113eSDavid van Moolenbroek 	if (!nu_name)
1325*83ee113eSDavid van Moolenbroek 		log_fatal ("No memory for new option space name.");
1326*83ee113eSDavid van Moolenbroek 	strcpy (nu_name, val);
1327*83ee113eSDavid van Moolenbroek 	nu -> name = nu_name;
1328*83ee113eSDavid van Moolenbroek 
1329*83ee113eSDavid van Moolenbroek 	do {
1330*83ee113eSDavid van Moolenbroek 		token = next_token(&val, NULL, cfile);
1331*83ee113eSDavid van Moolenbroek 		switch(token) {
1332*83ee113eSDavid van Moolenbroek 		      case SEMI:
1333*83ee113eSDavid van Moolenbroek 			break;
1334*83ee113eSDavid van Moolenbroek 
1335*83ee113eSDavid van Moolenbroek 		      case CODE:
1336*83ee113eSDavid van Moolenbroek 			token = next_token(&val, NULL, cfile);
1337*83ee113eSDavid van Moolenbroek 			if (token != WIDTH) {
1338*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "expecting width token.");
1339*83ee113eSDavid van Moolenbroek 				goto bad;
1340*83ee113eSDavid van Moolenbroek 			}
1341*83ee113eSDavid van Moolenbroek 
1342*83ee113eSDavid van Moolenbroek 			token = next_token(&val, NULL, cfile);
1343*83ee113eSDavid van Moolenbroek 			if (token != NUMBER) {
1344*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "expecting number 1, 2, 4.");
1345*83ee113eSDavid van Moolenbroek 				goto bad;
1346*83ee113eSDavid van Moolenbroek 			}
1347*83ee113eSDavid van Moolenbroek 
1348*83ee113eSDavid van Moolenbroek 			tsize = atoi(val);
1349*83ee113eSDavid van Moolenbroek 
1350*83ee113eSDavid van Moolenbroek 
1351*83ee113eSDavid van Moolenbroek 			switch (tsize) {
1352*83ee113eSDavid van Moolenbroek 			      case 1:
1353*83ee113eSDavid van Moolenbroek 				if (!hsize)
1354*83ee113eSDavid van Moolenbroek 					hsize = BYTE_NAME_HASH_SIZE;
1355*83ee113eSDavid van Moolenbroek 				break;
1356*83ee113eSDavid van Moolenbroek 			      case 2:
1357*83ee113eSDavid van Moolenbroek 				if (!hsize)
1358*83ee113eSDavid van Moolenbroek 					hsize = WORD_NAME_HASH_SIZE;
1359*83ee113eSDavid van Moolenbroek 				break;
1360*83ee113eSDavid van Moolenbroek 			      case 4:
1361*83ee113eSDavid van Moolenbroek 				if (!hsize)
1362*83ee113eSDavid van Moolenbroek 					hsize = QUAD_NAME_HASH_SIZE;
1363*83ee113eSDavid van Moolenbroek 				break;
1364*83ee113eSDavid van Moolenbroek 			      default:
1365*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "invalid code width (%d), "
1366*83ee113eSDavid van Moolenbroek 					          "expecting a 1, 2 or 4.",
1367*83ee113eSDavid van Moolenbroek 					   tsize);
1368*83ee113eSDavid van Moolenbroek 				goto bad;
1369*83ee113eSDavid van Moolenbroek 			}
1370*83ee113eSDavid van Moolenbroek 			break;
1371*83ee113eSDavid van Moolenbroek 
1372*83ee113eSDavid van Moolenbroek 		      case LENGTH:
1373*83ee113eSDavid van Moolenbroek 			token = next_token(&val, NULL, cfile);
1374*83ee113eSDavid van Moolenbroek 			if (token != WIDTH) {
1375*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "expecting width token.");
1376*83ee113eSDavid van Moolenbroek 				goto bad;
1377*83ee113eSDavid van Moolenbroek 			}
1378*83ee113eSDavid van Moolenbroek 
1379*83ee113eSDavid van Moolenbroek 			token = next_token(&val, NULL, cfile);
1380*83ee113eSDavid van Moolenbroek 			if (token != NUMBER) {
1381*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "expecting number 1 or 2.");
1382*83ee113eSDavid van Moolenbroek 				goto bad;
1383*83ee113eSDavid van Moolenbroek 			}
1384*83ee113eSDavid van Moolenbroek 
1385*83ee113eSDavid van Moolenbroek 			lsize = atoi(val);
1386*83ee113eSDavid van Moolenbroek 			if (lsize != 1 && lsize != 2) {
1387*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "invalid length width (%d) "
1388*83ee113eSDavid van Moolenbroek 						  "expecting 1 or 2.", lsize);
1389*83ee113eSDavid van Moolenbroek 				goto bad;
1390*83ee113eSDavid van Moolenbroek 			}
1391*83ee113eSDavid van Moolenbroek 
1392*83ee113eSDavid van Moolenbroek 			break;
1393*83ee113eSDavid van Moolenbroek 
1394*83ee113eSDavid van Moolenbroek 		      case HASH:
1395*83ee113eSDavid van Moolenbroek 			token = next_token(&val, NULL, cfile);
1396*83ee113eSDavid van Moolenbroek 			if (token != SIZE) {
1397*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "expecting size token.");
1398*83ee113eSDavid van Moolenbroek 				goto bad;
1399*83ee113eSDavid van Moolenbroek 			}
1400*83ee113eSDavid van Moolenbroek 
1401*83ee113eSDavid van Moolenbroek 			token = next_token(&val, NULL, cfile);
1402*83ee113eSDavid van Moolenbroek 			if (token != NUMBER) {
1403*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "expecting a 10base number");
1404*83ee113eSDavid van Moolenbroek 				goto bad;
1405*83ee113eSDavid van Moolenbroek 			}
1406*83ee113eSDavid van Moolenbroek 
1407*83ee113eSDavid van Moolenbroek 			/* (2^31)-1 is the highest Mersenne prime we should
1408*83ee113eSDavid van Moolenbroek 			 * probably allow...
1409*83ee113eSDavid van Moolenbroek 			 */
1410*83ee113eSDavid van Moolenbroek 			hsize = atoi(val);
1411*83ee113eSDavid van Moolenbroek 			if (hsize < 0 || hsize > 0x7FFFFFFF) {
1412*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "invalid hash length: %d",
1413*83ee113eSDavid van Moolenbroek 					   hsize);
1414*83ee113eSDavid van Moolenbroek 				goto bad;
1415*83ee113eSDavid van Moolenbroek 			}
1416*83ee113eSDavid van Moolenbroek 
1417*83ee113eSDavid van Moolenbroek 			break;
1418*83ee113eSDavid van Moolenbroek 
1419*83ee113eSDavid van Moolenbroek 		      default:
1420*83ee113eSDavid van Moolenbroek 			parse_warn(cfile, "Unexpected token.");
1421*83ee113eSDavid van Moolenbroek 		}
1422*83ee113eSDavid van Moolenbroek 	} while (token != SEMI);
1423*83ee113eSDavid van Moolenbroek 
1424*83ee113eSDavid van Moolenbroek 	if (!hsize)
1425*83ee113eSDavid van Moolenbroek 		hsize = DEFAULT_SPACE_HASH_SIZE;
1426*83ee113eSDavid van Moolenbroek 
1427*83ee113eSDavid van Moolenbroek 	nu -> lookup_func = lookup_hashed_option;
1428*83ee113eSDavid van Moolenbroek 	nu -> option_state_dereference = hashed_option_state_dereference;
1429*83ee113eSDavid van Moolenbroek 	nu -> foreach = hashed_option_space_foreach;
1430*83ee113eSDavid van Moolenbroek 	nu -> save_func = save_hashed_option;
1431*83ee113eSDavid van Moolenbroek 	nu -> delete_func = delete_hashed_option;
1432*83ee113eSDavid van Moolenbroek 	nu -> encapsulate = hashed_option_space_encapsulate;
1433*83ee113eSDavid van Moolenbroek 	nu -> decode = parse_option_buffer;
1434*83ee113eSDavid van Moolenbroek 	nu -> length_size = lsize;
1435*83ee113eSDavid van Moolenbroek 	nu -> tag_size = tsize;
1436*83ee113eSDavid van Moolenbroek 	switch(tsize) {
1437*83ee113eSDavid van Moolenbroek 	      case 1:
1438*83ee113eSDavid van Moolenbroek 		nu->get_tag = getUChar;
1439*83ee113eSDavid van Moolenbroek 		nu->store_tag = putUChar;
1440*83ee113eSDavid van Moolenbroek 		break;
1441*83ee113eSDavid van Moolenbroek 	      case 2:
1442*83ee113eSDavid van Moolenbroek 		nu->get_tag = getUShort;
1443*83ee113eSDavid van Moolenbroek 		nu->store_tag = putUShort;
1444*83ee113eSDavid van Moolenbroek 		break;
1445*83ee113eSDavid van Moolenbroek 	      case 4:
1446*83ee113eSDavid van Moolenbroek 		nu->get_tag = getULong;
1447*83ee113eSDavid van Moolenbroek 		nu->store_tag = putULong;
1448*83ee113eSDavid van Moolenbroek 		break;
1449*83ee113eSDavid van Moolenbroek 	      default:
1450*83ee113eSDavid van Moolenbroek 		log_fatal("Impossible condition at %s:%d.", MDL);
1451*83ee113eSDavid van Moolenbroek 	}
1452*83ee113eSDavid van Moolenbroek 	switch(lsize) {
1453*83ee113eSDavid van Moolenbroek 	     case 0:
1454*83ee113eSDavid van Moolenbroek 		nu->get_length = NULL;
1455*83ee113eSDavid van Moolenbroek 		nu->store_length = NULL;
1456*83ee113eSDavid van Moolenbroek 		break;
1457*83ee113eSDavid van Moolenbroek 	     case 1:
1458*83ee113eSDavid van Moolenbroek 		nu->get_length = getUChar;
1459*83ee113eSDavid van Moolenbroek 		nu->store_length = putUChar;
1460*83ee113eSDavid van Moolenbroek 		break;
1461*83ee113eSDavid van Moolenbroek 	     case 2:
1462*83ee113eSDavid van Moolenbroek 		nu->get_length = getUShort;
1463*83ee113eSDavid van Moolenbroek 		nu->store_length = putUShort;
1464*83ee113eSDavid van Moolenbroek 		break;
1465*83ee113eSDavid van Moolenbroek 	     default:
1466*83ee113eSDavid van Moolenbroek 		log_fatal("Impossible condition at %s:%d.", MDL);
1467*83ee113eSDavid van Moolenbroek 	}
1468*83ee113eSDavid van Moolenbroek 	nu -> index = universe_count++;
1469*83ee113eSDavid van Moolenbroek 	if (nu -> index >= universe_max) {
1470*83ee113eSDavid van Moolenbroek 		ua = dmalloc (universe_max * 2 * sizeof *ua, MDL);
1471*83ee113eSDavid van Moolenbroek 		if (!ua)
1472*83ee113eSDavid van Moolenbroek 			log_fatal ("No memory to expand option space array.");
1473*83ee113eSDavid van Moolenbroek 		memcpy (ua, universes, universe_max * sizeof *ua);
1474*83ee113eSDavid van Moolenbroek 		universe_max *= 2;
1475*83ee113eSDavid van Moolenbroek 		dfree (universes, MDL);
1476*83ee113eSDavid van Moolenbroek 		universes = ua;
1477*83ee113eSDavid van Moolenbroek 	}
1478*83ee113eSDavid van Moolenbroek 	universes [nu -> index] = nu;
1479*83ee113eSDavid van Moolenbroek 	if (!option_name_new_hash(&nu->name_hash, hsize, MDL) ||
1480*83ee113eSDavid van Moolenbroek 	    !option_code_new_hash(&nu->code_hash, hsize, MDL))
1481*83ee113eSDavid van Moolenbroek 		log_fatal("Can't allocate %s option hash table.", nu->name);
1482*83ee113eSDavid van Moolenbroek 	universe_hash_add (universe_hash, nu -> name, 0, nu, MDL);
1483*83ee113eSDavid van Moolenbroek 	return;
1484*83ee113eSDavid van Moolenbroek 
1485*83ee113eSDavid van Moolenbroek     bad:
1486*83ee113eSDavid van Moolenbroek 	dfree(nu_name, MDL);
1487*83ee113eSDavid van Moolenbroek 	dfree(nu, MDL);
1488*83ee113eSDavid van Moolenbroek }
1489*83ee113eSDavid van Moolenbroek 
1490*83ee113eSDavid van Moolenbroek /* This is faked up to look good right now.   Ideally, this should do a
1491*83ee113eSDavid van Moolenbroek    recursive parse and allow arbitrary data structure definitions, but for
1492*83ee113eSDavid van Moolenbroek    now it just allows you to specify a single type, an array of single types,
1493*83ee113eSDavid van Moolenbroek    a sequence of types, or an array of sequences of types.
1494*83ee113eSDavid van Moolenbroek 
1495*83ee113eSDavid van Moolenbroek    ocd :== NUMBER EQUALS ocsd SEMI
1496*83ee113eSDavid van Moolenbroek 
1497*83ee113eSDavid van Moolenbroek    ocsd :== ocsd_type |
1498*83ee113eSDavid van Moolenbroek 	    ocsd_type_sequence |
1499*83ee113eSDavid van Moolenbroek 	    ARRAY OF ocsd_simple_type_sequence
1500*83ee113eSDavid van Moolenbroek 
1501*83ee113eSDavid van Moolenbroek    ocsd_type_sequence :== LBRACE ocsd_types RBRACE
1502*83ee113eSDavid van Moolenbroek 
1503*83ee113eSDavid van Moolenbroek    ocsd_simple_type_sequence :== LBRACE ocsd_simple_types RBRACE
1504*83ee113eSDavid van Moolenbroek 
1505*83ee113eSDavid van Moolenbroek    ocsd_types :== ocsd_type |
1506*83ee113eSDavid van Moolenbroek 		  ocsd_types ocsd_type
1507*83ee113eSDavid van Moolenbroek 
1508*83ee113eSDavid van Moolenbroek    ocsd_type :== ocsd_simple_type |
1509*83ee113eSDavid van Moolenbroek 		 ARRAY OF ocsd_simple_type
1510*83ee113eSDavid van Moolenbroek 
1511*83ee113eSDavid van Moolenbroek    ocsd_simple_types :== ocsd_simple_type |
1512*83ee113eSDavid van Moolenbroek 			 ocsd_simple_types ocsd_simple_type
1513*83ee113eSDavid van Moolenbroek 
1514*83ee113eSDavid van Moolenbroek    ocsd_simple_type :== BOOLEAN |
1515*83ee113eSDavid van Moolenbroek 			INTEGER NUMBER |
1516*83ee113eSDavid van Moolenbroek 			SIGNED INTEGER NUMBER |
1517*83ee113eSDavid van Moolenbroek 			UNSIGNED INTEGER NUMBER |
1518*83ee113eSDavid van Moolenbroek 			IP-ADDRESS |
1519*83ee113eSDavid van Moolenbroek 			TEXT |
1520*83ee113eSDavid van Moolenbroek 			STRING |
1521*83ee113eSDavid van Moolenbroek 			ENCAPSULATE identifier */
1522*83ee113eSDavid van Moolenbroek 
parse_option_code_definition(cfile,option)1523*83ee113eSDavid van Moolenbroek int parse_option_code_definition (cfile, option)
1524*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
1525*83ee113eSDavid van Moolenbroek 	struct option *option;
1526*83ee113eSDavid van Moolenbroek {
1527*83ee113eSDavid van Moolenbroek 	const char *val;
1528*83ee113eSDavid van Moolenbroek 	enum dhcp_token token;
1529*83ee113eSDavid van Moolenbroek 	struct option *oldopt;
1530*83ee113eSDavid van Moolenbroek 	unsigned arrayp = 0;
1531*83ee113eSDavid van Moolenbroek 	int recordp = 0;
1532*83ee113eSDavid van Moolenbroek 	int no_more_in_record = 0;
1533*83ee113eSDavid van Moolenbroek 	char tokbuf [128];
1534*83ee113eSDavid van Moolenbroek 	unsigned tokix = 0;
1535*83ee113eSDavid van Moolenbroek 	char type;
1536*83ee113eSDavid van Moolenbroek 	int is_signed;
1537*83ee113eSDavid van Moolenbroek 	char *s;
1538*83ee113eSDavid van Moolenbroek 	int has_encapsulation = 0;
1539*83ee113eSDavid van Moolenbroek 	struct universe *encapsulated;
1540*83ee113eSDavid van Moolenbroek 
1541*83ee113eSDavid van Moolenbroek 	/* Parse the option code. */
1542*83ee113eSDavid van Moolenbroek 	token = next_token (&val, (unsigned *)0, cfile);
1543*83ee113eSDavid van Moolenbroek 	if (token != NUMBER) {
1544*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "expecting option code number.");
1545*83ee113eSDavid van Moolenbroek 		skip_to_semi (cfile);
1546*83ee113eSDavid van Moolenbroek 		return 0;
1547*83ee113eSDavid van Moolenbroek 	}
1548*83ee113eSDavid van Moolenbroek 	option -> code = atoi (val);
1549*83ee113eSDavid van Moolenbroek 
1550*83ee113eSDavid van Moolenbroek 	token = next_token (&val, (unsigned *)0, cfile);
1551*83ee113eSDavid van Moolenbroek 	if (token != EQUAL) {
1552*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "expecting \"=\"");
1553*83ee113eSDavid van Moolenbroek 		skip_to_semi (cfile);
1554*83ee113eSDavid van Moolenbroek 		return 0;
1555*83ee113eSDavid van Moolenbroek 	}
1556*83ee113eSDavid van Moolenbroek 
1557*83ee113eSDavid van Moolenbroek 	/* See if this is an array. */
1558*83ee113eSDavid van Moolenbroek 	token = next_token (&val, (unsigned *)0, cfile);
1559*83ee113eSDavid van Moolenbroek 	if (token == ARRAY) {
1560*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
1561*83ee113eSDavid van Moolenbroek 		if (token != OF) {
1562*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "expecting \"of\".");
1563*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
1564*83ee113eSDavid van Moolenbroek 			return 0;
1565*83ee113eSDavid van Moolenbroek 		}
1566*83ee113eSDavid van Moolenbroek 		arrayp = 1;
1567*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
1568*83ee113eSDavid van Moolenbroek 	}
1569*83ee113eSDavid van Moolenbroek 
1570*83ee113eSDavid van Moolenbroek 	if (token == LBRACE) {
1571*83ee113eSDavid van Moolenbroek 		recordp = 1;
1572*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
1573*83ee113eSDavid van Moolenbroek 	}
1574*83ee113eSDavid van Moolenbroek 
1575*83ee113eSDavid van Moolenbroek 	/* At this point we're expecting a data type. */
1576*83ee113eSDavid van Moolenbroek       next_type:
1577*83ee113eSDavid van Moolenbroek 	if (has_encapsulation) {
1578*83ee113eSDavid van Moolenbroek 		parse_warn (cfile,
1579*83ee113eSDavid van Moolenbroek 			    "encapsulate must always be the last item.");
1580*83ee113eSDavid van Moolenbroek 		skip_to_semi (cfile);
1581*83ee113eSDavid van Moolenbroek 		return 0;
1582*83ee113eSDavid van Moolenbroek 	}
1583*83ee113eSDavid van Moolenbroek 
1584*83ee113eSDavid van Moolenbroek 	switch (token) {
1585*83ee113eSDavid van Moolenbroek 	      case ARRAY:
1586*83ee113eSDavid van Moolenbroek 		if (arrayp) {
1587*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "no nested arrays.");
1588*83ee113eSDavid van Moolenbroek 			skip_to_rbrace (cfile, recordp);
1589*83ee113eSDavid van Moolenbroek 			if (recordp)
1590*83ee113eSDavid van Moolenbroek 				skip_to_semi (cfile);
1591*83ee113eSDavid van Moolenbroek 			return 0;
1592*83ee113eSDavid van Moolenbroek 		}
1593*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
1594*83ee113eSDavid van Moolenbroek 		if (token != OF) {
1595*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "expecting \"of\".");
1596*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
1597*83ee113eSDavid van Moolenbroek 			return 0;
1598*83ee113eSDavid van Moolenbroek 		}
1599*83ee113eSDavid van Moolenbroek 		arrayp = recordp + 1;
1600*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
1601*83ee113eSDavid van Moolenbroek 		if ((recordp) && (token == LBRACE)) {
1602*83ee113eSDavid van Moolenbroek 			parse_warn (cfile,
1603*83ee113eSDavid van Moolenbroek 				    "only uniform array inside record.");
1604*83ee113eSDavid van Moolenbroek 			skip_to_rbrace (cfile, recordp + 1);
1605*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
1606*83ee113eSDavid van Moolenbroek 			return 0;
1607*83ee113eSDavid van Moolenbroek 		}
1608*83ee113eSDavid van Moolenbroek 		goto next_type;
1609*83ee113eSDavid van Moolenbroek 	      case BOOLEAN:
1610*83ee113eSDavid van Moolenbroek 		type = 'f';
1611*83ee113eSDavid van Moolenbroek 		break;
1612*83ee113eSDavid van Moolenbroek 	      case INTEGER:
1613*83ee113eSDavid van Moolenbroek 		is_signed = 1;
1614*83ee113eSDavid van Moolenbroek 	      parse_integer:
1615*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
1616*83ee113eSDavid van Moolenbroek 		if (token != NUMBER) {
1617*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "expecting number.");
1618*83ee113eSDavid van Moolenbroek 			skip_to_rbrace (cfile, recordp);
1619*83ee113eSDavid van Moolenbroek 			if (recordp)
1620*83ee113eSDavid van Moolenbroek 				skip_to_semi (cfile);
1621*83ee113eSDavid van Moolenbroek 			return 0;
1622*83ee113eSDavid van Moolenbroek 		}
1623*83ee113eSDavid van Moolenbroek 		switch (atoi (val)) {
1624*83ee113eSDavid van Moolenbroek 		      case 8:
1625*83ee113eSDavid van Moolenbroek 			type = is_signed ? 'b' : 'B';
1626*83ee113eSDavid van Moolenbroek 			break;
1627*83ee113eSDavid van Moolenbroek 		      case 16:
1628*83ee113eSDavid van Moolenbroek 			type = is_signed ? 's' : 'S';
1629*83ee113eSDavid van Moolenbroek 			break;
1630*83ee113eSDavid van Moolenbroek 		      case 32:
1631*83ee113eSDavid van Moolenbroek 			type = is_signed ? 'l' : 'L';
1632*83ee113eSDavid van Moolenbroek 			break;
1633*83ee113eSDavid van Moolenbroek 		      default:
1634*83ee113eSDavid van Moolenbroek 			parse_warn (cfile,
1635*83ee113eSDavid van Moolenbroek 				    "%s bit precision is not supported.", val);
1636*83ee113eSDavid van Moolenbroek 			skip_to_rbrace (cfile, recordp);
1637*83ee113eSDavid van Moolenbroek 			if (recordp)
1638*83ee113eSDavid van Moolenbroek 				skip_to_semi (cfile);
1639*83ee113eSDavid van Moolenbroek 			return 0;
1640*83ee113eSDavid van Moolenbroek 		}
1641*83ee113eSDavid van Moolenbroek 		break;
1642*83ee113eSDavid van Moolenbroek 	      case SIGNED:
1643*83ee113eSDavid van Moolenbroek 		is_signed = 1;
1644*83ee113eSDavid van Moolenbroek 	      parse_signed:
1645*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
1646*83ee113eSDavid van Moolenbroek 		if (token != INTEGER) {
1647*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "expecting \"integer\" keyword.");
1648*83ee113eSDavid van Moolenbroek 			skip_to_rbrace (cfile, recordp);
1649*83ee113eSDavid van Moolenbroek 			if (recordp)
1650*83ee113eSDavid van Moolenbroek 				skip_to_semi (cfile);
1651*83ee113eSDavid van Moolenbroek 			return 0;
1652*83ee113eSDavid van Moolenbroek 		}
1653*83ee113eSDavid van Moolenbroek 		goto parse_integer;
1654*83ee113eSDavid van Moolenbroek 	      case UNSIGNED:
1655*83ee113eSDavid van Moolenbroek 		is_signed = 0;
1656*83ee113eSDavid van Moolenbroek 		goto parse_signed;
1657*83ee113eSDavid van Moolenbroek 
1658*83ee113eSDavid van Moolenbroek 	      case IP_ADDRESS:
1659*83ee113eSDavid van Moolenbroek 		type = 'I';
1660*83ee113eSDavid van Moolenbroek 		break;
1661*83ee113eSDavid van Moolenbroek 	      case IP6_ADDRESS:
1662*83ee113eSDavid van Moolenbroek 		type = '6';
1663*83ee113eSDavid van Moolenbroek 		break;
1664*83ee113eSDavid van Moolenbroek 	      case DOMAIN_NAME:
1665*83ee113eSDavid van Moolenbroek 		type = 'd';
1666*83ee113eSDavid van Moolenbroek 		goto no_arrays;
1667*83ee113eSDavid van Moolenbroek 	      case DOMAIN_LIST:
1668*83ee113eSDavid van Moolenbroek 		/* Consume optional compression indicator. */
1669*83ee113eSDavid van Moolenbroek 		token = peek_token(&val, NULL, cfile);
1670*83ee113eSDavid van Moolenbroek 		if (token == COMPRESSED) {
1671*83ee113eSDavid van Moolenbroek 			skip_token(&val, NULL, cfile);
1672*83ee113eSDavid van Moolenbroek 			tokbuf[tokix++] = 'D';
1673*83ee113eSDavid van Moolenbroek 			type = 'c';
1674*83ee113eSDavid van Moolenbroek 		} else
1675*83ee113eSDavid van Moolenbroek 			type = 'D';
1676*83ee113eSDavid van Moolenbroek 		goto no_arrays;
1677*83ee113eSDavid van Moolenbroek 	      case TEXT:
1678*83ee113eSDavid van Moolenbroek 		type = 't';
1679*83ee113eSDavid van Moolenbroek 	      no_arrays:
1680*83ee113eSDavid van Moolenbroek 		if (arrayp) {
1681*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "arrays of text strings not %s",
1682*83ee113eSDavid van Moolenbroek 				    "yet supported.");
1683*83ee113eSDavid van Moolenbroek 			skip_to_rbrace (cfile, recordp);
1684*83ee113eSDavid van Moolenbroek 			if (recordp)
1685*83ee113eSDavid van Moolenbroek 				skip_to_semi (cfile);
1686*83ee113eSDavid van Moolenbroek 			return 0;
1687*83ee113eSDavid van Moolenbroek 		}
1688*83ee113eSDavid van Moolenbroek 		no_more_in_record = 1;
1689*83ee113eSDavid van Moolenbroek 		break;
1690*83ee113eSDavid van Moolenbroek 	      case STRING_TOKEN:
1691*83ee113eSDavid van Moolenbroek 		type = 'X';
1692*83ee113eSDavid van Moolenbroek 		goto no_arrays;
1693*83ee113eSDavid van Moolenbroek 
1694*83ee113eSDavid van Moolenbroek 	      case ENCAPSULATE:
1695*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
1696*83ee113eSDavid van Moolenbroek 		if (!is_identifier (token)) {
1697*83ee113eSDavid van Moolenbroek 			parse_warn (cfile,
1698*83ee113eSDavid van Moolenbroek 				    "expecting option space identifier");
1699*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
1700*83ee113eSDavid van Moolenbroek 			return 0;
1701*83ee113eSDavid van Moolenbroek 		}
1702*83ee113eSDavid van Moolenbroek 		encapsulated = NULL;
1703*83ee113eSDavid van Moolenbroek 		if (!universe_hash_lookup(&encapsulated, universe_hash,
1704*83ee113eSDavid van Moolenbroek 					  val, strlen(val), MDL)) {
1705*83ee113eSDavid van Moolenbroek 			parse_warn(cfile, "unknown option space %s", val);
1706*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
1707*83ee113eSDavid van Moolenbroek 			return 0;
1708*83ee113eSDavid van Moolenbroek 		}
1709*83ee113eSDavid van Moolenbroek 		if (strlen (val) + tokix + 2 > sizeof (tokbuf))
1710*83ee113eSDavid van Moolenbroek 			goto toobig;
1711*83ee113eSDavid van Moolenbroek 		tokbuf [tokix++] = 'E';
1712*83ee113eSDavid van Moolenbroek 		strcpy (&tokbuf [tokix], val);
1713*83ee113eSDavid van Moolenbroek 		tokix += strlen (val);
1714*83ee113eSDavid van Moolenbroek 		type = '.';
1715*83ee113eSDavid van Moolenbroek 		has_encapsulation = 1;
1716*83ee113eSDavid van Moolenbroek 		break;
1717*83ee113eSDavid van Moolenbroek 
1718*83ee113eSDavid van Moolenbroek 	      case ZEROLEN:
1719*83ee113eSDavid van Moolenbroek 		type = 'Z';
1720*83ee113eSDavid van Moolenbroek 		if (arrayp) {
1721*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "array incompatible with zerolen.");
1722*83ee113eSDavid van Moolenbroek 			skip_to_rbrace (cfile, recordp);
1723*83ee113eSDavid van Moolenbroek 			if (recordp)
1724*83ee113eSDavid van Moolenbroek 				skip_to_semi (cfile);
1725*83ee113eSDavid van Moolenbroek 			return 0;
1726*83ee113eSDavid van Moolenbroek 		}
1727*83ee113eSDavid van Moolenbroek 		no_more_in_record = 1;
1728*83ee113eSDavid van Moolenbroek 		break;
1729*83ee113eSDavid van Moolenbroek 
1730*83ee113eSDavid van Moolenbroek 	      default:
1731*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "unknown data type %s", val);
1732*83ee113eSDavid van Moolenbroek 		skip_to_rbrace (cfile, recordp);
1733*83ee113eSDavid van Moolenbroek 		if (recordp)
1734*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
1735*83ee113eSDavid van Moolenbroek 		return 0;
1736*83ee113eSDavid van Moolenbroek 	}
1737*83ee113eSDavid van Moolenbroek 
1738*83ee113eSDavid van Moolenbroek 	if (tokix == sizeof tokbuf) {
1739*83ee113eSDavid van Moolenbroek 	      toobig:
1740*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "too many types in record.");
1741*83ee113eSDavid van Moolenbroek 		skip_to_rbrace (cfile, recordp);
1742*83ee113eSDavid van Moolenbroek 		if (recordp)
1743*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
1744*83ee113eSDavid van Moolenbroek 		return 0;
1745*83ee113eSDavid van Moolenbroek 	}
1746*83ee113eSDavid van Moolenbroek 	tokbuf [tokix++] = type;
1747*83ee113eSDavid van Moolenbroek 
1748*83ee113eSDavid van Moolenbroek 	if (recordp) {
1749*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
1750*83ee113eSDavid van Moolenbroek 		if (arrayp > recordp) {
1751*83ee113eSDavid van Moolenbroek 			if (tokix == sizeof tokbuf) {
1752*83ee113eSDavid van Moolenbroek 				parse_warn (cfile,
1753*83ee113eSDavid van Moolenbroek 					    "too many types in record.");
1754*83ee113eSDavid van Moolenbroek 				skip_to_rbrace (cfile, 1);
1755*83ee113eSDavid van Moolenbroek 				skip_to_semi (cfile);
1756*83ee113eSDavid van Moolenbroek 				return 0;
1757*83ee113eSDavid van Moolenbroek 			}
1758*83ee113eSDavid van Moolenbroek 			arrayp = 0;
1759*83ee113eSDavid van Moolenbroek 			tokbuf[tokix++] = 'a';
1760*83ee113eSDavid van Moolenbroek 		}
1761*83ee113eSDavid van Moolenbroek 		if (token == COMMA) {
1762*83ee113eSDavid van Moolenbroek 			if (no_more_in_record) {
1763*83ee113eSDavid van Moolenbroek 				parse_warn (cfile,
1764*83ee113eSDavid van Moolenbroek 					    "%s must be at end of record.",
1765*83ee113eSDavid van Moolenbroek 					    type == 't' ? "text" : "string");
1766*83ee113eSDavid van Moolenbroek 				skip_to_rbrace (cfile, 1);
1767*83ee113eSDavid van Moolenbroek 				if (recordp)
1768*83ee113eSDavid van Moolenbroek 					skip_to_semi (cfile);
1769*83ee113eSDavid van Moolenbroek 				return 0;
1770*83ee113eSDavid van Moolenbroek 			}
1771*83ee113eSDavid van Moolenbroek 			token = next_token (&val, (unsigned *)0, cfile);
1772*83ee113eSDavid van Moolenbroek 			goto next_type;
1773*83ee113eSDavid van Moolenbroek 		}
1774*83ee113eSDavid van Moolenbroek 		if (token != RBRACE) {
1775*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "expecting right brace.");
1776*83ee113eSDavid van Moolenbroek 			skip_to_rbrace (cfile, 1);
1777*83ee113eSDavid van Moolenbroek 			if (recordp)
1778*83ee113eSDavid van Moolenbroek 				skip_to_semi (cfile);
1779*83ee113eSDavid van Moolenbroek 			return 0;
1780*83ee113eSDavid van Moolenbroek 		}
1781*83ee113eSDavid van Moolenbroek 	}
1782*83ee113eSDavid van Moolenbroek 	if (!parse_semi (cfile)) {
1783*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "semicolon expected.");
1784*83ee113eSDavid van Moolenbroek 		skip_to_semi (cfile);
1785*83ee113eSDavid van Moolenbroek 		if (recordp)
1786*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
1787*83ee113eSDavid van Moolenbroek 		return 0;
1788*83ee113eSDavid van Moolenbroek 	}
1789*83ee113eSDavid van Moolenbroek 	if (has_encapsulation && arrayp) {
1790*83ee113eSDavid van Moolenbroek 		parse_warn (cfile,
1791*83ee113eSDavid van Moolenbroek 			    "Arrays of encapsulations don't make sense.");
1792*83ee113eSDavid van Moolenbroek 		return 0;
1793*83ee113eSDavid van Moolenbroek 	}
1794*83ee113eSDavid van Moolenbroek 	s = dmalloc(tokix + (arrayp ? 1 : 0) + 1, MDL);
1795*83ee113eSDavid van Moolenbroek 	if (s == NULL) {
1796*83ee113eSDavid van Moolenbroek 		log_fatal("no memory for option format.");
1797*83ee113eSDavid van Moolenbroek 	}
1798*83ee113eSDavid van Moolenbroek 	memcpy(s, tokbuf, tokix);
1799*83ee113eSDavid van Moolenbroek 	if (arrayp) {
1800*83ee113eSDavid van Moolenbroek 		s[tokix++] = (arrayp > recordp) ? 'a' : 'A';
1801*83ee113eSDavid van Moolenbroek 	}
1802*83ee113eSDavid van Moolenbroek 	s[tokix] = '\0';
1803*83ee113eSDavid van Moolenbroek 
1804*83ee113eSDavid van Moolenbroek 	option -> format = s;
1805*83ee113eSDavid van Moolenbroek 
1806*83ee113eSDavid van Moolenbroek 	oldopt = NULL;
1807*83ee113eSDavid van Moolenbroek 	option_code_hash_lookup(&oldopt, option->universe->code_hash,
1808*83ee113eSDavid van Moolenbroek 				&option->code, 0, MDL);
1809*83ee113eSDavid van Moolenbroek 	if (oldopt != NULL) {
1810*83ee113eSDavid van Moolenbroek 		/*
1811*83ee113eSDavid van Moolenbroek 		 * XXX: This illegalizes a configuration syntax that was
1812*83ee113eSDavid van Moolenbroek 		 * valid in 3.0.x, where multiple name->code mappings are
1813*83ee113eSDavid van Moolenbroek 		 * given, but only one code->name mapping survives.  It is
1814*83ee113eSDavid van Moolenbroek 		 * unclear what can or should be done at this point, but it
1815*83ee113eSDavid van Moolenbroek 		 * seems best to retain 3.0.x behaviour for upgrades to go
1816*83ee113eSDavid van Moolenbroek 		 * smoothly.
1817*83ee113eSDavid van Moolenbroek 		 *
1818*83ee113eSDavid van Moolenbroek 		option_name_hash_delete(option->universe->name_hash,
1819*83ee113eSDavid van Moolenbroek 					oldopt->name, 0, MDL);
1820*83ee113eSDavid van Moolenbroek 		 */
1821*83ee113eSDavid van Moolenbroek 		option_code_hash_delete(option->universe->code_hash,
1822*83ee113eSDavid van Moolenbroek 					&oldopt->code, 0, MDL);
1823*83ee113eSDavid van Moolenbroek 
1824*83ee113eSDavid van Moolenbroek 		option_dereference(&oldopt, MDL);
1825*83ee113eSDavid van Moolenbroek 	}
1826*83ee113eSDavid van Moolenbroek 	option_code_hash_add(option->universe->code_hash, &option->code, 0,
1827*83ee113eSDavid van Moolenbroek 			     option, MDL);
1828*83ee113eSDavid van Moolenbroek 	option_name_hash_add(option->universe->name_hash, option->name, 0,
1829*83ee113eSDavid van Moolenbroek 			     option, MDL);
1830*83ee113eSDavid van Moolenbroek 	if (has_encapsulation) {
1831*83ee113eSDavid van Moolenbroek 		/* INSIST(tokbuf[0] == 'E'); */
1832*83ee113eSDavid van Moolenbroek 		/* INSIST(encapsulated != NULL); */
1833*83ee113eSDavid van Moolenbroek 		if (!option_code_hash_lookup(&encapsulated->enc_opt,
1834*83ee113eSDavid van Moolenbroek 					     option->universe->code_hash,
1835*83ee113eSDavid van Moolenbroek 					     &option->code, 0, MDL)) {
1836*83ee113eSDavid van Moolenbroek 			log_fatal("error finding encapsulated option (%s:%d)",
1837*83ee113eSDavid van Moolenbroek 				  MDL);
1838*83ee113eSDavid van Moolenbroek 		}
1839*83ee113eSDavid van Moolenbroek 	}
1840*83ee113eSDavid van Moolenbroek 	return 1;
1841*83ee113eSDavid van Moolenbroek }
1842*83ee113eSDavid van Moolenbroek 
1843*83ee113eSDavid van Moolenbroek /*
1844*83ee113eSDavid van Moolenbroek  * base64 :== NUMBER_OR_STRING
1845*83ee113eSDavid van Moolenbroek  */
1846*83ee113eSDavid van Moolenbroek 
parse_base64(data,cfile)1847*83ee113eSDavid van Moolenbroek int parse_base64 (data, cfile)
1848*83ee113eSDavid van Moolenbroek 	struct data_string *data;
1849*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
1850*83ee113eSDavid van Moolenbroek {
1851*83ee113eSDavid van Moolenbroek 	const char *val;
1852*83ee113eSDavid van Moolenbroek 	int i, j, k;
1853*83ee113eSDavid van Moolenbroek 	unsigned acc = 0;
1854*83ee113eSDavid van Moolenbroek 	static unsigned char
1855*83ee113eSDavid van Moolenbroek 		from64 [] = {64, 64, 64, 64, 64, 64, 64, 64,  /*  \"#$%&' */
1856*83ee113eSDavid van Moolenbroek 			     64, 64, 64, 62, 64, 64, 64, 63,  /* ()*+,-./ */
1857*83ee113eSDavid van Moolenbroek 			     52, 53, 54, 55, 56, 57, 58, 59,  /* 01234567 */
1858*83ee113eSDavid van Moolenbroek 			     60, 61, 64, 64, 64, 64, 64, 64,  /* 89:;<=>? */
1859*83ee113eSDavid van Moolenbroek 			     64, 0, 1, 2, 3, 4, 5, 6,	      /* @ABCDEFG */
1860*83ee113eSDavid van Moolenbroek 			     7, 8, 9, 10, 11, 12, 13, 14,     /* HIJKLMNO */
1861*83ee113eSDavid van Moolenbroek 			     15, 16, 17, 18, 19, 20, 21, 22,  /* PQRSTUVW */
1862*83ee113eSDavid van Moolenbroek 			     23, 24, 25, 64, 64, 64, 64, 64,  /* XYZ[\]^_ */
1863*83ee113eSDavid van Moolenbroek 			     64, 26, 27, 28, 29, 30, 31, 32,  /* 'abcdefg */
1864*83ee113eSDavid van Moolenbroek 			     33, 34, 35, 36, 37, 38, 39, 40,  /* hijklmno */
1865*83ee113eSDavid van Moolenbroek 			     41, 42, 43, 44, 45, 46, 47, 48,  /* pqrstuvw */
1866*83ee113eSDavid van Moolenbroek 			     49, 50, 51, 64, 64, 64, 64, 64}; /* xyz{|}~  */
1867*83ee113eSDavid van Moolenbroek 	struct string_list *bufs = NULL,
1868*83ee113eSDavid van Moolenbroek 			   *last = NULL,
1869*83ee113eSDavid van Moolenbroek 			   *t;
1870*83ee113eSDavid van Moolenbroek 	int cc = 0;
1871*83ee113eSDavid van Moolenbroek 	int terminated = 0;
1872*83ee113eSDavid van Moolenbroek 	int valid_base64;
1873*83ee113eSDavid van Moolenbroek 
1874*83ee113eSDavid van Moolenbroek 	/* It's possible for a + or a / to cause a base64 quantity to be
1875*83ee113eSDavid van Moolenbroek 	   tokenized into more than one token, so we have to parse them all
1876*83ee113eSDavid van Moolenbroek 	   in before decoding. */
1877*83ee113eSDavid van Moolenbroek 	do {
1878*83ee113eSDavid van Moolenbroek 		unsigned l;
1879*83ee113eSDavid van Moolenbroek 
1880*83ee113eSDavid van Moolenbroek 		(void)next_token(&val, &l, cfile);
1881*83ee113eSDavid van Moolenbroek 		t = dmalloc(l + sizeof(*t), MDL);
1882*83ee113eSDavid van Moolenbroek 		if (t == NULL)
1883*83ee113eSDavid van Moolenbroek 			log_fatal("no memory for base64 buffer.");
1884*83ee113eSDavid van Moolenbroek 		memset(t, 0, (sizeof(*t)) - 1);
1885*83ee113eSDavid van Moolenbroek 		memcpy(t->string, val, l + 1);
1886*83ee113eSDavid van Moolenbroek 		cc += l;
1887*83ee113eSDavid van Moolenbroek 		if (last)
1888*83ee113eSDavid van Moolenbroek 			last->next = t;
1889*83ee113eSDavid van Moolenbroek 		else
1890*83ee113eSDavid van Moolenbroek 			bufs = t;
1891*83ee113eSDavid van Moolenbroek 		last = t;
1892*83ee113eSDavid van Moolenbroek 		(void)peek_token(&val, NULL, cfile);
1893*83ee113eSDavid van Moolenbroek 		valid_base64 = 1;
1894*83ee113eSDavid van Moolenbroek 		for (i = 0; val[i]; i++) {
1895*83ee113eSDavid van Moolenbroek 			/* Check to see if the character is valid.  It
1896*83ee113eSDavid van Moolenbroek 			   may be out of range or within the right range
1897*83ee113eSDavid van Moolenbroek 			   but not used in the mapping */
1898*83ee113eSDavid van Moolenbroek 			if (((val[i] < ' ') || (val[i] > 'z')) ||
1899*83ee113eSDavid van Moolenbroek 			    ((from64[val[i] - ' '] > 63) && (val[i] != '='))) {
1900*83ee113eSDavid van Moolenbroek 				valid_base64 = 0;
1901*83ee113eSDavid van Moolenbroek 				break; /* no need to continue for loop */
1902*83ee113eSDavid van Moolenbroek 			}
1903*83ee113eSDavid van Moolenbroek 		}
1904*83ee113eSDavid van Moolenbroek 	} while (valid_base64);
1905*83ee113eSDavid van Moolenbroek 
1906*83ee113eSDavid van Moolenbroek 	data->len = cc;
1907*83ee113eSDavid van Moolenbroek 	data->len = (data->len * 3) / 4;
1908*83ee113eSDavid van Moolenbroek 	if (!buffer_allocate(&data->buffer, data->len, MDL)) {
1909*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "can't allocate buffer for base64 data.");
1910*83ee113eSDavid van Moolenbroek 		data->len = 0;
1911*83ee113eSDavid van Moolenbroek 		data->data = NULL;
1912*83ee113eSDavid van Moolenbroek 		goto out;
1913*83ee113eSDavid van Moolenbroek 	}
1914*83ee113eSDavid van Moolenbroek 
1915*83ee113eSDavid van Moolenbroek 	j = k = 0;
1916*83ee113eSDavid van Moolenbroek 	for (t = bufs; t; t = t->next) {
1917*83ee113eSDavid van Moolenbroek 	    for (i = 0; t->string[i]; i++) {
1918*83ee113eSDavid van Moolenbroek 		unsigned foo = t->string[i];
1919*83ee113eSDavid van Moolenbroek 		if (terminated && foo != '=') {
1920*83ee113eSDavid van Moolenbroek 			parse_warn(cfile,
1921*83ee113eSDavid van Moolenbroek 				   "stuff after base64 '=' terminator: %s.",
1922*83ee113eSDavid van Moolenbroek 				   &t->string[i]);
1923*83ee113eSDavid van Moolenbroek 			goto bad;
1924*83ee113eSDavid van Moolenbroek 		}
1925*83ee113eSDavid van Moolenbroek 		if ((foo < ' ') || (foo > 'z')) {
1926*83ee113eSDavid van Moolenbroek 		      bad64:
1927*83ee113eSDavid van Moolenbroek 			parse_warn(cfile,
1928*83ee113eSDavid van Moolenbroek 				   "invalid base64 character %d.",
1929*83ee113eSDavid van Moolenbroek 				   t->string[i]);
1930*83ee113eSDavid van Moolenbroek 		      bad:
1931*83ee113eSDavid van Moolenbroek 			data_string_forget(data, MDL);
1932*83ee113eSDavid van Moolenbroek 			goto out;
1933*83ee113eSDavid van Moolenbroek 		}
1934*83ee113eSDavid van Moolenbroek 		if (foo == '=')
1935*83ee113eSDavid van Moolenbroek 			terminated = 1;
1936*83ee113eSDavid van Moolenbroek 		else {
1937*83ee113eSDavid van Moolenbroek 			foo = from64[foo - ' '];
1938*83ee113eSDavid van Moolenbroek 			if (foo == 64)
1939*83ee113eSDavid van Moolenbroek 				goto bad64;
1940*83ee113eSDavid van Moolenbroek 			acc = (acc << 6) + foo;
1941*83ee113eSDavid van Moolenbroek 			switch (k % 4) {
1942*83ee113eSDavid van Moolenbroek 			      case 0:
1943*83ee113eSDavid van Moolenbroek 				break;
1944*83ee113eSDavid van Moolenbroek 			      case 1:
1945*83ee113eSDavid van Moolenbroek 				data->buffer->data[j++] = (acc >> 4);
1946*83ee113eSDavid van Moolenbroek 				acc = acc & 0x0f;
1947*83ee113eSDavid van Moolenbroek 				break;
1948*83ee113eSDavid van Moolenbroek 
1949*83ee113eSDavid van Moolenbroek 			      case 2:
1950*83ee113eSDavid van Moolenbroek 				data->buffer->data[j++] = (acc >> 2);
1951*83ee113eSDavid van Moolenbroek 				acc = acc & 0x03;
1952*83ee113eSDavid van Moolenbroek 				break;
1953*83ee113eSDavid van Moolenbroek 			      case 3:
1954*83ee113eSDavid van Moolenbroek 				data->buffer->data[j++] = acc;
1955*83ee113eSDavid van Moolenbroek 				acc = 0;
1956*83ee113eSDavid van Moolenbroek 				break;
1957*83ee113eSDavid van Moolenbroek 			}
1958*83ee113eSDavid van Moolenbroek 		}
1959*83ee113eSDavid van Moolenbroek 		k++;
1960*83ee113eSDavid van Moolenbroek 	    }
1961*83ee113eSDavid van Moolenbroek 	}
1962*83ee113eSDavid van Moolenbroek 	if (k % 4) {
1963*83ee113eSDavid van Moolenbroek 		if (acc) {
1964*83ee113eSDavid van Moolenbroek 			parse_warn(cfile,
1965*83ee113eSDavid van Moolenbroek 				   "partial base64 value left over: %d.",
1966*83ee113eSDavid van Moolenbroek 				   acc);
1967*83ee113eSDavid van Moolenbroek 		}
1968*83ee113eSDavid van Moolenbroek 	}
1969*83ee113eSDavid van Moolenbroek 	data->len = j;
1970*83ee113eSDavid van Moolenbroek 	data->data = data->buffer->data;
1971*83ee113eSDavid van Moolenbroek       out:
1972*83ee113eSDavid van Moolenbroek 	for (t = bufs; t; t = last) {
1973*83ee113eSDavid van Moolenbroek 		last = t->next;
1974*83ee113eSDavid van Moolenbroek 		dfree(t, MDL);
1975*83ee113eSDavid van Moolenbroek 	}
1976*83ee113eSDavid van Moolenbroek 	if (data->len)
1977*83ee113eSDavid van Moolenbroek 		return 1;
1978*83ee113eSDavid van Moolenbroek 	else
1979*83ee113eSDavid van Moolenbroek 		return 0;
1980*83ee113eSDavid van Moolenbroek }
1981*83ee113eSDavid van Moolenbroek 
1982*83ee113eSDavid van Moolenbroek 
1983*83ee113eSDavid van Moolenbroek /*
1984*83ee113eSDavid van Moolenbroek  * colon-separated-hex-list :== NUMBER |
1985*83ee113eSDavid van Moolenbroek  *				NUMBER COLON colon-separated-hex-list
1986*83ee113eSDavid van Moolenbroek  */
1987*83ee113eSDavid van Moolenbroek 
parse_cshl(data,cfile)1988*83ee113eSDavid van Moolenbroek int parse_cshl (data, cfile)
1989*83ee113eSDavid van Moolenbroek 	struct data_string *data;
1990*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
1991*83ee113eSDavid van Moolenbroek {
1992*83ee113eSDavid van Moolenbroek 	u_int8_t ibuf [128];
1993*83ee113eSDavid van Moolenbroek 	unsigned ilen = 0;
1994*83ee113eSDavid van Moolenbroek 	unsigned tlen = 0;
1995*83ee113eSDavid van Moolenbroek 	struct option_tag *sl = (struct option_tag *)0;
1996*83ee113eSDavid van Moolenbroek 	struct option_tag *next, **last = &sl;
1997*83ee113eSDavid van Moolenbroek 	enum dhcp_token token;
1998*83ee113eSDavid van Moolenbroek 	const char *val;
1999*83ee113eSDavid van Moolenbroek 	unsigned char *rvp;
2000*83ee113eSDavid van Moolenbroek 
2001*83ee113eSDavid van Moolenbroek 	do {
2002*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
2003*83ee113eSDavid van Moolenbroek 		if (token != NUMBER && token != NUMBER_OR_NAME) {
2004*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "expecting hexadecimal number.");
2005*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
2006*83ee113eSDavid van Moolenbroek 			for (; sl; sl = next) {
2007*83ee113eSDavid van Moolenbroek 				next = sl -> next;
2008*83ee113eSDavid van Moolenbroek 				dfree (sl, MDL);
2009*83ee113eSDavid van Moolenbroek 			}
2010*83ee113eSDavid van Moolenbroek 			return 0;
2011*83ee113eSDavid van Moolenbroek 		}
2012*83ee113eSDavid van Moolenbroek 		if (ilen == sizeof ibuf) {
2013*83ee113eSDavid van Moolenbroek 			next = (struct option_tag *)
2014*83ee113eSDavid van Moolenbroek 				dmalloc (ilen - 1 +
2015*83ee113eSDavid van Moolenbroek 					 sizeof (struct option_tag), MDL);
2016*83ee113eSDavid van Moolenbroek 			if (!next)
2017*83ee113eSDavid van Moolenbroek 				log_fatal ("no memory for string list.");
2018*83ee113eSDavid van Moolenbroek 			memcpy (next -> data, ibuf, ilen);
2019*83ee113eSDavid van Moolenbroek 			*last = next;
2020*83ee113eSDavid van Moolenbroek 			last = &next -> next;
2021*83ee113eSDavid van Moolenbroek 			tlen += ilen;
2022*83ee113eSDavid van Moolenbroek 			ilen = 0;
2023*83ee113eSDavid van Moolenbroek 		}
2024*83ee113eSDavid van Moolenbroek 		convert_num (cfile, &ibuf [ilen++], val, 16, 8);
2025*83ee113eSDavid van Moolenbroek 
2026*83ee113eSDavid van Moolenbroek 		token = peek_token (&val, (unsigned *)0, cfile);
2027*83ee113eSDavid van Moolenbroek 		if (token != COLON)
2028*83ee113eSDavid van Moolenbroek 			break;
2029*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
2030*83ee113eSDavid van Moolenbroek 	} while (1);
2031*83ee113eSDavid van Moolenbroek 
2032*83ee113eSDavid van Moolenbroek 	if (!buffer_allocate (&data -> buffer, tlen + ilen, MDL))
2033*83ee113eSDavid van Moolenbroek 		log_fatal ("no memory to store octet data.");
2034*83ee113eSDavid van Moolenbroek 	data -> data = &data -> buffer -> data [0];
2035*83ee113eSDavid van Moolenbroek 	data -> len = tlen + ilen;
2036*83ee113eSDavid van Moolenbroek 	data -> terminated = 0;
2037*83ee113eSDavid van Moolenbroek 
2038*83ee113eSDavid van Moolenbroek 	rvp = &data -> buffer -> data [0];
2039*83ee113eSDavid van Moolenbroek 	while (sl) {
2040*83ee113eSDavid van Moolenbroek 		next = sl -> next;
2041*83ee113eSDavid van Moolenbroek 		memcpy (rvp, sl -> data, sizeof ibuf);
2042*83ee113eSDavid van Moolenbroek 		rvp += sizeof ibuf;
2043*83ee113eSDavid van Moolenbroek 		dfree (sl, MDL);
2044*83ee113eSDavid van Moolenbroek 		sl = next;
2045*83ee113eSDavid van Moolenbroek 	}
2046*83ee113eSDavid van Moolenbroek 
2047*83ee113eSDavid van Moolenbroek 	memcpy (rvp, ibuf, ilen);
2048*83ee113eSDavid van Moolenbroek 	return 1;
2049*83ee113eSDavid van Moolenbroek }
2050*83ee113eSDavid van Moolenbroek 
2051*83ee113eSDavid van Moolenbroek /*
2052*83ee113eSDavid van Moolenbroek  * executable-statements :== executable-statement executable-statements |
2053*83ee113eSDavid van Moolenbroek  *			     executable-statement
2054*83ee113eSDavid van Moolenbroek  *
2055*83ee113eSDavid van Moolenbroek  * executable-statement :==
2056*83ee113eSDavid van Moolenbroek  *	IF if-statement |
2057*83ee113eSDavid van Moolenbroek  * 	ADD class-name SEMI |
2058*83ee113eSDavid van Moolenbroek  *	BREAK SEMI |
2059*83ee113eSDavid van Moolenbroek  *	OPTION option-parameter SEMI |
2060*83ee113eSDavid van Moolenbroek  *	SUPERSEDE option-parameter SEMI |
2061*83ee113eSDavid van Moolenbroek  *	PREPEND option-parameter SEMI |
2062*83ee113eSDavid van Moolenbroek  *	APPEND option-parameter SEMI
2063*83ee113eSDavid van Moolenbroek  */
2064*83ee113eSDavid van Moolenbroek 
parse_executable_statements(statements,cfile,lose,case_context)2065*83ee113eSDavid van Moolenbroek int parse_executable_statements (statements, cfile, lose, case_context)
2066*83ee113eSDavid van Moolenbroek 	struct executable_statement **statements;
2067*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
2068*83ee113eSDavid van Moolenbroek 	int *lose;
2069*83ee113eSDavid van Moolenbroek 	enum expression_context case_context;
2070*83ee113eSDavid van Moolenbroek {
2071*83ee113eSDavid van Moolenbroek 	struct executable_statement **next;
2072*83ee113eSDavid van Moolenbroek 
2073*83ee113eSDavid van Moolenbroek 	next = statements;
2074*83ee113eSDavid van Moolenbroek 	while (parse_executable_statement (next, cfile, lose, case_context))
2075*83ee113eSDavid van Moolenbroek 		next = &((*next) -> next);
2076*83ee113eSDavid van Moolenbroek 	if (!*lose)
2077*83ee113eSDavid van Moolenbroek 		return 1;
2078*83ee113eSDavid van Moolenbroek 	return 0;
2079*83ee113eSDavid van Moolenbroek }
2080*83ee113eSDavid van Moolenbroek 
parse_executable_statement(result,cfile,lose,case_context)2081*83ee113eSDavid van Moolenbroek int parse_executable_statement (result, cfile, lose, case_context)
2082*83ee113eSDavid van Moolenbroek 	struct executable_statement **result;
2083*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
2084*83ee113eSDavid van Moolenbroek 	int *lose;
2085*83ee113eSDavid van Moolenbroek 	enum expression_context case_context;
2086*83ee113eSDavid van Moolenbroek {
2087*83ee113eSDavid van Moolenbroek #if defined(ENABLE_EXECUTE)
2088*83ee113eSDavid van Moolenbroek 	unsigned len;
2089*83ee113eSDavid van Moolenbroek 	struct expression **ep;
2090*83ee113eSDavid van Moolenbroek #endif
2091*83ee113eSDavid van Moolenbroek 	enum dhcp_token token;
2092*83ee113eSDavid van Moolenbroek 	const char *val;
2093*83ee113eSDavid van Moolenbroek 	struct class *cta;
2094*83ee113eSDavid van Moolenbroek 	struct option *option=NULL;
2095*83ee113eSDavid van Moolenbroek 	struct option_cache *cache;
2096*83ee113eSDavid van Moolenbroek 	int known;
2097*83ee113eSDavid van Moolenbroek 	int flag;
2098*83ee113eSDavid van Moolenbroek 	int i;
2099*83ee113eSDavid van Moolenbroek 	struct dns_zone *zone;
2100*83ee113eSDavid van Moolenbroek 	isc_result_t status;
2101*83ee113eSDavid van Moolenbroek 	char *s;
2102*83ee113eSDavid van Moolenbroek 
2103*83ee113eSDavid van Moolenbroek 	token = peek_token (&val, (unsigned *)0, cfile);
2104*83ee113eSDavid van Moolenbroek 	switch (token) {
2105*83ee113eSDavid van Moolenbroek 	      case DB_TIME_FORMAT:
2106*83ee113eSDavid van Moolenbroek 		skip_token(&val, NULL, cfile);
2107*83ee113eSDavid van Moolenbroek 		token = next_token(&val, NULL, cfile);
2108*83ee113eSDavid van Moolenbroek 		if (token == DEFAULT) {
2109*83ee113eSDavid van Moolenbroek 			db_time_format = DEFAULT_TIME_FORMAT;
2110*83ee113eSDavid van Moolenbroek 		} else if (token == LOCAL) {
2111*83ee113eSDavid van Moolenbroek 			db_time_format = LOCAL_TIME_FORMAT;
2112*83ee113eSDavid van Moolenbroek 		} else {
2113*83ee113eSDavid van Moolenbroek 			parse_warn(cfile, "Expecting 'local' or 'default'.");
2114*83ee113eSDavid van Moolenbroek 			if (token != SEMI)
2115*83ee113eSDavid van Moolenbroek 				skip_to_semi(cfile);
2116*83ee113eSDavid van Moolenbroek 			*lose = 1;
2117*83ee113eSDavid van Moolenbroek 			return 0;
2118*83ee113eSDavid van Moolenbroek 		}
2119*83ee113eSDavid van Moolenbroek 
2120*83ee113eSDavid van Moolenbroek 		token = next_token(&val, NULL, cfile);
2121*83ee113eSDavid van Moolenbroek 		if (token != SEMI) {
2122*83ee113eSDavid van Moolenbroek 			parse_warn(cfile, "Expecting a semicolon.");
2123*83ee113eSDavid van Moolenbroek 			*lose = 1;
2124*83ee113eSDavid van Moolenbroek 			return 0;
2125*83ee113eSDavid van Moolenbroek 		}
2126*83ee113eSDavid van Moolenbroek 
2127*83ee113eSDavid van Moolenbroek 		/* We're done here. */
2128*83ee113eSDavid van Moolenbroek 		return 1;
2129*83ee113eSDavid van Moolenbroek 
2130*83ee113eSDavid van Moolenbroek 	      case IF:
2131*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
2132*83ee113eSDavid van Moolenbroek 		return parse_if_statement (result, cfile, lose);
2133*83ee113eSDavid van Moolenbroek 
2134*83ee113eSDavid van Moolenbroek 	      case TOKEN_ADD:
2135*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
2136*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
2137*83ee113eSDavid van Moolenbroek 		if (token != STRING) {
2138*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "expecting class name.");
2139*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
2140*83ee113eSDavid van Moolenbroek 			*lose = 1;
2141*83ee113eSDavid van Moolenbroek 			return 0;
2142*83ee113eSDavid van Moolenbroek 		}
2143*83ee113eSDavid van Moolenbroek 		cta = (struct class *)0;
2144*83ee113eSDavid van Moolenbroek 		status = find_class (&cta, val, MDL);
2145*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS) {
2146*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "class %s: %s",
2147*83ee113eSDavid van Moolenbroek 				    val, isc_result_totext (status));
2148*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
2149*83ee113eSDavid van Moolenbroek 			*lose = 1;
2150*83ee113eSDavid van Moolenbroek 			return 0;
2151*83ee113eSDavid van Moolenbroek 		}
2152*83ee113eSDavid van Moolenbroek 		if (!parse_semi (cfile)) {
2153*83ee113eSDavid van Moolenbroek 			*lose = 1;
2154*83ee113eSDavid van Moolenbroek 			return 0;
2155*83ee113eSDavid van Moolenbroek 		}
2156*83ee113eSDavid van Moolenbroek 		if (!executable_statement_allocate (result, MDL))
2157*83ee113eSDavid van Moolenbroek 			log_fatal ("no memory for new statement.");
2158*83ee113eSDavid van Moolenbroek 		(*result) -> op = add_statement;
2159*83ee113eSDavid van Moolenbroek 		(*result) -> data.add = cta;
2160*83ee113eSDavid van Moolenbroek 		break;
2161*83ee113eSDavid van Moolenbroek 
2162*83ee113eSDavid van Moolenbroek 	      case BREAK:
2163*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
2164*83ee113eSDavid van Moolenbroek 		if (!parse_semi (cfile)) {
2165*83ee113eSDavid van Moolenbroek 			*lose = 1;
2166*83ee113eSDavid van Moolenbroek 			return 0;
2167*83ee113eSDavid van Moolenbroek 		}
2168*83ee113eSDavid van Moolenbroek 		if (!executable_statement_allocate (result, MDL))
2169*83ee113eSDavid van Moolenbroek 			log_fatal ("no memory for new statement.");
2170*83ee113eSDavid van Moolenbroek 		(*result) -> op = break_statement;
2171*83ee113eSDavid van Moolenbroek 		break;
2172*83ee113eSDavid van Moolenbroek 
2173*83ee113eSDavid van Moolenbroek 	      case SEND:
2174*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
2175*83ee113eSDavid van Moolenbroek 		known = 0;
2176*83ee113eSDavid van Moolenbroek 		status = parse_option_name (cfile, 0, &known, &option);
2177*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS || option == NULL) {
2178*83ee113eSDavid van Moolenbroek 			*lose = 1;
2179*83ee113eSDavid van Moolenbroek 			return 0;
2180*83ee113eSDavid van Moolenbroek 		}
2181*83ee113eSDavid van Moolenbroek 		status = parse_option_statement(result, cfile, 1, option,
2182*83ee113eSDavid van Moolenbroek 						send_option_statement);
2183*83ee113eSDavid van Moolenbroek 		option_dereference(&option, MDL);
2184*83ee113eSDavid van Moolenbroek 		return status;
2185*83ee113eSDavid van Moolenbroek 
2186*83ee113eSDavid van Moolenbroek 	      case SUPERSEDE:
2187*83ee113eSDavid van Moolenbroek 	      case OPTION:
2188*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
2189*83ee113eSDavid van Moolenbroek 		known = 0;
2190*83ee113eSDavid van Moolenbroek 		status = parse_option_name (cfile, 0, &known, &option);
2191*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS || option == NULL) {
2192*83ee113eSDavid van Moolenbroek 			*lose = 1;
2193*83ee113eSDavid van Moolenbroek 			return 0;
2194*83ee113eSDavid van Moolenbroek 		}
2195*83ee113eSDavid van Moolenbroek 		status = parse_option_statement(result, cfile, 1, option,
2196*83ee113eSDavid van Moolenbroek 						supersede_option_statement);
2197*83ee113eSDavid van Moolenbroek 		option_dereference(&option, MDL);
2198*83ee113eSDavid van Moolenbroek 		return status;
2199*83ee113eSDavid van Moolenbroek 
2200*83ee113eSDavid van Moolenbroek 	      case ALLOW:
2201*83ee113eSDavid van Moolenbroek 		flag = 1;
2202*83ee113eSDavid van Moolenbroek 		goto pad;
2203*83ee113eSDavid van Moolenbroek 	      case DENY:
2204*83ee113eSDavid van Moolenbroek 		flag = 0;
2205*83ee113eSDavid van Moolenbroek 		goto pad;
2206*83ee113eSDavid van Moolenbroek 	      case IGNORE:
2207*83ee113eSDavid van Moolenbroek 		flag = 2;
2208*83ee113eSDavid van Moolenbroek 	      pad:
2209*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
2210*83ee113eSDavid van Moolenbroek 		cache = (struct option_cache *)0;
2211*83ee113eSDavid van Moolenbroek 		if (!parse_allow_deny (&cache, cfile, flag))
2212*83ee113eSDavid van Moolenbroek 			return 0;
2213*83ee113eSDavid van Moolenbroek 		if (!executable_statement_allocate (result, MDL))
2214*83ee113eSDavid van Moolenbroek 			log_fatal ("no memory for new statement.");
2215*83ee113eSDavid van Moolenbroek 		(*result) -> op = supersede_option_statement;
2216*83ee113eSDavid van Moolenbroek 		(*result) -> data.option = cache;
2217*83ee113eSDavid van Moolenbroek 		break;
2218*83ee113eSDavid van Moolenbroek 
2219*83ee113eSDavid van Moolenbroek 	      case DEFAULT:
2220*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
2221*83ee113eSDavid van Moolenbroek 		token = peek_token (&val, (unsigned *)0, cfile);
2222*83ee113eSDavid van Moolenbroek 		if (token == COLON)
2223*83ee113eSDavid van Moolenbroek 			goto switch_default;
2224*83ee113eSDavid van Moolenbroek 		known = 0;
2225*83ee113eSDavid van Moolenbroek 		status = parse_option_name (cfile, 0, &known, &option);
2226*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS || option == NULL) {
2227*83ee113eSDavid van Moolenbroek 			*lose = 1;
2228*83ee113eSDavid van Moolenbroek 			return 0;
2229*83ee113eSDavid van Moolenbroek 		}
2230*83ee113eSDavid van Moolenbroek 		status = parse_option_statement(result, cfile, 1, option,
2231*83ee113eSDavid van Moolenbroek 						default_option_statement);
2232*83ee113eSDavid van Moolenbroek 		option_dereference(&option, MDL);
2233*83ee113eSDavid van Moolenbroek 		return status;
2234*83ee113eSDavid van Moolenbroek 
2235*83ee113eSDavid van Moolenbroek 	      case PREPEND:
2236*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
2237*83ee113eSDavid van Moolenbroek 		known = 0;
2238*83ee113eSDavid van Moolenbroek 		status = parse_option_name (cfile, 0, &known, &option);
2239*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS || option == NULL) {
2240*83ee113eSDavid van Moolenbroek 			*lose = 1;
2241*83ee113eSDavid van Moolenbroek 			return 0;
2242*83ee113eSDavid van Moolenbroek 		}
2243*83ee113eSDavid van Moolenbroek 		status = parse_option_statement(result, cfile, 1, option,
2244*83ee113eSDavid van Moolenbroek 						prepend_option_statement);
2245*83ee113eSDavid van Moolenbroek 		option_dereference(&option, MDL);
2246*83ee113eSDavid van Moolenbroek 		return status;
2247*83ee113eSDavid van Moolenbroek 
2248*83ee113eSDavid van Moolenbroek 	      case APPEND:
2249*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
2250*83ee113eSDavid van Moolenbroek 		known = 0;
2251*83ee113eSDavid van Moolenbroek 		status = parse_option_name (cfile, 0, &known, &option);
2252*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS || option == NULL) {
2253*83ee113eSDavid van Moolenbroek 			*lose = 1;
2254*83ee113eSDavid van Moolenbroek 			return 0;
2255*83ee113eSDavid van Moolenbroek 		}
2256*83ee113eSDavid van Moolenbroek 		status = parse_option_statement(result, cfile, 1, option,
2257*83ee113eSDavid van Moolenbroek 						append_option_statement);
2258*83ee113eSDavid van Moolenbroek 		option_dereference(&option, MDL);
2259*83ee113eSDavid van Moolenbroek 		return status;
2260*83ee113eSDavid van Moolenbroek 
2261*83ee113eSDavid van Moolenbroek 	      case ON:
2262*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
2263*83ee113eSDavid van Moolenbroek 		return parse_on_statement (result, cfile, lose);
2264*83ee113eSDavid van Moolenbroek 
2265*83ee113eSDavid van Moolenbroek 	      case SWITCH:
2266*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
2267*83ee113eSDavid van Moolenbroek 		return parse_switch_statement (result, cfile, lose);
2268*83ee113eSDavid van Moolenbroek 
2269*83ee113eSDavid van Moolenbroek 	      case CASE:
2270*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
2271*83ee113eSDavid van Moolenbroek 		if (case_context == context_any) {
2272*83ee113eSDavid van Moolenbroek 			parse_warn (cfile,
2273*83ee113eSDavid van Moolenbroek 				    "case statement in inappropriate scope.");
2274*83ee113eSDavid van Moolenbroek 			*lose = 1;
2275*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
2276*83ee113eSDavid van Moolenbroek 			return 0;
2277*83ee113eSDavid van Moolenbroek 		}
2278*83ee113eSDavid van Moolenbroek 		return parse_case_statement (result,
2279*83ee113eSDavid van Moolenbroek 					     cfile, lose, case_context);
2280*83ee113eSDavid van Moolenbroek 
2281*83ee113eSDavid van Moolenbroek 	      switch_default:
2282*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
2283*83ee113eSDavid van Moolenbroek 		if (case_context == context_any) {
2284*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "switch default statement in %s",
2285*83ee113eSDavid van Moolenbroek 				    "inappropriate scope.");
2286*83ee113eSDavid van Moolenbroek 
2287*83ee113eSDavid van Moolenbroek 			*lose = 1;
2288*83ee113eSDavid van Moolenbroek 			return 0;
2289*83ee113eSDavid van Moolenbroek 		} else {
2290*83ee113eSDavid van Moolenbroek 			if (!executable_statement_allocate (result, MDL))
2291*83ee113eSDavid van Moolenbroek 				log_fatal ("no memory for default statement.");
2292*83ee113eSDavid van Moolenbroek 			(*result) -> op = default_statement;
2293*83ee113eSDavid van Moolenbroek 			return 1;
2294*83ee113eSDavid van Moolenbroek 		}
2295*83ee113eSDavid van Moolenbroek 
2296*83ee113eSDavid van Moolenbroek 	      case DEFINE:
2297*83ee113eSDavid van Moolenbroek 	      case TOKEN_SET:
2298*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
2299*83ee113eSDavid van Moolenbroek 		if (token == DEFINE)
2300*83ee113eSDavid van Moolenbroek 			flag = 1;
2301*83ee113eSDavid van Moolenbroek 		else
2302*83ee113eSDavid van Moolenbroek 			flag = 0;
2303*83ee113eSDavid van Moolenbroek 
2304*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
2305*83ee113eSDavid van Moolenbroek 		if (token != NAME && token != NUMBER_OR_NAME) {
2306*83ee113eSDavid van Moolenbroek 			parse_warn (cfile,
2307*83ee113eSDavid van Moolenbroek 				    "%s can't be a variable name", val);
2308*83ee113eSDavid van Moolenbroek 		      badset:
2309*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
2310*83ee113eSDavid van Moolenbroek 			*lose = 1;
2311*83ee113eSDavid van Moolenbroek 			return 0;
2312*83ee113eSDavid van Moolenbroek 		}
2313*83ee113eSDavid van Moolenbroek 
2314*83ee113eSDavid van Moolenbroek 		if (!executable_statement_allocate (result, MDL))
2315*83ee113eSDavid van Moolenbroek 			log_fatal ("no memory for set statement.");
2316*83ee113eSDavid van Moolenbroek 		(*result) -> op = flag ? define_statement : set_statement;
2317*83ee113eSDavid van Moolenbroek 		(*result) -> data.set.name = dmalloc (strlen (val) + 1, MDL);
2318*83ee113eSDavid van Moolenbroek 		if (!(*result)->data.set.name)
2319*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate variable name");
2320*83ee113eSDavid van Moolenbroek 		strcpy ((*result) -> data.set.name, val);
2321*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
2322*83ee113eSDavid van Moolenbroek 
2323*83ee113eSDavid van Moolenbroek 		if (token == LPAREN) {
2324*83ee113eSDavid van Moolenbroek 			struct string_list *head, *cur, *new;
2325*83ee113eSDavid van Moolenbroek 			struct expression *expr;
2326*83ee113eSDavid van Moolenbroek 			head = cur = (struct string_list *)0;
2327*83ee113eSDavid van Moolenbroek 			do {
2328*83ee113eSDavid van Moolenbroek 				token = next_token (&val,
2329*83ee113eSDavid van Moolenbroek 						    (unsigned *)0, cfile);
2330*83ee113eSDavid van Moolenbroek 				if (token == RPAREN)
2331*83ee113eSDavid van Moolenbroek 					break;
2332*83ee113eSDavid van Moolenbroek 				if (token != NAME && token != NUMBER_OR_NAME) {
2333*83ee113eSDavid van Moolenbroek 					parse_warn (cfile,
2334*83ee113eSDavid van Moolenbroek 						    "expecting argument name");
2335*83ee113eSDavid van Moolenbroek 					skip_to_rbrace (cfile, 0);
2336*83ee113eSDavid van Moolenbroek 					*lose = 1;
2337*83ee113eSDavid van Moolenbroek 					executable_statement_dereference
2338*83ee113eSDavid van Moolenbroek 						(result, MDL);
2339*83ee113eSDavid van Moolenbroek 					return 0;
2340*83ee113eSDavid van Moolenbroek 				}
2341*83ee113eSDavid van Moolenbroek 				new = ((struct string_list *)
2342*83ee113eSDavid van Moolenbroek 				       dmalloc (sizeof (struct string_list) +
2343*83ee113eSDavid van Moolenbroek 						strlen (val), MDL));
2344*83ee113eSDavid van Moolenbroek 				if (!new)
2345*83ee113eSDavid van Moolenbroek 					log_fatal ("can't allocate string.");
2346*83ee113eSDavid van Moolenbroek 				memset (new, 0, sizeof *new);
2347*83ee113eSDavid van Moolenbroek 				strcpy (new -> string, val);
2348*83ee113eSDavid van Moolenbroek 				if (cur) {
2349*83ee113eSDavid van Moolenbroek 					cur -> next = new;
2350*83ee113eSDavid van Moolenbroek 					cur = new;
2351*83ee113eSDavid van Moolenbroek 				} else {
2352*83ee113eSDavid van Moolenbroek 					head = cur = new;
2353*83ee113eSDavid van Moolenbroek 				}
2354*83ee113eSDavid van Moolenbroek 				token = next_token (&val,
2355*83ee113eSDavid van Moolenbroek 						    (unsigned *)0, cfile);
2356*83ee113eSDavid van Moolenbroek 			} while (token == COMMA);
2357*83ee113eSDavid van Moolenbroek 
2358*83ee113eSDavid van Moolenbroek 			if (token != RPAREN) {
2359*83ee113eSDavid van Moolenbroek 				parse_warn (cfile, "expecting right paren.");
2360*83ee113eSDavid van Moolenbroek 			      badx:
2361*83ee113eSDavid van Moolenbroek 				skip_to_semi (cfile);
2362*83ee113eSDavid van Moolenbroek 				*lose = 1;
2363*83ee113eSDavid van Moolenbroek 				executable_statement_dereference (result, MDL);
2364*83ee113eSDavid van Moolenbroek 				return 0;
2365*83ee113eSDavid van Moolenbroek 			}
2366*83ee113eSDavid van Moolenbroek 
2367*83ee113eSDavid van Moolenbroek 			token = next_token (&val, (unsigned *)0, cfile);
2368*83ee113eSDavid van Moolenbroek 			if (token != LBRACE) {
2369*83ee113eSDavid van Moolenbroek 				parse_warn (cfile, "expecting left brace.");
2370*83ee113eSDavid van Moolenbroek 				goto badx;
2371*83ee113eSDavid van Moolenbroek 			}
2372*83ee113eSDavid van Moolenbroek 
2373*83ee113eSDavid van Moolenbroek 			expr = (struct expression *)0;
2374*83ee113eSDavid van Moolenbroek 			if (!(expression_allocate (&expr, MDL)))
2375*83ee113eSDavid van Moolenbroek 				log_fatal ("can't allocate expression.");
2376*83ee113eSDavid van Moolenbroek 			expr -> op = expr_function;
2377*83ee113eSDavid van Moolenbroek 			if (!fundef_allocate (&expr -> data.func, MDL))
2378*83ee113eSDavid van Moolenbroek 				log_fatal ("can't allocate fundef.");
2379*83ee113eSDavid van Moolenbroek 			expr -> data.func -> args = head;
2380*83ee113eSDavid van Moolenbroek 			(*result) -> data.set.expr = expr;
2381*83ee113eSDavid van Moolenbroek 
2382*83ee113eSDavid van Moolenbroek 			if (!(parse_executable_statements
2383*83ee113eSDavid van Moolenbroek 			      (&expr -> data.func -> statements, cfile, lose,
2384*83ee113eSDavid van Moolenbroek 			       case_context))) {
2385*83ee113eSDavid van Moolenbroek 				if (*lose)
2386*83ee113eSDavid van Moolenbroek 					goto badx;
2387*83ee113eSDavid van Moolenbroek 			}
2388*83ee113eSDavid van Moolenbroek 
2389*83ee113eSDavid van Moolenbroek 			token = next_token (&val, (unsigned *)0, cfile);
2390*83ee113eSDavid van Moolenbroek 			if (token != RBRACE) {
2391*83ee113eSDavid van Moolenbroek 				parse_warn (cfile, "expecting rigt brace.");
2392*83ee113eSDavid van Moolenbroek 				goto badx;
2393*83ee113eSDavid van Moolenbroek 			}
2394*83ee113eSDavid van Moolenbroek 		} else {
2395*83ee113eSDavid van Moolenbroek 			if (token != EQUAL) {
2396*83ee113eSDavid van Moolenbroek 				parse_warn (cfile,
2397*83ee113eSDavid van Moolenbroek 					    "expecting '=' in %s statement.",
2398*83ee113eSDavid van Moolenbroek 					    flag ? "define" : "set");
2399*83ee113eSDavid van Moolenbroek 				goto badset;
2400*83ee113eSDavid van Moolenbroek 			}
2401*83ee113eSDavid van Moolenbroek 
2402*83ee113eSDavid van Moolenbroek 			if (!parse_expression (&(*result) -> data.set.expr,
2403*83ee113eSDavid van Moolenbroek 					       cfile, lose, context_any,
2404*83ee113eSDavid van Moolenbroek 					       (struct expression **)0,
2405*83ee113eSDavid van Moolenbroek 					       expr_none)) {
2406*83ee113eSDavid van Moolenbroek 				if (!*lose)
2407*83ee113eSDavid van Moolenbroek 					parse_warn (cfile,
2408*83ee113eSDavid van Moolenbroek 						    "expecting expression.");
2409*83ee113eSDavid van Moolenbroek 				else
2410*83ee113eSDavid van Moolenbroek 					*lose = 1;
2411*83ee113eSDavid van Moolenbroek 				skip_to_semi (cfile);
2412*83ee113eSDavid van Moolenbroek 				executable_statement_dereference (result, MDL);
2413*83ee113eSDavid van Moolenbroek 				return 0;
2414*83ee113eSDavid van Moolenbroek 			}
2415*83ee113eSDavid van Moolenbroek 			if (!parse_semi (cfile)) {
2416*83ee113eSDavid van Moolenbroek 				*lose = 1;
2417*83ee113eSDavid van Moolenbroek 				executable_statement_dereference (result, MDL);
2418*83ee113eSDavid van Moolenbroek 				return 0;
2419*83ee113eSDavid van Moolenbroek 			}
2420*83ee113eSDavid van Moolenbroek 		}
2421*83ee113eSDavid van Moolenbroek 		break;
2422*83ee113eSDavid van Moolenbroek 
2423*83ee113eSDavid van Moolenbroek 	      case UNSET:
2424*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
2425*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
2426*83ee113eSDavid van Moolenbroek 		if (token != NAME && token != NUMBER_OR_NAME) {
2427*83ee113eSDavid van Moolenbroek 			parse_warn (cfile,
2428*83ee113eSDavid van Moolenbroek 				    "%s can't be a variable name", val);
2429*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
2430*83ee113eSDavid van Moolenbroek 			*lose = 1;
2431*83ee113eSDavid van Moolenbroek 			return 0;
2432*83ee113eSDavid van Moolenbroek 		}
2433*83ee113eSDavid van Moolenbroek 
2434*83ee113eSDavid van Moolenbroek 		if (!executable_statement_allocate (result, MDL))
2435*83ee113eSDavid van Moolenbroek 			log_fatal ("no memory for set statement.");
2436*83ee113eSDavid van Moolenbroek 		(*result) -> op = unset_statement;
2437*83ee113eSDavid van Moolenbroek 		(*result) -> data.unset = dmalloc (strlen (val) + 1, MDL);
2438*83ee113eSDavid van Moolenbroek 		if (!(*result)->data.unset)
2439*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate variable name");
2440*83ee113eSDavid van Moolenbroek 		strcpy ((*result) -> data.unset, val);
2441*83ee113eSDavid van Moolenbroek 		if (!parse_semi (cfile)) {
2442*83ee113eSDavid van Moolenbroek 			*lose = 1;
2443*83ee113eSDavid van Moolenbroek 			executable_statement_dereference (result, MDL);
2444*83ee113eSDavid van Moolenbroek 			return 0;
2445*83ee113eSDavid van Moolenbroek 		}
2446*83ee113eSDavid van Moolenbroek 		break;
2447*83ee113eSDavid van Moolenbroek 
2448*83ee113eSDavid van Moolenbroek 	      case EVAL:
2449*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
2450*83ee113eSDavid van Moolenbroek 		if (!executable_statement_allocate (result, MDL))
2451*83ee113eSDavid van Moolenbroek 			log_fatal ("no memory for eval statement.");
2452*83ee113eSDavid van Moolenbroek 		(*result) -> op = eval_statement;
2453*83ee113eSDavid van Moolenbroek 
2454*83ee113eSDavid van Moolenbroek 		if (!parse_expression (&(*result) -> data.eval,
2455*83ee113eSDavid van Moolenbroek 				       cfile, lose, context_data, /* XXX */
2456*83ee113eSDavid van Moolenbroek 				       (struct expression **)0, expr_none)) {
2457*83ee113eSDavid van Moolenbroek 			if (!*lose)
2458*83ee113eSDavid van Moolenbroek 				parse_warn (cfile,
2459*83ee113eSDavid van Moolenbroek 					    "expecting data expression.");
2460*83ee113eSDavid van Moolenbroek 			else
2461*83ee113eSDavid van Moolenbroek 				*lose = 1;
2462*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
2463*83ee113eSDavid van Moolenbroek 			executable_statement_dereference (result, MDL);
2464*83ee113eSDavid van Moolenbroek 			return 0;
2465*83ee113eSDavid van Moolenbroek 		}
2466*83ee113eSDavid van Moolenbroek 		if (!parse_semi (cfile)) {
2467*83ee113eSDavid van Moolenbroek 			*lose = 1;
2468*83ee113eSDavid van Moolenbroek 			executable_statement_dereference (result, MDL);
2469*83ee113eSDavid van Moolenbroek 		}
2470*83ee113eSDavid van Moolenbroek 		break;
2471*83ee113eSDavid van Moolenbroek 
2472*83ee113eSDavid van Moolenbroek 	      case EXECUTE:
2473*83ee113eSDavid van Moolenbroek #ifdef ENABLE_EXECUTE
2474*83ee113eSDavid van Moolenbroek 		skip_token(&val, NULL, cfile);
2475*83ee113eSDavid van Moolenbroek 
2476*83ee113eSDavid van Moolenbroek 		if (!executable_statement_allocate (result, MDL))
2477*83ee113eSDavid van Moolenbroek 			log_fatal ("no memory for execute statement.");
2478*83ee113eSDavid van Moolenbroek 		(*result)->op = execute_statement;
2479*83ee113eSDavid van Moolenbroek 
2480*83ee113eSDavid van Moolenbroek 		token = next_token(&val, NULL, cfile);
2481*83ee113eSDavid van Moolenbroek 		if (token != LPAREN) {
2482*83ee113eSDavid van Moolenbroek 			parse_warn(cfile, "left parenthesis expected.");
2483*83ee113eSDavid van Moolenbroek 			skip_to_semi(cfile);
2484*83ee113eSDavid van Moolenbroek 			*lose = 1;
2485*83ee113eSDavid van Moolenbroek 			return 0;
2486*83ee113eSDavid van Moolenbroek 		}
2487*83ee113eSDavid van Moolenbroek 
2488*83ee113eSDavid van Moolenbroek 		token = next_token(&val, &len, cfile);
2489*83ee113eSDavid van Moolenbroek 		if (token != STRING) {
2490*83ee113eSDavid van Moolenbroek 			parse_warn(cfile, "Expecting a quoted string.");
2491*83ee113eSDavid van Moolenbroek 			skip_to_semi(cfile);
2492*83ee113eSDavid van Moolenbroek 			*lose = 1;
2493*83ee113eSDavid van Moolenbroek 			return 0;
2494*83ee113eSDavid van Moolenbroek 		}
2495*83ee113eSDavid van Moolenbroek 
2496*83ee113eSDavid van Moolenbroek 		(*result)->data.execute.command = dmalloc(len + 1, MDL);
2497*83ee113eSDavid van Moolenbroek 		if ((*result)->data.execute.command == NULL)
2498*83ee113eSDavid van Moolenbroek 			log_fatal("can't allocate command name");
2499*83ee113eSDavid van Moolenbroek 		strcpy((*result)->data.execute.command, val);
2500*83ee113eSDavid van Moolenbroek 
2501*83ee113eSDavid van Moolenbroek 		ep = &(*result)->data.execute.arglist;
2502*83ee113eSDavid van Moolenbroek 		(*result)->data.execute.argc = 0;
2503*83ee113eSDavid van Moolenbroek 
2504*83ee113eSDavid van Moolenbroek 		while((token = next_token(&val, NULL, cfile)) == COMMA) {
2505*83ee113eSDavid van Moolenbroek 			if (!expression_allocate(ep, MDL))
2506*83ee113eSDavid van Moolenbroek 				log_fatal ("can't allocate expression");
2507*83ee113eSDavid van Moolenbroek 
2508*83ee113eSDavid van Moolenbroek  			if (!parse_data_expression (&(*ep) -> data.arg.val,
2509*83ee113eSDavid van Moolenbroek  					       cfile, lose)) {
2510*83ee113eSDavid van Moolenbroek 				if (!*lose) {
2511*83ee113eSDavid van Moolenbroek 					parse_warn (cfile,
2512*83ee113eSDavid van Moolenbroek 						    "expecting expression.");
2513*83ee113eSDavid van Moolenbroek 					*lose = 1;
2514*83ee113eSDavid van Moolenbroek 				}
2515*83ee113eSDavid van Moolenbroek 				skip_to_semi(cfile);
2516*83ee113eSDavid van Moolenbroek 				*lose = 1;
2517*83ee113eSDavid van Moolenbroek 				return 0;
2518*83ee113eSDavid van Moolenbroek 			}
2519*83ee113eSDavid van Moolenbroek 			ep = &(*ep)->data.arg.next;
2520*83ee113eSDavid van Moolenbroek 			(*result)->data.execute.argc++;
2521*83ee113eSDavid van Moolenbroek 		}
2522*83ee113eSDavid van Moolenbroek 
2523*83ee113eSDavid van Moolenbroek 		if (token != RPAREN) {
2524*83ee113eSDavid van Moolenbroek 			parse_warn(cfile, "right parenthesis expected.");
2525*83ee113eSDavid van Moolenbroek 			skip_to_semi(cfile);
2526*83ee113eSDavid van Moolenbroek 			*lose = 1;
2527*83ee113eSDavid van Moolenbroek 			return 0;
2528*83ee113eSDavid van Moolenbroek 		}
2529*83ee113eSDavid van Moolenbroek 
2530*83ee113eSDavid van Moolenbroek 		if (!parse_semi (cfile)) {
2531*83ee113eSDavid van Moolenbroek 			*lose = 1;
2532*83ee113eSDavid van Moolenbroek 			executable_statement_dereference (result, MDL);
2533*83ee113eSDavid van Moolenbroek 		}
2534*83ee113eSDavid van Moolenbroek #else /* ! ENABLE_EXECUTE */
2535*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "define ENABLE_EXECUTE in site.h to "
2536*83ee113eSDavid van Moolenbroek 				  "enable execute(); expressions.");
2537*83ee113eSDavid van Moolenbroek 		skip_to_semi(cfile);
2538*83ee113eSDavid van Moolenbroek 		*lose = 1;
2539*83ee113eSDavid van Moolenbroek 		return 0;
2540*83ee113eSDavid van Moolenbroek #endif /* ENABLE_EXECUTE */
2541*83ee113eSDavid van Moolenbroek 		break;
2542*83ee113eSDavid van Moolenbroek 
2543*83ee113eSDavid van Moolenbroek 	      case RETURN:
2544*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
2545*83ee113eSDavid van Moolenbroek 
2546*83ee113eSDavid van Moolenbroek 		if (!executable_statement_allocate (result, MDL))
2547*83ee113eSDavid van Moolenbroek 			log_fatal ("no memory for return statement.");
2548*83ee113eSDavid van Moolenbroek 		(*result) -> op = return_statement;
2549*83ee113eSDavid van Moolenbroek 
2550*83ee113eSDavid van Moolenbroek 		if (!parse_expression (&(*result) -> data.retval,
2551*83ee113eSDavid van Moolenbroek 				       cfile, lose, context_data,
2552*83ee113eSDavid van Moolenbroek 				       (struct expression **)0, expr_none)) {
2553*83ee113eSDavid van Moolenbroek 			if (!*lose)
2554*83ee113eSDavid van Moolenbroek 				parse_warn (cfile,
2555*83ee113eSDavid van Moolenbroek 					    "expecting data expression.");
2556*83ee113eSDavid van Moolenbroek 			else
2557*83ee113eSDavid van Moolenbroek 				*lose = 1;
2558*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
2559*83ee113eSDavid van Moolenbroek 			executable_statement_dereference (result, MDL);
2560*83ee113eSDavid van Moolenbroek 			return 0;
2561*83ee113eSDavid van Moolenbroek 		}
2562*83ee113eSDavid van Moolenbroek 		if (!parse_semi (cfile)) {
2563*83ee113eSDavid van Moolenbroek 			*lose = 1;
2564*83ee113eSDavid van Moolenbroek 			executable_statement_dereference (result, MDL);
2565*83ee113eSDavid van Moolenbroek 			return 0;
2566*83ee113eSDavid van Moolenbroek 		}
2567*83ee113eSDavid van Moolenbroek 		break;
2568*83ee113eSDavid van Moolenbroek 
2569*83ee113eSDavid van Moolenbroek 	      case LOG:
2570*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
2571*83ee113eSDavid van Moolenbroek 
2572*83ee113eSDavid van Moolenbroek 		if (!executable_statement_allocate (result, MDL))
2573*83ee113eSDavid van Moolenbroek 			log_fatal ("no memory for log statement.");
2574*83ee113eSDavid van Moolenbroek 		(*result) -> op = log_statement;
2575*83ee113eSDavid van Moolenbroek 
2576*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
2577*83ee113eSDavid van Moolenbroek 		if (token != LPAREN) {
2578*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "left parenthesis expected.");
2579*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
2580*83ee113eSDavid van Moolenbroek 			*lose = 1;
2581*83ee113eSDavid van Moolenbroek 			return 0;
2582*83ee113eSDavid van Moolenbroek 		}
2583*83ee113eSDavid van Moolenbroek 
2584*83ee113eSDavid van Moolenbroek 		token = peek_token (&val, (unsigned *)0, cfile);
2585*83ee113eSDavid van Moolenbroek 		i = 1;
2586*83ee113eSDavid van Moolenbroek 		if (token == FATAL) {
2587*83ee113eSDavid van Moolenbroek 			(*result) -> data.log.priority = log_priority_fatal;
2588*83ee113eSDavid van Moolenbroek 		} else if (token == ERROR) {
2589*83ee113eSDavid van Moolenbroek 			(*result) -> data.log.priority = log_priority_error;
2590*83ee113eSDavid van Moolenbroek 		} else if (token == TOKEN_DEBUG) {
2591*83ee113eSDavid van Moolenbroek 			(*result) -> data.log.priority = log_priority_debug;
2592*83ee113eSDavid van Moolenbroek 		} else if (token == INFO) {
2593*83ee113eSDavid van Moolenbroek 			(*result) -> data.log.priority = log_priority_info;
2594*83ee113eSDavid van Moolenbroek 		} else {
2595*83ee113eSDavid van Moolenbroek 			(*result) -> data.log.priority = log_priority_debug;
2596*83ee113eSDavid van Moolenbroek 			i = 0;
2597*83ee113eSDavid van Moolenbroek 		}
2598*83ee113eSDavid van Moolenbroek 		if (i) {
2599*83ee113eSDavid van Moolenbroek 			skip_token(&val, (unsigned *)0, cfile);
2600*83ee113eSDavid van Moolenbroek 			token = next_token (&val, (unsigned *)0, cfile);
2601*83ee113eSDavid van Moolenbroek 			if (token != COMMA) {
2602*83ee113eSDavid van Moolenbroek 				parse_warn (cfile, "comma expected.");
2603*83ee113eSDavid van Moolenbroek 				skip_to_semi (cfile);
2604*83ee113eSDavid van Moolenbroek 				*lose = 1;
2605*83ee113eSDavid van Moolenbroek 				return 0;
2606*83ee113eSDavid van Moolenbroek 			}
2607*83ee113eSDavid van Moolenbroek 		}
2608*83ee113eSDavid van Moolenbroek 
2609*83ee113eSDavid van Moolenbroek 		if (!(parse_data_expression
2610*83ee113eSDavid van Moolenbroek 		      (&(*result) -> data.log.expr, cfile, lose))) {
2611*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
2612*83ee113eSDavid van Moolenbroek 			*lose = 1;
2613*83ee113eSDavid van Moolenbroek 			return 0;
2614*83ee113eSDavid van Moolenbroek 		}
2615*83ee113eSDavid van Moolenbroek 
2616*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
2617*83ee113eSDavid van Moolenbroek 		if (token != RPAREN) {
2618*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "right parenthesis expected.");
2619*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
2620*83ee113eSDavid van Moolenbroek 			*lose = 1;
2621*83ee113eSDavid van Moolenbroek 			return 0;
2622*83ee113eSDavid van Moolenbroek 		}
2623*83ee113eSDavid van Moolenbroek 
2624*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
2625*83ee113eSDavid van Moolenbroek 		if (token != SEMI) {
2626*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "semicolon expected.");
2627*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
2628*83ee113eSDavid van Moolenbroek 			*lose = 1;
2629*83ee113eSDavid van Moolenbroek 			return 0;
2630*83ee113eSDavid van Moolenbroek 		}
2631*83ee113eSDavid van Moolenbroek 		break;
2632*83ee113eSDavid van Moolenbroek 
2633*83ee113eSDavid van Moolenbroek 		/* Not really a statement, but we parse it here anyway
2634*83ee113eSDavid van Moolenbroek 		   because it's appropriate for all DHCP agents with
2635*83ee113eSDavid van Moolenbroek 		   parsers. */
2636*83ee113eSDavid van Moolenbroek 	      case ZONE:
2637*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
2638*83ee113eSDavid van Moolenbroek 		zone = (struct dns_zone *)0;
2639*83ee113eSDavid van Moolenbroek 		if (!dns_zone_allocate (&zone, MDL))
2640*83ee113eSDavid van Moolenbroek 			log_fatal ("no memory for new zone.");
2641*83ee113eSDavid van Moolenbroek 		zone -> name = parse_host_name (cfile);
2642*83ee113eSDavid van Moolenbroek 		if (!zone -> name) {
2643*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "expecting hostname.");
2644*83ee113eSDavid van Moolenbroek 		      badzone:
2645*83ee113eSDavid van Moolenbroek 			*lose = 1;
2646*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
2647*83ee113eSDavid van Moolenbroek 			dns_zone_dereference (&zone, MDL);
2648*83ee113eSDavid van Moolenbroek 			return 0;
2649*83ee113eSDavid van Moolenbroek 		}
2650*83ee113eSDavid van Moolenbroek 		i = strlen (zone -> name);
2651*83ee113eSDavid van Moolenbroek 		if (zone -> name [i - 1] != '.') {
2652*83ee113eSDavid van Moolenbroek 			s = dmalloc ((unsigned)i + 2, MDL);
2653*83ee113eSDavid van Moolenbroek 			if (!s) {
2654*83ee113eSDavid van Moolenbroek 				parse_warn (cfile, "no trailing '.' on zone");
2655*83ee113eSDavid van Moolenbroek 				goto badzone;
2656*83ee113eSDavid van Moolenbroek 			}
2657*83ee113eSDavid van Moolenbroek 			strcpy (s, zone -> name);
2658*83ee113eSDavid van Moolenbroek 			s [i] = '.';
2659*83ee113eSDavid van Moolenbroek 			s [i + 1] = 0;
2660*83ee113eSDavid van Moolenbroek 			dfree (zone -> name, MDL);
2661*83ee113eSDavid van Moolenbroek 			zone -> name = s;
2662*83ee113eSDavid van Moolenbroek 		}
2663*83ee113eSDavid van Moolenbroek 		if (!parse_zone (zone, cfile))
2664*83ee113eSDavid van Moolenbroek 			goto badzone;
2665*83ee113eSDavid van Moolenbroek 		status = enter_dns_zone (zone);
2666*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS) {
2667*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "dns zone key %s: %s",
2668*83ee113eSDavid van Moolenbroek 				    zone -> name, isc_result_totext (status));
2669*83ee113eSDavid van Moolenbroek 			dns_zone_dereference (&zone, MDL);
2670*83ee113eSDavid van Moolenbroek 			return 0;
2671*83ee113eSDavid van Moolenbroek 		}
2672*83ee113eSDavid van Moolenbroek 		dns_zone_dereference (&zone, MDL);
2673*83ee113eSDavid van Moolenbroek 		return 1;
2674*83ee113eSDavid van Moolenbroek 
2675*83ee113eSDavid van Moolenbroek 		/* Also not really a statement, but same idea as above. */
2676*83ee113eSDavid van Moolenbroek 	      case KEY:
2677*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
2678*83ee113eSDavid van Moolenbroek 		if (!parse_key (cfile)) {
2679*83ee113eSDavid van Moolenbroek 			*lose = 1;
2680*83ee113eSDavid van Moolenbroek 			return 0;
2681*83ee113eSDavid van Moolenbroek 		}
2682*83ee113eSDavid van Moolenbroek 		return 1;
2683*83ee113eSDavid van Moolenbroek 
2684*83ee113eSDavid van Moolenbroek 	      default:
2685*83ee113eSDavid van Moolenbroek 		if (config_universe && is_identifier (token)) {
2686*83ee113eSDavid van Moolenbroek 			option = (struct option *)0;
2687*83ee113eSDavid van Moolenbroek 			option_name_hash_lookup(&option,
2688*83ee113eSDavid van Moolenbroek 						config_universe->name_hash,
2689*83ee113eSDavid van Moolenbroek 						val, 0, MDL);
2690*83ee113eSDavid van Moolenbroek 			if (option) {
2691*83ee113eSDavid van Moolenbroek 				skip_token(&val, (unsigned *)0, cfile);
2692*83ee113eSDavid van Moolenbroek 				status = parse_option_statement
2693*83ee113eSDavid van Moolenbroek 						(result, cfile, 1, option,
2694*83ee113eSDavid van Moolenbroek 						 supersede_option_statement);
2695*83ee113eSDavid van Moolenbroek 				option_dereference(&option, MDL);
2696*83ee113eSDavid van Moolenbroek 				return status;
2697*83ee113eSDavid van Moolenbroek 			}
2698*83ee113eSDavid van Moolenbroek 		}
2699*83ee113eSDavid van Moolenbroek 
2700*83ee113eSDavid van Moolenbroek 		if (token == NUMBER_OR_NAME || token == NAME) {
2701*83ee113eSDavid van Moolenbroek 			/* This is rather ugly.  Since function calls are
2702*83ee113eSDavid van Moolenbroek 			   data expressions, fake up an eval statement. */
2703*83ee113eSDavid van Moolenbroek 			if (!executable_statement_allocate (result, MDL))
2704*83ee113eSDavid van Moolenbroek 				log_fatal ("no memory for eval statement.");
2705*83ee113eSDavid van Moolenbroek 			(*result) -> op = eval_statement;
2706*83ee113eSDavid van Moolenbroek 
2707*83ee113eSDavid van Moolenbroek 			if (!parse_expression (&(*result) -> data.eval,
2708*83ee113eSDavid van Moolenbroek 					       cfile, lose, context_data,
2709*83ee113eSDavid van Moolenbroek 					       (struct expression **)0,
2710*83ee113eSDavid van Moolenbroek 					       expr_none)) {
2711*83ee113eSDavid van Moolenbroek 				if (!*lose)
2712*83ee113eSDavid van Moolenbroek 					parse_warn (cfile, "expecting "
2713*83ee113eSDavid van Moolenbroek 						    "function call.");
2714*83ee113eSDavid van Moolenbroek 				else
2715*83ee113eSDavid van Moolenbroek 					*lose = 1;
2716*83ee113eSDavid van Moolenbroek 				skip_to_semi (cfile);
2717*83ee113eSDavid van Moolenbroek 				executable_statement_dereference (result, MDL);
2718*83ee113eSDavid van Moolenbroek 				return 0;
2719*83ee113eSDavid van Moolenbroek 			}
2720*83ee113eSDavid van Moolenbroek 			if (!parse_semi (cfile)) {
2721*83ee113eSDavid van Moolenbroek 				*lose = 1;
2722*83ee113eSDavid van Moolenbroek 				executable_statement_dereference (result, MDL);
2723*83ee113eSDavid van Moolenbroek 				return 0;
2724*83ee113eSDavid van Moolenbroek 			}
2725*83ee113eSDavid van Moolenbroek 			break;
2726*83ee113eSDavid van Moolenbroek 		}
2727*83ee113eSDavid van Moolenbroek 
2728*83ee113eSDavid van Moolenbroek 		*lose = 0;
2729*83ee113eSDavid van Moolenbroek 		return 0;
2730*83ee113eSDavid van Moolenbroek 	}
2731*83ee113eSDavid van Moolenbroek 
2732*83ee113eSDavid van Moolenbroek 	return 1;
2733*83ee113eSDavid van Moolenbroek }
2734*83ee113eSDavid van Moolenbroek 
2735*83ee113eSDavid van Moolenbroek /* zone-statements :== zone-statement |
2736*83ee113eSDavid van Moolenbroek 		       zone-statement zone-statements
2737*83ee113eSDavid van Moolenbroek    zone-statement :==
2738*83ee113eSDavid van Moolenbroek 	PRIMARY ip-addresses SEMI |
2739*83ee113eSDavid van Moolenbroek 	SECONDARY ip-addresses SEMI |
2740*83ee113eSDavid van Moolenbroek 	PRIMARY6 ip-address6 SEMI |
2741*83ee113eSDavid van Moolenbroek 	SECONDARY6 ip-address6 SEMI |
2742*83ee113eSDavid van Moolenbroek 	key-reference SEMI
2743*83ee113eSDavid van Moolenbroek    ip-addresses :== ip-addr-or-hostname |
2744*83ee113eSDavid van Moolenbroek 		  ip-addr-or-hostname COMMA ip-addresses
2745*83ee113eSDavid van Moolenbroek    key-reference :== KEY STRING |
2746*83ee113eSDavid van Moolenbroek 		    KEY identifier */
2747*83ee113eSDavid van Moolenbroek 
parse_zone(struct dns_zone * zone,struct parse * cfile)2748*83ee113eSDavid van Moolenbroek int parse_zone (struct dns_zone *zone, struct parse *cfile)
2749*83ee113eSDavid van Moolenbroek {
2750*83ee113eSDavid van Moolenbroek 	int token;
2751*83ee113eSDavid van Moolenbroek 	const char *val;
2752*83ee113eSDavid van Moolenbroek 	char *key_name;
2753*83ee113eSDavid van Moolenbroek 	struct option_cache *oc;
2754*83ee113eSDavid van Moolenbroek 	int done = 0;
2755*83ee113eSDavid van Moolenbroek 
2756*83ee113eSDavid van Moolenbroek 	token = next_token (&val, (unsigned *)0, cfile);
2757*83ee113eSDavid van Moolenbroek 	if (token != LBRACE) {
2758*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "expecting left brace");
2759*83ee113eSDavid van Moolenbroek 		return 0;
2760*83ee113eSDavid van Moolenbroek 	}
2761*83ee113eSDavid van Moolenbroek 
2762*83ee113eSDavid van Moolenbroek 	do {
2763*83ee113eSDavid van Moolenbroek 	    token = peek_token (&val, (unsigned *)0, cfile);
2764*83ee113eSDavid van Moolenbroek 	    switch (token) {
2765*83ee113eSDavid van Moolenbroek 		  case PRIMARY:
2766*83ee113eSDavid van Moolenbroek 		    if (zone -> primary) {
2767*83ee113eSDavid van Moolenbroek 			    parse_warn (cfile,
2768*83ee113eSDavid van Moolenbroek 					"more than one primary.");
2769*83ee113eSDavid van Moolenbroek 			    skip_to_semi (cfile);
2770*83ee113eSDavid van Moolenbroek 			    return 0;
2771*83ee113eSDavid van Moolenbroek 		    }
2772*83ee113eSDavid van Moolenbroek 		    if (!option_cache_allocate (&zone -> primary, MDL))
2773*83ee113eSDavid van Moolenbroek 			    log_fatal ("can't allocate primary option cache.");
2774*83ee113eSDavid van Moolenbroek 		    oc = zone -> primary;
2775*83ee113eSDavid van Moolenbroek 		    goto consemup;
2776*83ee113eSDavid van Moolenbroek 
2777*83ee113eSDavid van Moolenbroek 		  case SECONDARY:
2778*83ee113eSDavid van Moolenbroek 		    if (zone -> secondary) {
2779*83ee113eSDavid van Moolenbroek 			    parse_warn (cfile, "more than one secondary.");
2780*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
2781*83ee113eSDavid van Moolenbroek 			return 0;
2782*83ee113eSDavid van Moolenbroek 		    }
2783*83ee113eSDavid van Moolenbroek 		    if (!option_cache_allocate (&zone -> secondary, MDL))
2784*83ee113eSDavid van Moolenbroek 			    log_fatal ("can't allocate secondary.");
2785*83ee113eSDavid van Moolenbroek 		    oc = zone -> secondary;
2786*83ee113eSDavid van Moolenbroek 		  consemup:
2787*83ee113eSDavid van Moolenbroek 		    skip_token(&val, (unsigned *)0, cfile);
2788*83ee113eSDavid van Moolenbroek 		    do {
2789*83ee113eSDavid van Moolenbroek 			    struct expression *expr = (struct expression *)0;
2790*83ee113eSDavid van Moolenbroek 			    if (!parse_ip_addr_or_hostname (&expr, cfile, 0)) {
2791*83ee113eSDavid van Moolenbroek 				parse_warn (cfile,
2792*83ee113eSDavid van Moolenbroek 					    "expecting IP addr or hostname.");
2793*83ee113eSDavid van Moolenbroek 				skip_to_semi (cfile);
2794*83ee113eSDavid van Moolenbroek 				return 0;
2795*83ee113eSDavid van Moolenbroek 			    }
2796*83ee113eSDavid van Moolenbroek 			    if (oc -> expression) {
2797*83ee113eSDavid van Moolenbroek 				    struct expression *old =
2798*83ee113eSDavid van Moolenbroek 					    (struct expression *)0;
2799*83ee113eSDavid van Moolenbroek 				    expression_reference (&old,
2800*83ee113eSDavid van Moolenbroek 							  oc -> expression,
2801*83ee113eSDavid van Moolenbroek 							  MDL);
2802*83ee113eSDavid van Moolenbroek 				    expression_dereference (&oc -> expression,
2803*83ee113eSDavid van Moolenbroek 							    MDL);
2804*83ee113eSDavid van Moolenbroek 				    if (!make_concat (&oc -> expression,
2805*83ee113eSDavid van Moolenbroek 						      old, expr))
2806*83ee113eSDavid van Moolenbroek 					log_fatal ("no memory for concat.");
2807*83ee113eSDavid van Moolenbroek 				    expression_dereference (&expr, MDL);
2808*83ee113eSDavid van Moolenbroek 				    expression_dereference (&old, MDL);
2809*83ee113eSDavid van Moolenbroek 			    } else {
2810*83ee113eSDavid van Moolenbroek 				    expression_reference (&oc -> expression,
2811*83ee113eSDavid van Moolenbroek 							  expr, MDL);
2812*83ee113eSDavid van Moolenbroek 				    expression_dereference (&expr, MDL);
2813*83ee113eSDavid van Moolenbroek 			    }
2814*83ee113eSDavid van Moolenbroek 			    token = next_token (&val, (unsigned *)0, cfile);
2815*83ee113eSDavid van Moolenbroek 		    } while (token == COMMA);
2816*83ee113eSDavid van Moolenbroek 		    if (token != SEMI) {
2817*83ee113eSDavid van Moolenbroek 			    parse_warn (cfile, "expecting semicolon.");
2818*83ee113eSDavid van Moolenbroek 			    skip_to_semi (cfile);
2819*83ee113eSDavid van Moolenbroek 			    return 0;
2820*83ee113eSDavid van Moolenbroek 		    }
2821*83ee113eSDavid van Moolenbroek 		    break;
2822*83ee113eSDavid van Moolenbroek 
2823*83ee113eSDavid van Moolenbroek 	          case PRIMARY6:
2824*83ee113eSDavid van Moolenbroek 		    if (zone->primary6) {
2825*83ee113eSDavid van Moolenbroek 			    parse_warn(cfile, "more than one primary6.");
2826*83ee113eSDavid van Moolenbroek 			    skip_to_semi(cfile);
2827*83ee113eSDavid van Moolenbroek 			    return (0);
2828*83ee113eSDavid van Moolenbroek 		    }
2829*83ee113eSDavid van Moolenbroek 		    if (!option_cache_allocate (&zone->primary6, MDL))
2830*83ee113eSDavid van Moolenbroek 			    log_fatal("can't allocate primary6 option cache.");
2831*83ee113eSDavid van Moolenbroek 		    oc = zone->primary6;
2832*83ee113eSDavid van Moolenbroek 		    goto consemup6;
2833*83ee113eSDavid van Moolenbroek 
2834*83ee113eSDavid van Moolenbroek 	          case SECONDARY6:
2835*83ee113eSDavid van Moolenbroek 		    if (zone->secondary6) {
2836*83ee113eSDavid van Moolenbroek 			    parse_warn(cfile, "more than one secondary6.");
2837*83ee113eSDavid van Moolenbroek 			    skip_to_semi(cfile);
2838*83ee113eSDavid van Moolenbroek 			    return (0);
2839*83ee113eSDavid van Moolenbroek 		    }
2840*83ee113eSDavid van Moolenbroek 		    if (!option_cache_allocate (&zone->secondary6, MDL))
2841*83ee113eSDavid van Moolenbroek 			    log_fatal("can't allocate secondary6 "
2842*83ee113eSDavid van Moolenbroek 				      "option cache.");
2843*83ee113eSDavid van Moolenbroek 		    oc = zone->secondary6;
2844*83ee113eSDavid van Moolenbroek 	          consemup6:
2845*83ee113eSDavid van Moolenbroek 		    skip_token(&val, NULL, cfile);
2846*83ee113eSDavid van Moolenbroek 		    do {
2847*83ee113eSDavid van Moolenbroek 			    struct expression *expr = NULL;
2848*83ee113eSDavid van Moolenbroek 			    if (parse_ip6_addr_expr(&expr, cfile) == 0) {
2849*83ee113eSDavid van Moolenbroek 				    parse_warn(cfile, "expecting IPv6 addr.");
2850*83ee113eSDavid van Moolenbroek 				    skip_to_semi(cfile);
2851*83ee113eSDavid van Moolenbroek 				    return (0);
2852*83ee113eSDavid van Moolenbroek 			    }
2853*83ee113eSDavid van Moolenbroek 			    if (oc->expression) {
2854*83ee113eSDavid van Moolenbroek 				    struct expression *old = NULL;
2855*83ee113eSDavid van Moolenbroek 				    expression_reference(&old, oc->expression,
2856*83ee113eSDavid van Moolenbroek 							 MDL);
2857*83ee113eSDavid van Moolenbroek 				    expression_dereference(&oc->expression,
2858*83ee113eSDavid van Moolenbroek 							   MDL);
2859*83ee113eSDavid van Moolenbroek 				    if (!make_concat(&oc->expression,
2860*83ee113eSDavid van Moolenbroek 						     old, expr))
2861*83ee113eSDavid van Moolenbroek 					    log_fatal("no memory for concat.");
2862*83ee113eSDavid van Moolenbroek 				    expression_dereference(&expr, MDL);
2863*83ee113eSDavid van Moolenbroek 				    expression_dereference(&old, MDL);
2864*83ee113eSDavid van Moolenbroek 			    } else {
2865*83ee113eSDavid van Moolenbroek 				    expression_reference(&oc->expression,
2866*83ee113eSDavid van Moolenbroek 							 expr, MDL);
2867*83ee113eSDavid van Moolenbroek 				    expression_dereference(&expr, MDL);
2868*83ee113eSDavid van Moolenbroek 			    }
2869*83ee113eSDavid van Moolenbroek 			    token = next_token(&val, NULL, cfile);
2870*83ee113eSDavid van Moolenbroek 		    } while (token == COMMA);
2871*83ee113eSDavid van Moolenbroek 		    if (token != SEMI) {
2872*83ee113eSDavid van Moolenbroek 			    parse_warn(cfile, "expecting semicolon.");
2873*83ee113eSDavid van Moolenbroek 			    skip_to_semi(cfile);
2874*83ee113eSDavid van Moolenbroek 			    return (0);
2875*83ee113eSDavid van Moolenbroek 		    }
2876*83ee113eSDavid van Moolenbroek 		    break;
2877*83ee113eSDavid van Moolenbroek 
2878*83ee113eSDavid van Moolenbroek 		  case KEY:
2879*83ee113eSDavid van Moolenbroek 		    skip_token(&val, (unsigned *)0, cfile);
2880*83ee113eSDavid van Moolenbroek 		    token = peek_token (&val, (unsigned *)0, cfile);
2881*83ee113eSDavid van Moolenbroek 		    if (token == STRING) {
2882*83ee113eSDavid van Moolenbroek 			    skip_token(&val, (unsigned *)0, cfile);
2883*83ee113eSDavid van Moolenbroek 			    key_name = (char *)0;
2884*83ee113eSDavid van Moolenbroek 		    } else {
2885*83ee113eSDavid van Moolenbroek 			    key_name = parse_host_name (cfile);
2886*83ee113eSDavid van Moolenbroek 			    if (!key_name) {
2887*83ee113eSDavid van Moolenbroek 				    parse_warn (cfile, "expecting key name.");
2888*83ee113eSDavid van Moolenbroek 				    skip_to_semi (cfile);
2889*83ee113eSDavid van Moolenbroek 				    return 0;
2890*83ee113eSDavid van Moolenbroek 			    }
2891*83ee113eSDavid van Moolenbroek 			    val = key_name;
2892*83ee113eSDavid van Moolenbroek 		    }
2893*83ee113eSDavid van Moolenbroek 		    if (omapi_auth_key_lookup_name (&zone -> key, val) !=
2894*83ee113eSDavid van Moolenbroek 			ISC_R_SUCCESS)
2895*83ee113eSDavid van Moolenbroek 			    parse_warn (cfile, "unknown key %s", val);
2896*83ee113eSDavid van Moolenbroek 		    if (key_name)
2897*83ee113eSDavid van Moolenbroek 			    dfree (key_name, MDL);
2898*83ee113eSDavid van Moolenbroek 		    if (!parse_semi (cfile))
2899*83ee113eSDavid van Moolenbroek 			    return 0;
2900*83ee113eSDavid van Moolenbroek 		    break;
2901*83ee113eSDavid van Moolenbroek 
2902*83ee113eSDavid van Moolenbroek 		  default:
2903*83ee113eSDavid van Moolenbroek 		    done = 1;
2904*83ee113eSDavid van Moolenbroek 		    break;
2905*83ee113eSDavid van Moolenbroek 	    }
2906*83ee113eSDavid van Moolenbroek 	} while (!done);
2907*83ee113eSDavid van Moolenbroek 
2908*83ee113eSDavid van Moolenbroek 	token = next_token (&val, (unsigned *)0, cfile);
2909*83ee113eSDavid van Moolenbroek 	if (token != RBRACE) {
2910*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "expecting right brace.");
2911*83ee113eSDavid van Moolenbroek 		return 0;
2912*83ee113eSDavid van Moolenbroek 	}
2913*83ee113eSDavid van Moolenbroek 	return 1;
2914*83ee113eSDavid van Moolenbroek }
2915*83ee113eSDavid van Moolenbroek 
2916*83ee113eSDavid van Moolenbroek /* key-statements :== key-statement |
2917*83ee113eSDavid van Moolenbroek 		      key-statement key-statements
2918*83ee113eSDavid van Moolenbroek    key-statement :==
2919*83ee113eSDavid van Moolenbroek 	ALGORITHM host-name SEMI |
2920*83ee113eSDavid van Moolenbroek 	secret-definition SEMI
2921*83ee113eSDavid van Moolenbroek    secret-definition :== SECRET base64val |
2922*83ee113eSDavid van Moolenbroek 			 SECRET STRING */
2923*83ee113eSDavid van Moolenbroek 
parse_key(struct parse * cfile)2924*83ee113eSDavid van Moolenbroek int parse_key (struct parse *cfile)
2925*83ee113eSDavid van Moolenbroek {
2926*83ee113eSDavid van Moolenbroek 	int token;
2927*83ee113eSDavid van Moolenbroek 	const char *val;
2928*83ee113eSDavid van Moolenbroek 	int done = 0;
2929*83ee113eSDavid van Moolenbroek 	struct auth_key *key;
2930*83ee113eSDavid van Moolenbroek 	struct data_string ds;
2931*83ee113eSDavid van Moolenbroek 	isc_result_t status;
2932*83ee113eSDavid van Moolenbroek 	char *s;
2933*83ee113eSDavid van Moolenbroek 
2934*83ee113eSDavid van Moolenbroek 	key = (struct auth_key *)0;
2935*83ee113eSDavid van Moolenbroek 	if (omapi_auth_key_new (&key, MDL) != ISC_R_SUCCESS)
2936*83ee113eSDavid van Moolenbroek 		log_fatal ("no memory for key");
2937*83ee113eSDavid van Moolenbroek 
2938*83ee113eSDavid van Moolenbroek 	token = peek_token (&val, (unsigned *)0, cfile);
2939*83ee113eSDavid van Moolenbroek 	if (token == STRING) {
2940*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
2941*83ee113eSDavid van Moolenbroek 		key -> name = dmalloc (strlen (val) + 1, MDL);
2942*83ee113eSDavid van Moolenbroek 		if (!key -> name)
2943*83ee113eSDavid van Moolenbroek 			log_fatal ("no memory for key name.");
2944*83ee113eSDavid van Moolenbroek 		strcpy (key -> name, val);
2945*83ee113eSDavid van Moolenbroek 
2946*83ee113eSDavid van Moolenbroek 	} else {
2947*83ee113eSDavid van Moolenbroek 		key -> name = parse_host_name (cfile);
2948*83ee113eSDavid van Moolenbroek 		if (!key -> name) {
2949*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "expecting key name.");
2950*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
2951*83ee113eSDavid van Moolenbroek 			goto bad;
2952*83ee113eSDavid van Moolenbroek 		}
2953*83ee113eSDavid van Moolenbroek 	}
2954*83ee113eSDavid van Moolenbroek 
2955*83ee113eSDavid van Moolenbroek 	token = next_token (&val, (unsigned *)0, cfile);
2956*83ee113eSDavid van Moolenbroek 	if (token != LBRACE) {
2957*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "expecting left brace");
2958*83ee113eSDavid van Moolenbroek 		goto bad;
2959*83ee113eSDavid van Moolenbroek 	}
2960*83ee113eSDavid van Moolenbroek 
2961*83ee113eSDavid van Moolenbroek 	do {
2962*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
2963*83ee113eSDavid van Moolenbroek 		switch (token) {
2964*83ee113eSDavid van Moolenbroek 		      case ALGORITHM:
2965*83ee113eSDavid van Moolenbroek 			if (key -> algorithm) {
2966*83ee113eSDavid van Moolenbroek 				parse_warn (cfile,
2967*83ee113eSDavid van Moolenbroek 					    "key %s: too many algorithms",
2968*83ee113eSDavid van Moolenbroek 					    key -> name);
2969*83ee113eSDavid van Moolenbroek 				goto rbad;
2970*83ee113eSDavid van Moolenbroek 			}
2971*83ee113eSDavid van Moolenbroek 			key -> algorithm = parse_host_name (cfile);
2972*83ee113eSDavid van Moolenbroek 			if (!key -> algorithm) {
2973*83ee113eSDavid van Moolenbroek 				parse_warn (cfile,
2974*83ee113eSDavid van Moolenbroek 					    "expecting key algorithm name.");
2975*83ee113eSDavid van Moolenbroek 				goto rbad;
2976*83ee113eSDavid van Moolenbroek 			}
2977*83ee113eSDavid van Moolenbroek 			if (!parse_semi (cfile))
2978*83ee113eSDavid van Moolenbroek 				goto rbad;
2979*83ee113eSDavid van Moolenbroek 			/* If the algorithm name isn't an FQDN, tack on
2980*83ee113eSDavid van Moolenbroek 			   the .SIG-ALG.REG.NET. domain. */
2981*83ee113eSDavid van Moolenbroek 			s = strrchr (key -> algorithm, '.');
2982*83ee113eSDavid van Moolenbroek 			if (!s) {
2983*83ee113eSDavid van Moolenbroek 			    static char add [] = ".SIG-ALG.REG.INT.";
2984*83ee113eSDavid van Moolenbroek 			    s = dmalloc (strlen (key -> algorithm) +
2985*83ee113eSDavid van Moolenbroek 					 sizeof (add), MDL);
2986*83ee113eSDavid van Moolenbroek 			    if (!s) {
2987*83ee113eSDavid van Moolenbroek 				log_error ("no memory for key %s.",
2988*83ee113eSDavid van Moolenbroek 					   "algorithm");
2989*83ee113eSDavid van Moolenbroek 				goto rbad;
2990*83ee113eSDavid van Moolenbroek 			    }
2991*83ee113eSDavid van Moolenbroek 			    strcpy (s, key -> algorithm);
2992*83ee113eSDavid van Moolenbroek 			    strcat (s, add);
2993*83ee113eSDavid van Moolenbroek 			    dfree (key -> algorithm, MDL);
2994*83ee113eSDavid van Moolenbroek 			    key -> algorithm = s;
2995*83ee113eSDavid van Moolenbroek 			} else if (s [1]) {
2996*83ee113eSDavid van Moolenbroek 			    /* If there is no trailing '.', hack one in. */
2997*83ee113eSDavid van Moolenbroek 			    s = dmalloc (strlen (key -> algorithm) + 2, MDL);
2998*83ee113eSDavid van Moolenbroek 			    if (!s) {
2999*83ee113eSDavid van Moolenbroek 				    log_error ("no memory for key %s.",
3000*83ee113eSDavid van Moolenbroek 					       key -> algorithm);
3001*83ee113eSDavid van Moolenbroek 				    goto rbad;
3002*83ee113eSDavid van Moolenbroek 			    }
3003*83ee113eSDavid van Moolenbroek 			    strcpy (s, key -> algorithm);
3004*83ee113eSDavid van Moolenbroek 			    strcat (s, ".");
3005*83ee113eSDavid van Moolenbroek 			    dfree (key -> algorithm, MDL);
3006*83ee113eSDavid van Moolenbroek 			    key -> algorithm = s;
3007*83ee113eSDavid van Moolenbroek 			}
3008*83ee113eSDavid van Moolenbroek 			break;
3009*83ee113eSDavid van Moolenbroek 
3010*83ee113eSDavid van Moolenbroek 		      case SECRET:
3011*83ee113eSDavid van Moolenbroek 			if (key -> key) {
3012*83ee113eSDavid van Moolenbroek 				parse_warn (cfile, "key %s: too many secrets",
3013*83ee113eSDavid van Moolenbroek 					    key -> name);
3014*83ee113eSDavid van Moolenbroek 				goto rbad;
3015*83ee113eSDavid van Moolenbroek 			}
3016*83ee113eSDavid van Moolenbroek 
3017*83ee113eSDavid van Moolenbroek 			memset (&ds, 0, sizeof(ds));
3018*83ee113eSDavid van Moolenbroek 			if (!parse_base64 (&ds, cfile))
3019*83ee113eSDavid van Moolenbroek 				goto rbad;
3020*83ee113eSDavid van Moolenbroek 			status = omapi_data_string_new (&key -> key, ds.len,
3021*83ee113eSDavid van Moolenbroek 							MDL);
3022*83ee113eSDavid van Moolenbroek 			if (status != ISC_R_SUCCESS)
3023*83ee113eSDavid van Moolenbroek 				goto rbad;
3024*83ee113eSDavid van Moolenbroek 			memcpy (key -> key -> value,
3025*83ee113eSDavid van Moolenbroek 				ds.buffer -> data, ds.len);
3026*83ee113eSDavid van Moolenbroek 			data_string_forget (&ds, MDL);
3027*83ee113eSDavid van Moolenbroek 
3028*83ee113eSDavid van Moolenbroek 			if (!parse_semi (cfile))
3029*83ee113eSDavid van Moolenbroek 				goto rbad;
3030*83ee113eSDavid van Moolenbroek 			break;
3031*83ee113eSDavid van Moolenbroek 
3032*83ee113eSDavid van Moolenbroek 		      default:
3033*83ee113eSDavid van Moolenbroek 			done = 1;
3034*83ee113eSDavid van Moolenbroek 			break;
3035*83ee113eSDavid van Moolenbroek 		}
3036*83ee113eSDavid van Moolenbroek 	} while (!done);
3037*83ee113eSDavid van Moolenbroek 	if (token != RBRACE) {
3038*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "expecting right brace.");
3039*83ee113eSDavid van Moolenbroek 		goto rbad;
3040*83ee113eSDavid van Moolenbroek 	}
3041*83ee113eSDavid van Moolenbroek 	/* Allow the BIND 8 syntax, which has a semicolon after each
3042*83ee113eSDavid van Moolenbroek 	   closing brace. */
3043*83ee113eSDavid van Moolenbroek 	token = peek_token (&val, (unsigned *)0, cfile);
3044*83ee113eSDavid van Moolenbroek 	if (token == SEMI) {
3045*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
3046*83ee113eSDavid van Moolenbroek 	}
3047*83ee113eSDavid van Moolenbroek 
3048*83ee113eSDavid van Moolenbroek 	/* Remember the key. */
3049*83ee113eSDavid van Moolenbroek 	status = omapi_auth_key_enter (key);
3050*83ee113eSDavid van Moolenbroek 	if (status != ISC_R_SUCCESS) {
3051*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "tsig key %s: %s",
3052*83ee113eSDavid van Moolenbroek 			    key -> name, isc_result_totext (status));
3053*83ee113eSDavid van Moolenbroek 		goto bad;
3054*83ee113eSDavid van Moolenbroek 	}
3055*83ee113eSDavid van Moolenbroek 	omapi_auth_key_dereference (&key, MDL);
3056*83ee113eSDavid van Moolenbroek 	return 1;
3057*83ee113eSDavid van Moolenbroek 
3058*83ee113eSDavid van Moolenbroek       rbad:
3059*83ee113eSDavid van Moolenbroek 	skip_to_rbrace (cfile, 1);
3060*83ee113eSDavid van Moolenbroek       bad:
3061*83ee113eSDavid van Moolenbroek 	omapi_auth_key_dereference (&key, MDL);
3062*83ee113eSDavid van Moolenbroek 	return 0;
3063*83ee113eSDavid van Moolenbroek }
3064*83ee113eSDavid van Moolenbroek 
3065*83ee113eSDavid van Moolenbroek /*
3066*83ee113eSDavid van Moolenbroek  * on-statement :== event-types LBRACE executable-statements RBRACE
3067*83ee113eSDavid van Moolenbroek  * event-types :== event-type OR event-types |
3068*83ee113eSDavid van Moolenbroek  *		   event-type
3069*83ee113eSDavid van Moolenbroek  * event-type :== EXPIRY | COMMIT | RELEASE
3070*83ee113eSDavid van Moolenbroek  */
3071*83ee113eSDavid van Moolenbroek 
parse_on_statement(result,cfile,lose)3072*83ee113eSDavid van Moolenbroek int parse_on_statement (result, cfile, lose)
3073*83ee113eSDavid van Moolenbroek 	struct executable_statement **result;
3074*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
3075*83ee113eSDavid van Moolenbroek 	int *lose;
3076*83ee113eSDavid van Moolenbroek {
3077*83ee113eSDavid van Moolenbroek 	enum dhcp_token token;
3078*83ee113eSDavid van Moolenbroek 	const char *val;
3079*83ee113eSDavid van Moolenbroek 
3080*83ee113eSDavid van Moolenbroek 	if (!executable_statement_allocate (result, MDL))
3081*83ee113eSDavid van Moolenbroek 		log_fatal ("no memory for new statement.");
3082*83ee113eSDavid van Moolenbroek 	(*result) -> op = on_statement;
3083*83ee113eSDavid van Moolenbroek 
3084*83ee113eSDavid van Moolenbroek 	do {
3085*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
3086*83ee113eSDavid van Moolenbroek 		switch (token) {
3087*83ee113eSDavid van Moolenbroek 		      case EXPIRY:
3088*83ee113eSDavid van Moolenbroek 			(*result) -> data.on.evtypes |= ON_EXPIRY;
3089*83ee113eSDavid van Moolenbroek 			break;
3090*83ee113eSDavid van Moolenbroek 
3091*83ee113eSDavid van Moolenbroek 		      case COMMIT:
3092*83ee113eSDavid van Moolenbroek 			(*result) -> data.on.evtypes |= ON_COMMIT;
3093*83ee113eSDavid van Moolenbroek 			break;
3094*83ee113eSDavid van Moolenbroek 
3095*83ee113eSDavid van Moolenbroek 		      case RELEASE:
3096*83ee113eSDavid van Moolenbroek 			(*result) -> data.on.evtypes |= ON_RELEASE;
3097*83ee113eSDavid van Moolenbroek 			break;
3098*83ee113eSDavid van Moolenbroek 
3099*83ee113eSDavid van Moolenbroek 		      case TRANSMISSION:
3100*83ee113eSDavid van Moolenbroek 			(*result) -> data.on.evtypes |= ON_TRANSMISSION;
3101*83ee113eSDavid van Moolenbroek 			break;
3102*83ee113eSDavid van Moolenbroek 
3103*83ee113eSDavid van Moolenbroek 		      default:
3104*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "expecting a lease event type");
3105*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
3106*83ee113eSDavid van Moolenbroek 			*lose = 1;
3107*83ee113eSDavid van Moolenbroek 			executable_statement_dereference (result, MDL);
3108*83ee113eSDavid van Moolenbroek 			return 0;
3109*83ee113eSDavid van Moolenbroek 		}
3110*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
3111*83ee113eSDavid van Moolenbroek 	} while (token == OR);
3112*83ee113eSDavid van Moolenbroek 
3113*83ee113eSDavid van Moolenbroek 	/* Semicolon means no statements. */
3114*83ee113eSDavid van Moolenbroek 	if (token == SEMI)
3115*83ee113eSDavid van Moolenbroek 		return 1;
3116*83ee113eSDavid van Moolenbroek 
3117*83ee113eSDavid van Moolenbroek 	if (token != LBRACE) {
3118*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "left brace expected.");
3119*83ee113eSDavid van Moolenbroek 		skip_to_semi (cfile);
3120*83ee113eSDavid van Moolenbroek 		*lose = 1;
3121*83ee113eSDavid van Moolenbroek 		executable_statement_dereference (result, MDL);
3122*83ee113eSDavid van Moolenbroek 		return 0;
3123*83ee113eSDavid van Moolenbroek 	}
3124*83ee113eSDavid van Moolenbroek 	if (!parse_executable_statements (&(*result) -> data.on.statements,
3125*83ee113eSDavid van Moolenbroek 					  cfile, lose, context_any)) {
3126*83ee113eSDavid van Moolenbroek 		if (*lose) {
3127*83ee113eSDavid van Moolenbroek 			/* Try to even things up. */
3128*83ee113eSDavid van Moolenbroek 			do {
3129*83ee113eSDavid van Moolenbroek 				token = next_token (&val,
3130*83ee113eSDavid van Moolenbroek 						    (unsigned *)0, cfile);
3131*83ee113eSDavid van Moolenbroek 			} while (token != END_OF_FILE && token != RBRACE);
3132*83ee113eSDavid van Moolenbroek 			executable_statement_dereference (result, MDL);
3133*83ee113eSDavid van Moolenbroek 			return 0;
3134*83ee113eSDavid van Moolenbroek 		}
3135*83ee113eSDavid van Moolenbroek 	}
3136*83ee113eSDavid van Moolenbroek 	token = next_token (&val, (unsigned *)0, cfile);
3137*83ee113eSDavid van Moolenbroek 	if (token != RBRACE) {
3138*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "right brace expected.");
3139*83ee113eSDavid van Moolenbroek 		skip_to_semi (cfile);
3140*83ee113eSDavid van Moolenbroek 		*lose = 1;
3141*83ee113eSDavid van Moolenbroek 		executable_statement_dereference (result, MDL);
3142*83ee113eSDavid van Moolenbroek 		return 0;
3143*83ee113eSDavid van Moolenbroek 	}
3144*83ee113eSDavid van Moolenbroek 	return 1;
3145*83ee113eSDavid van Moolenbroek }
3146*83ee113eSDavid van Moolenbroek 
3147*83ee113eSDavid van Moolenbroek /*
3148*83ee113eSDavid van Moolenbroek  * switch-statement :== LPAREN expr RPAREN LBRACE executable-statements RBRACE
3149*83ee113eSDavid van Moolenbroek  *
3150*83ee113eSDavid van Moolenbroek  */
3151*83ee113eSDavid van Moolenbroek 
parse_switch_statement(result,cfile,lose)3152*83ee113eSDavid van Moolenbroek int parse_switch_statement (result, cfile, lose)
3153*83ee113eSDavid van Moolenbroek 	struct executable_statement **result;
3154*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
3155*83ee113eSDavid van Moolenbroek 	int *lose;
3156*83ee113eSDavid van Moolenbroek {
3157*83ee113eSDavid van Moolenbroek 	enum dhcp_token token;
3158*83ee113eSDavid van Moolenbroek 	const char *val;
3159*83ee113eSDavid van Moolenbroek 
3160*83ee113eSDavid van Moolenbroek 	if (!executable_statement_allocate (result, MDL))
3161*83ee113eSDavid van Moolenbroek 		log_fatal ("no memory for new statement.");
3162*83ee113eSDavid van Moolenbroek 	(*result) -> op = switch_statement;
3163*83ee113eSDavid van Moolenbroek 
3164*83ee113eSDavid van Moolenbroek 	token = next_token (&val, (unsigned *)0, cfile);
3165*83ee113eSDavid van Moolenbroek 	if (token != LPAREN) {
3166*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "expecting left brace.");
3167*83ee113eSDavid van Moolenbroek 	      pfui:
3168*83ee113eSDavid van Moolenbroek 		*lose = 1;
3169*83ee113eSDavid van Moolenbroek 		skip_to_semi (cfile);
3170*83ee113eSDavid van Moolenbroek 	      gnorf:
3171*83ee113eSDavid van Moolenbroek 		executable_statement_dereference (result, MDL);
3172*83ee113eSDavid van Moolenbroek 		return 0;
3173*83ee113eSDavid van Moolenbroek 	}
3174*83ee113eSDavid van Moolenbroek 
3175*83ee113eSDavid van Moolenbroek 	if (!parse_expression (&(*result) -> data.s_switch.expr,
3176*83ee113eSDavid van Moolenbroek 			       cfile, lose, context_data_or_numeric,
3177*83ee113eSDavid van Moolenbroek 			       (struct expression **)0, expr_none)) {
3178*83ee113eSDavid van Moolenbroek 		if (!*lose) {
3179*83ee113eSDavid van Moolenbroek 			parse_warn (cfile,
3180*83ee113eSDavid van Moolenbroek 				    "expecting data or numeric expression.");
3181*83ee113eSDavid van Moolenbroek 			goto pfui;
3182*83ee113eSDavid van Moolenbroek 		}
3183*83ee113eSDavid van Moolenbroek 		goto gnorf;
3184*83ee113eSDavid van Moolenbroek 	}
3185*83ee113eSDavid van Moolenbroek 
3186*83ee113eSDavid van Moolenbroek 	token = next_token (&val, (unsigned *)0, cfile);
3187*83ee113eSDavid van Moolenbroek 	if (token != RPAREN) {
3188*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "right paren expected.");
3189*83ee113eSDavid van Moolenbroek 		goto pfui;
3190*83ee113eSDavid van Moolenbroek 	}
3191*83ee113eSDavid van Moolenbroek 
3192*83ee113eSDavid van Moolenbroek 	token = next_token (&val, (unsigned *)0, cfile);
3193*83ee113eSDavid van Moolenbroek 	if (token != LBRACE) {
3194*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "left brace expected.");
3195*83ee113eSDavid van Moolenbroek 		goto pfui;
3196*83ee113eSDavid van Moolenbroek 	}
3197*83ee113eSDavid van Moolenbroek 	if (!(parse_executable_statements
3198*83ee113eSDavid van Moolenbroek 	      (&(*result) -> data.s_switch.statements, cfile, lose,
3199*83ee113eSDavid van Moolenbroek 	       (is_data_expression ((*result) -> data.s_switch.expr)
3200*83ee113eSDavid van Moolenbroek 		? context_data : context_numeric)))) {
3201*83ee113eSDavid van Moolenbroek 		if (*lose) {
3202*83ee113eSDavid van Moolenbroek 			skip_to_rbrace (cfile, 1);
3203*83ee113eSDavid van Moolenbroek 			executable_statement_dereference (result, MDL);
3204*83ee113eSDavid van Moolenbroek 			return 0;
3205*83ee113eSDavid van Moolenbroek 		}
3206*83ee113eSDavid van Moolenbroek 	}
3207*83ee113eSDavid van Moolenbroek 	token = next_token (&val, (unsigned *)0, cfile);
3208*83ee113eSDavid van Moolenbroek 	if (token != RBRACE) {
3209*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "right brace expected.");
3210*83ee113eSDavid van Moolenbroek 		goto pfui;
3211*83ee113eSDavid van Moolenbroek 	}
3212*83ee113eSDavid van Moolenbroek 	return 1;
3213*83ee113eSDavid van Moolenbroek }
3214*83ee113eSDavid van Moolenbroek 
3215*83ee113eSDavid van Moolenbroek /*
3216*83ee113eSDavid van Moolenbroek  * case-statement :== CASE expr COLON
3217*83ee113eSDavid van Moolenbroek  *
3218*83ee113eSDavid van Moolenbroek  */
3219*83ee113eSDavid van Moolenbroek 
parse_case_statement(result,cfile,lose,case_context)3220*83ee113eSDavid van Moolenbroek int parse_case_statement (result, cfile, lose, case_context)
3221*83ee113eSDavid van Moolenbroek 	struct executable_statement **result;
3222*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
3223*83ee113eSDavid van Moolenbroek 	int *lose;
3224*83ee113eSDavid van Moolenbroek 	enum expression_context case_context;
3225*83ee113eSDavid van Moolenbroek {
3226*83ee113eSDavid van Moolenbroek 	enum dhcp_token token;
3227*83ee113eSDavid van Moolenbroek 	const char *val;
3228*83ee113eSDavid van Moolenbroek 
3229*83ee113eSDavid van Moolenbroek 	if (!executable_statement_allocate (result, MDL))
3230*83ee113eSDavid van Moolenbroek 		log_fatal ("no memory for new statement.");
3231*83ee113eSDavid van Moolenbroek 	(*result) -> op = case_statement;
3232*83ee113eSDavid van Moolenbroek 
3233*83ee113eSDavid van Moolenbroek 	if (!parse_expression (&(*result) -> data.c_case,
3234*83ee113eSDavid van Moolenbroek 			       cfile, lose, case_context,
3235*83ee113eSDavid van Moolenbroek 			       (struct expression **)0, expr_none))
3236*83ee113eSDavid van Moolenbroek 	{
3237*83ee113eSDavid van Moolenbroek 		if (!*lose) {
3238*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "expecting %s expression.",
3239*83ee113eSDavid van Moolenbroek 				    (case_context == context_data
3240*83ee113eSDavid van Moolenbroek 				     ? "data" : "numeric"));
3241*83ee113eSDavid van Moolenbroek 		}
3242*83ee113eSDavid van Moolenbroek 	      pfui:
3243*83ee113eSDavid van Moolenbroek 		*lose = 1;
3244*83ee113eSDavid van Moolenbroek 		skip_to_semi (cfile);
3245*83ee113eSDavid van Moolenbroek 		executable_statement_dereference (result, MDL);
3246*83ee113eSDavid van Moolenbroek 		return 0;
3247*83ee113eSDavid van Moolenbroek 	}
3248*83ee113eSDavid van Moolenbroek 
3249*83ee113eSDavid van Moolenbroek 	token = next_token (&val, (unsigned *)0, cfile);
3250*83ee113eSDavid van Moolenbroek 	if (token != COLON) {
3251*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "colon expected.");
3252*83ee113eSDavid van Moolenbroek 		goto pfui;
3253*83ee113eSDavid van Moolenbroek 	}
3254*83ee113eSDavid van Moolenbroek 	return 1;
3255*83ee113eSDavid van Moolenbroek }
3256*83ee113eSDavid van Moolenbroek 
3257*83ee113eSDavid van Moolenbroek /*
3258*83ee113eSDavid van Moolenbroek  * if-statement :== boolean-expression LBRACE executable-statements RBRACE
3259*83ee113eSDavid van Moolenbroek  *						else-statement
3260*83ee113eSDavid van Moolenbroek  *
3261*83ee113eSDavid van Moolenbroek  * else-statement :== <null> |
3262*83ee113eSDavid van Moolenbroek  *		      ELSE LBRACE executable-statements RBRACE |
3263*83ee113eSDavid van Moolenbroek  *		      ELSE IF if-statement |
3264*83ee113eSDavid van Moolenbroek  *		      ELSIF if-statement
3265*83ee113eSDavid van Moolenbroek  */
3266*83ee113eSDavid van Moolenbroek 
parse_if_statement(result,cfile,lose)3267*83ee113eSDavid van Moolenbroek int parse_if_statement (result, cfile, lose)
3268*83ee113eSDavid van Moolenbroek 	struct executable_statement **result;
3269*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
3270*83ee113eSDavid van Moolenbroek 	int *lose;
3271*83ee113eSDavid van Moolenbroek {
3272*83ee113eSDavid van Moolenbroek 	enum dhcp_token token;
3273*83ee113eSDavid van Moolenbroek 	const char *val;
3274*83ee113eSDavid van Moolenbroek 	int parenp;
3275*83ee113eSDavid van Moolenbroek 
3276*83ee113eSDavid van Moolenbroek 	if (!executable_statement_allocate (result, MDL))
3277*83ee113eSDavid van Moolenbroek 		log_fatal ("no memory for if statement.");
3278*83ee113eSDavid van Moolenbroek 
3279*83ee113eSDavid van Moolenbroek 	(*result) -> op = if_statement;
3280*83ee113eSDavid van Moolenbroek 
3281*83ee113eSDavid van Moolenbroek 	token = peek_token (&val, (unsigned *)0, cfile);
3282*83ee113eSDavid van Moolenbroek 	if (token == LPAREN) {
3283*83ee113eSDavid van Moolenbroek 		parenp = 1;
3284*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
3285*83ee113eSDavid van Moolenbroek 	} else
3286*83ee113eSDavid van Moolenbroek 		parenp = 0;
3287*83ee113eSDavid van Moolenbroek 
3288*83ee113eSDavid van Moolenbroek 
3289*83ee113eSDavid van Moolenbroek 	if (!parse_boolean_expression (&(*result) -> data.ie.expr,
3290*83ee113eSDavid van Moolenbroek 				       cfile, lose)) {
3291*83ee113eSDavid van Moolenbroek 		if (!*lose)
3292*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "boolean expression expected.");
3293*83ee113eSDavid van Moolenbroek 		executable_statement_dereference (result, MDL);
3294*83ee113eSDavid van Moolenbroek 		*lose = 1;
3295*83ee113eSDavid van Moolenbroek 		return 0;
3296*83ee113eSDavid van Moolenbroek 	}
3297*83ee113eSDavid van Moolenbroek #if defined (DEBUG_EXPRESSION_PARSE)
3298*83ee113eSDavid van Moolenbroek 	print_expression ("if condition", (*result) -> data.ie.expr);
3299*83ee113eSDavid van Moolenbroek #endif
3300*83ee113eSDavid van Moolenbroek 	if (parenp) {
3301*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
3302*83ee113eSDavid van Moolenbroek 		if (token != RPAREN) {
3303*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "expecting right paren.");
3304*83ee113eSDavid van Moolenbroek 			*lose = 1;
3305*83ee113eSDavid van Moolenbroek 			executable_statement_dereference (result, MDL);
3306*83ee113eSDavid van Moolenbroek 			return 0;
3307*83ee113eSDavid van Moolenbroek 		}
3308*83ee113eSDavid van Moolenbroek 	}
3309*83ee113eSDavid van Moolenbroek 	token = next_token (&val, (unsigned *)0, cfile);
3310*83ee113eSDavid van Moolenbroek 	if (token != LBRACE) {
3311*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "left brace expected.");
3312*83ee113eSDavid van Moolenbroek 		skip_to_semi (cfile);
3313*83ee113eSDavid van Moolenbroek 		*lose = 1;
3314*83ee113eSDavid van Moolenbroek 		executable_statement_dereference (result, MDL);
3315*83ee113eSDavid van Moolenbroek 		return 0;
3316*83ee113eSDavid van Moolenbroek 	}
3317*83ee113eSDavid van Moolenbroek 	if (!parse_executable_statements (&(*result) -> data.ie.tc,
3318*83ee113eSDavid van Moolenbroek 					  cfile, lose, context_any)) {
3319*83ee113eSDavid van Moolenbroek 		if (*lose) {
3320*83ee113eSDavid van Moolenbroek 			/* Try to even things up. */
3321*83ee113eSDavid van Moolenbroek 			do {
3322*83ee113eSDavid van Moolenbroek 				token = next_token (&val,
3323*83ee113eSDavid van Moolenbroek 						    (unsigned *)0, cfile);
3324*83ee113eSDavid van Moolenbroek 			} while (token != END_OF_FILE && token != RBRACE);
3325*83ee113eSDavid van Moolenbroek 			executable_statement_dereference (result, MDL);
3326*83ee113eSDavid van Moolenbroek 			return 0;
3327*83ee113eSDavid van Moolenbroek 		}
3328*83ee113eSDavid van Moolenbroek 	}
3329*83ee113eSDavid van Moolenbroek 	token = next_token (&val, (unsigned *)0, cfile);
3330*83ee113eSDavid van Moolenbroek 	if (token != RBRACE) {
3331*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "right brace expected.");
3332*83ee113eSDavid van Moolenbroek 		skip_to_semi (cfile);
3333*83ee113eSDavid van Moolenbroek 		*lose = 1;
3334*83ee113eSDavid van Moolenbroek 		executable_statement_dereference (result, MDL);
3335*83ee113eSDavid van Moolenbroek 		return 0;
3336*83ee113eSDavid van Moolenbroek 	}
3337*83ee113eSDavid van Moolenbroek 	token = peek_token (&val, (unsigned *)0, cfile);
3338*83ee113eSDavid van Moolenbroek 	if (token == ELSE) {
3339*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
3340*83ee113eSDavid van Moolenbroek 		token = peek_token (&val, (unsigned *)0, cfile);
3341*83ee113eSDavid van Moolenbroek 		if (token == IF) {
3342*83ee113eSDavid van Moolenbroek 			skip_token(&val, (unsigned *)0, cfile);
3343*83ee113eSDavid van Moolenbroek 			if (!parse_if_statement (&(*result) -> data.ie.fc,
3344*83ee113eSDavid van Moolenbroek 						 cfile, lose)) {
3345*83ee113eSDavid van Moolenbroek 				if (!*lose)
3346*83ee113eSDavid van Moolenbroek 					parse_warn (cfile,
3347*83ee113eSDavid van Moolenbroek 						    "expecting if statement");
3348*83ee113eSDavid van Moolenbroek 				executable_statement_dereference (result, MDL);
3349*83ee113eSDavid van Moolenbroek 				*lose = 1;
3350*83ee113eSDavid van Moolenbroek 				return 0;
3351*83ee113eSDavid van Moolenbroek 			}
3352*83ee113eSDavid van Moolenbroek 		} else if (token != LBRACE) {
3353*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "left brace or if expected.");
3354*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
3355*83ee113eSDavid van Moolenbroek 			*lose = 1;
3356*83ee113eSDavid van Moolenbroek 			executable_statement_dereference (result, MDL);
3357*83ee113eSDavid van Moolenbroek 			return 0;
3358*83ee113eSDavid van Moolenbroek 		} else {
3359*83ee113eSDavid van Moolenbroek 			skip_token(&val, (unsigned *)0, cfile);
3360*83ee113eSDavid van Moolenbroek 			if (!(parse_executable_statements
3361*83ee113eSDavid van Moolenbroek 			      (&(*result) -> data.ie.fc,
3362*83ee113eSDavid van Moolenbroek 			       cfile, lose, context_any))) {
3363*83ee113eSDavid van Moolenbroek 				executable_statement_dereference (result, MDL);
3364*83ee113eSDavid van Moolenbroek 				return 0;
3365*83ee113eSDavid van Moolenbroek 			}
3366*83ee113eSDavid van Moolenbroek 			token = next_token (&val, (unsigned *)0, cfile);
3367*83ee113eSDavid van Moolenbroek 			if (token != RBRACE) {
3368*83ee113eSDavid van Moolenbroek 				parse_warn (cfile, "right brace expected.");
3369*83ee113eSDavid van Moolenbroek 				skip_to_semi (cfile);
3370*83ee113eSDavid van Moolenbroek 				*lose = 1;
3371*83ee113eSDavid van Moolenbroek 				executable_statement_dereference (result, MDL);
3372*83ee113eSDavid van Moolenbroek 				return 0;
3373*83ee113eSDavid van Moolenbroek 			}
3374*83ee113eSDavid van Moolenbroek 		}
3375*83ee113eSDavid van Moolenbroek 	} else if (token == ELSIF) {
3376*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
3377*83ee113eSDavid van Moolenbroek 		if (!parse_if_statement (&(*result) -> data.ie.fc,
3378*83ee113eSDavid van Moolenbroek 					 cfile, lose)) {
3379*83ee113eSDavid van Moolenbroek 			if (!*lose)
3380*83ee113eSDavid van Moolenbroek 				parse_warn (cfile,
3381*83ee113eSDavid van Moolenbroek 					    "expecting conditional.");
3382*83ee113eSDavid van Moolenbroek 			executable_statement_dereference (result, MDL);
3383*83ee113eSDavid van Moolenbroek 			*lose = 1;
3384*83ee113eSDavid van Moolenbroek 			return 0;
3385*83ee113eSDavid van Moolenbroek 		}
3386*83ee113eSDavid van Moolenbroek 	} else
3387*83ee113eSDavid van Moolenbroek 		(*result) -> data.ie.fc = (struct executable_statement *)0;
3388*83ee113eSDavid van Moolenbroek 
3389*83ee113eSDavid van Moolenbroek 	return 1;
3390*83ee113eSDavid van Moolenbroek }
3391*83ee113eSDavid van Moolenbroek 
3392*83ee113eSDavid van Moolenbroek /*
3393*83ee113eSDavid van Moolenbroek  * boolean_expression :== CHECK STRING |
3394*83ee113eSDavid van Moolenbroek  *  			  NOT boolean-expression |
3395*83ee113eSDavid van Moolenbroek  *			  data-expression EQUAL data-expression |
3396*83ee113eSDavid van Moolenbroek  *			  data-expression BANG EQUAL data-expression |
3397*83ee113eSDavid van Moolenbroek  *			  data-expression REGEX_MATCH data-expression |
3398*83ee113eSDavid van Moolenbroek  *			  boolean-expression AND boolean-expression |
3399*83ee113eSDavid van Moolenbroek  *			  boolean-expression OR boolean-expression
3400*83ee113eSDavid van Moolenbroek  *			  EXISTS OPTION-NAME
3401*83ee113eSDavid van Moolenbroek  */
3402*83ee113eSDavid van Moolenbroek 
parse_boolean_expression(expr,cfile,lose)3403*83ee113eSDavid van Moolenbroek int parse_boolean_expression (expr, cfile, lose)
3404*83ee113eSDavid van Moolenbroek 	struct expression **expr;
3405*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
3406*83ee113eSDavid van Moolenbroek 	int *lose;
3407*83ee113eSDavid van Moolenbroek {
3408*83ee113eSDavid van Moolenbroek 	/* Parse an expression... */
3409*83ee113eSDavid van Moolenbroek 	if (!parse_expression (expr, cfile, lose, context_boolean,
3410*83ee113eSDavid van Moolenbroek 			       (struct expression **)0, expr_none))
3411*83ee113eSDavid van Moolenbroek 		return 0;
3412*83ee113eSDavid van Moolenbroek 
3413*83ee113eSDavid van Moolenbroek 	if (!is_boolean_expression (*expr) &&
3414*83ee113eSDavid van Moolenbroek 	    (*expr) -> op != expr_variable_reference &&
3415*83ee113eSDavid van Moolenbroek 	    (*expr) -> op != expr_funcall) {
3416*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "Expecting a boolean expression.");
3417*83ee113eSDavid van Moolenbroek 		*lose = 1;
3418*83ee113eSDavid van Moolenbroek 		expression_dereference (expr, MDL);
3419*83ee113eSDavid van Moolenbroek 		return 0;
3420*83ee113eSDavid van Moolenbroek 	}
3421*83ee113eSDavid van Moolenbroek 	return 1;
3422*83ee113eSDavid van Moolenbroek }
3423*83ee113eSDavid van Moolenbroek 
3424*83ee113eSDavid van Moolenbroek /* boolean :== ON SEMI | OFF SEMI | TRUE SEMI | FALSE SEMI */
3425*83ee113eSDavid van Moolenbroek 
parse_boolean(cfile)3426*83ee113eSDavid van Moolenbroek int parse_boolean (cfile)
3427*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
3428*83ee113eSDavid van Moolenbroek {
3429*83ee113eSDavid van Moolenbroek 	const char *val;
3430*83ee113eSDavid van Moolenbroek 	int rv;
3431*83ee113eSDavid van Moolenbroek 
3432*83ee113eSDavid van Moolenbroek         (void)next_token(&val, NULL, cfile);
3433*83ee113eSDavid van Moolenbroek 	if (!strcasecmp (val, "true")
3434*83ee113eSDavid van Moolenbroek 	    || !strcasecmp (val, "on"))
3435*83ee113eSDavid van Moolenbroek 		rv = 1;
3436*83ee113eSDavid van Moolenbroek 	else if (!strcasecmp (val, "false")
3437*83ee113eSDavid van Moolenbroek 		 || !strcasecmp (val, "off"))
3438*83ee113eSDavid van Moolenbroek 		rv = 0;
3439*83ee113eSDavid van Moolenbroek 	else {
3440*83ee113eSDavid van Moolenbroek 		parse_warn (cfile,
3441*83ee113eSDavid van Moolenbroek 			    "boolean value (true/false/on/off) expected");
3442*83ee113eSDavid van Moolenbroek 		skip_to_semi (cfile);
3443*83ee113eSDavid van Moolenbroek 		return 0;
3444*83ee113eSDavid van Moolenbroek 	}
3445*83ee113eSDavid van Moolenbroek 	parse_semi (cfile);
3446*83ee113eSDavid van Moolenbroek 	return rv;
3447*83ee113eSDavid van Moolenbroek }
3448*83ee113eSDavid van Moolenbroek 
3449*83ee113eSDavid van Moolenbroek 
3450*83ee113eSDavid van Moolenbroek /*
3451*83ee113eSDavid van Moolenbroek  * data_expression :== SUBSTRING LPAREN data-expression COMMA
3452*83ee113eSDavid van Moolenbroek  *					numeric-expression COMMA
3453*83ee113eSDavid van Moolenbroek  *					numeric-expression RPAREN |
3454*83ee113eSDavid van Moolenbroek  *		       CONCAT LPAREN data-expression COMMA
3455*83ee113eSDavid van Moolenbroek  *					data-expression RPAREN
3456*83ee113eSDavid van Moolenbroek  *		       SUFFIX LPAREN data_expression COMMA
3457*83ee113eSDavid van Moolenbroek  *		       		     numeric-expression RPAREN |
3458*83ee113eSDavid van Moolenbroek  *		       LCASE LPAREN data_expression RPAREN |
3459*83ee113eSDavid van Moolenbroek  *		       UCASE LPAREN data_expression RPAREN |
3460*83ee113eSDavid van Moolenbroek  *		       OPTION option_name |
3461*83ee113eSDavid van Moolenbroek  *		       HARDWARE |
3462*83ee113eSDavid van Moolenbroek  *		       PACKET LPAREN numeric-expression COMMA
3463*83ee113eSDavid van Moolenbroek  *				     numeric-expression RPAREN |
3464*83ee113eSDavid van Moolenbroek  *		       V6RELAY LPAREN numeric-expression COMMA
3465*83ee113eSDavid van Moolenbroek  *				      data-expression RPAREN |
3466*83ee113eSDavid van Moolenbroek  *		       STRING |
3467*83ee113eSDavid van Moolenbroek  *		       colon_separated_hex_list
3468*83ee113eSDavid van Moolenbroek  */
3469*83ee113eSDavid van Moolenbroek 
parse_data_expression(expr,cfile,lose)3470*83ee113eSDavid van Moolenbroek int parse_data_expression (expr, cfile, lose)
3471*83ee113eSDavid van Moolenbroek 	struct expression **expr;
3472*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
3473*83ee113eSDavid van Moolenbroek 	int *lose;
3474*83ee113eSDavid van Moolenbroek {
3475*83ee113eSDavid van Moolenbroek 	/* Parse an expression... */
3476*83ee113eSDavid van Moolenbroek 	if (!parse_expression (expr, cfile, lose, context_data,
3477*83ee113eSDavid van Moolenbroek 			       (struct expression **)0, expr_none))
3478*83ee113eSDavid van Moolenbroek 		return 0;
3479*83ee113eSDavid van Moolenbroek 
3480*83ee113eSDavid van Moolenbroek 	if (!is_data_expression (*expr) &&
3481*83ee113eSDavid van Moolenbroek 	    (*expr) -> op != expr_variable_reference &&
3482*83ee113eSDavid van Moolenbroek 	    (*expr) -> op != expr_funcall) {
3483*83ee113eSDavid van Moolenbroek 		expression_dereference (expr, MDL);
3484*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "Expecting a data expression.");
3485*83ee113eSDavid van Moolenbroek 		*lose = 1;
3486*83ee113eSDavid van Moolenbroek 		return 0;
3487*83ee113eSDavid van Moolenbroek 	}
3488*83ee113eSDavid van Moolenbroek 	return 1;
3489*83ee113eSDavid van Moolenbroek }
3490*83ee113eSDavid van Moolenbroek 
3491*83ee113eSDavid van Moolenbroek /*
3492*83ee113eSDavid van Moolenbroek  * numeric-expression :== EXTRACT_INT LPAREN data-expression
3493*83ee113eSDavid van Moolenbroek  *					     COMMA number RPAREN |
3494*83ee113eSDavid van Moolenbroek  *			  NUMBER
3495*83ee113eSDavid van Moolenbroek  */
3496*83ee113eSDavid van Moolenbroek 
parse_numeric_expression(expr,cfile,lose)3497*83ee113eSDavid van Moolenbroek int parse_numeric_expression (expr, cfile, lose)
3498*83ee113eSDavid van Moolenbroek 	struct expression **expr;
3499*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
3500*83ee113eSDavid van Moolenbroek 	int *lose;
3501*83ee113eSDavid van Moolenbroek {
3502*83ee113eSDavid van Moolenbroek 	/* Parse an expression... */
3503*83ee113eSDavid van Moolenbroek 	if (!parse_expression (expr, cfile, lose, context_numeric,
3504*83ee113eSDavid van Moolenbroek 			       (struct expression **)0, expr_none))
3505*83ee113eSDavid van Moolenbroek 		return 0;
3506*83ee113eSDavid van Moolenbroek 
3507*83ee113eSDavid van Moolenbroek 	if (!is_numeric_expression (*expr) &&
3508*83ee113eSDavid van Moolenbroek 	    (*expr) -> op != expr_variable_reference &&
3509*83ee113eSDavid van Moolenbroek 	    (*expr) -> op != expr_funcall) {
3510*83ee113eSDavid van Moolenbroek 		expression_dereference (expr, MDL);
3511*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "Expecting a numeric expression.");
3512*83ee113eSDavid van Moolenbroek 		*lose = 1;
3513*83ee113eSDavid van Moolenbroek 		return 0;
3514*83ee113eSDavid van Moolenbroek 	}
3515*83ee113eSDavid van Moolenbroek 	return 1;
3516*83ee113eSDavid van Moolenbroek }
3517*83ee113eSDavid van Moolenbroek 
3518*83ee113eSDavid van Moolenbroek /* Parse a subexpression that does not contain a binary operator. */
3519*83ee113eSDavid van Moolenbroek 
parse_non_binary(expr,cfile,lose,context)3520*83ee113eSDavid van Moolenbroek int parse_non_binary (expr, cfile, lose, context)
3521*83ee113eSDavid van Moolenbroek 	struct expression **expr;
3522*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
3523*83ee113eSDavid van Moolenbroek 	int *lose;
3524*83ee113eSDavid van Moolenbroek 	enum expression_context context;
3525*83ee113eSDavid van Moolenbroek {
3526*83ee113eSDavid van Moolenbroek 	enum dhcp_token token;
3527*83ee113eSDavid van Moolenbroek 	const char *val;
3528*83ee113eSDavid van Moolenbroek 	struct collection *col;
3529*83ee113eSDavid van Moolenbroek 	struct expression *nexp, **ep;
3530*83ee113eSDavid van Moolenbroek 	int known;
3531*83ee113eSDavid van Moolenbroek 	char *cptr;
3532*83ee113eSDavid van Moolenbroek 	isc_result_t status;
3533*83ee113eSDavid van Moolenbroek 	unsigned len;
3534*83ee113eSDavid van Moolenbroek 
3535*83ee113eSDavid van Moolenbroek 	token = peek_token (&val, (unsigned *)0, cfile);
3536*83ee113eSDavid van Moolenbroek 
3537*83ee113eSDavid van Moolenbroek 	/* Check for unary operators... */
3538*83ee113eSDavid van Moolenbroek 	switch (token) {
3539*83ee113eSDavid van Moolenbroek 	      case CHECK:
3540*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
3541*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
3542*83ee113eSDavid van Moolenbroek 		if (token != STRING) {
3543*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "string expected.");
3544*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
3545*83ee113eSDavid van Moolenbroek 			*lose = 1;
3546*83ee113eSDavid van Moolenbroek 			return 0;
3547*83ee113eSDavid van Moolenbroek 		}
3548*83ee113eSDavid van Moolenbroek 		for (col = collections; col; col = col -> next)
3549*83ee113eSDavid van Moolenbroek 			if (!strcmp (col -> name, val))
3550*83ee113eSDavid van Moolenbroek 				break;
3551*83ee113eSDavid van Moolenbroek 		if (!col) {
3552*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "unknown collection.");
3553*83ee113eSDavid van Moolenbroek 			*lose = 1;
3554*83ee113eSDavid van Moolenbroek 			return 0;
3555*83ee113eSDavid van Moolenbroek 		}
3556*83ee113eSDavid van Moolenbroek 		if (!expression_allocate (expr, MDL))
3557*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate expression");
3558*83ee113eSDavid van Moolenbroek 		(*expr) -> op = expr_check;
3559*83ee113eSDavid van Moolenbroek 		(*expr) -> data.check = col;
3560*83ee113eSDavid van Moolenbroek 		break;
3561*83ee113eSDavid van Moolenbroek 
3562*83ee113eSDavid van Moolenbroek 	      case TOKEN_NOT:
3563*83ee113eSDavid van Moolenbroek 		skip_token(&val, NULL, cfile);
3564*83ee113eSDavid van Moolenbroek 		if (!expression_allocate (expr, MDL))
3565*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate expression");
3566*83ee113eSDavid van Moolenbroek 		(*expr)->op = expr_not;
3567*83ee113eSDavid van Moolenbroek 		if (!parse_non_binary (&(*expr)->data.not,
3568*83ee113eSDavid van Moolenbroek 				       cfile, lose, context_boolean)) {
3569*83ee113eSDavid van Moolenbroek 			if (!*lose) {
3570*83ee113eSDavid van Moolenbroek 				parse_warn (cfile, "expression expected");
3571*83ee113eSDavid van Moolenbroek 				skip_to_semi (cfile);
3572*83ee113eSDavid van Moolenbroek 			}
3573*83ee113eSDavid van Moolenbroek 			*lose = 1;
3574*83ee113eSDavid van Moolenbroek 			expression_dereference (expr, MDL);
3575*83ee113eSDavid van Moolenbroek 			return (0);
3576*83ee113eSDavid van Moolenbroek 		}
3577*83ee113eSDavid van Moolenbroek 		if (!is_boolean_expression ((*expr) -> data.not)) {
3578*83ee113eSDavid van Moolenbroek 			*lose = 1;
3579*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "boolean expression expected");
3580*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
3581*83ee113eSDavid van Moolenbroek 			expression_dereference (expr, MDL);
3582*83ee113eSDavid van Moolenbroek 			return 0;
3583*83ee113eSDavid van Moolenbroek 		}
3584*83ee113eSDavid van Moolenbroek 		break;
3585*83ee113eSDavid van Moolenbroek 
3586*83ee113eSDavid van Moolenbroek 	      case LPAREN:
3587*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
3588*83ee113eSDavid van Moolenbroek 		if (!parse_expression (expr, cfile, lose, context,
3589*83ee113eSDavid van Moolenbroek 				       (struct expression **)0, expr_none)) {
3590*83ee113eSDavid van Moolenbroek 			if (!*lose) {
3591*83ee113eSDavid van Moolenbroek 				parse_warn (cfile, "expression expected");
3592*83ee113eSDavid van Moolenbroek 				skip_to_semi (cfile);
3593*83ee113eSDavid van Moolenbroek 			}
3594*83ee113eSDavid van Moolenbroek 			*lose = 1;
3595*83ee113eSDavid van Moolenbroek 			return 0;
3596*83ee113eSDavid van Moolenbroek 		}
3597*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
3598*83ee113eSDavid van Moolenbroek 		if (token != RPAREN) {
3599*83ee113eSDavid van Moolenbroek 			*lose = 1;
3600*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "right paren expected");
3601*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
3602*83ee113eSDavid van Moolenbroek 			return 0;
3603*83ee113eSDavid van Moolenbroek 		}
3604*83ee113eSDavid van Moolenbroek 		break;
3605*83ee113eSDavid van Moolenbroek 
3606*83ee113eSDavid van Moolenbroek 	      case EXISTS:
3607*83ee113eSDavid van Moolenbroek 		skip_token(&val, NULL, cfile);
3608*83ee113eSDavid van Moolenbroek 		if (!expression_allocate (expr, MDL))
3609*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate expression");
3610*83ee113eSDavid van Moolenbroek 		(*expr)->op = expr_exists;
3611*83ee113eSDavid van Moolenbroek 		known = 0;
3612*83ee113eSDavid van Moolenbroek 		/* Pass reference directly to expression structure. */
3613*83ee113eSDavid van Moolenbroek 		status = parse_option_name(cfile, 0, &known,
3614*83ee113eSDavid van Moolenbroek 					   &(*expr)->data.option);
3615*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS ||
3616*83ee113eSDavid van Moolenbroek 		    (*expr)->data.option == NULL) {
3617*83ee113eSDavid van Moolenbroek 			*lose = 1;
3618*83ee113eSDavid van Moolenbroek 			expression_dereference (expr, MDL);
3619*83ee113eSDavid van Moolenbroek 			return (0);
3620*83ee113eSDavid van Moolenbroek 		}
3621*83ee113eSDavid van Moolenbroek 		break;
3622*83ee113eSDavid van Moolenbroek 
3623*83ee113eSDavid van Moolenbroek 	      case STATIC:
3624*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
3625*83ee113eSDavid van Moolenbroek 		if (!expression_allocate (expr, MDL))
3626*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate expression");
3627*83ee113eSDavid van Moolenbroek 		(*expr) -> op = expr_static;
3628*83ee113eSDavid van Moolenbroek 		break;
3629*83ee113eSDavid van Moolenbroek 
3630*83ee113eSDavid van Moolenbroek 	      case KNOWN:
3631*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
3632*83ee113eSDavid van Moolenbroek 		if (!expression_allocate (expr, MDL))
3633*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate expression");
3634*83ee113eSDavid van Moolenbroek 		(*expr) -> op = expr_known;
3635*83ee113eSDavid van Moolenbroek 		break;
3636*83ee113eSDavid van Moolenbroek 
3637*83ee113eSDavid van Moolenbroek 	      case SUBSTRING:
3638*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
3639*83ee113eSDavid van Moolenbroek 		if (!expression_allocate (expr, MDL))
3640*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate expression");
3641*83ee113eSDavid van Moolenbroek 		(*expr) -> op = expr_substring;
3642*83ee113eSDavid van Moolenbroek 
3643*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
3644*83ee113eSDavid van Moolenbroek 		if (token != LPAREN) {
3645*83ee113eSDavid van Moolenbroek 		      nolparen:
3646*83ee113eSDavid van Moolenbroek 			expression_dereference (expr, MDL);
3647*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "left parenthesis expected.");
3648*83ee113eSDavid van Moolenbroek 			*lose = 1;
3649*83ee113eSDavid van Moolenbroek 			return 0;
3650*83ee113eSDavid van Moolenbroek 		}
3651*83ee113eSDavid van Moolenbroek 
3652*83ee113eSDavid van Moolenbroek 		if (!parse_data_expression (&(*expr) -> data.substring.expr,
3653*83ee113eSDavid van Moolenbroek 					    cfile, lose)) {
3654*83ee113eSDavid van Moolenbroek 		      nodata:
3655*83ee113eSDavid van Moolenbroek 			expression_dereference (expr, MDL);
3656*83ee113eSDavid van Moolenbroek 			if (!*lose) {
3657*83ee113eSDavid van Moolenbroek 				parse_warn (cfile,
3658*83ee113eSDavid van Moolenbroek 					    "expecting data expression.");
3659*83ee113eSDavid van Moolenbroek 				skip_to_semi (cfile);
3660*83ee113eSDavid van Moolenbroek 				*lose = 1;
3661*83ee113eSDavid van Moolenbroek 			}
3662*83ee113eSDavid van Moolenbroek 			return 0;
3663*83ee113eSDavid van Moolenbroek 		}
3664*83ee113eSDavid van Moolenbroek 
3665*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
3666*83ee113eSDavid van Moolenbroek 		if (token != COMMA) {
3667*83ee113eSDavid van Moolenbroek 		      nocomma:
3668*83ee113eSDavid van Moolenbroek 			expression_dereference (expr, MDL);
3669*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "comma expected.");
3670*83ee113eSDavid van Moolenbroek 			*lose = 1;
3671*83ee113eSDavid van Moolenbroek 
3672*83ee113eSDavid van Moolenbroek 			return 0;
3673*83ee113eSDavid van Moolenbroek 		}
3674*83ee113eSDavid van Moolenbroek 
3675*83ee113eSDavid van Moolenbroek 		if (!parse_numeric_expression
3676*83ee113eSDavid van Moolenbroek 		    (&(*expr) -> data.substring.offset,cfile, lose)) {
3677*83ee113eSDavid van Moolenbroek 		      nonum:
3678*83ee113eSDavid van Moolenbroek 			if (!*lose) {
3679*83ee113eSDavid van Moolenbroek 				parse_warn (cfile,
3680*83ee113eSDavid van Moolenbroek 					    "expecting numeric expression.");
3681*83ee113eSDavid van Moolenbroek 				skip_to_semi (cfile);
3682*83ee113eSDavid van Moolenbroek 				*lose = 1;
3683*83ee113eSDavid van Moolenbroek 			}
3684*83ee113eSDavid van Moolenbroek 			expression_dereference (expr, MDL);
3685*83ee113eSDavid van Moolenbroek 			return 0;
3686*83ee113eSDavid van Moolenbroek 		}
3687*83ee113eSDavid van Moolenbroek 
3688*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
3689*83ee113eSDavid van Moolenbroek 		if (token != COMMA)
3690*83ee113eSDavid van Moolenbroek 			goto nocomma;
3691*83ee113eSDavid van Moolenbroek 
3692*83ee113eSDavid van Moolenbroek 		if (!parse_numeric_expression
3693*83ee113eSDavid van Moolenbroek 		    (&(*expr) -> data.substring.len, cfile, lose))
3694*83ee113eSDavid van Moolenbroek 			goto nonum;
3695*83ee113eSDavid van Moolenbroek 
3696*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
3697*83ee113eSDavid van Moolenbroek 		if (token != RPAREN) {
3698*83ee113eSDavid van Moolenbroek 		      norparen:
3699*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "right parenthesis expected.");
3700*83ee113eSDavid van Moolenbroek 			*lose = 1;
3701*83ee113eSDavid van Moolenbroek 			expression_dereference (expr, MDL);
3702*83ee113eSDavid van Moolenbroek 			return 0;
3703*83ee113eSDavid van Moolenbroek 		}
3704*83ee113eSDavid van Moolenbroek 		break;
3705*83ee113eSDavid van Moolenbroek 
3706*83ee113eSDavid van Moolenbroek 	      case SUFFIX:
3707*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
3708*83ee113eSDavid van Moolenbroek 		if (!expression_allocate (expr, MDL))
3709*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate expression");
3710*83ee113eSDavid van Moolenbroek 		(*expr) -> op = expr_suffix;
3711*83ee113eSDavid van Moolenbroek 
3712*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
3713*83ee113eSDavid van Moolenbroek 		if (token != LPAREN)
3714*83ee113eSDavid van Moolenbroek 			goto nolparen;
3715*83ee113eSDavid van Moolenbroek 
3716*83ee113eSDavid van Moolenbroek 		if (!parse_data_expression (&(*expr) -> data.suffix.expr,
3717*83ee113eSDavid van Moolenbroek 					    cfile, lose))
3718*83ee113eSDavid van Moolenbroek 			goto nodata;
3719*83ee113eSDavid van Moolenbroek 
3720*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
3721*83ee113eSDavid van Moolenbroek 		if (token != COMMA)
3722*83ee113eSDavid van Moolenbroek 			goto nocomma;
3723*83ee113eSDavid van Moolenbroek 
3724*83ee113eSDavid van Moolenbroek 		if (!parse_numeric_expression (&(*expr) -> data.suffix.len,
3725*83ee113eSDavid van Moolenbroek 					       cfile, lose))
3726*83ee113eSDavid van Moolenbroek 			goto nonum;
3727*83ee113eSDavid van Moolenbroek 
3728*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
3729*83ee113eSDavid van Moolenbroek 		if (token != RPAREN)
3730*83ee113eSDavid van Moolenbroek 			goto norparen;
3731*83ee113eSDavid van Moolenbroek 		break;
3732*83ee113eSDavid van Moolenbroek 
3733*83ee113eSDavid van Moolenbroek 	      case LCASE:
3734*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
3735*83ee113eSDavid van Moolenbroek 		if (!expression_allocate(expr, MDL))
3736*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate expression");
3737*83ee113eSDavid van Moolenbroek 		(*expr)->op = expr_lcase;
3738*83ee113eSDavid van Moolenbroek 
3739*83ee113eSDavid van Moolenbroek 		token = next_token(&val, (unsigned *)0, cfile);
3740*83ee113eSDavid van Moolenbroek 		if (token != LPAREN)
3741*83ee113eSDavid van Moolenbroek 			goto nolparen;
3742*83ee113eSDavid van Moolenbroek 
3743*83ee113eSDavid van Moolenbroek 		if (!parse_data_expression(&(*expr)->data.lcase, cfile, lose))
3744*83ee113eSDavid van Moolenbroek 			goto nodata;
3745*83ee113eSDavid van Moolenbroek 
3746*83ee113eSDavid van Moolenbroek 		token = next_token(&val, (unsigned *)0, cfile);
3747*83ee113eSDavid van Moolenbroek 		if (token != RPAREN)
3748*83ee113eSDavid van Moolenbroek 			goto norparen;
3749*83ee113eSDavid van Moolenbroek 		break;
3750*83ee113eSDavid van Moolenbroek 
3751*83ee113eSDavid van Moolenbroek 	      case UCASE:
3752*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
3753*83ee113eSDavid van Moolenbroek 		if (!expression_allocate(expr, MDL))
3754*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate expression");
3755*83ee113eSDavid van Moolenbroek 		(*expr)->op = expr_ucase;
3756*83ee113eSDavid van Moolenbroek 
3757*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
3758*83ee113eSDavid van Moolenbroek 		if (token != LPAREN)
3759*83ee113eSDavid van Moolenbroek 			goto nolparen;
3760*83ee113eSDavid van Moolenbroek 
3761*83ee113eSDavid van Moolenbroek 		if (!parse_data_expression(&(*expr)->data.ucase,
3762*83ee113eSDavid van Moolenbroek 					   cfile, lose))
3763*83ee113eSDavid van Moolenbroek 			goto nodata;
3764*83ee113eSDavid van Moolenbroek 
3765*83ee113eSDavid van Moolenbroek 		token = next_token(&val, (unsigned *)0, cfile);
3766*83ee113eSDavid van Moolenbroek 		if (token != RPAREN)
3767*83ee113eSDavid van Moolenbroek 			goto norparen;
3768*83ee113eSDavid van Moolenbroek 		break;
3769*83ee113eSDavid van Moolenbroek 
3770*83ee113eSDavid van Moolenbroek 	      case CONCAT:
3771*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
3772*83ee113eSDavid van Moolenbroek 		if (!expression_allocate (expr, MDL))
3773*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate expression");
3774*83ee113eSDavid van Moolenbroek 		(*expr) -> op = expr_concat;
3775*83ee113eSDavid van Moolenbroek 
3776*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
3777*83ee113eSDavid van Moolenbroek 		if (token != LPAREN)
3778*83ee113eSDavid van Moolenbroek 			goto nolparen;
3779*83ee113eSDavid van Moolenbroek 
3780*83ee113eSDavid van Moolenbroek 		if (!parse_data_expression (&(*expr) -> data.concat [0],
3781*83ee113eSDavid van Moolenbroek 					    cfile, lose))
3782*83ee113eSDavid van Moolenbroek 			goto nodata;
3783*83ee113eSDavid van Moolenbroek 
3784*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
3785*83ee113eSDavid van Moolenbroek 		if (token != COMMA)
3786*83ee113eSDavid van Moolenbroek 			goto nocomma;
3787*83ee113eSDavid van Moolenbroek 
3788*83ee113eSDavid van Moolenbroek 	      concat_another:
3789*83ee113eSDavid van Moolenbroek 		if (!parse_data_expression (&(*expr) -> data.concat [1],
3790*83ee113eSDavid van Moolenbroek 					    cfile, lose))
3791*83ee113eSDavid van Moolenbroek 			goto nodata;
3792*83ee113eSDavid van Moolenbroek 
3793*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
3794*83ee113eSDavid van Moolenbroek 
3795*83ee113eSDavid van Moolenbroek 		if (token == COMMA) {
3796*83ee113eSDavid van Moolenbroek 			nexp = (struct expression *)0;
3797*83ee113eSDavid van Moolenbroek 			if (!expression_allocate (&nexp, MDL))
3798*83ee113eSDavid van Moolenbroek 				log_fatal ("can't allocate at CONCAT2");
3799*83ee113eSDavid van Moolenbroek 			nexp -> op = expr_concat;
3800*83ee113eSDavid van Moolenbroek 			expression_reference (&nexp -> data.concat [0],
3801*83ee113eSDavid van Moolenbroek 					      *expr, MDL);
3802*83ee113eSDavid van Moolenbroek 			expression_dereference (expr, MDL);
3803*83ee113eSDavid van Moolenbroek 			expression_reference (expr, nexp, MDL);
3804*83ee113eSDavid van Moolenbroek 			expression_dereference (&nexp, MDL);
3805*83ee113eSDavid van Moolenbroek 			goto concat_another;
3806*83ee113eSDavid van Moolenbroek 		}
3807*83ee113eSDavid van Moolenbroek 
3808*83ee113eSDavid van Moolenbroek 		if (token != RPAREN)
3809*83ee113eSDavid van Moolenbroek 			goto norparen;
3810*83ee113eSDavid van Moolenbroek 		break;
3811*83ee113eSDavid van Moolenbroek 
3812*83ee113eSDavid van Moolenbroek 	      case BINARY_TO_ASCII:
3813*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
3814*83ee113eSDavid van Moolenbroek 		if (!expression_allocate (expr, MDL))
3815*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate expression");
3816*83ee113eSDavid van Moolenbroek 		(*expr) -> op = expr_binary_to_ascii;
3817*83ee113eSDavid van Moolenbroek 
3818*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
3819*83ee113eSDavid van Moolenbroek 		if (token != LPAREN)
3820*83ee113eSDavid van Moolenbroek 			goto nolparen;
3821*83ee113eSDavid van Moolenbroek 
3822*83ee113eSDavid van Moolenbroek 		if (!parse_numeric_expression (&(*expr) -> data.b2a.base,
3823*83ee113eSDavid van Moolenbroek 					       cfile, lose))
3824*83ee113eSDavid van Moolenbroek 			goto nodata;
3825*83ee113eSDavid van Moolenbroek 
3826*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
3827*83ee113eSDavid van Moolenbroek 		if (token != COMMA)
3828*83ee113eSDavid van Moolenbroek 			goto nocomma;
3829*83ee113eSDavid van Moolenbroek 
3830*83ee113eSDavid van Moolenbroek 		if (!parse_numeric_expression (&(*expr) -> data.b2a.width,
3831*83ee113eSDavid van Moolenbroek 					       cfile, lose))
3832*83ee113eSDavid van Moolenbroek 			goto nodata;
3833*83ee113eSDavid van Moolenbroek 
3834*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
3835*83ee113eSDavid van Moolenbroek 		if (token != COMMA)
3836*83ee113eSDavid van Moolenbroek 			goto nocomma;
3837*83ee113eSDavid van Moolenbroek 
3838*83ee113eSDavid van Moolenbroek 		if (!parse_data_expression (&(*expr) -> data.b2a.separator,
3839*83ee113eSDavid van Moolenbroek 					    cfile, lose))
3840*83ee113eSDavid van Moolenbroek 			goto nodata;
3841*83ee113eSDavid van Moolenbroek 
3842*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
3843*83ee113eSDavid van Moolenbroek 		if (token != COMMA)
3844*83ee113eSDavid van Moolenbroek 			goto nocomma;
3845*83ee113eSDavid van Moolenbroek 
3846*83ee113eSDavid van Moolenbroek 		if (!parse_data_expression (&(*expr) -> data.b2a.buffer,
3847*83ee113eSDavid van Moolenbroek 					    cfile, lose))
3848*83ee113eSDavid van Moolenbroek 			goto nodata;
3849*83ee113eSDavid van Moolenbroek 
3850*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
3851*83ee113eSDavid van Moolenbroek 		if (token != RPAREN)
3852*83ee113eSDavid van Moolenbroek 			goto norparen;
3853*83ee113eSDavid van Moolenbroek 		break;
3854*83ee113eSDavid van Moolenbroek 
3855*83ee113eSDavid van Moolenbroek 	      case REVERSE:
3856*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
3857*83ee113eSDavid van Moolenbroek 		if (!expression_allocate (expr, MDL))
3858*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate expression");
3859*83ee113eSDavid van Moolenbroek 		(*expr) -> op = expr_reverse;
3860*83ee113eSDavid van Moolenbroek 
3861*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
3862*83ee113eSDavid van Moolenbroek 		if (token != LPAREN)
3863*83ee113eSDavid van Moolenbroek 			goto nolparen;
3864*83ee113eSDavid van Moolenbroek 
3865*83ee113eSDavid van Moolenbroek 		if (!(parse_numeric_expression
3866*83ee113eSDavid van Moolenbroek 		      (&(*expr) -> data.reverse.width, cfile, lose)))
3867*83ee113eSDavid van Moolenbroek 			goto nodata;
3868*83ee113eSDavid van Moolenbroek 
3869*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
3870*83ee113eSDavid van Moolenbroek 		if (token != COMMA)
3871*83ee113eSDavid van Moolenbroek 			goto nocomma;
3872*83ee113eSDavid van Moolenbroek 
3873*83ee113eSDavid van Moolenbroek 		if (!(parse_data_expression
3874*83ee113eSDavid van Moolenbroek 		      (&(*expr) -> data.reverse.buffer, cfile, lose)))
3875*83ee113eSDavid van Moolenbroek 			goto nodata;
3876*83ee113eSDavid van Moolenbroek 
3877*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
3878*83ee113eSDavid van Moolenbroek 		if (token != RPAREN)
3879*83ee113eSDavid van Moolenbroek 			goto norparen;
3880*83ee113eSDavid van Moolenbroek 		break;
3881*83ee113eSDavid van Moolenbroek 
3882*83ee113eSDavid van Moolenbroek 	      case PICK:
3883*83ee113eSDavid van Moolenbroek 		/* pick (a, b, c) actually produces an internal representation
3884*83ee113eSDavid van Moolenbroek 		   that looks like pick (a, pick (b, pick (c, nil))). */
3885*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
3886*83ee113eSDavid van Moolenbroek 		if (!(expression_allocate (expr, MDL)))
3887*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate expression");
3888*83ee113eSDavid van Moolenbroek 
3889*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
3890*83ee113eSDavid van Moolenbroek 		if (token != LPAREN)
3891*83ee113eSDavid van Moolenbroek 			goto nolparen;
3892*83ee113eSDavid van Moolenbroek 
3893*83ee113eSDavid van Moolenbroek 		nexp = (struct expression *)0;
3894*83ee113eSDavid van Moolenbroek 		expression_reference (&nexp, *expr, MDL);
3895*83ee113eSDavid van Moolenbroek 		do {
3896*83ee113eSDavid van Moolenbroek 		    nexp -> op = expr_pick_first_value;
3897*83ee113eSDavid van Moolenbroek 		    if (!(parse_data_expression
3898*83ee113eSDavid van Moolenbroek 			  (&nexp -> data.pick_first_value.car,
3899*83ee113eSDavid van Moolenbroek 			   cfile, lose)))
3900*83ee113eSDavid van Moolenbroek 			goto nodata;
3901*83ee113eSDavid van Moolenbroek 
3902*83ee113eSDavid van Moolenbroek 		    token = next_token (&val, (unsigned *)0, cfile);
3903*83ee113eSDavid van Moolenbroek 		    if (token == COMMA) {
3904*83ee113eSDavid van Moolenbroek 			struct expression *foo = (struct expression *)0;
3905*83ee113eSDavid van Moolenbroek 			if (!expression_allocate (&foo, MDL))
3906*83ee113eSDavid van Moolenbroek 			    log_fatal ("can't allocate expr");
3907*83ee113eSDavid van Moolenbroek 			expression_reference
3908*83ee113eSDavid van Moolenbroek 				(&nexp -> data.pick_first_value.cdr, foo, MDL);
3909*83ee113eSDavid van Moolenbroek 			expression_dereference (&nexp, MDL);
3910*83ee113eSDavid van Moolenbroek 			expression_reference (&nexp, foo, MDL);
3911*83ee113eSDavid van Moolenbroek 			expression_dereference (&foo, MDL);
3912*83ee113eSDavid van Moolenbroek 		    }
3913*83ee113eSDavid van Moolenbroek 		} while (token == COMMA);
3914*83ee113eSDavid van Moolenbroek 		expression_dereference (&nexp, MDL);
3915*83ee113eSDavid van Moolenbroek 
3916*83ee113eSDavid van Moolenbroek 		if (token != RPAREN)
3917*83ee113eSDavid van Moolenbroek 			goto norparen;
3918*83ee113eSDavid van Moolenbroek 		break;
3919*83ee113eSDavid van Moolenbroek 
3920*83ee113eSDavid van Moolenbroek 	      case OPTION:
3921*83ee113eSDavid van Moolenbroek 	      case CONFIG_OPTION:
3922*83ee113eSDavid van Moolenbroek 		if (!expression_allocate (expr, MDL))
3923*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate expression");
3924*83ee113eSDavid van Moolenbroek 		(*expr) -> op = (token == OPTION
3925*83ee113eSDavid van Moolenbroek 				 ? expr_option
3926*83ee113eSDavid van Moolenbroek 				 : expr_config_option);
3927*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
3928*83ee113eSDavid van Moolenbroek 		known = 0;
3929*83ee113eSDavid van Moolenbroek 		/* Pass reference directly to expression structure. */
3930*83ee113eSDavid van Moolenbroek 		status = parse_option_name(cfile, 0, &known,
3931*83ee113eSDavid van Moolenbroek 					   &(*expr)->data.option);
3932*83ee113eSDavid van Moolenbroek 		if (status != ISC_R_SUCCESS ||
3933*83ee113eSDavid van Moolenbroek 		    (*expr)->data.option == NULL) {
3934*83ee113eSDavid van Moolenbroek 			*lose = 1;
3935*83ee113eSDavid van Moolenbroek 			expression_dereference (expr, MDL);
3936*83ee113eSDavid van Moolenbroek 			return 0;
3937*83ee113eSDavid van Moolenbroek 		}
3938*83ee113eSDavid van Moolenbroek 		break;
3939*83ee113eSDavid van Moolenbroek 
3940*83ee113eSDavid van Moolenbroek 	      case HARDWARE:
3941*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
3942*83ee113eSDavid van Moolenbroek 		if (!expression_allocate (expr, MDL))
3943*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate expression");
3944*83ee113eSDavid van Moolenbroek 		(*expr) -> op = expr_hardware;
3945*83ee113eSDavid van Moolenbroek 		break;
3946*83ee113eSDavid van Moolenbroek 
3947*83ee113eSDavid van Moolenbroek 	      case LEASED_ADDRESS:
3948*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
3949*83ee113eSDavid van Moolenbroek 		if (!expression_allocate (expr, MDL))
3950*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate expression");
3951*83ee113eSDavid van Moolenbroek 		(*expr) -> op = expr_leased_address;
3952*83ee113eSDavid van Moolenbroek 		break;
3953*83ee113eSDavid van Moolenbroek 
3954*83ee113eSDavid van Moolenbroek 	      case CLIENT_STATE:
3955*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
3956*83ee113eSDavid van Moolenbroek 		if (!expression_allocate (expr, MDL))
3957*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate expression");
3958*83ee113eSDavid van Moolenbroek 		(*expr) -> op = expr_client_state;
3959*83ee113eSDavid van Moolenbroek 		break;
3960*83ee113eSDavid van Moolenbroek 
3961*83ee113eSDavid van Moolenbroek 	      case FILENAME:
3962*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
3963*83ee113eSDavid van Moolenbroek 		if (!expression_allocate (expr, MDL))
3964*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate expression");
3965*83ee113eSDavid van Moolenbroek 		(*expr) -> op = expr_filename;
3966*83ee113eSDavid van Moolenbroek 		break;
3967*83ee113eSDavid van Moolenbroek 
3968*83ee113eSDavid van Moolenbroek 	      case SERVER_NAME:
3969*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
3970*83ee113eSDavid van Moolenbroek 		if (!expression_allocate (expr, MDL))
3971*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate expression");
3972*83ee113eSDavid van Moolenbroek 		(*expr) -> op = expr_sname;
3973*83ee113eSDavid van Moolenbroek 		break;
3974*83ee113eSDavid van Moolenbroek 
3975*83ee113eSDavid van Moolenbroek 	      case LEASE_TIME:
3976*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
3977*83ee113eSDavid van Moolenbroek 		if (!expression_allocate (expr, MDL))
3978*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate expression");
3979*83ee113eSDavid van Moolenbroek 		(*expr) -> op = expr_lease_time;
3980*83ee113eSDavid van Moolenbroek 		break;
3981*83ee113eSDavid van Moolenbroek 
3982*83ee113eSDavid van Moolenbroek 	      case TOKEN_NULL:
3983*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
3984*83ee113eSDavid van Moolenbroek 		if (!expression_allocate (expr, MDL))
3985*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate expression");
3986*83ee113eSDavid van Moolenbroek 		(*expr) -> op = expr_null;
3987*83ee113eSDavid van Moolenbroek 		break;
3988*83ee113eSDavid van Moolenbroek 
3989*83ee113eSDavid van Moolenbroek 	      case HOST_DECL_NAME:
3990*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
3991*83ee113eSDavid van Moolenbroek 		if (!expression_allocate (expr, MDL))
3992*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate expression");
3993*83ee113eSDavid van Moolenbroek 		(*expr) -> op = expr_host_decl_name;
3994*83ee113eSDavid van Moolenbroek 		break;
3995*83ee113eSDavid van Moolenbroek 
3996*83ee113eSDavid van Moolenbroek 	      case PACKET:
3997*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
3998*83ee113eSDavid van Moolenbroek 		if (!expression_allocate (expr, MDL))
3999*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate expression");
4000*83ee113eSDavid van Moolenbroek 		(*expr) -> op = expr_packet;
4001*83ee113eSDavid van Moolenbroek 
4002*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
4003*83ee113eSDavid van Moolenbroek 		if (token != LPAREN)
4004*83ee113eSDavid van Moolenbroek 			goto nolparen;
4005*83ee113eSDavid van Moolenbroek 
4006*83ee113eSDavid van Moolenbroek 		if (!parse_numeric_expression (&(*expr) -> data.packet.offset,
4007*83ee113eSDavid van Moolenbroek 					       cfile, lose))
4008*83ee113eSDavid van Moolenbroek 			goto nonum;
4009*83ee113eSDavid van Moolenbroek 
4010*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
4011*83ee113eSDavid van Moolenbroek 		if (token != COMMA)
4012*83ee113eSDavid van Moolenbroek 			goto nocomma;
4013*83ee113eSDavid van Moolenbroek 
4014*83ee113eSDavid van Moolenbroek 		if (!parse_numeric_expression (&(*expr) -> data.packet.len,
4015*83ee113eSDavid van Moolenbroek 					       cfile, lose))
4016*83ee113eSDavid van Moolenbroek 			goto nonum;
4017*83ee113eSDavid van Moolenbroek 
4018*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
4019*83ee113eSDavid van Moolenbroek 		if (token != RPAREN)
4020*83ee113eSDavid van Moolenbroek 			goto norparen;
4021*83ee113eSDavid van Moolenbroek 		break;
4022*83ee113eSDavid van Moolenbroek 
4023*83ee113eSDavid van Moolenbroek 	      case STRING:
4024*83ee113eSDavid van Moolenbroek 		skip_token(&val, &len, cfile);
4025*83ee113eSDavid van Moolenbroek 		if (!make_const_data (expr, (const unsigned char *)val,
4026*83ee113eSDavid van Moolenbroek 				      len, 1, 1, MDL))
4027*83ee113eSDavid van Moolenbroek 			log_fatal ("can't make constant string expression.");
4028*83ee113eSDavid van Moolenbroek 		break;
4029*83ee113eSDavid van Moolenbroek 
4030*83ee113eSDavid van Moolenbroek 	      case EXTRACT_INT:
4031*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
4032*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
4033*83ee113eSDavid van Moolenbroek 		if (token != LPAREN) {
4034*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "left parenthesis expected.");
4035*83ee113eSDavid van Moolenbroek 			*lose = 1;
4036*83ee113eSDavid van Moolenbroek 			return 0;
4037*83ee113eSDavid van Moolenbroek 		}
4038*83ee113eSDavid van Moolenbroek 
4039*83ee113eSDavid van Moolenbroek 		if (!expression_allocate (expr, MDL))
4040*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate expression");
4041*83ee113eSDavid van Moolenbroek 
4042*83ee113eSDavid van Moolenbroek 		if (!parse_data_expression (&(*expr) -> data.extract_int,
4043*83ee113eSDavid van Moolenbroek 					    cfile, lose)) {
4044*83ee113eSDavid van Moolenbroek 			if (!*lose) {
4045*83ee113eSDavid van Moolenbroek 				parse_warn (cfile,
4046*83ee113eSDavid van Moolenbroek 					    "expecting data expression.");
4047*83ee113eSDavid van Moolenbroek 				skip_to_semi (cfile);
4048*83ee113eSDavid van Moolenbroek 				*lose = 1;
4049*83ee113eSDavid van Moolenbroek 			}
4050*83ee113eSDavid van Moolenbroek 			expression_dereference (expr, MDL);
4051*83ee113eSDavid van Moolenbroek 			return 0;
4052*83ee113eSDavid van Moolenbroek 		}
4053*83ee113eSDavid van Moolenbroek 
4054*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
4055*83ee113eSDavid van Moolenbroek 		if (token != COMMA) {
4056*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "comma expected.");
4057*83ee113eSDavid van Moolenbroek 			*lose = 1;
4058*83ee113eSDavid van Moolenbroek 			expression_dereference (expr, MDL);
4059*83ee113eSDavid van Moolenbroek 			return 0;
4060*83ee113eSDavid van Moolenbroek 		}
4061*83ee113eSDavid van Moolenbroek 
4062*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
4063*83ee113eSDavid van Moolenbroek 		if (token != NUMBER) {
4064*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "number expected.");
4065*83ee113eSDavid van Moolenbroek 			*lose = 1;
4066*83ee113eSDavid van Moolenbroek 			expression_dereference (expr, MDL);
4067*83ee113eSDavid van Moolenbroek 			return 0;
4068*83ee113eSDavid van Moolenbroek 		}
4069*83ee113eSDavid van Moolenbroek 		switch (atoi (val)) {
4070*83ee113eSDavid van Moolenbroek 		      case 8:
4071*83ee113eSDavid van Moolenbroek 			(*expr) -> op = expr_extract_int8;
4072*83ee113eSDavid van Moolenbroek 			break;
4073*83ee113eSDavid van Moolenbroek 
4074*83ee113eSDavid van Moolenbroek 		      case 16:
4075*83ee113eSDavid van Moolenbroek 			(*expr) -> op = expr_extract_int16;
4076*83ee113eSDavid van Moolenbroek 			break;
4077*83ee113eSDavid van Moolenbroek 
4078*83ee113eSDavid van Moolenbroek 		      case 32:
4079*83ee113eSDavid van Moolenbroek 			(*expr) -> op = expr_extract_int32;
4080*83ee113eSDavid van Moolenbroek 			break;
4081*83ee113eSDavid van Moolenbroek 
4082*83ee113eSDavid van Moolenbroek 		      default:
4083*83ee113eSDavid van Moolenbroek 			parse_warn (cfile,
4084*83ee113eSDavid van Moolenbroek 				    "unsupported integer size %d", atoi (val));
4085*83ee113eSDavid van Moolenbroek 			*lose = 1;
4086*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
4087*83ee113eSDavid van Moolenbroek 			expression_dereference (expr, MDL);
4088*83ee113eSDavid van Moolenbroek 			return 0;
4089*83ee113eSDavid van Moolenbroek 		}
4090*83ee113eSDavid van Moolenbroek 
4091*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
4092*83ee113eSDavid van Moolenbroek 		if (token != RPAREN) {
4093*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "right parenthesis expected.");
4094*83ee113eSDavid van Moolenbroek 			*lose = 1;
4095*83ee113eSDavid van Moolenbroek 			expression_dereference (expr, MDL);
4096*83ee113eSDavid van Moolenbroek 			return 0;
4097*83ee113eSDavid van Moolenbroek 		}
4098*83ee113eSDavid van Moolenbroek 		break;
4099*83ee113eSDavid van Moolenbroek 
4100*83ee113eSDavid van Moolenbroek 	      case ENCODE_INT:
4101*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
4102*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
4103*83ee113eSDavid van Moolenbroek 		if (token != LPAREN) {
4104*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "left parenthesis expected.");
4105*83ee113eSDavid van Moolenbroek 			*lose = 1;
4106*83ee113eSDavid van Moolenbroek 			return 0;
4107*83ee113eSDavid van Moolenbroek 		}
4108*83ee113eSDavid van Moolenbroek 
4109*83ee113eSDavid van Moolenbroek 		if (!expression_allocate (expr, MDL))
4110*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate expression");
4111*83ee113eSDavid van Moolenbroek 
4112*83ee113eSDavid van Moolenbroek 		if (!parse_numeric_expression (&(*expr) -> data.encode_int,
4113*83ee113eSDavid van Moolenbroek 					       cfile, lose)) {
4114*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "expecting numeric expression.");
4115*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
4116*83ee113eSDavid van Moolenbroek 			*lose = 1;
4117*83ee113eSDavid van Moolenbroek 			expression_dereference (expr, MDL);
4118*83ee113eSDavid van Moolenbroek 			return 0;
4119*83ee113eSDavid van Moolenbroek 		}
4120*83ee113eSDavid van Moolenbroek 
4121*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
4122*83ee113eSDavid van Moolenbroek 		if (token != COMMA) {
4123*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "comma expected.");
4124*83ee113eSDavid van Moolenbroek 			*lose = 1;
4125*83ee113eSDavid van Moolenbroek 			expression_dereference (expr, MDL);
4126*83ee113eSDavid van Moolenbroek 			return 0;
4127*83ee113eSDavid van Moolenbroek 		}
4128*83ee113eSDavid van Moolenbroek 
4129*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
4130*83ee113eSDavid van Moolenbroek 		if (token != NUMBER) {
4131*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "number expected.");
4132*83ee113eSDavid van Moolenbroek 			*lose = 1;
4133*83ee113eSDavid van Moolenbroek 			expression_dereference (expr, MDL);
4134*83ee113eSDavid van Moolenbroek 			return 0;
4135*83ee113eSDavid van Moolenbroek 		}
4136*83ee113eSDavid van Moolenbroek 		switch (atoi (val)) {
4137*83ee113eSDavid van Moolenbroek 		      case 8:
4138*83ee113eSDavid van Moolenbroek 			(*expr) -> op = expr_encode_int8;
4139*83ee113eSDavid van Moolenbroek 			break;
4140*83ee113eSDavid van Moolenbroek 
4141*83ee113eSDavid van Moolenbroek 		      case 16:
4142*83ee113eSDavid van Moolenbroek 			(*expr) -> op = expr_encode_int16;
4143*83ee113eSDavid van Moolenbroek 			break;
4144*83ee113eSDavid van Moolenbroek 
4145*83ee113eSDavid van Moolenbroek 		      case 32:
4146*83ee113eSDavid van Moolenbroek 			(*expr) -> op = expr_encode_int32;
4147*83ee113eSDavid van Moolenbroek 			break;
4148*83ee113eSDavid van Moolenbroek 
4149*83ee113eSDavid van Moolenbroek 		      default:
4150*83ee113eSDavid van Moolenbroek 			parse_warn (cfile,
4151*83ee113eSDavid van Moolenbroek 				    "unsupported integer size %d", atoi (val));
4152*83ee113eSDavid van Moolenbroek 			*lose = 1;
4153*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
4154*83ee113eSDavid van Moolenbroek 			expression_dereference (expr, MDL);
4155*83ee113eSDavid van Moolenbroek 			return 0;
4156*83ee113eSDavid van Moolenbroek 		}
4157*83ee113eSDavid van Moolenbroek 
4158*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
4159*83ee113eSDavid van Moolenbroek 		if (token != RPAREN) {
4160*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "right parenthesis expected.");
4161*83ee113eSDavid van Moolenbroek 			*lose = 1;
4162*83ee113eSDavid van Moolenbroek 			expression_dereference (expr, MDL);
4163*83ee113eSDavid van Moolenbroek 			return 0;
4164*83ee113eSDavid van Moolenbroek 		}
4165*83ee113eSDavid van Moolenbroek 		break;
4166*83ee113eSDavid van Moolenbroek 
4167*83ee113eSDavid van Moolenbroek 	      case NUMBER:
4168*83ee113eSDavid van Moolenbroek 		/* If we're in a numeric context, this should just be a
4169*83ee113eSDavid van Moolenbroek 		   number, by itself. */
4170*83ee113eSDavid van Moolenbroek 		if (context == context_numeric ||
4171*83ee113eSDavid van Moolenbroek 		    context == context_data_or_numeric) {
4172*83ee113eSDavid van Moolenbroek 			skip_token(&val, (unsigned *)0, cfile);
4173*83ee113eSDavid van Moolenbroek 			if (!expression_allocate (expr, MDL))
4174*83ee113eSDavid van Moolenbroek 				log_fatal ("can't allocate expression");
4175*83ee113eSDavid van Moolenbroek 			(*expr) -> op = expr_const_int;
4176*83ee113eSDavid van Moolenbroek 			(*expr) -> data.const_int = atoi (val);
4177*83ee113eSDavid van Moolenbroek 			break;
4178*83ee113eSDavid van Moolenbroek 		}
4179*83ee113eSDavid van Moolenbroek 
4180*83ee113eSDavid van Moolenbroek 	      case NUMBER_OR_NAME:
4181*83ee113eSDavid van Moolenbroek 		if (!expression_allocate (expr, MDL))
4182*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate expression");
4183*83ee113eSDavid van Moolenbroek 
4184*83ee113eSDavid van Moolenbroek 		(*expr) -> op = expr_const_data;
4185*83ee113eSDavid van Moolenbroek 		if (!parse_cshl (&(*expr) -> data.const_data, cfile)) {
4186*83ee113eSDavid van Moolenbroek 			expression_dereference (expr, MDL);
4187*83ee113eSDavid van Moolenbroek 			return 0;
4188*83ee113eSDavid van Moolenbroek 		}
4189*83ee113eSDavid van Moolenbroek 		break;
4190*83ee113eSDavid van Moolenbroek 
4191*83ee113eSDavid van Moolenbroek 	      case NS_FORMERR:
4192*83ee113eSDavid van Moolenbroek 		known = FORMERR;
4193*83ee113eSDavid van Moolenbroek 		goto ns_const;
4194*83ee113eSDavid van Moolenbroek 	      ns_const:
4195*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
4196*83ee113eSDavid van Moolenbroek 		if (!expression_allocate (expr, MDL))
4197*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate expression");
4198*83ee113eSDavid van Moolenbroek 		(*expr) -> op = expr_const_int;
4199*83ee113eSDavid van Moolenbroek 		(*expr) -> data.const_int = known;
4200*83ee113eSDavid van Moolenbroek 		break;
4201*83ee113eSDavid van Moolenbroek 
4202*83ee113eSDavid van Moolenbroek 	      case NS_NOERROR:
4203*83ee113eSDavid van Moolenbroek 		known = ISC_R_SUCCESS;
4204*83ee113eSDavid van Moolenbroek 		goto ns_const;
4205*83ee113eSDavid van Moolenbroek 
4206*83ee113eSDavid van Moolenbroek 	      case NS_NOTAUTH:
4207*83ee113eSDavid van Moolenbroek 		known = DHCP_R_NOTAUTH;
4208*83ee113eSDavid van Moolenbroek 		goto ns_const;
4209*83ee113eSDavid van Moolenbroek 
4210*83ee113eSDavid van Moolenbroek 	      case NS_NOTIMP:
4211*83ee113eSDavid van Moolenbroek 		known = ISC_R_NOTIMPLEMENTED;
4212*83ee113eSDavid van Moolenbroek 		goto ns_const;
4213*83ee113eSDavid van Moolenbroek 
4214*83ee113eSDavid van Moolenbroek 	      case NS_NOTZONE:
4215*83ee113eSDavid van Moolenbroek 		known = DHCP_R_NOTZONE;
4216*83ee113eSDavid van Moolenbroek 		goto ns_const;
4217*83ee113eSDavid van Moolenbroek 
4218*83ee113eSDavid van Moolenbroek 	      case NS_NXDOMAIN:
4219*83ee113eSDavid van Moolenbroek 		known = DHCP_R_NXDOMAIN;
4220*83ee113eSDavid van Moolenbroek 		goto ns_const;
4221*83ee113eSDavid van Moolenbroek 
4222*83ee113eSDavid van Moolenbroek 	      case NS_NXRRSET:
4223*83ee113eSDavid van Moolenbroek 		known = DHCP_R_NXRRSET;
4224*83ee113eSDavid van Moolenbroek 		goto ns_const;
4225*83ee113eSDavid van Moolenbroek 
4226*83ee113eSDavid van Moolenbroek 	      case NS_REFUSED:
4227*83ee113eSDavid van Moolenbroek 		known = DHCP_R_REFUSED;
4228*83ee113eSDavid van Moolenbroek 		goto ns_const;
4229*83ee113eSDavid van Moolenbroek 
4230*83ee113eSDavid van Moolenbroek 	      case NS_SERVFAIL:
4231*83ee113eSDavid van Moolenbroek 		known = DHCP_R_SERVFAIL;
4232*83ee113eSDavid van Moolenbroek 		goto ns_const;
4233*83ee113eSDavid van Moolenbroek 
4234*83ee113eSDavid van Moolenbroek 	      case NS_YXDOMAIN:
4235*83ee113eSDavid van Moolenbroek 		known = DHCP_R_YXDOMAIN;
4236*83ee113eSDavid van Moolenbroek 		goto ns_const;
4237*83ee113eSDavid van Moolenbroek 
4238*83ee113eSDavid van Moolenbroek 	      case NS_YXRRSET:
4239*83ee113eSDavid van Moolenbroek 		known = DHCP_R_YXRRSET;
4240*83ee113eSDavid van Moolenbroek 		goto ns_const;
4241*83ee113eSDavid van Moolenbroek 
4242*83ee113eSDavid van Moolenbroek 	      case BOOTING:
4243*83ee113eSDavid van Moolenbroek 		known = S_INIT;
4244*83ee113eSDavid van Moolenbroek 		goto ns_const;
4245*83ee113eSDavid van Moolenbroek 
4246*83ee113eSDavid van Moolenbroek 	      case REBOOT:
4247*83ee113eSDavid van Moolenbroek 		known = S_REBOOTING;
4248*83ee113eSDavid van Moolenbroek 		goto ns_const;
4249*83ee113eSDavid van Moolenbroek 
4250*83ee113eSDavid van Moolenbroek 	      case SELECT:
4251*83ee113eSDavid van Moolenbroek 		known = S_SELECTING;
4252*83ee113eSDavid van Moolenbroek 		goto ns_const;
4253*83ee113eSDavid van Moolenbroek 
4254*83ee113eSDavid van Moolenbroek 	      case REQUEST:
4255*83ee113eSDavid van Moolenbroek 		known = S_REQUESTING;
4256*83ee113eSDavid van Moolenbroek 		goto ns_const;
4257*83ee113eSDavid van Moolenbroek 
4258*83ee113eSDavid van Moolenbroek 	      case BOUND:
4259*83ee113eSDavid van Moolenbroek 		known = S_BOUND;
4260*83ee113eSDavid van Moolenbroek 		goto ns_const;
4261*83ee113eSDavid van Moolenbroek 
4262*83ee113eSDavid van Moolenbroek 	      case RENEW:
4263*83ee113eSDavid van Moolenbroek 		known = S_RENEWING;
4264*83ee113eSDavid van Moolenbroek 		goto ns_const;
4265*83ee113eSDavid van Moolenbroek 
4266*83ee113eSDavid van Moolenbroek 	      case REBIND:
4267*83ee113eSDavid van Moolenbroek 		known = S_REBINDING;
4268*83ee113eSDavid van Moolenbroek 		goto ns_const;
4269*83ee113eSDavid van Moolenbroek 
4270*83ee113eSDavid van Moolenbroek 	      case DEFINED:
4271*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
4272*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
4273*83ee113eSDavid van Moolenbroek 		if (token != LPAREN)
4274*83ee113eSDavid van Moolenbroek 			goto nolparen;
4275*83ee113eSDavid van Moolenbroek 
4276*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
4277*83ee113eSDavid van Moolenbroek 		if (token != NAME && token != NUMBER_OR_NAME) {
4278*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "%s can't be a variable name", val);
4279*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
4280*83ee113eSDavid van Moolenbroek 			*lose = 1;
4281*83ee113eSDavid van Moolenbroek 			return 0;
4282*83ee113eSDavid van Moolenbroek 		}
4283*83ee113eSDavid van Moolenbroek 
4284*83ee113eSDavid van Moolenbroek 		if (!expression_allocate (expr, MDL))
4285*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate expression");
4286*83ee113eSDavid van Moolenbroek 		(*expr) -> op = expr_variable_exists;
4287*83ee113eSDavid van Moolenbroek 		(*expr) -> data.variable = dmalloc (strlen (val) + 1, MDL);
4288*83ee113eSDavid van Moolenbroek 		if (!(*expr)->data.variable)
4289*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate variable name");
4290*83ee113eSDavid van Moolenbroek 		strcpy ((*expr) -> data.variable, val);
4291*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
4292*83ee113eSDavid van Moolenbroek 		if (token != RPAREN)
4293*83ee113eSDavid van Moolenbroek 			goto norparen;
4294*83ee113eSDavid van Moolenbroek 		break;
4295*83ee113eSDavid van Moolenbroek 
4296*83ee113eSDavid van Moolenbroek 		/* This parses 'gethostname()'. */
4297*83ee113eSDavid van Moolenbroek 	      case GETHOSTNAME:
4298*83ee113eSDavid van Moolenbroek 		skip_token(&val, NULL, cfile);
4299*83ee113eSDavid van Moolenbroek 		if (!expression_allocate(expr, MDL))
4300*83ee113eSDavid van Moolenbroek 			log_fatal("can't allocate expression");
4301*83ee113eSDavid van Moolenbroek 		(*expr)->op = expr_gethostname;
4302*83ee113eSDavid van Moolenbroek 
4303*83ee113eSDavid van Moolenbroek 		token = next_token(NULL, NULL, cfile);
4304*83ee113eSDavid van Moolenbroek 		if (token != LPAREN)
4305*83ee113eSDavid van Moolenbroek 			goto nolparen;
4306*83ee113eSDavid van Moolenbroek 
4307*83ee113eSDavid van Moolenbroek 		token = next_token(NULL, NULL, cfile);
4308*83ee113eSDavid van Moolenbroek 		if (token != RPAREN)
4309*83ee113eSDavid van Moolenbroek 			goto norparen;
4310*83ee113eSDavid van Moolenbroek 		break;
4311*83ee113eSDavid van Moolenbroek 
4312*83ee113eSDavid van Moolenbroek 	      case GETHOSTBYNAME:
4313*83ee113eSDavid van Moolenbroek 		skip_token(&val, NULL, cfile);
4314*83ee113eSDavid van Moolenbroek 		token = next_token(NULL, NULL, cfile);
4315*83ee113eSDavid van Moolenbroek 		if (token != LPAREN)
4316*83ee113eSDavid van Moolenbroek 			goto nolparen;
4317*83ee113eSDavid van Moolenbroek 
4318*83ee113eSDavid van Moolenbroek 		/* The argument is a quoted string. */
4319*83ee113eSDavid van Moolenbroek 		token = next_token(&val, NULL, cfile);
4320*83ee113eSDavid van Moolenbroek 		if (token != STRING) {
4321*83ee113eSDavid van Moolenbroek 			parse_warn(cfile, "Expecting quoted literal: "
4322*83ee113eSDavid van Moolenbroek 					  "\"foo.example.com\"");
4323*83ee113eSDavid van Moolenbroek 			skip_to_semi(cfile);
4324*83ee113eSDavid van Moolenbroek 			*lose = 1;
4325*83ee113eSDavid van Moolenbroek 			return 0;
4326*83ee113eSDavid van Moolenbroek 		}
4327*83ee113eSDavid van Moolenbroek 		if (!make_host_lookup(expr, val))
4328*83ee113eSDavid van Moolenbroek 			log_fatal("Error creating gethostbyname() internal "
4329*83ee113eSDavid van Moolenbroek 				  "record. (%s:%d)", MDL);
4330*83ee113eSDavid van Moolenbroek 
4331*83ee113eSDavid van Moolenbroek 		token = next_token(NULL, NULL, cfile);
4332*83ee113eSDavid van Moolenbroek 		if (token != RPAREN)
4333*83ee113eSDavid van Moolenbroek 			goto norparen;
4334*83ee113eSDavid van Moolenbroek 		break;
4335*83ee113eSDavid van Moolenbroek 
4336*83ee113eSDavid van Moolenbroek 	      case V6RELAY:
4337*83ee113eSDavid van Moolenbroek 		skip_token(&val, NULL, cfile);
4338*83ee113eSDavid van Moolenbroek 		if (!expression_allocate (expr, MDL))
4339*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate expression");
4340*83ee113eSDavid van Moolenbroek 		(*expr)->op = expr_v6relay;
4341*83ee113eSDavid van Moolenbroek 
4342*83ee113eSDavid van Moolenbroek 		token = next_token (&val, NULL, cfile);
4343*83ee113eSDavid van Moolenbroek 		if (token != LPAREN)
4344*83ee113eSDavid van Moolenbroek 			goto nolparen;
4345*83ee113eSDavid van Moolenbroek 
4346*83ee113eSDavid van Moolenbroek 		if (!parse_numeric_expression (&(*expr)->data.v6relay.relay,
4347*83ee113eSDavid van Moolenbroek 						cfile, lose))
4348*83ee113eSDavid van Moolenbroek 			goto nodata;
4349*83ee113eSDavid van Moolenbroek 
4350*83ee113eSDavid van Moolenbroek 		token = next_token (&val, NULL, cfile);
4351*83ee113eSDavid van Moolenbroek 		if (token != COMMA)
4352*83ee113eSDavid van Moolenbroek 			goto nocomma;
4353*83ee113eSDavid van Moolenbroek 
4354*83ee113eSDavid van Moolenbroek 		if (!parse_data_expression (&(*expr)->data.v6relay.roption,
4355*83ee113eSDavid van Moolenbroek 					    cfile, lose))
4356*83ee113eSDavid van Moolenbroek 			goto nodata;
4357*83ee113eSDavid van Moolenbroek 
4358*83ee113eSDavid van Moolenbroek 		token = next_token (&val, NULL, cfile);
4359*83ee113eSDavid van Moolenbroek 
4360*83ee113eSDavid van Moolenbroek 		if (token != RPAREN)
4361*83ee113eSDavid van Moolenbroek 			goto norparen;
4362*83ee113eSDavid van Moolenbroek 		break;
4363*83ee113eSDavid van Moolenbroek 
4364*83ee113eSDavid van Moolenbroek 		/* Not a valid start to an expression... */
4365*83ee113eSDavid van Moolenbroek 	      default:
4366*83ee113eSDavid van Moolenbroek 		if (token != NAME && token != NUMBER_OR_NAME)
4367*83ee113eSDavid van Moolenbroek 			return 0;
4368*83ee113eSDavid van Moolenbroek 
4369*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
4370*83ee113eSDavid van Moolenbroek 
4371*83ee113eSDavid van Moolenbroek 		/* Save the name of the variable being referenced. */
4372*83ee113eSDavid van Moolenbroek 		cptr = dmalloc (strlen (val) + 1, MDL);
4373*83ee113eSDavid van Moolenbroek 		if (!cptr)
4374*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate variable name");
4375*83ee113eSDavid van Moolenbroek 		strcpy (cptr, val);
4376*83ee113eSDavid van Moolenbroek 
4377*83ee113eSDavid van Moolenbroek 		/* Simple variable reference, as far as we can tell. */
4378*83ee113eSDavid van Moolenbroek 		token = peek_token (&val, (unsigned *)0, cfile);
4379*83ee113eSDavid van Moolenbroek 		if (token != LPAREN) {
4380*83ee113eSDavid van Moolenbroek 			if (!expression_allocate (expr, MDL))
4381*83ee113eSDavid van Moolenbroek 				log_fatal ("can't allocate expression");
4382*83ee113eSDavid van Moolenbroek 			(*expr) -> op = expr_variable_reference;
4383*83ee113eSDavid van Moolenbroek 			(*expr) -> data.variable = cptr;
4384*83ee113eSDavid van Moolenbroek 			break;
4385*83ee113eSDavid van Moolenbroek 		}
4386*83ee113eSDavid van Moolenbroek 
4387*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
4388*83ee113eSDavid van Moolenbroek 		if (!expression_allocate (expr, MDL))
4389*83ee113eSDavid van Moolenbroek 			log_fatal ("can't allocate expression");
4390*83ee113eSDavid van Moolenbroek 		(*expr) -> op = expr_funcall;
4391*83ee113eSDavid van Moolenbroek 		(*expr) -> data.funcall.name = cptr;
4392*83ee113eSDavid van Moolenbroek 
4393*83ee113eSDavid van Moolenbroek 		/* Now parse the argument list. */
4394*83ee113eSDavid van Moolenbroek 		ep = &(*expr) -> data.funcall.arglist;
4395*83ee113eSDavid van Moolenbroek 		do {
4396*83ee113eSDavid van Moolenbroek 			if (!expression_allocate (ep, MDL))
4397*83ee113eSDavid van Moolenbroek 				log_fatal ("can't allocate expression");
4398*83ee113eSDavid van Moolenbroek 			(*ep) -> op = expr_arg;
4399*83ee113eSDavid van Moolenbroek 			if (!parse_expression (&(*ep) -> data.arg.val,
4400*83ee113eSDavid van Moolenbroek 					       cfile, lose, context_any,
4401*83ee113eSDavid van Moolenbroek 					       (struct expression **)0,
4402*83ee113eSDavid van Moolenbroek 					       expr_none)) {
4403*83ee113eSDavid van Moolenbroek 				if (!*lose) {
4404*83ee113eSDavid van Moolenbroek 					parse_warn (cfile,
4405*83ee113eSDavid van Moolenbroek 						    "expecting expression.");
4406*83ee113eSDavid van Moolenbroek 					*lose = 1;
4407*83ee113eSDavid van Moolenbroek 				}
4408*83ee113eSDavid van Moolenbroek 				skip_to_semi (cfile);
4409*83ee113eSDavid van Moolenbroek 				expression_dereference (expr, MDL);
4410*83ee113eSDavid van Moolenbroek 				return 0;
4411*83ee113eSDavid van Moolenbroek 			}
4412*83ee113eSDavid van Moolenbroek 			ep = &((*ep) -> data.arg.next);
4413*83ee113eSDavid van Moolenbroek 			token = next_token (&val, (unsigned *)0, cfile);
4414*83ee113eSDavid van Moolenbroek 		} while (token == COMMA);
4415*83ee113eSDavid van Moolenbroek 		if (token != RPAREN) {
4416*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "Right parenthesis expected.");
4417*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
4418*83ee113eSDavid van Moolenbroek 			*lose = 1;
4419*83ee113eSDavid van Moolenbroek 			expression_dereference (expr, MDL);
4420*83ee113eSDavid van Moolenbroek 			return 0;
4421*83ee113eSDavid van Moolenbroek 		}
4422*83ee113eSDavid van Moolenbroek 		break;
4423*83ee113eSDavid van Moolenbroek 	}
4424*83ee113eSDavid van Moolenbroek 	return 1;
4425*83ee113eSDavid van Moolenbroek }
4426*83ee113eSDavid van Moolenbroek 
4427*83ee113eSDavid van Moolenbroek /* Parse an expression. */
4428*83ee113eSDavid van Moolenbroek 
parse_expression(expr,cfile,lose,context,plhs,binop)4429*83ee113eSDavid van Moolenbroek int parse_expression (expr, cfile, lose, context, plhs, binop)
4430*83ee113eSDavid van Moolenbroek 	struct expression **expr;
4431*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
4432*83ee113eSDavid van Moolenbroek 	int *lose;
4433*83ee113eSDavid van Moolenbroek 	enum expression_context context;
4434*83ee113eSDavid van Moolenbroek 	struct expression **plhs;
4435*83ee113eSDavid van Moolenbroek 	enum expr_op binop;
4436*83ee113eSDavid van Moolenbroek {
4437*83ee113eSDavid van Moolenbroek 	enum dhcp_token token;
4438*83ee113eSDavid van Moolenbroek 	const char *val;
4439*83ee113eSDavid van Moolenbroek 	struct expression *rhs = (struct expression *)0, *tmp;
4440*83ee113eSDavid van Moolenbroek 	struct expression *lhs = (struct expression *)0;
4441*83ee113eSDavid van Moolenbroek 	enum expr_op next_op;
4442*83ee113eSDavid van Moolenbroek 	enum expression_context
4443*83ee113eSDavid van Moolenbroek 		lhs_context = context_any,
4444*83ee113eSDavid van Moolenbroek 		rhs_context = context_any;
4445*83ee113eSDavid van Moolenbroek 
4446*83ee113eSDavid van Moolenbroek 	/* Consume the left hand side we were passed. */
4447*83ee113eSDavid van Moolenbroek 	if (plhs) {
4448*83ee113eSDavid van Moolenbroek 		expression_reference (&lhs, *plhs, MDL);
4449*83ee113eSDavid van Moolenbroek 		expression_dereference (plhs, MDL);
4450*83ee113eSDavid van Moolenbroek 	}
4451*83ee113eSDavid van Moolenbroek 
4452*83ee113eSDavid van Moolenbroek       new_rhs:
4453*83ee113eSDavid van Moolenbroek 	if (!parse_non_binary (&rhs, cfile, lose, context)) {
4454*83ee113eSDavid van Moolenbroek 		/* If we already have a left-hand side, then it's not
4455*83ee113eSDavid van Moolenbroek 		   okay for there not to be a right-hand side here, so
4456*83ee113eSDavid van Moolenbroek 		   we need to flag it as an error. */
4457*83ee113eSDavid van Moolenbroek 		if (lhs) {
4458*83ee113eSDavid van Moolenbroek 			if (!*lose) {
4459*83ee113eSDavid van Moolenbroek 				parse_warn (cfile,
4460*83ee113eSDavid van Moolenbroek 					    "expecting right-hand side.");
4461*83ee113eSDavid van Moolenbroek 				*lose = 1;
4462*83ee113eSDavid van Moolenbroek 				skip_to_semi (cfile);
4463*83ee113eSDavid van Moolenbroek 			}
4464*83ee113eSDavid van Moolenbroek 			expression_dereference (&lhs, MDL);
4465*83ee113eSDavid van Moolenbroek 		}
4466*83ee113eSDavid van Moolenbroek 		return 0;
4467*83ee113eSDavid van Moolenbroek 	}
4468*83ee113eSDavid van Moolenbroek 
4469*83ee113eSDavid van Moolenbroek 	/* At this point, rhs contains either an entire subexpression,
4470*83ee113eSDavid van Moolenbroek 	   or at least a left-hand-side.   If we do not see a binary token
4471*83ee113eSDavid van Moolenbroek 	   as the next token, we're done with the expression. */
4472*83ee113eSDavid van Moolenbroek 
4473*83ee113eSDavid van Moolenbroek 	token = peek_token (&val, (unsigned *)0, cfile);
4474*83ee113eSDavid van Moolenbroek 	switch (token) {
4475*83ee113eSDavid van Moolenbroek 	      case BANG:
4476*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
4477*83ee113eSDavid van Moolenbroek 		token = peek_token (&val, (unsigned *)0, cfile);
4478*83ee113eSDavid van Moolenbroek 		if (token != EQUAL) {
4479*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "! in boolean context without =");
4480*83ee113eSDavid van Moolenbroek 			*lose = 1;
4481*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
4482*83ee113eSDavid van Moolenbroek 			if (lhs)
4483*83ee113eSDavid van Moolenbroek 				expression_dereference (&lhs, MDL);
4484*83ee113eSDavid van Moolenbroek 			return 0;
4485*83ee113eSDavid van Moolenbroek 		}
4486*83ee113eSDavid van Moolenbroek 		next_op = expr_not_equal;
4487*83ee113eSDavid van Moolenbroek 		context = expression_context (rhs);
4488*83ee113eSDavid van Moolenbroek 		break;
4489*83ee113eSDavid van Moolenbroek 
4490*83ee113eSDavid van Moolenbroek 	      case EQUAL:
4491*83ee113eSDavid van Moolenbroek 		next_op = expr_equal;
4492*83ee113eSDavid van Moolenbroek 		context = expression_context (rhs);
4493*83ee113eSDavid van Moolenbroek 		break;
4494*83ee113eSDavid van Moolenbroek 
4495*83ee113eSDavid van Moolenbroek 	      case TILDE:
4496*83ee113eSDavid van Moolenbroek #ifdef HAVE_REGEX_H
4497*83ee113eSDavid van Moolenbroek 		skip_token(&val, NULL, cfile);
4498*83ee113eSDavid van Moolenbroek 		token = peek_token(&val, NULL, cfile);
4499*83ee113eSDavid van Moolenbroek 
4500*83ee113eSDavid van Moolenbroek 		if (token == TILDE)
4501*83ee113eSDavid van Moolenbroek 			next_op = expr_iregex_match;
4502*83ee113eSDavid van Moolenbroek 		else if (token == EQUAL)
4503*83ee113eSDavid van Moolenbroek 			next_op = expr_regex_match;
4504*83ee113eSDavid van Moolenbroek 		else {
4505*83ee113eSDavid van Moolenbroek 			parse_warn(cfile, "expecting ~= or ~~ operator");
4506*83ee113eSDavid van Moolenbroek 			*lose = 1;
4507*83ee113eSDavid van Moolenbroek 			skip_to_semi(cfile);
4508*83ee113eSDavid van Moolenbroek 			if (lhs)
4509*83ee113eSDavid van Moolenbroek 				expression_dereference(&lhs, MDL);
4510*83ee113eSDavid van Moolenbroek 			return 0;
4511*83ee113eSDavid van Moolenbroek 		}
4512*83ee113eSDavid van Moolenbroek 
4513*83ee113eSDavid van Moolenbroek 		context = expression_context(rhs);
4514*83ee113eSDavid van Moolenbroek #else
4515*83ee113eSDavid van Moolenbroek 		parse_warn(cfile, "No support for regex operator.");
4516*83ee113eSDavid van Moolenbroek 		*lose = 1;
4517*83ee113eSDavid van Moolenbroek 		skip_to_semi(cfile);
4518*83ee113eSDavid van Moolenbroek 		if (lhs != NULL)
4519*83ee113eSDavid van Moolenbroek 			expression_dereference(&lhs, MDL);
4520*83ee113eSDavid van Moolenbroek 		return 0;
4521*83ee113eSDavid van Moolenbroek #endif
4522*83ee113eSDavid van Moolenbroek 		break;
4523*83ee113eSDavid van Moolenbroek 
4524*83ee113eSDavid van Moolenbroek 	      case AND:
4525*83ee113eSDavid van Moolenbroek 		next_op = expr_and;
4526*83ee113eSDavid van Moolenbroek 		context = expression_context (rhs);
4527*83ee113eSDavid van Moolenbroek 		break;
4528*83ee113eSDavid van Moolenbroek 
4529*83ee113eSDavid van Moolenbroek 	      case OR:
4530*83ee113eSDavid van Moolenbroek 		next_op = expr_or;
4531*83ee113eSDavid van Moolenbroek 		context = expression_context (rhs);
4532*83ee113eSDavid van Moolenbroek 		break;
4533*83ee113eSDavid van Moolenbroek 
4534*83ee113eSDavid van Moolenbroek 	      case PLUS:
4535*83ee113eSDavid van Moolenbroek 		next_op = expr_add;
4536*83ee113eSDavid van Moolenbroek 		context = expression_context (rhs);
4537*83ee113eSDavid van Moolenbroek 		break;
4538*83ee113eSDavid van Moolenbroek 
4539*83ee113eSDavid van Moolenbroek 	      case MINUS:
4540*83ee113eSDavid van Moolenbroek 		next_op = expr_subtract;
4541*83ee113eSDavid van Moolenbroek 		context = expression_context (rhs);
4542*83ee113eSDavid van Moolenbroek 		break;
4543*83ee113eSDavid van Moolenbroek 
4544*83ee113eSDavid van Moolenbroek 	      case SLASH:
4545*83ee113eSDavid van Moolenbroek 		next_op = expr_divide;
4546*83ee113eSDavid van Moolenbroek 		context = expression_context (rhs);
4547*83ee113eSDavid van Moolenbroek 		break;
4548*83ee113eSDavid van Moolenbroek 
4549*83ee113eSDavid van Moolenbroek 	      case ASTERISK:
4550*83ee113eSDavid van Moolenbroek 		next_op = expr_multiply;
4551*83ee113eSDavid van Moolenbroek 		context = expression_context (rhs);
4552*83ee113eSDavid van Moolenbroek 		break;
4553*83ee113eSDavid van Moolenbroek 
4554*83ee113eSDavid van Moolenbroek 	      case PERCENT:
4555*83ee113eSDavid van Moolenbroek 		next_op = expr_remainder;
4556*83ee113eSDavid van Moolenbroek 		context = expression_context (rhs);
4557*83ee113eSDavid van Moolenbroek 		break;
4558*83ee113eSDavid van Moolenbroek 
4559*83ee113eSDavid van Moolenbroek 	      case AMPERSAND:
4560*83ee113eSDavid van Moolenbroek 		next_op = expr_binary_and;
4561*83ee113eSDavid van Moolenbroek 		context = expression_context (rhs);
4562*83ee113eSDavid van Moolenbroek 		break;
4563*83ee113eSDavid van Moolenbroek 
4564*83ee113eSDavid van Moolenbroek 	      case PIPE:
4565*83ee113eSDavid van Moolenbroek 		next_op = expr_binary_or;
4566*83ee113eSDavid van Moolenbroek 		context = expression_context (rhs);
4567*83ee113eSDavid van Moolenbroek 		break;
4568*83ee113eSDavid van Moolenbroek 
4569*83ee113eSDavid van Moolenbroek 	      case CARET:
4570*83ee113eSDavid van Moolenbroek 		next_op = expr_binary_xor;
4571*83ee113eSDavid van Moolenbroek 		context = expression_context (rhs);
4572*83ee113eSDavid van Moolenbroek 		break;
4573*83ee113eSDavid van Moolenbroek 
4574*83ee113eSDavid van Moolenbroek 	      default:
4575*83ee113eSDavid van Moolenbroek 		next_op = expr_none;
4576*83ee113eSDavid van Moolenbroek 	}
4577*83ee113eSDavid van Moolenbroek 
4578*83ee113eSDavid van Moolenbroek 	/* If we have no lhs yet, we just parsed it. */
4579*83ee113eSDavid van Moolenbroek 	if (!lhs) {
4580*83ee113eSDavid van Moolenbroek 		/* If there was no operator following what we just parsed,
4581*83ee113eSDavid van Moolenbroek 		   then we're done - return it. */
4582*83ee113eSDavid van Moolenbroek 		if (next_op == expr_none) {
4583*83ee113eSDavid van Moolenbroek 			*expr = rhs;
4584*83ee113eSDavid van Moolenbroek 			return 1;
4585*83ee113eSDavid van Moolenbroek 		}
4586*83ee113eSDavid van Moolenbroek 		lhs = rhs;
4587*83ee113eSDavid van Moolenbroek 		rhs = (struct expression *)0;
4588*83ee113eSDavid van Moolenbroek 		binop = next_op;
4589*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
4590*83ee113eSDavid van Moolenbroek 		goto new_rhs;
4591*83ee113eSDavid van Moolenbroek 	}
4592*83ee113eSDavid van Moolenbroek 
4593*83ee113eSDavid van Moolenbroek 	/* If the next binary operator is of greater precedence than the
4594*83ee113eSDavid van Moolenbroek 	 * current operator, then rhs we have parsed so far is actually
4595*83ee113eSDavid van Moolenbroek 	 * the lhs of the next operator.  To get this value, we have to
4596*83ee113eSDavid van Moolenbroek 	 * recurse.
4597*83ee113eSDavid van Moolenbroek 	 */
4598*83ee113eSDavid van Moolenbroek 	if (binop != expr_none && next_op != expr_none &&
4599*83ee113eSDavid van Moolenbroek 	    op_precedence (binop, next_op) < 0) {
4600*83ee113eSDavid van Moolenbroek 
4601*83ee113eSDavid van Moolenbroek 		/* Eat the subexpression operator token, which we pass to
4602*83ee113eSDavid van Moolenbroek 		 * parse_expression...we only peek()'d earlier.
4603*83ee113eSDavid van Moolenbroek 		 */
4604*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
4605*83ee113eSDavid van Moolenbroek 
4606*83ee113eSDavid van Moolenbroek 		/* Continue parsing of the right hand side with that token. */
4607*83ee113eSDavid van Moolenbroek 		tmp = rhs;
4608*83ee113eSDavid van Moolenbroek 		rhs = (struct expression *)0;
4609*83ee113eSDavid van Moolenbroek 		if (!parse_expression (&rhs, cfile, lose, op_context (next_op),
4610*83ee113eSDavid van Moolenbroek 				       &tmp, next_op)) {
4611*83ee113eSDavid van Moolenbroek 			if (!*lose) {
4612*83ee113eSDavid van Moolenbroek 				parse_warn (cfile,
4613*83ee113eSDavid van Moolenbroek 					    "expecting a subexpression");
4614*83ee113eSDavid van Moolenbroek 				*lose = 1;
4615*83ee113eSDavid van Moolenbroek 			}
4616*83ee113eSDavid van Moolenbroek 			return 0;
4617*83ee113eSDavid van Moolenbroek 		}
4618*83ee113eSDavid van Moolenbroek 		next_op = expr_none;
4619*83ee113eSDavid van Moolenbroek 	}
4620*83ee113eSDavid van Moolenbroek 
4621*83ee113eSDavid van Moolenbroek 	if (binop != expr_none) {
4622*83ee113eSDavid van Moolenbroek 	  rhs_context = expression_context(rhs);
4623*83ee113eSDavid van Moolenbroek 	  lhs_context = expression_context(lhs);
4624*83ee113eSDavid van Moolenbroek 
4625*83ee113eSDavid van Moolenbroek 	  if ((rhs_context != context_any) && (lhs_context != context_any) &&
4626*83ee113eSDavid van Moolenbroek 			(rhs_context != lhs_context)) {
4627*83ee113eSDavid van Moolenbroek 	    parse_warn (cfile, "illegal expression relating different types");
4628*83ee113eSDavid van Moolenbroek 	    skip_to_semi (cfile);
4629*83ee113eSDavid van Moolenbroek 	    expression_dereference (&rhs, MDL);
4630*83ee113eSDavid van Moolenbroek 	    expression_dereference (&lhs, MDL);
4631*83ee113eSDavid van Moolenbroek 	    *lose = 1;
4632*83ee113eSDavid van Moolenbroek 	    return 0;
4633*83ee113eSDavid van Moolenbroek 	  }
4634*83ee113eSDavid van Moolenbroek 
4635*83ee113eSDavid van Moolenbroek 	  switch(binop) {
4636*83ee113eSDavid van Moolenbroek 	    case expr_not_equal:
4637*83ee113eSDavid van Moolenbroek 	    case expr_equal:
4638*83ee113eSDavid van Moolenbroek 		if ((rhs_context != context_data_or_numeric) &&
4639*83ee113eSDavid van Moolenbroek 		    (rhs_context != context_data) &&
4640*83ee113eSDavid van Moolenbroek 		    (rhs_context != context_numeric) &&
4641*83ee113eSDavid van Moolenbroek 		    (rhs_context != context_any)) {
4642*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "expecting data/numeric expression");
4643*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
4644*83ee113eSDavid van Moolenbroek 			expression_dereference (&rhs, MDL);
4645*83ee113eSDavid van Moolenbroek 			*lose = 1;
4646*83ee113eSDavid van Moolenbroek 			return 0;
4647*83ee113eSDavid van Moolenbroek 		}
4648*83ee113eSDavid van Moolenbroek 		break;
4649*83ee113eSDavid van Moolenbroek 
4650*83ee113eSDavid van Moolenbroek 	    case expr_regex_match:
4651*83ee113eSDavid van Moolenbroek #ifdef HAVE_REGEX_H
4652*83ee113eSDavid van Moolenbroek 		if (expression_context(rhs) != context_data) {
4653*83ee113eSDavid van Moolenbroek 			parse_warn(cfile, "expecting data expression");
4654*83ee113eSDavid van Moolenbroek 			skip_to_semi(cfile);
4655*83ee113eSDavid van Moolenbroek 			expression_dereference(&rhs, MDL);
4656*83ee113eSDavid van Moolenbroek 			*lose = 1;
4657*83ee113eSDavid van Moolenbroek 			return 0;
4658*83ee113eSDavid van Moolenbroek 		}
4659*83ee113eSDavid van Moolenbroek #else
4660*83ee113eSDavid van Moolenbroek 		/* It should not be possible to attempt to parse the right
4661*83ee113eSDavid van Moolenbroek 		 * hand side of an operator there is no support for.
4662*83ee113eSDavid van Moolenbroek 		 */
4663*83ee113eSDavid van Moolenbroek 		log_fatal("Impossible condition at %s:%d.", MDL);
4664*83ee113eSDavid van Moolenbroek #endif
4665*83ee113eSDavid van Moolenbroek 		break;
4666*83ee113eSDavid van Moolenbroek 
4667*83ee113eSDavid van Moolenbroek 	    case expr_and:
4668*83ee113eSDavid van Moolenbroek 	    case expr_or:
4669*83ee113eSDavid van Moolenbroek 		if ((rhs_context != context_boolean) &&
4670*83ee113eSDavid van Moolenbroek 		    (rhs_context != context_any)) {
4671*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "expecting boolean expressions");
4672*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
4673*83ee113eSDavid van Moolenbroek 			expression_dereference (&rhs, MDL);
4674*83ee113eSDavid van Moolenbroek 			*lose = 1;
4675*83ee113eSDavid van Moolenbroek 			return 0;
4676*83ee113eSDavid van Moolenbroek 		}
4677*83ee113eSDavid van Moolenbroek 		break;
4678*83ee113eSDavid van Moolenbroek 
4679*83ee113eSDavid van Moolenbroek 	    case expr_add:
4680*83ee113eSDavid van Moolenbroek 	    case expr_subtract:
4681*83ee113eSDavid van Moolenbroek 	    case expr_divide:
4682*83ee113eSDavid van Moolenbroek 	    case expr_multiply:
4683*83ee113eSDavid van Moolenbroek 	    case expr_remainder:
4684*83ee113eSDavid van Moolenbroek 	    case expr_binary_and:
4685*83ee113eSDavid van Moolenbroek 	    case expr_binary_or:
4686*83ee113eSDavid van Moolenbroek 	    case expr_binary_xor:
4687*83ee113eSDavid van Moolenbroek 		if ((rhs_context != context_numeric) &&
4688*83ee113eSDavid van Moolenbroek 		    (rhs_context != context_any)) {
4689*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "expecting numeric expressions");
4690*83ee113eSDavid van Moolenbroek                         skip_to_semi (cfile);
4691*83ee113eSDavid van Moolenbroek                         expression_dereference (&rhs, MDL);
4692*83ee113eSDavid van Moolenbroek                         *lose = 1;
4693*83ee113eSDavid van Moolenbroek                         return 0;
4694*83ee113eSDavid van Moolenbroek 		}
4695*83ee113eSDavid van Moolenbroek 		break;
4696*83ee113eSDavid van Moolenbroek 
4697*83ee113eSDavid van Moolenbroek 	    default:
4698*83ee113eSDavid van Moolenbroek 		break;
4699*83ee113eSDavid van Moolenbroek 	  }
4700*83ee113eSDavid van Moolenbroek 	}
4701*83ee113eSDavid van Moolenbroek 
4702*83ee113eSDavid van Moolenbroek 	/* Now, if we didn't find a binary operator, we're done parsing
4703*83ee113eSDavid van Moolenbroek 	   this subexpression, so combine it with the preceding binary
4704*83ee113eSDavid van Moolenbroek 	   operator and return the result. */
4705*83ee113eSDavid van Moolenbroek 	if (next_op == expr_none) {
4706*83ee113eSDavid van Moolenbroek 		if (!expression_allocate (expr, MDL))
4707*83ee113eSDavid van Moolenbroek 			log_fatal ("Can't allocate expression!");
4708*83ee113eSDavid van Moolenbroek 
4709*83ee113eSDavid van Moolenbroek 		(*expr) -> op = binop;
4710*83ee113eSDavid van Moolenbroek 		/* All the binary operators' data union members
4711*83ee113eSDavid van Moolenbroek 		   are the same, so we'll cheat and use the member
4712*83ee113eSDavid van Moolenbroek 		   for the equals operator. */
4713*83ee113eSDavid van Moolenbroek 		(*expr) -> data.equal [0] = lhs;
4714*83ee113eSDavid van Moolenbroek 		(*expr) -> data.equal [1] = rhs;
4715*83ee113eSDavid van Moolenbroek 		return 1;
4716*83ee113eSDavid van Moolenbroek 	}
4717*83ee113eSDavid van Moolenbroek 
4718*83ee113eSDavid van Moolenbroek 	/* Eat the operator token - we now know it was a binary operator... */
4719*83ee113eSDavid van Moolenbroek 	skip_token(&val, (unsigned *)0, cfile);
4720*83ee113eSDavid van Moolenbroek 
4721*83ee113eSDavid van Moolenbroek 	/* Now combine the LHS and the RHS using binop. */
4722*83ee113eSDavid van Moolenbroek 	tmp = (struct expression *)0;
4723*83ee113eSDavid van Moolenbroek 	if (!expression_allocate (&tmp, MDL))
4724*83ee113eSDavid van Moolenbroek 		log_fatal ("No memory for equal precedence combination.");
4725*83ee113eSDavid van Moolenbroek 
4726*83ee113eSDavid van Moolenbroek 	/* Store the LHS and RHS. */
4727*83ee113eSDavid van Moolenbroek 	tmp -> data.equal [0] = lhs;
4728*83ee113eSDavid van Moolenbroek 	tmp -> data.equal [1] = rhs;
4729*83ee113eSDavid van Moolenbroek 	tmp -> op = binop;
4730*83ee113eSDavid van Moolenbroek 
4731*83ee113eSDavid van Moolenbroek 	lhs = tmp;
4732*83ee113eSDavid van Moolenbroek 	tmp = (struct expression *)0;
4733*83ee113eSDavid van Moolenbroek 	rhs = (struct expression *)0;
4734*83ee113eSDavid van Moolenbroek 
4735*83ee113eSDavid van Moolenbroek 	/* Recursions don't return until we have parsed the end of the
4736*83ee113eSDavid van Moolenbroek 	   expression, so if we recursed earlier, we can now return what
4737*83ee113eSDavid van Moolenbroek 	   we got. */
4738*83ee113eSDavid van Moolenbroek 	if (next_op == expr_none) {
4739*83ee113eSDavid van Moolenbroek 		*expr = lhs;
4740*83ee113eSDavid van Moolenbroek 		return 1;
4741*83ee113eSDavid van Moolenbroek 	}
4742*83ee113eSDavid van Moolenbroek 
4743*83ee113eSDavid van Moolenbroek 	binop = next_op;
4744*83ee113eSDavid van Moolenbroek 	goto new_rhs;
4745*83ee113eSDavid van Moolenbroek }
4746*83ee113eSDavid van Moolenbroek 
4747*83ee113eSDavid van Moolenbroek 
parse_option_data(expr,cfile,lookups,option)4748*83ee113eSDavid van Moolenbroek int parse_option_data (expr, cfile, lookups, option)
4749*83ee113eSDavid van Moolenbroek struct expression **expr;
4750*83ee113eSDavid van Moolenbroek struct parse *cfile;
4751*83ee113eSDavid van Moolenbroek int lookups;
4752*83ee113eSDavid van Moolenbroek struct option *option;
4753*83ee113eSDavid van Moolenbroek {
4754*83ee113eSDavid van Moolenbroek 	const char *val;
4755*83ee113eSDavid van Moolenbroek 	const char *fmt = NULL;
4756*83ee113eSDavid van Moolenbroek 	struct expression *tmp;
4757*83ee113eSDavid van Moolenbroek 	enum dhcp_token token;
4758*83ee113eSDavid van Moolenbroek 
4759*83ee113eSDavid van Moolenbroek 	do {
4760*83ee113eSDavid van Moolenbroek 		/*
4761*83ee113eSDavid van Moolenbroek                  * Set a flag if this is an array of a simple type (i.e.,
4762*83ee113eSDavid van Moolenbroek                  * not an array of pairs of IP addresses, or something like
4763*83ee113eSDavid van Moolenbroek                  * that.
4764*83ee113eSDavid van Moolenbroek                  */
4765*83ee113eSDavid van Moolenbroek 		int uniform = 0;
4766*83ee113eSDavid van Moolenbroek 
4767*83ee113eSDavid van Moolenbroek 	      and_again:
4768*83ee113eSDavid van Moolenbroek 		/* Set fmt to start of format for 'A' and one char back
4769*83ee113eSDavid van Moolenbroek 		 * for 'a'.
4770*83ee113eSDavid van Moolenbroek 		 */
4771*83ee113eSDavid van Moolenbroek 		if ((fmt != NULL) && (fmt != option->format) && (*fmt == 'a'))
4772*83ee113eSDavid van Moolenbroek 			fmt -= 1;
4773*83ee113eSDavid van Moolenbroek 		else if ((fmt == NULL) || (*fmt == 'A'))
4774*83ee113eSDavid van Moolenbroek 			fmt = option->format;
4775*83ee113eSDavid van Moolenbroek 
4776*83ee113eSDavid van Moolenbroek 		/* 'a' means always uniform */
4777*83ee113eSDavid van Moolenbroek 		if ((fmt[0] != 'Z') && (tolower((unsigned char)fmt[1]) == 'a'))
4778*83ee113eSDavid van Moolenbroek 			uniform = 1;
4779*83ee113eSDavid van Moolenbroek 
4780*83ee113eSDavid van Moolenbroek 		do {
4781*83ee113eSDavid van Moolenbroek 			if ((*fmt == 'A') || (*fmt == 'a'))
4782*83ee113eSDavid van Moolenbroek 				break;
4783*83ee113eSDavid van Moolenbroek 			if (*fmt == 'o') {
4784*83ee113eSDavid van Moolenbroek 				/* consume the optional flag */
4785*83ee113eSDavid van Moolenbroek 				fmt++;
4786*83ee113eSDavid van Moolenbroek 				continue;
4787*83ee113eSDavid van Moolenbroek 			}
4788*83ee113eSDavid van Moolenbroek 
4789*83ee113eSDavid van Moolenbroek 			if (fmt[1] == 'o') {
4790*83ee113eSDavid van Moolenbroek 				/*
4791*83ee113eSDavid van Moolenbroek 				 * A value for the current format is
4792*83ee113eSDavid van Moolenbroek 				 * optional - check to see if the next
4793*83ee113eSDavid van Moolenbroek 				 * token is a semi-colon if so we don't
4794*83ee113eSDavid van Moolenbroek 				 * need to parse it and doing so would
4795*83ee113eSDavid van Moolenbroek 				 * consume the semi-colon which our
4796*83ee113eSDavid van Moolenbroek 				 * caller is expecting to parse
4797*83ee113eSDavid van Moolenbroek 				 */
4798*83ee113eSDavid van Moolenbroek 				token = peek_token(&val, (unsigned *)0,
4799*83ee113eSDavid van Moolenbroek 						   cfile);
4800*83ee113eSDavid van Moolenbroek 				if (token == SEMI) {
4801*83ee113eSDavid van Moolenbroek 					fmt++;
4802*83ee113eSDavid van Moolenbroek 					continue;
4803*83ee113eSDavid van Moolenbroek 				}
4804*83ee113eSDavid van Moolenbroek 			}
4805*83ee113eSDavid van Moolenbroek 
4806*83ee113eSDavid van Moolenbroek 			tmp = *expr;
4807*83ee113eSDavid van Moolenbroek 			*expr = NULL;
4808*83ee113eSDavid van Moolenbroek 
4809*83ee113eSDavid van Moolenbroek 			if (!parse_option_token(expr, cfile, &fmt, tmp,
4810*83ee113eSDavid van Moolenbroek 						uniform, lookups)) {
4811*83ee113eSDavid van Moolenbroek 				if (fmt [1] != 'o') {
4812*83ee113eSDavid van Moolenbroek 					if (tmp)
4813*83ee113eSDavid van Moolenbroek 						expression_dereference (&tmp,
4814*83ee113eSDavid van Moolenbroek 									MDL);
4815*83ee113eSDavid van Moolenbroek 					return 0;
4816*83ee113eSDavid van Moolenbroek 				}
4817*83ee113eSDavid van Moolenbroek 				*expr = tmp;
4818*83ee113eSDavid van Moolenbroek 				tmp = NULL;
4819*83ee113eSDavid van Moolenbroek 			}
4820*83ee113eSDavid van Moolenbroek 			if (tmp)
4821*83ee113eSDavid van Moolenbroek 				expression_dereference (&tmp, MDL);
4822*83ee113eSDavid van Moolenbroek 
4823*83ee113eSDavid van Moolenbroek 			fmt++;
4824*83ee113eSDavid van Moolenbroek 		} while (*fmt != '\0');
4825*83ee113eSDavid van Moolenbroek 
4826*83ee113eSDavid van Moolenbroek 		if ((*fmt == 'A') || (*fmt == 'a')) {
4827*83ee113eSDavid van Moolenbroek 			token = peek_token (&val, (unsigned *)0, cfile);
4828*83ee113eSDavid van Moolenbroek 			/* Comma means: continue with next element in array */
4829*83ee113eSDavid van Moolenbroek 			if (token == COMMA) {
4830*83ee113eSDavid van Moolenbroek 				skip_token(&val, (unsigned *)0, cfile);
4831*83ee113eSDavid van Moolenbroek 				continue;
4832*83ee113eSDavid van Moolenbroek 			}
4833*83ee113eSDavid van Moolenbroek 			/* no comma: end of array.
4834*83ee113eSDavid van Moolenbroek 			   'A' or end of string means: leave the loop */
4835*83ee113eSDavid van Moolenbroek 			if ((*fmt == 'A') || (fmt[1] == '\0'))
4836*83ee113eSDavid van Moolenbroek 				break;
4837*83ee113eSDavid van Moolenbroek 			/* 'a' means: go on with next char */
4838*83ee113eSDavid van Moolenbroek 			if (*fmt == 'a') {
4839*83ee113eSDavid van Moolenbroek 				fmt++;
4840*83ee113eSDavid van Moolenbroek 				goto and_again;
4841*83ee113eSDavid van Moolenbroek 			}
4842*83ee113eSDavid van Moolenbroek 		}
4843*83ee113eSDavid van Moolenbroek 	} while ((*fmt == 'A') || (*fmt == 'a'));
4844*83ee113eSDavid van Moolenbroek 
4845*83ee113eSDavid van Moolenbroek         return 1;
4846*83ee113eSDavid van Moolenbroek }
4847*83ee113eSDavid van Moolenbroek 
4848*83ee113eSDavid van Moolenbroek /* option-statement :== identifier DOT identifier <syntax> SEMI
4849*83ee113eSDavid van Moolenbroek 		      | identifier <syntax> SEMI
4850*83ee113eSDavid van Moolenbroek 
4851*83ee113eSDavid van Moolenbroek    Option syntax is handled specially through format strings, so it
4852*83ee113eSDavid van Moolenbroek    would be painful to come up with BNF for it.   However, it always
4853*83ee113eSDavid van Moolenbroek    starts as above and ends in a SEMI. */
4854*83ee113eSDavid van Moolenbroek 
parse_option_statement(result,cfile,lookups,option,op)4855*83ee113eSDavid van Moolenbroek int parse_option_statement (result, cfile, lookups, option, op)
4856*83ee113eSDavid van Moolenbroek 	struct executable_statement **result;
4857*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
4858*83ee113eSDavid van Moolenbroek 	int lookups;
4859*83ee113eSDavid van Moolenbroek 	struct option *option;
4860*83ee113eSDavid van Moolenbroek 	enum statement_op op;
4861*83ee113eSDavid van Moolenbroek {
4862*83ee113eSDavid van Moolenbroek 	const char *val;
4863*83ee113eSDavid van Moolenbroek 	enum dhcp_token token;
4864*83ee113eSDavid van Moolenbroek 	struct expression *expr = (struct expression *)0;
4865*83ee113eSDavid van Moolenbroek 	int lose;
4866*83ee113eSDavid van Moolenbroek 
4867*83ee113eSDavid van Moolenbroek 	token = peek_token (&val, (unsigned *)0, cfile);
4868*83ee113eSDavid van Moolenbroek 	if ((token == SEMI) && (option->format[0] != 'Z')) {
4869*83ee113eSDavid van Moolenbroek 		/* Eat the semicolon... */
4870*83ee113eSDavid van Moolenbroek 		/*
4871*83ee113eSDavid van Moolenbroek 		 * XXXSK: I'm not sure why we should ever get here, but we
4872*83ee113eSDavid van Moolenbroek 		 * 	  do during our startup. This confuses things if
4873*83ee113eSDavid van Moolenbroek 		 * 	  we are parsing a zero-length option, so don't
4874*83ee113eSDavid van Moolenbroek 		 * 	  eat the semicolon token in that case.
4875*83ee113eSDavid van Moolenbroek 		 */
4876*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
4877*83ee113eSDavid van Moolenbroek 	} else if (token == EQUAL) {
4878*83ee113eSDavid van Moolenbroek 		/* Eat the equals sign. */
4879*83ee113eSDavid van Moolenbroek 		skip_token(&val, (unsigned *)0, cfile);
4880*83ee113eSDavid van Moolenbroek 
4881*83ee113eSDavid van Moolenbroek 		/* Parse a data expression and use its value for the data. */
4882*83ee113eSDavid van Moolenbroek 		if (!parse_data_expression (&expr, cfile, &lose)) {
4883*83ee113eSDavid van Moolenbroek 			/* In this context, we must have an executable
4884*83ee113eSDavid van Moolenbroek 			   statement, so if we found something else, it's
4885*83ee113eSDavid van Moolenbroek 			   still an error. */
4886*83ee113eSDavid van Moolenbroek 			if (!lose) {
4887*83ee113eSDavid van Moolenbroek 				parse_warn (cfile,
4888*83ee113eSDavid van Moolenbroek 					    "expecting a data expression.");
4889*83ee113eSDavid van Moolenbroek 				skip_to_semi (cfile);
4890*83ee113eSDavid van Moolenbroek 			}
4891*83ee113eSDavid van Moolenbroek 			return 0;
4892*83ee113eSDavid van Moolenbroek 		}
4893*83ee113eSDavid van Moolenbroek 	} else {
4894*83ee113eSDavid van Moolenbroek 		if (! parse_option_data(&expr, cfile, lookups, option))
4895*83ee113eSDavid van Moolenbroek 			return 0;
4896*83ee113eSDavid van Moolenbroek 	}
4897*83ee113eSDavid van Moolenbroek 
4898*83ee113eSDavid van Moolenbroek 	if (!parse_semi (cfile))
4899*83ee113eSDavid van Moolenbroek 		return 0;
4900*83ee113eSDavid van Moolenbroek 	if (!executable_statement_allocate (result, MDL))
4901*83ee113eSDavid van Moolenbroek 		log_fatal ("no memory for option statement.");
4902*83ee113eSDavid van Moolenbroek 
4903*83ee113eSDavid van Moolenbroek         (*result)->op = op;
4904*83ee113eSDavid van Moolenbroek 	if (expr && !option_cache (&(*result)->data.option,
4905*83ee113eSDavid van Moolenbroek 				   NULL, expr, option, MDL))
4906*83ee113eSDavid van Moolenbroek 		log_fatal ("no memory for option cache");
4907*83ee113eSDavid van Moolenbroek 
4908*83ee113eSDavid van Moolenbroek 	if (expr)
4909*83ee113eSDavid van Moolenbroek 		expression_dereference (&expr, MDL);
4910*83ee113eSDavid van Moolenbroek 
4911*83ee113eSDavid van Moolenbroek 	return 1;
4912*83ee113eSDavid van Moolenbroek }
4913*83ee113eSDavid van Moolenbroek 
parse_option_token(rv,cfile,fmt,expr,uniform,lookups)4914*83ee113eSDavid van Moolenbroek int parse_option_token (rv, cfile, fmt, expr, uniform, lookups)
4915*83ee113eSDavid van Moolenbroek 	struct expression **rv;
4916*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
4917*83ee113eSDavid van Moolenbroek 	const char **fmt;
4918*83ee113eSDavid van Moolenbroek 	struct expression *expr;
4919*83ee113eSDavid van Moolenbroek 	int uniform;
4920*83ee113eSDavid van Moolenbroek 	int lookups;
4921*83ee113eSDavid van Moolenbroek {
4922*83ee113eSDavid van Moolenbroek 	const char *val;
4923*83ee113eSDavid van Moolenbroek 	enum dhcp_token token;
4924*83ee113eSDavid van Moolenbroek 	struct expression *t = (struct expression *)0;
4925*83ee113eSDavid van Moolenbroek 	unsigned char buf [4];
4926*83ee113eSDavid van Moolenbroek 	unsigned len;
4927*83ee113eSDavid van Moolenbroek 	struct iaddr addr;
4928*83ee113eSDavid van Moolenbroek 	int compress;
4929*83ee113eSDavid van Moolenbroek 	isc_boolean_t freeval = ISC_FALSE;
4930*83ee113eSDavid van Moolenbroek 	const char *f, *g;
4931*83ee113eSDavid van Moolenbroek 	struct enumeration_value *e;
4932*83ee113eSDavid van Moolenbroek 
4933*83ee113eSDavid van Moolenbroek 	switch (**fmt) {
4934*83ee113eSDavid van Moolenbroek 	      case 'U':
4935*83ee113eSDavid van Moolenbroek 		token = next_token (&val, &len, cfile);
4936*83ee113eSDavid van Moolenbroek 		if (!is_identifier (token)) {
4937*83ee113eSDavid van Moolenbroek 			if ((*fmt) [1] != 'o') {
4938*83ee113eSDavid van Moolenbroek 				parse_warn (cfile, "expecting identifier.");
4939*83ee113eSDavid van Moolenbroek 				if (token != SEMI)
4940*83ee113eSDavid van Moolenbroek 					skip_to_semi (cfile);
4941*83ee113eSDavid van Moolenbroek 			}
4942*83ee113eSDavid van Moolenbroek 			return 0;
4943*83ee113eSDavid van Moolenbroek 		}
4944*83ee113eSDavid van Moolenbroek 		if (!make_const_data (&t, (const unsigned char *)val,
4945*83ee113eSDavid van Moolenbroek 				      len, 1, 1, MDL))
4946*83ee113eSDavid van Moolenbroek 			log_fatal ("No memory for %s", val);
4947*83ee113eSDavid van Moolenbroek 		break;
4948*83ee113eSDavid van Moolenbroek 
4949*83ee113eSDavid van Moolenbroek 	      case 'E':
4950*83ee113eSDavid van Moolenbroek 		g = strchr (*fmt, '.');
4951*83ee113eSDavid van Moolenbroek 		if (!g) {
4952*83ee113eSDavid van Moolenbroek 			parse_warn (cfile,
4953*83ee113eSDavid van Moolenbroek 				    "malformed encapsulation format (bug!)");
4954*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
4955*83ee113eSDavid van Moolenbroek 			return 0;
4956*83ee113eSDavid van Moolenbroek 		}
4957*83ee113eSDavid van Moolenbroek 		*fmt = g;
4958*83ee113eSDavid van Moolenbroek 		/* FALL THROUGH */
4959*83ee113eSDavid van Moolenbroek 		/* to get string value for the option */
4960*83ee113eSDavid van Moolenbroek 	      case 'X':
4961*83ee113eSDavid van Moolenbroek 		token = peek_token (&val, (unsigned *)0, cfile);
4962*83ee113eSDavid van Moolenbroek 		if (token == NUMBER_OR_NAME || token == NUMBER) {
4963*83ee113eSDavid van Moolenbroek 			if (!expression_allocate (&t, MDL))
4964*83ee113eSDavid van Moolenbroek 				return 0;
4965*83ee113eSDavid van Moolenbroek 			if (!parse_cshl (&t -> data.const_data, cfile)) {
4966*83ee113eSDavid van Moolenbroek 				expression_dereference (&t, MDL);
4967*83ee113eSDavid van Moolenbroek 				return 0;
4968*83ee113eSDavid van Moolenbroek 			}
4969*83ee113eSDavid van Moolenbroek 			t -> op = expr_const_data;
4970*83ee113eSDavid van Moolenbroek 		} else {
4971*83ee113eSDavid van Moolenbroek 			token = next_token (&val, &len, cfile);
4972*83ee113eSDavid van Moolenbroek 
4973*83ee113eSDavid van Moolenbroek 			if(token == STRING) {
4974*83ee113eSDavid van Moolenbroek 				if (!make_const_data (&t,
4975*83ee113eSDavid van Moolenbroek 						(const unsigned char *)val,
4976*83ee113eSDavid van Moolenbroek 							len, 1, 1, MDL))
4977*83ee113eSDavid van Moolenbroek 					log_fatal ("No memory for \"%s\"", val);
4978*83ee113eSDavid van Moolenbroek 			} else {
4979*83ee113eSDavid van Moolenbroek                                 if ((*fmt) [1] != 'o') {
4980*83ee113eSDavid van Moolenbroek 				        parse_warn (cfile, "expecting string "
4981*83ee113eSDavid van Moolenbroek 					            "or hexadecimal data.");
4982*83ee113eSDavid van Moolenbroek 				        skip_to_semi (cfile);
4983*83ee113eSDavid van Moolenbroek                                 }
4984*83ee113eSDavid van Moolenbroek 				return 0;
4985*83ee113eSDavid van Moolenbroek 			}
4986*83ee113eSDavid van Moolenbroek 		}
4987*83ee113eSDavid van Moolenbroek 		break;
4988*83ee113eSDavid van Moolenbroek 
4989*83ee113eSDavid van Moolenbroek               case 'D': /* Domain list... */
4990*83ee113eSDavid van Moolenbroek 		if ((*fmt)[1] == 'c') {
4991*83ee113eSDavid van Moolenbroek 			compress = 1;
4992*83ee113eSDavid van Moolenbroek 			/* Skip the compress-flag atom. */
4993*83ee113eSDavid van Moolenbroek 			(*fmt)++;
4994*83ee113eSDavid van Moolenbroek 		} else
4995*83ee113eSDavid van Moolenbroek 			compress = 0;
4996*83ee113eSDavid van Moolenbroek 
4997*83ee113eSDavid van Moolenbroek 		t = parse_domain_list(cfile, compress);
4998*83ee113eSDavid van Moolenbroek 
4999*83ee113eSDavid van Moolenbroek 		if (!t) {
5000*83ee113eSDavid van Moolenbroek 			if ((*fmt)[1] != 'o')
5001*83ee113eSDavid van Moolenbroek 				skip_to_semi(cfile);
5002*83ee113eSDavid van Moolenbroek 			return 0;
5003*83ee113eSDavid van Moolenbroek 		}
5004*83ee113eSDavid van Moolenbroek 
5005*83ee113eSDavid van Moolenbroek 		break;
5006*83ee113eSDavid van Moolenbroek 
5007*83ee113eSDavid van Moolenbroek 	      case 'd': /* Domain name... */
5008*83ee113eSDavid van Moolenbroek 		val = parse_host_name (cfile);
5009*83ee113eSDavid van Moolenbroek 		if (!val) {
5010*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "not a valid domain name.");
5011*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
5012*83ee113eSDavid van Moolenbroek 			return 0;
5013*83ee113eSDavid van Moolenbroek 		}
5014*83ee113eSDavid van Moolenbroek 		len = strlen (val);
5015*83ee113eSDavid van Moolenbroek 		freeval = ISC_TRUE;
5016*83ee113eSDavid van Moolenbroek 		goto make_string;
5017*83ee113eSDavid van Moolenbroek 
5018*83ee113eSDavid van Moolenbroek 	      case 't': /* Text string... */
5019*83ee113eSDavid van Moolenbroek 		token = next_token (&val, &len, cfile);
5020*83ee113eSDavid van Moolenbroek 		if (token != STRING && !is_identifier (token)) {
5021*83ee113eSDavid van Moolenbroek 			if ((*fmt) [1] != 'o') {
5022*83ee113eSDavid van Moolenbroek 				parse_warn (cfile, "expecting string.");
5023*83ee113eSDavid van Moolenbroek 				if (token != SEMI)
5024*83ee113eSDavid van Moolenbroek 					skip_to_semi (cfile);
5025*83ee113eSDavid van Moolenbroek 			}
5026*83ee113eSDavid van Moolenbroek 			return 0;
5027*83ee113eSDavid van Moolenbroek 		}
5028*83ee113eSDavid van Moolenbroek 	      make_string:
5029*83ee113eSDavid van Moolenbroek 		if (!make_const_data (&t, (const unsigned char *)val,
5030*83ee113eSDavid van Moolenbroek 				      len, 1, 1, MDL))
5031*83ee113eSDavid van Moolenbroek 			log_fatal ("No memory for concatenation");
5032*83ee113eSDavid van Moolenbroek 		if (freeval == ISC_TRUE) {
5033*83ee113eSDavid van Moolenbroek 			dfree((char *)val, MDL);
5034*83ee113eSDavid van Moolenbroek 			freeval = ISC_FALSE;
5035*83ee113eSDavid van Moolenbroek 			POST(freeval);
5036*83ee113eSDavid van Moolenbroek 		}
5037*83ee113eSDavid van Moolenbroek 		break;
5038*83ee113eSDavid van Moolenbroek 
5039*83ee113eSDavid van Moolenbroek 	      case 'N':
5040*83ee113eSDavid van Moolenbroek 		f = (*fmt) + 1;
5041*83ee113eSDavid van Moolenbroek 		g = strchr (*fmt, '.');
5042*83ee113eSDavid van Moolenbroek 		if (!g) {
5043*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "malformed %s (bug!)",
5044*83ee113eSDavid van Moolenbroek 				    "enumeration format");
5045*83ee113eSDavid van Moolenbroek 		      foo:
5046*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
5047*83ee113eSDavid van Moolenbroek 			return 0;
5048*83ee113eSDavid van Moolenbroek 		}
5049*83ee113eSDavid van Moolenbroek 		*fmt = g;
5050*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
5051*83ee113eSDavid van Moolenbroek 		if (!is_identifier (token)) {
5052*83ee113eSDavid van Moolenbroek 			parse_warn (cfile,
5053*83ee113eSDavid van Moolenbroek 				    "identifier expected");
5054*83ee113eSDavid van Moolenbroek 			goto foo;
5055*83ee113eSDavid van Moolenbroek 		}
5056*83ee113eSDavid van Moolenbroek 		e = find_enumeration_value (f, (*fmt) - f, &len, val);
5057*83ee113eSDavid van Moolenbroek 		if (!e) {
5058*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "unknown value");
5059*83ee113eSDavid van Moolenbroek 			goto foo;
5060*83ee113eSDavid van Moolenbroek 		}
5061*83ee113eSDavid van Moolenbroek 		if (!make_const_data (&t, &e -> value, len, 0, 1, MDL))
5062*83ee113eSDavid van Moolenbroek 			return 0;
5063*83ee113eSDavid van Moolenbroek 		break;
5064*83ee113eSDavid van Moolenbroek 
5065*83ee113eSDavid van Moolenbroek 	      case 'I': /* IP address or hostname. */
5066*83ee113eSDavid van Moolenbroek 		if (lookups) {
5067*83ee113eSDavid van Moolenbroek 			if (!parse_ip_addr_or_hostname (&t, cfile, uniform))
5068*83ee113eSDavid van Moolenbroek 				return 0;
5069*83ee113eSDavid van Moolenbroek 		} else {
5070*83ee113eSDavid van Moolenbroek 			if (!parse_ip_addr (cfile, &addr))
5071*83ee113eSDavid van Moolenbroek 				return 0;
5072*83ee113eSDavid van Moolenbroek 			if (!make_const_data (&t, addr.iabuf, addr.len,
5073*83ee113eSDavid van Moolenbroek 					      0, 1, MDL))
5074*83ee113eSDavid van Moolenbroek 				return 0;
5075*83ee113eSDavid van Moolenbroek 		}
5076*83ee113eSDavid van Moolenbroek 		break;
5077*83ee113eSDavid van Moolenbroek 
5078*83ee113eSDavid van Moolenbroek 	      case '6': /* IPv6 address. */
5079*83ee113eSDavid van Moolenbroek 		if (!parse_ip6_addr(cfile, &addr)) {
5080*83ee113eSDavid van Moolenbroek 			return 0;
5081*83ee113eSDavid van Moolenbroek 		}
5082*83ee113eSDavid van Moolenbroek 		if (!make_const_data(&t, addr.iabuf, addr.len, 0, 1, MDL)) {
5083*83ee113eSDavid van Moolenbroek 			return 0;
5084*83ee113eSDavid van Moolenbroek 		}
5085*83ee113eSDavid van Moolenbroek 		break;
5086*83ee113eSDavid van Moolenbroek 
5087*83ee113eSDavid van Moolenbroek 	      case 'T':	/* Lease interval. */
5088*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
5089*83ee113eSDavid van Moolenbroek 		if (token != INFINITE)
5090*83ee113eSDavid van Moolenbroek 			goto check_number;
5091*83ee113eSDavid van Moolenbroek 		putLong (buf, -1);
5092*83ee113eSDavid van Moolenbroek 		if (!make_const_data (&t, buf, 4, 0, 1, MDL))
5093*83ee113eSDavid van Moolenbroek 			return 0;
5094*83ee113eSDavid van Moolenbroek 		break;
5095*83ee113eSDavid van Moolenbroek 
5096*83ee113eSDavid van Moolenbroek 	      case 'L': /* Unsigned 32-bit integer... */
5097*83ee113eSDavid van Moolenbroek 	      case 'l':	/* Signed 32-bit integer... */
5098*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
5099*83ee113eSDavid van Moolenbroek 	      check_number:
5100*83ee113eSDavid van Moolenbroek 		if ((token != NUMBER) && (token != NUMBER_OR_NAME)) {
5101*83ee113eSDavid van Moolenbroek 		      need_number:
5102*83ee113eSDavid van Moolenbroek 			if ((*fmt) [1] != 'o') {
5103*83ee113eSDavid van Moolenbroek 				parse_warn (cfile, "expecting number.");
5104*83ee113eSDavid van Moolenbroek 				if (token != SEMI)
5105*83ee113eSDavid van Moolenbroek 					skip_to_semi (cfile);
5106*83ee113eSDavid van Moolenbroek 			}
5107*83ee113eSDavid van Moolenbroek 			return 0;
5108*83ee113eSDavid van Moolenbroek 		}
5109*83ee113eSDavid van Moolenbroek 		convert_num (cfile, buf, val, 0, 32);
5110*83ee113eSDavid van Moolenbroek 		if (!make_const_data (&t, buf, 4, 0, 1, MDL))
5111*83ee113eSDavid van Moolenbroek 			return 0;
5112*83ee113eSDavid van Moolenbroek 		break;
5113*83ee113eSDavid van Moolenbroek 
5114*83ee113eSDavid van Moolenbroek 	      case 's':	/* Signed 16-bit integer. */
5115*83ee113eSDavid van Moolenbroek 	      case 'S':	/* Unsigned 16-bit integer. */
5116*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
5117*83ee113eSDavid van Moolenbroek 		if ((token != NUMBER) && (token != NUMBER_OR_NAME))
5118*83ee113eSDavid van Moolenbroek 			goto need_number;
5119*83ee113eSDavid van Moolenbroek 		convert_num (cfile, buf, val, 0, 16);
5120*83ee113eSDavid van Moolenbroek 		if (!make_const_data (&t, buf, 2, 0, 1, MDL))
5121*83ee113eSDavid van Moolenbroek 			return 0;
5122*83ee113eSDavid van Moolenbroek 		break;
5123*83ee113eSDavid van Moolenbroek 
5124*83ee113eSDavid van Moolenbroek 	      case 'b':	/* Signed 8-bit integer. */
5125*83ee113eSDavid van Moolenbroek 	      case 'B':	/* Unsigned 8-bit integer. */
5126*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
5127*83ee113eSDavid van Moolenbroek 		if ((token != NUMBER) && (token != NUMBER_OR_NAME))
5128*83ee113eSDavid van Moolenbroek 			goto need_number;
5129*83ee113eSDavid van Moolenbroek 		convert_num (cfile, buf, val, 0, 8);
5130*83ee113eSDavid van Moolenbroek 		if (!make_const_data (&t, buf, 1, 0, 1, MDL))
5131*83ee113eSDavid van Moolenbroek 			return 0;
5132*83ee113eSDavid van Moolenbroek 		break;
5133*83ee113eSDavid van Moolenbroek 
5134*83ee113eSDavid van Moolenbroek 	      case 'f': /* Boolean flag. */
5135*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
5136*83ee113eSDavid van Moolenbroek 		if (!is_identifier (token)) {
5137*83ee113eSDavid van Moolenbroek 			if ((*fmt) [1] != 'o')
5138*83ee113eSDavid van Moolenbroek 				parse_warn (cfile, "expecting identifier.");
5139*83ee113eSDavid van Moolenbroek 		      bad_flag:
5140*83ee113eSDavid van Moolenbroek 			if ((*fmt) [1] != 'o') {
5141*83ee113eSDavid van Moolenbroek 				if (token != SEMI)
5142*83ee113eSDavid van Moolenbroek 					skip_to_semi (cfile);
5143*83ee113eSDavid van Moolenbroek 			}
5144*83ee113eSDavid van Moolenbroek 			return 0;
5145*83ee113eSDavid van Moolenbroek 		}
5146*83ee113eSDavid van Moolenbroek 		if (!strcasecmp (val, "true")
5147*83ee113eSDavid van Moolenbroek 		    || !strcasecmp (val, "on"))
5148*83ee113eSDavid van Moolenbroek 			buf [0] = 1;
5149*83ee113eSDavid van Moolenbroek 		else if (!strcasecmp (val, "false")
5150*83ee113eSDavid van Moolenbroek 			 || !strcasecmp (val, "off"))
5151*83ee113eSDavid van Moolenbroek 			buf [0] = 0;
5152*83ee113eSDavid van Moolenbroek 		else if (!strcasecmp (val, "ignore"))
5153*83ee113eSDavid van Moolenbroek 			buf [0] = 2;
5154*83ee113eSDavid van Moolenbroek 		else {
5155*83ee113eSDavid van Moolenbroek 			if ((*fmt) [1] != 'o')
5156*83ee113eSDavid van Moolenbroek 				parse_warn (cfile, "expecting boolean.");
5157*83ee113eSDavid van Moolenbroek 			goto bad_flag;
5158*83ee113eSDavid van Moolenbroek 		}
5159*83ee113eSDavid van Moolenbroek 		if (!make_const_data (&t, buf, 1, 0, 1, MDL))
5160*83ee113eSDavid van Moolenbroek 			return 0;
5161*83ee113eSDavid van Moolenbroek 		break;
5162*83ee113eSDavid van Moolenbroek 
5163*83ee113eSDavid van Moolenbroek 	      case 'Z': /* Zero-length option. */
5164*83ee113eSDavid van Moolenbroek 		token = peek_token (&val, (unsigned *)0, cfile);
5165*83ee113eSDavid van Moolenbroek 		if (token != SEMI) {
5166*83ee113eSDavid van Moolenbroek 			parse_warn(cfile, "semicolon expected.");
5167*83ee113eSDavid van Moolenbroek 			skip_to_semi(cfile);
5168*83ee113eSDavid van Moolenbroek 		}
5169*83ee113eSDavid van Moolenbroek 		buf[0] = '\0';
5170*83ee113eSDavid van Moolenbroek 		if (!make_const_data(&t,        /* expression */
5171*83ee113eSDavid van Moolenbroek 				     buf,       /* buffer */
5172*83ee113eSDavid van Moolenbroek 				     0,         /* length */
5173*83ee113eSDavid van Moolenbroek 				     0,         /* terminated */
5174*83ee113eSDavid van Moolenbroek 				     1,         /* allocate */
5175*83ee113eSDavid van Moolenbroek 				     MDL))
5176*83ee113eSDavid van Moolenbroek 			return 0;
5177*83ee113eSDavid van Moolenbroek 		break;
5178*83ee113eSDavid van Moolenbroek 
5179*83ee113eSDavid van Moolenbroek 	      default:
5180*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "Bad format '%c' in parse_option_token.",
5181*83ee113eSDavid van Moolenbroek 			    **fmt);
5182*83ee113eSDavid van Moolenbroek 		skip_to_semi (cfile);
5183*83ee113eSDavid van Moolenbroek 		return 0;
5184*83ee113eSDavid van Moolenbroek 	}
5185*83ee113eSDavid van Moolenbroek 	if (expr) {
5186*83ee113eSDavid van Moolenbroek 		if (!make_concat (rv, expr, t))
5187*83ee113eSDavid van Moolenbroek 			return 0;
5188*83ee113eSDavid van Moolenbroek 	} else
5189*83ee113eSDavid van Moolenbroek 		expression_reference (rv, t, MDL);
5190*83ee113eSDavid van Moolenbroek 	expression_dereference (&t, MDL);
5191*83ee113eSDavid van Moolenbroek 	return 1;
5192*83ee113eSDavid van Moolenbroek }
5193*83ee113eSDavid van Moolenbroek 
parse_option_decl(oc,cfile)5194*83ee113eSDavid van Moolenbroek int parse_option_decl (oc, cfile)
5195*83ee113eSDavid van Moolenbroek 	struct option_cache **oc;
5196*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
5197*83ee113eSDavid van Moolenbroek {
5198*83ee113eSDavid van Moolenbroek 	const char *val;
5199*83ee113eSDavid van Moolenbroek 	int token;
5200*83ee113eSDavid van Moolenbroek 	u_int8_t buf [4];
5201*83ee113eSDavid van Moolenbroek 	u_int8_t hunkbuf [1024];
5202*83ee113eSDavid van Moolenbroek 	unsigned hunkix = 0;
5203*83ee113eSDavid van Moolenbroek 	const char *fmt, *f;
5204*83ee113eSDavid van Moolenbroek 	struct option *option=NULL;
5205*83ee113eSDavid van Moolenbroek 	struct iaddr ip_addr;
5206*83ee113eSDavid van Moolenbroek 	u_int8_t *dp;
5207*83ee113eSDavid van Moolenbroek 	const u_int8_t *cdp;
5208*83ee113eSDavid van Moolenbroek 	unsigned len;
5209*83ee113eSDavid van Moolenbroek 	int nul_term = 0;
5210*83ee113eSDavid van Moolenbroek 	struct buffer *bp;
5211*83ee113eSDavid van Moolenbroek 	int known = 0;
5212*83ee113eSDavid van Moolenbroek 	int compress;
5213*83ee113eSDavid van Moolenbroek 	struct expression *express = NULL;
5214*83ee113eSDavid van Moolenbroek 	struct enumeration_value *e;
5215*83ee113eSDavid van Moolenbroek 	isc_result_t status;
5216*83ee113eSDavid van Moolenbroek 
5217*83ee113eSDavid van Moolenbroek 	status = parse_option_name (cfile, 0, &known, &option);
5218*83ee113eSDavid van Moolenbroek 	if (status != ISC_R_SUCCESS || option == NULL)
5219*83ee113eSDavid van Moolenbroek 		return 0;
5220*83ee113eSDavid van Moolenbroek 
5221*83ee113eSDavid van Moolenbroek 	fmt = option->format;
5222*83ee113eSDavid van Moolenbroek 
5223*83ee113eSDavid van Moolenbroek 	/* Parse the option data... */
5224*83ee113eSDavid van Moolenbroek 	do {
5225*83ee113eSDavid van Moolenbroek 		for (; *fmt; fmt++) {
5226*83ee113eSDavid van Moolenbroek 			if (*fmt == 'A') {
5227*83ee113eSDavid van Moolenbroek 				/* 'A' is an array of records, start at
5228*83ee113eSDavid van Moolenbroek 				 *  the beginning
5229*83ee113eSDavid van Moolenbroek 				 */
5230*83ee113eSDavid van Moolenbroek 				fmt = option->format;
5231*83ee113eSDavid van Moolenbroek 				break;
5232*83ee113eSDavid van Moolenbroek 			}
5233*83ee113eSDavid van Moolenbroek 
5234*83ee113eSDavid van Moolenbroek 			if (*fmt == 'a') {
5235*83ee113eSDavid van Moolenbroek 				/* 'a' is an array of the last field,
5236*83ee113eSDavid van Moolenbroek 				 * back up one format character
5237*83ee113eSDavid van Moolenbroek 				 */
5238*83ee113eSDavid van Moolenbroek 				fmt--;
5239*83ee113eSDavid van Moolenbroek 				break;
5240*83ee113eSDavid van Moolenbroek 			}
5241*83ee113eSDavid van Moolenbroek 			if (*fmt == 'o' && fmt != option -> format)
5242*83ee113eSDavid van Moolenbroek 				continue;
5243*83ee113eSDavid van Moolenbroek 			switch (*fmt) {
5244*83ee113eSDavid van Moolenbroek 			      case 'E':
5245*83ee113eSDavid van Moolenbroek 				fmt = strchr (fmt, '.');
5246*83ee113eSDavid van Moolenbroek 				if (!fmt) {
5247*83ee113eSDavid van Moolenbroek 					parse_warn (cfile,
5248*83ee113eSDavid van Moolenbroek 						    "malformed %s (bug!)",
5249*83ee113eSDavid van Moolenbroek 						    "encapsulation format");
5250*83ee113eSDavid van Moolenbroek 					goto parse_exit;
5251*83ee113eSDavid van Moolenbroek 				}
5252*83ee113eSDavid van Moolenbroek 				/* FALL THROUGH */
5253*83ee113eSDavid van Moolenbroek 				/* to get string value for the option */
5254*83ee113eSDavid van Moolenbroek 			      case 'X':
5255*83ee113eSDavid van Moolenbroek 				len = parse_X (cfile, &hunkbuf [hunkix],
5256*83ee113eSDavid van Moolenbroek 					       sizeof hunkbuf - hunkix);
5257*83ee113eSDavid van Moolenbroek 				hunkix += len;
5258*83ee113eSDavid van Moolenbroek 				break;
5259*83ee113eSDavid van Moolenbroek 
5260*83ee113eSDavid van Moolenbroek 			      case 't': /* Text string... */
5261*83ee113eSDavid van Moolenbroek 				token = peek_token (&val,
5262*83ee113eSDavid van Moolenbroek 						    &len, cfile);
5263*83ee113eSDavid van Moolenbroek 				if (token == SEMI && fmt[1] == 'o') {
5264*83ee113eSDavid van Moolenbroek 					fmt++;
5265*83ee113eSDavid van Moolenbroek 					break;
5266*83ee113eSDavid van Moolenbroek 				}
5267*83ee113eSDavid van Moolenbroek 				token = next_token (&val,
5268*83ee113eSDavid van Moolenbroek 						    &len, cfile);
5269*83ee113eSDavid van Moolenbroek 				if (token != STRING) {
5270*83ee113eSDavid van Moolenbroek 					parse_warn (cfile,
5271*83ee113eSDavid van Moolenbroek 						    "expecting string.");
5272*83ee113eSDavid van Moolenbroek 					goto parse_exit;
5273*83ee113eSDavid van Moolenbroek 				}
5274*83ee113eSDavid van Moolenbroek 				if (hunkix + len + 1 > sizeof hunkbuf) {
5275*83ee113eSDavid van Moolenbroek 					parse_warn (cfile,
5276*83ee113eSDavid van Moolenbroek 						    "option data buffer %s",
5277*83ee113eSDavid van Moolenbroek 						    "overflow");
5278*83ee113eSDavid van Moolenbroek 					goto parse_exit;
5279*83ee113eSDavid van Moolenbroek 				}
5280*83ee113eSDavid van Moolenbroek 				memcpy (&hunkbuf [hunkix], val, len + 1);
5281*83ee113eSDavid van Moolenbroek 				nul_term = 1;
5282*83ee113eSDavid van Moolenbroek 				hunkix += len;
5283*83ee113eSDavid van Moolenbroek 				break;
5284*83ee113eSDavid van Moolenbroek 
5285*83ee113eSDavid van Moolenbroek 			      case 'D':
5286*83ee113eSDavid van Moolenbroek 				if (fmt[1] == 'c') {
5287*83ee113eSDavid van Moolenbroek 					compress = 1;
5288*83ee113eSDavid van Moolenbroek 					fmt++;
5289*83ee113eSDavid van Moolenbroek 				} else
5290*83ee113eSDavid van Moolenbroek 					compress = 0;
5291*83ee113eSDavid van Moolenbroek 
5292*83ee113eSDavid van Moolenbroek 				express = parse_domain_list(cfile, compress);
5293*83ee113eSDavid van Moolenbroek 
5294*83ee113eSDavid van Moolenbroek 				if (express == NULL)
5295*83ee113eSDavid van Moolenbroek 					goto exit;
5296*83ee113eSDavid van Moolenbroek 
5297*83ee113eSDavid van Moolenbroek 				if (express->op != expr_const_data) {
5298*83ee113eSDavid van Moolenbroek 					parse_warn(cfile, "unexpected "
5299*83ee113eSDavid van Moolenbroek 							  "expression");
5300*83ee113eSDavid van Moolenbroek 					goto parse_exit;
5301*83ee113eSDavid van Moolenbroek 				}
5302*83ee113eSDavid van Moolenbroek 
5303*83ee113eSDavid van Moolenbroek 				len = express->data.const_data.len;
5304*83ee113eSDavid van Moolenbroek 				cdp = express->data.const_data.data;
5305*83ee113eSDavid van Moolenbroek 
5306*83ee113eSDavid van Moolenbroek 				if ((hunkix + len) > sizeof(hunkbuf)) {
5307*83ee113eSDavid van Moolenbroek 					parse_warn(cfile, "option data buffer "
5308*83ee113eSDavid van Moolenbroek 							  "overflow");
5309*83ee113eSDavid van Moolenbroek 					goto parse_exit;
5310*83ee113eSDavid van Moolenbroek 				}
5311*83ee113eSDavid van Moolenbroek 				memcpy(&hunkbuf[hunkix], cdp, len);
5312*83ee113eSDavid van Moolenbroek 				hunkix += len;
5313*83ee113eSDavid van Moolenbroek 
5314*83ee113eSDavid van Moolenbroek 				expression_dereference(&express, MDL);
5315*83ee113eSDavid van Moolenbroek 				break;
5316*83ee113eSDavid van Moolenbroek 
5317*83ee113eSDavid van Moolenbroek 			      case 'N':
5318*83ee113eSDavid van Moolenbroek 				f = fmt + 1;
5319*83ee113eSDavid van Moolenbroek 				fmt = strchr (fmt, '.');
5320*83ee113eSDavid van Moolenbroek 				if (!fmt) {
5321*83ee113eSDavid van Moolenbroek 					parse_warn (cfile,
5322*83ee113eSDavid van Moolenbroek 						    "malformed %s (bug!)",
5323*83ee113eSDavid van Moolenbroek 						    "enumeration format");
5324*83ee113eSDavid van Moolenbroek 					goto parse_exit;
5325*83ee113eSDavid van Moolenbroek 				}
5326*83ee113eSDavid van Moolenbroek 				token = next_token (&val,
5327*83ee113eSDavid van Moolenbroek 						    (unsigned *)0, cfile);
5328*83ee113eSDavid van Moolenbroek 				if (!is_identifier (token)) {
5329*83ee113eSDavid van Moolenbroek 					parse_warn (cfile,
5330*83ee113eSDavid van Moolenbroek 						    "identifier expected");
5331*83ee113eSDavid van Moolenbroek 					goto parse_exit;
5332*83ee113eSDavid van Moolenbroek 				}
5333*83ee113eSDavid van Moolenbroek 				e = find_enumeration_value (f, fmt - f,
5334*83ee113eSDavid van Moolenbroek 							    &len, val);
5335*83ee113eSDavid van Moolenbroek 				if (!e) {
5336*83ee113eSDavid van Moolenbroek 					parse_warn (cfile,
5337*83ee113eSDavid van Moolenbroek 						    "unknown value");
5338*83ee113eSDavid van Moolenbroek 					goto parse_exit;
5339*83ee113eSDavid van Moolenbroek 				}
5340*83ee113eSDavid van Moolenbroek 				dp = &e -> value;
5341*83ee113eSDavid van Moolenbroek 				goto alloc;
5342*83ee113eSDavid van Moolenbroek 
5343*83ee113eSDavid van Moolenbroek 			      case '6':
5344*83ee113eSDavid van Moolenbroek 				if (!parse_ip6_addr(cfile, &ip_addr))
5345*83ee113eSDavid van Moolenbroek 					goto exit;
5346*83ee113eSDavid van Moolenbroek 				len = ip_addr.len;
5347*83ee113eSDavid van Moolenbroek 				dp = ip_addr.iabuf;
5348*83ee113eSDavid van Moolenbroek 				goto alloc;
5349*83ee113eSDavid van Moolenbroek 
5350*83ee113eSDavid van Moolenbroek 			      case 'I': /* IP address. */
5351*83ee113eSDavid van Moolenbroek 				if (!parse_ip_addr (cfile, &ip_addr))
5352*83ee113eSDavid van Moolenbroek 					goto exit;
5353*83ee113eSDavid van Moolenbroek 				len = ip_addr.len;
5354*83ee113eSDavid van Moolenbroek 				dp = ip_addr.iabuf;
5355*83ee113eSDavid van Moolenbroek 
5356*83ee113eSDavid van Moolenbroek 			      alloc:
5357*83ee113eSDavid van Moolenbroek 				if (hunkix + len > sizeof hunkbuf) {
5358*83ee113eSDavid van Moolenbroek 					parse_warn (cfile,
5359*83ee113eSDavid van Moolenbroek 						    "option data buffer %s",
5360*83ee113eSDavid van Moolenbroek 						    "overflow");
5361*83ee113eSDavid van Moolenbroek 					goto parse_exit;
5362*83ee113eSDavid van Moolenbroek 				}
5363*83ee113eSDavid van Moolenbroek 				memcpy (&hunkbuf [hunkix], dp, len);
5364*83ee113eSDavid van Moolenbroek 				hunkix += len;
5365*83ee113eSDavid van Moolenbroek 				break;
5366*83ee113eSDavid van Moolenbroek 
5367*83ee113eSDavid van Moolenbroek 			      case 'L': /* Unsigned 32-bit integer... */
5368*83ee113eSDavid van Moolenbroek 			      case 'l':	/* Signed 32-bit integer... */
5369*83ee113eSDavid van Moolenbroek 				token = next_token (&val,
5370*83ee113eSDavid van Moolenbroek 						    (unsigned *)0, cfile);
5371*83ee113eSDavid van Moolenbroek 				if ((token != NUMBER) &&
5372*83ee113eSDavid van Moolenbroek 				    (token != NUMBER_OR_NAME)) {
5373*83ee113eSDavid van Moolenbroek 				      need_number:
5374*83ee113eSDavid van Moolenbroek 					parse_warn (cfile,
5375*83ee113eSDavid van Moolenbroek 						    "expecting number.");
5376*83ee113eSDavid van Moolenbroek 					if (token != SEMI)
5377*83ee113eSDavid van Moolenbroek 						goto parse_exit;
5378*83ee113eSDavid van Moolenbroek 					else
5379*83ee113eSDavid van Moolenbroek 						goto exit;
5380*83ee113eSDavid van Moolenbroek 				}
5381*83ee113eSDavid van Moolenbroek 				convert_num (cfile, buf, val, 0, 32);
5382*83ee113eSDavid van Moolenbroek 				len = 4;
5383*83ee113eSDavid van Moolenbroek 				dp = buf;
5384*83ee113eSDavid van Moolenbroek 				goto alloc;
5385*83ee113eSDavid van Moolenbroek 
5386*83ee113eSDavid van Moolenbroek 			      case 's':	/* Signed 16-bit integer. */
5387*83ee113eSDavid van Moolenbroek 			      case 'S':	/* Unsigned 16-bit integer. */
5388*83ee113eSDavid van Moolenbroek 				token = next_token (&val,
5389*83ee113eSDavid van Moolenbroek 						    (unsigned *)0, cfile);
5390*83ee113eSDavid van Moolenbroek 				if ((token != NUMBER) &&
5391*83ee113eSDavid van Moolenbroek 				    (token != NUMBER_OR_NAME))
5392*83ee113eSDavid van Moolenbroek 					goto need_number;
5393*83ee113eSDavid van Moolenbroek 				convert_num (cfile, buf, val, 0, 16);
5394*83ee113eSDavid van Moolenbroek 				len = 2;
5395*83ee113eSDavid van Moolenbroek 				dp = buf;
5396*83ee113eSDavid van Moolenbroek 				goto alloc;
5397*83ee113eSDavid van Moolenbroek 
5398*83ee113eSDavid van Moolenbroek 			      case 'b':	/* Signed 8-bit integer. */
5399*83ee113eSDavid van Moolenbroek 			      case 'B':	/* Unsigned 8-bit integer. */
5400*83ee113eSDavid van Moolenbroek 				token = next_token (&val,
5401*83ee113eSDavid van Moolenbroek 						    (unsigned *)0, cfile);
5402*83ee113eSDavid van Moolenbroek 				if ((token != NUMBER) &&
5403*83ee113eSDavid van Moolenbroek 				    (token != NUMBER_OR_NAME))
5404*83ee113eSDavid van Moolenbroek 					goto need_number;
5405*83ee113eSDavid van Moolenbroek 				convert_num (cfile, buf, val, 0, 8);
5406*83ee113eSDavid van Moolenbroek 				len = 1;
5407*83ee113eSDavid van Moolenbroek 				dp = buf;
5408*83ee113eSDavid van Moolenbroek 				goto alloc;
5409*83ee113eSDavid van Moolenbroek 
5410*83ee113eSDavid van Moolenbroek 			      case 'f': /* Boolean flag. */
5411*83ee113eSDavid van Moolenbroek 				token = next_token (&val,
5412*83ee113eSDavid van Moolenbroek 						    (unsigned *)0, cfile);
5413*83ee113eSDavid van Moolenbroek 				if (!is_identifier (token)) {
5414*83ee113eSDavid van Moolenbroek 					parse_warn (cfile,
5415*83ee113eSDavid van Moolenbroek 						    "expecting identifier.");
5416*83ee113eSDavid van Moolenbroek 				      bad_flag:
5417*83ee113eSDavid van Moolenbroek 					if (token != SEMI)
5418*83ee113eSDavid van Moolenbroek 						goto parse_exit;
5419*83ee113eSDavid van Moolenbroek 					else
5420*83ee113eSDavid van Moolenbroek 						goto exit;
5421*83ee113eSDavid van Moolenbroek 				}
5422*83ee113eSDavid van Moolenbroek 				if (!strcasecmp (val, "true")
5423*83ee113eSDavid van Moolenbroek 				    || !strcasecmp (val, "on"))
5424*83ee113eSDavid van Moolenbroek 					buf [0] = 1;
5425*83ee113eSDavid van Moolenbroek 				else if (!strcasecmp (val, "false")
5426*83ee113eSDavid van Moolenbroek 					 || !strcasecmp (val, "off"))
5427*83ee113eSDavid van Moolenbroek 					buf [0] = 0;
5428*83ee113eSDavid van Moolenbroek 				else {
5429*83ee113eSDavid van Moolenbroek 					parse_warn (cfile,
5430*83ee113eSDavid van Moolenbroek 						    "expecting boolean.");
5431*83ee113eSDavid van Moolenbroek 					goto bad_flag;
5432*83ee113eSDavid van Moolenbroek 				}
5433*83ee113eSDavid van Moolenbroek 				len = 1;
5434*83ee113eSDavid van Moolenbroek 				dp = buf;
5435*83ee113eSDavid van Moolenbroek 				goto alloc;
5436*83ee113eSDavid van Moolenbroek 
5437*83ee113eSDavid van Moolenbroek 			      case 'Z':	/* Zero-length option */
5438*83ee113eSDavid van Moolenbroek 				token = peek_token(&val, (unsigned *)0, cfile);
5439*83ee113eSDavid van Moolenbroek 				if (token != SEMI) {
5440*83ee113eSDavid van Moolenbroek 					parse_warn(cfile,
5441*83ee113eSDavid van Moolenbroek 						   "semicolon expected.");
5442*83ee113eSDavid van Moolenbroek 					goto parse_exit;
5443*83ee113eSDavid van Moolenbroek 				}
5444*83ee113eSDavid van Moolenbroek 				len = 0;
5445*83ee113eSDavid van Moolenbroek 				buf[0] = '\0';
5446*83ee113eSDavid van Moolenbroek 				break;
5447*83ee113eSDavid van Moolenbroek 
5448*83ee113eSDavid van Moolenbroek 			      default:
5449*83ee113eSDavid van Moolenbroek 				log_error ("parse_option_param: Bad format %c",
5450*83ee113eSDavid van Moolenbroek 				      *fmt);
5451*83ee113eSDavid van Moolenbroek 				goto parse_exit;
5452*83ee113eSDavid van Moolenbroek 			}
5453*83ee113eSDavid van Moolenbroek 		}
5454*83ee113eSDavid van Moolenbroek 		token = next_token (&val, (unsigned *)0, cfile);
5455*83ee113eSDavid van Moolenbroek 	} while (*fmt && token == COMMA);
5456*83ee113eSDavid van Moolenbroek 
5457*83ee113eSDavid van Moolenbroek 	if (token != SEMI) {
5458*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "semicolon expected.");
5459*83ee113eSDavid van Moolenbroek 		goto parse_exit;
5460*83ee113eSDavid van Moolenbroek 	}
5461*83ee113eSDavid van Moolenbroek 
5462*83ee113eSDavid van Moolenbroek 	bp = (struct buffer *)0;
5463*83ee113eSDavid van Moolenbroek 	if (!buffer_allocate (&bp, hunkix + nul_term, MDL))
5464*83ee113eSDavid van Moolenbroek 		log_fatal ("no memory to store option declaration.");
5465*83ee113eSDavid van Moolenbroek 	memcpy (bp -> data, hunkbuf, hunkix + nul_term);
5466*83ee113eSDavid van Moolenbroek 
5467*83ee113eSDavid van Moolenbroek 	if (!option_cache_allocate (oc, MDL))
5468*83ee113eSDavid van Moolenbroek 		log_fatal ("out of memory allocating option cache.");
5469*83ee113eSDavid van Moolenbroek 
5470*83ee113eSDavid van Moolenbroek 	(*oc) -> data.buffer = bp;
5471*83ee113eSDavid van Moolenbroek 	(*oc) -> data.data = &bp -> data [0];
5472*83ee113eSDavid van Moolenbroek 	(*oc) -> data.terminated = nul_term;
5473*83ee113eSDavid van Moolenbroek 	(*oc) -> data.len = hunkix;
5474*83ee113eSDavid van Moolenbroek 	option_reference(&(*oc)->option, option, MDL);
5475*83ee113eSDavid van Moolenbroek 	option_dereference(&option, MDL);
5476*83ee113eSDavid van Moolenbroek 	return 1;
5477*83ee113eSDavid van Moolenbroek 
5478*83ee113eSDavid van Moolenbroek parse_exit:
5479*83ee113eSDavid van Moolenbroek 	if (express != NULL)
5480*83ee113eSDavid van Moolenbroek 		expression_dereference(&express, MDL);
5481*83ee113eSDavid van Moolenbroek 	skip_to_semi (cfile);
5482*83ee113eSDavid van Moolenbroek exit:
5483*83ee113eSDavid van Moolenbroek 	option_dereference(&option, MDL);
5484*83ee113eSDavid van Moolenbroek 
5485*83ee113eSDavid van Moolenbroek 	return 0;
5486*83ee113eSDavid van Moolenbroek }
5487*83ee113eSDavid van Moolenbroek 
5488*83ee113eSDavid van Moolenbroek /* Consider merging parse_cshl into this. */
5489*83ee113eSDavid van Moolenbroek 
parse_X(cfile,buf,max)5490*83ee113eSDavid van Moolenbroek int parse_X (cfile, buf, max)
5491*83ee113eSDavid van Moolenbroek 	struct parse *cfile;
5492*83ee113eSDavid van Moolenbroek 	u_int8_t *buf;
5493*83ee113eSDavid van Moolenbroek 	unsigned max;
5494*83ee113eSDavid van Moolenbroek {
5495*83ee113eSDavid van Moolenbroek 	int token;
5496*83ee113eSDavid van Moolenbroek 	const char *val;
5497*83ee113eSDavid van Moolenbroek 	unsigned len;
5498*83ee113eSDavid van Moolenbroek 
5499*83ee113eSDavid van Moolenbroek 	token = peek_token (&val, (unsigned *)0, cfile);
5500*83ee113eSDavid van Moolenbroek 	if (token == NUMBER_OR_NAME || token == NUMBER) {
5501*83ee113eSDavid van Moolenbroek 		len = 0;
5502*83ee113eSDavid van Moolenbroek 		do {
5503*83ee113eSDavid van Moolenbroek 			token = next_token (&val, (unsigned *)0, cfile);
5504*83ee113eSDavid van Moolenbroek 			if (token != NUMBER && token != NUMBER_OR_NAME) {
5505*83ee113eSDavid van Moolenbroek 				parse_warn (cfile,
5506*83ee113eSDavid van Moolenbroek 					    "expecting hexadecimal constant.");
5507*83ee113eSDavid van Moolenbroek 				skip_to_semi (cfile);
5508*83ee113eSDavid van Moolenbroek 				return 0;
5509*83ee113eSDavid van Moolenbroek 			}
5510*83ee113eSDavid van Moolenbroek 			convert_num (cfile, &buf [len], val, 16, 8);
5511*83ee113eSDavid van Moolenbroek 			if (len++ > max) {
5512*83ee113eSDavid van Moolenbroek 				parse_warn (cfile,
5513*83ee113eSDavid van Moolenbroek 					    "hexadecimal constant too long.");
5514*83ee113eSDavid van Moolenbroek 				skip_to_semi (cfile);
5515*83ee113eSDavid van Moolenbroek 				return 0;
5516*83ee113eSDavid van Moolenbroek 			}
5517*83ee113eSDavid van Moolenbroek 			token = peek_token (&val, (unsigned *)0, cfile);
5518*83ee113eSDavid van Moolenbroek 			if (token == COLON)
5519*83ee113eSDavid van Moolenbroek 				token = next_token (&val,
5520*83ee113eSDavid van Moolenbroek 						    (unsigned *)0, cfile);
5521*83ee113eSDavid van Moolenbroek 		} while (token == COLON);
5522*83ee113eSDavid van Moolenbroek 		val = (char *)buf;
5523*83ee113eSDavid van Moolenbroek 	} else if (token == STRING) {
5524*83ee113eSDavid van Moolenbroek 		skip_token(&val, &len, cfile);
5525*83ee113eSDavid van Moolenbroek 		if (len + 1 > max) {
5526*83ee113eSDavid van Moolenbroek 			parse_warn (cfile, "string constant too long.");
5527*83ee113eSDavid van Moolenbroek 			skip_to_semi (cfile);
5528*83ee113eSDavid van Moolenbroek 			return 0;
5529*83ee113eSDavid van Moolenbroek 		}
5530*83ee113eSDavid van Moolenbroek 		memcpy (buf, val, len + 1);
5531*83ee113eSDavid van Moolenbroek 	} else {
5532*83ee113eSDavid van Moolenbroek 		parse_warn (cfile, "expecting string or hexadecimal data");
5533*83ee113eSDavid van Moolenbroek 		skip_to_semi (cfile);
5534*83ee113eSDavid van Moolenbroek 		return 0;
5535*83ee113eSDavid van Moolenbroek 	}
5536*83ee113eSDavid van Moolenbroek 	return len;
5537*83ee113eSDavid van Moolenbroek }
5538*83ee113eSDavid van Moolenbroek 
parse_warn(struct parse * cfile,const char * fmt,...)5539*83ee113eSDavid van Moolenbroek int parse_warn (struct parse *cfile, const char *fmt, ...)
5540*83ee113eSDavid van Moolenbroek {
5541*83ee113eSDavid van Moolenbroek 	va_list list;
5542*83ee113eSDavid van Moolenbroek 	char lexbuf [256];
5543*83ee113eSDavid van Moolenbroek 	char mbuf [1024];
5544*83ee113eSDavid van Moolenbroek 	char fbuf [1024];
5545*83ee113eSDavid van Moolenbroek 	unsigned i, lix;
5546*83ee113eSDavid van Moolenbroek 
5547*83ee113eSDavid van Moolenbroek 	do_percentm (mbuf, fmt);
5548*83ee113eSDavid van Moolenbroek 	/* %Audit% This is log output. %2004.06.17,Safe%
5549*83ee113eSDavid van Moolenbroek 	 * If we truncate we hope the user can get a hint from the log.
5550*83ee113eSDavid van Moolenbroek 	 */
5551*83ee113eSDavid van Moolenbroek 	snprintf (fbuf, sizeof fbuf, "%s line %d: %s",
5552*83ee113eSDavid van Moolenbroek 		  cfile -> tlname, cfile -> lexline, mbuf);
5553*83ee113eSDavid van Moolenbroek 
5554*83ee113eSDavid van Moolenbroek 	va_start (list, fmt);
5555*83ee113eSDavid van Moolenbroek 	vsnprintf (mbuf, sizeof mbuf, fbuf, list);
5556*83ee113eSDavid van Moolenbroek 	va_end (list);
5557*83ee113eSDavid van Moolenbroek 
5558*83ee113eSDavid van Moolenbroek 	lix = 0;
5559*83ee113eSDavid van Moolenbroek 	for (i = 0;
5560*83ee113eSDavid van Moolenbroek 	     cfile -> token_line [i] && i < (cfile -> lexchar - 1); i++) {
5561*83ee113eSDavid van Moolenbroek 		if (lix < (sizeof lexbuf) - 1)
5562*83ee113eSDavid van Moolenbroek 			lexbuf [lix++] = ' ';
5563*83ee113eSDavid van Moolenbroek 		if (cfile -> token_line [i] == '\t') {
5564*83ee113eSDavid van Moolenbroek 			for (; lix < (sizeof lexbuf) - 1 && (lix & 7); lix++)
5565*83ee113eSDavid van Moolenbroek 				lexbuf [lix] = ' ';
5566*83ee113eSDavid van Moolenbroek 		}
5567*83ee113eSDavid van Moolenbroek 	}
5568*83ee113eSDavid van Moolenbroek 	lexbuf [lix] = 0;
5569*83ee113eSDavid van Moolenbroek 
5570*83ee113eSDavid van Moolenbroek #ifndef DEBUG
5571*83ee113eSDavid van Moolenbroek 	syslog (log_priority | LOG_ERR, "%s", mbuf);
5572*83ee113eSDavid van Moolenbroek 	syslog (log_priority | LOG_ERR, "%s", cfile -> token_line);
5573*83ee113eSDavid van Moolenbroek 	if (cfile -> lexchar < 81)
5574*83ee113eSDavid van Moolenbroek 		syslog (log_priority | LOG_ERR, "%s^", lexbuf);
5575*83ee113eSDavid van Moolenbroek #endif
5576*83ee113eSDavid van Moolenbroek 
5577*83ee113eSDavid van Moolenbroek 	if (log_perror) {
5578*83ee113eSDavid van Moolenbroek 		IGNORE_RET (write (STDERR_FILENO, mbuf, strlen (mbuf)));
5579*83ee113eSDavid van Moolenbroek 		IGNORE_RET (write (STDERR_FILENO, "\n", 1));
5580*83ee113eSDavid van Moolenbroek 		IGNORE_RET (write (STDERR_FILENO, cfile -> token_line,
5581*83ee113eSDavid van Moolenbroek 				   strlen (cfile -> token_line)));
5582*83ee113eSDavid van Moolenbroek 		IGNORE_RET (write (STDERR_FILENO, "\n", 1));
5583*83ee113eSDavid van Moolenbroek 		if (cfile -> lexchar < 81)
5584*83ee113eSDavid van Moolenbroek 			IGNORE_RET (write (STDERR_FILENO, lexbuf, lix));
5585*83ee113eSDavid van Moolenbroek 		IGNORE_RET (write (STDERR_FILENO, "^\n", 2));
5586*83ee113eSDavid van Moolenbroek 	}
5587*83ee113eSDavid van Moolenbroek 
5588*83ee113eSDavid van Moolenbroek 	cfile -> warnings_occurred = 1;
5589*83ee113eSDavid van Moolenbroek 
5590*83ee113eSDavid van Moolenbroek 	return 0;
5591*83ee113eSDavid van Moolenbroek }
5592*83ee113eSDavid van Moolenbroek 
5593*83ee113eSDavid van Moolenbroek struct expression *
parse_domain_list(struct parse * cfile,int compress)5594*83ee113eSDavid van Moolenbroek parse_domain_list(struct parse *cfile, int compress)
5595*83ee113eSDavid van Moolenbroek {
5596*83ee113eSDavid van Moolenbroek 	const char *val;
5597*83ee113eSDavid van Moolenbroek 	enum dhcp_token token = SEMI;
5598*83ee113eSDavid van Moolenbroek 	struct expression *t = NULL;
5599*83ee113eSDavid van Moolenbroek 	unsigned len, clen = 0;
5600*83ee113eSDavid van Moolenbroek 	int result;
5601*83ee113eSDavid van Moolenbroek 	unsigned char compbuf[256 * NS_MAXCDNAME];
5602*83ee113eSDavid van Moolenbroek 	const unsigned char *dnptrs[256], **lastdnptr;
5603*83ee113eSDavid van Moolenbroek 
5604*83ee113eSDavid van Moolenbroek 	memset(compbuf, 0, sizeof(compbuf));
5605*83ee113eSDavid van Moolenbroek 	memset(dnptrs, 0, sizeof(dnptrs));
5606*83ee113eSDavid van Moolenbroek 	dnptrs[0] = compbuf;
5607*83ee113eSDavid van Moolenbroek 	lastdnptr = &dnptrs[255];
5608*83ee113eSDavid van Moolenbroek 
5609*83ee113eSDavid van Moolenbroek 	do {
5610*83ee113eSDavid van Moolenbroek 		/* Consume the COMMA token if peeked. */
5611*83ee113eSDavid van Moolenbroek 		if (token == COMMA)
5612*83ee113eSDavid van Moolenbroek 			skip_token(&val, NULL, cfile);
5613*83ee113eSDavid van Moolenbroek 
5614*83ee113eSDavid van Moolenbroek 		/* Get next (or first) value. */
5615*83ee113eSDavid van Moolenbroek 		token = next_token(&val, &len, cfile);
5616*83ee113eSDavid van Moolenbroek 
5617*83ee113eSDavid van Moolenbroek 		if (token != STRING) {
5618*83ee113eSDavid van Moolenbroek 			parse_warn(cfile, "Expecting a domain string.");
5619*83ee113eSDavid van Moolenbroek 			return NULL;
5620*83ee113eSDavid van Moolenbroek 		}
5621*83ee113eSDavid van Moolenbroek 
5622*83ee113eSDavid van Moolenbroek 		/* If compression pointers are enabled, compress.  If not,
5623*83ee113eSDavid van Moolenbroek 		 * just pack the names in series into the buffer.
5624*83ee113eSDavid van Moolenbroek 		 */
5625*83ee113eSDavid van Moolenbroek 		if (compress) {
5626*83ee113eSDavid van Moolenbroek 			result = MRns_name_compress(val, compbuf + clen,
5627*83ee113eSDavid van Moolenbroek 						    sizeof(compbuf) - clen,
5628*83ee113eSDavid van Moolenbroek 						    dnptrs, lastdnptr);
5629*83ee113eSDavid van Moolenbroek 
5630*83ee113eSDavid van Moolenbroek 			if (result < 0) {
5631*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "Error compressing domain "
5632*83ee113eSDavid van Moolenbroek 						  "list: %m");
5633*83ee113eSDavid van Moolenbroek 				return NULL;
5634*83ee113eSDavid van Moolenbroek 			}
5635*83ee113eSDavid van Moolenbroek 
5636*83ee113eSDavid van Moolenbroek 			clen += result;
5637*83ee113eSDavid van Moolenbroek 		} else {
5638*83ee113eSDavid van Moolenbroek 			result = MRns_name_pton(val, compbuf + clen,
5639*83ee113eSDavid van Moolenbroek 						sizeof(compbuf) - clen);
5640*83ee113eSDavid van Moolenbroek 
5641*83ee113eSDavid van Moolenbroek 			/* result == 1 means the input was fully qualified.
5642*83ee113eSDavid van Moolenbroek 			 * result == 0 means the input wasn't.
5643*83ee113eSDavid van Moolenbroek 			 * result == -1 means bad things.
5644*83ee113eSDavid van Moolenbroek 			 */
5645*83ee113eSDavid van Moolenbroek 			if (result < 0) {
5646*83ee113eSDavid van Moolenbroek 				parse_warn(cfile, "Error assembling domain "
5647*83ee113eSDavid van Moolenbroek 						  "list: %m");
5648*83ee113eSDavid van Moolenbroek 				return NULL;
5649*83ee113eSDavid van Moolenbroek 			}
5650*83ee113eSDavid van Moolenbroek 
5651*83ee113eSDavid van Moolenbroek 			/*
5652*83ee113eSDavid van Moolenbroek 			 * We need to figure out how many bytes to increment
5653*83ee113eSDavid van Moolenbroek 			 * our buffer pointer since pton doesn't tell us.
5654*83ee113eSDavid van Moolenbroek 			 */
5655*83ee113eSDavid van Moolenbroek 			while (compbuf[clen] != 0)
5656*83ee113eSDavid van Moolenbroek 				clen += compbuf[clen] + 1;
5657*83ee113eSDavid van Moolenbroek 
5658*83ee113eSDavid van Moolenbroek 			/* Count the last label (0). */
5659*83ee113eSDavid van Moolenbroek 			clen++;
5660*83ee113eSDavid van Moolenbroek 		}
5661*83ee113eSDavid van Moolenbroek 
5662*83ee113eSDavid van Moolenbroek 		if (clen > sizeof(compbuf))
5663*83ee113eSDavid van Moolenbroek 			log_fatal("Impossible error at %s:%d", MDL);
5664*83ee113eSDavid van Moolenbroek 
5665*83ee113eSDavid van Moolenbroek 		token = peek_token(&val, NULL, cfile);
5666*83ee113eSDavid van Moolenbroek 	} while (token == COMMA);
5667*83ee113eSDavid van Moolenbroek 
5668*83ee113eSDavid van Moolenbroek 	if (!make_const_data(&t, compbuf, clen, 1, 1, MDL))
5669*83ee113eSDavid van Moolenbroek 		log_fatal("No memory for domain list object.");
5670*83ee113eSDavid van Moolenbroek 
5671*83ee113eSDavid van Moolenbroek 	return t;
5672*83ee113eSDavid van Moolenbroek }
5673*83ee113eSDavid van Moolenbroek 
5674