]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lib/jsonwrt: don't use ctype.h for ASCII chars
authorKarel Zak <kzak@redhat.com>
Thu, 6 May 2021 14:35:50 +0000 (16:35 +0200)
committerKarel Zak <kzak@redhat.com>
Thu, 6 May 2021 14:35:50 +0000 (16:35 +0200)
tolower() does not work "as expected" for tr_TR.UTF-8 (Turkish).
Fortunately, we need to convert only objects and variables names in
JSON output, and this is always old good ASCII.

Anyway, for more details:

$ cat a.c
#include <ctype.h>
#include <stdio.h>
#include <locale.h>

int main(void)
{
int in, out;

setlocale(LC_ALL, "");

in ='I';
out = tolower(in);

printf("%1$c [%1$d] --> %2$c [%2$d]\n", in, out);
return 0;
}

$ make a
cc     a.c   -o a

$ LANG=en_US.utf8 ./a
I [73] --> i [105]

$ LANG=tr_TR.UTF-8 ./a
I [73] --> I [73]

Fixes: https://github.com/karelzak/util-linux/issues/1302
Signed-off-by: Karel Zak <kzak@redhat.com>
lib/jsonwrt.c

index 92d64f74645b78e3d80f0b66961706bbbc166fd4..f2003e80836b36f5000a4e1474e267de2596d1d4 100644 (file)
@@ -8,6 +8,8 @@
  */
 #include <stdio.h>
 #include <inttypes.h>
+#include <ctype.h>
+#include <cctype.h>
 
 #include "c.h"
 #include "jsonwrt.h"
@@ -31,7 +33,7 @@ static void fputs_quoted_case_json(const char *data, FILE *out, int dir)
        fputc('"', out);
        for (p = data; p && *p; p++) {
 
-               const unsigned char c = (unsigned char) *p;
+               const unsigned int c = (unsigned int) *p;
 
                /* From http://www.json.org
                 *
@@ -49,8 +51,17 @@ static void fputs_quoted_case_json(const char *data, FILE *out, int dir)
 
                /* All non-control characters OK; do the case swap as required. */
                if (c >= 0x20) {
-                       fputc(dir ==  1 ? toupper(c) :
-                             dir == -1 ? tolower(c) : *p, out);
+                       /*
+                        * Don't use locale sensitive ctype.h functions for regular
+                        * ASCII chars, because for example with Turkish locale
+                        * (aka LANG=tr_TR.UTF-8) toupper('I') returns 'I'.
+                        */
+                       if (c <= 127)
+                               fputc(dir ==  1 ? c_toupper(c) :
+                                     dir == -1 ? c_tolower(c) : *p, out);
+                       else
+                               fputc(dir ==  1 ? toupper(c) :
+                                     dir == -1 ? tolower(c) : *p, out);
                        continue;
                }