[BACK]Return to rs.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / rs

Annotation of src/usr.bin/rs/rs.c, Revision 1.7

1.7     ! millert     1: /*     $OpenBSD: rs.c,v 1.6 2001/11/19 19:02:16 mpech Exp $    */
1.3       deraadt     2:
1.1       deraadt     3: /*-
                      4:  * Copyright (c) 1993
                      5:  *     The Regents of the University of California.  All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  * 3. All advertising materials mentioning features or use of this software
                     16:  *    must display the following acknowledgement:
                     17:  *     This product includes software developed by the University of
                     18:  *     California, Berkeley and its contributors.
                     19:  * 4. Neither the name of the University nor the names of its contributors
                     20:  *    may be used to endorse or promote products derived from this software
                     21:  *    without specific prior written permission.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     24:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     25:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     26:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     27:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     28:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     29:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     31:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     32:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     33:  * SUCH DAMAGE.
                     34:  */
                     35:
                     36: #ifndef lint
                     37: static char copyright[] =
                     38: "@(#) Copyright (c) 1993\n\
                     39:        The Regents of the University of California.  All rights reserved.\n";
                     40: #endif /* not lint */
                     41:
                     42: #ifndef lint
                     43: static char sccsid[] = "@(#)rs.c       8.1 (Berkeley) 6/6/93";
                     44: #endif /* not lint */
                     45:
                     46: /*
                     47:  *     rs - reshape a data array
                     48:  *     Author:  John Kunze, Office of Comp. Affairs, UCB
                     49:  *             BEWARE: lots of unfinished edges
                     50:  */
                     51:
                     52: #include <ctype.h>
1.4       millert    53: #include <err.h>
1.1       deraadt    54: #include <stdio.h>
                     55: #include <stdlib.h>
                     56: #include <string.h>
                     57:
                     58: long   flags;
                     59: #define        TRANSPOSE       000001
                     60: #define        MTRANSPOSE      000002
                     61: #define        ONEPERLINE      000004
                     62: #define        ONEISEPONLY     000010
                     63: #define        ONEOSEPONLY     000020
                     64: #define        NOTRIMENDCOL    000040
                     65: #define        SQUEEZE         000100
                     66: #define        SHAPEONLY       000200
                     67: #define        DETAILSHAPE     000400
                     68: #define        RIGHTADJUST     001000
                     69: #define        NULLPAD         002000
                     70: #define        RECYCLE         004000
                     71: #define        SKIPPRINT       010000
                     72: #define        ICOLBOUNDS      020000
                     73: #define        OCOLBOUNDS      040000
                     74: #define ONEPERCHAR     0100000
                     75: #define NOARGS         0200000
                     76:
                     77: short  *colwidths;
                     78: short  *cord;
                     79: short  *icbd;
                     80: short  *ocbd;
                     81: int    nelem;
                     82: char   **elem;
                     83: char   **endelem;
                     84: char   *curline;
                     85: int    allocsize = BUFSIZ;
                     86: int    curlen;
                     87: int    irows, icols;
                     88: int    orows, ocols;
                     89: int    maxlen;
                     90: int    skip;
                     91: int    propgutter;
                     92: char   isep = ' ', osep = ' ';
                     93: int    owidth = 80, gutter = 2;
                     94:
1.7     ! millert    95: void     usage(char *, char *);
        !            96: void     getargs(int, char *[]);
        !            97: void     getfile(void);
        !            98: int      getline(void);
        !            99: char    *getlist(short **, char *);
        !           100: char    *getnum(int *, char *, int);
        !           101: char   **getptrs(char **);
        !           102: void     prepfile(void);
        !           103: void     prints(char *, int);
        !           104: void     putfile(void);
1.1       deraadt   105:
1.2       deraadt   106: #define INCR(ep) do {                  \
                    107:        if (++ep >= endelem)            \
                    108:                ep = getptrs(ep);       \
                    109: } while(0)
                    110:
1.1       deraadt   111: int
                    112: main(argc, argv)
                    113:        int argc;
                    114:        char *argv[];
                    115: {
                    116:        getargs(argc, argv);
                    117:        getfile();
                    118:        if (flags & SHAPEONLY) {
                    119:                printf("%d %d\n", irows, icols);
                    120:                exit(0);
                    121:        }
                    122:        prepfile();
                    123:        putfile();
                    124:        exit(0);
                    125: }
                    126:
                    127: void
                    128: getfile()
                    129: {
1.6       mpech     130:        char *p;
                    131:        char *endp;
                    132:        char **ep = 0;
1.1       deraadt   133:        int multisep = (flags & ONEISEPONLY ? 0 : 1);
                    134:        int nullpad = flags & NULLPAD;
                    135:        char **padto;
                    136:
                    137:        while (skip--) {
                    138:                getline();
                    139:                if (flags & SKIPPRINT)
                    140:                        puts(curline);
                    141:        }
                    142:        getline();
                    143:        if (flags & NOARGS && curlen < owidth)
                    144:                flags |= ONEPERLINE;
                    145:        if (flags & ONEPERLINE)
                    146:                icols = 1;
                    147:        else                            /* count cols on first line */
                    148:                for (p = curline, endp = curline + curlen; p < endp; p++) {
                    149:                        if (*p == isep && multisep)
                    150:                                continue;
                    151:                        icols++;
                    152:                        while (*p && *p != isep)
                    153:                                p++;
                    154:                }
                    155:        ep = getptrs(elem);
                    156:        p = curline;
                    157:        do {
                    158:                if (flags & ONEPERLINE) {
1.2       deraadt   159:                        *ep = curline;
                    160:                        INCR(ep);               /* prepare for next entry */
1.1       deraadt   161:                        if (maxlen < curlen)
                    162:                                maxlen = curlen;
                    163:                        irows++;
                    164:                        continue;
                    165:                }
                    166:                for (p = curline, endp = curline + curlen; p < endp; p++) {
                    167:                        if (*p == isep && multisep)
                    168:                                continue;       /* eat up column separators */
                    169:                        if (*p == isep)         /* must be an empty column */
                    170:                                *ep = "";
                    171:                        else                    /* store column entry */
                    172:                                *ep = p;
                    173:                        while (p < endp && *p != isep)
                    174:                                p++;            /* find end of entry */
                    175:                        *p = '\0';              /* mark end of entry */
                    176:                        if (maxlen < p - *ep)   /* update maxlen */
                    177:                                maxlen = p - *ep;
1.2       deraadt   178:                        INCR(ep);               /* prepare for next entry */
1.1       deraadt   179:                }
                    180:                irows++;                        /* update row count */
                    181:                if (nullpad) {                  /* pad missing entries */
                    182:                        padto = elem + irows * icols;
1.2       deraadt   183:                        while (ep < padto) {
                    184:                                *ep = "";
                    185:                                INCR(ep);
                    186:                        }
1.1       deraadt   187:                }
                    188:        } while (getline() != EOF);
                    189:        *ep = 0;                                /* mark end of pointers */
                    190:        nelem = ep - elem;
                    191: }
                    192:
                    193: void
                    194: putfile()
                    195: {
1.6       mpech     196:        char **ep;
                    197:        int i, j, n;
1.1       deraadt   198:
                    199:        ep = elem;
1.2       deraadt   200:        if (flags & TRANSPOSE) {
1.1       deraadt   201:                for (i = 0; i < orows; i++) {
                    202:                        for (j = i; j < nelem; j += orows)
                    203:                                prints(ep[j], (j - i) / orows);
                    204:                        putchar('\n');
                    205:                }
1.2       deraadt   206:        } else {
                    207:                for (n = 0, i = 0; i < orows && n < nelem; i++) {
                    208:                        for (j = 0; j < ocols; j++) {
                    209:                                if (n++ >= nelem)
                    210:                                        break;
1.1       deraadt   211:                                prints(*ep++, j);
1.2       deraadt   212:                        }
1.1       deraadt   213:                        putchar('\n');
                    214:                }
1.2       deraadt   215:        }
1.1       deraadt   216: }
                    217:
                    218: void
                    219: prints(s, col)
                    220:        char *s;
                    221:        int col;
                    222: {
1.6       mpech     223:        int n;
                    224:        char *p = s;
1.1       deraadt   225:
                    226:        while (*p)
                    227:                p++;
                    228:        n = (flags & ONEOSEPONLY ? 1 : colwidths[col] - (p - s));
                    229:        if (flags & RIGHTADJUST)
                    230:                while (n-- > 0)
                    231:                        putchar(osep);
                    232:        for (p = s; *p; p++)
                    233:                putchar(*p);
                    234:        while (n-- > 0)
                    235:                putchar(osep);
                    236: }
                    237:
                    238: void
1.2       deraadt   239: usage(msg, s)
1.1       deraadt   240:        char *msg, *s;
                    241: {
1.2       deraadt   242:        warnx(msg, s);
1.1       deraadt   243:        fprintf(stderr,
1.2       deraadt   244: "Usage:  rs [ -[csCS][x][kKgGw][N]tTeEnyjhHm ] [ rows [ cols ] ]\n");
1.1       deraadt   245:        exit(1);
                    246: }
                    247:
                    248: void
                    249: prepfile()
                    250: {
1.6       mpech     251:        char **ep;
                    252:        int  i;
                    253:        int  j;
1.1       deraadt   254:        char **lp;
                    255:        int colw;
                    256:        int max = 0;
                    257:        int n;
                    258:
                    259:        if (!nelem)
                    260:                exit(0);
                    261:        gutter += maxlen * propgutter / 100.0;
                    262:        colw = maxlen + gutter;
                    263:        if (flags & MTRANSPOSE) {
                    264:                orows = icols;
                    265:                ocols = irows;
                    266:        }
                    267:        else if (orows == 0 && ocols == 0) {    /* decide rows and cols */
                    268:                ocols = owidth / colw;
1.2       deraadt   269:                if (ocols == 0) {
1.4       millert   270:                        warnx("Display width %d is less than column width %d",
                    271:                            owidth, colw);
1.2       deraadt   272:                        ocols = 1;
                    273:                }
1.1       deraadt   274:                if (ocols > nelem)
                    275:                        ocols = nelem;
                    276:                orows = nelem / ocols + (nelem % ocols ? 1 : 0);
                    277:        }
                    278:        else if (orows == 0)                    /* decide on rows */
                    279:                orows = nelem / ocols + (nelem % ocols ? 1 : 0);
                    280:        else if (ocols == 0)                    /* decide on cols */
                    281:                ocols = nelem / orows + (nelem % orows ? 1 : 0);
                    282:        lp = elem + orows * ocols;
                    283:        while (lp > endelem) {
                    284:                getptrs(elem + nelem);
                    285:                lp = elem + orows * ocols;
                    286:        }
                    287:        if (flags & RECYCLE) {
                    288:                for (ep = elem + nelem; ep < lp; ep++)
                    289:                        *ep = *(ep - nelem);
                    290:                nelem = lp - elem;
                    291:        }
                    292:        if (!(colwidths = (short *) malloc(ocols * sizeof(short))))
1.2       deraadt   293:                errx(1, "malloc:  No gutter space");
1.1       deraadt   294:        if (flags & SQUEEZE) {
                    295:                if (flags & TRANSPOSE)
                    296:                        for (ep = elem, i = 0; i < ocols; i++) {
                    297:                                for (j = 0; j < orows; j++)
                    298:                                        if ((n = strlen(*ep++)) > max)
                    299:                                                max = n;
                    300:                                colwidths[i] = max + gutter;
                    301:                        }
                    302:                else
1.5       deraadt   303:                        for (ep = elem, i = 0; i < ocols; i++) {
1.1       deraadt   304:                                for (j = i; j < nelem; j += ocols)
                    305:                                        if ((n = strlen(ep[j])) > max)
                    306:                                                max = n;
                    307:                                colwidths[i] = max + gutter;
                    308:                        }
                    309:        }
                    310:        /*      for (i = 0; i < orows; i++) {
                    311:                        for (j = i; j < nelem; j += orows)
                    312:                                prints(ep[j], (j - i) / orows);
                    313:                        putchar('\n');
                    314:                }
                    315:        else
                    316:                for (i = 0; i < orows; i++) {
                    317:                        for (j = 0; j < ocols; j++)
                    318:                                prints(*ep++, j);
                    319:                        putchar('\n');
                    320:                }*/
                    321:        else
                    322:                for (i = 0; i < ocols; i++)
                    323:                        colwidths[i] = colw;
                    324:        if (!(flags & NOTRIMENDCOL)) {
                    325:                if (flags & RIGHTADJUST)
                    326:                        colwidths[0] -= gutter;
                    327:                else
                    328:                        colwidths[ocols - 1] = 0;
                    329:        }
                    330:        n = orows * ocols;
                    331:        if (n > nelem && (flags & RECYCLE))
                    332:                nelem = n;
                    333:        /*for (i = 0; i < ocols; i++)
                    334:                fprintf(stderr, "%d ",colwidths[i]);
                    335:        fprintf(stderr, "is colwidths, nelem %d\n", nelem);*/
                    336: }
                    337:
                    338: #define        BSIZE   2048
                    339: char   ibuf[BSIZE];            /* two screenfuls should do */
                    340:
                    341: int
                    342: getline()      /* get line; maintain curline, curlen; manage storage */
                    343: {
                    344:        static  int putlength;
                    345:        static  char *endblock = ibuf + BSIZE;
1.6       mpech     346:        char *p;
                    347:        int c, i;
1.1       deraadt   348:
                    349:        if (!irows) {
                    350:                curline = ibuf;
                    351:                putlength = flags & DETAILSHAPE;
                    352:        }
                    353:        else if (skip <= 0) {                   /* don't waste storage */
                    354:                curline += curlen + 1;
                    355:                if (putlength)          /* print length, recycle storage */
                    356:                        printf(" %d line %d\n", curlen, irows);
                    357:        }
                    358:        if (!putlength && endblock - curline < BUFSIZ) {   /* need storage */
                    359:                /*ww = endblock-curline; tt += ww;*/
                    360:                /*printf("#wasted %d total %d\n",ww,tt);*/
                    361:                if (!(curline = (char *) malloc(BSIZE)))
1.2       deraadt   362:                        errx(1, "File too large");
1.1       deraadt   363:                endblock = curline + BSIZE;
                    364:                /*printf("#endb %d curline %d\n",endblock,curline);*/
                    365:        }
                    366:        for (p = curline, i = 1; i < BUFSIZ; *p++ = c, i++)
                    367:                if ((c = getchar()) == EOF || c == '\n')
                    368:                        break;
                    369:        *p = '\0';
                    370:        curlen = i - 1;
                    371:        return(c);
                    372: }
                    373:
                    374: char **
                    375: getptrs(sp)
                    376:        char **sp;
                    377: {
1.6       mpech     378:        char **p;
1.1       deraadt   379:
1.2       deraadt   380:        allocsize += allocsize;
                    381:        p = (char **)realloc(elem, allocsize * sizeof(char *));
                    382:        if (p == (char **)0)
                    383:                err(1, "no memory");
                    384:
                    385:        sp += (p - elem);
                    386:        endelem = (elem = p) + allocsize;
                    387:        return(sp);
1.1       deraadt   388: }
                    389:
                    390: void
                    391: getargs(ac, av)
                    392:        int ac;
                    393:        char *av[];
                    394: {
1.6       mpech     395:        char *p;
1.1       deraadt   396:
                    397:        if (ac == 1) {
                    398:                flags |= NOARGS | TRANSPOSE;
                    399:        }
                    400:        while (--ac && **++av == '-')
                    401:                for (p = *av+1; *p; p++)
                    402:                        switch (*p) {
                    403:                        case 'T':
                    404:                                flags |= MTRANSPOSE;
                    405:                        case 't':
                    406:                                flags |= TRANSPOSE;
                    407:                                break;
                    408:                        case 'c':               /* input col. separator */
                    409:                                flags |= ONEISEPONLY;
                    410:                        case 's':               /* one or more allowed */
                    411:                                if (p[1])
                    412:                                        isep = *++p;
                    413:                                else
                    414:                                        isep = '\t';    /* default is ^I */
                    415:                                break;
                    416:                        case 'C':
                    417:                                flags |= ONEOSEPONLY;
                    418:                        case 'S':
                    419:                                if (p[1])
                    420:                                        osep = *++p;
                    421:                                else
                    422:                                        osep = '\t';    /* default is ^I */
                    423:                                break;
                    424:                        case 'w':               /* window width, default 80 */
                    425:                                p = getnum(&owidth, p, 0);
                    426:                                if (owidth <= 0)
1.2       deraadt   427:                                usage("Width must be a positive integer", "");
1.1       deraadt   428:                                break;
                    429:                        case 'K':                       /* skip N lines */
                    430:                                flags |= SKIPPRINT;
                    431:                        case 'k':                       /* skip, do not print */
                    432:                                p = getnum(&skip, p, 0);
                    433:                                if (!skip)
                    434:                                        skip = 1;
                    435:                                break;
                    436:                        case 'm':
                    437:                                flags |= NOTRIMENDCOL;
                    438:                                break;
                    439:                        case 'g':               /* gutter space */
                    440:                                p = getnum(&gutter, p, 0);
                    441:                                break;
                    442:                        case 'G':
                    443:                                p = getnum(&propgutter, p, 0);
                    444:                                break;
                    445:                        case 'e':               /* each line is an entry */
                    446:                                flags |= ONEPERLINE;
                    447:                                break;
                    448:                        case 'E':
                    449:                                flags |= ONEPERCHAR;
                    450:                                break;
                    451:                        case 'j':                       /* right adjust */
                    452:                                flags |= RIGHTADJUST;
                    453:                                break;
                    454:                        case 'n':       /* null padding for missing values */
                    455:                                flags |= NULLPAD;
                    456:                                break;
                    457:                        case 'y':
                    458:                                flags |= RECYCLE;
                    459:                                break;
                    460:                        case 'H':                       /* print shape only */
                    461:                                flags |= DETAILSHAPE;
                    462:                        case 'h':
                    463:                                flags |= SHAPEONLY;
                    464:                                break;
                    465:                        case 'z':                       /* squeeze col width */
                    466:                                flags |= SQUEEZE;
                    467:                                break;
                    468:                        /*case 'p':
                    469:                                ipagespace = atoi(++p); (default is 1)
                    470:                                break;*/
                    471:                        case 'o':                       /* col order */
                    472:                                p = getlist(&cord, p);
                    473:                                break;
                    474:                        case 'b':
                    475:                                flags |= ICOLBOUNDS;
                    476:                                p = getlist(&icbd, p);
                    477:                                break;
                    478:                        case 'B':
                    479:                                flags |= OCOLBOUNDS;
                    480:                                p = getlist(&ocbd, p);
                    481:                                break;
                    482:                        default:
1.2       deraadt   483:                                usage("Bad flag:  %.1s", p);
1.1       deraadt   484:                        }
                    485:        /*if (!osep)
                    486:                osep = isep;*/
                    487:        switch (ac) {
                    488:        /*case 3:
                    489:                opages = atoi(av[2]);*/
                    490:        case 2:
                    491:                ocols = atoi(av[1]);
                    492:        case 1:
                    493:                orows = atoi(av[0]);
                    494:        case 0:
                    495:                break;
                    496:        default:
1.2       deraadt   497:                usage("Too many arguments.", "");
1.1       deraadt   498:        }
                    499: }
                    500:
                    501: char *
                    502: getlist(list, p)
                    503:        short **list;
                    504:        char *p;
                    505: {
1.6       mpech     506:        int count = 1;
                    507:        char *t;
1.1       deraadt   508:
                    509:        for (t = p + 1; *t; t++) {
                    510:                if (!isdigit(*t))
1.2       deraadt   511:                        usage("Option %.1s requires a list of unsigned numbers separated by commas", t);
1.1       deraadt   512:                count++;
                    513:                while (*t && isdigit(*t))
                    514:                        t++;
                    515:                if (*t != ',')
                    516:                        break;
                    517:        }
                    518:        if (!(*list = (short *) malloc(count * sizeof(short))))
1.2       deraadt   519:                errx(1, "No list space");
1.1       deraadt   520:        count = 0;
                    521:        for (t = p + 1; *t; t++) {
                    522:                (*list)[count++] = atoi(t);
                    523:                printf("++ %d ", (*list)[count-1]);
                    524:                fflush(stdout);
                    525:                while (*t && isdigit(*t))
                    526:                        t++;
                    527:                if (*t != ',')
                    528:                        break;
                    529:        }
                    530:        (*list)[count] = 0;
                    531:        return(t - 1);
                    532: }
                    533:
                    534: char *
                    535: getnum(num, p, strict) /* num = number p points to; if (strict) complain */
                    536:        int *num, strict;       /* returns pointer to end of num */
                    537:        char *p;
                    538: {
1.6       mpech     539:        char *t = p;
1.1       deraadt   540:
                    541:        if (!isdigit(*++t)) {
                    542:                if (strict || *t == '-' || *t == '+')
1.2       deraadt   543:                        usage("Option %.1s requires an unsigned integer", p);
1.1       deraadt   544:                *num = 0;
                    545:                return(p);
                    546:        }
                    547:        *num = atoi(t);
                    548:        while (*++t)
                    549:                if (!isdigit(*t))
                    550:                        break;
                    551:        return(--t);
                    552: }