summaryrefslogtreecommitdiffstats
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c307
1 files changed, 171 insertions, 136 deletions
diff --git a/main.c b/main.c
index 1205f48..e5a8dd5 100644
--- a/main.c
+++ b/main.c
@@ -1,5 +1,5 @@
/* Clzip - LZMA lossless data compressor
- Copyright (C) 2010-2022 Antonio Diaz Diaz.
+ Copyright (C) 2010-2023 Antonio Diaz Diaz.
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
@@ -16,9 +16,9 @@
*/
/*
Exit status: 0 for a normal exit, 1 for environmental problems
- (file not found, invalid flags, I/O errors, etc), 2 to indicate a
- corrupt or invalid input file, 3 for an internal consistency error
- (e.g., bug) which caused clzip to panic.
+ (file not found, invalid command-line options, I/O errors, etc), 2 to
+ indicate a corrupt or invalid input file, 3 for an internal consistency
+ error (e.g., bug) which caused clzip to panic.
*/
#define _FILE_OFFSET_BITS 64
@@ -26,10 +26,10 @@
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
-#include <limits.h>
+#include <limits.h> /* SSIZE_MAX */
#include <signal.h>
#include <stdbool.h>
-#include <stdint.h>
+#include <stdint.h> /* SIZE_MAX */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -80,7 +80,7 @@
int verbosity = 0;
static const char * const program_name = "clzip";
-static const char * const program_year = "2022";
+static const char * const program_year = "2023";
static const char * invocation_name = "clzip"; /* default value */
static const struct { const char * from; const char * to; } known_extensions[] = {
@@ -111,14 +111,15 @@ static void show_help( void )
"C++ compiler.\n"
"\nLzip is a lossless data compressor with a user interface similar to the one\n"
"of gzip or bzip2. Lzip uses a simplified form of the 'Lempel-Ziv-Markov\n"
- "chain-Algorithm' (LZMA) stream format and provides a 3 factor integrity\n"
- "checking to maximize interoperability and optimize safety. Lzip can compress\n"
- "about as fast as gzip (lzip -0) or compress most files more than bzip2\n"
- "(lzip -9). Decompression speed is intermediate between gzip and bzip2.\n"
- "Lzip is better than gzip and bzip2 from a data recovery perspective. Lzip\n"
- "has been designed, written, and tested with great care to replace gzip and\n"
- "bzip2 as the standard general-purpose compressed format for unix-like\n"
- "systems.\n"
+ "chain-Algorithm' (LZMA) stream format to maximize interoperability. The\n"
+ "maximum dictionary size is 512 MiB so that any lzip file can be decompressed\n"
+ "on 32-bit machines. Lzip provides accurate and robust 3-factor integrity\n"
+ "checking. Lzip can compress about as fast as gzip (lzip -0) or compress most\n"
+ "files more than bzip2 (lzip -9). Decompression speed is intermediate between\n"
+ "gzip and bzip2. Lzip is better than gzip and bzip2 from a data recovery\n"
+ "perspective. Lzip has been designed, written, and tested with great care to\n"
+ "replace gzip and bzip2 as the standard general-purpose compressed format for\n"
+ "Unix-like systems.\n"
"\nUsage: %s [options] [files]\n", invocation_name );
printf( "\nOptions:\n"
" -h, --help display this help and exit\n"
@@ -126,7 +127,7 @@ static void show_help( void )
" -a, --trailing-error exit with error status if trailing data\n"
" -b, --member-size=<bytes> set member size limit in bytes\n"
" -c, --stdout write to standard output, keep input files\n"
- " -d, --decompress decompress\n"
+ " -d, --decompress decompress, test compressed file integrity\n"
" -f, --force overwrite existing output files\n"
" -F, --recompress force re-compression of compressed files\n"
" -k, --keep keep (don't delete) input files\n"
@@ -141,25 +142,27 @@ static void show_help( void )
" -0 .. -9 set compression level [default 6]\n"
" --fast alias for -0\n"
" --best alias for -9\n"
+ " --empty-error exit with error status if empty member in file\n"
+ " --marking-error exit with error status if 1st LZMA byte not 0\n"
" --loose-trailing allow trailing data seeming corrupt header\n"
"\nIf no file names are given, or if a file is '-', clzip compresses or\n"
"decompresses from standard input to standard output.\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"
- "Dictionary sizes 12 to 29 are interpreted as powers of two, meaning 2^12\n"
- "to 2^29 bytes.\n"
- "\nThe bidimensional parameter space of LZMA can't be mapped to a linear\n"
- "scale optimal for all files. If your files are large, very repetitive,\n"
- "etc, you may need to use the options --dictionary-size and --match-length\n"
- "directly to achieve optimal performance.\n"
+ "Dictionary sizes 12 to 29 are interpreted as powers of two, meaning 2^12 to\n"
+ "2^29 bytes.\n"
+ "\nThe bidimensional parameter space of LZMA can't be mapped to a linear scale\n"
+ "optimal for all files. If your files are large, very repetitive, etc, you\n"
+ "may need to use the options --dictionary-size and --match-length directly\n"
+ "to achieve optimal performance.\n"
"\nTo extract all the files from archive 'foo.tar.lz', use the commands\n"
"'tar -xf foo.tar.lz' or 'clzip -cd foo.tar.lz | tar -xf -'.\n"
- "\nExit status: 0 for a normal exit, 1 for environmental problems (file\n"
- "not found, invalid flags, I/O errors, etc), 2 to indicate a corrupt or\n"
- "invalid input file, 3 for an internal consistency error (e.g., bug) which\n"
- "caused clzip to panic.\n"
+ "\nExit status: 0 for a normal exit, 1 for environmental problems\n"
+ "(file not found, invalid command-line options, I/O errors, etc), 2 to\n"
+ "indicate a corrupt or invalid input file, 3 for an internal consistency\n"
+ "error (e.g., bug) which caused clzip to panic.\n"
"\nThe ideas embodied in clzip are due to (at least) the following people:\n"
- "Abraham Lempel and Jacob Ziv (for the LZ algorithm), Andrey Markov (for the\n"
+ "Abraham Lempel and Jacob Ziv (for the LZ algorithm), Andrei Markov (for the\n"
"definition of Markov chains), G.N.N. Martin (for the definition of range\n"
"encoding), Igor Pavlov (for putting all the above together in LZMA), and\n"
"Julian Seward (for bzip2's CLI).\n"
@@ -264,16 +267,15 @@ const char * bad_version( const unsigned version )
const char * format_ds( const unsigned dictionary_size )
{
- enum { bufsize = 16, factor = 1024 };
+ enum { bufsize = 16, factor = 1024, n = 3 };
static char buf[bufsize];
- const char * const prefix[8] =
- { "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi" };
+ const char * const prefix[n] = { "Ki", "Mi", "Gi" };
const char * p = "";
const char * np = " ";
unsigned num = dictionary_size;
bool exact = ( num % factor == 0 );
- int i; for( i = 0; i < 8 && ( num > 9999 || ( exact && num >= factor ) ); ++i )
+ int i; for( i = 0; i < n && ( num > 9999 || ( exact && num >= factor ) ); ++i )
{ num /= factor; if( num % factor != 0 ) exact = false;
p = prefix[i]; np = ""; }
snprintf( buf, bufsize, "%s%4u %sB", np, num, p );
@@ -287,12 +289,12 @@ void show_header( const unsigned dictionary_size )
}
-/* separate large numbers >= 100_000 in groups of 3 digits using '_' */
+/* separate numbers of 5 or more digits in groups of 3 digits using '_' */
static const char * format_num3( unsigned long long num )
{
- const char * const si_prefix = "kMGTPEZY";
- const char * const binary_prefix = "KMGTPEZY";
- enum { buffers = 8, bufsize = 4 * sizeof (long long) };
+ enum { buffers = 8, bufsize = 4 * sizeof num, n = 10 };
+ const char * const si_prefix = "kMGTPEZYRQ";
+ const char * const binary_prefix = "KMGTPEZYRQ";
static char buffer[buffers][bufsize]; /* circle of static buffers for printf */
static int current = 0;
int i;
@@ -302,15 +304,15 @@ static const char * format_num3( unsigned long long num )
if( num > 1024 )
{
char prefix = 0; /* try binary first, then si */
- for( i = 0; i < 8 && num >= 1024 && num % 1024 == 0; ++i )
+ for( i = 0; i < n && num != 0 && num % 1024 == 0; ++i )
{ num /= 1024; prefix = binary_prefix[i]; }
if( prefix ) *(--p) = 'i';
else
- for( i = 0; i < 8 && num >= 1000 && num % 1000 == 0; ++i )
+ for( i = 0; i < n && num != 0 && num % 1000 == 0; ++i )
{ num /= 1000; prefix = si_prefix[i]; }
if( prefix ) *(--p) = prefix;
}
- const bool split = num >= 100000;
+ const bool split = num >= 10000;
for( i = 0; ; )
{
@@ -321,6 +323,16 @@ static const char * format_num3( unsigned long long num )
}
+void show_option_error( const char * const arg, const char * const msg,
+ const char * const option_name )
+ {
+ if( verbosity >= 0 )
+ fprintf( stderr, "%s: '%s': %s option '%s'.\n",
+ program_name, arg, msg, option_name );
+ }
+
+
+/* Recognized formats: <num>k, <num>Ki, <num>[MGTPEZYRQ][i] */
static unsigned long long getnum( const char * const arg,
const char * const option_name,
const unsigned long long llimit,
@@ -330,12 +342,8 @@ static unsigned long long getnum( const char * const arg,
errno = 0;
unsigned long long result = strtoull( arg, &tail, 0 );
if( tail == arg )
- {
- if( verbosity >= 0 )
- fprintf( stderr, "%s: Bad or missing numerical argument in "
- "option '%s'.\n", program_name, option_name );
- exit( 1 );
- }
+ { show_option_error( arg, "Bad or missing numerical argument in",
+ option_name ); exit( 1 ); }
if( !errno && tail[0] )
{
@@ -344,6 +352,8 @@ static unsigned long long getnum( const char * const arg,
int i;
switch( tail[0] )
{
+ case 'Q': exponent = 10; break;
+ case 'R': exponent = 9; break;
case 'Y': exponent = 8; break;
case 'Z': exponent = 7; break;
case 'E': exponent = 6; break;
@@ -355,12 +365,8 @@ static unsigned long long getnum( const char * const arg,
case 'k': if( factor == 1000 ) exponent = 1; break;
}
if( exponent <= 0 )
- {
- if( verbosity >= 0 )
- fprintf( stderr, "%s: Bad multiplier in numerical argument of "
- "option '%s'.\n", program_name, option_name );
- exit( 1 );
- }
+ { show_option_error( arg, "Bad multiplier in numerical argument of",
+ option_name ); exit( 1 ); }
for( i = 0; i < exponent; ++i )
{
if( ulimit / factor >= result ) result *= factor;
@@ -371,8 +377,8 @@ static unsigned long long getnum( const char * const arg,
if( errno )
{
if( verbosity >= 0 )
- fprintf( stderr, "%s: Numerical argument out of limits [%s,%s] "
- "in option '%s'.\n", program_name, format_num3( llimit ),
+ fprintf( stderr, "%s: '%s': Value out of limits [%s,%s] in "
+ "option '%s'.\n", program_name, arg, format_num3( llimit ),
format_num3( ulimit ), option_name );
exit( 1 );
}
@@ -453,7 +459,7 @@ static void set_d_outname( const char * const name, const int eindex )
strcpy( output_filename, name );
strcat( output_filename, ".out" );
if( verbosity >= 1 )
- fprintf( stderr, "%s: Can't guess original name for '%s' -- using '%s'\n",
+ fprintf( stderr, "%s: %s: Can't guess original name -- using '%s'\n",
program_name, name, output_filename );
}
@@ -474,9 +480,9 @@ int open_instream( const char * const name, struct stat * const in_statsp,
if( i != 0 || ( !S_ISREG( mode ) && ( !can_read || one_to_one ) ) )
{
if( verbosity >= 0 )
- fprintf( stderr, "%s: Input file '%s' is not a regular file%s.\n",
+ fprintf( stderr, "%s: %s: Input file is not a regular file%s.\n",
program_name, name, ( can_read && one_to_one ) ?
- ",\n and neither '-c' nor '-o' were specified" : "" );
+ ",\n and neither '-c' nor '-o' were specified" : "" );
close( infd );
infd = -1;
}
@@ -492,7 +498,7 @@ static int open_instream2( const char * const name, struct stat * const in_stats
if( program_mode == m_compress && !recompress && eindex >= 0 )
{
if( verbosity >= 0 )
- fprintf( stderr, "%s: Input file '%s' already has '%s' suffix.\n",
+ fprintf( stderr, "%s: %s: Input file already has '%s' suffix.\n",
program_name, name, known_extensions[eindex].from );
return -1;
}
@@ -500,6 +506,33 @@ static int open_instream2( const char * const name, struct stat * const in_stats
}
+static bool make_dirs( const char * const name )
+ {
+ int i = strlen( name );
+ while( i > 0 && name[i-1] != '/' ) --i; /* remove last component */
+ while( i > 0 && name[i-1] == '/' ) --i; /* remove slash(es) */
+ const int dirsize = i; /* size of dirname without trailing slash(es) */
+
+ for( i = 0; i < dirsize; ) /* if dirsize == 0, dirname is '/' or empty */
+ {
+ while( i < dirsize && name[i] == '/' ) ++i;
+ const int first = i;
+ while( i < dirsize && name[i] != '/' ) ++i;
+ if( first < i )
+ {
+ char partial[i+1]; memcpy( partial, name, i ); partial[i] = 0;
+ const mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
+ struct stat st;
+ if( stat( partial, &st ) == 0 )
+ { if( !S_ISDIR( st.st_mode ) ) { errno = ENOTDIR; return false; } }
+ else if( mkdir( partial, mode ) != 0 && errno != EEXIST )
+ return false; /* if EEXIST, another process created the dir */
+ }
+ }
+ return true;
+ }
+
+
static bool open_outstream( const bool force, const bool protect )
{
const mode_t usr_rw = S_IRUSR | S_IWUSR;
@@ -508,18 +541,21 @@ static bool open_outstream( const bool force, const bool protect )
int flags = O_CREAT | O_WRONLY | O_BINARY;
if( force ) flags |= O_TRUNC; else flags |= O_EXCL;
- outfd = open( output_filename, flags, outfd_mode );
- if( outfd >= 0 ) delete_output_on_interrupt = true;
- else if( verbosity >= 0 )
- {
+ outfd = -1;
+ const int len = strlen( output_filename );
+ if( len > 0 && output_filename[len-1] == '/' ) errno = EISDIR;
+ else {
+ if( !protect && !make_dirs( output_filename ) )
+ { show_file_error( output_filename,
+ "Error creating intermediate directory", errno ); return false; }
+ outfd = open( output_filename, flags, outfd_mode );
+ if( outfd >= 0 ) { delete_output_on_interrupt = true; return true; }
if( errno == EEXIST )
- fprintf( stderr, "%s: Output file '%s' already exists, skipping.\n",
- program_name, output_filename );
- else
- fprintf( stderr, "%s: Can't create output file '%s': %s\n",
- program_name, output_filename, strerror( errno ) );
+ { show_file_error( output_filename,
+ "Output file already exists, skipping.", 0 ); return false; }
}
- return ( outfd >= 0 );
+ show_file_error( output_filename, "Can't create output file", errno );
+ return false;
}
@@ -537,12 +573,10 @@ void cleanup_and_fail( const int retval )
if( delete_output_on_interrupt )
{
delete_output_on_interrupt = false;
- if( verbosity >= 0 )
- fprintf( stderr, "%s: Deleting output file '%s', if it exists.\n",
- program_name, output_filename );
+ show_file_error( output_filename, "Deleting output file, if it exists.", 0 );
if( outfd >= 0 ) { close( outfd ); outfd = -1; }
if( remove( output_filename ) != 0 && errno != ENOENT )
- show_error( "WARNING: deletion of output file (apparently) failed.", 0, false );
+ show_error( "warning: deletion of output file failed", errno, false );
}
exit( retval );
}
@@ -596,10 +630,8 @@ static void close_and_set_permissions( const struct stat * const in_statsp )
warning = true;
}
if( close( outfd ) != 0 )
- {
- show_error( "Error closing output file", errno, false );
- cleanup_and_fail( 1 );
- }
+ { show_file_error( output_filename, "Error closing output file", errno );
+ cleanup_and_fail( 1 ); }
outfd = -1;
delete_output_on_interrupt = false;
if( in_statsp )
@@ -610,7 +642,8 @@ static void close_and_set_permissions( const struct stat * const in_statsp )
if( utime( output_filename, &t ) != 0 ) warning = true;
}
if( warning && verbosity >= 1 )
- show_error( "Can't change output file attributes.", 0, false );
+ show_file_error( output_filename,
+ "warning: can't change output file attributes", errno );
}
@@ -724,7 +757,7 @@ static int compress( const unsigned long long cfile_size,
}
-static unsigned char xdigit( const unsigned value )
+static unsigned char xdigit( const unsigned value ) /* hex digit for 'value' */
{
if( value <= 9 ) return '0' + value;
if( value <= 15 ) return 'A' + value - 10;
@@ -756,13 +789,13 @@ static bool show_trailing_data( const uint8_t * const data, const int size,
Pp_show_msg( pp, buf );
if( ignore_trailing == 0 ) show_file_error( pp->name, trailing_msg, 0 );
}
- return ( ignore_trailing > 0 );
+ return ignore_trailing > 0;
}
static int decompress( const unsigned long long cfile_size, const int infd,
- struct Pretty_print * const pp, const bool ignore_trailing,
- const bool loose_trailing, const bool testing )
+ const struct Cl_options * const cl_opts,
+ struct Pretty_print * const pp, const bool testing )
{
unsigned long long partial_file_pos = 0;
struct Range_decoder rdec;
@@ -781,28 +814,25 @@ static int decompress( const unsigned long long cfile_size, const int infd,
if( first_member )
{ show_file_error( pp->name, "File ends unexpectedly at member header.", 0 );
retval = 2; }
- else if( Lh_verify_prefix( header, size ) )
+ else if( Lh_check_prefix( header, size ) )
{ Pp_show_msg( pp, "Truncated header in multimember file." );
- show_trailing_data( header, size, pp, true, -1 );
- retval = 2; }
- else if( size > 0 && !show_trailing_data( header, size, pp,
- true, ignore_trailing ) )
- retval = 2;
+ show_trailing_data( header, size, pp, true, -1 ); retval = 2; }
+ else if( size > 0 && !show_trailing_data( header, size, pp, true,
+ cl_opts->ignore_trailing ) ) retval = 2;
break;
}
- if( !Lh_verify_magic( header ) )
+ if( !Lh_check_magic( header ) )
{
if( first_member )
{ show_file_error( pp->name, bad_magic_msg, 0 ); retval = 2; }
- else if( !loose_trailing && Lh_verify_corrupt( header ) )
+ else if( !cl_opts->loose_trailing && Lh_check_corrupt( header ) )
{ Pp_show_msg( pp, corrupt_mm_msg );
- show_trailing_data( header, size, pp, false, -1 );
- retval = 2; }
- else if( !show_trailing_data( header, size, pp, false, ignore_trailing ) )
- retval = 2;
+ show_trailing_data( header, size, pp, false, -1 ); retval = 2; }
+ else if( !show_trailing_data( header, size, pp, false,
+ cl_opts->ignore_trailing ) ) retval = 2;
break;
}
- if( !Lh_verify_version( header ) )
+ if( !Lh_check_version( header ) )
{ Pp_show_msg( pp, bad_version( Lh_version( header ) ) );
retval = 2; break; }
const unsigned dictionary_size = Lh_get_dictionary_size( header );
@@ -816,7 +846,7 @@ static int decompress( const unsigned long long cfile_size, const int infd,
if( !LZd_init( &decoder, &rdec, dictionary_size, outfd ) )
{ Pp_show_msg( pp, mem_msg ); retval = 1; break; }
show_dprogress( cfile_size, partial_file_pos, &rdec, pp ); /* init */
- const int result = LZd_decode_member( &decoder, pp );
+ const int result = LZd_decode_member( &decoder, cl_opts, pp );
partial_file_pos += Rd_member_position( &rdec );
LZd_free( &decoder );
if( result != 0 )
@@ -828,6 +858,8 @@ static int decompress( const unsigned long long cfile_size, const int infd,
"File ends unexpectedly" : "Decoder error",
partial_file_pos );
}
+ else if( result == 5 ) Pp_show_msg( pp, empty_msg );
+ else if( result == 6 ) Pp_show_msg( pp, marking_msg );
retval = 2; break;
}
if( verbosity >= 2 )
@@ -933,8 +965,8 @@ void show_dprogress( const unsigned long long cfile_size,
int main( const int argc, const char * const argv[] )
{
- /* Mapping from gzip/bzip2 style 1..9 compression modes
- to the corresponding LZMA compression modes. */
+ /* Mapping from gzip/bzip2 style 0..9 compression levels to the
+ corresponding LZMA compression parameters. */
const struct Lzma_options option_mapping[] =
{
{ 1 << 16, 16 }, /* -0 */
@@ -955,48 +987,50 @@ int main( const int argc, const char * const argv[] )
const char * default_output_filename = "";
enum Mode program_mode = m_compress;
int i;
+ struct Cl_options cl_opts; /* command-line options */
+ Cl_options_init( &cl_opts );
bool force = false;
- bool ignore_trailing = true;
bool keep_input_files = false;
- bool loose_trailing = false;
bool recompress = false;
bool to_stdout = false;
bool zero = false;
if( argc > 0 ) invocation_name = argv[0];
- enum { opt_lt = 256 };
+ enum { opt_eer = 256, opt_lt, opt_mer };
const struct ap_Option options[] =
{
- { '0', "fast", ap_no },
- { '1', 0, ap_no },
- { '2', 0, ap_no },
- { '3', 0, ap_no },
- { '4', 0, ap_no },
- { '5', 0, ap_no },
- { '6', 0, ap_no },
- { '7', 0, ap_no },
- { '8', 0, ap_no },
- { '9', "best", ap_no },
- { 'a', "trailing-error", ap_no },
- { 'b', "member-size", ap_yes },
- { 'c', "stdout", ap_no },
- { 'd', "decompress", ap_no },
- { 'f', "force", ap_no },
- { 'F', "recompress", ap_no },
- { 'h', "help", ap_no },
- { 'k', "keep", ap_no },
- { 'l', "list", ap_no },
- { 'm', "match-length", ap_yes },
- { 'n', "threads", ap_yes },
- { 'o', "output", ap_yes },
- { 'q', "quiet", ap_no },
- { 's', "dictionary-size", ap_yes },
- { 'S', "volume-size", ap_yes },
- { 't', "test", ap_no },
- { 'v', "verbose", ap_no },
- { 'V', "version", ap_no },
- { opt_lt, "loose-trailing", ap_no },
- { 0, 0, ap_no } };
+ { '0', "fast", ap_no },
+ { '1', 0, ap_no },
+ { '2', 0, ap_no },
+ { '3', 0, ap_no },
+ { '4', 0, ap_no },
+ { '5', 0, ap_no },
+ { '6', 0, ap_no },
+ { '7', 0, ap_no },
+ { '8', 0, ap_no },
+ { '9', "best", ap_no },
+ { 'a', "trailing-error", ap_no },
+ { 'b', "member-size", ap_yes },
+ { 'c', "stdout", ap_no },
+ { 'd', "decompress", ap_no },
+ { 'f', "force", ap_no },
+ { 'F', "recompress", ap_no },
+ { 'h', "help", ap_no },
+ { 'k', "keep", ap_no },
+ { 'l', "list", ap_no },
+ { 'm', "match-length", ap_yes },
+ { 'n', "threads", ap_yes },
+ { 'o', "output", ap_yes },
+ { 'q', "quiet", ap_no },
+ { 's', "dictionary-size", ap_yes },
+ { 'S', "volume-size", ap_yes },
+ { 't', "test", ap_no },
+ { 'v', "verbose", ap_no },
+ { 'V', "version", ap_no },
+ { opt_eer, "empty-error", ap_no },
+ { opt_lt, "loose-trailing", ap_no },
+ { opt_mer, "marking-error", ap_no },
+ { 0, 0, ap_no } };
CRC32_init();
@@ -1020,7 +1054,7 @@ int main( const int argc, const char * const argv[] )
case '5': case '6': case '7': case '8': case '9':
zero = ( code == '0' );
encoder_options = option_mapping[code-'0']; break;
- case 'a': ignore_trailing = false; break;
+ case 'a': cl_opts.ignore_trailing = false; break;
case 'b': member_size = getnum( arg, pn, 100000, max_member_size ); break;
case 'c': to_stdout = true; break;
case 'd': set_mode( &program_mode, m_decompress ); break;
@@ -1042,8 +1076,10 @@ int main( const int argc, const char * const argv[] )
case 't': set_mode( &program_mode, m_test ); break;
case 'v': if( verbosity < 4 ) ++verbosity; break;
case 'V': show_version(); return 0;
- case opt_lt: loose_trailing = true; break;
- default : internal_error( "uncaught option." );
+ case opt_eer: cl_opts.ignore_empty = false; break;
+ case opt_lt: cl_opts.loose_trailing = true; break;
+ case opt_mer: cl_opts.ignore_marking = false; break;
+ default: internal_error( "uncaught option." );
}
} /* end process options */
@@ -1065,7 +1101,7 @@ int main( const int argc, const char * const argv[] )
}
if( program_mode == m_list )
- return list_files( filenames, num_filenames, ignore_trailing, loose_trailing );
+ return list_files( filenames, num_filenames, &cl_opts );
if( program_mode == m_compress )
{
@@ -1119,7 +1155,7 @@ int main( const int argc, const char * const argv[] )
eindex, one_to_one, recompress );
if( infd < 0 ) { set_retval( &retval, 1 ); continue; }
if( !check_tty_in( pp.name, infd, program_mode, &retval ) ) continue;
- if( one_to_one ) /* open outfd after verifying infd */
+ if( one_to_one ) /* open outfd after checking infd */
{
if( program_mode == m_compress )
set_c_outname( input_filename, true, true, volume_size > 0 );
@@ -1132,7 +1168,7 @@ int main( const int argc, const char * const argv[] )
if( one_to_one && !check_tty_out( program_mode ) )
{ set_retval( &retval, 1 ); return retval; } /* don't delete a tty */
- if( to_file && outfd < 0 ) /* open outfd after verifying infd */
+ if( to_file && outfd < 0 ) /* open outfd after checking infd */
{
if( program_mode == m_compress ) set_c_outname( default_output_filename,
filenames_given, false, volume_size > 0 );
@@ -1154,8 +1190,7 @@ int main( const int argc, const char * const argv[] )
tmp = compress( cfile_size, member_size, volume_size, infd,
&encoder_options, &pp, in_statsp, zero );
else
- tmp = decompress( cfile_size, infd, &pp, ignore_trailing,
- loose_trailing, program_mode == m_test );
+ tmp = decompress( cfile_size, infd, &cl_opts, &pp, program_mode == m_test );
if( close( infd ) != 0 )
{ show_file_error( pp.name, "Error closing input file", errno );
set_retval( &tmp, 1 ); }