On 2025-08-17 08:45, Paul Eggert wrote:
On 8/16/25 19:01, Collin Funk wrote:
Is there any reason that gzip doesn't use quote and error from Gnulib?
e.g. to avoid dependencies on locale stuff?

Partly that, and partly because it's a symptom of a larger issue: gzip was written in a hurry and is poorly structured and people understandably don't want to mess with it. Decades ago I toyed with the idea of rewriting it from scratch but gave it up as a job not worth doing.

I shook free some time to address the issue with gzip, which was the focus of the original bug report, and installed the attached patch. Boldly closing the bug report; we can reopen it if I missed something.
From ede0a8888a4d3d0750e1651e01f198e2faab5d59 Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email protected]>
Date: Mon, 25 May 2026 22:55:10 -0700
Subject: [PATCH] gzip: quote oddball file names in diagnostics
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* NEWS: Mention this.
* bootstrap.conf (gnulib_modules): Add c-ctype, quotearg.
(gnulib_tool_option_extras): Avoid c32isprint, mbrtoc32,
mbsinit, mbszero, uchar-h.
* configure.ac (USE_C_LOCALE): Define.
* gzexe.in, zdiff.in, zforce.in, zgrep.in:
Do not send file names to stderr; it’s not worth the trouble
to try to safely quote them in these rarely-used scripts.
* gzip.c, util.c: Reorder includes for sanity, putting config.h
first, then tailor.h, then our others, then Gnulib’s, then POSIX’s.
* gzip.c, trees.c, util.c:
Include <c-ctype.h> instead of <ctype.h>; all function uses changed.
* gzip.c (progerror, main, treat_file, create_outfile, open_input_file)
(make_ofname, get_method, do_list, check_ofname, copy_stat, treat_dir):
* unlzw.c (unlzw):
* unzip.c (check_zipfile, unzip):
* util.c (gzip_error, warning, read_error, write_err):
* zip.c (zip):
Quote unusual file names in diagnostics.
* gzip.c (progerror): Treat null argument as naming standard input,
so that we needn’t quote it.  Argument changed.
* lib/.gitignore, m4/.gitignore: Update.
* tests/null-suffix-clobber: Adjust to match new quoting behavior.
* util.c (quotef, quotef_n): New functions.
* zip.c: Don’t include <ctype.h>; not needed.
---
 NEWS                      |   3 +
 bootstrap.conf            |   6 ++
 configure.ac              |   3 +
 gzexe.in                  |  24 ++++----
 gzip.c                    | 114 ++++++++++++++++++++------------------
 gzip.h                    |   2 +
 lib/.gitignore            |   6 ++
 m4/.gitignore             |   5 ++
 tests/null-suffix-clobber |   2 +-
 trees.c                   |   8 ++-
 unlzw.c                   |   5 +-
 unzip.c                   |  12 ++--
 util.c                    |  42 ++++++++++----
 zdiff.in                  |   4 +-
 zforce.in                 |   4 +-
 zgrep.in                  |   2 +-
 zip.c                     |   3 +-
 17 files changed, 148 insertions(+), 97 deletions(-)

diff --git a/NEWS b/NEWS
index e668d53..55f381e 100644
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,9 @@ GNU gzip NEWS                                    -*- outline -*-
   descriptors.  These can appear in well-formed streamed zip files.
   [bug present since the beginning]
 
+  gzip diagnostics now quote file names containing unusual characters.
+  [bug present since the beginning]
+
   A use of uninitialized memory on some malformed inputs has been fixed.
   [bug present since the beginning]
 
diff --git a/bootstrap.conf b/bootstrap.conf
index cdd1e78..bfce470 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -20,6 +20,7 @@ gnulib_modules="
 alignasof
 announce-gen
 assert-h
+c-ctype
 calloc-gnu
 close
 crc-x86_64
@@ -49,6 +50,7 @@ maintainer-makefile
 malloc-gnu
 manywarnings
 openat-safer
+quotearg
 readme-release
 realloc-posix
 savedir
@@ -72,13 +74,17 @@ yesno
 # Additional gnulib-tool options to use.  Use "\newline" to break lines.
 # We don't need the getline and rpmatch, since yesno doesn't do i18n.
 gnulib_tool_option_extras="\
+ --avoid c32isprint\
  --avoid getline\
  --avoid gnulib-i18n\
+ --avoid mbrtoc32\
+ --avoid mbsinit\
  --avoid threadlib\
  --avoid rpmatch\
  --avoid windows-once\
  --avoid windows-spin\
  --avoid windows-tls\
+ --avoid uchar-h\
  --symlink\
  --makefile-name=gnulib.mk\
 "
diff --git a/configure.ac b/configure.ac
index ca3126e..f8ce122 100644
--- a/configure.ac
+++ b/configure.ac
@@ -30,6 +30,9 @@ AM_INIT_AUTOMAKE([1.11 subdir-objects dist-xz dist-zip
                   color-tests parallel-tests])
 AM_SILENT_RULES([yes]) # make --enable-silent-rules the default.
 
+dnl gzip does not use setlocale.
+AC_DEFINE([USE_C_LOCALE], [1], [Define to 1 if only the C locale is used.])
+
 dnl POSIXCHECK is worthwhile for maintainers, but adds several seconds
 dnl (more than 10% execution time) to ./configure, with no benefit for
 dnl most users.  Using it to look for bugs requires:
diff --git a/gzexe.in b/gzexe.in
index f3d46cc..3a78df5 100644
--- a/gzexe.in
+++ b/gzexe.in
@@ -86,22 +86,22 @@ for i do
   esac
   if test ! -f "$file" || test ! -r "$file"; then
     res=$?
-    printf >&2 '%s\n' "$0: $i is not a readable regular file"
+    printf >&2 '%s\n' "$0: operand is not a readable regular file"
     continue
   fi
   if test $decomp -eq 0; then
     case `LC_ALL=C sed -n -e 1d -e '/^skip=[0-9][0-9]*$/p' -e 2q "$file"` in
     skip=[0-9] | skip=[0-9][0-9] | skip=[0-9][0-9][0-9])
-      printf >&2 '%s\n' "$0: $i is already gzexe'd"
+      printf >&2 '%s\n' "$0: file is is already gzexe'd"
       continue;;
     esac
   fi
   if test -u "$file"; then
-    printf >&2 '%s\n' "$0: $i has setuid permission, unchanged"
+    printf >&2 '%s\n' "$0: file has setuid permission, unchanged"
     continue
   fi
   if test -g "$file"; then
-    printf >&2 '%s\n' "$0: $i has setgid permission, unchanged"
+    printf >&2 '%s\n' "$0: file has setgid permission, unchanged"
     continue
   fi
   case /$file in
@@ -109,7 +109,7 @@ for i do
   */dirname | */expr | */'gzip' | \
   */ln | */mkdir | */mktemp | */mv | */printf | */rm | \
   */sed | */sh | */sleep | */test | */tail)
-    printf >&2 '%s\n' "$0: $i might depend on itself"; continue;;
+    printf >&2 '%s\n' "$0: file might depend on itself"; continue;;
   esac
 
   dir=`dirname "$file"` || dir=$TMPDIR
@@ -130,7 +130,7 @@ for i do
     (umask 77; set -C; > "$tmp")
   fi && { cp -p "$file" "$tmp" 2>/dev/null || cp "$file" "$tmp"; } || {
     res=$?
-    printf >&2 '%s\n' "$0: cannot copy $file"
+    printf >&2 '%s\n' "$0: cannot copy file"
     continue
   }
   if test -w "$tmp"; then
@@ -139,7 +139,7 @@ for i do
     writable=0
     chmod u+w "$tmp" || {
       res=$?
-      printf >&2 '%s\n' "$0: cannot chmod $tmp"
+      printf >&2 '%s\n' "$0: cannot chmod tmp directory"
       continue
     }
   fi
@@ -196,7 +196,7 @@ fi; exit $res
 EOF
     'gzip' -cv9 "$file") > "$tmp" || {
       res=$?
-      printf >&2 '%s\n' "$0: compression not possible for $i, file unchanged."
+      printf >&2 '%s\n' "$0: compression not possible, file unchanged."
       continue
     }
 
@@ -214,13 +214,13 @@ EOF
     esac
     tail $tail_n +$skip "$file" | 'gzip' -cd > "$tmp" || {
       res=$?
-      printf >&2 '%s\n' "$0: $i probably not in gzexe format, file unchanged."
+      printf >&2 '%s\n' "$0: file probably not in gzexe format, file unchanged."
       continue
     }
   fi
   test $writable -eq 1 || chmod u-w "$tmp" || {
     res=$?
-    printf >&2 '%s\n' "$0: $tmp: cannot chmod"
+    printf >&2 '%s\n' "$0: cannot chmod tmp file"
     continue
   }
   ln -f "$file" "$file~" 2>/dev/null || {
@@ -228,12 +228,12 @@ EOF
     rm -f "$file~" && cp -p "$file" "$file~"
   } || {
     res=$?
-    printf >&2 '%s\n' "$0: cannot backup $i as $i~"
+    printf >&2 '%s\n' "$0: cannot backup file as file~"
     continue
   }
   mv -f "$tmp" "$file" || {
     res=$?
-    printf >&2 '%s\n' "$0: cannot rename $tmp to $i"
+    printf >&2 '%s\n' "$0: cannot rename tmp file to destination"
     continue
   }
   tmp=
diff --git a/gzip.c b/gzip.c
index 1fb2621..db39667 100644
--- a/gzip.c
+++ b/gzip.c
@@ -55,37 +55,36 @@ static char const license_msg[] =
  */
 
 #include <config.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include <signal.h>
-#include <stdcountof.h>
-#include <stddef.h>
-#include <sys/stat.h>
-#include <getopt.h>
-#include <errno.h>
 
 #include "tailor.h"
+
 #include "gzip.h"
-#include "intprops.h"
 #include "lzw.h"
 #include "revision.h"
-#include "timespec.h"
-
-#include "dirname.h"
-#include "fcntl--.h"
-#include "filename.h"
-#include "ignore-value.h"
-#include "stat-time.h"
 #include "version.h"
-#include "xalloc.h"
-#include "yesno.h"
 
-                /* configuration */
+#include <c-ctype.h>
+#include <dirname.h>
+#include <fcntl--.h>
+#include <filename.h>
+#include <ignore-value.h>
+#include <intprops.h>
+#include <stat-time.h>
+#include <timespec.h>
+#include <xalloc.h>
+#include <yesno.h>
 
-#include <limits.h>
+#include <errno.h>
+#include <getopt.h>
 #include <inttypes.h>
-#include <unistd.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdcountof.h>
+#include <stddef.h>
 #include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #ifndef NO_DIR
 # define NO_DIR 0
@@ -408,7 +407,8 @@ version ()
 static void
 progerror (char const *string)
 {
-    fprintf (stderr, "%s: %s: %s\n", program_name, string, strerror (errno));
+    fprintf (stderr, "%s: %s: %s\n", program_name,
+             string ? quotef (string) : "standard input", strerror (errno));
     exit_code = ERROR;
 }
 
@@ -597,7 +597,8 @@ int main (int argc, char **argv)
     }
 #endif
     if (z_len == 0 || z_len > MAX_SUFFIX) {
-        fprintf(stderr, "%s: invalid suffix '%s'\n", program_name, z_suffix);
+        fprintf (stderr, "%s: %s: invalid suffix\n", program_name,
+                 quotef (z_suffix));
         do_exit(ERROR);
     }
 
@@ -731,7 +732,7 @@ treat_stdin ()
     /* Get the file's timestamp and size.  */
     if (fstat (STDIN_FILENO, &istat) != 0)
       {
-        progerror ("standard input");
+        progerror (NULL);
         do_exit (ERROR);
       }
 
@@ -857,7 +858,7 @@ treat_file (char *iname)
 #endif
         close (ifd);
         WARN ((stderr, "%s: %s is a directory -- ignored\n",
-               program_name, ifname));
+               program_name, quotef (ifname)));
         return;
     }
 
@@ -867,21 +868,21 @@ treat_file (char *iname)
           {
             WARN ((stderr,
                    "%s: %s is not a directory or a regular file - ignored\n",
-                   program_name, ifname));
+                   program_name, quotef (ifname)));
             close (ifd);
             return;
           }
         if (istat.st_mode & S_ISUID)
           {
             WARN ((stderr, "%s: %s is set-user-ID on execution - ignored\n",
-                   program_name, ifname));
+                   program_name, quotef (ifname)));
             close (ifd);
             return;
           }
         if (istat.st_mode & S_ISGID)
           {
             WARN ((stderr, "%s: %s is set-group-ID on execution - ignored\n",
-                   program_name, ifname));
+                   program_name, quotef (ifname)));
             close (ifd);
             return;
           }
@@ -892,14 +893,14 @@ treat_file (char *iname)
               {
                 WARN ((stderr,
                        "%s: %s has the sticky bit set - file ignored\n",
-                       program_name, ifname));
+                       program_name, quotef (ifname)));
                 close (ifd);
                 return;
               }
             if (2 <= istat.st_nlink)
               {
                 WARN ((stderr, "%s: %s has %ju other link%s -- file ignored\n",
-                       program_name, ifname,
+                       program_name, quotef (ifname),
                        (uintmax_t) {istat.st_nlink - 1},
                        istat.st_nlink == 2 ? "" : "s"));
                 close (ifd);
@@ -944,14 +945,14 @@ treat_file (char *iname)
 
         if (!decompress && save_orig_name && !verbose && !quiet) {
             fprintf(stderr, "%s: %s compressed to %s\n",
-                    program_name, ifname, ofname);
+                    program_name, quotef_n (0, ifname), quotef_n (1, ofname));
         }
     }
     /* Keep the name even if not truncated except with --no-name: */
     if (!save_orig_name) save_orig_name = !no_name;
 
     if (verbose && !list) {
-        fprintf(stderr, "%s:\t", ifname);
+      fprintf (stderr, "%s:\t", quotef (ifname));
     }
 
     /* Actually do the compression/decompression. Loop over zipped members.
@@ -1003,7 +1004,7 @@ treat_file (char *iname)
             sigprocmask (SIG_SETMASK, &oldset, NULL);
 
             if (unlink_errno)
-              WARN ((stderr, "%s: %s: %s\n", program_name, ifname,
+              WARN ((stderr, "%s: %s: %s\n", program_name, quotef (ifname),
                      strerror (unlink_errno)));
           }
       }
@@ -1025,7 +1026,7 @@ treat_file (char *iname)
         }
         if (!test)
           fprintf(stderr, " -- %s %s", keep ? "created" : "replaced with",
-                  ofname);
+                  quotef (ofname));
         eputstring ("\n");
     }
 }
@@ -1114,7 +1115,7 @@ create_outfile ()
     {
       /* name might be too long if an original name was saved */
       WARN ((stderr, "%s: %s: warning, name truncated\n",
-             program_name, ofname));
+             program_name, quotef (ofname)));
     }
 
   return OK;
@@ -1333,7 +1334,8 @@ open_input_file (char *iname, struct stat *sbuf)
     return -1;
 
  name_too_long:
-    fprintf (stderr, "%s: %s: file name too long\n", program_name, iname);
+    fprintf (stderr, "%s: %s: file name too long\n", program_name,
+             quotef (iname));
     exit_code = ERROR;
     return -1;
 }
@@ -1362,7 +1364,7 @@ make_ofname ()
             /* Avoid annoying messages with -r */
             if (verbose || (!recursive && !quiet)) {
                 WARN((stderr,"%s: %s: unknown suffix -- ignored\n",
-                      program_name, ifname));
+                      program_name, quotef (ifname)));
             }
             return WARNING;
         }
@@ -1380,7 +1382,7 @@ make_ofname ()
         if (verbose || (!recursive && !quiet)) {
             /* Don't use WARN, as it affects exit status.  */
             fprintf (stderr, "%s: %s already has %s suffix -- unchanged\n",
-                     program_name, ifname, suff);
+                     program_name, quotef_n (0, ifname), quotef_n (1, suff));
         }
         return WARNING;
     } else {
@@ -1417,7 +1419,8 @@ make_ofname ()
     return OK;
 
  name_too_long:
-    WARN ((stderr, "%s: %s: file name too long\n", program_name, ifname));
+    WARN ((stderr, "%s: %s: file name too long\n", program_name,
+           quotef (ifname)));
     return WARNING;
 }
 
@@ -1497,7 +1500,7 @@ get_method (int in, bool first)
         if (method != DEFLATED) {
             fprintf(stderr,
                     "%s: %s: unknown method %d -- not supported\n",
-                    program_name, ifname, method);
+                    program_name, quotef (ifname), method);
             exit_code = ERROR;
             return -1;
         }
@@ -1507,14 +1510,14 @@ get_method (int in, bool first)
         if ((flags & ENCRYPTED) != 0) {
             fprintf(stderr,
                     "%s: %s is encrypted -- not supported\n",
-                    program_name, ifname);
+                    program_name, quotef (ifname));
             exit_code = ERROR;
             return -1;
         }
         if ((flags & RESERVED) != 0) {
             fprintf(stderr,
                     "%s: %s has flags 0x%x -- not supported\n",
-                    program_name, ifname, flags);
+                    program_name, quotef (ifname), flags);
             exit_code = ERROR;
             if (force <= 1) return -1;
         }
@@ -1533,7 +1536,7 @@ get_method (int in, bool first)
               {
                 WARN ((stderr,
                        "%s: %s: MTIME %lu out of range for this platform\n",
-                       program_name, ifname, stamp));
+                       program_name, quotef (ifname), stamp));
                 time_stamp.tv_sec = TYPE_MAXIMUM (time_t);
                 time_stamp.tv_nsec = TIMESPEC_RESOLUTION - 1;
               }
@@ -1560,7 +1563,7 @@ get_method (int in, bool first)
             len |= (lenbuf[1] = get_byte ()) << 8;
             if (verbose) {
                 fprintf(stderr,"%s: %s: extra field of %u bytes ignored\n",
-                        program_name, ifname, len);
+                        program_name, quotef (ifname), len);
             }
             if (flags & HEADER_CRC)
               updcrc (lenbuf, 2);
@@ -1609,7 +1612,7 @@ get_method (int in, bool first)
               {
                 fprintf (stderr,
                          "%s: %s: header checksum 0x%04x != computed checksum 0x%04x\n",
-                         program_name, ifname, header16, crc16);
+                         program_name, quotef (ifname), header16, crc16);
                 exit_code = ERROR;
                 if (force <= 1)
                   return -1;
@@ -1658,7 +1661,7 @@ get_method (int in, bool first)
 
     if (part_nb == 1) {
         fprintf (stderr, "\n%s: %s: not in gzip format\n",
-                 program_name, ifname);
+                 program_name, quotef (ifname));
         exit_code = ERROR;
         return -1;
     } else {
@@ -1671,13 +1674,13 @@ get_method (int in, bool first)
               {
                 if (verbose)
                   WARN ((stderr, "\n%s: %s: decompression OK, trailing zero bytes ignored\n",
-                         program_name, ifname));
+                         program_name, quotef (ifname)));
                 return -3;
               }
           }
 
         WARN((stderr, "\n%s: %s: decompression OK, trailing garbage ignored\n",
-              program_name, ifname));
+              program_name, quotef (ifname)));
         return -2;
     }
 }
@@ -1760,7 +1763,7 @@ do_list (int method)
         total_out += bytes_out;
     }
     display_ratio(bytes_out-(bytes_in-header_bytes), bytes_out, stdout);
-    printf(" %s\n", ofname);
+    printf (" %s\n", quotef (ofname));
 }
 
 /* ========================================================================
@@ -1836,7 +1839,8 @@ check_ofname ()
     /* Ask permission to overwrite the existing file */
     if (!force) {
         int ok = 0;
-        fprintf (stderr, "%s: %s already exists;", program_name, ofname);
+        fprintf (stderr, "%s: %s already exists;",
+                 program_name, quotef (ofname));
         if (foreground && (presume_input_tty || isatty (STDIN_FILENO))) {
             eputstring (" do you wish to overwrite (y or n)? ");
             fflush(stderr);
@@ -1898,11 +1902,12 @@ copy_stat (struct stat *ifstat)
     if (fdutimens (ofd, ofname, timespec) == 0)
       {
         if (restoring && 1 < verbose) {
-            fprintf(stderr, "%s: timestamp restored\n", ofname);
+          fprintf (stderr, "%s: timestamp restored\n", quotef (ofname));
         }
       }
     else
-      WARN ((stderr, "%s: %s: %s\n", program_name, ofname, strerror (errno)));
+      WARN ((stderr, "%s: %s: %s\n", program_name, quotef (ofname),
+             strerror (errno)));
 #endif
 
     /* Change the group first, then the permissions, then the owner.
@@ -1919,7 +1924,8 @@ copy_stat (struct stat *ifstat)
     r = chmod (ofname, mode);
 #endif
     if (r != 0)
-      WARN ((stderr, "%s: %s: %s\n", program_name, ofname, strerror (errno)));
+      WARN ((stderr, "%s: %s: %s\n", program_name, quotef (ofname),
+             strerror (errno)));
 
     do_chown (ofd, ofname, ifstat->st_uid, -1);
 }
@@ -1967,7 +1973,7 @@ treat_dir (int fd, char *dir)
             treat_file(nbuf);
         } else {
             fprintf(stderr,"%s: %s/%s: pathname too long\n",
-                    program_name, dir, entry);
+                    program_name, quotef_n (0, dir), quotef_n (1, entry));
             exit_code = ERROR;
         }
     }
diff --git a/gzip.h b/gzip.h
index 3c0c801..6689da1 100644
--- a/gzip.h
+++ b/gzip.h
@@ -320,6 +320,8 @@ _Noreturn extern void read_error (void);
 _Noreturn extern void write_err (int err);
 _Noreturn extern void write_error (void);
 extern void display_ratio (off_t num, off_t den, FILE *file);
+extern char *quotef (char const *arg);
+extern char *quotef_n (int n, char const *arg);
 
         /* in inflate.c */
 extern int gzip_inflate (void);
diff --git a/lib/.gitignore b/lib/.gitignore
index fc08891..3bd1063 100644
--- a/lib/.gitignore
+++ b/lib/.gitignore
@@ -16,6 +16,8 @@
 /byteswap.h
 /byteswap.in.h
 /c++defs.h
+/c-ctype.c
+/c-ctype.h
 /calloc.c
 /chdir-long.c
 /chdir-long.h
@@ -122,6 +124,7 @@
 /malloc.c
 /malloca.c
 /malloca.h
+/mbszero.c
 /memchr.c
 /memchr.valgrind
 /memeq.c
@@ -147,6 +150,9 @@
 /pthread_sigmask.c
 /qsort.c
 /qsort_r.c
+/quote.h
+/quotearg.c
+/quotearg.h
 /raise.c
 /readdir.c
 /readlink.c
diff --git a/m4/.gitignore b/m4/.gitignore
index f88e1b1..d1006a8 100644
--- a/m4/.gitignore
+++ b/m4/.gitignore
@@ -66,12 +66,16 @@
 /lib-ignore.m4
 /limits-h.m4
 /locale-en.m4
+/locale-ja.m4
+/locale-zh.m4
 /lseek.m4
 /lstat.m4
 /malloc.m4
 /malloca.m4
 /manywarnings-c++.m4
 /manywarnings.m4
+/mbrtowc.m4
+/mbstate_t.m4
 /memchr.m4
 /memeq.m4
 /mempcpy.m4
@@ -96,6 +100,7 @@
 /pipe.m4
 /pthread_sigmask.m4
 /qsort_r.m4
+/quotearg.m4
 /raise.m4
 /readdir.m4
 /readlink.m4
diff --git a/tests/null-suffix-clobber b/tests/null-suffix-clobber
index 9aa5b70..a7f9003 100755
--- a/tests/null-suffix-clobber
+++ b/tests/null-suffix-clobber
@@ -21,7 +21,7 @@
 
 printf anything | gzip > F.gz || framework_failure_
 echo y > yes || framework_failure_
-echo "gzip: invalid suffix ''" > expected-err || framework_failure_
+echo "gzip: '': invalid suffix" > expected-err || framework_failure_
 
 fail=0
 
diff --git a/trees.c b/trees.c
index cc3aeff..684d672 100644
--- a/trees.c
+++ b/trees.c
@@ -66,11 +66,12 @@
  */
 
 #include <config.h>
-#include <ctype.h>
 
 #include "tailor.h"
 #include "gzip.h"
 
+#include <c-ctype.h>
+
 /* ===========================================================================
  * Constants
  */
@@ -607,7 +608,8 @@ gen_codes (ct_data near *tree, int max_code)
         tree[n].Code = bi_reverse(next_code[len]++, len);
 
         Tracec(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
-             n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1u));
+                                      n, c_isgraph (n) ? n : ' ', len,
+                                      tree[n].Code, next_code[len] - 1u));
     }
 }
 
@@ -1047,7 +1049,7 @@ compress_block (ct_data near *ltree, ct_data near *dtree)
         lc = l_buf[lx++];
         if ((flag & 1) == 0) {
             send_code(lc, ltree); /* send a literal byte */
-            Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+            Tracecv (c_isgraph (lc), (stderr," '%c' ", lc));
         } else {
             /* Here, lc is the match length - MIN_MATCH */
             code = length_code[lc];
diff --git a/unlzw.c b/unlzw.c
index a0dab13..358add3 100644
--- a/unlzw.c
+++ b/unlzw.c
@@ -125,7 +125,8 @@ unlzw (int in, int out)
     block_mode = maxbits & BLOCK_MODE;
     if ((maxbits & LZW_RESERVED) != 0) {
         WARN((stderr, "\n%s: %s: warning, unknown flags 0x%x\n",
-              program_name, ifname, (unsigned int) maxbits & LZW_RESERVED));
+              program_name, quotef (ifname),
+              (unsigned int) maxbits & LZW_RESERVED));
     }
     maxbits &= BIT_MASK;
     maxmaxcode = MAXCODE(maxbits);
@@ -133,7 +134,7 @@ unlzw (int in, int out)
     if (maxbits > BITS) {
         fprintf(stderr,
                 "\n%s: %s: compressed with %d bits, can only handle %d bits\n",
-                program_name, ifname, maxbits, BITS);
+                program_name, quotef (ifname), maxbits, BITS);
         exit_code = ERROR;
         return ERROR;
     }
diff --git a/unzip.c b/unzip.c
index ca93295..e3d40b6 100644
--- a/unzip.c
+++ b/unzip.c
@@ -139,7 +139,7 @@ check_zipfile (int in)
 
     if (bad)
       {
-        fprintf (stderr, "\n%s: %s: %s\n", program_name, ifname, bad);
+        fprintf (stderr, "\n%s: %s: %s\n", program_name, quotef (ifname), bad);
         exit_code = ERROR;
         return ERROR;
       }
@@ -240,7 +240,7 @@ unzip (int in, int out)
           {
             fprintf (stderr,
                      "\n%s: %s: invalid compressed data--crc/length error\n",
-                     program_name, ifname);
+                     program_name, quotef (ifname));
             err = ERROR;
           }
       }
@@ -264,14 +264,14 @@ unzip (int in, int out)
           {
             fprintf (stderr,
                      "\n%s: %s: invalid compressed data--crc error\n",
-                     program_name, ifname);
+                     program_name, quotef (ifname));
             err = ERROR;
           }
         if ((off_t) orig_len != len)
           {
             fprintf (stderr,
                      "\n%s: %s: invalid compressed data--length error\n",
-                     program_name, ifname);
+                     program_name, quotef (ifname));
             err = ERROR;
           }
     }
@@ -292,13 +292,13 @@ unzip (int in, int out)
             if (to_stdout)
               WARN ((stderr,
                      "%s: %s has more than one entry--rest ignored\n",
-                     program_name, ifname));
+                     program_name, quotef (ifname)));
             else
               {
                 /* Don't destroy the input zip file.  */
                 fprintf (stderr,
                          "%s: %s has more than one entry -- unchanged\n",
-                         program_name, ifname);
+                         program_name, quotef (ifname));
                 err = ERROR;
               }
           }
diff --git a/util.c b/util.c
index c133ee3..eca9fbe 100644
--- a/util.c
+++ b/util.c
@@ -18,19 +18,22 @@
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #include <config.h>
-#include <ctype.h>
-#include <errno.h>
-#include <limits.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdlib.h>
 
-#include "crc.h"
 #include "tailor.h"
 #include "gzip.h"
+
+#include <c-ctype.h>
+#include <crc.h>
 #include <dirname.h>
+#include <quotearg.h>
 #include <xalloc.h>
 
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <unistd.h>
+
 #ifndef EPIPE
 # define EPIPE 0
 #endif
@@ -233,7 +236,7 @@ strlwr (char *s)
 {
     char *t;
     for (t = s; *t; t++)
-      *t = tolower ((unsigned char) *t);
+      *t = c_tolower (*t);
     return s;
 }
 
@@ -364,7 +367,7 @@ char *add_envopt(
 void
 gzip_error (char const *m)
 {
-    fprintf (stderr, "\n%s: %s: %s\n", program_name, ifname, m);
+    fprintf (stderr, "\n%s: %s: %s\n", program_name, quotef (ifname), m);
     abort_gzip();
 }
 
@@ -377,13 +380,13 @@ xalloc_die ()
 
 void warning (char const *m)
 {
-    WARN ((stderr, "%s: %s: warning: %s\n", program_name, ifname, m));
+  WARN ((stderr, "%s: %s: warning: %s\n", program_name, quotef (ifname), m));
 }
 
 void read_error()
 {
     fprintf (stderr, "\n%s: %s: %s\n",
-             program_name, ifname,
+             program_name, quotef (ifname),
              errno ? strerror (errno) : "unexpected end of file");
     abort_gzip();
 }
@@ -393,7 +396,8 @@ write_err (int err)
 {
   int exitcode = err == EPIPE ? WARNING : ERROR;
   if (! (exitcode == WARNING && quiet))
-    fprintf (stderr, "\n%s: %s: %s\n", program_name, ofname, strerror (err));
+    fprintf (stderr, "\n%s: %s: %s\n", program_name, quotef (ofname),
+             strerror (err));
   finish_up_gzip (exitcode);
 }
 
@@ -414,3 +418,17 @@ display_ratio (off_t num, off_t den, FILE *file)
   else
     fputs (" -Inf%", file);
 }
+
+/* Quote file names.  */
+
+char *
+quotef (char const *arg)
+{
+  return quotef_n (0, arg);
+}
+
+char *
+quotef_n (int n, char const *arg)
+{
+  return quotearg_n_style_colon (n, shell_escape_quoting_style, arg);
+}
diff --git a/zdiff.in b/zdiff.in
index 8262c44..5f0e868 100644
--- a/zdiff.in
+++ b/zdiff.in
@@ -69,7 +69,7 @@ do
          '') file1=$arg;;
          *) case $file2 in
             '') file2=$arg;;
-            *) printf >&2 '%s\n' "$0: extra operand '$arg'"; exit 2;;
+            *) printf >&2 '%s\n' "$0: extra operand"; exit 2;;
             esac;;
          esac;;
      *) cmp="$cmp $needop '"`printf '%sX\n' "$arg" | LC_ALL=C sed "$escape"`
@@ -109,7 +109,7 @@ case $file2 in
         eval "$cmp" - '"$FILE"' >&3
     );;
   *)
-    printf >&2 '%s\n' "$0: $file1: unknown compressed file extension"
+    printf >&2 '%s\n' "$0: unknown compressed file extension"
     exit 2;;
   esac;;
 *)
diff --git a/zforce.in b/zforce.in
index 5ccf8cf..c2e0628 100644
--- a/zforce.in
+++ b/zforce.in
@@ -50,7 +50,7 @@ for i do
   esac
 
   if test ! -f "$i" ; then
-    printf '%s\n' "zforce: $i not a file"
+    printf '%s\n' "zforce: operand is not a file"
     res=1
     continue
   fi
@@ -58,7 +58,7 @@ for i do
   if 'gzip' -lv < "$i" 2>/dev/null | grep '^defl' > /dev/null; then
 
     new="$i.gz"
-    mv "$i" "$new" && printf '%s\n' "$i -- replaced with $new" || res=1
+    mv "$i" "$new" && printf '%s\n' "file replaced" || res=1
   fi
 done
 exit $res
diff --git a/zgrep.in b/zgrep.in
index 3ba748d..95b9a41 100644
--- a/zgrep.in
+++ b/zgrep.in
@@ -110,7 +110,7 @@ while test $# -ne 0; do
 
   case $option in
   (-[drRzZ] | --di* | --exc* | --inc* | --rec* | --nu*)
-    printf >&2 '%s: %s: option not supported\n' "$0" "$option"
+    printf >&2 '%s: option not supported\n' "$0"
     exit 2;;
   (-e* | --reg*)
     have_pat=1;;
diff --git a/zip.c b/zip.c
index 4e20a95..2f80a7f 100644
--- a/zip.c
+++ b/zip.c
@@ -17,7 +17,6 @@
    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #include <config.h>
-#include <ctype.h>
 
 #include "tailor.h"
 #include "gzip.h"
@@ -102,7 +101,7 @@ zip (int in, int out)
    */
     if (ifile_size != -1L && bytes_in != ifile_size) {
         fprintf(stderr, "%s: %s: file size changed while zipping\n",
-                program_name, ifname);
+                program_name, quotef (ifname));
     }
 #endif
 
-- 
2.53.0

Reply via email to