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.

cueprint.c 9.5 KiB

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