grep.cpp 6.7 KB

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