aboutsummaryrefslogtreecommitdiff
path: root/libio/fileops.c
diff options
context:
space:
mode:
Diffstat (limited to 'libio/fileops.c')
-rw-r--r--libio/fileops.c120
1 files changed, 86 insertions, 34 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 */