xref: /openbsd-src/usr.bin/dig/lib/isc/lex.c (revision ac19a2a78de14b2db59150dc99fcc2bd5c328bb7)
15185a700Sflorian /*
25185a700Sflorian  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
35185a700Sflorian  *
45185a700Sflorian  * Permission to use, copy, modify, and/or distribute this software for any
55185a700Sflorian  * purpose with or without fee is hereby granted, provided that the above
65185a700Sflorian  * copyright notice and this permission notice appear in all copies.
75185a700Sflorian  *
85185a700Sflorian  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
95185a700Sflorian  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
105185a700Sflorian  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
115185a700Sflorian  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
125185a700Sflorian  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
135185a700Sflorian  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
145185a700Sflorian  * PERFORMANCE OF THIS SOFTWARE.
155185a700Sflorian  */
165185a700Sflorian 
17*ac19a2a7Sjsg /* $Id: lex.c,v 1.15 2022/06/25 12:14:18 jsg Exp $ */
185185a700Sflorian 
195185a700Sflorian /*! \file */
205185a700Sflorian 
215185a700Sflorian #include <stdlib.h>
225185a700Sflorian 
235185a700Sflorian #include <isc/buffer.h>
245185a700Sflorian 
255185a700Sflorian #include <isc/lex.h>
265185a700Sflorian 
271cf3f1c7Sjung #include <errno.h>
285185a700Sflorian #include <string.h>
295185a700Sflorian #include <isc/util.h>
305185a700Sflorian 
311cf3f1c7Sjung #include "unix/errno2result.h"
321cf3f1c7Sjung 
335185a700Sflorian typedef struct inputsource {
345185a700Sflorian 	isc_result_t			result;
351fb015a8Sflorian 	int			is_file;
361fb015a8Sflorian 	int			need_close;
371fb015a8Sflorian 	int			at_eof;
381fb015a8Sflorian 	int			last_was_eol;
395185a700Sflorian 	isc_buffer_t *			pushback;
405185a700Sflorian 	unsigned int			ignored;
415185a700Sflorian 	void *				input;
425185a700Sflorian 	char *				name;
435185a700Sflorian 	unsigned long			line;
445185a700Sflorian 	unsigned long			saved_line;
455185a700Sflorian 	ISC_LINK(struct inputsource)	link;
465185a700Sflorian } inputsource;
475185a700Sflorian 
485185a700Sflorian struct isc_lex {
495185a700Sflorian 	/* Unlocked. */
505185a700Sflorian 	size_t				max_token;
515185a700Sflorian 	char *				data;
525185a700Sflorian 	unsigned int			comments;
531fb015a8Sflorian 	int			comment_ok;
541fb015a8Sflorian 	int			last_was_eol;
555185a700Sflorian 	unsigned int			paren_count;
565185a700Sflorian 	unsigned int			saved_paren_count;
575185a700Sflorian 	isc_lexspecials_t		specials;
585185a700Sflorian 	LIST(struct inputsource)	sources;
595185a700Sflorian };
605185a700Sflorian 
615185a700Sflorian static inline isc_result_t
grow_data(isc_lex_t * lex,size_t * remainingp,char ** currp,char ** prevp)625185a700Sflorian grow_data(isc_lex_t *lex, size_t *remainingp, char **currp, char **prevp) {
635185a700Sflorian 	char *tmp;
645185a700Sflorian 
655185a700Sflorian 	tmp = malloc(lex->max_token * 2 + 1);
665185a700Sflorian 	if (tmp == NULL)
675185a700Sflorian 		return (ISC_R_NOMEMORY);
685185a700Sflorian 	memmove(tmp, lex->data, lex->max_token + 1);
695185a700Sflorian 	*currp = tmp + (*currp - lex->data);
705185a700Sflorian 	if (*prevp != NULL)
715185a700Sflorian 		*prevp = tmp + (*prevp - lex->data);
725185a700Sflorian 	free(lex->data);
735185a700Sflorian 	lex->data = tmp;
745185a700Sflorian 	*remainingp += lex->max_token;
755185a700Sflorian 	lex->max_token *= 2;
765185a700Sflorian 	return (ISC_R_SUCCESS);
775185a700Sflorian }
785185a700Sflorian 
795185a700Sflorian isc_result_t
isc_lex_create(size_t max_token,isc_lex_t ** lexp)805185a700Sflorian isc_lex_create(size_t max_token, isc_lex_t **lexp) {
815185a700Sflorian 	isc_lex_t *lex;
825185a700Sflorian 
835185a700Sflorian 	/*
845185a700Sflorian 	 * Create a lexer.
855185a700Sflorian 	 */
865185a700Sflorian 	REQUIRE(lexp != NULL && *lexp == NULL);
875185a700Sflorian 
885185a700Sflorian 	if (max_token == 0U)
895185a700Sflorian 		max_token = 1;
905185a700Sflorian 
915185a700Sflorian 	lex = malloc(sizeof(*lex));
925185a700Sflorian 	if (lex == NULL)
935185a700Sflorian 		return (ISC_R_NOMEMORY);
945185a700Sflorian 	lex->data = malloc(max_token + 1);
955185a700Sflorian 	if (lex->data == NULL) {
965185a700Sflorian 		free(lex);
975185a700Sflorian 		return (ISC_R_NOMEMORY);
985185a700Sflorian 	}
995185a700Sflorian 	lex->max_token = max_token;
1005185a700Sflorian 	lex->comments = 0;
1011fb015a8Sflorian 	lex->comment_ok = 1;
1021fb015a8Sflorian 	lex->last_was_eol = 1;
1035185a700Sflorian 	lex->paren_count = 0;
1045185a700Sflorian 	lex->saved_paren_count = 0;
1055185a700Sflorian 	memset(lex->specials, 0, 256);
1065185a700Sflorian 	INIT_LIST(lex->sources);
1075185a700Sflorian 
1085185a700Sflorian 	*lexp = lex;
1095185a700Sflorian 
1105185a700Sflorian 	return (ISC_R_SUCCESS);
1115185a700Sflorian }
1125185a700Sflorian 
1135185a700Sflorian void
isc_lex_destroy(isc_lex_t ** lexp)1145185a700Sflorian isc_lex_destroy(isc_lex_t **lexp) {
1155185a700Sflorian 	isc_lex_t *lex;
1165185a700Sflorian 
1175185a700Sflorian 	/*
1185185a700Sflorian 	 * Destroy the lexer.
1195185a700Sflorian 	 */
1205185a700Sflorian 
1215185a700Sflorian 	REQUIRE(lexp != NULL);
1225185a700Sflorian 	lex = *lexp;
1235185a700Sflorian 
1245185a700Sflorian 	while (!EMPTY(lex->sources))
1255185a700Sflorian 		RUNTIME_CHECK(isc_lex_close(lex) == ISC_R_SUCCESS);
1265185a700Sflorian 	if (lex->data != NULL)
1275185a700Sflorian 		free(lex->data);
1285185a700Sflorian 	free(lex);
1295185a700Sflorian 
1305185a700Sflorian 	*lexp = NULL;
1315185a700Sflorian }
1325185a700Sflorian 
1335185a700Sflorian void
isc_lex_setcomments(isc_lex_t * lex,unsigned int comments)1345185a700Sflorian isc_lex_setcomments(isc_lex_t *lex, unsigned int comments) {
1355185a700Sflorian 	/*
1365185a700Sflorian 	 * Set allowed lexer commenting styles.
1375185a700Sflorian 	 */
1385185a700Sflorian 
1395185a700Sflorian 	lex->comments = comments;
1405185a700Sflorian }
1415185a700Sflorian 
1425185a700Sflorian void
isc_lex_setspecials(isc_lex_t * lex,isc_lexspecials_t specials)1435185a700Sflorian isc_lex_setspecials(isc_lex_t *lex, isc_lexspecials_t specials) {
1445185a700Sflorian 	/*
1455185a700Sflorian 	 * The characters in 'specials' are returned as tokens.  Along with
1465185a700Sflorian 	 * whitespace, they delimit strings and numbers.
1475185a700Sflorian 	 */
1485185a700Sflorian 
1495185a700Sflorian 	memmove(lex->specials, specials, 256);
1505185a700Sflorian }
1515185a700Sflorian 
1525185a700Sflorian static inline isc_result_t
new_source(isc_lex_t * lex,int is_file,int need_close,void * input,const char * name)1531fb015a8Sflorian new_source(isc_lex_t *lex, int is_file, int need_close,
1545185a700Sflorian 	   void *input, const char *name)
1555185a700Sflorian {
1565185a700Sflorian 	inputsource *source;
1575185a700Sflorian 	isc_result_t result;
1585185a700Sflorian 
1595185a700Sflorian 	source = malloc(sizeof(*source));
1605185a700Sflorian 	if (source == NULL)
1615185a700Sflorian 		return (ISC_R_NOMEMORY);
1625185a700Sflorian 	source->result = ISC_R_SUCCESS;
1635185a700Sflorian 	source->is_file = is_file;
1645185a700Sflorian 	source->need_close = need_close;
1651fb015a8Sflorian 	source->at_eof = 0;
1665185a700Sflorian 	source->last_was_eol = lex->last_was_eol;
1675185a700Sflorian 	source->input = input;
1685185a700Sflorian 	source->name = strdup(name);
1695185a700Sflorian 	if (source->name == NULL) {
1705185a700Sflorian 		free(source);
1715185a700Sflorian 		return (ISC_R_NOMEMORY);
1725185a700Sflorian 	}
1735185a700Sflorian 	source->pushback = NULL;
1745185a700Sflorian 	result = isc_buffer_allocate(&source->pushback,
1755185a700Sflorian 				     (unsigned int)lex->max_token);
1765185a700Sflorian 	if (result != ISC_R_SUCCESS) {
1775185a700Sflorian 		free(source->name);
1785185a700Sflorian 		free(source);
1795185a700Sflorian 		return (result);
1805185a700Sflorian 	}
1815185a700Sflorian 	source->ignored = 0;
1825185a700Sflorian 	source->line = 1;
1835185a700Sflorian 	ISC_LIST_INITANDPREPEND(lex->sources, source, link);
1845185a700Sflorian 
1855185a700Sflorian 	return (ISC_R_SUCCESS);
1865185a700Sflorian }
1875185a700Sflorian 
1885185a700Sflorian isc_result_t
isc_lex_openfile(isc_lex_t * lex,const char * filename)1895185a700Sflorian isc_lex_openfile(isc_lex_t *lex, const char *filename) {
1901cf3f1c7Sjung 	isc_result_t result = ISC_R_SUCCESS;
1915185a700Sflorian 	FILE *stream = NULL;
1925185a700Sflorian 
1935185a700Sflorian 	/*
1945185a700Sflorian 	 * Open 'filename' and make it the current input source for 'lex'.
1955185a700Sflorian 	 */
1965185a700Sflorian 
1971cf3f1c7Sjung 	if ((stream = fopen(filename, "r")) == NULL)
1981cf3f1c7Sjung 		return (isc__errno2result(errno));
1995185a700Sflorian 
2001fb015a8Sflorian 	result = new_source(lex, 1, 1, stream, filename);
2015185a700Sflorian 	if (result != ISC_R_SUCCESS)
2025185a700Sflorian 		(void)fclose(stream);
2035185a700Sflorian 	return (result);
2045185a700Sflorian }
2055185a700Sflorian 
2065185a700Sflorian isc_result_t
isc_lex_close(isc_lex_t * lex)2075185a700Sflorian isc_lex_close(isc_lex_t *lex) {
2085185a700Sflorian 	inputsource *source;
2095185a700Sflorian 
2105185a700Sflorian 	/*
2115185a700Sflorian 	 * Close the most recently opened object (i.e. file or buffer).
2125185a700Sflorian 	 */
2135185a700Sflorian 
2145185a700Sflorian 	source = HEAD(lex->sources);
2155185a700Sflorian 	if (source == NULL)
2165185a700Sflorian 		return (ISC_R_NOMORE);
2175185a700Sflorian 
2185185a700Sflorian 	ISC_LIST_UNLINK(lex->sources, source, link);
2195185a700Sflorian 	lex->last_was_eol = source->last_was_eol;
2205185a700Sflorian 	if (source->is_file) {
2215185a700Sflorian 		if (source->need_close)
2225185a700Sflorian 			(void)fclose((FILE *)(source->input));
2235185a700Sflorian 	}
2245185a700Sflorian 	free(source->name);
2255185a700Sflorian 	isc_buffer_free(&source->pushback);
2265185a700Sflorian 	free(source);
2275185a700Sflorian 
2285185a700Sflorian 	return (ISC_R_SUCCESS);
2295185a700Sflorian }
2305185a700Sflorian 
2315185a700Sflorian typedef enum {
2325185a700Sflorian 	lexstate_start,
2335185a700Sflorian 	lexstate_string,
2345185a700Sflorian 	lexstate_maybecomment,
2355185a700Sflorian 	lexstate_ccomment,
2365185a700Sflorian 	lexstate_ccommentend,
2375185a700Sflorian 	lexstate_eatline,
2385185a700Sflorian 	lexstate_qstring
2395185a700Sflorian } lexstate;
2405185a700Sflorian 
2415185a700Sflorian static void
pushback(inputsource * source,int c)2425185a700Sflorian pushback(inputsource *source, int c) {
2435185a700Sflorian 	REQUIRE(source->pushback->current > 0);
2445185a700Sflorian 	if (c == EOF) {
2451fb015a8Sflorian 		source->at_eof = 0;
2465185a700Sflorian 		return;
2475185a700Sflorian 	}
2485185a700Sflorian 	source->pushback->current--;
2495185a700Sflorian 	if (c == '\n')
2505185a700Sflorian 		source->line--;
2515185a700Sflorian }
2525185a700Sflorian 
2535185a700Sflorian static isc_result_t
pushandgrow(inputsource * source,int c)2545185a700Sflorian pushandgrow(inputsource *source, int c) {
2555185a700Sflorian 	if (isc_buffer_availablelength(source->pushback) == 0) {
2565185a700Sflorian 		isc_buffer_t *tbuf = NULL;
2575185a700Sflorian 		unsigned int oldlen;
2585185a700Sflorian 		isc_region_t used;
2595185a700Sflorian 		isc_result_t result;
2605185a700Sflorian 
2615185a700Sflorian 		oldlen = isc_buffer_length(source->pushback);
2625185a700Sflorian 		result = isc_buffer_allocate(&tbuf, oldlen * 2);
2635185a700Sflorian 		if (result != ISC_R_SUCCESS)
2645185a700Sflorian 			return (result);
2655185a700Sflorian 		isc_buffer_usedregion(source->pushback, &used);
2665185a700Sflorian 		result = isc_buffer_copyregion(tbuf, &used);
2675185a700Sflorian 		INSIST(result == ISC_R_SUCCESS);
2685185a700Sflorian 		tbuf->current = source->pushback->current;
2695185a700Sflorian 		isc_buffer_free(&source->pushback);
2705185a700Sflorian 		source->pushback = tbuf;
2715185a700Sflorian 	}
2725185a700Sflorian 	isc_buffer_putuint8(source->pushback, (uint8_t)c);
2735185a700Sflorian 	return (ISC_R_SUCCESS);
2745185a700Sflorian }
2755185a700Sflorian 
2765185a700Sflorian isc_result_t
isc_lex_gettoken(isc_lex_t * lex,unsigned int options,isc_token_t * tokenp)2775185a700Sflorian isc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp) {
2785185a700Sflorian 	inputsource *source;
2795185a700Sflorian 	int c;
2801fb015a8Sflorian 	int done = 0;
2811fb015a8Sflorian 	int no_comments = 0;
2821fb015a8Sflorian 	int escaped = 0;
2835185a700Sflorian 	lexstate state = lexstate_start;
2845185a700Sflorian 	lexstate saved_state = lexstate_start;
2855185a700Sflorian 	isc_buffer_t *buffer;
2865185a700Sflorian 	FILE *stream;
2875185a700Sflorian 	char *curr, *prev;
2885185a700Sflorian 	size_t remaining;
2895185a700Sflorian 	isc_result_t result;
2905185a700Sflorian 
2915185a700Sflorian 	/*
2925185a700Sflorian 	 * Get the next token.
2935185a700Sflorian 	 */
2945185a700Sflorian 
2955185a700Sflorian 	source = HEAD(lex->sources);
2965185a700Sflorian 	REQUIRE(tokenp != NULL);
2975185a700Sflorian 
2985185a700Sflorian 	if (source == NULL) {
2995185a700Sflorian 		if ((options & ISC_LEXOPT_NOMORE) != 0) {
3005185a700Sflorian 			tokenp->type = isc_tokentype_nomore;
3015185a700Sflorian 			return (ISC_R_SUCCESS);
3025185a700Sflorian 		}
3035185a700Sflorian 		return (ISC_R_NOMORE);
3045185a700Sflorian 	}
3055185a700Sflorian 
3065185a700Sflorian 	if (source->result != ISC_R_SUCCESS)
3075185a700Sflorian 		return (source->result);
3085185a700Sflorian 
3095185a700Sflorian 	lex->saved_paren_count = lex->paren_count;
3105185a700Sflorian 	source->saved_line = source->line;
3115185a700Sflorian 
3125185a700Sflorian 	if (isc_buffer_remaininglength(source->pushback) == 0 &&
3135185a700Sflorian 	    source->at_eof)
3145185a700Sflorian 	{
3155185a700Sflorian 		if ((options & ISC_LEXOPT_EOF) != 0) {
3165185a700Sflorian 			tokenp->type = isc_tokentype_eof;
3175185a700Sflorian 			return (ISC_R_SUCCESS);
3185185a700Sflorian 		}
3195185a700Sflorian 		return (ISC_R_EOF);
3205185a700Sflorian 	}
3215185a700Sflorian 
3225185a700Sflorian 	isc_buffer_compact(source->pushback);
3235185a700Sflorian 
3245185a700Sflorian 	curr = lex->data;
3255185a700Sflorian 	*curr = '\0';
3265185a700Sflorian 
3275185a700Sflorian 	prev = NULL;
3285185a700Sflorian 	remaining = lex->max_token;
3295185a700Sflorian 
3305185a700Sflorian 	if (source->is_file)
3315185a700Sflorian 		flockfile(source->input);
3325185a700Sflorian 
3335185a700Sflorian 	do {
3345185a700Sflorian 		if (isc_buffer_remaininglength(source->pushback) == 0) {
3355185a700Sflorian 			if (source->is_file) {
3365185a700Sflorian 				stream = source->input;
3375185a700Sflorian 
3385185a700Sflorian 				c = getc_unlocked(stream);
3395185a700Sflorian 				if (c == EOF) {
3405185a700Sflorian 					if (ferror(stream)) {
3415185a700Sflorian 						source->result = ISC_R_IOERROR;
3425185a700Sflorian 						result = source->result;
3435185a700Sflorian 						goto done;
3445185a700Sflorian 					}
3451fb015a8Sflorian 					source->at_eof = 1;
3465185a700Sflorian 				}
3475185a700Sflorian 			} else {
3485185a700Sflorian 				buffer = source->input;
3495185a700Sflorian 
3505185a700Sflorian 				if (buffer->current == buffer->used) {
3515185a700Sflorian 					c = EOF;
3521fb015a8Sflorian 					source->at_eof = 1;
3535185a700Sflorian 				} else {
3545185a700Sflorian 					c = *((unsigned char *)buffer->base +
3555185a700Sflorian 					      buffer->current);
3565185a700Sflorian 					buffer->current++;
3575185a700Sflorian 				}
3585185a700Sflorian 			}
3595185a700Sflorian 			if (c != EOF) {
3605185a700Sflorian 				source->result = pushandgrow(source, c);
3615185a700Sflorian 				if (source->result != ISC_R_SUCCESS) {
3625185a700Sflorian 					result = source->result;
3635185a700Sflorian 					goto done;
3645185a700Sflorian 				}
3655185a700Sflorian 			}
3665185a700Sflorian 		}
3675185a700Sflorian 
3685185a700Sflorian 		if (!source->at_eof) {
3695185a700Sflorian 			if (state == lexstate_start)
3705185a700Sflorian 				/* Token has not started yet. */
3715185a700Sflorian 				source->ignored =
3725185a700Sflorian 				   isc_buffer_consumedlength(source->pushback);
3735185a700Sflorian 			c = isc_buffer_getuint8(source->pushback);
3745185a700Sflorian 		} else {
3755185a700Sflorian 			c = EOF;
3765185a700Sflorian 		}
3775185a700Sflorian 
3785185a700Sflorian 		if (c == '\n')
3795185a700Sflorian 			source->line++;
3805185a700Sflorian 
3815185a700Sflorian 		if (lex->comment_ok && !no_comments) {
382e6d3fd4aSflorian 			if (c == '/' &&
3835185a700Sflorian 				   (lex->comments &
3845185a700Sflorian 				    (ISC_LEXCOMMENT_C|
3855185a700Sflorian 				     ISC_LEXCOMMENT_CPLUSPLUS)) != 0) {
3865185a700Sflorian 				saved_state = state;
3875185a700Sflorian 				state = lexstate_maybecomment;
3881fb015a8Sflorian 				no_comments = 1;
3895185a700Sflorian 				continue;
3905185a700Sflorian 			} else if (c == '#' &&
3915185a700Sflorian 				   ((lex->comments & ISC_LEXCOMMENT_SHELL)
3925185a700Sflorian 				    != 0)) {
3935185a700Sflorian 				saved_state = state;
3945185a700Sflorian 				state = lexstate_eatline;
3951fb015a8Sflorian 				no_comments = 1;
3965185a700Sflorian 				continue;
3975185a700Sflorian 			}
3985185a700Sflorian 		}
3995185a700Sflorian 
4005185a700Sflorian 	no_read:
4015185a700Sflorian 		/* INSIST(c == EOF || (c >= 0 && c <= 255)); */
4025185a700Sflorian 		switch (state) {
4035185a700Sflorian 		case lexstate_start:
4045185a700Sflorian 			if (c == EOF) {
4051fb015a8Sflorian 				lex->last_was_eol = 0;
4065185a700Sflorian 				if ((options & ISC_LEXOPT_EOF) == 0) {
4075185a700Sflorian 					result = ISC_R_EOF;
4085185a700Sflorian 					goto done;
4095185a700Sflorian 				}
4105185a700Sflorian 				tokenp->type = isc_tokentype_eof;
4111fb015a8Sflorian 				done = 1;
412cf681e04Sflorian 			} else if (c == ' ' || c == '\t') {
413cf681e04Sflorian 				lex->last_was_eol = 0;
4145185a700Sflorian 			} else if (c == '\n') {
4151fb015a8Sflorian 				lex->last_was_eol = 1;
416cf681e04Sflorian 			} else if (c == '\r') {
417cf681e04Sflorian 				lex->last_was_eol = 0;
4185185a700Sflorian 			} else if (c == '"' &&
4195185a700Sflorian 				   (options & ISC_LEXOPT_QSTRING) != 0) {
4201fb015a8Sflorian 				lex->last_was_eol = 0;
4211fb015a8Sflorian 				no_comments = 1;
4225185a700Sflorian 				state = lexstate_qstring;
4235185a700Sflorian 			} else if (lex->specials[c]) {
4241fb015a8Sflorian 				lex->last_was_eol = 0;
4255185a700Sflorian 				tokenp->type = isc_tokentype_special;
4265185a700Sflorian 				tokenp->value.as_char = c;
4271fb015a8Sflorian 				done = 1;
4285185a700Sflorian 			} else {
4291fb015a8Sflorian 				lex->last_was_eol = 0;
4305185a700Sflorian 				state = lexstate_string;
4315185a700Sflorian 				goto no_read;
4325185a700Sflorian 			}
4335185a700Sflorian 			break;
4345185a700Sflorian 		case lexstate_string:
4355185a700Sflorian 			/*
4365185a700Sflorian 			 * EOF needs to be checked before lex->specials[c]
4375185a700Sflorian 			 * as lex->specials[EOF] is not a good idea.
4385185a700Sflorian 			 */
4395185a700Sflorian 			if (c == '\r' || c == '\n' || c == EOF ||
4405185a700Sflorian 			    (!escaped &&
4415185a700Sflorian 			     (c == ' ' || c == '\t' || lex->specials[c]))) {
4425185a700Sflorian 				pushback(source, c);
4435185a700Sflorian 				if (source->result != ISC_R_SUCCESS) {
4445185a700Sflorian 					result = source->result;
4455185a700Sflorian 					goto done;
4465185a700Sflorian 				}
4475185a700Sflorian 				tokenp->type = isc_tokentype_string;
4485185a700Sflorian 				tokenp->value.as_textregion.base = lex->data;
4495185a700Sflorian 				tokenp->value.as_textregion.length =
4505185a700Sflorian 					(unsigned int)
4515185a700Sflorian 					(lex->max_token - remaining);
4521fb015a8Sflorian 				done = 1;
4535185a700Sflorian 				continue;
4545185a700Sflorian 			}
4555185a700Sflorian 			if (remaining == 0U) {
4565185a700Sflorian 				result = grow_data(lex, &remaining,
4575185a700Sflorian 						   &curr, &prev);
4585185a700Sflorian 				if (result != ISC_R_SUCCESS)
4595185a700Sflorian 					goto done;
4605185a700Sflorian 			}
4615185a700Sflorian 			INSIST(remaining > 0U);
4625185a700Sflorian 			*curr++ = c;
4635185a700Sflorian 			*curr = '\0';
4645185a700Sflorian 			remaining--;
4655185a700Sflorian 			break;
4665185a700Sflorian 		case lexstate_maybecomment:
4675185a700Sflorian 			if (c == '*' &&
4685185a700Sflorian 			    (lex->comments & ISC_LEXCOMMENT_C) != 0) {
4695185a700Sflorian 				state = lexstate_ccomment;
4705185a700Sflorian 				continue;
4715185a700Sflorian 			} else if (c == '/' &&
4725185a700Sflorian 			    (lex->comments & ISC_LEXCOMMENT_CPLUSPLUS) != 0) {
4735185a700Sflorian 				state = lexstate_eatline;
4745185a700Sflorian 				continue;
4755185a700Sflorian 			}
4765185a700Sflorian 			pushback(source, c);
4775185a700Sflorian 			c = '/';
4781fb015a8Sflorian 			no_comments = 0;
4795185a700Sflorian 			state = saved_state;
4805185a700Sflorian 			goto no_read;
4815185a700Sflorian 		case lexstate_ccomment:
4825185a700Sflorian 			if (c == EOF) {
4835185a700Sflorian 				result = ISC_R_UNEXPECTEDEND;
4845185a700Sflorian 				goto done;
4855185a700Sflorian 			}
4865185a700Sflorian 			if (c == '*')
4875185a700Sflorian 				state = lexstate_ccommentend;
4885185a700Sflorian 			break;
4895185a700Sflorian 		case lexstate_ccommentend:
4905185a700Sflorian 			if (c == EOF) {
4915185a700Sflorian 				result = ISC_R_UNEXPECTEDEND;
4925185a700Sflorian 				goto done;
4935185a700Sflorian 			}
4945185a700Sflorian 			if (c == '/') {
4955185a700Sflorian 				/*
4965185a700Sflorian 				 * C-style comments become a single space.
4975185a700Sflorian 				 * We do this to ensure that a comment will
4985185a700Sflorian 				 * act as a delimiter for strings and
4995185a700Sflorian 				 * numbers.
5005185a700Sflorian 				 */
5015185a700Sflorian 				c = ' ';
5021fb015a8Sflorian 				no_comments = 0;
5035185a700Sflorian 				state = saved_state;
5045185a700Sflorian 				goto no_read;
5055185a700Sflorian 			} else if (c != '*')
5065185a700Sflorian 				state = lexstate_ccomment;
5075185a700Sflorian 			break;
5085185a700Sflorian 		case lexstate_eatline:
5095185a700Sflorian 			if ((c == '\n') || (c == EOF)) {
5101fb015a8Sflorian 				no_comments = 0;
5115185a700Sflorian 				state = saved_state;
5125185a700Sflorian 				goto no_read;
5135185a700Sflorian 			}
5145185a700Sflorian 			break;
5155185a700Sflorian 		case lexstate_qstring:
5165185a700Sflorian 			if (c == EOF) {
5175185a700Sflorian 				result = ISC_R_UNEXPECTEDEND;
5185185a700Sflorian 				goto done;
5195185a700Sflorian 			}
5205185a700Sflorian 			if (c == '"') {
5215185a700Sflorian 				if (escaped) {
5221fb015a8Sflorian 					escaped = 0;
5235185a700Sflorian 					/*
5245185a700Sflorian 					 * Overwrite the preceding backslash.
5255185a700Sflorian 					 */
5265185a700Sflorian 					INSIST(prev != NULL);
5275185a700Sflorian 					*prev = '"';
5285185a700Sflorian 				} else {
5295185a700Sflorian 					tokenp->type = isc_tokentype_qstring;
5305185a700Sflorian 					tokenp->value.as_textregion.base =
5315185a700Sflorian 						lex->data;
5325185a700Sflorian 					tokenp->value.as_textregion.length =
5335185a700Sflorian 						(unsigned int)
5345185a700Sflorian 						(lex->max_token - remaining);
5351fb015a8Sflorian 					no_comments = 0;
5361fb015a8Sflorian 					done = 1;
5375185a700Sflorian 				}
5385185a700Sflorian 			} else {
5395185a700Sflorian 				if (c == '\n' && !escaped &&
5405185a700Sflorian 			    (options & ISC_LEXOPT_QSTRINGMULTILINE) == 0) {
5415185a700Sflorian 					pushback(source, c);
5425185a700Sflorian 					result = ISC_R_UNBALANCEDQUOTES;
5435185a700Sflorian 					goto done;
5445185a700Sflorian 				}
5455185a700Sflorian 				if (c == '\\' && !escaped)
5461fb015a8Sflorian 					escaped = 1;
5475185a700Sflorian 				else
5481fb015a8Sflorian 					escaped = 0;
5495185a700Sflorian 				if (remaining == 0U) {
5505185a700Sflorian 					result = grow_data(lex, &remaining,
5515185a700Sflorian 							   &curr, &prev);
5525185a700Sflorian 					if (result != ISC_R_SUCCESS)
5535185a700Sflorian 						goto done;
5545185a700Sflorian 				}
5555185a700Sflorian 				INSIST(remaining > 0U);
5565185a700Sflorian 				prev = curr;
5575185a700Sflorian 				*curr++ = c;
5585185a700Sflorian 				*curr = '\0';
5595185a700Sflorian 				remaining--;
5605185a700Sflorian 			}
5615185a700Sflorian 			break;
5625185a700Sflorian 		default:
5635185a700Sflorian 			FATAL_ERROR(__FILE__, __LINE__, "Unexpected state %d",
5645185a700Sflorian 				    state);
5655185a700Sflorian 			/* Does not return. */
5665185a700Sflorian 		}
5675185a700Sflorian 
5685185a700Sflorian 	} while (!done);
5695185a700Sflorian 
5705185a700Sflorian 	result = ISC_R_SUCCESS;
5715185a700Sflorian  done:
5725185a700Sflorian 	if (source->is_file)
5735185a700Sflorian 		funlockfile(source->input);
5745185a700Sflorian 	return (result);
5755185a700Sflorian }
5765185a700Sflorian 
5775185a700Sflorian void
isc_lex_ungettoken(isc_lex_t * lex,isc_token_t * tokenp)5785185a700Sflorian isc_lex_ungettoken(isc_lex_t *lex, isc_token_t *tokenp) {
5795185a700Sflorian 	inputsource *source;
5805185a700Sflorian 	/*
5815185a700Sflorian 	 * Unget the current token.
5825185a700Sflorian 	 */
5835185a700Sflorian 
5845185a700Sflorian 	source = HEAD(lex->sources);
5855185a700Sflorian 	REQUIRE(source != NULL);
5865185a700Sflorian 	REQUIRE(tokenp != NULL);
5875185a700Sflorian 	REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 ||
5885185a700Sflorian 		tokenp->type == isc_tokentype_eof);
5895185a700Sflorian 
5905185a700Sflorian 	UNUSED(tokenp);
5915185a700Sflorian 
5925185a700Sflorian 	isc_buffer_first(source->pushback);
5935185a700Sflorian 	lex->paren_count = lex->saved_paren_count;
5945185a700Sflorian 	source->line = source->saved_line;
5951fb015a8Sflorian 	source->at_eof = 0;
5965185a700Sflorian }
5975185a700Sflorian 
5985185a700Sflorian void
isc_lex_getlasttokentext(isc_lex_t * lex,isc_token_t * tokenp,isc_region_t * r)5995185a700Sflorian isc_lex_getlasttokentext(isc_lex_t *lex, isc_token_t *tokenp, isc_region_t *r)
6005185a700Sflorian {
6015185a700Sflorian 	inputsource *source;
6025185a700Sflorian 
6035185a700Sflorian 	source = HEAD(lex->sources);
6045185a700Sflorian 	REQUIRE(source != NULL);
6055185a700Sflorian 	REQUIRE(tokenp != NULL);
6065185a700Sflorian 	REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 ||
6075185a700Sflorian 		tokenp->type == isc_tokentype_eof);
6085185a700Sflorian 
6095185a700Sflorian 	UNUSED(tokenp);
6105185a700Sflorian 
6115185a700Sflorian 	INSIST(source->ignored <= isc_buffer_consumedlength(source->pushback));
6125185a700Sflorian 	r->base = (unsigned char *)isc_buffer_base(source->pushback) +
6135185a700Sflorian 		  source->ignored;
6145185a700Sflorian 	r->length = isc_buffer_consumedlength(source->pushback) -
6155185a700Sflorian 		    source->ignored;
6165185a700Sflorian }
6175185a700Sflorian 
6185185a700Sflorian char *
isc_lex_getsourcename(isc_lex_t * lex)6195185a700Sflorian isc_lex_getsourcename(isc_lex_t *lex) {
6205185a700Sflorian 	inputsource *source;
6215185a700Sflorian 
6225185a700Sflorian 	source = HEAD(lex->sources);
6235185a700Sflorian 
6245185a700Sflorian 	if (source == NULL)
6255185a700Sflorian 		return (NULL);
6265185a700Sflorian 
6275185a700Sflorian 	return (source->name);
6285185a700Sflorian }
6295185a700Sflorian 
6305185a700Sflorian unsigned long
isc_lex_getsourceline(isc_lex_t * lex)6315185a700Sflorian isc_lex_getsourceline(isc_lex_t *lex) {
6325185a700Sflorian 	inputsource *source;
6335185a700Sflorian 
6345185a700Sflorian 	source = HEAD(lex->sources);
6355185a700Sflorian 
6365185a700Sflorian 	if (source == NULL)
6375185a700Sflorian 		return (0);
6385185a700Sflorian 
6395185a700Sflorian 	return (source->line);
6405185a700Sflorian }
641