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