localename: Improvements for MacOS X and Cygwin.
[gnulib.git] / lib / localename.c
index 1310cb5..ceed70f 100644 (file)
@@ -31,9 +31,9 @@
 
 #include <stdlib.h>
 #include <locale.h>
+#include <string.h>
 
 #if HAVE_CFLOCALECOPYCURRENT || HAVE_CFPREFERENCESCOPYAPPVALUE
-# include <string.h>
 # include <CoreFoundation/CFString.h>
 # if HAVE_CFLOCALECOPYCURRENT
 #  include <CoreFoundation/CFLocale.h>
@@ -46,7 +46,7 @@
 # define WIN32_NATIVE
 #endif
 
-#ifdef WIN32_NATIVE
+#if defined WIN32_NATIVE || defined __CYGWIN__ /* WIN32 or Cygwin */
 # define WIN32_LEAN_AND_MEAN
 # include <windows.h>
 /* List of language codes, sorted by value:
@@ -1394,7 +1394,7 @@ gl_locale_name_canonicalize (char *name)
 #endif
 
 
-#ifdef WIN32_NATIVE
+#if defined WIN32_NATIVE || defined __CYGWIN__ /* WIN32 or Cygwin */
 
 /* Canonicalize a Win32 native locale name to a Unix locale name.
    NAME is a sufficiently large buffer.
@@ -2518,6 +2518,30 @@ gl_locale_name_posix (int category, const char *categoryname)
 #if defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES && defined HAVE_LOCALE_NULL
   return setlocale (category, NULL);
 #else
+  /* On other systems we ignore what setlocale reports and instead look at the
+     environment variables directly.  This is necessary
+       1. on systems which have a facility for customizing the default locale
+          (MacOS X, native Windows, Cygwin) and where the system's setlocale()
+          function ignores this default locale (MacOS X, Cygwin), in two cases:
+          a. when the user missed to use the setlocale() override from libintl
+             (for example by not including <libintl.h>),
+          b. when setlocale supports only the "C" locale, such as on Cygwin
+             1.5.x.  In this case even the override from libintl cannot help.
+       2. on all systems where setlocale supports only the "C" locale.  */
+  /* Strictly speaking, it is a POSIX violation to look at the environment
+     variables regardless whether setlocale has been called or not.  POSIX
+     says:
+         "For C-language programs, the POSIX locale shall be the
+          default locale when the setlocale() function is not called."
+     But we assume that all programs that use internationalized APIs call
+     setlocale (LC_ALL, "").  */
+  return gl_locale_name_environ (category, categoryname);
+#endif
+}
+
+const char *
+gl_locale_name_environ (int category, const char *categoryname)
+{
   const char *retval;
 
   /* Setting of LC_ALL overrides all other.  */
@@ -2531,10 +2555,21 @@ gl_locale_name_posix (int category, const char *categoryname)
   /* Last possibility is the LANG environment variable.  */
   retval = getenv ("LANG");
   if (retval != NULL && retval[0] != '\0')
-    return retval;
+    {
+#if HAVE_CFLOCALECOPYCURRENT || HAVE_CFPREFERENCESCOPYAPPVALUE
+      /* MacOS X 10.2 or newer.
+         Ignore invalid LANG value set by the Terminal application.  */
+      if (strcmp (retval, "UTF-8") != 0)
+#endif
+#if defined __CYGWIN__
+      /* Cygwin.
+         Ignore dummy LANG value set by ~/.profile.  */
+      if (strcmp (retval, "C.UTF-8") != 0)
+#endif
+        return retval;
+    }
 
   return NULL;
-#endif
 }
 
 const char *
@@ -2547,9 +2582,28 @@ gl_locale_name_default (void)
       implementation-defined locale.  Some implementations may provide
       facilities for local installation administrators to set the default
       locale, customizing it for each location.  POSIX:2001 does not require
-      such a facility.  */
+      such a facility.
+
+     The systems with such a facility are MacOS X and Windows: They provide a
+     GUI that allows the user to choose a locale.
+       - On MacOS X, by default, none of LC_* or LANG are set.  Starting with
+         MacOS X 10.4 or 10.5, LANG is set for processes launched by the
+         'Terminal' application (but sometimes to an incorrect value "UTF-8").
+         When no environment variable is set, setlocale (LC_ALL, "") uses the
+         "C" locale.
+       - On native Windows, by default, none of LC_* or LANG are set.
+         When no environment variable is set, setlocale (LC_ALL, "") uses the
+         locale chosen by the user.
+       - On Cygwin 1.5.x, by default, none of LC_* or LANG are set.
+         When no environment variable is set, setlocale (LC_ALL, "") uses the
+         "C" locale.
+       - On Cygwin 1.7, by default, LANG is set to "C.UTF-8" when the default
+         ~/.profile is executed.
+         When no environment variable is set, setlocale (LC_ALL, "") uses the
+         "C.UTF-8" locale, which operates in the same way as the "C" locale.
+  */
 
-#if !(HAVE_CFLOCALECOPYCURRENT || HAVE_CFPREFERENCESCOPYAPPVALUE || defined(WIN32_NATIVE))
+#if !(HAVE_CFLOCALECOPYCURRENT || HAVE_CFPREFERENCESCOPYAPPVALUE || defined WIN32_NATIVE || defined __CYGWIN__)
 
   /* The system does not have a way of setting the locale, other than the
      POSIX specified environment variables.  We use C as default locale.  */
@@ -2603,7 +2657,7 @@ gl_locale_name_default (void)
 
 # endif
 
-# if defined(WIN32_NATIVE) /* WIN32, not Cygwin */
+# if defined WIN32_NATIVE || defined __CYGWIN__ /* WIN32 or Cygwin */
   {
     LCID lcid;