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
7 * V1.1: 6th September 1989
9 * Bugs, criticisms, etc,
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.
18 * - separation of error messages ( stderr) and output (stdout).
19 * - support for -b and -n (no effect, -b acts as -c)
21 *-------------------------------------------------------------------------
24 #include <sys/types.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
38 int args
[MAX_ARGS
* 2];
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
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 */
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
)
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;
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
);
123 if (num_args
== MAX_ARGS
) cuterror(MAX_ARGS_EXEEDED_ERROR
);
124 if (!isdigit(line
[i
]) && line
[i
] != '-') cuterror(SYNTAX_ERROR
);
127 args
[arg_ptr
+ 1] = BUFSIZ
;
130 while (line
[i
] != ',' && line
[i
] != 0) {
131 if (isdigit(line
[i
])) {
133 while (isdigit(line
[i
]))
134 args
[arg_ptr
] = 10 * args
[arg_ptr
] + line
[i
++] - '0';
135 if (!args
[arg_ptr
]) cuterror(POSITION_ERROR
);
137 } else if (line
[i
] != '-') {
138 cuterror(SYNTAX_ERROR
);
141 if (line
[i
] == '-') {
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
);
151 arg_ptr
= num_args
* 2;
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;
166 case DUMP_STDIN
: printf("%s", line
); break;
169 columns
[maxcol
++] = line
;
170 for (i
= 0; i
< length
; i
++) {
171 if (*(line
+ i
) == delim
) {
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
) {
184 if (flag_s
!= SET
) printf("%s", line
);
186 for (i
= 0; i
< num_args
; i
++) {
187 for (j
= args
[i
* 2]; j
<= args
[i
* 2 + 1]; j
++)
189 printf("%s", columns
[j
- 1]);
190 if (i
!= num_args
- 1 || j
!= args
[i
* 2 + 1])
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
);
216 int numberFilenames
= 0;
219 if (argc
== 1) cuterror(USAGE
);
222 if (argv
[i
][0] == '-') {
223 switch (argv
[i
++][1]) {
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];
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");
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");
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");
254 case 'i': flag_i
= SET
; break;
255 case 's': flag_s
= SET
; break;
256 case '\0': /* - means: read from stdin */
259 case 'n': /* needed for Posix, but no effect here */
261 warn(OPTION_NOT_APPLICABLE
, "n");
264 warn(UNKNOWN_OPTION
, &(argv
[i
- 1][1]));
272 /* Here follow the checks, if the selected options are reasonable. */
273 if (mode
== OPTIONB
) /* since in Minix char := byte */
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");
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");
287 if (numberFilenames
!= 0) {
290 if (argv
[i
][0] == '-') {
291 switch (argv
[i
][1]) {
295 case 'd': i
+= argv
[i
][2] ? 1 : 2; break;
298 case 's': i
++; break;
307 if ((fd
= fopen(argv
[i
++], "r")) == NULL
) {
308 warn(FILE_NOT_READABLE
, argv
[i
- 1]);