1 /* Scanner for slon config file */ 2 3 %{ 4 #include <sys/stat.h> 5 #include <errno.h> 6 #include <ctype.h> 7 #include <pthread.h> 8 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <sys/types.h> 13 14 #ifndef WIN32 15 #include <unistd.h> 16 #endif 17 18 #include "slon.h" 19 20 21 #define CONFIG_FILENAME "./slon.conf" 22 23 static unsigned ConfigFileLineno; 24 25 enum { 26 SLON_ID = 1, 27 SLON_STRING = 2, 28 SLON_INTEGER = 3, 29 SLON_REAL = 4, 30 SLON_EQUALS = 5, 31 SLON_UNQUOTED_STRING = 6, 32 SLON_QUALIFIED_ID = 7, 33 SLON_ESCAPED_STRING = 8, 34 SLON_EOL = 99, 35 SLON_FERROR = 100 36 }; 37 38 #define YY_USER_INIT (ConfigFileLineno = 1) 39 40 /* prototype, so compiler is happy with our high warnings setting */ 41 int SLON_yylex(void); 42 char *SLON_scanstr(char *); 43 %} 44 45 %option 8bit 46 %option never-interactive 47 %option nodefault 48 %option nounput 49 %option noyywrap 50 51 SIGN ("-"|"+") 52 DIGIT [0-9] 53 HEXDIGIT [0-9a-fA-F] 54 55 INTEGER {SIGN}?({DIGIT}+|0x{HEXDIGIT}+) 56 57 EXPONENT [Ee]{SIGN}?{DIGIT}+ 58 REAL {SIGN}?{DIGIT}*"."{DIGIT}*{EXPONENT}? 59 60 LETTER [A-Za-z_\200-\377] 61 LETTER_OR_DIGIT [A-Za-z_0-9\200-\377] 62 63 ID {LETTER}{LETTER_OR_DIGIT}* 64 QUALIFIED_ID {ID}"."{ID} 65 66 UNQUOTED_STRING {LETTER}({LETTER_OR_DIGIT}|[-._:/])* 67 STRING \'([^'\n]|\\.)*\' 68 ESCAPED_STRING \"([^"\n]|\\.)*\" 69 %% 70 71 \n ConfigFileLineno++; return SLON_EOL; 72 [ \t\r]+ /* eat whitespace */ 73 #.* /* eat comment */ 74 75 {ID} return SLON_ID; 76 {QUALIFIED_ID} return SLON_QUALIFIED_ID; 77 {STRING} return SLON_STRING; 78 {UNQUOTED_STRING} return SLON_UNQUOTED_STRING; 79 {ESCAPED_STRING} return SLON_ESCAPED_STRING; 80 {INTEGER} return SLON_INTEGER; 81 {REAL} return SLON_REAL; 82 = return SLON_EQUALS; 83 84 . return SLON_FERROR; 85 86 %% 87 88 struct name_value_pair 89 { 90 char *name; 91 char *value; 92 struct name_value_pair *next; 93 }; 94 95 /* 96 * Free a list of name/value pairs, including the names and the values 97 */ 98 static void 99 free_name_value_list(struct name_value_pair * list) 100 { 101 struct name_value_pair *item; 102 103 item = list; 104 while (item) 105 { 106 struct name_value_pair *save; 107 108 save = item->next; 109 free(item->name); 110 free(item->value); 111 free(item); 112 item = save; 113 } 114 } 115 116 void ProcessConfigFile(const char *filename) 117 { 118 int token, parse_state; 119 char *opt_name, *opt_value; 120 int elevel; 121 struct name_value_pair *item, *head, *tail; 122 FILE * fp; 123 124 elevel = SLON_ERROR; 125 126 /* 127 * Open the conf file 128 */ 129 if (filename == NULL) 130 { 131 fp = fopen(CONFIG_FILENAME, "r"); 132 } 133 else 134 { 135 fp = fopen(filename, "r"); 136 } 137 if (!fp) 138 { 139 /* File not found is fine */ 140 if (errno != ENOENT) 141 { 142 slon_log(elevel,"could not open configuration file \"%s\"\n", filename); 143 144 } 145 return; 146 } 147 148 /* Ok we have the file, lets parse it */ 149 150 yyin = fp; 151 parse_state = 0; 152 head = NULL; 153 tail = head; 154 opt_name = NULL; 155 opt_value = opt_name; 156 157 while ( (token = yylex()) ) 158 { 159 switch(parse_state) 160 { 161 case 0: 162 if (token == SLON_EOL) /* empty line */ 163 { 164 continue; 165 } 166 if (token != SLON_ID && token != SLON_QUALIFIED_ID) 167 { 168 goto parse_error; 169 } 170 opt_name = strdup(yytext); 171 parse_state = 1; 172 break; 173 case 1: 174 /* ignore equals sign */ 175 if (token == SLON_EQUALS) 176 { 177 token = yylex(); 178 } 179 if (token != SLON_ID && token != SLON_STRING && token != SLON_INTEGER && token != SLON_REAL && token != SLON_UNQUOTED_STRING && token != SLON_ESCAPED_STRING) 180 { 181 goto parse_error; 182 } 183 opt_value = strdup(yytext); 184 if (token == SLON_STRING || token == SLON_ESCAPED_STRING) 185 { 186 memmove(opt_value,opt_value+1,strlen(opt_value)-1); 187 opt_value[strlen(opt_value)-2]='\0'; 188 opt_value=SLON_scanstr(opt_value); 189 } 190 parse_state = 2; 191 break; 192 case 2: /* OEL ? */ 193 if (token != SLON_EOL) 194 { 195 goto parse_error; 196 } 197 item = malloc(sizeof *item); 198 item->name = opt_name; 199 item->value = opt_value; 200 201 if (strcmp(opt_name, "custom_variable_classes") == 0) 202 { 203 item->next = head; 204 head = item; 205 if (!tail) 206 { 207 tail = item; 208 } 209 } 210 else 211 { 212 /* append to list */ 213 item->next = NULL; 214 if (!head) 215 { 216 head = item; 217 } 218 else 219 { 220 tail->next = item; 221 } 222 tail = item; 223 } 224 parse_state = 0; 225 break; 226 } 227 } 228 /* 229 * If we encountered an EOF after we've already 230 * reached parse_state of 2, we already have a complete 231 * configuration line, it's just terminated with EOF 232 * instead of EOL. Store that config option. 233 */ 234 if(parse_state == 2) 235 { 236 item = malloc(sizeof *item); 237 item->name = opt_name; 238 item->value = opt_value; 239 if (strcmp(opt_name, "custom_variable_classes") == 0) 240 { 241 item->next = head; 242 head = item; 243 if (!tail) 244 { 245 tail = item; 246 } 247 } 248 else 249 { 250 /* append to list */ 251 item->next = NULL; 252 if (!head) 253 { 254 head = item; 255 } 256 else 257 { 258 tail->next = item; 259 } 260 tail = item; 261 } 262 parse_state = 0; 263 } 264 265 fclose(fp); 266 267 for(item = head; item; item=item->next) 268 { 269 set_config_option(item->name, item->value); 270 } 271 272 cleanup_exit: 273 free_name_value_list(head); 274 return; 275 276 parse_error: 277 fclose(fp); 278 free_name_value_list(head); 279 if (token == SLON_EOL) 280 { 281 slon_log(elevel, "syntax error in file \"%s\" line %u, near end of line\n", filename, ConfigFileLineno - 1); 282 } 283 284 else 285 { 286 slon_log(elevel, "syntax error in file \"%s\" line %u, near end of line\n", filename, ConfigFileLineno - 1); 287 } 288 } 289 290 291 292 293 294 295 296 char *SLON_scanstr(char *s) 297 { 298 char *newStr; 299 int len, 300 i, 301 j; 302 303 if (s == NULL || s[0] == '\0') 304 { 305 if (s != NULL) 306 free(s); 307 return strdup(""); 308 } 309 len = strlen(s); 310 311 newStr = malloc(len + 1); /* string cannot get longer */ 312 if (newStr == NULL) 313 slon_log(SLON_FATAL, "out of memory\n"); 314 315 for (i = 0, j = 0; i < len; i++) 316 { 317 if (s[i] == '\\') 318 { 319 i++; 320 switch (s[i]) 321 { 322 case 'b': 323 newStr[j] = '\b'; 324 break; 325 case 'f': 326 newStr[j] = '\f'; 327 break; 328 case 'n': 329 newStr[j] = '\n'; 330 break; 331 case 'r': 332 newStr[j] = '\r'; 333 break; 334 case 't': 335 newStr[j] = '\t'; 336 break; 337 case '0': 338 case '1': 339 case '2': 340 case '3': 341 case '4': 342 case '5': 343 case '6': 344 case '7': 345 { 346 int k; 347 long octVal = 0; 348 349 for (k = 0; 350 s[i + k] >= '0' && s[i 351 + k] <= '7' && k < 3; 352 k++) 353 octVal = (octVal << 3) + 354 (s[i + k] - '0'); 355 i += k - 1; 356 newStr[j] = ((char) octVal); 357 } 358 break; 359 default: 360 newStr[j] = s[i]; 361 break; 362 } 363 } /* switch */ 364 else 365 newStr[j] = s[i]; 366 j++; 367 } 368 newStr[j] = '\0'; 369 free(s); 370 return newStr; 371 } 372 373 /* 374 * Local Variables: 375 * tab-width: 4 376 * c-indent-level: 4 377 * c-basic-offset: 4 378 * End: 379 */ 380