cut.c revision 1591
1126756Smlaier/*
2126756Smlaier * Copyright (c) 1989, 1993
3126756Smlaier *	The Regents of the University of California.  All rights reserved.
4126756Smlaier *
5126756Smlaier * This code is derived from software contributed to Berkeley by
6126756Smlaier * Adam S. Moskowitz of Menlo Consulting and Marciano Pitargue.
7126756Smlaier *
8126756Smlaier * Redistribution and use in source and binary forms, with or without
9126756Smlaier * modification, are permitted provided that the following conditions
10126756Smlaier * are met:
11126756Smlaier * 1. Redistributions of source code must retain the above copyright
12126756Smlaier *    notice, this list of conditions and the following disclaimer.
13126756Smlaier * 2. Redistributions in binary form must reproduce the above copyright
14126756Smlaier *    notice, this list of conditions and the following disclaimer in the
15126756Smlaier *    documentation and/or other materials provided with the distribution.
16126756Smlaier * 3. All advertising materials mentioning features or use of this software
17126756Smlaier *    must display the following acknowledgement:
18126756Smlaier *	This product includes software developed by the University of
19126756Smlaier *	California, Berkeley and its contributors.
20126756Smlaier * 4. Neither the name of the University nor the names of its contributors
21126756Smlaier *    may be used to endorse or promote products derived from this software
22126756Smlaier *    without specific prior written permission.
23126756Smlaier *
24126756Smlaier * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25126756Smlaier * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26126756Smlaier * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27126756Smlaier * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28126756Smlaier * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29126756Smlaier * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30126756Smlaier * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31126756Smlaier * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32126756Smlaier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33126756Smlaier * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34126756Smlaier * SUCH DAMAGE.
35126756Smlaier */
36126756Smlaier
37126756Smlaier#ifndef lint
38126756Smlaierstatic char copyright[] =
39126756Smlaier"@(#) Copyright (c) 1989, 1993\n\
40126756Smlaier	The Regents of the University of California.  All rights reserved.\n";
41126756Smlaier#endif /* not lint */
42126756Smlaier
43126756Smlaier#ifndef lint
44126756Smlaierstatic char sccsid[] = "@(#)cut.c	8.1 (Berkeley) 6/6/93";
45126756Smlaier#endif /* not lint */
46126756Smlaier
47126756Smlaier#include <ctype.h>
48126756Smlaier#include <errno.h>
49126756Smlaier#include <limits.h>
50126756Smlaier#include <stdio.h>
51126756Smlaier#include <stdlib.h>
52126756Smlaier#include <string.h>
53126756Smlaier
54126756Smlaierint	cflag;
55126756Smlaierchar	dchar;
56126756Smlaierint	dflag;
57126756Smlaierint	fflag;
58126756Smlaierint	sflag;
59126756Smlaier
60126756Smlaiervoid	c_cut __P((FILE *, char *));
61126756Smlaiervoid	err __P((const char *, ...));
62126756Smlaiervoid	f_cut __P((FILE *, char *));
63126756Smlaiervoid	get_list __P((char *));
64126756Smlaiervoid	usage __P((void));
65126756Smlaier
66126756Smlaierint
67126756Smlaiermain(argc, argv)
68126756Smlaier	int argc;
69126756Smlaier	char *argv[];
70126756Smlaier{
71126756Smlaier	FILE *fp;
72126756Smlaier	void (*fcn) __P((FILE *, char *));
73126756Smlaier	int ch;
74126756Smlaier
75126756Smlaier	dchar = '\t';			/* default delimiter is \t */
76126756Smlaier
77126756Smlaier	while ((ch = getopt(argc, argv, "c:d:f:s")) != EOF)
78126756Smlaier		switch(ch) {
79126756Smlaier		case 'c':
80126756Smlaier			fcn = c_cut;
81126756Smlaier			get_list(optarg);
82126756Smlaier			cflag = 1;
83126756Smlaier			break;
84126756Smlaier		case 'd':
85126756Smlaier			dchar = *optarg;
86126756Smlaier			dflag = 1;
87126756Smlaier			break;
88126756Smlaier		case 'f':
89126756Smlaier			get_list(optarg);
90126756Smlaier			fcn = f_cut;
91126756Smlaier			fflag = 1;
92126756Smlaier			break;
93126756Smlaier		case 's':
94126756Smlaier			sflag = 1;
95126756Smlaier			break;
96126756Smlaier		case '?':
97126756Smlaier		default:
98126756Smlaier			usage();
99126756Smlaier		}
100126756Smlaier	argc -= optind;
101126756Smlaier	argv += optind;
102126756Smlaier
103126756Smlaier	if (fflag) {
104126756Smlaier		if (cflag)
105126756Smlaier			usage();
106126756Smlaier	} else if (!cflag || dflag || sflag)
107126756Smlaier		usage();
108126756Smlaier
109126756Smlaier	if (*argv)
110126756Smlaier		for (; *argv; ++argv) {
111126756Smlaier			if (!(fp = fopen(*argv, "r")))
112126756Smlaier				err("%s: %s\n", *argv, strerror(errno));
113126756Smlaier			fcn(fp, *argv);
114126756Smlaier			(void)fclose(fp);
115126756Smlaier		}
116126756Smlaier	else
117126756Smlaier		fcn(stdin, "stdin");
118126756Smlaier	exit(0);
119126756Smlaier}
120126756Smlaier
121126756Smlaierint autostart, autostop, maxval;
122126756Smlaier
123126756Smlaierchar positions[_POSIX2_LINE_MAX + 1];
124126756Smlaier
125126756Smlaiervoid
126126756Smlaierget_list(list)
127126756Smlaier	char *list;
128126756Smlaier{
129126756Smlaier	register int setautostart, start, stop;
130126756Smlaier	register char *pos;
131126756Smlaier	char *p;
132126756Smlaier
133126756Smlaier	/*
134126756Smlaier	 * set a byte in the positions array to indicate if a field or
135126756Smlaier	 * column is to be selected; use +1, it's 1-based, not 0-based.
136126756Smlaier	 * This parser is less restrictive than the Draft 9 POSIX spec.
137126756Smlaier	 * POSIX doesn't allow lists that aren't in increasing order or
138126756Smlaier	 * overlapping lists.  We also handle "-3-5" although there's no
139126756Smlaier	 * real reason too.
140126756Smlaier	 */
141126756Smlaier	for (; p = strtok(list, ", \t"); list = NULL) {
142126756Smlaier		setautostart = start = stop = 0;
143126756Smlaier		if (*p == '-') {
144126756Smlaier			++p;
145126756Smlaier			setautostart = 1;
146126756Smlaier		}
147126756Smlaier		if (isdigit(*p)) {
148126756Smlaier			start = stop = strtol(p, &p, 10);
149126756Smlaier			if (setautostart && start > autostart)
150126756Smlaier				autostart = start;
151126756Smlaier		}
152126756Smlaier		if (*p == '-') {
153126756Smlaier			if (isdigit(p[1]))
154126756Smlaier				stop = strtol(p + 1, &p, 10);
155126756Smlaier			if (*p == '-') {
156126756Smlaier				++p;
157126756Smlaier				if (!autostop || autostop > stop)
158126756Smlaier					autostop = stop;
159126756Smlaier			}
160126756Smlaier		}
161126756Smlaier		if (*p)
162126756Smlaier			err("[-cf] list: illegal list value\n");
163126756Smlaier		if (!stop || !start)
164126756Smlaier			err("[-cf] list: values may not include zero\n");
165126756Smlaier		if (stop > _POSIX2_LINE_MAX)
166126756Smlaier			err("[-cf] list: %d too large (max %d)\n",
167126756Smlaier			    stop, _POSIX2_LINE_MAX);
168126756Smlaier		if (maxval < stop)
169126756Smlaier			maxval = stop;
170126756Smlaier		for (pos = positions + start; start++ <= stop; *pos++ = 1);
171126756Smlaier	}
172126756Smlaier
173126756Smlaier	/* overlapping ranges */
174126756Smlaier	if (autostop && maxval > autostop)
175126756Smlaier		maxval = autostop;
176126756Smlaier
177126756Smlaier	/* set autostart */
178126756Smlaier	if (autostart)
179126756Smlaier		memset(positions + 1, '1', autostart);
180126756Smlaier}
181126756Smlaier
182126756Smlaier/* ARGSUSED */
183126756Smlaiervoid
184126756Smlaierc_cut(fp, fname)
185126756Smlaier	FILE *fp;
186126756Smlaier	char *fname;
187126756Smlaier{
188126756Smlaier	register int ch, col;
189126756Smlaier	register char *pos;
190126756Smlaier
191126756Smlaier	for (;;) {
192126756Smlaier		pos = positions + 1;
193126756Smlaier		for (col = maxval; col; --col) {
194126756Smlaier			if ((ch = getc(fp)) == EOF)
195126756Smlaier				return;
196126756Smlaier			if (ch == '\n')
197126756Smlaier				break;
198126756Smlaier			if (*pos++)
199126756Smlaier				(void)putchar(ch);
200126756Smlaier		}
201126756Smlaier		if (ch != '\n')
202126756Smlaier			if (autostop)
203126756Smlaier				while ((ch = getc(fp)) != EOF && ch != '\n')
204126756Smlaier					(void)putchar(ch);
205126756Smlaier			else
206126756Smlaier				while ((ch = getc(fp)) != EOF && ch != '\n');
207126756Smlaier		(void)putchar('\n');
208126756Smlaier	}
209126756Smlaier}
210126756Smlaier
211126756Smlaiervoid
212126756Smlaierf_cut(fp, fname)
213126756Smlaier	FILE *fp;
214126756Smlaier	char *fname;
215126756Smlaier{
216126756Smlaier	register int ch, field, isdelim;
217126756Smlaier	register char *pos, *p, sep;
218126756Smlaier	int output;
219126756Smlaier	char lbuf[_POSIX2_LINE_MAX + 1];
220126756Smlaier
221126756Smlaier	for (sep = dchar, output = 0; fgets(lbuf, sizeof(lbuf), fp);) {
222126756Smlaier		for (isdelim = 0, p = lbuf;; ++p) {
223126756Smlaier			if (!(ch = *p))
224126756Smlaier				err("%s: line too long.\n", fname);
225126756Smlaier			/* this should work if newline is delimiter */
226126756Smlaier			if (ch == sep)
227126756Smlaier				isdelim = 1;
228126756Smlaier			if (ch == '\n') {
229126756Smlaier				if (!isdelim && !sflag)
230126756Smlaier					(void)printf("%s", lbuf);
231126756Smlaier				break;
232126756Smlaier			}
233126756Smlaier		}
234126756Smlaier		if (!isdelim)
235126756Smlaier			continue;
236126756Smlaier
237126756Smlaier		pos = positions + 1;
238126756Smlaier		for (field = maxval, p = lbuf; field; --field, ++pos) {
239126756Smlaier			if (*pos) {
240126756Smlaier				if (output++)
241126756Smlaier					(void)putchar(sep);
242126756Smlaier				while ((ch = *p++) != '\n' && ch != sep)
243126756Smlaier					(void)putchar(ch);
244126756Smlaier			} else
245126756Smlaier				while ((ch = *p++) != '\n' && ch != sep);
246126756Smlaier			if (ch == '\n')
247126756Smlaier				break;
248126756Smlaier		}
249126756Smlaier		if (ch != '\n')
250126756Smlaier			if (autostop) {
251126756Smlaier				if (output)
252126756Smlaier					(void)putchar(sep);
253126756Smlaier				for (; (ch = *p) != '\n'; ++p)
254126756Smlaier					(void)putchar(ch);
255126756Smlaier			} else
256126756Smlaier				for (; (ch = *p) != '\n'; ++p);
257126756Smlaier		(void)putchar('\n');
258126756Smlaier	}
259126756Smlaier}
260126756Smlaier
261126756Smlaiervoid
262126756Smlaierusage()
263126756Smlaier{
264126756Smlaier	(void)fprintf(stderr,
265126756Smlaier"usage:\tcut -c list [file1 ...]\n\tcut -f list [-s] [-d delim] [file ...]\n");
266126756Smlaier	exit(1);
267126756Smlaier}
268126756Smlaier
269126756Smlaier#if __STDC__
270126756Smlaier#include <stdarg.h>
271126756Smlaier#else
272126756Smlaier#include <varargs.h>
273126756Smlaier#endif
274126756Smlaier
275126756Smlaiervoid
276126756Smlaier#if __STDC__
277126756Smlaiererr(const char *fmt, ...)
278126756Smlaier#else
279126756Smlaiererr(fmt, va_alist)
280126756Smlaier	char *fmt;
281126756Smlaier        va_dcl
282126756Smlaier#endif
283126756Smlaier{
284126756Smlaier	va_list ap;
285126756Smlaier#if __STDC__
286126756Smlaier	va_start(ap, fmt);
287126756Smlaier#else
288126756Smlaier	va_start(ap);
289126756Smlaier#endif
290126756Smlaier	(void)fprintf(stderr, "cut: ");
291126756Smlaier	(void)vfprintf(stderr, fmt, ap);
292126756Smlaier	va_end(ap);
293126756Smlaier	(void)fprintf(stderr, "\n");
294126756Smlaier	exit(1);
295126756Smlaier	/* NOTREACHED */
296126756Smlaier}
297126756Smlaier