ntp_scanner.c revision 330141
1230557Sjimharris
2230557Sjimharris/* ntp_scanner.c
3230557Sjimharris *
4230557Sjimharris * The source code for a simple lexical analyzer.
5230557Sjimharris *
6230557Sjimharris * Written By:	Sachin Kamboj
7230557Sjimharris *		University of Delaware
8230557Sjimharris *		Newark, DE 19711
9230557Sjimharris * Copyright (c) 2006
10230557Sjimharris */
11230557Sjimharris
12230557Sjimharris#ifdef HAVE_CONFIG_H
13230557Sjimharris# include <config.h>
14230557Sjimharris#endif
15230557Sjimharris
16230557Sjimharris#include <stdio.h>
17230557Sjimharris#include <ctype.h>
18230557Sjimharris#include <stdlib.h>
19230557Sjimharris#include <errno.h>
20230557Sjimharris#include <string.h>
21230557Sjimharris
22230557Sjimharris#include "ntpd.h"
23230557Sjimharris#include "ntp_config.h"
24230557Sjimharris#include "ntpsim.h"
25230557Sjimharris#include "ntp_scanner.h"
26230557Sjimharris#include "ntp_parser.h"
27230557Sjimharris
28230557Sjimharris/* ntp_keyword.h declares finite state machine and token text */
29230557Sjimharris#include "ntp_keyword.h"
30230557Sjimharris
31230557Sjimharris
32230557Sjimharris
33230557Sjimharris/* SCANNER GLOBAL VARIABLES
34230557Sjimharris * ------------------------
35230557Sjimharris */
36230557Sjimharris
37230557Sjimharris#define MAX_LEXEME (1024 + 1)	/* The maximum size of a lexeme */
38230557Sjimharrischar yytext[MAX_LEXEME];	/* Buffer for storing the input text/lexeme */
39230557Sjimharrisu_int32 conf_file_sum;		/* Simple sum of characters read */
40230557Sjimharris
41230557Sjimharrisstatic struct FILE_INFO * lex_stack = NULL;
42230557Sjimharris
43230557Sjimharris
44230557Sjimharris
45230557Sjimharris/* CONSTANTS
46230557Sjimharris * ---------
47230557Sjimharris */
48230557Sjimharris
49230557Sjimharris
50230557Sjimharris/* SCANNER GLOBAL VARIABLES
51230557Sjimharris * ------------------------
52230557Sjimharris */
53230557Sjimharrisconst char special_chars[] = "{}(),;|=";
54230557Sjimharris
55230557Sjimharris
56230557Sjimharris/* FUNCTIONS
57230557Sjimharris * ---------
58230557Sjimharris */
59230557Sjimharris
60230557Sjimharrisstatic int is_keyword(char *lexeme, follby *pfollowedby);
61230557Sjimharris
62230557Sjimharris
63230557Sjimharris/*
64230557Sjimharris * keyword() - Return the keyword associated with token T_ identifier.
65230557Sjimharris *	       See also token_name() for the string-ized T_ identifier.
66230557Sjimharris *	       Example: keyword(T_Server) returns "server"
67230557Sjimharris *			token_name(T_Server) returns "T_Server"
68230557Sjimharris */
69230557Sjimharrisconst char *
70230557Sjimharriskeyword(
71230557Sjimharris	int token
72230557Sjimharris	)
73230557Sjimharris{
74230557Sjimharris	size_t i;
75230557Sjimharris	const char *text;
76230557Sjimharris
77230557Sjimharris	i = token - LOWEST_KEYWORD_ID;
78230557Sjimharris
79230557Sjimharris	if (i < COUNTOF(keyword_text))
80230557Sjimharris		text = keyword_text[i];
81230557Sjimharris	else
82230557Sjimharris		text = NULL;
83230557Sjimharris
84230557Sjimharris	return (text != NULL)
85230557Sjimharris		   ? text
86230557Sjimharris		   : "(keyword not found)";
87230557Sjimharris}
88230557Sjimharris
89230557Sjimharris
90230557Sjimharris/* FILE & STRING BUFFER INTERFACE
91230557Sjimharris * ------------------------------
92230557Sjimharris *
93230557Sjimharris * This set out as a couple of wrapper functions around the standard C
94230557Sjimharris * fgetc and ungetc functions in order to include positional
95230557Sjimharris * bookkeeping. Alas, this is no longer a good solution with nested
96230557Sjimharris * input files and the possibility to send configuration commands via
97230557Sjimharris * 'ntpdc' and 'ntpq'.
98230557Sjimharris *
99230557Sjimharris * Now there are a few functions to maintain a stack of nested input
100230557Sjimharris * sources (though nesting is only allowd for disk files) and from the
101230557Sjimharris * scanner / parser point of view there's no difference between both
102230557Sjimharris * types of sources.
103230557Sjimharris *
104230557Sjimharris * The 'fgetc()' / 'ungetc()' replacements now operate on a FILE_INFO
105230557Sjimharris * structure. Instead of trying different 'ungetc()' strategies for file
106230557Sjimharris * and buffer based parsing, we keep the backup char in our own
107230557Sjimharris * FILE_INFO structure. This is sufficient, as the parser does *not*
108230557Sjimharris * jump around via 'seek' or the like, and there's no need to
109230557Sjimharris * check/clear the backup store in other places than 'lex_getch()'.
110230557Sjimharris */
111230557Sjimharris
112230557Sjimharris/*
113230557Sjimharris * Allocate an info structure and attach it to a file.
114230557Sjimharris *
115230557Sjimharris * Note: When 'mode' is NULL, then the INFO block will be set up to
116230557Sjimharris * contain a NULL file pointer, as suited for remote config command
117230557Sjimharris * parsing. Otherwise having a NULL file pointer is considered an error,
118230557Sjimharris * and a NULL info block pointer is returned to indicate failure!
119230557Sjimharris *
120230557Sjimharris * Note: We use a variable-sized structure to hold a copy of the file
121230557Sjimharris * name (or, more proper, the input source description). This is more
122230557Sjimharris * secure than keeping a reference to some other storage that might go
123230557Sjimharris * out of scope.
124230557Sjimharris */
125230557Sjimharrisstatic struct FILE_INFO *
126230557Sjimharrislex_open(
127230557Sjimharris	const char *path,
128230557Sjimharris	const char *mode
129230557Sjimharris	)
130230557Sjimharris{
131230557Sjimharris	struct FILE_INFO *stream;
132230557Sjimharris	size_t            nnambuf;
133230557Sjimharris
134230557Sjimharris	nnambuf = strlen(path);
135230557Sjimharris	stream = emalloc_zero(sizeof(*stream) + nnambuf);
136230557Sjimharris	stream->curpos.nline = 1;
137230557Sjimharris	stream->backch = EOF;
138230557Sjimharris	/* copy name with memcpy -- trailing NUL already there! */
139230557Sjimharris	memcpy(stream->fname, path, nnambuf);
140230557Sjimharris
141230557Sjimharris	if (NULL != mode) {
142230557Sjimharris		stream->fpi = fopen(path, mode);
143230557Sjimharris		if (NULL == stream->fpi) {
144230557Sjimharris			free(stream);
145230557Sjimharris			stream = NULL;
146230557Sjimharris		}
147230557Sjimharris	}
148230557Sjimharris	return stream;
149230557Sjimharris}
150230557Sjimharris
151230557Sjimharris/* get next character from buffer or file. This will return any putback
152230557Sjimharris * character first; it will also make sure the last line is at least
153230557Sjimharris * virtually terminated with a '\n'.
154230557Sjimharris */
155230557Sjimharrisstatic int
156230557Sjimharrislex_getch(
157230557Sjimharris	struct FILE_INFO *stream
158230557Sjimharris	)
159230557Sjimharris{
160230557Sjimharris	int ch;
161230557Sjimharris
162230557Sjimharris	if (NULL == stream || stream->force_eof)
163230557Sjimharris		return EOF;
164230557Sjimharris
165230557Sjimharris	if (EOF != stream->backch) {
166230557Sjimharris		ch = stream->backch;
167230557Sjimharris		stream->backch = EOF;
168230557Sjimharris		if (stream->fpi)
169230557Sjimharris			conf_file_sum += ch;
170230557Sjimharris		stream->curpos.ncol++;
171230557Sjimharris	} else if (stream->fpi) {
172230557Sjimharris		/* fetch next 7-bit ASCII char (or EOF) from file */
173230557Sjimharris		while ((ch = fgetc(stream->fpi)) != EOF && ch > SCHAR_MAX)
174230557Sjimharris			stream->curpos.ncol++;
175230557Sjimharris		if (EOF != ch) {
176230557Sjimharris			conf_file_sum += ch;
177230557Sjimharris			stream->curpos.ncol++;
178230557Sjimharris		}
179230557Sjimharris	} else {
180230557Sjimharris		/* fetch next 7-bit ASCII char from buffer */
181230557Sjimharris		const char * scan;
182230557Sjimharris		scan = &remote_config.buffer[remote_config.pos];
183230557Sjimharris		while ((ch = (u_char)*scan) > SCHAR_MAX) {
184230557Sjimharris			scan++;
185230557Sjimharris			stream->curpos.ncol++;
186230557Sjimharris		}
187230557Sjimharris		if ('\0' != ch) {
188230557Sjimharris			scan++;
189230557Sjimharris			stream->curpos.ncol++;
190230557Sjimharris		} else {
191230557Sjimharris			ch = EOF;
192230557Sjimharris		}
193230557Sjimharris		remote_config.pos = (int)(scan - remote_config.buffer);
194230557Sjimharris	}
195230557Sjimharris
196230557Sjimharris	/* If the last line ends without '\n', generate one. This
197230557Sjimharris	 * happens most likely on Windows, where editors often have a
198230557Sjimharris	 * sloppy concept of a line.
199230557Sjimharris	 */
200230557Sjimharris	if (EOF == ch && stream->curpos.ncol != 0)
201230557Sjimharris		ch = '\n';
202230557Sjimharris
203230557Sjimharris	/* update scan position tallies */
204230557Sjimharris	if (ch == '\n') {
205230557Sjimharris		stream->bakpos = stream->curpos;
206230557Sjimharris		stream->curpos.nline++;
207230557Sjimharris		stream->curpos.ncol = 0;
208230557Sjimharris	}
209230557Sjimharris
210230557Sjimharris	return ch;
211230557Sjimharris}
212230557Sjimharris
213230557Sjimharris/* Note: lex_ungetch will fail to track more than one line of push
214230557Sjimharris * back. But since it guarantees only one char of back storage anyway,
215230557Sjimharris * this should not be a problem.
216230557Sjimharris */
217230557Sjimharrisstatic int
218230557Sjimharrislex_ungetch(
219230557Sjimharris	int ch,
220230557Sjimharris	struct FILE_INFO *stream
221230557Sjimharris	)
222230557Sjimharris{
223230557Sjimharris	/* check preconditions */
224230557Sjimharris	if (NULL == stream || stream->force_eof)
225230557Sjimharris		return EOF;
226230557Sjimharris	if (EOF != stream->backch || EOF == ch)
227230557Sjimharris		return EOF;
228230557Sjimharris
229230557Sjimharris	/* keep for later reference and update checksum */
230230557Sjimharris	stream->backch = (u_char)ch;
231230557Sjimharris	if (stream->fpi)
232230557Sjimharris		conf_file_sum -= stream->backch;
233230557Sjimharris
234230557Sjimharris	/* update position */
235230557Sjimharris	if (stream->backch == '\n') {
236230557Sjimharris	    stream->curpos = stream->bakpos;
237230557Sjimharris	    stream->bakpos.ncol = -1;
238230557Sjimharris	}
239230557Sjimharris	stream->curpos.ncol--;
240230557Sjimharris	return stream->backch;
241230557Sjimharris}
242230557Sjimharris
243230557Sjimharris/* dispose of an input structure. If the file pointer is not NULL, close
244230557Sjimharris * the file. This function does not check the result of 'fclose()'.
245230557Sjimharris */
246230557Sjimharrisstatic void
247230557Sjimharrislex_close(
248230557Sjimharris	struct FILE_INFO *stream
249230557Sjimharris	)
250230557Sjimharris{
251230557Sjimharris	if (NULL != stream) {
252230557Sjimharris		if (NULL != stream->fpi)
253230557Sjimharris			fclose(stream->fpi);
254230557Sjimharris		free(stream);
255230557Sjimharris	}
256230557Sjimharris}
257230557Sjimharris
258230557Sjimharris/* INPUT STACK
259230557Sjimharris * -----------
260230557Sjimharris *
261230557Sjimharris * Nested input sources are a bit tricky at first glance. We deal with
262230557Sjimharris * this problem using a stack of input sources, that is, a forward
263230557Sjimharris * linked list of FILE_INFO structs.
264230557Sjimharris *
265230557Sjimharris * This stack is never empty during parsing; while an encounter with EOF
266230557Sjimharris * can and will remove nested input sources, removing the last element
267230557Sjimharris * in the stack will not work during parsing, and the EOF condition of
268230557Sjimharris * the outermost input file remains until the parser folds up.
269230557Sjimharris */
270230557Sjimharris
271230557Sjimharrisstatic struct FILE_INFO *
272230557Sjimharris_drop_stack_do(
273230557Sjimharris	struct FILE_INFO * head
274230557Sjimharris	)
275230557Sjimharris{
276230557Sjimharris	struct FILE_INFO * tail;
277230557Sjimharris	while (NULL != head) {
278230557Sjimharris		tail = head->st_next;
279230557Sjimharris		lex_close(head);
280230557Sjimharris		head = tail;
281230557Sjimharris	}
282230557Sjimharris	return head;
283230557Sjimharris}
284230557Sjimharris
285230557Sjimharris
286230557Sjimharris
287230557Sjimharris/* Create a singleton input source on an empty lexer stack. This will
288230557Sjimharris * fail if there is already an input source, or if the underlying disk
289230557Sjimharris * file cannot be opened.
290230557Sjimharris *
291230557Sjimharris * Returns TRUE if a new input object was successfully created.
292230557Sjimharris */
293230557Sjimharrisint/*BOOL*/
294230557Sjimharrislex_init_stack(
295230557Sjimharris	const char * path,
296230557Sjimharris	const char * mode
297230557Sjimharris	)
298230557Sjimharris{
299230557Sjimharris	if (NULL != lex_stack || NULL == path)
300230557Sjimharris		return FALSE;
301230557Sjimharris
302230557Sjimharris	lex_stack = lex_open(path, mode);
303230557Sjimharris	return (NULL != lex_stack);
304230557Sjimharris}
305230557Sjimharris
306230557Sjimharris/* This removes *all* input sources from the stack, leaving the head
307230557Sjimharris * pointer as NULL. Any attempt to parse in that state is likely to bomb
308230557Sjimharris * with segmentation faults or the like.
309230557Sjimharris *
310230557Sjimharris * In other words: Use this to clean up after parsing, and do not parse
311230557Sjimharris * anything until the next 'lex_init_stack()' succeeded.
312230557Sjimharris */
313230557Sjimharrisvoid
314230557Sjimharrislex_drop_stack()
315230557Sjimharris{
316230557Sjimharris	lex_stack = _drop_stack_do(lex_stack);
317230557Sjimharris}
318230557Sjimharris
319230557Sjimharris/* Flush the lexer input stack: This will nip all input objects on the
320230557Sjimharris * stack (but keeps the current top-of-stack) and marks the top-of-stack
321230557Sjimharris * as inactive. Any further calls to lex_getch yield only EOF, and it's
322 * no longer possible to push something back.
323 *
324 * Returns TRUE if there is a head element (top-of-stack) that was not
325 * in the force-eof mode before this call.
326 */
327int/*BOOL*/
328lex_flush_stack()
329{
330	int retv = FALSE;
331
332	if (NULL != lex_stack) {
333		retv = !lex_stack->force_eof;
334		lex_stack->force_eof = TRUE;
335		lex_stack->st_next = _drop_stack_do(
336					lex_stack->st_next);
337	}
338	return retv;
339}
340
341/* Push another file on the parsing stack. If the mode is NULL, create a
342 * FILE_INFO suitable for in-memory parsing; otherwise, create a
343 * FILE_INFO that is bound to a local/disc file. Note that 'path' must
344 * not be NULL, or the function will fail.
345 *
346 * Returns TRUE if a new info record was pushed onto the stack.
347 */
348int/*BOOL*/ lex_push_file(
349	const char * path,
350	const char * mode
351	)
352{
353	struct FILE_INFO * next = NULL;
354
355	if (NULL != path) {
356		next = lex_open(path, mode);
357		if (NULL != next) {
358			next->st_next = lex_stack;
359			lex_stack = next;
360		}
361	}
362	return (NULL != next);
363}
364
365/* Pop, close & free the top of the include stack, unless the stack
366 * contains only a singleton input object. In that case the function
367 * fails, because the parser does not expect the input stack to be
368 * empty.
369 *
370 * Returns TRUE if an object was successfuly popped from the stack.
371 */
372int/*BOOL*/
373lex_pop_file(void)
374{
375	struct FILE_INFO * head = lex_stack;
376	struct FILE_INFO * tail = NULL;
377
378	if (NULL != head) {
379		tail = head->st_next;
380		if (NULL != tail) {
381			lex_stack = tail;
382			lex_close(head);
383		}
384	}
385	return (NULL != tail);
386}
387
388/* Get include nesting level. This currently loops over the stack and
389 * counts elements; but since this is of concern only with an include
390 * statement and the nesting depth has a small limit, there's no
391 * bottleneck expected here.
392 *
393 * Returns the nesting level of includes, that is, the current depth of
394 * the lexer input stack.
395 *
396 * Note:
397 */
398size_t
399lex_level(void)
400{
401	size_t            cnt = 0;
402	struct FILE_INFO *ipf = lex_stack;
403
404	while (NULL != ipf) {
405		cnt++;
406		ipf = ipf->st_next;
407	}
408	return cnt;
409}
410
411/* check if the current input is from a file */
412int/*BOOL*/
413lex_from_file(void)
414{
415	return (NULL != lex_stack) && (NULL != lex_stack->fpi);
416}
417
418struct FILE_INFO *
419lex_current()
420{
421	/* this became so simple, it could be a macro. But then,
422	 * lex_stack needed to be global...
423	 */
424	return lex_stack;
425}
426
427
428/* STATE MACHINES
429 * --------------
430 */
431
432/* Keywords */
433static int
434is_keyword(
435	char *lexeme,
436	follby *pfollowedby
437	)
438{
439	follby fb;
440	int curr_s;		/* current state index */
441	int token;
442	int i;
443
444	curr_s = SCANNER_INIT_S;
445	token = 0;
446
447	for (i = 0; lexeme[i]; i++) {
448		while (curr_s && (lexeme[i] != SS_CH(sst[curr_s])))
449			curr_s = SS_OTHER_N(sst[curr_s]);
450
451		if (curr_s && (lexeme[i] == SS_CH(sst[curr_s]))) {
452			if ('\0' == lexeme[i + 1]
453			    && FOLLBY_NON_ACCEPTING
454			       != SS_FB(sst[curr_s])) {
455				fb = SS_FB(sst[curr_s]);
456				*pfollowedby = fb;
457				token = curr_s;
458				break;
459			}
460			curr_s = SS_MATCH_N(sst[curr_s]);
461		} else
462			break;
463	}
464
465	return token;
466}
467
468
469/* Integer */
470static int
471is_integer(
472	char *lexeme
473	)
474{
475	int	i;
476	int	is_neg;
477	u_int	u_val;
478
479	i = 0;
480
481	/* Allow a leading minus sign */
482	if (lexeme[i] == '-') {
483		i++;
484		is_neg = TRUE;
485	} else {
486		is_neg = FALSE;
487	}
488
489	/* Check that all the remaining characters are digits */
490	for (; lexeme[i] != '\0'; i++) {
491		if (!isdigit((u_char)lexeme[i]))
492			return FALSE;
493	}
494
495	if (is_neg)
496		return TRUE;
497
498	/* Reject numbers that fit in unsigned but not in signed int */
499	if (1 == sscanf(lexeme, "%u", &u_val))
500		return (u_val <= INT_MAX);
501	else
502		return FALSE;
503}
504
505
506/* U_int -- assumes is_integer() has returned FALSE */
507static int
508is_u_int(
509	char *lexeme
510	)
511{
512	int	i;
513	int	is_hex;
514
515	i = 0;
516	if ('0' == lexeme[i] && 'x' == tolower((u_char)lexeme[i + 1])) {
517		i += 2;
518		is_hex = TRUE;
519	} else {
520		is_hex = FALSE;
521	}
522
523	/* Check that all the remaining characters are digits */
524	for (; lexeme[i] != '\0'; i++) {
525		if (is_hex && !isxdigit((u_char)lexeme[i]))
526			return FALSE;
527		if (!is_hex && !isdigit((u_char)lexeme[i]))
528			return FALSE;
529	}
530
531	return TRUE;
532}
533
534
535/* Double */
536static int
537is_double(
538	char *lexeme
539	)
540{
541	u_int num_digits = 0;  /* Number of digits read */
542	u_int i;
543
544	i = 0;
545
546	/* Check for an optional '+' or '-' */
547	if ('+' == lexeme[i] || '-' == lexeme[i])
548		i++;
549
550	/* Read the integer part */
551	for (; lexeme[i] && isdigit((u_char)lexeme[i]); i++)
552		num_digits++;
553
554	/* Check for the optional decimal point */
555	if ('.' == lexeme[i]) {
556		i++;
557		/* Check for any digits after the decimal point */
558		for (; lexeme[i] && isdigit((u_char)lexeme[i]); i++)
559			num_digits++;
560	}
561
562	/*
563	 * The number of digits in both the decimal part and the
564	 * fraction part must not be zero at this point
565	 */
566	if (!num_digits)
567		return 0;
568
569	/* Check if we are done */
570	if (!lexeme[i])
571		return 1;
572
573	/* There is still more input, read the exponent */
574	if ('e' == tolower((u_char)lexeme[i]))
575		i++;
576	else
577		return 0;
578
579	/* Read an optional Sign */
580	if ('+' == lexeme[i] || '-' == lexeme[i])
581		i++;
582
583	/* Now read the exponent part */
584	while (lexeme[i] && isdigit((u_char)lexeme[i]))
585		i++;
586
587	/* Check if we are done */
588	if (!lexeme[i])
589		return 1;
590	else
591		return 0;
592}
593
594
595/* is_special() - Test whether a character is a token */
596static inline int
597is_special(
598	int ch
599	)
600{
601	return strchr(special_chars, ch) != NULL;
602}
603
604
605static int
606is_EOC(
607	int ch
608	)
609{
610	if ((old_config_style && (ch == '\n')) ||
611	    (!old_config_style && (ch == ';')))
612		return 1;
613	return 0;
614}
615
616
617char *
618quote_if_needed(char *str)
619{
620	char *ret;
621	size_t len;
622	size_t octets;
623
624	len = strlen(str);
625	octets = len + 2 + 1;
626	ret = emalloc(octets);
627	if ('"' != str[0]
628	    && (strcspn(str, special_chars) < len
629		|| strchr(str, ' ') != NULL)) {
630		snprintf(ret, octets, "\"%s\"", str);
631	} else
632		strlcpy(ret, str, octets);
633
634	return ret;
635}
636
637
638static int
639create_string_token(
640	char *lexeme
641	)
642{
643	char *pch;
644
645	/*
646	 * ignore end of line whitespace
647	 */
648	pch = lexeme;
649	while (*pch && isspace((u_char)*pch))
650		pch++;
651
652	if (!*pch) {
653		yylval.Integer = T_EOC;
654		return yylval.Integer;
655	}
656
657	yylval.String = estrdup(lexeme);
658	return T_String;
659}
660
661
662/*
663 * yylex() - function that does the actual scanning.
664 * Bison expects this function to be called yylex and for it to take no
665 * input and return an int.
666 * Conceptually yylex "returns" yylval as well as the actual return
667 * value representing the token or type.
668 */
669int
670yylex(void)
671{
672	static follby	followedby = FOLLBY_TOKEN;
673	size_t		i;
674	int		instring;
675	int		yylval_was_set;
676	int		converted;
677	int		token;		/* The return value */
678	int		ch;
679
680	instring = FALSE;
681	yylval_was_set = FALSE;
682
683	do {
684		/* Ignore whitespace at the beginning */
685		while (EOF != (ch = lex_getch(lex_stack)) &&
686		       isspace(ch) &&
687		       !is_EOC(ch))
688
689			; /* Null Statement */
690
691		if (EOF == ch) {
692
693			if ( ! lex_pop_file())
694				return 0;
695			token = T_EOC;
696			goto normal_return;
697
698		} else if (is_EOC(ch)) {
699
700			/* end FOLLBY_STRINGS_TO_EOC effect */
701			followedby = FOLLBY_TOKEN;
702			token = T_EOC;
703			goto normal_return;
704
705		} else if (is_special(ch) && FOLLBY_TOKEN == followedby) {
706			/* special chars are their own token values */
707			token = ch;
708			/*
709			 * '=' outside simulator configuration implies
710			 * a single string following as in:
711			 * setvar Owner = "The Boss" default
712			 */
713			if ('=' == ch && old_config_style)
714				followedby = FOLLBY_STRING;
715			yytext[0] = (char)ch;
716			yytext[1] = '\0';
717			goto normal_return;
718		} else
719			lex_ungetch(ch, lex_stack);
720
721		/* save the position of start of the token */
722		lex_stack->tokpos = lex_stack->curpos;
723
724		/* Read in the lexeme */
725		i = 0;
726		while (EOF != (ch = lex_getch(lex_stack))) {
727
728			yytext[i] = (char)ch;
729
730			/* Break on whitespace or a special character */
731			if (isspace(ch) || is_EOC(ch)
732			    || '"' == ch
733			    || (FOLLBY_TOKEN == followedby
734				&& is_special(ch)))
735				break;
736
737			/* Read the rest of the line on reading a start
738			   of comment character */
739			if ('#' == ch) {
740				while (EOF != (ch = lex_getch(lex_stack))
741				       && '\n' != ch)
742					; /* Null Statement */
743				break;
744			}
745
746			i++;
747			if (i >= COUNTOF(yytext))
748				goto lex_too_long;
749		}
750		/* Pick up all of the string inside between " marks, to
751		 * end of line.  If we make it to EOL without a
752		 * terminating " assume it for them.
753		 *
754		 * XXX - HMS: I'm not sure we want to assume the closing "
755		 */
756		if ('"' == ch) {
757			instring = TRUE;
758			while (EOF != (ch = lex_getch(lex_stack)) &&
759			       ch != '"' && ch != '\n') {
760				yytext[i++] = (char)ch;
761				if (i >= COUNTOF(yytext))
762					goto lex_too_long;
763			}
764			/*
765			 * yytext[i] will be pushed back as not part of
766			 * this lexeme, but any closing quote should
767			 * not be pushed back, so we read another char.
768			 */
769			if ('"' == ch)
770				ch = lex_getch(lex_stack);
771		}
772		/* Pushback the last character read that is not a part
773		 * of this lexeme. This fails silently if ch is EOF,
774		 * but then the EOF condition persists and is handled on
775		 * the next turn by the include stack mechanism.
776		 */
777		lex_ungetch(ch, lex_stack);
778
779		yytext[i] = '\0';
780	} while (i == 0);
781
782	/* Now return the desired token */
783
784	/* First make sure that the parser is *not* expecting a string
785	 * as the next token (based on the previous token that was
786	 * returned) and that we haven't read a string.
787	 */
788
789	if (followedby == FOLLBY_TOKEN && !instring) {
790		token = is_keyword(yytext, &followedby);
791		if (token) {
792			/*
793			 * T_Server is exceptional as it forces the
794			 * following token to be a string in the
795			 * non-simulator parts of the configuration,
796			 * but in the simulator configuration section,
797			 * "server" is followed by "=" which must be
798			 * recognized as a token not a string.
799			 */
800			if (T_Server == token && !old_config_style)
801				followedby = FOLLBY_TOKEN;
802			goto normal_return;
803		} else if (is_integer(yytext)) {
804			yylval_was_set = TRUE;
805			errno = 0;
806			if ((yylval.Integer = strtol(yytext, NULL, 10)) == 0
807			    && ((errno == EINVAL) || (errno == ERANGE))) {
808				msyslog(LOG_ERR,
809					"Integer cannot be represented: %s",
810					yytext);
811				if (lex_from_file()) {
812					exit(1);
813				} else {
814					/* force end of parsing */
815					yylval.Integer = 0;
816					return 0;
817				}
818			}
819			token = T_Integer;
820			goto normal_return;
821		} else if (is_u_int(yytext)) {
822			yylval_was_set = TRUE;
823			if ('0' == yytext[0] &&
824			    'x' == tolower((unsigned long)yytext[1]))
825				converted = sscanf(&yytext[2], "%x",
826						   &yylval.U_int);
827			else
828				converted = sscanf(yytext, "%u",
829						   &yylval.U_int);
830			if (1 != converted) {
831				msyslog(LOG_ERR,
832					"U_int cannot be represented: %s",
833					yytext);
834				if (lex_from_file()) {
835					exit(1);
836				} else {
837					/* force end of parsing */
838					yylval.Integer = 0;
839					return 0;
840				}
841			}
842			token = T_U_int;
843			goto normal_return;
844		} else if (is_double(yytext)) {
845			yylval_was_set = TRUE;
846			errno = 0;
847			if ((yylval.Double = atof(yytext)) == 0 && errno == ERANGE) {
848				msyslog(LOG_ERR,
849					"Double too large to represent: %s",
850					yytext);
851				exit(1);
852			} else {
853				token = T_Double;
854				goto normal_return;
855			}
856		} else {
857			/* Default: Everything is a string */
858			yylval_was_set = TRUE;
859			token = create_string_token(yytext);
860			goto normal_return;
861		}
862	}
863
864	/*
865	 * Either followedby is not FOLLBY_TOKEN or this lexeme is part
866	 * of a string.  Hence, we need to return T_String.
867	 *
868	 * _Except_ we might have a -4 or -6 flag on a an association
869	 * configuration line (server, peer, pool, etc.).
870	 *
871	 * This is a terrible hack, but the grammar is ambiguous so we
872	 * don't have a choice.  [SK]
873	 *
874	 * The ambiguity is in the keyword scanner, not ntp_parser.y.
875	 * We do not require server addresses be quoted in ntp.conf,
876	 * complicating the scanner's job.  To avoid trying (and
877	 * failing) to match an IP address or DNS name to a keyword,
878	 * the association keywords use FOLLBY_STRING in the keyword
879	 * table, which tells the scanner to force the next token to be
880	 * a T_String, so it does not try to match a keyword but rather
881	 * expects a string when -4/-6 modifiers to server, peer, etc.
882	 * are encountered.
883	 * restrict -4 and restrict -6 parsing works correctly without
884	 * this hack, as restrict uses FOLLBY_TOKEN.  [DH]
885	 */
886	if ('-' == yytext[0]) {
887		if ('4' == yytext[1]) {
888			token = T_Ipv4_flag;
889			goto normal_return;
890		} else if ('6' == yytext[1]) {
891			token = T_Ipv6_flag;
892			goto normal_return;
893		}
894	}
895
896	if (FOLLBY_STRING == followedby)
897		followedby = FOLLBY_TOKEN;
898
899	yylval_was_set = TRUE;
900	token = create_string_token(yytext);
901
902normal_return:
903	if (T_EOC == token)
904		DPRINTF(4,("\t<end of command>\n"));
905	else
906		DPRINTF(4, ("yylex: lexeme '%s' -> %s\n", yytext,
907			    token_name(token)));
908
909	if (!yylval_was_set)
910		yylval.Integer = token;
911
912	return token;
913
914lex_too_long:
915	yytext[min(sizeof(yytext) - 1, 50)] = 0;
916	msyslog(LOG_ERR,
917		"configuration item on line %d longer than limit of %lu, began with '%s'",
918		lex_stack->curpos.nline, (u_long)min(sizeof(yytext) - 1, 50),
919		yytext);
920
921	/*
922	 * If we hit the length limit reading the startup configuration
923	 * file, abort.
924	 */
925	if (lex_from_file())
926		exit(sizeof(yytext) - 1);
927
928	/*
929	 * If it's runtime configuration via ntpq :config treat it as
930	 * if the configuration text ended before the too-long lexeme,
931	 * hostname, or string.
932	 */
933	yylval.Integer = 0;
934	return 0;
935}
936