1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
|
/*
*
* Copyright (c) 2004
* John Maddock
*
* Use, modification and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*/
#include <boost/regex.hpp>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#ifdef BOOST_MSVC
#pragma warning(disable:4512 4244)
#endif
#include <boost/program_options.hpp>
namespace po = boost::program_options;
int after_context;
int before_context;
bool print_byte_offset;
bool count_only;
std::string pattern;
bool print_non_matching_files;
bool files_only;
bool print_line_numbers;
boost::regex_constants::syntax_option_type flags = boost::regex_constants::basic;
boost::regex re;
boost::smatch what;
std::string current_file;
int file_count;
void process_stream(std::istream& is)
{
std::string line;
int match_found = 0;
int linenum = 1;
while(std::getline(is, line))
{
bool result = boost::regex_search(line, what, re);
if(result)
{
if(print_non_matching_files)
return;
if(files_only)
{
std::cout << current_file << std::endl;
return;
}
if(!match_found && !count_only && (file_count > 1))
{
std::cout << current_file << ":\n";
}
++match_found;
if(!count_only)
{
if(print_line_numbers)
{
std::cout << linenum << ":";
}
if(print_byte_offset)
{
std::cout << what.position() << ":";
}
std::cout << what[0] << std::endl;
}
}
++linenum;
}
if(count_only && match_found)
{
std::cout << match_found << " matches found in file " << current_file << std::endl;
}
else if(print_non_matching_files && !match_found)
{
std::cout << current_file << std::endl;
}
}
void process_file(const std::string& name)
{
current_file = name;
std::ifstream is(name.c_str());
if(is.bad())
{
std::cerr << "Unable to open file " << name << std::endl;
}
process_stream(is);
}
int main(int argc, char * argv[])
{
try{
po::options_description opts("Options");
opts.add_options()
("help,h", "produce help message")
//("after-context,A", po::value<int>(&after_context)->default_value(0), "Print arg lines of trailing context after matching lines. Places a line containing -- between contiguous groups of matches.")
//("before-context,B", po::value<int>(&before_context)->default_value(0), "Print arg lines of leading context before matching lines. Places a line containing -- between contiguous groups of matches.")
//("context,C", po::value<int>(), "Print arg lines of output context. Places a line containing -- between contiguous groups of matches.")
("byte-offset,b", "Print the byte offset within the input file before each line of output.")
("count,c", "Suppress normal output; instead print a count of matching lines for each input file. With the -v, --invert-match option (see below), count non-matching lines.")
("extended-regexp,E", "Interpret PATTERN as an POSIX-extended regular expression.")
("perl-regexp,P", "Interpret PATTERN as a Perl regular expression.")
//("regexp,e", po::value<std::string>(&pattern), "Use PATTERN as the pattern; useful to protect patterns beginning with -.")
("basic-regexp,G", "Interpret arg as a POSIX-basic regular expression (see below). This is the default.")
("ignore-case,i", "Ignore case distinctions in both the PATTERN and the input files.")
("files-without-match,L", "Suppress normal output; instead print the name of each input file from which no output would normally have been printed. The scanning will stop on the first match.")
("files-with-matches,l", "Suppress normal output; instead print the name of each input file from which output would normally have been printed. The scanning will stop on the first match.")
("line-number,n", "Prefix each line of output with the line number within its input file.")
;
// Hidden options, will be allowed both on command line and
// in config file, but will not be shown to the user.
po::options_description hidden("Hidden options");
hidden.add_options()
("input-file", po::value< std::vector<std::string> >(), "input file")
("input-pattern", po::value< std::string >(), "input file")
;
po::options_description cmdline_options;
cmdline_options.add(opts).add(hidden);
po::positional_options_description p;
p.add("input-pattern", 1);
p.add("input-file", -1);
po::variables_map vm;
po::store(po::command_line_parser(argc, argv).options(cmdline_options)/*.options(hidden)*/.positional(p).run(), vm);
po::notify(vm);
if (vm.count("help"))
{
std::cout << opts << "\n";
return 0;
}
if (vm.count("context"))
{
after_context = vm["context"].as< int >();
before_context = after_context;
}
if(vm.count("extended-regexp"))
{
flags = boost::regex_constants::extended;
}
if(vm.count("basic-regexp"))
{
flags = boost::regex_constants::basic;
}
if(vm.count("perl-regexp"))
{
flags = boost::regex_constants::perl;
}
if(vm.count("ignore-case"))
{
flags |= boost::regex_constants::icase;
}
if(vm.count("byte-offset"))
{
print_byte_offset = true;
}
if(vm.count("count"))
{
count_only = true;
}
if(vm.count("files-without-match"))
{
print_non_matching_files = true;
}
if(vm.count("files-with-matches"))
{
files_only = true;
}
if(vm.count("line-number"))
{
print_line_numbers = true;
}
if(vm.count("input-pattern"))
{
pattern = vm["input-pattern"].as< std::string >();
re.assign(pattern, flags);
}
else
{
std::cerr << "No pattern specified" << std::endl;
return 1;
}
if (vm.count("input-file"))
{
const std::vector<std::string>& files = vm["input-file"].as< std::vector<std::string> >();
file_count = files.size();
for(std::vector<std::string>::const_iterator i = files.begin(); i != files.end(); ++i)
{
process_file(*i);
}
}
else
{
// no input files, scan stdin instead:
process_stream(std::cin);
}
}
catch(const std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}
|