1
0
mirror of git://git.sv.gnu.org/coreutils.git synced 2026-08-04 15:49:42 +02:00

(complement, COMPLEMENT_OPTION): New.

(longopts): Add --complement.
(usage): Say not that -b, -c, and -f `print' fields,
but rather that they `select' fields for printing.
Describe the new --complement option.
(mark_range_start): Extracted from set_fields.
(print_kth): Support --complement.
(compare_ranges): New function.
(set_fields): Rewrite the part that populates range_start_ht,
merging it with the part that populates printable_field.
(main): Handle --complement.

From Paolo Bonzini.
This commit is contained in:
Jim Meyering
2004-12-04 13:32:48 +00:00
parent 4dd208a372
commit 7380cf792a
+63 -47
View File
@@ -126,6 +126,10 @@ static enum operating_mode operating_mode;
with field mode. */ with field mode. */
static bool suppress_non_delimited; static bool suppress_non_delimited;
/* If nonzero, print all bytes, characters, or fields _except_
those that were specified. */
static bool complement;
/* The delimeter character for field mode. */ /* The delimeter character for field mode. */
static unsigned char delim; static unsigned char delim;
@@ -155,7 +159,8 @@ static Hash_table *range_start_ht;
non-character as a pseudo short option, starting with CHAR_MAX + 1. */ non-character as a pseudo short option, starting with CHAR_MAX + 1. */
enum enum
{ {
OUTPUT_DELIMITER_OPTION = CHAR_MAX + 1 OUTPUT_DELIMITER_OPTION = CHAR_MAX + 1,
COMPLEMENT_OPTION
}; };
static struct option const longopts[] = static struct option const longopts[] =
@@ -166,6 +171,7 @@ static struct option const longopts[] =
{"delimiter", required_argument, 0, 'd'}, {"delimiter", required_argument, 0, 'd'},
{"only-delimited", no_argument, 0, 's'}, {"only-delimited", no_argument, 0, 's'},
{"output-delimiter", required_argument, 0, OUTPUT_DELIMITER_OPTION}, {"output-delimiter", required_argument, 0, OUTPUT_DELIMITER_OPTION},
{"complement", no_argument, 0, COMPLEMENT_OPTION},
{GETOPT_HELP_OPTION_DECL}, {GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL}, {GETOPT_VERSION_OPTION_DECL},
{0, 0, 0, 0} {0, 0, 0, 0}
@@ -191,15 +197,19 @@ Print selected parts of lines from each FILE to standard output.\n\
Mandatory arguments to long options are mandatory for short options too.\n\ Mandatory arguments to long options are mandatory for short options too.\n\
"), stdout); "), stdout);
fputs (_("\ fputs (_("\
-b, --bytes=LIST output only these bytes\n\ -b, --bytes=LIST select only these bytes\n\
-c, --characters=LIST output only these characters\n\ -c, --characters=LIST select only these characters\n\
-d, --delimiter=DELIM use DELIM instead of TAB for field delimiter\n\ -d, --delimiter=DELIM use DELIM instead of TAB for field delimiter\n\
"), stdout); "), stdout);
fputs (_("\ fputs (_("\
-f, --fields=LIST output only these fields; also print any line\n\ -f, --fields=LIST select only these fields; also print any line\n\
that contains no delimiter character, unless\n\ that contains no delimiter character, unless\n\
the -s option is specified\n\ the -s option is specified\n\
-n (ignored)\n\ -n (ignored)\n\
"), stdout);
fputs (_("\
--complement complement the set of selected bytes, characters\n\
or fields.\n\
"), stdout); "), stdout);
fputs (_("\ fputs (_("\
-s, --only-delimited do not print lines not containing delimiters\n\ -s, --only-delimited do not print lines not containing delimiters\n\
@@ -227,6 +237,19 @@ With no FILE, or when FILE is -, read standard input.\n\
exit (status); exit (status);
} }
static inline void
mark_range_start (size_t i)
{
/* Record the fact that `i' is a range-start index. */
void *ent_from_table = hash_insert (range_start_ht, (void*) i);
if (ent_from_table == NULL)
{
/* Insertion failed due to lack of memory. */
xalloc_die ();
}
assert ((size_t) ent_from_table == i);
}
static inline void static inline void
mark_printable_field (size_t i) mark_printable_field (size_t i)
{ {
@@ -272,15 +295,25 @@ is_range_start_index (size_t i)
static bool static bool
print_kth (size_t k, bool *range_start) print_kth (size_t k, bool *range_start)
{ {
if ((0 < eol_range_start && eol_range_start <= k) bool k_selected
|| (k <= max_range_endpoint && is_printable_field (k))) = ((0 < eol_range_start && eol_range_start <= k)
{ || (k <= max_range_endpoint && is_printable_field (k)));
if (range_start)
*range_start = is_range_start_index (k);
return true;
}
return false; bool is_selected = k_selected ^ complement;
if (range_start && is_selected)
*range_start = is_range_start_index (k);
return is_selected;
}
/* Comparison function for qsort to order the list of
struct range_pairs. */
static int
compare_ranges (const void *a, const void *b)
{
int a_start = ((const struct range_pair *) a)->lo;
int b_start = ((const struct range_pair *) b)->lo;
return a_start < b_start ? -1 : a_start > b_start;
} }
/* Given the list of field or byte range specifications FIELDSTR, set /* Given the list of field or byte range specifications FIELDSTR, set
@@ -461,51 +494,30 @@ set_fields (const char *fieldstr)
printable_field = xzalloc (max_range_endpoint / CHAR_BIT + 1); 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. */ /* Set the array entries corresponding to integers in the ranges of RP. */
for (i = 0; i < n_rp; i++) for (i = 0; i < n_rp; i++)
{ {
size_t j; size_t j;
for (j = rp[i].lo; j <= rp[i].hi; j++) size_t rsi_candidate;
{
mark_printable_field (j);
}
}
if (output_delimiter_specified)
{
/* Record the range-start indices, i.e., record each start /* Record the range-start indices, i.e., record each start
index that is not part of any other (lo..hi] range. */ index that is not part of any other (lo..hi] range. */
for (i = 0; i <= n_rp; i++) rsi_candidate = complement ? rp[i].hi + 1 : rp[i].lo;
{ if (output_delimiter_specified
size_t j; && !is_printable_field (rsi_candidate))
size_t rsi = (i < n_rp ? rp[i].lo : eol_range_start); mark_range_start (rsi_candidate);
for (j = 0; j < n_rp; j++) for (j = rp[i].lo; j <= rp[i].hi; j++)
{ mark_printable_field (j);
if (rp[j].lo < rsi && rsi <= rp[j].hi)
{
rsi = 0;
break;
}
}
if (eol_range_start && eol_range_start < rsi)
rsi = 0;
if (rsi)
{
/* Record the fact that `rsi' is a range-start index. */
void *ent_from_table = hash_insert (range_start_ht, (void*) rsi);
if (ent_from_table == NULL)
{
/* Insertion failed due to lack of memory. */
xalloc_die ();
}
assert ((size_t) ent_from_table == rsi);
}
}
} }
if (output_delimiter_specified
&& !complement
&& eol_range_start && !is_printable_field (eol_range_start))
mark_range_start (eol_range_start);
free (rp); free (rp);
return field_found; return field_found;
@@ -799,6 +811,10 @@ main (int argc, char **argv)
suppress_non_delimited = true; suppress_non_delimited = true;
break; break;
case COMPLEMENT_OPTION:
complement = true;
break;
case_GETOPT_HELP_CHAR; case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);