Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 
 
 

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