[PATCH 2/2] quotearg: support USE_C_LOCALE variant

Paul Eggert <[email protected]>
Newsgroups gmane.comp.lib.gnulib.bugs
Message-ID <[email protected]>
This is for gzip, which does not use setlocale,
but does need to quote file names.
* lib/quotearg.c (USE_C_LOCALE): Default to 0.  If set, include
c-ctype.h instead of ctype.h, gettext.h, uchar.h, wchar.h; and
define _ to be an identity macro.
(wch, mbstate): New types.
(mbs_clear, mbrtowch, wchisprint, chisprint): New functions.
(gettext_quote, quotearg_buffer_restyled): Use them.
---
 ChangeLog      | 10 ++++++
 lib/quotearg.c | 91 ++++++++++++++++++++++++++++++++++++++++++--------
 2 files changed, 87 insertions(+), 14 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index cd74c15b09..ec8648260e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,15 @@
 2026-05-25  Paul Eggert  <[email protected]>
 
+	quotearg: support USE_C_LOCALE variant
+	This is for gzip, which does not use setlocale,
+	but does need to quote file names.
+	* lib/quotearg.c (USE_C_LOCALE): Default to 0.  If set, include
+	c-ctype.h instead of ctype.h, gettext.h, uchar.h, wchar.h; and
+	define _ to be an identity macro.
+	(wch, mbstate): New types.
+	(mbs_clear, mbrtowch, wchisprint, chisprint): New functions.
+	(gettext_quote, quotearg_buffer_restyled): Use them.
+
 	quotearg: lessen dependencies
 	* lib/quotearg.c: Do not include c-strcaseeq.h, as its
 	macros are no longer used here.
diff --git a/lib/quotearg.c b/lib/quotearg.c
index c3706016ec..21014d4782 100644
--- a/lib/quotearg.c
+++ b/lib/quotearg.c
@@ -33,17 +33,80 @@
 #include "minmax.h"
 #include "xalloc.h"
 
-#include <ctype.h>
 #include <errno.h>
 #include <limits.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
-#include <uchar.h>
-#include <wchar.h>
 
-#include "gettext.h"
-#define _(msgid) dgettext (GNULIB_TEXT_DOMAIN, msgid)
+/* If USE_C_LOCALE is set to 1, this file defines a function that uses the
+   "C" locale, regardless of the current locale.  Applications
+   defining this macro might avoid the need for Gnulib's c32isprint,
+   gettext-h, mbrtoc32, mbsinit, mbszero, wchar-h, and uchar-h modules,
+   but they also need the c-ctype module.  */
+#ifndef USE_C_LOCALE
+# define USE_C_LOCALE 0
+#endif
+
+#if USE_C_LOCALE
+# include <c-ctype.h>
+typedef unsigned char wch;
+typedef struct incomplete_mbstate *mbstate;
+# ifndef GNULIB_MBRTOC32_REGULAR
+#  define GNULIB_MBRTOC32_REGULAR 1
+# endif
+#else
+# include <ctype.h>
+# include <wchar.h>
+# include <uchar.h>
+typedef char32_t wch;
+typedef mbstate_t mbstate;
+#endif
+
+static void
+mbs_clear (MAYBE_UNUSED mbstate *ps)
+{
+#if !USE_C_LOCALE
+  mbszero (ps);
+#endif
+}
+
+static size_t
+mbrtowch (wch *pwc, char const *s, size_t n, MAYBE_UNUSED mbstate *ps)
+{
+#if USE_C_LOCALE
+  return n && (*pwc = *s);
+#else
+  return mbrtoc32 (pwc, s, n, ps);
+#endif
+}
+
+static bool
+wchisprint (wch w)
+{
+#if USE_C_LOCALE
+  return c_isprint (w);
+#else
+  return c32isprint (w);
+#endif
+}
+
+static bool
+chisprint (unsigned char c)
+{
+#if USE_C_LOCALE
+  return c_isprint (c);
+#else
+  return isprint (c) != 0;
+#endif
+}
+
+#if USE_C_LOCALE
+# define _(msgid) msgid
+#else
+# include "gettext.h"
+# define _(msgid) dgettext (GNULIB_TEXT_DOMAIN, msgid)
+#endif
 #define N_(msgid) msgid
 
 #ifndef SIZE_MAX
@@ -225,9 +288,9 @@ gettext_quote (char const *msgid, enum quoting_style s)
      and means we need not use a function like locale_charset that
      has other dependencies.  */
   static char const quote[][4] = { "\xe2\x80\x98", "\xe2\x80\x99" };
-  char32_t w;
-  mbstate_t mbs; mbszero (&mbs);
-  if (mbrtoc32 (&w, quote[0], 3, &mbs) == 3 && w == 0x2018)
+  wch w;
+  mbstate mbs; mbs_clear (&mbs);
+  if (mbrtowch (&w, quote[0], 3, &mbs) == 3 && w == 0x2018)
     return quote[msgid[0] == '\''];
 
   return (s == clocale_quoting_style ? "\"" : "'");
@@ -254,7 +317,7 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
                           char const *left_quote,
                           char const *right_quote)
 {
-  bool unibyte_locale = MB_CUR_MAX == 1;
+  bool unibyte_locale = USE_C_LOCALE || MB_CUR_MAX == 1;
 
   size_t len = 0;
   size_t orig_buffersize = 0;
@@ -601,11 +664,11 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
             if (unibyte_locale)
               {
                 m = 1;
-                printable = isprint (c) != 0;
+                printable = chisprint (c);
               }
             else
               {
-                mbstate_t mbs; mbszero (&mbs);
+                mbstate mbs; mbs_clear (&mbs);
 
                 m = 0;
                 printable = true;
@@ -614,8 +677,8 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
 
                 for (;;)
                   {
-                    char32_t w;
-                    size_t bytes = mbrtoc32 (&w, &arg[i + m],
+                    wch w;
+                    size_t bytes = mbrtowch (&w, &arg[i + m],
                                              argsize - (i + m), &mbs);
                     if (bytes == 0)
                       break;
@@ -653,7 +716,7 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
                                 }
                           }
 
-                        if (! c32isprint (w))
+                        if (! wchisprint (w))
                           printable = false;
                         m += bytes;
                       }
-- 
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.