1
0
Fork 0

Merging upstream version 1.1~rc2.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-24 05:43:06 +01:00
parent 24e2ea3a41
commit e13f4df619
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
26 changed files with 1151 additions and 583 deletions

View file

@ -1,3 +1,15 @@
2013-07-07 Antonio Diaz Diaz <antonio@gnu.org>
* Version 1.1-rc2 released.
* Fixed all uses of decompressed/uncompressed.
2013-07-04 Antonio Diaz Diaz <antonio@gnu.org>
* Version 1.1-rc1 released.
* Added options '--bz2', '--gz', '--lz' and '--xz' to all utilities.
* Added runtime configuration file 'zutilsrc'.
* New function 'good_status' checks exit status of all children.
2013-05-31 Antonio Diaz Diaz <antonio@gnu.org>
* Version 1.0 released.
@ -7,7 +19,7 @@
file and '--recursive' has not been selected.
* Zgrep: Fixed output of option '-L' (it behaved like '-l').
* zcmp.cc: Fixed deadlock when '-n' option is used.
* zdiff.cc (set_data_feeder): Call decompressor with option "-q"
* zdiff.cc (set_data_feeder): Call compressor with option "-q"
only if verbosity < 0.
* zutils.cc (set_data_feeder): Likewise.
* Changed quote characters in messages as advised by GNU Standards.

View file

@ -1,7 +1,7 @@
Requirements
------------
You will need a C++ compiler.
I use gcc 4.8.0 and 3.3.6, but the code should compile with any
I use gcc 4.8.1 and 3.3.6, but the code should compile with any
standards compliant compiler.
Gcc is available at http://gcc.gnu.org.

View file

@ -7,9 +7,9 @@ INSTALL_DATA = $(INSTALL) -p -m 644
INSTALL_DIR = $(INSTALL) -d -m 755
SHELL = /bin/sh
objs = arg_parser.o zutils.o main.o
zcmp_objs = arg_parser.o zutils.o zcmp.o
zdiff_objs = arg_parser.o zutils.o zdiff.o
objs = arg_parser.o rc.o zutils.o main.o
zcmp_objs = arg_parser.o rc.o zutils.o zcmp.o
zdiff_objs = arg_parser.o rc.o zutils.o zdiff.o
scripts = zcat zegrep zfgrep zgrep ztest
@ -57,6 +57,9 @@ main.o : main.cc
zdiff.o : zdiff.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -DDIFF=\"$(DIFF)\" -c -o $@ $<
rc.o : rc.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -DSYSCONFDIR=\"$(sysconfdir)\" -c -o $@ $<
zutils.o : zutils.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -DPROGVERSION=\"$(pkgversion)\" -c -o $@ $<
@ -66,10 +69,11 @@ zutils.o : zutils.cc
$(objs) : Makefile
$(scripts) : Makefile
arg_parser.o : arg_parser.h
main.o : arg_parser.h zutils.h zcat.cc zgrep.cc ztest.cc
zcmp.o : arg_parser.h zutils.h zcmpdiff.cc Makefile
zdiff.o : arg_parser.h zutils.h zcmpdiff.cc Makefile
zutils.o : zutils.h
main.o : arg_parser.h zutils.h rc.h zcat.cc zgrep.cc ztest.cc
rc.o : arg_parser.h zutils.h rc.h
zcmp.o : arg_parser.h zutils.h rc.h zcmpdiff.cc Makefile
zdiff.o : arg_parser.h zutils.h rc.h zcmpdiff.cc Makefile
zutils.o : zutils.h rc.h
doc : info man
@ -120,6 +124,10 @@ install-bin : all
$(INSTALL_SCRIPT) ./zfgrep "$(DESTDIR)$(bindir)/zfgrep"
$(INSTALL_SCRIPT) ./zgrep "$(DESTDIR)$(bindir)/zgrep"
$(INSTALL_SCRIPT) ./ztest "$(DESTDIR)$(bindir)/ztest"
if [ ! -e "$(DESTDIR)$(sysconfdir)/$(pkgname)rc" ] ; then \
if [ ! -d "$(DESTDIR)$(sysconfdir)" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(sysconfdir)" ; fi ; \
$(INSTALL_DATA) $(VPATH)/$(pkgname)rc "$(DESTDIR)$(sysconfdir)/$(pkgname)rc" ; \
fi
install-info :
if [ ! -d "$(DESTDIR)$(infodir)" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(infodir)" ; fi
@ -148,6 +156,7 @@ uninstall-bin :
-rm -f "$(DESTDIR)$(bindir)/zfgrep"
-rm -f "$(DESTDIR)$(bindir)/zgrep"
-rm -f "$(DESTDIR)$(bindir)/ztest"
-rm -f "$(DESTDIR)$(sysconfdir)/$(pkgname)rc"
uninstall-info :
-install-info --info-dir="$(DESTDIR)$(infodir)" --remove "$(DESTDIR)$(infodir)/$(pkgname).info"
@ -177,6 +186,7 @@ dist : doc
$(DISTNAME)/testsuite/check.sh \
$(DISTNAME)/testsuite/test.txt \
$(DISTNAME)/testsuite/test.txt.tar \
$(DISTNAME)/$(pkgname)rc \
$(DISTNAME)/*.h \
$(DISTNAME)/*.cc \
$(DISTNAME)/z*.in

32
NEWS
View file

@ -1,28 +1,12 @@
Changes in version 1.0:
Changes in version 1.1:
The new option "--format" has been added to all utilities.
The new options "--bz2", "--gz", "--lz" and "--xz" have been added to
all utilities.
Zgrep no more prefixes the file name to the output by default when
searching one file and "--recursive" has not been selected.
Zutils now provides the runtime configuration file "zutilsrc", which
allows the user change the compressor to be used for each format.
The output of "zgrep -L" has been fixed (it behaved like "zgrep -l").
The checking of the exit status of compressors has been improved.
A deadlock in zcmp, which happens when the "-n" option is used, has been
fixed.
Decompressors are now invoked without the "-q" option except if
explicitly requested, as some simplified implementations do not accept
it.
Quote characters in messages have been changed as advised by GNU Coding
Standards.
"configure" now accepts options with a separate argument.
Configure option "--datadir" has been renamed to "--datarootdir" to
follow GNU Standards.
The target "install-bin" has been added to the Makefile.
Information has been added to the INSTALL file about how to install
zutils along with GNU gzip.
The use of "decompressed" and "uncompressed" in the documentation have
been revised.

9
README
View file

@ -1,8 +1,8 @@
Description
Zutils is a collection of utilities able to deal with any combination of
compressed and non-compressed files transparently. If any given file,
including standard input, is compressed, its uncompressed content is
compressed and uncompressed files transparently. If any given file,
including standard input, is compressed, its decompressed content is
used. Compressed files are decompressed on the fly; no temporary files
are created.
@ -12,6 +12,7 @@ those utilities supporting it.
The provided utilities are zcat, zcmp, zdiff, zgrep and ztest.
The supported formats are bzip2, gzip, lzip and xz.
The compressor to be used for each format is configurable at runtime.
Zcat, zcmp, zdiff, and zgrep are improved replacements for the shell
scripts provided with GNU gzip. Ztest is unique to zutils.
@ -20,6 +21,10 @@ NOTE: Bzip2 and lzip provide well-defined values of exit status, which
makes them safe to use with zutils. Gzip and xz may return ambiguous
warning values, making them less reliable backends for zutils.
LANGUAGE NOTE: Uncompressed = not compressed = plain data; it may never
have been compressed. Decompressed is used to refer to data which has
undergone the process of decompression.
Copyright (C) 2009, 2010, 2011, 2012, 2013 Antonio Diaz Diaz.

18
configure vendored
View file

@ -6,9 +6,9 @@
# to copy, distribute and modify it.
pkgname=zutils
pkgversion=1.0
pkgversion=1.1-rc2
progname=zutils
srctrigger=zutils.h
srctrigger=${pkgname}rc
# clear some things potentially inherited from environment.
LC_ALL=C
@ -20,6 +20,7 @@ bindir='$(exec_prefix)/bin'
datarootdir='$(prefix)/share'
infodir='$(datarootdir)/info'
mandir='$(datarootdir)/man'
sysconfdir='$(prefix)/etc'
CXX=g++
CPPFLAGS=
CXXFLAGS='-Wall -W -O2'
@ -66,6 +67,7 @@ while [ $# != 0 ] ; do
echo " --datarootdir=DIR base directory for doc and data [${datarootdir}]"
echo " --infodir=DIR info files directory [${infodir}]"
echo " --mandir=DIR man pages directory [${mandir}]"
echo " --sysconfdir=DIR read-only single-machine data directory [${sysconfdir}]"
echo " CXX=COMPILER C++ compiler to use [g++]"
echo " CPPFLAGS=OPTIONS command line options for the preprocessor [${CPPFLAGS}]"
echo " CXXFLAGS=OPTIONS command line options for the C++ compiler [${CXXFLAGS}]"
@ -84,6 +86,7 @@ while [ $# != 0 ] ; do
--datarootdir) datarootdir=$1 ; arg2=yes ;;
--infodir) infodir=$1 ; arg2=yes ;;
--mandir) mandir=$1 ; arg2=yes ;;
--sysconfdir) sysconfdir=$1 ; arg2=yes ;;
--srcdir=*) srcdir=${optarg} ;;
--prefix=*) prefix=${optarg} ;;
@ -92,6 +95,7 @@ while [ $# != 0 ] ; do
--datarootdir=*) datarootdir=${optarg} ;;
--infodir=*) infodir=${optarg} ;;
--mandir=*) mandir=${optarg} ;;
--sysconfdir=*) sysconfdir=${optarg} ;;
--no-create) no_create=yes ;;
CXX=*) CXX=${optarg} ;;
@ -106,7 +110,7 @@ while [ $# != 0 ] ; do
*=* | *-*-*) ;;
*)
echo "configure: unrecognized option: '${option}'" 1>&2
echo "Try 'configure --help' for more information."
echo "Try 'configure --help' for more information." 1>&2
exit 1 ;;
esac
@ -131,10 +135,8 @@ if [ -z "${srcdir}" ] ; then
fi
if [ ! -r "${srcdir}/${srctrigger}" ] ; then
exec 1>&2
echo
echo "configure: Can't find sources in ${srcdir} ${srcdirtext}"
echo "configure: (At least ${srctrigger} is missing)."
echo "configure: Can't find sources in ${srcdir} ${srcdirtext}" 1>&2
echo "configure: (At least ${srctrigger} is missing)." 1>&2
exit 1
fi
@ -166,6 +168,7 @@ echo "bindir = ${bindir}"
echo "datarootdir = ${datarootdir}"
echo "infodir = ${infodir}"
echo "mandir = ${mandir}"
echo "sysconfdir = ${sysconfdir}"
echo "CXX = ${CXX}"
echo "CPPFLAGS = ${CPPFLAGS}"
echo "CXXFLAGS = ${CXXFLAGS}"
@ -191,6 +194,7 @@ bindir = ${bindir}
datarootdir = ${datarootdir}
infodir = ${infodir}
mandir = ${mandir}
sysconfdir = ${sysconfdir}
CXX = ${CXX}
CPPFLAGS = ${CPPFLAGS}
CXXFLAGS = ${CXXFLAGS}

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH ZCAT "1" "May 2013" "Zcat (zutils) 1.0" "User Commands"
.TH ZCAT "1" "July 2013" "Zcat (zutils) 1.1-rc2" "User Commands"
.SH NAME
Zcat \- decompress and concatenate files to standard output
.SH SYNOPSIS
@ -7,7 +7,7 @@ Zcat \- decompress and concatenate files to standard output
[\fIoptions\fR] [\fIfiles\fR]
.SH DESCRIPTION
Zcat copies each given file ("\-" means standard input), to standard
output. If any given file is compressed, its uncompressed content is
output. If any given file is compressed, its decompressed content is
used. If a given file does not exist, and its name does not end with one
of the known extensions, zcat tries the compressed file names
corresponding to the supported formats. If no files are specified,
@ -17,7 +17,7 @@ all uncompressed or all in the same compression format.
.PP
The supported formats are bzip2, gzip, lzip and xz.
.PP
Exit status is 0 if no errors occurred, 1 otherwise.
Exit status is 0 if no errors occurred, non\-zero otherwise.
.SH OPTIONS
.TP
\fB\-h\fR, \fB\-\-help\fR
@ -44,6 +44,9 @@ force given format (bz2, gz, lz, xz)
\fB\-n\fR, \fB\-\-number\fR
number all output lines
.TP
\fB\-N\fR, \fB\-\-no\-rcfile\fR
don't read runtime configuration file
.TP
\fB\-q\fR, \fB\-\-quiet\fR
suppress all messages
.TP
@ -64,6 +67,18 @@ use '^' and 'M\-' notation, except for LF and TAB
.TP
\fB\-\-verbose\fR
verbose mode (show error messages)
.TP
\fB\-\-bz2=\fR<command>
set compressor and options for bzip2 format
.TP
\fB\-\-gz=\fR<command>
set compressor and options for gzip format
.TP
\fB\-\-lz=\fR<command>
set compressor and options for lzip format
.TP
\fB\-\-xz=\fR<command>
set compressor and options for xz format
.SH "REPORTING BUGS"
Report bugs to zutils\-bug@nongnu.org
.br

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH ZCMP "1" "May 2013" "Zcmp (zutils) 1.0" "User Commands"
.TH ZCMP "1" "July 2013" "Zcmp (zutils) 1.1-rc2" "User Commands"
.SH NAME
Zcmp \- decompress and compare two files byte by byte
.SH SYNOPSIS
@ -9,19 +9,22 @@ Zcmp \- decompress and compare two files byte by byte
Zcmp compares two files ("\-" means standard input), and if they
differ, tells the first byte and line number where they differ. Bytes
and lines are numbered starting with 1. If any given file is compressed,
its uncompressed content is used. Compressed files are uncompressed on
its decompressed content is used. Compressed files are decompressed on
the fly; no temporary files are created.
.PP
The supported formats are bzip2, gzip, lzip and xz.
.PP
Compares <file1> to <file2>. If <file2> is omitted zcmp tries the
following:
If <file1> is compressed, compares <file1> to the file with the
corresponding decompressed file name (removes the extension from
<file1>).
If <file1> is not compressed, compares <file1> to the uncompressed
.IP
1. If <file1> is compressed, compares its decompressed contents with
the corresponding uncompressed file (the name of <file1> with the
extension removed).
.IP
2. If <file1> is uncompressed, compares it with the decompressed
contents of <file1>.[lz|bz2|gz|xz] (the first one that is found).
If no suitable file is found, compares <file1> to data read from
.IP
3. If no suitable file is found, compares <file1> with data read from
standard input.
.PP
Exit status is 0 if inputs are identical, 1 if different, 2 if trouble.
@ -48,6 +51,9 @@ list position, value of all differing bytes
\fB\-n\fR, \fB\-\-bytes=\fR<n>
compare at most <n> bytes
.TP
\fB\-N\fR, \fB\-\-no\-rcfile\fR
don't read runtime configuration file
.TP
\fB\-q\fR, \fB\-\-quiet\fR
suppress all messages
.TP
@ -56,6 +62,18 @@ suppress all messages
.TP
\fB\-v\fR, \fB\-\-verbose\fR
verbose mode (same as \fB\-\-list\fR)
.TP
\fB\-\-bz2=\fR<command>
set compressor and options for bzip2 format
.TP
\fB\-\-gz=\fR<command>
set compressor and options for gzip format
.TP
\fB\-\-lz=\fR<command>
set compressor and options for lzip format
.TP
\fB\-\-xz=\fR<command>
set compressor and options for xz format
.PP
Numbers may be followed by a multiplier: k = kB = 10^3 = 1000,
Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH ZDIFF "1" "May 2013" "Zdiff (zutils) 1.0" "User Commands"
.TH ZDIFF "1" "July 2013" "Zdiff (zutils) 1.1-rc2" "User Commands"
.SH NAME
Zdiff \- decompress and compare two files line by line
.SH SYNOPSIS
@ -8,7 +8,7 @@ Zdiff \- decompress and compare two files line by line
.SH DESCRIPTION
Zdiff compares two files ("\-" means standard input), and if they
differ, shows the differences line by line. If any given file is
compressed, its uncompressed content is used. Zdiff is a front end to
compressed, its decompressed content is used. Zdiff is a front end to
the diff program and has the limitation that messages from diff refer to
temporary filenames instead of those specified.
.PP
@ -16,12 +16,15 @@ The supported formats are bzip2, gzip, lzip and xz.
.PP
Compares <file1> to <file2>. If <file2> is omitted zdiff tries the
following:
If <file1> is compressed, compares <file1> to the file with the
corresponding decompressed file name (removes the extension from
<file1>).
If <file1> is not compressed, compares <file1> to the uncompressed
.IP
1. If <file1> is compressed, compares its decompressed contents with
the corresponding uncompressed file (the name of <file1> with the
extension removed).
.IP
2. If <file1> is uncompressed, compares it with the decompressed
contents of <file1>.[lz|bz2|gz|xz] (the first one that is found).
If no suitable file is found, compares <file1> to data read from
.IP
3. If no suitable file is found, compares <file1> with data read from
standard input.
.PP
Exit status is 0 if inputs are identical, 1 if different, 2 if trouble.
@ -60,6 +63,9 @@ force given formats (bz2, gz, lz, xz)
\fB\-i\fR, \fB\-\-ignore\-case\fR
ignore case differences in file contents
.TP
\fB\-N\fR, \fB\-\-no\-rcfile\fR
don't read runtime configuration file
.TP
\fB\-p\fR, \fB\-\-show\-c\-function\fR
show which C function each change is in
.TP
@ -83,6 +89,18 @@ same as \fB\-u\fR but use <n> lines of context
.TP
\fB\-w\fR, \fB\-\-ignore\-all\-space\fR
ignore all white space
.TP
\fB\-\-bz2=\fR<command>
set compressor and options for bzip2 format
.TP
\fB\-\-gz=\fR<command>
set compressor and options for gzip format
.TP
\fB\-\-lz=\fR<command>
set compressor and options for lzip format
.TP
\fB\-\-xz=\fR<command>
set compressor and options for xz format
.PP
Numbers may be followed by a multiplier: k = kB = 10^3 = 1000,
Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH ZGREP "1" "May 2013" "Zgrep (zutils) 1.0" "User Commands"
.TH ZGREP "1" "July 2013" "Zgrep (zutils) 1.1-rc2" "User Commands"
.SH NAME
Zgrep \- search compressed files for a regular expression
.SH SYNOPSIS
@ -7,8 +7,8 @@ Zgrep \- search compressed files for a regular expression
[\fIoptions\fR] \fI<pattern> \fR[\fIfiles\fR]
.SH DESCRIPTION
Zgrep is a front end to the grep program that allows transparent search
on any combination of compressed and non\-compressed files. If any given
file is compressed, its uncompressed content is used. If a given file
on any combination of compressed and uncompressed files. If any given
file is compressed, its decompressed content is used. If a given file
does not exist, and its name does not end with one of the known
extensions, zgrep tries the compressed file names corresponding to the
supported formats. If no files are specified, data is read from
@ -84,6 +84,9 @@ stop after <n> matches
\fB\-n\fR, \fB\-\-line\-number\fR
print the line number of each line
.TP
\fB\-N\fR, \fB\-\-no\-rcfile\fR
don't read runtime configuration file
.TP
\fB\-o\fR, \fB\-\-only\-matching\fR
show only the part of a line matching <pattern>
.TP
@ -107,6 +110,18 @@ match only whole words
.TP
\fB\-x\fR, \fB\-\-line\-regexp\fR
match only whole lines
.TP
\fB\-\-bz2=\fR<command>
set compressor and options for bzip2 format
.TP
\fB\-\-gz=\fR<command>
set compressor and options for gzip format
.TP
\fB\-\-lz=\fR<command>
set compressor and options for lzip format
.TP
\fB\-\-xz=\fR<command>
set compressor and options for xz format
.SH "REPORTING BUGS"
Report bugs to zutils\-bug@nongnu.org
.br

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH ZTEST "1" "May 2013" "Ztest (zutils) 1.0" "User Commands"
.TH ZTEST "1" "July 2013" "Ztest (zutils) 1.1-rc2" "User Commands"
.SH NAME
Ztest \- verify integrity of compressed files
.SH SYNOPSIS
@ -7,9 +7,9 @@ Ztest \- verify integrity of compressed files
[\fIoptions\fR] [\fIfiles\fR]
.SH DESCRIPTION
Ztest verifies the integrity of the specified compressed files.
Non\-compressed files are ignored. If no files are specified, the
integrity of compressed data read from standard input is verified. Data
read from standard input must be all in the same compression format.
Uncompressed files are ignored. If no files are specified, the integrity
of compressed data read from standard input is verified. Data read from
standard input must be all in the same compression format.
.PP
The supported formats are bzip2, gzip, lzip and xz.
.PP
@ -30,6 +30,9 @@ output version information and exit
\fB\-\-format=\fR<fmt>
force given format (bz2, gz, lz, xz)
.TP
\fB\-N\fR, \fB\-\-no\-rcfile\fR
don't read runtime configuration file
.TP
\fB\-q\fR, \fB\-\-quiet\fR
suppress all messages
.TP
@ -38,6 +41,18 @@ operate recursively on directories
.TP
\fB\-v\fR, \fB\-\-verbose\fR
be verbose (a 2nd \fB\-v\fR gives more)
.TP
\fB\-\-bz2=\fR<command>
set compressor and options for bzip2 format
.TP
\fB\-\-gz=\fR<command>
set compressor and options for gzip format
.TP
\fB\-\-lz=\fR<command>
set compressor and options for lzip format
.TP
\fB\-\-xz=\fR<command>
set compressor and options for xz format
.SH "REPORTING BUGS"
Report bugs to zutils\-bug@nongnu.org
.br

View file

@ -12,18 +12,20 @@ File: zutils.info, Node: Top, Next: Introduction, Up: (dir)
Zutils Manual
*************
This manual is for Zutils (version 1.0, 31 May 2013).
This manual is for Zutils (version 1.1-rc2, 7 July 2013).
* Menu:
* Introduction:: Purpose and features of zutils
* Common options:: Common options
* The zutilsrc file:: The zutils configuration file
* Zcat:: Concatenating compressed files
* Zcmp:: Comparing compressed files byte by byte
* Zdiff:: Comparing compressed files line by line
* Zgrep:: Searching inside compressed files
* Ztest:: Testing integrity of compressed files
* Problems:: Reporting bugs
* Concept Index:: Index of concepts
* Concept index:: Index of concepts
Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013 Antonio Diaz Diaz.
@ -32,14 +34,14 @@ This manual is for Zutils (version 1.0, 31 May 2013).
copy, distribute and modify it.

File: zutils.info, Node: Introduction, Next: Zcat, Prev: Top, Up: Top
File: zutils.info, Node: Introduction, Next: Common options, Prev: Top, Up: Top
1 Introduction
**************
Zutils is a collection of utilities able to deal with any combination of
compressed and non-compressed files transparently. If any given file,
including standard input, is compressed, its uncompressed content is
compressed and uncompressed files transparently. If any given file,
including standard input, is compressed, its decompressed content is
used. Compressed files are decompressed on the fly; no temporary files
are created.
@ -49,6 +51,7 @@ in those utilities supporting it.
The provided utilities are zcat, zcmp, zdiff, zgrep and ztest.
The supported formats are bzip2, gzip, lzip and xz.
The compressor to be used for each format is configurable at runtime.
Zcat, zcmp, zdiff, and zgrep are improved replacements for the shell
scripts provided with GNU gzip. Ztest is unique to zutils.
@ -57,6 +60,10 @@ scripts provided with GNU gzip. Ztest is unique to zutils.
which makes them safe to use with zutils. Gzip and xz may return
ambiguous warning values, making them less reliable backends for zutils.
LANGUAGE NOTE: Uncompressed = not compressed = plain data; it may
never have been compressed. Decompressed is used to refer to data which
has undergone the process of decompression.
Numbers given as arguments to options (positions, sizes) may be
followed by a multiplier and an optional `B' for "byte".
@ -74,13 +81,81 @@ Z zettabyte (10^21) | Zi zebibyte (2^70)
Y yottabyte (10^24) | Yi yobibyte (2^80)

File: zutils.info, Node: Zcat, Next: Zcmp, Prev: Introduction, Up: Top
File: zutils.info, Node: Common options, Next: The zutilsrc file, Prev: Introduction, Up: Top
2 Zcat
2 Common options
****************
The following options are available in all the utilities. Rather than
writing identical descriptions for each of the programs, they are
described here.
`-h'
`--help'
Print an informative help message describing the options and exit.
Zgrep only supports the `--help' form of this option.
`-V'
`--version'
Print the version number on the standard output and exit.
`-N'
`--no-rcfile'
Don't read the runtime configuration file `zutilsrc'.
`--bz2=COMMAND'
`--gz=COMMAND'
`--lz=COMMAND'
`--xz=COMMAND'
Set program (may include arguments) to be used as (de)compressor
for the given format. These options override the values set in
`zutilsrc'. The compression program used must meet three
requirements:
1. When called with the `-d' option, it must read compressed
data from the standard input and produce decompressed data on
the standard output.
2. If the `-q' option is passed to zutils, the compression
program must also accept it.
3. It must return 0 if no errors occurred, and a non-zero value
otherwise.

File: zutils.info, Node: The zutilsrc file, Next: Zcat, Prev: Common options, Up: Top
3 The zutilsrc file
*******************
`zutilsrc' is the runtime configuration file for zutils. In it you may
define the compressor name and options to be used for each format. The
`zutilsrc' file is optional; you do not need to install it in order to
run zutils.
The compressors specified in the command line override those
specified in the `zutilsrc' file.
You may copy the system `zutilsrc' file `${sysconfdir}/zutilsrc' to
`$HOME/.zutilsrc' and customize these options as you like. The file
syntax is fairly obvious (and there are further instructions in it):
1. Any line beginning with `#' is a comment line.
2. Each non-comment line defines the command to be used for the given
format, with the syntax:
<format> = <compressor> [options]
where <format> is one of `bz2', `gz', `lz' or `xz'.

File: zutils.info, Node: Zcat, Next: Zcmp, Prev: The zutilsrc file, Up: Top
4 Zcat
******
Zcat copies each given file (`-' means standard input), to standard
output. If any given file is compressed, its uncompressed content is
output. If any given file is compressed, its decompressed content is
used. If a given file does not exist, and its name does not end with one
of the known extensions, zcat tries the compressed file names
corresponding to the supported formats.
@ -94,18 +169,10 @@ same compression format.
zcat [OPTIONS] [FILES]
Exit status is 0 if no errors occurred, 1 otherwise.
Exit status is 0 if no errors occurred, non-zero otherwise.
Zcat supports the following options:
`-h'
`--help'
Print an informative help message describing the options and exit.
`-V'
`--version'
Print the version number of zcat on the standard output and exit.
`-A'
`--show-all'
Equivalent to `-vET'.
@ -164,13 +231,13 @@ Exit status is 0 if no errors occurred, 1 otherwise.

File: zutils.info, Node: Zcmp, Next: Zdiff, Prev: Zcat, Up: Top
3 Zcmp
5 Zcmp
******
Zcmp compares two files (`-' means standard input), and if they differ,
tells the first byte and line number where they differ. Bytes and lines
are numbered starting with 1. If any given file is compressed, its
uncompressed content is used. Compressed files are decompressed on the
decompressed content is used. Compressed files are decompressed on the
fly; no temporary files are created.
The format for running zcmp is:
@ -180,14 +247,14 @@ fly; no temporary files are created.
This compares FILE1 to FILE2. If FILE2 is omitted zcmp tries the
following:
1. If FILE1 is compressed, compares FILE1 to the file with the
corresponding decompressed file name (removes the extension from
FILE1).
1. If FILE1 is compressed, compares its decompressed contents with
the corresponding uncompressed file (the name of FILE1 with the
extension removed).
2. If FILE1 is not compressed, compares FILE1 to the uncompressed
2. If FILE1 is uncompressed, compares it with the decompressed
contents of FILE1.[lz|bz2|gz|xz] (the first one that is found).
3. If no suitable file is found, compares FILE1 to data read from
3. If no suitable file is found, compares FILE1 with data read from
standard input.
An exit status of 0 means no differences were found, 1 means some
@ -195,14 +262,6 @@ differences were found, and 2 means trouble.
Zcmp supports the following options:
`-h'
`--help'
Print an informative help message describing the options and exit.
`-V'
`--version'
Print the version number of zcmp on the standard output and exit.
`-b'
`--print-bytes'
Print the differing bytes. Print control bytes as a `^' followed by
@ -247,12 +306,12 @@ differences were found, and 2 means trouble.

File: zutils.info, Node: Zdiff, Next: Zgrep, Prev: Zcmp, Up: Top
4 Zdiff
6 Zdiff
*******
Zdiff compares two files (`-' means standard input), and if they
differ, shows the differences line by line. If any given file is
compressed, its uncompressed content is used. Zdiff is a front end to
compressed, its decompressed content is used. Zdiff is a front end to
the diff program and has the limitation that messages from diff refer to
temporary filenames instead of those specified.
@ -263,14 +322,14 @@ temporary filenames instead of those specified.
This compares FILE1 to FILE2. If FILE2 is omitted zdiff tries the
following:
1. If FILE1 is compressed, compares FILE1 to the file with the
corresponding decompressed file name (removes the extension from
FILE1).
1. If FILE1 is compressed, compares its decompressed contents with
the corresponding uncompressed file (the name of FILE1 with the
extension removed).
2. If FILE1 is not compressed, compares FILE1 to the uncompressed
2. If FILE1 is uncompressed, compares it with the decompressed
contents of FILE1.[lz|bz2|gz|xz] (the first one that is found).
3. If no suitable file is found, compares FILE1 to data read from
3. If no suitable file is found, compares FILE1 with data read from
standard input.
An exit status of 0 means no differences were found, 1 means some
@ -278,14 +337,6 @@ differences were found, and 2 means trouble.
Zdiff supports the following options:
`-h'
`--help'
Print an informative help message describing the options and exit.
`-V'
`--version'
Print the version number of zdiff on the standard output and exit.
`-a'
`--text'
Treat all files as text.
@ -360,12 +411,12 @@ differences were found, and 2 means trouble.

File: zutils.info, Node: Zgrep, Next: Ztest, Prev: Zdiff, Up: Top
5 Zgrep
7 Zgrep
*******
Zgrep is a front end to the grep program that allows transparent search
on any combination of compressed and non-compressed files. If any given
file is compressed, its uncompressed content is used. If a given file
on any combination of compressed and uncompressed files. If any given
file is compressed, its decompressed content is used. If a given file
does not exist, and its name does not end with one of the known
extensions, zgrep tries the compressed file names corresponding to the
supported formats.
@ -384,13 +435,6 @@ matches were found, and 2 means trouble.
Zgrep supports the following options:
`--help'
Print an informative help message describing the options and exit.
`-V'
`--version'
Print the version number of zgrep on the standard output and exit.
`-a'
`--text'
Treat all files as text.
@ -503,13 +547,13 @@ matches were found, and 2 means trouble.

File: zutils.info, Node: Ztest, Next: Problems, Prev: Zgrep, Up: Top
6 Ztest
8 Ztest
*******
Ztest verifies the integrity of the specified compressed files.
Non-compressed files are ignored. If no files are specified, the
integrity of compressed data read from standard input is verified. Data
read from standard input must be all in the same compression format.
Uncompressed files are ignored. If no files are specified, the integrity
of compressed data read from standard input is verified. Data read from
standard input must be all in the same compression format.
Note that some xz files lack integrity information, and therefore
can't be verified as reliably as the other formats can.
@ -524,14 +568,6 @@ environmental problems (file not found, invalid flags, I/O errors, etc),
Ztest supports the following options:
`-h'
`--help'
Print an informative help message describing the options and exit.
`-V'
`--version'
Print the version number of ztest on the standard output and exit.
`--format=FMT'
Force the given compression format. Valid values for FMT are
`bz2', `gz', `lz' and `xz'. If this option is used, all files not
@ -552,9 +588,9 @@ environmental problems (file not found, invalid flags, I/O errors, etc),

File: zutils.info, Node: Problems, Next: Concept Index, Prev: Ztest, Up: Top
File: zutils.info, Node: Problems, Next: Concept index, Prev: Ztest, Up: Top
7 Reporting Bugs
9 Reporting Bugs
****************
There are probably bugs in zutils. There are certainly errors and
@ -567,17 +603,19 @@ for all eternity, if not longer.
by running `zutils --version'.

File: zutils.info, Node: Concept Index, Prev: Problems, Up: Top
File: zutils.info, Node: Concept index, Prev: Problems, Up: Top
Concept Index
Concept index
*************
[index]
* Menu:
* bugs: Problems. (line 6)
* common options: Common options. (line 6)
* getting help: Problems. (line 6)
* introduction: Introduction. (line 6)
* the zutilsrc file: The zutilsrc file. (line 6)
* zcat: Zcat. (line 6)
* zcmp: Zcmp. (line 6)
* zdiff: Zdiff. (line 6)
@ -588,14 +626,16 @@ Concept Index

Tag Table:
Node: Top224
Node: Introduction1000
Node: Zcat2794
Node: Zcmp4880
Node: Zdiff7366
Node: Zgrep10032
Node: Ztest13043
Node: Problems14447
Node: Concept Index14976
Node: Introduction1097
Node: Common options3155
Node: The zutilsrc file4404
Node: Zcat5330
Node: Zcmp7252
Node: Zdiff9576
Node: Zgrep12079
Node: Ztest14916
Node: Problems16141
Node: Concept index16670

End Tag Table

View file

@ -6,8 +6,8 @@
@finalout
@c %**end of header
@set UPDATED 31 May 2013
@set VERSION 1.0
@set UPDATED 7 July 2013
@set VERSION 1.1-rc2
@dircategory Data Compression
@direntry
@ -36,13 +36,15 @@ This manual is for Zutils (version @value{VERSION}, @value{UPDATED}).
@menu
* Introduction:: Purpose and features of zutils
* Common options:: Common options
* The zutilsrc file:: The zutils configuration file
* Zcat:: Concatenating compressed files
* Zcmp:: Comparing compressed files byte by byte
* Zdiff:: Comparing compressed files line by line
* Zgrep:: Searching inside compressed files
* Ztest:: Testing integrity of compressed files
* Problems:: Reporting bugs
* Concept Index:: Index of concepts
* Concept index:: Index of concepts
@end menu
@sp 1
@ -58,8 +60,8 @@ to copy, distribute and modify it.
@cindex introduction
Zutils is a collection of utilities able to deal with any combination of
compressed and non-compressed files transparently. If any given file,
including standard input, is compressed, its uncompressed content is
compressed and uncompressed files transparently. If any given file,
including standard input, is compressed, its decompressed content is
used. Compressed files are decompressed on the fly; no temporary files
are created.
@ -69,7 +71,8 @@ in those utilities supporting it.
@noindent
The provided utilities are zcat, zcmp, zdiff, zgrep and ztest.@*
The supported formats are bzip2, gzip, lzip and xz.
The supported formats are bzip2, gzip, lzip and xz.@*
The compressor to be used for each format is configurable at runtime.
Zcat, zcmp, zdiff, and zgrep are improved replacements for the shell
scripts provided with GNU gzip. Ztest is unique to zutils.
@ -78,6 +81,10 @@ NOTE: Bzip2 and lzip provide well-defined values of exit status, which
makes them safe to use with zutils. Gzip and xz may return ambiguous
warning values, making them less reliable backends for zutils.
LANGUAGE NOTE: Uncompressed = not compressed = plain data; it may never
have been compressed. Decompressed is used to refer to data which has
undergone the process of decompression.
@sp 1
Numbers given as arguments to options (positions, sizes) may be followed
by a multiplier and an optional @samp{B} for "byte".
@ -97,12 +104,85 @@ Table of SI and binary prefixes (unit multipliers):
@end multitable
@node Common options
@chapter Common options
@cindex common options
The following options are available in all the utilities. Rather than
writing identical descriptions for each of the programs, they are
described here.
@table @samp
@item -h
@itemx --help
Print an informative help message describing the options and exit. Zgrep
only supports the @samp{--help} form of this option.
@item -V
@itemx --version
Print the version number on the standard output and exit.
@item -N
@itemx --no-rcfile
Don't read the runtime configuration file @samp{zutilsrc}.
@item --bz2=@var{command}
@itemx --gz=@var{command}
@itemx --lz=@var{command}
@itemx --xz=@var{command}
Set program (may include arguments) to be used as (de)compressor for the
given format. These options override the values set in @file{zutilsrc}.
The compression program used must meet three requirements:
@enumerate
@item
When called with the @samp{-d} option, it must read compressed data from
the standard input and produce decompressed data on the standard output.
@item
If the @samp{-q} option is passed to zutils, the compression program
must also accept it.
@item
It must return 0 if no errors occurred, and a non-zero value otherwise.
@end enumerate
@end table
@node The zutilsrc file
@chapter The zutilsrc file
@cindex the zutilsrc file
@file{zutilsrc} is the runtime configuration file for zutils. In it you
may define the compressor name and options to be used for each format.
The @file{zutilsrc} file is optional; you do not need to install it in
order to run zutils.
The compressors specified in the command line override those specified
in the @file{zutilsrc} file.
You may copy the system @file{zutilsrc} file
@file{$@{sysconfdir@}/zutilsrc} to @file{$HOME/.zutilsrc} and customize
these options as you like. The file syntax is fairly obvious (and there
are further instructions in it):
@enumerate
@item
Any line beginning with @samp{#} is a comment line.
@item
Each non-comment line defines the command to be used for the given
format, with the syntax:
@example
<format> = <compressor> [options]
@end example
where <format> is one of @samp{bz2}, @samp{gz}, @samp{lz} or @samp{xz}.
@end enumerate
@node Zcat
@chapter Zcat
@cindex zcat
Zcat copies each given file (@samp{-} means standard input), to standard
output. If any given file is compressed, its uncompressed content is
output. If any given file is compressed, its decompressed content is
used. If a given file does not exist, and its name does not end with one
of the known extensions, zcat tries the compressed file names
corresponding to the supported formats.
@ -119,19 +199,11 @@ zcat [@var{options}] [@var{files}]
@end example
@noindent
Exit status is 0 if no errors occurred, 1 otherwise.
Exit status is 0 if no errors occurred, non-zero otherwise.
Zcat supports the following options:
@table @samp
@item -h
@itemx --help
Print an informative help message describing the options and exit.
@item -V
@itemx --version
Print the version number of zcat on the standard output and exit.
@item -A
@itemx --show-all
Equivalent to @samp{-vET}.
@ -195,7 +267,7 @@ Verbose mode. Show error messages.
Zcmp compares two files (@samp{-} means standard input), and if they
differ, tells the first byte and line number where they differ. Bytes
and lines are numbered starting with 1. If any given file is compressed,
its uncompressed content is used. Compressed files are decompressed on
its decompressed content is used. Compressed files are decompressed on
the fly; no temporary files are created.
The format for running zcmp is:
@ -210,15 +282,14 @@ tries the following:
@enumerate
@item
If @var{file1} is compressed, compares @var{file1} to the file with the
corresponding decompressed file name (removes the extension from
@var{file1}).
If @var{file1} is compressed, compares its decompressed contents with
the corresponding uncompressed file (the name of @var{file1} with the
extension removed).
@item
If @var{file1} is not compressed, compares @var{file1} to the
uncompressed contents of @var{file1}.[lz|bz2|gz|xz] (the first one that
is found).
If @var{file1} is uncompressed, compares it with the decompressed
contents of @var{file1}.[lz|bz2|gz|xz] (the first one that is found).
@item
If no suitable file is found, compares @var{file1} to data read from
If no suitable file is found, compares @var{file1} with data read from
standard input.
@end enumerate
@ -229,14 +300,6 @@ differences were found, and 2 means trouble.
Zcmp supports the following options:
@table @samp
@item -h
@itemx --help
Print an informative help message describing the options and exit.
@item -V
@itemx --version
Print the version number of zcmp on the standard output and exit.
@item -b
@itemx --print-bytes
Print the differing bytes. Print control bytes as a @samp{^} followed by
@ -286,7 +349,7 @@ files differ.
Zdiff compares two files (@samp{-} means standard input), and if they
differ, shows the differences line by line. If any given file is
compressed, its uncompressed content is used. Zdiff is a front end to
compressed, its decompressed content is used. Zdiff is a front end to
the diff program and has the limitation that messages from diff refer to
temporary filenames instead of those specified.
@ -302,15 +365,14 @@ zdiff tries the following:
@enumerate
@item
If @var{file1} is compressed, compares @var{file1} to the file with the
corresponding decompressed file name (removes the extension from
@var{file1}).
If @var{file1} is compressed, compares its decompressed contents with
the corresponding uncompressed file (the name of @var{file1} with the
extension removed).
@item
If @var{file1} is not compressed, compares @var{file1} to the
uncompressed contents of @var{file1}.[lz|bz2|gz|xz] (the first one that
is found).
If @var{file1} is uncompressed, compares it with the decompressed
contents of @var{file1}.[lz|bz2|gz|xz] (the first one that is found).
@item
If no suitable file is found, compares @var{file1} to data read from
If no suitable file is found, compares @var{file1} with data read from
standard input.
@end enumerate
@ -321,14 +383,6 @@ differences were found, and 2 means trouble.
Zdiff supports the following options:
@table @samp
@item -h
@itemx --help
Print an informative help message describing the options and exit.
@item -V
@itemx --version
Print the version number of zdiff on the standard output and exit.
@item -a
@itemx --text
Treat all files as text.
@ -407,8 +461,8 @@ Ignore all white space.
@cindex zgrep
Zgrep is a front end to the grep program that allows transparent search
on any combination of compressed and non-compressed files. If any given
file is compressed, its uncompressed content is used. If a given file
on any combination of compressed and uncompressed files. If any given
file is compressed, its decompressed content is used. If a given file
does not exist, and its name does not end with one of the known
extensions, zgrep tries the compressed file names corresponding to the
supported formats.
@ -431,13 +485,6 @@ matches were found, and 2 means trouble.
Zgrep supports the following options:
@table @samp
@item --help
Print an informative help message describing the options and exit.
@item -V
@itemx --version
Print the version number of zgrep on the standard output and exit.
@item -a
@itemx --text
Treat all files as text.
@ -554,9 +601,9 @@ Match only whole lines.
@cindex ztest
Ztest verifies the integrity of the specified compressed files.
Non-compressed files are ignored. If no files are specified, the
integrity of compressed data read from standard input is verified. Data
read from standard input must be all in the same compression format.
Uncompressed files are ignored. If no files are specified, the integrity
of compressed data read from standard input is verified. Data read from
standard input must be all in the same compression format.
Note that some xz files lack integrity information, and therefore can't
be verified as reliably as the other formats can.
@ -575,14 +622,6 @@ environmental problems (file not found, invalid flags, I/O errors, etc),
Ztest supports the following options:
@table @samp
@item -h
@itemx --help
Print an informative help message describing the options and exit.
@item -V
@itemx --version
Print the version number of ztest on the standard output and exit.
@item --format=@var{fmt}
Force the given compression format. Valid values for @var{fmt} are
@samp{bz2}, @samp{gz}, @samp{lz} and @samp{xz}. If this option is used,
@ -619,8 +658,8 @@ If you find a bug in zutils, please send electronic mail to
find by running @w{@samp{zutils --version}}.
@node Concept Index
@unnumbered Concept Index
@node Concept index
@unnumbered Concept index
@printindex cp

50
main.cc
View file

@ -37,6 +37,7 @@
#include "arg_parser.h"
#include "zutils.h"
#include "rc.h"
#if CHAR_BIT != 8
#error "Environments where CHAR_BIT != 8 are not supported."
@ -57,8 +58,8 @@ enum Mode { m_none, m_zcat, m_zgrep, m_ztest };
void show_help()
{
std::printf( "Zutils is a collection of utilities able to deal with any combination of\n"
"compressed and non-compressed files transparently. If any given file,\n"
"including standard input, is compressed, its uncompressed content is used.\n"
"compressed and uncompressed files transparently. If any given file,\n"
"including standard input, is compressed, its decompressed content is used.\n"
"\nThe supported formats are bzip2, gzip, lzip and xz.\n"
"\nUsage: %s <operation> [options] [files]\n", invocation_name );
std::printf( "\nTry '%s <operation> --help' for more specific help.\n", invocation_name );
@ -118,10 +119,11 @@ int open_instream( std::string & input_filename, const Mode program_mode,
int main( const int argc, const char * const argv[] )
{
enum { format_opt = 256, help_opt, verbose_opt,
bz2_opt, gz_opt, lz_opt, xz_opt,
zcat_opt, zgrep_opt, ztest_opt };
const Arg_parser::Option * options = 0;
int infd = -1;
int format_type = -1;
int format_index = -1;
Mode program_mode = m_none;
bool recursive = false;
std::string input_filename;
@ -144,6 +146,7 @@ int main( const int argc, const char * const argv[] )
{ 'l', "list", Arg_parser::no }, // gzip
{ 'L', "license", Arg_parser::no }, // gzip
{ 'n', "number", Arg_parser::no }, // cat
{ 'N', "no-rcfile", Arg_parser::no },
{ 'q', "quiet", Arg_parser::no },
{ 'r', "recursive", Arg_parser::no },
{ 's', "squeeze-blank", Arg_parser::no }, // cat
@ -153,6 +156,10 @@ int main( const int argc, const char * const argv[] )
{ 'V', "version", Arg_parser::no },
{ format_opt, "format", Arg_parser::yes },
{ 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 },
{ zcat_opt, "zcat", Arg_parser::no },
{ 0 , 0, Arg_parser::no } };
@ -176,6 +183,7 @@ int main( const int argc, const char * const argv[] )
{ 'L', "files-without-match", Arg_parser::no }, // grep GNU
{ 'm', "max-count", Arg_parser::yes }, // grep GNU
{ 'n', "line-number", Arg_parser::no }, // grep
{ 'N', "no-rcfile", Arg_parser::no },
{ 'o', "only-matching", Arg_parser::no }, // grep
{ 'q', "quiet", Arg_parser::no },
{ 'r', "recursive", Arg_parser::no },
@ -187,17 +195,26 @@ int main( const int argc, const char * const argv[] )
{ format_opt, "format", Arg_parser::yes },
{ help_opt, "help", 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 },
{ zgrep_opt, "zgrep", Arg_parser::no },
{ 0 , 0, Arg_parser::no } };
const Arg_parser::Option m_ztest_options[] =
{
{ 'h', "help", Arg_parser::no },
{ 'N', "no-rcfile", Arg_parser::no },
{ 'q', "quiet", Arg_parser::no },
{ 'r', "recursive", Arg_parser::no },
{ 'v', "verbose", Arg_parser::no },
{ 'V', "version", Arg_parser::no },
{ format_opt, "format", Arg_parser::yes },
{ bz2_opt, "bz2", Arg_parser::yes },
{ gz_opt, "gz", Arg_parser::yes },
{ lz_opt, "lz", Arg_parser::yes },
{ xz_opt, "xz", Arg_parser::yes },
{ ztest_opt, "ztest", Arg_parser::no },
{ 0 , 0, Arg_parser::no } };
@ -244,10 +261,12 @@ int main( const int argc, const char * const argv[] )
}
} // end parse operation
const int eretval = ( program_mode == m_zgrep ) ? 2 : 1;
const Arg_parser parser( argc, argv, options );
if( parser.error().size() ) // bad option
{ show_error( parser.error().c_str(), 0, true );
return ( program_mode == m_zcat || program_mode == m_ztest ) ? 1 : 2; }
{ show_error( parser.error().c_str(), 0, true ); return eretval; }
maybe_process_config_file( parser );
int argind = 0;
int grep_show_name = -1;
@ -263,9 +282,14 @@ int main( const int argc, const char * const argv[] )
{ grep_args.push_back( arg ); grep_pattern_found = true; continue; }
else break; // no more options
}
if( code == format_opt )
switch( code ) // common options
{
format_type = get_format_type( arg ); continue;
case 'N': continue;
case format_opt: format_index = parse_format_type( arg ); continue;
case bz2_opt: parse_compressor( arg, fmt_bz2, eretval ); continue;
case gz_opt: parse_compressor( arg, fmt_gz, eretval ); continue;
case lz_opt: parse_compressor( arg, fmt_lz, eretval ); continue;
case xz_opt: parse_compressor( arg, fmt_xz, eretval ); continue;
}
switch( program_mode )
{
@ -396,7 +420,7 @@ int main( const int argc, const char * const argv[] )
continue;
}
}
infd = open_instream( input_filename, program_mode, format_type < 0 );
infd = open_instream( input_filename, program_mode, format_index < 0 );
if( infd < 0 ) { if( retval < 1 ) retval = 1; continue; }
}
@ -406,18 +430,18 @@ int main( const int argc, const char * const argv[] )
case m_none:
break;
case m_zcat:
tmp = cat( infd, format_type, input_filename, cat_options );
tmp = cat( infd, format_index, input_filename, cat_options );
break;
case m_zgrep:
if( infd == STDIN_FILENO )
tmp = zgrep_stdin( infd, format_type, grep_args );
else tmp = zgrep_file( infd, format_type, input_filename, grep_args,
tmp = zgrep_stdin( infd, format_index, grep_args );
else tmp = zgrep_file( infd, format_index, input_filename, grep_args,
grep_list_mode, grep_show_name );
break;
case m_ztest:
if( infd == STDIN_FILENO )
tmp = ztest_stdin( infd, format_type, ztest_args );
else tmp = ztest_file( infd, format_type, input_filename, ztest_args );
tmp = ztest_stdin( infd, format_index, ztest_args );
else tmp = ztest_file( infd, format_index, input_filename, ztest_args );
break;
}
if( program_mode == m_zgrep )

229
rc.cc Normal file
View file

@ -0,0 +1,229 @@
/* Zutils - Utilities dealing with compressed files
Copyright (C) 2009, 2010, 2011, 2012, 2013 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 3 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/>.
*/
#define _FILE_OFFSET_BITS 64
#include <cstdio>
#include <cstdlib>
#include <string>
#include <vector>
#include <stdint.h>
#include "arg_parser.h"
#include "zutils.h"
#include "rc.h"
namespace {
std::string compressor_names[num_formats] =
{ "bzip2", "gzip", "lzip", "xz" }; // default compressor names
// args to compressors, maybe empty
std::vector< std::string > compressor_args[num_formats];
int my_fgetc( FILE * const f )
{
int ch;
bool comment = false;
do {
ch = std::fgetc( f );
if( ch == '#' ) comment = true;
else if( ch == '\n' || ch == EOF ) comment = false;
else if( ch == '\\' && comment )
{
const int c = std::fgetc( f );
if( c == '\n' ) { std::ungetc( c, f ); comment = false; }
}
}
while( comment );
return ch;
}
// Returns the parity of escapes (backslashes) at the end of a string.
bool trailing_escape( const std::string & s )
{
unsigned len = s.size();
bool odd_escape = false;
while( len > 0 && s[--len] == '\\' ) odd_escape = !odd_escape;
return odd_escape;
}
// Read a line discarding comments, leading whitespace and blank lines.
// Escaped newlines are discarded.
// Returns the empty string if at EOF.
//
const std::string & my_fgets( FILE * const f, int & linenum )
{
static std::string s;
bool strip = true; // strip leading whitespace
s.clear();
while( true )
{
int ch = my_fgetc( f );
if( strip )
{
strip = false;
while( std::isspace( ch ) )
{ if( ch == '\n' ) { ++linenum; } ch = my_fgetc( f ); }
}
if( ch == EOF ) { if( s.size() > 0 ) { ++linenum; } break; }
else if( ch == '\n' )
{
++linenum; strip = true;
if( trailing_escape( s ) ) s.erase( s.size() - 1 );
else if( s.size() > 0 ) break;
}
else s += ch;
}
return s;
}
bool parse_rc_line( const std::string & line,
const char * const filename, const int linenum )
{
const int len = line.size();
int i = 0;
while( i < len && std::isspace( line[i] ) ) ++i; // strip spaces
int l = i;
while( i < len && line[i] != '=' && !std::isspace( line[i] ) ) ++i;
if( l >= i )
{ if( verbosity >= 0 )
std::fprintf( stderr, "%s %d: missing format name.\n", filename, linenum );
return false; }
const std::string name( line, l, i - l );
int format_index = -1;
for( int i = 0; i < num_formats; ++i )
if( name == format_names[i] ) { format_index = i; break; }
if( format_index < 0 )
{ if( verbosity >= 0 )
std::fprintf( stderr, "%s %d: bad format name '%s'\n",
filename, linenum, name.c_str() );
return false; }
while( i < len && std::isspace( line[i] ) ) ++i; // strip spaces
if( i <= 0 || i >= len || line[i] != '=' )
{ if( verbosity >= 0 )
std::fprintf( stderr, "%s %d: missing '='.\n", filename, linenum );
return false; }
++i; // skip the '='
while( i < len && std::isspace( line[i] ) ) ++i; // strip spaces
l = i;
while( i < len && !std::isspace( line[i] ) ) ++i;
if( l >= i )
{ if( verbosity >= 0 )
std::fprintf( stderr, "%s %d: missing compressor name.\n", filename, linenum );
return false; }
compressor_names[format_index].assign( line, l, i - l );
compressor_args[format_index].clear();
while( i < len )
{
while( i < len && std::isspace( line[i] ) ) ++i; // strip spaces
l = i;
while( i < len && !std::isspace( line[i] ) ) ++i;
if( l < i )
compressor_args[format_index].push_back( std::string( line, l, i - l ) );
}
return true;
}
// Returns 0 for success, 1 for file not found, 2 for syntax error.
int process_rcfile( const std::string & name )
{
FILE * const f = std::fopen( name.c_str(), "r" );
if( !f ) return 1;
int linenum = 0;
int retval = 0;
while( true )
{
const std::string & line = my_fgets( f, linenum );
if( line.size() == 0 ) break; // EOF
if( !parse_rc_line( line, name.c_str(), linenum ) )
{ retval = 2; break; }
}
std::fclose( f );
return retval;
}
} // end namespace
void maybe_process_config_file( const Arg_parser & parser )
{
for( int i = 0; i < parser.arguments(); ++i )
if( parser.code( i ) == 'N' ) return;
std::string name;
const char * p = std::getenv( "HOME" ); if( p ) name = p;
if( name.size() )
{
name += "/."; name += config_file_name;
const int retval = process_rcfile( name );
if( retval == 0 ) return;
if( retval == 2 ) std::exit( 2 );
}
name = SYSCONFDIR; name += '/'; name += config_file_name;
const int retval = process_rcfile( name );
if( retval == 2 ) std::exit( 2 );
}
void parse_compressor( const std::string & arg, const int format_index,
const int eretval )
{
const int len = arg.size();
int i = 0;
while( i < len && std::isspace( arg[i] ) ) ++i; // strip spaces
int l = i;
while( i < len && !std::isspace( arg[i] ) ) ++i;
if( l >= i )
{ show_error( "Missing compressor name." ); std::exit( eretval ); }
compressor_names[format_index].assign( arg, l, i - l );
compressor_args[format_index].clear();
while( i < len )
{
while( i < len && std::isspace( arg[i] ) ) ++i; // strip spaces
l = i;
while( i < len && !std::isspace( arg[i] ) ) ++i;
if( l < i )
compressor_args[format_index].push_back( std::string( arg, l, i - l ) );
}
}
const char * get_compressor_name( const int format_index )
{
if( format_index >= 0 && format_index < num_formats )
return compressor_names[format_index].c_str();
return 0;
}
const std::vector< std::string > & get_compressor_args( const int format_index )
{
return compressor_args[format_index];
}

27
rc.h Normal file
View file

@ -0,0 +1,27 @@
/* Zutils - Utilities dealing with compressed files
Copyright (C) 2009, 2010, 2011, 2012, 2013 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 3 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/>.
*/
class Arg_parser;
void maybe_process_config_file( const Arg_parser & parser );
void parse_compressor( const std::string & arg, const int format_index,
const int eretval = 2 );
const char * get_compressor_name( const int format_index );
const std::vector< std::string > & get_compressor_args( const int format_index );

View file

@ -50,280 +50,293 @@ printf "testing zutils-%s..." "$2"
printf "\ntesting zcat-%s..." "$2"
for i in ${extensions}; do
"${ZCAT}" in.$i > copy || fail=1
"${ZCAT}" -N in.$i > copy || fail=1
cmp in copy || fail=1
printf .
"${ZCAT}" --format=$i in.$i > copy || fail=1
"${ZCAT}" -N --format=$i in.$i > copy || fail=1
cmp in copy || fail=1
printf .
"${ZCAT}" in.$i | dd bs=1000 count=1 > copy 2> /dev/null || fail=1
"${ZCAT}" -N in.$i | dd bs=1000 count=1 > copy 2> /dev/null || fail=1
dd if=in bs=1000 count=1 2> /dev/null | cmp - copy || fail=1
printf .
done
"${ZCAT}" < in > copy || fail=1
"${ZCAT}" -N < in > copy || fail=1
cmp in copy || fail=1
printf .
"${ZCAT}" < in.gz > copy || fail=1
"${ZCAT}" -N < in.gz > copy || fail=1
cmp in copy || fail=1
printf .
"${ZCAT}" < in.bz2 > copy || fail=1
"${ZCAT}" -N < in.bz2 > copy || fail=1
cmp in copy || fail=1
printf .
"${ZCAT}" < in.lz > copy || fail=1
"${ZCAT}" -N < in.lz > copy || fail=1
cmp in copy || fail=1
printf .
"${ZCAT}" in > copy || fail=1
"${ZCAT}" -N --lz='lzip -q' < in.lz > copy || fail=1
cmp in copy || fail=1
printf .
"${ZCAT}" lz_only > copy || fail=1
"${ZCAT}" -N in > copy || fail=1
cmp in copy || fail=1
printf .
"${ZCAT}" in in.gz in.bz2 in.lz -- -in- -in-.lz > copy6 || fail=1
"${ZCAT}" -N lz_only > copy || fail=1
cmp in copy || fail=1
printf .
"${ZCAT}" -N in in.gz in.bz2 in.lz -- -in- -in-.lz > copy6 || fail=1
cmp in6 copy6 || fail=1
printf .
"${ZCAT}" --format=gz in.bz2 2> /dev/null
"${ZCAT}" -N --format=gz in.bz2 2> /dev/null
if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZCAT}" --format=bz2 in.lz 2> /dev/null
"${ZCAT}" -N --format=bz2 in.lz 2> /dev/null
if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZCAT}" --format=lz in.gz 2> /dev/null
"${ZCAT}" -N --format=lz in.gz 2> /dev/null
if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZCAT}" --bad-option 2> /dev/null
"${ZCAT}" -N --bad-option 2> /dev/null
if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
printf "\ntesting zcmp-%s..." "$2"
for i in ${extensions}; do
"${ZCMP}" in.$i || fail=1
"${ZCMP}" -N in.$i || fail=1
printf .
"${ZCMP}" in in.$i || fail=1
"${ZCMP}" -N in in.$i || fail=1
printf .
"${ZCMP}" -i 100 -n 500 in6 in.$i || fail=1
"${ZCMP}" -N -i 100 -n 500 in6 in.$i || fail=1
printf .
"${ZCMP}" in in.$i --format=,$i || fail=1
"${ZCMP}" -N in in.$i --format=,$i || fail=1
printf .
"${ZCMP}" in.$i in || fail=1
"${ZCMP}" -N in.$i in || fail=1
printf .
"${ZCMP}" -i 1000:1000 -n 50 in.$i in6 || fail=1
"${ZCMP}" -N -i 1000:1000 -n 50 in.$i in6 || fail=1
printf .
"${ZCMP}" in.$i in --format=$i || fail=1
"${ZCMP}" -N in.$i in --format=$i || fail=1
printf .
done
"${ZCMP}" in in6 2> /dev/null
"${ZCMP}" -N in in6 2> /dev/null
if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZCMP}" -n 0 in in6 || fail=1
"${ZCMP}" -n 100 in in6 || fail=1
"${ZCMP}" -n 1000 in in6 || fail=1
"${ZCMP}" -n 10000 in in6 || fail=1
"${ZCMP}" -N -n 0 in in6 || fail=1
"${ZCMP}" -N -n 100 in in6 || fail=1
"${ZCMP}" -N -n 1000 in in6 || fail=1
"${ZCMP}" -N -n 10000 in in6 || fail=1
printf .
"${ZCMP}" in.tar pin.tar > /dev/null
"${ZCMP}" -N in.tar pin.tar > /dev/null
if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZCMP}" -i 0,11 in.tar pin.tar 2> /dev/null
"${ZCMP}" -N -i 0,11 in.tar pin.tar 2> /dev/null
if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZCMP}" -i 0,11 -n 0 in.tar pin.tar || fail=1
"${ZCMP}" -i 0,11 -n 100 in.tar pin.tar || fail=1
"${ZCMP}" -i 0,11 -n 1000 in.tar pin.tar || fail=1
"${ZCMP}" -i 0,11 -n 10000 in.tar pin.tar || fail=1
"${ZCMP}" -N -i 0,11 -n 0 in.tar pin.tar || fail=1
"${ZCMP}" -N -i 0,11 -n 100 in.tar pin.tar || fail=1
"${ZCMP}" -N -i 0,11 -n 1000 in.tar pin.tar || fail=1
"${ZCMP}" -N -i 0,11 -n 10000 in.tar pin.tar || fail=1
printf .
"${ZCMP}" - || fail=1
"${ZCMP}" -N - || fail=1
printf .
"${ZCMP}" in in || fail=1
"${ZCMP}" -N in in || fail=1
printf .
"${ZCMP}" in || fail=1
"${ZCMP}" -N in || fail=1
printf .
"${ZCMP}" in.lz in.gz || fail=1
"${ZCMP}" -N in.lz in.gz || fail=1
printf .
"${ZCMP}" in.gz -- -in-.lz || fail=1
"${ZCMP}" -N --lz='lzip -q' in.lz in.gz || fail=1
printf .
"${ZCMP}" -- -in-.lz in.gz || fail=1
"${ZCMP}" -N in.gz -- -in-.lz || fail=1
printf .
"${ZCMP}" in -- -in-.lz || fail=1
"${ZCMP}" -N -- -in-.lz in.gz || fail=1
printf .
"${ZCMP}" -- -in- in.lz || fail=1
"${ZCMP}" -N in -- -in-.lz || fail=1
printf .
"${ZCMP}" in.lz -- -in- || fail=1
"${ZCMP}" -N -- -in- in.lz || fail=1
printf .
"${ZCMP}" -- -in-.lz in || fail=1
"${ZCMP}" -N in.lz -- -in- || fail=1
printf .
"${ZCMP}" -- -in- in || fail=1
"${ZCMP}" -N -- -in-.lz in || fail=1
printf .
"${ZCMP}" in -- -in- || fail=1
"${ZCMP}" -N -- -in- in || fail=1
printf .
"${ZCMP}" lz_only.lz < in || fail=1
"${ZCMP}" -N in -- -in- || fail=1
printf .
"${ZCMP}" in.lz - < in || fail=1
"${ZCMP}" -N lz_only.lz < in || fail=1
printf .
"${ZCMP}" - in.lz < in || fail=1
"${ZCMP}" -N in.lz - < in || fail=1
printf .
"${ZCMP}" in - < in.lz || fail=1
"${ZCMP}" -N - in.lz < in || fail=1
printf .
"${ZCMP}" - in < in.lz || fail=1
"${ZCMP}" -N in - < in.lz || fail=1
printf .
"${ZCMP}" -q --format=lz in.lz
"${ZCMP}" -N - in < in.lz || fail=1
printf .
"${ZCMP}" -N -q --format=lz in.lz
if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZCMP}" --format=lz in.gz in.lz 2> /dev/null
"${ZCMP}" -N --format=lz in.gz in.lz 2> /dev/null
if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZCMP}" -n -1 in in 2> /dev/null
"${ZCMP}" -N -n -1 in in 2> /dev/null
if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZCMP}" --bad-option in in 2> /dev/null
"${ZCMP}" -N --bad-option in in 2> /dev/null
if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
printf "\ntesting zdiff-%s..." "$2"
for i in ${extensions}; do
"${ZDIFF}" in.$i || fail=1
"${ZDIFF}" -N in.$i > /dev/null || fail=1
printf .
"${ZDIFF}" in in.$i || fail=1
"${ZDIFF}" -N in in.$i > /dev/null || fail=1
printf .
"${ZDIFF}" --format=,$i in in.$i || fail=1
"${ZDIFF}" -N --format=,$i in in.$i > /dev/null || fail=1
printf .
"${ZDIFF}" in.$i in || fail=1
"${ZDIFF}" -N in.$i in > /dev/null || fail=1
printf .
"${ZDIFF}" --format=$i, in.$i in || fail=1
"${ZDIFF}" -N --format=$i, in.$i in > /dev/null || fail=1
printf .
done
"${ZDIFF}" in in6 > /dev/null
"${ZDIFF}" -N in in6 > /dev/null
if [ $? != 0 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZDIFF}" in.tar pin.tar > /dev/null
"${ZDIFF}" -N in.tar pin.tar > /dev/null
if [ $? != 0 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZDIFF}" - || fail=1
"${ZDIFF}" -N - || fail=1
printf .
"${ZDIFF}" in in || fail=1
"${ZDIFF}" -N in in || fail=1
printf .
"${ZDIFF}" in || fail=1
"${ZDIFF}" -N in > /dev/null || fail=1
printf .
"${ZDIFF}" in.lz in.gz || fail=1
"${ZDIFF}" -N in.lz in.gz > /dev/null || fail=1
printf .
"${ZDIFF}" in.gz -- -in-.lz || fail=1
"${ZDIFF}" -N --lz='lzip -q' in.lz in.gz > /dev/null || fail=1
printf .
"${ZDIFF}" -- -in-.lz in.gz || fail=1
"${ZDIFF}" -N in.gz -- -in-.lz > /dev/null || fail=1
printf .
"${ZDIFF}" in -- -in-.lz || fail=1
"${ZDIFF}" -N -- -in-.lz in.gz > /dev/null || fail=1
printf .
"${ZDIFF}" -- -in- in.lz || fail=1
"${ZDIFF}" -N in -- -in-.lz > /dev/null || fail=1
printf .
"${ZDIFF}" in.lz -- -in- || fail=1
"${ZDIFF}" -N -- -in- in.lz > /dev/null || fail=1
printf .
"${ZDIFF}" -- -in-.lz in || fail=1
"${ZDIFF}" -N in.lz -- -in- > /dev/null || fail=1
printf .
"${ZDIFF}" -- -in- in || fail=1
"${ZDIFF}" -N -- -in-.lz in > /dev/null || fail=1
printf .
"${ZDIFF}" in -- -in- || fail=1
"${ZDIFF}" -N -- -in- in > /dev/null || fail=1
printf .
"${ZDIFF}" lz_only.lz < in || fail=1
"${ZDIFF}" -N in -- -in- > /dev/null || fail=1
printf .
"${ZDIFF}" in.lz - < in || fail=1
"${ZDIFF}" -N lz_only.lz < in > /dev/null || fail=1
printf .
"${ZDIFF}" - in.lz < in || fail=1
"${ZDIFF}" -N in.lz - < in > /dev/null || fail=1
printf .
"${ZDIFF}" in - < in.lz || fail=1
"${ZDIFF}" -N - in.lz < in > /dev/null || fail=1
printf .
"${ZDIFF}" - in < in.lz || fail=1
"${ZDIFF}" -N in - < in.lz > /dev/null || fail=1
printf .
"${ZDIFF}" -q --format=bz2 in.bz2 2> /dev/null
"${ZDIFF}" -N - in < in.lz > /dev/null || fail=1
printf .
"${ZDIFF}" -N -q --format=bz2 in.bz2 2> /dev/null
if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZDIFF}" -q --format=,lz in.lz in.bz2 > /dev/null 2> /dev/null
"${ZDIFF}" -N -q --format=,lz in.lz in.bz2 > /dev/null 2> /dev/null
if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZDIFF}" --bad-option 2> /dev/null
"${ZDIFF}" -N --bad-option 2> /dev/null
if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
printf "\ntesting zgrep-%s..." "$2"
for i in ${extensions}; do
"${ZGREP}" "GNU" in.$i > /dev/null || fail=1
"${ZGREP}" -N "GNU" in.$i > /dev/null || fail=1
printf .
"${ZGREP}" -l "GNU" in.$i > /dev/null || fail=1
"${ZGREP}" -N -l "GNU" in.$i > /dev/null || fail=1
printf .
"${ZGREP}" -L "GNU" in.$i || fail=1
"${ZGREP}" -N -L "GNU" in.$i || fail=1
printf .
"${ZGREP}" --format=$i "GNU" in.$i > /dev/null || fail=1
"${ZGREP}" -N --format=$i "GNU" in.$i > /dev/null || fail=1
printf .
"${ZGREP}" -v "nx_pattern" in.$i > /dev/null || fail=1
"${ZGREP}" -N -v "nx_pattern" in.$i > /dev/null || fail=1
printf .
"${ZGREP}" "nx_pattern" in.$i
"${ZGREP}" -N "nx_pattern" in.$i
if [ $? != 0 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZGREP}" -l "nx_pattern" in.$i
"${ZGREP}" -N -l "nx_pattern" in.$i
if [ $? != 0 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZGREP}" -L "nx_pattern" in.$i > /dev/null
"${ZGREP}" -N -L "nx_pattern" in.$i > /dev/null
if [ $? != 0 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZGREP}" --format=$i "GNU" in 2> /dev/null
"${ZGREP}" -N --format=$i "GNU" in 2> /dev/null
if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
done
"${ZGREP}" "GNU" < pin.tar > /dev/null || fail=1
"${ZGREP}" -N "GNU" < pin.tar > /dev/null || fail=1
printf .
"${ZGREP}" "GNU" pin.tar > /dev/null || fail=1
"${ZGREP}" -N "GNU" pin.tar > /dev/null || fail=1
printf .
"${ZGREP}" -r "GNU" . > /dev/null || fail=1
"${ZGREP}" -N -r "GNU" . > /dev/null || fail=1
printf .
"${ZGREP}" "nx_pattern" -r . in > /dev/null
"${ZGREP}" -N "nx_pattern" -r . in > /dev/null
if [ $? != 0 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZGREP}" "GNU" < in > /dev/null || fail=1
"${ZGREP}" -N "GNU" < in > /dev/null || fail=1
printf .
"${ZGREP}" "GNU" < in.gz > /dev/null || fail=1
"${ZGREP}" -N "GNU" < in.gz > /dev/null || fail=1
printf .
"${ZGREP}" "GNU" < in.bz2 > /dev/null || fail=1
"${ZGREP}" -N "GNU" < in.bz2 > /dev/null || fail=1
printf .
"${ZGREP}" "GNU" < in.lz > /dev/null || fail=1
"${ZGREP}" -N "GNU" < in.lz > /dev/null || fail=1
printf .
"${ZGREP}" "GNU" in > /dev/null || fail=1
"${ZGREP}" -N "GNU" --lz='lzip -q' < in.lz > /dev/null || fail=1
printf .
"${ZGREP}" "GNU" -- -in- > /dev/null || fail=1
"${ZGREP}" -N "GNU" in > /dev/null || fail=1
printf .
"${ZGREP}" "GNU" -- -in-.lz > /dev/null || fail=1
"${ZGREP}" -N "GNU" -- -in- > /dev/null || fail=1
printf .
"${ZGREP}" "GNU" in in.gz in.bz2 in.lz -- -in- > /dev/null || fail=1
"${ZGREP}" -N "GNU" -- -in-.lz > /dev/null || fail=1
printf .
"${ZGREP}" -l "GNU" in in.gz in.bz2 in.lz -- -in- > /dev/null || fail=1
"${ZGREP}" -N "GNU" in in.gz in.bz2 in.lz -- -in- > /dev/null || fail=1
printf .
"${ZGREP}" -L "GNU" in in.gz in.bz2 in.lz -- -in- || fail=1
"${ZGREP}" -N -l "GNU" in in.gz in.bz2 in.lz -- -in- > /dev/null || fail=1
printf .
"${ZGREP}" -l "nx_pattern" in in.gz in.bz2 in.lz -- -in-
"${ZGREP}" -N -L "GNU" in in.gz in.bz2 in.lz -- -in- || fail=1
printf .
"${ZGREP}" -N -l "nx_pattern" in in.gz in.bz2 in.lz -- -in-
if [ $? != 0 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZGREP}" -L "nx_pattern" in in.gz in.bz2 in.lz -- -in- > /dev/null
"${ZGREP}" -N -L "nx_pattern" in in.gz in.bz2 in.lz -- -in- > /dev/null
if [ $? != 0 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZGREP}" --bad-option 2> /dev/null
"${ZGREP}" -N --bad-option 2> /dev/null
if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZEGREP}" "GNU" in > /dev/null || fail=1
"${ZEGREP}" -N "GNU" in > /dev/null || fail=1
printf .
"${ZFGREP}" "GNU" in > /dev/null || fail=1
"${ZFGREP}" -N "GNU" in > /dev/null || fail=1
printf .
printf "\ntesting ztest-%s..." "$2"
for i in ${extensions}; do
"${ZTEST}" --format=$i < in.$i || fail=1
"${ZTEST}" -N --format=$i < in.$i || fail=1
printf .
"${ZTEST}" --format=$i < in 2> /dev/null
"${ZTEST}" -N --format=$i < in 2> /dev/null
if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZTEST}" --format=$i in 2> /dev/null
"${ZTEST}" -N --format=$i in 2> /dev/null
if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
done
"${ZTEST}" in in.gz in.bz2 in.lz -- -in- || fail=1
"${ZTEST}" -N in in.gz in.bz2 in.lz -- -in- || fail=1
printf .
"${ZTEST}" < in.gz || fail=1
"${ZTEST}" -N < in.gz || fail=1
printf .
"${ZTEST}" < in.bz2 || fail=1
"${ZTEST}" -N < in.bz2 || fail=1
printf .
"${ZTEST}" < in.lz || fail=1
"${ZTEST}" -N < in.lz || fail=1
printf .
"${ZTEST}" -r . || fail=1
"${ZTEST}" -N --lz='lzip -q' < in.lz || fail=1
printf .
"${ZTEST}" < in 2> /dev/null
"${ZTEST}" -N -r . || fail=1
printf .
"${ZTEST}" -N < in 2> /dev/null
if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
dd if=in.lz bs=1000 count=1 2> /dev/null | "${ZTEST}" -q
dd if=in.lz bs=1000 count=1 2> /dev/null | "${ZTEST}" -N -q
if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZTEST}" --format=lz in.bz2 2> /dev/null
"${ZTEST}" -N --format=lz in.bz2 2> /dev/null
if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZTEST}" --bad-option 2> /dev/null
"${ZTEST}" -N --lz='lzip --bad-option' in.lz 2> /dev/null
if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZTEST}" -N --bad-option 2> /dev/null
if [ $? = 1 ] ; then printf . ; else printf - ; fail=1 ; fi
echo

29
zcat.cc
View file

@ -61,7 +61,7 @@ Line_number line_number;
void show_zcat_help()
{
std::printf( "Zcat copies each given file (\"-\" means standard input), to standard\n"
"output. If any given file is compressed, its uncompressed content is\n"
"output. If any given file is compressed, its decompressed content is\n"
"used. If a given file does not exist, and its name does not end with one\n"
"of the known extensions, zcat tries the compressed file names\n"
"corresponding to the supported formats. If no files are specified,\n"
@ -70,7 +70,7 @@ void show_zcat_help()
"all uncompressed or all in the same compression format.\n"
"\nThe supported formats are bzip2, gzip, lzip and xz.\n"
"\nUsage: zcat [options] [files]\n"
"\nExit status is 0 if no errors occurred, 1 otherwise.\n"
"\nExit status is 0 if no errors occurred, non-zero otherwise.\n"
"\nOptions:\n"
" -h, --help display this help and exit\n"
" -V, --version output version information and exit\n"
@ -80,13 +80,18 @@ void show_zcat_help()
" -E, --show-ends display '$' at end of each line\n"
" --format=<fmt> force given format (bz2, gz, lz, xz)\n"
" -n, --number number all output lines\n"
" -N, --no-rcfile don't read runtime configuration file\n"
" -q, --quiet suppress all messages\n"
" -r, --recursive operate recursively on directories\n"
" -s, --squeeze-blank never more than one single blank line\n"
" -t equivalent to '-vT'\n"
" -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" );
" --verbose verbose mode (show error messages)\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"
" --xz=<command> set compressor and options for xz format\n" );
show_help_addr();
}
@ -187,7 +192,7 @@ int do_cat( const int infd, const int buffer_size,
}
int cat( int infd, const int format_type, const std::string & input_filename,
int cat( int infd, const int format_index, const std::string & input_filename,
const Cat_options & cat_options )
{
enum { buffer_size = 4096 };
@ -195,17 +200,17 @@ int cat( int infd, const int format_type, const std::string & input_filename,
uint8_t * const inbuf = new uint8_t[buffer_size+1];
// buffer with space for character quoting and 255-digit line number
uint8_t * const outbuf = new uint8_t[(4*buffer_size)+256];
pid_t pid = 0;
int retval = 0;
if( !set_data_feeder( &infd, &pid, format_type ) ) retval = 1;
Children children;
if( !set_data_feeder( &infd, children, format_index ) ) retval = 1;
else
retval = do_cat( infd, buffer_size, inbuf, outbuf,
input_filename, cat_options );
if( retval == 0 )
if( pid && wait_for_child( pid, "data feeder" ) != 0 ) retval = 1;
if( retval == 0 )
if( close( infd ) != 0 )
{ show_close_error( "data feeder" ); retval = 1; }
delete[] inbuf; delete[] outbuf;
if( !good_status( children, retval == 0 ) ) retval = 1;
if( retval == 0 && close( infd ) != 0 )
{ show_close_error( "data feeder" ); retval = 1; }
delete[] outbuf; delete[] inbuf;
return retval;
}

60
zcmp.cc
View file

@ -37,6 +37,7 @@
#include "arg_parser.h"
#include "zutils.h"
#include "rc.h"
#if CHAR_BIT != 8
#error "Environments where CHAR_BIT != 8 are not supported."
@ -57,19 +58,19 @@ void show_help()
std::printf( "Zcmp compares two files (\"-\" means standard input), and if they\n"
"differ, tells the first byte and line number where they differ. Bytes\n"
"and lines are numbered starting with 1. If any given file is compressed,\n"
"its uncompressed content is used. Compressed files are uncompressed on\n"
"its decompressed content is used. Compressed files are decompressed on\n"
"the fly; no temporary files are created.\n"
"\nThe supported formats are bzip2, gzip, lzip and xz.\n"
"\nUsage: zcmp [options] file1 [file2]\n"
"\nCompares <file1> to <file2>. If <file2> is omitted zcmp tries the\n"
"following:\n"
"If <file1> is compressed, compares <file1> to the file with the\n"
"corresponding decompressed file name (removes the extension from\n"
"<file1>).\n"
"If <file1> is not compressed, compares <file1> to the uncompressed\n"
"contents of <file1>.[lz|bz2|gz|xz] (the first one that is found).\n"
"If no suitable file is found, compares <file1> to data read from\n"
"standard input.\n"
"\n 1. If <file1> is compressed, compares its decompressed contents with\n"
" the corresponding uncompressed file (the name of <file1> with the\n"
" extension removed).\n"
"\n 2. If <file1> is uncompressed, compares it with the decompressed\n"
" contents of <file1>.[lz|bz2|gz|xz] (the first one that is found).\n"
"\n 3. If no suitable file is found, compares <file1> with data read from\n"
" standard input.\n"
"\nExit status is 0 if inputs are identical, 1 if different, 2 if trouble.\n"
"\nOptions:\n"
" -h, --help display this help and exit\n"
@ -79,9 +80,14 @@ void show_help()
" -i, --ignore-initial=<n>[,<n2>] ignore differences in the first <n> bytes\n"
" -l, --list list position, value of all differing bytes\n"
" -n, --bytes=<n> compare at most <n> bytes\n"
" -N, --no-rcfile don't read runtime configuration file\n"
" -q, --quiet suppress all messages\n"
" -s, --silent (same as --quiet)\n"
" -v, --verbose verbose mode (same as --list)\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"
" --xz=<command> set compressor and options for xz format\n"
"Numbers may be followed by a multiplier: k = kB = 10^3 = 1000,\n"
"Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...\n" );
show_help_addr();
@ -310,7 +316,7 @@ int cmp( const long long max_size, const int infd[2],
int main( const int argc, const char * const argv[] )
{
enum { format_opt = 256 };
enum { format_opt = 256, bz2_opt, gz_opt, lz_opt, xz_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
@ -326,17 +332,24 @@ int main( const int argc, const char * const argv[] )
{ 'i', "ignore-initial", Arg_parser::yes },
{ 'l', "list", Arg_parser::no },
{ 'n', "bytes", Arg_parser::yes },
{ 'N', "no-rcfile", Arg_parser::no },
{ 'q', "quiet", Arg_parser::no },
{ 's', "silent", Arg_parser::no },
{ 'v', "verbose", Arg_parser::no },
{ 'V', "version", Arg_parser::no },
{ format_opt, "format", Arg_parser::yes },
{ bz2_opt, "bz2", Arg_parser::yes },
{ gz_opt, "gz", Arg_parser::yes },
{ lz_opt, "lz", Arg_parser::yes },
{ xz_opt, "xz", Arg_parser::yes },
{ 0 , 0, Arg_parser::no } };
const Arg_parser parser( argc, argv, options );
if( parser.error().size() ) // bad option
{ show_error( parser.error().c_str(), 0, true ); return 2; }
maybe_process_config_file( parser );
int argind = 0;
for( ; argind < parser.arguments(); ++argind )
{
@ -350,11 +363,16 @@ int main( const int argc, const char * const argv[] )
case 'i': parse_ignore_initial( arg, ignore_initial ); break;
case 'l': verbosity = 1; break;
case 'n': max_size = getnum( arg ); break;
case 'N': break;
case 'q':
case 's': verbosity = -1; break;
case 'v': verbosity = 1; break;
case 'V': show_version( "Zcmp" ); return 0;
case format_opt: get_format_types( arg, format_types ); break;
case format_opt: parse_format_types( arg, format_types ); break;
case bz2_opt: parse_compressor( arg, fmt_bz2 ); break;
case gz_opt: parse_compressor( arg, fmt_gz ); break;
case lz_opt: parse_compressor( arg, fmt_lz ); break;
case xz_opt: parse_compressor( arg, fmt_xz ); break;
default : internal_error( "uncaught option" );
}
} // end process options
@ -405,9 +423,9 @@ int main( const int argc, const char * const argv[] )
int old_infd[2]; // copy of file descriptors of the two files
old_infd[0] = infd[0]; old_infd[1] = infd[1];
pid_t pid[2];
if( !set_data_feeder( &infd[0], &pid[0], format_types[0] ) ||
!set_data_feeder( &infd[1], &pid[1], format_types[1] ) )
Children children[2];
if( !set_data_feeder( &infd[0], children[0], format_types[0] ) ||
!set_data_feeder( &infd[1], children[1], format_types[1] ) )
return 2;
for( int i = 0; i < 2; ++i )
@ -419,20 +437,8 @@ int main( const int argc, const char * const argv[] )
int retval = cmp( max_size, infd, filenames, print_bytes );
if( retval != 0 || max_size >= 0 )
{
for( int i = 0; i < 2; ++i )
if( pid[i] )
{
const int tmp = child_status( pid[i], "data feeder" );
if( tmp < 0 ) kill( pid[i], SIGTERM ); // child not terminated
else if( tmp != 0 ) retval = 2; // child status != 0
}
}
else
if( ( pid[0] && wait_for_child( pid[0], "data feeder" ) != 0 ) ||
( pid[1] && wait_for_child( pid[1], "data feeder" ) != 0 ) )
retval = 2;
for( int i = 0; i < 2; ++i )
if( !good_status( children[i], retval == 0 && max_size < 0 ) ) retval = 2;
for( int i = 0; i < 2; ++i )
{

View file

@ -66,13 +66,13 @@ int open_other_instream( std::string & name )
}
void get_format_types( const std::string & arg, int format_types[2] )
void parse_format_types( const std::string & arg, int format_types[2] )
{
const unsigned i = std::min( arg.find( ',' ), arg.size() );
if( i > 0 ) format_types[0] = get_format_type( arg.substr( 0, i ) );
if( i > 0 ) format_types[0] = parse_format_type( arg.substr( 0, i ) );
else format_types[0] = -1;
if( i + 1 < arg.size() ) format_types[1] =
get_format_type( arg.substr( i + 1 ) );
parse_format_type( arg.substr( i + 1 ) );
else format_types[1] = -1;
}

152
zdiff.cc
View file

@ -37,6 +37,7 @@
#include "arg_parser.h"
#include "zutils.h"
#include "rc.h"
#if CHAR_BIT != 8
#error "Environments where CHAR_BIT != 8 are not supported."
@ -54,20 +55,20 @@ void show_help()
{
std::printf( "Zdiff compares two files (\"-\" means standard input), and if they\n"
"differ, shows the differences line by line. If any given file is\n"
"compressed, its uncompressed content is used. Zdiff is a front end to\n"
"compressed, its decompressed content is used. Zdiff is a front end to\n"
"the diff program and has the limitation that messages from diff refer to\n"
"temporary filenames instead of those specified.\n"
"\nThe supported formats are bzip2, gzip, lzip and xz.\n"
"\nUsage: zdiff [options] file1 [file2]\n"
"\nCompares <file1> to <file2>. If <file2> is omitted zdiff tries the\n"
"following:\n"
"If <file1> is compressed, compares <file1> to the file with the\n"
"corresponding decompressed file name (removes the extension from\n"
"<file1>).\n"
"If <file1> is not compressed, compares <file1> to the uncompressed\n"
"contents of <file1>.[lz|bz2|gz|xz] (the first one that is found).\n"
"If no suitable file is found, compares <file1> to data read from\n"
"standard input.\n"
"\n 1. If <file1> is compressed, compares its decompressed contents with\n"
" the corresponding uncompressed file (the name of <file1> with the\n"
" extension removed).\n"
"\n 2. If <file1> is uncompressed, compares it with the decompressed\n"
" contents of <file1>.[lz|bz2|gz|xz] (the first one that is found).\n"
"\n 3. If no suitable file is found, compares <file1> with data read from\n"
" standard input.\n"
"\nExit status is 0 if inputs are identical, 1 if different, 2 if trouble.\n"
"\nOptions:\n"
" -h, --help display this help and exit\n"
@ -81,6 +82,7 @@ void show_help()
" -E, --ignore-tab-expansion ignore changes due to tab expansion\n"
" --format=[<fmt1>][,<fmt2>] force given formats (bz2, gz, lz, xz)\n"
" -i, --ignore-case ignore case differences in file contents\n"
" -N, --no-rcfile don't read runtime configuration file\n"
" -p, --show-c-function show which C function each change is in\n"
" -q, --brief output only whether files differ\n"
" -s, --report-identical-files report when two files are identical\n"
@ -89,6 +91,10 @@ void show_help()
" -u use the unified output format\n"
" -U, --unified=<n> same as -u but use <n> lines of context\n"
" -w, --ignore-all-space ignore all white space\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"
" --xz=<command> set compressor and options for xz format\n"
"Numbers may be followed by a multiplier: k = kB = 10^3 = 1000,\n"
"Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...\n" );
show_help_addr();
@ -151,59 +157,70 @@ bool set_fifonames( const std::string filenames[2] )
bool set_data_feeder( const std::string & fifoname, const int infd,
pid_t * const pidp, const int format_type )
Children & children, int format_index )
{
const uint8_t * magic_data = 0;
int magic_size = 0;
const char * const decompressor_name = ( format_type >= 0 ) ?
decompressor_names[format_type] :
test_format( infd, &magic_data, &magic_size );
if( format_index < 0 )
format_index = test_format( infd, &magic_data, &magic_size );
children.compressor_name = get_compressor_name( format_index );
if( decompressor_name ) // compressed
if( children.compressor_name ) // compressed
{
int fda[2]; // pipe from feeder to decompressor
int fda[2]; // pipe from feeder to compressor
if( pipe( fda ) < 0 )
{ show_error( "Can't create pipe", errno ); return false; }
const pid_t pid = fork();
if( pid == 0 ) // child (decompressor feeder)
if( pid == 0 ) // child 1 (compressor feeder)
{
const pid_t pid2 = fork();
if( pid2 == 0 ) // grandchild (decompressor)
{
const int outfd = open( fifoname.c_str(), O_WRONLY | o_binary );
if( outfd < 0 )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Can't open FIFO '%s' for writing: %s.\n",
util_name, fifoname.c_str(), std::strerror( errno ) );
_exit( 2 );
}
if( dup2( fda[0], STDIN_FILENO ) >= 0 &&
dup2( outfd, STDOUT_FILENO ) >= 0 &&
close( fda[0] ) == 0 && close( fda[1] ) == 0 &&
close( outfd ) == 0 )
execlp( decompressor_name, decompressor_name,
(verbosity >= 0) ? "-d" : "-dq", (char *)0 );
show_exec_error( decompressor_name );
_exit( 2 );
}
if( pid2 < 0 )
{ show_fork_error( decompressor_name ); _exit( 2 ); }
if( close( fda[0] ) != 0 ||
!feed_data( infd, fda[1], magic_data, magic_size ) )
_exit( 2 );
if( close( fda[1] ) != 0 )
{ show_close_error( "data feeder" ); _exit( 2 ); }
_exit( wait_for_child( pid2, decompressor_name ) );
_exit( 0 );
}
// parent
if( pid < 0 ) // parent
{ show_fork_error( "data feeder" ); return false; }
const pid_t pid2 = fork();
if( pid2 == 0 ) // child 2 (compressor)
{
const int outfd = open( fifoname.c_str(), O_WRONLY | o_binary );
if( outfd < 0 )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Can't open FIFO '%s' for writing: %s.\n",
util_name, fifoname.c_str(), std::strerror( errno ) );
_exit( 2 );
}
if( dup2( fda[0], STDIN_FILENO ) >= 0 &&
dup2( outfd, STDOUT_FILENO ) >= 0 &&
close( fda[0] ) == 0 && close( fda[1] ) == 0 &&
close( outfd ) == 0 )
{
const std::vector< std::string > & compressor_args =
get_compressor_args( format_index );
const int size = compressor_args.size();
const char ** const argv = new const char *[size+3];
argv[0] = children.compressor_name;
for( int i = 0; i < size; ++i )
argv[i+1] = compressor_args[i].c_str();
argv[size+1] = ( verbosity >= 0 ) ? "-d" : "-dq";
argv[size+2] = 0;
execvp( argv[0], (char **)argv );
}
show_exec_error( children.compressor_name );
_exit( 2 );
}
if( pid2 < 0 ) // parent
{ show_fork_error( children.compressor_name ); return false; }
close( fda[0] ); close( fda[1] );
if( pid < 0 )
{ show_fork_error( "decompressor feeder" ); return false; }
*pidp = pid;
children.pid[0] = pid;
children.pid[1] = pid2;
}
else // not compressed
else // uncompressed
{
const pid_t pid = fork();
if( pid == 0 ) // child (feeder)
@ -222,10 +239,10 @@ bool set_data_feeder( const std::string & fifoname, const int infd,
{ show_close_error( "data feeder" ); _exit( 2 ); }
_exit( 0 );
}
// parent
if( pid < 0 )
if( pid < 0 ) // parent
{ show_fork_error( "data feeder" ); return false; }
*pidp = pid;
children.pid[0] = pid;
children.pid[1] = 0;
}
return true;
}
@ -251,7 +268,7 @@ void set_signals()
int main( const int argc, const char * const argv[] )
{
enum { format_opt = 256 };
enum { format_opt = 256, bz2_opt, gz_opt, lz_opt, xz_opt };
std::vector< const char * > diff_args; // args to diff, maybe empty
int format_types[2] = { -1, -1 };
invocation_name = argv[0];
@ -268,6 +285,7 @@ int main( const int argc, const char * const argv[] )
{ 'E', "ignore-tab-expansion", Arg_parser::no },
{ 'h', "help", Arg_parser::no },
{ 'i', "ignore-case", Arg_parser::no },
{ 'N', "no-rcfile", Arg_parser::no },
{ 'p', "show-c-function", Arg_parser::no },
{ 'q', "brief", Arg_parser::no },
{ 's', "report-identical-files", Arg_parser::no },
@ -278,12 +296,18 @@ int main( const int argc, const char * const argv[] )
{ 'V', "version", Arg_parser::no },
{ 'w', "ignore-all-space", Arg_parser::no },
{ format_opt, "format", Arg_parser::yes },
{ bz2_opt, "bz2", Arg_parser::yes },
{ gz_opt, "gz", Arg_parser::yes },
{ lz_opt, "lz", Arg_parser::yes },
{ xz_opt, "xz", Arg_parser::yes },
{ 0 , 0, Arg_parser::no } };
const Arg_parser parser( argc, argv, options );
if( parser.error().size() ) // bad option
{ show_error( parser.error().c_str(), 0, true ); return 2; }
maybe_process_config_file( parser );
int argind = 0;
for( ; argind < parser.arguments(); ++argind )
{
@ -301,6 +325,7 @@ int main( const int argc, const char * const argv[] )
case 'E': diff_args.push_back( "-E" ); break;
case 'h': show_help(); return 0;
case 'i': diff_args.push_back( "-i" ); break;
case 'N': break;
case 'p': diff_args.push_back( "-p" ); break;
case 'q': diff_args.push_back( "-q" ); break;
case 's': diff_args.push_back( "-s" ); break;
@ -310,7 +335,11 @@ int main( const int argc, const char * const argv[] )
case 'U': diff_args.push_back( "-U" ); diff_args.push_back( arg ); break;
case 'V': show_version( "Zdiff" ); return 0;
case 'w': diff_args.push_back( "-w" ); break;
case format_opt: get_format_types( arg, format_types ); break;
case format_opt: parse_format_types( arg, format_types ); break;
case bz2_opt: parse_compressor( arg, fmt_bz2 ); break;
case gz_opt: parse_compressor( arg, fmt_gz ); break;
case lz_opt: parse_compressor( arg, fmt_lz ); break;
case xz_opt: parse_compressor( arg, fmt_xz ); break;
default : internal_error( "uncaught option" );
}
} // end process options
@ -375,31 +404,18 @@ int main( const int argc, const char * const argv[] )
show_exec_error( DIFF );
_exit( 2 );
}
// parent
if( diff_pid < 0 )
if( diff_pid < 0 ) // parent
{ show_fork_error( DIFF ); return 2; }
pid_t pid[2];
if( !set_data_feeder( fifonames[0], infd[0], &pid[0], format_types[0] ) ||
!set_data_feeder( fifonames[1], infd[1], &pid[1], format_types[1] ) )
Children children[2];
if( !set_data_feeder( fifonames[0], infd[0], children[0], format_types[0] ) ||
!set_data_feeder( fifonames[1], infd[1], children[1], format_types[1] ) )
return 2;
int retval = wait_for_child( diff_pid, DIFF );
if( retval != 0 )
{
for( int i = 0; i < 2; ++i )
if( pid[i] )
{
const int tmp = child_status( pid[i], "data feeder" );
if( tmp < 0 ) kill( pid[i], SIGTERM ); // child not terminated
else if( tmp != 0 ) retval = 2; // child status != 0
}
}
else
if( ( pid[0] && wait_for_child( pid[0], "data feeder" ) != 0 ) ||
( pid[1] && wait_for_child( pid[1], "data feeder" ) != 0 ) )
retval = 2;
for( int i = 0; i < 2; ++i )
if( !good_status( children[i], retval == 0 ) ) retval = 2;
for( int i = 0; i < 2; ++i )
if( filenames[i] != "-" && close( infd[i] ) != 0 )

View file

@ -18,8 +18,8 @@
void show_zgrep_help()
{
std::printf( "Zgrep is a front end to the grep program that allows transparent search\n"
"on any combination of compressed and non-compressed files. If any given\n"
"file is compressed, its uncompressed content is used. If a given file\n"
"on any combination of compressed and uncompressed files. If any given\n"
"file is compressed, its decompressed content is used. If a given file\n"
"does not exist, and its name does not end with one of the known\n"
"extensions, zgrep tries the compressed file names corresponding to the\n"
"supported formats. If no files are specified, data is read from\n"
@ -51,6 +51,7 @@ void show_zgrep_help()
" -L, --files-without-match only print names of files containing no matches\n"
" -m, --max-count=<n> stop after <n> matches\n"
" -n, --line-number print the line number of each line\n"
" -N, --no-rcfile don't read runtime configuration file\n"
" -o, --only-matching show only the part of a line matching <pattern>\n"
" -q, --quiet suppress all messages\n"
" -r, --recursive operate recursively on directories\n"
@ -58,16 +59,20 @@ void show_zgrep_help()
" -v, --invert-match select non-matching lines\n"
" --verbose verbose mode (show error messages)\n"
" -w, --word-regexp match only whole words\n"
" -x, --line-regexp match only whole lines\n" );
" -x, --line-regexp match only whole lines\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"
" --xz=<command> set compressor and options for xz format\n" );
show_help_addr();
}
int zgrep_stdin( int infd, const int format_type,
int zgrep_stdin( int infd, const int format_index,
const std::vector< const char * > & grep_args )
{
pid_t pid;
if( !set_data_feeder( &infd, &pid, format_type ) ) return 2;
Children children;
if( !set_data_feeder( &infd, children, format_index ) ) return 2;
const pid_t grep_pid = fork();
if( grep_pid == 0 ) // child (grep)
{
@ -83,28 +88,26 @@ int zgrep_stdin( int infd, const int format_type,
show_exec_error( GREP );
_exit( 2 );
}
// parent
if( grep_pid < 0 )
if( grep_pid < 0 ) // parent
{ show_fork_error( GREP ); return 2; }
int retval = wait_for_child( grep_pid, GREP );
if( retval != 1 )
{ if( pid ) kill( pid, SIGTERM ); }
else
if( pid && wait_for_child( pid, "data feeder" ) != 0 ) retval = 2;
if( !good_status( children, retval == 1 ) ) retval = 2;
if( close( infd ) != 0 )
{ show_close_error( "data feeder" ); return 2; }
return retval;
}
int zgrep_file( int infd, const int format_type,
int zgrep_file( int infd, const int format_index,
const std::string & input_filename,
const std::vector< const char * > & grep_args,
const int grep_list_mode, const bool grep_show_name )
{
pid_t pid;
if( !set_data_feeder( &infd, &pid, format_type ) ) return 2;
Children children;
if( !set_data_feeder( &infd, children, format_index ) ) return 2;
int fda[2]; // pipe from grep
if( pipe( fda ) < 0 )
{ show_error( "Can't create pipe", errno ); return 2; }
@ -125,10 +128,10 @@ int zgrep_file( int infd, const int format_type,
show_exec_error( GREP );
_exit( 2 );
}
// parent
close( fda[1] );
if( grep_pid < 0 )
if( grep_pid < 0 ) // parent
{ show_fork_error( GREP ); return 2; }
close( fda[1] );
enum { buffer_size = 256 };
uint8_t buffer[buffer_size];
bool line_begin = true;
@ -154,10 +157,9 @@ int zgrep_file( int infd, const int format_type,
}
int retval = wait_for_child( grep_pid, GREP );
if( retval != 1 )
{ if( pid ) kill( pid, SIGTERM ); }
else
if( pid && wait_for_child( pid, "data feeder" ) != 0 ) retval = 2;
if( !good_status( children, retval == 1 ) ) retval = 2;
if( grep_list_mode && (retval == 0) == (grep_list_mode == 1) )
std::printf( "%s\n", input_filename.c_str() );
if( close( infd ) != 0 )

106
ztest.cc
View file

@ -18,9 +18,9 @@
void show_ztest_help()
{
std::printf( "Ztest verifies the integrity of the specified compressed files.\n"
"Non-compressed files are ignored. If no files are specified, the\n"
"integrity of compressed data read from standard input is verified. Data\n"
"read from standard input must be all in the same compression format.\n"
"Uncompressed files are ignored. If no files are specified, the integrity\n"
"of compressed data read from standard input is verified. Data read from\n"
"standard input must be all in the same compression format.\n"
"\nThe supported formats are bzip2, gzip, lzip and xz.\n"
"\nNote that some xz files lack integrity information, and therefore can't\n"
"be verified as reliably as the other formats can.\n"
@ -32,100 +32,114 @@ void show_ztest_help()
" -h, --help display this help and exit\n"
" -V, --version output version information and exit\n"
" --format=<fmt> force given format (bz2, gz, lz, xz)\n"
" -N, --no-rcfile don't read runtime configuration file\n"
" -q, --quiet suppress all messages\n"
" -r, --recursive operate recursively on directories\n"
" -v, --verbose be verbose (a 2nd -v gives more)\n" );
" -v, --verbose be verbose (a 2nd -v gives more)\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"
" --xz=<command> set compressor and options for xz format\n" );
show_help_addr();
}
int ztest_stdin( const int infd, const int format_type,
int ztest_stdin( const int infd, int format_index,
const std::vector< const char * > & ztest_args )
{
const uint8_t * magic_data = 0;
int magic_size = 0;
const char * const decompressor_name = ( format_type >= 0 ) ?
decompressor_names[format_type] :
test_format( infd, &magic_data, &magic_size );
if( !decompressor_name )
if( format_index < 0 )
format_index = test_format( infd, &magic_data, &magic_size );
const char * const compressor_name = get_compressor_name( format_index );
if( !compressor_name )
{ show_error( "Unknown data format read from stdin." ); return 2; }
int fda[2]; // pipe from feeder
if( pipe( fda ) < 0 )
{ show_error( "Can't create pipe", errno ); return 1; }
const pid_t pid = fork();
if( pid == 0 ) // child1 (decompressor)
if( pid == 0 ) // child1 (compressor)
{
if( dup2( fda[0], STDIN_FILENO ) >= 0 &&
close( fda[0] ) == 0 && close( fda[1] ) == 0 )
{
const char ** const argv = new const char *[ztest_args.size()+3];
argv[0] = decompressor_name;
for( unsigned i = 0; i < ztest_args.size(); ++i )
argv[i+1] = ztest_args[i];
argv[ztest_args.size()+1] = "-t";
argv[ztest_args.size()+2] = 0;
const std::vector< std::string > & compressor_args =
get_compressor_args( format_index );
const int size = compressor_args.size();
const int size2 = ztest_args.size();
const char ** const argv = new const char *[size+size2+3];
argv[0] = compressor_name;
for( int i = 0; i < size; ++i )
argv[i+1] = compressor_args[i].c_str();
for( int i = 0; i < size2; ++i )
argv[i+size+1] = ztest_args[i];
argv[size+size2+1] = "-t";
argv[size+size2+2] = 0;
execvp( argv[0], (char **)argv );
}
show_exec_error( decompressor_name );
show_exec_error( compressor_name );
_exit( 1 );
}
// parent
if( pid < 0 )
{ show_fork_error( decompressor_name ); return 1; }
if( pid < 0 ) // parent
{ show_fork_error( compressor_name ); return 1; }
const pid_t pid2 = fork();
if( pid2 == 0 ) // child2 (decompressor feeder)
if( pid2 == 0 ) // child2 (compressor feeder)
{
if( close( fda[0] ) != 0 ||
!feed_data( infd, fda[1], magic_data, magic_size ) )
_exit( 1 );
if( close( fda[1] ) != 0 )
{ show_close_error( "decompressor feeder" ); _exit( 1 ); }
{ show_close_error( "data feeder" ); _exit( 1 ); }
_exit( 0 );
}
// parent
if( pid2 < 0 )
{ show_fork_error( "decompressor feeder" ); return 1; }
if( pid2 < 0 ) // parent
{ show_fork_error( "data feeder" ); return 1; }
close( fda[0] ); close( fda[1] );
int retval = wait_for_child( pid, decompressor_name, 1 );
if( retval == 0 && wait_for_child( pid2, "decompressor feeder" ) != 0 )
int retval = wait_for_child( pid, compressor_name, 1 );
if( retval == 0 && wait_for_child( pid2, "data feeder" ) != 0 )
retval = 1;
return retval;
}
int ztest_file( const int infd, const int format_type,
int ztest_file( const int infd, int format_index,
const std::string & input_filename,
const std::vector< const char * > & ztest_args )
{
const uint8_t * magic_data = 0;
int magic_size = 0;
const char * const decompressor_name = ( format_type >= 0 ) ?
decompressor_names[format_type] :
test_format( infd, &magic_data, &magic_size );
if( !decompressor_name )
if( format_index < 0 )
format_index = test_format( infd, &magic_data, &magic_size );
const char * const compressor_name = get_compressor_name( format_index );
if( !compressor_name )
return 0; // skip this file
const pid_t pid = fork();
if( pid == 0 ) // child (decompressor)
if( pid == 0 ) // child (compressor)
{
const char ** const argv = new const char *[ztest_args.size()+5];
argv[0] = decompressor_name;
for( unsigned i = 0; i < ztest_args.size(); ++i )
argv[i+1] = ztest_args[i];
argv[ztest_args.size()+1] = "-t";
argv[ztest_args.size()+2] = "--";
argv[ztest_args.size()+3] = input_filename.c_str();
argv[ztest_args.size()+4] = 0;
const std::vector< std::string > & compressor_args =
get_compressor_args( format_index );
const int size = compressor_args.size();
const int size2 = ztest_args.size();
const char ** const argv = new const char *[size+size2+5];
argv[0] = compressor_name;
for( int i = 0; i < size; ++i )
argv[i+1] = compressor_args[i].c_str();
for( int i = 0; i < size2; ++i )
argv[i+size+1] = ztest_args[i];
argv[size+size2+1] = "-t";
argv[size+size2+2] = "--";
argv[size+size2+3] = input_filename.c_str();
argv[size+size2+4] = 0;
execvp( argv[0], (char **)argv );
show_exec_error( decompressor_name );
show_exec_error( compressor_name );
_exit( 1 );
}
// parent
if( pid < 0 )
{ show_fork_error( decompressor_name ); return 1; }
if( pid < 0 ) // parent
{ show_fork_error( compressor_name ); return 1; }
return wait_for_child( pid, decompressor_name, 1 );
return wait_for_child( pid, compressor_name, 1 );
}

123
zutils.cc
View file

@ -22,11 +22,13 @@
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
#include <stdint.h>
#include <unistd.h>
#include <sys/wait.h>
#include "zutils.h"
#include "rc.h"
const char * invocation_name = 0;
@ -35,7 +37,7 @@ const char * util_name = program_name;
int verbosity = 0;
int get_format_type( const std::string & arg )
int parse_format_type( const std::string & arg )
{
for( int i = 0; i < num_formats; ++i )
if( arg == format_names[i] )
@ -102,56 +104,90 @@ bool feed_data( const int infd, const int outfd,
}
bool set_data_feeder( int * const infdp, pid_t * const pidp,
const int format_type )
bool good_status( const Children & children, const bool finished )
{
bool error = false;
for( int i = 0; i < 2; ++i )
{
const pid_t pid = children.pid[i];
if( pid )
{
const char * const msg =
( i & 1 ) ? children.compressor_name : "data feeder";
if( !finished )
{
const int tmp = child_status( pid, msg );
if( tmp < 0 ) kill( pid, SIGTERM ); // child not terminated
else if( tmp != 0 ) error = true; // child status != 0
}
else
if( wait_for_child( pid, msg ) != 0 ) error = true;
}
}
return !error;
}
bool set_data_feeder( int * const infdp, Children & children, int format_index )
{
const uint8_t * magic_data = 0;
int magic_size = 0;
const char * const decompressor_name = ( format_type >= 0 ) ?
decompressor_names[format_type] :
test_format( *infdp, &magic_data, &magic_size );
if( format_index < 0 )
format_index = test_format( *infdp, &magic_data, &magic_size );
children.compressor_name = get_compressor_name( format_index );
if( decompressor_name ) // compressed
if( children.compressor_name ) // compressed
{
int fda[2]; // pipe from feeder
int fda2[2]; // pipe from decompressor
int fda2[2]; // pipe from compressor
if( pipe( fda ) < 0 || pipe( fda2 ) < 0 )
{ show_error( "Can't create pipe", errno ); return false; }
const int old_infd = *infdp;
*infdp = fda2[0];
const pid_t pid = fork();
if( pid == 0 ) // child (decompressor feeder)
if( pid == 0 ) // child 1 (compressor feeder)
{
const pid_t pid2 = fork();
if( pid2 == 0 ) // grandchild (decompressor)
{
if( dup2( fda[0], STDIN_FILENO ) >= 0 &&
dup2( fda2[1], STDOUT_FILENO ) >= 0 &&
close( fda[0] ) == 0 && close( fda[1] ) == 0 &&
close( fda2[0] ) == 0 && close( fda2[1] ) == 0 )
execlp( decompressor_name, decompressor_name,
(verbosity >= 0) ? "-d" : "-dq", (char *)0 );
show_exec_error( decompressor_name );
_exit( 2 );
}
if( pid2 < 0 )
{ show_fork_error( decompressor_name ); _exit( 2 ); }
if( close( fda[0] ) != 0 ||
close( fda2[0] ) != 0 || close( fda2[1] ) != 0 ||
!feed_data( old_infd, fda[1], magic_data, magic_size ) )
_exit( 2 );
if( close( fda[1] ) != 0 )
{ show_close_error( "decompressor feeder" ); _exit( 2 ); }
_exit( wait_for_child( pid2, decompressor_name ) );
{ show_close_error( "data feeder" ); _exit( 2 ); }
_exit( 0 );
}
// parent
if( pid < 0 ) // parent
{ show_fork_error( "data feeder" ); return false; }
const pid_t pid2 = fork();
if( pid2 == 0 ) // child 2 (compressor)
{
if( dup2( fda[0], STDIN_FILENO ) >= 0 &&
dup2( fda2[1], STDOUT_FILENO ) >= 0 &&
close( fda[0] ) == 0 && close( fda[1] ) == 0 &&
close( fda2[0] ) == 0 && close( fda2[1] ) == 0 )
{
const std::vector< std::string > & compressor_args =
get_compressor_args( format_index );
const int size = compressor_args.size();
const char ** const argv = new const char *[size+3];
argv[0] = children.compressor_name;
for( int i = 0; i < size; ++i )
argv[i+1] = compressor_args[i].c_str();
argv[size+1] = ( verbosity >= 0 ) ? "-d" : "-dq";
argv[size+2] = 0;
execvp( argv[0], (char **)argv );
}
show_exec_error( children.compressor_name );
_exit( 2 );
}
if( pid2 < 0 ) // parent
{ show_fork_error( children.compressor_name ); return false; }
close( fda[0] ); close( fda[1] ); close( fda2[1] );
if( pid < 0 )
{ show_fork_error( "decompressor feeder" ); return false; }
*pidp = pid;
children.pid[0] = pid;
children.pid[1] = pid2;
}
else // not compressed
else // uncompressed
{
int fda[2]; // pipe from feeder
if( pipe( fda ) < 0 )
@ -168,11 +204,11 @@ bool set_data_feeder( int * const infdp, pid_t * const pidp,
{ show_close_error( "data feeder" ); _exit( 2 ); }
_exit( 0 );
}
// parent
close( fda[1] );
if( pid < 0 )
if( pid < 0 ) // parent
{ show_fork_error( "data feeder" ); return false; }
*pidp = pid;
close( fda[1] );
children.pid[0] = pid;
children.pid[1] = 0;
}
return true;
}
@ -187,7 +223,7 @@ void show_help_addr()
void show_version( const char * const Util_name )
{
if( !Util_name || !*Util_name )
if( !Util_name || !Util_name[0] )
std::printf( "%s %s\n", Program_name, PROGVERSION );
else
std::printf( "%s (%s) %s\n", Util_name, program_name, PROGVERSION );
@ -256,9 +292,8 @@ void internal_error( const char * const msg )
}
const char * test_format( const int infd,
const uint8_t ** const magic_datap,
int * const magic_sizep )
int test_format( const int infd, const uint8_t ** const magic_datap,
int * const magic_sizep )
{
enum { buf_size = 5 };
static uint8_t buf[buf_size];
@ -271,13 +306,13 @@ const char * test_format( const int infd,
if( readblock( infd, &buf[i], 1 ) == 1 && buf[i++] == bzip2_magic[1] &&
readblock( infd, &buf[i], 1 ) == 1 && buf[i++] == bzip2_magic[2] )
{ *magic_datap = bzip2_magic; *magic_sizep = bzip2_magic_size;
return decompressor_names[fmt_bz2]; }
return fmt_bz2; }
}
else if( buf[0] == gzip_magic[0] )
{
if( readblock( infd, &buf[i], 1 ) == 1 && buf[i++] == gzip_magic[1] )
{ *magic_datap = gzip_magic; *magic_sizep = gzip_magic_size;
return decompressor_names[fmt_gz]; }
return fmt_gz; }
}
else if( buf[0] == lzip_magic[0] )
{
@ -285,7 +320,7 @@ const char * test_format( const int infd,
readblock( infd, &buf[i], 1 ) == 1 && buf[i++] == lzip_magic[2] &&
readblock( infd, &buf[i], 1 ) == 1 && buf[i++] == lzip_magic[3] )
{ *magic_datap = lzip_magic; *magic_sizep = lzip_magic_size;
return decompressor_names[fmt_lz]; }
return fmt_lz; }
}
else if( buf[0] == xz_magic[0] )
{
@ -294,11 +329,11 @@ const char * test_format( const int infd,
readblock( infd, &buf[i], 1 ) == 1 && buf[i++] == xz_magic[3] &&
readblock( infd, &buf[i], 1 ) == 1 && buf[i++] == xz_magic[4] )
{ *magic_datap = xz_magic; *magic_sizep = xz_magic_size;
return decompressor_names[fmt_xz]; }
return fmt_xz; }
}
}
*magic_datap = buf; *magic_sizep = i;
return 0;
return -1;
}

View file

@ -15,9 +15,10 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
const char * const Program_name = "Zutils";
const char * const program_name = "zutils";
const char * const program_year = "2013";
const char * const Program_name = "Zutils";
const char * const program_name = "zutils";
const char * const config_file_name = "zutilsrc";
const char * const program_year = "2013";
extern const char * invocation_name;
extern const char * util_name;
@ -27,8 +28,6 @@ enum { fmt_bz2, fmt_gz, fmt_lz, fmt_xz, num_formats };
const char * const format_names[num_formats] = { "bz2", "gz", "lz", "xz" };
const char * const simple_extensions[num_formats] =
{ ".bz2", ".gz", ".lz", ".xz" };
const char * const decompressor_names[num_formats] =
{ "bzip2", "gzip", "lzip", "xz" };
const int8_t format_order[num_formats] =
{ fmt_lz, fmt_bz2, fmt_gz, fmt_xz }; // search order
@ -47,14 +46,20 @@ const uint8_t xz_magic[xz_magic_size] =
{ 0xFD, 0x37, 0x7A, 0x58, 0x5A }; // 0xFD, "7zXZ"
int get_format_type( const std::string & arg );
int parse_format_type( const std::string & arg );
int readblock( const int fd, uint8_t * const buf, const int size );
int writeblock( const int fd, const uint8_t * const buf, const int size );
bool feed_data( const int infd, const int outfd,
const uint8_t * magic_data, const int magic_size );
bool set_data_feeder( int * const infdp, pid_t * const pidp,
const int format_type );
struct Children
{
const char * compressor_name;
pid_t pid[2]; // data feeder, compressor
};
bool good_status( const Children & children, const bool finished );
bool set_data_feeder( int * const infdp, Children & children, int format_index );
void show_help_addr();
void show_version( const char * const Util_name = 0 );
@ -66,9 +71,10 @@ void show_exec_error( const char * const prog_name );
void show_fork_error( const char * const prog_name );
void internal_error( const char * const msg );
const char * test_format( const int infd,
const uint8_t ** const magic_datap,
int * const magic_sizep );
// Returns format index or -1 if uncompressed
//
int test_format( const int infd, const uint8_t ** const magic_datap,
int * const magic_sizep );
// Returns exit status of child process 'pid', or 'eretval' in case of error.
//

16
zutilsrc Normal file
View file

@ -0,0 +1,16 @@
#
# Runtime Configuration file for Zutils
#
# Zutils looks for this file in:
# 1 - $HOME/.zutilsrc
# 2 - ${sysconfdir}/zutilsrc
# This file sets the compressor and options to be used for each format.
# The command line options override compressors specified in this file.
# Syntax: <format> = <compressor> [options]
# Uncomment each line you want to take effect.
# bz2 = lbzip2 -n2
# gz = pigz -p2
# lz = plzip -n2
# xz = pixz -p2