1
0
Fork 0

Adding upstream version 1.2~pre3.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-24 05:45:53 +01:00
parent c9a98be648
commit cac35a934f
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
32 changed files with 1172 additions and 1035 deletions

View file

@ -1,3 +1,11 @@
2013-10-11 Antonio Diaz Diaz <antonio@gnu.org>
* Version 1.2-pre3 released.
* Removed zutils executable. Utils are now independent executables.
* zupdate.cc: Added new option '-k, --keep'.
* zupdate.cc: Ignore xz files if xz compressor is not installed.
* zgrep.cc: Fixed the exit status returned on error.
2013-09-04 Antonio Diaz Diaz <antonio@gnu.org> 2013-09-04 Antonio Diaz Diaz <antonio@gnu.org>
* Version 1.2-pre2 released. * Version 1.2-pre2 released.

View file

@ -7,28 +7,26 @@ INSTALL_DATA = $(INSTALL) -p -m 644
INSTALL_DIR = $(INSTALL) -d -m 755 INSTALL_DIR = $(INSTALL) -d -m 755
SHELL = /bin/sh SHELL = /bin/sh
objs = arg_parser.o rc.o zutils.o main.o objs = arg_parser.o rc.o zutils.o \
zcat.o zcmp.o zdiff.o zgrep.o ztest.o zupdate.o
zcat_objs = arg_parser.o rc.o zutils.o zcat.o
zcmp_objs = arg_parser.o rc.o zutils.o zcmp.o zcmp_objs = arg_parser.o rc.o zutils.o zcmp.o
zdiff_objs = arg_parser.o rc.o zutils.o zdiff.o zdiff_objs = arg_parser.o rc.o zutils.o zdiff.o
zupdate_objs = arg_parser.o rc.o zutils.o zupdate.o zgrep_objs = arg_parser.o rc.o zutils.o zgrep.o
scripts = zcat zegrep zfgrep zgrep ztest ztest_objs = arg_parser.o rc.o zutils.o ztest.o
zupdate_objs = arg_parser.o rc.o zupdate.o
programs = zcat zcmp zdiff zgrep ztest zupdate
scripts = zegrep zfgrep
.PHONY : all install install-bin install-info install-man install-strip \ .PHONY : all install install-bin install-info install-man install-strip \
uninstall uninstall-bin uninstall-info uninstall-man \ uninstall uninstall-bin uninstall-info uninstall-man \
doc info man check dist clean distclean doc info man check dist clean distclean
all : $(progname) zcmp zdiff zupdate $(scripts) all : $(programs) $(scripts)
$(progname) : $(objs) zcat : $(zcat_objs)
$(CXX) $(LDFLAGS) -o $@ $(objs) $(CXX) $(LDFLAGS) -o $@ $(zcat_objs)
$(progname)_profiled : $(objs)
$(CXX) $(LDFLAGS) -pg -o $@ $(objs)
zcat : zcat.in
cat $(VPATH)/zcat.in > $@
chmod a+x zcat
zcmp : $(zcmp_objs) zcmp : $(zcmp_objs)
$(CXX) $(LDFLAGS) -o $@ $(zcmp_objs) $(CXX) $(LDFLAGS) -o $@ $(zcmp_objs)
@ -44,28 +42,23 @@ zfgrep : zfgrep.in
cat $(VPATH)/zfgrep.in > $@ cat $(VPATH)/zfgrep.in > $@
chmod a+x zfgrep chmod a+x zfgrep
zgrep : zgrep.in zgrep : $(zgrep_objs)
cat $(VPATH)/zgrep.in > $@ $(CXX) $(LDFLAGS) -o $@ $(zgrep_objs)
chmod a+x zgrep
ztest : ztest.in ztest : $(ztest_objs)
cat $(VPATH)/ztest.in > $@ $(CXX) $(LDFLAGS) -o $@ $(ztest_objs)
chmod a+x ztest
zupdate : $(zupdate_objs) zupdate : $(zupdate_objs)
$(CXX) $(LDFLAGS) -o $@ $(zupdate_objs) $(CXX) $(LDFLAGS) -o $@ $(zupdate_objs)
main.o : main.cc rc.o : rc.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -DGREP=\"$(GREP)\" -c -o $@ $< $(CXX) $(CPPFLAGS) $(CXXFLAGS) -DPROGVERSION=\"$(pkgversion)\" -DSYSCONFDIR=\"$(sysconfdir)\" -c -o $@ $<
zdiff.o : zdiff.cc zdiff.o : zdiff.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -DDIFF=\"$(DIFF)\" -c -o $@ $< $(CXX) $(CPPFLAGS) $(CXXFLAGS) -DDIFF=\"$(DIFF)\" -c -o $@ $<
rc.o : rc.cc zgrep.o : zgrep.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -DSYSCONFDIR=\"$(sysconfdir)\" -c -o $@ $< $(CXX) $(CPPFLAGS) $(CXXFLAGS) -DGREP=\"$(GREP)\" -c -o $@ $<
zutils.o : zutils.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -DPROGVERSION=\"$(pkgversion)\" -c -o $@ $<
%.o : %.cc %.o : %.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $< $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<
@ -73,12 +66,14 @@ zutils.o : zutils.cc
$(objs) : Makefile $(objs) : Makefile
$(scripts) : Makefile $(scripts) : Makefile
arg_parser.o : arg_parser.h arg_parser.o : arg_parser.h
main.o : arg_parser.h zutils.h rc.h zcat.cc zgrep.cc ztest.cc rc.o : arg_parser.h rc.h
rc.o : arg_parser.h zutils.h rc.h zcat.o : arg_parser.h rc.h zutils.h recursive.cc
zcmp.o : arg_parser.h zutils.h rc.h zcmpdiff.cc Makefile zcmp.o : arg_parser.h rc.h zutils.h zcmpdiff.cc
zdiff.o : arg_parser.h zutils.h rc.h zcmpdiff.cc Makefile zdiff.o : arg_parser.h rc.h zutils.h zcmpdiff.cc
zupdate.o : arg_parser.h zutils.h rc.h Makefile zgrep.o : arg_parser.h rc.h zutils.h recursive.cc
zutils.o : zutils.h rc.h ztest.o : arg_parser.h rc.h zutils.h recursive.cc
zupdate.o : arg_parser.h rc.h recursive.cc
zutils.o : rc.h zutils.h
doc : info man doc : info man
@ -91,7 +86,7 @@ $(VPATH)/doc/$(pkgname).info : $(VPATH)/doc/$(pkgname).texinfo
man : $(VPATH)/doc/zcat.1 $(VPATH)/doc/zcmp.1 $(VPATH)/doc/zdiff.1 \ man : $(VPATH)/doc/zcat.1 $(VPATH)/doc/zcmp.1 $(VPATH)/doc/zdiff.1 \
$(VPATH)/doc/zgrep.1 $(VPATH)/doc/ztest.1 $(VPATH)/doc/zupdate.1 $(VPATH)/doc/zgrep.1 $(VPATH)/doc/ztest.1 $(VPATH)/doc/zupdate.1
$(VPATH)/doc/zcat.1 : $(progname) zcat $(VPATH)/doc/zcat.1 : zcat
help2man -n 'decompress and concatenate files to standard output' \ help2man -n 'decompress and concatenate files to standard output' \
-o $@ --no-info ./zcat -o $@ --no-info ./zcat
@ -103,11 +98,11 @@ $(VPATH)/doc/zdiff.1 : zdiff
help2man -n 'decompress and compare two files line by line' \ help2man -n 'decompress and compare two files line by line' \
-o $@ --no-info ./zdiff -o $@ --no-info ./zdiff
$(VPATH)/doc/zgrep.1 : $(progname) zgrep $(VPATH)/doc/zgrep.1 : zgrep
help2man -n 'search compressed files for a regular expression' \ help2man -n 'search compressed files for a regular expression' \
-o $@ --no-info ./zgrep -o $@ --no-info ./zgrep
$(VPATH)/doc/ztest.1 : $(progname) ztest $(VPATH)/doc/ztest.1 : ztest
help2man -n 'verify integrity of compressed files' \ help2man -n 'verify integrity of compressed files' \
-o $@ --no-info ./ztest -o $@ --no-info ./ztest
@ -125,14 +120,13 @@ install : install-bin install-info install-man
install-bin : all install-bin : all
if [ ! -d "$(DESTDIR)$(bindir)" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(bindir)" ; fi if [ ! -d "$(DESTDIR)$(bindir)" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(bindir)" ; fi
$(INSTALL_PROGRAM) ./$(progname) "$(DESTDIR)$(bindir)/$(progname)" $(INSTALL_PROGRAM) ./zcat "$(DESTDIR)$(bindir)/zcat"
$(INSTALL_SCRIPT) ./zcat "$(DESTDIR)$(bindir)/zcat"
$(INSTALL_PROGRAM) ./zcmp "$(DESTDIR)$(bindir)/zcmp" $(INSTALL_PROGRAM) ./zcmp "$(DESTDIR)$(bindir)/zcmp"
$(INSTALL_PROGRAM) ./zdiff "$(DESTDIR)$(bindir)/zdiff" $(INSTALL_PROGRAM) ./zdiff "$(DESTDIR)$(bindir)/zdiff"
$(INSTALL_SCRIPT) ./zegrep "$(DESTDIR)$(bindir)/zegrep" $(INSTALL_SCRIPT) ./zegrep "$(DESTDIR)$(bindir)/zegrep"
$(INSTALL_SCRIPT) ./zfgrep "$(DESTDIR)$(bindir)/zfgrep" $(INSTALL_SCRIPT) ./zfgrep "$(DESTDIR)$(bindir)/zfgrep"
$(INSTALL_SCRIPT) ./zgrep "$(DESTDIR)$(bindir)/zgrep" $(INSTALL_PROGRAM) ./zgrep "$(DESTDIR)$(bindir)/zgrep"
$(INSTALL_SCRIPT) ./ztest "$(DESTDIR)$(bindir)/ztest" $(INSTALL_PROGRAM) ./ztest "$(DESTDIR)$(bindir)/ztest"
$(INSTALL_PROGRAM) ./zupdate "$(DESTDIR)$(bindir)/zupdate" $(INSTALL_PROGRAM) ./zupdate "$(DESTDIR)$(bindir)/zupdate"
if [ ! -e "$(DESTDIR)$(sysconfdir)/$(pkgname)rc" ] ; then \ if [ ! -e "$(DESTDIR)$(sysconfdir)/$(pkgname)rc" ] ; then \
if [ ! -d "$(DESTDIR)$(sysconfdir)" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(sysconfdir)" ; fi ; \ if [ ! -d "$(DESTDIR)$(sysconfdir)" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(sysconfdir)" ; fi ; \
@ -159,7 +153,6 @@ install-strip : all
uninstall : uninstall-bin uninstall-info uninstall-man uninstall : uninstall-bin uninstall-info uninstall-man
uninstall-bin : uninstall-bin :
-rm -f "$(DESTDIR)$(bindir)/$(progname)"
-rm -f "$(DESTDIR)$(bindir)/zcat" -rm -f "$(DESTDIR)$(bindir)/zcat"
-rm -f "$(DESTDIR)$(bindir)/zcmp" -rm -f "$(DESTDIR)$(bindir)/zcmp"
-rm -f "$(DESTDIR)$(bindir)/zdiff" -rm -f "$(DESTDIR)$(bindir)/zdiff"
@ -207,8 +200,7 @@ dist : doc
lzip -v -9 $(DISTNAME).tar lzip -v -9 $(DISTNAME).tar
clean : clean :
-rm -f $(progname) $(progname)_profiled $(objs) -rm -f $(programs) $(scripts) $(objs)
-rm -f zcmp zcmp.o zdiff zdiff.o zupdate zupdate.o $(scripts)
distclean : clean distclean : clean
-rm -f Makefile config.status *.tar *.tar.lz -rm -f Makefile config.status *.tar *.tar.lz

5
NEWS
View file

@ -1,4 +1,9 @@
Changes in version 1.2: Changes in version 1.2:
The zutils executable has been removed. All utilities are now
independent executables.
The new utility zupdate, which recompresses bzip2, gzip and xz files to The new utility zupdate, which recompresses bzip2, gzip and xz files to
lzip format, has been added. lzip format, has been added.
The exit status of zgrep should now be identical to that of grep.

7
README
View file

@ -10,16 +10,17 @@ These utilities are not wrapper scripts but safer and more efficient C++
programs. In particular the "--recursive" option is very efficient in programs. In particular the "--recursive" option is very efficient in
those utilities supporting it. those utilities supporting it.
The provided utilities are zcat, zcmp, zdiff, zgrep and ztest. The provided utilities are zcat, zcmp, zdiff, zgrep, ztest and zupdate.
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. The compressor to be used for each format is configurable at runtime.
Zcat, zcmp, zdiff, and zgrep are improved replacements for the shell Zcat, zcmp, zdiff, and zgrep are improved replacements for the shell
scripts provided with GNU gzip. Ztest is unique to zutils. scripts provided with GNU gzip. Ztest is unique to zutils. Zupdate is
similar to gzip's znew.
NOTE: Bzip2 and lzip provide well-defined values of exit status, which 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 makes them safe to use with zutils. Gzip and xz may return ambiguous
warning values, making them less reliable backends for zutils. warning values, making them less reliable back ends for zutils.
LANGUAGE NOTE: Uncompressed = not compressed = plain data; it may never LANGUAGE NOTE: Uncompressed = not compressed = plain data; it may never
have been compressed. Decompressed is used to refer to data which has have been compressed. Decompressed is used to refer to data which has

4
configure vendored
View file

@ -6,8 +6,7 @@
# to copy, distribute and modify it. # to copy, distribute and modify it.
pkgname=zutils pkgname=zutils
pkgversion=1.2-pre2 pkgversion=1.2-pre3
progname=zutils
srctrigger=doc/${pkgname}.texinfo srctrigger=doc/${pkgname}.texinfo
# clear some things potentially inherited from environment. # clear some things potentially inherited from environment.
@ -186,7 +185,6 @@ cat > Makefile << EOF
pkgname = ${pkgname} pkgname = ${pkgname}
pkgversion = ${pkgversion} pkgversion = ${pkgversion}
progname = ${progname}
VPATH = ${srcdir} VPATH = ${srcdir}
prefix = ${prefix} prefix = ${prefix}
exec_prefix = ${exec_prefix} exec_prefix = ${exec_prefix}

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1. .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH ZCAT "1" "September 2013" "Zcat (zutils) 1.2-pre2" "User Commands" .TH ZCAT "1" "October 2013" "Zcat (zutils) 1.2-pre3" "User Commands"
.SH NAME .SH NAME
Zcat \- decompress and concatenate files to standard output Zcat \- decompress and concatenate files to standard output
.SH SYNOPSIS .SH SYNOPSIS

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1. .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH ZCMP "1" "September 2013" "Zcmp (zutils) 1.2-pre2" "User Commands" .TH ZCMP "1" "October 2013" "Zcmp (zutils) 1.2-pre3" "User Commands"
.SH NAME .SH NAME
Zcmp \- decompress and compare two files byte by byte Zcmp \- decompress and compare two files byte by byte
.SH SYNOPSIS .SH SYNOPSIS

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1. .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH ZDIFF "1" "September 2013" "Zdiff (zutils) 1.2-pre2" "User Commands" .TH ZDIFF "1" "October 2013" "Zdiff (zutils) 1.2-pre3" "User Commands"
.SH NAME .SH NAME
Zdiff \- decompress and compare two files line by line Zdiff \- decompress and compare two files line by line
.SH SYNOPSIS .SH SYNOPSIS

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1. .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH ZGREP "1" "September 2013" "Zgrep (zutils) 1.2-pre2" "User Commands" .TH ZGREP "1" "October 2013" "Zgrep (zutils) 1.2-pre3" "User Commands"
.SH NAME .SH NAME
Zgrep \- search compressed files for a regular expression Zgrep \- search compressed files for a regular expression
.SH SYNOPSIS .SH SYNOPSIS

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1. .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH ZTEST "1" "September 2013" "Ztest (zutils) 1.2-pre2" "User Commands" .TH ZTEST "1" "October 2013" "Ztest (zutils) 1.2-pre3" "User Commands"
.SH NAME .SH NAME
Ztest \- verify integrity of compressed files Ztest \- verify integrity of compressed files
.SH SYNOPSIS .SH SYNOPSIS

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1. .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH ZUPDATE "1" "September 2013" "Zupdate (zutils) 1.2-pre2" "User Commands" .TH ZUPDATE "1" "October 2013" "Zupdate (zutils) 1.2-pre3" "User Commands"
.SH NAME .SH NAME
Zupdate \- recompress bzip2, gzip, xz files to lzip files Zupdate \- recompress bzip2, gzip, xz files to lzip files
.SH SYNOPSIS .SH SYNOPSIS
@ -35,6 +35,9 @@ output version information and exit
\fB\-f\fR, \fB\-\-force\fR \fB\-f\fR, \fB\-\-force\fR
do not skip a file even if the .lz exists do not skip a file even if the .lz exists
.TP .TP
\fB\-k\fR, \fB\-\-keep\fR
keep (don't delete) input files
.TP
\fB\-l\fR, \fB\-\-lzip\-verbose\fR \fB\-l\fR, \fB\-\-lzip\-verbose\fR
pass a \fB\-v\fR option to the lzip compressor pass a \fB\-v\fR option to the lzip compressor
.TP .TP

View file

@ -1,4 +1,4 @@
This is zutils.info, produced by makeinfo version 4.13 from This is zutils.info, produced by makeinfo version 4.13+ from
zutils.texinfo. zutils.texinfo.
INFO-DIR-SECTION Data Compression INFO-DIR-SECTION Data Compression
@ -12,7 +12,7 @@ File: zutils.info, Node: Top, Next: Introduction, Up: (dir)
Zutils Manual Zutils Manual
************* *************
This manual is for Zutils (version 1.2-pre2, 4 September 2013). This manual is for Zutils (version 1.2-pre3, 11 October 2013).
* Menu: * Menu:
@ -47,7 +47,7 @@ used. Compressed files are decompressed on the fly; no temporary files
are created. are created.
These utilities are not wrapper scripts but safer and more efficient These utilities are not wrapper scripts but safer and more efficient
C++ programs. In particular the `--recursive' option is very efficient C++ programs. In particular the '--recursive' option is very efficient
in those utilities supporting it. in those utilities supporting it.
The provided utilities are zcat, zcmp, zdiff, zgrep, ztest and zupdate. The provided utilities are zcat, zcmp, zdiff, zgrep, ztest and zupdate.
@ -60,7 +60,8 @@ similar to gzip's znew.
NOTE: Bzip2 and lzip provide well-defined values of exit status, NOTE: Bzip2 and lzip provide well-defined values of exit status,
which makes them safe to use with zutils. Gzip and xz may return which makes them safe to use with zutils. Gzip and xz may return
ambiguous warning values, making them less reliable backends for zutils. ambiguous warning values, making them less reliable back ends for
zutils.
LANGUAGE NOTE: Uncompressed = not compressed = plain data; it may LANGUAGE NOTE: Uncompressed = not compressed = plain data; it may
never have been compressed. Decompressed is used to refer to data which never have been compressed. Decompressed is used to refer to data which
@ -68,7 +69,7 @@ has undergone the process of decompression.
Numbers given as arguments to options (positions, sizes) may be Numbers given as arguments to options (positions, sizes) may be
followed by a multiplier and an optional `B' for "byte". followed by a multiplier and an optional 'B' for "byte".
Table of SI and binary prefixes (unit multipliers): Table of SI and binary prefixes (unit multipliers):
@ -92,33 +93,33 @@ The following options are available in all the utilities. Rather than
writing identical descriptions for each of the programs, they are writing identical descriptions for each of the programs, they are
described here. described here.
`-h' '-h'
`--help' '--help'
Print an informative help message describing the options and exit. Print an informative help message describing the options and exit.
Zgrep only supports the `--help' form of this option. Zgrep only supports the '--help' form of this option.
`-V' '-V'
`--version' '--version'
Print the version number on the standard output and exit. Print the version number on the standard output and exit.
`-N' '-N'
`--no-rcfile' '--no-rcfile'
Don't read the runtime configuration file `zutilsrc'. Don't read the runtime configuration file 'zutilsrc'.
`--bz2=COMMAND' '--bz2=COMMAND'
`--gz=COMMAND' '--gz=COMMAND'
`--lz=COMMAND' '--lz=COMMAND'
`--xz=COMMAND' '--xz=COMMAND'
Set program (may include arguments) to be used as (de)compressor Set program (may include arguments) to be used as (de)compressor
for the given format. These options override the values set in for the given format. These options override the values set in
`zutilsrc'. The compression program used must meet three 'zutilsrc'. The compression program used must meet three
requirements: requirements:
1. When called with the `-d' option, it must read compressed 1. When called with the '-d' option, it must read compressed
data from the standard input and produce decompressed data on data from the standard input and produce decompressed data on
the standard output. the standard output.
2. If the `-q' option is passed to zutils, the compression 2. If the '-q' option is passed to zutils, the compression
program must also accept it. program must also accept it.
3. It must return 0 if no errors occurred, and a non-zero value 3. It must return 0 if no errors occurred, and a non-zero value
@ -131,24 +132,24 @@ File: zutils.info, Node: The zutilsrc file, Next: Zcat, Prev: Common options,
3 The zutilsrc file 3 The zutilsrc file
******************* *******************
`zutilsrc' is the runtime configuration file for zutils. In it you may '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 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 'zutilsrc' file is optional; you do not need to install it in order to
run zutils. run zutils.
The compressors specified in the command line override those The compressors specified in the command line override those
specified in the `zutilsrc' file. specified in the 'zutilsrc' file.
You may copy the system `zutilsrc' file `${sysconfdir}/zutilsrc' to You may copy the system 'zutilsrc' file '${sysconfdir}/zutilsrc' to
`$HOME/.zutilsrc' and customize these options as you like. The file '$HOME/.zutilsrc' and customize these options as you like. The file
syntax is fairly obvious (and there are further instructions in it): syntax is fairly obvious (and there are further instructions in it):
1. Any line beginning with `#' is a comment line. 1. Any line beginning with '#' is a comment line.
2. Each non-comment line defines the command to be used for the given 2. Each non-comment line defines the command to be used for the given
format, with the syntax: format, with the syntax:
<format> = <compressor> [options] <format> = <compressor> [options]
where <format> is one of `bz2', `gz', `lz' or `xz'. where <format> is one of 'bz2', 'gz', 'lz' or 'xz'.
 
File: zutils.info, Node: Zcat, Next: Zcmp, Prev: The zutilsrc file, Up: Top File: zutils.info, Node: Zcat, Next: Zcmp, Prev: The zutilsrc file, Up: Top
@ -156,7 +157,7 @@ File: zutils.info, Node: Zcat, Next: Zcmp, Prev: The zutilsrc file, Up: Top
4 Zcat 4 Zcat
****** ******
Zcat copies each given file (`-' means standard input), to standard Zcat copies each given file ('-' means standard input), to standard
output. If any given file is compressed, its decompressed 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 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 of the known extensions, zcat tries the compressed file names
@ -175,58 +176,58 @@ Exit status is 0 if no errors occurred, non-zero otherwise.
Zcat supports the following options: Zcat supports the following options:
`-A' '-A'
`--show-all' '--show-all'
Equivalent to `-vET'. Equivalent to '-vET'.
`-b' '-b'
`--number-nonblank' '--number-nonblank'
Number all nonblank output lines, starting with 1. The line count Number all nonblank output lines, starting with 1. The line count
is unlimited. is unlimited.
`-e' '-e'
Equivalent to `-vE'. Equivalent to '-vE'.
`-E' '-E'
`--show-ends' '--show-ends'
Print a `$' after the end of each line. Print a '$' after the end of each line.
`--format=FMT' '--format=FMT'
Force the given compression format. Valid values for FMT are Force the given compression format. Valid values for FMT are
`bz2', `gz', `lz' and `xz'. If this option is used, the exact file 'bz2', 'gz', 'lz' and 'xz'. If this option is used, the exact file
name must be given. Other names won't be tried. name must be given. Other names won't be tried.
`-n' '-n'
`--number' '--number'
Number all output lines, starting with 1. The line count is Number all output lines, starting with 1. The line count is
unlimited. unlimited.
`-q' '-q'
`--quiet' '--quiet'
Quiet operation. Suppress all messages. Quiet operation. Suppress all messages.
`-r' '-r'
`--recursive' '--recursive'
Operate recursively on directories. Operate recursively on directories.
`-s' '-s'
`--squeeze-blank' '--squeeze-blank'
Replace multiple adjacent blank lines with a single blank line. Replace multiple adjacent blank lines with a single blank line.
`-t' '-t'
Equivalent to `-vT'. Equivalent to '-vT'.
`-T' '-T'
`--show-tabs' '--show-tabs'
Print TAB characters as `^I'. Print TAB characters as '^I'.
`-v' '-v'
`--show-nonprinting' '--show-nonprinting'
Print control characters except for LF (newline) and TAB using `^' Print control characters except for LF (newline) and TAB using '^'
notation and precede characters larger than 127 with `M-' (which notation and precede characters larger than 127 with 'M-' (which
stands for "meta"). stands for "meta").
`--verbose' '--verbose'
Verbose mode. Show error messages. Verbose mode. Show error messages.
@ -236,7 +237,7 @@ File: zutils.info, Node: Zcmp, Next: Zdiff, Prev: Zcat, Up: Top
5 Zcmp 5 Zcmp
****** ******
Zcmp compares two files (`-' means standard input), and if they differ, Zcmp compares two files ('-' means standard input), and if they differ,
tells the first byte and line number where they differ. Bytes and lines 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 are numbered starting with 1. If any given file is compressed, its
decompressed content is used. Compressed files are decompressed on the decompressed content is used. Compressed files are decompressed on the
@ -264,43 +265,43 @@ differences were found, and 2 means trouble.
Zcmp supports the following options: Zcmp supports the following options:
`-b' '-b'
`--print-bytes' '--print-bytes'
Print the differing bytes. Print control bytes as a `^' followed by Print the differing bytes. Print control bytes as a '^' followed by
a letter, and precede bytes larger than 127 with `M-' (which stands a letter, and precede bytes larger than 127 with 'M-' (which stands
for "meta"). for "meta").
`--format=[FMT1][,FMT2]' '--format=[FMT1][,FMT2]'
Force the given compression formats. Any of FMT1 or FMT2 may be Force the given compression formats. Any of FMT1 or FMT2 may be
omitted and the corresponding format will be automatically omitted and the corresponding format will be automatically
detected. Valid values for FMT are `bz2', `gz', `lz' and `xz'. If detected. Valid values for FMT are 'bz2', 'gz', 'lz' and 'xz'. If
at least one format is specified with this option, the exact file at least one format is specified with this option, the exact file
names of both FILE1 and FILE2 must be given. Other names won't be names of both FILE1 and FILE2 must be given. Other names won't be
tried. tried.
`-i SIZE' '-i SIZE'
`--ignore-initial=SIZE' '--ignore-initial=SIZE'
Ignore any differences in the first SIZE bytes of the input files. Ignore any differences in the first SIZE bytes of the input files.
Treat files with fewer than SIZE bytes as if they were empty. If Treat files with fewer than SIZE bytes as if they were empty. If
SIZE is in the form `SIZE1,SIZE2', ignore the first SIZE1 bytes of SIZE is in the form 'SIZE1,SIZE2', ignore the first SIZE1 bytes of
the first input file and the first SIZE2 bytes of the second input the first input file and the first SIZE2 bytes of the second input
file. file.
`-l' '-l'
`-v' '-v'
`--list' '--list'
`--verbose' '--verbose'
Print the byte numbers (in decimal) and values (in octal) of all Print the byte numbers (in decimal) and values (in octal) of all
differing bytes. differing bytes.
`-n COUNT' '-n COUNT'
`--bytes=COUNT' '--bytes=COUNT'
Compare at most COUNT input bytes. Compare at most COUNT input bytes.
`-q' '-q'
`-s' '-s'
`--quiet' '--quiet'
`--silent' '--silent'
Do not print anything; only return an exit status indicating Do not print anything; only return an exit status indicating
whether the files differ. whether the files differ.
@ -311,7 +312,7 @@ File: zutils.info, Node: Zdiff, Next: Zgrep, Prev: Zcmp, Up: Top
6 Zdiff 6 Zdiff
******* *******
Zdiff compares two files (`-' means standard input), and if they Zdiff compares two files ('-' means standard input), and if they
differ, shows the differences line by line. If any given file is differ, shows the differences line by line. If any given file is
compressed, its decompressed 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 the diff program and has the limitation that messages from diff refer to
@ -339,74 +340,74 @@ differences were found, and 2 means trouble.
Zdiff supports the following options: Zdiff supports the following options:
`-a' '-a'
`--text' '--text'
Treat all files as text. Treat all files as text.
`-b' '-b'
`--ignore-space-change' '--ignore-space-change'
Ignore changes in the amount of white space. Ignore changes in the amount of white space.
`-B' '-B'
`--ignore-blank-lines' '--ignore-blank-lines'
Ignore changes whose lines are all blank. Ignore changes whose lines are all blank.
`-c' '-c'
Use the context output format. Use the context output format.
`-C N' '-C N'
`--context=N' '--context=N'
Same as -c but use N lines of context. Same as -c but use N lines of context.
`-d' '-d'
`--minimal' '--minimal'
Try hard to find a smaller set of changes. Try hard to find a smaller set of changes.
`-E' '-E'
`--ignore-tab-expansion' '--ignore-tab-expansion'
Ignore changes due to tab expansion. Ignore changes due to tab expansion.
`--format=[FMT1][,FMT2]' '--format=[FMT1][,FMT2]'
Force the given compression formats. Any of FMT1 or FMT2 may be Force the given compression formats. Any of FMT1 or FMT2 may be
omitted and the corresponding format will be automatically omitted and the corresponding format will be automatically
detected. Valid values for FMT are `bz2', `gz', `lz' and `xz'. If detected. Valid values for FMT are 'bz2', 'gz', 'lz' and 'xz'. If
at least one format is specified with this option, the exact file at least one format is specified with this option, the exact file
names of both FILE1 and FILE2 must be given. Other names won't be names of both FILE1 and FILE2 must be given. Other names won't be
tried. tried.
`-i' '-i'
`--ignore-case' '--ignore-case'
Ignore case differences in file contents. Ignore case differences in file contents.
`-p' '-p'
`--show-c-function' '--show-c-function'
Show which C function each change is in. Show which C function each change is in.
`-q' '-q'
`--brief' '--brief'
Output only whether files differ. Output only whether files differ.
`-s' '-s'
`--report-identical-files' '--report-identical-files'
Report when two files are identical. Report when two files are identical.
`-t' '-t'
`--expand-tabs' '--expand-tabs'
Expand tabs to spaces in output. Expand tabs to spaces in output.
`-T' '-T'
`--initial-tab' '--initial-tab'
Make tabs line up by prepending a tab. Make tabs line up by prepending a tab.
`-u' '-u'
Use the unified output format. Use the unified output format.
`-U N' '-U N'
`--unified=N' '--unified=N'
Same as -u but use N lines of context. Same as -u but use N lines of context.
`-w' '-w'
`--ignore-all-space' '--ignore-all-space'
Ignore all white space. Ignore all white space.
@ -437,112 +438,113 @@ matches were found, and 2 means trouble.
Zgrep supports the following options: Zgrep supports the following options:
`-a' '-a'
`--text' '--text'
Treat all files as text. Treat all files as text.
`-A N' '-A N'
`--after-context=N' '--after-context=N'
Print N lines of trailing context. Print N lines of trailing context.
`-b' '-b'
`--byte-offset' '--byte-offset'
Print the byte offset of each line. Print the byte offset of each line.
`-B N' '-B N'
`--before-context=N' '--before-context=N'
Print N lines of leading context. Print N lines of leading context.
`-c' '-c'
`--count' '--count'
Only print a count of matching lines per file. Only print a count of matching lines per file.
`-C N' '-C N'
`--context=N' '--context=N'
Print N lines of output context. Print N lines of output context.
`-e PATTERN' '-e PATTERN'
`--regexp=PATTERN' '--regexp=PATTERN'
Use PATTERN as the pattern to match. Use PATTERN as the pattern to match.
`-E' '-E'
`--extended-regexp' '--extended-regexp'
Treat PATTERN as an extended regular expression. Treat PATTERN as an extended regular expression.
`-f FILE' '-f FILE'
`--file=FILE' '--file=FILE'
Obtain patterns from FILE, one per line. Obtain patterns from FILE, one per line.
`-F' '-F'
`--fixed-strings' '--fixed-strings'
Treat PATTERN as a set of newline-separated strings. Treat PATTERN as a set of newline-separated strings.
`--format=FMT' '--format=FMT'
Force the given compression format. Valid values for FMT are Force the given compression format. Valid values for FMT are
`bz2', `gz', `lz' and `xz'. If this option is used, the exact file 'bz2', 'gz', 'lz' and 'xz'. If this option is used, the exact file
name must be given. Other names won't be tried. name must be given. Other names won't be tried.
`-h' '-h'
`--no-filename' '--no-filename'
Suppress the prefixing of filenames on output when multiple files Suppress the prefixing of filenames on output when multiple files
are searched. are searched.
`-H' '-H'
`--with-filename' '--with-filename'
Print the filename for each match. Print the filename for each match.
`-i' '-i'
`--ignore-case' '--ignore-case'
Ignore case distinctions. Ignore case distinctions.
`-I' '-I'
Ignore binary files. Ignore binary files.
`-l' '-l'
`--files-with-matches' '--files-with-matches'
Only print names of files containing at least one match. Only print names of files containing at least one match.
`-L' '-L'
`--files-without-match' '--files-without-match'
Only print names of files not containing any matches. Only print names of files not containing any matches.
`-m N' '-m N'
`--max-count=N' '--max-count=N'
Stop after N matches. Stop after N matches.
`-n' '-n'
`--line-number' '--line-number'
Prefix each matched line with its line number in the input file. Prefix each matched line with its line number in the input file.
`-o' '-o'
`--only-matching' '--only-matching'
Show only the part of matching lines that actually matches PATTERN. Show only the part of matching lines that actually matches PATTERN.
`-q' '-q'
`--quiet' '--quiet'
Suppress all messages. Suppress all messages. Exit immediately with zero status if any
match is found, even if an error was detected.
`-r' '-r'
`--recursive' '--recursive'
Operate recursively on directories. Operate recursively on directories.
`-s' '-s'
`--no-messages' '--no-messages'
Suppress error messages. Suppress error messages about nonexistent or unreadable files.
`-v' '-v'
`--invert-match' '--invert-match'
Select non-matching lines. Select non-matching lines.
`--verbose' '--verbose'
Verbose mode. Show error messages. Verbose mode. Show error messages.
`-w' '-w'
`--word-regexp' '--word-regexp'
Match only whole words. Match only whole words.
`-x' '-x'
`--line-regexp' '--line-regexp'
Match only whole lines. Match only whole lines.
@ -570,21 +572,21 @@ environmental problems (file not found, invalid flags, I/O errors, etc),
Ztest supports the following options: Ztest supports the following options:
`--format=FMT' '--format=FMT'
Force the given compression format. Valid values for FMT are Force the given compression format. Valid values for FMT are
`bz2', `gz', `lz' and `xz'. If this option is used, all files not 'bz2', 'gz', 'lz' and 'xz'. If this option is used, all files not
in the given format will fail. in the given format will fail.
`-q' '-q'
`--quiet' '--quiet'
Quiet operation. Suppress all messages. Quiet operation. Suppress all messages.
`-r' '-r'
`--recursive' '--recursive'
Operate recursively on directories. Operate recursively on directories.
`-v' '-v'
`--verbose' '--verbose'
Verbose mode. Show the verify status for each file processed. Verbose mode. Show the verify status for each file processed.
Further -v's increase the verbosity level. Further -v's increase the verbosity level.
@ -604,15 +606,15 @@ is chosen as destination because it is by far the most appropriate for
long-term data archiving. long-term data archiving.
If the lzip compressed version of a file already exists, the file is If the lzip compressed version of a file already exists, the file is
skipped unless the `--force' option is given. In this case, if the skipped unless the '--force' option is given. In this case, if the
comparison fails, an error is returned and the original file is not comparison fails, an error is returned and the original file is not
deleted. The operation of zupdate is meant to be safe and not produce deleted. The operation of zupdate is meant to be safe and not produce
any data loss. Therefore, existing lzip compressed files are never any data loss. Therefore, existing lzip compressed files are never
overwritten nor deleted. overwritten nor deleted.
The names of the original files must have one of the following The names of the original files must have one of the following
extensions: `.bz2', `.tbz', `.tbz2', `.gz', `.tgz', `.xz', `.txz'. The extensions: '.bz2', '.tbz', '.tbz2', '.gz', '.tgz', '.xz', '.txz'. The
files produced have the extensions `.lz' or `.tar.lz'. files produced have the extensions '.lz' or '.tar.lz'.
The format for running zupdate is: The format for running zupdate is:
@ -623,35 +625,40 @@ recompressed (if needed), compared and deleted. Non-zero otherwise.
Zupdate supports the following options: Zupdate supports the following options:
`-f' '-f'
`--force' '--force'
Do not skip a file for which a lzip compressed version already Do not skip a file for which a lzip compressed version already
exists. `--force' compares the content of the input file with the exists. '--force' compares the content of the input file with the
content of the lzip file and deletes the input file if both content of the lzip file and deletes the input file if both
contents are identical. contents are identical.
`-l' '-k'
`--lzip-verbose' '--keep'
Pass a `-v' option to the lzip compressor so that it shows the Keep (don't delete) the input file after comparing it with the
compression ratio for each file processed. Using lzip 1.15 and lzip file.
newer, a second `-l' shows the progress of compression. Use it
together with `-v' to see the name of the file.
`-q' '-l'
`--quiet' '--lzip-verbose'
Pass a '-v' option to the lzip compressor so that it shows the
compression ratio for each file processed. Using lzip 1.15 and
newer, a second '-l' shows the progress of compression. Use it
together with '-v' to see the name of the file.
'-q'
'--quiet'
Quiet operation. Suppress all messages. Quiet operation. Suppress all messages.
`-r' '-r'
`--recursive' '--recursive'
Operate recursively on directories. Operate recursively on directories.
`-v' '-v'
`--verbose' '--verbose'
Verbose mode. Show the files being processed. A second `-v' also Verbose mode. Show the files being processed. A second '-v' also
shows the files being ignored. shows the files being ignored.
`-0 .. -9' '-0 .. -9'
Set the compression level of lzip. By default zupdate passes `-9' Set the compression level of lzip. By default zupdate passes '-9'
to lzip. to lzip.
@ -668,7 +675,7 @@ for all eternity, if not longer.
If you find a bug in zutils, please send electronic mail to If you find a bug in zutils, please send electronic mail to
<zutils-bug@nongnu.org>. Include the version number, which you can find <zutils-bug@nongnu.org>. Include the version number, which you can find
by running `zutils --version'. by running 'zcmp --version'.
 
File: zutils.info, Node: Concept index, Prev: Problems, Up: Top File: zutils.info, Node: Concept index, Prev: Problems, Up: Top
@ -694,18 +701,18 @@ Concept index
 
Tag Table: Tag Table:
Node: Top224 Node: Top225
Node: Introduction1156 Node: Introduction1156
Node: Common options3258 Node: Common options3259
Node: The zutilsrc file4507 Node: The zutilsrc file4508
Node: Zcat5433 Node: Zcat5434
Node: Zcmp7355 Node: Zcmp7356
Node: Zdiff9679 Node: Zdiff9680
Node: Zgrep12182 Node: Zgrep12183
Node: Ztest15019 Node: Ztest15151
Node: Zupdate16243 Node: Zupdate16375
Node: Problems18477 Node: Problems18708
Node: Concept index19010 Node: Concept index19239
 
End Tag Table End Tag Table

View file

@ -6,8 +6,8 @@
@finalout @finalout
@c %**end of header @c %**end of header
@set UPDATED 4 September 2013 @set UPDATED 11 October 2013
@set VERSION 1.2-pre2 @set VERSION 1.2-pre3
@dircategory Data Compression @dircategory Data Compression
@direntry @direntry
@ -80,7 +80,7 @@ similar to gzip's znew.
NOTE: Bzip2 and lzip provide well-defined values of exit status, which 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 makes them safe to use with zutils. Gzip and xz may return ambiguous
warning values, making them less reliable backends for zutils. warning values, making them less reliable back ends for zutils.
LANGUAGE NOTE: Uncompressed = not compressed = plain data; it may never LANGUAGE NOTE: Uncompressed = not compressed = plain data; it may never
have been compressed. Decompressed is used to refer to data which has have been compressed. Decompressed is used to refer to data which has
@ -570,7 +570,8 @@ Show only the part of matching lines that actually matches @var{pattern}.
@item -q @item -q
@itemx --quiet @itemx --quiet
Suppress all messages. Suppress all messages. Exit immediately with zero status if any match is
found, even if an error was detected.
@item -r @item -r
@itemx --recursive @itemx --recursive
@ -578,7 +579,7 @@ Operate recursively on directories.
@item -s @item -s
@itemx --no-messages @itemx --no-messages
Suppress error messages. Suppress error messages about nonexistent or unreadable files.
@item -v @item -v
@itemx --invert-match @itemx --invert-match
@ -689,6 +690,10 @@ Do not skip a file for which a lzip compressed version already exists.
of the lzip file and deletes the input file if both contents are of the lzip file and deletes the input file if both contents are
identical. identical.
@item -k
@itemx --keep
Keep (don't delete) the input file after comparing it with the lzip file.
@item -l @item -l
@itemx --lzip-verbose @itemx --lzip-verbose
Pass a @samp{-v} option to the lzip compressor so that it shows the Pass a @samp{-v} option to the lzip compressor so that it shows the
@ -728,7 +733,7 @@ for all eternity, if not longer.
If you find a bug in zutils, please send electronic mail to If you find a bug in zutils, please send electronic mail to
@email{zutils-bug@@nongnu.org}. Include the version number, which you can @email{zutils-bug@@nongnu.org}. Include the version number, which you can
find by running @w{@samp{zutils --version}}. find by running @w{@samp{zcmp --version}}.
@node Concept index @node Concept index

467
main.cc
View file

@ -1,467 +0,0 @@
/* 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 <cerrno>
#include <climits>
#include <csignal>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <list>
#include <string>
#include <vector>
#include <dirent.h>
#include <fcntl.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/stat.h>
#if defined(__MSVCRT__) || defined(__OS2__)
#include <io.h>
#endif
#include "arg_parser.h"
#include "zutils.h"
#include "rc.h"
#if CHAR_BIT != 8
#error "Environments where CHAR_BIT != 8 are not supported."
#endif
namespace {
#ifdef O_BINARY
const int o_binary = O_BINARY;
#else
const int o_binary = 0;
#endif
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 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 );
std::printf( "\nOperations:\n"
" -h, --help display this help and exit\n"
" -V, --version output version information and exit\n"
" --zcat zcat operation\n"
" --zgrep zgrep operation\n"
" --ztest ztest operation\n" );
show_help_addr();
}
int simple_extension_index( const std::string & name )
{
for( int i = 0; i < num_formats; ++i )
{
const std::string ext( simple_extensions[i] );
if( name.size() > ext.size() &&
name.compare( name.size() - ext.size(), ext.size(), ext ) == 0 )
return i;
}
return -1;
}
int open_instream( std::string & input_filename, const Mode program_mode,
const bool search )
{
int infd = open( input_filename.c_str(), O_RDONLY | o_binary );
if( infd < 0 )
{
if( search && ( program_mode == m_zcat || program_mode == m_zgrep ) &&
simple_extension_index( input_filename ) < 0 )
{
for( int i = 0; i < num_formats; ++i )
{
const std::string name( input_filename +
simple_extensions[format_order[i]] );
infd = open( name.c_str(), O_RDONLY | o_binary );
if( infd >= 0 ) { input_filename = name; break; }
}
}
if( infd < 0 )
show_error2( "Can't open input file", input_filename.c_str() );
}
return infd;
}
#include "zcat.cc"
#include "zgrep.cc"
#include "ztest.cc"
} // end namespace
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_index = -1;
Mode program_mode = m_none;
bool recursive = false;
std::string input_filename;
std::list< std::string > filenames;
Cat_options cat_options;
std::vector< const char * > grep_args; // args to grep, maybe empty
std::vector< const char * > ztest_args; // args to ztest, maybe empty
invocation_name = argv[0];
const Arg_parser::Option m_zcat_options[] =
{
{ 'A', "show-all", Arg_parser::no }, // cat
{ 'b', "number-nonblank", Arg_parser::no }, // cat
{ 'c', "stdout", Arg_parser::no }, // gzip
{ 'd', "decompress", Arg_parser::no }, // gzip
{ 'e', 0, Arg_parser::no }, // cat
{ 'E', "show-ends", Arg_parser::no }, // cat
{ 'f', "force", Arg_parser::no }, // gzip
{ 'h', "help", Arg_parser::no },
{ '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
{ 't', 0, Arg_parser::no }, // cat
{ 'T', "show-tabs", Arg_parser::no }, // cat
{ 'v', "show-nonprinting", Arg_parser::no }, // cat
{ '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 } };
const Arg_parser::Option m_zgrep_options[] =
{
{ 'a', "text", Arg_parser::no }, // grep GNU
{ 'A', "after-context", Arg_parser::yes }, // grep GNU
{ 'b', "byte-offset", Arg_parser::no }, // grep GNU
{ 'B', "before-context", Arg_parser::yes }, // grep GNU
{ 'c', "count", Arg_parser::no }, // grep
{ 'C', "context", Arg_parser::yes }, // grep GNU
{ 'e', "regexp", Arg_parser::yes }, // grep
{ 'E', "extended-regexp", Arg_parser::no }, // grep
{ 'f', "file ", Arg_parser::yes }, // grep
{ 'F', "fixed-strings", Arg_parser::no }, // grep
{ 'h', "no-filename", Arg_parser::no }, // grep GNU
{ 'H', "with-filename", Arg_parser::no }, // grep GNU
{ 'i', "ignore-case", Arg_parser::no }, // grep
{ 'I', 0, Arg_parser::no }, // grep GNU
{ 'l', "files-with-matches", Arg_parser::no }, // grep
{ '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 },
{ 's', "no-messages", Arg_parser::no }, // grep
{ 'v', "invert-match", Arg_parser::no }, // grep
{ 'V', "version", Arg_parser::no },
{ 'w', "word-regexp", Arg_parser::no }, // grep GNU
{ 'x', "line-regexp", Arg_parser::no }, // grep
{ 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 } };
{ // parse operation
const Arg_parser::Option operations[] =
{
{ 'h', "help", Arg_parser::no },
{ 'V', "version", Arg_parser::no },
{ zcat_opt, "zcat", Arg_parser::no },
{ zgrep_opt, "zgrep", Arg_parser::no },
{ ztest_opt, "ztest", Arg_parser::no },
{ 0 , 0, Arg_parser::no } };
const Arg_parser parser( argv[1], ( argc > 2 ) ? argv[2] : 0, operations );
if( parser.error().size() ) // bad operation
{ show_error( parser.error().c_str(), 0, true ); return 1; }
if( parser.arguments() > 0 )
{
switch( parser.code( 0 ) )
{
case 0 : break;
case 'h': show_help(); return 0;
case 'V': show_version(); return 0;
case zcat_opt : program_mode = m_zcat; options = m_zcat_options;
util_name = "zcat"; break;
case zgrep_opt : program_mode = m_zgrep; options = m_zgrep_options;
util_name = "zgrep"; break;
case ztest_opt : program_mode = m_ztest; options = m_ztest_options;
util_name = "ztest"; break;
default : internal_error( "uncaught option" );
}
}
#if defined(__MSVCRT__) || defined(__OS2__)
setmode( STDIN_FILENO, O_BINARY );
setmode( STDOUT_FILENO, O_BINARY );
#endif
if( program_mode == m_none )
{
show_error( "You must specify the operation to be performed.", 0, true );
return 1;
}
} // 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 eretval; }
maybe_process_config_file( parser );
int argind = 0;
int grep_show_name = -1;
int grep_list_mode = 0; // 1 = list matches, -1 = list non matches
bool grep_pattern_found = false;
for( ; argind < parser.arguments(); ++argind )
{
const int code = parser.code( argind );
const char * const arg = parser.argument( argind ).c_str();
if( !code )
{
if( program_mode == m_zgrep && !grep_pattern_found )
{ grep_args.push_back( arg ); grep_pattern_found = true; continue; }
else break; // no more options
}
switch( code ) // common options
{
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 )
{
case m_none: internal_error( "invalid operation" ); break;
case m_zcat:
switch( code )
{
case 'A': cat_options.show_ends = true;
cat_options.show_nonprinting = true;
cat_options.show_tabs = true; break;
case 'b': cat_options.number_lines = 1; break;
case 'c': break;
case 'd': break;
case 'e': cat_options.show_nonprinting = true; // fall through
case 'E': cat_options.show_ends = true; break;
case 'f': break;
case 'h': show_zcat_help(); return 0;
case 'l': break;
case 'L': break;
case 'n': if( cat_options.number_lines == 0 )
{ cat_options.number_lines = 2; } break;
case 'q': verbosity = -1; break;
case 'r': recursive = true; break;
case 's': cat_options.squeeze_blank = true; break;
case 't': cat_options.show_nonprinting = true; // fall through
case 'T': cat_options.show_tabs = true; break;
case 'v': cat_options.show_nonprinting = true; break;
case 'V': show_version( "Zcat" ); return 0;
case verbose_opt : if( verbosity < 4 ) ++verbosity; break;
case zcat_opt : break;
default : internal_error( "uncaught option" );
} break;
case m_zgrep:
switch( code )
{
case 'a': grep_args.push_back( "-a" ); break;
case 'A': grep_args.push_back( "-A" ); grep_args.push_back( arg ); break;
case 'b': grep_args.push_back( "-b" ); break;
case 'B': grep_args.push_back( "-B" ); grep_args.push_back( arg ); break;
case 'c': grep_args.push_back( "-c" ); break;
case 'C': grep_args.push_back( "-C" ); grep_args.push_back( arg ); break;
case 'e': grep_args.push_back( "-e" ); grep_args.push_back( arg );
grep_pattern_found = true; break;
case 'E': grep_args.push_back( "-E" ); break;
case 'f': grep_args.push_back( "-f" ); grep_args.push_back( arg );
grep_pattern_found = true; break;
case 'F': grep_args.push_back( "-F" ); break;
case 'h': grep_show_name = false; break;
case 'H': grep_show_name = true; break;
case 'i': grep_args.push_back( "-i" ); break;
case 'I': grep_args.push_back( "-I" ); break;
case 'l': grep_args.push_back( "-l" ); grep_list_mode = 1; break;
case 'L': grep_args.push_back( "-L" ); grep_list_mode = -1; break;
case 'm': grep_args.push_back( "-m" ); grep_args.push_back( arg ); break;
case 'n': grep_args.push_back( "-n" ); break;
case 'o': grep_args.push_back( "-o" ); break;
case 'q': grep_args.push_back( "-q" ); verbosity = -1; break;
case 'r': recursive = true; break;
case 's': grep_args.push_back( "-s" ); verbosity = -1; break;
case 'v': grep_args.push_back( "-v" ); break;
case 'V': show_version( "Zgrep" ); return 0;
case 'w': grep_args.push_back( "-w" ); break;
case 'x': grep_args.push_back( "-x" ); break;
case help_opt : show_zgrep_help(); return 0;
case verbose_opt : if( verbosity < 4 ) ++verbosity; break;
case zgrep_opt : break;
default : internal_error( "uncaught option" );
} break;
case m_ztest:
switch( code )
{
case 'h': show_ztest_help(); return 0;
case 'q': verbosity = -1; ztest_args.push_back( "-q" ); break;
case 'r': recursive = true; break;
case 'v': if( verbosity < 4 ) ++verbosity;
ztest_args.push_back( "-v" ); break;
case 'V': show_version( "Ztest" ); return 0;
case ztest_opt : break;
default : internal_error( "uncaught option" );
} break;
}
} // end process options
if( program_mode == m_zgrep && !grep_pattern_found )
{ show_error( "Pattern not found." ); return 2; }
for( ; argind < parser.arguments(); ++argind )
filenames.push_back( parser.argument( argind ) );
if( filenames.empty() ) filenames.push_back("-");
if( grep_show_name < 0 )
grep_show_name = ( filenames.size() != 1 || recursive );
int retval = ( program_mode == m_zgrep ) ? 1 : 0;
while( !filenames.empty() )
{
input_filename = filenames.front();
filenames.pop_front();
if( !input_filename.size() || input_filename == "-" )
{
input_filename.clear();
infd = STDIN_FILENO;
}
else
{
if( recursive )
{
struct stat st;
if( stat( input_filename.c_str(), &st ) == 0 && S_ISDIR( st.st_mode ) )
{
DIR * const dirp = opendir( input_filename.c_str() );
if( !dirp )
{
show_error2( "Can't open directory", input_filename.c_str() );
if( retval < 1 ) retval = 1; continue;
}
std::list< std::string > tmp_list;
while( true )
{
const struct dirent * const entryp = readdir( dirp );
if( !entryp ) { closedir( dirp ); break; }
std::string tmp_name( entryp->d_name );
if( tmp_name != "." && tmp_name != ".." )
tmp_list.push_back( input_filename + "/" + tmp_name );
}
filenames.splice( filenames.begin(), tmp_list );
continue;
}
}
infd = open_instream( input_filename, program_mode, format_index < 0 );
if( infd < 0 ) { if( retval < 1 ) retval = 1; continue; }
}
int tmp = 0;
switch( program_mode )
{
case m_none:
break;
case m_zcat:
tmp = cat( infd, format_index, input_filename, cat_options );
break;
case m_zgrep:
if( infd == STDIN_FILENO )
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_index, ztest_args );
else tmp = ztest_file( infd, format_index, input_filename, ztest_args );
break;
}
if( program_mode == m_zgrep )
{ if( tmp == 0 || ( tmp == 2 && retval == 1 ) ) retval = tmp; }
else if( tmp > retval ) retval = tmp;
if( input_filename.size() )
{ close( infd ); infd = -1; }
}
if( std::fclose( stdout ) != 0 )
{
show_error( "Can't close stdout", errno );
switch( program_mode )
{
case m_none: break;
case m_zcat: retval = 1; break;
case m_zgrep: if( retval != 0 || verbosity >= 0 ) retval = 2; break;
case m_ztest: if( retval == 0 ) retval = 1; break;
}
}
return retval;
}

112
rc.cc
View file

@ -17,19 +17,28 @@
#define _FILE_OFFSET_BITS 64 #define _FILE_OFFSET_BITS 64
#include <cerrno>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <cstring>
#include <string> #include <string>
#include <vector> #include <vector>
#include <stdint.h> #include <unistd.h>
#include <sys/wait.h>
#include "arg_parser.h" #include "arg_parser.h"
#include "zutils.h"
#include "rc.h" #include "rc.h"
const char * invocation_name = 0;
const char * program_name = 0;
int verbosity = 0;
namespace { namespace {
const char * const config_file_name = "zutilsrc";
const char * const program_year = "2013";
std::string compressor_names[num_formats] = std::string compressor_names[num_formats] =
{ "bzip2", "gzip", "lzip", "xz" }; // default compressor names { "bzip2", "gzip", "lzip", "xz" }; // default compressor names
@ -227,3 +236,102 @@ const std::vector< std::string > & get_compressor_args( const int format_index )
{ {
return compressor_args[format_index]; return compressor_args[format_index];
} }
void show_help_addr()
{
std::printf( "\nReport bugs to zutils-bug@nongnu.org\n"
"Zutils home page: http://www.nongnu.org/zutils/zutils.html\n" );
}
void show_version( const char * const Program_name )
{
std::printf( "%s (zutils) %s\n", Program_name, PROGVERSION );
std::printf( "Copyright (C) %s Antonio Diaz Diaz.\n", program_year );
std::printf( "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n"
"This is free software: you are free to change and redistribute it.\n"
"There is NO WARRANTY, to the extent permitted by law.\n" );
}
void show_error( const char * const msg, const int errcode, const bool help )
{
if( verbosity >= 0 )
{
if( msg && msg[0] )
{
std::fprintf( stderr, "%s: %s", program_name, msg );
if( errcode > 0 )
std::fprintf( stderr, ": %s", std::strerror( errcode ) );
std::fprintf( stderr, "\n" );
}
if( help )
std::fprintf( stderr, "Try '%s --help' for more information.\n",
invocation_name );
}
}
void show_error2( const char * const msg, const char * const name )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: %s '%s': %s.\n",
program_name, msg, name, std::strerror( errno ) );
}
void internal_error( const char * const msg )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: internal error: %s.\n", program_name, msg );
std::exit( 3 );
}
void show_close_error( const char * const prog_name )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Can't close output of %s: %s.\n",
program_name, prog_name, std::strerror( errno ) );
}
void show_exec_error( const char * const prog_name )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Can't exec '%s': %s.\n",
program_name, prog_name, std::strerror( errno ) );
}
void show_fork_error( const char * const prog_name )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Can't fork '%s': %s.\n",
program_name, prog_name, std::strerror( errno ) );
}
int wait_for_child( const pid_t pid, const char * const name,
const int eretval, const bool isgzxz )
{
int status;
while( waitpid( pid, &status, 0 ) == -1 )
{
if( errno != EINTR )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Error waiting termination of '%s': %s.\n",
program_name, name, std::strerror( errno ) );
_exit( eretval );
}
}
if( WIFEXITED( status ) )
{
const int tmp = WEXITSTATUS( status );
if( isgzxz && eretval == 1 && tmp == 1 ) return 2; // for ztest
return tmp;
}
return eretval;
}

27
rc.h
View file

@ -15,6 +15,17 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
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 int format_order[num_formats] =
{ fmt_lz, fmt_bz2, fmt_gz, fmt_xz }; // search order
extern const char * invocation_name;
extern const char * program_name;
extern int verbosity;
class Arg_parser; class Arg_parser;
void maybe_process_config_file( const Arg_parser & parser ); void maybe_process_config_file( const Arg_parser & parser );
@ -23,5 +34,19 @@ void parse_compressor( const std::string & arg, const int format_index,
const int eretval = 2 ); const int eretval = 2 );
const char * get_compressor_name( const int format_index ); const char * get_compressor_name( const int format_index );
const std::vector< std::string > & get_compressor_args( const int format_index ); const std::vector< std::string > & get_compressor_args( const int format_index );
void show_help_addr();
void show_version( const char * const Program_name );
void show_error( const char * const msg, const int errcode = 0,
const bool help = false );
void show_error2( const char * const msg, const char * const name );
void internal_error( const char * const msg );
void show_close_error( const char * const prog_name = "data feeder" );
void show_exec_error( const char * const prog_name );
void show_fork_error( const char * const prog_name );
// Returns exit status of child process 'pid', or 'eretval' in case of error.
//
int wait_for_child( const pid_t pid, const char * const name,
const int eretval = 2, const bool isgzxz = false );

61
recursive.cc Normal file
View file

@ -0,0 +1,61 @@
/* 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/>.
*/
bool next_filename( std::list< std::string > & filenames,
std::string & input_filename, bool & error,
const bool recursive, const bool ignore_stdin = false,
const bool no_messages = false )
{
while( !filenames.empty() )
{
input_filename = filenames.front();
filenames.pop_front();
if( input_filename.empty() || input_filename == "-" )
{
if( ignore_stdin ) continue;
input_filename.clear(); return true;
}
if( recursive )
{
struct stat st;
if( stat( input_filename.c_str(), &st ) == 0 && S_ISDIR( st.st_mode ) )
{
DIR * const dirp = opendir( input_filename.c_str() );
if( !dirp )
{
if( !no_messages )
show_error2( "Can't open directory", input_filename.c_str() );
error = true; continue;
}
std::list< std::string > tmp_list;
while( true )
{
const struct dirent * const entryp = readdir( dirp );
if( !entryp ) { closedir( dirp ); break; }
std::string tmp_name( entryp->d_name );
if( tmp_name != "." && tmp_name != ".." )
tmp_list.push_back( input_filename + "/" + tmp_name );
}
filenames.splice( filenames.begin(), tmp_list );
continue;
}
}
return true;
}
input_filename.clear();
return false;
}

View file

@ -46,9 +46,7 @@ cat in.lz > lz_only.lz || framework_failure
cat in in in in in in > in6 || framework_failure cat in in in in in in > in6 || framework_failure
fail=0 fail=0
printf "testing zutils-%s..." "$2" printf "testing zcat-%s..." "$2"
printf "\ntesting zcat-%s..." "$2"
for i in ${extensions}; do for i in ${extensions}; do
"${ZCAT}" -N in.$i > copy || fail=1 "${ZCAT}" -N in.$i > copy || fail=1
@ -299,6 +297,8 @@ if [ $? != 0 ] ; then printf . ; else printf - ; fail=1 ; fi
if [ $? != 0 ] ; then printf . ; else printf - ; fail=1 ; fi if [ $? != 0 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZGREP}" -N --bad-option 2> /dev/null "${ZGREP}" -N --bad-option 2> /dev/null
if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZGREP}" -N "GNU" -s nx_file
if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
"${ZEGREP}" -N "GNU" in > /dev/null || fail=1 "${ZEGREP}" -N "GNU" in > /dev/null || fail=1
printf . printf .
@ -388,8 +388,8 @@ rm -f x.lz || framework_failure
cat in.bz2 > x.bz2 || framework_failure cat in.bz2 > x.bz2 || framework_failure
cat in.gz > x.gz || framework_failure cat in.gz > x.gz || framework_failure
"${ZUPDATE}" -N -f x.bz2 x.gz 2> /dev/null "${ZUPDATE}" -N -f -k x.bz2 x.gz 2> /dev/null
if [ $? = 0 ] && [ ! -e x.bz2 ] && [ ! -e x.gz ] && [ -e x.lz ] ; then printf . if [ $? = 0 ] && [ -e x.bz2 ] && [ -e x.gz ] && [ -e x.lz ] ; then printf .
else printf - ; fail=1 else printf - ; fail=1
fi fi
rm -f x.lz || framework_failure rm -f x.lz || framework_failure

198
zcat.cc
View file

@ -15,6 +15,39 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#define _FILE_OFFSET_BITS 64
#include <cerrno>
#include <climits>
#include <csignal>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <list>
#include <string>
#include <vector>
#include <dirent.h>
#include <fcntl.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/stat.h>
#if defined(__MSVCRT__) || defined(__OS2__)
#include <io.h>
#endif
#include "arg_parser.h"
#include "rc.h"
#include "zutils.h"
#ifndef O_BINARY
#define O_BINARY 0
#endif
namespace {
#include "recursive.cc"
struct Cat_options struct Cat_options
{ {
int number_lines; // 0 = no, 1 = nonblank, 2 = all int number_lines; // 0 = no, 1 = nonblank, 2 = all
@ -58,7 +91,7 @@ public:
Line_number line_number; Line_number line_number;
void show_zcat_help() void show_help()
{ {
std::printf( "Zcat copies each given file (\"-\" means standard input), to standard\n" std::printf( "Zcat copies each given file (\"-\" means standard input), to standard\n"
"output. If any given file is compressed, its decompressed content is\n" "output. If any given file is compressed, its decompressed content is\n"
@ -96,6 +129,41 @@ void show_zcat_help()
} }
int simple_extension_index( const std::string & name )
{
for( int i = 0; i < num_formats; ++i )
{
const std::string ext( simple_extensions[i] );
if( name.size() > ext.size() &&
name.compare( name.size() - ext.size(), ext.size(), ext ) == 0 )
return i;
}
return -1;
}
int open_instream( std::string & input_filename, const bool search )
{
int infd = open( input_filename.c_str(), O_RDONLY | O_BINARY );
if( infd < 0 )
{
if( search && simple_extension_index( input_filename ) < 0 )
{
for( int i = 0; i < num_formats; ++i )
{
const std::string name( input_filename +
simple_extensions[format_order[i]] );
infd = open( name.c_str(), O_RDONLY | O_BINARY );
if( infd >= 0 ) { input_filename = name; break; }
}
}
if( infd < 0 )
show_error2( "Can't open input file", input_filename.c_str() );
}
return infd;
}
int do_cat( const int infd, const int buffer_size, int do_cat( const int infd, const int buffer_size,
uint8_t * const inbuf, uint8_t * const outbuf, uint8_t * const inbuf, uint8_t * const outbuf,
const std::string & input_filename, const std::string & input_filename,
@ -210,7 +278,133 @@ int cat( int infd, const int format_index, const std::string & input_filename,
if( !good_status( children, retval == 0 ) ) retval = 1; if( !good_status( children, retval == 0 ) ) retval = 1;
if( retval == 0 && close( infd ) != 0 ) if( retval == 0 && close( infd ) != 0 )
{ show_close_error( "data feeder" ); retval = 1; } { show_close_error(); retval = 1; }
delete[] outbuf; delete[] inbuf; delete[] outbuf; delete[] inbuf;
return retval; return retval;
} }
} // end namespace
int main( const int argc, const char * const argv[] )
{
enum { format_opt = 256, verbose_opt, bz2_opt, gz_opt, lz_opt, xz_opt };
int infd = -1;
int format_index = -1;
bool recursive = false;
std::string input_filename;
std::list< std::string > filenames;
Cat_options cat_options;
invocation_name = argv[0];
program_name = "zcat";
const Arg_parser::Option options[] =
{
{ 'A', "show-all", Arg_parser::no }, // cat
{ 'b', "number-nonblank", Arg_parser::no }, // cat
{ 'c', "stdout", Arg_parser::no }, // gzip
{ 'd', "decompress", Arg_parser::no }, // gzip
{ 'e', 0, Arg_parser::no }, // cat
{ 'E', "show-ends", Arg_parser::no }, // cat
{ 'f', "force", Arg_parser::no }, // gzip
{ 'h', "help", Arg_parser::no },
{ '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
{ 't', 0, Arg_parser::no }, // cat
{ 'T', "show-tabs", Arg_parser::no }, // cat
{ 'v', "show-nonprinting", Arg_parser::no }, // cat
{ '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 },
{ 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 1; }
maybe_process_config_file( parser );
int argind = 0;
for( ; argind < parser.arguments(); ++argind )
{
const int code = parser.code( argind );
if( !code ) break; // no more options
const char * const arg = parser.argument( argind ).c_str();
switch( code )
{
case 'A': cat_options.show_ends = true;
cat_options.show_nonprinting = true;
cat_options.show_tabs = true; break;
case 'b': cat_options.number_lines = 1; break;
case 'c': break;
case 'd': break;
case 'e': cat_options.show_nonprinting = true; // fall through
case 'E': cat_options.show_ends = true; break;
case 'f': break;
case 'h': show_help(); return 0;
case 'l': break;
case 'L': break;
case 'n': if( cat_options.number_lines == 0 )
{ cat_options.number_lines = 2; } break;
case 'N': break;
case 'q': verbosity = -1; break;
case 'r': recursive = true; break;
case 's': cat_options.squeeze_blank = true; break;
case 't': cat_options.show_nonprinting = true; // fall through
case 'T': cat_options.show_tabs = true; break;
case 'v': cat_options.show_nonprinting = true; break;
case 'V': show_version( "Zcat" ); return 0;
case format_opt: format_index = parse_format_type( arg ); break;
case verbose_opt: if( verbosity < 4 ) ++verbosity; break;
case bz2_opt: parse_compressor( arg, fmt_bz2, 1 ); break;
case gz_opt: parse_compressor( arg, fmt_gz, 1 ); break;
case lz_opt: parse_compressor( arg, fmt_lz, 1 ); break;
case xz_opt: parse_compressor( arg, fmt_xz, 1 ); break;
default : internal_error( "uncaught option" );
}
} // end process options
#if defined(__MSVCRT__) || defined(__OS2__)
setmode( STDIN_FILENO, O_BINARY );
setmode( STDOUT_FILENO, O_BINARY );
#endif
for( ; argind < parser.arguments(); ++argind )
filenames.push_back( parser.argument( argind ) );
if( filenames.empty() ) filenames.push_back("-");
int retval = 0;
bool error = false;
while( next_filename( filenames, input_filename, error, recursive ) )
{
if( input_filename.empty() ) infd = STDIN_FILENO;
else
{
infd = open_instream( input_filename, format_index < 0 );
if( infd < 0 ) { error = true; continue; }
}
const int tmp = cat( infd, format_index, input_filename, cat_options );
if( tmp > retval ) retval = tmp;
if( input_filename.size() ) { close( infd ); infd = -1; }
}
if( std::fclose( stdout ) != 0 )
{
show_error( "Can't close stdout", errno );
error = true;
}
if( error && retval == 0 ) retval = 1;
return retval;
}

View file

@ -1,3 +0,0 @@
#! /bin/sh
bindir=`echo "$0" | sed -e 's,[^/]*$,,'`
exec "${bindir}"zutils --zcat "$@"

13
zcmp.cc
View file

@ -36,12 +36,8 @@
#endif #endif
#include "arg_parser.h" #include "arg_parser.h"
#include "zutils.h"
#include "rc.h" #include "rc.h"
#include "zutils.h"
#if CHAR_BIT != 8
#error "Environments where CHAR_BIT != 8 are not supported."
#endif
#ifndef LLONG_MAX #ifndef LLONG_MAX
#define LLONG_MAX 0x7FFFFFFFFFFFFFFFLL #define LLONG_MAX 0x7FFFFFFFFFFFFFFFLL
@ -52,7 +48,6 @@ namespace {
#include "zcmpdiff.cc" #include "zcmpdiff.cc"
void show_help() void show_help()
{ {
std::printf( "Zcmp compares two files (\"-\" means standard input), and if they\n" std::printf( "Zcmp compares two files (\"-\" means standard input), and if they\n"
@ -301,7 +296,7 @@ int cmp( const long long max_size, const int infd[2],
{ {
if( verbosity >= 0 ) if( verbosity >= 0 )
std::fprintf( stderr, "%s: EOF on %s\n", std::fprintf( stderr, "%s: EOF on %s\n",
util_name, filenames[rd[1]<rd[0]].c_str() ); program_name, filenames[rd[1]<rd[0]].c_str() );
return 1; return 1;
} }
if( min_rd != buffer_size ) break; if( min_rd != buffer_size ) break;
@ -323,7 +318,7 @@ int main( const int argc, const char * const argv[] )
int format_types[2] = { -1, -1 }; int format_types[2] = { -1, -1 };
bool print_bytes = false; bool print_bytes = false;
invocation_name = argv[0]; invocation_name = argv[0];
util_name = "zcmp"; program_name = "zcmp";
const Arg_parser::Option options[] = const Arg_parser::Option options[] =
{ {
@ -443,7 +438,7 @@ int main( const int argc, const char * const argv[] )
for( int i = 0; i < 2; ++i ) for( int i = 0; i < 2; ++i )
{ {
if( close( infd[i] ) != 0 ) if( close( infd[i] ) != 0 )
{ show_close_error( "data feeder" ); retval = 2; } { show_close_error(); retval = 2; }
if( filenames[i] != "-" && close( old_infd[i] ) != 0 ) if( filenames[i] != "-" && close( old_infd[i] ) != 0 )
{ {
show_error2( "Can't close input file", filenames[i].c_str() ); show_error2( "Can't close input file", filenames[i].c_str() );

View file

@ -15,10 +15,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifdef O_BINARY #ifndef O_BINARY
const int o_binary = O_BINARY; #define O_BINARY 0
#else
const int o_binary = 0;
#endif #endif
struct { const char * from; const char * to; } const known_extensions[] = { struct { const char * from; const char * to; } const known_extensions[] = {
@ -36,7 +34,7 @@ struct { const char * from; const char * to; } const known_extensions[] = {
int open_instream( const std::string & input_filename ) int open_instream( const std::string & input_filename )
{ {
int infd = open( input_filename.c_str(), O_RDONLY | o_binary ); int infd = open( input_filename.c_str(), O_RDONLY | O_BINARY );
if( infd < 0 ) if( infd < 0 )
show_error2( "Can't open input file", input_filename.c_str() ); show_error2( "Can't open input file", input_filename.c_str() );
return infd; return infd;
@ -53,13 +51,13 @@ int open_other_instream( std::string & name )
{ {
name.resize( name.size() - from.size() ); name.resize( name.size() - from.size() );
name += known_extensions[i].to; name += known_extensions[i].to;
return open( name.c_str(), O_RDONLY | o_binary ); return open( name.c_str(), O_RDONLY | O_BINARY );
} }
} }
for( int i = 0; i < num_formats; ++i ) for( int i = 0; i < num_formats; ++i )
{ // search compressed version { // search compressed version
const std::string s( name + simple_extensions[format_order[i]] ); const std::string s( name + simple_extensions[format_order[i]] );
const int infd = open( s.c_str(), O_RDONLY | o_binary ); const int infd = open( s.c_str(), O_RDONLY | O_BINARY );
if( infd >= 0 ) { name = s; return infd; } if( infd >= 0 ) { name = s; return infd; }
} }
return -1; return -1;

View file

@ -36,12 +36,8 @@
#endif #endif
#include "arg_parser.h" #include "arg_parser.h"
#include "zutils.h"
#include "rc.h" #include "rc.h"
#include "zutils.h"
#if CHAR_BIT != 8
#error "Environments where CHAR_BIT != 8 are not supported."
#endif
namespace { namespace {
@ -50,7 +46,6 @@ std::string fifonames[2]; // names of the two fifos passed to diff
#include "zcmpdiff.cc" #include "zcmpdiff.cc"
void show_help() void show_help()
{ {
std::printf( "Zdiff compares two files (\"-\" means standard input), and if they\n" std::printf( "Zdiff compares two files (\"-\" means standard input), and if they\n"
@ -177,7 +172,7 @@ bool set_data_feeder( const std::string & fifoname, const int infd,
!feed_data( infd, fda[1], magic_data, magic_size ) ) !feed_data( infd, fda[1], magic_data, magic_size ) )
_exit( 2 ); _exit( 2 );
if( close( fda[1] ) != 0 ) if( close( fda[1] ) != 0 )
{ show_close_error( "data feeder" ); _exit( 2 ); } { show_close_error(); _exit( 2 ); }
_exit( 0 ); _exit( 0 );
} }
if( pid < 0 ) // parent if( pid < 0 ) // parent
@ -186,12 +181,12 @@ bool set_data_feeder( const std::string & fifoname, const int infd,
const pid_t pid2 = fork(); const pid_t pid2 = fork();
if( pid2 == 0 ) // child 2 (compressor) if( pid2 == 0 ) // child 2 (compressor)
{ {
const int outfd = open( fifoname.c_str(), O_WRONLY | o_binary ); const int outfd = open( fifoname.c_str(), O_WRONLY | O_BINARY );
if( outfd < 0 ) if( outfd < 0 )
{ {
if( verbosity >= 0 ) if( verbosity >= 0 )
std::fprintf( stderr, "%s: Can't open FIFO '%s' for writing: %s.\n", std::fprintf( stderr, "%s: Can't open FIFO '%s' for writing: %s.\n",
util_name, fifoname.c_str(), std::strerror( errno ) ); program_name, fifoname.c_str(), std::strerror( errno ) );
_exit( 2 ); _exit( 2 );
} }
if( dup2( fda[0], STDIN_FILENO ) >= 0 && if( dup2( fda[0], STDIN_FILENO ) >= 0 &&
@ -225,18 +220,18 @@ bool set_data_feeder( const std::string & fifoname, const int infd,
const pid_t pid = fork(); const pid_t pid = fork();
if( pid == 0 ) // child (feeder) if( pid == 0 ) // child (feeder)
{ {
const int outfd = open( fifoname.c_str(), O_WRONLY | o_binary ); const int outfd = open( fifoname.c_str(), O_WRONLY | O_BINARY );
if( outfd < 0 ) if( outfd < 0 )
{ {
if( verbosity >= 0 ) if( verbosity >= 0 )
std::fprintf( stderr, "%s: Can't open FIFO '%s' for writing: %s.\n", std::fprintf( stderr, "%s: Can't open FIFO '%s' for writing: %s.\n",
util_name, fifoname.c_str(), std::strerror( errno ) ); program_name, fifoname.c_str(), std::strerror( errno ) );
_exit( 2 ); _exit( 2 );
} }
if( !feed_data( infd, outfd, magic_data, magic_size ) ) if( !feed_data( infd, outfd, magic_data, magic_size ) )
_exit( 2 ); _exit( 2 );
if( close( outfd ) != 0 ) if( close( outfd ) != 0 )
{ show_close_error( "data feeder" ); _exit( 2 ); } { show_close_error(); _exit( 2 ); }
_exit( 0 ); _exit( 0 );
} }
if( pid < 0 ) // parent if( pid < 0 ) // parent
@ -272,7 +267,7 @@ int main( const int argc, const char * const argv[] )
std::vector< const char * > diff_args; // args to diff, maybe empty std::vector< const char * > diff_args; // args to diff, maybe empty
int format_types[2] = { -1, -1 }; int format_types[2] = { -1, -1 };
invocation_name = argv[0]; invocation_name = argv[0];
util_name = "zdiff"; program_name = "zdiff";
const Arg_parser::Option options[] = const Arg_parser::Option options[] =
{ {

View file

@ -1,3 +1,3 @@
#! /bin/sh #! /bin/sh
bindir=`echo "$0" | sed -e 's,[^/]*$,,'` bindir=`echo "$0" | sed -e 's,[^/]*$,,'`
exec "${bindir}"zutils --zgrep -E "$@" exec "${bindir}"zgrep -E "$@"

View file

@ -1,3 +1,3 @@
#! /bin/sh #! /bin/sh
bindir=`echo "$0" | sed -e 's,[^/]*$,,'` bindir=`echo "$0" | sed -e 's,[^/]*$,,'`
exec "${bindir}"zutils --zgrep -F "$@" exec "${bindir}"zgrep -F "$@"

247
zgrep.cc
View file

@ -15,7 +15,40 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
void show_zgrep_help() #define _FILE_OFFSET_BITS 64
#include <cerrno>
#include <climits>
#include <csignal>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <list>
#include <string>
#include <vector>
#include <dirent.h>
#include <fcntl.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/stat.h>
#if defined(__MSVCRT__) || defined(__OS2__)
#include <io.h>
#endif
#include "arg_parser.h"
#include "rc.h"
#include "zutils.h"
#ifndef O_BINARY
#define O_BINARY 0
#endif
namespace {
#include "recursive.cc"
void show_help()
{ {
std::printf( "Zgrep is a front end to the grep program that allows transparent search\n" std::printf( "Zgrep is a front end to the grep program that allows transparent search\n"
"on any combination of compressed and uncompressed files. If any given\n" "on any combination of compressed and uncompressed files. If any given\n"
@ -68,6 +101,42 @@ void show_zgrep_help()
} }
int simple_extension_index( const std::string & name )
{
for( int i = 0; i < num_formats; ++i )
{
const std::string ext( simple_extensions[i] );
if( name.size() > ext.size() &&
name.compare( name.size() - ext.size(), ext.size(), ext ) == 0 )
return i;
}
return -1;
}
int open_instream( std::string & input_filename,
const bool no_messages, const bool search )
{
int infd = open( input_filename.c_str(), O_RDONLY | O_BINARY );
if( infd < 0 )
{
if( search && simple_extension_index( input_filename ) < 0 )
{
for( int i = 0; i < num_formats; ++i )
{
const std::string name( input_filename +
simple_extensions[format_order[i]] );
infd = open( name.c_str(), O_RDONLY | O_BINARY );
if( infd >= 0 ) { input_filename = name; break; }
}
}
if( infd < 0 && !no_messages )
show_error2( "Can't open input file", input_filename.c_str() );
}
return infd;
}
int zgrep_stdin( int infd, const int format_index, int zgrep_stdin( int infd, const int format_index,
const std::vector< const char * > & grep_args ) const std::vector< const char * > & grep_args )
{ {
@ -96,7 +165,7 @@ int zgrep_stdin( int infd, const int format_index,
if( !good_status( children, retval == 1 ) ) retval = 2; if( !good_status( children, retval == 1 ) ) retval = 2;
if( close( infd ) != 0 ) if( close( infd ) != 0 )
{ show_close_error( "data feeder" ); return 2; } { show_close_error(); return 2; }
return retval; return retval;
} }
@ -104,7 +173,7 @@ int zgrep_stdin( int infd, const int format_index,
int zgrep_file( int infd, const int format_index, int zgrep_file( int infd, const int format_index,
const std::string & input_filename, const std::string & input_filename,
const std::vector< const char * > & grep_args, const std::vector< const char * > & grep_args,
const int grep_list_mode, const bool grep_show_name ) const int list_mode, const bool show_name )
{ {
Children children; Children children;
if( !set_data_feeder( &infd, children, format_index ) ) return 2; if( !set_data_feeder( &infd, children, format_index ) ) return 2;
@ -140,9 +209,9 @@ int zgrep_file( int infd, const int format_index,
const int size = readblock( fda[0], buffer, buffer_size ); const int size = readblock( fda[0], buffer, buffer_size );
if( size != buffer_size && errno ) if( size != buffer_size && errno )
{ show_error( "Read error", errno ); return 2; } { show_error( "Read error", errno ); return 2; }
if( size > 0 && !grep_list_mode ) if( size > 0 && !list_mode )
{ {
if( grep_show_name ) if( show_name )
for( int i = 0; i < size; ++i ) for( int i = 0; i < size; ++i )
{ {
if( line_begin ) if( line_begin )
@ -160,11 +229,175 @@ int zgrep_file( int infd, const int format_index,
if( !good_status( children, retval == 1 ) ) retval = 2; if( !good_status( children, retval == 1 ) ) retval = 2;
if( grep_list_mode && (retval == 0) == (grep_list_mode == 1) ) if( list_mode && (retval == 0) == (list_mode == 1) )
std::printf( "%s\n", input_filename.c_str() ); std::printf( "%s\n", input_filename.c_str() );
if( close( infd ) != 0 ) if( close( infd ) != 0 )
{ show_close_error( "data feeder" ); return 2; } { show_close_error(); return 2; }
if( close( fda[0] ) != 0 ) if( close( fda[0] ) != 0 )
{ show_close_error( GREP ); return 2; } { show_close_error( GREP ); return 2; }
return retval; return retval;
} }
} // end namespace
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 };
int format_index = -1;
int infd = -1;
int list_mode = 0; // 1 = list matches, -1 = list non matches
int show_name = -1; // tri-state bool
bool error = false;
bool no_messages = false;
bool recursive = false;
std::string input_filename;
std::list< std::string > filenames;
std::vector< const char * > grep_args; // args to grep, maybe empty
invocation_name = argv[0];
program_name = "zgrep";
const Arg_parser::Option options[] =
{
{ 'a', "text", Arg_parser::no }, // grep GNU
{ 'A', "after-context", Arg_parser::yes }, // grep GNU
{ 'b', "byte-offset", Arg_parser::no }, // grep GNU
{ 'B', "before-context", Arg_parser::yes }, // grep GNU
{ 'c', "count", Arg_parser::no }, // grep
{ 'C', "context", Arg_parser::yes }, // grep GNU
{ 'e', "regexp", Arg_parser::yes }, // grep
{ 'E', "extended-regexp", Arg_parser::no }, // grep
{ 'f', "file ", Arg_parser::yes }, // grep
{ 'F', "fixed-strings", Arg_parser::no }, // grep
{ 'h', "no-filename", Arg_parser::no }, // grep GNU
{ 'H', "with-filename", Arg_parser::no }, // grep GNU
{ 'i', "ignore-case", Arg_parser::no }, // grep
{ 'I', 0, Arg_parser::no }, // grep GNU
{ 'l', "files-with-matches", Arg_parser::no }, // grep
{ '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 },
{ 's', "no-messages", Arg_parser::no }, // grep
{ 'v', "invert-match", Arg_parser::no }, // grep
{ 'V', "version", Arg_parser::no },
{ 'w', "word-regexp", Arg_parser::no }, // grep GNU
{ 'x', "line-regexp", Arg_parser::no }, // grep
{ 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 },
{ 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;
bool pattern_found = false;
for( ; argind < parser.arguments(); ++argind )
{
const int code = parser.code( argind );
const char * const arg = parser.argument( argind ).c_str();
if( !code )
{
if( !pattern_found )
{ grep_args.push_back( arg ); pattern_found = true; continue; }
else break; // no more options
}
switch( code )
{
case 'a': grep_args.push_back( "-a" ); break;
case 'A': grep_args.push_back( "-A" ); grep_args.push_back( arg ); break;
case 'b': grep_args.push_back( "-b" ); break;
case 'B': grep_args.push_back( "-B" ); grep_args.push_back( arg ); break;
case 'c': grep_args.push_back( "-c" ); break;
case 'C': grep_args.push_back( "-C" ); grep_args.push_back( arg ); break;
case 'e': grep_args.push_back( "-e" ); grep_args.push_back( arg );
pattern_found = true; break;
case 'E': grep_args.push_back( "-E" ); break;
case 'f': grep_args.push_back( "-f" ); grep_args.push_back( arg );
pattern_found = true; break;
case 'F': grep_args.push_back( "-F" ); break;
case 'h': show_name = false; break;
case 'H': show_name = true; break;
case 'i': grep_args.push_back( "-i" ); break;
case 'I': grep_args.push_back( "-I" ); break;
case 'l': grep_args.push_back( "-l" ); list_mode = 1; break;
case 'L': grep_args.push_back( "-L" ); list_mode = -1; break;
case 'm': grep_args.push_back( "-m" ); grep_args.push_back( arg ); break;
case 'n': grep_args.push_back( "-n" ); break;
case 'N': break;
case 'o': grep_args.push_back( "-o" ); break;
case 'q': grep_args.push_back( "-q" ); verbosity = -1; break;
case 'r': recursive = true; break;
case 's': grep_args.push_back( "-s" ); no_messages = true; break;
case 'v': grep_args.push_back( "-v" ); break;
case 'V': show_version( "Zgrep" ); return 0;
case 'w': grep_args.push_back( "-w" ); break;
case 'x': grep_args.push_back( "-x" ); break;
case format_opt : format_index = parse_format_type( arg ); break;
case help_opt : show_help(); return 0;
case verbose_opt: if( verbosity < 4 ) ++verbosity;
no_messages = false; 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
#if defined(__MSVCRT__) || defined(__OS2__)
setmode( STDIN_FILENO, O_BINARY );
setmode( STDOUT_FILENO, O_BINARY );
#endif
if( !pattern_found ) { show_error( "Pattern not found." ); return 2; }
for( ; argind < parser.arguments(); ++argind )
filenames.push_back( parser.argument( argind ) );
if( filenames.empty() ) filenames.push_back("-");
if( show_name < 0 ) show_name = ( filenames.size() != 1 || recursive );
int retval = 1;
while( next_filename( filenames, input_filename, error, recursive,
false, no_messages ) )
{
if( input_filename.empty() ) infd = STDIN_FILENO;
else
{
infd = open_instream( input_filename, no_messages, format_index < 0 );
if( infd < 0 ) { error = true; continue; }
}
int tmp;
if( infd == STDIN_FILENO )
tmp = zgrep_stdin( infd, format_index, grep_args );
else tmp = zgrep_file( infd, format_index, input_filename, grep_args,
list_mode, show_name );
if( tmp == 0 || ( tmp == 2 && retval == 1 ) ) retval = tmp;
if( input_filename.size() ) { close( infd ); infd = -1; }
if( retval == 0 && verbosity < 0 ) break;
}
if( std::fclose( stdout ) != 0 )
{
show_error( "Can't close stdout", errno );
error = true;
}
if( error && ( retval != 0 || verbosity >= 0 ) ) retval = 2;
return retval;
}

View file

@ -1,3 +0,0 @@
#! /bin/sh
bindir=`echo "$0" | sed -e 's,[^/]*$,,'`
exec "${bindir}"zutils --zgrep "$@"

145
ztest.cc
View file

@ -15,7 +15,40 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
void show_ztest_help() #define _FILE_OFFSET_BITS 64
#include <cerrno>
#include <climits>
#include <csignal>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <list>
#include <string>
#include <vector>
#include <dirent.h>
#include <fcntl.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/stat.h>
#if defined(__MSVCRT__) || defined(__OS2__)
#include <io.h>
#endif
#include "arg_parser.h"
#include "rc.h"
#include "zutils.h"
#ifndef O_BINARY
#define O_BINARY 0
#endif
namespace {
#include "recursive.cc"
void show_help()
{ {
std::printf( "Ztest verifies the integrity of the specified compressed files.\n" std::printf( "Ztest verifies the integrity of the specified compressed files.\n"
"Uncompressed files are ignored. If no files are specified, the integrity\n" "Uncompressed files are ignored. If no files are specified, the integrity\n"
@ -44,6 +77,15 @@ void show_ztest_help()
} }
int open_instream( std::string & input_filename )
{
int infd = open( input_filename.c_str(), O_RDONLY | O_BINARY );
if( infd < 0 )
show_error2( "Can't open input file", input_filename.c_str() );
return infd;
}
int ztest_stdin( const int infd, int format_index, int ztest_stdin( const int infd, int format_index,
const std::vector< const char * > & ztest_args ) const std::vector< const char * > & ztest_args )
{ {
@ -65,7 +107,7 @@ int ztest_stdin( const int infd, int format_index,
!feed_data( infd, fda[1], magic_data, magic_size ) ) !feed_data( infd, fda[1], magic_data, magic_size ) )
_exit( 1 ); _exit( 1 );
if( close( fda[1] ) != 0 ) if( close( fda[1] ) != 0 )
{ show_close_error( "data feeder" ); _exit( 1 ); } { show_close_error(); _exit( 1 ); }
_exit( 0 ); _exit( 0 );
} }
if( pid < 0 ) // parent if( pid < 0 ) // parent
@ -145,3 +187,102 @@ int ztest_file( const int infd, int format_index,
const bool isgzxz = ( format_index == fmt_gz || format_index == fmt_xz ); const bool isgzxz = ( format_index == fmt_gz || format_index == fmt_xz );
return wait_for_child( pid, compressor_name, 1, isgzxz ); return wait_for_child( pid, compressor_name, 1, isgzxz );
} }
} // end namespace
int main( const int argc, const char * const argv[] )
{
enum { format_opt = 256, bz2_opt, gz_opt, lz_opt, xz_opt };
int infd = -1;
int format_index = -1;
bool recursive = false;
std::string input_filename;
std::list< std::string > filenames;
std::vector< const char * > ztest_args; // args to ztest, maybe empty
invocation_name = argv[0];
program_name = "ztest";
const Arg_parser::Option 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 },
{ 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 1; }
maybe_process_config_file( parser );
int argind = 0;
for( ; argind < parser.arguments(); ++argind )
{
const int code = parser.code( argind );
if( !code ) break; // no more options
const char * const arg = parser.argument( argind ).c_str();
switch( code )
{
case 'h': show_help(); return 0;
case 'N': break;
case 'q': verbosity = -1; ztest_args.push_back( "-q" ); break;
case 'r': recursive = true; break;
case 'v': if( verbosity < 4 ) ++verbosity;
ztest_args.push_back( "-v" ); break;
case 'V': show_version( "Ztest" ); return 0;
case format_opt: format_index = parse_format_type( arg ); break;
case bz2_opt: parse_compressor( arg, fmt_bz2, 1 ); break;
case gz_opt: parse_compressor( arg, fmt_gz, 1 ); break;
case lz_opt: parse_compressor( arg, fmt_lz, 1 ); break;
case xz_opt: parse_compressor( arg, fmt_xz, 1 ); break;
default : internal_error( "uncaught option" );
}
} // end process options
#if defined(__MSVCRT__) || defined(__OS2__)
setmode( STDIN_FILENO, O_BINARY );
setmode( STDOUT_FILENO, O_BINARY );
#endif
for( ; argind < parser.arguments(); ++argind )
filenames.push_back( parser.argument( argind ) );
if( filenames.empty() ) filenames.push_back("-");
int retval = 0;
bool error = false;
while( next_filename( filenames, input_filename, error, recursive ) )
{
if( input_filename.empty() ) infd = STDIN_FILENO;
else
{
infd = open_instream( input_filename );
if( infd < 0 ) { error = true; continue; }
}
int tmp;
if( infd == STDIN_FILENO )
tmp = ztest_stdin( infd, format_index, ztest_args );
else tmp = ztest_file( infd, format_index, input_filename, ztest_args );
if( tmp > retval ) retval = tmp;
if( input_filename.size() ) { close( infd ); infd = -1; }
}
if( std::fclose( stdout ) != 0 )
{
show_error( "Can't close stdout", errno );
error = true;
}
if( error && retval == 0 ) retval = 1;
return retval;
}

View file

@ -1,3 +0,0 @@
#! /bin/sh
bindir=`echo "$0" | sed -e 's,[^/]*$,,'`
exec "${bindir}"zutils --ztest "$@"

View file

@ -37,24 +37,18 @@
#endif #endif
#include "arg_parser.h" #include "arg_parser.h"
#include "zutils.h"
#include "rc.h" #include "rc.h"
#if CHAR_BIT != 8 #ifndef O_BINARY
#error "Environments where CHAR_BIT != 8 are not supported." #define O_BINARY 0
#endif #endif
namespace { namespace {
#ifdef O_BINARY #include "recursive.cc"
const int o_binary = O_BINARY;
#else
const int o_binary = 0;
#endif
void show_help()
void show_zupdate_help()
{ {
std::printf( "Zupdate recompresses files from bzip2, gzip, and xz formats to lzip format.\n" std::printf( "Zupdate recompresses files from bzip2, gzip, and xz formats to lzip format.\n"
"The originals are compared with the new files and then deleted.\n" "The originals are compared with the new files and then deleted.\n"
@ -77,6 +71,7 @@ void show_zupdate_help()
" -h, --help display this help and exit\n" " -h, --help display this help and exit\n"
" -V, --version output version information and exit\n" " -V, --version output version information and exit\n"
" -f, --force do not skip a file even if the .lz exists\n" " -f, --force do not skip a file even if the .lz exists\n"
" -k, --keep keep (don't delete) input files\n"
" -l, --lzip-verbose pass a -v option to the lzip compressor\n" " -l, --lzip-verbose pass a -v option to the lzip compressor\n"
" -N, --no-rcfile don't read runtime configuration file\n" " -N, --no-rcfile don't read runtime configuration file\n"
" -q, --quiet suppress all messages\n" " -q, --quiet suppress all messages\n"
@ -97,10 +92,10 @@ int cant_execute( const std::string & command, const int status )
{ {
if( WIFEXITED( status ) ) if( WIFEXITED( status ) )
std::fprintf( stderr, "%s: Error executing '%s'. Exit status = %d.\n", std::fprintf( stderr, "%s: Error executing '%s'. Exit status = %d.\n",
util_name, command.c_str(), WEXITSTATUS( status ) ); program_name, command.c_str(), WEXITSTATUS( status ) );
else else
std::fprintf( stderr, "%s: Can't execute '%s'.\n", std::fprintf( stderr, "%s: Can't execute '%s'.\n",
util_name, command.c_str() ); program_name, command.c_str() );
} }
return 1; return 1;
} }
@ -136,11 +131,13 @@ struct { const char * from; const char * to; int format_index; } const
{ ".txz", ".tar", fmt_xz }, { ".txz", ".tar", fmt_xz },
{ 0, 0, -1 } }; { 0, 0, -1 } };
int disable_xz = -1; // tri-state bool
// Returns 0 for success, -1 for file skipped, 1 for error. // Returns 0 for success, -1 for file skipped, 1 for error.
int zupdate_file( const std::string & name, const char * const lzip_name, int zupdate_file( const std::string & name, const char * const lzip_name,
const std::vector< std::string > & lzip_args2, const std::vector< std::string > & lzip_args2,
const bool force ) const bool force, const bool keep_input_files )
{ {
int format_index = -1; int format_index = -1;
std::string dname; // decompressed_name std::string dname; // decompressed_name
@ -158,7 +155,7 @@ int zupdate_file( const std::string & name, const char * const lzip_name,
{ {
if( verbosity >= 2 ) if( verbosity >= 2 )
std::fprintf( stderr, "%s: Input file '%s' already has '%s' suffix.\n", std::fprintf( stderr, "%s: Input file '%s' already has '%s' suffix.\n",
util_name, name.c_str(), known_extensions[i].from ); program_name, name.c_str(), known_extensions[i].from );
return 0; // ignore this file return 0; // ignore this file
} }
break; break;
@ -169,7 +166,7 @@ int zupdate_file( const std::string & name, const char * const lzip_name,
{ {
if( verbosity >= 2 ) if( verbosity >= 2 )
std::fprintf( stderr, "%s: Unknown extension in file name '%s' -- ignored.\n", std::fprintf( stderr, "%s: Unknown extension in file name '%s' -- ignored.\n",
util_name, name.c_str() ); program_name, name.c_str() );
return 0; // ignore this file return 0; // ignore this file
} }
@ -178,14 +175,14 @@ int zupdate_file( const std::string & name, const char * const lzip_name,
{ {
if( verbosity >= 0 ) if( verbosity >= 0 )
std::fprintf( stderr, "%s: Can't stat input file '%s': %s.\n", std::fprintf( stderr, "%s: Can't stat input file '%s': %s.\n",
util_name, name.c_str(), std::strerror( errno ) ); program_name, name.c_str(), std::strerror( errno ) );
return 1; return 1;
} }
if( !S_ISREG( in_stats.st_mode ) ) if( !S_ISREG( in_stats.st_mode ) )
{ {
if( verbosity >= 0 ) if( verbosity >= 0 )
std::fprintf( stderr, "%s: Input file '%s' is not a regular file.\n", std::fprintf( stderr, "%s: Input file '%s' is not a regular file.\n",
util_name, name.c_str() ); program_name, name.c_str() );
return 1; return 1;
} }
@ -196,10 +193,20 @@ int zupdate_file( const std::string & name, const char * const lzip_name,
{ {
if( verbosity >= 0 ) if( verbosity >= 0 )
std::fprintf( stderr, "%s: Output file '%s' already exists, skipping.\n", std::fprintf( stderr, "%s: Output file '%s' already exists, skipping.\n",
util_name, rname.c_str() ); program_name, rname.c_str() );
return -1; return -1;
} }
if( format_index == fmt_xz )
{
if( disable_xz < 0 )
{
std::string command( compressor_name ); command += " -V > /dev/null";
disable_xz = ( std::system( command.c_str() ) != 0 );
}
if( disable_xz ) return 0; // ignore this file if no xz installed
}
if( !lz_exists ) // recompress if( !lz_exists ) // recompress
{ {
if( verbosity >= 1 ) if( verbosity >= 1 )
@ -280,11 +287,11 @@ int zupdate_file( const std::string & name, const char * const lzip_name,
return cant_execute( zcmp_command, status ); } return cant_execute( zcmp_command, status ); }
} }
if( std::remove( name.c_str() ) != 0 && errno != ENOENT ) if( !keep_input_files && std::remove( name.c_str() ) != 0 && errno != ENOENT )
{ {
if( verbosity >= 0 ) if( verbosity >= 0 )
std::fprintf( stderr, "%s: Can't delete input file '%s': %s.\n", std::fprintf( stderr, "%s: Can't delete input file '%s': %s.\n",
util_name, name.c_str(), std::strerror( errno ) ); program_name, name.c_str(), std::strerror( errno ) );
return 1; return 1;
} }
return 0; return 0;
@ -300,9 +307,10 @@ int main( const int argc, const char * const argv[] )
std::list< std::string > filenames; std::list< std::string > filenames;
std::vector< std::string > lzip_args2; // args to lzip, maybe empty std::vector< std::string > lzip_args2; // args to lzip, maybe empty
bool force = false; bool force = false;
bool keep_input_files = false;
bool recursive = false; bool recursive = false;
invocation_name = argv[0]; invocation_name = argv[0];
util_name = "zupdate"; program_name = "zupdate";
const Arg_parser::Option options[] = const Arg_parser::Option options[] =
{ {
@ -318,6 +326,7 @@ int main( const int argc, const char * const argv[] )
{ '9', 0, Arg_parser::no }, { '9', 0, Arg_parser::no },
{ 'f', "force", Arg_parser::no }, { 'f', "force", Arg_parser::no },
{ 'h', "help", Arg_parser::no }, { 'h', "help", Arg_parser::no },
{ 'k', "keep", Arg_parser::no },
{ 'l', "lzip-verbose", Arg_parser::no }, { 'l', "lzip-verbose", Arg_parser::no },
{ 'N', "no-rcfile", Arg_parser::no }, { 'N', "no-rcfile", Arg_parser::no },
{ 'q', "quiet", Arg_parser::no }, { 'q', "quiet", Arg_parser::no },
@ -342,23 +351,24 @@ int main( const int argc, const char * const argv[] )
const int code = parser.code( argind ); const int code = parser.code( argind );
if( !code ) break; // no more options if( !code ) break; // no more options
const char * const arg = parser.argument( argind ).c_str(); const char * const arg = parser.argument( argind ).c_str();
switch( code ) // common options switch( code )
{ {
case '0': case '1': case '2': case '3': case '4': case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': case '5': case '6': case '7': case '8': case '9':
lzip_args2.push_back( "-" ); lzip_args2.back() += code; break; lzip_args2.push_back( "-" ); lzip_args2.back() += code; break;
case 'f': force = true; break; case 'f': force = true; break;
case 'h': show_zupdate_help(); return 0; case 'h': show_help(); return 0;
case 'k': keep_input_files = true; break;
case 'l': lzip_args2.push_back( "-v" ); break; case 'l': lzip_args2.push_back( "-v" ); break;
case 'N': continue; case 'N': break;
case 'q': verbosity = -1; lzip_args2.push_back( "-q" ); break; case 'q': verbosity = -1; lzip_args2.push_back( "-q" ); break;
case 'r': recursive = true; break; case 'r': recursive = true; break;
case 'v': if( verbosity < 4 ) ++verbosity; break; case 'v': if( verbosity < 4 ) ++verbosity; break;
case 'V': show_version( "Zupdate" ); return 0; case 'V': show_version( "Zupdate" ); return 0;
case bz2_opt: parse_compressor( arg, fmt_bz2, 1 ); continue; case bz2_opt: parse_compressor( arg, fmt_bz2, 1 ); break;
case gz_opt: parse_compressor( arg, fmt_gz, 1 ); continue; case gz_opt: parse_compressor( arg, fmt_gz, 1 ); break;
case lz_opt: parse_compressor( arg, fmt_lz, 1 ); continue; case lz_opt: parse_compressor( arg, fmt_lz, 1 ); break;
case xz_opt: parse_compressor( arg, fmt_xz, 1 ); continue; case xz_opt: parse_compressor( arg, fmt_xz, 1 ); break;
default : internal_error( "uncaught option" ); default : internal_error( "uncaught option" );
} }
} // end process options } // end process options
@ -376,40 +386,15 @@ int main( const int argc, const char * const argv[] )
filenames.push_back( parser.argument( argind ) ); filenames.push_back( parser.argument( argind ) );
int retval = 0; int retval = 0;
while( !filenames.empty() ) bool error = false;
while( next_filename( filenames, input_filename, error, recursive, true ) )
{ {
input_filename = filenames.front(); int tmp = zupdate_file( input_filename, lzip_name, lzip_args2, force,
filenames.pop_front(); keep_input_files );
if( !input_filename.size() || input_filename == "-" ) continue; if( tmp < 0 ) error = true;
if( recursive )
{
struct stat st;
if( stat( input_filename.c_str(), &st ) == 0 && S_ISDIR( st.st_mode ) )
{
DIR * const dirp = opendir( input_filename.c_str() );
if( !dirp )
{
show_error2( "Can't open directory", input_filename.c_str() );
if( retval < 1 ) retval = 1; continue;
}
std::list< std::string > tmp_list;
while( true )
{
const struct dirent * const entryp = readdir( dirp );
if( !entryp ) { closedir( dirp ); break; }
std::string tmp_name( entryp->d_name );
if( tmp_name != "." && tmp_name != ".." )
tmp_list.push_back( input_filename + "/" + tmp_name );
}
filenames.splice( filenames.begin(), tmp_list );
continue;
}
}
int tmp = zupdate_file( input_filename, lzip_name, lzip_args2, force );
if( tmp < 0 && retval < 1 ) retval = 1;
if( tmp > retval ) retval = tmp; if( tmp > retval ) retval = tmp;
if( tmp > 0 ) break; if( tmp > 0 ) break;
} }
if( error && retval == 0 ) retval = 1;
return retval; return retval;
} }

175
zutils.cc
View file

@ -27,14 +27,51 @@
#include <unistd.h> #include <unistd.h>
#include <sys/wait.h> #include <sys/wait.h>
#include "zutils.h"
#include "rc.h" #include "rc.h"
#include "zutils.h"
const char * invocation_name = 0; namespace {
const char * util_name = program_name;
int verbosity = 0; // first magic byte must be different among formats
enum { bzip2_magic_size = 3,
gzip_magic_size = 2,
lzip_magic_size = 4,
xz_magic_size = 5 };
const uint8_t bzip2_magic[bzip2_magic_size] =
{ 0x42, 0x5A, 0x68 }; // "BZh"
const uint8_t gzip_magic[gzip_magic_size] =
{ 0x1F, 0x8B };
const uint8_t lzip_magic[lzip_magic_size] =
{ 0x4C, 0x5A, 0x49, 0x50 }; // "LZIP"
const uint8_t xz_magic[xz_magic_size] =
{ 0xFD, 0x37, 0x7A, 0x58, 0x5A }; // 0xFD, "7zXZ"
// Returns -1 if child not terminated, 2 in case of error, or
// exit status of child process 'pid'.
//
int child_status( const pid_t pid, const char * const name )
{
int status;
while( true )
{
const int tmp = waitpid( pid, &status, WNOHANG );
if( tmp == -1 && errno != EINTR )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Error checking status of '%s': %s.\n",
program_name, name, std::strerror( errno ) );
_exit( 2 );
}
if( tmp == 0 ) return -1; // child not terminated
if( tmp == pid ) break; // child terminated
}
if( WIFEXITED( status ) ) return WEXITSTATUS( status );
return 2;
}
} // end namespace
int parse_format_type( const std::string & arg ) int parse_format_type( const std::string & arg )
@ -152,7 +189,7 @@ bool set_data_feeder( int * const infdp, Children & children, int format_index )
!feed_data( old_infd, fda[1], magic_data, magic_size ) ) !feed_data( old_infd, fda[1], magic_data, magic_size ) )
_exit( 2 ); _exit( 2 );
if( close( fda[1] ) != 0 ) if( close( fda[1] ) != 0 )
{ show_close_error( "data feeder" ); _exit( 2 ); } { show_close_error(); _exit( 2 ); }
_exit( 0 ); _exit( 0 );
} }
if( pid < 0 ) // parent if( pid < 0 ) // parent
@ -201,7 +238,7 @@ bool set_data_feeder( int * const infdp, Children & children, int format_index )
!feed_data( old_infd, fda[1], magic_data, magic_size ) ) !feed_data( old_infd, fda[1], magic_data, magic_size ) )
_exit( 2 ); _exit( 2 );
if( close( fda[1] ) != 0 ) if( close( fda[1] ) != 0 )
{ show_close_error( "data feeder" ); _exit( 2 ); } { show_close_error(); _exit( 2 ); }
_exit( 0 ); _exit( 0 );
} }
if( pid < 0 ) // parent if( pid < 0 ) // parent
@ -214,84 +251,6 @@ bool set_data_feeder( int * const infdp, Children & children, int format_index )
} }
void show_help_addr()
{
std::printf( "\nReport bugs to zutils-bug@nongnu.org\n"
"Zutils home page: http://www.nongnu.org/zutils/zutils.html\n" );
}
void show_version( const char * const 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 );
std::printf( "Copyright (C) %s Antonio Diaz Diaz.\n", program_year );
std::printf( "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n"
"This is free software: you are free to change and redistribute it.\n"
"There is NO WARRANTY, to the extent permitted by law.\n" );
}
void show_error( const char * const msg, const int errcode, const bool help )
{
if( verbosity >= 0 )
{
if( msg && msg[0] )
{
std::fprintf( stderr, "%s: %s", util_name, msg );
if( errcode > 0 )
std::fprintf( stderr, ": %s", std::strerror( errcode ) );
std::fprintf( stderr, "\n" );
}
if( help )
std::fprintf( stderr, "Try '%s --help' for more information.\n",
invocation_name );
}
}
void show_error2( const char * const msg, const char * const name )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: %s '%s': %s.\n",
util_name, msg, name, std::strerror( errno ) );
}
void show_close_error( const char * const prog_name )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Can't close output of %s: %s.\n",
util_name, prog_name, std::strerror( errno ) );
}
void show_exec_error( const char * const prog_name )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Can't exec '%s': %s.\n",
util_name, prog_name, std::strerror( errno ) );
}
void show_fork_error( const char * const prog_name )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Can't fork '%s': %s.\n",
util_name, prog_name, std::strerror( errno ) );
}
void internal_error( const char * const msg )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: internal error: %s.\n", util_name, msg );
std::exit( 3 );
}
int test_format( const int infd, const uint8_t ** const magic_datap, int test_format( const int infd, const uint8_t ** const magic_datap,
int * const magic_sizep ) int * const magic_sizep )
{ {
@ -335,51 +294,3 @@ int test_format( const int infd, const uint8_t ** const magic_datap,
*magic_datap = buf; *magic_sizep = i; *magic_datap = buf; *magic_sizep = i;
return -1; return -1;
} }
int wait_for_child( const pid_t pid, const char * const name,
const int eretval, const bool isgzxz )
{
int status;
while( waitpid( pid, &status, 0 ) == -1 )
{
if( errno != EINTR )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Error waiting termination of '%s': %s.\n",
util_name, name, std::strerror( errno ) );
_exit( eretval );
}
}
if( WIFEXITED( status ) )
{
const int tmp = WEXITSTATUS( status );
if( isgzxz && eretval == 1 && tmp == 1 ) return 2; // for ztest
return tmp;
}
return eretval;
}
int child_status( const pid_t pid, const char * const name,
const int eretval )
{
int status;
while( true )
{
const int tmp = waitpid( pid, &status, WNOHANG );
if( tmp == -1 && errno != EINTR )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Error checking status of '%s': %s.\n",
util_name, name, std::strerror( errno ) );
_exit( eretval );
}
if( tmp == 0 ) return -1; // child not terminated
if( tmp == pid ) break; // child terminated
}
if( WIFEXITED( status ) ) return WEXITSTATUS( status );
return eretval;
}

View file

@ -15,37 +15,6 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. 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 config_file_name = "zutilsrc";
const char * const program_year = "2013";
extern const char * invocation_name;
extern const char * util_name;
extern int verbosity;
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 int8_t format_order[num_formats] =
{ fmt_lz, fmt_bz2, fmt_gz, fmt_xz }; // search order
// first magic byte must be different among formats
enum { bzip2_magic_size = 3,
gzip_magic_size = 2,
lzip_magic_size = 4,
xz_magic_size = 5 };
const uint8_t bzip2_magic[bzip2_magic_size] =
{ 0x42, 0x5A, 0x68 }; // "BZh"
const uint8_t gzip_magic[gzip_magic_size] =
{ 0x1F, 0x8B };
const uint8_t lzip_magic[lzip_magic_size] =
{ 0x4C, 0x5A, 0x49, 0x50 }; // "LZIP"
const uint8_t xz_magic[xz_magic_size] =
{ 0xFD, 0x37, 0x7A, 0x58, 0x5A }; // 0xFD, "7zXZ"
int parse_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 readblock( const int fd, uint8_t * const buf, const int size );
@ -61,28 +30,7 @@ struct Children
bool good_status( const Children & children, const bool finished ); bool good_status( const Children & children, const bool finished );
bool set_data_feeder( int * const infdp, Children & children, int format_index ); 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 );
void show_error( const char * const msg, const int errcode = 0,
const bool help = false );
void show_error2( const char * const msg, const char * const name );
void show_close_error( const char * const prog_name );
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 );
// Returns format index or -1 if uncompressed // Returns format index or -1 if uncompressed
// //
int test_format( const int infd, const uint8_t ** const magic_datap, int test_format( const int infd, const uint8_t ** const magic_datap,
int * const magic_sizep ); int * const magic_sizep );
// Returns exit status of child process 'pid', or 'eretval' in case of error.
//
int wait_for_child( const pid_t pid, const char * const name,
const int eretval = 2, const bool isgzxz = false );
// Returns -1 if child not terminated, 'eretval' in case of error, or
// exit status of child process 'pid'.
//
int child_status( const pid_t pid, const char * const name,
const int eretval = 2 );