Hash :
9f48fb99
Author :
Date :
2022-02-12T16:27:05
filevercmp: fix several unexpected results Problems reported by Michael Debertol in <https://bugs.gnu.org/49239>. While looking into this, I spotted some more areas where the code and documentation did not agree, or where the documentation was unclear. The biggest change needed by coreutils is a new function filenvercmp that can compare byte strings containing NUL. * lib/filevercmp.c: Do not include sys/types.h, stdlib.h, string.h. Include idx.h, verify.h. (match_suffix): Remove, replacing all uses with calls to ... (file_prefixlen): ... this new function. Simplify it by avoiding the need for a confusing READ_ALPHA state variable. Change its API to something more useful, with a *LEN arg. it with a new *LEN arg. (file_prefixlen, verrevcmp): Prefer idx_t to size_t where either will do. (order): Change args to S, POS, LEN instead of just S[POS]. This lets us handle NUL bytes correctly. Callers changed. Verify that ints are sufficiently wide for its API. (verrevcmp): Don't assume that S1[S1_LEN] is a non-digit, and likewise for S2[S2_LEN]. The byte might not be accessible if filenvercmp is being called. (filevercmp): Reimplement by calling filenvercmp. (filenvercmp): New function, rewritten without the assumption that the inputs are null-terminated. Remove "easy comparison to see if strings are identical", as the use of it later (a) was undocumented, and (b) caused sort -V to be unstable. When both strings start with ".", do not skip past the "."s before looking for suffixes, as this disagreed with the documentation. * lib/filevercmp.h: Fix comments, which had many mistakes. (filenvercmp): New decl. * modules/filevercmp (Depends-on): Add idx, verify. Remove string. * tests/test-filevercmp.c: Include string.h. (examples): Reorder examples ".0" and ".9" that matched the code but not the documentation. The code has been fixed to match the documentation. Add some examples involving \1 so that they can be tried with both \1 and \0. Add some other examples taken from the bug report. (equals): New set of test cases. (sign, test_filevercmp): New functions. (main): Remove test case where the fixed filevercmp disagrees with strverscmp. Use test_filevercmp instead of filevercmp, so that we also test filenvercmp. Test the newly-introduced EQUALS cases.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
/* Compare file names containing version numbers.
Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
Copyright (C) 2001 Anthony Towns <aj@azure.humbug.org.au>
Copyright (C) 2008-2022 Free Software Foundation, Inc.
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This file is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#ifndef FILEVERCMP_H
#define FILEVERCMP_H
#include <stddef.h>
/* Compare strings A and B as file names containing version numbers,
and return an integer that is negative, zero, or positive depending
on whether A compares less than, equal to, or greater than B.
Use the following version sort algorithm:
1. Compare the strings' maximal-length non-digit prefixes lexically.
If there is a difference return that difference.
Otherwise discard the prefixes and continue with the next step.
2. Compare the strings' maximal-length digit prefixes, using
numeric comparison of the numbers represented by each prefix.
(Treat an empty prefix as zero; this can happen only at string end.)
If there is a difference, return that difference.
Otherwise discard the prefixes and continue with the next step.
3. If both strings are empty, return 0. Otherwise continue with step 1.
In version sort, lexical comparison is left to right, byte by byte,
using the byte's numeric value (0-255), except that:
1. ASCII letters sort before other bytes.
2. A tilde sorts before anything, even an empty string.
In addition to the version sort rules, the following strings have
special priority and sort before all other strings (listed in order):
1. The empty string.
2. ".".
3. "..".
4. Strings starting with "." sort before other strings.
Before comparing two strings where both begin with non-".",
or where both begin with "." but neither is "." or "..",
suffixes matching the C-locale extended regular expression
(\.[A-Za-z~][A-Za-z0-9~]*)*$ are removed and the strings compared
without them, using version sort without special priority;
if they do not compare equal, this comparison result is used and
the suffixes are effectively ignored. Otherwise, the entire
strings are compared using version sort.
This function is intended to be a replacement for strverscmp. */
int filevercmp (char const *a, char const *b) _GL_ATTRIBUTE_PURE;
/* Like filevercmp, except compare the byte arrays A (of length ALEN)
and B (of length BLEN) so that A and B can contain '\0', which
sorts just before '\1'. But if ALEN is -1 treat A as a string
terminated by '\0', and similarly for BLEN. */
int filenvercmp (char const *a, ptrdiff_t alen, char const *b, ptrdiff_t blen)
_GL_ATTRIBUTE_PURE;
#endif /* FILEVERCMP_H */