| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- /* Copyright (C) 1998-2026 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, see
- <https://www.gnu.org/licenses/>. */
- #include <ctype.h>
- #include <langinfo.h>
- #include <limits.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <locale/localeinfo.h>
- #include <wcsmbsload.h>
- #include <libc-lock.h>
- /* These are the descriptions for the default conversion functions. */
- static const struct __gconv_step to_wc =
- {
- .__shlib_handle = NULL,
- .__modname = NULL,
- .__counter = INT_MAX,
- .__from_name = (char *) "ANSI_X3.4-1968//TRANSLIT",
- .__to_name = (char *) "INTERNAL",
- .__fct = __gconv_transform_ascii_internal,
- .__btowc_fct = __gconv_btwoc_ascii,
- .__init_fct = NULL,
- .__end_fct = NULL,
- .__min_needed_from = 1,
- .__max_needed_from = 1,
- .__min_needed_to = 4,
- .__max_needed_to = 4,
- .__stateful = 0,
- .__data = NULL
- };
- static const struct __gconv_step to_mb =
- {
- .__shlib_handle = NULL,
- .__modname = NULL,
- .__counter = INT_MAX,
- .__from_name = (char *) "INTERNAL",
- .__to_name = (char *) "ANSI_X3.4-1968//TRANSLIT",
- .__fct = __gconv_transform_internal_ascii,
- .__btowc_fct = NULL,
- .__init_fct = NULL,
- .__end_fct = NULL,
- .__min_needed_from = 4,
- .__max_needed_from = 4,
- .__min_needed_to = 1,
- .__max_needed_to = 1,
- .__stateful = 0,
- .__data = NULL
- };
- /* For the default locale we only have to handle ANSI_X3.4-1968. */
- const struct gconv_fcts __wcsmbs_gconv_fcts_c =
- {
- .towc = (struct __gconv_step *) &to_wc,
- .towc_nsteps = 1,
- .tomb = (struct __gconv_step *) &to_mb,
- .tomb_nsteps = 1,
- };
- attribute_hidden
- struct __gconv_step *
- __wcsmbs_getfct (const char *to, const char *from, size_t *nstepsp)
- {
- size_t nsteps;
- struct __gconv_step *result;
- #if 0
- size_t nstateful;
- size_t cnt;
- #endif
- if (__gconv_find_transform (to, from, &result, &nsteps, 0) != __GCONV_OK)
- /* Loading the conversion step is not possible. */
- return NULL;
- /* Maybe it is someday necessary to allow more than one step.
- Currently this is not the case since the conversions handled here
- are from and to INTERNAL and there always is a converted for
- that. It the directly following code is enabled the libio
- functions will have to allocate appropriate __gconv_step_data
- elements instead of only one. */
- #if 0
- /* Count the number of stateful conversions. Since we will only
- have one 'mbstate_t' object available we can only deal with one
- stateful conversion. */
- nstateful = 0;
- for (cnt = 0; cnt < nsteps; ++cnt)
- if (result[cnt].__stateful)
- ++nstateful;
- if (nstateful > 1)
- #else
- if (nsteps > 1)
- #endif
- {
- /* We cannot handle this case. */
- __gconv_close_transform (result, nsteps);
- result = NULL;
- }
- else
- *nstepsp = nsteps;
- return result;
- }
- /* Extract from the given locale name the character set portion. Since
- only the XPG form of the name includes this information we don't have
- to take care for the CEN form. */
- #define extract_charset_name(str) \
- ({ \
- const char *cp = str; \
- char *result = NULL; \
- \
- cp += strcspn (cp, "@.+,"); \
- if (*cp == '.') \
- { \
- const char *endp = ++cp; \
- while (*endp != '\0' && *endp != '@') \
- ++endp; \
- if (endp != cp) \
- result = strndupa (cp, endp - cp); \
- } \
- result; \
- })
- /* Some of the functions here must not be used while setlocale is called. */
- __libc_rwlock_define (extern, __libc_setlocale_lock attribute_hidden)
- /* Load conversion functions for the currently selected locale. */
- void
- __wcsmbs_load_conv (struct __locale_data *new_category)
- {
- struct lc_ctype_data *data = new_category->private;
- /* Acquire the lock. */
- __libc_rwlock_wrlock (__libc_setlocale_lock);
- /* We should repeat the test since while we waited some other thread
- might have run this function. */
- if (__glibc_likely (data->fcts == NULL))
- {
- /* We must find the real functions. */
- const char *charset_name;
- const char *complete_name;
- struct gconv_fcts *new_fcts;
- int use_translit;
- /* Allocate the gconv_fcts structure. */
- new_fcts = calloc (1, sizeof *new_fcts);
- if (new_fcts == NULL)
- goto failed;
- /* Get name of charset of the locale. */
- charset_name = new_category->values[_NL_ITEM_INDEX(CODESET)].string;
- /* Does the user want transliteration? */
- use_translit = new_category->use_translit;
- /* Normalize the name and add the slashes necessary for a
- complete lookup. */
- complete_name = norm_add_slashes (charset_name,
- use_translit ? "TRANSLIT" : "");
- /* It is not necessary to use transliteration in this direction
- since the internal character set is supposed to be able to
- represent all others. */
- new_fcts->towc = __wcsmbs_getfct ("INTERNAL", complete_name,
- &new_fcts->towc_nsteps);
- if (new_fcts->towc != NULL)
- new_fcts->tomb = __wcsmbs_getfct (complete_name, "INTERNAL",
- &new_fcts->tomb_nsteps);
- /* If any of the conversion functions is not available we don't
- use any since this would mean we cannot convert back and
- forth. NB: NEW_FCTS was allocated with calloc. */
- if (new_fcts->tomb == NULL)
- {
- if (new_fcts->towc != NULL)
- __gconv_close_transform (new_fcts->towc, new_fcts->towc_nsteps);
- free (new_fcts);
- failed:
- data->fcts = (void *) &__wcsmbs_gconv_fcts_c;
- }
- else
- data->fcts = new_fcts;
- }
- __libc_rwlock_unlock (__libc_setlocale_lock);
- }
- /* Clone the current conversion function set. */
- void
- __wcsmbs_clone_conv (struct gconv_fcts *copy)
- {
- const struct gconv_fcts *orig;
- orig = get_gconv_fcts (_NL_CURRENT_DATA (LC_CTYPE));
- /* Copy the data. */
- *copy = *orig;
- /* Now increment the usage counters. Note: This assumes
- copy->*_nsteps == 1. The current locale holds a reference, so it
- is still there after acquiring the lock. */
- __libc_lock_lock (__gconv_lock);
- bool overflow = false;
- if (copy->towc->__shlib_handle != NULL)
- overflow |= __builtin_add_overflow (copy->towc->__counter, 1,
- ©->towc->__counter);
- if (copy->tomb->__shlib_handle != NULL)
- overflow |= __builtin_add_overflow (copy->tomb->__counter, 1,
- ©->tomb->__counter);
- __libc_lock_unlock (__gconv_lock);
- if (overflow)
- __libc_fatal ("\
- Fatal glibc error: gconv module reference counter overflow\n");
- }
- /* Get converters for named charset. */
- int
- __wcsmbs_named_conv (struct gconv_fcts *copy, const char *name)
- {
- copy->towc = __wcsmbs_getfct ("INTERNAL", name, ©->towc_nsteps);
- if (copy->towc == NULL)
- return 1;
- copy->tomb = __wcsmbs_getfct (name, "INTERNAL", ©->tomb_nsteps);
- if (copy->tomb == NULL)
- {
- __gconv_close_transform (copy->towc, copy->towc_nsteps);
- return 1;
- }
- return 0;
- }
- void
- _nl_cleanup_ctype (struct __locale_data *locale)
- {
- struct lc_ctype_data *data = locale->private;
- if (data->fcts != NULL && data->fcts != &__wcsmbs_gconv_fcts_c)
- {
- /* Free the old conversions. */
- __gconv_close_transform (data->fcts->tomb, data->fcts->tomb_nsteps);
- __gconv_close_transform (data->fcts->towc, data->fcts->towc_nsteps);
- free ((void *) data->fcts);
- data->fcts = NULL;
- /* data itself is allocated within locale. */
- }
- }
|