coverity appeasement - redundant check
[minix.git] / commands / cut / cut.c
blob15a76ff07507211c99a3ae95ebc2eca4e8973b7c
1 /* $NetBSD: cut.c,v 1.25 2008/07/21 14:19:22 lukem Exp $ */
3 /*
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Adam S. Moskowitz of Menlo Consulting and Marciano Pitargue.
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. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
35 #include <sys/cdefs.h>
37 #include <ctype.h>
38 #include <err.h>
39 #include <errno.h>
40 #include <limits.h>
41 #include <locale.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include <util.h>
47 #include <wchar.h>
48 #include <sys/param.h>
50 #define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
52 static int bflag;
53 static int cflag;
54 static char dchar;
55 static int dflag;
56 static int fflag;
57 static int sflag;
59 static void b_cut(FILE *, const char *);
60 #if 0
61 static void c_cut(FILE *, const char *);
62 #endif
63 static void f_cut(FILE *, const char *);
64 static void get_list(char *);
65 static void usage(void) __dead;
67 int
68 main(int argc, char *argv[])
70 FILE *fp;
71 void (*fcn)(FILE *, const char *);
72 int ch;
74 fcn = NULL;
75 (void)setlocale(LC_ALL, "");
77 dchar = '\t'; /* default delimiter is \t */
79 /* Since we don't support multi-byte characters, the -c and -b
80 options are equivalent, and the -n option is meaningless. */
81 while ((ch = getopt(argc, argv, "b:c:d:f:sn")) != -1)
82 switch(ch) {
83 case 'b':
84 case 'c':
85 fcn = b_cut;
86 get_list(optarg);
87 bflag = 1;
88 break;
89 #if 0
90 case 'c':
91 fcn = c_cut;
92 get_list(optarg);
93 cflag = 1;
94 break;
95 #endif
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();
114 argc -= optind;
115 argv += optind;
117 if (fflag) {
118 if (cflag || bflag)
119 usage();
120 } else if ((!cflag && !bflag) || dflag || sflag)
121 usage();
122 else if (bflag && cflag)
123 usage();
125 if (*argv)
126 for (; *argv; ++argv) {
127 if (strcmp(*argv, "-") == 0)
128 fcn(stdin, "stdin");
129 else {
130 if ((fp = fopen(*argv, "r")) == NULL)
131 err(1, "%s", *argv);
132 fcn(fp, *argv);
133 (void)fclose(fp);
136 else
137 fcn(stdin, "stdin");
138 return 0;
141 static size_t autostart, autostop, maxval;
143 static char *positions = NULL;
144 static size_t numpositions = 0;
145 #define ALLOC_CHUNK 4096 /* malloc granularity */
147 static void
148 get_list(char *list)
150 size_t setautostart, start, stop;
151 char *pos;
152 char *p;
154 if (positions == NULL) {
155 numpositions = ALLOC_CHUNK;
156 positions = ecalloc(numpositions, sizeof(*positions));
160 * set a byte in the positions array to indicate if a field or
161 * column is to be selected; use +1, it's 1-based, not 0-based.
162 * This parser is less restrictive than the Draft 9 POSIX spec.
163 * POSIX doesn't allow lists that aren't in increasing order or
164 * overlapping lists. We also handle "-3-5" although there's no
165 * real reason too.
167 for (; (p = strtok(list, ", \t")) != NULL; list = NULL) {
168 setautostart = start = stop = 0;
169 if (*p == '-') {
170 ++p;
171 setautostart = 1;
173 if (isdigit((unsigned char)*p)) {
174 start = stop = strtol(p, &p, 10);
175 if (setautostart && start > autostart)
176 autostart = start;
178 if (*p == '-') {
179 if (isdigit((unsigned char)p[1]))
180 stop = strtol(p + 1, &p, 10);
181 if (*p == '-') {
182 ++p;
183 if (!autostop || autostop > stop)
184 autostop = stop;
187 if (*p)
188 errx(1, "[-cf] list: illegal list value");
189 if (!stop || !start)
190 errx(1, "[-cf] list: values may not include zero");
191 if (stop + 1 > numpositions) {
192 size_t newsize;
193 newsize = roundup(stop + 1, ALLOC_CHUNK);
194 positions = erealloc(positions, newsize);
195 (void)memset(positions + numpositions, 0,
196 newsize - numpositions);
197 numpositions = newsize;
199 if (maxval < stop)
200 maxval = stop;
201 for (pos = positions + start; start++ <= stop; pos++)
202 *pos = 1;
205 /* overlapping ranges */
206 if (autostop && maxval > autostop)
207 maxval = autostop;
209 /* set autostart */
210 if (autostart)
211 (void)memset(positions + 1, '1', autostart);
214 static void
215 /*ARGSUSED*/
216 f_cut(FILE *fp, const char *fname __unused)
218 int ch, field, isdelim;
219 char *pos, *p, sep;
220 int output;
221 size_t len;
222 char *lbuf, *tbuf;
224 for (sep = dchar, tbuf = NULL; (lbuf = fgetln(fp, &len)) != NULL;) {
225 output = 0;
226 if (lbuf[len - 1] != '\n') {
227 /* no newline at the end of the last line so add one */
228 if ((tbuf = (char *)malloc(len + 1)) == NULL)
229 err(1, NULL);
230 (void)memcpy(tbuf, lbuf, len);
231 tbuf[len++] = '\n';
232 lbuf = tbuf;
234 for (isdelim = 0, p = lbuf;; ++p) {
235 ch = *p;
236 /* this should work if newline is delimiter */
237 if (ch == sep)
238 isdelim = 1;
239 if (ch == '\n') {
240 if (!isdelim && !sflag)
241 (void)fwrite(lbuf, len, 1, stdout);
242 break;
245 if (!isdelim)
246 continue;
248 pos = positions + 1;
249 for (field = maxval, p = lbuf; field; --field, ++pos) {
250 if (*pos) {
251 if (output++)
252 (void)putchar(sep);
253 while ((ch = *p++) != '\n' && ch != sep)
254 (void)putchar(ch);
255 } else {
256 while ((ch = *p++) != '\n' && ch != sep)
257 continue;
259 if (ch == '\n')
260 break;
262 if (ch != '\n') {
263 if (autostop) {
264 if (output)
265 (void)putchar(sep);
266 for (; (ch = *p) != '\n'; ++p)
267 (void)putchar(ch);
268 } else
269 for (; (ch = *p) != '\n'; ++p);
271 (void)putchar('\n');
272 if (tbuf) {
273 free(tbuf);
274 tbuf = NULL;
277 if (tbuf)
278 free(tbuf);
281 static void
282 usage(void)
284 (void)fprintf(stderr, "Usage:\tcut -b list [-n] [file ...]\n"
285 "\tcut -c list [file1 ...]\n"
286 "\tcut -f list [-d delim] [-s] [file ...]\n");
287 exit(1);
290 /* make b_put(): */
291 #define CUT_BYTE 1
292 #include "x_cut.c"
293 #undef CUT_BYTE
295 #if 0
296 /* make c_put(): */
297 #define CUT_BYTE 0
298 #include "x_cut.c"
299 #undef CUT_BYTE
300 #endif