diff -aru textutils-2.0.21/doc/coreutils.texi textutils-2.0.21-pb/doc/coreutils.texi --- textutils-2.0.21/doc/coreutils.texi Sun Feb 17 21:47:23 2002 +++ textutils-2.0.21-pb/doc/coreutils.texi Wed Mar 20 18:26:18 2002 @@ -3270,23 +3270,34 @@ @opindex -D @opindex --all-repeated @cindex all duplicate lines, outputting -Print all copies of each duplicate line. -This option is useful mainly in conjunction with other options e.g., +@itemx -G +@itemx --group[=@var{delimit-method}] +@opindex -G +@opindex --group +@cindex group all lines, outputting +Print all copies of each duplicate line (@option{-D}) or +Group all lines (@option{-G}). The difference between these +is that the @option{--all-repeated} (@option{-D}) option +does not output unique lines. + +These options are useful mainly in conjunction with other options e.g., to ignore case or to compare only selected fields. The optional @var{delimit-method} tells how to delimit -groups of duplicate lines, and must be one of the following: +groups of (duplicate) lines, and must be one of the following: @table @samp @item none Do not delimit groups of duplicate lines. This is equivalent to @option{--all-repeated} (@option{-D}). +This option not valid when grouping, +(i.e. when used with @option{--group} (@option{-G})). @item prepend -Output a newline before each group of duplicate lines. +Output a newline before each group of (duplicate) lines. @item separate -Separate groups of duplicate lines with a single newline. +Separate groups of (duplicate) lines with a single newline. This is the same as using @samp{prepend}, except that there is no newline before the first group, and hence may be better suited for output direct to users. diff -aru textutils-2.0.21/src/uniq.c textutils-2.0.21-pb/src/uniq.c --- textutils-2.0.21/src/uniq.c Sat Feb 16 07:23:15 2002 +++ textutils-2.0.21-pb/src/uniq.c Wed Mar 20 18:58:18 2002 @@ -71,10 +71,11 @@ enum output_mode { - output_repeated, /* -d Only lines that are repeated. */ - output_all_repeated, /* -D All lines that are repeated. */ - output_unique, /* -u Only lines that are not repeated. */ - output_all /* Default. Print first copy of each line. */ + output_all=0, /* Default. Print first copy of each line. */ + output_repeated=1, /* -d Only lines that are repeated. */ + output_all_repeated=2, /* -D All lines that are repeated. */ + output_unique=4, /* -u Only lines that are not repeated. */ + output_all_grouped=8 /* -G Group all lines. */ }; /* Which lines to output. */ @@ -113,6 +114,7 @@ {"count", no_argument, NULL, 'c'}, {"repeated", no_argument, NULL, 'd'}, {"all-repeated", optional_argument, NULL, 'D'}, + {"group", optional_argument, NULL, 'G'}, {"ignore-case", no_argument, NULL, 'i'}, {"unique", no_argument, NULL, 'u'}, {"skip-fields", required_argument, NULL, 'f'}, @@ -151,6 +153,9 @@ -D, --all-repeated[=delimit-method] print all duplicate lines\n\ delimit-method={none(default),prepend,separate}\n\ Delimiting is done with blank lines.\n\ + -G, --group[=delimit-method] group all lines\n\ + delimit-method={prepend,separate(default)}\n\ + Delimiting is done with blank lines.\n\ -f, --skip-fields=N avoid comparing the first N fields\n\ -i, --ignore-case ignore differences in case when comparing\n\ -s, --skip-chars=N avoid comparing the first N characters\n\ @@ -342,7 +347,19 @@ if (match) ++match_count; - if (mode == output_all_repeated && delimit_groups != DM_NONE) + if ((mode & output_unique) && (mode & output_all_repeated)) /* -G */ + if (!match) + { + if (!match_count) /* a uniq line */ + { + if ((delimit_groups == DM_PREPEND) || + (delimit_groups == DM_SEPARATE && !first_delimiter)) + putc ('\n', ostream); + first_delimiter = 0; /* Only used when DM_SEPARATE */ + } + } + + if ((mode & output_all_repeated) && (delimit_groups != DM_NONE)) { if (!match) { @@ -358,7 +375,7 @@ } } - if (!match || mode == output_all_repeated) + if (!match || (mode & output_all_repeated)) { writeline (prevline, ostream, match_count); SWAP_LINES (prevline, thisline); @@ -369,6 +386,14 @@ } } + if ((mode & output_unique) && (mode & output_all_repeated)) /* -G */ + { + if (match_count == 0) + if ((delimit_groups == DM_PREPEND) || + (delimit_groups == DM_SEPARATE && !first_delimiter)) + putc ('\n', ostream); + } + writeline (prevline, ostream, match_count); } @@ -418,7 +443,7 @@ if (optc == -1 || (posixly_correct && nfiles != 0) || ((optc = getopt_long (argc, argv, - "-0123456789Dcdf:is:uw:", longopts, NULL)) + "-0123456789Dcdf:G::is:uw:", longopts, NULL)) == -1)) { if (optind == argc) @@ -475,11 +500,11 @@ break; case 'd': - mode = output_repeated; + mode += output_repeated; break; case 'D': - mode = output_all_repeated; + mode += output_all_repeated; if (optarg == NULL) delimit_groups = DM_NONE; else @@ -493,6 +518,16 @@ N_("invalid number of fields to skip")); break; + case 'G': + mode += output_all_grouped; + if (optarg == NULL) + delimit_groups = DM_SEPARATE; + else + delimit_groups = XARGMATCH ("--group", optarg, + delimit_method_string, + delimit_method_map); + break; + case 'i': ignore_case = 1; break; @@ -503,7 +538,7 @@ break; case 'u': - mode = output_unique; + mode += output_unique; break; case 'w': @@ -527,13 +562,54 @@ usage (EXIT_FAILURE); } - if (countmode == count_occurrences && mode == output_all_repeated) + if (countmode == count_occurrences && (mode & (output_all_repeated | output_all_grouped))) + { + error (0, 0, + _("printing all (duplicated) lines and repeat counts is meaningless")); + usage (1); + } + + if ((mode & output_all_grouped) && (mode != output_all_grouped)) + { + error (0, 0, + _("printing all groups in combination with other modes is meaningless")); + usage (1); + } + + if ((mode & output_unique) && (mode & output_all_repeated)) { error (0, 0, - _("printing all duplicated lines and repeat counts is meaningless")); + _("specifying to print both unique and all duplicate lines is redundant\n" + "(This is what the --group option does)")); usage (1); } + if ((mode & output_all_grouped) && (delimit_groups == DM_NONE)) + { + error (0, 0, + _("printing all groups while not delimiting them is redundant\n" + "(The input data will not be changed)")); + usage (1); + } + + if ((mode & output_unique) && (mode & output_repeated)) + { + error (0, 0, + _("specifying to print both unique and duplicate lines is redundant\n" + "(This is uniq's default mode of operation)")); + usage (1); + } + + if ((mode & output_repeated) && (mode & output_all_repeated)) + { + error (0, 0, + _("printing both duplicate lines and all duplicate lines is meaningless")); + usage (1); + } + + if (mode & output_all_grouped) + mode = output_unique | output_all_repeated; + check_file (file[0], file[1]); exit (EXIT_SUCCESS); diff -aru textutils-2.0.21/tests/uniq/Test.pm textutils-2.0.21-pb/tests/uniq/Test.pm --- textutils-2.0.21/tests/uniq/Test.pm Mon Feb 18 12:39:12 2002 +++ textutils-2.0.21-pb/tests/uniq/Test.pm Wed Mar 20 19:01:49 2002 @@ -73,16 +73,32 @@ ['101', '-c', "a\nb\n", " 1\ta\n 1\tb\n", 0], ['102', '-c', "a\na\n", " 2\ta\n", 0], # Check the local -D (--all-repeated) option -['110', '-D', "a\na\n", "a\na\n", 0], -['111', '-D -w1',"a a\na b\n", "a a\na b\n", 0], -['112', '-D -c', "a a\na b\n", "", 1], -['113', '--all-repeated=separate',"a\na\n", "a\na\n", 0], -['114', '--all-repeated=separate',"a\na\nb\nc\nc\n", "a\na\n\nc\nc\n", 0], -['115', '--all-repeated=separate',"a\na\nb\nb\nc\n", "a\na\n\nb\nb\n", 0], -['116', '--all-repeated=prepend', "a\na\n", "\na\na\n", 0], -['117', '--all-repeated=prepend', "a\na\nb\nc\nc\n", "\na\na\n\nc\nc\n", 0], -['118', '--all-repeated=prepend', "a\nb\n", "", 0], -['119', '--all-repeated=badoption', "a\n", "", 1], +['110', '-D', "a\na\n", "a\na\n", 0], +['111', '-D -w1', "a a\na b\n", "a a\na b\n", 0], +['112', '--all-repeated=separate', "a\na\n", "a\na\n", 0], +['113', '--all-repeated=separate', "a\na\nb\nc\nc\n", "a\na\n\nc\nc\n", 0], +['114', '--all-repeated=separate', "a\na\nb\nb\nc\n", "a\na\n\nb\nb\n", 0], +['115', '--all-repeated=prepend', "a\na\n", "\na\na\n", 0], +['116', '--all-repeated=prepend', "a\na\nb\nc\nc\n", "\na\na\n\nc\nc\n", 0], +['117', '--all-repeated=prepend', "a\nb\n", "", 0], +['118', '--all-repeated=badoption', "a\n", "", 1], +# Check the -G (--group) option +['120', '-G', "a\na\n", "a\na\n", 0], +['121', '-G -w1', "a a\na b\n", "a a\na b\n", 0], +['122', '--group=separate', "a\na\n", "a\na\n", 0], +['123', '--group=separate', "a\na\nb\nc\nc\n", "a\na\n\nb\n\nc\nc\n", 0], +['124', '--group=separate', "a\na\nb\nb\nc\n", "a\na\n\nb\nb\n\nc\n", 0], +['125', '--group=prepend', "a\na\n", "\na\na\n", 0], +['126', '--group=prepend', "a\na\nb\nc\nc\n", "\na\na\n\nb\n\nc\nc\n", 0], +['127', '--group=prepend', "a\nb\n", "\na\n\nb\n", 0], +['128', '--group=badoption', "a\n", "", 1], +# Check invalid option combinations +['130', '-D -c', "a\na\n", "", 1], +['131', '-G -c', "a\na\n", "", 1], +['132', '-D -G', "a\na\n", "", 1], +['133', '-D -u', "a\na\n", "", 1], +['134', '-u -d', "a\na\n", "", 1], +['135', '-D -d', "a\na\n", "", 1], ); sub test_vector