LCOV - code coverage report
Current view: top level - rsc/source/rscpp - cpp1.c (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 125 142 88.0 %
Date: 2014-11-03 Functions: 5 5 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #define NOMAIN
      21             : 
      22             : #include <stdio.h>
      23             : #include <ctype.h>
      24             : #include "cppdef.h"
      25             : #include "cpp.h"
      26             : 
      27             : FILE* pCppOut = NULL;
      28             : FILE* pCppIn  = NULL;
      29             : 
      30             : #if OSL_DEBUG_LEVEL > 1
      31             : FILE* pDefOut = NULL;       /* ER  evtl. #define's dump */
      32             : #endif
      33             : 
      34             : #ifdef B200
      35             : /* einzige Moeglichkeit unter BC Stack und Heap festzusetzen */
      36             : extern unsigned _stklen  = 24000;
      37             : extern unsigned _heaplen = 30000;
      38             : #endif
      39             : 
      40             : 
      41             : 
      42             : /*
      43             :  * Commonly used global variables:
      44             :  * line         is the current input line number.
      45             :  * wrongline    is set in many places when the actual output
      46             :  *              line is out of sync with the numbering, e.g,
      47             :  *              when expanding a macro with an embedded newline.
      48             :  *
      49             :  * token        holds the last identifier scanned (which might
      50             :  *              be a candidate for macro expansion).
      51             :  * errors       is the running cpp error counter.
      52             :  * infile       is the head of a linked list of input files (extended by
      53             :  *              #include and macros being expanded).  infile always points
      54             :  *              to the current file/macro.  infile->parent to the includer,
      55             :  *              etc.  infile->fd is NULL if this input stream is a macro.
      56             :  */
      57             : int line;                   /* Current line number          */
      58             : int wrongline;              /* Force #line to compiler      */
      59             : char token[IDMAX + 1];      /* Current input token          */
      60             : int errors;                 /* cpp error counter            */
      61             : FILEINFO* infile = NULL;    /* Current input file           */
      62             : #if OSL_DEBUG_LEVEL > 1
      63             : int debug;                  /* TRUE if debugging now        */
      64             : int bDumpDefs;              /* TRUE if #define's dump req.  */
      65             : #ifdef EVALDEFS
      66             : int bIsInEval;              /* TRUE if #define eval now     */
      67             : char EvalBuf[NEVALBUF + 1]; /* evaluation buffer            */
      68             : int nEvalOff = 0;           /* offset to free buffer pos    */
      69             : #endif
      70             : #endif
      71             : /*
      72             :  * This counter is incremented when a macro expansion is initiated.
      73             :  * If it exceeds a built-in value, the expansion stops -- this tests
      74             :  * for a runaway condition:
      75             :  *      #define X Y
      76             :  *      #define Y X
      77             :  *      X
      78             :  * This can be disabled by falsifying rec_recover.  (Nothing does this
      79             :  * currently: it is a hook for an eventual invocation flag.)
      80             :  */
      81             : int recursion;              /* Infinite recursion counter   */
      82             : int rec_recover = TRUE;     /* Unwind recursive macros      */
      83             : 
      84             : /*
      85             :  * instring is set TRUE when a string is scanned.  It modifies the
      86             :  * behavior of the "get next character" routine, causing all characters
      87             :  * to be passed to the caller (except <DEF_MAGIC>).  Note especially that
      88             :  * comments and \<newline> are not removed from the source.  (This
      89             :  * prevents cpp output lines from being arbitrarily long).
      90             :  *
      91             :  * inmacro is set by #define -- it absorbs comments and converts
      92             :  * form-feed and vertical-tab to space, but returns \<newline>
      93             :  * to the caller.  Strictly speaking, this is a bug as \<newline>
      94             :  * shouldn't delimit tokens, but we'll worry about that some other
      95             :  * time -- it is more important to prevent infinitly long output lines.
      96             :  *
      97             :  * instring and inmarcor are parameters to the get() routine which
      98             :  * were made global for speed.
      99             :  */
     100             : int instring = FALSE;       /* TRUE if scanning string      */
     101             : int inmacro = FALSE;        /* TRUE if #defining a macro    */
     102             : 
     103             : /*
     104             :  * work[] and workp are used to store one piece of text in a temporay
     105             :  * buffer.  To initialize storage, set workp = work.  To store one
     106             :  * character, call save(c);  (This will fatally exit if there isn't
     107             :  * room.)  To terminate the string, call save(EOS).  Note that
     108             :  * the work buffer is used by several subroutines -- be sure your
     109             :  * data won't be overwritten.  The extra byte in the allocation is
     110             :  * needed for string formal replacement.
     111             :  */
     112             : char work[NWORK + 1];        /* Work buffer                  */
     113             : char* workp;                 /* Work buffer pointer          */
     114             : 
     115             : /*
     116             :  * keepcomments is set TRUE by the -C option.  If TRUE, comments
     117             :  * are written directly to the output stream.  This is needed if
     118             :  * the output from cpp is to be passed to lint (which uses commands
     119             :  * embedded in comments).  cflag contains the permanent state of the
     120             :  * -C flag.  keepcomments is always falsified when processing #control
     121             :  * commands and when compilation is suppressed by a false #if
     122             :  *
     123             :  * If eflag is set, CPP returns "success" even if non-fatal errors
     124             :  * were detected.
     125             :  *
     126             :  * If nflag is non-zero, no symbols are predefined except __LINE__.
     127             :  * __FILE__, and __DATE__.  If nflag > 1, absolutely no symbols
     128             :  * are predefined.
     129             :  */
     130             : int keepcomments = FALSE;   /* Write out comments flag      */
     131             : int cflag = FALSE;          /* -C option (keep comments)    */
     132             : int eflag = FALSE;          /* -E option (never fail)       */
     133             : int nflag = 0;              /* -N option (no predefines)    */
     134             : 
     135             : /*
     136             :  * ifstack[] holds information about nested #if's.  It is always
     137             :  * accessed via *ifptr.  The information is as follows:
     138             :  *      WAS_COMPILING   state of compiling flag at outer level.
     139             :  *      ELSE_SEEN       set TRUE when #else seen to prevent 2nd #else.
     140             :  *      TRUE_SEEN       set TRUE when #if or #elif succeeds
     141             :  * ifstack[0] holds the compiling flag.  It is TRUE if compilation
     142             :  * is currently enabled.  Note that this must be initialized TRUE.
     143             :  */
     144             : char ifstack[BLK_NEST] = { TRUE };   /* #if information      */
     145             : char* ifptr = ifstack;               /* -> current ifstack[] */
     146             : 
     147             : /*
     148             :  * incdir[] stores the -i directories (and the system-specific
     149             :  * #include <...> directories.
     150             :  */
     151             : char* incdir[NINCLUDE];              /* -i directories               */
     152             : char** incend = incdir;              /* -> free space in incdir[]    */
     153             : 
     154             : /*
     155             :  * This is the table used to predefine target machine and operating
     156             :  * system designators.  It may need hacking for specific circumstances.
     157             :  * Note: it is not clear that this is part of the Ansi Standard.
     158             :  * The -N option suppresses preset definitions.
     159             :  */
     160             : char* preset[] =
     161             : {                   /* names defined at cpp start   */
     162             : #ifdef  MACHINE
     163             :         MACHINE,
     164             : #endif
     165             : #ifdef  SYSTEM
     166             :         SYSTEM,
     167             : #endif
     168             : #ifdef  COMPILER
     169             :         COMPILER,
     170             : #endif
     171             : #if OSL_DEBUG_LEVEL > 1
     172             :         "decus_cpp",                    /* Ourselves!                   */
     173             : #endif
     174             :         NULL                            /* Must be last                 */
     175             : };
     176             : 
     177             : /*
     178             :  * The value of these predefined symbols must be recomputed whenever
     179             :  * they are evaluated.  The order must not be changed.
     180             :  */
     181             : char* magic[] =
     182             : {                    /* Note: order is important     */
     183             :         "__LINE__",
     184             :         "__FILE__",
     185             :         NULL                            /* Must be last                 */
     186             : };
     187             : 
     188             : static char* sharpfilename = NULL;
     189             : 
     190             : int nRunde = 0;
     191             : 
     192         363 : void InitCpp1()
     193             : {
     194             :     int i;
     195             :     /* in der LIB-Version muessen alle Variablen initialisiert werden */
     196             : 
     197         363 :     line = wrongline = errors = recursion = 0;
     198       46464 :     for( i = 0; i < IDMAX; i++ )
     199       46101 :         token[ i ] = 0;
     200             : 
     201    46464363 :     for( i = 0; i < NWORK; i++ )
     202    46464000 :         work[ i ] = 0;
     203             : 
     204       36663 :     for( i = 0; i < NINCLUDE; i++ )
     205       36300 :         incdir[ i ] = NULL;
     206             : 
     207         363 :     workp = NULL;
     208       11979 :     for( i = 0; i < BLK_NEST; i++ )
     209       11616 :         ifstack[ i ] = TRUE;
     210         363 :     ifptr = ifstack;
     211             : 
     212         363 :     pCppOut = stdout;
     213         363 :     pCppIn  = stdin;
     214             : #if OSL_DEBUG_LEVEL > 1
     215             :     debug = 0;
     216             :     bDumpDefs = 0;
     217             :     pDefOut = stdout;
     218             : #ifdef EVALDEFS
     219             :     bIsInEval = 0;
     220             :     for( i = 0; i < NEVALBUF; i++ )
     221             :         EvalBuf[ i ] = 0;
     222             :     nEvalOff = 0;
     223             : #endif
     224             : #endif
     225         363 :     rec_recover = TRUE;
     226         363 :     infile = NULL;
     227         363 :     instring = inmacro = keepcomments = cflag = eflag = FALSE;
     228         363 :     nflag = 0;
     229         363 :     incend = incdir;
     230         363 :     sharpfilename = NULL;
     231         363 : }
     232             : 
     233         363 : int MAIN(int argc, char** argv)
     234             : {
     235             :     int    i;
     236         363 :     char** useargv = 0;
     237         363 :     char** pfargv = NULL;
     238             : 
     239         363 :     if( nRunde == 0 )
     240             :     {
     241         363 :         pCppIn = stdin;
     242         363 :         pCppOut = stdout;
     243             :     }
     244             : 
     245         363 :     nRunde++;
     246         363 :     InitCpp1();
     247         363 :     InitCpp2();
     248         363 :     InitCpp3();
     249         363 :     InitCpp4();
     250         363 :     InitCpp5();
     251         363 :     InitCpp6();
     252             : 
     253         363 :     initdefines();                          /* O.S. specific def's  */
     254         363 :     if ( argv[argc-1][0] == '@' )
     255             :     {
     256         363 :         i = readoptions( argv[1], &pfargv );    /* Command file */
     257         363 :         useargv=pfargv;
     258             :     }
     259             :     else
     260             :     {
     261           0 :         i = dooptions(argc, argv);              /* Command line -flags  */
     262           0 :         useargv=argv;
     263             :     }
     264         363 :     switch (i)
     265             :     {
     266             : #if OSL_DEBUG_LEVEL > 1
     267             :     case 4:
     268             :         if ( bDumpDefs )
     269             :         {
     270             :             /*
     271             :              * Get defBase file, "-" means use stdout.
     272             :              */
     273             :             if (!streq(useargv[3], "-"))
     274             :             {
     275             :                 pDefOut = fopen( useargv[3], "w" );
     276             :                 if( pDefOut == NULL )
     277             :                 {
     278             :                     perror(useargv[3]);
     279             :                     cerror("Can't open output file \"%s\"", useargv[3]);
     280             :                     exit(IO_ERROR);
     281             :                 }
     282             :             }                           /* Continue by opening output    */
     283             :         }
     284             : #endif
     285             :     case 3:
     286             :         /*
     287             :          * Get output file, "-" means use stdout.
     288             :          */
     289         363 :         if (!streq(useargv[2], "-"))
     290             :         {
     291         363 :             pCppOut = fopen( useargv[2], "w" );
     292         363 :             if( pCppOut == NULL )
     293             :             {
     294           0 :                 perror(useargv[2]);
     295           0 :                 cerror("Can't open output file \"%s\"", useargv[2]);
     296           0 :                 exit(IO_ERROR);
     297             :             }
     298             :         }                           /* Continue by opening input    */
     299             :     case 2:                         /* One file -> stdin            */
     300             :         /*
     301             :          * Open input file, "-" means use stdin.
     302             :          */
     303         363 :         if (!streq(useargv[1], "-"))
     304             :         {
     305         363 :             pCppIn = fopen( useargv[1], "r" );
     306         363 :             if( pCppIn == NULL)
     307             :             {
     308           0 :                 perror(useargv[1]);
     309           0 :                 cerror("Can't open input file \"%s\"", useargv[1]);
     310           0 :                 exit(IO_ERROR);
     311             :             }
     312         363 :             strncpy(work, useargv[1], NWORK);  /* Remember input filename      */
     313         363 :             break;
     314             :         }                           /* Else, just get stdin         */
     315             :     case 0:                         /* No args?                     */
     316             :     case 1:                         /* No files, stdin -> stdout    */
     317           0 :         work[0] = EOS;              /* Unix can't find stdin name   */
     318           0 :         break;
     319             : 
     320             :     default:
     321           0 :         exit(IO_ERROR);             /* Can't happen                 */
     322             :     }
     323             : 
     324         363 :     setincdirs();                   /* Setup -I include directories */
     325         363 :     addfile( pCppIn, work);           /* "open" main input file       */
     326             : #if OSL_DEBUG_LEVEL > 1
     327             :     if (debug > 0 || bDumpDefs)
     328             :         dumpdef("preset #define symbols");
     329             : #endif
     330         363 :     if( pCppIn != stdin )
     331         363 :         rewind( pCppIn );
     332             : 
     333         363 :     cppmain();                      /* Process main file            */
     334             : 
     335         363 :     if ((i = (ifptr - &ifstack[0])) != 0)
     336             :     {
     337           0 :         cierror("Inside #ifdef block at end of input, depth = %d", i);
     338             :     }
     339             : #if OSL_DEBUG_LEVEL > 1
     340             :     if( pDefOut != stdout && pDefOut != stderr )
     341             :         fclose( pDefOut );
     342             : #endif
     343         363 :     if( pCppOut != stdout && pCppOut != stderr )
     344         363 :         fclose( pCppOut );
     345             : 
     346         363 :     if (errors > 0)
     347             :     {
     348           0 :         fprintf(stderr, (errors == 1)
     349             :                 ? "%d error in preprocessor\n"
     350             :                 : "%d errors in preprocessor\n", errors);
     351           0 :         if (!eflag)
     352           0 :             exit(IO_ERROR);
     353             :     }
     354         363 :     if( pfargv )
     355         363 :         free(pfargv);
     356         363 :     return( IO_NORMAL );
     357             : 
     358             : }
     359             : 
     360             : /*
     361             :  * Main process for cpp -- copies tokens from the current input
     362             :  * stream (main file, include file, or a macro) to the output
     363             :  * file.
     364             :  */
     365         363 : void cppmain()
     366             : {
     367             :     int c;              /* Current character    */
     368             :     int counter;        /* newlines and spaces  */
     369             : 
     370             :     /*
     371             :      * Explicitly output a #line at the start of cpp output so
     372             :      * that lint (etc.) knows the name of the original source
     373             :      * file.  If we don't do this explicitly, we may get
     374             :      * the name of the first #include file instead.
     375             :      * We also seem to need a blank line following that first #line.
     376             :      */
     377             : #ifdef EVALDEFS
     378             :     if ( !bIsInEval )
     379             : #endif
     380             :     {
     381         363 :         sharp();
     382         363 :         PUTCHAR('\n');
     383             :     }
     384             :     /*
     385             :      * This loop is started "from the top" at the beginning of each line
     386             :      * wrongline is set TRUE in many places if it is necessary to write
     387             :      * a #line record.  (But we don't write them when expanding macros.)
     388             :      *
     389             :      * The counter variable has two different uses:  at
     390             :      * the start of a line, it counts the number of blank lines that
     391             :      * have been skipped over.  These are then either output via
     392             :      * #line records or by outputting explicit blank lines.
     393             :      * When expanding tokens within a line, the counter remembers
     394             :      * whether a blank/tab has been output.  These are dropped
     395             :      * at the end of the line, and replaced by a single blank
     396             :      * within lines.
     397             :      */
     398             :     for (;;)
     399             :     {
     400       78948 :         counter = 0;                        /* Count empty lines    */
     401             :         for (;;)
     402             :         {                                   /* For each line, ...   */
     403     1127975 :             while (type[(c = get())] == SPA) /* Skip leading blanks */
     404             :                 ;                           /* in this line.        */
     405     1127975 :             if (c == '\n')                  /* If line's all blank, */
     406      317915 :                 ++counter;                  /* Do nothing now       */
     407      810060 :             else if (c == '#')
     408             :             {            /* Is 1st non-space '#' */
     409      730701 :                 keepcomments = FALSE;       /* Don't pass comments  */
     410      730701 :                 counter = control(counter); /* Yes, do a #command   */
     411      730701 :                 keepcomments = (cflag && compiling);
     412             :             }
     413       79359 :             else if (c == EOF_CHAR)         /* At end of file?      */
     414             :             {
     415         363 :                 break;
     416             :             }
     417       78996 :             else if (!compiling)
     418             :             {                               /* #ifdef false?        */
     419         411 :                 skipnl();                   /* Skip to newline      */
     420         411 :                 counter++;                  /* Count it, too.       */
     421             :             }
     422             :             else
     423             :             {
     424       78585 :                 break;                      /* Actual token         */
     425             :             }
     426     1049027 :         }
     427       78948 :         if (c == EOF_CHAR)                  /* Exit process at      */
     428         363 :             break;                          /* End of file          */
     429             :         /*
     430             :          * If the loop didn't terminate because of end of file, we
     431             :          * know there is a token to compile.  First, clean up after
     432             :          * absorbing newlines.  counter has the number we skipped.
     433             :          */
     434       78585 :         if ((wrongline && infile->fp != NULL) || counter > 4)
     435        1504 :             sharp();                        /* Output # line number */
     436             :         else
     437             :         {                                   /* If just a few, stuff */
     438      161289 :             while (--counter >= 0)          /* them out ourselves   */
     439        7127 :                 PUTCHAR('\n');
     440             :         }
     441             :         /*
     442             :          * Process each token on this line.
     443             :          */
     444       78585 :         unget();                            /* Reread the char.     */
     445             :         for (;;)
     446             :         {                                   /* For the whole line,  */
     447             :             do
     448             :             {                            /* Token concat. loop   */
     449     1373238 :                 for (counter = 0; type[(c = get())] == SPA;)
     450             :                 {
     451      249496 :                     counter++;              /* Skip over blanks     */
     452             : 
     453             :                 }
     454      561871 :                 if (c == EOF_CHAR || c == '\n')
     455             :                     goto end_line;          /* Exit line loop       */
     456      483286 :                 else if (counter > 0)       /* If we got any spaces */
     457      230407 :                     PUTCHAR(' ');           /* Output one space     */
     458      483286 :                 c = macroid(c);             /* Grab the token       */
     459             :             }
     460      483286 :             while (type[c] == LET && catenate());
     461             : 
     462      483286 :             if (c == EOF_CHAR || c == '\n') /* From macro exp error */
     463             :                 goto end_line;              /* Exit line loop       */
     464             : 
     465      483286 :             switch (type[c])
     466             :             {
     467             :             case LET:
     468       87742 :                 fputs(token, pCppOut);       /* Quite ordinary token */
     469             : #ifdef EVALDEFS
     470             :                 {
     471             :                     int len;
     472             :                     if ( bIsInEval
     473             :                          && nEvalOff + (len=strlen(token)) < NEVALBUF )
     474             :                     {
     475             :                         strcpy( &EvalBuf[nEvalOff], token );
     476             :                         nEvalOff += len;
     477             :                     }
     478             :                 }
     479             : #endif
     480       87742 :                 break;
     481             : 
     482             : 
     483             :             case DIG:                       /* Output a number      */
     484             :             case DOT:                       /* Dot may begin floats */
     485             : #ifdef EVALDEFS
     486             :                 if ( bIsInEval )
     487             :                     scannumber(c, outputEval);
     488             :                 else
     489             :                     scannumber(c, output);
     490             : #else
     491       62505 :                 scannumber(c, output);
     492             : #endif
     493       62505 :                 break;
     494             : 
     495             :             case QUO:                       /* char or string const */
     496       24441 :                 scanstring(c, output);      /* Copy it to output    */
     497       24441 :                 break;
     498             : 
     499             :             default:                        /* Some other character */
     500      308598 :                 cput(c);                    /* Just output it       */
     501             : #ifdef EVALDEFS
     502             :                 if ( bIsInEval && nEvalOff < NEVALBUF )
     503             :                     EvalBuf[nEvalOff++] = c;
     504             : #endif
     505      308598 :                 break;
     506             :             }                               /* Switch ends          */
     507      483286 :         }                                   /* Line for loop        */
     508             :       end_line:
     509       78585 :         if (c == '\n')
     510             :         {                                   /* Compiling at EOL?    */
     511       78585 :             PUTCHAR('\n');                  /* Output newline, if   */
     512       78585 :             if (infile->fp == NULL)         /* Expanding a macro,   */
     513           0 :                 wrongline = TRUE;           /* Output # line later  */
     514             :         }
     515       78585 :     }                                       /* Continue until EOF   */
     516             : #ifdef EVALDEFS
     517             :     if ( bIsInEval )
     518             :         EvalBuf[nEvalOff++] = '\0';
     519             : #endif
     520         363 : }
     521             : 
     522             : /*
     523             :  * Output one character to stdout -- output() is passed as an
     524             :  * argument to scanstring()
     525             :  */
     526      708104 : void output(int c)
     527             : {
     528      708104 :     if (c != TOK_SEP)
     529      708104 :         PUTCHAR(c);
     530      708104 : }
     531             : 
     532             : #ifdef EVALDEFS
     533             : /*
     534             :  * Output one character to stdout -- output() is passed as an
     535             :  * argument to scanstring()
     536             :  */
     537             : int outputEval(int c)
     538             : {
     539             :     if (c != TOK_SEP)
     540             :     {
     541             :         PUTCHAR(c);
     542             :         if ( bIsInEval && nEvalOff < NEVALBUF )
     543             :             EvalBuf[nEvalOff++] = c;
     544             :     }
     545             : }
     546             : #endif
     547             : 
     548             : 
     549             : /*
     550             :  * Output a line number line.
     551             :  */
     552        1867 : void sharp()
     553             : {
     554             :     char* name;
     555             : 
     556        1867 :     if (keepcomments)                       /* Make sure # comes on */
     557           0 :         PUTCHAR('\n');                      /* a fresh, new line.   */
     558             : 
     559        1867 :     fprintf( pCppOut, "#%s %d", LINE_PREFIX, line);
     560        1867 :     if (infile->fp != NULL)
     561             :     {
     562        1867 :         name = (infile->progname != NULL) ? infile->progname : infile->filename;
     563        3371 :         if (sharpfilename == NULL ||
     564        3008 :             (sharpfilename != NULL && !streq(name, sharpfilename)))
     565             :         {
     566         365 :             if (sharpfilename != NULL)
     567           2 :                 free(sharpfilename);
     568         365 :             sharpfilename = savestring(name);
     569         365 :             fprintf( pCppOut, " \"%s\"", name);
     570             :         }
     571             :     }
     572        1867 :     PUTCHAR('\n');
     573        1867 :     wrongline = FALSE;
     574        1867 : }
     575             : 
     576             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10