[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.16

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