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