cmml-validate.c

This is the full source code of the cmml-validate program, which parses a CMML instance document and validates it against the cmml.dtd returning true/false. In case of an error the faulty tag including line and col number is reported. It also spits out warnings for strange stuff.

00001 /* Copyright (C) 2003 CSIRO Australia
00002 
00003    Redistribution and use in source and binary forms, with or without
00004    modification, are permitted provided that the following conditions
00005    are met:
00006    
00007    - Redistributions of source code must retain the above copyright
00008    notice, this list of conditions and the following disclaimer.
00009    
00010    - Redistributions in binary form must reproduce the above copyright
00011    notice, this list of conditions and the following disclaimer in the
00012    documentation and/or other materials provided with the distribution.
00013    
00014    - Neither the name of the CSIRO nor the names of its
00015    contributors may be used to endorse or promote products derived from
00016    this software without specific prior written permission.
00017    
00018    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00019    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00020    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00021    PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE ORGANISATION OR
00022    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00023    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00024    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00025    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00026    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00027    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029 */
00030 
00031 #include "config.h"
00032 
00033 #include <stdio.h>
00034 #include <stdlib.h>
00035 #include <fcntl.h>
00036 #include <ctype.h>
00037 #include <string.h>
00038 #include <errno.h>
00039 
00040 #ifndef WIN32
00041 #include <unistd.h>
00042 #endif
00043 
00044 #ifdef HAVE_GETOPT_H
00045 #include <getopt.h>
00046 #endif
00047 
00048 #include <cmml.h>
00049 
00079 #define BUFSIZE 100000
00080 
00081 /*
00082 #define DEBUG
00083 */
00084 
00088 static int verbose;
00089 
00095 static void
00096 PrintUsage(char *prog) {
00097   fprintf(stderr, "Usage: %s [options] filename\n", prog);
00098   fprintf(stderr, "Validate a CMML file.\n\n");
00099   fprintf(stderr, "Possible options:\n");
00100 #ifdef HAVE_GETOPT_LONG
00101   fprintf(stderr, "  -i clip_id, --id clip_id\n");
00102   fprintf(stderr, "                 Start parsing from the named clip.\n");
00103   fprintf(stderr, "  -s seconds, --sec seconds\n");
00104   fprintf(stderr, "                 Start parsing from the given seconds offset\n");
00105   fprintf(stderr, "  -u utc,     --utc utc\n");
00106   fprintf(stderr, "                 Start parsing from the given utc time\n");
00107   fprintf(stderr, "  -b, --verbose  Output parsed file to stdout\n");
00108   fprintf(stderr, "  -h, --help     Display this help information\n");
00109   fprintf(stderr, "  -v, --version  Display version information\n");
00110 #else
00111   fprintf(stderr, "  -i clip_id     Start parsing from the named clip\n");
00112   fprintf(stderr, "  -s seconds     Start parsing from the given seconds offset\n");
00113   fprintf(stderr, "  -u utc         Start parsing from the given utc time\n");
00114   fprintf(stderr, "  -b             Output parsed file to stdout\n");
00115   fprintf(stderr, "  -h             Display this help information\n");
00116   fprintf(stderr, "  -v             Display version information\n");
00117 #endif
00118   fprintf(stderr, "\nPlease report bugs to <libcmml-devel@cmis.csiro.au>.\n");
00119   exit(1);
00120 }
00121 
00132 static int
00133 read_stream (CMML * cmml, const CMML_Stream * stream, void * user_data) {
00134   char buf[BUFSIZE];
00135   CMML_Error * err;
00136   if ((err = cmml_get_last_error(cmml)) != NULL) {
00137     cmml_error_snprint(buf, BUFSIZE, err, cmml);
00138     fprintf(stderr, "cmml-validate: Parsing stream tag %s\n", buf);
00139     fprintf(stderr, "cmml-validate: Non-recoverable error\n");
00140     return -1;
00141   } else {
00142     /* print stream */
00143     if (verbose) {
00144       cmml_stream_pretty_snprint (buf, BUFSIZE, (CMML_Stream *) stream);
00145       fprintf(stdout, "%s\n", buf);
00146     }
00147   }  return 0;
00148 }
00149 
00160 static int
00161 read_head (CMML * cmml, const CMML_Head * head, void * user_data) {
00162   char buf[BUFSIZE];
00163   CMML_Error * err;
00164   if ((err = cmml_get_last_error(cmml)) != NULL) {
00165     cmml_error_snprint(buf, BUFSIZE, err, cmml);
00166     fprintf(stderr, "cmml-validate: Parsing head tag %s\n", buf);
00167     fprintf(stderr, "cmml-validate: Non-recoverable error\n");
00168     return -1;
00169   } else {
00170     if (verbose) {
00171       cmml_head_pretty_snprint (buf, BUFSIZE, (CMML_Head *) head);
00172       fprintf(stdout, "%s\n", buf);
00173     }
00174   }
00175   return 0;
00176 }
00177 
00188 static int
00189 read_clip (CMML * cmml, const CMML_Clip * clip, void * user_data) {
00190   char buf[BUFSIZE];
00191   CMML_Error * err;
00192   if ((err = cmml_get_last_error(cmml)) != NULL) {
00193     cmml_error_snprint(buf, BUFSIZE, err, cmml);
00194     fprintf(stderr, "cmml-validate: Parsing clip %s\n", buf);
00195     fprintf(stderr, "cmml-validate: Skipping clip\n\n");
00196     return -1;
00197   } else {
00198     if (verbose) {
00199       cmml_clip_pretty_snprint (buf, BUFSIZE, (CMML_Clip *) clip);
00200       fprintf(stdout, "%s\n", buf);
00201     }
00202   }
00203   return 0;
00204 }
00205 
00212 int main(int argc, char *argv[])
00213 {
00214   char *pathfile = NULL;
00215   int i;
00216   char buf[BUFSIZE];
00217   CMML * doc;
00218   CMML_Error * err;
00219   CMML_Preamble * pre;
00220   long n = 0;
00221   char * clip_id = NULL;
00222   double secs = -1.0;
00223   char * utc = NULL;
00224   int sloppy = 0;
00225   verbose = 0;
00226 
00227   while (1) {
00228     char * optstring = "hvbyi:s:u:";
00229 
00230 #ifdef HAVE_GETOPT_LONG
00231     static struct option long_options[] = {
00232       {"help",no_argument,0,'h'},
00233       {"version",no_argument,0, 'v'},
00234       {"verbose",no_argument,0,'b'},
00235       {"sloppy",no_argument,0,'y'},
00236       {"id",required_argument,0,'i'},
00237       {"sec",required_argument,0,'s'},
00238       {"utc",required_argument,0,'u'},
00239       {0,0,0,0}
00240     };
00241 
00242     i = getopt_long(argc, argv, optstring, long_options, NULL);
00243 #else
00244     i = getopt(argc, argv, optstring);
00245 #endif
00246 
00247     if (i == -1) break;
00248     if (i == ':') PrintUsage(argv[0]);
00249 
00250     switch (i) {
00251     case 'h': /* help */
00252       PrintUsage(argv[0]);
00253       break;
00254     case 'v': /* version */
00255       fprintf(stdout, "cmml-validate version " VERSION "\n");
00256       fprintf(stdout, "# cmml-validate, Copyright (C) 2003 CSIRO Australia www.csiro.au ; www.annodex.net\n");
00257       break;
00258     case 'i': /* clip_id */
00259       clip_id = optarg;
00260       break;
00261     case 's': /* seconds */
00262       if (!isalpha(optarg[0])) {
00263         secs = atof(optarg);
00264       }
00265       break;
00266     case 'u': /* utc */
00267       utc = optarg;
00268       break;
00269     case 'y': /* sloppy */
00270       sloppy = 1;
00271       break;
00272     case 'b': /* verbose */
00273       verbose = 1;
00274       break;
00275     default:
00276       break;
00277     }
00278   }
00279 
00280   /* more arguments that were not parsed */
00281   if (optind > argc) {
00282     PrintUsage(argv[0]);
00283   }
00284 
00285   /* no filename given? */
00286   if (optind == argc) {
00287     pathfile = "-";
00288   } else {
00289     pathfile = argv[optind++];
00290   }
00291 
00292   /* try open file for parsing and setup cmml parsing */
00293   errno=0;
00294   if (strcmp (pathfile, "-") == 0) {
00295     doc = cmml_new (stdin);
00296   } else {
00297     doc = cmml_open (pathfile);
00298   }
00299 
00300   if (doc == NULL) {
00301     if (errno == 0) {
00302       fprintf(stderr, "%s: %s: CMML error opening file\n", argv[0], pathfile);
00303     } else {
00304       fprintf(stderr, "%s: %s: %s\n", argv[0], pathfile, strerror(errno));
00305     }
00306     PrintUsage(argv[0]);
00307   }
00308 
00309   /* turn on sloppy parsing if requested */
00310   if (sloppy) {
00311     cmml_set_sloppy(doc, 1);
00312   }
00313 
00314   /* print preamble */
00315   if (verbose) {
00316     pre = cmml_get_preamble(doc);
00317     cmml_preamble_snprint(buf, BUFSIZE, pre);
00318     fprintf(stdout, "%s\n", buf);
00319   }
00320 
00321   /* seek to clip_id; if not found, to file end */
00322   if (clip_id != NULL) {
00323     /* register callbacks */
00324     cmml_set_read_callbacks (doc, read_stream, read_head, NULL, NULL);
00325     cmml_skip_to_id (doc, clip_id);
00326   }
00327 
00328   /* seek to time offset; if not found, to file end */
00329   if (secs > 0 || utc != NULL) {
00330     /* register callbacks */
00331     cmml_set_read_callbacks (doc, read_stream, read_head, NULL, NULL);
00332     if (secs > 0) {
00333       cmml_skip_to_secs (doc, secs);
00334     } else { /* if (utc != NULL) { */
00335       cmml_skip_to_utc (doc, utc);
00336     }
00337   }
00338 
00339   /* register callbacks */
00340   cmml_set_read_callbacks (doc, read_stream, read_head, read_clip, NULL);
00341 
00342   /* read document frame-wise and check against CMML.dtd */
00343   while ((n = cmml_read (doc, BUFSIZE)) > 0) {
00344     /* if error reading, print and exit */
00345     if ((err = cmml_get_last_error(doc)) != NULL && err->type != CMML_EOF) {
00346       char *filename;
00347       filename = (strrchr(pathfile, '/') == NULL ? pathfile
00348                   : strrchr(pathfile, '/')+1);
00349       cmml_error_snprint(buf, BUFSIZE, err, doc);
00350       fprintf (stderr, "%s:%s\n", filename, buf);
00351       goto cleanup;
00352     }
00353   }
00354 
00355   err = cmml_get_last_error(doc);
00356   if (err!=NULL && err->type != CMML_EOF) {
00357       char *filename;
00358       filename = (strrchr(pathfile, '/') == NULL ? pathfile
00359                   : strrchr(pathfile, '/')+1);
00360       cmml_error_snprint(buf, BUFSIZE, err, doc);
00361       fprintf (stderr, "%s:%s\n", filename, buf);
00362       goto cleanup;
00363   }
00364 
00365   /* write end tag */
00366   if (verbose) {
00367     fprintf(stdout, "</cmml>\n");
00368   }
00369   
00370  cleanup:
00371   /* clean up */
00372   cmml_close(doc);
00373 
00374   return 0;
00375 }

Generated on Mon Jan 8 14:47:15 2007 for libcmml by  doxygen 1.5.1