rev |
line source |
meillo@14
|
1 /* cut - remove parts of lines of files
|
meillo@14
|
2 Copyright (C) 1984 by David M. Ihnat
|
meillo@14
|
3
|
meillo@14
|
4 This program is a total rewrite of the Bell Laboratories Unix(Tm)
|
meillo@14
|
5 command of the same name, as of System V. It contains no proprietary
|
meillo@14
|
6 code, and therefore may be used without violation of any proprietary
|
meillo@14
|
7 agreements whatsoever. However, you will notice that the program is
|
meillo@14
|
8 copyrighted by me. This is to assure the program does *not* fall
|
meillo@14
|
9 into the public domain. Thus, I may specify just what I am now:
|
meillo@14
|
10 This program may be freely copied and distributed, provided this notice
|
meillo@14
|
11 remains; it may not be sold for profit without express written consent of
|
meillo@14
|
12 the author.
|
meillo@14
|
13 Please note that I recreated the behavior of the Unix(Tm) 'cut' command
|
meillo@14
|
14 as faithfully as possible; however, I haven't run a full set of regression
|
meillo@14
|
15 tests. Thus, the user of this program accepts full responsibility for any
|
meillo@14
|
16 effects or loss; in particular, the author is not responsible for any losses,
|
meillo@14
|
17 explicit or incidental, that may be incurred through use of this program.
|
meillo@14
|
18
|
meillo@14
|
19 I ask that any bugs (and, if possible, fixes) be reported to me when
|
meillo@14
|
20 possible. -David Ihnat (312) 784-4544 ignatz@homebru.chi.il.us
|
meillo@14
|
21
|
meillo@14
|
22 POSIX changes, bug fixes, long-named options, and cleanup
|
meillo@14
|
23 by David MacKenzie <djm@ai.mit.edu>.
|
meillo@14
|
24
|
meillo@14
|
25 Options:
|
meillo@14
|
26 --bytes=byte-list
|
meillo@14
|
27 -b byte-list Print only the bytes in positions listed
|
meillo@14
|
28 in BYTE-LIST.
|
meillo@14
|
29 Tabs and backspaces are treated like any
|
meillo@14
|
30 other character; they take up 1 byte.
|
meillo@14
|
31
|
meillo@14
|
32 --characters=character-list
|
meillo@14
|
33 -c character-list Print only characters in positions listed
|
meillo@14
|
34 in CHARACTER-LIST.
|
meillo@14
|
35 The same as -b for now, but
|
meillo@14
|
36 internationalization will change that.
|
meillo@14
|
37 Tabs and backspaces are treated like any
|
meillo@14
|
38 other character; they take up 1 character.
|
meillo@14
|
39
|
meillo@14
|
40 --fields=field-list
|
meillo@14
|
41 -f field-list Print only the fields listed in FIELD-LIST.
|
meillo@14
|
42 Fields are separated by a TAB by default.
|
meillo@14
|
43
|
meillo@14
|
44 --delimiter=delim
|
meillo@14
|
45 -d delim For -f, fields are separated by the first
|
meillo@14
|
46 character in DELIM instead of TAB.
|
meillo@14
|
47
|
meillo@14
|
48 -n Do not split multibyte chars (no-op for now).
|
meillo@14
|
49
|
meillo@14
|
50 --only-delimited
|
meillo@14
|
51 -s For -f, do not print lines that do not contain
|
meillo@14
|
52 the field separator character.
|
meillo@14
|
53
|
meillo@14
|
54 The BYTE-LIST, CHARACTER-LIST, and FIELD-LIST are one or more numbers
|
meillo@14
|
55 or ranges separated by commas. The first byte, character, and field
|
meillo@14
|
56 are numbered 1.
|
meillo@14
|
57
|
meillo@14
|
58 A FILE of `-' means standard input. */
|
meillo@14
|
59
|
meillo@14
|
60 #define _GNU_SOURCE
|
meillo@14
|
61 #include <ctype.h>
|
meillo@14
|
62 #ifndef isblank
|
meillo@14
|
63 #define isblank(c) ((c) == ' ' || (c) == '\t')
|
meillo@14
|
64 #endif
|
meillo@14
|
65 #include <stdio.h>
|
meillo@14
|
66 #include <getopt.h>
|
meillo@14
|
67 #include <sys/types.h>
|
meillo@14
|
68 #include "system.h"
|
meillo@14
|
69
|
meillo@14
|
70 #ifdef isascii
|
meillo@14
|
71 #define ISDIGIT(c) (isascii ((c)) && isdigit ((c)))
|
meillo@14
|
72 #else
|
meillo@14
|
73 #define ISDIGIT(c) (isdigit ((c)))
|
meillo@14
|
74 #endif
|
meillo@14
|
75
|
meillo@14
|
76 char *xmalloc ();
|
meillo@14
|
77 char *xrealloc ();
|
meillo@14
|
78 int set_fields ();
|
meillo@14
|
79 int cut_file ();
|
meillo@14
|
80 void cut_stream ();
|
meillo@14
|
81 void cut_bytes ();
|
meillo@14
|
82 void cut_fields ();
|
meillo@14
|
83 void enlarge_line ();
|
meillo@14
|
84 void error ();
|
meillo@14
|
85 void invalid_list ();
|
meillo@14
|
86 void usage ();
|
meillo@14
|
87
|
meillo@14
|
88 /* The number of elements allocated for the input line
|
meillo@14
|
89 and the byte or field number.
|
meillo@14
|
90 Enlarged as necessary. */
|
meillo@14
|
91 int line_size;
|
meillo@14
|
92
|
meillo@14
|
93 /* Processed output buffer. */
|
meillo@14
|
94 char *outbuf;
|
meillo@14
|
95
|
meillo@14
|
96 /* Where to save next char to output. */
|
meillo@14
|
97 char *outbufptr;
|
meillo@14
|
98
|
meillo@14
|
99 /* Raw line buffer for field mode. */
|
meillo@14
|
100 char *inbuf;
|
meillo@14
|
101
|
meillo@14
|
102 /* Where to save next input char. */
|
meillo@14
|
103 char *inbufptr;
|
meillo@14
|
104
|
meillo@14
|
105 /* What can be done about a byte or field. */
|
meillo@14
|
106 enum field_action
|
meillo@14
|
107 {
|
meillo@14
|
108 field_omit,
|
meillo@14
|
109 field_output
|
meillo@14
|
110 };
|
meillo@14
|
111
|
meillo@14
|
112 /* In byte mode, which bytes to output.
|
meillo@14
|
113 In field mode, which `delim'-separated fields to output.
|
meillo@14
|
114 Both bytes and fields are numbered starting with 1,
|
meillo@14
|
115 so the first element of `fields' is unused. */
|
meillo@14
|
116 enum field_action *fields;
|
meillo@14
|
117
|
meillo@14
|
118 enum operating_mode
|
meillo@14
|
119 {
|
meillo@14
|
120 undefined_mode,
|
meillo@14
|
121
|
meillo@14
|
122 /* Output characters that are in the given bytes. */
|
meillo@14
|
123 byte_mode,
|
meillo@14
|
124
|
meillo@14
|
125 /* Output the given delimeter-separated fields. */
|
meillo@14
|
126 field_mode
|
meillo@14
|
127 };
|
meillo@14
|
128
|
meillo@14
|
129 enum operating_mode operating_mode;
|
meillo@14
|
130
|
meillo@14
|
131 /* If nonzero,
|
meillo@14
|
132 for field mode, do not output lines containing no delimeter characters. */
|
meillo@14
|
133 int delimited_lines_only;
|
meillo@14
|
134
|
meillo@14
|
135 /* The delimeter character for field mode. */
|
meillo@14
|
136 unsigned char delim;
|
meillo@14
|
137
|
meillo@14
|
138 /* Nonzero if we have ever read standard input. */
|
meillo@14
|
139 int have_read_stdin;
|
meillo@14
|
140
|
meillo@14
|
141 /* The name this program was run with. */
|
meillo@14
|
142 char *program_name;
|
meillo@14
|
143
|
meillo@14
|
144 struct option longopts[] =
|
meillo@14
|
145 {
|
meillo@14
|
146 {"bytes", 1, 0, 'b'},
|
meillo@14
|
147 {"characters", 1, 0, 'c'},
|
meillo@14
|
148 {"fields", 1, 0, 'f'},
|
meillo@14
|
149 {"delimiter", 1, 0, 'd'},
|
meillo@14
|
150 {"only-delimited", 0, 0, 's'},
|
meillo@14
|
151 {0, 0, 0, 0}
|
meillo@14
|
152 };
|
meillo@14
|
153
|
meillo@14
|
154 void
|
meillo@14
|
155 main (argc, argv)
|
meillo@14
|
156 int argc;
|
meillo@14
|
157 char **argv;
|
meillo@14
|
158 {
|
meillo@14
|
159 int optc, exit_status = 0;
|
meillo@14
|
160
|
meillo@14
|
161 program_name = argv[0];
|
meillo@14
|
162
|
meillo@14
|
163 line_size = 512;
|
meillo@14
|
164 operating_mode = undefined_mode;
|
meillo@14
|
165 delimited_lines_only = 0;
|
meillo@14
|
166 delim = '\0';
|
meillo@14
|
167 have_read_stdin = 0;
|
meillo@14
|
168
|
meillo@14
|
169 fields = (enum field_action *)
|
meillo@14
|
170 xmalloc (line_size * sizeof (enum field_action));
|
meillo@14
|
171 outbuf = (char *) xmalloc (line_size);
|
meillo@14
|
172 inbuf = (char *) xmalloc (line_size);
|
meillo@14
|
173
|
meillo@14
|
174 for (optc = 0; optc < line_size; optc++)
|
meillo@14
|
175 fields[optc] = field_omit;
|
meillo@14
|
176
|
meillo@14
|
177 while ((optc = getopt_long (argc, argv, "b:c:d:f:ns", longopts, (int *) 0))
|
meillo@14
|
178 != EOF)
|
meillo@14
|
179 {
|
meillo@14
|
180 switch (optc)
|
meillo@14
|
181 {
|
meillo@14
|
182 case 'b':
|
meillo@14
|
183 case 'c':
|
meillo@14
|
184 /* Build the byte list. */
|
meillo@14
|
185 if (operating_mode != undefined_mode)
|
meillo@14
|
186 usage ();
|
meillo@14
|
187 operating_mode = byte_mode;
|
meillo@14
|
188 if (set_fields (optarg) == 0)
|
meillo@14
|
189 error (2, 0, "no fields given");
|
meillo@14
|
190 break;
|
meillo@14
|
191
|
meillo@14
|
192 case 'f':
|
meillo@14
|
193 /* Build the field list. */
|
meillo@14
|
194 if (operating_mode != undefined_mode)
|
meillo@14
|
195 usage ();
|
meillo@14
|
196 operating_mode = field_mode;
|
meillo@14
|
197 if (set_fields (optarg) == 0)
|
meillo@14
|
198 error (2, 0, "no fields given");
|
meillo@14
|
199 break;
|
meillo@14
|
200
|
meillo@14
|
201 case 'd':
|
meillo@14
|
202 /* New delimiter. */
|
meillo@14
|
203 if (optarg[0] == '\0')
|
meillo@14
|
204 error (2, 0, "no delimiter given");
|
meillo@14
|
205 if (optarg[1] != '\0')
|
meillo@14
|
206 error (2, 0, "delimiter must be a single character");
|
meillo@14
|
207 delim = optarg[0];
|
meillo@14
|
208 break;
|
meillo@14
|
209
|
meillo@14
|
210 case 'n':
|
meillo@14
|
211 break;
|
meillo@14
|
212
|
meillo@14
|
213 case 's':
|
meillo@14
|
214 delimited_lines_only++;
|
meillo@14
|
215 break;
|
meillo@14
|
216
|
meillo@14
|
217 default:
|
meillo@14
|
218 usage ();
|
meillo@14
|
219 }
|
meillo@14
|
220 }
|
meillo@14
|
221
|
meillo@14
|
222 if (operating_mode == undefined_mode)
|
meillo@14
|
223 usage ();
|
meillo@14
|
224
|
meillo@14
|
225 if ((delimited_lines_only || delim != '\0') && operating_mode != field_mode)
|
meillo@14
|
226 usage ();
|
meillo@14
|
227
|
meillo@14
|
228 if (delim == '\0')
|
meillo@14
|
229 delim = '\t';
|
meillo@14
|
230
|
meillo@14
|
231 if (optind == argc)
|
meillo@14
|
232 exit_status |= cut_file ("-");
|
meillo@14
|
233 else
|
meillo@14
|
234 for (; optind < argc; optind++)
|
meillo@14
|
235 exit_status |= cut_file (argv[optind]);
|
meillo@14
|
236
|
meillo@14
|
237 if (have_read_stdin && fclose (stdin) == EOF)
|
meillo@14
|
238 {
|
meillo@14
|
239 error (0, errno, "-");
|
meillo@14
|
240 exit_status = 1;
|
meillo@14
|
241 }
|
meillo@14
|
242 if (ferror (stdout) || fclose (stdout) == EOF)
|
meillo@14
|
243 error (1, 0, "write error");
|
meillo@14
|
244
|
meillo@14
|
245 exit (exit_status);
|
meillo@14
|
246 }
|
meillo@14
|
247
|
meillo@14
|
248 /* Select for printing the positions in `fields' that are listed in
|
meillo@14
|
249 byte or field specification FIELDSTR. FIELDSTR should be
|
meillo@14
|
250 composed of one or more numbers or ranges of numbers, separated by
|
meillo@14
|
251 blanks or commas. Incomplete ranges may be given: `-m' means
|
meillo@14
|
252 `1-m'; `n-' means `n' through end of line or last field.
|
meillo@14
|
253
|
meillo@14
|
254 Return the number of fields selected. */
|
meillo@14
|
255
|
meillo@14
|
256 int
|
meillo@14
|
257 set_fields (fieldstr)
|
meillo@14
|
258 char *fieldstr;
|
meillo@14
|
259 {
|
meillo@14
|
260 int initial = 1; /* Value of first number in a range. */
|
meillo@14
|
261 int dash_found = 0; /* Nonzero if a '-' is found in this field. */
|
meillo@14
|
262 int value = 0; /* If nonzero, a number being accumulated. */
|
meillo@14
|
263 int fields_selected = 0; /* Number of fields selected so far. */
|
meillo@14
|
264 /* If nonzero, index of first field in a range that goes to end of line. */
|
meillo@14
|
265 int eol_range_start = 0;
|
meillo@14
|
266
|
meillo@14
|
267 for (;;)
|
meillo@14
|
268 {
|
meillo@14
|
269 if (*fieldstr == '-')
|
meillo@14
|
270 {
|
meillo@14
|
271 /* Starting a range. */
|
meillo@14
|
272 if (dash_found)
|
meillo@14
|
273 invalid_list ();
|
meillo@14
|
274 dash_found++;
|
meillo@14
|
275 fieldstr++;
|
meillo@14
|
276
|
meillo@14
|
277 if (value)
|
meillo@14
|
278 {
|
meillo@14
|
279 if (value >= line_size)
|
meillo@14
|
280 enlarge_line (value);
|
meillo@14
|
281 initial = value;
|
meillo@14
|
282 value = 0;
|
meillo@14
|
283 }
|
meillo@14
|
284 else
|
meillo@14
|
285 initial = 1;
|
meillo@14
|
286 }
|
meillo@14
|
287 else if (*fieldstr == ',' || isblank (*fieldstr) || *fieldstr == '\0')
|
meillo@14
|
288 {
|
meillo@14
|
289 /* Ending the string, or this field/byte sublist. */
|
meillo@14
|
290 if (dash_found)
|
meillo@14
|
291 {
|
meillo@14
|
292 dash_found = 0;
|
meillo@14
|
293
|
meillo@14
|
294 /* A range. Possibilites: -n, m-n, n-.
|
meillo@14
|
295 In any case, `initial' contains the start of the range. */
|
meillo@14
|
296 if (value == 0)
|
meillo@14
|
297 {
|
meillo@14
|
298 /* `n-'. From `initial' to end of line. */
|
meillo@14
|
299 eol_range_start = initial;
|
meillo@14
|
300 fields_selected++;
|
meillo@14
|
301 }
|
meillo@14
|
302 else
|
meillo@14
|
303 {
|
meillo@14
|
304 /* `m-n' or `-n' (1-n). */
|
meillo@14
|
305 if (value < initial)
|
meillo@14
|
306 invalid_list ();
|
meillo@14
|
307
|
meillo@14
|
308 if (value >= line_size)
|
meillo@14
|
309 enlarge_line (value);
|
meillo@14
|
310
|
meillo@14
|
311 /* Is there already a range going to end of line? */
|
meillo@14
|
312 if (eol_range_start != 0)
|
meillo@14
|
313 {
|
meillo@14
|
314 /* Yes. Is the new sequence already contained
|
meillo@14
|
315 in the old one? If so, no processing is
|
meillo@14
|
316 necessary. */
|
meillo@14
|
317 if (initial < eol_range_start)
|
meillo@14
|
318 {
|
meillo@14
|
319 /* No, the new sequence starts before the
|
meillo@14
|
320 old. Does the old range going to end of line
|
meillo@14
|
321 extend into the new range? */
|
meillo@14
|
322 if (eol_range_start < value)
|
meillo@14
|
323 /* Yes. Simply move the end of line marker. */
|
meillo@14
|
324 eol_range_start = initial;
|
meillo@14
|
325 else
|
meillo@14
|
326 {
|
meillo@14
|
327 /* No. A simple range, before and disjoint from
|
meillo@14
|
328 the range going to end of line. Fill it. */
|
meillo@14
|
329 for (; initial <= value; initial++)
|
meillo@14
|
330 fields[initial] = field_output;
|
meillo@14
|
331 }
|
meillo@14
|
332
|
meillo@14
|
333 /* In any case, some fields were selected. */
|
meillo@14
|
334 fields_selected++;
|
meillo@14
|
335 }
|
meillo@14
|
336 }
|
meillo@14
|
337 else
|
meillo@14
|
338 {
|
meillo@14
|
339 /* There is no range going to end of line. */
|
meillo@14
|
340 for (; initial <= value; initial++)
|
meillo@14
|
341 fields[initial] = field_output;
|
meillo@14
|
342 fields_selected++;
|
meillo@14
|
343 }
|
meillo@14
|
344 value = 0;
|
meillo@14
|
345 }
|
meillo@14
|
346 }
|
meillo@14
|
347 else if (value != 0)
|
meillo@14
|
348 {
|
meillo@14
|
349 /* A simple field number, not a range. */
|
meillo@14
|
350 if (value >= line_size)
|
meillo@14
|
351 enlarge_line (value);
|
meillo@14
|
352
|
meillo@14
|
353 fields[value] = field_output;
|
meillo@14
|
354 value = 0;
|
meillo@14
|
355 fields_selected++;
|
meillo@14
|
356 }
|
meillo@14
|
357
|
meillo@14
|
358 if (*fieldstr == '\0')
|
meillo@14
|
359 {
|
meillo@14
|
360 /* If there was a range going to end of line, fill the
|
meillo@14
|
361 array from the end of line point. */
|
meillo@14
|
362 if (eol_range_start)
|
meillo@14
|
363 for (initial = eol_range_start; initial < line_size; initial++)
|
meillo@14
|
364 fields[initial] = field_output;
|
meillo@14
|
365
|
meillo@14
|
366 return fields_selected;
|
meillo@14
|
367 }
|
meillo@14
|
368
|
meillo@14
|
369 fieldstr++;
|
meillo@14
|
370 }
|
meillo@14
|
371 else if (ISDIGIT (*fieldstr))
|
meillo@14
|
372 {
|
meillo@14
|
373 value = 10 * value + *fieldstr - '0';
|
meillo@14
|
374 fieldstr++;
|
meillo@14
|
375 }
|
meillo@14
|
376 else
|
meillo@14
|
377 invalid_list ();
|
meillo@14
|
378 }
|
meillo@14
|
379 }
|
meillo@14
|
380
|
meillo@14
|
381 /* Process file FILE to standard output.
|
meillo@14
|
382 Return 0 if successful, 1 if not. */
|
meillo@14
|
383
|
meillo@14
|
384 int
|
meillo@14
|
385 cut_file (file)
|
meillo@14
|
386 char *file;
|
meillo@14
|
387 {
|
meillo@14
|
388 FILE *stream;
|
meillo@14
|
389
|
meillo@14
|
390 if (!strcmp (file, "-"))
|
meillo@14
|
391 {
|
meillo@14
|
392 have_read_stdin = 1;
|
meillo@14
|
393 stream = stdin;
|
meillo@14
|
394 }
|
meillo@14
|
395 else
|
meillo@14
|
396 {
|
meillo@14
|
397 stream = fopen (file, "r");
|
meillo@14
|
398 if (stream == NULL)
|
meillo@14
|
399 {
|
meillo@14
|
400 error (0, errno, "%s", file);
|
meillo@14
|
401 return 1;
|
meillo@14
|
402 }
|
meillo@14
|
403 }
|
meillo@14
|
404
|
meillo@14
|
405 cut_stream (stream);
|
meillo@14
|
406
|
meillo@14
|
407 if (ferror (stream))
|
meillo@14
|
408 {
|
meillo@14
|
409 error (0, errno, "%s", file);
|
meillo@14
|
410 return 1;
|
meillo@14
|
411 }
|
meillo@14
|
412 if (!strcmp (file, "-"))
|
meillo@14
|
413 clearerr (stream); /* Also clear EOF. */
|
meillo@14
|
414 else if (fclose (stream) == EOF)
|
meillo@14
|
415 {
|
meillo@14
|
416 error (0, errno, "%s", file);
|
meillo@14
|
417 return 1;
|
meillo@14
|
418 }
|
meillo@14
|
419 return 0;
|
meillo@14
|
420 }
|
meillo@14
|
421
|
meillo@14
|
422 void
|
meillo@14
|
423 cut_stream (stream)
|
meillo@14
|
424 FILE *stream;
|
meillo@14
|
425 {
|
meillo@14
|
426 if (operating_mode == byte_mode)
|
meillo@14
|
427 cut_bytes (stream);
|
meillo@14
|
428 else
|
meillo@14
|
429 cut_fields (stream);
|
meillo@14
|
430 }
|
meillo@14
|
431
|
meillo@14
|
432 /* Print the file open for reading on stream STREAM
|
meillo@14
|
433 with the bytes marked `field_omit' in `fields' removed from each line. */
|
meillo@14
|
434
|
meillo@14
|
435 void
|
meillo@14
|
436 cut_bytes (stream)
|
meillo@14
|
437 FILE *stream;
|
meillo@14
|
438 {
|
meillo@14
|
439 register int c; /* Each character from the file. */
|
meillo@14
|
440 int doneflag = 0; /* Nonzero if EOF reached. */
|
meillo@14
|
441 int char_count; /* Number of chars in the line so far. */
|
meillo@14
|
442
|
meillo@14
|
443 while (doneflag == 0)
|
meillo@14
|
444 {
|
meillo@14
|
445 /* Start processing a line. */
|
meillo@14
|
446 outbufptr = outbuf;
|
meillo@14
|
447 char_count = 0;
|
meillo@14
|
448
|
meillo@14
|
449 do
|
meillo@14
|
450 {
|
meillo@14
|
451 c = getc (stream);
|
meillo@14
|
452 if (c == EOF)
|
meillo@14
|
453 {
|
meillo@14
|
454 doneflag++;
|
meillo@14
|
455 break;
|
meillo@14
|
456 }
|
meillo@14
|
457
|
meillo@14
|
458 /* If this character is to be sent, stow it in the outbuffer. */
|
meillo@14
|
459
|
meillo@14
|
460 if (++char_count == line_size - 1)
|
meillo@14
|
461 enlarge_line (char_count);
|
meillo@14
|
462
|
meillo@14
|
463 if (fields[char_count] == field_output || c == '\n')
|
meillo@14
|
464 *outbufptr++ = c;
|
meillo@14
|
465 }
|
meillo@14
|
466 while (c != '\n');
|
meillo@14
|
467
|
meillo@14
|
468 if (char_count)
|
meillo@14
|
469 fwrite (outbuf, sizeof (char), outbufptr - outbuf, stdout);
|
meillo@14
|
470 }
|
meillo@14
|
471 }
|
meillo@14
|
472
|
meillo@14
|
473 /* Print the file open for reading on stream STREAM
|
meillo@14
|
474 with the fields marked `field_omit' in `fields' removed from each line.
|
meillo@14
|
475 All characters are initially stowed in the raw input buffer, until
|
meillo@14
|
476 at least one field has been found. */
|
meillo@14
|
477
|
meillo@14
|
478 void
|
meillo@14
|
479 cut_fields (stream)
|
meillo@14
|
480 FILE *stream;
|
meillo@14
|
481 {
|
meillo@14
|
482 register int c; /* Each character from the file. */
|
meillo@14
|
483 int doneflag = 0; /* Nonzero if EOF reached. */
|
meillo@14
|
484 int char_count; /* Number of chars in line before any delim. */
|
meillo@14
|
485 int fieldfound; /* Nonzero if any fields to print found. */
|
meillo@14
|
486 int curr_field; /* Current index in `fields'. */
|
meillo@14
|
487
|
meillo@14
|
488 while (doneflag == 0)
|
meillo@14
|
489 {
|
meillo@14
|
490 char_count = 0;
|
meillo@14
|
491 fieldfound = 0;
|
meillo@14
|
492 curr_field = 1;
|
meillo@14
|
493 outbufptr = outbuf;
|
meillo@14
|
494 inbufptr = inbuf;
|
meillo@14
|
495
|
meillo@14
|
496 do
|
meillo@14
|
497 {
|
meillo@14
|
498 c = getc (stream);
|
meillo@14
|
499 if (c == EOF)
|
meillo@14
|
500 {
|
meillo@14
|
501 doneflag++;
|
meillo@14
|
502 break;
|
meillo@14
|
503 }
|
meillo@14
|
504
|
meillo@14
|
505 if (fields[curr_field] == field_output && c != '\n')
|
meillo@14
|
506 {
|
meillo@14
|
507 /* Working on a field. It, and its terminating
|
meillo@14
|
508 delimiter, go only into the processed buffer. */
|
meillo@14
|
509 fieldfound = 1;
|
meillo@14
|
510 if (outbufptr - outbuf == line_size - 2)
|
meillo@14
|
511 enlarge_line (outbufptr - outbuf);
|
meillo@14
|
512 *outbufptr++ = c;
|
meillo@14
|
513 }
|
meillo@14
|
514 else if (fieldfound == 0)
|
meillo@14
|
515 {
|
meillo@14
|
516 if (++char_count == line_size - 1)
|
meillo@14
|
517 enlarge_line (char_count);
|
meillo@14
|
518 *inbufptr++ = c;
|
meillo@14
|
519 }
|
meillo@14
|
520
|
meillo@14
|
521 if (c == delim && ++curr_field == line_size - 1)
|
meillo@14
|
522 enlarge_line (curr_field);
|
meillo@14
|
523 }
|
meillo@14
|
524 while (c != '\n');
|
meillo@14
|
525
|
meillo@14
|
526 if (fieldfound)
|
meillo@14
|
527 {
|
meillo@14
|
528 /* Something was found. Print it. */
|
meillo@14
|
529 if (outbufptr[-1] == delim)
|
meillo@14
|
530 --outbufptr; /* Suppress trailing delimiter. */
|
meillo@14
|
531
|
meillo@14
|
532 fwrite (outbuf, sizeof (char), outbufptr - outbuf, stdout);
|
meillo@14
|
533 if (c == '\n')
|
meillo@14
|
534 putc (c, stdout);
|
meillo@14
|
535 }
|
meillo@14
|
536 else if (!delimited_lines_only && char_count)
|
meillo@14
|
537 /* A line with some characters, no delimiters, and no
|
meillo@14
|
538 suppression. Print it. */
|
meillo@14
|
539 fwrite (inbuf, sizeof (char), inbufptr - inbuf, stdout);
|
meillo@14
|
540 }
|
meillo@14
|
541 }
|
meillo@14
|
542
|
meillo@14
|
543 /* Extend the buffers to accomodate at least NEW_SIZE characters. */
|
meillo@14
|
544
|
meillo@14
|
545 void
|
meillo@14
|
546 enlarge_line (new_size)
|
meillo@14
|
547 int new_size;
|
meillo@14
|
548 {
|
meillo@14
|
549 char *newp;
|
meillo@14
|
550 int i;
|
meillo@14
|
551
|
meillo@14
|
552 new_size += 256; /* Leave some room to grow. */
|
meillo@14
|
553
|
meillo@14
|
554 fields = (enum field_action *)
|
meillo@14
|
555 xrealloc (fields, new_size * sizeof (enum field_action));
|
meillo@14
|
556
|
meillo@14
|
557 newp = (char *) xrealloc (outbuf, new_size);
|
meillo@14
|
558 outbufptr += newp - outbuf;
|
meillo@14
|
559 outbuf = newp;
|
meillo@14
|
560
|
meillo@14
|
561 newp = (char *) xrealloc (inbuf, new_size);
|
meillo@14
|
562 inbufptr += newp - inbuf;
|
meillo@14
|
563 inbuf = newp;
|
meillo@14
|
564
|
meillo@14
|
565 for (i = line_size; i < new_size; i++)
|
meillo@14
|
566 fields[i] = field_omit;
|
meillo@14
|
567 line_size = new_size;
|
meillo@14
|
568 }
|
meillo@14
|
569
|
meillo@14
|
570 void
|
meillo@14
|
571 invalid_list ()
|
meillo@14
|
572 {
|
meillo@14
|
573 error (2, 0, "invalid byte or field list");
|
meillo@14
|
574 }
|
meillo@14
|
575
|
meillo@14
|
576 void
|
meillo@14
|
577 usage ()
|
meillo@14
|
578 {
|
meillo@14
|
579 fprintf (stderr, "\
|
meillo@14
|
580 Usage: %s {-b byte-list,--bytes=byte-list} [-n] [file...]\n\
|
meillo@14
|
581 %s {-c character-list,--characters=character-list} [file...]\n\
|
meillo@14
|
582 %s {-f field-list,--fields=field-list} [-d delim] [-s]\n\
|
meillo@14
|
583 [--delimiter=delim] [--only-delimited] [file...]\n",
|
meillo@14
|
584 program_name, program_name, program_name);
|
meillo@14
|
585 exit (2);
|
meillo@14
|
586 }
|