1
0
Fork 0

Adding upstream version 0.4.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-24 04:51:33 +01:00
parent 527d6bc346
commit 1bfa18df1d
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
22 changed files with 1234 additions and 125 deletions

View file

@ -1,4 +1,10 @@
2009-08-?? Antonio Diaz Diaz <ant_diaz@teleline.es>
2009-09-17 Antonio Diaz Diaz <ant_diaz@teleline.es>
* Version 0.4 released.
* Added two new utilities; zegrep and zfgrep.
* Added zutils executable which recognizes file formats.
2009-08-28 Antonio Diaz Diaz <ant_diaz@teleline.es>
* Version 0.3 released.
* Removed default compressor.

View file

@ -1,7 +1,12 @@
Requirements
------------
You will need a Posix compatible shell command interpreter like Bash or
Dash.
You will need a C++ compiler.
I use gcc 4.3.4 and 3.3.6, but the code should compile with any
standards compliant compiler.
Gcc is available at http://gcc.gnu.org.
You will also need a Posix compatible shell command interpreter like
Bash or Dash.
Bash is available at http://gnu.org/software/bash/bash.html.
Dash is available at http://packages.debian.org/stable/dash/.

View file

@ -1,5 +1,5 @@
DISTNAME = $(pkgname)-$(pkgversion)
DISTNAME = $(progname)-$(progversion)
INSTALL = install
INSTALL_PROGRAM = $(INSTALL) -p -m 755
INSTALL_SCRIPT = $(INSTALL) -p -m 755
@ -7,17 +7,24 @@ INSTALL_DATA = $(INSTALL) -p -m 644
INSTALL_DIR = $(INSTALL) -d -m 755
SHELL = /bin/sh
scripts = zcat zcmp zdiff zgrep
objs = arg_parser.o main.o
scripts = zcat zcmp zdiff zegrep zfgrep zgrep
.PHONY : all install install-info install-man install-strip \
uninstall uninstall-info uninstall-man \
doc info man check dist clean distclean
all : $(scripts)
all : $(progname) $(scripts)
$(progname) : $(objs)
$(CXX) $(LDFLAGS) -o $(progname) $(objs)
$(progname)_profiled : $(objs)
$(CXX) $(LDFLAGS) -pg -o $(progname)_profiled $(objs)
zcat : zcat.in
sed -e 's|VERSION|$(pkgversion)|g' $(VPATH)/zcat.in > zcat
sed -e 's,VERSION,$(progversion),g' $(VPATH)/zcat.in > zcat
chmod a+x zcat
zcmp : zcmp.in
@ -25,23 +32,44 @@ zcmp : zcmp.in
chmod a+x zcmp
zdiff : zdiff.in
sed -e 's|VERSION|$(pkgversion)|g' $(VPATH)/zdiff.in > zdiff
sed -e 's,VERSION,$(progversion),g' $(VPATH)/zdiff.in > zdiff
chmod a+x zdiff
zegrep : zegrep.in
cat $(VPATH)/zegrep.in > zegrep
chmod a+x zegrep
zfgrep : zfgrep.in
cat $(VPATH)/zfgrep.in > zfgrep
chmod a+x zfgrep
zgrep : zgrep.in
sed -e 's|VERSION|$(pkgversion)|g' $(VPATH)/zgrep.in > zgrep
sed -e 's,VERSION,$(progversion),g' $(VPATH)/zgrep.in > zgrep
chmod a+x zgrep
main.o : main.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -DPROGVERSION=\"$(progversion)\" -c -o $@ $<
%.o : %.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<
$(objs) : Makefile
$(scripts) : Makefile
arg_parser.o : arg_parser.h
main.o : arg_parser.h
doc : info man
info : $(VPATH)/doc/$(pkgname).info
info : $(VPATH)/doc/$(progname).info
$(VPATH)/doc/$(pkgname).info : $(VPATH)/doc/$(pkgname).texinfo
cd $(VPATH)/doc && makeinfo $(pkgname).texinfo
$(VPATH)/doc/$(progname).info : $(VPATH)/doc/$(progname).texinfo
cd $(VPATH)/doc && makeinfo $(progname).texinfo
man : $(VPATH)/doc/zcat.1 $(VPATH)/doc/zdiff.1 $(VPATH)/doc/zgrep.1
man : $(VPATH)/doc/$(progname).1 $(VPATH)/doc/zcat.1 $(VPATH)/doc/zdiff.1 \
$(VPATH)/doc/zgrep.1
$(VPATH)/doc/$(progname).1 : $(progname)
help2man -o $(VPATH)/doc/$(progname).1 ./$(progname)
$(VPATH)/doc/zcat.1 : zcat
help2man -o $(VPATH)/doc/zcat.1 --no-info ./zcat
@ -60,38 +88,55 @@ check : all $(VPATH)/testsuite/check.sh
install : all install-info install-man
if test ! -d $(DESTDIR)$(bindir) ; then $(INSTALL_DIR) $(DESTDIR)$(bindir) ; fi
$(INSTALL_PROGRAM) ./$(progname) $(DESTDIR)$(bindir)/$(progname)
$(INSTALL_SCRIPT) zcat $(DESTDIR)$(bindir)/zcat
$(INSTALL_SCRIPT) zcmp $(DESTDIR)$(bindir)/zcmp
$(INSTALL_SCRIPT) zdiff $(DESTDIR)$(bindir)/zdiff
$(INSTALL_SCRIPT) zegrep $(DESTDIR)$(bindir)/zegrep
$(INSTALL_SCRIPT) zfgrep $(DESTDIR)$(bindir)/zfgrep
$(INSTALL_SCRIPT) zgrep $(DESTDIR)$(bindir)/zgrep
install-info :
if test ! -d $(DESTDIR)$(infodir) ; then $(INSTALL_DIR) $(DESTDIR)$(infodir) ; fi
$(INSTALL_DATA) $(VPATH)/doc/$(pkgname).info $(DESTDIR)$(infodir)/$(pkgname).info
-install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/$(pkgname).info
$(INSTALL_DATA) $(VPATH)/doc/$(progname).info $(DESTDIR)$(infodir)/$(progname).info
-install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/$(progname).info
install-man :
if test ! -d $(DESTDIR)$(mandir)/man1 ; then $(INSTALL_DIR) $(DESTDIR)$(mandir)/man1 ; fi
$(INSTALL_DATA) $(VPATH)/doc/$(progname).1 $(DESTDIR)$(mandir)/man1/$(progname).1
$(INSTALL_DATA) $(VPATH)/doc/zcat.1 $(DESTDIR)$(mandir)/man1/zcat.1
-rm -f $(DESTDIR)$(mandir)/man1/zcmp.1
cd $(DESTDIR)$(mandir)/man1 && ln -s zdiff.1 zcmp.1
$(INSTALL_DATA) $(VPATH)/doc/zdiff.1 $(DESTDIR)$(mandir)/man1/zdiff.1
$(INSTALL_DATA) $(VPATH)/doc/zgrep.1 $(DESTDIR)$(mandir)/man1/zgrep.1
-rm -f $(DESTDIR)$(mandir)/man1/zegrep.1
-rm -f $(DESTDIR)$(mandir)/man1/zfgrep.1
cd $(DESTDIR)$(mandir)/man1 && ln -s zgrep.1 zegrep.1
cd $(DESTDIR)$(mandir)/man1 && ln -s zgrep.1 zfgrep.1
install-strip : all
$(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install
uninstall : uninstall-info uninstall-man
-rm -f $(DESTDIR)$(bindir)/$(progname)
-rm -f $(DESTDIR)$(bindir)/zcat
-rm -f $(DESTDIR)$(bindir)/zcmp
-rm -f $(DESTDIR)$(bindir)/zdiff
-rm -f $(DESTDIR)$(bindir)/zegrep
-rm -f $(DESTDIR)$(bindir)/zfgrep
-rm -f $(DESTDIR)$(bindir)/zgrep
uninstall-info :
-install-info --info-dir=$(DESTDIR)$(infodir) --remove $(DESTDIR)$(infodir)/$(pkgname).info
-rm -f $(DESTDIR)$(infodir)/$(pkgname).info
-install-info --info-dir=$(DESTDIR)$(infodir) --remove $(DESTDIR)$(infodir)/$(progname).info
-rm -f $(DESTDIR)$(infodir)/$(progname).info
uninstall-man :
-rm -f $(DESTDIR)$(mandir)/man1/$(progname).1
-rm -f $(DESTDIR)$(mandir)/man1/zcat.1
-rm -f $(DESTDIR)$(mandir)/man1/zcmp.1
-rm -f $(DESTDIR)$(mandir)/man1/zdiff.1
-rm -f $(DESTDIR)$(mandir)/man1/zegrep.1
-rm -f $(DESTDIR)$(mandir)/man1/zfgrep.1
-rm -f $(DESTDIR)$(mandir)/man1/zgrep.1
dist :
@ -105,20 +150,18 @@ dist :
$(DISTNAME)/NEWS \
$(DISTNAME)/README \
$(DISTNAME)/configure \
$(DISTNAME)/doc/zcat.1 \
$(DISTNAME)/doc/zdiff.1 \
$(DISTNAME)/doc/zgrep.1 \
$(DISTNAME)/doc/$(pkgname).info \
$(DISTNAME)/doc/$(pkgname).texinfo \
$(DISTNAME)/doc/*.1 \
$(DISTNAME)/doc/$(progname).info \
$(DISTNAME)/doc/$(progname).texinfo \
$(DISTNAME)/testsuite/check.sh \
$(DISTNAME)/zcat.in \
$(DISTNAME)/zcmp.in \
$(DISTNAME)/zdiff.in \
$(DISTNAME)/zgrep.in
$(DISTNAME)/*.h \
$(DISTNAME)/*.cc \
$(DISTNAME)/z*.in
rm -f $(DISTNAME)
lzip -v -9 $(DISTNAME).tar
clean :
-rm -f $(progname) $(progname)_profiled $(objs)
-rm -f $(scripts)
distclean : clean

6
NEWS
View file

@ -1,3 +1,5 @@
Changes in version 0.2:
Changes in version 0.4:
Support for the xz compressor has been added.
Two new utilities have been added; zegrep and zfgrep.
Zutils now recognizes file formats independently of filename extensions.

3
README
View file

@ -4,7 +4,8 @@ Zutils is a collection of utilities for dealing with any combination of
compressed and non-compressed files transparently. The supported
compressors are gzip, bzip2, lzip and xz.
The currently provided utilities are zcat, zcmp, zdiff and zgrep.
The currently provided utilities are zcat, zcmp, zdiff, zegrep, zfgrep
and zgrep.
Copyright (C) 2009 Antonio Diaz Diaz.

193
arg_parser.cc Normal file
View file

@ -0,0 +1,193 @@
/* Arg_parser - A POSIX/GNU command line argument parser.
Copyright (C) 2006, 2007, 2008, 2009 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/>.
*/
#include <cstring>
#include <string>
#include <vector>
#include "arg_parser.h"
bool Arg_parser::parse_long_option( const char * const opt, const char * const arg,
const Option options[], int & argind )
{
unsigned int len;
int index = -1;
bool exact = false, ambig = false;
for( len = 0; opt[len+2] && opt[len+2] != '='; ++len ) ;
// Test all long options for either exact match or abbreviated matches.
for( int i = 0; options[i].code != 0; ++i )
if( options[i].name && !std::strncmp( options[i].name, &opt[2], len ) )
{
if( std::strlen( options[i].name ) == len ) // Exact match found
{ index = i; exact = true; break; }
else if( index < 0 ) index = i; // First nonexact match found
else if( options[index].code != options[i].code ||
options[index].has_arg != options[i].has_arg )
ambig = true; // Second or later nonexact match found
}
if( ambig && !exact )
{
error_ = "option `"; error_ += opt; error_ += "' is ambiguous";
return false;
}
if( index < 0 ) // nothing found
{
error_ = "unrecognized option `"; error_ += opt; error_ += '\'';
return false;
}
++argind;
data.push_back( Record( options[index].code ) );
if( opt[len+2] ) // `--<long_option>=<argument>' syntax
{
if( options[index].has_arg == no )
{
error_ = "option `--"; error_ += options[index].name;
error_ += "' doesn't allow an argument";
return false;
}
if( options[index].has_arg == yes && !opt[len+3] )
{
error_ = "option `--"; error_ += options[index].name;
error_ += "' requires an argument";
return false;
}
data.back().argument = &opt[len+3];
return true;
}
if( options[index].has_arg == yes )
{
if( !arg || !arg[0] )
{
error_ = "option `--"; error_ += options[index].name;
error_ += "' requires an argument";
return false;
}
++argind; data.back().argument = arg;
return true;
}
return true;
}
bool Arg_parser::parse_short_option( const char * const opt, const char * const arg,
const Option options[], int & argind )
{
int cind = 1; // character index in opt
while( cind > 0 )
{
int index = -1;
const unsigned char c = opt[cind];
if( c != 0 )
for( int i = 0; options[i].code; ++i )
if( c == options[i].code )
{ index = i; break; }
if( index < 0 )
{
error_ = "invalid option -- "; error_ += c;
return false;
}
data.push_back( Record( c ) );
if( opt[++cind] == 0 ) { ++argind; cind = 0; } // opt finished
if( options[index].has_arg != no && cind > 0 && opt[cind] )
{
data.back().argument = &opt[cind]; ++argind; cind = 0;
}
else if( options[index].has_arg == yes )
{
if( !arg || !arg[0] )
{
error_ = "option requires an argument -- "; error_ += c;
return false;
}
data.back().argument = arg; ++argind; cind = 0;
}
}
return true;
}
Arg_parser::Arg_parser( const int argc, const char * const argv[],
const Option options[], const bool in_order )
{
if( argc < 2 || !argv || !options ) return;
std::vector< std::string > non_options; // skipped non-options
int argind = 1; // index in argv
while( argind < argc )
{
const unsigned char ch1 = argv[argind][0];
const unsigned char ch2 = ( ch1 ? argv[argind][1] : 0 );
if( ch1 == '-' && ch2 ) // we found an option
{
const char * const opt = argv[argind];
const char * const arg = (argind + 1 < argc) ? argv[argind+1] : 0;
if( ch2 == '-' )
{
if( !argv[argind][2] ) { ++argind; break; } // we found "--"
else if( !parse_long_option( opt, arg, options, argind ) ) break;
}
else if( !parse_short_option( opt, arg, options, argind ) ) break;
}
else
{
if( !in_order ) non_options.push_back( argv[argind++] );
else { data.push_back( Record() ); data.back().argument = argv[argind++]; }
}
}
if( error_.size() ) data.clear();
else
{
for( unsigned int i = 0; i < non_options.size(); ++i )
{ data.push_back( Record() ); data.back().argument.swap( non_options[i] ); }
while( argind < argc )
{ data.push_back( Record() ); data.back().argument = argv[argind++]; }
}
}
Arg_parser::Arg_parser( const char * const opt, const char * const arg,
const Option options[] )
{
if( !opt || !opt[0] || !options ) return;
if( opt[0] == '-' && opt[1] ) // we found an option
{
int argind = 1; // dummy
if( opt[1] == '-' )
{ if( opt[2] ) parse_long_option( opt, arg, options, argind ); }
else
parse_short_option( opt, arg, options, argind );
if( error_.size() ) data.clear();
}
else { data.push_back( Record() ); data.back().argument = opt; }
}

95
arg_parser.h Normal file
View file

@ -0,0 +1,95 @@
/* Arg_parser - A POSIX/GNU command line argument parser.
Copyright (C) 2006, 2007, 2008, 2009 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/>.
*/
/* Arg_parser reads the arguments in `argv' and creates a number of
option codes, option arguments and non-option arguments.
In case of error, `error' returns a non-empty error message.
`options' is an array of `struct Option' terminated by an element
containing a code which is zero. A null name means a short-only
option. A code value outside the unsigned char range means a
long-only option.
Arg_parser normally makes it appear as if all the option arguments
were specified before all the non-option arguments for the purposes
of parsing, even if the user of your program intermixed option and
non-option arguments. If you want the arguments in the exact order
the user typed them, call `Arg_parser' with `in_order' = true.
The argument `--' terminates all options; any following arguments are
treated as non-option arguments, even if they begin with a hyphen.
The syntax for optional option arguments is `-<short_option><argument>'
(without whitespace), or `--<long_option>=<argument>'.
*/
class Arg_parser
{
public:
enum Has_arg { no, yes, maybe };
struct Option
{
int code; // Short option letter or code ( code != 0 )
const char * name; // Long option name (maybe null)
Has_arg has_arg;
};
private:
struct Record
{
int code;
std::string argument;
Record( const int c = 0 ) : code( c ) {}
};
std::string error_;
std::vector< Record > data;
bool parse_long_option( const char * const opt, const char * const arg,
const Option options[], int & argind );
bool parse_short_option( const char * const opt, const char * const arg,
const Option options[], int & argind );
public:
Arg_parser( const int argc, const char * const argv[],
const Option options[], const bool in_order = false );
// Restricted constructor. Parses a single token and argument (if any)
Arg_parser( const char * const opt, const char * const arg,
const Option options[] );
const std::string & error() const throw() { return error_; }
// The number of arguments parsed (may be different from argc)
int arguments() const throw() { return data.size(); }
// If code( i ) is 0, argument( i ) is a non-option.
// Else argument( i ) is the option's argument (or empty).
int code( const int i ) const throw()
{
if( i >= 0 && i < arguments() ) return data[i].code;
else return 0;
}
const std::string & argument( const int i ) const throw()
{
if( i >= 0 && i < arguments() ) return data[i].argument;
else return error_;
}
};

12
configure vendored
View file

@ -5,12 +5,12 @@
# This configure script is free software: you have unlimited permission
# to copy, distribute and modify it.
#
# Date of this version: 2009-08-13
# Date of this version: 2009-09-17
args=
no_create=
pkgname=zutils
pkgversion=0.3
progname=zutils
progversion=0.4
srctrigger=zdiff.in
# clear some things potentially inherited from environment.
@ -71,7 +71,7 @@ while [ x"$1" != x ] ; do
echo
exit 0 ;;
--version | --ve* | -V)
echo "Configure script for ${pkgname} version ${pkgversion}"
echo "Configure script for ${progname} version ${progversion}"
exit 0 ;;
--srcdir* | --sr*)
srcdir=`echo ${optarg} | sed -e 's,/$,,'` ;;
@ -191,8 +191,8 @@ cat > Makefile << EOF
# This Makefile is free software: you have unlimited permission
# to copy, distribute and modify it.
pkgname = ${pkgname}
pkgversion = ${pkgversion}
progname = ${progname}
progversion = ${progversion}
VPATH = ${srcdir}
prefix = ${prefix}
exec_prefix = ${exec_prefix}

View file

@ -1,7 +1,7 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.36.
.TH ZCAT "1" "August 2009" "Zcat 0.3" "User Commands"
.TH ZCAT "1" "September 2009" "Zcat 0.4" "User Commands"
.SH NAME
Zcat \- manual page for Zcat 0.3
Zcat \- manual page for Zcat 0.4
.SH SYNOPSIS
.B zcat
[\fIOPTIONS\fR] [\fICAT_OPTIONS\fR] [\fIFILES\fR]

View file

@ -1,7 +1,7 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.36.
.TH ZDIFF "1" "August 2009" "Zdiff 0.3" "User Commands"
.TH ZDIFF "1" "September 2009" "Zdiff 0.4" "User Commands"
.SH NAME
Zdiff \- manual page for Zdiff 0.3
Zdiff \- manual page for Zdiff 0.4
.SH SYNOPSIS
.B zdiff
[\fIOPTIONS\fR] [\fIDIFF_OPTIONS\fR] \fIFILE1 \fR[\fIFILE2\fR]

View file

@ -1,7 +1,7 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.36.
.TH ZGREP "1" "August 2009" "Zgrep 0.3" "User Commands"
.TH ZGREP "1" "September 2009" "Zgrep 0.4" "User Commands"
.SH NAME
Zgrep \- manual page for Zgrep 0.3
Zgrep \- manual page for Zgrep 0.4
.SH SYNOPSIS
.B zgrep
[\fIOPTIONS\fR] [\fIGREP_OPTIONS\fR] \fIPATTERN \fR[\fIFILES\fR]
@ -15,6 +15,9 @@ used. If a given file does not exist, zgrep tries the compressed file
names corresponding to the supported compressors.
The supported compressors are gzip, bzip2, lzip and xz.
.PP
Zegrep is a shortcut for "zgrep \fB\-E\fR"
Zfgrep is a shortcut for "zgrep \fB\-F\fR"
.PP
GREP_OPTIONS are passed directly to grep.
The exit status from grep is preserved.
.SH OPTIONS

46
doc/zutils.1 Normal file
View file

@ -0,0 +1,46 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.36.
.TH ZUTILS "1" "September 2009" "Zutils 0.4" "User Commands"
.SH NAME
Zutils \- manual page for Zutils 0.4
.SH SYNOPSIS
.B zutils
[\fIoptions\fR] [\fIfiles\fR]
.SH DESCRIPTION
Zutils \- A file format detector for compressed files.
.SH OPTIONS
.TP
\fB\-h\fR, \fB\-\-help\fR
display this help and exit
.TP
\fB\-V\fR, \fB\-\-version\fR
output version information and exit
.TP
\fB\-q\fR, \fB\-\-quiet\fR
suppress all messages
.TP
\fB\-t\fR, \fB\-\-test\fR
test compressed file type
.TP
\fB\-v\fR, \fB\-\-verbose\fR
be verbose (a 2nd \fB\-v\fR gives more)
.SH "REPORTING BUGS"
Report bugs to zutils\-bug@nongnu.org
Zutils home page: http://www.nongnu.org/zutils/zutils.html
.SH COPYRIGHT
Copyright \(co 2009 Antonio Diaz Diaz.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
.br
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
.SH "SEE ALSO"
The full documentation for
.B Zutils
is maintained as a Texinfo manual. If the
.B info
and
.B Zutils
programs are properly installed at your site, the command
.IP
.B info Zutils
.PP
should give you access to the complete manual.

Binary file not shown.

View file

@ -5,8 +5,8 @@
@finalout
@c %**end of header
@set UPDATED 13 August 2009
@set VERSION 0.2
@set UPDATED 17 September 2009
@set VERSION 0.4
@dircategory Data Compression
@direntry
@ -55,7 +55,8 @@ Zutils is a collection of utilities for dealing with any combination of
compressed and non-compressed files transparently. The supported
compressors are gzip, bzip2, lzip and xz.
The currently provided utilities are zcat, zcmp, zdiff and zgrep.
The currently provided utilities are zcat, zcmp, zdiff, zegrep, zfgrep
and zgrep.
@node Zcat
@ -147,6 +148,8 @@ refer to temporary filenames instead of those specified.
@node Zgrep
@chapter Zgrep
@cindex zegrep
@cindex zfgrep
@cindex zgrep
Zgrep is a wrapper script around the grep command that allows
@ -156,6 +159,11 @@ used. If a given file does not exist, zgrep tries the compressed file
names corresponding to the supported compressors. The supported
compressors are gzip, bzip2, lzip and xz.
@noindent
Zegrep is a shortcut for @samp{zgrep -E}@*
Zfgrep is a shortcut for @samp{zgrep -F}
The format for running zgrep is:
@example

688
main.cc Normal file
View file

@ -0,0 +1,688 @@
/* Zutils - A file format detector for compressed files
Copyright (C) 2009 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/>.
*/
/*
Return values: 0 for a normal exit, 1 for environmental problems
(file not found, invalid flags, I/O errors, etc), 2 to indicate a
corrupt or invalid input file, 3 for an internal consistency error
(eg, bug) which caused zutils to panic.
*/
#define _FILE_OFFSET_BITS 64
#include <algorithm>
#include <cerrno>
#include <climits>
#include <csignal>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
#include <fcntl.h>
#include <stdint.h>
#include <unistd.h>
#include <utime.h>
#include <sys/stat.h>
#include <sys/time.h>
#include "arg_parser.h"
#ifndef LLONG_MAX
#define LLONG_MAX 0x7FFFFFFFFFFFFFFFLL
#endif
#ifndef LLONG_MIN
#define LLONG_MIN (-LLONG_MAX - 1LL)
#endif
#ifndef ULLONG_MAX
#define ULLONG_MAX 0xFFFFFFFFFFFFFFFFULL
#endif
namespace {
const char * invocation_name = 0;
const char * const Program_name = "Zutils";
const char * const program_name = "zutils";
const char * const program_year = "2009";
struct { const char * from; const char * to; } const known_extensions[] = {
{ ".zf", "" },
{ 0, 0 } };
enum Mode { m_compress = 0, m_decompress, m_test };
std::string output_filename;
int outhandle = -1;
int verbosity = 0;
bool delete_output_on_interrupt = false;
class Pretty_print
{
const char * const stdin_name;
const unsigned int stdin_name_len;
unsigned int longest_name;
std::string name_;
mutable bool first_post;
public:
Pretty_print( const std::vector< std::string > & filenames )
: stdin_name( "(stdin)" ), stdin_name_len( std::strlen( stdin_name ) ),
longest_name( 0 ), first_post( false )
{
for( unsigned int i = 0; i < filenames.size(); ++i )
{
const std::string & s = filenames[i];
const unsigned int len = ( ( s == "-" ) ? stdin_name_len : s.size() );
if( len > longest_name ) longest_name = len;
}
if( longest_name == 0 ) longest_name = stdin_name_len;
}
void set_name( const std::string & filename )
{
if( filename.size() && filename != "-" ) name_ = filename;
else name_ = stdin_name;
first_post = true;
}
void reset() const throw() { if( name_.size() ) first_post = true; }
const char * name() const throw() { return name_.c_str(); }
void operator()( const char * const msg = 0 ) const throw();
};
void Pretty_print::operator()( const char * const msg ) const throw()
{
if( verbosity >= 0 )
{
if( first_post )
{
first_post = false;
std::fprintf( stderr, " %s: ", name_.c_str() );
for( unsigned int i = 0; i < longest_name - name_.size(); ++i )
std::fprintf( stderr, " " );
if( !msg ) std::fflush( stderr );
}
if( msg ) std::fprintf( stderr, "%s.\n", msg );
}
}
void show_help() throw()
{
std::printf( "%s - A file format detector for compressed files.\n", Program_name );
std::printf( "\nUsage: %s [options] [files]\n", invocation_name );
std::printf( "\nOptions:\n" );
std::printf( " -h, --help display this help and exit\n" );
std::printf( " -V, --version output version information and exit\n" );
// std::printf( " -c, --stdout send output to standard output\n" );
// std::printf( " -d, --decompress decompress\n" );
// std::printf( " -f, --force overwrite existing output files\n" );
// std::printf( " -k, --keep keep (don't delete) input files\n" );
// std::printf( " -o, --output=<file> if reading stdin, place the output into <file>\n" );
std::printf( " -q, --quiet suppress all messages\n" );
std::printf( " -t, --test test compressed file type\n" );
std::printf( " -v, --verbose be verbose (a 2nd -v gives more)\n" );
std::printf( "\nReport bugs to zutils-bug@nongnu.org\n" );
std::printf( "Zutils home page: http://www.nongnu.org/zutils/zutils.html\n" );
}
void show_version() throw()
{
std::printf( "%s %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" );
std::printf( "This is free software: you are free to change and redistribute it.\n" );
std::printf( "There is NO WARRANTY, to the extent permitted by law.\n" );
}
void show_error( const char * msg, const int errcode = 0, const bool help = false ) throw()
{
if( verbosity >= 0 )
{
if( msg && msg[0] != 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 && invocation_name && invocation_name[0] != 0 )
std::fprintf( stderr, "Try `%s --help' for more information.\n", invocation_name );
}
}
void internal_error( const char * msg )
{
std::string s( "internal error: " ); s += msg;
show_error( s.c_str() );
std::exit( 3 );
}
const char * format_num( long long num, long long limit = 9999,
const int set_prefix = 0 ) throw()
{
const char * const si_prefix[8] =
{ "k", "M", "G", "T", "P", "E", "Z", "Y" };
const char * const binary_prefix[8] =
{ "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi" };
static bool si = false;
static char buf[16];
if( set_prefix ) si = ( set_prefix > 0 );
const int factor = ( si ) ? 1000 : 1024;
const char * const *prefix = ( si ) ? si_prefix : binary_prefix;
const char *p = "";
limit = std::max( 999LL, std::min( 999999LL, limit ) );
for( int i = 0; i < 8 && ( llabs( num ) > limit ||
( llabs( num ) >= factor && num % factor == 0 ) ); ++i )
{ num /= factor; p = prefix[i]; }
snprintf( buf, sizeof buf, "%lld %s", num, p );
return buf;
}
long long getnum( const char * ptr, const int bs,
const long long llimit = LLONG_MIN + 1,
const long long ulimit = LLONG_MAX ) throw()
{
errno = 0;
char *tail;
long long result = strtoll( ptr, &tail, 0 );
if( tail == ptr )
{
show_error( "bad or missing numerical argument", 0, true );
std::exit( 1 );
}
if( !errno && tail[0] )
{
int factor = ( tail[1] == 'i' ) ? 1024 : 1000;
int exponent = 0;
bool bad_multiplier = false;
switch( tail[0] )
{
case ' ': break;
case 'b': if( bs > 0 ) { factor = bs; exponent = 1; }
else bad_multiplier = true;
break;
case 'Y': exponent = 8; break;
case 'Z': exponent = 7; break;
case 'E': exponent = 6; break;
case 'P': exponent = 5; break;
case 'T': exponent = 4; break;
case 'G': exponent = 3; break;
case 'M': exponent = 2; break;
case 'K': if( factor == 1024 ) exponent = 1; else bad_multiplier = true;
break;
case 'k': if( factor == 1000 ) exponent = 1; else bad_multiplier = true;
break;
default: bad_multiplier = true;
}
if( bad_multiplier )
{
show_error( "bad multiplier in numerical argument", 0, true );
std::exit( 1 );
}
for( int i = 0; i < exponent; ++i )
{
if( LLONG_MAX / factor >= llabs( result ) ) result *= factor;
else { errno = ERANGE; break; }
}
}
if( !errno && ( result < llimit || result > ulimit ) ) errno = ERANGE;
if( errno )
{
show_error( "numerical argument out of limits" );
std::exit( 1 );
}
return result;
}
int extension_index( const std::string & name ) throw()
{
for( int i = 0; known_extensions[i].from; ++i )
{
const std::string ext( known_extensions[i].from );
if( name.size() > ext.size() &&
name.compare( name.size() - ext.size(), ext.size(), ext ) == 0 )
return i;
}
return -1;
}
int open_instream( const std::string & name, struct stat * in_statsp,
const Mode program_mode, const int eindex,
const bool force, const bool to_stdout ) throw()
{
int inhandle = -1;
if( program_mode == m_compress && !force && eindex >= 0 )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: input file `%s' already has `%s' suffix.\n",
program_name, name.c_str(),
known_extensions[eindex].from );
}
else
{
inhandle = open( name.c_str(), O_RDONLY );
if( inhandle < 0 )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Can't open input file `%s': %s.\n",
program_name, name.c_str(), std::strerror( errno ) );
}
else
{
const int i = fstat( inhandle, in_statsp );
const mode_t & mode = in_statsp->st_mode;
if( i < 0 || !( S_ISREG( mode ) || ( to_stdout &&
( S_ISFIFO( mode ) || S_ISSOCK( mode ) ||
S_ISBLK( mode ) || S_ISCHR( mode ) ) ) ) )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: input file `%s' is not a regular file%s.\n",
program_name, name.c_str(),
to_stdout ? "" : " and `--stdout' was not specified" );
close( inhandle );
inhandle = -1;
}
}
}
return inhandle;
}
void set_c_outname( const std::string & name ) throw()
{
output_filename = name;
output_filename += known_extensions[0].from;
}
void set_d_outname( const std::string & name, const int i ) throw()
{
if( i >= 0 )
{
const std::string from( known_extensions[i].from );
if( name.size() > from.size() )
{
output_filename.assign( name, 0, name.size() - from.size() );
output_filename += known_extensions[i].to;
return;
}
}
output_filename = name; output_filename += ".out";
if( verbosity >= 0 )
std::fprintf( stderr, "%s: can't guess original name for `%s' -- using `%s'.\n",
program_name, name.c_str(), output_filename.c_str() );
}
bool open_outstream( const bool /*force*/ ) throw()
{
/* if( force )
outhandle = open( output_filename.c_str(), O_CREAT | O_TRUNC | O_WRONLY,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
else outhandle = open( output_filename.c_str(), O_CREAT | O_EXCL | O_WRONLY,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
if( outhandle < 0 )
{
if( errno == EEXIST ) outhandle = -2; else outhandle = -1;
if( verbosity >= 0 )
{
if( outhandle == -2 )
std::fprintf( stderr, "%s: Output file %s already exists, skipping.\n",
program_name, output_filename.c_str() );
else
std::fprintf( stderr, "%s: Can't create output file `%s': %s.\n",
program_name, output_filename.c_str(), std::strerror( errno ) );
}
}*/
return ( outhandle >= 0 );
}
bool check_tty( const int inhandle, const Mode program_mode ) throw()
{
if( program_mode == m_compress && isatty( outhandle ) )
{
show_error( "I won't write compressed data to a terminal.", 0, true );
return false;
}
if( ( program_mode == m_decompress || program_mode == m_test ) &&
isatty( inhandle ) )
{
show_error( "I won't read compressed data from a terminal.", 0, true );
return false;
}
return true;
}
void cleanup_and_fail( const int retval ) throw()
{
if( delete_output_on_interrupt )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Deleting output file `%s', if it exists.\n",
program_name, output_filename.c_str() );
if( outhandle >= 0 ) { close( outhandle ); outhandle = -1; }
if( std::remove( output_filename.c_str() ) != 0 )
show_error( "WARNING: deletion of output file (apparently) failed." );
}
std::exit( retval );
}
// Set permissions, owner and times.
void close_and_set_permissions( const struct stat * in_statsp, int * retvalp )
{
int tmp = 0;
if( in_statsp )
{
if( fchmod( outhandle, in_statsp->st_mode ) != 0 ) tmp = 1;
if( !tmp ) (void)fchown( outhandle, in_statsp->st_uid, in_statsp->st_gid );
// fchown will in many cases return with EPERM, which can be safely ignored.
}
if( close( outhandle ) == 0 ) outhandle = -1;
else cleanup_and_fail( 1 );
delete_output_on_interrupt = false;
if( !in_statsp ) return;
if( !tmp )
{
struct utimbuf t;
t.actime = in_statsp->st_atime;
t.modtime = in_statsp->st_mtime;
tmp = utime( output_filename.c_str(), &t );
}
if( tmp )
{
if( tmp > *retvalp ) *retvalp = tmp;
show_error( "I can't change output file attributes." );
cleanup_and_fail( *retvalp );
}
}
// Returns the number of bytes really read.
// If (returned value < size) and (errno == 0), means EOF was reached.
//
int readblock( const int fd, char * buf, const int size ) throw()
{
int rest = size;
errno = 0;
while( rest > 0 )
{
errno = 0;
const int n = read( fd, buf + size - rest, rest );
if( n > 0 ) rest -= n;
else if( n == 0 ) break;
else if( errno != EINTR && errno != EAGAIN ) break;
}
return ( rest > 0 ) ? size - rest : size;
}
// Returns the number of bytes really written.
// If (returned value < size), it is always an error.
//
int writeblock( const int fd, const char * buf, const int size ) throw()
{
int rest = size;
errno = 0;
while( rest > 0 )
{
errno = 0;
const int n = write( fd, buf + size - rest, rest );
if( n > 0 ) rest -= n;
else if( errno && errno != EINTR && errno != EAGAIN ) break;
}
return ( rest > 0 ) ? size - rest : size;
}
/*
int compress( const int inhandle, const Pretty_print & pp,
const struct stat * in_statsp, int * retvalp )
{
long long in_size = 0, out_size = 0;
if( verbosity >= 1 )
{
pp();
if( in_size <= 0 || out_size <= 0 )
std::fprintf( stderr, "no data compressed.\n" );
else
std::fprintf( stderr, "%6.3f:1, %6.3f bits/byte, "
"%5.2f%% saved, %lld in, %lld out.\n",
(double)in_size / out_size,
( 8.0 * out_size ) / in_size,
100.0 * ( 1.0 - ( (double)out_size / in_size ) ),
in_size, out_size );
}
return 0;
}
int decompress( const int inhandle, const Pretty_print & pp )
{
if( verbosity >= 1 )
std::fprintf( stderr, "done\n" );
return 0;
}
*/
int test_type( const int inhandle, const Pretty_print & pp )
{
unsigned char buf[5];
const char * msg = 0;
const int size = readblock( inhandle, (char *)buf, sizeof buf );
if( size == (int)sizeof buf )
{
if( buf[0] == 0x1F && buf[1] == 0x8B )
msg = "gzip";
else if( buf[0] == 'B' && buf[1] == 'Z' && buf[2] == 'h' )
msg = "bzip2";
else if( buf[0] == 'L' && buf[1] == 'Z' && buf[2] == 'I' && buf[3] == 'P' )
msg = "lzip";
else if( buf[1] == '7' && buf[2] == 'z' && buf[3] == 'X' && buf[4] == 'Z' )
msg = "xz";
}
const int retval = ( msg ? 0 : 1 );
if( verbosity >= 0 )
{
if( verbosity >= 1 ) pp();
if( !msg ) msg = "unknown";
std::printf( "%s\n", msg );
}
return retval;
}
extern "C" void signal_handler( int ) throw()
{
show_error( "Control-C or similar caught, quitting." );
cleanup_and_fail( 0 );
}
void set_signals() throw()
{
signal( SIGHUP, signal_handler );
signal( SIGINT, signal_handler );
signal( SIGTERM, signal_handler );
}
} // end namespace
int main( const int argc, const char * argv[] )
{
int inhandle = -1;
Mode program_mode = m_compress;
bool force = false;
bool keep_input_files = false;
bool to_stdout = false;
std::string input_filename;
std::string default_output_filename;
std::vector< std::string > filenames;
invocation_name = argv[0];
const Arg_parser::Option options[] =
{
{ 'c', "stdout", Arg_parser::no },
{ 'd', "decompress", Arg_parser::no },
{ 'f', "force", Arg_parser::no },
{ 'h', "help", Arg_parser::no },
{ 'k', "keep", Arg_parser::no },
{ 'o', "output", Arg_parser::yes },
{ 'q', "quiet", Arg_parser::no },
{ 't', "test", Arg_parser::no },
{ 'v', "verbose", Arg_parser::no },
{ 'V', "version", Arg_parser::no },
{ 0 , 0, Arg_parser::no } };
Arg_parser parser( argc, argv, options );
if( parser.error().size() ) // bad option
{ show_error( parser.error().c_str(), 0, true ); return 1; }
int argind = 0;
for( ; argind < parser.arguments(); ++argind )
{
const int code = parser.code( argind );
if( !code ) break; // no more options
const char * arg = parser.argument( argind ).c_str();
switch( code )
{
case 'c': to_stdout = true; break;
case 'd': program_mode = m_decompress; break;
case 'f': force = true; break;
case 'h': show_help(); return 0;
case 'k': keep_input_files = true; break;
case 'o': default_output_filename = arg; break;
case 'q': verbosity = -1; break;
case 't': program_mode = m_test; break;
case 'v': if( verbosity < 4 ) ++verbosity; break;
case 'V': show_version(); return 0;
default : internal_error( "uncaught option" );
}
}
bool filenames_given = false;
for( ; argind < parser.arguments(); ++argind )
{
if( parser.argument( argind ) != "-" ) filenames_given = true;
filenames.push_back( parser.argument( argind ) );
}
if( filenames.empty() ) filenames.push_back("-");
if( filenames_given ) set_signals();
Pretty_print pp( filenames );
if( program_mode == m_test )
outhandle = -1;
int retval = 0;
for( unsigned int i = 0; i < filenames.size(); ++i )
{
struct stat in_stats;
output_filename.clear();
if( !filenames[i].size() || filenames[i] == "-" )
{
input_filename.clear();
inhandle = STDIN_FILENO;
if( program_mode != m_test )
{
if( to_stdout || !default_output_filename.size() )
outhandle = STDOUT_FILENO;
else
{
if( program_mode == m_compress )
set_c_outname( default_output_filename );
else output_filename = default_output_filename;
if( !open_outstream( force ) )
{
if( outhandle == -1 && retval < 1 ) retval = 1;
close( inhandle ); inhandle = -1;
continue;
}
}
}
}
else
{
input_filename = filenames[i];
const int eindex = extension_index( input_filename );
inhandle = open_instream( input_filename, &in_stats, program_mode,
eindex, force, to_stdout );
if( inhandle < 0 ) { if( retval < 1 ) retval = 1; continue; }
if( program_mode != m_test )
{
if( to_stdout ) outhandle = STDOUT_FILENO;
else
{
if( program_mode == m_compress )
set_c_outname( input_filename );
else set_d_outname( input_filename, eindex );
if( !open_outstream( force ) )
{
if( outhandle == -1 && retval < 1 ) retval = 1;
close( inhandle ); inhandle = -1;
continue;
}
}
}
}
if( !check_tty( inhandle, program_mode ) ) return 1;
if( output_filename.size() && !to_stdout && program_mode != m_test )
delete_output_on_interrupt = true;
// const struct stat * in_statsp = input_filename.size() ? &in_stats : 0;
pp.set_name( input_filename );
int tmp = 0;
switch( program_mode )
{
case m_compress:
/*tmp = compress( inhandle, pp, in_statsp, &retval );*/ break;
case m_decompress:
/*tmp = decompress( inhandle, pp );*/ break;
case m_test:
tmp = test_type( inhandle, pp ); break;
}
if( tmp > retval ) retval = tmp;
if( tmp && program_mode != m_test ) cleanup_and_fail( retval );
/*
if( delete_output_on_interrupt )
close_and_set_permissions( in_statsp, &retval );
if( input_filename.size() )
{
close( inhandle ); inhandle = -1;
if( !keep_input_files && !to_stdout && program_mode != m_test )
std::remove( input_filename.c_str() );
}*/
}
if( outhandle >= 0 ) close( outhandle );
return retval;
}

View file

@ -10,8 +10,12 @@ export LC_ALL
objdir=`pwd`
testdir=`cd "$1" ; pwd`
ZCAT="${objdir}"/zcat
ZCMP="${objdir}"/zcmp
ZDIFF="${objdir}"/zdiff
ZGREP="${objdir}"/zgrep
ZEGREP="${objdir}"/zegrep
ZFGREP="${objdir}"/zfgrep
ZUTILS="${objdir}"/zutils
compressors="gzip bzip2 lzip"
extensions="gz bz2 lz"
framework_failure() { echo 'failure in testing framework'; exit 1; }
@ -54,11 +58,11 @@ echo -n .
for i in ${extensions}; do
"${ZDIFF}" --cmp in.$i || fail=1
"${ZCMP}" in.$i || fail=1
echo -n .
"${ZDIFF}" --cmp in in.$i || fail=1
"${ZCMP}" in in.$i || fail=1
echo -n .
"${ZDIFF}" --cmp in.$i in || fail=1
"${ZCMP}" in.$i in || fail=1
echo -n .
done
@ -107,6 +111,17 @@ echo -n .
echo -n .
"${ZGREP}" License in in.gz in.bz2 in.lz -- -in- 2>&1 > /dev/null || fail=1
echo -n .
"${ZEGREP}" License in 2>&1 > /dev/null || fail=1
echo -n .
"${ZFGREP}" License in 2>&1 > /dev/null || fail=1
echo -n .
if [ "gzip" != `"${ZUTILS}" -t in.gz` ]; then fail=1 ; fi
echo -n .
if [ "bzip2" != `"${ZUTILS}" -t in.bz2` ]; then fail=1 ; fi
echo -n .
if [ "lzip" != `"${ZUTILS}" -t in.lz` ]; then fail=1 ; fi
echo -n .
echo

32
zcat.in
View file

@ -59,28 +59,26 @@ retval=0
for i in "$@" ; do
if [ "$i" = "--" ] && [ ${two_hyphens} = 0 ] ; then two_hyphens=1
else
if [ -f "$i" ]; then
case "$i" in
*.gz | *.tgz)
prog="gzip -cdfq" ;;
*.bz2 | *.tbz | *.tbz2)
prog="bzip2 -cdfq" ;;
*.lz | *.tlz)
prog="lzip -cdfq" ;;
*.xz | *.txz)
prog="xz -cdfq" ;;
*)
prog=cat ;;
esac
elif [ -f "$i.gz" ]; then i="$i.gz" ; prog="gzip -cdfq"
elif [ -f "$i.bz2" ]; then i="$i.bz2" ; prog="bzip2 -cdfq"
elif [ -f "$i.lz" ]; then i="$i.lz" ; prog="lzip -cdfq"
elif [ -f "$i.xz" ]; then i="$i.xz" ; prog="xz -cdfq"
if [ ! -f "$i" ]; then
if [ -f "$i.gz" ]; then i="$i.gz"
elif [ -f "$i.bz2" ]; then i="$i.bz2"
elif [ -f "$i.lz" ]; then i="$i.lz"
elif [ -f "$i.xz" ]; then i="$i.xz"
else
echo "$0: File \"$i\" not found or not a regular file" 1>&2
if [ ${retval} = 0 ]; then retval=1 ; fi
continue
fi
fi
bindir=`echo "$0" | sed -e 's,[^/]*$,,'`
prog_name=`"${bindir}"zutils -t -- "$i"`
case "${prog_name}" in
gzip) prog="gzip -cdfq" ;;
bzip2) prog="bzip2 -cdfq" ;;
lzip) prog="lzip -cdfq" ;;
xz) prog="xz -cdfq" ;;
*) prog=cat ;;
esac
${prog} -- "$i" | cat ${args}
r=$?
if [ $r != 0 ]; then retval=$r ; fi

View file

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

View file

@ -95,24 +95,15 @@ fi
if [ -z "${file2}" ]; then
case "${file1}" in
*.gz)
file2=`printf "%s" "${file1}" | sed 's/.gz$//'` ;;
*.tgz)
file2=`printf "%s" "${file1}" | sed 's/tgz$/tar/'` ;;
*.bz2)
file2=`printf "%s" "${file1}" | sed 's/.bz2$//'` ;;
*.tbz)
file2=`printf "%s" "${file1}" | sed 's/tbz$/tar/'` ;;
*.tbz2)
file2=`printf "%s" "${file1}" | sed 's/tbz2$/tar/'` ;;
*.lz)
file2=`printf "%s" "${file1}" | sed 's/.lz$//'` ;;
*.tlz)
file2=`printf "%s" "${file1}" | sed 's/tlz$/tar/'` ;;
*.xz)
file2=`printf "%s" "${file1}" | sed 's/.xz$//'` ;;
*.txz)
file2=`printf "%s" "${file1}" | sed 's/txz$/tar/'` ;;
*.gz) file2=`printf "%s" "${file1}" | sed -e 's,.gz$,,'` ;;
*.tgz) file2=`printf "%s" "${file1}" | sed -e 's,tgz$,tar,'` ;;
*.bz2) file2=`printf "%s" "${file1}" | sed -e 's,.bz2$,,'` ;;
*.tbz) file2=`printf "%s" "${file1}" | sed -e 's,tbz$,tar,'` ;;
*.tbz2) file2=`printf "%s" "${file1}" | sed -e 's,tbz2$,tar,'` ;;
*.lz) file2=`printf "%s" "${file1}" | sed -e 's,.lz$,,'` ;;
*.tlz) file2=`printf "%s" "${file1}" | sed -e 's,tlz$,tar,'` ;;
*.xz) file2=`printf "%s" "${file1}" | sed -e 's,.xz$,,'` ;;
*.txz) file2=`printf "%s" "${file1}" | sed -e 's,txz$,tar,'` ;;
*)
if [ -f "${file1}.gz" ]; then file2="${file1}.gz"
elif [ -f "${file1}.bz2" ]; then file2="${file1}.bz2"
@ -127,18 +118,25 @@ fi
prog1=
prog2=
case "${file1}" in
*.gz | *.tgz) prog1=gzip ;;
*.bz2 | *.tbz | *.tbz2) prog1=bzip2 ;;
*.lz | *.tlz) prog1=lzip ;;
*.xz | *.txz) prog1=xz ;;
bindir=`echo "$0" | sed -e 's,[^/]*$,,'`
if [ -f "${file1}" ]; then
prog_name=`"${bindir}"zutils -t -- "${file1}"`
case "${prog_name}" in
gzip) prog1=gzip ;;
bzip2) prog1=bzip2 ;;
lzip) prog1=lzip ;;
xz) prog1=xz ;;
esac
case "${file2}" in
*.gz | *.tgz) prog2=gzip ;;
*.bz2 | *.tbz | *.tbz2) prog2=bzip2 ;;
*.lz | *.tlz) prog2=lzip ;;
*.xz | *.txz) prog2=xz ;;
fi
if [ -f "${file2}" ]; then
prog_name=`"${bindir}"zutils -t -- "${file2}"`
case "${prog_name}" in
gzip) prog2=gzip ;;
bzip2) prog2=bzip2 ;;
lzip) prog2=lzip ;;
xz) prog2=xz ;;
esac
fi
retval=0
if [ -n "${prog1}" ]; then

3
zegrep.in Normal file
View file

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

3
zfgrep.in Normal file
View file

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

View file

@ -27,6 +27,9 @@ while [ x"$1" != x ] ; do
echo "names corresponding to the supported compressors."
echo "The supported compressors are gzip, bzip2, lzip and xz."
echo
echo "Zegrep is a shortcut for \"zgrep -E\""
echo "Zfgrep is a shortcut for \"zgrep -F\""
echo
echo "Usage: $0 [OPTIONS] [GREP_OPTIONS] PATTERN [FILES]"
echo
echo "GREP_OPTIONS are passed directly to grep."
@ -81,28 +84,26 @@ retval=0
for i in "$@" ; do
if [ "$i" = "--" ] && [ ${two_hyphens} = 0 ] ; then two_hyphens=1
else
if [ -f "$i" ]; then
case "$i" in
*.gz | *.tgz)
prog="gzip -cdfq" ;;
*.bz2 | *.tbz | *.tbz2)
prog="bzip2 -cdfq" ;;
*.lz | *.tlz)
prog="lzip -cdfq" ;;
*.xz | *.txz)
prog="xz -cdfq" ;;
*)
prog=cat ;;
esac
elif [ -f "$i.gz" ]; then i="$i.gz" ; prog="gzip -cdfq"
elif [ -f "$i.bz2" ]; then i="$i.bz2" ; prog="bzip2 -cdfq"
elif [ -f "$i.lz" ]; then i="$i.lz" ; prog="lzip -cdfq"
elif [ -f "$i.xz" ]; then i="$i.xz" ; prog="xz -cdfq"
if [ ! -f "$i" ]; then
if [ -f "$i.gz" ]; then i="$i.gz"
elif [ -f "$i.bz2" ]; then i="$i.bz2"
elif [ -f "$i.lz" ]; then i="$i.lz"
elif [ -f "$i.xz" ]; then i="$i.xz"
else
echo "$0: File \"$i\" not found or not a regular file" 1>&2
if [ ${retval} = 0 ]; then retval=1 ; fi
continue
fi
fi
bindir=`echo "$0" | sed -e 's,[^/]*$,,'`
prog_name=`"${bindir}"zutils -t -- "$i"`
case "${prog_name}" in
gzip) prog="gzip -cdfq" ;;
bzip2) prog="bzip2 -cdfq" ;;
lzip) prog="lzip -cdfq" ;;
xz) prog="xz -cdfq" ;;
*) prog=cat ;;
esac
if [ ${list} = 1 ]; then
${prog} -- "$i" | grep ${args} 2>&1 > /dev/null && echo "$i"
r=$?
@ -110,11 +111,11 @@ for i in "$@" ; do
${prog} -- "$i" | grep ${args}
r=$?
else
j=`printf "%s" "$i" | sed 's/\\\\/\\\\\\\\/g'`
j=`printf "%s" "$j" | sed 's/|/\\\\|/g'`
j=`printf "%s" "$j" | sed 's/&/\\\\&/g'`
j=`printf "%s" "$i" | sed -e 's,\\\\,\\\\\\\\,g'`
j=`printf "%s" "$j" | sed -e 's,|,\\\\|,g'`
j=`printf "%s" "$j" | sed -e 's,&,\\\\&,g'`
j=`printf "%s" "$j" | tr '\n' ' '`
${prog} -- "$i" | grep ${args} | sed "s|^|${j}:|"
${prog} -- "$i" | grep ${args} | sed -e "s,^,${j}:,"
r=$?
fi
[ $r != 0 ] && retval="$r"