From: epg@pretzelnet.org <> Date: Sun, 12 Jan 2014 01:59:50 +0000 (-0800) Subject: lame id3v2-grep tool X-Git-Url: https://diplodocus.org/git/flac-archive/commitdiff_plain/6b068d17c33b79554fdb3006d438c8a203812527?ds=sidebyside lame id3v2-grep tool --- diff --git a/id3v2-grep.cc b/id3v2-grep.cc new file mode 100644 index 0000000..90bbeea --- /dev/null +++ b/id3v2-grep.cc @@ -0,0 +1,144 @@ +extern "C" { +#include +} + +#include +#include +#include + +#include +#include +#include + +using std::cerr; +using std::cout; +using std::endl; +using std::string; +using std::stringstream; + +const string FRAME_ID_OPT("id"); +const string FRAME_TEXT_OPT("text"); + +static bool diag = true; +static enum { PRINT_BOTH, PRINT_FILE, PRINT_MATCH, PRINT_NONE, + 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) +{ + if (!file.hasID3v2Tag()) { + return false; + } + bool found = false; + for (const auto *frame : file.ID3v2Tag()->frameList()) { + stringstream sstream; + switch (grep_frame) { + case GREP_BOTH: + sstream << frame->frameID() << "=" << frame->toString(); + break; + case GREP_ID: + sstream << frame->frameID(); + break; + case GREP_TEXT: + sstream << frame->toString(); + break; + } + const string &s = sstream.str(); + if (s.find(pattern, 0) == string::npos) { + continue; + } + found = true; + if (print == PRINT_BOTH) { + cout << fn << ":" << s << endl; + } else if (print == PRINT_MATCH) { + cout << s << endl; + } + } + if (found && print == PRINT_FILE) { + cout << fn << endl; + } + return found; +} + +int +main(int argc, char **argv) +{ + char *pattern_c = nullptr; + int c; + while ((c = getopt(argc, argv, "e:HhlqsQ:")) != -1) { + switch (c) { + case 'e': + pattern_c = optarg; + break; + case 'H': + print = PRINT_BOTH; + break; + case 'h': + print = PRINT_MATCH; + break; + case 'l': + print = PRINT_FILE; + break; + case 'q': + print = PRINT_NONE; + break; + case 's': + diag = false; + break; + case 'Q': + if (optarg == FRAME_ID_OPT) { + grep_frame = GREP_ID; + } else if (optarg == FRAME_TEXT_OPT) { + grep_frame = GREP_TEXT; + } else { + cerr << "invalid option -- '-Q" << optarg << endl; + return 2; + } + break; + default: + // getopt printed an error. + return 2; + } + } + argc -= optind; argv += optind; + + // TODO: multiple patterns + if (pattern_c == nullptr) { + if (argc == 0) { + cerr << "no pattern" << endl; + return 2; + } + pattern_c = *argv++; + argc--; + } + string pattern(pattern_c); + + if (print == PRINT_DEFAULT) { + print = argc > 1 ? PRINT_BOTH : PRINT_MATCH; + } + + int bad_files = 0; + bool found = false; + for (; *argv != nullptr; argv++) { + char *fn = *argv; + TagLib::MPEG::File f(fn); + if (!f.isValid()) { + if (diag) { + cerr << "failed to open " << fn << endl; + } + bad_files++; + continue; + } + found |= grep(pattern, f, fn); + } + + if (bad_files > 0) { + return 3; + } + if (found) { + return 0; + } + return 1; +}