/* Duplicate handle for selection of locales.
- Copyright (C) 1997, 2000, 2001, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1997, 2000, 2001, 2002, 2005 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
__locale_t
__duplocale (__locale_t dataset)
{
+ /* This static object is returned for newlocale (LC_ALL_MASK, "C"). */
+ if (dataset == _nl_C_locobj_ptr)
+ return dataset;
+
__locale_t result;
int cnt;
+ size_t names_len = 0;
- /* We modify global data. */
- __libc_lock_lock (__libc_setlocale_lock);
+ /* Calculate the total space we need to store all the names. */
+ for (cnt = 0; cnt < __LC_LAST; ++cnt)
+ if (cnt != LC_ALL && dataset->__names[cnt] != _nl_C_name)
+ names_len += strlen (dataset->__names[cnt]) + 1;
/* Get memory. */
- result = (__locale_t) malloc (sizeof (struct __locale_struct));
-
- if (result != NULL)
- /* Duplicate the names in a separate loop first so we can
- bail out if strdup fails and not have touched usage_counts. */
- for (cnt = 0; cnt < __LC_LAST; ++cnt)
- if (cnt != LC_ALL)
- {
- if (dataset->__names[cnt] == _nl_C_name)
- result->__names[cnt] = _nl_C_name;
- else
- {
- result->__names[cnt] = __strdup (dataset->__names[cnt]);
- if (result->__names[cnt] == NULL)
- {
- while (cnt-- > 0)
- if (dataset->__names[cnt] != _nl_C_name)
- free ((char *) dataset->__names[cnt]);
- free (result);
- result = NULL;
- break;
- }
- }
- }
+ result = malloc (sizeof (struct __locale_struct) + names_len);
if (result != NULL)
{
+ char *namep = (char *) (result + 1);
+
+ /* We modify global data (the usage counts). */
+ __libc_lock_lock (__libc_setlocale_lock);
+
for (cnt = 0; cnt < __LC_LAST; ++cnt)
if (cnt != LC_ALL)
{
result->__locales[cnt] = dataset->__locales[cnt];
if (result->__locales[cnt]->usage_count < MAX_USAGE_COUNT)
++result->__locales[cnt]->usage_count;
+
+ if (dataset->__names[cnt] == _nl_C_name)
+ result->__names[cnt] = _nl_C_name;
+ else
+ {
+ result->__names[cnt] = namep;
+ namep = __stpcpy (namep, dataset->__names[cnt]) + 1;
+ }
}
/* Update the special members. */
result->__ctype_b = dataset->__ctype_b;
result->__ctype_tolower = dataset->__ctype_tolower;
result->__ctype_toupper = dataset->__ctype_toupper;
- }
- /* It's done. */
- __libc_lock_unlock (__libc_setlocale_lock);
+ /* It's done. */
+ __libc_lock_unlock (__libc_setlocale_lock);
+ }
return result;
}