Browse Source

Merge branch '4374_version_sort_fix2'

* 4374_version_sort_fix2:
  Ticket #4374: fix file sort by version.
Andrew Borodin 2 years ago
parent
commit
0e583d756e
3 changed files with 17 additions and 9 deletions
  1. 2 0
      lib/strutil.h
  2. 13 7
      lib/strutil/filevercmp.c
  3. 2 2
      tests/lib/strutil/filevercmp.c

+ 2 - 0
lib/strutil.h

@@ -577,6 +577,8 @@ int str_verscmp (const char *s1, const char *s2);
    (\.[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.
+   When removing a suffix from a nonempty string, remove the maximal-length suffix such that
+   the remaining string is nonempty.
  */
 int filevercmp (const char *a, const char *b);
 

+ 13 - 7
lib/strutil/filevercmp.c

@@ -39,6 +39,9 @@
 /* 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 *lem to s's length.
  * Otherwise, *len should be nonnegative, s is a char array, and *len does not change.
  */
@@ -46,17 +49,13 @@ static ssize_t
 file_prefixlen (const char *s, ssize_t * len)
 {
     size_t n = (size_t) (*len); /* SIZE_MAX if N == -1 */
-    size_t i;
+    size_t i = 0;
+    size_t prefixlen = 0;
 
-    for (i = 0;; i++)
+    while (TRUE)
     {
-        size_t prefixlen = i;
         gboolean done;
 
-        while (i + 1 < n && s[i] == '.' && (g_ascii_isalpha (s[i + 1]) || s[i + 1] == '~'))
-            for (i += 2; i < n && (g_ascii_isalnum (s[i]) || s[i] == '~'); i++)
-                ;
-
         if (*len < 0)
             done = s[i] == '\0';
         else
@@ -67,6 +66,13 @@ file_prefixlen (const char *s, ssize_t * len)
             *len = (ssize_t) i;
             return (ssize_t) prefixlen;
         }
+
+        i++;
+        prefixlen = i;
+
+        while (i + 1 < n && s[i] == '.' && (g_ascii_isalpha (s[i + 1]) || s[i + 1] == '~'))
+            for (i += 2; i < n && (g_ascii_isalnum (s[i]) || s[i] == '~'); i++)
+                ;
     }
 }
 

+ 2 - 2
tests/lib/strutil/filevercmp.c

@@ -139,6 +139,8 @@ static const char *filevercmp_test_ds2[] = {
     "",
     ".",
     "..",
+    ".0",
+    ".9",
     ".A",
     ".Z",
     ".a~",
@@ -149,8 +151,6 @@ static const char *filevercmp_test_ds2[] = {
     ".zz~",
     ".zz",
     ".zz.~1~",
-    ".0",
-    ".9",
     ".zz.0",
     ".\1",
     ".\1.txt",