source: trunk/minix/commands/simple/cut.c@ 15

Last change on this file since 15 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 7.5 KB
Line 
1/* cut - extract columns from a file or stdin. Author: Michael J. Holme
2 *
3 * Copyright 1989, Michael John Holme, All rights reserved.
4 * This code may be freely distributed, provided that this notice
5 * remains intact.
6 *
7 * V1.1: 6th September 1989
8 *
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 *-------------------------------------------------------------------------
22 */
23
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>
30
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 */
35
36#define MAX_ARGS 32 /* Maximum number of fields following -f or
37 * -c switches */
38int args[MAX_ARGS * 2];
39int num_args;
40
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 */
48
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
55
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
64
65
66int mode; /* 0 = dump stdin to stdout, 1=-f, 2=-c */
67int flag_i; /* SET = -i set on command line */
68int flag_s; /* SET = -s set on command line */
69char delim = '\t'; /* default delimiting character */
70FILE *fd;
71char *name;
72char line[BUFSIZ];
73int exit_status;
74
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));
80
81void warn(warn_number, option)
82int warn_number;
83char *option;
84{
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"
90 };
91
92 fprintf(stderr, warn_msg[warn_number], name, option);
93 exit_status = warn_number + 1;
94
95}
96
97void cuterror(err)
98int err;
99{
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"
108 };
109
110 fprintf(stderr, err_mes[err - 101], name);
111 exit(err);
112}
113
114
115void get_args()
116{
117 int i = 0;
118 int arg_ptr = 0;
119 int flag;
120
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);
125
126 args[arg_ptr] = 1;
127 args[arg_ptr + 1] = BUFSIZ;
128 flag = 1;
129
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 }
138 if (line[i] == '-') {
139 arg_ptr |= 1;
140 i++;
141 flag = 0;
142 }
143 }
144 if (flag && arg_ptr & 1) args[arg_ptr] = args[arg_ptr - 1];
145 if (args[num_args * 2] > args[num_args * 2 + 1])
146 cuterror(RANGE_ERROR);
147 num_args++;
148 arg_ptr = num_args * 2;
149 }
150 while (line[i++]);
151}
152
153
154void cut()
155{
156 int i, j, length, maxcol;
157 char *columns[MAX_FIELD];
158
159 while (fgets(line, BUFSIZ, fd)) {
160 length = strlen(line) - 1;
161 *(line + length) = 0;
162 switch (mode) {
163 case DUMP_STDIN: printf("%s", line); break;
164 case OPTIONF:
165 maxcol = 0;
166 columns[maxcol++] = line;
167 for (i = 0; i < length; i++) {
168 if (*(line + i) == delim) {
169 *(line + i) = 0;
170 if (maxcol == MAX_FIELD)
171 cuterror(MAX_FIELDS_EXEEDED_ERROR);
172 columns[maxcol] = line + i + 1;
173 while (*(line + i + 1) == delim && flag_i) {
174 columns[maxcol]++;
175 i++;
176 }
177 maxcol++;
178 }
179 }
180 if (maxcol == 1) {
181 if (flag_s != SET) printf("%s", line);
182 } else {
183 for (i = 0; i < num_args; i++) {
184 for (j = args[i * 2]; j <= args[i * 2 + 1]; j++)
185 if (j <= maxcol) {
186 printf("%s", columns[j - 1]);
187 if (i != num_args - 1 || j != args[i * 2 + 1])
188 putchar(delim);
189 }
190 }
191 }
192 break;
193 case OPTIONC:
194 for (i = 0; i < num_args; i++) {
195 for (j = args[i * 2]; j <= (args[i * 2 + 1] > length ? length :
196 args[i * 2 + 1]); j++)
197 putchar(*(line + j - 1));
198 }
199 }
200 if (maxcol == 1 && flag_s == SET);
201 else
202 putchar('\n');
203 }
204}
205
206
207int main(argc, argv)
208int argc;
209char *argv[];
210{
211 int i = 1;
212 int numberFilenames = 0;
213 name = argv[0];
214
215 if (argc == 1) cuterror(USAGE);
216
217 while (i < argc) {
218 if (argv[i][0] == '-') {
219 switch (argv[i++][1]) {
220 case 'd':
221 if (mode == OPTIONC || mode == OPTIONB)
222 warn(DELIMITER_NOT_APPLICABLE, "d");
223 delim = argv[i++][0];
224 break;
225 case 'f':
226 sprintf(line, "%s", argv[i++]);
227 if (mode == OPTIONC || mode == OPTIONB)
228 warn(OVERRIDING_PREVIOUS_MODE, "f");
229 mode = OPTIONF;
230 break;
231 case 'b':
232 sprintf(line, "%s", argv[i++]);
233 if (mode == OPTIONF || mode == OPTIONC)
234 warn(OVERRIDING_PREVIOUS_MODE, "b");
235 mode = OPTIONB;
236 break;
237 case 'c':
238 sprintf(line, "%s", argv[i++]);
239 if (mode == OPTIONF || mode == OPTIONB)
240 warn(OVERRIDING_PREVIOUS_MODE, "c");
241 mode = OPTIONC;
242 break;
243 case 'i': flag_i = SET; break;
244 case 's': flag_s = SET; break;
245 case '\0': /* - means: read from stdin */
246 numberFilenames++;
247 break;
248 case 'n': /* needed for Posix, but no effect here */
249 if (mode != OPTIONB)
250 warn(OPTION_NOT_APPLICABLE, "n");
251 break;
252 default:
253 warn(UNKNOWN_OPTION, &(argv[i - 1][1]));
254 }
255 } else {
256 i++;
257 numberFilenames++;
258 }
259 }
260
261/* Here follow the checks, if the selected options are reasonable. */
262 if (mode == OPTIONB) /* since in Minix char := byte */
263 mode = OPTIONC;
264/* Flag -s is only allowed with -f, otherwise warn and reset flag_s */
265 if (flag_s == SET && (mode == OPTIONB || mode == OPTIONC)) {
266 warn(OPTION_NOT_APPLICABLE, "s");
267 flag_s = NOTSET;
268 }
269
270/* Flag -i is only allowed with -f, otherwise warn and reset flag_i */
271 if (flag_i == SET && mode == OPTIONF) {
272 warn(OPTION_NOT_APPLICABLE, "s");
273 flag_i = NOTSET;
274 }
275 get_args();
276 if (numberFilenames != 0) {
277 i = 1;
278 while (i < argc) {
279 if (argv[i][0] == '-') {
280 switch (argv[i][1]) {
281 case 'f':
282 case 'c':
283 case 'b':
284 case 'd': i += 2; break;
285 case 'n':
286 case 'i':
287 case 's': i++; break;
288 case '\0':
289 fd = stdin;
290 i++;
291 cut();
292 break;
293 default: i++;
294 }
295 } else {
296 if ((fd = fopen(argv[i++], "r")) == NULL) {
297 warn(FILE_NOT_READABLE, argv[i - 1]);
298 } else {
299 cut();
300 fclose(fd);
301 }
302 }
303 }
304 } else {
305 fd = stdin;
306 cut();
307 }
308
309 return(exit_status);
310}
Note: See TracBrowser for help on using the repository browser.