# include # include # include // stat # include // getopt # include // scandir # include // getcwd # include // errno # include "qmp3.hh" # include "qfile.hh" # include "qexception.hh" # include "qreport.hh" # include "qmisc.hh" using namespace std; #ifdef NLS # include # include # define _(s) gettext (s) #else # define _(s) (s) #endif struct options { bool all, html, recursive, showall, showdirs, showfiles, showsummary, split, verbose; string outfilename; ofstream *out; }; void usage () { cerr << ' ' << APPNAME << ": generate reports from mp3 files and directories\n"; cerr << " syntax: " << APPNAME << " [option]... file...\n"; cerr << _(" options:\n"); cerr << _(" -a, --all-files: report all files, not just *.mp3\n"); cerr << _(" -A, --show-all: implies -d, -f, -s\n"); // cerr << _(" --all-mp3: consider files as mp3 streams"\n"); cerr << _(" -d, --dirs: show a report for every directory\n"); cerr << _(" -f, --files: show a report for every file\n"); cerr << _(" -h, --help: show this help and exit\n"); cerr << _(" -H, --html: output in html format (default is text)\n"); // cerr << _(" -o, --outfilename : output file (by default stdout)\n"); cerr << _(" -r, --recursive: scan directories\n"); // cerr << _(" -s: scan streams for validity (slower but more accurate)\n"); cerr << _(" -s, --summary: show a summary report\n"); cerr << _(" -S, --split: split report across visited directories\n"); cerr << _(" -v, --verbose: show more detailed info\n"); cerr << _(" -V, --version: show version and exit\n"); // allow user defined format for showing // treure segons com i quan el temps que triga } qreport report_file (string filename, struct options &opts) { try { if (opts.all) { qfile f(filename); if (opts.verbose) cerr << _("reporting file") << " '" << filename << "'\n"; qreport r(f); if (opts.showfiles) { if (opts.html) { r.html(opts.out); *opts.out << "
" << endl; } else *opts.out << r << endl; } return r; } } catch (qexception e) { cerr << filename << ": " << e << endl; } return qreport(); } qreport report_mp3 (string mp3name, struct options &opts) { try { qmp3 mp3(mp3name); if (mp3.isVbr()) { if (opts.verbose) cerr << mp3.getName() << _(": vbr detected => automatic check") << endl; mp3.scan(); } if (opts.verbose) cerr << _("reporting mp3 file") << " '" << mp3name << "'\n"; qreport r(mp3); if (opts.showfiles) { if (opts.html) { r.html(opts.out); *opts.out << "
" << endl; } else *opts.out << r << endl; } return r; } catch (qexception e) { cerr << mp3name << ": " << e << endl; return qreport(); } } qreport report_directory (string dirname, struct options &opts) { if (opts.verbose) cerr << _("reporting directory") << " '" << dirname << "'\n"; qreport dirreport(dirname); if (!opts.recursive) { if (opts.verbose) cerr << APPNAME << ": '" << dirname << ' ' << _("is a directory") << '\n'; return dirreport; } char previous_wd[1025],wd[1025]; ofstream *out; if (opts.split) { if (getcwd(previous_wd,sizeof(previous_wd))==NULL) { cerr << _("cannot get current directory") << " (" << dirname << "): " << strerror(errno) << '\n'; return dirreport; } if (chdir(dirname.c_str())) { cerr << _("cannot move to dir") << dirname << ": " << strerror(errno) << '\n'; return dirreport; } if (getcwd(wd,sizeof(wd))==NULL) { cerr << _("cannot get current directory") << " (" << dirname << "): " << strerror(errno) << '\n'; return dirreport; } char *index = strrchr(wd,'/'); string outfilename; if (*index && index!=wd) outfilename = string((index+1)); else outfilename = string ("qmp3report"); if (opts.html) outfilename += string(".html"); else outfilename += string(".txt"); if (opts.verbose) cerr << _("opening output file") << " '" << outfilename << "'\n"; out = opts.out; opts.out = new ofstream(outfilename.c_str()); dirname = string("."); } int n; struct dirent **namelist; if ((n = scandir(dirname.c_str(),&namelist,0,alphasort))<0) { cerr << APPNAME << ':' << _("cannot scan") << " '" << dirname << "'\n"; return dirreport; } for (int i=0; id_name,".") || !strcmp(namelist[i]->d_name,"..")) continue; struct stat filestat; string filepathname; if (dirname==".") filepathname = string(namelist[i]->d_name); else filepathname = dirname + string("/") + string(namelist[i]->d_name); if (stat(filepathname.c_str(),&filestat)) { cerr << APPNAME << ": " << _("error reading") << " '" << dirname << "' status: " << strerror(errno) << '\n'; continue; } if (S_ISDIR(filestat.st_mode)) { dirreport.add(report_directory(filepathname,opts)); continue; } if (S_ISREG(filestat.st_mode)) { int length = filepathname.length(); if (length>4 && !strncasecmp((char*)(&(filepathname.c_str()[length-4])),".mp3",4)) dirreport.add(report_mp3(filepathname,opts)); else { if (opts.all) dirreport.add(report_file(filepathname,opts)); } continue; } if (opts.verbose) cerr << filepathname << _(" is a special file. skipping.") << endl; } if (opts.split) { if (opts.html) *opts.out << " 
" << endl; else *opts.out << endl; *opts.out << dirreport << endl; opts.out->close(); opts.out = out; chdir (previous_wd); } if (opts.showdirs && dirreport.getFiles()>0) { if (opts.html) { // if split fer que en lloc d'assenyalar al directori apunti al report // que conté. dirreport.html(opts.out,dirreport.getName()+string("/")+dirreport.getName()+string(".html")); *opts.out << "
" << endl; } else *opts.out << dirreport << endl; } return dirreport; } int main (int argc, char **argv) { int option; struct options opts={false,false,false,false,false,false,false,false,false,""}; static struct option long_options[] = { {"all-files",no_argument,0,'a'}, {"show-all",no_argument,0,'A'}, // {"all-mp3",no_argument,0,'Q'}, ?????? {"dirs",no_argument,0,'d'}, {"files",no_argument,0,'f'}, {"help",no_argument,0,'h'}, {"html",no_argument,0,'H'}, {"recursive",no_argument,0,'r'}, {"summary",no_argument,0,'s'}, {"split",no_argument,0,'S'}, {"verbose",no_argument,0,'v'}, {"version",no_argument,0,'V'}, {0,0,0,0} }; #ifdef NLS setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); #endif // un altre dia, per defecte llegir *.mp3 ... if (argc==1) { usage(); return 1; } // supress getopt error message opterr = 0; while ((option = getopt_long(argc, argv, "aAdfhHo:rsSvV",long_options,0)) != EOF) switch (option) { case 'a': opts.all = true; break; case 'A': opts.showdirs=opts.showfiles=opts.showsummary = true; break; case 'd': opts.showdirs = true; break; case 'f': opts.showfiles = true; break; case 'h': usage(); return 0; break; case 'H': opts.html = true; break; case 'r': opts.recursive = true; break; case 's': opts.showsummary = true;break; case 'S': opts.split = true; break; case 'v': opts.verbose = true; break; case 'V': cerr << APPNAME << " - " << _("version") << ' ' << VERSION << _("build") << ' ' << __DATE__ << '\n'; return 0; break; case '?': default: cerr << APPNAME << ": " << _("option") << " '" << argv[optind-1] << "' " << _("is not recognized or bad used") << '\n'; usage(); return 1; } if (argc<=optind) { // hauríem de fer *.mp3 ... cerr << APPNAME << _(": no input file(s)") << endl; usage(); return 1; } qreport base; opts.out = new ofstream; if (opts.split) opts.out = new ofstream("/dev/null"); else { opts.out = new ofstream; if (opts.html) *opts.out << "\nqmp3report\n\n\n\n"; } for (; optind4 && !strncasecmp((char*)(&(argv[optind][length-4])),".mp3",4)) base.add(report_mp3(argv[optind],opts)); else { if (opts.all) base.add(report_file(argv[optind],opts)); } continue; } if (opts.verbose) cerr << argv[optind] << _(" is a special file. skipping.") << endl; } catch (qexception e) { cerr << e << endl; } } if (opts.showsummary) { if (!opts.html || opts.split) { cout << base << endl; } else { base.html(new ofstream); cout << "
" << endl; } } if (!opts.split) { if (opts.html) { *opts.out << "\n\n"; } } opts.out->close(); }