--- bash-2.05b/locale.c.mitr	2002-10-10 03:03:16.000000000 +0200
+++ bash-2.05b/locale.c	2002-10-10 03:16:32.000000000 +0200
@@ -47,6 +47,16 @@
    categories */
 static char *lc_all;
 
+/* tracks the value of LANG; used to provide default value for locale
+   categories */
+static char *lang;
+
+static int reload_all_locales __P((void));
+
+/* As a general rule, never EVER call setlocale (foo, ""). libc doesn't
+   know about shell variables and uses values from environment at time
+   of shell startup. */
+
 /* Set the value of default_locale and make the current locale the
    system default locale.  This should be called very early in main(). */
 void
@@ -137,15 +147,16 @@
       FREE (lc_all);
       if (value)
 	lc_all = savestring (value);
-      else if (default_locale)
-	lc_all = savestring (default_locale);
       else
 	{
 	  lc_all = (char *)xmalloc (1);
 	  lc_all[0] = '\0';
 	}
 #if defined (HAVE_SETLOCALE)
-      return (setlocale (LC_ALL, lc_all) != 0);
+      if (*lc_all != '\0')
+	return (setlocale (LC_ALL, lc_all) != 0);
+      else
+	return reload_all_locales ();
 #else
       return (1);
 #endif
@@ -155,27 +166,27 @@
   else if (var[3] == 'C' && var[4] == 'T')	/* LC_CTYPE */
     {
       if (lc_all == 0 || *lc_all == '\0')
-	return (setlocale (LC_CTYPE, value ? value : "") != 0);
+	return (setlocale (LC_CTYPE, get_locale_var ("LC_CTYPE")) != 0);
     }
   else if (var[3] == 'C' && var[4] == 'O')	/* LC_COLLATE */
     {
 #  if defined (LC_COLLATE)
       if (lc_all == 0 || *lc_all == '\0')
-	return (setlocale (LC_COLLATE, value ? value : "") != 0);
+	return (setlocale (LC_COLLATE, get_locale_var ("LC_COLLATE")) != 0);
 #  endif /* LC_COLLATE */
     }
   else if (var[3] == 'M' && var[4] == 'E')	/* LC_MESSAGES */
     {
 #  if defined (LC_MESSAGES)
       if (lc_all == 0 || *lc_all == '\0')
-	return (setlocale (LC_MESSAGES, value ? value : "") != 0);
+	return (setlocale (LC_MESSAGES, get_locale_var ("LC_MESSAGES")) != 0);
 #  endif /* LC_MESSAGES */
     }
   else if (var[3] == 'N' && var[4] == 'U')	/* LC_NUMERIC */
     {
 #  if defined (LC_NUMERIC)
       if (lc_all == 0 || *lc_all == '\0')
-	return (setlocale (LC_NUMERIC, value ? value : "") != 0);
+	return (setlocale (LC_NUMERIC, get_locale_var ("LC_NUMERIC")) != 0);
 #  endif /* LC_NUMERIC */
     }
 #endif /* HAVE_SETLOCALE */
@@ -190,7 +201,46 @@
 set_lang (var, value)
      char *var, *value;
 {
-  return ((lc_all == 0 || *lc_all == 0) ? setlocale (LC_ALL, value?value:"") != NULL : 0);
+  FREE (lang);
+  if (value)
+    lang = savestring (value);
+  else
+    {
+      lang = (char *)xmalloc (1);
+      lang[0] = '\0';
+    }
+  return ((lc_all == 0 || *lc_all == 0) ? reload_all_locales () : 0);
+}
+
+/* LC_ALL is unset or empty and a variable affecting all locales (even those
+   we don't know about) has chaged. Rebuild the whole mess.
+   Returns 1 on success, 0 on failure. */
+static int
+reload_all_locales ()
+{
+#if defined (HAVE_SETLOCALE)
+  char *locale;
+
+  locale = lang;
+  if (locale == 0 || *locale == '\0')
+    locale = default_locale;
+  if (setlocale (LC_ALL, locale) == 0)
+    return (0);
+
+  /* It doesn't matter whether we return success or failure when one of the
+     following fails, because return value of our callers is ignored ;-). */
+  setlocale (LC_CTYPE, get_locale_var ("LC_CTYPE"));
+#  if defined (LC_COLLATE)
+  setlocale (LC_COLLATE, get_locale_var ("LC_COLLATE"));
+#  endif /* LC_COLLATE */
+#  if defined (LC_MESSAGES)
+  setlocale (LC_MESSAGES, get_locale_var ("LC_MESSAGES"));
+#  endif /* LC_MESSAGES */
+#  if defined (LC_NUMERIC)
+  setlocale (LC_NUMERIC, get_locale_var ("LC_NUMERIC"));
+#  endif /* LC_NUMERIC */
+#endif /* HAVE_SETLOCALE */
+  return (1);
 }
 
 /* Get the value of one of the locale variables (LC_MESSAGES, LC_CTYPE) */
@@ -202,9 +252,16 @@
 
   locale = lc_all;
 
-  if (locale == 0)
+  if (locale == 0 || *locale == '\0')
     locale = get_string_value (var);
-  if (locale == 0)
+  if (locale == 0 || *locale == '\0')
+    locale = lang;
+  if (locale == 0 || *locale == '\0')
+    /* FIXME: This is not really portable. Valid values of the 2nd parameter
+       to setlocale () are implementation defined, which doesn't even
+       guarantee that what is a valid locale name in one category is a valid
+       name in other category. In fact, glibc may from setlocale (LC_ALL, "")
+       return LC_CTYPE=cs_CZ.UTF-8;LC_NUMERIC=C;... */
     locale = default_locale;
 
   return (locale);
