]> diplodocus.org Git - flac-archive/blob - id3v2-grep.cc
90bbeeabcfc315bc845f5df5674e8106ea623d6d
[flac-archive] / id3v2-grep.cc
1 extern "C" {
2 #include <unistd.h>
3 }
4
5 #include <ostream>
6 #include <sstream>
7 #include <string>
8
9 #include <id3v2frame.h>
10 #include <id3v2tag.h>
11 #include <mpegfile.h>
12
13 using std::cerr;
14 using std::cout;
15 using std::endl;
16 using std::string;
17 using std::stringstream;
18
19 const string FRAME_ID_OPT("id");
20 const string FRAME_TEXT_OPT("text");
21
22 static bool diag = true;
23 static enum { PRINT_BOTH, PRINT_FILE, PRINT_MATCH, PRINT_NONE,
24 PRINT_DEFAULT } print = PRINT_DEFAULT;
25 static enum { GREP_BOTH, GREP_ID, GREP_TEXT } grep_frame = GREP_BOTH;
26
27 // TODO: use regexec(3)
28 static bool
29 grep(const string &pattern, TagLib::MPEG::File &file, const char *fn)
30 {
31 if (!file.hasID3v2Tag()) {
32 return false;
33 }
34 bool found = false;
35 for (const auto *frame : file.ID3v2Tag()->frameList()) {
36 stringstream sstream;
37 switch (grep_frame) {
38 case GREP_BOTH:
39 sstream << frame->frameID() << "=" << frame->toString();
40 break;
41 case GREP_ID:
42 sstream << frame->frameID();
43 break;
44 case GREP_TEXT:
45 sstream << frame->toString();
46 break;
47 }
48 const string &s = sstream.str();
49 if (s.find(pattern, 0) == string::npos) {
50 continue;
51 }
52 found = true;
53 if (print == PRINT_BOTH) {
54 cout << fn << ":" << s << endl;
55 } else if (print == PRINT_MATCH) {
56 cout << s << endl;
57 }
58 }
59 if (found && print == PRINT_FILE) {
60 cout << fn << endl;
61 }
62 return found;
63 }
64
65 int
66 main(int argc, char **argv)
67 {
68 char *pattern_c = nullptr;
69 int c;
70 while ((c = getopt(argc, argv, "e:HhlqsQ:")) != -1) {
71 switch (c) {
72 case 'e':
73 pattern_c = optarg;
74 break;
75 case 'H':
76 print = PRINT_BOTH;
77 break;
78 case 'h':
79 print = PRINT_MATCH;
80 break;
81 case 'l':
82 print = PRINT_FILE;
83 break;
84 case 'q':
85 print = PRINT_NONE;
86 break;
87 case 's':
88 diag = false;
89 break;
90 case 'Q':
91 if (optarg == FRAME_ID_OPT) {
92 grep_frame = GREP_ID;
93 } else if (optarg == FRAME_TEXT_OPT) {
94 grep_frame = GREP_TEXT;
95 } else {
96 cerr << "invalid option -- '-Q" << optarg << endl;
97 return 2;
98 }
99 break;
100 default:
101 // getopt printed an error.
102 return 2;
103 }
104 }
105 argc -= optind; argv += optind;
106
107 // TODO: multiple patterns
108 if (pattern_c == nullptr) {
109 if (argc == 0) {
110 cerr << "no pattern" << endl;
111 return 2;
112 }
113 pattern_c = *argv++;
114 argc--;
115 }
116 string pattern(pattern_c);
117
118 if (print == PRINT_DEFAULT) {
119 print = argc > 1 ? PRINT_BOTH : PRINT_MATCH;
120 }
121
122 int bad_files = 0;
123 bool found = false;
124 for (; *argv != nullptr; argv++) {
125 char *fn = *argv;
126 TagLib::MPEG::File f(fn);
127 if (!f.isValid()) {
128 if (diag) {
129 cerr << "failed to open " << fn << endl;
130 }
131 bad_files++;
132 continue;
133 }
134 found |= grep(pattern, f, fn);
135 }
136
137 if (bad_files > 0) {
138 return 3;
139 }
140 if (found) {
141 return 0;
142 }
143 return 1;
144 }