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