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