1
0
Fork 0

Merging upstream version 1.9.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-24 05:59:37 +01:00
parent 3e7d50525b
commit 13941d3cbe
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
30 changed files with 1188 additions and 1060 deletions

107
ChangeLog
View file

@ -1,9 +1,25 @@
2020-06-27 Antonio Diaz Diaz <antonio@gnu.org>
* Version 1.9 released.
* zcmp.cc zdiff.cc: Read standard input only if requested.
* zdiff.cc (main): Pass options '-W' and '-y' to diff.
* zutils.cc (test_format): Detect bzip2 and lzip files better.
* ztest.cc (main): Continue testing if any input file is a terminal.
If verbosity >= 1, print number of files that failed the test.
* zcat.cc zgrep.cc ztest.cc (main): Check return value of close( infd ).
* zutils.cc (good_status): Ignore trailing data remaining in feeder.
* zupdate.cc (zupdate_file): Support new and old lzip option '-o'.
Keep combined extensions: tgz, tbz, tbz2, txz --> tlz.
Quote file names in zcmp_command to allow file names with spaces.
* *.cc (main): Set a valid invocation_name even if argc == 0.
* zutils.texi: Improve descriptions of zcat, zcmp, and zdiff.
2019-01-01 Antonio Diaz Diaz <antonio@gnu.org> 2019-01-01 Antonio Diaz Diaz <antonio@gnu.org>
* Version 1.8 released. * Version 1.8 released.
* zcat.cc: Fixed a buffer overflow on outbuf when '-v' is used. * zcat.cc: Fix a buffer overflow on outbuf when '-v' is used.
* zcat.cc (cat): A canary byte has been added to outbuf. * zcat.cc (cat): A canary byte has been added to outbuf.
* Added new option '-R, --dereference-recursive'. * New option '-R, --dereference-recursive'.
* Option '-r, --recursive' now skips symlinks. * Option '-r, --recursive' now skips symlinks.
* If no files and recursive, examine current working directory. * If no files and recursive, examine current working directory.
* recursive.cc (test_full_name): Detect directory loops. * recursive.cc (test_full_name): Detect directory loops.
@ -11,15 +27,15 @@
* recursive.cc: Remove extra trailing slashes from directory args. * recursive.cc: Remove extra trailing slashes from directory args.
* zcatgrep.cc (open_instream): Show correct errno. * zcatgrep.cc (open_instream): Show correct errno.
* 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>
* Version 1.7 released. * Version 1.7 released.
* zgrep.cc (main): Pass '--color' option to grep. * zgrep.cc (main): Pass option '--color' to grep.
* check.sh: Added new tests for zgrep. * check.sh: Add new tests for zgrep.
2017-04-05 Antonio Diaz Diaz <antonio@gnu.org> 2017-04-05 Antonio Diaz Diaz <antonio@gnu.org>
@ -41,124 +57,123 @@
* Version 1.4 released. * Version 1.4 released.
* Option '--format' has been renamed to '-O, --force-format'. * Option '--format' has been renamed to '-O, --force-format'.
* Added new option '-M, --format=<list>' to all utilities. * Add new option '-M, --format=<list>' to all utilities.
* zgrep.cc (main): Pass '-e' to grep if pattern begins with '-'. * zgrep.cc (main): Pass '-e' to grep if pattern begins with '-'.
* Makefile.in: Added new targets 'install*-compress'. * Makefile.in: New targets 'install*-compress'.
2014-08-30 Antonio Diaz Diaz <antonio@gnu.org> 2014-08-30 Antonio Diaz Diaz <antonio@gnu.org>
* Version 1.3 released. * Version 1.3 released.
* check.sh: Fixed two values of expected exit status. * check.sh: Fix two values of expected exit status.
* zutils.texi: Documented that '--format' does not verify format. * zutils.texi: Document that '--format' does not verify format.
* Added two missing #includes. * Add two missing #includes.
* License changed to GPL version 2 or later. * Change license to GPL version 2 or later.
2014-02-01 Antonio Diaz Diaz <antonio@gnu.org> 2014-02-01 Antonio Diaz Diaz <antonio@gnu.org>
* Version 1.2 released. * Version 1.2 released.
* Added new utility; zupdate. * New utility; zupdate.
* Removed zutils executable. Utils are now independent executables. * Remove zutils executable. Utils are now independent executables.
* zgrep.cc: Fixed the exit status returned on error. * zgrep.cc: Fix the exit status returned on error.
* zutils.texinfo: Renamed to zutils.texi. * zutils.texinfo: Rename to zutils.texi.
2013-08-02 Antonio Diaz Diaz <antonio@gnu.org> 2013-08-02 Antonio Diaz Diaz <antonio@gnu.org>
* Version 1.1 released. * Version 1.1 released.
* Added options '--bz2', '--gz', '--lz' and '--xz' to all utilities. * Add options '--bz2', '--gz', '--lz', and '--xz' to all utilities.
* Added runtime configuration file 'zutilsrc'. * Add runtime configuration file 'zutilsrc'.
* New function 'good_status' checks exit status of all children. * New function 'good_status' checks exit status of all children.
* Fixed all uses of decompressed/uncompressed in the documentation. * Fix all uses of decompressed/uncompressed in the documentation.
2013-05-31 Antonio Diaz Diaz <antonio@gnu.org> 2013-05-31 Antonio Diaz Diaz <antonio@gnu.org>
* Version 1.0 released. * Version 1.0 released.
* Added new option '--format' to all utilities. * Add new option '--format' to all utilities.
* main.cc (main): Make 'grep_show_name' tri-state so that file * main.cc (main): Make 'grep_show_name' tri-state so that file
name is no prefixed to output by default when searching one name is no prefixed to output by default when searching one
file and '--recursive' has not been selected. file and '--recursive' has not been selected.
* Zgrep: Fixed output of option '-L' (it behaved like '-l'). * Zgrep: Fix output of option '-L' (it behaved like '-l').
* zcmp.cc: Fixed deadlock when '-n' option is used. * zcmp.cc: Fix deadlock when option '-n' is used.
* zdiff.cc (set_data_feeder): Call compressor with option "-q" * zdiff.cc (set_data_feeder): Call compressor with option '-q'
only if verbosity < 0. only if verbosity < 0.
* zutils.cc (set_data_feeder): Likewise. * zutils.cc (set_data_feeder): Likewise.
* Changed quote characters in messages as advised by GNU Standards. * Change quote characters in messages as advised by GNU Standards.
* configure: Options now accept a separate argument. * configure: Options now accept a separate argument.
* configure: 'datadir' renamed to 'datarootdir'. Rename 'datadir' to 'datarootdir'. Ignore environment variables.
* Makefile.in: Added new target 'install-bin'. * Makefile.in: New target 'install-bin'.
* Use 'setmode' instead of '_setmode' on Windows and OS/2. * Use 'setmode' instead of '_setmode' on Windows and OS/2.
* zcat.cc (Line_number): Fixed a portability issue with Solaris 9. * zcat.cc (Line_number): Fix a portability issue with Solaris 9.
* INSTALL: Document installing zutils along with GNU gzip. * INSTALL: Document installing zutils along with GNU gzip.
2011-01-11 Antonio Diaz Diaz <ant_diaz@teleline.es> 2011-01-11 Antonio Diaz Diaz <ant_diaz@teleline.es>
* Version 0.9 released. * Version 0.9 released.
* configure: Added new options 'DIFF' and 'GREP'. * configure: New options 'DIFF' and 'GREP'.
* zcmp.cc: Fixed deadlock when files differ. * zcmp.cc: Fix deadlock when files differ.
* zgrep.cc: Fixed deadlock when binary file matches. * zgrep.cc: Fix deadlock when binary file matches.
2010-11-15 Antonio Diaz Diaz <ant_diaz@teleline.es> 2010-11-15 Antonio Diaz Diaz <ant_diaz@teleline.es>
* Version 0.8 released. * Version 0.8 released.
* main.cc: Added new options '--zcat', '--zgrep' and '--ztest'. * main.cc: New options '--zcat', '--zgrep', and '--ztest'.
* zcat.cc: New file implementing zcat+cat functionality in C++. * zcat.cc: New file implementing zcat+cat functionality in C++.
* zcmp.cc: New file implementing zcmp+cmp functionality in C++. * zcmp.cc: New file implementing zcmp+cmp functionality in C++.
* doc/zcmp.1: New file. * doc/zcmp.1: New file.
* zcmp.in: Removed. * Remove files zcmp.in, zdiff.in.
* zdiff.cc: New file implementing zdiff functionality in C++. * zdiff.cc: New file implementing zdiff functionality in C++.
* zdiff.in: Removed.
* zgrep.cc: New file implementing zgrep functionality in C++. * zgrep.cc: New file implementing zgrep functionality in C++.
* All mentions to zegrep and zfgrep have been removed from the * All mentions to zegrep and zfgrep have been removed from the
documentation because egrep and fgrep are deprecated. documentation because egrep and fgrep are deprecated.
* ztest.cc: New file implementing ztest functionality in C++. * ztest.cc: New file implementing ztest functionality in C++.
* Makefile.in: Added quotes to directory names. * Makefile.in: Add quotes to directory names.
* check.sh: Use 'test.txt' instead of 'COPYING' for testing. * check.sh: Use 'test.txt' instead of 'COPYING' for testing.
* Removed environment safeguards from configure as requested by * Remove environment safeguards from configure as requested by
Richard Stallman. Now environment variables affect configure. Richard Stallman. Now environment variables affect configure.
2009-10-21 Antonio Diaz Diaz <ant_diaz@teleline.es> 2009-10-21 Antonio Diaz Diaz <ant_diaz@teleline.es>
* Version 0.7 released. * Version 0.7 released.
* Added new utility; ztest. * New utility; ztest.
* zcat.in: Added new option '--recursive'. * zcat.in: New option '-r, --recursive'.
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: Removed again default compressor. Format of * zcat.in, zgrep.in: Remove again default compressor. Format of
data read from stdin is now automatically detected. data read from stdin is now automatically detected.
* Makefile.in: Added '--name' option 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>
* Version 0.5 released. * Version 0.5 released.
* zcat.in, zgrep.in: Read again data from stdin. * zcat.in, zgrep.in: Read again data from stdin.
* Added again default compressor for stdin only. * Add again default compressor for stdin only.
2009-09-17 Antonio Diaz Diaz <ant_diaz@teleline.es> 2009-09-17 Antonio Diaz Diaz <ant_diaz@teleline.es>
* Version 0.4 released. * Version 0.4 released.
* Added two new utilities; zegrep and zfgrep. * Add two new utilities; zegrep and zfgrep.
* Added zutils executable which recognizes file formats. * Add zutils executable which recognizes file formats.
2009-08-28 Antonio Diaz Diaz <ant_diaz@teleline.es> 2009-08-28 Antonio Diaz Diaz <ant_diaz@teleline.es>
* Version 0.3 released. * Version 0.3 released.
* Removed default compressor. * Remove default compressor.
* zcat.in, zgrep.in: Don't read data from stdin. * zcat.in, zgrep.in: Don't read data from stdin.
* Updated home page and mailing list addresses. * Update home page and mailing list addresses.
2009-08-13 Antonio Diaz Diaz <ant_diaz@teleline.es> 2009-08-13 Antonio Diaz Diaz <ant_diaz@teleline.es>
* Version 0.2 released. * Version 0.2 released.
* Added support for xz. * Add support for xz.
2009-08-07 Antonio Diaz Diaz <ant_diaz@teleline.es> 2009-08-07 Antonio Diaz Diaz <ant_diaz@teleline.es>
* Version 0.1 released. * Version 0.1 released.
Copyright (C) 2009-2019 Antonio Diaz Diaz. Copyright (C) 2009-2020 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
modify it. modify it.

22
INSTALL
View file

@ -1,7 +1,7 @@
Requirements Requirements
------------ ------------
You will need a C++ compiler. You will need a C++11 compiler. (gcc 3.3.6 or newer is recommended).
I use gcc 5.3.0 and 4.1.2, but the code should compile with any standards I use gcc 6.1.0 and 4.1.2, 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.
@ -44,21 +44,21 @@ the main archive.
documentation. documentation.
Or type 'make install-compress', which additionally compresses the Or type 'make install-compress', which additionally compresses the
info manual and the man pages after installation. (Installing info manual and the man pages after installation.
compressed docs may become the default in the future). (Installing compressed docs may become the default in the future).
You can install only the programs, the info manual or the man pages by You can install only the programs, the info manual, or the man pages by
typing 'make install-bin', 'make install-info' or 'make install-man' typing 'make install-bin', 'make install-info', or 'make install-man'
respectively. respectively.
Another way Another way
----------- -----------
You can also compile zutils into a separate directory. You can also compile zutils into a separate directory.
To do this, you must use a version of 'make' that supports the 'VPATH' To do this, you must use a version of 'make' that supports the variable
variable, such as GNU 'make'. 'cd' to the directory where you want the 'VPATH', such as GNU 'make'. 'cd' to the directory where you want the
object files and executables to go and run the 'configure' script. object files and executables to go and run the 'configure' script.
'configure' automatically checks for the source code in '.', in '..' and 'configure' automatically checks for the source code in '.', in '..', and
in the directory that 'configure' is in. in the directory that 'configure' is in.
'configure' recognizes the option '--srcdir=DIR' to control where to 'configure' recognizes the option '--srcdir=DIR' to control where to
@ -69,7 +69,7 @@ After running 'configure', you can run 'make' and 'make install' as
explained above. explained above.
Copyright (C) 2009-2019 Antonio Diaz Diaz. Copyright (C) 2009-2020 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.

52
NEWS
View file

@ -1,38 +1,36 @@
Changes in version 1.8: Changes in version 1.9:
A buffer overflow has been fixed in zcat which happened sometimes when zcmp anf zdiff now meet the POSIX requirement for cmp and diff that the
the '-v, --show-nonprinting' option was used (or indirectly enabled). standard input shall be used only if the file1 or file2 operand refers to
A canary byte has been added to the output buffer to prevent the buffer standard input.
overflow from happening again.
The option '-R, --dereference-recursive', which recursively follows zdiff now passes the options '-W' and '-y' to diff. (But it only works if
symbolic links, has been added to zcat, zgrep, ztest and zupdate. the diff program used supports them).
The option '-r, --recursive' now skips symlinks that are encountered Bzip2 and lzip files are now detected better.
recursively. ('echo LZIP | zcat' and 'echo BZh5 | zcat' no longer return an error).
If no files are given to zcat, zgrep, ztest and zupdate, a recursive ztest now continues checking the rest of the files if any input file is a
search will now examine the current working directory. terminal.
Recursive directory loops are now detected. 'ztest -v' now prints the number of files that failed the test (like lzip).
zcat and zgrep now ignore directories given in the command line if zcat, zgrep, and ztest now check for errors when closing the input file in
'--recursive' is not specified, instead of reporting an error. addition to checking when closing the input from the decompressor.
Extra trailing slashes are now removed from directories given in the Trailing data remaining in the data feeder to the decompressor are now
command line before recursing into them. correctly ignored.
zcat and zgrep now show the right error when they can't open an input zupdate has been modified to support the new behavior of lzip 1.22's option
file instead of showing "No such file or directory". '-o' while retaining:
perfect backwards compatibility with older versions of lzip down to 1.20,
good backwards compatibility with older versions of lzip down to 1.11,
acceptable backwards compatibility with older versions of lzip down to 1.4.
Killed decompressors are now waited for, preventing failure caused by zupdate now keeps combined extensions: tgz, tbz, tbz2, txz --> tlz.
too many open pipes. This is useful when recompressing Slackware packages, for example.
Test and document that if a file fails to decompress, zcat, zgrep and zupdate now puts single quotes around file names when calling zcmp to allow
ztest continue processing the rest of the files. file names with spaces. (But putting spaces in file names is a bad idea).
Test and document that if an error happens while recompressing a file, The descriptions of zcat, zcmp, and zdiff have been improved.
zupdate exits immediately without recompressing the rest of the files.
The configure script now accepts appending options to CXXFLAGS using the
syntax 'CXXFLAGS+=OPTIONS'.

44
README
View file

@ -1,46 +1,46 @@
Description Description
Zutils is a collection of utilities able to process any combination of Zutils is a collection of utilities able to process any combination of
compressed and uncompressed files transparently. If any given file, compressed and uncompressed files transparently. If any file given,
including standard input, is compressed, its decompressed content is including standard input, is compressed, its decompressed content is used.
used. Compressed files are decompressed on the fly; no temporary files Compressed files are decompressed on the fly; no temporary files are
are created. created.
These utilities are not wrapper scripts but safer and more efficient C++ These utilities are not wrapper scripts but safer and more efficient C++
programs. In particular the '--recursive' option is very efficient in 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, and xz.
Zutils uses external compressors. The compressor to be used for each Zutils uses external compressors. The compressor to be used for each format
format is configurable at runtime. is configurable at runtime.
zcat, zcmp, zdiff, and zgrep are improved replacements for the shell zcat, zcmp, zdiff, and zgrep are improved replacements for the shell scripts
scripts provided by GNU gzip. ztest is unique to zutils. zupdate is provided by GNU gzip. ztest is unique to zutils. zupdate is similar to
similar to gzip's znew. 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
makes them safe to use with zutils. Gzip and xz may return ambiguous them safe to use with zutils. Gzip and xz may return ambiguous warning
warning values, making them less reliable back ends for zutils. values, making them less reliable back ends for zutils.
FORMAT NOTE 1: The '--format' option 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:
'zgrep foo -r --format=bz2,lz somedir somefile.tar'. 'zgrep foo -r --format=bz2,lz somedir somefile.tar'.
FORMAT NOTE 2: If the '--force-format' option 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,
allowing for example the processing of compress'd (.Z) files with gzip: allowing for example the processing of compress'd (.Z) files with gzip:
'zcmp --force-format=gz file.Z file.lz'. 'zcmp --force-format=gz file.Z file.lz'.
LANGUAGE NOTE: Uncompressed = not compressed = plain data; it may never LANGUAGE NOTE: Uncompressed = not compressed = plain data; it may never have
have been compressed. Decompressed is used to refer to data which have been compressed. Decompressed is used to refer to data which have undergone
undergone the process of decompression. the process of decompression.
Copyright (C) 2009-2019 Antonio Diaz Diaz. Copyright (C) 2009-2020 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.
The file Makefile.in is a data file used by configure to produce the The file Makefile.in is a data file used by configure to produce the
Makefile. It has the same copyright owner and permissions that configure Makefile. It has the same copyright owner and permissions that configure

View file

@ -1,15 +1,15 @@
/* Arg_parser - POSIX/GNU command line argument parser. (C++ version) /* Arg_parser - POSIX/GNU command line argument parser. (C++ version)
Copyright (C) 2006-2019 Antonio Diaz Diaz. Copyright (C) 2006-2020 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
that the following conditions are met: that the following conditions are met:
1. Redistributions of source code must retain the above copyright 1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer. notice, this list of conditions, and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright 2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the notice, this list of conditions, and the following disclaimer in the
documentation and/or other materials provided with the distribution. documentation and/or other materials provided with the distribution.
This library is distributed in the hope that it will be useful, This library is distributed in the hope that it will be useful,
@ -167,7 +167,7 @@ Arg_parser::Arg_parser( const int argc, const char * const argv[],
else non_options.push_back( argv[argind++] ); else non_options.push_back( argv[argind++] );
} }
} }
if( error_.size() ) data.clear(); if( !error_.empty() ) data.clear();
else else
{ {
for( unsigned i = 0; i < non_options.size(); ++i ) for( unsigned i = 0; i < non_options.size(); ++i )
@ -190,7 +190,7 @@ Arg_parser::Arg_parser( const char * const opt, const char * const arg,
{ if( opt[2] ) parse_long_option( opt, arg, options, argind ); } { if( opt[2] ) parse_long_option( opt, arg, options, argind ); }
else else
parse_short_option( opt, arg, options, argind ); parse_short_option( opt, arg, options, argind );
if( error_.size() ) data.clear(); if( !error_.empty() ) data.clear();
} }
else data.push_back( Record( opt ) ); else data.push_back( Record( opt ) );
} }

View file

@ -1,15 +1,15 @@
/* Arg_parser - POSIX/GNU command line argument parser. (C++ version) /* Arg_parser - POSIX/GNU command line argument parser. (C++ version)
Copyright (C) 2006-2019 Antonio Diaz Diaz. Copyright (C) 2006-2020 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
that the following conditions are met: that the following conditions are met:
1. Redistributions of source code must retain the above copyright 1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer. notice, this list of conditions, and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright 2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the notice, this list of conditions, and the following disclaimer in the
documentation and/or other materials provided with the distribution. documentation and/or other materials provided with the distribution.
This library is distributed in the hope that it will be useful, This library is distributed in the hope that it will be useful,
@ -18,7 +18,7 @@
*/ */
/* Arg_parser reads the arguments in 'argv' and creates a number of /* Arg_parser reads the arguments in 'argv' and creates a number of
option codes, option arguments and non-option arguments. option codes, option arguments, and non-option arguments.
In case of error, 'error' returns a non-empty error message. In case of error, 'error' returns a non-empty error message.
@ -61,6 +61,7 @@ private:
explicit Record( const char * const arg ) : code( 0 ), argument( arg ) {} explicit Record( const char * const arg ) : code( 0 ), argument( arg ) {}
}; };
const std::string empty_arg;
std::string error_; std::string error_;
std::vector< Record > data; std::vector< Record > data;
@ -73,17 +74,17 @@ public:
Arg_parser( const int argc, const char * const argv[], Arg_parser( const int argc, const char * const argv[],
const Option options[], const bool in_order = false ); const Option options[], const bool in_order = false );
// Restricted constructor. Parses a single token and argument (if any) // Restricted constructor. Parses a single token and argument (if any).
Arg_parser( const char * const opt, const char * const arg, Arg_parser( const char * const opt, const char * const arg,
const Option options[] ); const Option options[] );
const std::string & error() const { return error_; } const std::string & error() const { return error_; }
// The number of arguments parsed (may be different from argc) // The number of arguments parsed. May be different from argc.
int arguments() const { return data.size(); } int arguments() const { return data.size(); }
// If code( i ) is 0, argument( i ) is a non-option. /* If code( i ) is 0, argument( i ) is a non-option.
// Else argument( i ) is the option's argument (or empty). Else argument( i ) is the option's argument (or empty). */
int code( const int i ) const int code( const int i ) const
{ {
if( i >= 0 && i < arguments() ) return data[i].code; if( i >= 0 && i < arguments() ) return data[i].code;
@ -93,6 +94,6 @@ public:
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;
else return error_; else return empty_arg;
} }
}; };

25
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-2019 Antonio Diaz Diaz. # Copyright (C) 2009-2020 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.8 pkgversion=1.9
srctrigger=doc/${pkgname}.texi srctrigger=doc/${pkgname}.texi
# clear some things potentially inherited from environment. # clear some things potentially inherited from environment.
@ -28,11 +28,7 @@ DIFF=diff
GREP=grep GREP=grep
# checking whether we are using GNU C++. # checking whether we are using GNU C++.
/bin/sh -c "${CXX} --version" > /dev/null 2>&1 || /bin/sh -c "${CXX} --version" > /dev/null 2>&1 || { CXX=c++ ; CXXFLAGS=-O2 ; }
{
CXX=c++
CXXFLAGS=-O2
}
# Loop over all args # Loop over all args
args= args=
@ -44,11 +40,12 @@ while [ $# != 0 ] ; do
shift shift
# Add the argument quoted to args # Add the argument quoted to args
args="${args} \"${option}\"" if [ -z "${args}" ] ; then args="\"${option}\""
else args="${args} \"${option}\"" ; fi
# Split out the argument for options that take them # Split out the argument for options that take them
case ${option} in case ${option} in
*=*) optarg=`echo ${option} | sed -e 's,^[^=]*=,,;s,/$,,'` ;; *=*) optarg=`echo "${option}" | sed -e 's,^[^=]*=,,;s,/$,,'` ;;
esac esac
# Process the options # Process the options
@ -134,7 +131,7 @@ if [ -z "${srcdir}" ] ; then
if [ ! -r "${srcdir}/${srctrigger}" ] ; then srcdir=.. ; fi if [ ! -r "${srcdir}/${srctrigger}" ] ; then srcdir=.. ; fi
if [ ! -r "${srcdir}/${srctrigger}" ] ; then if [ ! -r "${srcdir}/${srctrigger}" ] ; then
## the sed command below emulates the dirname command ## the sed command below emulates the dirname command
srcdir=`echo $0 | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` srcdir=`echo "$0" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
fi fi
fi fi
@ -157,7 +154,7 @@ if [ -z "${no_create}" ] ; then
# Run this file to recreate the current configuration. # Run this file to recreate the current configuration.
# #
# 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.
exec /bin/sh $0 ${args} --no-create exec /bin/sh $0 ${args} --no-create
EOF EOF
@ -182,11 +179,11 @@ 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-2019 Antonio Diaz Diaz. # Copyright (C) 2009-2020 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
# to copy, distribute and modify it. # to copy, distribute, and modify it.
pkgname = ${pkgname} pkgname = ${pkgname}
pkgversion = ${pkgversion} pkgversion = ${pkgversion}

View file

@ -1,27 +1,29 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.1. .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.1.
.TH ZCAT "1" "January 2019" "zcat (zutils) 1.8" "User Commands" .TH ZCAT "1" "June 2020" "zcat (zutils) 1.9" "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
.B zcat .B zcat
[\fI\,options\/\fR] [\fI\,files\/\fR] [\fI\,options\/\fR] [\fI\,files\/\fR]
.SH DESCRIPTION .SH DESCRIPTION
Zcat copies each given file to standard output. If any given file is zcat copies each file argument to standard output in sequence. If any
compressed, its decompressed content is used. If a given file does not file given is compressed, its decompressed content is copied. If a file
exist, and its name does not end with one of the known extensions, zcat given does not exist, and its name does not end with one of the known
tries the compressed file names corresponding to the formats supported. extensions, zcat tries the compressed file names corresponding to the
formats supported. If a file fails to decompress, zcat continues copying the
rest of the files.
.PP .PP
If a file is specified as '\-', data are read from standard input, If a file is specified as '\-', data are read from standard input,
decompressed if needed, and sent to standard output. Data read from decompressed if needed, and sent to standard output. Data read from
standard input must be of the same type; all uncompressed or all in the standard input must be of the same type; all uncompressed or all in the
same compression format. same compressed format.
.PP .PP
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, and xz.
.PP .PP
Exit status is 0 if no errors occurred, non\-zero otherwise. Exit status is 0 if no errors occurred, 1 otherwise.
.SH OPTIONS .SH OPTIONS
.TP .TP
\fB\-h\fR, \fB\-\-help\fR \fB\-h\fR, \fB\-\-help\fR
@ -52,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 given format (bz2, gz, lz, xz) force the format given (bz2, gz, lz, xz)
.TP .TP
\fB\-q\fR, \fB\-\-quiet\fR \fB\-q\fR, \fB\-\-quiet\fR
suppress all messages suppress all messages
@ -94,7 +96,7 @@ 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 2019 Antonio Diaz Diaz. Copyright \(co 2020 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.

View file

@ -1,31 +1,29 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.1. .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.1.
.TH ZCMP "1" "January 2019" "zcmp (zutils) 1.8" "User Commands" .TH ZCMP "1" "June 2020" "zcmp (zutils) 1.9" "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
.B zcmp .B zcmp
[\fI\,options\/\fR] \fI\,file1 \/\fR[\fI\,file2\/\fR] [\fI\,options\/\fR] \fI\,file1 \/\fR[\fI\,file2\/\fR]
.SH DESCRIPTION .SH DESCRIPTION
Zcmp compares two files ('\-' means standard input), and if they differ, zcmp compares two files and, if they differ, writes to standard output the
tells the first byte and line number where they differ. Bytes and lines first byte and line number where they differ. Bytes and lines are numbered
are numbered starting with 1. If any given file is compressed, its starting with 1. A hyphen '\-' used as a file argument means standard input.
decompressed content is used. Compressed files are decompressed on the If any file given is compressed, its decompressed content is used. Compressed
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, and xz.
.PP .PP
Zcmp compares file1 to file2. If file2 is omitted zcmp tries the 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
following: following:
.IP .IP
1. If file1 is compressed, compares its decompressed contents with \- If file1 is compressed, compares its decompressed contents with
the corresponding uncompressed file (the name of file1 with the the corresponding uncompressed file (the name of file1 with the
extension removed). extension removed).
.IP .IP
2. 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|xz] (the first one that is found).
.IP
3. If no suitable file is found, compares file1 with data read from
standard input.
.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
@ -55,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 given formats (bz2, gz, lz, xz) force the formats given (bz2, gz, lz, xz)
.TP .TP
\fB\-q\fR, \fB\-\-quiet\fR \fB\-q\fR, \fB\-\-quiet\fR
suppress all messages suppress all messages
@ -85,7 +83,7 @@ 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 2019 Antonio Diaz Diaz. Copyright \(co 2020 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.

View file

@ -1,33 +1,32 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.1. .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.1.
.TH ZDIFF "1" "January 2019" "zdiff (zutils) 1.8" "User Commands" .TH ZDIFF "1" "June 2020" "zdiff (zutils) 1.9" "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
.B zdiff .B zdiff
[\fI\,options\/\fR] \fI\,file1 \/\fR[\fI\,file2\/\fR] [\fI\,options\/\fR] \fI\,file1 \/\fR[\fI\,file2\/\fR]
.SH DESCRIPTION .SH DESCRIPTION
Zdiff compares two files ('\-' means standard input), and if they zdiff compares two files and, if they differ, writes to standard output the
differ, shows the differences line by line. If any given file is differences line by line. A hyphen '\-' used as a file argument means standard
compressed, its decompressed content is used. Zdiff is a front end to input. If any file given is compressed, its decompressed content is used.
the diff program and has the limitation that messages from diff refer to zdiff is a front end to the program diff and has the limitation that messages
temporary filenames 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. The formats supported are bzip2, gzip, lzip, and xz.
.PP .PP
Zdiff compares file1 to file2. If file2 is omitted zdiff tries the 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
following: following:
.IP .IP
1. If file1 is compressed, compares its decompressed contents with \- If file1 is compressed, compares its decompressed contents with
the corresponding uncompressed file (the name of file1 with the the corresponding uncompressed file (the name of file1 with the
extension removed). extension removed).
.IP .IP
2. 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|xz] (the first one that is found).
.IP
3. If no suitable file is found, compares file1 with data read from
standard input.
.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.
.SH OPTIONS .SH OPTIONS
.TP .TP
\fB\-h\fR, \fB\-\-help\fR \fB\-h\fR, \fB\-\-help\fR
@ -67,7 +66,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 given formats (bz2, gz, lz, xz) force the formats given (bz2, gz, lz, xz)
.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
@ -93,6 +92,12 @@ same as \fB\-u\fR but use <n> lines of context
\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
\fB\-W\fR, \fB\-\-width=\fR<n>
output at most <n> print columns
.TP
\fB\-y\fR, \fB\-\-side\-by\-side\fR
output in two columns
.TP
\fB\-\-bz2=\fR<command> \fB\-\-bz2=\fR<command>
set compressor and options for bzip2 format set compressor and options for bzip2 format
.TP .TP
@ -109,7 +114,7 @@ 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 2019 Antonio Diaz Diaz. Copyright \(co 2020 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.

View file

@ -1,29 +1,31 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.1. .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.1.
.TH ZGREP "1" "January 2019" "zgrep (zutils) 1.8" "User Commands" .TH ZGREP "1" "June 2020" "zgrep (zutils) 1.9" "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
.B zgrep .B zgrep
[\fI\,options\/\fR] \fI\,<pattern> \/\fR[\fI\,files\/\fR] [\fI\,options\/\fR] \fI\,<pattern> \/\fR[\fI\,files\/\fR]
.SH DESCRIPTION .SH DESCRIPTION
Zgrep is a front end to the grep program that allows transparent search zgrep is a front end to the program grep that allows transparent search
on any combination of compressed and uncompressed files. If any given on any combination of compressed and uncompressed files. If any file
file is compressed, its decompressed content is used. If a given file given is compressed, its decompressed content is used. If a file given
does not exist, and its name does not end with one of the known does not exist, and its name does not end with one of the known
extensions, zgrep tries the compressed file names corresponding to the extensions, zgrep tries the compressed file names corresponding to the
formats supported. formats supported. If a file fails to decompress, zgrep continues
searching the rest of the files.
.PP .PP
If a file is specified as '\-', data are read from standard input, If a file is specified as '\-', data are read from standard input,
decompressed if needed, and fed to grep. Data read from standard input decompressed if needed, and fed to grep. Data read from standard input
must be of the same type; all uncompressed or all in the same must be of the same type; all uncompressed or all in the same
compression format. compressed format.
.PP .PP
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, and xz.
.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.
.SH OPTIONS .SH OPTIONS
.TP .TP
\fB\-\-help\fR \fB\-\-help\fR
@ -99,7 +101,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 given format (bz2, gz, lz, xz) force the format given (bz2, gz, lz, xz)
.TP .TP
\fB\-q\fR, \fB\-\-quiet\fR \fB\-q\fR, \fB\-\-quiet\fR
suppress all messages suppress all messages
@ -144,7 +146,7 @@ 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 2019 Antonio Diaz Diaz. Copyright \(co 2020 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.

View file

@ -1,20 +1,24 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.1. .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.1.
.TH ZTEST "1" "January 2019" "ztest (zutils) 1.8" "User Commands" .TH ZTEST "1" "June 2020" "ztest (zutils) 1.9" "User Commands"
.SH NAME .SH NAME
ztest \- verify the integrity of compressed files ztest \- verify the integrity of compressed files
.SH SYNOPSIS .SH SYNOPSIS
.B ztest .B ztest
[\fI\,options\/\fR] [\fI\,files\/\fR] [\fI\,options\/\fR] [\fI\,files\/\fR]
.SH DESCRIPTION .SH DESCRIPTION
Ztest verifies the integrity of the specified compressed files. ztest verifies the integrity of the compressed files specified.
Uncompressed files are ignored. If a file is specified as '\-', the Uncompressed files are ignored. If a file is specified as '\-', the
integrity of compressed data read from standard input is verified. Data integrity of compressed data read from standard input is verified. Data
read from standard input must be all in the same compression format. read from standard input must be all in the same compressed format. If
a file fails to decompress, does not exist, can't be opened, or is a
terminal, ztest continues verifying the rest of the files. A final
diagnostic is shown at verbosity level 1 or higher if any file fails the
test when testing multiple files.
.PP .PP
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, and xz.
.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
@ -41,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 given format (bz2, gz, lz, xz) force the format given (bz2, gz, lz, xz)
.TP .TP
\fB\-q\fR, \fB\-\-quiet\fR \fB\-q\fR, \fB\-\-quiet\fR
suppress all messages suppress all messages
@ -71,7 +75,7 @@ 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 2019 Antonio Diaz Diaz. Copyright \(co 2020 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.

View file

@ -1,12 +1,12 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.1. .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.1.
.TH ZUPDATE "1" "January 2019" "zupdate (zutils) 1.8" "User Commands" .TH ZUPDATE "1" "June 2020" "zupdate (zutils) 1.9" "User Commands"
.SH NAME .SH NAME
zupdate \- recompress bzip2, gzip, xz files to lzip format zupdate \- recompress bzip2, gzip, xz 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, and xz 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
@ -18,15 +18,18 @@ If no files are specified, recursive searches examine the current
working directory, and nonrecursive searches do nothing. working directory, and nonrecursive searches do nothing.
.PP .PP
If the lzip compressed version of a file already exists, the file is If the lzip compressed version of a file already exists, the file is
skipped unless the '\-\-force' option is given. In this case, if the skipped unless the option '\-\-force' is given. In this case, if the
comparison with the existing lzip version fails, an error is returned comparison with the existing lzip version fails, an error is returned
and the original file is not deleted. The operation of zupdate is meant and the original file is not deleted. The operation of zupdate is meant
to be safe and not produce 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.
.PP .PP
Exit status is 0 if all the compressed files were successfully The names of the original files must have one of the following extensions:
recompressed (if needed), compared and deleted (if requested). Non\-zero \&'.bz2', '.gz', and '.xz' are recompressed to '.lz'.
otherwise. \&'.tbz', '.tbz2', '.tgz', and '.txz' are recompressed to '.tlz'.
.PP
Exit status is 0 if all the compressed files were successfully recompressed
(if needed), compared, and deleted (if requested). Non\-zero otherwise.
.SH OPTIONS .SH OPTIONS
.TP .TP
\fB\-h\fR, \fB\-\-help\fR \fB\-h\fR, \fB\-\-help\fR
@ -42,7 +45,7 @@ don't skip a file even if the .lz exists
keep (don't delete) input files keep (don't delete) input files
.TP .TP
\fB\-l\fR, \fB\-\-lzip\-verbose\fR \fB\-l\fR, \fB\-\-lzip\-verbose\fR
pass a \fB\-v\fR option to the lzip compressor pass one option \fB\-v\fR to the lzip compressor
.TP .TP
\fB\-M\fR, \fB\-\-format=\fR<list> \fB\-M\fR, \fB\-\-format=\fR<list>
process only the formats in <list> process only the formats in <list>
@ -81,7 +84,7 @@ 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 2019 Antonio Diaz Diaz. Copyright \(co 2020 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.

View file

@ -1,5 +1,4 @@
This is zutils.info, produced by makeinfo version 4.13+ from This is zutils.info, produced by makeinfo version 4.13+ from zutils.texi.
zutils.texi.
INFO-DIR-SECTION Data Compression INFO-DIR-SECTION Data Compression
START-INFO-DIR-ENTRY START-INFO-DIR-ENTRY
@ -12,7 +11,7 @@ File: zutils.info, Node: Top, Next: Introduction, Up: (dir)
Zutils Manual Zutils Manual
************* *************
This manual is for Zutils (version 1.8, 1 January 2019). This manual is for Zutils (version 1.9, 27 June 2020).
* Menu: * Menu:
@ -29,10 +28,10 @@ This manual is for Zutils (version 1.8, 1 January 2019).
* Concept index:: Index of concepts * Concept index:: Index of concepts
Copyright (C) 2009-2019 Antonio Diaz Diaz. Copyright (C) 2009-2020 Antonio Diaz Diaz.
This manual is free documentation: you have unlimited permission to This manual is free documentation: you have unlimited permission to copy,
copy, distribute and modify it. distribute, and modify it.
 
File: zutils.info, Node: Introduction, Next: Common options, Prev: Top, Up: Top File: zutils.info, Node: Introduction, Next: Common options, Prev: Top, Up: Top
@ -41,45 +40,45 @@ File: zutils.info, Node: Introduction, Next: Common options, Prev: Top, Up:
************** **************
Zutils is a collection of utilities able to process any combination of Zutils is a collection of utilities able to process any combination of
compressed and uncompressed files transparently. If any given file, compressed and uncompressed files transparently. If any file given,
including standard input, is compressed, its decompressed content is including standard input, is compressed, its decompressed content is used.
used. Compressed files are decompressed on the fly; no temporary files Compressed files are decompressed on the fly; no temporary files are
are created. created.
These utilities are not wrapper scripts but safer and more efficient These utilities are not wrapper scripts but safer and more efficient C++
C++ programs. In particular the '--recursive' option is very efficient programs. In particular the option '--recursive' is very efficient in those
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, and xz.
Zutils uses external compressors. The compressor to be used for each Zutils uses external compressors. The compressor to be used for each format
format is configurable at runtime. is configurable at runtime.
zcat, zcmp, zdiff, and zgrep are improved replacements for the shell zcat, zcmp, zdiff, and zgrep are improved replacements for the shell
scripts provided by GNU gzip. ztest is unique to zutils. zupdate is scripts provided by GNU gzip. ztest is unique to zutils. zupdate is similar
similar to gzip's znew. to gzip's znew.
NOTE: Bzip2 and lzip provide well-defined values of exit status, NOTE: Bzip2 and lzip provide well-defined values of exit status, which
which makes them safe to use with zutils. Gzip and xz may return makes them safe to use with zutils. Gzip and xz may return ambiguous warning
ambiguous warning values, making them less reliable back ends for values, making them less reliable back ends for zutils. *Note
zutils. *Note compressor-requirements::. compressor-requirements::.
FORMAT NOTE 1: The '--format' option allows the processing of a FORMAT NOTE 1: The option '--format' allows the processing of a subset
subset of formats in recursive mode and when trying compressed file of formats in recursive mode and when trying compressed file names:
names: 'zgrep foo -r --format=bz2,lz somedir somefile.tar'. 'zgrep foo -r --format=bz2,lz somedir somefile.tar'.
FORMAT NOTE 2: If the '--force-format' option is given, the files FORMAT NOTE 2: If the option '--force-format' is given, the files are
are passed to the corresponding decompressor without verifying their passed to the corresponding decompressor without verifying their format,
format, allowing for example the processing of compress'd (.Z) files allowing for example the processing of compress'd (.Z) files with gzip:
with gzip: 'zcmp --force-format=gz file.Z file.lz'. 'zcmp --force-format=gz file.Z file.lz'.
LANGUAGE NOTE: Uncompressed = not compressed = plain data; it may LANGUAGE NOTE: Uncompressed = not compressed = plain data; it may never
never have been compressed. Decompressed is used to refer to data which have been compressed. Decompressed is used to refer to data which have
have undergone the process of decompression. undergone the process of decompression.
Numbers given as arguments to options (positions, sizes) may be Numbers given as arguments to options (positions, sizes) may be followed
followed by a multiplier and an optional 'B' for "byte". by a multiplier and an optional 'B' for "byte".
Table of SI and binary prefixes (unit multipliers): Table of SI and binary prefixes (unit multipliers):
@ -99,9 +98,9 @@ File: zutils.info, Node: Common options, Next: The zutilsrc file, Prev: Intro
2 Common options 2 Common options
**************** ****************
The following options are available in all the utilities. Rather than The following options: are available in all the utilities. Rather than
writing identical descriptions for each of the programs, they are writing identical descriptions for each of the programs, they are described
described here. here. *Note Argument syntax: (arg_parser)Argument syntax.
'-h' '-h'
'--help' '--help'
@ -110,19 +109,19 @@ described here.
'-V' '-V'
'--version' '--version'
Print the version number on the standard output and exit. This Print the version number on the standard output and exit. This version
version number should be included in all bug reports. number should be included in all bug reports.
'-M FORMAT_LIST' '-M FORMAT_LIST'
'--format=FORMAT_LIST' '--format=FORMAT_LIST'
Process only the formats listed in the comma-separated Process only the formats listed in the comma-separated FORMAT_LIST.
FORMAT_LIST. Valid formats are 'bz2', 'gz', 'lz', 'xz' and 'un' Valid formats are 'bz2', 'gz', 'lz', 'xz', and 'un' for
for 'uncompressed', meaning "any file name without a known 'uncompressed', meaning "any file name without a known extension".
extension". This option excludes files based on extension, instead This option excludes files based on extension, instead of format,
of format, because it is more efficient. The exclusion only because it is more efficient. The exclusion only applies to names
applies to names generated automatically (for example when adding generated automatically (for example when adding extensions to a file
extensions to a file name or when operating recursively on name or when operating recursively on directories). Files given in the
directories). Files given in the command line are always processed. command line are always processed.
Each format in FORMAT_LIST enables file names with the following Each format in FORMAT_LIST enables file names with the following
extensions: extensions:
@ -141,17 +140,20 @@ described here.
'--gz=COMMAND' '--gz=COMMAND'
'--lz=COMMAND' '--lz=COMMAND'
'--xz=COMMAND' '--xz=COMMAND'
Set program (may include arguments) to be used as (de)compressor Set program to be used as (de)compressor for the corresponding format.
for the given format. The name of the program can't begin with COMMAND may include arguments. For example '--lz='plzip --threads=2''.
'-'. These options override the values set in 'zutilsrc'. The The program set with '--lz' is used for both compression and
compression program used must meet three requirements: decompression. The other three are used only for decompression. The
name of the program can't begin with '-'. These options override the
values set in 'zutilsrc'. The compression program used must meet three
requirements:
1. When called with the '-d' option, it must read compressed 1. When called with the option '-d', it must read compressed data
data from the standard input and produce decompressed data on from the standard input and produce decompressed data on the
the standard output. standard output.
2. If the '-q' option is passed to zutils, the compression 2. If the option '-q' is passed to zutils, the compression program
program must also accept it. must also accept it.
3. It must return 0 if no errors occurred, and a non-zero value 3. It must return 0 if no errors occurred, and a non-zero value
otherwise. otherwise.
@ -165,22 +167,22 @@ File: zutils.info, Node: The zutilsrc file, Next: Zcat, Prev: Common options,
'zutilsrc' is the runtime configuration file for zutils. In it you may 'zutilsrc' is the runtime configuration file for zutils. In it you may
define the compressor name and options to be used for each format. The define the compressor name and options to be used for each format. The
'zutilsrc' file is optional; you don't need to install it in order to 'zutilsrc' file is optional; you don't need to install it in order to run
run zutils. zutils.
The compressors specified in the command line override those The compressors specified in the command line override those specified
specified in the 'zutilsrc' file. in the 'zutilsrc' file.
You may copy the system 'zutilsrc' file '${sysconfdir}/zutilsrc' to You may copy the system 'zutilsrc' file '${sysconfdir}/zutilsrc' to
'$HOME/.zutilsrc' and customize these options as you like. The file '$HOME/.zutilsrc' and customize these options as you like. The file syntax
syntax is fairly obvious (and there are further instructions in it): is fairly obvious (and there are further instructions in it):
1. Any line beginning with '#' is a comment line. 1. Any line beginning with '#' is a comment line.
2. Each non-comment line defines the command to be used for the given 2. Each non-comment line defines the command to be used for the
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', or 'xz'.
 
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
@ -188,26 +190,26 @@ File: zutils.info, Node: Zcat, Next: Zcmp, Prev: The zutilsrc file, Up: Top
4 Zcat 4 Zcat
****** ******
zcat copies each given file to standard output. If any given file is zcat copies each FILE argument to standard output in sequence. If any file
compressed, its decompressed content is used. If a given file does not given is compressed, its decompressed content is copied. If a file given
exist, and its name does not end with one of the known extensions, zcat does not exist, and its name does not end with one of the known extensions,
tries the compressed file names corresponding to the formats supported. zcat tries the compressed file names corresponding to the formats
If a file fails to decompress, zcat continues copying the rest of the supported. If a file fails to decompress, zcat continues copying the rest
files. of the files.
If a file is specified as '-', data are read from standard input, If a file is specified as '-', data are read from standard input,
decompressed if needed, and sent to standard output. Data read from decompressed if needed, and sent to standard output. Data read from
standard input must be of the same type; all uncompressed or all in the standard input must be of the same type; all uncompressed or all in the
same compression format. same compressed format.
If no files are specified, recursive searches examine the current If no files are specified, recursive searches examine the current working
working directory, and nonrecursive searches read standard input. directory, and nonrecursive searches read standard input.
The format for running zcat is: The format for running zcat is:
zcat [OPTIONS] [FILES] zcat [OPTIONS] [FILES]
Exit status is 0 if no errors occurred, non-zero otherwise. Exit status is 0 if no errors occurred, 1 otherwise.
zcat supports the following options: zcat supports the following options:
@ -217,8 +219,8 @@ Exit status is 0 if no errors occurred, non-zero otherwise.
'-b' '-b'
'--number-nonblank' '--number-nonblank'
Number all nonblank output lines, starting with 1. The line count Number all nonblank output lines, starting with 1. The line count is
is unlimited. unlimited.
'-e' '-e'
Equivalent to '-vE'. Equivalent to '-vE'.
@ -229,16 +231,14 @@ Exit status is 0 if no errors occurred, non-zero otherwise.
'-n' '-n'
'--number' '--number'
Number all output lines, starting with 1. The line count is Number all output lines, starting with 1. The line count is unlimited.
unlimited.
'-O FORMAT' '-O FORMAT'
'--force-format=FORMAT' '--force-format=FORMAT'
Force the given compression format. Valid values for FORMAT are Force the compressed format given. Valid values for FORMAT are 'bz2',
'bz2', 'gz', 'lz' and 'xz'. If this option is used, the files are 'gz', 'lz', and 'xz'. If this option is used, the files are passed to
passed to the corresponding decompressor without verifying their the corresponding decompressor without verifying their format, and the
format, and the exact file name must be given. Other names won't exact file name must be given. Other names won't be tried.
be tried.
'-q' '-q'
'--quiet' '--quiet'
@ -247,8 +247,8 @@ Exit status is 0 if no errors occurred, non-zero otherwise.
'-r' '-r'
'--recursive' '--recursive'
For each directory operand, read and process all files in that For each directory operand, read and process all files in that
directory, recursively. Follow symbolic links in the command line, directory, recursively. Follow symbolic links given in the command
but skip symlinks that are encountered recursively. line, but skip symbolic links that are encountered recursively.
'-R' '-R'
'--dereference-recursive' '--dereference-recursive'
@ -282,28 +282,27 @@ File: zutils.info, Node: Zcmp, Next: Zdiff, Prev: Zcat, Up: Top
5 Zcmp 5 Zcmp
****** ******
zcmp compares two files ('-' means standard input), and if they differ, zcmp compares two files and, if they differ, writes to standard output the
tells the first byte and line number where they differ. Bytes and lines first byte and line number where they differ. Bytes and lines are numbered
are numbered starting with 1. If any given file is compressed, its starting with 1. A hyphen '-' used as a FILE argument means standard input.
decompressed content is used. Compressed files are decompressed on the If any file given is compressed, its decompressed content is used.
fly; no temporary files are created. Compressed files are decompressed on the fly; no temporary files are
created.
The format for running zcmp is: The format for running zcmp is:
zcmp [OPTIONS] FILE1 [FILE2] zcmp [OPTIONS] FILE1 [FILE2]
This compares FILE1 to FILE2. If FILE2 is omitted zcmp tries the This 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
following: following:
1. If FILE1 is compressed, compares its decompressed contents with - If FILE1 is compressed, compares its decompressed contents with the
the corresponding uncompressed file (the name of FILE1 with the corresponding uncompressed file (the name of FILE1 with the extension
extension removed). removed).
2. If FILE1 is uncompressed, compares it with the decompressed - If FILE1 is uncompressed, compares it with the decompressed contents
contents of FILE1.[lz|bz2|gz|xz] (the first one that is found). of FILE1.[lz|bz2|gz|xz] (the first one that is found).
3. If no suitable file is found, compares FILE1 with data read from
standard input.
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.
@ -312,17 +311,16 @@ differences were found, and 2 means trouble.
'-b' '-b'
'--print-bytes' '--print-bytes'
Print the differing bytes. Print control bytes as a '^' followed by Print the differing bytes. Print control bytes as a '^' followed by a
a letter, and precede bytes larger than 127 with 'M-' (which stands letter, and precede bytes larger than 127 with 'M-' (which stands for
for "meta"). "meta").
'-i SIZE' '-i SIZE'
'--ignore-initial=SIZE' '--ignore-initial=SIZE'
Ignore any differences in the first SIZE bytes of the input files. Ignore any differences in the first SIZE bytes of the input files.
Treat files with fewer than SIZE bytes as if they were empty. If Treat files with fewer than SIZE bytes as if they were empty. If SIZE
SIZE is in the form 'SIZE1:SIZE2', ignore the first SIZE1 bytes of is in the form 'SIZE1:SIZE2', ignore the first SIZE1 bytes of the
the first input file and the first SIZE2 bytes of the second input first input file and the first SIZE2 bytes of the second input file.
file.
'-l' '-l'
'-v' '-v'
@ -337,20 +335,20 @@ differences were found, and 2 means trouble.
'-O [FORMAT1][,FORMAT2]' '-O [FORMAT1][,FORMAT2]'
'--force-format=[FORMAT1][,FORMAT2]' '--force-format=[FORMAT1][,FORMAT2]'
Force the given compression formats. Any of FORMAT1 or FORMAT2 may Force the compressed formats given. Any of FORMAT1 or FORMAT2 may be
be omitted and the corresponding format will be automatically omitted and the corresponding format will be automatically detected.
detected. Valid values for FORMAT are 'bz2', 'gz', 'lz' and 'xz'. Valid values for FORMAT are 'bz2', 'gz', 'lz', and 'xz'. If at least
If at least one format is specified with this option, the file is one format is specified with this option, the file is passed to the
passed to the corresponding decompressor without verifying its corresponding decompressor without verifying its format, and the exact
format, and the exact file names of both FILE1 and FILE2 must be file names of both FILE1 and FILE2 must be given. Other names won't be
given. Other names won't be tried. tried.
'-q' '-q'
'-s' '-s'
'--quiet' '--quiet'
'--silent' '--silent'
Don't print anything; only return an exit status indicating Don't print anything; only return an exit status indicating whether the
whether the files differ. files differ.
 
@ -359,34 +357,33 @@ File: zutils.info, Node: Zdiff, Next: Zgrep, Prev: Zcmp, Up: Top
6 Zdiff 6 Zdiff
******* *******
zdiff compares two files ('-' means standard input), and if they zdiff compares two files and, if they differ, writes to standard output the
differ, shows the differences line by line. If any given file is differences line by line. A hyphen '-' used as a FILE argument means
compressed, its decompressed content is used. zdiff is a front end to standard input. If any file given is compressed, its decompressed content
the diff program and has the limitation that messages from diff refer to is used. zdiff is a front end to the program diff and has the limitation
temporary file names instead of those specified. that messages from diff refer to temporary file names instead of those
specified.
The format for running zdiff is: The format for running zdiff is:
zdiff [OPTIONS] FILE1 [FILE2] zdiff [OPTIONS] FILE1 [FILE2]
This compares FILE1 to FILE2. If FILE2 is omitted zdiff tries the This 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
following: following:
1. If FILE1 is compressed, compares its decompressed contents with - If FILE1 is compressed, compares its decompressed contents with the
the corresponding uncompressed file (the name of FILE1 with the corresponding uncompressed file (the name of FILE1 with the extension
extension removed). removed).
2. If FILE1 is uncompressed, compares it with the decompressed - If FILE1 is uncompressed, compares it with the decompressed contents
contents of FILE1.[lz|bz2|gz|xz] (the first one that is found). of FILE1.[lz|bz2|gz|xz] (the first one that is found).
3. If no suitable file is found, compares FILE1 with data read from
standard input.
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.
zdiff supports the following options (some options only work if the zdiff supports the following options (some options only work if the diff
diff program used supports them): program used supports them):
'-a' '-a'
'--text' '--text'
@ -421,13 +418,13 @@ diff program used supports them):
'-O [FORMAT1][,FORMAT2]' '-O [FORMAT1][,FORMAT2]'
'--force-format=[FORMAT1][,FORMAT2]' '--force-format=[FORMAT1][,FORMAT2]'
Force the given compression formats. Any of FORMAT1 or FORMAT2 may Force the compressed formats given. Any of FORMAT1 or FORMAT2 may be
be omitted and the corresponding format will be automatically omitted and the corresponding format will be automatically detected.
detected. Valid values for FORMAT are 'bz2', 'gz', 'lz' and 'xz'. Valid values for FORMAT are 'bz2', 'gz', 'lz', and 'xz'. If at least
If at least one format is specified with this option, the file is one format is specified with this option, the file is passed to the
passed to the corresponding decompressor without verifying its corresponding decompressor without verifying its format, and the exact
format, and the exact file names of both FILE1 and FILE2 must be file names of both FILE1 and FILE2 must be given. Other names won't be
given. Other names won't be tried. tried.
'-p' '-p'
'--show-c-function' '--show-c-function'
@ -467,31 +464,29 @@ File: zutils.info, Node: Zgrep, Next: Ztest, Prev: Zdiff, Up: Top
7 Zgrep 7 Zgrep
******* *******
zgrep is a front end to the grep program that allows transparent search zgrep is a front end to the program grep that allows transparent search on
on any combination of compressed and uncompressed files. If any given any combination of compressed and uncompressed files. If any file given is
file is compressed, its decompressed content is used. If a given file compressed, its decompressed content is used. If a file given does not
does not exist, and its name does not end with one of the known exist, and its name does not end with one of the known extensions, zgrep
extensions, zgrep tries the compressed file names corresponding to the tries the compressed file names corresponding to the formats supported. If
formats supported. If a file fails to decompress, zgrep continues a file fails to decompress, zgrep continues searching the rest of the files.
searching the rest of the files.
If a file is specified as '-', data are read from standard input, If a file is specified as '-', data are read from standard input,
decompressed if needed, and fed to grep. Data read from standard input decompressed if needed, and fed to grep. Data read from standard input must
must be of the same type; all uncompressed or all in the same be of the same type; all uncompressed or all in the same compressed format.
compression format.
If no files are specified, recursive searches examine the current If no files are specified, recursive searches examine the current working
working directory, and nonrecursive searches read standard input. directory, and nonrecursive searches read standard input.
The format for running zgrep is: The format for running zgrep is:
zgrep [OPTIONS] PATTERN [FILES] zgrep [OPTIONS] PATTERN [FILES]
An exit status of 0 means at least one match was found, 1 means no An exit status of 0 means at least one match was found, 1 means no matches
matches were found, and 2 means trouble. were found, and 2 means trouble.
zgrep supports the following options (some options only work if the zgrep supports the following options (some options only work if the grep
grep program used supports them): program used supports them):
'-a' '-a'
'--text' '--text'
@ -518,7 +513,7 @@ grep program used supports them):
Print N lines of output context. Print N lines of output context.
'--color[=WHEN]' '--color[=WHEN]'
Show matched strings in color. WHEN is 'never', 'always' or 'auto'. Show matched strings in color. WHEN is 'never', 'always', or 'auto'.
'-e PATTERN' '-e PATTERN'
'--regexp=PATTERN' '--regexp=PATTERN'
@ -531,9 +526,9 @@ grep program used supports them):
'-f FILE' '-f FILE'
'--file=FILE' '--file=FILE'
Obtain patterns from FILE, one per line. Obtain patterns from FILE, one per line.
When searching in several files at once, command substitution can When searching in several files at once, command substitution can be
be used with '-e' to read FILE only once, for example if FILE is used with '-e' to read FILE only once, for example if FILE is not a
not a regular file: 'zgrep -e "$(cat FILE)" file1.lz file2.gz' regular file: 'zgrep -e "$(cat FILE)" file1.lz file2.gz'
'-F' '-F'
'--fixed-strings' '--fixed-strings'
@ -541,8 +536,8 @@ grep program used supports them):
'-h' '-h'
'--no-filename' '--no-filename'
Suppress the prefixing of file names on output when multiple files Suppress the prefixing of file names on output when multiple files are
are searched. searched.
'-H' '-H'
'--with-filename' '--with-filename'
@ -577,22 +572,21 @@ grep program used supports them):
'-O FORMAT' '-O FORMAT'
'--force-format=FORMAT' '--force-format=FORMAT'
Force the given compression format. Valid values for FORMAT are Force the compressed format given. Valid values for FORMAT are 'bz2',
'bz2', 'gz', 'lz' and 'xz'. If this option is used, the files are 'gz', 'lz', and 'xz'. If this option is used, the files are passed to
passed to the corresponding decompressor without verifying their the corresponding decompressor without verifying their format, and the
format, and the exact file name must be given. Other names won't exact file name must be given. Other names won't be tried.
be tried.
'-q' '-q'
'--quiet' '--quiet'
Suppress all messages. Exit immediately with zero status if any Suppress all messages. Exit immediately with zero status if any match
match is found, even if an error was detected. is found, even if an error was detected.
'-r' '-r'
'--recursive' '--recursive'
For each directory operand, read and process all files in that For each directory operand, read and process all files in that
directory, recursively. Follow symbolic links in the command line, directory, recursively. Follow symbolic links given in the command
but skip symlinks that are encountered recursively. line, but skip symbolic links that are encountered recursively.
'-R' '-R'
'--dereference-recursive' '--dereference-recursive'
@ -625,42 +619,43 @@ File: zutils.info, Node: Ztest, Next: Zupdate, Prev: Zgrep, Up: Top
8 Ztest 8 Ztest
******* *******
ztest verifies the integrity of the specified compressed files. ztest verifies the integrity of the compressed files specified.
Uncompressed files are ignored. If a file is specified as '-', the Uncompressed files are ignored. If a file is specified as '-', the
integrity of compressed data read from standard input is verified. Data integrity of compressed data read from standard input is verified. Data
read from standard input must be all in the same compression format. If read from standard input must be all in the same compressed format. If a
a file fails to decompress, ztest continues verifying the rest of the file fails to decompress, does not exist, can't be opened, or is a
files. terminal, ztest continues verifying the rest of the files. A final
diagnostic is shown at verbosity level 1 or higher if any file fails the
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
working directory, and nonrecursive searches read standard input. directory, and nonrecursive searches read standard input.
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 verify the integrity of all xz files. Third, section 2.1.1.2 'Stream Flags'
Flags' of the xz format specification allows xz decompressors to of the xz format specification allows xz decompressors to produce garbage
produce garbage output without issuing any warning. Therefore, xz files output without issuing any warning. Therefore, xz files can't always be
can't always be verified as reliably as files in the other formats can. verified as reliably as files in the other formats can.
The format for running ztest is: The format for running ztest is:
ztest [OPTIONS] [FILES] ztest [OPTIONS] [FILES]
The exit status is 0 if all compressed files verify OK, 1 if The exit status is 0 if all compressed files verify OK, 1 if environmental
environmental problems (file not found, invalid flags, I/O errors, etc), problems (file not found, invalid flags, I/O errors, etc), 2 if any
2 if any compressed file is corrupt or invalid. compressed file is corrupt or invalid.
ztest supports the following options: ztest supports the following options:
'-O FORMAT' '-O FORMAT'
'--force-format=FORMAT' '--force-format=FORMAT'
Force the given compression format. Valid values for FORMAT are Force the compressed format given. Valid values for FORMAT are 'bz2',
'bz2', 'gz', 'lz' and 'xz'. If this option is used, the files are 'gz', 'lz', and 'xz'. If this option is used, the files are passed to
passed to the corresponding decompressor without verifying their the corresponding decompressor without verifying their format, and any
format, and any files in a format that the decompressor can't files in a format that the decompressor can't understand will fail.
understand will fail. For example, '--force-format=gz' can test For example, '--force-format=gz' can test gzipped (.gz) and compress'd
gzipped (.gz) and compress'd (.Z) files if the compressor used is (.Z) files if the compressor used is GNU gzip.
GNU gzip.
'-q' '-q'
'--quiet' '--quiet'
@ -669,8 +664,8 @@ environmental problems (file not found, invalid flags, I/O errors, etc),
'-r' '-r'
'--recursive' '--recursive'
For each directory operand, read and process all files in that For each directory operand, read and process all files in that
directory, recursively. Follow symbolic links in the command line, directory, recursively. Follow symbolic links given in the command
but skip symlinks that are encountered recursively. line, but skip symbolic links that are encountered recursively.
'-R' '-R'
'--dereference-recursive' '--dereference-recursive'
@ -689,68 +684,69 @@ 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 zupdate recompresses files from bzip2, gzip, and xz formats to lzip format.
format. Each original is compared with the new file and then deleted. Each original is compared with the new file and then deleted. Only regular
Only regular files with standard file name extensions are recompressed, files with standard file name extensions are recompressed, other files are
other files are ignored. Compressed files are decompressed and then ignored. Compressed files are decompressed and then recompressed on the fly;
recompressed on the fly; no temporary files are created. If an error no temporary files are created. If an error happens while recompressing a
happens while recompressing a file, zupdate exits immediately without file, zupdate exits immediately without recompressing the rest of the files.
recompressing the rest of the files. The lzip format is chosen as The lzip format is chosen as destination because it is the most appropriate
destination because it is the most appropriate for long-term data for long-term data archiving.
archiving.
If no files are specified, recursive searches examine the current If no files are specified, recursive searches examine the current working
working directory, and nonrecursive searches do nothing. directory, and nonrecursive searches do nothing.
If the lzip compressed version of a file already exists, the file is If the lzip compressed version of a file already exists, the file is
skipped unless the '--force' option is given. In this case, if the skipped unless the option '--force' is given. In this case, if the
comparison with the existing lzip version fails, an error is returned comparison with the existing lzip version fails, an error is returned and
and the original file is not deleted. The operation of zupdate is meant the original file is not deleted. The operation of zupdate is meant to be
to be safe and not produce any data loss. Therefore, existing lzip safe and not cause any data loss. Therefore, existing lzip compressed files
compressed files are never overwritten nor deleted. are never overwritten nor deleted.
Combining the '--force' and '--keep' options, as in Combining the options '--force' and '--keep', as in
'zupdate -f -k *.gz', verifies that there are no differences between 'zupdate -f -k *.gz', verifies that there are no differences between each
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: '.bz2', '.tbz', '.tbz2', '.gz', '.tgz', '.xz', '.txz'. The extensions:
files produced have the extensions '.lz' or '.tar.lz'. '.bz2', '.gz', and '.xz' are recompressed to '.lz'.
'.tbz', '.tbz2', '.tgz', and '.txz' are recompressed to '.tlz'.
Keeping the combined extensions ('.tgz' -> '.tlz') may be useful when
recompressing Slackware packages, for example.
Recompressing a file is much like copying or moving it; therefore Recompressing a file is much like copying or moving it; therefore zupdate
zupdate preserves the access and modification dates, permissions, and, preserves the access and modification dates, permissions, and, when
when possible, ownership of the file just as 'cp -p' does. (If the user possible, ownership of the file just as 'cp -p' does. (If the user ID or
ID or the group ID can't be duplicated, the file permission bits S_ISUID the group ID can't be duplicated, the file permission bits S_ISUID and
and S_ISGID are cleared). S_ISGID are cleared).
The format for running zupdate is: The format for running zupdate is:
zupdate [OPTIONS] [FILES] zupdate [OPTIONS] [FILES]
Exit status is 0 if all the compressed files were successfully Exit status is 0 if all the compressed files were successfully recompressed
recompressed (if needed), compared and deleted (if requested). Non-zero (if needed), compared, and deleted (if requested). Non-zero otherwise.
otherwise.
zupdate supports the following options: zupdate supports the following options:
'-f' '-f'
'--force' '--force'
Don't skip a file for which a lzip compressed version already Don't skip a file for which a lzip compressed version already exists.
exists. '--force' compares the content of the input file with the '--force' compares the content of the input file with the content of
content of the existing lzip file and deletes the input file if the existing lzip file and deletes the input file if both contents are
both contents are identical. identical.
'-k' '-k'
'--keep' '--keep'
Keep (don't delete) the input file after comparing it with the Keep (don't delete) the input file after comparing it with the lzip
lzip file. file.
'-l' '-l'
'--lzip-verbose' '--lzip-verbose'
Pass a '-v' option to the lzip compressor so that it shows the Pass one option '-v' to the lzip compressor so that it shows the
compression ratio for each file processed. Using lzip 1.15 and compression ratio for each file processed. Using lzip 1.15 or newer, a
newer, a second '-l' shows the progress of compression. Use it second '-l' shows the progress of compression. Use it together with
together with '-v' to see the name of the file. '-v' to see the name of the file.
'-q' '-q'
'--quiet' '--quiet'
@ -759,8 +755,8 @@ otherwise.
'-r' '-r'
'--recursive' '--recursive'
For each directory operand, read and process all files in that For each directory operand, read and process all files in that
directory, recursively. Follow symbolic links in the command line, directory, recursively. Follow symbolic links given in the command
but skip symlinks that are encountered recursively. line, but skip symbolic links that are encountered recursively.
'-R' '-R'
'--dereference-recursive' '--dereference-recursive'
@ -769,12 +765,13 @@ otherwise.
'-v' '-v'
'--verbose' '--verbose'
Verbose mode. Show the files being processed. A second '-v' also Verbose mode. Show the files being processed. A second '-v' also shows
shows the files being ignored. the files being ignored.
'-0 .. -9' '-0 .. -9'
Set the compression level of lzip. By default zupdate passes '-9' Set the compression level of lzip. By default zupdate passes '-9' to
to lzip. lzip. Custom compression options can be passed to lzip with the option
'--lz'. For example '--lz='lzip -9 -s64MiB''.
 
@ -783,14 +780,14 @@ File: zutils.info, Node: Problems, Next: Concept index, Prev: Zupdate, Up: T
10 Reporting bugs 10 Reporting bugs
***************** *****************
There are probably bugs in zutils. There are certainly errors and There are probably bugs in zutils. There are certainly errors and omissions
omissions in this manual. If you report them, they will get fixed. If in this manual. If you report them, they will get fixed. If you don't, no
you don't, no one will ever know about them and they will remain unfixed one will ever know about them and they will remain unfixed for all
for all eternity, if not longer. eternity, if not longer.
If you find a bug in zutils, please send electronic mail to If you find a bug in zutils, please send electronic mail to
<zutils-bug@nongnu.org>. Include the version number, which you can find <zutils-bug@nongnu.org>. Include the version number, which you can find by
by running 'zupdate --version'. running 'zupdate --version'.
 
File: zutils.info, Node: Concept index, Prev: Problems, Up: Top File: zutils.info, Node: Concept index, Prev: Problems, Up: Top
@ -817,18 +814,18 @@ Concept index
 
Tag Table: Tag Table:
Node: Top222 Node: Top222
Node: Introduction1149 Node: Introduction1148
Node: Common options3773 Node: Common options3773
Ref: compressor-requirements5596 Ref: compressor-requirements5844
Node: The zutilsrc file5968 Node: The zutilsrc file6216
Node: Zcat6893 Node: Zcat7149
Node: Zcmp9445 Node: Zcmp9712
Node: Zdiff11904 Node: Zdiff12202
Node: Zgrep14608 Node: Zgrep14942
Node: Ztest18603 Node: Ztest18944
Node: Zupdate20938 Node: Zupdate21451
Node: Problems24364 Node: Problems25123
Node: Concept index24898 Node: Concept index25657
 
End Tag Table End Tag Table

View file

@ -6,8 +6,8 @@
@finalout @finalout
@c %**end of header @c %**end of header
@set UPDATED 1 January 2019 @set UPDATED 27 June 2020
@set VERSION 1.8 @set VERSION 1.9
@dircategory Data Compression @dircategory Data Compression
@direntry @direntry
@ -49,53 +49,54 @@ This manual is for Zutils (version @value{VERSION}, @value{UPDATED}).
@end menu @end menu
@sp 1 @sp 1
Copyright @copyright{} 2009-2019 Antonio Diaz Diaz. Copyright @copyright{} 2009-2020 Antonio Diaz Diaz.
This manual is free documentation: you have unlimited permission This manual is free documentation: you have unlimited permission to copy,
to copy, distribute and modify it. distribute, and modify it.
@node Introduction @node Introduction
@chapter Introduction @chapter Introduction
@cindex introduction @cindex introduction
Zutils is a collection of utilities able to process any combination of @uref{http://www.nongnu.org/zutils/zutils.html,,Zutils}
compressed and uncompressed files transparently. If any given file, is a collection of utilities able to process any combination of
including standard input, is compressed, its decompressed content is compressed and uncompressed files transparently. If any file given,
used. Compressed files are decompressed on the fly; no temporary files including standard input, is compressed, its decompressed content is used.
are created. Compressed files are decompressed on the fly; no temporary files are
created.
These utilities are not wrapper scripts but safer and more efficient C++ These utilities are not wrapper scripts but safer and more efficient C++
programs. In particular the @samp{--recursive} option is very efficient programs. In particular the option @samp{--recursive} is very efficient in
in those utilities supporting it. 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, and xz.@*
Zutils uses external compressors. The compressor to be used for each Zutils uses external compressors. The compressor to be used for each format
format is configurable at runtime. is configurable at runtime.
zcat, zcmp, zdiff, and zgrep are improved replacements for the shell zcat, zcmp, zdiff, and zgrep are improved replacements for the shell scripts
scripts provided by GNU gzip. ztest is unique to zutils. zupdate is provided by GNU gzip. ztest is unique to zutils. zupdate is similar to
similar to gzip's znew. 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
makes them safe to use with zutils. Gzip and xz may return ambiguous them safe to use with zutils. Gzip and xz may return ambiguous warning
warning values, making them less reliable back ends for zutils. values, making them less reliable back ends for zutils.
@xref{compressor-requirements}. @xref{compressor-requirements}.
FORMAT NOTE 1: The @samp{--format} option allows the processing of a FORMAT NOTE 1: The option @samp{--format} allows the processing of a subset
subset of formats in recursive mode and when trying compressed file of formats in recursive mode and when trying compressed file names:
names: @w{@samp{zgrep foo -r --format=bz2,lz somedir somefile.tar}}. @w{@samp{zgrep foo -r --format=bz2,lz somedir somefile.tar}}.
FORMAT NOTE 2: If the @samp{--force-format} option is given, the files FORMAT NOTE 2: If the option @samp{--force-format} is given, the files are
are passed to the corresponding decompressor without verifying their passed to the corresponding decompressor without verifying their format,
format, allowing for example the processing of compress'd (.Z) files allowing for example the processing of compress'd (.Z) files with gzip:
with gzip: @w{@samp{zcmp --force-format=gz file.Z file.lz}}. @w{@samp{zcmp --force-format=gz file.Z file.lz}}.
LANGUAGE NOTE: Uncompressed = not compressed = plain data; it may never LANGUAGE NOTE: Uncompressed = not compressed = plain data; it may never have
have been compressed. Decompressed is used to refer to data which have been compressed. Decompressed is used to refer to data which have undergone
undergone the process of decompression. the process of decompression.
@sp 1 @sp 1
Numbers given as arguments to options (positions, sizes) may be followed Numbers given as arguments to options (positions, sizes) may be followed
@ -120,9 +121,13 @@ Table of SI and binary prefixes (unit multipliers):
@chapter Common options @chapter Common options
@cindex common options @cindex common options
The following options are available in all the utilities. Rather than The following
writing identical descriptions for each of the programs, they are @uref{http://www.nongnu.org/arg-parser/manual/arg_parser_manual.html#Argument-syntax,,options}:
described here. are available in all the utilities. Rather than writing identical
descriptions for each of the programs, they are described here.
@ifnothtml
@xref{Argument syntax,,,arg_parser}.
@end ifnothtml
@table @code @table @code
@item -h @item -h
@ -139,7 +144,7 @@ This version number should be included in all bug reports.
@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}. Valid formats are @samp{bz2}, @samp{gz}, @samp{lz}, @var{format_list}. Valid formats are @samp{bz2}, @samp{gz}, @samp{lz},
@samp{xz} and @samp{un} for @samp{uncompressed}, meaning "any file name @samp{xz}, and @samp{un} for @samp{uncompressed}, meaning "any file name
without a known extension". This option excludes files based on without a known extension". This option excludes files based on
extension, instead of format, because it is more efficient. The extension, instead of format, because it is more efficient. The
exclusion only applies to names generated automatically (for example exclusion only applies to names generated automatically (for example
@ -165,19 +170,22 @@ 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}
Set program (may include arguments) to be used as (de)compressor for the Set program to be used as (de)compressor for the corresponding format.
given format. The name of the program can't begin with @samp{-}. These @var{command} may include arguments. For example
options override the values set in @file{zutilsrc}. The compression @w{@samp{--lz='plzip --threads=2'}}. The program set with @samp{--lz} is
program used must meet three requirements: used for both compression and decompression. The other three are used only
for decompression. The name of the program can't begin with @samp{-}. These
options override the values set in @file{zutilsrc}. The compression program
used must meet three requirements:
@anchor{compressor-requirements} @anchor{compressor-requirements}
@enumerate @enumerate
@item @item
When called with the @samp{-d} option, it must read compressed data from When called with the option @samp{-d}, it must read compressed data from
the standard input and produce decompressed data on the standard output. the standard input and produce decompressed data on the standard output.
@item @item
If the @samp{-q} option is passed to zutils, the compression program If the option @samp{-q} is passed to zutils, the compression program must
must also accept it. also accept it.
@item @item
It must return 0 if no errors occurred, and a non-zero value otherwise. It must return 0 if no errors occurred, and a non-zero value otherwise.
@end enumerate @end enumerate
@ -206,12 +214,12 @@ are further instructions in it):
@item @item
Any line beginning with @samp{#} is a comment line. Any line beginning with @samp{#} is a comment line.
@item @item
Each non-comment line defines the command to be used for the given Each non-comment line defines the command to be used for the corresponding
format, with the syntax: 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}, or @samp{xz}.
@end enumerate @end enumerate
@ -219,20 +227,20 @@ where <format> is one of @samp{bz2}, @samp{gz}, @samp{lz} or @samp{xz}.
@chapter Zcat @chapter Zcat
@cindex zcat @cindex zcat
zcat copies each given file to standard output. If any given file is zcat copies each @var{file} argument to standard output in sequence. If any
compressed, its decompressed content is used. If a given file does not file given is compressed, its decompressed content is copied. If a file
exist, and its name does not end with one of the known extensions, zcat given does not exist, and its name does not end with one of the known
tries the compressed file names corresponding to the formats supported. extensions, zcat tries the compressed file names corresponding to the
If a file fails to decompress, zcat continues copying the rest of the formats supported. If a file fails to decompress, zcat continues copying the
files. rest of the files.
If a file is specified as @samp{-}, data are read from standard input, If a file is specified as @samp{-}, data are read from standard input,
decompressed if needed, and sent to standard output. Data read from decompressed if needed, and sent to standard output. Data read from
standard input must be of the same type; all uncompressed or all in the standard input must be of the same type; all uncompressed or all in the
same compression format. same compressed format.
If no files are specified, recursive searches examine the current If no files are specified, recursive searches examine the current working
working directory, and nonrecursive searches read standard input. directory, and nonrecursive searches read standard input.
The format for running zcat is: The format for running zcat is:
@ -241,7 +249,7 @@ zcat [@var{options}] [@var{files}]
@end example @end example
@noindent @noindent
Exit status is 0 if no errors occurred, non-zero otherwise. Exit status is 0 if no errors occurred, 1 otherwise.
zcat supports the following options: zcat supports the following options:
@ -268,8 +276,8 @@ 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 given compression format. 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}, and @samp{xz}. If this option is used,
the files are passed to the corresponding decompressor without verifying the files are passed to the corresponding decompressor without verifying
their format, and the exact file name must be given. Other names won't their format, and the exact file name must be given. Other names won't
be tried. be tried.
@ -280,14 +288,14 @@ Quiet operation. Suppress all messages.
@item -r @item -r
@itemx --recursive @itemx --recursive
For each directory operand, read and process all files in that For each directory operand, read and process all files in that directory,
directory, recursively. Follow symbolic links in the command line, but recursively. Follow symbolic links given in the command line, but skip
skip symlinks that are encountered recursively. symbolic links that are encountered recursively.
@item -R @item -R
@itemx --dereference-recursive @itemx --dereference-recursive
For each directory operand, read and process all files in that For each directory operand, read and process all files in that directory,
directory, recursively, following all symbolic links. recursively, following all symbolic links.
@item -s @item -s
@itemx --squeeze-blank @itemx --squeeze-blank
@ -316,11 +324,12 @@ Verbose mode. Show error messages.
@chapter Zcmp @chapter Zcmp
@cindex zcmp @cindex zcmp
zcmp compares two files (@samp{-} means standard input), and if they zcmp compares two files and, if they differ, writes to standard output the
differ, tells the first byte and line number where they differ. Bytes first byte and line number where they differ. Bytes and lines are numbered
and lines are numbered starting with 1. If any given file is compressed, starting with 1. A hyphen @samp{-} used as a @var{file} argument means
its decompressed content is used. Compressed files are decompressed on standard input. If any file given is compressed, its decompressed content is
the fly; no temporary files are created. used. Compressed files are decompressed on the fly; no temporary files are
created.
The format for running zcmp is: The format for running zcmp is:
@ -329,10 +338,11 @@ zcmp [@var{options}] @var{file1} [@var{file2}]
@end example @end example
@noindent @noindent
This compares @var{file1} to @var{file2}. If @var{file2} is omitted zcmp This compares @var{file1} to @var{file2}. The standard input is used only if
tries the following: @var{file1} or @var{file2} refers to standard input. If @var{file2} is
omitted zcmp tries the following:
@enumerate @itemize -
@item @item
If @var{file1} is compressed, compares its decompressed contents with If @var{file1} is compressed, compares its decompressed contents with
the corresponding uncompressed file (the name of @var{file1} with the the corresponding uncompressed file (the name of @var{file1} with the
@ -340,10 +350,7 @@ 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|xz] (the first one that is found).
@item @end itemize
If no suitable file is found, compares @var{file1} with data read from
standard input.
@end enumerate
@noindent @noindent
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
@ -379,10 +386,10 @@ 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 given compression formats. Any of @var{format1} or Force the compressed formats given. Any of @var{format1} or
@var{format2} may be omitted and the corresponding format will be @var{format2} may be omitted and the corresponding format will be
automatically detected. Valid values for @var{format} are @samp{bz2}, automatically detected. Valid values for @var{format} are @samp{bz2},
@samp{gz}, @samp{lz} and @samp{xz}. If at least one format is specified @samp{gz}, @samp{lz}, and @samp{xz}. If at least one format is specified
with this option, the file is passed to the corresponding decompressor with this option, the file is passed to the corresponding decompressor
without verifying its format, and the exact file names of both without verifying its format, and the exact file names of both
@var{file1} and @var{file2} must be given. Other names won't be tried. @var{file1} and @var{file2} must be given. Other names won't be tried.
@ -401,11 +408,12 @@ files differ.
@chapter Zdiff @chapter Zdiff
@cindex zdiff @cindex zdiff
zdiff compares two files (@samp{-} means standard input), and if they zdiff compares two files and, if they differ, writes to standard output the
differ, shows the differences line by line. If any given file is differences line by line. A hyphen @samp{-} used as a @var{file} argument
compressed, its decompressed content is used. zdiff is a front end to means standard input. If any file given is compressed, its decompressed
the diff program and has the limitation that messages from diff refer to content is used. zdiff is a front end to the program diff and has the
temporary file names instead of those specified. limitation that messages from diff refer to temporary file names instead of
those specified.
The format for running zdiff is: The format for running zdiff is:
@ -414,10 +422,11 @@ zdiff [@var{options}] @var{file1} [@var{file2}]
@end example @end example
@noindent @noindent
This compares @var{file1} to @var{file2}. If @var{file2} is omitted This compares @var{file1} to @var{file2}. The standard input is used only if
zdiff tries the following: @var{file1} or @var{file2} refers to standard input. If @var{file2} is
omitted zdiff tries the following:
@enumerate @itemize -
@item @item
If @var{file1} is compressed, compares its decompressed contents with If @var{file1} is compressed, compares its decompressed contents with
the corresponding uncompressed file (the name of @var{file1} with the the corresponding uncompressed file (the name of @var{file1} with the
@ -425,10 +434,7 @@ 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|xz] (the first one that is found).
@item @end itemize
If no suitable file is found, compares @var{file1} with data read from
standard input.
@end enumerate
@noindent @noindent
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
@ -471,10 +477,10 @@ 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 given compression formats. Any of @var{format1} or Force the compressed formats given. Any of @var{format1} or
@var{format2} may be omitted and the corresponding format will be @var{format2} may be omitted and the corresponding format will be
automatically detected. Valid values for @var{format} are @samp{bz2}, automatically detected. Valid values for @var{format} are @samp{bz2},
@samp{gz}, @samp{lz} and @samp{xz}. If at least one format is specified @samp{gz}, @samp{lz}, and @samp{xz}. If at least one format is specified
with this option, the file is passed to the corresponding decompressor with this option, the file is passed to the corresponding decompressor
without verifying its format, and the exact file names of both without verifying its format, and the exact file names of both
@var{file1} and @var{file2} must be given. Other names won't be tried. @var{file1} and @var{file2} must be given. Other names won't be tried.
@ -517,9 +523,9 @@ Ignore all white space.
@chapter Zgrep @chapter Zgrep
@cindex zgrep @cindex zgrep
zgrep is a front end to the grep program that allows transparent search zgrep is a front end to the program grep that allows transparent search
on any combination of compressed and uncompressed files. If any given on any combination of compressed and uncompressed files. If any file
file is compressed, its decompressed content is used. If a given file given is compressed, its decompressed content is used. If a file given
does not exist, and its name does not end with one of the known does not exist, and its name does not end with one of the known
extensions, zgrep tries the compressed file names corresponding to the extensions, zgrep tries the compressed file names corresponding to the
formats supported. If a file fails to decompress, zgrep continues formats supported. If a file fails to decompress, zgrep continues
@ -528,10 +534,10 @@ searching the rest of the files.
If a file is specified as @samp{-}, data are read from standard input, If a file is specified as @samp{-}, data are read from standard input,
decompressed if needed, and fed to grep. Data read from standard input decompressed if needed, and fed to grep. Data read from standard input
must be of the same type; all uncompressed or all in the same must be of the same type; all uncompressed or all in the same
compression format. compressed format.
If no files are specified, recursive searches examine the current If no files are specified, recursive searches examine the current working
working directory, and nonrecursive searches read standard input. directory, and nonrecursive searches read standard input.
The format for running zgrep is: The format for running zgrep is:
@ -572,7 +578,7 @@ Only print a count of matching lines per file.
Print @var{n} lines of output context. Print @var{n} lines of output context.
@item --color[=@var{when}] @item --color[=@var{when}]
Show matched strings in color. @var{when} is @samp{never}, @samp{always} Show matched strings in color. @var{when} is @samp{never}, @samp{always},
or @samp{auto}. or @samp{auto}.
@item -e @var{pattern} @item -e @var{pattern}
@ -587,9 +593,9 @@ Treat @var{pattern} as an extended regular expression.
@itemx --file=@var{file} @itemx --file=@var{file}
Obtain patterns from @var{file}, one per line.@* Obtain patterns from @var{file}, one per line.@*
When searching in several files at once, command substitution can be When searching in several files at once, command substitution can be
used with @code{-e} to read @var{file} only once, for example if used with @samp{-e} to read @var{file} only once, for example if
@var{file} is not a regular file: @var{file} is not a regular file:
@w{@code{zgrep -e "$(cat @var{file})" file1.lz file2.gz}} @w{@samp{zgrep -e "$(cat @var{file})" file1.lz file2.gz}}
@item -F @item -F
@itemx --fixed-strings @itemx --fixed-strings
@ -633,8 +639,8 @@ 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 given compression format. 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}, and @samp{xz}. If this option is used,
the files are passed to the corresponding decompressor without verifying the files are passed to the corresponding decompressor without verifying
their format, and the exact file name must be given. Other names won't their format, and the exact file name must be given. Other names won't
be tried. be tried.
@ -646,14 +652,14 @@ found, even if an error was detected.
@item -r @item -r
@itemx --recursive @itemx --recursive
For each directory operand, read and process all files in that For each directory operand, read and process all files in that directory,
directory, recursively. Follow symbolic links in the command line, but recursively. Follow symbolic links given in the command line, but skip
skip symlinks that are encountered recursively. symbolic links that are encountered recursively.
@item -R @item -R
@itemx --dereference-recursive @itemx --dereference-recursive
For each directory operand, read and process all files in that For each directory operand, read and process all files in that directory,
directory, recursively, following all symbolic links. recursively, following all symbolic links.
@item -s @item -s
@itemx --no-messages @itemx --no-messages
@ -681,15 +687,17 @@ Match only whole lines.
@chapter Ztest @chapter Ztest
@cindex ztest @cindex ztest
ztest verifies the integrity of the specified compressed files. ztest verifies the integrity of the compressed files specified.
Uncompressed files are ignored. If a file is specified as @samp{-}, the Uncompressed files are ignored. If a file is specified as @samp{-}, the
integrity of compressed data read from standard input is verified. Data integrity of compressed data read from standard input is verified. Data
read from standard input must be all in the same compression format. If read from standard input must be all in the same compressed format. If
a file fails to decompress, ztest continues verifying the rest of the a file fails to decompress, does not exist, can't be opened, or is a
files. terminal, ztest continues verifying the rest of the files. A final
diagnostic is shown at verbosity level 1 or higher if any file fails the
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
working directory, and nonrecursive searches read standard input. directory, and nonrecursive searches read standard input.
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
@ -717,13 +725,12 @@ ztest supports the following options:
@table @code @table @code
@item -O @var{format} @item -O @var{format}
@itemx --force-format=@var{format} @itemx --force-format=@var{format}
Force the given compression format. 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}, and @samp{xz}. If this option is used, the
the files are passed to the corresponding decompressor without verifying files are passed to the corresponding decompressor without verifying their
their format, and any files in a format that the decompressor can't format, and any files in a format that the decompressor can't understand
understand will fail. For example, @samp{--force-format=gz} can test will fail. For example, @samp{--force-format=gz} can test gzipped (.gz) and
gzipped (.gz) and compress'd (.Z) files if the compressor used is GNU compress'd (.Z) files if the compressor used is GNU gzip.
gzip.
@item -q @item -q
@itemx --quiet @itemx --quiet
@ -731,14 +738,14 @@ Quiet operation. Suppress all messages.
@item -r @item -r
@itemx --recursive @itemx --recursive
For each directory operand, read and process all files in that For each directory operand, read and process all files in that directory,
directory, recursively. Follow symbolic links in the command line, but recursively. Follow symbolic links given in the command line, but skip
skip symlinks that are encountered recursively. symbolic links that are encountered recursively.
@item -R @item -R
@itemx --dereference-recursive @itemx --dereference-recursive
For each directory operand, read and process all files in that For each directory operand, read and process all files in that directory,
directory, recursively, following all symbolic links. recursively, following all symbolic links.
@item -v @item -v
@itemx --verbose @itemx --verbose
@ -752,40 +759,41 @@ 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 zupdate recompresses files from bzip2, gzip, and xz formats to lzip format.
format. Each original is compared with the new file and then deleted. Each original is compared with the new file and then deleted. Only regular
Only regular files with standard file name extensions are recompressed, files with standard file name extensions are recompressed, other files are
other files are ignored. Compressed files are decompressed and then ignored. Compressed files are decompressed and then recompressed on the fly;
recompressed on the fly; no temporary files are created. If an error no temporary files are created. If an error happens while recompressing a
happens while recompressing a file, zupdate exits immediately without file, zupdate exits immediately without recompressing the rest of the files.
recompressing the rest of the files. The lzip format is chosen as The lzip format is chosen as destination because it is the most appropriate
destination because it is the most appropriate for long-term data for long-term data archiving.
archiving.
If no files are specified, recursive searches examine the current If no files are specified, recursive searches examine the current working
working directory, and nonrecursive searches do nothing. directory, and nonrecursive searches do nothing.
If the lzip compressed version of a file already exists, the file is If the lzip compressed version of a file already exists, the file is
skipped unless the @samp{--force} option is given. In this case, if the skipped unless the option @samp{--force} is given. In this case, if the
comparison with the existing lzip version fails, an error is returned comparison with the existing lzip version fails, an error is returned
and the original file is not deleted. The operation of zupdate is meant and the original file is not deleted. The operation of zupdate is meant
to be safe and not produce 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.
Combining the @samp{--force} and @samp{--keep} options, as in Combining the options @samp{--force} and @samp{--keep}, as in
@w{@code{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 The names of the original files must have one of the following extensions:@*
extensions: @samp{.bz2}, @samp{.tbz}, @samp{.tbz2}, @samp{.gz}, @samp{.bz2}, @samp{.gz}, and @samp{.xz} are recompressed to @samp{.lz}.@*
@samp{.tgz}, @samp{.xz}, @samp{.txz}. The files produced have the @samp{.tbz}, @samp{.tbz2}, @samp{.tgz}, and @samp{.txz} are recompressed to
extensions @samp{.lz} or @samp{.tar.lz}. @samp{.tlz}.@*
Keeping the combined extensions (@samp{.tgz} --> @samp{.tlz}) may be useful
when recompressing Slackware packages, for example.
Recompressing a file is much like copying or moving it; therefore Recompressing a file is much like copying or moving it; therefore zupdate
zupdate preserves the access and modification dates, permissions, and, preserves the access and modification dates, permissions, and, when
when possible, ownership of the file just as @samp{cp -p} does. (If the user possible, ownership of the file just as @samp{cp -p} does. (If the user ID or
ID or the group ID can't be duplicated, the file permission bits S_ISUID the group ID can't be duplicated, the file permission bits S_ISUID and
and S_ISGID are cleared). S_ISGID are cleared).
The format for running zupdate is: The format for running zupdate is:
@ -794,9 +802,8 @@ zupdate [@var{options}] [@var{files}]
@end example @end example
@noindent @noindent
Exit status is 0 if all the compressed files were successfully Exit status is 0 if all the compressed files were successfully recompressed
recompressed (if needed), compared and deleted (if requested). Non-zero (if needed), compared, and deleted (if requested). Non-zero otherwise.
otherwise.
zupdate supports the following options: zupdate supports the following options:
@ -814,8 +821,8 @@ Keep (don't delete) the input file after comparing it with the lzip file.
@item -l @item -l
@itemx --lzip-verbose @itemx --lzip-verbose
Pass a @samp{-v} option to the lzip compressor so that it shows the Pass one option @samp{-v} to the lzip compressor so that it shows the
compression ratio for each file processed. Using lzip 1.15 and newer, a compression ratio for each file processed. Using lzip 1.15 or newer, a
second @samp{-l} shows the progress of compression. Use it together with second @samp{-l} shows the progress of compression. Use it together with
@samp{-v} to see the name of the file. @samp{-v} to see the name of the file.
@ -825,14 +832,14 @@ Quiet operation. Suppress all messages.
@item -r @item -r
@itemx --recursive @itemx --recursive
For each directory operand, read and process all files in that For each directory operand, read and process all files in that directory,
directory, recursively. Follow symbolic links in the command line, but recursively. Follow symbolic links given in the command line, but skip
skip symlinks that are encountered recursively. symbolic links that are encountered recursively.
@item -R @item -R
@itemx --dereference-recursive @itemx --dereference-recursive
For each directory operand, read and process all files in that For each directory operand, read and process all files in that directory,
directory, recursively, following all symbolic links. recursively, following all symbolic links.
@item -v @item -v
@itemx --verbose @itemx --verbose
@ -840,8 +847,9 @@ Verbose mode. Show the files being processed. A second @samp{-v} also
shows the files being ignored. shows the files being ignored.
@item -0 .. -9 @item -0 .. -9
Set the compression level of lzip. By default zupdate passes @samp{-9} Set the compression level of lzip. By default zupdate passes @samp{-9} to
to lzip. lzip. Custom compression options can be passed to lzip with the option
@samp{--lz}. For example @w{@samp{--lz='lzip -9 -s64MiB'}}.
@end table @end table
@ -858,7 +866,7 @@ for all eternity, if not longer.
If you find a bug in zutils, please send electronic mail to If you find a bug in zutils, please send electronic mail to
@email{zutils-bug@@nongnu.org}. Include the version number, which you can @email{zutils-bug@@nongnu.org}. Include the version number, which you can
find by running @w{@code{zupdate --version}}. find by running @w{@samp{zupdate --version}}.
@node Concept index @node Concept index

18
rc.cc
View file

@ -1,5 +1,5 @@
/* Zutils - Utilities dealing with compressed files /* Zutils - Utilities dealing with compressed files
Copyright (C) 2009-2019 Antonio Diaz Diaz. Copyright (C) 2009-2020 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 = "2019"; const char * const program_year = "2020";
std::string compressor_names[num_formats] = std::string compressor_names[num_formats] =
{ "bzip2", "gzip", "lzip", "xz" }; // default compressor names { "bzip2", "gzip", "lzip", "xz" }; // default compressor names
// args to compressors, maybe empty // args to compressors read from rc or from options --[bglx]z, 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.
@ -93,10 +93,10 @@ 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. Returns 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 )
{ {
static std::string s; static std::string s;
@ -237,7 +237,7 @@ void parse_format_list( const std::string & arg )
enabled_formats[format_index] = true; enabled_formats[format_index] = true;
} }
if( error ) if( error )
{ show_error( "Bad argument for '--format' option." ); std::exit( 1 ); } { show_error( "Bad argument for option '--format'." ); std::exit( 1 ); }
} }
@ -246,7 +246,7 @@ int parse_format_type( const std::string & arg )
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 '--force-format' option." ); show_error( "Bad argument for option '--force-format'." );
std::exit( 1 ); std::exit( 1 );
} }

4
rc.h
View file

@ -1,5 +1,5 @@
/* Zutils - Utilities dealing with compressed files /* Zutils - Utilities dealing with compressed files
Copyright (C) 2009-2019 Antonio Diaz Diaz. Copyright (C) 2009-2020 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/>.
*/ */
enum { fmt_bz2, fmt_gz, fmt_lz, fmt_xz, num_formats }; enum { fmt_bz2, fmt_gz, fmt_lz, fmt_xz, 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" };
const char * const simple_extensions[num_formats] = const char * const simple_extensions[num_formats] =
{ ".bz2", ".gz", ".lz", ".xz" }; { ".bz2", ".gz", ".lz", ".xz" };

View file

@ -1,5 +1,5 @@
/* Zutils - Utilities dealing with compressed files /* Zutils - Utilities dealing with compressed files
Copyright (C) 2009-2019 Antonio Diaz Diaz. Copyright (C) 2009-2020 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,8 +15,8 @@
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 /* Returns 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 )
{ {
@ -41,12 +41,14 @@ bool test_full_name( const std::string & full_name, const struct stat * stp,
{ loop = true; break; } { loop = true; break; }
} }
if( loop ) // full_name already visited or above tree if( loop ) // full_name already visited or above tree
show_file_error( full_name.c_str(), "warning: Recursive directory loop" ); show_file_error( full_name.c_str(), "warning: Recursive directory loop." );
return !loop; // (link to) directory return !loop; // (link to) directory
} }
// Returns in input_filename the next filename. /* Returns in input_filename the next filename, or "." for stdin.
("." was chosen because it is not a valid filename).
Sets '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,
@ -56,10 +58,10 @@ bool next_filename( std::list< std::string > & filenames,
{ {
input_filename = filenames.front(); input_filename = filenames.front();
filenames.pop_front(); filenames.pop_front();
if( input_filename.empty() || input_filename == "-" ) if( input_filename == "-" )
{ {
if( ignore_stdin ) continue; if( ignore_stdin ) continue;
input_filename.clear(); return true; input_filename = "."; return true;
} }
struct stat st; struct stat st;
if( stat( input_filename.c_str(), &st ) == 0 && S_ISDIR( st.st_mode ) ) if( stat( input_filename.c_str(), &st ) == 0 && S_ISDIR( st.st_mode ) )

View file

@ -1,9 +1,9 @@
#! /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-2019 Antonio Diaz Diaz. # Copyright (C) 2009-2020 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.
LC_ALL=C LC_ALL=C
export LC_ALL export LC_ALL
@ -74,6 +74,10 @@ for i in ${extensions}; do
test_failed $LINENO $i test_failed $LINENO $i
done done
printf "LZIP\001-.............................." | "${ZCAT}" -N > /dev/null 2>&1
[ $? = 1 ] || test_failed $LINENO
printf "LZIPxxxxxx" | "${ZCAT}" -N > /dev/null || test_failed $LINENO
printf "BZh9xxxxxx" | "${ZCAT}" -N > /dev/null || test_failed $LINENO
"${ZCAT}" -N -v -s "${testdir}"/zcat_vs.dat > /dev/null || test_failed $LINENO "${ZCAT}" -N -v -s "${testdir}"/zcat_vs.dat > /dev/null || test_failed $LINENO
"${ZCAT}" -N < in > copy || test_failed $LINENO "${ZCAT}" -N < in > copy || test_failed $LINENO
cmp in copy || test_failed $LINENO cmp in copy || test_failed $LINENO
@ -91,6 +95,8 @@ cmp in copy || test_failed $LINENO
cmp in copy || test_failed $LINENO cmp in copy || test_failed $LINENO
"${ZCAT}" -N lz_only > copy || test_failed $LINENO "${ZCAT}" -N lz_only > copy || test_failed $LINENO
cmp in copy || test_failed $LINENO cmp in copy || test_failed $LINENO
cat in.lz in in in in | "${ZCAT}" -N > copy || test_failed $LINENO # tdata
cmp in copy || test_failed $LINENO
"${ZCAT}" -N in in.gz in.bz2 in.lz -- -in- -in-.lz > copy || test_failed $LINENO "${ZCAT}" -N in in.gz in.bz2 in.lz -- -in- -in-.lz > copy || test_failed $LINENO
cmp in6 copy || test_failed $LINENO cmp in6 copy || test_failed $LINENO
"${ZCAT}" -Nq in in.gz in.bz2 in.lz "${bad0_lz}" -- -in- -in-.lz > copy "${ZCAT}" -Nq in in.gz in.bz2 in.lz "${bad0_lz}" -- -in- -in-.lz > copy
@ -105,6 +111,8 @@ cmp in6 copy || test_failed $LINENO
"${ZCAT}" -N -R . > /dev/null || test_failed $LINENO "${ZCAT}" -N -R . > /dev/null || test_failed $LINENO
"${ZCAT}" -N -R > /dev/null || test_failed $LINENO "${ZCAT}" -N -R > /dev/null || test_failed $LINENO
"${ZCAT}" -Nq "" < in.lz > /dev/null
[ $? = 1 ] || test_failed $LINENO
"${ZCAT}" -Nq --format=, in.lz "${ZCAT}" -Nq --format=, in.lz
[ $? = 1 ] || test_failed $LINENO [ $? = 1 ] || test_failed $LINENO
"${ZCAT}" -Nq --format=,lz in.lz "${ZCAT}" -Nq --format=,lz in.lz
@ -132,11 +140,11 @@ printf "\ntesting zcmp-%s..." "$2"
for i in ${extensions}; do for i in ${extensions}; do
"${ZCMP}" -N in.$i || test_failed $LINENO $i "${ZCMP}" -N in.$i || test_failed $LINENO $i
"${ZCMP}" -N in in.$i || test_failed $LINENO $i "${ZCMP}" -N in in.$i || test_failed $LINENO $i
"${ZCMP}" -N -i 1kB:1000 -n 500 in6 in.$i || test_failed $LINENO $i
"${ZCMP}" -N in in.$i --force-format=,$i || test_failed $LINENO $i "${ZCMP}" -N in in.$i --force-format=,$i || test_failed $LINENO $i
"${ZCMP}" -N in.$i in || test_failed $LINENO $i "${ZCMP}" -N in.$i in || test_failed $LINENO $i
"${ZCMP}" -N -i 1KiB:1024 -n 50 in.$i in6 || test_failed $LINENO $i
"${ZCMP}" -N in.$i in --force-format=$i || test_failed $LINENO $i "${ZCMP}" -N in.$i in --force-format=$i || test_failed $LINENO $i
"${ZCMP}" -N -i 1kB:1000 -n 500 in6 in.$i || test_failed $LINENO $i
"${ZCMP}" -N -i 1KiB:1024 -n 50 in.$i in6 || test_failed $LINENO $i
done done
"${ZCMP}" -Nq in in6 "${ZCMP}" -Nq in in6
@ -153,9 +161,13 @@ done
"${ZCMP}" -N -i 0:11 -n 100 in.tar pin.tar || test_failed $LINENO "${ZCMP}" -N -i 0:11 -n 100 in.tar pin.tar || test_failed $LINENO
"${ZCMP}" -N -i 0:11 -n 1Ki in.tar pin.tar || test_failed $LINENO "${ZCMP}" -N -i 0:11 -n 1Ki in.tar pin.tar || test_failed $LINENO
"${ZCMP}" -N -i 0:11 -n 10KiB in.tar pin.tar || test_failed $LINENO "${ZCMP}" -N -i 0:11 -n 10KiB in.tar pin.tar || test_failed $LINENO
"${ZCMP}" -N - || test_failed $LINENO "${ZCMP}" -N - - || test_failed $LINENO
"${ZCMP}" -Nq -
[ $? = 2 ] || test_failed $LINENO
"${ZCMP}" -N in in || test_failed $LINENO "${ZCMP}" -N in in || test_failed $LINENO
"${ZCMP}" -N in || test_failed $LINENO "${ZCMP}" -N in || test_failed $LINENO
"${ZCMP}" -N --format=gz,bz2 in || test_failed $LINENO
"${ZCMP}" -N --format=gz in || test_failed $LINENO
"${ZCMP}" -N in.lz in.gz || test_failed $LINENO "${ZCMP}" -N in.lz in.gz || test_failed $LINENO
"${ZCMP}" -N --lz='lzip -q' in.lz in.gz || test_failed $LINENO "${ZCMP}" -N --lz='lzip -q' in.lz in.gz || test_failed $LINENO
"${ZCMP}" -N in.gz -- -in-.lz || test_failed $LINENO "${ZCMP}" -N in.gz -- -in-.lz || test_failed $LINENO
@ -166,12 +178,16 @@ done
"${ZCMP}" -N -- -in-.lz in || test_failed $LINENO "${ZCMP}" -N -- -in-.lz in || test_failed $LINENO
"${ZCMP}" -N -- -in- in || test_failed $LINENO "${ZCMP}" -N -- -in- in || test_failed $LINENO
"${ZCMP}" -N in -- -in- || test_failed $LINENO "${ZCMP}" -N in -- -in- || test_failed $LINENO
"${ZCMP}" -N lz_only.lz < in || test_failed $LINENO
"${ZCMP}" -N in.lz - < in || test_failed $LINENO "${ZCMP}" -N in.lz - < in || test_failed $LINENO
"${ZCMP}" -N - in.lz < in || test_failed $LINENO "${ZCMP}" -N - in.lz < in || test_failed $LINENO
"${ZCMP}" -N in - < in.lz || test_failed $LINENO "${ZCMP}" -N in - < in.lz || test_failed $LINENO
"${ZCMP}" -N - in < in.lz || test_failed $LINENO "${ZCMP}" -N - in < in.lz || test_failed $LINENO
"${ZCMP}" -N -q --force-format=lz in.lz "${ZCMP}" -N lz_only.lz - < in || test_failed $LINENO
"${ZCMP}" -Nq lz_only.lz
[ $? = 2 ] || test_failed $LINENO
"${ZCMP}" -Nq "" in
[ $? = 2 ] || test_failed $LINENO
"${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=$? r=$?
@ -184,7 +200,7 @@ r=$?
[ $? = 2 ] || test_failed $LINENO [ $? = 2 ] || test_failed $LINENO
"${ZCMP}" -Nq -n -1 in in "${ZCMP}" -Nq -n -1 in in
[ $? = 2 ] || test_failed $LINENO [ $? = 2 ] || test_failed $LINENO
"${ZCMP}" -Nq -n 100BB in in "${ZCMP}" -N -q -n 100BB in in
[ $? = 2 ] || test_failed $LINENO [ $? = 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
@ -195,16 +211,20 @@ printf "\ntesting zdiff-%s..." "$2"
for i in ${extensions}; do for i in ${extensions}; do
"${ZDIFF}" -N in.$i > /dev/null || test_failed $LINENO $i "${ZDIFF}" -N in.$i > /dev/null || test_failed $LINENO $i
"${ZDIFF}" -N in in.$i > /dev/null || test_failed $LINENO $i "${ZDIFF}" -N in in.$i > /dev/null || test_failed $LINENO $i
"${ZDIFF}" -N --force-format=,$i in in.$i > /dev/null || "${ZDIFF}" -N in in.$i --force-format=,$i > /dev/null ||
test_failed $LINENO $i test_failed $LINENO $i
"${ZDIFF}" -N in.$i in > /dev/null || test_failed $LINENO $i "${ZDIFF}" -N in.$i in > /dev/null || test_failed $LINENO $i
"${ZDIFF}" -N --force-format=$i, in.$i in > /dev/null || "${ZDIFF}" -N in.$i in --force-format=$i, > /dev/null ||
test_failed $LINENO $i test_failed $LINENO $i
done done
"${ZDIFF}" -N in in6 > /dev/null && test_failed $LINENO "${ZDIFF}" -N in in6 > /dev/null
[ $? = 1 ] || test_failed $LINENO
# GNU diff 3.0 returns 2 when binary files differ
"${ZDIFF}" -N in.tar pin.tar > /dev/null && test_failed $LINENO "${ZDIFF}" -N in.tar pin.tar > /dev/null && test_failed $LINENO
"${ZDIFF}" -N - || test_failed $LINENO "${ZDIFF}" -N - - || test_failed $LINENO
"${ZDIFF}" -N - 2> /dev/null
[ $? = 2 ] || test_failed $LINENO
"${ZDIFF}" -N in in || test_failed $LINENO "${ZDIFF}" -N in in || test_failed $LINENO
"${ZDIFF}" -N in || test_failed $LINENO "${ZDIFF}" -N in || test_failed $LINENO
"${ZDIFF}" -N --format=gz,bz2 in || test_failed $LINENO "${ZDIFF}" -N --format=gz,bz2 in || test_failed $LINENO
@ -219,14 +239,18 @@ done
"${ZDIFF}" -N -- -in-.lz in > /dev/null || test_failed $LINENO "${ZDIFF}" -N -- -in-.lz in > /dev/null || test_failed $LINENO
"${ZDIFF}" -N -- -in- in > /dev/null || test_failed $LINENO "${ZDIFF}" -N -- -in- in > /dev/null || test_failed $LINENO
"${ZDIFF}" -N in -- -in- > /dev/null || test_failed $LINENO "${ZDIFF}" -N in -- -in- > /dev/null || test_failed $LINENO
"${ZDIFF}" -N lz_only.lz < in > /dev/null || test_failed $LINENO
"${ZDIFF}" -N in.lz - < in > /dev/null || test_failed $LINENO "${ZDIFF}" -N in.lz - < in > /dev/null || test_failed $LINENO
"${ZDIFF}" -N - in.lz < in > /dev/null || test_failed $LINENO "${ZDIFF}" -N - in.lz < in > /dev/null || test_failed $LINENO
"${ZDIFF}" -N in - < in.lz > /dev/null || test_failed $LINENO "${ZDIFF}" -N in - < in.lz > /dev/null || test_failed $LINENO
"${ZDIFF}" -N - in < in.lz > /dev/null || test_failed $LINENO "${ZDIFF}" -N - in < in.lz > /dev/null || test_failed $LINENO
"${ZDIFF}" -N lz_only.lz - < in > /dev/null || test_failed $LINENO
"${ZDIFF}" -N lz_only.lz 2> /dev/null
[ $? = 2 ] || test_failed $LINENO
"${ZDIFF}" -N "" in 2> /dev/null
[ $? = 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}" -N -q --force-format=bz2 in.bz2 2> /dev/null "${ZDIFF}" -Nq --force-format=bz2 in.bz2 2> /dev/null
[ $? = 2 ] || test_failed $LINENO [ $? = 2 ] || test_failed $LINENO
"${ZDIFF}" -N -q --force-format=,lz in.lz in.bz2 > /dev/null 2>&1 "${ZDIFF}" -N -q --force-format=,lz in.lz in.bz2 > /dev/null 2>&1
r=$? r=$?
@ -237,14 +261,14 @@ r=$?
mkdir tmp2 mkdir tmp2
cat in > tmp2/a || framework_failure cat in > tmp2/a || framework_failure
cat in.lz > tmp2/a.lz || framework_failure cat in.lz > tmp2/a.lz || framework_failure
"${ZDIFF}" -N --format=bz2 tmp2/a < /dev/null > /dev/null "${ZDIFF}" -N --format=bz2 tmp2/a 2> /dev/null
[ $? = 1 ] || test_failed $LINENO [ $? = 2 ] || test_failed $LINENO
"${ZDIFF}" -N --format=gz tmp2/a < /dev/null > /dev/null "${ZDIFF}" -N --format=gz tmp2/a 2> /dev/null
[ $? = 1 ] || test_failed $LINENO [ $? = 2 ] || test_failed $LINENO
"${ZDIFF}" -N --format=lz tmp2/a.lz < /dev/null > /dev/null "${ZDIFF}" -N --format=lz tmp2/a.lz 2> /dev/null
[ $? = 1 ] || test_failed $LINENO [ $? = 2 ] || test_failed $LINENO
"${ZDIFF}" -N --format=lz tmp2/a < /dev/null || test_failed $LINENO "${ZDIFF}" -N --format=lz tmp2/a || test_failed $LINENO
"${ZDIFF}" -N --format=un tmp2/a.lz < /dev/null || test_failed $LINENO "${ZDIFF}" -N --format=un tmp2/a.lz || test_failed $LINENO
rm -r tmp2 || framework_failure rm -r tmp2 || framework_failure
@ -300,6 +324,8 @@ done
"${ZGREP}" -N "GNU" . "${ZGREP}" -N "GNU" .
[ $? = 1 ] || test_failed $LINENO [ $? = 1 ] || test_failed $LINENO
"${ZGREP}" -N "GNU" "" < in.lz 2> /dev/null
[ $? = 2 ] || test_failed $LINENO
"${ZGREP}" -N --bad-option 2> /dev/null "${ZGREP}" -N --bad-option 2> /dev/null
[ $? = 2 ] || test_failed $LINENO [ $? = 2 ] || test_failed $LINENO
"${ZGREP}" -N "GNU" -s nx_file "${ZGREP}" -N "GNU" -s nx_file
@ -336,11 +362,13 @@ done
"${ZTEST}" -Nq in.gz "${bad0_lz}" in.bz2 "${bad1_lz}" in.lz "${ZTEST}" -Nq in.gz "${bad0_lz}" in.bz2 "${bad1_lz}" in.lz
[ $? = 2 ] || test_failed $LINENO [ $? = 2 ] || test_failed $LINENO
lines=`"${ZTEST}" -N in.gz "${bad0_lz}" in.bz2 "${bad1_lz}" in.lz 2>&1 | wc -l` lines=`"${ZTEST}" -N in.gz "${bad0_lz}" in.bz2 "${bad1_lz}" in.lz 2>&1 | wc -l`
[ "${lines}" -eq 2 ] || test_failed $LINENO [ "${lines}" -eq 2 ] || test_failed $LINENO "${lines}"
lines=`"${ZTEST}" -Nv in.gz "${bad0_lz}" in.bz2 "${bad1_lz}" in.lz 2>&1 | wc -l` lines=`"${ZTEST}" -Nv in.gz "${bad0_lz}" in.bz2 "${bad1_lz}" in.lz 2>&1 | wc -l`
[ "${lines}" -eq 5 ] || test_failed $LINENO [ "${lines}" -eq 6 ] || test_failed $LINENO "${lines}"
"${ZTEST}" -Nq < in "${ZTEST}" -Nq < in
[ $? = 2 ] || test_failed $LINENO [ $? = 2 ] || test_failed $LINENO
"${ZTEST}" -Nq "" < in.lz
[ $? = 1 ] || test_failed $LINENO
dd if=in.lz bs=1000 count=1 2> /dev/null | "${ZTEST}" -N -q dd if=in.lz bs=1000 count=1 2> /dev/null | "${ZTEST}" -N -q
[ $? = 2 ] || test_failed $LINENO [ $? = 2 ] || test_failed $LINENO
"${ZTEST}" -Nq --force-format=lz in.bz2 "${ZTEST}" -Nq --force-format=lz in.bz2
@ -353,6 +381,7 @@ dd if=in.lz bs=1000 count=1 2> /dev/null | "${ZTEST}" -N -q
printf "\ntesting zupdate-%s..." "$2" printf "\ntesting zupdate-%s..." "$2"
"${ZUPDATE}" -N "" || test_failed $LINENO
cat in.bz2 > a.bz2 || framework_failure cat in.bz2 > a.bz2 || framework_failure
cat in.gz > a.gz || framework_failure cat in.gz > a.gz || framework_failure
"${ZUPDATE}" -Nq --bz2=bad_command a.bz2 "${ZUPDATE}" -Nq --bz2=bad_command a.bz2
@ -415,6 +444,24 @@ cat in.gz > a.gz || framework_failure
[ -e a.lz ] || test_failed $LINENO [ -e a.lz ] || test_failed $LINENO
rm -f a.lz || framework_failure rm -f a.lz || framework_failure
cat in.bz2 > a.tbz || framework_failure # keep combined extensions
cat in.bz2 > b.tbz2 || framework_failure
cat in.gz > c.tgz || framework_failure
"${ZUPDATE}" -N a.tbz b.tbz2 c.tgz || test_failed $LINENO
[ ! -e a.tbz ] || test_failed $LINENO
[ ! -e b.tbz2 ] || test_failed $LINENO
[ ! -e c.tgz ] || test_failed $LINENO
[ ! -e a ] || test_failed $LINENO
[ ! -e b ] || test_failed $LINENO
[ ! -e c ] || test_failed $LINENO
[ ! -e a.lz ] || test_failed $LINENO
[ ! -e b.lz ] || test_failed $LINENO
[ ! -e c.lz ] || test_failed $LINENO
[ -e a.tlz ] || test_failed $LINENO
[ -e b.tlz ] || test_failed $LINENO
[ -e c.tlz ] || test_failed $LINENO
rm -f a.tlz b.tlz c.tlz || framework_failure
cat in.bz2 > a.bz2 || framework_failure cat in.bz2 > a.bz2 || framework_failure
cat "${bad0_gz}" > b.gz || framework_failure cat "${bad0_gz}" > b.gz || framework_failure
cat in.gz > c.gz || framework_failure cat in.gz > c.gz || framework_failure
@ -434,6 +481,13 @@ cat in.bz2 > a.bz2 || framework_failure
[ -e a.lz ] || test_failed $LINENO [ -e a.lz ] || test_failed $LINENO
rm -f a.lz || framework_failure rm -f a.lz || framework_failure
cat in.gz > 'name with spaces.gz' || framework_failure
"${ZUPDATE}" -N -1 -q 'name with spaces.gz' || test_failed $LINENO
[ ! -e 'name with spaces.gz' ] || test_failed $LINENO
[ -e 'name with spaces.lz' ] || test_failed $LINENO
"${ZCMP}" -N in 'name with spaces.lz' || test_failed $LINENO
rm -f 'name with spaces.lz' || framework_failure
mkdir tmp2 mkdir tmp2
mkdir tmp2/tmp3 mkdir tmp2/tmp3
cat in.bz2 > tmp2/tmp3/a.bz2 || framework_failure cat in.bz2 > tmp2/tmp3/a.bz2 || framework_failure

74
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-2019 Antonio Diaz Diaz. Copyright (C) 2010-2020 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
@ -90,19 +90,21 @@ Line_number line_number;
void show_help() void show_help()
{ {
std::printf( "Zcat copies each given file to standard output. If any given file is\n" std::printf( "zcat copies each file argument to standard output in sequence. If any\n"
"compressed, its decompressed content is used. If a given file does not\n" "file given is compressed, its decompressed content is copied. If a file\n"
"exist, and its name does not end with one of the known extensions, zcat\n" "given does not exist, and its name does not end with one of the known\n"
"tries the compressed file names corresponding to the formats supported.\n" "extensions, zcat tries the compressed file names corresponding to the\n"
"formats supported. If a file fails to decompress, zcat continues copying the\n"
"rest of the files.\n"
"\nIf a file is specified as '-', data are read from standard input,\n" "\nIf a file is specified as '-', data are read from standard input,\n"
"decompressed if needed, and sent to standard output. Data read from\n" "decompressed if needed, and sent to standard output. Data read from\n"
"standard input must be of the same type; all uncompressed or all in the\n" "standard input must be of the same type; all uncompressed or all in the\n"
"same compression 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, and xz.\n"
"\nUsage: zcat [options] [files]\n" "\nUsage: zcat [options] [files]\n"
"\nExit status is 0 if no errors occurred, non-zero otherwise.\n" "\nExit status is 0 if no errors occurred, 1 otherwise.\n"
"\nOptions:\n" "\nOptions:\n"
" -h, --help display this help and exit\n" " -h, --help display this help and exit\n"
" -V, --version output version information and exit\n" " -V, --version output version information and exit\n"
@ -113,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 given format (bz2, gz, lz, xz)\n" " -O, --force-format=<fmt> force the format given (bz2, gz, lz, xz)\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"
@ -130,7 +132,7 @@ void show_help()
} }
int do_cat( const int infd, const int buffer_size, bool do_cat( const int infd, const int buffer_size,
uint8_t * const inbuf, uint8_t * const outbuf, uint8_t * const inbuf, uint8_t * const outbuf,
const std::string & input_filename, const std::string & input_filename,
const Cat_options & cat_options ) const Cat_options & cat_options )
@ -148,7 +150,7 @@ int do_cat( const int infd, const int buffer_size,
if( outpos >= buffer_size ) if( outpos >= buffer_size )
{ {
if( writeblock( STDOUT_FILENO, outbuf, outpos ) != outpos ) if( writeblock( STDOUT_FILENO, outbuf, outpos ) != outpos )
{ show_error( "Write error", errno ); return 1; } { show_error( "Write error", errno ); return false; }
outpos = 0; outpos = 0;
} }
if( inpos > rd ) // inbuf is empty if( inpos > rd ) // inbuf is empty
@ -157,14 +159,14 @@ int do_cat( const int infd, const int buffer_size,
if( rd != buffer_size && errno ) if( rd != buffer_size && errno )
{ {
show_file_error( input_filename.c_str(), "Read error", errno ); show_file_error( input_filename.c_str(), "Read error", errno );
return 1; return false;
} }
if( rd == 0 ) if( rd == 0 )
{ {
if( writeblock( STDOUT_FILENO, outbuf, outpos ) != outpos ) if( writeblock( STDOUT_FILENO, outbuf, outpos ) != outpos )
{ show_error( "Write error", errno ); return 1; } { show_error( "Write error", errno ); return false; }
outpos = 0; outpos = 0;
return 0; return true;
} }
inpos = 0; inpos = 0;
inbuf[rd] = '\n'; // sentinel newline inbuf[rd] = '\n'; // sentinel newline
@ -226,32 +228,27 @@ int do_cat( const int infd, const int buffer_size,
} }
int cat( int infd, const int format_index, const std::string & input_filename, bool cat( int infd, const int format_index, const std::string & input_filename,
const Cat_options & cat_options ) const Cat_options & cat_options )
{ {
enum { buffer_size = 4096, outbuf_size = (5 * buffer_size) + 256 + 1 }; enum { buffer_size = 4096, outbuf_size = (5 * buffer_size) + 256 + 1 };
// buffer with space for sentinel newline at the end // input buffer with space for sentinel newline at the end
uint8_t * const inbuf = new uint8_t[buffer_size+1]; uint8_t * const inbuf = new uint8_t[buffer_size+1];
// buffer with space for character quoting, 255-digit line number, // output buffer with space for character quoting, 255-digit line number,
// worst case flushing respect to inbuf, and a canary byte. // worst case flushing respect to inbuf, and a canary byte.
uint8_t * const outbuf = new uint8_t[outbuf_size]; uint8_t * const outbuf = new uint8_t[outbuf_size];
outbuf[outbuf_size-1] = 0; outbuf[outbuf_size-1] = 0;
int retval = 0;
Children children; Children children;
if( !set_data_feeder( input_filename, &infd, children, format_index ) ) bool error = false;
retval = 1;
else
retval = do_cat( infd, buffer_size, inbuf, outbuf,
input_filename, cat_options );
if( !good_status( children, retval == 0 ) ) retval = 1; if( !set_data_feeder( input_filename, &infd, children, format_index ) ||
!do_cat( infd, buffer_size, inbuf, outbuf, input_filename, cat_options ) )
if( retval == 0 && close( infd ) != 0 ) error = true;
{ show_close_error(); retval = 1; } if( !good_status( children, !error ) ) error = true;
if( outbuf[outbuf_size-1] != 0 ) if( !error && close( infd ) != 0 ) { show_close_error(); error = true; }
internal_error( "buffer overflow." ); if( outbuf[outbuf_size-1] != 0 ) internal_error( "buffer overflow." );
delete[] outbuf; delete[] inbuf; delete[] outbuf; delete[] inbuf;
return retval; return !error;
} }
} // end namespace } // end namespace
@ -264,8 +261,8 @@ int main( const int argc, const char * const argv[] )
int recursive = 0; // 1 = '-r', 2 = '-R' int recursive = 0; // 1 = '-r', 2 = '-R'
std::list< std::string > filenames; std::list< std::string > filenames;
Cat_options cat_options; Cat_options cat_options;
invocation_name = argv[0];
program_name = "zcat"; program_name = "zcat";
invocation_name = ( argc > 0 ) ? argv[0] : program_name;
const Arg_parser::Option options[] = const Arg_parser::Option options[] =
{ {
@ -357,16 +354,15 @@ int main( const int argc, const char * const argv[] )
if( filenames.empty() ) filenames.push_back( recursive ? "." : "-" ); if( filenames.empty() ) filenames.push_back( recursive ? "." : "-" );
std::string input_filename; std::string input_filename;
int retval = 0;
bool error = false; bool error = false;
bool stdin_used = false; bool stdin_used = false;
while( next_filename( filenames, input_filename, error, recursive ) ) while( next_filename( filenames, input_filename, error, recursive ) )
{ {
int infd; int infd;
if( input_filename.empty() ) if( input_filename == "." )
{ {
if( stdin_used ) continue; else stdin_used = true; if( stdin_used ) continue; else stdin_used = true;
infd = STDIN_FILENO; infd = STDIN_FILENO; input_filename = "-";
} }
else else
{ {
@ -374,10 +370,11 @@ int main( const int argc, const char * const argv[] )
if( infd < 0 ) { error = true; continue; } if( infd < 0 ) { error = true; continue; }
} }
const int tmp = cat( infd, format_index, input_filename, cat_options ); if( !cat( infd, format_index, input_filename, cat_options ) ) error = true;
if( tmp > retval ) retval = tmp;
if( input_filename.size() ) close( infd ); if( close( infd ) != 0 )
{ show_file_error( input_filename.c_str(), "Error closing input file",
errno ); error = true; }
} }
if( std::fclose( stdout ) != 0 ) if( std::fclose( stdout ) != 0 )
@ -385,6 +382,5 @@ int main( const int argc, const char * const argv[] )
show_error( "Error closing stdout", errno ); show_error( "Error closing stdout", errno );
error = true; error = true;
} }
if( error && retval == 0 ) retval = 1; return error;
return retval;
} }

View file

@ -1,5 +1,5 @@
/* Common code for zcat and zgrep /* Common code for zcat and zgrep
Copyright (C) 2010-2019 Antonio Diaz Diaz. Copyright (C) 2010-2020 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

48
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-2019 Antonio Diaz Diaz. Copyright (C) 2010-2020 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,22 +50,21 @@ namespace {
void show_help() void show_help()
{ {
std::printf( "Zcmp compares two files ('-' means standard input), and if they differ,\n" std::printf( "zcmp compares two files and, if they differ, writes to standard output the\n"
"tells the first byte and line number where they differ. Bytes and lines\n" "first byte and line number where they differ. Bytes and lines are numbered\n"
"are numbered starting with 1. If any given file is compressed, its\n" "starting with 1. A hyphen '-' used as a file argument means standard input.\n"
"decompressed content is used. Compressed files are decompressed on the\n" "If any file given is compressed, its decompressed content is used. Compressed\n"
"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, and xz.\n"
"\nUsage: zcmp [options] file1 [file2]\n" "\nUsage: zcmp [options] file1 [file2]\n"
"\nZcmp compares file1 to file2. If file2 is omitted zcmp tries the\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"
"following:\n" "following:\n"
"\n 1. If file1 is compressed, compares its decompressed contents with\n" "\n - If file1 is compressed, compares its decompressed contents with\n"
" 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 2. 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|xz] (the first one that is found).\n"
"\n 3. If no suitable file is found, compares file1 with data read from\n"
" standard input.\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"
@ -76,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 given formats (bz2, gz, lz, xz)\n" " -O, --force-format=[<f1>][,<f2>] force the formats given (bz2, gz, lz, xz)\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"
@ -84,7 +83,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"
"Numbers 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();
} }
@ -326,8 +325,8 @@ int main( const int argc, const char * const argv[] )
long long max_size = -1; // < 0 means unlimited size long long max_size = -1; // < 0 means unlimited size
int format_types[2] = { -1, -1 }; int format_types[2] = { -1, -1 };
bool print_bytes = false; bool print_bytes = false;
invocation_name = argv[0];
program_name = "zcmp"; program_name = "zcmp";
invocation_name = ( argc > 0 ) ? argv[0] : program_name;
const Arg_parser::Option options[] = const Arg_parser::Option options[] =
{ {
@ -403,28 +402,33 @@ int main( const int argc, const char * const argv[] )
STDIN_FILENO : open_instream( filenames[0] ); STDIN_FILENO : open_instream( filenames[0] );
if( infd[0] < 0 ) return 2; if( infd[0] < 0 ) return 2;
if( ( files == 1 && filenames[0] == "-" ) || if( files == 2 )
( files == 2 && check_identical( filenames[0].c_str(), {
filenames[1].c_str() ) ) ) if( check_identical( filenames[0].c_str(), filenames[1].c_str() ) )
{ {
if( ignore_initial[0] == ignore_initial[1] ) return 0; if( ignore_initial[0] == ignore_initial[1] ) return 0;
else { show_error( "Can't compare parts of same file." ); return 2; } else { show_error( "Can't compare parts of same file." ); return 2; }
} }
if( files == 2 )
{
infd[1] = ( filenames[1] == "-" ) ? infd[1] = ( filenames[1] == "-" ) ?
STDIN_FILENO : open_instream( filenames[1] ); STDIN_FILENO : open_instream( filenames[1] );
if( infd[1] < 0 ) return 2; if( infd[1] < 0 ) return 2;
} }
else else
{ {
if( filenames[0] == "-" )
{ show_error( "Missing operand after '-'.", 0, true ); return 2; }
if( format_types[0] >= 0 || format_types[1] >= 0 ) if( format_types[0] >= 0 || format_types[1] >= 0 )
{ show_error( "Two files must be given when format is specified.", 0, true ); { show_error( "Two files must be given when format is specified.", 0, true );
return 2; } return 2; }
filenames[1] = filenames[0]; filenames[1] = filenames[0];
infd[1] = open_other_instream( filenames[1] ); infd[1] = open_other_instream( filenames[1] );
if( infd[1] < 0 ) { infd[1] = STDIN_FILENO; filenames[1] = "-"; } if( infd[1] < 0 )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Can't find file to compare with '%s'.\n",
program_name, filenames[0].c_str() );
show_error( 0, 0, true ); return 2;
}
} }
int old_infd[2]; // copy of file descriptors of the two files int old_infd[2]; // copy of file descriptors of the two files

View file

@ -1,5 +1,5 @@
/* Common code for zcmp and zdiff /* Common code for zcmp and zdiff
Copyright (C) 2010-2019 Antonio Diaz Diaz. Copyright (C) 2010-2020 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
@ -38,10 +38,10 @@ int open_other_instream( std::string & name )
name += extension_to( eindex ); name += extension_to( eindex );
return open( name.c_str(), O_RDONLY | O_BINARY ); return open( name.c_str(), O_RDONLY | O_BINARY );
} }
if( eindex < 0 ) if( eindex < 0 ) // search compressed version
for( int i = 0; i < num_formats; ++i ) for( int i = 0; i < num_formats; ++i )
if( enabled_format( format_order[i] ) ) if( enabled_format( format_order[i] ) )
{ // search compressed version {
const std::string s( name + simple_extensions[format_order[i]] ); const std::string s( name + simple_extensions[format_order[i]] );
const int infd = open( s.c_str(), O_RDONLY | O_BINARY ); const int infd = open( s.c_str(), O_RDONLY | O_BINARY );
if( infd >= 0 ) { name = s; return infd; } if( infd >= 0 ) { name = s; return infd; }
@ -63,7 +63,7 @@ void parse_format_types2( const std::string & arg, int format_types[2] )
bool check_identical( const char * const name1, const char * const name2 ) bool check_identical( const char * const name1, const char * const name2 )
{ {
if( !std::strcmp( name1, name2 ) ) return true; if( std::strcmp( name1, name2 ) == 0 ) return true;
struct stat stat1, stat2; struct stat stat1, stat2;
if( stat( name1, &stat1 ) || stat( name2, &stat2 ) ) return false; if( stat( name1, &stat1 ) || stat( name2, &stat2 ) ) return false;
return ( stat1.st_ino == stat2.st_ino && stat1.st_dev == stat2.st_dev ); return ( stat1.st_ino == stat2.st_ino && stat1.st_dev == stat2.st_dev );

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-2019 Antonio Diaz Diaz. Copyright (C) 2010-2020 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
@ -39,6 +39,7 @@
#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 {
@ -48,23 +49,23 @@ std::string fifonames[2]; // names of the two fifos passed to diff
void show_help() void show_help()
{ {
std::printf( "Zdiff compares two files ('-' means standard input), and if they\n" std::printf( "zdiff compares two files and, if they differ, writes to standard output the\n"
"differ, shows the differences line by line. If any given file is\n" "differences line by line. A hyphen '-' used as a file argument means standard\n"
"compressed, its decompressed content is used. Zdiff is a front end to\n" "input. If any file given is compressed, its decompressed content is used.\n"
"the diff program and has the limitation that messages from diff refer to\n" "zdiff is a front end to the program diff and has the limitation that messages\n"
"temporary filenames 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" "\nThe formats supported are bzip2, gzip, lzip, and xz.\n"
"\nUsage: zdiff [options] file1 [file2]\n" "\nUsage: zdiff [options] file1 [file2]\n"
"\nZdiff compares file1 to file2. If file2 is omitted zdiff tries the\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"
"following:\n" "following:\n"
"\n 1. If file1 is compressed, compares its decompressed contents with\n" "\n - If file1 is compressed, compares its decompressed contents with\n"
" 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 2. 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|xz] (the first one that is found).\n"
"\n 3. If no suitable file is found, compares file1 with data read from\n"
" standard input.\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"
"\nOptions:\n" "\nOptions:\n"
" -h, --help display this help and exit\n" " -h, --help display this help and exit\n"
" -V, --version output version information and exit\n" " -V, --version output version information and exit\n"
@ -78,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 given formats (bz2, gz, lz, xz)\n" " -O, --force-format=[<f1>][,<f2>] force the formats given (bz2, gz, lz, xz)\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,6 +88,8 @@ void show_help()
" -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"
" -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"
" -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"
@ -112,8 +115,8 @@ extern "C" void remove_fifos()
} }
// Set fifonames[i] to "${TMPDIR}/<coded_pid>[_-]<basename(filenames[i])>" /* Set fifonames[i] to "${TMPDIR}/<coded_pid>[_-]<basename(filenames[i])>"
// and create FIFOs. and create FIFOs. */
bool set_fifonames( const std::string filenames[2] ) bool set_fifonames( const std::string filenames[2] )
{ {
enum { num_codes = 36 }; enum { num_codes = 36 };
@ -152,10 +155,10 @@ bool set_data_feeder( const std::string & filename,
const std::string & fifoname, const int infd, const std::string & fifoname, const int infd,
Children & children, int format_index ) Children & children, int format_index )
{ {
const uint8_t * magic_data = 0; uint8_t magic_data[magic_buf_size];
int magic_size = 0; int magic_size = 0;
if( format_index < 0 ) if( format_index < 0 )
format_index = test_format( infd, &magic_data, &magic_size ); format_index = test_format( infd, magic_data, &magic_size );
children.compressor_name = get_compressor_name( format_index ); children.compressor_name = get_compressor_name( format_index );
if( children.compressor_name ) // compressed if( children.compressor_name ) // compressed
@ -264,8 +267,8 @@ 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 };
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 };
invocation_name = argv[0];
program_name = "zdiff"; program_name = "zdiff";
invocation_name = ( argc > 0 ) ? argv[0] : program_name;
const Arg_parser::Option options[] = const Arg_parser::Option options[] =
{ {
@ -290,6 +293,8 @@ int main( const int argc, const char * const argv[] )
{ 'U', "unified", Arg_parser::yes }, { 'U', "unified", Arg_parser::yes },
{ '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 },
{ 'y', "side-by-side", Arg_parser::no },
{ bz2_opt, "bz2", Arg_parser::yes }, { bz2_opt, "bz2", Arg_parser::yes },
{ gz_opt, "gz", Arg_parser::yes }, { gz_opt, "gz", Arg_parser::yes },
{ lz_opt, "lz", Arg_parser::yes }, { lz_opt, "lz", Arg_parser::yes },
@ -333,6 +338,9 @@ int main( const int argc, const char * const argv[] )
diff_args.push_back( arg.c_str() ); break; diff_args.push_back( arg.c_str() ); break;
case 'V': show_version(); return 0; case 'V': show_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" );
diff_args.push_back( arg.c_str() ); break;
case 'y': diff_args.push_back( "-y" ); break;
case bz2_opt: parse_compressor( arg, fmt_bz2 ); break; case bz2_opt: parse_compressor( arg, fmt_bz2 ); break;
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;
@ -361,25 +369,30 @@ int main( const int argc, const char * const argv[] )
STDIN_FILENO : open_instream( filenames[0] ); STDIN_FILENO : open_instream( filenames[0] );
if( infd[0] < 0 ) return 2; if( infd[0] < 0 ) return 2;
if( ( files == 1 && filenames[0] == "-" ) ||
( files == 2 && check_identical( filenames[0].c_str(),
filenames[1].c_str() ) ) )
return 0;
if( files == 2 ) if( files == 2 )
{ {
if( check_identical( filenames[0].c_str(), filenames[1].c_str() ) )
return 0;
infd[1] = ( filenames[1] == "-" ) ? infd[1] = ( filenames[1] == "-" ) ?
STDIN_FILENO : open_instream( filenames[1] ); STDIN_FILENO : open_instream( filenames[1] );
if( infd[1] < 0 ) return 2; if( infd[1] < 0 ) return 2;
} }
else else
{ {
if( filenames[0] == "-" )
{ show_error( "Missing operand after '-'.", 0, true ); return 2; }
if( format_types[0] >= 0 || format_types[1] >= 0 ) if( format_types[0] >= 0 || format_types[1] >= 0 )
{ show_error( "Two files must be given when format is specified.", 0, true ); { show_error( "Two files must be given when format is specified.", 0, true );
return 2; } return 2; }
filenames[1] = filenames[0]; filenames[1] = filenames[0];
infd[1] = open_other_instream( filenames[1] ); infd[1] = open_other_instream( filenames[1] );
if( infd[1] < 0 ) { infd[1] = STDIN_FILENO; filenames[1] = "-"; } if( infd[1] < 0 )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Can't find file to compare with '%s'.\n",
program_name, filenames[0].c_str() );
show_error( 0, 0, true ); return 2;
}
} }
std::atexit( remove_fifos ); std::atexit( remove_fifos );

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-2019 Antonio Diaz Diaz. Copyright (C) 2010-2020 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
@ -47,21 +47,23 @@ namespace {
void show_help() void show_help()
{ {
std::printf( "Zgrep is a front end to the grep program that allows transparent search\n" std::printf( "zgrep is a front end to the program grep that allows transparent search\n"
"on any combination of compressed and uncompressed files. If any given\n" "on any combination of compressed and uncompressed files. If any file\n"
"file is compressed, its decompressed content is used. If a given file\n" "given is compressed, its decompressed content is used. If a file given\n"
"does not exist, and its name does not end with one of the known\n" "does not exist, and its name does not end with one of the known\n"
"extensions, zgrep tries the compressed file names corresponding to the\n" "extensions, zgrep tries the compressed file names corresponding to the\n"
"formats supported.\n" "formats supported. If a file fails to decompress, zgrep continues\n"
"searching the rest of the files.\n"
"\nIf a file is specified as '-', data are read from standard input,\n" "\nIf a file is specified as '-', data are read from standard input,\n"
"decompressed if needed, and fed to grep. Data read from standard input\n" "decompressed if needed, and fed to grep. Data read from standard input\n"
"must be of the same type; all uncompressed or all in the same\n" "must be of the same type; all uncompressed or all in the same\n"
"compression 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" "\nThe formats supported are bzip2, gzip, lzip, and xz.\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"
"\nOptions:\n" "\nOptions:\n"
" --help display this help and exit\n" " --help display this help and exit\n"
" -V, --version output version information and exit\n" " -V, --version output version information and exit\n"
@ -87,7 +89,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 given format (bz2, gz, lz, xz)\n" " -O, --force-format=<fmt> force the format given (bz2, gz, lz, xz)\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"
@ -100,7 +102,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"
"Numbers 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,15 +219,15 @@ 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 };
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'
int show_name = -1; // tri-state bool int show_name = -1; // tri-state bool
bool no_messages = false; bool no_messages = false;
std::list< std::string > filenames; std::list< std::string > filenames;
std::vector< const char * > grep_args; // args to grep, maybe empty std::vector< const char * > grep_args; // args to grep, maybe empty
std::string color_option; // needed because of optional arg std::string color_option; // needed because of optional arg
invocation_name = argv[0];
program_name = "zgrep"; program_name = "zgrep";
invocation_name = ( argc > 0 ) ? argv[0] : program_name;
const Arg_parser::Option options[] = const Arg_parser::Option options[] =
{ {
@ -365,10 +367,10 @@ int main( const int argc, const char * const argv[] )
false, no_messages ) ) false, no_messages ) )
{ {
int infd; int infd;
if( input_filename.empty() ) if( input_filename == "." )
{ {
if( stdin_used ) continue; else stdin_used = true; if( stdin_used ) continue; else stdin_used = true;
infd = STDIN_FILENO; infd = STDIN_FILENO; input_filename = "-";
} }
else else
{ {
@ -383,7 +385,9 @@ int main( const int argc, const char * const argv[] )
list_mode, show_name ); list_mode, show_name );
if( tmp == 0 || ( tmp == 2 && retval == 1 ) ) retval = tmp; if( tmp == 0 || ( tmp == 2 && retval == 1 ) ) retval = tmp;
if( input_filename.size() ) close( infd ); if( close( infd ) != 0 )
{ show_file_error( input_filename.c_str(), "Error closing input file",
errno ); error = true; }
if( retval == 0 && verbosity < 0 ) break; if( retval == 0 && verbosity < 0 ) break;
} }

View file

@ -1,5 +1,5 @@
/* Ztest - verify the integrity of compressed files /* Ztest - verify the integrity of compressed files
Copyright (C) 2010-2019 Antonio Diaz Diaz. Copyright (C) 2010-2020 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,17 @@ namespace {
void show_help() void show_help()
{ {
std::printf( "Ztest verifies the integrity of the specified compressed files.\n" std::printf( "ztest verifies the integrity of the compressed files specified.\n"
"Uncompressed files are ignored. If a file is specified as '-', the\n" "Uncompressed files are ignored. If a file is specified as '-', the\n"
"integrity of compressed data read from standard input is verified. Data\n" "integrity of compressed data read from standard input is verified. Data\n"
"read from standard input must be all in the same compression format.\n" "read from standard input must be all in the same compressed format. If\n"
"a file fails to decompress, does not exist, can't be opened, or is a\n"
"terminal, ztest continues verifying the rest of the files. A final\n"
"diagnostic is shown at verbosity level 1 or higher if any file fails the\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, and xz.\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"
@ -72,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 given format (bz2, gz, lz, xz)\n" " -O, --force-format=<fmt> force the format given (bz2, gz, lz, xz)\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"
@ -97,10 +101,10 @@ int open_instream( const std::string & input_filename )
int ztest_stdin( const int infd, int format_index, int ztest_stdin( const int infd, int format_index,
const std::vector< const char * > & ztest_args ) const std::vector< const char * > & ztest_args )
{ {
const uint8_t * magic_data = 0; uint8_t magic_data[magic_buf_size];
int magic_size = 0; int magic_size = 0;
if( format_index < 0 ) if( format_index < 0 )
format_index = test_format( infd, &magic_data, &magic_size ); format_index = test_format( infd, magic_data, &magic_size );
const char * const compressor_name = get_compressor_name( format_index ); const char * const compressor_name = get_compressor_name( format_index );
if( !compressor_name ) if( !compressor_name )
{ show_error( "Unknown data format read from stdin." ); return 2; } { show_error( "Unknown data format read from stdin." ); return 2; }
@ -161,10 +165,10 @@ int ztest_file( const int infd, int format_index,
const std::vector< const char * > & ztest_args ) const std::vector< const char * > & ztest_args )
{ {
static int disable_xz = -1; // tri-state bool static int disable_xz = -1; // tri-state bool
const uint8_t * magic_data = 0; uint8_t magic_data[magic_buf_size];
int magic_size = 0; int magic_size = 0;
if( format_index < 0 ) if( format_index < 0 )
format_index = test_format( infd, &magic_data, &magic_size ); format_index = test_format( infd, magic_data, &magic_size );
const char * const compressor_name = get_compressor_name( format_index ); const char * const compressor_name = get_compressor_name( format_index );
if( !compressor_name ) if( !compressor_name )
return 0; // ignore this file return 0; // ignore this file
@ -217,8 +221,8 @@ int main( const int argc, const char * const argv[] )
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< const char * > ztest_args; // args to ztest, maybe empty std::vector< const char * > ztest_args; // args to ztest, maybe empty
invocation_name = argv[0];
program_name = "ztest"; program_name = "ztest";
invocation_name = ( argc > 0 ) ? argv[0] : program_name;
const Arg_parser::Option options[] = const Arg_parser::Option options[] =
{ {
@ -280,16 +284,17 @@ int main( const int argc, const char * const argv[] )
if( filenames.empty() ) filenames.push_back( recursive ? "." : "-" ); if( filenames.empty() ) filenames.push_back( recursive ? "." : "-" );
std::string input_filename; std::string input_filename;
int files_tested = 0, failed_tests = 0;
int retval = 0; int retval = 0;
bool error = false; bool error = false;
bool stdin_used = false; bool stdin_used = false;
while( next_filename( filenames, input_filename, error, recursive ) ) while( next_filename( filenames, input_filename, error, recursive ) )
{ {
int infd; int infd;
if( input_filename.empty() ) if( input_filename == "." )
{ {
if( stdin_used ) continue; else stdin_used = true; if( stdin_used ) continue; else stdin_used = true;
infd = STDIN_FILENO; infd = STDIN_FILENO; input_filename = "-";
} }
else else
{ {
@ -297,13 +302,23 @@ int main( const int argc, const char * const argv[] )
if( infd < 0 ) { error = true; continue; } if( infd < 0 ) { error = true; continue; }
} }
if( isatty( infd ) ) // for example /dev/tty
{
show_file_error( input_filename == "-" ? "(stdin)" : input_filename.c_str(),
"I won't read compressed data from a terminal." );
close( infd ); error = true; continue;
}
int tmp; int tmp;
if( infd == STDIN_FILENO ) if( infd == STDIN_FILENO )
tmp = ztest_stdin( infd, format_index, ztest_args ); tmp = ztest_stdin( infd, format_index, ztest_args );
else tmp = ztest_file( infd, format_index, input_filename, ztest_args ); else tmp = ztest_file( infd, format_index, input_filename, ztest_args );
if( tmp > retval ) retval = tmp; if( tmp > retval ) retval = tmp;
++files_tested; if( tmp ) ++failed_tests;
if( input_filename.size() ) close( infd ); if( close( infd ) != 0 )
{ show_file_error( input_filename.c_str(), "Error closing input file",
errno ); error = true; }
} }
if( std::fclose( stdout ) != 0 ) // in case decompressor writes to stdout if( std::fclose( stdout ) != 0 ) // in case decompressor writes to stdout
@ -312,5 +327,9 @@ int main( const int argc, const char * const argv[] )
error = true; error = true;
} }
if( error && retval == 0 ) retval = 1; if( error && retval == 0 ) retval = 1;
if( failed_tests > 0 && verbosity >= 1 && files_tested > 1 )
std::fprintf( stderr, "%s: warning: %d %s failed the test.\n",
program_name, failed_tests,
( failed_tests == 1 ) ? "file" : "files" );
return retval; return retval;
} }

View file

@ -1,5 +1,5 @@
/* Zupdate - recompress bzip2, gzip, xz files to lzip format /* Zupdate - recompress bzip2, gzip, xz files to lzip format
Copyright (C) 2013-2019 Antonio Diaz Diaz. Copyright (C) 2013-2020 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
@ -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, and xz 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"
@ -61,21 +61,23 @@ void show_help()
"\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 do nothing.\n" "working directory, and nonrecursive searches do nothing.\n"
"\nIf the lzip compressed version of a file already exists, the file is\n" "\nIf the lzip compressed version of a file already exists, the file is\n"
"skipped unless the '--force' option is given. In this case, if the\n" "skipped unless the option '--force' is given. In this case, if the\n"
"comparison with the existing lzip version fails, an error is returned\n" "comparison with the existing lzip version fails, an error is returned\n"
"and the original file is not deleted. The operation of zupdate is meant\n" "and the original file is not deleted. The operation of zupdate is meant\n"
"to be safe and not produce 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"
"'.bz2', '.gz', and '.xz' are recompressed to '.lz'.\n"
"'.tbz', '.tbz2', '.tgz', and '.txz' 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\n" "\nExit status is 0 if all the compressed files were successfully recompressed\n"
"recompressed (if needed), compared and deleted (if requested). Non-zero\n" "(if needed), compared, and deleted (if requested). Non-zero otherwise.\n"
"otherwise.\n"
"\nOptions:\n" "\nOptions:\n"
" -h, --help display this help and exit\n" " -h, --help display this help and exit\n"
" -V, --version output version information and exit\n" " -V, --version output version information and exit\n"
" -f, --force don't skip a file even if the .lz exists\n" " -f, --force don't skip a file even if the .lz exists\n"
" -k, --keep keep (don't delete) input files\n" " -k, --keep keep (don't delete) input files\n"
" -l, --lzip-verbose pass a -v option to the lzip compressor\n" " -l, --lzip-verbose pass one option -v to the lzip compressor\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"
" -q, --quiet suppress all messages\n" " -q, --quiet suppress all messages\n"
@ -106,7 +108,7 @@ int cant_execute( const std::string & command, const int status )
} }
// Set permissions, owner and times. // Set permissions, owner, and times.
void set_permissions( const char * const rname, const struct stat & in_stats ) void set_permissions( const char * const rname, const struct stat & in_stats )
{ {
bool warning = false; bool warning = false;
@ -135,7 +137,7 @@ int zupdate_file( const std::string & name, const char * const lzip_name,
{ {
static int disable_xz = -1; // tri-state bool static int disable_xz = -1; // tri-state bool
int format_index = -1; int format_index = -1;
std::string dname; // decompressed_name std::string rname; // recompressed name
const int eindex = extension_index( name ); // search extension const int eindex = extension_index( name ); // search extension
if( eindex >= 0 ) if( eindex >= 0 )
@ -148,8 +150,9 @@ int zupdate_file( const std::string & name, const char * const lzip_name,
program_name, name.c_str(), extension_from( eindex ) ); program_name, name.c_str(), extension_from( eindex ) );
return 0; // ignore this file return 0; // ignore this file
} }
dname.assign( name, 0, name.size() - std::strlen( extension_from( eindex ) ) ); rname.assign( name, 0, name.size() - std::strlen( extension_from( eindex ) ) );
dname += extension_to( eindex ); rname += ( std::strcmp( extension_to( eindex ), ".tar" ) == 0 ) ?
".tlz" : ".lz"; // keep combined extension
} }
const char * const compressor_name = get_compressor_name( format_index ); const char * const compressor_name = get_compressor_name( format_index );
if( !compressor_name ) if( !compressor_name )
@ -176,9 +179,11 @@ int zupdate_file( const std::string & name, const char * const lzip_name,
return 1; return 1;
} }
struct stat st; struct stat st; // not used
std::string rname( dname ); rname += ".lz"; // recompressed_name const std::string rname2( rname + ".lz" ); // produced by lzip < 1.20
const bool lz_exists = ( stat( rname.c_str(), &st ) == 0 ); const bool lz_exists = ( stat( rname.c_str(), &st ) == 0 );
// don't modify an existing 'rname.lz'
const bool lz_lz_exists = ( stat( rname2.c_str(), &st ) == 0 );
if( lz_exists && !force ) if( lz_exists && !force )
{ {
if( verbosity >= 0 ) if( verbosity >= 0 )
@ -245,7 +250,7 @@ int zupdate_file( const std::string & name, const char * const lzip_name,
for( int i = 0; i < size; ++i ) argv[i+2] = lzip_args[i].c_str(); for( int i = 0; i < size; ++i ) argv[i+2] = lzip_args[i].c_str();
for( int i = 0; i < size2; ++i ) argv[i+size+2] = lzip_args2[i].c_str(); for( int i = 0; i < size2; ++i ) argv[i+size+2] = lzip_args2[i].c_str();
argv[size+size2+2] = "-o"; argv[size+size2+2] = "-o";
argv[size+size2+3] = dname.c_str(); argv[size+size2+3] = rname.c_str();
argv[size+size2+4] = 0; argv[size+size2+4] = 0;
execvp( argv[0], (char **)argv ); execvp( argv[0], (char **)argv );
} }
@ -258,7 +263,14 @@ int zupdate_file( const std::string & name, const char * const lzip_name,
close( fda[0] ); close( fda[1] ); close( fda[0] ); close( fda[1] );
int retval = wait_for_child( pid, compressor_name ); int retval = wait_for_child( pid, compressor_name );
int retval2 = wait_for_child( pid2, lzip_name ); int retval2 = wait_for_child( pid2, lzip_name );
if( retval || retval2 ) { std::remove( rname.c_str() ); return 1; } if( retval || retval2 )
{ if( !lz_lz_exists ) std::remove( rname2.c_str() ); // lzip < 1.20
std::remove( rname.c_str() ); return 1; }
if( stat( rname.c_str(), &st ) != 0 &&
( lz_lz_exists || stat( rname2.c_str(), &st ) != 0 ||
std::rename( rname2.c_str(), rname.c_str() ) != 0 ) )
{ show_file_error( rname.c_str(), "Error renaming output file", errno );
return 1; } // lzip < 1.11
set_permissions( rname.c_str(), in_stats ); set_permissions( rname.c_str(), in_stats );
} }
@ -268,11 +280,12 @@ int zupdate_file( const std::string & name, const char * const lzip_name,
std::string zcmp_command( invocation_name ); std::string zcmp_command( invocation_name );
unsigned i = zcmp_command.size(); unsigned i = zcmp_command.size();
while( i > 0 && zcmp_command[i-1] != '/' ) --i; while( i > 0 && zcmp_command[i-1] != '/' ) --i;
zcmp_command.resize( i ); zcmp_command.resize( i ); zcmp_command.insert( 0U, 1, '\'' );
zcmp_command += "zcmp "; // ${bindir}zcmp zcmp_command += "zcmp' "; // '[dir/]zcmp'
if( no_rcfile ) zcmp_command += "-N "; if( no_rcfile ) zcmp_command += "-N ";
if( verbosity < 0 ) zcmp_command += "-q "; if( verbosity < 0 ) zcmp_command += "-q ";
zcmp_command += name; zcmp_command += ' '; zcmp_command += rname; zcmp_command += '\''; zcmp_command += name;
zcmp_command += "' '"; zcmp_command += rname; zcmp_command += '\'';
int status = std::system( zcmp_command.c_str() ); int status = std::system( zcmp_command.c_str() );
if( status != 0 ) if( status != 0 )
{ if( !lz_exists ) std::remove( rname.c_str() ); { if( !lz_exists ) std::remove( rname.c_str() );
@ -301,8 +314,8 @@ int main( const int argc, const char * const argv[] )
bool force = false; bool force = false;
bool keep_input_files = false; bool keep_input_files = false;
bool no_rcfile = false; bool no_rcfile = false;
invocation_name = argv[0];
program_name = "zupdate"; program_name = "zupdate";
invocation_name = ( argc > 0 ) ? argv[0] : program_name;
const Arg_parser::Option options[] = const Arg_parser::Option options[] =
{ {

119
zutils.cc
View file

@ -1,5 +1,5 @@
/* Zutils - Utilities dealing with compressed files /* Zutils - Utilities dealing with compressed files
Copyright (C) 2009-2019 Antonio Diaz Diaz. Copyright (C) 2009-2020 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
@ -34,24 +34,21 @@
namespace { namespace {
// first magic byte must be different among formats inline bool isvalid_ds( const uint8_t ds ) // lzip valid dictionary_size
enum { bzip2_magic_size = 3, {
gzip_magic_size = 2, enum { min_dictionary_size = 1 << 12,
lzip_magic_size = 4, max_dictionary_size = 1 << 29 };
xz_magic_size = 5 }; unsigned dictionary_size = ( 1 << ( ds & 0x1F ) );
const uint8_t bzip2_magic[bzip2_magic_size] = if( dictionary_size > min_dictionary_size )
{ 0x42, 0x5A, 0x68 }; // "BZh" dictionary_size -= ( dictionary_size / 16 ) * ( ( ds >> 5 ) & 7 );
const uint8_t gzip_magic[gzip_magic_size] = return ( dictionary_size >= min_dictionary_size &&
{ 0x1F, 0x8B }; dictionary_size <= max_dictionary_size );
const uint8_t lzip_magic[lzip_magic_size] = }
{ 0x4C, 0x5A, 0x49, 0x50 }; // "LZIP"
const uint8_t xz_magic[xz_magic_size] =
{ 0xFD, 0x37, 0x7A, 0x58, 0x5A }; // 0xFD, "7zXZ"
// Returns -1 if child not terminated, 2 in case of error, or /* Returns -1 if child not terminated, 2 in case of error, or exit status of
// exit status of child process 'pid'. child process 'pid'.
// */
int child_status( const pid_t pid, const char * const name ) int child_status( const pid_t pid, const char * const name )
{ {
int status; int status;
@ -69,15 +66,16 @@ int child_status( const pid_t pid, const char * const name )
if( tmp == pid ) break; // child terminated if( tmp == pid ) break; // child terminated
} }
if( WIFEXITED( status ) ) return WEXITSTATUS( status ); if( WIFEXITED( status ) ) return WEXITSTATUS( status );
if( WIFSIGNALED( status ) && WTERMSIG( status ) == SIGPIPE ) return 0;
return 2; return 2;
} }
} // end namespace } // end namespace
// Returns the number of bytes really read. /* Returns the number of bytes really read.
// If (returned value < size) and (errno == 0), means EOF was reached. If (returned value < 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 )
{ {
int sz = 0; int sz = 0;
@ -94,9 +92,9 @@ int readblock( const int fd, uint8_t * const buf, const int size )
} }
// Returns the number of bytes really written. /* Returns the number of bytes really written.
// If (returned value < size), it is always an error. If (returned value < 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 )
{ {
int sz = 0; int sz = 0;
@ -144,8 +142,9 @@ bool good_status( const Children & children, const bool finished )
if( pid ) if( pid )
{ {
const char * const name = const char * const name =
( i & 1 ) ? children.compressor_name : "data feeder"; ( i == 0 ) ? "data feeder" : children.compressor_name;
if( !finished ) // even if compressor finished, trailing data may remain in data feeder
if( i == 0 || !finished )
{ {
const int tmp = child_status( pid, name ); const int tmp = child_status( pid, name );
if( tmp < 0 ) // child not terminated if( tmp < 0 ) // child not terminated
@ -163,10 +162,10 @@ bool good_status( const Children & children, const bool finished )
bool set_data_feeder( const std::string & filename, int * const infdp, bool set_data_feeder( const std::string & filename, int * const infdp,
Children & children, int format_index ) Children & children, int format_index )
{ {
const uint8_t * magic_data = 0; uint8_t magic_data[magic_buf_size];
int magic_size = 0; int magic_size = 0;
if( format_index < 0 ) if( format_index < 0 )
format_index = test_format( *infdp, &magic_data, &magic_size ); format_index = test_format( *infdp, magic_data, &magic_size );
children.compressor_name = get_compressor_name( format_index ); children.compressor_name = get_compressor_name( format_index );
if( children.compressor_name ) // compressed if( children.compressor_name ) // compressed
@ -247,46 +246,38 @@ bool set_data_feeder( const std::string & filename, int * const infdp,
} }
int test_format( const int infd, const uint8_t ** const magic_datap, // Returns format index or -1 if uncompressed
//
int test_format( const int infd, uint8_t magic_data[],
int * const magic_sizep ) int * const magic_sizep )
{ {
enum { buf_size = 5 }; enum { bzip2_magic_size = 3,
static uint8_t buf[buf_size]; gzip_magic_size = 2,
int i = 0; lzip_magic_size = 5,
if( readblock( infd, buf, 1 ) == 1 ) xz_magic_size = 5 };
const uint8_t bzip2_magic[bzip2_magic_size] =
{ 0x42, 0x5A, 0x68 }; // "BZh"
const uint8_t gzip_magic[gzip_magic_size] =
{ 0x1F, 0x8B };
const uint8_t lzip_magic[lzip_magic_size] =
{ 0x4C, 0x5A, 0x49, 0x50, 0x01 }; // "LZIP\001"
const uint8_t xz_magic[xz_magic_size] =
{ 0xFD, 0x37, 0x7A, 0x58, 0x5A }; // 0xFD, "7zXZ"
*magic_sizep = readblock( infd, magic_data, magic_buf_size );
if( *magic_sizep == magic_buf_size )
{ {
++i; if( std::memcmp( magic_data, bzip2_magic, bzip2_magic_size ) == 0 &&
if( buf[0] == bzip2_magic[0] ) magic_data[3] >= '1' && magic_data[3] <= '9' &&
{ std::memcmp( magic_data + 4, "1AY&SY", 6 ) == 0 )
if( readblock( infd, &buf[i], 1 ) == 1 && buf[i++] == bzip2_magic[1] && return fmt_bz2;
readblock( infd, &buf[i], 1 ) == 1 && buf[i++] == bzip2_magic[2] ) if( std::memcmp( magic_data, gzip_magic, gzip_magic_size ) == 0 )
{ *magic_datap = bzip2_magic; *magic_sizep = bzip2_magic_size; return fmt_gz;
return fmt_bz2; } 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, xz_magic, xz_magic_size ) == 0 )
return fmt_xz;
} }
else if( buf[0] == gzip_magic[0] )
{
if( readblock( infd, &buf[i], 1 ) == 1 && buf[i++] == gzip_magic[1] )
{ *magic_datap = gzip_magic; *magic_sizep = gzip_magic_size;
return fmt_gz; }
}
else if( buf[0] == lzip_magic[0] )
{
if( readblock( infd, &buf[i], 1 ) == 1 && buf[i++] == lzip_magic[1] &&
readblock( infd, &buf[i], 1 ) == 1 && buf[i++] == lzip_magic[2] &&
readblock( infd, &buf[i], 1 ) == 1 && buf[i++] == lzip_magic[3] )
{ *magic_datap = lzip_magic; *magic_sizep = lzip_magic_size;
return fmt_lz; }
}
else if( buf[0] == xz_magic[0] )
{
if( readblock( infd, &buf[i], 1 ) == 1 && buf[i++] == xz_magic[1] &&
readblock( infd, &buf[i], 1 ) == 1 && buf[i++] == xz_magic[2] &&
readblock( infd, &buf[i], 1 ) == 1 && buf[i++] == xz_magic[3] &&
readblock( infd, &buf[i], 1 ) == 1 && buf[i++] == xz_magic[4] )
{ *magic_datap = xz_magic; *magic_sizep = xz_magic_size;
return fmt_xz; }
}
}
*magic_datap = buf; *magic_sizep = i;
return -1; return -1;
} }

View file

@ -1,5 +1,5 @@
/* Zutils - Utilities dealing with compressed files /* Zutils - Utilities dealing with compressed files
Copyright (C) 2009-2019 Antonio Diaz Diaz. Copyright (C) 2009-2020 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
@ -29,7 +29,9 @@ bool good_status( const Children & children, const bool finished );
bool set_data_feeder( const std::string & filename, int * const infdp, bool set_data_feeder( const std::string & filename, int * const infdp,
Children & children, int format_index ); Children & children, int format_index );
enum { magic_buf_size = 10 }; // >= longest extended magic (bzip2)
// Returns format index or -1 if uncompressed // Returns format index or -1 if uncompressed
// //
int test_format( const int infd, const uint8_t ** const magic_datap, int test_format( const int infd, uint8_t magic_data[],
int * const magic_sizep ); int * const magic_sizep );