--- old/src/uniq.c 2023-10-26 22:16:06.128439677 +0200 +++ new/src/uniq.c 2023-10-26 22:15:43.965104621 +0200 @@ -51,6 +51,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; @@ -146,6 +149,7 @@ {"ignore-case", no_argument, nullptr, 'i'}, {"unique", no_argument, nullptr, 'u'}, {"skip-fields", required_argument, nullptr, 'f'}, + {"check-fields", required_argument, nullptr, 'm'}, {"skip-chars", required_argument, nullptr, 's'}, {"check-chars", required_argument, nullptr, 'w'}, {"zero-terminated", no_argument, nullptr, 'z'}, @@ -193,6 +197,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); @@ -252,7 +261,7 @@ ATTRIBUTE_PURE static char * -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 (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; } @@ -366,8 +390,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 = (!prevfield || different (thisfield, prevfield, thislen, prevlen)); @@ -402,8 +425,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)) { @@ -416,8 +438,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; @@ -497,6 +518,7 @@ skip_chars = 0; skip_fields = 0; + check_fields = 0; check_chars = SIZE_MAX; output_unique = output_first_repeated = true; output_later_repeated = false; @@ -512,7 +534,7 @@ if (optc == -1 || (posixly_correct && nfiles != 0) || ((optc = getopt_long (argc, argv, - "-0123456789Dcdf:is:uw:z", + "-0123456789Dcdf:im:s:uw:z", longopts, nullptr)) == -1)) { @@ -607,6 +629,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"));