On this system:

$ uname -a
OpenBSD cjg-openbsd6 6.2 GENERIC#132 amd64


compiling and running the attached file yields buggy results.

setlocale(LC_ALL, "C") returned 'C'
setlocale(LC_CTYPE, "cguevara_and_khw") returned 'cguevara_and_khw'
setlocale(LC_CTYPE, NULL) returned 'cguevara_and_khw'
setlocale(LC_TIME, "en_US.UTF-8") returned 'en_US.UTF-8'
setlocale(LC_TIME, NULL) returned 'en_US.UTF-8'
setlocale(LC_NUMERIC, "es_ES.UTF-8") returned 'es_ES.UTF-8'
setlocale(LC_NUMERIC, NULL) returned 'es_ES.UTF-8'
setlocale(LC_MONETARY, "it_IT.UTF-8") returned 'it_IT.UTF-8'
setlocale(LC_MONETARY, NULL) returned 'it_IT.UTF-8'
setlocale(LC_COLLATE, "nl_NL.UTF-8") returned 'nl_NL.UTF-8'
setlocale(LC_COLLATE, NULL) returned 'nl_NL.UTF-8'
setlocale(LC_MESSAGES, "de_DE.UTF-8") returned 'de_DE.UTF-8'
setlocale(LC_MESSAGES, NULL) returned 'de_DE.UTF-8'
setlocale(LC_CTYPE, "ro_RO.UTF-8") returned 'ro_RO.UTF-8'
setlocale(LC_CTYPE, NULL) returned 'ro_RO.UTF-8'
setlocale(LC_ALL, NULL) returned 'C'


All locales but 'cguevara_and_khw' were listed in the output of 'locale -a'. That one was used to be a deliberately bad locale name.

The man page of setlocale says that it returns NULL on invalid input. Furthermore, it says only LC_CTYPE can be non-C, non-POSIX. That means that almost all the setlocale calls to change things should have returned NULL, and similarly almost all the ones with NULL as the parameter should have returned "C".

The Romanian locale should have been legal, but then why doesn't the final call to see what LC_ALL is, list LC_CTYPE as being Romanian with the other categories being "C".

Running the program on Linux yields instead
setlocale(LC_ALL, "C") returned 'C'
setlocale(LC_CTYPE, "cguevara_and_khw") returned 'NULL'
setlocale(LC_CTYPE, NULL) returned 'C'
setlocale(LC_TIME, "en_US.UTF-8") returned 'en_US.UTF-8'
setlocale(LC_TIME, NULL) returned 'en_US.UTF-8'
setlocale(LC_NUMERIC, "es_ES.UTF-8") returned 'es_ES.UTF-8'
setlocale(LC_NUMERIC, NULL) returned 'es_ES.UTF-8'
setlocale(LC_MONETARY, "it_IT.UTF-8") returned 'it_IT.UTF-8'
setlocale(LC_MONETARY, NULL) returned 'it_IT.UTF-8'
setlocale(LC_COLLATE, "nl_NL.UTF-8") returned 'nl_NL.UTF-8'
setlocale(LC_COLLATE, NULL) returned 'nl_NL.UTF-8'
setlocale(LC_MESSAGES, "de_DE.UTF-8") returned 'de_DE.UTF-8'
setlocale(LC_MESSAGES, NULL) returned 'de_DE.UTF-8'
setlocale(LC_CTYPE, "ro_RO.UTF-8") returned 'ro_RO.UTF-8'
setlocale(LC_CTYPE, NULL) returned 'ro_RO.UTF-8'
setlocale(LC_ALL, NULL) returned 'LC_CTYPE=ro_RO.UTF-8;LC_NUMERIC=es_ES.UTF-8;LC_TIME=en_US.UTF-8;LC_COLLATE=nl_NL.UTF-8;LC_MONETARY=it_IT.UTF-8;LC_MESSAGES=de_DE.UTF-8;LC_PAPER=C;LC_NAME=C;LC_ADDRESS=C;LC_TELEPHONE=C;LC_MEASUREMENT=C;LC_IDENTIFICATION=C'

which looks to me like proper functioning

Karl Williamson
#include <stdio.h>
#include <locale.h>

const int categories[] =        {  LC_CTYPE,            LC_TIME,      LC_NUMERIC,    LC_MONETARY,   LC_COLLATE,    LC_MESSAGES,   LC_CTYPE };
const char * category_names[] = { "LC_CTYPE",          "LC_TIME",    "LC_NUMERIC",  "LC_MONETARY", "LC_COLLATE",  "LC_MESSAGES", "LC_CTYPE" };
const char * names[]  =         { "cguevara_and_khw", "en_US.UTF-8", "es_ES.UTF-8", "it_IT.UTF-8", "nl_NL.UTF-8", "de_DE.UTF-8", "ro_RO.UTF-8" };

int main(int argc, char** argv) {
    char * name;
    unsigned int i;

    printf("setlocale(LC_ALL, \"C\") returned '%s'\n", setlocale(LC_ALL, "C"));

    for (i = 0; i < sizeof(categories)/sizeof(categories[0]); i++) {
        char * name = setlocale(categories[i], names[i]);
        printf("setlocale(%s, \"%s\") returned '%s'\n", category_names[i], names[i], (name == NULL) ? "NULL" : name);

        name = setlocale(categories[i], NULL);
        printf("setlocale(%s, NULL) returned '%s'\n", category_names[i], (name == NULL) ? "NULL" : name);
    }

    printf("setlocale(LC_ALL, NULL) returned '%s'\n", setlocale(LC_ALL, NULL));
}

Reply via email to