extern "C" {
+#include <regex.h>
#include <unistd.h>
}
PRINT_DEFAULT } print = PRINT_DEFAULT;
static enum { GREP_BOTH, GREP_ID, GREP_TEXT } grep_frame = GREP_BOTH;
-// TODO: use regexec(3)
-static bool
-grep(const string &pattern, TagLib::MPEG::File &file, const char *fn)
+static int
+grep(const regex_t ®ex, TagLib::MPEG::File &file, const char *fn)
{
if (!file.hasID3v2Tag()) {
- return false;
+ return REG_NOMATCH;
}
bool found = false;
for (const auto *frame : file.ID3v2Tag()->frameList()) {
break;
}
const string &s = sstream.str();
- if (s.find(pattern, 0) == string::npos) {
+ int status = regexec(®ex, s.c_str(), 0, nullptr, 0);
+ if (status == REG_NOMATCH) {
continue;
}
+ if (status != 0) {
+ return status;
+ }
found = true;
if (print == PRINT_BOTH) {
cout << fn << ":" << s << endl;
if (found && print == PRINT_FILE) {
cout << fn << endl;
}
- return found;
+ return found ? 0 : REG_NOMATCH;
+}
+
+static void
+regex_error(int status, const regex_t ®ex)
+{
+ char message[512];
+ regerror(status, ®ex, message, sizeof(message));
+ cerr << message << endl;
}
int
main(int argc, char **argv)
{
- char *pattern_c = nullptr;
+ bool ignore_case = false, use_ere = false;
+ char *pattern = nullptr;
int c;
- while ((c = getopt(argc, argv, "e:HhlqsQ:")) != -1) {
+ while ((c = getopt(argc, argv, "Eie:HhlqsQ:")) != -1) {
switch (c) {
+ case 'E':
+ use_ere = true;
+ break;
+ case 'i':
+ ignore_case = true;
+ break;
case 'e':
- pattern_c = optarg;
+ pattern = optarg;
break;
case 'H':
print = PRINT_BOTH;
argc -= optind; argv += optind;
// TODO: multiple patterns
- if (pattern_c == nullptr) {
+ if (pattern == nullptr) {
if (argc == 0) {
cerr << "no pattern" << endl;
return 2;
}
- pattern_c = *argv++;
+ pattern = *argv++;
argc--;
}
- string pattern(pattern_c);
+ int cflags = REG_NOSUB;
+ if (ignore_case) cflags |= REG_ICASE;
+ if (use_ere) cflags |= REG_EXTENDED;
+ regex_t regex;
+ int status = regcomp(®ex, pattern, cflags);
+ if (status != 0) {
+ regex_error(status, regex);
+ return 3;
+ }
if (print == PRINT_DEFAULT) {
print = argc > 1 ? PRINT_BOTH : PRINT_MATCH;
bad_files++;
continue;
}
- found |= grep(pattern, f, fn);
+ int status = grep(regex, f, fn);
+ if (status == 0) {
+ found = true;
+ } else if (status != REG_NOMATCH) {
+ regex_error(status, regex);
+ return 3;
+ }
}
if (bad_files > 0) {
- return 3;
+ return 4;
}
if (found) {
return 0;