xref: /netbsd-src/external/bsd/ntp/dist/ntpd/ntp_scanner.c (revision eabc0478de71e4e011a5b4e0392741e01d491794)
1*eabc0478Schristos /*	$NetBSD: ntp_scanner.c,v 1.15 2024/08/18 20:47:18 christos Exp $	*/
2abb0f93cSkardel 
3abb0f93cSkardel 
4abb0f93cSkardel /* ntp_scanner.c
5abb0f93cSkardel  *
6abb0f93cSkardel  * The source code for a simple lexical analyzer.
7abb0f93cSkardel  *
8abb0f93cSkardel  * Written By:	Sachin Kamboj
9abb0f93cSkardel  *		University of Delaware
10abb0f93cSkardel  *		Newark, DE 19711
11abb0f93cSkardel  * Copyright (c) 2006
12abb0f93cSkardel  */
13abb0f93cSkardel 
14abb0f93cSkardel #ifdef HAVE_CONFIG_H
15abb0f93cSkardel # include <config.h>
16abb0f93cSkardel #endif
17abb0f93cSkardel 
18abb0f93cSkardel #include <stdio.h>
19abb0f93cSkardel #include <ctype.h>
20abb0f93cSkardel #include <stdlib.h>
21abb0f93cSkardel #include <errno.h>
22abb0f93cSkardel #include <string.h>
23abb0f93cSkardel 
242950cc38Schristos #include "ntpd.h"
25abb0f93cSkardel #include "ntp_config.h"
26abb0f93cSkardel #include "ntpsim.h"
27abb0f93cSkardel #include "ntp_scanner.h"
28abb0f93cSkardel #include "ntp_parser.h"
29abb0f93cSkardel 
30abb0f93cSkardel /* ntp_keyword.h declares finite state machine and token text */
31abb0f93cSkardel #include "ntp_keyword.h"
32abb0f93cSkardel 
33abb0f93cSkardel 
34abb0f93cSkardel 
35abb0f93cSkardel /* SCANNER GLOBAL VARIABLES
36abb0f93cSkardel  * ------------------------
37abb0f93cSkardel  */
38abb0f93cSkardel 
39*eabc0478Schristos #define MAX_LEXEME	128	/* The maximum size of a lexeme */
40abb0f93cSkardel char yytext[MAX_LEXEME];	/* Buffer for storing the input text/lexeme */
412950cc38Schristos u_int32 conf_file_sum;		/* Simple sum of characters read */
42abb0f93cSkardel 
435d681e99Schristos static struct FILE_INFO * lex_stack = NULL;
44abb0f93cSkardel 
45abb0f93cSkardel 
46abb0f93cSkardel 
47abb0f93cSkardel /* CONSTANTS
48abb0f93cSkardel  * ---------
49abb0f93cSkardel  */
50abb0f93cSkardel 
51abb0f93cSkardel 
52abb0f93cSkardel /* SCANNER GLOBAL VARIABLES
53abb0f93cSkardel  * ------------------------
54abb0f93cSkardel  */
55abb0f93cSkardel const char special_chars[] = "{}(),;|=";
56abb0f93cSkardel 
57abb0f93cSkardel 
58abb0f93cSkardel /* FUNCTIONS
59abb0f93cSkardel  * ---------
60abb0f93cSkardel  */
61abb0f93cSkardel 
62abb0f93cSkardel static int is_keyword(char *lexeme, follby *pfollowedby);
63abb0f93cSkardel 
64abb0f93cSkardel 
65abb0f93cSkardel /*
663123f114Skardel  * keyword() - Return the keyword associated with token T_ identifier.
673123f114Skardel  *	       See also token_name() for the string-ized T_ identifier.
683123f114Skardel  *	       Example: keyword(T_Server) returns "server"
693123f114Skardel  *			token_name(T_Server) returns "T_Server"
70abb0f93cSkardel  */
71abb0f93cSkardel const char *
72abb0f93cSkardel keyword(
73abb0f93cSkardel 	int token
74abb0f93cSkardel 	)
75abb0f93cSkardel {
76e19314b7Schristos 	size_t i;
77abb0f93cSkardel 	const char *text;
78cdfa2a7eSchristos 	static char sbuf[64];
79abb0f93cSkardel 
80abb0f93cSkardel 	i = token - LOWEST_KEYWORD_ID;
81abb0f93cSkardel 
82cdfa2a7eSchristos 	switch (token) {
83cdfa2a7eSchristos 	    case T_ServerresponseFuzz:
84cdfa2a7eSchristos 		text = "serverresponse fuzz";
85cdfa2a7eSchristos 		break;
86abb0f93cSkardel 
87cdfa2a7eSchristos 	    default:
88cdfa2a7eSchristos 		if (i < COUNTOF(keyword_text)) {
89cdfa2a7eSchristos 			text = keyword_text[i];
90cdfa2a7eSchristos 		} else {
91cdfa2a7eSchristos 			snprintf(sbuf, sizeof sbuf,
92cdfa2a7eSchristos 				"(keyword #%u not found)", token);
93cdfa2a7eSchristos 			text = sbuf;
94cdfa2a7eSchristos 		}
95cdfa2a7eSchristos 	}
96cdfa2a7eSchristos 
97cdfa2a7eSchristos 	return text;
98abb0f93cSkardel }
99abb0f93cSkardel 
100abb0f93cSkardel 
1015d681e99Schristos /* FILE & STRING BUFFER INTERFACE
1025d681e99Schristos  * ------------------------------
1035d681e99Schristos  *
1045d681e99Schristos  * This set out as a couple of wrapper functions around the standard C
1055d681e99Schristos  * fgetc and ungetc functions in order to include positional
1065d681e99Schristos  * bookkeeping. Alas, this is no longer a good solution with nested
1075d681e99Schristos  * input files and the possibility to send configuration commands via
1085d681e99Schristos  * 'ntpdc' and 'ntpq'.
1095d681e99Schristos  *
1105d681e99Schristos  * Now there are a few functions to maintain a stack of nested input
1115d681e99Schristos  * sources (though nesting is only allowd for disk files) and from the
1125d681e99Schristos  * scanner / parser point of view there's no difference between both
1135d681e99Schristos  * types of sources.
1145d681e99Schristos  *
1155d681e99Schristos  * The 'fgetc()' / 'ungetc()' replacements now operate on a FILE_INFO
1165d681e99Schristos  * structure. Instead of trying different 'ungetc()' strategies for file
1175d681e99Schristos  * and buffer based parsing, we keep the backup char in our own
1185d681e99Schristos  * FILE_INFO structure. This is sufficient, as the parser does *not*
1195d681e99Schristos  * jump around via 'seek' or the like, and there's no need to
1205d681e99Schristos  * check/clear the backup store in other places than 'lex_getch()'.
121abb0f93cSkardel  */
122abb0f93cSkardel 
1235d681e99Schristos /*
1245d681e99Schristos  * Allocate an info structure and attach it to a file.
1255d681e99Schristos  *
1265d681e99Schristos  * Note: When 'mode' is NULL, then the INFO block will be set up to
1275d681e99Schristos  * contain a NULL file pointer, as suited for remote config command
1285d681e99Schristos  * parsing. Otherwise having a NULL file pointer is considered an error,
1295d681e99Schristos  * and a NULL info block pointer is returned to indicate failure!
1305d681e99Schristos  *
1315d681e99Schristos  * Note: We use a variable-sized structure to hold a copy of the file
1325d681e99Schristos  * name (or, more proper, the input source description). This is more
1335d681e99Schristos  * secure than keeping a reference to some other storage that might go
1345d681e99Schristos  * out of scope.
1355d681e99Schristos  */
1365d681e99Schristos static struct FILE_INFO *
1375d681e99Schristos lex_open(
138abb0f93cSkardel 	const char *path,
139abb0f93cSkardel 	const char *mode
140abb0f93cSkardel 	)
141abb0f93cSkardel {
1425d681e99Schristos 	struct FILE_INFO *stream;
1435d681e99Schristos 	size_t            nnambuf;
144abb0f93cSkardel 
1455d681e99Schristos 	nnambuf = strlen(path);
1465d681e99Schristos 	stream = emalloc_zero(sizeof(*stream) + nnambuf);
1475d681e99Schristos 	stream->curpos.nline = 1;
1485d681e99Schristos 	stream->backch = EOF;
1495d681e99Schristos 	/* copy name with memcpy -- trailing NUL already there! */
1505d681e99Schristos 	memcpy(stream->fname, path, nnambuf);
151abb0f93cSkardel 
1525d681e99Schristos 	if (NULL != mode) {
1535d681e99Schristos 		stream->fpi = fopen(path, mode);
1545d681e99Schristos 		if (NULL == stream->fpi) {
1555d681e99Schristos 			free(stream);
1565d681e99Schristos 			stream = NULL;
157abb0f93cSkardel 		}
1585d681e99Schristos 	}
1595d681e99Schristos 	return stream;
160abb0f93cSkardel }
161abb0f93cSkardel 
1625d681e99Schristos /* get next character from buffer or file. This will return any putback
1635d681e99Schristos  * character first; it will also make sure the last line is at least
1645d681e99Schristos  * virtually terminated with a '\n'.
1655d681e99Schristos  */
1665d681e99Schristos static int
1675d681e99Schristos lex_getch(
168abb0f93cSkardel 	struct FILE_INFO *stream
169abb0f93cSkardel 	)
170abb0f93cSkardel {
1712950cc38Schristos 	int ch;
172abb0f93cSkardel 
1735d681e99Schristos 	if (NULL == stream || stream->force_eof)
1745d681e99Schristos 		return EOF;
1752950cc38Schristos 
1765d681e99Schristos 	if (EOF != stream->backch) {
1775d681e99Schristos 		ch = stream->backch;
1785d681e99Schristos 		stream->backch = EOF;
1795d681e99Schristos 		if (stream->fpi)
1805d681e99Schristos 			conf_file_sum += ch;
1814eea345dSchristos 		stream->curpos.ncol++;
1825d681e99Schristos 	} else if (stream->fpi) {
1835d681e99Schristos 		/* fetch next 7-bit ASCII char (or EOF) from file */
1845d681e99Schristos 		while ((ch = fgetc(stream->fpi)) != EOF && ch > SCHAR_MAX)
1855d681e99Schristos 			stream->curpos.ncol++;
1862950cc38Schristos 		if (EOF != ch) {
1875d681e99Schristos 			conf_file_sum += ch;
1885d681e99Schristos 			stream->curpos.ncol++;
189abb0f93cSkardel 		}
1905d681e99Schristos 	} else {
1915d681e99Schristos 		/* fetch next 7-bit ASCII char from buffer */
1925d681e99Schristos 		const char * scan;
1935d681e99Schristos 		scan = &remote_config.buffer[remote_config.pos];
1945d681e99Schristos 		while ((ch = (u_char)*scan) > SCHAR_MAX) {
1955d681e99Schristos 			scan++;
1965d681e99Schristos 			stream->curpos.ncol++;
1975d681e99Schristos 		}
1985d681e99Schristos 		if ('\0' != ch) {
1995d681e99Schristos 			scan++;
2005d681e99Schristos 			stream->curpos.ncol++;
2015d681e99Schristos 		} else {
2025d681e99Schristos 			ch = EOF;
2035d681e99Schristos 		}
2045d681e99Schristos 		remote_config.pos = (int)(scan - remote_config.buffer);
2055d681e99Schristos 	}
2065d681e99Schristos 
2075d681e99Schristos 	/* If the last line ends without '\n', generate one. This
2085d681e99Schristos 	 * happens most likely on Windows, where editors often have a
2095d681e99Schristos 	 * sloppy concept of a line.
2105d681e99Schristos 	 */
2115d681e99Schristos 	if (EOF == ch && stream->curpos.ncol != 0)
2125d681e99Schristos 		ch = '\n';
2135d681e99Schristos 
2145d681e99Schristos 	/* update scan position tallies */
2155d681e99Schristos 	if (ch == '\n') {
2165d681e99Schristos 		stream->bakpos = stream->curpos;
2175d681e99Schristos 		stream->curpos.nline++;
2185d681e99Schristos 		stream->curpos.ncol = 0;
2192950cc38Schristos 	}
2202950cc38Schristos 
221abb0f93cSkardel 	return ch;
222abb0f93cSkardel }
223abb0f93cSkardel 
2245d681e99Schristos /* Note: lex_ungetch will fail to track more than one line of push
2255d681e99Schristos  * back. But since it guarantees only one char of back storage anyway,
2265d681e99Schristos  * this should not be a problem.
227abb0f93cSkardel  */
2285d681e99Schristos static int
2295d681e99Schristos lex_ungetch(
230abb0f93cSkardel 	int ch,
231abb0f93cSkardel 	struct FILE_INFO *stream
232abb0f93cSkardel 	)
233abb0f93cSkardel {
2345d681e99Schristos 	/* check preconditions */
2355d681e99Schristos 	if (NULL == stream || stream->force_eof)
2365d681e99Schristos 		return EOF;
2375d681e99Schristos 	if (EOF != stream->backch || EOF == ch)
2385d681e99Schristos 		return EOF;
2395d681e99Schristos 
2405d681e99Schristos 	/* keep for later reference and update checksum */
2415d681e99Schristos 	stream->backch = (u_char)ch;
2425d681e99Schristos 	if (stream->fpi)
2435d681e99Schristos 		conf_file_sum -= stream->backch;
2445d681e99Schristos 
2455d681e99Schristos 	/* update position */
2465d681e99Schristos 	if (stream->backch == '\n') {
2475d681e99Schristos 	    stream->curpos = stream->bakpos;
2485d681e99Schristos 	    stream->bakpos.ncol = -1;
249abb0f93cSkardel 	}
2505d681e99Schristos 	stream->curpos.ncol--;
2515d681e99Schristos 	return stream->backch;
252abb0f93cSkardel }
253abb0f93cSkardel 
2545d681e99Schristos /* dispose of an input structure. If the file pointer is not NULL, close
2555d681e99Schristos  * the file. This function does not check the result of 'fclose()'.
2565d681e99Schristos  */
2575d681e99Schristos static void
2585d681e99Schristos lex_close(
259abb0f93cSkardel 	struct FILE_INFO *stream
260abb0f93cSkardel 	)
261abb0f93cSkardel {
2625d681e99Schristos 	if (NULL != stream) {
2635d681e99Schristos 		if (NULL != stream->fpi)
2645d681e99Schristos 			fclose(stream->fpi);
265abb0f93cSkardel 		free(stream);
2665d681e99Schristos 	}
267abb0f93cSkardel }
268abb0f93cSkardel 
2695d681e99Schristos /* INPUT STACK
2705d681e99Schristos  * -----------
271abb0f93cSkardel  *
2725d681e99Schristos  * Nested input sources are a bit tricky at first glance. We deal with
2735d681e99Schristos  * this problem using a stack of input sources, that is, a forward
2745d681e99Schristos  * linked list of FILE_INFO structs.
2755d681e99Schristos  *
2765d681e99Schristos  * This stack is never empty during parsing; while an encounter with EOF
2775d681e99Schristos  * can and will remove nested input sources, removing the last element
2785d681e99Schristos  * in the stack will not work during parsing, and the EOF condition of
2795d681e99Schristos  * the outermost input file remains until the parser folds up.
280abb0f93cSkardel  */
281abb0f93cSkardel 
2825d681e99Schristos static struct FILE_INFO *
283*eabc0478Schristos drop_stack_do(
2845d681e99Schristos 	struct FILE_INFO * head
285abb0f93cSkardel 	)
286abb0f93cSkardel {
2875d681e99Schristos 	struct FILE_INFO * tail;
2885d681e99Schristos 	while (NULL != head) {
2895d681e99Schristos 		tail = head->st_next;
2905d681e99Schristos 		lex_close(head);
2915d681e99Schristos 		head = tail;
292abb0f93cSkardel 	}
2935d681e99Schristos 	return head;
294abb0f93cSkardel }
295abb0f93cSkardel 
2965d681e99Schristos 
2975d681e99Schristos 
2985d681e99Schristos /* Create a singleton input source on an empty lexer stack. This will
2995d681e99Schristos  * fail if there is already an input source, or if the underlying disk
3005d681e99Schristos  * file cannot be opened.
3015d681e99Schristos  *
3025d681e99Schristos  * Returns TRUE if a new input object was successfully created.
3035d681e99Schristos  */
3045d681e99Schristos int/*BOOL*/
3055d681e99Schristos lex_init_stack(
3065d681e99Schristos 	const char * path,
3075d681e99Schristos 	const char * mode
308abb0f93cSkardel 	)
309abb0f93cSkardel {
3105d681e99Schristos 	if (NULL != lex_stack || NULL == path)
3115d681e99Schristos 		return FALSE;
312abb0f93cSkardel 
3135d681e99Schristos 	lex_stack = lex_open(path, mode);
3145d681e99Schristos 	return (NULL != lex_stack);
315abb0f93cSkardel }
316abb0f93cSkardel 
3175d681e99Schristos /* This removes *all* input sources from the stack, leaving the head
3185d681e99Schristos  * pointer as NULL. Any attempt to parse in that state is likely to bomb
3195d681e99Schristos  * with segmentation faults or the like.
3205d681e99Schristos  *
3215d681e99Schristos  * In other words: Use this to clean up after parsing, and do not parse
3225d681e99Schristos  * anything until the next 'lex_init_stack()' succeeded.
3235d681e99Schristos  */
3245d681e99Schristos void
325*eabc0478Schristos lex_drop_stack(void)
3265d681e99Schristos {
327*eabc0478Schristos 	lex_stack = drop_stack_do(lex_stack);
3285d681e99Schristos }
3295d681e99Schristos 
3305d681e99Schristos /* Flush the lexer input stack: This will nip all input objects on the
3315d681e99Schristos  * stack (but keeps the current top-of-stack) and marks the top-of-stack
3325d681e99Schristos  * as inactive. Any further calls to lex_getch yield only EOF, and it's
3335d681e99Schristos  * no longer possible to push something back.
3345d681e99Schristos  *
3355d681e99Schristos  * Returns TRUE if there is a head element (top-of-stack) that was not
3365d681e99Schristos  * in the force-eof mode before this call.
3375d681e99Schristos  */
3385d681e99Schristos int/*BOOL*/
339*eabc0478Schristos lex_flush_stack(void)
3405d681e99Schristos {
3415d681e99Schristos 	int retv = FALSE;
3425d681e99Schristos 
3435d681e99Schristos 	if (NULL != lex_stack) {
3445d681e99Schristos 		retv = !lex_stack->force_eof;
3455d681e99Schristos 		lex_stack->force_eof = TRUE;
346*eabc0478Schristos 		lex_stack->st_next = drop_stack_do(
3475d681e99Schristos 					lex_stack->st_next);
3485d681e99Schristos 	}
3495d681e99Schristos 	return retv;
3505d681e99Schristos }
3515d681e99Schristos 
3525d681e99Schristos /* Push another file on the parsing stack. If the mode is NULL, create a
3535d681e99Schristos  * FILE_INFO suitable for in-memory parsing; otherwise, create a
3545d681e99Schristos  * FILE_INFO that is bound to a local/disc file. Note that 'path' must
3555d681e99Schristos  * not be NULL, or the function will fail.
3565d681e99Schristos  *
3575d681e99Schristos  * Returns TRUE if a new info record was pushed onto the stack.
3585d681e99Schristos  */
3595d681e99Schristos int/*BOOL*/ lex_push_file(
3605d681e99Schristos 	const char * path,
3615d681e99Schristos 	const char * mode
3625d681e99Schristos 	)
3635d681e99Schristos {
3645d681e99Schristos 	struct FILE_INFO * next = NULL;
3655d681e99Schristos 
3665d681e99Schristos 	if (NULL != path) {
3675d681e99Schristos 		next = lex_open(path, mode);
3685d681e99Schristos 		if (NULL != next) {
3695d681e99Schristos 			next->st_next = lex_stack;
3705d681e99Schristos 			lex_stack = next;
3715d681e99Schristos 		}
3725d681e99Schristos 	}
3735d681e99Schristos 	return (NULL != next);
3745d681e99Schristos }
3755d681e99Schristos 
3765d681e99Schristos /* Pop, close & free the top of the include stack, unless the stack
3775d681e99Schristos  * contains only a singleton input object. In that case the function
3785d681e99Schristos  * fails, because the parser does not expect the input stack to be
3795d681e99Schristos  * empty.
3805d681e99Schristos  *
3815d681e99Schristos  * Returns TRUE if an object was successfuly popped from the stack.
3825d681e99Schristos  */
3835d681e99Schristos int/*BOOL*/
3845d681e99Schristos lex_pop_file(void)
3855d681e99Schristos {
3865d681e99Schristos 	struct FILE_INFO * head = lex_stack;
3875d681e99Schristos 	struct FILE_INFO * tail = NULL;
3885d681e99Schristos 
3895d681e99Schristos 	if (NULL != head) {
3905d681e99Schristos 		tail = head->st_next;
3915d681e99Schristos 		if (NULL != tail) {
3925d681e99Schristos 			lex_stack = tail;
3935d681e99Schristos 			lex_close(head);
3945d681e99Schristos 		}
3955d681e99Schristos 	}
3965d681e99Schristos 	return (NULL != tail);
3975d681e99Schristos }
3985d681e99Schristos 
3995d681e99Schristos /* Get include nesting level. This currently loops over the stack and
4005d681e99Schristos  * counts elements; but since this is of concern only with an include
4015d681e99Schristos  * statement and the nesting depth has a small limit, there's no
4025d681e99Schristos  * bottleneck expected here.
4035d681e99Schristos  *
4045d681e99Schristos  * Returns the nesting level of includes, that is, the current depth of
4055d681e99Schristos  * the lexer input stack.
4065d681e99Schristos  *
4075d681e99Schristos  * Note:
4085d681e99Schristos  */
4095d681e99Schristos size_t
4105d681e99Schristos lex_level(void)
4115d681e99Schristos {
4125d681e99Schristos 	size_t            cnt = 0;
4135d681e99Schristos 	struct FILE_INFO *ipf = lex_stack;
4145d681e99Schristos 
4155d681e99Schristos 	while (NULL != ipf) {
4165d681e99Schristos 		cnt++;
4175d681e99Schristos 		ipf = ipf->st_next;
4185d681e99Schristos 	}
4195d681e99Schristos 	return cnt;
4205d681e99Schristos }
4215d681e99Schristos 
4225d681e99Schristos /* check if the current input is from a file */
4235d681e99Schristos int/*BOOL*/
4245d681e99Schristos lex_from_file(void)
4255d681e99Schristos {
4265d681e99Schristos 	return (NULL != lex_stack) && (NULL != lex_stack->fpi);
4275d681e99Schristos }
4285d681e99Schristos 
4295d681e99Schristos struct FILE_INFO *
430*eabc0478Schristos lex_current(void)
4315d681e99Schristos {
4325d681e99Schristos 	/* this became so simple, it could be a macro. But then,
4335d681e99Schristos 	 * lex_stack needed to be global...
4345d681e99Schristos 	 */
4355d681e99Schristos 	return lex_stack;
4365d681e99Schristos }
437abb0f93cSkardel 
438abb0f93cSkardel 
439abb0f93cSkardel /* STATE MACHINES
440abb0f93cSkardel  * --------------
441abb0f93cSkardel  */
442abb0f93cSkardel 
443abb0f93cSkardel /* Keywords */
444abb0f93cSkardel static int
445abb0f93cSkardel is_keyword(
446abb0f93cSkardel 	char *lexeme,
447abb0f93cSkardel 	follby *pfollowedby
448abb0f93cSkardel 	)
449abb0f93cSkardel {
450abb0f93cSkardel 	follby fb;
451abb0f93cSkardel 	int curr_s;		/* current state index */
452abb0f93cSkardel 	int token;
453abb0f93cSkardel 	int i;
454abb0f93cSkardel 
455abb0f93cSkardel 	curr_s = SCANNER_INIT_S;
456abb0f93cSkardel 	token = 0;
457abb0f93cSkardel 
458abb0f93cSkardel 	for (i = 0; lexeme[i]; i++) {
459abb0f93cSkardel 		while (curr_s && (lexeme[i] != SS_CH(sst[curr_s])))
460abb0f93cSkardel 			curr_s = SS_OTHER_N(sst[curr_s]);
461abb0f93cSkardel 
462abb0f93cSkardel 		if (curr_s && (lexeme[i] == SS_CH(sst[curr_s]))) {
463abb0f93cSkardel 			if ('\0' == lexeme[i + 1]
464abb0f93cSkardel 			    && FOLLBY_NON_ACCEPTING
465abb0f93cSkardel 			       != SS_FB(sst[curr_s])) {
466abb0f93cSkardel 				fb = SS_FB(sst[curr_s]);
467abb0f93cSkardel 				*pfollowedby = fb;
468abb0f93cSkardel 				token = curr_s;
469abb0f93cSkardel 				break;
470abb0f93cSkardel 			}
471abb0f93cSkardel 			curr_s = SS_MATCH_N(sst[curr_s]);
472abb0f93cSkardel 		} else
473abb0f93cSkardel 			break;
474abb0f93cSkardel 	}
475abb0f93cSkardel 
476abb0f93cSkardel 	return token;
477abb0f93cSkardel }
478abb0f93cSkardel 
479abb0f93cSkardel 
480abb0f93cSkardel /* Integer */
481abb0f93cSkardel static int
482abb0f93cSkardel is_integer(
483abb0f93cSkardel 	char *lexeme
484abb0f93cSkardel 	)
485abb0f93cSkardel {
4862950cc38Schristos 	int	i;
4872950cc38Schristos 	int	is_neg;
4882950cc38Schristos 	u_int	u_val;
4892950cc38Schristos 
4902950cc38Schristos 	i = 0;
491abb0f93cSkardel 
492abb0f93cSkardel 	/* Allow a leading minus sign */
4932950cc38Schristos 	if (lexeme[i] == '-') {
4942950cc38Schristos 		i++;
4952950cc38Schristos 		is_neg = TRUE;
4962950cc38Schristos 	} else {
4972950cc38Schristos 		is_neg = FALSE;
4982950cc38Schristos 	}
499abb0f93cSkardel 
500abb0f93cSkardel 	/* Check that all the remaining characters are digits */
5012950cc38Schristos 	for (; lexeme[i] != '\0'; i++) {
5025d681e99Schristos 		if (!isdigit((u_char)lexeme[i]))
5032950cc38Schristos 			return FALSE;
504abb0f93cSkardel 	}
5052950cc38Schristos 
5062950cc38Schristos 	if (is_neg)
5072950cc38Schristos 		return TRUE;
5082950cc38Schristos 
5092950cc38Schristos 	/* Reject numbers that fit in unsigned but not in signed int */
5102950cc38Schristos 	if (1 == sscanf(lexeme, "%u", &u_val))
5112950cc38Schristos 		return (u_val <= INT_MAX);
5122950cc38Schristos 	else
5132950cc38Schristos 		return FALSE;
5142950cc38Schristos }
5152950cc38Schristos 
5162950cc38Schristos 
5172950cc38Schristos /* U_int -- assumes is_integer() has returned FALSE */
5182950cc38Schristos static int
5192950cc38Schristos is_u_int(
5202950cc38Schristos 	char *lexeme
5212950cc38Schristos 	)
5222950cc38Schristos {
5232950cc38Schristos 	int	i;
5242950cc38Schristos 	int	is_hex;
5252950cc38Schristos 
5262950cc38Schristos 	i = 0;
5275d681e99Schristos 	if ('0' == lexeme[i] && 'x' == tolower((u_char)lexeme[i + 1])) {
5282950cc38Schristos 		i += 2;
5292950cc38Schristos 		is_hex = TRUE;
5302950cc38Schristos 	} else {
5312950cc38Schristos 		is_hex = FALSE;
5322950cc38Schristos 	}
5332950cc38Schristos 
5342950cc38Schristos 	/* Check that all the remaining characters are digits */
5352950cc38Schristos 	for (; lexeme[i] != '\0'; i++) {
5365d681e99Schristos 		if (is_hex && !isxdigit((u_char)lexeme[i]))
5372950cc38Schristos 			return FALSE;
5385d681e99Schristos 		if (!is_hex && !isdigit((u_char)lexeme[i]))
5392950cc38Schristos 			return FALSE;
5402950cc38Schristos 	}
5412950cc38Schristos 
5422950cc38Schristos 	return TRUE;
543abb0f93cSkardel }
544abb0f93cSkardel 
545abb0f93cSkardel 
546abb0f93cSkardel /* Double */
547abb0f93cSkardel static int
548abb0f93cSkardel is_double(
549abb0f93cSkardel 	char *lexeme
550abb0f93cSkardel 	)
551abb0f93cSkardel {
5523123f114Skardel 	u_int num_digits = 0;  /* Number of digits read */
5533123f114Skardel 	u_int i;
554abb0f93cSkardel 
555abb0f93cSkardel 	i = 0;
556abb0f93cSkardel 
557abb0f93cSkardel 	/* Check for an optional '+' or '-' */
558abb0f93cSkardel 	if ('+' == lexeme[i] || '-' == lexeme[i])
559abb0f93cSkardel 		i++;
560abb0f93cSkardel 
561abb0f93cSkardel 	/* Read the integer part */
5625d681e99Schristos 	for (; lexeme[i] && isdigit((u_char)lexeme[i]); i++)
563abb0f93cSkardel 		num_digits++;
564abb0f93cSkardel 
5652950cc38Schristos 	/* Check for the optional decimal point */
5662950cc38Schristos 	if ('.' == lexeme[i]) {
567abb0f93cSkardel 		i++;
568abb0f93cSkardel 		/* Check for any digits after the decimal point */
5695d681e99Schristos 		for (; lexeme[i] && isdigit((u_char)lexeme[i]); i++)
570abb0f93cSkardel 			num_digits++;
5712950cc38Schristos 	}
572abb0f93cSkardel 
573abb0f93cSkardel 	/*
574abb0f93cSkardel 	 * The number of digits in both the decimal part and the
575abb0f93cSkardel 	 * fraction part must not be zero at this point
576abb0f93cSkardel 	 */
577abb0f93cSkardel 	if (!num_digits)
578abb0f93cSkardel 		return 0;
579abb0f93cSkardel 
580abb0f93cSkardel 	/* Check if we are done */
581abb0f93cSkardel 	if (!lexeme[i])
582abb0f93cSkardel 		return 1;
583abb0f93cSkardel 
584abb0f93cSkardel 	/* There is still more input, read the exponent */
5855d681e99Schristos 	if ('e' == tolower((u_char)lexeme[i]))
586abb0f93cSkardel 		i++;
587abb0f93cSkardel 	else
588abb0f93cSkardel 		return 0;
589abb0f93cSkardel 
590abb0f93cSkardel 	/* Read an optional Sign */
591abb0f93cSkardel 	if ('+' == lexeme[i] || '-' == lexeme[i])
592abb0f93cSkardel 		i++;
593abb0f93cSkardel 
594abb0f93cSkardel 	/* Now read the exponent part */
5955d681e99Schristos 	while (lexeme[i] && isdigit((u_char)lexeme[i]))
596abb0f93cSkardel 		i++;
597abb0f93cSkardel 
598abb0f93cSkardel 	/* Check if we are done */
599abb0f93cSkardel 	if (!lexeme[i])
600abb0f93cSkardel 		return 1;
601abb0f93cSkardel 	else
602abb0f93cSkardel 		return 0;
603abb0f93cSkardel }
604abb0f93cSkardel 
605abb0f93cSkardel 
606abb0f93cSkardel /* is_special() - Test whether a character is a token */
607abb0f93cSkardel static inline int
608abb0f93cSkardel is_special(
609abb0f93cSkardel 	int ch
610abb0f93cSkardel 	)
611abb0f93cSkardel {
6129893a031Skardel 	return strchr(special_chars, ch) != NULL;
613abb0f93cSkardel }
614abb0f93cSkardel 
615abb0f93cSkardel 
616abb0f93cSkardel static int
617abb0f93cSkardel is_EOC(
618abb0f93cSkardel 	int ch
619abb0f93cSkardel 	)
620abb0f93cSkardel {
621abb0f93cSkardel 	if ((old_config_style && (ch == '\n')) ||
622abb0f93cSkardel 	    (!old_config_style && (ch == ';')))
623abb0f93cSkardel 		return 1;
624abb0f93cSkardel 	return 0;
625abb0f93cSkardel }
626abb0f93cSkardel 
627abb0f93cSkardel 
628abb0f93cSkardel char *
629abb0f93cSkardel quote_if_needed(char *str)
630abb0f93cSkardel {
631abb0f93cSkardel 	char *ret;
632abb0f93cSkardel 	size_t len;
633abb0f93cSkardel 	size_t octets;
634abb0f93cSkardel 
635abb0f93cSkardel 	len = strlen(str);
636abb0f93cSkardel 	octets = len + 2 + 1;
637abb0f93cSkardel 	ret = emalloc(octets);
638abb0f93cSkardel 	if ('"' != str[0]
639abb0f93cSkardel 	    && (strcspn(str, special_chars) < len
640abb0f93cSkardel 		|| strchr(str, ' ') != NULL)) {
641abb0f93cSkardel 		snprintf(ret, octets, "\"%s\"", str);
642abb0f93cSkardel 	} else
6432950cc38Schristos 		strlcpy(ret, str, octets);
644abb0f93cSkardel 
645abb0f93cSkardel 	return ret;
646abb0f93cSkardel }
647abb0f93cSkardel 
648abb0f93cSkardel 
649abb0f93cSkardel static int
650abb0f93cSkardel create_string_token(
651abb0f93cSkardel 	char *lexeme
652abb0f93cSkardel 	)
653abb0f93cSkardel {
654abb0f93cSkardel 	char *pch;
655abb0f93cSkardel 
656abb0f93cSkardel 	/*
657abb0f93cSkardel 	 * ignore end of line whitespace
658abb0f93cSkardel 	 */
659abb0f93cSkardel 	pch = lexeme;
6605d681e99Schristos 	while (*pch && isspace((u_char)*pch))
661abb0f93cSkardel 		pch++;
662abb0f93cSkardel 
663abb0f93cSkardel 	if (!*pch) {
664abb0f93cSkardel 		yylval.Integer = T_EOC;
665abb0f93cSkardel 		return yylval.Integer;
666abb0f93cSkardel 	}
667abb0f93cSkardel 
668abb0f93cSkardel 	yylval.String = estrdup(lexeme);
669abb0f93cSkardel 	return T_String;
670abb0f93cSkardel }
671abb0f93cSkardel 
672abb0f93cSkardel 
673abb0f93cSkardel /*
674abb0f93cSkardel  * yylex() - function that does the actual scanning.
675abb0f93cSkardel  * Bison expects this function to be called yylex and for it to take no
676abb0f93cSkardel  * input and return an int.
677abb0f93cSkardel  * Conceptually yylex "returns" yylval as well as the actual return
678abb0f93cSkardel  * value representing the token or type.
679abb0f93cSkardel  */
680abb0f93cSkardel int
6815d681e99Schristos yylex(void)
682abb0f93cSkardel {
683abb0f93cSkardel 	static follby	followedby = FOLLBY_TOKEN;
6842950cc38Schristos 	size_t		i;
6852950cc38Schristos 	int		instring;
6862950cc38Schristos 	int		yylval_was_set;
6872950cc38Schristos 	int		converted;
6882950cc38Schristos 	int		token;		/* The return value */
6892950cc38Schristos 	int		ch;
6902950cc38Schristos 
6912950cc38Schristos 	instring = FALSE;
6922950cc38Schristos 	yylval_was_set = FALSE;
693abb0f93cSkardel 
694abb0f93cSkardel 	do {
695abb0f93cSkardel 		/* Ignore whitespace at the beginning */
6965d681e99Schristos 		while (EOF != (ch = lex_getch(lex_stack)) &&
697abb0f93cSkardel 		       isspace(ch) &&
698abb0f93cSkardel 		       !is_EOC(ch))
6995d681e99Schristos 
700abb0f93cSkardel 			; /* Null Statement */
701abb0f93cSkardel 
702abb0f93cSkardel 		if (EOF == ch) {
703abb0f93cSkardel 
7045d681e99Schristos 			if ( ! lex_pop_file())
705abb0f93cSkardel 				return 0;
706abb0f93cSkardel 			token = T_EOC;
707abb0f93cSkardel 			goto normal_return;
708abb0f93cSkardel 
709abb0f93cSkardel 		} else if (is_EOC(ch)) {
710abb0f93cSkardel 
711abb0f93cSkardel 			/* end FOLLBY_STRINGS_TO_EOC effect */
712abb0f93cSkardel 			followedby = FOLLBY_TOKEN;
713abb0f93cSkardel 			token = T_EOC;
714abb0f93cSkardel 			goto normal_return;
715abb0f93cSkardel 
716abb0f93cSkardel 		} else if (is_special(ch) && FOLLBY_TOKEN == followedby) {
717abb0f93cSkardel 			/* special chars are their own token values */
718abb0f93cSkardel 			token = ch;
719abb0f93cSkardel 			/*
7202950cc38Schristos 			 * '=' outside simulator configuration implies
7212950cc38Schristos 			 * a single string following as in:
722abb0f93cSkardel 			 * setvar Owner = "The Boss" default
723abb0f93cSkardel 			 */
7242950cc38Schristos 			if ('=' == ch && old_config_style)
725abb0f93cSkardel 				followedby = FOLLBY_STRING;
726abb0f93cSkardel 			yytext[0] = (char)ch;
727abb0f93cSkardel 			yytext[1] = '\0';
728abb0f93cSkardel 			goto normal_return;
729abb0f93cSkardel 		} else
7305d681e99Schristos 			lex_ungetch(ch, lex_stack);
731abb0f93cSkardel 
732abb0f93cSkardel 		/* save the position of start of the token */
7335d681e99Schristos 		lex_stack->tokpos = lex_stack->curpos;
734abb0f93cSkardel 
735abb0f93cSkardel 		/* Read in the lexeme */
736abb0f93cSkardel 		i = 0;
7375d681e99Schristos 		while (EOF != (ch = lex_getch(lex_stack))) {
738abb0f93cSkardel 
739abb0f93cSkardel 			yytext[i] = (char)ch;
740abb0f93cSkardel 
741abb0f93cSkardel 			/* Break on whitespace or a special character */
742abb0f93cSkardel 			if (isspace(ch) || is_EOC(ch)
743abb0f93cSkardel 			    || '"' == ch
744abb0f93cSkardel 			    || (FOLLBY_TOKEN == followedby
745abb0f93cSkardel 				&& is_special(ch)))
746abb0f93cSkardel 				break;
747abb0f93cSkardel 
748abb0f93cSkardel 			/* Read the rest of the line on reading a start
749abb0f93cSkardel 			   of comment character */
750abb0f93cSkardel 			if ('#' == ch) {
7515d681e99Schristos 				while (EOF != (ch = lex_getch(lex_stack))
752abb0f93cSkardel 				       && '\n' != ch)
753abb0f93cSkardel 					; /* Null Statement */
754abb0f93cSkardel 				break;
755abb0f93cSkardel 			}
756abb0f93cSkardel 
757abb0f93cSkardel 			i++;
758abb0f93cSkardel 			if (i >= COUNTOF(yytext))
759abb0f93cSkardel 				goto lex_too_long;
760abb0f93cSkardel 		}
761abb0f93cSkardel 		/* Pick up all of the string inside between " marks, to
762abb0f93cSkardel 		 * end of line.  If we make it to EOL without a
763abb0f93cSkardel 		 * terminating " assume it for them.
764abb0f93cSkardel 		 *
765abb0f93cSkardel 		 * XXX - HMS: I'm not sure we want to assume the closing "
766abb0f93cSkardel 		 */
767abb0f93cSkardel 		if ('"' == ch) {
7682950cc38Schristos 			instring = TRUE;
7695d681e99Schristos 			while (EOF != (ch = lex_getch(lex_stack)) &&
770abb0f93cSkardel 			       ch != '"' && ch != '\n') {
771abb0f93cSkardel 				yytext[i++] = (char)ch;
772abb0f93cSkardel 				if (i >= COUNTOF(yytext))
773abb0f93cSkardel 					goto lex_too_long;
774abb0f93cSkardel 			}
775abb0f93cSkardel 			/*
776abb0f93cSkardel 			 * yytext[i] will be pushed back as not part of
777abb0f93cSkardel 			 * this lexeme, but any closing quote should
778abb0f93cSkardel 			 * not be pushed back, so we read another char.
779abb0f93cSkardel 			 */
780abb0f93cSkardel 			if ('"' == ch)
7815d681e99Schristos 				ch = lex_getch(lex_stack);
782abb0f93cSkardel 		}
783abb0f93cSkardel 		/* Pushback the last character read that is not a part
7845d681e99Schristos 		 * of this lexeme. This fails silently if ch is EOF,
7855d681e99Schristos 		 * but then the EOF condition persists and is handled on
7865d681e99Schristos 		 * the next turn by the include stack mechanism.
787abb0f93cSkardel 		 */
7885d681e99Schristos 		lex_ungetch(ch, lex_stack);
7895d681e99Schristos 
790abb0f93cSkardel 		yytext[i] = '\0';
791abb0f93cSkardel 	} while (i == 0);
792abb0f93cSkardel 
793abb0f93cSkardel 	/* Now return the desired token */
794abb0f93cSkardel 
795abb0f93cSkardel 	/* First make sure that the parser is *not* expecting a string
796abb0f93cSkardel 	 * as the next token (based on the previous token that was
797abb0f93cSkardel 	 * returned) and that we haven't read a string.
798abb0f93cSkardel 	 */
799abb0f93cSkardel 
800abb0f93cSkardel 	if (followedby == FOLLBY_TOKEN && !instring) {
801abb0f93cSkardel 		token = is_keyword(yytext, &followedby);
8022950cc38Schristos 		if (token) {
8032950cc38Schristos 			/*
8042950cc38Schristos 			 * T_Server is exceptional as it forces the
8052950cc38Schristos 			 * following token to be a string in the
8062950cc38Schristos 			 * non-simulator parts of the configuration,
8072950cc38Schristos 			 * but in the simulator configuration section,
8082950cc38Schristos 			 * "server" is followed by "=" which must be
8092950cc38Schristos 			 * recognized as a token not a string.
8102950cc38Schristos 			 */
8112950cc38Schristos 			if (T_Server == token && !old_config_style)
8122950cc38Schristos 				followedby = FOLLBY_TOKEN;
813abb0f93cSkardel 			goto normal_return;
8142950cc38Schristos 		} else if (is_integer(yytext)) {
8152950cc38Schristos 			yylval_was_set = TRUE;
816abb0f93cSkardel 			errno = 0;
817abb0f93cSkardel 			if ((yylval.Integer = strtol(yytext, NULL, 10)) == 0
818abb0f93cSkardel 			    && ((errno == EINVAL) || (errno == ERANGE))) {
819abb0f93cSkardel 				msyslog(LOG_ERR,
820abb0f93cSkardel 					"Integer cannot be represented: %s",
821abb0f93cSkardel 					yytext);
8225d681e99Schristos 				if (lex_from_file()) {
823abb0f93cSkardel 					exit(1);
824abb0f93cSkardel 				} else {
8252950cc38Schristos 					/* force end of parsing */
8262950cc38Schristos 					yylval.Integer = 0;
8272950cc38Schristos 					return 0;
8282950cc38Schristos 				}
8292950cc38Schristos 			}
830abb0f93cSkardel 			token = T_Integer;
831abb0f93cSkardel 			goto normal_return;
8322950cc38Schristos 		} else if (is_u_int(yytext)) {
8332950cc38Schristos 			yylval_was_set = TRUE;
8342950cc38Schristos 			if ('0' == yytext[0] &&
8355d681e99Schristos 			    'x' == tolower((unsigned long)yytext[1]))
8362950cc38Schristos 				converted = sscanf(&yytext[2], "%x",
8372950cc38Schristos 						   &yylval.U_int);
8382950cc38Schristos 			else
8392950cc38Schristos 				converted = sscanf(yytext, "%u",
8402950cc38Schristos 						   &yylval.U_int);
8412950cc38Schristos 			if (1 != converted) {
8422950cc38Schristos 				msyslog(LOG_ERR,
8432950cc38Schristos 					"U_int cannot be represented: %s",
8442950cc38Schristos 					yytext);
8455d681e99Schristos 				if (lex_from_file()) {
8462950cc38Schristos 					exit(1);
8472950cc38Schristos 				} else {
8482950cc38Schristos 					/* force end of parsing */
8492950cc38Schristos 					yylval.Integer = 0;
8502950cc38Schristos 					return 0;
851abb0f93cSkardel 				}
852abb0f93cSkardel 			}
8532950cc38Schristos 			token = T_U_int;
8542950cc38Schristos 			goto normal_return;
8552950cc38Schristos 		} else if (is_double(yytext)) {
8562950cc38Schristos 			yylval_was_set = TRUE;
857abb0f93cSkardel 			errno = 0;
858abb0f93cSkardel 			if ((yylval.Double = atof(yytext)) == 0 && errno == ERANGE) {
859abb0f93cSkardel 				msyslog(LOG_ERR,
860abb0f93cSkardel 					"Double too large to represent: %s",
861abb0f93cSkardel 					yytext);
862abb0f93cSkardel 				exit(1);
863abb0f93cSkardel 			} else {
864abb0f93cSkardel 				token = T_Double;
865abb0f93cSkardel 				goto normal_return;
866abb0f93cSkardel 			}
867abb0f93cSkardel 		} else {
868abb0f93cSkardel 			/* Default: Everything is a string */
8692950cc38Schristos 			yylval_was_set = TRUE;
870abb0f93cSkardel 			token = create_string_token(yytext);
871abb0f93cSkardel 			goto normal_return;
872abb0f93cSkardel 		}
873abb0f93cSkardel 	}
874abb0f93cSkardel 
875abb0f93cSkardel 	/*
876abb0f93cSkardel 	 * Either followedby is not FOLLBY_TOKEN or this lexeme is part
877abb0f93cSkardel 	 * of a string.  Hence, we need to return T_String.
878abb0f93cSkardel 	 *
879abb0f93cSkardel 	 * _Except_ we might have a -4 or -6 flag on a an association
880abb0f93cSkardel 	 * configuration line (server, peer, pool, etc.).
881abb0f93cSkardel 	 *
882abb0f93cSkardel 	 * This is a terrible hack, but the grammar is ambiguous so we
883abb0f93cSkardel 	 * don't have a choice.  [SK]
884abb0f93cSkardel 	 *
885abb0f93cSkardel 	 * The ambiguity is in the keyword scanner, not ntp_parser.y.
886abb0f93cSkardel 	 * We do not require server addresses be quoted in ntp.conf,
887abb0f93cSkardel 	 * complicating the scanner's job.  To avoid trying (and
888abb0f93cSkardel 	 * failing) to match an IP address or DNS name to a keyword,
889abb0f93cSkardel 	 * the association keywords use FOLLBY_STRING in the keyword
890abb0f93cSkardel 	 * table, which tells the scanner to force the next token to be
891abb0f93cSkardel 	 * a T_String, so it does not try to match a keyword but rather
892abb0f93cSkardel 	 * expects a string when -4/-6 modifiers to server, peer, etc.
893abb0f93cSkardel 	 * are encountered.
894abb0f93cSkardel 	 * restrict -4 and restrict -6 parsing works correctly without
895abb0f93cSkardel 	 * this hack, as restrict uses FOLLBY_TOKEN.  [DH]
896abb0f93cSkardel 	 */
897abb0f93cSkardel 	if ('-' == yytext[0]) {
898abb0f93cSkardel 		if ('4' == yytext[1]) {
899abb0f93cSkardel 			token = T_Ipv4_flag;
900abb0f93cSkardel 			goto normal_return;
901abb0f93cSkardel 		} else if ('6' == yytext[1]) {
902abb0f93cSkardel 			token = T_Ipv6_flag;
903abb0f93cSkardel 			goto normal_return;
904abb0f93cSkardel 		}
905abb0f93cSkardel 	}
906abb0f93cSkardel 
907abb0f93cSkardel 	if (FOLLBY_STRING == followedby)
908abb0f93cSkardel 		followedby = FOLLBY_TOKEN;
909abb0f93cSkardel 
9102950cc38Schristos 	yylval_was_set = TRUE;
911abb0f93cSkardel 	token = create_string_token(yytext);
912abb0f93cSkardel 
913abb0f93cSkardel normal_return:
914abb0f93cSkardel 	if (T_EOC == token)
915*eabc0478Schristos 		DPRINTF(10, ("\t<end of command>\n"));
916abb0f93cSkardel 	else
917*eabc0478Schristos 		DPRINTF(10, ("yylex: lexeme '%s' -> %s\n", yytext,
918abb0f93cSkardel 			    token_name(token)));
919abb0f93cSkardel 
920abb0f93cSkardel 	if (!yylval_was_set)
921abb0f93cSkardel 		yylval.Integer = token;
922abb0f93cSkardel 
923abb0f93cSkardel 	return token;
924abb0f93cSkardel 
925abb0f93cSkardel lex_too_long:
926*eabc0478Schristos 	/*
927*eabc0478Schristos 	 * DLH: What is the purpose of the limit of 50?
928*eabc0478Schristos 	 * Is there any reason for yytext[] to be bigger?
929*eabc0478Schristos 	 */
930abb0f93cSkardel 	yytext[min(sizeof(yytext) - 1, 50)] = 0;
931abb0f93cSkardel 	msyslog(LOG_ERR,
9322950cc38Schristos 		"configuration item on line %d longer than limit of %lu, began with '%s'",
9335d681e99Schristos 		lex_stack->curpos.nline, (u_long)min(sizeof(yytext) - 1, 50),
9342950cc38Schristos 		yytext);
935abb0f93cSkardel 
936abb0f93cSkardel 	/*
937abb0f93cSkardel 	 * If we hit the length limit reading the startup configuration
938abb0f93cSkardel 	 * file, abort.
939abb0f93cSkardel 	 */
9405d681e99Schristos 	if (lex_from_file())
941abb0f93cSkardel 		exit(sizeof(yytext) - 1);
942abb0f93cSkardel 
943abb0f93cSkardel 	/*
944abb0f93cSkardel 	 * If it's runtime configuration via ntpq :config treat it as
945abb0f93cSkardel 	 * if the configuration text ended before the too-long lexeme,
946abb0f93cSkardel 	 * hostname, or string.
947abb0f93cSkardel 	 */
948abb0f93cSkardel 	yylval.Integer = 0;
949abb0f93cSkardel 	return 0;
950abb0f93cSkardel }
951