diff options
Diffstat (limited to 'src/cut.c')
-rw-r--r-- | src/cut.c | 104 |
1 files changed, 55 insertions, 49 deletions
@@ -1,5 +1,5 @@ /* cut - remove parts of lines of files - Copyright (C) 1997-2012 Free Software Foundation, Inc. + Copyright (C) 1997-2013 Free Software Foundation, Inc. Copyright (C) 1984 David M. Ihnat This program is free software: you can redistribute it and/or modify @@ -192,11 +192,10 @@ Usage: %s OPTION... [FILE]...\n\ program_name); fputs (_("\ Print selected parts of lines from each FILE to standard output.\n\ -\n\ -"), stdout); - fputs (_("\ -Mandatory arguments to long options are mandatory for short options too.\n\ "), stdout); + + emit_mandatory_arg_note (); + fputs (_("\ -b, --bytes=LIST select only these bytes\n\ -c, --characters=LIST select only these characters\n\ @@ -365,10 +364,13 @@ set_fields (const char *fieldstr) in_digits = false; /* Starting a range. */ if (dash_found) - FATAL_ERROR (_("invalid byte or field list")); + FATAL_ERROR (_("invalid byte, character or field list")); dash_found = true; fieldstr++; + if (lhs_specified && !value) + FATAL_ERROR (_("fields and positions are numbered from 1")); + initial = (lhs_specified ? value : 1); value = 0; } @@ -388,8 +390,10 @@ set_fields (const char *fieldstr) In any case, 'initial' contains the start of the range. */ if (!rhs_specified) { - /* 'n-'. From 'initial' to end of line. */ - eol_range_start = initial; + /* 'n-'. From 'initial' to end of line. If we've already + seen an M- range, ignore subsequent N- unless N < M. */ + if (eol_range_start == 0 || initial < eol_range_start) + eol_range_start = initial; field_found = true; } else @@ -486,7 +490,7 @@ set_fields (const char *fieldstr) fieldstr++; } else - FATAL_ERROR (_("invalid byte or field list")); + FATAL_ERROR (_("invalid byte, character or field list")); } max_range_endpoint = 0; @@ -495,37 +499,40 @@ set_fields (const char *fieldstr) if (rp[i].hi > max_range_endpoint) max_range_endpoint = rp[i].hi; } - if (max_range_endpoint < eol_range_start) - max_range_endpoint = eol_range_start; /* Allocate an array large enough so that it may be indexed by the field numbers corresponding to all finite ranges (i.e. '2-6' or '-4', but not '5-') in FIELDSTR. */ - printable_field = xzalloc (max_range_endpoint / CHAR_BIT + 1); + if (max_range_endpoint) + printable_field = xzalloc (max_range_endpoint / CHAR_BIT + 1); qsort (rp, n_rp, sizeof (rp[0]), compare_ranges); /* Set the array entries corresponding to integers in the ranges of RP. */ for (i = 0; i < n_rp; i++) { - size_t j; - size_t rsi_candidate; + /* Ignore any range that is subsumed by the to-EOL range. */ + if (eol_range_start && eol_range_start <= rp[i].lo) + continue; /* Record the range-start indices, i.e., record each start index that is not part of any other (lo..hi] range. */ - rsi_candidate = complement ? rp[i].hi + 1 : rp[i].lo; + size_t rsi_candidate = complement ? rp[i].hi + 1 : rp[i].lo; if (output_delimiter_specified && !is_printable_field (rsi_candidate)) mark_range_start (rsi_candidate); - for (j = rp[i].lo; j <= rp[i].hi; j++) + for (size_t j = rp[i].lo; j <= rp[i].hi; j++) mark_printable_field (j); } if (output_delimiter_specified && !complement - && eol_range_start && !is_printable_field (eol_range_start)) + && eol_range_start + && max_range_endpoint + && (max_range_endpoint < eol_range_start + || !is_printable_field (eol_range_start))) mark_range_start (eol_range_start); free (rp); @@ -596,6 +603,7 @@ cut_fields (FILE *stream) return; ungetc (c, stream); + c = 0; /* To support the semantics of the -s flag, we may have to buffer all of the first field to determine whether it is 'delimited.' @@ -611,6 +619,7 @@ cut_fields (FILE *stream) { ssize_t len; size_t n_bytes; + bool got_line; len = getndelim2 (&field_1_buffer, &field_1_bufsize, 0, GETNLINE_NO_LIMIT, delim, '\n', stream); @@ -626,12 +635,15 @@ cut_fields (FILE *stream) n_bytes = len; assert (n_bytes != 0); + c = 0; + got_line = field_1_buffer[n_bytes - 1] == '\n'; + /* If the first field extends to the end of line (it is not delimited) and we are printing all non-delimited lines, print this one. */ - if (to_uchar (field_1_buffer[n_bytes - 1]) != delim) + if (to_uchar (field_1_buffer[n_bytes - 1]) != delim || got_line) { - if (suppress_non_delimited) + if (suppress_non_delimited && !(got_line && delim == '\n')) { /* Empty. */ } @@ -639,8 +651,9 @@ cut_fields (FILE *stream) { fwrite (field_1_buffer, sizeof (char), n_bytes, stdout); /* Make sure the output line is newline terminated. */ - if (field_1_buffer[n_bytes - 1] != '\n') + if (! got_line) putchar ('\n'); + c = '\n'; } continue; } @@ -653,53 +666,46 @@ cut_fields (FILE *stream) ++field_idx; } - if (c != EOF) + int prev_c = c; + + if (print_kth (field_idx, NULL)) { - if (print_kth (field_idx, NULL)) + if (found_any_selected_field) { - if (found_any_selected_field) - { - fwrite (output_delimiter_string, sizeof (char), - output_delimiter_length, stdout); - } - found_any_selected_field = true; - - while ((c = getc (stream)) != delim && c != '\n' && c != EOF) - { - putchar (c); - } + fwrite (output_delimiter_string, sizeof (char), + output_delimiter_length, stdout); } - else + found_any_selected_field = true; + + while ((c = getc (stream)) != delim && c != '\n' && c != EOF) { - while ((c = getc (stream)) != delim && c != '\n' && c != EOF) - { - /* Empty. */ - } + putchar (c); + prev_c = c; } } - - if (c == '\n') + else { - c = getc (stream); - if (c != EOF) + while ((c = getc (stream)) != delim && c != '\n' && c != EOF) { - ungetc (c, stream); - c = '\n'; + prev_c = c; } } - if (c == delim) - ++field_idx; - else if (c == '\n' || c == EOF) + if (c == '\n' || c == EOF) { if (found_any_selected_field || !(suppress_non_delimited && field_idx == 1)) - putchar ('\n'); + { + if (c == '\n' || prev_c != '\n') + putchar ('\n'); + } if (c == EOF) break; field_idx = 1; found_any_selected_field = false; } + else if (c == delim) + field_idx++; } } @@ -840,7 +846,7 @@ main (int argc, char **argv) if (operating_mode == undefined_mode) FATAL_ERROR (_("you must specify a list of bytes, characters, or fields")); - if (delim != '\0' && operating_mode != field_mode) + if (delim_specified && operating_mode != field_mode) FATAL_ERROR (_("an input delimiter may be specified only\ when operating on fields")); |