LCOV - code coverage report
Current view: top level - rsc/source/rscpp - cpp2.c (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 114 192 59.4 %
Date: 2014-11-03 Functions: 6 6 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <stdio.h>
      21             : #include <ctype.h>
      22             : #include "cppdef.h"
      23             : #include "cpp.h"
      24             : 
      25             : /*
      26             :  * Generate (by hand-inspection) a set of unique values for each control
      27             :  * operator.  Note that this is not guaranteed to work for non-Ascii
      28             :  * machines.  CPP won't compile if there are hash conflicts.
      29             :  */
      30             : 
      31             : #define L_assert        ('a' + ('s' << 1))
      32             : #define L_define        ('d' + ('f' << 1))
      33             : #define L_elif          ('e' + ('i' << 1))
      34             : #define L_else          ('e' + ('s' << 1))
      35             : #define L_endif         ('e' + ('d' << 1))
      36             : #define L_if            ('i' + (EOS << 1))
      37             : #define L_ifdef         ('i' + ('d' << 1))
      38             : #define L_ifndef        ('i' + ('n' << 1))
      39             : #define L_include       ('i' + ('c' << 1))
      40             : #define L_line          ('l' + ('n' << 1))
      41             : #define L_nogood        (EOS + (EOS << 1))      /* To catch #i          */
      42             : #define L_pragma        ('p' + ('a' << 1))
      43             : #define L_undef         ('u' + ('d' << 1))
      44             : #define L_error         ('e' + ('r' << 1))      /* BP 5.3.92, #error */
      45             : #if OSL_DEBUG_LEVEL > 1
      46             : #define L_debug         ('d' + ('b' << 1))      /* #debug               */
      47             : #define L_nodebug       ('n' + ('d' << 1))      /* #nodebug             */
      48             : #endif
      49             : 
      50             : 
      51         363 : void InitCpp2()
      52             : {
      53             : 
      54         363 : }
      55             : 
      56             : /*
      57             :  * Process #control lines.  Simple commands are processed inline,
      58             :  * while complex commands have their own subroutines.
      59             :  *
      60             :  * The counter is used to force out a newline before #line, and
      61             :  * #pragma commands.  This prevents these commands from ending up at
      62             :  * the end of the previous line if cpp is invoked with the -C option.
      63             :  */
      64      730701 : int control(int counter)
      65             : {
      66             :     int c;
      67             :     char* tp;
      68             :     int hash;
      69             :     char* ep;
      70             : 
      71      730701 :     c = skipws();
      72      730701 :     if (c == '\n' || c == EOF_CHAR)
      73           0 :         return (counter + 1);
      74      730701 :     if (!isdigit(c))
      75      730701 :         scanid(c);                  /* Get #word to token[]         */
      76             :     else
      77             :     {
      78           0 :         unget();                    /* Hack -- allow #123 as a      */
      79           0 :         strcpy(token, "line");      /* synonym for #line 123        */
      80             :     }
      81      730701 :     hash = (token[1] == EOS) ? L_nogood : (token[0] + (token[2] << 1));
      82      730701 :     switch (hash)
      83             :     {
      84           0 :     case L_assert:  tp = "assert";          break;
      85      711554 :     case L_define:  tp = "define";          break;
      86          40 :     case L_elif:    tp = "elif";            break;
      87          22 :     case L_else:    tp = "else";            break;
      88        6623 :     case L_endif:   tp = "endif";           break;
      89         457 :     case L_if:      tp = "if";              break;
      90         161 :     case L_ifdef:   tp = "ifdef";           break;
      91        6005 :     case L_ifndef:  tp = "ifndef";          break;
      92        5314 :     case L_include: tp = "include";         break;
      93           0 :     case L_line:    tp = "line";            break;
      94           0 :     case L_pragma:  tp = "pragma";          break;
      95         145 :     case L_undef:   tp = "undef";           break;
      96         380 :     case L_error:   tp = "error";           break;
      97             : #if OSL_DEBUG_LEVEL > 1
      98             :     case L_debug:   tp = "debug";           break;
      99             :     case L_nodebug: tp = "nodebug";         break;
     100             : #endif
     101           0 :     default:        hash = L_nogood;
     102             :         /*fall-through*/
     103           0 :     case L_nogood:  tp = "";                break;
     104             :     }
     105      730701 :     if (!streq(tp, token))
     106           0 :         hash = L_nogood;
     107             :     /*
     108             :      * hash is set to a unique value corresponding to the
     109             :      * control keyword (or L_nogood if we think it's nonsense).
     110             :      */
     111      730701 :     if (infile->fp == NULL)
     112           0 :         cwarn("Control line \"%s\" within macro expansion", token);
     113      730701 :     if (!compiling)
     114             :     {                       /* Not compiling now    */
     115      218699 :         switch (hash)
     116             :         {
     117             :         case L_if:                          /* These can't turn     */
     118             :         case L_ifdef:                       /*  compilation on, but */
     119             :         case L_ifndef:                      /*   we must nest #if's */
     120          19 :             if (++ifptr >= &ifstack[BLK_NEST])
     121           0 :                 goto if_nest_err;
     122          19 :             *ifptr = 0;                     /* !WAS_COMPILING       */
     123             :         case L_line:                        /* Many                 */
     124             :             /*
     125             :              * Are pragma's always processed?
     126             :              */
     127             :         case L_pragma:                      /*  options             */
     128             :         case L_include:                     /*   are uninteresting  */
     129             :         case L_define:                      /*    if we             */
     130             :         case L_undef:                       /*     aren't           */
     131             :         case L_assert:                      /*      compiling.      */
     132             :         case L_error:                       /* BP 5.3.92, #error */
     133      215695 :         dump_line:      skipnl();                       /* Ignore rest of line  */
     134      215695 :             return (counter + 1);
     135             :         }
     136             :     }
     137             :     /*
     138             :      * Make sure that #line and #pragma are output on a fresh line.
     139             :      */
     140      515026 :     if (counter > 0 && (hash == L_line || hash == L_pragma))
     141             :     {
     142           0 :         PUTCHAR('\n');
     143           0 :         counter--;
     144             :     }
     145             : 
     146      515026 :     switch (hash)
     147             :     {
     148             :     case L_line:
     149             :         /*
     150             :          * Parse the line to update the line number and "progname"
     151             :          * field and line number for the next input line.
     152             :          * Set wrongline to force it out later.
     153             :          */
     154           0 :         c = skipws();
     155           0 :         workp = work;                       /* Save name in work    */
     156           0 :         while (c != '\n' && c != EOF_CHAR)
     157             :         {
     158           0 :             save(c);
     159           0 :             c = get();
     160             :         }
     161           0 :         unget();
     162           0 :         save(EOS);
     163             :         /*
     164             :          * Split #line argument into <line-number> and <name>
     165             :          * We subtract 1 as we want the number of the next line.
     166             :          */
     167           0 :         line = atoi(work) - 1;              /* Reset line number    */
     168           0 :         for (tp = work; isdigit(*tp) || type[(int)*tp] == SPA; tp++)
     169             :             ;                               /* Skip over digits     */
     170           0 :         if (*tp != EOS)                     /* Got a filename, so:  */
     171             :         {
     172           0 :             if (*tp == '"' && (ep = strrchr(tp + 1, '"')) != NULL)
     173             :             {
     174           0 :                 tp++;                       /* Skip over left quote */
     175           0 :                 *ep = EOS;                  /* And ignore right one */
     176             :             }
     177           0 :             if (infile->progname != NULL)   /* Give up the old name */
     178           0 :                 free(infile->progname);     /* if it's allocated.   */
     179           0 :             infile->progname = savestring(tp);
     180             :         }
     181           0 :         wrongline = TRUE;                   /* Force output later   */
     182           0 :         break;
     183             : 
     184             :     case L_include:
     185        4203 :         doinclude();
     186        4203 :         break;
     187             : 
     188             :     case L_define:
     189      497505 :         dodefine();
     190      497505 :         break;
     191             : 
     192             :     case L_undef:
     193          29 :         doundef();
     194          29 :         break;
     195             : 
     196             :     case L_else:
     197          22 :         if (ifptr == &ifstack[0])
     198           0 :             goto nest_err;
     199          22 :         else if ((*ifptr & ELSE_SEEN) != 0)
     200           0 :             goto else_seen_err;
     201          22 :         *ifptr |= ELSE_SEEN;
     202          22 :         if ((*ifptr & WAS_COMPILING) != 0)
     203             :         {
     204          21 :             if (compiling || (*ifptr & TRUE_SEEN) != 0)
     205          19 :                 compiling = FALSE;
     206             :             else
     207             :             {
     208           2 :                 compiling = TRUE;
     209             :             }
     210             :         }
     211          22 :         break;
     212             : 
     213             :     case L_elif:
     214          40 :         if (ifptr == &ifstack[0])
     215           0 :             goto nest_err;
     216          40 :         else if ((*ifptr & ELSE_SEEN) != 0)
     217             :         {
     218           0 :           else_seen_err:  cerror("#%s may not follow #else", token);
     219           0 :             goto dump_line;
     220             :         }
     221          40 :         if ((*ifptr & (WAS_COMPILING | TRUE_SEEN)) != WAS_COMPILING)
     222             :         {
     223          20 :             compiling = FALSE;              /* Done compiling stuff */
     224          20 :             goto dump_line;                 /* Skip this clause     */
     225             :         }
     226          20 :         doif(L_if);
     227          20 :         break;
     228             : 
     229             :     case L_if:
     230             :     case L_ifdef:
     231             :     case L_ifndef:
     232        6604 :         if (++ifptr >= &ifstack[BLK_NEST])
     233           0 :           if_nest_err:    cfatal("Too many nested #%s statements", token);
     234        6604 :         *ifptr = WAS_COMPILING;
     235        6604 :         doif(hash);
     236        6604 :         break;
     237             : 
     238             :     case L_endif:
     239        6623 :         if (ifptr == &ifstack[0])
     240             :         {
     241           0 :           nest_err:       cerror("#%s must be in an #if", token);
     242           0 :             goto dump_line;
     243             :         }
     244        6623 :         if (!compiling && (*ifptr & WAS_COMPILING) != 0)
     245        2982 :             wrongline = TRUE;
     246        6623 :         compiling = ((*ifptr & WAS_COMPILING) != 0);
     247        6623 :         --ifptr;
     248        6623 :         break;
     249             : 
     250             :     case L_assert:
     251           0 :         if (eval() == 0)
     252           0 :             cerror("Preprocessor assertion failure", NULLST);
     253           0 :         break;
     254             : 
     255             :     case L_pragma:
     256             :         /*
     257             :          * #pragma is provided to pass "options" to later
     258             :          * passes of the compiler.  cpp doesn't have any yet.
     259             :          */
     260           0 :         fprintf( pCppOut, "#pragma ");
     261           0 :         while ((c = get()) != '\n' && c != EOF_CHAR)
     262           0 :             cput(c);
     263           0 :         unget();
     264           0 :         break;
     265             : 
     266             : #if OSL_DEBUG_LEVEL > 1
     267             :     case L_debug:
     268             :         if (debug == 0)
     269             :             dumpdef("debug set on");
     270             :         debug++;
     271             :         break;
     272             : 
     273             :     case L_nodebug:
     274             :         debug--;
     275             :         break;
     276             : #endif
     277             :     case L_error:                       /* BP 5.3.92, #error */
     278           0 :         fprintf( pCppOut, "cpp: line %u, Error directive: ", line );
     279           0 :         while ((c = get()) != '\n' && c != EOF_CHAR)
     280           0 :             cput(c);
     281           0 :         fprintf( pCppOut, "\n" );
     282           0 :         exit( 1 );
     283             : 
     284             :     default:
     285             :         /*
     286             :          * Undefined #control keyword.
     287             :          * Note: the correct behavior may be to warn and
     288             :          * pass the line to a subsequent compiler pass.
     289             :          * This would allow #asm or similar extensions.
     290             :          */
     291           0 :         cerror("Illegal # command \"%s\"", token);
     292           0 :         break;
     293             :     }
     294      515006 :     if (hash != L_include)
     295             :     {
     296      510803 :         if (skipws() != '\n')
     297             :         {
     298           0 :             cwarn("Unexpected text in #control line ignored", NULLST);
     299           0 :             skipnl();
     300             :         }
     301             :     }
     302      515006 :     return (counter + 1);
     303             : }
     304             : 
     305             : /*
     306             :  * Process an #if, #ifdef, or #ifndef.  The latter two are straightforward,
     307             :  * while #if needs a subroutine of its own to evaluate the expression.
     308             :  *
     309             :  * doif() is called only if compiling is TRUE.  If false, compilation
     310             :  * is always suppressed, so we don't need to evaluate anything.  This
     311             :  * suppresses unnecessary warnings.
     312             :  */
     313        6624 : FILE_LOCAL void doif(int hash)
     314             : {
     315             :     int c;
     316             :     int found;
     317             : 
     318        6624 :     if ((c = skipws()) == '\n' || c == EOF_CHAR)
     319             :     {
     320           0 :         unget();
     321           0 :         goto badif;
     322             :     }
     323        6624 :     if (hash == L_if)
     324             :     {
     325         469 :         unget();
     326         469 :         found = (eval() != 0);      /* Evaluate expr, != 0 is  TRUE */
     327         469 :         hash = L_ifdef;             /* #if is now like #ifdef       */
     328             :     }
     329             :     else
     330             :     {
     331        6155 :         if (type[c] != LET)         /* Next non-blank isn't letter  */
     332           0 :             goto badif;             /* ... is an error              */
     333        6155 :         found = (lookid(c) != NULL); /* Look for it in symbol table */
     334             :     }
     335        6624 :     if (found == (hash == L_ifdef))
     336             :     {
     337        3659 :         compiling = TRUE;
     338        3659 :         *ifptr |= TRUE_SEEN;
     339             :     }
     340             :     else
     341             :     {
     342        2965 :         compiling = FALSE;
     343             :     }
     344        6624 :     return;
     345             : 
     346           0 :   badif:  cerror("#if, #ifdef, or #ifndef without an argument", NULLST);
     347           0 :     skipnl();                               /* Prevent an extra     */
     348           0 :     unget();                                /* Error message        */
     349           0 :     return;
     350             : }
     351             : 
     352             : /*
     353             :  * Process the #include control line.
     354             :  * There are three variations:
     355             :  *      #include "file"         search somewhere relative to the
     356             :  *                              current source file, if not found,
     357             :  *                              treat as #include <file>.
     358             :  *      #include <file>         Search in an implementation-dependent
     359             :  *                              list of places.
     360             :  *      #include token          Expand the token, it must be one of
     361             :  *                              "file" or <file>, process as such.
     362             :  *
     363             :  * Note: the November 12 draft forbids '>' in the #include <file> format.
     364             :  * This restriction is unnecessary and not implemented.
     365             :  */
     366        4203 : FILE_LOCAL void doinclude()
     367             : {
     368             :     int c;
     369             :     int delim;
     370             : 
     371        4203 :     delim = macroid(skipws());
     372        4203 :     if (delim != '<' && delim != '"')
     373           0 :         goto incerr;
     374        4203 :     if (delim == '<')
     375        3299 :         delim = '>';
     376        4203 :     workp = work;
     377        4203 :     instring = TRUE;                /* Accept all characters        */
     378             : #ifdef CONTROL_COMMENTS_NOT_ALLOWED
     379             :     while ((c = get()) != '\n' && c != EOF_CHAR)
     380             :         save(c);                    /* Put it away.                 */
     381             :     unget();                        /* Force nl after includee      */
     382             :     /*
     383             :      * The draft is unclear if the following should be done.
     384             :      */
     385             :     while (--workp >= work && *workp == ' ')
     386             :         ;                           /* Trim blanks from filename    */
     387             :     if (*workp != delim)
     388             :         goto incerr;
     389             : #else
     390       68065 :     while ((c = get()) != delim && c != EOF_CHAR)
     391       59659 :         save(c);
     392             : #endif
     393        4203 :     *workp = EOS;                   /* Terminate filename           */
     394        4203 :     instring = FALSE;
     395        4203 :     if (openinclude(work, (delim == '"')))
     396        4203 :         return;
     397             :     /*
     398             :      * No sense continuing if #include file isn't there.
     399             :      */
     400           0 :     cfatal("Cannot open include file \"%s\"", work);
     401             : 
     402           0 :   incerr: cerror("#include syntax error", NULLST);
     403           0 :     return;
     404             : }
     405             : 
     406             : /*
     407             :  * Actually open an include file.  This routine is only called from
     408             :  * doinclude() above, but was written as a separate subroutine for
     409             :  * programmer convenience.  It searches the list of directories
     410             :  * and actually opens the file, linking it into the list of
     411             :  * active files.  Returns TRUE if the file was opened, FALSE
     412             :  * if openinclude() fails.  No error message is printed.
     413             :  */
     414        4203 : FILE_LOCAL int openinclude(char* filename, int searchlocal)
     415             : {
     416             :     char** incptr;
     417             :     char tmpname[NFWORK]; /* Filename work area   */
     418             : 
     419        4203 :     if (searchlocal)
     420             :     {
     421             :         /*
     422             :          * Look in local directory first
     423             :          */
     424             : #if HOST == SYS_UNIX
     425             :         /*
     426             :          * Try to open filename relative to the directory of the current
     427             :          * source file (as opposed to the current directory). (ARF, SCK).
     428             :          */
     429        1808 :         if (filename[0] != '/' &&
     430         904 :             hasdirectory(infile->filename, tmpname, NFWORK))
     431         904 :         {
     432         904 :             int len = strlen(tmpname);
     433         904 :             int len2 = strlen(filename);
     434         904 :             if(len + len2 < NFWORK)
     435             :             {
     436         904 :                 memcpy(tmpname + len, filename, len2);
     437         904 :                 tmpname[len + len2] = 0;
     438             :             }
     439             :             else
     440             :             {
     441           0 :                 cfatal("Filename work buffer overflow", NULLST);
     442             :             }
     443             :         }
     444             :         else
     445             :         {
     446           0 :             int len = strlen(filename);
     447           0 :             if(len < NFWORK)
     448             :             {
     449           0 :                 memcpy(tmpname, filename, len);
     450           0 :                 tmpname[len] = 0;
     451             :             }
     452             :             else
     453             :             {
     454           0 :                 cfatal("Filename work buffer overflow", NULLST);
     455             :             }
     456             :         }
     457             : #else
     458             :         if (!hasdirectory(filename, tmpname, NFWORK) &&
     459             :             hasdirectory(infile->filename, tmpname, NFWORK))
     460             :         {
     461             :             strcat(tmpname, filename);
     462             :         }
     463             :         else
     464             :         {
     465             :             strcpy(tmpname, filename);
     466             :         }
     467             : #endif
     468         904 :         if (openfile(tmpname))
     469           8 :             return (TRUE);
     470             :     }
     471             :     /*
     472             :      * Look in any directories specified by -I command line
     473             :      * arguments, then in the builtin search list.
     474             :      */
     475       12886 :     for (incptr = incdir; incptr < incend; incptr++)
     476             :     {
     477       12886 :         if (strlen(*incptr) + strlen(filename) >= (NFWORK - 1))
     478           0 :             cfatal("Filename work buffer overflow", NULLST);
     479             :         else
     480             :         {
     481             : #if HOST == SYS_UNIX
     482       12886 :             if (filename[0] == '/')
     483           0 :                 strcpy(tmpname, filename);
     484             :             else
     485       12886 :                 sprintf(tmpname, "%s/%s", *incptr, filename);
     486             : 
     487             : #elif HOST == SYS_UNKNOWN
     488             :             if (filename[0] == '\\')
     489             :                 strcpy(tmpname, filename);
     490             :             else
     491             :                 sprintf(tmpname, "%s\\%s", *incptr, filename);
     492             : #else
     493             :             if (!hasdirectory(filename, tmpname, NFWORK))
     494             :                 sprintf(tmpname, "%s%s", *incptr, filename);
     495             : #endif
     496       12886 :             if (openfile(tmpname))
     497        4195 :                 return (TRUE);
     498             :         }
     499             :     }
     500           0 :     return (FALSE);
     501             : }
     502             : 
     503             : /*
     504             :  * If a device or directory is found in the source filename string, the
     505             :  * node/device/directory part of the string is copied to result and
     506             :  * hasdirectory returns TRUE.  Else, nothing is copied and it returns FALSE.
     507             :  */
     508         904 : FILE_LOCAL int hasdirectory(char* source, char* result, int max)
     509             : {
     510             : #if HOST == SYS_UNIX
     511             :     char* tp;
     512             : 
     513         904 :     if ((tp = strrchr(source, '/')) == NULL)
     514           0 :         return (FALSE);
     515             :     else
     516             :     {
     517         904 :         int len = (int)(tp - source);
     518         904 :         if(len < max)
     519             :         {
     520         904 :             memcpy(result, source, len);
     521         904 :             result[len] = 0;
     522             :         }
     523             :         else
     524             :         {
     525           0 :             cfatal("Filename work buffer overflow", NULLST);
     526             :         }
     527         904 :         return (TRUE);
     528             :     }
     529             : #else
     530             :     /*
     531             :      * Random DEC operating system (RSTS/E)
     532             :      */
     533             :     char* tp;
     534             : 
     535             :     (void)max;
     536             : 
     537             :     if ((tp = strrchr(source, ']')) == NULL &&
     538             :         (tp = strrchr(source, ':')) == NULL)
     539             :     {
     540             :         return (FALSE);
     541             :     }
     542             :     else
     543             :     {
     544             :         strncpy(result, source, tp - source + 1);
     545             :         result[tp - source + 1] = EOS;
     546             :         return (TRUE);
     547             :     }
     548             : #endif
     549             : }
     550             : 
     551             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10