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> 2025-01-05 Antonio Diaz Diaz <antonio@gnu.org>
* Version 1.14 released. * Version 1.14 released.

View file

@ -75,12 +75,12 @@ $(objs) : Makefile
$(scripts) : Makefile $(scripts) : Makefile
arg_parser.o : arg_parser.h arg_parser.o : arg_parser.h
rc.o : arg_parser.h rc.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 zcmp.o : arg_parser.h rc.h zutils.h zcmpdiff.cc
zdiff.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 zgrep.o : arg_parser.h rc.h zutils.h exclude.cc recursive.cc zcatgrep.cc
ztest.o : arg_parser.h rc.h zutils.h recursive.cc ztest.o : arg_parser.h rc.h zutils.h exclude.cc recursive.cc
zupdate.o : arg_parser.h rc.h recursive.cc zupdate.o : arg_parser.h rc.h exclude.cc recursive.cc
zutils.o : rc.h zutils.h zutils.o : rc.h zutils.h
doc : info man doc : info man
@ -230,8 +230,8 @@ dist : doc
$(DISTNAME)/testsuite/test.txt.tar \ $(DISTNAME)/testsuite/test.txt.tar \
$(DISTNAME)/testsuite/zcat_vs.dat \ $(DISTNAME)/testsuite/zcat_vs.dat \
$(DISTNAME)/testsuite/test_bad_crc.lz \ $(DISTNAME)/testsuite/test_bad_crc.lz \
$(DISTNAME)/testsuite/zero_bad_crc.lz \ $(DISTNAME)/testsuite/em_bad_crc.lz \
$(DISTNAME)/testsuite/zero_bad_crc.gz $(DISTNAME)/testsuite/em_bad_crc.gz
rm -f $(DISTNAME) rm -f $(DISTNAME)
lzip -v -9 $(DISTNAME).tar 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 The new option '-x, --exclude' has been added to zcat, ztest, and zupdate.
following the last slash in directory arguments; The new option '--exclude' has been added to zgrep.
'../a' recompresses the file ../a/b.gz to dir/a/b.lz, while It excludes files matching a shell pattern (for example '*.o').
'../a/' recompresses the file ../a/b.gz to dir/b.lz.
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. # to copy, distribute, and modify it.
pkgname=zutils pkgname=zutils
pkgversion=1.14 pkgversion=1.15
srctrigger=doc/${pkgname}.texi srctrigger=doc/${pkgname}.texi
# clear some things potentially inherited from environment. # 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. .\" 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 .SH NAME
zcat \- decompress and concatenate files to standard output zcat \- decompress and concatenate files to standard output
.SH SYNOPSIS .SH SYNOPSIS
@ -86,6 +86,9 @@ use '^' and 'M\-' notation, except for LF and TAB
\fB\-\-verbose\fR \fB\-\-verbose\fR
verbose mode (show error messages) verbose mode (show error messages)
.TP .TP
\fB\-x\fR, \fB\-\-exclude=\fR<pattern>
exclude files matching a shell pattern
.TP
\fB\-\-bz2=\fR<command> \fB\-\-bz2=\fR<command>
set compressor and options for bzip2 format set compressor and options for bzip2 format
.TP .TP

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2. .\" 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 .SH NAME
zcmp \- decompress and compare two files byte by byte zcmp \- decompress and compare two files byte by byte
.SH SYNOPSIS .SH SYNOPSIS

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.2. .\" 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 .SH NAME
zdiff \- decompress and compare two files line by line zdiff \- decompress and compare two files line by line
.SH SYNOPSIS .SH SYNOPSIS

View file

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

View file

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

View file

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

View file

@ -11,7 +11,7 @@ File: zutils.info, Node: Top, Next: Introduction, Up: (dir)
Zutils Manual 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: * 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 Verbose mode. Show error messages. Repeating it increases the verbosity
level. *Note version::. 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 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. were found, and 2 means trouble.
'zgrep' supports the following options (Some options only work if the grep '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 program used supports them. Options '--exclude', '-h', '-H', '-r', '-R',
'zgrep' and not passed to grep): and '-Z' are managed by 'zgrep' and not passed to grep):
'-a' '-a'
'--text' '--text'
@ -583,6 +592,14 @@ program used supports them. Options -h, -H, -r, -R, and -Z are managed by
'--extended-regexp' '--extended-regexp'
Interpret PATTERN as an extended regular expression (ERE). 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' '-f FILE'
'--file=FILE' '--file=FILE'
Obtain patterns from FILE, one per line. 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 Verbose mode. Show the check status for each file processed. Further
-v's increase the verbosity level. *Note version::. -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 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 the files being ignored and increases the verbosity level. *Note
version::. 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' '-0 .. -9'
Set the compression level of lzip. By default 'zupdate' passes '-9' to Set the compression level of lzip. By default 'zupdate' passes '-9' to
lzip. Custom compression options can be passed to lzip with the option lzip. Custom compression options can be passed to lzip with the option
@ -1031,22 +1066,22 @@ Concept index
 
Tag Table: Tag Table:
Node: Top217 Node: Top217
Node: Introduction1218 Node: Introduction1215
Ref: search-order2365 Ref: search-order2362
Node: Common options3522 Node: Common options3519
Ref: version4060 Ref: version4057
Ref: compressor-requirements6011 Ref: compressor-requirements6008
Node: Configuration7470 Node: Configuration7467
Node: Zcat8503 Node: Zcat8500
Node: Zcmp11314 Node: Zcmp11784
Node: Zdiff14554 Node: Zdiff15024
Node: Zgrep17609 Node: Zgrep18079
Node: Ztest23753 Node: Ztest24706
Node: Zupdate26543 Node: Zupdate27969
Ref: lz-compressor32558 Ref: lz-compressor34457
Node: Argument syntax33259 Node: Argument syntax35158
Node: Problems35151 Node: Problems37050
Node: Concept index35693 Node: Concept index37592
 
End Tag Table End Tag Table

View file

@ -6,8 +6,8 @@
@finalout @finalout
@c %**end of header @c %**end of header
@set UPDATED 5 January 2025 @set UPDATED 27 May 2025
@set VERSION 1.14 @set VERSION 1.15
@dircategory Compression @dircategory Compression
@direntry @direntry
@ -350,6 +350,16 @@ for "meta").
Verbose mode. Show error messages. Repeating it increases the verbosity Verbose mode. Show error messages. Repeating it increases the verbosity
level. @xref{version}. 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 @end table
@ -611,7 +621,8 @@ matches were found, and 2 means trouble.
@noindent @noindent
@command{zgrep} supports the following options (Some options only work if @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): managed by @command{zgrep} and not passed to grep):
@table @code @table @code
@ -651,6 +662,15 @@ Use @var{pattern} as the pattern to match.
@itemx --extended-regexp @itemx --extended-regexp
Interpret @var{pattern} as an extended regular expression (ERE). 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} @item -f @var{file}
@itemx --file=@var{file} @itemx --file=@var{file}
Obtain patterns from @var{file}, one per line.@* 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 Note that error detection in the xz format is broken. First, some xz files
lack integrity information. Second, not all xz decompressors can 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 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} @uref{http://tukaani.org/xz/xz-file-format.txt,,xz format specification}
allows xz decompressors to produce garbage output without issuing any 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 Verbose mode. Show the check status for each file processed. Further -v's
increase the verbosity level. @xref{version}. 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 @end table
@ -1007,6 +1037,16 @@ recursively, following all symbolic links.
Verbose mode. Show the files being processed. A second @option{-v} also shows Verbose mode. Show the files being processed. A second @option{-v} also shows
the files being ignored and increases the verbosity level. @xref{version}. 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 @item -0 .. -9
Set the compression level of lzip. By default @command{zupdate} passes Set the compression level of lzip. By default @command{zupdate} passes
@option{-9} to lzip. Custom compression options can be passed to lzip with @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 ); const bool help = false );
void show_file_error( const char * const filename, const char * const msg, void show_file_error( const char * const filename, const char * const msg,
const int errcode = 0 ); 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 internal_error( const char * const msg );
void show_option_error( const char * const arg, const char * const msg, void show_option_error( const char * const arg, const char * const msg,
const char * const option_name ); const char * const option_name );

View file

@ -63,6 +63,7 @@ bool next_filename( std::list< std::string > & filenames,
if( ignore_stdin ) continue; if( ignore_stdin ) continue;
input_filename = "."; return true; input_filename = "."; return true;
} }
if( Exclude::excluded( input_filename.c_str() ) ) continue; // skip file
struct stat st; struct stat st;
if( stat( input_filename.c_str(), &st ) == 0 && S_ISDIR( st.st_mode ) ) 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 $i in || compressor_needed
printf "Hello World!\n" > hello || framework_failure printf "Hello World!\n" > hello || framework_failure
$i hello || compressor_needed $i hello || compressor_needed
touch zero || framework_failure touch em || framework_failure
$i zero || compressor_needed $i em || compressor_needed
done done
cp "${testdir}"/test.txt in || framework_failure 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 -- -in-.lz || framework_failure
cp in.lz lz_only.lz || framework_failure cp in.lz lz_only.lz || framework_failure
cat in in in in in in > in6 || framework_failure cat in in in in in in > in6 || framework_failure
bad0_lz="${testdir}"/zero_bad_crc.lz bad0_lz="${testdir}"/em_bad_crc.lz
bad0_gz="${testdir}"/zero_bad_crc.gz bad0_gz="${testdir}"/em_bad_crc.gz
bad1_lz="${testdir}"/test_bad_crc.lz bad1_lz="${testdir}"/test_bad_crc.lz
touch empty empty.bz2 empty.gz empty.lz || framework_failure touch empty empty.bz2 empty.gz empty.lz || framework_failure
fail=0 fail=0
@ -75,9 +75,9 @@ for i in ${extensions}; do
cmp in out || test_failed $LINENO $i cmp in out || test_failed $LINENO $i
"${ZCAT}" -N in.$i empty.$i > out || test_failed $LINENO $i "${ZCAT}" -N in.$i empty.$i > out || test_failed $LINENO $i
cmp in 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 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 cmp in out || test_failed $LINENO $i
"${ZCAT}" -N --format=un in.$i > out || test_failed $LINENO $i "${ZCAT}" -N --format=un in.$i > out || test_failed $LINENO $i
cmp in 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 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 -i 1KiB:1024 -n 50 in.$i in6 || test_failed $LINENO $i
"${ZCMP}" -N empty empty.$i || 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 done
"${ZCMP}" -N -q in in6 "${ZCMP}" -N -q in in6
@ -248,7 +248,7 @@ for i in ${extensions}; do
"${ZDIFF}" -N in.$i in --force-format=$i, > /dev/null || "${ZDIFF}" -N in.$i in --force-format=$i, > /dev/null ||
test_failed $LINENO $i test_failed $LINENO $i
"${ZDIFF}" -N empty empty.$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 done
"${ZDIFF}" -N in in6 > /dev/null "${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 "${ZGREP}" -N --force-format=$i "GNU" in 2> /dev/null
[ $? = 2 ] || test_failed $LINENO $i [ $? = 2 ] || test_failed $LINENO $i
"${ZGREP}" -N "nx_pattern" empty.$i && 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 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 "nx_pattern" empty && test_failed $LINENO
"${ZGREP}" -N pin.tar4 -e "GNU" > /dev/null || test_failed $LINENO "${ZGREP}" -N pin.tar4 -e "GNU" > /dev/null || test_failed $LINENO
"${ZGREP}" -N "GNU" < pin.tar4 > /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 "${ZCMP}" -N in 'name with spaces.lz' || test_failed $LINENO
rm -f 'name with spaces.lz' || framework_failure 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 "${ZUPDATE}" -N -0 -q z.gz || test_failed $LINENO
[ ! -e z.gz ] || test_failed $LINENO [ ! -e z.gz ] || test_failed $LINENO
[ -e z.lz ] || test_failed $LINENO [ -e z.lz ] || test_failed $LINENO

34
zcat.cc
View file

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

32
zcmp.cc
View file

@ -93,17 +93,17 @@ void show_help()
// separate numbers of 5 or more digits in groups of 3 digits using '_' // 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 }; enum { buffers = 8, bufsize = 4 * sizeof num, n = 10 };
const char * const si_prefix = "kMGTPEZYRQ"; const char * const si_prefix = "kMGTPEZYRQ";
const char * const binary_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; static int current = 0;
char * const buf = buffer[current++]; current %= buffers; char * const buf = buffer[current++]; current %= buffers;
char * p = buf + bufsize - 1; // fill the buffer backwards char * p = buf + bufsize - 1; // fill the buffer backwards
*p = 0; // terminator *p = 0; // terminator
const bool negative = num < 0; const bool negative = num < 0;
if( num > 9999 || num < -9999 ) if( num > 9999 || num < -9999 )
{ {
@ -180,8 +180,8 @@ long long getnum( const char * const arg, const char * const option_name,
{ {
if( verbosity >= 0 ) if( verbosity >= 0 )
std::fprintf( stderr, "%s: '%s': Value out of limits [%s,%s] in " std::fprintf( stderr, "%s: '%s': Value out of limits [%s,%s] in "
"option '%s'.\n", program_name, arg, format_num3( llimit ), "option '%s'.\n", program_name, arg, format_num3p( llimit ),
format_num3( ulimit ), option_name ); format_num3p( ulimit ), option_name );
std::exit( 2 ); std::exit( 2 );
} }
if( tailp ) *tailp = tail; if( tailp ) *tailp = tail;
@ -372,7 +372,6 @@ done:
int main( const int argc, const char * const argv[] ) 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 // number of initial bytes ignored for each file
long long ignore_initial[2] = { 0, 0 }; long long ignore_initial[2] = { 0, 0 };
long long max_size = -1; // < 0 means unlimited size 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"; program_name = "zcmp";
invocation_name = ( argc > 0 ) ? argv[0] : program_name; 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[] = const Arg_parser::Option options[] =
{ {
{ 'b', "print-bytes", Arg_parser::no }, { 'b', "print-bytes", Arg_parser::no },
@ -400,11 +400,11 @@ int main( const int argc, const char * const argv[] )
{ 's', "script", Arg_parser::no }, { 's', "script", Arg_parser::no },
{ 'v', "verbose", Arg_parser::no }, { 'v', "verbose", Arg_parser::no },
{ 'V', "version", Arg_parser::no }, { 'V', "version", Arg_parser::no },
{ bz2_opt, "bz2", Arg_parser::yes }, { opt_bz2, "bz2", Arg_parser::yes },
{ gz_opt, "gz", Arg_parser::yes }, { opt_gz, "gz", Arg_parser::yes },
{ lz_opt, "lz", Arg_parser::yes }, { opt_lz, "lz", Arg_parser::yes },
{ xz_opt, "xz", Arg_parser::yes }, { opt_xz, "xz", Arg_parser::yes },
{ zst_opt, "zst", Arg_parser::yes }, { opt_zst, "zst", Arg_parser::yes },
{ 0, 0, Arg_parser::no } }; { 0, 0, Arg_parser::no } };
const Arg_parser parser( argc, argv, options ); 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 's': scripted = true; break;
case 'v': if( verbosity < 4 ) ++verbosity; break; case 'v': if( verbosity < 4 ) ++verbosity; break;
case 'V': show_version(); return 0; case 'V': show_version(); return 0;
case bz2_opt: parse_compressor( sarg, pn, fmt_bz2 ); break; case opt_bz2: parse_compressor( sarg, pn, fmt_bz2 ); break;
case gz_opt: parse_compressor( sarg, pn, fmt_gz ); break; case opt_gz: parse_compressor( sarg, pn, fmt_gz ); break;
case lz_opt: parse_compressor( sarg, pn, fmt_lz ); break; case opt_lz: parse_compressor( sarg, pn, fmt_lz ); break;
case xz_opt: parse_compressor( sarg, pn, fmt_xz ); break; case opt_xz: parse_compressor( sarg, pn, fmt_xz ); break;
case zst_opt: parse_compressor( sarg, pn, fmt_zst ); break; case opt_zst: parse_compressor( sarg, pn, fmt_zst ); break;
default: internal_error( "uncaught option." ); default: internal_error( "uncaught option." );
} }
} // end process options } // end process options

View file

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

View file

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

View file

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

View file

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