1*2b15cb3dSCy Schubert 2*2b15cb3dSCy Schubert /* ntp_scanner.c 3*2b15cb3dSCy Schubert * 4*2b15cb3dSCy Schubert * The source code for a simple lexical analyzer. 5*2b15cb3dSCy Schubert * 6*2b15cb3dSCy Schubert * Written By: Sachin Kamboj 7*2b15cb3dSCy Schubert * University of Delaware 8*2b15cb3dSCy Schubert * Newark, DE 19711 9*2b15cb3dSCy Schubert * Copyright (c) 2006 10*2b15cb3dSCy Schubert */ 11*2b15cb3dSCy Schubert 12*2b15cb3dSCy Schubert #ifdef HAVE_CONFIG_H 13*2b15cb3dSCy Schubert # include <config.h> 14*2b15cb3dSCy Schubert #endif 15*2b15cb3dSCy Schubert 16*2b15cb3dSCy Schubert #include <stdio.h> 17*2b15cb3dSCy Schubert #include <ctype.h> 18*2b15cb3dSCy Schubert #include <stdlib.h> 19*2b15cb3dSCy Schubert #include <errno.h> 20*2b15cb3dSCy Schubert #include <string.h> 21*2b15cb3dSCy Schubert 22*2b15cb3dSCy Schubert #include "ntpd.h" 23*2b15cb3dSCy Schubert #include "ntp_config.h" 24*2b15cb3dSCy Schubert #include "ntpsim.h" 25*2b15cb3dSCy Schubert #include "ntp_scanner.h" 26*2b15cb3dSCy Schubert #include "ntp_parser.h" 27*2b15cb3dSCy Schubert 28*2b15cb3dSCy Schubert /* ntp_keyword.h declares finite state machine and token text */ 29*2b15cb3dSCy Schubert #include "ntp_keyword.h" 30*2b15cb3dSCy Schubert 31*2b15cb3dSCy Schubert 32*2b15cb3dSCy Schubert 33*2b15cb3dSCy Schubert /* SCANNER GLOBAL VARIABLES 34*2b15cb3dSCy Schubert * ------------------------ 35*2b15cb3dSCy Schubert */ 36*2b15cb3dSCy Schubert 37*2b15cb3dSCy Schubert #define MAX_LEXEME (1024 + 1) /* The maximum size of a lexeme */ 38*2b15cb3dSCy Schubert char yytext[MAX_LEXEME]; /* Buffer for storing the input text/lexeme */ 39*2b15cb3dSCy Schubert u_int32 conf_file_sum; /* Simple sum of characters read */ 40*2b15cb3dSCy Schubert 41*2b15cb3dSCy Schubert 42*2b15cb3dSCy Schubert 43*2b15cb3dSCy Schubert 44*2b15cb3dSCy Schubert /* CONSTANTS 45*2b15cb3dSCy Schubert * --------- 46*2b15cb3dSCy Schubert */ 47*2b15cb3dSCy Schubert 48*2b15cb3dSCy Schubert 49*2b15cb3dSCy Schubert /* SCANNER GLOBAL VARIABLES 50*2b15cb3dSCy Schubert * ------------------------ 51*2b15cb3dSCy Schubert */ 52*2b15cb3dSCy Schubert const char special_chars[] = "{}(),;|="; 53*2b15cb3dSCy Schubert 54*2b15cb3dSCy Schubert 55*2b15cb3dSCy Schubert /* FUNCTIONS 56*2b15cb3dSCy Schubert * --------- 57*2b15cb3dSCy Schubert */ 58*2b15cb3dSCy Schubert 59*2b15cb3dSCy Schubert static int is_keyword(char *lexeme, follby *pfollowedby); 60*2b15cb3dSCy Schubert 61*2b15cb3dSCy Schubert 62*2b15cb3dSCy Schubert /* 63*2b15cb3dSCy Schubert * keyword() - Return the keyword associated with token T_ identifier. 64*2b15cb3dSCy Schubert * See also token_name() for the string-ized T_ identifier. 65*2b15cb3dSCy Schubert * Example: keyword(T_Server) returns "server" 66*2b15cb3dSCy Schubert * token_name(T_Server) returns "T_Server" 67*2b15cb3dSCy Schubert */ 68*2b15cb3dSCy Schubert const char * 69*2b15cb3dSCy Schubert keyword( 70*2b15cb3dSCy Schubert int token 71*2b15cb3dSCy Schubert ) 72*2b15cb3dSCy Schubert { 73*2b15cb3dSCy Schubert size_t i; 74*2b15cb3dSCy Schubert const char *text; 75*2b15cb3dSCy Schubert 76*2b15cb3dSCy Schubert i = token - LOWEST_KEYWORD_ID; 77*2b15cb3dSCy Schubert 78*2b15cb3dSCy Schubert if (i < COUNTOF(keyword_text)) 79*2b15cb3dSCy Schubert text = keyword_text[i]; 80*2b15cb3dSCy Schubert else 81*2b15cb3dSCy Schubert text = NULL; 82*2b15cb3dSCy Schubert 83*2b15cb3dSCy Schubert return (text != NULL) 84*2b15cb3dSCy Schubert ? text 85*2b15cb3dSCy Schubert : "(keyword not found)"; 86*2b15cb3dSCy Schubert } 87*2b15cb3dSCy Schubert 88*2b15cb3dSCy Schubert 89*2b15cb3dSCy Schubert /* FILE INTERFACE 90*2b15cb3dSCy Schubert * -------------- 91*2b15cb3dSCy Schubert * We define a couple of wrapper functions around the standard C fgetc 92*2b15cb3dSCy Schubert * and ungetc functions in order to include positional bookkeeping 93*2b15cb3dSCy Schubert */ 94*2b15cb3dSCy Schubert 95*2b15cb3dSCy Schubert struct FILE_INFO * 96*2b15cb3dSCy Schubert F_OPEN( 97*2b15cb3dSCy Schubert const char *path, 98*2b15cb3dSCy Schubert const char *mode 99*2b15cb3dSCy Schubert ) 100*2b15cb3dSCy Schubert { 101*2b15cb3dSCy Schubert struct FILE_INFO *my_info; 102*2b15cb3dSCy Schubert 103*2b15cb3dSCy Schubert my_info = emalloc(sizeof *my_info); 104*2b15cb3dSCy Schubert 105*2b15cb3dSCy Schubert my_info->line_no = 1; 106*2b15cb3dSCy Schubert my_info->col_no = 0; 107*2b15cb3dSCy Schubert my_info->prev_line_col_no = 0; 108*2b15cb3dSCy Schubert my_info->prev_token_col_no = 0; 109*2b15cb3dSCy Schubert my_info->fname = path; 110*2b15cb3dSCy Schubert 111*2b15cb3dSCy Schubert my_info->fd = fopen(path, mode); 112*2b15cb3dSCy Schubert if (NULL == my_info->fd) { 113*2b15cb3dSCy Schubert free(my_info); 114*2b15cb3dSCy Schubert return NULL; 115*2b15cb3dSCy Schubert } 116*2b15cb3dSCy Schubert return my_info; 117*2b15cb3dSCy Schubert } 118*2b15cb3dSCy Schubert 119*2b15cb3dSCy Schubert int 120*2b15cb3dSCy Schubert FGETC( 121*2b15cb3dSCy Schubert struct FILE_INFO *stream 122*2b15cb3dSCy Schubert ) 123*2b15cb3dSCy Schubert { 124*2b15cb3dSCy Schubert int ch; 125*2b15cb3dSCy Schubert 126*2b15cb3dSCy Schubert do 127*2b15cb3dSCy Schubert ch = fgetc(stream->fd); 128*2b15cb3dSCy Schubert while (EOF != ch && (CHAR_MIN > ch || ch > CHAR_MAX)); 129*2b15cb3dSCy Schubert 130*2b15cb3dSCy Schubert if (EOF != ch) { 131*2b15cb3dSCy Schubert if (input_from_file) 132*2b15cb3dSCy Schubert conf_file_sum += (u_char)ch; 133*2b15cb3dSCy Schubert ++stream->col_no; 134*2b15cb3dSCy Schubert if (ch == '\n') { 135*2b15cb3dSCy Schubert stream->prev_line_col_no = stream->col_no; 136*2b15cb3dSCy Schubert ++stream->line_no; 137*2b15cb3dSCy Schubert stream->col_no = 1; 138*2b15cb3dSCy Schubert } 139*2b15cb3dSCy Schubert } 140*2b15cb3dSCy Schubert 141*2b15cb3dSCy Schubert return ch; 142*2b15cb3dSCy Schubert } 143*2b15cb3dSCy Schubert 144*2b15cb3dSCy Schubert /* BUGS: 1. Function will fail on more than one line of pushback 145*2b15cb3dSCy Schubert * 2. No error checking is done to see if ungetc fails 146*2b15cb3dSCy Schubert * SK: I don't think its worth fixing these bugs for our purposes ;-) 147*2b15cb3dSCy Schubert */ 148*2b15cb3dSCy Schubert int 149*2b15cb3dSCy Schubert UNGETC( 150*2b15cb3dSCy Schubert int ch, 151*2b15cb3dSCy Schubert struct FILE_INFO *stream 152*2b15cb3dSCy Schubert ) 153*2b15cb3dSCy Schubert { 154*2b15cb3dSCy Schubert if (input_from_file) 155*2b15cb3dSCy Schubert conf_file_sum -= (u_char)ch; 156*2b15cb3dSCy Schubert if (ch == '\n') { 157*2b15cb3dSCy Schubert stream->col_no = stream->prev_line_col_no; 158*2b15cb3dSCy Schubert stream->prev_line_col_no = -1; 159*2b15cb3dSCy Schubert --stream->line_no; 160*2b15cb3dSCy Schubert } 161*2b15cb3dSCy Schubert --stream->col_no; 162*2b15cb3dSCy Schubert return ungetc(ch, stream->fd); 163*2b15cb3dSCy Schubert } 164*2b15cb3dSCy Schubert 165*2b15cb3dSCy Schubert int 166*2b15cb3dSCy Schubert FCLOSE( 167*2b15cb3dSCy Schubert struct FILE_INFO *stream 168*2b15cb3dSCy Schubert ) 169*2b15cb3dSCy Schubert { 170*2b15cb3dSCy Schubert int ret_val = fclose(stream->fd); 171*2b15cb3dSCy Schubert 172*2b15cb3dSCy Schubert if (!ret_val) 173*2b15cb3dSCy Schubert free(stream); 174*2b15cb3dSCy Schubert return ret_val; 175*2b15cb3dSCy Schubert } 176*2b15cb3dSCy Schubert 177*2b15cb3dSCy Schubert /* STREAM INTERFACE 178*2b15cb3dSCy Schubert * ---------------- 179*2b15cb3dSCy Schubert * Provide a wrapper for the stream functions so that the 180*2b15cb3dSCy Schubert * stream can either read from a file or from a character 181*2b15cb3dSCy Schubert * array. 182*2b15cb3dSCy Schubert * NOTE: This is not very efficient for reading from character 183*2b15cb3dSCy Schubert * arrays, but needed to allow remote configuration where the 184*2b15cb3dSCy Schubert * configuration command is provided through ntpq. 185*2b15cb3dSCy Schubert * 186*2b15cb3dSCy Schubert * The behavior of there two functions is determined by the 187*2b15cb3dSCy Schubert * input_from_file flag. 188*2b15cb3dSCy Schubert */ 189*2b15cb3dSCy Schubert 190*2b15cb3dSCy Schubert static int 191*2b15cb3dSCy Schubert get_next_char( 192*2b15cb3dSCy Schubert struct FILE_INFO *ip_file 193*2b15cb3dSCy Schubert ) 194*2b15cb3dSCy Schubert { 195*2b15cb3dSCy Schubert char ch; 196*2b15cb3dSCy Schubert 197*2b15cb3dSCy Schubert if (input_from_file) 198*2b15cb3dSCy Schubert return FGETC(ip_file); 199*2b15cb3dSCy Schubert else { 200*2b15cb3dSCy Schubert if (remote_config.buffer[remote_config.pos] == '\0') 201*2b15cb3dSCy Schubert return EOF; 202*2b15cb3dSCy Schubert else { 203*2b15cb3dSCy Schubert ip_file->col_no++; 204*2b15cb3dSCy Schubert ch = remote_config.buffer[remote_config.pos++]; 205*2b15cb3dSCy Schubert if (ch == '\n') { 206*2b15cb3dSCy Schubert ip_file->prev_line_col_no = ip_file->col_no; 207*2b15cb3dSCy Schubert ++ip_file->line_no; 208*2b15cb3dSCy Schubert ip_file->col_no = 1; 209*2b15cb3dSCy Schubert } 210*2b15cb3dSCy Schubert return ch; 211*2b15cb3dSCy Schubert } 212*2b15cb3dSCy Schubert } 213*2b15cb3dSCy Schubert } 214*2b15cb3dSCy Schubert 215*2b15cb3dSCy Schubert static void 216*2b15cb3dSCy Schubert push_back_char( 217*2b15cb3dSCy Schubert struct FILE_INFO *ip_file, 218*2b15cb3dSCy Schubert int ch 219*2b15cb3dSCy Schubert ) 220*2b15cb3dSCy Schubert { 221*2b15cb3dSCy Schubert if (input_from_file) 222*2b15cb3dSCy Schubert UNGETC(ch, ip_file); 223*2b15cb3dSCy Schubert else { 224*2b15cb3dSCy Schubert if (ch == '\n') { 225*2b15cb3dSCy Schubert ip_file->col_no = ip_file->prev_line_col_no; 226*2b15cb3dSCy Schubert ip_file->prev_line_col_no = -1; 227*2b15cb3dSCy Schubert --ip_file->line_no; 228*2b15cb3dSCy Schubert } 229*2b15cb3dSCy Schubert --ip_file->col_no; 230*2b15cb3dSCy Schubert 231*2b15cb3dSCy Schubert remote_config.pos--; 232*2b15cb3dSCy Schubert } 233*2b15cb3dSCy Schubert } 234*2b15cb3dSCy Schubert 235*2b15cb3dSCy Schubert 236*2b15cb3dSCy Schubert 237*2b15cb3dSCy Schubert /* STATE MACHINES 238*2b15cb3dSCy Schubert * -------------- 239*2b15cb3dSCy Schubert */ 240*2b15cb3dSCy Schubert 241*2b15cb3dSCy Schubert /* Keywords */ 242*2b15cb3dSCy Schubert static int 243*2b15cb3dSCy Schubert is_keyword( 244*2b15cb3dSCy Schubert char *lexeme, 245*2b15cb3dSCy Schubert follby *pfollowedby 246*2b15cb3dSCy Schubert ) 247*2b15cb3dSCy Schubert { 248*2b15cb3dSCy Schubert follby fb; 249*2b15cb3dSCy Schubert int curr_s; /* current state index */ 250*2b15cb3dSCy Schubert int token; 251*2b15cb3dSCy Schubert int i; 252*2b15cb3dSCy Schubert 253*2b15cb3dSCy Schubert curr_s = SCANNER_INIT_S; 254*2b15cb3dSCy Schubert token = 0; 255*2b15cb3dSCy Schubert 256*2b15cb3dSCy Schubert for (i = 0; lexeme[i]; i++) { 257*2b15cb3dSCy Schubert while (curr_s && (lexeme[i] != SS_CH(sst[curr_s]))) 258*2b15cb3dSCy Schubert curr_s = SS_OTHER_N(sst[curr_s]); 259*2b15cb3dSCy Schubert 260*2b15cb3dSCy Schubert if (curr_s && (lexeme[i] == SS_CH(sst[curr_s]))) { 261*2b15cb3dSCy Schubert if ('\0' == lexeme[i + 1] 262*2b15cb3dSCy Schubert && FOLLBY_NON_ACCEPTING 263*2b15cb3dSCy Schubert != SS_FB(sst[curr_s])) { 264*2b15cb3dSCy Schubert fb = SS_FB(sst[curr_s]); 265*2b15cb3dSCy Schubert *pfollowedby = fb; 266*2b15cb3dSCy Schubert token = curr_s; 267*2b15cb3dSCy Schubert break; 268*2b15cb3dSCy Schubert } 269*2b15cb3dSCy Schubert curr_s = SS_MATCH_N(sst[curr_s]); 270*2b15cb3dSCy Schubert } else 271*2b15cb3dSCy Schubert break; 272*2b15cb3dSCy Schubert } 273*2b15cb3dSCy Schubert 274*2b15cb3dSCy Schubert return token; 275*2b15cb3dSCy Schubert } 276*2b15cb3dSCy Schubert 277*2b15cb3dSCy Schubert 278*2b15cb3dSCy Schubert /* Integer */ 279*2b15cb3dSCy Schubert static int 280*2b15cb3dSCy Schubert is_integer( 281*2b15cb3dSCy Schubert char *lexeme 282*2b15cb3dSCy Schubert ) 283*2b15cb3dSCy Schubert { 284*2b15cb3dSCy Schubert int i; 285*2b15cb3dSCy Schubert int is_neg; 286*2b15cb3dSCy Schubert u_int u_val; 287*2b15cb3dSCy Schubert 288*2b15cb3dSCy Schubert i = 0; 289*2b15cb3dSCy Schubert 290*2b15cb3dSCy Schubert /* Allow a leading minus sign */ 291*2b15cb3dSCy Schubert if (lexeme[i] == '-') { 292*2b15cb3dSCy Schubert i++; 293*2b15cb3dSCy Schubert is_neg = TRUE; 294*2b15cb3dSCy Schubert } else { 295*2b15cb3dSCy Schubert is_neg = FALSE; 296*2b15cb3dSCy Schubert } 297*2b15cb3dSCy Schubert 298*2b15cb3dSCy Schubert /* Check that all the remaining characters are digits */ 299*2b15cb3dSCy Schubert for (; lexeme[i] != '\0'; i++) { 300*2b15cb3dSCy Schubert if (!isdigit((unsigned char)lexeme[i])) 301*2b15cb3dSCy Schubert return FALSE; 302*2b15cb3dSCy Schubert } 303*2b15cb3dSCy Schubert 304*2b15cb3dSCy Schubert if (is_neg) 305*2b15cb3dSCy Schubert return TRUE; 306*2b15cb3dSCy Schubert 307*2b15cb3dSCy Schubert /* Reject numbers that fit in unsigned but not in signed int */ 308*2b15cb3dSCy Schubert if (1 == sscanf(lexeme, "%u", &u_val)) 309*2b15cb3dSCy Schubert return (u_val <= INT_MAX); 310*2b15cb3dSCy Schubert else 311*2b15cb3dSCy Schubert return FALSE; 312*2b15cb3dSCy Schubert } 313*2b15cb3dSCy Schubert 314*2b15cb3dSCy Schubert 315*2b15cb3dSCy Schubert /* U_int -- assumes is_integer() has returned FALSE */ 316*2b15cb3dSCy Schubert static int 317*2b15cb3dSCy Schubert is_u_int( 318*2b15cb3dSCy Schubert char *lexeme 319*2b15cb3dSCy Schubert ) 320*2b15cb3dSCy Schubert { 321*2b15cb3dSCy Schubert int i; 322*2b15cb3dSCy Schubert int is_hex; 323*2b15cb3dSCy Schubert 324*2b15cb3dSCy Schubert i = 0; 325*2b15cb3dSCy Schubert if ('0' == lexeme[i] && 'x' == tolower((unsigned char)lexeme[i + 1])) { 326*2b15cb3dSCy Schubert i += 2; 327*2b15cb3dSCy Schubert is_hex = TRUE; 328*2b15cb3dSCy Schubert } else { 329*2b15cb3dSCy Schubert is_hex = FALSE; 330*2b15cb3dSCy Schubert } 331*2b15cb3dSCy Schubert 332*2b15cb3dSCy Schubert /* Check that all the remaining characters are digits */ 333*2b15cb3dSCy Schubert for (; lexeme[i] != '\0'; i++) { 334*2b15cb3dSCy Schubert if (is_hex && !isxdigit((unsigned char)lexeme[i])) 335*2b15cb3dSCy Schubert return FALSE; 336*2b15cb3dSCy Schubert if (!is_hex && !isdigit((unsigned char)lexeme[i])) 337*2b15cb3dSCy Schubert return FALSE; 338*2b15cb3dSCy Schubert } 339*2b15cb3dSCy Schubert 340*2b15cb3dSCy Schubert return TRUE; 341*2b15cb3dSCy Schubert } 342*2b15cb3dSCy Schubert 343*2b15cb3dSCy Schubert 344*2b15cb3dSCy Schubert /* Double */ 345*2b15cb3dSCy Schubert static int 346*2b15cb3dSCy Schubert is_double( 347*2b15cb3dSCy Schubert char *lexeme 348*2b15cb3dSCy Schubert ) 349*2b15cb3dSCy Schubert { 350*2b15cb3dSCy Schubert u_int num_digits = 0; /* Number of digits read */ 351*2b15cb3dSCy Schubert u_int i; 352*2b15cb3dSCy Schubert 353*2b15cb3dSCy Schubert i = 0; 354*2b15cb3dSCy Schubert 355*2b15cb3dSCy Schubert /* Check for an optional '+' or '-' */ 356*2b15cb3dSCy Schubert if ('+' == lexeme[i] || '-' == lexeme[i]) 357*2b15cb3dSCy Schubert i++; 358*2b15cb3dSCy Schubert 359*2b15cb3dSCy Schubert /* Read the integer part */ 360*2b15cb3dSCy Schubert for (; lexeme[i] && isdigit((unsigned char)lexeme[i]); i++) 361*2b15cb3dSCy Schubert num_digits++; 362*2b15cb3dSCy Schubert 363*2b15cb3dSCy Schubert /* Check for the optional decimal point */ 364*2b15cb3dSCy Schubert if ('.' == lexeme[i]) { 365*2b15cb3dSCy Schubert i++; 366*2b15cb3dSCy Schubert /* Check for any digits after the decimal point */ 367*2b15cb3dSCy Schubert for (; lexeme[i] && isdigit((unsigned char)lexeme[i]); i++) 368*2b15cb3dSCy Schubert num_digits++; 369*2b15cb3dSCy Schubert } 370*2b15cb3dSCy Schubert 371*2b15cb3dSCy Schubert /* 372*2b15cb3dSCy Schubert * The number of digits in both the decimal part and the 373*2b15cb3dSCy Schubert * fraction part must not be zero at this point 374*2b15cb3dSCy Schubert */ 375*2b15cb3dSCy Schubert if (!num_digits) 376*2b15cb3dSCy Schubert return 0; 377*2b15cb3dSCy Schubert 378*2b15cb3dSCy Schubert /* Check if we are done */ 379*2b15cb3dSCy Schubert if (!lexeme[i]) 380*2b15cb3dSCy Schubert return 1; 381*2b15cb3dSCy Schubert 382*2b15cb3dSCy Schubert /* There is still more input, read the exponent */ 383*2b15cb3dSCy Schubert if ('e' == tolower((unsigned char)lexeme[i])) 384*2b15cb3dSCy Schubert i++; 385*2b15cb3dSCy Schubert else 386*2b15cb3dSCy Schubert return 0; 387*2b15cb3dSCy Schubert 388*2b15cb3dSCy Schubert /* Read an optional Sign */ 389*2b15cb3dSCy Schubert if ('+' == lexeme[i] || '-' == lexeme[i]) 390*2b15cb3dSCy Schubert i++; 391*2b15cb3dSCy Schubert 392*2b15cb3dSCy Schubert /* Now read the exponent part */ 393*2b15cb3dSCy Schubert while (lexeme[i] && isdigit((unsigned char)lexeme[i])) 394*2b15cb3dSCy Schubert i++; 395*2b15cb3dSCy Schubert 396*2b15cb3dSCy Schubert /* Check if we are done */ 397*2b15cb3dSCy Schubert if (!lexeme[i]) 398*2b15cb3dSCy Schubert return 1; 399*2b15cb3dSCy Schubert else 400*2b15cb3dSCy Schubert return 0; 401*2b15cb3dSCy Schubert } 402*2b15cb3dSCy Schubert 403*2b15cb3dSCy Schubert 404*2b15cb3dSCy Schubert /* is_special() - Test whether a character is a token */ 405*2b15cb3dSCy Schubert static inline int 406*2b15cb3dSCy Schubert is_special( 407*2b15cb3dSCy Schubert int ch 408*2b15cb3dSCy Schubert ) 409*2b15cb3dSCy Schubert { 410*2b15cb3dSCy Schubert return strchr(special_chars, ch) != NULL; 411*2b15cb3dSCy Schubert } 412*2b15cb3dSCy Schubert 413*2b15cb3dSCy Schubert 414*2b15cb3dSCy Schubert static int 415*2b15cb3dSCy Schubert is_EOC( 416*2b15cb3dSCy Schubert int ch 417*2b15cb3dSCy Schubert ) 418*2b15cb3dSCy Schubert { 419*2b15cb3dSCy Schubert if ((old_config_style && (ch == '\n')) || 420*2b15cb3dSCy Schubert (!old_config_style && (ch == ';'))) 421*2b15cb3dSCy Schubert return 1; 422*2b15cb3dSCy Schubert return 0; 423*2b15cb3dSCy Schubert } 424*2b15cb3dSCy Schubert 425*2b15cb3dSCy Schubert 426*2b15cb3dSCy Schubert char * 427*2b15cb3dSCy Schubert quote_if_needed(char *str) 428*2b15cb3dSCy Schubert { 429*2b15cb3dSCy Schubert char *ret; 430*2b15cb3dSCy Schubert size_t len; 431*2b15cb3dSCy Schubert size_t octets; 432*2b15cb3dSCy Schubert 433*2b15cb3dSCy Schubert len = strlen(str); 434*2b15cb3dSCy Schubert octets = len + 2 + 1; 435*2b15cb3dSCy Schubert ret = emalloc(octets); 436*2b15cb3dSCy Schubert if ('"' != str[0] 437*2b15cb3dSCy Schubert && (strcspn(str, special_chars) < len 438*2b15cb3dSCy Schubert || strchr(str, ' ') != NULL)) { 439*2b15cb3dSCy Schubert snprintf(ret, octets, "\"%s\"", str); 440*2b15cb3dSCy Schubert } else 441*2b15cb3dSCy Schubert strlcpy(ret, str, octets); 442*2b15cb3dSCy Schubert 443*2b15cb3dSCy Schubert return ret; 444*2b15cb3dSCy Schubert } 445*2b15cb3dSCy Schubert 446*2b15cb3dSCy Schubert 447*2b15cb3dSCy Schubert static int 448*2b15cb3dSCy Schubert create_string_token( 449*2b15cb3dSCy Schubert char *lexeme 450*2b15cb3dSCy Schubert ) 451*2b15cb3dSCy Schubert { 452*2b15cb3dSCy Schubert char *pch; 453*2b15cb3dSCy Schubert 454*2b15cb3dSCy Schubert /* 455*2b15cb3dSCy Schubert * ignore end of line whitespace 456*2b15cb3dSCy Schubert */ 457*2b15cb3dSCy Schubert pch = lexeme; 458*2b15cb3dSCy Schubert while (*pch && isspace((unsigned char)*pch)) 459*2b15cb3dSCy Schubert pch++; 460*2b15cb3dSCy Schubert 461*2b15cb3dSCy Schubert if (!*pch) { 462*2b15cb3dSCy Schubert yylval.Integer = T_EOC; 463*2b15cb3dSCy Schubert return yylval.Integer; 464*2b15cb3dSCy Schubert } 465*2b15cb3dSCy Schubert 466*2b15cb3dSCy Schubert yylval.String = estrdup(lexeme); 467*2b15cb3dSCy Schubert return T_String; 468*2b15cb3dSCy Schubert } 469*2b15cb3dSCy Schubert 470*2b15cb3dSCy Schubert 471*2b15cb3dSCy Schubert /* 472*2b15cb3dSCy Schubert * yylex() - function that does the actual scanning. 473*2b15cb3dSCy Schubert * Bison expects this function to be called yylex and for it to take no 474*2b15cb3dSCy Schubert * input and return an int. 475*2b15cb3dSCy Schubert * Conceptually yylex "returns" yylval as well as the actual return 476*2b15cb3dSCy Schubert * value representing the token or type. 477*2b15cb3dSCy Schubert */ 478*2b15cb3dSCy Schubert int 479*2b15cb3dSCy Schubert yylex( 480*2b15cb3dSCy Schubert struct FILE_INFO *ip_file 481*2b15cb3dSCy Schubert ) 482*2b15cb3dSCy Schubert { 483*2b15cb3dSCy Schubert static follby followedby = FOLLBY_TOKEN; 484*2b15cb3dSCy Schubert size_t i; 485*2b15cb3dSCy Schubert int instring; 486*2b15cb3dSCy Schubert int yylval_was_set; 487*2b15cb3dSCy Schubert int converted; 488*2b15cb3dSCy Schubert int token; /* The return value */ 489*2b15cb3dSCy Schubert int ch; 490*2b15cb3dSCy Schubert 491*2b15cb3dSCy Schubert if (input_from_file) 492*2b15cb3dSCy Schubert ip_file = fp[curr_include_level]; 493*2b15cb3dSCy Schubert instring = FALSE; 494*2b15cb3dSCy Schubert yylval_was_set = FALSE; 495*2b15cb3dSCy Schubert 496*2b15cb3dSCy Schubert do { 497*2b15cb3dSCy Schubert /* Ignore whitespace at the beginning */ 498*2b15cb3dSCy Schubert while (EOF != (ch = get_next_char(ip_file)) && 499*2b15cb3dSCy Schubert isspace(ch) && 500*2b15cb3dSCy Schubert !is_EOC(ch)) 501*2b15cb3dSCy Schubert ; /* Null Statement */ 502*2b15cb3dSCy Schubert 503*2b15cb3dSCy Schubert if (EOF == ch) { 504*2b15cb3dSCy Schubert 505*2b15cb3dSCy Schubert if (!input_from_file || curr_include_level <= 0) 506*2b15cb3dSCy Schubert return 0; 507*2b15cb3dSCy Schubert 508*2b15cb3dSCy Schubert FCLOSE(fp[curr_include_level]); 509*2b15cb3dSCy Schubert ip_file = fp[--curr_include_level]; 510*2b15cb3dSCy Schubert token = T_EOC; 511*2b15cb3dSCy Schubert goto normal_return; 512*2b15cb3dSCy Schubert 513*2b15cb3dSCy Schubert } else if (is_EOC(ch)) { 514*2b15cb3dSCy Schubert 515*2b15cb3dSCy Schubert /* end FOLLBY_STRINGS_TO_EOC effect */ 516*2b15cb3dSCy Schubert followedby = FOLLBY_TOKEN; 517*2b15cb3dSCy Schubert token = T_EOC; 518*2b15cb3dSCy Schubert goto normal_return; 519*2b15cb3dSCy Schubert 520*2b15cb3dSCy Schubert } else if (is_special(ch) && FOLLBY_TOKEN == followedby) { 521*2b15cb3dSCy Schubert /* special chars are their own token values */ 522*2b15cb3dSCy Schubert token = ch; 523*2b15cb3dSCy Schubert /* 524*2b15cb3dSCy Schubert * '=' outside simulator configuration implies 525*2b15cb3dSCy Schubert * a single string following as in: 526*2b15cb3dSCy Schubert * setvar Owner = "The Boss" default 527*2b15cb3dSCy Schubert */ 528*2b15cb3dSCy Schubert if ('=' == ch && old_config_style) 529*2b15cb3dSCy Schubert followedby = FOLLBY_STRING; 530*2b15cb3dSCy Schubert yytext[0] = (char)ch; 531*2b15cb3dSCy Schubert yytext[1] = '\0'; 532*2b15cb3dSCy Schubert goto normal_return; 533*2b15cb3dSCy Schubert } else 534*2b15cb3dSCy Schubert push_back_char(ip_file, ch); 535*2b15cb3dSCy Schubert 536*2b15cb3dSCy Schubert /* save the position of start of the token */ 537*2b15cb3dSCy Schubert ip_file->prev_token_line_no = ip_file->line_no; 538*2b15cb3dSCy Schubert ip_file->prev_token_col_no = ip_file->col_no; 539*2b15cb3dSCy Schubert 540*2b15cb3dSCy Schubert /* Read in the lexeme */ 541*2b15cb3dSCy Schubert i = 0; 542*2b15cb3dSCy Schubert while (EOF != (ch = get_next_char(ip_file))) { 543*2b15cb3dSCy Schubert 544*2b15cb3dSCy Schubert yytext[i] = (char)ch; 545*2b15cb3dSCy Schubert 546*2b15cb3dSCy Schubert /* Break on whitespace or a special character */ 547*2b15cb3dSCy Schubert if (isspace(ch) || is_EOC(ch) 548*2b15cb3dSCy Schubert || '"' == ch 549*2b15cb3dSCy Schubert || (FOLLBY_TOKEN == followedby 550*2b15cb3dSCy Schubert && is_special(ch))) 551*2b15cb3dSCy Schubert break; 552*2b15cb3dSCy Schubert 553*2b15cb3dSCy Schubert /* Read the rest of the line on reading a start 554*2b15cb3dSCy Schubert of comment character */ 555*2b15cb3dSCy Schubert if ('#' == ch) { 556*2b15cb3dSCy Schubert while (EOF != (ch = get_next_char(ip_file)) 557*2b15cb3dSCy Schubert && '\n' != ch) 558*2b15cb3dSCy Schubert ; /* Null Statement */ 559*2b15cb3dSCy Schubert break; 560*2b15cb3dSCy Schubert } 561*2b15cb3dSCy Schubert 562*2b15cb3dSCy Schubert i++; 563*2b15cb3dSCy Schubert if (i >= COUNTOF(yytext)) 564*2b15cb3dSCy Schubert goto lex_too_long; 565*2b15cb3dSCy Schubert } 566*2b15cb3dSCy Schubert /* Pick up all of the string inside between " marks, to 567*2b15cb3dSCy Schubert * end of line. If we make it to EOL without a 568*2b15cb3dSCy Schubert * terminating " assume it for them. 569*2b15cb3dSCy Schubert * 570*2b15cb3dSCy Schubert * XXX - HMS: I'm not sure we want to assume the closing " 571*2b15cb3dSCy Schubert */ 572*2b15cb3dSCy Schubert if ('"' == ch) { 573*2b15cb3dSCy Schubert instring = TRUE; 574*2b15cb3dSCy Schubert while (EOF != (ch = get_next_char(ip_file)) && 575*2b15cb3dSCy Schubert ch != '"' && ch != '\n') { 576*2b15cb3dSCy Schubert yytext[i++] = (char)ch; 577*2b15cb3dSCy Schubert if (i >= COUNTOF(yytext)) 578*2b15cb3dSCy Schubert goto lex_too_long; 579*2b15cb3dSCy Schubert } 580*2b15cb3dSCy Schubert /* 581*2b15cb3dSCy Schubert * yytext[i] will be pushed back as not part of 582*2b15cb3dSCy Schubert * this lexeme, but any closing quote should 583*2b15cb3dSCy Schubert * not be pushed back, so we read another char. 584*2b15cb3dSCy Schubert */ 585*2b15cb3dSCy Schubert if ('"' == ch) 586*2b15cb3dSCy Schubert ch = get_next_char(ip_file); 587*2b15cb3dSCy Schubert } 588*2b15cb3dSCy Schubert /* Pushback the last character read that is not a part 589*2b15cb3dSCy Schubert * of this lexeme. 590*2b15cb3dSCy Schubert * If the last character read was an EOF, pushback a 591*2b15cb3dSCy Schubert * newline character. This is to prevent a parse error 592*2b15cb3dSCy Schubert * when there is no newline at the end of a file. 593*2b15cb3dSCy Schubert */ 594*2b15cb3dSCy Schubert if (EOF == ch) 595*2b15cb3dSCy Schubert push_back_char(ip_file, '\n'); 596*2b15cb3dSCy Schubert else 597*2b15cb3dSCy Schubert push_back_char(ip_file, ch); 598*2b15cb3dSCy Schubert yytext[i] = '\0'; 599*2b15cb3dSCy Schubert } while (i == 0); 600*2b15cb3dSCy Schubert 601*2b15cb3dSCy Schubert /* Now return the desired token */ 602*2b15cb3dSCy Schubert 603*2b15cb3dSCy Schubert /* First make sure that the parser is *not* expecting a string 604*2b15cb3dSCy Schubert * as the next token (based on the previous token that was 605*2b15cb3dSCy Schubert * returned) and that we haven't read a string. 606*2b15cb3dSCy Schubert */ 607*2b15cb3dSCy Schubert 608*2b15cb3dSCy Schubert if (followedby == FOLLBY_TOKEN && !instring) { 609*2b15cb3dSCy Schubert token = is_keyword(yytext, &followedby); 610*2b15cb3dSCy Schubert if (token) { 611*2b15cb3dSCy Schubert /* 612*2b15cb3dSCy Schubert * T_Server is exceptional as it forces the 613*2b15cb3dSCy Schubert * following token to be a string in the 614*2b15cb3dSCy Schubert * non-simulator parts of the configuration, 615*2b15cb3dSCy Schubert * but in the simulator configuration section, 616*2b15cb3dSCy Schubert * "server" is followed by "=" which must be 617*2b15cb3dSCy Schubert * recognized as a token not a string. 618*2b15cb3dSCy Schubert */ 619*2b15cb3dSCy Schubert if (T_Server == token && !old_config_style) 620*2b15cb3dSCy Schubert followedby = FOLLBY_TOKEN; 621*2b15cb3dSCy Schubert goto normal_return; 622*2b15cb3dSCy Schubert } else if (is_integer(yytext)) { 623*2b15cb3dSCy Schubert yylval_was_set = TRUE; 624*2b15cb3dSCy Schubert errno = 0; 625*2b15cb3dSCy Schubert if ((yylval.Integer = strtol(yytext, NULL, 10)) == 0 626*2b15cb3dSCy Schubert && ((errno == EINVAL) || (errno == ERANGE))) { 627*2b15cb3dSCy Schubert msyslog(LOG_ERR, 628*2b15cb3dSCy Schubert "Integer cannot be represented: %s", 629*2b15cb3dSCy Schubert yytext); 630*2b15cb3dSCy Schubert if (input_from_file) { 631*2b15cb3dSCy Schubert exit(1); 632*2b15cb3dSCy Schubert } else { 633*2b15cb3dSCy Schubert /* force end of parsing */ 634*2b15cb3dSCy Schubert yylval.Integer = 0; 635*2b15cb3dSCy Schubert return 0; 636*2b15cb3dSCy Schubert } 637*2b15cb3dSCy Schubert } 638*2b15cb3dSCy Schubert token = T_Integer; 639*2b15cb3dSCy Schubert goto normal_return; 640*2b15cb3dSCy Schubert } else if (is_u_int(yytext)) { 641*2b15cb3dSCy Schubert yylval_was_set = TRUE; 642*2b15cb3dSCy Schubert if ('0' == yytext[0] && 643*2b15cb3dSCy Schubert 'x' == tolower((unsigned char)yytext[1])) 644*2b15cb3dSCy Schubert converted = sscanf(&yytext[2], "%x", 645*2b15cb3dSCy Schubert &yylval.U_int); 646*2b15cb3dSCy Schubert else 647*2b15cb3dSCy Schubert converted = sscanf(yytext, "%u", 648*2b15cb3dSCy Schubert &yylval.U_int); 649*2b15cb3dSCy Schubert if (1 != converted) { 650*2b15cb3dSCy Schubert msyslog(LOG_ERR, 651*2b15cb3dSCy Schubert "U_int cannot be represented: %s", 652*2b15cb3dSCy Schubert yytext); 653*2b15cb3dSCy Schubert if (input_from_file) { 654*2b15cb3dSCy Schubert exit(1); 655*2b15cb3dSCy Schubert } else { 656*2b15cb3dSCy Schubert /* force end of parsing */ 657*2b15cb3dSCy Schubert yylval.Integer = 0; 658*2b15cb3dSCy Schubert return 0; 659*2b15cb3dSCy Schubert } 660*2b15cb3dSCy Schubert } 661*2b15cb3dSCy Schubert token = T_U_int; 662*2b15cb3dSCy Schubert goto normal_return; 663*2b15cb3dSCy Schubert } else if (is_double(yytext)) { 664*2b15cb3dSCy Schubert yylval_was_set = TRUE; 665*2b15cb3dSCy Schubert errno = 0; 666*2b15cb3dSCy Schubert if ((yylval.Double = atof(yytext)) == 0 && errno == ERANGE) { 667*2b15cb3dSCy Schubert msyslog(LOG_ERR, 668*2b15cb3dSCy Schubert "Double too large to represent: %s", 669*2b15cb3dSCy Schubert yytext); 670*2b15cb3dSCy Schubert exit(1); 671*2b15cb3dSCy Schubert } else { 672*2b15cb3dSCy Schubert token = T_Double; 673*2b15cb3dSCy Schubert goto normal_return; 674*2b15cb3dSCy Schubert } 675*2b15cb3dSCy Schubert } else { 676*2b15cb3dSCy Schubert /* Default: Everything is a string */ 677*2b15cb3dSCy Schubert yylval_was_set = TRUE; 678*2b15cb3dSCy Schubert token = create_string_token(yytext); 679*2b15cb3dSCy Schubert goto normal_return; 680*2b15cb3dSCy Schubert } 681*2b15cb3dSCy Schubert } 682*2b15cb3dSCy Schubert 683*2b15cb3dSCy Schubert /* 684*2b15cb3dSCy Schubert * Either followedby is not FOLLBY_TOKEN or this lexeme is part 685*2b15cb3dSCy Schubert * of a string. Hence, we need to return T_String. 686*2b15cb3dSCy Schubert * 687*2b15cb3dSCy Schubert * _Except_ we might have a -4 or -6 flag on a an association 688*2b15cb3dSCy Schubert * configuration line (server, peer, pool, etc.). 689*2b15cb3dSCy Schubert * 690*2b15cb3dSCy Schubert * This is a terrible hack, but the grammar is ambiguous so we 691*2b15cb3dSCy Schubert * don't have a choice. [SK] 692*2b15cb3dSCy Schubert * 693*2b15cb3dSCy Schubert * The ambiguity is in the keyword scanner, not ntp_parser.y. 694*2b15cb3dSCy Schubert * We do not require server addresses be quoted in ntp.conf, 695*2b15cb3dSCy Schubert * complicating the scanner's job. To avoid trying (and 696*2b15cb3dSCy Schubert * failing) to match an IP address or DNS name to a keyword, 697*2b15cb3dSCy Schubert * the association keywords use FOLLBY_STRING in the keyword 698*2b15cb3dSCy Schubert * table, which tells the scanner to force the next token to be 699*2b15cb3dSCy Schubert * a T_String, so it does not try to match a keyword but rather 700*2b15cb3dSCy Schubert * expects a string when -4/-6 modifiers to server, peer, etc. 701*2b15cb3dSCy Schubert * are encountered. 702*2b15cb3dSCy Schubert * restrict -4 and restrict -6 parsing works correctly without 703*2b15cb3dSCy Schubert * this hack, as restrict uses FOLLBY_TOKEN. [DH] 704*2b15cb3dSCy Schubert */ 705*2b15cb3dSCy Schubert if ('-' == yytext[0]) { 706*2b15cb3dSCy Schubert if ('4' == yytext[1]) { 707*2b15cb3dSCy Schubert token = T_Ipv4_flag; 708*2b15cb3dSCy Schubert goto normal_return; 709*2b15cb3dSCy Schubert } else if ('6' == yytext[1]) { 710*2b15cb3dSCy Schubert token = T_Ipv6_flag; 711*2b15cb3dSCy Schubert goto normal_return; 712*2b15cb3dSCy Schubert } 713*2b15cb3dSCy Schubert } 714*2b15cb3dSCy Schubert 715*2b15cb3dSCy Schubert instring = FALSE; 716*2b15cb3dSCy Schubert if (FOLLBY_STRING == followedby) 717*2b15cb3dSCy Schubert followedby = FOLLBY_TOKEN; 718*2b15cb3dSCy Schubert 719*2b15cb3dSCy Schubert yylval_was_set = TRUE; 720*2b15cb3dSCy Schubert token = create_string_token(yytext); 721*2b15cb3dSCy Schubert 722*2b15cb3dSCy Schubert normal_return: 723*2b15cb3dSCy Schubert if (T_EOC == token) 724*2b15cb3dSCy Schubert DPRINTF(4,("\t<end of command>\n")); 725*2b15cb3dSCy Schubert else 726*2b15cb3dSCy Schubert DPRINTF(4, ("yylex: lexeme '%s' -> %s\n", yytext, 727*2b15cb3dSCy Schubert token_name(token))); 728*2b15cb3dSCy Schubert 729*2b15cb3dSCy Schubert if (!yylval_was_set) 730*2b15cb3dSCy Schubert yylval.Integer = token; 731*2b15cb3dSCy Schubert 732*2b15cb3dSCy Schubert return token; 733*2b15cb3dSCy Schubert 734*2b15cb3dSCy Schubert lex_too_long: 735*2b15cb3dSCy Schubert yytext[min(sizeof(yytext) - 1, 50)] = 0; 736*2b15cb3dSCy Schubert msyslog(LOG_ERR, 737*2b15cb3dSCy Schubert "configuration item on line %d longer than limit of %lu, began with '%s'", 738*2b15cb3dSCy Schubert ip_file->line_no, (u_long)min(sizeof(yytext) - 1, 50), 739*2b15cb3dSCy Schubert yytext); 740*2b15cb3dSCy Schubert 741*2b15cb3dSCy Schubert /* 742*2b15cb3dSCy Schubert * If we hit the length limit reading the startup configuration 743*2b15cb3dSCy Schubert * file, abort. 744*2b15cb3dSCy Schubert */ 745*2b15cb3dSCy Schubert if (input_from_file) 746*2b15cb3dSCy Schubert exit(sizeof(yytext) - 1); 747*2b15cb3dSCy Schubert 748*2b15cb3dSCy Schubert /* 749*2b15cb3dSCy Schubert * If it's runtime configuration via ntpq :config treat it as 750*2b15cb3dSCy Schubert * if the configuration text ended before the too-long lexeme, 751*2b15cb3dSCy Schubert * hostname, or string. 752*2b15cb3dSCy Schubert */ 753*2b15cb3dSCy Schubert yylval.Integer = 0; 754*2b15cb3dSCy Schubert return 0; 755*2b15cb3dSCy Schubert } 756