about summary refs log tree commit diff
path: root/libio
diff options
context:
space:
mode:
Diffstat (limited to 'libio')
-rw-r--r--libio/fileops.c120
-rw-r--r--libio/iofclose.c12
-rw-r--r--libio/iofwide.c23
3 files changed, 101 insertions, 54 deletions
diff --git a/libio/fileops.c b/libio/fileops.c
index 03f71d71c0..3947fa8d6c 100644
--- a/libio/fileops.c
+++ b/libio/fileops.c
@@ -31,6 +31,7 @@
 # define _POSIX_SOURCE
 #endif
 #include "libioP.h"
+#include <assert.h>
 #include <fcntl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -42,6 +43,8 @@
 #endif
 #if _LIBC
 # include "../wcsmbs/wcsmbsload.h"
+# include "../iconv/gconv_charset.h"
+# include "../iconv/gconv_int.h"
 # include <shlib-compat.h>
 #endif
 #ifndef errno
@@ -74,6 +77,12 @@ extern int errno;
 # define _IO_new_file_xsputn _IO_file_xsputn
 #endif
 
+
+#ifdef _LIBC
+extern struct __gconv_trans_data __libio_translit;
+#endif
+
+
 /* An fstream can be in at most one of put mode, get mode, or putback mode.
    Putback mode is a variant of get mode.
 
@@ -238,8 +247,9 @@ _IO_new_file_fopen (fp, filename, mode, is32not64)
   int oprot = 0666;
   int i;
   _IO_FILE *result;
-#if _LIBC
+#ifdef _LIBC
   const char *cs;
+  const char *last_recognized;
 #endif
 
   if (_IO_file_is_open (fp))
@@ -264,6 +274,9 @@ _IO_new_file_fopen (fp, filename, mode, is32not64)
       __set_errno (EINVAL);
       return NULL;
     }
+#ifdef _LIBC
+  last_recognized = mode;
+#endif
   for (i = 1; i < 4; ++i)
     {
       switch (*++mode)
@@ -273,11 +286,20 @@ _IO_new_file_fopen (fp, filename, mode, is32not64)
 	case '+':
 	  omode = O_RDWR;
 	  read_write &= _IO_IS_APPENDING;
+#ifdef _LIBC
+	  last_recognized = mode;
+#endif
 	  continue;
 	case 'x':
 	  oflags |= O_EXCL;
+#ifdef _LIBC
+	  last_recognized = mode;
+#endif
 	  continue;
 	case 'b':
+#ifdef _LIBC
+	  last_recognized = mode;
+#endif
 	default:
 	  /* Ignore.  */
 	  continue;
@@ -289,48 +311,78 @@ _IO_new_file_fopen (fp, filename, mode, is32not64)
 			  is32not64);
 
 
-#if _LIBC
-  /* Test whether the mode string specifies the conversion.  */
-  cs = strstr (mode, ",ccs=");
-  if (cs != NULL)
+#ifdef _LIBC
+  if (result != NULL)
     {
-      /* Yep.  Load the appropriate conversions and set the orientation
-	 to wide.  */
-	struct gconv_fcts fcts;
-	struct _IO_codecvt *cc;
+      /* Test whether the mode string specifies the conversion.  */
+      cs = strstr (last_recognized + 1, ",ccs=");
+      if (cs != NULL)
+	{
+	  /* Yep.  Load the appropriate conversions and set the orientation
+	     to wide.  */
+	  struct gconv_fcts fcts;
+	  struct _IO_codecvt *cc;
+	  char *endp = __strchrnul (cs + 5, ',');
+	  char ccs[endp - (cs + 5) + 3];
+
+	  *((char *) __mempcpy (ccs, cs + 5, endp - (cs + 5))) = '\0';
+	  strip (ccs, ccs);
+
+	  if (__wcsmbs_named_conv (&fcts, ccs[2] == '\0'
+				   ? upstr (ccs, cs + 5) : ccs) != 0)
+	    {
+	      /* Something went wrong, we cannot load the conversion modules.
+		 This means we cannot proceed since the user explicitly asked
+		 for these.  */
+	      __set_errno (EINVAL);
+	      return NULL;
+	    }
 
-	if (! _IO_CHECK_WIDE (fp) || __wcsmbs_named_conv (&fcts, cs + 5) != 0)
-	  {
-	    /* Something went wrong, we cannot load the conversion modules.
-	       This means we cannot proceed since the user explicitly asked
-	       for these.  */
-	    _IO_new_fclose (result);
-	    return NULL;
-	  }
+	  assert (fcts.towc_nsteps == 1);
+	  assert (fcts.tomb_nsteps == 1);
+
+	  fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
+	  fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_write_base;
+
+	  /* Clear the state.  We start all over again.  */
+	  memset (&fp->_wide_data->_IO_state, '\0', sizeof (__mbstate_t));
+	  memset (&fp->_wide_data->_IO_last_state, '\0', sizeof (__mbstate_t));
+
+	  cc = fp->_codecvt = &fp->_wide_data->_codecvt;
 
-	cc = fp->_codecvt = &fp->_wide_data->_codecvt;
+	  /* The functions are always the same.  */
+	  *cc = __libio_codecvt;
 
-	/* The functions are always the same.  */
-	*cc = __libio_codecvt;
+	  cc->__cd_in.__cd.__nsteps = fcts.towc_nsteps;
+	  cc->__cd_in.__cd.__steps = fcts.towc;
 
-	cc->__cd_in.__cd.__nsteps = 1; /* Only one step allowed.  */
-	cc->__cd_in.__cd.__steps = fcts.towc;
+	  cc->__cd_in.__cd.__data[0].__invocation_counter = 0;
+	  cc->__cd_in.__cd.__data[0].__internal_use = 1;
+	  cc->__cd_in.__cd.__data[0].__flags = __GCONV_IS_LAST;
+	  cc->__cd_in.__cd.__data[0].__statep = &result->_wide_data->_IO_state;
 
-	cc->__cd_in.__cd.__data[0].__invocation_counter = 0;
-	cc->__cd_in.__cd.__data[0].__internal_use = 1;
-	cc->__cd_in.__cd.__data[0].__flags = __GCONV_IS_LAST;
-	cc->__cd_in.__cd.__data[0].__statep = &result->_wide_data->_IO_state;
+	  /* XXX For now no transliteration.  */
+	  cc->__cd_in.__cd.__data[0].__trans = NULL;
 
-	cc->__cd_out.__cd.__nsteps = 1; /* Only one step allowed.  */
-	cc->__cd_out.__cd.__steps = fcts.tomb;
+	  cc->__cd_out.__cd.__nsteps = fcts.tomb_nsteps;
+	  cc->__cd_out.__cd.__steps = fcts.tomb;
 
-	cc->__cd_out.__cd.__data[0].__invocation_counter = 0;
-	cc->__cd_out.__cd.__data[0].__internal_use = 1;
-	cc->__cd_out.__cd.__data[0].__flags = __GCONV_IS_LAST;
-	cc->__cd_out.__cd.__data[0].__statep = &result->_wide_data->_IO_state;
+	  cc->__cd_out.__cd.__data[0].__invocation_counter = 0;
+	  cc->__cd_out.__cd.__data[0].__internal_use = 1;
+	  cc->__cd_out.__cd.__data[0].__flags = __GCONV_IS_LAST;
+	  cc->__cd_out.__cd.__data[0].__statep =
+	    &result->_wide_data->_IO_state;
 
-	/* Set the mode now.  */
-	result->_mode = 1;
+	  /* And now the transliteration.  */
+	  cc->__cd_out.__cd.__data[0].__trans = &__libio_translit;
+
+	  /* Set the mode now.  */
+	  result->_mode = 1;
+
+	  /* We don't need the step data structure anymore.  */
+	  __gconv_release_cache (fcts.towc, fcts.towc_nsteps);
+	  __gconv_release_cache (fcts.tomb, fcts.tomb_nsteps);
+	}
     }
 #endif	/* GNU libc */
 
diff --git a/libio/iofclose.c b/libio/iofclose.c
index 660c118359..45bd0afa7d 100644
--- a/libio/iofclose.c
+++ b/libio/iofclose.c
@@ -72,16 +72,8 @@ _IO_new_fclose (fp)
 	 the conversion functions.  */
       struct _IO_codecvt *cc = fp->_codecvt;
 
-      if (cc->__cd_in.__cd.__steps->__shlib_handle != NULL)
-	{
-	  --cc->__cd_in.__cd.__steps->__counter;
-	  __gconv_close_transform (cc->__cd_in.__cd.__steps, 1);
-	}
-      if (cc->__cd_out.__cd.__steps->__shlib_handle != NULL)
-	{
-	  --cc->__cd_out.__cd.__steps->__counter;
-	  __gconv_close_transform (cc->__cd_out.__cd.__steps, 1);
-	}
+      __gconv_release_step (cc->__cd_in.__cd.__steps);
+      __gconv_release_step (cc->__cd_out.__cd.__steps);
 #endif
     }
   _IO_cleanup_region_end (0);
diff --git a/libio/iofwide.c b/libio/iofwide.c
index d191baaf99..aa314fe671 100644
--- a/libio/iofwide.c
+++ b/libio/iofwide.c
@@ -30,6 +30,7 @@
 # include <dlfcn.h>
 # include <wchar.h>
 #endif
+#include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -81,7 +82,7 @@ struct _IO_codecvt __libio_codecvt =
 
 
 #ifdef _LIBC
-static struct __gconv_trans_data libio_translit =
+struct __gconv_trans_data __libio_translit =
 {
   .__trans_fct = __gconv_transliterate
 };
@@ -134,11 +135,13 @@ _IO_fwide (fp, mode)
 	memset (&fp->_wide_data->_IO_last_state, '\0', sizeof (__mbstate_t));
 
 	__wcsmbs_clone_conv (&fcts);
+	assert (fcts.towc_nsteps == 1);
+	assert (fcts.tomb_nsteps == 1);
 
 	/* The functions are always the same.  */
 	*cc = __libio_codecvt;
 
-	cc->__cd_in.__cd.__nsteps = 1; /* Only one step allowed.  */
+	cc->__cd_in.__cd.__nsteps = fcts.towc_nsteps;
 	cc->__cd_in.__cd.__steps = fcts.towc;
 
 	cc->__cd_in.__cd.__data[0].__invocation_counter = 0;
@@ -149,7 +152,7 @@ _IO_fwide (fp, mode)
 	/* XXX For now no transliteration.  */
 	cc->__cd_in.__cd.__data[0].__trans = NULL;
 
-	cc->__cd_out.__cd.__nsteps = 1; /* Only one step allowed.  */
+	cc->__cd_out.__cd.__nsteps = fcts.tomb_nsteps;
 	cc->__cd_out.__cd.__steps = fcts.tomb;
 
 	cc->__cd_out.__cd.__data[0].__invocation_counter = 0;
@@ -158,11 +161,7 @@ _IO_fwide (fp, mode)
 	cc->__cd_out.__cd.__data[0].__statep = &fp->_wide_data->_IO_state;
 
 	/* And now the transliteration.  */
-#ifdef _LIBC
-	cc->__cd_out.__cd.__data[0].__trans = &libio_translit;
-#else
-	cc->__cd_out.__cd.__data[0].__trans = NULL;
-#endif
+	cc->__cd_out.__cd.__data[0].__trans = &__libio_translit;
       }
 #else
 # ifdef _GLIBCPP_USE_WCHAR_T
@@ -188,8 +187,12 @@ _IO_fwide (fp, mode)
 	  cc->__cd_out = iconv_open (external_ccs, internal_ccs);
 
 	if (cc->__cd_in == (iconv_t) -1 || cc->__cd_out == (iconv_t) -1)
-	  /* XXX */
-	  abort ();
+	  {
+	    if (cc->__cd_in != (iconv_t) -1)
+	      iconv_close (cc->__cd_in);
+	    /* XXX */
+	    abort ();
+	  }
       }
 # else
 #  error "somehow determine this from LC_CTYPE"