summaryrefslogtreecommitdiff
path: root/src/cut.c
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2013-02-16 14:42:43 +0000
committerIgor Pashev <pashev.igor@gmail.com>2013-02-16 14:42:43 +0000
commit7548e75065063dae256d94e6c7f4f9f43bd7f210 (patch)
treef23b000f8822f6eb70249c1106a3275deaa03bac /src/cut.c
parentddefcddae2e97579f82320f4fd70d0ba14a52392 (diff)
parent974ab3dd887985e3aa347f3c6521f819296396a0 (diff)
downloadcoreutils-7548e75065063dae256d94e6c7f4f9f43bd7f210.tar.gz
Merge tag 'upstream/8.21'
Upstream version 8.21
Diffstat (limited to 'src/cut.c')
-rw-r--r--src/cut.c104
1 files changed, 55 insertions, 49 deletions
diff --git a/src/cut.c b/src/cut.c
index 87380ac6..494aad77 100644
--- a/src/cut.c
+++ b/src/cut.c
@@ -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"));