2025-02-24 05:04:07 +01:00
|
|
|
/* Zutils - Utilities dealing with compressed files
|
|
|
|
Copyright (C) 2009, 2010 Antonio Diaz Diaz.
|
2025-02-24 04:51:50 +01:00
|
|
|
|
|
|
|
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>
|
2025-02-24 05:04:07 +01:00
|
|
|
#include <list>
|
2025-02-24 04:51:50 +01:00
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
2025-02-24 05:04:07 +01:00
|
|
|
#include <dirent.h>
|
2025-02-24 04:51:50 +01:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/stat.h>
|
2025-02-24 05:04:07 +01:00
|
|
|
#if defined(__MSVCRT__) || defined(__OS2__)
|
|
|
|
#include <io.h>
|
|
|
|
#endif
|
2025-02-24 04:51:50 +01:00
|
|
|
|
|
|
|
#include "arg_parser.h"
|
2025-02-24 05:04:07 +01:00
|
|
|
#include "zutils.h"
|
2025-02-24 04:51:50 +01:00
|
|
|
|
2025-02-24 05:04:07 +01:00
|
|
|
#if CHAR_BIT != 8
|
|
|
|
#error "Environments where CHAR_BIT != 8 are not supported."
|
2025-02-24 04:51:50 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2025-02-24 05:04:07 +01:00
|
|
|
#ifdef O_BINARY
|
|
|
|
const int o_binary = O_BINARY;
|
|
|
|
#else
|
|
|
|
const int o_binary = 0;
|
|
|
|
#endif
|
2025-02-24 04:51:50 +01:00
|
|
|
|
2025-02-24 05:04:07 +01:00
|
|
|
enum Mode { m_none, m_zcat, m_zgrep, m_ztest };
|
2025-02-24 04:51:50 +01:00
|
|
|
|
|
|
|
|
|
|
|
void show_help() throw()
|
|
|
|
{
|
2025-02-24 05:04:07 +01:00
|
|
|
std::printf( "Zutils is a collection of utilities able to deal with any combination of\n" );
|
|
|
|
std::printf( "compressed and non-compressed files transparently. If any given file,\n" );
|
|
|
|
std::printf( "including standard input, is compressed, its uncompressed content is used.\n" );
|
|
|
|
std::printf( "The supported compressors are bzip2, gzip, lzip and xz.\n" );
|
|
|
|
std::printf( "\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" );
|
2025-02-24 04:51:50 +01:00
|
|
|
std::printf( " -h, --help display this help and exit\n" );
|
|
|
|
std::printf( " -V, --version output version information and exit\n" );
|
2025-02-24 05:04:07 +01:00
|
|
|
std::printf( " --zcat zcat operation\n" );
|
|
|
|
std::printf( " --zgrep zgrep operation\n" );
|
|
|
|
std::printf( " --ztest ztest operation\n" );
|
|
|
|
show_help_addr();
|
2025-02-24 04:51:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-02-24 05:04:07 +01:00
|
|
|
int simple_extension_index( const std::string & name ) throw()
|
2025-02-24 04:51:50 +01:00
|
|
|
{
|
2025-02-24 05:04:07 +01:00
|
|
|
for( int i = 0; simple_extensions[i]; ++i )
|
2025-02-24 04:51:50 +01:00
|
|
|
{
|
2025-02-24 05:04:07 +01:00
|
|
|
const std::string ext( simple_extensions[i] );
|
2025-02-24 04:51:50 +01:00
|
|
|
if( name.size() > ext.size() &&
|
|
|
|
name.compare( name.size() - ext.size(), ext.size(), ext ) == 0 )
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-02-24 05:04:07 +01:00
|
|
|
int open_instream( std::string & input_filename, const Mode program_mode ) throw()
|
2025-02-24 04:51:50 +01:00
|
|
|
{
|
2025-02-24 05:04:07 +01:00
|
|
|
int infd = open( input_filename.c_str(), O_RDONLY | o_binary );
|
|
|
|
if( infd < 0 )
|
2025-02-24 04:51:50 +01:00
|
|
|
{
|
2025-02-24 05:04:07 +01:00
|
|
|
if( ( program_mode == m_zcat || program_mode == m_zgrep )
|
|
|
|
&& simple_extension_index( input_filename ) < 0 )
|
2025-02-24 04:51:50 +01:00
|
|
|
{
|
2025-02-24 05:04:07 +01:00
|
|
|
for( int i = 0; simple_extensions[i]; ++i )
|
2025-02-24 04:51:50 +01:00
|
|
|
{
|
2025-02-24 05:04:07 +01:00
|
|
|
const std::string name( input_filename + simple_extensions[i] );
|
|
|
|
infd = open( name.c_str(), O_RDONLY | o_binary );
|
|
|
|
if( infd >= 0 ) { input_filename = name; break; }
|
2025-02-24 04:51:50 +01:00
|
|
|
}
|
|
|
|
}
|
2025-02-24 05:04:07 +01:00
|
|
|
if( infd < 0 && verbosity >= 0 )
|
|
|
|
std::fprintf( stderr, "%s: Can't open input file `%s': %s.\n",
|
|
|
|
util_name, input_filename.c_str(), std::strerror( errno ) );
|
2025-02-24 04:51:50 +01:00
|
|
|
}
|
2025-02-24 05:04:07 +01:00
|
|
|
return infd;
|
2025-02-24 04:51:50 +01:00
|
|
|
}
|
|
|
|
|
2025-02-24 05:04:07 +01:00
|
|
|
#include "zcat.cc"
|
|
|
|
#include "zgrep.cc"
|
|
|
|
#include "ztest.cc"
|
2025-02-24 04:51:50 +01:00
|
|
|
|
2025-02-24 05:04:07 +01:00
|
|
|
} // end namespace
|
2025-02-24 04:51:50 +01:00
|
|
|
|
|
|
|
|
2025-02-24 05:04:07 +01:00
|
|
|
int main( const int argc, const char * const argv[] )
|
2025-02-24 04:51:50 +01:00
|
|
|
{
|
2025-02-24 05:04:07 +01:00
|
|
|
enum { help_opt = 256, verbose_opt, zcat_opt, zgrep_opt, ztest_opt };
|
|
|
|
const Arg_parser::Option * options = 0;
|
|
|
|
int infd = -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];
|
2025-02-24 04:51:50 +01:00
|
|
|
|
2025-02-24 05:04:07 +01:00
|
|
|
const Arg_parser::Option m_zcat_options[] =
|
2025-02-24 04:51:50 +01:00
|
|
|
{
|
2025-02-24 05:04:07 +01:00
|
|
|
{ '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
|
|
|
|
{ '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 },
|
|
|
|
{ verbose_opt, "verbose", Arg_parser::no },
|
|
|
|
{ zcat_opt, "zcat", Arg_parser::no },
|
|
|
|
{ 0 , 0, Arg_parser::no } };
|
|
|
|
|
|
|
|
const Arg_parser::Option m_zgrep_options[] =
|
2025-02-24 04:51:50 +01:00
|
|
|
{
|
2025-02-24 05:04:07 +01:00
|
|
|
{ '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
|
|
|
|
{ '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
|
|
|
|
{ help_opt, "help", Arg_parser::no },
|
|
|
|
{ verbose_opt, "verbose", Arg_parser::no },
|
|
|
|
{ zgrep_opt, "zgrep", Arg_parser::no },
|
|
|
|
{ 0 , 0, Arg_parser::no } };
|
|
|
|
|
|
|
|
const Arg_parser::Option m_ztest_options[] =
|
2025-02-24 04:58:15 +01:00
|
|
|
{
|
2025-02-24 05:04:07 +01:00
|
|
|
{ 'h', "help", Arg_parser::no },
|
|
|
|
{ 'q', "quiet", Arg_parser::no },
|
|
|
|
{ 'r', "recursive", Arg_parser::no },
|
|
|
|
{ 'v', "verbose", Arg_parser::no },
|
|
|
|
{ 'V', "version", Arg_parser::no },
|
|
|
|
{ ztest_opt, "ztest", Arg_parser::no },
|
|
|
|
{ 0 , 0, Arg_parser::no } };
|
|
|
|
|
|
|
|
{ // parse operation
|
|
|
|
const Arg_parser::Option operations[] =
|
2025-02-24 04:58:15 +01:00
|
|
|
{
|
2025-02-24 05:04:07 +01:00
|
|
|
{ '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; }
|
2025-02-24 04:58:15 +01:00
|
|
|
|
2025-02-24 05:04:07 +01:00
|
|
|
if( parser.arguments() > 0 )
|
2025-02-24 04:58:15 +01:00
|
|
|
{
|
2025-02-24 05:04:07 +01:00
|
|
|
switch( parser.code( 0 ) )
|
2025-02-24 04:58:15 +01:00
|
|
|
{
|
2025-02-24 05:04:07 +01:00
|
|
|
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" );
|
2025-02-24 04:58:15 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-02-24 05:04:07 +01:00
|
|
|
#if defined(__MSVCRT__) || defined(__OS2__)
|
|
|
|
_setmode( STDIN_FILENO, O_BINARY );
|
|
|
|
_setmode( STDOUT_FILENO, O_BINARY );
|
|
|
|
#endif
|
2025-02-24 04:58:15 +01:00
|
|
|
|
2025-02-24 05:04:07 +01:00
|
|
|
if( program_mode == m_none )
|
2025-02-24 04:51:50 +01:00
|
|
|
{
|
2025-02-24 05:04:07 +01:00
|
|
|
show_error( "You must specify the operation to be performed.", 0, true );
|
|
|
|
return 1;
|
2025-02-24 04:51:50 +01:00
|
|
|
}
|
2025-02-24 05:04:07 +01:00
|
|
|
} // end parse operation
|
2025-02-24 04:51:50 +01:00
|
|
|
|
2025-02-24 05:04:07 +01:00
|
|
|
const Arg_parser parser( argc, argv, options );
|
2025-02-24 04:51:50 +01:00
|
|
|
if( parser.error().size() ) // bad option
|
2025-02-24 05:04:07 +01:00
|
|
|
{ show_error( parser.error().c_str(), 0, true );
|
|
|
|
return ( program_mode == m_zcat ) ? 1 : 2; }
|
2025-02-24 04:51:50 +01:00
|
|
|
|
|
|
|
int argind = 0;
|
2025-02-24 05:04:07 +01:00
|
|
|
bool grep_list = false;
|
|
|
|
bool grep_show_name = true;
|
|
|
|
bool grep_pattern_found = false;
|
2025-02-24 04:51:50 +01:00
|
|
|
for( ; argind < parser.arguments(); ++argind )
|
|
|
|
{
|
|
|
|
const int code = parser.code( argind );
|
2025-02-24 05:04:07 +01:00
|
|
|
const char * arg = parser.argument( argind ).c_str();
|
|
|
|
if( !code )
|
2025-02-24 04:51:50 +01:00
|
|
|
{
|
2025-02-24 05:04:07 +01:00
|
|
|
if( program_mode == m_zgrep && !grep_pattern_found )
|
|
|
|
{ grep_args.push_back( arg ); grep_pattern_found = true; continue; }
|
|
|
|
else break; // no more options
|
2025-02-24 04:51:50 +01:00
|
|
|
}
|
2025-02-24 05:04:07 +01:00
|
|
|
switch( program_mode )
|
|
|
|
{
|
|
|
|
case m_none: internal_error( "invalid operation" );
|
|
|
|
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 = true; break;
|
|
|
|
case 'L': grep_args.push_back( "-L" ); grep_list = true; 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
|
2025-02-24 04:51:50 +01:00
|
|
|
|
2025-02-24 05:04:07 +01:00
|
|
|
if( program_mode == m_zgrep && !grep_pattern_found )
|
|
|
|
{ show_error( "Pattern not found.", 0, true ); return 2; }
|
2025-02-24 04:58:15 +01:00
|
|
|
|
2025-02-24 04:51:50 +01:00
|
|
|
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("-");
|
|
|
|
|
2025-02-24 05:04:07 +01:00
|
|
|
int retval = ( ( program_mode == m_zgrep ) ? 1 : 0 );
|
|
|
|
while( !filenames.empty() )
|
2025-02-24 04:51:50 +01:00
|
|
|
{
|
2025-02-24 05:04:07 +01:00
|
|
|
input_filename = filenames.front();
|
|
|
|
filenames.pop_front();
|
|
|
|
if( !input_filename.size() || input_filename == "-" )
|
2025-02-24 04:51:50 +01:00
|
|
|
{
|
|
|
|
input_filename.clear();
|
2025-02-24 05:04:07 +01:00
|
|
|
infd = STDIN_FILENO;
|
2025-02-24 04:51:50 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2025-02-24 05:04:07 +01:00
|
|
|
if( recursive )
|
2025-02-24 04:51:50 +01:00
|
|
|
{
|
2025-02-24 05:04:07 +01:00
|
|
|
struct stat st;
|
|
|
|
if( !stat( input_filename.c_str(), &st ) && S_ISDIR( st.st_mode ) )
|
2025-02-24 04:51:50 +01:00
|
|
|
{
|
2025-02-24 05:04:07 +01:00
|
|
|
DIR * const dirp = opendir( input_filename.c_str() );
|
|
|
|
if( !dirp )
|
2025-02-24 04:51:50 +01:00
|
|
|
{
|
2025-02-24 05:04:07 +01:00
|
|
|
if( verbosity >= 0 )
|
|
|
|
std::fprintf( stderr, "%s: Can't open directory `%s': %s.\n",
|
|
|
|
util_name, input_filename.c_str(), std::strerror( errno ) );
|
|
|
|
if( retval < 1 ) retval = 1; continue;
|
2025-02-24 04:51:50 +01:00
|
|
|
}
|
2025-02-24 05:04:07 +01:00
|
|
|
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;
|
2025-02-24 04:51:50 +01:00
|
|
|
}
|
|
|
|
}
|
2025-02-24 05:04:07 +01:00
|
|
|
infd = open_instream( input_filename, program_mode );
|
|
|
|
if( infd < 0 ) { if( retval < 1 ) retval = 1; continue; }
|
2025-02-24 04:51:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int tmp = 0;
|
|
|
|
switch( program_mode )
|
|
|
|
{
|
2025-02-24 05:04:07 +01:00
|
|
|
case m_none:
|
|
|
|
break;
|
|
|
|
case m_zcat:
|
|
|
|
tmp = cat( infd, input_filename, cat_options );
|
|
|
|
break;
|
|
|
|
case m_zgrep:
|
|
|
|
if( infd == STDIN_FILENO )
|
|
|
|
tmp = zgrep_stdin( infd, grep_args );
|
|
|
|
else tmp = zgrep_file( infd, input_filename, grep_args,
|
|
|
|
grep_list, grep_show_name );
|
|
|
|
break;
|
|
|
|
case m_ztest:
|
|
|
|
if( infd == STDIN_FILENO )
|
|
|
|
tmp = ztest_stdin( infd, ztest_args );
|
|
|
|
else tmp = ztest_file( infd, input_filename, ztest_args );
|
2025-02-24 04:58:15 +01:00
|
|
|
break;
|
2025-02-24 04:51:50 +01:00
|
|
|
}
|
2025-02-24 05:04:07 +01:00
|
|
|
if( program_mode == m_zgrep )
|
|
|
|
{ if( tmp == 0 || ( tmp == 2 && retval == 1 ) ) retval = tmp; }
|
|
|
|
else if( tmp > retval ) retval = tmp;
|
2025-02-24 04:58:15 +01:00
|
|
|
|
2025-02-24 04:51:50 +01:00
|
|
|
if( input_filename.size() )
|
2025-02-24 05:04:07 +01:00
|
|
|
{ close( infd ); infd = -1; }
|
|
|
|
}
|
|
|
|
|
|
|
|
if( std::fclose( stdout ) != 0 )
|
|
|
|
{
|
|
|
|
show_error( "Can't close stdout", errno );
|
|
|
|
switch( program_mode )
|
2025-02-24 04:51:50 +01:00
|
|
|
{
|
2025-02-24 05:04:07 +01:00
|
|
|
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;
|
2025-02-24 04:58:15 +01:00
|
|
|
}
|
2025-02-24 04:51:50 +01:00
|
|
|
}
|
|
|
|
return retval;
|
|
|
|
}
|