--- old/src/uniq.c 2016-10-05 20:45:05.445188226 +0200 +++ new/src/uniq.c 2016-10-05 21:25:24.298871811 +0200 @@ -57,6 +57,9 @@ /* Number of fields to skip on each line when doing comparisons. */ static size_t skip_fields; +/* Number of fields to compare. */ +static size_t max_fields; + /* Number of chars to skip after skipping any fields. */ static size_t skip_chars; @@ -152,6 +155,7 @@ {"ignore-case", no_argument, NULL, 'i'}, {"unique", no_argument, NULL, 'u'}, {"skip-fields", required_argument, NULL, 'f'}, + {"max-fields", required_argument, NULL, 'm'}, {"skip-chars", required_argument, NULL, 's'}, {"check-chars", required_argument, NULL, 'w'}, {"zero-terminated", no_argument, NULL, 'z'}, @@ -199,6 +203,11 @@ "), stdout); fputs (_("\ -i, --ignore-case ignore differences in case when comparing\n\ +"), stdout); + fputs (_("\ + -m, --max-fields=N compare no more than N fields\n\ +"), stdout); + fputs (_("\ -s, --skip-chars=N avoid comparing the first N characters\n\ -u, --unique only print unique lines\n\ "), stdout); @@ -252,7 +261,7 @@ return a pointer to the beginning of the line's field to be compared. */ static char * _GL_ATTRIBUTE_PURE -find_field (struct linebuffer const *line) +find_field (struct linebuffer const *line, size_t *len) { size_t count; char const *lp = line->buffer; @@ -269,6 +278,21 @@ i += MIN (skip_chars, size - i); + if (max_fields == 0) + (*len) = size; + else + { + (*len) = i; + for (count = 0; count < max_fields && (*len) < size; count ++) + { + while ((*len) < size && field_sep (lp[*len])) + (*len)++; + while ((*len) < size && !field_sep (lp[*len])) + (*len)++; + } + } + (*len) = (*len) - i; + return line->buffer + i; } @@ -369,8 +393,7 @@ if (readlinebuffer_delim (thisline, stdin, delimiter) == 0) break; - thisfield = find_field (thisline); - thislen = thisline->length - 1 - (thisfield - thisline->buffer); + thisfield = find_field (thisline,&thislen); new_group = (prevline->length == 0 || different (thisfield, prevfield, thislen, prevlen)); @@ -404,8 +427,7 @@ if (readlinebuffer_delim (prevline, stdin, delimiter) == 0) goto closefiles; - prevfield = find_field (prevline); - prevlen = prevline->length - 1 - (prevfield - prevline->buffer); + prevfield = find_field (prevline,&prevlen); while (!feof (stdin)) { @@ -418,8 +440,7 @@ goto closefiles; break; } - thisfield = find_field (thisline); - thislen = thisline->length - 1 - (thisfield - thisline->buffer); + thisfield = find_field (thisline,&thislen); match = !different (thisfield, prevfield, thislen, prevlen); match_count += match; @@ -500,6 +521,7 @@ skip_chars = 0; skip_fields = 0; + max_fields = 0; check_chars = SIZE_MAX; output_unique = output_first_repeated = true; output_later_repeated = false; @@ -515,7 +537,7 @@ if (optc == -1 || (posixly_correct && nfiles != 0) || ((optc = getopt_long (argc, argv, - "-0123456789Dcdf:is:uw:z", longopts, NULL)) + "-0123456789Dcdf:im:s:uw:z", longopts, NULL)) == -1)) { if (argc <= optind) @@ -609,6 +631,11 @@ ignore_case = true; break; + case 'm': + max_fields = size_opt (optarg, + N_("invalid number of fields to compare")); + break; + case 's': skip_chars = size_opt (optarg, N_("invalid number of bytes to skip"));