Thanks for the bug report. I installed the attached patch into Gnulib master and propagated this into Coreutils, so it should be fixed in the next Coreutils release.
From 1ba2b66ea45f9bc43cdc0f6f93efa59157d2b2ba Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email protected]>
Date: Fri, 3 Jun 2022 17:27:44 -0700
Subject: [PATCH] =?UTF-8?q?filevercmp:=20don=E2=80=99t=20treat=20entire=20?=
 =?UTF-8?q?filename=20as=20suffix?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Problem reported by Artém S. Tashkinóv in:
https://lists.gnu.org/r/bug-gnulib/2022-06/msg00012.html
* lib/filevercmp.c (file_prefixlen): When stripping
(\.[A-Za-z~][A-Za-z0-9~]*)*$ suffixes, do not strip
the entire file name.
* tests/test-filevercmp.c (examples): Adjust to match new behavior.
---
 ChangeLog               | 10 ++++++++++
 lib/filevercmp.c        | 18 +++++++++++-------
 lib/filevercmp.h        |  4 +++-
 tests/test-filevercmp.c |  4 ++--
 4 files changed, 26 insertions(+), 10 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 4449ff14f9..95d1314cdc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2022-06-03  Paul Eggert  <[email protected]>
+
+	filevercmp: don’t treat entire filename as suffix
+	Problem reported by Artém S. Tashkinóv in:
+	https://lists.gnu.org/r/bug-gnulib/2022-06/msg00012.html
+	* lib/filevercmp.c (file_prefixlen): When stripping
+	(\.[A-Za-z~][A-Za-z0-9~]*)*$ suffixes, do not strip
+	the entire file name.
+	* tests/test-filevercmp.c (examples): Adjust to match new behavior.
+
 2022-06-03  Bruno Haible  <[email protected]>
 
 	setlocale: Update after Turkey changed its name.
diff --git a/lib/filevercmp.c b/lib/filevercmp.c
index d546e79054..7e54793e61 100644
--- a/lib/filevercmp.c
+++ b/lib/filevercmp.c
@@ -29,6 +29,8 @@
 /* Return the length of a prefix of S that corresponds to the suffix
    defined by this extended regular expression in the C locale:
      (\.[A-Za-z~][A-Za-z0-9~]*)*$
+   Use the longest suffix matching this regular expression,
+   except do not use all of S as a suffix if S is nonempty.
    If *LEN is -1, S is a string; set *LEN to S's length.
    Otherwise, *LEN should be nonnegative, S is a char array,
    and *LEN does not change.  */
@@ -36,20 +38,22 @@ static idx_t
 file_prefixlen (char const *s, ptrdiff_t *len)
 {
   size_t n = *len;  /* SIZE_MAX if N == -1.  */
+  idx_t prefixlen = 0;
 
-  for (idx_t i = 0; ; i++)
+  for (idx_t i = 0; ; )
     {
-      idx_t prefixlen = i;
-      while (i + 1 < n && s[i] == '.' && (c_isalpha (s[i + 1])
-                                          || s[i + 1] == '~'))
-        for (i += 2; i < n && (c_isalnum (s[i]) || s[i] == '~'); i++)
-          continue;
-
       if (*len < 0 ? !s[i] : i == n)
         {
           *len = i;
           return prefixlen;
         }
+
+      i++;
+      prefixlen = i;
+      while (i + 1 < n && s[i] == '.' && (c_isalpha (s[i + 1])
+                                          || s[i + 1] == '~'))
+        for (i += 2; i < n && (c_isalnum (s[i]) || s[i] == '~'); i++)
+          continue;
     }
 }
 
diff --git a/lib/filevercmp.h b/lib/filevercmp.h
index 5a33677671..57949760b2 100644
--- a/lib/filevercmp.h
+++ b/lib/filevercmp.h
@@ -61,7 +61,9 @@
    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.
+   strings are compared using version sort.  When removing a suffix
+   from a nonempty string, remove the maximal-length suffix such that
+   the remaining string is nonempty.
 
    This function is intended to be a replacement for strverscmp.  */
 int filevercmp (char const *a, char const *b) _GL_ATTRIBUTE_PURE;
diff --git a/tests/test-filevercmp.c b/tests/test-filevercmp.c
index b2a7e90f3f..998250990d 100644
--- a/tests/test-filevercmp.c
+++ b/tests/test-filevercmp.c
@@ -29,6 +29,8 @@ static const char *const examples[] =
   "",
   ".",
   "..",
+  ".0",
+  ".9",
   ".A",
   ".Z",
   ".a~",
@@ -39,8 +41,6 @@ static const char *const examples[] =
   ".zz~",
   ".zz",
   ".zz.~1~",
-  ".0",
-  ".9",
   ".zz.0",
   ".\1",
   ".\1.txt",
-- 
2.36.1

Reply via email to