Rewrite to use iconv functionality.
authordrepper <drepper>
Tue, 7 Apr 1998 09:14:56 +0000 (09:14 +0000)
committerdrepper <drepper>
Tue, 7 Apr 1998 09:14:56 +0000 (09:14 +0000)
wcsmbs/btowc.c
wcsmbs/mbrtowc.c
wcsmbs/mbsnrtowcs.c
wcsmbs/mbsrtowcs.c
wcsmbs/wcrtomb.c
wcsmbs/wcsnrtombs.c
wcsmbs/wcsrtombs.c
wcsmbs/wctob.c

index 4c2f9df..268b1f2 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>
 
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <gconv.h>
 #include <stdio.h>
+#include <string.h>
 #include <wchar.h>
+#include <wcsmbsload.h>
 
 
-/* We use UTF8 encoding for multibyte strings and therefore a valid
-   one byte multibyte string only can have a value from 0 to 0x7f.  */
 wint_t
 btowc (c)
      int c;
 {
-  if (WEOF != (wint_t) EOF || c < 0 || c > 0x7f)
+  char buf[sizeof (wchar_t)];
+  struct gconv_step_data data;
+  char inbuf[1];
+  size_t inbytes;
+  size_t converted;
+  int status;
+
+  /* If the parameter does not fit into one byte or it is the EOF value
+     we can give the answer now.  */
+  if (c < -128 || c > 127 || c == EOF)
+    return WEOF;
+
+  /* Tell where we want the result.  */
+  data.outbuf = (char *) buf;
+  data.outbufavail = 0;
+  data.outbufsize = sizeof (wchar_t);
+  data.is_last = 1;
+  data.statep = &data.__state;
+
+  /* Make sure we start in the initial state.  */
+  memset (&data.__state, '\0', sizeof (mbstate_t));
+
+  /* Make sure we use the correct function.  */
+  update_conversion_ptrs ();
+
+  /* Create the input string.  */
+  inbuf[0] = c;
+  inbytes = 1;
+
+  status = (*__wcsmbs_gconv_fcts.towc->fct) (__wcsmbs_gconv_fcts.towc,
+                                            &data, inbuf, &inbytes,
+                                            &converted, 0);
+  /* The conversion failed.  */
+  if (status != GCONV_OK && status != GCONV_FULL_OUTPUT)
     return WEOF;
-  else
-    return (wint_t) c;
+
+  return *(wchar_t *)buf;
 }
index cf0bbd6..99bc5a4 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
 
    Boston, MA 02111-1307, USA.  */
 
 #include <errno.h>
+#include <gconv.h>
 #include <wchar.h>
+#include <wcsmbsload.h>
+
+#include <assert.h>
 
 #ifndef EILSEQ
-#define EILSEQ EINVAL
+# define EILSEQ EINVAL
 #endif
 
 
-static mbstate_t internal;
+/* This is the private state used if PS is NULL.  */
+static mbstate_t state;
 
 size_t
 __mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps)
 {
-  size_t used = 0;
-
-  if (ps == NULL)
-    ps = &internal;
-
+  wchar_t buf[1];
+  struct gconv_step_data data;
+  size_t inbytes;
+  int status;
+  size_t result;
+
+  /* Tell where we want the result.  */
+  data.outbuf = (char *) (pwc ?: buf);
+  data.outbufavail = 0;
+  data.outbufsize = sizeof (wchar_t);
+  data.is_last = 1;
+  data.statep = ps ?: &state;
+
+  /* A first special case is if S is NULL.  This means put PS in the
+     initial state.  */
   if (s == NULL)
     {
-      /* See first paragraph of description in 7.16.6.3.2.  */
-      ps->count = 0;
-      return 0;
+      data.outbuf = (char *) buf;
+      s = "";
+      n = 1;
     }
 
-  if (n > 0)
-    {
-      if (ps->count == 0)
-       {
-         unsigned char byte = (unsigned char) *s++;
-         ++used;
-
-         /* We must look for a possible first byte of a UTF8 sequence.  */
-         if (byte < 0x80)
-           {
-             /* One byte sequence.  */
-             if (pwc != NULL)
-               *pwc = (wchar_t) byte;
-             return byte ? used : 0;
-           }
-
-         if ((byte & 0xc0) == 0x80 || (byte & 0xfe) == 0xfe)
-           {
-             /* Oh, oh.  An encoding error.  */
-             __set_errno (EILSEQ);
-             return (size_t) -1;
-           }
-
-         if ((byte & 0xe0) == 0xc0)
-           {
-             /* We expect two bytes.  */
-             ps->count = 1;
-             ps->value = byte & 0x1f;
-           }
-         else if ((byte & 0xf0) == 0xe0)
-           {
-             /* We expect three bytes.  */
-             ps->count = 2;
-             ps->value = byte & 0x0f;
-           }
-         else if ((byte & 0xf8) == 0xf0)
-           {
-             /* We expect four bytes.  */
-             ps->count = 3;
-             ps->value = byte & 0x07;
-           }
-         else if ((byte & 0xfc) == 0xf8)
-           {
-             /* We expect five bytes.  */
-             ps->count = 4;
-             ps->value = byte & 0x03;
-           }
-         else
-           {
-             /* We expect six bytes.  */
-             ps->count = 5;
-             ps->value = byte & 0x01;
-           }
-       }
+  /* Make sure we use the correct function.  */
+  update_conversion_ptrs ();
 
-      /* We know we have to handle a multibyte character and there are
-        some more bytes to read.  */
-      while (used < n)
+  /* Do a normal conversion.  */
+  inbytes = n;
+  status = (*__wcsmbs_gconv_fcts.towc->fct) (__wcsmbs_gconv_fcts.towc,
+                                            &data, s, &inbytes, NULL, 0);
+
+  /* There must not be any problems with the conversion but illegal input
+     characters.  The output buffer must be large enough, otherwise the
+     definition of MB_CUR_MAX is not correct.  All the other possible
+     errors also must not happen.  */
+  assert (status == GCONV_OK || status == GCONV_ILLEGAL_INPUT
+         || status == GCONV_INCOMPLETE_INPUT);
+
+  if (status == GCONV_OK)
+    {
+      if (*(wchar_t *)data.outbuf == L'\0')
        {
-         /* The second to sixths byte must be of the form 10xxxxxx.  */
-         unsigned char byte = (unsigned char) *s++;
-         ++used;
-
-         if ((byte & 0xc0) != 0x80)
-           {
-             /* Oh, oh.  An encoding error.  */
-             __set_errno (EILSEQ);
-             return (size_t) -1;
-           }
-
-         ps->value <<= 6;
-         ps->value |= byte & 0x3f;
-
-         if (--ps->count == 0)
-           {
-             /* The character is finished.  */
-             if (pwc != NULL)
-               *pwc = (wchar_t) ps->value;
-             return ps->value ? used : 0;
-           }
+         /* The converted character is the NUL character.  */
+         assert (mbsinit (data.statep));
+         result = 0;
        }
+      else
+       result = n - inbytes;
+    }
+  else
+    {
+      result = status == GCONV_INCOMPLETE_INPUT ? (size_t) -2 : (size_t) -1;
+      __set_errno (EILSEQ);
     }
 
-  return (size_t) -2;
+  return result;
 }
 weak_alias (__mbrtowc, mbrtowc)
index db67d5c..ded15e4 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
 
    Boston, MA 02111-1307, USA.  */
 
 #include <errno.h>
+#include <gconv.h>
+#include <string.h>
 #include <wchar.h>
+#include <wcsmbsload.h>
+
+#include <assert.h>
 
 #ifndef EILSEQ
-#define EILSEQ EINVAL
+# define EILSEQ EINVAL
 #endif
 
 
-/* We don't need the state really because we don't have shift states
-   to maintain between calls to this function.  */
-static mbstate_t internal;
+/* This is the private state used if PS is NULL.  */
+static mbstate_t state;
 
 /* This is a non-standard function but it is very useful in the
    implementation of stdio because we have to deal with unterminated
@@ -40,128 +44,89 @@ __mbsnrtowcs (dst, src, nmc, len, ps)
      size_t len;
      mbstate_t *ps;
 {
-  size_t written = 0;
-  const char *run = *src;
-  const char *last = run + nmc;
-  wchar_t value;
-  size_t count;
+  size_t inbytes_in;
+  struct gconv_step_data data;
+  size_t result = 0;
+  int status;
 
-  if (ps == NULL)
-    ps = &internal;
+  /* Tell where we want the result.  */
+  data.is_last = 1;
+  data.statep = ps ?: &state;
 
-  /* Get information from last use of this state.  */
-  count = ps->count;
-  value = ps->value;
+  if (nmc == 0)
+    return 0;
+  inbytes_in = __strnlen (*src, nmc - 1) + 1;
 
-  if (dst == NULL)
-    /* The LEN parameter has to be ignored if we don't actually write
-       anything.  */
-    len = ~0;
+  /* Make sure we use the correct function.  */
+  update_conversion_ptrs ();
 
-  /* Copy all words.  */
-  while (written < len && run < last)
+  /* We have to handle DST == NULL special.  */
+  if (dst == NULL)
     {
-      unsigned char byte;
-
-      /* Store address of next byte to process.  */
-      *src = run;
-
-      /* Start reading a new character only if we are in the initial
-        state.  */
-      if (count == 0)
-       {
-         byte = *run++;
-
-         /* We expect a start of a new multibyte character.  */
-         if (byte < 0x80)
-           {
-             /* One byte sequence.  */
-             count = 0;
-             value = byte;
-           }
-         else if ((byte & 0xe0) == 0xc0)
-           {
-             count = 1;
-             value = byte & 0x1f;
-           }
-         else if ((byte & 0xf0) == 0xe0)
-           {
-             /* We expect three bytes.  */
-             count = 2;
-             value = byte & 0x0f;
-           }
-         else if ((byte & 0xf8) == 0xf0)
-           {
-             /* We expect four bytes.  */
-             count = 3;
-             value = byte & 0x07;
-           }
-         else if ((byte & 0xfc) == 0xf8)
-           {
-             /* We expect five bytes.  */
-             count = 4;
-             value = byte & 0x03;
-           }
-         else if ((byte & 0xfe) == 0xfc)
-           {
-             /* We expect six bytes.  */
-             count = 5;
-             value = byte & 0x01;
-           }
-         else
-           {
-             /* This is an illegal encoding.  */
-             __set_errno (EILSEQ);
-             return (size_t) -1;
-           }
-       }
-
-      /* Read the possible remaining bytes.  */
-      while (run < last && count > 0)
-       {
-         byte = *run++;
-         --count;
-
-         if ((byte & 0xc0) != 0x80)
-           {
-             /* This is an illegal encoding.  */
-             __set_errno (EILSEQ);
-             return (size_t) -1;
-           }
-
-         value <<= 6;
-         value |= byte & 0x3f;
-       }
-
-      /* If this character is only partially available remember this.  */
-      if (run == last && count != 0)
+      wchar_t buf[64];         /* Just an arbitrary size.  */
+      size_t inbytes = inbytes_in;
+      const char *inbuf = *src;
+      size_t written;
+
+      data.outbuf = (char *) buf;
+      data.outbufsize = sizeof (buf);
+      do
        {
-         ps->count = count;
-         ps->value = value;
-         break;
+         inbuf += inbytes_in - inbytes;
+         inbytes_in = inbytes;
+         data.outbufavail = 0;
+         written = 0;
+
+         status = (*__wcsmbs_gconv_fcts.towc->fct) (__wcsmbs_gconv_fcts.towc,
+                                                    &data, inbuf, &inbytes,
+                                                    &written, 0);
+         result += written;
        }
+      while (status == GCONV_FULL_OUTPUT);
 
-      /* Store value is required.  */
-      if (dst != NULL)
-       *dst++ = value;
-
-      /* The whole sequence is read.  Check whether end of string is
-        reached.  */
-      if (value == L'\0')
+      if (status == GCONV_OK && ((wchar_t *) dst)[written - 1] == L'\0')
+       /* Don't count the NUL character in.  */
+       --result;
+    }
+  else
+    {
+      /* This code is based on the safe assumption that all internal
+        multi-byte encodings use the NUL byte only to mark the end
+        of the string.  */
+      size_t inbytes = inbytes_in;
+
+      data.outbuf = (char *) dst;
+      data.outbufsize = len * sizeof (wchar_t);
+      data.outbufavail = 0;
+
+      status = (*__wcsmbs_gconv_fcts.towc->fct) (__wcsmbs_gconv_fcts.towc,
+                                                &data, *src, &inbytes,
+                                                &result, 0);
+
+      /* We have to determine whether the last character converted
+        is the NUL character.  */
+      if (status == GCONV_OK && ((wchar_t *) dst)[result - 1] == L'\0')
        {
-         /* Found the end of the string.  */
+         assert (result > 0);
+         assert (mbsinit (data.statep));
          *src = NULL;
-         ps->count = 0;
-         return written;
+         --result;
        }
-
-      /* Increment counter of produced words.  */
-      ++written;
+      else
+       *src += inbytes_in - inbytes;
     }
 
-  /* Store address of next byte to process.  */
-  *src = run;
+  /* There must not be any problems with the conversion but illegal input
+     characters.  */
+  assert (status == GCONV_OK || status == GCONV_ILLEGAL_INPUT
+         || status == GCONV_INCOMPLETE_INPUT || status == GCONV_FULL_OUTPUT);
+
+  if (status != GCONV_OK && status != GCONV_FULL_OUTPUT)
+    {
+      result = (size_t) -1;
+      __set_errno (EILSEQ);
+    }
 
-  return written;
+  return result;
 }
 weak_alias (__mbsnrtowcs, mbsnrtowcs)
index 84d4cbf..d0af40f 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
 
    Boston, MA 02111-1307, USA.  */
 
 #include <errno.h>
+#include <gconv.h>
+#include <string.h>
 #include <wchar.h>
+#include <wcsmbsload.h>
+
+#include <assert.h>
 
 #ifndef EILSEQ
-#define EILSEQ EINVAL
+# define EILSEQ EINVAL
 #endif
 
 
-/* We don't need the state really because we don't have shift states
-   to maintain between calls to this function.  */
-static mbstate_t internal;
+/* This is the private state used if PS is NULL.  */
+static mbstate_t state;
 
 size_t
 __mbsrtowcs (dst, src, len, ps)
@@ -36,108 +40,86 @@ __mbsrtowcs (dst, src, len, ps)
      size_t len;
      mbstate_t *ps;
 {
-  size_t written = 0;
-  const char *run = *src;
+  struct gconv_step_data data;
+  size_t result = 0;
+  int status;
 
-  if (ps == NULL)
-    ps = &internal;
+  /* Tell where we want the result.  */
+  data.is_last = 1;
+  data.statep = ps ?: &state;
 
-  if (dst == NULL)
-    /* The LEN parameter has to be ignored if we don't actually write
-       anything.  */
-    len = ~0;
+  /* Make sure we use the correct function.  */
+  update_conversion_ptrs ();
 
-  /* Copy all words.  */
-  while (written < len)
+  /* We have to handle DST == NULL special.  */
+  if (dst == NULL)
     {
-      wchar_t value;
-      size_t count;
-      unsigned char byte;
-
-      /* Store address of next byte to process.  */
-      *src = run;
-
-      byte = *run++;
-
-      /* We expect a start of a new multibyte character.  */
-      if (byte < 0x80)
-       {
-         /* One byte sequence.  */
-         count = 0;
-         value = byte;
-       }
-      else if ((byte & 0xe0) == 0xc0)
-       {
-         count = 1;
-         value = byte & 0x1f;
-       }
-      else if ((byte & 0xf0) == 0xe0)
-       {
-         /* We expect three bytes.  */
-         count = 2;
-         value = byte & 0x0f;
-       }
-      else if ((byte & 0xf8) == 0xf0)
-       {
-         /* We expect four bytes.  */
-         count = 3;
-         value = byte & 0x07;
-       }
-      else if ((byte & 0xfc) == 0xf8)
-       {
-         /* We expect five bytes.  */
-         count = 4;
-         value = byte & 0x03;
-       }
-      else if ((byte & 0xfe) == 0xfc)
+      wchar_t buf[64];         /* Just an arbitrary size.  */
+      size_t inbytes_in = strlen (*src) + 1;
+      size_t inbytes = inbytes_in;
+      const char *inbuf = *src;
+      size_t written;
+
+      data.outbuf = (char *) buf;
+      data.outbufsize = sizeof (buf);
+      do
        {
-         /* We expect six bytes.  */
-         count = 5;
-         value = byte & 0x01;
-       }
-      else
-       {
-         /* This is an illegal encoding.  */
-         __set_errno (EILSEQ);
-         return (size_t) -1;
-       }
-
-      /* Read the possible remaining bytes.  */
-      while (count-- > 0)
-       {
-         byte = *run++;
-
-         if ((byte & 0xc0) != 0x80)
-           {
-             /* This is an illegal encoding.  */
-             __set_errno (EILSEQ);
-             return (size_t) -1;
-           }
-
-         value <<= 6;
-         value |= byte & 0x3f;
+         inbuf += inbytes_in - inbytes;
+         inbytes_in = inbytes;
+         data.outbufavail = 0;
+         written = 0;
+
+         status = (*__wcsmbs_gconv_fcts.towc->fct) (__wcsmbs_gconv_fcts.towc,
+                                                    &data, inbuf, &inbytes,
+                                                    &written, 0);
+         result += written;
        }
+      while (status == GCONV_FULL_OUTPUT);
 
-      /* Store value is required.  */
-      if (dst != NULL)
-       *dst++ = value;
-
-      /* The whole sequence is read.  Check whether end of string is
-        reached.  */
-      if (value == L'\0')
+      if (status == GCONV_OK && ((wchar_t *) dst)[written - 1] == L'\0')
+       /* Don't count the NUL character in.  */
+       --result;
+    }
+  else
+    {
+      /* This code is based on the safe assumption that all internal
+        multi-byte encodings use the NUL byte only to mark the end
+        of the string.  */
+      size_t inbytes_in = __strnlen (*src, len * MB_CUR_MAX) + 1;
+      size_t inbytes = inbytes_in;
+
+      data.outbuf = (char *) dst;
+      data.outbufsize = len * sizeof (wchar_t);
+      data.outbufavail = 0;
+
+      status = (*__wcsmbs_gconv_fcts.towc->fct) (__wcsmbs_gconv_fcts.towc,
+                                                &data, *src, &inbytes,
+                                                &result, 0);
+
+      /* We have to determine whether the last character converted
+        is the NUL character.  */
+      if (status == GCONV_OK && ((wchar_t *) dst)[result - 1] == L'\0')
        {
-         /* Found the end of the string.  */
+         assert (result > 0);
+         assert (mbsinit (data.statep));
          *src = NULL;
-         return written;
+         --result;
        }
-
-      /* Increment counter of produced words.  */
-      ++written;
+      else
+       *src += inbytes_in - inbytes;
     }
 
-  /* Store address of next byte to process.  */
-  *src = run;
+  /* There must not be any problems with the conversion but illegal input
+     characters.  */
+  assert (status == GCONV_OK || status == GCONV_ILLEGAL_INPUT
+         || status == GCONV_INCOMPLETE_INPUT || status == GCONV_FULL_OUTPUT);
+
+  if (status != GCONV_OK && status != GCONV_FULL_OUTPUT)
+    {
+      result = (size_t) -1;
+      __set_errno (EILSEQ);
+    }
 
-  return written;
+  return result;
 }
 weak_alias (__mbsrtowcs, mbsrtowcs)
index 63859e1..d45ae44 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
 
    Boston, MA 02111-1307, USA.  */
 
 #include <errno.h>
+#include <gconv.h>
+#include <stdlib.h>
 #include <wchar.h>
+#include <wcsmbsload.h>
+
+#include <assert.h>
 
 #ifndef EILSEQ
-#define EILSEQ EINVAL
+# define EILSEQ EINVAL
 #endif
 
-static const wchar_t encoding_mask[] =
-{
-  ~0x7ff, ~0xffff, ~0x1fffff, ~0x3ffffff
-};
-
-static const unsigned char encoding_byte[] =
-{
-  0xc0, 0xe0, 0xf0, 0xf8, 0xfc
-};
 
-/* The state is for this UTF8 encoding not used.  */
-static mbstate_t internal;
+/* This is the private state used if PS is NULL.  */
+static mbstate_t state;
 
 size_t
 __wcrtomb (char *s, wchar_t wc, mbstate_t *ps)
 {
-  size_t written = 0;
-
-  if (ps == NULL)
-    ps = &internal;
-
+  char buf[MB_CUR_MAX];
+  struct gconv_step_data data;
+  int status;
+  size_t result;
+
+  /* Tell where we want the result.  */
+  data.outbuf = s;
+  data.outbufavail = 0;
+  data.outbufsize = MB_CUR_MAX;
+  data.is_last = 1;
+  data.statep = ps ?: &state;
+
+  /* A first special case is if S is NULL.  This means put PS in the
+     initial state.  */
   if (s == NULL)
     {
-      /* This is equivalent to wcrtomb (<<internal>, L'\0', ps).  We
-        only have to reset the state.  */
-      ps->count = 0;
-      return 1;
+      data.outbuf = buf;
+      wc = L'\0';
     }
 
-  /* Store the UTF8 representation of WC.  */
-  if (wc < 0 || wc > 0x7fffffff)
+  /* Make sure we use the correct function.  */
+  update_conversion_ptrs ();
+
+  /* If WC is the NUL character we write into the output buffer the byte
+     sequence necessary for PS to get into the initial state, followed
+     by a NUL byte.  */
+  if (wc == L'\0')
     {
-      /* This is no correct ISO 10646 character.  */
-      __set_errno (EILSEQ);
-      return (size_t) -1;
-    }
+      size_t inbytes = 0;
+
+      status = (*__wcsmbs_gconv_fcts.tomb->fct) (__wcsmbs_gconv_fcts.tomb,
+                                                &data, NULL, &inbytes,
+                                                NULL, 1);
 
-  if (wc < 0x80)
+      if (status == GCONV_OK)
+       data.outbuf[data.outbufavail++] = '\0';
+    }
+  else
     {
-      /* It's a one byte sequence.  */
-      if (s != NULL)
-       *s = (char) wc;
-      ps->count = 0;
-      return 1;
+      /* Do a normal conversion.  */
+      size_t inbytes = sizeof (wchar_t);
+
+      status = (*__wcsmbs_gconv_fcts.tomb->fct) (__wcsmbs_gconv_fcts.tomb,
+                                                &data, (char *) &wc, &inbytes,
+                                                NULL, 0);
     }
 
-  for (written = 2; written < 6; ++written)
-    if ((wc & encoding_mask[written - 2]) == 0)
-      break;
+  /* There must not be any problems with the conversion but illegal input
+     characters.  The output buffer must be large enough, otherwise the
+     definition of MB_CUR_MAX is not correct.  All the other possible
+     errors also must not happen.  */
+  assert (status == GCONV_OK || status == GCONV_ILLEGAL_INPUT
+         || status == GCONV_INCOMPLETE_INPUT);
 
-  if (s != NULL)
+  if (status == GCONV_OK)
+    result = data.outbufavail;
+  else
     {
-      size_t cnt = written;
-      s[0] = encoding_byte[cnt - 2];
-
-      --cnt;
-      do
-       {
-         s[cnt] = 0x80 | (wc & 0x3f);
-         wc >>= 6;
-       }
-      while (--cnt > 0);
-      s[0] |= wc;
+      result = (size_t) -1;
+      __set_errno (EILSEQ);
     }
 
-  return written;
+  return result;
 }
 weak_alias (__wcrtomb, wcrtomb)
index f6c8048..2dd9f7c 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
 
    Boston, MA 02111-1307, USA.  */
 
 #include <errno.h>
+#include <gconv.h>
 #include <wchar.h>
+#include <wcsmbsload.h>
+
+#include <assert.h>
 
 #ifndef EILSEQ
-#define EILSEQ EINVAL
+# define EILSEQ EINVAL
 #endif
 
 
-static const wchar_t encoding_mask[] =
-{
-  ~0x7ff, ~0xffff, ~0x1fffff, ~0x3ffffff
-};
-
-static const unsigned char encoding_byte[] =
-{
-  0xc0, 0xe0, 0xf0, 0xf8, 0xfc
-};
-
-/* We don't need the state really because we don't have shift states
-   to maintain between calls to this function.  */
-static mbstate_t internal;
+/* This is the private state used if PS is NULL.  */
+static mbstate_t state;
 
 /* This is a non-standard function but it is very useful in the
    implementation of stdio because we have to deal with unterminated
@@ -50,85 +43,91 @@ __wcsnrtombs (dst, src, nwc, len, ps)
      size_t len;
      mbstate_t *ps;
 {
-  size_t written = 0;
-  const wchar_t *run = *src;
+  struct gconv_step_data data;
+  size_t inbytes_in;
+  int status;
+  size_t result;
 
-  if (ps == NULL)
-    ps = &internal;
+  /* Tell where we want the result.  */
+  data.is_last = 1;
+  data.statep = ps ?: &state;
 
-  if (dst == NULL)
-    /* The LEN parameter has to be ignored if we don't actually write
-       anything.  */
-    len = ~0;
+  if (nwc == 0)
+    return 0;
+  inbytes_in = __wcsnlen (*src, nwc - 1) + 1;
 
-  while (written < len && nwc-- > 0)
-    {
-      wchar_t wc;
+  /* Make sure we use the correct function.  */
+  update_conversion_ptrs ();
 
-      /* Store position of first unprocessed word.  */
-      *src = run;
+  /* We have to handle DST == NULL special.  */
+  if (dst == NULL)
+    {
+      char buf[256];           /* Just an arbitrary value.  */
+      size_t inbytes = inbytes_in;
+      const wchar_t *inbuf = *src;
+      size_t written;
 
-      wc = *run++;
+      data.outbuf = buf;
+      data.outbufsize = sizeof (buf);
 
-      if (wc < 0 || wc > 0x7fffffff)
+      do
        {
-         /* This is no correct ISO 10646 character.  */
-         __set_errno (EILSEQ);
-         return (size_t) -1;
+         inbuf += (inbytes_in - inbytes) / sizeof (wchar_t);
+         inbytes_in = inbytes;
+         data.outbufavail = 0;
+         written = 0;
+
+         status = (*__wcsmbs_gconv_fcts.tomb->fct) (__wcsmbs_gconv_fcts.tomb,
+                                                    &data,
+                                                    (const char *) inbuf,
+                                                    &inbytes, &written, 0);
+         result += written;
        }
+      while (status == GCONV_FULL_OUTPUT);
 
-      if (wc == L'\0')
+      if (status == GCONV_OK && dst[data.outbufavail - 1] == '\0')
+       /* Don't count the NUL character in.  */
+       --result;
+    }
+  else
+    {
+      /* This code is based on the safe assumption that all internal
+        multi-byte encodings use the NUL byte only to mark the end
+        of the string.  */
+      size_t inbytes = inbytes_in;
+
+      data.outbuf = dst;
+      data.outbufavail = 0;
+      data.outbufsize = len;
+
+      status = (*__wcsmbs_gconv_fcts.tomb->fct) (__wcsmbs_gconv_fcts.tomb,
+                                                &data, (const char *) *src,
+                                                &inbytes, &result, 0);
+
+      /* We have to determine whether the last character converted
+        is the NUL character.  */
+      if (status == GCONV_OK && dst[data.outbufavail - 1] == '\0')
        {
-         /* Found the end.  */
-         if (dst != NULL)
-           *dst = '\0';
+         assert (data.outbufavail > 0);
+         assert (mbsinit (data.statep));
          *src = NULL;
-         return written;
-       }
-      else if (wc < 0x80)
-       {
-         /* It's an one byte sequence.  */
-         if (dst != NULL)
-           *dst++ = (char) wc;
-         ++written;
+         --result;
        }
       else
-       {
-         size_t step;
-
-         for (step = 2; step < 6; ++step)
-           if ((wc & encoding_mask[step - 2]) == 0)
-             break;
-
-         if (written + step >= len)
-           /* Too long.  */
-           break;
-
-         if (dst != NULL)
-           {
-             size_t cnt = step;
-
-             dst[0] = encoding_byte[cnt - 2];
-
-             --cnt;
-             do
-               {
-                 dst[cnt] = 0x80 | (wc & 0x3f);
-                 wc >>= 6;
-               }
-             while (--cnt > 0);
-             dst[0] |= wc;
+       *src += result;
+    }
 
-             dst += step;
-           }
+  /* There must not be any problems with the conversion but illegal input
+     characters.  */
+  assert (status == GCONV_OK || status == GCONV_ILLEGAL_INPUT
+         || status == GCONV_INCOMPLETE_INPUT || status == GCONV_FULL_OUTPUT);
 
-         written += step;
-       }
+  if (status != GCONV_OK && status != GCONV_FULL_OUTPUT)
+    {
+      result = (size_t) -1;
+      __set_errno (EILSEQ);
     }
 
-  /* Store position of first unprocessed word.  */
-  *src = run;
-
-  return written;
+  return result;
 }
 weak_alias (__wcsnrtombs, wcsnrtombs)
index cc21a51..35bb58e 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
 
    Boston, MA 02111-1307, USA.  */
 
 #include <errno.h>
+#include <stdlib.h>
+#include <gconv.h>
 #include <wchar.h>
+#include <wcsmbsload.h>
+
+#include <assert.h>
 
 #ifndef EILSEQ
-#define EILSEQ EINVAL
+# define EILSEQ EINVAL
 #endif
 
 
-static const wchar_t encoding_mask[] =
-{
-  ~0x7ff, ~0xffff, ~0x1fffff, ~0x3ffffff
-};
-
-static const unsigned char encoding_byte[] =
-{
-  0xc0, 0xe0, 0xf0, 0xf8, 0xfc
-};
-
-/* We don't need the state really because we don't have shift states
-   to maintain between calls to this function.  */
-static mbstate_t internal;
+/* This is the private state used if PS is NULL.  */
+static mbstate_t state;
 
 size_t
 __wcsrtombs (dst, src, len, ps)
@@ -46,89 +40,88 @@ __wcsrtombs (dst, src, len, ps)
      size_t len;
      mbstate_t *ps;
 {
-  size_t written = 0;
-  const wchar_t *run = *src;
+  struct gconv_step_data data;
+  int status;
+  size_t result;
 
-  if (ps == NULL)
-    ps = &internal;
+  /* Tell where we want the result.  */
+  data.is_last = 1;
+  data.statep = ps ?: &state;
 
-  if (dst == NULL)
-    /* The LEN parameter has to be ignored if we don't actually write
-       anything.  */
-    len = ~0;
+  /* Make sure we use the correct function.  */
+  update_conversion_ptrs ();
 
-  while (written < len)
+  /* We have to handle DST == NULL special.  */
+  if (dst == NULL)
     {
-      wchar_t wc;
-
-      /* Store position of first unprocessed word.  */
-      *src = run;
+      char buf[256];           /* Just an arbitrary value.  */
+      size_t inbytes_in = __wcslen (*src) + 1;
+      size_t inbytes = inbytes_in;
+      const wchar_t *inbuf = *src;
+      size_t written;
 
-      wc = *run++;
+      data.outbuf = buf;
+      data.outbufsize = sizeof (buf);
 
-      if (wc < 0 || wc > 0x7fffffff)
+      do
        {
-         /* This is no correct ISO 10646 character.  */
-         __set_errno (EILSEQ);
-         return (size_t) -1;
+         inbuf += (inbytes_in - inbytes) / sizeof (wchar_t);
+         inbytes_in = inbytes;
+         data.outbufavail = 0;
+         written = 0;
+
+         status = (*__wcsmbs_gconv_fcts.tomb->fct) (__wcsmbs_gconv_fcts.tomb,
+                                                    &data,
+                                                    (const char *) inbuf,
+                                                    &inbytes, &written, 0);
+         result += written;
        }
+      while (status == GCONV_FULL_OUTPUT);
 
-      if (wc == L'\0')
+      if (status == GCONV_OK && dst[data.outbufavail - 1] == '\0')
+       /* Don't count the NUL character in.  */
+       --result;
+    }
+  else
+    {
+      /* This code is based on the safe assumption that all internal
+        multi-byte encodings use the NUL byte only to mark the end
+        of the string.  */
+      size_t inbytes_in = __wcsnlen (*src, len * MB_CUR_MAX) + 1;
+      size_t inbytes = inbytes_in;
+
+      data.outbuf = dst;
+      data.outbufavail = 0;
+      data.outbufsize = len;
+
+      status = (*__wcsmbs_gconv_fcts.tomb->fct) (__wcsmbs_gconv_fcts.tomb,
+                                                &data, (const char *) *src,
+                                                &inbytes, &result, 0);
+
+      /* We have to determine whether the last character converted
+        is the NUL character.  */
+      if (status == GCONV_OK && dst[data.outbufavail - 1] == '\0')
        {
-         /* Found the end.  */
-         if (dst != NULL)
-           *dst = '\0';
-         ps->count = 0;
+         assert (data.outbufavail > 0);
+         assert (mbsinit (data.statep));
          *src = NULL;
-         return written;
-       }
-      else if (wc < 0x80)
-       {
-         /* It's an one byte sequence.  */
-         if (dst != NULL)
-           *dst++ = (char) wc;
-         ++written;
+         --result;
        }
       else
-       {
-         size_t step;
-
-         for (step = 2; step < 6; ++step)
-           if ((wc & encoding_mask[step - 2]) == 0)
-             break;
-
-         if (written + step >= len)
-           /* Too long.  */
-           break;
-
-         if (dst != NULL)
-           {
-             size_t cnt = step;
-
-             dst[0] = encoding_byte[cnt - 2];
-
-             --cnt;
-             do
-               {
-                 dst[cnt] = 0x80 | (wc & 0x3f);
-                 wc >>= 6;
-               }
-             while (--cnt > 0);
-             dst[0] |= wc;
-
-             dst += step;
-           }
-
-         written += step;
-       }
+       *src += result;
     }
 
-  /* Store position of first unprocessed word.  */
-  *src = run;
+  /* There must not be any problems with the conversion but illegal input
+     characters.  */
+  assert (status == GCONV_OK || status == GCONV_ILLEGAL_INPUT
+         || status == GCONV_INCOMPLETE_INPUT || status == GCONV_FULL_OUTPUT);
 
-  /* Signal that we finished correctly.  */
-  ps->count = 0;
+  if (status != GCONV_OK && status != GCONV_FULL_OUTPUT)
+    {
+      result = (size_t) -1;
+      __set_errno (EILSEQ);
+    }
 
-  return written;
+  return result;
 }
 weak_alias (__wcsrtombs, wcsrtombs)
index ce1063a..0461877 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1996.
 
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <gconv.h>
 #include <stdio.h>
+#include <string.h>
 #include <wchar.h>
+#include <wcsmbsload.h>
 
 
-/* We use UTF8 encoding for multibyte strings and therefore a valid
-   one byte multibyte string only can have a value from 0 to 0x7f.  */
 int
 wctob (c)
      wint_t c;
 {
-  return (c >= 0 && c <= 0x7f) ? c : EOF;
+  char buf[MB_LEN_MAX];
+  struct gconv_step_data data;
+  wchar_t inbuf[1];
+  size_t inbytes;
+  size_t converted;
+  int status;
+
+  /* Tell where we want the result.  */
+  data.outbuf = (char *) buf;
+  data.outbufavail = 0;
+  data.outbufsize = MB_LEN_MAX;
+  data.is_last = 1;
+  data.statep = &data.__state;
+
+  /* Make sure we start in the initial state.  */
+  memset (&data.__state, '\0', sizeof (mbstate_t));
+
+  /* Make sure we use the correct function.  */
+  update_conversion_ptrs ();
+
+  /* Create the input string.  */
+  inbuf[0] = c;
+  inbytes = sizeof (wchar_t);
+
+  status = (*__wcsmbs_gconv_fcts.tomb->fct) (__wcsmbs_gconv_fcts.tomb, &data,
+                                            (const char *) inbuf, &inbytes,
+                                            &converted, 0);
+  /* The conversion failed or the output is too long.  */
+  if (status != GCONV_OK && status != GCONV_FULL_OUTPUT
+      || data.outbufavail != 1)
+    return WEOF;
+
+  return buf[0];
 }