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