You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 18 година
пре 19 година
пре 19 година
пре 19 година
пре 18 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
пре 19 година
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. /*
  2. * cueprint.c -- print cd information based on a template
  3. *
  4. * Copyright (C) 2004, 2005, 2006 Svend Sorensen
  5. * For license terms, see the file COPYING in this distribution.
  6. */
  7. #include <ctype.h> /* isdigit() */
  8. #include <getopt.h> /* getopt_long() */
  9. #include <stdio.h> /* fprintf(), printf(), snprintf(), stderr */
  10. #include <stdlib.h> /* exit() */
  11. #include <string.h> /* strcasecmp() */
  12. #include "cuefile.h"
  13. #if HAVE_CONFIG_H
  14. #include "config.h"
  15. #else /* not HAVE_CONFIG_H */
  16. #define PACKAGE_STRING "cueprint"
  17. #endif /* HAVE_CONFIG_H */
  18. /* default templates */
  19. #define D_TEMPLATE "\
  20. Disc Information\n\
  21. arranger: %A\n\
  22. composer: %C\n\
  23. genre: %G\n\
  24. message: %M\n\
  25. no. of tracks: %N\n\
  26. performer: %P\n\
  27. songwriter: %S\n\
  28. title: %T\n\
  29. UPC/EAN: %U\n\
  30. "
  31. #define T_TEMPLATE "\
  32. \n\
  33. Track %n Information\n\
  34. arranger: %a\n\
  35. composer: %c\n\
  36. genre: %g\n\
  37. ISRC: %i\n\
  38. message: %m\n\
  39. track number: %n\n\
  40. perfomer: %p\n\
  41. title: %t\n\
  42. ISRC (CD-TEXT): %u\n\
  43. "
  44. /* default string to print for unset (NULL) values */
  45. #define VALUE_UNSET ""
  46. /*
  47. * *_get_* functions can return an int or a char *
  48. */
  49. typedef union {
  50. int ival;
  51. char *sval;
  52. char cval;
  53. } Value;
  54. char *progname;
  55. /* Print usage information and exit */
  56. void usage(int status)
  57. {
  58. if (0 == status) {
  59. printf("Usage: %s [option...] [file...]\n", progname);
  60. printf("Report disc and track information from a CUE or TOC file.\n"
  61. "\n"
  62. "OPTIONS\n"
  63. "-h, --help print usage\n"
  64. "-i, --input-format cue|toc set format of file(s)\n"
  65. "-n, --track-number <number> only print track information for single track\n"
  66. "-d, --disc-template <template> set disc template\n"
  67. "-t, --track-template <template> set track template\n"
  68. "-V, --version print version information\n"
  69. "\n"
  70. "Default disc template: %s\n"
  71. "Default track template: %s\n"
  72. "See the manual page for more information.\n",
  73. D_TEMPLATE, T_TEMPLATE);
  74. } else {
  75. fprintf(stderr, "Try `%s --help' for more information.\n", progname);
  76. }
  77. exit (status);
  78. }
  79. /* Print version information and exit */
  80. void version()
  81. {
  82. printf("%s\n", PACKAGE_STRING);
  83. exit(0);
  84. }
  85. /*
  86. * TODO: Shouldn't we be using vprintf() to help us out with this stuff?
  87. * (Branden Robinson)
  88. */
  89. void disc_field(char *conv, int length, Cd *cd, Value *value)
  90. {
  91. char *c; /* pointer to conversion character */
  92. Cdtext *cdtext = NULL;
  93. cdtext = cd_get_cdtext(cd);
  94. c = conv + length - 1;
  95. /*
  96. * After setting value, set *c to specify value type:
  97. * 'd' integer
  98. * 's' string
  99. * 'c' character
  100. */
  101. switch (*c) {
  102. case 'A':
  103. value->sval = cdtext_get(PTI_ARRANGER, cdtext);
  104. *c = 's';
  105. break;
  106. case 'C':
  107. value->sval = cdtext_get(PTI_COMPOSER, cdtext);
  108. *c = 's';
  109. break;
  110. case 'G':
  111. value->sval = cdtext_get(PTI_GENRE, cdtext);
  112. *c = 's';
  113. break;
  114. case 'M':
  115. value->sval = cdtext_get(PTI_MESSAGE, cdtext);
  116. *c = 's';
  117. break;
  118. case 'N':
  119. value->ival = cd_get_ntrack(cd);
  120. *c = 'd';
  121. break;
  122. case 'P':
  123. value->sval = cdtext_get(PTI_PERFORMER, cdtext);
  124. *c = 's';
  125. break;
  126. case 'R':
  127. value->sval = cdtext_get(PTI_ARRANGER, cdtext);
  128. *c = 's';
  129. break;
  130. case 'S':
  131. value->sval = cdtext_get(PTI_SONGWRITER, cdtext);
  132. *c = 's';
  133. break;
  134. case 'T':
  135. value->sval = cdtext_get(PTI_TITLE, cdtext);
  136. *c = 's';
  137. break;
  138. case 'U':
  139. value->sval = cdtext_get(PTI_UPC_ISRC, cdtext);
  140. *c = 's';
  141. break;
  142. default:
  143. value->cval = *c;
  144. *c = 'c';
  145. break;
  146. }
  147. }
  148. void track_field(char *conv, int length, Cd *cd, int trackno, Value *value)
  149. {
  150. char *c; /* pointer to conversion character */
  151. Track *track = NULL;
  152. Cdtext *cdtext = NULL;
  153. track = cd_get_track(cd, trackno);
  154. cdtext = track_get_cdtext(track);
  155. c = conv + length - 1;
  156. switch (*c) {
  157. case 'a':
  158. value->sval = cdtext_get(PTI_ARRANGER, cdtext);
  159. *c = 's';
  160. break;
  161. case 'c':
  162. value->sval = cdtext_get(PTI_COMPOSER, cdtext);
  163. *c = 's';
  164. break;
  165. case 'f':
  166. value->sval = track_get_filename(track);
  167. *c = 's';
  168. break;
  169. case 'g':
  170. value->sval = cdtext_get(PTI_GENRE, cdtext);
  171. *c = 's';
  172. break;
  173. case 'i':
  174. value->sval = track_get_isrc(track);
  175. *c = 's';
  176. break;
  177. case 'm':
  178. value->sval = cdtext_get(PTI_MESSAGE, cdtext);
  179. *c = 's';
  180. break;
  181. case 'n':
  182. value->ival = trackno;
  183. *c = 'd';
  184. break;
  185. case 'p':
  186. value->sval = cdtext_get(PTI_PERFORMER, cdtext);
  187. *c = 's';
  188. break;
  189. case 's':
  190. value->sval = cdtext_get(PTI_SONGWRITER, cdtext);
  191. *c = 's';
  192. break;
  193. case 't':
  194. value->sval = cdtext_get(PTI_TITLE, cdtext);
  195. *c = 's';
  196. break;
  197. case 'u':
  198. value->sval = cdtext_get(PTI_UPC_ISRC, cdtext);
  199. *c = 's';
  200. break;
  201. default:
  202. disc_field(conv, length, cd, value);
  203. break;
  204. }
  205. }
  206. /*
  207. * Print a conversion specification.
  208. * [flag(s)][width][.precision]<conversion-char>
  209. */
  210. void print_conv(char *start, int length, Cd *cd, int trackno)
  211. {
  212. char *conv; /* copy of conversion specification */
  213. Value value;
  214. char *c; /* pointer to conversion-char */
  215. /* TODO: use strndup? */
  216. conv = malloc((unsigned) (length + 1));
  217. strncpy(conv, start, length);
  218. conv[length] = '\0';
  219. /* conversion character */
  220. if (0 == trackno) {
  221. disc_field(conv, length, cd, &value);
  222. } else {
  223. track_field(conv, length, cd, trackno, &value);
  224. }
  225. c = conv + length - 1;
  226. switch (*c) {
  227. case 'c':
  228. printf(conv, value.cval);
  229. break;
  230. case 'd':
  231. printf(conv, value.ival);
  232. break;
  233. case 's':
  234. if (NULL == value.sval)
  235. printf(conv, VALUE_UNSET);
  236. else
  237. printf(conv, value.sval);
  238. break;
  239. default:
  240. printf("%d: ", strlen(conv));
  241. printf("%s", conv);
  242. }
  243. free(conv);
  244. }
  245. void cd_printf(char *format, Cd *cd, int trackno)
  246. {
  247. char *c; /* pointer into format */
  248. char *conv_start;
  249. int conv_length;
  250. for (c = format; '\0' != *c; c++) {
  251. if ('%' == *c) {
  252. conv_start = c;
  253. conv_length = 1;
  254. c++;
  255. /* flags */
  256. while ( \
  257. '-' == *c \
  258. || '+' == *c \
  259. || ' ' == *c \
  260. || '0' == *c \
  261. || '#' == *c \
  262. ) {
  263. conv_length++;
  264. c++;
  265. }
  266. /* field width */
  267. /* '*' not recognized */
  268. while (0 != isdigit(*c)) {
  269. conv_length++;
  270. c++;
  271. }
  272. /* precision */
  273. /* '*' not recognized */
  274. if ('.' == *c) {
  275. conv_length++;
  276. c++;
  277. while (0 != isdigit(*c)) {
  278. conv_length++;
  279. c++;
  280. }
  281. }
  282. /* length modifier (h, l, or L) */
  283. /* not recognized */
  284. /* conversion character */
  285. conv_length++;
  286. print_conv(conv_start, conv_length, cd, trackno);
  287. } else {
  288. putchar(*c);
  289. }
  290. }
  291. }
  292. int info(char *name, int format, int trackno, char *d_template, char *t_template)
  293. {
  294. Cd *cd = NULL;
  295. int ntrack;
  296. if (NULL == (cd = cf_parse(name, &format))) {
  297. fprintf(stderr, "%s: error: unable to parse input file"
  298. " `%s'\n", progname, name);
  299. return -1;
  300. }
  301. ntrack = cd_get_ntrack(cd);
  302. if (-1 == trackno) {
  303. cd_printf(d_template, cd, 0);
  304. for (trackno = 1; trackno <= ntrack; trackno++) {
  305. cd_printf(t_template, cd, trackno);
  306. }
  307. } else if (0 == trackno) {
  308. cd_printf(d_template, cd, trackno);
  309. } else if (0 < trackno && ntrack >= trackno) {
  310. cd_printf(t_template, cd, trackno);
  311. } else {
  312. fprintf(stderr, "%s: error: track number out of range\n", progname);
  313. return -1;
  314. }
  315. return 0;
  316. }
  317. /*
  318. * Translate escape sequences in a string.
  319. * The string is overwritten and terminated.
  320. * TODO: this does not handle octal and hexidecimal escapes
  321. * except for \0
  322. */
  323. void translate_escapes(char *s)
  324. {
  325. char *read;
  326. char *write;
  327. read = s;
  328. write = s;
  329. while ('\0' != *read) {
  330. if ('\\' == *read) {
  331. read++;
  332. switch (*read) {
  333. case 'a':
  334. *write = '\a';
  335. break;
  336. case 'b':
  337. *write = '\b';
  338. break;
  339. case 'f':
  340. *write = '\f';
  341. break;
  342. case 'n':
  343. *write = '\n';
  344. break;
  345. case 'r':
  346. *write = '\r';
  347. break;
  348. case 't':
  349. *write = '\t';
  350. break;
  351. case 'v':
  352. *write = '\v';
  353. break;
  354. case '0':
  355. *write = '\0';
  356. break;
  357. default:
  358. /* ?, ', " are handled by the default */
  359. *write = *read;
  360. break;
  361. }
  362. } else {
  363. *write = *read;
  364. }
  365. read++;
  366. write++;
  367. }
  368. *write = '\0';
  369. }
  370. int main(int argc, char *argv[])
  371. {
  372. int format = UNKNOWN;
  373. int trackno = -1; /* track number (-1 = unspecified,
  374. 0 = disc info) */
  375. char *d_template = NULL; /* disc template */
  376. char *t_template = NULL; /* track template */
  377. int ret = 0; /* return value of info() */
  378. /* option variables */
  379. int c;
  380. /* getopt_long() variables */
  381. extern char *optarg;
  382. extern int optind;
  383. static struct option longopts[] = {
  384. {"help", no_argument, NULL, 'h'},
  385. {"input-format", required_argument, NULL, 'i'},
  386. {"track-number", required_argument, NULL, 'n'},
  387. {"disc-template", required_argument, NULL, 'd'},
  388. {"track-template", required_argument, NULL, 't'},
  389. {"version", no_argument, NULL, 'V'},
  390. {NULL, 0, NULL, 0}
  391. };
  392. progname = argv[0];
  393. while (-1 != (c = getopt_long(argc, argv, "hi:n:d:t:V", longopts, NULL))) {
  394. switch (c) {
  395. case 'h':
  396. usage(0);
  397. break;
  398. case 'i':
  399. if (0 == strcmp("cue", optarg)) {
  400. format = CUE;
  401. } else if (0 == strcmp("toc", optarg)) {
  402. format = TOC;
  403. } else {
  404. fprintf(stderr, "%s: error: unknown input file"
  405. " format `%s'\n", progname, optarg);
  406. usage(1);
  407. }
  408. break;
  409. case 'n':
  410. trackno = atoi(optarg);
  411. break;
  412. case 'd':
  413. d_template = optarg;
  414. break;
  415. case 't':
  416. t_template = optarg;
  417. break;
  418. case 'V':
  419. version();
  420. break;
  421. default:
  422. usage(1);
  423. break;
  424. }
  425. }
  426. /* If no disc or track template is set, use the defaults for both. */
  427. /* TODO: alternative to strdup to get variable strings? */
  428. if (NULL == d_template && NULL == t_template) {
  429. d_template = strdup(D_TEMPLATE);
  430. t_template = strdup(T_TEMPLATE);
  431. } else {
  432. if (NULL == d_template) {
  433. d_template = strdup("");
  434. }
  435. if (NULL == t_template) {
  436. t_template = strdup("");
  437. }
  438. }
  439. /* Translate escape sequences. */
  440. translate_escapes(d_template);
  441. translate_escapes(t_template);
  442. /* What we do depends on the number of operands. */
  443. if (optind == argc) {
  444. /* No operands: report information about stdin. */
  445. ret = info("-", format, trackno, d_template, t_template);
  446. } else {
  447. /* Report information about each operand. */
  448. for (; optind < argc; optind++) {
  449. ret = info(argv[optind], format, trackno, d_template, t_template);
  450. /* Exit if info() returns nonzero. */
  451. if (!ret) {
  452. break;
  453. }
  454. }
  455. }
  456. return ret;
  457. }