lib/jsonwrt: don't use ctype.h for ASCII chars

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>
This commit is contained in:
Karel Zak 2021-05-06 16:35:50 +02:00
parent 3a07505a39
commit 64a89adaa1
1 changed files with 14 additions and 3 deletions

View 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;
}