]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
version comparisons: stop using locale-dependent isdigit() 23414/head
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 19 May 2022 07:05:48 +0000 (09:05 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 19 May 2022 09:07:28 +0000 (11:07 +0200)
The docs are not entirely clear what glyphs qualify as digits.
The function is supposed to be locale-dependent, but I couldn't
get it to return true on any non-ascii digits I tried.
But it's better to be safe than sorry, let's use our trivial
replacement instead.

src/fundamental/string-util-fundamental.c
src/test/test-string-util.c

index 57b4d535f3a96f5b67e5fbb3e86e85e989e907e7..feccb822ff78ae3cf6ca99047df08f51d0d01737 100644 (file)
@@ -77,19 +77,18 @@ sd_char* endswith_no_case(const sd_char *s, const sd_char *postfix) {
         return (sd_char*) s + sl - pl;
 }
 
-#ifdef SD_BOOT
-static sd_bool isdigit(sd_char a) {
+static sd_bool is_digit(sd_char a) {
+        /* Locale-independent version of isdigit(). */
         return a >= '0' && a <= '9';
 }
-#endif
 
 static sd_bool is_alpha(sd_char a) {
-        /* Locale independent version of isalpha(). */
+        /* Locale-independent version of isalpha(). */
         return (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z');
 }
 
 static sd_bool is_valid_version_char(sd_char a) {
-        return isdigit(a) || is_alpha(a) || IN_SET(a, '~', '-', '^', '.');
+        return is_digit(a) || is_alpha(a) || IN_SET(a, '~', '-', '^', '.');
 }
 
 sd_int strverscmp_improved(const sd_char *a, const sd_char *b) {
@@ -187,7 +186,7 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) {
                         b++;
                 }
 
-                if (isdigit(*a) || isdigit(*b)) {
+                if (is_digit(*a) || is_digit(*b)) {
                         /* Skip leading '0', to make 00123 equivalent to 123. */
                         while (*a == '0')
                                 a++;
@@ -196,9 +195,9 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) {
 
                         /* Find the leading numeric segments. One may be an empty string. So,
                          * numeric segments are always newer than alpha segments. */
-                        for (aa = a; isdigit(*aa); aa++)
+                        for (aa = a; is_digit(*aa); aa++)
                                 ;
-                        for (bb = b; isdigit(*bb); bb++)
+                        for (bb = b; is_digit(*bb); bb++)
                                 ;
 
                         /* To compare numeric segments without parsing their values, first compare the
index d0a4eca3906e56b87d82bd634f2f5fd03b27b74b..1054f9ea31df7540a4088451f0a39c23a55fae09 100644 (file)
@@ -1,5 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
+#include <ctype.h>
+
 #include "alloc-util.h"
 #include "locale-util.h"
 #include "macro.h"
@@ -914,6 +916,13 @@ TEST(strverscmp_improved) {
 
         /* invalid characters */
         assert_se(strverscmp_improved("123_aa2-67.89", "123aa+2-67.89") == 0);
+
+        /* non-ASCII digits */
+        (void) setlocale(LC_NUMERIC, "ar_YE.utf8");
+        assert_se(strverscmp_improved("1٠١٢٣٤٥٦٧٨٩", "1") == 0);
+
+        (void) setlocale(LC_NUMERIC, "th_TH.utf8");
+        assert_se(strverscmp_improved("1๐๑๒๓๔๕๖๗๘๙", "1") == 0);
 }
 
 #define RPMVERCMP(a, b, c) \