xref: /netbsd-src/external/mpl/dhcp/dist/common/conflex.c (revision f407d9293b6650aa8c33d6a995f797bb6aaefd90)
1 /*	$NetBSD: conflex.c,v 1.3 2022/04/03 01:10:58 christos Exp $	*/
2 
3 /* conflex.c
4 
5    Lexical scanner for dhcpd config file... */
6 
7 /*
8  * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC")
9  * Copyright (c) 1995-2003 by Internet Software Consortium
10  *
11  * This Source Code Form is subject to the terms of the Mozilla Public
12  * License, v. 2.0. If a copy of the MPL was not distributed with this
13  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
18  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  *   Internet Systems Consortium, Inc.
24  *   PO Box 360
25  *   Newmarket, NH 03857 USA
26  *   <info@isc.org>
27  *   https://www.isc.org/
28  *
29  */
30 
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: conflex.c,v 1.3 2022/04/03 01:10:58 christos Exp $");
33 
34 #include "dhcpd.h"
35 #include <ctype.h>
36 
37 static int get_char (struct parse *);
38 static void unget_char(struct parse *, int);
39 static void skip_to_eol (struct parse *);
40 static enum dhcp_token read_whitespace(int c, struct parse *cfile);
41 static enum dhcp_token read_string (struct parse *);
42 static enum dhcp_token read_number (int, struct parse *);
43 static enum dhcp_token read_num_or_name (int, struct parse *);
44 static enum dhcp_token intern (char *, enum dhcp_token);
45 
new_parse(cfile,file,inbuf,buflen,name,eolp)46 isc_result_t new_parse (cfile, file, inbuf, buflen, name, eolp)
47 	struct parse **cfile;
48 	int file;
49 	char *inbuf;
50 	unsigned buflen;
51 	const char *name;
52 	int eolp;
53 {
54 	isc_result_t status = ISC_R_SUCCESS;
55 	struct parse *tmp;
56 
57 	tmp = dmalloc(sizeof(struct parse), MDL);
58 	if (tmp == NULL) {
59 		return (ISC_R_NOMEMORY);
60 	}
61 
62 	/*
63 	 * We don't need to initialize things to zero here, since
64 	 * dmalloc() returns memory that is set to zero.
65 	 */
66 	tmp->tlname = name;
67 	tmp->lpos = tmp -> line = 1;
68 	tmp->cur_line = tmp->line1;
69 	tmp->prev_line = tmp->line2;
70 	tmp->token_line = tmp->cur_line;
71 	tmp->cur_line[0] = tmp->prev_line[0] = 0;
72 	tmp->file = file;
73 	tmp->eol_token = eolp;
74 
75 	if (inbuf != NULL) {
76 		tmp->inbuf = inbuf;
77 		tmp->buflen = buflen;
78 		tmp->bufsiz = 0;
79 	} else {
80 		struct stat sb;
81 
82 		if (fstat(file, &sb) < 0) {
83 			status = ISC_R_IOERROR;
84 			goto cleanup;
85 		}
86 
87 		if (sb.st_size == 0)
88 			goto cleanup;
89 
90 		tmp->bufsiz = tmp->buflen = (size_t) sb.st_size;
91 		tmp->inbuf = mmap(NULL, tmp->bufsiz, PROT_READ, MAP_SHARED,
92 				  file, 0);
93 
94 		if (tmp->inbuf == MAP_FAILED) {
95 			status = ISC_R_IOERROR;
96 			goto cleanup;
97 		}
98 	}
99 
100 	*cfile = tmp;
101 	return (ISC_R_SUCCESS);
102 
103 cleanup:
104 	dfree(tmp, MDL);
105 	return (status);
106 }
107 
end_parse(cfile)108 isc_result_t end_parse (cfile)
109 	struct parse **cfile;
110 {
111 	/* "Memory" config files have no file. */
112 	if ((*cfile)->file != -1) {
113 		munmap((*cfile)->inbuf, (*cfile)->bufsiz);
114 		close((*cfile)->file);
115 	}
116 
117 	if ((*cfile)->saved_state != NULL) {
118 		dfree((*cfile)->saved_state, MDL);
119 	}
120 
121 	dfree(*cfile, MDL);
122 	*cfile = NULL;
123 	return ISC_R_SUCCESS;
124 }
125 
126 /*
127  * Save the current state of the parser.
128  *
129  * Only one state may be saved. Any previous saved state is
130  * lost.
131  */
132 isc_result_t
save_parse_state(struct parse * cfile)133 save_parse_state(struct parse *cfile) {
134 	/*
135 	 * Free any previous saved state.
136 	 */
137 	if (cfile->saved_state != NULL) {
138 		dfree(cfile->saved_state, MDL);
139 	}
140 
141 	/*
142 	 * Save our current state.
143 	 */
144 	cfile->saved_state = dmalloc(sizeof(struct parse), MDL);
145 	if (cfile->saved_state == NULL) {
146 		return ISC_R_NOMEMORY;
147 	}
148 	memcpy(cfile->saved_state, cfile, sizeof(*cfile));
149 	return ISC_R_SUCCESS;
150 }
151 
152 /*
153  * Return the parser to the previous saved state.
154  *
155  * You must call save_parse_state() every time before calling
156  * restore_parse_state().
157  *
158  * Note: When the read function callback is in use in ldap mode,
159  * a call to get_char() may reallocate the buffer and will append
160  * config data to the buffer until a state restore.
161  * Do not restore to the (freed) pointer and size, but use new one.
162  */
163 isc_result_t
restore_parse_state(struct parse * cfile)164 restore_parse_state(struct parse *cfile) {
165 	struct parse *saved_state;
166 #if defined(LDAP_CONFIGURATION)
167 	char *inbuf = cfile->inbuf;
168 	size_t size = cfile->bufsiz;
169 #endif
170 
171 	if (cfile->saved_state == NULL) {
172 		return DHCP_R_NOTYET;
173 	}
174 
175 	saved_state = cfile->saved_state;
176 	memcpy(cfile, saved_state, sizeof(*cfile));
177 	dfree(saved_state, MDL);
178 	cfile->saved_state = NULL;
179 
180 #if defined(LDAP_CONFIGURATION)
181 	cfile->inbuf = inbuf;
182 	cfile->bufsiz = size;
183 #endif
184 	return ISC_R_SUCCESS;
185 }
186 
get_char(cfile)187 static int get_char (cfile)
188 	struct parse *cfile;
189 {
190 	/* My kingdom for WITH... */
191 	int c;
192 
193 	if (cfile->bufix == cfile->buflen) {
194 #if !defined(LDAP_CONFIGURATION)
195 		c = EOF;
196 #else /* defined(LDAP_CONFIGURATION) */
197 		if (cfile->read_function != NULL)
198 			c = cfile->read_function(cfile);
199 		else
200 			c = EOF;
201 #endif
202 	} else {
203 		c = cfile->inbuf [cfile->bufix];
204 		cfile->bufix++;
205 	}
206 
207 	if (!cfile->ugflag) {
208 		if (c == EOL) {
209 			if (cfile->cur_line == cfile->line1) {
210 				cfile->cur_line = cfile->line2;
211 				cfile->prev_line = cfile->line1;
212 			} else {
213 				cfile->cur_line = cfile->line1;
214 				cfile->prev_line = cfile->line2;
215 			}
216 			cfile->line++;
217 			cfile->lpos = 1;
218 			cfile->cur_line [0] = 0;
219 		} else if (c != EOF) {
220 			if (cfile->lpos <= 80) {
221 				cfile->cur_line [cfile->lpos - 1] = c;
222 				cfile->cur_line [cfile->lpos] = 0;
223 			}
224 			cfile->lpos++;
225 		}
226 	} else
227 		cfile->ugflag = 0;
228 	return c;
229 }
230 
231 /*
232  * Return a character to our input buffer.
233  */
234 static void
unget_char(struct parse * cfile,int c)235 unget_char(struct parse *cfile, int c) {
236 	if (c != EOF) {
237 		cfile->bufix--;
238 		cfile->ugflag = 1;	/* do not put characters into
239 					   our error buffer on the next
240 					   call to get_char() */
241 	}
242 }
243 
244 /*
245  * GENERAL NOTE ABOUT TOKENS
246  *
247  * We normally only want non-whitespace tokens. There are some
248  * circumstances where we *do* want to see whitespace (for example
249  * when parsing IPv6 addresses).
250  *
251  * Generally we use the next_token() function to read tokens. This
252  * in turn calls get_next_token, which does *not* return tokens for
253  * whitespace. Rather, it skips these.
254  *
255  * When we need to see whitespace, we us next_raw_token(), which also
256  * returns the WHITESPACE token.
257  *
258  * The peek_token() and peek_raw_token() functions work as expected.
259  *
260  * Warning: if you invoke peek_token(), then if there is a whitespace
261  * token, it will be lost, and subsequent use of next_raw_token() or
262  * peek_raw_token() will NOT see it.
263  */
264 
265 static enum dhcp_token
get_raw_token(struct parse * cfile)266 get_raw_token(struct parse *cfile) {
267 	int c;
268 	enum dhcp_token ttok;
269 	static char tb [2];
270 	int l, p;
271 
272 	do {
273 		l = cfile -> line;
274 		p = cfile -> lpos;
275 
276 		c = get_char (cfile);
277 		if (!((c == '\n') && cfile->eol_token) &&
278 		    isascii(c) && isspace(c)) {
279 		    	ttok = read_whitespace(c, cfile);
280 			break;
281 		}
282 		if (c == '#') {
283 			skip_to_eol (cfile);
284 			continue;
285 		}
286 		if (c == '"') {
287 			cfile -> lexline = l;
288 			cfile -> lexchar = p;
289 			ttok = read_string (cfile);
290 			break;
291 		}
292 		if ((isascii (c) && isdigit (c)) || c == '-') {
293 			cfile -> lexline = l;
294 			cfile -> lexchar = p;
295 			ttok = read_number (c, cfile);
296 			break;
297 		} else if (isascii (c) && isalpha (c)) {
298 			cfile -> lexline = l;
299 			cfile -> lexchar = p;
300 			ttok = read_num_or_name (c, cfile);
301 			break;
302 		} else if (c == EOF) {
303 			ttok = END_OF_FILE;
304 			cfile -> tlen = 0;
305 			break;
306 		} else {
307 			cfile -> lexline = l;
308 			cfile -> lexchar = p;
309 			tb [0] = c;
310 			tb [1] = 0;
311 			cfile -> tval = tb;
312 			cfile -> tlen = 1;
313 			ttok = c;
314 			break;
315 		}
316 	} while (1);
317 	return ttok;
318 }
319 
320 /*
321  * The get_next_token() function consumes the next token and
322  * returns it to the caller.
323  *
324  * Since the code is almost the same for "normal" and "raw"
325  * input, we pass a flag to alter the way it works.
326  */
327 
328 static enum dhcp_token
get_next_token(const char ** rval,unsigned * rlen,struct parse * cfile,isc_boolean_t raw)329 get_next_token(const char **rval, unsigned *rlen,
330 	       struct parse *cfile, isc_boolean_t raw) {
331 	int rv;
332 
333 	if (cfile -> token) {
334 		if (cfile -> lexline != cfile -> tline)
335 			cfile -> token_line = cfile -> cur_line;
336 		cfile -> lexchar = cfile -> tlpos;
337 		cfile -> lexline = cfile -> tline;
338 		rv = cfile -> token;
339 		cfile -> token = 0;
340 	} else {
341 		rv = get_raw_token(cfile);
342 		cfile -> token_line = cfile -> cur_line;
343 	}
344 
345 	if (!raw) {
346 		while (rv == WHITESPACE) {
347 			rv = get_raw_token(cfile);
348 			cfile->token_line = cfile->cur_line;
349 		}
350 	}
351 
352 	if (rval)
353 		*rval = cfile -> tval;
354 	if (rlen)
355 		*rlen = cfile -> tlen;
356 #ifdef DEBUG_TOKENS
357 	fprintf (stderr, "%s:%d ", cfile -> tval, rv);
358 #endif
359 	return rv;
360 }
361 
362 
363 /*
364  * Get the next token from cfile and return it.
365  *
366  * If rval is non-NULL, set the pointer it contains to
367  * the contents of the token.
368  *
369  * If rlen is non-NULL, set the integer it contains to
370  * the length of the token.
371  */
372 
373 enum dhcp_token
next_token(const char ** rval,unsigned * rlen,struct parse * cfile)374 next_token(const char **rval, unsigned *rlen, struct parse *cfile) {
375 	return get_next_token(rval, rlen, cfile, ISC_FALSE);
376 }
377 
378 
379 /*
380  * The same as the next_token() function above, but will return space
381  * as the WHITESPACE token.
382  */
383 
384 enum dhcp_token
next_raw_token(const char ** rval,unsigned * rlen,struct parse * cfile)385 next_raw_token(const char **rval, unsigned *rlen, struct parse *cfile) {
386 	return get_next_token(rval, rlen, cfile, ISC_TRUE);
387 }
388 
389 
390 /*
391  * The do_peek_token() function checks the next token without
392  * consuming it, and returns it to the caller.
393  *
394  * Since the code is almost the same for "normal" and "raw"
395  * input, we pass a flag to alter the way it works. (See the
396  * warning in the GENERAL NOTES ABOUT TOKENS above though.)
397  */
398 
399 static enum dhcp_token
do_peek_token(const char ** rval,unsigned int * rlen,struct parse * cfile,isc_boolean_t raw)400 do_peek_token(const char **rval, unsigned int *rlen,
401 	      struct parse *cfile, isc_boolean_t raw) {
402 	int x;
403 
404 	if (!cfile->token || (!raw && (cfile->token == WHITESPACE))) {
405 		cfile -> tlpos = cfile -> lexchar;
406 		cfile -> tline = cfile -> lexline;
407 
408 		do {
409 			cfile->token = get_raw_token(cfile);
410 		} while (!raw && (cfile->token == WHITESPACE));
411 
412 		if (cfile -> lexline != cfile -> tline)
413 			cfile -> token_line = cfile -> prev_line;
414 
415 		x = cfile -> lexchar;
416 		cfile -> lexchar = cfile -> tlpos;
417 		cfile -> tlpos = x;
418 
419 		x = cfile -> lexline;
420 		cfile -> lexline = cfile -> tline;
421 		cfile -> tline = x;
422 	}
423 	if (rval)
424 		*rval = cfile -> tval;
425 	if (rlen)
426 		*rlen = cfile -> tlen;
427 #ifdef DEBUG_TOKENS
428 	fprintf (stderr, "(%s:%d) ", cfile -> tval, cfile -> token);
429 #endif
430 	return cfile -> token;
431 }
432 
433 
434 /*
435  * Get the next token from cfile and return it, leaving it for a
436  * subsequent call to next_token().
437  *
438  * Note that it WILL consume whitespace tokens.
439  *
440  * If rval is non-NULL, set the pointer it contains to
441  * the contents of the token.
442  *
443  * If rlen is non-NULL, set the integer it contains to
444  * the length of the token.
445  */
446 
447 enum dhcp_token
peek_token(const char ** rval,unsigned * rlen,struct parse * cfile)448 peek_token(const char **rval, unsigned *rlen, struct parse *cfile) {
449 	return do_peek_token(rval, rlen, cfile, ISC_FALSE);
450 }
451 
452 
453 /*
454  * The same as the peek_token() function above, but will return space
455  * as the WHITESPACE token.
456  */
457 
458 enum dhcp_token
peek_raw_token(const char ** rval,unsigned * rlen,struct parse * cfile)459 peek_raw_token(const char **rval, unsigned *rlen, struct parse *cfile) {
460 	return do_peek_token(rval, rlen, cfile, ISC_TRUE);
461 }
462 
skip_to_eol(cfile)463 static void skip_to_eol (cfile)
464 	struct parse *cfile;
465 {
466 	int c;
467 	do {
468 		c = get_char (cfile);
469 		if (c == EOF)
470 			return;
471 		if (c == EOL) {
472 			return;
473 		}
474 	} while (1);
475 }
476 
477 static enum dhcp_token
read_whitespace(int c,struct parse * cfile)478 read_whitespace(int c, struct parse *cfile) {
479 	int ofs;
480 
481 	/*
482 	 * Read as much whitespace as we have available.
483 	 */
484 	ofs = 0;
485 	do {
486 		if (ofs >= (sizeof(cfile->tokbuf) - 1)) {
487 			/*
488 			 * As the file includes a huge amount of whitespace,
489 			 * it's probably broken.
490 			 * Print out a warning and bail out.
491 			 */
492 			parse_warn(cfile,
493 				   "whitespace too long, buffer overflow.");
494 			log_fatal("Exiting");
495 		}
496 		cfile->tokbuf[ofs++] = c;
497 		c = get_char(cfile);
498 		if (c == EOF)
499 			return END_OF_FILE;
500 	} while (!((c == '\n') && cfile->eol_token) &&
501 		 isascii(c) && isspace(c));
502 
503 	/*
504 	 * Put the last (non-whitespace) character back.
505 	 */
506 	unget_char(cfile, c);
507 
508 	/*
509 	 * Return our token.
510 	 */
511 	cfile->tokbuf[ofs] = '\0';
512 	cfile->tlen = ofs;
513 	cfile->tval = cfile->tokbuf;
514 	return WHITESPACE;
515 }
516 
read_string(cfile)517 static enum dhcp_token read_string (cfile)
518 	struct parse *cfile;
519 {
520 	int i;
521 	int bs = 0;
522 	int c;
523 	int value = 0;
524 	int hex = 0;
525 
526 	for (i = 0; i < sizeof cfile -> tokbuf; i++) {
527 	      again:
528 		c = get_char (cfile);
529 		if (c == EOF) {
530 			parse_warn (cfile, "eof in string constant");
531 			break;
532 		}
533 		if (bs == 1) {
534 			switch (c) {
535 			      case 't':
536 				cfile -> tokbuf [i] = '\t';
537 				break;
538 			      case 'r':
539 				cfile -> tokbuf [i] = '\r';
540 				break;
541 			      case 'n':
542 				cfile -> tokbuf [i] = '\n';
543 				break;
544 			      case 'b':
545 				cfile -> tokbuf [i] = '\b';
546 				break;
547 			      case '0':
548 			      case '1':
549 			      case '2':
550 			      case '3':
551 				hex = 0;
552 				value = c - '0';
553 				++bs;
554 				goto again;
555 			      case 'x':
556 				hex = 1;
557 				value = 0;
558 				++bs;
559 				goto again;
560 			      default:
561 				cfile -> tokbuf [i] = c;
562 				break;
563 			}
564 			bs = 0;
565 		} else if (bs > 1) {
566 			if (hex) {
567 				if (c >= '0' && c <= '9') {
568 					value = value * 16 + (c - '0');
569 				} else if (c >= 'a' && c <= 'f') {
570 					value = value * 16 + (c - 'a' + 10);
571 				} else if (c >= 'A' && c <= 'F') {
572 					value = value * 16 + (c - 'A' + 10);
573 				} else {
574 					parse_warn (cfile,
575 						    "invalid hex digit: %x",
576 						    c);
577 					bs = 0;
578 					continue;
579 				}
580 				if (++bs == 4) {
581 					cfile -> tokbuf [i] = value;
582 					bs = 0;
583 				} else
584 					goto again;
585 			} else {
586 				if (c >= '0' && c <= '7') {
587 					value = value * 8 + (c - '0');
588 				} else {
589 				    if (value != 0) {
590 					parse_warn (cfile,
591 						    "invalid octal digit %x",
592 						    c);
593 					continue;
594 				    } else
595 					cfile -> tokbuf [i] = 0;
596 				    bs = 0;
597 				}
598 				if (++bs == 4) {
599 					cfile -> tokbuf [i] = value;
600 					bs = 0;
601 				} else
602 					goto again;
603 			}
604 		} else if (c == '\\') {
605 			bs = 1;
606 			goto again;
607 		} else if (c == '"')
608 			break;
609 		else
610 			cfile -> tokbuf [i] = c;
611 	}
612 	/* Normally, I'd feel guilty about this, but we're talking about
613 	   strings that'll fit in a DHCP packet here... */
614 	if (i == sizeof cfile -> tokbuf) {
615 		parse_warn (cfile,
616 			    "string constant larger than internal buffer");
617 		--i;
618 	}
619 	cfile -> tokbuf [i] = 0;
620 	cfile -> tlen = i;
621 	cfile -> tval = cfile -> tokbuf;
622 	return STRING;
623 }
624 
read_number(c,cfile)625 static enum dhcp_token read_number (c, cfile)
626 	int c;
627 	struct parse *cfile;
628 {
629 	int i = 0;
630 	int token = NUMBER;
631 
632 	cfile -> tokbuf [i++] = c;
633 	for (; i < sizeof cfile -> tokbuf; i++) {
634 		c = get_char (cfile);
635 
636 		/* Promote NUMBER -> NUMBER_OR_NAME -> NAME, never demote.
637 		 * Except in the case of '0x' syntax hex, which gets called
638 		 * a NAME at '0x', and returned to NUMBER_OR_NAME once it's
639 		 * verified to be at least 0xf or less.
640 		 */
641 		switch(isascii(c) ? token : BREAK) {
642 		    case NUMBER:
643 			if(isdigit(c))
644 				break;
645 			/* FALLTHROUGH */
646 		    case NUMBER_OR_NAME:
647 			if(isxdigit(c)) {
648 				token = NUMBER_OR_NAME;
649 				break;
650 			}
651 			/* FALLTHROUGH */
652 		    case NAME:
653 			if((i == 2) && isxdigit(c) &&
654 				(cfile->tokbuf[0] == '0') &&
655 				((cfile->tokbuf[1] == 'x') ||
656 				 (cfile->tokbuf[1] == 'X'))) {
657 				token = NUMBER_OR_NAME;
658 				break;
659 			} else if(((c == '-') || (c == '_') || isalnum(c))) {
660 				token = NAME;
661 				break;
662 			}
663 			/* FALLTHROUGH */
664 		    case BREAK:
665 			/* At this point c is either EOF or part of the next
666 			 * token.  If not EOF, rewind the file one byte so
667 			 * the next token is read from there.
668 			 */
669 			unget_char(cfile, c);
670 			goto end_read;
671 
672 		    default:
673 			log_fatal("read_number():%s:%d: impossible case", MDL);
674 		}
675 
676 		cfile -> tokbuf [i] = c;
677 	}
678 
679 	if (i == sizeof cfile -> tokbuf) {
680 		parse_warn (cfile,
681 			    "numeric token larger than internal buffer");
682 		--i;
683 	}
684 
685   end_read:
686 	cfile -> tokbuf [i] = 0;
687 	cfile -> tlen = i;
688 	cfile -> tval = cfile -> tokbuf;
689 
690 	/*
691 	 * If this entire token from start to finish was "-", such as
692 	 * the middle parameter in "42 - 7", return just the MINUS token.
693 	 */
694 	if ((i == 1) && (cfile->tokbuf[i] == '-'))
695 		return MINUS;
696 	else
697 		return token;
698 }
699 
read_num_or_name(c,cfile)700 static enum dhcp_token read_num_or_name (c, cfile)
701 	int c;
702 	struct parse *cfile;
703 {
704 	int i = 0;
705 	enum dhcp_token rv = NUMBER_OR_NAME;
706 	cfile -> tokbuf [i++] = c;
707 	for (; i < sizeof cfile -> tokbuf; i++) {
708 		c = get_char (cfile);
709 		if (!isascii (c) ||
710 		    (c != '-' && c != '_' && !isalnum (c))) {
711 		    	unget_char(cfile, c);
712 			break;
713 		}
714 		if (!isxdigit (c))
715 			rv = NAME;
716 		cfile -> tokbuf [i] = c;
717 	}
718 	if (i == sizeof cfile -> tokbuf) {
719 		parse_warn (cfile, "token larger than internal buffer");
720 		--i;
721 	}
722 	cfile -> tokbuf [i] = 0;
723 	cfile -> tlen = i;
724 	cfile -> tval = cfile -> tokbuf;
725 	return intern(cfile->tval, rv);
726 }
727 
728 static enum dhcp_token
intern(char * atom,enum dhcp_token dfv)729 intern(char *atom, enum dhcp_token dfv) {
730 	if (!isascii(atom[0]))
731 		return dfv;
732 
733 	switch (tolower((unsigned char)atom[0])) {
734 	      case '-':
735 		if (atom [1] == 0)
736 			return MINUS;
737 		break;
738 
739 	      case 'a':
740 		if (!strcasecmp(atom + 1, "bandoned"))
741 			return TOKEN_ABANDONED;
742 		if (!strcasecmp(atom + 1, "ctive"))
743 			return TOKEN_ACTIVE;
744 		if (!strncasecmp(atom + 1, "dd", 2)) {
745 			if (atom[3] == '\0')
746 				return TOKEN_ADD;
747 			else if (!strcasecmp(atom + 3, "ress"))
748 				return ADDRESS;
749 			break;
750 		}
751 		if (!strcasecmp(atom + 1, "fter"))
752 			return AFTER;
753 		if (isascii(atom[1]) &&
754 		    (tolower((unsigned char)atom[1]) == 'l')) {
755 			if (!strcasecmp(atom + 2, "gorithm"))
756 				return ALGORITHM;
757 			if (!strcasecmp(atom + 2, "ias"))
758 				return ALIAS;
759 			if (isascii(atom[2]) &&
760 			    (tolower((unsigned char)atom[2]) == 'l')) {
761 				if (atom[3] == '\0')
762 					return ALL;
763 				else if (!strcasecmp(atom + 3, "ow"))
764 					return ALLOW;
765 				break;
766 			}
767 			if (!strcasecmp(atom + 2, "so"))
768 				return TOKEN_ALSO;
769 			break;
770 		}
771 		if (isascii(atom[1]) &&
772 		    (tolower((unsigned char)atom[1]) == 'n')) {
773 			if (!strcasecmp(atom + 2, "d"))
774 				return AND;
775 			if (!strcasecmp(atom + 2, "ycast-mac"))
776 				return ANYCAST_MAC;
777 			break;
778 		}
779 		if (!strcasecmp(atom + 1, "ppend"))
780 			return APPEND;
781 		if (!strcasecmp(atom + 1, "rray"))
782 			return ARRAY;
783 		if (isascii(atom[1]) &&
784 		    (tolower((unsigned char)atom[1]) == 't')) {
785 			if (atom[2] == '\0')
786 				return AT;
787 			if (!strcasecmp(atom + 2, "sfp"))
788 				return ATSFP;
789 			break;
790 		}
791 		if (!strcasecmp(atom + 1, "uthoring-byte-order"))
792 			return AUTHORING_BYTE_ORDER;
793 		if (!strncasecmp(atom + 1, "ut", 2)) {
794 			if (isascii(atom[3]) &&
795 			    (tolower((unsigned char)atom[3]) == 'h')) {
796 				if (!strncasecmp(atom + 4, "enticat", 7)) {
797 					if (!strcasecmp(atom + 11, "ed"))
798 						return AUTHENTICATED;
799 					if (!strcasecmp(atom + 11, "ion"))
800 						return AUTHENTICATION;
801 					break;
802 				}
803 				if (!strcasecmp(atom + 4, "oritative"))
804 					return AUTHORITATIVE;
805 				break;
806 			}
807 			if (!strcasecmp(atom + 3, "o-partner-down"))
808 				return AUTO_PARTNER_DOWN;
809 			break;
810 		}
811 		break;
812 	      case 'b':
813 		if (!strcasecmp (atom + 1, "ackup"))
814 			return TOKEN_BACKUP;
815 		if (!strcasecmp (atom + 1, "ootp"))
816 			return TOKEN_BOOTP;
817 		if (!strcasecmp (atom + 1, "inding"))
818 			return BINDING;
819 		if (!strcasecmp (atom + 1, "inary-to-ascii"))
820 			return BINARY_TO_ASCII;
821 		if (!strcasecmp (atom + 1, "ackoff-cutoff"))
822 			return BACKOFF_CUTOFF;
823 		if (!strcasecmp (atom + 1, "ooting"))
824 			return BOOTING;
825 		if (!strcasecmp (atom + 1, "oot-unknown-clients"))
826 			return BOOT_UNKNOWN_CLIENTS;
827 		if (!strcasecmp (atom + 1, "reak"))
828 			return BREAK;
829 		if (!strcasecmp (atom + 1, "illing"))
830 			return BILLING;
831 		if (!strcasecmp (atom + 1, "oolean"))
832 			return BOOLEAN;
833 		if (!strcasecmp (atom + 1, "alance"))
834 			return BALANCE;
835 		if (!strcasecmp (atom + 1, "ound"))
836 			return BOUND;
837 		if (!strcasecmp(atom+1, "ig-endian")) {
838 			return TOKEN_BIG_ENDIAN;
839 		}
840 		break;
841 	      case 'c':
842 		if (!strcasecmp(atom + 1, "ase"))
843 			return CASE;
844 		if (!strcasecmp(atom + 1, "heck"))
845 			return CHECK;
846 		if (!strcasecmp(atom + 1, "iaddr"))
847 			return CIADDR;
848 		if (isascii(atom[1]) &&
849 		    tolower((unsigned char)atom[1]) == 'l') {
850 			if (!strcasecmp(atom + 2, "ass"))
851 				return CLASS;
852 			if (!strncasecmp(atom + 2, "ient", 4)) {
853 				if (!strcasecmp(atom + 6, "s"))
854 					return CLIENTS;
855 				if (atom[6] == '-') {
856 					if (!strcasecmp(atom + 7, "hostname"))
857 						return CLIENT_HOSTNAME;
858 					if (!strcasecmp(atom + 7, "identifier"))
859 						return CLIENT_IDENTIFIER;
860 					if (!strcasecmp(atom + 7, "state"))
861 						return CLIENT_STATE;
862 					if (!strcasecmp(atom + 7, "updates"))
863 						return CLIENT_UPDATES;
864 					break;
865 				}
866 				break;
867 			}
868 			if (!strcasecmp(atom + 2, "ose"))
869 				return TOKEN_CLOSE;
870 			if (!strcasecmp(atom + 2, "tt"))
871 				return CLTT;
872 			break;
873 		}
874 		if (isascii(atom[1]) &&
875 		    tolower((unsigned char)atom[1]) == 'o') {
876 			if (!strcasecmp(atom + 2, "de"))
877 				return CODE;
878 			if (isascii(atom[2]) &&
879 			    tolower((unsigned char)atom[2]) == 'm') {
880 				if (!strcasecmp(atom + 3, "mit"))
881 					return COMMIT;
882 				if (!strcasecmp(atom + 3,
883 						"munications-interrupted"))
884 					return COMMUNICATIONS_INTERRUPTED;
885 				if (!strcasecmp(atom + 3, "pressed"))
886 					return COMPRESSED;
887 				break;
888 			}
889 			if (isascii(atom[2]) &&
890 			    tolower((unsigned char)atom[2]) == 'n') {
891 				if (!strcasecmp(atom + 3, "cat"))
892 					return CONCAT;
893 				if (!strcasecmp(atom + 3, "fig-option"))
894 					return CONFIG_OPTION;
895 				if (!strcasecmp(atom + 3, "flict-done"))
896 					return CONFLICT_DONE;
897 				if (!strcasecmp(atom + 3, "nect"))
898 					return CONNECT;
899 				break;
900 			}
901 			break;
902 		}
903 		if (!strcasecmp(atom + 1, "reate"))
904 			return TOKEN_CREATE;
905 		break;
906 	      case 'd':
907 		if (!strcasecmp(atom + 1, "b-time-format"))
908 			return DB_TIME_FORMAT;
909 		if (!strcasecmp (atom + 1, "omain"))
910 			return DOMAIN;
911 		if (!strncasecmp (atom + 1, "omain-", 6)) {
912 			if (!strcasecmp(atom + 7, "name"))
913 				return DOMAIN_NAME;
914 			if (!strcasecmp(atom + 7, "list"))
915 				return DOMAIN_LIST;
916 		}
917 		if (!strcasecmp (atom + 1, "o-forward-updates"))
918 			return DO_FORWARD_UPDATE;
919 		/* do-forward-update is included for historical reasons */
920 		if (!strcasecmp (atom + 1, "o-forward-update"))
921 			return DO_FORWARD_UPDATE;
922 		if (!strcasecmp (atom + 1, "ebug"))
923 			return TOKEN_DEBUG;
924 		if (!strcasecmp (atom + 1, "eny"))
925 			return DENY;
926 		if (!strcasecmp (atom + 1, "eleted"))
927 			return TOKEN_DELETED;
928 		if (!strcasecmp (atom + 1, "elete"))
929 			return TOKEN_DELETE;
930 		if (!strncasecmp (atom + 1, "efault", 6)) {
931 			if (!atom [7])
932 				return DEFAULT;
933 			if (!strcasecmp(atom + 7, "-duid"))
934 				return DEFAULT_DUID;
935 			if (!strcasecmp (atom + 7, "-lease-time"))
936 				return DEFAULT_LEASE_TIME;
937 			break;
938 		}
939 		if (!strncasecmp (atom + 1, "ynamic", 6)) {
940 			if (!atom [7])
941 				return DYNAMIC;
942 			if (!strncasecmp (atom + 7, "-bootp", 6)) {
943 				if (!atom [13])
944 					return DYNAMIC_BOOTP;
945 				if (!strcasecmp (atom + 13, "-lease-cutoff"))
946 					return DYNAMIC_BOOTP_LEASE_CUTOFF;
947 				if (!strcasecmp (atom + 13, "-lease-length"))
948 					return DYNAMIC_BOOTP_LEASE_LENGTH;
949 				break;
950 			}
951 		}
952 		if (!strcasecmp (atom + 1, "uplicates"))
953 			return DUPLICATES;
954 		if (!strcasecmp (atom + 1, "eclines"))
955 			return DECLINES;
956 		if (!strncasecmp (atom + 1, "efine", 5)) {
957 			if (!strcasecmp (atom + 6, "d"))
958 				return DEFINED;
959 			if (!atom [6])
960 				return DEFINE;
961 		}
962 		if (!strcasecmp (atom + 1, "isconnect"))
963 			return DISCONNECT;
964 		break;
965 	      case 'e':
966 		if (isascii (atom [1]) &&
967 		    tolower((unsigned char)atom[1]) == 'x') {
968 			if (!strcasecmp (atom + 2, "tract-int"))
969 				return EXTRACT_INT;
970 			if (!strcasecmp (atom + 2, "ists"))
971 				return EXISTS;
972 			if (!strcasecmp (atom + 2, "piry"))
973 				return EXPIRY;
974 			if (!strcasecmp (atom + 2, "pire"))
975 				return EXPIRE;
976 			if (!strcasecmp (atom + 2, "pired"))
977 				return TOKEN_EXPIRED;
978 		}
979 		if (!strcasecmp (atom + 1, "ncode-int"))
980 			return ENCODE_INT;
981 		if (!strcasecmp(atom + 1, "poch"))
982 			return EPOCH;
983 		if (!strcasecmp (atom + 1, "thernet"))
984 			return ETHERNET;
985 		if (!strcasecmp (atom + 1, "nds"))
986 			return ENDS;
987 		if (!strncasecmp (atom + 1, "ls", 2)) {
988 			if (!strcasecmp (atom + 3, "e"))
989 				return ELSE;
990 			if (!strcasecmp (atom + 3, "if"))
991 				return ELSIF;
992 			break;
993 		}
994 		if (!strcasecmp (atom + 1, "rror"))
995 			return ERROR;
996 		if (!strcasecmp (atom + 1, "val"))
997 			return EVAL;
998 		if (!strcasecmp (atom + 1, "ncapsulate"))
999 			return ENCAPSULATE;
1000 		if (!strcasecmp(atom + 1, "xecute"))
1001 			return EXECUTE;
1002 		if (!strcasecmp(atom+1, "n")) {
1003 			return EN;
1004 		}
1005 		break;
1006 	      case 'f':
1007 		if (!strcasecmp (atom + 1, "atal"))
1008 			return FATAL;
1009 		if (!strcasecmp (atom + 1, "ilename"))
1010 			return FILENAME;
1011 		if (!strcasecmp (atom + 1, "ixed-address"))
1012 			return FIXED_ADDR;
1013 		if (!strcasecmp (atom + 1, "ixed-address6"))
1014 			return FIXED_ADDR6;
1015 		if (!strcasecmp (atom + 1, "ixed-prefix6"))
1016 			return FIXED_PREFIX6;
1017 		if (!strcasecmp (atom + 1, "ddi"))
1018 			return TOKEN_FDDI;
1019 		if (!strcasecmp (atom + 1, "ormerr"))
1020 			return NS_FORMERR;
1021 		if (!strcasecmp (atom + 1, "unction"))
1022 			return FUNCTION;
1023 		if (!strcasecmp (atom + 1, "ailover"))
1024 			return FAILOVER;
1025 		if (!strcasecmp (atom + 1, "ree"))
1026 			return TOKEN_FREE;
1027 		break;
1028 	      case 'g':
1029 		if (!strncasecmp(atom + 1, "et", 2)) {
1030 			if (!strcasecmp(atom + 3, "-lease-hostnames"))
1031 				return GET_LEASE_HOSTNAMES;
1032 			if (!strcasecmp(atom + 3, "hostbyname"))
1033 				return GETHOSTBYNAME;
1034 			if (!strcasecmp(atom + 3, "hostname"))
1035 				return GETHOSTNAME;
1036 			break;
1037 		}
1038 		if (!strcasecmp (atom + 1, "iaddr"))
1039 			return GIADDR;
1040 		if (!strcasecmp (atom + 1, "roup"))
1041 			return GROUP;
1042 		break;
1043 	      case 'h':
1044 		if (!strcasecmp(atom + 1, "ash"))
1045 			return HASH;
1046 		if (!strcasecmp (atom + 1, "ba"))
1047 			return HBA;
1048 		if (!strcasecmp (atom + 1, "ost"))
1049 			return HOST;
1050 		if (!strcasecmp (atom + 1, "ost-decl-name"))
1051 			return HOST_DECL_NAME;
1052 		if (!strcasecmp(atom + 1, "ost-identifier"))
1053 			return HOST_IDENTIFIER;
1054 		if (!strcasecmp (atom + 1, "ardware"))
1055 			return HARDWARE;
1056 		if (!strcasecmp (atom + 1, "ostname"))
1057 			return HOSTNAME;
1058 		if (!strcasecmp (atom + 1, "elp"))
1059 			return TOKEN_HELP;
1060 		if (!strcasecmp (atom + 1, "ex")) {
1061 			return TOKEN_HEX;
1062 		}
1063 		break;
1064 	      case 'i':
1065 	      	if (!strcasecmp(atom+1, "a-na"))
1066 			return IA_NA;
1067 	      	if (!strcasecmp(atom+1, "a-ta"))
1068 			return IA_TA;
1069 	      	if (!strcasecmp(atom+1, "a-pd"))
1070 			return IA_PD;
1071 	      	if (!strcasecmp(atom+1, "aaddr"))
1072 			return IAADDR;
1073 	      	if (!strcasecmp(atom+1, "aprefix"))
1074 			return IAPREFIX;
1075 		if (!strcasecmp (atom + 1, "nclude"))
1076 			return INCLUDE;
1077 		if (!strcasecmp (atom + 1, "nteger"))
1078 			return INTEGER;
1079 		if (!strcasecmp (atom  + 1, "nfiniband"))
1080 			return TOKEN_INFINIBAND;
1081 		if (!strcasecmp (atom + 1, "nfinite"))
1082 			return INFINITE;
1083 		if (!strcasecmp (atom + 1, "nfo"))
1084 			return INFO;
1085 		if (!strcasecmp (atom + 1, "p-address"))
1086 			return IP_ADDRESS;
1087 		if (!strcasecmp (atom + 1, "p6-address"))
1088 			return IP6_ADDRESS;
1089 		if (!strcasecmp (atom + 1, "nitial-interval"))
1090 			return INITIAL_INTERVAL;
1091 		if (!strcasecmp (atom + 1, "nitial-delay"))
1092 			return INITIAL_DELAY;
1093 		if (!strcasecmp (atom + 1, "nterface"))
1094 			return INTERFACE;
1095 		if (!strcasecmp (atom + 1, "dentifier"))
1096 			return IDENTIFIER;
1097 		if (!strcasecmp (atom + 1, "f"))
1098 			return IF;
1099 		if (!strcasecmp (atom + 1, "s"))
1100 			return IS;
1101 		if (!strcasecmp (atom + 1, "gnore"))
1102 			return IGNORE;
1103 		break;
1104 	      case 'k':
1105 		if (!strncasecmp (atom + 1, "nown", 4)) {
1106 			if (!strcasecmp (atom + 5, "-clients"))
1107 				return KNOWN_CLIENTS;
1108 			if (!atom[5])
1109 				return KNOWN;
1110 			break;
1111 		}
1112 		if (!strcasecmp (atom + 1, "ey"))
1113 			return KEY;
1114 		if (!strcasecmp (atom + 1, "ey-algorithm"))
1115 			return KEY_ALGORITHM;
1116 		break;
1117 	      case 'l':
1118 		if (!strcasecmp (atom + 1, "case"))
1119 			return LCASE;
1120 		if (!strcasecmp (atom + 1, "ease"))
1121 			return LEASE;
1122 		if (!strcasecmp(atom + 1, "ease6"))
1123 			return LEASE6;
1124 		if (!strcasecmp (atom + 1, "eased-address"))
1125 			return LEASED_ADDRESS;
1126 		if (!strcasecmp (atom + 1, "ease-time"))
1127 			return LEASE_TIME;
1128 		if (!strcasecmp(atom + 1, "easequery"))
1129 			return LEASEQUERY;
1130 		if (!strcasecmp(atom + 1, "ength"))
1131 			return LENGTH;
1132 		if (!strcasecmp (atom + 1, "imit"))
1133 			return LIMIT;
1134 		if (!strcasecmp (atom + 1, "et"))
1135 			return LET;
1136 		if (!strcasecmp (atom + 1, "oad"))
1137 			return LOAD;
1138 		if (!strcasecmp(atom + 1, "ocal"))
1139 			return LOCAL;
1140 		if (!strcasecmp (atom + 1, "og"))
1141 			return LOG;
1142 		if (!strcasecmp(atom+1, "lt")) {
1143 			return LLT;
1144 		}
1145 		if (!strcasecmp(atom+1, "l")) {
1146 			return LL;
1147 		}
1148 		if (!strcasecmp(atom+1, "ittle-endian")) {
1149 			return TOKEN_LITTLE_ENDIAN;
1150 		}
1151 		if (!strcasecmp (atom + 1, "ease-id-format")) {
1152 			return LEASE_ID_FORMAT;
1153 		}
1154 		break;
1155 	      case 'm':
1156 		if (!strncasecmp (atom + 1, "ax", 2)) {
1157 			if (!atom [3])
1158 				return TOKEN_MAX;
1159 			if (!strcasecmp (atom + 3, "-balance"))
1160 				return MAX_BALANCE;
1161 			if (!strncasecmp (atom + 3, "-lease-", 7)) {
1162 				if (!strcasecmp(atom + 10, "misbalance"))
1163 					return MAX_LEASE_MISBALANCE;
1164 				if (!strcasecmp(atom + 10, "ownership"))
1165 					return MAX_LEASE_OWNERSHIP;
1166 				if (!strcasecmp(atom + 10, "time"))
1167 					return MAX_LEASE_TIME;
1168 			}
1169 			if (!strcasecmp(atom + 3, "-life"))
1170 				return MAX_LIFE;
1171 			if (!strcasecmp (atom + 3, "-transmit-idle"))
1172 				return MAX_TRANSMIT_IDLE;
1173 			if (!strcasecmp (atom + 3, "-response-delay"))
1174 				return MAX_RESPONSE_DELAY;
1175 			if (!strcasecmp (atom + 3, "-unacked-updates"))
1176 				return MAX_UNACKED_UPDATES;
1177 		}
1178 		if (!strncasecmp (atom + 1, "in-", 3)) {
1179 			if (!strcasecmp (atom + 4, "balance"))
1180 				return MIN_BALANCE;
1181 			if (!strcasecmp (atom + 4, "lease-time"))
1182 				return MIN_LEASE_TIME;
1183 			if (!strcasecmp (atom + 4, "secs"))
1184 				return MIN_SECS;
1185 			break;
1186 		}
1187 		if (!strncasecmp (atom + 1, "edi", 3)) {
1188 			if (!strcasecmp (atom + 4, "a"))
1189 				return MEDIA;
1190 			if (!strcasecmp (atom + 4, "um"))
1191 				return MEDIUM;
1192 			break;
1193 		}
1194 		if (!strcasecmp (atom + 1, "atch"))
1195 			return MATCH;
1196 		if (!strcasecmp (atom + 1, "embers"))
1197 			return MEMBERS;
1198 		if (!strcasecmp (atom + 1, "y"))
1199 			return MY;
1200 		if (!strcasecmp (atom + 1, "clt"))
1201 			return MCLT;
1202 		break;
1203 	      case 'n':
1204 		if (!strcasecmp (atom + 1, "ormal"))
1205 			return NORMAL;
1206 		if (!strcasecmp (atom + 1, "ameserver"))
1207 			return NAMESERVER;
1208 		if (!strcasecmp (atom + 1, "etmask"))
1209 			return NETMASK;
1210 		if (!strcasecmp (atom + 1, "ever"))
1211 			return NEVER;
1212 		if (!strcasecmp (atom + 1, "ext-server"))
1213 			return NEXT_SERVER;
1214 		if (!strcasecmp (atom + 1, "ot"))
1215 			return TOKEN_NOT;
1216 		if (!strcasecmp (atom + 1, "o"))
1217 			return TOKEN_NO;
1218 		if (!strcasecmp (atom + 1, "oerror"))
1219 			return NS_NOERROR;
1220 		if (!strcasecmp (atom + 1, "otauth"))
1221 			return NS_NOTAUTH;
1222 		if (!strcasecmp (atom + 1, "otimp"))
1223 			return NS_NOTIMP;
1224 		if (!strcasecmp (atom + 1, "otzone"))
1225 			return NS_NOTZONE;
1226 		if (!strcasecmp (atom + 1, "xdomain"))
1227 			return NS_NXDOMAIN;
1228 		if (!strcasecmp (atom + 1, "xrrset"))
1229 			return NS_NXRRSET;
1230 		if (!strcasecmp (atom + 1, "ull"))
1231 			return TOKEN_NULL;
1232 		if (!strcasecmp (atom + 1, "ext"))
1233 			return TOKEN_NEXT;
1234 		if (!strcasecmp (atom + 1, "ew"))
1235 			return TOKEN_NEW;
1236 		break;
1237 	      case 'o':
1238 		if (!strcasecmp (atom + 1, "mapi"))
1239 			return OMAPI;
1240 		if (!strcasecmp (atom + 1, "r"))
1241 			return OR;
1242 		if (!strcasecmp (atom + 1, "n"))
1243 			return ON;
1244 		if (!strcasecmp (atom + 1, "pen"))
1245 			return TOKEN_OPEN;
1246 		if (!strcasecmp (atom + 1, "ption"))
1247 			return OPTION;
1248 		if (!strcasecmp (atom + 1, "ne-lease-per-client"))
1249 			return ONE_LEASE_PER_CLIENT;
1250 		if (!strcasecmp (atom + 1, "f"))
1251 			return OF;
1252 		if (!strcasecmp (atom + 1, "wner"))
1253 			return OWNER;
1254 		if (!strcasecmp (atom + 1, "ctal")) {
1255 			return TOKEN_OCTAL;
1256 		}
1257 		break;
1258 	      case 'p':
1259 		if (!strcasecmp (atom + 1, "arse-vendor-option"))
1260 			return PARSE_VENDOR_OPT;
1261 		if (!strcasecmp (atom + 1, "repend"))
1262 			return PREPEND;
1263 		if (!strcasecmp(atom + 1, "referred-life"))
1264 			return PREFERRED_LIFE;
1265 		if (!strcasecmp (atom + 1, "acket"))
1266 			return PACKET;
1267 		if (!strcasecmp (atom + 1, "ool"))
1268 			return POOL;
1269 		if (!strcasecmp (atom + 1, "ool6"))
1270 			return POOL6;
1271 		if (!strcasecmp (atom + 1, "refix6"))
1272 			return PREFIX6;
1273 		if (!strcasecmp (atom + 1, "seudo"))
1274 			return PSEUDO;
1275 		if (!strcasecmp (atom + 1, "eer"))
1276 			return PEER;
1277 		if (!strcasecmp (atom + 1, "rimary"))
1278 			return PRIMARY;
1279 		if (!strcasecmp (atom + 1, "rimary6"))
1280 			return PRIMARY6;
1281 		if (!strncasecmp (atom + 1, "artner", 6)) {
1282 			if (!atom [7])
1283 				return PARTNER;
1284 			if (!strcasecmp (atom + 7, "-down"))
1285 				return PARTNER_DOWN;
1286 		}
1287 		if (!strcasecmp (atom + 1, "ort"))
1288 			return PORT;
1289 		if (!strcasecmp (atom + 1, "otential-conflict"))
1290 			return POTENTIAL_CONFLICT;
1291 		if (!strcasecmp (atom + 1, "ick-first-value") ||
1292 		    !strcasecmp (atom + 1, "ick"))
1293 			return PICK;
1294 		if (!strcasecmp (atom + 1, "aused"))
1295 			return PAUSED;
1296 		break;
1297 	      case 'r':
1298 		if (!strcasecmp(atom + 1, "ange"))
1299 			return RANGE;
1300 		if (!strcasecmp(atom + 1, "ange6"))
1301 			return RANGE6;
1302 		if (isascii(atom[1]) &&
1303 		    (tolower((unsigned char)atom[1]) == 'e')) {
1304 			if (!strcasecmp(atom + 2, "bind"))
1305 				return REBIND;
1306 			if (!strcasecmp(atom + 2, "boot"))
1307 				return REBOOT;
1308 			if (!strcasecmp(atom + 2, "contact-interval"))
1309 				return RECONTACT_INTERVAL;
1310 			if (!strncasecmp(atom + 2, "cover", 5)) {
1311 				if (atom[7] == '\0')
1312 					return RECOVER;
1313 				if (!strcasecmp(atom + 7, "-done"))
1314 					return RECOVER_DONE;
1315 				if (!strcasecmp(atom + 7, "-wait"))
1316 					return RECOVER_WAIT;
1317 				break;
1318 			}
1319 			if (!strcasecmp(atom + 2, "fresh"))
1320 				return REFRESH;
1321 			if (!strcasecmp(atom + 2, "fused"))
1322 				return NS_REFUSED;
1323 			if (!strcasecmp(atom + 2, "ject"))
1324 				return REJECT;
1325 			if (!strcasecmp(atom + 2, "lease"))
1326 				return RELEASE;
1327 			if (!strcasecmp(atom + 2, "leased"))
1328 				return TOKEN_RELEASED;
1329 			if (!strcasecmp(atom + 2, "move"))
1330 				return REMOVE;
1331 			if (!strcasecmp(atom + 2, "new"))
1332 				return RENEW;
1333 			if (!strcasecmp(atom + 2, "quest"))
1334 				return REQUEST;
1335 			if (!strcasecmp(atom + 2, "quire"))
1336 				return REQUIRE;
1337 			if (isascii(atom[2]) &&
1338 			    (tolower((unsigned char)atom[2]) == 's')) {
1339 				if (!strcasecmp(atom + 3, "erved"))
1340 					return TOKEN_RESERVED;
1341 				if (!strcasecmp(atom + 3, "et"))
1342 					return TOKEN_RESET;
1343 				if (!strcasecmp(atom + 3,
1344 						"olution-interrupted"))
1345 					return RESOLUTION_INTERRUPTED;
1346 				break;
1347 			}
1348 			if (!strcasecmp(atom + 2, "try"))
1349 				return RETRY;
1350 			if (!strcasecmp(atom + 2, "turn"))
1351 				return RETURN;
1352 			if (!strcasecmp(atom + 2, "verse"))
1353 				return REVERSE;
1354 			if (!strcasecmp(atom + 2, "wind"))
1355 				return REWIND;
1356 			break;
1357 		}
1358 		break;
1359 	      case 's':
1360 		if (!strcasecmp(atom + 1, "cript"))
1361 			return SCRIPT;
1362 		if (isascii(atom[1]) &&
1363 		    tolower((unsigned char)atom[1]) == 'e') {
1364 			if (!strcasecmp(atom + 2, "arch"))
1365 				return SEARCH;
1366 			if (isascii(atom[2]) &&
1367 			    tolower((unsigned char)atom[2]) == 'c') {
1368 				if (!strncasecmp(atom + 3, "ond", 3)) {
1369                                         if (!strcasecmp(atom + 6, "ary"))
1370 						return SECONDARY;
1371                                         if (!strcasecmp(atom + 6, "ary6"))
1372 						return SECONDARY6;
1373                                         if (!strcasecmp(atom + 6, "s"))
1374                                                 return SECONDS;
1375 					break;
1376 				}
1377                                 if (!strcasecmp(atom + 3, "ret"))
1378                                         return SECRET;
1379 				break;
1380 			}
1381 			if (!strncasecmp(atom + 2, "lect", 4)) {
1382                                 if (atom[6] == '\0')
1383                                         return SELECT;
1384                                 if (!strcasecmp(atom + 6, "-timeout"))
1385                                         return SELECT_TIMEOUT;
1386 				break;
1387 			}
1388                         if (!strcasecmp(atom + 2, "nd"))
1389                                 return SEND;
1390 			if (!strncasecmp(atom + 2, "rv", 2)) {
1391 				if (!strncasecmp(atom + 4, "er", 2)) {
1392                                         if (atom[6] == '\0')
1393                                                 return TOKEN_SERVER;
1394 					if (atom[6] == '-') {
1395 						if (!strcasecmp(atom + 7,
1396 								"duid"))
1397 							return SERVER_DUID;
1398                                                 if (!strcasecmp(atom + 7,
1399 								"name"))
1400                                                         return SERVER_NAME;
1401                                                 if (!strcasecmp(atom + 7,
1402 								"identifier"))
1403                                                       return SERVER_IDENTIFIER;
1404 						break;
1405 					}
1406 					break;
1407 				}
1408                                 if (!strcasecmp(atom + 4, "fail"))
1409                                         return NS_SERVFAIL;
1410 				break;
1411 			}
1412                         if (!strcasecmp(atom + 2, "t"))
1413                                 return TOKEN_SET;
1414 			break;
1415 		}
1416 		if (isascii(atom[1]) &&
1417 		    tolower((unsigned char)atom[1]) == 'h') {
1418                         if (!strcasecmp(atom + 2, "ared-network"))
1419                                 return SHARED_NETWORK;
1420                         if (!strcasecmp(atom + 2, "utdown"))
1421                                 return SHUTDOWN;
1422 			break;
1423 		}
1424 		if (isascii(atom[1]) &&
1425 		    tolower((unsigned char)atom[1]) == 'i') {
1426                         if (!strcasecmp(atom + 2, "addr"))
1427                                 return SIADDR;
1428                         if (!strcasecmp(atom + 2, "gned"))
1429                                 return SIGNED;
1430                         if (!strcasecmp(atom + 2, "ze"))
1431                                 return SIZE;
1432 			break;
1433 		}
1434 		if (isascii(atom[1]) &&
1435 		    tolower((unsigned char)atom[1]) == 'p') {
1436 			if (isascii(atom[2]) &&
1437 			    tolower((unsigned char)atom[2]) == 'a') {
1438                                 if (!strcasecmp(atom + 3, "ce"))
1439                                         return SPACE;
1440                                 if (!strcasecmp(atom + 3, "wn"))
1441                                         return SPAWN;
1442 				break;
1443 			}
1444                         if (!strcasecmp(atom + 2, "lit"))
1445                                 return SPLIT;
1446 			break;
1447 		}
1448 		if (isascii(atom[1]) &&
1449 		    tolower((unsigned char)atom[1]) == 't') {
1450 			if (isascii(atom[2]) &&
1451 			    tolower((unsigned char)atom[2]) == 'a') {
1452 				if(!strncasecmp(atom + 3, "rt", 2)) {
1453                                          if (!strcasecmp(atom + 5, "s"))
1454                                                  return STARTS;
1455                                          if (!strcasecmp(atom + 5, "up"))
1456                                                  return STARTUP;
1457 					break;
1458 				}
1459 				if (isascii(atom[3]) &&
1460 				    tolower((unsigned char)atom[3]) == 't') {
1461                                         if (!strcasecmp(atom + 4, "e"))
1462                                                 return STATE;
1463                                         if (!strcasecmp(atom + 4, "ic"))
1464                                                 return STATIC;
1465 					break;
1466 				}
1467 			}
1468                         if (!strcasecmp(atom + 2, "ring"))
1469                                 return STRING_TOKEN;
1470 			break;
1471 		}
1472                 if (!strncasecmp(atom + 1, "ub", 2)) {
1473                         if (!strcasecmp(atom + 3, "class"))
1474                                 return SUBCLASS;
1475                         if (!strcasecmp(atom + 3, "net"))
1476                                 return SUBNET;
1477                         if (!strcasecmp(atom + 3, "net6"))
1478                                 return SUBNET6;
1479                         if (!strcasecmp(atom + 3, "string"))
1480                                 return SUBSTRING;
1481                         break;
1482                 }
1483 		if (isascii(atom[1]) &&
1484 		    tolower((unsigned char)atom[1]) == 'u') {
1485                         if (!strcasecmp(atom + 2, "ffix"))
1486                                 return SUFFIX;
1487                         if (!strcasecmp(atom + 2, "persede"))
1488                                 return SUPERSEDE;
1489 		}
1490                 if (!strcasecmp(atom + 1, "witch"))
1491                         return SWITCH;
1492 		break;
1493 	      case 't':
1494 		if (!strcasecmp (atom + 1, "imestamp"))
1495 			return TIMESTAMP;
1496 		if (!strcasecmp (atom + 1, "imeout"))
1497 			return TIMEOUT;
1498 		if (!strcasecmp (atom + 1, "oken-ring"))
1499 			return TOKEN_RING;
1500 		if (!strcasecmp (atom + 1, "ext"))
1501 			return TEXT;
1502 		if (!strcasecmp (atom + 1, "stp"))
1503 			return TSTP;
1504 		if (!strcasecmp (atom + 1, "sfp"))
1505 			return TSFP;
1506 		if (!strcasecmp (atom + 1, "ransmission"))
1507 			return TRANSMISSION;
1508 		if (!strcasecmp(atom + 1, "emporary"))
1509 			return TEMPORARY;
1510 		break;
1511 	      case 'u':
1512 		if (!strcasecmp (atom + 1, "case"))
1513 			return UCASE;
1514 		if (!strcasecmp (atom + 1, "nset"))
1515 			return UNSET;
1516 		if (!strcasecmp (atom + 1, "nsigned"))
1517 			return UNSIGNED;
1518 		if (!strcasecmp (atom + 1, "id"))
1519 			return UID;
1520 		if (!strncasecmp (atom + 1, "se", 2)) {
1521 			if (!strcasecmp (atom + 3, "r-class"))
1522 				return USER_CLASS;
1523 			if (!strcasecmp (atom + 3, "-host-decl-names"))
1524 				return USE_HOST_DECL_NAMES;
1525 			if (!strcasecmp (atom + 3,
1526 					 "-lease-addr-for-default-route"))
1527 				return USE_LEASE_ADDR_FOR_DEFAULT_ROUTE;
1528 			break;
1529 		}
1530 		if (!strncasecmp (atom + 1, "nknown", 6)) {
1531 			if (!strcasecmp (atom + 7, "-clients"))
1532 				return UNKNOWN_CLIENTS;
1533 			if (!strcasecmp (atom + 7, "-state"))
1534 				return UNKNOWN_STATE;
1535 			if (!atom [7])
1536 				return UNKNOWN;
1537 			break;
1538 		}
1539 		if (!strcasecmp (atom + 1, "nauthenticated"))
1540 			return UNAUTHENTICATED;
1541 		if (!strcasecmp (atom + 1, "pdate"))
1542 			return UPDATE;
1543 		break;
1544 	      case 'v':
1545 		if (!strcasecmp (atom + 1, "6relay"))
1546 			return V6RELAY;
1547 		if (!strcasecmp (atom + 1, "6relopt"))
1548 			return V6RELOPT;
1549 		if (!strcasecmp (atom + 1, "endor-class"))
1550 			return VENDOR_CLASS;
1551 		if (!strcasecmp (atom + 1, "endor"))
1552 			return VENDOR;
1553 		break;
1554 	      case 'w':
1555 		if (!strcasecmp (atom + 1, "ith"))
1556 			return WITH;
1557 		if (!strcasecmp(atom + 1, "idth"))
1558 			return WIDTH;
1559 		break;
1560 	      case 'y':
1561 		if (!strcasecmp (atom + 1, "iaddr"))
1562 			return YIADDR;
1563 		if (!strcasecmp (atom + 1, "xdomain"))
1564 			return NS_YXDOMAIN;
1565 		if (!strcasecmp (atom + 1, "xrrset"))
1566 			return NS_YXRRSET;
1567 		break;
1568 	      case 'z':
1569 		if (!strcasecmp (atom + 1, "erolen"))
1570 			return ZEROLEN;
1571 		if (!strcasecmp (atom + 1, "one"))
1572 			return ZONE;
1573 		break;
1574 	}
1575 	return dfv;
1576 }
1577