--- old/src/uniq.c 2016-10-05 20:45:05.445188226 +0200 +++ new/src/uniq.c 2016-10-05 21:25:24.298871811 +0200 @@ -58,6 +58,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 check_fields; + /* Number of chars to skip after skipping any fields. */ static size_t skip_chars; @@ -153,6 +156,7 @@ {"ignore-case", no_argument, NULL, 'i'}, {"unique", no_argument, NULL, 'u'}, {"skip-fields", required_argument, NULL, 'f'}, + {"check-fields", required_argument, NULL, 'm'}, {"skip-chars", required_argument, NULL, 's'}, {"check-chars", required_argument, NULL, 'w'}, {"zero-terminated", no_argument, NULL, 'z'}, @@ -200,6 +204,11 @@ "), stdout); fputs (_("\ -i, --ignore-case ignore differences in case when comparing\n\ +"), stdout); + fputs (_("\ + -m, --check-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); @@ -260,7 +269,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; @@ -277,6 +286,21 @@ i += MIN (skip_chars, size - i); + if (check_fields == 0) + (*len) = size; + else + { + (*len) = i; + for (count = 0; count < check_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; } @@ -377,8 +401,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)); @@ -412,8 +435,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)) { @@ -426,8 +448,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; @@ -508,6 +529,7 @@ skip_chars = 0; skip_fields = 0; + check_fields = 0; check_chars = SIZE_MAX; output_unique = output_first_repeated = true; output_later_repeated = false; @@ -523,7 +545,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) @@ -617,6 +639,11 @@ ignore_case = true; break; + case 'm': + check_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"));