#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#ifndef WIN32
#include <unistd.h>
#endif
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#include <cmml.h>
#define BUFSIZE 100000
static int verbose;
static void
PrintUsage(char *prog) {
fprintf(stderr, "Usage: %s [options] filename\n", prog);
fprintf(stderr, "Validate a CMML file.\n\n");
fprintf(stderr, "Possible options:\n");
#ifdef HAVE_GETOPT_LONG
fprintf(stderr, " -i clip_id, --id clip_id\n");
fprintf(stderr, " Start parsing from the named clip.\n");
fprintf(stderr, " -s seconds, --sec seconds\n");
fprintf(stderr, " Start parsing from the given seconds offset\n");
fprintf(stderr, " -u utc, --utc utc\n");
fprintf(stderr, " Start parsing from the given utc time\n");
fprintf(stderr, " -b, --verbose Output parsed file to stdout\n");
fprintf(stderr, " -h, --help Display this help information\n");
fprintf(stderr, " -v, --version Display version information\n");
#else
fprintf(stderr, " -i clip_id Start parsing from the named clip\n");
fprintf(stderr, " -s seconds Start parsing from the given seconds offset\n");
fprintf(stderr, " -u utc Start parsing from the given utc time\n");
fprintf(stderr, " -b Output parsed file to stdout\n");
fprintf(stderr, " -h Display this help information\n");
fprintf(stderr, " -v Display version information\n");
#endif
fprintf(stderr, "\nPlease report bugs to <libcmml-devel@cmis.csiro.au>.\n");
exit(1);
}
static int
read_stream (CMML * cmml, const CMML_Stream * stream, void * user_data) {
char buf[BUFSIZE];
CMML_Error * err;
if ((err = cmml_get_last_error(cmml)) != NULL) {
cmml_error_snprint(buf, BUFSIZE, err, cmml);
fprintf(stderr, "cmml-validate: Parsing stream tag %s\n", buf);
fprintf(stderr, "cmml-validate: Non-recoverable error\n");
return -1;
} else {
if (verbose) {
cmml_stream_pretty_snprint (buf, BUFSIZE, (CMML_Stream *) stream);
fprintf(stdout, "%s\n", buf);
}
} return 0;
}
static int
read_head (CMML * cmml, const CMML_Head * head, void * user_data) {
char buf[BUFSIZE];
CMML_Error * err;
if ((err = cmml_get_last_error(cmml)) != NULL) {
cmml_error_snprint(buf, BUFSIZE, err, cmml);
fprintf(stderr, "cmml-validate: Parsing head tag %s\n", buf);
fprintf(stderr, "cmml-validate: Non-recoverable error\n");
return -1;
} else {
if (verbose) {
cmml_head_pretty_snprint (buf, BUFSIZE, (CMML_Head *) head);
fprintf(stdout, "%s\n", buf);
}
}
return 0;
}
static int
read_clip (CMML * cmml, const CMML_Clip * clip, void * user_data) {
char buf[BUFSIZE];
CMML_Error * err;
if ((err = cmml_get_last_error(cmml)) != NULL) {
cmml_error_snprint(buf, BUFSIZE, err, cmml);
fprintf(stderr, "cmml-validate: Parsing clip %s\n", buf);
fprintf(stderr, "cmml-validate: Skipping clip\n\n");
return -1;
} else {
if (verbose) {
cmml_clip_pretty_snprint (buf, BUFSIZE, (CMML_Clip *) clip);
fprintf(stdout, "%s\n", buf);
}
}
return 0;
}
int main(int argc, char *argv[])
{
char *pathfile = NULL;
int i;
char buf[BUFSIZE];
CMML * doc;
CMML_Error * err;
CMML_Preamble * pre;
long n = 0;
char * clip_id = NULL;
double secs = -1.0;
char * utc = NULL;
int sloppy = 0;
verbose = 0;
while (1) {
char * optstring = "hvbyi:s:u:";
#ifdef HAVE_GETOPT_LONG
static struct option long_options[] = {
{"help",no_argument,0,'h'},
{"version",no_argument,0, 'v'},
{"verbose",no_argument,0,'b'},
{"sloppy",no_argument,0,'y'},
{"id",required_argument,0,'i'},
{"sec",required_argument,0,'s'},
{"utc",required_argument,0,'u'},
{0,0,0,0}
};
i = getopt_long(argc, argv, optstring, long_options, NULL);
#else
i = getopt(argc, argv, optstring);
#endif
if (i == -1) break;
if (i == ':') PrintUsage(argv[0]);
switch (i) {
case 'h':
PrintUsage(argv[0]);
break;
case 'v':
fprintf(stdout, "cmml-validate version " VERSION "\n");
fprintf(stdout, "# cmml-validate, Copyright (C) 2003 CSIRO Australia www.csiro.au ; www.annodex.net\n");
break;
case 'i':
clip_id = optarg;
break;
case 's':
if (!isalpha(optarg[0])) {
secs = atof(optarg);
}
break;
case 'u':
utc = optarg;
break;
case 'y':
sloppy = 1;
break;
case 'b':
verbose = 1;
break;
default:
break;
}
}
if (optind > argc) {
PrintUsage(argv[0]);
}
if (optind == argc) {
pathfile = "-";
} else {
pathfile = argv[optind++];
}
errno=0;
if (strcmp (pathfile, "-") == 0) {
doc = cmml_new (stdin);
} else {
doc = cmml_open (pathfile);
}
if (doc == NULL) {
if (errno == 0) {
fprintf(stderr, "%s: %s: CMML error opening file\n", argv[0], pathfile);
} else {
fprintf(stderr, "%s: %s: %s\n", argv[0], pathfile, strerror(errno));
}
PrintUsage(argv[0]);
}
if (sloppy) {
cmml_set_sloppy(doc, 1);
}
if (verbose) {
pre = cmml_get_preamble(doc);
cmml_preamble_snprint(buf, BUFSIZE, pre);
fprintf(stdout, "%s\n", buf);
}
if (clip_id != NULL) {
cmml_set_read_callbacks (doc, read_stream, read_head, NULL, NULL);
cmml_skip_to_id (doc, clip_id);
}
if (secs > 0 || utc != NULL) {
cmml_set_read_callbacks (doc, read_stream, read_head, NULL, NULL);
if (secs > 0) {
cmml_skip_to_secs (doc, secs);
} else {
cmml_skip_to_utc (doc, utc);
}
}
cmml_set_read_callbacks (doc, read_stream, read_head, read_clip, NULL);
while ((n = cmml_read (doc, BUFSIZE)) > 0) {
if ((err = cmml_get_last_error(doc)) != NULL && err->type != CMML_EOF) {
char *filename;
filename = (strrchr(pathfile, '/') == NULL ? pathfile
: strrchr(pathfile, '/')+1);
cmml_error_snprint(buf, BUFSIZE, err, doc);
fprintf (stderr, "%s:%s\n", filename, buf);
goto cleanup;
}
}
err = cmml_get_last_error(doc);
if (n == -1 || (err!=NULL && err->type != CMML_EOF)) {
char *filename;
filename = (strrchr(pathfile, '/') == NULL ? pathfile
: strrchr(pathfile, '/')+1);
cmml_error_snprint(buf, BUFSIZE, err, doc);
fprintf (stderr, "%s:%s\n", filename, buf);
goto cleanup;
}
if (verbose) {
fprintf(stdout, "</cmml>\n");
}
cleanup:
cmml_close(doc);
return 0;
}