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
37*f5f40dd6SCy Schubert #define MAX_LEXEME 128 /* 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 *
keyword(int token)702b15cb3dSCy Schubert keyword(
712b15cb3dSCy Schubert int token
722b15cb3dSCy Schubert )
732b15cb3dSCy Schubert {
742b15cb3dSCy Schubert size_t i;
752b15cb3dSCy Schubert const char *text;
762d4e511cSCy Schubert static char sbuf[64];
772b15cb3dSCy Schubert
782b15cb3dSCy Schubert i = token - LOWEST_KEYWORD_ID;
792b15cb3dSCy Schubert
802d4e511cSCy Schubert switch (token) {
812d4e511cSCy Schubert case T_ServerresponseFuzz:
822d4e511cSCy Schubert text = "serverresponse fuzz";
832d4e511cSCy Schubert break;
842b15cb3dSCy Schubert
852d4e511cSCy Schubert default:
862d4e511cSCy Schubert if (i < COUNTOF(keyword_text)) {
872d4e511cSCy Schubert text = keyword_text[i];
882d4e511cSCy Schubert } else {
892d4e511cSCy Schubert snprintf(sbuf, sizeof sbuf,
902d4e511cSCy Schubert "(keyword #%u not found)", token);
912d4e511cSCy Schubert text = sbuf;
922d4e511cSCy Schubert }
932d4e511cSCy Schubert }
942d4e511cSCy Schubert
952d4e511cSCy Schubert return text;
962b15cb3dSCy Schubert }
972b15cb3dSCy Schubert
982b15cb3dSCy Schubert
99276da39aSCy Schubert /* FILE & STRING BUFFER INTERFACE
100276da39aSCy Schubert * ------------------------------
101276da39aSCy Schubert *
102276da39aSCy Schubert * This set out as a couple of wrapper functions around the standard C
103276da39aSCy Schubert * fgetc and ungetc functions in order to include positional
104276da39aSCy Schubert * bookkeeping. Alas, this is no longer a good solution with nested
105276da39aSCy Schubert * input files and the possibility to send configuration commands via
106276da39aSCy Schubert * 'ntpdc' and 'ntpq'.
107276da39aSCy Schubert *
108276da39aSCy Schubert * Now there are a few functions to maintain a stack of nested input
109276da39aSCy Schubert * sources (though nesting is only allowd for disk files) and from the
110276da39aSCy Schubert * scanner / parser point of view there's no difference between both
111276da39aSCy Schubert * types of sources.
112276da39aSCy Schubert *
113276da39aSCy Schubert * The 'fgetc()' / 'ungetc()' replacements now operate on a FILE_INFO
114276da39aSCy Schubert * structure. Instead of trying different 'ungetc()' strategies for file
115276da39aSCy Schubert * and buffer based parsing, we keep the backup char in our own
116276da39aSCy Schubert * FILE_INFO structure. This is sufficient, as the parser does *not*
117276da39aSCy Schubert * jump around via 'seek' or the like, and there's no need to
118276da39aSCy Schubert * check/clear the backup store in other places than 'lex_getch()'.
1192b15cb3dSCy Schubert */
1202b15cb3dSCy Schubert
121276da39aSCy Schubert /*
122276da39aSCy Schubert * Allocate an info structure and attach it to a file.
123276da39aSCy Schubert *
124276da39aSCy Schubert * Note: When 'mode' is NULL, then the INFO block will be set up to
125276da39aSCy Schubert * contain a NULL file pointer, as suited for remote config command
126276da39aSCy Schubert * parsing. Otherwise having a NULL file pointer is considered an error,
127276da39aSCy Schubert * and a NULL info block pointer is returned to indicate failure!
128276da39aSCy Schubert *
129276da39aSCy Schubert * Note: We use a variable-sized structure to hold a copy of the file
130276da39aSCy Schubert * name (or, more proper, the input source description). This is more
131276da39aSCy Schubert * secure than keeping a reference to some other storage that might go
132276da39aSCy Schubert * out of scope.
133276da39aSCy Schubert */
134276da39aSCy Schubert static struct FILE_INFO *
lex_open(const char * path,const char * mode)135276da39aSCy Schubert lex_open(
1362b15cb3dSCy Schubert const char *path,
1372b15cb3dSCy Schubert const char *mode
1382b15cb3dSCy Schubert )
1392b15cb3dSCy Schubert {
140276da39aSCy Schubert struct FILE_INFO *stream;
141276da39aSCy Schubert size_t nnambuf;
1422b15cb3dSCy Schubert
143276da39aSCy Schubert nnambuf = strlen(path);
144276da39aSCy Schubert stream = emalloc_zero(sizeof(*stream) + nnambuf);
145276da39aSCy Schubert stream->curpos.nline = 1;
146276da39aSCy Schubert stream->backch = EOF;
147276da39aSCy Schubert /* copy name with memcpy -- trailing NUL already there! */
148276da39aSCy Schubert memcpy(stream->fname, path, nnambuf);
1492b15cb3dSCy Schubert
150276da39aSCy Schubert if (NULL != mode) {
151276da39aSCy Schubert stream->fpi = fopen(path, mode);
152276da39aSCy Schubert if (NULL == stream->fpi) {
153276da39aSCy Schubert free(stream);
154276da39aSCy Schubert stream = NULL;
1552b15cb3dSCy Schubert }
156276da39aSCy Schubert }
157276da39aSCy Schubert return stream;
1582b15cb3dSCy Schubert }
1592b15cb3dSCy Schubert
160276da39aSCy Schubert /* get next character from buffer or file. This will return any putback
161276da39aSCy Schubert * character first; it will also make sure the last line is at least
162276da39aSCy Schubert * virtually terminated with a '\n'.
163276da39aSCy Schubert */
164276da39aSCy Schubert static int
lex_getch(struct FILE_INFO * stream)165276da39aSCy Schubert lex_getch(
1662b15cb3dSCy Schubert struct FILE_INFO *stream
1672b15cb3dSCy Schubert )
1682b15cb3dSCy Schubert {
1692b15cb3dSCy Schubert int ch;
1702b15cb3dSCy Schubert
171276da39aSCy Schubert if (NULL == stream || stream->force_eof)
172276da39aSCy Schubert return EOF;
1732b15cb3dSCy Schubert
174276da39aSCy Schubert if (EOF != stream->backch) {
175276da39aSCy Schubert ch = stream->backch;
176276da39aSCy Schubert stream->backch = EOF;
177276da39aSCy Schubert if (stream->fpi)
178276da39aSCy Schubert conf_file_sum += ch;
17909100258SXin LI stream->curpos.ncol++;
180276da39aSCy Schubert } else if (stream->fpi) {
181276da39aSCy Schubert /* fetch next 7-bit ASCII char (or EOF) from file */
182276da39aSCy Schubert while ((ch = fgetc(stream->fpi)) != EOF && ch > SCHAR_MAX)
183276da39aSCy Schubert stream->curpos.ncol++;
1842b15cb3dSCy Schubert if (EOF != ch) {
185276da39aSCy Schubert conf_file_sum += ch;
186276da39aSCy Schubert stream->curpos.ncol++;
1872b15cb3dSCy Schubert }
188276da39aSCy Schubert } else {
189276da39aSCy Schubert /* fetch next 7-bit ASCII char from buffer */
190276da39aSCy Schubert const char * scan;
191276da39aSCy Schubert scan = &remote_config.buffer[remote_config.pos];
192276da39aSCy Schubert while ((ch = (u_char)*scan) > SCHAR_MAX) {
193276da39aSCy Schubert scan++;
194276da39aSCy Schubert stream->curpos.ncol++;
195276da39aSCy Schubert }
196276da39aSCy Schubert if ('\0' != ch) {
197276da39aSCy Schubert scan++;
198276da39aSCy Schubert stream->curpos.ncol++;
199276da39aSCy Schubert } else {
200276da39aSCy Schubert ch = EOF;
201276da39aSCy Schubert }
202276da39aSCy Schubert remote_config.pos = (int)(scan - remote_config.buffer);
203276da39aSCy Schubert }
204276da39aSCy Schubert
205276da39aSCy Schubert /* If the last line ends without '\n', generate one. This
206276da39aSCy Schubert * happens most likely on Windows, where editors often have a
207276da39aSCy Schubert * sloppy concept of a line.
208276da39aSCy Schubert */
209276da39aSCy Schubert if (EOF == ch && stream->curpos.ncol != 0)
210276da39aSCy Schubert ch = '\n';
211276da39aSCy Schubert
212276da39aSCy Schubert /* update scan position tallies */
213276da39aSCy Schubert if (ch == '\n') {
214276da39aSCy Schubert stream->bakpos = stream->curpos;
215276da39aSCy Schubert stream->curpos.nline++;
216276da39aSCy Schubert stream->curpos.ncol = 0;
2172b15cb3dSCy Schubert }
2182b15cb3dSCy Schubert
2192b15cb3dSCy Schubert return ch;
2202b15cb3dSCy Schubert }
2212b15cb3dSCy Schubert
222276da39aSCy Schubert /* Note: lex_ungetch will fail to track more than one line of push
223276da39aSCy Schubert * back. But since it guarantees only one char of back storage anyway,
224276da39aSCy Schubert * this should not be a problem.
2252b15cb3dSCy Schubert */
226276da39aSCy Schubert static int
lex_ungetch(int ch,struct FILE_INFO * stream)227276da39aSCy Schubert lex_ungetch(
2282b15cb3dSCy Schubert int ch,
2292b15cb3dSCy Schubert struct FILE_INFO *stream
2302b15cb3dSCy Schubert )
2312b15cb3dSCy Schubert {
232276da39aSCy Schubert /* check preconditions */
233276da39aSCy Schubert if (NULL == stream || stream->force_eof)
234276da39aSCy Schubert return EOF;
235276da39aSCy Schubert if (EOF != stream->backch || EOF == ch)
236276da39aSCy Schubert return EOF;
237276da39aSCy Schubert
238276da39aSCy Schubert /* keep for later reference and update checksum */
239276da39aSCy Schubert stream->backch = (u_char)ch;
240276da39aSCy Schubert if (stream->fpi)
241276da39aSCy Schubert conf_file_sum -= stream->backch;
242276da39aSCy Schubert
243276da39aSCy Schubert /* update position */
244276da39aSCy Schubert if (stream->backch == '\n') {
245276da39aSCy Schubert stream->curpos = stream->bakpos;
246276da39aSCy Schubert stream->bakpos.ncol = -1;
2472b15cb3dSCy Schubert }
248276da39aSCy Schubert stream->curpos.ncol--;
249276da39aSCy Schubert return stream->backch;
2502b15cb3dSCy Schubert }
2512b15cb3dSCy Schubert
252276da39aSCy Schubert /* dispose of an input structure. If the file pointer is not NULL, close
253276da39aSCy Schubert * the file. This function does not check the result of 'fclose()'.
254276da39aSCy Schubert */
255276da39aSCy Schubert static void
lex_close(struct FILE_INFO * stream)256276da39aSCy Schubert lex_close(
2572b15cb3dSCy Schubert struct FILE_INFO *stream
2582b15cb3dSCy Schubert )
2592b15cb3dSCy Schubert {
260276da39aSCy Schubert if (NULL != stream) {
261276da39aSCy Schubert if (NULL != stream->fpi)
262276da39aSCy Schubert fclose(stream->fpi);
2632b15cb3dSCy Schubert free(stream);
264276da39aSCy Schubert }
2652b15cb3dSCy Schubert }
2662b15cb3dSCy Schubert
267276da39aSCy Schubert /* INPUT STACK
268276da39aSCy Schubert * -----------
2692b15cb3dSCy Schubert *
270276da39aSCy Schubert * Nested input sources are a bit tricky at first glance. We deal with
271276da39aSCy Schubert * this problem using a stack of input sources, that is, a forward
272276da39aSCy Schubert * linked list of FILE_INFO structs.
273276da39aSCy Schubert *
274276da39aSCy Schubert * This stack is never empty during parsing; while an encounter with EOF
275276da39aSCy Schubert * can and will remove nested input sources, removing the last element
276276da39aSCy Schubert * in the stack will not work during parsing, and the EOF condition of
277276da39aSCy Schubert * the outermost input file remains until the parser folds up.
2782b15cb3dSCy Schubert */
2792b15cb3dSCy Schubert
280276da39aSCy Schubert static struct FILE_INFO *
drop_stack_do(struct FILE_INFO * head)281*f5f40dd6SCy Schubert drop_stack_do(
282276da39aSCy Schubert struct FILE_INFO * head
2832b15cb3dSCy Schubert )
2842b15cb3dSCy Schubert {
285276da39aSCy Schubert struct FILE_INFO * tail;
286276da39aSCy Schubert while (NULL != head) {
287276da39aSCy Schubert tail = head->st_next;
288276da39aSCy Schubert lex_close(head);
289276da39aSCy Schubert head = tail;
2902b15cb3dSCy Schubert }
291276da39aSCy Schubert return head;
2922b15cb3dSCy Schubert }
2932b15cb3dSCy Schubert
294276da39aSCy Schubert
295276da39aSCy Schubert
296276da39aSCy Schubert /* Create a singleton input source on an empty lexer stack. This will
297276da39aSCy Schubert * fail if there is already an input source, or if the underlying disk
298276da39aSCy Schubert * file cannot be opened.
299276da39aSCy Schubert *
300276da39aSCy Schubert * Returns TRUE if a new input object was successfully created.
301276da39aSCy Schubert */
302276da39aSCy Schubert int/*BOOL*/
lex_init_stack(const char * path,const char * mode)303276da39aSCy Schubert lex_init_stack(
304276da39aSCy Schubert const char * path,
305276da39aSCy Schubert const char * mode
3062b15cb3dSCy Schubert )
3072b15cb3dSCy Schubert {
308276da39aSCy Schubert if (NULL != lex_stack || NULL == path)
309276da39aSCy Schubert return FALSE;
3102b15cb3dSCy Schubert
311276da39aSCy Schubert lex_stack = lex_open(path, mode);
312276da39aSCy Schubert return (NULL != lex_stack);
3132b15cb3dSCy Schubert }
3142b15cb3dSCy Schubert
315276da39aSCy Schubert /* This removes *all* input sources from the stack, leaving the head
316276da39aSCy Schubert * pointer as NULL. Any attempt to parse in that state is likely to bomb
317276da39aSCy Schubert * with segmentation faults or the like.
318276da39aSCy Schubert *
319276da39aSCy Schubert * In other words: Use this to clean up after parsing, and do not parse
320276da39aSCy Schubert * anything until the next 'lex_init_stack()' succeeded.
321276da39aSCy Schubert */
322276da39aSCy Schubert void
lex_drop_stack(void)323*f5f40dd6SCy Schubert lex_drop_stack(void)
324276da39aSCy Schubert {
325*f5f40dd6SCy Schubert lex_stack = drop_stack_do(lex_stack);
326276da39aSCy Schubert }
327276da39aSCy Schubert
328276da39aSCy Schubert /* Flush the lexer input stack: This will nip all input objects on the
329276da39aSCy Schubert * stack (but keeps the current top-of-stack) and marks the top-of-stack
330276da39aSCy Schubert * as inactive. Any further calls to lex_getch yield only EOF, and it's
331276da39aSCy Schubert * no longer possible to push something back.
332276da39aSCy Schubert *
333276da39aSCy Schubert * Returns TRUE if there is a head element (top-of-stack) that was not
334276da39aSCy Schubert * in the force-eof mode before this call.
335276da39aSCy Schubert */
336276da39aSCy Schubert int/*BOOL*/
lex_flush_stack(void)337*f5f40dd6SCy Schubert lex_flush_stack(void)
338276da39aSCy Schubert {
339276da39aSCy Schubert int retv = FALSE;
340276da39aSCy Schubert
341276da39aSCy Schubert if (NULL != lex_stack) {
342276da39aSCy Schubert retv = !lex_stack->force_eof;
343276da39aSCy Schubert lex_stack->force_eof = TRUE;
344*f5f40dd6SCy Schubert lex_stack->st_next = drop_stack_do(
345276da39aSCy Schubert lex_stack->st_next);
346276da39aSCy Schubert }
347276da39aSCy Schubert return retv;
348276da39aSCy Schubert }
349276da39aSCy Schubert
350276da39aSCy Schubert /* Push another file on the parsing stack. If the mode is NULL, create a
351276da39aSCy Schubert * FILE_INFO suitable for in-memory parsing; otherwise, create a
352276da39aSCy Schubert * FILE_INFO that is bound to a local/disc file. Note that 'path' must
353276da39aSCy Schubert * not be NULL, or the function will fail.
354276da39aSCy Schubert *
355276da39aSCy Schubert * Returns TRUE if a new info record was pushed onto the stack.
356276da39aSCy Schubert */
lex_push_file(const char * path,const char * mode)357276da39aSCy Schubert int/*BOOL*/ lex_push_file(
358276da39aSCy Schubert const char * path,
359276da39aSCy Schubert const char * mode
360276da39aSCy Schubert )
361276da39aSCy Schubert {
362276da39aSCy Schubert struct FILE_INFO * next = NULL;
363276da39aSCy Schubert
364276da39aSCy Schubert if (NULL != path) {
365276da39aSCy Schubert next = lex_open(path, mode);
366276da39aSCy Schubert if (NULL != next) {
367276da39aSCy Schubert next->st_next = lex_stack;
368276da39aSCy Schubert lex_stack = next;
369276da39aSCy Schubert }
370276da39aSCy Schubert }
371276da39aSCy Schubert return (NULL != next);
372276da39aSCy Schubert }
373276da39aSCy Schubert
374276da39aSCy Schubert /* Pop, close & free the top of the include stack, unless the stack
375276da39aSCy Schubert * contains only a singleton input object. In that case the function
376276da39aSCy Schubert * fails, because the parser does not expect the input stack to be
377276da39aSCy Schubert * empty.
378276da39aSCy Schubert *
379276da39aSCy Schubert * Returns TRUE if an object was successfuly popped from the stack.
380276da39aSCy Schubert */
381276da39aSCy Schubert int/*BOOL*/
lex_pop_file(void)382276da39aSCy Schubert lex_pop_file(void)
383276da39aSCy Schubert {
384276da39aSCy Schubert struct FILE_INFO * head = lex_stack;
385276da39aSCy Schubert struct FILE_INFO * tail = NULL;
386276da39aSCy Schubert
387276da39aSCy Schubert if (NULL != head) {
388276da39aSCy Schubert tail = head->st_next;
389276da39aSCy Schubert if (NULL != tail) {
390276da39aSCy Schubert lex_stack = tail;
391276da39aSCy Schubert lex_close(head);
392276da39aSCy Schubert }
393276da39aSCy Schubert }
394276da39aSCy Schubert return (NULL != tail);
395276da39aSCy Schubert }
396276da39aSCy Schubert
397276da39aSCy Schubert /* Get include nesting level. This currently loops over the stack and
398276da39aSCy Schubert * counts elements; but since this is of concern only with an include
399276da39aSCy Schubert * statement and the nesting depth has a small limit, there's no
400276da39aSCy Schubert * bottleneck expected here.
401276da39aSCy Schubert *
402276da39aSCy Schubert * Returns the nesting level of includes, that is, the current depth of
403276da39aSCy Schubert * the lexer input stack.
404276da39aSCy Schubert *
405276da39aSCy Schubert * Note:
406276da39aSCy Schubert */
407276da39aSCy Schubert size_t
lex_level(void)408276da39aSCy Schubert lex_level(void)
409276da39aSCy Schubert {
410276da39aSCy Schubert size_t cnt = 0;
411276da39aSCy Schubert struct FILE_INFO *ipf = lex_stack;
412276da39aSCy Schubert
413276da39aSCy Schubert while (NULL != ipf) {
414276da39aSCy Schubert cnt++;
415276da39aSCy Schubert ipf = ipf->st_next;
416276da39aSCy Schubert }
417276da39aSCy Schubert return cnt;
418276da39aSCy Schubert }
419276da39aSCy Schubert
420276da39aSCy Schubert /* check if the current input is from a file */
421276da39aSCy Schubert int/*BOOL*/
lex_from_file(void)422276da39aSCy Schubert lex_from_file(void)
423276da39aSCy Schubert {
424276da39aSCy Schubert return (NULL != lex_stack) && (NULL != lex_stack->fpi);
425276da39aSCy Schubert }
426276da39aSCy Schubert
427276da39aSCy Schubert struct FILE_INFO *
lex_current(void)428*f5f40dd6SCy Schubert lex_current(void)
429276da39aSCy Schubert {
430276da39aSCy Schubert /* this became so simple, it could be a macro. But then,
431276da39aSCy Schubert * lex_stack needed to be global...
432276da39aSCy Schubert */
433276da39aSCy Schubert return lex_stack;
434276da39aSCy Schubert }
4352b15cb3dSCy Schubert
4362b15cb3dSCy Schubert
4372b15cb3dSCy Schubert /* STATE MACHINES
4382b15cb3dSCy Schubert * --------------
4392b15cb3dSCy Schubert */
4402b15cb3dSCy Schubert
4412b15cb3dSCy Schubert /* Keywords */
4422b15cb3dSCy Schubert static int
is_keyword(char * lexeme,follby * pfollowedby)4432b15cb3dSCy Schubert is_keyword(
4442b15cb3dSCy Schubert char *lexeme,
4452b15cb3dSCy Schubert follby *pfollowedby
4462b15cb3dSCy Schubert )
4472b15cb3dSCy Schubert {
4482b15cb3dSCy Schubert follby fb;
4492b15cb3dSCy Schubert int curr_s; /* current state index */
4502b15cb3dSCy Schubert int token;
4512b15cb3dSCy Schubert int i;
4522b15cb3dSCy Schubert
4532b15cb3dSCy Schubert curr_s = SCANNER_INIT_S;
4542b15cb3dSCy Schubert token = 0;
4552b15cb3dSCy Schubert
4562b15cb3dSCy Schubert for (i = 0; lexeme[i]; i++) {
4572b15cb3dSCy Schubert while (curr_s && (lexeme[i] != SS_CH(sst[curr_s])))
4582b15cb3dSCy Schubert curr_s = SS_OTHER_N(sst[curr_s]);
4592b15cb3dSCy Schubert
4602b15cb3dSCy Schubert if (curr_s && (lexeme[i] == SS_CH(sst[curr_s]))) {
4612b15cb3dSCy Schubert if ('\0' == lexeme[i + 1]
4622b15cb3dSCy Schubert && FOLLBY_NON_ACCEPTING
4632b15cb3dSCy Schubert != SS_FB(sst[curr_s])) {
4642b15cb3dSCy Schubert fb = SS_FB(sst[curr_s]);
4652b15cb3dSCy Schubert *pfollowedby = fb;
4662b15cb3dSCy Schubert token = curr_s;
4672b15cb3dSCy Schubert break;
4682b15cb3dSCy Schubert }
4692b15cb3dSCy Schubert curr_s = SS_MATCH_N(sst[curr_s]);
4702b15cb3dSCy Schubert } else
4712b15cb3dSCy Schubert break;
4722b15cb3dSCy Schubert }
4732b15cb3dSCy Schubert
4742b15cb3dSCy Schubert return token;
4752b15cb3dSCy Schubert }
4762b15cb3dSCy Schubert
4772b15cb3dSCy Schubert
4782b15cb3dSCy Schubert /* Integer */
4792b15cb3dSCy Schubert static int
is_integer(char * lexeme)4802b15cb3dSCy Schubert is_integer(
4812b15cb3dSCy Schubert char *lexeme
4822b15cb3dSCy Schubert )
4832b15cb3dSCy Schubert {
4842b15cb3dSCy Schubert int i;
4852b15cb3dSCy Schubert int is_neg;
4862b15cb3dSCy Schubert u_int u_val;
4872b15cb3dSCy Schubert
4882b15cb3dSCy Schubert i = 0;
4892b15cb3dSCy Schubert
4902b15cb3dSCy Schubert /* Allow a leading minus sign */
4912b15cb3dSCy Schubert if (lexeme[i] == '-') {
4922b15cb3dSCy Schubert i++;
4932b15cb3dSCy Schubert is_neg = TRUE;
4942b15cb3dSCy Schubert } else {
4952b15cb3dSCy Schubert is_neg = FALSE;
4962b15cb3dSCy Schubert }
4972b15cb3dSCy Schubert
4982b15cb3dSCy Schubert /* Check that all the remaining characters are digits */
4992b15cb3dSCy Schubert for (; lexeme[i] != '\0'; i++) {
500276da39aSCy Schubert if (!isdigit((u_char)lexeme[i]))
5012b15cb3dSCy Schubert return FALSE;
5022b15cb3dSCy Schubert }
5032b15cb3dSCy Schubert
5042b15cb3dSCy Schubert if (is_neg)
5052b15cb3dSCy Schubert return TRUE;
5062b15cb3dSCy Schubert
5072b15cb3dSCy Schubert /* Reject numbers that fit in unsigned but not in signed int */
5082b15cb3dSCy Schubert if (1 == sscanf(lexeme, "%u", &u_val))
5092b15cb3dSCy Schubert return (u_val <= INT_MAX);
5102b15cb3dSCy Schubert else
5112b15cb3dSCy Schubert return FALSE;
5122b15cb3dSCy Schubert }
5132b15cb3dSCy Schubert
5142b15cb3dSCy Schubert
5152b15cb3dSCy Schubert /* U_int -- assumes is_integer() has returned FALSE */
5162b15cb3dSCy Schubert static int
is_u_int(char * lexeme)5172b15cb3dSCy Schubert is_u_int(
5182b15cb3dSCy Schubert char *lexeme
5192b15cb3dSCy Schubert )
5202b15cb3dSCy Schubert {
5212b15cb3dSCy Schubert int i;
5222b15cb3dSCy Schubert int is_hex;
5232b15cb3dSCy Schubert
5242b15cb3dSCy Schubert i = 0;
525276da39aSCy Schubert if ('0' == lexeme[i] && 'x' == tolower((u_char)lexeme[i + 1])) {
5262b15cb3dSCy Schubert i += 2;
5272b15cb3dSCy Schubert is_hex = TRUE;
5282b15cb3dSCy Schubert } else {
5292b15cb3dSCy Schubert is_hex = FALSE;
5302b15cb3dSCy Schubert }
5312b15cb3dSCy Schubert
5322b15cb3dSCy Schubert /* Check that all the remaining characters are digits */
5332b15cb3dSCy Schubert for (; lexeme[i] != '\0'; i++) {
534276da39aSCy Schubert if (is_hex && !isxdigit((u_char)lexeme[i]))
5352b15cb3dSCy Schubert return FALSE;
536276da39aSCy Schubert if (!is_hex && !isdigit((u_char)lexeme[i]))
5372b15cb3dSCy Schubert return FALSE;
5382b15cb3dSCy Schubert }
5392b15cb3dSCy Schubert
5402b15cb3dSCy Schubert return TRUE;
5412b15cb3dSCy Schubert }
5422b15cb3dSCy Schubert
5432b15cb3dSCy Schubert
5442b15cb3dSCy Schubert /* Double */
5452b15cb3dSCy Schubert static int
is_double(char * lexeme)5462b15cb3dSCy Schubert is_double(
5472b15cb3dSCy Schubert char *lexeme
5482b15cb3dSCy Schubert )
5492b15cb3dSCy Schubert {
5502b15cb3dSCy Schubert u_int num_digits = 0; /* Number of digits read */
5512b15cb3dSCy Schubert u_int i;
5522b15cb3dSCy Schubert
5532b15cb3dSCy Schubert i = 0;
5542b15cb3dSCy Schubert
5552b15cb3dSCy Schubert /* Check for an optional '+' or '-' */
5562b15cb3dSCy Schubert if ('+' == lexeme[i] || '-' == lexeme[i])
5572b15cb3dSCy Schubert i++;
5582b15cb3dSCy Schubert
5592b15cb3dSCy Schubert /* Read the integer part */
560276da39aSCy Schubert for (; lexeme[i] && isdigit((u_char)lexeme[i]); i++)
5612b15cb3dSCy Schubert num_digits++;
5622b15cb3dSCy Schubert
5632b15cb3dSCy Schubert /* Check for the optional decimal point */
5642b15cb3dSCy Schubert if ('.' == lexeme[i]) {
5652b15cb3dSCy Schubert i++;
5662b15cb3dSCy Schubert /* Check for any digits after the decimal point */
567276da39aSCy Schubert for (; lexeme[i] && isdigit((u_char)lexeme[i]); i++)
5682b15cb3dSCy Schubert num_digits++;
5692b15cb3dSCy Schubert }
5702b15cb3dSCy Schubert
5712b15cb3dSCy Schubert /*
5722b15cb3dSCy Schubert * The number of digits in both the decimal part and the
5732b15cb3dSCy Schubert * fraction part must not be zero at this point
5742b15cb3dSCy Schubert */
5752b15cb3dSCy Schubert if (!num_digits)
5762b15cb3dSCy Schubert return 0;
5772b15cb3dSCy Schubert
5782b15cb3dSCy Schubert /* Check if we are done */
5792b15cb3dSCy Schubert if (!lexeme[i])
5802b15cb3dSCy Schubert return 1;
5812b15cb3dSCy Schubert
5822b15cb3dSCy Schubert /* There is still more input, read the exponent */
583276da39aSCy Schubert if ('e' == tolower((u_char)lexeme[i]))
5842b15cb3dSCy Schubert i++;
5852b15cb3dSCy Schubert else
5862b15cb3dSCy Schubert return 0;
5872b15cb3dSCy Schubert
5882b15cb3dSCy Schubert /* Read an optional Sign */
5892b15cb3dSCy Schubert if ('+' == lexeme[i] || '-' == lexeme[i])
5902b15cb3dSCy Schubert i++;
5912b15cb3dSCy Schubert
5922b15cb3dSCy Schubert /* Now read the exponent part */
593276da39aSCy Schubert while (lexeme[i] && isdigit((u_char)lexeme[i]))
5942b15cb3dSCy Schubert i++;
5952b15cb3dSCy Schubert
5962b15cb3dSCy Schubert /* Check if we are done */
5972b15cb3dSCy Schubert if (!lexeme[i])
5982b15cb3dSCy Schubert return 1;
5992b15cb3dSCy Schubert else
6002b15cb3dSCy Schubert return 0;
6012b15cb3dSCy Schubert }
6022b15cb3dSCy Schubert
6032b15cb3dSCy Schubert
6042b15cb3dSCy Schubert /* is_special() - Test whether a character is a token */
6052b15cb3dSCy Schubert static inline int
is_special(int ch)6062b15cb3dSCy Schubert is_special(
6072b15cb3dSCy Schubert int ch
6082b15cb3dSCy Schubert )
6092b15cb3dSCy Schubert {
6102b15cb3dSCy Schubert return strchr(special_chars, ch) != NULL;
6112b15cb3dSCy Schubert }
6122b15cb3dSCy Schubert
6132b15cb3dSCy Schubert
6142b15cb3dSCy Schubert static int
is_EOC(int ch)6152b15cb3dSCy Schubert is_EOC(
6162b15cb3dSCy Schubert int ch
6172b15cb3dSCy Schubert )
6182b15cb3dSCy Schubert {
6192b15cb3dSCy Schubert if ((old_config_style && (ch == '\n')) ||
6202b15cb3dSCy Schubert (!old_config_style && (ch == ';')))
6212b15cb3dSCy Schubert return 1;
6222b15cb3dSCy Schubert return 0;
6232b15cb3dSCy Schubert }
6242b15cb3dSCy Schubert
6252b15cb3dSCy Schubert
6262b15cb3dSCy Schubert char *
quote_if_needed(char * str)6272b15cb3dSCy Schubert quote_if_needed(char *str)
6282b15cb3dSCy Schubert {
6292b15cb3dSCy Schubert char *ret;
6302b15cb3dSCy Schubert size_t len;
6312b15cb3dSCy Schubert size_t octets;
6322b15cb3dSCy Schubert
6332b15cb3dSCy Schubert len = strlen(str);
6342b15cb3dSCy Schubert octets = len + 2 + 1;
6352b15cb3dSCy Schubert ret = emalloc(octets);
6362b15cb3dSCy Schubert if ('"' != str[0]
6372b15cb3dSCy Schubert && (strcspn(str, special_chars) < len
6382b15cb3dSCy Schubert || strchr(str, ' ') != NULL)) {
6392b15cb3dSCy Schubert snprintf(ret, octets, "\"%s\"", str);
6402b15cb3dSCy Schubert } else
6412b15cb3dSCy Schubert strlcpy(ret, str, octets);
6422b15cb3dSCy Schubert
6432b15cb3dSCy Schubert return ret;
6442b15cb3dSCy Schubert }
6452b15cb3dSCy Schubert
6462b15cb3dSCy Schubert
6472b15cb3dSCy Schubert static int
create_string_token(char * lexeme)6482b15cb3dSCy Schubert create_string_token(
6492b15cb3dSCy Schubert char *lexeme
6502b15cb3dSCy Schubert )
6512b15cb3dSCy Schubert {
6522b15cb3dSCy Schubert char *pch;
6532b15cb3dSCy Schubert
6542b15cb3dSCy Schubert /*
6552b15cb3dSCy Schubert * ignore end of line whitespace
6562b15cb3dSCy Schubert */
6572b15cb3dSCy Schubert pch = lexeme;
658276da39aSCy Schubert while (*pch && isspace((u_char)*pch))
6592b15cb3dSCy Schubert pch++;
6602b15cb3dSCy Schubert
6612b15cb3dSCy Schubert if (!*pch) {
6622b15cb3dSCy Schubert yylval.Integer = T_EOC;
6632b15cb3dSCy Schubert return yylval.Integer;
6642b15cb3dSCy Schubert }
6652b15cb3dSCy Schubert
6662b15cb3dSCy Schubert yylval.String = estrdup(lexeme);
6672b15cb3dSCy Schubert return T_String;
6682b15cb3dSCy Schubert }
6692b15cb3dSCy Schubert
6702b15cb3dSCy Schubert
6712b15cb3dSCy Schubert /*
6722b15cb3dSCy Schubert * yylex() - function that does the actual scanning.
6732b15cb3dSCy Schubert * Bison expects this function to be called yylex and for it to take no
6742b15cb3dSCy Schubert * input and return an int.
6752b15cb3dSCy Schubert * Conceptually yylex "returns" yylval as well as the actual return
6762b15cb3dSCy Schubert * value representing the token or type.
6772b15cb3dSCy Schubert */
6782b15cb3dSCy Schubert int
yylex(void)679276da39aSCy Schubert yylex(void)
6802b15cb3dSCy Schubert {
6812b15cb3dSCy Schubert static follby followedby = FOLLBY_TOKEN;
68268ba7e87SXin LI size_t i;
6832b15cb3dSCy Schubert int instring;
6842b15cb3dSCy Schubert int yylval_was_set;
6852b15cb3dSCy Schubert int converted;
6862b15cb3dSCy Schubert int token; /* The return value */
6872b15cb3dSCy Schubert int ch;
6882b15cb3dSCy Schubert
6892b15cb3dSCy Schubert instring = FALSE;
6902b15cb3dSCy Schubert yylval_was_set = FALSE;
6912b15cb3dSCy Schubert
6922b15cb3dSCy Schubert do {
6932b15cb3dSCy Schubert /* Ignore whitespace at the beginning */
694276da39aSCy Schubert while (EOF != (ch = lex_getch(lex_stack)) &&
6952b15cb3dSCy Schubert isspace(ch) &&
6962b15cb3dSCy Schubert !is_EOC(ch))
697276da39aSCy Schubert
6982b15cb3dSCy Schubert ; /* Null Statement */
6992b15cb3dSCy Schubert
7002b15cb3dSCy Schubert if (EOF == ch) {
7012b15cb3dSCy Schubert
702276da39aSCy Schubert if ( ! lex_pop_file())
7032b15cb3dSCy Schubert return 0;
7042b15cb3dSCy Schubert token = T_EOC;
7052b15cb3dSCy Schubert goto normal_return;
7062b15cb3dSCy Schubert
7072b15cb3dSCy Schubert } else if (is_EOC(ch)) {
7082b15cb3dSCy Schubert
7092b15cb3dSCy Schubert /* end FOLLBY_STRINGS_TO_EOC effect */
7102b15cb3dSCy Schubert followedby = FOLLBY_TOKEN;
7112b15cb3dSCy Schubert token = T_EOC;
7122b15cb3dSCy Schubert goto normal_return;
7132b15cb3dSCy Schubert
7142b15cb3dSCy Schubert } else if (is_special(ch) && FOLLBY_TOKEN == followedby) {
7152b15cb3dSCy Schubert /* special chars are their own token values */
7162b15cb3dSCy Schubert token = ch;
7172b15cb3dSCy Schubert /*
7182b15cb3dSCy Schubert * '=' outside simulator configuration implies
7192b15cb3dSCy Schubert * a single string following as in:
7202b15cb3dSCy Schubert * setvar Owner = "The Boss" default
7212b15cb3dSCy Schubert */
7222b15cb3dSCy Schubert if ('=' == ch && old_config_style)
7232b15cb3dSCy Schubert followedby = FOLLBY_STRING;
7242b15cb3dSCy Schubert yytext[0] = (char)ch;
7252b15cb3dSCy Schubert yytext[1] = '\0';
7262b15cb3dSCy Schubert goto normal_return;
7272b15cb3dSCy Schubert } else
728276da39aSCy Schubert lex_ungetch(ch, lex_stack);
7292b15cb3dSCy Schubert
7302b15cb3dSCy Schubert /* save the position of start of the token */
731276da39aSCy Schubert lex_stack->tokpos = lex_stack->curpos;
7322b15cb3dSCy Schubert
7332b15cb3dSCy Schubert /* Read in the lexeme */
7342b15cb3dSCy Schubert i = 0;
735276da39aSCy Schubert while (EOF != (ch = lex_getch(lex_stack))) {
7362b15cb3dSCy Schubert
7372b15cb3dSCy Schubert yytext[i] = (char)ch;
7382b15cb3dSCy Schubert
7392b15cb3dSCy Schubert /* Break on whitespace or a special character */
7402b15cb3dSCy Schubert if (isspace(ch) || is_EOC(ch)
7412b15cb3dSCy Schubert || '"' == ch
7422b15cb3dSCy Schubert || (FOLLBY_TOKEN == followedby
7432b15cb3dSCy Schubert && is_special(ch)))
7442b15cb3dSCy Schubert break;
7452b15cb3dSCy Schubert
7462b15cb3dSCy Schubert /* Read the rest of the line on reading a start
7472b15cb3dSCy Schubert of comment character */
7482b15cb3dSCy Schubert if ('#' == ch) {
749276da39aSCy Schubert while (EOF != (ch = lex_getch(lex_stack))
7502b15cb3dSCy Schubert && '\n' != ch)
7512b15cb3dSCy Schubert ; /* Null Statement */
7522b15cb3dSCy Schubert break;
7532b15cb3dSCy Schubert }
7542b15cb3dSCy Schubert
7552b15cb3dSCy Schubert i++;
7562b15cb3dSCy Schubert if (i >= COUNTOF(yytext))
7572b15cb3dSCy Schubert goto lex_too_long;
7582b15cb3dSCy Schubert }
7592b15cb3dSCy Schubert /* Pick up all of the string inside between " marks, to
7602b15cb3dSCy Schubert * end of line. If we make it to EOL without a
7612b15cb3dSCy Schubert * terminating " assume it for them.
7622b15cb3dSCy Schubert *
7632b15cb3dSCy Schubert * XXX - HMS: I'm not sure we want to assume the closing "
7642b15cb3dSCy Schubert */
7652b15cb3dSCy Schubert if ('"' == ch) {
7662b15cb3dSCy Schubert instring = TRUE;
767276da39aSCy Schubert while (EOF != (ch = lex_getch(lex_stack)) &&
7682b15cb3dSCy Schubert ch != '"' && ch != '\n') {
7692b15cb3dSCy Schubert yytext[i++] = (char)ch;
7702b15cb3dSCy Schubert if (i >= COUNTOF(yytext))
7712b15cb3dSCy Schubert goto lex_too_long;
7722b15cb3dSCy Schubert }
7732b15cb3dSCy Schubert /*
7742b15cb3dSCy Schubert * yytext[i] will be pushed back as not part of
7752b15cb3dSCy Schubert * this lexeme, but any closing quote should
7762b15cb3dSCy Schubert * not be pushed back, so we read another char.
7772b15cb3dSCy Schubert */
7782b15cb3dSCy Schubert if ('"' == ch)
779276da39aSCy Schubert ch = lex_getch(lex_stack);
7802b15cb3dSCy Schubert }
7812b15cb3dSCy Schubert /* Pushback the last character read that is not a part
782276da39aSCy Schubert * of this lexeme. This fails silently if ch is EOF,
783276da39aSCy Schubert * but then the EOF condition persists and is handled on
784276da39aSCy Schubert * the next turn by the include stack mechanism.
7852b15cb3dSCy Schubert */
786276da39aSCy Schubert lex_ungetch(ch, lex_stack);
787276da39aSCy Schubert
7882b15cb3dSCy Schubert yytext[i] = '\0';
7892b15cb3dSCy Schubert } while (i == 0);
7902b15cb3dSCy Schubert
7912b15cb3dSCy Schubert /* Now return the desired token */
7922b15cb3dSCy Schubert
7932b15cb3dSCy Schubert /* First make sure that the parser is *not* expecting a string
7942b15cb3dSCy Schubert * as the next token (based on the previous token that was
7952b15cb3dSCy Schubert * returned) and that we haven't read a string.
7962b15cb3dSCy Schubert */
7972b15cb3dSCy Schubert
7982b15cb3dSCy Schubert if (followedby == FOLLBY_TOKEN && !instring) {
7992b15cb3dSCy Schubert token = is_keyword(yytext, &followedby);
8002b15cb3dSCy Schubert if (token) {
8012b15cb3dSCy Schubert /*
8022b15cb3dSCy Schubert * T_Server is exceptional as it forces the
8032b15cb3dSCy Schubert * following token to be a string in the
8042b15cb3dSCy Schubert * non-simulator parts of the configuration,
8052b15cb3dSCy Schubert * but in the simulator configuration section,
8062b15cb3dSCy Schubert * "server" is followed by "=" which must be
8072b15cb3dSCy Schubert * recognized as a token not a string.
8082b15cb3dSCy Schubert */
8092b15cb3dSCy Schubert if (T_Server == token && !old_config_style)
8102b15cb3dSCy Schubert followedby = FOLLBY_TOKEN;
8112b15cb3dSCy Schubert goto normal_return;
8122b15cb3dSCy Schubert } else if (is_integer(yytext)) {
8132b15cb3dSCy Schubert yylval_was_set = TRUE;
8142b15cb3dSCy Schubert errno = 0;
8152b15cb3dSCy Schubert if ((yylval.Integer = strtol(yytext, NULL, 10)) == 0
8162b15cb3dSCy Schubert && ((errno == EINVAL) || (errno == ERANGE))) {
8172b15cb3dSCy Schubert msyslog(LOG_ERR,
8182b15cb3dSCy Schubert "Integer cannot be represented: %s",
8192b15cb3dSCy Schubert yytext);
820276da39aSCy Schubert if (lex_from_file()) {
8212b15cb3dSCy Schubert exit(1);
8222b15cb3dSCy Schubert } else {
8232b15cb3dSCy Schubert /* force end of parsing */
8242b15cb3dSCy Schubert yylval.Integer = 0;
8252b15cb3dSCy Schubert return 0;
8262b15cb3dSCy Schubert }
8272b15cb3dSCy Schubert }
8282b15cb3dSCy Schubert token = T_Integer;
8292b15cb3dSCy Schubert goto normal_return;
8302b15cb3dSCy Schubert } else if (is_u_int(yytext)) {
8312b15cb3dSCy Schubert yylval_was_set = TRUE;
8322b15cb3dSCy Schubert if ('0' == yytext[0] &&
833276da39aSCy Schubert 'x' == tolower((unsigned long)yytext[1]))
8342b15cb3dSCy Schubert converted = sscanf(&yytext[2], "%x",
8352b15cb3dSCy Schubert &yylval.U_int);
8362b15cb3dSCy Schubert else
8372b15cb3dSCy Schubert converted = sscanf(yytext, "%u",
8382b15cb3dSCy Schubert &yylval.U_int);
8392b15cb3dSCy Schubert if (1 != converted) {
8402b15cb3dSCy Schubert msyslog(LOG_ERR,
8412b15cb3dSCy Schubert "U_int cannot be represented: %s",
8422b15cb3dSCy Schubert yytext);
843276da39aSCy Schubert if (lex_from_file()) {
8442b15cb3dSCy Schubert exit(1);
8452b15cb3dSCy Schubert } else {
8462b15cb3dSCy Schubert /* force end of parsing */
8472b15cb3dSCy Schubert yylval.Integer = 0;
8482b15cb3dSCy Schubert return 0;
8492b15cb3dSCy Schubert }
8502b15cb3dSCy Schubert }
8512b15cb3dSCy Schubert token = T_U_int;
8522b15cb3dSCy Schubert goto normal_return;
8532b15cb3dSCy Schubert } else if (is_double(yytext)) {
8542b15cb3dSCy Schubert yylval_was_set = TRUE;
8552b15cb3dSCy Schubert errno = 0;
8562b15cb3dSCy Schubert if ((yylval.Double = atof(yytext)) == 0 && errno == ERANGE) {
8572b15cb3dSCy Schubert msyslog(LOG_ERR,
8582b15cb3dSCy Schubert "Double too large to represent: %s",
8592b15cb3dSCy Schubert yytext);
8602b15cb3dSCy Schubert exit(1);
8612b15cb3dSCy Schubert } else {
8622b15cb3dSCy Schubert token = T_Double;
8632b15cb3dSCy Schubert goto normal_return;
8642b15cb3dSCy Schubert }
8652b15cb3dSCy Schubert } else {
8662b15cb3dSCy Schubert /* Default: Everything is a string */
8672b15cb3dSCy Schubert yylval_was_set = TRUE;
8682b15cb3dSCy Schubert token = create_string_token(yytext);
8692b15cb3dSCy Schubert goto normal_return;
8702b15cb3dSCy Schubert }
8712b15cb3dSCy Schubert }
8722b15cb3dSCy Schubert
8732b15cb3dSCy Schubert /*
8742b15cb3dSCy Schubert * Either followedby is not FOLLBY_TOKEN or this lexeme is part
8752b15cb3dSCy Schubert * of a string. Hence, we need to return T_String.
8762b15cb3dSCy Schubert *
8772b15cb3dSCy Schubert * _Except_ we might have a -4 or -6 flag on a an association
8782b15cb3dSCy Schubert * configuration line (server, peer, pool, etc.).
8792b15cb3dSCy Schubert *
8802b15cb3dSCy Schubert * This is a terrible hack, but the grammar is ambiguous so we
8812b15cb3dSCy Schubert * don't have a choice. [SK]
8822b15cb3dSCy Schubert *
8832b15cb3dSCy Schubert * The ambiguity is in the keyword scanner, not ntp_parser.y.
8842b15cb3dSCy Schubert * We do not require server addresses be quoted in ntp.conf,
8852b15cb3dSCy Schubert * complicating the scanner's job. To avoid trying (and
8862b15cb3dSCy Schubert * failing) to match an IP address or DNS name to a keyword,
8872b15cb3dSCy Schubert * the association keywords use FOLLBY_STRING in the keyword
8882b15cb3dSCy Schubert * table, which tells the scanner to force the next token to be
8892b15cb3dSCy Schubert * a T_String, so it does not try to match a keyword but rather
8902b15cb3dSCy Schubert * expects a string when -4/-6 modifiers to server, peer, etc.
8912b15cb3dSCy Schubert * are encountered.
8922b15cb3dSCy Schubert * restrict -4 and restrict -6 parsing works correctly without
8932b15cb3dSCy Schubert * this hack, as restrict uses FOLLBY_TOKEN. [DH]
8942b15cb3dSCy Schubert */
8952b15cb3dSCy Schubert if ('-' == yytext[0]) {
8962b15cb3dSCy Schubert if ('4' == yytext[1]) {
8972b15cb3dSCy Schubert token = T_Ipv4_flag;
8982b15cb3dSCy Schubert goto normal_return;
8992b15cb3dSCy Schubert } else if ('6' == yytext[1]) {
9002b15cb3dSCy Schubert token = T_Ipv6_flag;
9012b15cb3dSCy Schubert goto normal_return;
9022b15cb3dSCy Schubert }
9032b15cb3dSCy Schubert }
9042b15cb3dSCy Schubert
9052b15cb3dSCy Schubert if (FOLLBY_STRING == followedby)
9062b15cb3dSCy Schubert followedby = FOLLBY_TOKEN;
9072b15cb3dSCy Schubert
9082b15cb3dSCy Schubert yylval_was_set = TRUE;
9092b15cb3dSCy Schubert token = create_string_token(yytext);
9102b15cb3dSCy Schubert
9112b15cb3dSCy Schubert normal_return:
9122b15cb3dSCy Schubert if (T_EOC == token)
913*f5f40dd6SCy Schubert DPRINTF(10, ("\t<end of command>\n"));
9142b15cb3dSCy Schubert else
915*f5f40dd6SCy Schubert DPRINTF(10, ("yylex: lexeme '%s' -> %s\n", yytext,
9162b15cb3dSCy Schubert token_name(token)));
9172b15cb3dSCy Schubert
9182b15cb3dSCy Schubert if (!yylval_was_set)
9192b15cb3dSCy Schubert yylval.Integer = token;
9202b15cb3dSCy Schubert
9212b15cb3dSCy Schubert return token;
9222b15cb3dSCy Schubert
9232b15cb3dSCy Schubert lex_too_long:
924*f5f40dd6SCy Schubert /*
925*f5f40dd6SCy Schubert * DLH: What is the purpose of the limit of 50?
926*f5f40dd6SCy Schubert * Is there any reason for yytext[] to be bigger?
927*f5f40dd6SCy Schubert */
9282b15cb3dSCy Schubert yytext[min(sizeof(yytext) - 1, 50)] = 0;
9292b15cb3dSCy Schubert msyslog(LOG_ERR,
9302b15cb3dSCy Schubert "configuration item on line %d longer than limit of %lu, began with '%s'",
931276da39aSCy Schubert lex_stack->curpos.nline, (u_long)min(sizeof(yytext) - 1, 50),
9322b15cb3dSCy Schubert yytext);
9332b15cb3dSCy Schubert
9342b15cb3dSCy Schubert /*
9352b15cb3dSCy Schubert * If we hit the length limit reading the startup configuration
9362b15cb3dSCy Schubert * file, abort.
9372b15cb3dSCy Schubert */
938276da39aSCy Schubert if (lex_from_file())
9392b15cb3dSCy Schubert exit(sizeof(yytext) - 1);
9402b15cb3dSCy Schubert
9412b15cb3dSCy Schubert /*
9422b15cb3dSCy Schubert * If it's runtime configuration via ntpq :config treat it as
9432b15cb3dSCy Schubert * if the configuration text ended before the too-long lexeme,
9442b15cb3dSCy Schubert * hostname, or string.
9452b15cb3dSCy Schubert */
9462b15cb3dSCy Schubert yylval.Integer = 0;
9472b15cb3dSCy Schubert return 0;
9482b15cb3dSCy Schubert }
949