93dc2d
commit de82cb0da4b8fa5b3d56c457438d2568c67ab1b1
93dc2d
Author: Joseph Myers <joseph@codesourcery.com>
93dc2d
Date:   Tue Oct 12 13:48:39 2021 +0000
93dc2d
93dc2d
    Add TEST_COMPARE_STRING_WIDE to support/check.h
93dc2d
    
93dc2d
    I'd like to be able to test narrow and wide string interfaces, with
93dc2d
    the narrow string tests using TEST_COMPARE_STRING and the wide string
93dc2d
    tests using something analogous (possibly generated using macros from
93dc2d
    a common test template for both the narrow and wide string tests where
93dc2d
    appropriate).
93dc2d
    
93dc2d
    Add such a TEST_COMPARE_STRING_WIDE, along with functions
93dc2d
    support_quote_blob_wide and support_test_compare_string_wide that it
93dc2d
    builds on.  Those functions are built using macros from common
93dc2d
    templates shared by the narrow and wide string implementations, though
93dc2d
    I didn't do that for the tests of test functions.  In
93dc2d
    support_quote_blob_wide, I chose to use the \x{} delimited escape
93dc2d
    sequence syntax proposed for C2X in N2785, rather than e.g. trying to
93dc2d
    generate the end of a string and the start of a new string when
93dc2d
    ambiguity would result from undelimited \x (when the next character
93dc2d
    after such an escape sequence is valid hex) or forcing an escape
93dc2d
    sequence to be used for the next character in the case of such
93dc2d
    ambiguity.
93dc2d
    
93dc2d
    Tested for x86_64.
93dc2d
93dc2d
diff --git a/support/Makefile b/support/Makefile
93dc2d
index 75bad6715ac3d08c..3c941e1ba9e29aa4 100644
93dc2d
--- a/support/Makefile
93dc2d
+++ b/support/Makefile
93dc2d
@@ -70,6 +70,7 @@ libsupport-routines = \
93dc2d
   support_openpty \
93dc2d
   support_paths \
93dc2d
   support_quote_blob \
93dc2d
+  support_quote_blob_wide \
93dc2d
   support_quote_string \
93dc2d
   support_record_failure \
93dc2d
   support_run_diff \
93dc2d
@@ -83,6 +84,7 @@ libsupport-routines = \
93dc2d
   support_test_compare_blob \
93dc2d
   support_test_compare_failure \
93dc2d
   support_test_compare_string \
93dc2d
+  support_test_compare_string_wide \
93dc2d
   support_test_main \
93dc2d
   support_test_verify_impl \
93dc2d
   support_wait_for_thread_exit \
93dc2d
@@ -275,11 +277,13 @@ tests = \
93dc2d
   tst-support-open-dev-null-range \
93dc2d
   tst-support-process_state \
93dc2d
   tst-support_quote_blob \
93dc2d
+  tst-support_quote_blob_wide \
93dc2d
   tst-support_quote_string \
93dc2d
   tst-support_record_failure \
93dc2d
   tst-test_compare \
93dc2d
   tst-test_compare_blob \
93dc2d
   tst-test_compare_string \
93dc2d
+  tst-test_compare_string_wide \
93dc2d
   tst-timespec \
93dc2d
   tst-xreadlink \
93dc2d
   tst-xsigstack \
93dc2d
diff --git a/support/check.h b/support/check.h
93dc2d
index 83662b2d10c8cf58..9b1844352f32513a 100644
93dc2d
--- a/support/check.h
93dc2d
+++ b/support/check.h
93dc2d
@@ -20,6 +20,7 @@
93dc2d
 #define SUPPORT_CHECK_H
93dc2d
 
93dc2d
 #include <sys/cdefs.h>
93dc2d
+#include <stddef.h>
93dc2d
 
93dc2d
 __BEGIN_DECLS
93dc2d
 
93dc2d
@@ -171,11 +172,25 @@ void support_test_compare_blob (const void *left,
93dc2d
   (support_test_compare_string (left, right, __FILE__, __LINE__, \
93dc2d
                                 #left, #right))
93dc2d
 
93dc2d
+/* Compare the wide strings LEFT and RIGHT and report a test failure
93dc2d
+   if they are different.  Also report failure if one of the arguments
93dc2d
+   is a null pointer and the other is not.  The strings should be
93dc2d
+   reasonably short because on mismatch, both are printed.  */
93dc2d
+#define TEST_COMPARE_STRING_WIDE(left, right)                         \
93dc2d
+  (support_test_compare_string_wide (left, right, __FILE__, __LINE__, \
93dc2d
+				     #left, #right))
93dc2d
+
93dc2d
 void support_test_compare_string (const char *left, const char *right,
93dc2d
                                   const char *file, int line,
93dc2d
                                   const char *left_expr,
93dc2d
                                   const char *right_expr);
93dc2d
 
93dc2d
+void support_test_compare_string_wide (const wchar_t *left,
93dc2d
+				       const wchar_t *right,
93dc2d
+				       const char *file, int line,
93dc2d
+				       const char *left_expr,
93dc2d
+				       const char *right_expr);
93dc2d
+
93dc2d
 /* Internal function called by the test driver.  */
93dc2d
 int support_report_failure (int status)
93dc2d
   __attribute__ ((weak, warn_unused_result));
93dc2d
diff --git a/support/support.h b/support/support.h
93dc2d
index c219e0d9d1aef046..29d56c7c891ee34b 100644
93dc2d
--- a/support/support.h
93dc2d
+++ b/support/support.h
93dc2d
@@ -73,6 +73,12 @@ void support_write_file_string (const char *path, const char *contents);
93dc2d
    the result).  */
93dc2d
 char *support_quote_blob (const void *blob, size_t length);
93dc2d
 
93dc2d
+/* Quote the contents of the wide character array starting at BLOB, of
93dc2d
+   LENGTH wide characters, in such a way that the result string can be
93dc2d
+   included in a C wide string literal (in single/double quotes,
93dc2d
+   without putting the quotes into the result).  */
93dc2d
+char *support_quote_blob_wide (const void *blob, size_t length);
93dc2d
+
93dc2d
 /* Quote the contents of the string, in such a way that the result
93dc2d
    string can be included in a C literal (in single/double quotes,
93dc2d
    without putting the quotes into the result).  */
93dc2d
diff --git a/support/support_quote_blob.c b/support/support_quote_blob.c
93dc2d
index b5e70125f13eb081..611980c9a2108670 100644
93dc2d
--- a/support/support_quote_blob.c
93dc2d
+++ b/support/support_quote_blob.c
93dc2d
@@ -1,4 +1,4 @@
93dc2d
-/* Quote a blob so that it can be used in C literals.
93dc2d
+/* Quote a narrow string blob so that it can be used in C literals.
93dc2d
    Copyright (C) 2018-2021 Free Software Foundation, Inc.
93dc2d
    This file is part of the GNU C Library.
93dc2d
 
93dc2d
@@ -16,68 +16,9 @@
93dc2d
    License along with the GNU C Library; if not, see
93dc2d
    <https://www.gnu.org/licenses/>.  */
93dc2d
 
93dc2d
-#include <support/support.h>
93dc2d
-#include <support/xmemstream.h>
93dc2d
+#define CHAR unsigned char
93dc2d
+#define L_(C) C
93dc2d
+#define SUPPORT_QUOTE_BLOB support_quote_blob
93dc2d
+#define WIDE 0
93dc2d
 
93dc2d
-char *
93dc2d
-support_quote_blob (const void *blob, size_t length)
93dc2d
-{
93dc2d
-  struct xmemstream out;
93dc2d
-  xopen_memstream (&out;;
93dc2d
-
93dc2d
-  const unsigned char *p = blob;
93dc2d
-  for (size_t i = 0; i < length; ++i)
93dc2d
-    {
93dc2d
-      unsigned char ch = p[i];
93dc2d
-
93dc2d
-      /* Use C backslash escapes for those control characters for
93dc2d
-         which they are defined.  */
93dc2d
-      switch (ch)
93dc2d
-        {
93dc2d
-          case '\a':
93dc2d
-            putc_unlocked ('\\', out.out);
93dc2d
-            putc_unlocked ('a', out.out);
93dc2d
-            break;
93dc2d
-          case '\b':
93dc2d
-            putc_unlocked ('\\', out.out);
93dc2d
-            putc_unlocked ('b', out.out);
93dc2d
-            break;
93dc2d
-          case '\f':
93dc2d
-            putc_unlocked ('\\', out.out);
93dc2d
-            putc_unlocked ('f', out.out);
93dc2d
-            break;
93dc2d
-          case '\n':
93dc2d
-            putc_unlocked ('\\', out.out);
93dc2d
-            putc_unlocked ('n', out.out);
93dc2d
-            break;
93dc2d
-          case '\r':
93dc2d
-            putc_unlocked ('\\', out.out);
93dc2d
-            putc_unlocked ('r', out.out);
93dc2d
-            break;
93dc2d
-          case '\t':
93dc2d
-            putc_unlocked ('\\', out.out);
93dc2d
-            putc_unlocked ('t', out.out);
93dc2d
-            break;
93dc2d
-          case '\v':
93dc2d
-            putc_unlocked ('\\', out.out);
93dc2d
-            putc_unlocked ('v', out.out);
93dc2d
-            break;
93dc2d
-          case '\\':
93dc2d
-          case '\'':
93dc2d
-          case '\"':
93dc2d
-            putc_unlocked ('\\', out.out);
93dc2d
-            putc_unlocked (ch, out.out);
93dc2d
-            break;
93dc2d
-        default:
93dc2d
-          if (ch < ' ' || ch > '~')
93dc2d
-            /* Use octal sequences because they are fixed width,
93dc2d
-               unlike hexadecimal sequences.  */
93dc2d
-            fprintf (out.out, "\\%03o", ch);
93dc2d
-          else
93dc2d
-            putc_unlocked (ch, out.out);
93dc2d
-        }
93dc2d
-    }
93dc2d
-
93dc2d
-  xfclose_memstream (&out;;
93dc2d
-  return out.buffer;
93dc2d
-}
93dc2d
+#include "support_quote_blob_main.c"
93dc2d
diff --git a/support/support_quote_blob_main.c b/support/support_quote_blob_main.c
93dc2d
new file mode 100644
93dc2d
index 0000000000000000..19ccfad59311bfee
93dc2d
--- /dev/null
93dc2d
+++ b/support/support_quote_blob_main.c
93dc2d
@@ -0,0 +1,88 @@
93dc2d
+/* Quote a blob so that it can be used in C literals.
93dc2d
+   Copyright (C) 2018-2021 Free Software Foundation, Inc.
93dc2d
+   This file is part of the GNU C Library.
93dc2d
+
93dc2d
+   The GNU C Library is free software; you can redistribute it and/or
93dc2d
+   modify it under the terms of the GNU Lesser General Public
93dc2d
+   License as published by the Free Software Foundation; either
93dc2d
+   version 2.1 of the License, or (at your option) any later version.
93dc2d
+
93dc2d
+   The GNU C Library is distributed in the hope that it will be useful,
93dc2d
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
93dc2d
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
93dc2d
+   Lesser General Public License for more details.
93dc2d
+
93dc2d
+   You should have received a copy of the GNU Lesser General Public
93dc2d
+   License along with the GNU C Library; if not, see
93dc2d
+   <https://www.gnu.org/licenses/>.  */
93dc2d
+
93dc2d
+#include <support/support.h>
93dc2d
+#include <support/xmemstream.h>
93dc2d
+
93dc2d
+char *
93dc2d
+SUPPORT_QUOTE_BLOB (const void *blob, size_t length)
93dc2d
+{
93dc2d
+  struct xmemstream out;
93dc2d
+  xopen_memstream (&out;;
93dc2d
+
93dc2d
+  const CHAR *p = blob;
93dc2d
+  for (size_t i = 0; i < length; ++i)
93dc2d
+    {
93dc2d
+      CHAR ch = p[i];
93dc2d
+
93dc2d
+      /* Use C backslash escapes for those control characters for
93dc2d
+	 which they are defined.  */
93dc2d
+      switch (ch)
93dc2d
+	{
93dc2d
+	case L_('\a'):
93dc2d
+	  putc_unlocked ('\\', out.out);
93dc2d
+	  putc_unlocked ('a', out.out);
93dc2d
+	  break;
93dc2d
+	case L_('\b'):
93dc2d
+	  putc_unlocked ('\\', out.out);
93dc2d
+	  putc_unlocked ('b', out.out);
93dc2d
+	  break;
93dc2d
+	case L_('\f'):
93dc2d
+	  putc_unlocked ('\\', out.out);
93dc2d
+	  putc_unlocked ('f', out.out);
93dc2d
+	  break;
93dc2d
+	case L_('\n'):
93dc2d
+	  putc_unlocked ('\\', out.out);
93dc2d
+	  putc_unlocked ('n', out.out);
93dc2d
+	  break;
93dc2d
+	case L_('\r'):
93dc2d
+	  putc_unlocked ('\\', out.out);
93dc2d
+	  putc_unlocked ('r', out.out);
93dc2d
+	  break;
93dc2d
+	case L_('\t'):
93dc2d
+	  putc_unlocked ('\\', out.out);
93dc2d
+	  putc_unlocked ('t', out.out);
93dc2d
+	  break;
93dc2d
+	case L_('\v'):
93dc2d
+	  putc_unlocked ('\\', out.out);
93dc2d
+	  putc_unlocked ('v', out.out);
93dc2d
+	  break;
93dc2d
+	case L_('\\'):
93dc2d
+	case L_('\''):
93dc2d
+	case L_('\"'):
93dc2d
+	  putc_unlocked ('\\', out.out);
93dc2d
+	  putc_unlocked (ch, out.out);
93dc2d
+	  break;
93dc2d
+	default:
93dc2d
+	  if (ch < L_(' ') || ch > L_('~'))
93dc2d
+	    /* For narrow characters, use octal sequences because they
93dc2d
+	       are fixed width, unlike hexadecimal sequences.  For
93dc2d
+	       wide characters, use N2785 delimited escape
93dc2d
+	       sequences.  */
93dc2d
+	    if (WIDE)
93dc2d
+	      fprintf (out.out, "\\x{%x}", (unsigned int) ch);
93dc2d
+	    else
93dc2d
+	      fprintf (out.out, "\\%03o", (unsigned int) ch);
93dc2d
+	  else
93dc2d
+	    putc_unlocked (ch, out.out);
93dc2d
+	}
93dc2d
+    }
93dc2d
+
93dc2d
+  xfclose_memstream (&out;;
93dc2d
+  return out.buffer;
93dc2d
+}
93dc2d
diff --git a/support/support_quote_blob_wide.c b/support/support_quote_blob_wide.c
93dc2d
new file mode 100644
93dc2d
index 0000000000000000..c451ed889c21c626
93dc2d
--- /dev/null
93dc2d
+++ b/support/support_quote_blob_wide.c
93dc2d
@@ -0,0 +1,24 @@
93dc2d
+/* Quote a wide string blob so that it can be used in C literals.
93dc2d
+   Copyright (C) 2018-2021 Free Software Foundation, Inc.
93dc2d
+   This file is part of the GNU C Library.
93dc2d
+
93dc2d
+   The GNU C Library is free software; you can redistribute it and/or
93dc2d
+   modify it under the terms of the GNU Lesser General Public
93dc2d
+   License as published by the Free Software Foundation; either
93dc2d
+   version 2.1 of the License, or (at your option) any later version.
93dc2d
+
93dc2d
+   The GNU C Library is distributed in the hope that it will be useful,
93dc2d
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
93dc2d
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
93dc2d
+   Lesser General Public License for more details.
93dc2d
+
93dc2d
+   You should have received a copy of the GNU Lesser General Public
93dc2d
+   License along with the GNU C Library; if not, see
93dc2d
+   <https://www.gnu.org/licenses/>.  */
93dc2d
+
93dc2d
+#define CHAR wchar_t
93dc2d
+#define L_(C) L ## C
93dc2d
+#define SUPPORT_QUOTE_BLOB support_quote_blob_wide
93dc2d
+#define WIDE 1
93dc2d
+
93dc2d
+#include "support_quote_blob_main.c"
93dc2d
diff --git a/support/support_test_compare_string.c b/support/support_test_compare_string.c
93dc2d
index cbeaf7b1eeea8ca8..12bafe43d44ae3d7 100644
93dc2d
--- a/support/support_test_compare_string.c
93dc2d
+++ b/support/support_test_compare_string.c
93dc2d
@@ -16,76 +16,13 @@
93dc2d
    License along with the GNU C Library; if not, see
93dc2d
    <https://www.gnu.org/licenses/>.  */
93dc2d
 
93dc2d
-#include <stdio.h>
93dc2d
-#include <stdlib.h>
93dc2d
-#include <string.h>
93dc2d
-#include <support/check.h>
93dc2d
-#include <support/support.h>
93dc2d
-#include <support/xmemstream.h>
93dc2d
-
93dc2d
-static void
93dc2d
-report_length (const char *what, const char *str, size_t length)
93dc2d
-{
93dc2d
-  if (str == NULL)
93dc2d
-    printf ("  %s string: NULL\n", what);
93dc2d
-  else
93dc2d
-    printf ("  %s string: %zu bytes\n", what, length);
93dc2d
-}
93dc2d
-
93dc2d
-static void
93dc2d
-report_string (const char *what, const unsigned char *blob,
93dc2d
-               size_t length, const char *expr)
93dc2d
-{
93dc2d
-  if (length > 0)
93dc2d
-    {
93dc2d
-      printf ("  %s (evaluated from %s):\n", what, expr);
93dc2d
-      char *quoted = support_quote_blob (blob, length);
93dc2d
-      printf ("      \"%s\"\n", quoted);
93dc2d
-      free (quoted);
93dc2d
-
93dc2d
-      fputs ("     ", stdout);
93dc2d
-      for (size_t i = 0; i < length; ++i)
93dc2d
-        printf (" %02X", blob[i]);
93dc2d
-      putc ('\n', stdout);
93dc2d
-    }
93dc2d
-}
93dc2d
-
93dc2d
-static size_t
93dc2d
-string_length_or_zero (const char *str)
93dc2d
-{
93dc2d
-  if (str == NULL)
93dc2d
-    return 0;
93dc2d
-  else
93dc2d
-    return strlen (str);
93dc2d
-}
93dc2d
-
93dc2d
-void
93dc2d
-support_test_compare_string (const char *left, const char *right,
93dc2d
-                             const char *file, int line,
93dc2d
-                             const char *left_expr, const char *right_expr)
93dc2d
-{
93dc2d
-  /* Two null pointers are accepted.  */
93dc2d
-  if (left == NULL && right == NULL)
93dc2d
-    return;
93dc2d
-
93dc2d
-  size_t left_length = string_length_or_zero (left);
93dc2d
-  size_t right_length = string_length_or_zero (right);
93dc2d
-
93dc2d
-  if (left_length != right_length || left == NULL || right == NULL
93dc2d
-      || memcmp (left, right, left_length) != 0)
93dc2d
-    {
93dc2d
-      support_record_failure ();
93dc2d
-      printf ("%s:%d: error: string comparison failed\n", file, line);
93dc2d
-      if (left_length == right_length && right != NULL && left != NULL)
93dc2d
-        printf ("  string length: %zu bytes\n", left_length);
93dc2d
-      else
93dc2d
-        {
93dc2d
-          report_length ("left", left, left_length);
93dc2d
-          report_length ("right", right, right_length);
93dc2d
-        }
93dc2d
-      report_string ("left", (const unsigned char *) left,
93dc2d
-                     left_length, left_expr);
93dc2d
-      report_string ("right", (const unsigned char *) right,
93dc2d
-                     right_length, right_expr);
93dc2d
-    }
93dc2d
-}
93dc2d
+#define CHAR char
93dc2d
+#define UCHAR unsigned char
93dc2d
+#define LPREFIX ""
93dc2d
+#define STRLEN strlen
93dc2d
+#define MEMCMP memcmp
93dc2d
+#define SUPPORT_QUOTE_BLOB support_quote_blob
93dc2d
+#define SUPPORT_TEST_COMPARE_STRING support_test_compare_string
93dc2d
+#define WIDE 0
93dc2d
+
93dc2d
+#include "support_test_compare_string_main.c"
93dc2d
diff --git a/support/support_test_compare_string_main.c b/support/support_test_compare_string_main.c
93dc2d
new file mode 100644
93dc2d
index 0000000000000000..0edc0ca97d79d71e
93dc2d
--- /dev/null
93dc2d
+++ b/support/support_test_compare_string_main.c
93dc2d
@@ -0,0 +1,94 @@
93dc2d
+/* Check two strings for equality.
93dc2d
+   Copyright (C) 2018-2021 Free Software Foundation, Inc.
93dc2d
+   This file is part of the GNU C Library.
93dc2d
+
93dc2d
+   The GNU C Library is free software; you can redistribute it and/or
93dc2d
+   modify it under the terms of the GNU Lesser General Public
93dc2d
+   License as published by the Free Software Foundation; either
93dc2d
+   version 2.1 of the License, or (at your option) any later version.
93dc2d
+
93dc2d
+   The GNU C Library is distributed in the hope that it will be useful,
93dc2d
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
93dc2d
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
93dc2d
+   Lesser General Public License for more details.
93dc2d
+
93dc2d
+   You should have received a copy of the GNU Lesser General Public
93dc2d
+   License along with the GNU C Library; if not, see
93dc2d
+   <https://www.gnu.org/licenses/>.  */
93dc2d
+
93dc2d
+#include <stdio.h>
93dc2d
+#include <stdlib.h>
93dc2d
+#include <string.h>
93dc2d
+#include <wchar.h>
93dc2d
+#include <support/check.h>
93dc2d
+#include <support/support.h>
93dc2d
+#include <support/xmemstream.h>
93dc2d
+
93dc2d
+static void
93dc2d
+report_length (const char *what, const CHAR *str, size_t length)
93dc2d
+{
93dc2d
+  if (str == NULL)
93dc2d
+    printf ("  %s string: NULL\n", what);
93dc2d
+  else
93dc2d
+    printf ("  %s string: %zu %s\n", what, length,
93dc2d
+	    WIDE ? "wide characters" : "bytes");
93dc2d
+}
93dc2d
+
93dc2d
+static void
93dc2d
+report_string (const char *what, const UCHAR *blob,
93dc2d
+               size_t length, const char *expr)
93dc2d
+{
93dc2d
+  if (length > 0)
93dc2d
+    {
93dc2d
+      printf ("  %s (evaluated from %s):\n", what, expr);
93dc2d
+      char *quoted = SUPPORT_QUOTE_BLOB (blob, length);
93dc2d
+      printf ("      %s\"%s\"\n", LPREFIX, quoted);
93dc2d
+      free (quoted);
93dc2d
+
93dc2d
+      fputs ("     ", stdout);
93dc2d
+      for (size_t i = 0; i < length; ++i)
93dc2d
+        printf (" %02X", (unsigned int) blob[i]);
93dc2d
+      putc ('\n', stdout);
93dc2d
+    }
93dc2d
+}
93dc2d
+
93dc2d
+static size_t
93dc2d
+string_length_or_zero (const CHAR *str)
93dc2d
+{
93dc2d
+  if (str == NULL)
93dc2d
+    return 0;
93dc2d
+  else
93dc2d
+    return STRLEN (str);
93dc2d
+}
93dc2d
+
93dc2d
+void
93dc2d
+SUPPORT_TEST_COMPARE_STRING (const CHAR *left, const CHAR *right,
93dc2d
+                             const char *file, int line,
93dc2d
+                             const char *left_expr, const char *right_expr)
93dc2d
+{
93dc2d
+  /* Two null pointers are accepted.  */
93dc2d
+  if (left == NULL && right == NULL)
93dc2d
+    return;
93dc2d
+
93dc2d
+  size_t left_length = string_length_or_zero (left);
93dc2d
+  size_t right_length = string_length_or_zero (right);
93dc2d
+
93dc2d
+  if (left_length != right_length || left == NULL || right == NULL
93dc2d
+      || MEMCMP (left, right, left_length) != 0)
93dc2d
+    {
93dc2d
+      support_record_failure ();
93dc2d
+      printf ("%s:%d: error: string comparison failed\n", file, line);
93dc2d
+      if (left_length == right_length && right != NULL && left != NULL)
93dc2d
+        printf ("  string length: %zu %s\n", left_length,
93dc2d
+		WIDE ? "wide characters" : "bytes");
93dc2d
+      else
93dc2d
+        {
93dc2d
+          report_length ("left", left, left_length);
93dc2d
+          report_length ("right", right, right_length);
93dc2d
+        }
93dc2d
+      report_string ("left", (const UCHAR *) left,
93dc2d
+                     left_length, left_expr);
93dc2d
+      report_string ("right", (const UCHAR *) right,
93dc2d
+                     right_length, right_expr);
93dc2d
+    }
93dc2d
+}
93dc2d
diff --git a/support/support_test_compare_string_wide.c b/support/support_test_compare_string_wide.c
93dc2d
new file mode 100644
93dc2d
index 0000000000000000..88b560b142a3c356
93dc2d
--- /dev/null
93dc2d
+++ b/support/support_test_compare_string_wide.c
93dc2d
@@ -0,0 +1,28 @@
93dc2d
+/* Check two wide strings for equality.
93dc2d
+   Copyright (C) 2018-2021 Free Software Foundation, Inc.
93dc2d
+   This file is part of the GNU C Library.
93dc2d
+
93dc2d
+   The GNU C Library is free software; you can redistribute it and/or
93dc2d
+   modify it under the terms of the GNU Lesser General Public
93dc2d
+   License as published by the Free Software Foundation; either
93dc2d
+   version 2.1 of the License, or (at your option) any later version.
93dc2d
+
93dc2d
+   The GNU C Library is distributed in the hope that it will be useful,
93dc2d
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
93dc2d
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
93dc2d
+   Lesser General Public License for more details.
93dc2d
+
93dc2d
+   You should have received a copy of the GNU Lesser General Public
93dc2d
+   License along with the GNU C Library; if not, see
93dc2d
+   <https://www.gnu.org/licenses/>.  */
93dc2d
+
93dc2d
+#define CHAR wchar_t
93dc2d
+#define UCHAR wchar_t
93dc2d
+#define LPREFIX "L"
93dc2d
+#define STRLEN wcslen
93dc2d
+#define MEMCMP wmemcmp
93dc2d
+#define SUPPORT_QUOTE_BLOB support_quote_blob_wide
93dc2d
+#define SUPPORT_TEST_COMPARE_STRING support_test_compare_string_wide
93dc2d
+#define WIDE 1
93dc2d
+
93dc2d
+#include "support_test_compare_string_main.c"
93dc2d
diff --git a/support/tst-support_quote_blob_wide.c b/support/tst-support_quote_blob_wide.c
93dc2d
new file mode 100644
93dc2d
index 0000000000000000..ea71a1f7f873b23a
93dc2d
--- /dev/null
93dc2d
+++ b/support/tst-support_quote_blob_wide.c
93dc2d
@@ -0,0 +1,66 @@
93dc2d
+/* Test the support_quote_blob_wide function.
93dc2d
+   Copyright (C) 2018-2021 Free Software Foundation, Inc.
93dc2d
+   This file is part of the GNU C Library.
93dc2d
+
93dc2d
+   The GNU C Library is free software; you can redistribute it and/or
93dc2d
+   modify it under the terms of the GNU Lesser General Public
93dc2d
+   License as published by the Free Software Foundation; either
93dc2d
+   version 2.1 of the License, or (at your option) any later version.
93dc2d
+
93dc2d
+   The GNU C Library is distributed in the hope that it will be useful,
93dc2d
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
93dc2d
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
93dc2d
+   Lesser General Public License for more details.
93dc2d
+
93dc2d
+   You should have received a copy of the GNU Lesser General Public
93dc2d
+   License along with the GNU C Library; if not, see
93dc2d
+   <https://www.gnu.org/licenses/>.  */
93dc2d
+
93dc2d
+#include <support/check.h>
93dc2d
+#include <support/support.h>
93dc2d
+#include <string.h>
93dc2d
+#include <stdlib.h>
93dc2d
+
93dc2d
+static int
93dc2d
+do_test (void)
93dc2d
+{
93dc2d
+  /* Check handling of the empty blob, both with and without trailing
93dc2d
+     NUL byte.  */
93dc2d
+  char *p = support_quote_blob_wide (L"", 0);
93dc2d
+  TEST_COMPARE (strlen (p), 0);
93dc2d
+  free (p);
93dc2d
+  p = support_quote_blob_wide (L"X", 0);
93dc2d
+  TEST_COMPARE (strlen (p), 0);
93dc2d
+  free (p);
93dc2d
+
93dc2d
+  /* Check escaping of backslash-escaped characters, and lack of
93dc2d
+     escaping for other shell meta-characters.  */
93dc2d
+  p = support_quote_blob_wide (L"$()*?`@[]{}~\'\"X", 14);
93dc2d
+  TEST_COMPARE (strcmp (p, "$()*?`@[]{}~\\'\\\""), 0);
93dc2d
+  free (p);
93dc2d
+
93dc2d
+  /* Check lack of escaping for letters and digits.  */
93dc2d
+#define LETTERS_AND_DIGTS                       \
93dc2d
+  "abcdefghijklmnopqrstuvwxyz"                  \
93dc2d
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"                  \
93dc2d
+  "0123456789"
93dc2d
+#define CONCATX(X, Y) X ## Y
93dc2d
+#define CONCAT(X, Y) CONCATX (X, Y)
93dc2d
+#define WLETTERS_AND_DIGTS CONCAT (L, LETTERS_AND_DIGTS)
93dc2d
+  p = support_quote_blob_wide (WLETTERS_AND_DIGTS "@", 2 * 26 + 10);
93dc2d
+  TEST_COMPARE (strcmp (p, LETTERS_AND_DIGTS), 0);
93dc2d
+  free (p);
93dc2d
+
93dc2d
+  /* Check escaping of control characters and other non-printable
93dc2d
+     characters.  */
93dc2d
+  p = support_quote_blob_wide (L"\r\n\t\a\b\f\v\1\177\200\377"
93dc2d
+			       "\x123\x76543210\xfedcba98\0@", 17);
93dc2d
+  TEST_COMPARE (strcmp (p, "\\r\\n\\t\\a\\b\\f\\v\\x{1}"
93dc2d
+                        "\\x{7f}\\x{80}\\x{ff}\\x{123}\\x{76543210}"
93dc2d
+			"\\x{fedcba98}\\x{0}@\\x{0}"), 0);
93dc2d
+  free (p);
93dc2d
+
93dc2d
+  return 0;
93dc2d
+}
93dc2d
+
93dc2d
+#include <support/test-driver.c>
93dc2d
diff --git a/support/tst-test_compare_string_wide.c b/support/tst-test_compare_string_wide.c
93dc2d
new file mode 100644
93dc2d
index 0000000000000000..548f7dcdc60b82d8
93dc2d
--- /dev/null
93dc2d
+++ b/support/tst-test_compare_string_wide.c
93dc2d
@@ -0,0 +1,107 @@
93dc2d
+/* Basic test for the TEST_COMPARE_STRING_WIDE macro.
93dc2d
+   Copyright (C) 2018-2021 Free Software Foundation, Inc.
93dc2d
+   This file is part of the GNU C Library.
93dc2d
+
93dc2d
+   The GNU C Library is free software; you can redistribute it and/or
93dc2d
+   modify it under the terms of the GNU Lesser General Public
93dc2d
+   License as published by the Free Software Foundation; either
93dc2d
+   version 2.1 of the License, or (at your option) any later version.
93dc2d
+
93dc2d
+   The GNU C Library is distributed in the hope that it will be useful,
93dc2d
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
93dc2d
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
93dc2d
+   Lesser General Public License for more details.
93dc2d
+
93dc2d
+   You should have received a copy of the GNU Lesser General Public
93dc2d
+   License along with the GNU C Library; if not, see
93dc2d
+   <https://www.gnu.org/licenses/>.  */
93dc2d
+
93dc2d
+#include <string.h>
93dc2d
+#include <support/check.h>
93dc2d
+#include <support/capture_subprocess.h>
93dc2d
+
93dc2d
+static void
93dc2d
+subprocess (void *closure)
93dc2d
+{
93dc2d
+  /* These tests should fail.  They were chosen to cover differences
93dc2d
+     in length (with the same contents), single-bit mismatches, and
93dc2d
+     mismatching null pointers.  */
93dc2d
+  TEST_COMPARE_STRING_WIDE (L"", NULL);             /* Line 29.  */
93dc2d
+  TEST_COMPARE_STRING_WIDE (L"X", L"");              /* Line 30.  */
93dc2d
+  TEST_COMPARE_STRING_WIDE (NULL, L"X");            /* Line 31.  */
93dc2d
+  TEST_COMPARE_STRING_WIDE (L"abcd", L"abcD");       /* Line 32.  */
93dc2d
+  TEST_COMPARE_STRING_WIDE (L"abcd", NULL);         /* Line 33.  */
93dc2d
+  TEST_COMPARE_STRING_WIDE (NULL, L"abcd");         /* Line 34.  */
93dc2d
+}
93dc2d
+
93dc2d
+/* Same contents, different addresses.  */
93dc2d
+wchar_t buffer_abc_1[] = L"abc";
93dc2d
+wchar_t buffer_abc_2[] = L"abc";
93dc2d
+
93dc2d
+static int
93dc2d
+do_test (void)
93dc2d
+{
93dc2d
+  /* This should succeed.  Even if the pointers and array contents are
93dc2d
+     different, zero-length inputs are not different.  */
93dc2d
+  TEST_COMPARE_STRING_WIDE (NULL, NULL);
93dc2d
+  TEST_COMPARE_STRING_WIDE (L"", L"");
93dc2d
+  TEST_COMPARE_STRING_WIDE (buffer_abc_1, buffer_abc_2);
93dc2d
+  TEST_COMPARE_STRING_WIDE (buffer_abc_1, L"abc");
93dc2d
+
93dc2d
+  struct support_capture_subprocess proc = support_capture_subprocess
93dc2d
+    (&subprocess, NULL);
93dc2d
+
93dc2d
+  /* Discard the reported error.  */
93dc2d
+  support_record_failure_reset ();
93dc2d
+
93dc2d
+  puts ("info: *** subprocess output starts ***");
93dc2d
+  fputs (proc.out.buffer, stdout);
93dc2d
+  puts ("info: *** subprocess output ends ***");
93dc2d
+
93dc2d
+  TEST_VERIFY
93dc2d
+    (strcmp (proc.out.buffer,
93dc2d
+"tst-test_compare_string_wide.c:29: error: string comparison failed\n"
93dc2d
+"  left string: 0 wide characters\n"
93dc2d
+"  right string: NULL\n"
93dc2d
+"tst-test_compare_string_wide.c:30: error: string comparison failed\n"
93dc2d
+"  left string: 1 wide characters\n"
93dc2d
+"  right string: 0 wide characters\n"
93dc2d
+"  left (evaluated from L\"X\"):\n"
93dc2d
+"      L\"X\"\n"
93dc2d
+"      58\n"
93dc2d
+"tst-test_compare_string_wide.c:31: error: string comparison failed\n"
93dc2d
+"  left string: NULL\n"
93dc2d
+"  right string: 1 wide characters\n"
93dc2d
+"  right (evaluated from L\"X\"):\n"
93dc2d
+"      L\"X\"\n"
93dc2d
+"      58\n"
93dc2d
+"tst-test_compare_string_wide.c:32: error: string comparison failed\n"
93dc2d
+"  string length: 4 wide characters\n"
93dc2d
+"  left (evaluated from L\"abcd\"):\n"
93dc2d
+"      L\"abcd\"\n"
93dc2d
+"      61 62 63 64\n"
93dc2d
+"  right (evaluated from L\"abcD\"):\n"
93dc2d
+"      L\"abcD\"\n"
93dc2d
+"      61 62 63 44\n"
93dc2d
+"tst-test_compare_string_wide.c:33: error: string comparison failed\n"
93dc2d
+"  left string: 4 wide characters\n"
93dc2d
+"  right string: NULL\n"
93dc2d
+"  left (evaluated from L\"abcd\"):\n"
93dc2d
+"      L\"abcd\"\n"
93dc2d
+"      61 62 63 64\n"
93dc2d
+"tst-test_compare_string_wide.c:34: error: string comparison failed\n"
93dc2d
+"  left string: NULL\n"
93dc2d
+"  right string: 4 wide characters\n"
93dc2d
+"  right (evaluated from L\"abcd\"):\n"
93dc2d
+"      L\"abcd\"\n"
93dc2d
+"      61 62 63 64\n"
93dc2d
+             ) == 0);
93dc2d
+
93dc2d
+  /* Check that there is no output on standard error.  */
93dc2d
+  support_capture_subprocess_check (&proc, "TEST_COMPARE_STRING_WIDE",
93dc2d
+                                    0, sc_allow_stdout);
93dc2d
+
93dc2d
+  return 0;
93dc2d
+}
93dc2d
+
93dc2d
+#include <support/test-driver.c>