packages: don't put oss on cd.
[minix.git] / commands / cut / cut.c
blobd3641cac1f18ded345750be881762c780ce5e784
1 /* cut - extract columns from a file or stdin. Author: Michael J. Holme
3 * Copyright 1989, Michael John Holme, All rights reserved.
4 * This code may be freely distributed, provided that this notice
5 * remains intact.
7 * V1.1: 6th September 1989
9 * Bugs, criticisms, etc,
10 * c/o Mark Powell
11 * JANET sq79@uk.ac.liv
12 * ARPA sq79%liv.ac.uk@nsfnet-relay.ac.uk
13 * UUCP ...!mcvax!ukc!liv.ac.uk!sq79
14 *-------------------------------------------------------------------------
15 * Changed for POSIX1003.2/Draft10 conformance
16 * Thomas Brupbacher (tobr@mw.lpc.ethz.ch), September 1990.
17 * Changes:
18 * - separation of error messages ( stderr) and output (stdout).
19 * - support for -b and -n (no effect, -b acts as -c)
20 * - support for -s
21 *-------------------------------------------------------------------------
24 #include <sys/types.h>
25 #include <ctype.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <stdlib.h>
29 #include <stdio.h>
31 #define MAX_FIELD 80 /* Pointers to the beginning of each field
32 * are stored in columns[], if a line holds
33 * more than MAX_FIELD columns the array
34 * boundary is exceed. But unlikely at 80 */
36 #define MAX_ARGS 32 /* Maximum number of fields following -f or
37 * -c switches */
38 int args[MAX_ARGS * 2];
39 int num_args;
41 /* Lots of new defines, should easen maintainance... */
42 #define DUMP_STDIN 0 /* define for mode: no options */
43 #define OPTIONF 1 /* define for mode: option -f */
44 #define OPTIONC 2 /* define for mode: option -c */
45 #define OPTIONB 3 /* define for mode: option -b */
46 #define NOTSET 0 /* option not selected */
47 #define SET 1 /* option selected */
49 /* Defines for the warnings */
50 #define DELIMITER_NOT_APPLICABLE 0
51 #define OVERRIDING_PREVIOUS_MODE 1
52 #define OPTION_NOT_APPLICABLE 2
53 #define UNKNOWN_OPTION 3
54 #define FILE_NOT_READABLE 4
56 /* Defines for the fatal errors */
57 #define SYNTAX_ERROR 101
58 #define POSITION_ERROR 102
59 #define USAGE 103
60 #define LINE_TO_LONG_ERROR 104
61 #define RANGE_ERROR 105
62 #define MAX_FIELDS_EXEEDED_ERROR 106
63 #define MAX_ARGS_EXEEDED_ERROR 107
66 int mode; /* 0 = dump stdin to stdout, 1=-f, 2=-c */
67 int flag_i; /* SET = -i set on command line */
68 int flag_s; /* SET = -s set on command line */
69 char delim = '\t'; /* default delimiting character */
70 FILE *fd;
71 char *name;
72 char line[BUFSIZ];
73 int exit_status;
75 _PROTOTYPE(int main, (int argc, char **argv));
76 _PROTOTYPE(void warn, (int warn_number, char *option));
77 _PROTOTYPE(void cuterror, (int err));
78 _PROTOTYPE(void get_args, (void));
79 _PROTOTYPE(void cut, (void));
81 void warn(warn_number, option)
82 int warn_number;
83 char *option;
85 static char *warn_msg[] = {
86 "%s: Option -d allowed only with -f\n",
87 "%s: -%s overrides earlier option\n",
88 "%s: -%s not allowed in current mode\n",
89 "%s: Cannot open %s\n"
92 fprintf(stderr, warn_msg[warn_number], name, option);
93 exit_status = warn_number + 1;
97 void cuterror(err)
98 int err;
100 static char *err_mes[] = {
101 "%s: syntax error\n",
102 "%s: position must be >0\n",
103 "%s: usage: cut [-f args [-i] [-d x]]|[-c args] [filename [...]]\n",
104 "%s: line longer than BUFSIZ\n",
105 "%s: range must not decrease from left to right\n",
106 "%s: MAX_FIELD exceeded\n",
107 "%s: MAX_ARGS exceeded\n"
110 fprintf(stderr, err_mes[err - 101], name);
111 exit(err);
115 void get_args()
117 int i = 0;
118 int arg_ptr = 0;
119 int flag;
121 num_args = 0;
122 do {
123 if (num_args == MAX_ARGS) cuterror(MAX_ARGS_EXEEDED_ERROR);
124 if (!isdigit(line[i]) && line[i] != '-') cuterror(SYNTAX_ERROR);
126 args[arg_ptr] = 1;
127 args[arg_ptr + 1] = BUFSIZ;
128 flag = 1;
130 while (line[i] != ',' && line[i] != 0) {
131 if (isdigit(line[i])) {
132 args[arg_ptr] = 0;
133 while (isdigit(line[i]))
134 args[arg_ptr] = 10 * args[arg_ptr] + line[i++] - '0';
135 if (!args[arg_ptr]) cuterror(POSITION_ERROR);
136 arg_ptr++;
137 } else if (line[i] != '-') {
138 cuterror(SYNTAX_ERROR);
141 if (line[i] == '-') {
142 arg_ptr |= 1;
143 i++;
144 flag = 0;
147 if (flag && arg_ptr & 1) args[arg_ptr] = args[arg_ptr - 1];
148 if (args[num_args * 2] > args[num_args * 2 + 1])
149 cuterror(RANGE_ERROR);
150 num_args++;
151 arg_ptr = num_args * 2;
153 while (line[i++]);
157 void cut()
159 int i, j, length, maxcol;
160 char *columns[MAX_FIELD];
162 while (fgets(line, BUFSIZ, fd)) {
163 length = strlen(line) - 1;
164 *(line + length) = 0;
165 switch (mode) {
166 case DUMP_STDIN: printf("%s", line); break;
167 case OPTIONF:
168 maxcol = 0;
169 columns[maxcol++] = line;
170 for (i = 0; i < length; i++) {
171 if (*(line + i) == delim) {
172 *(line + i) = 0;
173 if (maxcol == MAX_FIELD)
174 cuterror(MAX_FIELDS_EXEEDED_ERROR);
175 columns[maxcol] = line + i + 1;
176 while (*(line + i + 1) == delim && flag_i) {
177 columns[maxcol]++;
178 i++;
180 maxcol++;
183 if (maxcol == 1) {
184 if (flag_s != SET) printf("%s", line);
185 } else {
186 for (i = 0; i < num_args; i++) {
187 for (j = args[i * 2]; j <= args[i * 2 + 1]; j++)
188 if (j <= maxcol) {
189 printf("%s", columns[j - 1]);
190 if (i != num_args - 1 || j != args[i * 2 + 1])
191 putchar(delim);
195 break;
196 case OPTIONC:
197 for (i = 0; i < num_args; i++) {
198 for (j = args[i * 2]; j <= (args[i * 2 + 1] > length ? length :
199 args[i * 2 + 1]); j++)
200 putchar(*(line + j - 1));
203 if (maxcol == 1 && flag_s == SET);
204 else
205 putchar('\n');
210 int main(argc, argv)
211 int argc;
212 char *argv[];
214 char *linearg;
215 int i = 1;
216 int numberFilenames = 0;
217 name = argv[0];
219 if (argc == 1) cuterror(USAGE);
221 while (i < argc) {
222 if (argv[i][0] == '-') {
223 switch (argv[i++][1]) {
224 case 'd':
225 if (mode == OPTIONC || mode == OPTIONB)
226 warn(DELIMITER_NOT_APPLICABLE, "d");
227 delim = argv[i - 1][2] ?
228 argv[i - 1][2] : argv[i++][0];
229 break;
230 case 'f':
231 linearg = argv[i - 1][2] ?
232 (argv[i - 1] + 2) : argv[i++];
233 sprintf(line, "%s", linearg);
234 if (mode == OPTIONC || mode == OPTIONB)
235 warn(OVERRIDING_PREVIOUS_MODE, "f");
236 mode = OPTIONF;
237 break;
238 case 'b':
239 linearg = argv[i - 1][2] ?
240 (argv[i - 1] + 2) : argv[i++];
241 sprintf(line, "%s", linearg);
242 if (mode == OPTIONF || mode == OPTIONC)
243 warn(OVERRIDING_PREVIOUS_MODE, "b");
244 mode = OPTIONB;
245 break;
246 case 'c':
247 linearg = argv[i - 1][2] ?
248 (argv[i - 1] + 2) : argv[i++];
249 sprintf(line, "%s", linearg);
250 if (mode == OPTIONF || mode == OPTIONB)
251 warn(OVERRIDING_PREVIOUS_MODE, "c");
252 mode = OPTIONC;
253 break;
254 case 'i': flag_i = SET; break;
255 case 's': flag_s = SET; break;
256 case '\0': /* - means: read from stdin */
257 numberFilenames++;
258 break;
259 case 'n': /* needed for Posix, but no effect here */
260 if (mode != OPTIONB)
261 warn(OPTION_NOT_APPLICABLE, "n");
262 break;
263 default:
264 warn(UNKNOWN_OPTION, &(argv[i - 1][1]));
266 } else {
267 i++;
268 numberFilenames++;
272 /* Here follow the checks, if the selected options are reasonable. */
273 if (mode == OPTIONB) /* since in Minix char := byte */
274 mode = OPTIONC;
275 /* Flag -s is only allowed with -f, otherwise warn and reset flag_s */
276 if (flag_s == SET && (mode == OPTIONB || mode == OPTIONC)) {
277 warn(OPTION_NOT_APPLICABLE, "s");
278 flag_s = NOTSET;
281 /* Flag -i is only allowed with -f, otherwise warn and reset flag_i */
282 if (flag_i == SET && mode == OPTIONF) {
283 warn(OPTION_NOT_APPLICABLE, "s");
284 flag_i = NOTSET;
286 get_args();
287 if (numberFilenames != 0) {
288 i = 1;
289 while (i < argc) {
290 if (argv[i][0] == '-') {
291 switch (argv[i][1]) {
292 case 'f':
293 case 'c':
294 case 'b':
295 case 'd': i += argv[i][2] ? 1 : 2; break;
296 case 'n':
297 case 'i':
298 case 's': i++; break;
299 case '\0':
300 fd = stdin;
301 i++;
302 cut();
303 break;
304 default: i++;
306 } else {
307 if ((fd = fopen(argv[i++], "r")) == NULL) {
308 warn(FILE_NOT_READABLE, argv[i - 1]);
309 } else {
310 cut();
311 fclose(fd);
315 } else {
316 fd = stdin;
317 cut();
320 return(exit_status);