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:
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user