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