/* conflex.c Lexical scanner for dhcpd config file... */ /* * Copyright (c) 1995, 1996, 1997 The Internet Software Consortium. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of The Internet Software Consortium nor the names * of its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This software has been written for the Internet Software Consortium * by Ted Lemon in cooperation with Vixie * Enterprises. To learn more about the Internet Software Consortium, * see ``http://www.vix.com/isc''. To learn more about Vixie * Enterprises, see ``http://www.vix.com''. */ #ifndef lint static char copyright[] = "$Id: conflex.c,v 1.29.2.4 1999/04/06 14:58:55 mellon Exp $ Copyright (c) 1995, 1996, 1997 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" #include "dhctoken.h" #include int lexline; int lexchar; char *token_line; char *prev_line; char *cur_line; char *tlname; int eol_token; static char line1 [81]; static char line2 [81]; static int lpos; static int line; static int tlpos; static int tline; static int token; static int ugflag; static char *tval; static char tokbuf [1500]; #ifdef OLD_LEXER char comments [4096]; int comment_index; #endif static int get_char PROTO ((FILE *)); static int get_token PROTO ((FILE *)); static void skip_to_eol PROTO ((FILE *)); static int read_string PROTO ((FILE *)); static int read_number PROTO ((int, FILE *)); static int read_num_or_name PROTO ((int, FILE *)); static int intern PROTO ((char *, int)); void new_parse (name) char *name; { tlname = name; lpos = line = 1; cur_line = line1; prev_line = line2; token_line = cur_line; cur_line [0] = prev_line [0] = 0; warnings_occurred = 0; } static int get_char (cfile) FILE *cfile; { int c = getc (cfile); if (!ugflag) { if (c == EOL) { if (cur_line == line1) { cur_line = line2; prev_line = line1; } else { cur_line = line2; prev_line = line1; } line++; lpos = 1; cur_line [0] = 0; } else if (c != EOF) { if (lpos <= 81) { cur_line [lpos - 1] = c; cur_line [lpos] = 0; } lpos++; } } else ugflag = 0; return c; } static int get_token (cfile) FILE *cfile; { int c; int ttok; static char tb [2]; int l, p, u; do { l = line; p = lpos; u = ugflag; c = get_char (cfile); #ifdef OLD_LEXER if (c == '\n' && p == 1 && !u && comment_index < sizeof comments) comments [comment_index++] = '\n'; #endif if (!(c == '\n' && eol_token) && isascii (c) && isspace (c)) continue; if (c == '#') { #ifdef OLD_LEXER if (comment_index < sizeof comments) comments [comment_index++] = '#'; #endif skip_to_eol (cfile); continue; } if (c == '"') { lexline = l; lexchar = p; ttok = read_string (cfile); break; } if ((isascii (c) && isdigit (c)) || c == '-') { lexline = l; lexchar = p; ttok = read_number (c, cfile); break; } else if (isascii (c) && isalpha (c)) { lexline = l; lexchar = p; ttok = read_num_or_name (c, cfile); break; } else { lexline = l; lexchar = p; tb [0] = c; tb [1] = 0; tval = tb; ttok = c; break; } } while (1); return ttok; } int next_token (rval, cfile) char **rval; FILE *cfile; { int rv; if (token) { if (lexline != tline) token_line = cur_line; lexchar = tlpos; lexline = tline; rv = token; token = 0; } else { rv = get_token (cfile); token_line = cur_line; } if (rval) *rval = tval; #ifdef DEBUG_TOKENS fprintf (stderr, "%s:%d ", tval, rv); #endif return rv; } int peek_token (rval, cfile) char **rval; FILE *cfile; { int x; if (!token) { tlpos = lexchar; tline = lexline; token = get_token (cfile); if (lexline != tline) token_line = prev_line; x = lexchar; lexchar = tlpos; tlpos = x; x = lexline; lexline = tline; tline = x; } if (rval) *rval = tval; #ifdef DEBUG_TOKENS fprintf (stderr, "(%s:%d) ", tval, token); #endif return token; } static void skip_to_eol (cfile) FILE *cfile; { int c; do { c = get_char (cfile); if (c == EOF) return; #ifdef OLD_LEXER if (comment_index < sizeof (comments)) comments [comment_index++] = c; #endif if (c == EOL) { return; } } while (1); } static int read_string (cfile) FILE *cfile; { int i; int bs = 0; int c; for (i = 0; i < sizeof tokbuf; i++) { c = get_char (cfile); if (c == EOF) { parse_warn ("eof in string constant"); break; } if (bs) { bs = 0; tokbuf [i] = c; } else if (c == '\\') bs = 1; else if (c == '"') break; else tokbuf [i] = c; } /* Normally, I'd feel guilty about this, but we're talking about strings that'll fit in a DHCP packet here... */ if (i == sizeof tokbuf) { parse_warn ("string constant larger than internal buffer"); --i; } tokbuf [i] = 0; tval = tokbuf; return STRING; } static int read_number (c, cfile) int c; FILE *cfile; { int seenx = 0; int i = 0; int token = NUMBER; tokbuf [i++] = c; for (; i < sizeof tokbuf; i++) { c = get_char (cfile); if (!seenx && c == 'x') { seenx = 1; #ifndef OLD_LEXER } else if (isascii (c) && !isxdigit (c) && (c == '-' || c == '_' || isalpha (c))) { token = NAME; } else if (isascii (c) && !isdigit (c) && isxdigit (c)) { token = NUMBER_OR_NAME; #endif } else if (!isascii (c) || !isxdigit (c)) { ungetc (c, cfile); ugflag = 1; break; } tokbuf [i] = c; } if (i == sizeof tokbuf) { parse_warn ("numeric token larger than internal buffer"); --i; } tokbuf [i] = 0; tval = tokbuf; return token; } static int read_num_or_name (c, cfile) int c; FILE *cfile; { int i = 0; int rv = NUMBER_OR_NAME; tokbuf [i++] = c; for (; i < sizeof tokbuf; i++) { c = get_char (cfile); if (!isascii (c) || (c != '-' && c != '_' && !isalnum (c))) { ungetc (c, cfile); ugflag = 1; break; } if (!isxdigit (c)) rv = NAME; tokbuf [i] = c; } if (i == sizeof tokbuf) { parse_warn ("token larger than internal buffer"); --i; } tokbuf [i] = 0; tval = tokbuf; return intern (tval, rv); } static int intern (atom, dfv) char *atom; int dfv; { if (!isascii (atom [0])) return dfv; switch (tolower (atom [0])) { case 'a': if (!strcasecmp (atom + 1, "lways-reply-rfc1048")) return ALWAYS_REPLY_RFC1048; if (!strcasecmp (atom + 1, "ppend")) return APPEND; if (!strcasecmp (atom + 1, "llow")) return ALLOW; if (!strcasecmp (atom + 1, "lias")) return ALIAS; if (!strcasecmp (atom + 1, "bandoned")) return ABANDONED; if (!strcasecmp (atom + 1, "uthoritative")) return AUTHORITATIVE; break; case 'b': if (!strcasecmp (atom + 1, "ackoff-cutoff")) return BACKOFF_CUTOFF; if (!strcasecmp (atom + 1, "ootp")) return BOOTP; if (!strcasecmp (atom + 1, "ooting")) return BOOTING; if (!strcasecmp (atom + 1, "oot-unknown-clients")) return BOOT_UNKNOWN_CLIENTS; case 'c': if (!strcasecmp (atom + 1, "lass")) return CLASS; if (!strcasecmp (atom + 1, "iaddr")) return CIADDR; if (!strcasecmp (atom + 1, "lient-identifier")) return CLIENT_IDENTIFIER; if (!strcasecmp (atom + 1, "lient-hostname")) return CLIENT_HOSTNAME; break; case 'd': if (!strcasecmp (atom + 1, "omain")) return DOMAIN; if (!strcasecmp (atom + 1, "eny")) return DENY; if (!strncasecmp (atom + 1, "efault", 6)) { if (!atom [7]) return DEFAULT; if (!strcasecmp (atom + 7, "-lease-time")) return DEFAULT_LEASE_TIME; break; } if (!strncasecmp (atom + 1, "ynamic-bootp", 12)) { if (!atom [13]) return DYNAMIC_BOOTP; if (!strcasecmp (atom + 13, "-lease-cutoff")) return DYNAMIC_BOOTP_LEASE_CUTOFF; if (!strcasecmp (atom + 13, "-lease-length")) return DYNAMIC_BOOTP_LEASE_LENGTH; break; } break; case 'e': if (!strcasecmp (atom + 1, "thernet")) return ETHERNET; if (!strcasecmp (atom + 1, "nds")) return ENDS; if (!strcasecmp (atom + 1, "xpire")) return EXPIRE; break; case 'f': if (!strcasecmp (atom + 1, "ilename")) return FILENAME; if (!strcasecmp (atom + 1, "ixed-address")) return FIXED_ADDR; if (!strcasecmp (atom + 1, "ddi")) return FDDI; break; case 'g': if (!strcasecmp (atom + 1, "iaddr")) return GIADDR; if (!strcasecmp (atom + 1, "roup")) return GROUP; if (!strcasecmp (atom + 1, "et-lease-hostnames")) return GET_LEASE_HOSTNAMES; break; case 'h': if (!strcasecmp (atom + 1, "ost")) return HOST; if (!strcasecmp (atom + 1, "ardware")) return HARDWARE; if (!strcasecmp (atom + 1, "ostname")) return HOSTNAME; break; case 'i': if (!strcasecmp (atom + 1, "nitial-interval")) return INITIAL_INTERVAL; if (!strcasecmp (atom + 1, "nterface")) return INTERFACE; break; case 'l': if (!strcasecmp (atom + 1, "ease")) return LEASE; break; case 'm': if (!strcasecmp (atom + 1, "ax-lease-time")) return MAX_LEASE_TIME; if (!strncasecmp (atom + 1, "edi", 3)) { if (!strcasecmp (atom + 4, "a")) return MEDIA; if (!strcasecmp (atom + 4, "um")) return MEDIUM; break; } break; case 'n': if (!strcasecmp (atom + 1, "ameserver")) return NAMESERVER; if (!strcasecmp (atom + 1, "etmask")) return NETMASK; if (!strcasecmp (atom + 1, "ext-server")) return NEXT_SERVER; if (!strcasecmp (atom + 1, "ot")) return TOKEN_NOT; break; case 'o': if (!strcasecmp (atom + 1, "ption")) return OPTION; if (!strcasecmp (atom + 1, "ne-lease-per-client")) return ONE_LEASE_PER_CLIENT; break; case 'p': if (!strcasecmp (atom + 1, "repend")) return PREPEND; if (!strcasecmp (atom + 1, "acket")) return PACKET; break; case 'r': if (!strcasecmp (atom + 1, "ange")) return RANGE; if (!strcasecmp (atom + 1, "equest")) return REQUEST; if (!strcasecmp (atom + 1, "equire")) return REQUIRE; if (!strcasecmp (atom + 1, "etry")) return RETRY; if (!strcasecmp (atom + 1, "enew")) return RENEW; if (!strcasecmp (atom + 1, "ebind")) return REBIND; if (!strcasecmp (atom + 1, "eboot")) return REBOOT; if (!strcasecmp (atom + 1, "eject")) return REJECT; break; case 's': if (!strcasecmp (atom + 1, "earch")) return SEARCH; if (!strcasecmp (atom + 1, "tarts")) return STARTS; if (!strcasecmp (atom + 1, "iaddr")) return SIADDR; if (!strcasecmp (atom + 1, "ubnet")) return SUBNET; if (!strcasecmp (atom + 1, "hared-network")) return SHARED_NETWORK; if (!strcasecmp (atom + 1, "erver-name")) return SERVER_NAME; if (!strcasecmp (atom + 1, "erver-identifier")) return SERVER_IDENTIFIER; if (!strcasecmp (atom + 1, "elect-timeout")) return SELECT_TIMEOUT; if (!strcasecmp (atom + 1, "end")) return SEND; if (!strcasecmp (atom + 1, "cript")) return SCRIPT; if (!strcasecmp (atom + 1, "upersede")) return SUPERSEDE; break; case 't': if (!strcasecmp (atom + 1, "imestamp")) return TIMESTAMP; if (!strcasecmp (atom + 1, "imeout")) return TIMEOUT; if (!strcasecmp (atom + 1, "oken-ring")) return TOKEN_RING; break; case 'u': if (!strncasecmp (atom + 1, "se", 2)) { if (!strcasecmp (atom + 3, "r-class")) return USER_CLASS; if (!strcasecmp (atom + 3, "-host-decl-names")) return USE_HOST_DECL_NAMES; if (!strcasecmp (atom + 3, "-lease-addr-for-default-route")) return USE_LEASE_ADDR_FOR_DEFAULT_ROUTE; break; } if (!strcasecmp (atom + 1, "id")) return UID; if (!strcasecmp (atom + 1, "nknown-clients")) return UNKNOWN_CLIENTS; break; case 'v': if (!strcasecmp (atom + 1, "endor-class")) return VENDOR_CLASS; break; case 'y': if (!strcasecmp (atom + 1, "iaddr")) return YIADDR; break; } return dfv; }