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.
 
 
 
 
 
 

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