summaryrefslogtreecommitdiff
path: root/wcsmbs/wcsmbsload.c
diff options
context:
space:
mode:
Diffstat (limited to 'wcsmbs/wcsmbsload.c')
-rw-r--r--wcsmbs/wcsmbsload.c140
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);
+}