00001
00002
00003
00004
00005
00006
00007
00008
00009 #include "wvstring.h"
00010 #include "wvstringlist.h"
00011 #include "wvargs.h"
00012 #include "wvregex.h"
00013 #include "wvfile.h"
00014
00015
00016 #define VERSION "0.1.0"
00017
00018 static void output_filename(WvStringParm filename,
00019 char suffix, bool display_nulls)
00020 {
00021 wvout->print(!!filename? filename: WvFastString("(standard input)"));
00022 if (display_nulls)
00023 wvout->write("\0", 1);
00024 else
00025 wvout->write(&suffix, 1);
00026 }
00027
00028
00029 static int match(const WvRegex ®ex, WvStringParm filename, WvStream *file,
00030 bool invert_match, bool display_filename, bool display_line_number,
00031 bool display_nulls, bool display_nothing, bool end_on_first_match)
00032 {
00033 int count = 0;
00034 int lineno = 0;
00035 while (file->isok())
00036 {
00037 const char *line = file->blocking_getline(-1);
00038 if (line == NULL) break;
00039 ++lineno;
00040
00041 bool result = regex.match(line);
00042 if (invert_match) result = !result;
00043
00044 if (result)
00045 {
00046 ++count;
00047 if (end_on_first_match) return count;
00048 }
00049
00050 if (!result || display_nothing) continue;
00051
00052 if (display_filename)
00053 output_filename(filename, ':', display_nulls);
00054 if (display_line_number)
00055 wvout->print("%s:", lineno);
00056 wvout->print("%s\n", line);
00057 }
00058 return count;
00059 }
00060
00061
00062 int main(int argc, char **argv)
00063 {
00064 WvArgs args;
00065
00066 args.set_version("wvgrep (WvStreams grep) " VERSION "\n");
00067 args.set_email("<" WVPACKAGE_BUGREPORT ">");
00068
00069 bool opt_count = false;
00070 args.add_set_bool_option('c', "count", WvString::null, opt_count);
00071
00072 bool opt_extended_regexp = false;
00073 args.add_set_bool_option('E', "extended-regexp", WvString::null, opt_extended_regexp);
00074
00075 WvString opt_regexp;
00076 args.add_option('e', "regexp", WvString::null, WvString::null, opt_regexp);
00077
00078 bool opt_basic_regexp = false;
00079 args.add_set_bool_option('G', "basic-regexp", WvString::null, opt_basic_regexp);
00080
00081 bool opt_with_filename = false;
00082 args.add_set_bool_option('H', "with-filename", WvString::null, opt_with_filename);
00083
00084 bool opt_no_filename = false;
00085 args.add_set_bool_option('h', "no-filename", WvString::null, opt_no_filename);
00086
00087 bool opt_ignore_case = false;
00088 args.add_set_bool_option('i', "ignore-case", WvString::null, opt_ignore_case);
00089 args.add_set_bool_option('y', WvString::null, "Synonym for -i", opt_ignore_case);
00090
00091 bool opt_files_without_match = false;
00092 args.add_set_bool_option('L', "files-without-match", WvString::null, opt_files_without_match);
00093
00094 bool opt_files_with_matches = false;
00095 args.add_set_bool_option('l', "files-with-matches", WvString::null, opt_files_with_matches);
00096
00097 bool opt_line_number = false;
00098 args.add_set_bool_option('n', "line-number", WvString::null, opt_line_number);
00099
00100 bool opt_quiet = false;
00101 args.add_set_bool_option('q', "quiet", WvString::null, opt_quiet);
00102 args.add_set_bool_option(0, "silent", "Synonym for --quiet", opt_quiet);
00103
00104 bool opt_no_messages = false;
00105 args.add_set_bool_option('s', "no-message", WvString::null, opt_no_messages);
00106
00107 bool opt_invert_match = false;
00108 args.add_set_bool_option('v', "invert-match", WvString::null, opt_invert_match);
00109
00110 bool opt_line_regexp = false;
00111 args.add_set_bool_option('x', "line-regexp", WvString::null, opt_line_regexp);
00112
00113 bool opt_null = false;
00114 args.add_set_bool_option('Z', "null", WvString::null, opt_null);
00115
00116 args.add_required_arg("PATTERN");
00117 args.add_optional_arg("FILE", true);
00118
00119 args.set_help_header("Search for PATTERN in each FILE or standard input.");
00120 args.set_help_footer("With no FILE, this program reads standard input.");
00121
00122 WvStringList remaining_args;
00123 args.process(argc, argv, &remaining_args);
00124
00125 if (!opt_regexp && !remaining_args.isempty())
00126 opt_regexp = remaining_args.popstr();
00127
00128 int cflags = WvFastString(argv[0]) == "egrep"?
00129 WvRegex::EXTENDED: WvRegex::BASIC;
00130 if (opt_extended_regexp) cflags = WvRegex::EXTENDED;
00131 if (opt_basic_regexp) cflags = WvRegex::BASIC;
00132 if (opt_ignore_case) cflags |= WvRegex::ICASE;
00133
00134 WvString regex_str;
00135 if (opt_line_regexp)
00136 regex_str = WvString("^%s$", opt_regexp);
00137 else regex_str = opt_regexp;
00138
00139 WvRegex regex(regex_str, cflags);
00140 if (!regex.isok())
00141 {
00142 WvString errstr = regex.errstr();
00143 wverr->print("%s: Invalid regular expression", argv[0]);
00144 if (!!errstr) wverr->print(errstr);
00145 wverr->write("\n", 1);
00146 return 2;
00147 }
00148
00149 bool display_filename = remaining_args.count() >= 2;
00150 if (opt_with_filename) display_filename = true;
00151 if (opt_no_filename) display_filename = false;
00152
00153 if (remaining_args.isempty())
00154 remaining_args.append(WvString::null);
00155
00156 bool found_match = false;
00157 WvStringList::Iter filename(remaining_args);
00158 for (filename.rewind(); filename.next(); )
00159 {
00160 WvStream *file;
00161 if (!!*filename)
00162 file = new WvFile(*filename, O_RDONLY);
00163 else
00164 file = wvcon;
00165
00166 if (!file->isok())
00167 {
00168 if (!opt_no_messages)
00169 wverr->print("%s: %s: %s\n", argv[0],
00170 *filename, file->errstr());
00171 if (!!*filename) WVRELEASE(file);
00172 continue;
00173 }
00174
00175 int count = match(regex, *filename, file,
00176 opt_invert_match, display_filename, opt_line_number, opt_null,
00177 opt_count || opt_files_without_match || opt_files_with_matches,
00178 opt_quiet);
00179
00180 if (!!*filename) WVRELEASE(file);
00181
00182 if (opt_files_with_matches || opt_files_without_match)
00183 {
00184 bool display = opt_files_with_matches? count>0: count==0;
00185 if (display)
00186 output_filename(*filename, '\n', opt_null);
00187 }
00188 else if(opt_count)
00189 {
00190 if (display_filename)
00191 output_filename(*filename, ':', opt_null);
00192 wvout->print("%s\n", count);
00193 }
00194
00195 found_match = found_match || count > 0;
00196 if (opt_quiet && found_match) break;
00197 }
00198
00199 return found_match? 0: 1;
00200 }