]> sourceware.org Git - newlib-cygwin.git/commitdiff
Implement newlocale, freelocale, duplocale, uselocale
authorCorinna Vinschen <corinna@vinschen.de>
Fri, 22 Jul 2016 20:54:07 +0000 (22:54 +0200)
committerCorinna Vinschen <corinna@vinschen.de>
Mon, 15 Aug 2016 08:56:57 +0000 (10:56 +0200)
Add global const __C_locale for reference purposes.

Bump Cygwin API minor number and DLL major version number to 2.6.0.

Signed-off by: Corinna Vinschen <corinna@vinschen.de>

newlib/libc/include/locale.h
newlib/libc/locale/locale.c
winsup/cygwin/common.din
winsup/cygwin/include/cygwin/version.h

index 40e41245153bd1e3bcf171df9892f26f4c4244a8..d60132c352da49d7026f39b449d35e461de699ac 100644 (file)
@@ -65,14 +65,24 @@ struct lconv
   char int_p_sign_posn;
 };
 
+struct _reent;
+char *_EXFUN(_setlocale_r,(struct _reent *, int, const char *));
+struct lconv *_EXFUN(_localeconv_r,(struct _reent *));
+
+locale_t _newlocale_r (struct _reent *, int, const char *, locale_t);
+void _freelocale_r (struct _reent *, locale_t);
+locale_t _duplocale_r (struct _reent *, locale_t);
+locale_t _uselocale_r (struct _reent *, locale_t);
+
 #ifndef _REENT_ONLY
-char *_EXFUN(setlocale,(int category, const char *locale));
+char *_EXFUN(setlocale,(int, const char *));
 struct lconv *_EXFUN(localeconv,(void));
-#endif
 
-struct _reent;
-char *_EXFUN(_setlocale_r,(struct _reent *, int category, const char *locale));
-struct lconv *_EXFUN(_localeconv_r,(struct _reent *));
+locale_t newlocale (int, const char *, locale_t);
+void freelocale (locale_t);
+locale_t duplocale (locale_t);
+locale_t uselocale (locale_t);
+#endif
 
 _END_STD_C
 
index 35c5e6c6f43844d92a45f88b66f54a05b4204bf5..4f2d6d2716a78cdc85100107bbc0856f9f0db11c 100644 (file)
@@ -226,6 +226,34 @@ static char *categories[_LC_LAST] = {
  */
 char __default_locale[ENCODING_LEN + 1] = DEFAULT_LOCALE;
 
+const struct __locale_t __C_locale =
+{
+  { "C", "C", "C", "C", "C", "C", "C", },
+  __ascii_wctomb,
+  __ascii_mbtowc,
+  0,
+  NULL,
+#ifndef __HAVE_LOCALE_INFO__
+  "\1",
+  "ASCII",
+  "ASCII",
+#else
+  {
+    { NULL, NULL },                    /* LC_ALL */
+#ifdef __CYGWIN__
+    { &_C_collate_locale, NULL },      /* LC_COLLATE */
+#else
+    { NULL, NULL },                    /* LC_COLLATE */
+#endif
+    { &_C_ctype_locale, NULL },                /* LC_CTYPE */
+    { &_C_monetary_locale, NULL },     /* LC_MONETARY */
+    { &_C_numeric_locale, NULL },      /* LC_NUMERIC */
+    { &_C_time_locale, NULL },         /* LC_TIME */
+    { &_C_messages_locale, NULL },     /* LC_MESSAGES */
+  },
+#endif
+};
+
 struct __locale_t __global_locale =
 {
   { "C", "C", DEFAULT_LOCALE, "C", "C", "C", "C", },
@@ -1008,6 +1036,205 @@ _DEFUN (_localeconv_r, (data),
   return (struct lconv *) &lconv;
 }
 
+#define LC_VALID_MASK  (LC_COLLATE_MASK | LC_CTYPE_MASK | LC_MONETARY_MASK \
+                        | LC_NUMERIC_MASK | LC_TIME_MASK | LC_MESSAGES_MASK)
+
+struct __locale_t *
+_newlocale_r (struct _reent *p, int category_mask, const char *locale,
+             struct __locale_t *base)
+{
+  struct __locale_t tmp_locale, *new_locale;
+  int i;
+
+  /* Convert LC_ALL_MASK to a mask containing all valid MASK values.
+     This simplifies the code below. */
+  if (category_mask & LC_ALL_MASK)
+    {
+      category_mask &= ~LC_ALL_MASK;
+      category_mask |= LC_VALID_MASK;
+    }
+  /* Check for invalid mask values and valid locale ptr. */
+  if (category_mask & ~LC_VALID_MASK || !locale)
+    {
+      p->_errno = EINVAL;
+      return NULL;
+    }
+  /* If the new locale is supposed to be all default locale, just return
+     a pointer to the default locale. */
+  if ((!base && category_mask == 0)
+      || (category_mask == LC_VALID_MASK
+         && (!strcmp (locale, "C") || !strcmp (locale, "POSIX"))))
+    return (struct __locale_t *) &__C_locale;
+  /* Start with setting all values to the default locale values. */
+  tmp_locale = __C_locale;
+  /* Fill out category strings. */
+  if (!*locale)
+    {
+      for (i = 1; i < _LC_LAST; ++i)
+       if (((1 << i) & category_mask) != 0)
+         {
+           const char *env = __get_locale_env (p, i);
+           if (strlen (env) > ENCODING_LEN)
+             {
+               p->_errno = EINVAL;
+               return NULL;
+             }
+           strcpy (tmp_locale.categories[i], env);
+         }
+    }
+  else
+    {
+      for (i = 1; i < _LC_LAST; ++i)
+       if (((1 << i) & category_mask) != 0)
+         strcpy (tmp_locale.categories[i], locale);
+    }
+  /* Now go over all categories and set them. */
+  for (i = 1; i < _LC_LAST; ++i)
+    {
+      if (((1 << i) & category_mask) != 0)
+       {
+         /* Nothing to do for "C"/"POSIX" locale. */
+         if (!strcmp (tmp_locale.categories[i], "C")
+             || !strcmp (tmp_locale.categories[i], "POSIX"))
+           continue;
+         /* If the new locale is the old locale, just copy it over. */
+         if (base && !strcmp (base->categories[i], tmp_locale.categories[i]))
+           {
+             if (i == LC_CTYPE)
+               {
+                 tmp_locale.wctomb = base->wctomb;
+                 tmp_locale.mbtowc = base->mbtowc;
+                 tmp_locale.cjk_lang = base->cjk_lang;
+                 tmp_locale.ctype_ptr - base->ctype_ptr;
+               }
+#ifdef __HAVE_LOCALE_INFO__
+             tmp_locale.lc_cat[i].ptr = base->lc_cat[i].ptr;
+             /* Mark the value as "has still to be copied".  We do this in
+                two steps to simplify freeing new locale types in case of a
+                subsequent error. */
+             tmp_locale.lc_cat[i].buf = (void *) -1;
+#else
+             if (i == LC_CTYPE)
+               strcpy (tmp_locale.ctype_codeset, base->ctype_codeset);
+             else if (i == LC_MESSAGES)
+               strcpy (tmp_locale.message_codeset, base->message_codeset);
+#endif
+             continue;
+           }
+         /* Otherwise load locale data. */
+         if (!loadlocale (&tmp_locale, i, tmp_locale.categories[i]))
+           goto error;
+       }
+    }
+  /* Allocate new locale_t. */
+  new_locale = (struct __locale_t *) _calloc_r (p, 1, sizeof *new_locale);
+  if (!new_locale)
+    goto error;
+#ifdef __HAVE_LOCALE_INFO__
+  /* Second step of copying over.  At this point we can safely copy.  Make
+     sure to invalidate the copied buffer pointers in base, so a subsequent
+     freelocale (base) doesn't free the buffers now used in the new locale. */
+  for (i = 1; i < _LC_LAST; ++i)
+    if (tmp_locale.lc_cat[i].buf == (const void *) -1)
+      {
+       tmp_locale.lc_cat[i].buf = base->lc_cat[i].buf;
+       base->lc_cat[i].buf = NULL;
+      }
+#endif
+
+  *new_locale = tmp_locale;
+  return new_locale;
+
+error:
+  /* An error occured while we had already (potentially) allocated memory.
+     Free memory and return NULL.  errno is supposed to be set already. */
+#ifdef __HAVE_LOCALE_INFO__
+  for (i = 1; i < _LC_LAST; ++i)
+    if (tmp_locale.lc_cat[i].buf
+       && tmp_locale.lc_cat[i].buf != (const void *) -1)
+      _free_r (p, tmp_locale.lc_cat[i].buf);
+#endif
+
+  return NULL;
+}
+
+void
+_freelocale_r (struct _reent *p, struct __locale_t *locobj)
+{
+  /* Sanity check.  The "C" locale is static, don't try to free it. */
+  if (!locobj || locobj == &__C_locale || locobj == LC_GLOBAL_LOCALE)
+    return;
+#ifdef __HAVE_LOCALE_INFO__
+  for (int i = 1; i < _LC_LAST; ++i)
+    if (locobj->lc_cat[i].buf)
+      _free_r (p, locobj->lc_cat[i].buf);
+#endif
+  _free_r (p, locobj);
+}
+
+struct __locale_t *
+_duplocale_r (struct _reent *p, struct __locale_t *locobj)
+{
+  struct __locale_t tmp_locale, *new_locale;
+  int i;
+
+  /* LC_GLOBAL_LOCALE denotes the global locale. */
+  if (locobj == LC_GLOBAL_LOCALE)
+    locobj = __get_global_locale ();
+  /* The "C" locale is used statically, never copied. */
+  else if (locobj == &__C_locale)
+    return (struct __locale_t *) &__C_locale;
+  /* Copy locale content. */
+  tmp_locale = *locobj;
+#ifdef __HAVE_LOCALE_INFO__
+  for (i = 1; i < _LC_LAST; ++i)
+    if (locobj->lc_cat[i].buf)
+      {
+       /* If the object is not a "C" locale category, copy it.  Just call
+          loadlocale.  It knows what to do to replicate the category. */
+       tmp_locale.lc_cat[i].ptr = NULL;
+       tmp_locale.lc_cat[i].buf = NULL;
+       if (!loadlocale (&tmp_locale, i, tmp_locale.categories[i]))
+         goto error;
+      }
+#endif
+  /* Allocate new locale_t. */
+  new_locale = (struct __locale_t *) _calloc_r (p, 1, sizeof *new_locale);
+  if (!new_locale)
+    goto error;
+
+  *new_locale = tmp_locale;
+  return new_locale;
+
+error:
+  /* An error occured while we had already (potentially) allocated memory.
+     Free memory and return NULL.  errno is supposed to be set already. */
+#ifdef __HAVE_LOCALE_INFO__
+  while (--i > 0)
+    if (tmp_locale.lc_cat[i].buf)
+      _free_r (p, tmp_locale.lc_cat[i].buf);
+#endif
+
+  return NULL;
+}
+
+struct __locale_t *
+_uselocale_r (struct _reent *p, struct __locale_t *newloc)
+{
+  struct __locale_t *current_locale;
+
+  current_locale = __get_locale_r (p);
+  if (!current_locale)
+    current_locale = LC_GLOBAL_LOCALE;
+
+  if (newloc == LC_GLOBAL_LOCALE)
+    p->_locale = NULL;
+  else if (newloc)
+    p->_locale = newloc;
+
+  return current_locale;
+}
+
 #ifndef _REENT_ONLY
 
 char *
@@ -1024,4 +1251,27 @@ _DEFUN_VOID (localeconv)
   return _localeconv_r (_REENT);
 }
 
+struct __locale_t *
+newlocale (int category_mask, const char *locale, struct __locale_t *base)
+{
+  return _newlocale_r (_REENT, category_mask, locale, base);
+}
+
+void
+freelocale (struct __locale_t *locobj)
+{
+  _freelocale_r (_REENT, locobj);
+}
+
+struct __locale_t *
+duplocale (struct __locale_t *locobj)
+{
+  return _duplocale_r (_REENT, locobj);
+}
+
+struct __locale_t *
+uselocale (struct __locale_t *newloc)
+{
+  return _uselocale_r (_REENT, newloc);
+}
 #endif
index acb3fabb9b916a1b6ff8c960d38a563ae4793f21..0660a38e79a2708389daa11ac81242b07574b34e 100644 (file)
@@ -381,6 +381,7 @@ dreml= remainderl NOSIGFE
 dup SIGFE
 dup2 SIGFE
 dup3 SIGFE
+duplocale SIGFE
 eaccess = euidaccess SIGFE
 ecvt SIGFE
 ecvtbuf SIGFE
@@ -536,6 +537,7 @@ fread_unlocked SIGFE
 free SIGFE
 freeaddrinfo = cygwin_freeaddrinfo SIGFE
 freeifaddrs SIGFE
+freelocale SIGFE
 fremovexattr SIGFE
 freopen SIGFE
 frexp NOSIGFE
@@ -900,6 +902,7 @@ nanosleep SIGFE
 nearbyint NOSIGFE
 nearbyintf NOSIGFE
 nearbyintl NOSIGFE
+newlocale SIGFE
 nextafter NOSIGFE
 nextafterf NOSIGFE
 nextafterl NOSIGFE
@@ -1417,6 +1420,7 @@ unlockpt NOSIGFE
 unsetenv SIGFE
 updwtmp SIGFE
 updwtmpx SIGFE
+uselocale SIGFE
 usleep SIGFE
 utime SIGFE
 utimensat SIGFE
index 1f5bf721256b70a4fa9b69c91a23e95ee7934f28..9ae5983f8026114e014c0d4a519c8112d7f4a72b 100644 (file)
@@ -10,8 +10,8 @@ details. */
    the Cygwin shared library".  This version is used to track important
    changes to the DLL and is mainly informative in nature. */
 
-#define CYGWIN_VERSION_DLL_MAJOR 2005
-#define CYGWIN_VERSION_DLL_MINOR 3
+#define CYGWIN_VERSION_DLL_MAJOR 2006
+#define CYGWIN_VERSION_DLL_MINOR 0
 
 /* Major numbers before CYGWIN_VERSION_DLL_EPOCH are incompatible. */
 
@@ -454,12 +454,13 @@ details. */
        nexttowardf, nexttowardl, pow10l, powl, remainderl, remquol, roundl,
        scalbl, scalblnl, scalbnl, sincosl, sinhl, sinl, tanhl, tanl,
        tgammal, truncl.
+  298: newlocale, freelocale, duplocale, uselocale.
 
   Note that we forgot to bump the api for ualarm, strtoll, strtoull,
   sigaltstack, sethostname. */
 
 #define CYGWIN_VERSION_API_MAJOR 0
-#define CYGWIN_VERSION_API_MINOR 297
+#define CYGWIN_VERSION_API_MINOR 298
 
 /* There is also a compatibity version number associated with the shared memory
    regions.  It is incremented when incompatible changes are made to the shared
This page took 0.042272 seconds and 5 git commands to generate.