Annotation of src/usr.bin/cut/cut.c, Revision 1.20
1.20 ! deraadt 1: /* $OpenBSD: cut.c,v 1.19 2015/08/18 17:10:48 deraadt 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:
36: #include <ctype.h>
37: #include <err.h>
38: #include <errno.h>
39: #include <limits.h>
40: #include <locale.h>
41: #include <stdio.h>
42: #include <stdlib.h>
43: #include <string.h>
44: #include <unistd.h>
45:
46: int cflag;
47: char dchar;
48: int dflag;
49: int fflag;
50: int sflag;
51:
1.9 millert 52: void c_cut(FILE *, char *);
53: void f_cut(FILE *, char *);
54: void get_list(char *);
55: void usage(void);
1.1 deraadt 56:
57: int
1.11 deraadt 58: main(int argc, char *argv[])
1.1 deraadt 59: {
60: FILE *fp;
1.9 millert 61: void (*fcn)(FILE *, char *);
1.18 sobrado 62: int ch, rval;
1.1 deraadt 63:
64: setlocale (LC_ALL, "");
65:
1.20 ! deraadt 66: if (tame("stdio rpath", NULL) == -1)
! 67: err(1, "tame");
! 68:
1.1 deraadt 69: dchar = '\t'; /* default delimiter is \t */
70:
71: /* Since we don't support multi-byte characters, the -c and -b
72: options are equivalent, and the -n option is meaningless. */
1.3 millert 73: while ((ch = getopt(argc, argv, "b:c:d:f:sn")) != -1)
1.1 deraadt 74: switch(ch) {
75: case 'b':
76: case 'c':
77: fcn = c_cut;
78: get_list(optarg);
79: cflag = 1;
80: break;
81: case 'd':
82: dchar = *optarg;
83: dflag = 1;
84: break;
85: case 'f':
86: get_list(optarg);
87: fcn = f_cut;
88: fflag = 1;
89: break;
90: case 's':
91: sflag = 1;
92: break;
93: case 'n':
94: break;
95: case '?':
96: default:
97: usage();
98: }
99: argc -= optind;
100: argv += optind;
101:
102: if (fflag) {
103: if (cflag)
104: usage();
105: } else if (!cflag || dflag || sflag)
106: usage();
107:
1.18 sobrado 108: rval = 0;
1.1 deraadt 109: if (*argv)
110: for (; *argv; ++argv) {
1.17 sobrado 111: if (strcmp(*argv, "-") == 0)
112: fcn(stdin, "stdin");
113: else {
114: if ((fp = fopen(*argv, "r"))) {
115: fcn(fp, *argv);
116: (void)fclose(fp);
117: } else {
1.18 sobrado 118: rval = 1;
1.17 sobrado 119: warn("%s", *argv);
120: }
121: }
1.1 deraadt 122: }
1.20 ! deraadt 123: else {
! 124: if (tame("stdio rpath", NULL) == -1)
! 125: err(1, "tame");
1.1 deraadt 126: fcn(stdin, "stdin");
1.20 ! deraadt 127: }
1.18 sobrado 128: exit(rval);
1.1 deraadt 129: }
130:
131: int autostart, autostop, maxval;
132:
133: char positions[_POSIX2_LINE_MAX + 1];
134:
135: void
1.11 deraadt 136: get_list(char *list)
1.1 deraadt 137: {
1.8 mpech 138: int setautostart, start, stop;
139: char *pos;
1.1 deraadt 140: char *p;
141:
142: /*
143: * set a byte in the positions array to indicate if a field or
144: * column is to be selected; use +1, it's 1-based, not 0-based.
145: * This parser is less restrictive than the Draft 9 POSIX spec.
146: * POSIX doesn't allow lists that aren't in increasing order or
147: * overlapping lists. We also handle "-3-5" although there's no
148: * real reason too.
149: */
1.7 aaron 150: while ((p = strsep(&list, ", \t"))) {
1.1 deraadt 151: setautostart = start = stop = 0;
152: if (*p == '-') {
153: ++p;
154: setautostart = 1;
155: }
1.16 deraadt 156: if (isdigit((unsigned char)*p)) {
1.1 deraadt 157: start = stop = strtol(p, &p, 10);
158: if (setautostart && start > autostart)
159: autostart = start;
160: }
161: if (*p == '-') {
1.16 deraadt 162: if (isdigit((unsigned char)p[1]))
1.1 deraadt 163: stop = strtol(p + 1, &p, 10);
164: if (*p == '-') {
165: ++p;
166: if (!autostop || autostop > stop)
167: autostop = stop;
168: }
169: }
170: if (*p)
1.15 schwarze 171: errx(1, "[-bcf] list: illegal list value");
1.1 deraadt 172: if (!stop || !start)
1.15 schwarze 173: errx(1, "[-bcf] list: values may not include zero");
1.1 deraadt 174: if (stop > _POSIX2_LINE_MAX)
1.15 schwarze 175: errx(1, "[-bcf] list: %d too large (max %d)",
1.1 deraadt 176: stop, _POSIX2_LINE_MAX);
177: if (maxval < stop)
178: maxval = stop;
1.7 aaron 179: for (pos = positions + start; start++ <= stop; *pos++ = 1)
180: ;
1.1 deraadt 181: }
182:
183: /* overlapping ranges */
184: if (autostop && maxval > autostop)
185: maxval = autostop;
186:
187: /* set autostart */
188: if (autostart)
189: memset(positions + 1, '1', autostart);
190: }
191:
192: /* ARGSUSED */
193: void
1.11 deraadt 194: c_cut(FILE *fp, char *fname)
1.1 deraadt 195: {
1.8 mpech 196: int ch, col;
197: char *pos;
1.1 deraadt 198:
199: for (;;) {
200: pos = positions + 1;
201: for (col = maxval; col; --col) {
202: if ((ch = getc(fp)) == EOF)
203: return;
204: if (ch == '\n')
205: break;
206: if (*pos++)
207: (void)putchar(ch);
208: }
1.7 aaron 209: if (ch != '\n') {
1.1 deraadt 210: if (autostop)
211: while ((ch = getc(fp)) != EOF && ch != '\n')
212: (void)putchar(ch);
213: else
1.7 aaron 214: while ((ch = getc(fp)) != EOF && ch != '\n')
215: ;
216: }
1.1 deraadt 217: (void)putchar('\n');
218: }
219: }
220:
221: void
1.11 deraadt 222: f_cut(FILE *fp, char *fname)
1.1 deraadt 223: {
1.8 mpech 224: int ch, field, isdelim;
225: char *pos, *p, sep;
1.1 deraadt 226: int output;
1.7 aaron 227: size_t len;
228: char *lbuf, *tbuf;
1.1 deraadt 229:
1.7 aaron 230: for (sep = dchar, tbuf = NULL; (lbuf = fgetln(fp, &len));) {
1.1 deraadt 231: output = 0;
1.7 aaron 232: if (lbuf[len - 1] != '\n') {
233: /* no newline at the end of the last line so add one */
1.19 deraadt 234: if ((tbuf = malloc(len + 1)) == NULL)
1.7 aaron 235: err(1, NULL);
236: memcpy(tbuf, lbuf, len);
237: tbuf[len] = '\n';
238: lbuf = tbuf;
239: }
1.1 deraadt 240: for (isdelim = 0, p = lbuf;; ++p) {
1.7 aaron 241: ch = *p;
1.1 deraadt 242: /* this should work if newline is delimiter */
243: if (ch == sep)
244: isdelim = 1;
245: if (ch == '\n') {
246: if (!isdelim && !sflag)
1.7 aaron 247: (void)fwrite(lbuf, len, 1, stdout);
1.1 deraadt 248: break;
249: }
250: }
251: if (!isdelim)
252: continue;
253:
254: pos = positions + 1;
255: for (field = maxval, p = lbuf; field; --field, ++pos) {
256: if (*pos) {
257: if (output++)
258: (void)putchar(sep);
259: while ((ch = *p++) != '\n' && ch != sep)
260: (void)putchar(ch);
261: } else
1.7 aaron 262: while ((ch = *p++) != '\n' && ch != sep)
263: ;
1.1 deraadt 264: if (ch == '\n')
265: break;
266: }
1.7 aaron 267: if (ch != '\n') {
1.1 deraadt 268: if (autostop) {
269: if (output)
270: (void)putchar(sep);
271: for (; (ch = *p) != '\n'; ++p)
272: (void)putchar(ch);
273: } else
1.7 aaron 274: for (; (ch = *p) != '\n'; ++p)
275: ;
276: }
1.1 deraadt 277: (void)putchar('\n');
278: }
1.7 aaron 279: if (tbuf)
280: free(tbuf);
1.1 deraadt 281: }
282:
283: void
1.11 deraadt 284: usage(void)
1.1 deraadt 285: {
286: (void)fprintf(stderr,
1.13 sobrado 287: "usage: cut -b list [-n] [file ...]\n"
288: " cut -c list [file ...]\n"
289: " cut -f list [-s] [-d delim] [file ...]\n");
1.1 deraadt 290: exit(1);
291: }