summaryrefslogtreecommitdiffstats
path: root/zcmp.cc
diff options
context:
space:
mode:
Diffstat (limited to 'zcmp.cc')
-rw-r--r--zcmp.cc53
1 files changed, 30 insertions, 23 deletions
diff --git a/zcmp.cc b/zcmp.cc
index b118840..e7e1b44 100644
--- a/zcmp.cc
+++ b/zcmp.cc
@@ -58,13 +58,10 @@ void show_help()
"\nThe formats supported are bzip2, gzip, lzip, xz, and zstd.\n"
"\nUsage: zcmp [options] file1 [file2]\n"
"\nzcmp compares file1 to file2. The standard input is used only if file1 or\n"
- "file2 refers to standard input. If file2 is omitted zcmp tries the\n"
- "following:\n"
- "\n - 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 - If file1 is uncompressed, compares it with the decompressed\n"
- " contents of file1.[lz|bz2|gz|zst|xz] (the first one that is found).\n"
+ "file2 refers to standard input. If file2 is omitted zcmp tries to compare\n"
+ "file1 with the corresponding uncompressed file (if file1 is compressed), and\n"
+ "then with the corresponding compressed files of the remaining formats until\n"
+ "one is found.\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"
@@ -98,9 +95,9 @@ void show_help()
// separate numbers of 5 or more digits in groups of 3 digits using '_'
const char * format_num3( long long num )
{
- const char * const si_prefix = "kMGTPEZY";
- const char * const binary_prefix = "KMGTPEZY";
- enum { buffers = 8, bufsize = 4 * sizeof num };
+ 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;
@@ -108,19 +105,22 @@ const char * format_num3( long long num )
char * p = buf + bufsize - 1; // fill the buffer backwards
*p = 0; // terminator
const bool negative = num < 0;
- char prefix = 0; // try binary first, then si
- for( int i = 0; i < 8 && num != 0 && ( num / 1024 ) * 1024 == num; ++i )
- { num /= 1024; prefix = binary_prefix[i]; }
- if( prefix ) *(--p) = 'i';
- else
- for( int i = 0; i < 8 && num != 0 && ( num / 1000 ) * 1000 == num; ++i )
- { num /= 1000; prefix = si_prefix[i]; }
- if( prefix ) *(--p) = prefix;
+ if( num > 1024 || num < -1024 )
+ {
+ char prefix = 0; // try binary first, then si
+ for( int i = 0; i < n && num != 0 && num % 1024 == 0; ++i )
+ { num /= 1024; prefix = binary_prefix[i]; }
+ if( prefix ) *(--p) = 'i';
+ else
+ for( int i = 0; i < n && num != 0 && num % 1000 == 0; ++i )
+ { num /= 1000; prefix = si_prefix[i]; }
+ if( prefix ) *(--p) = prefix;
+ }
const bool split = num >= 10000 || num <= -10000;
for( int i = 0; ; )
{
- long long onum = num; num /= 10;
+ const long long onum = num; num /= 10;
*(--p) = llabs( onum - ( 10 * num ) ) + '0'; if( num == 0 ) break;
if( split && ++i >= 3 ) { i = 0; *(--p) = '_'; }
}
@@ -129,6 +129,7 @@ const char * format_num3( long long num )
}
+// Recognized formats: <num>k[B], <num>Ki[B], <num>[MGTPEZYRQ][i][B]
long long getnum( const char * const arg, const char * const option_name,
const char ** const tailp = 0,
const long long llimit = 0,
@@ -152,6 +153,8 @@ long long getnum( const char * const arg, const char * const option_name,
int exponent = -1; // -1 = bad multiplier
switch( ch )
{
+ 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;
@@ -210,7 +213,7 @@ bool skip_ignore_initial( const long long ignore_initial, const int infd )
const int size = std::min( rest, (long long)buffer_size );
const int rd = readblock( infd, buffer, size );
if( rd != size && errno ) return false;
- if( rd < size ) break;
+ if( rd < size ) break; // EOF
rest -= rd;
}
}
@@ -270,6 +273,7 @@ int cmp( const long long max_size, const int infd[2],
uint8_t * buffer[2];
buffer[0] = buffer0; buffer[1] = buffer1;
int retval = 0;
+ bool empty[2] = { true, true };
while( rest > 0 )
{
@@ -282,6 +286,7 @@ int cmp( const long long max_size, const int infd[2],
if( rd[i] != size && errno )
{ show_file_error( filenames[i].c_str(), "Read error", errno );
retval = 2; goto done; }
+ if( rd[i] > 0 ) empty[i] = false;
}
for( int i = 0; i < 2; ++i )
if( rd[i] < size ) finished[i] = true;
@@ -345,11 +350,13 @@ int cmp( const long long max_size, const int infd[2],
if( rd[0] != rd[1] )
{
+ const int i = rd[1] < rd[0];
if( verbosity >= 0 )
- std::fprintf( stderr, list ?
+ std::fprintf( stderr, empty[i] ?
+ "%s: EOF on %s which is empty\n" : list ?
"%s: EOF on %s after byte %llu\n" :
"%s: EOF on %s after byte %llu, in line %llu\n",
- program_name, filenames[rd[1]<rd[0]].c_str(),
+ program_name, filenames[i].c_str(),
byte_number - 1, line_number );
retval = 1; break;
}
@@ -434,7 +441,7 @@ int main( const int argc, const char * const argv[] )
case lz_opt: parse_compressor( sarg, pn, fmt_lz ); break;
case xz_opt: parse_compressor( sarg, pn, fmt_xz ); break;
case zst_opt: parse_compressor( sarg, pn, fmt_zst ); break;
- default : internal_error( "uncaught option." );
+ default: internal_error( "uncaught option." );
}
} // end process options