LCOV - code coverage report
Current view: top level - libreoffice/workdir/unxlngi6.pro/UnpackedTarball/ucpp - cpp.c (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 0 1255 0.0 %
Date: 2012-12-17 Functions: 0 47 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * C and T preprocessor, and integrated lexer
       3             :  * (c) Thomas Pornin 1999 - 2002
       4             :  *
       5             :  * Redistribution and use in source and binary forms, with or without
       6             :  * modification, are permitted provided that the following conditions
       7             :  * are met:
       8             :  * 1. Redistributions of source code must retain the above copyright
       9             :  *    notice, this list of conditions and the following disclaimer.
      10             :  * 2. Redistributions in binary form must reproduce the above copyright
      11             :  *    notice, this list of conditions and the following disclaimer in the
      12             :  *    documentation and/or other materials provided with the distribution.
      13             :  * 4. The name of the authors may not be used to endorse or promote
      14             :  *    products derived from this software without specific prior written
      15             :  *    permission.
      16             :  *
      17             :  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
      18             :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
      19             :  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      20             :  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
      21             :  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      22             :  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
      23             :  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
      24             :  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
      25             :  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
      26             :  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
      27             :  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      28             :  *
      29             :  */
      30             : 
      31             : #define VERS_MAJ        1
      32             : #define VERS_MIN        3
      33             : /* uncomment the following if you cannot set it with a compiler flag */
      34             : /* #define STAND_ALONE */
      35             : 
      36             : #include "tune.h"
      37             : #include <stdio.h>
      38             : #include <string.h>
      39             : #include <stdarg.h>
      40             : #include <setjmp.h>
      41             : #include <stddef.h>
      42             : #include <limits.h>
      43             : #include <time.h>
      44             : #include "ucppi.h"
      45             : #include "mem.h"
      46             : #include "nhash.h"
      47             : #ifdef UCPP_MMAP
      48             : #include <unistd.h>
      49             : #include <sys/types.h>
      50             : #include <sys/mman.h>
      51             : #include <fcntl.h>
      52             : #endif
      53             : 
      54             : /*
      55             :  * The standard path where includes are looked for.
      56             :  */
      57             : #ifdef STAND_ALONE
      58             : static char *include_path_std[] = { STD_INCLUDE_PATH, 0 };
      59             : #endif
      60             : static char **include_path;
      61             : static size_t include_path_nb = 0;
      62             : 
      63             : int no_special_macros = 0;
      64             : int emit_dependencies = 0, emit_defines = 0, emit_assertions = 0;
      65             : FILE *emit_output;
      66             : 
      67             : #ifdef STAND_ALONE
      68             : static char *system_macros_def[] = { STD_MACROS, 0 };
      69             : static char *system_assertions_def[] = { STD_ASSERT, 0 };
      70             : #endif
      71             : 
      72             : char *current_filename = 0, *current_long_filename = 0;
      73             : static int current_incdir = -1;
      74             : 
      75             : #ifndef NO_UCPP_ERROR_FUNCTIONS
      76             : /*
      77             :  * "ouch" is the name for an internal ucpp error. If AUDIT is not defined,
      78             :  * no code calling this function will be generated; a "ouch" may still be
      79             :  * emitted by getmem() (in mem.c) if MEM_CHECK is defined, but this "ouch"
      80             :  * does not use this function.
      81             :  */
      82           0 : void ucpp_ouch(char *fmt, ...)
      83             : {
      84             :         va_list ap;
      85             : 
      86           0 :         va_start(ap, fmt);
      87           0 :         fprintf(stderr, "%s: ouch, ", current_filename);
      88           0 :         vfprintf(stderr, fmt, ap);
      89           0 :         fprintf(stderr, "\n");
      90           0 :         va_end(ap);
      91           0 :         die();
      92           0 : }
      93             : 
      94             : /*
      95             :  * report an error, with current_filename, line, and printf-like syntax
      96             :  */
      97           0 : void ucpp_error(long line, char *fmt, ...)
      98             : {
      99             :         va_list ap;
     100             : 
     101           0 :         va_start(ap, fmt);
     102           0 :         if (line > 0)
     103           0 :                 fprintf(stderr, "%s: line %ld: ", current_filename, line);
     104           0 :         else if (line == 0) fprintf(stderr, "%s: ", current_filename);
     105           0 :         vfprintf(stderr, fmt, ap);
     106           0 :         fprintf(stderr, "\n");
     107           0 :         if (line >= 0) {
     108           0 :                 struct stack_context *sc = report_context();
     109             :                 size_t i;
     110             : 
     111           0 :                 for (i = 0; sc[i].line >= 0; i ++)
     112           0 :                         fprintf(stderr, "\tincluded from %s:%ld\n",
     113           0 :                                 sc[i].long_name ? sc[i].long_name : sc[i].name,
     114           0 :                                 sc[i].line);
     115           0 :                 freemem(sc);
     116             :         }
     117           0 :         va_end(ap);
     118           0 : }
     119             : 
     120             : /*
     121             :  * like error(), with the mention "warning"
     122             :  */
     123           0 : void ucpp_warning(long line, char *fmt, ...)
     124             : {
     125             :         va_list ap;
     126             : 
     127           0 :         va_start(ap, fmt);
     128           0 :         if (line > 0)
     129           0 :                 fprintf(stderr, "%s: warning: line %ld: ",
     130             :                         current_filename, line);
     131           0 :         else if (line == 0)
     132           0 :                 fprintf(stderr, "%s: warning: ", current_filename);
     133           0 :         else fprintf(stderr, "warning: ");
     134           0 :         vfprintf(stderr, fmt, ap);
     135           0 :         fprintf(stderr, "\n");
     136           0 :         if (line >= 0) {
     137           0 :                 struct stack_context *sc = report_context();
     138             :                 size_t i;
     139             : 
     140           0 :                 for (i = 0; sc[i].line >= 0; i ++)
     141           0 :                         fprintf(stderr, "\tincluded from %s:%ld\n",
     142           0 :                                 sc[i].long_name ? sc[i].long_name : sc[i].name,
     143           0 :                                 sc[i].line);
     144           0 :                 freemem(sc);
     145             :         }
     146           0 :         va_end(ap);
     147           0 : }
     148             : #endif  /* NO_UCPP_ERROR_FUNCTIONS */
     149             : 
     150             : /*
     151             :  * Some memory allocations are manually garbage-collected; essentially,
     152             :  * strings duplicated in the process of macro replacement. Each such
     153             :  * string is referenced in the garbage_fifo, which is cleared when all
     154             :  * nested macros have been resolved.
     155             :  */
     156             : 
     157             : struct garbage_fifo {
     158             :         char **garbage;
     159             :         size_t ngarb, memgarb;
     160             : };
     161             : 
     162             : /*
     163             :  * throw_away() marks a string to be collected later
     164             :  */
     165           0 : void throw_away(struct garbage_fifo *gf, char *n)
     166             : {
     167           0 :         wan(gf->garbage, gf->ngarb, n, gf->memgarb);
     168           0 : }
     169             : 
     170             : /*
     171             :  * free marked strings
     172             :  */
     173           0 : void garbage_collect(struct garbage_fifo *gf)
     174             : {
     175             :         size_t i;
     176             : 
     177           0 :         for (i = 0; i < gf->ngarb; i ++) freemem(gf->garbage[i]);
     178           0 :         gf->ngarb = 0;
     179           0 : }
     180             : 
     181           0 : static void init_garbage_fifo(struct garbage_fifo *gf)
     182             : {
     183           0 :         gf->garbage = getmem((gf->memgarb = GARBAGE_LIST_MEMG)
     184             :                 * sizeof(char *));
     185           0 :         gf->ngarb = 0;
     186           0 : }
     187             : 
     188           0 : static void free_garbage_fifo(struct garbage_fifo *gf)
     189             : {
     190           0 :         garbage_collect(gf);
     191           0 :         freemem(gf->garbage);
     192           0 :         freemem(gf);
     193           0 : }
     194             : 
     195             : /*
     196             :  * order is important: it must match the token-constants declared as an
     197             :  * enum in the header file.
     198             :  */
     199             : char *operators_name[] = {
     200             :         " ", "\n", " ",
     201             :         "0000", "name", "bunch", "pragma", "context",
     202             :         "\"dummy string\"", "'dummy char'",
     203             :         "/", "/=", "-", "--", "-=", "->", "+", "++", "+=", "<", "<=", "<<",
     204             :         "<<=", ">", ">=", ">>", ">>=", "=", "==",
     205             : #ifdef CAST_OP
     206             :         "=>",
     207             : #endif
     208             :         "~", "!=", "&", "&&", "&=", "|", "||", "|=", "%", "%=", "*", "*=",
     209             :         "^", "^=", "!",
     210             :         "{", "}", "[", "]", "(", ")", ",", "?", ";",
     211             :         ":", ".", "...", "#", "##", " ", "ouch", "<:", ":>", "<%", "%>",
     212             :         "%:", "%:%:"
     213             : };
     214             : 
     215             : /* the ascii representation of a token */
     216             : #ifdef SEMPER_FIDELIS
     217             : #define tname(x)        (ttWHI((x).type) ? " " : S_TOKEN((x).type) \
     218             :                         ? (x).name : operators_name[(x).type])
     219             : #else
     220             : #define tname(x)        (S_TOKEN((x).type) ? (x).name \
     221             :                         : operators_name[(x).type])
     222             : #endif
     223             : 
     224           0 : char *token_name(struct token *t)
     225             : {
     226           0 :         return tname(*t);
     227             : }
     228             : 
     229             : /*
     230             :  * To speed up deeply nested and repeated inclusions, we:
     231             :  * -- use a hash table to remember where we found each file
     232             :  * -- remember when the file is protected by a #ifndef/#define/#endif
     233             :  *    construction; we can then avoid including several times a file
     234             :  *    when this is not necessary.
     235             :  * -- remember in which directory, in the include path, the file was found.
     236             :  */
     237             : struct found_file {
     238             :         hash_item_header head;    /* first field */
     239             :         char *name;
     240             :         char *protect;
     241             : };
     242             : 
     243             : /*
     244             :  * For files from system include path.
     245             :  */
     246             : struct found_file_sys {
     247             :         hash_item_header head;    /* first field */
     248             :         struct found_file *rff;
     249             :         int incdir;
     250             : };
     251             : 
     252             : static HTT found_files, found_files_sys;
     253             : static int found_files_init_done = 0, found_files_sys_init_done = 0;
     254             : 
     255           0 : static struct found_file *new_found_file(void)
     256             : {
     257           0 :         struct found_file *ff = getmem(sizeof(struct found_file));
     258             : 
     259           0 :         ff->name = 0;
     260           0 :         ff->protect = 0;
     261           0 :         return ff;
     262             : }
     263             : 
     264           0 : static void del_found_file(void *m)
     265             : {
     266           0 :         struct found_file *ff = (struct found_file *)m;
     267             : 
     268           0 :         if (ff->name) freemem(ff->name);
     269           0 :         if (ff->protect) freemem(ff->protect);
     270           0 :         freemem(ff);
     271           0 : }
     272             : 
     273           0 : static struct found_file_sys *new_found_file_sys(void)
     274             : {
     275           0 :         struct found_file_sys *ffs = getmem(sizeof(struct found_file_sys));
     276             : 
     277           0 :         ffs->rff = 0;
     278           0 :         ffs->incdir = -1;
     279           0 :         return ffs;
     280             : }
     281             : 
     282           0 : static void del_found_file_sys(void *m)
     283             : {
     284           0 :         struct found_file_sys *ffs = (struct found_file_sys *)m;
     285             : 
     286           0 :         freemem(ffs);
     287           0 : }
     288             : 
     289             : /*
     290             :  * To keep up with the #ifndef/#define/#endif protection mechanism
     291             :  * detection.
     292             :  */
     293             : struct protect protect_detect;
     294             : static struct protect *protect_detect_stack = 0;
     295             : 
     296           0 : void set_init_filename(char *x, int real_file)
     297             : {
     298           0 :         if (current_filename) freemem(current_filename);
     299           0 :         current_filename = sdup(x);
     300           0 :         current_long_filename = 0;
     301           0 :         current_incdir = -1;
     302           0 :         if (real_file) {
     303           0 :                 protect_detect.macro = 0;
     304           0 :                 protect_detect.state = 1;
     305           0 :                 protect_detect.ff = new_found_file();
     306           0 :                 protect_detect.ff->name = sdup(x);
     307           0 :                 HTT_put(&found_files, protect_detect.ff, x);
     308             :         } else {
     309           0 :                 protect_detect.state = 0;
     310             :         }
     311           0 : }
     312             : 
     313           0 : static void init_found_files(void)
     314             : {
     315           0 :         if (found_files_init_done) HTT_kill(&found_files);
     316           0 :         HTT_init(&found_files, del_found_file);
     317           0 :         found_files_init_done = 1;
     318           0 :         if (found_files_sys_init_done) HTT_kill(&found_files_sys);
     319           0 :         HTT_init(&found_files_sys, del_found_file_sys);
     320           0 :         found_files_sys_init_done = 1;
     321           0 : }
     322             : 
     323             : /*
     324             :  * Set the lexer state at the beginning of a file.
     325             :  */
     326           0 : static void reinit_lexer_state(struct lexer_state *ls, int wb)
     327             : {
     328             : #ifndef NO_UCPP_BUF
     329             :         ls->input_buf = wb ? getmem(INPUT_BUF_MEMG) : 0;
     330             : #ifdef UCPP_MMAP
     331             :         ls->from_mmap = 0;
     332             : #endif
     333             : #endif
     334           0 :         ls->input = 0;
     335           0 :         ls->ebuf = ls->pbuf = 0;
     336           0 :         ls->nlka = 0;
     337           0 :         ls->macfile = 0;
     338           0 :         ls->discard = 1;
     339           0 :         ls->last = 0;                /* we suppose '\n' is not 0 */
     340           0 :         ls->line = 1;
     341           0 :         ls->ltwnl = 1;
     342           0 :         ls->oline = 1;
     343           0 :         ls->pending_token = 0;
     344           0 :         ls->cli = 0;
     345           0 :         ls->copy_line[COPY_LINE_LENGTH - 1] = 0;
     346           0 :         ls->ifnest = 0;
     347           0 :         ls->condf[0] = ls->condf[1] = 0;
     348           0 : }
     349             : 
     350             : /*
     351             :  * Initialize the struct lexer_state, with optional input and output buffers.
     352             :  */
     353           0 : void init_buf_lexer_state(struct lexer_state *ls, int wb)
     354             : {
     355           0 :         reinit_lexer_state(ls, wb);
     356             : #ifndef NO_UCPP_BUF
     357             :         ls->output_buf = wb ? getmem(OUTPUT_BUF_MEMG) : 0;
     358             : #endif
     359           0 :         ls->sbuf = 0;
     360           0 :         ls->output_fifo = 0;
     361             : 
     362           0 :         ls->ctok = getmem(sizeof(struct token));
     363           0 :         ls->ctok->name = getmem(ls->tknl = TOKEN_NAME_MEMG);
     364           0 :         ls->pending_token = 0;
     365             : 
     366           0 :         ls->flags = 0;
     367           0 :         ls->count_trigraphs = 0;
     368           0 :         ls->gf = getmem(sizeof(struct garbage_fifo));
     369           0 :         init_garbage_fifo(ls->gf);
     370           0 :         ls->condcomp = 1;
     371           0 :         ls->condnest = 0;
     372             : #ifdef INMACRO_FLAG
     373             :         ls->inmacro = 0;
     374             :         ls->macro_count = 0;
     375             : #endif
     376           0 : }
     377             : 
     378             : /*
     379             :  * Initialize the (complex) struct lexer_state.
     380             :  */
     381           0 : void init_lexer_state(struct lexer_state *ls)
     382             : {
     383           0 :         init_buf_lexer_state(ls, 1);
     384           0 :         ls->input = 0;
     385           0 : }
     386             : 
     387             : /*
     388             :  * Restore what is needed from a lexer_state. This is used for #include.
     389             :  */
     390           0 : static void restore_lexer_state(struct lexer_state *ls,
     391             :         struct lexer_state *lsbak)
     392             : {
     393             : #ifndef NO_UCPP_BUF
     394             :         freemem(ls->input_buf);
     395             :         ls->input_buf = lsbak->input_buf;
     396             : #ifdef UCPP_MMAP
     397             :         ls->from_mmap = lsbak->from_mmap;
     398             :         ls->input_buf_sav = lsbak->input_buf_sav;
     399             : #endif
     400             : #endif
     401           0 :         ls->input = lsbak->input;
     402           0 :         ls->ebuf = lsbak->ebuf;
     403           0 :         ls->pbuf = lsbak->pbuf;
     404           0 :         ls->nlka = lsbak->nlka;
     405           0 :         ls->discard = lsbak->discard;
     406           0 :         ls->line = lsbak->line;
     407           0 :         ls->oline = lsbak->oline;
     408           0 :         ls->ifnest = lsbak->ifnest;
     409           0 :         ls->condf[0] = lsbak->condf[0];
     410           0 :         ls->condf[1] = lsbak->condf[1];
     411           0 : }
     412             : 
     413             : /*
     414             :  * close input file operations on a struct lexer_state
     415             :  */
     416           0 : static void close_input(struct lexer_state *ls)
     417             : {
     418             : #ifdef UCPP_MMAP
     419             :         if (ls->from_mmap) {
     420             :                 munmap((void *)ls->input_buf, ls->ebuf);
     421             :                 ls->from_mmap = 0;
     422             :                 ls->input_buf = ls->input_buf_sav;
     423             :         }
     424             : #endif
     425           0 :         if (ls->input) {
     426           0 :                 fclose(ls->input);
     427           0 :                 ls->input = 0;
     428             :         }
     429           0 : }
     430             : 
     431             : /*
     432             :  * file_context (and the two functions push_ and pop_) are used to save
     433             :  * all that is needed when including a file.
     434             :  */
     435             : static struct file_context {
     436             :         struct lexer_state ls;
     437             :         char *name, *long_name;
     438             :         int incdir;
     439             : } *ls_stack;
     440             : static size_t ls_depth = 0;
     441             : 
     442           0 : static void push_file_context(struct lexer_state *ls)
     443             : {
     444             :         struct file_context fc;
     445             : 
     446           0 :         fc.name = current_filename;
     447           0 :         fc.long_name = current_long_filename;
     448           0 :         fc.incdir = current_incdir;
     449           0 :         mmv(&(fc.ls), ls, sizeof(struct lexer_state));
     450           0 :         aol(ls_stack, ls_depth, fc, LS_STACK_MEMG);
     451           0 :         ls_depth --;
     452           0 :         aol(protect_detect_stack, ls_depth, protect_detect, LS_STACK_MEMG);
     453           0 :         protect_detect.macro = 0;
     454           0 : }
     455             : 
     456           0 : static void pop_file_context(struct lexer_state *ls)
     457             : {
     458             : #ifdef AUDIT
     459             :         if (ls_depth <= 0) ouch("prepare to meet thy creator");
     460             : #endif
     461           0 :         close_input(ls);
     462           0 :         restore_lexer_state(ls, &(ls_stack[-- ls_depth].ls));
     463           0 :         if (protect_detect.macro) freemem(protect_detect.macro);
     464           0 :         protect_detect = protect_detect_stack[ls_depth];
     465           0 :         if (current_filename) freemem(current_filename);
     466           0 :         current_filename = ls_stack[ls_depth].name;
     467           0 :         current_long_filename = ls_stack[ls_depth].long_name;
     468           0 :         current_incdir = ls_stack[ls_depth].incdir;
     469           0 :         if (ls_depth == 0) {
     470           0 :                 freemem(ls_stack);
     471           0 :                 freemem(protect_detect_stack);
     472             :         }
     473           0 : }
     474             : 
     475             : /*
     476             :  * report_context() returns the list of successive includers of the
     477             :  * current file, ending with a dummy entry with a negative line number.
     478             :  * The caller is responsible for freeing the returned pointer.
     479             :  */
     480           0 : struct stack_context *report_context(void)
     481             : {
     482             :         struct stack_context *sc;
     483             :         size_t i;
     484             : 
     485           0 :         sc = getmem((ls_depth + 1) * sizeof(struct stack_context));
     486           0 :         for (i = 0; i < ls_depth; i ++) {
     487           0 :                 sc[i].name = ls_stack[ls_depth - i - 1].name;
     488           0 :                 sc[i].long_name = ls_stack[ls_depth - i - 1].long_name;
     489           0 :                 sc[i].line = ls_stack[ls_depth - i - 1].ls.line - 1;
     490             :         }
     491           0 :         sc[ls_depth].line = -1;
     492           0 :         return sc;
     493             : }
     494             : 
     495             : /*
     496             :  * init_lexer_mode() is used to end initialization of a struct lexer_state
     497             :  * if it must be used for a lexer
     498             :  */
     499           0 : void init_lexer_mode(struct lexer_state *ls)
     500             : {
     501           0 :         ls->flags = DEFAULT_LEXER_FLAGS;
     502           0 :         ls->output_fifo = getmem(sizeof(struct token_fifo));
     503           0 :         ls->output_fifo->art = ls->output_fifo->nt = 0;
     504           0 :         ls->toplevel_of = ls->output_fifo;
     505           0 :         ls->save_ctok = ls->ctok;
     506           0 : }
     507             : 
     508             : /*
     509             :  * release memory used by a struct lexer_state; this implies closing
     510             :  * any input stream held by this structure.
     511             :  */
     512           0 : void free_lexer_state(struct lexer_state *ls)
     513             : {
     514           0 :         close_input(ls);
     515             : #ifndef NO_UCPP_BUF
     516             :         if (ls->input_buf) {
     517             :                 freemem(ls->input_buf);
     518             :                 ls->input_buf = 0;
     519             :         }
     520             :         if (ls->output_buf) {
     521             :                 freemem(ls->output_buf);
     522             :                 ls->output_buf = 0;
     523             :         }
     524             : #endif
     525           0 :         if (ls->ctok && (!ls->output_fifo || ls->output_fifo->nt == 0)) {
     526           0 :                 freemem(ls->ctok->name);
     527           0 :                 freemem(ls->ctok);
     528           0 :                 ls->ctok = 0;
     529             :         }
     530           0 :         if (ls->gf) {
     531           0 :                 free_garbage_fifo(ls->gf);
     532           0 :                 ls->gf = 0;
     533             :         }
     534           0 :         if (ls->output_fifo) {
     535           0 :                 freemem(ls->output_fifo);
     536           0 :                 ls->output_fifo = 0;
     537             :         }
     538           0 : }
     539             : 
     540             : /*
     541             :  * Print line information.
     542             :  */
     543           0 : static void print_line_info(struct lexer_state *ls, unsigned long flags)
     544             : {
     545           0 :         char *fn = current_long_filename ?
     546           0 :                 current_long_filename : current_filename;
     547             :         char *b, *d;
     548             : 
     549           0 :         b = getmem(50 + strlen(fn));
     550           0 :         if (flags & GCC_LINE_NUM) {
     551           0 :                 sprintf(b, "# %ld \"%s\"\n", ls->line, fn);
     552             :         } else {
     553           0 :                 sprintf(b, "#line %ld \"%s\"\n", ls->line, fn);
     554             :         }
     555           0 :         for (d = b; *d; d ++) put_char(ls, (unsigned char)(*d));
     556           0 :         freemem(b);
     557           0 : }
     558             : 
     559             : /*
     560             :  * Enter a file; this implies the possible emission of a #line directive.
     561             :  * The flags used are passed as second parameter instead of being
     562             :  * extracted from the struct lexer_state.
     563             :  *
     564             :  * As a command-line option, gcc-like directives (with only a '#',
     565             :  * without 'line') may be produced.
     566             :  *
     567             :  * enter_file() returns 1 if a (CONTEXT) token was produced, 0 otherwise.
     568             :  */
     569           0 : int enter_file(struct lexer_state *ls, unsigned long flags)
     570             : {
     571           0 :         char *fn = current_long_filename ?
     572           0 :                 current_long_filename : current_filename;
     573             : 
     574           0 :         if (!(flags & LINE_NUM)) return 0;
     575           0 :         if ((flags & LEXER) && !(flags & TEXT_OUTPUT)) {
     576             :                 struct token t;
     577             : 
     578           0 :                 t.type = CONTEXT;
     579           0 :                 t.line = ls->line;
     580           0 :                 t.name = fn;
     581           0 :                 print_token(ls, &t, 0);
     582           0 :                 return 1;
     583             :         }
     584           0 :         print_line_info(ls, flags);
     585           0 :         ls->oline --;        /* emitted #line troubled oline */
     586           0 :         return 0;
     587             : }
     588             : 
     589             : #ifdef UCPP_MMAP
     590             : /*
     591             :  * We open() the file, then fdopen() it and fseek() to its end. If the
     592             :  * fseek() worked, we try to mmap() the file, up to the point where we
     593             :  * arrived.
     594             :  * On an architecture where end-of-lines are multibytes and translated
     595             :  * into single '\n', bad things could happen. We strongly hope that, if
     596             :  * we could fseek() to the end but could not mmap(), then we can get back.
     597             :  */
     598             : static void *find_file_map;
     599             : static size_t map_length;
     600             : 
     601             : FILE *fopen_mmap_file(char *name)
     602             : {
     603             :         FILE *f;
     604             :         int fd;
     605             :         long l;
     606             : 
     607             :         find_file_map = 0;
     608             :         fd = open(name, O_RDONLY, 0);
     609             :         if (fd < 0) return 0;
     610             :         l = lseek(fd, 0, SEEK_END);
     611             :         f = fdopen(fd, "r");
     612             :         if (!f) {
     613             :                 close(fd);
     614             :                 return 0;
     615             :         }
     616             :         if (l < 0) return f; /* not seekable */
     617             :         map_length = l;
     618             :         if ((find_file_map = mmap(0, map_length, PROT_READ,
     619             :                 MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
     620             :                 /* we could not mmap() the file; get back */
     621             :                 find_file_map = 0;
     622             :                 if (fseek(f, 0, SEEK_SET)) {
     623             :                         /* bwaah... can't get back. This file is cursed. */
     624             :                         fclose(f);
     625             :                         return 0;
     626             :                 }
     627             :         }
     628             :         return f;
     629             : }
     630             : 
     631             : void set_input_file(struct lexer_state *ls, FILE *f)
     632             : {
     633             :         ls->input = f;
     634             :         if (find_file_map) {
     635             :                 ls->from_mmap = 1;
     636             :                 ls->input_buf_sav = ls->input_buf;
     637             :                 ls->input_buf = find_file_map;
     638             :                 ls->pbuf = 0;
     639             :                 ls->ebuf = map_length;
     640             :         } else {
     641             :                 ls->from_mmap = 0;
     642             :         }
     643             : }
     644             : #endif
     645             : 
     646             : /*
     647             :  * Find a file by looking through the include path.
     648             :  * return value: a FILE * on the file, opened in "r" mode, or 0.
     649             :  *
     650             :  * find_file_error will contain:
     651             :  *   FF_ERROR      on error (file not found or impossible to read)
     652             :  *   FF_PROTECT    file is protected and therefore useless to read
     653             :  *   FF_KNOWN      file is already known
     654             :  *   FF_UNKNOWN    file was not already known
     655             :  */
     656             : static int find_file_error;
     657             : 
     658             : enum { FF_ERROR, FF_PROTECT, FF_KNOWN, FF_UNKNOWN };
     659             : 
     660           0 : static FILE *find_file(char *name, int localdir)
     661             : {
     662             :         FILE *f;
     663           0 :         int i, incdir = -1;
     664           0 :         size_t nl = strlen(name);
     665           0 :         char *s = 0;
     666           0 :         struct found_file *ff = 0, *nff;
     667           0 :         int lf = 0;
     668           0 :         int nffa = 0;
     669             : 
     670           0 :         find_file_error = FF_ERROR;
     671           0 :         protect_detect.state = -1;
     672           0 :         protect_detect.macro = 0;
     673           0 :         if (localdir) {
     674             :                 int i;
     675           0 :                 char *rfn = current_long_filename ? current_long_filename
     676           0 :                         : current_filename;
     677             : 
     678           0 :                 for (i = strlen(rfn) - 1; i >= 0; i --)
     679             : #ifdef MSDOS
     680             :                         if (rfn[i] == '\\') break;
     681             : #else
     682           0 :                         if (rfn[i] == '/') break;
     683             : #endif
     684             : #if defined MSDOS
     685             :                 if (i >= 0 && *name != '\\' && (nl < 2 || name[1] != ':'))
     686             : #elif defined AMIGA
     687             :                 if (i >= 0 && *name != '/' && (nl < 2 || name[1] != ':'))
     688             : #else
     689           0 :                 if (i >= 0 && *name != '/')
     690             : #endif
     691             :                 {
     692             :                         /*
     693             :                          * current file is somewhere else, and the provided
     694             :                          * file name is not absolute, so we must adjust the
     695             :                          * base for looking for the file; besides,
     696             :                          * found_files and found_files_loc are irrelevant
     697             :                          * for this search.
     698             :                          */
     699           0 :                         s = getmem(i + 2 + nl);
     700           0 :                         mmv(s, rfn, i);
     701             : #ifdef MSDOS
     702             :                         s[i] = '\\';
     703             : #else
     704           0 :                         s[i] = '/';
     705             : #endif
     706           0 :                         mmv(s + i + 1, name, nl);
     707           0 :                         s[i + 1 + nl] = 0;
     708           0 :                         ff = HTT_get(&found_files, s);
     709           0 :                 } else ff = HTT_get(&found_files, name);
     710             :         }
     711           0 :         if (!ff) {
     712           0 :                 struct found_file_sys *ffs = HTT_get(&found_files_sys, name);
     713             : 
     714           0 :                 if (ffs) {
     715           0 :                         ff = ffs->rff;
     716           0 :                         incdir = ffs->incdir;
     717             :                 }
     718             :         }
     719             :         /*
     720             :          * At that point: if the file was found in the cache, ff points to
     721             :          * the cached descriptive structure; its name is s if s is not 0,
     722             :          * name otherwise.
     723             :          */
     724           0 :         if (ff) goto found_file_cache;
     725             : 
     726             :         /*
     727             :          * This is the first time we find the file, or it was not protected.
     728             :          */
     729           0 :         protect_detect.ff = new_found_file();
     730           0 :         nffa = 1;
     731           0 :         if (localdir &&
     732             : #ifdef UCPP_MMAP
     733             :                 (f = fopen_mmap_file(s ? s : name))
     734             : #else
     735           0 :                 (f = fopen(s ? s : name, "r"))
     736             : #endif
     737             :                 ) {
     738           0 :                 lf = 1;
     739           0 :                 goto found_file;
     740             :         }
     741             :         /*
     742             :          * If s contains a name, that name is now irrelevant: it was a
     743             :          * filename for a search in the current directory, and the file
     744             :          * was not found.
     745             :          */
     746           0 :         if (s) {
     747           0 :                 freemem(s);
     748           0 :                 s = 0;
     749             :         }
     750           0 :         for (i = 0; (size_t)i < include_path_nb; i ++) {
     751           0 :                 size_t ni = strlen(include_path[i]);
     752             : 
     753           0 :                 s = getmem(ni + nl + 2);
     754           0 :                 mmv(s, include_path[i], ni);
     755             : #ifdef AMIGA
     756             :         /* contributed by Volker Barthelmann */
     757             :                 if (ni == 1 && *s == '.') {
     758             :                         *s = 0;
     759             :                         ni = 0;
     760             :                 }
     761             :                 if (ni > 0 && s[ni - 1] != ':' && s[ni - 1] != '/') {
     762             :                         s[ni] = '/';
     763             :                         mmv(s + ni + 1, name, nl + 1);
     764             :                 } else {
     765             :                         mmv(s + ni, name, nl + 1);
     766             :                 }
     767             : #else
     768           0 :                 s[ni] = '/';
     769           0 :                 mmv(s + ni + 1, name, nl + 1);
     770             : #endif
     771             : #ifdef MSDOS
     772             :                 /* on msdos systems, replace all / by \ */
     773             :                 {
     774             :                         char *c;
     775             : 
     776             :                         for (c = s; *c; c ++) if (*c == '/') *c = '\\';
     777             :                 }
     778             : #endif
     779           0 :                 incdir = i;
     780           0 :                 if ((ff = HTT_get(&found_files, s)) != 0) {
     781             :                         /*
     782             :                          * The file is known, but not as a system include
     783             :                          * file under the name provided.
     784             :                          */
     785           0 :                         struct found_file_sys *ffs = new_found_file_sys();
     786             : 
     787           0 :                         ffs->rff = ff;
     788           0 :                         ffs->incdir = incdir;
     789           0 :                         HTT_put(&found_files_sys, ffs, name);
     790           0 :                         freemem(s);
     791           0 :                         s = 0;
     792           0 :                         if (nffa) {
     793           0 :                                 del_found_file(protect_detect.ff);
     794           0 :                                 protect_detect.ff = 0;
     795           0 :                                 nffa = 0;
     796             :                         }
     797           0 :                         goto found_file_cache;
     798             :                 }
     799             : #ifdef UCPP_MMAP
     800             :                 f = fopen_mmap_file(s);
     801             : #else
     802           0 :                 f = fopen(s, "r");
     803             : #endif
     804           0 :                 if (f) goto found_file;
     805           0 :                 freemem(s);
     806           0 :                 s = 0;
     807             :         }
     808             : zero_out:
     809           0 :         if (s) freemem(s);
     810           0 :         if (nffa) {
     811           0 :                 del_found_file(protect_detect.ff);
     812           0 :                 protect_detect.ff = 0;
     813           0 :                 nffa = 0;
     814             :         }
     815           0 :         return 0;
     816             : 
     817             :         /*
     818             :          * This part is invoked when the file was found in the
     819             :          * cache.
     820             :          */
     821             : found_file_cache:
     822           0 :         if (ff->protect) {
     823           0 :                 if (get_macro(ff->protect)) {
     824             :                         /* file is protected, do not include it */
     825           0 :                         find_file_error = FF_PROTECT;
     826           0 :                         goto zero_out;
     827             :                 }
     828             :                 /* file is protected but the guardian macro is
     829             :                    not available; disable guardian detection. */
     830           0 :                 protect_detect.state = 0;
     831             :         }
     832           0 :         protect_detect.ff = ff;
     833             : #ifdef UCPP_MMAP
     834             :         f = fopen_mmap_file(HASH_ITEM_NAME(ff));
     835             : #else
     836           0 :         f = fopen(HASH_ITEM_NAME(ff), "r");
     837             : #endif
     838           0 :         if (!f) goto zero_out;
     839           0 :         find_file_error = FF_KNOWN;
     840           0 :         goto found_file_2;
     841             : 
     842             :         /*
     843             :          * This part is invoked when we found a new file, which was not
     844             :          * yet referenced. If lf == 1, then the file was found directly,
     845             :          * otherwise it was found in some system include directory.
     846             :          * A new found_file structure has been allocated and is in
     847             :          * protect_detect.ff
     848             :          */
     849             : found_file:
     850           0 :         if (f && ((emit_dependencies == 1 && lf && current_incdir == -1)
     851           0 :                 || emit_dependencies == 2)) {
     852           0 :                 fprintf(emit_output, " %s", s ? s : name);
     853             :         }
     854           0 :         nff = protect_detect.ff;
     855           0 :         nff->name = sdup(name);
     856             : #ifdef AUDIT
     857             :         if (
     858             : #endif
     859           0 :         HTT_put(&found_files, nff, s ? s : name)
     860             : #ifdef AUDIT
     861             :         ) ouch("filename collided with a wraith")
     862             : #endif
     863             :         ;
     864           0 :         if (!lf) {
     865           0 :                 struct found_file_sys *ffs = new_found_file_sys();
     866             : 
     867           0 :                 ffs->rff = nff;
     868           0 :                 ffs->incdir = incdir;
     869           0 :                 HTT_put(&found_files_sys, ffs, name);
     870             :         }
     871           0 :         if (s) freemem(s);
     872           0 :         s = 0;
     873           0 :         find_file_error = FF_UNKNOWN;
     874           0 :         ff = nff;
     875             : 
     876             : found_file_2:
     877           0 :         if (s) freemem(s);
     878           0 :         current_long_filename = HASH_ITEM_NAME(ff);
     879             : #ifdef NO_LIBC_BUF
     880             :         setbuf(f, 0);
     881             : #endif
     882           0 :         current_incdir = incdir;
     883           0 :         return f;
     884             : }
     885             : 
     886             : /*
     887             :  * Find the named file by looking through the end of the include path.
     888             :  * This is for #include_next directives.
     889             :  * #include_next <foo> and #include_next "foo" are considered identical,
     890             :  * for all practical purposes.
     891             :  */
     892           0 : static FILE *find_file_next(char *name)
     893             : {
     894             :         int i;
     895           0 :         size_t nl = strlen(name);
     896             :         FILE *f;
     897             :         struct found_file *ff;
     898             : 
     899           0 :         find_file_error = FF_ERROR;
     900           0 :         protect_detect.state = -1;
     901           0 :         protect_detect.macro = 0;
     902           0 :         for (i = current_incdir + 1; (size_t)i < include_path_nb; i ++) {
     903             :                 char *s;
     904           0 :                 size_t ni = strlen(include_path[i]);
     905             : 
     906           0 :                 s = getmem(ni + nl + 2);
     907           0 :                 mmv(s, include_path[i], ni);
     908           0 :                 s[ni] = '/';
     909           0 :                 mmv(s + ni + 1, name, nl + 1);
     910             : #ifdef MSDOS
     911             :                 /* on msdos systems, replace all / by \ */
     912             :                 {
     913             :                         char *c;
     914             : 
     915             :                         for (c = s; *c; c ++) if (*c == '/') *c = '\\';
     916             :                 }
     917             : #endif
     918           0 :                 ff = HTT_get(&found_files, s);
     919           0 :                 if (ff) {
     920             :                         /* file was found in the cache */
     921           0 :                         if (ff->protect) {
     922           0 :                                 if (get_macro(ff->protect)) {
     923           0 :                                         find_file_error = FF_PROTECT;
     924           0 :                                         freemem(s);
     925           0 :                                         return 0;
     926             :                                 }
     927             :                                 /* file is protected but the guardian macro is
     928             :                                    not available; disable guardian detection. */
     929           0 :                                 protect_detect.state = 0;
     930             :                         }
     931           0 :                         protect_detect.ff = ff;
     932             : #ifdef UCPP_MMAP
     933             :                         f = fopen_mmap_file(HASH_ITEM_NAME(ff));
     934             : #else
     935           0 :                         f = fopen(HASH_ITEM_NAME(ff), "r");
     936             : #endif
     937           0 :                         if (!f) {
     938             :                                 /* file is referenced but yet unavailable. */
     939           0 :                                 freemem(s);
     940           0 :                                 return 0;
     941             :                         }
     942           0 :                         find_file_error = FF_KNOWN;
     943           0 :                         freemem(s);
     944           0 :                         s = HASH_ITEM_NAME(ff);
     945             :                 } else {
     946             : #ifdef UCPP_MMAP
     947             :                         f = fopen_mmap_file(s);
     948             : #else
     949           0 :                         f = fopen(s, "r");
     950             : #endif
     951           0 :                         if (f) {
     952           0 :                                 if (emit_dependencies == 2) {
     953           0 :                                         fprintf(emit_output, " %s", s);
     954             :                                 }
     955           0 :                                 ff = protect_detect.ff = new_found_file();
     956           0 :                                 ff->name = sdup(s);
     957             : #ifdef AUDIT
     958             :                                 if (
     959             : #endif
     960           0 :                                 HTT_put(&found_files, ff, s)
     961             : #ifdef AUDIT
     962             :                                 ) ouch("filename collided with a wraith")
     963             : #endif
     964             :                                 ;
     965           0 :                                 find_file_error = FF_UNKNOWN;
     966           0 :                                 freemem(s);
     967           0 :                                 s = HASH_ITEM_NAME(ff);
     968             :                         }
     969             :                 }
     970           0 :                 if (f) {
     971           0 :                         current_long_filename = s;
     972           0 :                         current_incdir = i;
     973           0 :                         return f;
     974             :                 }
     975           0 :                 freemem(s);
     976             :         }
     977           0 :         return 0;
     978             : }
     979             : 
     980             : /*
     981             :  * The #if directive. This function parse the expression, performs macro
     982             :  * expansion (and handles the "defined" operator), and call eval_expr.
     983             :  * return value: 1 if the expression is true, 0 if it is false, -1 on error.
     984             :  */
     985           0 : static int handle_if(struct lexer_state *ls)
     986             : {
     987             :         struct token_fifo tf, tf1, tf2, tf3, *save_tf;
     988           0 :         long l = ls->line;
     989             :         unsigned long z;
     990           0 :         int ret = 0, ltww = 1;
     991             : 
     992             :         /* first, get the whole line */
     993           0 :         tf.art = tf.nt = 0;
     994           0 :         while (!next_token(ls) && ls->ctok->type != NEWLINE) {
     995             :                 struct token t;
     996             : 
     997           0 :                 if (ltww && ttMWS(ls->ctok->type)) continue;
     998           0 :                 ltww = ttMWS(ls->ctok->type);
     999           0 :                 t.type = ls->ctok->type;
    1000           0 :                 t.line = l;
    1001           0 :                 if (S_TOKEN(ls->ctok->type)) {
    1002           0 :                         t.name = sdup(ls->ctok->name);
    1003           0 :                         throw_away(ls->gf, t.name);
    1004             :                 }
    1005           0 :                 aol(tf.t, tf.nt, t, TOKEN_LIST_MEMG);
    1006             :         }
    1007           0 :         if (ltww && tf.nt) if ((-- tf.nt) == 0) freemem(tf.t);
    1008           0 :         if (tf.nt == 0) {
    1009           0 :                 error(l, "void condition for a #if/#elif");
    1010           0 :                 return -1;
    1011             :         }
    1012             :         /* handle the "defined" operator */
    1013           0 :         tf1.art = tf1.nt = 0;
    1014           0 :         while (tf.art < tf.nt) {
    1015             :                 struct token *ct, rt;
    1016             :                 struct macro *m;
    1017             :                 size_t nidx, eidx;
    1018             : 
    1019           0 :                 ct = tf.t + (tf.art ++);
    1020           0 :                 if (ct->type == NAME && !strcmp(ct->name, "defined")) {
    1021           0 :                         if (tf.art >= tf.nt) goto store_token;
    1022           0 :                         nidx = tf.art;
    1023           0 :                         if (ttMWS(tf.t[nidx].type))
    1024           0 :                                 if (++ nidx >= tf.nt) goto store_token;
    1025           0 :                         if (tf.t[nidx].type == NAME) {
    1026           0 :                                 eidx = nidx;
    1027           0 :                                 goto check_macro;
    1028             :                         }
    1029           0 :                         if (tf.t[nidx].type != LPAR) goto store_token;
    1030           0 :                         if (++ nidx >= tf.nt) goto store_token;
    1031           0 :                         if (ttMWS(tf.t[nidx].type))
    1032           0 :                                 if (++ nidx >= tf.nt) goto store_token;
    1033           0 :                         if (tf.t[nidx].type != NAME) goto store_token;
    1034           0 :                         eidx = nidx + 1;
    1035           0 :                         if (eidx >= tf.nt) goto store_token;
    1036           0 :                         if (ttMWS(tf.t[eidx].type))
    1037           0 :                                 if (++ eidx >= tf.nt) goto store_token;
    1038           0 :                         if (tf.t[eidx].type != RPAR) goto store_token;
    1039           0 :                         goto check_macro;
    1040             :                 }
    1041             :         store_token:
    1042           0 :                 aol(tf1.t, tf1.nt, *ct, TOKEN_LIST_MEMG);
    1043           0 :                 continue;
    1044             : 
    1045             :         check_macro:
    1046           0 :                 m = get_macro(tf.t[nidx].name);
    1047           0 :                 rt.type = NUMBER;
    1048           0 :                 rt.name = m ? "1L" : "0L";
    1049           0 :                 aol(tf1.t, tf1.nt, rt, TOKEN_LIST_MEMG);
    1050           0 :                 tf.art = eidx + 1;
    1051             :         }
    1052           0 :         freemem(tf.t);
    1053           0 :         if (tf1.nt == 0) {
    1054           0 :                 error(l, "void condition (after expansion) for a #if/#elif");
    1055           0 :                 return -1;
    1056             :         }
    1057             : 
    1058             :         /* perform all macro substitutions */
    1059           0 :         tf2.art = tf2.nt = 0;
    1060           0 :         save_tf = ls->output_fifo;
    1061           0 :         ls->output_fifo = &tf2;
    1062           0 :         while (tf1.art < tf1.nt) {
    1063             :                 struct token *ct;
    1064             : 
    1065           0 :                 ct = tf1.t + (tf1.art ++);
    1066           0 :                 if (ct->type == NAME) {
    1067           0 :                         struct macro *m = get_macro(ct->name);
    1068             : 
    1069           0 :                         if (m) {
    1070           0 :                                 if (substitute_macro(ls, m, &tf1, 0,
    1071             : #ifdef NO_PRAGMA_IN_DIRECTIVE
    1072             :                                         1,
    1073             : #else
    1074             :                                         0,
    1075             : #endif
    1076             :                                         ct->line)) {
    1077           0 :                                         ls->output_fifo = save_tf;
    1078           0 :                                         goto error1;
    1079             :                                 }
    1080           0 :                                 continue;
    1081             :                         }
    1082           0 :                 } else if ((ct->type == SHARP || ct->type == DIG_SHARP)
    1083           0 :                         && (ls->flags & HANDLE_ASSERTIONS)) {
    1084             :                         /* we have an assertion; parse it */
    1085           0 :                         int nnp, ltww = 1;
    1086           0 :                         size_t i = tf1.art;
    1087             :                         struct token_fifo atl;
    1088             :                         char *aname;
    1089             :                         struct assert *a;
    1090           0 :                         int av = 0;
    1091             :                         struct token rt;
    1092             : 
    1093           0 :                         atl.art = atl.nt = 0;
    1094           0 :                         while (i < tf1.nt && ttMWS(tf1.t[i].type)) i ++;
    1095           0 :                         if (i >= tf1.nt) goto assert_error;
    1096           0 :                         if (tf1.t[i].type != NAME) goto assert_error;
    1097           0 :                         aname = tf1.t[i ++].name;
    1098           0 :                         while (i < tf1.nt && ttMWS(tf1.t[i].type)) i ++;
    1099           0 :                         if (i >= tf1.nt) goto assert_generic;
    1100           0 :                         if (tf1.t[i].type != LPAR) goto assert_generic;
    1101           0 :                         i ++;
    1102           0 :                         for (nnp = 1; nnp && i < tf1.nt; i ++) {
    1103           0 :                                 if (ltww && ttMWS(tf1.t[i].type)) continue;
    1104           0 :                                 if (tf1.t[i].type == LPAR) nnp ++;
    1105           0 :                                 else if (tf1.t[i].type == RPAR
    1106           0 :                                         && (-- nnp) == 0) {
    1107           0 :                                         tf1.art = i + 1;
    1108           0 :                                         break;
    1109             :                                 }
    1110           0 :                                 ltww = ttMWS(tf1.t[i].type);
    1111           0 :                                 aol(atl.t, atl.nt, tf1.t[i], TOKEN_LIST_MEMG);
    1112             :                         }
    1113           0 :                         if (nnp) goto assert_error;
    1114           0 :                         if (ltww && atl.nt && (-- atl.nt) == 0) freemem(atl.t);
    1115           0 :                         if (atl.nt == 0) goto assert_error;
    1116             : 
    1117             :                         /* the assertion is in aname and atl; check it */
    1118           0 :                         a = get_assertion(aname);
    1119           0 :                         if (a) for (i = 0; i < a->nbval; i ++)
    1120           0 :                                 if (!cmp_token_list(&atl, a->val + i)) {
    1121           0 :                                         av = 1;
    1122           0 :                                         break;
    1123             :                                 }
    1124           0 :                         rt.type = NUMBER;
    1125           0 :                         rt.name = av ? "1" : "0";
    1126           0 :                         aol(tf2.t, tf2.nt, rt, TOKEN_LIST_MEMG);
    1127           0 :                         if (atl.nt) freemem(atl.t);
    1128           0 :                         continue;
    1129             : 
    1130             :                 assert_generic:
    1131           0 :                         tf1.art = i;
    1132           0 :                         rt.type = NUMBER;
    1133           0 :                         rt.name = get_assertion(aname) ? "1" : "0";
    1134           0 :                         aol(tf2.t, tf2.nt, rt, TOKEN_LIST_MEMG);
    1135           0 :                         continue;
    1136             : 
    1137             :                 assert_error:
    1138           0 :                         error(l, "syntax error for assertion in #if");
    1139           0 :                         ls->output_fifo = save_tf;
    1140             :                         goto error1;
    1141             :                 }
    1142           0 :                 aol(tf2.t, tf2.nt, *ct, TOKEN_LIST_MEMG);
    1143             :         }
    1144           0 :         ls->output_fifo = save_tf;
    1145           0 :         freemem(tf1.t);
    1146           0 :         if (tf2.nt == 0) {
    1147           0 :                 error(l, "void condition (after expansion) for a #if/#elif");
    1148           0 :                 return -1;
    1149             :         }
    1150             : 
    1151             :         /*
    1152             :          * suppress whitespace and replace rogue identifiers by 0
    1153             :          */
    1154           0 :         tf3.art = tf3.nt = 0;
    1155           0 :         while (tf2.art < tf2.nt) {
    1156           0 :                 struct token *ct = tf2.t + (tf2.art ++);
    1157             : 
    1158           0 :                 if (ttMWS(ct->type)) continue;
    1159           0 :                 if (ct->type == NAME) {
    1160             :                         /*
    1161             :                          * a rogue identifier; we replace it with "0".
    1162             :                          */
    1163             :                         struct token rt;
    1164             : 
    1165           0 :                         rt.type = NUMBER;
    1166           0 :                         rt.name = "0";
    1167           0 :                         aol(tf3.t, tf3.nt, rt, TOKEN_LIST_MEMG);
    1168           0 :                         continue;
    1169             :                 }
    1170           0 :                 aol(tf3.t, tf3.nt, *ct, TOKEN_LIST_MEMG);
    1171             :         }
    1172           0 :         freemem(tf2.t);
    1173             : 
    1174           0 :         if (tf3.nt == 0) {
    1175           0 :                 error(l, "void condition (after expansion) for a #if/#elif");
    1176           0 :                 return -1;
    1177             :         }
    1178           0 :         eval_line = l;
    1179           0 :         z = eval_expr(&tf3, &ret, (ls->flags & WARN_STANDARD) != 0);
    1180           0 :         freemem(tf3.t);
    1181           0 :         if (ret) return -1;
    1182           0 :         return (z != 0);
    1183             : 
    1184             : error1:
    1185           0 :         if (tf1.nt) freemem(tf1.t);
    1186           0 :         if (tf2.nt) freemem(tf2.t);
    1187           0 :         return -1;
    1188             : }
    1189             : 
    1190             : /*
    1191             :  * A #include was found; parse the end of line, replace macros if
    1192             :  * necessary.
    1193             :  *
    1194             :  * If nex is set to non-zero, the directive is considered as a #include_next
    1195             :  * (extension to C99, mimicked from GNU)
    1196             :  */
    1197           0 : static int handle_include(struct lexer_state *ls, unsigned long flags, int nex)
    1198             : {
    1199           0 :         int c, string_fname = 0;
    1200             :         char *fname;
    1201             :         unsigned char *fname2;
    1202           0 :         size_t fname_ptr = 0;
    1203           0 :         long l = ls->line;
    1204             :         int x, y;
    1205             :         FILE *f;
    1206             :         struct token_fifo tf, tf2, *save_tf;
    1207             :         size_t nl;
    1208             :         int tgd;
    1209             :         struct lexer_state alt_ls;
    1210             : 
    1211             : #define left_angle(t)   ((t) == LT || (t) == LEQ || (t) == LSH \
    1212             :                         || (t) == ASLSH || (t) == DIG_LBRK || (t) == LBRA)
    1213             : #define right_angle(t)  ((t) == GT || (t) == RSH || (t) == ARROW \
    1214             :                         || (t) == DIG_RBRK || (t) == DIG_RBRA)
    1215             : 
    1216           0 :         while ((c = grap_char(ls)) >= 0 && c != '\n') {
    1217           0 :                 if (space_char(c)) {
    1218           0 :                         discard_char(ls);
    1219           0 :                         continue;
    1220             :                 }
    1221           0 :                 if (c == '<') {
    1222           0 :                         discard_char(ls);
    1223           0 :                         while ((c = grap_char(ls)) >= 0) {
    1224           0 :                                 discard_char(ls);
    1225           0 :                                 if (c == '\n') goto include_last_chance;
    1226           0 :                                 if (c == '>') break;
    1227           0 :                                 aol(fname, fname_ptr, (char)c, FNAME_MEMG);
    1228             :                         }
    1229           0 :                         aol(fname, fname_ptr, (char)0, FNAME_MEMG);
    1230           0 :                         string_fname = 0;
    1231           0 :                         goto do_include;
    1232           0 :                 } else if (c == '"') {
    1233           0 :                         discard_char(ls);
    1234           0 :                         while ((c = grap_char(ls)) >= 0) {
    1235           0 :                                 discard_char(ls);
    1236           0 :                                 if (c == '\n') {
    1237             :                                 /* macro replacements won't save that one */
    1238           0 :                                         if (fname_ptr) freemem(fname);
    1239           0 :                                         goto include_error;
    1240             :                                 }
    1241           0 :                                 if (c == '"') break;
    1242           0 :                                 aol(fname, fname_ptr, (char)c, FNAME_MEMG);
    1243             :                         }
    1244           0 :                         aol(fname, fname_ptr, (char)0, FNAME_MEMG);
    1245           0 :                         string_fname = 1;
    1246           0 :                         goto do_include;
    1247             :                 }
    1248           0 :                 goto include_macro;
    1249             :         }
    1250             : 
    1251             : include_last_chance:
    1252             :         /*
    1253             :          * We found a '<' but not the trailing '>'; so we tokenize the
    1254             :          * line, and try to act upon it. The standard lets us free in that
    1255             :          * matter, and no sane programmer would use such a construct, but
    1256             :          * it is no reason not to support it.
    1257             :          */
    1258           0 :         if (fname_ptr == 0) goto include_error;
    1259           0 :         fname2 = getmem(fname_ptr + 1);
    1260           0 :         mmv(fname2 + 1, fname, fname_ptr);
    1261           0 :         fname2[0] = '<';
    1262             :         /*
    1263             :          * We merely copy the lexer_state structure; this should be ok,
    1264             :          * since we do want to share the memory structure (garbage_fifo),
    1265             :          * and do not touch any other context-full thing.
    1266             :          */
    1267           0 :         alt_ls = *ls;
    1268           0 :         alt_ls.input = 0;
    1269           0 :         alt_ls.input_string = fname2;
    1270           0 :         alt_ls.pbuf = 0;
    1271           0 :         alt_ls.ebuf = fname_ptr + 1;
    1272           0 :         tf.art = tf.nt = 0;
    1273           0 :         while (!next_token(&alt_ls)) {
    1274           0 :                 if (!ttMWS(alt_ls.ctok->type)) {
    1275             :                         struct token t;
    1276             : 
    1277           0 :                         t.type = alt_ls.ctok->type;
    1278           0 :                         t.line = l;
    1279           0 :                         if (S_TOKEN(alt_ls.ctok->type)) {
    1280           0 :                                 t.name = sdup(alt_ls.ctok->name);
    1281           0 :                                 throw_away(alt_ls.gf, t.name);
    1282             :                         }
    1283           0 :                         aol(tf.t, tf.nt, t, TOKEN_LIST_MEMG);
    1284             :                 }
    1285             :         }
    1286           0 :         freemem(fname2);
    1287           0 :         if (alt_ls.pbuf < alt_ls.ebuf) goto include_error;
    1288             :                 /* tokenizing failed */
    1289           0 :         goto include_macro2;
    1290             :         
    1291             : include_error:
    1292           0 :         error(l, "invalid '#include'");
    1293           0 :         return 1;
    1294             : 
    1295             : include_macro:
    1296           0 :         tf.art = tf.nt = 0;
    1297           0 :         while (!next_token(ls) && ls->ctok->type != NEWLINE) {
    1298           0 :                 if (!ttMWS(ls->ctok->type)) {
    1299             :                         struct token t;
    1300             : 
    1301           0 :                         t.type = ls->ctok->type;
    1302           0 :                         t.line = l;
    1303           0 :                         if (S_TOKEN(ls->ctok->type)) {
    1304           0 :                                 t.name = sdup(ls->ctok->name);
    1305           0 :                                 throw_away(ls->gf, t.name);
    1306             :                         }
    1307           0 :                         aol(tf.t, tf.nt, t, TOKEN_LIST_MEMG);
    1308             :                 }
    1309             :         }
    1310             : include_macro2:
    1311           0 :         tf2.art = tf2.nt = 0;
    1312           0 :         save_tf = ls->output_fifo;
    1313           0 :         ls->output_fifo = &tf2;
    1314           0 :         while (tf.art < tf.nt) {
    1315             :                 struct token *ct;
    1316             : 
    1317           0 :                 ct = tf.t + (tf.art ++);
    1318           0 :                 if (ct->type == NAME) {
    1319           0 :                         struct macro *m = get_macro(ct->name);
    1320           0 :                         if (m) {
    1321           0 :                                 if (substitute_macro(ls, m, &tf, 0,
    1322             : #ifdef NO_PRAGMA_IN_DIRECTIVE
    1323             :                                         1,
    1324             : #else
    1325             :                                         0,
    1326             : #endif
    1327             :                                         ct->line)) {
    1328           0 :                                         ls->output_fifo = save_tf;
    1329           0 :                                         return -1;
    1330             :                                 }
    1331           0 :                                 continue;
    1332             :                         }
    1333             :                 }
    1334           0 :                 aol(tf2.t, tf2.nt, *ct, TOKEN_LIST_MEMG);
    1335             :         }
    1336           0 :         freemem(tf.t);
    1337           0 :         ls->output_fifo = save_tf;
    1338           0 :         for (x = 0; (size_t)x < tf2.nt && ttWHI(tf2.t[x].type); x ++);
    1339           0 :         for (y = tf2.nt - 1; y >= 0 && ttWHI(tf2.t[y].type); y --);
    1340           0 :         if ((size_t)x >= tf2.nt) goto include_macro_err;
    1341           0 :         if (tf2.t[x].type == STRING) {
    1342           0 :                 if (y != x) goto include_macro_err;
    1343           0 :                 if (tf2.t[x].name[0] == 'L') {
    1344           0 :                         if (ls->flags & WARN_STANDARD)
    1345           0 :                                 warning(l, "wide string for #include");
    1346           0 :                         fname = sdup(tf2.t[x].name);
    1347           0 :                         nl = strlen(fname);
    1348           0 :                         *(fname + nl - 1) = 0;
    1349           0 :                         mmvwo(fname, fname + 2, nl - 2);
    1350             :                 } else {
    1351           0 :                         fname = sdup(tf2.t[x].name);
    1352           0 :                         nl = strlen(fname);
    1353           0 :                         *(fname + nl - 1) = 0;
    1354           0 :                         mmvwo(fname, fname + 1, nl - 1);
    1355             :                 }
    1356           0 :                 string_fname = 1;
    1357           0 :         } else if (left_angle(tf2.t[x].type) && right_angle(tf2.t[y].type)) {
    1358             :                 int i, j;
    1359             : 
    1360           0 :                 if (ls->flags & WARN_ANNOYING) warning(l, "reconstruction "
    1361             :                         "of <foo> in #include");
    1362           0 :                 for (j = 0, i = x; i <= y; i ++) if (!ttWHI(tf2.t[i].type))
    1363           0 :                         j += strlen(tname(tf2.t[i]));
    1364           0 :                 fname = getmem(j + 1);
    1365           0 :                 for (j = 0, i = x; i <= y; i ++) {
    1366           0 :                         if (ttWHI(tf2.t[i].type)) continue;
    1367           0 :                         strcpy(fname + j, tname(tf2.t[i]));
    1368           0 :                         j += strlen(tname(tf2.t[i]));
    1369             :                 }
    1370           0 :                 *(fname + j - 1) = 0;
    1371           0 :                 mmvwo(fname, fname + 1, j);
    1372           0 :                 string_fname = 0;
    1373             :         } else goto include_macro_err;
    1374           0 :         freemem(tf2.t);
    1375           0 :         goto do_include_next;
    1376             : 
    1377             : include_macro_err:
    1378           0 :         error(l, "macro expansion did not produce a valid filename "
    1379             :                 "for #include");
    1380           0 :         if (tf2.nt) freemem(tf2.t);
    1381           0 :         return 1;
    1382             : 
    1383             : do_include:
    1384           0 :         tgd = 1;
    1385           0 :         while (!next_token(ls)) {
    1386           0 :                 if (tgd && !ttWHI(ls->ctok->type)
    1387           0 :                         && (ls->flags & WARN_STANDARD)) {
    1388           0 :                         warning(l, "trailing garbage in #include");
    1389           0 :                         tgd = 0;
    1390             :                 }
    1391           0 :                 if (ls->ctok->type == NEWLINE) break;
    1392             :         }
    1393             : 
    1394             :         /* the increment of ls->line is intended so that the line
    1395             :            numbering is reported correctly in report_context() even if
    1396             :            the #include is at the end of the file with no trailing newline */
    1397           0 :         if (ls->ctok->type != NEWLINE) ls->line ++;
    1398             : do_include_next:
    1399           0 :         if (!(ls->flags & LEXER) && (ls->flags & KEEP_OUTPUT))
    1400           0 :                 put_char(ls, '\n');
    1401           0 :         push_file_context(ls);
    1402           0 :         reinit_lexer_state(ls, 1);
    1403             : #ifdef MSDOS
    1404             :         /* on msdos systems, replace all / by \ */
    1405             :         {
    1406             :                 char *d;
    1407             : 
    1408             :                 for (d = fname; *d; d ++) if (*d == '/') *d = '\\';
    1409             :         }
    1410             : #endif
    1411           0 :         f = nex ? find_file_next(fname) : find_file(fname, string_fname);
    1412           0 :         if (!f) {
    1413           0 :                 current_filename = 0;
    1414           0 :                 pop_file_context(ls);
    1415           0 :                 if (find_file_error == FF_ERROR) {
    1416           0 :                         error(l, "file '%s' not found", fname);
    1417           0 :                         freemem(fname);
    1418           0 :                         return 1;
    1419             :                 }
    1420             :                 /* file was found, but it is useless to include it again */
    1421           0 :                 freemem(fname);
    1422           0 :                 return 0;
    1423             :         }
    1424             : #ifdef UCPP_MMAP
    1425             :         set_input_file(ls, f);
    1426             : #else
    1427           0 :         ls->input = f;
    1428             : #endif
    1429           0 :         current_filename = fname;
    1430           0 :         enter_file(ls, flags);
    1431           0 :         return 0;
    1432             : 
    1433             : #undef left_angle
    1434             : #undef right_angle
    1435             : }
    1436             : 
    1437             : /*
    1438             :  * for #line directives
    1439             :  */
    1440           0 : static int handle_line(struct lexer_state *ls, unsigned long flags)
    1441             : {
    1442             :         char *fname;
    1443           0 :         long l = ls->line;
    1444             :         struct token_fifo tf, tf2, *save_tf;
    1445             :         size_t nl, j;
    1446             :         unsigned long z;
    1447             : 
    1448           0 :         tf.art = tf.nt = 0;
    1449           0 :         while (!next_token(ls) && ls->ctok->type != NEWLINE) {
    1450           0 :                 if (!ttMWS(ls->ctok->type)) {
    1451             :                         struct token t;
    1452             : 
    1453           0 :                         t.type = ls->ctok->type;
    1454           0 :                         t.line = l;
    1455           0 :                         if (S_TOKEN(ls->ctok->type)) {
    1456           0 :                                 t.name = sdup(ls->ctok->name);
    1457           0 :                                 throw_away(ls->gf, t.name);
    1458             :                         }
    1459           0 :                         aol(tf.t, tf.nt, t, TOKEN_LIST_MEMG);
    1460             :                 }
    1461             :         }
    1462           0 :         tf2.art = tf2.nt = 0;
    1463           0 :         save_tf = ls->output_fifo;
    1464           0 :         ls->output_fifo = &tf2;
    1465           0 :         while (tf.art < tf.nt) {
    1466             :                 struct token *ct;
    1467             : 
    1468           0 :                 ct = tf.t + (tf.art ++);
    1469           0 :                 if (ct->type == NAME) {
    1470           0 :                         struct macro *m = get_macro(ct->name);
    1471           0 :                         if (m) {
    1472           0 :                                 if (substitute_macro(ls, m, &tf, 0,
    1473             : #ifdef NO_PRAGMA_IN_DIRECTIVE
    1474             :                                         1,
    1475             : #else
    1476             :                                         0,
    1477             : #endif
    1478             :                                         ct->line)) {
    1479           0 :                                         ls->output_fifo = save_tf;
    1480           0 :                                         return -1;
    1481             :                                 }
    1482           0 :                                 continue;
    1483             :                         }
    1484             :                 }
    1485           0 :                 aol(tf2.t, tf2.nt, *ct, TOKEN_LIST_MEMG);
    1486             :         }
    1487           0 :         freemem(tf.t);
    1488           0 :         for (tf2.art = 0; tf2.art < tf2.nt && ttWHI(tf2.t[tf2.art].type);
    1489           0 :                 tf2.art ++);
    1490           0 :         ls->output_fifo = save_tf;
    1491           0 :         if (tf2.art == tf2.nt || (tf2.t[tf2.art].type != NUMBER
    1492           0 :                 && tf2.t[tf2.art].type != CHAR)) {
    1493           0 :                 error(l, "not a valid number for #line");
    1494           0 :                 goto line_macro_err;
    1495             :         }
    1496           0 :         for (j = 0; tf2.t[tf2.art].name[j]; j ++)
    1497           0 :                 if (tf2.t[tf2.art].name[j] < '0'
    1498           0 :                         || tf2.t[tf2.art].name[j] > '9')
    1499           0 :                         if (ls->flags & WARN_STANDARD)
    1500           0 :                                 warning(l, "non-standard line number in #line");
    1501           0 :         if (catch(eval_exception)) goto line_macro_err;
    1502           0 :         z = strtoconst(tf2.t[tf2.art].name);
    1503           0 :         if (j > 10 || z > 2147483647U) {
    1504           0 :                 error(l, "out-of-bound line number for #line");
    1505           0 :                 goto line_macro_err;
    1506             :         }
    1507           0 :         ls->oline = ls->line = z;
    1508           0 :         if ((++ tf2.art) < tf2.nt) {
    1509             :                 size_t i;
    1510             : 
    1511           0 :                 for (i = tf2.art; i < tf2.nt && ttMWS(tf2.t[i].type); i ++);
    1512           0 :                 if (i < tf2.nt) {
    1513           0 :                         if (tf2.t[i].type != STRING) {
    1514           0 :                                 error(l, "not a valid filename for #line");
    1515           0 :                                 goto line_macro_err;
    1516             :                         }
    1517           0 :                         if (tf2.t[i].name[0] == 'L') {
    1518           0 :                                 if (ls->flags & WARN_STANDARD) {
    1519           0 :                                         warning(l, "wide string for #line");
    1520             :                                 }
    1521           0 :                                 fname = sdup(tf2.t[i].name);
    1522           0 :                                 nl = strlen(fname);
    1523           0 :                                 *(fname + nl - 1) = 0;
    1524           0 :                                 mmvwo(fname, fname + 2, nl - 2);
    1525             :                         } else {
    1526           0 :                                 fname = sdup(tf2.t[i].name);
    1527           0 :                                 nl = strlen(fname);
    1528           0 :                                 *(fname + nl - 1) = 0;
    1529           0 :                                 mmvwo(fname, fname + 1, nl - 1);
    1530             :                         }
    1531           0 :                         if (current_filename) freemem(current_filename);
    1532           0 :                         current_filename = fname;
    1533             :                 }
    1534           0 :                 for (i ++; i < tf2.nt && ttMWS(tf2.t[i].type); i ++);
    1535           0 :                 if (i < tf2.nt && (ls->flags & WARN_STANDARD)) {
    1536           0 :                         warning(l, "trailing garbage in #line");
    1537             :                 }
    1538             :         }
    1539           0 :         freemem(tf2.t);
    1540           0 :         enter_file(ls, flags);
    1541           0 :         return 0;
    1542             : 
    1543             : line_macro_err:
    1544           0 :         if (tf2.nt) freemem(tf2.t);
    1545           0 :         return 1;
    1546             : }
    1547             : 
    1548             : /*
    1549             :  * a #error directive: we emit the message without any modification
    1550             :  * (except the usual backslash+newline and trigraphs)
    1551             :  */
    1552           0 : static void handle_error(struct lexer_state *ls)
    1553             : {
    1554             :         int c;
    1555           0 :         size_t p = 0, lp = 128;
    1556           0 :         long l = ls->line;
    1557           0 :         unsigned char *buf = getmem(lp);
    1558             : 
    1559           0 :         while ((c = grap_char(ls)) >= 0 && c != '\n') {
    1560           0 :                 discard_char(ls);
    1561           0 :                 wan(buf, p, (unsigned char)c, lp);
    1562             :         }
    1563           0 :         wan(buf, p, 0, lp);
    1564           0 :         error(l, "#error%s", buf);
    1565           0 :         freemem(buf);
    1566           0 : }
    1567             : 
    1568             : /*
    1569             :  * convert digraph tokens to their standard equivalent.
    1570             :  */
    1571           0 : static int undig(int type)
    1572             : {
    1573             :         static int ud[6] = { LBRK, RBRK, LBRA, RBRA, SHARP, DSHARP };
    1574             : 
    1575           0 :         return ud[type - DIG_LBRK];
    1576             : }
    1577             : 
    1578             : #ifdef PRAGMA_TOKENIZE
    1579             : /*
    1580             :  * Make a compressed representation of a token list; the contents of
    1581             :  * the token_fifo are freed. Values equal to 0 are replaced by
    1582             :  * PRAGMA_TOKEN_END (by default, (unsigned char)'\n') and the compressed
    1583             :  * string is padded by a 0 (so that it may be * handled like a string).
    1584             :  * Digraph tokens are replaced by their non-digraph equivalents.
    1585             :  */
    1586           0 : struct comp_token_fifo compress_token_list(struct token_fifo *tf)
    1587             : {
    1588             :         struct comp_token_fifo ct;
    1589             :         size_t l;
    1590             : 
    1591           0 :         for (l = 0, tf->art = 0; tf->art < tf->nt; tf->art ++) {
    1592           0 :                 l ++;
    1593           0 :                 if (S_TOKEN(tf->t[tf->art].type))
    1594           0 :                         l += strlen(tf->t[tf->art].name) + 1;
    1595             :         }
    1596           0 :         ct.t = getmem((ct.length = l) + 1);
    1597           0 :         for (l = 0, tf->art = 0; tf->art < tf->nt; tf->art ++) {
    1598           0 :                 int tt = tf->t[tf->art].type;
    1599             : 
    1600           0 :                 if (tt == 0) tt = PRAGMA_TOKEN_END;
    1601           0 :                 if (tt > DIGRAPH_TOKENS && tt < DIGRAPH_TOKENS_END)
    1602           0 :                         tt = undig(tt);
    1603           0 :                 ct.t[l ++] = tt;
    1604           0 :                 if (S_TOKEN(tt)) {
    1605           0 :                         char *tn = tf->t[tf->art].name;
    1606           0 :                         size_t sl = strlen(tn);
    1607             : 
    1608           0 :                         mmv(ct.t + l, tn, sl);
    1609           0 :                         l += sl;
    1610           0 :                         ct.t[l ++] = PRAGMA_TOKEN_END;
    1611           0 :                         freemem(tn);
    1612             :                 }
    1613             :         }
    1614           0 :         ct.t[l] = 0;
    1615           0 :         if (tf->nt) freemem(tf->t);
    1616           0 :         ct.rp = 0;
    1617           0 :         return ct;
    1618             : }
    1619             : #endif
    1620             : 
    1621             : /*
    1622             :  * A #pragma directive: we make a PRAGMA token containing the rest of
    1623             :  * the line.
    1624             :  *
    1625             :  * We strongly hope that we are called only in LEXER mode.
    1626             :  */
    1627           0 : static void handle_pragma(struct lexer_state *ls)
    1628             : {
    1629             :         unsigned char *buf;
    1630             :         struct token t;
    1631           0 :         long l = ls->line;
    1632             : 
    1633             : #ifdef PRAGMA_TOKENIZE
    1634             :         struct token_fifo tf;
    1635             : 
    1636           0 :         tf.art = tf.nt = 0;
    1637           0 :         while (!next_token(ls) && ls->ctok->type != NEWLINE)
    1638           0 :                 if (!ttMWS(ls->ctok->type)) break;
    1639           0 :         if (ls->ctok->type != NEWLINE) {
    1640             :                 do {
    1641             :                         struct token t;
    1642             : 
    1643           0 :                         t.type = ls->ctok->type;
    1644           0 :                         if (ttMWS(t.type)) continue;
    1645           0 :                         if (S_TOKEN(t.type)) t.name = sdup(ls->ctok->name);
    1646           0 :                         aol(tf.t, tf.nt, t, TOKEN_LIST_MEMG);
    1647           0 :                 } while (!next_token(ls) && ls->ctok->type != NEWLINE);
    1648             :         }
    1649           0 :         if (tf.nt == 0) {
    1650             :                 /* void pragma are silently ignored */
    1651           0 :                 return;
    1652             :         }
    1653           0 :         buf = (compress_token_list(&tf)).t;
    1654             : #else
    1655             :         int c, x = 1, y = 32;
    1656             : 
    1657             :         while ((c = grap_char(ls)) >= 0 && c != '\n') {
    1658             :                 discard_char(ls);
    1659             :                 if (!space_char(c)) break;
    1660             :         }
    1661             :         /* void #pragma are ignored */
    1662             :         if (c == '\n') return;
    1663             :         buf = getmem(y);
    1664             :         buf[0] = c;
    1665             :         while ((c = grap_char(ls)) >= 0 && c != '\n') {
    1666             :                 discard_char(ls);
    1667             :                 wan(buf, x, c, y);
    1668             :         }
    1669             :         for (x --; x >= 0 && space_char(buf[x]); x --);
    1670             :         x ++;
    1671             :         wan(buf, x, 0, y);
    1672             : #endif
    1673           0 :         t.type = PRAGMA;
    1674           0 :         t.line = l;
    1675           0 :         t.name = (char *)buf;
    1676           0 :         aol(ls->output_fifo->t, ls->output_fifo->nt, t, TOKEN_LIST_MEMG);
    1677           0 :         throw_away(ls->gf, (char *)buf);
    1678             : }
    1679             : 
    1680             : /*
    1681             :  * We saw a # at the beginning of a line (or preceeded only by whitespace).
    1682             :  * We check the directive name and act accordingly.
    1683             :  */
    1684           0 : static int handle_cpp(struct lexer_state *ls, int sharp_type)
    1685             : {
    1686             : #define condfset(x)     do { \
    1687             :                 ls->condf[(x) / 32] |= 1UL << ((x) % 32); \
    1688             :         } while (0)
    1689             : #define condfclr(x)     do { \
    1690             :                 ls->condf[(x) / 32] &= ~(1UL << ((x) % 32)); \
    1691             :         } while (0)
    1692             : #define condfval(x)     ((ls->condf[(x) / 32] & (1UL << ((x) % 32))) != 0)
    1693             : 
    1694           0 :         long l = ls->line;
    1695           0 :         unsigned long save_flags = ls->flags;
    1696           0 :         int ret = 0;
    1697             : 
    1698           0 :         save_flags = ls->flags;
    1699           0 :         ls->flags |= LEXER;
    1700           0 :         while (!next_token(ls)) {
    1701           0 :                 int t = ls->ctok->type;
    1702             : 
    1703           0 :                 switch (t) {
    1704             :                 case COMMENT:
    1705           0 :                         if (ls->flags & WARN_ANNOYING) {
    1706           0 :                                 warning(l, "comment in the middle of "
    1707             :                                         "a cpp directive");
    1708             :                         }
    1709             :                         /* fall through */
    1710             :                 case NONE:
    1711           0 :                         continue;
    1712             :                 case NEWLINE:
    1713             :                         /* null directive */
    1714           0 :                         if (ls->flags & WARN_ANNOYING) {
    1715             :                                 /* truly an annoying warning; null directives
    1716             :                                    are rare but may increase readability of
    1717             :                                    some source files, and they are legal */
    1718           0 :                                 warning(l, "null cpp directive");
    1719             :                         }
    1720           0 :                         if (!(ls->flags & LEXER)) put_char(ls, '\n');
    1721           0 :                         goto handle_exit2;
    1722             :                 case NAME:
    1723           0 :                         break;
    1724             :                 default:
    1725           0 :                         if (ls->flags & FAIL_SHARP) {
    1726             :                                 /* LPS 20050602 - ignores '#!' if on the first line */
    1727           0 :                                 if( ( l == 1 ) &&
    1728           0 :                                     ( ls->condcomp ) )
    1729             :                                 {
    1730           0 :                                         ret = 1;
    1731             :                                 }
    1732             :                                 else
    1733             :                                 /* LPS 20050602 */
    1734           0 :                                 if (ls->condcomp) {
    1735           0 :                                         error(l, "rogue '#'");
    1736           0 :                                         ret = 1;
    1737             :                                 } else {
    1738           0 :                                         if (ls->flags & WARN_STANDARD) {
    1739           0 :                                                 warning(l, "rogue '#' in code "
    1740             :                                                         "compiled out");
    1741           0 :                                                 ret = 0;
    1742             :                                         }
    1743             :                                 }
    1744           0 :                                 ls->flags = save_flags;
    1745           0 :                                 goto handle_warp_ign;
    1746             :                         } else {
    1747             :                                 struct token u;
    1748             : 
    1749           0 :                                 u.type = sharp_type;
    1750           0 :                                 u.line = l;
    1751           0 :                                 ls->flags = save_flags;
    1752           0 :                                 print_token(ls, &u, 0);
    1753           0 :                                 print_token(ls, ls->ctok, 0);
    1754           0 :                                 if (ls->flags & WARN_ANNOYING) {
    1755           0 :                                         warning(l, "rogue '#' dumped");
    1756             :                                 }
    1757             :                                 goto handle_exit3;
    1758             :                         }
    1759             :                 }
    1760           0 :                 if (ls->condcomp) {
    1761           0 :                         if (!strcmp(ls->ctok->name, "define")) {
    1762           0 :                                 ret = handle_define(ls);
    1763           0 :                                 goto handle_exit;
    1764           0 :                         } else if (!strcmp(ls->ctok->name, "undef")) {
    1765           0 :                                 ret = handle_undef(ls);
    1766           0 :                                 goto handle_exit;
    1767           0 :                         } else if (!strcmp(ls->ctok->name, "if")) {
    1768           0 :                                 if ((++ ls->ifnest) > 63) goto too_many_if;
    1769           0 :                                 condfclr(ls->ifnest - 1);
    1770           0 :                                 ret = handle_if(ls);
    1771           0 :                                 if (ret > 0) ret = 0;
    1772           0 :                                 else if (ret == 0) {
    1773           0 :                                         ls->condcomp = 0;
    1774           0 :                                         ls->condmet = 0;
    1775           0 :                                         ls->condnest = ls->ifnest - 1;
    1776             :                                 }
    1777           0 :                                 else ret = 1;
    1778           0 :                                 goto handle_exit;
    1779           0 :                         } else if (!strcmp(ls->ctok->name, "ifdef")) {
    1780           0 :                                 if ((++ ls->ifnest) > 63) goto too_many_if;
    1781           0 :                                 condfclr(ls->ifnest - 1);
    1782           0 :                                 ret = handle_ifdef(ls);
    1783           0 :                                 if (ret > 0) ret = 0;
    1784           0 :                                 else if (ret == 0) {
    1785           0 :                                         ls->condcomp = 0;
    1786           0 :                                         ls->condmet = 0;
    1787           0 :                                         ls->condnest = ls->ifnest - 1;
    1788             :                                 }
    1789           0 :                                 else ret = 1;
    1790           0 :                                 goto handle_exit;
    1791           0 :                         } else if (!strcmp(ls->ctok->name, "ifndef")) {
    1792           0 :                                 if ((++ ls->ifnest) > 63) goto too_many_if;
    1793           0 :                                 condfclr(ls->ifnest - 1);
    1794           0 :                                 ret = handle_ifndef(ls);
    1795           0 :                                 if (ret > 0) ret = 0;
    1796           0 :                                 else if (ret == 0) {
    1797           0 :                                         ls->condcomp = 0;
    1798           0 :                                         ls->condmet = 0;
    1799           0 :                                         ls->condnest = ls->ifnest - 1;
    1800             :                                 }
    1801           0 :                                 else ret = 1;
    1802           0 :                                 goto handle_exit;
    1803           0 :                         } else if (!strcmp(ls->ctok->name, "else")) {
    1804           0 :                                 if (ls->ifnest == 0
    1805           0 :                                         || condfval(ls->ifnest - 1)) {
    1806           0 :                                         error(l, "rogue #else");
    1807           0 :                                         ret = 1;
    1808           0 :                                         goto handle_warp;
    1809             :                                 }
    1810           0 :                                 condfset(ls->ifnest - 1);
    1811           0 :                                 if (ls->ifnest == 1) protect_detect.state = 0;
    1812           0 :                                 ls->condcomp = 0;
    1813           0 :                                 ls->condmet = 1;
    1814           0 :                                 ls->condnest = ls->ifnest - 1;
    1815           0 :                                 goto handle_warp;
    1816           0 :                         } else if (!strcmp(ls->ctok->name, "elif")) {
    1817           0 :                                 if (ls->ifnest == 0
    1818           0 :                                         || condfval(ls->ifnest - 1)) {
    1819           0 :                                         error(l, "rogue #elif");
    1820           0 :                                         ret = 1;
    1821           0 :                                         goto handle_warp_ign;
    1822             :                                 }
    1823           0 :                                 if (ls->ifnest == 1) protect_detect.state = 0;
    1824           0 :                                 ls->condcomp = 0;
    1825           0 :                                 ls->condmet = 1;
    1826           0 :                                 ls->condnest = ls->ifnest - 1;
    1827           0 :                                 goto handle_warp_ign;
    1828           0 :                         } else if (!strcmp(ls->ctok->name, "endif")) {
    1829           0 :                                 if (ls->ifnest == 0) {
    1830           0 :                                         error(l, "unmatched #endif");
    1831           0 :                                         ret = 1;
    1832           0 :                                         goto handle_warp;
    1833             :                                 }
    1834           0 :                                 if ((-- ls->ifnest) == 0
    1835           0 :                                         && protect_detect.state == 2) {
    1836           0 :                                         protect_detect.state = 3;
    1837             :                                 }
    1838           0 :                                 goto handle_warp;
    1839           0 :                         } else if (!strcmp(ls->ctok->name, "include")) {
    1840           0 :                                 ret = handle_include(ls, save_flags, 0);
    1841           0 :                                 goto handle_exit3;
    1842           0 :                         } else if (!strcmp(ls->ctok->name, "include_next")) {
    1843           0 :                                 ret = handle_include(ls, save_flags, 1);
    1844           0 :                                 goto handle_exit3;
    1845           0 :                         } else if (!strcmp(ls->ctok->name, "pragma")) {
    1846           0 :                                 if (!(save_flags & LEXER)) {
    1847             : #ifdef PRAGMA_DUMP
    1848             :                                         /* dump #pragma in output */
    1849             :                                         struct token u;
    1850             : 
    1851           0 :                                         u.type = sharp_type;
    1852           0 :                                         u.line = l;
    1853           0 :                                         ls->flags = save_flags;
    1854           0 :                                         print_token(ls, &u, 0);
    1855           0 :                                         print_token(ls, ls->ctok, 0);
    1856           0 :                                         while (ls->flags |= LEXER,
    1857           0 :                                                 !next_token(ls)) {
    1858             :                                                 long save_line;
    1859             : 
    1860           0 :                                                 ls->flags &= ~LEXER;
    1861           0 :                                                 save_line = ls->line;
    1862           0 :                                                 ls->line = l;
    1863           0 :                                                 print_token(ls, ls->ctok, 0);
    1864           0 :                                                 ls->line = save_line;
    1865           0 :                                                 if (ls->ctok->type == NEWLINE)
    1866           0 :                                                         break;
    1867             :                                         }
    1868             :                                         goto handle_exit3;
    1869             : #else
    1870             :                                         if (ls->flags & WARN_PRAGMA)
    1871             :                                                 warning(l, "#pragma ignored "
    1872             :                                                         "and not dumped");
    1873             :                                         goto handle_warp_ign;
    1874             : #endif
    1875             :                                 }
    1876           0 :                                 if (!(ls->flags & HANDLE_PRAGMA))
    1877           0 :                                         goto handle_warp_ign;
    1878           0 :                                 handle_pragma(ls);
    1879           0 :                                 goto handle_exit;
    1880           0 :                         } else if (!strcmp(ls->ctok->name, "error")) {
    1881           0 :                                 ret = 1;
    1882           0 :                                 handle_error(ls);
    1883           0 :                                 goto handle_exit;
    1884           0 :                         } else if (!strcmp(ls->ctok->name, "line")) {
    1885           0 :                                 ret = handle_line(ls, save_flags);
    1886           0 :                                 goto handle_exit;
    1887           0 :                         } else if ((ls->flags & HANDLE_ASSERTIONS)
    1888           0 :                                 && !strcmp(ls->ctok->name, "assert")) {
    1889           0 :                                 ret = handle_assert(ls);
    1890           0 :                                 goto handle_exit;
    1891           0 :                         } else if ((ls->flags & HANDLE_ASSERTIONS)
    1892           0 :                                 && !strcmp(ls->ctok->name, "unassert")) {
    1893           0 :                                 ret = handle_unassert(ls);
    1894           0 :                                 goto handle_exit;
    1895             :                         }
    1896             :                 } else {
    1897           0 :                         if (!strcmp(ls->ctok->name, "else")) {
    1898           0 :                                 if (condfval(ls->ifnest - 1)
    1899           0 :                                         && (ls->flags & WARN_STANDARD)) {
    1900           0 :                                         warning(l, "rogue #else in code "
    1901             :                                                 "compiled out");
    1902             :                                 }
    1903           0 :                                 if (ls->condnest == ls->ifnest - 1) {
    1904           0 :                                         if (!ls->condmet) ls->condcomp = 1;
    1905             :                                 }
    1906           0 :                                 condfset(ls->ifnest - 1);
    1907           0 :                                 if (ls->ifnest == 1) protect_detect.state = 0;
    1908           0 :                                 goto handle_warp;
    1909           0 :                         } else if (!strcmp(ls->ctok->name, "elif")) {
    1910           0 :                                 if (condfval(ls->ifnest - 1)
    1911           0 :                                         && (ls->flags & WARN_STANDARD)) {
    1912           0 :                                         warning(l, "rogue #elif in code "
    1913             :                                                 "compiled out");
    1914             :                                 }
    1915           0 :                                 if (ls->condnest != ls->ifnest - 1
    1916           0 :                                         || ls->condmet)
    1917             :                                         goto handle_warp_ign;
    1918           0 :                                 if (ls->ifnest == 1) protect_detect.state = 0;
    1919           0 :                                 ret = handle_if(ls);
    1920           0 :                                 if (ret > 0) {
    1921           0 :                                         ls->condcomp = 1;
    1922           0 :                                         ls->condmet = 1;
    1923           0 :                                         ret = 0;
    1924           0 :                                 } else if (ret < 0) ret = 1;
    1925           0 :                                 goto handle_exit;
    1926           0 :                         } else if (!strcmp(ls->ctok->name, "endif")) {
    1927           0 :                                 if ((-- ls->ifnest) == ls->condnest) {
    1928           0 :                                         if (ls->ifnest == 0 &&
    1929           0 :                                                 protect_detect.state == 2)
    1930           0 :                                                 protect_detect.state = 3;
    1931           0 :                                         ls->condcomp = 1;
    1932             :                                 }
    1933           0 :                                 goto handle_warp;
    1934           0 :                         } else if (!strcmp(ls->ctok->name, "if")
    1935           0 :                                 || !strcmp(ls->ctok->name, "ifdef")
    1936           0 :                                 || !strcmp(ls->ctok->name, "ifndef")) {
    1937           0 :                                 if ((++ ls->ifnest) > 63) goto too_many_if;
    1938           0 :                                 condfclr(ls->ifnest - 1);
    1939             :                         }
    1940           0 :                         goto handle_warp_ign;
    1941             :                 }
    1942             :                 /*
    1943             :                  * Unrecognized directive. We emit either an error or
    1944             :                  * an annoying warning, depending on a command-line switch.
    1945             :                  */
    1946           0 :                 if (ls->flags & FAIL_SHARP) {
    1947           0 :                         error(l, "unknown cpp directive '#%s'",
    1948           0 :                                 ls->ctok->name);
    1949           0 :                         goto handle_warp_ign;
    1950             :                 } else {
    1951             :                         struct token u;
    1952             : 
    1953           0 :                         u.type = sharp_type;
    1954           0 :                         u.line = l;
    1955           0 :                         ls->flags = save_flags;
    1956           0 :                         print_token(ls, &u, 0);
    1957           0 :                         print_token(ls, ls->ctok, 0);
    1958           0 :                         if (ls->flags & WARN_ANNOYING) {
    1959           0 :                                 warning(l, "rogue '#' dumped");
    1960             :                         }
    1961             :                 }
    1962             :         }
    1963           0 :         return 1;
    1964             : 
    1965             : handle_warp_ign:
    1966           0 :         while (!next_token(ls)) if (ls->ctok->type == NEWLINE) break;
    1967           0 :         goto handle_exit;
    1968             : handle_warp:
    1969           0 :         while (!next_token(ls)) {
    1970           0 :                 if (!ttWHI(ls->ctok->type) && (ls->flags & WARN_STANDARD)) {
    1971           0 :                         warning(l, "trailing garbage in "
    1972             :                                 "preprocessing directive");
    1973             :                 }
    1974           0 :                 if (ls->ctok->type == NEWLINE) break;
    1975             :         }
    1976             : handle_exit:
    1977           0 :         if (!(ls->flags & LEXER)) put_char(ls, '\n');
    1978             : handle_exit3:
    1979           0 :         if (protect_detect.state == 1) {
    1980           0 :                 protect_detect.state = 0;
    1981           0 :         } else if (protect_detect.state == -1) {
    1982             :                 /* just after the #include */
    1983           0 :                 protect_detect.state = 1;
    1984             :         }
    1985             : handle_exit2:
    1986           0 :         ls->flags = save_flags;
    1987           0 :         return ret;
    1988             : too_many_if:
    1989           0 :         error(l, "too many levels of conditional inclusion (max 63)");
    1990           0 :         ret = 1;
    1991           0 :         goto handle_warp;
    1992             : #undef condfset
    1993             : #undef condfclr
    1994             : #undef condfval
    1995             : }
    1996             : 
    1997             : /*
    1998             :  * This is the main entry function. It maintains count of #, and call the
    1999             :  * appropriate functions when it encounters a cpp directive or a macro
    2000             :  * name.
    2001             :  * return value: positive on error; CPPERR_EOF means "end of input reached"
    2002             :  */
    2003           0 : int cpp(struct lexer_state *ls)
    2004             : {
    2005           0 :         int r = 0;
    2006             : 
    2007           0 :         while (next_token(ls)) {
    2008           0 :                 if (protect_detect.state == 3) {
    2009             :                         /*
    2010             :                          * At that point, protect_detect.ff->protect might
    2011             :                          * be non-zero, if the file has been recursively
    2012             :                          * included, and a guardian detected.
    2013             :                          */
    2014           0 :                         if (!protect_detect.ff->protect) {
    2015             :                                 /* Cool ! A new guardian has been detected. */
    2016           0 :                                 protect_detect.ff->protect =
    2017           0 :                                         protect_detect.macro;
    2018           0 :                         } else if (protect_detect.macro) {
    2019             :                                 /* We found a guardian but an old one. */
    2020           0 :                                 freemem(protect_detect.macro);
    2021             :                         }
    2022           0 :                         protect_detect.macro = 0;
    2023             :                 }
    2024           0 :                 if (ls->ifnest) {
    2025           0 :                         error(ls->line, "unterminated #if construction "
    2026             :                                 "(depth %ld)", ls->ifnest);
    2027           0 :                         r = CPPERR_NEST;
    2028             :                 }
    2029           0 :                 if (ls_depth == 0) return CPPERR_EOF;
    2030           0 :                 close_input(ls);
    2031           0 :                 if (!(ls->flags & LEXER) && !ls->ltwnl) {
    2032           0 :                         put_char(ls, '\n');
    2033           0 :                         ls->ltwnl = 1;
    2034             :                 }
    2035           0 :                 pop_file_context(ls);
    2036           0 :                 ls->oline ++;
    2037           0 :                 if (enter_file(ls, ls->flags)) {
    2038           0 :                         ls->ctok->type = NEWLINE;
    2039           0 :                         ls->ltwnl = 1;
    2040           0 :                         break;
    2041             :                 }
    2042             :         }
    2043           0 :         if (!(ls->ltwnl && (ls->ctok->type == SHARP
    2044           0 :                 || ls->ctok->type == DIG_SHARP))
    2045           0 :                 && protect_detect.state == 1 && !ttWHI(ls->ctok->type)) {
    2046             :                 /* the first non-whitespace token encountered is not
    2047             :                    a sharp introducing a cpp directive */
    2048           0 :                 protect_detect.state = 0;
    2049             :         }
    2050           0 :         if (protect_detect.state == 3 && !ttWHI(ls->ctok->type)) {
    2051             :                 /* a non-whitespace token encountered after the #endif */
    2052           0 :                 protect_detect.state = 0;
    2053             :         }
    2054           0 :         if (ls->condcomp) {
    2055           0 :                 if (ls->ltwnl && (ls->ctok->type == SHARP
    2056           0 :                         || ls->ctok->type == DIG_SHARP)) {
    2057           0 :                         int x = handle_cpp(ls, ls->ctok->type);
    2058             : 
    2059           0 :                         ls->ltwnl = 1;
    2060           0 :                         return r ? r : x;
    2061             :                 }
    2062           0 :                 if (ls->ctok->type == NAME) {
    2063             :                         struct macro *m;
    2064             : 
    2065           0 :                         if ((m = get_macro(ls->ctok->name)) != 0) {
    2066             :                                 int x;
    2067             : 
    2068           0 :                                 x = substitute_macro(ls, m, 0, 1, 0,
    2069           0 :                                         ls->ctok->line);
    2070           0 :                                 if (!(ls->flags & LEXER))
    2071           0 :                                         garbage_collect(ls->gf);
    2072           0 :                                 return r ? r : x;
    2073             :                         }
    2074           0 :                         if (!(ls->flags & LEXER))
    2075           0 :                                 print_token(ls, ls->ctok, 0);
    2076             :                 }
    2077             :         } else {
    2078           0 :                 if (ls->ltwnl && (ls->ctok->type == SHARP
    2079           0 :                         || ls->ctok->type == DIG_SHARP)) {
    2080           0 :                         int x = handle_cpp(ls, ls->ctok->type);
    2081             : 
    2082           0 :                         ls->ltwnl = 1;
    2083           0 :                         return r ? r : x;
    2084             :                 }
    2085             :         }
    2086           0 :         if (ls->ctok->type == NEWLINE) ls->ltwnl = 1;
    2087           0 :         else if (!ttWHI(ls->ctok->type)) ls->ltwnl = 0;
    2088           0 :         return r ? r : -1;
    2089             : }
    2090             : 
    2091             : #ifndef STAND_ALONE
    2092             : /*
    2093             :  * llex() and lex() are the lexing functions, when the preprocessor is
    2094             :  * linked to another code. llex() should be called only by lex().
    2095             :  */
    2096             : static int llex(struct lexer_state *ls)
    2097             : {
    2098             :         struct token_fifo *tf = ls->output_fifo;
    2099             :         int r;
    2100             : 
    2101             :         if (tf->nt != 0) {
    2102             :                 if (tf->art < tf->nt) {
    2103             : #ifdef INMACRO_FLAG
    2104             :                         if (!ls->inmacro) {
    2105             :                                 ls->inmacro = 1;
    2106             :                                 ls->macro_count ++;
    2107             :                         }
    2108             : #endif
    2109             :                         ls->ctok = tf->t + (tf->art ++);
    2110             :                         if (ls->ctok->type > DIGRAPH_TOKENS
    2111             :                                 && ls->ctok->type < DIGRAPH_TOKENS_END) {
    2112             :                                 ls->ctok->type = undig(ls->ctok->type);
    2113             :                         }
    2114             :                         return 0;
    2115             :                 } else {
    2116             : #ifdef INMACRO_FLAG
    2117             :                         ls->inmacro = 0;
    2118             : #endif
    2119             :                         freemem(tf->t);
    2120             :                         tf->art = tf->nt = 0;
    2121             :                         garbage_collect(ls->gf);
    2122             :                         ls->ctok = ls->save_ctok;
    2123             :                 }
    2124             :         }
    2125             :         r = cpp(ls);
    2126             :         if (ls->ctok->type > DIGRAPH_TOKENS
    2127             :                 && ls->ctok->type < LAST_MEANINGFUL_TOKEN) {
    2128             :                 ls->ctok->type = undig(ls->ctok->type);
    2129             :         }
    2130             :         if (r > 0) return r;
    2131             :         if (r < 0) return 0;
    2132             :         return llex(ls);
    2133             : }
    2134             : 
    2135             : /*
    2136             :  * lex() reads the next token from the processed stream and stores it
    2137             :  * into ls->ctok.
    2138             :  * return value: non zero on error (including CPPERR_EOF, which is not
    2139             :  * quite an error)
    2140             :  */
    2141             : int lex(struct lexer_state *ls)
    2142             : {
    2143             :         int r;
    2144             : 
    2145             :         do {
    2146             :                 r = llex(ls);
    2147             : #ifdef SEMPER_FIDELIS
    2148             :         } while (!r && !ls->condcomp);
    2149             : #else
    2150             :         } while (!r && (!ls->condcomp || (ttWHI(ls->ctok->type) &&
    2151             :                 (!(ls->flags & LINE_NUM) || ls->ctok->type != NEWLINE))));
    2152             : #endif
    2153             :         return r;
    2154             : }
    2155             : #endif
    2156             : 
    2157             : /*
    2158             :  * check_cpp_errors() must be called when the end of input is reached;
    2159             :  * it checks pending errors due to truncated constructs (actually none,
    2160             :  * this is reserved for future evolutions).
    2161             :  */
    2162           0 : int check_cpp_errors(struct lexer_state *ls)
    2163             : {
    2164           0 :         if (ls->flags & KEEP_OUTPUT) {
    2165           0 :                 put_char(ls, '\n');
    2166             :         }
    2167           0 :         if (emit_dependencies) fputc('\n', emit_output);
    2168             : #ifndef NO_UCPP_BUF
    2169             :         if (!(ls->flags & LEXER)) {
    2170             :                 flush_output(ls);
    2171             :         }
    2172             : #endif
    2173           0 :         if ((ls->flags & WARN_TRIGRAPHS) && ls->count_trigraphs)
    2174           0 :                 warning(0, "%ld trigraph(s) encountered", ls->count_trigraphs);
    2175           0 :         return 0;
    2176             : }
    2177             : 
    2178             : /*
    2179             :  * init_cpp() initializes static tables inside ucpp. It needs not be
    2180             :  * called more than once.
    2181             :  */
    2182           0 : void init_cpp(void)
    2183             : {
    2184           0 :         init_cppm();
    2185           0 : }
    2186             : 
    2187             : /*
    2188             :  * (re)init the global tables.
    2189             :  * If standard_assertions is non 0, init the assertions table.
    2190             :  */
    2191           0 : void init_tables(int with_assertions)
    2192             : {
    2193             :         time_t t;
    2194             :         struct tm *ct;
    2195             : 
    2196           0 :         init_buf_lexer_state(&dsharp_lexer, 0);
    2197             : #ifdef PRAGMA_TOKENIZE
    2198           0 :         init_buf_lexer_state(&tokenize_lexer, 0);
    2199             : #endif
    2200           0 :         time(&t);
    2201           0 :         ct = localtime(&t);
    2202             : #ifdef NOSTRFTIME
    2203             :         /* we have a quite old compiler, that does not know the
    2204             :            (standard since 1990) strftime() function. */
    2205             :         {
    2206             :                 char *c = asctime(ct);
    2207             : 
    2208             :                 compile_time[0] = '"';
    2209             :                 mmv(compile_time + 1, c + 11, 8);
    2210             :                 compile_time[9] = '"';
    2211             :                 compile_time[10] = 0;
    2212             :                 compile_date[0] = '"';
    2213             :                 mmv(compile_date + 1, c + 4, 7);
    2214             :                 mmv(compile_date + 8, c + 20, 4);
    2215             :                 compile_date[12] = '"';
    2216             :                 compile_date[13] = 0;
    2217             :         }
    2218             : #else
    2219           0 :         strftime(compile_time, 12, "\"%H:%M:%S\"", ct);
    2220           0 :         strftime(compile_date, 24, "\"%b %d %Y\"", ct);
    2221             : #endif
    2222           0 :         init_macros();
    2223           0 :         if (with_assertions) init_assertions();
    2224           0 :         init_found_files();
    2225           0 : }
    2226             : 
    2227             : /*
    2228             :  * Resets the include path.
    2229             :  */
    2230           0 : void init_include_path(char *incpath[])
    2231             : {
    2232           0 :         if (include_path_nb) {
    2233             :                 size_t i;
    2234             : 
    2235           0 :                 for (i = 0; i < include_path_nb; i ++)
    2236           0 :                         freemem(include_path[i]);
    2237           0 :                 freemem(include_path);
    2238           0 :                 include_path_nb = 0;
    2239             :         }
    2240           0 :         if (incpath) {
    2241             :                 int i;
    2242             : 
    2243           0 :                 for (i = 0; incpath[i]; i ++)
    2244           0 :                         aol(include_path, include_path_nb,
    2245             :                                 sdup(incpath[i]), INCPATH_MEMG);
    2246             :         }
    2247           0 : }
    2248             : 
    2249             : /*
    2250             :  * add_incpath() adds "path" to the standard include path.
    2251             :  */
    2252           0 : void add_incpath(char *path)
    2253             : {
    2254           0 :         aol(include_path, include_path_nb, sdup(path), INCPATH_MEMG);
    2255           0 : }
    2256             : 
    2257             : /*
    2258             :  * This function cleans the memory. It should release all allocated
    2259             :  * memory structures and may be called even if the current pre-processing
    2260             :  * is not finished or reported an error.
    2261             :  */
    2262           0 : void wipeout()
    2263             : {
    2264             :         struct lexer_state ls;
    2265             : 
    2266           0 :         if (include_path_nb > 0) {
    2267             :                 size_t i;
    2268             : 
    2269           0 :                 for (i = 0; i < include_path_nb; i ++)
    2270           0 :                         freemem(include_path[i]);
    2271           0 :                 freemem(include_path);
    2272           0 :                 include_path = 0;
    2273           0 :                 include_path_nb = 0;
    2274             :         }
    2275           0 :         if (current_filename) freemem(current_filename);
    2276           0 :         current_filename = 0;
    2277           0 :         current_long_filename = 0;
    2278           0 :         current_incdir = -1;
    2279           0 :         protect_detect.state = 0;
    2280           0 :         if (protect_detect.macro) freemem(protect_detect.macro);
    2281           0 :         protect_detect.macro = 0;
    2282           0 :         protect_detect.ff = 0;
    2283           0 :         init_lexer_state(&ls);
    2284           0 :         while (ls_depth > 0) pop_file_context(&ls);
    2285           0 :         free_lexer_state(&ls);
    2286           0 :         free_lexer_state(&dsharp_lexer);
    2287             : #ifdef PRAGMA_TOKENIZE
    2288           0 :         free_lexer_state(&tokenize_lexer);
    2289             : #endif
    2290           0 :         if (found_files_init_done) HTT_kill(&found_files);
    2291           0 :         found_files_init_done = 0;
    2292           0 :         if (found_files_sys_init_done) HTT_kill(&found_files_sys);
    2293           0 :         found_files_sys_init_done = 0;
    2294           0 :         wipe_macros();
    2295           0 :         wipe_assertions();
    2296           0 : }
    2297             : 
    2298             : #ifdef STAND_ALONE
    2299             : /*
    2300             :  * print some help
    2301             :  */
    2302           0 : static void usage(char *command_name)
    2303             : {
    2304           0 :         fprintf(stderr,
    2305             :         "Usage: %s [options] [file]\n"
    2306             :         "language options:\n"
    2307             :         "  -C              keep comments in output\n"
    2308             :         "  -s              keep '#' when no cpp directive is recognized\n"
    2309             :         "  -l              do not emit line numbers\n"
    2310             :         "  -lg             emit gcc-like line numbers\n"
    2311             :         "  -CC             disable C++-like comments\n"
    2312             :         "  -a, -na, -a0    handle (or not) assertions\n"
    2313             :         "  -V              disable macros with extra arguments\n"
    2314             :         "  -u              understand UTF-8 in source\n"
    2315             :         "  -X              enable -a, -u and -Y\n"
    2316             :         "  -c90            mimic C90 behaviour\n"
    2317             :         "  -t              disable trigraph support\n"
    2318             :         "warning options:\n"
    2319             :         "  -wt             emit a final warning when trigaphs are encountered\n"
    2320             :         "  -wtt            emit warnings for each trigaph encountered\n"
    2321             :         "  -wa             emit warnings that are usually useless\n"
    2322             :         "  -w0             disable standard warnings\n"
    2323             :         "directory options:\n"
    2324             :         "  -I directory    add 'directory' before the standard include path\n"
    2325             :         "  -J directory    add 'directory' after the standard include path\n"
    2326             :         "  -zI             do not use the standard include path\n"
    2327             :         "  -M              emit Makefile-like dependencies instead of normal "
    2328             :                         "output\n"
    2329             :         "  -Ma             emit also dependancies for system files\n"
    2330             :         "  -o file         store output in file\n"
    2331             :         "macro and assertion options:\n"
    2332             :         "  -Dmacro         predefine 'macro'\n"
    2333             :         "  -Dmacro=def     predefine 'macro' with 'def' content\n"
    2334             :         "  -Umacro         undefine 'macro'\n"
    2335             :         "  -Afoo(bar)      assert foo(bar)\n"
    2336             :         "  -Bfoo(bar)      unassert foo(bar)\n"
    2337             :         "  -Y              predefine system-dependant macros\n"
    2338             :         "  -Z              do not predefine special macros\n"
    2339             :         "  -d              emit defined macros\n"
    2340             :         "  -e              emit assertions\n"
    2341             :         "misc options:\n"
    2342             :         "  -v              print version number and settings\n"
    2343             :         "  -h              show this help\n",
    2344             :         command_name);
    2345           0 : }
    2346             : 
    2347             : /*
    2348             :  * print version and compile-time settings
    2349             :  */
    2350           0 : static void version(void)
    2351             : {
    2352             :         size_t i;
    2353             : 
    2354           0 :         fprintf(stderr, "ucpp version %d.%d\n", VERS_MAJ, VERS_MIN);
    2355           0 :         fprintf(stderr, "search path:\n");
    2356           0 :         for (i = 0; i < include_path_nb; i ++)
    2357           0 :                 fprintf(stderr, "  %s\n", include_path[i]);
    2358           0 : }
    2359             : 
    2360             : /*
    2361             :  * parse_opt() initializes many things according to the command-line
    2362             :  * options.
    2363             :  * Return values:
    2364             :  * 0  on success
    2365             :  * 1  on semantic error (redefinition of a special macro, for instance)
    2366             :  * 2  on syntaxic error (unknown options for instance)
    2367             :  */
    2368           0 : static int parse_opt(int argc, char *argv[], struct lexer_state *ls)
    2369             : {
    2370           0 :         int i, ret = 0;
    2371           0 :         char *filename = 0;
    2372           0 :         int with_std_incpath = 1;
    2373           0 :         int print_version = 0, print_defs = 0, print_asserts = 0;
    2374           0 :         int system_macros = 0, standard_assertions = 1;
    2375             : 
    2376           0 :         init_lexer_state(ls);
    2377           0 :         ls->flags = DEFAULT_CPP_FLAGS;
    2378           0 :         emit_output = ls->output = stdout;
    2379           0 :         for (i = 1; i < argc; i ++) if (argv[i][0] == '-') {
    2380           0 :                 if (!strcmp(argv[i], "-h")) {
    2381           0 :                         return 2;
    2382           0 :                 } else if (!strcmp(argv[i], "-C")) {
    2383           0 :                         ls->flags &= ~DISCARD_COMMENTS;
    2384           0 :                 } else if (!strcmp(argv[i], "-CC")) {
    2385           0 :                         ls->flags &= ~CPLUSPLUS_COMMENTS;
    2386           0 :                 } else if (!strcmp(argv[i], "-a")) {
    2387           0 :                         ls->flags |= HANDLE_ASSERTIONS;
    2388           0 :                 } else if (!strcmp(argv[i], "-na")) {
    2389           0 :                         ls->flags |= HANDLE_ASSERTIONS;
    2390           0 :                         standard_assertions = 0;
    2391           0 :                 } else if (!strcmp(argv[i], "-a0")) {
    2392           0 :                         ls->flags &= ~HANDLE_ASSERTIONS;
    2393           0 :                 } else if (!strcmp(argv[i], "-V")) {
    2394           0 :                         ls->flags &= ~MACRO_VAARG;
    2395           0 :                 } else if (!strcmp(argv[i], "-u")) {
    2396           0 :                         ls->flags |= UTF8_SOURCE;
    2397           0 :                 } else if (!strcmp(argv[i], "-X")) {
    2398           0 :                         ls->flags |= HANDLE_ASSERTIONS;
    2399           0 :                         ls->flags |= UTF8_SOURCE;
    2400           0 :                         system_macros = 1;
    2401           0 :                 } else if (!strcmp(argv[i], "-c90")) {
    2402           0 :                         ls->flags &= ~MACRO_VAARG;
    2403           0 :                         ls->flags &= ~CPLUSPLUS_COMMENTS;
    2404           0 :                         c99_compliant = 0;
    2405           0 :                         c99_hosted = -1;
    2406           0 :                 } else if (!strcmp(argv[i], "-t")) {
    2407           0 :                         ls->flags &= ~HANDLE_TRIGRAPHS;
    2408           0 :                 } else if (!strcmp(argv[i], "-wt")) {
    2409           0 :                         ls->flags |= WARN_TRIGRAPHS;
    2410           0 :                 } else if (!strcmp(argv[i], "-wtt")) {
    2411           0 :                         ls->flags |= WARN_TRIGRAPHS_MORE;
    2412           0 :                 } else if (!strcmp(argv[i], "-wa")) {
    2413           0 :                         ls->flags |= WARN_ANNOYING;
    2414           0 :                 } else if (!strcmp(argv[i], "-w0")) {
    2415           0 :                         ls->flags &= ~WARN_STANDARD;
    2416           0 :                         ls->flags &= ~WARN_PRAGMA;
    2417           0 :                 } else if (!strcmp(argv[i], "-s")) {
    2418           0 :                         ls->flags &= ~FAIL_SHARP;
    2419           0 :                 } else if (!strcmp(argv[i], "-l")) {
    2420           0 :                         ls->flags &= ~LINE_NUM;
    2421           0 :                 } else if (!strcmp(argv[i], "-lg")) {
    2422           0 :                         ls->flags |= GCC_LINE_NUM;
    2423           0 :                 } else if (!strcmp(argv[i], "-M")) {
    2424           0 :                         ls->flags &= ~KEEP_OUTPUT;
    2425           0 :                         emit_dependencies = 1;
    2426           0 :                 } else if (!strcmp(argv[i], "-Ma")) {
    2427           0 :                         ls->flags &= ~KEEP_OUTPUT;
    2428           0 :                         emit_dependencies = 2;
    2429           0 :                 } else if (!strcmp(argv[i], "-Y")) {
    2430           0 :                         system_macros = 1;
    2431           0 :                 } else if (!strcmp(argv[i], "-Z")) {
    2432           0 :                         no_special_macros = 1;
    2433           0 :                 } else if (!strcmp(argv[i], "-d")) {
    2434           0 :                         ls->flags &= ~KEEP_OUTPUT;
    2435           0 :                         print_defs = 1;
    2436           0 :                 } else if (!strcmp(argv[i], "-e")) {
    2437           0 :                         ls->flags &= ~KEEP_OUTPUT;
    2438           0 :                         print_asserts = 1;
    2439           0 :                 } else if (!strcmp(argv[i], "-zI")) {
    2440           0 :                         with_std_incpath = 0;
    2441           0 :                 } else if (!strcmp(argv[i], "-I") || !strcmp(argv[i], "-J")) {
    2442           0 :                         i ++;
    2443           0 :                 } else if (!strcmp(argv[i], "-o")) {
    2444           0 :                         if ((++ i) >= argc) {
    2445           0 :                                 error(-1, "missing filename after -o");
    2446           0 :                                 return 2;
    2447             :                         }
    2448           0 :                         if (argv[i][0] == '-' && argv[i][1] == 0) {
    2449           0 :                                 emit_output = ls->output = stdout;
    2450             :                         } else {
    2451           0 :                                 ls->output = fopen(argv[i], "w");
    2452           0 :                                 if (!ls->output) {
    2453           0 :                                         error(-1, "failed to open for "
    2454           0 :                                                 "writing: %s", argv[i]);
    2455           0 :                                         return 2;
    2456             :                                 }
    2457           0 :                                 emit_output = ls->output;
    2458             :                         }
    2459           0 :                 } else if (!strcmp(argv[i], "-v")) {
    2460           0 :                         print_version = 1;
    2461           0 :                 } else if (argv[i][1] != 'I' && argv[i][1] != 'J'
    2462           0 :                         && argv[i][1] != 'D' && argv[i][1] != 'U'
    2463           0 :                         && argv[i][1] != 'A' && argv[i][1] != 'B')
    2464           0 :                         warning(-1, "unknown option '%s'", argv[i]);
    2465             :         } else {
    2466           0 :                 if (filename != 0) {
    2467           0 :                         error(-1, "spurious duplicate filename '%s' - vs. '%s' ", argv[i], filename);
    2468           0 :                         return 2;
    2469             :                 }
    2470           0 :                 filename = argv[i];
    2471             :         }
    2472           0 :         init_tables(ls->flags & HANDLE_ASSERTIONS);
    2473           0 :         init_include_path(0);
    2474           0 :         if (filename) {
    2475             : #ifdef UCPP_MMAP
    2476             :                 FILE *f = fopen_mmap_file(filename);
    2477             : 
    2478             :                 ls->input = 0;
    2479             :                 if (f) set_input_file(ls, f);
    2480             : #else
    2481           0 :                 ls->input = fopen(filename, "r");
    2482             : #endif
    2483           0 :                 if (!ls->input) {
    2484           0 :                         error(-1, "file '%s' not found", filename);
    2485           0 :                         return 1;
    2486             :                 }
    2487             : #ifdef NO_LIBC_BUF
    2488             :                 setbuf(ls->input, 0);
    2489             : #endif
    2490           0 :                 set_init_filename(filename, 1);
    2491             :         } else {
    2492           0 :                 ls->input = stdin;
    2493           0 :                 set_init_filename("<stdin>", 0);
    2494             :         }
    2495           0 :         for (i = 1; i < argc; i ++)
    2496           0 :                 if (argv[i][0] == '-' && argv[i][1] == 'I')
    2497           0 :                         add_incpath(argv[i][2] ? argv[i] + 2 : argv[i + 1]);
    2498           0 :         if (system_macros) for (i = 0; system_macros_def[i]; i ++)
    2499           0 :                 ret = ret || define_macro(ls, system_macros_def[i]);
    2500           0 :         for (i = 1; i < argc; i ++)
    2501           0 :                 if (argv[i][0] == '-' && argv[i][1] == 'D')
    2502           0 :                         ret = ret || define_macro(ls, argv[i] + 2);
    2503           0 :         for (i = 1; i < argc; i ++)
    2504           0 :                 if (argv[i][0] == '-' && argv[i][1] == 'U')
    2505           0 :                         ret = ret || undef_macro(ls, argv[i] + 2);
    2506           0 :         if (ls->flags & HANDLE_ASSERTIONS) {
    2507           0 :                 if (standard_assertions)
    2508           0 :                         for (i = 0; system_assertions_def[i]; i ++)
    2509           0 :                                 make_assertion(system_assertions_def[i]);
    2510           0 :                 for (i = 1; i < argc; i ++)
    2511           0 :                         if (argv[i][0] == '-' && argv[i][1] == 'A')
    2512           0 :                                 ret = ret || make_assertion(argv[i] + 2);
    2513           0 :                 for (i = 1; i < argc; i ++)
    2514           0 :                         if (argv[i][0] == '-' && argv[i][1] == 'B')
    2515           0 :                                 ret = ret || destroy_assertion(argv[i] + 2);
    2516             :         } else {
    2517           0 :                 for (i = 1; i < argc; i ++)
    2518           0 :                         if (argv[i][0] == '-'
    2519           0 :                                 && (argv[i][1] == 'A' || argv[i][1] == 'B'))
    2520           0 :                                 warning(-1, "assertions disabled");
    2521             :         }
    2522           0 :         if (with_std_incpath) {
    2523           0 :                 for (i = 0; include_path_std[i]; i ++)
    2524           0 :                         add_incpath(include_path_std[i]);
    2525             :         }
    2526           0 :         for (i = 1; i < argc; i ++)
    2527           0 :                 if (argv[i][0] == '-' && argv[i][1] == 'J')
    2528           0 :                         add_incpath(argv[i][2] ? argv[i] + 2 : argv[i + 1]);
    2529             : 
    2530           0 :         if (print_version) {
    2531           0 :                 version();
    2532           0 :                 return 1;
    2533             :         }
    2534           0 :         if (print_defs) {
    2535           0 :                 print_defines();
    2536           0 :                 emit_defines = 1;
    2537             :         }
    2538           0 :         if (print_asserts && (ls->flags & HANDLE_ASSERTIONS)) {
    2539           0 :                 print_assertions();
    2540           0 :                 emit_assertions = 1;
    2541             :         }
    2542           0 :         return ret;
    2543             : }
    2544             : 
    2545           0 : int main(int argc, char *argv[])
    2546             : {
    2547             :         struct lexer_state ls;
    2548           0 :         int r, fr = 0;
    2549             : 
    2550           0 :         init_cpp();
    2551           0 :         if ((r = parse_opt(argc, argv, &ls)) != 0) {
    2552           0 :                 if (r == 2) usage(argv[0]);
    2553           0 :                 return EXIT_FAILURE;
    2554             :         }
    2555           0 :         enter_file(&ls, ls.flags);
    2556           0 :         while ((r = cpp(&ls)) < CPPERR_EOF) fr = fr || (r > 0);
    2557           0 :         fr = fr || check_cpp_errors(&ls);
    2558           0 :         free_lexer_state(&ls);
    2559           0 :         wipeout();
    2560             : #ifdef MEM_DEBUG
    2561             :         report_leaks();
    2562             : #endif
    2563           0 :         return fr ? EXIT_FAILURE : EXIT_SUCCESS;
    2564             : }
    2565             : #endif

Generated by: LCOV version 1.10