xref: /aoo4110/main/rsc/source/rscpp/cpp2.c (revision b1cdbd2c)
1*b1cdbd2cSJim Jagielski /**************************************************************
2*b1cdbd2cSJim Jagielski  *
3*b1cdbd2cSJim Jagielski  * Licensed to the Apache Software Foundation (ASF) under one
4*b1cdbd2cSJim Jagielski  * or more contributor license agreements.  See the NOTICE file
5*b1cdbd2cSJim Jagielski  * distributed with this work for additional information
6*b1cdbd2cSJim Jagielski  * regarding copyright ownership.  The ASF licenses this file
7*b1cdbd2cSJim Jagielski  * to you under the Apache License, Version 2.0 (the
8*b1cdbd2cSJim Jagielski  * "License"); you may not use this file except in compliance
9*b1cdbd2cSJim Jagielski  * with the License.  You may obtain a copy of the License at
10*b1cdbd2cSJim Jagielski  *
11*b1cdbd2cSJim Jagielski  *   http://www.apache.org/licenses/LICENSE-2.0
12*b1cdbd2cSJim Jagielski  *
13*b1cdbd2cSJim Jagielski  * Unless required by applicable law or agreed to in writing,
14*b1cdbd2cSJim Jagielski  * software distributed under the License is distributed on an
15*b1cdbd2cSJim Jagielski  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*b1cdbd2cSJim Jagielski  * KIND, either express or implied.  See the License for the
17*b1cdbd2cSJim Jagielski  * specific language governing permissions and limitations
18*b1cdbd2cSJim Jagielski  * under the License.
19*b1cdbd2cSJim Jagielski  *
20*b1cdbd2cSJim Jagielski  *************************************************************/
21*b1cdbd2cSJim Jagielski 
22*b1cdbd2cSJim Jagielski 
23*b1cdbd2cSJim Jagielski 
24*b1cdbd2cSJim Jagielski #include        <stdio.h>
25*b1cdbd2cSJim Jagielski #include        <ctype.h>
26*b1cdbd2cSJim Jagielski #include        "cppdef.h"
27*b1cdbd2cSJim Jagielski #include        "cpp.h"
28*b1cdbd2cSJim Jagielski #if HOST == SYS_VMS
29*b1cdbd2cSJim Jagielski /*
30*b1cdbd2cSJim Jagielski  * Include the rms stuff.  (We can't just include rms.h as it uses the
31*b1cdbd2cSJim Jagielski  * VaxC-specific library include syntax that Decus CPP doesn't support.
32*b1cdbd2cSJim Jagielski  * By including things by hand, we can CPP ourself.)
33*b1cdbd2cSJim Jagielski  */
34*b1cdbd2cSJim Jagielski #include        <nam.h>
35*b1cdbd2cSJim Jagielski #include        <fab.h>
36*b1cdbd2cSJim Jagielski #include        <rab.h>
37*b1cdbd2cSJim Jagielski #include        <rmsdef.h>
38*b1cdbd2cSJim Jagielski #endif
39*b1cdbd2cSJim Jagielski 
40*b1cdbd2cSJim Jagielski /*
41*b1cdbd2cSJim Jagielski  * Generate (by hand-inspection) a set of unique values for each control
42*b1cdbd2cSJim Jagielski  * operator.  Note that this is not guaranteed to work for non-Ascii
43*b1cdbd2cSJim Jagielski  * machines.  CPP won't compile if there are hash conflicts.
44*b1cdbd2cSJim Jagielski  */
45*b1cdbd2cSJim Jagielski 
46*b1cdbd2cSJim Jagielski #define L_assert        ('a' + ('s' << 1))
47*b1cdbd2cSJim Jagielski #define L_define        ('d' + ('f' << 1))
48*b1cdbd2cSJim Jagielski #define L_elif          ('e' + ('i' << 1))
49*b1cdbd2cSJim Jagielski #define L_else          ('e' + ('s' << 1))
50*b1cdbd2cSJim Jagielski #define L_endif         ('e' + ('d' << 1))
51*b1cdbd2cSJim Jagielski #define L_if            ('i' + (EOS << 1))
52*b1cdbd2cSJim Jagielski #define L_ifdef         ('i' + ('d' << 1))
53*b1cdbd2cSJim Jagielski #define L_ifndef        ('i' + ('n' << 1))
54*b1cdbd2cSJim Jagielski #define L_include       ('i' + ('c' << 1))
55*b1cdbd2cSJim Jagielski #define L_line          ('l' + ('n' << 1))
56*b1cdbd2cSJim Jagielski #define L_nogood        (EOS + (EOS << 1))      /* To catch #i          */
57*b1cdbd2cSJim Jagielski #define L_pragma        ('p' + ('a' << 1))
58*b1cdbd2cSJim Jagielski #define L_undef         ('u' + ('d' << 1))
59*b1cdbd2cSJim Jagielski #define L_error         ('e' + ('r' << 1))      /* BP 5.3.92, #error */
60*b1cdbd2cSJim Jagielski #define MAXLINE 80                              /* BP 5.3.92, #error */
61*b1cdbd2cSJim Jagielski #if OSL_DEBUG_LEVEL > 1
62*b1cdbd2cSJim Jagielski #define L_debug         ('d' + ('b' << 1))      /* #debug               */
63*b1cdbd2cSJim Jagielski #define L_nodebug       ('n' + ('d' << 1))      /* #nodebug             */
64*b1cdbd2cSJim Jagielski #endif
65*b1cdbd2cSJim Jagielski 
66*b1cdbd2cSJim Jagielski 
InitCpp2()67*b1cdbd2cSJim Jagielski void InitCpp2()
68*b1cdbd2cSJim Jagielski {
69*b1cdbd2cSJim Jagielski 
70*b1cdbd2cSJim Jagielski }
71*b1cdbd2cSJim Jagielski 
72*b1cdbd2cSJim Jagielski 
73*b1cdbd2cSJim Jagielski int
control(int counter)74*b1cdbd2cSJim Jagielski control(int counter)
75*b1cdbd2cSJim Jagielski /*
76*b1cdbd2cSJim Jagielski  * Process #control lines.  Simple commands are processed inline,
77*b1cdbd2cSJim Jagielski  * while complex commands have their own subroutines.
78*b1cdbd2cSJim Jagielski  *
79*b1cdbd2cSJim Jagielski  * The counter is used to force out a newline before #line, and
80*b1cdbd2cSJim Jagielski  * #pragma commands.  This prevents these commands from ending up at
81*b1cdbd2cSJim Jagielski  * the end of the previous line if cpp is invoked with the -C option.
82*b1cdbd2cSJim Jagielski  */
83*b1cdbd2cSJim Jagielski {
84*b1cdbd2cSJim Jagielski         register int            c;
85*b1cdbd2cSJim Jagielski         register char           *tp;
86*b1cdbd2cSJim Jagielski         register int            hash;
87*b1cdbd2cSJim Jagielski         char                    *ep;
88*b1cdbd2cSJim Jagielski 
89*b1cdbd2cSJim Jagielski         c = skipws();
90*b1cdbd2cSJim Jagielski         if (c == '\n' || c == EOF_CHAR)
91*b1cdbd2cSJim Jagielski             return (counter + 1);
92*b1cdbd2cSJim Jagielski         if (!isdigit(c))
93*b1cdbd2cSJim Jagielski             scanid(c);                  /* Get #word to token[]         */
94*b1cdbd2cSJim Jagielski         else {
95*b1cdbd2cSJim Jagielski             unget();                    /* Hack -- allow #123 as a      */
96*b1cdbd2cSJim Jagielski             strcpy(token, "line");      /* synonym for #line 123        */
97*b1cdbd2cSJim Jagielski         }
98*b1cdbd2cSJim Jagielski         hash = (token[1] == EOS) ? L_nogood : (token[0] + (token[2] << 1));
99*b1cdbd2cSJim Jagielski         switch (hash) {
100*b1cdbd2cSJim Jagielski         case L_assert:  tp = "assert";          break;
101*b1cdbd2cSJim Jagielski         case L_define:  tp = "define";          break;
102*b1cdbd2cSJim Jagielski         case L_elif:    tp = "elif";            break;
103*b1cdbd2cSJim Jagielski         case L_else:    tp = "else";            break;
104*b1cdbd2cSJim Jagielski         case L_endif:   tp = "endif";           break;
105*b1cdbd2cSJim Jagielski         case L_if:      tp = "if";              break;
106*b1cdbd2cSJim Jagielski         case L_ifdef:   tp = "ifdef";           break;
107*b1cdbd2cSJim Jagielski         case L_ifndef:  tp = "ifndef";          break;
108*b1cdbd2cSJim Jagielski         case L_include: tp = "include";         break;
109*b1cdbd2cSJim Jagielski         case L_line:    tp = "line";            break;
110*b1cdbd2cSJim Jagielski         case L_pragma:  tp = "pragma";          break;
111*b1cdbd2cSJim Jagielski         case L_undef:   tp = "undef";           break;
112*b1cdbd2cSJim Jagielski         case L_error:   tp = "error";           break;
113*b1cdbd2cSJim Jagielski #if OSL_DEBUG_LEVEL > 1
114*b1cdbd2cSJim Jagielski         case L_debug:   tp = "debug";           break;
115*b1cdbd2cSJim Jagielski         case L_nodebug: tp = "nodebug";         break;
116*b1cdbd2cSJim Jagielski #endif
117*b1cdbd2cSJim Jagielski         default:        hash = L_nogood;
118*b1cdbd2cSJim Jagielski         case L_nogood:  tp = "";                break;
119*b1cdbd2cSJim Jagielski         }
120*b1cdbd2cSJim Jagielski         if (!streq(tp, token))
121*b1cdbd2cSJim Jagielski             hash = L_nogood;
122*b1cdbd2cSJim Jagielski         /*
123*b1cdbd2cSJim Jagielski          * hash is set to a unique value corresponding to the
124*b1cdbd2cSJim Jagielski          * control keyword (or L_nogood if we think it's nonsense).
125*b1cdbd2cSJim Jagielski          */
126*b1cdbd2cSJim Jagielski         if (infile->fp == NULL)
127*b1cdbd2cSJim Jagielski             cwarn("Control line \"%s\" within macro expansion", token);
128*b1cdbd2cSJim Jagielski         if (!compiling) {                       /* Not compiling now    */
129*b1cdbd2cSJim Jagielski             switch (hash) {
130*b1cdbd2cSJim Jagielski             case L_if:                          /* These can't turn     */
131*b1cdbd2cSJim Jagielski             case L_ifdef:                       /*  compilation on, but */
132*b1cdbd2cSJim Jagielski             case L_ifndef:                      /*   we must nest #if's */
133*b1cdbd2cSJim Jagielski                 if (++ifptr >= &ifstack[BLK_NEST])
134*b1cdbd2cSJim Jagielski                     goto if_nest_err;
135*b1cdbd2cSJim Jagielski                 *ifptr = 0;                     /* !WAS_COMPILING       */
136*b1cdbd2cSJim Jagielski             case L_line:                        /* Many                 */
137*b1cdbd2cSJim Jagielski             /*
138*b1cdbd2cSJim Jagielski              * Are pragma's always processed?
139*b1cdbd2cSJim Jagielski              */
140*b1cdbd2cSJim Jagielski             case L_pragma:                      /*  options             */
141*b1cdbd2cSJim Jagielski             case L_include:                     /*   are uninteresting  */
142*b1cdbd2cSJim Jagielski             case L_define:                      /*    if we             */
143*b1cdbd2cSJim Jagielski             case L_undef:                       /*     aren't           */
144*b1cdbd2cSJim Jagielski             case L_assert:                      /*      compiling.      */
145*b1cdbd2cSJim Jagielski             case L_error:                       /* BP 5.3.92, #error */
146*b1cdbd2cSJim Jagielski dump_line:      skipnl();                       /* Ignore rest of line  */
147*b1cdbd2cSJim Jagielski                 return (counter + 1);
148*b1cdbd2cSJim Jagielski             }
149*b1cdbd2cSJim Jagielski         }
150*b1cdbd2cSJim Jagielski         /*
151*b1cdbd2cSJim Jagielski          * Make sure that #line and #pragma are output on a fresh line.
152*b1cdbd2cSJim Jagielski          */
153*b1cdbd2cSJim Jagielski         if (counter > 0 && (hash == L_line || hash == L_pragma)) {
154*b1cdbd2cSJim Jagielski             PUTCHAR('\n');
155*b1cdbd2cSJim Jagielski             counter--;
156*b1cdbd2cSJim Jagielski         }
157*b1cdbd2cSJim Jagielski         switch (hash) {
158*b1cdbd2cSJim Jagielski         case L_line:
159*b1cdbd2cSJim Jagielski             /*
160*b1cdbd2cSJim Jagielski              * Parse the line to update the line number and "progname"
161*b1cdbd2cSJim Jagielski              * field and line number for the next input line.
162*b1cdbd2cSJim Jagielski              * Set wrongline to force it out later.
163*b1cdbd2cSJim Jagielski              */
164*b1cdbd2cSJim Jagielski             c = skipws();
165*b1cdbd2cSJim Jagielski             workp = work;                       /* Save name in work    */
166*b1cdbd2cSJim Jagielski             while (c != '\n' && c != EOF_CHAR) {
167*b1cdbd2cSJim Jagielski                 save(c);
168*b1cdbd2cSJim Jagielski                 c = get();
169*b1cdbd2cSJim Jagielski             }
170*b1cdbd2cSJim Jagielski             unget();
171*b1cdbd2cSJim Jagielski             save(EOS);
172*b1cdbd2cSJim Jagielski             /*
173*b1cdbd2cSJim Jagielski              * Split #line argument into <line-number> and <name>
174*b1cdbd2cSJim Jagielski              * We subtract 1 as we want the number of the next line.
175*b1cdbd2cSJim Jagielski              */
176*b1cdbd2cSJim Jagielski             line = atoi(work) - 1;              /* Reset line number    */
177*b1cdbd2cSJim Jagielski             for (tp = work; isdigit(*tp) || type[(int)*tp] == SPA; tp++)
178*b1cdbd2cSJim Jagielski                 ;                               /* Skip over digits     */
179*b1cdbd2cSJim Jagielski             if (*tp != EOS) {                   /* Got a filename, so:  */
180*b1cdbd2cSJim Jagielski                 if (*tp == '"' && (ep = strrchr(tp + 1, '"')) != NULL) {
181*b1cdbd2cSJim Jagielski                     tp++;                       /* Skip over left quote */
182*b1cdbd2cSJim Jagielski                     *ep = EOS;                  /* And ignore right one */
183*b1cdbd2cSJim Jagielski                 }
184*b1cdbd2cSJim Jagielski                 if (infile->progname != NULL)   /* Give up the old name */
185*b1cdbd2cSJim Jagielski                     free(infile->progname);     /* if it's allocated.   */
186*b1cdbd2cSJim Jagielski                 infile->progname = savestring(tp);
187*b1cdbd2cSJim Jagielski             }
188*b1cdbd2cSJim Jagielski             wrongline = TRUE;                   /* Force output later   */
189*b1cdbd2cSJim Jagielski             break;
190*b1cdbd2cSJim Jagielski 
191*b1cdbd2cSJim Jagielski         case L_include:
192*b1cdbd2cSJim Jagielski             doinclude();
193*b1cdbd2cSJim Jagielski             break;
194*b1cdbd2cSJim Jagielski 
195*b1cdbd2cSJim Jagielski         case L_define:
196*b1cdbd2cSJim Jagielski             dodefine();
197*b1cdbd2cSJim Jagielski             break;
198*b1cdbd2cSJim Jagielski 
199*b1cdbd2cSJim Jagielski         case L_undef:
200*b1cdbd2cSJim Jagielski             doundef();
201*b1cdbd2cSJim Jagielski             break;
202*b1cdbd2cSJim Jagielski 
203*b1cdbd2cSJim Jagielski         case L_else:
204*b1cdbd2cSJim Jagielski             if (ifptr == &ifstack[0])
205*b1cdbd2cSJim Jagielski                 goto nest_err;
206*b1cdbd2cSJim Jagielski             else if ((*ifptr & ELSE_SEEN) != 0)
207*b1cdbd2cSJim Jagielski                 goto else_seen_err;
208*b1cdbd2cSJim Jagielski             *ifptr |= ELSE_SEEN;
209*b1cdbd2cSJim Jagielski             if ((*ifptr & WAS_COMPILING) != 0) {
210*b1cdbd2cSJim Jagielski                 if (compiling || (*ifptr & TRUE_SEEN) != 0)
211*b1cdbd2cSJim Jagielski                     compiling = FALSE;
212*b1cdbd2cSJim Jagielski                 else {
213*b1cdbd2cSJim Jagielski                     compiling = TRUE;
214*b1cdbd2cSJim Jagielski                 }
215*b1cdbd2cSJim Jagielski             }
216*b1cdbd2cSJim Jagielski             break;
217*b1cdbd2cSJim Jagielski 
218*b1cdbd2cSJim Jagielski         case L_elif:
219*b1cdbd2cSJim Jagielski             if (ifptr == &ifstack[0])
220*b1cdbd2cSJim Jagielski                 goto nest_err;
221*b1cdbd2cSJim Jagielski             else if ((*ifptr & ELSE_SEEN) != 0) {
222*b1cdbd2cSJim Jagielski else_seen_err:  cerror("#%s may not follow #else", token);
223*b1cdbd2cSJim Jagielski                 goto dump_line;
224*b1cdbd2cSJim Jagielski             }
225*b1cdbd2cSJim Jagielski             if ((*ifptr & (WAS_COMPILING | TRUE_SEEN)) != WAS_COMPILING) {
226*b1cdbd2cSJim Jagielski                 compiling = FALSE;              /* Done compiling stuff */
227*b1cdbd2cSJim Jagielski                 goto dump_line;                 /* Skip this clause     */
228*b1cdbd2cSJim Jagielski             }
229*b1cdbd2cSJim Jagielski             doif(L_if);
230*b1cdbd2cSJim Jagielski             break;
231*b1cdbd2cSJim Jagielski 
232*b1cdbd2cSJim Jagielski         case L_if:
233*b1cdbd2cSJim Jagielski         case L_ifdef:
234*b1cdbd2cSJim Jagielski         case L_ifndef:
235*b1cdbd2cSJim Jagielski             if (++ifptr >= &ifstack[BLK_NEST])
236*b1cdbd2cSJim Jagielski if_nest_err:    cfatal("Too many nested #%s statements", token);
237*b1cdbd2cSJim Jagielski             *ifptr = WAS_COMPILING;
238*b1cdbd2cSJim Jagielski             doif(hash);
239*b1cdbd2cSJim Jagielski             break;
240*b1cdbd2cSJim Jagielski 
241*b1cdbd2cSJim Jagielski         case L_endif:
242*b1cdbd2cSJim Jagielski             if (ifptr == &ifstack[0]) {
243*b1cdbd2cSJim Jagielski nest_err:       cerror("#%s must be in an #if", token);
244*b1cdbd2cSJim Jagielski                 goto dump_line;
245*b1cdbd2cSJim Jagielski             }
246*b1cdbd2cSJim Jagielski             if (!compiling && (*ifptr & WAS_COMPILING) != 0)
247*b1cdbd2cSJim Jagielski                 wrongline = TRUE;
248*b1cdbd2cSJim Jagielski             compiling = ((*ifptr & WAS_COMPILING) != 0);
249*b1cdbd2cSJim Jagielski             --ifptr;
250*b1cdbd2cSJim Jagielski             break;
251*b1cdbd2cSJim Jagielski 
252*b1cdbd2cSJim Jagielski         case L_assert:
253*b1cdbd2cSJim Jagielski             if (eval() == 0)
254*b1cdbd2cSJim Jagielski                 cerror("Preprocessor assertion failure", NULLST);
255*b1cdbd2cSJim Jagielski             break;
256*b1cdbd2cSJim Jagielski 
257*b1cdbd2cSJim Jagielski         case L_pragma:
258*b1cdbd2cSJim Jagielski             /*
259*b1cdbd2cSJim Jagielski              * #pragma is provided to pass "options" to later
260*b1cdbd2cSJim Jagielski              * passes of the compiler.  cpp doesn't have any yet.
261*b1cdbd2cSJim Jagielski              */
262*b1cdbd2cSJim Jagielski             fprintf( pCppOut, "#pragma ");
263*b1cdbd2cSJim Jagielski             while ((c = get()) != '\n' && c != EOF_CHAR)
264*b1cdbd2cSJim Jagielski                 cput(c);
265*b1cdbd2cSJim Jagielski             unget();
266*b1cdbd2cSJim Jagielski             break;
267*b1cdbd2cSJim Jagielski 
268*b1cdbd2cSJim Jagielski #if OSL_DEBUG_LEVEL > 1
269*b1cdbd2cSJim Jagielski         case L_debug:
270*b1cdbd2cSJim Jagielski             if (debug == 0)
271*b1cdbd2cSJim Jagielski                 dumpdef("debug set on");
272*b1cdbd2cSJim Jagielski             debug++;
273*b1cdbd2cSJim Jagielski             break;
274*b1cdbd2cSJim Jagielski 
275*b1cdbd2cSJim Jagielski         case L_nodebug:
276*b1cdbd2cSJim Jagielski             debug--;
277*b1cdbd2cSJim Jagielski             break;
278*b1cdbd2cSJim Jagielski #endif
279*b1cdbd2cSJim Jagielski         case L_error:                       /* BP 5.3.92, #error */
280*b1cdbd2cSJim Jagielski         {
281*b1cdbd2cSJim Jagielski             fprintf( pCppOut, "cpp: line %u, Error directive: ", line );
282*b1cdbd2cSJim Jagielski             while ((c = get()) != '\n' && c != EOF_CHAR)
283*b1cdbd2cSJim Jagielski                 cput(c);
284*b1cdbd2cSJim Jagielski             fprintf( pCppOut, "\n" );
285*b1cdbd2cSJim Jagielski             exit( 1 );
286*b1cdbd2cSJim Jagielski             break;
287*b1cdbd2cSJim Jagielski         }
288*b1cdbd2cSJim Jagielski         default:
289*b1cdbd2cSJim Jagielski             /*
290*b1cdbd2cSJim Jagielski              * Undefined #control keyword.
291*b1cdbd2cSJim Jagielski              * Note: the correct behavior may be to warn and
292*b1cdbd2cSJim Jagielski              * pass the line to a subsequent compiler pass.
293*b1cdbd2cSJim Jagielski              * This would allow #asm or similar extensions.
294*b1cdbd2cSJim Jagielski              */
295*b1cdbd2cSJim Jagielski             cerror("Illegal # command \"%s\"", token);
296*b1cdbd2cSJim Jagielski             break;
297*b1cdbd2cSJim Jagielski         }
298*b1cdbd2cSJim Jagielski         if (hash != L_include) {
299*b1cdbd2cSJim Jagielski #if OLD_PREPROCESSOR
300*b1cdbd2cSJim Jagielski             /*
301*b1cdbd2cSJim Jagielski              * Ignore the rest of the #control line so you can write
302*b1cdbd2cSJim Jagielski              *          #if     foo
303*b1cdbd2cSJim Jagielski              *          #endif  foo
304*b1cdbd2cSJim Jagielski              */
305*b1cdbd2cSJim Jagielski             goto dump_line;                     /* Take common exit     */
306*b1cdbd2cSJim Jagielski #else
307*b1cdbd2cSJim Jagielski             if (skipws() != '\n') {
308*b1cdbd2cSJim Jagielski                 cwarn("Unexpected text in #control line ignored", NULLST);
309*b1cdbd2cSJim Jagielski                 skipnl();
310*b1cdbd2cSJim Jagielski             }
311*b1cdbd2cSJim Jagielski #endif
312*b1cdbd2cSJim Jagielski         }
313*b1cdbd2cSJim Jagielski         return (counter + 1);
314*b1cdbd2cSJim Jagielski }
315*b1cdbd2cSJim Jagielski 
316*b1cdbd2cSJim Jagielski FILE_LOCAL
doif(int hash)317*b1cdbd2cSJim Jagielski void doif(int hash)
318*b1cdbd2cSJim Jagielski /*
319*b1cdbd2cSJim Jagielski  * Process an #if, #ifdef, or #ifndef.  The latter two are straightforward,
320*b1cdbd2cSJim Jagielski  * while #if needs a subroutine of its own to evaluate the expression.
321*b1cdbd2cSJim Jagielski  *
322*b1cdbd2cSJim Jagielski  * doif() is called only if compiling is TRUE.  If false, compilation
323*b1cdbd2cSJim Jagielski  * is always supressed, so we don't need to evaluate anything.  This
324*b1cdbd2cSJim Jagielski  * supresses unnecessary warnings.
325*b1cdbd2cSJim Jagielski  */
326*b1cdbd2cSJim Jagielski {
327*b1cdbd2cSJim Jagielski         register int            c;
328*b1cdbd2cSJim Jagielski         register int            found;
329*b1cdbd2cSJim Jagielski 
330*b1cdbd2cSJim Jagielski         if ((c = skipws()) == '\n' || c == EOF_CHAR) {
331*b1cdbd2cSJim Jagielski             unget();
332*b1cdbd2cSJim Jagielski             goto badif;
333*b1cdbd2cSJim Jagielski         }
334*b1cdbd2cSJim Jagielski         if (hash == L_if) {
335*b1cdbd2cSJim Jagielski             unget();
336*b1cdbd2cSJim Jagielski             found = (eval() != 0);      /* Evaluate expr, != 0 is  TRUE */
337*b1cdbd2cSJim Jagielski             hash = L_ifdef;             /* #if is now like #ifdef       */
338*b1cdbd2cSJim Jagielski         }
339*b1cdbd2cSJim Jagielski         else {
340*b1cdbd2cSJim Jagielski             if (type[c] != LET)         /* Next non-blank isn't letter  */
341*b1cdbd2cSJim Jagielski                 goto badif;             /* ... is an error              */
342*b1cdbd2cSJim Jagielski             found = (lookid(c) != NULL); /* Look for it in symbol table */
343*b1cdbd2cSJim Jagielski         }
344*b1cdbd2cSJim Jagielski         if (found == (hash == L_ifdef)) {
345*b1cdbd2cSJim Jagielski             compiling = TRUE;
346*b1cdbd2cSJim Jagielski             *ifptr |= TRUE_SEEN;
347*b1cdbd2cSJim Jagielski         }
348*b1cdbd2cSJim Jagielski         else {
349*b1cdbd2cSJim Jagielski             compiling = FALSE;
350*b1cdbd2cSJim Jagielski         }
351*b1cdbd2cSJim Jagielski         return;
352*b1cdbd2cSJim Jagielski 
353*b1cdbd2cSJim Jagielski badif:  cerror("#if, #ifdef, or #ifndef without an argument", NULLST);
354*b1cdbd2cSJim Jagielski #if !OLD_PREPROCESSOR
355*b1cdbd2cSJim Jagielski         skipnl();                               /* Prevent an extra     */
356*b1cdbd2cSJim Jagielski         unget();                                /* Error message        */
357*b1cdbd2cSJim Jagielski #endif
358*b1cdbd2cSJim Jagielski         return;
359*b1cdbd2cSJim Jagielski }
360*b1cdbd2cSJim Jagielski 
361*b1cdbd2cSJim Jagielski FILE_LOCAL
doinclude()362*b1cdbd2cSJim Jagielski void doinclude()
363*b1cdbd2cSJim Jagielski /*
364*b1cdbd2cSJim Jagielski  * Process the #include control line.
365*b1cdbd2cSJim Jagielski  * There are three variations:
366*b1cdbd2cSJim Jagielski  *      #include "file"         search somewhere relative to the
367*b1cdbd2cSJim Jagielski  *                              current source file, if not found,
368*b1cdbd2cSJim Jagielski  *                              treat as #include <file>.
369*b1cdbd2cSJim Jagielski  *      #include <file>         Search in an implementation-dependent
370*b1cdbd2cSJim Jagielski  *                              list of places.
371*b1cdbd2cSJim Jagielski  *      #include token          Expand the token, it must be one of
372*b1cdbd2cSJim Jagielski  *                              "file" or <file>, process as such.
373*b1cdbd2cSJim Jagielski  *
374*b1cdbd2cSJim Jagielski  * Note: the November 12 draft forbids '>' in the #include <file> format.
375*b1cdbd2cSJim Jagielski  * This restriction is unnecessary and not implemented.
376*b1cdbd2cSJim Jagielski  */
377*b1cdbd2cSJim Jagielski {
378*b1cdbd2cSJim Jagielski         register int            c;
379*b1cdbd2cSJim Jagielski         register int            delim;
380*b1cdbd2cSJim Jagielski #if HOST == SYS_VMS
381*b1cdbd2cSJim Jagielski         char                    def_filename[NAM$C_MAXRSS + 1];
382*b1cdbd2cSJim Jagielski #endif
383*b1cdbd2cSJim Jagielski 
384*b1cdbd2cSJim Jagielski         delim = macroid(skipws());
385*b1cdbd2cSJim Jagielski         if (delim != '<' && delim != '"')
386*b1cdbd2cSJim Jagielski             goto incerr;
387*b1cdbd2cSJim Jagielski         if (delim == '<')
388*b1cdbd2cSJim Jagielski             delim = '>';
389*b1cdbd2cSJim Jagielski         workp = work;
390*b1cdbd2cSJim Jagielski         instring = TRUE;                /* Accept all characters        */
391*b1cdbd2cSJim Jagielski #ifdef CONTROL_COMMENTS_NOT_ALLOWED
392*b1cdbd2cSJim Jagielski         while ((c = get()) != '\n' && c != EOF_CHAR)
393*b1cdbd2cSJim Jagielski             save(c);                    /* Put it away.                 */
394*b1cdbd2cSJim Jagielski         unget();                        /* Force nl after includee      */
395*b1cdbd2cSJim Jagielski         /*
396*b1cdbd2cSJim Jagielski          * The draft is unclear if the following should be done.
397*b1cdbd2cSJim Jagielski          */
398*b1cdbd2cSJim Jagielski         while (--workp >= work && *workp == ' ')
399*b1cdbd2cSJim Jagielski             ;                           /* Trim blanks from filename    */
400*b1cdbd2cSJim Jagielski         if (*workp != delim)
401*b1cdbd2cSJim Jagielski             goto incerr;
402*b1cdbd2cSJim Jagielski #else
403*b1cdbd2cSJim Jagielski         while ((c = get()) != delim && c != EOF_CHAR)
404*b1cdbd2cSJim Jagielski             save(c);
405*b1cdbd2cSJim Jagielski #endif
406*b1cdbd2cSJim Jagielski         *workp = EOS;                   /* Terminate filename           */
407*b1cdbd2cSJim Jagielski         instring = FALSE;
408*b1cdbd2cSJim Jagielski #if HOST == SYS_VMS
409*b1cdbd2cSJim Jagielski         /*
410*b1cdbd2cSJim Jagielski          * Assume the default .h filetype.
411*b1cdbd2cSJim Jagielski          */
412*b1cdbd2cSJim Jagielski         if (!vmsparse(work, ".H", def_filename)) {
413*b1cdbd2cSJim Jagielski             perror(work);               /* Oops.                        */
414*b1cdbd2cSJim Jagielski             goto incerr;
415*b1cdbd2cSJim Jagielski         }
416*b1cdbd2cSJim Jagielski         else if (openinclude(def_filename, (delim == '"')))
417*b1cdbd2cSJim Jagielski             return;
418*b1cdbd2cSJim Jagielski #else
419*b1cdbd2cSJim Jagielski         if (openinclude(work, (delim == '"')))
420*b1cdbd2cSJim Jagielski             return;
421*b1cdbd2cSJim Jagielski #endif
422*b1cdbd2cSJim Jagielski         /*
423*b1cdbd2cSJim Jagielski          * No sense continuing if #include file isn't there.
424*b1cdbd2cSJim Jagielski          */
425*b1cdbd2cSJim Jagielski         cfatal("Cannot open include file \"%s\"", work);
426*b1cdbd2cSJim Jagielski 
427*b1cdbd2cSJim Jagielski incerr: cerror("#include syntax error", NULLST);
428*b1cdbd2cSJim Jagielski         return;
429*b1cdbd2cSJim Jagielski }
430*b1cdbd2cSJim Jagielski 
431*b1cdbd2cSJim Jagielski FILE_LOCAL int
openinclude(char * filename,int searchlocal)432*b1cdbd2cSJim Jagielski openinclude(char* filename, int searchlocal)
433*b1cdbd2cSJim Jagielski /*
434*b1cdbd2cSJim Jagielski  * Actually open an include file.  This routine is only called from
435*b1cdbd2cSJim Jagielski  * doinclude() above, but was written as a separate subroutine for
436*b1cdbd2cSJim Jagielski  * programmer convenience.  It searches the list of directories
437*b1cdbd2cSJim Jagielski  * and actually opens the file, linking it into the list of
438*b1cdbd2cSJim Jagielski  * active files.  Returns TRUE if the file was opened, FALSE
439*b1cdbd2cSJim Jagielski  * if openinclude() fails.  No error message is printed.
440*b1cdbd2cSJim Jagielski  */
441*b1cdbd2cSJim Jagielski {
442*b1cdbd2cSJim Jagielski         register char           **incptr;
443*b1cdbd2cSJim Jagielski #if HOST == SYS_VMS
444*b1cdbd2cSJim Jagielski #if NFWORK < (NAM$C_MAXRSS + 1)
445*b1cdbd2cSJim Jagielski     << error, NFWORK is not greater than NAM$C_MAXRSS >>
446*b1cdbd2cSJim Jagielski #endif
447*b1cdbd2cSJim Jagielski #endif
448*b1cdbd2cSJim Jagielski         char                    tmpname[NFWORK]; /* Filename work area   */
449*b1cdbd2cSJim Jagielski 
450*b1cdbd2cSJim Jagielski         if (searchlocal) {
451*b1cdbd2cSJim Jagielski             /*
452*b1cdbd2cSJim Jagielski              * Look in local directory first
453*b1cdbd2cSJim Jagielski              */
454*b1cdbd2cSJim Jagielski #if HOST == SYS_UNIX
455*b1cdbd2cSJim Jagielski             /*
456*b1cdbd2cSJim Jagielski              * Try to open filename relative to the directory of the current
457*b1cdbd2cSJim Jagielski              * source file (as opposed to the current directory). (ARF, SCK).
458*b1cdbd2cSJim Jagielski              */
459*b1cdbd2cSJim Jagielski             if (filename[0] != '/'
460*b1cdbd2cSJim Jagielski              && hasdirectory(infile->filename, tmpname))
461*b1cdbd2cSJim Jagielski                 strcat(tmpname, filename);
462*b1cdbd2cSJim Jagielski             else {
463*b1cdbd2cSJim Jagielski                 strcpy(tmpname, filename);
464*b1cdbd2cSJim Jagielski             }
465*b1cdbd2cSJim Jagielski #else
466*b1cdbd2cSJim Jagielski             if (!hasdirectory(filename, tmpname)
467*b1cdbd2cSJim Jagielski              && hasdirectory(infile->filename, tmpname))
468*b1cdbd2cSJim Jagielski                 strcat(tmpname, filename);
469*b1cdbd2cSJim Jagielski             else {
470*b1cdbd2cSJim Jagielski                 strcpy(tmpname, filename);
471*b1cdbd2cSJim Jagielski             }
472*b1cdbd2cSJim Jagielski #endif
473*b1cdbd2cSJim Jagielski             if (openfile(tmpname))
474*b1cdbd2cSJim Jagielski                 return (TRUE);
475*b1cdbd2cSJim Jagielski         }
476*b1cdbd2cSJim Jagielski         /*
477*b1cdbd2cSJim Jagielski          * Look in any directories specified by -I command line
478*b1cdbd2cSJim Jagielski          * arguments, then in the builtin search list.
479*b1cdbd2cSJim Jagielski          */
480*b1cdbd2cSJim Jagielski         for (incptr = incdir; incptr < incend; incptr++) {
481*b1cdbd2cSJim Jagielski             if (strlen(*incptr) + strlen(filename) >= (NFWORK - 1))
482*b1cdbd2cSJim Jagielski                 cfatal("Filename work buffer overflow", NULLST);
483*b1cdbd2cSJim Jagielski             else {
484*b1cdbd2cSJim Jagielski #if HOST == SYS_UNIX
485*b1cdbd2cSJim Jagielski                 if (filename[0] == '/')
486*b1cdbd2cSJim Jagielski                     strcpy(tmpname, filename);
487*b1cdbd2cSJim Jagielski                 else {
488*b1cdbd2cSJim Jagielski                     sprintf(tmpname, "%s/%s", *incptr, filename);
489*b1cdbd2cSJim Jagielski                 }
490*b1cdbd2cSJim Jagielski #elif HOST == SYS_UNKNOWN
491*b1cdbd2cSJim Jagielski                 if (filename[0] == '\\')
492*b1cdbd2cSJim Jagielski                     strcpy(tmpname, filename);
493*b1cdbd2cSJim Jagielski                 else {
494*b1cdbd2cSJim Jagielski                     sprintf(tmpname, "%s\\%s", *incptr, filename);
495*b1cdbd2cSJim Jagielski                 }
496*b1cdbd2cSJim Jagielski #else
497*b1cdbd2cSJim Jagielski                 if (!hasdirectory(filename, tmpname))
498*b1cdbd2cSJim Jagielski                     sprintf(tmpname, "%s%s", *incptr, filename);
499*b1cdbd2cSJim Jagielski #endif
500*b1cdbd2cSJim Jagielski                 if (openfile(tmpname))
501*b1cdbd2cSJim Jagielski                     return (TRUE);
502*b1cdbd2cSJim Jagielski             }
503*b1cdbd2cSJim Jagielski         }
504*b1cdbd2cSJim Jagielski         return (FALSE);
505*b1cdbd2cSJim Jagielski }
506*b1cdbd2cSJim Jagielski 
507*b1cdbd2cSJim Jagielski FILE_LOCAL int
hasdirectory(char * source,char * result)508*b1cdbd2cSJim Jagielski hasdirectory(char* source, char* result)
509*b1cdbd2cSJim Jagielski /*
510*b1cdbd2cSJim Jagielski  * If a device or directory is found in the source filename string, the
511*b1cdbd2cSJim Jagielski  * node/device/directory part of the string is copied to result and
512*b1cdbd2cSJim Jagielski  * hasdirectory returns TRUE.  Else, nothing is copied and it returns FALSE.
513*b1cdbd2cSJim Jagielski  */
514*b1cdbd2cSJim Jagielski {
515*b1cdbd2cSJim Jagielski #if HOST == SYS_UNIX
516*b1cdbd2cSJim Jagielski         register char           *tp;
517*b1cdbd2cSJim Jagielski 
518*b1cdbd2cSJim Jagielski         if ((tp = strrchr(source, '/')) == NULL)
519*b1cdbd2cSJim Jagielski             return (FALSE);
520*b1cdbd2cSJim Jagielski         else {
521*b1cdbd2cSJim Jagielski             strncpy(result, source, tp - source + 1);
522*b1cdbd2cSJim Jagielski             result[tp - source + 1] = EOS;
523*b1cdbd2cSJim Jagielski             return (TRUE);
524*b1cdbd2cSJim Jagielski         }
525*b1cdbd2cSJim Jagielski #else
526*b1cdbd2cSJim Jagielski #if HOST == SYS_VMS
527*b1cdbd2cSJim Jagielski         if (vmsparse(source, NULLST, result)
528*b1cdbd2cSJim Jagielski          && result[0] != EOS)
529*b1cdbd2cSJim Jagielski             return (TRUE);
530*b1cdbd2cSJim Jagielski         else {
531*b1cdbd2cSJim Jagielski             return (FALSE);
532*b1cdbd2cSJim Jagielski         }
533*b1cdbd2cSJim Jagielski #else
534*b1cdbd2cSJim Jagielski         /*
535*b1cdbd2cSJim Jagielski          * Random DEC operating system (RSX, RT11, RSTS/E)
536*b1cdbd2cSJim Jagielski          */
537*b1cdbd2cSJim Jagielski         register char           *tp;
538*b1cdbd2cSJim Jagielski 
539*b1cdbd2cSJim Jagielski         if ((tp = strrchr(source, ']')) == NULL
540*b1cdbd2cSJim Jagielski          && (tp = strrchr(source, ':')) == NULL)
541*b1cdbd2cSJim Jagielski             return (FALSE);
542*b1cdbd2cSJim Jagielski         else {
543*b1cdbd2cSJim Jagielski             strncpy(result, source, tp - source + 1);
544*b1cdbd2cSJim Jagielski             result[tp - source + 1] = EOS;
545*b1cdbd2cSJim Jagielski             return (TRUE);
546*b1cdbd2cSJim Jagielski         }
547*b1cdbd2cSJim Jagielski #endif
548*b1cdbd2cSJim Jagielski #endif
549*b1cdbd2cSJim Jagielski }
550*b1cdbd2cSJim Jagielski 
551*b1cdbd2cSJim Jagielski #if HOST == SYS_VMS
552*b1cdbd2cSJim Jagielski 
553*b1cdbd2cSJim Jagielski /*
554*b1cdbd2cSJim Jagielski  * EXP_DEV is set if a device was specified, EXP_DIR if a directory
555*b1cdbd2cSJim Jagielski  * is specified.  (Both set indicate a file-logical, but EXP_DEV
556*b1cdbd2cSJim Jagielski  * would be set by itself if you are reading, say, SYS$INPUT:)
557*b1cdbd2cSJim Jagielski  */
558*b1cdbd2cSJim Jagielski #define DEVDIR (NAM$M_EXP_DEV | NAM$M_EXP_DIR)
559*b1cdbd2cSJim Jagielski 
560*b1cdbd2cSJim Jagielski FILE_LOCAL int
vmsparse(source,defstring,result)561*b1cdbd2cSJim Jagielski vmsparse(source, defstring, result)
562*b1cdbd2cSJim Jagielski char            *source;
563*b1cdbd2cSJim Jagielski char            *defstring;     /* non-NULL -> default string.          */
564*b1cdbd2cSJim Jagielski char            *result;        /* Size is at least NAM$C_MAXRSS + 1    */
565*b1cdbd2cSJim Jagielski /*
566*b1cdbd2cSJim Jagielski  * Parse the source string, applying the default (properly, using
567*b1cdbd2cSJim Jagielski  * the system parse routine), storing it in result.
568*b1cdbd2cSJim Jagielski  * TRUE if it parsed, FALSE on error.
569*b1cdbd2cSJim Jagielski  *
570*b1cdbd2cSJim Jagielski  * If defstring is NULL, there are no defaults and result gets
571*b1cdbd2cSJim Jagielski  * (just) the node::[directory] part of the string (possibly "")
572*b1cdbd2cSJim Jagielski  */
573*b1cdbd2cSJim Jagielski {
574*b1cdbd2cSJim Jagielski         struct FAB      fab = cc$rms_fab;       /* File access block    */
575*b1cdbd2cSJim Jagielski         struct NAM      nam = cc$rms_nam;       /* File name block      */
576*b1cdbd2cSJim Jagielski         char            fullname[NAM$C_MAXRSS + 1];
577*b1cdbd2cSJim Jagielski         register char   *rp;                    /* Result pointer       */
578*b1cdbd2cSJim Jagielski 
579*b1cdbd2cSJim Jagielski         fab.fab$l_nam = &nam;                   /* fab -> nam           */
580*b1cdbd2cSJim Jagielski         fab.fab$l_fna = source;                 /* Source filename      */
581*b1cdbd2cSJim Jagielski         fab.fab$b_fns = strlen(source);         /* Size of source       */
582*b1cdbd2cSJim Jagielski         fab.fab$l_dna = defstring;              /* Default string       */
583*b1cdbd2cSJim Jagielski         if (defstring != NULLST)
584*b1cdbd2cSJim Jagielski             fab.fab$b_dns = strlen(defstring);  /* Size of default      */
585*b1cdbd2cSJim Jagielski         nam.nam$l_esa = fullname;               /* Expanded filename    */
586*b1cdbd2cSJim Jagielski         nam.nam$b_ess = NAM$C_MAXRSS;           /* Expanded name size   */
587*b1cdbd2cSJim Jagielski         if (sys$parse(&fab) == RMS$_NORMAL) {   /* Parse away           */
588*b1cdbd2cSJim Jagielski             fullname[nam.nam$b_esl] = EOS;      /* Terminate string     */
589*b1cdbd2cSJim Jagielski             result[0] = EOS;                    /* Just in case         */
590*b1cdbd2cSJim Jagielski             rp = &result[0];
591*b1cdbd2cSJim Jagielski             /*
592*b1cdbd2cSJim Jagielski              * Remove stuff added implicitly, accepting node names and
593*b1cdbd2cSJim Jagielski              * dev:[directory] strings (but not process-permanent files).
594*b1cdbd2cSJim Jagielski              */
595*b1cdbd2cSJim Jagielski             if ((nam.nam$l_fnb & NAM$M_PPF) == 0) {
596*b1cdbd2cSJim Jagielski                 if ((nam.nam$l_fnb & NAM$M_NODE) != 0) {
597*b1cdbd2cSJim Jagielski                     strncpy(result, nam.nam$l_node, nam.nam$b_node);
598*b1cdbd2cSJim Jagielski                     rp += nam.nam$b_node;
599*b1cdbd2cSJim Jagielski                     *rp = EOS;
600*b1cdbd2cSJim Jagielski                 }
601*b1cdbd2cSJim Jagielski                 if ((nam.nam$l_fnb & DEVDIR) == DEVDIR) {
602*b1cdbd2cSJim Jagielski                     strncpy(rp, nam.nam$l_dev, nam.nam$b_dev + nam.nam$b_dir);
603*b1cdbd2cSJim Jagielski                     rp += nam.nam$b_dev + nam.nam$b_dir;
604*b1cdbd2cSJim Jagielski                     *rp = EOS;
605*b1cdbd2cSJim Jagielski                 }
606*b1cdbd2cSJim Jagielski             }
607*b1cdbd2cSJim Jagielski             if (defstring != NULLST) {
608*b1cdbd2cSJim Jagielski                 strncpy(rp, nam.nam$l_name, nam.nam$b_name + nam.nam$b_type);
609*b1cdbd2cSJim Jagielski                 rp += nam.nam$b_name + nam.nam$b_type;
610*b1cdbd2cSJim Jagielski                 *rp = EOS;
611*b1cdbd2cSJim Jagielski                 if ((nam.nam$l_fnb & NAM$M_EXP_VER) != 0) {
612*b1cdbd2cSJim Jagielski                     strncpy(rp, nam.nam$l_ver, nam.nam$b_ver);
613*b1cdbd2cSJim Jagielski                     rp[nam.nam$b_ver] = EOS;
614*b1cdbd2cSJim Jagielski                 }
615*b1cdbd2cSJim Jagielski             }
616*b1cdbd2cSJim Jagielski             return (TRUE);
617*b1cdbd2cSJim Jagielski         }
618*b1cdbd2cSJim Jagielski         return (FALSE);
619*b1cdbd2cSJim Jagielski }
620*b1cdbd2cSJim Jagielski #endif
621*b1cdbd2cSJim Jagielski 
622