/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* Copyright (c) 1982 Regents of the University of California */ /* * unifdef - remove ifdef'ed lines */ #include #include #include #include #include #include FILE *input; #ifndef YES #define YES 1 #define NO 0 #endif char *progname; char *filename; char text; /* -t option in effect: this is a text file */ char lnblank; /* -l option in effect: blank deleted lines */ char complement; /* -c option in effect: complement the operation */ #define MAXSYMS 100 char true[MAXSYMS]; char ignore[MAXSYMS]; char *sym[MAXSYMS]; signed char insym[MAXSYMS]; #define KWSIZE 8 char buf[KWSIZE]; char nsyms; char incomment; #define QUOTE1 0 #define QUOTE2 1 char inquote[2]; int exitstat; static char *skipcomment(char *cp); static char *skipquote(char *cp, int type); static char *nextsym(char *p); static int doif(int thissym, int inif, int prevreject, int depth); static void pfile(void); static int getlin(char *line, int maxline, FILE *inp, int expandtabs); static void prname(void); static void flushline(int keep); static int checkline(int *cursym); static int error(int err, int line, int depth); static void putlin(char *line, FILE *fio); static void usage(void) { (void) fprintf(stderr, gettext( "Usage: %s [-l] [-t] [-c] [[-Dsym] [-Usym] [-idsym] " "[-iusym]]... [file]\n" " At least one arg from [-D -U -id -iu] is required\n"), progname); exit(2); } int main(int argc, char **argv) { char **curarg; char *cp; char *cp1; char ignorethis; (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" #endif (void) textdomain(TEXT_DOMAIN); progname = argv[0][0] ? argv[0] : "unifdef"; for (curarg = &argv[1]; --argc > 0; curarg++) { if (*(cp1 = cp = *curarg) != '-') break; if (*++cp1 == 'i') { ignorethis = YES; cp1++; } else ignorethis = NO; if ((*cp1 == 'D' || *cp1 == 'U') && cp1[1] != '\0') { if (nsyms >= MAXSYMS) { prname(); (void) fprintf(stderr, gettext("too many symbols.\n")); exit(2); } ignore[nsyms] = ignorethis; true[nsyms] = *cp1 == 'D' ? YES : NO; sym[nsyms++] = &cp1[1]; } else if (ignorethis) goto unrec; else if (strcmp(&cp[1], "t") == 0) text = YES; else if (strcmp(&cp[1], "l") == 0) lnblank = YES; else if (strcmp(&cp[1], "c") == 0) complement = YES; else { unrec: prname(); (void) fprintf(stderr, gettext("unrecognized option: %s\n"), cp); usage(); } } if (nsyms == 0) { usage(); } if (argc > 1) { prname(); (void) fprintf(stderr, gettext("can only do one file.\n")); } else if (argc == 1) { filename = *curarg; if ((input = fopen(filename, "r")) != NULL) { pfile(); (void) fclose(input); } else { prname(); perror(*curarg); } } else { filename = "[stdin]"; input = stdin; pfile(); } (void) fflush(stdout); return (exitstat); } /* types of input lines: */ #define PLAIN 0 /* ordinary line */ #define TRUE 1 /* a true #ifdef of a symbol known to us */ #define FALSE 2 /* a false #ifdef of a symbol known to us */ #define OTHER 3 /* an #ifdef of a symbol not known to us */ #define ELSE 4 /* #else */ #define ENDIF 5 /* #endif */ #define LEOF 6 /* end of file */ /* should be int declaration, was char */ int reject; /* 0 or 1: pass thru; 1 or 2: ignore comments */ int linenum; /* current line number */ int stqcline; /* start of current comment or quote */ char *errs[] = { #define NO_ERR 0 "", #define END_ERR 1 "", #define ELSE_ERR 2 "Inappropriate else", #define ENDIF_ERR 3 "Inappropriate endif", #define IEOF_ERR 4 "Premature EOF in ifdef", #define CEOF_ERR 5 "Premature EOF in comment", #define Q1EOF_ERR 6 "Premature EOF in quoted character", #define Q2EOF_ERR 7 "Premature EOF in quoted string" }; static void pfile(void) { reject = 0; (void) doif(-1, NO, reject, 0); } static int doif( int thissym, /* index of the symbol who was last ifdef'ed */ int inif, /* YES or NO we are inside an ifdef */ int prevreject, /* previous value of reject */ int depth /* depth of ifdef's */ ) { int lineval; int thisreject; int doret; /* tmp return value of doif */ int cursym; /* index of the symbol returned by checkline */ int stline; /* line number when called this time */ int err; stline = linenum; for (;;) { switch (lineval = checkline(&cursym)) { case PLAIN: flushline(YES); break; case TRUE: case FALSE: thisreject = reject; if (lineval == TRUE) insym[cursym] = 1; else { if (reject < 2) reject = ignore[cursym] ? 1 : 2; insym[cursym] = -1; } if (ignore[cursym]) flushline(YES); else { exitstat = 0; flushline(NO); } if ((doret = doif(cursym, YES, thisreject, depth + 1)) != NO_ERR) return (error(doret, stline, depth)); break; case OTHER: flushline(YES); if ((doret = doif(-1, YES, reject, depth + 1)) != NO_ERR) return (error(doret, stline, depth)); break; case ELSE: if (inif != 1) return (error(ELSE_ERR, linenum, depth)); inif = 2; if (thissym >= 0) { if ((insym[thissym] = -insym[thissym]) < 0) reject = ignore[thissym] ? 1 : 2; else reject = prevreject; if (!ignore[thissym]) { flushline(NO); break; } } flushline(YES); break; case ENDIF: if (inif == 0) return (error(ENDIF_ERR, linenum, depth)); if (thissym >= 0) { insym[thissym] = 0; reject = prevreject; if (!ignore[thissym]) { flushline(NO); return (NO_ERR); } } flushline(YES); return (NO_ERR); case LEOF: err = incomment ? CEOF_ERR : inquote[QUOTE1] ? Q1EOF_ERR : inquote[QUOTE2] ? Q2EOF_ERR : NO_ERR; if (inif) { if (err != NO_ERR) (void) error(err, stqcline, depth); return (error(IEOF_ERR, stline, depth)); } else if (err != NO_ERR) return (error(err, stqcline, depth)); else return (NO_ERR); } } } #define endsym(c) (!isalpha(c) && !isdigit(c) && c != '_') #define MAXLINE 256 char tline[MAXLINE]; static int checkline(int *cursym) { char *cp; char *symp; char chr; char *scp; int retval; int symind; char keyword[KWSIZE]; linenum++; if (getlin(tline, sizeof (tline), input, NO) == EOF) return (LEOF); retval = PLAIN; if (*(cp = tline) != '#' || incomment || inquote[QUOTE1] || inquote[QUOTE2]) goto eol; cp = skipcomment(++cp); symp = keyword; while (!endsym (*cp)) { *symp = *cp++; if (++symp >= &keyword[KWSIZE]) goto eol; } *symp = '\0'; if (strcmp(keyword, "ifdef") == 0) { retval = YES; goto ifdef; } else if (strcmp(keyword, "if") == 0) { cp = skipcomment(++cp); if (strcmp(nextsym(cp), "defined") == 0) { cp += strlen("defined") + 1; /* skip to identifier */ while (endsym(*cp)) ++cp; retval = YES; goto ifdef; } else { retval = OTHER; goto eol; } } else if (strcmp(keyword, "ifndef") == 0) { retval = NO; ifdef: scp = cp = skipcomment(cp); if (incomment) { retval = PLAIN; goto eol; } symind = 0; for (;;) { if (insym[symind] == 0) { for (symp = sym[symind], cp = scp; *symp && *cp == *symp; cp++, symp++) { /* NULL */ } chr = *cp; if (*symp == '\0' && endsym(chr)) { *cursym = symind; retval = (retval ^ true[symind]) ? FALSE : TRUE; break; } } if (++symind >= nsyms) { retval = OTHER; break; } } } else if (strcmp(keyword, "else") == 0) retval = ELSE; else if (strcmp(keyword, "endif") == 0) retval = ENDIF; eol: if (!text && !reject) while (*cp) { if (incomment) cp = skipcomment(cp); else if (inquote[QUOTE1]) cp = skipquote(cp, QUOTE1); else if (inquote[QUOTE2]) cp = skipquote(cp, QUOTE2); else if (*cp == '/' && cp[1] == '*') cp = skipcomment(cp); else if (*cp == '\'') cp = skipquote(cp, QUOTE1); else if (*cp == '"') cp = skipquote(cp, QUOTE2); else cp++; } return (retval); } /* * Skip over comments and stop at the next character * position that is not whitespace. */ static char * skipcomment(char *cp) { if (incomment) goto inside; for (;;) { while (*cp == ' ' || *cp == '\t') cp++; if (text) return (cp); if (cp[0] != '/' || cp[1] != '*') return (cp); cp += 2; if (!incomment) { incomment = YES; stqcline = linenum; } inside: for (;;) { for (; *cp != '*'; cp++) if (*cp == '\0') return (cp); if (*++cp == '/') break; } incomment = NO; cp++; } } /* * Skip over a quoted string or character and stop at the next charaacter * position that is not whitespace. */ static char * skipquote(char *cp, int type) { char qchar; qchar = type == QUOTE1 ? '\'' : '"'; if (inquote[type]) goto inside; for (;;) { if (*cp != qchar) return (cp); cp++; if (!inquote[type]) { inquote[type] = YES; stqcline = linenum; } inside: for (; ; cp++) { if (*cp == qchar) break; if (*cp == '\0' || *cp == '\\' && *++cp == '\0') return (cp); } inquote[type] = NO; cp++; } } /* * special getlin - treats form-feed as an end-of-line * and expands tabs if asked for */ static int getlin(char *line, int maxline, FILE *inp, int expandtabs) { int tmp; int num; int chr; #ifdef FFSPECIAL static char havechar = NO; /* have leftover char from last time */ static char svchar; #endif num = 0; #ifdef FFSPECIAL if (havechar) { havechar = NO; chr = svchar; goto ent; } #endif while (num + 8 < maxline) { /* leave room for tab */ chr = getc(inp); if (isprint(chr)) { #ifdef FFSPECIAL ent: #endif *line++ = chr; num++; } else switch (chr) { case EOF: return (EOF); case '\t': if (expandtabs) { num += tmp = 8 - (num & 7); do *line++ = ' '; while (--tmp); break; } /* FALLTHROUGH */ default: *line++ = chr; num++; break; case '\n': *line = '\n'; num++; goto end; #ifdef FFSPECIAL case '\f': if (++num == 1) *line = '\f'; else { *line = '\n'; havechar = YES; svchar = chr; } goto end; #endif } } end: *++line = '\0'; return (num); } static void flushline(int keep) { if ((keep && reject < 2) ^ complement) putlin(tline, stdout); else if (lnblank) putlin("\n", stdout); } /* * putlin - for tools */ static void putlin(char *line, FILE *fio) { char chr; while (chr = *line++) (void) putc(chr, fio); } static void prname(void) { (void) fprintf(stderr, "%s: ", progname); } static int error(int err, int line, int depth) { if (err == END_ERR) return (err); prname(); #ifndef TESTING (void) fprintf(stderr, gettext("Error in %s line %d: %s.\n"), filename, line, gettext(errs[err])); #endif #ifdef TESTING (void) fprintf(stderr, gettext("Error in %s line %d: %s. "), filename, line, errs[err]); (void) fprintf(stderr, gettext("ifdef depth: %d\n"), depth); #endif exitstat = 1; return (depth > 1 ? IEOF_ERR : END_ERR); } /* return the next token in the line buffer */ char * nextsym(char *p) { char *key; int i = KWSIZE; key = buf; while (!endsym(*p) && --i) *key++ = *p++; *key = '\0'; return (buf); }