/*
* cueprint.c -- print cd information based on a template
*
* Copyright (C) 2004 Svend Sorensen
* For license terms, see the file COPYING in this distribution.
*/
#include <stdio.h>
#include <stdlib.h> /* exit() */
#include <string.h> /* strcmp() */
#include <unistd.h> /* getopt() */
#include <ctype.h> /* isdigit() */
#include "cuefile.h"
/* default templates */
#define D_TEMPLATE "\
Disc Information\n\
arranger: %A\n\
composer: %C\n\
genre: %G\n\
message: %M\n\
no. of tracks: %N\n\
performer: %P\n\
songwriter: %S\n\
title: %T\n\
UPC/EAN: %U\n\
"
#define T_TEMPLATE "\
\n\
Track %n Information\n\
arranger: %a\n\
composer: %c\n\
genre: %g\n\
ISRC: %i\n\
message: %m\n\
track number: %n\n\
perfomer: %p\n\
title: %t\n\
ISRC (CD-TEXT): %u\n\
"
char *progname;
void usage (int status)
{
if (0 == status) {
fprintf(stdout, "%s: usage: cueprint [-h] [-i cue|toc] [-d TEMPLATE] [-t TEMPLATE] [file...]\n", progname);
fputs("\
\n\
OPTIONS\n\
-h print usage\n\
-i cue|toc set format of file(s)\n\
-d TEMPLATE set disc template (see TEMPLATE EXPANSION)\n\
-t TEMPLATE set track template (see TEMPLATE EXPANSION)\n\
\n\
Template Expansion\n\
Disc:\n\
%A - album arranger\n\
%C - album composer\n\
%G - album genre\n\
%M - album message\n\
%N - number of tracks\n\
%P - album performer\n\
%S - album songwriter\n\
%T - album title\n\
%U - album UPC/EAN\n\
Track:\n\
%a - track arranger\n\
%c - track composer\n\
%g - track genre\n\
%i - track ISRC\n\
%m - track message\n\
%n - track number\n\
%p - track perfomer\n\
%t - track title\n\
%u - track ISRC (CD-TEXT)\n\
\n\
Any other %<character> is expanded to that character. For example, to get a\n\
'%', use %%.\n\
", stdout);
fprintf(stdout, "default disc template is:\n%s\n", D_TEMPLATE);
fprintf(stdout, "default track template is:\n%s\n", T_TEMPLATE);
} else {
fprintf(stderr, "%s: syntax error\n", progname);
fprintf(stderr, "run `%s -h' for usage\n", progname);
}
exit (status);
}
void disc_field (char *conv, int length, Cd *cd)
{
char *c; /* pointer to conversion character */
Cdtext *cdtext = NULL;
cdtext = cd_get_cdtext(cd);
c = conv + length - 1;
switch (*c) {
case 'A':
*c = 's';
printf(conv, cdtext_get(PTI_ARRANGER, cdtext));
break;
case 'C':
*c = 's';
printf(conv, cdtext_get(PTI_COMPOSER, cdtext));
break;
case 'G':
*c = 's';
printf(conv, cdtext_get(PTI_GENRE, cdtext));
break;
case 'M':
*c = 's';
printf(conv, cdtext_get(PTI_MESSAGE, cdtext));
break;
case 'N':
*c = 'd'; /* tracks is an integer */
printf(conv, cd_get_ntrack(cd));
break;
case 'P':
*c = 's';
printf(conv, cdtext_get(PTI_PERFORMER, cdtext));
break;
case 'R':
*c = 's';
printf(conv, cdtext_get(PTI_ARRANGER, cdtext));
break;
case 'S':
*c = 's';
printf(conv, cdtext_get(PTI_SONGWRITER, cdtext));
break;
case 'T':
*c = 's';
printf(conv, cdtext_get(PTI_TITLE, cdtext));
break;
case 'U':
*c = 's';
printf(conv, cdtext_get(PTI_UPC_ISRC, cdtext));
break;
default:
putchar(*c);
break;
}
}
void track_field (char *conv, int length, Cd *cd, int trackno)
{
char *c; /* pointer to conversion character */
Track *track = NULL;
Cdtext *cdtext = NULL;
track = cd_get_track(cd, trackno);
cdtext = track_get_cdtext(track);
c = conv + length - 1;
switch (*c) {
case 'a':
*c = 's';
printf(conv, cdtext_get(PTI_ARRANGER, cdtext));
break;
case 'c':
*c = 's';
printf(conv, cdtext_get(PTI_COMPOSER, cdtext));
break;
case 'f':
*c = 's';
printf(conv, track_get_filename(track));
break;
case 'g':
*c = 's';
printf(conv, cdtext_get(PTI_GENRE, cdtext));
break;
case 'i':
*c = 's';
printf(conv, track_get_isrc(track));
break;
case 'm':
*c = 's';
printf(conv, cdtext_get(PTI_MESSAGE, cdtext));
break;
case 'n':
*c = 'd'; /* track number is an integer */
printf(conv, trackno);
break;
case 'p':
*c = 's';
printf(conv, cdtext_get(PTI_PERFORMER, cdtext));
break;
case 's':
*c = 's';
printf(conv, cdtext_get(PTI_SONGWRITER, cdtext));
break;
case 't':
*c = 's';
printf(conv, cdtext_get(PTI_TITLE, cdtext));
break;
case 'u':
*c = 's';
printf(conv, cdtext_get(PTI_UPC_ISRC, cdtext));
break;
default:
disc_field(conv, length, cd);
break;
}
}
/* print a % conversion specification
* %[flag(s)][width][.precision]<conversion-char>
*/
void print_conv (char *start, int length, Cd *cd, int trackno)
{
char *conv; /* copy of conversion specification */
/* TODO: use strndup? */
conv = malloc ((unsigned) (length + 1));
strncpy(conv, start, length);
conv[length] = '\0';
/* conversion character */
if (0 == trackno)
disc_field(conv, length, cd);
else
track_field(conv, length, cd, trackno);
free(conv);
}
/* print an single-character escape
* `c' is the character after the `/'
* NOTE: this does not handle octal and hexidecimal escapes
* except for \0
*/
void print_esc (char *c)
{
switch (*c) {
case 'a':
putchar('\a');
break;
case 'b':
putchar('\b');
break;
case 'f':
putchar('\f');
break;
case 'n':
putchar('\n');
break;
case 'r':
putchar('\r');
break;
case 't':
putchar('\t');
break;
case 'v':
putchar('\v');
break;
case '0':
putchar('\0');
break;
default:
/* ?, ', " are handled by the default */
putchar(*c);
break;
}
}
void cd_printf (char *format, Cd *cd, int trackno)
{
char *c; /* pointer into format */
char *conv_start;
int conv_length;
for (c = format; '\0' != *c; c++) {
switch (*c) {
case '%':
conv_start = c;
conv_length = 1;
c++;
/* flags */
while ( \
'-' == *c \
|| '+' == *c \
|| ' ' == *c \
|| '0' == *c \
|| '#' == *c \
) {
conv_length++;
c++;
}
/* field width */
/* '*' not recognized */
while (0 != isdigit(*c)) {
conv_length++;
c++;
}
/* precision */
/* '*' not recognized */
if ('.' == *c) {
conv_length++;
c++;
while (0 != isdigit(*c)) {
conv_length++;
c++;
}
}
/* length modifier (h, l, or L) */
/* not recognized */
/* conversion character */
conv_length++;
print_conv(conv_start, conv_length, cd, trackno);
break;
case '\\':
c++;
print_esc(c);
break;
default:
putchar(*c);
break;
}
}
}
int info (char *name, int format, char *d_template, char *t_template)
{
Cd *cd = NULL;
int i; /* track number */
if (NULL == (cd = cf_parse(name, &format))) {
fprintf(stderr, "%s: input file error\n", name);
return -1;
}
cd_printf(d_template, cd, 0);
for (i = 1; i <= cd_get_ntrack(cd); i++) {
cd_printf(t_template, cd, i);
}
return 0;
}
int main (int argc, char **argv)
{
int format = UNKNOWN;
char *d_template = NULL; /* disc template */
char *t_template = NULL; /* track template */
/* getopt () variables */
char c;
extern char *optarg;
extern int optind;
progname = *argv;
while (-1 != (c = getopt(argc, argv, "hi:d:t:"))) {
switch (c) {
case 'h':
usage(0);
break;
case 'i':
if (0 == strcmp("cue", optarg))
format = CUE;
else if (0 == strcmp("toc", optarg))
format = TOC;
break;
case 'd':
d_template = optarg;
break;
case 't':
t_template = optarg;
break;
default:
usage(1);
break;
}
}
/* if no disc or track template is set, use the defaults for both */
if (NULL == d_template && NULL == t_template) {
d_template = D_TEMPLATE;
t_template = T_TEMPLATE;
} else {
if (NULL == d_template)
d_template = "";
if (NULL == t_template)
t_template = "";
}
if (optind == argc) {
info("-", format, d_template, t_template);
} else {
for (; optind < argc; optind++)
info(argv[optind], format, d_template, t_template);
}
return 0;
}
|