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.
 
 
 
 
 
 

427 lines
8.1 KiB

  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 <unistd.h> /* getopt() */
  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. char *progname;
  40. void usage (int status)
  41. {
  42. if (0 == status) {
  43. fprintf(stdout, "%s: usage: cueprint [-h] [-i cue|toc] [-n TRACKNUMBER] [-d TEMPLATE] [-t TEMPLATE] [file...]\n", progname);
  44. fputs("\
  45. \n\
  46. OPTIONS\n\
  47. -h print usage\n\
  48. -i cue|toc set format of file(s)\n\
  49. -n TRACKNUMBER only print track information for track TRACKNUMBER\n\
  50. -d TEMPLATE set disc template (see TEMPLATE EXPANSION)\n\
  51. -t TEMPLATE set track template (see TEMPLATE EXPANSION)\n\
  52. \n\
  53. Template Expansion\n\
  54. Disc:\n\
  55. %A - album arranger\n\
  56. %C - album composer\n\
  57. %G - album genre\n\
  58. %M - album message\n\
  59. %N - number of tracks\n\
  60. %P - album performer\n\
  61. %S - album songwriter\n\
  62. %T - album title\n\
  63. %U - album UPC/EAN\n\
  64. Track:\n\
  65. %a - track arranger\n\
  66. %c - track composer\n\
  67. %g - track genre\n\
  68. %i - track ISRC\n\
  69. %m - track message\n\
  70. %n - track number\n\
  71. %p - track perfomer\n\
  72. %t - track title\n\
  73. %u - track ISRC (CD-TEXT)\n\
  74. \n\
  75. Any other %<character> is expanded to that character. For example, to get a\n\
  76. '%', use %%.\n\
  77. ", stdout);
  78. fprintf(stdout, "default disc template is:\n%s\n", D_TEMPLATE);
  79. fprintf(stdout, "default track template is:\n%s\n", T_TEMPLATE);
  80. } else {
  81. fprintf(stderr, "%s: syntax error\n", progname);
  82. fprintf(stderr, "run `%s -h' for usage\n", progname);
  83. }
  84. exit (status);
  85. }
  86. void disc_field (char *conv, int length, Cd *cd)
  87. {
  88. char *c; /* pointer to conversion character */
  89. Cdtext *cdtext = NULL;
  90. cdtext = cd_get_cdtext(cd);
  91. c = conv + length - 1;
  92. switch (*c) {
  93. case 'A':
  94. *c = 's';
  95. printf(conv, cdtext_get(PTI_ARRANGER, cdtext));
  96. break;
  97. case 'C':
  98. *c = 's';
  99. printf(conv, cdtext_get(PTI_COMPOSER, cdtext));
  100. break;
  101. case 'G':
  102. *c = 's';
  103. printf(conv, cdtext_get(PTI_GENRE, cdtext));
  104. break;
  105. case 'M':
  106. *c = 's';
  107. printf(conv, cdtext_get(PTI_MESSAGE, cdtext));
  108. break;
  109. case 'N':
  110. *c = 'd'; /* tracks is an integer */
  111. printf(conv, cd_get_ntrack(cd));
  112. break;
  113. case 'P':
  114. *c = 's';
  115. printf(conv, cdtext_get(PTI_PERFORMER, cdtext));
  116. break;
  117. case 'R':
  118. *c = 's';
  119. printf(conv, cdtext_get(PTI_ARRANGER, cdtext));
  120. break;
  121. case 'S':
  122. *c = 's';
  123. printf(conv, cdtext_get(PTI_SONGWRITER, cdtext));
  124. break;
  125. case 'T':
  126. *c = 's';
  127. printf(conv, cdtext_get(PTI_TITLE, cdtext));
  128. break;
  129. case 'U':
  130. *c = 's';
  131. printf(conv, cdtext_get(PTI_UPC_ISRC, cdtext));
  132. break;
  133. default:
  134. putchar(*c);
  135. break;
  136. }
  137. }
  138. void track_field (char *conv, int length, Cd *cd, int trackno)
  139. {
  140. char *c; /* pointer to conversion character */
  141. Track *track = NULL;
  142. Cdtext *cdtext = NULL;
  143. track = cd_get_track(cd, trackno);
  144. cdtext = track_get_cdtext(track);
  145. c = conv + length - 1;
  146. switch (*c) {
  147. case 'a':
  148. *c = 's';
  149. printf(conv, cdtext_get(PTI_ARRANGER, cdtext));
  150. break;
  151. case 'c':
  152. *c = 's';
  153. printf(conv, cdtext_get(PTI_COMPOSER, cdtext));
  154. break;
  155. case 'f':
  156. *c = 's';
  157. printf(conv, track_get_filename(track));
  158. break;
  159. case 'g':
  160. *c = 's';
  161. printf(conv, cdtext_get(PTI_GENRE, cdtext));
  162. break;
  163. case 'i':
  164. *c = 's';
  165. printf(conv, track_get_isrc(track));
  166. break;
  167. case 'm':
  168. *c = 's';
  169. printf(conv, cdtext_get(PTI_MESSAGE, cdtext));
  170. break;
  171. case 'n':
  172. *c = 'd'; /* track number is an integer */
  173. printf(conv, trackno);
  174. break;
  175. case 'p':
  176. *c = 's';
  177. printf(conv, cdtext_get(PTI_PERFORMER, cdtext));
  178. break;
  179. case 's':
  180. *c = 's';
  181. printf(conv, cdtext_get(PTI_SONGWRITER, cdtext));
  182. break;
  183. case 't':
  184. *c = 's';
  185. printf(conv, cdtext_get(PTI_TITLE, cdtext));
  186. break;
  187. case 'u':
  188. *c = 's';
  189. printf(conv, cdtext_get(PTI_UPC_ISRC, cdtext));
  190. break;
  191. default:
  192. disc_field(conv, length, cd);
  193. break;
  194. }
  195. }
  196. /* print a % conversion specification
  197. * %[flag(s)][width][.precision]<conversion-char>
  198. */
  199. void print_conv (char *start, int length, Cd *cd, int trackno)
  200. {
  201. char *conv; /* copy of conversion specification */
  202. /* TODO: use strndup? */
  203. conv = malloc ((unsigned) (length + 1));
  204. strncpy(conv, start, length);
  205. conv[length] = '\0';
  206. /* conversion character */
  207. if (0 == trackno)
  208. disc_field(conv, length, cd);
  209. else
  210. track_field(conv, length, cd, trackno);
  211. free(conv);
  212. }
  213. /* print an single-character escape
  214. * `c' is the character after the `/'
  215. * NOTE: this does not handle octal and hexidecimal escapes
  216. * except for \0
  217. */
  218. void print_esc (char *c)
  219. {
  220. switch (*c) {
  221. case 'a':
  222. putchar('\a');
  223. break;
  224. case 'b':
  225. putchar('\b');
  226. break;
  227. case 'f':
  228. putchar('\f');
  229. break;
  230. case 'n':
  231. putchar('\n');
  232. break;
  233. case 'r':
  234. putchar('\r');
  235. break;
  236. case 't':
  237. putchar('\t');
  238. break;
  239. case 'v':
  240. putchar('\v');
  241. break;
  242. case '0':
  243. putchar('\0');
  244. break;
  245. default:
  246. /* ?, ', " are handled by the default */
  247. putchar(*c);
  248. break;
  249. }
  250. }
  251. void cd_printf (char *format, Cd *cd, int trackno)
  252. {
  253. char *c; /* pointer into format */
  254. char *conv_start;
  255. int conv_length;
  256. for (c = format; '\0' != *c; c++) {
  257. switch (*c) {
  258. case '%':
  259. conv_start = c;
  260. conv_length = 1;
  261. c++;
  262. /* flags */
  263. while ( \
  264. '-' == *c \
  265. || '+' == *c \
  266. || ' ' == *c \
  267. || '0' == *c \
  268. || '#' == *c \
  269. ) {
  270. conv_length++;
  271. c++;
  272. }
  273. /* field width */
  274. /* '*' not recognized */
  275. while (0 != isdigit(*c)) {
  276. conv_length++;
  277. c++;
  278. }
  279. /* precision */
  280. /* '*' not recognized */
  281. if ('.' == *c) {
  282. conv_length++;
  283. c++;
  284. while (0 != isdigit(*c)) {
  285. conv_length++;
  286. c++;
  287. }
  288. }
  289. /* length modifier (h, l, or L) */
  290. /* not recognized */
  291. /* conversion character */
  292. conv_length++;
  293. print_conv(conv_start, conv_length, cd, trackno);
  294. break;
  295. case '\\':
  296. c++;
  297. print_esc(c);
  298. break;
  299. default:
  300. putchar(*c);
  301. break;
  302. }
  303. }
  304. }
  305. int info (char *name, int format, int trackno, char *d_template, char *t_template)
  306. {
  307. Cd *cd = NULL;
  308. int ntrack;
  309. if (NULL == (cd = cf_parse(name, &format))) {
  310. fprintf(stderr, "%s: input file error\n", name);
  311. return -1;
  312. }
  313. ntrack = cd_get_ntrack(cd);
  314. if (-1 == trackno) {
  315. cd_printf(d_template, cd, 0);
  316. for (trackno = 1; trackno <= ntrack; trackno++) {
  317. cd_printf(t_template, cd, trackno);
  318. }
  319. } else if (0 == trackno) {
  320. cd_printf(d_template, cd, trackno);
  321. } else if (0 < trackno && ntrack >= trackno) {
  322. cd_printf(t_template, cd, trackno);
  323. } else {
  324. fprintf(stderr, "%s: track number out of range\n", progname);
  325. return -1;
  326. }
  327. return 0;
  328. }
  329. int main (int argc, char **argv)
  330. {
  331. int format = UNKNOWN;
  332. int trackno = -1; /* track number (-1 = unspecified, 0 = disc info) */
  333. char *d_template = NULL; /* disc template */
  334. char *t_template = NULL; /* track template */
  335. /* getopt () variables */
  336. char c;
  337. extern char *optarg;
  338. extern int optind;
  339. progname = *argv;
  340. while (-1 != (c = getopt(argc, argv, "hi:n:d:t:"))) {
  341. switch (c) {
  342. case 'h':
  343. usage(0);
  344. break;
  345. case 'i':
  346. if (0 == strcmp("cue", optarg))
  347. format = CUE;
  348. else if (0 == strcmp("toc", optarg))
  349. format = TOC;
  350. break;
  351. case 'n':
  352. trackno = atoi(optarg);
  353. break;
  354. case 'd':
  355. d_template = optarg;
  356. break;
  357. case 't':
  358. t_template = optarg;
  359. break;
  360. default:
  361. usage(1);
  362. break;
  363. }
  364. }
  365. /* if no disc or track template is set, use the defaults for both */
  366. if (NULL == d_template && NULL == t_template) {
  367. d_template = D_TEMPLATE;
  368. t_template = T_TEMPLATE;
  369. } else {
  370. if (NULL == d_template)
  371. d_template = "";
  372. if (NULL == t_template)
  373. t_template = "";
  374. }
  375. if (optind == argc) {
  376. info("-", format, trackno, d_template, t_template);
  377. } else {
  378. for (; optind < argc; optind++)
  379. info(argv[optind], format, trackno, d_template, t_template);
  380. }
  381. return 0;
  382. }