about summary refs log tree commit diff
path: root/string/strxfrm.c
diff options
context:
space:
mode:
Diffstat (limited to 'string/strxfrm.c')
-rw-r--r--string/strxfrm.c54
1 files changed, 51 insertions, 3 deletions
diff --git a/string/strxfrm.c b/string/strxfrm.c
index 300967bc2b..f94c16b50b 100644
--- a/string/strxfrm.c
+++ b/string/strxfrm.c
@@ -21,9 +21,10 @@ Boston, MA 02111-1307, USA.  */
 #include <stdlib.h>
 #include <string.h>
 
-#ifndef STRING_TYPE
+#ifndef WIDE_VERSION
 # define STRING_TYPE char
 # define USTRING_TYPE unsigned char
+# define L_(Ch) Ch
 # define STRXFRM strxfrm
 # define STRLEN strlen
 # define STPNCPY __stpncpy
@@ -34,9 +35,10 @@ Boston, MA 02111-1307, USA.  */
 #include "../locale/weight.h"
 
 
+#ifndef WIDE_VERSION
 /* Write 32 bit value UTF-8 encoded but only if enough space is left.  */
 static __inline size_t
-print_val (u_int32_t value, STRING_TYPE *dest, size_t max, size_t act)
+print_val (u_int32_t value, char *dest, size_t max, size_t act)
 {
   char tmp[6];
   int idx = 0;
@@ -90,6 +92,48 @@ print_val (u_int32_t value, STRING_TYPE *dest, size_t max, size_t act)
 
   return act;
 }
+#else
+static __inline size_t
+print_val (u_int32_t value, wchar_t *dest, size_t max, size_t act)
+{
+  /* We cannot really assume wchar_t is 32 bits wide.  But it is for
+     GCC and so we don't do much optimization for the other case.  */
+  if (sizeof (wchar_t) == 4)
+    {
+      if (act < max)
+	dest[act] = (wchar_t) value;
+      ++act;
+    }
+  else
+    {
+      wchar_t tmp[3];
+      size_t idx = 0;
+
+      if (value < 0x8000)
+	tmp[idx++] = (wchar_t) act;
+      else
+	{
+	  tmp[idx++] = (wchar_t) (0x8000 + (value & 0x3fff));
+	  value >>= 14;
+	  if (value < 0x2000)
+	    tmp[idx++] = (wchar_t) (0xc000 + value);
+	  else
+	    {
+	      tmp[idx++] = (wchar_t) (0x8000 + (value & 0x3fff));
+	      value >>= 14;
+	      tmp[idx++] = (wchar_t) (0xe000 + value);
+	    }
+	}
+      while (idx-- > 0)
+	{
+	  if (act < max)
+	    dest[act] = tmp[idx];
+	  ++act;
+	}
+    }
+  return act;
+}
+#endif
 
 
 /* Transform SRC into a form such that the result of strcmp
@@ -184,5 +228,9 @@ STRXFRM (STRING_TYPE *dest, const STRING_TYPE *src, size_t n)
     }
 
   /* Terminate string.  */
-  return print_val (0, dest, n, written);
+  if (written < n)
+    dest[written] = L_('\0');
+
+  /* Return length without counting the terminating '\0'.  */
+  return written;
 }