diff options
author | Daniel Baumann <mail@daniel-baumann.ch> | 2015-11-08 04:26:51 +0000 |
---|---|---|
committer | Daniel Baumann <mail@daniel-baumann.ch> | 2015-11-08 04:26:51 +0000 |
commit | abdd6f5dd4e9b01f68646858e3abc58325436be3 (patch) | |
tree | 7d78c505a87aed973c3154a810d57feb259b69a6 /zdiff.cc | |
parent | Adding upstream version 1.0. (diff) | |
download | zutils-abdd6f5dd4e9b01f68646858e3abc58325436be3.tar.xz zutils-abdd6f5dd4e9b01f68646858e3abc58325436be3.zip |
Adding upstream version 1.1~rc2.upstream/1.1_rc2
Signed-off-by: Daniel Baumann <mail@daniel-baumann.ch>
Diffstat (limited to 'zdiff.cc')
-rw-r--r-- | zdiff.cc | 152 |
1 files changed, 84 insertions, 68 deletions
@@ -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." @@ -54,20 +55,20 @@ void show_help() { std::printf( "Zdiff compares two files (\"-\" means standard input), and if they\n" "differ, shows the differences line by line. If any given file is\n" - "compressed, its uncompressed content is used. Zdiff is a front end to\n" + "compressed, its decompressed content is used. Zdiff is a front end to\n" "the diff program and has the limitation that messages from diff refer to\n" "temporary filenames instead of those specified.\n" "\nThe supported formats are bzip2, gzip, lzip and xz.\n" "\nUsage: zdiff [options] file1 [file2]\n" "\nCompares <file1> to <file2>. If <file2> is omitted zdiff 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" @@ -81,6 +82,7 @@ void show_help() " -E, --ignore-tab-expansion ignore changes due to tab expansion\n" " --format=[<fmt1>][,<fmt2>] force given formats (bz2, gz, lz, xz)\n" " -i, --ignore-case ignore case differences in file contents\n" + " -N, --no-rcfile don't read runtime configuration file\n" " -p, --show-c-function show which C function each change is in\n" " -q, --brief output only whether files differ\n" " -s, --report-identical-files report when two files are identical\n" @@ -89,6 +91,10 @@ void show_help() " -u use the unified output format\n" " -U, --unified=<n> same as -u but use <n> lines of context\n" " -w, --ignore-all-space ignore all white space\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(); @@ -151,59 +157,70 @@ bool set_fifonames( const std::string filenames[2] ) bool set_data_feeder( const std::string & fifoname, const int infd, - pid_t * const pidp, const int format_type ) + Children & children, int format_index ) { const uint8_t * magic_data = 0; int magic_size = 0; - const char * const decompressor_name = ( format_type >= 0 ) ? - decompressor_names[format_type] : - test_format( infd, &magic_data, &magic_size ); + if( format_index < 0 ) + format_index = test_format( infd, &magic_data, &magic_size ); + children.compressor_name = get_compressor_name( format_index ); - if( decompressor_name ) // compressed + if( children.compressor_name ) // compressed { - int fda[2]; // pipe from feeder to decompressor + int fda[2]; // pipe from feeder to compressor if( pipe( fda ) < 0 ) { show_error( "Can't create pipe", errno ); return false; } const pid_t pid = fork(); - if( pid == 0 ) // child (decompressor feeder) + if( pid == 0 ) // child 1 (compressor feeder) { - const pid_t pid2 = fork(); - if( pid2 == 0 ) // grandchild (decompressor) - { - const int outfd = open( fifoname.c_str(), O_WRONLY | o_binary ); - if( outfd < 0 ) - { - if( verbosity >= 0 ) - std::fprintf( stderr, "%s: Can't open FIFO '%s' for writing: %s.\n", - util_name, fifoname.c_str(), std::strerror( errno ) ); - _exit( 2 ); - } - if( dup2( fda[0], STDIN_FILENO ) >= 0 && - dup2( outfd, STDOUT_FILENO ) >= 0 && - close( fda[0] ) == 0 && close( fda[1] ) == 0 && - close( outfd ) == 0 ) - execlp( decompressor_name, decompressor_name, - (verbosity >= 0) ? "-d" : "-dq", (char *)0 ); - show_exec_error( decompressor_name ); - _exit( 2 ); - } - if( pid2 < 0 ) - { show_fork_error( decompressor_name ); _exit( 2 ); } - if( close( fda[0] ) != 0 || !feed_data( infd, fda[1], magic_data, magic_size ) ) _exit( 2 ); if( close( fda[1] ) != 0 ) { show_close_error( "data feeder" ); _exit( 2 ); } - _exit( wait_for_child( pid2, decompressor_name ) ); + _exit( 0 ); } - // parent + if( pid < 0 ) // parent + { show_fork_error( "data feeder" ); return false; } + + const pid_t pid2 = fork(); + if( pid2 == 0 ) // child 2 (compressor) + { + const int outfd = open( fifoname.c_str(), O_WRONLY | o_binary ); + if( outfd < 0 ) + { + if( verbosity >= 0 ) + std::fprintf( stderr, "%s: Can't open FIFO '%s' for writing: %s.\n", + util_name, fifoname.c_str(), std::strerror( errno ) ); + _exit( 2 ); + } + if( dup2( fda[0], STDIN_FILENO ) >= 0 && + dup2( outfd, STDOUT_FILENO ) >= 0 && + close( fda[0] ) == 0 && close( fda[1] ) == 0 && + close( outfd ) == 0 ) + { + const std::vector< std::string > & compressor_args = + get_compressor_args( format_index ); + const int size = compressor_args.size(); + const char ** const argv = new const char *[size+3]; + argv[0] = children.compressor_name; + for( int i = 0; i < size; ++i ) + argv[i+1] = compressor_args[i].c_str(); + argv[size+1] = ( verbosity >= 0 ) ? "-d" : "-dq"; + argv[size+2] = 0; + execvp( argv[0], (char **)argv ); + } + show_exec_error( children.compressor_name ); + _exit( 2 ); + } + if( pid2 < 0 ) // parent + { show_fork_error( children.compressor_name ); return false; } + close( fda[0] ); close( fda[1] ); - if( pid < 0 ) - { show_fork_error( "decompressor feeder" ); return false; } - *pidp = pid; + children.pid[0] = pid; + children.pid[1] = pid2; } - else // not compressed + else // uncompressed { const pid_t pid = fork(); if( pid == 0 ) // child (feeder) @@ -222,10 +239,10 @@ bool set_data_feeder( const std::string & fifoname, const int infd, { show_close_error( "data feeder" ); _exit( 2 ); } _exit( 0 ); } - // parent - if( pid < 0 ) + if( pid < 0 ) // parent { show_fork_error( "data feeder" ); return false; } - *pidp = pid; + children.pid[0] = pid; + children.pid[1] = 0; } return true; } @@ -251,7 +268,7 @@ void set_signals() 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 }; std::vector< const char * > diff_args; // args to diff, maybe empty int format_types[2] = { -1, -1 }; invocation_name = argv[0]; @@ -268,6 +285,7 @@ int main( const int argc, const char * const argv[] ) { 'E', "ignore-tab-expansion", Arg_parser::no }, { 'h', "help", Arg_parser::no }, { 'i', "ignore-case", Arg_parser::no }, + { 'N', "no-rcfile", Arg_parser::no }, { 'p', "show-c-function", Arg_parser::no }, { 'q', "brief", Arg_parser::no }, { 's', "report-identical-files", Arg_parser::no }, @@ -278,12 +296,18 @@ int main( const int argc, const char * const argv[] ) { 'V', "version", Arg_parser::no }, { 'w', "ignore-all-space", 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 ) { @@ -301,6 +325,7 @@ int main( const int argc, const char * const argv[] ) case 'E': diff_args.push_back( "-E" ); break; case 'h': show_help(); return 0; case 'i': diff_args.push_back( "-i" ); break; + case 'N': break; case 'p': diff_args.push_back( "-p" ); break; case 'q': diff_args.push_back( "-q" ); break; case 's': diff_args.push_back( "-s" ); break; @@ -310,7 +335,11 @@ int main( const int argc, const char * const argv[] ) case 'U': diff_args.push_back( "-U" ); diff_args.push_back( arg ); break; case 'V': show_version( "Zdiff" ); return 0; case 'w': diff_args.push_back( "-w" ); break; - 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 @@ -375,31 +404,18 @@ int main( const int argc, const char * const argv[] ) show_exec_error( DIFF ); _exit( 2 ); } - // parent - if( diff_pid < 0 ) + if( diff_pid < 0 ) // parent { show_fork_error( DIFF ); return 2; } - pid_t pid[2]; - if( !set_data_feeder( fifonames[0], infd[0], &pid[0], format_types[0] ) || - !set_data_feeder( fifonames[1], infd[1], &pid[1], format_types[1] ) ) + Children children[2]; + if( !set_data_feeder( fifonames[0], infd[0], children[0], format_types[0] ) || + !set_data_feeder( fifonames[1], infd[1], children[1], format_types[1] ) ) return 2; int retval = wait_for_child( diff_pid, DIFF ); - if( retval != 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 ) ) retval = 2; for( int i = 0; i < 2; ++i ) if( filenames[i] != "-" && close( infd[i] ) != 0 ) |