about summary refs log tree commit diff
path: root/wcsmbs/wcsmbsload.c
diff options
context:
space:
mode:
Diffstat (limited to 'wcsmbs/wcsmbsload.c')
-rw-r--r--wcsmbs/wcsmbsload.c88
1 files changed, 65 insertions, 23 deletions
diff --git a/wcsmbs/wcsmbsload.c b/wcsmbs/wcsmbsload.c
index f5d9426c32..c096804a68 100644
--- a/wcsmbs/wcsmbsload.c
+++ b/wcsmbs/wcsmbsload.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
 
@@ -41,8 +41,8 @@ static struct __gconv_step to_wc =
   .__shlib_handle = NULL,
   .__modname = NULL,
   .__counter = INT_MAX,
-  .__from_name = "ANSI_X3.4-1968//TRANSLIT",
-  .__to_name = "INTERNAL",
+  .__from_name = (char *) "ANSI_X3.4-1968//TRANSLIT",
+  .__to_name = (char *) "INTERNAL",
   .__fct = __gconv_transform_ascii_internal,
   .__init_fct = NULL,
   .__end_fct = NULL,
@@ -59,8 +59,8 @@ static struct __gconv_step to_mb =
   .__shlib_handle = NULL,
   .__modname = NULL,
   .__counter = INT_MAX,
-  .__from_name = "INTERNAL",
-  .__to_name = "ANSI_X3.4-1968//TRANSLIT",
+  .__from_name = (char *) "INTERNAL",
+  .__to_name = (char *) "ANSI_X3.4-1968//TRANSLIT",
   .__fct = __gconv_transform_internal_ascii,
   .__init_fct = NULL,
   .__end_fct = NULL,
@@ -77,22 +77,33 @@ static struct __gconv_step to_mb =
 struct gconv_fcts __wcsmbs_gconv_fcts =
 {
   .towc = &to_wc,
-  .tomb = &to_mb
+  .towc_nsteps = 1,
+  .tomb = &to_mb,
+  .tomb_nsteps = 1
 };
 
 
 static inline struct __gconv_step *
-getfct (const char *to, const char *from)
+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.  */
@@ -101,11 +112,16 @@ getfct (const char *to, const char *from)
     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;
 }
@@ -160,12 +176,18 @@ __wcsmbs_load_conv (const struct locale_data *new_category)
 	  const char *charset_name;
 	  const char *complete_name;
 	  struct __gconv_step *new_towc;
+	  size_t new_towc_nsteps;
 	  struct __gconv_step *new_tomb;
+	  size_t new_tomb_nsteps;
 	  int use_translit;
 
 	  /* Free the old conversions.  */
-	  __gconv_close_transform (__wcsmbs_gconv_fcts.tomb, 1);
-	  __gconv_close_transform (__wcsmbs_gconv_fcts.towc, 1);
+	  if (__wcsmbs_gconv_fcts.tomb != &to_mb)
+	    __gconv_close_transform (__wcsmbs_gconv_fcts.tomb,
+				     __wcsmbs_gconv_fcts.tomb_nsteps);
+	  if (__wcsmbs_gconv_fcts.towc != &to_wc)
+	    __gconv_close_transform (__wcsmbs_gconv_fcts.towc,
+				     __wcsmbs_gconv_fcts.towc_nsteps);
 
 	  /* Get name of charset of the locale.  */
 	  charset_name = new_category->values[_NL_ITEM_INDEX(CODESET)].string;
@@ -181,9 +203,10 @@ __wcsmbs_load_conv (const struct locale_data *new_category)
 	  /* 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_towc = getfct ("INTERNAL", complete_name);
+	  new_towc = getfct ("INTERNAL", complete_name, &new_towc_nsteps);
 	  new_tomb = (new_towc != NULL
-		      ? getfct (complete_name, "INTERNAL") : NULL);
+		      ? getfct (complete_name, "INTERNAL", &new_tomb_nsteps)
+		      : NULL);
 
 	  /* If any of the conversion functions is not available we don't
 	     use any since this would mean we cannot convert back and
@@ -197,7 +220,9 @@ __wcsmbs_load_conv (const struct locale_data *new_category)
 	    }
 
 	  __wcsmbs_gconv_fcts.tomb = new_tomb;
+	  __wcsmbs_gconv_fcts.tomb_nsteps = new_tomb_nsteps;
 	  __wcsmbs_gconv_fcts.towc = new_towc;
+	  __wcsmbs_gconv_fcts.towc_nsteps = new_towc_nsteps;
 	}
 
       /* Set last-used variable for current locale.  */
@@ -232,27 +257,44 @@ __wcsmbs_clone_conv (struct gconv_fcts *copy)
 }
 
 
-/* Clone the current conversion function set.  */
+/* Get converters for named charset.  */
 int
 internal_function
 __wcsmbs_named_conv (struct gconv_fcts *copy, const char *name)
 {
-  copy->towc = getfct ("INTERNAL", name);
+  copy->towc = getfct ("INTERNAL", name, &copy->towc_nsteps);
   if (copy->towc != NULL)
     {
-      copy->tomb = getfct (name, "INTERNAL");
+      copy->tomb = getfct (name, "INTERNAL", &copy->tomb_nsteps);
       if (copy->tomb == NULL)
-	__gconv_close_transform (copy->towc, 1);
+	__gconv_close_transform (copy->towc, copy->towc_nsteps);
     }
 
-  if (copy->towc == NULL || copy->tomb == NULL)
-    return 1;
+  return copy->towc == NULL || copy->tomb == NULL ? 1 : 0;
+}
 
-  /* Now increment the usage counters.  */
-  if (copy->towc->__shlib_handle != NULL)
-    ++copy->towc->__counter;
-  if (copy->tomb->__shlib_handle != NULL)
-    ++copy->tomb->__counter;
 
-  return 0;
+/* Free all resources if necessary.  */
+static void __attribute__ ((unused))
+free_mem (void)
+{
+  if (__wcsmbs_gconv_fcts.tomb != &to_mb)
+    {
+      struct __gconv_step *old = __wcsmbs_gconv_fcts.tomb;
+      size_t nold = __wcsmbs_gconv_fcts.tomb_nsteps;
+      __wcsmbs_gconv_fcts.tomb = &to_mb;
+      __wcsmbs_gconv_fcts.tomb_nsteps = 1;
+      __gconv_release_cache (old, nold);
+    }
+
+  if (__wcsmbs_gconv_fcts.towc != &to_wc)
+    {
+      struct __gconv_step *old = __wcsmbs_gconv_fcts.towc;
+      size_t nold = __wcsmbs_gconv_fcts.towc_nsteps;
+      __wcsmbs_gconv_fcts.towc = &to_wc;
+      __wcsmbs_gconv_fcts.towc_nsteps = 1;
+      __gconv_release_cache (old, nold);
+    }
 }
+
+text_set_element (__libc_subfreeres, free_mem);