]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - wcsmbs/c16rtomb.c
Undo accidental commit to ChangeLog.19.
[thirdparty/glibc.git] / wcsmbs / c16rtomb.c
index 91b18b0d2ebb7d12d5d0e33b780b9bca1f5826a0..7af9c1589892740d7abde1a069bafc1c4f7f08b0 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2011-2013 Free Software Foundation, Inc.
+/* Copyright (C) 2011-2019 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@gmail.com>, 2011.
 
@@ -14,7 +14,7 @@
 
    You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
+   <https://www.gnu.org/licenses/>.  */
 
 #include <uchar.h>
 #include <wchar.h>
@@ -26,7 +26,42 @@ static mbstate_t state;
 size_t
 c16rtomb (char *s, char16_t c16, mbstate_t *ps)
 {
-  // XXX The ISO C 11 spec I have does not say anything about handling
-  // XXX surrogates in this interface.
-  return wcrtomb (s, c16, ps ?: &state);
+  wchar_t wc = c16;
+
+  if (ps == NULL)
+    ps = &state;
+
+  if (s == NULL)
+    {
+      /* Reset any state relating to surrogate pairs.  */
+      ps->__count &= 0x7fffffff;
+      ps->__value.__wch = 0;
+      wc = 0;
+    }
+
+  if (ps->__count & 0x80000000)
+    {
+      /* The previous call passed in the first surrogate of a
+        surrogate pair.  */
+      ps->__count &= 0x7fffffff;
+      if (wc >= 0xdc00 && wc < 0xe000)
+       wc = (0x10000
+             + ((ps->__value.__wch & 0x3ff) << 10)
+             + (wc & 0x3ff));
+      else
+       /* This is not a low surrogate; ensure an EILSEQ error by
+          trying to decode the high surrogate as a wide character on
+          its own.  */
+       wc = ps->__value.__wch;
+      ps->__value.__wch = 0;
+    }
+  else if (wc >= 0xd800 && wc < 0xdc00)
+    {
+      /* The high part of a surrogate pair.  */
+      ps->__count |= 0x80000000;
+      ps->__value.__wch = wc;
+      return 0;
+    }
+
+  return wcrtomb (s, wc, ps);
 }