]> git.ipfire.org Git - thirdparty/dhcp.git/blame - server/confpars.c
Fix bootp address initialization
[thirdparty/dhcp.git] / server / confpars.c
CommitLineData
d7837182
TL
1/* confpars.c
2
3 Parser for dhcpd config file... */
4
5/*
95821729
TL
6 * Copyright (c) 1995, 1996 The Internet Software Consortium.
7 * All rights reserved.
d7837182
TL
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[] =
45"@(#) Copyright (c) 1995 The Internet Software Consortium. All rights reserved.\n";
46#endif /* not lint */
47
48#include "dhcpd.h"
49#include "dhctoken.h"
50
51static TIME parsed_time;
52
53/* conf-file :== statements
54 declarations :== <nil> | declaration | declarations declaration */
55
56void readconf (void)
57{
58 FILE *cfile;
59 char *val;
60 int token;
61
62 /* Set up the initial dhcp option universe. */
63 initialize_universes ();
64
65 if ((cfile = fopen (_PATH_DHCPD_CONF, "r")) == NULL)
66 error ("Can't open %s: %m", _PATH_DHCPD_CONF);
67 do {
68 token = peek_token (&val, cfile);
69 if (token == EOF)
70 break;
71 parse_statement (cfile);
72 } while (1);
73}
74
75/* statement :== host_statement */
76
77void parse_statement (cfile)
78 FILE *cfile;
79{
80 char *val;
81 jmp_buf bc;
82
83 switch (next_token (&val, cfile)) {
84 case HOST:
85 if (!setjmp (bc)) {
86 struct host_decl *hd =
87 parse_host_statement (cfile, &bc);
88 if (hd) {
89 enter_host (hd);
90 }
91 }
92 break;
93 case LEASE:
94 if (!setjmp (bc)) {
95 struct lease *lease =
96 parse_lease_statement (cfile, &bc);
97 enter_lease (lease);
98 }
99 break;
100 case TIMESTAMP:
101 if (!setjmp (bc)) {
102 parsed_time = parse_timestamp (cfile, &bc);
103 }
104 break;
105 case RANGE:
106 if (!setjmp (bc)) {
107 parse_address_range (cfile, &bc);
108 }
109 break;
110 default:
111 parse_warn ("expecting a declaration.");
112 skip_to_semi (cfile);
113 break;
114 }
115}
116
117void skip_to_semi (cfile)
118 FILE *cfile;
119{
120 int token;
121 char *val;
122
123 do {
124 token = next_token (&val, cfile);
125 } while (token != SEMI && token != EOF);
126}
127
128/* host_statement :== HOST hostname declarations SEMI
129 host_declarations :== <nil> | host_declaration
089fb364 130 | host_declarations host_declaration SEMI */
d7837182
TL
131
132struct host_decl *parse_host_statement (cfile, bc)
133 FILE *cfile;
134 jmp_buf *bc;
135{
136 char *val;
137 int token;
138 struct host_decl tmp, *perm;
139
140 memset (&tmp, 0, sizeof tmp);
141 tmp.name = parse_host_name (cfile, bc);
142 do {
143 token = peek_token (&val, cfile);
144 if (token == SEMI) {
145 token = next_token (&val, cfile);
146 break;
147 }
148 parse_host_decl (cfile, bc, &tmp);
149 } while (1);
150 perm = (struct host_decl *)malloc (sizeof (struct host_decl));
151 if (!perm)
152 error ("can't allocate host decl struct for %s.", tmp.name);
153 *perm = tmp;
154 return perm;
155}
156
157/* host_name :== identifier | host_name DOT identifier */
158
159char *parse_host_name (cfile, bc)
160 FILE *cfile;
161 jmp_buf *bc;
162{
163 char *val;
164 int token;
165 int len = 0;
166 char *s;
167 char *t;
168 pair c = (pair)0;
169
170 /* Read a dotted hostname... */
171 do {
172 /* Read a token, which should be an identifier. */
173 token = next_token (&val, cfile);
174 if (!is_identifier (token)) {
089fb364 175 parse_warn ("expecting an identifier in hostname");
d7837182
TL
176 skip_to_semi (cfile);
177 longjmp (*bc, 1);
178 }
179 /* Store this identifier... */
180 if (!(s = (char *)malloc (strlen (val) + 1)))
181 error ("can't allocate temp space for hostname.");
182 strcpy (s, val);
183 c = cons ((caddr_t)s, c);
184 len += strlen (s) + 1;
185 /* Look for a dot; if it's there, keep going, otherwise
186 we're done. */
187 token = peek_token (&val, cfile);
188 if (token == DOT)
189 token = next_token (&val, cfile);
190 } while (token == DOT);
191
192 /* Assemble the hostname together into a string. */
193 if (!(s = (char *)malloc (len)))
194 error ("can't allocate space for hostname.");
195 t = s + len;
196 *--t = 0;
197 while (c) {
198 pair cdr = c -> cdr;
199 int l = strlen ((char *)(c -> car));
200 t -= l;
201 memcpy (t, (char *)(c -> car), l);
202 /* Free up temp space. */
203 free (c -> car);
204 free (c);
205 c = cdr;
206 if (t != s)
207 *--t = '.';
208 }
209 return s;
210}
211
212/* host_declaration :== hardware_declaration | filename_declaration
213 | fixed_addr_declaration | option_declaration */
214
215void parse_host_decl (cfile, bc, decl)
216 FILE *cfile;
217 jmp_buf *bc;
218 struct host_decl *decl;
219{
220 char *val;
221 int token;
222
223 token = next_token (&val, cfile);
224 switch (token) {
225 case HARDWARE:
226 parse_hardware_decl (cfile, bc, decl);
227 break;
228 case FILENAME:
229 parse_filename_decl (cfile, bc, decl);
230 break;
231 case FIXED_ADDR:
232 parse_fixed_addr_decl (cfile, bc, decl);
233 break;
234 case OPTION:
235 parse_option_decl (cfile, bc, decl);
236 break;
97ca1699
TL
237 case CIADDR:
238 decl -> ciaddr =
239 tree_cache (parse_ip_addr_or_hostname (cfile, bc, 0));
240 break;
241 case YIADDR:
242 decl -> yiaddr =
243 tree_cache (parse_ip_addr_or_hostname (cfile, bc, 0));
244 break;
245 case SIADDR:
246 decl -> siaddr =
247 tree_cache (parse_ip_addr_or_hostname (cfile, bc, 0));
248 break;
249 case GIADDR:
250 decl -> giaddr =
251 tree_cache (parse_ip_addr_or_hostname (cfile, bc, 0));
252 break;
d7837182
TL
253 default:
254 parse_warn ("expecting a dhcp option declaration.");
255 skip_to_semi (cfile);
256 longjmp (*bc, 1);
257 break;
258 }
259}
260
261/* hardware_decl :== HARDWARE ETHERNET NUMBER COLON NUMBER COLON NUMBER COLON
262 NUMBER COLON NUMBER COLON NUMBER */
263
264void parse_hardware_decl (cfile, bc, decl)
265 FILE *cfile;
266 jmp_buf *bc;
267 struct host_decl *decl;
268{
269 char *val;
270 int token;
271 struct hardware hw;
272
273 hw = parse_hardware_addr (cfile, bc);
274
275 /* Find space for the new interface... */
276 if (decl -> interfaces) {
277 decl -> interfaces =
278 (struct hardware *)realloc (decl -> interfaces,
279 ++decl -> interface_count *
280 sizeof (struct hardware));
281 } else {
282 decl -> interfaces =
283 (struct hardware *)malloc (sizeof (struct hardware));
284 decl -> interface_count = 1;
285 }
286 if (!decl -> interfaces)
287 error ("no memory for hardware interface info.");
288
289 /* Copy out the information... */
290 decl -> interfaces [decl -> interface_count - 1].htype = hw.htype;
291 decl -> interfaces [decl -> interface_count - 1].hlen = hw.hlen;
292 memcpy (decl -> interfaces [decl -> interface_count - 1].haddr,
293 &hw.haddr, hw.hlen);
294}
295
296struct hardware parse_hardware_addr (cfile, bc)
297 FILE *cfile;
298 jmp_buf *bc;
299{
300 char *val;
301 int token;
302 int hlen;
303 struct hardware rv;
304
305 token = next_token (&val, cfile);
306 switch (token) {
307 case ETHERNET:
308 rv.htype = ARPHRD_ETHER;
309 hlen = 6;
310 parse_numeric_aggregate (cfile, bc,
311 (unsigned char *)&rv.haddr, &hlen,
312 COLON, 16, 8);
313 rv.hlen = hlen;
314 break;
315 default:
316 parse_warn ("expecting a network hardware type");
317 skip_to_semi (cfile);
318 longjmp (*bc, 1);
319 }
320 return rv;
321}
322
323/* filename_decl :== FILENAME STRING */
324
325void parse_filename_decl (cfile, bc, decl)
326 FILE *cfile;
327 jmp_buf *bc;
328 struct host_decl *decl;
329{
330 char *val;
331 int token;
332 char *s;
333
334 token = next_token (&val, cfile);
335 if (token != STRING) {
336 parse_warn ("filename must be a string");
337 skip_to_semi (cfile);
338 longjmp (*bc, 1);
339 }
340 s = (char *)malloc (strlen (val));
341 if (!s)
342 error ("no memory for filename.");
343 strcpy (s, val);
344 decl -> filename = s;
345}
346
347/* ip_addr_or_hostname :== ip_address | hostname
348 ip_address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER
349
350 Parse an ip address or a hostname. If uniform is zero, put in
351 a TREE_LIMIT node to catch hostnames that evaluate to more than
352 one IP address. */
353
354struct tree *parse_ip_addr_or_hostname (cfile, bc, uniform)
355 FILE *cfile;
356 jmp_buf *bc;
357 int uniform;
358{
359 char *val;
360 int token;
361 unsigned char addr [4];
362 int len = sizeof addr;
363 char *name;
364 struct tree *rv;
365
366 token = peek_token (&val, cfile);
367 if (is_identifier (token)) {
368 name = parse_host_name (cfile, bc);
369 rv = tree_host_lookup (name);
370 if (!uniform)
371 rv = tree_limit (rv, 4);
372 } else if (token == NUMBER) {
373 parse_numeric_aggregate (cfile, bc, addr, &len, DOT, 10, 8);
374 rv = tree_const (addr, len);
375 } else {
376 parse_warn ("%s (%d): expecting IP address or hostname",
377 val, token);
378 skip_to_semi (cfile);
379 longjmp (*bc, 1);
380 }
381 return rv;
382}
383
384
385/* fixed_addr_declaration :== FIXED_ADDR ip_addr_or_hostname */
386
387void parse_fixed_addr_decl (cfile, bc, decl)
388 FILE *cfile;
389 jmp_buf *bc;
390 struct host_decl *decl;
391{
392 decl -> fixed_addr =
393 tree_cache (parse_ip_addr_or_hostname (cfile, bc, 0));
394}
395
396/* option_declaration :== OPTION identifier DOT identifier <syntax> |
397 OPTION identifier <syntax>
398
399 Option syntax is handled specially through format strings, so it
400 would be painful to come up with BNF for it. However, it always
401 starts as above. */
402
403void parse_option_decl (cfile, bc, decl)
404 FILE *cfile;
405 jmp_buf *bc;
406 struct host_decl *decl;
407{
408 char *val;
409 int token;
410 unsigned char buf [4];
411 char *vendor;
412 char *fmt;
413 struct universe *universe;
414 struct option *option;
415 struct tree *tree = (struct tree *)0;
416
417 token = next_token (&val, cfile);
418 if (!is_identifier (token)) {
419 parse_warn ("expecting identifier after option keyword.");
420 if (token != SEMI)
421 skip_to_semi (cfile);
422 longjmp (*bc, 1);
423 }
424 vendor = dmalloc (strlen (val) + 1, "parse_option_decl");
425 strcpy (vendor, val);
426 token = peek_token (&val, cfile);
427 if (token == DOT) {
428 /* Go ahead and take the DOT token... */
429 token = next_token (&val, cfile);
430
431 /* The next token should be an identifier... */
432 token = next_token (&val, cfile);
433 if (!is_identifier (token)) {
434 parse_warn ("expecting identifier after '.'");
435 if (token != SEMI)
436 skip_to_semi (cfile);
437 longjmp (*bc, 1);
438 }
439
440 /* Look up the option name hash table for the specified
441 vendor. */
442 universe = (struct universe *)hash_lookup (&universe_hash,
443 vendor, 0);
444 /* If it's not there, we can't parse the rest of the
445 statement. */
446 if (!universe) {
447 parse_warn ("no vendor named %s.", vendor);
448 skip_to_semi (cfile);
449 longjmp (*bc, 1);
450 }
451 } else {
452 /* Use the default hash table, which contains all the
453 standard dhcp option names. */
454 val = vendor;
455 universe = &dhcp_universe;
456 }
457
458 /* Look up the actual option info... */
459 option = (struct option *)hash_lookup (universe -> hash, val, 0);
460
461 /* If we didn't get an option structure, it's an undefined option. */
462 if (!option) {
463 if (val == vendor)
464 parse_warn ("no option named %s", val);
465 else
466 parse_warn ("no option named %s for vendor %s",
467 val, vendor);
468 skip_to_semi (cfile);
469 longjmp (*bc, 1);
470 }
471
472 /* Free the initial identifier token. */
473 free (vendor);
474
475 /* Parse the option data... */
476 do {
477 /* Set a flag if this is an array of a simple type (i.e.,
478 not an array of pairs of IP addresses, or something
479 like that. */
480 int uniform = option -> format [1] == 'A';
481
482 for (fmt = option -> format; *fmt; fmt++) {
483 if (*fmt == 'A')
484 break;
485 switch (*fmt) {
486 case 't': /* Text string... */
487 token = next_token (&val, cfile);
488 if (token != STRING
489 && !is_identifier (token)) {
490 parse_warn ("expecting string.");
491 if (token != SEMI)
492 skip_to_semi (cfile);
493 longjmp (*bc, 1);
494 }
495 tree = tree_concat (tree,
496 tree_const (val,
497 strlen (val)));
498 break;
499
500 case 'I': /* IP address or hostname. */
501 tree = tree_concat (tree,
502 parse_ip_addr_or_hostname
503 (cfile, bc, uniform));
504 break;
505
506 case 'L': /* Unsigned 32-bit integer... */
507 case 'l': /* Signed 32-bit integer... */
508 token = next_token (&val, cfile);
509 if (token != NUMBER) {
510 need_number:
511 parse_warn ("expecting number.");
512 if (token != SEMI)
513 skip_to_semi (cfile);
514 longjmp (*bc, 1);
515 }
516 convert_num (buf, val, 0, 32);
517 tree = tree_concat (tree, tree_const (buf, 4));
518 break;
519 case 's': /* Signed 16-bit integer. */
520 case 'S': /* Unsigned 16-bit integer. */
521 token = next_token (&val, cfile);
522 if (token != NUMBER)
523 goto need_number;
524 convert_num (buf, val, 0, 16);
525 tree = tree_concat (tree, tree_const (buf, 2));
526 break;
527 case 'b': /* Signed 8-bit integer. */
528 case 'B': /* Unsigned 8-bit integer. */
529 token = next_token (&val, cfile);
530 if (token != NUMBER)
531 goto need_number;
532 convert_num (buf, val, 0, 8);
533 tree = tree_concat (tree, tree_const (buf, 1));
534 break;
535 case 'f': /* Boolean flag. */
536 token = next_token (&val, cfile);
537 if (!is_identifier (token)) {
538 parse_warn ("expecting identifier.");
539 bad_flag:
540 if (token != SEMI)
541 skip_to_semi (cfile);
542 longjmp (*bc, 1);
543 }
544 if (!strcasecmp (val, "true")
545 || !strcasecmp (val, "on"))
546 buf [0] = 1;
547 else if (!strcasecmp (val, "false")
548 || !strcasecmp (val, "off"))
549 buf [0] = 0;
550 else {
551 parse_warn ("expecting boolean.");
552 goto bad_flag;
553 }
554 tree = tree_concat (tree, tree_const (buf, 1));
555 break;
556 default:
557 warn ("Bad format %c in parse_option_decl.",
558 *fmt);
559 skip_to_semi (cfile);
560 longjmp (*bc, 1);
561 }
562 }
563 if (*fmt == 'A') {
564 token = peek_token (&val, cfile);
565 if (token == COMMA) {
566 token = next_token (&val, cfile);
567 continue;
568 }
569 break;
570 }
571 } while (*fmt == 'A');
572
573 if (decl -> options [option -> code]) {
574 parse_warn ("duplicate option code %d (%s).",
575 option -> code, option -> name);
576 }
577 decl -> options [option -> code] = tree_cache (tree);
578}
579
089fb364 580/* timestamp :== TIMESTAMP date SEMI
d7837182
TL
581
582 Timestamps are actually not used in dhcpd.conf, which is a static file,
583 but rather in the database file and the journal file. */
584
585TIME parse_timestamp (cfile, bc)
586 FILE *cfile;
587 jmp_buf *bc;
588{
089fb364
TL
589 TIME rv;
590 char *val;
591 int token;
592
593 rv = parse_date (cfile, bc);
594 token = next_token (&val, cfile);
595 if (token != SEMI) {
596 parse_warn ("semicolon expected");
597 skip_to_semi (cfile);
598 longjmp (*bc, 1);
599 }
600 return rv;
d7837182
TL
601}
602
089fb364 603/* lease_decl :== LEASE ip_address lease_modifiers SEMI
d7837182
TL
604 lease_modifiers :== <nil>
605 | lease_modifier
606 | lease_modifier lease_modifiers
607 lease_modifier :== STARTS date
608 | ENDS date
609 | UID hex_numbers
610 | HOST identifier
611 | CLASS identifier
612 | TIMESTAMP number */
613
614struct lease *parse_lease_statement (cfile, bc)
615 FILE *cfile;
616 jmp_buf *bc;
617{
618 char *val;
619 int token;
620 unsigned char addr [4];
621 int len = sizeof addr;
622 char *name;
623 unsigned char *uid;
624 int seenmask = 0;
625 int seenbit;
626 char tbuf [32];
627 char ubuf [1024];
628 static struct lease lease;
629
630 /* Get the address for which the lease has been issued. */
631 parse_numeric_aggregate (cfile, bc, addr, &len, DOT, 10, 8);
089fb364
TL
632 memcpy (lease.ip_addr.iabuf, addr, len);
633 lease.ip_addr.len = len;
d7837182
TL
634
635 do {
636 token = next_token (&val, cfile);
637 if (token == SEMI)
638 break;
639 strncpy (val, tbuf, sizeof tbuf);
640 tbuf [(sizeof tbuf) - 1] = 0;
641
642 /* Parse any of the times associated with the lease. */
643 if (token == STARTS || token == ENDS || token == TIMESTAMP) {
644 TIME t;
645 t = parse_date (cfile, bc);
646 switch (token) {
647 case STARTS:
648 seenbit = 1;
649 lease.starts = t;
650 break;
651
652 case ENDS:
653 seenbit = 2;
654 lease.ends = t;
655 break;
656
657 case TIMESTAMP:
658 seenbit = 4;
659 lease.timestamp = t;
660 break;
661 }
662 } else {
663 switch (token) {
664 /* Colon-seperated hexadecimal octets... */
665 case UID:
666 seenbit = 8;
667 lease.uid_len = 0;
668 parse_numeric_aggregate (cfile, bc, ubuf,
669 &lease.uid_len,
670 ':', 16, 8);
671 lease.uid = (unsigned char *)
672 malloc (lease.uid_len);
673 if (!lease.uid) {
674 error ("No memory for lease uid");
675 }
676 memcpy (lease.uid, ubuf, lease.uid_len);
677 break;
678
679 case HOST:
680 seenbit = 16;
681 token = next_token (&val, cfile);
682 if (!is_identifier (token)) {
683 if (token != SEMI)
684 skip_to_semi (cfile);
685 longjmp (*bc, 1);
686 }
687 lease.host =
688 find_host_by_name (val);
689 if (!lease.host)
690 parse_warn ("lease host ``%s'' is %s",
089fb364 691 val,
d7837182
TL
692 "no longer known.");
693 break;
694
695 case CLASS:
696 seenbit = 32;
697 token = next_token (&val, cfile);
698 if (!is_identifier (token)) {
699 if (token != SEMI)
700 skip_to_semi (cfile);
701 longjmp (*bc, 1);
702 }
703 /* for now, we aren't using this. */
704 break;
705
706 case HARDWARE:
707 seenbit = 64;
708 lease.hardware_addr
709 = parse_hardware_addr (cfile, bc);
710 break;
711
712 default:
713 if (token != SEMI)
714 skip_to_semi (cfile);
715 longjmp (*bc, 1);
716 }
717 }
718 if (seenmask & seenbit) {
719 parse_warn ("Too many %s declarations in lease %s\n",
089fb364 720 tbuf, piaddr (lease.ip_addr));
d7837182
TL
721 } else
722 seenmask |= seenbit;
723 } while (1);
724 return &lease;
725}
726
089fb364 727/* address_range :== RANGE ip_address ip_address ip_address SEMI */
d7837182
TL
728
729void parse_address_range (cfile, bc)
730 FILE *cfile;
731 jmp_buf *bc;
732{
089fb364 733 struct iaddr low, high, mask;
d7837182
TL
734 unsigned char addr [4];
735 int len = sizeof addr;
089fb364
TL
736 int token;
737 char *val;
d7837182
TL
738
739 /* Get the bottom address in the range... */
740 parse_numeric_aggregate (cfile, bc, addr, &len, DOT, 10, 8);
089fb364
TL
741 memcpy (low.iabuf, addr, len);
742 low.len = len;
d7837182
TL
743
744 /* Get the top address in the range... */
745 parse_numeric_aggregate (cfile, bc, addr, &len, DOT, 10, 8);
089fb364
TL
746 memcpy (high.iabuf, addr, len);
747 high.len = len;
d7837182
TL
748
749 /* Get the netmask of the subnet containing the range... */
750 parse_numeric_aggregate (cfile, bc, addr, &len, DOT, 10, 8);
089fb364
TL
751 memcpy (mask.iabuf, addr, len);
752 mask.len = len;
753
754 /* Snarf the semi... */
755 token = next_token (&val, cfile);
756 if (token != SEMI) {
757 parse_warn ("semicolon expected");
758 skip_to_semi (cfile);
759 longjmp (*bc, 1);
760 }
d7837182
TL
761
762 /* Create the new address range... */
763 new_address_range (low, high, mask);
764}
765
766/* date :== NUMBER NUMBER/NUMBER/NUMBER NUMBER:NUMBER:NUMBER
767
768 Dates are always in GMT; first number is day of week; next is
769 year/month/day; next is hours:minutes:seconds on a 24-hour
770 clock. */
771
772TIME parse_date (cfile, bc)
773 FILE *cfile;
774 jmp_buf *bc;
775{
776 TIME t;
777 struct tm tm;
778 char *val;
779 int token;
780
781 /* Day of week... */
782 token = next_token (&val, cfile);
783 if (token != NUMBER) {
784 parse_warn ("numeric day of week expected.");
785 if (token != SEMI)
786 skip_to_semi (cfile);
787 longjmp (*bc, 1);
788 }
089fb364 789 tm.tm_wday = atoi (val);
d7837182
TL
790
791 /* Year... */
792 token = next_token (&val, cfile);
793 if (token != NUMBER) {
794 parse_warn ("numeric year expected.");
795 if (token != SEMI)
796 skip_to_semi (cfile);
797 longjmp (*bc, 1);
798 }
089fb364 799 tm.tm_year = atoi (val);
d7837182
TL
800 if (tm.tm_year > 1900)
801 tm.tm_year -= 1900;
802
803 /* Slash seperating year from month... */
804 token = next_token (&val, cfile);
805 if (token != SLASH) {
806 parse_warn ("expected slash seperating year from month.");
807 if (token != SEMI)
808 skip_to_semi (cfile);
809 longjmp (*bc, 1);
810 }
811
812 /* Month... */
813 token = next_token (&val, cfile);
814 if (token != NUMBER) {
815 parse_warn ("numeric month expected.");
816 if (token != SEMI)
817 skip_to_semi (cfile);
818 longjmp (*bc, 1);
819 }
089fb364 820 tm.tm_mon = atoi (val);
d7837182
TL
821
822 /* Slash seperating month from day... */
823 token = next_token (&val, cfile);
824 if (token != SLASH) {
825 parse_warn ("expected slash seperating month from day.");
826 if (token != SEMI)
827 skip_to_semi (cfile);
828 longjmp (*bc, 1);
829 }
830
831 /* Month... */
832 token = next_token (&val, cfile);
833 if (token != NUMBER) {
834 parse_warn ("numeric day of month expected.");
835 if (token != SEMI)
836 skip_to_semi (cfile);
837 longjmp (*bc, 1);
838 }
089fb364 839 tm.tm_mday = atoi (val);
d7837182
TL
840
841 /* Hour... */
842 token = next_token (&val, cfile);
843 if (token != NUMBER) {
844 parse_warn ("numeric hour expected.");
845 if (token != SEMI)
846 skip_to_semi (cfile);
847 longjmp (*bc, 1);
848 }
089fb364 849 tm.tm_hour = atoi (val);
d7837182
TL
850
851 /* Colon seperating hour from minute... */
852 token = next_token (&val, cfile);
853 if (token != COLON) {
854 parse_warn ("expected colon seperating hour from minute.");
855 if (token != SEMI)
856 skip_to_semi (cfile);
857 longjmp (*bc, 1);
858 }
859
860 /* Minute... */
861 token = next_token (&val, cfile);
862 if (token != NUMBER) {
863 parse_warn ("numeric minute expected.");
864 if (token != SEMI)
865 skip_to_semi (cfile);
866 longjmp (*bc, 1);
867 }
089fb364 868 tm.tm_min = atoi (val);
d7837182
TL
869
870 /* Colon seperating minute from second... */
871 token = next_token (&val, cfile);
872 if (token != COLON) {
873 parse_warn ("expected colon seperating hour from minute.");
874 if (token != SEMI)
875 skip_to_semi (cfile);
876 longjmp (*bc, 1);
877 }
878
879 /* Minute... */
880 token = next_token (&val, cfile);
881 if (token != NUMBER) {
882 parse_warn ("numeric minute expected.");
883 if (token != SEMI)
884 skip_to_semi (cfile);
885 longjmp (*bc, 1);
886 }
089fb364 887 tm.tm_sec = atoi (val);
d7837182
TL
888
889 tm.tm_zone = "GMT";
890 tm.tm_isdst = 0;
891 tm.tm_gmtoff = 0;
892
893 /* XXX */ /* We assume that mktime does not use tm_yday. */
894 tm.tm_yday = 0;
895
896 return mktime (&tm);
897}
898
899/* No BNF for numeric aggregates - that's defined by the caller. What
900 this function does is to parse a sequence of numbers seperated by
901 the token specified in seperator. If max is zero, any number of
902 numbers will be parsed; otherwise, exactly max numbers are
903 expected. Base and size tell us how to internalize the numbers
904 once they've been tokenized. */
905
906unsigned char *parse_numeric_aggregate (cfile, bc, buf,
907 max, seperator, base, size)
908 FILE *cfile;
909 jmp_buf *bc;
910 unsigned char *buf;
911 int *max;
912 int seperator;
913 int base;
914 int size;
915{
916 char *val;
917 int token;
918 unsigned char *bufp = buf, *s, *t;
919 int count = 0;
920 pair c = (pair)0;
921
922 if (!bufp && *max) {
923 bufp = (unsigned char *)malloc (*max * size / 8);
924 if (!bufp)
925 error ("can't allocate space for numeric aggregate");
926 } else
927 s = bufp;
928
929 do {
930 if (count) {
931 token = peek_token (&val, cfile);
932 if (token != seperator) {
933 if (!*max)
934 break;
935 parse_warn ("too few numbers.");
936 skip_to_semi (cfile);
937 longjmp (*bc, 1);
938 }
939 token = next_token (&val, cfile);
940 }
941 token = next_token (&val, cfile);
942 /* Allow NUMBER_OR_ATOM if base is 16. */
943 if (token != NUMBER &&
944 (base != 16 || token != NUMBER_OR_ATOM)) {
945 parse_warn ("expecting numeric value.");
946 skip_to_semi (cfile);
947 longjmp (*bc, 1);
948 }
949 /* If we can, convert the number now; otherwise, build
950 a linked list of all the numbers. */
951 if (s) {
952 convert_num (s, val, base, size);
953 s += size / 8;
954 } else {
955 t = (char *)malloc (strlen (val) + 1);
956 if (!t)
957 error ("no temp space for number.");
958 strcpy (t, val);
959 c = cons (t, c);
960 }
961 } while (++count != *max);
962
963 /* If we had to cons up a list, convert it now. */
964 if (c) {
965 bufp = (unsigned char *)malloc (count * size / 8);
966 if (!bufp)
967 error ("can't allocate space for numeric aggregate.");
968 s = bufp;
969 *max = count;
970 }
971 while (c) {
972 pair cdr = c -> cdr;
973 convert_num (s, (char *)(c -> car), base, size);
974 s += size / 8;
975 /* Free up temp space. */
976 free (c -> car);
977 free (c);
978 c = cdr;
979 }
980 return bufp;
981}
982
983void convert_num (buf, str, base, size)
984 unsigned char *buf;
985 char *str;
986 int base;
987 int size;
988{
989 char *ptr = str;
990 int negative = 0;
991 u_int32_t val = 0;
992 int tval;
993 int max;
994
995 if (*ptr == '-') {
996 negative = 1;
997 ++ptr;
998 }
999
1000 /* If base wasn't specified, figure it out from the data. */
1001 if (!base) {
1002 if (ptr [0] == '0') {
1003 if (ptr [1] == 'x') {
1004 base = 16;
1005 ptr += 2;
1006 } else if (isascii (ptr [1]) && isdigit (ptr [1])) {
1007 base = 8;
1008 ptr += 1;
1009 } else {
1010 base = 10;
1011 }
1012 } else {
1013 base = 10;
1014 }
1015 }
1016
1017 do {
1018 tval = *ptr++;
1019 /* XXX assumes ASCII... */
1020 if (tval >= 'a')
1021 tval = tval - 'a' + 10;
1022 else if (tval >= 'A')
1023 tval = tval - 'A' + 10;
1024 else if (tval >= '0')
1025 tval -= '0';
1026 else {
1027 warn ("Bogus number: %s.", str);
1028 break;
1029 }
1030 if (tval >= base) {
1031 warn ("Bogus number: %s: digit %d not in base %d\n",
1032 str, tval, base);
1033 break;
1034 }
1035 val = val * base + tval;
1036 } while (*ptr);
1037
1038 if (negative)
1039 max = (1 << (size - 1));
1040 else
1041 max = (1 << size) - 1;
1042 if (val > max) {
1043 switch (base) {
1044 case 8:
1045 warn ("value %s%lo exceeds max (%d) for precision.",
1046 negative ? "-" : "", val, max);
1047 break;
1048 case 16:
1049 warn ("value %s%lx exceeds max (%d) for precision.",
1050 negative ? "-" : "", val, max);
1051 break;
1052 default:
1053 warn ("value %s%ld exceeds max (%d) for precision.",
1054 negative ? "-" : "", val, max);
1055 break;
1056 }
1057 }
1058
1059 if (negative) {
1060 switch (size) {
1061 case 8:
1062 *buf = -(unsigned long)val;
1063 break;
1064 case 16:
1065 putShort (buf, -(unsigned long)val);
1066 break;
1067 case 32:
1068 putLong (buf, -(unsigned long)val);
1069 break;
1070 default:
1071 warn ("Unexpected integer size: %d\n");
1072 break;
1073 }
1074 } else {
1075 switch (size) {
1076 case 8:
1077 *buf = (u_int8_t)val;
1078 break;
1079 case 16:
1080 putUShort (buf, (u_int16_t)val);
1081 break;
1082 case 32:
1083 putULong (buf, val);
1084 break;
1085 default:
1086 warn ("Unexpected integer size: %d\n");
1087 break;
1088 }
1089 }
1090}