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

1.29    ! schwarze    1: /*     $OpenBSD: rs.c,v 1.28 2015/11/10 14:42:41 schwarze 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: /*
                     33:  *     rs - reshape a data array
                     34:  *     Author:  John Kunze, Office of Comp. Affairs, UCB
                     35:  *             BEWARE: lots of unfinished edges
                     36:  */
                     37:
                     38: #include <ctype.h>
1.4       millert    39: #include <err.h>
1.14      millert    40: #include <errno.h>
                     41: #include <limits.h>
1.1       deraadt    42: #include <stdio.h>
                     43: #include <stdlib.h>
                     44: #include <string.h>
1.23      millert    45: #include <unistd.h>
1.1       deraadt    46:
                     47: long   flags;
                     48: #define        TRANSPOSE       000001
                     49: #define        MTRANSPOSE      000002
                     50: #define        ONEPERLINE      000004
                     51: #define        ONEISEPONLY     000010
                     52: #define        ONEOSEPONLY     000020
                     53: #define        NOTRIMENDCOL    000040
                     54: #define        SQUEEZE         000100
                     55: #define        SHAPEONLY       000200
                     56: #define        DETAILSHAPE     000400
                     57: #define        RIGHTADJUST     001000
                     58: #define        NULLPAD         002000
                     59: #define        RECYCLE         004000
                     60: #define        SKIPPRINT       010000
                     61: #define ONEPERCHAR     0100000
                     62: #define NOARGS         0200000
                     63:
                     64: short  *colwidths;
                     65: int    nelem;
                     66: char   **elem;
                     67: char   **endelem;
                     68: char   *curline;
                     69: int    allocsize = BUFSIZ;
1.28      schwarze   70: ssize_t        curlen;
1.1       deraadt    71: int    irows, icols;
                     72: int    orows, ocols;
1.28      schwarze   73: ssize_t        maxlen;
1.1       deraadt    74: int    skip;
                     75: int    propgutter;
                     76: char   isep = ' ', osep = ' ';
                     77: int    owidth = 80, gutter = 2;
                     78:
1.12      millert    79: void     usage(void);
1.7       millert    80: void     getargs(int, char *[]);
                     81: void     getfile(void);
1.21      fgsch      82: int      get_line(void);
1.7       millert    83: char   **getptrs(char **);
                     84: void     prepfile(void);
                     85: void     prints(char *, int);
                     86: void     putfile(void);
1.1       deraadt    87:
1.2       deraadt    88: #define INCR(ep) do {                  \
                     89:        if (++ep >= endelem)            \
                     90:                ep = getptrs(ep);       \
                     91: } while(0)
                     92:
1.1       deraadt    93: int
1.9       deraadt    94: main(int argc, char *argv[])
1.1       deraadt    95: {
1.27      deraadt    96:        if (pledge("stdio", NULL) == -1)
                     97:                err(1, "pledge");
1.26      deraadt    98:
1.1       deraadt    99:        getargs(argc, argv);
                    100:        getfile();
                    101:        if (flags & SHAPEONLY) {
                    102:                printf("%d %d\n", irows, icols);
                    103:                exit(0);
                    104:        }
                    105:        prepfile();
                    106:        putfile();
                    107:        exit(0);
                    108: }
                    109:
                    110: void
1.9       deraadt   111: getfile(void)
1.1       deraadt   112: {
1.6       mpech     113:        char *p;
                    114:        char *endp;
1.11      tedu      115:        char **ep = NULL;
1.1       deraadt   116:        int multisep = (flags & ONEISEPONLY ? 0 : 1);
                    117:        int nullpad = flags & NULLPAD;
                    118:        char **padto;
                    119:
                    120:        while (skip--) {
1.28      schwarze  121:                if (get_line() == EOF)
                    122:                        return;
1.1       deraadt   123:                if (flags & SKIPPRINT)
                    124:                        puts(curline);
                    125:        }
1.28      schwarze  126:        if (get_line() == EOF)
                    127:                return;
1.1       deraadt   128:        if (flags & NOARGS && curlen < owidth)
                    129:                flags |= ONEPERLINE;
                    130:        if (flags & ONEPERLINE)
                    131:                icols = 1;
                    132:        else                            /* count cols on first line */
                    133:                for (p = curline, endp = curline + curlen; p < endp; p++) {
                    134:                        if (*p == isep && multisep)
                    135:                                continue;
                    136:                        icols++;
                    137:                        while (*p && *p != isep)
                    138:                                p++;
                    139:                }
                    140:        ep = getptrs(elem);
                    141:        p = curline;
                    142:        do {
                    143:                if (flags & ONEPERLINE) {
1.2       deraadt   144:                        *ep = curline;
                    145:                        INCR(ep);               /* prepare for next entry */
1.1       deraadt   146:                        if (maxlen < curlen)
                    147:                                maxlen = curlen;
                    148:                        irows++;
                    149:                        continue;
                    150:                }
                    151:                for (p = curline, endp = curline + curlen; p < endp; p++) {
                    152:                        if (*p == isep && multisep)
                    153:                                continue;       /* eat up column separators */
                    154:                        if (*p == isep)         /* must be an empty column */
                    155:                                *ep = "";
                    156:                        else                    /* store column entry */
                    157:                                *ep = p;
                    158:                        while (p < endp && *p != isep)
                    159:                                p++;            /* find end of entry */
                    160:                        *p = '\0';              /* mark end of entry */
                    161:                        if (maxlen < p - *ep)   /* update maxlen */
                    162:                                maxlen = p - *ep;
1.2       deraadt   163:                        INCR(ep);               /* prepare for next entry */
1.1       deraadt   164:                }
                    165:                irows++;                        /* update row count */
                    166:                if (nullpad) {                  /* pad missing entries */
                    167:                        padto = elem + irows * icols;
1.2       deraadt   168:                        while (ep < padto) {
                    169:                                *ep = "";
                    170:                                INCR(ep);
                    171:                        }
1.1       deraadt   172:                }
1.21      fgsch     173:        } while (get_line() != EOF);
1.11      tedu      174:        *ep = NULL;                             /* mark end of pointers */
1.1       deraadt   175:        nelem = ep - elem;
                    176: }
                    177:
                    178: void
1.9       deraadt   179: putfile(void)
1.1       deraadt   180: {
1.6       mpech     181:        char **ep;
                    182:        int i, j, n;
1.1       deraadt   183:
                    184:        ep = elem;
1.2       deraadt   185:        if (flags & TRANSPOSE) {
1.1       deraadt   186:                for (i = 0; i < orows; i++) {
                    187:                        for (j = i; j < nelem; j += orows)
                    188:                                prints(ep[j], (j - i) / orows);
                    189:                        putchar('\n');
                    190:                }
1.2       deraadt   191:        } else {
                    192:                for (n = 0, i = 0; i < orows && n < nelem; i++) {
                    193:                        for (j = 0; j < ocols; j++) {
                    194:                                if (n++ >= nelem)
                    195:                                        break;
1.1       deraadt   196:                                prints(*ep++, j);
1.2       deraadt   197:                        }
1.1       deraadt   198:                        putchar('\n');
                    199:                }
1.2       deraadt   200:        }
1.1       deraadt   201: }
                    202:
                    203: void
1.9       deraadt   204: prints(char *s, int col)
1.1       deraadt   205: {
1.6       mpech     206:        int n;
                    207:        char *p = s;
1.1       deraadt   208:
                    209:        while (*p)
                    210:                p++;
                    211:        n = (flags & ONEOSEPONLY ? 1 : colwidths[col] - (p - s));
                    212:        if (flags & RIGHTADJUST)
                    213:                while (n-- > 0)
                    214:                        putchar(osep);
                    215:        for (p = s; *p; p++)
                    216:                putchar(*p);
                    217:        while (n-- > 0)
                    218:                putchar(osep);
                    219: }
                    220:
                    221: void
1.12      millert   222: usage(void)
1.1       deraadt   223: {
1.12      millert   224:        extern char *__progname;
                    225:
1.1       deraadt   226:        fprintf(stderr,
1.19      sobrado   227:            "usage: %s [-CcSs[x]] [-GgKkw N] [-EeHhjmnTtyz] [rows [cols]]\n",
1.12      millert   228:            __progname);
1.1       deraadt   229:        exit(1);
                    230: }
                    231:
                    232: void
1.9       deraadt   233: prepfile(void)
1.1       deraadt   234: {
1.6       mpech     235:        char **ep;
                    236:        int  i;
                    237:        int  j;
1.1       deraadt   238:        char **lp;
                    239:        int colw;
                    240:        int max = 0;
                    241:        int n;
                    242:
                    243:        if (!nelem)
                    244:                exit(0);
                    245:        gutter += maxlen * propgutter / 100.0;
                    246:        colw = maxlen + gutter;
                    247:        if (flags & MTRANSPOSE) {
                    248:                orows = icols;
                    249:                ocols = irows;
                    250:        }
                    251:        else if (orows == 0 && ocols == 0) {    /* decide rows and cols */
                    252:                ocols = owidth / colw;
1.2       deraadt   253:                if (ocols == 0) {
1.4       millert   254:                        warnx("Display width %d is less than column width %d",
                    255:                            owidth, colw);
1.2       deraadt   256:                        ocols = 1;
                    257:                }
1.1       deraadt   258:                if (ocols > nelem)
                    259:                        ocols = nelem;
                    260:                orows = nelem / ocols + (nelem % ocols ? 1 : 0);
                    261:        }
                    262:        else if (orows == 0)                    /* decide on rows */
                    263:                orows = nelem / ocols + (nelem % ocols ? 1 : 0);
                    264:        else if (ocols == 0)                    /* decide on cols */
                    265:                ocols = nelem / orows + (nelem % orows ? 1 : 0);
                    266:        lp = elem + orows * ocols;
                    267:        while (lp > endelem) {
                    268:                getptrs(elem + nelem);
                    269:                lp = elem + orows * ocols;
                    270:        }
                    271:        if (flags & RECYCLE) {
                    272:                for (ep = elem + nelem; ep < lp; ep++)
                    273:                        *ep = *(ep - nelem);
                    274:                nelem = lp - elem;
                    275:        }
1.25      deraadt   276:        if (!(colwidths = calloc(ocols, sizeof(short))))
1.2       deraadt   277:                errx(1, "malloc:  No gutter space");
1.1       deraadt   278:        if (flags & SQUEEZE) {
1.29    ! schwarze  279:                for (ep = elem, i = 0; i < ocols; i++) {
        !           280:                        max = 0;
        !           281:                        if (flags & TRANSPOSE) {
1.1       deraadt   282:                                for (j = 0; j < orows; j++)
                    283:                                        if ((n = strlen(*ep++)) > max)
                    284:                                                max = n;
1.29    ! schwarze  285:                        } else {
1.1       deraadt   286:                                for (j = i; j < nelem; j += ocols)
                    287:                                        if ((n = strlen(ep[j])) > max)
                    288:                                                max = n;
                    289:                        }
1.29    ! schwarze  290:                        colwidths[i] = max + gutter;
        !           291:                }
1.13      millert   292:        } else {
1.1       deraadt   293:                for (i = 0; i < ocols; i++)
                    294:                        colwidths[i] = colw;
1.13      millert   295:        }
1.1       deraadt   296:        if (!(flags & NOTRIMENDCOL)) {
                    297:                if (flags & RIGHTADJUST)
                    298:                        colwidths[0] -= gutter;
                    299:                else
                    300:                        colwidths[ocols - 1] = 0;
                    301:        }
                    302:        n = orows * ocols;
                    303:        if (n > nelem && (flags & RECYCLE))
                    304:                nelem = n;
                    305: }
                    306:
                    307: int
1.21      fgsch     308: get_line(void) /* get line; maintain curline, curlen; manage storage */
1.1       deraadt   309: {
1.28      schwarze  310:        static  char    *ibuf = NULL;
                    311:        static  size_t   ibufsz = 0;
                    312:
                    313:        if (irows > 0 && flags & DETAILSHAPE)
                    314:                printf(" %zd line %d\n", curlen, irows);
                    315:
                    316:        if ((curlen = getline(&ibuf, &ibufsz, stdin)) == EOF) {
                    317:                if (ferror(stdin))
                    318:                        err(1, NULL);
                    319:                return EOF;
                    320:        }
                    321:        if (curlen > 0 && ibuf[curlen - 1] == '\n')
                    322:                ibuf[--curlen] = '\0';
1.1       deraadt   323:
1.28      schwarze  324:        if (skip >= 0 || flags & SHAPEONLY)
1.1       deraadt   325:                curline = ibuf;
1.28      schwarze  326:        else if ((curline = strdup(ibuf)) == NULL)
                    327:                err(1, NULL);
                    328:
                    329:        return 0;
1.1       deraadt   330: }
                    331:
                    332: char **
1.9       deraadt   333: getptrs(char **sp)
1.1       deraadt   334: {
1.6       mpech     335:        char **p;
1.22      otto      336:        int newsize;
1.1       deraadt   337:
1.10      tedu      338:        newsize = allocsize * 2;
1.24      doug      339:        p = reallocarray(elem, newsize, sizeof(char *));
1.10      tedu      340:        if (p == NULL)
1.2       deraadt   341:                err(1, "no memory");
                    342:
1.22      otto      343:        allocsize = newsize;
                    344:        sp += p - elem;
1.10      tedu      345:        elem = p;
                    346:        endelem = elem + allocsize;
1.2       deraadt   347:        return(sp);
1.1       deraadt   348: }
                    349:
                    350: void
1.9       deraadt   351: getargs(int ac, char *av[])
1.1       deraadt   352: {
1.12      millert   353:        int ch;
1.14      millert   354:        const char *errstr;
1.1       deraadt   355:
1.12      millert   356:        if (ac == 1)
1.1       deraadt   357:                flags |= NOARGS | TRANSPOSE;
1.12      millert   358:        while ((ch = getopt(ac, av, "c::C::s::S::k:K:g:G:w:tTeEnyjhHmz")) != -1) {
                    359:                switch (ch) {
                    360:                case 'T':
                    361:                        flags |= MTRANSPOSE;
                    362:                        /* FALLTHROUGH */
                    363:                case 't':
                    364:                        flags |= TRANSPOSE;
                    365:                        break;
                    366:                case 'c':               /* input col. separator */
                    367:                        flags |= ONEISEPONLY;
                    368:                        /* FALLTHROUGH */
                    369:                case 's':               /* one or more allowed */
                    370:                        if (optarg == NULL)
                    371:                                isep = '\t';    /* default is ^I */
                    372:                        else if (optarg[1] != '\0')
                    373:                                usage();        /* single char only */
                    374:                        else
                    375:                                isep = *optarg;
                    376:                        break;
                    377:                case 'C':
                    378:                        flags |= ONEOSEPONLY;
                    379:                        /* FALLTHROUGH */
                    380:                case 'S':
                    381:                        if (optarg == NULL)
                    382:                                osep = '\t';    /* default is ^I */
                    383:                        else if (optarg[1] != '\0')
                    384:                                usage();        /* single char only */
                    385:                        else
                    386:                                osep = *optarg;
                    387:                        break;
                    388:                case 'w':               /* window width, default 80 */
1.14      millert   389:                        owidth = strtonum(optarg, 1, INT_MAX, &errstr);
                    390:                        if (errstr) {
                    391:                                warnx("width %s", errstr);
1.12      millert   392:                                usage();
                    393:                        }
                    394:                        break;
                    395:                case 'K':                       /* skip N lines */
                    396:                        flags |= SKIPPRINT;
                    397:                        /* FALLTHROUGH */
                    398:                case 'k':                       /* skip, do not print */
1.14      millert   399:                        skip = strtonum(optarg, 0, INT_MAX, &errstr);
                    400:                        if (errstr) {
                    401:                                warnx("skip value %s", errstr);
                    402:                                usage();
                    403:                        }
                    404:                        if (skip == 0)
1.12      millert   405:                                skip = 1;
                    406:                        break;
                    407:                case 'm':
                    408:                        flags |= NOTRIMENDCOL;
                    409:                        break;
1.14      millert   410:                case 'g':               /* gutter width */
                    411:                        gutter = strtonum(optarg, 0, INT_MAX, &errstr);
                    412:                        if (errstr) {
                    413:                                warnx("gutter width %s", errstr);
                    414:                                usage();
                    415:                        }
1.12      millert   416:                        break;
                    417:                case 'G':
1.14      millert   418:                        propgutter = strtonum(optarg, 0, INT_MAX, &errstr);
                    419:                        if (errstr) {
                    420:                                warnx("gutter proportion %s", errstr);
                    421:                                usage();
                    422:                        }
1.12      millert   423:                        break;
                    424:                case 'e':               /* each line is an entry */
                    425:                        flags |= ONEPERLINE;
                    426:                        break;
                    427:                case 'E':
                    428:                        flags |= ONEPERCHAR;
                    429:                        break;
                    430:                case 'j':                       /* right adjust */
                    431:                        flags |= RIGHTADJUST;
                    432:                        break;
                    433:                case 'n':       /* null padding for missing values */
                    434:                        flags |= NULLPAD;
                    435:                        break;
                    436:                case 'y':
                    437:                        flags |= RECYCLE;
                    438:                        break;
                    439:                case 'H':                       /* print shape only */
                    440:                        flags |= DETAILSHAPE;
                    441:                        /* FALLTHROUGH */
                    442:                case 'h':
                    443:                        flags |= SHAPEONLY;
                    444:                        break;
                    445:                case 'z':                       /* squeeze col width */
                    446:                        flags |= SQUEEZE;
                    447:                        break;
                    448:                default:
                    449:                        usage();
                    450:                }
1.1       deraadt   451:        }
1.12      millert   452:        ac -= optind;
                    453:        av += optind;
                    454:
1.1       deraadt   455:        switch (ac) {
                    456:        case 2:
1.14      millert   457:                ocols = strtonum(av[1], 0, INT_MAX, &errstr);
                    458:                if (errstr) {
                    459:                        warnx("columns value %s", errstr);
                    460:                        usage();
                    461:                }
1.17      moritz    462:                /* FALLTHROUGH */
1.1       deraadt   463:        case 1:
1.14      millert   464:                orows = strtonum(av[0], 0, INT_MAX, &errstr);
                    465:                if (errstr) {
                    466:                        warnx("columns value %s", errstr);
                    467:                        usage();
                    468:                }
1.17      moritz    469:                /* FALLTHROUGH */
1.1       deraadt   470:        case 0:
                    471:                break;
                    472:        default:
1.12      millert   473:                usage();
1.1       deraadt   474:        }
                    475: }