xref: /freebsd/contrib/ntp/ntpd/ntp_scanner.c (revision 68ba7e87e74b00b0511b346607b464f318c91083)
12b15cb3dSCy Schubert 
22b15cb3dSCy Schubert /* ntp_scanner.c
32b15cb3dSCy Schubert  *
42b15cb3dSCy Schubert  * The source code for a simple lexical analyzer.
52b15cb3dSCy Schubert  *
62b15cb3dSCy Schubert  * Written By:	Sachin Kamboj
72b15cb3dSCy Schubert  *		University of Delaware
82b15cb3dSCy Schubert  *		Newark, DE 19711
92b15cb3dSCy Schubert  * Copyright (c) 2006
102b15cb3dSCy Schubert  */
112b15cb3dSCy Schubert 
122b15cb3dSCy Schubert #ifdef HAVE_CONFIG_H
132b15cb3dSCy Schubert # include <config.h>
142b15cb3dSCy Schubert #endif
152b15cb3dSCy Schubert 
162b15cb3dSCy Schubert #include <stdio.h>
172b15cb3dSCy Schubert #include <ctype.h>
182b15cb3dSCy Schubert #include <stdlib.h>
192b15cb3dSCy Schubert #include <errno.h>
202b15cb3dSCy Schubert #include <string.h>
212b15cb3dSCy Schubert 
222b15cb3dSCy Schubert #include "ntpd.h"
232b15cb3dSCy Schubert #include "ntp_config.h"
242b15cb3dSCy Schubert #include "ntpsim.h"
252b15cb3dSCy Schubert #include "ntp_scanner.h"
262b15cb3dSCy Schubert #include "ntp_parser.h"
272b15cb3dSCy Schubert 
282b15cb3dSCy Schubert /* ntp_keyword.h declares finite state machine and token text */
292b15cb3dSCy Schubert #include "ntp_keyword.h"
302b15cb3dSCy Schubert 
312b15cb3dSCy Schubert 
322b15cb3dSCy Schubert 
332b15cb3dSCy Schubert /* SCANNER GLOBAL VARIABLES
342b15cb3dSCy Schubert  * ------------------------
352b15cb3dSCy Schubert  */
362b15cb3dSCy Schubert 
372b15cb3dSCy Schubert #define MAX_LEXEME (1024 + 1)	/* The maximum size of a lexeme */
382b15cb3dSCy Schubert char yytext[MAX_LEXEME];	/* Buffer for storing the input text/lexeme */
392b15cb3dSCy Schubert u_int32 conf_file_sum;		/* Simple sum of characters read */
402b15cb3dSCy Schubert 
41276da39aSCy Schubert static struct FILE_INFO * lex_stack = NULL;
422b15cb3dSCy Schubert 
432b15cb3dSCy Schubert 
442b15cb3dSCy Schubert 
452b15cb3dSCy Schubert /* CONSTANTS
462b15cb3dSCy Schubert  * ---------
472b15cb3dSCy Schubert  */
482b15cb3dSCy Schubert 
492b15cb3dSCy Schubert 
502b15cb3dSCy Schubert /* SCANNER GLOBAL VARIABLES
512b15cb3dSCy Schubert  * ------------------------
522b15cb3dSCy Schubert  */
532b15cb3dSCy Schubert const char special_chars[] = "{}(),;|=";
542b15cb3dSCy Schubert 
552b15cb3dSCy Schubert 
562b15cb3dSCy Schubert /* FUNCTIONS
572b15cb3dSCy Schubert  * ---------
582b15cb3dSCy Schubert  */
592b15cb3dSCy Schubert 
602b15cb3dSCy Schubert static int is_keyword(char *lexeme, follby *pfollowedby);
612b15cb3dSCy Schubert 
622b15cb3dSCy Schubert 
632b15cb3dSCy Schubert /*
642b15cb3dSCy Schubert  * keyword() - Return the keyword associated with token T_ identifier.
652b15cb3dSCy Schubert  *	       See also token_name() for the string-ized T_ identifier.
662b15cb3dSCy Schubert  *	       Example: keyword(T_Server) returns "server"
672b15cb3dSCy Schubert  *			token_name(T_Server) returns "T_Server"
682b15cb3dSCy Schubert  */
692b15cb3dSCy Schubert const char *
702b15cb3dSCy Schubert keyword(
712b15cb3dSCy Schubert 	int token
722b15cb3dSCy Schubert 	)
732b15cb3dSCy Schubert {
742b15cb3dSCy Schubert 	size_t i;
752b15cb3dSCy Schubert 	const char *text;
762b15cb3dSCy Schubert 
772b15cb3dSCy Schubert 	i = token - LOWEST_KEYWORD_ID;
782b15cb3dSCy Schubert 
792b15cb3dSCy Schubert 	if (i < COUNTOF(keyword_text))
802b15cb3dSCy Schubert 		text = keyword_text[i];
812b15cb3dSCy Schubert 	else
822b15cb3dSCy Schubert 		text = NULL;
832b15cb3dSCy Schubert 
842b15cb3dSCy Schubert 	return (text != NULL)
852b15cb3dSCy Schubert 		   ? text
862b15cb3dSCy Schubert 		   : "(keyword not found)";
872b15cb3dSCy Schubert }
882b15cb3dSCy Schubert 
892b15cb3dSCy Schubert 
90276da39aSCy Schubert /* FILE & STRING BUFFER INTERFACE
91276da39aSCy Schubert  * ------------------------------
92276da39aSCy Schubert  *
93276da39aSCy Schubert  * This set out as a couple of wrapper functions around the standard C
94276da39aSCy Schubert  * fgetc and ungetc functions in order to include positional
95276da39aSCy Schubert  * bookkeeping. Alas, this is no longer a good solution with nested
96276da39aSCy Schubert  * input files and the possibility to send configuration commands via
97276da39aSCy Schubert  * 'ntpdc' and 'ntpq'.
98276da39aSCy Schubert  *
99276da39aSCy Schubert  * Now there are a few functions to maintain a stack of nested input
100276da39aSCy Schubert  * sources (though nesting is only allowd for disk files) and from the
101276da39aSCy Schubert  * scanner / parser point of view there's no difference between both
102276da39aSCy Schubert  * types of sources.
103276da39aSCy Schubert  *
104276da39aSCy Schubert  * The 'fgetc()' / 'ungetc()' replacements now operate on a FILE_INFO
105276da39aSCy Schubert  * structure. Instead of trying different 'ungetc()' strategies for file
106276da39aSCy Schubert  * and buffer based parsing, we keep the backup char in our own
107276da39aSCy Schubert  * FILE_INFO structure. This is sufficient, as the parser does *not*
108276da39aSCy Schubert  * jump around via 'seek' or the like, and there's no need to
109276da39aSCy Schubert  * check/clear the backup store in other places than 'lex_getch()'.
1102b15cb3dSCy Schubert  */
1112b15cb3dSCy Schubert 
112276da39aSCy Schubert /*
113276da39aSCy Schubert  * Allocate an info structure and attach it to a file.
114276da39aSCy Schubert  *
115276da39aSCy Schubert  * Note: When 'mode' is NULL, then the INFO block will be set up to
116276da39aSCy Schubert  * contain a NULL file pointer, as suited for remote config command
117276da39aSCy Schubert  * parsing. Otherwise having a NULL file pointer is considered an error,
118276da39aSCy Schubert  * and a NULL info block pointer is returned to indicate failure!
119276da39aSCy Schubert  *
120276da39aSCy Schubert  * Note: We use a variable-sized structure to hold a copy of the file
121276da39aSCy Schubert  * name (or, more proper, the input source description). This is more
122276da39aSCy Schubert  * secure than keeping a reference to some other storage that might go
123276da39aSCy Schubert  * out of scope.
124276da39aSCy Schubert  */
125276da39aSCy Schubert static struct FILE_INFO *
126276da39aSCy Schubert lex_open(
1272b15cb3dSCy Schubert 	const char *path,
1282b15cb3dSCy Schubert 	const char *mode
1292b15cb3dSCy Schubert 	)
1302b15cb3dSCy Schubert {
131276da39aSCy Schubert 	struct FILE_INFO *stream;
132276da39aSCy Schubert 	size_t            nnambuf;
1332b15cb3dSCy Schubert 
134276da39aSCy Schubert 	nnambuf = strlen(path);
135276da39aSCy Schubert 	stream = emalloc_zero(sizeof(*stream) + nnambuf);
136276da39aSCy Schubert 	stream->curpos.nline = 1;
137276da39aSCy Schubert 	stream->backch = EOF;
138276da39aSCy Schubert 	/* copy name with memcpy -- trailing NUL already there! */
139276da39aSCy Schubert 	memcpy(stream->fname, path, nnambuf);
1402b15cb3dSCy Schubert 
141276da39aSCy Schubert 	if (NULL != mode) {
142276da39aSCy Schubert 		stream->fpi = fopen(path, mode);
143276da39aSCy Schubert 		if (NULL == stream->fpi) {
144276da39aSCy Schubert 			free(stream);
145276da39aSCy Schubert 			stream = NULL;
1462b15cb3dSCy Schubert 		}
147276da39aSCy Schubert 	}
148276da39aSCy Schubert 	return stream;
1492b15cb3dSCy Schubert }
1502b15cb3dSCy Schubert 
151276da39aSCy Schubert /* get next character from buffer or file. This will return any putback
152276da39aSCy Schubert  * character first; it will also make sure the last line is at least
153276da39aSCy Schubert  * virtually terminated with a '\n'.
154276da39aSCy Schubert  */
155276da39aSCy Schubert static int
156276da39aSCy Schubert lex_getch(
1572b15cb3dSCy Schubert 	struct FILE_INFO *stream
1582b15cb3dSCy Schubert 	)
1592b15cb3dSCy Schubert {
1602b15cb3dSCy Schubert 	int ch;
1612b15cb3dSCy Schubert 
162276da39aSCy Schubert 	if (NULL == stream || stream->force_eof)
163276da39aSCy Schubert 		return EOF;
1642b15cb3dSCy Schubert 
165276da39aSCy Schubert 	if (EOF != stream->backch) {
166276da39aSCy Schubert 		ch = stream->backch;
167276da39aSCy Schubert 		stream->backch = EOF;
168276da39aSCy Schubert 		if (stream->fpi)
169276da39aSCy Schubert 			conf_file_sum += ch;
170276da39aSCy Schubert 	} else if (stream->fpi) {
171276da39aSCy Schubert 		/* fetch next 7-bit ASCII char (or EOF) from file */
172276da39aSCy Schubert 		while ((ch = fgetc(stream->fpi)) != EOF && ch > SCHAR_MAX)
173276da39aSCy Schubert 			stream->curpos.ncol++;
1742b15cb3dSCy Schubert 		if (EOF != ch) {
175276da39aSCy Schubert 			conf_file_sum += ch;
176276da39aSCy Schubert 			stream->curpos.ncol++;
1772b15cb3dSCy Schubert 		}
178276da39aSCy Schubert 	} else {
179276da39aSCy Schubert 		/* fetch next 7-bit ASCII char from buffer */
180276da39aSCy Schubert 		const char * scan;
181276da39aSCy Schubert 		scan = &remote_config.buffer[remote_config.pos];
182276da39aSCy Schubert 		while ((ch = (u_char)*scan) > SCHAR_MAX) {
183276da39aSCy Schubert 			scan++;
184276da39aSCy Schubert 			stream->curpos.ncol++;
185276da39aSCy Schubert 		}
186276da39aSCy Schubert 		if ('\0' != ch) {
187276da39aSCy Schubert 			scan++;
188276da39aSCy Schubert 			stream->curpos.ncol++;
189276da39aSCy Schubert 		} else {
190276da39aSCy Schubert 			ch = EOF;
191276da39aSCy Schubert 		}
192276da39aSCy Schubert 		remote_config.pos = (int)(scan - remote_config.buffer);
193276da39aSCy Schubert 	}
194276da39aSCy Schubert 
195276da39aSCy Schubert 	/* If the last line ends without '\n', generate one. This
196276da39aSCy Schubert 	 * happens most likely on Windows, where editors often have a
197276da39aSCy Schubert 	 * sloppy concept of a line.
198276da39aSCy Schubert 	 */
199276da39aSCy Schubert 	if (EOF == ch && stream->curpos.ncol != 0)
200276da39aSCy Schubert 		ch = '\n';
201276da39aSCy Schubert 
202276da39aSCy Schubert 	/* update scan position tallies */
203276da39aSCy Schubert 	if (ch == '\n') {
204276da39aSCy Schubert 		stream->bakpos = stream->curpos;
205276da39aSCy Schubert 		stream->curpos.nline++;
206276da39aSCy Schubert 		stream->curpos.ncol = 0;
2072b15cb3dSCy Schubert 	}
2082b15cb3dSCy Schubert 
2092b15cb3dSCy Schubert 	return ch;
2102b15cb3dSCy Schubert }
2112b15cb3dSCy Schubert 
212276da39aSCy Schubert /* Note: lex_ungetch will fail to track more than one line of push
213276da39aSCy Schubert  * back. But since it guarantees only one char of back storage anyway,
214276da39aSCy Schubert  * this should not be a problem.
2152b15cb3dSCy Schubert  */
216276da39aSCy Schubert static int
217276da39aSCy Schubert lex_ungetch(
2182b15cb3dSCy Schubert 	int ch,
2192b15cb3dSCy Schubert 	struct FILE_INFO *stream
2202b15cb3dSCy Schubert 	)
2212b15cb3dSCy Schubert {
222276da39aSCy Schubert 	/* check preconditions */
223276da39aSCy Schubert 	if (NULL == stream || stream->force_eof)
224276da39aSCy Schubert 		return EOF;
225276da39aSCy Schubert 	if (EOF != stream->backch || EOF == ch)
226276da39aSCy Schubert 		return EOF;
227276da39aSCy Schubert 
228276da39aSCy Schubert 	/* keep for later reference and update checksum */
229276da39aSCy Schubert 	stream->backch = (u_char)ch;
230276da39aSCy Schubert 	if (stream->fpi)
231276da39aSCy Schubert 		conf_file_sum -= stream->backch;
232276da39aSCy Schubert 
233276da39aSCy Schubert 	/* update position */
234276da39aSCy Schubert 	if (stream->backch == '\n') {
235276da39aSCy Schubert 	    stream->curpos = stream->bakpos;
236276da39aSCy Schubert 	    stream->bakpos.ncol = -1;
2372b15cb3dSCy Schubert 	}
238276da39aSCy Schubert 	stream->curpos.ncol--;
239276da39aSCy Schubert 	return stream->backch;
2402b15cb3dSCy Schubert }
2412b15cb3dSCy Schubert 
242276da39aSCy Schubert /* dispose of an input structure. If the file pointer is not NULL, close
243276da39aSCy Schubert  * the file. This function does not check the result of 'fclose()'.
244276da39aSCy Schubert  */
245276da39aSCy Schubert static void
246276da39aSCy Schubert lex_close(
2472b15cb3dSCy Schubert 	struct FILE_INFO *stream
2482b15cb3dSCy Schubert 	)
2492b15cb3dSCy Schubert {
250276da39aSCy Schubert 	if (NULL != stream) {
251276da39aSCy Schubert 		if (NULL != stream->fpi)
252276da39aSCy Schubert 			fclose(stream->fpi);
2532b15cb3dSCy Schubert 		free(stream);
254276da39aSCy Schubert 	}
2552b15cb3dSCy Schubert }
2562b15cb3dSCy Schubert 
257276da39aSCy Schubert /* INPUT STACK
258276da39aSCy Schubert  * -----------
2592b15cb3dSCy Schubert  *
260276da39aSCy Schubert  * Nested input sources are a bit tricky at first glance. We deal with
261276da39aSCy Schubert  * this problem using a stack of input sources, that is, a forward
262276da39aSCy Schubert  * linked list of FILE_INFO structs.
263276da39aSCy Schubert  *
264276da39aSCy Schubert  * This stack is never empty during parsing; while an encounter with EOF
265276da39aSCy Schubert  * can and will remove nested input sources, removing the last element
266276da39aSCy Schubert  * in the stack will not work during parsing, and the EOF condition of
267276da39aSCy Schubert  * the outermost input file remains until the parser folds up.
2682b15cb3dSCy Schubert  */
2692b15cb3dSCy Schubert 
270276da39aSCy Schubert static struct FILE_INFO *
271276da39aSCy Schubert _drop_stack_do(
272276da39aSCy Schubert 	struct FILE_INFO * head
2732b15cb3dSCy Schubert 	)
2742b15cb3dSCy Schubert {
275276da39aSCy Schubert 	struct FILE_INFO * tail;
276276da39aSCy Schubert 	while (NULL != head) {
277276da39aSCy Schubert 		tail = head->st_next;
278276da39aSCy Schubert 		lex_close(head);
279276da39aSCy Schubert 		head = tail;
2802b15cb3dSCy Schubert 	}
281276da39aSCy Schubert 	return head;
2822b15cb3dSCy Schubert }
2832b15cb3dSCy Schubert 
284276da39aSCy Schubert 
285276da39aSCy Schubert 
286276da39aSCy Schubert /* Create a singleton input source on an empty lexer stack. This will
287276da39aSCy Schubert  * fail if there is already an input source, or if the underlying disk
288276da39aSCy Schubert  * file cannot be opened.
289276da39aSCy Schubert  *
290276da39aSCy Schubert  * Returns TRUE if a new input object was successfully created.
291276da39aSCy Schubert  */
292276da39aSCy Schubert int/*BOOL*/
293276da39aSCy Schubert lex_init_stack(
294276da39aSCy Schubert 	const char * path,
295276da39aSCy Schubert 	const char * mode
2962b15cb3dSCy Schubert 	)
2972b15cb3dSCy Schubert {
298276da39aSCy Schubert 	if (NULL != lex_stack || NULL == path)
299276da39aSCy Schubert 		return FALSE;
3002b15cb3dSCy Schubert 
301276da39aSCy Schubert 	lex_stack = lex_open(path, mode);
302276da39aSCy Schubert 	return (NULL != lex_stack);
3032b15cb3dSCy Schubert }
3042b15cb3dSCy Schubert 
305276da39aSCy Schubert /* This removes *all* input sources from the stack, leaving the head
306276da39aSCy Schubert  * pointer as NULL. Any attempt to parse in that state is likely to bomb
307276da39aSCy Schubert  * with segmentation faults or the like.
308276da39aSCy Schubert  *
309276da39aSCy Schubert  * In other words: Use this to clean up after parsing, and do not parse
310276da39aSCy Schubert  * anything until the next 'lex_init_stack()' succeeded.
311276da39aSCy Schubert  */
312276da39aSCy Schubert void
313276da39aSCy Schubert lex_drop_stack()
314276da39aSCy Schubert {
315276da39aSCy Schubert 	lex_stack = _drop_stack_do(lex_stack);
316276da39aSCy Schubert }
317276da39aSCy Schubert 
318276da39aSCy Schubert /* Flush the lexer input stack: This will nip all input objects on the
319276da39aSCy Schubert  * stack (but keeps the current top-of-stack) and marks the top-of-stack
320276da39aSCy Schubert  * as inactive. Any further calls to lex_getch yield only EOF, and it's
321276da39aSCy Schubert  * no longer possible to push something back.
322276da39aSCy Schubert  *
323276da39aSCy Schubert  * Returns TRUE if there is a head element (top-of-stack) that was not
324276da39aSCy Schubert  * in the force-eof mode before this call.
325276da39aSCy Schubert  */
326276da39aSCy Schubert int/*BOOL*/
327276da39aSCy Schubert lex_flush_stack()
328276da39aSCy Schubert {
329276da39aSCy Schubert 	int retv = FALSE;
330276da39aSCy Schubert 
331276da39aSCy Schubert 	if (NULL != lex_stack) {
332276da39aSCy Schubert 		retv = !lex_stack->force_eof;
333276da39aSCy Schubert 		lex_stack->force_eof = TRUE;
334276da39aSCy Schubert 		lex_stack->st_next = _drop_stack_do(
335276da39aSCy Schubert 					lex_stack->st_next);
336276da39aSCy Schubert 	}
337276da39aSCy Schubert 	return retv;
338276da39aSCy Schubert }
339276da39aSCy Schubert 
340276da39aSCy Schubert /* Push another file on the parsing stack. If the mode is NULL, create a
341276da39aSCy Schubert  * FILE_INFO suitable for in-memory parsing; otherwise, create a
342276da39aSCy Schubert  * FILE_INFO that is bound to a local/disc file. Note that 'path' must
343276da39aSCy Schubert  * not be NULL, or the function will fail.
344276da39aSCy Schubert  *
345276da39aSCy Schubert  * Returns TRUE if a new info record was pushed onto the stack.
346276da39aSCy Schubert  */
347276da39aSCy Schubert int/*BOOL*/ lex_push_file(
348276da39aSCy Schubert 	const char * path,
349276da39aSCy Schubert 	const char * mode
350276da39aSCy Schubert 	)
351276da39aSCy Schubert {
352276da39aSCy Schubert 	struct FILE_INFO * next = NULL;
353276da39aSCy Schubert 
354276da39aSCy Schubert 	if (NULL != path) {
355276da39aSCy Schubert 		next = lex_open(path, mode);
356276da39aSCy Schubert 		if (NULL != next) {
357276da39aSCy Schubert 			next->st_next = lex_stack;
358276da39aSCy Schubert 			lex_stack = next;
359276da39aSCy Schubert 		}
360276da39aSCy Schubert 	}
361276da39aSCy Schubert 	return (NULL != next);
362276da39aSCy Schubert }
363276da39aSCy Schubert 
364276da39aSCy Schubert /* Pop, close & free the top of the include stack, unless the stack
365276da39aSCy Schubert  * contains only a singleton input object. In that case the function
366276da39aSCy Schubert  * fails, because the parser does not expect the input stack to be
367276da39aSCy Schubert  * empty.
368276da39aSCy Schubert  *
369276da39aSCy Schubert  * Returns TRUE if an object was successfuly popped from the stack.
370276da39aSCy Schubert  */
371276da39aSCy Schubert int/*BOOL*/
372276da39aSCy Schubert lex_pop_file(void)
373276da39aSCy Schubert {
374276da39aSCy Schubert 	struct FILE_INFO * head = lex_stack;
375276da39aSCy Schubert 	struct FILE_INFO * tail = NULL;
376276da39aSCy Schubert 
377276da39aSCy Schubert 	if (NULL != head) {
378276da39aSCy Schubert 		tail = head->st_next;
379276da39aSCy Schubert 		if (NULL != tail) {
380276da39aSCy Schubert 			lex_stack = tail;
381276da39aSCy Schubert 			lex_close(head);
382276da39aSCy Schubert 		}
383276da39aSCy Schubert 	}
384276da39aSCy Schubert 	return (NULL != tail);
385276da39aSCy Schubert }
386276da39aSCy Schubert 
387276da39aSCy Schubert /* Get include nesting level. This currently loops over the stack and
388276da39aSCy Schubert  * counts elements; but since this is of concern only with an include
389276da39aSCy Schubert  * statement and the nesting depth has a small limit, there's no
390276da39aSCy Schubert  * bottleneck expected here.
391276da39aSCy Schubert  *
392276da39aSCy Schubert  * Returns the nesting level of includes, that is, the current depth of
393276da39aSCy Schubert  * the lexer input stack.
394276da39aSCy Schubert  *
395276da39aSCy Schubert  * Note:
396276da39aSCy Schubert  */
397276da39aSCy Schubert size_t
398276da39aSCy Schubert lex_level(void)
399276da39aSCy Schubert {
400276da39aSCy Schubert 	size_t            cnt = 0;
401276da39aSCy Schubert 	struct FILE_INFO *ipf = lex_stack;
402276da39aSCy Schubert 
403276da39aSCy Schubert 	while (NULL != ipf) {
404276da39aSCy Schubert 		cnt++;
405276da39aSCy Schubert 		ipf = ipf->st_next;
406276da39aSCy Schubert 	}
407276da39aSCy Schubert 	return cnt;
408276da39aSCy Schubert }
409276da39aSCy Schubert 
410276da39aSCy Schubert /* check if the current input is from a file */
411276da39aSCy Schubert int/*BOOL*/
412276da39aSCy Schubert lex_from_file(void)
413276da39aSCy Schubert {
414276da39aSCy Schubert 	return (NULL != lex_stack) && (NULL != lex_stack->fpi);
415276da39aSCy Schubert }
416276da39aSCy Schubert 
417276da39aSCy Schubert struct FILE_INFO *
418276da39aSCy Schubert lex_current()
419276da39aSCy Schubert {
420276da39aSCy Schubert 	/* this became so simple, it could be a macro. But then,
421276da39aSCy Schubert 	 * lex_stack needed to be global...
422276da39aSCy Schubert 	 */
423276da39aSCy Schubert 	return lex_stack;
424276da39aSCy Schubert }
4252b15cb3dSCy Schubert 
4262b15cb3dSCy Schubert 
4272b15cb3dSCy Schubert /* STATE MACHINES
4282b15cb3dSCy Schubert  * --------------
4292b15cb3dSCy Schubert  */
4302b15cb3dSCy Schubert 
4312b15cb3dSCy Schubert /* Keywords */
4322b15cb3dSCy Schubert static int
4332b15cb3dSCy Schubert is_keyword(
4342b15cb3dSCy Schubert 	char *lexeme,
4352b15cb3dSCy Schubert 	follby *pfollowedby
4362b15cb3dSCy Schubert 	)
4372b15cb3dSCy Schubert {
4382b15cb3dSCy Schubert 	follby fb;
4392b15cb3dSCy Schubert 	int curr_s;		/* current state index */
4402b15cb3dSCy Schubert 	int token;
4412b15cb3dSCy Schubert 	int i;
4422b15cb3dSCy Schubert 
4432b15cb3dSCy Schubert 	curr_s = SCANNER_INIT_S;
4442b15cb3dSCy Schubert 	token = 0;
4452b15cb3dSCy Schubert 
4462b15cb3dSCy Schubert 	for (i = 0; lexeme[i]; i++) {
4472b15cb3dSCy Schubert 		while (curr_s && (lexeme[i] != SS_CH(sst[curr_s])))
4482b15cb3dSCy Schubert 			curr_s = SS_OTHER_N(sst[curr_s]);
4492b15cb3dSCy Schubert 
4502b15cb3dSCy Schubert 		if (curr_s && (lexeme[i] == SS_CH(sst[curr_s]))) {
4512b15cb3dSCy Schubert 			if ('\0' == lexeme[i + 1]
4522b15cb3dSCy Schubert 			    && FOLLBY_NON_ACCEPTING
4532b15cb3dSCy Schubert 			       != SS_FB(sst[curr_s])) {
4542b15cb3dSCy Schubert 				fb = SS_FB(sst[curr_s]);
4552b15cb3dSCy Schubert 				*pfollowedby = fb;
4562b15cb3dSCy Schubert 				token = curr_s;
4572b15cb3dSCy Schubert 				break;
4582b15cb3dSCy Schubert 			}
4592b15cb3dSCy Schubert 			curr_s = SS_MATCH_N(sst[curr_s]);
4602b15cb3dSCy Schubert 		} else
4612b15cb3dSCy Schubert 			break;
4622b15cb3dSCy Schubert 	}
4632b15cb3dSCy Schubert 
4642b15cb3dSCy Schubert 	return token;
4652b15cb3dSCy Schubert }
4662b15cb3dSCy Schubert 
4672b15cb3dSCy Schubert 
4682b15cb3dSCy Schubert /* Integer */
4692b15cb3dSCy Schubert static int
4702b15cb3dSCy Schubert is_integer(
4712b15cb3dSCy Schubert 	char *lexeme
4722b15cb3dSCy Schubert 	)
4732b15cb3dSCy Schubert {
4742b15cb3dSCy Schubert 	int	i;
4752b15cb3dSCy Schubert 	int	is_neg;
4762b15cb3dSCy Schubert 	u_int	u_val;
4772b15cb3dSCy Schubert 
4782b15cb3dSCy Schubert 	i = 0;
4792b15cb3dSCy Schubert 
4802b15cb3dSCy Schubert 	/* Allow a leading minus sign */
4812b15cb3dSCy Schubert 	if (lexeme[i] == '-') {
4822b15cb3dSCy Schubert 		i++;
4832b15cb3dSCy Schubert 		is_neg = TRUE;
4842b15cb3dSCy Schubert 	} else {
4852b15cb3dSCy Schubert 		is_neg = FALSE;
4862b15cb3dSCy Schubert 	}
4872b15cb3dSCy Schubert 
4882b15cb3dSCy Schubert 	/* Check that all the remaining characters are digits */
4892b15cb3dSCy Schubert 	for (; lexeme[i] != '\0'; i++) {
490276da39aSCy Schubert 		if (!isdigit((u_char)lexeme[i]))
4912b15cb3dSCy Schubert 			return FALSE;
4922b15cb3dSCy Schubert 	}
4932b15cb3dSCy Schubert 
4942b15cb3dSCy Schubert 	if (is_neg)
4952b15cb3dSCy Schubert 		return TRUE;
4962b15cb3dSCy Schubert 
4972b15cb3dSCy Schubert 	/* Reject numbers that fit in unsigned but not in signed int */
4982b15cb3dSCy Schubert 	if (1 == sscanf(lexeme, "%u", &u_val))
4992b15cb3dSCy Schubert 		return (u_val <= INT_MAX);
5002b15cb3dSCy Schubert 	else
5012b15cb3dSCy Schubert 		return FALSE;
5022b15cb3dSCy Schubert }
5032b15cb3dSCy Schubert 
5042b15cb3dSCy Schubert 
5052b15cb3dSCy Schubert /* U_int -- assumes is_integer() has returned FALSE */
5062b15cb3dSCy Schubert static int
5072b15cb3dSCy Schubert is_u_int(
5082b15cb3dSCy Schubert 	char *lexeme
5092b15cb3dSCy Schubert 	)
5102b15cb3dSCy Schubert {
5112b15cb3dSCy Schubert 	int	i;
5122b15cb3dSCy Schubert 	int	is_hex;
5132b15cb3dSCy Schubert 
5142b15cb3dSCy Schubert 	i = 0;
515276da39aSCy Schubert 	if ('0' == lexeme[i] && 'x' == tolower((u_char)lexeme[i + 1])) {
5162b15cb3dSCy Schubert 		i += 2;
5172b15cb3dSCy Schubert 		is_hex = TRUE;
5182b15cb3dSCy Schubert 	} else {
5192b15cb3dSCy Schubert 		is_hex = FALSE;
5202b15cb3dSCy Schubert 	}
5212b15cb3dSCy Schubert 
5222b15cb3dSCy Schubert 	/* Check that all the remaining characters are digits */
5232b15cb3dSCy Schubert 	for (; lexeme[i] != '\0'; i++) {
524276da39aSCy Schubert 		if (is_hex && !isxdigit((u_char)lexeme[i]))
5252b15cb3dSCy Schubert 			return FALSE;
526276da39aSCy Schubert 		if (!is_hex && !isdigit((u_char)lexeme[i]))
5272b15cb3dSCy Schubert 			return FALSE;
5282b15cb3dSCy Schubert 	}
5292b15cb3dSCy Schubert 
5302b15cb3dSCy Schubert 	return TRUE;
5312b15cb3dSCy Schubert }
5322b15cb3dSCy Schubert 
5332b15cb3dSCy Schubert 
5342b15cb3dSCy Schubert /* Double */
5352b15cb3dSCy Schubert static int
5362b15cb3dSCy Schubert is_double(
5372b15cb3dSCy Schubert 	char *lexeme
5382b15cb3dSCy Schubert 	)
5392b15cb3dSCy Schubert {
5402b15cb3dSCy Schubert 	u_int num_digits = 0;  /* Number of digits read */
5412b15cb3dSCy Schubert 	u_int i;
5422b15cb3dSCy Schubert 
5432b15cb3dSCy Schubert 	i = 0;
5442b15cb3dSCy Schubert 
5452b15cb3dSCy Schubert 	/* Check for an optional '+' or '-' */
5462b15cb3dSCy Schubert 	if ('+' == lexeme[i] || '-' == lexeme[i])
5472b15cb3dSCy Schubert 		i++;
5482b15cb3dSCy Schubert 
5492b15cb3dSCy Schubert 	/* Read the integer part */
550276da39aSCy Schubert 	for (; lexeme[i] && isdigit((u_char)lexeme[i]); i++)
5512b15cb3dSCy Schubert 		num_digits++;
5522b15cb3dSCy Schubert 
5532b15cb3dSCy Schubert 	/* Check for the optional decimal point */
5542b15cb3dSCy Schubert 	if ('.' == lexeme[i]) {
5552b15cb3dSCy Schubert 		i++;
5562b15cb3dSCy Schubert 		/* Check for any digits after the decimal point */
557276da39aSCy Schubert 		for (; lexeme[i] && isdigit((u_char)lexeme[i]); i++)
5582b15cb3dSCy Schubert 			num_digits++;
5592b15cb3dSCy Schubert 	}
5602b15cb3dSCy Schubert 
5612b15cb3dSCy Schubert 	/*
5622b15cb3dSCy Schubert 	 * The number of digits in both the decimal part and the
5632b15cb3dSCy Schubert 	 * fraction part must not be zero at this point
5642b15cb3dSCy Schubert 	 */
5652b15cb3dSCy Schubert 	if (!num_digits)
5662b15cb3dSCy Schubert 		return 0;
5672b15cb3dSCy Schubert 
5682b15cb3dSCy Schubert 	/* Check if we are done */
5692b15cb3dSCy Schubert 	if (!lexeme[i])
5702b15cb3dSCy Schubert 		return 1;
5712b15cb3dSCy Schubert 
5722b15cb3dSCy Schubert 	/* There is still more input, read the exponent */
573276da39aSCy Schubert 	if ('e' == tolower((u_char)lexeme[i]))
5742b15cb3dSCy Schubert 		i++;
5752b15cb3dSCy Schubert 	else
5762b15cb3dSCy Schubert 		return 0;
5772b15cb3dSCy Schubert 
5782b15cb3dSCy Schubert 	/* Read an optional Sign */
5792b15cb3dSCy Schubert 	if ('+' == lexeme[i] || '-' == lexeme[i])
5802b15cb3dSCy Schubert 		i++;
5812b15cb3dSCy Schubert 
5822b15cb3dSCy Schubert 	/* Now read the exponent part */
583276da39aSCy Schubert 	while (lexeme[i] && isdigit((u_char)lexeme[i]))
5842b15cb3dSCy Schubert 		i++;
5852b15cb3dSCy Schubert 
5862b15cb3dSCy Schubert 	/* Check if we are done */
5872b15cb3dSCy Schubert 	if (!lexeme[i])
5882b15cb3dSCy Schubert 		return 1;
5892b15cb3dSCy Schubert 	else
5902b15cb3dSCy Schubert 		return 0;
5912b15cb3dSCy Schubert }
5922b15cb3dSCy Schubert 
5932b15cb3dSCy Schubert 
5942b15cb3dSCy Schubert /* is_special() - Test whether a character is a token */
5952b15cb3dSCy Schubert static inline int
5962b15cb3dSCy Schubert is_special(
5972b15cb3dSCy Schubert 	int ch
5982b15cb3dSCy Schubert 	)
5992b15cb3dSCy Schubert {
6002b15cb3dSCy Schubert 	return strchr(special_chars, ch) != NULL;
6012b15cb3dSCy Schubert }
6022b15cb3dSCy Schubert 
6032b15cb3dSCy Schubert 
6042b15cb3dSCy Schubert static int
6052b15cb3dSCy Schubert is_EOC(
6062b15cb3dSCy Schubert 	int ch
6072b15cb3dSCy Schubert 	)
6082b15cb3dSCy Schubert {
6092b15cb3dSCy Schubert 	if ((old_config_style && (ch == '\n')) ||
6102b15cb3dSCy Schubert 	    (!old_config_style && (ch == ';')))
6112b15cb3dSCy Schubert 		return 1;
6122b15cb3dSCy Schubert 	return 0;
6132b15cb3dSCy Schubert }
6142b15cb3dSCy Schubert 
6152b15cb3dSCy Schubert 
6162b15cb3dSCy Schubert char *
6172b15cb3dSCy Schubert quote_if_needed(char *str)
6182b15cb3dSCy Schubert {
6192b15cb3dSCy Schubert 	char *ret;
6202b15cb3dSCy Schubert 	size_t len;
6212b15cb3dSCy Schubert 	size_t octets;
6222b15cb3dSCy Schubert 
6232b15cb3dSCy Schubert 	len = strlen(str);
6242b15cb3dSCy Schubert 	octets = len + 2 + 1;
6252b15cb3dSCy Schubert 	ret = emalloc(octets);
6262b15cb3dSCy Schubert 	if ('"' != str[0]
6272b15cb3dSCy Schubert 	    && (strcspn(str, special_chars) < len
6282b15cb3dSCy Schubert 		|| strchr(str, ' ') != NULL)) {
6292b15cb3dSCy Schubert 		snprintf(ret, octets, "\"%s\"", str);
6302b15cb3dSCy Schubert 	} else
6312b15cb3dSCy Schubert 		strlcpy(ret, str, octets);
6322b15cb3dSCy Schubert 
6332b15cb3dSCy Schubert 	return ret;
6342b15cb3dSCy Schubert }
6352b15cb3dSCy Schubert 
6362b15cb3dSCy Schubert 
6372b15cb3dSCy Schubert static int
6382b15cb3dSCy Schubert create_string_token(
6392b15cb3dSCy Schubert 	char *lexeme
6402b15cb3dSCy Schubert 	)
6412b15cb3dSCy Schubert {
6422b15cb3dSCy Schubert 	char *pch;
6432b15cb3dSCy Schubert 
6442b15cb3dSCy Schubert 	/*
6452b15cb3dSCy Schubert 	 * ignore end of line whitespace
6462b15cb3dSCy Schubert 	 */
6472b15cb3dSCy Schubert 	pch = lexeme;
648276da39aSCy Schubert 	while (*pch && isspace((u_char)*pch))
6492b15cb3dSCy Schubert 		pch++;
6502b15cb3dSCy Schubert 
6512b15cb3dSCy Schubert 	if (!*pch) {
6522b15cb3dSCy Schubert 		yylval.Integer = T_EOC;
6532b15cb3dSCy Schubert 		return yylval.Integer;
6542b15cb3dSCy Schubert 	}
6552b15cb3dSCy Schubert 
6562b15cb3dSCy Schubert 	yylval.String = estrdup(lexeme);
6572b15cb3dSCy Schubert 	return T_String;
6582b15cb3dSCy Schubert }
6592b15cb3dSCy Schubert 
6602b15cb3dSCy Schubert 
6612b15cb3dSCy Schubert /*
6622b15cb3dSCy Schubert  * yylex() - function that does the actual scanning.
6632b15cb3dSCy Schubert  * Bison expects this function to be called yylex and for it to take no
6642b15cb3dSCy Schubert  * input and return an int.
6652b15cb3dSCy Schubert  * Conceptually yylex "returns" yylval as well as the actual return
6662b15cb3dSCy Schubert  * value representing the token or type.
6672b15cb3dSCy Schubert  */
6682b15cb3dSCy Schubert int
669276da39aSCy Schubert yylex(void)
6702b15cb3dSCy Schubert {
6712b15cb3dSCy Schubert 	static follby	followedby = FOLLBY_TOKEN;
672*68ba7e87SXin LI 	size_t		i;
6732b15cb3dSCy Schubert 	int		instring;
6742b15cb3dSCy Schubert 	int		yylval_was_set;
6752b15cb3dSCy Schubert 	int		converted;
6762b15cb3dSCy Schubert 	int		token;		/* The return value */
6772b15cb3dSCy Schubert 	int		ch;
6782b15cb3dSCy Schubert 
6792b15cb3dSCy Schubert 	instring = FALSE;
6802b15cb3dSCy Schubert 	yylval_was_set = FALSE;
6812b15cb3dSCy Schubert 
6822b15cb3dSCy Schubert 	do {
6832b15cb3dSCy Schubert 		/* Ignore whitespace at the beginning */
684276da39aSCy Schubert 		while (EOF != (ch = lex_getch(lex_stack)) &&
6852b15cb3dSCy Schubert 		       isspace(ch) &&
6862b15cb3dSCy Schubert 		       !is_EOC(ch))
687276da39aSCy Schubert 
6882b15cb3dSCy Schubert 			; /* Null Statement */
6892b15cb3dSCy Schubert 
6902b15cb3dSCy Schubert 		if (EOF == ch) {
6912b15cb3dSCy Schubert 
692276da39aSCy Schubert 			if ( ! lex_pop_file())
6932b15cb3dSCy Schubert 				return 0;
6942b15cb3dSCy Schubert 			token = T_EOC;
6952b15cb3dSCy Schubert 			goto normal_return;
6962b15cb3dSCy Schubert 
6972b15cb3dSCy Schubert 		} else if (is_EOC(ch)) {
6982b15cb3dSCy Schubert 
6992b15cb3dSCy Schubert 			/* end FOLLBY_STRINGS_TO_EOC effect */
7002b15cb3dSCy Schubert 			followedby = FOLLBY_TOKEN;
7012b15cb3dSCy Schubert 			token = T_EOC;
7022b15cb3dSCy Schubert 			goto normal_return;
7032b15cb3dSCy Schubert 
7042b15cb3dSCy Schubert 		} else if (is_special(ch) && FOLLBY_TOKEN == followedby) {
7052b15cb3dSCy Schubert 			/* special chars are their own token values */
7062b15cb3dSCy Schubert 			token = ch;
7072b15cb3dSCy Schubert 			/*
7082b15cb3dSCy Schubert 			 * '=' outside simulator configuration implies
7092b15cb3dSCy Schubert 			 * a single string following as in:
7102b15cb3dSCy Schubert 			 * setvar Owner = "The Boss" default
7112b15cb3dSCy Schubert 			 */
7122b15cb3dSCy Schubert 			if ('=' == ch && old_config_style)
7132b15cb3dSCy Schubert 				followedby = FOLLBY_STRING;
7142b15cb3dSCy Schubert 			yytext[0] = (char)ch;
7152b15cb3dSCy Schubert 			yytext[1] = '\0';
7162b15cb3dSCy Schubert 			goto normal_return;
7172b15cb3dSCy Schubert 		} else
718276da39aSCy Schubert 			lex_ungetch(ch, lex_stack);
7192b15cb3dSCy Schubert 
7202b15cb3dSCy Schubert 		/* save the position of start of the token */
721276da39aSCy Schubert 		lex_stack->tokpos = lex_stack->curpos;
7222b15cb3dSCy Schubert 
7232b15cb3dSCy Schubert 		/* Read in the lexeme */
7242b15cb3dSCy Schubert 		i = 0;
725276da39aSCy Schubert 		while (EOF != (ch = lex_getch(lex_stack))) {
7262b15cb3dSCy Schubert 
7272b15cb3dSCy Schubert 			yytext[i] = (char)ch;
7282b15cb3dSCy Schubert 
7292b15cb3dSCy Schubert 			/* Break on whitespace or a special character */
7302b15cb3dSCy Schubert 			if (isspace(ch) || is_EOC(ch)
7312b15cb3dSCy Schubert 			    || '"' == ch
7322b15cb3dSCy Schubert 			    || (FOLLBY_TOKEN == followedby
7332b15cb3dSCy Schubert 				&& is_special(ch)))
7342b15cb3dSCy Schubert 				break;
7352b15cb3dSCy Schubert 
7362b15cb3dSCy Schubert 			/* Read the rest of the line on reading a start
7372b15cb3dSCy Schubert 			   of comment character */
7382b15cb3dSCy Schubert 			if ('#' == ch) {
739276da39aSCy Schubert 				while (EOF != (ch = lex_getch(lex_stack))
7402b15cb3dSCy Schubert 				       && '\n' != ch)
7412b15cb3dSCy Schubert 					; /* Null Statement */
7422b15cb3dSCy Schubert 				break;
7432b15cb3dSCy Schubert 			}
7442b15cb3dSCy Schubert 
7452b15cb3dSCy Schubert 			i++;
7462b15cb3dSCy Schubert 			if (i >= COUNTOF(yytext))
7472b15cb3dSCy Schubert 				goto lex_too_long;
7482b15cb3dSCy Schubert 		}
7492b15cb3dSCy Schubert 		/* Pick up all of the string inside between " marks, to
7502b15cb3dSCy Schubert 		 * end of line.  If we make it to EOL without a
7512b15cb3dSCy Schubert 		 * terminating " assume it for them.
7522b15cb3dSCy Schubert 		 *
7532b15cb3dSCy Schubert 		 * XXX - HMS: I'm not sure we want to assume the closing "
7542b15cb3dSCy Schubert 		 */
7552b15cb3dSCy Schubert 		if ('"' == ch) {
7562b15cb3dSCy Schubert 			instring = TRUE;
757276da39aSCy Schubert 			while (EOF != (ch = lex_getch(lex_stack)) &&
7582b15cb3dSCy Schubert 			       ch != '"' && ch != '\n') {
7592b15cb3dSCy Schubert 				yytext[i++] = (char)ch;
7602b15cb3dSCy Schubert 				if (i >= COUNTOF(yytext))
7612b15cb3dSCy Schubert 					goto lex_too_long;
7622b15cb3dSCy Schubert 			}
7632b15cb3dSCy Schubert 			/*
7642b15cb3dSCy Schubert 			 * yytext[i] will be pushed back as not part of
7652b15cb3dSCy Schubert 			 * this lexeme, but any closing quote should
7662b15cb3dSCy Schubert 			 * not be pushed back, so we read another char.
7672b15cb3dSCy Schubert 			 */
7682b15cb3dSCy Schubert 			if ('"' == ch)
769276da39aSCy Schubert 				ch = lex_getch(lex_stack);
7702b15cb3dSCy Schubert 		}
7712b15cb3dSCy Schubert 		/* Pushback the last character read that is not a part
772276da39aSCy Schubert 		 * of this lexeme. This fails silently if ch is EOF,
773276da39aSCy Schubert 		 * but then the EOF condition persists and is handled on
774276da39aSCy Schubert 		 * the next turn by the include stack mechanism.
7752b15cb3dSCy Schubert 		 */
776276da39aSCy Schubert 		lex_ungetch(ch, lex_stack);
777276da39aSCy Schubert 
7782b15cb3dSCy Schubert 		yytext[i] = '\0';
7792b15cb3dSCy Schubert 	} while (i == 0);
7802b15cb3dSCy Schubert 
7812b15cb3dSCy Schubert 	/* Now return the desired token */
7822b15cb3dSCy Schubert 
7832b15cb3dSCy Schubert 	/* First make sure that the parser is *not* expecting a string
7842b15cb3dSCy Schubert 	 * as the next token (based on the previous token that was
7852b15cb3dSCy Schubert 	 * returned) and that we haven't read a string.
7862b15cb3dSCy Schubert 	 */
7872b15cb3dSCy Schubert 
7882b15cb3dSCy Schubert 	if (followedby == FOLLBY_TOKEN && !instring) {
7892b15cb3dSCy Schubert 		token = is_keyword(yytext, &followedby);
7902b15cb3dSCy Schubert 		if (token) {
7912b15cb3dSCy Schubert 			/*
7922b15cb3dSCy Schubert 			 * T_Server is exceptional as it forces the
7932b15cb3dSCy Schubert 			 * following token to be a string in the
7942b15cb3dSCy Schubert 			 * non-simulator parts of the configuration,
7952b15cb3dSCy Schubert 			 * but in the simulator configuration section,
7962b15cb3dSCy Schubert 			 * "server" is followed by "=" which must be
7972b15cb3dSCy Schubert 			 * recognized as a token not a string.
7982b15cb3dSCy Schubert 			 */
7992b15cb3dSCy Schubert 			if (T_Server == token && !old_config_style)
8002b15cb3dSCy Schubert 				followedby = FOLLBY_TOKEN;
8012b15cb3dSCy Schubert 			goto normal_return;
8022b15cb3dSCy Schubert 		} else if (is_integer(yytext)) {
8032b15cb3dSCy Schubert 			yylval_was_set = TRUE;
8042b15cb3dSCy Schubert 			errno = 0;
8052b15cb3dSCy Schubert 			if ((yylval.Integer = strtol(yytext, NULL, 10)) == 0
8062b15cb3dSCy Schubert 			    && ((errno == EINVAL) || (errno == ERANGE))) {
8072b15cb3dSCy Schubert 				msyslog(LOG_ERR,
8082b15cb3dSCy Schubert 					"Integer cannot be represented: %s",
8092b15cb3dSCy Schubert 					yytext);
810276da39aSCy Schubert 				if (lex_from_file()) {
8112b15cb3dSCy Schubert 					exit(1);
8122b15cb3dSCy Schubert 				} else {
8132b15cb3dSCy Schubert 					/* force end of parsing */
8142b15cb3dSCy Schubert 					yylval.Integer = 0;
8152b15cb3dSCy Schubert 					return 0;
8162b15cb3dSCy Schubert 				}
8172b15cb3dSCy Schubert 			}
8182b15cb3dSCy Schubert 			token = T_Integer;
8192b15cb3dSCy Schubert 			goto normal_return;
8202b15cb3dSCy Schubert 		} else if (is_u_int(yytext)) {
8212b15cb3dSCy Schubert 			yylval_was_set = TRUE;
8222b15cb3dSCy Schubert 			if ('0' == yytext[0] &&
823276da39aSCy Schubert 			    'x' == tolower((unsigned long)yytext[1]))
8242b15cb3dSCy Schubert 				converted = sscanf(&yytext[2], "%x",
8252b15cb3dSCy Schubert 						   &yylval.U_int);
8262b15cb3dSCy Schubert 			else
8272b15cb3dSCy Schubert 				converted = sscanf(yytext, "%u",
8282b15cb3dSCy Schubert 						   &yylval.U_int);
8292b15cb3dSCy Schubert 			if (1 != converted) {
8302b15cb3dSCy Schubert 				msyslog(LOG_ERR,
8312b15cb3dSCy Schubert 					"U_int cannot be represented: %s",
8322b15cb3dSCy Schubert 					yytext);
833276da39aSCy Schubert 				if (lex_from_file()) {
8342b15cb3dSCy Schubert 					exit(1);
8352b15cb3dSCy Schubert 				} else {
8362b15cb3dSCy Schubert 					/* force end of parsing */
8372b15cb3dSCy Schubert 					yylval.Integer = 0;
8382b15cb3dSCy Schubert 					return 0;
8392b15cb3dSCy Schubert 				}
8402b15cb3dSCy Schubert 			}
8412b15cb3dSCy Schubert 			token = T_U_int;
8422b15cb3dSCy Schubert 			goto normal_return;
8432b15cb3dSCy Schubert 		} else if (is_double(yytext)) {
8442b15cb3dSCy Schubert 			yylval_was_set = TRUE;
8452b15cb3dSCy Schubert 			errno = 0;
8462b15cb3dSCy Schubert 			if ((yylval.Double = atof(yytext)) == 0 && errno == ERANGE) {
8472b15cb3dSCy Schubert 				msyslog(LOG_ERR,
8482b15cb3dSCy Schubert 					"Double too large to represent: %s",
8492b15cb3dSCy Schubert 					yytext);
8502b15cb3dSCy Schubert 				exit(1);
8512b15cb3dSCy Schubert 			} else {
8522b15cb3dSCy Schubert 				token = T_Double;
8532b15cb3dSCy Schubert 				goto normal_return;
8542b15cb3dSCy Schubert 			}
8552b15cb3dSCy Schubert 		} else {
8562b15cb3dSCy Schubert 			/* Default: Everything is a string */
8572b15cb3dSCy Schubert 			yylval_was_set = TRUE;
8582b15cb3dSCy Schubert 			token = create_string_token(yytext);
8592b15cb3dSCy Schubert 			goto normal_return;
8602b15cb3dSCy Schubert 		}
8612b15cb3dSCy Schubert 	}
8622b15cb3dSCy Schubert 
8632b15cb3dSCy Schubert 	/*
8642b15cb3dSCy Schubert 	 * Either followedby is not FOLLBY_TOKEN or this lexeme is part
8652b15cb3dSCy Schubert 	 * of a string.  Hence, we need to return T_String.
8662b15cb3dSCy Schubert 	 *
8672b15cb3dSCy Schubert 	 * _Except_ we might have a -4 or -6 flag on a an association
8682b15cb3dSCy Schubert 	 * configuration line (server, peer, pool, etc.).
8692b15cb3dSCy Schubert 	 *
8702b15cb3dSCy Schubert 	 * This is a terrible hack, but the grammar is ambiguous so we
8712b15cb3dSCy Schubert 	 * don't have a choice.  [SK]
8722b15cb3dSCy Schubert 	 *
8732b15cb3dSCy Schubert 	 * The ambiguity is in the keyword scanner, not ntp_parser.y.
8742b15cb3dSCy Schubert 	 * We do not require server addresses be quoted in ntp.conf,
8752b15cb3dSCy Schubert 	 * complicating the scanner's job.  To avoid trying (and
8762b15cb3dSCy Schubert 	 * failing) to match an IP address or DNS name to a keyword,
8772b15cb3dSCy Schubert 	 * the association keywords use FOLLBY_STRING in the keyword
8782b15cb3dSCy Schubert 	 * table, which tells the scanner to force the next token to be
8792b15cb3dSCy Schubert 	 * a T_String, so it does not try to match a keyword but rather
8802b15cb3dSCy Schubert 	 * expects a string when -4/-6 modifiers to server, peer, etc.
8812b15cb3dSCy Schubert 	 * are encountered.
8822b15cb3dSCy Schubert 	 * restrict -4 and restrict -6 parsing works correctly without
8832b15cb3dSCy Schubert 	 * this hack, as restrict uses FOLLBY_TOKEN.  [DH]
8842b15cb3dSCy Schubert 	 */
8852b15cb3dSCy Schubert 	if ('-' == yytext[0]) {
8862b15cb3dSCy Schubert 		if ('4' == yytext[1]) {
8872b15cb3dSCy Schubert 			token = T_Ipv4_flag;
8882b15cb3dSCy Schubert 			goto normal_return;
8892b15cb3dSCy Schubert 		} else if ('6' == yytext[1]) {
8902b15cb3dSCy Schubert 			token = T_Ipv6_flag;
8912b15cb3dSCy Schubert 			goto normal_return;
8922b15cb3dSCy Schubert 		}
8932b15cb3dSCy Schubert 	}
8942b15cb3dSCy Schubert 
8952b15cb3dSCy Schubert 	instring = FALSE;
8962b15cb3dSCy Schubert 	if (FOLLBY_STRING == followedby)
8972b15cb3dSCy Schubert 		followedby = FOLLBY_TOKEN;
8982b15cb3dSCy Schubert 
8992b15cb3dSCy Schubert 	yylval_was_set = TRUE;
9002b15cb3dSCy Schubert 	token = create_string_token(yytext);
9012b15cb3dSCy Schubert 
9022b15cb3dSCy Schubert normal_return:
9032b15cb3dSCy Schubert 	if (T_EOC == token)
9042b15cb3dSCy Schubert 		DPRINTF(4,("\t<end of command>\n"));
9052b15cb3dSCy Schubert 	else
9062b15cb3dSCy Schubert 		DPRINTF(4, ("yylex: lexeme '%s' -> %s\n", yytext,
9072b15cb3dSCy Schubert 			    token_name(token)));
9082b15cb3dSCy Schubert 
9092b15cb3dSCy Schubert 	if (!yylval_was_set)
9102b15cb3dSCy Schubert 		yylval.Integer = token;
9112b15cb3dSCy Schubert 
9122b15cb3dSCy Schubert 	return token;
9132b15cb3dSCy Schubert 
9142b15cb3dSCy Schubert lex_too_long:
9152b15cb3dSCy Schubert 	yytext[min(sizeof(yytext) - 1, 50)] = 0;
9162b15cb3dSCy Schubert 	msyslog(LOG_ERR,
9172b15cb3dSCy Schubert 		"configuration item on line %d longer than limit of %lu, began with '%s'",
918276da39aSCy Schubert 		lex_stack->curpos.nline, (u_long)min(sizeof(yytext) - 1, 50),
9192b15cb3dSCy Schubert 		yytext);
9202b15cb3dSCy Schubert 
9212b15cb3dSCy Schubert 	/*
9222b15cb3dSCy Schubert 	 * If we hit the length limit reading the startup configuration
9232b15cb3dSCy Schubert 	 * file, abort.
9242b15cb3dSCy Schubert 	 */
925276da39aSCy Schubert 	if (lex_from_file())
9262b15cb3dSCy Schubert 		exit(sizeof(yytext) - 1);
9272b15cb3dSCy Schubert 
9282b15cb3dSCy Schubert 	/*
9292b15cb3dSCy Schubert 	 * If it's runtime configuration via ntpq :config treat it as
9302b15cb3dSCy Schubert 	 * if the configuration text ended before the too-long lexeme,
9312b15cb3dSCy Schubert 	 * hostname, or string.
9322b15cb3dSCy Schubert 	 */
9332b15cb3dSCy Schubert 	yylval.Integer = 0;
9342b15cb3dSCy Schubert 	return 0;
9352b15cb3dSCy Schubert }
936