This is the mail archive of the cygwin-cvs@cygwin.com mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[newlib-cygwin] Implement newlocale, freelocale, duplocale, uselocale


https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=aefd8b5b518b958f64506a6f74aeffb4f47bde8a

commit aefd8b5b518b958f64506a6f74aeffb4f47bde8a
Author: Corinna Vinschen <corinna@vinschen.de>
Date:   Fri Jul 22 22:54:07 2016 +0200

    Implement newlocale, freelocale, duplocale, uselocale
    
    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>

Diff:
---
 newlib/libc/include/locale.h           |  20 ++-
 newlib/libc/locale/locale.c            | 250 +++++++++++++++++++++++++++++++++
 winsup/cygwin/common.din               |   4 +
 winsup/cygwin/include/cygwin/version.h |   7 +-
 4 files changed, 273 insertions(+), 8 deletions(-)

diff --git a/newlib/libc/include/locale.h b/newlib/libc/include/locale.h
index 40e4124..d60132c 100644
--- a/newlib/libc/include/locale.h
+++ b/newlib/libc/include/locale.h
@@ -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
 
diff --git a/newlib/libc/locale/locale.c b/newlib/libc/locale/locale.c
index 35c5e6c..4f2d6d2 100644
--- a/newlib/libc/locale/locale.c
+++ b/newlib/libc/locale/locale.c
@@ -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
diff --git a/winsup/cygwin/common.din b/winsup/cygwin/common.din
index acb3fab..0660a38 100644
--- a/winsup/cygwin/common.din
+++ b/winsup/cygwin/common.din
@@ -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
diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h
index 1f5bf72..9ae5983 100644
--- a/winsup/cygwin/include/cygwin/version.h
+++ b/winsup/cygwin/include/cygwin/version.h
@@ -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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]