1
0
Fork 0

Merging upstream version 1.1~rc2.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-24 05:43:06 +01:00
parent 24e2ea3a41
commit e13f4df619
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
26 changed files with 1151 additions and 583 deletions

60
zcmp.cc
View file

@ -37,6 +37,7 @@
#include "arg_parser.h"
#include "zutils.h"
#include "rc.h"
#if CHAR_BIT != 8
#error "Environments where CHAR_BIT != 8 are not supported."
@ -57,19 +58,19 @@ void show_help()
std::printf( "Zcmp compares two files (\"-\" means standard input), and if they\n"
"differ, tells the first byte and line number where they differ. Bytes\n"
"and lines are numbered starting with 1. If any given file is compressed,\n"
"its uncompressed content is used. Compressed files are uncompressed on\n"
"its decompressed content is used. Compressed files are decompressed on\n"
"the fly; no temporary files are created.\n"
"\nThe supported formats are bzip2, gzip, lzip and xz.\n"
"\nUsage: zcmp [options] file1 [file2]\n"
"\nCompares <file1> to <file2>. If <file2> is omitted zcmp tries the\n"
"following:\n"
"If <file1> is compressed, compares <file1> to the file with the\n"
"corresponding decompressed file name (removes the extension from\n"
"<file1>).\n"
"If <file1> is not compressed, compares <file1> to the uncompressed\n"
"contents of <file1>.[lz|bz2|gz|xz] (the first one that is found).\n"
"If no suitable file is found, compares <file1> to data read from\n"
"standard input.\n"
"\n 1. If <file1> is compressed, compares its decompressed contents with\n"
" the corresponding uncompressed file (the name of <file1> with the\n"
" extension removed).\n"
"\n 2. If <file1> is uncompressed, compares it with the decompressed\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"
"\nOptions:\n"
" -h, --help display this help and exit\n"
@ -79,9 +80,14 @@ void show_help()
" -i, --ignore-initial=<n>[,<n2>] ignore differences in the first <n> bytes\n"
" -l, --list list position, value of all differing bytes\n"
" -n, --bytes=<n> compare at most <n> bytes\n"
" -N, --no-rcfile don't read runtime configuration file\n"
" -q, --quiet suppress all messages\n"
" -s, --silent (same as --quiet)\n"
" -v, --verbose verbose mode (same as --list)\n"
" --bz2=<command> set compressor and options for bzip2 format\n"
" --gz=<command> set compressor and options for gzip format\n"
" --lz=<command> set compressor and options for lzip 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"
"Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...\n" );
show_help_addr();
@ -310,7 +316,7 @@ int cmp( const long long max_size, const int infd[2],
int main( const int argc, const char * const argv[] )
{
enum { format_opt = 256 };
enum { format_opt = 256, bz2_opt, gz_opt, lz_opt, xz_opt };
// number of initial bytes ignored for each file
long long ignore_initial[2] = { 0, 0 };
long long max_size = -1; // < 0 means unlimited size
@ -326,17 +332,24 @@ int main( const int argc, const char * const argv[] )
{ 'i', "ignore-initial", Arg_parser::yes },
{ 'l', "list", Arg_parser::no },
{ 'n', "bytes", Arg_parser::yes },
{ 'N', "no-rcfile", Arg_parser::no },
{ 'q', "quiet", Arg_parser::no },
{ 's', "silent", Arg_parser::no },
{ 'v', "verbose", Arg_parser::no },
{ 'V', "version", Arg_parser::no },
{ format_opt, "format", Arg_parser::yes },
{ bz2_opt, "bz2", Arg_parser::yes },
{ gz_opt, "gz", Arg_parser::yes },
{ lz_opt, "lz", Arg_parser::yes },
{ xz_opt, "xz", Arg_parser::yes },
{ 0 , 0, Arg_parser::no } };
const Arg_parser parser( argc, argv, options );
if( parser.error().size() ) // bad option
{ show_error( parser.error().c_str(), 0, true ); return 2; }
maybe_process_config_file( parser );
int argind = 0;
for( ; argind < parser.arguments(); ++argind )
{
@ -350,11 +363,16 @@ int main( const int argc, const char * const argv[] )
case 'i': parse_ignore_initial( arg, ignore_initial ); break;
case 'l': verbosity = 1; break;
case 'n': max_size = getnum( arg ); break;
case 'N': break;
case 'q':
case 's': verbosity = -1; break;
case 'v': verbosity = 1; break;
case 'V': show_version( "Zcmp" ); return 0;
case format_opt: get_format_types( arg, format_types ); break;
case format_opt: parse_format_types( arg, format_types ); break;
case bz2_opt: parse_compressor( arg, fmt_bz2 ); break;
case gz_opt: parse_compressor( arg, fmt_gz ); break;
case lz_opt: parse_compressor( arg, fmt_lz ); break;
case xz_opt: parse_compressor( arg, fmt_xz ); break;
default : internal_error( "uncaught option" );
}
} // end process options
@ -405,9 +423,9 @@ int main( const int argc, const char * const argv[] )
int old_infd[2]; // copy of file descriptors of the two files
old_infd[0] = infd[0]; old_infd[1] = infd[1];
pid_t pid[2];
if( !set_data_feeder( &infd[0], &pid[0], format_types[0] ) ||
!set_data_feeder( &infd[1], &pid[1], format_types[1] ) )
Children children[2];
if( !set_data_feeder( &infd[0], children[0], format_types[0] ) ||
!set_data_feeder( &infd[1], children[1], format_types[1] ) )
return 2;
for( int i = 0; i < 2; ++i )
@ -419,20 +437,8 @@ int main( const int argc, const char * const argv[] )
int retval = cmp( max_size, infd, filenames, print_bytes );
if( retval != 0 || max_size >= 0 )
{
for( int i = 0; i < 2; ++i )
if( pid[i] )
{
const int tmp = child_status( pid[i], "data feeder" );
if( tmp < 0 ) kill( pid[i], SIGTERM ); // child not terminated
else if( tmp != 0 ) retval = 2; // child status != 0
}
}
else
if( ( pid[0] && wait_for_child( pid[0], "data feeder" ) != 0 ) ||
( pid[1] && wait_for_child( pid[1], "data feeder" ) != 0 ) )
retval = 2;
for( int i = 0; i < 2; ++i )
if( !good_status( children[i], retval == 0 && max_size < 0 ) ) retval = 2;
for( int i = 0; i < 2; ++i )
{