1228060Sbapt/* Input routines. 2228060Sbapt Copyright (C) 1989-1998, 2002-2004 Free Software Foundation, Inc. 3228060Sbapt Written by Douglas C. Schmidt <schmidt@ics.uci.edu> 4228060Sbapt and Bruno Haible <bruno@clisp.org>. 5228060Sbapt 6228060Sbapt This file is part of GNU GPERF. 7228060Sbapt 8228060Sbapt GNU GPERF is free software; you can redistribute it and/or modify 9228060Sbapt it under the terms of the GNU General Public License as published by 10228060Sbapt the Free Software Foundation; either version 2, or (at your option) 11228060Sbapt any later version. 12228060Sbapt 13228060Sbapt GNU GPERF is distributed in the hope that it will be useful, 14228060Sbapt but WITHOUT ANY WARRANTY; without even the implied warranty of 15228060Sbapt MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16228060Sbapt GNU General Public License for more details. 17228060Sbapt 18228060Sbapt You should have received a copy of the GNU General Public License 19228060Sbapt along with this program; see the file COPYING. 20228060Sbapt If not, write to the Free Software Foundation, Inc., 21228060Sbapt 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ 22228060Sbapt 23228060Sbapt/* Specification. */ 24228060Sbapt#include "input.h" 25228060Sbapt 26228060Sbapt#include <stdio.h> 27228060Sbapt#include <stdlib.h> /* declares exit() */ 28228060Sbapt#include <string.h> /* declares strncpy(), strchr() */ 29228060Sbapt#include <limits.h> /* defines UCHAR_MAX etc. */ 30228060Sbapt#include "options.h" 31228060Sbapt#include "getline.h" 32228060Sbapt 33228060SbaptInput::Input (FILE *stream, Keyword_Factory *keyword_factory) 34228060Sbapt : _stream (stream), _factory (keyword_factory) 35228060Sbapt{ 36228060Sbapt} 37228060Sbapt 38228060Sbapt/* Returns a pretty representation of the input file name, for error and 39228060Sbapt warning messages. */ 40228060Sbaptstatic const char * 41228060Sbaptpretty_input_file_name () 42228060Sbapt{ 43228060Sbapt if (option.get_input_file_name ()) 44228060Sbapt return option.get_input_file_name (); 45228060Sbapt else 46228060Sbapt return "(standard input)"; 47228060Sbapt} 48228060Sbapt 49228060Sbapt/* Returns true if the given line contains a "%DECL" declaration. */ 50228060Sbaptstatic bool 51228060Sbaptis_declaration (const char *line, const char *line_end, unsigned int lineno, 52228060Sbapt const char *decl) 53228060Sbapt{ 54228060Sbapt /* Skip '%'. */ 55228060Sbapt line++; 56228060Sbapt 57228060Sbapt /* Skip DECL. */ 58228060Sbapt for (const char *d = decl; *d; d++) 59228060Sbapt { 60228060Sbapt if (!(line < line_end)) 61228060Sbapt return false; 62228060Sbapt if (!(*line == *d || (*d == '-' && *line == '_'))) 63228060Sbapt return false; 64228060Sbapt line++; 65228060Sbapt } 66228060Sbapt if (line < line_end 67228060Sbapt && ((*line >= 'A' && *line <= 'Z') 68228060Sbapt || (*line >= 'a' && *line <= 'z') 69228060Sbapt || *line == '-' || *line == '_')) 70228060Sbapt return false; 71228060Sbapt 72228060Sbapt /* OK, found DECL. */ 73228060Sbapt 74228060Sbapt /* Skip whitespace. */ 75228060Sbapt while (line < line_end && (*line == ' ' || *line == '\t')) 76228060Sbapt line++; 77228060Sbapt 78228060Sbapt /* Expect end of line. */ 79228060Sbapt if (line < line_end && *line != '\n') 80228060Sbapt { 81228060Sbapt fprintf (stderr, "%s:%u: junk after declaration\n", 82228060Sbapt pretty_input_file_name (), lineno); 83228060Sbapt exit (1); 84228060Sbapt } 85228060Sbapt 86228060Sbapt return true; 87228060Sbapt} 88228060Sbapt 89228060Sbapt/* Tests if the given line contains a "%DECL=ARG" declaration. 90228060Sbapt If yes, it sets *ARGP to the argument, and returns true. 91228060Sbapt Otherwise, it returns false. */ 92228060Sbaptstatic bool 93228060Sbaptis_declaration_with_arg (const char *line, const char *line_end, 94228060Sbapt unsigned int lineno, 95228060Sbapt const char *decl, char **argp) 96228060Sbapt{ 97228060Sbapt /* Skip '%'. */ 98228060Sbapt line++; 99228060Sbapt 100228060Sbapt /* Skip DECL. */ 101228060Sbapt for (const char *d = decl; *d; d++) 102228060Sbapt { 103228060Sbapt if (!(line < line_end)) 104228060Sbapt return false; 105228060Sbapt if (!(*line == *d || (*d == '-' && *line == '_'))) 106228060Sbapt return false; 107228060Sbapt line++; 108228060Sbapt } 109228060Sbapt if (line < line_end 110228060Sbapt && ((*line >= 'A' && *line <= 'Z') 111228060Sbapt || (*line >= 'a' && *line <= 'z') 112228060Sbapt || *line == '-' || *line == '_')) 113228060Sbapt return false; 114228060Sbapt 115228060Sbapt /* OK, found DECL. */ 116228060Sbapt 117228060Sbapt /* Skip '='. */ 118228060Sbapt if (!(line < line_end && *line == '=')) 119228060Sbapt { 120228060Sbapt fprintf (stderr, "%s:%u: missing argument in %%%s=ARG declaration.\n", 121228060Sbapt pretty_input_file_name (), lineno, decl); 122228060Sbapt exit (1); 123228060Sbapt } 124228060Sbapt line++; 125228060Sbapt 126228060Sbapt /* The next word is the argument. */ 127228060Sbapt char *arg = new char[line_end - line + 1]; 128228060Sbapt char *p = arg; 129228060Sbapt while (line < line_end && !(*line == ' ' || *line == '\t' || *line == '\n')) 130228060Sbapt *p++ = *line++; 131228060Sbapt *p = '\0'; 132228060Sbapt 133228060Sbapt /* Skip whitespace. */ 134228060Sbapt while (line < line_end && (*line == ' ' || *line == '\t')) 135228060Sbapt line++; 136228060Sbapt 137228060Sbapt /* Expect end of line. */ 138228060Sbapt if (line < line_end && *line != '\n') 139228060Sbapt { 140228060Sbapt fprintf (stderr, "%s:%u: junk after declaration\n", 141228060Sbapt pretty_input_file_name (), lineno); 142228060Sbapt exit (1); 143228060Sbapt } 144228060Sbapt 145228060Sbapt *argp = arg; 146228060Sbapt return true; 147228060Sbapt} 148228060Sbapt 149228060Sbapt/* Tests if the given line contains a "%define DECL ARG" declaration. 150228060Sbapt If yes, it sets *ARGP to the argument, and returns true. 151228060Sbapt Otherwise, it returns false. */ 152228060Sbaptstatic bool 153228060Sbaptis_define_declaration (const char *line, const char *line_end, 154228060Sbapt unsigned int lineno, 155228060Sbapt const char *decl, char **argp) 156228060Sbapt{ 157228060Sbapt /* Skip '%'. */ 158228060Sbapt line++; 159228060Sbapt 160228060Sbapt /* Skip "define". */ 161228060Sbapt { 162228060Sbapt for (const char *d = "define"; *d; d++) 163228060Sbapt { 164228060Sbapt if (!(line < line_end)) 165228060Sbapt return false; 166228060Sbapt if (!(*line == *d)) 167228060Sbapt return false; 168228060Sbapt line++; 169228060Sbapt } 170228060Sbapt if (!(line < line_end && (*line == ' ' || *line == '\t'))) 171228060Sbapt return false; 172228060Sbapt } 173228060Sbapt 174228060Sbapt /* Skip whitespace. */ 175228060Sbapt while (line < line_end && (*line == ' ' || *line == '\t')) 176228060Sbapt line++; 177228060Sbapt 178228060Sbapt /* Skip DECL. */ 179228060Sbapt for (const char *d = decl; *d; d++) 180228060Sbapt { 181228060Sbapt if (!(line < line_end)) 182228060Sbapt return false; 183228060Sbapt if (!(*line == *d || (*d == '-' && *line == '_'))) 184228060Sbapt return false; 185228060Sbapt line++; 186228060Sbapt } 187228060Sbapt if (line < line_end 188228060Sbapt && ((*line >= 'A' && *line <= 'Z') 189228060Sbapt || (*line >= 'a' && *line <= 'z') 190228060Sbapt || *line == '-' || *line == '_')) 191228060Sbapt return false; 192228060Sbapt 193228060Sbapt /* OK, found DECL. */ 194228060Sbapt 195228060Sbapt /* Skip whitespace. */ 196228060Sbapt if (!(line < line_end && (*line == ' ' || *line == '\t'))) 197228060Sbapt { 198228060Sbapt fprintf (stderr, "%s:%u:" 199228060Sbapt " missing argument in %%define %s ARG declaration.\n", 200228060Sbapt pretty_input_file_name (), lineno, decl); 201228060Sbapt exit (1); 202228060Sbapt } 203228060Sbapt do 204228060Sbapt line++; 205228060Sbapt while (line < line_end && (*line == ' ' || *line == '\t')); 206228060Sbapt 207228060Sbapt /* The next word is the argument. */ 208228060Sbapt char *arg = new char[line_end - line + 1]; 209228060Sbapt char *p = arg; 210228060Sbapt while (line < line_end && !(*line == ' ' || *line == '\t' || *line == '\n')) 211228060Sbapt *p++ = *line++; 212228060Sbapt *p = '\0'; 213228060Sbapt 214228060Sbapt /* Skip whitespace. */ 215228060Sbapt while (line < line_end && (*line == ' ' || *line == '\t')) 216228060Sbapt line++; 217228060Sbapt 218228060Sbapt /* Expect end of line. */ 219228060Sbapt if (line < line_end && *line != '\n') 220228060Sbapt { 221228060Sbapt fprintf (stderr, "%s:%u: junk after declaration\n", 222228060Sbapt pretty_input_file_name (), lineno); 223228060Sbapt exit (1); 224228060Sbapt } 225228060Sbapt 226228060Sbapt *argp = arg; 227228060Sbapt return true; 228228060Sbapt} 229228060Sbapt 230228060Sbapt/* Reads the entire input file. */ 231228060Sbaptvoid 232228060SbaptInput::read_input () 233228060Sbapt{ 234228060Sbapt /* The input file has the following structure: 235228060Sbapt DECLARATIONS 236228060Sbapt %% 237228060Sbapt KEYWORDS 238228060Sbapt %% 239228060Sbapt ADDITIONAL_CODE 240228060Sbapt Since the DECLARATIONS and the ADDITIONAL_CODE sections are optional, 241228060Sbapt we have to read the entire file in the case there is only one %% 242228060Sbapt separator line, in order to determine whether the structure is 243228060Sbapt DECLARATIONS 244228060Sbapt %% 245228060Sbapt KEYWORDS 246228060Sbapt or 247228060Sbapt KEYWORDS 248228060Sbapt %% 249228060Sbapt ADDITIONAL_CODE 250228060Sbapt When the option -t is given or when the first section contains 251228060Sbapt declaration lines starting with %, we go for the first interpretation, 252228060Sbapt otherwise for the second interpretation. */ 253228060Sbapt 254228060Sbapt char *input = NULL; 255228060Sbapt size_t input_size = 0; 256228060Sbapt int input_length = get_delim (&input, &input_size, EOF, _stream); 257228060Sbapt if (input_length < 0) 258228060Sbapt { 259228060Sbapt if (ferror (_stream)) 260228060Sbapt fprintf (stderr, "%s: error while reading input file\n", 261228060Sbapt pretty_input_file_name ()); 262228060Sbapt else 263228060Sbapt fprintf (stderr, "%s: The input file is empty!\n", 264228060Sbapt pretty_input_file_name ()); 265228060Sbapt exit (1); 266228060Sbapt } 267228060Sbapt 268228060Sbapt /* We use input_end as a limit, in order to cope with NUL bytes in the 269228060Sbapt input. But note that one trailing NUL byte has been added after 270228060Sbapt input_end, for convenience. */ 271228060Sbapt char *input_end = input + input_length; 272228060Sbapt 273228060Sbapt const char *declarations; 274228060Sbapt const char *declarations_end; 275228060Sbapt const char *keywords; 276228060Sbapt const char *keywords_end; 277228060Sbapt unsigned int keywords_lineno; 278228060Sbapt 279228060Sbapt /* Break up the input into the three sections. */ 280228060Sbapt { 281228060Sbapt const char *separator[2] = { NULL, NULL }; 282228060Sbapt unsigned int separator_lineno[2] = { 0, 0 }; 283228060Sbapt int separators = 0; 284228060Sbapt { 285228060Sbapt unsigned int lineno = 1; 286228060Sbapt for (const char *p = input; p < input_end; ) 287228060Sbapt { 288228060Sbapt if (p[0] == '%' && p[1] == '%') 289228060Sbapt { 290228060Sbapt separator[separators] = p; 291228060Sbapt separator_lineno[separators] = lineno; 292228060Sbapt if (++separators == 2) 293228060Sbapt break; 294228060Sbapt } 295228060Sbapt lineno++; 296228060Sbapt p = (const char *) memchr (p, '\n', input_end - p); 297228060Sbapt if (p != NULL) 298228060Sbapt p++; 299228060Sbapt else 300228060Sbapt p = input_end; 301228060Sbapt } 302228060Sbapt } 303228060Sbapt 304228060Sbapt bool has_declarations; 305228060Sbapt if (separators == 1) 306228060Sbapt { 307228060Sbapt if (option[TYPE]) 308228060Sbapt has_declarations = true; 309228060Sbapt else 310228060Sbapt { 311228060Sbapt has_declarations = false; 312228060Sbapt for (const char *p = input; p < separator[0]; ) 313228060Sbapt { 314228060Sbapt if (p[0] == '%') 315228060Sbapt { 316228060Sbapt has_declarations = true; 317228060Sbapt break; 318228060Sbapt } 319228060Sbapt p = (const char *) memchr (p, '\n', separator[0] - p); 320228060Sbapt if (p != NULL) 321228060Sbapt p++; 322228060Sbapt else 323228060Sbapt p = separator[0]; 324228060Sbapt } 325228060Sbapt } 326228060Sbapt } 327228060Sbapt else 328228060Sbapt has_declarations = (separators > 0); 329228060Sbapt 330228060Sbapt if (has_declarations) 331228060Sbapt { 332228060Sbapt declarations = input; 333228060Sbapt declarations_end = separator[0]; 334228060Sbapt /* Give a warning if the separator line is nonempty. */ 335228060Sbapt bool nonempty_line = false; 336228060Sbapt const char *p; 337228060Sbapt for (p = declarations_end + 2; p < input_end; ) 338228060Sbapt { 339228060Sbapt if (*p == '\n') 340228060Sbapt { 341228060Sbapt p++; 342228060Sbapt break; 343228060Sbapt } 344228060Sbapt if (!(*p == ' ' || *p == '\t')) 345228060Sbapt nonempty_line = true; 346228060Sbapt p++; 347228060Sbapt } 348228060Sbapt if (nonempty_line) 349228060Sbapt fprintf (stderr, "%s:%u: warning: junk after %%%% is ignored\n", 350228060Sbapt pretty_input_file_name (), separator_lineno[0]); 351228060Sbapt keywords = p; 352228060Sbapt keywords_lineno = separator_lineno[0] + 1; 353228060Sbapt } 354228060Sbapt else 355228060Sbapt { 356228060Sbapt declarations = NULL; 357228060Sbapt declarations_end = NULL; 358228060Sbapt keywords = input; 359228060Sbapt keywords_lineno = 1; 360228060Sbapt } 361228060Sbapt 362228060Sbapt if (separators > (has_declarations ? 1 : 0)) 363228060Sbapt { 364228060Sbapt keywords_end = separator[separators-1]; 365228060Sbapt _verbatim_code = separator[separators-1] + 2; 366228060Sbapt _verbatim_code_end = input_end; 367228060Sbapt _verbatim_code_lineno = separator_lineno[separators-1]; 368228060Sbapt } 369228060Sbapt else 370228060Sbapt { 371228060Sbapt keywords_end = input_end; 372228060Sbapt _verbatim_code = NULL; 373228060Sbapt _verbatim_code_end = NULL; 374228060Sbapt _verbatim_code_lineno = 0; 375228060Sbapt } 376228060Sbapt } 377228060Sbapt 378228060Sbapt /* Parse the declarations section. */ 379228060Sbapt 380228060Sbapt _verbatim_declarations = NULL; 381228060Sbapt _verbatim_declarations_end = NULL; 382228060Sbapt _verbatim_declarations_lineno = 0; 383228060Sbapt _struct_decl = NULL; 384228060Sbapt _struct_decl_lineno = 0; 385228060Sbapt _return_type = NULL; 386228060Sbapt _struct_tag = NULL; 387228060Sbapt { 388228060Sbapt unsigned int lineno = 1; 389228060Sbapt char *struct_decl = NULL; 390228060Sbapt unsigned int *struct_decl_linenos = NULL; 391228060Sbapt unsigned int struct_decl_linecount = 0; 392228060Sbapt for (const char *line = declarations; line < declarations_end; ) 393228060Sbapt { 394228060Sbapt const char *line_end; 395228060Sbapt line_end = (const char *) memchr (line, '\n', declarations_end - line); 396228060Sbapt if (line_end != NULL) 397228060Sbapt line_end++; 398228060Sbapt else 399228060Sbapt line_end = declarations_end; 400228060Sbapt 401228060Sbapt if (*line == '%') 402228060Sbapt { 403228060Sbapt if (line[1] == '{') 404228060Sbapt { 405228060Sbapt /* Handle %{. */ 406228060Sbapt if (_verbatim_declarations != NULL) 407228060Sbapt { 408228060Sbapt fprintf (stderr, "%s:%u:\n%s:%u:" 409228060Sbapt " only one %%{...%%} section is allowed\n", 410228060Sbapt pretty_input_file_name (), 411228060Sbapt _verbatim_declarations_lineno, 412228060Sbapt pretty_input_file_name (), lineno); 413228060Sbapt exit (1); 414228060Sbapt } 415228060Sbapt _verbatim_declarations = line + 2; 416228060Sbapt _verbatim_declarations_lineno = lineno; 417228060Sbapt } 418228060Sbapt else if (line[1] == '}') 419228060Sbapt { 420228060Sbapt /* Handle %}. */ 421228060Sbapt if (_verbatim_declarations == NULL) 422228060Sbapt { 423228060Sbapt fprintf (stderr, "%s:%u:" 424228060Sbapt " %%} outside of %%{...%%} section\n", 425228060Sbapt pretty_input_file_name (), lineno); 426228060Sbapt exit (1); 427228060Sbapt } 428228060Sbapt if (_verbatim_declarations_end != NULL) 429228060Sbapt { 430228060Sbapt fprintf (stderr, "%s:%u:" 431228060Sbapt " %%{...%%} section already closed\n", 432228060Sbapt pretty_input_file_name (), lineno); 433228060Sbapt exit (1); 434228060Sbapt } 435228060Sbapt _verbatim_declarations_end = line; 436228060Sbapt /* Give a warning if the rest of the line is nonempty. */ 437228060Sbapt bool nonempty_line = false; 438228060Sbapt const char *q; 439228060Sbapt for (q = line + 2; q < line_end; q++) 440228060Sbapt { 441228060Sbapt if (*q == '\n') 442228060Sbapt { 443228060Sbapt q++; 444228060Sbapt break; 445228060Sbapt } 446228060Sbapt if (!(*q == ' ' || *q == '\t')) 447228060Sbapt nonempty_line = true; 448228060Sbapt } 449228060Sbapt if (nonempty_line) 450228060Sbapt fprintf (stderr, "%s:%u:" 451228060Sbapt " warning: junk after %%} is ignored\n", 452228060Sbapt pretty_input_file_name (), lineno); 453228060Sbapt } 454228060Sbapt else if (_verbatim_declarations != NULL 455228060Sbapt && _verbatim_declarations_end == NULL) 456228060Sbapt { 457228060Sbapt fprintf (stderr, "%s:%u:" 458228060Sbapt " warning: %% directives are ignored" 459228060Sbapt " inside the %%{...%%} section\n", 460228060Sbapt pretty_input_file_name (), lineno); 461228060Sbapt } 462228060Sbapt else 463228060Sbapt { 464228060Sbapt char *arg; 465228060Sbapt 466228060Sbapt if (is_declaration_with_arg (line, line_end, lineno, 467228060Sbapt "delimiters", &arg)) 468228060Sbapt option.set_delimiters (arg); 469228060Sbapt else 470228060Sbapt 471228060Sbapt if (is_declaration (line, line_end, lineno, "struct-type")) 472228060Sbapt option.set (TYPE); 473228060Sbapt else 474228060Sbapt 475228060Sbapt if (is_declaration (line, line_end, lineno, "ignore-case")) 476228060Sbapt option.set (UPPERLOWER); 477228060Sbapt else 478228060Sbapt 479228060Sbapt if (is_declaration_with_arg (line, line_end, lineno, 480228060Sbapt "language", &arg)) 481228060Sbapt option.set_language (arg); 482228060Sbapt else 483228060Sbapt 484228060Sbapt if (is_define_declaration (line, line_end, lineno, 485228060Sbapt "slot-name", &arg)) 486228060Sbapt option.set_slot_name (arg); 487228060Sbapt else 488228060Sbapt 489228060Sbapt if (is_define_declaration (line, line_end, lineno, 490228060Sbapt "initializer-suffix", &arg)) 491228060Sbapt option.set_initializer_suffix (arg); 492228060Sbapt else 493228060Sbapt 494228060Sbapt if (is_define_declaration (line, line_end, lineno, 495228060Sbapt "hash-function-name", &arg)) 496228060Sbapt option.set_hash_name (arg); 497228060Sbapt else 498228060Sbapt 499228060Sbapt if (is_define_declaration (line, line_end, lineno, 500228060Sbapt "lookup-function-name", &arg)) 501228060Sbapt option.set_function_name (arg); 502228060Sbapt else 503228060Sbapt 504228060Sbapt if (is_define_declaration (line, line_end, lineno, 505228060Sbapt "class-name", &arg)) 506228060Sbapt option.set_class_name (arg); 507228060Sbapt else 508228060Sbapt 509228060Sbapt if (is_declaration (line, line_end, lineno, "7bit")) 510228060Sbapt option.set (SEVENBIT); 511228060Sbapt else 512228060Sbapt 513228060Sbapt if (is_declaration (line, line_end, lineno, "compare-lengths")) 514228060Sbapt option.set (LENTABLE); 515228060Sbapt else 516228060Sbapt 517228060Sbapt if (is_declaration (line, line_end, lineno, "compare-strncmp")) 518228060Sbapt option.set (COMP); 519228060Sbapt else 520228060Sbapt 521228060Sbapt if (is_declaration (line, line_end, lineno, "readonly-tables")) 522228060Sbapt option.set (CONST); 523228060Sbapt else 524228060Sbapt 525228060Sbapt if (is_declaration (line, line_end, lineno, "enum")) 526228060Sbapt option.set (ENUM); 527228060Sbapt else 528228060Sbapt 529228060Sbapt if (is_declaration (line, line_end, lineno, "includes")) 530228060Sbapt option.set (INCLUDE); 531228060Sbapt else 532228060Sbapt 533228060Sbapt if (is_declaration (line, line_end, lineno, "global-table")) 534228060Sbapt option.set (GLOBAL); 535228060Sbapt else 536228060Sbapt 537228060Sbapt if (is_declaration (line, line_end, lineno, "pic")) 538228060Sbapt option.set (SHAREDLIB); 539228060Sbapt else 540228060Sbapt 541228060Sbapt if (is_define_declaration (line, line_end, lineno, 542228060Sbapt "string-pool-name", &arg)) 543228060Sbapt option.set_stringpool_name (arg); 544228060Sbapt else 545228060Sbapt 546228060Sbapt if (is_declaration (line, line_end, lineno, "null-strings")) 547228060Sbapt option.set (NULLSTRINGS); 548228060Sbapt else 549228060Sbapt 550228060Sbapt if (is_define_declaration (line, line_end, lineno, 551228060Sbapt "word-array-name", &arg)) 552228060Sbapt option.set_wordlist_name (arg); 553228060Sbapt else 554228060Sbapt 555228060Sbapt if (is_define_declaration (line, line_end, lineno, 556228060Sbapt "length-table-name", &arg)) 557228060Sbapt option.set_lengthtable_name (arg); 558228060Sbapt else 559228060Sbapt 560228060Sbapt if (is_declaration_with_arg (line, line_end, lineno, 561228060Sbapt "switch", &arg)) 562228060Sbapt { 563228060Sbapt option.set_total_switches (atoi (arg)); 564228060Sbapt if (option.get_total_switches () <= 0) 565228060Sbapt { 566228060Sbapt fprintf (stderr, "%s:%u: number of switches %s" 567228060Sbapt " must be a positive number\n", 568228060Sbapt pretty_input_file_name (), lineno, arg); 569228060Sbapt exit (1); 570228060Sbapt } 571228060Sbapt } 572228060Sbapt else 573228060Sbapt 574228060Sbapt if (is_declaration (line, line_end, lineno, "omit-struct-type")) 575228060Sbapt option.set (NOTYPE); 576228060Sbapt else 577228060Sbapt 578228060Sbapt { 579228060Sbapt fprintf (stderr, "%s:%u: unrecognized %% directive\n", 580228060Sbapt pretty_input_file_name (), lineno); 581228060Sbapt exit (1); 582228060Sbapt } 583228060Sbapt } 584228060Sbapt } 585228060Sbapt else if (!(_verbatim_declarations != NULL 586228060Sbapt && _verbatim_declarations_end == NULL)) 587228060Sbapt { 588228060Sbapt /* Append the line to struct_decl. */ 589228060Sbapt size_t old_len = (struct_decl ? strlen (struct_decl) : 0); 590228060Sbapt size_t line_len = line_end - line; 591228060Sbapt size_t new_len = old_len + line_len + 1; 592228060Sbapt char *new_struct_decl = new char[new_len]; 593228060Sbapt if (old_len > 0) 594228060Sbapt memcpy (new_struct_decl, struct_decl, old_len); 595228060Sbapt memcpy (new_struct_decl + old_len, line, line_len); 596228060Sbapt new_struct_decl[old_len + line_len] = '\0'; 597228060Sbapt if (struct_decl) 598228060Sbapt delete[] struct_decl; 599228060Sbapt struct_decl = new_struct_decl; 600228060Sbapt /* Append the lineno to struct_decl_linenos. */ 601228060Sbapt unsigned int *new_struct_decl_linenos = 602228060Sbapt new unsigned int[struct_decl_linecount + 1]; 603228060Sbapt if (struct_decl_linecount > 0) 604228060Sbapt memcpy (new_struct_decl_linenos, struct_decl_linenos, 605228060Sbapt struct_decl_linecount * sizeof (unsigned int)); 606228060Sbapt new_struct_decl_linenos[struct_decl_linecount] = lineno; 607228060Sbapt if (struct_decl_linenos) 608228060Sbapt delete[] struct_decl_linenos; 609228060Sbapt struct_decl_linenos = new_struct_decl_linenos; 610228060Sbapt /* Increment struct_decl_linecount. */ 611228060Sbapt struct_decl_linecount++; 612228060Sbapt } 613228060Sbapt lineno++; 614228060Sbapt line = line_end; 615228060Sbapt } 616228060Sbapt if (_verbatim_declarations != NULL && _verbatim_declarations_end == NULL) 617228060Sbapt { 618228060Sbapt fprintf (stderr, "%s:%u: unterminated %%{ section\n", 619228060Sbapt pretty_input_file_name (), _verbatim_declarations_lineno); 620228060Sbapt exit (1); 621228060Sbapt } 622228060Sbapt 623228060Sbapt /* Determine _struct_decl, _return_type, _struct_tag. */ 624228060Sbapt if (option[TYPE]) 625228060Sbapt { 626228060Sbapt if (struct_decl) 627228060Sbapt { 628228060Sbapt /* Drop leading whitespace and comments. */ 629228060Sbapt { 630228060Sbapt char *p = struct_decl; 631228060Sbapt unsigned int *l = struct_decl_linenos; 632228060Sbapt for (;;) 633228060Sbapt { 634228060Sbapt if (p[0] == ' ' || p[0] == '\t') 635228060Sbapt { 636228060Sbapt p++; 637228060Sbapt continue; 638228060Sbapt } 639228060Sbapt if (p[0] == '\n') 640228060Sbapt { 641228060Sbapt l++; 642228060Sbapt p++; 643228060Sbapt continue; 644228060Sbapt } 645228060Sbapt if (p[0] == '/') 646228060Sbapt { 647228060Sbapt if (p[1] == '*') 648228060Sbapt { 649228060Sbapt /* Skip over ANSI C style comment. */ 650228060Sbapt p += 2; 651228060Sbapt while (p[0] != '\0') 652228060Sbapt { 653228060Sbapt if (p[0] == '*' && p[1] == '/') 654228060Sbapt { 655228060Sbapt p += 2; 656228060Sbapt break; 657228060Sbapt } 658228060Sbapt if (p[0] == '\n') 659228060Sbapt l++; 660228060Sbapt p++; 661228060Sbapt } 662228060Sbapt continue; 663228060Sbapt } 664228060Sbapt if (p[1] == '/') 665228060Sbapt { 666228060Sbapt /* Skip over ISO C99 or C++ style comment. */ 667228060Sbapt p += 2; 668228060Sbapt while (p[0] != '\0' && p[0] != '\n') 669228060Sbapt p++; 670228060Sbapt if (p[0] == '\n') 671228060Sbapt { 672228060Sbapt l++; 673228060Sbapt p++; 674228060Sbapt } 675228060Sbapt continue; 676228060Sbapt } 677228060Sbapt } 678228060Sbapt break; 679228060Sbapt } 680228060Sbapt if (p != struct_decl) 681228060Sbapt { 682228060Sbapt size_t len = strlen (p); 683228060Sbapt char *new_struct_decl = new char[len + 1]; 684228060Sbapt memcpy (new_struct_decl, p, len + 1); 685228060Sbapt delete[] struct_decl; 686228060Sbapt struct_decl = new_struct_decl; 687228060Sbapt } 688228060Sbapt _struct_decl_lineno = *l; 689228060Sbapt } 690228060Sbapt /* Drop trailing whitespace. */ 691228060Sbapt for (char *p = struct_decl + strlen (struct_decl); p > struct_decl;) 692228060Sbapt if (p[-1] == '\n' || p[-1] == ' ' || p[-1] == '\t') 693228060Sbapt *--p = '\0'; 694228060Sbapt else 695228060Sbapt break; 696228060Sbapt } 697228060Sbapt if (struct_decl == NULL || struct_decl[0] == '\0') 698228060Sbapt { 699228060Sbapt fprintf (stderr, "%s: missing struct declaration" 700228060Sbapt " for option --struct-type\n", 701228060Sbapt pretty_input_file_name ()); 702228060Sbapt exit (1); 703228060Sbapt } 704228060Sbapt { 705228060Sbapt /* Ensure trailing semicolon. */ 706228060Sbapt size_t old_len = strlen (struct_decl); 707228060Sbapt if (struct_decl[old_len - 1] != ';') 708228060Sbapt { 709228060Sbapt char *new_struct_decl = new char[old_len + 2]; 710228060Sbapt memcpy (new_struct_decl, struct_decl, old_len); 711228060Sbapt new_struct_decl[old_len] = ';'; 712228060Sbapt new_struct_decl[old_len + 1] = '\0'; 713228060Sbapt delete[] struct_decl; 714228060Sbapt struct_decl = new_struct_decl; 715228060Sbapt } 716228060Sbapt } 717228060Sbapt /* Set _struct_decl to the entire declaration. */ 718228060Sbapt _struct_decl = struct_decl; 719228060Sbapt /* Set _struct_tag to the naked "struct something". */ 720228060Sbapt const char *p; 721228060Sbapt for (p = struct_decl; *p && *p != '{' && *p != ';' && *p != '\n'; p++) 722228060Sbapt ; 723228060Sbapt for (; p > struct_decl;) 724228060Sbapt if (p[-1] == '\n' || p[-1] == ' ' || p[-1] == '\t') 725228060Sbapt --p; 726228060Sbapt else 727228060Sbapt break; 728228060Sbapt size_t struct_tag_length = p - struct_decl; 729228060Sbapt char *struct_tag = new char[struct_tag_length + 1]; 730228060Sbapt memcpy (struct_tag, struct_decl, struct_tag_length); 731228060Sbapt struct_tag[struct_tag_length] = '\0'; 732228060Sbapt _struct_tag = struct_tag; 733228060Sbapt /* The return type of the lookup function is "struct something *". 734228060Sbapt No "const" here, because if !option[CONST], some user code might 735228060Sbapt want to modify the structure. */ 736228060Sbapt char *return_type = new char[struct_tag_length + 3]; 737228060Sbapt memcpy (return_type, struct_decl, struct_tag_length); 738228060Sbapt return_type[struct_tag_length] = ' '; 739228060Sbapt return_type[struct_tag_length + 1] = '*'; 740228060Sbapt return_type[struct_tag_length + 2] = '\0'; 741228060Sbapt _return_type = return_type; 742228060Sbapt } 743228060Sbapt 744228060Sbapt if (struct_decl_linenos) 745228060Sbapt delete[] struct_decl_linenos; 746228060Sbapt } 747228060Sbapt 748228060Sbapt /* Parse the keywords section. */ 749228060Sbapt { 750228060Sbapt Keyword_List **list_tail = &_head; 751228060Sbapt const char *delimiters = option.get_delimiters (); 752228060Sbapt unsigned int lineno = keywords_lineno; 753228060Sbapt bool charset_dependent = false; 754228060Sbapt for (const char *line = keywords; line < keywords_end; ) 755228060Sbapt { 756228060Sbapt const char *line_end; 757228060Sbapt line_end = (const char *) memchr (line, '\n', keywords_end - line); 758228060Sbapt if (line_end != NULL) 759228060Sbapt line_end++; 760228060Sbapt else 761228060Sbapt line_end = keywords_end; 762228060Sbapt 763228060Sbapt if (line[0] == '#') 764228060Sbapt ; /* Comment line. */ 765228060Sbapt else if (line[0] == '%') 766228060Sbapt { 767228060Sbapt fprintf (stderr, "%s:%u:" 768228060Sbapt " declarations are not allowed in the keywords section.\n" 769228060Sbapt "To declare a keyword starting with %%, enclose it in" 770228060Sbapt " double-quotes.\n", 771228060Sbapt pretty_input_file_name (), lineno); 772228060Sbapt exit (1); 773228060Sbapt } 774228060Sbapt else 775228060Sbapt { 776228060Sbapt /* An input line carrying a keyword. */ 777228060Sbapt const char *keyword; 778228060Sbapt size_t keyword_length; 779228060Sbapt const char *rest; 780228060Sbapt 781228060Sbapt if (line[0] == '"') 782228060Sbapt { 783228060Sbapt /* Parse a string in ANSI C syntax. */ 784228060Sbapt char *kp = new char[line_end-line]; 785228060Sbapt keyword = kp; 786228060Sbapt const char *lp = line + 1; 787228060Sbapt 788228060Sbapt for (;;) 789228060Sbapt { 790228060Sbapt if (lp == line_end) 791228060Sbapt { 792228060Sbapt fprintf (stderr, "%s:%u: unterminated string\n", 793228060Sbapt pretty_input_file_name (), lineno); 794228060Sbapt exit (1); 795228060Sbapt } 796228060Sbapt 797228060Sbapt char c = *lp; 798228060Sbapt if (c == '\\') 799228060Sbapt { 800228060Sbapt c = *++lp; 801228060Sbapt switch (c) 802228060Sbapt { 803228060Sbapt case '0': case '1': case '2': case '3': 804228060Sbapt case '4': case '5': case '6': case '7': 805228060Sbapt { 806228060Sbapt int code = 0; 807228060Sbapt int count = 0; 808228060Sbapt while (count < 3 && *lp >= '0' && *lp <= '7') 809228060Sbapt { 810228060Sbapt code = (code << 3) + (*lp - '0'); 811228060Sbapt lp++; 812228060Sbapt count++; 813228060Sbapt } 814228060Sbapt if (code > UCHAR_MAX) 815228060Sbapt fprintf (stderr, 816228060Sbapt "%s:%u: octal escape out of range\n", 817228060Sbapt pretty_input_file_name (), lineno); 818228060Sbapt *kp = static_cast<char>(code); 819228060Sbapt break; 820228060Sbapt } 821228060Sbapt case 'x': 822228060Sbapt { 823228060Sbapt int code = 0; 824228060Sbapt int count = 0; 825228060Sbapt lp++; 826228060Sbapt while ((*lp >= '0' && *lp <= '9') 827228060Sbapt || (*lp >= 'A' && *lp <= 'F') 828228060Sbapt || (*lp >= 'a' && *lp <= 'f')) 829228060Sbapt { 830228060Sbapt code = (code << 4) 831228060Sbapt + (*lp >= 'A' && *lp <= 'F' 832228060Sbapt ? *lp - 'A' + 10 : 833228060Sbapt *lp >= 'a' && *lp <= 'f' 834228060Sbapt ? *lp - 'a' + 10 : 835228060Sbapt *lp - '0'); 836228060Sbapt lp++; 837228060Sbapt count++; 838228060Sbapt } 839228060Sbapt if (count == 0) 840228060Sbapt fprintf (stderr, "%s:%u: hexadecimal escape" 841228060Sbapt " without any hex digits\n", 842228060Sbapt pretty_input_file_name (), lineno); 843228060Sbapt if (code > UCHAR_MAX) 844228060Sbapt fprintf (stderr, "%s:%u: hexadecimal escape" 845228060Sbapt " out of range\n", 846228060Sbapt pretty_input_file_name (), lineno); 847228060Sbapt *kp = static_cast<char>(code); 848228060Sbapt break; 849228060Sbapt } 850228060Sbapt case '\\': case '\'': case '"': 851228060Sbapt *kp = c; 852228060Sbapt lp++; 853228060Sbapt charset_dependent = true; 854228060Sbapt break; 855228060Sbapt case 'n': 856228060Sbapt *kp = '\n'; 857228060Sbapt lp++; 858228060Sbapt charset_dependent = true; 859228060Sbapt break; 860228060Sbapt case 't': 861228060Sbapt *kp = '\t'; 862228060Sbapt lp++; 863228060Sbapt charset_dependent = true; 864228060Sbapt break; 865228060Sbapt case 'r': 866228060Sbapt *kp = '\r'; 867228060Sbapt lp++; 868228060Sbapt charset_dependent = true; 869228060Sbapt break; 870228060Sbapt case 'f': 871228060Sbapt *kp = '\f'; 872228060Sbapt lp++; 873228060Sbapt charset_dependent = true; 874228060Sbapt break; 875228060Sbapt case 'b': 876228060Sbapt *kp = '\b'; 877228060Sbapt lp++; 878228060Sbapt charset_dependent = true; 879228060Sbapt break; 880228060Sbapt case 'a': 881228060Sbapt *kp = '\a'; 882228060Sbapt lp++; 883228060Sbapt charset_dependent = true; 884228060Sbapt break; 885228060Sbapt case 'v': 886228060Sbapt *kp = '\v'; 887228060Sbapt lp++; 888228060Sbapt charset_dependent = true; 889228060Sbapt break; 890228060Sbapt default: 891228060Sbapt fprintf (stderr, "%s:%u: invalid escape sequence" 892228060Sbapt " in string\n", 893228060Sbapt pretty_input_file_name (), lineno); 894228060Sbapt exit (1); 895228060Sbapt } 896228060Sbapt } 897228060Sbapt else if (c == '"') 898228060Sbapt break; 899228060Sbapt else 900228060Sbapt { 901228060Sbapt *kp = c; 902228060Sbapt lp++; 903228060Sbapt charset_dependent = true; 904228060Sbapt } 905228060Sbapt kp++; 906228060Sbapt } 907228060Sbapt lp++; 908228060Sbapt if (lp < line_end && *lp != '\n') 909228060Sbapt { 910228060Sbapt if (strchr (delimiters, *lp) == NULL) 911228060Sbapt { 912228060Sbapt fprintf (stderr, "%s:%u: string not followed" 913228060Sbapt " by delimiter\n", 914228060Sbapt pretty_input_file_name (), lineno); 915228060Sbapt exit (1); 916228060Sbapt } 917228060Sbapt lp++; 918228060Sbapt } 919228060Sbapt keyword_length = kp - keyword; 920228060Sbapt if (option[TYPE]) 921228060Sbapt { 922228060Sbapt char *line_rest = new char[line_end - lp + 1]; 923228060Sbapt memcpy (line_rest, lp, line_end - lp); 924228060Sbapt line_rest[line_end - lp - 925228060Sbapt (line_end > lp && line_end[-1] == '\n' ? 1 : 0)] 926228060Sbapt = '\0'; 927228060Sbapt rest = line_rest; 928228060Sbapt } 929228060Sbapt else 930228060Sbapt rest = empty_string; 931228060Sbapt } 932228060Sbapt else 933228060Sbapt { 934228060Sbapt /* Not a string. Look for the delimiter. */ 935228060Sbapt const char *lp = line; 936228060Sbapt for (;;) 937228060Sbapt { 938228060Sbapt if (!(lp < line_end && *lp != '\n')) 939228060Sbapt { 940228060Sbapt keyword = line; 941228060Sbapt keyword_length = lp - line; 942228060Sbapt rest = empty_string; 943228060Sbapt break; 944228060Sbapt } 945228060Sbapt if (strchr (delimiters, *lp) != NULL) 946228060Sbapt { 947228060Sbapt keyword = line; 948228060Sbapt keyword_length = lp - line; 949228060Sbapt lp++; 950228060Sbapt if (option[TYPE]) 951228060Sbapt { 952228060Sbapt char *line_rest = new char[line_end - lp + 1]; 953228060Sbapt memcpy (line_rest, lp, line_end - lp); 954228060Sbapt line_rest[line_end - lp - 955228060Sbapt (line_end > lp && line_end[-1] == '\n' 956228060Sbapt ? 1 : 0)] 957228060Sbapt = '\0'; 958228060Sbapt rest = line_rest; 959228060Sbapt } 960228060Sbapt else 961228060Sbapt rest = empty_string; 962228060Sbapt break; 963228060Sbapt } 964228060Sbapt lp++; 965228060Sbapt } 966228060Sbapt if (keyword_length > 0) 967228060Sbapt charset_dependent = true; 968228060Sbapt } 969228060Sbapt 970228060Sbapt /* Allocate Keyword and add it to the list. */ 971228060Sbapt Keyword *new_kw = _factory->create_keyword (keyword, keyword_length, 972228060Sbapt rest); 973228060Sbapt new_kw->_lineno = lineno; 974228060Sbapt *list_tail = new Keyword_List (new_kw); 975228060Sbapt list_tail = &(*list_tail)->rest(); 976228060Sbapt } 977228060Sbapt 978228060Sbapt lineno++; 979228060Sbapt line = line_end; 980228060Sbapt } 981228060Sbapt *list_tail = NULL; 982228060Sbapt 983228060Sbapt if (_head == NULL) 984228060Sbapt { 985228060Sbapt fprintf (stderr, "%s: No keywords in input file!\n", 986228060Sbapt pretty_input_file_name ()); 987228060Sbapt exit (1); 988228060Sbapt } 989228060Sbapt 990228060Sbapt _charset_dependent = charset_dependent; 991228060Sbapt } 992228060Sbapt 993228060Sbapt /* To be freed in the destructor. */ 994228060Sbapt _input = input; 995228060Sbapt _input_end = input_end; 996228060Sbapt} 997228060Sbapt 998228060SbaptInput::~Input () 999228060Sbapt{ 1000228060Sbapt /* Free allocated memory. */ 1001228060Sbapt delete[] const_cast<char*>(_return_type); 1002228060Sbapt delete[] const_cast<char*>(_struct_tag); 1003228060Sbapt delete[] const_cast<char*>(_struct_decl); 1004228060Sbapt delete[] _input; 1005228060Sbapt} 1006