1258945Sroberto/*
2258945Sroberto * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
3258945Sroberto * Copyright (C) 1998-2003  Internet Software Consortium.
4258945Sroberto *
5258945Sroberto * Permission to use, copy, modify, and/or distribute this software for any
6258945Sroberto * purpose with or without fee is hereby granted, provided that the above
7258945Sroberto * copyright notice and this permission notice appear in all copies.
8258945Sroberto *
9258945Sroberto * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10258945Sroberto * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11258945Sroberto * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12258945Sroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13258945Sroberto * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14258945Sroberto * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15258945Sroberto * PERFORMANCE OF THIS SOFTWARE.
16258945Sroberto */
17258945Sroberto
18258945Sroberto/* $Id: lex.c,v 1.86 2007/09/17 09:56:29 shane Exp $ */
19258945Sroberto
20258945Sroberto/*! \file */
21258945Sroberto
22258945Sroberto#include <config.h>
23258945Sroberto
24258945Sroberto#include <ctype.h>
25258945Sroberto#include <errno.h>
26258945Sroberto#include <stdlib.h>
27258945Sroberto
28258945Sroberto#include <isc/buffer.h>
29258945Sroberto#include <isc/file.h>
30258945Sroberto#include <isc/lex.h>
31258945Sroberto#include <isc/mem.h>
32258945Sroberto#include <isc/msgs.h>
33258945Sroberto#include <isc/parseint.h>
34258945Sroberto#include <isc/print.h>
35258945Sroberto#include <isc/stdio.h>
36258945Sroberto#include <isc/string.h>
37258945Sroberto#include <isc/util.h>
38258945Sroberto
39258945Srobertotypedef struct inputsource {
40258945Sroberto	isc_result_t			result;
41258945Sroberto	isc_boolean_t			is_file;
42258945Sroberto	isc_boolean_t			need_close;
43258945Sroberto	isc_boolean_t			at_eof;
44258945Sroberto	isc_buffer_t *			pushback;
45258945Sroberto	unsigned int			ignored;
46258945Sroberto	void *				input;
47258945Sroberto	char *				name;
48258945Sroberto	unsigned long			line;
49258945Sroberto	unsigned long			saved_line;
50258945Sroberto	ISC_LINK(struct inputsource)	link;
51258945Sroberto} inputsource;
52258945Sroberto
53258945Sroberto#define LEX_MAGIC			ISC_MAGIC('L', 'e', 'x', '!')
54258945Sroberto#define VALID_LEX(l)			ISC_MAGIC_VALID(l, LEX_MAGIC)
55258945Sroberto
56258945Srobertostruct isc_lex {
57258945Sroberto	/* Unlocked. */
58258945Sroberto	unsigned int			magic;
59258945Sroberto	isc_mem_t *			mctx;
60258945Sroberto	size_t				max_token;
61258945Sroberto	char *				data;
62258945Sroberto	unsigned int			comments;
63258945Sroberto	isc_boolean_t			comment_ok;
64258945Sroberto	isc_boolean_t			last_was_eol;
65258945Sroberto	unsigned int			paren_count;
66258945Sroberto	unsigned int			saved_paren_count;
67258945Sroberto	isc_lexspecials_t		specials;
68258945Sroberto	LIST(struct inputsource)	sources;
69258945Sroberto};
70258945Sroberto
71258945Srobertostatic inline isc_result_t
72258945Srobertogrow_data(isc_lex_t *lex, size_t *remainingp, char **currp, char **prevp) {
73258945Sroberto	char *new;
74258945Sroberto
75258945Sroberto	new = isc_mem_get(lex->mctx, lex->max_token * 2 + 1);
76258945Sroberto	if (new == NULL)
77258945Sroberto		return (ISC_R_NOMEMORY);
78258945Sroberto	memcpy(new, lex->data, lex->max_token + 1);
79258945Sroberto	*currp = new + (*currp - lex->data);
80258945Sroberto	if (*prevp != NULL)
81258945Sroberto		*prevp = new + (*prevp - lex->data);
82258945Sroberto	isc_mem_put(lex->mctx, lex->data, lex->max_token + 1);
83258945Sroberto	lex->data = new;
84258945Sroberto	*remainingp += lex->max_token;
85258945Sroberto	lex->max_token *= 2;
86258945Sroberto	return (ISC_R_SUCCESS);
87258945Sroberto}
88258945Sroberto
89258945Srobertoisc_result_t
90258945Srobertoisc_lex_create(isc_mem_t *mctx, size_t max_token, isc_lex_t **lexp) {
91258945Sroberto	isc_lex_t *lex;
92258945Sroberto
93258945Sroberto	/*
94258945Sroberto	 * Create a lexer.
95258945Sroberto	 */
96258945Sroberto
97258945Sroberto	REQUIRE(lexp != NULL && *lexp == NULL);
98258945Sroberto	REQUIRE(max_token > 0U);
99258945Sroberto
100258945Sroberto	lex = isc_mem_get(mctx, sizeof(*lex));
101258945Sroberto	if (lex == NULL)
102258945Sroberto		return (ISC_R_NOMEMORY);
103258945Sroberto	lex->data = isc_mem_get(mctx, max_token + 1);
104258945Sroberto	if (lex->data == NULL) {
105258945Sroberto		isc_mem_put(mctx, lex, sizeof(*lex));
106258945Sroberto		return (ISC_R_NOMEMORY);
107258945Sroberto	}
108258945Sroberto	lex->mctx = mctx;
109258945Sroberto	lex->max_token = max_token;
110258945Sroberto	lex->comments = 0;
111258945Sroberto	lex->comment_ok = ISC_TRUE;
112258945Sroberto	lex->last_was_eol = ISC_TRUE;
113258945Sroberto	lex->paren_count = 0;
114258945Sroberto	lex->saved_paren_count = 0;
115258945Sroberto	memset(lex->specials, 0, 256);
116258945Sroberto	INIT_LIST(lex->sources);
117258945Sroberto	lex->magic = LEX_MAGIC;
118258945Sroberto
119258945Sroberto	*lexp = lex;
120258945Sroberto
121258945Sroberto	return (ISC_R_SUCCESS);
122258945Sroberto}
123258945Sroberto
124258945Srobertovoid
125258945Srobertoisc_lex_destroy(isc_lex_t **lexp) {
126258945Sroberto	isc_lex_t *lex;
127258945Sroberto
128258945Sroberto	/*
129258945Sroberto	 * Destroy the lexer.
130258945Sroberto	 */
131258945Sroberto
132258945Sroberto	REQUIRE(lexp != NULL);
133258945Sroberto	lex = *lexp;
134258945Sroberto	REQUIRE(VALID_LEX(lex));
135258945Sroberto
136258945Sroberto	while (!EMPTY(lex->sources))
137258945Sroberto		RUNTIME_CHECK(isc_lex_close(lex) == ISC_R_SUCCESS);
138258945Sroberto	if (lex->data != NULL)
139258945Sroberto		isc_mem_put(lex->mctx, lex->data, lex->max_token + 1);
140258945Sroberto	lex->magic = 0;
141258945Sroberto	isc_mem_put(lex->mctx, lex, sizeof(*lex));
142258945Sroberto
143258945Sroberto	*lexp = NULL;
144258945Sroberto}
145258945Sroberto
146258945Srobertounsigned int
147258945Srobertoisc_lex_getcomments(isc_lex_t *lex) {
148258945Sroberto	/*
149258945Sroberto	 * Return the current lexer commenting styles.
150258945Sroberto	 */
151258945Sroberto
152258945Sroberto	REQUIRE(VALID_LEX(lex));
153258945Sroberto
154258945Sroberto	return (lex->comments);
155258945Sroberto}
156258945Sroberto
157258945Srobertovoid
158258945Srobertoisc_lex_setcomments(isc_lex_t *lex, unsigned int comments) {
159258945Sroberto	/*
160258945Sroberto	 * Set allowed lexer commenting styles.
161258945Sroberto	 */
162258945Sroberto
163258945Sroberto	REQUIRE(VALID_LEX(lex));
164258945Sroberto
165258945Sroberto	lex->comments = comments;
166258945Sroberto}
167258945Sroberto
168258945Srobertovoid
169258945Srobertoisc_lex_getspecials(isc_lex_t *lex, isc_lexspecials_t specials) {
170258945Sroberto	/*
171258945Sroberto	 * Put the current list of specials into 'specials'.
172258945Sroberto	 */
173258945Sroberto
174258945Sroberto	REQUIRE(VALID_LEX(lex));
175258945Sroberto
176258945Sroberto	memcpy(specials, lex->specials, 256);
177258945Sroberto}
178258945Sroberto
179258945Srobertovoid
180258945Srobertoisc_lex_setspecials(isc_lex_t *lex, isc_lexspecials_t specials) {
181258945Sroberto	/*
182258945Sroberto	 * The characters in 'specials' are returned as tokens.  Along with
183258945Sroberto	 * whitespace, they delimit strings and numbers.
184258945Sroberto	 */
185258945Sroberto
186258945Sroberto	REQUIRE(VALID_LEX(lex));
187258945Sroberto
188258945Sroberto	memcpy(lex->specials, specials, 256);
189258945Sroberto}
190258945Sroberto
191258945Srobertostatic inline isc_result_t
192258945Srobertonew_source(isc_lex_t *lex, isc_boolean_t is_file, isc_boolean_t need_close,
193258945Sroberto	   void *input, const char *name)
194258945Sroberto{
195258945Sroberto	inputsource *source;
196258945Sroberto	isc_result_t result;
197258945Sroberto
198258945Sroberto	source = isc_mem_get(lex->mctx, sizeof(*source));
199258945Sroberto	if (source == NULL)
200258945Sroberto		return (ISC_R_NOMEMORY);
201258945Sroberto	source->result = ISC_R_SUCCESS;
202258945Sroberto	source->is_file = is_file;
203258945Sroberto	source->need_close = need_close;
204258945Sroberto	source->at_eof = ISC_FALSE;
205258945Sroberto	source->input = input;
206258945Sroberto	source->name = isc_mem_strdup(lex->mctx, name);
207258945Sroberto	if (source->name == NULL) {
208258945Sroberto		isc_mem_put(lex->mctx, source, sizeof(*source));
209258945Sroberto		return (ISC_R_NOMEMORY);
210258945Sroberto	}
211258945Sroberto	source->pushback = NULL;
212258945Sroberto	result = isc_buffer_allocate(lex->mctx, &source->pushback,
213258945Sroberto				     lex->max_token);
214258945Sroberto	if (result != ISC_R_SUCCESS) {
215258945Sroberto		isc_mem_free(lex->mctx, source->name);
216258945Sroberto		isc_mem_put(lex->mctx, source, sizeof(*source));
217258945Sroberto		return (result);
218258945Sroberto	}
219258945Sroberto	source->ignored = 0;
220258945Sroberto	source->line = 1;
221258945Sroberto	ISC_LIST_INITANDPREPEND(lex->sources, source, link);
222258945Sroberto
223258945Sroberto	return (ISC_R_SUCCESS);
224258945Sroberto}
225258945Sroberto
226258945Srobertoisc_result_t
227258945Srobertoisc_lex_openfile(isc_lex_t *lex, const char *filename) {
228258945Sroberto	isc_result_t result;
229258945Sroberto	FILE *stream = NULL;
230258945Sroberto
231258945Sroberto	/*
232258945Sroberto	 * Open 'filename' and make it the current input source for 'lex'.
233258945Sroberto	 */
234258945Sroberto
235258945Sroberto	REQUIRE(VALID_LEX(lex));
236258945Sroberto
237258945Sroberto	result = isc_stdio_open(filename, "r", &stream);
238258945Sroberto	if (result != ISC_R_SUCCESS)
239258945Sroberto		return (result);
240258945Sroberto
241258945Sroberto	result = new_source(lex, ISC_TRUE, ISC_TRUE, stream, filename);
242258945Sroberto	if (result != ISC_R_SUCCESS)
243258945Sroberto		(void)fclose(stream);
244258945Sroberto	return (result);
245258945Sroberto}
246258945Sroberto
247258945Srobertoisc_result_t
248258945Srobertoisc_lex_openstream(isc_lex_t *lex, FILE *stream) {
249258945Sroberto	char name[128];
250258945Sroberto
251258945Sroberto	/*
252258945Sroberto	 * Make 'stream' the current input source for 'lex'.
253258945Sroberto	 */
254258945Sroberto
255258945Sroberto	REQUIRE(VALID_LEX(lex));
256258945Sroberto
257258945Sroberto	snprintf(name, sizeof(name), "stream-%p", stream);
258258945Sroberto
259258945Sroberto	return (new_source(lex, ISC_TRUE, ISC_FALSE, stream, name));
260258945Sroberto}
261258945Sroberto
262258945Srobertoisc_result_t
263258945Srobertoisc_lex_openbuffer(isc_lex_t *lex, isc_buffer_t *buffer) {
264258945Sroberto	char name[128];
265258945Sroberto
266258945Sroberto	/*
267258945Sroberto	 * Make 'buffer' the current input source for 'lex'.
268258945Sroberto	 */
269258945Sroberto
270258945Sroberto	REQUIRE(VALID_LEX(lex));
271258945Sroberto
272258945Sroberto	snprintf(name, sizeof(name), "buffer-%p", buffer);
273258945Sroberto
274258945Sroberto	return (new_source(lex, ISC_FALSE, ISC_FALSE, buffer, name));
275258945Sroberto}
276258945Sroberto
277258945Srobertoisc_result_t
278258945Srobertoisc_lex_close(isc_lex_t *lex) {
279258945Sroberto	inputsource *source;
280258945Sroberto
281258945Sroberto	/*
282258945Sroberto	 * Close the most recently opened object (i.e. file or buffer).
283258945Sroberto	 */
284258945Sroberto
285258945Sroberto	REQUIRE(VALID_LEX(lex));
286258945Sroberto
287258945Sroberto	source = HEAD(lex->sources);
288258945Sroberto	if (source == NULL)
289258945Sroberto		return (ISC_R_NOMORE);
290258945Sroberto
291258945Sroberto	ISC_LIST_UNLINK(lex->sources, source, link);
292258945Sroberto	if (source->is_file) {
293258945Sroberto		if (source->need_close)
294258945Sroberto			(void)fclose((FILE *)(source->input));
295258945Sroberto	}
296258945Sroberto	isc_mem_free(lex->mctx, source->name);
297258945Sroberto	isc_buffer_free(&source->pushback);
298258945Sroberto	isc_mem_put(lex->mctx, source, sizeof(*source));
299258945Sroberto
300258945Sroberto	return (ISC_R_SUCCESS);
301258945Sroberto}
302258945Sroberto
303258945Srobertotypedef enum {
304258945Sroberto	lexstate_start,
305258945Sroberto	lexstate_crlf,
306258945Sroberto	lexstate_string,
307258945Sroberto	lexstate_number,
308258945Sroberto	lexstate_maybecomment,
309258945Sroberto	lexstate_ccomment,
310258945Sroberto	lexstate_ccommentend,
311258945Sroberto	lexstate_eatline,
312258945Sroberto	lexstate_qstring
313258945Sroberto} lexstate;
314258945Sroberto
315258945Sroberto#define IWSEOL (ISC_LEXOPT_INITIALWS | ISC_LEXOPT_EOL)
316258945Sroberto
317258945Srobertostatic void
318258945Srobertopushback(inputsource *source, int c) {
319258945Sroberto	REQUIRE(source->pushback->current > 0);
320258945Sroberto	if (c == EOF) {
321258945Sroberto		source->at_eof = ISC_FALSE;
322258945Sroberto		return;
323258945Sroberto	}
324258945Sroberto	source->pushback->current--;
325258945Sroberto	if (c == '\n')
326258945Sroberto		source->line--;
327258945Sroberto}
328258945Sroberto
329258945Srobertostatic isc_result_t
330258945Srobertopushandgrow(isc_lex_t *lex, inputsource *source, int c) {
331258945Sroberto	if (isc_buffer_availablelength(source->pushback) == 0) {
332258945Sroberto		isc_buffer_t *tbuf = NULL;
333258945Sroberto		unsigned int oldlen;
334258945Sroberto		isc_region_t used;
335258945Sroberto		isc_result_t result;
336258945Sroberto
337258945Sroberto		oldlen = isc_buffer_length(source->pushback);
338258945Sroberto		result = isc_buffer_allocate(lex->mctx, &tbuf, oldlen * 2);
339258945Sroberto		if (result != ISC_R_SUCCESS)
340258945Sroberto			return (result);
341258945Sroberto		isc_buffer_usedregion(source->pushback, &used);
342258945Sroberto		result = isc_buffer_copyregion(tbuf, &used);
343258945Sroberto		INSIST(result == ISC_R_SUCCESS);
344258945Sroberto		tbuf->current = source->pushback->current;
345258945Sroberto		isc_buffer_free(&source->pushback);
346258945Sroberto		source->pushback = tbuf;
347258945Sroberto	}
348258945Sroberto	isc_buffer_putuint8(source->pushback, (isc_uint8_t)c);
349258945Sroberto	return (ISC_R_SUCCESS);
350258945Sroberto}
351258945Sroberto
352258945Srobertoisc_result_t
353258945Srobertoisc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp) {
354258945Sroberto	inputsource *source;
355258945Sroberto	int c;
356258945Sroberto	isc_boolean_t done = ISC_FALSE;
357258945Sroberto	isc_boolean_t no_comments = ISC_FALSE;
358258945Sroberto	isc_boolean_t escaped = ISC_FALSE;
359258945Sroberto	lexstate state = lexstate_start;
360258945Sroberto	lexstate saved_state = lexstate_start;
361258945Sroberto	isc_buffer_t *buffer;
362258945Sroberto	FILE *stream;
363258945Sroberto	char *curr, *prev;
364258945Sroberto	size_t remaining;
365258945Sroberto	isc_uint32_t as_ulong;
366258945Sroberto	unsigned int saved_options;
367258945Sroberto	isc_result_t result;
368258945Sroberto
369258945Sroberto	/*
370258945Sroberto	 * Get the next token.
371258945Sroberto	 */
372258945Sroberto
373258945Sroberto	REQUIRE(VALID_LEX(lex));
374258945Sroberto	source = HEAD(lex->sources);
375258945Sroberto	REQUIRE(tokenp != NULL);
376258945Sroberto
377258945Sroberto	if (source == NULL) {
378258945Sroberto		if ((options & ISC_LEXOPT_NOMORE) != 0) {
379258945Sroberto			tokenp->type = isc_tokentype_nomore;
380258945Sroberto			return (ISC_R_SUCCESS);
381258945Sroberto		}
382258945Sroberto		return (ISC_R_NOMORE);
383258945Sroberto	}
384258945Sroberto
385258945Sroberto	if (source->result != ISC_R_SUCCESS)
386258945Sroberto		return (source->result);
387258945Sroberto
388258945Sroberto	lex->saved_paren_count = lex->paren_count;
389258945Sroberto	source->saved_line = source->line;
390258945Sroberto
391258945Sroberto	if (isc_buffer_remaininglength(source->pushback) == 0 &&
392258945Sroberto	    source->at_eof)
393258945Sroberto	{
394258945Sroberto		if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 &&
395258945Sroberto		    lex->paren_count != 0) {
396258945Sroberto			lex->paren_count = 0;
397258945Sroberto			return (ISC_R_UNBALANCED);
398258945Sroberto		}
399258945Sroberto		if ((options & ISC_LEXOPT_EOF) != 0) {
400258945Sroberto			tokenp->type = isc_tokentype_eof;
401258945Sroberto			return (ISC_R_SUCCESS);
402258945Sroberto		}
403258945Sroberto		return (ISC_R_EOF);
404258945Sroberto	}
405258945Sroberto
406258945Sroberto	isc_buffer_compact(source->pushback);
407258945Sroberto
408258945Sroberto	saved_options = options;
409258945Sroberto	if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 && lex->paren_count > 0)
410258945Sroberto		options &= ~IWSEOL;
411258945Sroberto
412258945Sroberto	curr = lex->data;
413258945Sroberto	*curr = '\0';
414258945Sroberto
415258945Sroberto	prev = NULL;
416258945Sroberto	remaining = lex->max_token;
417258945Sroberto
418258945Sroberto#ifdef HAVE_FLOCKFILE
419258945Sroberto	if (source->is_file)
420258945Sroberto		flockfile(source->input);
421258945Sroberto#endif
422258945Sroberto
423258945Sroberto	do {
424258945Sroberto		if (isc_buffer_remaininglength(source->pushback) == 0) {
425258945Sroberto			if (source->is_file) {
426258945Sroberto				stream = source->input;
427258945Sroberto
428258945Sroberto#if defined(HAVE_FLOCKFILE) && defined(HAVE_GETCUNLOCKED)
429258945Sroberto				c = getc_unlocked(stream);
430258945Sroberto#else
431258945Sroberto				c = getc(stream);
432258945Sroberto#endif
433258945Sroberto				if (c == EOF) {
434258945Sroberto					if (ferror(stream)) {
435258945Sroberto						source->result = ISC_R_IOERROR;
436258945Sroberto						result = source->result;
437258945Sroberto						goto done;
438258945Sroberto					}
439258945Sroberto					source->at_eof = ISC_TRUE;
440258945Sroberto				}
441258945Sroberto			} else {
442258945Sroberto				buffer = source->input;
443258945Sroberto
444258945Sroberto				if (buffer->current == buffer->used) {
445258945Sroberto					c = EOF;
446258945Sroberto					source->at_eof = ISC_TRUE;
447258945Sroberto				} else {
448258945Sroberto					c = *((char *)buffer->base +
449258945Sroberto					      buffer->current);
450258945Sroberto					buffer->current++;
451258945Sroberto				}
452258945Sroberto			}
453258945Sroberto			if (c != EOF) {
454258945Sroberto				source->result = pushandgrow(lex, source, c);
455258945Sroberto				if (source->result != ISC_R_SUCCESS) {
456258945Sroberto					result = source->result;
457258945Sroberto					goto done;
458258945Sroberto				}
459258945Sroberto			}
460258945Sroberto		}
461258945Sroberto
462258945Sroberto		if (!source->at_eof) {
463258945Sroberto			if (state == lexstate_start)
464258945Sroberto				/* Token has not started yet. */
465258945Sroberto				source->ignored =
466258945Sroberto				   isc_buffer_consumedlength(source->pushback);
467258945Sroberto			c = isc_buffer_getuint8(source->pushback);
468258945Sroberto		} else {
469258945Sroberto			c = EOF;
470258945Sroberto		}
471258945Sroberto
472258945Sroberto		if (c == '\n')
473258945Sroberto			source->line++;
474258945Sroberto
475258945Sroberto		if (lex->comment_ok && !no_comments) {
476258945Sroberto			if (!escaped && c == ';' &&
477258945Sroberto			    ((lex->comments & ISC_LEXCOMMENT_DNSMASTERFILE)
478258945Sroberto			     != 0)) {
479258945Sroberto				saved_state = state;
480258945Sroberto				state = lexstate_eatline;
481258945Sroberto				no_comments = ISC_TRUE;
482258945Sroberto				continue;
483258945Sroberto			} else if (c == '/' &&
484258945Sroberto				   (lex->comments &
485258945Sroberto				    (ISC_LEXCOMMENT_C|
486258945Sroberto				     ISC_LEXCOMMENT_CPLUSPLUS)) != 0) {
487258945Sroberto				saved_state = state;
488258945Sroberto				state = lexstate_maybecomment;
489258945Sroberto				no_comments = ISC_TRUE;
490258945Sroberto				continue;
491258945Sroberto			} else if (c == '#' &&
492258945Sroberto				   ((lex->comments & ISC_LEXCOMMENT_SHELL)
493258945Sroberto				    != 0)) {
494258945Sroberto				saved_state = state;
495258945Sroberto				state = lexstate_eatline;
496258945Sroberto				no_comments = ISC_TRUE;
497258945Sroberto				continue;
498258945Sroberto			}
499258945Sroberto		}
500258945Sroberto
501258945Sroberto	no_read:
502258945Sroberto		/* INSIST(c == EOF || (c >= 0 && c <= 255)); */
503258945Sroberto		switch (state) {
504258945Sroberto		case lexstate_start:
505258945Sroberto			if (c == EOF) {
506258945Sroberto				lex->last_was_eol = ISC_FALSE;
507258945Sroberto				if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 &&
508258945Sroberto				    lex->paren_count != 0) {
509258945Sroberto					lex->paren_count = 0;
510258945Sroberto					result = ISC_R_UNBALANCED;
511258945Sroberto					goto done;
512258945Sroberto				}
513258945Sroberto				if ((options & ISC_LEXOPT_EOF) == 0) {
514258945Sroberto					result = ISC_R_EOF;
515258945Sroberto					goto done;
516258945Sroberto				}
517258945Sroberto				tokenp->type = isc_tokentype_eof;
518258945Sroberto				done = ISC_TRUE;
519258945Sroberto			} else if (c == ' ' || c == '\t') {
520258945Sroberto				if (lex->last_was_eol &&
521258945Sroberto				    (options & ISC_LEXOPT_INITIALWS)
522258945Sroberto				    != 0) {
523258945Sroberto					lex->last_was_eol = ISC_FALSE;
524258945Sroberto					tokenp->type = isc_tokentype_initialws;
525258945Sroberto 					tokenp->value.as_char = c;
526258945Sroberto					done = ISC_TRUE;
527258945Sroberto				}
528258945Sroberto			} else if (c == '\n') {
529258945Sroberto				if ((options & ISC_LEXOPT_EOL) != 0) {
530258945Sroberto					tokenp->type = isc_tokentype_eol;
531258945Sroberto					done = ISC_TRUE;
532258945Sroberto				}
533258945Sroberto				lex->last_was_eol = ISC_TRUE;
534258945Sroberto			} else if (c == '\r') {
535258945Sroberto				if ((options & ISC_LEXOPT_EOL) != 0)
536258945Sroberto					state = lexstate_crlf;
537258945Sroberto			} else if (c == '"' &&
538258945Sroberto				   (options & ISC_LEXOPT_QSTRING) != 0) {
539258945Sroberto				lex->last_was_eol = ISC_FALSE;
540258945Sroberto				no_comments = ISC_TRUE;
541258945Sroberto				state = lexstate_qstring;
542258945Sroberto			} else if (lex->specials[c]) {
543258945Sroberto				lex->last_was_eol = ISC_FALSE;
544258945Sroberto				if ((c == '(' || c == ')') &&
545258945Sroberto				    (options & ISC_LEXOPT_DNSMULTILINE) != 0) {
546258945Sroberto					if (c == '(') {
547258945Sroberto						if (lex->paren_count == 0)
548258945Sroberto							options &= ~IWSEOL;
549258945Sroberto						lex->paren_count++;
550258945Sroberto					} else {
551258945Sroberto						if (lex->paren_count == 0) {
552258945Sroberto						    result = ISC_R_UNBALANCED;
553258945Sroberto						    goto done;
554258945Sroberto						}
555258945Sroberto						lex->paren_count--;
556258945Sroberto						if (lex->paren_count == 0)
557258945Sroberto							options =
558258945Sroberto								saved_options;
559258945Sroberto					}
560258945Sroberto					continue;
561258945Sroberto				}
562258945Sroberto				tokenp->type = isc_tokentype_special;
563258945Sroberto				tokenp->value.as_char = c;
564258945Sroberto				done = ISC_TRUE;
565258945Sroberto			} else if (isdigit((unsigned char)c) &&
566258945Sroberto				   (options & ISC_LEXOPT_NUMBER) != 0) {
567258945Sroberto				lex->last_was_eol = ISC_FALSE;
568258945Sroberto				if ((options & ISC_LEXOPT_OCTAL) != 0 &&
569258945Sroberto				    (c == '8' || c == '9'))
570258945Sroberto					state = lexstate_string;
571258945Sroberto				else
572258945Sroberto					state = lexstate_number;
573258945Sroberto				goto no_read;
574258945Sroberto			} else {
575258945Sroberto				lex->last_was_eol = ISC_FALSE;
576258945Sroberto				state = lexstate_string;
577258945Sroberto				goto no_read;
578258945Sroberto			}
579258945Sroberto			break;
580258945Sroberto		case lexstate_crlf:
581258945Sroberto			if (c != '\n')
582258945Sroberto				pushback(source, c);
583258945Sroberto			tokenp->type = isc_tokentype_eol;
584258945Sroberto			done = ISC_TRUE;
585258945Sroberto			lex->last_was_eol = ISC_TRUE;
586258945Sroberto			break;
587258945Sroberto		case lexstate_number:
588258945Sroberto			if (c == EOF || !isdigit((unsigned char)c)) {
589258945Sroberto				if (c == ' ' || c == '\t' || c == '\r' ||
590258945Sroberto				    c == '\n' || c == EOF ||
591258945Sroberto				    lex->specials[c]) {
592258945Sroberto					int base;
593258945Sroberto					if ((options & ISC_LEXOPT_OCTAL) != 0)
594258945Sroberto						base = 8;
595258945Sroberto					else if ((options & ISC_LEXOPT_CNUMBER) != 0)
596258945Sroberto						base = 0;
597258945Sroberto					else
598258945Sroberto						base = 10;
599258945Sroberto					pushback(source, c);
600258945Sroberto
601258945Sroberto					result = isc_parse_uint32(&as_ulong,
602258945Sroberto								  lex->data,
603258945Sroberto								  base);
604258945Sroberto					if (result == ISC_R_SUCCESS) {
605258945Sroberto						tokenp->type =
606258945Sroberto							isc_tokentype_number;
607258945Sroberto						tokenp->value.as_ulong =
608258945Sroberto							as_ulong;
609258945Sroberto					} else if (result == ISC_R_BADNUMBER) {
610258945Sroberto						isc_tokenvalue_t *v;
611258945Sroberto
612258945Sroberto						tokenp->type =
613258945Sroberto							isc_tokentype_string;
614258945Sroberto						v = &(tokenp->value);
615258945Sroberto						v->as_textregion.base =
616258945Sroberto							lex->data;
617258945Sroberto						v->as_textregion.length =
618258945Sroberto							lex->max_token -
619258945Sroberto							remaining;
620258945Sroberto					} else
621258945Sroberto						goto done;
622258945Sroberto					done = ISC_TRUE;
623258945Sroberto					continue;
624258945Sroberto				} else if (!(options & ISC_LEXOPT_CNUMBER) ||
625258945Sroberto					   ((c != 'x' && c != 'X') ||
626258945Sroberto					   (curr != &lex->data[1]) ||
627258945Sroberto					   (lex->data[0] != '0'))) {
628258945Sroberto					/* Above test supports hex numbers */
629258945Sroberto					state = lexstate_string;
630258945Sroberto				}
631258945Sroberto			} else if ((options & ISC_LEXOPT_OCTAL) != 0 &&
632258945Sroberto				   (c == '8' || c == '9')) {
633258945Sroberto				state = lexstate_string;
634258945Sroberto			}
635258945Sroberto			if (remaining == 0U) {
636258945Sroberto				result = grow_data(lex, &remaining,
637258945Sroberto						   &curr, &prev);
638258945Sroberto				if (result != ISC_R_SUCCESS)
639258945Sroberto					goto done;
640258945Sroberto			}
641258945Sroberto			INSIST(remaining > 0U);
642258945Sroberto			*curr++ = c;
643258945Sroberto			*curr = '\0';
644258945Sroberto			remaining--;
645258945Sroberto			break;
646258945Sroberto		case lexstate_string:
647258945Sroberto			/*
648258945Sroberto			 * EOF needs to be checked before lex->specials[c]
649258945Sroberto			 * as lex->specials[EOF] is not a good idea.
650258945Sroberto			 */
651258945Sroberto			if (c == '\r' || c == '\n' || c == EOF ||
652258945Sroberto			    (!escaped &&
653258945Sroberto			     (c == ' ' || c == '\t' || lex->specials[c]))) {
654258945Sroberto				pushback(source, c);
655258945Sroberto				if (source->result != ISC_R_SUCCESS) {
656258945Sroberto					result = source->result;
657258945Sroberto					goto done;
658258945Sroberto				}
659258945Sroberto				tokenp->type = isc_tokentype_string;
660258945Sroberto				tokenp->value.as_textregion.base = lex->data;
661258945Sroberto				tokenp->value.as_textregion.length =
662258945Sroberto					lex->max_token - remaining;
663258945Sroberto				done = ISC_TRUE;
664258945Sroberto				continue;
665258945Sroberto			}
666258945Sroberto			if ((options & ISC_LEXOPT_ESCAPE) != 0)
667258945Sroberto				escaped = (!escaped && c == '\\') ?
668258945Sroberto						ISC_TRUE : ISC_FALSE;
669258945Sroberto			if (remaining == 0U) {
670258945Sroberto				result = grow_data(lex, &remaining,
671258945Sroberto						   &curr, &prev);
672258945Sroberto				if (result != ISC_R_SUCCESS)
673258945Sroberto					goto done;
674258945Sroberto			}
675258945Sroberto			INSIST(remaining > 0U);
676258945Sroberto			*curr++ = c;
677258945Sroberto			*curr = '\0';
678258945Sroberto			remaining--;
679258945Sroberto			break;
680258945Sroberto		case lexstate_maybecomment:
681258945Sroberto			if (c == '*' &&
682258945Sroberto			    (lex->comments & ISC_LEXCOMMENT_C) != 0) {
683258945Sroberto				state = lexstate_ccomment;
684258945Sroberto				continue;
685258945Sroberto			} else if (c == '/' &&
686258945Sroberto			    (lex->comments & ISC_LEXCOMMENT_CPLUSPLUS) != 0) {
687258945Sroberto				state = lexstate_eatline;
688258945Sroberto				continue;
689258945Sroberto			}
690258945Sroberto			pushback(source, c);
691258945Sroberto			c = '/';
692258945Sroberto			no_comments = ISC_FALSE;
693258945Sroberto			state = saved_state;
694258945Sroberto			goto no_read;
695258945Sroberto		case lexstate_ccomment:
696258945Sroberto			if (c == EOF) {
697258945Sroberto				result = ISC_R_UNEXPECTEDEND;
698258945Sroberto				goto done;
699258945Sroberto			}
700258945Sroberto			if (c == '*')
701258945Sroberto				state = lexstate_ccommentend;
702258945Sroberto			break;
703258945Sroberto		case lexstate_ccommentend:
704258945Sroberto			if (c == EOF) {
705258945Sroberto				result = ISC_R_UNEXPECTEDEND;
706258945Sroberto				goto done;
707258945Sroberto			}
708258945Sroberto			if (c == '/') {
709258945Sroberto				/*
710258945Sroberto				 * C-style comments become a single space.
711258945Sroberto				 * We do this to ensure that a comment will
712258945Sroberto				 * act as a delimiter for strings and
713258945Sroberto				 * numbers.
714258945Sroberto				 */
715258945Sroberto				c = ' ';
716258945Sroberto				no_comments = ISC_FALSE;
717258945Sroberto				state = saved_state;
718258945Sroberto				goto no_read;
719258945Sroberto			} else if (c != '*')
720258945Sroberto				state = lexstate_ccomment;
721258945Sroberto			break;
722258945Sroberto		case lexstate_eatline:
723258945Sroberto			if ((c == '\n') || (c == EOF)) {
724258945Sroberto				no_comments = ISC_FALSE;
725258945Sroberto				state = saved_state;
726258945Sroberto				goto no_read;
727258945Sroberto			}
728258945Sroberto			break;
729258945Sroberto		case lexstate_qstring:
730258945Sroberto			if (c == EOF) {
731258945Sroberto				result = ISC_R_UNEXPECTEDEND;
732258945Sroberto				goto done;
733258945Sroberto			}
734258945Sroberto			if (c == '"') {
735258945Sroberto				if (escaped) {
736258945Sroberto					escaped = ISC_FALSE;
737258945Sroberto					/*
738258945Sroberto					 * Overwrite the preceding backslash.
739258945Sroberto					 */
740258945Sroberto					INSIST(prev != NULL);
741258945Sroberto					*prev = '"';
742258945Sroberto				} else {
743258945Sroberto					tokenp->type = isc_tokentype_qstring;
744258945Sroberto					tokenp->value.as_textregion.base =
745258945Sroberto						lex->data;
746258945Sroberto					tokenp->value.as_textregion.length =
747258945Sroberto						lex->max_token - remaining;
748258945Sroberto					no_comments = ISC_FALSE;
749258945Sroberto					done = ISC_TRUE;
750258945Sroberto				}
751258945Sroberto			} else {
752258945Sroberto				if (c == '\n' && !escaped &&
753258945Sroberto			    (options & ISC_LEXOPT_QSTRINGMULTILINE) == 0) {
754258945Sroberto					pushback(source, c);
755258945Sroberto					result = ISC_R_UNBALANCEDQUOTES;
756258945Sroberto					goto done;
757258945Sroberto				}
758258945Sroberto				if (c == '\\' && !escaped)
759258945Sroberto					escaped = ISC_TRUE;
760258945Sroberto				else
761258945Sroberto					escaped = ISC_FALSE;
762258945Sroberto				if (remaining == 0U) {
763258945Sroberto					result = grow_data(lex, &remaining,
764258945Sroberto							   &curr, &prev);
765258945Sroberto					if (result != ISC_R_SUCCESS)
766258945Sroberto						goto done;
767258945Sroberto				}
768258945Sroberto				INSIST(remaining > 0U);
769258945Sroberto				prev = curr;
770258945Sroberto				*curr++ = c;
771258945Sroberto				*curr = '\0';
772258945Sroberto				remaining--;
773258945Sroberto			}
774258945Sroberto			break;
775258945Sroberto		default:
776258945Sroberto			FATAL_ERROR(__FILE__, __LINE__,
777258945Sroberto				    isc_msgcat_get(isc_msgcat, ISC_MSGSET_LEX,
778258945Sroberto						   ISC_MSG_UNEXPECTEDSTATE,
779258945Sroberto						   "Unexpected state %d"),
780258945Sroberto				    state);
781258945Sroberto			/* Does not return. */
782258945Sroberto		}
783258945Sroberto
784258945Sroberto	} while (!done);
785258945Sroberto
786258945Sroberto	result = ISC_R_SUCCESS;
787258945Sroberto done:
788258945Sroberto#ifdef HAVE_FLOCKFILE
789258945Sroberto	if (source->is_file)
790258945Sroberto		funlockfile(source->input);
791258945Sroberto#endif
792258945Sroberto	return (result);
793258945Sroberto}
794258945Sroberto
795258945Srobertoisc_result_t
796258945Srobertoisc_lex_getmastertoken(isc_lex_t *lex, isc_token_t *token,
797258945Sroberto		       isc_tokentype_t expect, isc_boolean_t eol)
798258945Sroberto{
799258945Sroberto	unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
800258945Sroberto			       ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE;
801258945Sroberto	isc_result_t result;
802258945Sroberto
803258945Sroberto	if (expect == isc_tokentype_qstring)
804258945Sroberto		options |= ISC_LEXOPT_QSTRING;
805258945Sroberto	else if (expect == isc_tokentype_number)
806258945Sroberto		options |= ISC_LEXOPT_NUMBER;
807258945Sroberto	result = isc_lex_gettoken(lex, options, token);
808258945Sroberto	if (result == ISC_R_RANGE)
809258945Sroberto		isc_lex_ungettoken(lex, token);
810258945Sroberto	if (result != ISC_R_SUCCESS)
811258945Sroberto		return (result);
812258945Sroberto
813258945Sroberto	if (eol && ((token->type == isc_tokentype_eol) ||
814258945Sroberto		    (token->type == isc_tokentype_eof)))
815258945Sroberto		return (ISC_R_SUCCESS);
816258945Sroberto	if (token->type == isc_tokentype_string &&
817258945Sroberto	    expect == isc_tokentype_qstring)
818258945Sroberto		return (ISC_R_SUCCESS);
819258945Sroberto	if (token->type != expect) {
820258945Sroberto		isc_lex_ungettoken(lex, token);
821258945Sroberto		if (token->type == isc_tokentype_eol ||
822258945Sroberto		    token->type == isc_tokentype_eof)
823258945Sroberto			return (ISC_R_UNEXPECTEDEND);
824258945Sroberto		if (expect == isc_tokentype_number)
825258945Sroberto			return (ISC_R_BADNUMBER);
826258945Sroberto		return (ISC_R_UNEXPECTEDTOKEN);
827258945Sroberto	}
828258945Sroberto	return (ISC_R_SUCCESS);
829258945Sroberto}
830258945Sroberto
831258945Srobertoisc_result_t
832258945Srobertoisc_lex_getoctaltoken(isc_lex_t *lex, isc_token_t *token, isc_boolean_t eol)
833258945Sroberto{
834258945Sroberto	unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
835258945Sroberto			       ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE|
836258945Sroberto			       ISC_LEXOPT_NUMBER | ISC_LEXOPT_OCTAL;
837258945Sroberto	isc_result_t result;
838258945Sroberto
839258945Sroberto	result = isc_lex_gettoken(lex, options, token);
840258945Sroberto	if (result == ISC_R_RANGE)
841258945Sroberto		isc_lex_ungettoken(lex, token);
842258945Sroberto	if (result != ISC_R_SUCCESS)
843258945Sroberto		return (result);
844258945Sroberto
845258945Sroberto	if (eol && ((token->type == isc_tokentype_eol) ||
846258945Sroberto		    (token->type == isc_tokentype_eof)))
847258945Sroberto		return (ISC_R_SUCCESS);
848258945Sroberto	if (token->type != isc_tokentype_number) {
849258945Sroberto		isc_lex_ungettoken(lex, token);
850258945Sroberto		if (token->type == isc_tokentype_eol ||
851258945Sroberto		    token->type == isc_tokentype_eof)
852258945Sroberto			return (ISC_R_UNEXPECTEDEND);
853258945Sroberto		return (ISC_R_BADNUMBER);
854258945Sroberto	}
855258945Sroberto	return (ISC_R_SUCCESS);
856258945Sroberto}
857258945Sroberto
858258945Srobertovoid
859258945Srobertoisc_lex_ungettoken(isc_lex_t *lex, isc_token_t *tokenp) {
860258945Sroberto	inputsource *source;
861258945Sroberto	/*
862258945Sroberto	 * Unget the current token.
863258945Sroberto	 */
864258945Sroberto
865258945Sroberto	REQUIRE(VALID_LEX(lex));
866258945Sroberto	source = HEAD(lex->sources);
867258945Sroberto	REQUIRE(source != NULL);
868258945Sroberto	REQUIRE(tokenp != NULL);
869258945Sroberto	REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 ||
870258945Sroberto		tokenp->type == isc_tokentype_eof);
871258945Sroberto
872258945Sroberto	UNUSED(tokenp);
873258945Sroberto
874258945Sroberto	isc_buffer_first(source->pushback);
875258945Sroberto	lex->paren_count = lex->saved_paren_count;
876258945Sroberto	source->line = source->saved_line;
877258945Sroberto	source->at_eof = ISC_FALSE;
878258945Sroberto}
879258945Sroberto
880258945Srobertovoid
881258945Srobertoisc_lex_getlasttokentext(isc_lex_t *lex, isc_token_t *tokenp, isc_region_t *r)
882258945Sroberto{
883258945Sroberto	inputsource *source;
884258945Sroberto
885258945Sroberto	REQUIRE(VALID_LEX(lex));
886258945Sroberto	source = HEAD(lex->sources);
887258945Sroberto	REQUIRE(source != NULL);
888258945Sroberto	REQUIRE(tokenp != NULL);
889258945Sroberto	REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 ||
890258945Sroberto		tokenp->type == isc_tokentype_eof);
891258945Sroberto
892258945Sroberto	UNUSED(tokenp);
893258945Sroberto
894258945Sroberto	INSIST(source->ignored <= isc_buffer_consumedlength(source->pushback));
895258945Sroberto	r->base = (unsigned char *)isc_buffer_base(source->pushback) +
896258945Sroberto		  source->ignored;
897258945Sroberto	r->length = isc_buffer_consumedlength(source->pushback) -
898258945Sroberto		    source->ignored;
899258945Sroberto}
900258945Sroberto
901258945Sroberto
902258945Srobertochar *
903258945Srobertoisc_lex_getsourcename(isc_lex_t *lex) {
904258945Sroberto	inputsource *source;
905258945Sroberto
906258945Sroberto	REQUIRE(VALID_LEX(lex));
907258945Sroberto	source = HEAD(lex->sources);
908258945Sroberto
909258945Sroberto	if (source == NULL)
910258945Sroberto		return (NULL);
911258945Sroberto
912258945Sroberto	return (source->name);
913258945Sroberto}
914258945Sroberto
915258945Srobertounsigned long
916258945Srobertoisc_lex_getsourceline(isc_lex_t *lex) {
917258945Sroberto	inputsource *source;
918258945Sroberto
919258945Sroberto	REQUIRE(VALID_LEX(lex));
920258945Sroberto	source = HEAD(lex->sources);
921258945Sroberto
922258945Sroberto	if (source == NULL)
923258945Sroberto		return (0);
924258945Sroberto
925258945Sroberto	return (source->line);
926258945Sroberto}
927258945Sroberto
928258945Sroberto
929258945Srobertoisc_result_t
930258945Srobertoisc_lex_setsourcename(isc_lex_t *lex, const char *name) {
931258945Sroberto	inputsource *source;
932258945Sroberto	char *newname;
933258945Sroberto
934258945Sroberto	REQUIRE(VALID_LEX(lex));
935258945Sroberto	source = HEAD(lex->sources);
936258945Sroberto
937258945Sroberto	if (source == NULL)
938258945Sroberto		return(ISC_R_NOTFOUND);
939258945Sroberto	newname = isc_mem_strdup(lex->mctx, name);
940258945Sroberto	if (newname == NULL)
941258945Sroberto		return (ISC_R_NOMEMORY);
942258945Sroberto	isc_mem_free(lex->mctx, source->name);
943258945Sroberto	source->name = newname;
944258945Sroberto	return (ISC_R_SUCCESS);
945258945Sroberto}
946258945Sroberto
947258945Srobertoisc_boolean_t
948258945Srobertoisc_lex_isfile(isc_lex_t *lex) {
949258945Sroberto	inputsource *source;
950258945Sroberto
951258945Sroberto	REQUIRE(VALID_LEX(lex));
952258945Sroberto
953258945Sroberto	source = HEAD(lex->sources);
954258945Sroberto
955258945Sroberto	if (source == NULL)
956258945Sroberto		return (ISC_FALSE);
957258945Sroberto
958258945Sroberto	return (source->is_file);
959258945Sroberto}
960