wkt@ccadfa.adfa.oz.au (Warren Toomey) (11/14/90)
Before 1.6 hits the beta mailing list, here's a new version of ifdef(1) that copes with #if's. Whole source, as the diffs were longer. I also include a manual, as 1.5 didn't have one. I just noticed a patch for Clam under MacMinix - I'll have to integrate that into the next version, which is due out soon, if I ever get re-enthused with it. Also in the pipeline is a new version of dump(8), which does multi-vol backups. Warren Toomey echo x - ifdef.c sed '/^X/s///' > ifdef.c << '/' X/* Ifdef - remove #ifdefs Author: Warren Toomey */ X X/* Ifdef: Remove unwanted ifdefs from C code */ X/* Written by Warren Toomey - 1989 */ X/* You may freely copy or give away this source as */ X/* Long as this notice remains intact. */ X/* 890916 - Added usage() before getopt() - meb */ X/* 900517 - Added (limited) support for #if's */ X X#include <sys/types.h> X#include <string.h> X#include <stdlib.h> X#include <stdio.h> X X/* Definition of structures and constants used in ifdef.c */ X X/* Types of symbols */ X#define DEF 1 /* Symbol is defined */ X#define UNDEF 2 /* Symbol isn't defined */ X#define IGN 3 /* Ignore this symbol unless defined */ X X/* Redef mode values */ X#define MUTABLE 1 /* Symbol can change defined <-> undefined */ X#define IMMUTABLE 2 /* Symbol can't change as above */ X X/* Processing modes */ X#define NO 0 /* Don't process */ X#define YES 1 /* Process */ X X/* Ignore (IGN), ignore but process */ Xstruct DEFINE { X char *symbol; /* SLL of defined symbols. The redef */ X char type; /* field indicates if this symbol can */ X char redef; /* change from defined <-> undefined. */ X struct DEFINE *next; /* Type is DEF or UNDEF. */ X}; X X/* Global variables & structures */ XFILE *zin; /* Input file for processing */ Xstruct DEFINE *defptr; /* Defined symbols SLL */ Xstruct DEFINE *defend; /* Ptr to last node in defptr */ Xstruct DEFINE *deftemp; /* Ptr to last found node */ Xint line = 1; /* Current line number */ Xint table = 0; /* Don't normally want a table */ X X/* Forward declarations, sigh */ Xvoid printtable(); X X#ifdef __STDC__ Xchar fgetarg ( FILE *stream , char *cbuf ) X#else Xchar fgetarg(stream, cbuf) /* Get next arg from file into cbuf, */ XFILE *stream; /* returning the character that */ Xchar *cbuf; /* terminated it. Cbuf returns 0 */ X#endif X{ /* if no arg. EOF is returned if no */ X int ch; /* args left in file. */ X int i; X X i = 0; X cbuf[i] = 0; X X while (((ch = fgetc(stream)) == ' ') || (ch == '\t') || (ch == '\n')) X if (ch == '\n') return(ch); /* Bypass leading */ X /* Whitespace */ X if (feof(stream)) return(EOF); X X cbuf[i++] = ch; X X while (((ch = fgetc(stream)) != ' ') && (ch != '\t') && (ch != '\n')) X cbuf[i++] = ch; /* Get the argument */ X X cbuf[i] = 0; X return(ch); X} X X X#ifdef __STDC__ Xint find ( char *sym ) X#else Xint find(sym) Xchar *sym; X#endif X{ /* Return DEF if defined else UNDEF */ X X deftemp = defptr; X while (deftemp) { /* Search for the symbol */ X if (!strcmp(deftemp->symbol, sym)) X return(deftemp->type); /* Setting up the type */ X deftemp = deftemp->next; X } X return(0); X} X X X X#define Define(x,y) defit(x,y,DEF) X#define Undefine(x,y) defit(x,y,UNDEF) X#define Ignore(x,y) defit(x,y,IGN) X X#ifdef __STDC__ Xvoid defit ( char *sym , int redef , int type ) X#else Xvoid defit(sym, redef, type) /* Add symbol to the define list */ Xchar *sym; Xchar redef; /* Mode: MUTABLE etc */ Xchar type; /* Type: DEF, UNDEF, IGN */ X#endif X{ X struct DEFINE *temp; X char c; X X c = find(sym); /* First try finding the symbol */ X if (type == c) return; /* Return if already declared */ X if (c) { /* We have to move if from DEF <-> UNDEF */ X if (deftemp->redef == IMMUTABLE) X return; X else { X deftemp->type = type; X deftemp->redef = redef; X } X } else { /* We must create a struct & add it */ X /* Malloc room for the struct */ X if ((temp = (struct DEFINE *)malloc((unsigned)sizeof(struct DEFINE))) == NULL) { X (void)fprintf(stderr, "ifdef: could not malloc\n"); X exit(1); X } X X /* Malloc room for symbol */ X if ((temp->symbol = (char *)malloc((unsigned)strlen(sym) + 1)) == NULL) { X (void)fprintf(stderr, "ifdef: could not malloc\n"); X exit(1); X } X (void)strcpy(temp->symbol, sym); /* Copy symbol into struct */ X temp->redef = redef; /* and set its redef mode too */ X temp->type = type; /* as well as making it defined */ X X X /* Now add to the SLL */ X if (defptr == NULL) /* If first node set */ X defptr = temp; /* the pointers to it */ X else X defend->next = temp; /* else add it to the */ X defend = temp; /* end of the list. */ X } X} X X X X#ifdef __STDC__ Xvoid stop ( void ) X#else Xvoid stop() X#endif X{ /* Stop: Tidy up at EOF */ X if (table) printtable(); X (void)fclose(zin); X exit(0); X} X X#define Goto { line++; if (ch!='\n') gotoeoln(); } X#define Print { line++; if (ch!='\n') prteoln(); } X X#ifdef __STDC__ Xvoid gotoeoln ( void ) X#else Xvoid gotoeoln() /* Go to the end of the line */ X#endif X{ X int ch; X while ((ch = fgetc(zin)) != '\n') X if (ch == EOF) stop(); X} X X X#ifdef __STDC__ Xvoid prteoln ( void ) X#else Xvoid prteoln() /* Print to the end of the line */ X#endif X{ X int ch; X while ((ch = fgetc(zin)) != '\n') X if (ch == EOF) X stop(); X else X (void)putchar(ch); X (void)putchar('\n'); X} X X X#ifdef __STDC__ Xvoid printtable ( void ) X#else Xvoid printtable() /* Print the defines in the SLL */ X#endif X{ X struct DEFINE *temp; X X (void)printf("Defined\n\n"); X X temp = defptr; X while (temp) { X if (temp->type == DEF) (void)printf("%s\n", temp->symbol); X temp = temp->next; X } X X (void)printf("\n\nUndefined\n\n"); X X temp = defptr; X while (temp) { X if (temp->type == UNDEF) (void)printf("%s\n", temp->symbol); X temp = temp->next; X } X} X X#ifdef __STDC__ Xchar getendif ( void ) X#else Xchar getendif() X#endif X{ /* Find matching endif when ignoring */ X char word[80]; /* Buffer for symbols */ X int ch; X int skip; /* Number of skipped #ifdefs */ X X skip = 1; X X while (1) { X /* Scan through the file looking for starting lines */ X if ((ch = fgetc(zin)) == EOF) X stop(); /* Get first char on the line */ X if (ch != '#') { /* If not a # ignore line */ X (void)putchar(ch); X Print; X continue; X } X ch = fgetarg(zin, word); /* Get the word after the # */ X X if (!strcmp(word, "ifdef") || !strcmp(word, "ifndef")) skip++; X /* Keep track of ifdefs & */ X if (!strcmp(word, "endif")) skip--; /* endifs */ X X (void)printf("#%s%c", word, ch); /* Print the line out */ X Print; X if (!skip) return('\n'); /* If matching endif, return */ X } X} X X X#ifdef __STDC__ Xvoid gettable ( void ) X#else Xvoid gettable() /* Get & print a table of defines etc. */ X#endif X{ X X char word[80]; /* Buffer for symbols */ X int ch; X X while (1) { X /* Scan through the file looking for starting lines */ X if ((ch = fgetc(zin)) == EOF) X stop(); /* Get first char on the line */ X if (ch != '#') { /* If not a # ignore line */ X Goto; X continue; X } X ch = fgetarg(zin, word); /* Get the word after the # */ X X if (!strcmp(word, "define")) { /* Define: Define the */ X ch = fgetarg(zin, word); /* symbol, and goto */ X Define(word, MUTABLE); /* the end of line */ X Goto; X continue; X } X if (!strcmp(word, "undef")) { /* Undef: Undefine the */ X ch = fgetarg(zin, word); /* symbol, and goto */ X Undefine(word, MUTABLE); /* the end of line */ X Goto; X continue; X } /* Ifdef: */ X if (!strcmp(word, "ifdef") || !strcmp(word, "ifndef")) { X ch = fgetarg(zin, word); /* Get the symbol */ X if (find(word) != DEF) X Undefine(word, MUTABLE); /* undefine it */ X Goto; X continue; X } X Goto; /* else ignore the line */ X } X} X X X X#ifdef __STDC__ Xvoid parse ( void ) X#else Xvoid parse() X#endif X{ /* Parse & remove ifdefs from C source */ X char word[80]; /* Buffer for symbols */ X int ch; X int proc; /* Should we be processing this bit? */ X int skip; /* Number of skipped #ifdefs */ X X proc = 1; X skip = 0; X X while (1) { X /* Scan through the file looking for starting lines */ X if ((ch = fgetc(zin)) == EOF) X stop(); /* Get first char on the line */ X if (ch != '#') X if (proc) { /* If not # and we're processing */ X (void)putchar(ch); /* then print the line */ X Print; X continue; X } else { X Goto; /* else just skip the line */ X continue; X } X X ch = fgetarg(zin, word); /* Get the word after the # */ X X if (!strcmp(word, "define") && proc) { /* Define: Define the */ X ch = fgetarg(zin, word); /* symbol, and goto */ X Define(word, MUTABLE); /* the end of line */ X (void)printf("#define %s%c", word, ch); X Print; X continue; X } X if (!strcmp(word, "undef") && proc) { /* Undef: Undefine the */ X ch = fgetarg(zin, word); /* symbol, and goto */ X Undefine(word, MUTABLE); /* the end of line */ X (void)printf("#undef %s%c", word, ch); X Print; X continue; X } X if (!strcmp(word, "if")) { /* If: we cannot handle these */ X if (!proc) /* at the moment, so just */ X skip++; /* treat them as an ignored */ X else { /* definition */ X (void)printf("#%s%c",word,ch); X Print; X ch = getendif(); /* Get matching endif */ X continue; X } X } X if (!strcmp(word, "ifdef")) { /* Ifdef: */ X if (!proc) /* If not processing */ X skip++; /* skip it */ X else { X ch = fgetarg(zin, word); /* Get the symbol */ X switch (find(word)) { X case DEF: X break; X case IGN: X (void)printf("#ifdef %s%c", word, ch); X Print; X ch = getendif(); /* Get matching endif */ X break; X /* If symbol undefined */ X default: X Undefine(word, MUTABLE); /* undefine it */ X proc = 0; /* & stop processing */ X } X } X Goto; X continue; X } X if (!strcmp(word, "ifndef")) { X /* Ifndef: */ X if (!proc) /* If not processing */ X skip++; /* skip the line */ X else { X ch = fgetarg(zin, word); /* Get the symbol */ X switch (find(word)) { /* If defined, stop */ X case DEF: X proc = 0; /* processing */ X break; X case IGN: X (void)printf("#ifdef %s%c", word, ch); X Print; X ch = getendif(); /* Get matching endif */ X break; X } X } X Goto; X continue; X } X if (!strcmp(word, "else") && !skip) { /* Else: Flip processing */ X proc = !proc; X Goto; X continue; X } X if (!strcmp(word, "endif")) { /* Endif: If no skipped */ X /* ifdefs turn processing */ X if (!skip) /* on, else decrement the */ X proc = 1; /* number of skips */ X else X skip--; X Goto; X continue; X } X /* The word fails all of the above tests, so if we're */ X /* processing, print the line. */ X if (proc) { X (void)printf("#%s%c", word, ch); X Print; X } else X Goto; X } X} X X X#ifdef __STDC__ Xvoid usage ( void ) X#else Xvoid usage() X#endif X{ X (void)fprintf(stderr, "Usage: ifdef [-t] [-Dsymbol] [-dsymbol] [-Usymbol] [-Isymbol] <file>\n"); X exit(0); X} X X X#ifdef __STDC__ Xint main ( int argc , char *argv []) X#else Xint main(argc, argv) Xint argc; Xchar *argv[]; X#endif X{ X extern int optind; X extern char *optarg; X X char sym[80]; /* Temp symbol storage */ X int c; X X if (argc == 1) usage(); /* Catch the curious user */ X while ((c = getopt(argc, argv, "tD:d:U:I:")) != EOF) { X switch (c) { X case 't': X table = 1; /* Get the various options */ X break; X X case 'd': X (void)strcpy(sym, optarg); X Define(sym, MUTABLE); X break; X X case 'D': X (void)strcpy(sym, optarg); X Define(sym, IMMUTABLE); X break; X X case 'U': X (void)strcpy(sym, optarg); X Undefine(sym, IMMUTABLE); X break; X X case 'I': X (void)strcpy(sym, optarg); X Ignore(sym, IMMUTABLE); X break; X X default: usage(); X } X } X X zin = stdin; /* If a C file is named */ X /* Open stdin with it */ X if (*argv[argc - 1] != '-') { X (void)fclose(zin); X if ((zin = fopen(argv[argc - 1], "r")) == NULL) { X perror("ifdef"); X exit(1); X } X } X if (table) X gettable(); /* Either generate a table or */ X else X parse(); /* parse & replace with the file */ X} / echo x - ifdef.1 sed '/^X/s///' > ifdef.1 << '/' X.TH ifdef 1L X.SH NAME Xifdef \- remove conditional code from C files X.SH SYNTAX Xifdef [\-t] [\-dsymbol] [\-Dsymbol] [\-Usymbol] [\-Isymbol] <file> X.SH OPTIONS XOptions are processed by X.B getopts(3). X.TP 8 X.B \-t XTable mode. X.I Ifdef Xproduces a table of the defined and undefined symbols in the given file. X.TP X.B \-dsymbol XDefine the symbol before processing takes place. Note that if the symbol Xis later #undef'd, then it will become undefined. X.TP X.B \-Dsymbol XDefine the symbol, and make it X.I immutable. XThat is, later #undef's will not undefine the symbol. X.TP X.B \-Usymbol XUndefine the symbol, and make it X.I immutable. XSuccessive #define's will not define this symbol. X.TP X.B \-Isymbol XIgnore this symbol in processing. #ifdef's using this symbol will be Xleft in the output code. X.SH DESCRIPTION X.I Ifdef Xis a small program which allows conditional code [ #ifdef ... #endif ] Xto be selectively removed from C files, but at the same time leaving Xall other C preprocessor commands intact [ #define, #include etc ]. XThe resulting code can then be viewed or compiled with any unnecessary Xconditional code missing. X.PP XInput to X.I ifdef Xis either a X.B file Xnamed as the last argument, or standard input if no file is named. X.I Ifdef Xtakes the input file, and processes it, removing unwanted conditional Xcode. The resulting code is placed on the standard output. X.PP XSymbols may be Xdefined with the X.B \-d Xand X.B \-D Xoptions ( like the C preprocessor ), except that the latter option Xmakes the symbol X.I immutable, Xand hence cannot be #undef'd at a later time. Similarly, the X.B \-U Xoption undefines a symbol X.I immutably, Xpreventing it from being #define'd at a later time. Note that symbols Xnot mentioned at runtime are undefined but mutable. X.PP X.I Ifdef Xignores any values given to a symbol; in fact, if given an option of Xthe form X.PP X\-DLEVEL=22 X.PP Xthen it will assume the defined symbol is X.B LEVEL=22. X.PP XThe X.B \-I Xoption allows a specific symbol to be Xignored thoughout the processing of the file. Any #ifdef code Xusing the symbol will be left intact in the output code. X.PP XFinally, the X.B \-t Xoption puts X.I ifdef Xinto table mode; instead of putting the resulting code on the standard Xoutput, X.I ifdef Xreturns a list of symbols that were defined or not defined in the code. XThis is useful for finding out what symbols are tested for in a new Xpiece of code. When this option is used, all #defines will be found, so Xthat X.PP X.B #define FOO X.PP X.B #undef FOO X.PP Xwill make X.I ifdef Xbelieve FOO is undefined, although it may have been defined for parts of the Xcode. X.SH BUGS XNo checking is done to see if the conditional code is semantically Xcorrect. Missing or extra #ifdef's etc. are not detected. X.I Ifdef Xprovides limited support for the preprocessor directives #if and #elif, by Xtreating them as an ignored symbol, and leaving the enclosed code in the Xoutput. X.PP X.SH SEE ALSO Xcpp(1), scpp(1L). / -- Warren Toomey VK1XWT, rescreened. Deep in the bowels of ADFA Comp Science. `What the hell is SIGTTIN?'