/* * C P P 3 . C * * File open and command line options * * Edit history * 13-Nov-84 MM Split from cpp1.c * 21-Oct-85 rms Make -g command arg not cause an error. * 14-Mar-86 FNF Incorporate macro based C debugging package. * Port to the Commodore AMIGA. */ #include #include #include "cppdef.h" #include "cpp.h" #if DEBUG && (HOST == SYS_VMS || HOST == SYS_UNIX) #include extern int abort(); /* For debugging */ #endif int openfile(filename) char *filename; /* * Open a file, add it to the linked list of open files. * This is called only from openfile() above. */ { register FILE *fp; extern FILE *fopen (); DBUG_ENTER ("openfile"); if ((fp = fopen(filename, "r")) == NULL) { #if DEBUG perror(filename); #endif DBUG_RETURN (FALSE); } #if DEBUG if (debug) fprintf(stderr, "Reading from \"%s\"\n", filename); #endif addfile(fp, filename); DBUG_RETURN (TRUE); } addfile(fp, filename) FILE *fp; /* Open file pointer */ char *filename; /* Name of the file */ /* * Initialize tables for this open file. This is called from openfile() * above (for #include files), and from the entry to cpp to open the main * input file. It calls a common routine, getfile() to build the FILEINFO * structure which is used to read characters. (getfile() is also called * to setup a macro replacement.) */ { register FILEINFO *file; extern FILEINFO *getfile(); DBUG_ENTER ("addfile"); file = getfile(NBUFF, filename); file->fp = fp; /* Better remember FILE * */ file->buffer[0] = EOS; /* Initialize for first read */ line = 1; /* Working on line 1 now */ wrongline = TRUE; /* Force out initial #line */ DBUG_VOID_RETURN; } setincdirs() /* * Append system-specific directories to the include directory list. * Called only when cpp is started. */ { DBUG_ENTER ("setincdirs"); #ifdef CPP_INCLUDE *incend++ = CPP_INCLUDE; #define IS_INCLUDE 1 #else #define IS_INCLUDE 0 #endif #if HOST == SYS_UNIX *incend++ = "/usr/include"; #define MAXINCLUDE (NINCLUDE - 1 - IS_INCLUDE) #endif #if HOST == SYS_AMIGADOS *incend++ = "df0:include"; /* These should be fixed. fnf */ *incend++ = "df1:include"; #define MAXINCLUDE (NINCLUDE - 2 - IS_INCLUDE) #endif #if HOST == SYS_VMS extern char *getenv(); if (getenv("C$LIBRARY") != NULL) *incend++ = "C$LIBRARY:"; *incend++ = "SYS$LIBRARY:"; #define MAXINCLUDE (NINCLUDE - 2 - IS_INCLUDE) #endif #if HOST == SYS_RSX extern int $$rsts; /* TRUE on RSTS/E */ extern int $$pos; /* TRUE on PRO-350 P/OS */ extern int $$vms; /* TRUE on VMS compat. */ if ($$pos) { /* P/OS? */ *incend++ = "SY:[ZZDECUSC]"; /* C #includes */ *incend++ = "LB:[1,5]"; /* RSX library */ } else if ($$rsts) { /* RSTS/E? */ *incend++ = "SY:@"; /* User-defined account */ *incend++ = "C:"; /* Decus-C library */ *incend++ = "LB:[1,1]"; /* RSX library */ } else if ($$vms) { /* VMS compatibility? */ *incend++ = "C:"; } else { /* Plain old RSX/IAS */ *incend++ = "LB:[1,1]"; } #define MAXINCLUDE (NINCLUDE - 3 - IS_INCLUDE) #endif #if HOST == SYS_RT11 extern int $$rsts; /* RSTS/E emulation? */ if ($$rsts) *incend++ = "SY:@"; /* User-defined account */ *incend++ = "C:"; /* Decus-C library disk */ *incend++ = "SY:"; /* System (boot) disk */ #define MAXINCLUDE (NINCLUDE - 3 - IS_INCLUDE) #endif DBUG_VOID_RETURN; } int dooptions(argc, argv) int argc; char *argv[]; /* * dooptions is called to process command line arguments (-Detc). * It is called only at cpp startup. */ { register char *ap; register DEFBUF *dp; register int c; int i, j; char *arg; SIZES *sizp; /* For -S */ int size; /* For -S */ int isdatum; /* FALSE for -S* */ int endtest; /* For -S */ DBUG_ENTER ("dooptions"); for (i = j = 1; i < argc; i++) { arg = ap = argv[i]; if (*ap++ != '-' || *ap == EOS) argv[j++] = argv[i]; else { c = *ap++; /* Option byte */ if (islower(c)) /* Normalize case */ c = toupper(c); switch (c) { /* Command character */ case 'C': /* Keep comments */ cflag = TRUE; keepcomments = TRUE; break; case 'D': /* Define symbol */ #if HOST != SYS_UNIX zap_uc(ap); /* Force define to U.C. */ #endif /* * If the option is just "-Dfoo", make it -Dfoo=1 */ while (*ap != EOS && *ap != '=') ap++; if (*ap == EOS) ap = "1"; else *ap++ = EOS; /* * Now, save the word and its definition. */ dp = defendel(argv[i] + 2, FALSE); dp->repl = savestring(ap); dp->nargs = DEF_NOARGS; break; case 'E': /* Ignore non-fatal */ eflag = TRUE; /* errors. */ break; case 'G': /* Cmpiler's debug switch */ break; case 'I': /* Include directory */ if (incend >= &incdir[MAXINCLUDE]) cfatal("Too many include directories", NULLST); *incend++ = ap; break; case 'N': /* No predefineds */ nflag++; /* Repeat to undefine */ break; /* __LINE__, etc. */ case 'S': sizp = size_table; if (isdatum = (*ap != '*')) /* If it's just -S, */ endtest = T_FPTR; /* Stop here */ else { /* But if it's -S* */ ap++; /* Step over '*' */ endtest = 0; /* Stop at end marker */ } while (sizp->bits != endtest && *ap != EOS) { if (!isdigit(*ap)) { /* Skip to next digit */ ap++; continue; } size = 0; /* Compile the value */ while (isdigit(*ap)) { size *= 10; size += (*ap++ - '0'); } if (isdatum) sizp->size = size; /* Datum size */ else sizp->psize = size; /* Pointer size */ sizp++; } if (sizp->bits != endtest) cwarn("-S, too few values specified in %s", argv[i]); else if (*ap != EOS) cwarn("-S, too many values, \"%s\" unused", ap); break; case 'U': /* Undefine symbol */ #if HOST != SYS_UNIX zap_uc(ap); #endif if (defendel(ap, TRUE) == NULL) cwarn("\"%s\" wasn't defined", ap); break; #if DEBUG case 'X': /* Debug */ debug = (isdigit(*ap)) ? atoi(ap) : 1; #if (HOST == SYS_VMS || HOST == SYS_UNIX) signal(SIGINT, abort); /* Trap "interrupt" */ #endif fprintf(stderr, "Debug set to %d\n", debug); break; #endif default: /* What is this one? */ cwarn("Unknown option \"%s\"", arg); fprintf(stderr, "The following options are valid:\n"); fprintf(stderr, " -C\t\t\tWrite source file comments to output\n"); fprintf(stderr, " -Dsymbol=value"); fprintf(stderr, "\tDefine a symbol with the given (optional) value\n"); fprintf(stderr, " -Idirectory"); fprintf(stderr, "\t\tAdd a directory to the #include search list\n"); fprintf(stderr, " -N\t\t\tDon't predefine target-specific names\n"); fprintf(stderr, " -Stext\t\tSpecify sizes for #if sizeof\n"); fprintf(stderr, " -Usymbol\t\tUndefine symbol\n"); #if DEBUG fprintf(stderr, " -Xvalue\t\tSet internal debug flag\n"); #endif break; } /* Switch on all options */ } /* If it's a -option */ } /* For all arguments */ if (j > 3) { cerror( "Too many file arguments. Usage: cpp [input [output]]", NULLST); } DBUG_RETURN (j); /* Return new argc */ } #if HOST != SYS_UNIX FILE_LOCAL zap_uc(ap) register char *ap; /* * Dec operating systems mangle upper-lower case in command lines. * This routine forces the -D and -U arguments to uppercase. * It is called only on cpp startup by dooptions(). */ { DBUG_ENTER ("zap_uc"); while (*ap != EOS) { /* * Don't use islower() here so it works with Multinational */ if (*ap >= 'a' && *ap <= 'z') *ap = toupper(*ap); ap++; } DBUG_VOID_RETURN; } #endif initdefines() /* * Initialize the built-in #define's. There are two flavors: * #define decus 1 (static definitions) * #define __FILE__ ?? (dynamic, evaluated by magic) * Called only on cpp startup. * * Note: the built-in static definitions are supressed by the -N option. * __LINE__, __FILE__, and __DATE__ are always present. */ { register char **pp; register char *tp; register DEFBUF *dp; int i; long tvec; extern char *ctime(); DBUG_ENTER ("initdefines"); DBUG_2 ("defs", "initialize built in defines"); /* * Predefine the built-in symbols. Allow the * implementor to pre-define a symbol as "" to * eliminate it. */ if (nflag == 0) { for (pp = preset; *pp != NULL; pp++) { if (*pp[0] != EOS) { dp = defendel(*pp, FALSE); dp->repl = savestring("1"); dp->nargs = DEF_NOARGS; } } } /* * The magic pre-defines (__FILE__ and __LINE__ are * initialized with negative argument counts. expand() * notices this and calls the appropriate routine. * DEF_NOARGS is one greater than the first "magic" definition. */ if (nflag < 2) { for (pp = magic, i = DEF_NOARGS; *pp != NULL; pp++) { dp = defendel(*pp, FALSE); dp->nargs = --i; } #if OK_DATE /* * Define __DATE__ as today's date. */ dp = defendel("__DATE__", FALSE); dp->repl = tp = getmem(27); dp->nargs = DEF_NOARGS; time(&tvec); *tp++ = '"'; strcpy(tp, ctime(&tvec)); tp[24] = '"'; /* Overwrite newline */ #endif } DBUG_VOID_RETURN; } #if HOST == SYS_VMS /* * getredirection() is intended to aid in porting C programs * to VMS (Vax-11 C) which does not support '>' and '<' * I/O redirection. With suitable modification, it may * useful for other portability problems as well. */ int getredirection(argc, argv) int argc; char **argv; /* * Process vms redirection arg's. Exit if any error is seen. * If getredirection() processes an argument, it is erased * from the vector. getredirection() returns a new argc value. * * Warning: do not try to simplify the code for vms. The code * presupposes that getredirection() is called before any data is * read from stdin or written to stdout. * * Normal usage is as follows: * * main(argc, argv) * int argc; * char *argv[]; * { * argc = getredirection(argc, argv); * } */ { register char *ap; /* Argument pointer */ int i; /* argv[] index */ int j; /* Output index */ int file; /* File_descriptor */ extern int errno; /* Last vms i/o error */ DBUG_ENTER ("getredirection"); for (j = i = 1; i < argc; i++) { /* Do all arguments */ switch (*(ap = argv[i])) { case '<': /* ': /* >file or >>file */ if (*++ap == '>') { /* >>file */ /* * If the file exists, and is writable by us, * call freopen to append to the file (using the * file's current attributes). Otherwise, create * a new file with "vanilla" attributes as if the * argument was given as ">filename". * access(name, 2) returns zero if we can write on * the specified file. */ if (access(++ap, 2) == 0) { if (freopen(ap, "a", stdout) != NULL) break; /* Exit case statement */ perror(ap); /* Error, can't append */ exit(errno); /* After access test */ } /* If file accessable */ } /* * On vms, we want to create the file using "standard" * record attributes. creat(...) creates the file * using the caller's default protection mask and * "variable length, implied carriage return" * attributes. dup2() associates the file with stdout. */ if ((file = creat(ap, 0, "rat=cr", "rfm=var")) == -1 || dup2(file, fileno(stdout)) == -1) { perror(ap); /* Can't create file */ exit(errno); /* is a fatal error */ } /* If '>' creation */ break; /* Exit case test */ default: argv[j++] = ap; /* Not a redirector */ break; /* Exit case test */ } } /* For all arguments */ argv[j] = NULL; /* Terminate argv[] */ DBUG_RETURN (j); /* Return new argc */ } #endif