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 #if defined(_MSC_VER) && (_MSC_VER > 1310) 24 #define _USE_32BIT_TIME_T 25 #endif 26 27 #include <stdio.h> 28 #ifdef UNX 29 #include <stdlib.h> 30 #endif 31 #include <ctype.h> 32 #include "cppdef.h" 33 #include "cpp.h" 34 35 #include "time.h" /* BP */ 36 37 #ifndef _STRING_H 38 #include <string.h> 39 #endif 40 41 #ifndef _NO_PROTO 42 int AddInclude( char *pIncStr ); /* BP, 11.09.91, Forward-Deklaration */ 43 #endif 44 45 #if (OSL_DEBUG_LEVEL > 1) && (HOST == SYS_VMS || HOST == SYS_UNIX) 46 #include <signal.h> 47 #endif 48 49 void InitCpp3() 50 { 51 } 52 53 54 int 55 openfile(char* filename) 56 /* 57 * Open a file, add it to the linked list of open files. 58 * This is called only from openfile() above. 59 */ 60 { 61 register FILE *fp; 62 63 if ((fp = fopen(filename, "r")) == NULL) { 64 #if OSL_DEBUG_LEVEL > 1 65 if ( debug || !bDumpDefs ) 66 perror(filename); 67 #endif 68 return (FALSE); 69 } 70 #if OSL_DEBUG_LEVEL > 1 71 if (debug) 72 fprintf(stderr, "Reading from \"%s\"\n", filename); 73 #endif 74 addfile(fp, filename); 75 return (TRUE); 76 } 77 78 void addfile(FILE* fp, char* filename) 79 /* 80 * Initialize tables for this open file. This is called from openfile() 81 * above (for #include files), and from the entry to cpp to open the main 82 * input file. It calls a common routine, getfile() to build the FILEINFO 83 * structure which is used to read characters. (getfile() is also called 84 * to setup a macro replacement.) 85 */ 86 { 87 register FILEINFO *file; 88 /* #ifndef _NO_PROTO */ 89 extern FILEINFO *getfile( int bufsize, char *filename ); /* BP */ 90 /* #endif */ 91 file = getfile(NBUFF, filename); 92 file->fp = fp; /* Better remember FILE * */ 93 file->buffer[0] = EOS; /* Initialize for first read */ 94 line = 1; /* Working on line 1 now */ 95 wrongline = TRUE; /* Force out initial #line */ 96 } 97 98 void setincdirs() 99 /* 100 * Append system-specific directories to the include directory list. 101 * Called only when cpp is started. 102 */ 103 { 104 105 #ifdef CPP_INCLUDE 106 *incend++ = CPP_INCLUDE; 107 #define IS_INCLUDE 1 108 #else 109 #define IS_INCLUDE 0 110 #endif 111 112 #if HOST == SYS_UNIX 113 *incend++ = "/usr/include"; 114 #define MAXINCLUDE (NINCLUDE - 1 - IS_INCLUDE) 115 #endif 116 117 #if HOST == SYS_VMS 118 extern char *getenv(); 119 120 if (getenv("C$LIBRARY") != NULL) 121 *incend++ = "C$LIBRARY:"; 122 *incend++ = "SYS$LIBRARY:"; 123 #define MAXINCLUDE (NINCLUDE - 2 - IS_INCLUDE) 124 #endif 125 126 #if HOST == SYS_RSX 127 extern int $$rsts; /* TRUE on RSTS/E */ 128 extern int $$pos; /* TRUE on PRO-350 P/OS */ 129 extern int $$vms; /* TRUE on VMS compat. */ 130 131 if ($$pos) { /* P/OS? */ 132 *incend++ = "SY:[ZZDECUSC]"; /* C #includes */ 133 *incend++ = "LB:[1,5]"; /* RSX library */ 134 } 135 else if ($$rsts) { /* RSTS/E? */ 136 *incend++ = "SY:@"; /* User-defined account */ 137 *incend++ = "C:"; /* Decus-C library */ 138 *incend++ = "LB:[1,1]"; /* RSX library */ 139 } 140 else if ($$vms) { /* VMS compatibility? */ 141 *incend++ = "C:"; 142 } 143 else { /* Plain old RSX/IAS */ 144 *incend++ = "LB:[1,1]"; 145 } 146 #define MAXINCLUDE (NINCLUDE - 3 - IS_INCLUDE) 147 #endif 148 149 #if HOST == SYS_RT11 150 extern int $$rsts; /* RSTS/E emulation? */ 151 152 if ($$rsts) 153 *incend++ = "SY:@"; /* User-defined account */ 154 *incend++ = "C:"; /* Decus-C library disk */ 155 *incend++ = "SY:"; /* System (boot) disk */ 156 #define MAXINCLUDE (NINCLUDE - 3 - IS_INCLUDE) 157 #endif 158 159 #if HOST == SYS_UNKNOWN 160 /* 161 * BP: 25.07.91, Kontext: GenMake 162 * Unter DOS wird nun auch die Environment-Variable INCLUDE ausgewetet. 163 * Es kommt erschwerend hinzu, dass alle Eintraege, die mit ';' getrennt 164 * sind, mit in die Liste aufenommen werden muessen. 165 * Dies wird mit der Funktion strtok() realisiert. 166 * Vorsicht bei der Benutzung von malloc !!! 167 * In savestring wird naemlich getmem() verwendet. Vermutlich kommen sich 168 * die beiden Funktion in die Quere. Als ich malloc statt savestring 169 * verwendete knallte es in strcpy() ! 170 */ 171 172 #if !defined( ZTC ) && !defined( WNT ) && !defined(BLC) && ! defined UNX && ! defined OS2 173 extern char *getenv( char *pStr ); /* BP */ 174 #endif 175 char *pIncGetEnv = NULL; /* Pointer auf INCLUDE */ 176 177 if ( ( pIncGetEnv = getenv("INCLUDE") ) != NULL ) 178 AddInclude( pIncGetEnv ); 179 180 #define MAXINCLUDE (NINCLUDE - 3 - IS_INCLUDE) 181 #endif 182 183 184 } 185 186 /* BP: 11.09.91, Kontext: Erweiterung des INCLUDE-Services 187 * Bislang konnte der cpp keine Include-Angaben in der Kommandozeile 188 * vertragen, bei denen die directries mit ';' getrennt wurden. 189 * Dies ist auch verstaendlich, da dieses cpp fuer UNIX-Systeme 190 * massgeschneidert wurde und in UNI die ';' als Zeichen zum Abschluss 191 * von Kommandos gilt. 192 */ 193 194 int AddInclude( char* pIncStr ) 195 { 196 char *pIncEnv = NULL; /* Kopie des INCLUDE */ 197 char *pIncPos; /* wandert zum naechsten */ 198 199 pIncEnv = savestring( pIncStr ); 200 pIncPos = strtok( pIncEnv, ";" ); 201 202 while( pIncPos != NULL ) 203 { 204 if (incend >= &incdir[MAXINCLUDE]) 205 cfatal("Too many include directories", NULLST); 206 *incend++ = pIncPos; 207 pIncPos = strtok( NULL, ";" ); 208 } 209 return( 1 ); 210 } 211 212 213 214 215 int 216 dooptions(int argc, char** argv) 217 /* 218 * dooptions is called to process command line arguments (-Detc). 219 * It is called only at cpp startup. 220 */ 221 { 222 register char *ap; 223 register DEFBUF *dp; 224 register int c; 225 int i, j; 226 char *arg; 227 SIZES *sizp; /* For -S */ 228 int size; /* For -S */ 229 int isdatum; /* FALSE for -S* */ 230 int endtest; /* For -S */ 231 232 for (i = j = 1; i < argc; i++) { 233 arg = ap = argv[i]; 234 235 if (*ap++ != '-' || *ap == EOS) 236 { 237 argv[j++] = argv[i]; 238 } 239 else { 240 c = *ap++; /* Option byte */ 241 if (islower(c)) /* Normalize case */ 242 c = toupper(c); 243 switch (c) { /* Command character */ 244 case 'C': /* Keep comments */ 245 cflag = TRUE; 246 keepcomments = TRUE; 247 break; 248 249 case 'D': /* Define symbol */ 250 #if HOST != SYS_UNIX 251 /* zap_uc(ap); */ /* Force define to U.C. */ 252 #endif 253 /* 254 * If the option is just "-Dfoo", make it -Dfoo=1 255 */ 256 while (*ap != EOS && *ap != '=') 257 ap++; 258 if (*ap == EOS) 259 ap = "1"; 260 else 261 *ap++ = EOS; 262 /* 263 * Now, save the word and its definition. 264 */ 265 dp = defendel(argv[i] + 2, FALSE); 266 dp->repl = savestring(ap); 267 dp->nargs = DEF_NOARGS; 268 break; 269 270 case 'E': /* Ignore non-fatal */ 271 eflag = TRUE; /* errors. */ 272 break; 273 274 case 'I': /* Include directory */ 275 AddInclude( ap ); /* BP, 11.09.91 */ 276 break; 277 278 case 'N': /* No predefineds */ 279 nflag++; /* Repeat to undefine */ 280 break; /* __LINE__, etc. */ 281 282 case 'S': 283 sizp = size_table; 284 if (0 != (isdatum = (*ap != '*'))) /* If it's just -S, */ 285 endtest = T_FPTR; /* Stop here */ 286 else { /* But if it's -S* */ 287 ap++; /* Step over '*' */ 288 endtest = 0; /* Stop at end marker */ 289 } 290 while (sizp->bits != endtest && *ap != EOS) { 291 if (!isdigit(*ap)) { /* Skip to next digit */ 292 ap++; 293 continue; 294 } 295 size = 0; /* Compile the value */ 296 while (isdigit(*ap)) { 297 size *= 10; 298 size += (*ap++ - '0'); 299 } 300 if (isdatum) 301 sizp->size = size; /* Datum size */ 302 else 303 sizp->psize = size; /* Pointer size */ 304 sizp++; 305 } 306 if (sizp->bits != endtest) 307 cwarn("-S, too few values specified in %s", argv[i]); 308 else if (*ap != EOS) 309 cwarn("-S, too many values, \"%s\" unused", ap); 310 break; 311 312 case 'U': /* Undefine symbol */ 313 #if HOST != SYS_UNIX 314 /* zap_uc(ap);*/ 315 #endif 316 if (defendel(ap, TRUE) == NULL) 317 cwarn("\"%s\" wasn't defined", ap); 318 break; 319 320 #if OSL_DEBUG_LEVEL > 1 321 case 'X': /* Debug */ 322 debug = (isdigit(*ap)) ? atoi(ap) : 1; 323 #if (HOST == SYS_VMS || HOST == SYS_UNIX) 324 signal(SIGINT, (void (*)(int)) abort); /* Trap "interrupt" */ 325 #endif 326 fprintf(stderr, "Debug set to %d\n", debug); 327 break; 328 #endif 329 330 #if OSL_DEBUG_LEVEL > 1 331 case 'P': /* #define's dump */ 332 bDumpDefs = 1; 333 fprintf(stderr, "Dump #define's is on\n"); 334 break; 335 #endif 336 337 default: /* What is this one? */ 338 cwarn("Unknown option \"%s\"", arg); 339 fprintf(stderr, "The following options are valid:\n\ 340 -C\t\t\tWrite source file comments to output\n\ 341 -Dsymbol=value\tDefine a symbol with the given (optional) value\n\ 342 -Idirectory\t\tAdd a directory to the #include search list\n\ 343 -N\t\t\tDon't predefine target-specific names\n\ 344 -Stext\t\tSpecify sizes for #if sizeof\n\ 345 -Usymbol\t\tUndefine symbol\n"); 346 #if OSL_DEBUG_LEVEL > 1 347 fprintf(stderr, " -Xvalue\t\tSet internal debug flag\n"); 348 fprintf(stderr, " -P\t\t\tdump #define's\n"); 349 #endif 350 break; 351 } /* Switch on all options */ 352 } /* If it's a -option */ 353 } /* For all arguments */ 354 #if OSL_DEBUG_LEVEL > 1 355 if ( (bDumpDefs ? j > 4 : j > 3) ) { 356 #else 357 if (j > 3) { 358 #endif 359 cerror( 360 "Too many file arguments. Usage: cpp [input [output]]", 361 NULLST); 362 } 363 return (j); /* Return new argc */ 364 } 365 366 int 367 readoptions(char* filename, char*** pfargv) 368 { 369 FILE *fp; 370 int c; 371 int bInQuotes = 0; 372 char optbuff[1024], *poptbuff; 373 int fargc=0, back; 374 char *fargv[PARALIMIT], **pfa; 375 376 pfa=*pfargv=malloc(sizeof(fargv)); 377 378 poptbuff=&optbuff[0]; 379 filename++; 380 if ((fp = fopen(filename, "r")) == NULL) { 381 #if OSL_DEBUG_LEVEL > 1 382 if ( debug || !bDumpDefs ) 383 perror(filename); 384 #endif 385 return (FALSE); 386 } 387 do 388 { 389 /* 390 * #i27914# double ticks '"' now have a duplicate function: 391 * 1. they define a string ( e.g. -DFOO="baz" ) 392 * 2. a string can contain spaces, so -DFOO="baz zum" defines one 393 * argument no two ! 394 */ 395 c=fgetc(fp); 396 if ( c != ' ' && c != CR && c != NL && c != HT && c != EOF) 397 { 398 *poptbuff++=(char)c; 399 if( c == '"' ) 400 bInQuotes = ~bInQuotes; 401 } 402 else 403 { 404 if( c != EOF && bInQuotes ) 405 *poptbuff++=(char)c; 406 else 407 { 408 *poptbuff=EOS; 409 if (strlen(optbuff)>0) 410 { 411 pfa[fargc+1]=malloc(strlen(optbuff)+1); 412 strcpy(pfa[fargc+1],optbuff); 413 fargc++; 414 pfa[fargc+1]=NULL; 415 poptbuff=&optbuff[0]; 416 } 417 } 418 } 419 } 420 while ( c != EOF ); 421 422 fclose(fp); 423 back=dooptions(fargc+1,pfa); 424 425 return (back); 426 } 427 428 429 430 #if HOST != SYS_UNIX 431 FILE_LOCAL void 432 zap_uc(char* ap) 433 /* 434 * Dec operating systems mangle upper-lower case in command lines. 435 * This routine forces the -D and -U arguments to uppercase. 436 * It is called only on cpp startup by dooptions(). 437 */ 438 { 439 while (*ap != EOS) { 440 /* 441 * Don't use islower() here so it works with Multinational 442 */ 443 if (*ap >= 'a' && *ap <= 'z') 444 *ap = (char)toupper(*ap); 445 ap++; 446 } 447 } 448 #endif 449 450 void initdefines() 451 /* 452 * Initialize the built-in #define's. There are two flavors: 453 * #define decus 1 (static definitions) 454 * #define __FILE__ ?? (dynamic, evaluated by magic) 455 * Called only on cpp startup. 456 * 457 * Note: the built-in static definitions are suppressed by the -N option. 458 * __LINE__, __FILE__, and __DATE__ are always present. 459 */ 460 { 461 register char **pp; 462 register char *tp; 463 register DEFBUF *dp; 464 int i; 465 long tvec; 466 467 #if !defined( ZTC ) && !defined( WNT ) && !defined(BLC) && !defined(G3) 468 extern char *ctime(); 469 #endif 470 471 /* 472 * Predefine the built-in symbols. Allow the 473 * implementor to pre-define a symbol as "" to 474 * eliminate it. 475 */ 476 if (nflag == 0) { 477 for (pp = preset; *pp != NULL; pp++) { 478 if (*pp[0] != EOS) { 479 dp = defendel(*pp, FALSE); 480 dp->repl = savestring("1"); 481 dp->nargs = DEF_NOARGS; 482 } 483 } 484 } 485 /* 486 * The magic pre-defines (__FILE__ and __LINE__ are 487 * initialized with negative argument counts. expand() 488 * notices this and calls the appropriate routine. 489 * DEF_NOARGS is one greater than the first "magic" definition. 490 */ 491 if (nflag < 2) { 492 for (pp = magic, i = DEF_NOARGS; *pp != NULL; pp++) { 493 dp = defendel(*pp, FALSE); 494 dp->nargs = --i; 495 } 496 #if OK_DATE 497 /* 498 * Define __DATE__ as today's date. 499 */ 500 dp = defendel("__DATE__", FALSE); 501 dp->repl = tp = getmem(27); 502 dp->nargs = DEF_NOARGS; 503 time( (time_t*)&tvec); 504 *tp++ = '"'; 505 strcpy(tp, ctime((const time_t*)&tvec)); 506 tp[24] = '"'; /* Overwrite newline */ 507 #endif 508 } 509 } 510 511 #if HOST == SYS_VMS 512 /* 513 * getredirection() is intended to aid in porting C programs 514 * to VMS (Vax-11 C) which does not support '>' and '<' 515 * I/O redirection. With suitable modification, it may 516 * useful for other portability problems as well. 517 */ 518 519 int 520 getredirection(argc, argv) 521 int argc; 522 char **argv; 523 /* 524 * Process vms redirection arg's. Exit if any error is seen. 525 * If getredirection() processes an argument, it is erased 526 * from the vector. getredirection() returns a new argc value. 527 * 528 * Warning: do not try to simplify the code for vms. The code 529 * presupposes that getredirection() is called before any data is 530 * read from stdin or written to stdout. 531 * 532 * Normal usage is as follows: 533 * 534 * main(argc, argv) 535 * int argc; 536 * char *argv[]; 537 * { 538 * argc = getredirection(argc, argv); 539 * } 540 */ 541 { 542 register char *ap; /* Argument pointer */ 543 int i; /* argv[] index */ 544 int j; /* Output index */ 545 int file; /* File_descriptor */ 546 extern int errno; /* Last vms i/o error */ 547 548 for (j = i = 1; i < argc; i++) { /* Do all arguments */ 549 switch (*(ap = argv[i])) { 550 case '<': /* <file */ 551 if (freopen(++ap, "r", stdin) == NULL) { 552 perror(ap); /* Can't find file */ 553 exit(errno); /* Is a fatal error */ 554 } 555 break; 556 557 case '>': /* >file or >>file */ 558 if (*++ap == '>') { /* >>file */ 559 /* 560 * If the file exists, and is writable by us, 561 * call freopen to append to the file (using the 562 * file's current attributes). Otherwise, create 563 * a new file with "vanilla" attributes as if the 564 * argument was given as ">filename". 565 * access(name, 2) returns zero if we can write on 566 * the specified file. 567 */ 568 if (access(++ap, 2) == 0) { 569 if (freopen(ap, "a", stdout) != NULL) 570 break; /* Exit case statement */ 571 perror(ap); /* Error, can't append */ 572 exit(errno); /* After access test */ 573 } /* If file accessible */ 574 } 575 /* 576 * On vms, we want to create the file using "standard" 577 * record attributes. creat(...) creates the file 578 * using the caller's default protection mask and 579 * "variable length, implied carriage return" 580 * attributes. dup2() associates the file with stdout. 581 */ 582 if ((file = creat(ap, 0, "rat=cr", "rfm=var")) == -1 583 || dup2(file, fileno(stdout)) == -1) { 584 perror(ap); /* Can't create file */ 585 exit(errno); /* is a fatal error */ 586 } /* If '>' creation */ 587 break; /* Exit case test */ 588 589 default: 590 argv[j++] = ap; /* Not a redirector */ 591 break; /* Exit case test */ 592 } 593 } /* For all arguments */ 594 argv[j] = NULL; /* Terminate argv[] */ 595 return (j); /* Return new argc */ 596 } 597 #endif 598