mandoc: update to 1.14.5
[unleashed.git] / bin / cut / cut.c
blob9ce5a7019712feabf17c57bcf4b08d4820e3c7b3
1 /* $OpenBSD: cut.c,v 1.25 2018/07/13 08:51:14 krw Exp $ */
2 /* $NetBSD: cut.c,v 1.9 1995/09/02 05:59:23 jtc Exp $ */
4 /*
5 * Copyright (c) 1989, 1993
6 * The Regents of the University of California. All rights reserved.
8 * This code is derived from software contributed to Berkeley by
9 * Adam S. Moskowitz of Menlo Consulting and Marciano Pitargue.
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. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
36 #include <assert.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>
47 char dchar[5];
48 int dlen;
50 int bflag;
51 int cflag;
52 int dflag;
53 int fflag;
54 int nflag;
55 int sflag;
57 void b_cut(FILE *, char *);
58 void c_cut(FILE *, char *);
59 void f_cut(FILE *, char *);
60 void get_list(char *);
61 void usage(void);
63 int
64 main(int argc, char *argv[])
66 FILE *fp;
67 void (*fcn)(FILE *, char *);
68 int ch, rval;
70 setlocale(LC_CTYPE, "");
72 if (pledge("stdio rpath", NULL) == -1)
73 err(1, "pledge");
75 dchar[0] = '\t'; /* default delimiter */
76 dchar[1] = '\0';
77 dlen = 1;
79 while ((ch = getopt(argc, argv, "b:c:d:f:sn")) != -1)
80 switch(ch) {
81 case 'b':
82 get_list(optarg);
83 bflag = 1;
84 break;
85 case 'c':
86 get_list(optarg);
87 cflag = 1;
88 break;
89 case 'd':
90 if ((dlen = mblen(optarg, MB_CUR_MAX)) == -1)
91 usage();
92 assert(dlen < sizeof(dchar));
93 (void)memcpy(dchar, optarg, dlen);
94 dchar[dlen] = '\0';
95 dflag = 1;
96 break;
97 case 'f':
98 get_list(optarg);
99 fflag = 1;
100 break;
101 case 'n':
102 nflag = 1;
103 break;
104 case 's':
105 sflag = 1;
106 break;
107 case '?':
108 default:
109 usage();
111 argc -= optind;
112 argv += optind;
114 if (bflag + cflag + fflag != 1 ||
115 (nflag && !bflag) ||
116 ((dflag || sflag) && !fflag))
117 usage();
119 if (MB_CUR_MAX == 1) {
120 nflag = 0;
121 if (cflag) {
122 bflag = 1;
123 cflag = 0;
127 fcn = fflag ? f_cut : (cflag || nflag) ? c_cut : b_cut;
129 rval = 0;
130 if (*argv)
131 for (; *argv; ++argv) {
132 if (strcmp(*argv, "-") == 0)
133 fcn(stdin, "stdin");
134 else {
135 if ((fp = fopen(*argv, "r"))) {
136 fcn(fp, *argv);
137 (void)fclose(fp);
138 } else {
139 rval = 1;
140 warn("%s", *argv);
144 else {
145 if (pledge("stdio rpath", NULL) == -1)
146 err(1, "pledge");
148 fcn(stdin, "stdin");
150 exit(rval);
153 int autostart, autostop, maxval;
155 char positions[_POSIX2_LINE_MAX + 1];
158 read_number(char **p)
160 int dash, n;
161 const char *errstr;
162 char *q;
164 q = *p + strcspn(*p, "-");
165 dash = *q == '-';
166 *q = '\0';
167 n = strtonum(*p, 1, _POSIX2_LINE_MAX, &errstr);
168 if (errstr != NULL)
169 errx(1, "[-bcf] list: %s %s (allowed 1-%d)", *p, errstr,
170 _POSIX2_LINE_MAX);
171 if (dash)
172 *q = '-';
173 *p = q;
175 return n;
178 void
179 get_list(char *list)
181 int setautostart, start, stop;
182 char *p;
185 * set a byte in the positions array to indicate if a field or
186 * column is to be selected; use +1, it's 1-based, not 0-based.
187 * This parser is less restrictive than the Draft 9 POSIX spec.
188 * POSIX doesn't allow lists that aren't in increasing order or
189 * overlapping lists. We also handle "-3-5" although there's no
190 * real reason too.
192 while ((p = strsep(&list, ", \t"))) {
193 setautostart = start = stop = 0;
194 if (*p == '-') {
195 ++p;
196 setautostart = 1;
198 if (isdigit((unsigned char)*p)) {
199 start = stop = read_number(&p);
200 if (setautostart && start > autostart)
201 autostart = start;
203 if (*p == '-') {
204 if (isdigit((unsigned char)p[1])) {
205 ++p;
206 stop = read_number(&p);
208 if (*p == '-') {
209 ++p;
210 if (!autostop || autostop > stop)
211 autostop = stop;
214 if (*p != '\0' || !stop || !start)
215 errx(1, "[-bcf] list: illegal list value");
216 if (maxval < stop)
217 maxval = stop;
218 if (start <= stop)
219 memset(positions + start, 1, stop - start + 1);
222 /* overlapping ranges */
223 if (autostop && maxval > autostop)
224 maxval = autostop;
226 /* set autostart */
227 if (autostart)
228 memset(positions + 1, '1', autostart);
231 /* ARGSUSED */
232 void
233 b_cut(FILE *fp, char *fname)
235 int ch = 0;
236 int col;
237 char *pos;
239 for (;;) {
240 pos = positions + 1;
241 for (col = maxval; col; --col) {
242 if ((ch = getc(fp)) == EOF)
243 return;
244 if (ch == '\n')
245 break;
246 if (*pos++)
247 (void)putchar(ch);
249 if (ch != '\n') {
250 if (autostop)
251 while ((ch = getc(fp)) != EOF && ch != '\n')
252 (void)putchar(ch);
253 else
254 while ((ch = getc(fp)) != EOF && ch != '\n')
257 (void)putchar('\n');
261 void
262 c_cut(FILE *fp, char *fname)
264 static char *line = NULL;
265 static size_t linesz = 0;
266 ssize_t linelen;
267 char *cp, *pos, *maxpos;
268 int len;
270 while ((linelen = getline(&line, &linesz, fp)) != -1) {
271 if (line[linelen - 1] == '\n')
272 line[linelen - 1] = '\0';
274 cp = line;
275 pos = positions + 1;
276 maxpos = pos + maxval;
277 while(pos < maxpos && *cp != '\0') {
278 len = mblen(cp, MB_CUR_MAX);
279 if (len == -1)
280 len = 1;
281 pos += nflag ? len : 1;
282 if (pos[-1] == '\0')
283 cp += len;
284 else
285 while (len--)
286 putchar(*cp++);
288 if (autostop)
289 puts(cp);
290 else
291 putchar('\n');
295 void
296 f_cut(FILE *fp, char *fname)
298 static char *line = NULL;
299 static size_t linesz = 0;
300 ssize_t linelen;
301 char *sp, *ep, *pos, *maxpos;
302 int output;
304 while ((linelen = getline(&line, &linesz, fp)) != -1) {
305 if (line[linelen - 1] == '\n')
306 line[linelen - 1] = '\0';
308 if ((ep = strstr(line, dchar)) == NULL) {
309 if (!sflag)
310 puts(line);
311 continue;
314 pos = positions + 1;
315 maxpos = pos + maxval;
316 output = 0;
317 sp = line;
318 for (;;) {
319 if (*pos++) {
320 if (output)
321 fputs(dchar, stdout);
322 while (sp < ep)
323 putchar(*sp++);
324 output = 1;
325 } else
326 sp = ep;
327 if (*sp == '\0' || pos == maxpos)
328 break;
329 sp += dlen;
330 if ((ep = strstr(sp, dchar)) == NULL)
331 ep = strchr(sp, '\0');
333 if (autostop)
334 puts(sp);
335 else
336 putchar('\n');
340 void
341 usage(void)
343 (void)fprintf(stderr,
344 "usage: cut -b list [-n] [file ...]\n"
345 " cut -c list [file ...]\n"
346 " cut -f list [-s] [-d delim] [file ...]\n");
347 exit(1);