File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / lib / isc / lex.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 7 months ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    1: /*
    2:  * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
    3:  * Copyright (C) 1998-2003  Internet Software Consortium.
    4:  *
    5:  * Permission to use, copy, modify, and/or distribute this software for any
    6:  * purpose with or without fee is hereby granted, provided that the above
    7:  * copyright notice and this permission notice appear in all copies.
    8:  *
    9:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
   10:  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
   11:  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
   12:  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
   13:  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
   14:  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
   15:  * PERFORMANCE OF THIS SOFTWARE.
   16:  */
   17: 
   18: /* $Id: lex.c,v 1.1.1.1 2012/05/29 12:08:38 misho Exp $ */
   19: 
   20: /*! \file */
   21: 
   22: #include <config.h>
   23: 
   24: #include <ctype.h>
   25: #include <errno.h>
   26: #include <stdlib.h>
   27: 
   28: #include <isc/buffer.h>
   29: #include <isc/file.h>
   30: #include <isc/lex.h>
   31: #include <isc/mem.h>
   32: #include <isc/msgs.h>
   33: #include <isc/parseint.h>
   34: #include <isc/print.h>
   35: #include <isc/stdio.h>
   36: #include <isc/string.h>
   37: #include <isc/util.h>
   38: 
   39: typedef struct inputsource {
   40: 	isc_result_t			result;
   41: 	isc_boolean_t			is_file;
   42: 	isc_boolean_t			need_close;
   43: 	isc_boolean_t			at_eof;
   44: 	isc_buffer_t *			pushback;
   45: 	unsigned int			ignored;
   46: 	void *				input;
   47: 	char *				name;
   48: 	unsigned long			line;
   49: 	unsigned long			saved_line;
   50: 	ISC_LINK(struct inputsource)	link;
   51: } inputsource;
   52: 
   53: #define LEX_MAGIC			ISC_MAGIC('L', 'e', 'x', '!')
   54: #define VALID_LEX(l)			ISC_MAGIC_VALID(l, LEX_MAGIC)
   55: 
   56: struct isc_lex {
   57: 	/* Unlocked. */
   58: 	unsigned int			magic;
   59: 	isc_mem_t *			mctx;
   60: 	size_t				max_token;
   61: 	char *				data;
   62: 	unsigned int			comments;
   63: 	isc_boolean_t			comment_ok;
   64: 	isc_boolean_t			last_was_eol;
   65: 	unsigned int			paren_count;
   66: 	unsigned int			saved_paren_count;
   67: 	isc_lexspecials_t		specials;
   68: 	LIST(struct inputsource)	sources;
   69: };
   70: 
   71: static inline isc_result_t
   72: grow_data(isc_lex_t *lex, size_t *remainingp, char **currp, char **prevp) {
   73: 	char *new;
   74: 
   75: 	new = isc_mem_get(lex->mctx, lex->max_token * 2 + 1);
   76: 	if (new == NULL)
   77: 		return (ISC_R_NOMEMORY);
   78: 	memcpy(new, lex->data, lex->max_token + 1);
   79: 	*currp = new + (*currp - lex->data);
   80: 	if (*prevp != NULL)
   81: 		*prevp = new + (*prevp - lex->data);
   82: 	isc_mem_put(lex->mctx, lex->data, lex->max_token + 1);
   83: 	lex->data = new;
   84: 	*remainingp += lex->max_token;
   85: 	lex->max_token *= 2;
   86: 	return (ISC_R_SUCCESS);
   87: }
   88: 
   89: isc_result_t
   90: isc_lex_create(isc_mem_t *mctx, size_t max_token, isc_lex_t **lexp) {
   91: 	isc_lex_t *lex;
   92: 
   93: 	/*
   94: 	 * Create a lexer.
   95: 	 */
   96: 
   97: 	REQUIRE(lexp != NULL && *lexp == NULL);
   98: 	REQUIRE(max_token > 0U);
   99: 
  100: 	lex = isc_mem_get(mctx, sizeof(*lex));
  101: 	if (lex == NULL)
  102: 		return (ISC_R_NOMEMORY);
  103: 	lex->data = isc_mem_get(mctx, max_token + 1);
  104: 	if (lex->data == NULL) {
  105: 		isc_mem_put(mctx, lex, sizeof(*lex));
  106: 		return (ISC_R_NOMEMORY);
  107: 	}
  108: 	lex->mctx = mctx;
  109: 	lex->max_token = max_token;
  110: 	lex->comments = 0;
  111: 	lex->comment_ok = ISC_TRUE;
  112: 	lex->last_was_eol = ISC_TRUE;
  113: 	lex->paren_count = 0;
  114: 	lex->saved_paren_count = 0;
  115: 	memset(lex->specials, 0, 256);
  116: 	INIT_LIST(lex->sources);
  117: 	lex->magic = LEX_MAGIC;
  118: 
  119: 	*lexp = lex;
  120: 
  121: 	return (ISC_R_SUCCESS);
  122: }
  123: 
  124: void
  125: isc_lex_destroy(isc_lex_t **lexp) {
  126: 	isc_lex_t *lex;
  127: 
  128: 	/*
  129: 	 * Destroy the lexer.
  130: 	 */
  131: 
  132: 	REQUIRE(lexp != NULL);
  133: 	lex = *lexp;
  134: 	REQUIRE(VALID_LEX(lex));
  135: 
  136: 	while (!EMPTY(lex->sources))
  137: 		RUNTIME_CHECK(isc_lex_close(lex) == ISC_R_SUCCESS);
  138: 	if (lex->data != NULL)
  139: 		isc_mem_put(lex->mctx, lex->data, lex->max_token + 1);
  140: 	lex->magic = 0;
  141: 	isc_mem_put(lex->mctx, lex, sizeof(*lex));
  142: 
  143: 	*lexp = NULL;
  144: }
  145: 
  146: unsigned int
  147: isc_lex_getcomments(isc_lex_t *lex) {
  148: 	/*
  149: 	 * Return the current lexer commenting styles.
  150: 	 */
  151: 
  152: 	REQUIRE(VALID_LEX(lex));
  153: 
  154: 	return (lex->comments);
  155: }
  156: 
  157: void
  158: isc_lex_setcomments(isc_lex_t *lex, unsigned int comments) {
  159: 	/*
  160: 	 * Set allowed lexer commenting styles.
  161: 	 */
  162: 
  163: 	REQUIRE(VALID_LEX(lex));
  164: 
  165: 	lex->comments = comments;
  166: }
  167: 
  168: void
  169: isc_lex_getspecials(isc_lex_t *lex, isc_lexspecials_t specials) {
  170: 	/*
  171: 	 * Put the current list of specials into 'specials'.
  172: 	 */
  173: 
  174: 	REQUIRE(VALID_LEX(lex));
  175: 
  176: 	memcpy(specials, lex->specials, 256);
  177: }
  178: 
  179: void
  180: isc_lex_setspecials(isc_lex_t *lex, isc_lexspecials_t specials) {
  181: 	/*
  182: 	 * The characters in 'specials' are returned as tokens.  Along with
  183: 	 * whitespace, they delimit strings and numbers.
  184: 	 */
  185: 
  186: 	REQUIRE(VALID_LEX(lex));
  187: 
  188: 	memcpy(lex->specials, specials, 256);
  189: }
  190: 
  191: static inline isc_result_t
  192: new_source(isc_lex_t *lex, isc_boolean_t is_file, isc_boolean_t need_close,
  193: 	   void *input, const char *name)
  194: {
  195: 	inputsource *source;
  196: 	isc_result_t result;
  197: 
  198: 	source = isc_mem_get(lex->mctx, sizeof(*source));
  199: 	if (source == NULL)
  200: 		return (ISC_R_NOMEMORY);
  201: 	source->result = ISC_R_SUCCESS;
  202: 	source->is_file = is_file;
  203: 	source->need_close = need_close;
  204: 	source->at_eof = ISC_FALSE;
  205: 	source->input = input;
  206: 	source->name = isc_mem_strdup(lex->mctx, name);
  207: 	if (source->name == NULL) {
  208: 		isc_mem_put(lex->mctx, source, sizeof(*source));
  209: 		return (ISC_R_NOMEMORY);
  210: 	}
  211: 	source->pushback = NULL;
  212: 	result = isc_buffer_allocate(lex->mctx, &source->pushback,
  213: 				     lex->max_token);
  214: 	if (result != ISC_R_SUCCESS) {
  215: 		isc_mem_free(lex->mctx, source->name);
  216: 		isc_mem_put(lex->mctx, source, sizeof(*source));
  217: 		return (result);
  218: 	}
  219: 	source->ignored = 0;
  220: 	source->line = 1;
  221: 	ISC_LIST_INITANDPREPEND(lex->sources, source, link);
  222: 
  223: 	return (ISC_R_SUCCESS);
  224: }
  225: 
  226: isc_result_t
  227: isc_lex_openfile(isc_lex_t *lex, const char *filename) {
  228: 	isc_result_t result;
  229: 	FILE *stream = NULL;
  230: 
  231: 	/*
  232: 	 * Open 'filename' and make it the current input source for 'lex'.
  233: 	 */
  234: 
  235: 	REQUIRE(VALID_LEX(lex));
  236: 
  237: 	result = isc_stdio_open(filename, "r", &stream);
  238: 	if (result != ISC_R_SUCCESS)
  239: 		return (result);
  240: 
  241: 	result = new_source(lex, ISC_TRUE, ISC_TRUE, stream, filename);
  242: 	if (result != ISC_R_SUCCESS)
  243: 		(void)fclose(stream);
  244: 	return (result);
  245: }
  246: 
  247: isc_result_t
  248: isc_lex_openstream(isc_lex_t *lex, FILE *stream) {
  249: 	char name[128];
  250: 
  251: 	/*
  252: 	 * Make 'stream' the current input source for 'lex'.
  253: 	 */
  254: 
  255: 	REQUIRE(VALID_LEX(lex));
  256: 
  257: 	snprintf(name, sizeof(name), "stream-%p", stream);
  258: 
  259: 	return (new_source(lex, ISC_TRUE, ISC_FALSE, stream, name));
  260: }
  261: 
  262: isc_result_t
  263: isc_lex_openbuffer(isc_lex_t *lex, isc_buffer_t *buffer) {
  264: 	char name[128];
  265: 
  266: 	/*
  267: 	 * Make 'buffer' the current input source for 'lex'.
  268: 	 */
  269: 
  270: 	REQUIRE(VALID_LEX(lex));
  271: 
  272: 	snprintf(name, sizeof(name), "buffer-%p", buffer);
  273: 
  274: 	return (new_source(lex, ISC_FALSE, ISC_FALSE, buffer, name));
  275: }
  276: 
  277: isc_result_t
  278: isc_lex_close(isc_lex_t *lex) {
  279: 	inputsource *source;
  280: 
  281: 	/*
  282: 	 * Close the most recently opened object (i.e. file or buffer).
  283: 	 */
  284: 
  285: 	REQUIRE(VALID_LEX(lex));
  286: 
  287: 	source = HEAD(lex->sources);
  288: 	if (source == NULL)
  289: 		return (ISC_R_NOMORE);
  290: 
  291: 	ISC_LIST_UNLINK(lex->sources, source, link);
  292: 	if (source->is_file) {
  293: 		if (source->need_close)
  294: 			(void)fclose((FILE *)(source->input));
  295: 	}
  296: 	isc_mem_free(lex->mctx, source->name);
  297: 	isc_buffer_free(&source->pushback);
  298: 	isc_mem_put(lex->mctx, source, sizeof(*source));
  299: 
  300: 	return (ISC_R_SUCCESS);
  301: }
  302: 
  303: typedef enum {
  304: 	lexstate_start,
  305: 	lexstate_crlf,
  306: 	lexstate_string,
  307: 	lexstate_number,
  308: 	lexstate_maybecomment,
  309: 	lexstate_ccomment,
  310: 	lexstate_ccommentend,
  311: 	lexstate_eatline,
  312: 	lexstate_qstring
  313: } lexstate;
  314: 
  315: #define IWSEOL (ISC_LEXOPT_INITIALWS | ISC_LEXOPT_EOL)
  316: 
  317: static void
  318: pushback(inputsource *source, int c) {
  319: 	REQUIRE(source->pushback->current > 0);
  320: 	if (c == EOF) {
  321: 		source->at_eof = ISC_FALSE;
  322: 		return;
  323: 	}
  324: 	source->pushback->current--;
  325: 	if (c == '\n')
  326: 		source->line--;
  327: }
  328: 
  329: static isc_result_t
  330: pushandgrow(isc_lex_t *lex, inputsource *source, int c) {
  331: 	if (isc_buffer_availablelength(source->pushback) == 0) {
  332: 		isc_buffer_t *tbuf = NULL;
  333: 		unsigned int oldlen;
  334: 		isc_region_t used;
  335: 		isc_result_t result;
  336: 
  337: 		oldlen = isc_buffer_length(source->pushback);
  338: 		result = isc_buffer_allocate(lex->mctx, &tbuf, oldlen * 2);
  339: 		if (result != ISC_R_SUCCESS)
  340: 			return (result);
  341: 		isc_buffer_usedregion(source->pushback, &used);
  342: 		result = isc_buffer_copyregion(tbuf, &used);
  343: 		INSIST(result == ISC_R_SUCCESS);
  344: 		tbuf->current = source->pushback->current;
  345: 		isc_buffer_free(&source->pushback);
  346: 		source->pushback = tbuf;
  347: 	}
  348: 	isc_buffer_putuint8(source->pushback, (isc_uint8_t)c);
  349: 	return (ISC_R_SUCCESS);
  350: }
  351: 
  352: isc_result_t
  353: isc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp) {
  354: 	inputsource *source;
  355: 	int c;
  356: 	isc_boolean_t done = ISC_FALSE;
  357: 	isc_boolean_t no_comments = ISC_FALSE;
  358: 	isc_boolean_t escaped = ISC_FALSE;
  359: 	lexstate state = lexstate_start;
  360: 	lexstate saved_state = lexstate_start;
  361: 	isc_buffer_t *buffer;
  362: 	FILE *stream;
  363: 	char *curr, *prev;
  364: 	size_t remaining;
  365: 	isc_uint32_t as_ulong;
  366: 	unsigned int saved_options;
  367: 	isc_result_t result;
  368: 
  369: 	/*
  370: 	 * Get the next token.
  371: 	 */
  372: 
  373: 	REQUIRE(VALID_LEX(lex));
  374: 	source = HEAD(lex->sources);
  375: 	REQUIRE(tokenp != NULL);
  376: 
  377: 	if (source == NULL) {
  378: 		if ((options & ISC_LEXOPT_NOMORE) != 0) {
  379: 			tokenp->type = isc_tokentype_nomore;
  380: 			return (ISC_R_SUCCESS);
  381: 		}
  382: 		return (ISC_R_NOMORE);
  383: 	}
  384: 
  385: 	if (source->result != ISC_R_SUCCESS)
  386: 		return (source->result);
  387: 
  388: 	lex->saved_paren_count = lex->paren_count;
  389: 	source->saved_line = source->line;
  390: 
  391: 	if (isc_buffer_remaininglength(source->pushback) == 0 &&
  392: 	    source->at_eof)
  393: 	{
  394: 		if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 &&
  395: 		    lex->paren_count != 0) {
  396: 			lex->paren_count = 0;
  397: 			return (ISC_R_UNBALANCED);
  398: 		}
  399: 		if ((options & ISC_LEXOPT_EOF) != 0) {
  400: 			tokenp->type = isc_tokentype_eof;
  401: 			return (ISC_R_SUCCESS);
  402: 		}
  403: 		return (ISC_R_EOF);
  404: 	}
  405: 
  406: 	isc_buffer_compact(source->pushback);
  407: 
  408: 	saved_options = options;
  409: 	if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 && lex->paren_count > 0)
  410: 		options &= ~IWSEOL;
  411: 
  412: 	curr = lex->data;
  413: 	*curr = '\0';
  414: 
  415: 	prev = NULL;
  416: 	remaining = lex->max_token;
  417: 
  418: #ifdef HAVE_FLOCKFILE
  419: 	if (source->is_file)
  420: 		flockfile(source->input);
  421: #endif
  422: 
  423: 	do {
  424: 		if (isc_buffer_remaininglength(source->pushback) == 0) {
  425: 			if (source->is_file) {
  426: 				stream = source->input;
  427: 
  428: #if defined(HAVE_FLOCKFILE) && defined(HAVE_GETCUNLOCKED)
  429: 				c = getc_unlocked(stream);
  430: #else
  431: 				c = getc(stream);
  432: #endif
  433: 				if (c == EOF) {
  434: 					if (ferror(stream)) {
  435: 						source->result = ISC_R_IOERROR;
  436: 						result = source->result;
  437: 						goto done;
  438: 					}
  439: 					source->at_eof = ISC_TRUE;
  440: 				}
  441: 			} else {
  442: 				buffer = source->input;
  443: 
  444: 				if (buffer->current == buffer->used) {
  445: 					c = EOF;
  446: 					source->at_eof = ISC_TRUE;
  447: 				} else {
  448: 					c = *((char *)buffer->base +
  449: 					      buffer->current);
  450: 					buffer->current++;
  451: 				}
  452: 			}
  453: 			if (c != EOF) {
  454: 				source->result = pushandgrow(lex, source, c);
  455: 				if (source->result != ISC_R_SUCCESS) {
  456: 					result = source->result;
  457: 					goto done;
  458: 				}
  459: 			}
  460: 		}
  461: 
  462: 		if (!source->at_eof) {
  463: 			if (state == lexstate_start)
  464: 				/* Token has not started yet. */
  465: 				source->ignored =
  466: 				   isc_buffer_consumedlength(source->pushback);
  467: 			c = isc_buffer_getuint8(source->pushback);
  468: 		} else {
  469: 			c = EOF;
  470: 		}
  471: 
  472: 		if (c == '\n')
  473: 			source->line++;
  474: 
  475: 		if (lex->comment_ok && !no_comments) {
  476: 			if (!escaped && c == ';' &&
  477: 			    ((lex->comments & ISC_LEXCOMMENT_DNSMASTERFILE)
  478: 			     != 0)) {
  479: 				saved_state = state;
  480: 				state = lexstate_eatline;
  481: 				no_comments = ISC_TRUE;
  482: 				continue;
  483: 			} else if (c == '/' &&
  484: 				   (lex->comments &
  485: 				    (ISC_LEXCOMMENT_C|
  486: 				     ISC_LEXCOMMENT_CPLUSPLUS)) != 0) {
  487: 				saved_state = state;
  488: 				state = lexstate_maybecomment;
  489: 				no_comments = ISC_TRUE;
  490: 				continue;
  491: 			} else if (c == '#' &&
  492: 				   ((lex->comments & ISC_LEXCOMMENT_SHELL)
  493: 				    != 0)) {
  494: 				saved_state = state;
  495: 				state = lexstate_eatline;
  496: 				no_comments = ISC_TRUE;
  497: 				continue;
  498: 			}
  499: 		}
  500: 
  501: 	no_read:
  502: 		/* INSIST(c == EOF || (c >= 0 && c <= 255)); */
  503: 		switch (state) {
  504: 		case lexstate_start:
  505: 			if (c == EOF) {
  506: 				lex->last_was_eol = ISC_FALSE;
  507: 				if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 &&
  508: 				    lex->paren_count != 0) {
  509: 					lex->paren_count = 0;
  510: 					result = ISC_R_UNBALANCED;
  511: 					goto done;
  512: 				}
  513: 				if ((options & ISC_LEXOPT_EOF) == 0) {
  514: 					result = ISC_R_EOF;
  515: 					goto done;
  516: 				}
  517: 				tokenp->type = isc_tokentype_eof;
  518: 				done = ISC_TRUE;
  519: 			} else if (c == ' ' || c == '\t') {
  520: 				if (lex->last_was_eol &&
  521: 				    (options & ISC_LEXOPT_INITIALWS)
  522: 				    != 0) {
  523: 					lex->last_was_eol = ISC_FALSE;
  524: 					tokenp->type = isc_tokentype_initialws;
  525:  					tokenp->value.as_char = c;
  526: 					done = ISC_TRUE;
  527: 				}
  528: 			} else if (c == '\n') {
  529: 				if ((options & ISC_LEXOPT_EOL) != 0) {
  530: 					tokenp->type = isc_tokentype_eol;
  531: 					done = ISC_TRUE;
  532: 				}
  533: 				lex->last_was_eol = ISC_TRUE;
  534: 			} else if (c == '\r') {
  535: 				if ((options & ISC_LEXOPT_EOL) != 0)
  536: 					state = lexstate_crlf;
  537: 			} else if (c == '"' &&
  538: 				   (options & ISC_LEXOPT_QSTRING) != 0) {
  539: 				lex->last_was_eol = ISC_FALSE;
  540: 				no_comments = ISC_TRUE;
  541: 				state = lexstate_qstring;
  542: 			} else if (lex->specials[c]) {
  543: 				lex->last_was_eol = ISC_FALSE;
  544: 				if ((c == '(' || c == ')') &&
  545: 				    (options & ISC_LEXOPT_DNSMULTILINE) != 0) {
  546: 					if (c == '(') {
  547: 						if (lex->paren_count == 0)
  548: 							options &= ~IWSEOL;
  549: 						lex->paren_count++;
  550: 					} else {
  551: 						if (lex->paren_count == 0) {
  552: 						    result = ISC_R_UNBALANCED;
  553: 						    goto done;
  554: 						}
  555: 						lex->paren_count--;
  556: 						if (lex->paren_count == 0)
  557: 							options =
  558: 								saved_options;
  559: 					}
  560: 					continue;
  561: 				}
  562: 				tokenp->type = isc_tokentype_special;
  563: 				tokenp->value.as_char = c;
  564: 				done = ISC_TRUE;
  565: 			} else if (isdigit((unsigned char)c) &&
  566: 				   (options & ISC_LEXOPT_NUMBER) != 0) {
  567: 				lex->last_was_eol = ISC_FALSE;
  568: 				if ((options & ISC_LEXOPT_OCTAL) != 0 &&
  569: 				    (c == '8' || c == '9'))
  570: 					state = lexstate_string;
  571: 				else
  572: 					state = lexstate_number;
  573: 				goto no_read;
  574: 			} else {
  575: 				lex->last_was_eol = ISC_FALSE;
  576: 				state = lexstate_string;
  577: 				goto no_read;
  578: 			}
  579: 			break;
  580: 		case lexstate_crlf:
  581: 			if (c != '\n')
  582: 				pushback(source, c);
  583: 			tokenp->type = isc_tokentype_eol;
  584: 			done = ISC_TRUE;
  585: 			lex->last_was_eol = ISC_TRUE;
  586: 			break;
  587: 		case lexstate_number:
  588: 			if (c == EOF || !isdigit((unsigned char)c)) {
  589: 				if (c == ' ' || c == '\t' || c == '\r' ||
  590: 				    c == '\n' || c == EOF ||
  591: 				    lex->specials[c]) {
  592: 					int base;
  593: 					if ((options & ISC_LEXOPT_OCTAL) != 0)
  594: 						base = 8;
  595: 					else if ((options & ISC_LEXOPT_CNUMBER) != 0)
  596: 						base = 0;
  597: 					else
  598: 						base = 10;
  599: 					pushback(source, c);
  600: 
  601: 					result = isc_parse_uint32(&as_ulong,
  602: 								  lex->data,
  603: 								  base);
  604: 					if (result == ISC_R_SUCCESS) {
  605: 						tokenp->type =
  606: 							isc_tokentype_number;
  607: 						tokenp->value.as_ulong =
  608: 							as_ulong;
  609: 					} else if (result == ISC_R_BADNUMBER) {
  610: 						isc_tokenvalue_t *v;
  611: 
  612: 						tokenp->type =
  613: 							isc_tokentype_string;
  614: 						v = &(tokenp->value);
  615: 						v->as_textregion.base =
  616: 							lex->data;
  617: 						v->as_textregion.length =
  618: 							lex->max_token -
  619: 							remaining;
  620: 					} else
  621: 						goto done;
  622: 					done = ISC_TRUE;
  623: 					continue;
  624: 				} else if (!(options & ISC_LEXOPT_CNUMBER) ||
  625: 					   ((c != 'x' && c != 'X') ||
  626: 					   (curr != &lex->data[1]) ||
  627: 					   (lex->data[0] != '0'))) {
  628: 					/* Above test supports hex numbers */
  629: 					state = lexstate_string;
  630: 				}
  631: 			} else if ((options & ISC_LEXOPT_OCTAL) != 0 &&
  632: 				   (c == '8' || c == '9')) {
  633: 				state = lexstate_string;
  634: 			}
  635: 			if (remaining == 0U) {
  636: 				result = grow_data(lex, &remaining,
  637: 						   &curr, &prev);
  638: 				if (result != ISC_R_SUCCESS)
  639: 					goto done;
  640: 			}
  641: 			INSIST(remaining > 0U);
  642: 			*curr++ = c;
  643: 			*curr = '\0';
  644: 			remaining--;
  645: 			break;
  646: 		case lexstate_string:
  647: 			/*
  648: 			 * EOF needs to be checked before lex->specials[c]
  649: 			 * as lex->specials[EOF] is not a good idea.
  650: 			 */
  651: 			if (c == '\r' || c == '\n' || c == EOF ||
  652: 			    (!escaped &&
  653: 			     (c == ' ' || c == '\t' || lex->specials[c]))) {
  654: 				pushback(source, c);
  655: 				if (source->result != ISC_R_SUCCESS) {
  656: 					result = source->result;
  657: 					goto done;
  658: 				}
  659: 				tokenp->type = isc_tokentype_string;
  660: 				tokenp->value.as_textregion.base = lex->data;
  661: 				tokenp->value.as_textregion.length =
  662: 					lex->max_token - remaining;
  663: 				done = ISC_TRUE;
  664: 				continue;
  665: 			}
  666: 			if ((options & ISC_LEXOPT_ESCAPE) != 0)
  667: 				escaped = (!escaped && c == '\\') ?
  668: 						ISC_TRUE : ISC_FALSE;
  669: 			if (remaining == 0U) {
  670: 				result = grow_data(lex, &remaining,
  671: 						   &curr, &prev);
  672: 				if (result != ISC_R_SUCCESS)
  673: 					goto done;
  674: 			}
  675: 			INSIST(remaining > 0U);
  676: 			*curr++ = c;
  677: 			*curr = '\0';
  678: 			remaining--;
  679: 			break;
  680: 		case lexstate_maybecomment:
  681: 			if (c == '*' &&
  682: 			    (lex->comments & ISC_LEXCOMMENT_C) != 0) {
  683: 				state = lexstate_ccomment;
  684: 				continue;
  685: 			} else if (c == '/' &&
  686: 			    (lex->comments & ISC_LEXCOMMENT_CPLUSPLUS) != 0) {
  687: 				state = lexstate_eatline;
  688: 				continue;
  689: 			}
  690: 			pushback(source, c);
  691: 			c = '/';
  692: 			no_comments = ISC_FALSE;
  693: 			state = saved_state;
  694: 			goto no_read;
  695: 		case lexstate_ccomment:
  696: 			if (c == EOF) {
  697: 				result = ISC_R_UNEXPECTEDEND;
  698: 				goto done;
  699: 			}
  700: 			if (c == '*')
  701: 				state = lexstate_ccommentend;
  702: 			break;
  703: 		case lexstate_ccommentend:
  704: 			if (c == EOF) {
  705: 				result = ISC_R_UNEXPECTEDEND;
  706: 				goto done;
  707: 			}
  708: 			if (c == '/') {
  709: 				/*
  710: 				 * C-style comments become a single space.
  711: 				 * We do this to ensure that a comment will
  712: 				 * act as a delimiter for strings and
  713: 				 * numbers.
  714: 				 */
  715: 				c = ' ';
  716: 				no_comments = ISC_FALSE;
  717: 				state = saved_state;
  718: 				goto no_read;
  719: 			} else if (c != '*')
  720: 				state = lexstate_ccomment;
  721: 			break;
  722: 		case lexstate_eatline:
  723: 			if ((c == '\n') || (c == EOF)) {
  724: 				no_comments = ISC_FALSE;
  725: 				state = saved_state;
  726: 				goto no_read;
  727: 			}
  728: 			break;
  729: 		case lexstate_qstring:
  730: 			if (c == EOF) {
  731: 				result = ISC_R_UNEXPECTEDEND;
  732: 				goto done;
  733: 			}
  734: 			if (c == '"') {
  735: 				if (escaped) {
  736: 					escaped = ISC_FALSE;
  737: 					/*
  738: 					 * Overwrite the preceding backslash.
  739: 					 */
  740: 					INSIST(prev != NULL);
  741: 					*prev = '"';
  742: 				} else {
  743: 					tokenp->type = isc_tokentype_qstring;
  744: 					tokenp->value.as_textregion.base =
  745: 						lex->data;
  746: 					tokenp->value.as_textregion.length =
  747: 						lex->max_token - remaining;
  748: 					no_comments = ISC_FALSE;
  749: 					done = ISC_TRUE;
  750: 				}
  751: 			} else {
  752: 				if (c == '\n' && !escaped &&
  753: 			    (options & ISC_LEXOPT_QSTRINGMULTILINE) == 0) {
  754: 					pushback(source, c);
  755: 					result = ISC_R_UNBALANCEDQUOTES;
  756: 					goto done;
  757: 				}
  758: 				if (c == '\\' && !escaped)
  759: 					escaped = ISC_TRUE;
  760: 				else
  761: 					escaped = ISC_FALSE;
  762: 				if (remaining == 0U) {
  763: 					result = grow_data(lex, &remaining,
  764: 							   &curr, &prev);
  765: 					if (result != ISC_R_SUCCESS)
  766: 						goto done;
  767: 				}
  768: 				INSIST(remaining > 0U);
  769: 				prev = curr;
  770: 				*curr++ = c;
  771: 				*curr = '\0';
  772: 				remaining--;
  773: 			}
  774: 			break;
  775: 		default:
  776: 			FATAL_ERROR(__FILE__, __LINE__,
  777: 				    isc_msgcat_get(isc_msgcat, ISC_MSGSET_LEX,
  778: 						   ISC_MSG_UNEXPECTEDSTATE,
  779: 						   "Unexpected state %d"),
  780: 				    state);
  781: 			/* Does not return. */
  782: 		}
  783: 
  784: 	} while (!done);
  785: 
  786: 	result = ISC_R_SUCCESS;
  787:  done:
  788: #ifdef HAVE_FLOCKFILE
  789: 	if (source->is_file)
  790: 		funlockfile(source->input);
  791: #endif
  792: 	return (result);
  793: }
  794: 
  795: isc_result_t
  796: isc_lex_getmastertoken(isc_lex_t *lex, isc_token_t *token,
  797: 		       isc_tokentype_t expect, isc_boolean_t eol)
  798: {
  799: 	unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
  800: 			       ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE;
  801: 	isc_result_t result;
  802: 
  803: 	if (expect == isc_tokentype_qstring)
  804: 		options |= ISC_LEXOPT_QSTRING;
  805: 	else if (expect == isc_tokentype_number)
  806: 		options |= ISC_LEXOPT_NUMBER;
  807: 	result = isc_lex_gettoken(lex, options, token);
  808: 	if (result == ISC_R_RANGE)
  809: 		isc_lex_ungettoken(lex, token);
  810: 	if (result != ISC_R_SUCCESS)
  811: 		return (result);
  812: 
  813: 	if (eol && ((token->type == isc_tokentype_eol) ||
  814: 		    (token->type == isc_tokentype_eof)))
  815: 		return (ISC_R_SUCCESS);
  816: 	if (token->type == isc_tokentype_string &&
  817: 	    expect == isc_tokentype_qstring)
  818: 		return (ISC_R_SUCCESS);
  819: 	if (token->type != expect) {
  820: 		isc_lex_ungettoken(lex, token);
  821: 		if (token->type == isc_tokentype_eol ||
  822: 		    token->type == isc_tokentype_eof)
  823: 			return (ISC_R_UNEXPECTEDEND);
  824: 		if (expect == isc_tokentype_number)
  825: 			return (ISC_R_BADNUMBER);
  826: 		return (ISC_R_UNEXPECTEDTOKEN);
  827: 	}
  828: 	return (ISC_R_SUCCESS);
  829: }
  830: 
  831: isc_result_t
  832: isc_lex_getoctaltoken(isc_lex_t *lex, isc_token_t *token, isc_boolean_t eol)
  833: {
  834: 	unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
  835: 			       ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE|
  836: 			       ISC_LEXOPT_NUMBER | ISC_LEXOPT_OCTAL;
  837: 	isc_result_t result;
  838: 
  839: 	result = isc_lex_gettoken(lex, options, token);
  840: 	if (result == ISC_R_RANGE)
  841: 		isc_lex_ungettoken(lex, token);
  842: 	if (result != ISC_R_SUCCESS)
  843: 		return (result);
  844: 
  845: 	if (eol && ((token->type == isc_tokentype_eol) ||
  846: 		    (token->type == isc_tokentype_eof)))
  847: 		return (ISC_R_SUCCESS);
  848: 	if (token->type != isc_tokentype_number) {
  849: 		isc_lex_ungettoken(lex, token);
  850: 		if (token->type == isc_tokentype_eol ||
  851: 		    token->type == isc_tokentype_eof)
  852: 			return (ISC_R_UNEXPECTEDEND);
  853: 		return (ISC_R_BADNUMBER);
  854: 	}
  855: 	return (ISC_R_SUCCESS);
  856: }
  857: 
  858: void
  859: isc_lex_ungettoken(isc_lex_t *lex, isc_token_t *tokenp) {
  860: 	inputsource *source;
  861: 	/*
  862: 	 * Unget the current token.
  863: 	 */
  864: 
  865: 	REQUIRE(VALID_LEX(lex));
  866: 	source = HEAD(lex->sources);
  867: 	REQUIRE(source != NULL);
  868: 	REQUIRE(tokenp != NULL);
  869: 	REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 ||
  870: 		tokenp->type == isc_tokentype_eof);
  871: 
  872: 	UNUSED(tokenp);
  873: 
  874: 	isc_buffer_first(source->pushback);
  875: 	lex->paren_count = lex->saved_paren_count;
  876: 	source->line = source->saved_line;
  877: 	source->at_eof = ISC_FALSE;
  878: }
  879: 
  880: void
  881: isc_lex_getlasttokentext(isc_lex_t *lex, isc_token_t *tokenp, isc_region_t *r)
  882: {
  883: 	inputsource *source;
  884: 
  885: 	REQUIRE(VALID_LEX(lex));
  886: 	source = HEAD(lex->sources);
  887: 	REQUIRE(source != NULL);
  888: 	REQUIRE(tokenp != NULL);
  889: 	REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 ||
  890: 		tokenp->type == isc_tokentype_eof);
  891: 
  892: 	UNUSED(tokenp);
  893: 
  894: 	INSIST(source->ignored <= isc_buffer_consumedlength(source->pushback));
  895: 	r->base = (unsigned char *)isc_buffer_base(source->pushback) +
  896: 		  source->ignored;
  897: 	r->length = isc_buffer_consumedlength(source->pushback) -
  898: 		    source->ignored;
  899: }
  900: 
  901: 
  902: char *
  903: isc_lex_getsourcename(isc_lex_t *lex) {
  904: 	inputsource *source;
  905: 
  906: 	REQUIRE(VALID_LEX(lex));
  907: 	source = HEAD(lex->sources);
  908: 
  909: 	if (source == NULL)
  910: 		return (NULL);
  911: 
  912: 	return (source->name);
  913: }
  914: 
  915: unsigned long
  916: isc_lex_getsourceline(isc_lex_t *lex) {
  917: 	inputsource *source;
  918: 
  919: 	REQUIRE(VALID_LEX(lex));
  920: 	source = HEAD(lex->sources);
  921: 
  922: 	if (source == NULL)
  923: 		return (0);
  924: 
  925: 	return (source->line);
  926: }
  927: 
  928: 
  929: isc_result_t
  930: isc_lex_setsourcename(isc_lex_t *lex, const char *name) {
  931: 	inputsource *source;
  932: 	char *newname;
  933: 
  934: 	REQUIRE(VALID_LEX(lex));
  935: 	source = HEAD(lex->sources);
  936: 
  937: 	if (source == NULL)
  938: 		return(ISC_R_NOTFOUND);
  939: 	newname = isc_mem_strdup(lex->mctx, name);
  940: 	if (newname == NULL)
  941: 		return (ISC_R_NOMEMORY);
  942: 	isc_mem_free(lex->mctx, source->name);
  943: 	source->name = newname;
  944: 	return (ISC_R_SUCCESS);
  945: }
  946: 
  947: isc_boolean_t
  948: isc_lex_isfile(isc_lex_t *lex) {
  949: 	inputsource *source;
  950: 
  951: 	REQUIRE(VALID_LEX(lex));
  952: 
  953: 	source = HEAD(lex->sources);
  954: 
  955: 	if (source == NULL)
  956: 		return (ISC_FALSE);
  957: 
  958: 	return (source->is_file);
  959: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>