zcmp.cc (zutils-1.8.tar.lz) | : | zcmp.cc (zutils-1.9.tar.lz) | ||
---|---|---|---|---|
/* 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 | |||
the Free Software Foundation, either version 2 of the License, or | the Free Software Foundation, either version 2 of the License, or | |||
(at your option) any later version. | (at your option) any later version. | |||
This program is distributed in the hope that it will be useful, | This program is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU General Public License for more details. | GNU General Public License for more details. | |||
You should have received a copy of the GNU General Public License | You should have received a copy of the GNU General Public License | |||
along with this program. If not, see <http://www.gnu.org/licenses/>. | along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | */ | |||
#define _FILE_OFFSET_BITS 64 | #define _FILE_OFFSET_BITS 64 | |||
#include <algorithm> | #include <algorithm> | |||
#include <cctype> | #include <cctype> | |||
#include <cerrno> | #include <cerrno> | |||
#include <climits> | #include <climits> | |||
#include <csignal> | #include <csignal> | |||
#include <cstdio> | #include <cstdio> | |||
skipping to change at line 52 | skipping to change at line 52 | |||
#ifndef LLONG_MAX | #ifndef LLONG_MAX | |||
#define LLONG_MAX 0x7FFFFFFFFFFFFFFFLL | #define LLONG_MAX 0x7FFFFFFFFFFFFFFFLL | |||
#endif | #endif | |||
namespace { | namespace { | |||
#include "zcmpdiff.cc" | #include "zcmpdiff.cc" | |||
void show_help() | void show_help() | |||
{ | { | |||
std::printf( "Zcmp compares two files ('-' means standard input), and if they | std::printf( "zcmp compares two files and, if they differ, writes to standard | |||
differ,\n" | output the\n" | |||
"tells the first byte and line number where they differ. Bytes an | "first byte and line number where they differ. Bytes and lines ar | |||
d lines\n" | e numbered\n" | |||
"are numbered starting with 1. If any given file is compressed, i | "starting with 1. A hyphen '-' used as a file argument means stan | |||
ts\n" | dard input.\n" | |||
"decompressed content is used. Compressed files are decompressed | "If any file given is compressed, its decompressed content is use | |||
on the\n" | d. Compressed\n" | |||
"fly; no temporary files are created.\n" | "files are decompressed on the fly; no temporary files are create | |||
"\nThe formats supported are bzip2, gzip, lzip and xz.\n" | d.\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 t | "\nzcmp compares file1 to file2. The standard input is used only | |||
he\n" | if file1 or\n" | |||
"file2 refers to standard input. If file2 is omitted zcmp tries t | ||||
he\n" | ||||
"following:\n" | "following:\n" | |||
"\n 1. If file1 is compressed, compares its decompressed content s with\n" | "\n - If file1 is compressed, compares its decompressed contents with\n" | |||
" the corresponding uncompressed file (the name of file1 with th e\n" | " the corresponding uncompressed file (the name of file1 with th e\n" | |||
" extension removed).\n" | " extension removed).\n" | |||
"\n 2. If file1 is uncompressed, compares it with the decompress ed\n" | "\n - If file1 is uncompressed, compares it with the decompresse d\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 re | ||||
ad 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 " | |||
" -V, --version output version information a nd exit\n" | " -V, --version output version information a nd exit\n" | |||
" -b, --print-bytes print differing bytes\n" | " -b, --print-bytes print differing bytes\n" | |||
" -i, --ignore-initial=<n>[:<n2>] ignore differences in the fi rst <n> bytes\n" | " -i, --ignore-initial=<n>[:<n2>] ignore differences in the fi rst <n> bytes\n" | |||
" -l, --list list position, value of all differing bytes\n" | " -l, --list list position, value of all differing bytes\n" | |||
" -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 configura tion file\n" | " -N, --no-rcfile don't read runtime configura tion 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" | |||
" --bz2=<command> set compressor and options f or bzip2 format\n" | " --bz2=<command> set compressor and options f or bzip2 format\n" | |||
" --gz=<command> set compressor and options f or gzip format\n" | " --gz=<command> set compressor and options f or gzip format\n" | |||
" --lz=<command> set compressor and options f or lzip format\n" | " --lz=<command> set compressor and options f or lzip format\n" | |||
" --xz=<command> set compressor and options f or xz format\n" | " --xz=<command> set compressor and options f or 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(); | |||
} | } | |||
long long getnum( const char * const ptr, const char ** const tailp = 0, | long long getnum( const char * const ptr, const char ** const tailp = 0, | |||
const long long llimit = 0, | const long long llimit = 0, | |||
const long long ulimit = LLONG_MAX ) | const long long ulimit = LLONG_MAX ) | |||
{ | { | |||
char * tail; | char * tail; | |||
errno = 0; | errno = 0; | |||
skipping to change at line 321 | skipping to change at line 320 | |||
} // end namespace | } // end namespace | |||
int main( const int argc, const char * const argv[] ) | int main( const int argc, const char * const argv[] ) | |||
{ | { | |||
enum { bz2_opt = 256, gz_opt, lz_opt, xz_opt }; | enum { bz2_opt = 256, gz_opt, lz_opt, xz_opt }; | |||
// number of initial bytes ignored for each file | // number of initial bytes ignored for each file | |||
long long ignore_initial[2] = { 0, 0 }; | long long ignore_initial[2] = { 0, 0 }; | |||
long long max_size = -1; // < 0 means unlimited size | long long max_size = -1; // < 0 means unlimited size | |||
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[] = | |||
{ | { | |||
{ 'b', "print-bytes", Arg_parser::no }, | { 'b', "print-bytes", Arg_parser::no }, | |||
{ 'h', "help", Arg_parser::no }, | { 'h', "help", Arg_parser::no }, | |||
{ 'i', "ignore-initial", Arg_parser::yes }, | { 'i', "ignore-initial", Arg_parser::yes }, | |||
{ 'l', "list", Arg_parser::no }, | { 'l', "list", Arg_parser::no }, | |||
{ 'M', "format", Arg_parser::yes }, | { 'M', "format", Arg_parser::yes }, | |||
{ 'n', "bytes", Arg_parser::yes }, | { 'n', "bytes", Arg_parser::yes }, | |||
{ 'N', "no-rcfile", Arg_parser::no }, | { 'N', "no-rcfile", Arg_parser::no }, | |||
skipping to change at line 398 | skipping to change at line 397 | |||
const int files = parser.arguments() - argind; | const int files = parser.arguments() - argind; | |||
std::string filenames[2]; // file names of the two input files | std::string filenames[2]; // file names of the two input files | |||
filenames[0] = parser.argument( argind ); | filenames[0] = parser.argument( argind ); | |||
if( files == 2 ) filenames[1] = parser.argument( argind + 1 ); | if( files == 2 ) filenames[1] = parser.argument( argind + 1 ); | |||
int infd[2]; // file descriptors of the two files | int infd[2]; // file descriptors of the two files | |||
infd[0] = ( filenames[0] == "-" ) ? | infd[0] = ( filenames[0] == "-" ) ? | |||
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() ) ) ) | ||||
{ | ||||
if( ignore_initial[0] == ignore_initial[1] ) return 0; | ||||
else { show_error( "Can't compare parts of same file." ); return 2; } | ||||
} | ||||
if( files == 2 ) | if( files == 2 ) | |||
{ | { | |||
if( check_identical( filenames[0].c_str(), filenames[1].c_str() ) ) | ||||
{ | ||||
if( ignore_initial[0] == ignore_initial[1] ) return 0; | ||||
else { show_error( "Can't compare parts of same file." ); return 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 | |||
old_infd[0] = infd[0]; old_infd[1] = infd[1]; | old_infd[0] = infd[0]; old_infd[1] = infd[1]; | |||
Children children[2]; | Children children[2]; | |||
if( !set_data_feeder( filenames[0], &infd[0], children[0], format_types[0] ) | | | if( !set_data_feeder( filenames[0], &infd[0], children[0], format_types[0] ) | | | |||
!set_data_feeder( filenames[1], &infd[1], children[1], format_types[1] ) ) | !set_data_feeder( filenames[1], &infd[1], children[1], format_types[1] ) ) | |||
return 2; | return 2; | |||
for( int i = 0; i < 2; ++i ) | for( int i = 0; i < 2; ++i ) | |||
End of changes. 16 change blocks. | ||||
42 lines changed or deleted | 47 lines changed or added |