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

Annotation of src/usr.bin/cut/cut.c, Revision 1.28

1.28    ! guenther    1: /*     $OpenBSD: cut.c,v 1.27 2022/12/04 23:50:47 cheloha Exp $        */
1.1       deraadt     2: /*     $NetBSD: cut.c,v 1.9 1995/09/02 05:59:23 jtc Exp $      */
                      3:
                      4: /*
                      5:  * Copyright (c) 1989, 1993
                      6:  *     The Regents of the University of California.  All rights reserved.
                      7:  *
                      8:  * This code is derived from software contributed to Berkeley by
                      9:  * Adam S. Moskowitz of Menlo Consulting and Marciano Pitargue.
                     10:  *
                     11:  * Redistribution and use in source and binary forms, with or without
                     12:  * modification, are permitted provided that the following conditions
                     13:  * are met:
                     14:  * 1. Redistributions of source code must retain the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer.
                     16:  * 2. Redistributions in binary form must reproduce the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer in the
                     18:  *    documentation and/or other materials provided with the distribution.
1.10      millert    19:  * 3. Neither the name of the University nor the names of its contributors
1.1       deraadt    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:
1.23      schwarze   36: #include <assert.h>
1.1       deraadt    37: #include <ctype.h>
                     38: #include <err.h>
                     39: #include <errno.h>
                     40: #include <limits.h>
                     41: #include <locale.h>
                     42: #include <stdio.h>
                     43: #include <stdlib.h>
                     44: #include <string.h>
                     45: #include <unistd.h>
                     46:
1.23      schwarze   47: char   dchar[5];
                     48: int    dlen;
                     49:
                     50: int    bflag;
1.1       deraadt    51: int    cflag;
                     52: int    dflag;
                     53: int    fflag;
1.23      schwarze   54: int    nflag;
1.1       deraadt    55: int    sflag;
                     56:
1.23      schwarze   57: void   b_cut(FILE *, char *);
1.9       millert    58: void   c_cut(FILE *, char *);
                     59: void   f_cut(FILE *, char *);
                     60: void   get_list(char *);
                     61: void   usage(void);
1.1       deraadt    62:
                     63: int
1.11      deraadt    64: main(int argc, char *argv[])
1.1       deraadt    65: {
                     66:        FILE *fp;
1.9       millert    67:        void (*fcn)(FILE *, char *);
1.18      sobrado    68:        int ch, rval;
1.1       deraadt    69:
1.23      schwarze   70:        setlocale(LC_CTYPE, "");
1.1       deraadt    71:
1.21      deraadt    72:        if (pledge("stdio rpath", NULL) == -1)
                     73:                err(1, "pledge");
1.20      deraadt    74:
1.23      schwarze   75:        dchar[0] = '\t';                /* default delimiter */
                     76:        dchar[1] = '\0';
                     77:        dlen = 1;
1.1       deraadt    78:
1.3       millert    79:        while ((ch = getopt(argc, argv, "b:c:d:f:sn")) != -1)
1.1       deraadt    80:                switch(ch) {
                     81:                case 'b':
1.23      schwarze   82:                        get_list(optarg);
                     83:                        bflag = 1;
                     84:                        break;
1.1       deraadt    85:                case 'c':
                     86:                        get_list(optarg);
                     87:                        cflag = 1;
                     88:                        break;
                     89:                case 'd':
1.23      schwarze   90:                        if ((dlen = mblen(optarg, MB_CUR_MAX)) == -1)
                     91:                                usage();
                     92:                        assert(dlen < sizeof(dchar));
                     93:                        (void)memcpy(dchar, optarg, dlen);
                     94:                        dchar[dlen] = '\0';
1.1       deraadt    95:                        dflag = 1;
                     96:                        break;
                     97:                case 'f':
                     98:                        get_list(optarg);
                     99:                        fflag = 1;
                    100:                        break;
1.23      schwarze  101:                case 'n':
                    102:                        nflag = 1;
                    103:                        break;
1.1       deraadt   104:                case 's':
                    105:                        sflag = 1;
                    106:                        break;
                    107:                default:
                    108:                        usage();
                    109:                }
                    110:        argc -= optind;
                    111:        argv += optind;
                    112:
1.23      schwarze  113:        if (bflag + cflag + fflag != 1 ||
                    114:            (nflag && !bflag) ||
                    115:            ((dflag || sflag) && !fflag))
1.1       deraadt   116:                usage();
                    117:
1.23      schwarze  118:        if (MB_CUR_MAX == 1) {
                    119:                nflag = 0;
                    120:                if (cflag) {
                    121:                        bflag = 1;
                    122:                        cflag = 0;
                    123:                }
                    124:        }
                    125:
                    126:        fcn = fflag ? f_cut : (cflag || nflag) ? c_cut : b_cut;
                    127:
1.18      sobrado   128:        rval = 0;
1.1       deraadt   129:        if (*argv)
                    130:                for (; *argv; ++argv) {
1.17      sobrado   131:                        if (strcmp(*argv, "-") == 0)
                    132:                                fcn(stdin, "stdin");
                    133:                        else {
                    134:                                if ((fp = fopen(*argv, "r"))) {
                    135:                                        fcn(fp, *argv);
                    136:                                        (void)fclose(fp);
                    137:                                } else {
1.18      sobrado   138:                                        rval = 1;
1.17      sobrado   139:                                        warn("%s", *argv);
                    140:                                }
                    141:                        }
1.1       deraadt   142:                }
1.20      deraadt   143:        else {
1.26      tobias    144:                if (pledge("stdio", NULL) == -1)
1.21      deraadt   145:                        err(1, "pledge");
1.22      mmcc      146:
1.1       deraadt   147:                fcn(stdin, "stdin");
1.20      deraadt   148:        }
1.18      sobrado   149:        exit(rval);
1.1       deraadt   150: }
                    151:
                    152: int autostart, autostop, maxval;
                    153:
                    154: char positions[_POSIX2_LINE_MAX + 1];
                    155:
1.24      tobias    156: int
                    157: read_number(char **p)
                    158: {
                    159:        int dash, n;
                    160:        const char *errstr;
                    161:        char *q;
                    162:
                    163:        q = *p + strcspn(*p, "-");
                    164:        dash = *q == '-';
                    165:        *q = '\0';
                    166:        n = strtonum(*p, 1, _POSIX2_LINE_MAX, &errstr);
                    167:        if (errstr != NULL)
                    168:                errx(1, "[-bcf] list: %s %s (allowed 1-%d)", *p, errstr,
                    169:                    _POSIX2_LINE_MAX);
                    170:        if (dash)
                    171:                *q = '-';
                    172:        *p = q;
                    173:
                    174:        return n;
                    175: }
                    176:
1.1       deraadt   177: void
1.11      deraadt   178: get_list(char *list)
1.1       deraadt   179: {
1.8       mpech     180:        int setautostart, start, stop;
1.1       deraadt   181:        char *p;
                    182:
                    183:        /*
                    184:         * set a byte in the positions array to indicate if a field or
                    185:         * column is to be selected; use +1, it's 1-based, not 0-based.
                    186:         * This parser is less restrictive than the Draft 9 POSIX spec.
                    187:         * POSIX doesn't allow lists that aren't in increasing order or
                    188:         * overlapping lists.  We also handle "-3-5" although there's no
                    189:         * real reason too.
                    190:         */
1.7       aaron     191:        while ((p = strsep(&list, ", \t"))) {
1.1       deraadt   192:                setautostart = start = stop = 0;
                    193:                if (*p == '-') {
                    194:                        ++p;
                    195:                        setautostart = 1;
                    196:                }
1.16      deraadt   197:                if (isdigit((unsigned char)*p)) {
1.24      tobias    198:                        start = stop = read_number(&p);
1.1       deraadt   199:                        if (setautostart && start > autostart)
                    200:                                autostart = start;
                    201:                }
                    202:                if (*p == '-') {
1.24      tobias    203:                        if (isdigit((unsigned char)p[1])) {
                    204:                                ++p;
                    205:                                stop = read_number(&p);
                    206:                        }
1.1       deraadt   207:                        if (*p == '-') {
                    208:                                ++p;
                    209:                                if (!autostop || autostop > stop)
                    210:                                        autostop = stop;
                    211:                        }
                    212:                }
1.24      tobias    213:                if (*p != '\0' || !stop || !start)
1.15      schwarze  214:                        errx(1, "[-bcf] list: illegal list value");
1.1       deraadt   215:                if (maxval < stop)
                    216:                        maxval = stop;
1.24      tobias    217:                if (start <= stop)
                    218:                        memset(positions + start, 1, stop - start + 1);
1.1       deraadt   219:        }
                    220:
                    221:        /* overlapping ranges */
                    222:        if (autostop && maxval > autostop)
                    223:                maxval = autostop;
                    224:
                    225:        /* set autostart */
                    226:        if (autostart)
                    227:                memset(positions + 1, '1', autostart);
                    228: }
                    229:
                    230: void
1.23      schwarze  231: b_cut(FILE *fp, char *fname)
1.1       deraadt   232: {
1.8       mpech     233:        int ch, col;
                    234:        char *pos;
1.1       deraadt   235:
                    236:        for (;;) {
                    237:                pos = positions + 1;
                    238:                for (col = maxval; col; --col) {
                    239:                        if ((ch = getc(fp)) == EOF)
                    240:                                return;
                    241:                        if (ch == '\n')
                    242:                                break;
                    243:                        if (*pos++)
                    244:                                (void)putchar(ch);
                    245:                }
1.7       aaron     246:                if (ch != '\n') {
1.1       deraadt   247:                        if (autostop)
                    248:                                while ((ch = getc(fp)) != EOF && ch != '\n')
                    249:                                        (void)putchar(ch);
                    250:                        else
1.7       aaron     251:                                while ((ch = getc(fp)) != EOF && ch != '\n')
                    252:                                        ;
                    253:                }
1.1       deraadt   254:                (void)putchar('\n');
                    255:        }
                    256: }
                    257:
                    258: void
1.23      schwarze  259: c_cut(FILE *fp, char *fname)
1.1       deraadt   260: {
1.23      schwarze  261:        static char     *line = NULL;
                    262:        static size_t    linesz = 0;
                    263:        ssize_t          linelen;
                    264:        char            *cp, *pos, *maxpos;
                    265:        int              len;
                    266:
                    267:        while ((linelen = getline(&line, &linesz, fp)) != -1) {
                    268:                if (line[linelen - 1] == '\n')
                    269:                        line[linelen - 1] = '\0';
1.1       deraadt   270:
1.23      schwarze  271:                cp = line;
                    272:                pos = positions + 1;
                    273:                maxpos = pos + maxval;
                    274:                while(pos < maxpos && *cp != '\0') {
                    275:                        len = mblen(cp, MB_CUR_MAX);
                    276:                        if (len == -1)
                    277:                                len = 1;
                    278:                        pos += nflag ? len : 1;
                    279:                        if (pos[-1] == '\0')
                    280:                                cp += len;
                    281:                        else
                    282:                                while (len--)
                    283:                                        putchar(*cp++);
1.1       deraadt   284:                }
1.23      schwarze  285:                if (autostop)
                    286:                        puts(cp);
                    287:                else
                    288:                        putchar('\n');
                    289:        }
                    290: }
                    291:
                    292: void
                    293: f_cut(FILE *fp, char *fname)
                    294: {
                    295:        static char     *line = NULL;
                    296:        static size_t    linesz = 0;
                    297:        ssize_t          linelen;
                    298:        char            *sp, *ep, *pos, *maxpos;
                    299:        int              output;
                    300:
                    301:        while ((linelen = getline(&line, &linesz, fp)) != -1) {
                    302:                if (line[linelen - 1] == '\n')
                    303:                        line[linelen - 1] = '\0';
                    304:
                    305:                if ((ep = strstr(line, dchar)) == NULL) {
                    306:                        if (!sflag)
                    307:                                puts(line);
1.1       deraadt   308:                        continue;
1.23      schwarze  309:                }
1.1       deraadt   310:
                    311:                pos = positions + 1;
1.23      schwarze  312:                maxpos = pos + maxval;
                    313:                output = 0;
                    314:                sp = line;
                    315:                for (;;) {
                    316:                        if (*pos++) {
                    317:                                if (output)
                    318:                                        fputs(dchar, stdout);
                    319:                                while (sp < ep)
                    320:                                        putchar(*sp++);
                    321:                                output = 1;
1.1       deraadt   322:                        } else
1.23      schwarze  323:                                sp = ep;
                    324:                        if (*sp == '\0' || pos == maxpos)
1.1       deraadt   325:                                break;
1.23      schwarze  326:                        sp += dlen;
                    327:                        if ((ep = strstr(sp, dchar)) == NULL)
                    328:                                ep = strchr(sp, '\0');
                    329:                }
                    330:                if (autostop)
                    331:                        puts(sp);
                    332:                else
                    333:                        putchar('\n');
1.1       deraadt   334:        }
                    335: }
                    336:
                    337: void
1.11      deraadt   338: usage(void)
1.1       deraadt   339: {
                    340:        (void)fprintf(stderr,
1.13      sobrado   341:            "usage: cut -b list [-n] [file ...]\n"
                    342:            "       cut -c list [file ...]\n"
                    343:            "       cut -f list [-s] [-d delim] [file ...]\n");
1.1       deraadt   344:        exit(1);
                    345: }