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>
This commit is contained in:
Corinna Vinschen 2016-07-22 22:54:07 +02:00
parent d4f6cae9cd
commit aefd8b5b51
4 changed files with 274 additions and 9 deletions

View File

@ -65,15 +65,25 @@ struct lconv
char int_p_sign_posn; char int_p_sign_posn;
}; };
#ifndef _REENT_ONLY
char *_EXFUN(setlocale,(int category, const char *locale));
struct lconv *_EXFUN(localeconv,(void));
#endif
struct _reent; struct _reent;
char *_EXFUN(_setlocale_r,(struct _reent *, int category, const char *locale)); char *_EXFUN(_setlocale_r,(struct _reent *, int, const char *));
struct lconv *_EXFUN(_localeconv_r,(struct _reent *)); 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, const char *));
struct lconv *_EXFUN(localeconv,(void));
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 _END_STD_C
#endif /* _LOCALE_H_ */ #endif /* _LOCALE_H_ */

View File

@ -226,6 +226,34 @@ static char *categories[_LC_LAST] = {
*/ */
char __default_locale[ENCODING_LEN + 1] = DEFAULT_LOCALE; 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 = struct __locale_t __global_locale =
{ {
{ "C", "C", DEFAULT_LOCALE, "C", "C", "C", "C", }, { "C", "C", DEFAULT_LOCALE, "C", "C", "C", "C", },
@ -1008,6 +1036,205 @@ _DEFUN (_localeconv_r, (data),
return (struct lconv *) &lconv; 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 #ifndef _REENT_ONLY
char * char *
@ -1024,4 +1251,27 @@ _DEFUN_VOID (localeconv)
return _localeconv_r (_REENT); 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 #endif

View File

@ -381,6 +381,7 @@ dreml= remainderl NOSIGFE
dup SIGFE dup SIGFE
dup2 SIGFE dup2 SIGFE
dup3 SIGFE dup3 SIGFE
duplocale SIGFE
eaccess = euidaccess SIGFE eaccess = euidaccess SIGFE
ecvt SIGFE ecvt SIGFE
ecvtbuf SIGFE ecvtbuf SIGFE
@ -536,6 +537,7 @@ fread_unlocked SIGFE
free SIGFE free SIGFE
freeaddrinfo = cygwin_freeaddrinfo SIGFE freeaddrinfo = cygwin_freeaddrinfo SIGFE
freeifaddrs SIGFE freeifaddrs SIGFE
freelocale SIGFE
fremovexattr SIGFE fremovexattr SIGFE
freopen SIGFE freopen SIGFE
frexp NOSIGFE frexp NOSIGFE
@ -900,6 +902,7 @@ nanosleep SIGFE
nearbyint NOSIGFE nearbyint NOSIGFE
nearbyintf NOSIGFE nearbyintf NOSIGFE
nearbyintl NOSIGFE nearbyintl NOSIGFE
newlocale SIGFE
nextafter NOSIGFE nextafter NOSIGFE
nextafterf NOSIGFE nextafterf NOSIGFE
nextafterl NOSIGFE nextafterl NOSIGFE
@ -1417,6 +1420,7 @@ unlockpt NOSIGFE
unsetenv SIGFE unsetenv SIGFE
updwtmp SIGFE updwtmp SIGFE
updwtmpx SIGFE updwtmpx SIGFE
uselocale SIGFE
usleep SIGFE usleep SIGFE
utime SIGFE utime SIGFE
utimensat SIGFE utimensat SIGFE

View File

@ -10,8 +10,8 @@ details. */
the Cygwin shared library". This version is used to track important the Cygwin shared library". This version is used to track important
changes to the DLL and is mainly informative in nature. */ changes to the DLL and is mainly informative in nature. */
#define CYGWIN_VERSION_DLL_MAJOR 2005 #define CYGWIN_VERSION_DLL_MAJOR 2006
#define CYGWIN_VERSION_DLL_MINOR 3 #define CYGWIN_VERSION_DLL_MINOR 0
/* Major numbers before CYGWIN_VERSION_DLL_EPOCH are incompatible. */ /* Major numbers before CYGWIN_VERSION_DLL_EPOCH are incompatible. */
@ -454,12 +454,13 @@ details. */
nexttowardf, nexttowardl, pow10l, powl, remainderl, remquol, roundl, nexttowardf, nexttowardl, pow10l, powl, remainderl, remquol, roundl,
scalbl, scalblnl, scalbnl, sincosl, sinhl, sinl, tanhl, tanl, scalbl, scalblnl, scalbnl, sincosl, sinhl, sinl, tanhl, tanl,
tgammal, truncl. tgammal, truncl.
298: newlocale, freelocale, duplocale, uselocale.
Note that we forgot to bump the api for ualarm, strtoll, strtoull, Note that we forgot to bump the api for ualarm, strtoll, strtoull,
sigaltstack, sethostname. */ sigaltstack, sethostname. */
#define CYGWIN_VERSION_API_MAJOR 0 #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 /* There is also a compatibity version number associated with the shared memory
regions. It is incremented when incompatible changes are made to the shared regions. It is incremented when incompatible changes are made to the shared