Annotation of src/usr.bin/cut/cut.c, Revision 1.6
1.6 ! aaron 1: /* $OpenBSD: cut.c,v 1.5 1997/11/05 00:18:44 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.
19: * 3. All advertising materials mentioning features or use of this software
20: * must display the following acknowledgement:
21: * This product includes software developed by the University of
22: * California, Berkeley and its contributors.
23: * 4. Neither the name of the University nor the names of its contributors
24: * may be used to endorse or promote products derived from this software
25: * without specific prior written permission.
26: *
27: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37: * SUCH DAMAGE.
38: */
39:
40: #ifndef lint
41: static char copyright[] =
42: "@(#) Copyright (c) 1989, 1993\n\
43: The Regents of the University of California. All rights reserved.\n";
44: #endif /* not lint */
45:
46: #ifndef lint
47: #if 0
48: static char sccsid[] = "@(#)cut.c 8.3 (Berkeley) 5/4/95";
49: #endif
1.6 ! aaron 50: static char rcsid[] = "$OpenBSD: cut.c,v 1.5 1997/11/05 00:18:44 deraadt Exp $";
1.1 deraadt 51: #endif /* not lint */
52:
53: #include <ctype.h>
54: #include <err.h>
55: #include <errno.h>
56: #include <limits.h>
57: #include <locale.h>
58: #include <stdio.h>
59: #include <stdlib.h>
60: #include <string.h>
61: #include <unistd.h>
62:
63: int cflag;
64: char dchar;
65: int dflag;
66: int fflag;
67: int sflag;
68:
69: void c_cut __P((FILE *, char *));
70: void f_cut __P((FILE *, char *));
71: void get_list __P((char *));
72: void usage __P((void));
73:
74: int
75: main(argc, argv)
76: int argc;
77: char *argv[];
78: {
79: FILE *fp;
80: void (*fcn) __P((FILE *, char *));
81: int ch;
82:
83: setlocale (LC_ALL, "");
84:
85: dchar = '\t'; /* default delimiter is \t */
86:
87: /* Since we don't support multi-byte characters, the -c and -b
88: options are equivalent, and the -n option is meaningless. */
1.3 millert 89: while ((ch = getopt(argc, argv, "b:c:d:f:sn")) != -1)
1.1 deraadt 90: switch(ch) {
91: case 'b':
92: case 'c':
93: fcn = c_cut;
94: get_list(optarg);
95: cflag = 1;
96: break;
97: case 'd':
98: dchar = *optarg;
99: dflag = 1;
100: break;
101: case 'f':
102: get_list(optarg);
103: fcn = f_cut;
104: fflag = 1;
105: break;
106: case 's':
107: sflag = 1;
108: break;
109: case 'n':
110: break;
111: case '?':
112: default:
113: usage();
114: }
115: argc -= optind;
116: argv += optind;
117:
118: if (fflag) {
119: if (cflag)
120: usage();
121: } else if (!cflag || dflag || sflag)
122: usage();
123:
124: if (*argv)
125: for (; *argv; ++argv) {
126: if (!(fp = fopen(*argv, "r")))
127: err(1, "%s", *argv);
128: fcn(fp, *argv);
129: (void)fclose(fp);
130: }
131: else
132: fcn(stdin, "stdin");
133: exit(0);
134: }
135:
136: int autostart, autostop, maxval;
137:
138: char positions[_POSIX2_LINE_MAX + 1];
139:
140: void
141: get_list(list)
142: char *list;
143: {
144: register int setautostart, start, stop;
145: register char *pos;
146: char *p;
147:
148: /*
149: * set a byte in the positions array to indicate if a field or
150: * column is to be selected; use +1, it's 1-based, not 0-based.
151: * This parser is less restrictive than the Draft 9 POSIX spec.
152: * POSIX doesn't allow lists that aren't in increasing order or
153: * overlapping lists. We also handle "-3-5" although there's no
154: * real reason too.
155: */
1.6 ! aaron 156: for (; p = strsep(&list, ", \t");) {
1.1 deraadt 157: setautostart = start = stop = 0;
158: if (*p == '-') {
159: ++p;
160: setautostart = 1;
161: }
162: if (isdigit(*p)) {
163: start = stop = strtol(p, &p, 10);
164: if (setautostart && start > autostart)
165: autostart = start;
166: }
167: if (*p == '-') {
168: if (isdigit(p[1]))
169: stop = strtol(p + 1, &p, 10);
170: if (*p == '-') {
171: ++p;
172: if (!autostop || autostop > stop)
173: autostop = stop;
174: }
175: }
176: if (*p)
1.4 millert 177: errx(1, "[-cf] list: illegal list value");
1.1 deraadt 178: if (!stop || !start)
1.4 millert 179: errx(1, "[-cf] list: values may not include zero");
1.1 deraadt 180: if (stop > _POSIX2_LINE_MAX)
1.4 millert 181: errx(1, "[-cf] list: %d too large (max %d)",
1.1 deraadt 182: stop, _POSIX2_LINE_MAX);
183: if (maxval < stop)
184: maxval = stop;
185: for (pos = positions + start; start++ <= stop; *pos++ = 1);
186: }
187:
188: /* overlapping ranges */
189: if (autostop && maxval > autostop)
190: maxval = autostop;
191:
192: /* set autostart */
193: if (autostart)
194: memset(positions + 1, '1', autostart);
195: }
196:
197: /* ARGSUSED */
198: void
199: c_cut(fp, fname)
200: FILE *fp;
201: char *fname;
202: {
203: register int ch, col;
204: register char *pos;
205:
206: for (;;) {
207: pos = positions + 1;
208: for (col = maxval; col; --col) {
209: if ((ch = getc(fp)) == EOF)
210: return;
211: if (ch == '\n')
212: break;
213: if (*pos++)
214: (void)putchar(ch);
215: }
216: if (ch != '\n')
217: if (autostop)
218: while ((ch = getc(fp)) != EOF && ch != '\n')
219: (void)putchar(ch);
220: else
221: while ((ch = getc(fp)) != EOF && ch != '\n');
222: (void)putchar('\n');
223: }
224: }
225:
226: void
227: f_cut(fp, fname)
228: FILE *fp;
229: char *fname;
230: {
231: register int ch, field, isdelim;
232: register char *pos, *p, sep;
233: int output;
234: char lbuf[_POSIX2_LINE_MAX + 1];
235:
236: for (sep = dchar; fgets(lbuf, sizeof(lbuf), fp);) {
237: output = 0;
238: for (isdelim = 0, p = lbuf;; ++p) {
239: if (!(ch = *p))
1.4 millert 240: errx(1, "%s: line too long.", fname);
1.1 deraadt 241: /* this should work if newline is delimiter */
242: if (ch == sep)
243: isdelim = 1;
244: if (ch == '\n') {
245: if (!isdelim && !sflag)
246: (void)printf("%s", lbuf);
247: break;
248: }
249: }
250: if (!isdelim)
251: continue;
252:
253: pos = positions + 1;
254: for (field = maxval, p = lbuf; field; --field, ++pos) {
255: if (*pos) {
256: if (output++)
257: (void)putchar(sep);
258: while ((ch = *p++) != '\n' && ch != sep)
259: (void)putchar(ch);
260: } else
261: while ((ch = *p++) != '\n' && ch != sep);
262: if (ch == '\n')
263: break;
264: }
265: if (ch != '\n')
266: if (autostop) {
267: if (output)
268: (void)putchar(sep);
269: for (; (ch = *p) != '\n'; ++p)
270: (void)putchar(ch);
271: } else
272: for (; (ch = *p) != '\n'; ++p);
273: (void)putchar('\n');
274: }
275: }
276:
277: void
278: usage()
279: {
280: (void)fprintf(stderr,
1.5 deraadt 281: "usage:\tcut -c list [file1 ...]\n"
282: "\tcut -f list [-s] [-d delim] [file ...]\n"
283: "\tcut -b list [-n] [file ...]\n");
1.1 deraadt 284: exit(1);
285: }