OSDN Git Service

* libc/locale/locale.c (_setlocale_r): New implementation based on
authorcorinna <corinna>
Tue, 3 Mar 2009 09:28:44 +0000 (09:28 +0000)
committercorinna <corinna>
Tue, 3 Mar 2009 09:28:44 +0000 (09:28 +0000)
FreeBSD's setlocale.
(currentlocale): New helper function.
(loadlocale): Ditto.
(__locale_charset): New function.
(__locale_msgcharset): Rename from __locale_charset.
* libc/ctype/local.h (__lc_ctype): Remove declaration.
(__locale_charset): Declare.
* libc/ctype/iswalpha.c (iswalpha): Call __locale_charset instead of
using __lc_ctype directly.  Only compare against the charset alone.
* libc/ctype/iswblank.c (iswblank): Ditto.
* libc/ctype/iswcntrl.c (iswcntrl): Ditto.
* libc/ctype/iswprint.c (iswprint): Ditto.
* libc/ctype/iswpunct.c (iswpunct): Ditto.
* libc/ctype/iswspace.c (iswspace): Ditto.
* libc/ctype/towlower.c (towlower): Ditto.
* libc/ctype/towupper.c (towupper): Ditto.
* libc/stdlib/mbtowc_r.c (_mbtowc_r): Ditto.
* libc/stdlib/wctomb_r.c (_wctomb_r): Ditto.
* libc/sys/linux/intl/loadmsgcat.c (_nl_init_domain_conv): Call
__locale_msgcharset instead of __locale_charset.

14 files changed:
newlib/ChangeLog
newlib/libc/ctype/iswalpha.c
newlib/libc/ctype/iswblank.c
newlib/libc/ctype/iswcntrl.c
newlib/libc/ctype/iswprint.c
newlib/libc/ctype/iswpunct.c
newlib/libc/ctype/iswspace.c
newlib/libc/ctype/local.h
newlib/libc/ctype/towlower.c
newlib/libc/ctype/towupper.c
newlib/libc/locale/locale.c
newlib/libc/stdlib/mbtowc_r.c
newlib/libc/stdlib/wctomb_r.c
newlib/libc/sys/linux/intl/loadmsgcat.c

index bab663c..3e40182 100644 (file)
@@ -1,3 +1,27 @@
+2009-03-03  Corinna Vinschen  <corinna@vinschen.de>
+
+       * libc/locale/locale.c (_setlocale_r): New implementation based on
+       FreeBSD's setlocale.
+       (currentlocale): New helper function.
+       (loadlocale): Ditto.
+       (__locale_charset): New function.
+       (__locale_msgcharset): Rename from __locale_charset.
+       * libc/ctype/local.h (__lc_ctype): Remove declaration.
+       (__locale_charset): Declare.
+       * libc/ctype/iswalpha.c (iswalpha): Call __locale_charset instead of
+       using __lc_ctype directly.  Only compare against the charset alone.
+       * libc/ctype/iswblank.c (iswblank): Ditto.
+       * libc/ctype/iswcntrl.c (iswcntrl): Ditto.
+       * libc/ctype/iswprint.c (iswprint): Ditto.
+       * libc/ctype/iswpunct.c (iswpunct): Ditto.
+       * libc/ctype/iswspace.c (iswspace): Ditto.
+       * libc/ctype/towlower.c (towlower): Ditto.
+       * libc/ctype/towupper.c (towupper): Ditto.
+       * libc/stdlib/mbtowc_r.c (_mbtowc_r): Ditto.
+       * libc/stdlib/wctomb_r.c (_wctomb_r): Ditto.
+       * libc/sys/linux/intl/loadmsgcat.c (_nl_init_domain_conv): Call
+       __locale_msgcharset instead of __locale_charset.
+
 2009-03-02  Jeff Johnston  <jjohnstn@redhat.com>
 
        * libc/stdlib/wctomb_r.c (_wctomb_r): When checking single-byte
@@ -33,8 +57,7 @@
 2009-02-25  Corinna Vinschen  <corinna@vinschen.de>
 
        * libc/stdlib/mbtowc_r.c (_mbtowc_r): Remove conversion of 5 and 6 
-       byte UTF-8
-       sequences since they are invalid in the Unicode standard.
+       byte UTF-8 sequences since they are invalid in the Unicode standard.
        Handle surrogate pairs in case of wchar_t == UTF-16.
        * libc/stdlib/wctomb_r.c (_wctomb_r): Don't convert invalid Unicode 
        wchar_t values beyond 0x10ffff into UTF-8 chars.  Handle surrogate 
index 7f8de8e..a2c9cf9 100644 (file)
@@ -69,29 +69,25 @@ No supporting OS subroutines are required.
 int
 _DEFUN(iswalpha,(c), wint_t c)
 {
-  int unicode = 0;
-  if (__lc_ctype[0] == 'C' && __lc_ctype[1] == '\0')
-    {
-      unicode = 0;
-      /* fall-through */ 
-    }
 #ifdef _MB_CAPABLE
-  else if (!strcmp (__lc_ctype, "C-JIS"))
+  int unicode = 0;
+
+  if (!strcmp (__locale_charset (), "JIS"))
     {
       c = __jp2uc (c, JP_JIS);
       unicode = 1;
     }
-  else if (!strcmp (__lc_ctype, "C-SJIS"))
+  else if (!strcmp (__locale_charset (), "SJIS"))
     {
       c = __jp2uc (c, JP_SJIS);
       unicode = 1;
     }
-  else if (!strcmp (__lc_ctype, "C-EUCJP"))
+  else if (!strcmp (__locale_charset (), "EUCJP"))
     {
       c = __jp2uc (c, JP_EUCJP);
       unicode = 1;
     }
-  else if (!strcmp (__lc_ctype, "C-UTF-8"))
+  else if (!strcmp (__locale_charset (), "UTF-8"))
     {
       unicode = 1;
     }
index 48205bb..4db8ae0 100644 (file)
@@ -65,29 +65,25 @@ No supporting OS subroutines are required.
 int
 _DEFUN(iswblank,(c), wint_t c)
 {
-  int unicode = 0;
-  if (__lc_ctype[0] == 'C' && __lc_ctype[1] == '\0')
-    {
-      unicode = 0;
-      /* fall-through */ 
-    }
 #ifdef _MB_CAPABLE
-  else if (!strcmp (__lc_ctype, "C-JIS"))
+  int unicode = 0;
+
+  if (!strcmp (__locale_charset (), "JIS"))
     {
       c = __jp2uc (c, JP_JIS);
       unicode = 1;
     }
-  else if (!strcmp (__lc_ctype, "C-SJIS"))
+  else if (!strcmp (__locale_charset (), "SJIS"))
     {
       c = __jp2uc (c, JP_SJIS);
       unicode = 1;
     }
-  else if (!strcmp (__lc_ctype, "C-EUCJP"))
+  else if (!strcmp (__locale_charset (), "EUCJP"))
     {
       c = __jp2uc (c, JP_EUCJP);
       unicode = 1;
     }
-  else if (!strcmp (__lc_ctype, "C-UTF-8"))
+  else if (!strcmp (__locale_charset (), "UTF-8"))
     {
       unicode = 1;
     }
index 15ff1fa..b9f9460 100644 (file)
@@ -65,29 +65,25 @@ No supporting OS subroutines are required.
 int
 _DEFUN(iswcntrl,(c), wint_t c)
 {
-  int unicode = 0;
-  if (__lc_ctype[0] == 'C' && __lc_ctype[1] == '\0')
-    {
-      unicode = 0;
-      /* fall-through */ 
-    }
 #ifdef _MB_CAPABLE
-  else if (!strcmp (__lc_ctype, "C-JIS"))
+  int unicode = 0;
+
+  if (!strcmp (__locale_charset (), "JIS"))
     {
       c = __jp2uc (c, JP_JIS);
       unicode = 1;
     }
-  else if (!strcmp (__lc_ctype, "C-SJIS"))
+  else if (!strcmp (__locale_charset (), "SJIS"))
     {
       c = __jp2uc (c, JP_SJIS);
       unicode = 1;
     }
-  else if (!strcmp (__lc_ctype, "C-EUCJP"))
+  else if (!strcmp (__locale_charset (), "EUCJP"))
     {
       c = __jp2uc (c, JP_EUCJP);
       unicode = 1;
     }
-  else if (!strcmp (__lc_ctype, "C-UTF-8"))
+  else if (!strcmp (__locale_charset (), "UTF-8"))
     {
       unicode = 1;
     }
index 6c0cc55..814a26b 100644 (file)
@@ -69,29 +69,25 @@ No supporting OS subroutines are required.
 int
 _DEFUN(iswprint,(c), wint_t c)
 {
-  int unicode = 0;
-  if (__lc_ctype[0] == 'C' && __lc_ctype[1] == '\0')
-    {
-      unicode = 0;
-      /* fall-through */ 
-    }
 #ifdef _MB_CAPABLE
-  else if (!strcmp (__lc_ctype, "C-JIS"))
+  int unicode = 0;
+
+  if (!strcmp (__locale_charset (), "JIS"))
     {
       c = __jp2uc (c, JP_JIS);
       unicode = 1;
     }
-  else if (!strcmp (__lc_ctype, "C-SJIS"))
+  else if (!strcmp (__locale_charset (), "SJIS"))
     {
       c = __jp2uc (c, JP_SJIS);
       unicode = 1;
     }
-  else if (!strcmp (__lc_ctype, "C-EUCJP"))
+  else if (!strcmp (__locale_charset (), "EUCJP"))
     {
       c = __jp2uc (c, JP_EUCJP);
       unicode = 1;
     }
-  else if (!strcmp (__lc_ctype, "C-UTF-8"))
+  else if (!strcmp (__locale_charset (), "UTF-8"))
     {
       unicode = 1;
     }
index c6a4eda..1f19b66 100644 (file)
@@ -69,29 +69,25 @@ No supporting OS subroutines are required.
 int
 _DEFUN(iswpunct,(c), wint_t c)
 {
-  int unicode = 0;
-  if (__lc_ctype[0] == 'C' && __lc_ctype[1] == '\0')
-    {
-      unicode = 0;
-      /* fall-through */ 
-    }
 #ifdef _MB_CAPABLE
-  else if (!strcmp (__lc_ctype, "C-JIS"))
+  int unicode = 0;
+
+  if (!strcmp (__locale_charset (), "JIS"))
     {
       c = __jp2uc (c, JP_JIS);
       unicode = 1;
     }
-  else if (!strcmp (__lc_ctype, "C-SJIS"))
+  else if (!strcmp (__locale_charset (), "SJIS"))
     {
       c = __jp2uc (c, JP_SJIS);
       unicode = 1;
     }
-  else if (!strcmp (__lc_ctype, "C-EUCJP"))
+  else if (!strcmp (__locale_charset (), "EUCJP"))
     {
       c = __jp2uc (c, JP_EUCJP);
       unicode = 1;
     }
-  else if (!strcmp (__lc_ctype, "C-UTF-8"))
+  else if (!strcmp (__locale_charset (), "UTF-8"))
     {
       unicode = 1;
     }
index e10a35d..b9c7439 100644 (file)
@@ -65,29 +65,25 @@ No supporting OS subroutines are required.
 int
 _DEFUN(iswspace,(c), wint_t c)
 {
-  int unicode = 0;
-  if (__lc_ctype[0] == 'C' && __lc_ctype[1] == '\0')
-    {
-      unicode = 0;
-      /* fall-through */ 
-    }
 #ifdef _MB_CAPABLE
-  else if (!strcmp (__lc_ctype, "C-JIS"))
+  int unicode = 0;
+
+  if (!strcmp (__locale_charset (), "JIS"))
     {
       c = __jp2uc (c, JP_JIS);
       unicode = 1;
     }
-  else if (!strcmp (__lc_ctype, "C-SJIS"))
+  else if (!strcmp (__locale_charset (), "SJIS"))
     {
       c = __jp2uc (c, JP_SJIS);
       unicode = 1;
     }
-  else if (!strcmp (__lc_ctype, "C-EUCJP"))
+  else if (!strcmp (__locale_charset (), "EUCJP"))
     {
       c = __jp2uc (c, JP_EUCJP);
       unicode = 1;
     }
-  else if (!strcmp (__lc_ctype, "C-UTF-8"))
+  else if (!strcmp (__locale_charset (), "UTF-8"))
     {
       unicode = 1;
     }
index b1eca42..9471607 100644 (file)
@@ -20,7 +20,7 @@
 #define WC_UPPER       11
 #define WC_XDIGIT      12
 
-extern char __lc_ctype[12];
+extern char *__locale_charset ();
 
 /* Japanese encoding types supported */
 #define JP_JIS         1
index 89873c2..c3fcb77 100644 (file)
@@ -69,30 +69,25 @@ No supporting OS subroutines are required.
 wint_t
 _DEFUN(towlower,(c), wint_t c)
 {
+#ifdef _MB_CAPABLE
   int unicode = 0;
 
-  if (__lc_ctype[0] == 'C' && __lc_ctype[1] == '\0')
-    {
-      unicode = 0;
-      /* fall-through */ 
-    }
-#ifdef _MB_CAPABLE
-  else if (!strcmp (__lc_ctype, "C-JIS"))
+  if (!strcmp (__locale_charset (), "JIS"))
     {
       c = __jp2uc (c, JP_JIS);
       unicode = 1;
     }
-  else if (!strcmp (__lc_ctype, "C-SJIS"))
+  else if (!strcmp (__locale_charset (), "SJIS"))
     {
       c = __jp2uc (c, JP_SJIS);
       unicode = 1;
     }
-  else if (!strcmp (__lc_ctype, "C-EUCJP"))
+  else if (!strcmp (__locale_charset (), "EUCJP"))
     {
       c = __jp2uc (c, JP_EUCJP);
       unicode = 1;
     }
-  else if (!strcmp (__lc_ctype, "C-UTF-8"))
+  else if (!strcmp (__locale_charset (), "UTF-8"))
     {
       unicode = 1;
     }
index ec6c4ff..385dc9b 100644 (file)
@@ -69,30 +69,25 @@ No supporting OS subroutines are required.
 wint_t
 _DEFUN(towupper,(c), wint_t c)
 {
+#ifdef _MB_CAPABLE
   int unicode = 0;
 
-  if (__lc_ctype[0] == 'C' && __lc_ctype[1] == '\0')
-    {
-      unicode = 0;
-      /* fall-through */ 
-    }
-#ifdef _MB_CAPABLE
-  else if (!strcmp (__lc_ctype, "C-JIS"))
+  if (!strcmp (__locale_charset (), "JIS"))
     {
       c = __jp2uc (c, JP_JIS);
       unicode = 1;
     }
-  else if (!strcmp (__lc_ctype, "C-SJIS"))
+  else if (!strcmp (__locale_charset (), "SJIS"))
     {
       c = __jp2uc (c, JP_SJIS);
       unicode = 1;
     }
-  else if (!strcmp (__lc_ctype, "C-EUCJP"))
+  else if (!strcmp (__locale_charset (), "EUCJP"))
     {
       c = __jp2uc (c, JP_EUCJP);
       unicode = 1;
     }
-  else if (!strcmp (__lc_ctype, "C-UTF-8"))
+  else if (!strcmp (__locale_charset (), "UTF-8"))
     {
       unicode = 1;
     }
index d48a53a..7c92d0c 100644 (file)
@@ -42,13 +42,16 @@ execution environment for international collating and formatting
 information; <<localeconv>> reports on the settings of the current
 locale.
 
-This is a minimal implementation, supporting only the required <<"C">>
-value for <[locale]>; strings representing other locales are not
-honored unless _MB_CAPABLE is defined in which case three new
-extensions are allowed for LC_CTYPE or LC_MESSAGES only: <<"C-JIS">>, 
-<<"C-EUCJP">>, <<"C-SJIS">>, or <<"C-ISO-8859-1">>.  (<<"">> is 
-also accepted; it represents the default locale
-for an implementation, here equivalent to <<"C">>.)
+This is a minimal implementation, supporting only the required <<"POSIX">>
+and <<"C">> values for <[locale]>; strings representing other locales are not
+honored unless _MB_CAPABLE is defined in which case POSIX locale strings
+are allowed, plus five extensions supported for backward compatibility with
+older implementations using newlib: <<"C-UTF-8">>, <<"C-JIS">>, <<"C-EUCJP">>,
+<<"C-SJIS">>, or <<"C-ISO-8859-x">> with 1 <= x <= 15.  Even when using
+POSIX locale strings, the only charsets allowed are <<"UTF-8">>, <<"JIS">>,
+<<"EUCJP">>, <<"SJIS">>, or <<"ISO-8859-x">> with 1 <= x <= 15.  (<<"">> is 
+also accepted; if given, the settings are read from the corresponding
+LC_* environment variables and $LANG according to POSIX rules.
 
 If you use <<NULL>> as the <[locale]> argument, <<setlocale>> returns
 a pointer to the string representing the current locale (always
@@ -66,9 +69,13 @@ in effect.
 <[reent]> is a pointer to a reentrancy structure.
 
 RETURNS
-<<setlocale>> returns either a pointer to a string naming the locale
-currently in effect (always <<"C">> for this implementation, or, if
-the locale request cannot be honored, <<NULL>>.
+A successful call to <<setlocale>> returns a pointer to a string
+associated with the specified category for the new locale.  The string
+returned by <<setlocale>> is such that a subsequent call using that
+string will restore that category (or all categories in case of LC_ALL),
+to that state.  The application shall not modify the string returned
+which may be overwritten by a subsequent call to <<setlocale>>.
+On error, <<setlocale>> returns <<NULL>>.
 
 <<localeconv>> returns a pointer to a structure of type <<lconv>>,
 which describes the formatting and collating conventions in effect (in
@@ -81,16 +88,50 @@ implementations is the C locale.
 No supporting OS subroutines are required.
 */
 
+/* Parts of this code are originally taken from FreeBSD. */
 /*
- * setlocale, localeconv : internationalize your locale.
- *                         (Only "C" or null supported).
+ * Copyright (c) 1996 - 2002 FreeBSD Project
+ * Copyright (c) 1991, 1993
+ *      The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  */
 
 #include <newlib.h>
+#include <errno.h>
 #include <locale.h>
 #include <string.h>
 #include <limits.h>
 #include <reent.h>
+#include <stdlib.h>
+
+#define _LC_LAST      7
+#define ENCODING_LEN 31
 
 #ifdef __CYGWIN__
 int __declspec(dllexport) __mb_cur_max = 1;
@@ -109,11 +150,48 @@ static _CONST struct lconv lconv =
   CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX,
 };
 
+#ifdef _MB_CAPABLE
+/*
+ * Category names for getenv()
+ */
+static char *categories[_LC_LAST] = {
+  "LC_ALL",
+  "LC_COLLATE",
+  "LC_CTYPE",
+  "LC_MONETARY",
+  "LC_NUMERIC",
+  "LC_TIME",
+  "LC_MESSAGES",
+};
+
+/*
+ * Current locales for each category
+ */
+static char current_categories[_LC_LAST][ENCODING_LEN + 1] = {
+    "C",
+    "C",
+    "C",
+    "C",
+    "C",
+    "C",
+    "C",
+};
+
+/*
+ * The locales we are going to try and load
+ */
+static char new_categories[_LC_LAST][ENCODING_LEN + 1];
+static char saved_categories[_LC_LAST][ENCODING_LEN + 1];
+
+static char current_locale_string[_LC_LAST * (ENCODING_LEN + 1/*"/"*/ + 1)];
+static char *currentlocale(void);
+static char *loadlocale(struct _reent *, int);
+static const char *__get_locale_env(struct _reent *, int);
 
-char * _EXFUN(__locale_charset,(_VOID));
+#endif
 
-static char *charset = "ISO-8859-1";
-char __lc_ctype[12] = "C";
+static char lc_ctype_charset[ENCODING_LEN + 1] = "ISO-8859-1";
+static char lc_message_charset[ENCODING_LEN + 1] = "ISO-8859-1";
 
 char *
 _DEFUN(_setlocale_r, (p, category, locale),
@@ -124,154 +202,303 @@ _DEFUN(_setlocale_r, (p, category, locale),
 #ifndef _MB_CAPABLE
   if (locale)
     { 
-      if (strcmp (locale, "C") && strcmp (locale, ""))
-        return 0;
+      if (strcmp (locale, "POSIX") && strcmp (locale, "C")
+         && strcmp (locale, ""))
+        return NULL;
       p->_current_category = category;  
       p->_current_locale = locale;
     }
   return "C";
 #else
-  static char last_lc_ctype[12] = "C";
-  static char lc_messages[12] = "C";
-  static char last_lc_messages[12] = "C";
+  int i, j, len, saverr;
+  const char *env, *r;
 
-  if (locale)
+  if (category < LC_ALL || category >= _LC_LAST)
     {
-      char *locale_name = (char *)locale;
-      if (category != LC_CTYPE && category != LC_MESSAGES) 
-        { 
-          if (strcmp (locale, "C") && strcmp (locale, ""))
-            return 0;
-          if (category == LC_ALL)
-            {
-              strcpy (last_lc_ctype, __lc_ctype);
-              strcpy (__lc_ctype, "C");
-              strcpy (last_lc_messages, lc_messages);
-              strcpy (lc_messages, "C");
-              __mb_cur_max = 1;
-            }
-        }
-      else
-        {
-          if (locale[0] == 'C' && locale[1] == '-')
-            {
-              switch (locale[2])
-                {
-                case 'U':
-                  if (strcmp (locale, "C-UTF-8"))
-                    return 0;
-                break;
-                case 'J':
-                  if (strcmp (locale, "C-JIS"))
-                    return 0;
-                break;
-                case 'E':
-                  if (strcmp (locale, "C-EUCJP"))
-                    return 0;
-                break;
-                case 'S':
-                  if (strcmp (locale, "C-SJIS"))
-                    return 0;
-                break;
-                case 'I':
-                  if (strcmp (locale, "C-ISO-8859-1"))
-                    return 0;
-                break;
-                default:
-                  return 0;
-                }
-            }
-          else 
-            {
-              if (strcmp (locale, "C") && strcmp (locale, ""))
-                return 0;
-              locale_name = "C"; /* C is always the default locale */
-            }
-
-          if (category == LC_CTYPE)
-            {
-              strcpy (last_lc_ctype, __lc_ctype);
-              strcpy (__lc_ctype, locale_name);
-
-              __mb_cur_max = 1;
-              if (locale[1] == '-')
-                {
-                  switch (locale[2])
-                    {
-                    case 'U':
-                      __mb_cur_max = 6;
-                    break;
-                    case 'J':
-                      __mb_cur_max = 8;
-                    break;
-                    case 'E':
-                      __mb_cur_max = 2;
-                    break;
-                    case 'S':
-                      __mb_cur_max = 2;
-                    break;
-                    case 'I':
-                    default:
-                      __mb_cur_max = 1;
-                    }
-                }
-            }
-          else
-            {
-              strcpy (last_lc_messages, lc_messages);
-              strcpy (lc_messages, locale_name);
-
-              charset = "ISO-8859-1";
-              if (locale[1] == '-')
-                {
-                  switch (locale[2])
-                    {
-                    case 'U':
-                      charset = "UTF-8";
-                    break;
-                    case 'J':
-                      charset = "JIS";
-                    break;
-                    case 'E':
-                      charset = "EUCJP";
-                    break;
-                    case 'S':
-                      charset = "SJIS";
-                    break;
-                    case 'I':
-                      charset = "ISO-8859-1";
-                    break;
-                    default:
-                      return 0;
-                    }
-                }
-            }
-        }
-      p->_current_category = category;  
-      p->_current_locale = locale;
+      p->_errno = EINVAL;
+      return NULL;
+    }
+
+  if (locale == NULL)
+    return category != LC_ALL ? current_categories[category] : currentlocale();
+
+  /*
+   * Default to the current locale for everything.
+   */
+  for (i = 1; i < _LC_LAST; ++i)
+    strcpy (new_categories[i], current_categories[i]);
 
-      if (category == LC_CTYPE)
-        return last_lc_ctype;
-      else if (category == LC_MESSAGES)
-        return last_lc_messages;
+  /*
+   * Now go fill up new_categories from the locale argument
+   */
+  if (!*locale)
+    {
+      if (category == LC_ALL)
+       {
+         for (i = 1; i < _LC_LAST; ++i)
+           {
+             env = __get_locale_env (p, i);
+             if (strlen (env) > ENCODING_LEN)
+               {
+                 p->_errno = EINVAL;
+                 return NULL;
+               }
+             strcpy (new_categories[i], env);
+           }
+       }
+      else
+       {
+         env = __get_locale_env (p, category);
+         if (strlen (env) > ENCODING_LEN)
+           {
+             p->_errno = EINVAL;
+             return NULL;
+           }
+         strcpy (new_categories[category], env);
+       }
+    }
+  else if (category != LC_ALL)
+    {
+      if (strlen (locale) > ENCODING_LEN)
+       {
+         p->_errno = EINVAL;
+         return NULL;
+       }
+      strcpy (new_categories[category], locale);
     }
   else
     {
-      if (category == LC_CTYPE)
-        return __lc_ctype;
-      else if (category == LC_MESSAGES)
-        return lc_messages;
+      if ((r = strchr (locale, '/')) == NULL)
+       {
+         if (strlen (locale) > ENCODING_LEN)
+           {
+             p->_errno = EINVAL;
+             return NULL;
+           }
+         for (i = 1; i < _LC_LAST; ++i)
+           strcpy (new_categories[i], locale);
+       }
+      else
+       {
+         for (i = 1; r[1] == '/'; ++r)
+           ;
+         if (!r[1])
+           {
+             p->_errno = EINVAL;
+             return NULL;  /* Hmm, just slashes... */
+           }
+         do
+           {
+             if (i == _LC_LAST)
+               break;  /* Too many slashes... */
+             if ((len = r - locale) > ENCODING_LEN)
+               {
+                 p->_errno = EINVAL;
+                 return NULL;
+               }
+             strlcpy (new_categories[i], locale, len + 1);
+             i++;
+             while (*r == '/')
+               r++;
+             locale = r;
+             while (*r && *r != '/')
+               r++;
+           }
+         while (*locale);
+         while (i < _LC_LAST)
+           {
+             strcpy (new_categories[i], new_categories[i-1]);
+             i++;
+           }
+       }
     }
-  return "C";
+
+  if (category != LC_ALL)
+    return loadlocale (p, category);
+
+  for (i = 1; i < _LC_LAST; ++i)
+    {
+      strcpy (saved_categories[i], current_categories[i]);
+      if (loadlocale (p, i) == NULL)
+       {
+         saverr = p->_errno;
+         for (j = 1; j < i; j++)
+           {
+             strcpy (new_categories[j], saved_categories[j]);
+             if (loadlocale (p, j) == NULL)
+               {
+                 strcpy (new_categories[j], "C");
+                 loadlocale (p, j);
+               }
+           }
+         p->_errno = saverr;
+         return NULL;
+       }
+    }
+  return currentlocale ();
+#endif
+}
+
+#ifdef _MB_CAPABLE
+static char *
+currentlocale()
+{
+        int i;
+
+        (void)strcpy(current_locale_string, current_categories[1]);
+
+        for (i = 2; i < _LC_LAST; ++i)
+                if (strcmp(current_categories[1], current_categories[i])) {
+                        for (i = 2; i < _LC_LAST; ++i) {
+                                (void)strcat(current_locale_string, "/");
+                                (void)strcat(current_locale_string,
+                                             current_categories[i]);
+                        }
+                        break;
+                }
+        return (current_locale_string);
+}
 #endif
+
+#ifdef _MB_CAPABLE
+static char *
+loadlocale(struct _reent *p, int category)
+{
+  /* At this point a full-featured system would just load the locale
+     specific data from the locale files.
+     What we do here for now is to check the incoming string for correctness.
+     The string must be in one of the allowed locale strings, either
+     one in POSIX-style, or one in the old newlib style to maintain
+     backward compatibility.  If the local string is correct, the charset
+     is extracted and stored in lc_ctype_charset or lc_message_charset
+     dependent on the cateogry. */
+  char *locale = new_categories[category];
+  char charset[ENCODING_LEN + 1];
+  unsigned long val;
+  char *end;
+  int mbc_max;
   
+  /* "POSIX" is translated to "C", as on Linux. */
+  if (!strcmp (locale, "POSIX"))
+    strcpy (locale, "C");
+  if (!strcmp (locale, "C"))                           /* Default "C" locale */
+    strcpy (charset, "ISO-8859-1");
+  else if (locale[0] == 'C' && locale[1] == '-')       /* Old newlib style */
+       strcpy (charset, locale + 2);
+  else                                                 /* POSIX style */
+    {
+      char *c = locale;
+
+      /* Don't use ctype macros here, they might be localized. */
+      /* Language */
+      if (c[0] <= 'a' || c[0] >= 'z'
+         || c[1] <= 'a' || c[1] >= 'z')
+       return NULL;
+      c += 2;
+      if (c[0] == '_')
+        {
+         /* Territory */
+         ++c;
+         if (c[0] <= 'A' || c[0] >= 'Z'
+             || c[1] <= 'A' || c[1] >= 'Z')
+           return NULL;
+         c += 2;
+       }
+      if (c[0] == '.')
+       {
+         /* Charset */
+         strcpy (charset, c + 1);
+         if ((c = strchr (charset, '@')))
+           /* Strip off modifier */
+           *c = '\0';
+       }
+      else if (c[0] == '\0' || c[0] == '@')
+       /* End of string or just a modifier */
+       strcpy (charset, "ISO-8859-1");
+      else
+       /* Invalid string */
+       return NULL;
+    }
+  /* We only support this subset of charsets. */
+  switch (charset[0])
+    {
+    case 'U':
+      if (strcmp (charset, "UTF-8"))
+       return NULL;
+      mbc_max = 6;
+    break;
+    case 'J':
+      if (strcmp (charset, "JIS"))
+       return NULL;
+      mbc_max = 8;
+    break;
+    case 'E':
+      if (strcmp (charset, "EUCJP"))
+       return NULL;
+      mbc_max = 2;
+    break;
+    case 'S':
+      if (strcmp (charset, "SJIS"))
+       return NULL;
+      mbc_max = 2;
+    break;
+    case 'I':
+    default:
+      /* Must be exactly one of ISO-8859-1, [...] ISO-8859-15. */
+      if (strncmp (charset, "ISO-8859-", 9))
+       return NULL;
+      val = strtol (charset + 9, &end, 10);
+      if (val < 1 || val > 15 || *end)
+       return NULL;
+      mbc_max = 1;
+      break;
+    }
+  if (category == LC_CTYPE)
+    {
+      strcpy (lc_ctype_charset, charset);
+      __mb_cur_max = mbc_max;
+    }
+  else if (category == LC_MESSAGES)
+    strcpy (lc_message_charset, charset);
+  p->_current_category = category;  
+  p->_current_locale = locale;
+  return strcpy(current_categories[category], new_categories[category]);
 }
 
+static const char *
+__get_locale_env(struct _reent *p, int category)
+{
+  const char *env;
+
+  /* 1. check LC_ALL. */
+  env = _getenv_r (p, categories[0]);
+
+  /* 2. check LC_* */
+  if (env == NULL || !*env)
+    env = _getenv_r (p, categories[category]);
+
+  /* 3. check LANG */
+  if (env == NULL || !*env)
+    env = _getenv_r (p, "LANG");
+
+  /* 4. if none is set, fall to "C" */
+  if (env == NULL || !*env)
+    env = "C";
+
+  return env;
+}
+#endif
+
 char *
 _DEFUN_VOID(__locale_charset)
 {
-  return charset;
+  return lc_ctype_charset;
+}
+
+char *
+_DEFUN_VOID(__locale_msgcharset)
+{
+  return lc_message_charset;
 }
 
 struct lconv *
index 00021be..693c06c 100644 (file)
@@ -45,8 +45,6 @@ static JIS_ACTION JIS_action_table[JIS_S_NUM][JIS_C_NUM] = {
 /* we override the mbstate_t __count field for more complex encodings and use it store a state value */
 #define __state __count
 
-extern char __lc_ctype[12];
-
 int
 _DEFUN (_mbtowc_r, (r, pwc, s, n, state),
         struct _reent *r   _AND
@@ -65,9 +63,9 @@ _DEFUN (_mbtowc_r, (r, pwc, s, n, state),
     return -2;
 
 #ifdef _MB_CAPABLE
-  if (strlen (__lc_ctype) <= 1)
+  if (strlen (__locale_charset ()) <= 1)
     { /* fall-through */ }
-  else if (!strcmp (__lc_ctype, "C-UTF-8"))
+  else if (!strcmp (__locale_charset (), "UTF-8"))
     {
       int ch;
       int i = 0;
@@ -221,7 +219,7 @@ _DEFUN (_mbtowc_r, (r, pwc, s, n, state),
       else
        return -1;
     }      
-  else if (!strcmp (__lc_ctype, "C-SJIS"))
+  else if (!strcmp (__locale_charset (), "SJIS"))
     {
       int ch;
       int i = 0;
@@ -251,7 +249,7 @@ _DEFUN (_mbtowc_r, (r, pwc, s, n, state),
            return -1;
        }
     }
-  else if (!strcmp (__lc_ctype, "C-EUCJP"))
+  else if (!strcmp (__locale_charset (), "EUCJP"))
     {
       int ch;
       int i = 0;
@@ -281,7 +279,7 @@ _DEFUN (_mbtowc_r, (r, pwc, s, n, state),
            return -1;
        }
     }
-  else if (!strcmp (__lc_ctype, "C-JIS"))
+  else if (!strcmp (__locale_charset (), "JIS"))
     {
       JIS_STATE curr_state;
       JIS_ACTION action;
index b5205fc..7178514 100644 (file)
@@ -8,8 +8,6 @@
 /* for some conversions, we use the __count field as a place to store a state value */
 #define __state __count
 
-extern char __lc_ctype[12];
-
 int
 _DEFUN (_wctomb_r, (r, s, wchar, state),
         struct _reent *r     _AND 
@@ -22,9 +20,9 @@ _DEFUN (_wctomb_r, (r, s, wchar, state),
      is 4, as is the case on cygwin.  */
   wint_t wchar = _wchar;
 
-  if (strlen (__lc_ctype) <= 1)
+  if (strlen (__locale_charset ()) <= 1)
     { /* fall-through */ }
-  else if (!strcmp (__lc_ctype, "C-UTF-8"))
+  else if (!strcmp (__locale_charset (), "UTF-8"))
     {
       if (s == NULL)
         return 0; /* UTF-8 encoding is not state-dependent */
@@ -106,7 +104,7 @@ _DEFUN (_wctomb_r, (r, s, wchar, state),
          return -1;
        }
     }
-  else if (!strcmp (__lc_ctype, "C-SJIS"))
+  else if (!strcmp (__locale_charset (), "SJIS"))
     {
       unsigned char char2 = (unsigned char)wchar;
       unsigned char char1 = (unsigned char)(wchar >> 8);
@@ -130,7 +128,7 @@ _DEFUN (_wctomb_r, (r, s, wchar, state),
            }
         }
     }
-  else if (!strcmp (__lc_ctype, "C-EUCJP"))
+  else if (!strcmp (__locale_charset (), "EUCJP"))
     {
       unsigned char char2 = (unsigned char)wchar;
       unsigned char char1 = (unsigned char)(wchar >> 8);
@@ -154,7 +152,7 @@ _DEFUN (_wctomb_r, (r, s, wchar, state),
            }
         }
     }
-  else if (!strcmp (__lc_ctype, "C-JIS"))
+  else if (!strcmp (__locale_charset (), "JIS"))
     {
       int cnt = 0; 
       unsigned char char2 = (unsigned char)wchar;
index b5f722e..0e5464a 100644 (file)
@@ -266,8 +266,8 @@ _nl_init_domain_conv (domain_file, domain, domainbinding)
                  outcharset = (*_nl_current[LC_CTYPE])->values[_NL_ITEM_INDEX (CODESET)].string;
 # else
 #  if HAVE_ICONV
-                 extern const char *__locale_charset (void);
-                 outcharset = __locale_charset ();
+                 extern const char *__locale_msgcharset (void);
+                 outcharset = __locale_msgcharset ();
 #  endif
 # endif
                }