]> diplodocus.org Git - flac-archive/commitdiff
lame id3v2-grep tool
authorepg@pretzelnet.org <>
Sun, 12 Jan 2014 01:59:50 +0000 (17:59 -0800)
committerepg@pretzelnet.org <>
Sun, 12 Jan 2014 01:59:50 +0000 (17:59 -0800)
id3v2-grep.cc [new file with mode: 0644]

diff --git a/id3v2-grep.cc b/id3v2-grep.cc
new file mode 100644 (file)
index 0000000..90bbeea
--- /dev/null
@@ -0,0 +1,144 @@
+extern "C" {
+#include <unistd.h>
+}
+
+#include <ostream>
+#include <sstream>
+#include <string>
+
+#include <id3v2frame.h>
+#include <id3v2tag.h>
+#include <mpegfile.h>
+
+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;
+}