WvStreams
|
00001 /* -*- Mode: C++ -*- 00002 * Worldvisions Weaver Software: 00003 * Copyright (C) 1997-2004 Net Integration Technologies, Inc. 00004 * 00005 * A clone of grep(1) that is written entirely in WvStreams 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 }