1
0
Fork 0

Merging upstream version 1.15.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-05-28 19:30:37 +02:00
parent ba8e0a83c7
commit 60d97c7cb2
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
24 changed files with 310 additions and 146 deletions

View file

@ -1,3 +1,10 @@
2025-05-27 Antonio Diaz Diaz <antonio@gnu.org>
* Version 1.15 released.
* zcat, ztest, zupdate: New option '-x, --exclude'.
* zgrep: New option '--exclude'.
* zgrep.cc: Exit with status 2 if write error on stdout.
2025-01-05 Antonio Diaz Diaz <antonio@gnu.org>
* Version 1.14 released.

View file

@ -75,12 +75,12 @@ $(objs) : Makefile
$(scripts) : Makefile
arg_parser.o : arg_parser.h
rc.o : arg_parser.h rc.h
zcat.o : arg_parser.h rc.h zutils.h recursive.cc zcatgrep.cc
zcat.o : arg_parser.h rc.h zutils.h exclude.cc recursive.cc zcatgrep.cc
zcmp.o : arg_parser.h rc.h zutils.h zcmpdiff.cc
zdiff.o : arg_parser.h rc.h zutils.h zcmpdiff.cc
zgrep.o : arg_parser.h rc.h zutils.h recursive.cc zcatgrep.cc
ztest.o : arg_parser.h rc.h zutils.h recursive.cc
zupdate.o : arg_parser.h rc.h recursive.cc
zgrep.o : arg_parser.h rc.h zutils.h exclude.cc recursive.cc zcatgrep.cc
ztest.o : arg_parser.h rc.h zutils.h exclude.cc recursive.cc
zupdate.o : arg_parser.h rc.h exclude.cc recursive.cc
zutils.o : rc.h zutils.h
doc : info man
@ -230,8 +230,8 @@ dist : doc
$(DISTNAME)/testsuite/test.txt.tar \
$(DISTNAME)/testsuite/zcat_vs.dat \
$(DISTNAME)/testsuite/test_bad_crc.lz \
$(DISTNAME)/testsuite/zero_bad_crc.lz \
$(DISTNAME)/testsuite/zero_bad_crc.gz
$(DISTNAME)/testsuite/em_bad_crc.lz \
$(DISTNAME)/testsuite/em_bad_crc.gz
rm -f $(DISTNAME)
lzip -v -9 $(DISTNAME).tar

11
NEWS
View file

@ -1,8 +1,7 @@
Changes in version 1.14:
Changes in version 1.15:
'zupdate --recursive --destdir=dir' now keeps the file name component
following the last slash in directory arguments;
'../a' recompresses the file ../a/b.gz to dir/a/b.lz, while
'../a/' recompresses the file ../a/b.gz to dir/b.lz.
The new option '-x, --exclude' has been added to zcat, ztest, and zupdate.
The new option '--exclude' has been added to zgrep.
It excludes files matching a shell pattern (for example '*.o').
The chapter 'Syntax of command-line arguments' has been added to the manual.
zgrep now exits with status 2 if a write error happens on stdout.

2
configure vendored
View file

@ -6,7 +6,7 @@
# to copy, distribute, and modify it.
pkgname=zutils
pkgversion=1.14
pkgversion=1.15
srctrigger=doc/${pkgname}.texi
# clear some things potentially inherited from environment.

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2.
.TH ZCAT "1" "January 2025" "zutils 1.14" "User Commands"
.TH ZCAT "1" "May 2025" "zutils 1.15" "User Commands"
.SH NAME
zcat \- decompress and concatenate files to standard output
.SH SYNOPSIS
@ -86,6 +86,9 @@ use '^' and 'M\-' notation, except for LF and TAB
\fB\-\-verbose\fR
verbose mode (show error messages)
.TP
\fB\-x\fR, \fB\-\-exclude=\fR<pattern>
exclude files matching a shell pattern
.TP
\fB\-\-bz2=\fR<command>
set compressor and options for bzip2 format
.TP

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2.
.TH ZCMP "1" "January 2025" "zutils 1.14" "User Commands"
.TH ZCMP "1" "May 2025" "zutils 1.15" "User Commands"
.SH NAME
zcmp \- decompress and compare two files byte by byte
.SH SYNOPSIS

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2.
.TH ZDIFF "1" "January 2025" "zutils 1.14" "User Commands"
.TH ZDIFF "1" "May 2025" "zutils 1.15" "User Commands"
.SH NAME
zdiff \- decompress and compare two files line by line
.SH SYNOPSIS

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2.
.TH ZGREP "1" "January 2025" "zutils 1.14" "User Commands"
.TH ZGREP "1" "May 2025" "zutils 1.15" "User Commands"
.SH NAME
zgrep \- search compressed files for a regular expression
.SH SYNOPSIS
@ -63,6 +63,9 @@ use <pattern> as the pattern to match
\fB\-E\fR, \fB\-\-extended\-regexp\fR
<pattern> is an extended regular expression
.TP
\fB\-\-exclude=\fR<pattern>
exclude files matching a shell pattern
.TP
\fB\-f\fR, \fB\-\-file=\fR<file>
obtain patterns from <file>
.TP

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2.
.TH ZTEST "1" "January 2025" "zutils 1.14" "User Commands"
.TH ZTEST "1" "May 2025" "zutils 1.15" "User Commands"
.SH NAME
ztest \- check the integrity of compressed files
.SH SYNOPSIS
@ -62,6 +62,9 @@ recursively follow symbolic links
\fB\-v\fR, \fB\-\-verbose\fR
be verbose (a 2nd \fB\-v\fR gives more)
.TP
\fB\-x\fR, \fB\-\-exclude=\fR<pattern>
exclude files matching a shell pattern
.TP
\fB\-\-bz2=\fR<command>
set compressor and options for bzip2 format
.TP

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2.
.TH ZUPDATE "1" "January 2025" "zutils 1.14" "User Commands"
.TH ZUPDATE "1" "May 2025" "zutils 1.15" "User Commands"
.SH NAME
zupdate \- recompress bzip2, gzip, xz, zstd files to lzip format
.SH SYNOPSIS
@ -79,6 +79,9 @@ recursively follow symbolic links
\fB\-v\fR, \fB\-\-verbose\fR
be verbose (a 2nd \fB\-v\fR gives more)
.TP
\fB\-x\fR, \fB\-\-exclude=\fR<pattern>
exclude files matching a shell pattern
.TP
\fB\-0\fR .. \fB\-9\fR
set compression level [default 9]
.TP

View file

@ -11,7 +11,7 @@ File: zutils.info, Node: Top, Next: Introduction, Up: (dir)
Zutils Manual
*************
This manual is for Zutils (version 1.14, 5 January 2025).
This manual is for Zutils (version 1.15, 27 May 2025).
* Menu:
@ -302,6 +302,15 @@ Exit status is 0 if no errors occurred, 1 otherwise.
Verbose mode. Show error messages. Repeating it increases the verbosity
level. *Note version::.
'-x PATTERN'
'--exclude=PATTERN'
Exclude files matching a shell pattern like '*.o', even if the files
are specified in the command line. A file is considered to match if any
component of the file name matches. For example, '*.o' matches
'foo.o', 'foo.o/bar' and 'foo/bar.o'. If PATTERN contains a '/', it
matches a corresponding '/' in the file name. For example, 'foo/*.o'
matches 'foo/bar.o'. Multiple '--exclude' options can be specified.

File: zutils.info, Node: Zcmp, Next: Zdiff, Prev: Zcat, Up: Top
@ -545,8 +554,8 @@ An exit status of 0 means at least one match was found, 1 means no matches
were found, and 2 means trouble.
'zgrep' supports the following options (Some options only work if the grep
program used supports them. Options -h, -H, -r, -R, and -Z are managed by
'zgrep' and not passed to grep):
program used supports them. Options '--exclude', '-h', '-H', '-r', '-R',
and '-Z' are managed by 'zgrep' and not passed to grep):
'-a'
'--text'
@ -583,6 +592,14 @@ program used supports them. Options -h, -H, -r, -R, and -Z are managed by
'--extended-regexp'
Interpret PATTERN as an extended regular expression (ERE).
'--exclude=PATTERN'
Exclude files matching a shell pattern like '*.o', even if the files
are specified in the command line. A file is considered to match if any
component of the file name matches. For example, '*.o' matches
'foo.o', 'foo.o/bar' and 'foo/bar.o'. If PATTERN contains a '/', it
matches a corresponding '/' in the file name. For example, 'foo/*.o'
matches 'foo/bar.o'. Multiple '--exclude' options can be specified.
'-f FILE'
'--file=FILE'
Obtain patterns from FILE, one per line.
@ -787,6 +804,15 @@ incorrect file name extension.
Verbose mode. Show the check status for each file processed. Further
-v's increase the verbosity level. *Note version::.
'-x PATTERN'
'--exclude=PATTERN'
Exclude files matching a shell pattern like '*.o', even if the files
are specified in the command line. A file is considered to match if any
component of the file name matches. For example, '*.o' matches
'foo.o', 'foo.o/bar' and 'foo/bar.o'. If PATTERN contains a '/', it
matches a corresponding '/' in the file name. For example, 'foo/*.o'
matches 'foo/bar.o'. Multiple '--exclude' options can be specified.

File: zutils.info, Node: Zupdate, Next: Argument syntax, Prev: Ztest, Up: Top
@ -925,6 +951,15 @@ compressor can't be run, or comparison fails).
the files being ignored and increases the verbosity level. *Note
version::.
'-x PATTERN'
'--exclude=PATTERN'
Exclude files matching a shell pattern like '*.o', even if the files
are specified in the command line. A file is considered to match if any
component of the file name matches. For example, '*.o' matches
'foo.o', 'foo.o/bar' and 'foo/bar.o'. If PATTERN contains a '/', it
matches a corresponding '/' in the file name. For example, 'foo/*.o'
matches 'foo/bar.o'. Multiple '--exclude' options can be specified.
'-0 .. -9'
Set the compression level of lzip. By default 'zupdate' passes '-9' to
lzip. Custom compression options can be passed to lzip with the option
@ -1031,22 +1066,22 @@ Concept index

Tag Table:
Node: Top217
Node: Introduction1218
Ref: search-order2365
Node: Common options3522
Ref: version4060
Ref: compressor-requirements6011
Node: Configuration7470
Node: Zcat8503
Node: Zcmp11314
Node: Zdiff14554
Node: Zgrep17609
Node: Ztest23753
Node: Zupdate26543
Ref: lz-compressor32558
Node: Argument syntax33259
Node: Problems35151
Node: Concept index35693
Node: Introduction1215
Ref: search-order2362
Node: Common options3519
Ref: version4057
Ref: compressor-requirements6008
Node: Configuration7467
Node: Zcat8500
Node: Zcmp11784
Node: Zdiff15024
Node: Zgrep18079
Node: Ztest24706
Node: Zupdate27969
Ref: lz-compressor34457
Node: Argument syntax35158
Node: Problems37050
Node: Concept index37592

End Tag Table

View file

@ -6,8 +6,8 @@
@finalout
@c %**end of header
@set UPDATED 5 January 2025
@set VERSION 1.14
@set UPDATED 27 May 2025
@set VERSION 1.15
@dircategory Compression
@direntry
@ -350,6 +350,16 @@ for "meta").
Verbose mode. Show error messages. Repeating it increases the verbosity
level. @xref{version}.
@item -x @var{pattern}
@itemx --exclude=@var{pattern}
Exclude files matching a shell pattern like @file{*.o}, even if the files
are specified in the command line. A file is considered to match if any
component of the file name matches. For example, @file{*.o} matches
@file{foo.o}, @file{foo.o/bar} and @file{foo/bar.o}. If @var{pattern}
contains a @samp{/}, it matches a corresponding @samp{/} in the file name.
For example, @file{foo/*.o} matches @file{foo/bar.o}. Multiple
@option{--exclude} options can be specified.
@end table
@ -611,7 +621,8 @@ matches were found, and 2 means trouble.
@noindent
@command{zgrep} supports the following options (Some options only work if
the grep program used supports them. Options -h, -H, -r, -R, and -Z are
the grep program used supports them. Options @option{--exclude},
@option{-h}, @option{-H}, @option{-r}, @option{-R}, and @option{-Z} are
managed by @command{zgrep} and not passed to grep):
@table @code
@ -651,6 +662,15 @@ Use @var{pattern} as the pattern to match.
@itemx --extended-regexp
Interpret @var{pattern} as an extended regular expression (ERE).
@item --exclude=@var{pattern}
Exclude files matching a shell pattern like @file{*.o}, even if the files
are specified in the command line. A file is considered to match if any
component of the file name matches. For example, @file{*.o} matches
@file{foo.o}, @file{foo.o/bar} and @file{foo/bar.o}. If @var{pattern}
contains a @samp{/}, it matches a corresponding @samp{/} in the file name.
For example, @file{foo/*.o} matches @file{foo/bar.o}. Multiple
@option{--exclude} options can be specified.
@item -f @var{file}
@itemx --file=@var{file}
Obtain patterns from @var{file}, one per line.@*
@ -812,7 +832,7 @@ files are ignored.
Note that error detection in the xz format is broken. First, some xz files
lack integrity information. Second, not all xz decompressors can
@uref{http://www.nongnu.org/lzip/xz_inadequate.html#fragmented,,check the integrity}
@uref{http://www.nongnu.org/lzip/xz_inadequate.html#checking,,check the integrity}
of all xz files. Third, section 2.1.1.2 'Stream Flags' of the
@uref{http://tukaani.org/xz/xz-file-format.txt,,xz format specification}
allows xz decompressors to produce garbage output without issuing any
@ -864,6 +884,16 @@ recursively, following all symbolic links.
Verbose mode. Show the check status for each file processed. Further -v's
increase the verbosity level. @xref{version}.
@item -x @var{pattern}
@itemx --exclude=@var{pattern}
Exclude files matching a shell pattern like @file{*.o}, even if the files
are specified in the command line. A file is considered to match if any
component of the file name matches. For example, @file{*.o} matches
@file{foo.o}, @file{foo.o/bar} and @file{foo/bar.o}. If @var{pattern}
contains a @samp{/}, it matches a corresponding @samp{/} in the file name.
For example, @file{foo/*.o} matches @file{foo/bar.o}. Multiple
@option{--exclude} options can be specified.
@end table
@ -1007,6 +1037,16 @@ recursively, following all symbolic links.
Verbose mode. Show the files being processed. A second @option{-v} also shows
the files being ignored and increases the verbosity level. @xref{version}.
@item -x @var{pattern}
@itemx --exclude=@var{pattern}
Exclude files matching a shell pattern like @file{*.o}, even if the files
are specified in the command line. A file is considered to match if any
component of the file name matches. For example, @file{*.o} matches
@file{foo.o}, @file{foo.o/bar} and @file{foo/bar.o}. If @var{pattern}
contains a @samp{/}, it matches a corresponding @samp{/} in the file name.
For example, @file{foo/*.o} matches @file{foo/bar.o}. Multiple
@option{--exclude} options can be specified.
@item -0 .. -9
Set the compression level of lzip. By default @command{zupdate} passes
@option{-9} to lzip. Custom compression options can be passed to lzip with

49
exclude.cc Normal file
View file

@ -0,0 +1,49 @@
/* Zutils - Utilities dealing with compressed files
Copyright (C) 2013-2025 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
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <fnmatch.h>
namespace Exclude {
std::vector< std::string > patterns; // list of patterns
void add_pattern( const std::string & arg )
{ patterns.push_back( arg ); }
bool excluded( const char * const filename )
{
if( patterns.empty() ) return false;
const char * p = filename;
do {
for( unsigned i = 0; i < patterns.size(); ++i )
// ignore a trailing sequence starting with '/' in filename
#ifdef FNM_LEADING_DIR
if( fnmatch( patterns[i].c_str(), p, FNM_LEADING_DIR ) == 0 ) return true;
#else
if( fnmatch( patterns[i].c_str(), p, 0 ) == 0 ||
fnmatch( ( patterns[i] + "/*" ).c_str(), p, 0 ) == 0 ) return true;
#endif
while( *p && *p != '/' ) ++p; // skip component
while( *p == '/' ) ++p; // skip slashes
} while( *p );
return false;
}
} // end namespace Exclude

2
rc.h
View file

@ -61,6 +61,8 @@ void show_error( const char * const msg, const int errcode = 0,
const bool help = false );
void show_file_error( const char * const filename, const char * const msg,
const int errcode = 0 );
inline void show_stdout_error( const int errcode = 0 )
{ show_file_error( "(stdout)", "Write error", errcode ); }
void internal_error( const char * const msg );
void show_option_error( const char * const arg, const char * const msg,
const char * const option_name );

View file

@ -63,6 +63,7 @@ bool next_filename( std::list< std::string > & filenames,
if( ignore_stdin ) continue;
input_filename = "."; return true;
}
if( Exclude::excluded( input_filename.c_str() ) ) continue; // skip file
struct stat st;
if( stat( input_filename.c_str(), &st ) == 0 && S_ISDIR( st.st_mode ) )
{

View file

@ -43,8 +43,8 @@ for i in ${compressors}; do
$i in || compressor_needed
printf "Hello World!\n" > hello || framework_failure
$i hello || compressor_needed
touch zero || framework_failure
$i zero || compressor_needed
touch em || framework_failure
$i em || compressor_needed
done
cp "${testdir}"/test.txt in || framework_failure
@ -55,8 +55,8 @@ cp in -- -in- || framework_failure
cp in.lz -- -in-.lz || framework_failure
cp in.lz lz_only.lz || framework_failure
cat in in in in in in > in6 || framework_failure
bad0_lz="${testdir}"/zero_bad_crc.lz
bad0_gz="${testdir}"/zero_bad_crc.gz
bad0_lz="${testdir}"/em_bad_crc.lz
bad0_gz="${testdir}"/em_bad_crc.gz
bad1_lz="${testdir}"/test_bad_crc.lz
touch empty empty.bz2 empty.gz empty.lz || framework_failure
fail=0
@ -75,9 +75,9 @@ for i in ${extensions}; do
cmp in out || test_failed $LINENO $i
"${ZCAT}" -N in.$i empty.$i > out || test_failed $LINENO $i
cmp in out || test_failed $LINENO $i
"${ZCAT}" -N zero.$i in.$i > out || test_failed $LINENO $i
"${ZCAT}" -N em.$i in.$i > out || test_failed $LINENO $i
cmp in out || test_failed $LINENO $i
"${ZCAT}" -N in.$i zero.$i > out || test_failed $LINENO $i
"${ZCAT}" -N in.$i em.$i > out || test_failed $LINENO $i
cmp in out || test_failed $LINENO $i
"${ZCAT}" -N --format=un in.$i > out || test_failed $LINENO $i
cmp in out || test_failed $LINENO $i
@ -163,7 +163,7 @@ for i in ${extensions}; do
"${ZCMP}" -N -i 1kB:1000 -n 500 in6 in.$i || test_failed $LINENO $i
"${ZCMP}" -N -i 1KiB:1024 -n 50 in.$i in6 || test_failed $LINENO $i
"${ZCMP}" -N empty empty.$i || test_failed $LINENO $i
"${ZCMP}" -N empty zero.$i || test_failed $LINENO $i
"${ZCMP}" -N empty em.$i || test_failed $LINENO $i
done
"${ZCMP}" -N -q in in6
@ -248,7 +248,7 @@ for i in ${extensions}; do
"${ZDIFF}" -N in.$i in --force-format=$i, > /dev/null ||
test_failed $LINENO $i
"${ZDIFF}" -N empty empty.$i > /dev/null || test_failed $LINENO $i
"${ZDIFF}" -N empty zero.$i > /dev/null || test_failed $LINENO $i
"${ZDIFF}" -N empty em.$i > /dev/null || test_failed $LINENO $i
done
"${ZDIFF}" -N in in6 > /dev/null
@ -329,9 +329,12 @@ for i in ${extensions}; do
"${ZGREP}" -N --force-format=$i "GNU" in 2> /dev/null
[ $? = 2 ] || test_failed $LINENO $i
"${ZGREP}" -N "nx_pattern" empty.$i && test_failed $LINENO $i
"${ZGREP}" -N "nx_pattern" zero.$i && test_failed $LINENO $i
"${ZGREP}" -N "nx_pattern" em.$i && test_failed $LINENO $i
done
printf "GNU\n" > patfile || framework_failure
"${ZGREP}" -N -f patfile in > /dev/null || test_failed $LINENO
rm -f patfile || framework_failure
"${ZGREP}" -N "nx_pattern" empty && test_failed $LINENO
"${ZGREP}" -N pin.tar4 -e "GNU" > /dev/null || test_failed $LINENO
"${ZGREP}" -N "GNU" < pin.tar4 > /dev/null || test_failed $LINENO
@ -592,7 +595,7 @@ cp in.gz 'name with spaces.gz' || framework_failure
"${ZCMP}" -N in 'name with spaces.lz' || test_failed $LINENO
rm -f 'name with spaces.lz' || framework_failure
cp zero.gz z.gz || framework_failure
cp em.gz z.gz || framework_failure
"${ZUPDATE}" -N -0 -q z.gz || test_failed $LINENO
[ ! -e z.gz ] || test_failed $LINENO
[ -e z.lz ] || test_failed $LINENO

34
zcat.cc
View file

@ -42,6 +42,7 @@
namespace {
#include "exclude.cc"
#include "recursive.cc"
#include "zcatgrep.cc"
@ -126,6 +127,7 @@ void show_help()
" -T, --show-tabs display TAB characters as '^I'\n"
" -v, --show-nonprinting use '^' and 'M-' notation, except for LF and TAB\n"
" --verbose verbose mode (show error messages)\n"
" -x, --exclude=<pattern> exclude files matching a shell pattern\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"
@ -155,7 +157,7 @@ bool do_cat( const int infd, const int buffer_size,
if( outpos >= buffer_size )
{
if( writeblock( STDOUT_FILENO, outbuf, outpos ) != outpos )
{ show_error( "Write error", errno ); return false; }
{ show_stdout_error( errno ); return false; }
outpos = 0;
}
if( inpos > rd ) // inbuf is empty
@ -169,7 +171,7 @@ bool do_cat( const int infd, const int buffer_size,
if( rd == 0 )
{
if( writeblock( STDOUT_FILENO, outbuf, outpos ) != outpos )
{ show_error( "Write error", errno ); return false; }
{ show_stdout_error( errno ); return false; }
outpos = 0;
return true;
}
@ -261,7 +263,6 @@ bool cat( int infd, const int format_index, const std::string & input_filename,
int main( const int argc, const char * const argv[] )
{
enum { verbose_opt = 256, bz2_opt, gz_opt, lz_opt, xz_opt, zst_opt };
int format_index = -1; // undefined
int recursive = 0; // 1 = '-r', 2 = '-R'
std::list< std::string > filenames;
@ -269,6 +270,7 @@ int main( const int argc, const char * const argv[] )
program_name = "zcat";
invocation_name = ( argc > 0 ) ? argv[0] : program_name;
enum { opt_bz2 = 256, opt_gz, opt_lz, opt_verbose, opt_xz, opt_zst };
const Arg_parser::Option options[] =
{
{ 'A', "show-all", Arg_parser::no }, // cat
@ -293,12 +295,13 @@ int main( const int argc, const char * const argv[] )
{ 'T', "show-tabs", Arg_parser::no }, // cat
{ 'v', "show-nonprinting", Arg_parser::no }, // cat
{ 'V', "version", Arg_parser::no },
{ verbose_opt, "verbose", Arg_parser::no },
{ bz2_opt, "bz2", Arg_parser::yes },
{ gz_opt, "gz", Arg_parser::yes },
{ lz_opt, "lz", Arg_parser::yes },
{ xz_opt, "xz", Arg_parser::yes },
{ zst_opt, "zst", Arg_parser::yes },
{ 'x', "exclude", Arg_parser::yes },
{ opt_verbose, "verbose", Arg_parser::no },
{ opt_bz2, "bz2", Arg_parser::yes },
{ opt_gz, "gz", Arg_parser::yes },
{ opt_lz, "lz", Arg_parser::yes },
{ opt_xz, "xz", Arg_parser::yes },
{ opt_zst, "zst", Arg_parser::yes },
{ 0, 0, Arg_parser::no } };
const Arg_parser parser( argc, argv, options );
@ -341,12 +344,13 @@ int main( const int argc, const char * const argv[] )
case 'T': cat_options.show_tabs = true; break;
case 'v': cat_options.show_nonprinting = true; break;
case 'V': show_version(); return 0;
case verbose_opt: if( verbosity < 4 ) ++verbosity; break;
case bz2_opt: parse_compressor( arg, pn, fmt_bz2, 1 ); break;
case gz_opt: parse_compressor( arg, pn, fmt_gz, 1 ); break;
case lz_opt: parse_compressor( arg, pn, fmt_lz, 1 ); break;
case xz_opt: parse_compressor( arg, pn, fmt_xz, 1 ); break;
case zst_opt: parse_compressor( arg, pn, fmt_zst, 1 ); break;
case 'x': Exclude::add_pattern( arg ); break;
case opt_verbose: if( verbosity < 4 ) ++verbosity; break;
case opt_bz2: parse_compressor( arg, pn, fmt_bz2, 1 ); break;
case opt_gz: parse_compressor( arg, pn, fmt_gz, 1 ); break;
case opt_lz: parse_compressor( arg, pn, fmt_lz, 1 ); break;
case opt_xz: parse_compressor( arg, pn, fmt_xz, 1 ); break;
case opt_zst: parse_compressor( arg, pn, fmt_zst, 1 ); break;
default: internal_error( "uncaught option." );
}
} // end process options

30
zcmp.cc
View file

@ -93,12 +93,12 @@ 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 * format_num3p( long long 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 char buffer[buffers][bufsize]; // circle of buffers for printf
static int current = 0;
char * const buf = buffer[current++]; current %= buffers;
@ -180,8 +180,8 @@ long long getnum( const char * const arg, const char * const option_name,
{
if( verbosity >= 0 )
std::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 );
"option '%s'.\n", program_name, arg, format_num3p( llimit ),
format_num3p( ulimit ), option_name );
std::exit( 2 );
}
if( tailp ) *tailp = tail;
@ -372,7 +372,6 @@ done:
int main( const int argc, const char * const argv[] )
{
enum { bz2_opt = 256, gz_opt, lz_opt, xz_opt, zst_opt };
// number of initial bytes ignored for each file
long long ignore_initial[2] = { 0, 0 };
long long max_size = -1; // < 0 means unlimited size
@ -384,6 +383,7 @@ int main( const int argc, const char * const argv[] )
program_name = "zcmp";
invocation_name = ( argc > 0 ) ? argv[0] : program_name;
enum { opt_bz2 = 256, opt_gz, opt_lz, opt_xz, opt_zst };
const Arg_parser::Option options[] =
{
{ 'b', "print-bytes", Arg_parser::no },
@ -400,11 +400,11 @@ int main( const int argc, const char * const argv[] )
{ 's', "script", Arg_parser::no },
{ 'v', "verbose", Arg_parser::no },
{ 'V', "version", Arg_parser::no },
{ bz2_opt, "bz2", Arg_parser::yes },
{ gz_opt, "gz", Arg_parser::yes },
{ lz_opt, "lz", Arg_parser::yes },
{ xz_opt, "xz", Arg_parser::yes },
{ zst_opt, "zst", Arg_parser::yes },
{ opt_bz2, "bz2", Arg_parser::yes },
{ opt_gz, "gz", Arg_parser::yes },
{ opt_lz, "lz", Arg_parser::yes },
{ opt_xz, "xz", Arg_parser::yes },
{ opt_zst, "zst", Arg_parser::yes },
{ 0, 0, Arg_parser::no } };
const Arg_parser parser( argc, argv, options );
@ -436,11 +436,11 @@ int main( const int argc, const char * const argv[] )
case 's': scripted = true; break;
case 'v': if( verbosity < 4 ) ++verbosity; break;
case 'V': show_version(); return 0;
case bz2_opt: parse_compressor( sarg, pn, fmt_bz2 ); break;
case gz_opt: parse_compressor( sarg, pn, fmt_gz ); break;
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;
case opt_bz2: parse_compressor( sarg, pn, fmt_bz2 ); break;
case opt_gz: parse_compressor( sarg, pn, fmt_gz ); break;
case opt_lz: parse_compressor( sarg, pn, fmt_lz ); break;
case opt_xz: parse_compressor( sarg, pn, fmt_xz ); break;
case opt_zst: parse_compressor( sarg, pn, fmt_zst ); break;
default: internal_error( "uncaught option." );
}
} // end process options

View file

@ -257,12 +257,12 @@ void set_signals()
int main( const int argc, const char * const argv[] )
{
enum { bz2_opt = 256, gz_opt, lz_opt, xz_opt, zst_opt };
std::vector< const char * > diff_args; // args to diff, maybe empty
int format_types[2] = { -1, -1 }; // < 0 means undefined
program_name = "zdiff";
invocation_name = ( argc > 0 ) ? argv[0] : program_name;
enum { opt_bz2 = 256, opt_gz, opt_lz, opt_xz, opt_zst };
const Arg_parser::Option options[] =
{
{ 'a', "text", Arg_parser::no },
@ -289,11 +289,11 @@ int main( const int argc, const char * const argv[] )
{ 'w', "ignore-all-space", Arg_parser::no },
{ 'W', "width", Arg_parser::yes },
{ 'y', "side-by-side", Arg_parser::no },
{ bz2_opt, "bz2", Arg_parser::yes },
{ gz_opt, "gz", Arg_parser::yes },
{ lz_opt, "lz", Arg_parser::yes },
{ xz_opt, "xz", Arg_parser::yes },
{ zst_opt, "zst", Arg_parser::yes },
{ opt_bz2, "bz2", Arg_parser::yes },
{ opt_gz, "gz", Arg_parser::yes },
{ opt_lz, "lz", Arg_parser::yes },
{ opt_xz, "xz", Arg_parser::yes },
{ opt_zst, "zst", Arg_parser::yes },
{ 0, 0, Arg_parser::no } };
const Arg_parser parser( argc, argv, options );
@ -336,11 +336,11 @@ int main( const int argc, const char * const argv[] )
case 'w': diff_args.push_back( "-w" ); break;
case 'W': diff_args.push_back( "-W" ); diff_args.push_back( arg ); break;
case 'y': diff_args.push_back( "-y" ); break;
case bz2_opt: parse_compressor( sarg, pn, fmt_bz2 ); break;
case gz_opt: parse_compressor( sarg, pn, fmt_gz ); break;
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;
case opt_bz2: parse_compressor( sarg, pn, fmt_bz2 ); break;
case opt_gz: parse_compressor( sarg, pn, fmt_gz ); break;
case opt_lz: parse_compressor( sarg, pn, fmt_lz ); break;
case opt_xz: parse_compressor( sarg, pn, fmt_xz ); break;
case opt_zst: parse_compressor( sarg, pn, fmt_zst ); break;
default: internal_error( "uncaught option." );
}
} // end process options

View file

@ -42,6 +42,7 @@
namespace {
#include "exclude.cc"
#include "recursive.cc"
#include "zcatgrep.cc"
@ -77,6 +78,7 @@ void show_help()
" --color[=<when>] show matched strings in color\n"
" -e, --regexp=<pattern> use <pattern> as the pattern to match\n"
" -E, --extended-regexp <pattern> is an extended regular expression\n"
" --exclude=<pattern> exclude files matching a shell pattern\n"
" -f, --file=<file> obtain patterns from <file>\n"
" -F, --fixed-strings <pattern> is a set of newline-separated strings\n"
" -G, --basic-regexp <pattern> is a basic regular expression (default)\n"
@ -186,7 +188,7 @@ int zgrep_file( int infd, const int format_index,
{ line_begin = true; if( line_buffered ) std::fflush( stdout ); }
}
else if( std::fwrite( buffer, 1, size, stdout ) != (unsigned)size )
{ std::fflush( stdout ); show_error( "Write error", errno ); return 2; }
{ std::fflush( stdout ); show_stdout_error( errno ); return 2; }
}
}
std::fflush( stdout );
@ -202,6 +204,8 @@ int zgrep_file( int infd, const int format_index,
{ show_close_error(); return 2; }
if( close( fda[0] ) != 0 )
{ show_close_error( GREP ); return 2; }
if( retval == 0 && std::ferror( stdout ) )
{ show_stdout_error(); retval = 2; }
return retval;
}
@ -210,8 +214,6 @@ int zgrep_file( int infd, const int format_index,
int main( const int argc, const char * const argv[] )
{
enum { help_opt = 256, verbose_opt, color_opt, label_opt, linebuf_opt,
bz2_opt, gz_opt, lz_opt, xz_opt, zst_opt };
int format_index = -1; // undefined
int list_mode = 0; // 1 = list matches, -1 = list non-matches
int recursive = 0; // 1 = '-r', 2 = '-R'
@ -228,6 +230,8 @@ int main( const int argc, const char * const argv[] )
program_name = "zgrep";
invocation_name = ( argc > 0 ) ? argv[0] : program_name;
enum { opt_bz2 = 256, opt_color, opt_exc, opt_gz, opt_help, opt_label,
opt_linebuf, opt_lz, opt_verbose, opt_xz, opt_zst };
const Arg_parser::Option options[] =
{
{ 'a', "text", Arg_parser::no }, // grep GNU
@ -266,16 +270,17 @@ int main( const int argc, const char * const argv[] )
{ 'w', "word-regexp", Arg_parser::no }, // grep GNU
{ 'x', "line-regexp", Arg_parser::no }, // grep
{ 'Z', "null", Arg_parser::no }, // grep GNU
{ help_opt, "help", Arg_parser::no },
{ verbose_opt, "verbose", Arg_parser::no },
{ color_opt, "color", Arg_parser::maybe },
{ label_opt, "label", Arg_parser::yes },
{ linebuf_opt, "line-buffered", Arg_parser::no },
{ bz2_opt, "bz2", Arg_parser::yes },
{ gz_opt, "gz", Arg_parser::yes },
{ lz_opt, "lz", Arg_parser::yes },
{ xz_opt, "xz", Arg_parser::yes },
{ zst_opt, "zst", Arg_parser::yes },
{ opt_color, "color", Arg_parser::maybe },
{ opt_exc, "exclude", Arg_parser::yes },
{ opt_help, "help", Arg_parser::no },
{ opt_label, "label", Arg_parser::yes },
{ opt_linebuf, "line-buffered", Arg_parser::no },
{ opt_verbose, "verbose", Arg_parser::no },
{ opt_bz2, "bz2", Arg_parser::yes },
{ opt_gz, "gz", Arg_parser::yes },
{ opt_lz, "lz", Arg_parser::yes },
{ opt_xz, "xz", Arg_parser::yes },
{ opt_zst, "zst", Arg_parser::yes },
{ 0, 0, Arg_parser::no } };
const Arg_parser parser( argc, argv, options );
@ -332,21 +337,22 @@ int main( const int argc, const char * const argv[] )
case 'w': grep_args.push_back( "-w" ); break;
case 'x': grep_args.push_back( "-x" ); break;
case 'Z': z_null = true; break;
case help_opt: show_help(); return 0;
case verbose_opt: no_messages = false; if( verbosity < 4 ) ++verbosity;
case opt_help: show_help(); return 0;
case opt_exc: Exclude::add_pattern( sarg ); break;
case opt_verbose: no_messages = false; if( verbosity < 4 ) ++verbosity;
break;
case color_opt: color_option = "--color";
case opt_color: color_option = "--color";
if( !sarg.empty() ) { color_option += '='; color_option += sarg; }
break;
case label_opt: label_option = "--label="; label_option += sarg;
case opt_label: label_option = "--label="; label_option += sarg;
label = arg; break;
case linebuf_opt: grep_args.push_back( "--line-buffered" );
case opt_linebuf: grep_args.push_back( "--line-buffered" );
line_buffered = true; break;
case bz2_opt: parse_compressor( sarg, pn, fmt_bz2 ); break;
case gz_opt: parse_compressor( sarg, pn, fmt_gz ); break;
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;
case opt_bz2: parse_compressor( sarg, pn, fmt_bz2 ); break;
case opt_gz: parse_compressor( sarg, pn, fmt_gz ); break;
case opt_lz: parse_compressor( sarg, pn, fmt_lz ); break;
case opt_xz: parse_compressor( sarg, pn, fmt_xz ); break;
case opt_zst: parse_compressor( sarg, pn, fmt_zst ); break;
default: internal_error( "uncaught option." );
}
} // end process options
@ -404,14 +410,12 @@ int main( const int argc, const char * const argv[] )
if( close( infd ) != 0 )
{ show_file_error( input_filename.c_str(), "Error closing input file",
errno ); error = true; }
if( retval == 0 && verbosity < 0 ) break;
if( ( retval == 0 && verbosity < 0 ) || // match
( retval == 2 && verbosity >= 0 ) ) break; // error
}
if( std::fclose( stdout ) != 0 )
{
show_error( "Error closing stdout", errno );
error = true;
}
if( std::fclose( stdout ) != 0 && !error )
{ show_error( "Error closing stdout", errno ); error = true; }
if( error && ( retval != 0 || verbosity >= 0 ) ) retval = 2;
return retval;
}

View file

@ -46,6 +46,7 @@
namespace {
#include "exclude.cc"
#include "recursive.cc"
void show_help()
@ -84,6 +85,7 @@ void show_help()
" -r, --recursive operate recursively on directories\n"
" -R, --dereference-recursive recursively follow symbolic links\n"
" -v, --verbose be verbose (a 2nd -v gives more)\n"
" -x, --exclude=<pattern> exclude files matching a shell pattern\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"
@ -247,7 +249,6 @@ int ztest_file( const int infd, int format_index,
int main( const int argc, const char * const argv[] )
{
enum { bz2_opt = 256, gz_opt, lz_opt, xz_opt, zst_opt };
int format_index = -1; // undefined
int recursive = 0; // 1 = '-r', 2 = '-R'
std::list< std::string > filenames;
@ -255,6 +256,7 @@ int main( const int argc, const char * const argv[] )
program_name = "ztest";
invocation_name = ( argc > 0 ) ? argv[0] : program_name;
enum { opt_bz2 = 256, opt_gz, opt_lz, opt_xz, opt_zst };
const Arg_parser::Option options[] =
{
{ 'h', "help", Arg_parser::no },
@ -266,11 +268,12 @@ int main( const int argc, const char * const argv[] )
{ 'R', "dereference-recursive", Arg_parser::no },
{ 'v', "verbose", Arg_parser::no },
{ 'V', "version", Arg_parser::no },
{ bz2_opt, "bz2", Arg_parser::yes },
{ gz_opt, "gz", Arg_parser::yes },
{ lz_opt, "lz", Arg_parser::yes },
{ xz_opt, "xz", Arg_parser::yes },
{ zst_opt, "zst", Arg_parser::yes },
{ 'x', "exclude", Arg_parser::yes },
{ opt_bz2, "bz2", Arg_parser::yes },
{ opt_gz, "gz", Arg_parser::yes },
{ opt_lz, "lz", Arg_parser::yes },
{ opt_xz, "xz", Arg_parser::yes },
{ opt_zst, "zst", Arg_parser::yes },
{ 0, 0, Arg_parser::no } };
const Arg_parser parser( argc, argv, options );
@ -298,11 +301,12 @@ int main( const int argc, const char * const argv[] )
case 'v': if( verbosity < 4 ) ++verbosity;
ztest_args.push_back( "-v" ); break;
case 'V': show_version(); return 0;
case bz2_opt: parse_compressor( arg, pn, fmt_bz2, 1 ); break;
case gz_opt: parse_compressor( arg, pn, fmt_gz, 1 ); break;
case lz_opt: parse_compressor( arg, pn, fmt_lz, 1 ); break;
case xz_opt: parse_compressor( arg, pn, fmt_xz, 1 ); break;
case zst_opt: parse_compressor( arg, pn, fmt_zst, 1 ); break;
case 'x': Exclude::add_pattern( arg ); break;
case opt_bz2: parse_compressor( arg, pn, fmt_bz2, 1 ); break;
case opt_gz: parse_compressor( arg, pn, fmt_gz, 1 ); break;
case opt_lz: parse_compressor( arg, pn, fmt_lz, 1 ); break;
case opt_xz: parse_compressor( arg, pn, fmt_xz, 1 ); break;
case opt_zst: parse_compressor( arg, pn, fmt_zst, 1 ); break;
default: internal_error( "uncaught option." );
}
} // end process options

View file

@ -51,6 +51,7 @@
namespace {
#include "exclude.cc"
#include "recursive.cc"
void show_help()
@ -94,6 +95,7 @@ void show_help()
" -r, --recursive operate recursively on directories\n"
" -R, --dereference-recursive recursively follow symbolic links\n"
" -v, --verbose be verbose (a 2nd -v gives more)\n"
" -x, --exclude=<pattern> exclude files matching a shell pattern\n"
" -0 .. -9 set compression level [default 9]\n"
" --bz2=<command> set compressor and options for bzip2 format\n"
" --gz=<command> set compressor and options for gzip format\n"
@ -382,7 +384,6 @@ int zupdate_file( const std::string & name, const char * const lzip_name,
int main( const int argc, const char * const argv[] )
{
enum { bz2_opt = 256, gz_opt, lz_opt, xz_opt, zst_opt };
int recursive = 0; // 1 = '-r', 2 = '-R'
std::string destdir; // write recompressed files here
std::vector< std::string > lzip_args2; // args to lzip, maybe empty
@ -394,6 +395,7 @@ int main( const int argc, const char * const argv[] )
program_name = "zupdate";
invocation_name = ( argc > 0 ) ? argv[0] : program_name;
enum { opt_bz2 = 256, opt_gz, opt_lz, opt_xz, opt_zst };
const Arg_parser::Option options[] =
{
{ '0', 0, Arg_parser::no },
@ -420,11 +422,12 @@ int main( const int argc, const char * const argv[] )
{ 'R', "dereference-recursive", Arg_parser::no },
{ 'v', "verbose", Arg_parser::no },
{ 'V', "version", Arg_parser::no },
{ bz2_opt, "bz2", Arg_parser::yes },
{ gz_opt, "gz", Arg_parser::yes },
{ lz_opt, "lz", Arg_parser::yes },
{ xz_opt, "xz", Arg_parser::yes },
{ zst_opt, "zst", Arg_parser::yes },
{ 'x', "exclude", Arg_parser::yes },
{ opt_bz2, "bz2", Arg_parser::yes },
{ opt_gz, "gz", Arg_parser::yes },
{ opt_lz, "lz", Arg_parser::yes },
{ opt_xz, "xz", Arg_parser::yes },
{ opt_zst, "zst", Arg_parser::yes },
{ 0, 0, Arg_parser::no } };
const Arg_parser parser( argc, argv, options );
@ -459,11 +462,12 @@ int main( const int argc, const char * const argv[] )
case 'R': recursive = 2; break;
case 'v': if( verbosity < 4 ) ++verbosity; break;
case 'V': show_version(); return 0;
case bz2_opt: parse_compressor( arg, pn, fmt_bz2, 1 ); break;
case gz_opt: parse_compressor( arg, pn, fmt_gz, 1 ); break;
case lz_opt: parse_compressor( arg, pn, fmt_lz, 1 ); break;
case xz_opt: parse_compressor( arg, pn, fmt_xz, 1 ); break;
case zst_opt: parse_compressor( arg, pn, fmt_zst, 1 ); break;
case 'x': Exclude::add_pattern( arg ); break;
case opt_bz2: parse_compressor( arg, pn, fmt_bz2, 1 ); break;
case opt_gz: parse_compressor( arg, pn, fmt_gz, 1 ); break;
case opt_lz: parse_compressor( arg, pn, fmt_lz, 1 ); break;
case opt_xz: parse_compressor( arg, pn, fmt_xz, 1 ); break;
case opt_zst: parse_compressor( arg, pn, fmt_zst, 1 ); break;
default: internal_error( "uncaught option." );
}
} // end process options