Don't use undefined macro 'max'.
[gnulib.git] / lib / mbrtowc.c
index e5ae0bc..0fec5f1 100644 (file)
@@ -1,5 +1,5 @@
 /* Convert multibyte character to wide character.
-   Copyright (C) 1999-2002, 2005-2008 Free Software Foundation, Inc.
+   Copyright (C) 1999-2002, 2005-2009 Free Software Foundation, Inc.
    Written by Bruno Haible <bruno@clisp.org>, 2008.
 
    This program is free software: you can redistribute it and/or modify
 /* Specification.  */
 #include <wchar.h>
 
-#include <errno.h>
-#include <stdlib.h>
+#if GNULIB_defined_mbstate_t
+/* Implement mbrtowc() on top of mbtowc().  */
 
-#include "localcharset.h"
-#include "streq.h"
-#include "verify.h"
+# include <errno.h>
+# include <stdlib.h>
+
+# include "localcharset.h"
+# include "streq.h"
+# include "verify.h"
 
 
 verify (sizeof (mbstate_t) >= 4);
@@ -86,12 +89,12 @@ mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps)
        return (size_t)(-1);
       }
 
-    /* Here 0 < m ≤ 4.  */
+    /* Here m > 0.  */
 
-#if __GLIBC__
+# if __GLIBC__
     /* Work around bug <http://sourceware.org/bugzilla/show_bug.cgi?id=9674> */
     mbtowc (NULL, NULL, 0);
-#endif
+# endif
     {
       int res = mbtowc (pwc, p, m);
 
@@ -115,7 +118,7 @@ mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps)
         lack mbrtowc(), we use the second approach.
         The possible encodings are:
           - 8-bit encodings,
-          - EUC-JP, EUC-KR, GB2312, EUC-TW, BIG5, SJIS,
+          - EUC-JP, EUC-KR, GB2312, EUC-TW, BIG5, GB18030, SJIS,
           - UTF-8.
         Use specialized code for each.  */
       if (m >= 4 || m >= MB_CUR_MAX)
@@ -235,6 +238,39 @@ mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps)
              }
            goto invalid;
          }
+       if (STREQ (encoding, "GB18030", 'G', 'B', '1', '8', '0', '3', '0', 0, 0))
+         {
+           if (m == 1)
+             {
+               unsigned char c = (unsigned char) p[0];
+
+               if ((c >= 0x90 && c <= 0xe3) || (c >= 0xf8 && c <= 0xfe))
+                 goto incomplete;
+             }
+           else /* m == 2 || m == 3 */
+             {
+               unsigned char c = (unsigned char) p[0];
+
+               if (c >= 0x90 && c <= 0xe3)
+                 {
+                   unsigned char c2 = (unsigned char) p[1];
+
+                   if (c2 >= 0x30 && c2 <= 0x39)
+                     {
+                       if (m == 2)
+                         goto incomplete;
+                       else /* m == 3 */
+                         {
+                           unsigned char c3 = (unsigned char) p[2];
+
+                           if (c3 >= 0x81 && c3 <= 0xfe)
+                             goto incomplete;
+                         }
+                     }
+                 }
+             }
+           goto invalid;
+         }
        if (STREQ (encoding, "SJIS", 'S', 'J', 'I', 'S', 0, 0, 0, 0, 0))
          {
            if (m == 1)
@@ -255,10 +291,14 @@ mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps)
      incomplete:
       {
        size_t k = nstate;
-       /* Here 0 < k < m < 4.  */
+       /* Here 0 <= k < m < 4.  */
        pstate[++k] = s[0];
        if (k < m)
-         pstate[++k] = s[1];
+         {
+           pstate[++k] = s[1];
+           if (k < m)
+             pstate[++k] = s[2];
+         }
        if (k != m)
          abort ();
       }
@@ -272,3 +312,75 @@ mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps)
     }
   }
 }
+
+#else
+/* Override the system's mbrtowc() function.  */
+
+# undef mbrtowc
+
+size_t
+rpl_mbrtowc (wchar_t *pwc, const char *s, size_t n, mbstate_t *ps)
+{
+# if MBRTOWC_NULL_ARG_BUG || MBRTOWC_RETVAL_BUG
+  if (s == NULL)
+    {
+      pwc = NULL;
+      s = "";
+      n = 1;
+    }
+# endif
+
+# if MBRTOWC_RETVAL_BUG
+  {
+    static mbstate_t internal_state;
+
+    /* Override mbrtowc's internal state.  We can not call mbsinit() on the
+       hidden internal state, but we can call it on our variable.  */
+    if (ps == NULL)
+      ps = &internal_state;
+
+    if (!mbsinit (ps))
+      {
+       /* Parse the rest of the multibyte character byte for byte.  */
+       size_t count = 0;
+       for (; n > 0; s++, n--)
+         {
+           wchar_t wc;
+           size_t ret = mbrtowc (&wc, s, 1, ps);
+
+           if (ret == (size_t)(-1))
+             return (size_t)(-1);
+           count++;
+           if (ret != (size_t)(-2))
+             {
+               /* The multibyte character has been completed.  */
+               if (pwc != NULL)
+                 *pwc = wc;
+               return (wc == 0 ? 0 : count);
+             }
+         }
+       return (size_t)(-2);
+      }
+  }
+# endif
+
+# if MBRTOWC_NUL_RETVAL_BUG
+  {
+    wchar_t wc;
+    size_t ret = mbrtowc (&wc, s, n, ps);
+
+    if (ret != (size_t)(-1) && ret != (size_t)(-2))
+      {
+       if (pwc != NULL)
+         *pwc = wc;
+       if (wc == 0)
+         ret = 0;
+      }
+    return ret;
+  }
+# else
+  return mbrtowc (pwc, s, n, ps);
+# endif
+}
+
+#endif