diff options
Diffstat (limited to 'wcsmbs/wcsmbsload.c')
-rw-r--r-- | wcsmbs/wcsmbsload.c | 140 |
1 files changed, 94 insertions, 46 deletions
diff --git a/wcsmbs/wcsmbsload.c b/wcsmbs/wcsmbsload.c index b16aa6c500..b02acad68d 100644 --- a/wcsmbs/wcsmbsload.c +++ b/wcsmbs/wcsmbsload.c @@ -36,64 +36,76 @@ const struct locale_data *__wcsmbs_last_locale = &_nl_C_LC_CTYPE; /* These are the descriptions for the default conversion functions. */ -static struct gconv_step to_wc = +static struct __gconv_step to_wc = { - shlib_handle: NULL, - modname: NULL, - counter: INT_MAX, - from_name: "ANSI_X3.4-1968//", - to_name: "INTERNAL", - fct: __gconv_transform_ascii_internal, - 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 + .__shlib_handle = NULL, + .__modname = NULL, + .__counter = INT_MAX, + .__from_name = "ANSI_X3.4-1968//", + .__to_name = "INTERNAL", + .__fct = __gconv_transform_ascii_internal, + .__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 struct gconv_step to_mb = +static struct __gconv_step to_mb = { - shlib_handle: NULL, - modname: NULL, - counter: INT_MAX, - from_name: "INTERNAL", - to_name: "ANSI_X3.4-1968//", - fct: __gconv_transform_internal_ascii, - 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 + .__shlib_handle = NULL, + .__modname = NULL, + .__counter = INT_MAX, + .__from_name = "INTERNAL", + .__to_name = "ANSI_X3.4-1968//", + .__fct = __gconv_transform_internal_ascii, + .__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. */ struct gconv_fcts __wcsmbs_gconv_fcts = { - towc: &to_wc, - tomb: &to_mb + .towc = &to_wc, + .tomb = &to_mb }; -static inline struct gconv_step * +static inline struct __gconv_step * getfct (const char *to, const char *from) { size_t nsteps; - struct gconv_step *result; + struct __gconv_step *result; + size_t nstateful; + size_t cnt; - if (__gconv_find_transform (to, from, &result, &nsteps) != GCONV_OK) + if (__gconv_find_transform (to, from, &result, &nsteps) != __GCONV_OK) /* Loading the conversion step is not possible. */ return NULL; - /* We must only have one step in this conversion. */ - if (nsteps != 1) - return NULL; + /* 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) + { + /* We cannot handle this case. */ + __gconv_close_transform (result, nsteps); + result = NULL; + } return result; } @@ -148,14 +160,15 @@ getfct (const char *to, const char *from) }) +/* We must modify global data. */ +__libc_lock_define_initialized (static, lock) + + /* Load conversion functions for the currently selected locale. */ void internal_function __wcsmbs_load_conv (const struct locale_data *new_category) { - /* We must modify global data. */ - __libc_lock_define_initialized (static, lock) - /* Acquire the lock. */ __libc_lock_lock (lock); @@ -174,6 +187,12 @@ __wcsmbs_load_conv (const struct locale_data *new_category) /* We must find the real functions. */ const char *charset_name; const char *complete_name; + struct __gconv_step *new_towc; + struct __gconv_step *new_tomb; + + /* Free the old conversions. */ + __gconv_close_transform (__wcsmbs_gconv_fcts.tomb, 1); + __gconv_close_transform (__wcsmbs_gconv_fcts.towc, 1); /* Get name of charset of the locale. We first examine whether we have a character set mentioned in the locale @@ -188,15 +207,23 @@ __wcsmbs_load_conv (const struct locale_data *new_category) complete lookup. */ complete_name = norm_add_slashes (charset_name); - __wcsmbs_gconv_fcts.tomb = getfct (complete_name, "INTERNAL"); - __wcsmbs_gconv_fcts.towc = getfct ("INTERNAL", complete_name); + new_towc = getfct ("INTERNAL", complete_name); + if (new_towc != NULL) + new_tomb = getfct (complete_name, "INTERNAL"); /* If any of the conversion functions is not available we don't use any since this would mean we cannot convert back and forth.*/ - if (__wcsmbs_gconv_fcts.towc == NULL - || __wcsmbs_gconv_fcts.tomb == NULL) - goto failed; + if (new_towc == NULL || new_tomb == NULL) + { + if (new_towc != NULL) + __gconv_close_transform (new_towc, 1); + + goto failed; + } + + __wcsmbs_gconv_fcts.tomb = new_tomb; + __wcsmbs_gconv_fcts.towc = new_towc; } /* Set last-used variable for current locale. */ @@ -205,3 +232,24 @@ __wcsmbs_load_conv (const struct locale_data *new_category) __libc_lock_unlock (lock); } + + +/* Clone the current conversion function set. */ +void +internal_function +__wcsmbs_clone_conv (struct gconv_fcts *copy) +{ + /* Make sure the data structures remain the same until we are finished. */ + __libc_lock_lock (lock); + + /* Copy the data. */ + *copy = __wcsmbs_gconv_fcts; + + /* Now increment the usage counters. */ + if (copy->towc->__shlib_handle != NULL) + ++copy->towc->__counter; + if (copy->tomb->__shlib_handle != NULL) + ++copy->tomb->__counter; + + __libc_lock_unlock (lock); +} |