xref: /netbsd-src/external/mpl/dhcp/dist/common/conflex.c (revision e6c7e151de239c49d2e38720a061ed9d1fa99309)
1 /*	$NetBSD: conflex.c,v 1.2 2018/04/07 22:37:29 christos Exp $	*/
2 
3 /* conflex.c
4 
5    Lexical scanner for dhcpd config file... */
6 
7 /*
8  * Copyright (c) 2004-2017 by 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  *   950 Charter Street
25  *   Redwood City, CA 94063
26  *   <info@isc.org>
27  *   https://www.isc.org/
28  *
29  */
30 
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: conflex.c,v 1.2 2018/04/07 22:37:29 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 
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 
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
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
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 
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
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
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
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
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
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
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
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
459 peek_raw_token(const char **rval, unsigned *rlen, struct parse *cfile) {
460 	return do_peek_token(rval, rlen, cfile, ISC_TRUE);
461 }
462 
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
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 
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 
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 
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
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 		break;
963 	      case 'e':
964 		if (isascii (atom [1]) &&
965 		    tolower((unsigned char)atom[1]) == 'x') {
966 			if (!strcasecmp (atom + 2, "tract-int"))
967 				return EXTRACT_INT;
968 			if (!strcasecmp (atom + 2, "ists"))
969 				return EXISTS;
970 			if (!strcasecmp (atom + 2, "piry"))
971 				return EXPIRY;
972 			if (!strcasecmp (atom + 2, "pire"))
973 				return EXPIRE;
974 			if (!strcasecmp (atom + 2, "pired"))
975 				return TOKEN_EXPIRED;
976 		}
977 		if (!strcasecmp (atom + 1, "ncode-int"))
978 			return ENCODE_INT;
979 		if (!strcasecmp(atom + 1, "poch"))
980 			return EPOCH;
981 		if (!strcasecmp (atom + 1, "thernet"))
982 			return ETHERNET;
983 		if (!strcasecmp (atom + 1, "nds"))
984 			return ENDS;
985 		if (!strncasecmp (atom + 1, "ls", 2)) {
986 			if (!strcasecmp (atom + 3, "e"))
987 				return ELSE;
988 			if (!strcasecmp (atom + 3, "if"))
989 				return ELSIF;
990 			break;
991 		}
992 		if (!strcasecmp (atom + 1, "rror"))
993 			return ERROR;
994 		if (!strcasecmp (atom + 1, "val"))
995 			return EVAL;
996 		if (!strcasecmp (atom + 1, "ncapsulate"))
997 			return ENCAPSULATE;
998 		if (!strcasecmp(atom + 1, "xecute"))
999 			return EXECUTE;
1000 		if (!strcasecmp(atom+1, "n")) {
1001 			return EN;
1002 		}
1003 		break;
1004 	      case 'f':
1005 		if (!strcasecmp (atom + 1, "atal"))
1006 			return FATAL;
1007 		if (!strcasecmp (atom + 1, "ilename"))
1008 			return FILENAME;
1009 		if (!strcasecmp (atom + 1, "ixed-address"))
1010 			return FIXED_ADDR;
1011 		if (!strcasecmp (atom + 1, "ixed-address6"))
1012 			return FIXED_ADDR6;
1013 		if (!strcasecmp (atom + 1, "ixed-prefix6"))
1014 			return FIXED_PREFIX6;
1015 		if (!strcasecmp (atom + 1, "ddi"))
1016 			return TOKEN_FDDI;
1017 		if (!strcasecmp (atom + 1, "ormerr"))
1018 			return NS_FORMERR;
1019 		if (!strcasecmp (atom + 1, "unction"))
1020 			return FUNCTION;
1021 		if (!strcasecmp (atom + 1, "ailover"))
1022 			return FAILOVER;
1023 		if (!strcasecmp (atom + 1, "ree"))
1024 			return TOKEN_FREE;
1025 		break;
1026 	      case 'g':
1027 		if (!strncasecmp(atom + 1, "et", 2)) {
1028 			if (!strcasecmp(atom + 3, "-lease-hostnames"))
1029 				return GET_LEASE_HOSTNAMES;
1030 			if (!strcasecmp(atom + 3, "hostbyname"))
1031 				return GETHOSTBYNAME;
1032 			if (!strcasecmp(atom + 3, "hostname"))
1033 				return GETHOSTNAME;
1034 			break;
1035 		}
1036 		if (!strcasecmp (atom + 1, "iaddr"))
1037 			return GIADDR;
1038 		if (!strcasecmp (atom + 1, "roup"))
1039 			return GROUP;
1040 		break;
1041 	      case 'h':
1042 		if (!strcasecmp(atom + 1, "ash"))
1043 			return HASH;
1044 		if (!strcasecmp (atom + 1, "ba"))
1045 			return HBA;
1046 		if (!strcasecmp (atom + 1, "ost"))
1047 			return HOST;
1048 		if (!strcasecmp (atom + 1, "ost-decl-name"))
1049 			return HOST_DECL_NAME;
1050 		if (!strcasecmp(atom + 1, "ost-identifier"))
1051 			return HOST_IDENTIFIER;
1052 		if (!strcasecmp (atom + 1, "ardware"))
1053 			return HARDWARE;
1054 		if (!strcasecmp (atom + 1, "ostname"))
1055 			return HOSTNAME;
1056 		if (!strcasecmp (atom + 1, "elp"))
1057 			return TOKEN_HELP;
1058 		if (!strcasecmp (atom + 1, "ex")) {
1059 			return TOKEN_HEX;
1060 		}
1061 		break;
1062 	      case 'i':
1063 	      	if (!strcasecmp(atom+1, "a-na"))
1064 			return IA_NA;
1065 	      	if (!strcasecmp(atom+1, "a-ta"))
1066 			return IA_TA;
1067 	      	if (!strcasecmp(atom+1, "a-pd"))
1068 			return IA_PD;
1069 	      	if (!strcasecmp(atom+1, "aaddr"))
1070 			return IAADDR;
1071 	      	if (!strcasecmp(atom+1, "aprefix"))
1072 			return IAPREFIX;
1073 		if (!strcasecmp (atom + 1, "nclude"))
1074 			return INCLUDE;
1075 		if (!strcasecmp (atom + 1, "nteger"))
1076 			return INTEGER;
1077 		if (!strcasecmp (atom  + 1, "nfiniband"))
1078 			return TOKEN_INFINIBAND;
1079 		if (!strcasecmp (atom + 1, "nfinite"))
1080 			return INFINITE;
1081 		if (!strcasecmp (atom + 1, "nfo"))
1082 			return INFO;
1083 		if (!strcasecmp (atom + 1, "p-address"))
1084 			return IP_ADDRESS;
1085 		if (!strcasecmp (atom + 1, "p6-address"))
1086 			return IP6_ADDRESS;
1087 		if (!strcasecmp (atom + 1, "nitial-interval"))
1088 			return INITIAL_INTERVAL;
1089 		if (!strcasecmp (atom + 1, "nitial-delay"))
1090 			return INITIAL_DELAY;
1091 		if (!strcasecmp (atom + 1, "nterface"))
1092 			return INTERFACE;
1093 		if (!strcasecmp (atom + 1, "dentifier"))
1094 			return IDENTIFIER;
1095 		if (!strcasecmp (atom + 1, "f"))
1096 			return IF;
1097 		if (!strcasecmp (atom + 1, "s"))
1098 			return IS;
1099 		if (!strcasecmp (atom + 1, "gnore"))
1100 			return IGNORE;
1101 		break;
1102 	      case 'k':
1103 		if (!strncasecmp (atom + 1, "nown", 4)) {
1104 			if (!strcasecmp (atom + 5, "-clients"))
1105 				return KNOWN_CLIENTS;
1106 			if (!atom[5])
1107 				return KNOWN;
1108 			break;
1109 		}
1110 		if (!strcasecmp (atom + 1, "ey"))
1111 			return KEY;
1112 		if (!strcasecmp (atom + 1, "ey-algorithm"))
1113 			return KEY_ALGORITHM;
1114 		break;
1115 	      case 'l':
1116 		if (!strcasecmp (atom + 1, "case"))
1117 			return LCASE;
1118 		if (!strcasecmp (atom + 1, "ease"))
1119 			return LEASE;
1120 		if (!strcasecmp(atom + 1, "ease6"))
1121 			return LEASE6;
1122 		if (!strcasecmp (atom + 1, "eased-address"))
1123 			return LEASED_ADDRESS;
1124 		if (!strcasecmp (atom + 1, "ease-time"))
1125 			return LEASE_TIME;
1126 		if (!strcasecmp(atom + 1, "easequery"))
1127 			return LEASEQUERY;
1128 		if (!strcasecmp(atom + 1, "ength"))
1129 			return LENGTH;
1130 		if (!strcasecmp (atom + 1, "imit"))
1131 			return LIMIT;
1132 		if (!strcasecmp (atom + 1, "et"))
1133 			return LET;
1134 		if (!strcasecmp (atom + 1, "oad"))
1135 			return LOAD;
1136 		if (!strcasecmp(atom + 1, "ocal"))
1137 			return LOCAL;
1138 		if (!strcasecmp (atom + 1, "og"))
1139 			return LOG;
1140 		if (!strcasecmp(atom+1, "lt")) {
1141 			return LLT;
1142 		}
1143 		if (!strcasecmp(atom+1, "l")) {
1144 			return LL;
1145 		}
1146 		if (!strcasecmp(atom+1, "ittle-endian")) {
1147 			return TOKEN_LITTLE_ENDIAN;
1148 		}
1149 		if (!strcasecmp (atom + 1, "ease-id-format")) {
1150 			return LEASE_ID_FORMAT;
1151 		}
1152 		break;
1153 	      case 'm':
1154 		if (!strncasecmp (atom + 1, "ax", 2)) {
1155 			if (!atom [3])
1156 				return TOKEN_MAX;
1157 			if (!strcasecmp (atom + 3, "-balance"))
1158 				return MAX_BALANCE;
1159 			if (!strncasecmp (atom + 3, "-lease-", 7)) {
1160 				if (!strcasecmp(atom + 10, "misbalance"))
1161 					return MAX_LEASE_MISBALANCE;
1162 				if (!strcasecmp(atom + 10, "ownership"))
1163 					return MAX_LEASE_OWNERSHIP;
1164 				if (!strcasecmp(atom + 10, "time"))
1165 					return MAX_LEASE_TIME;
1166 			}
1167 			if (!strcasecmp(atom + 3, "-life"))
1168 				return MAX_LIFE;
1169 			if (!strcasecmp (atom + 3, "-transmit-idle"))
1170 				return MAX_TRANSMIT_IDLE;
1171 			if (!strcasecmp (atom + 3, "-response-delay"))
1172 				return MAX_RESPONSE_DELAY;
1173 			if (!strcasecmp (atom + 3, "-unacked-updates"))
1174 				return MAX_UNACKED_UPDATES;
1175 		}
1176 		if (!strncasecmp (atom + 1, "in-", 3)) {
1177 			if (!strcasecmp (atom + 4, "balance"))
1178 				return MIN_BALANCE;
1179 			if (!strcasecmp (atom + 4, "lease-time"))
1180 				return MIN_LEASE_TIME;
1181 			if (!strcasecmp (atom + 4, "secs"))
1182 				return MIN_SECS;
1183 			break;
1184 		}
1185 		if (!strncasecmp (atom + 1, "edi", 3)) {
1186 			if (!strcasecmp (atom + 4, "a"))
1187 				return MEDIA;
1188 			if (!strcasecmp (atom + 4, "um"))
1189 				return MEDIUM;
1190 			break;
1191 		}
1192 		if (!strcasecmp (atom + 1, "atch"))
1193 			return MATCH;
1194 		if (!strcasecmp (atom + 1, "embers"))
1195 			return MEMBERS;
1196 		if (!strcasecmp (atom + 1, "y"))
1197 			return MY;
1198 		if (!strcasecmp (atom + 1, "clt"))
1199 			return MCLT;
1200 		break;
1201 	      case 'n':
1202 		if (!strcasecmp (atom + 1, "ormal"))
1203 			return NORMAL;
1204 		if (!strcasecmp (atom + 1, "ameserver"))
1205 			return NAMESERVER;
1206 		if (!strcasecmp (atom + 1, "etmask"))
1207 			return NETMASK;
1208 		if (!strcasecmp (atom + 1, "ever"))
1209 			return NEVER;
1210 		if (!strcasecmp (atom + 1, "ext-server"))
1211 			return NEXT_SERVER;
1212 		if (!strcasecmp (atom + 1, "ot"))
1213 			return TOKEN_NOT;
1214 		if (!strcasecmp (atom + 1, "o"))
1215 			return TOKEN_NO;
1216 		if (!strcasecmp (atom + 1, "oerror"))
1217 			return NS_NOERROR;
1218 		if (!strcasecmp (atom + 1, "otauth"))
1219 			return NS_NOTAUTH;
1220 		if (!strcasecmp (atom + 1, "otimp"))
1221 			return NS_NOTIMP;
1222 		if (!strcasecmp (atom + 1, "otzone"))
1223 			return NS_NOTZONE;
1224 		if (!strcasecmp (atom + 1, "xdomain"))
1225 			return NS_NXDOMAIN;
1226 		if (!strcasecmp (atom + 1, "xrrset"))
1227 			return NS_NXRRSET;
1228 		if (!strcasecmp (atom + 1, "ull"))
1229 			return TOKEN_NULL;
1230 		if (!strcasecmp (atom + 1, "ext"))
1231 			return TOKEN_NEXT;
1232 		if (!strcasecmp (atom + 1, "ew"))
1233 			return TOKEN_NEW;
1234 		break;
1235 	      case 'o':
1236 		if (!strcasecmp (atom + 1, "mapi"))
1237 			return OMAPI;
1238 		if (!strcasecmp (atom + 1, "r"))
1239 			return OR;
1240 		if (!strcasecmp (atom + 1, "n"))
1241 			return ON;
1242 		if (!strcasecmp (atom + 1, "pen"))
1243 			return TOKEN_OPEN;
1244 		if (!strcasecmp (atom + 1, "ption"))
1245 			return OPTION;
1246 		if (!strcasecmp (atom + 1, "ne-lease-per-client"))
1247 			return ONE_LEASE_PER_CLIENT;
1248 		if (!strcasecmp (atom + 1, "f"))
1249 			return OF;
1250 		if (!strcasecmp (atom + 1, "wner"))
1251 			return OWNER;
1252 		if (!strcasecmp (atom + 1, "ctal")) {
1253 			return TOKEN_OCTAL;
1254 		}
1255 		break;
1256 	      case 'p':
1257 		if (!strcasecmp (atom + 1, "arse-vendor-option"))
1258 			return PARSE_VENDOR_OPT;
1259 		if (!strcasecmp (atom + 1, "repend"))
1260 			return PREPEND;
1261 		if (!strcasecmp(atom + 1, "referred-life"))
1262 			return PREFERRED_LIFE;
1263 		if (!strcasecmp (atom + 1, "acket"))
1264 			return PACKET;
1265 		if (!strcasecmp (atom + 1, "ool"))
1266 			return POOL;
1267 		if (!strcasecmp (atom + 1, "ool6"))
1268 			return POOL6;
1269 		if (!strcasecmp (atom + 1, "refix6"))
1270 			return PREFIX6;
1271 		if (!strcasecmp (atom + 1, "seudo"))
1272 			return PSEUDO;
1273 		if (!strcasecmp (atom + 1, "eer"))
1274 			return PEER;
1275 		if (!strcasecmp (atom + 1, "rimary"))
1276 			return PRIMARY;
1277 		if (!strcasecmp (atom + 1, "rimary6"))
1278 			return PRIMARY6;
1279 		if (!strncasecmp (atom + 1, "artner", 6)) {
1280 			if (!atom [7])
1281 				return PARTNER;
1282 			if (!strcasecmp (atom + 7, "-down"))
1283 				return PARTNER_DOWN;
1284 		}
1285 		if (!strcasecmp (atom + 1, "ort"))
1286 			return PORT;
1287 		if (!strcasecmp (atom + 1, "otential-conflict"))
1288 			return POTENTIAL_CONFLICT;
1289 		if (!strcasecmp (atom + 1, "ick-first-value") ||
1290 		    !strcasecmp (atom + 1, "ick"))
1291 			return PICK;
1292 		if (!strcasecmp (atom + 1, "aused"))
1293 			return PAUSED;
1294 		break;
1295 	      case 'r':
1296 		if (!strcasecmp(atom + 1, "ange"))
1297 			return RANGE;
1298 		if (!strcasecmp(atom + 1, "ange6"))
1299 			return RANGE6;
1300 		if (isascii(atom[1]) &&
1301 		    (tolower((unsigned char)atom[1]) == 'e')) {
1302 			if (!strcasecmp(atom + 2, "bind"))
1303 				return REBIND;
1304 			if (!strcasecmp(atom + 2, "boot"))
1305 				return REBOOT;
1306 			if (!strcasecmp(atom + 2, "contact-interval"))
1307 				return RECONTACT_INTERVAL;
1308 			if (!strncasecmp(atom + 2, "cover", 5)) {
1309 				if (atom[7] == '\0')
1310 					return RECOVER;
1311 				if (!strcasecmp(atom + 7, "-done"))
1312 					return RECOVER_DONE;
1313 				if (!strcasecmp(atom + 7, "-wait"))
1314 					return RECOVER_WAIT;
1315 				break;
1316 			}
1317 			if (!strcasecmp(atom + 2, "fresh"))
1318 				return REFRESH;
1319 			if (!strcasecmp(atom + 2, "fused"))
1320 				return NS_REFUSED;
1321 			if (!strcasecmp(atom + 2, "ject"))
1322 				return REJECT;
1323 			if (!strcasecmp(atom + 2, "lease"))
1324 				return RELEASE;
1325 			if (!strcasecmp(atom + 2, "leased"))
1326 				return TOKEN_RELEASED;
1327 			if (!strcasecmp(atom + 2, "move"))
1328 				return REMOVE;
1329 			if (!strcasecmp(atom + 2, "new"))
1330 				return RENEW;
1331 			if (!strcasecmp(atom + 2, "quest"))
1332 				return REQUEST;
1333 			if (!strcasecmp(atom + 2, "quire"))
1334 				return REQUIRE;
1335 			if (isascii(atom[2]) &&
1336 			    (tolower((unsigned char)atom[2]) == 's')) {
1337 				if (!strcasecmp(atom + 3, "erved"))
1338 					return TOKEN_RESERVED;
1339 				if (!strcasecmp(atom + 3, "et"))
1340 					return TOKEN_RESET;
1341 				if (!strcasecmp(atom + 3,
1342 						"olution-interrupted"))
1343 					return RESOLUTION_INTERRUPTED;
1344 				break;
1345 			}
1346 			if (!strcasecmp(atom + 2, "try"))
1347 				return RETRY;
1348 			if (!strcasecmp(atom + 2, "turn"))
1349 				return RETURN;
1350 			if (!strcasecmp(atom + 2, "verse"))
1351 				return REVERSE;
1352 			if (!strcasecmp(atom + 2, "wind"))
1353 				return REWIND;
1354 			break;
1355 		}
1356 		break;
1357 	      case 's':
1358 		if (!strcasecmp(atom + 1, "cript"))
1359 			return SCRIPT;
1360 		if (isascii(atom[1]) &&
1361 		    tolower((unsigned char)atom[1]) == 'e') {
1362 			if (!strcasecmp(atom + 2, "arch"))
1363 				return SEARCH;
1364 			if (isascii(atom[2]) &&
1365 			    tolower((unsigned char)atom[2]) == 'c') {
1366 				if (!strncasecmp(atom + 3, "ond", 3)) {
1367                                         if (!strcasecmp(atom + 6, "ary"))
1368 						return SECONDARY;
1369                                         if (!strcasecmp(atom + 6, "ary6"))
1370 						return SECONDARY6;
1371                                         if (!strcasecmp(atom + 6, "s"))
1372                                                 return SECONDS;
1373 					break;
1374 				}
1375                                 if (!strcasecmp(atom + 3, "ret"))
1376                                         return SECRET;
1377 				break;
1378 			}
1379 			if (!strncasecmp(atom + 2, "lect", 4)) {
1380                                 if (atom[6] == '\0')
1381                                         return SELECT;
1382                                 if (!strcasecmp(atom + 6, "-timeout"))
1383                                         return SELECT_TIMEOUT;
1384 				break;
1385 			}
1386                         if (!strcasecmp(atom + 2, "nd"))
1387                                 return SEND;
1388 			if (!strncasecmp(atom + 2, "rv", 2)) {
1389 				if (!strncasecmp(atom + 4, "er", 2)) {
1390                                         if (atom[6] == '\0')
1391                                                 return TOKEN_SERVER;
1392 					if (atom[6] == '-') {
1393 						if (!strcasecmp(atom + 7,
1394 								"duid"))
1395 							return SERVER_DUID;
1396                                                 if (!strcasecmp(atom + 7,
1397 								"name"))
1398                                                         return SERVER_NAME;
1399                                                 if (!strcasecmp(atom + 7,
1400 								"identifier"))
1401                                                       return SERVER_IDENTIFIER;
1402 						break;
1403 					}
1404 					break;
1405 				}
1406                                 if (!strcasecmp(atom + 4, "fail"))
1407                                         return NS_SERVFAIL;
1408 				break;
1409 			}
1410                         if (!strcasecmp(atom + 2, "t"))
1411                                 return TOKEN_SET;
1412 			break;
1413 		}
1414 		if (isascii(atom[1]) &&
1415 		    tolower((unsigned char)atom[1]) == 'h') {
1416                         if (!strcasecmp(atom + 2, "ared-network"))
1417                                 return SHARED_NETWORK;
1418                         if (!strcasecmp(atom + 2, "utdown"))
1419                                 return SHUTDOWN;
1420 			break;
1421 		}
1422 		if (isascii(atom[1]) &&
1423 		    tolower((unsigned char)atom[1]) == 'i') {
1424                         if (!strcasecmp(atom + 2, "addr"))
1425                                 return SIADDR;
1426                         if (!strcasecmp(atom + 2, "gned"))
1427                                 return SIGNED;
1428                         if (!strcasecmp(atom + 2, "ze"))
1429                                 return SIZE;
1430 			break;
1431 		}
1432 		if (isascii(atom[1]) &&
1433 		    tolower((unsigned char)atom[1]) == 'p') {
1434 			if (isascii(atom[2]) &&
1435 			    tolower((unsigned char)atom[2]) == 'a') {
1436                                 if (!strcasecmp(atom + 3, "ce"))
1437                                         return SPACE;
1438                                 if (!strcasecmp(atom + 3, "wn"))
1439                                         return SPAWN;
1440 				break;
1441 			}
1442                         if (!strcasecmp(atom + 2, "lit"))
1443                                 return SPLIT;
1444 			break;
1445 		}
1446 		if (isascii(atom[1]) &&
1447 		    tolower((unsigned char)atom[1]) == 't') {
1448 			if (isascii(atom[2]) &&
1449 			    tolower((unsigned char)atom[2]) == 'a') {
1450 				if(!strncasecmp(atom + 3, "rt", 2)) {
1451                                          if (!strcasecmp(atom + 5, "s"))
1452                                                  return STARTS;
1453                                          if (!strcasecmp(atom + 5, "up"))
1454                                                  return STARTUP;
1455 					break;
1456 				}
1457 				if (isascii(atom[3]) &&
1458 				    tolower((unsigned char)atom[3]) == 't') {
1459                                         if (!strcasecmp(atom + 4, "e"))
1460                                                 return STATE;
1461                                         if (!strcasecmp(atom + 4, "ic"))
1462                                                 return STATIC;
1463 					break;
1464 				}
1465 			}
1466                         if (!strcasecmp(atom + 2, "ring"))
1467                                 return STRING_TOKEN;
1468 			break;
1469 		}
1470                 if (!strncasecmp(atom + 1, "ub", 2)) {
1471                         if (!strcasecmp(atom + 3, "class"))
1472                                 return SUBCLASS;
1473                         if (!strcasecmp(atom + 3, "net"))
1474                                 return SUBNET;
1475                         if (!strcasecmp(atom + 3, "net6"))
1476                                 return SUBNET6;
1477                         if (!strcasecmp(atom + 3, "string"))
1478                                 return SUBSTRING;
1479                         break;
1480                 }
1481 		if (isascii(atom[1]) &&
1482 		    tolower((unsigned char)atom[1]) == 'u') {
1483                         if (!strcasecmp(atom + 2, "ffix"))
1484                                 return SUFFIX;
1485                         if (!strcasecmp(atom + 2, "persede"))
1486                                 return SUPERSEDE;
1487 		}
1488                 if (!strcasecmp(atom + 1, "witch"))
1489                         return SWITCH;
1490 		break;
1491 	      case 't':
1492 		if (!strcasecmp (atom + 1, "imestamp"))
1493 			return TIMESTAMP;
1494 		if (!strcasecmp (atom + 1, "imeout"))
1495 			return TIMEOUT;
1496 		if (!strcasecmp (atom + 1, "oken-ring"))
1497 			return TOKEN_RING;
1498 		if (!strcasecmp (atom + 1, "ext"))
1499 			return TEXT;
1500 		if (!strcasecmp (atom + 1, "stp"))
1501 			return TSTP;
1502 		if (!strcasecmp (atom + 1, "sfp"))
1503 			return TSFP;
1504 		if (!strcasecmp (atom + 1, "ransmission"))
1505 			return TRANSMISSION;
1506 		if (!strcasecmp(atom + 1, "emporary"))
1507 			return TEMPORARY;
1508 		break;
1509 	      case 'u':
1510 		if (!strcasecmp (atom + 1, "case"))
1511 			return UCASE;
1512 		if (!strcasecmp (atom + 1, "nset"))
1513 			return UNSET;
1514 		if (!strcasecmp (atom + 1, "nsigned"))
1515 			return UNSIGNED;
1516 		if (!strcasecmp (atom + 1, "id"))
1517 			return UID;
1518 		if (!strncasecmp (atom + 1, "se", 2)) {
1519 			if (!strcasecmp (atom + 3, "r-class"))
1520 				return USER_CLASS;
1521 			if (!strcasecmp (atom + 3, "-host-decl-names"))
1522 				return USE_HOST_DECL_NAMES;
1523 			if (!strcasecmp (atom + 3,
1524 					 "-lease-addr-for-default-route"))
1525 				return USE_LEASE_ADDR_FOR_DEFAULT_ROUTE;
1526 			break;
1527 		}
1528 		if (!strncasecmp (atom + 1, "nknown", 6)) {
1529 			if (!strcasecmp (atom + 7, "-clients"))
1530 				return UNKNOWN_CLIENTS;
1531 			if (!strcasecmp (atom + 7, "-state"))
1532 				return UNKNOWN_STATE;
1533 			if (!atom [7])
1534 				return UNKNOWN;
1535 			break;
1536 		}
1537 		if (!strcasecmp (atom + 1, "nauthenticated"))
1538 			return UNAUTHENTICATED;
1539 		if (!strcasecmp (atom + 1, "pdate"))
1540 			return UPDATE;
1541 		break;
1542 	      case 'v':
1543 		if (!strcasecmp (atom + 1, "6relay"))
1544 			return V6RELAY;
1545 		if (!strcasecmp (atom + 1, "6relopt"))
1546 			return V6RELOPT;
1547 		if (!strcasecmp (atom + 1, "endor-class"))
1548 			return VENDOR_CLASS;
1549 		if (!strcasecmp (atom + 1, "endor"))
1550 			return VENDOR;
1551 		break;
1552 	      case 'w':
1553 		if (!strcasecmp (atom + 1, "ith"))
1554 			return WITH;
1555 		if (!strcasecmp(atom + 1, "idth"))
1556 			return WIDTH;
1557 		break;
1558 	      case 'y':
1559 		if (!strcasecmp (atom + 1, "iaddr"))
1560 			return YIADDR;
1561 		if (!strcasecmp (atom + 1, "xdomain"))
1562 			return NS_YXDOMAIN;
1563 		if (!strcasecmp (atom + 1, "xrrset"))
1564 			return NS_YXRRSET;
1565 		break;
1566 	      case 'z':
1567 		if (!strcasecmp (atom + 1, "erolen"))
1568 			return ZEROLEN;
1569 		if (!strcasecmp (atom + 1, "one"))
1570 			return ZONE;
1571 		break;
1572 	}
1573 	return dfv;
1574 }
1575 
1576