void 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; time_t tvec; #if !defined( WNT ) && !defined(G3) extern char *ctime(); #endif /* * 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 } }
/* * 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 suppressed by the -N option. * __LINE__, __FILE__, and __DATE__ are always present. */ void initdefines() { char** pp; char* tp; DEFBUF* dp; int i; time_t tvec; /* * 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 } }
void doundef(struct Global *global) /* * Remove the symbol from the defined list. * Called from the #control processor. */ { int c; if (type[(c = skipws(global))] != LET) cerror(global, ERROR_ILLEGAL_UNDEF); else { scanid(global, c); /* Get name to tokenbuf */ (void) defendel(global, global->tokenbuf, TRUE); } }
void deldefines(struct Global *global) { /* * Delete the built-in #define's. */ char **pp; int i; /* * Delete the built-in symbols, unless -WW. */ if (global->wflag < 2) { for (pp = global->preset; *pp != NULL; pp++) { defendel(global, *pp, TRUE); } } /* * The magic pre-defines __FILE__ and __LINE__ */ for (pp = global->magic, i = DEF_NOARGS; *pp != NULL; pp++) { defendel(global, *pp, TRUE); } #if OK_DATE /* * Undefine __DATE__. */ defendel(global, "__DATE__", TRUE); /* * Undefine __TIME__. */ defendel(global, "__TIME__", TRUE); #endif return; }
/* * Remove the symbol from the defined list. * Called from the #control processor. */ void doundef() { int c; if (type[(c = skipws())] != LET) cerror("Illegal #undef argument", NULLST); else { scanid(c); /* Get name to token[] */ if (defendel(token, TRUE) == NULL) { #ifdef STRICT_UNDEF cwarn("Symbol \"%s\" not defined in #undef", token); #endif } } }
int dooptions(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 */ 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 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 'I': /* Include directory */ AddInclude( ap ); /* BP, 11.09.91 */ break; case 'N': /* No predefineds */ nflag++; /* Repeat to undefine */ break; /* __LINE__, etc. */ case 'S': sizp = size_table; if (0 != (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 (defendel(ap, TRUE) == NULL) cwarn("\"%s\" wasn't defined", ap); break; #if OSL_DEBUG_LEVEL > 1 case 'X': /* Debug */ debug = (isdigit(*ap)) ? atoi(ap) : 1; #if (HOST == SYS_VMS || HOST == SYS_UNIX) signal(SIGINT, (void (*)(int)) abort); /* Trap "interrupt" */ #endif fprintf(stderr, "Debug set to %d\n", debug); break; #endif #if OSL_DEBUG_LEVEL > 1 case 'P': /* #define's dump */ bDumpDefs = 1; fprintf(stderr, "Dump #define's is on\n"); break; #endif default: /* What is this one? */ cwarn("Unknown option \"%s\"", arg); fprintf(stderr, "The following options are valid:\n\ -C\t\t\tWrite source file comments to output\n\ -Dsymbol=value\tDefine a symbol with the given (optional) value\n\ -Idirectory\t\tAdd a directory to the #include search list\n\ -N\t\t\tDon't predefine target-specific names\n\ -Stext\t\tSpecify sizes for #if sizeof\n\ -Usymbol\t\tUndefine symbol\n"); #if OSL_DEBUG_LEVEL > 1 fprintf(stderr, " -Xvalue\t\tSet internal debug flag\n"); fprintf(stderr, " -P\t\t\tdump #define's\n"); #endif break; } /* Switch on all options */ } /* If it's a -option */ } /* For all arguments */ #if OSL_DEBUG_LEVEL > 1 if ( (bDumpDefs ? j > 4 : j > 3) ) { #else if (j > 3) { #endif cerror( "Too many file arguments. Usage: cpp [input [output]]", NULLST); } return (j); /* Return new argc */ } int readoptions(char* filename, char*** pfargv) { FILE *fp; int c; int bInQuotes = 0; char optbuff[1024], *poptbuff; int fargc=0, back; char *fargv[PARALIMIT], **pfa; pfa=*pfargv=malloc(sizeof(fargv)); poptbuff=&optbuff[0]; filename++; if ((fp = fopen(filename, "r")) == NULL) { #if OSL_DEBUG_LEVEL > 1 if ( debug || !bDumpDefs ) perror(filename); #endif return (FALSE); } do { /* * #i27914# double ticks '"' now have a duplicate function: * 1. they define a string ( e.g. -DFOO="baz" ) * 2. a string can contain spaces, so -DFOO="baz zum" defines one * argument no two ! */ c=fgetc(fp); if ( c != ' ' && c != CR && c != NL && c != HT && c != EOF) { *poptbuff++=(char)c; if( c == '"' ) bInQuotes = ~bInQuotes; } else { if( c != EOF && bInQuotes ) *poptbuff++=(char)c; else { *poptbuff=EOS; if (strlen(optbuff)>0) { pfa[fargc+1]=malloc(strlen(optbuff)+1); strcpy(pfa[fargc+1],optbuff); fargc++; pfa[fargc+1]=0; poptbuff=&optbuff[0]; } } } } while ( c != EOF ); fclose(fp); back=dooptions(fargc+1,pfa); return (back); }
ReturnCode initdefines(struct Global *global) { /* * 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__, __TIME__ and __DATE__ are always present. */ char **pp; char *tp; DEFBUF *dp; struct tm *tm; int i; time_t tvec; static char months[12][4] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; /* * Predefine the built-in symbols. Allow the * implementor to pre-define a symbol as "" to * eliminate it. */ if (!(global->nflag & NFLAG_BUILTIN)) { for (pp = global->preset; *pp != NULL; pp++) { if (*pp[0] != EOS) { dp = defendel(global, *pp, FALSE); if(!dp) return(FPP_OUT_OF_MEMORY); dp->repl = savestring(global, "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 (!(global->nflag & NFLAG_PREDEFINE)) { for (pp = global->magic, i = DEF_NOARGS; *pp != NULL; pp++) { dp = defendel(global, *pp, FALSE); if(!dp) return(FPP_OUT_OF_MEMORY); dp->nargs = --i; } #if OK_DATE /* * Define __DATE__ as today's date. */ dp = defendel(global, "__DATE__", FALSE); tp = Getmem(global, 14); if(!tp || !dp) return(FPP_OUT_OF_MEMORY); dp->repl = tp; dp->nargs = DEF_NOARGS; time(&tvec); tm = localtime(&tvec); sprintf(tp, "\"%3s %2d %4d\"", /* "Aug 20 1988" */ months[tm->tm_mon], tm->tm_mday, tm->tm_year + 1900); /* * Define __TIME__ as this moment's time. */ dp = defendel(global, "__TIME__", FALSE); tp = Getmem(global, 11); if(!tp || !dp) return(FPP_OUT_OF_MEMORY); dp->repl = tp; dp->nargs = DEF_NOARGS; sprintf(tp, "\"%2d:%02d:%02d\"", /* "20:42:31" */ tm->tm_hour, tm->tm_min, tm->tm_sec); #endif } return(FPP_OK); }
int dooptions(struct Global *global, struct fppTag *tags) { /* * dooptions is called to process command line arguments (-Detc). * It is called only at cpp startup. */ DEFBUF *dp; char end=FALSE; /* end of taglist */ while(tags && !end) { switch(tags->tag) { case FPPTAG_END: end=TRUE; break; case FPPTAG_INITFUNC: global->initialfunc = (char *) tags->data; break; case FPPTAG_DISPLAYFUNCTIONS: global->outputfunctions = TRUEFALSE(tags->data); break; case FPPTAG_RIGHTCONCAT: global->rightconcat = TRUEFALSE(tags->data); break; case FPPTAG_OUTPUTMAIN: global->outputfile = TRUEFALSE(tags->data); break; case FPPTAG_NESTED_COMMENTS: global->nestcomments = TRUEFALSE(tags->data); break; case FPPTAG_WARNMISSINCLUDE: global->warnnoinclude = TRUEFALSE(tags->data); break; case FPPTAG_WARN_NESTED_COMMENTS: global->warnnestcomments = TRUEFALSE(tags->data); break; case FPPTAG_OUTPUTSPACE: global->showspace = TRUEFALSE(tags->data); break; case FPPTAG_OUTPUTBALANCE: global->showbalance = TRUEFALSE(tags->data); break; case FPPTAG_OUTPUTINCLUDES: global->showincluded = TRUEFALSE(tags->data); break; case FPPTAG_IGNOREVERSION: global->showversion = TRUEFALSE(tags->data); break; case FPPTAG_WARNILLEGALCPP: global->warnillegalcpp=TRUEFALSE(tags->data); break; case FPPTAG_OUTPUTLINE: global->outputLINE= TRUEFALSE(tags->data); break; case FPPTAG_KEEPCOMMENTS: if(tags->data) { global->cflag = TRUE; global->keepcomments = TRUE; } break; case FPPTAG_DEFINE: /* * If the option is just "-Dfoo", make it -Dfoo=1 */ { char *symbol=(char *)tags->data; char *text=symbol; while (*text != EOS && *text != '=') text++; if (*text == EOS) text = "1"; else *text++ = EOS; /* * Now, save the word and its definition. */ dp = defendel(global, symbol, FALSE); if(!dp) return(FPP_OUT_OF_MEMORY); dp->repl = savestring(global, text); dp->nargs = DEF_NOARGS; } break; case FPPTAG_IGNORE_NONFATAL: global->eflag = TRUE; break; case FPPTAG_INCLUDE_DIR: if (global->incend >= &global->incdir[NINCLUDE]) { cfatal(global, FATAL_TOO_MANY_INCLUDE_DIRS); return(FPP_TOO_MANY_INCLUDE_DIRS); } *global->incend++ = (char *)tags->data; break; case FPPTAG_INCLUDE_FILE: case FPPTAG_INCLUDE_MACRO_FILE: if (global->included >= NINCLUDE) { cfatal(global, FATAL_TOO_MANY_INCLUDE_FILES); return(FPP_TOO_MANY_INCLUDE_FILES); } global->include[global->included] = (char *)tags->data; global->includeshow[global->included] = (tags->tag == FPPTAG_INCLUDE_FILE); global->included++; break; case FPPTAG_BUILTINS: global->nflag|=(tags->data?NFLAG_BUILTIN:0); break; case FPPTAG_PREDEFINES: global->nflag|=(tags->data?NFLAG_PREDEFINE:0); break; case FPPTAG_IGNORE_CPLUSPLUS: global->cplusplus=!tags->data; break; case FPPTAG_SIZEOF_TABLE: { SIZES *sizp; /* For -S */ int size; /* For -S */ int isdatum; /* FALSE for -S* */ int endtest; /* For -S */ char *text=(char *)tags->data; sizp = size_table; if (isdatum = (*text != '*')) /* If it's just -S, */ endtest = T_FPTR; /* Stop here */ else { /* But if it's -S* */ text++; /* Step over '*' */ endtest = 0; /* Stop at end marker */ } while (sizp->bits != endtest && *text != EOS) { if (!isdigit(*text)) { /* Skip to next digit */ text++; continue; } size = 0; /* Compile the value */ while (isdigit(*text)) { size *= 10; size += (*text++ - '0'); } if (isdatum) sizp->size = size; /* Datum size */ else sizp->psize = size; /* Pointer size */ sizp++; } if (sizp->bits != endtest) cwarn(global, WARN_TOO_FEW_VALUES_TO_SIZEOF, NULL); else if (*text != EOS) cwarn(global, WARN_TOO_MANY_VALUES_TO_SIZEOF, NULL); } break; case FPPTAG_UNDEFINE: if (defendel(global, (char *)tags->data, TRUE) == NULL) cwarn(global, WARN_NOT_DEFINED, tags->data); break; case FPPTAG_OUTPUT_DEFINES: global->wflag++; break; case FPPTAG_INPUT_NAME: strcpy(global->work, tags->data); /* Remember input filename */ global->first_file=tags->data; break; case FPPTAG_INPUT: global->input=(char *(*)(char *, int, void *))tags->data; break; case FPPTAG_OUTPUT: global->output=(void (*)(int, void *))tags->data; break; case FPPTAG_ERROR: global->error=(void (*)(void *, char *, va_list))tags->data; break; case FPPTAG_USERDATA: global->userdata=tags->data; break; case FPPTAG_LINE: global->linelines= TRUEFALSE(tags->data); break; case FPPTAG_EXCLFUNC: global->excludedinit[ global->excluded++ ] = (char *)tags->data; break; default: cwarn(global, WARN_INTERNAL_ERROR, NULL); break; } tags++; } return(0); }
/* * Called from control when a #define is scanned. This module * parses formal parameters and the replacement string. When * the formal parameter name is encountered in the replacement * string, it is replaced by a character in the range 128 to * 128+NPARAM (this allows up to 32 parameters within the * Dec Multinational range). * * There is some special case code to distinguish * #define foo bar * from #define foo() bar * * Also, we make sure that * #define foo foo * expands to "foo" but doesn't put cpp into an infinite loop. * * A warning message is printed if you redefine a symbol to a * different text. I.e, * #define foo 123 * #define foo 123 * is ok, but * #define foo 123 * #define foo +123 * is not. * * The following subroutines are called from define(): * checkparm called when a token is scanned. It checks through the * array of formal parameters. If a match is found, the * token is replaced by a control byte which will be used * to locate the parameter when the macro is expanded. * textput puts a string in the macro work area (parm[]), updating * parmp to point to the first free byte in parm[]. * textput() tests for work buffer overflow. * charput puts a single character in the macro work area (parm[]) * in a manner analogous to textput(). */ void dodefine() { int c; DEFBUF* dp; /* -> new definition */ int isredefine; /* TRUE if redefined */ char* old = NULL; /* Remember redefined */ if (type[(c = skipws())] != LET) goto bad_define; isredefine = FALSE; /* Set if redefining */ if ((dp = lookid(c)) == NULL) /* If not known now */ dp = defendel(token, FALSE); /* Save the name */ else /* It's known: */ { isredefine = TRUE; /* Remember this fact */ old = dp->repl; /* Remember replacement */ dp->repl = NULL; /* No replacement now */ } parlist[0] = parmp = parm; /* Setup parm buffer */ if ((c = get()) == '(') /* With arguments? */ { nargs = 0; /* Init formals counter */ do /* Collect formal parms */ { if (nargs >= LASTPARM) cfatal("Too many arguments for macro", NULLST); else if ((c = skipws()) == ')') break; /* Got them all */ else if (type[c] != LET) /* Bad formal syntax */ goto bad_define; scanid(c); /* Get the formal param */ parlist[nargs++] = parmp; /* Save its start */ textput(token); /* Save text in parm[] */ } while ((c = skipws()) == ','); /* Get another argument */ if (c != ')') /* Must end at ) */ goto bad_define; c = ' '; /* Will skip to body */ } else { /* * DEF_NOARGS is needed to distinguish between * "#define foo" and "#define foo()". */ nargs = DEF_NOARGS; /* No () parameters */ } if (type[c] == SPA) /* At whitespace? */ c = skipws(); /* Not any more. */ workp = work; /* Replacement put here */ inmacro = TRUE; /* Keep \<newline> now */ while (c != EOF_CHAR && c != '\n') /* Compile macro body */ { if (c == '#') /* Token concatenation? */ { while (workp > work && type[(int)workp[-1]] == SPA) --workp; /* Erase leading spaces */ save(TOK_SEP); /* Stuff a delimiter */ c = skipws(); /* Eat whitespace */ if (type[c] == LET) /* Another token here? */ ; /* Stuff it normally */ else if (type[c] == DIG) /* Digit string after? */ { while (type[c] == DIG) /* Stuff the digits */ { save(c); c = get(); } save(TOK_SEP); /* Delimit 2nd token */ } else { ciwarn("Strange character after # (%d.)", c); } continue; } switch (type[c]) { case LET: checkparm(c, dp); /* Might be a formal */ break; case DIG: /* Number in mac. body */ case DOT: /* Maybe a float number */ scannumber(c, save); /* Scan it off */ break; case QUO: /* String in mac. body */ stparmscan(c); break; case BSH: /* Backslash */ save('\\'); if ((c = get()) == '\n') wrongline = TRUE; save(c); break; case SPA: /* Absorb whitespace */ /* * Note: the "end of comment" marker is passed on * to allow comments to separate tokens. */ if (workp[-1] == ' ') /* Absorb multiple */ break; /* spaces */ else if (c == '\t') c = ' '; /* Normalize tabs */ /* Fall through to store character */ default: /* Other character */ save(c); break; } c = get(); } inmacro = FALSE; /* Stop newline hack */ unget(); /* For control check */ if (workp > work && workp[-1] == ' ') /* Drop trailing blank */ workp--; *workp = EOS; /* Terminate work */ dp->repl = savestring(work); /* Save the string */ dp->nargs = nargs; /* Save arg count */ #if OSL_DEBUG_LEVEL > 1 if (debug) dumpadef("macro definition", dp); else if (bDumpDefs) dumpadef(NULL, dp); #endif if (isredefine) /* Error if redefined */ { if ((old != NULL && dp->repl != NULL && !streq(old, dp->repl)) || (old == NULL && dp->repl != NULL) || (old != NULL && dp->repl == NULL)) { #ifdef STRICT_UNDEF cerror("Redefining defined variable \"%s\"", dp->name); #else cwarn("Redefining defined variable \"%s\"", dp->name); #endif } if (old != NULL) /* We don't need the */ free(old); /* old definition now. */ } return; bad_define: cerror("#define syntax error", NULLST); inmacro = FALSE; /* Stop <newline> hack */ }
/* * dooptions is called to process command line arguments (-Detc). * It is called only at cpp startup. */ int dooptions(int argc, char** argv) { char* ap; DEFBUF* dp; int c; int i, j; char* arg; SIZES* sizp; /* For -S */ int size; /* For -S */ int isdatum; /* FALSE for -S* */ int endtest; /* For -S */ 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 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 'I': /* Include directory */ AddInclude( ap ); /* BP, 11.09.91 */ break; case 'N': /* No predefineds */ nflag++; /* Repeat to undefine */ break; /* __LINE__, etc. */ case 'S': sizp = size_table; if (0 != (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 (defendel(ap, TRUE) == NULL) cwarn("\"%s\" wasn't defined", ap); break; #if OSL_DEBUG_LEVEL > 1 case 'X': /* Debug */ debug = (isdigit(*ap)) ? atoi(ap) : 1; #if (HOST == SYS_UNIX) signal(SIGINT, (void (*)(int)) abort); /* Trap "interrupt" */ #endif fprintf(stderr, "Debug set to %d\n", debug); break; #endif #if OSL_DEBUG_LEVEL > 1 case 'P': /* #define's dump */ bDumpDefs = 1; fprintf(stderr, "Dump #define's is on\n"); break; #endif default: /* What is this one? */ cwarn("Unknown option \"%s\"", arg); fprintf(stderr, "The following options are valid:\n\ -C\t\t\tWrite source file comments to output\n\ -Dsymbol=value\tDefine a symbol with the given (optional) value\n\ -Idirectory\t\tAdd a directory to the #include search list\n\ -N\t\t\tDon't predefine target-specific names\n\ -Stext\t\tSpecify sizes for #if sizeof\n\ -Usymbol\t\tUndefine symbol\n"); #if OSL_DEBUG_LEVEL > 1 fprintf(stderr, " -Xvalue\t\tSet internal debug flag\n"); fprintf(stderr, " -P\t\t\tdump #define's\n"); #endif break; } /* Switch on all options */ } /* If it's a -option */ } /* For all arguments */ #if OSL_DEBUG_LEVEL > 1 if ( (bDumpDefs ? j > 4 : j > 3) ) #else if (j > 3) #endif { cerror( "Too many file arguments. Usage: cpp [input [output]]", NULLST); } return (j); /* Return new argc */ }
ReturnCode dodefine(struct Global *global) { /* * Called from control when a #define is scanned. This module * parses formal parameters and the replacement string. When * the formal parameter name is encountered in the replacement * string, it is replaced by a character in the range 128 to * 128+NPARAM (this allows up to 32 parameters within the * Dec Multinational range). If cpp is ported to an EBCDIC * machine, you will have to make other arrangements. * * There is some special case code to distinguish * #define foo bar * from #define foo() bar * * Also, we make sure that * #define foo foo * expands to "foo" but doesn't put cpp into an infinite loop. * * A warning message is printed if you redefine a symbol to a * different text. I.e, * #define foo 123 * #define foo 123 * is ok, but * #define foo 123 * #define foo +123 * is not. * * The following subroutines are called from define(): * checkparm called when a token is scanned. It checks through the * array of formal parameters. If a match is found, the * token is replaced by a control byte which will be used * to locate the parameter when the macro is expanded. * textput puts a string in the macro work area (parm[]), updating * parmp to point to the first free byte in parm[]. * textput() tests for work buffer overflow. * charput puts a single character in the macro work area (parm[]) * in a manner analogous to textput(). */ int c; DEFBUF *dp; /* -> new definition */ int isredefine; /* TRUE if redefined */ char *old = NULL; /* Remember redefined */ ReturnCode ret; #if OK_CONCAT int quoting; /* Remember we saw a # */ #endif if (type[(c = skipws(global))] != LET) { cerror(global, ERROR_DEFINE_SYNTAX); global->inmacro = FALSE; /* Stop <newline> hack */ return(FPP_OK); } isredefine = FALSE; /* Set if redefining */ if ((dp = lookid(global, c)) == NULL) { /* If not known now */ dp = defendel(global, global->tokenbuf, FALSE); /* Save the name */ if(!dp) return(FPP_OUT_OF_MEMORY); } else { /* It's known: */ isredefine = TRUE; /* Remember this fact */ old = dp->repl; /* Remember replacement */ dp->repl = NULL; /* No replacement now */ } global->parlist[0] = global->parmp = global->parm; /* Setup parm buffer */ if ((c = get(global)) == '(') { /* With arguments? */ global->nargs = 0; /* Init formals counter */ do { /* Collect formal parms */ if (global->nargs >= LASTPARM) { cfatal(global, FATAL_TOO_MANY_ARGUMENTS_MACRO); return(FPP_TOO_MANY_ARGUMENTS); } else if ((c = skipws(global)) == ')') break; /* Got them all */ else if (type[c] != LET) { /* Bad formal syntax */ cerror(global, ERROR_DEFINE_SYNTAX); global->inmacro = FALSE; /* Stop <newline> hack */ return(FPP_OK); } scanid(global, c); /* Get the formal param */ global->parlist[global->nargs++] = global->parmp; /* Save its start */ ret=textput(global, global->tokenbuf); /* Save text in parm[] */ if(ret) return(ret); } while ((c = skipws(global)) == ','); /* Get another argument */ if (c != ')') { /* Must end at ) */ cerror(global, ERROR_DEFINE_SYNTAX); global->inmacro = FALSE; /* Stop <newline> hack */ return(FPP_OK); } c = ' '; /* Will skip to body */ } else { /* * DEF_NOARGS is needed to distinguish between * "#define foo" and "#define foo()". */ global->nargs = DEF_NOARGS; /* No () parameters */ } if (type[c] == SPA) /* At whitespace? */ c = skipws(global); /* Not any more. */ global->workp = global->work; /* Replacement put here */ global->inmacro = TRUE; /* Keep \<newline> now */ quoting = 0; /* No # seen yet. */ while (c != EOF_CHAR && c != '\n') { /* Compile macro body */ #if OK_CONCAT if (c == '#') { /* Token concatenation? */ if ((c = get(global)) != '#') { /* No, not really */ quoting = 1; /* Maybe quoting op. */ continue; } while (global->workp > global->work && type[(unsigned)*(global->workp - 1)] == SPA) --global->workp; /* Erase leading spaces */ if((ret=save(global, TOK_SEP))) /* Stuff a delimiter */ return(ret); c = skipws(global); /* Eat whitespace */ continue; } #endif switch (type[c]) { case LET: #if OK_CONCAT ret=checkparm(global, c, dp, quoting); /* Might be a formal */ #else ret=checkparm(c, dp); /* Might be a formal */ #endif if(ret) return(ret); break; case DIG: /* Number in mac. body */ case DOT: /* Maybe a float number */ ret=scannumber(global, c, save); /* Scan it off */ if(ret) return(ret); break; case QUO: /* String in mac. body */ ret=stparmscan(global, c); if(ret) return(ret); break; case BSH: /* Backslash */ ret=save(global, '\\'); if(ret) return(ret); if ((c = get(global)) == '\n') global->wrongline = TRUE; ret=save(global, c); if(ret) return(ret); break; case SPA: /* Absorb whitespace */ /* * Note: the "end of comment" marker is passed on * to allow comments to separate tokens. */ if (global->workp[-1] == ' ') /* Absorb multiple */ break; /* spaces */ else if (c == '\t') c = ' '; /* Normalize tabs */ /* Fall through to store character */ default: /* Other character */ ret=save(global, c); if(ret) return(ret); break; } c = get(global); quoting = 0; /* Only when immediately*/ /* preceding a formal */ } global->inmacro = FALSE; /* Stop newline hack */ unget(global); /* For control check */ if (global->workp > global->work && global->workp[-1] == ' ') /* Drop trailing blank */ global->workp--; *global->workp = EOS; /* Terminate work */ dp->repl = savestring(global, global->work); /* Save the string */ dp->nargs = global->nargs; /* Save arg count */ if (isredefine) { /* Error if redefined */ if ((old != NULL && dp->repl != NULL && !streq(old, dp->repl)) || (old == NULL && dp->repl != NULL) || (old != NULL && dp->repl == NULL)) { cerror(global, ERROR_REDEFINE, dp->name); } if (old != NULL) /* We don't need the */ free(old); /* old definition now. */ } return(FPP_OK); }