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