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