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 * 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 * 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 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 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 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 * 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*/ 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 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*/ 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 */ 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*/ 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 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*/ 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 * 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 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 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 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 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 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 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 * 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 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 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