|
|
1.1 root 1: /*
2: * Copyright (c) 1989 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * This code is derived from software contributed to Berkeley by
6: * Adam S. Moskowitz of Menlo Consulting and Marciano Pitargue.
7: *
8: * Redistribution and use in source and binary forms are permitted provided
9: * that: (1) source distributions retain this entire copyright notice and
10: * comment, and (2) distributions including binaries display the following
11: * acknowledgement: ``This product includes software developed by the
12: * University of California, Berkeley and its contributors'' in the
13: * documentation or other materials provided with the distribution and in
14: * all advertising materials mentioning features or use of this software.
15: * Neither the name of the University nor the names of its contributors may
16: * be used to endorse or promote products derived from this software without
17: * specific prior written permission.
18: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
19: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
20: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21: */
22:
23: #ifndef lint
24: char copyright[] =
25: "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
26: All rights reserved.\n";
27: static char sccsid[] = "@(#)cut.c 5.3 (Berkeley) 6/24/90";
28: #endif /* not lint */
29:
30: #include <stdio.h>
31: #include <ctype.h>
32: #if COHERENT
33: #include <string.h>
34: #define _BSD_LINE_MAX BUFSIZ /* compatibility */
35: #else
36: #include <limits.h>
37: #endif
38:
39: int cflag;
40: char dchar;
41: int dflag;
42: int fflag;
43: int sflag;
44: long strtol();
45:
46: main(argc, argv)
47: int argc;
48: char **argv;
49: {
50: extern char *optarg;
51: extern int errno, optind;
52: FILE *fp;
53: int ch, (*fcn)(), c_cut(), f_cut();
54: char *strerror();
55:
56: dchar = '\t'; /* default delimiter is \t */
57:
58: while ((ch = getopt(argc, argv, "c:d:f:s")) != EOF)
59: switch(ch) {
60: case 'c':
61: fcn = c_cut;
62: get_list(optarg);
63: cflag = 1;
64: break;
65: case 'd':
66: dchar = *optarg;
67: dflag = 1;
68: break;
69: case 'f':
70: get_list(optarg);
71: fcn = f_cut;
72: fflag = 1;
73: break;
74: case 's':
75: sflag = 1;
76: break;
77: case '?':
78: default:
79: usage();
80: }
81: argc -= optind;
82: argv += optind;
83:
84: if (fflag) {
85: if (cflag)
86: usage();
87: } else if (!cflag || dflag || sflag)
88: usage();
89:
90: if (*argv)
91: for (; *argv; ++argv) {
92: if (!(fp = fopen(*argv, "r"))) {
93: (void)fprintf(stderr,
94: "cut: %s: %s\n", *argv, strerror(errno));
95: exit(1);
96: }
97: (*fcn)(fp, *argv);
98: }
99: else
100: (*fcn)(stdin, "stdin");
101: exit(0);
102: }
103:
104: int autostart, autostop, maxval;
105:
106: char positions[_BSD_LINE_MAX + 1];
107:
108: get_list(list)
109: char *list;
110: {
111: register char *pos;
112: register int setautostart, start, stop;
113: char *p, *strtok();
114:
115: /*
116: * set a byte in the positions array to indicate if a field or
117: * column is to be selected; use +1, it's 1-based, not 0-based.
118: * This parser is less restrictive than the Draft 9 POSIX spec.
119: * POSIX doesn't allow lists that aren't in increasing order or
120: * overlapping lists. We also handle "-3-5" although there's no
121: * real reason too.
122: */
123: for (; p = strtok(list, ", \t"); list = NULL) {
124: setautostart = start = stop = 0;
125: if (*p == '-') {
126: ++p;
127: setautostart = 1;
128: }
129: if (isdigit(*p)) {
130: start = stop = strtol(p, &p, 10);
131: if (setautostart && start > autostart)
132: autostart = start;
133: }
134: if (*p == '-') {
135: if (isdigit(p[1]))
136: stop = strtol(p + 1, &p, 10);
137: if (*p == '-') {
138: ++p;
139: if (!autostop || autostop > stop)
140: autostop = stop;
141: }
142: }
143: if (*p)
144: badlist("illegal list value");
145: if (!stop || !start)
146: badlist("values may not include zero");
147: if (stop > _BSD_LINE_MAX) {
148: /* positions used rather than allocate a new buffer */
149: (void)sprintf(positions, "%d too large (max %d)",
150: stop, _BSD_LINE_MAX);
151: badlist(positions);
152: }
153: if (maxval < stop)
154: maxval = stop;
155: for (pos = positions + start; start++ <= stop; *pos++ = 1);
156: }
157:
158: /* overlapping ranges */
159: if (autostop && maxval > autostop)
160: maxval = autostop;
161:
162: /* set autostart */
163: if (autostart)
164: memset(positions + 1, '1', autostart);
165: }
166:
167: /* ARGSUSED */
168: c_cut(fp, fname)
169: FILE *fp;
170: char *fname;
171: {
172: register int ch, col;
173: register char *pos;
174:
175: for (;;) {
176: pos = positions + 1;
177: for (col = maxval; col; --col) {
178: if ((ch = getc(fp)) == EOF)
179: return;
180: if (ch == '\n')
181: break;
182: if (*pos++)
183: putchar(ch);
184: }
185: if (ch != '\n')
186: if (autostop)
187: while ((ch = getc(fp)) != EOF && ch != '\n')
188: putchar(ch);
189: else
190: while ((ch = getc(fp)) != EOF && ch != '\n');
191: putchar('\n');
192: }
193: }
194:
195: f_cut(fp, fname)
196: FILE *fp;
197: char *fname;
198: {
199: register int ch, field, isdelim;
200: register char *pos, *p, sep;
201: int output;
202: char lbuf[_BSD_LINE_MAX + 1];
203:
204: for (sep = dchar, output = 0; fgets(lbuf, sizeof(lbuf), fp);) {
205: for (isdelim = 0, p = lbuf;; ++p) {
206: if (!(ch = *p)) {
207: (void)fprintf(stderr,
208: "cut: %s: line too long.\n", fname);
209: exit(1);
210: }
211: /* this should work if newline is delimiter */
212: if (ch == sep)
213: isdelim = 1;
214: if (ch == '\n') {
215: if (!isdelim && !sflag)
216: (void)printf("%s", lbuf);
217: break;
218: }
219: }
220: if (!isdelim)
221: continue;
222:
223: pos = positions + 1;
224: for (field = maxval, p = lbuf; field; --field, ++pos) {
225: if (*pos) {
226: if (output++)
227: putchar(sep);
228: while ((ch = *p++) != '\n' && ch != sep)
229: putchar(ch);
230: } else
231: while ((ch = *p++) != '\n' && ch != sep);
232: if (ch == '\n')
233: break;
234: }
235: if (ch != '\n')
236: if (autostop) {
237: if (output)
238: putchar(sep);
239: for (; (ch = *p) != '\n'; ++p)
240: putchar(ch);
241: } else
242: for (; (ch = *p) != '\n'; ++p);
243: putchar('\n');
244: }
245: }
246:
247: badlist(msg)
248: char *msg;
249: {
250: (void)fprintf(stderr, "cut: [-cf] list: %s.\n", msg);
251: exit(1);
252: }
253:
254: usage()
255: {
256: (void)fprintf(stderr,
257: "usage:\tcut -c list [file1 ...]\n\tcut -f list [-s] [-d delim] [file ...]\n");
258: exit(1);
259: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.