This patch documents the changes needed in djdev203 to update locale support
to djdev204.  This locale support is required for both to compile __AND__ use
libiconv, libunistring and gettext with your application.
This changes are not required neither for DJGPP 2.04 nor for a freshly
compiled libc.a from the CVS repository code.

Regards,
Guerrero, Juan Manuel






diff -aprNU5 djgpp-2.03.orig/include/locale.h djgpp-2.03/include/locale.h
--- djgpp-2.03.orig/include/locale.h	1997-08-31 12:43:14 +0100
+++ djgpp-2.03/include/locale.h	2012-09-23 07:49:10 +0100
@@ -1,11 +1,15 @@
+/* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
+/* Copyright (C) 2002 DJ Delorie, see COPYING.DJ for details */
+/* Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details */
 /* Copyright (C) 1997 DJ Delorie, see COPYING.DJ for details */
 /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
 #ifndef __dj_include_locale_h_
 #define __dj_include_locale_h_
 
 #ifdef __cplusplus
+namespace std {
 extern "C" {
 #endif
 
 #ifndef __dj_ENFORCE_ANSI_FREESTANDING
 
@@ -13,11 +17,20 @@ extern "C" {
 #define LC_COLLATE	0x01
 #define LC_CTYPE	0x02
 #define LC_MONETARY	0x04
 #define LC_NUMERIC	0x08
 #define LC_TIME		0x10
-#define NULL		0
+
+/* Some programs think they know better... */
+#undef NULL
+#if (__GNUC__ >= 4) && defined(__cplusplus)
+#  define NULL          __null
+#elif defined(__cplusplus)
+#  define NULL          0
+#else
+#  define NULL          ((void*)0)
+#endif
 
 struct lconv {
   char *currency_symbol;
   char *decimal_point;
   char *grouping;
@@ -34,15 +47,26 @@ struct lconv {
   char n_sep_by_space;
   char n_sign_posn;
   char p_cs_precedes;
   char p_sep_by_space;
   char p_sign_posn;
+  char int_n_cs_precedes;
+  char int_n_sep_by_space;
+  char int_n_sign_posn;
+  char int_p_cs_precedes;
+  char int_p_sep_by_space;
+  char int_p_sign_posn;
 };
 
 struct lconv *	localeconv(void);
 char *		setlocale(int _category, const char *_locale);
 
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) \
+  || !defined(__STRICT_ANSI__) || defined(__cplusplus)
+
+#endif /* (__STDC_VERSION__ >= 199901L) || !__STRICT_ANSI__ */
+
 #ifndef __STRICT_ANSI__
 
 #ifndef _POSIX_SOURCE
 
 #endif /* !_POSIX_SOURCE */
@@ -52,8 +76,20 @@ char *		setlocale(int _category, const c
 #ifndef __dj_ENFORCE_FUNCTION_CALLS
 #endif /* !__dj_ENFORCE_FUNCTION_CALLS */
 
 #ifdef __cplusplus
 }
+}
 #endif
 
 #endif /* !__dj_include_locale_h_ */
+
+
+#if defined(__cplusplus) && !defined(__dj_ENFORCE_ANSI_FREESTANDING)
+#ifndef __dj_via_cplusplus_header_
+
+using std::lconv;
+using std::localeconv;
+using std::setlocale;
+
+#endif /* !__dj_via_cplusplus_header_ */
+#endif /* __cplusplus && !__dj_ENFORCE_ANSI_FREESTANDING */
diff -aprNU5 djgpp-2.03.orig/src/libc/ansi/locale/lconv.c djgpp-2.03/src/libc/ansi/locale/lconv.c
--- djgpp-2.03.orig/src/libc/ansi/locale/lconv.c	1997-08-31 12:43:30 +0100
+++ djgpp-2.03/src/libc/ansi/locale/lconv.c	2002-11-28 09:06:28 +0100
@@ -22,10 +22,16 @@ static struct lconv __lconv_ = {
   CHAR_MAX,
   CHAR_MAX,
   CHAR_MAX,
   CHAR_MAX,
   CHAR_MAX,
+  CHAR_MAX,
+  CHAR_MAX,
+  CHAR_MAX,
+  CHAR_MAX,
+  CHAR_MAX,
+  CHAR_MAX,
   CHAR_MAX
 };
 
 struct lconv *localeconv()
 {
diff -aprNU5 djgpp-2.03.orig/src/libc/ansi/locale/setlocal.c djgpp-2.03/src/libc/ansi/locale/setlocal.c
--- djgpp-2.03.orig/src/libc/ansi/locale/setlocal.c	1994-11-29 04:18:16 +0100
+++ djgpp-2.03/src/libc/ansi/locale/setlocal.c	2005-03-17 18:55:06 +0100
@@ -1,13 +1,642 @@
-/* Copyright (C) 1994 DJ Delorie, see COPYING.DJ for details */
+/*
+ * setlocal.c: Set or read international environment
+ *
+ * Copyright (C) 2002, 2005 Alexander S. Aganichev <asa@users.sf.net>
+ *
+ * This software may be used freely so long as this copyright notice is
+ * left intact.  There is no warranty on this software.
+ */
+
 #include <locale.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
 #include <string.h>
+#include <dpmi.h>
+#ifdef TEST
+#include <sys/farptr.h>
+#else
+#include <libc/farptrgs.h>
+#endif
+#include <go32.h>
+#include <limits.h>
+
+/*
+ * Number of supported categories
+ */
+#define LC_CATEGORIES 5
+
+/*
+ * Maximum name length for locale
+ */
+#define LC_MAXNAMESIZE 16
+
+/*
+ * Buffer size for the defined locales
+ */
+#define LC_BUFSIZ (LC_MAXNAMESIZE * LC_CATEGORIES)
+
+/*
+ * This variable contains the locales defined in the order LC_COLLATE,
+ * LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME separated by comma. If all
+ * locales are the same, then locale specified only once.
+ */
+static char lc_buffer[LC_BUFSIZ];
+static char lc_current[LC_CATEGORIES][LC_MAXNAMESIZE] =
+{
+  "C", "C", "C", "C", "C"
+};
+
+/*
+ * This is what we can extract from country.sys for our purposes.
+ */
+static char currency_symbol[6] = "";
+static char mon_decimal_point[2] = "";
+static char mon_thousands_sep[2] = "";
+static char decimal_point[2] = ".";
+static char thousands_sep[2] = "";
+
+extern unsigned char __dj_collate_table[];
+extern char __dj_date_format[];
+extern char __dj_time_format[];
+
+/*
+ * Reset collate table to the C locale
+ */
+static int
+resetlocalecollate(void)
+{
+  int i;
+
+  for (i = 0; i < 256; i++)
+    __dj_collate_table[i] = i;
+  return 1;
+}
+
+/*
+ * Reset ctype tables to the C locale
+ */
+static int
+resetlocalectype(void)
+{
+  int i;
+
+  /* ASCII portion always left unchanged */
+  for (i = 128; i < 256; i++)
+  {
+    __dj_ctype_tolower[i + 1] = i;
+    __dj_ctype_toupper[i + 1] = i;
+    __dj_ctype_flags[i + 1] = 0;
+  }
+  return 1;
+}
+
+/*
+ * Reset monetary to the C locale
+ * lcnv should be non-NULL
+ */
+static int
+resetlocalemonetary(void)
+{
+  int honored = 0;
+  struct lconv *lcnv = localeconv();
+
+  if(lcnv != NULL)
+  {
+    *currency_symbol = '\0';
+    lcnv->int_curr_symbol = lcnv->currency_symbol = currency_symbol;
+    *mon_thousands_sep = '\0';
+    lcnv->mon_thousands_sep = mon_thousands_sep;
+    *mon_decimal_point = '\0';
+    lcnv->mon_decimal_point = mon_decimal_point;
+    /* lcnv->mon_grouping = ""; */
+    /* lcnv->negative_sign = ""; */
+    /* lcnv->positive_sign = ""; */
+    lcnv->int_frac_digits = lcnv->frac_digits = CHAR_MAX;
+    lcnv->p_cs_precedes = lcnv->n_cs_precedes = CHAR_MAX;
+    lcnv->p_sep_by_space = lcnv->n_sep_by_space = CHAR_MAX;
+    /* lcnv->p_sign_posn = lcnv->n_sign_posn = CHAR_MAX; */
+    honored = 1;
+  }
+  return honored;
+}
+
+/*
+ * Reset numeric to the C locale
+ * lcnv should be non-NULL
+ */
+static int
+resetlocalenumeric(void)
+{
+  int honored = 0;
+  struct lconv *lcnv = localeconv();
+
+  if(lcnv != NULL)
+  {
+    *thousands_sep = '\0';
+    lcnv->thousands_sep = thousands_sep;
+    strcpy(decimal_point, ".");
+    lcnv->decimal_point = decimal_point;
+    /* lcnv->grouping = ""; */
+    honored = 1;
+  }
+  return honored;
+}
 
-char *setlocale(int category, const char *locale)
+/*
+ * Reset time strings to the C locale
+ */
+static int
+resetlocaletime(void)
 {
-  static char CLOCALE[] = "C";
-  if (locale == 0)
-    return CLOCALE;
-  if (strcmp(locale, CLOCALE) && strcmp(locale, "POSIX") && locale[0])
+  strcpy(__dj_date_format, "%m/%d/%y");
+  strcpy(__dj_time_format, "%H:%M:%S");
+  return 1;
+}
+
+/*
+ * Set collate table to the locale specified
+ * regs->x.bx = code page
+ * regs->x.dx = country ID
+ * regs->x.es/di = segment/offset
+ */
+static int
+setlocalecollate(const char *locale __attribute__((unused)), int selector,
+                 __dpmi_regs *regs)
+{
+  regs->h.ah = 0x65;
+  regs->h.al = 0x06;
+  regs->x.cx = 5;
+  __dpmi_int(0x21, regs);
+  if ((regs->x.flags & 1) || (regs->x.cx != 5))
     return 0;
-  return CLOCALE;
+  else
+  {
+    unsigned int table = _farpeekw(selector, 3) * 16 + _farpeekw(selector, 1);
+    int size = _farpeekw(_dos_ds, table);
+
+    movedata(_dos_ds, table + 2, _my_ds(), (unsigned int) __dj_collate_table,
+             size);
+    return 1;
+  }
+}
+
+/*
+ * Set ctype table to the locale specified
+ * regs->x.bx = code page
+ * regs->x.dx = country ID
+ * regs->x.es/di = segment/offset
+ */
+static int
+setlocalectype(const char *locale __attribute__((unused)), int selector,
+               __dpmi_regs *regs)
+{
+  int temp_flags;
+  int i;
+
+  regs->h.ah = 0x65;
+  regs->h.al = 0x02;
+  regs->x.cx = 5;
+  __dpmi_int(0x21, regs);
+  if ((regs->x.flags & 1) || (regs->x.cx != 5))
+    return 0;
+  else
+  {
+    unsigned int table = _farpeekw(selector, 3) * 16 + _farpeekw(selector, 1);
+    int size = _farpeekw(_dos_ds, table);
+
+    movedata(_dos_ds, table + 2, _my_ds(),
+             (unsigned int) &(__dj_ctype_toupper[128 + 1]), size);
+
+    /* let's build lowercase table from uppercase... */
+    for (i = 0; i < size; i++)
+    {
+      int c = toupper(i + 128);
+      if ((c != i + 128) && (c > 127))
+        __dj_ctype_tolower[c + 1] = i + 128;
+    }
+    for (i = 128; i < 256; i++)
+    {
+      /*
+       * Actually isgraph(), ispunct() and isspace() will return wrong results
+       * for some letters like 0xff in CP866 but we can't detect them reliably
+       */
+      temp_flags = __dj_ISPRINT | __dj_ISGRAPH;
+      if (tolower(i) != toupper(i))
+      {
+        temp_flags |= __dj_ISALPHA | __dj_ISALNUM;
+        if (i == toupper(i))
+          temp_flags |= __dj_ISUPPER;
+        else
+          temp_flags |= __dj_ISLOWER;
+      }
+      else
+        temp_flags |= __dj_ISPUNCT;
+      __dj_ctype_flags[i + 1] = temp_flags;
+    }
+    return 1;
+  }
+}
+
+/*
+ * Set monetary values to the locale specified
+ */
+static int
+setlocalemonetary(const char *locale, int selector,
+                  __dpmi_regs *regs __attribute__((unused)))
+{
+  struct lconv *lcnv = localeconv();
+
+  if(lcnv == NULL)
+    return 0;
+  else
+  {
+    /* parse: de_DE_EURO.850 */
+    const char *p = strrchr(locale, '_');
+
+    if ((p != NULL) && !strnicmp(p + 1, "EURO", 4))
+      strcpy(currency_symbol, "EUR");
+    else
+      movedata(selector, 9, _my_ds(), (unsigned) currency_symbol, 5);
+    lcnv->int_curr_symbol = lcnv->currency_symbol = currency_symbol;
+    movedata(selector, 14, _my_ds(), (unsigned) mon_thousands_sep, 2);
+    lcnv->mon_thousands_sep = mon_thousands_sep;
+    movedata(selector, 16, _my_ds(), (unsigned) mon_decimal_point, 2);
+    lcnv->mon_decimal_point = mon_decimal_point;
+    /* lcnv->mon_grouping = ""; */
+    /* lcnv->negative_sign = ""; */
+    /* lcnv->positive_sign = ""; */
+    lcnv->int_frac_digits = lcnv->frac_digits = _farpeekb(selector, 24);
+    lcnv->p_cs_precedes = lcnv->n_cs_precedes = _farpeekb(selector, 23) & 1;
+    lcnv->p_sep_by_space = lcnv->n_sep_by_space = _farpeekb(selector, 23) & 2;
+    /* lcnv->p_sign_posn = lcnv->n_sign_posn = CHAR_MAX; */
+    return 1;
+  }
+}
+
+/*
+ * Set numeric values to the locale specified
+ */
+static int
+setlocalenumeric(const char *locale __attribute__((unused)), int selector,
+                 __dpmi_regs *regs __attribute__((unused)))
+{
+  struct lconv *lcnv = localeconv();
+
+  if(lcnv == NULL)
+    return 0;
+  else
+  {
+    movedata(selector, 14, _my_ds(), (unsigned) thousands_sep, 2);
+    lcnv->thousands_sep = thousands_sep;
+    movedata(selector, 16, _my_ds(), (unsigned) decimal_point, 2);
+    lcnv->decimal_point = decimal_point;
+    /* lcnv->grouping = ""; */
+    return 1;
+  }
+}
+
+/*
+ * Set time strings to the locale specified
+ */
+static int
+setlocaletime(const char *locale __attribute__((unused)), int selector,
+              __dpmi_regs *regs __attribute__((unused)))
+{
+  switch (_farpeekw(selector, 7)) {
+  case 0:
+  default:
+    strcpy(__dj_date_format, "%m/%d/%y");
+    break;
+  case 1:
+    strcpy(__dj_date_format, "%d/%m/%y");
+    break;
+  case 2:
+    strcpy(__dj_date_format, "%y/%m/%d");
+    break;
+  }
+  __dj_date_format[2] = __dj_date_format[5] = _farpeekb(selector, 18);
+  if (_farpeekb(selector, 24) & 1)
+    strcpy(__dj_time_format, "%H:%M:%S");
+  else
+    strcpy(__dj_time_format, "%I:%M:%S %p");
+  __dj_time_format[2] = __dj_time_format[5] = _farpeekb(selector, 20);
+  return 1;
+}
+
+static const struct _cat
+{
+  int type;
+  const char *env;
+  int (*reset)(void);
+  int (*set)(const char *locale, int selector, __dpmi_regs *regs);
+}
+cat[LC_CATEGORIES] =
+{
+  { LC_COLLATE, "LC_COLLATE", resetlocalecollate, setlocalecollate },
+  { LC_CTYPE, "LC_CTYPE", resetlocalectype, setlocalectype },
+  { LC_MONETARY, "LC_MONETARY", resetlocalemonetary, setlocalemonetary },
+  { LC_NUMERIC, "LC_NUMERIC", resetlocalenumeric, setlocalenumeric },
+  { LC_TIME, "LC_TIME", resetlocaletime, setlocaletime }
+};
+
+static const struct _loc2id
+{
+  int id;
+  const char *loc;
+  size_t len;
+}
+loc2id[] =
+{
+  { 43,    "de_AT",       5 },
+  { 43,    "de_AT_EURO",  10 },
+  { 41,    "de_CH",       5 },
+  { 49,    "de_DE",       5 },
+  { 49,    "de_DE_EURO",  10 },
+  { 352,   "de_LU",       5 },
+  { 352,   "de_LU_EURO",  10 },
+  { 61,    "en_AU",       5 },
+  { 32,    "en_BE",       5 },
+  { 4,     "en_CA",       5 },
+  { 44,    "en_GB",       5 },
+  { 61,    "en_IE",       5 },
+  { 61,    "en_IE_EURO",  10 },
+  { 64,    "en_NZ",       5 },
+  { 1,     "en_US",       5 },
+  { 27,    "en_ZA",       5 },
+  { 54,    "es_AR",       5 },
+  { 591,   "es_BO",       5 },
+  { 56,    "es_CL",       5 },
+  { 57,    "es_CO",       5 },
+  { 506,   "es_CR",       5 },
+  { 809,   "es_DO",       5 },
+  { 593,   "es_EC",       5 },
+  { 34,    "es_ES",       5 },
+  { 34,    "es_ES_EURO",  10 },
+  { 502,   "es_GT",       5 },
+  { 504,   "es_HN",       5 },
+  { 52,    "es_MX",       5 },
+  { 507,   "es_PA",       5 },
+  { 51,    "es_PE",       5 },
+  { 595,   "es_PY",       5 },
+  { 503,   "es_SV",       5 },
+  { 598,   "es_UY",       5 },
+  { 58,    "es_VE",       5 },
+  { 372,   "et_ET",       5 },
+  { 358,   "fi_FI",       5 },
+  { 358,   "fi_FI_EURO",  10 },
+  { 32,    "fr_BE",       5 },
+  { 32,    "fr_BE_EURO",  10 },
+  { 2,     "fr_CA",       5 },
+  { 41,    "fr_CH",       5 },
+  { 352,   "fr_LU",       5 },
+  { 352,   "fr_LU_EURO",  10 },
+  { 33,    "fr_FR",       5 },
+  { 33,    "fr_FR_EURO",  10 },
+  { 30,    "gr_GR",       5 },
+  { 30,    "gr_GR_EURO",  10 },
+  { 972,   "he_IL",       5 },
+  { 385,   "hr_HR",       5 },
+  { 36,    "hu_HU",       5 },
+  { 354,   "is_IS",       5 },
+  { 41,    "it_CH",       5 },
+  { 39,    "it_IT",       5 },
+  { 39,    "it_IT_EURO",  10 },
+  { 370,   "lt_LT",       5 },
+  { 371,   "lv_LV",       5 },
+  { 389,   "mk_MK",       5 },
+  { 91,    "mr_IN",       5 },
+  { 356,   "mt_MT",       5 },
+  { 32,    "nl_BE",       5 },
+  { 32,    "nl_BE_EURO",  10 },
+  { 31,    "nl_NL",       5 },
+  { 31,    "nl_NL_EURO",  10 },
+  { 47,    "no_NO",       5 },
+  { 48,    "pl_PL",       5 },
+  { 55,    "pt_BR",       5 },
+  { 351,   "pt_PT",       5 },
+  { 351,   "pt_PT_EURO",  10 },
+  { 40,    "ro_RO",       5 },
+  { 7,     "ru_RU",       5 },
+  { 38,    "sh_YU",       5 },
+  { 42,    "sk_SK",       5 },
+  { 386,   "sl_SI",       5 },
+  { 355,   "sq_AL",       5 },
+  { 381,   "sr_YU",       5 },
+  { 358,   "sv_FI",       5 },
+  { 46,    "sv_SE",       5 },
+  { 91,    "ta_IN",       5 },
+  { 200,   "th_TH",       5 },
+  { 90,    "tr_TR",       5 },
+  { 804,   "uk_UA",       5 },
+  { 84,    "vi_VN",       5 }
+};
+
+/*
+ * Set or read international environment
+ */
+char *
+setlocale(int category, const char *locale)
+{
+  int honored = 1;
+  int i;
+
+  if (locale != NULL)
+  {
+    int segment = -1, selector = -1;
+    __dpmi_regs regs;
+    char buf[LC_MAXNAMESIZE];
+    char *p1, *p2;
+
+    strncpy(lc_buffer, locale, LC_BUFSIZ);
+    lc_buffer[LC_BUFSIZ - 1] = '\0';
+    p1 = lc_buffer - 1;
+    p2 = lc_buffer;
+    for (i = 0; i < LC_CATEGORIES; i++)
+    {
+      locale = p2;
+      p1 = strchr (p2, ',');
+      if (p1 == NULL)
+      {
+        p1 = p2;
+      }
+      else
+      {
+        *p1 = '\0';
+        p2 = p1 + 1;
+      }
+      if ((category == LC_ALL) || (cat[i].type == category))
+      {
+        if (*locale == '\0')
+        {
+          const char *env;
+          if ((env = getenv (cat[i].env)) != NULL)
+          {
+            locale = env;
+          }
+          else
+          if ((env = getenv ("LC_ALL")) != NULL)
+          {
+            locale = env;
+          }
+          else
+          if ((env = getenv ("LANG")) != NULL)
+          {
+            locale = env;
+          }
+        }
+        if (!stricmp(locale, "C") || !stricmp(locale, "POSIX"))
+        {
+          if (cat[i].reset() == 0)
+          {
+            honored = 0;
+            continue;
+          }
+        }
+        else
+        {
+          int CID, CCP;
+          size_t j;
+
+          /* Allocate DOS memory */
+          if (segment == -1)
+          {
+            if ((segment = __dpmi_allocate_dos_memory(3, &selector)) == -1)
+            {
+              honored = 0;
+              continue;
+            }
+          }
+
+          /* Now try to find out the country/codepage */
+          CID = 0xffff;
+          CCP = 0xffff;
+          if (*locale != '\0')
+          {
+            size_t len;
+            const char *p = strchr(locale, '.');
+            if (p == NULL)
+              p = locale + strlen(locale);
+            len = p - locale;
+            for (j = 0; j < sizeof(loc2id) / sizeof(*loc2id); j++)
+              if (!strncmp(locale, loc2id[j].loc,
+                           len >= loc2id[j].len ? len : loc2id[j].len))
+              {
+                CID = loc2id[j].id;
+                break;
+              }
+            if (*p == '.')
+              CCP = atoi(p + 1);
+            /* User requested the country/codepage we doesn't know about */
+            if ((CID == 0xffff) || ((*p == '.') && (CCP == 0xffff)))
+            {
+              honored = 0;
+              continue;
+            }
+          }
+
+          regs.h.ah = 0x65;
+          regs.h.al = 0x01;
+          regs.x.bx = CCP;
+          regs.x.dx = CID;
+          regs.x.cx = 41;
+          regs.x.es = segment;
+          regs.x.di = 0;
+          __dpmi_int(0x21, &regs);
+          if ((regs.x.flags & 1) || (regs.x.cx != 41))
+          {
+            honored = 0;
+            continue;
+          }
+
+          if (*locale == '\0')
+          {
+            CID = _farpeekw(selector, 3);
+            CCP = _farpeekw(selector, 5);
+            locale = "??_??";
+            for (j = 0; j < sizeof(loc2id) / sizeof(*loc2id); j++)
+              if (loc2id[j].id == CID)
+              {
+                locale = loc2id[j].loc;
+                break;
+              }
+            sprintf(buf, "%s.%u", locale, CCP);
+            locale = buf;
+          }
+
+          /* regs.x.bx, regs.x.dx, regs.x.es/di are preserved by DOS */
+          if (cat[i].set(locale, selector, &regs) == 0)
+          {
+            honored = 0;
+            continue;
+          }
+        }
+
+        strncpy(lc_current[i], locale, LC_MAXNAMESIZE);
+        lc_current[i][LC_MAXNAMESIZE - 1] = '\0';
+      }
+    }
+    if (segment != -1)
+      __dpmi_free_dos_memory(selector);
+  }
+
+  if (honored)
+  {
+    if (category != LC_ALL)
+    {
+      for (i = 0; i < LC_CATEGORIES; i++)
+        if (cat[i].type == category)
+          return lc_current[i];
+      return NULL;
+    }
+    if (!stricmp(lc_current[0], lc_current[1]) &&
+        !stricmp(lc_current[1], lc_current[2]) &&
+        !stricmp(lc_current[2], lc_current[3]) &&
+        !stricmp(lc_current[3], lc_current[4]))
+    {
+      return lc_current[0];
+    }
+    else
+    {
+      char *p;
+
+      p = lc_buffer;
+      for (i = 0; i < LC_CATEGORIES; i++)
+      {
+	size_t len = strlen(lc_current[i]);
+        memcpy(p, lc_current[i], len + 1);
+        p += len;
+        if (i != (LC_CATEGORIES - 1))
+          *p++ = ',';
+      }
+      return lc_buffer;
+    }
+  }
+  else
+    return NULL;
+}
+
+#ifdef TEST
+
+extern unsigned char __dj_collate_table[256];
+extern char __dj_date_format[];
+extern char __dj_time_format[];
+
+int
+main(int ac, char *av[])
+{
+  int i;
+  const char *loc = (ac == 1) ? "" : av[1];
+  char *lc;
+  lc = setlocale(LC_ALL, loc);
+  lc = setlocale(LC_ALL, NULL);
+  printf("Locale: %s\n", lc ? lc : "not detected");
+  for (i = 32; i < 256; i++)
+    printf("%c%c%c|", (char) i, tolower(i), toupper(i));
+  printf("\n");
+  for (i = 0; i < 256; i++)
+    printf("%02xh ", __dj_collate_table[i]);
+  printf("\n%f\n%s %s\n", 1000456.23, __dj_date_format, __dj_time_format);
+  return 0;
 }
+#endif
diff -aprNU5 djgpp-2.03.orig/src/libc/ansi/string/strcoll.c djgpp-2.03/src/libc/ansi/string/strcoll.c
--- djgpp-2.03.orig/src/libc/ansi/string/strcoll.c	1994-11-29 04:41:28 +0100
+++ djgpp-2.03/src/libc/ansi/string/strcoll.c	2003-11-08 12:19:40 +0100
@@ -1,8 +1,57 @@
+/* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
 /* Copyright (C) 1994 DJ Delorie, see COPYING.DJ for details */
+
 #include <string.h>
 
+unsigned char __dj_collate_table[256] =
+{
+  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+  0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+  0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+  0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+  0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+  0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+  0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+  0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+  0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+  0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+  0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+  0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+  0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+  0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+  0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+  0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+  0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+  0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+  0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+  0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+  0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+  0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+  0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+  0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+  0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+  0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+  0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+  0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+  0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
+
+#define coll(c) __dj_collate_table[(unsigned char)c]
+
 int
 strcoll(const char *s1, const char *s2)
 {
-  return strcmp(s1, s2);
+  while (coll(*s1) == coll(*s2))
+  {
+    if (*s1 == 0)
+    {
+      return 0;
+    }
+    s1++;
+    s2++;
+  }
+  return coll(*s1) - coll(*s2);
 }
diff -aprNU5 djgpp-2.03.orig/src/libc/ansi/time/strftime.c djgpp-2.03/src/libc/ansi/time/strftime.c
--- djgpp-2.03.orig/src/libc/ansi/time/strftime.c	2001-11-25 16:25:02 +0100
+++ djgpp-2.03/src/libc/ansi/time/strftime.c	2008-12-20 18:33:32 +0100
@@ -1,14 +1,23 @@
+/* Copyright (C) 2008 DJ Delorie, see COPYING.DJ for details */
+/* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
 /* Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details */
 /* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */
 /* Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details */
 /* Copyright (C) 1994 DJ Delorie, see COPYING.DJ for details */
 #include <string.h>
 #include <time.h>
 #include <ctype.h>
+#include <stdbool.h>
 
-#define TM_YEAR_BASE 1900
+
+#define THURSDAY       4
+#define SATURDAY       6
+#define SUNDAY         7
+
+#define TM_YEAR_BASE   1900
+#define IS_LEAP(year)  ((((year) % 4) == 0) && ((((year) % 100) != 0) || (((year) % 400) == 0)))
 
 static const char *afmt[] = {
   "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
 };
 static const char *Afmt[] = {
@@ -21,14 +30,101 @@ static const char *bfmt[] = {
 };
 static const char *Bfmt[] = {
   "January", "February", "March", "April", "May", "June", "July",
   "August", "September", "October", "November", "December",
 };
+static const char __ISO8601_date_format[] = "%Y-%m-%d";
+char __dj_date_format[10] = "%m/%d/%y";
+char __dj_time_format[16] = "%H:%M:%S";
 
 static size_t gsize;
 static char *pt;
 
+static __inline__ int
+_compute_iso_wday_of_jan_01(const struct tm *t)
+{
+  /*
+   *  ISO week starts with Monday = 1 and ends with Sunday = 7.
+   */
+
+  int wday_jan_01;
+
+
+  wday_jan_01 = (7 + t->tm_wday - t->tm_yday % 7) % 7;
+  if (wday_jan_01 == 0)
+    wday_jan_01 = 7;
+
+  return wday_jan_01;
+}
+
+static int
+_compute_iso_standard_week(const struct tm *t)
+{
+  /*
+   *  In ISO 8601:2000 standard week-based year system,
+   *  weeks begin on a Monday and week 1 of the year is
+   *  the week that includes January 4th, which is also
+   *  the week that includes the first Thursday of the
+   *  year, and is also the first week that contains at
+   *  least four days in the year.
+   */
+
+  int iso_wday_of_jan_01, iso_week;
+
+
+  iso_wday_of_jan_01 = _compute_iso_wday_of_jan_01(t);  /*  Mon = 1, ..., Sun = 7.  */
+  iso_week = (6 + t->tm_yday - (6 + t->tm_wday) % 7) / 7;
+  if (iso_week == 0 && iso_wday_of_jan_01 > THURSDAY)   /*  Week belongs to the previous year.  */
+  {
+    if ((iso_wday_of_jan_01 == SUNDAY) ||
+        (iso_wday_of_jan_01 == SATURDAY && !IS_LEAP(t->tm_year - 1 + TM_YEAR_BASE)))
+      iso_week = 52;
+    else
+      iso_week = 53;
+  }
+  else
+  {
+    int is_leap_year = IS_LEAP(t->tm_year + TM_YEAR_BASE);
+    int iso_wday_of_dec_31 = (365 + is_leap_year - t->tm_yday + (6 + t->tm_wday) % 7) % 7;  /*  Mon = 1, ..., Sun = 7.  */
+
+    if (t->tm_yday > (360 + is_leap_year) && iso_wday_of_dec_31 < THURSDAY)  /*  Belongs to the following year.  */
+      iso_week = 1;
+    else  /*  Belongs to the current year.  */
+      iso_week++;
+  }
+
+  return iso_week;
+}
+
+static int
+_compute_iso_week_based_year(const struct tm *t)
+{
+  /*
+   *  ISO 8601:2000 standard week-based year system.
+   */
+
+  int iso_wday_of_jan_01, iso_year, week;
+
+
+  iso_wday_of_jan_01 = _compute_iso_wday_of_jan_01(t);  /*  Mon = 1, ..., Sun = 7.  */
+  week = (6 + t->tm_yday - (6 + t->tm_wday) % 7) / 7;
+  if (week == 0 && iso_wday_of_jan_01 > THURSDAY)  /*  Belongs to the previous year.  */
+    iso_year = t->tm_year - 1 + TM_YEAR_BASE;
+  else
+  {
+    int is_leap_year = IS_LEAP(t->tm_year + TM_YEAR_BASE);
+    int iso_wday_of_dec_31 = (365 + is_leap_year - t->tm_yday + (6 + t->tm_wday) % 7) % 7;  /*  Mon = 1, ..., Sun = 7.  */
+
+    if (t->tm_yday > (360 + is_leap_year) && iso_wday_of_dec_31 < THURSDAY)  /*  Belongs to the following year.  */
+      iso_year = t->tm_year + 1 + TM_YEAR_BASE;
+    else  /*  Belongs to the current year.  */
+      iso_year = t->tm_year + TM_YEAR_BASE;
+  }
+
+  return iso_year;
+}
+
 static int
 _add(const char *str, int upcase)
 {
   for (;; ++pt, --gsize)
   {
@@ -64,52 +160,71 @@ _fmt(const char *format, const struct tm
 {
   for (; *format; ++format)
   {
     if (*format == '%')
     {
-      int pad = '0', space=' ';
-      if (format[1] == '_')
-	pad = space = ' ', format++;
-      if (format[1] == '-')
-	pad = space = 0, format++;
-      if (format[1] == '0')
-	pad = space = '0', format++;
-      if (format[1] == '^')
-	upcase = 1, format++;
+      int flag_seen, pad = '0', space=' ', swap_case = false;
+
+      /*  Parse flags.  */
+      do {
+        flag_seen = false;
+        if (format[1] == '_')
+          flag_seen = true, pad = space = ' ', format++;
+        if (format[1] == '-')
+          flag_seen = true, pad = space = 0, format++;
+        if (format[1] == '0')
+          flag_seen = true, pad = space = '0', format++;
+        if (format[1] == '^')
+          flag_seen = true, upcase = true, format++;
+        if (format[1] == '#')
+          flag_seen = true, swap_case = true, format++;
+      } while (flag_seen);
+
+      /*  Parse modifiers.  */
+      if (format[1] == 'E' || format[1] == 'O')
+	format++;  /*  Only C/POSIX locale is supported.  */
 
       switch(*++format)
       {
       case '\0':
 	--format;
 	break;
       case 'A':
+	if (swap_case)
+	  upcase = true;
 	if (t->tm_wday < 0 || t->tm_wday > 6)
 	  return 0;
 	if (!_add(Afmt[t->tm_wday], upcase))
 	  return 0;
 	continue;
       case 'a':
+	if (swap_case)
+	  upcase = true;
 	if (t->tm_wday < 0 || t->tm_wday > 6)
 	  return 0;
 	if (!_add(afmt[t->tm_wday], upcase))
 	  return 0;
 	continue;
       case 'B':
+	if (swap_case)
+	  upcase = true;
 	if (t->tm_mon < 0 || t->tm_mon > 11)
 	  return 0;
 	if (!_add(Bfmt[t->tm_mon], upcase))
 	  return 0;
 	continue;
       case 'b':
       case 'h':
+	if (swap_case)
+	  upcase = true;
 	if (t->tm_mon < 0 || t->tm_mon > 11)
 	  return 0;
 	if (!_add(bfmt[t->tm_mon], upcase))
 	  return 0;
 	continue;
       case 'C':
-	if (!_conv((t->tm_year+TM_YEAR_BASE)/100, 2, pad))
+	if (!_conv((t->tm_year + TM_YEAR_BASE) / 100, 2, pad))
 	  return 0;
 	continue;
       case 'c':
 	if (!_fmt("%a %b %e %H:%M:%S %Y", t, upcase))
 	  return 0;
@@ -124,10 +239,22 @@ _fmt(const char *format, const struct tm
 	continue;
       case 'd':
 	if (!_conv(t->tm_mday, 2, pad))
 	  return 0;
 	continue;
+      case 'F':
+	if (!_fmt(__ISO8601_date_format, t, upcase))
+	  return 0;
+	continue;
+      case 'G':
+	if (!_conv(_compute_iso_week_based_year(t), 4, pad))
+	  return 0;
+	continue;
+      case 'g':
+	if (!_conv(_compute_iso_week_based_year(t) % 100, 2, pad))
+	  return 0;
+	continue;
       case 'H':
 	if (!_conv(t->tm_hour, 2, pad))
 	  return 0;
 	continue;
       case 'I':
@@ -158,12 +285,17 @@ _fmt(const char *format, const struct tm
 	continue;
       case 'n':
 	if (!_add("\n", upcase))
 	  return 0;
 	continue;
+      case 'P':
+	if (!_add(t->tm_hour >= 12 ? "pm" : "am", upcase))
+	  return 0;
+	continue;
       case 'p':
-	if (!_add(t->tm_hour >= 12 ? "PM" : "AM", upcase))
+	upcase = swap_case ? false : true;
+	if (!_add(t->tm_hour >= 12 ? "pm" : "am", upcase))
 	  return 0;
 	continue;
       case 'R':
 	if (!_fmt("%H:%M", t, upcase))
 	  return 0;
@@ -174,12 +306,22 @@ _fmt(const char *format, const struct tm
 	continue;
       case 'S':
 	if (!_conv(t->tm_sec, 2, pad))
 	  return 0;
 	continue;
+      case 's':
+	{
+	  struct tm _t;
+	  time_t _time;
+
+	  _t = *t;
+	  _time = mktime(&_t);
+          if (_time == (time_t)-1 || !_conv(_time, -1, pad))
+	    return 0;
+	}
+	continue;
       case 'T':
-      case 'X':
 	if (!_fmt("%H:%M:%S", t, upcase))
 	  return 0;
 	continue;
       case 't':
 	if (!_add("\t", upcase))
@@ -188,12 +330,15 @@ _fmt(const char *format, const struct tm
       case 'u':
 	if (!_conv(t->tm_wday==0 ? 7 : t->tm_wday, 1, pad))
 	  return 0;
 	continue;
       case 'U':
-	if (!_conv((t->tm_yday + 7 - t->tm_wday) / 7,
-		   2, pad))
+	if (!_conv((t->tm_yday + 7 - t->tm_wday) / 7, 2, pad))
+	  return 0;
+	continue;
+      case 'V':
+	if (!_conv(_compute_iso_standard_week(t), 2, pad))
 	  return 0;
 	continue;
       case 'W':
 	if (!_conv((t->tm_yday + 7 -
 		    (t->tm_wday ? (t->tm_wday - 1) : 6))
@@ -202,34 +347,54 @@ _fmt(const char *format, const struct tm
 	continue;
       case 'w':
 	if (!_conv(t->tm_wday, 1, pad))
 	  return 0;
 	continue;
+      case 'X':
+	if (!_fmt(__dj_time_format, t, upcase))
+	  return 0;
+	continue;
       case 'x':
-	if (!_fmt("%m/%d/%y", t, upcase))
+	if (!_fmt(__dj_date_format, t, upcase))
 	  return 0;
 	continue;
       case 'y':
-      case 'g':
 	if (!_conv((t->tm_year + TM_YEAR_BASE) % 100, 2, pad))
 	  return 0;
 	continue;
       case 'Y':
-      case 'G':
 	if (!_conv(t->tm_year + TM_YEAR_BASE, 4, pad))
 	  return 0;
 	continue;
       case 'z':
-	if (!_add(t->__tm_gmtoff<0 ? "-" : "+", 0))
+	if (!_add(t->__tm_gmtoff < 0 ? "-" : "+", 0))
 	  return 0;
-	if (!_conv(t->__tm_gmtoff<0 ? -t->__tm_gmtoff : t->__tm_gmtoff, 4, pad))
+	if (!_conv(t->__tm_gmtoff < 0 ? -t->__tm_gmtoff : t->__tm_gmtoff, 4, pad))
 	  return 0;
 	continue;
       case 'Z':
-	if (!t->tm_zone || !_add(t->tm_zone, upcase))
+	if (t->tm_zone)
+	{
+	  char tm_zone[32];
+
+	  strcpy(tm_zone, t->tm_zone);
+	  if (swap_case)
+	  {
+	    upcase = false;
+	    strlwr(tm_zone);
+	  }
+	  if (!_add(tm_zone, upcase))
+	    return 0;
+	}
+	else
 	  return 0;
 	continue;
+      case '+':
+	/*
+	 *  The date and time in date(1) format.  An extension introduced
+	 *  with Olson's timezone package and still not supported.
+	 */
       case '%':
 	/*
 	 * X311J/88-090 (4.12.3.5): if conversion char is
 	 * undefined, behavior is undefined.  Print out the
 	 * character itself as printf(3) does.
@@ -249,11 +414,11 @@ size_t
 strftime(char *s, size_t maxsize, const char *format, const struct tm *t)
 {
   pt = s;
   if ((gsize = maxsize) < 1)
     return 0;
-  if (_fmt(format, t, 0))
+  if (_fmt(format, t, false))
   {
     *pt = '\0';
     return maxsize - gsize;
   }
   return 0;
