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
    (\.[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
    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.
    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);
 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
 /* 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~]*)*$
  * 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.
  * 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.
  * 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)
 file_prefixlen (const char *s, ssize_t * len)
 {
 {
     size_t n = (size_t) (*len); /* SIZE_MAX if N == -1 */
     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;
         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)
         if (*len < 0)
             done = s[i] == '\0';
             done = s[i] == '\0';
         else
         else
@@ -67,6 +66,13 @@ file_prefixlen (const char *s, ssize_t * len)
             *len = (ssize_t) i;
             *len = (ssize_t) i;
             return (ssize_t) prefixlen;
             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",
     ".A",
     ".Z",
     ".Z",
     ".a~",
     ".a~",
@@ -149,8 +151,6 @@ static const char *filevercmp_test_ds2[] = {
     ".zz~",
     ".zz~",
     ".zz",
     ".zz",
     ".zz.~1~",
     ".zz.~1~",
-    ".0",
-    ".9",
     ".zz.0",
     ".zz.0",
     ".\1",
     ".\1",
     ".\1.txt",
     ".\1.txt",