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