LCOV - code coverage report
Current view: top level - rsc/source/rscpp - cpp6.c (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 250 369 67.8 %
Date: 2015-06-13 12:38:46 Functions: 17 24 70.8 %
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             : #include <sal/types.h>
      21             : #include <stdio.h>
      22             : #include <ctype.h>
      23             : #include <string.h>
      24             : #include "cppdef.h"
      25             : #include "cpp.h"
      26             : 
      27             : /*ER evaluate macros to pDefOut */
      28             : 
      29             : /*
      30             :  * skipnl()     skips over input text to the end of the line.
      31             :  * skipws()     skips over "whitespace" (spaces or tabs), but
      32             :  *              not skip over the end of the line.  It skips over
      33             :  *              TOK_SEP, however (though that shouldn't happen).
      34             :  * scanid()     reads the next token (C identifier) into token[].
      35             :  *              The caller has already read the first character of
      36             :  *              the identifier.  Unlike macroid(), the token is
      37             :  *              never expanded.
      38             :  * macroid()    reads the next token (C identifier) into token[].
      39             :  *              If it is a #defined macro, it is expanded, and
      40             :  *              macroid() returns TRUE, otherwise, FALSE.
      41             :  * catenate()   Does the dirty work of token concatenation, TRUE if it did.
      42             :  * scanstring() Reads a string from the input stream, calling
      43             :  *              a user-supplied function for each character.
      44             :  *              This function may be output() to write the
      45             :  *              string to the output file, or save() to save
      46             :  *              the string in the work buffer.
      47             :  * scannumber() Reads a C numeric constant from the input stream,
      48             :  *              calling the user-supplied function for each
      49             :  *              character.  (output() or save() as noted above.)
      50             :  * save()       Save one character in the work[] buffer.
      51             :  * savestring() Saves a string in malloc() memory.
      52             :  * getfile()    Initialize a new FILEINFO structure, called when
      53             :  *              #include opens a new file, or a macro is to be
      54             :  *              expanded.
      55             :  * getmem()     Get a specified number of bytes from malloc memory.
      56             :  * output()     Write one character to stdout (calling PUTCHAR) --
      57             :  *              implemented as a function so its address may be
      58             :  *              passed to scanstring() and scannumber().
      59             :  * lookid()     Scans the next token (identifier) from the input
      60             :  *              stream.  Looks for it in the #defined symbol table.
      61             :  *              Returns a pointer to the definition, if found, or NULL
      62             :  *              if not present.  The identifier is stored in token[].
      63             :  * defnedel()   Define enter/delete subroutine.  Updates the
      64             :  *              symbol table.
      65             :  * get()        Read the next byte from the current input stream,
      66             :  *              handling end of (macro/file) input and embedded
      67             :  *              comments appropriately.  Note that the global
      68             :  *              instring is -- essentially -- a parameter to get().
      69             :  * cget()       Like get(), but skip over TOK_SEP.
      70             :  * unget()      Push last gotten character back on the input stream.
      71             :  * cerror(), cwarn(), cfatal(), cierror(), ciwarn()
      72             :  *              These routines format an print messages to the user.
      73             :  *              cerror & cwarn take a format and a single string argument.
      74             :  *              cierror & ciwarn take a format and a single int (char) argument.
      75             :  *              cfatal takes a format and a single string argument.
      76             :  */
      77             : 
      78             : /*
      79             :  * This table must be rewritten for a non-Ascii machine.
      80             :  *
      81             :  * Note that several "non-visible" characters have special meaning:
      82             :  * Hex 1D DEF_MAGIC -- a flag to prevent #define recursion.
      83             :  * Hex 1E TOK_SEP   -- a delimiter for token concatenation
      84             :  * Hex 1F COM_SEP   -- a zero-width whitespace for comment concatenation
      85             :  */
      86             : #if TOK_SEP != 0x1E || COM_SEP != 0x1F || DEF_MAGIC != 0x1D
      87             :         << error type table is not correct >>
      88             : #endif
      89             : 
      90             : #define DOL     LET
      91             : 
      92             : 
      93             : char type[256] = {              /* Character type codes    Hex          */
      94             :    END,   000,   000,   000,   000,   000,   000,   000, /* 00          */
      95             :    000,   SPA,   000,   000,   000,   000,   000,   000, /* 08          */
      96             :    000,   000,   000,   000,   000,   000,   000,   000, /* 10          */
      97             :    000,   000,   000,   000,   000,   LET,   000,   SPA, /* 18          */
      98             :    SPA,OP_NOT,   QUO,   000,   DOL,OP_MOD,OP_AND,   QUO, /* 20  !"#$%&' */
      99             : OP_LPA,OP_RPA,OP_MUL,OP_ADD,   000,OP_SUB,   DOT,OP_DIV, /* 28 ()*+,-./ */
     100             :    DIG,   DIG,   DIG,   DIG,   DIG,   DIG,   DIG,   DIG, /* 30 01234567 */
     101             :    DIG,   DIG,OP_COL,   000, OP_LT, OP_EQ, OP_GT,OP_QUE, /* 38 89:;<=>? */
     102             :    000,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 40 @ABCDEFG */
     103             :    LET,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 48 HIJKLMNO */
     104             :    LET,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 50 PQRSTUVW */
     105             :    LET,   LET,   LET,   000,   BSH,   000,OP_XOR,   LET, /* 58 XYZ[\]^_ */
     106             :    000,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 60 `abcdefg */
     107             :    LET,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 68 hijklmno */
     108             :    LET,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 70 pqrstuvw */
     109             :    LET,   LET,   LET,   000, OP_OR,   000,OP_NOT,   000, /* 78 xyz{|}~  */
     110             :    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF  */
     111             :    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF  */
     112             :    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF  */
     113             :    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF  */
     114             :    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF  */
     115             :    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF  */
     116             :    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF  */
     117             :    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF  */
     118             : };
     119             : 
     120             : 
     121             : /*
     122             :  *                      C P P   S y m b o l   T a b l e s
     123             :  */
     124             : 
     125             : /*
     126             :  * SBSIZE defines the number of hash-table slots for the symbol table.
     127             :  * It must be a power of 2.
     128             :  */
     129             : #ifndef SBSIZE
     130             : #define SBSIZE  64
     131             : #endif
     132             : #define SBMASK  (SBSIZE - 1)
     133             : #if (SBSIZE ^ SBMASK) != ((SBSIZE * 2) - 1)
     134             :         << error, SBSIZE must be a power of 2 >>
     135             : #endif
     136             : 
     137             : 
     138             : static DEFBUF   *symtab[SBSIZE];        /* Symbol table queue headers   */
     139             : 
     140         361 : void InitCpp6()
     141             : {
     142             :     int i;
     143       23465 :     for( i = 0; i < SBSIZE; i++ )
     144       23104 :         symtab[ i ] = NULL;
     145         361 : }
     146             : 
     147             : 
     148             : 
     149             : /*
     150             :  * Skip to the end of the current input line.
     151             :  */
     152    11637954 : void skipnl()
     153             : {
     154             :     int c;
     155             : 
     156             :     do
     157             :     {                            /* Skip to newline      */
     158    11637954 :         c = get();
     159             :     }
     160    11637954 :     while (c != '\n' && c != EOF_CHAR);
     161      210568 : }
     162             : 
     163             : /*
     164             :  * Skip over whitespace
     165             :  */
     166    11063651 : int skipws()
     167             : {
     168             :     int            c;
     169             : 
     170             :     do {                            /* Skip whitespace      */
     171    11063651 :         c = get();
     172    11063651 :     } while (type[c] == SPA);
     173     2207295 :     return c;
     174             : }
     175             : 
     176             : /*
     177             :  * Get the next token (an id) into the token buffer.
     178             :  * Note: this code is duplicated in lookid().
     179             :  * Change one, change both.
     180             :  */
     181     1132153 : void scanid(int c)
     182             : {
     183             :     char* bp;
     184             : 
     185     1132153 :     if (c == DEF_MAGIC)                     /* Eat the magic token  */
     186           0 :         c = get();                          /* undefiner.           */
     187     1132153 :     bp = token;
     188             :     do
     189             :     {
     190    10023767 :         if (bp < &token[IDMAX])             /* token dim is IDMAX+1 */
     191    10023767 :             *bp++ = (char)c;
     192    10023767 :         c = get();
     193             :     }
     194    10023767 :     while (type[c] == LET || type[c] == DIG);
     195     1132153 :     unget();
     196     1132153 :     *bp = EOS;
     197     1132153 : }
     198             : 
     199             : /*
     200             :  * If c is a letter, scan the id.  if it's #defined, expand it and scan
     201             :  * the next character and try again.
     202             :  *
     203             :  * Else, return the character.  If type[c] is a LET, the token is in token.
     204             :  */
     205      476582 : int macroid(int c)
     206             : {
     207             :     DEFBUF* dp;
     208             : 
     209      476582 :     if (infile != NULL && infile->fp != NULL)
     210      270197 :         recursion = 0;
     211     1031734 :     while (type[c] == LET && (dp = lookid(c)) != NULL)
     212             :     {
     213       78570 :         expand(dp);
     214       78570 :         c = get();
     215             :     }
     216      476582 :     return c;
     217             : }
     218             : 
     219             : /*
     220             :  * A token was just read (via macroid).
     221             :  * If the next character is TOK_SEP, concatenate the next token
     222             :  * return TRUE -- which should recall macroid after refreshing
     223             :  * macroid's argument.  If it is not TOK_SEP, unget() the character
     224             :  * and return FALSE.
     225             :  */
     226       82878 : int catenate()
     227             : {
     228             :     int c;
     229             :     char* token1;
     230             : 
     231       82878 :     if (get() != TOK_SEP)                   /* Token concatenation  */
     232             :     {
     233       82878 :         unget();
     234       82878 :         return FALSE;
     235             :     }
     236             :     else
     237             :     {
     238           0 :         token1 = savestring(token);         /* Save first token     */
     239           0 :         c = macroid(get());                 /* Scan next token      */
     240           0 :         switch(type[c])                     /* What was it?         */
     241             :         {
     242             :         case LET:                           /* An identifier, ...   */
     243           0 :             if (strlen(token1) + strlen(token) >= NWORK)
     244           0 :                 cfatal("work buffer overflow doing %s #", token1);
     245           0 :             sprintf(work, "%s%s", token1, token);
     246           0 :             break;
     247             : 
     248             :         case DIG:                           /* A digit string       */
     249           0 :             strcpy(work, token1);
     250           0 :             workp = work + strlen(work);
     251             :             do
     252             :             {
     253           0 :                 save(c);
     254             :             }
     255           0 :             while ((c = get()) != TOK_SEP);
     256             :             /*
     257             :              * The trailing TOK_SEP is no longer needed.
     258             :              */
     259           0 :             save(EOS);
     260           0 :             break;
     261             : 
     262             :         default:                            /* An error, ...        */
     263           0 :             if (isprint(c))
     264           0 :                 cierror("Strange character '%c' after #", c);
     265             :             else
     266           0 :                 cierror("Strange character (%d.) after #", c);
     267           0 :             strcpy(work, token1);
     268           0 :             unget();
     269           0 :             break;
     270             :         }
     271             :         /*
     272             :          * work has the concatenated token and token1 has
     273             :          * the first token (no longer needed).  Unget the
     274             :          * new (concatenated) token after freeing token1.
     275             :          * Finally, setup to read the new token.
     276             :          */
     277           0 :         free(token1);                       /* Free up memory       */
     278           0 :         ungetstring(work);                  /* Unget the new thing, */
     279           0 :         return TRUE;
     280             :     }
     281             : }
     282             : 
     283             : /*
     284             :  * Scan off a string.  Warning if terminated by newline or EOF.
     285             :  * outfun() outputs the character -- to a buffer if in a macro.
     286             :  * TRUE if ok, FALSE if error.
     287             :  */
     288       74054 : int scanstring(int delim,
     289             : #ifndef _NO_PROTO
     290             :            void (*outfun)( int ) /* BP */    /* Output function              */
     291             : #else
     292             :            void (*outfun)() /* BP */
     293             : #endif
     294             :     )
     295             : {
     296             :     int c;
     297             : 
     298       74054 :     instring = TRUE;                /* Don't strip comments         */
     299       74054 :     (*outfun)(delim);
     300     1640696 :     while ((c = get()) != delim &&
     301     1492588 :            c != '\n' &&
     302             :            c != EOF_CHAR)
     303             :     {
     304     1492588 :         if (c != DEF_MAGIC)
     305     1492588 :             (*outfun)(c);
     306     1492588 :         if (c == '\\')
     307         619 :             (*outfun)(get());
     308             :     }
     309       74054 :     instring = FALSE;
     310       74054 :     if (c == delim)
     311             :     {
     312       74054 :         (*outfun)(c);
     313       74054 :         return TRUE;
     314             :     }
     315             :     else
     316             :     {
     317           0 :         cerror("Unterminated string", NULLST);
     318           0 :         unget();
     319           0 :         return FALSE;
     320             :     }
     321             : }
     322             : 
     323             : /*
     324             :  * Process a number.  We know that c is from 0 to 9 or dot.
     325             :  * Algorithm from Dave Conroy's Decus C.
     326             :  */
     327      485430 : void scannumber(int c,
     328             : #ifndef _NO_PROTO
     329             :                 void (*outfun)( int )  /* BP */    /* Output/store func    */
     330             : #else
     331             :                 void (*outfun)() /* BP */
     332             : #endif
     333             :     )
     334             : {
     335             :     int radix;                              /* 8, 10, or 16         */
     336             :     int expseen;                            /* 'e' seen in floater  */
     337             :     int signseen;                           /* '+' or '-' seen      */
     338             :     int octal89;                            /* For bad octal test   */
     339             :     int dotflag;                            /* TRUE if '.' was seen */
     340             : 
     341      485430 :     expseen = FALSE;                        /* No exponent seen yet */
     342      485430 :     signseen = TRUE;                        /* No +/- allowed yet   */
     343      485430 :     octal89 = FALSE;                        /* No bad octal yet     */
     344      485430 :     radix = 10;                             /* Assume decimal       */
     345      485430 :     if ((dotflag = (c == '.')) != FALSE)    /* . something?         */
     346             :     {
     347           0 :         (*outfun)('.');                     /* Always out the dot   */
     348           0 :         if (type[(c = get())] != DIG)       /* If not a float numb, */
     349             :         {
     350           0 :             unget();                        /* Rescan strange char  */
     351      485430 :             return;                         /* All done for now     */
     352             :         }
     353             :     }                                       /* End of float test    */
     354      485430 :     else if (c == '0')                      /* Octal or hex?        */
     355             :     {
     356       16637 :         (*outfun)(c);                       /* Stuff initial zero   */
     357       16637 :         radix = 8;                          /* Assume it's octal    */
     358       16637 :         c = get();                          /* Look for an 'x'      */
     359       16637 :         if (c == 'x' || c == 'X')           /* Did we get one?      */
     360             :         {
     361       10574 :             radix = 16;                     /* Remember new radix   */
     362       10574 :             (*outfun)(c);                   /* Stuff the 'x'        */
     363       10574 :             c = get();                      /* Get next character   */
     364             :         }
     365             :     }
     366             :     for (;;)                                /* Process curr. char.  */
     367             :     {
     368             :         /*
     369             :          * Note that this algorithm accepts "012e4" and "03.4"
     370             :          * as legitimate floating-point numbers.
     371             :          */
     372     1823957 :         if (radix != 16 && (c == 'e' || c == 'E'))
     373             :         {
     374           0 :             if (expseen)                    /* Already saw 'E'?     */
     375           0 :                 break;                      /* Exit loop, bad nbr.  */
     376           0 :             expseen = TRUE;                 /* Set exponent seen    */
     377           0 :             signseen = FALSE;               /* We can read '+' now  */
     378           0 :             radix = 10;                     /* Decimal exponent     */
     379             :         }
     380     1823957 :         else if (radix != 16 && c == '.')
     381             :         {
     382           0 :             if (dotflag)                    /* Saw dot already?     */
     383           0 :                 break;                      /* Exit loop, two dots  */
     384           0 :             dotflag = TRUE;                 /* Remember the dot     */
     385           0 :             radix = 10;                     /* Decimal fraction     */
     386             :         }
     387     1823957 :         else if (c == '+' || c == '-')      /* 1.0e+10              */
     388             :         {
     389        3858 :             if (signseen)                   /* Sign in wrong place? */
     390        3858 :                 break;                      /* Exit loop, not nbr.  */
     391             :             /* signseen = TRUE; */          /* Remember we saw it   */
     392             :         }
     393             :         else                                /* Check the digit      */
     394             :         {
     395     1820099 :             switch (c)
     396             :             {
     397             :             case '8': case '9':             /* Sometimes wrong      */
     398      179060 :                 octal89 = TRUE;             /* Do check later       */
     399             :             case '0': case '1': case '2': case '3':
     400             :             case '4': case '5': case '6': case '7':
     401     1331323 :                 break;                      /* Always ok            */
     402             : 
     403             :             case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
     404             :             case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
     405        7204 :                 if (radix == 16)            /* Alpha's are ok only  */
     406        7204 :                     break;                  /* if reading hex.      */
     407             :             default:                        /* At number end        */
     408      481572 :                 goto done;                  /* Break from for loop  */
     409             :             }                               /* End of switch        */
     410             :         }                                   /* End general case     */
     411     1338527 :         (*outfun)(c);                       /* Accept the character */
     412     1338527 :         signseen = TRUE;                    /* Don't read sign now  */
     413     1338527 :         c = get();                          /* Read another char    */
     414     1338527 :     }                                       /* End of scan loop     */
     415             :     /*
     416             :      * When we break out of the scan loop, c contains the first
     417             :      * character (maybe) not in the number.  If the number is an
     418             :      * integer, allow a trailing 'L' for long and/or a trailing 'U'
     419             :      * for unsigned.  If not those, push the trailing character back
     420             :      * on the input stream.  Floating point numbers accept a trailing
     421             :      * 'L' for "long double".
     422             :      */
     423             :   done:
     424      485430 :     if (dotflag || expseen)           /* Floating point?      */
     425             :     {
     426           0 :         if (c == 'l' || c == 'L')
     427             :         {
     428           0 :             (*outfun)(c);
     429           0 :             get();                          /* Ungotten later       */
     430             :         }
     431             :     }
     432             :     else                                    /* Else it's an integer */
     433             :     {
     434             :         /*
     435             :          * We know that dotflag and expseen are both zero, now:
     436             :          * dotflag signals "saw 'L'", and
     437             :          * expseen signals "saw 'U'".
     438             :          */
     439             :         for (;;)
     440             :         {
     441      491278 :             switch (c)
     442             :             {
     443             :             case 'l':
     444             :             case 'L':
     445        2924 :                 if (dotflag)
     446           0 :                     goto nomore;
     447        2924 :                 dotflag = TRUE;
     448        2924 :                 break;
     449             : 
     450             :             case 'u':
     451             :             case 'U':
     452        2924 :                 if (expseen)
     453           0 :                     goto nomore;
     454        2924 :                 expseen = TRUE;
     455        2924 :                 break;
     456             : 
     457             :             default:
     458      485430 :                 goto nomore;
     459             :             }
     460        5848 :             (*outfun)(c);                   /* Got 'L' or 'U'.      */
     461        5848 :             c = get();                      /* Look at next, too.   */
     462        5848 :         }
     463             :     }
     464             :   nomore:
     465      485430 :     unget();                                /* Not part of a number */
     466      485430 :     if (octal89 && radix == 8)
     467           0 :         cwarn("Illegal digit in octal number", NULLST);
     468             : }
     469             : 
     470    10293853 : void save(int c)
     471             : {
     472    10293853 :     if (workp >= &work[NWORK])
     473             :     {
     474           0 :         work[NWORK-1] = '\0';
     475           0 :         cfatal("Work buffer overflow:  %s", work);
     476             :     }
     477             :     else
     478    10293853 :         *workp++ = (char)c;
     479    10293853 : }
     480             : 
     481             : /*
     482             :  * Store a string into free memory.
     483             :  */
     484      578598 : char* savestring(char* text)
     485             : {
     486             :     char* result;
     487             : 
     488      578598 :     size_t size = strlen(text) + 1;
     489      578598 :     result = getmem(size);
     490      578598 :     strcpy(result, text);
     491      578598 :     return result;
     492             : }
     493             : 
     494             : /*
     495             :  * Common FILEINFO buffer initialization for a new file or macro.
     496             :  */
     497       83079 : FILEINFO* getfile(size_t bufsize, char* name)
     498             : {
     499             :     FILEINFO* file;
     500             :     size_t size;
     501             : 
     502       83079 :     size = strlen(name);                    /* File/macro name      */
     503       83079 :     file = (FILEINFO*) getmem(sizeof (FILEINFO) + bufsize + size);
     504       83079 :     file->parent = infile;                  /* Chain files together */
     505       83079 :     file->fp = NULL;                        /* No file yet          */
     506       83079 :     file->filename = savestring(name);      /* Save file/macro name */
     507       83079 :     file->progname = NULL;                  /* No #line seen yet    */
     508       83079 :     file->unrecur = 0;                      /* No macro fixup       */
     509       83079 :     file->bptr = file->buffer;              /* Initialize line ptr  */
     510       83079 :     file->buffer[0] = EOS;                  /* Force first read     */
     511       83079 :     file->line = 0;                         /* (Not used just yet)  */
     512       83079 :     if (infile != NULL)                     /* If #include file     */
     513       82718 :         infile->line = line;                /* Save current line    */
     514       83079 :     infile = file;                          /* New current file     */
     515       83079 :     line = 1;                               /* Note first line      */
     516       83079 :     return file;                            /* All done.            */
     517             : }
     518             : 
     519             : /*
     520             :  * Get a block of free memory.
     521             :  */
     522     1146668 : char* getmem(size_t size)
     523             : {
     524             :     char* result;
     525             : 
     526     1146668 :     if ((result = malloc((unsigned) size)) == NULL)
     527           0 :         cfatal("Out of memory", NULLST);
     528     1146668 :     return result;
     529             : }
     530             : 
     531             : /*
     532             :  * Look for the next token in the symbol table.  Returns token in "token".
     533             :  * If found, returns the table pointer;  Else returns NULL.
     534             :  */
     535      654378 : DEFBUF* lookid(int c)
     536             : {
     537             :     int nhash;
     538             :     DEFBUF* dp;
     539             :     char* np;
     540      654378 :     int temp = 0;
     541             :     int isrecurse;      /* For #define foo foo  */
     542             : 
     543      654378 :     np = token;
     544      654378 :     nhash = 0;
     545      654378 :     if (0 != (isrecurse = (c == DEF_MAGIC)))/* If recursive macro   */
     546           0 :         c = get();                          /* hack, skip DEF_MAGIC */
     547             :     do
     548             :     {
     549    11241885 :         if (np < &token[IDMAX])             /* token dim is IDMAX+1 */
     550             :         {
     551    11241885 :             *np++ = (char)c;                /* Store token byte     */
     552    11241885 :             nhash += c;                     /* Update hash value    */
     553             :         }
     554    11241885 :         c = get();                          /* And get another byte */
     555             :     }
     556    11241885 :     while (type[c] == LET || type[c] == DIG);
     557      654378 :     unget();                                /* Rescan terminator    */
     558      654378 :     *np = EOS;                              /* Terminate token      */
     559      654378 :     if (isrecurse)                          /* Recursive definition */
     560           0 :         return NULL;                        /* undefined just now   */
     561      654378 :     nhash += (np - token);                  /* Fix hash value       */
     562      654378 :     dp = symtab[nhash & SBMASK];            /* Starting bucket      */
     563    12675165 :     while (dp != (DEFBUF*) NULL)           /* Search symbol table  */
     564             :     {
     565    12102133 :         if (dp->hash == nhash &&            /* Fast precheck        */
     566      495889 :             (temp = strcmp(dp->name, token)) >= 0)
     567             :         {
     568      239835 :             break;
     569             :         }
     570    11366409 :         dp = dp->link;                      /* Nope, try next one   */
     571             :     }
     572      654378 :     return ((temp == 0) ? dp : NULL);
     573             : }
     574             : 
     575             : /*
     576             :  * Enter this name in the lookup table (delete = FALSE)
     577             :  * or delete this name (delete = TRUE).
     578             :  * Returns a pointer to the define block (delete = FALSE)
     579             :  * Returns NULL if the symbol wasn't defined (delete = TRUE).
     580             :  */
     581      484659 : DEFBUF* defendel(char* name, int delete)
     582             : {
     583             :     DEFBUF* dp;
     584             :     DEFBUF** prevp;
     585             :     char* np;
     586             :     int nhash;
     587      484659 :     int temp=0;
     588             :     int size;
     589             : 
     590    10354261 :     for (nhash = 0, np = name; *np != EOS;)
     591     9384943 :         nhash += *np++;
     592      484659 :     size = (np - name);
     593      484659 :     nhash += size;
     594      484659 :     prevp = &symtab[nhash & SBMASK];
     595     8616363 :     while ((dp = *prevp) != (DEFBUF*) NULL)
     596             :     {
     597     8142666 :         if (dp->hash == nhash &&
     598      350812 :             (temp = strcmp(dp->name, name)) >= 0)
     599             :         {
     600      144809 :             if (temp > 0)
     601      144780 :                 dp = NULL;                  /* Not found            */
     602             :             else
     603             :             {
     604          29 :                 *prevp = dp->link;          /* Found, unlink and    */
     605          29 :                 if (dp->repl != NULL)       /* Free the replacement */
     606          29 :                     free(dp->repl);         /* if any, and then     */
     607          29 :                 free((char*) dp);          /* Free the symbol      */
     608          29 :                 dp = NULL;
     609             :             }
     610      144809 :             break;
     611             :         }
     612     7647045 :         prevp = &dp->link;
     613             :     }
     614      484659 :     if (!delete)
     615             :     {
     616      484630 :         dp = (DEFBUF*) getmem(sizeof (DEFBUF) + size);
     617      484630 :         dp->link = *prevp;
     618      484630 :         *prevp = dp;
     619      484630 :         dp->hash = nhash;
     620      484630 :         dp->repl = NULL;
     621      484630 :         dp->nargs = 0;
     622      484630 :         strcpy(dp->name, name);
     623             :     }
     624      484659 :     return dp;
     625             : }
     626             : 
     627             : #if OSL_DEBUG_LEVEL > 1
     628             : 
     629             : void dumpdef(char* why)
     630             : {
     631             :     DEFBUF* dp;
     632             :     DEFBUF** syp;
     633             :     FILE* pRememberOut = NULL;
     634             : 
     635             :     if ( bDumpDefs )    /*ER */
     636             :     {
     637             :         pRememberOut = pCppOut;
     638             :         pCppOut = pDefOut;
     639             :     }
     640             :     fprintf( pCppOut, "CPP symbol table dump %s\n", why);
     641             :     for (syp = symtab; syp < &symtab[SBSIZE]; syp++)
     642             :     {
     643             :         if ((dp = *syp) != (DEFBUF*) NULL)
     644             :         {
     645             :             fprintf( pCppOut, "symtab[%" SAL_PRI_PTRDIFFT "d]\n", (syp - symtab));
     646             :             do
     647             :             {
     648             :                 dumpadef((char*) NULL, dp);
     649             :             }
     650             :             while ((dp = dp->link) != (DEFBUF*) NULL);
     651             :         }
     652             :     }
     653             :     if ( bDumpDefs )
     654             :     {
     655             :         fprintf( pCppOut, "\n");
     656             :         pCppOut = pRememberOut;
     657             :     }
     658             : }
     659             : 
     660             : void dumpadef(char* why, DEFBUF* dp)
     661             : {
     662             :     char* cp;
     663             :     int c;
     664             :     FILE* pRememberOut = NULL;
     665             : 
     666             : /*ER dump #define's to pDefOut */
     667             :     if ( bDumpDefs )
     668             :     {
     669             :         pRememberOut = pCppOut;
     670             :         pCppOut = pDefOut;
     671             :     }
     672             :     fprintf( pCppOut, " \"%s\" [%d]", dp->name, dp->nargs);
     673             :     if (why != NULL)
     674             :         fprintf( pCppOut, " (%s)", why);
     675             :     if (dp->repl != NULL)
     676             :     {
     677             :         fprintf( pCppOut, " => ");
     678             :         for (cp = dp->repl; (c = *cp++ & 0xFF) != EOS;)
     679             :         {
     680             : #ifdef SOLAR
     681             :             if (c == DEL)
     682             :             {
     683             :                 c = *cp++ & 0xFF;
     684             :                 if( c == EOS ) break;
     685             :                 fprintf( pCppOut, "<%%%d>", c - MAC_PARM);
     686             :             }
     687             : #else
     688             :             if (c >= MAC_PARM && c <= (MAC_PARM + PAR_MAC))
     689             :                 fprintf( pCppOut, "<%%%d>", c - MAC_PARM);
     690             : #endif
     691             :             else if (isprint(c) || c == '\n' || c == '\t')
     692             :                 PUTCHAR(c);
     693             :             else if (c < ' ')
     694             :                 fprintf( pCppOut, "<^%c>", c + '@');
     695             :             else
     696             :                 fprintf( pCppOut, "<\\0%o>", c);
     697             :         }
     698             : /*ER evaluate macros to pDefOut */
     699             : #ifdef EVALDEFS
     700             :         if ( bDumpDefs && !bIsInEval && dp->nargs <= 0 )
     701             :         {
     702             :             FILEINFO* infileSave = infile;
     703             :             char* tokenSave = savestring( token );
     704             :             char* workSave = savestring( work );
     705             :             int lineSave = line;
     706             :             int wronglineSave = wrongline;
     707             :             int recursionSave = recursion;
     708             :             FILEINFO* file;
     709             :             EVALTYPE valEval;
     710             : 
     711             :             bIsInEval = 1;
     712             :             infile = NULL;          /* start from scrap */
     713             :             line = 0;
     714             :             wrongline = 0;
     715             :             *token = EOS;
     716             :             *work = EOS;
     717             :             recursion = 0;
     718             :             file = getfile( strlen( dp->repl ), dp->name );
     719             :             strcpy( file->buffer, dp->repl );
     720             :             fprintf( pCppOut, " ===> ");
     721             :             nEvalOff = 0;
     722             :             cppmain();              /* get() frees also *file */
     723             :             valEval = 0;
     724             :             if ( 0 == evaluate( EvalBuf, &valEval ) )
     725             :             {
     726             : #ifdef EVALFLOATS
     727             :                 if ( valEval != (EVALTYPE)((long)valEval ) )
     728             :                     fprintf( pCppOut, " ==eval=> %f", valEval );
     729             :                 else
     730             : #endif
     731             :                     fprintf( pCppOut, " ==eval=> %ld", (long)valEval );
     732             :             }
     733             :             recursion = recursionSave;
     734             :             wrongline = wronglineSave;
     735             :             line = lineSave;
     736             :             strcpy( work, workSave );
     737             :             free( workSave );
     738             :             strcpy( token, tokenSave );
     739             :             free( tokenSave );
     740             :             infile = infileSave;
     741             :             bIsInEval = 0;
     742             :         }
     743             : #endif
     744             :     }
     745             :     else
     746             :     {
     747             :         fprintf( pCppOut, ", no replacement.");
     748             :     }
     749             :     PUTCHAR('\n');
     750             :     if ( bDumpDefs )
     751             :         pCppOut = pRememberOut;
     752             : }
     753             : #endif
     754             : 
     755             : /*
     756             :  *                      G E T
     757             :  */
     758             : 
     759             : /*
     760             :  * Return the next character from a macro or the current file.
     761             :  * Handle end of file from #include files.
     762             :  */
     763    63745852 : int get()
     764             : {
     765             :     int c;
     766             :     FILEINFO* file;
     767             :     int popped;         /* Recursion fixup      */
     768             : 
     769    63745852 :     popped = 0;
     770             :   get_from_file:
     771    63828570 :     if ((file = infile) == NULL)
     772           0 :         return EOF_CHAR;
     773             :   newline:
     774             : 
     775             :     /*
     776             :      * Read a character from the current input line or macro.
     777             :      * At EOS, either finish the current macro (freeing temp.
     778             :      * storage) or read another line from the current input file.
     779             :      * At EOF, exit the current file (#include) or, at EOF from
     780             :      * the cpp input file, return EOF_CHAR to finish processing.
     781             :      */
     782    65068365 :     if ((c = *file->bptr++ & 0xFF) == EOS)
     783             :     {
     784             :         /*
     785             :          * Nothing in current line or macro.  Get next line (if
     786             :          * input from a file), or do end of file/macro processing.
     787             :          * In the latter case, jump back to restart from the top.
     788             :          */
     789     1282660 :         if (file->fp == NULL)               /* NULL if macro        */
     790             :         {
     791       78570 :             popped++;
     792       78570 :             recursion -= file->unrecur;
     793       78570 :             if (recursion < 0)
     794           0 :                 recursion = 0;
     795       78570 :             infile = file->parent;          /* Unwind file chain    */
     796             :         }
     797             :         else                                /* Else get from a file */
     798             :         {
     799     1204090 :             if ((file->bptr = fgets(file->buffer, NBUFF, file->fp)) != NULL)
     800             :             {
     801             : #if OSL_DEBUG_LEVEL > 1
     802             :                 if (debug > 1)              /* Dump it to stdout    */
     803             :                 {
     804             :                     fprintf( pCppOut, "\n#line %d (%s), %s",
     805             :                              line, file->filename, file->buffer);
     806             :                 }
     807             : #endif
     808     1199581 :                 goto newline;               /* process the line     */
     809             :             }
     810             :             else
     811             :             {
     812        4509 :                 if( file->fp != stdin )
     813        4509 :                     fclose(file->fp);           /* Close finished file  */
     814        4509 :                 if ((infile = file->parent) != NULL)
     815             :                 {
     816             :                     /*
     817             :                      * There is an "ungotten" newline in the current
     818             :                      * infile buffer (set there by doinclude() in
     819             :                      * cpp1.c).  Thus, we know that the mainline code
     820             :                      * is skipping over blank lines and will do a
     821             :                      * #line at its convenience.
     822             :                      */
     823        4148 :                     wrongline = TRUE;       /* Need a #line now     */
     824             :                 }
     825             :             }
     826             :         }
     827             :         /*
     828             :          * Free up space used by the (finished) file or macro and
     829             :          * restart input from the parent file/macro, if any.
     830             :          */
     831       83079 :         free(file->filename);               /* Free name and        */
     832       83079 :         if (file->progname != NULL)         /* if a #line was seen, */
     833           0 :             free(file->progname);           /* free it, too.        */
     834       83079 :         free((char*) file);                /* Free file space      */
     835       83079 :         if (infile == NULL)                 /* If at end of file    */
     836         361 :             return EOF_CHAR;                /* Return end of file   */
     837       82718 :         line = infile->line;                /* Reset line number    */
     838       82718 :         goto get_from_file;                 /* Get from the top.    */
     839             :     }
     840             :     /*
     841             :      * Common processing for the new character.
     842             :      */
     843    63785705 :     if (c == DEF_MAGIC && file->fp != NULL) /* Don't allow delete   */
     844           0 :         goto newline;                       /* from a file          */
     845    63785705 :     if (file->parent != NULL)               /* Macro or #include    */
     846             :     {
     847    61177152 :         if (popped != 0)
     848       59981 :             file->parent->unrecur += popped;
     849             :         else
     850             :         {
     851    61117171 :             recursion -= file->parent->unrecur;
     852    61117171 :             if (recursion < 0)
     853         550 :                 recursion = 0;
     854    61117171 :             file->parent->unrecur = 0;
     855             :         }
     856             :     }
     857             : #if (HOST == SYS_UNIX)
     858    63785705 :     if (c == '\r')
     859           0 :         return get();                       /* DOS fuck             */
     860             : #endif
     861    63785705 :     if (c == '\n')                          /* Maintain current     */
     862     1785270 :         ++line;                             /* line counter         */
     863    63785705 :     if (instring)                           /* Strings just return  */
     864    12211130 :         return c;                           /* the character.       */
     865    51574575 :     else if (c == '/')                      /* Comment?             */
     866             :     {
     867      159550 :         instring = TRUE;                    /* So get() won't loop  */
     868             : 
     869      159550 :         c = get();
     870      159550 :         if ((c != '*') && (c != '/'))       /* Next byte '*'?       */
     871             :         {
     872        1082 :             instring = FALSE;               /* Nope, no comment     */
     873        1082 :             unget();                        /* Push the char. back  */
     874        1082 :             return '/';                     /* Return the slash     */
     875             :         }
     876      158468 :         if (keepcomments)                   /* If writing comments  */
     877             :         {
     878           0 :             PUTCHAR('/');                   /* Write out the        */
     879             :             /*   initializer        */
     880           0 :             if( '*' == c )
     881           0 :                 PUTCHAR('*');
     882             :             else
     883           0 :                 PUTCHAR('/');
     884             :         }
     885      158468 :         if( '*' == c )
     886             :         {
     887             :             for (;;)                         /* Eat a comment        */
     888             :             {
     889     5220516 :                 c = get();
     890             :               test:
     891     5339973 :                 if (keepcomments && c != EOF_CHAR)
     892           0 :                     cput(c);
     893     5339973 :                 switch (c)
     894             :                 {
     895             :                 case EOF_CHAR:
     896           0 :                     cerror("EOF in comment", NULLST);
     897           0 :                     return EOF_CHAR;
     898             : 
     899             :                 case '/':
     900       41909 :                     if ((c = get()) != '*')     /* Don't let comments   */
     901       41909 :                         goto test;              /* Nest.                */
     902             : #ifdef STRICT_COMMENTS
     903             :                     cwarn("Nested comments", NULLST);
     904             : #endif
     905             :                     /* Fall into * stuff    */
     906             :                 case '*':
     907      100881 :                     if ((c = get()) != '/')     /* If comment doesn't   */
     908       77548 :                         goto test;              /* end, look at next    */
     909       23333 :                     instring = FALSE;           /* End of comment,      */
     910       23333 :                     if (keepcomments)           /* Put out the comment  */
     911             :                     {
     912           0 :                         cput(c);                /* terminator, too      */
     913             :                     }
     914             :                     /*
     915             :                      * A comment is syntactically "whitespace" --
     916             :                      * however, there are certain strange sequences
     917             :                      * such as
     918             :                      *          #define foo(x)  (something)
     919             :                      *                  foo|* comment *|(123)
     920             :                      *       these are '/' ^           ^
     921             :                      * where just returning space (or COM_SEP) will cause
     922             :                      * problems.  This can be "fixed" by overwriting the
     923             :                      * '/' in the input line buffer with ' ' (or COM_SEP)
     924             :                      * but that may mess up an error message.
     925             :                      * So, we peek ahead -- if the next character is
     926             :                      * "whitespace" we just get another character, if not,
     927             :                      * we modify the buffer.  All in the name of purity.
     928             :                      */
     929       23333 :                     if (*file->bptr == '\n' || type[*file->bptr & 0xFF] == SPA)
     930             :                         goto newline;
     931          25 :                     return (file->bptr[-1] = ' ');
     932             : 
     933             :                 case '\n':                      /* we'll need a #line   */
     934       84152 :                     if (!keepcomments)
     935       84152 :                         wrongline = TRUE;       /* later...             */
     936             :                 default:                        /* Anything else is     */
     937     5197183 :                     break;                      /* Just a character     */
     938             :                 }                               /* End switch           */
     939     5197183 :             }                                   /* End comment loop     */
     940             :         }
     941             :         else                                    /* c++ comment          */
     942             :         {
     943             :             for (;;)                            /* Eat a comment        */
     944             :             {
     945     5057985 :                 c = get();
     946     5057985 :                 if (keepcomments && c != EOF_CHAR)
     947           0 :                     cput(c);
     948     5057985 :                 if( EOF_CHAR == c )
     949           0 :                     return EOF_CHAR;
     950     5057985 :                 else if( '\n' == c )
     951             :                 {
     952      135135 :                     instring = FALSE;           /* End of comment,      */
     953      135135 :                     return c;
     954             :                 }
     955     4922850 :             }
     956             :         }
     957             :     }                                       /* End if in comment    */
     958    51415025 :     else if (!inmacro && c == '\\')         /* If backslash, peek   */
     959             :     {
     960       16906 :         if ((c = get()) == '\n')            /* for a <nl>.  If so,  */
     961             :         {
     962       16906 :             wrongline = TRUE;
     963       16906 :             goto newline;
     964             :         }
     965             :         else                                /* Backslash anything   */
     966             :         {
     967           0 :             unget();                        /* Get it later         */
     968           0 :             return '\\';                    /* Return the backslash */
     969             :         }
     970             :     }
     971    51398119 :     else if (c == '\f' || c == VT)          /* Form Feed, Vertical  */
     972             :     {
     973           0 :         c = ' ';                            /* Tab are whitespace   */
     974             :     }
     975    51398119 :     else if (c == 0xef)                     /* eat up UTF-8 BOM */
     976             :     {
     977           0 :         if((c = get()) == 0xbb)
     978             :         {
     979           0 :             if((c = get()) == 0xbf)
     980             :             {
     981           0 :                 c = get();
     982           0 :                 return c;
     983             :             }
     984             :             else
     985             :             {
     986           0 :                 unget();
     987           0 :                 unget();
     988           0 :                 return 0xef;
     989             :             }
     990             :         }
     991             :         else
     992             :         {
     993           0 :             unget();
     994           0 :             return 0xef;
     995             :         }
     996             :     }
     997    51398119 :     return c;                             /* Just return the char */
     998             : }
     999             : 
    1000             : /*
    1001             :  * Backup the pointer to reread the last character.  Fatal error
    1002             :  * (code bug) if we backup too far.  unget() may be called,
    1003             :  * without problems, at end of file.  Only one character may
    1004             :  * be ungotten.  If you need to unget more, call ungetstring().
    1005             :  */
    1006     2923574 : void unget()
    1007             : {
    1008             :     FILEINFO* file;
    1009             : 
    1010     2923574 :     if ((file = infile) == NULL)
    1011     2923574 :         return;                     /* Unget after EOF              */
    1012     2923574 :     if (--file->bptr < file->buffer)
    1013           0 :         cfatal("Too much pushback", NULLST);
    1014     2923574 :     if (*file->bptr == '\n')        /* Ungetting a newline?         */
    1015      572113 :         --line;                     /* Unget the line number, too   */
    1016             : }
    1017             : 
    1018             : /*
    1019             :  * Push a string back on the input stream.  This is done by treating
    1020             :  * the text as if it were a macro.
    1021             :  */
    1022           0 : void ungetstring(char* text)
    1023             : {
    1024             :     FILEINFO* file;
    1025           0 :     file = getfile(strlen(text) + 1, "");
    1026           0 :     strcpy(file->buffer, text);
    1027           0 : }
    1028             : 
    1029             : /*
    1030             :  * Get one character, absorb "funny space" after comments or
    1031             :  * token concatenation
    1032             :  */
    1033       18785 : int cget()
    1034             : {
    1035             :     int c;
    1036             : 
    1037             :     do
    1038             :     {
    1039       18785 :         c = get();
    1040             :     }
    1041       18785 :     while (c == TOK_SEP);
    1042       18785 :     return c;
    1043             : }
    1044             : 
    1045             : /*
    1046             :  * Error messages and other hacks.  The first byte of severity
    1047             :  * is 'S' for string arguments and 'I' for int arguments.  This
    1048             :  * is needed for portability with machines that have int's that
    1049             :  * are shorter than  char *'s.
    1050             :  */
    1051             : 
    1052             : /*
    1053             :  * Print filenames, macro names, and line numbers for error messages.
    1054             :  */
    1055           0 : static void domsg(char* severity, char* format, void* arg)
    1056             : {
    1057             :     char* tp;
    1058             :     FILEINFO* file;
    1059             : 
    1060           0 :     fprintf(stderr, "%sline %d, %s: ", MSG_PREFIX, line, &severity[1]);
    1061           0 :     if (*severity == 'S')
    1062           0 :         fprintf(stderr, format, (char*)arg);
    1063             :     else
    1064           0 :         fprintf(stderr, format, *((int*)arg) );
    1065           0 :     putc('\n', stderr);
    1066           0 :     if ((file = infile) == NULL)
    1067           0 :         return;                             /* At end of file       */
    1068           0 :     if (file->fp != NULL)
    1069             :     {
    1070           0 :         tp = file->buffer;                  /* Print current file   */
    1071           0 :         fprintf(stderr, "%s", tp);          /* name, making sure    */
    1072           0 :         if (tp[strlen(tp) - 1] != '\n')     /* there's a newline    */
    1073           0 :             putc('\n', stderr);
    1074             :     }
    1075           0 :     while ((file = file->parent) != NULL)   /* Print #includes, too */
    1076             :     {
    1077           0 :         if (file->fp == NULL)
    1078           0 :             fprintf(stderr, "from macro %s\n", file->filename);
    1079             :         else
    1080             :         {
    1081           0 :             tp = file->buffer;
    1082           0 :             fprintf(stderr, "from file %s, line %d:\n%s",
    1083           0 :                     (file->progname != NULL)
    1084             :                     ? file->progname : file->filename,
    1085             :                     file->line, tp);
    1086           0 :             if (tp[strlen(tp) - 1] != '\n')
    1087           0 :                 putc('\n', stderr);
    1088             :         }
    1089             :     }
    1090             : }
    1091             : 
    1092             : /*
    1093             :  * Print a normal error message, string argument.
    1094             :  */
    1095           0 : void cerror(char* format, char* sarg)
    1096             : {
    1097           0 :     domsg("SError", format, sarg);
    1098           0 :     errors++;
    1099           0 : }
    1100             : 
    1101             : /*
    1102             :  * Print a normal error message, numeric argument.
    1103             :  */
    1104           0 : void cierror(char* format, int narg)
    1105             : {
    1106           0 :     domsg("IError", format, &narg);
    1107           0 :     errors++;
    1108           0 : }
    1109             : 
    1110             : /*
    1111             :  * A real disaster
    1112             :  */
    1113           0 : void cfatal(char* format, char* sarg)
    1114             : {
    1115           0 :     domsg("SFatal error", format, sarg);
    1116           0 :     exit(IO_ERROR);
    1117             : }
    1118             : 
    1119             : /*
    1120             :  * A non-fatal error, string argument.
    1121             :  */
    1122           0 : void cwarn(char* format, char* sarg)
    1123             : {
    1124           0 :     domsg("SWarning", format, sarg);
    1125           0 : }
    1126             : 
    1127             : /*
    1128             :  * A non-fatal error, numeric argument.
    1129             :  */
    1130           0 : void ciwarn(char* format, int narg)
    1131             : {
    1132           0 :     domsg("IWarning", format, &narg);
    1133           0 : }
    1134             : 
    1135             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11