Search code examples
cposixlocaleerrnosetlocale

setlocale raising errno while a non-NULL value is returned


Consider the following minimalistic code fragment:

#include <stdio.h>
#include <errno.h>
#include <locale.h>

int main() {
    const char *locale = setlocale(LC_ALL, "");
    if (errno == ENOENT) {
        printf("Locale %s unavailable.\n", locale ? locale : "<unknown>");
    } else if (errno) {
        printf("setlocale() failed: errno = %d\n", errno);
        perror("setlocale() failed");
    }

    if (locale) {
        printf("Current locale: %s\n", locale);
    }

    return errno;
}

This runs successfully on a number of UNIX boxes (Solaris 8, Debian Linux 8, OpenBSD 5.8). There's a few exceptions, however.

According to the manual page, setlocale returns NULL if locale specified by the process environment (LC_ALL et al.) is unavailable (i. e. the corresponding files are missing and need to be generated with localegen or a similar tool). Testing reveals that errno is set to ENOENT in this case, but on one of Debian 7 boxes setlocale returns a valid non-NULL locale string and sets errno to ENOENT.

The other strange behaviour is exhibited by Cygwin: for each of the single-byte Cyrillic locales (ru_RU.CP1251, ru_RU.CP866, ru_RU.KOI8-R, ru_RU.ISO-8859-5), setlocale returns a correct locale string and sets errno to EILSEQ. At the same time, ru_RU.UTF-8 is not affected.

How can any of the above cases be further diagnosed?


Solution

  • POSIX does not specify how setlocale affects errno (see section ERRORS where it says “no errors are specified”). You can safely disregard the value of errno after a setlocale call.

    An implementation of setlocale should never touch errno, but it seems like some of the implementations you tested are buggy in this regard. I recommend you to file a bug report against the projects that supplied the faulty setlocale implementation.