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

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