504 lines
12 KiB
C
504 lines
12 KiB
C
/* ifdef - remove #ifdefs Author: Warren Toomey */
|
|
|
|
/* Copyright 1989 by Warren Toomey wkt@cs.adfa.oz.au[@uunet.uu.net]
|
|
*
|
|
* You may freely copy or distribute this code as long as this notice
|
|
* remains intact.
|
|
*
|
|
* You may modify this code, as long as this notice remains intact, and
|
|
* you add another notice indicating that the code has been modified.
|
|
*
|
|
* You may NOT sell this code or in any way profit from this code without
|
|
* prior agreement from the author.
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
|
|
/* Definition of structures and constants used in ifdef.c */
|
|
|
|
/* Types of symbols */
|
|
#define DEF 1 /* Symbol is defined */
|
|
#define UNDEF 2 /* Symbol isn't defined */
|
|
#define IGN 3 /* Ignore this symbol unless defined */
|
|
|
|
/* Redef mode values */
|
|
#define MUTABLE 1 /* Symbol can change defined <-> undefined */
|
|
#define IMMUTABLE 2 /* Symbol can't change as above */
|
|
|
|
/* Processing modes */
|
|
#define NO 0 /* Don't process */
|
|
#define YES 1 /* Process */
|
|
|
|
/* Ignore (IGN), ignore but process */
|
|
struct DEFINE {
|
|
char *symbol; /* SLL of defined symbols. The redef */
|
|
char type; /* field indicates if this symbol can */
|
|
char redef; /* change from defined <-> undefined. */
|
|
struct DEFINE *next; /* Type is DEF or UNDEF. */
|
|
};
|
|
|
|
/* Global variables & structures */
|
|
FILE *zin; /* Input file for processing */
|
|
struct DEFINE *defptr; /* Defined symbols SLL */
|
|
struct DEFINE *defend; /* Ptr to last node in defptr */
|
|
struct DEFINE *deftemp; /* Ptr to last found node */
|
|
int line = 1; /* Current line number */
|
|
int table = 0; /* Don't normally want a table */
|
|
|
|
extern int optind;
|
|
extern char *optarg;
|
|
|
|
/* Prototypes. */
|
|
_PROTOTYPE(int main, (int argc, char **argv));
|
|
_PROTOTYPE(char fgetarg, (FILE *stream, char *cbuf));
|
|
_PROTOTYPE(int find, (char *symd));
|
|
_PROTOTYPE(void defit, (char *sym, int redef, int typed));
|
|
_PROTOTYPE(void stop, (void));
|
|
_PROTOTYPE(void gotoeoln, (void));
|
|
_PROTOTYPE(void prteoln, (void));
|
|
_PROTOTYPE(void printtable, (void));
|
|
_PROTOTYPE(char getendif, (void));
|
|
_PROTOTYPE(void gettable, (void));
|
|
_PROTOTYPE(void parse, (void));
|
|
_PROTOTYPE(void usage, (void));
|
|
|
|
#ifdef __STDC__
|
|
char fgetarg ( FILE *stream , char *cbuf )
|
|
#else
|
|
char fgetarg(stream, cbuf) /* Get next arg from file into cbuf, */
|
|
FILE *stream; /* returning the character that */
|
|
char *cbuf; /* terminated it. Cbuf returns 0 */
|
|
#endif
|
|
{ /* if no arg. EOF is returned if no */
|
|
int ch; /* args left in file. */
|
|
int i;
|
|
|
|
i = 0;
|
|
cbuf[i] = 0;
|
|
|
|
while (((ch = fgetc(stream)) == ' ') || (ch == '\t') || (ch == '\n'))
|
|
if (ch == '\n') return(ch); /* Bypass leading */
|
|
/* Whitespace */
|
|
if (feof(stream)) return(EOF);
|
|
|
|
cbuf[i++] = ch;
|
|
|
|
while (((ch = fgetc(stream)) != ' ') && (ch != '\t') && (ch != '\n'))
|
|
cbuf[i++] = ch; /* Get the argument */
|
|
|
|
cbuf[i] = 0;
|
|
return(ch);
|
|
}
|
|
|
|
|
|
#ifdef __STDC__
|
|
int find ( char *sym )
|
|
#else
|
|
int find(sym)
|
|
char *sym;
|
|
#endif
|
|
{ /* Return DEF if defined else UNDEF */
|
|
|
|
deftemp = defptr;
|
|
while (deftemp) { /* Search for the symbol */
|
|
if (!strcmp(deftemp->symbol, sym))
|
|
return(deftemp->type); /* Setting up the type */
|
|
deftemp = deftemp->next;
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
|
|
|
|
#define Define(x,y) defit(x,y,DEF)
|
|
#define Undefine(x,y) defit(x,y,UNDEF)
|
|
#define Ignore(x,y) defit(x,y,IGN)
|
|
|
|
#ifdef __STDC__
|
|
void defit ( char *sym , int redef , int type )
|
|
#else
|
|
void defit(sym, redef, type) /* Add symbol to the define list */
|
|
char *sym;
|
|
char redef; /* Mode: MUTABLE etc */
|
|
char type; /* Type: DEF, UNDEF, IGN */
|
|
#endif
|
|
{
|
|
struct DEFINE *temp;
|
|
char c;
|
|
|
|
c = find(sym); /* First try finding the symbol */
|
|
if (type == c) return; /* Return if already declared */
|
|
if (c) { /* We have to move if from DEF <-> UNDEF */
|
|
if (deftemp->redef == IMMUTABLE)
|
|
return;
|
|
else {
|
|
deftemp->type = type;
|
|
deftemp->redef = redef;
|
|
}
|
|
} else { /* We must create a struct & add it */
|
|
/* Malloc room for the struct */
|
|
if ((temp = (struct DEFINE *)malloc(sizeof(struct DEFINE))) == NULL) {
|
|
(void)fprintf(stderr, "ifdef: could not malloc\n");
|
|
exit(1);
|
|
}
|
|
|
|
/* Malloc room for symbol */
|
|
if ((temp->symbol = (char *)malloc(strlen(sym) + 1)) == NULL) {
|
|
(void)fprintf(stderr, "ifdef: could not malloc\n");
|
|
exit(1);
|
|
}
|
|
(void)strcpy(temp->symbol, sym); /* Copy symbol into struct */
|
|
temp->redef = redef; /* and set its redef mode too */
|
|
temp->type = type; /* as well as making it defined */
|
|
|
|
|
|
/* Now add to the SLL */
|
|
if (defptr == NULL) /* If first node set */
|
|
defptr = temp; /* the pointers to it */
|
|
else
|
|
defend->next = temp; /* else add it to the */
|
|
defend = temp; /* end of the list. */
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#ifdef __STDC__
|
|
void stop ( void )
|
|
#else
|
|
void stop()
|
|
#endif
|
|
{ /* Stop: Tidy up at EOF */
|
|
if (table) printtable();
|
|
(void)fclose(zin);
|
|
exit(0);
|
|
}
|
|
|
|
#define Goto { line++; if (ch!='\n') gotoeoln(); }
|
|
#define Print { line++; if (ch!='\n') prteoln(); }
|
|
|
|
#ifdef __STDC__
|
|
void gotoeoln ( void )
|
|
#else
|
|
void gotoeoln() /* Go to the end of the line */
|
|
#endif
|
|
{
|
|
int ch;
|
|
while ((ch = fgetc(zin)) != '\n')
|
|
if (ch == EOF) stop();
|
|
}
|
|
|
|
|
|
#ifdef __STDC__
|
|
void prteoln ( void )
|
|
#else
|
|
void prteoln() /* Print to the end of the line */
|
|
#endif
|
|
{
|
|
int ch;
|
|
while ((ch = fgetc(zin)) != '\n')
|
|
if (ch == EOF)
|
|
stop();
|
|
else
|
|
(void)putchar(ch);
|
|
(void)putchar('\n');
|
|
}
|
|
|
|
|
|
#ifdef __STDC__
|
|
void printtable ( void )
|
|
#else
|
|
void printtable() /* Print the defines in the SLL */
|
|
#endif
|
|
{
|
|
struct DEFINE *temp;
|
|
|
|
(void)printf("Defined\n\n");
|
|
|
|
temp = defptr;
|
|
while (temp) {
|
|
if (temp->type == DEF) (void)printf("%s\n", temp->symbol);
|
|
temp = temp->next;
|
|
}
|
|
|
|
(void)printf("\n\nUndefined\n\n");
|
|
|
|
temp = defptr;
|
|
while (temp) {
|
|
if (temp->type == UNDEF) (void)printf("%s\n", temp->symbol);
|
|
temp = temp->next;
|
|
}
|
|
}
|
|
|
|
#ifdef __STDC__
|
|
char getendif ( void )
|
|
#else
|
|
char getendif()
|
|
#endif
|
|
{ /* Find matching endif when ignoring */
|
|
char word[80]; /* Buffer for symbols */
|
|
int ch;
|
|
int skip; /* Number of skipped #ifdefs */
|
|
|
|
skip = 1;
|
|
|
|
while (1) {
|
|
/* Scan through the file looking for starting lines */
|
|
if ((ch = fgetc(zin)) == EOF)
|
|
stop(); /* Get first char on the line */
|
|
if (ch != '#') { /* If not a # ignore line */
|
|
(void)putchar(ch);
|
|
Print;
|
|
continue;
|
|
}
|
|
ch = fgetarg(zin, word); /* Get the word after the # */
|
|
|
|
if (!strcmp(word, "ifdef") || !strcmp(word, "ifndef")) skip++;
|
|
/* Keep track of ifdefs & */
|
|
if (!strcmp(word, "endif")) skip--; /* endifs */
|
|
|
|
(void)printf("#%s%c", word, ch); /* Print the line out */
|
|
Print;
|
|
if (!skip) return('\n'); /* If matching endif, return */
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef __STDC__
|
|
void gettable ( void )
|
|
#else
|
|
void gettable() /* Get & print a table of defines etc. */
|
|
#endif
|
|
{
|
|
|
|
char word[80]; /* Buffer for symbols */
|
|
int ch;
|
|
|
|
while (1) {
|
|
/* Scan through the file looking for starting lines */
|
|
if ((ch = fgetc(zin)) == EOF)
|
|
stop(); /* Get first char on the line */
|
|
if (ch != '#') { /* If not a # ignore line */
|
|
Goto;
|
|
continue;
|
|
}
|
|
ch = fgetarg(zin, word); /* Get the word after the # */
|
|
|
|
if (!strcmp(word, "define")) { /* Define: Define the */
|
|
ch = fgetarg(zin, word); /* symbol, and goto */
|
|
Define(word, MUTABLE); /* the end of line */
|
|
Goto;
|
|
continue;
|
|
}
|
|
if (!strcmp(word, "undef")) { /* Undef: Undefine the */
|
|
ch = fgetarg(zin, word); /* symbol, and goto */
|
|
Undefine(word, MUTABLE); /* the end of line */
|
|
Goto;
|
|
continue;
|
|
} /* Ifdef: */
|
|
if (!strcmp(word, "ifdef") || !strcmp(word, "ifndef")) {
|
|
ch = fgetarg(zin, word); /* Get the symbol */
|
|
if (find(word) != DEF)
|
|
Undefine(word, MUTABLE); /* undefine it */
|
|
Goto;
|
|
continue;
|
|
}
|
|
Goto; /* else ignore the line */
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#ifdef __STDC__
|
|
void parse ( void )
|
|
#else
|
|
void parse()
|
|
#endif
|
|
{ /* Parse & remove ifdefs from C source */
|
|
char word[80]; /* Buffer for symbols */
|
|
int ch;
|
|
int proc; /* Should we be processing this bit? */
|
|
int skip; /* Number of skipped #ifdefs */
|
|
|
|
proc = 1;
|
|
skip = 0;
|
|
|
|
while (1) {
|
|
/* Scan through the file looking for starting lines */
|
|
if ((ch = fgetc(zin)) == EOF)
|
|
stop(); /* Get first char on the line */
|
|
if (ch != '#')
|
|
if (proc) { /* If not # and we're processing */
|
|
(void)putchar(ch); /* then print the line */
|
|
Print;
|
|
continue;
|
|
} else {
|
|
Goto; /* else just skip the line */
|
|
continue;
|
|
}
|
|
|
|
ch = fgetarg(zin, word); /* Get the word after the # */
|
|
|
|
if (!strcmp(word, "define") && proc) { /* Define: Define the */
|
|
ch = fgetarg(zin, word); /* symbol, and goto */
|
|
Define(word, MUTABLE); /* the end of line */
|
|
(void)printf("#define %s%c", word, ch);
|
|
Print;
|
|
continue;
|
|
}
|
|
if (!strcmp(word, "undef") && proc) { /* Undef: Undefine the */
|
|
ch = fgetarg(zin, word); /* symbol, and goto */
|
|
Undefine(word, MUTABLE); /* the end of line */
|
|
(void)printf("#undef %s%c", word, ch);
|
|
Print;
|
|
continue;
|
|
}
|
|
if (!strcmp(word, "if")) { /* If: we cannot handle these */
|
|
if (!proc) /* at the moment, so just */
|
|
skip++; /* treat them as an ignored */
|
|
else { /* definition */
|
|
(void)printf("#%s%c",word,ch);
|
|
Print;
|
|
ch = getendif(); /* Get matching endif */
|
|
continue;
|
|
}
|
|
}
|
|
if (!strcmp(word, "ifdef")) { /* Ifdef: */
|
|
if (!proc) /* If not processing */
|
|
skip++; /* skip it */
|
|
else {
|
|
ch = fgetarg(zin, word); /* Get the symbol */
|
|
switch (find(word)) {
|
|
case DEF:
|
|
break;
|
|
case IGN:
|
|
(void)printf("#ifdef %s%c", word, ch);
|
|
Print;
|
|
ch = getendif(); /* Get matching endif */
|
|
break;
|
|
/* If symbol undefined */
|
|
default:
|
|
Undefine(word, MUTABLE); /* undefine it */
|
|
proc = 0; /* & stop processing */
|
|
}
|
|
}
|
|
Goto;
|
|
continue;
|
|
}
|
|
if (!strcmp(word, "ifndef")) {
|
|
/* Ifndef: */
|
|
if (!proc) /* If not processing */
|
|
skip++; /* skip the line */
|
|
else {
|
|
ch = fgetarg(zin, word); /* Get the symbol */
|
|
switch (find(word)) { /* If defined, stop */
|
|
case DEF:
|
|
proc = 0; /* processing */
|
|
break;
|
|
case IGN:
|
|
(void)printf("#ifdef %s%c", word, ch);
|
|
Print;
|
|
ch = getendif(); /* Get matching endif */
|
|
break;
|
|
}
|
|
}
|
|
Goto;
|
|
continue;
|
|
}
|
|
if (!strcmp(word, "else") && !skip) { /* Else: Flip processing */
|
|
proc = !proc;
|
|
Goto;
|
|
continue;
|
|
}
|
|
if (!strcmp(word, "endif")) { /* Endif: If no skipped */
|
|
/* ifdefs turn processing */
|
|
if (!skip) /* on, else decrement the */
|
|
proc = 1; /* number of skips */
|
|
else
|
|
skip--;
|
|
Goto;
|
|
continue;
|
|
}
|
|
/* The word fails all of the above tests, so if we're */
|
|
/* processing, print the line. */
|
|
if (proc) {
|
|
(void)printf("#%s%c", word, ch);
|
|
Print;
|
|
} else
|
|
Goto;
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef __STDC__
|
|
void usage ( void )
|
|
#else
|
|
void usage()
|
|
#endif
|
|
{
|
|
(void)fprintf(stderr, "Usage: ifdef [-t] [-Dsymbol] [-dsymbol] [-Usymbol] [-Isymbol] <file>\n");
|
|
exit(0);
|
|
}
|
|
|
|
|
|
#ifdef __STDC__
|
|
int main(int argc , char *argv [])
|
|
#else
|
|
int main(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
#endif
|
|
{
|
|
char sym[80]; /* Temp symbol storage */
|
|
int c;
|
|
|
|
if (argc == 1) usage(); /* Catch the curious user */
|
|
while ((c = getopt(argc, argv, "tD:d:U:I:")) != EOF) {
|
|
switch (c) {
|
|
case 't':
|
|
table = 1; /* Get the various options */
|
|
break;
|
|
|
|
case 'd':
|
|
(void)strcpy(sym, optarg);
|
|
Define(sym, MUTABLE);
|
|
break;
|
|
|
|
case 'D':
|
|
(void)strcpy(sym, optarg);
|
|
Define(sym, IMMUTABLE);
|
|
break;
|
|
|
|
case 'U':
|
|
(void)strcpy(sym, optarg);
|
|
Undefine(sym, IMMUTABLE);
|
|
break;
|
|
|
|
case 'I':
|
|
(void)strcpy(sym, optarg);
|
|
Ignore(sym, IMMUTABLE);
|
|
break;
|
|
|
|
default: usage();
|
|
}
|
|
}
|
|
|
|
zin = stdin; /* If a C file is named */
|
|
/* Open stdin with it */
|
|
if (*argv[argc - 1] != '-') {
|
|
(void)fclose(zin);
|
|
if ((zin = fopen(argv[argc - 1], "r")) == NULL) {
|
|
perror("ifdef");
|
|
exit(1);
|
|
}
|
|
}
|
|
if (table)
|
|
gettable(); /* Either generate a table or */
|
|
else
|
|
parse(); /* parse & replace with the file */
|
|
return(0);
|
|
}
|