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