LCOV - code coverage report
Current view: top level - rsc/source/rscpp - cpp6.c (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 248 367 67.6 %
Date: 2014-11-03 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         363 : void InitCpp6()
     141             : {
     142             :     int i;
     143       23595 :     for( i = 0; i < SBSIZE; i++ )
     144       23232 :         symtab[ i ] = NULL;
     145         363 : }
     146             : 
     147             : 
     148             : 
     149             : /*
     150             :  * Skip to the end of the current input line.
     151             :  */
     152    11979924 : void skipnl()
     153             : {
     154             :     int c;
     155             : 
     156             :     do
     157             :     {                            /* Skip to newline      */
     158    11979924 :         c = get();
     159             :     }
     160    11979924 :     while (c != '\n' && c != EOF_CHAR);
     161      216106 : }
     162             : 
     163             : /*
     164             :  * Skip over whitespace
     165             :  */
     166    11408643 : int skipws()
     167             : {
     168             :     int            c;
     169             : 
     170             :     do {                            /* Skip whitespace      */
     171    11408643 :         c = get();
     172    11408643 :     } while (type[c] == SPA);
     173     2255914 :     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     1150173 : void scanid(int c)
     182             : {
     183             :     char* bp;
     184             : 
     185     1150173 :     if (c == DEF_MAGIC)                     /* Eat the magic token  */
     186           0 :         c = get();                          /* undefiner.           */
     187     1150173 :     bp = token;
     188             :     do
     189             :     {
     190    10156627 :         if (bp < &token[IDMAX])             /* token dim is IDMAX+1 */
     191    10156627 :             *bp++ = (char)c;
     192    10156627 :         c = get();
     193             :     }
     194    10156627 :     while (type[c] == LET || type[c] == DIG);
     195     1150173 :     unget();
     196     1150173 :     *bp = EOS;
     197     1150173 : }
     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      497065 : int macroid(int c)
     206             : {
     207             :     DEFBUF* dp;
     208             : 
     209      497065 :     if (infile != NULL && infile->fp != NULL)
     210      281040 :         recursion = 0;
     211     1075246 :     while (type[c] == LET && (dp = lookid(c)) != NULL)
     212             :     {
     213       81116 :         expand(dp);
     214       81116 :         c = get();
     215             :     }
     216      497065 :     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       87744 : int catenate()
     227             : {
     228             :     int c;
     229             :     char* token1;
     230             : 
     231       87744 :     if (get() != TOK_SEP)                   /* Token concatenation  */
     232             :     {
     233       87744 :         unget();
     234       87744 :         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       84111 : 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       84111 :     instring = TRUE;                /* Don't strip comments         */
     299       84111 :     (*outfun)(delim);
     300     1911544 :     while ((c = get()) != delim &&
     301     1743322 :            c != '\n' &&
     302             :            c != EOF_CHAR)
     303             :     {
     304     1743322 :         if (c != DEF_MAGIC)
     305     1743322 :             (*outfun)(c);
     306     1743322 :         if (c == '\\')
     307         642 :             (*outfun)(get());
     308             :     }
     309       84111 :     instring = FALSE;
     310       84111 :     if (c == delim)
     311             :     {
     312       84111 :         (*outfun)(c);
     313       84111 :         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      489020 : 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      489020 :     expseen = FALSE;                        /* No exponent seen yet */
     342      489020 :     signseen = TRUE;                        /* No +/- allowed yet   */
     343      489020 :     octal89 = FALSE;                        /* No bad octal yet     */
     344      489020 :     radix = 10;                             /* Assume decimal       */
     345      489020 :     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      489020 :             return;                         /* All done for now     */
     352             :         }
     353             :     }                                       /* End of float test    */
     354      489020 :     else if (c == '0')                      /* Octal or hex?        */
     355             :     {
     356       17511 :         (*outfun)(c);                       /* Stuff initial zero   */
     357       17511 :         radix = 8;                          /* Assume it's octal    */
     358       17511 :         c = get();                          /* Look for an 'x'      */
     359       17511 :         if (c == 'x' || c == 'X')           /* Did we get one?      */
     360             :         {
     361       11084 :             radix = 16;                     /* Remember new radix   */
     362       11084 :             (*outfun)(c);                   /* Stuff the 'x'        */
     363       11084 :             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     1825753 :         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     1825753 :         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     1825753 :         else if (c == '+' || c == '-')      /* 1.0e+10              */
     388             :         {
     389        4177 :             if (signseen)                   /* Sign in wrong place? */
     390        4177 :                 break;                      /* Exit loop, not nbr.  */
     391             :             /* signseen = TRUE; */          /* Remember we saw it   */
     392             :         }
     393             :         else                                /* Check the digit      */
     394             :         {
     395     1821576 :             switch (c)
     396             :             {
     397             :             case '8': case '9':             /* Sometimes wrong      */
     398      178981 :                 octal89 = TRUE;             /* Do check later       */
     399             :             case '0': case '1': case '2': case '3':
     400             :             case '4': case '5': case '6': case '7':
     401     1328983 :                 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        7750 :                 if (radix == 16)            /* Alpha's are ok only  */
     406        7750 :                     break;                  /* if reading hex.      */
     407             :             default:                        /* At number end        */
     408      484843 :                 goto done;                  /* Break from for loop  */
     409             :             }                               /* End of switch        */
     410             :         }                                   /* End general case     */
     411     1336733 :         (*outfun)(c);                       /* Accept the character */
     412     1336733 :         signseen = TRUE;                    /* Don't read sign now  */
     413     1336733 :         c = get();                          /* Read another char    */
     414     1336733 :     }                                       /* 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      489020 :     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      494868 :             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      489020 :                 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      489020 :     unget();                                /* Not part of a number */
     466      489020 :     if (octal89 && radix == 8)
     467           0 :         cwarn("Illegal digit in octal number", NULLST);
     468             : }
     469             : 
     470    10581181 : void save(int c)
     471             : {
     472    10581181 :     if (workp >= &work[NWORK])
     473             :     {
     474           0 :         work[NWORK-1] = '\0';
     475           0 :         cfatal("Work buffer overflow:  %s", work);
     476             :     }
     477             :     else
     478    10581181 :         *workp++ = (char)c;
     479    10581181 : }
     480             : 
     481             : /*
     482             :  * Store a string into free memory.
     483             :  */
     484      592232 : char* savestring(char* text)
     485             : {
     486             :     char* result;
     487             : 
     488      592232 :     result = getmem(strlen(text) + 1);
     489      592232 :     strcpy(result, text);
     490      592232 :     return (result);
     491             : }
     492             : 
     493             : /*
     494             :  * Common FILEINFO buffer initialization for a new file or macro.
     495             :  */
     496       85682 : FILEINFO* getfile(int bufsize, char* name)
     497             : {
     498             :     FILEINFO* file;
     499             :     int size;
     500             : 
     501       85682 :     size = strlen(name);                    /* File/macro name      */
     502       85682 :     file = (FILEINFO*) getmem(sizeof (FILEINFO) + bufsize + size);
     503       85682 :     file->parent = infile;                  /* Chain files together */
     504       85682 :     file->fp = NULL;                        /* No file yet          */
     505       85682 :     file->filename = savestring(name);      /* Save file/macro name */
     506       85682 :     file->progname = NULL;                  /* No #line seen yet    */
     507       85682 :     file->unrecur = 0;                      /* No macro fixup       */
     508       85682 :     file->bptr = file->buffer;              /* Initialize line ptr  */
     509       85682 :     file->buffer[0] = EOS;                  /* Force first read     */
     510       85682 :     file->line = 0;                         /* (Not used just yet)  */
     511       85682 :     if (infile != NULL)                     /* If #include file     */
     512       85319 :         infile->line = line;                /* Save current line    */
     513       85682 :     infile = file;                          /* New current file     */
     514       85682 :     line = 1;                               /* Note first line      */
     515       85682 :     return (file);                          /* All done.            */
     516             : }
     517             : 
     518             : /*
     519             :  * Get a block of free memory.
     520             :  */
     521     1173647 : char* getmem(int size)
     522             : {
     523             :     char* result;
     524             : 
     525     1173647 :     if ((result = malloc((unsigned) size)) == NULL)
     526           0 :         cfatal("Out of memory", NULLST);
     527     1173647 :     return (result);
     528             : }
     529             : 
     530             : /*
     531             :  * Look for the next token in the symbol table.  Returns token in "token".
     532             :  * If found, returns the table pointer;  Else returns NULL.
     533             :  */
     534      672521 : DEFBUF* lookid(int c)
     535             : {
     536             :     int nhash;
     537             :     DEFBUF* dp;
     538             :     char* np;
     539      672521 :     int temp = 0;
     540             :     int isrecurse;      /* For #define foo foo  */
     541             : 
     542      672521 :     np = token;
     543      672521 :     nhash = 0;
     544      672521 :     if (0 != (isrecurse = (c == DEF_MAGIC)))/* If recursive macro   */
     545           0 :         c = get();                          /* hack, skip DEF_MAGIC */
     546             :     do
     547             :     {
     548    11542720 :         if (np < &token[IDMAX])             /* token dim is IDMAX+1 */
     549             :         {
     550    11542720 :             *np++ = (char)c;                /* Store token byte     */
     551    11542720 :             nhash += c;                     /* Update hash value    */
     552             :         }
     553    11542720 :         c = get();                          /* And get another byte */
     554             :     }
     555    11542720 :     while (type[c] == LET || type[c] == DIG);
     556      672521 :     unget();                                /* Rescan terminator    */
     557      672521 :     *np = EOS;                              /* Terminate token      */
     558      672521 :     if (isrecurse)                          /* Recursive definition */
     559           0 :         return (NULL);                      /* undefined just now   */
     560      672521 :     nhash += (np - token);                  /* Fix hash value       */
     561      672521 :     dp = symtab[nhash & SBMASK];            /* Starting bucket      */
     562    13300555 :     while (dp != (DEFBUF*) NULL)           /* Search symbol table  */
     563             :     {
     564    12713807 :         if (dp->hash == nhash &&            /* Fast precheck        */
     565      511487 :             (temp = strcmp(dp->name, token)) >= 0)
     566             :         {
     567      246807 :             break;
     568             :         }
     569    11955513 :         dp = dp->link;                      /* Nope, try next one   */
     570             :     }
     571      672521 :     return ((temp == 0) ? dp : NULL);
     572             : }
     573             : 
     574             : /*
     575             :  * Enter this name in the lookup table (delete = FALSE)
     576             :  * or delete this name (delete = TRUE).
     577             :  * Returns a pointer to the define block (delete = FALSE)
     578             :  * Returns NULL if the symbol wasn't defined (delete = TRUE).
     579             :  */
     580      495399 : DEFBUF* defendel(char* name, int delete)
     581             : {
     582             :     DEFBUF* dp;
     583             :     DEFBUF** prevp;
     584             :     char* np;
     585             :     int nhash;
     586             :     int temp;
     587             :     int size;
     588             : 
     589    10605803 :     for (nhash = 0, np = name; *np != EOS;)
     590     9615005 :         nhash += *np++;
     591      495399 :     size = (np - name);
     592      495399 :     nhash += size;
     593      495399 :     prevp = &symtab[nhash & SBMASK];
     594     8873249 :     while ((dp = *prevp) != (DEFBUF*) NULL)
     595             :     {
     596     8390921 :         if (dp->hash == nhash &&
     597      360099 :             (temp = strcmp(dp->name, name)) >= 0)
     598             :         {
     599      148371 :             if (temp > 0)
     600      148342 :                 dp = NULL;                  /* Not found            */
     601             :             else
     602             :             {
     603          29 :                 *prevp = dp->link;          /* Found, unlink and    */
     604          29 :                 if (dp->repl != NULL)       /* Free the replacement */
     605          29 :                     free(dp->repl);         /* if any, and then     */
     606          29 :                 free((char*) dp);          /* Free the symbol      */
     607          29 :                 dp = NULL;
     608             :             }
     609      148371 :             break;
     610             :         }
     611     7882451 :         prevp = &dp->link;
     612             :     }
     613      495399 :     if (!delete)
     614             :     {
     615      495370 :         dp = (DEFBUF*) getmem(sizeof (DEFBUF) + size);
     616      495370 :         dp->link = *prevp;
     617      495370 :         *prevp = dp;
     618      495370 :         dp->hash = nhash;
     619      495370 :         dp->repl = NULL;
     620      495370 :         dp->nargs = 0;
     621      495370 :         strcpy(dp->name, name);
     622             :     }
     623      495399 :     return (dp);
     624             : }
     625             : 
     626             : #if OSL_DEBUG_LEVEL > 1
     627             : 
     628             : void dumpdef(char* why)
     629             : {
     630             :     DEFBUF* dp;
     631             :     DEFBUF** syp;
     632             :     FILE* pRememberOut = NULL;
     633             : 
     634             :     if ( bDumpDefs )    /*ER */
     635             :     {
     636             :         pRememberOut = pCppOut;
     637             :         pCppOut = pDefOut;
     638             :     }
     639             :     fprintf( pCppOut, "CPP symbol table dump %s\n", why);
     640             :     for (syp = symtab; syp < &symtab[SBSIZE]; syp++)
     641             :     {
     642             :         if ((dp = *syp) != (DEFBUF*) NULL)
     643             :         {
     644             :             fprintf( pCppOut, "symtab[%" SAL_PRI_PTRDIFFT "d]\n", (syp - symtab));
     645             :             do
     646             :             {
     647             :                 dumpadef((char*) NULL, dp);
     648             :             }
     649             :             while ((dp = dp->link) != (DEFBUF*) NULL);
     650             :         }
     651             :     }
     652             :     if ( bDumpDefs )
     653             :     {
     654             :         fprintf( pCppOut, "\n");
     655             :         pCppOut = pRememberOut;
     656             :     }
     657             : }
     658             : 
     659             : void dumpadef(char* why, DEFBUF* dp)
     660             : {
     661             :     char* cp;
     662             :     int c;
     663             :     FILE* pRememberOut = NULL;
     664             : 
     665             : /*ER dump #define's to pDefOut */
     666             :     if ( bDumpDefs )
     667             :     {
     668             :         pRememberOut = pCppOut;
     669             :         pCppOut = pDefOut;
     670             :     }
     671             :     fprintf( pCppOut, " \"%s\" [%d]", dp->name, dp->nargs);
     672             :     if (why != NULL)
     673             :         fprintf( pCppOut, " (%s)", why);
     674             :     if (dp->repl != NULL)
     675             :     {
     676             :         fprintf( pCppOut, " => ");
     677             :         for (cp = dp->repl; (c = *cp++ & 0xFF) != EOS;)
     678             :         {
     679             : #ifdef SOLAR
     680             :             if (c == DEL)
     681             :             {
     682             :                 c = *cp++ & 0xFF;
     683             :                 if( c == EOS ) break;
     684             :                 fprintf( pCppOut, "<%%%d>", c - MAC_PARM);
     685             :             }
     686             : #else
     687             :             if (c >= MAC_PARM && c <= (MAC_PARM + PAR_MAC))
     688             :                 fprintf( pCppOut, "<%%%d>", c - MAC_PARM);
     689             : #endif
     690             :             else if (isprint(c) || c == '\n' || c == '\t')
     691             :                 PUTCHAR(c);
     692             :             else if (c < ' ')
     693             :                 fprintf( pCppOut, "<^%c>", c + '@');
     694             :             else
     695             :                 fprintf( pCppOut, "<\\0%o>", c);
     696             :         }
     697             : /*ER evaluate macros to pDefOut */
     698             : #ifdef EVALDEFS
     699             :         if ( bDumpDefs && !bIsInEval && dp->nargs <= 0 )
     700             :         {
     701             :             FILEINFO* infileSave = infile;
     702             :             char* tokenSave = savestring( token );
     703             :             char* workSave = savestring( work );
     704             :             int lineSave = line;
     705             :             int wronglineSave = wrongline;
     706             :             int recursionSave = recursion;
     707             :             FILEINFO* file;
     708             :             EVALTYPE valEval;
     709             : 
     710             :             bIsInEval = 1;
     711             :             infile = NULL;          /* start from scrap */
     712             :             line = 0;
     713             :             wrongline = 0;
     714             :             *token = EOS;
     715             :             *work = EOS;
     716             :             recursion = 0;
     717             :             file = getfile( strlen( dp->repl ), dp->name );
     718             :             strcpy( file->buffer, dp->repl );
     719             :             fprintf( pCppOut, " ===> ");
     720             :             nEvalOff = 0;
     721             :             cppmain();              /* get() frees also *file */
     722             :             valEval = 0;
     723             :             if ( 0 == evaluate( EvalBuf, &valEval ) )
     724             :             {
     725             : #ifdef EVALFLOATS
     726             :                 if ( valEval != (EVALTYPE)((long)valEval ) )
     727             :                     fprintf( pCppOut, " ==eval=> %f", valEval );
     728             :                 else
     729             : #endif
     730             :                     fprintf( pCppOut, " ==eval=> %ld", (long)valEval );
     731             :             }
     732             :             recursion = recursionSave;
     733             :             wrongline = wronglineSave;
     734             :             line = lineSave;
     735             :             strcpy( work, workSave );
     736             :             free( workSave );
     737             :             strcpy( token, tokenSave );
     738             :             free( tokenSave );
     739             :             infile = infileSave;
     740             :             bIsInEval = 0;
     741             :         }
     742             : #endif
     743             :     }
     744             :     else
     745             :     {
     746             :         fprintf( pCppOut, ", no replacement.");
     747             :     }
     748             :     PUTCHAR('\n');
     749             :     if ( bDumpDefs )
     750             :         pCppOut = pRememberOut;
     751             : }
     752             : #endif
     753             : 
     754             : /*
     755             :  *                      G E T
     756             :  */
     757             : 
     758             : /*
     759             :  * Return the next character from a macro or the current file.
     760             :  * Handle end of file from #include files.
     761             :  */
     762    65390813 : int get()
     763             : {
     764             :     int c;
     765             :     FILEINFO* file;
     766             :     int popped;         /* Recursion fixup      */
     767             : 
     768    65390813 :     popped = 0;
     769             :   get_from_file:
     770    65476132 :     if ((file = infile) == NULL)
     771           0 :         return (EOF_CHAR);
     772             :   newline:
     773             : 
     774             :     /*
     775             :      * Read a character from the current input line or macro.
     776             :      * At EOS, either finish the current macro (freeing temp.
     777             :      * storage) or read another line from the current input file.
     778             :      * At EOF, exit the current file (#include) or, at EOF from
     779             :      * the cpp input file, return EOF_CHAR to finish processing.
     780             :      */
     781    66743242 :     if ((c = *file->bptr++ & 0xFF) == EOS)
     782             :     {
     783             :         /*
     784             :          * Nothing in current line or macro.  Get next line (if
     785             :          * input from a file), or do end of file/macro processing.
     786             :          * In the latter case, jump back to restart from the top.
     787             :          */
     788     1310953 :         if (file->fp == NULL)               /* NULL if macro        */
     789             :         {
     790       81116 :             popped++;
     791       81116 :             recursion -= file->unrecur;
     792       81116 :             if (recursion < 0)
     793           0 :                 recursion = 0;
     794       81116 :             infile = file->parent;          /* Unwind file chain    */
     795             :         }
     796             :         else                                /* Else get from a file */
     797             :         {
     798     1229837 :             if ((file->bptr = fgets(file->buffer, NBUFF, file->fp)) != NULL)
     799             :             {
     800             : #if OSL_DEBUG_LEVEL > 1
     801             :                 if (debug > 1)              /* Dump it to stdout    */
     802             :                 {
     803             :                     fprintf( pCppOut, "\n#line %d (%s), %s",
     804             :                              line, file->filename, file->buffer);
     805             :                 }
     806             : #endif
     807     1225271 :                 goto newline;               /* process the line     */
     808             :             }
     809             :             else
     810             :             {
     811        4566 :                 if( file->fp != stdin )
     812        4566 :                     fclose(file->fp);           /* Close finished file  */
     813        4566 :                 if ((infile = file->parent) != NULL)
     814             :                 {
     815             :                     /*
     816             :                      * There is an "ungotten" newline in the current
     817             :                      * infile buffer (set there by doinclude() in
     818             :                      * cpp1.c).  Thus, we know that the mainline code
     819             :                      * is skipping over blank lines and will do a
     820             :                      * #line at its convenience.
     821             :                      */
     822        4203 :                     wrongline = TRUE;       /* Need a #line now     */
     823             :                 }
     824             :             }
     825             :         }
     826             :         /*
     827             :          * Free up space used by the (finished) file or macro and
     828             :          * restart input from the parent file/macro, if any.
     829             :          */
     830       85682 :         free(file->filename);               /* Free name and        */
     831       85682 :         if (file->progname != NULL)         /* if a #line was seen, */
     832           0 :             free(file->progname);           /* free it, too.        */
     833       85682 :         free((char*) file);                /* Free file space      */
     834       85682 :         if (infile == NULL)                 /* If at end of file    */
     835         363 :             return (EOF_CHAR);              /* Return end of file   */
     836       85319 :         line = infile->line;                /* Reset line number    */
     837       85319 :         goto get_from_file;                 /* Get from the top.    */
     838             :     }
     839             :     /*
     840             :      * Common processing for the new character.
     841             :      */
     842    65432289 :     if (c == DEF_MAGIC && file->fp != NULL) /* Don't allow delete   */
     843           0 :         goto newline;                       /* from a file          */
     844    65432289 :     if (file->parent != NULL)               /* Macro or #include    */
     845             :     {
     846    62727130 :         if (popped != 0)
     847       61695 :             file->parent->unrecur += popped;
     848             :         else
     849             :         {
     850    62665435 :             recursion -= file->parent->unrecur;
     851    62665435 :             if (recursion < 0)
     852         555 :                 recursion = 0;
     853    62665435 :             file->parent->unrecur = 0;
     854             :         }
     855             :     }
     856             : #if (HOST == SYS_UNIX)
     857    65432289 :     if (c == '\r')
     858           0 :         return get();                       /* DOS fuck             */
     859             : #endif
     860    65432289 :     if (c == '\n')                          /* Maintain current     */
     861     1825642 :         ++line;                             /* line counter         */
     862    65432289 :     if (instring)                           /* Strings just return  */
     863    12612732 :         return (c);                         /* the character.       */
     864    52819557 :     else if (c == '/')                      /* Comment?             */
     865             :     {
     866      161028 :         instring = TRUE;                    /* So get() won't loop  */
     867             : 
     868      161028 :         c = get();
     869      161028 :         if ((c != '*') && (c != '/'))       /* Next byte '*'?       */
     870             :         {
     871        1111 :             instring = FALSE;               /* Nope, no comment     */
     872        1111 :             unget();                        /* Push the char. back  */
     873        1111 :             return ('/');                   /* Return the slash     */
     874             :         }
     875      159917 :         if (keepcomments)                   /* If writing comments  */
     876             :         {
     877           0 :             PUTCHAR('/');                   /* Write out the        */
     878             :             /*   initializer        */
     879           0 :             if( '*' == c )
     880           0 :                 PUTCHAR('*');
     881             :             else
     882           0 :                 PUTCHAR('/');
     883             :         }
     884      159917 :         if( '*' == c )
     885             :         {
     886             :             for (;;)                         /* Eat a comment        */
     887             :             {
     888     5304153 :                 c = get();
     889             :               test:
     890     5425129 :                 if (keepcomments && c != EOF_CHAR)
     891           0 :                     cput(c);
     892     5425129 :                 switch (c)
     893             :                 {
     894             :                 case EOF_CHAR:
     895           0 :                     cerror("EOF in comment", NULLST);
     896           0 :                     return (EOF_CHAR);
     897             : 
     898             :                 case '/':
     899       42446 :                     if ((c = get()) != '*')     /* Don't let comments   */
     900       42446 :                         goto test;              /* Nest.                */
     901             : #ifdef STRICT_COMMENTS
     902             :                     cwarn("Nested comments", NULLST);
     903             : #endif
     904             :                     /* Fall into * stuff    */
     905             :                 case '*':
     906      102069 :                     if ((c = get()) != '/')     /* If comment doesn't   */
     907       78530 :                         goto test;              /* end, look at next    */
     908       23539 :                     instring = FALSE;           /* End of comment,      */
     909       23539 :                     if (keepcomments)           /* Put out the comment  */
     910             :                     {
     911           0 :                         cput(c);                /* terminator, too      */
     912             :                     }
     913             :                     /*
     914             :                      * A comment is syntactically "whitespace" --
     915             :                      * however, there are certain strange sequences
     916             :                      * such as
     917             :                      *          #define foo(x)  (something)
     918             :                      *                  foo|* comment *|(123)
     919             :                      *       these are '/' ^           ^
     920             :                      * where just returning space (or COM_SEP) will cause
     921             :                      * problems.  This can be "fixed" by overwriting the
     922             :                      * '/' in the input line buffer with ' ' (or COM_SEP)
     923             :                      * but that may mess up an error message.
     924             :                      * So, we peek ahead -- if the next character is
     925             :                      * "whitespace" we just get another character, if not,
     926             :                      * we modify the buffer.  All in the name of purity.
     927             :                      */
     928       23539 :                     if (*file->bptr == '\n' || type[*file->bptr & 0xFF] == SPA)
     929             :                         goto newline;
     930          25 :                     return ((file->bptr[-1] = ' '));
     931             : 
     932             :                 case '\n':                      /* we'll need a #line   */
     933       85419 :                     if (!keepcomments)
     934       85419 :                         wrongline = TRUE;       /* later...             */
     935             :                 default:                        /* Anything else is     */
     936     5280614 :                     break;                      /* Just a character     */
     937             :                 }                               /* End switch           */
     938     5280614 :             }                                   /* End comment loop     */
     939             :         }
     940             :         else                                    /* c++ comment          */
     941             :         {
     942             :             for (;;)                            /* Eat a comment        */
     943             :             {
     944     5111099 :                 c = get();
     945     5111099 :                 if (keepcomments && c != EOF_CHAR)
     946           0 :                     cput(c);
     947     5111099 :                 if( EOF_CHAR == c )
     948           0 :                     return (EOF_CHAR);
     949     5111099 :                 else if( '\n' == c )
     950             :                 {
     951      136378 :                     instring = FALSE;           /* End of comment,      */
     952      136378 :                     return( c );
     953             :                 }
     954     4974721 :             }
     955             :         }
     956             :     }                                       /* End if in comment    */
     957    52658529 :     else if (!inmacro && c == '\\')         /* If backslash, peek   */
     958             :     {
     959       18325 :         if ((c = get()) == '\n')            /* for a <nl>.  If so,  */
     960             :         {
     961       18325 :             wrongline = TRUE;
     962       18325 :             goto newline;
     963             :         }
     964             :         else                                /* Backslash anything   */
     965             :         {
     966           0 :             unget();                        /* Get it later         */
     967           0 :             return ('\\');                  /* Return the backslash */
     968             :         }
     969             :     }
     970    52640204 :     else if (c == '\f' || c == VT)          /* Form Feed, Vertical  */
     971             :     {
     972           0 :         c = ' ';                            /* Tab are whitespace   */
     973             :     }
     974    52640204 :     else if (c == 0xef)                     /* eat up UTF-8 BOM */
     975             :     {
     976           0 :         if((c = get()) == 0xbb)
     977             :         {
     978           0 :             if((c = get()) == 0xbf)
     979             :             {
     980           0 :                 c = get();
     981           0 :                 return c;
     982             :             }
     983             :             else
     984             :             {
     985           0 :                 unget();
     986           0 :                 unget();
     987           0 :                 return 0xef;
     988             :             }
     989             :         }
     990             :         else
     991             :         {
     992           0 :             unget();
     993           0 :             return 0xef;
     994             :         }
     995             :     }
     996    52640204 :     return (c);                             /* Just return the char */
     997             : }
     998             : 
     999             : /*
    1000             :  * Backup the pointer to reread the last character.  Fatal error
    1001             :  * (code bug) if we backup too far.  unget() may be called,
    1002             :  * without problems, at end of file.  Only one character may
    1003             :  * be ungotten.  If you need to unget more, call ungetstring().
    1004             :  */
    1005     2981527 : void unget()
    1006             : {
    1007             :     FILEINFO* file;
    1008             : 
    1009     2981527 :     if ((file = infile) == NULL)
    1010     2981527 :         return;                     /* Unget after EOF              */
    1011     2981527 :     if (--file->bptr < file->buffer)
    1012           0 :         cfatal("Too much pushback", NULLST);
    1013     2981527 :     if (*file->bptr == '\n')        /* Ungetting a newline?         */
    1014      585438 :         --line;                     /* Unget the line number, too   */
    1015             : }
    1016             : 
    1017             : /*
    1018             :  * Push a string back on the input stream.  This is done by treating
    1019             :  * the text as if it were a macro.
    1020             :  */
    1021           0 : void ungetstring(char* text)
    1022             : {
    1023             :     FILEINFO* file;
    1024           0 :     file = getfile(strlen(text) + 1, "");
    1025           0 :     strcpy(file->buffer, text);
    1026           0 : }
    1027             : 
    1028             : /*
    1029             :  * Get one character, absorb "funny space" after comments or
    1030             :  * token concatenation
    1031             :  */
    1032       18725 : int cget()
    1033             : {
    1034             :     int c;
    1035             : 
    1036             :     do
    1037             :     {
    1038       18725 :         c = get();
    1039             :     }
    1040       18725 :     while (c == TOK_SEP);
    1041       18725 :     return (c);
    1042             : }
    1043             : 
    1044             : /*
    1045             :  * Error messages and other hacks.  The first byte of severity
    1046             :  * is 'S' for string arguments and 'I' for int arguments.  This
    1047             :  * is needed for portability with machines that have int's that
    1048             :  * are shorter than  char *'s.
    1049             :  */
    1050             : 
    1051             : /*
    1052             :  * Print filenames, macro names, and line numbers for error messages.
    1053             :  */
    1054           0 : static void domsg(char* severity, char* format, void* arg)
    1055             : {
    1056             :     char* tp;
    1057             :     FILEINFO* file;
    1058             : 
    1059           0 :     fprintf(stderr, "%sline %d, %s: ", MSG_PREFIX, line, &severity[1]);
    1060           0 :     if (*severity == 'S')
    1061           0 :         fprintf(stderr, format, (char*)arg);
    1062             :     else
    1063           0 :         fprintf(stderr, format, *((int*)arg) );
    1064           0 :     putc('\n', stderr);
    1065           0 :     if ((file = infile) == NULL)
    1066           0 :         return;                             /* At end of file       */
    1067           0 :     if (file->fp != NULL)
    1068             :     {
    1069           0 :         tp = file->buffer;                  /* Print current file   */
    1070           0 :         fprintf(stderr, "%s", tp);          /* name, making sure    */
    1071           0 :         if (tp[strlen(tp) - 1] != '\n')     /* there's a newline    */
    1072           0 :             putc('\n', stderr);
    1073             :     }
    1074           0 :     while ((file = file->parent) != NULL)   /* Print #includes, too */
    1075             :     {
    1076           0 :         if (file->fp == NULL)
    1077           0 :             fprintf(stderr, "from macro %s\n", file->filename);
    1078             :         else
    1079             :         {
    1080           0 :             tp = file->buffer;
    1081           0 :             fprintf(stderr, "from file %s, line %d:\n%s",
    1082           0 :                     (file->progname != NULL)
    1083             :                     ? file->progname : file->filename,
    1084             :                     file->line, tp);
    1085           0 :             if (tp[strlen(tp) - 1] != '\n')
    1086           0 :                 putc('\n', stderr);
    1087             :         }
    1088             :     }
    1089             : }
    1090             : 
    1091             : /*
    1092             :  * Print a normal error message, string argument.
    1093             :  */
    1094           0 : void cerror(char* format, char* sarg)
    1095             : {
    1096           0 :     domsg("SError", format, sarg);
    1097           0 :     errors++;
    1098           0 : }
    1099             : 
    1100             : /*
    1101             :  * Print a normal error message, numeric argument.
    1102             :  */
    1103           0 : void cierror(char* format, int narg)
    1104             : {
    1105           0 :     domsg("IError", format, &narg);
    1106           0 :     errors++;
    1107           0 : }
    1108             : 
    1109             : /*
    1110             :  * A real disaster
    1111             :  */
    1112           0 : void cfatal(char* format, char* sarg)
    1113             : {
    1114           0 :     domsg("SFatal error", format, sarg);
    1115           0 :     exit(IO_ERROR);
    1116             : }
    1117             : 
    1118             : /*
    1119             :  * A non-fatal error, string argument.
    1120             :  */
    1121           0 : void cwarn(char* format, char* sarg)
    1122             : {
    1123           0 :     domsg("SWarning", format, sarg);
    1124           0 : }
    1125             : 
    1126             : /*
    1127             :  * A non-fatal error, numeric argument.
    1128             :  */
    1129           0 : void ciwarn(char* format, int narg)
    1130             : {
    1131           0 :     domsg("IWarning", format, &narg);
    1132           0 : }
    1133             : 
    1134             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10