7346beeb29b8d188ded85055974ab6a1ab2d0717
[platform/upstream/coreutils.git] / src / cut.c
1 /* cut - remove parts of lines of files
2    Copyright (C) 1984, 1997, 1998, 1999, 2000 by David M. Ihnat
3
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software Foundation,
16    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18 /* Written by David Ihnat.  */
19
20 /* POSIX changes, bug fixes, long-named options, and cleanup
21    by David MacKenzie <djm@gnu.ai.mit.edu>.
22
23    Rewrite cut_fields and cut_bytes -- Jim Meyering.  */
24
25 #include <config.h>
26
27 #include <stdio.h>
28 #include <assert.h>
29 #include <getopt.h>
30 #include <sys/types.h>
31 #include "system.h"
32 #include "getstr.h"
33 #include "closeout.h"
34 #include "error.h"
35
36 /* The official name of this program (e.g., no `g' prefix).  */
37 #define PROGRAM_NAME "cut"
38
39 #define AUTHORS N_ ("David Ihnat, David MacKenzie, and Jim Meyering")
40
41 #define FATAL_ERROR(Message)                                            \
42   do                                                                    \
43     {                                                                   \
44       error (0, 0, (Message));                                          \
45       usage (2);                                                        \
46     }                                                                   \
47   while (0)
48
49 /* Append LOW, HIGH to the list RP of range pairs, allocating additional
50    space if necessary.  Update local variable N_RP.  When allocating,
51    update global variable N_RP_ALLOCATED.  */
52
53 #define ADD_RANGE_PAIR(rp, low, high)                                   \
54   do                                                                    \
55     {                                                                   \
56       if (n_rp >= n_rp_allocated)                                       \
57         {                                                               \
58           n_rp_allocated *= 2;                                          \
59           (rp) = (struct range_pair *) xrealloc ((char *) (rp),         \
60                                    n_rp_allocated * sizeof (*(rp)));    \
61         }                                                               \
62       rp[n_rp].lo = (low);                                              \
63       rp[n_rp].hi = (high);                                             \
64       ++n_rp;                                                           \
65     }                                                                   \
66   while (0)
67
68 struct range_pair
69   {
70     unsigned int lo;
71     unsigned int hi;
72   };
73
74 /* This buffer is used to support the semantics of the -s option
75    (or lack of same) when the specified field list includes (does
76    not include) the first field.  In both of those cases, the entire
77    first field must be read into this buffer to determine whether it
78    is followed by a delimiter or a newline before any of it may be
79    output.  Otherwise, cut_fields can do the job without using this
80    buffer.  */
81 static char *field_1_buffer;
82
83 /* The number of bytes allocated for FIELD_1_BUFFER.  */
84 static size_t field_1_bufsize;
85
86 /* The largest field or byte index used as an endpoint of a closed
87    or degenerate range specification;  this doesn't include the starting
88    index of right-open-ended ranges.  For example, with either range spec
89    `2-5,9-', `2-3,5,9-' this variable would be set to 5.  */
90 static unsigned int max_range_endpoint;
91
92 /* If nonzero, this is the index of the first field in a range that goes
93    to end of line. */
94 static unsigned int eol_range_start;
95
96 /* In byte mode, which bytes to output.
97    In field mode, which DELIM-separated fields to output.
98    Both bytes and fields are numbered starting with 1,
99    so the zeroth element of this array is unused.
100    A field or byte K has been selected if
101    (K <= MAX_RANGE_ENDPOINT and PRINTABLE_FIELD[K])
102     || (EOL_RANGE_START > 0 && K >= EOL_RANGE_START).  */
103 static int *printable_field;
104
105 enum operating_mode
106   {
107     undefined_mode,
108
109     /* Output characters that are in the given bytes. */
110     byte_mode,
111
112     /* Output the given delimeter-separated fields. */
113     field_mode
114   };
115
116 /* The name this program was run with. */
117 char *program_name;
118
119 static enum operating_mode operating_mode;
120
121 /* If nonzero do not output lines containing no delimeter characters.
122    Otherwise, all such lines are printed.  This option is valid only
123    with field mode.  */
124 static int suppress_non_delimited;
125
126 /* The delimeter character for field mode. */
127 static int delim;
128
129 /* The length of output_delimiter_string.  */
130 static size_t output_delimiter_length;
131
132 /* The output field separator string.  Defaults to the 1-character
133    string consisting of the input delimiter.  */
134 static char *output_delimiter_string;
135
136 /* Nonzero if we have ever read standard input. */
137 static int have_read_stdin;
138
139 /* For long options that have no equivalent short option, use a
140    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
141 enum
142 {
143   OUTPUT_DELIMITER_OPTION = CHAR_MAX + 1
144 };
145
146 static struct option const longopts[] =
147 {
148   {"bytes", required_argument, 0, 'b'},
149   {"characters", required_argument, 0, 'c'},
150   {"fields", required_argument, 0, 'f'},
151   {"delimiter", required_argument, 0, 'd'},
152   {"only-delimited", no_argument, 0, 's'},
153   {"output-delimiter", required_argument, 0, OUTPUT_DELIMITER_OPTION},
154   {GETOPT_HELP_OPTION_DECL},
155   {GETOPT_VERSION_OPTION_DECL},
156   {0, 0, 0, 0}
157 };
158
159 void
160 usage (int status)
161 {
162   if (status != 0)
163     fprintf (stderr, _("Try `%s --help' for more information.\n"),
164              program_name);
165   else
166     {
167       printf (_("\
168 Usage: %s [OPTION]... [FILE]...\n\
169 "),
170               program_name);
171       printf (_("\
172 Print selected parts of lines from each FILE to standard output.\n\
173 \n\
174   -b, --bytes=LIST        output only these bytes\n\
175   -c, --characters=LIST   output only these characters\n\
176   -d, --delimiter=DELIM   use DELIM instead of TAB for field delimiter\n\
177   -f, --fields=LIST       output only these fields;  also print any line\n\
178                             that contains no delimiter character, unless\n\
179                             the -s option is specified\n\
180   -n                      (ignored)\n\
181   -s, --only-delimited    do not print lines not containing delimiters\n\
182       --output-delimiter=STRING  use STRING as the output delimiter\n\
183                             the default is to use the input delimiter\n\
184       --help              display this help and exit\n\
185       --version           output version information and exit\n\
186 \n\
187 Use one, and only one of -b, -c or -f.  Each LIST is made up of one\n\
188 range, or many ranges separated by commas.  Each range is one of:\n\
189 \n\
190   N     N'th byte, character or field, counted from 1\n\
191   N-    from N'th byte, character or field, to end of line\n\
192   N-M   from N'th to M'th (included) byte, character or field\n\
193   -M    from first to M'th (included) byte, character or field\n\
194 \n\
195 With no FILE, or when FILE is -, read standard input.\n\
196 "));
197       puts (_("\nReport bugs to <bug-textutils@gnu.org>."));
198     }
199   exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
200 }
201
202 static int
203 print_kth (unsigned int k)
204 {
205   return ((0 < eol_range_start && eol_range_start <= k)
206           || (k <= max_range_endpoint && printable_field[k]));
207 }
208
209 /* Given the list of field or byte range specifications FIELDSTR, set
210    MAX_RANGE_ENDPOINT and allocate and initialize the PRINTABLE_FIELD
211    array.  If there is a right-open-ended range, set EOL_RANGE_START
212    to its starting index.  FIELDSTR should be composed of one or more
213    numbers or ranges of numbers, separated by blanks or commas.
214    Incomplete ranges may be given: `-m' means `1-m'; `n-' means `n'
215    through end of line.  Return nonzero if FIELDSTR contains at least
216    one field specification, zero otherwise.  */
217
218 /* FIXME-someday:  What if the user wants to cut out the 1,000,000-th field
219    of some huge input file?  This function shouldn't have to alloate a table
220    of a million ints just so we can test every field < 10^6 with an array
221    dereference.  Instead, consider using a dynamic hash table.  It would be
222    simpler and nearly as good a solution to use a 32K x 4-byte table with
223    one bit per field index instead of a whole `int' per index.  */
224
225 static int
226 set_fields (const char *fieldstr)
227 {
228   unsigned int initial = 1;     /* Value of first number in a range.  */
229   unsigned int value = 0;       /* If nonzero, a number being accumulated.  */
230   int dash_found = 0;           /* Nonzero if a '-' is found in this field.  */
231   int field_found = 0;          /* Non-zero if at least one field spec
232                                    has been processed.  */
233
234   struct range_pair *rp;
235   unsigned int n_rp;
236   unsigned int n_rp_allocated;
237   unsigned int i;
238
239   n_rp = 0;
240   n_rp_allocated = 16;
241   rp = (struct range_pair *) xmalloc (n_rp_allocated * sizeof (*rp));
242
243   /* Collect and store in RP the range end points.
244      It also sets EOL_RANGE_START if appropriate.  */
245
246   for (;;)
247     {
248       if (*fieldstr == '-')
249         {
250           /* Starting a range. */
251           if (dash_found)
252             FATAL_ERROR (_("invalid byte or field list"));
253           dash_found++;
254           fieldstr++;
255
256           if (value)
257             {
258               initial = value;
259               value = 0;
260             }
261           else
262             initial = 1;
263         }
264       else if (*fieldstr == ',' || ISBLANK (*fieldstr) || *fieldstr == '\0')
265         {
266           /* Ending the string, or this field/byte sublist. */
267           if (dash_found)
268             {
269               dash_found = 0;
270
271               /* A range.  Possibilites: -n, m-n, n-.
272                  In any case, `initial' contains the start of the range. */
273               if (value == 0)
274                 {
275                   /* `n-'.  From `initial' to end of line. */
276                   eol_range_start = initial;
277                   field_found = 1;
278                 }
279               else
280                 {
281                   /* `m-n' or `-n' (1-n). */
282                   if (value < initial)
283                     FATAL_ERROR (_("invalid byte or field list"));
284
285                   /* Is there already a range going to end of line? */
286                   if (eol_range_start != 0)
287                     {
288                       /* Yes.  Is the new sequence already contained
289                          in the old one?  If so, no processing is
290                          necessary. */
291                       if (initial < eol_range_start)
292                         {
293                           /* No, the new sequence starts before the
294                              old.  Does the old range going to end of line
295                              extend into the new range?  */
296                           if (value + 1 >= eol_range_start)
297                             {
298                               /* Yes.  Simply move the end of line marker. */
299                               eol_range_start = initial;
300                             }
301                           else
302                             {
303                               /* No.  A simple range, before and disjoint from
304                                  the range going to end of line.  Fill it. */
305                               ADD_RANGE_PAIR (rp, initial, value);
306                             }
307
308                           /* In any case, some fields were selected. */
309                           field_found = 1;
310                         }
311                     }
312                   else
313                     {
314                       /* There is no range going to end of line. */
315                       ADD_RANGE_PAIR (rp, initial, value);
316                       field_found = 1;
317                     }
318                   value = 0;
319                 }
320             }
321           else if (value != 0)
322             {
323               /* A simple field number, not a range. */
324               ADD_RANGE_PAIR (rp, value, value);
325               value = 0;
326               field_found = 1;
327             }
328
329           if (*fieldstr == '\0')
330             {
331               break;
332             }
333
334           fieldstr++;
335         }
336       else if (ISDIGIT (*fieldstr))
337         {
338           /* FIXME: detect overflow?  */
339           value = 10 * value + *fieldstr - '0';
340           fieldstr++;
341         }
342       else
343         FATAL_ERROR (_("invalid byte or field list"));
344     }
345
346   max_range_endpoint = 0;
347   for (i = 0; i < n_rp; i++)
348     {
349       if (rp[i].hi > max_range_endpoint)
350         max_range_endpoint = rp[i].hi;
351     }
352
353   /* Allocate an array large enough so that it may be indexed by
354      the field numbers corresponding to all finite ranges
355      (i.e. `2-6' or `-4', but not `5-') in FIELDSTR.  */
356
357   printable_field = (int *) xmalloc ((max_range_endpoint + 1) * sizeof (int));
358   memset (printable_field, 0, (max_range_endpoint + 1) * sizeof (int));
359
360   /* Set the array entries corresponding to integers in the ranges of RP.  */
361   for (i = 0; i < n_rp; i++)
362     {
363       unsigned int j;
364       for (j = rp[i].lo; j <= rp[i].hi; j++)
365         {
366           printable_field[j] = 1;
367         }
368     }
369
370   free (rp);
371
372   return field_found;
373 }
374
375 /* Read from stream STREAM, printing to standard output any selected bytes.  */
376
377 static void
378 cut_bytes (FILE *stream)
379 {
380   unsigned int byte_idx;        /* Number of chars in the line so far. */
381
382   byte_idx = 0;
383   while (1)
384     {
385       register int c;           /* Each character from the file. */
386
387       c = getc (stream);
388
389       if (c == '\n')
390         {
391           putchar ('\n');
392           byte_idx = 0;
393         }
394       else if (c == EOF)
395         {
396           if (byte_idx > 0)
397             putchar ('\n');
398           break;
399         }
400       else
401         {
402           ++byte_idx;
403           if (print_kth (byte_idx))
404             {
405               putchar (c);
406             }
407         }
408     }
409 }
410
411 /* Read from stream STREAM, printing to standard output any selected fields.  */
412
413 static void
414 cut_fields (FILE *stream)
415 {
416   int c;
417   unsigned int field_idx;
418   int found_any_selected_field;
419   int buffer_first_field;
420   int empty_input;
421
422   found_any_selected_field = 0;
423   field_idx = 1;
424
425   c = getc (stream);
426   empty_input = (c == EOF);
427   if (c != EOF)
428     ungetc (c, stream);
429
430   /* To support the semantics of the -s flag, we may have to buffer
431      all of the first field to determine whether it is `delimited.'
432      But that is unnecessary if all non-delimited lines must be printed
433      and the first field has been selected, or if non-delimited lines
434      must be suppressed and the first field has *not* been selected.
435      That is because a non-delimited line has exactly one field.  */
436   buffer_first_field = (suppress_non_delimited ^ !print_kth (1));
437
438   while (1)
439     {
440       if (field_idx == 1 && buffer_first_field)
441         {
442           int len;
443
444           len = getstr (&field_1_buffer, &field_1_bufsize, stream,
445                         delim, '\n', 0);
446           if (len < 0)
447             {
448               if (ferror (stream) || feof (stream))
449                 break;
450               xalloc_die ();
451             }
452
453           assert (len != 0);
454
455           /* If the first field extends to the end of line (it is not
456              delimited) and we are printing all non-delimited lines,
457              print this one.  */
458           if ((unsigned char) field_1_buffer[len - 1] != delim)
459             {
460               if (suppress_non_delimited)
461                 {
462                   /* Empty.  */
463                 }
464               else
465                 {
466                   fwrite (field_1_buffer, sizeof (char), len, stdout);
467                   /* Make sure the output line is newline terminated.  */
468                   if (field_1_buffer[len - 1] != '\n')
469                     putchar ('\n');
470                 }
471               continue;
472             }
473           if (print_kth (1))
474             {
475               /* Print the field, but not the trailing delimiter.  */
476               fwrite (field_1_buffer, sizeof (char), len - 1, stdout);
477               found_any_selected_field = 1;
478             }
479           ++field_idx;
480         }
481
482       if (c != EOF)
483         {
484           if (print_kth (field_idx))
485             {
486               if (found_any_selected_field)
487                 {
488                   fwrite (output_delimiter_string, sizeof (char),
489                           output_delimiter_length, stdout);
490                 }
491               found_any_selected_field = 1;
492
493               while ((c = getc (stream)) != delim && c != '\n' && c != EOF)
494                 {
495                   putchar (c);
496                 }
497             }
498           else
499             {
500               while ((c = getc (stream)) != delim && c != '\n' && c != EOF)
501                 {
502                   /* Empty.  */
503                 }
504             }
505         }
506
507       if (c == '\n')
508         {
509           c = getc (stream);
510           if (c != EOF)
511             {
512               ungetc (c, stream);
513               c = '\n';
514             }
515         }
516
517       if (c == delim)
518         ++field_idx;
519       else if (c == '\n' || c == EOF)
520         {
521           if (found_any_selected_field
522               || (!empty_input && !(suppress_non_delimited && field_idx == 1)))
523             putchar ('\n');
524           if (c == EOF)
525             break;
526           field_idx = 1;
527           found_any_selected_field = 0;
528         }
529     }
530 }
531
532 static void
533 cut_stream (FILE *stream)
534 {
535   if (operating_mode == byte_mode)
536     cut_bytes (stream);
537   else
538     cut_fields (stream);
539 }
540
541 /* Process file FILE to standard output.
542    Return 0 if successful, 1 if not. */
543
544 static int
545 cut_file (char *file)
546 {
547   FILE *stream;
548
549   if (STREQ (file, "-"))
550     {
551       have_read_stdin = 1;
552       stream = stdin;
553     }
554   else
555     {
556       stream = fopen (file, "r");
557       if (stream == NULL)
558         {
559           error (0, errno, "%s", file);
560           return 1;
561         }
562     }
563
564   cut_stream (stream);
565
566   if (ferror (stream))
567     {
568       error (0, errno, "%s", file);
569       return 1;
570     }
571   if (STREQ (file, "-"))
572     clearerr (stream);          /* Also clear EOF. */
573   else if (fclose (stream) == EOF)
574     {
575       error (0, errno, "%s", file);
576       return 1;
577     }
578   return 0;
579 }
580
581 int
582 main (int argc, char **argv)
583 {
584   int optc, exit_status = 0;
585   int delim_specified = 0;
586
587   program_name = argv[0];
588   setlocale (LC_ALL, "");
589   bindtextdomain (PACKAGE, LOCALEDIR);
590   textdomain (PACKAGE);
591
592   atexit (close_stdout);
593
594   operating_mode = undefined_mode;
595
596   /* By default, all non-delimited lines are printed.  */
597   suppress_non_delimited = 0;
598
599   delim = '\0';
600   have_read_stdin = 0;
601
602   while ((optc = getopt_long (argc, argv, "b:c:d:f:ns", longopts, NULL)) != -1)
603     {
604       switch (optc)
605         {
606         case 0:
607           break;
608
609         case 'b':
610         case 'c':
611           /* Build the byte list. */
612           if (operating_mode != undefined_mode)
613             FATAL_ERROR (_("only one type of list may be specified"));
614           operating_mode = byte_mode;
615           if (set_fields (optarg) == 0)
616             FATAL_ERROR (_("missing list of positions"));
617           break;
618
619         case 'f':
620           /* Build the field list. */
621           if (operating_mode != undefined_mode)
622             FATAL_ERROR (_("only one type of list may be specified"));
623           operating_mode = field_mode;
624           if (set_fields (optarg) == 0)
625             FATAL_ERROR (_("missing list of fields"));
626           break;
627
628         case 'd':
629           /* New delimiter. */
630           /* Interpret -d '' to mean `use the NUL byte as the delimiter.'  */
631           if (optarg[0] != '\0' && optarg[1] != '\0')
632             FATAL_ERROR (_("the delimiter must be a single character"));
633           delim = (unsigned char) optarg[0];
634           delim_specified = 1;
635           break;
636
637         case OUTPUT_DELIMITER_OPTION:
638           /* Interpret --output-delimiter='' to mean
639              `use the NUL byte as the delimiter.'  */
640           output_delimiter_length = (optarg[0] == '\0'
641                                      ? 1 : strlen (optarg));
642           output_delimiter_string = xstrdup (optarg);
643           break;
644
645         case 'n':
646           break;
647
648         case 's':
649           suppress_non_delimited = 1;
650           break;
651
652         case_GETOPT_HELP_CHAR;
653
654         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
655
656         default:
657           usage (2);
658         }
659     }
660
661   if (operating_mode == undefined_mode)
662     FATAL_ERROR (_("you must specify a list of bytes, characters, or fields"));
663
664   if (delim != '\0' && operating_mode != field_mode)
665     FATAL_ERROR (_("a delimiter may be specified only when operating on fields"));
666
667   if (suppress_non_delimited && operating_mode != field_mode)
668     FATAL_ERROR (_("suppressing non-delimited lines makes sense\n\
669 \tonly when operating on fields"));
670
671   if (!delim_specified)
672     delim = '\t';
673
674   if (output_delimiter_string == NULL)
675     {
676       static char dummy[2];
677       dummy[0] = delim;
678       dummy[1] = '\0';
679       output_delimiter_string = dummy;
680       output_delimiter_length = 1;
681     }
682
683   if (optind == argc)
684     exit_status |= cut_file ("-");
685   else
686     for (; optind < argc; optind++)
687       exit_status |= cut_file (argv[optind]);
688
689   if (have_read_stdin && fclose (stdin) == EOF)
690     {
691       error (0, errno, "-");
692       exit_status = 1;
693     }
694
695   exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
696 }