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