1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 #include <stdio.h> 29 #include <ctype.h> 30 #include "cppdef.h" 31 #include "cpp.h" 32 33 FILE *pCppOut = NULL; 34 FILE *pCppIn = NULL; 35 36 #if OSL_DEBUG_LEVEL > 1 37 FILE *pDefOut = NULL; /* ER evtl. #define's dump */ 38 #endif 39 40 #ifdef B200 41 /* BP, 25.07.91, einzige Moeglichkeit unter BC Stack und Heap festzusetzen */ 42 extern unsigned _stklen = 24000; 43 extern unsigned _heaplen = 30000; 44 #endif 45 46 47 48 /* 49 * Commonly used global variables: 50 * line is the current input line number. 51 * wrongline is set in many places when the actual output 52 * line is out of sync with the numbering, e.g, 53 * when expanding a macro with an embedded newline. 54 * 55 * token holds the last identifier scanned (which might 56 * be a candidate for macro expansion). 57 * errors is the running cpp error counter. 58 * infile is the head of a linked list of input files (extended by 59 * #include and macros being expanded). infile always points 60 * to the current file/macro. infile->parent to the includer, 61 * etc. infile->fd is NULL if this input stream is a macro. 62 */ 63 int line; /* Current line number */ 64 int wrongline; /* Force #line to compiler */ 65 char token[IDMAX + 1]; /* Current input token */ 66 int errors; /* cpp error counter */ 67 FILEINFO *infile = NULL; /* Current input file */ 68 #if OSL_DEBUG_LEVEL > 1 69 int debug; /* TRUE if debugging now */ 70 int bDumpDefs; /* TRUE if #define's dump req. */ 71 #ifdef EVALDEFS 72 int bIsInEval; /* TRUE if #define eval now */ 73 char EvalBuf[NEVALBUF + 1]; /* evaluation buffer */ 74 int nEvalOff = 0; /* offset to free buffer pos */ 75 #endif 76 #endif 77 /* 78 * This counter is incremented when a macro expansion is initiated. 79 * If it exceeds a built-in value, the expansion stops -- this tests 80 * for a runaway condition: 81 * #define X Y 82 * #define Y X 83 * X 84 * This can be disabled by falsifying rec_recover. (Nothing does this 85 * currently: it is a hook for an eventual invocation flag.) 86 */ 87 int recursion; /* Infinite recursion counter */ 88 int rec_recover = TRUE; /* Unwind recursive macros */ 89 90 /* 91 * instring is set TRUE when a string is scanned. It modifies the 92 * behavior of the "get next character" routine, causing all characters 93 * to be passed to the caller (except <DEF_MAGIC>). Note especially that 94 * comments and \<newline> are not removed from the source. (This 95 * prevents cpp output lines from being arbitrarily long). 96 * 97 * inmacro is set by #define -- it absorbs comments and converts 98 * form-feed and vertical-tab to space, but returns \<newline> 99 * to the caller. Strictly speaking, this is a bug as \<newline> 100 * shouldn't delimit tokens, but we'll worry about that some other 101 * time -- it is more important to prevent infinitly long output lines. 102 * 103 * instring and inmarcor are parameters to the get() routine which 104 * were made global for speed. 105 */ 106 int instring = FALSE; /* TRUE if scanning string */ 107 int inmacro = FALSE; /* TRUE if #defining a macro */ 108 109 /* 110 * work[] and workp are used to store one piece of text in a temporay 111 * buffer. To initialize storage, set workp = work. To store one 112 * character, call save(c); (This will fatally exit if there isn't 113 * room.) To terminate the string, call save(EOS). Note that 114 * the work buffer is used by several subroutines -- be sure your 115 * data won't be overwritten. The extra byte in the allocation is 116 * needed for string formal replacement. 117 */ 118 char work[NWORK + 1]; /* Work buffer */ 119 char *workp; /* Work buffer pointer */ 120 121 /* 122 * keepcomments is set TRUE by the -C option. If TRUE, comments 123 * are written directly to the output stream. This is needed if 124 * the output from cpp is to be passed to lint (which uses commands 125 * embedded in comments). cflag contains the permanent state of the 126 * -C flag. keepcomments is always falsified when processing #control 127 * commands and when compilation is supressed by a false #if 128 * 129 * If eflag is set, CPP returns "success" even if non-fatal errors 130 * were detected. 131 * 132 * If nflag is non-zero, no symbols are predefined except __LINE__. 133 * __FILE__, and __DATE__. If nflag > 1, absolutely no symbols 134 * are predefined. 135 */ 136 int keepcomments = FALSE; /* Write out comments flag */ 137 int cflag = FALSE; /* -C option (keep comments) */ 138 int eflag = FALSE; /* -E option (never fail) */ 139 int nflag = 0; /* -N option (no predefines) */ 140 141 /* 142 * ifstack[] holds information about nested #if's. It is always 143 * accessed via *ifptr. The information is as follows: 144 * WAS_COMPILING state of compiling flag at outer level. 145 * ELSE_SEEN set TRUE when #else seen to prevent 2nd #else. 146 * TRUE_SEEN set TRUE when #if or #elif succeeds 147 * ifstack[0] holds the compiling flag. It is TRUE if compilation 148 * is currently enabled. Note that this must be initialized TRUE. 149 */ 150 char ifstack[BLK_NEST] = { TRUE }; /* #if information */ 151 char *ifptr = ifstack; /* -> current ifstack[] */ 152 153 /* 154 * incdir[] stores the -i directories (and the system-specific 155 * #include <...> directories. 156 */ 157 char *incdir[NINCLUDE]; /* -i directories */ 158 char **incend = incdir; /* -> free space in incdir[] */ 159 160 /* 161 * This is the table used to predefine target machine and operating 162 * system designators. It may need hacking for specific circumstances. 163 * Note: it is not clear that this is part of the Ansi Standard. 164 * The -N option supresses preset definitions. 165 */ 166 char *preset[] = { /* names defined at cpp start */ 167 #ifdef MACHINE 168 MACHINE, 169 #endif 170 #ifdef SYSTEM 171 SYSTEM, 172 #endif 173 #ifdef COMPILER 174 COMPILER, 175 #endif 176 #if OSL_DEBUG_LEVEL > 1 177 "decus_cpp", /* Ourselves! */ 178 #endif 179 NULL /* Must be last */ 180 }; 181 182 /* 183 * The value of these predefined symbols must be recomputed whenever 184 * they are evaluated. The order must not be changed. 185 */ 186 char *magic[] = { /* Note: order is important */ 187 "__LINE__", 188 "__FILE__", 189 NULL /* Must be last */ 190 }; 191 192 static char *sharpfilename = NULL; 193 194 int nRunde = 0; 195 196 void InitCpp1() 197 { 198 int i; 199 /* BP */ 200 /* in der LIB-Version muessen alle Variablen initialisiert werden */ 201 202 line = wrongline = errors = recursion = 0; 203 for( i = 0; i < IDMAX; i++ ) 204 token[ i ] = 0; 205 206 for( i = 0; i < NWORK; i++ ) 207 work[ i ] = 0; 208 209 for( i = 0; i < NINCLUDE; i++ ) 210 incdir[ i ] = NULL; 211 212 workp = NULL; 213 for( i = 0; i < BLK_NEST; i++ ) 214 ifstack[ i ] = TRUE; 215 ifptr = ifstack; 216 217 pCppOut = stdout; 218 pCppIn = stdin; 219 #if OSL_DEBUG_LEVEL > 1 220 debug = 0; 221 bDumpDefs = 0; 222 pDefOut = stdout; 223 #ifdef EVALDEFS 224 bIsInEval = 0; 225 for( i = 0; i < NEVALBUF; i++ ) 226 EvalBuf[ i ] = 0; 227 nEvalOff = 0; 228 #endif 229 #endif 230 rec_recover = TRUE; 231 infile = NULL; 232 instring = inmacro = keepcomments = cflag = eflag = FALSE; 233 nflag = 0; 234 incend = incdir; 235 sharpfilename = NULL; 236 /* BP */ 237 } 238 239 int MAIN(int argc, char** argv) 240 { 241 register int i; 242 char **useargv, **pfargv; 243 244 245 if( nRunde == 0 ) 246 { 247 pCppIn = stdin; 248 pCppOut = stdout; 249 } 250 251 nRunde++; 252 InitCpp1(); 253 InitCpp2(); 254 InitCpp3(); 255 InitCpp4(); 256 InitCpp5(); 257 InitCpp6(); 258 259 #if HOST == SYS_VMS 260 argc = getredirection(argc, argv); /* vms >file and <file */ 261 #endif 262 initdefines(); /* O.S. specific def's */ 263 if ( argv[argc-1][0] == '@' ) 264 { 265 i = readoptions( argv[1], &pfargv ); /* Command file */ 266 useargv=pfargv; 267 } 268 else 269 { 270 i = dooptions(argc, argv); /* Command line -flags */ 271 useargv=argv; 272 } 273 switch (i) { 274 #if OSL_DEBUG_LEVEL > 1 275 case 4: 276 if ( bDumpDefs ) 277 { 278 /* 279 * Get defBase file, "-" means use stdout. 280 */ 281 if (!streq(useargv[3], "-")) { 282 #if HOST == SYS_VMS 283 /* 284 * On vms, reopen stdout with "vanilla rms" attributes. 285 */ 286 if ((i = creat(useargv[3], 0, "rat=cr", "rfm=var")) == -1 287 || dup2(i, fileno(stdout)) == -1) { 288 #else 289 /* alt if (freopen(useargv[3], "w", stdout) == NULL) { */ 290 291 pDefOut = fopen( useargv[3], "w" ); 292 if( pDefOut == NULL ) { 293 #endif 294 perror(useargv[3]); 295 cerror("Can't open output file \"%s\"", useargv[3]); 296 exit(IO_ERROR); 297 } 298 } /* Continue by opening output */ 299 } 300 /* OSL_DEBUG_LEVEL > 1 */ 301 #endif 302 case 3: 303 /* 304 * Get output file, "-" means use stdout. 305 */ 306 if (!streq(useargv[2], "-")) { 307 #if HOST == SYS_VMS 308 /* 309 * On vms, reopen stdout with "vanilla rms" attributes. 310 */ 311 if ((i = creat(useargv[2], 0, "rat=cr", "rfm=var")) == -1 312 || dup2(i, fileno(stdout)) == -1) { 313 #else 314 /* alt if (freopen(useargv[2], "w", stdout) == NULL) { */ 315 316 pCppOut = fopen( useargv[2], "w" ); 317 if( pCppOut == NULL ) { 318 #endif 319 perror(useargv[2]); 320 cerror("Can't open output file \"%s\"", useargv[2]); 321 exit(IO_ERROR); 322 } 323 } /* Continue by opening input */ 324 case 2: /* One file -> stdin */ 325 /* 326 * Open input file, "-" means use stdin. 327 */ 328 if (!streq(useargv[1], "-")) { 329 /* alt: if (freopen(useargv[1], "r", stdin) == NULL) { */ 330 pCppIn = fopen( useargv[1], "r" ); 331 if( pCppIn == NULL) { 332 perror(useargv[1]); 333 cerror("Can't open input file \"%s\"", useargv[1]); 334 exit(IO_ERROR); 335 } 336 strcpy(work, useargv[1]); /* Remember input filename */ 337 break; 338 } /* Else, just get stdin */ 339 case 0: /* No args? */ 340 case 1: /* No files, stdin -> stdout */ 341 #if (HOST == SYS_UNIX) || (HOST == SYS_UNKNOWN) 342 work[0] = EOS; /* Unix can't find stdin name */ 343 #else 344 fgetname(stdin, work); /* Vax-11C, Decus C know name */ 345 #endif 346 break; 347 348 default: 349 exit(IO_ERROR); /* Can't happen */ 350 } 351 /* if ( pfargv ) 352 { 353 for ( j=0;j++;j < PARALIMIT ) 354 { 355 if (pfargv[j]!=0) 356 free(pfargv[j]); 357 } 358 free(pfargv); 359 } 360 */ 361 362 setincdirs(); /* Setup -I include directories */ 363 addfile( pCppIn, work); /* "open" main input file */ 364 #if OSL_DEBUG_LEVEL > 1 365 if (debug > 0 || bDumpDefs) 366 dumpdef("preset #define symbols"); 367 #endif 368 if( pCppIn != stdin ) 369 rewind( pCppIn ); 370 371 cppmain(); /* Process main file */ 372 373 if ((i = (ifptr - &ifstack[0])) != 0) { 374 #if OLD_PREPROCESSOR 375 ciwarn("Inside #ifdef block at end of input, depth = %d", i); 376 #else 377 cierror("Inside #ifdef block at end of input, depth = %d", i); 378 #endif 379 } 380 #if OSL_DEBUG_LEVEL > 1 381 if( pDefOut != stdout && pDefOut != stderr ) 382 fclose( pDefOut ); 383 #endif 384 if( pCppOut != stdout && pCppOut != stderr ) 385 fclose( pCppOut ); 386 387 if (errors > 0) { 388 fprintf(stderr, (errors == 1) 389 ? "%d error in preprocessor\n" 390 : "%d errors in preprocessor\n", errors); 391 if (!eflag) 392 exit(IO_ERROR); 393 } 394 #ifdef NOMAIN /* BP */ /* kein exit im der LIB-Version */ 395 return( IO_NORMAL ); 396 #else 397 exit(IO_NORMAL); /* No errors or -E option set */ 398 #endif 399 400 } 401 402 FILE_LOCAL 403 void cppmain() 404 /* 405 * Main process for cpp -- copies tokens from the current input 406 * stream (main file, include file, or a macro) to the output 407 * file. 408 */ 409 { 410 register int c; /* Current character */ 411 register int counter; /* newlines and spaces */ 412 413 /* 414 * Explicitly output a #line at the start of cpp output so 415 * that lint (etc.) knows the name of the original source 416 * file. If we don't do this explicitly, we may get 417 * the name of the first #include file instead. 418 * We also seem to need a blank line following that first #line. 419 */ 420 #ifdef EVALDEFS 421 if ( !bIsInEval ) 422 #endif 423 { 424 sharp(); 425 PUTCHAR('\n'); 426 } 427 /* 428 * This loop is started "from the top" at the beginning of each line 429 * wrongline is set TRUE in many places if it is necessary to write 430 * a #line record. (But we don't write them when expanding macros.) 431 * 432 * The counter variable has two different uses: at 433 * the start of a line, it counts the number of blank lines that 434 * have been skipped over. These are then either output via 435 * #line records or by outputting explicit blank lines. 436 * When expanding tokens within a line, the counter remembers 437 * whether a blank/tab has been output. These are dropped 438 * at the end of the line, and replaced by a single blank 439 * within lines. 440 */ 441 for (;;) { 442 counter = 0; /* Count empty lines */ 443 for (;;) { /* For each line, ... */ 444 while (type[(c = get())] == SPA) /* Skip leading blanks */ 445 ; /* in this line. */ 446 if (c == '\n') /* If line's all blank, */ 447 ++counter; /* Do nothing now */ 448 else if (c == '#') { /* Is 1st non-space '#' */ 449 keepcomments = FALSE; /* Don't pass comments */ 450 counter = control(counter); /* Yes, do a #command */ 451 keepcomments = (cflag && compiling); 452 } 453 else if (c == EOF_CHAR) /* At end of file? */ 454 { 455 break; 456 } 457 else if (!compiling) { /* #ifdef false? */ 458 skipnl(); /* Skip to newline */ 459 counter++; /* Count it, too. */ 460 } 461 else { 462 break; /* Actual token */ 463 } 464 } 465 if (c == EOF_CHAR) /* Exit process at */ 466 break; /* End of file */ 467 /* 468 * If the loop didn't terminate because of end of file, we 469 * know there is a token to compile. First, clean up after 470 * absorbing newlines. counter has the number we skipped. 471 */ 472 if ((wrongline && infile->fp != NULL) || counter > 4) 473 sharp(); /* Output # line number */ 474 else { /* If just a few, stuff */ 475 while (--counter >= 0) /* them out ourselves */ 476 PUTCHAR('\n'); 477 } 478 /* 479 * Process each token on this line. 480 */ 481 unget(); /* Reread the char. */ 482 for (;;) { /* For the whole line, */ 483 do { /* Token concat. loop */ 484 for (counter = 0; (type[(c = get())] == SPA);) { 485 #if COMMENT_INVISIBLE 486 if (c != COM_SEP) 487 counter++; 488 #else 489 counter++; /* Skip over blanks */ 490 #endif 491 } 492 if (c == EOF_CHAR || c == '\n') 493 goto end_line; /* Exit line loop */ 494 else if (counter > 0) /* If we got any spaces */ 495 PUTCHAR(' '); /* Output one space */ 496 c = macroid(c); /* Grab the token */ 497 } while (type[c] == LET && catenate()); 498 if (c == EOF_CHAR || c == '\n') /* From macro exp error */ 499 goto end_line; /* Exit line loop */ 500 switch (type[c]) { 501 case LET: 502 fputs(token, pCppOut); /* Quite ordinary token */ 503 #ifdef EVALDEFS 504 { 505 int len; 506 if ( bIsInEval 507 && nEvalOff + (len=strlen(token)) < NEVALBUF ) 508 { 509 strcpy( &EvalBuf[nEvalOff], token ); 510 nEvalOff += len; 511 } 512 } 513 #endif 514 break; 515 516 517 case DIG: /* Output a number */ 518 case DOT: /* Dot may begin floats */ 519 #ifdef EVALDEFS 520 if ( bIsInEval ) 521 scannumber(c, outputEval); 522 else 523 scannumber(c, output); 524 #else 525 scannumber(c, output); 526 #endif 527 break; 528 529 case QUO: /* char or string const */ 530 scanstring(c, output); /* Copy it to output */ 531 break; 532 533 default: /* Some other character */ 534 cput(c); /* Just output it */ 535 #ifdef EVALDEFS 536 if ( bIsInEval && nEvalOff < NEVALBUF ) 537 EvalBuf[nEvalOff++] = c; 538 #endif 539 break; 540 } /* Switch ends */ 541 } /* Line for loop */ 542 end_line: if (c == '\n') { /* Compiling at EOL? */ 543 PUTCHAR('\n'); /* Output newline, if */ 544 if (infile->fp == NULL) /* Expanding a macro, */ 545 wrongline = TRUE; /* Output # line later */ 546 } 547 } /* Continue until EOF */ 548 #ifdef EVALDEFS 549 if ( bIsInEval ) 550 EvalBuf[nEvalOff++] = '\0'; 551 #endif 552 } 553 554 void output(int c) 555 /* 556 * Output one character to stdout -- output() is passed as an 557 * argument to scanstring() 558 */ 559 { 560 #if COMMENT_INVISIBLE 561 if (c != TOK_SEP && c != COM_SEP) 562 #else 563 if (c != TOK_SEP) 564 #endif 565 /* alt: PUTCHAR(c); */ 566 PUTCHAR(c); 567 } 568 569 #ifdef EVALDEFS 570 outputEval(c) 571 int c; 572 /* 573 * Output one character to stdout -- output() is passed as an 574 * argument to scanstring() 575 */ 576 { 577 #if COMMENT_INVISIBLE 578 if (c != TOK_SEP && c != COM_SEP) 579 #else 580 if (c != TOK_SEP) 581 #endif 582 /* alt: PUTCHAR(c); */ 583 { 584 PUTCHAR(c); 585 if ( bIsInEval && nEvalOff < NEVALBUF ) 586 EvalBuf[nEvalOff++] = c; 587 } 588 } 589 #endif 590 591 592 FILE_LOCAL 593 void sharp() 594 /* 595 * Output a line number line. 596 */ 597 { 598 register char *name; 599 600 if (keepcomments) /* Make sure # comes on */ 601 PUTCHAR('\n'); /* a fresh, new line. */ 602 fprintf( pCppOut, "#%s %d", LINE_PREFIX, line); 603 if (infile->fp != NULL) { 604 name = (infile->progname != NULL) 605 ? infile->progname : infile->filename; 606 if (sharpfilename == NULL 607 || (sharpfilename != NULL && !streq(name, sharpfilename)) ) { 608 if (sharpfilename != NULL) 609 free(sharpfilename); 610 sharpfilename = savestring(name); 611 fprintf( pCppOut, " \"%s\"", name); 612 } 613 } 614 PUTCHAR('\n'); 615 wrongline = FALSE; 616 } 617