WvStreams
wvgrep.cc
1/* -*- Mode: C++ -*-
2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2004 Net Integration Technologies, Inc.
4 *
5 * A clone of grep(1) that is written entirely in WvStreams
6 *
7 */
8
9#include "wvstring.h"
10#include "wvstringlist.h"
11#include "wvargs.h"
12#include "wvregex.h"
13#include "wvfile.h"
14
15
16#define VERSION "0.1.0"
17
18static void output_filename(WvStringParm filename,
19 char suffix, bool display_nulls)
20{
21 wvout->print(!!filename? filename: WvFastString("(standard input)"));
22 if (display_nulls)
23 wvout->write("\0", 1);
24 else
25 wvout->write(&suffix, 1);
26}
27
28
29static int match(const WvRegex &regex, WvStringParm filename, WvStream *file,
30 bool invert_match, bool display_filename, bool display_line_number,
31 bool display_nulls, bool display_nothing, bool end_on_first_match)
32{
33 int count = 0;
34 int lineno = 0;
35 while (file->isok())
36 {
37 const char *line = file->blocking_getline(-1);
38 if (line == NULL) break;
39 ++lineno;
40
41 bool result = regex.match(line);
42 if (invert_match) result = !result;
43
44 if (result)
45 {
46 ++count;
47 if (end_on_first_match) return count;
48 }
49
50 if (!result || display_nothing) continue;
51
52 if (display_filename)
53 output_filename(filename, ':', display_nulls);
54 if (display_line_number)
55 wvout->print("%s:", lineno);
56 wvout->print("%s\n", line);
57 }
58 return count;
59}
60
61
62int main(int argc, char **argv)
63{
64 WvArgs args;
65
66 args.set_version("wvgrep (WvStreams grep) " VERSION "\n");
67 args.set_email("<" WVPACKAGE_BUGREPORT ">");
68
69 bool opt_count = false;
70 args.add_set_bool_option('c', "count", WvString::null, opt_count);
71
72 bool opt_extended_regexp = false;
73 args.add_set_bool_option('E', "extended-regexp", WvString::null, opt_extended_regexp);
74
75 WvString opt_regexp;
76 args.add_option('e', "regexp", WvString::null, WvString::null, opt_regexp);
77
78 bool opt_basic_regexp = false;
79 args.add_set_bool_option('G', "basic-regexp", WvString::null, opt_basic_regexp);
80
81 bool opt_with_filename = false;
82 args.add_set_bool_option('H', "with-filename", WvString::null, opt_with_filename);
83
84 bool opt_no_filename = false;
85 args.add_set_bool_option('h', "no-filename", WvString::null, opt_no_filename);
86
87 bool opt_ignore_case = false;
88 args.add_set_bool_option('i', "ignore-case", WvString::null, opt_ignore_case);
89 args.add_set_bool_option('y', WvString::null, "Synonym for -i", opt_ignore_case);
90
91 bool opt_files_without_match = false;
92 args.add_set_bool_option('L', "files-without-match", WvString::null, opt_files_without_match);
93
94 bool opt_files_with_matches = false;
95 args.add_set_bool_option('l', "files-with-matches", WvString::null, opt_files_with_matches);
96
97 bool opt_line_number = false;
98 args.add_set_bool_option('n', "line-number", WvString::null, opt_line_number);
99
100 bool opt_quiet = false;
101 args.add_set_bool_option('q', "quiet", WvString::null, opt_quiet);
102 args.add_set_bool_option(0, "silent", "Synonym for --quiet", opt_quiet);
103
104 bool opt_no_messages = false;
105 args.add_set_bool_option('s', "no-message", WvString::null, opt_no_messages);
106
107 bool opt_invert_match = false;
108 args.add_set_bool_option('v', "invert-match", WvString::null, opt_invert_match);
109
110 bool opt_line_regexp = false;
111 args.add_set_bool_option('x', "line-regexp", WvString::null, opt_line_regexp);
112
113 bool opt_null = false;
114 args.add_set_bool_option('Z', "null", WvString::null, opt_null);
115
116 args.add_required_arg("PATTERN");
117 args.add_optional_arg("FILE", true);
118
119 args.set_help_header("Search for PATTERN in each FILE or standard input.");
120 args.set_help_footer("With no FILE, this program reads standard input.");
121
122 WvStringList remaining_args;
123 args.process(argc, argv, &remaining_args);
124
125 if (!opt_regexp && !remaining_args.isempty())
126 opt_regexp = remaining_args.popstr();
127
128 int cflags = WvFastString(argv[0]) == "egrep"?
129 WvRegex::EXTENDED: WvRegex::BASIC;
130 if (opt_extended_regexp) cflags = WvRegex::EXTENDED;
131 if (opt_basic_regexp) cflags = WvRegex::BASIC;
132 if (opt_ignore_case) cflags |= WvRegex::ICASE;
133
134 WvString regex_str;
135 if (opt_line_regexp)
136 regex_str = WvString("^%s$", opt_regexp);
137 else regex_str = opt_regexp;
138
139 WvRegex regex(regex_str, cflags);
140 if (!regex.isok())
141 {
142 WvString errstr = regex.errstr();
143 wverr->print("%s: Invalid regular expression", argv[0]);
144 if (!!errstr) wverr->print(errstr);
145 wverr->write("\n", 1);
146 return 2;
147 }
148
149 bool display_filename = remaining_args.count() >= 2;
150 if (opt_with_filename) display_filename = true;
151 if (opt_no_filename) display_filename = false;
152
153 if (remaining_args.isempty())
154 remaining_args.append(WvString::null);
155
156 bool found_match = false;
157 WvStringList::Iter filename(remaining_args);
158 for (filename.rewind(); filename.next(); )
159 {
160 WvStream *file;
161 if (!!*filename)
162 file = new WvFile(*filename, O_RDONLY);
163 else
164 file = wvcon;
165
166 if (!file->isok())
167 {
168 if (!opt_no_messages)
169 wverr->print("%s: %s: %s\n", argv[0],
170 *filename, file->errstr());
171 if (!!*filename) WVRELEASE(file);
172 continue;
173 }
174
175 int count = match(regex, *filename, file,
176 opt_invert_match, display_filename, opt_line_number, opt_null,
177 opt_count || opt_files_without_match || opt_files_with_matches,
178 opt_quiet);
179
180 if (!!*filename) WVRELEASE(file);
181
182 if (opt_files_with_matches || opt_files_without_match)
183 {
184 bool display = opt_files_with_matches? count>0: count==0;
185 if (display)
186 output_filename(*filename, '\n', opt_null);
187 }
188 else if(opt_count)
189 {
190 if (display_filename)
191 output_filename(*filename, ':', opt_null);
192 wvout->print("%s\n", count);
193 }
194
195 found_match = found_match || count > 0;
196 if (opt_quiet && found_match) break;
197 }
198
199 return found_match? 0: 1;
200}
WvArgs - Sane command-line argument processing for WvStreams.
void add_optional_arg(WvStringParm desc, bool multiple=false)
Add an optional argument to the list of parameters.
Definition wvargs.cc:982
void set_help_header(WvStringParm header)
Set the introductory help message, printed at the beginning of –help.
Definition wvargs.cc:831
bool process(int argc, char **argv, WvStringList *remaining_args=NULL)
Process the command line arguments passed to main() using the options provided through calls to add_o...
Definition wvargs.cc:784
void set_help_footer(WvStringParm footer)
Set the descriptive help message, printed at the end of –help.
Definition wvargs.cc:837
void set_version(WvStringParm version)
Set the –version string.
Definition wvargs.cc:819
void add_option(char short_option, WvStringParm long_option, WvStringParm desc, WvStringParm arg_desc, int &val)
Add a switch that takes an integer argument.
Definition wvargs.cc:888
void add_required_arg(WvStringParm desc, bool multiple=false)
Add a required argument to the list of parameters.
Definition wvargs.cc:966
void set_email(WvStringParm email)
Set the e-mail address for bug reports.
Definition wvargs.cc:825
void add_set_bool_option(char short_option, WvStringParm long_option, WvStringParm desc, bool &val)
Add a boolean option, which, when specified, sets the specified boolean variable to true.
Definition wvargs.cc:856
virtual bool isok() const
By default, returns true if geterr() == 0.
A WvFastString acts exactly like a WvString, but can take (const char *) strings without needing to a...
WvFile implements a stream connected to a file or Unix device.
WvRegex – Unified support for regular expressions.
Unified support for streams, that is, sequences of bytes that may or may not be ready for read/write ...
char * blocking_getline(time_t wait_msec, int separator='\n', int readahead=1024)
This is a version of getline() that allows you to block for more data to arrive.
Definition wvstream.cc:602
virtual bool isok() const
return true if the stream is actually usable right now
Definition wvstream.cc:445
virtual size_t write(const void *buf, size_t count)
Write data to the stream.
Definition wvstream.cc:532
This is a WvList of WvStrings, and is a really handy way to parse strings.
WvString popstr()
get the first string in the list, or an empty string if the list is empty.
WvString is an implementation of a simple and efficient printable-string class.