diff options
Diffstat (limited to 'main.cc')
-rw-r--r-- | main.cc | 143 |
1 files changed, 85 insertions, 58 deletions
@@ -71,8 +71,8 @@ struct { const char * from; const char * to; } const known_extensions[] = { { ".tlz", ".tar" }, { 0, 0 } }; -enum Mode { m_none, m_decompress, m_generate, m_merge, m_recover, m_repair, - m_split, m_test, m_update }; +enum Mode { m_none, m_decompress, m_generate, m_list, m_merge, m_range, + m_recover, m_repair, m_split, m_test, m_update }; std::string output_filename; int outfd = -1; @@ -87,22 +87,26 @@ void show_help() throw() std::printf( "%s - Data recovery tool and decompressor for lzipped files.\n", Program_name ); std::printf( "\nUsage: %s [options] [files]\n", invocation_name ); std::printf( "\nOptions:\n" - " -h, --help display this help and exit\n" - " -V, --version output version information and exit\n" - " -c, --stdout send decompressed output to standard output\n" - " -d, --decompress decompress\n" - " -f, --force overwrite existing output files\n" -// " -g, --generate-recover-file generate a recover file\n" - " -k, --keep keep (don't delete) input files\n" - " -m, --merge correct errors in file using several copies\n" - " -o, --output=<file> place the output into <file>\n" - " -q, --quiet suppress all messages\n" -// " -r, --recover correct errors in file using a recover file\n" - " -R, --repair try to repair a small error in file\n" - " -s, --split split a multimember file in single-member files\n" - " -t, --test test compressed file integrity\n" -// " -u, --update convert file from version 0 to version 1\n" - " -v, --verbose be verbose (a 2nd -v gives more)\n" + " -h, --help display this help and exit\n" + " -V, --version output version information and exit\n" + " -c, --stdout send decompressed output to standard output\n" + " -d, --decompress decompress\n" + " -D, --range-decompress=<range> decompress only a range of bytes (N-M)\n" + " -f, --force overwrite existing output files\n" +// " -g, --generate-recover-file generate a recover file\n" + " -k, --keep keep (don't delete) input files\n" + " -l, --list print total file sizes and ratios\n" + " -m, --merge correct errors in file using several copies\n" + " -o, --output=<file> place the output into <file>\n" + " -q, --quiet suppress all messages\n" +// " -r, --recover correct errors in file using a recover file\n" + " -R, --repair try to repair a small error in file\n" + " -s, --split split multimember file in single-member files\n" + " -t, --test test compressed file integrity\n" +// " -u, --update convert file from version 0 to version 1\n" + " -v, --verbose be verbose (a 2nd -v gives more)\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" "\nReport bugs to lzip-bug@nongnu.org\n" "Lziprecover home page: http://www.nongnu.org/lzip/lziprecover.html\n" ); } @@ -118,20 +122,13 @@ void show_version() throw() } -const char * format_num( long long num ) throw() +void one_file( const int argind, const int arguments ) throw() { - const char * const prefix[8] = - { "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi" }; - enum { buf_size = 16, factor = 1024 }; - static char buf[buf_size]; - const char *p = ""; - bool exact = ( num % factor == 0 ); - - for( int i = 0; i < 8 && ( llabs( num ) > 9999 || - ( exact && llabs( num ) >= factor ) ); ++i ) - { num /= factor; if( num % factor != 0 ) exact = false; p = prefix[i]; } - snprintf( buf, buf_size, "%lld %s", num, p ); - return buf; + if( argind + 1 != arguments ) + { + show_error( "You must specify exactly 1 file.", 0, true ); + std::exit( 1 ); + } } @@ -345,7 +342,7 @@ int decompress( const int infd, const Pretty_print & pp, const bool testing ) if( verbosity >= 2 ) std::fprintf( stderr, "version %d, dictionary size %7sB. ", header.version(), - format_num( header.dictionary_size() ) ); + format_num( header.dictionary_size(), 9999, -1 ) ); } LZ_decoder decoder( header, rdec, outfd ); @@ -403,6 +400,30 @@ void set_signals() throw() int verbosity = 0; +const char * format_num( long long num, long long limit, + const int set_prefix ) throw() + { + const char * const si_prefix[8] = + { "k", "M", "G", "T", "P", "E", "Z", "Y" }; + const char * const binary_prefix[8] = + { "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi" }; + static bool si = true; + static char buf[32]; + + if( set_prefix ) si = ( set_prefix > 0 ); + const int factor = ( si ? 1000 : 1024 ); + const char * const * prefix = ( si ? si_prefix : binary_prefix ); + const char * p = ""; + bool exact = ( num % factor == 0 ); + + for( int i = 0; i < 8 && ( llabs( num ) > limit || + ( exact && llabs( num ) >= factor ) ); ++i ) + { num /= factor; if( num % factor != 0 ) exact = false; p = prefix[i]; } + snprintf( buf, sizeof buf, "%lld %s", num, p ); + return buf; + } + + int open_instream( const std::string & name, struct stat * const in_statsp, const bool to_stdout, const bool reg_only ) throw() { @@ -491,25 +512,28 @@ int main( const int argc, const char * const argv[] ) bool to_stdout = false; std::string input_filename; std::string default_output_filename; + std::string range_string; std::vector< std::string > filenames; invocation_name = argv[0]; const Arg_parser::Option options[] = { - { 'c', "stdout", Arg_parser::no }, - { 'd', "decompress", Arg_parser::no }, - { 'f', "force", Arg_parser::no }, - { 'h', "help", Arg_parser::no }, - { 'k', "keep", Arg_parser::no }, - { 'm', "merge", Arg_parser::no }, - { 'o', "output", Arg_parser::yes }, - { 'q', "quiet", Arg_parser::no }, - { 'R', "repair", Arg_parser::no }, - { 's', "split", Arg_parser::no }, - { 't', "test", Arg_parser::no }, - { 'v', "verbose", Arg_parser::no }, - { 'V', "version", Arg_parser::no }, - { 0 , 0, Arg_parser::no } }; + { 'c', "stdout", Arg_parser::no }, + { 'd', "decompress", Arg_parser::no }, + { 'D', "range-decompress", Arg_parser::yes }, + { 'f', "force", Arg_parser::no }, + { 'h', "help", Arg_parser::no }, + { 'k', "keep", Arg_parser::no }, + { 'l', "list", Arg_parser::no }, + { 'm', "merge", Arg_parser::no }, + { 'o', "output", Arg_parser::yes }, + { 'q', "quiet", Arg_parser::no }, + { 'R', "repair", Arg_parser::no }, + { 's', "split", Arg_parser::no }, + { 't', "test", Arg_parser::no }, + { 'v', "verbose", Arg_parser::no }, + { 'V', "version", Arg_parser::no }, + { 0 , 0, Arg_parser::no } }; const Arg_parser parser( argc, argv, options ); if( parser.error().size() ) // bad option @@ -520,15 +544,19 @@ int main( const int argc, const char * const argv[] ) { const int code = parser.code( argind ); if( !code ) break; // no more options + const std::string & arg = parser.argument( argind ).c_str(); switch( code ) { case 'c': to_stdout = true; break; case 'd': set_mode( program_mode, m_decompress ); break; + case 'D': set_mode( program_mode, m_range ); + range_string = arg; break; case 'f': force = true; break; case 'h': show_help(); return 0; case 'k': keep_input_files = true; break; + case 'l': set_mode( program_mode, m_list ); break; case 'm': set_mode( program_mode, m_merge ); break; - case 'o': default_output_filename = parser.argument( argind ); break; + case 'o': default_output_filename = arg; break; case 'q': verbosity = -1; break; case 'R': set_mode( program_mode, m_repair ); break; case 's': set_mode( program_mode, m_split ); break; @@ -552,9 +580,10 @@ int main( const int argc, const char * const argv[] ) case m_update: case m_none: internal_error( "invalid operation" ); break; case m_decompress: break; + case m_list: + one_file( argind, parser.arguments() ); + return list_file( parser.argument( argind ) ); case m_merge: - { - std::vector< std::string > filenames; for( ; argind < parser.arguments(); ++argind ) filenames.push_back( parser.argument( argind ) ); if( filenames.size() < 2 ) @@ -562,21 +591,19 @@ int main( const int argc, const char * const argv[] ) if( !default_output_filename.size() ) default_output_filename = insert_fixed( filenames[0] ); return merge_files( filenames, default_output_filename, force ); - } break; + case m_range: + one_file( argind, parser.arguments() ); + return range_decompress( parser.argument( argind ), + default_output_filename, range_string, + to_stdout, force ); case m_repair: - { - if( argind + 1 != parser.arguments() ) - { show_error( "You must specify exactly 1 file.", 0, true ); return 1; } + one_file( argind, parser.arguments() ); if( !default_output_filename.size() ) default_output_filename = insert_fixed( parser.argument( argind ) ); return repair_file( parser.argument( argind ), default_output_filename, force ); - } break; case m_split: - { - if( argind + 1 != parser.arguments() ) - { show_error( "You must specify exactly 1 file.", 0, true ); return 1; } + one_file( argind, parser.arguments() ); return split_file( parser.argument( argind ), default_output_filename, force ); - } break; case m_test: break; } |