Annotation of 43BSDReno/pgrm/unifdef/unifdef.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1985 The Regents of the University of California.
                      3:  * All rights reserved.
                      4:  *
                      5:  * This code is derived from software contributed to Berkeley by
                      6:  * Dave Yost.
                      7:  *
                      8:  * Redistribution and use in source and binary forms are permitted
                      9:  * provided that: (1) source distributions retain this entire copyright
                     10:  * notice and comment, and (2) distributions including binaries display
                     11:  * the following acknowledgement:  ``This product includes software
                     12:  * developed by the University of California, Berkeley and its contributors''
                     13:  * in the documentation or other materials provided with the distribution
                     14:  * and in all advertising materials mentioning features or use of this
                     15:  * software. Neither the name of the University nor the names of its
                     16:  * contributors may be used to endorse or promote products derived
                     17:  * from this software without specific prior written permission.
                     18:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
                     19:  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
                     20:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
                     21:  */
                     22: 
                     23: #ifndef lint
                     24: char copyright[] =
                     25: "@(#) Copyright (c) 1985 The Regents of the University of California.\n\
                     26:  All rights reserved.\n";
                     27: #endif /* not lint */
                     28: 
                     29: #ifndef lint
                     30: static char sccsid[] = "@(#)unifdef.c  4.7 (Berkeley) 6/1/90";
                     31: #endif /* not lint */
                     32: 
                     33: /*
                     34:  * unifdef - remove ifdef'ed lines
                     35:  *
                     36:  *  Warning: will not work correctly if input contains null characters.
                     37:  *
                     38:  *  Wishlist:
                     39:  *      provide an option which will append the name of the
                     40:  *        appropriate symbol after #else's and #endif's
                     41:  *      provide an option which will check symbols after
                     42:  *        #else's and #endif's to see that they match their
                     43:  *        corresponding #ifdef or #ifndef
                     44:  */
                     45: 
                     46: #include <stdio.h>
                     47: #include <ctype.h>
                     48: 
                     49: #define BSS
                     50: FILE *input;
                     51: #ifndef YES
                     52: #define YES 1
                     53: #define NO  0
                     54: #endif/*YES */
                     55: typedef int Bool;
                     56: 
                     57: char *progname BSS;
                     58: char *filename BSS;
                     59: char text BSS;          /* -t option in effect: this is a text file */
                     60: char lnblank BSS;       /* -l option in effect: blank deleted lines */
                     61: char complement BSS;    /* -c option in effect: complement the operation */
                     62: 
                     63: #define MAXSYMS 100
                     64: char *symname[MAXSYMS] BSS; /* symbol name */
                     65: char true[MAXSYMS] BSS;     /* -Dsym */
                     66: char ignore[MAXSYMS] BSS;   /* -iDsym or -iUsym */
                     67: char insym[MAXSYMS] BSS;    /* state: false, inactive, true */
                     68: #define SYM_INACTIVE 0      /* symbol is currently inactive */
                     69: #define SYM_FALSE    1      /* symbol is currently false */
                     70: #define SYM_TRUE     2      /* symbol is currently true  */
                     71: 
                     72: char nsyms BSS;
                     73: char incomment BSS;         /* inside C comment */
                     74: 
                     75: #define QUOTE_NONE   0
                     76: #define QUOTE_SINGLE 1
                     77: #define QUOTE_DOUBLE 2
                     78: char inquote BSS;           /* inside single or double quotes */
                     79: 
                     80: int exitstat BSS;
                     81: char *skipcomment ();
                     82: char *skipquote ();
                     83: 
                     84: main (argc, argv)
                     85: int argc;
                     86: char **argv;
                     87: {
                     88:     char **curarg;
                     89:     register char *cp;
                     90:     register char *cp1;
                     91:     char ignorethis;
                     92: 
                     93:     progname = argv[0][0] ? argv[0] : "unifdef";
                     94: 
                     95:     for (curarg = &argv[1]; --argc > 0; curarg++) {
                     96:        if (*(cp1 = cp = *curarg) != '-')
                     97:            break;
                     98:        if (*++cp1 == 'i') {
                     99:            ignorethis = YES;
                    100:            cp1++;
                    101:        } else
                    102:            ignorethis = NO;
                    103:        if (   (   *cp1 == 'D'
                    104:                || *cp1 == 'U'
                    105:               )
                    106:            && cp1[1] != '\0'
                    107:           ) {
                    108:            register int symind;
                    109: 
                    110:            if ((symind = findsym (&cp1[1])) < 0) {
                    111:                if (nsyms >= MAXSYMS) {
                    112:                    prname ();
                    113:                    fprintf (stderr, "too many symbols.\n");
                    114:                    exit (2);
                    115:                }
                    116:                symind = nsyms++;
                    117:                symname[symind] = &cp1[1];
                    118:                insym[symind] = SYM_INACTIVE;
                    119:            }
                    120:            ignore[symind] = ignorethis;
                    121:            true[symind] = *cp1 == 'D' ? YES : NO;
                    122:        } else if (ignorethis)
                    123:            goto unrec;
                    124:        else if (strcmp (&cp[1], "t") == 0)
                    125:            text = YES;
                    126:        else if (strcmp (&cp[1], "l") == 0)
                    127:            lnblank = YES;
                    128:        else if (strcmp (&cp[1], "c") == 0)
                    129:            complement = YES;
                    130:        else {
                    131:  unrec:
                    132:            prname ();
                    133:            fprintf (stderr, "unrecognized option: %s\n", cp);
                    134:            goto usage;
                    135:        }
                    136:     }
                    137:     if (nsyms == 0) {
                    138:  usage:
                    139:        fprintf (stderr, "\
                    140: Usage: %s [-l] [-t] [-c] [[-Dsym] [-Usym] [-iDsym] [-iUsym]]... [file]\n\
                    141:     At least one arg from [-D -U -iD -iU] is required\n", progname);
                    142:        exit (2);
                    143:     }
                    144: 
                    145:     if (argc > 1) {
                    146:        prname ();
                    147:        fprintf (stderr, "can only do one file.\n");
                    148:     } else if (argc == 1) {
                    149:        filename = *curarg;
                    150:        if ((input = fopen (filename, "r")) != NULL) {
                    151:            pfile();
                    152:            (void) fclose (input);
                    153:        } else {
                    154:            prname ();
                    155:            fprintf (stderr, "can't open ");
                    156:            perror(*curarg);
                    157:        }
                    158:     } else {
                    159:        filename = "[stdin]";
                    160:        input = stdin;
                    161:        pfile();
                    162:     }
                    163: 
                    164:     (void) fflush (stdout);
                    165:     exit (exitstat);
                    166: }
                    167: 
                    168: /* types of input lines: */
                    169: typedef int Linetype;
                    170: #define LT_PLAIN       0   /* ordinary line */
                    171: #define LT_TRUE        1   /* a true  #ifdef of a symbol known to us */
                    172: #define LT_FALSE       2   /* a false #ifdef of a symbol known to us */
                    173: #define LT_OTHER       3   /* an #ifdef of a symbol not known to us */
                    174: #define LT_IF          4   /* an #ifdef of a symbol not known to us */
                    175: #define LT_ELSE        5   /* #else */
                    176: #define LT_ENDIF       6   /* #endif */
                    177: #define LT_LEOF        7   /* end of file */
                    178: extern Linetype checkline ();
                    179: 
                    180: typedef int Reject_level;
                    181: Reject_level reject BSS;    /* 0 or 1: pass thru; 1 or 2: ignore comments */
                    182: #define REJ_NO          0
                    183: #define REJ_IGNORE      1
                    184: #define REJ_YES         2
                    185: 
                    186: int linenum BSS;    /* current line number */
                    187: int stqcline BSS;   /* start of current coment or quote */
                    188: char *errs[] = {
                    189: #define NO_ERR      0
                    190:                        "",
                    191: #define END_ERR     1
                    192:                        "",
                    193: #define ELSE_ERR    2
                    194:                        "Inappropriate else",
                    195: #define ENDIF_ERR   3
                    196:                        "Inappropriate endif",
                    197: #define IEOF_ERR    4
                    198:                        "Premature EOF in ifdef",
                    199: #define CEOF_ERR    5
                    200:                        "Premature EOF in comment",
                    201: #define Q1EOF_ERR   6
                    202:                        "Premature EOF in quoted character",
                    203: #define Q2EOF_ERR   7
                    204:                        "Premature EOF in quoted string"
                    205: };
                    206: 
                    207: /* States for inif arg to doif */
                    208: #define IN_NONE 0
                    209: #define IN_IF   1
                    210: #define IN_ELSE 2
                    211: 
                    212: pfile ()
                    213: {
                    214:     reject = REJ_NO;
                    215:     (void) doif (-1, IN_NONE, reject, 0);
                    216:     return;
                    217: }
                    218: 
                    219: int
                    220: doif (thissym, inif, prevreject, depth)
                    221: register int thissym;   /* index of the symbol who was last ifdef'ed */
                    222: int inif;               /* YES or NO we are inside an ifdef */
                    223: Reject_level prevreject;/* previous value of reject */
                    224: int depth;              /* depth of ifdef's */
                    225: {
                    226:     register Linetype lineval;
                    227:     register Reject_level thisreject;
                    228:     int doret;          /* tmp return value of doif */
                    229:     int cursym;         /* index of the symbol returned by checkline */
                    230:     int stline;         /* line number when called this time */
                    231: 
                    232:     stline = linenum;
                    233:     for (;;) {
                    234:        switch (lineval = checkline (&cursym)) {
                    235:        case LT_PLAIN:
                    236:            flushline (YES);
                    237:            break;
                    238: 
                    239:        case LT_TRUE:
                    240:        case LT_FALSE:
                    241:            thisreject = reject;
                    242:            if (lineval == LT_TRUE)
                    243:                insym[cursym] = SYM_TRUE;
                    244:            else {
                    245:                if (reject != REJ_YES)
                    246:                    reject = ignore[cursym] ? REJ_IGNORE : REJ_YES;
                    247:                insym[cursym] = SYM_FALSE;
                    248:            }
                    249:            if (ignore[cursym])
                    250:                flushline (YES);
                    251:            else {
                    252:                exitstat = 1;
                    253:                flushline (NO);
                    254:            }
                    255:            if ((doret = doif (cursym, IN_IF, thisreject, depth + 1)) != NO_ERR)
                    256:                return error (doret, stline, depth);
                    257:            break;
                    258: 
                    259:        case LT_IF:
                    260:        case LT_OTHER:
                    261:            flushline (YES);
                    262:            if ((doret = doif (-1, IN_IF, reject, depth + 1)) != NO_ERR)
                    263:                return error (doret, stline, depth);
                    264:            break;
                    265: 
                    266:        case LT_ELSE:
                    267:            if (inif != IN_IF)
                    268:                return error (ELSE_ERR, linenum, depth);
                    269:            inif = IN_ELSE;
                    270:            if (thissym >= 0) {
                    271:                if (insym[thissym] == SYM_TRUE) {
                    272:                    reject = ignore[thissym] ? REJ_IGNORE : REJ_YES;
                    273:                    insym[thissym] = SYM_FALSE;
                    274:                } else { /* (insym[thissym] == SYM_FALSE) */
                    275:                    reject = prevreject;
                    276:                    insym[thissym] = SYM_TRUE;
                    277:                }
                    278:                if (!ignore[thissym]) {
                    279:                    flushline (NO);
                    280:                    break;
                    281:                }
                    282:            }
                    283:            flushline (YES);
                    284:            break;
                    285: 
                    286:        case LT_ENDIF:
                    287:            if (inif == IN_NONE)
                    288:                return error (ENDIF_ERR, linenum, depth);
                    289:            if (thissym >= 0) {
                    290:                insym[thissym] = SYM_INACTIVE;
                    291:                reject = prevreject;
                    292:                if (!ignore[thissym]) {
                    293:                    flushline (NO);
                    294:                    return NO_ERR;
                    295:                }
                    296:            }
                    297:            flushline (YES);
                    298:            return NO_ERR;
                    299: 
                    300:        case LT_LEOF: {
                    301:            int err;
                    302:            err =   incomment
                    303:                  ? CEOF_ERR
                    304:                  : inquote == QUOTE_SINGLE
                    305:                  ? Q1EOF_ERR
                    306:                  : inquote == QUOTE_DOUBLE
                    307:                  ? Q2EOF_ERR
                    308:                  : NO_ERR;
                    309:            if (inif != IN_NONE) {
                    310:                if (err != NO_ERR)
                    311:                    (void) error (err, stqcline, depth);
                    312:                return error (IEOF_ERR, stline, depth);
                    313:            } else if (err != NO_ERR)
                    314:                return error (err, stqcline, depth);
                    315:            else
                    316:                return NO_ERR;
                    317:            }
                    318:        }
                    319:     }
                    320: }
                    321: 
                    322: #define endsym(c) (!isalpha (c) && !isdigit (c) && c != '_')
                    323: 
                    324: #define MAXLINE 256
                    325: char tline[MAXLINE] BSS;
                    326: 
                    327: Linetype
                    328: checkline (cursym)
                    329: int *cursym;    /* if LT_TRUE or LT_FALSE returned, set this to sym index */
                    330: {
                    331:     register char *cp;
                    332:     register char *symp;
                    333:     char *scp;
                    334:     Linetype retval;
                    335: #   define KWSIZE 8
                    336:     char keyword[KWSIZE];
                    337: 
                    338:     linenum++;
                    339:     if (getlin (tline, sizeof tline, input, NO) == EOF)
                    340:        return LT_LEOF;
                    341: 
                    342:     retval = LT_PLAIN;
                    343:     if (   *(cp = tline) != '#'
                    344:        || incomment
                    345:        || inquote == QUOTE_SINGLE
                    346:        || inquote == QUOTE_DOUBLE
                    347:        )
                    348:        goto eol;
                    349: 
                    350:     cp = skipcomment (++cp);
                    351:     symp = keyword;
                    352:     while (!endsym (*cp)) {
                    353:        *symp = *cp++;
                    354:        if (++symp >= &keyword[KWSIZE])
                    355:            goto eol;
                    356:     }
                    357:     *symp = '\0';
                    358: 
                    359:     if (strcmp (keyword, "ifdef") == 0) {
                    360:        retval = YES;
                    361:        goto ifdef;
                    362:     } else if (strcmp (keyword, "ifndef") == 0) {
                    363:        retval = NO;
                    364:  ifdef:
                    365:        scp = cp = skipcomment (++cp);
                    366:        if (incomment) {
                    367:            retval = LT_PLAIN;
                    368:            goto eol;
                    369:        }
                    370:        {
                    371:            int symind;
                    372: 
                    373:            if ((symind = findsym (scp)) >= 0)
                    374:                retval = (retval ^ true[*cursym = symind])
                    375:                         ? LT_FALSE : LT_TRUE;
                    376:            else
                    377:                retval = LT_OTHER;
                    378:        }
                    379:     } else if (strcmp (keyword, "if") == 0)
                    380:        retval = LT_IF;
                    381:     else if (strcmp (keyword, "else") == 0)
                    382:        retval = LT_ELSE;
                    383:     else if (strcmp (keyword, "endif") == 0)
                    384:        retval = LT_ENDIF;
                    385: 
                    386:  eol:
                    387:     if (!text && reject != REJ_IGNORE)
                    388:        for (; *cp; ) {
                    389:            if (incomment)
                    390:                cp = skipcomment (cp);
                    391:            else if (inquote == QUOTE_SINGLE)
                    392:                cp = skipquote (cp, QUOTE_SINGLE);
                    393:            else if (inquote == QUOTE_DOUBLE)
                    394:                cp = skipquote (cp, QUOTE_DOUBLE);
                    395:            else if (*cp == '/' && cp[1] == '*')
                    396:                cp = skipcomment (cp);
                    397:            else if (*cp == '\'')
                    398:                cp = skipquote (cp, QUOTE_SINGLE);
                    399:            else if (*cp == '"')
                    400:                cp = skipquote (cp, QUOTE_DOUBLE);
                    401:            else
                    402:                cp++;
                    403:        }
                    404:     return retval;
                    405: }
                    406: 
                    407: /*
                    408:  *  Skip over comments and stop at the next charaacter
                    409:  *  position that is not whitespace.
                    410:  */
                    411: char *
                    412: skipcomment (cp)
                    413: register char *cp;
                    414: {
                    415:     if (incomment)
                    416:        goto inside;
                    417:     for (;; cp++) {
                    418:        while (*cp == ' ' || *cp == '\t')
                    419:            cp++;
                    420:        if (text)
                    421:            return cp;
                    422:        if (   cp[0] != '/'
                    423:            || cp[1] != '*'
                    424:           )
                    425:            return cp;
                    426:        cp += 2;
                    427:        if (!incomment) {
                    428:            incomment = YES;
                    429:            stqcline = linenum;
                    430:        }
                    431:  inside:
                    432:        for (;;) {
                    433:            for (; *cp != '*'; cp++)
                    434:                if (*cp == '\0')
                    435:                    return cp;
                    436:            if (*++cp == '/') {
                    437:                incomment = NO;
                    438:                break;
                    439:            }
                    440:        }
                    441:     }
                    442: }
                    443: 
                    444: /*
                    445:  *  Skip over a quoted string or character and stop at the next charaacter
                    446:  *  position that is not whitespace.
                    447:  */
                    448: char *
                    449: skipquote (cp, type)
                    450: register char *cp;
                    451: register int type;
                    452: {
                    453:     register char qchar;
                    454: 
                    455:     qchar = type == QUOTE_SINGLE ? '\'' : '"';
                    456: 
                    457:     if (inquote == type)
                    458:        goto inside;
                    459:     for (;; cp++) {
                    460:        if (*cp != qchar)
                    461:            return cp;
                    462:        cp++;
                    463:        inquote = type;
                    464:        stqcline = linenum;
                    465:  inside:
                    466:        for (; ; cp++) {
                    467:            if (*cp == qchar)
                    468:                break;
                    469:            if (   *cp == '\0'
                    470:                || *cp == '\\' && *++cp == '\0'
                    471:               )
                    472:                return cp;
                    473:        }
                    474:        inquote = QUOTE_NONE;
                    475:     }
                    476: }
                    477: 
                    478: /*
                    479:  *  findsym - look for the symbol in the symbol table.
                    480:  *            if found, return symbol table index,
                    481:  *            else return -1.
                    482:  */
                    483: int
                    484: findsym (str)
                    485: char *str;
                    486: {
                    487:     register char *cp;
                    488:     register char *symp;
                    489:     register int symind;
                    490:     register char chr;
                    491: 
                    492:     for (symind = 0; symind < nsyms; ++symind) {
                    493:        if (insym[symind] == SYM_INACTIVE) {
                    494:            for ( symp = symname[symind], cp = str
                    495:                ; *symp && *cp == *symp
                    496:                ; cp++, symp++
                    497:                )
                    498:                continue;
                    499:            chr = *cp;
                    500:            if (*symp == '\0' && endsym (chr))
                    501:                return symind;
                    502:        }
                    503:     }
                    504:     return -1;
                    505: }
                    506: 
                    507: /*
                    508:  *   getlin - expands tabs if asked for
                    509:  *            and (if compiled in) treats form-feed as an end-of-line
                    510:  */
                    511: int
                    512: getlin (line, maxline, inp, expandtabs)
                    513: register char *line;
                    514: int maxline;
                    515: FILE *inp;
                    516: int expandtabs;
                    517: {
                    518:     int tmp;
                    519:     register int num;
                    520:     register int chr;
                    521: #ifdef  FFSPECIAL
                    522:     static char havechar = NO;  /* have leftover char from last time */
                    523:     static char svchar BSS;
                    524: #endif/*FFSPECIAL */
                    525: 
                    526:     num = 0;
                    527: #ifdef  FFSPECIAL
                    528:     if (havechar) {
                    529:        havechar = NO;
                    530:        chr = svchar;
                    531:        goto ent;
                    532:     }
                    533: #endif/*FFSPECIAL */
                    534:     while (num + 8 < maxline) {   /* leave room for tab */
                    535:        chr = getc (inp);
                    536:        if (isprint (chr)) {
                    537: #ifdef  FFSPECIAL
                    538:  ent:
                    539: #endif/*FFSPECIAL */
                    540:            *line++ = chr;
                    541:            num++;
                    542:        } else
                    543:            switch (chr) {
                    544:            case EOF:
                    545:                return EOF;
                    546: 
                    547:            case '\t':
                    548:                if (expandtabs) {
                    549:                    num += tmp = 8 - (num & 7);
                    550:                    do
                    551:                        *line++ = ' ';
                    552:                    while (--tmp);
                    553:                    break;
                    554:                }
                    555:            default:
                    556:                *line++ = chr;
                    557:                num++;
                    558:                break;
                    559: 
                    560:            case '\n':
                    561:                *line = '\n';
                    562:                num++;
                    563:                goto end;
                    564: 
                    565: #ifdef  FFSPECIAL
                    566:            case '\f':
                    567:                if (++num == 1)
                    568:                    *line = '\f';
                    569:                else {
                    570:                    *line = '\n';
                    571:                    havechar = YES;
                    572:                    svchar = chr;
                    573:                }
                    574:                goto end;
                    575: #endif/*FFSPECIAL */
                    576:            }
                    577:     }
                    578:  end:
                    579:     *++line = '\0';
                    580:     return num;
                    581: }
                    582: 
                    583: flushline (keep)
                    584: Bool keep;
                    585: {
                    586:     if ((keep && reject != REJ_YES) ^ complement) {
                    587:        register char *line = tline;
                    588:        register FILE *out = stdout;
                    589:        register char chr;
                    590: 
                    591:        while (chr = *line++)
                    592:            putc (chr, out);
                    593:     } else if (lnblank)
                    594:        putc ('\n', stdout);
                    595:     return;
                    596: }
                    597: 
                    598: prname ()
                    599: {
                    600:     fprintf (stderr, "%s: ", progname);
                    601:     return;
                    602: }
                    603: 
                    604: int
                    605: error (err, line, depth)
                    606: int err;        /* type of error & index into error string array */
                    607: int line;       /* line number */
                    608: int depth;      /* how many ifdefs we are inside */
                    609: {
                    610:     if (err == END_ERR)
                    611:        return err;
                    612: 
                    613:     prname ();
                    614: 
                    615: #ifndef TESTING
                    616:     fprintf (stderr, "Error in %s line %d: %s.\n", filename, line, errs[err]);
                    617: #else/* TESTING */
                    618:     fprintf (stderr, "Error in %s line %d: %s. ", filename, line, errs[err]);
                    619:     fprintf (stderr, "ifdef depth: %d\n", depth);
                    620: #endif/*TESTING */
                    621: 
                    622:     exitstat = 2;
                    623:     return depth > 1 ? IEOF_ERR : END_ERR;
                    624: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.