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