]> git.ipfire.org Git - thirdparty/dhcp.git/blame - common/parse.c
Add new option cache handling code.
[thirdparty/dhcp.git] / common / parse.c
CommitLineData
63115431
TL
1/* parse.c
2
3 Common parser code for dhcpd and dhclient. */
4
5/*
4761e04b 6 * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.
63115431
TL
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of The Internet Software Consortium nor the names
19 * of its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * This software has been written for the Internet Software Consortium
37 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
38 * Enterprises. To learn more about the Internet Software Consortium,
39 * see ``http://www.vix.com/isc''. To learn more about Vixie
40 * Enterprises, see ``http://www.vix.com''.
41 */
42
43#ifndef lint
44static char copyright[] =
be6be08d 45"$Id: parse.c,v 1.7 1998/06/25 03:07:51 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n";
63115431
TL
46#endif /* not lint */
47
48#include "dhcpd.h"
49#include "dhctoken.h"
50
51/* Skip to the semicolon ending the current statement. If we encounter
52 braces, the matching closing brace terminates the statement. If we
53 encounter a right brace but haven't encountered a left brace, return
54 leaving the brace in the token buffer for the caller. If we see a
55 semicolon and haven't seen a left brace, return. This lets us skip
56 over:
57
58 statement;
59 statement foo bar { }
60 statement foo bar { statement { } }
61 statement}
62
63 ...et cetera. */
64
65void skip_to_semi (cfile)
66 FILE *cfile;
67{
68 int token;
69 char *val;
70 int brace_count = 0;
71
72 do {
73 token = peek_token (&val, cfile);
74 if (token == RBRACE) {
75 if (brace_count) {
76 token = next_token (&val, cfile);
77 if (!--brace_count)
78 return;
79 } else
80 return;
81 } else if (token == LBRACE) {
82 brace_count++;
83 } else if (token == SEMI && !brace_count) {
84 token = next_token (&val, cfile);
85 return;
796ef008
TL
86 } else if (token == EOL) {
87 /* EOL only happens when parsing /etc/resolv.conf,
88 and we treat it like a semicolon because the
89 resolv.conf file is line-oriented. */
90 token = next_token (&val, cfile);
91 return;
63115431
TL
92 }
93 token = next_token (&val, cfile);
94 } while (token != EOF);
95}
96
97int parse_semi (cfile)
98 FILE *cfile;
99{
100 int token;
101 char *val;
102
103 token = next_token (&val, cfile);
104 if (token != SEMI) {
105 parse_warn ("semicolon expected.");
106 skip_to_semi (cfile);
107 return 0;
108 }
109 return 1;
110}
111
112/* string-parameter :== STRING SEMI */
113
114char *parse_string (cfile)
115 FILE *cfile;
116{
117 char *val;
118 int token;
119 char *s;
120
121 token = next_token (&val, cfile);
122 if (token != STRING) {
123 parse_warn ("filename must be a string");
124 skip_to_semi (cfile);
125 return (char *)0;
126 }
127 s = (char *)malloc (strlen (val) + 1);
128 if (!s)
129 error ("no memory for string %s.", val);
130 strcpy (s, val);
131
132 if (!parse_semi (cfile))
133 return (char *)0;
134 return s;
135}
136
be6be08d
TL
137/*
138 * hostname :== IDENTIFIER
139 * | IDENTIFIER DOT
140 * | hostname DOT IDENTIFIER
141 */
796ef008
TL
142
143char *parse_host_name (cfile)
144 FILE *cfile;
145{
146 char *val;
147 int token;
148 int len = 0;
149 char *s;
150 char *t;
151 pair c = (pair)0;
152
153 /* Read a dotted hostname... */
154 do {
155 /* Read a token, which should be an identifier. */
68dda014
TL
156 token = peek_token (&val, cfile);
157 if (!is_identifier (token) && token != NUMBER)
158 break;
796ef008 159 token = next_token (&val, cfile);
68dda014 160
796ef008
TL
161 /* Store this identifier... */
162 if (!(s = (char *)malloc (strlen (val) + 1)))
163 error ("can't allocate temp space for hostname.");
164 strcpy (s, val);
165 c = cons ((caddr_t)s, c);
166 len += strlen (s) + 1;
167 /* Look for a dot; if it's there, keep going, otherwise
168 we're done. */
169 token = peek_token (&val, cfile);
170 if (token == DOT)
171 token = next_token (&val, cfile);
172 } while (token == DOT);
173
174 /* Assemble the hostname together into a string. */
175 if (!(s = (char *)malloc (len)))
176 error ("can't allocate space for hostname.");
177 t = s + len;
178 *--t = 0;
179 while (c) {
180 pair cdr = c -> cdr;
181 int l = strlen ((char *)(c -> car));
182 t -= l;
183 memcpy (t, (char *)(c -> car), l);
184 /* Free up temp space. */
185 free (c -> car);
186 free (c);
187 c = cdr;
188 if (t != s)
189 *--t = '.';
190 }
191 return s;
192}
193
be6be08d
TL
194/* ip-addr-or-hostname :== ip-address | hostname
195 ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER
196
197 Parse an ip address or a hostname. If uniform is zero, put in
198 an expr_substring node to limit hostnames that evaluate to more
199 than one IP address. */
200
201struct expression *parse_ip_addr_or_hostname (cfile, uniform)
202 FILE *cfile;
203 int uniform;
204{
205 char *val;
206 int token;
207 unsigned char addr [4];
208 int len = sizeof addr;
209 char *name;
210 struct expression *rv;
211
212 token = peek_token (&val, cfile);
213 if (is_identifier (token)) {
214 name = parse_host_name (cfile);
215 if (!name)
216 return (struct expression *)0;
217 rv = make_host_lookup (name);
218 if (!uniform)
219 rv = make_limit (rv, 4);
220 } else if (token == NUMBER) {
221 if (!parse_numeric_aggregate (cfile, addr, &len, DOT, 10, 8))
222 return (struct expression *)0;
223 rv = make_const_data (addr, len, 0, 0);
224 } else {
225 if (token != RBRACE && token != LBRACE)
226 token = next_token (&val, cfile);
227 parse_warn ("%s (%d): expecting IP address or hostname",
228 val, token);
229 if (token != SEMI)
230 skip_to_semi (cfile);
231 return (struct expression *)0;
232 }
233
234 return rv;
235}
236
237/*
238 * ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER
239 */
240
796ef008
TL
241int parse_ip_addr (cfile, addr)
242 FILE *cfile;
243 struct iaddr *addr;
244{
245 char *val;
246 int token;
247
248 addr -> len = 4;
249 if (parse_numeric_aggregate (cfile, addr -> iabuf,
250 &addr -> len, DOT, 10, 8))
251 return 1;
252 return 0;
253}
254
be6be08d
TL
255/*
256 * hardware-parameter :== HARDWARE hardware-type colon-seperated-hex-list SEMI
257 * hardware-type :== ETHERNET | TOKEN_RING
258 */
63115431
TL
259
260void parse_hardware_param (cfile, hardware)
261 FILE *cfile;
262 struct hardware *hardware;
263{
264 char *val;
265 int token;
266 int hlen;
267 unsigned char *t;
268
269 token = next_token (&val, cfile);
270 switch (token) {
271 case ETHERNET:
272 hardware -> htype = HTYPE_ETHER;
273 break;
274 case TOKEN_RING:
275 hardware -> htype = HTYPE_IEEE802;
276 break;
277 default:
278 parse_warn ("expecting a network hardware type");
279 skip_to_semi (cfile);
280 return;
281 }
282
283 /* Parse the hardware address information. Technically,
284 it would make a lot of sense to restrict the length of the
285 data we'll accept here to the length of a particular hardware
286 address type. Unfortunately, there are some broken clients
287 out there that put bogus data in the chaddr buffer, and we accept
288 that data in the lease file rather than simply failing on such
289 clients. Yuck. */
290 hlen = 0;
291 t = parse_numeric_aggregate (cfile, (unsigned char *)0, &hlen,
292 COLON, 16, 8);
293 if (!t)
294 return;
295 if (hlen > sizeof hardware -> haddr) {
296 free (t);
297 parse_warn ("hardware address too long");
298 } else {
299 hardware -> hlen = hlen;
300 memcpy ((unsigned char *)&hardware -> haddr [0],
301 t, hardware -> hlen);
302 free (t);
303 }
304
305 token = next_token (&val, cfile);
306 if (token != SEMI) {
307 parse_warn ("expecting semicolon.");
308 skip_to_semi (cfile);
309 }
310}
311
312/* lease-time :== NUMBER SEMI */
313
314void parse_lease_time (cfile, timep)
315 FILE *cfile;
316 TIME *timep;
317{
318 char *val;
319 int token;
320
321 token = next_token (&val, cfile);
322 if (token != NUMBER) {
323 parse_warn ("Expecting numeric lease time");
324 skip_to_semi (cfile);
325 return;
326 }
327 convert_num ((unsigned char *)timep, val, 10, 32);
328 /* Unswap the number - convert_num returns stuff in NBO. */
329 *timep = ntohl (*timep); /* XXX */
330
331 parse_semi (cfile);
332}
333
334/* No BNF for numeric aggregates - that's defined by the caller. What
335 this function does is to parse a sequence of numbers seperated by
336 the token specified in seperator. If max is zero, any number of
337 numbers will be parsed; otherwise, exactly max numbers are
338 expected. Base and size tell us how to internalize the numbers
339 once they've been tokenized. */
340
341unsigned char *parse_numeric_aggregate (cfile, buf,
342 max, seperator, base, size)
343 FILE *cfile;
344 unsigned char *buf;
345 int *max;
346 int seperator;
347 int base;
348 int size;
349{
350 char *val;
351 int token;
352 unsigned char *bufp = buf, *s, *t;
353 int count = 0;
354 pair c = (pair)0;
355
356 if (!bufp && *max) {
357 bufp = (unsigned char *)malloc (*max * size / 8);
358 if (!bufp)
359 error ("can't allocate space for numeric aggregate");
360 } else
361 s = bufp;
362
363 do {
364 if (count) {
365 token = peek_token (&val, cfile);
366 if (token != seperator) {
367 if (!*max)
368 break;
369 if (token != RBRACE && token != LBRACE)
370 token = next_token (&val, cfile);
371 parse_warn ("too few numbers.");
372 if (token != SEMI)
373 skip_to_semi (cfile);
374 return (unsigned char *)0;
375 }
376 token = next_token (&val, cfile);
377 }
378 token = next_token (&val, cfile);
379
380 if (token == EOF) {
381 parse_warn ("unexpected end of file");
382 break;
383 }
384
385 /* Allow NUMBER_OR_NAME if base is 16. */
386 if (token != NUMBER &&
387 (base != 16 || token != NUMBER_OR_NAME)) {
388 parse_warn ("expecting numeric value.");
389 skip_to_semi (cfile);
390 return (unsigned char *)0;
391 }
392 /* If we can, convert the number now; otherwise, build
393 a linked list of all the numbers. */
394 if (s) {
395 convert_num (s, val, base, size);
396 s += size / 8;
397 } else {
398 t = (unsigned char *)malloc (strlen (val) + 1);
399 if (!t)
400 error ("no temp space for number.");
338303a4
TL
401 strcpy ((char *)t, val);
402 c = cons ((caddr_t)t, c);
63115431
TL
403 }
404 } while (++count != *max);
405
406 /* If we had to cons up a list, convert it now. */
407 if (c) {
408 bufp = (unsigned char *)malloc (count * size / 8);
409 if (!bufp)
410 error ("can't allocate space for numeric aggregate.");
411 s = bufp + count - size / 8;
412 *max = count;
413 }
414 while (c) {
415 pair cdr = c -> cdr;
416 convert_num (s, (char *)(c -> car), base, size);
417 s -= size / 8;
418 /* Free up temp space. */
419 free (c -> car);
420 free (c);
421 c = cdr;
422 }
423 return bufp;
424}
425
426void convert_num (buf, str, base, size)
427 unsigned char *buf;
428 char *str;
429 int base;
430 int size;
431{
432 char *ptr = str;
433 int negative = 0;
434 u_int32_t val = 0;
435 int tval;
436 int max;
437
438 if (*ptr == '-') {
439 negative = 1;
440 ++ptr;
441 }
442
443 /* If base wasn't specified, figure it out from the data. */
444 if (!base) {
445 if (ptr [0] == '0') {
446 if (ptr [1] == 'x') {
447 base = 16;
448 ptr += 2;
449 } else if (isascii (ptr [1]) && isdigit (ptr [1])) {
450 base = 8;
451 ptr += 1;
452 } else {
453 base = 10;
454 }
455 } else {
456 base = 10;
457 }
458 }
459
460 do {
461 tval = *ptr++;
462 /* XXX assumes ASCII... */
463 if (tval >= 'a')
464 tval = tval - 'a' + 10;
465 else if (tval >= 'A')
466 tval = tval - 'A' + 10;
467 else if (tval >= '0')
468 tval -= '0';
469 else {
470 warn ("Bogus number: %s.", str);
471 break;
472 }
473 if (tval >= base) {
474 warn ("Bogus number: %s: digit %d not in base %d\n",
475 str, tval, base);
476 break;
477 }
478 val = val * base + tval;
479 } while (*ptr);
480
481 if (negative)
482 max = (1 << (size - 1));
483 else
484 max = (1 << (size - 1)) + ((1 << (size - 1)) - 1);
485 if (val > max) {
486 switch (base) {
487 case 8:
488 warn ("value %s%o exceeds max (%d) for precision.",
489 negative ? "-" : "", val, max);
490 break;
491 case 16:
492 warn ("value %s%x exceeds max (%d) for precision.",
493 negative ? "-" : "", val, max);
494 break;
495 default:
496 warn ("value %s%u exceeds max (%d) for precision.",
497 negative ? "-" : "", val, max);
498 break;
499 }
500 }
501
502 if (negative) {
503 switch (size) {
504 case 8:
505 *buf = -(unsigned long)val;
506 break;
507 case 16:
508 putShort (buf, -(unsigned long)val);
509 break;
510 case 32:
511 putLong (buf, -(unsigned long)val);
512 break;
513 default:
514 warn ("Unexpected integer size: %d\n", size);
515 break;
516 }
517 } else {
518 switch (size) {
519 case 8:
520 *buf = (u_int8_t)val;
521 break;
522 case 16:
523 putUShort (buf, (u_int16_t)val);
524 break;
525 case 32:
526 putULong (buf, val);
527 break;
528 default:
529 warn ("Unexpected integer size: %d\n", size);
530 break;
531 }
532 }
533}
534
be6be08d
TL
535/*
536 * date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER
537 * NUMBER COLON NUMBER COLON NUMBER SEMI
538 *
539 * Dates are always in GMT; first number is day of week; next is
540 * year/month/day; next is hours:minutes:seconds on a 24-hour
541 * clock.
542 */
63115431
TL
543
544TIME parse_date (cfile)
545 FILE *cfile;
546{
547 struct tm tm;
548 int guess;
549 char *val;
550 int token;
551 static int months [11] = { 31, 59, 90, 120, 151, 181,
552 212, 243, 273, 304, 334 };
553
554 /* Day of week... */
555 token = next_token (&val, cfile);
556 if (token != NUMBER) {
557 parse_warn ("numeric day of week expected.");
558 if (token != SEMI)
559 skip_to_semi (cfile);
560 return (TIME)0;
561 }
562 tm.tm_wday = atoi (val);
563
564 /* Year... */
565 token = next_token (&val, cfile);
566 if (token != NUMBER) {
567 parse_warn ("numeric year expected.");
568 if (token != SEMI)
569 skip_to_semi (cfile);
570 return (TIME)0;
571 }
edca2b1a
TL
572
573 /* Note: the following is not a Y2K bug - it's a Y1.9K bug. Until
574 somebody invents a time machine, I think we can safely disregard
575 it. This actually works around a stupid Y2K bug that was present
576 in a very early beta release of dhcpd. */
63115431
TL
577 tm.tm_year = atoi (val);
578 if (tm.tm_year > 1900)
579 tm.tm_year -= 1900;
580
581 /* Slash seperating year from month... */
582 token = next_token (&val, cfile);
583 if (token != SLASH) {
584 parse_warn ("expected slash seperating year from month.");
585 if (token != SEMI)
586 skip_to_semi (cfile);
587 return (TIME)0;
588 }
589
590 /* Month... */
591 token = next_token (&val, cfile);
592 if (token != NUMBER) {
593 parse_warn ("numeric month expected.");
594 if (token != SEMI)
595 skip_to_semi (cfile);
596 return (TIME)0;
597 }
598 tm.tm_mon = atoi (val) - 1;
599
600 /* Slash seperating month from day... */
601 token = next_token (&val, cfile);
602 if (token != SLASH) {
603 parse_warn ("expected slash seperating month from day.");
604 if (token != SEMI)
605 skip_to_semi (cfile);
606 return (TIME)0;
607 }
608
609 /* Month... */
610 token = next_token (&val, cfile);
611 if (token != NUMBER) {
612 parse_warn ("numeric day of month expected.");
613 if (token != SEMI)
614 skip_to_semi (cfile);
615 return (TIME)0;
616 }
617 tm.tm_mday = atoi (val);
618
619 /* Hour... */
620 token = next_token (&val, cfile);
621 if (token != NUMBER) {
622 parse_warn ("numeric hour expected.");
623 if (token != SEMI)
624 skip_to_semi (cfile);
625 return (TIME)0;
626 }
627 tm.tm_hour = atoi (val);
628
629 /* Colon seperating hour from minute... */
630 token = next_token (&val, cfile);
631 if (token != COLON) {
632 parse_warn ("expected colon seperating hour from minute.");
633 if (token != SEMI)
634 skip_to_semi (cfile);
635 return (TIME)0;
636 }
637
638 /* Minute... */
639 token = next_token (&val, cfile);
640 if (token != NUMBER) {
641 parse_warn ("numeric minute expected.");
642 if (token != SEMI)
643 skip_to_semi (cfile);
644 return (TIME)0;
645 }
646 tm.tm_min = atoi (val);
647
648 /* Colon seperating minute from second... */
649 token = next_token (&val, cfile);
650 if (token != COLON) {
651 parse_warn ("expected colon seperating hour from minute.");
652 if (token != SEMI)
653 skip_to_semi (cfile);
654 return (TIME)0;
655 }
656
657 /* Minute... */
658 token = next_token (&val, cfile);
659 if (token != NUMBER) {
660 parse_warn ("numeric minute expected.");
661 if (token != SEMI)
662 skip_to_semi (cfile);
663 return (TIME)0;
664 }
665 tm.tm_sec = atoi (val);
666 tm.tm_isdst = 0;
667
668 /* XXX */ /* We assume that mktime does not use tm_yday. */
669 tm.tm_yday = 0;
670
671 /* Make sure the date ends in a semicolon... */
672 token = next_token (&val, cfile);
673 if (token != SEMI) {
674 parse_warn ("semicolon expected.");
675 skip_to_semi (cfile);
676 return 0;
677 }
678
679 /* Guess the time value... */
680 guess = ((((((365 * (tm.tm_year - 70) + /* Days in years since '70 */
796ef008 681 (tm.tm_year - 69) / 4 + /* Leap days since '70 */
63115431
TL
682 (tm.tm_mon /* Days in months this year */
683 ? months [tm.tm_mon - 1]
684 : 0) +
685 (tm.tm_mon > 1 && /* Leap day this year */
796ef008
TL
686 !((tm.tm_year - 72) & 3)) +
687 tm.tm_mday - 1) * 24) + /* Day of month */
63115431
TL
688 tm.tm_hour) * 60) +
689 tm.tm_min) * 60) + tm.tm_sec;
690
691 /* This guess could be wrong because of leap seconds or other
692 weirdness we don't know about that the system does. For
693 now, we're just going to accept the guess, but at some point
694 it might be nice to do a successive approximation here to
695 get an exact value. Even if the error is small, if the
696 server is restarted frequently (and thus the lease database
697 is reread), the error could accumulate into something
698 significant. */
699
700 return guess;
701}
4761e04b 702
be6be08d
TL
703/*
704 * option-name :== IDENTIFIER |
705 IDENTIFIER . IDENTIFIER
706 */
707
4761e04b
TL
708struct option *parse_option_name (cfile)
709 FILE *cfile;
710{
711 char *val;
712 int token;
713 char *vendor;
714 struct universe *universe;
715 struct option *option;
716
717 token = next_token (&val, cfile);
718 if (!is_identifier (token)) {
719 parse_warn ("expecting identifier after option keyword.");
720 if (token != SEMI)
721 skip_to_semi (cfile);
722 return (struct option *)0;
723 }
724 vendor = malloc (strlen (val) + 1);
725 if (!vendor)
726 error ("no memory for vendor information.");
727 strcpy (vendor, val);
728 token = peek_token (&val, cfile);
729 if (token == DOT) {
730 /* Go ahead and take the DOT token... */
731 token = next_token (&val, cfile);
732
733 /* The next token should be an identifier... */
734 token = next_token (&val, cfile);
735 if (!is_identifier (token)) {
736 parse_warn ("expecting identifier after '.'");
737 if (token != SEMI)
738 skip_to_semi (cfile);
739 return (struct option *)0;
740 }
741
742 /* Look up the option name hash table for the specified
743 vendor. */
744 universe = ((struct universe *)
745 hash_lookup (&universe_hash,
746 (unsigned char *)vendor, 0));
747 /* If it's not there, we can't parse the rest of the
748 declaration. */
749 if (!universe) {
750 parse_warn ("no vendor named %s.", vendor);
751 skip_to_semi (cfile);
752 return (struct option *)0;
753 }
754 } else {
755 /* Use the default hash table, which contains all the
756 standard dhcp option names. */
757 val = vendor;
758 universe = &dhcp_universe;
759 }
760
761 /* Look up the actual option info... */
762 option = (struct option *)hash_lookup (universe -> hash,
763 (unsigned char *)val, 0);
764
765 /* If we didn't get an option structure, it's an undefined option. */
766 if (!option) {
767 if (val == vendor)
768 parse_warn ("no option named %s", val);
769 else
770 parse_warn ("no option named %s for vendor %s",
771 val, vendor);
772 skip_to_semi (cfile);
773 return (struct option *)0;
774 }
775
776 /* Free the initial identifier token. */
777 free (vendor);
778 return option;
779}
780
be6be08d
TL
781/*
782 * colon-seperated-hex-list :== NUMBER |
783 * NUMBER COLON colon-seperated-hex-list
784 */
785
4761e04b
TL
786unsigned char *parse_cshl (cfile, plen)
787 FILE *cfile;
788 int *plen;
789{
790 char ibuf [128];
791 int ilen = 0;
792 int tlen = 0;
793 struct option_tag *sl = (struct option_tag *)0;
794 struct option_tag *next, **last = &sl;
795 int token;
796 char *val;
797 unsigned char *rv, *rvp;
798
799 do {
800 token = next_token (&val, cfile);
801 if (token != NUMBER && token != NUMBER_OR_NAME) {
802 parse_warn ("expecting hexadecimal number.");
803 skip_to_semi (cfile);
804 for (; sl; sl = next) {
805 next = sl -> next;
806 dfree (sl, "parse_cshl");
807 }
808 return (unsigned char *)0;
809 }
810 if (ilen == sizeof ibuf) {
811 next = (struct option_tag *)
812 dmalloc (ilen - 1 +
813 sizeof (struct option_tag),
814 "parse_cshl");
815 if (!next)
816 error ("no memory for string list.");
817 memcpy (next -> data, ibuf, ilen);
818 *last = next;
819 last = &next -> next;
820 tlen += ilen;
821 ilen = 0;
822 }
823 convert_num (&ibuf [ilen++], val, 16, 8);
824
825 token = peek_token (&val, cfile);
826 if (token != COLON)
827 break;
828 token = next_token (&val, cfile);
829 } while (1);
830
831 rv = dmalloc (tlen + ilen, "parse_cshl");
832 if (!rv)
833 error ("no memory to store octet data.");
834 rvp = rv;
835 while (sl) {
836 next = sl -> next;
837 memcpy (rvp, sl -> data, sizeof ibuf);
838 rvp += sizeof ibuf;
839 dfree (sl, "parse_cshl");
840 sl = next;
841 }
842
843 memcpy (rvp, ibuf, ilen);
844 *plen = ilen + tlen;
845 return rv;
846}
be6be08d
TL
847
848/*
849 * executable-statements :== executable-statement executable-statements |
850 * executable-statement
851 *
852 * executable-statement :==
853 * IF if-statement |
854 * ADD class-name SEMI |
855 * BREAK SEMI |
856 * OPTION option-parameter SEMI |
857 * SUPERSEDE option-parameter SEMI |
858 * PREPEND option-parameter SEMI |
859 * APPEND option-parameter SEMI
860 */
861
862struct executable_statement *parse_executable_statements (cfile, lose)
863 FILE *cfile;
864 int *lose;
865{
866 struct executable_statement *head, **next;
867
868 next = &head;
869 while ((*next = parse_executable_statement (cfile, lose)))
870 next = &((*next) -> next);
871 if (!lose)
872 return head;
873 return (struct executable_statement *)0;
874}
875
876struct executable_statement *parse_executable_statement (cfile, lose)
877 FILE *cfile;
878 int *lose;
879{
880 int token;
881 char *val;
882 struct executable_statement *stmt, base;
883 struct class *cta;
884 struct option *option;
885
886 switch (peek_token (&val, cfile)) {
887 case IF:
888 stmt = parse_if_statement (cfile, lose);
889 return stmt;
890 case ADD:
891 token = next_token (&val, cfile);
892 if (token != STRING) {
893 parse_warn ("expecting class name.");
894 skip_to_semi (cfile);
895 *lose = 1;
896 return (struct executable_statement *)0;
897 }
898 cta = find_class (val);
899 if (!cta) {
900 parse_warn ("unknown class %s.", val);
901 skip_to_semi (cfile);
902 *lose = 1;
903 return (struct executable_statement *)0;
904 }
905 if (!parse_semi (cfile)) {
906 *lose = 1;
907 return (struct executable_statement *)0;
908 }
909 memset (&base, 0, sizeof base);
910 base.op = add_statement;
911 base.data.add = cta;
912 break;
913
914 case BREAK:
915 token = next_token (&val, cfile);
916 if (!parse_semi (cfile)) {
917 *lose = 1;
918 return (struct executable_statement *)0;
919 }
920 memset (&base, 0, sizeof base);
921 base.op = break_statement;
922 break;
923
924 case OPTION:
925 token = next_token (&val, cfile);
926 option = parse_option_name (cfile);
927 if (!option) {
928 *lose = 1;
929 return (struct executable_statement *)0;
930 }
931 return parse_option_statement (cfile, 1, option,
932 supersede_option_statement);
933
934 case DEFAULT:
935 token = next_token (&val, cfile);
936 option = parse_option_name (cfile);
937 if (!option) {
938 *lose = 1;
939 return (struct executable_statement *)0;
940 }
941 return parse_option_statement (cfile, 1, option,
942 default_option_statement);
943
944 case PREPEND:
945 token = next_token (&val, cfile);
946 option = parse_option_name (cfile);
947 if (!option) {
948 *lose = 1;
949 return (struct executable_statement *)0;
950 }
951 return parse_option_statement (cfile, 1, option,
952 prepend_option_statement);
953
954 case APPEND:
955 token = next_token (&val, cfile);
956 option = parse_option_name (cfile);
957 if (!option) {
958 *lose = 1;
959 return (struct executable_statement *)0;
960 }
961 return parse_option_statement (cfile, 1, option,
962 append_option_statement);
963
964 default:
965 *lose = 0;
966 return (struct executable_statement *)0;
967 }
968
969 stmt = ((struct executable_statement *)
970 dmalloc (sizeof (struct executable_statement),
971 "parse_executable_statement"));
972 if (!stmt)
973 error ("no memory for new statement.");
974 *stmt = base;
975 return stmt;
976}
977
978/*
979 * if-statement :== boolean-expression LBRACE executable-statements RBRACE
980 * else-statement
981 *
982 * else-statement :== <null> |
983 * ELSE LBRACE executable-statements RBRACE |
984 * ELSE IF if-statement |
985 * ELSIF if-statement
986 */
987
988struct executable_statement *parse_if_statement (cfile, lose)
989 FILE *cfile;
990 int *lose;
991{
992 int token;
993 char *val;
994 struct executable_statement *stmt;
995 struct expression *if_condition;
996 struct executable_statement *true, *false;
997
998 token = next_token (&val, cfile);
999 if_condition = parse_boolean_expression (cfile, lose);
1000 if (!if_condition) {
1001 if (!*lose)
1002 parse_warn ("boolean expression expected.");
1003 return (struct executable_statement *)0;
1004 }
1005 token = next_token (&val, cfile);
1006 if (token != LBRACE) {
1007 parse_warn ("left brace expected.");
1008 skip_to_semi (cfile);
1009 *lose = 1;
1010 return (struct executable_statement *)0;
1011 }
1012 true = parse_executable_statements (cfile, lose);
1013 if (*lose)
1014 return (struct executable_statement *)0;
1015 token = next_token (&val, cfile);
1016 if (token != RBRACE) {
1017 parse_warn ("right brace expected.");
1018 skip_to_semi (cfile);
1019 *lose = 1;
1020 return (struct executable_statement *)0;
1021 }
1022 token = peek_token (&val, cfile);
1023 if (token == ELSE) {
1024 token = next_token (&val, cfile);
1025 token = peek_token (&val, cfile);
1026 if (token == IF) {
1027 token = next_token (&val, cfile);
1028 false = parse_if_statement (cfile, lose);
1029 if (*lose)
1030 return (struct executable_statement *)0;
1031 } else if (token != LBRACE) {
1032 parse_warn ("left brace or if expected.");
1033 skip_to_semi (cfile);
1034 *lose = 1;
1035 return (struct executable_statement *)0;
1036 } else {
1037 token = next_token (&val, cfile);
1038 false = parse_executable_statement (cfile, lose);
1039 if (*lose)
1040 return (struct executable_statement *)0;
1041 }
1042 } else if (token == ELSIF) {
1043 token = next_token (&val, cfile);
1044 false = parse_if_statement (cfile, lose);
1045 if (*lose)
1046 return (struct executable_statement *)0;
1047 } else
1048 false = (struct executable_statement *)0;
1049
1050 stmt = ((struct executable_statement *)
1051 dmalloc (sizeof (struct executable_statement),
1052 "parse_if_statement"));
1053 if (!stmt)
1054 error ("no memory for if statement.");
1055 memset (stmt, 0, sizeof *stmt);
1056 stmt -> op = if_statement;
1057 stmt -> data.ie.expr = if_condition;
1058 stmt -> data.ie.true = true;
1059 stmt -> data.ie.false = false;
1060 return stmt;
1061}
1062
1063/*
1064 * boolean_expression :== CHECK STRING |
1065 * NOT boolean-expression |
1066 * data-expression EQUAL data-expression |
1067 * boolean-expression AND boolean-expression |
1068 * boolean-expression OR boolean-expression
1069 */
1070
1071
1072struct expression *parse_boolean_expression (cfile, lose)
1073 FILE *cfile;
1074 int *lose;
1075{
1076 int token;
1077 char *val;
1078 struct collection *col;
1079 struct expression buf, *rv;
1080 struct expression *left, *right;
1081
1082 token = peek_token (&val, cfile);
1083
1084 /* Check for unary operators... */
1085 switch (token) {
1086 case CHECK:
1087 token = next_token (&val, cfile);
1088 token = next_token (&val, cfile);
1089 if (token != STRING) {
1090 parse_warn ("string expected.");
1091 skip_to_semi (cfile);
1092 *lose = 1;
1093 return (struct expression *)0;
1094 }
1095 for (col = collections; col; col = col -> next)
1096 if (!strcmp (col -> name, val))
1097 break;
1098 if (!col) {
1099 parse_warn ("unknown collection.");
1100 *lose = 1;
1101 return (struct expression *)0;
1102 }
1103 buf.op = expr_check;
1104 buf.data.check = col;
1105 goto have_expr;
1106
1107 case NOT:
1108 token = next_token (&val, cfile);
1109 buf.op = expr_not;
1110 buf.data.not = parse_boolean_expression (cfile, lose);
1111 if (!buf.data.not) {
1112 if (!*lose) {
1113 parse_warn ("match expression expected");
1114 skip_to_semi (cfile);
1115 }
1116 *lose = 1;
1117 return (struct expression *)0;
1118 }
1119 goto have_expr;
1120 }
1121
1122 /* If we're going to find an expression at this point, it must
1123 involve a binary operator seperating two subexpressions. */
1124 left = parse_data_expression (cfile, lose);
1125 if (!left)
1126 return left;
1127 token = peek_token (&val, cfile);
1128 switch (token) {
1129 case EQUAL:
1130 buf.op = expr_equal;
1131 break;
1132 case AND:
1133 buf.op = expr_and;
1134 break;
1135 case OR:
1136 buf.op = expr_or;
1137 break;
1138 default:
1139 parse_warn ("Expecting a boolean expression.");
1140 skip_to_semi (cfile);
1141 *lose = 1;
1142 return (struct expression *)0;
1143 }
1144 token = next_token (&val, cfile);
1145
1146 /* Now find the RHS of the expression. */
1147 right = parse_data_expression (cfile, lose);
1148 if (!right) {
1149 if (!*lose) {
1150 if (buf.op == expr_equal)
1151 parse_warn ("Expecting a data expression.");
1152 else
1153 parse_warn ("Expecting a boolean expression.");
1154 skip_to_semi (cfile);
1155 }
1156 return right;
1157 }
1158
1159 /* Store the LHS and RHS. */
1160 buf.data.equal [0] = left;
1161 buf.data.equal [1] = right;
1162
1163 have_expr:
1164 rv = new_expression ("parse_boolean_expression");
1165 if (!rv)
1166 error ("No memory for boolean expression.");
1167 *rv = buf;
1168 return rv;
1169}
1170
1171/*
1172 * data_expression :== SUBSTRING LPAREN data-expression COMMA
1173 * numeric-expression COMMA
1174 * numeric-expression RPAREN |
1175 * SUFFIX LPAREN data_expression COMMA
1176 * numeric-expression |
1177 * OPTION option_name |
1178 * HARDWARE |
1179 * PACKET LPAREN numeric-expression COMMA
1180 * numeric-expression RPAREN |
1181 * STRING |
1182 * colon_seperated_hex_list
1183 */
1184
1185struct expression *parse_data_expression (cfile, lose)
1186 FILE *cfile;
1187 int *lose;
1188{
1189 int token;
1190 char *val;
1191 struct collection *col;
1192 struct expression buf, *rv;
1193 struct expression *left, *right;
1194 struct option *option;
1195
1196 token = peek_token (&val, cfile);
1197
1198 switch (token) {
1199 case SUBSTRING:
1200 token = next_token (&val, cfile);
1201 buf.op = expr_substring;
1202
1203 token = next_token (&val, cfile);
1204 if (token != LPAREN) {
1205 nolparen:
1206 parse_warn ("left parenthesis expected.");
1207 *lose = 1;
1208 return (struct expression *)0;
1209 }
1210
1211 rv = parse_data_expression (cfile, lose);
1212 if (!rv) {
1213 nodata:
1214 parse_warn ("expecting data expression.");
1215 skip_to_semi (cfile);
1216 *lose = 1;
1217 return (struct expression *)0;
1218 }
1219
1220 token = next_token (&val, cfile);
1221 if (token != COMMA) {
1222 nocomma:
1223 parse_warn ("comma expected.");
1224 *lose = 1;
1225 return (struct expression *)0;
1226 }
1227
1228 left = parse_numeric_expression (cfile, lose);
1229 if (!left) {
1230 nonum:
1231 if (!*lose) {
1232 parse_warn ("expecting numeric expression.");
1233 skip_to_semi (cfile);
1234 *lose = 1;
1235 }
1236 return (struct expression *)0;
1237 }
1238
1239 token = next_token (&val, cfile);
1240 if (token != COMMA)
1241 goto nocomma;
1242
1243 right = parse_numeric_expression (cfile, lose);
1244 if (!right)
1245 goto nonum;
1246
1247 token = next_token (&val, cfile);
1248 if (token != RPAREN) {
1249 norparen:
1250 parse_warn ("right parenthesis expected.");
1251 *lose = 1;
1252 return (struct expression *)0;
1253 }
1254 return make_substring (rv, left, right);
1255
1256 case SUFFIX:
1257 token = next_token (&val, cfile);
1258 buf.op = expr_suffix;
1259
1260 token = next_token (&val, cfile);
1261 if (token != LPAREN)
1262 goto nolparen;
1263
1264 buf.data.suffix.expr = parse_data_expression (cfile, lose);
1265 if (!buf.data.suffix.expr)
1266 goto nodata;
1267
1268 token = next_token (&val, cfile);
1269 if (token != COMMA)
1270 goto nocomma;
1271
1272 buf.data.suffix.len = parse_numeric_expression (cfile, lose);
1273 if (!buf.data.suffix.len)
1274 goto nonum;
1275
1276 token = next_token (&val, cfile);
1277 if (token != RPAREN)
1278 goto norparen;
1279 goto have_expr;
1280
1281 case OPTION:
1282 token = next_token (&val, cfile);
1283 buf.op = expr_option;
1284 buf.data.option = parse_option_name (cfile);
1285 if (!buf.data.option) {
1286 *lose = 1;
1287 return (struct expression *)0;
1288 }
1289 goto have_expr;
1290
1291 case HARDWARE:
1292 token = next_token (&val, cfile);
1293 buf.op = expr_hardware;
1294 goto have_expr;
1295
1296 case PACKET:
1297 token = next_token (&val, cfile);
1298 buf.op = expr_packet;
1299
1300 token = next_token (&val, cfile);
1301 if (token != LPAREN)
1302 goto nolparen;
1303
1304 buf.data.packet.offset =
1305 parse_numeric_expression (cfile, lose);
1306 if (!buf.data.packet.offset)
1307 goto nonum;
1308
1309 token = next_token (&val, cfile);
1310 if (token != COMMA)
1311 goto nocomma;
1312
1313 buf.data.packet.len =
1314 parse_numeric_expression (cfile, lose);
1315 if (!buf.data.substring.len)
1316 goto nonum;
1317
1318 token = next_token (&val, cfile);
1319 if (token != RPAREN)
1320 goto norparen;
1321 goto have_expr;
1322
1323 case STRING:
1324 token = next_token (&val, cfile);
1325 return make_const_data (val, strlen (val), 1, 1);
1326
1327 case NUMBER:
1328 case NUMBER_OR_NAME:
1329 buf.op = expr_const_data;
1330 memset (&buf.data, 0, sizeof buf.data);
1331 buf.data.const_data.data =
1332 parse_cshl (cfile, &buf.data.const_data.len);
1333 goto have_expr;
1334
1335 default:
1336 return (struct expression *)0;
1337 }
1338
1339 have_expr:
1340 rv = (struct expression *)dmalloc (sizeof (struct expression),
1341 "parse_boolean_expression");
1342 if (!rv)
1343 error ("No memory for boolean expression.");
1344 *rv = buf;
1345 return rv;
1346}
1347
1348/*
1349 * numeric-expression :== EXTRACT_INT LPAREN data-expression
1350 * COMMA number RPAREN |
1351 * NUMBER
1352 */
1353
1354struct expression *parse_numeric_expression (cfile, lose)
1355 FILE *cfile;
1356 int *lose;
1357{
1358 int token;
1359 char *val;
1360 struct collection *col;
1361 struct expression buf, *rv;
1362 struct expression *left, *right;
1363 struct option *option;
1364
1365 token = peek_token (&val, cfile);
1366
1367 switch (token) {
1368 case EXTRACT_INT:
1369 token = next_token (&val, cfile);
1370
1371 token = next_token (&val, cfile);
1372 if (token != LPAREN) {
1373 parse_warn ("left parenthesis expected.");
1374 *lose = 1;
1375 return (struct expression *)0;
1376 }
1377
1378 buf.data.extract_int.expr =
1379 parse_data_expression (cfile, lose);
1380 if (!buf.data.extract_int.expr) {
1381 parse_warn ("expecting data expression.");
1382 skip_to_semi (cfile);
1383 *lose = 1;
1384 return (struct expression *)0;
1385 }
1386
1387 token = next_token (&val, cfile);
1388 if (token != COMMA) {
1389 parse_warn ("comma expected.");
1390 *lose = 1;
1391 return (struct expression *)0;
1392 }
1393
1394 token = next_token (&val, cfile);
1395 if (token != NUMBER) {
1396 parse_warn ("number expected.");
1397 *lose = 1;
1398 return (struct expression *)0;
1399 }
1400 buf.data.extract_int.width = (struct expression *)0;
1401 switch (atoi (val)) {
1402 case 8:
1403 buf.op = expr_extract_int8;
1404 break;
1405
1406 case 16:
1407 buf.op = expr_extract_int16;
1408 break;
1409
1410 case 32:
1411 buf.op = expr_extract_int32;
1412 break;
1413
1414 default:
1415 parse_warn ("unsupported integer size %d", atoi (val));
1416 *lose = 1;
1417 skip_to_semi (cfile);
1418 return (struct expression *)0;
1419 }
1420
1421 token = next_token (&val, cfile);
1422 if (token != RPAREN) {
1423 parse_warn ("right parenthesis expected.");
1424 *lose = 1;
1425 return (struct expression *)0;
1426 }
1427 goto have_expr;
1428
1429 case NUMBER:
1430 buf.op = expr_const_int;
1431 buf.data.const_int = atoi (val);
1432 goto have_expr;
1433
1434 default:
1435 return (struct expression *)0;
1436 }
1437
1438 have_expr:
1439 rv = (struct expression *)dmalloc (sizeof (struct expression),
1440 "parse_boolean_expression");
1441 if (!rv)
1442 error ("No memory for boolean expression.");
1443 *rv = buf;
1444 return rv;
1445}
1446
1447/* option-statement :== identifier DOT identifier <syntax> SEMI
1448 | identifier <syntax> SEMI
1449
1450 Option syntax is handled specially through format strings, so it
1451 would be painful to come up with BNF for it. However, it always
1452 starts as above and ends in a SEMI. */
1453
1454struct executable_statement *parse_option_statement (cfile, lookups,
1455 option, op)
1456 FILE *cfile;
1457 int lookups;
1458 struct option *option;
1459 enum statement_op op;
1460{
1461 char *val;
1462 int token;
1463 char *fmt;
1464 struct expression *expr = (struct expression *)0;
1465 int lose;
1466 struct executable_statement *stmt;
1467
1468 token = peek_token (&val, cfile);
1469 if (token == SEMI) {
1470 /* Eat the semicolon... */
1471 token = next_token (&val, cfile);
1472 expr = make_const_data (0, 0, 0, 0);
1473 goto done;
1474 }
1475
1476 /* See if there's a data expression, and if so, use it rather than
1477 the standard format. */
1478 expr = ((struct expression *)parse_data_expression (cfile, &lose));
1479
1480 /* Found a data expression, but it was bogus? */
1481 if (lose)
1482 return (struct executable_statement *)0;
1483
1484 /* We found one. */
1485 if (expr)
1486 goto done;
1487
1488 /* Parse the option data... */
1489 do {
1490 /* Set a flag if this is an array of a simple type (i.e.,
1491 not an array of pairs of IP addresses, or something
1492 like that. */
1493 int uniform = option -> format [1] == 'A';
1494
1495 for (fmt = option -> format; *fmt; fmt++) {
1496 if (*fmt == 'A')
1497 break;
1498 expr = parse_option_token (cfile, fmt,
1499 expr, uniform, lookups);
1500 }
1501 if (*fmt == 'A') {
1502 token = peek_token (&val, cfile);
1503 if (token == COMMA) {
1504 token = next_token (&val, cfile);
1505 continue;
1506 }
1507 break;
1508 }
1509 } while (*fmt == 'A');
1510
1511 done:
1512 token = next_token (&val, cfile);
1513 if (token != SEMI) {
1514 parse_warn ("semicolon expected.");
1515 skip_to_semi (cfile);
1516 return (struct executable_statement *)0;
1517 }
1518 stmt = ((struct executable_statement *)
1519 dmalloc (sizeof *stmt, "parse_option_statement"));
1520 stmt -> op = op;
1521 stmt -> data.option = option_cache (expr, option);
1522 return stmt;
1523}
1524
1525struct expression *parse_option_token (cfile, fmt, expr, uniform, lookups)
1526 FILE *cfile;
1527 char *fmt;
1528 struct expression *expr;
1529 int uniform;
1530 int lookups;
1531{
1532 char *val;
1533 int token;
1534 struct expression *t;
1535 unsigned char buf [4];
1536 int len;
1537 unsigned char *ob;
1538 struct iaddr addr;
1539
1540 switch (*fmt) {
1541 case 'X':
1542 token = peek_token (&val, cfile);
1543 if (token == NUMBER_OR_NAME || token == NUMBER) {
1544 ob = parse_cshl (cfile, &len);
1545 return make_concat (expr,
1546 make_const_data (ob, len, 0, 0));
1547 } else if (token == STRING) {
1548 token = next_token (&val, cfile);
1549 return make_concat (expr,
1550 make_const_data ((unsigned char *)
1551 val,
1552 strlen (val),
1553 1, 1));
1554 } else {
1555 parse_warn ("expecting string %s.",
1556 "or hexadecimal data");
1557 skip_to_semi (cfile);
1558 return (struct expression *)0;
1559 }
1560 break;
1561
1562 case 't': /* Text string... */
1563 token = next_token (&val, cfile);
1564 if (token != STRING && !is_identifier (token)) {
1565 parse_warn ("expecting string.");
1566 if (token != SEMI)
1567 skip_to_semi (cfile);
1568 return (struct expression *)0;
1569 }
1570 return make_concat (expr,
1571 make_const_data ((unsigned char *)
1572 val, strlen (val), 1, 1));
1573 break;
1574
1575 case 'I': /* IP address or hostname. */
1576 if (lookups)
1577 t = parse_ip_addr_or_hostname (cfile, uniform);
1578 else {
1579 if (!parse_ip_addr (cfile, &addr))
1580 return (struct expression *)0;
1581 t = make_const_data (addr.iabuf, addr.len, 0, 1);
1582 }
1583 if (!t)
1584 return (struct expression *)0;
1585 return make_concat (expr, t);
1586 break;
1587
1588 case 'L': /* Unsigned 32-bit integer... */
1589 case 'l': /* Signed 32-bit integer... */
1590 token = next_token (&val, cfile);
1591 if (token != NUMBER) {
1592 need_number:
1593 parse_warn ("expecting number.");
1594 if (token != SEMI)
1595 skip_to_semi (cfile);
1596 return (struct expression *)0;
1597 }
1598 convert_num (buf, val, 0, 32);
1599 return make_concat (expr, make_const_data (buf, 4, 0, 1));
1600 break;
1601 case 's': /* Signed 16-bit integer. */
1602 case 'S': /* Unsigned 16-bit integer. */
1603 token = next_token (&val, cfile);
1604 if (token != NUMBER)
1605 goto need_number;
1606 convert_num (buf, val, 0, 16);
1607 return make_concat (expr, make_const_data (buf, 2, 0, 1));
1608 break;
1609 case 'b': /* Signed 8-bit integer. */
1610 case 'B': /* Unsigned 8-bit integer. */
1611 token = next_token (&val, cfile);
1612 if (token != NUMBER)
1613 goto need_number;
1614 convert_num (buf, val, 0, 8);
1615 return make_concat (expr, make_const_data (buf, 1, 0, 1));
1616 break;
1617 case 'f': /* Boolean flag. */
1618 token = next_token (&val, cfile);
1619 if (!is_identifier (token)) {
1620 parse_warn ("expecting identifier.");
1621 bad_flag:
1622 if (token != SEMI)
1623 skip_to_semi (cfile);
1624 return (struct expression *)0;
1625 }
1626 if (!strcasecmp (val, "true")
1627 || !strcasecmp (val, "on"))
1628 buf [0] = 1;
1629 else if (!strcasecmp (val, "false")
1630 || !strcasecmp (val, "off"))
1631 buf [0] = 0;
1632 else {
1633 parse_warn ("expecting boolean.");
1634 goto bad_flag;
1635 }
1636 return make_concat (expr, make_const_data (buf, 1, 0, 1));
1637 break;
1638 default:
1639 warn ("Bad format %c in parse_option_param.",
1640 *fmt);
1641 skip_to_semi (cfile);
1642 return (struct expression *)0;
1643 }
1644}