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:
parent
d4f6cae9cd
commit
aefd8b5b51
|
@ -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_ */
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue