diff options
Diffstat (limited to 'locale')
-rw-r--r-- | locale/duplocale.c | 51 | ||||
-rw-r--r-- | locale/freelocale.c | 19 | ||||
-rw-r--r-- | locale/newlocale.c | 118 | ||||
-rw-r--r-- | locale/xlocale.h | 4 |
4 files changed, 99 insertions, 93 deletions
diff --git a/locale/duplocale.c b/locale/duplocale.c index 867232e5a9..2fa29d14d6 100644 --- a/locale/duplocale.c +++ b/locale/duplocale.c @@ -35,54 +35,47 @@ __duplocale (__locale_t 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 (result->__names[cnt] != _nl_C_name) - free ((char *) result->__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; } diff --git a/locale/freelocale.c b/locale/freelocale.c index 2ba1432a27..ba0ae85d84 100644 --- a/locale/freelocale.c +++ b/locale/freelocale.c @@ -34,23 +34,18 @@ __freelocale (__locale_t dataset) { int cnt; - /* We modify global data. */ + /* We modify global data (the usage counts). */ __libc_lock_lock (__libc_setlocale_lock); for (cnt = 0; cnt < __LC_LAST; ++cnt) - if (cnt != LC_ALL) - { - if (dataset->__locales[cnt]->usage_count != UNDELETABLE) - /* We can remove the data. */ - _nl_remove_locale (cnt, dataset->__locales[cnt]); - if (dataset->__names[cnt] != _nl_C_name) - free ((char *) dataset->__names[cnt]); - } - - /* Free the locale_t handle itself. */ - free (dataset); + if (cnt != LC_ALL && dataset->__locales[cnt]->usage_count != UNDELETABLE) + /* We can remove the data. */ + _nl_remove_locale (cnt, dataset->__locales[cnt]); /* It's done. */ __libc_lock_unlock (__libc_setlocale_lock); + + /* Free the locale_t handle itself. */ + free (dataset); } weak_alias (__freelocale, freelocale) diff --git a/locale/newlocale.c b/locale/newlocale.c index ef6f94befb..3b8676ceeb 100644 --- a/locale/newlocale.c +++ b/locale/newlocale.c @@ -46,6 +46,7 @@ __newlocale (int category_mask, const char *locale, __locale_t base) size_t locale_path_len; const char *locpath_var; int cnt; + size_t names_len; /* We treat LC_ALL in the same way as if all bits were set. */ if (category_mask == 1 << LC_ALL) @@ -143,83 +144,98 @@ __newlocale (int category_mask, const char *locale, __locale_t base) } /* Now process all categories we are interested in. */ + names_len = 0; for (cnt = 0; cnt < __LC_LAST; ++cnt) - if ((category_mask & 1 << cnt) != 0) - { - result.__locales[cnt] = _nl_find_locale (locale_path, locale_path_len, - cnt, &newnames[cnt]); - if (result.__locales[cnt] == NULL) - { - free_data_and_exit: - while (cnt-- > 0) - if (((category_mask & 1 << cnt) != 0) - && result.__locales[cnt]->usage_count != UNDELETABLE) - /* We can remove the data. */ - _nl_remove_locale (cnt, result.__locales[cnt]); - return NULL; - } - } + { + if ((category_mask & 1 << cnt) != 0) + { + result.__locales[cnt] = _nl_find_locale (locale_path, + locale_path_len, + cnt, &newnames[cnt]); + if (result.__locales[cnt] == NULL) + { + free_cnt_data_and_exit: + while (cnt-- > 0) + if (((category_mask & 1 << cnt) != 0) + && result.__locales[cnt]->usage_count != UNDELETABLE) + /* We can remove the data. */ + _nl_remove_locale (cnt, result.__locales[cnt]); + return NULL; + } + + if (newnames[cnt] != _nl_C_name) + names_len += strlen (newnames[cnt]) + 1; + } + else if (cnt != LC_ALL && result.__names[cnt] != _nl_C_name) + /* Tally up the unchanged names from BASE as well. */ + names_len += strlen (result.__names[cnt]) + 1; + } + + /* We successfully loaded all required data. Allocate a new structure. + We can't just reuse the BASE pointer, because the name strings are + changing and we need the old name string area intact so we can copy + out of it into the new one without overlap problems should some + category's name be getting longer. */ + result_ptr = malloc (sizeof (struct __locale_struct) + names_len); + if (result_ptr == NULL) + { + cnt = __LC_LAST; + goto free_cnt_data_and_exit; + } - /* We successfully loaded all required data. */ if (base == NULL) { - /* Allocate new structure. */ - result_ptr = (__locale_t) malloc (sizeof (struct __locale_struct)); - if (result_ptr == NULL) - goto free_data_and_exit; + /* Fill in this new structure from scratch. */ + + char *namep = (char *) (result_ptr + 1); - /* Install strdup'd names in the new structure's __names array. + /* Install copied new names in the new structure's __names array. If resolved to "C", that is already in RESULT.__names to start. */ for (cnt = 0; cnt < __LC_LAST; ++cnt) if ((category_mask & 1 << cnt) != 0 && newnames[cnt] != _nl_C_name) { - result.__names[cnt] = __strdup (newnames[cnt]); - if (result.__names[cnt] == NULL) - { - free (result_ptr); - while (cnt-- > 0) - if (result.__names[cnt] != _nl_C_name) - free ((char *) result.__names[cnt]); - goto free_data_and_exit; - } + result.__names[cnt] = namep; + namep = __stpcpy (namep, newnames[cnt]) + 1; } *result_ptr = result; } else { - /* We modify the base structure. - First strdup the names we were given for the new locale. */ + /* We modify the base structure. */ - for (cnt = 0; cnt < __LC_LAST; ++cnt) - if ((category_mask & 1 << cnt) != 0 && newnames[cnt] != _nl_C_name) - { - newnames[cnt] = __strdup (newnames[cnt]); - if (newnames[cnt] == NULL) - { - while (cnt-- > 0) - if ((category_mask & 1 << cnt) != 0 && - newnames[cnt] != _nl_C_name) - free ((char *) newnames[cnt]); - goto free_data_and_exit; - } - } + char *namep = (char *) (result_ptr + 1); - /* Now that we can't lose, install the new data. */ for (cnt = 0; cnt < __LC_LAST; ++cnt) if ((category_mask & 1 << cnt) != 0) { if (base->__locales[cnt]->usage_count != UNDELETABLE) /* We can remove the old data. */ _nl_remove_locale (cnt, base->__locales[cnt]); - base->__locales[cnt] = result.__locales[cnt]; + result_ptr->__locales[cnt] = result.__locales[cnt]; - if (base->__names[cnt] != _nl_C_name) - free ((char *) base->__names[cnt]); - base->__names[cnt] = newnames[cnt]; + if (newnames[cnt] == _nl_C_name) + result_ptr->__names[cnt] = _nl_C_name; + else + { + result_ptr->__names[cnt] = namep; + namep = __stpcpy (namep, newnames[cnt]) + 1; + } + } + else if (cnt != LC_ALL) + { + /* The RESULT members point into the old BASE structure. */ + result_ptr->__locales[cnt] = result.__locales[cnt]; + if (result.__names[cnt] == _nl_C_name) + result_ptr->__names[cnt] = _nl_C_name; + else + { + result_ptr->__names[cnt] = namep; + namep = __stpcpy (namep, result.__names[cnt]) + 1; + } } - result_ptr = base; + free (base); } /* Update the special members. */ diff --git a/locale/xlocale.h b/locale/xlocale.h index 4fb557d3bf..2b17d6973f 100644 --- a/locale/xlocale.h +++ b/locale/xlocale.h @@ -29,12 +29,14 @@ typedef struct __locale_struct { /* Note: LC_ALL is not a valid index into this array. */ struct locale_data *__locales[13]; /* 13 = __LC_LAST. */ - const char *__names[13]; /* To increase the speed of this solution we add some special members. */ const unsigned short int *__ctype_b; const int *__ctype_tolower; const int *__ctype_toupper; + + /* Note: LC_ALL is not a valid index into this array. */ + const char *__names[13]; } *__locale_t; #endif /* xlocale.h */ |