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 67 void InitCpp2() 68 { 69 70 } 71 72 73 int 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 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 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 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 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 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