Annotation of coherent/d/bin/tr.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Tr translates characters from the standard input to the standard output.
        !             3:  * It usage is as follows:
        !             4:  *     tr [-c] [-d] [-s] [string1] [string2]
        !             5:  * In the two strings, in addition to normal characters, one can include
        !             6:  *     `x-y'   all characters between `x' and `y'
        !             7:  *     \r      ascii carriage return
        !             8:  *     \n      ascii line feed
        !             9:  *     \b      ascii back space
        !            10:  *     \t      ascii horizontal tab
        !            11:  *     \f      ascii form feed
        !            12:  *     \d, \dd or \ddd
        !            13:  *             character with ascii code d (or dd or ddd) in octal
        !            14:  *     \x      `x' for any `x' not listed above
        !            15:  * In the absence of any options, tr simply converts any character appearing
        !            16:  * in string1 to the character in the same position in string2.  If string2
        !            17:  * is shorter then string1, then it is extended by replicating the last
        !            18:  * character.
        !            19:  * The `-c' option simply compliments string1 with respect to the character
        !            20:  * set.  The resulting set of characters is used in increasing order.
        !            21:  * The `-d' option causes characters in string1 to be deleted rather than
        !            22:  * being translated.
        !            23:  * The `-s' option causes characters in string2 (or string1 if there is no
        !            24:  * string2 and the -d option is not specified) to be compressed on output.
        !            25:  * This means that multiple occurances of the same character are compressed
        !            26:  * to one occurance.
        !            27:  */
        !            28: #include <stdio.h>
        !            29: #include <sys/mdata.h>
        !            30: 
        !            31: 
        !            32: #define        bool    char                    /* boolean type */
        !            33: #define        not     !                       /* logical negation operator */
        !            34: #define        and     &&                      /* logical conjunction */
        !            35: #define        or      ||                      /* logical disjunction */
        !            36: #define        TRUE    (0 == 0)
        !            37: #define        FALSE   (not TRUE)
        !            38: #define        EOS     '\0'                    /* end-of-string char */
        !            39: #define        CSIZE   (1 << NBCHAR)           /* character set size */
        !            40: #define        MAXDIG  ((NBCHAR+2) / 3)        /* max digits in character constant */
        !            41: 
        !            42: 
        !            43: /*
        !            44:  * List is used to hold a character list from which characters are begin
        !            45:  * extrated.  It allows expansion of character ranges, backslash-protected
        !            46:  * characters and character ranges.
        !            47:  */
        !            48: typedef struct list {
        !            49:        unsigned char   *l_next,        /* next character from string */
        !            50:                        *l_start;       /* start of string */
        !            51:        bool            l_inr;          /* iff we are in a-b range */
        !            52:        int             l_rnext,        /* next to give if inrange */
        !            53:                        l_rhi;          /* maximum to give if inrange */
        !            54: }      list;
        !            55: 
        !            56: 
        !            57: bool           cflag,                  /* compliment string 1 */
        !            58:                dflag,                  /* delete chars in string 1 */
        !            59:                sflag,                  /* remove duplicates in string 2 */
        !            60:                delete[CSIZE],          /* set of chars to delete on input */
        !            61:                squeeze[CSIZE];         /* set of chars to squeeze on output */
        !            62: unsigned char  map[CSIZE];             /* map to apply to characters */
        !            63: 
        !            64: int            nextchar();             /* get next char of list */
        !            65: void           die(),                  /* print error message and exit */
        !            66:                usage(),                /* print usage message and exit */
        !            67:                scan(),                 /* actually do copy */
        !            68:                startlist(),            /* start list from string */
        !            69:                makeset(),              /* make set of chars in list */
        !            70:                maketrans();            /* make transformation table */
        !            71: unsigned char  *cstr();                /* compliment character list */
        !            72: char           *alloc(),               /* unfailable malloc */
        !            73:                *ralloc();              /* unfailable realloc */
        !            74: 
        !            75: 
        !            76: int
        !            77: main(argc, argv)
        !            78: int            argc;
        !            79: register char  *argv[];
        !            80: {
        !            81:        register unsigned char  *str1,
        !            82:                                *str2;
        !            83: 
        !            84:        for (str1=*++argv; str1 != NULL  &&  *str1 == '-'; str1=*++argv)
        !            85:                while (*++str1 != EOS)
        !            86:                        switch (*str1) {
        !            87:                        case 'c':
        !            88:                                cflag = TRUE;
        !            89:                                break;
        !            90:                        case 'd':
        !            91:                                dflag = TRUE;
        !            92:                                break;
        !            93:                        case 's':
        !            94:                                sflag = TRUE;
        !            95:                                break;
        !            96:                        default:
        !            97:                                usage();
        !            98:                        }
        !            99:        if (str1 == NULL)
        !           100:                usage();
        !           101:        if (cflag)
        !           102:                str1 = cstr(str1);
        !           103:        str2 = *++argv;
        !           104:        if (str2 != NULL  &&  *++argv != NULL)
        !           105:                usage();
        !           106:        if (dflag)
        !           107:                if (sflag) {            /* -d and -s */
        !           108:                        if (str2 == NULL)
        !           109:                                usage();
        !           110:                        makeset(str1, delete);
        !           111:                        makeset(str2, squeeze);
        !           112:                        maketrans(str1, str2, map);
        !           113:                } else {                /* -d and no -s */
        !           114:                        if (str2 != NULL)
        !           115:                                usage();
        !           116:                        makeset(str1, delete);
        !           117:                        maketrans("", "", map);
        !           118:                }
        !           119:        else
        !           120:                if (sflag)
        !           121:                        if (str2 == NULL) {     /* -s, no -d and one string */
        !           122:                                maketrans("", "", map);
        !           123:                                makeset(str1, squeeze);
        !           124:                        } else {                /* -s, no -d and two strings */
        !           125:                                maketrans(str1, str2, map);
        !           126:                                makeset(str2, squeeze);
        !           127:                        }
        !           128:                else {                  /* no -s, no -d */
        !           129:                        if (str2 == NULL)
        !           130:                                usage();
        !           131:                        maketrans(str1, str2, map);
        !           132:                }
        !           133:        scan();
        !           134:        return (0);
        !           135: }
        !           136: 
        !           137: 
        !           138: /*
        !           139:  * Die simply sends an error message to stderr and exits.
        !           140:  */
        !           141: void
        !           142: die(str)
        !           143: char   *str;
        !           144: {
        !           145:        fprintf(stderr, "%r\n", &str);
        !           146:        exit(1);
        !           147: }
        !           148: 
        !           149: 
        !           150: /*
        !           151:  * Usage gives a usage error message and exits.
        !           152:  */
        !           153: void
        !           154: usage()
        !           155: {
        !           156:        die("usage: tr [-cds] [from_list [to_list]]");
        !           157: }
        !           158: 
        !           159: 
        !           160: /*
        !           161:  * Scan does the acutal copying.  It deletes any input characters in
        !           162:  * the set `delete'.  It then transforms input characters to output
        !           163:  * characters useing the mapping `map'.  Finally, it changes multiple
        !           164:  * occurances of output characters in the set `squeeze' to single
        !           165:  * occurances.
        !           166:  */
        !           167: void
        !           168: scan()
        !           169: {
        !           170:        register int    ch,
        !           171:                        lastch;
        !           172: 
        !           173:        lastch = EOF;
        !           174:        while ((ch=getchar()) != EOF) {
        !           175:                if (delete[ch])
        !           176:                        continue;
        !           177:                ch = map[ch];
        !           178:                if (ch == lastch  &&  squeeze[ch])
        !           179:                        continue;
        !           180:                putchar(ch);
        !           181:                lastch = ch;
        !           182:        }
        !           183: }
        !           184: 
        !           185: 
        !           186: /*
        !           187:  * Makeset sets the array of bools `set' (indexed by chars) such that
        !           188:  * the i'th entry is TRUE iff character i appears in the character
        !           189:  * list `str'.
        !           190:  */
        !           191: void
        !           192: makeset(str, set)
        !           193: unsigned char  *str;
        !           194: register bool  *set;
        !           195: {
        !           196:        register bool   *rp;
        !           197:        register int    n;
        !           198:        list            cl;
        !           199: 
        !           200:        for (rp=set, n=CSIZE; --n >= 0;)
        !           201:                *rp++ = FALSE;
        !           202:        startlist(&cl, str);
        !           203:        while ((n=nextchar(&cl)) != EOF)
        !           204:                set[n] = TRUE;
        !           205:        return;
        !           206: }
        !           207: 
        !           208: 
        !           209: /*
        !           210:  * Maketrans sets the array of chars `map' (indexed by chars) to
        !           211:  * the mapping which converts all characters in the character list
        !           212:  * `str1' to the corresponding character in the character list `str2'.
        !           213:  * If `str2' is short, the last character is duplicated.
        !           214:  */
        !           215: void
        !           216: maketrans(str1, str2, map)
        !           217: unsigned char  *str1,
        !           218:                *str2,
        !           219:                *map;
        !           220: {
        !           221:        register unsigned char  *rp;
        !           222:        register int            n,
        !           223:                                m;
        !           224:        list                    l1,
        !           225:                                l2;
        !           226:        bool                    extra;
        !           227: 
        !           228:        startlist(&l1, str1);
        !           229:        startlist(&l2, str2);
        !           230:        for (rp=map, n=0; n < CSIZE; ++n)
        !           231:                *rp++ = n;
        !           232:        rp = map;
        !           233:        n = nextchar(&l2);
        !           234:        if (n == EOF) {
        !           235:                if (nextchar(&l1) != EOF)
        !           236:                        die("Second string empty");
        !           237:                return;
        !           238:        }
        !           239:        for (extra=FALSE; (m=nextchar(&l1)) != EOF;) {
        !           240:                rp[m] = n;
        !           241:                if (not extra) {
        !           242:                        m = nextchar(&l2);
        !           243:                        if (m != EOF)
        !           244:                                n = m;
        !           245:                        else
        !           246:                                extra = TRUE;
        !           247:                }
        !           248:        }
        !           249:        if (not extra  &&  nextchar(&l2) != EOF)
        !           250:                die("Extra characters in second string");
        !           251:        return;
        !           252: }
        !           253: 
        !           254: 
        !           255: /*
        !           256:  * Cstr returns a string which is the compliment of the string `str'.
        !           257:  */
        !           258: unsigned char  *
        !           259: cstr(str)
        !           260: unsigned char  *str;
        !           261: {
        !           262:        register unsigned char  *rp;
        !           263:        register bool           *sp;
        !           264:        register int            n;
        !           265:        bool                    set[CSIZE];
        !           266:        unsigned char           *res;
        !           267: 
        !           268:        makeset(str, set);
        !           269:        res = rp = (unsigned char *)alloc(3 + 2 + CSIZE + 1);
        !           270:        sp = set;
        !           271:        if (not *sp++) {                /* handle EOS specially */
        !           272:                *rp++ = '\\';
        !           273:                *rp++ = '0';
        !           274:                *rp++ = '0';
        !           275:                *rp++ = '0';
        !           276:        }
        !           277:        for (n=0; ++n < CSIZE;)
        !           278:                if (not *sp++) {
        !           279:                        if (n == '\\'  ||  n == '-')
        !           280:                                *rp++ = '\\';
        !           281:                        *rp++ = n;
        !           282:                }
        !           283:        *rp++ = EOS;
        !           284:        return ((unsigned char *)ralloc(res, rp - res));
        !           285: }
        !           286: 
        !           287: 
        !           288: /*
        !           289:  * Startlist sets the list pointed to by `lp' to the string `str'.
        !           290:  */
        !           291: void
        !           292: startlist(lp, str)
        !           293: register list  *lp;
        !           294: unsigned char  *str;
        !           295: {
        !           296:        lp->l_next = lp->l_start = str;
        !           297:        lp->l_inr = FALSE;
        !           298: }
        !           299: 
        !           300: 
        !           301: /*
        !           302:  * Nextchar returns the next character from the list pointed to by
        !           303:  * `lp'.  This includes backslash protection and character ranges.
        !           304:  * When there are no more characters, it returns EOF.
        !           305:  */
        !           306: int
        !           307: nextchar(lp)
        !           308: register list  *lp;
        !           309: {
        !           310:        register int    res;
        !           311:        int             getprot();
        !           312: 
        !           313:        if (lp->l_inr) {
        !           314:                res = lp->l_rnext;
        !           315:                lp->l_inr = ++lp->l_rnext <= lp->l_rhi;
        !           316:                return (res);
        !           317:        }
        !           318:        res = *lp->l_next++;
        !           319:        if (res == EOS)
        !           320:                return (EOF);
        !           321:        if (res == '\\')
        !           322:                res = getprot(lp);
        !           323:        if (*lp->l_next != '-')
        !           324:                return (res);
        !           325:        ++lp->l_next;
        !           326:        lp->l_rnext = res;
        !           327:        res = *lp->l_next++;
        !           328:        if (res == EOS)
        !           329:                die("Unexpected end of character list in `%s'", lp->l_start);
        !           330:        if (res == '\\')
        !           331:                res = getprot(lp);
        !           332:        if (lp->l_rnext > res)
        !           333:                die("Bad character range in `%s'", lp->l_start);
        !           334:        lp->l_rhi = res;
        !           335:        res = lp->l_rnext;
        !           336:        lp->l_inr = ++lp->l_rnext <= lp->l_rhi;
        !           337:        return (res);
        !           338: }
        !           339: 
        !           340: 
        !           341: /*
        !           342:  * Getprot is used to get a backslash protected character from the
        !           343:  * character list pointed to by `lp'.
        !           344:  */
        !           345: int
        !           346: getprot(lp)
        !           347: register list  *lp;
        !           348: {
        !           349:        register unsigned char  ch;
        !           350:        register unsigned       n;
        !           351:        int                     m;
        !           352: 
        !           353:        ch = *lp->l_next++;
        !           354:        switch (ch) {
        !           355:        case EOS:
        !           356:                die("Unexpected end of character list in `%s'", lp->l_start);
        !           357:        case 'r':
        !           358:                return ('\r');
        !           359:        case 'b':
        !           360:                return ('\b');
        !           361:        case 't':
        !           362:                return ('\t');
        !           363:        case 'n':
        !           364:                return ('\n');
        !           365:        case 'f':
        !           366:                return ('\f');
        !           367:        default:
        !           368:                break;
        !           369:        }
        !           370:        if ('0' > ch  ||  ch > '7')
        !           371:                return (ch);
        !           372:        n = ch - '0';
        !           373:        ch = *lp->l_next;
        !           374:        for (m=MAXDIG; --m > 0  &&  '0' <= ch  &&  ch <= '7'; ch=*++lp->l_next)
        !           375:                n = n*8 + ch-'0';
        !           376:        if (n >= CSIZE)
        !           377:                die("Illegal character constant in `%s'", lp->l_start);
        !           378:        return (n);
        !           379: }
        !           380: 
        !           381: 
        !           382: /*
        !           383:  * Alloc is simply an interface to malloc which does not return if
        !           384:  * there is no space.
        !           385:  */
        !           386: char   *
        !           387: alloc(len)
        !           388: unsigned       len;
        !           389: {
        !           390:        register char   *res;
        !           391:        extern char     *malloc();
        !           392: 
        !           393:        res = malloc(len);
        !           394:        if (res == NULL)
        !           395:                die("Out of space");
        !           396:        return (res);
        !           397: }
        !           398: 
        !           399: 
        !           400: /*
        !           401:  * Ralloc is simply an interface to realloc which does not return if
        !           402:  * there is no space.
        !           403:  */
        !           404: char   *
        !           405: ralloc(cp, len)
        !           406: char           *cp;
        !           407: unsigned       len;
        !           408: {
        !           409:        register char   *res;
        !           410:        extern char *realloc();
        !           411: 
        !           412:        res = realloc(cp, len);
        !           413:        if (res == NULL)
        !           414:                die("Out of space");
        !           415:        return (res);
        !           416: }

unix.superglobalmegacorp.com

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