1
0
Fork 0

Adding upstream version 1.11.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-24 06:00:49 +01:00
parent 4c3aebf1aa
commit f08d47ccf4
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
31 changed files with 734 additions and 377 deletions

View file

@ -1,3 +1,17 @@
2022-01-25 Antonio Diaz Diaz <antonio@gnu.org>
* Version 1.11 released.
* zcmp.cc, zdiff.cc (main): Fix race returning 1 instead of 2 when a
compressor is not found or when the wrong format is forced.
* zcmp.cc (getnum): Show option name and valid range if error.
* All tools: Show option name if error in option argument.
* Add support for zstd format to all tools.
* 'zdiff -v -V' now prints the version of the diff program used.
* 'zgrep --verbose -V' now prints the version of the grep program used.
* zutils.texi: Document recompression of read-only files by linking.
* zutils.texi: Change GNU Texinfo category to 'Compression'.
(Reported by Alfred M. Szmidt).
2021-01-05 Antonio Diaz Diaz <antonio@gnu.org> 2021-01-05 Antonio Diaz Diaz <antonio@gnu.org>
* Version 1.10 released. * Version 1.10 released.
@ -37,7 +51,7 @@
* zutils.cc (good_status): Wait for killed child. * zutils.cc (good_status): Wait for killed child.
* Test and document continuation or exit of zcat, zgrep, ztest, * Test and document continuation or exit of zcat, zgrep, ztest,
and zupdate in case of error. and zupdate in case of error.
* configure: Accept appending to CXXFLAGS, 'CXXFLAGS+=OPTIONS'. * configure: Accept appending to CXXFLAGS; 'CXXFLAGS+=OPTIONS'.
2018-02-13 Antonio Diaz Diaz <antonio@gnu.org> 2018-02-13 Antonio Diaz Diaz <antonio@gnu.org>
@ -147,8 +161,8 @@
2009-10-05 Antonio Diaz Diaz <ant_diaz@teleline.es> 2009-10-05 Antonio Diaz Diaz <ant_diaz@teleline.es>
* Version 0.6 released. * Version 0.6 released.
* zcat.in, zgrep.in: Remove again default compressor. Format of * zcat.in, zgrep.in: Remove again default compressor. The format of
data read from stdin is now automatically detected. the data read from stdin is now automatically detected.
* Makefile.in: Add option '--name' to help2man invocation. * Makefile.in: Add option '--name' to help2man invocation.
2009-10-01 Antonio Diaz Diaz <ant_diaz@teleline.es> 2009-10-01 Antonio Diaz Diaz <ant_diaz@teleline.es>
@ -180,7 +194,7 @@
* Version 0.1 released. * Version 0.1 released.
Copyright (C) 2009-2021 Antonio Diaz Diaz. Copyright (C) 2009-2022 Antonio Diaz Diaz.
This file is a collection of facts, and thus it is not copyrightable, This file is a collection of facts, and thus it is not copyrightable,
but just in case, you have unlimited permission to copy, distribute, and but just in case, you have unlimited permission to copy, distribute, and

View file

@ -1,7 +1,8 @@
Requirements Requirements
------------ ------------
You will need a C++11 compiler. (gcc 3.3.6 or newer is recommended). You will need a C++98 compiler with suport for 'long long'.
I use gcc 6.1.0 and 4.1.2, but the code should compile with any standards (gcc 3.3.6 or newer is recommended).
I use gcc 6.1.0 and 3.3.6, but the code should compile with any standards
compliant compiler. compliant compiler.
Gcc is available at http://gcc.gnu.org. Gcc is available at http://gcc.gnu.org.
@ -75,7 +76,7 @@ After running 'configure', you can run 'make' and 'make install' as
explained above. explained above.
Copyright (C) 2009-2021 Antonio Diaz Diaz. Copyright (C) 2009-2022 Antonio Diaz Diaz.
This file is free documentation: you have unlimited permission to copy, This file is free documentation: you have unlimited permission to copy,
distribute, and modify it. distribute, and modify it.

View file

@ -29,13 +29,13 @@ scripts = zegrep zfgrep
all : $(programs) $(scripts) all : $(programs) $(scripts)
zcat : $(zcat_objs) zcat : $(zcat_objs)
$(CXX) $(LDFLAGS) $(CXXFLAGS) -o $@ $(zcat_objs) $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $(zcat_objs)
zcmp : $(zcmp_objs) zcmp : $(zcmp_objs)
$(CXX) $(LDFLAGS) $(CXXFLAGS) -o $@ $(zcmp_objs) $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $(zcmp_objs)
zdiff : $(zdiff_objs) zdiff : $(zdiff_objs)
$(CXX) $(LDFLAGS) $(CXXFLAGS) -o $@ $(zdiff_objs) $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $(zdiff_objs)
zegrep : zegrep.in zegrep : zegrep.in
cat $(VPATH)/zegrep.in > $@ cat $(VPATH)/zegrep.in > $@
@ -46,13 +46,13 @@ zfgrep : zfgrep.in
chmod a+x zfgrep chmod a+x zfgrep
zgrep : $(zgrep_objs) zgrep : $(zgrep_objs)
$(CXX) $(LDFLAGS) $(CXXFLAGS) -o $@ $(zgrep_objs) $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $(zgrep_objs)
ztest : $(ztest_objs) ztest : $(ztest_objs)
$(CXX) $(LDFLAGS) $(CXXFLAGS) -o $@ $(ztest_objs) $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $(ztest_objs)
zupdate : $(zupdate_objs) zupdate : $(zupdate_objs)
$(CXX) $(LDFLAGS) $(CXXFLAGS) -o $@ $(zupdate_objs) $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $(zupdate_objs)
rc.o : rc.cc rc.o : rc.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -DPROGVERSION=\"$(pkgversion)\" -DSYSCONFDIR=\"$(sysconfdir)\" -c -o $@ $< $(CXX) $(CPPFLAGS) $(CXXFLAGS) -DPROGVERSION=\"$(pkgversion)\" -DSYSCONFDIR=\"$(sysconfdir)\" -c -o $@ $<
@ -91,27 +91,27 @@ man : $(VPATH)/doc/zcat.1 $(VPATH)/doc/zcmp.1 $(VPATH)/doc/zdiff.1 \
$(VPATH)/doc/zcat.1 : zcat $(VPATH)/doc/zcat.1 : zcat
help2man -n 'decompress and concatenate files to standard output' \ help2man -n 'decompress and concatenate files to standard output' \
-o $@ --no-info ./zcat -o $@ --info-page=$(pkgname) ./zcat
$(VPATH)/doc/zcmp.1 : zcmp $(VPATH)/doc/zcmp.1 : zcmp
help2man -n 'decompress and compare two files byte by byte' \ help2man -n 'decompress and compare two files byte by byte' \
-o $@ --no-info ./zcmp -o $@ --info-page=$(pkgname) ./zcmp
$(VPATH)/doc/zdiff.1 : zdiff $(VPATH)/doc/zdiff.1 : zdiff
help2man -n 'decompress and compare two files line by line' \ help2man -n 'decompress and compare two files line by line' \
-o $@ --no-info ./zdiff -o $@ --info-page=$(pkgname) ./zdiff
$(VPATH)/doc/zgrep.1 : zgrep $(VPATH)/doc/zgrep.1 : zgrep
help2man -n 'search compressed files for a regular expression' \ help2man -n 'search compressed files for a regular expression' \
-o $@ --no-info ./zgrep -o $@ --info-page=$(pkgname) ./zgrep
$(VPATH)/doc/ztest.1 : ztest $(VPATH)/doc/ztest.1 : ztest
help2man -n 'verify the integrity of compressed files' \ help2man -n 'verify the integrity of compressed files' \
-o $@ --no-info ./ztest -o $@ --info-page=$(pkgname) ./ztest
$(VPATH)/doc/zupdate.1 : zupdate $(VPATH)/doc/zupdate.1 : zupdate
help2man -n 'recompress bzip2, gzip, xz files to lzip format' \ help2man -n 'recompress bzip2, gzip, xz, zstd files to lzip format' \
-o $@ --no-info ./zupdate -o $@ --info-page=$(pkgname) ./zupdate
Makefile : $(VPATH)/configure $(VPATH)/Makefile.in Makefile : $(VPATH)/configure $(VPATH)/Makefile.in
./config.status ./config.status

33
NEWS
View file

@ -1,9 +1,30 @@
Changes in version 1.10: Changes in version 1.11:
A portability issue with Solaris 10 has been fixed. A race has been fixed in zcmp and zdiff that sometimes made them return 1
(files differ) instead of 2 (trouble) when a compressor is not found or when
the wrong format is forced.
It has been documented in the manual that 'zgrep -L' fails with GNU grep In case of error in an argument to a command line option, all tools now show
versions 3.2 to 3.4 inclusive because of a wrong change reverted in GNU grep the name of the option.
3.5.
'make check' now tests empty input files with all tools except zupdate. In case of error in a numerical argument to a command line option, zcmp
now shows the name of the option and the range of valid values.
Support for the zstd format has been added to all tools. This allows, among
other things, zupdating zstd files to lzip format for long-term archiving,
and using zcmp along with the unzcrash tool (from the lziprecover package)
to test zstd files.
'zdiff --verbose --version' now prints the version of the diff program used
if it supports the option '--version'.
'zgrep --verbose --version' now prints the version of the grep program used
if it supports the option '--version'.
It has been documented in the manual how to recompress files with zupdate
from a read-only file system to another place by first linking the files
from the destination directory and then compressing the links:
'ln -s /src/foo.gz . && zupdate foo.gz'
The texinfo category of the manual has been changed from 'Data Compression'
to 'Compression' to match that of gzip. (Reported by Alfred M. Szmidt).

13
README
View file

@ -11,7 +11,7 @@ programs. In particular the option '--recursive' is very efficient in
those utilities supporting it. those utilities supporting it.
The utilities provided are zcat, zcmp, zdiff, zgrep, ztest, and zupdate. The utilities provided are zcat, zcmp, zdiff, zgrep, ztest, and zupdate.
The formats supported are bzip2, gzip, lzip, and xz. The formats supported are bzip2, gzip, lzip, xz, and zstd.
Zutils uses external compressors. The compressor to be used for each format Zutils uses external compressors. The compressor to be used for each format
is configurable at runtime. is configurable at runtime.
@ -21,11 +21,14 @@ gzip's znew.
NOTE: Bzip2 and lzip provide well-defined values of exit status, which makes NOTE: Bzip2 and lzip provide well-defined values of exit status, which makes
them safe to use with zutils. Gzip and xz may return ambiguous warning them safe to use with zutils. Gzip and xz may return ambiguous warning
values, making them less reliable back ends for zutils. values, making them less reliable back ends for zutils. Zstd currently does
not even document its exit status in its man page.
FORMAT NOTE 1: The option '--format' allows the processing of a subset FORMAT NOTE 1: The option '--format' allows the processing of a subset
of formats in recursive mode and when trying compressed file names: of formats in recursive mode and when trying compressed file names. For
'zgrep foo -r --format=bz2,lz somedir somefile.tar'. example, use the following command to search for the string 'foo' in
gzip and lzip files only:
'zgrep foo -r --format=gz,lz somedir somefile.tar'.
FORMAT NOTE 2: If the option '--force-format' is given, the files are FORMAT NOTE 2: If the option '--force-format' is given, the files are
passed to the corresponding decompressor without verifying their format, passed to the corresponding decompressor without verifying their format,
@ -37,7 +40,7 @@ been compressed. Decompressed is used to refer to data which have undergone
the process of decompression. the process of decompression.
Copyright (C) 2009-2021 Antonio Diaz Diaz. Copyright (C) 2009-2022 Antonio Diaz Diaz.
This file is free documentation: you have unlimited permission to copy, This file is free documentation: you have unlimited permission to copy,
distribute, and modify it. distribute, and modify it.

View file

@ -1,5 +1,5 @@
/* Arg_parser - POSIX/GNU command line argument parser. (C++ version) /* Arg_parser - POSIX/GNU command line argument parser. (C++ version)
Copyright (C) 2006-2021 Antonio Diaz Diaz. Copyright (C) 2006-2022 Antonio Diaz Diaz.
This library is free software. Redistribution and use in source and This library is free software. Redistribution and use in source and
binary forms, with or without modification, are permitted provided binary forms, with or without modification, are permitted provided
@ -35,9 +35,10 @@ bool Arg_parser::parse_long_option( const char * const opt, const char * const a
// Test all long options for either exact match or abbreviated matches. // Test all long options for either exact match or abbreviated matches.
for( int i = 0; options[i].code != 0; ++i ) for( int i = 0; options[i].code != 0; ++i )
if( options[i].name && std::strncmp( options[i].name, &opt[2], len ) == 0 ) if( options[i].long_name &&
std::strncmp( options[i].long_name, &opt[2], len ) == 0 )
{ {
if( std::strlen( options[i].name ) == len ) // Exact match found if( std::strlen( options[i].long_name ) == len ) // Exact match found
{ index = i; exact = true; break; } { index = i; exact = true; break; }
else if( index < 0 ) index = i; // First nonexact match found else if( index < 0 ) index = i; // First nonexact match found
else if( options[index].code != options[i].code || else if( options[index].code != options[i].code ||
@ -58,19 +59,19 @@ bool Arg_parser::parse_long_option( const char * const opt, const char * const a
} }
++argind; ++argind;
data.push_back( Record( options[index].code ) ); data.push_back( Record( options[index].code, options[index].long_name ) );
if( opt[len+2] ) // '--<long_option>=<argument>' syntax if( opt[len+2] ) // '--<long_option>=<argument>' syntax
{ {
if( options[index].has_arg == no ) if( options[index].has_arg == no )
{ {
error_ = "option '--"; error_ += options[index].name; error_ = "option '--"; error_ += options[index].long_name;
error_ += "' doesn't allow an argument"; error_ += "' doesn't allow an argument";
return false; return false;
} }
if( options[index].has_arg == yes && !opt[len+3] ) if( options[index].has_arg == yes && !opt[len+3] )
{ {
error_ = "option '--"; error_ += options[index].name; error_ = "option '--"; error_ += options[index].long_name;
error_ += "' requires an argument"; error_ += "' requires an argument";
return false; return false;
} }
@ -82,7 +83,7 @@ bool Arg_parser::parse_long_option( const char * const opt, const char * const a
{ {
if( !arg || !arg[0] ) if( !arg || !arg[0] )
{ {
error_ = "option '--"; error_ += options[index].name; error_ = "option '--"; error_ += options[index].long_name;
error_ += "' requires an argument"; error_ += "' requires an argument";
return false; return false;
} }

View file

@ -1,5 +1,5 @@
/* Arg_parser - POSIX/GNU command line argument parser. (C++ version) /* Arg_parser - POSIX/GNU command line argument parser. (C++ version)
Copyright (C) 2006-2021 Antonio Diaz Diaz. Copyright (C) 2006-2022 Antonio Diaz Diaz.
This library is free software. Redistribution and use in source and This library is free software. Redistribution and use in source and
binary forms, with or without modification, are permitted provided binary forms, with or without modification, are permitted provided
@ -23,9 +23,9 @@
In case of error, 'error' returns a non-empty error message. In case of error, 'error' returns a non-empty error message.
'options' is an array of 'struct Option' terminated by an element 'options' is an array of 'struct Option' terminated by an element
containing a code which is zero. A null name means a short-only containing a code which is zero. A null long_name means a short-only
option. A code value outside the unsigned char range means a option. A code value outside the unsigned char range means a long-only
long-only option. option.
Arg_parser normally makes it appear as if all the option arguments Arg_parser normally makes it appear as if all the option arguments
were specified before all the non-option arguments for the purposes were specified before all the non-option arguments for the purposes
@ -48,7 +48,7 @@ public:
struct Option struct Option
{ {
int code; // Short option letter or code ( code != 0 ) int code; // Short option letter or code ( code != 0 )
const char * name; // Long option name (maybe null) const char * long_name; // Long option name (maybe null)
Has_arg has_arg; Has_arg has_arg;
}; };
@ -56,8 +56,12 @@ private:
struct Record struct Record
{ {
int code; int code;
std::string parsed_name;
std::string argument; std::string argument;
explicit Record( const int c ) : code( c ) {} explicit Record( const unsigned char c )
: code( c ), parsed_name( "-" ) { parsed_name += c; }
Record( const int c, const char * const long_name )
: code( c ), parsed_name( "--" ) { parsed_name += long_name; }
explicit Record( const char * const arg ) : code( 0 ), argument( arg ) {} explicit Record( const char * const arg ) : code( 0 ), argument( arg ) {}
}; };
@ -91,6 +95,13 @@ public:
else return 0; else return 0;
} }
// Full name of the option parsed (short or long).
const std::string & parsed_name( const int i ) const
{
if( i >= 0 && i < arguments() ) return data[i].parsed_name;
else return empty_arg;
}
const std::string & argument( const int i ) const const std::string & argument( const int i ) const
{ {
if( i >= 0 && i < arguments() ) return data[i].argument; if( i >= 0 && i < arguments() ) return data[i].argument;

6
configure vendored
View file

@ -1,12 +1,12 @@
#! /bin/sh #! /bin/sh
# configure script for Zutils - Utilities dealing with compressed files # configure script for Zutils - Utilities dealing with compressed files
# Copyright (C) 2009-2021 Antonio Diaz Diaz. # Copyright (C) 2009-2022 Antonio Diaz Diaz.
# #
# This configure script is free software: you have unlimited permission # This configure script is free software: you have unlimited permission
# to copy, distribute, and modify it. # to copy, distribute, and modify it.
pkgname=zutils pkgname=zutils
pkgversion=1.10 pkgversion=1.11
srctrigger=doc/${pkgname}.texi srctrigger=doc/${pkgname}.texi
# clear some things potentially inherited from environment. # clear some things potentially inherited from environment.
@ -179,7 +179,7 @@ echo "GREP = ${GREP}"
rm -f Makefile rm -f Makefile
cat > Makefile << EOF cat > Makefile << EOF
# Makefile for Zutils - Utilities dealing with compressed files # Makefile for Zutils - Utilities dealing with compressed files
# Copyright (C) 2009-2021 Antonio Diaz Diaz. # Copyright (C) 2009-2022 Antonio Diaz Diaz.
# This file was generated automatically by configure. Don't edit. # This file was generated automatically by configure. Don't edit.
# #
# This Makefile is free software: you have unlimited permission # This Makefile is free software: you have unlimited permission

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.16. .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.16.
.TH ZCAT "1" "January 2021" "zutils 1.10" "User Commands" .TH ZCAT "1" "January 2022" "zutils 1.11" "User Commands"
.SH NAME .SH NAME
zcat \- decompress and concatenate files to standard output zcat \- decompress and concatenate files to standard output
.SH SYNOPSIS .SH SYNOPSIS
@ -21,7 +21,7 @@ same compressed format.
If no files are specified, recursive searches examine the current If no files are specified, recursive searches examine the current
working directory, and nonrecursive searches read standard input. working directory, and nonrecursive searches read standard input.
.PP .PP
The formats supported are bzip2, gzip, lzip, and xz. The formats supported are bzip2, gzip, lzip, xz, and zstd.
.PP .PP
Exit status is 0 if no errors occurred, 1 otherwise. Exit status is 0 if no errors occurred, 1 otherwise.
.SH OPTIONS .SH OPTIONS
@ -54,7 +54,7 @@ number all output lines
don't read runtime configuration file don't read runtime configuration file
.TP .TP
\fB\-O\fR, \fB\-\-force\-format=\fR<fmt> \fB\-O\fR, \fB\-\-force\-format=\fR<fmt>
force the format given (bz2, gz, lz, xz) force the format given (bz2, gz, lz, xz, zst)
.TP .TP
\fB\-q\fR, \fB\-\-quiet\fR \fB\-q\fR, \fB\-\-quiet\fR
suppress all messages suppress all messages
@ -91,13 +91,28 @@ set compressor and options for lzip format
.TP .TP
\fB\-\-xz=\fR<command> \fB\-\-xz=\fR<command>
set compressor and options for xz format set compressor and options for xz format
.TP
\fB\-\-zst=\fR<command>
set compressor and options for zstd format
.SH "REPORTING BUGS" .SH "REPORTING BUGS"
Report bugs to zutils\-bug@nongnu.org Report bugs to zutils\-bug@nongnu.org
.br .br
Zutils home page: http://www.nongnu.org/zutils/zutils.html Zutils home page: http://www.nongnu.org/zutils/zutils.html
.SH COPYRIGHT .SH COPYRIGHT
Copyright \(co 2021 Antonio Diaz Diaz. Copyright \(co 2022 Antonio Diaz Diaz.
License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html> License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>
.br .br
This is free software: you are free to change and redistribute it. This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. There is NO WARRANTY, to the extent permitted by law.
.SH "SEE ALSO"
The full documentation for
.B zcat
is maintained as a Texinfo manual. If the
.B info
and
.B zcat
programs are properly installed at your site, the command
.IP
.B info zutils
.PP
should give you access to the complete manual.

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.16. .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.16.
.TH ZCMP "1" "January 2021" "zutils 1.10" "User Commands" .TH ZCMP "1" "January 2022" "zutils 1.11" "User Commands"
.SH NAME .SH NAME
zcmp \- decompress and compare two files byte by byte zcmp \- decompress and compare two files byte by byte
.SH SYNOPSIS .SH SYNOPSIS
@ -12,7 +12,7 @@ starting with 1. A hyphen '\-' used as a file argument means standard input.
If any file given is compressed, its decompressed content is used. Compressed If any file given is compressed, its decompressed content is used. Compressed
files are decompressed on the fly; no temporary files are created. files are decompressed on the fly; no temporary files are created.
.PP .PP
The formats supported are bzip2, gzip, lzip, and xz. The formats supported are bzip2, gzip, lzip, xz, and zstd.
.PP .PP
zcmp compares file1 to file2. The standard input is used only if file1 or zcmp compares file1 to file2. The standard input is used only if file1 or
file2 refers to standard input. If file2 is omitted zcmp tries the file2 refers to standard input. If file2 is omitted zcmp tries the
@ -23,7 +23,7 @@ the corresponding uncompressed file (the name of file1 with the
extension removed). extension removed).
.IP .IP
\- If file1 is uncompressed, compares it with the decompressed \- If file1 is uncompressed, compares it with the decompressed
contents of file1.[lz|bz2|gz|xz] (the first one that is found). contents of file1.[lz|bz2|gz|zst|xz] (the first one that is found).
.PP .PP
Exit status is 0 if inputs are identical, 1 if different, 2 if trouble. Exit status is 0 if inputs are identical, 1 if different, 2 if trouble.
.SH OPTIONS .SH OPTIONS
@ -53,7 +53,7 @@ compare at most <n> bytes
don't read runtime configuration file don't read runtime configuration file
.TP .TP
\fB\-O\fR, \fB\-\-force\-format\fR=\fI\,[\/\fR<f1>][,<f2>] \fB\-O\fR, \fB\-\-force\-format\fR=\fI\,[\/\fR<f1>][,<f2>]
force the formats given (bz2, gz, lz, xz) force the formats given (bz2,gz,lz,xz,zst)
.TP .TP
\fB\-q\fR, \fB\-\-quiet\fR \fB\-q\fR, \fB\-\-quiet\fR
suppress all messages suppress all messages
@ -75,6 +75,9 @@ set compressor and options for lzip format
.TP .TP
\fB\-\-xz=\fR<command> \fB\-\-xz=\fR<command>
set compressor and options for xz format set compressor and options for xz format
.TP
\fB\-\-zst=\fR<command>
set compressor and options for zstd format
.PP .PP
Numbers may be followed by a multiplier: k = kB = 10^3 = 1000, Numbers may be followed by a multiplier: k = kB = 10^3 = 1000,
Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc... Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...
@ -83,8 +86,20 @@ Report bugs to zutils\-bug@nongnu.org
.br .br
Zutils home page: http://www.nongnu.org/zutils/zutils.html Zutils home page: http://www.nongnu.org/zutils/zutils.html
.SH COPYRIGHT .SH COPYRIGHT
Copyright \(co 2021 Antonio Diaz Diaz. Copyright \(co 2022 Antonio Diaz Diaz.
License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html> License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>
.br .br
This is free software: you are free to change and redistribute it. This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. There is NO WARRANTY, to the extent permitted by law.
.SH "SEE ALSO"
The full documentation for
.B zcmp
is maintained as a Texinfo manual. If the
.B info
and
.B zcmp
programs are properly installed at your site, the command
.IP
.B info zutils
.PP
should give you access to the complete manual.

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.16. .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.16.
.TH ZDIFF "1" "January 2021" "zutils 1.10" "User Commands" .TH ZDIFF "1" "January 2022" "zutils 1.11" "User Commands"
.SH NAME .SH NAME
zdiff \- decompress and compare two files line by line zdiff \- decompress and compare two files line by line
.SH SYNOPSIS .SH SYNOPSIS
@ -12,7 +12,9 @@ input. If any file given is compressed, its decompressed content is used.
zdiff is a front end to the program diff and has the limitation that messages zdiff is a front end to the program diff and has the limitation that messages
from diff refer to temporary file names instead of those specified. from diff refer to temporary file names instead of those specified.
.PP .PP
The formats supported are bzip2, gzip, lzip, and xz. \&'zdiff \fB\-v\fR \fB\-V\fR' prints the version of the diff program used.
.PP
The formats supported are bzip2, gzip, lzip, xz, and zstd.
.PP .PP
zdiff compares file1 to file2. The standard input is used only if file1 or zdiff compares file1 to file2. The standard input is used only if file1 or
file2 refers to standard input. If file2 is omitted zdiff tries the file2 refers to standard input. If file2 is omitted zdiff tries the
@ -23,7 +25,7 @@ the corresponding uncompressed file (the name of file1 with the
extension removed). extension removed).
.IP .IP
\- If file1 is uncompressed, compares it with the decompressed \- If file1 is uncompressed, compares it with the decompressed
contents of file1.[lz|bz2|gz|xz] (the first one that is found). contents of file1.[lz|bz2|gz|zst|xz] (the first one that is found).
.PP .PP
Exit status is 0 if inputs are identical, 1 if different, 2 if trouble. Exit status is 0 if inputs are identical, 1 if different, 2 if trouble.
Some options only work if the diff program used supports them. Some options only work if the diff program used supports them.
@ -66,7 +68,7 @@ process only the formats in <list>
don't read runtime configuration file don't read runtime configuration file
.TP .TP
\fB\-O\fR, \fB\-\-force\-format\fR=\fI\,[\/\fR<f1>][,<f2>] \fB\-O\fR, \fB\-\-force\-format\fR=\fI\,[\/\fR<f1>][,<f2>]
force the formats given (bz2, gz, lz, xz) force the formats given (bz2,gz,lz,xz,zst)
.TP .TP
\fB\-p\fR, \fB\-\-show\-c\-function\fR \fB\-p\fR, \fB\-\-show\-c\-function\fR
show which C function each change is in show which C function each change is in
@ -89,6 +91,9 @@ use the unified output format
\fB\-U\fR, \fB\-\-unified=\fR<n> \fB\-U\fR, \fB\-\-unified=\fR<n>
same as \fB\-u\fR but use <n> lines of context same as \fB\-u\fR but use <n> lines of context
.TP .TP
\fB\-v\fR, \fB\-\-verbose\fR
verbose mode (for \fB\-\-version\fR)
.TP
\fB\-w\fR, \fB\-\-ignore\-all\-space\fR \fB\-w\fR, \fB\-\-ignore\-all\-space\fR
ignore all white space ignore all white space
.TP .TP
@ -109,13 +114,28 @@ set compressor and options for lzip format
.TP .TP
\fB\-\-xz=\fR<command> \fB\-\-xz=\fR<command>
set compressor and options for xz format set compressor and options for xz format
.TP
\fB\-\-zst=\fR<command>
set compressor and options for zstd format
.SH "REPORTING BUGS" .SH "REPORTING BUGS"
Report bugs to zutils\-bug@nongnu.org Report bugs to zutils\-bug@nongnu.org
.br .br
Zutils home page: http://www.nongnu.org/zutils/zutils.html Zutils home page: http://www.nongnu.org/zutils/zutils.html
.SH COPYRIGHT .SH COPYRIGHT
Copyright \(co 2021 Antonio Diaz Diaz. Copyright \(co 2022 Antonio Diaz Diaz.
License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html> License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>
.br .br
This is free software: you are free to change and redistribute it. This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. There is NO WARRANTY, to the extent permitted by law.
.SH "SEE ALSO"
The full documentation for
.B zdiff
is maintained as a Texinfo manual. If the
.B info
and
.B zdiff
programs are properly installed at your site, the command
.IP
.B info zutils
.PP
should give you access to the complete manual.

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.16. .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.16.
.TH ZGREP "1" "January 2021" "zutils 1.10" "User Commands" .TH ZGREP "1" "January 2022" "zutils 1.11" "User Commands"
.SH NAME .SH NAME
zgrep \- search compressed files for a regular expression zgrep \- search compressed files for a regular expression
.SH SYNOPSIS .SH SYNOPSIS
@ -22,7 +22,9 @@ compressed format.
If no files are specified, recursive searches examine the current If no files are specified, recursive searches examine the current
working directory, and nonrecursive searches read standard input. working directory, and nonrecursive searches read standard input.
.PP .PP
The formats supported are bzip2, gzip, lzip, and xz. \&'zgrep \fB\-\-verbose\fR \fB\-V\fR' prints the version of the grep program used.
.PP
The formats supported are bzip2, gzip, lzip, xz, and zstd.
.PP .PP
Exit status is 0 if match, 1 if no match, 2 if trouble. Exit status is 0 if match, 1 if no match, 2 if trouble.
Some options only work if the grep program used supports them. Some options only work if the grep program used supports them.
@ -101,7 +103,7 @@ don't read runtime configuration file
show only the part of a line matching <pattern> show only the part of a line matching <pattern>
.TP .TP
\fB\-O\fR, \fB\-\-force\-format=\fR<fmt> \fB\-O\fR, \fB\-\-force\-format=\fR<fmt>
force the format given (bz2, gz, lz, xz) force the format given (bz2, gz, lz, xz, zst)
.TP .TP
\fB\-q\fR, \fB\-\-quiet\fR \fB\-q\fR, \fB\-\-quiet\fR
suppress all messages suppress all messages
@ -138,6 +140,9 @@ set compressor and options for lzip format
.TP .TP
\fB\-\-xz=\fR<command> \fB\-\-xz=\fR<command>
set compressor and options for xz format set compressor and options for xz format
.TP
\fB\-\-zst=\fR<command>
set compressor and options for zstd format
.PP .PP
Numbers may be followed by a multiplier: k = kB = 10^3 = 1000, Numbers may be followed by a multiplier: k = kB = 10^3 = 1000,
Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc... Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...
@ -146,8 +151,20 @@ Report bugs to zutils\-bug@nongnu.org
.br .br
Zutils home page: http://www.nongnu.org/zutils/zutils.html Zutils home page: http://www.nongnu.org/zutils/zutils.html
.SH COPYRIGHT .SH COPYRIGHT
Copyright \(co 2021 Antonio Diaz Diaz. Copyright \(co 2022 Antonio Diaz Diaz.
License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html> License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>
.br .br
This is free software: you are free to change and redistribute it. This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. There is NO WARRANTY, to the extent permitted by law.
.SH "SEE ALSO"
The full documentation for
.B zgrep
is maintained as a Texinfo manual. If the
.B info
and
.B zgrep
programs are properly installed at your site, the command
.IP
.B info zutils
.PP
should give you access to the complete manual.

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.16. .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.16.
.TH ZTEST "1" "January 2021" "zutils 1.10" "User Commands" .TH ZTEST "1" "January 2022" "zutils 1.11" "User Commands"
.SH NAME .SH NAME
ztest \- verify the integrity of compressed files ztest \- verify the integrity of compressed files
.SH SYNOPSIS .SH SYNOPSIS
@ -18,7 +18,7 @@ test when testing multiple files.
If no files are specified, recursive searches examine the current If no files are specified, recursive searches examine the current
working directory, and nonrecursive searches read standard input. working directory, and nonrecursive searches read standard input.
.PP .PP
The formats supported are bzip2, gzip, lzip, and xz. The formats supported are bzip2, gzip, lzip, xz, and zstd.
.PP .PP
Note that error detection in the xz format is broken. First, some xz Note that error detection in the xz format is broken. First, some xz
files lack integrity information. Second, not all xz decompressors can files lack integrity information. Second, not all xz decompressors can
@ -45,7 +45,7 @@ process only the formats in <list>
don't read runtime configuration file don't read runtime configuration file
.TP .TP
\fB\-O\fR, \fB\-\-force\-format=\fR<fmt> \fB\-O\fR, \fB\-\-force\-format=\fR<fmt>
force the format given (bz2, gz, lz, xz) force the format given (bz2, gz, lz, xz, zst)
.TP .TP
\fB\-q\fR, \fB\-\-quiet\fR \fB\-q\fR, \fB\-\-quiet\fR
suppress all messages suppress all messages
@ -70,13 +70,28 @@ set compressor and options for lzip format
.TP .TP
\fB\-\-xz=\fR<command> \fB\-\-xz=\fR<command>
set compressor and options for xz format set compressor and options for xz format
.TP
\fB\-\-zst=\fR<command>
set compressor and options for zstd format
.SH "REPORTING BUGS" .SH "REPORTING BUGS"
Report bugs to zutils\-bug@nongnu.org Report bugs to zutils\-bug@nongnu.org
.br .br
Zutils home page: http://www.nongnu.org/zutils/zutils.html Zutils home page: http://www.nongnu.org/zutils/zutils.html
.SH COPYRIGHT .SH COPYRIGHT
Copyright \(co 2021 Antonio Diaz Diaz. Copyright \(co 2022 Antonio Diaz Diaz.
License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html> License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>
.br .br
This is free software: you are free to change and redistribute it. This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. There is NO WARRANTY, to the extent permitted by law.
.SH "SEE ALSO"
The full documentation for
.B ztest
is maintained as a Texinfo manual. If the
.B info
and
.B ztest
programs are properly installed at your site, the command
.IP
.B info zutils
.PP
should give you access to the complete manual.

View file

@ -1,12 +1,12 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.16. .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.16.
.TH ZUPDATE "1" "January 2021" "zutils 1.10" "User Commands" .TH ZUPDATE "1" "January 2022" "zutils 1.11" "User Commands"
.SH NAME .SH NAME
zupdate \- recompress bzip2, gzip, xz files to lzip format zupdate \- recompress bzip2, gzip, xz, zstd files to lzip format
.SH SYNOPSIS .SH SYNOPSIS
.B zupdate .B zupdate
[\fI\,options\/\fR] [\fI\,files\/\fR] [\fI\,options\/\fR] [\fI\,files\/\fR]
.SH DESCRIPTION .SH DESCRIPTION
zupdate recompresses files from bzip2, gzip, and xz formats to lzip zupdate recompresses files from bzip2, gzip, xz, and zstd formats to lzip
format. Each original is compared with the new file and then deleted. format. Each original is compared with the new file and then deleted.
Only regular files with standard file name extensions are recompressed, Only regular files with standard file name extensions are recompressed,
other files are ignored. Compressed files are decompressed and then other files are ignored. Compressed files are decompressed and then
@ -25,8 +25,10 @@ to be safe and not cause any data loss. Therefore, existing lzip
compressed files are never overwritten nor deleted. compressed files are never overwritten nor deleted.
.PP .PP
The names of the original files must have one of the following extensions: The names of the original files must have one of the following extensions:
\&'.bz2', '.gz', or '.xz', which are recompressed to '.lz'; .PP
\&'.tbz', '.tbz2', '.tgz', or '.txz', which are recompressed to '.tlz'. \&'.bz2', '.gz', '.xz', or '.zst', which are recompressed to '.lz'.
.PP
\&'.tbz', '.tbz2', '.tgz', '.txz', or '.tzst', which are recompressed to '.tlz'.
.PP .PP
Exit status is 0 if all the compressed files were successfully recompressed Exit status is 0 if all the compressed files were successfully recompressed
(if needed), compared, and deleted (if requested). Non\-zero otherwise. (if needed), compared, and deleted (if requested). Non\-zero otherwise.
@ -79,13 +81,28 @@ set compressor and options for lzip format
.TP .TP
\fB\-\-xz=\fR<command> \fB\-\-xz=\fR<command>
set compressor and options for xz format set compressor and options for xz format
.TP
\fB\-\-zst=\fR<command>
set compressor and options for zstd format
.SH "REPORTING BUGS" .SH "REPORTING BUGS"
Report bugs to zutils\-bug@nongnu.org Report bugs to zutils\-bug@nongnu.org
.br .br
Zutils home page: http://www.nongnu.org/zutils/zutils.html Zutils home page: http://www.nongnu.org/zutils/zutils.html
.SH COPYRIGHT .SH COPYRIGHT
Copyright \(co 2021 Antonio Diaz Diaz. Copyright \(co 2022 Antonio Diaz Diaz.
License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html> License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>
.br .br
This is free software: you are free to change and redistribute it. This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. There is NO WARRANTY, to the extent permitted by law.
.SH "SEE ALSO"
The full documentation for
.B zupdate
is maintained as a Texinfo manual. If the
.B info
and
.B zupdate
programs are properly installed at your site, the command
.IP
.B info zutils
.PP
should give you access to the complete manual.

View file

@ -1,6 +1,6 @@
This is zutils.info, produced by makeinfo version 4.13+ from zutils.texi. This is zutils.info, produced by makeinfo version 4.13+ from zutils.texi.
INFO-DIR-SECTION Data Compression INFO-DIR-SECTION Compression
START-INFO-DIR-ENTRY START-INFO-DIR-ENTRY
* Zutils: (zutils). Utilities dealing with compressed files * Zutils: (zutils). Utilities dealing with compressed files
END-INFO-DIR-ENTRY END-INFO-DIR-ENTRY
@ -11,7 +11,7 @@ File: zutils.info, Node: Top, Next: Introduction, Up: (dir)
Zutils Manual Zutils Manual
************* *************
This manual is for Zutils (version 1.10, 5 January 2021). This manual is for Zutils (version 1.11, 25 January 2022).
* Menu: * Menu:
@ -28,7 +28,7 @@ This manual is for Zutils (version 1.10, 5 January 2021).
* Concept index:: Index of concepts * Concept index:: Index of concepts
Copyright (C) 2009-2021 Antonio Diaz Diaz. Copyright (C) 2009-2022 Antonio Diaz Diaz.
This manual is free documentation: you have unlimited permission to copy, This manual is free documentation: you have unlimited permission to copy,
distribute, and modify it. distribute, and modify it.
@ -50,7 +50,7 @@ programs. In particular the option '--recursive' is very efficient in those
utilities supporting it. utilities supporting it.
The utilities provided are zcat, zcmp, zdiff, zgrep, ztest, and zupdate. The utilities provided are zcat, zcmp, zdiff, zgrep, ztest, and zupdate.
The formats supported are bzip2, gzip, lzip, and xz. The formats supported are bzip2, gzip, lzip, xz, and zstd.
Zutils uses external compressors. The compressor to be used for each format Zutils uses external compressors. The compressor to be used for each format
is configurable at runtime. is configurable at runtime.
@ -60,12 +60,14 @@ to gzip's znew.
NOTE: Bzip2 and lzip provide well-defined values of exit status, which NOTE: Bzip2 and lzip provide well-defined values of exit status, which
makes them safe to use with zutils. Gzip and xz may return ambiguous warning makes them safe to use with zutils. Gzip and xz may return ambiguous warning
values, making them less reliable back ends for zutils. *Note values, making them less reliable back ends for zutils. Zstd currently does
not even document its exit status in its man page. *Note
compressor-requirements::. compressor-requirements::.
FORMAT NOTE 1: The option '--format' allows the processing of a subset FORMAT NOTE 1: The option '--format' allows the processing of a subset
of formats in recursive mode and when trying compressed file names: of formats in recursive mode and when trying compressed file names. For
'zgrep foo -r --format=bz2,lz somedir somefile.tar'. example, use the following command to search for the string 'foo' in gzip
and lzip files only: 'zgrep foo -r --format=gz,lz somedir somefile.tar'.
FORMAT NOTE 2: If the option '--force-format' is given, the files are FORMAT NOTE 2: If the option '--force-format' is given, the files are
passed to the corresponding decompressor without verifying their format, passed to the corresponding decompressor without verifying their format,
@ -110,12 +112,14 @@ here. *Note Argument syntax: (arg_parser)Argument syntax.
'-V' '-V'
'--version' '--version'
Print the version number on the standard output and exit. This version Print the version number on the standard output and exit. This version
number should be included in all bug reports. number should be included in all bug reports. In verbose mode, zdiff
and zgrep print also the version of the diff or grep program used
respectively.
'-M FORMAT_LIST' '-M FORMAT_LIST'
'--format=FORMAT_LIST' '--format=FORMAT_LIST'
Process only the formats listed in the comma-separated FORMAT_LIST. Process only the formats listed in the comma-separated FORMAT_LIST.
Valid formats are 'bz2', 'gz', 'lz', 'xz', and 'un' for Valid formats are 'bz2', 'gz', 'lz', 'xz', 'zst', and 'un' for
'uncompressed', meaning "any file name without a known extension". 'uncompressed', meaning "any file name without a known extension".
This option excludes files based on extension, instead of format, This option excludes files based on extension, instead of format,
because it is more efficient. The exclusion only applies to names because it is more efficient. The exclusion only applies to names
@ -130,6 +134,7 @@ here. *Note Argument syntax: (arg_parser)Argument syntax.
gz enables .gz .tgz gz enables .gz .tgz
lz enables .lz .tlz lz enables .lz .tlz
xz enables .xz .txz xz enables .xz .txz
zst enables .zst .tzst
un enables any other file name un enables any other file name
'-N' '-N'
@ -140,17 +145,18 @@ here. *Note Argument syntax: (arg_parser)Argument syntax.
'--gz=COMMAND' '--gz=COMMAND'
'--lz=COMMAND' '--lz=COMMAND'
'--xz=COMMAND' '--xz=COMMAND'
'--zst=COMMAND'
Set program to be used as (de)compressor for the corresponding format. Set program to be used as (de)compressor for the corresponding format.
COMMAND may include arguments. For example '--lz='plzip --threads=2''. COMMAND may include arguments. For example '--lz='plzip --threads=2''.
The program set with '--lz' is used for both compression and The program set with '--lz' is used for both compression and
decompression. The other three are used only for decompression. The decompression. The others are used only for decompression. The name of
name of the program can't begin with '-'. These options override the the program can't begin with '-'. These options override the values
values set in 'zutilsrc'. The compression program used must meet three set in 'zutilsrc'. The compression program used must meet three
requirements: requirements:
1. When called with the option '-d', it must read compressed data 1. When called with the option '-d' and without file names, it must
from the standard input and produce decompressed data on the read compressed data from the standard input and produce
standard output. decompressed data on the standard output.
2. If the option '-q' is passed to zutils, the compression program 2. If the option '-q' is passed to zutils, the compression program
must also accept it. must also accept it.
@ -181,7 +187,7 @@ is fairly obvious (and there are further instructions in it):
2. Each non-comment line defines the command to be used for the 2. Each non-comment line defines the command to be used for the
corresponding format, with the syntax: corresponding format, with the syntax:
<format> = <compressor> [options] <format> = <compressor> [options]
where <format> is one of 'bz2', 'gz', 'lz', or 'xz'. where <format> is one of 'bz2', 'gz', 'lz', 'xz', or 'zst'.
 
File: zutils.info, Node: Zcat, Next: Zcmp, Prev: The zutilsrc file, Up: Top File: zutils.info, Node: Zcat, Next: Zcmp, Prev: The zutilsrc file, Up: Top
@ -235,9 +241,10 @@ Exit status is 0 if no errors occurred, 1 otherwise.
'-O FORMAT' '-O FORMAT'
'--force-format=FORMAT' '--force-format=FORMAT'
Force the compressed format given. Valid values for FORMAT are 'bz2', Force the compressed format given. Valid values for FORMAT are 'bz2',
'gz', 'lz', and 'xz'. If this option is used, the files are passed to 'gz', 'lz', 'xz', and 'zst'. If this option is used, the files are
the corresponding decompressor without verifying their format, and the passed to the corresponding decompressor without verifying their
exact file name must be given. Other names won't be tried. format, and the exact file name must be given. Other names won't be
tried.
'-q' '-q'
'--quiet' '--quiet'
@ -301,7 +308,7 @@ following:
removed). removed).
- If FILE1 is uncompressed, compares it with the decompressed contents - If FILE1 is uncompressed, compares it with the decompressed contents
of FILE1.[lz|bz2|gz|xz] (the first one that is found). of FILE1.[lz|bz2|gz|zst|xz] (the first one that is found).
An exit status of 0 means no differences were found, 1 means some An exit status of 0 means no differences were found, 1 means some
differences were found, and 2 means trouble. differences were found, and 2 means trouble.
@ -336,11 +343,11 @@ differences were found, and 2 means trouble.
'--force-format=[FORMAT1][,FORMAT2]' '--force-format=[FORMAT1][,FORMAT2]'
Force the compressed formats given. Any of FORMAT1 or FORMAT2 may be Force the compressed formats given. Any of FORMAT1 or FORMAT2 may be
omitted and the corresponding format will be automatically detected. omitted and the corresponding format will be automatically detected.
Valid values for FORMAT are 'bz2', 'gz', 'lz', and 'xz'. If at least Valid values for FORMAT are 'bz2', 'gz', 'lz', 'xz', and 'zst'. If at
one format is specified with this option, the file is passed to the least one format is specified with this option, the file is passed to
corresponding decompressor without verifying its format, and the exact the corresponding decompressor without verifying its format, and the
file names of both FILE1 and FILE2 must be given. Other names won't be exact file names of both FILE1 and FILE2 must be given. Other names
tried. won't be tried.
'-q' '-q'
'-s' '-s'
@ -376,7 +383,7 @@ following:
removed). removed).
- If FILE1 is uncompressed, compares it with the decompressed contents - If FILE1 is uncompressed, compares it with the decompressed contents
of FILE1.[lz|bz2|gz|xz] (the first one that is found). of FILE1.[lz|bz2|gz|zst|xz] (the first one that is found).
An exit status of 0 means no differences were found, 1 means some An exit status of 0 means no differences were found, 1 means some
differences were found, and 2 means trouble. differences were found, and 2 means trouble.
@ -419,11 +426,11 @@ program used supports them):
'--force-format=[FORMAT1][,FORMAT2]' '--force-format=[FORMAT1][,FORMAT2]'
Force the compressed formats given. Any of FORMAT1 or FORMAT2 may be Force the compressed formats given. Any of FORMAT1 or FORMAT2 may be
omitted and the corresponding format will be automatically detected. omitted and the corresponding format will be automatically detected.
Valid values for FORMAT are 'bz2', 'gz', 'lz', and 'xz'. If at least Valid values for FORMAT are 'bz2', 'gz', 'lz', 'xz', and 'zst'. If at
one format is specified with this option, the file is passed to the least one format is specified with this option, the file is passed to
corresponding decompressor without verifying its format, and the exact the corresponding decompressor without verifying its format, and the
file names of both FILE1 and FILE2 must be given. Other names won't be exact file names of both FILE1 and FILE2 must be given. Other names
tried. won't be tried.
'-p' '-p'
'--show-c-function' '--show-c-function'
@ -452,6 +459,11 @@ program used supports them):
'--unified=N' '--unified=N'
Same as -u but use N lines of context. Same as -u but use N lines of context.
'-v'
'--verbose'
When specified before '--version', print the version of the diff
program used.
'-w' '-w'
'--ignore-all-space' '--ignore-all-space'
Ignore all white space. Ignore all white space.
@ -576,9 +588,10 @@ program used supports them):
'-O FORMAT' '-O FORMAT'
'--force-format=FORMAT' '--force-format=FORMAT'
Force the compressed format given. Valid values for FORMAT are 'bz2', Force the compressed format given. Valid values for FORMAT are 'bz2',
'gz', 'lz', and 'xz'. If this option is used, the files are passed to 'gz', 'lz', 'xz', and 'zst'. If this option is used, the files are
the corresponding decompressor without verifying their format, and the passed to the corresponding decompressor without verifying their
exact file name must be given. Other names won't be tried. format, and the exact file name must be given. Other names won't be
tried.
'-q' '-q'
'--quiet' '--quiet'
@ -605,7 +618,8 @@ program used supports them):
Select non-matching lines. Select non-matching lines.
'--verbose' '--verbose'
Verbose mode. Show error messages. Verbose mode. Show error messages. When specified before '--version',
print the version of the grep program used.
'-w' '-w'
'--word-regexp' '--word-regexp'
@ -634,6 +648,10 @@ test when testing multiple files.
If no files are specified, recursive searches examine the current working If no files are specified, recursive searches examine the current working
directory, and nonrecursive searches read standard input. directory, and nonrecursive searches read standard input.
Bzip2, gzip, and lzip are the primary formats. Xz and zstd are optional.
If the decompressor for the xz or zstd formats is not found, the
corresponding files are ignored.
Note that error detection in the xz format is broken. First, some xz Note that error detection in the xz format is broken. First, some xz
files lack integrity information. Second, not all xz decompressors can files lack integrity information. Second, not all xz decompressors can
verify the integrity of all xz files. Third, section 2.1.1.2 'Stream Flags' verify the integrity of all xz files. Third, section 2.1.1.2 'Stream Flags'
@ -654,11 +672,12 @@ compressed file is corrupt or invalid.
'-O FORMAT' '-O FORMAT'
'--force-format=FORMAT' '--force-format=FORMAT'
Force the compressed format given. Valid values for FORMAT are 'bz2', Force the compressed format given. Valid values for FORMAT are 'bz2',
'gz', 'lz', and 'xz'. If this option is used, the files are passed to 'gz', 'lz', 'xz', and 'zst'. If this option is used, the files are
the corresponding decompressor without verifying their format, and any passed to the corresponding decompressor without verifying their
files in a format that the decompressor can't understand will fail. format, and any files in a format that the decompressor can't
For example, '--force-format=gz' can test gzipped (.gz) and compress'd understand will fail. For example, '--force-format=gz' can test
(.Z) files if the compressor used is GNU gzip. gzipped (.gz) and compress'd (.Z) files if the compressor used is GNU
gzip.
'-q' '-q'
'--quiet' '--quiet'
@ -687,14 +706,14 @@ File: zutils.info, Node: Zupdate, Next: Problems, Prev: Ztest, Up: Top
9 Zupdate 9 Zupdate
********* *********
zupdate recompresses files from bzip2, gzip, and xz formats to lzip format. zupdate recompresses files from bzip2, gzip, xz, and zstd formats to lzip
Each original is compared with the new file and then deleted. Only regular format. Each original is compared with the new file and then deleted. Only
files with standard file name extensions are recompressed, other files are regular files with standard file name extensions are recompressed, other
ignored. Compressed files are decompressed and then recompressed on the fly; files are ignored. Compressed files are decompressed and then recompressed
no temporary files are created. If an error happens while recompressing a on the fly; no temporary files are created. If an error happens while
file, zupdate exits immediately without recompressing the rest of the files. recompressing a file, zupdate exits immediately without recompressing the
The lzip format is chosen as destination because it is the most appropriate rest of the files. The lzip format is chosen as destination because it is
for long-term data archiving. the most appropriate for long-term data archiving.
If no files are specified, recursive searches examine the current working If no files are specified, recursive searches examine the current working
directory, and nonrecursive searches do nothing. directory, and nonrecursive searches do nothing.
@ -706,17 +725,26 @@ the original file is not deleted. The operation of zupdate is meant to be
safe and not cause any data loss. Therefore, existing lzip compressed files safe and not cause any data loss. Therefore, existing lzip compressed files
are never overwritten nor deleted. are never overwritten nor deleted.
Recompressing files from a read-only file system to another place can be
done by first linking the files from the destination directory and then
compressing the links: 'ln -s /src/foo.gz . && zupdate foo.gz'
Combining the options '--force' and '--keep', as in Combining the options '--force' and '--keep', as in
'zupdate -f -k *.gz', verifies that there are no differences between each 'zupdate -f -k *.gz', verifies that there are no differences between each
pair of files in a multiformat set of files. pair of files in a multiformat set of files.
The names of the original files must have one of the following The names of the original files must have one of the following
extensions: extensions:
'.bz2', '.gz', or '.xz', which are recompressed to '.lz'; '.bz2', '.gz', '.xz', or '.zst', which are recompressed to '.lz';
'.tbz', '.tbz2', '.tgz', or '.txz', which are recompressed to '.tlz'. '.tbz', '.tbz2', '.tgz', '.txz', or '.tzst', which are recompressed to
'.tlz'.
Keeping the combined extensions ('.tgz' -> '.tlz') may be useful when Keeping the combined extensions ('.tgz' -> '.tlz') may be useful when
recompressing Slackware packages, for example. recompressing Slackware packages, for example.
Bzip2, gzip, and lzip are the primary formats. Xz and zstd are optional.
If the decompressor for the xz or zstd formats is not found, the
corresponding files are ignored.
Recompressing a file is much like copying or moving it; therefore zupdate Recompressing a file is much like copying or moving it; therefore zupdate
preserves the access and modification dates, permissions, and, when preserves the access and modification dates, permissions, and, when
possible, ownership of the file just as 'cp -p' does. (If the user ID or possible, ownership of the file just as 'cp -p' does. (If the user ID or
@ -816,19 +844,19 @@ Concept index
 
Tag Table: Tag Table:
Node: Top222 Node: Top217
Node: Introduction1151 Node: Introduction1147
Node: Common options3776 Node: Common options3947
Ref: compressor-requirements5847 Ref: compressor-requirements6181
Node: The zutilsrc file6219 Node: The zutilsrc file6576
Node: Zcat7180 Node: Zcat7544
Node: Zcmp9743 Node: Zcmp10119
Node: Zdiff12233 Node: Zdiff12620
Node: Zgrep14973 Node: Zgrep15478
Node: Ztest19218 Node: Ztest19819
Node: Zupdate21725 Node: Zupdate22513
Node: Problems25409 Node: Problems26607
Node: Concept index25943 Node: Concept index27141
 
End Tag Table End Tag Table

View file

@ -6,10 +6,10 @@
@finalout @finalout
@c %**end of header @c %**end of header
@set UPDATED 5 January 2021 @set UPDATED 25 January 2022
@set VERSION 1.10 @set VERSION 1.11
@dircategory Data Compression @dircategory Compression
@direntry @direntry
* Zutils: (zutils). Utilities dealing with compressed files * Zutils: (zutils). Utilities dealing with compressed files
@end direntry @end direntry
@ -50,7 +50,7 @@ This manual is for Zutils (version @value{VERSION}, @value{UPDATED}).
@end menu @end menu
@sp 1 @sp 1
Copyright @copyright{} 2009-2021 Antonio Diaz Diaz. Copyright @copyright{} 2009-2022 Antonio Diaz Diaz.
This manual is free documentation: you have unlimited permission to copy, This manual is free documentation: you have unlimited permission to copy,
distribute, and modify it. distribute, and modify it.
@ -74,7 +74,7 @@ those utilities supporting it.
@noindent @noindent
The utilities provided are zcat, zcmp, zdiff, zgrep, ztest, and zupdate.@* The utilities provided are zcat, zcmp, zdiff, zgrep, ztest, and zupdate.@*
The formats supported are bzip2, gzip, lzip, and xz.@* The formats supported are bzip2, gzip, lzip, xz, and zstd.@*
Zutils uses external compressors. The compressor to be used for each format Zutils uses external compressors. The compressor to be used for each format
is configurable at runtime. is configurable at runtime.
@ -84,12 +84,15 @@ gzip's znew.
NOTE: Bzip2 and lzip provide well-defined values of exit status, which makes NOTE: Bzip2 and lzip provide well-defined values of exit status, which makes
them safe to use with zutils. Gzip and xz may return ambiguous warning them safe to use with zutils. Gzip and xz may return ambiguous warning
values, making them less reliable back ends for zutils. values, making them less reliable back ends for zutils. Zstd currently does
not even document its exit status in its man page.
@xref{compressor-requirements}. @xref{compressor-requirements}.
FORMAT NOTE 1: The option @samp{--format} allows the processing of a subset FORMAT NOTE 1: The option @samp{--format} allows the processing of a subset
of formats in recursive mode and when trying compressed file names: of formats in recursive mode and when trying compressed file names. For
@w{@samp{zgrep foo -r --format=bz2,lz somedir somefile.tar}}. example, use the following command to search for the string @samp{foo} in
gzip and lzip files only:
@w{@samp{zgrep foo -r --format=gz,lz somedir somefile.tar}}.
FORMAT NOTE 2: If the option @samp{--force-format} is given, the files are FORMAT NOTE 2: If the option @samp{--force-format} is given, the files are
passed to the corresponding decompressor without verifying their format, passed to the corresponding decompressor without verifying their format,
@ -141,17 +144,19 @@ only supports the @samp{--help} form of this option.
@itemx --version @itemx --version
Print the version number on the standard output and exit. Print the version number on the standard output and exit.
This version number should be included in all bug reports. This version number should be included in all bug reports.
In verbose mode, zdiff and zgrep print also the version of the diff or grep
program used respectively.
@item -M @var{format_list} @item -M @var{format_list}
@itemx --format=@var{format_list} @itemx --format=@var{format_list}
Process only the formats listed in the comma-separated Process only the formats listed in the comma-separated @var{format_list}.
@var{format_list}. Valid formats are @samp{bz2}, @samp{gz}, @samp{lz}, Valid formats are @samp{bz2}, @samp{gz}, @samp{lz}, @samp{xz}, @samp{zst},
@samp{xz}, and @samp{un} for @samp{uncompressed}, meaning "any file name and @samp{un} for @samp{uncompressed}, meaning "any file name without a
without a known extension". This option excludes files based on known extension". This option excludes files based on extension, instead of
extension, instead of format, because it is more efficient. The format, because it is more efficient. The exclusion only applies to names
exclusion only applies to names generated automatically (for example generated automatically (for example when adding extensions to a file name
when adding extensions to a file name or when operating recursively on or when operating recursively on directories). Files given in the command
directories). Files given in the command line are always processed. line are always processed.
Each format in @var{format_list} enables file names with the following Each format in @var{format_list} enables file names with the following
extensions: extensions:
@ -161,6 +166,7 @@ extensions:
@item gz @tab enables @tab .gz .tgz @item gz @tab enables @tab .gz .tgz
@item lz @tab enables @tab .lz .tlz @item lz @tab enables @tab .lz .tlz
@item xz @tab enables @tab .xz .txz @item xz @tab enables @tab .xz .txz
@item zst @tab enables @tab .zst .tzst
@item un @tab enables @tab any other file name @item un @tab enables @tab any other file name
@end multitable @end multitable
@ -172,19 +178,21 @@ Don't read the runtime configuration file @samp{zutilsrc}.
@itemx --gz=@var{command} @itemx --gz=@var{command}
@itemx --lz=@var{command} @itemx --lz=@var{command}
@itemx --xz=@var{command} @itemx --xz=@var{command}
@itemx --zst=@var{command}
Set program to be used as (de)compressor for the corresponding format. Set program to be used as (de)compressor for the corresponding format.
@var{command} may include arguments. For example @var{command} may include arguments. For example
@w{@samp{--lz='plzip --threads=2'}}. The program set with @samp{--lz} is @w{@samp{--lz='plzip --threads=2'}}. The program set with @samp{--lz} is
used for both compression and decompression. The other three are used only used for both compression and decompression. The others are used only for
for decompression. The name of the program can't begin with @samp{-}. These decompression. The name of the program can't begin with @samp{-}. These
options override the values set in @file{zutilsrc}. The compression program options override the values set in @file{zutilsrc}. The compression program
used must meet three requirements: used must meet three requirements:
@anchor{compressor-requirements} @anchor{compressor-requirements}
@enumerate @enumerate
@item @item
When called with the option @samp{-d}, it must read compressed data from When called with the option @samp{-d} and without file names, it must read
the standard input and produce decompressed data on the standard output. compressed data from the standard input and produce decompressed data on the
standard output.
@item @item
If the option @samp{-q} is passed to zutils, the compression program must If the option @samp{-q} is passed to zutils, the compression program must
also accept it. also accept it.
@ -220,7 +228,8 @@ format, with the syntax:
@example @example
<format> = <compressor> [options] <format> = <compressor> [options]
@end example @end example
where <format> is one of @samp{bz2}, @samp{gz}, @samp{lz}, or @samp{xz}. where <format> is one of @samp{bz2}, @samp{gz}, @samp{lz}, @samp{xz}, or
@samp{zst}.
@end enumerate @end enumerate
@ -278,10 +287,10 @@ Number all output lines, starting with 1. The line count is unlimited.
@item -O @var{format} @item -O @var{format}
@itemx --force-format=@var{format} @itemx --force-format=@var{format}
Force the compressed format given. Valid values for @var{format} are Force the compressed format given. Valid values for @var{format} are
@samp{bz2}, @samp{gz}, @samp{lz}, and @samp{xz}. If this option is used, @samp{bz2}, @samp{gz}, @samp{lz}, @samp{xz}, and @samp{zst}. If this option
the files are passed to the corresponding decompressor without verifying is used, the files are passed to the corresponding decompressor without
their format, and the exact file name must be given. Other names won't verifying their format, and the exact file name must be given. Other names
be tried. won't be tried.
@item -q @item -q
@itemx --quiet @itemx --quiet
@ -350,7 +359,7 @@ the corresponding uncompressed file (the name of @var{file1} with the
extension removed). extension removed).
@item @item
If @var{file1} is uncompressed, compares it with the decompressed If @var{file1} is uncompressed, compares it with the decompressed
contents of @var{file1}.[lz|bz2|gz|xz] (the first one that is found). contents of @var{file1}.[lz|bz2|gz|zst|xz] (the first one that is found).
@end itemize @end itemize
@noindent @noindent
@ -387,13 +396,13 @@ Compare at most @var{count} input bytes.
@item -O [@var{format1}][,@var{format2}] @item -O [@var{format1}][,@var{format2}]
@itemx --force-format=[@var{format1}][,@var{format2}] @itemx --force-format=[@var{format1}][,@var{format2}]
Force the compressed formats given. Any of @var{format1} or Force the compressed formats given. Any of @var{format1} or @var{format2}
@var{format2} may be omitted and the corresponding format will be may be omitted and the corresponding format will be automatically detected.
automatically detected. Valid values for @var{format} are @samp{bz2}, Valid values for @var{format} are @samp{bz2}, @samp{gz}, @samp{lz},
@samp{gz}, @samp{lz}, and @samp{xz}. If at least one format is specified @samp{xz}, and @samp{zst}. If at least one format is specified with this
with this option, the file is passed to the corresponding decompressor option, the file is passed to the corresponding decompressor without
without verifying its format, and the exact file names of both verifying its format, and the exact file names of both @var{file1} and
@var{file1} and @var{file2} must be given. Other names won't be tried. @var{file2} must be given. Other names won't be tried.
@item -q @item -q
@itemx -s @itemx -s
@ -434,7 +443,7 @@ the corresponding uncompressed file (the name of @var{file1} with the
extension removed). extension removed).
@item @item
If @var{file1} is uncompressed, compares it with the decompressed If @var{file1} is uncompressed, compares it with the decompressed
contents of @var{file1}.[lz|bz2|gz|xz] (the first one that is found). contents of @var{file1}.[lz|bz2|gz|zst|xz] (the first one that is found).
@end itemize @end itemize
@noindent @noindent
@ -478,13 +487,13 @@ Ignore case differences in file contents.
@item -O [@var{format1}][,@var{format2}] @item -O [@var{format1}][,@var{format2}]
@itemx --force-format=[@var{format1}][,@var{format2}] @itemx --force-format=[@var{format1}][,@var{format2}]
Force the compressed formats given. Any of @var{format1} or Force the compressed formats given. Any of @var{format1} or @var{format2}
@var{format2} may be omitted and the corresponding format will be may be omitted and the corresponding format will be automatically detected.
automatically detected. Valid values for @var{format} are @samp{bz2}, Valid values for @var{format} are @samp{bz2}, @samp{gz}, @samp{lz},
@samp{gz}, @samp{lz}, and @samp{xz}. If at least one format is specified @samp{xz}, and @samp{zst}. If at least one format is specified with this
with this option, the file is passed to the corresponding decompressor option, the file is passed to the corresponding decompressor without
without verifying its format, and the exact file names of both verifying its format, and the exact file names of both @var{file1} and
@var{file1} and @var{file2} must be given. Other names won't be tried. @var{file2} must be given. Other names won't be tried.
@item -p @item -p
@itemx --show-c-function @itemx --show-c-function
@ -513,6 +522,11 @@ Use the unified output format.
@itemx --unified=@var{n} @itemx --unified=@var{n}
Same as -u but use @var{n} lines of context. Same as -u but use @var{n} lines of context.
@item -v
@itemx --verbose
When specified before @samp{--version}, print the version of the diff
program used.
@item -w @item -w
@itemx --ignore-all-space @itemx --ignore-all-space
Ignore all white space. Ignore all white space.
@ -644,10 +658,10 @@ Show only the part of matching lines that actually matches @var{pattern}.
@item -O @var{format} @item -O @var{format}
@itemx --force-format=@var{format} @itemx --force-format=@var{format}
Force the compressed format given. Valid values for @var{format} are Force the compressed format given. Valid values for @var{format} are
@samp{bz2}, @samp{gz}, @samp{lz}, and @samp{xz}. If this option is used, @samp{bz2}, @samp{gz}, @samp{lz}, @samp{xz}, and @samp{zst}. If this option
the files are passed to the corresponding decompressor without verifying is used, the files are passed to the corresponding decompressor without
their format, and the exact file name must be given. Other names won't verifying their format, and the exact file name must be given. Other names
be tried. won't be tried.
@item -q @item -q
@itemx --quiet @itemx --quiet
@ -674,7 +688,8 @@ Suppress error messages about nonexistent or unreadable files.
Select non-matching lines. Select non-matching lines.
@item --verbose @item --verbose
Verbose mode. Show error messages. Verbose mode. Show error messages. When specified before @samp{--version},
print the version of the grep program used.
@item -w @item -w
@itemx --word-regexp @itemx --word-regexp
@ -703,6 +718,10 @@ test when testing multiple files.
If no files are specified, recursive searches examine the current working If no files are specified, recursive searches examine the current working
directory, and nonrecursive searches read standard input. directory, and nonrecursive searches read standard input.
Bzip2, gzip, and lzip are the primary formats. Xz and zstd are optional. If
the decompressor for the xz or zstd formats is not found, the corresponding
files are ignored.
Note that error detection in the xz format is broken. First, some xz Note that error detection in the xz format is broken. First, some xz
files lack integrity information. Second, not all xz decompressors can files lack integrity information. Second, not all xz decompressors can
@uref{http://www.nongnu.org/lzip/xz_inadequate.html#fragmented,,verify the integrity} @uref{http://www.nongnu.org/lzip/xz_inadequate.html#fragmented,,verify the integrity}
@ -730,11 +749,11 @@ ztest supports the following options:
@item -O @var{format} @item -O @var{format}
@itemx --force-format=@var{format} @itemx --force-format=@var{format}
Force the compressed format given. Valid values for @var{format} are Force the compressed format given. Valid values for @var{format} are
@samp{bz2}, @samp{gz}, @samp{lz}, and @samp{xz}. If this option is used, the @samp{bz2}, @samp{gz}, @samp{lz}, @samp{xz}, and @samp{zst}. If this option
files are passed to the corresponding decompressor without verifying their is used, the files are passed to the corresponding decompressor without
format, and any files in a format that the decompressor can't understand verifying their format, and any files in a format that the decompressor
will fail. For example, @samp{--force-format=gz} can test gzipped (.gz) and can't understand will fail. For example, @samp{--force-format=gz} can test
compress'd (.Z) files if the compressor used is GNU gzip. gzipped (.gz) and compress'd (.Z) files if the compressor used is GNU gzip.
@item -q @item -q
@itemx --quiet @itemx --quiet
@ -763,14 +782,14 @@ Further -v's increase the verbosity level.
@chapter Zupdate @chapter Zupdate
@cindex zupdate @cindex zupdate
zupdate recompresses files from bzip2, gzip, and xz formats to lzip format. zupdate recompresses files from bzip2, gzip, xz, and zstd formats to lzip
Each original is compared with the new file and then deleted. Only regular format. Each original is compared with the new file and then deleted. Only
files with standard file name extensions are recompressed, other files are regular files with standard file name extensions are recompressed, other
ignored. Compressed files are decompressed and then recompressed on the fly; files are ignored. Compressed files are decompressed and then recompressed
no temporary files are created. If an error happens while recompressing a on the fly; no temporary files are created. If an error happens while
file, zupdate exits immediately without recompressing the rest of the files. recompressing a file, zupdate exits immediately without recompressing the
The lzip format is chosen as destination because it is the most appropriate rest of the files. The lzip format is chosen as destination because it is
for long-term data archiving. the most appropriate for long-term data archiving.
If no files are specified, recursive searches examine the current working If no files are specified, recursive searches examine the current working
directory, and nonrecursive searches do nothing. directory, and nonrecursive searches do nothing.
@ -782,21 +801,29 @@ and the original file is not deleted. The operation of zupdate is meant
to be safe and not cause any data loss. Therefore, existing lzip to be safe and not cause any data loss. Therefore, existing lzip
compressed files are never overwritten nor deleted. compressed files are never overwritten nor deleted.
Recompressing files from a read-only file system to another place can be
done by first linking the files from the destination directory and then
compressing the links: @w{@samp{ln -s /src/foo.gz . && zupdate foo.gz}}
Combining the options @samp{--force} and @samp{--keep}, as in Combining the options @samp{--force} and @samp{--keep}, as in
@w{@samp{zupdate -f -k *.gz}}, verifies that there are no differences @w{@samp{zupdate -f -k *.gz}}, verifies that there are no differences
between each pair of files in a multiformat set of files. between each pair of files in a multiformat set of files.
The names of the original files must have one of the following extensions:@* The names of the original files must have one of the following extensions:@*
@samp{.bz2}, @samp{.gz}, or @samp{.xz}, which are recompressed to @samp{.bz2}, @samp{.gz}, @samp{.xz}, or @samp{.zst}, which are recompressed
@samp{.lz};@* to @samp{.lz};@*
@samp{.tbz}, @samp{.tbz2}, @samp{.tgz}, or @samp{.txz}, which are @samp{.tbz}, @samp{.tbz2}, @samp{.tgz}, @samp{.txz}, or @samp{.tzst}, which
recompressed to @samp{.tlz}.@* are recompressed to @samp{.tlz}.@*
Keeping the combined extensions (@samp{.tgz} --> @samp{.tlz}) may be useful Keeping the combined extensions (@samp{.tgz} --> @samp{.tlz}) may be useful
when recompressing Slackware packages, for example. when recompressing Slackware packages, for example.
Bzip2, gzip, and lzip are the primary formats. Xz and zstd are optional. If
the decompressor for the xz or zstd formats is not found, the corresponding
files are ignored.
Recompressing a file is much like copying or moving it; therefore zupdate Recompressing a file is much like copying or moving it; therefore zupdate
preserves the access and modification dates, permissions, and, when preserves the access and modification dates, permissions, and, when
possible, ownership of the file just as @samp{cp -p} does. (If the user ID or possible, ownership of the file just as @w{@samp{cp -p}} does. (If the user ID or
the group ID can't be duplicated, the file permission bits S_ISUID and the group ID can't be duplicated, the file permission bits S_ISUID and
S_ISGID are cleared). S_ISGID are cleared).

47
rc.cc
View file

@ -1,5 +1,5 @@
/* Zutils - Utilities dealing with compressed files /* Zutils - Utilities dealing with compressed files
Copyright (C) 2009-2021 Antonio Diaz Diaz. Copyright (C) 2009-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -37,12 +37,12 @@ int verbosity = 0;
namespace { namespace {
const char * const config_file_name = "zutilsrc"; const char * const config_file_name = "zutilsrc";
const char * const program_year = "2021"; const char * const program_year = "2022";
std::string compressor_names[num_formats] = std::string compressor_names[num_formats] =
{ "bzip2", "gzip", "lzip", "xz" }; // default compressor names { "bzip2", "gzip", "lzip", "xz", "zstd" }; // default compressor names
// args to compressors read from rc or from options --[bglx]z, maybe empty // args to compressors read from rc or from options like --lz, maybe empty
std::vector< std::string > compressor_args[num_formats]; std::vector< std::string > compressor_args[num_formats];
// vector of enabled formats plus [num_formats] for uncompressed. // vector of enabled formats plus [num_formats] for uncompressed.
@ -60,6 +60,8 @@ const struct { const char * from; const char * to; int format_index; }
{ ".tlz", ".tar", fmt_lz }, { ".tlz", ".tar", fmt_lz },
{ ".xz", "", fmt_xz }, { ".xz", "", fmt_xz },
{ ".txz", ".tar", fmt_xz }, { ".txz", ".tar", fmt_xz },
{ ".zst", "", fmt_zst },
{ ".tzst", ".tar", fmt_zst },
{ 0, 0, -1 } }; { 0, 0, -1 } };
@ -83,7 +85,7 @@ int my_fgetc( FILE * const f )
} }
// Returns the parity of escapes (backslashes) at the end of a string. // Return the parity of escapes (backslashes) at the end of a string.
bool trailing_escape( const std::string & s ) bool trailing_escape( const std::string & s )
{ {
unsigned len = s.size(); unsigned len = s.size();
@ -95,7 +97,7 @@ bool trailing_escape( const std::string & s )
/* Read a line discarding comments, leading whitespace, and blank lines. /* Read a line discarding comments, leading whitespace, and blank lines.
Escaped newlines are discarded. Escaped newlines are discarded.
Returns the empty string if at EOF. Return the empty string if at EOF.
*/ */
const std::string & my_fgets( FILE * const f, int & linenum ) const std::string & my_fgets( FILE * const f, int & linenum )
{ {
@ -186,7 +188,7 @@ bool parse_rc_line( const std::string & line,
} }
// Returns 0 for success, 1 for file not found, 2 for syntax error. // Return 0 if success, 1 if file not found, 2 if syntax error.
int process_rcfile( const std::string & name ) int process_rcfile( const std::string & name )
{ {
FILE * const f = std::fopen( name.c_str(), "r" ); FILE * const f = std::fopen( name.c_str(), "r" );
@ -217,7 +219,7 @@ bool enabled_format( const int format_index )
} }
void parse_format_list( const std::string & arg ) void parse_format_list( const std::string & arg, const char * const pn )
{ {
const std::string un( "uncompressed" ); const std::string un( "uncompressed" );
bool error = arg.empty(); bool error = arg.empty();
@ -236,17 +238,22 @@ void parse_format_list( const std::string & arg )
{ error = true; break; } { error = true; break; }
enabled_formats[format_index] = true; enabled_formats[format_index] = true;
} }
if( error ) if( !error ) return;
{ show_error( "Bad argument for option '--format'." ); std::exit( 1 ); } if( verbosity >= 0 )
std::fprintf( stderr, "%s: Bad argument in option '%s'.\n",
program_name, pn );
std::exit( 1 );
} }
int parse_format_type( const std::string & arg ) int parse_format_type( const std::string & arg, const char * const pn )
{ {
for( int i = 0; i < num_formats; ++i ) for( int i = 0; i < num_formats; ++i )
if( arg == format_names[i] ) if( arg == format_names[i] )
return i; return i;
show_error( "Bad argument for option '--force-format'." ); if( verbosity >= 0 )
std::fprintf( stderr, "%s: Bad argument in option '%s'.\n",
program_name, pn );
std::exit( 1 ); std::exit( 1 );
} }
@ -322,10 +329,24 @@ void show_help_addr()
} }
void show_version() void show_version( const char * const command )
{ {
std::printf( "%s (zutils) %s\n", program_name, PROGVERSION ); std::printf( "%s (zutils) %s\n", program_name, PROGVERSION );
std::printf( "Copyright (C) %s Antonio Diaz Diaz.\n", program_year ); std::printf( "Copyright (C) %s Antonio Diaz Diaz.\n", program_year );
if( command && verbosity >= 1 )
{
FILE * const f = popen( command, "r" );
if( f )
{
char command_version[1024] = { 0 };
const int rd = std::fread( command_version, 1, sizeof command_version, f );
pclose( f );
int i = 0;
while( i + 1 < rd && command_version[i] != '\n' ) ++i;
command_version[i] = 0;
if( command_version[0] ) std::printf( "Using %s\n", command_version );
}
}
std::printf( "License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>\n" std::printf( "License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>\n"
"This is free software: you are free to change and redistribute it.\n" "This is free software: you are free to change and redistribute it.\n"
"There is NO WARRANTY, to the extent permitted by law.\n" ); "There is NO WARRANTY, to the extent permitted by law.\n" );

19
rc.h
View file

@ -1,5 +1,5 @@
/* Zutils - Utilities dealing with compressed files /* Zutils - Utilities dealing with compressed files
Copyright (C) 2009-2021 Antonio Diaz Diaz. Copyright (C) 2009-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -15,16 +15,17 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
enum { fmt_bz2, fmt_gz, fmt_lz, fmt_xz, num_formats }; // format_index enum { fmt_bz2, fmt_gz, fmt_lz, fmt_xz, fmt_zst, num_formats }; // format_index
const char * const format_names[num_formats] = { "bz2", "gz", "lz", "xz" }; const char * const format_names[num_formats] =
{ "bz2", "gz", "lz", "xz", "zst" };
const char * const simple_extensions[num_formats] = const char * const simple_extensions[num_formats] =
{ ".bz2", ".gz", ".lz", ".xz" }; { ".bz2", ".gz", ".lz", ".xz", ".zst" };
const int format_order[num_formats] = const int format_order[num_formats] =
{ fmt_lz, fmt_bz2, fmt_gz, fmt_xz }; // search order { fmt_lz, fmt_bz2, fmt_gz, fmt_zst, fmt_xz }; // search order
bool enabled_format( const int format_index ); bool enabled_format( const int format_index );
void parse_format_list( const std::string & arg ); void parse_format_list( const std::string & arg, const char * const pn );
int parse_format_type( const std::string & arg ); int parse_format_type( const std::string & arg, const char * const pn );
int extension_index( const std::string & name ); // -1 if unknown int extension_index( const std::string & name ); // -1 if unknown
int extension_format( const int eindex ); // -1 if uncompressed int extension_format( const int eindex ); // -1 if uncompressed
@ -46,7 +47,7 @@ const char * get_compressor_name( const int format_index );
const std::vector< std::string > & get_compressor_args( const int format_index ); const std::vector< std::string > & get_compressor_args( const int format_index );
void show_help_addr(); void show_help_addr();
void show_version(); void show_version( const char * const command = 0 );
void show_error( const char * const msg, const int errcode = 0, void show_error( const char * const msg, const int errcode = 0,
const bool help = false ); const bool help = false );
void show_file_error( const char * const filename, const char * const msg, void show_file_error( const char * const filename, const char * const msg,
@ -56,7 +57,7 @@ void show_close_error( const char * const prog_name = "data feeder" );
void show_exec_error( const char * const prog_name ); void show_exec_error( const char * const prog_name );
void show_fork_error( const char * const prog_name ); void show_fork_error( const char * const prog_name );
// Returns exit status of child process 'pid', or 'eretval' in case of error. // Return exit status of child process 'pid', or 'eretval' in case of error.
// //
int wait_for_child( const pid_t pid, const char * const name, int wait_for_child( const pid_t pid, const char * const name,
const int eretval = 2, const bool isgzxz = false ); const int eretval = 2, const bool isgzxz = false );

View file

@ -1,5 +1,5 @@
/* Zutils - Utilities dealing with compressed files /* Zutils - Utilities dealing with compressed files
Copyright (C) 2009-2021 Antonio Diaz Diaz. Copyright (C) 2009-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -15,7 +15,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/* Returns true if full_name is a regular file with an enabled extension /* Return true if full_name is a regular file with an enabled extension
or (a link to) a directory. */ or (a link to) a directory. */
bool test_full_name( const std::string & full_name, const struct stat * stp, bool test_full_name( const std::string & full_name, const struct stat * stp,
const bool follow ) const bool follow )
@ -46,9 +46,9 @@ bool test_full_name( const std::string & full_name, const struct stat * stp,
} }
/* Returns in input_filename the next filename, or "." for stdin. /* Return in input_filename the next file name, or "." for stdin.
("." was chosen because it is not a valid filename). ("." was chosen instead of "-" because "." is not a valid file name).
Sets 'error' to true if a directory fails to open. */ Set 'error' to true if a directory fails to open. */
bool next_filename( std::list< std::string > & filenames, bool next_filename( std::list< std::string > & filenames,
std::string & input_filename, bool & error, std::string & input_filename, bool & error,
const int recursive, const bool ignore_stdin = false, const int recursive, const bool ignore_stdin = false,

View file

@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# check script for Zutils - Utilities dealing with compressed files # check script for Zutils - Utilities dealing with compressed files
# Copyright (C) 2009-2021 Antonio Diaz Diaz. # Copyright (C) 2009-2022 Antonio Diaz Diaz.
# #
# This script is free software: you have unlimited permission # This script is free software: you have unlimited permission
# to copy, distribute, and modify it. # to copy, distribute, and modify it.
@ -194,8 +194,7 @@ done
"${ZCMP}" -Nq --force-format=lz in.lz "${ZCMP}" -Nq --force-format=lz in.lz
[ $? = 2 ] || test_failed $LINENO [ $? = 2 ] || test_failed $LINENO
"${ZCMP}" -Nq --force-format=lz in.gz in.lz "${ZCMP}" -Nq --force-format=lz in.gz in.lz
r=$? [ $? = 2 ] || test_failed $LINENO
{ [ $r = 1 ] || [ $r = 2 ] ; } || test_failed $LINENO
"${ZCMP}" -Nq -i 100BB in in "${ZCMP}" -Nq -i 100BB in in
[ $? = 2 ] || test_failed $LINENO [ $? = 2 ] || test_failed $LINENO
"${ZCMP}" -Nq -i 100BB:100 in in "${ZCMP}" -Nq -i 100BB:100 in in
@ -206,6 +205,8 @@ r=$?
[ $? = 2 ] || test_failed $LINENO [ $? = 2 ] || test_failed $LINENO
"${ZCMP}" -N -q -n 100BB in in "${ZCMP}" -N -q -n 100BB in in
[ $? = 2 ] || test_failed $LINENO [ $? = 2 ] || test_failed $LINENO
"${ZCMP}" -Nq --gz=bad-gzip in.gz in.lz
[ $? = 2 ] || test_failed $LINENO
"${ZCMP}" -N --bad-option in in 2> /dev/null "${ZCMP}" -N --bad-option in in 2> /dev/null
[ $? = 2 ] || test_failed $LINENO [ $? = 2 ] || test_failed $LINENO
@ -255,11 +256,12 @@ done
[ $? = 2 ] || test_failed $LINENO [ $? = 2 ] || test_failed $LINENO
"${ZDIFF}" -N --bz2='-bzip2' in.bz2 2> /dev/null "${ZDIFF}" -N --bz2='-bzip2' in.bz2 2> /dev/null
[ $? = 2 ] || test_failed $LINENO [ $? = 2 ] || test_failed $LINENO
"${ZDIFF}" -Nq --force-format=bz2 in.bz2 2> /dev/null "${ZDIFF}" -N --brief --force-format=bz2 in.bz2 2> /dev/null
[ $? = 2 ] || test_failed $LINENO
"${ZDIFF}" -N --brief --force-format=,lz in.lz in.bz2 > /dev/null 2>&1
[ $? = 2 ] || test_failed $LINENO
"${ZDIFF}" -N --brief --gz=bad-gzip in.gz in.lz > /dev/null 2>&1
[ $? = 2 ] || test_failed $LINENO [ $? = 2 ] || test_failed $LINENO
"${ZDIFF}" -N -q --force-format=,lz in.lz in.bz2 > /dev/null 2>&1
r=$?
{ [ $r = 1 ] || [ $r = 2 ] ; } || test_failed $LINENO
"${ZDIFF}" -N --bad-option 2> /dev/null "${ZDIFF}" -N --bad-option 2> /dev/null
[ $? = 2 ] || test_failed $LINENO [ $? = 2 ] || test_failed $LINENO

22
zcat.cc
View file

@ -1,5 +1,5 @@
/* Zcat - decompress and concatenate files to standard output /* Zcat - decompress and concatenate files to standard output
Copyright (C) 2010-2021 Antonio Diaz Diaz. Copyright (C) 2010-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -31,7 +31,7 @@
#include <stdint.h> #include <stdint.h>
#include <unistd.h> #include <unistd.h>
#include <sys/stat.h> #include <sys/stat.h>
#if defined(__MSVCRT__) || defined(__OS2__) #if defined __MSVCRT__ || defined __OS2__
#include <io.h> #include <io.h>
#endif #endif
@ -102,7 +102,7 @@ void show_help()
"same compressed format.\n" "same compressed format.\n"
"\nIf no files are specified, recursive searches examine the current\n" "\nIf no files are specified, recursive searches examine the current\n"
"working directory, and nonrecursive searches read standard input.\n" "working directory, and nonrecursive searches read standard input.\n"
"\nThe formats supported are bzip2, gzip, lzip, and xz.\n" "\nThe formats supported are bzip2, gzip, lzip, xz, and zstd.\n"
"\nUsage: zcat [options] [files]\n" "\nUsage: zcat [options] [files]\n"
"\nExit status is 0 if no errors occurred, 1 otherwise.\n" "\nExit status is 0 if no errors occurred, 1 otherwise.\n"
"\nOptions:\n" "\nOptions:\n"
@ -115,7 +115,7 @@ void show_help()
" -M, --format=<list> process only the formats in <list>\n" " -M, --format=<list> process only the formats in <list>\n"
" -n, --number number all output lines\n" " -n, --number number all output lines\n"
" -N, --no-rcfile don't read runtime configuration file\n" " -N, --no-rcfile don't read runtime configuration file\n"
" -O, --force-format=<fmt> force the format given (bz2, gz, lz, xz)\n" " -O, --force-format=<fmt> force the format given (bz2, gz, lz, xz, zst)\n"
" -q, --quiet suppress all messages\n" " -q, --quiet suppress all messages\n"
" -r, --recursive operate recursively on directories\n" " -r, --recursive operate recursively on directories\n"
" -R, --dereference-recursive recursively follow symbolic links\n" " -R, --dereference-recursive recursively follow symbolic links\n"
@ -127,7 +127,8 @@ void show_help()
" --bz2=<command> set compressor and options for bzip2 format\n" " --bz2=<command> set compressor and options for bzip2 format\n"
" --gz=<command> set compressor and options for gzip format\n" " --gz=<command> set compressor and options for gzip format\n"
" --lz=<command> set compressor and options for lzip format\n" " --lz=<command> set compressor and options for lzip format\n"
" --xz=<command> set compressor and options for xz format\n" ); " --xz=<command> set compressor and options for xz format\n"
" --zst=<command> set compressor and options for zstd format\n" );
show_help_addr(); show_help_addr();
} }
@ -256,7 +257,7 @@ bool cat( int infd, const int format_index, const std::string & input_filename,
int main( const int argc, const char * const argv[] ) int main( const int argc, const char * const argv[] )
{ {
enum { verbose_opt = 256, bz2_opt, gz_opt, lz_opt, xz_opt }; enum { verbose_opt = 256, bz2_opt, gz_opt, lz_opt, xz_opt, zst_opt };
int format_index = -1; int format_index = -1;
int recursive = 0; // 1 = '-r', 2 = '-R' int recursive = 0; // 1 = '-r', 2 = '-R'
std::list< std::string > filenames; std::list< std::string > filenames;
@ -293,6 +294,7 @@ int main( const int argc, const char * const argv[] )
{ gz_opt, "gz", Arg_parser::yes }, { gz_opt, "gz", Arg_parser::yes },
{ lz_opt, "lz", Arg_parser::yes }, { lz_opt, "lz", Arg_parser::yes },
{ xz_opt, "xz", Arg_parser::yes }, { xz_opt, "xz", Arg_parser::yes },
{ zst_opt, "zst", Arg_parser::yes },
{ 0, 0, Arg_parser::no } }; { 0, 0, Arg_parser::no } };
const Arg_parser parser( argc, argv, options ); const Arg_parser parser( argc, argv, options );
@ -306,6 +308,7 @@ int main( const int argc, const char * const argv[] )
{ {
const int code = parser.code( argind ); const int code = parser.code( argind );
if( !code ) break; // no more options if( !code ) break; // no more options
const char * const pn = parser.parsed_name( argind ).c_str();
const std::string & arg = parser.argument( argind ); const std::string & arg = parser.argument( argind );
switch( code ) switch( code )
{ {
@ -321,11 +324,11 @@ int main( const int argc, const char * const argv[] )
case 'h': show_help(); return 0; case 'h': show_help(); return 0;
case 'l': break; case 'l': break;
case 'L': break; case 'L': break;
case 'M': parse_format_list( arg ); break; case 'M': parse_format_list( arg, pn ); break;
case 'n': if( cat_options.number_lines == 0 ) case 'n': if( cat_options.number_lines == 0 )
{ cat_options.number_lines = 2; } break; { cat_options.number_lines = 2; } break;
case 'N': break; case 'N': break;
case 'O': format_index = parse_format_type( arg ); break; case 'O': format_index = parse_format_type( arg, pn ); break;
case 'q': verbosity = -1; break; case 'q': verbosity = -1; break;
case 'r': recursive = 1; break; case 'r': recursive = 1; break;
case 'R': recursive = 2; break; case 'R': recursive = 2; break;
@ -339,11 +342,12 @@ int main( const int argc, const char * const argv[] )
case gz_opt: parse_compressor( arg, fmt_gz, 1 ); break; case gz_opt: parse_compressor( arg, fmt_gz, 1 ); break;
case lz_opt: parse_compressor( arg, fmt_lz, 1 ); break; case lz_opt: parse_compressor( arg, fmt_lz, 1 ); break;
case xz_opt: parse_compressor( arg, fmt_xz, 1 ); break; case xz_opt: parse_compressor( arg, fmt_xz, 1 ); break;
case zst_opt: parse_compressor( arg, fmt_zst, 1 ); break;
default : internal_error( "uncaught option." ); default : internal_error( "uncaught option." );
} }
} // end process options } // end process options
#if defined(__MSVCRT__) || defined(__OS2__) #if defined __MSVCRT__ || defined __OS2__
setmode( STDIN_FILENO, O_BINARY ); setmode( STDIN_FILENO, O_BINARY );
setmode( STDOUT_FILENO, O_BINARY ); setmode( STDOUT_FILENO, O_BINARY );
#endif #endif

View file

@ -1,5 +1,5 @@
/* Common code for zcat and zgrep /* Common code for zcat and zgrep
Copyright (C) 2010-2021 Antonio Diaz Diaz. Copyright (C) 2010-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by

111
zcmp.cc
View file

@ -1,5 +1,5 @@
/* Zcmp - decompress and compare two files byte by byte /* Zcmp - decompress and compare two files byte by byte
Copyright (C) 2010-2021 Antonio Diaz Diaz. Copyright (C) 2010-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -31,7 +31,7 @@
#include <stdint.h> #include <stdint.h>
#include <unistd.h> #include <unistd.h>
#include <sys/stat.h> #include <sys/stat.h>
#if defined(__MSVCRT__) || defined(__OS2__) #if defined __MSVCRT__ || defined __OS2__
#include <io.h> #include <io.h>
#endif #endif
@ -55,7 +55,7 @@ void show_help()
"starting with 1. A hyphen '-' used as a file argument means standard input.\n" "starting with 1. A hyphen '-' used as a file argument means standard input.\n"
"If any file given is compressed, its decompressed content is used. Compressed\n" "If any file given is compressed, its decompressed content is used. Compressed\n"
"files are decompressed on the fly; no temporary files are created.\n" "files are decompressed on the fly; no temporary files are created.\n"
"\nThe formats supported are bzip2, gzip, lzip, and xz.\n" "\nThe formats supported are bzip2, gzip, lzip, xz, and zstd.\n"
"\nUsage: zcmp [options] file1 [file2]\n" "\nUsage: zcmp [options] file1 [file2]\n"
"\nzcmp compares file1 to file2. The standard input is used only if file1 or\n" "\nzcmp compares file1 to file2. The standard input is used only if file1 or\n"
"file2 refers to standard input. If file2 is omitted zcmp tries the\n" "file2 refers to standard input. If file2 is omitted zcmp tries the\n"
@ -64,7 +64,7 @@ void show_help()
" the corresponding uncompressed file (the name of file1 with the\n" " the corresponding uncompressed file (the name of file1 with the\n"
" extension removed).\n" " extension removed).\n"
"\n - If file1 is uncompressed, compares it with the decompressed\n" "\n - If file1 is uncompressed, compares it with the decompressed\n"
" contents of file1.[lz|bz2|gz|xz] (the first one that is found).\n" " contents of file1.[lz|bz2|gz|zst|xz] (the first one that is found).\n"
"\nExit status is 0 if inputs are identical, 1 if different, 2 if trouble.\n" "\nExit status is 0 if inputs are identical, 1 if different, 2 if trouble.\n"
"\nOptions:\n" "\nOptions:\n"
" -h, --help display this help and exit\n" " -h, --help display this help and exit\n"
@ -75,7 +75,7 @@ void show_help()
" -M, --format=<list> process only the formats in <list>\n" " -M, --format=<list> process only the formats in <list>\n"
" -n, --bytes=<n> compare at most <n> bytes\n" " -n, --bytes=<n> compare at most <n> bytes\n"
" -N, --no-rcfile don't read runtime configuration file\n" " -N, --no-rcfile don't read runtime configuration file\n"
" -O, --force-format=[<f1>][,<f2>] force the formats given (bz2, gz, lz, xz)\n" " -O, --force-format=[<f1>][,<f2>] force the formats given (bz2,gz,lz,xz,zst)\n"
" -q, --quiet suppress all messages\n" " -q, --quiet suppress all messages\n"
" -s, --silent (same as --quiet)\n" " -s, --silent (same as --quiet)\n"
" -v, --verbose verbose mode (same as --list)\n" " -v, --verbose verbose mode (same as --list)\n"
@ -83,22 +83,60 @@ void show_help()
" --gz=<command> set compressor and options for gzip format\n" " --gz=<command> set compressor and options for gzip format\n"
" --lz=<command> set compressor and options for lzip format\n" " --lz=<command> set compressor and options for lzip format\n"
" --xz=<command> set compressor and options for xz format\n" " --xz=<command> set compressor and options for xz format\n"
" --zst=<command> set compressor and options for zstd format\n"
"\nNumbers may be followed by a multiplier: k = kB = 10^3 = 1000,\n" "\nNumbers may be followed by a multiplier: k = kB = 10^3 = 1000,\n"
"Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...\n" ); "Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...\n" );
show_help_addr(); show_help_addr();
} }
long long getnum( const char * const ptr, const char ** const tailp = 0, // separate large numbers >= 100_000 in groups of 3 digits using '_'
const char * format_num3( long long num )
{
const char * const si_prefix = "kMGTPEZY";
const char * const binary_prefix = "KMGTPEZY";
enum { buffers = 8, bufsize = 4 * sizeof (long long) };
static char buffer[buffers][bufsize]; // circle of static buffers for printf
static int current = 0;
char * const buf = buffer[current++]; current %= buffers;
char * p = buf + bufsize - 1; // fill the buffer backwards
*p = 0; // terminator
const bool negative = num < 0;
if( negative ) num = -num;
char prefix = 0; // try binary first, then si
for( int i = 0; i < 8 && num >= 1024 && num % 1024 == 0; ++i )
{ num /= 1024; prefix = binary_prefix[i]; }
if( prefix ) *(--p) = 'i';
else
for( int i = 0; i < 8 && num >= 1000 && num % 1000 == 0; ++i )
{ num /= 1000; prefix = si_prefix[i]; }
if( prefix ) *(--p) = prefix;
const bool split = num >= 100000;
for( int i = 0; ; )
{
*(--p) = num % 10 + '0'; num /= 10; if( num == 0 ) break;
if( split && ++i >= 3 ) { i = 0; *(--p) = '_'; }
}
if( negative ) *(--p) = '-';
return p;
}
long long getnum( const char * const arg, const char * const option_name,
const char ** const tailp = 0,
const long long llimit = 0, const long long llimit = 0,
const long long ulimit = LLONG_MAX ) const long long ulimit = LLONG_MAX )
{ {
char * tail; char * tail;
errno = 0; errno = 0;
long long result = strtoll( ptr, &tail, 0 ); long long result = strtoll( arg, &tail, 0 );
if( tail == ptr ) if( tail == arg )
{ {
show_error( "Bad or missing numerical argument.", 0, true ); if( verbosity >= 0 )
std::fprintf( stderr, "%s: Bad or missing numerical argument in "
"option '%s'.\n", program_name, option_name );
std::exit( 2 ); std::exit( 2 );
} }
if( result < 0 ) errno = ERANGE; if( result < 0 ) errno = ERANGE;
@ -126,7 +164,9 @@ long long getnum( const char * const ptr, const char ** const tailp = 0,
} }
if( exponent < 0 ) if( exponent < 0 )
{ {
show_error( "Bad multiplier in numerical argument.", 0, true ); if( verbosity >= 0 )
std::fprintf( stderr, "%s: Bad multiplier in numerical argument of "
"option '%s'.\n", program_name, option_name );
std::exit( 2 ); std::exit( 2 );
} }
for( int i = 0; i < exponent; ++i ) for( int i = 0; i < exponent; ++i )
@ -138,7 +178,10 @@ long long getnum( const char * const ptr, const char ** const tailp = 0,
if( !errno && ( result < llimit || result > ulimit ) ) errno = ERANGE; if( !errno && ( result < llimit || result > ulimit ) ) errno = ERANGE;
if( errno ) if( errno )
{ {
show_error( "Numerical argument out of limits." ); if( verbosity >= 0 )
std::fprintf( stderr, "%s: Numerical argument out of limits [%s,%s] "
"in option '%s'.\n", program_name, format_num3( llimit ),
format_num3( ulimit ), option_name );
std::exit( 2 ); std::exit( 2 );
} }
if( tailp ) *tailp = tail; if( tailp ) *tailp = tail;
@ -146,16 +189,19 @@ long long getnum( const char * const ptr, const char ** const tailp = 0,
} }
void parse_ignore_initial( const char * const arg, long long ignore_initial[2] ) void parse_ignore_initial( const char * const arg, const char * const pn,
long long ignore_initial[2] )
{ {
const char * tail; const char * tail;
ignore_initial[0] = getnum( arg, &tail ); ignore_initial[0] = getnum( arg, pn, &tail );
if( *tail == ':' || *tail == ',' ) if( *tail == ':' || *tail == ',' )
ignore_initial[1] = getnum( ++tail ); ignore_initial[1] = getnum( ++tail, pn );
else if( *tail == 0 ) ignore_initial[1] = ignore_initial[0]; else if( *tail == 0 ) ignore_initial[1] = ignore_initial[0];
else else
{ {
show_error( "Bad separator in argument of '--ignore-initial'", 0, true ); if( verbosity >= 0 )
std::fprintf( stderr, "%s: Bad separator in argument of option '%s'.\n",
program_name, pn );
std::exit( 2 ); std::exit( 2 );
} }
} }
@ -165,7 +211,7 @@ bool skip_ignore_initial( const long long ignore_initial, const int infd )
{ {
if( ignore_initial > 0 ) if( ignore_initial > 0 )
{ {
enum { buffer_size = 4096 }; const int buffer_size = 4096;
long long rest = ignore_initial; long long rest = ignore_initial;
uint8_t buffer[buffer_size]; uint8_t buffer[buffer_size];
while( rest > 0 ) while( rest > 0 )
@ -218,7 +264,8 @@ int block_compare( const uint8_t * const buffer0,
int cmp( const long long max_size, const int infd[2], int cmp( const long long max_size, const int infd[2],
const std::string filenames[2], const bool print_bytes ) const std::string filenames[2], bool finished[2],
const bool print_bytes )
{ {
const int buffer_size = 4096; const int buffer_size = 4096;
unsigned long long byte_number = 1; unsigned long long byte_number = 1;
@ -241,11 +288,11 @@ int cmp( const long long max_size, const int infd[2],
{ {
rd[i] = readblock( infd[i], buffer[i], size ); rd[i] = readblock( infd[i], buffer[i], size );
if( rd[i] != size && errno ) if( rd[i] != size && errno )
{ { show_file_error( filenames[i].c_str(), "Read error", errno );
show_file_error( filenames[i].c_str(), "Read error", errno ); return 2; }
return 2;
}
} }
for( int i = 0; i < 2; ++i )
if( rd[i] < size ) finished[i] = true;
const int min_rd = std::min( rd[0], rd[1] ); const int min_rd = std::min( rd[0], rd[1] );
buffer0[min_rd] = 0; // sentinels for the block compare buffer0[min_rd] = 0; // sentinels for the block compare
@ -319,7 +366,7 @@ int cmp( const long long max_size, const int infd[2],
int main( const int argc, const char * const argv[] ) int main( const int argc, const char * const argv[] )
{ {
enum { bz2_opt = 256, gz_opt, lz_opt, xz_opt }; enum { bz2_opt = 256, gz_opt, lz_opt, xz_opt, zst_opt };
// number of initial bytes ignored for each file // number of initial bytes ignored for each file
long long ignore_initial[2] = { 0, 0 }; long long ignore_initial[2] = { 0, 0 };
long long max_size = -1; // < 0 means unlimited size long long max_size = -1; // < 0 means unlimited size
@ -346,6 +393,7 @@ int main( const int argc, const char * const argv[] )
{ gz_opt, "gz", Arg_parser::yes }, { gz_opt, "gz", Arg_parser::yes },
{ lz_opt, "lz", Arg_parser::yes }, { lz_opt, "lz", Arg_parser::yes },
{ xz_opt, "xz", Arg_parser::yes }, { xz_opt, "xz", Arg_parser::yes },
{ zst_opt, "zst", Arg_parser::yes },
{ 0, 0, Arg_parser::no } }; { 0, 0, Arg_parser::no } };
const Arg_parser parser( argc, argv, options ); const Arg_parser parser( argc, argv, options );
@ -359,17 +407,18 @@ int main( const int argc, const char * const argv[] )
{ {
const int code = parser.code( argind ); const int code = parser.code( argind );
if( !code ) break; // no more options if( !code ) break; // no more options
const char * const pn = parser.parsed_name( argind ).c_str();
const std::string & arg = parser.argument( argind ); const std::string & arg = parser.argument( argind );
switch( code ) switch( code )
{ {
case 'b': print_bytes = true; break; case 'b': print_bytes = true; break;
case 'h': show_help(); return 0; case 'h': show_help(); return 0;
case 'i': parse_ignore_initial( arg.c_str(), ignore_initial ); break; case 'i': parse_ignore_initial( arg.c_str(), pn, ignore_initial ); break;
case 'l': verbosity = 1; break; case 'l': verbosity = 1; break;
case 'M': parse_format_list( arg ); break; case 'M': parse_format_list( arg, pn ); break;
case 'n': max_size = getnum( arg.c_str() ); break; case 'n': max_size = getnum( arg.c_str(), pn ); break;
case 'N': break; case 'N': break;
case 'O': parse_format_types2( arg, format_types ); break; case 'O': parse_format_types2( arg, pn, format_types ); break;
case 'q': case 'q':
case 's': verbosity = -1; break; case 's': verbosity = -1; break;
case 'v': verbosity = 1; break; case 'v': verbosity = 1; break;
@ -378,18 +427,19 @@ int main( const int argc, const char * const argv[] )
case gz_opt: parse_compressor( arg, fmt_gz ); break; case gz_opt: parse_compressor( arg, fmt_gz ); break;
case lz_opt: parse_compressor( arg, fmt_lz ); break; case lz_opt: parse_compressor( arg, fmt_lz ); break;
case xz_opt: parse_compressor( arg, fmt_xz ); break; case xz_opt: parse_compressor( arg, fmt_xz ); break;
case zst_opt: parse_compressor( arg, fmt_zst ); break;
default : internal_error( "uncaught option." ); default : internal_error( "uncaught option." );
} }
} // end process options } // end process options
#if defined(__MSVCRT__) || defined(__OS2__) #if defined __MSVCRT__ || defined __OS2__
setmode( STDIN_FILENO, O_BINARY ); setmode( STDIN_FILENO, O_BINARY );
setmode( STDOUT_FILENO, O_BINARY ); setmode( STDOUT_FILENO, O_BINARY );
#endif #endif
if( argind >= parser.arguments() ) if( argind >= parser.arguments() )
{ show_error( "No files given.", 0, true ); return 2; } { show_error( "No files given.", 0, true ); return 2; }
if( argind + 2 < parser.arguments() ) if( parser.arguments() - argind > 2 )
{ show_error( "Too many files.", 0, true ); return 2; } { show_error( "Too many files.", 0, true ); return 2; }
const int files = parser.arguments() - argind; const int files = parser.arguments() - argind;
@ -446,10 +496,11 @@ int main( const int argc, const char * const argv[] )
return 2; return 2;
} }
int retval = cmp( max_size, infd, filenames, print_bytes ); bool finished[2] = { false, false };
int retval = cmp( max_size, infd, filenames, finished, print_bytes );
for( int i = 0; i < 2; ++i ) for( int i = 0; i < 2; ++i )
if( !good_status( children[i], retval == 0 && max_size < 0 ) ) retval = 2; if( !good_status( children[i], finished[i] ) ) retval = 2;
for( int i = 0; i < 2; ++i ) for( int i = 0; i < 2; ++i )
{ {

View file

@ -1,5 +1,5 @@
/* Common code for zcmp and zdiff /* Common code for zcmp and zdiff
Copyright (C) 2010-2021 Antonio Diaz Diaz. Copyright (C) 2010-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -50,13 +50,14 @@ int open_other_instream( std::string & name )
} }
void parse_format_types2( const std::string & arg, int format_types[2] ) void parse_format_types2( const std::string & arg, const char * const pn,
int format_types[2] )
{ {
const unsigned i = std::min( arg.find( ',' ), arg.size() ); const unsigned i = std::min( arg.find( ',' ), arg.size() );
if( i > 0 ) format_types[0] = parse_format_type( arg.substr( 0, i ) ); if( i > 0 ) format_types[0] = parse_format_type( arg.substr( 0, i ), pn );
else format_types[0] = -1; else format_types[0] = -1;
if( i + 1 < arg.size() ) format_types[1] = if( i + 1 < arg.size() ) format_types[1] =
parse_format_type( arg.substr( i + 1 ) ); parse_format_type( arg.substr( i + 1 ), pn );
else format_types[1] = -1; else format_types[1] = -1;
} }

View file

@ -1,5 +1,5 @@
/* Zdiff - decompress and compare two files line by line /* Zdiff - decompress and compare two files line by line
Copyright (C) 2010-2021 Antonio Diaz Diaz. Copyright (C) 2010-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -31,7 +31,7 @@
#include <stdint.h> #include <stdint.h>
#include <unistd.h> #include <unistd.h>
#include <sys/stat.h> #include <sys/stat.h>
#if defined(__MSVCRT__) || defined(__OS2__) #if defined __MSVCRT__ || defined __OS2__
#include <io.h> #include <io.h>
#endif #endif
@ -39,7 +39,6 @@
#include "rc.h" #include "rc.h"
#include "zutils.h" #include "zutils.h"
// 'verbosity' is always 0 in zdiff; no --verbose or --quiet available.
namespace { namespace {
@ -54,7 +53,8 @@ void show_help()
"input. If any file given is compressed, its decompressed content is used.\n" "input. If any file given is compressed, its decompressed content is used.\n"
"zdiff is a front end to the program diff and has the limitation that messages\n" "zdiff is a front end to the program diff and has the limitation that messages\n"
"from diff refer to temporary file names instead of those specified.\n" "from diff refer to temporary file names instead of those specified.\n"
"\nThe formats supported are bzip2, gzip, lzip, and xz.\n" "\n'zdiff -v -V' prints the version of the diff program used.\n"
"\nThe formats supported are bzip2, gzip, lzip, xz, and zstd.\n"
"\nUsage: zdiff [options] file1 [file2]\n" "\nUsage: zdiff [options] file1 [file2]\n"
"\nzdiff compares file1 to file2. The standard input is used only if file1 or\n" "\nzdiff compares file1 to file2. The standard input is used only if file1 or\n"
"file2 refers to standard input. If file2 is omitted zdiff tries the\n" "file2 refers to standard input. If file2 is omitted zdiff tries the\n"
@ -63,7 +63,7 @@ void show_help()
" the corresponding uncompressed file (the name of file1 with the\n" " the corresponding uncompressed file (the name of file1 with the\n"
" extension removed).\n" " extension removed).\n"
"\n - If file1 is uncompressed, compares it with the decompressed\n" "\n - If file1 is uncompressed, compares it with the decompressed\n"
" contents of file1.[lz|bz2|gz|xz] (the first one that is found).\n" " contents of file1.[lz|bz2|gz|zst|xz] (the first one that is found).\n"
"\nExit status is 0 if inputs are identical, 1 if different, 2 if trouble.\n" "\nExit status is 0 if inputs are identical, 1 if different, 2 if trouble.\n"
"Some options only work if the diff program used supports them.\n" "Some options only work if the diff program used supports them.\n"
"\nOptions:\n" "\nOptions:\n"
@ -79,7 +79,7 @@ void show_help()
" -i, --ignore-case ignore case differences in file contents\n" " -i, --ignore-case ignore case differences in file contents\n"
" -M, --format=<list> process only the formats in <list>\n" " -M, --format=<list> process only the formats in <list>\n"
" -N, --no-rcfile don't read runtime configuration file\n" " -N, --no-rcfile don't read runtime configuration file\n"
" -O, --force-format=[<f1>][,<f2>] force the formats given (bz2, gz, lz, xz)\n" " -O, --force-format=[<f1>][,<f2>] force the formats given (bz2,gz,lz,xz,zst)\n"
" -p, --show-c-function show which C function each change is in\n" " -p, --show-c-function show which C function each change is in\n"
" -q, --brief output only whether files differ\n" " -q, --brief output only whether files differ\n"
" -s, --report-identical-files report when two files are identical\n" " -s, --report-identical-files report when two files are identical\n"
@ -87,13 +87,15 @@ void show_help()
" -T, --initial-tab make tabs line up by prepending a tab\n" " -T, --initial-tab make tabs line up by prepending a tab\n"
" -u use the unified output format\n" " -u use the unified output format\n"
" -U, --unified=<n> same as -u but use <n> lines of context\n" " -U, --unified=<n> same as -u but use <n> lines of context\n"
" -v, --verbose verbose mode (for --version)\n"
" -w, --ignore-all-space ignore all white space\n" " -w, --ignore-all-space ignore all white space\n"
" -W, --width=<n> output at most <n> print columns\n" " -W, --width=<n> output at most <n> print columns\n"
" -y, --side-by-side output in two columns\n" " -y, --side-by-side output in two columns\n"
" --bz2=<command> set compressor and options for bzip2 format\n" " --bz2=<command> set compressor and options for bzip2 format\n"
" --gz=<command> set compressor and options for gzip format\n" " --gz=<command> set compressor and options for gzip format\n"
" --lz=<command> set compressor and options for lzip format\n" " --lz=<command> set compressor and options for lzip format\n"
" --xz=<command> set compressor and options for xz format\n" ); " --xz=<command> set compressor and options for xz format\n"
" --zst=<command> set compressor and options for zstd format\n" );
show_help_addr(); show_help_addr();
} }
@ -264,7 +266,7 @@ void set_signals()
int main( const int argc, const char * const argv[] ) int main( const int argc, const char * const argv[] )
{ {
enum { bz2_opt = 256, gz_opt, lz_opt, xz_opt }; enum { bz2_opt = 256, gz_opt, lz_opt, xz_opt, zst_opt };
std::vector< const char * > diff_args; // args to diff, maybe empty std::vector< const char * > diff_args; // args to diff, maybe empty
int format_types[2] = { -1, -1 }; int format_types[2] = { -1, -1 };
program_name = "zdiff"; program_name = "zdiff";
@ -291,6 +293,7 @@ int main( const int argc, const char * const argv[] )
{ 'T', "initial-tab", Arg_parser::no }, { 'T', "initial-tab", Arg_parser::no },
{ 'u', 0, Arg_parser::no }, { 'u', 0, Arg_parser::no },
{ 'U', "unified", Arg_parser::yes }, { 'U', "unified", Arg_parser::yes },
{ 'v', "verbose", Arg_parser::no },
{ 'V', "version", Arg_parser::no }, { 'V', "version", Arg_parser::no },
{ 'w', "ignore-all-space", Arg_parser::no }, { 'w', "ignore-all-space", Arg_parser::no },
{ 'W', "width", Arg_parser::yes }, { 'W', "width", Arg_parser::yes },
@ -299,6 +302,7 @@ int main( const int argc, const char * const argv[] )
{ gz_opt, "gz", Arg_parser::yes }, { gz_opt, "gz", Arg_parser::yes },
{ lz_opt, "lz", Arg_parser::yes }, { lz_opt, "lz", Arg_parser::yes },
{ xz_opt, "xz", Arg_parser::yes }, { xz_opt, "xz", Arg_parser::yes },
{ zst_opt, "zst", Arg_parser::yes },
{ 0, 0, Arg_parser::no } }; { 0, 0, Arg_parser::no } };
const Arg_parser parser( argc, argv, options ); const Arg_parser parser( argc, argv, options );
@ -312,6 +316,7 @@ int main( const int argc, const char * const argv[] )
{ {
const int code = parser.code( argind ); const int code = parser.code( argind );
if( !code ) break; // no more options if( !code ) break; // no more options
const char * const pn = parser.parsed_name( argind ).c_str();
const std::string & arg = parser.argument( argind ); const std::string & arg = parser.argument( argind );
switch( code ) switch( code )
{ {
@ -325,9 +330,9 @@ int main( const int argc, const char * const argv[] )
case 'E': diff_args.push_back( "-E" ); break; case 'E': diff_args.push_back( "-E" ); break;
case 'h': show_help(); return 0; case 'h': show_help(); return 0;
case 'i': diff_args.push_back( "-i" ); break; case 'i': diff_args.push_back( "-i" ); break;
case 'M': parse_format_list( arg ); break; case 'M': parse_format_list( arg, pn ); break;
case 'N': break; case 'N': break;
case 'O': parse_format_types2( arg, format_types ); break; case 'O': parse_format_types2( arg, pn, format_types ); break;
case 'p': diff_args.push_back( "-p" ); break; case 'p': diff_args.push_back( "-p" ); break;
case 'q': diff_args.push_back( "-q" ); break; case 'q': diff_args.push_back( "-q" ); break;
case 's': diff_args.push_back( "-s" ); break; case 's': diff_args.push_back( "-s" ); break;
@ -336,7 +341,8 @@ int main( const int argc, const char * const argv[] )
case 'u': diff_args.push_back( "-u" ); break; case 'u': diff_args.push_back( "-u" ); break;
case 'U': diff_args.push_back( "-U" ); case 'U': diff_args.push_back( "-U" );
diff_args.push_back( arg.c_str() ); break; diff_args.push_back( arg.c_str() ); break;
case 'V': show_version(); return 0; case 'v': verbosity = 1; break;
case 'V': show_version( DIFF " --version" ); return 0;
case 'w': diff_args.push_back( "-w" ); break; case 'w': diff_args.push_back( "-w" ); break;
case 'W': diff_args.push_back( "-W" ); case 'W': diff_args.push_back( "-W" );
diff_args.push_back( arg.c_str() ); break; diff_args.push_back( arg.c_str() ); break;
@ -345,18 +351,19 @@ int main( const int argc, const char * const argv[] )
case gz_opt: parse_compressor( arg, fmt_gz ); break; case gz_opt: parse_compressor( arg, fmt_gz ); break;
case lz_opt: parse_compressor( arg, fmt_lz ); break; case lz_opt: parse_compressor( arg, fmt_lz ); break;
case xz_opt: parse_compressor( arg, fmt_xz ); break; case xz_opt: parse_compressor( arg, fmt_xz ); break;
case zst_opt: parse_compressor( arg, fmt_zst ); break;
default : internal_error( "uncaught option." ); default : internal_error( "uncaught option." );
} }
} // end process options } // end process options
#if defined(__MSVCRT__) || defined(__OS2__) #if defined __MSVCRT__ || defined __OS2__
setmode( STDIN_FILENO, O_BINARY ); setmode( STDIN_FILENO, O_BINARY );
setmode( STDOUT_FILENO, O_BINARY ); setmode( STDOUT_FILENO, O_BINARY );
#endif #endif
if( argind >= parser.arguments() ) if( argind >= parser.arguments() )
{ show_error( "No files given.", 0, true ); return 2; } { show_error( "No files given.", 0, true ); return 2; }
if( argind + 2 < parser.arguments() ) if( parser.arguments() - argind > 2 )
{ show_error( "Too many files.", 0, true ); return 2; } { show_error( "Too many files.", 0, true ); return 2; }
const int files = parser.arguments() - argind; const int files = parser.arguments() - argind;
@ -427,7 +434,19 @@ int main( const int argc, const char * const argv[] )
int retval = wait_for_child( diff_pid, DIFF ); int retval = wait_for_child( diff_pid, DIFF );
for( int i = 0; i < 2; ++i ) for( int i = 0; i < 2; ++i )
if( !good_status( children[i], retval == 0 ) ) retval = 2; {
int infd; // fifo from decompressor
do infd = open( fifonames[i].c_str(), O_RDONLY | O_NONBLOCK | O_BINARY );
while( infd < 0 && errno == EINTR );
bool finished = false; // set to true if fifo is empty and at EOF
if( infd >= 0 )
{
uint8_t b;
if( readblock( infd, &b, 1 ) <= 0 && errno == 0 ) finished = true;
close( infd );
}
if( !good_status( children[i], finished ) ) retval = 2;
}
for( int i = 0; i < 2; ++i ) for( int i = 0; i < 2; ++i )
if( filenames[i] != "-" && close( infd[i] ) != 0 ) if( filenames[i] != "-" && close( infd[i] ) != 0 )

View file

@ -1,5 +1,5 @@
/* Zgrep - search compressed files for a regular expression /* Zgrep - search compressed files for a regular expression
Copyright (C) 2010-2021 Antonio Diaz Diaz. Copyright (C) 2010-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -31,7 +31,7 @@
#include <stdint.h> #include <stdint.h>
#include <unistd.h> #include <unistd.h>
#include <sys/stat.h> #include <sys/stat.h>
#if defined(__MSVCRT__) || defined(__OS2__) #if defined __MSVCRT__ || defined __OS2__
#include <io.h> #include <io.h>
#endif #endif
@ -60,7 +60,8 @@ void show_help()
"compressed format.\n" "compressed format.\n"
"\nIf no files are specified, recursive searches examine the current\n" "\nIf no files are specified, recursive searches examine the current\n"
"working directory, and nonrecursive searches read standard input.\n" "working directory, and nonrecursive searches read standard input.\n"
"\nThe formats supported are bzip2, gzip, lzip, and xz.\n" "\n'zgrep --verbose -V' prints the version of the grep program used.\n"
"\nThe formats supported are bzip2, gzip, lzip, xz, and zstd.\n"
"\nUsage: zgrep [options] <pattern> [files]\n" "\nUsage: zgrep [options] <pattern> [files]\n"
"\nExit status is 0 if match, 1 if no match, 2 if trouble.\n" "\nExit status is 0 if match, 1 if no match, 2 if trouble.\n"
"Some options only work if the grep program used supports them.\n" "Some options only work if the grep program used supports them.\n"
@ -89,7 +90,7 @@ void show_help()
" -n, --line-number print the line number of each line\n" " -n, --line-number print the line number of each line\n"
" -N, --no-rcfile don't read runtime configuration file\n" " -N, --no-rcfile don't read runtime configuration file\n"
" -o, --only-matching show only the part of a line matching <pattern>\n" " -o, --only-matching show only the part of a line matching <pattern>\n"
" -O, --force-format=<fmt> force the format given (bz2, gz, lz, xz)\n" " -O, --force-format=<fmt> force the format given (bz2, gz, lz, xz, zst)\n"
" -q, --quiet suppress all messages\n" " -q, --quiet suppress all messages\n"
" -r, --recursive operate recursively on directories\n" " -r, --recursive operate recursively on directories\n"
" -R, --dereference-recursive recursively follow symbolic links\n" " -R, --dereference-recursive recursively follow symbolic links\n"
@ -102,6 +103,7 @@ void show_help()
" --gz=<command> set compressor and options for gzip format\n" " --gz=<command> set compressor and options for gzip format\n"
" --lz=<command> set compressor and options for lzip format\n" " --lz=<command> set compressor and options for lzip format\n"
" --xz=<command> set compressor and options for xz format\n" " --xz=<command> set compressor and options for xz format\n"
" --zst=<command> set compressor and options for zstd format\n"
"\nNumbers may be followed by a multiplier: k = kB = 10^3 = 1000,\n" "\nNumbers may be followed by a multiplier: k = kB = 10^3 = 1000,\n"
"Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...\n" ); "Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...\n" );
show_help_addr(); show_help_addr();
@ -217,7 +219,7 @@ int zgrep_file( int infd, const int format_index,
int main( const int argc, const char * const argv[] ) int main( const int argc, const char * const argv[] )
{ {
enum { help_opt = 256, verbose_opt, color_opt, enum { help_opt = 256, verbose_opt, color_opt,
bz2_opt, gz_opt, lz_opt, xz_opt }; bz2_opt, gz_opt, lz_opt, xz_opt, zst_opt };
int format_index = -1; int format_index = -1;
int list_mode = 0; // 1 = list matches, -1 = list non-matches int list_mode = 0; // 1 = list matches, -1 = list non-matches
int recursive = 0; // 1 = '-r', 2 = '-R' int recursive = 0; // 1 = '-r', 2 = '-R'
@ -268,6 +270,7 @@ int main( const int argc, const char * const argv[] )
{ gz_opt, "gz", Arg_parser::yes }, { gz_opt, "gz", Arg_parser::yes },
{ lz_opt, "lz", Arg_parser::yes }, { lz_opt, "lz", Arg_parser::yes },
{ xz_opt, "xz", Arg_parser::yes }, { xz_opt, "xz", Arg_parser::yes },
{ zst_opt, "zst", Arg_parser::yes },
{ 0, 0, Arg_parser::no } }; { 0, 0, Arg_parser::no } };
const Arg_parser parser( argc, argv, options ); const Arg_parser parser( argc, argv, options );
@ -282,6 +285,7 @@ int main( const int argc, const char * const argv[] )
{ {
const int code = parser.code( argind ); const int code = parser.code( argind );
if( !code ) break; // no more options if( !code ) break; // no more options
const char * const pn = parser.parsed_name( argind ).c_str();
const std::string & arg = parser.argument( argind ); const std::string & arg = parser.argument( argind );
switch( code ) switch( code )
{ {
@ -308,22 +312,22 @@ int main( const int argc, const char * const argv[] )
case 'L': grep_args.push_back( "-L" ); list_mode = -1; break; case 'L': grep_args.push_back( "-L" ); list_mode = -1; break;
case 'm': grep_args.push_back( "-m" ); case 'm': grep_args.push_back( "-m" );
grep_args.push_back( arg.c_str() ); break; grep_args.push_back( arg.c_str() ); break;
case 'M': parse_format_list( arg ); break; case 'M': parse_format_list( arg, pn ); break;
case 'n': grep_args.push_back( "-n" ); break; case 'n': grep_args.push_back( "-n" ); break;
case 'N': break; case 'N': break;
case 'o': grep_args.push_back( "-o" ); break; case 'o': grep_args.push_back( "-o" ); break;
case 'O': format_index = parse_format_type( arg ); break; case 'O': format_index = parse_format_type( arg, pn ); break;
case 'q': grep_args.push_back( "-q" ); verbosity = -1; break; case 'q': grep_args.push_back( "-q" ); verbosity = -1; break;
case 'r': recursive = 1; break; case 'r': recursive = 1; break;
case 'R': recursive = 2; break; case 'R': recursive = 2; break;
case 's': grep_args.push_back( "-s" ); no_messages = true; break; case 's': grep_args.push_back( "-s" ); no_messages = true; break;
case 'v': grep_args.push_back( "-v" ); break; case 'v': grep_args.push_back( "-v" ); break;
case 'V': show_version(); return 0; case 'V': show_version( GREP " --version" ); return 0;
case 'w': grep_args.push_back( "-w" ); break; case 'w': grep_args.push_back( "-w" ); break;
case 'x': grep_args.push_back( "-x" ); break; case 'x': grep_args.push_back( "-x" ); break;
case help_opt: show_help(); return 0; case help_opt: show_help(); return 0;
case verbose_opt: if( verbosity < 4 ) ++verbosity; case verbose_opt: no_messages = false; if( verbosity < 4 ) ++verbosity;
no_messages = false; break; break;
case color_opt: color_option = "--color"; case color_opt: color_option = "--color";
if( !arg.empty() ) { color_option += '='; color_option += arg; } if( !arg.empty() ) { color_option += '='; color_option += arg; }
break; break;
@ -331,6 +335,7 @@ int main( const int argc, const char * const argv[] )
case gz_opt: parse_compressor( arg, fmt_gz ); break; case gz_opt: parse_compressor( arg, fmt_gz ); break;
case lz_opt: parse_compressor( arg, fmt_lz ); break; case lz_opt: parse_compressor( arg, fmt_lz ); break;
case xz_opt: parse_compressor( arg, fmt_xz ); break; case xz_opt: parse_compressor( arg, fmt_xz ); break;
case zst_opt: parse_compressor( arg, fmt_zst ); break;
default : internal_error( "uncaught option." ); default : internal_error( "uncaught option." );
} }
} // end process options } // end process options
@ -338,7 +343,7 @@ int main( const int argc, const char * const argv[] )
if( !color_option.empty() ) // push the last value set if( !color_option.empty() ) // push the last value set
grep_args.push_back( color_option.c_str() ); grep_args.push_back( color_option.c_str() );
#if defined(__MSVCRT__) || defined(__OS2__) #if defined __MSVCRT__ || defined __OS2__
setmode( STDIN_FILENO, O_BINARY ); setmode( STDIN_FILENO, O_BINARY );
setmode( STDOUT_FILENO, O_BINARY ); setmode( STDOUT_FILENO, O_BINARY );
#endif #endif

View file

@ -1,5 +1,5 @@
/* Ztest - verify the integrity of compressed files /* Ztest - verify the integrity of compressed files
Copyright (C) 2010-2021 Antonio Diaz Diaz. Copyright (C) 2010-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -31,7 +31,7 @@
#include <stdint.h> #include <stdint.h>
#include <unistd.h> #include <unistd.h>
#include <sys/stat.h> #include <sys/stat.h>
#if defined(__MSVCRT__) || defined(__OS2__) #if defined __MSVCRT__ || defined __OS2__
#include <io.h> #include <io.h>
#endif #endif
@ -60,7 +60,7 @@ void show_help()
"test when testing multiple files.\n" "test when testing multiple files.\n"
"\nIf no files are specified, recursive searches examine the current\n" "\nIf no files are specified, recursive searches examine the current\n"
"working directory, and nonrecursive searches read standard input.\n" "working directory, and nonrecursive searches read standard input.\n"
"\nThe formats supported are bzip2, gzip, lzip, and xz.\n" "\nThe formats supported are bzip2, gzip, lzip, xz, and zstd.\n"
"\nNote that error detection in the xz format is broken. First, some xz\n" "\nNote that error detection in the xz format is broken. First, some xz\n"
"files lack integrity information. Second, not all xz decompressors can\n" "files lack integrity information. Second, not all xz decompressors can\n"
"verify the integrity of all xz files. Third, section 2.1.1.2 'Stream\n" "verify the integrity of all xz files. Third, section 2.1.1.2 'Stream\n"
@ -76,7 +76,7 @@ void show_help()
" -V, --version output version information and exit\n" " -V, --version output version information and exit\n"
" -M, --format=<list> process only the formats in <list>\n" " -M, --format=<list> process only the formats in <list>\n"
" -N, --no-rcfile don't read runtime configuration file\n" " -N, --no-rcfile don't read runtime configuration file\n"
" -O, --force-format=<fmt> force the format given (bz2, gz, lz, xz)\n" " -O, --force-format=<fmt> force the format given (bz2, gz, lz, xz, zst)\n"
" -q, --quiet suppress all messages\n" " -q, --quiet suppress all messages\n"
" -r, --recursive operate recursively on directories\n" " -r, --recursive operate recursively on directories\n"
" -R, --dereference-recursive recursively follow symbolic links\n" " -R, --dereference-recursive recursively follow symbolic links\n"
@ -84,7 +84,8 @@ void show_help()
" --bz2=<command> set compressor and options for bzip2 format\n" " --bz2=<command> set compressor and options for bzip2 format\n"
" --gz=<command> set compressor and options for gzip format\n" " --gz=<command> set compressor and options for gzip format\n"
" --lz=<command> set compressor and options for lzip format\n" " --lz=<command> set compressor and options for lzip format\n"
" --xz=<command> set compressor and options for xz format\n" ); " --xz=<command> set compressor and options for xz format\n"
" --zst=<command> set compressor and options for zstd format\n" );
show_help_addr(); show_help_addr();
} }
@ -164,7 +165,9 @@ int ztest_file( const int infd, int format_index,
const std::string & input_filename, const std::string & input_filename,
const std::vector< const char * > & ztest_args ) const std::vector< const char * > & ztest_args )
{ {
// bzip2, gzip, and lzip are the primary formats. xz and zstd are optional.
static int disable_xz = -1; // tri-state bool static int disable_xz = -1; // tri-state bool
static int disable_zst = -1; // tri-state bool
uint8_t magic_data[magic_buf_size]; uint8_t magic_data[magic_buf_size];
int magic_size = 0; int magic_size = 0;
if( format_index < 0 ) if( format_index < 0 )
@ -178,9 +181,24 @@ int ztest_file( const int infd, int format_index,
{ {
std::string command( compressor_name ); command += " -V > /dev/null 2>&1"; std::string command( compressor_name ); command += " -V > /dev/null 2>&1";
disable_xz = ( std::system( command.c_str() ) != 0 ); disable_xz = ( std::system( command.c_str() ) != 0 );
if( disable_xz && verbosity >= 2 )
std::fprintf( stderr, "%s: '%s' not found. Ignoring xz files.\n",
program_name, compressor_name );
} }
if( disable_xz ) return 0; // ignore this file if no xz installed if( disable_xz ) return 0; // ignore this file if no xz installed
} }
else if( format_index == fmt_zst )
{
if( disable_zst < 0 )
{
std::string command( compressor_name ); command += " -V > /dev/null 2>&1";
disable_zst = ( std::system( command.c_str() ) != 0 );
if( disable_zst && verbosity >= 2 )
std::fprintf( stderr, "%s: '%s' not found. Ignoring zstd files.\n",
program_name, compressor_name );
}
if( disable_zst ) return 0; // ignore this file if no zstd installed
}
const pid_t pid = fork(); const pid_t pid = fork();
@ -216,7 +234,7 @@ int ztest_file( const int infd, int format_index,
int main( const int argc, const char * const argv[] ) int main( const int argc, const char * const argv[] )
{ {
enum { bz2_opt = 256, gz_opt, lz_opt, xz_opt }; enum { bz2_opt = 256, gz_opt, lz_opt, xz_opt, zst_opt };
int format_index = -1; int format_index = -1;
int recursive = 0; // 1 = '-r', 2 = '-R' int recursive = 0; // 1 = '-r', 2 = '-R'
std::list< std::string > filenames; std::list< std::string > filenames;
@ -239,6 +257,7 @@ int main( const int argc, const char * const argv[] )
{ gz_opt, "gz", Arg_parser::yes }, { gz_opt, "gz", Arg_parser::yes },
{ lz_opt, "lz", Arg_parser::yes }, { lz_opt, "lz", Arg_parser::yes },
{ xz_opt, "xz", Arg_parser::yes }, { xz_opt, "xz", Arg_parser::yes },
{ zst_opt, "zst", Arg_parser::yes },
{ 0, 0, Arg_parser::no } }; { 0, 0, Arg_parser::no } };
const Arg_parser parser( argc, argv, options ); const Arg_parser parser( argc, argv, options );
@ -252,13 +271,14 @@ int main( const int argc, const char * const argv[] )
{ {
const int code = parser.code( argind ); const int code = parser.code( argind );
if( !code ) break; // no more options if( !code ) break; // no more options
const char * const pn = parser.parsed_name( argind ).c_str();
const std::string & arg = parser.argument( argind ); const std::string & arg = parser.argument( argind );
switch( code ) switch( code )
{ {
case 'h': show_help(); return 0; case 'h': show_help(); return 0;
case 'M': parse_format_list( arg ); break; case 'M': parse_format_list( arg, pn ); break;
case 'N': break; case 'N': break;
case 'O': format_index = parse_format_type( arg ); break; case 'O': format_index = parse_format_type( arg, pn ); break;
case 'q': verbosity = -1; ztest_args.push_back( "-q" ); break; case 'q': verbosity = -1; ztest_args.push_back( "-q" ); break;
case 'r': recursive = 1; break; case 'r': recursive = 1; break;
case 'R': recursive = 2; break; case 'R': recursive = 2; break;
@ -269,11 +289,12 @@ int main( const int argc, const char * const argv[] )
case gz_opt: parse_compressor( arg, fmt_gz, 1 ); break; case gz_opt: parse_compressor( arg, fmt_gz, 1 ); break;
case lz_opt: parse_compressor( arg, fmt_lz, 1 ); break; case lz_opt: parse_compressor( arg, fmt_lz, 1 ); break;
case xz_opt: parse_compressor( arg, fmt_xz, 1 ); break; case xz_opt: parse_compressor( arg, fmt_xz, 1 ); break;
case zst_opt: parse_compressor( arg, fmt_zst, 1 ); break;
default : internal_error( "uncaught option." ); default : internal_error( "uncaught option." );
} }
} // end process options } // end process options
#if defined(__MSVCRT__) || defined(__OS2__) #if defined __MSVCRT__ || defined __OS2__
setmode( STDIN_FILENO, O_BINARY ); setmode( STDIN_FILENO, O_BINARY );
setmode( STDOUT_FILENO, O_BINARY ); setmode( STDOUT_FILENO, O_BINARY );
#endif #endif

View file

@ -1,5 +1,5 @@
/* Zupdate - recompress bzip2, gzip, xz files to lzip format /* Zupdate - recompress bzip2, gzip, xz, zstd files to lzip format
Copyright (C) 2013-2021 Antonio Diaz Diaz. Copyright (C) 2013-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -33,7 +33,7 @@
#include <utime.h> #include <utime.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/wait.h> #include <sys/wait.h>
#if defined(__MSVCRT__) || defined(__OS2__) #if defined __MSVCRT__ || defined __OS2__
#include <io.h> #include <io.h>
#endif #endif
@ -51,7 +51,7 @@ namespace {
void show_help() void show_help()
{ {
std::printf( "zupdate recompresses files from bzip2, gzip, and xz formats to lzip\n" std::printf( "zupdate recompresses files from bzip2, gzip, xz, and zstd formats to lzip\n"
"format. Each original is compared with the new file and then deleted.\n" "format. Each original is compared with the new file and then deleted.\n"
"Only regular files with standard file name extensions are recompressed,\n" "Only regular files with standard file name extensions are recompressed,\n"
"other files are ignored. Compressed files are decompressed and then\n" "other files are ignored. Compressed files are decompressed and then\n"
@ -67,8 +67,8 @@ void show_help()
"to be safe and not cause any data loss. Therefore, existing lzip\n" "to be safe and not cause any data loss. Therefore, existing lzip\n"
"compressed files are never overwritten nor deleted.\n" "compressed files are never overwritten nor deleted.\n"
"\nThe names of the original files must have one of the following extensions:\n" "\nThe names of the original files must have one of the following extensions:\n"
"'.bz2', '.gz', or '.xz', which are recompressed to '.lz';\n" "\n'.bz2', '.gz', '.xz', or '.zst', which are recompressed to '.lz'.\n"
"'.tbz', '.tbz2', '.tgz', or '.txz', which are recompressed to '.tlz'.\n" "\n'.tbz', '.tbz2', '.tgz', '.txz', or '.tzst', which are recompressed to '.tlz'.\n"
"\nUsage: zupdate [options] [files]\n" "\nUsage: zupdate [options] [files]\n"
"\nExit status is 0 if all the compressed files were successfully recompressed\n" "\nExit status is 0 if all the compressed files were successfully recompressed\n"
"(if needed), compared, and deleted (if requested). Non-zero otherwise.\n" "(if needed), compared, and deleted (if requested). Non-zero otherwise.\n"
@ -88,7 +88,8 @@ void show_help()
" --bz2=<command> set compressor and options for bzip2 format\n" " --bz2=<command> set compressor and options for bzip2 format\n"
" --gz=<command> set compressor and options for gzip format\n" " --gz=<command> set compressor and options for gzip format\n"
" --lz=<command> set compressor and options for lzip format\n" " --lz=<command> set compressor and options for lzip format\n"
" --xz=<command> set compressor and options for xz format\n" ); " --xz=<command> set compressor and options for xz format\n"
" --zst=<command> set compressor and options for zstd format\n" );
show_help_addr(); show_help_addr();
} }
@ -125,17 +126,19 @@ void set_permissions( const char * const rname, const struct stat & in_stats )
t.modtime = in_stats.st_mtime; t.modtime = in_stats.st_mtime;
if( utime( rname, &t ) != 0 ) warning = true; if( utime( rname, &t ) != 0 ) warning = true;
if( warning && verbosity >= 2 ) if( warning && verbosity >= 2 )
show_error( "Can't change output file attributes." ); show_file_error( rname, "Can't change output file attributes.", errno );
} }
// Returns 0 for success, -1 for file skipped, 1 for error. // Return 0 if success, -1 if file skipped, 1 if error.
int zupdate_file( const std::string & name, const char * const lzip_name, int zupdate_file( const std::string & name, const char * const lzip_name,
const std::vector< std::string > & lzip_args2, const std::vector< std::string > & lzip_args2,
const bool force, const bool keep_input_files, const bool force, const bool keep_input_files,
const bool no_rcfile ) const bool no_rcfile )
{ {
// bzip2, gzip, and lzip are the primary formats. xz and zstd are optional.
static int disable_xz = -1; // tri-state bool static int disable_xz = -1; // tri-state bool
static int disable_zst = -1; // tri-state bool
int format_index = -1; int format_index = -1;
std::string rname; // recompressed name std::string rname; // recompressed name
@ -198,9 +201,24 @@ int zupdate_file( const std::string & name, const char * const lzip_name,
{ {
std::string command( compressor_name ); command += " -V > /dev/null 2>&1"; std::string command( compressor_name ); command += " -V > /dev/null 2>&1";
disable_xz = ( std::system( command.c_str() ) != 0 ); disable_xz = ( std::system( command.c_str() ) != 0 );
if( disable_xz && verbosity >= 2 )
std::fprintf( stderr, "%s: '%s' not found. Ignoring xz files.\n",
program_name, compressor_name );
} }
if( disable_xz ) return 0; // ignore this file if no xz installed if( disable_xz ) return 0; // ignore this file if no xz installed
} }
else if( format_index == fmt_zst )
{
if( disable_zst < 0 )
{
std::string command( compressor_name ); command += " -V > /dev/null 2>&1";
disable_zst = ( std::system( command.c_str() ) != 0 );
if( disable_zst && verbosity >= 2 )
std::fprintf( stderr, "%s: '%s' not found. Ignoring zstd files.\n",
program_name, compressor_name );
}
if( disable_zst ) return 0; // ignore this file if no zstd installed
}
if( !lz_exists ) // recompress if( !lz_exists ) // recompress
{ {
@ -307,7 +325,7 @@ int zupdate_file( const std::string & name, const char * const lzip_name,
int main( const int argc, const char * const argv[] ) int main( const int argc, const char * const argv[] )
{ {
enum { bz2_opt = 256, gz_opt, lz_opt, xz_opt }; enum { bz2_opt = 256, gz_opt, lz_opt, xz_opt, zst_opt };
int recursive = 0; // 1 = '-r', 2 = '-R' int recursive = 0; // 1 = '-r', 2 = '-R'
std::list< std::string > filenames; std::list< std::string > filenames;
std::vector< std::string > lzip_args2; // args to lzip, maybe empty std::vector< std::string > lzip_args2; // args to lzip, maybe empty
@ -344,6 +362,7 @@ int main( const int argc, const char * const argv[] )
{ gz_opt, "gz", Arg_parser::yes }, { gz_opt, "gz", Arg_parser::yes },
{ lz_opt, "lz", Arg_parser::yes }, { lz_opt, "lz", Arg_parser::yes },
{ xz_opt, "xz", Arg_parser::yes }, { xz_opt, "xz", Arg_parser::yes },
{ zst_opt, "zst", Arg_parser::yes },
{ 0, 0, Arg_parser::no } }; { 0, 0, Arg_parser::no } };
const Arg_parser parser( argc, argv, options ); const Arg_parser parser( argc, argv, options );
@ -357,6 +376,7 @@ int main( const int argc, const char * const argv[] )
{ {
const int code = parser.code( argind ); const int code = parser.code( argind );
if( !code ) break; // no more options if( !code ) break; // no more options
const char * const pn = parser.parsed_name( argind ).c_str();
const std::string & arg = parser.argument( argind ); const std::string & arg = parser.argument( argind );
switch( code ) switch( code )
{ {
@ -367,7 +387,7 @@ int main( const int argc, const char * const argv[] )
case 'h': show_help(); return 0; case 'h': show_help(); return 0;
case 'k': keep_input_files = true; break; case 'k': keep_input_files = true; break;
case 'l': lzip_args2.push_back( "-v" ); break; case 'l': lzip_args2.push_back( "-v" ); break;
case 'M': parse_format_list( arg ); break; case 'M': parse_format_list( arg, pn ); break;
case 'N': no_rcfile = true; break; case 'N': no_rcfile = true; break;
case 'q': verbosity = -1; lzip_args2.push_back( "-q" ); break; case 'q': verbosity = -1; lzip_args2.push_back( "-q" ); break;
case 'r': recursive = 1; break; case 'r': recursive = 1; break;
@ -378,11 +398,12 @@ int main( const int argc, const char * const argv[] )
case gz_opt: parse_compressor( arg, fmt_gz, 1 ); break; case gz_opt: parse_compressor( arg, fmt_gz, 1 ); break;
case lz_opt: parse_compressor( arg, fmt_lz, 1 ); break; case lz_opt: parse_compressor( arg, fmt_lz, 1 ); break;
case xz_opt: parse_compressor( arg, fmt_xz, 1 ); break; case xz_opt: parse_compressor( arg, fmt_xz, 1 ); break;
case zst_opt: parse_compressor( arg, fmt_zst, 1 ); break;
default : internal_error( "uncaught option." ); default : internal_error( "uncaught option." );
} }
} // end process options } // end process options
#if defined(__MSVCRT__) || defined(__OS2__) #if defined __MSVCRT__ || defined __OS2__
setmode( STDIN_FILENO, O_BINARY ); setmode( STDIN_FILENO, O_BINARY );
setmode( STDOUT_FILENO, O_BINARY ); setmode( STDOUT_FILENO, O_BINARY );
#endif #endif

View file

@ -1,5 +1,5 @@
/* Zutils - Utilities dealing with compressed files /* Zutils - Utilities dealing with compressed files
Copyright (C) 2009-2021 Antonio Diaz Diaz. Copyright (C) 2009-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -46,8 +46,8 @@ inline bool isvalid_ds( const uint8_t ds ) // lzip valid dictionary_size
} }
/* Returns -1 if child not terminated, 2 in case of error, or exit status of /* Return -1 if child not terminated, 2 in case of error, or exit status of
child process 'pid'. child process 'pid'. Return 0 if child was terminated by SIGPIPE.
*/ */
int child_status( const pid_t pid, const char * const name ) int child_status( const pid_t pid, const char * const name )
{ {
@ -73,8 +73,8 @@ int child_status( const pid_t pid, const char * const name )
} // end namespace } // end namespace
/* Returns the number of bytes really read. /* Return the number of bytes really read.
If (returned value < size) and (errno == 0), means EOF was reached. If (value returned < size) and (errno == 0), means EOF was reached.
*/ */
int readblock( const int fd, uint8_t * const buf, const int size ) int readblock( const int fd, uint8_t * const buf, const int size )
{ {
@ -92,8 +92,8 @@ int readblock( const int fd, uint8_t * const buf, const int size )
} }
/* Returns the number of bytes really written. /* Return the number of bytes really written.
If (returned value < size), it is always an error. If (value returned < size), it is always an error.
*/ */
int writeblock( const int fd, const uint8_t * const buf, const int size ) int writeblock( const int fd, const uint8_t * const buf, const int size )
{ {
@ -146,7 +146,7 @@ bool good_status( const Children & children, const bool finished )
// even if compressor finished, trailing data may remain in data feeder // even if compressor finished, trailing data may remain in data feeder
if( i == 0 || !finished ) if( i == 0 || !finished )
{ {
const int tmp = child_status( pid, name ); const int tmp = child_status( pid, name ); // 0 if SIGPIPE
if( tmp < 0 ) // child not terminated if( tmp < 0 ) // child not terminated
{ kill( pid, SIGTERM ); wait_for_child( pid, name ); } { kill( pid, SIGTERM ); wait_for_child( pid, name ); }
else if( tmp != 0 ) error = true; // child status != 0 else if( tmp != 0 ) error = true; // child status != 0
@ -246,7 +246,7 @@ bool set_data_feeder( const std::string & filename, int * const infdp,
} }
// Returns format index or -1 if uncompressed // Return format index, or -1 if uncompressed.
// //
int test_format( const int infd, uint8_t magic_data[], int test_format( const int infd, uint8_t magic_data[],
int * const magic_sizep ) int * const magic_sizep )
@ -254,7 +254,8 @@ int test_format( const int infd, uint8_t magic_data[],
enum { bzip2_magic_size = 3, enum { bzip2_magic_size = 3,
gzip_magic_size = 2, gzip_magic_size = 2,
lzip_magic_size = 5, lzip_magic_size = 5,
xz_magic_size = 5 }; xz_magic_size = 5,
zstd_magic_size = 4 };
const uint8_t bzip2_magic[bzip2_magic_size] = const uint8_t bzip2_magic[bzip2_magic_size] =
{ 0x42, 0x5A, 0x68 }; // "BZh" { 0x42, 0x5A, 0x68 }; // "BZh"
const uint8_t gzip_magic[gzip_magic_size] = const uint8_t gzip_magic[gzip_magic_size] =
@ -263,19 +264,23 @@ int test_format( const int infd, uint8_t magic_data[],
{ 0x4C, 0x5A, 0x49, 0x50, 0x01 }; // "LZIP\001" { 0x4C, 0x5A, 0x49, 0x50, 0x01 }; // "LZIP\001"
const uint8_t xz_magic[xz_magic_size] = const uint8_t xz_magic[xz_magic_size] =
{ 0xFD, 0x37, 0x7A, 0x58, 0x5A }; // 0xFD, "7zXZ" { 0xFD, 0x37, 0x7A, 0x58, 0x5A }; // 0xFD, "7zXZ"
const uint8_t zstd_magic[zstd_magic_size] =
{ 0x28, 0xB5, 0x2F, 0xFD }; // 0xFD2FB528 LE
*magic_sizep = readblock( infd, magic_data, magic_buf_size ); *magic_sizep = readblock( infd, magic_data, magic_buf_size );
if( *magic_sizep == magic_buf_size ) if( *magic_sizep == magic_buf_size ) // test formats in search order
{ {
if( std::memcmp( magic_data, lzip_magic, lzip_magic_size ) == 0 &&
isvalid_ds( magic_data[lzip_magic_size] ) )
return fmt_lz;
if( std::memcmp( magic_data, bzip2_magic, bzip2_magic_size ) == 0 && if( std::memcmp( magic_data, bzip2_magic, bzip2_magic_size ) == 0 &&
magic_data[3] >= '1' && magic_data[3] <= '9' && magic_data[3] >= '1' && magic_data[3] <= '9' &&
std::memcmp( magic_data + 4, "1AY&SY", 6 ) == 0 ) std::memcmp( magic_data + 4, "1AY&SY", 6 ) == 0 )
return fmt_bz2; return fmt_bz2;
if( std::memcmp( magic_data, gzip_magic, gzip_magic_size ) == 0 ) if( std::memcmp( magic_data, gzip_magic, gzip_magic_size ) == 0 )
return fmt_gz; return fmt_gz;
if( std::memcmp( magic_data, lzip_magic, lzip_magic_size ) == 0 && if( std::memcmp( magic_data, zstd_magic, zstd_magic_size ) == 0 )
isvalid_ds( magic_data[lzip_magic_size] ) ) return fmt_zst;
return fmt_lz;
if( std::memcmp( magic_data, xz_magic, xz_magic_size ) == 0 ) if( std::memcmp( magic_data, xz_magic, xz_magic_size ) == 0 )
return fmt_xz; return fmt_xz;
} }

View file

@ -1,5 +1,5 @@
/* Zutils - Utilities dealing with compressed files /* Zutils - Utilities dealing with compressed files
Copyright (C) 2009-2021 Antonio Diaz Diaz. Copyright (C) 2009-2022 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -31,7 +31,7 @@ bool set_data_feeder( const std::string & filename, int * const infdp,
enum { magic_buf_size = 10 }; // >= longest extended magic (bzip2) enum { magic_buf_size = 10 }; // >= longest extended magic (bzip2)
// Returns format index or -1 if uncompressed // Return format index, or -1 if uncompressed.
// //
int test_format( const int infd, uint8_t magic_data[], int test_format( const int infd, uint8_t magic_data[],
int * const magic_sizep ); int * const magic_sizep );

View file

@ -14,3 +14,4 @@
# gz = pigz -p2 # gz = pigz -p2
# lz = plzip -n2 # lz = plzip -n2
# xz = pixz -p2 # xz = pixz -p2
# zst = zstd -T2