[xiph-cvs] cvs commit: vorbis-tools/vorbiscomment Makefile.am vcedit.h vcomment.c
Ralph Giles
giles at xiph.org
Fri Jan 19 03:39:24 PST 2001
giles 01/01/19 03:39:24
Modified: vorbiscomment Makefile.am vcedit.h vcomment.c
Log:
Added something resembling a cmdline interface to the new vorbiscomment
example code. You can say
vorbiscomment [-l] <file>
and have it dump the comments to stdout, and
vorbiscomment -w <infile> <outfile>
and have it read a replacement set of comments from stdin.
Still needs some polishing, but it's at least marginally useful
now. I also tried to lay it out so it remained easy to read as
a code example.
The Makefile has been changed to build/install vorbiscomment by
default again, mostly on Monty's approval.
Revision Changes Path
1.6 +2 -2 vorbis-tools/vorbiscomment/Makefile.am
Index: Makefile.am
===================================================================
RCS file: /usr/local/cvsroot/vorbis-tools/vorbiscomment/Makefile.am,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- Makefile.am 2001/01/17 11:02:45 1.5
+++ Makefile.am 2001/01/19 11:39:23 1.6
@@ -2,12 +2,12 @@
AUTOMAKE_OPTIONS = foreign
-EXTRA_PROGRAMS = vorbiscomment
+bin_PROGRAMS = vorbiscomment
INCLUDES = @OGG_CFLAGS@ @VORBIS_CFLAGS@
vorbiscomment_LDFLAGS = @OGG_LIBS@ @VORBIS_LIBS@
-vorbiscomment_SOURCES = vcedit.c vcomment.c
+vorbiscomment_SOURCES = vcedit.c vcedit.h vcomment.c
debug:
$(MAKE) all CFLAGS="@DEBUG@"
1.2 +11 -11 vorbis-tools/vorbiscomment/vcedit.h
Index: vcedit.h
===================================================================
RCS file: /usr/local/cvsroot/vorbis-tools/vorbiscomment/vcedit.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- vcedit.h 2001/01/17 11:02:45 1.1
+++ vcedit.h 2001/01/19 11:39:23 1.2
@@ -16,24 +16,24 @@
typedef struct {
ogg_sync_state *oy;
- ogg_page *og;
+ ogg_page *og;
ogg_stream_state *os;
vorbis_comment *vc;
- FILE *in;
- long serial;
- unsigned char *mainbuf;
- unsigned char *bookbuf;
- int mainlen;
- int booklen;
+ FILE *in;
+ long serial;
+ unsigned char *mainbuf;
+ unsigned char *bookbuf;
+ int mainlen;
+ int booklen;
} vcedit_state;
extern vcedit_state * vcedit_new_state(void);
-extern void vcedit_clear(vcedit_state *state);
-extern vorbis_comment * vcedit_comments(vcedit_state *state);
-extern int vcedit_open(vcedit_state *state, FILE *in);
-extern int vcedit_write(vcedit_state *state, FILE *out);
+extern void vcedit_clear(vcedit_state *state);
+extern vorbis_comment * vcedit_comments(vcedit_state *state);
+extern int vcedit_open(vcedit_state *state, FILE *in);
+extern int vcedit_write(vcedit_state *state, FILE *out);
1.2 +372 -37 vorbis-tools/vorbiscomment/vcomment.c
Index: vcomment.c
===================================================================
RCS file: /usr/local/cvsroot/vorbis-tools/vorbiscomment/vcomment.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- vcomment.c 2001/01/17 11:02:45 1.1
+++ vcomment.c 2001/01/19 11:39:23 1.2
@@ -1,69 +1,404 @@
-/* This program is licensed under the GNU General Public License, version 2, a
- * copy of which is included with this program.
+/* This program is licensed under the GNU General Public License,
+ * version 2, a copy of which is included with this program.
*
* (c) 2000-2001 Michael Smith <msmith at labyrinth.net.au>
+ * (c) 2001 Ralph Giles <giles at ashlu.bc.ca>
*
- * Front end to show how to use vcedit. Note that it's not actually useful.
+ * Front end to show how to use vcedit;
+ * note that it's not very useful on its own.
*/
+
#include <stdio.h>
+#include <string.h>
+#include <getopt.h>
+
#include "vcedit.h"
+/* getopt format struct */
+struct option long_options[] = {
+ {"list",0,0,'l'},
+ {"write",0,0,'w'},
+ {"help",0,0,'h'},
+ {"quiet",0,0,'q'},
+ {"commentfile",1,0,'c'},
+ {NULL,0,0,0}
+};
+
+/* local parameter storage from parsed options */
+typedef struct {
+ int mode;
+ char *infilename, *outfilename;
+ char *commentfilename;
+ FILE *in, *out, *com;
+} param_t;
+
+#define MODE_NONE 0
+#define MODE_LIST 1
+#define MODE_WRITE 2
+
+/* prototypes */
+void usage(void);
+void print_comments(FILE *out, vorbis_comment *vc);
+int add_comment(char *line, vorbis_comment *vc);
+
+param_t *new_param(void);
+void parse_options(int argc, char *argv[], param_t *param);
+void open_files(param_t *p);
+void close_files(param_t *p);
+
+
+/**********
+ main.c
+
+ This is the main function where options are read and written
+ you should be able to just read this function and see how
+ to call the vcedit routines. Details of how to pack/unpack the
+ vorbis_comment structure itself are in the following two routines.
+ The rest of the file is ui dressing so make the program minimally
+ useful as a command line utility and can generally be ignored.
+
+***********/
+
int main(int argc, char **argv)
{
vcedit_state *state;
- vorbis_comment *comment;
+ vorbis_comment *vc;
+ param_t *param;
FILE *in, *out;
- if(argc < 3)
- {
- fprintf(stderr,
- "Usage: vcomment in.ogg out.ogg (to produce modified output)\n");
- return 1;
+ /* initialize the cmdline interface */
+ param = new_param();
+ parse_options(argc, argv, param);
+
+ /* take care of opening the requested files */
+ /* relevent file pointers are returned in the param struct */
+ open_files(param);
+
+ /* which mode are we in? */
+
+ if (param->mode == MODE_LIST) {
+
+ state = vcedit_new_state();
+
+ if(vcedit_open(state, param->in) < 0)
+ {
+ fprintf(stderr, "Failed to open file as vorbis.\n");
+ return 1;
+ }
+
+ /* extract and display the comments */
+ vc = vcedit_comments(state);
+ print_comments(param->com, vc);
+
+ /* done */
+ vcedit_clear(state);
+
+ close_files(param);
+ return 0;
}
- in = fopen(argv[1], "rb");
- if(!in)
- {
- fprintf(stderr, "Error opening input file \"%s\"\n", argv[1]);
- return 1;
+ if (param->mode = MODE_WRITE) {
+
+ state = vcedit_new_state();
+
+ if(vcedit_open(state, param->in) < 0)
+ {
+ fprintf(stderr, "Failed to open file as vorbis.\n");
+ return 1;
+ }
+
+ /* grab and clear the exisiting comments */
+ vc = vcedit_comments(state);
+ vorbis_comment_clear(vc);
+ vorbis_comment_init(vc);
+
+ /* build the replacement structure */
+ while (!feof(param->com)) {
+ /* FIXME should use a resizeable buffer! */
+ char *buf = (char *)malloc(1024*sizeof(char));
+
+ fgets(buf, 1024, param->com);
+ if (add_comment(buf, vc) < 0) {
+ fprintf(stderr,
+ "bad comment:\n\t\"%s\"\n",
+ buf);
+ }
+
+ free(buf);
+ }
+
+ /* write out the modified stream */
+ if(vcedit_write(state, param->out) < 0)
+ {
+ fprintf(stderr, "Failed to write comments to output file\n");
+ return 1;
+ }
+
+ /* done */
+ vcedit_clear(state);
+
+ close_files(param);
+ return 0;
}
+
+ /* should never reach this point */
+ fprintf(stderr, "no action specified\n");
+ return 1;
+}
+
+/**********
+
+ Print out the comments from the vorbis structure
+
+ this version just dumps the raw strings
+ a more elegant version would use vorbis_comment_query()
+
+***********/
+
+void print_comments(FILE *out, vorbis_comment *vc)
+{
+ int i;
+
+ for (i = 0; i < vc->comments; i++)
+ fprintf(out, "%s\n", vc->user_comments[i]);
+}
+
+/**********
+
+ Take a line of the form "TAG=value string", parse it,
+ and add it to the vorbis_comment structure. Error checking
+ is performed.
+
+ Note that this assumes a null-terminated string, which may cause
+ problems with > 8-bit character sets!
+
+***********/
- out = fopen(argv[2], "wb");
- if(!out)
+int add_comment(char *line, vorbis_comment *vc)
+{
+ char *mark, *value;
+
+ /* strip any terminal newline */
{
- fprintf(stderr, "Error opening output file \"%s\"\n", argv[1]);
- return 1;
+ int len = strlen(line);
+ if (line[len-1] == '\n') line[len-1] = '\0';
}
- state = vcedit_new_state();
+ /* validation: basically, we assume it's a tag
+ /* if it has an '=' after one or more alpha chars */
- if(vcedit_open(state, in) < 0)
- {
- fprintf(stderr, "Failed to open file as vorbis.\n");
- return 1;
+ mark = index(line, '=');
+ if (mark == NULL) return -1;
+
+ value = line;
+ while (value < mark) {
+ if (!isalpha(*value++)) return -1;
}
- comment = vcedit_comments(state);
+ /* split the line by turning the '=' in to a null */
+ *mark = '\0';
+ value++;
- /* Read comments, present to user. */
+ /* append the comment and return */
+ vorbis_comment_add_tag(vc, line, value);
- /* Now build new comments */
- vorbis_comment_clear(comment);
- vorbis_comment_init(comment);
+ return 0;
+}
- vorbis_comment_add_tag(comment, "COMMENTEDITED",
- "This file has had the comments in it edited "
- "(well, replaced by this useless text.");
- if(vcedit_write(state, out) < 0)
- {
- fprintf(stderr, "Failed to write comments to output file\n");
- return 1;
+/*** ui-specific routines ***/
+
+/**********
+
+ Print out to usage summary for the cmdline interface (ui)
+
+***********/
+
+void usage(void)
+{
+ fprintf(stderr,
+ "Usage: \n"
+ " vorbiscomment [-l] file.ogg (to list the comments)\n"
+ " vorbiscomment -w in.ogg out.ogg (to modify comments)\n"
+ " in the write case, a new set of comments in the form\n"
+ " 'TAG=value' is expected on stdin. This set will\n"
+ " completely replace the existing set.\n"
+ );
+}
+
+
+/**********
+
+ allocate and initialize a the parameter struct
+
+***********/
+
+param_t *new_param(void)
+{
+ param_t *param = (param_t *)malloc(sizeof(param_t));
+
+ /* mode */
+ param->mode = MODE_LIST;
+
+ /* filenames */
+ param->infilename = NULL;
+ param->outfilename = NULL;
+ param->commentfilename = "-"; /* default */
+
+ /* file pointers */
+ param->in = param->out = NULL;
+ param->com = NULL;
+
+ return param;
+}
+
+/**********
+ parse_options()
+
+ This function takes care of parsing the command line options
+ with getopt() and fills out the param struct with the mode,
+ flags, and filenames.
+
+***********/
+
+void parse_options(int argc, char *argv[], param_t *param)
+{
+ int ret;
+ int option_index = 1;
+
+ while ((ret = getopt_long(argc, argv, "lwhqc:",
+ long_options, &option_index)) != -1) {
+ switch (ret) {
+ case 0:
+ fprintf(stderr, "Internal error parsing command options\n");
+ exit(1);
+ break;
+ case 'l':
+ param->mode = MODE_LIST;
+ break;
+ case 'w':
+ param->mode = MODE_WRITE;
+ break;
+ case 'h':
+ usage();
+ exit(0);
+ break;
+ case 'q':
+ /* set quiet flag */
+ break;
+ case 'c':
+ param->commentfilename = strdup(optarg);
+ break;
+ default:
+ usage();
+ exit(1);
+ }
}
- vcedit_clear(state);
+ /* remaining bits must be the filenames */
+ if ((param->mode == MODE_LIST && (argc - optind) != 1) ||
+ (param->mode == MODE_WRITE && (argc - optind) != 2)) {
+ usage();
+ exit(1);
+ }
+ param->infilename = strdup(argv[optind]);
+ if (param->mode == MODE_WRITE)
+ param->outfilename = strdup(argv[optind+1]);
+}
- return 0;
+/**********
+ open_files()
+
+ This function takes care of opening the appropriate files
+ based on the mode and filenames in the param structure.
+ A filename of '-' is interpreted as stdin/out.
+
+ The idea is just to hide the tedious checking so main()
+ is easier to follow as an example.
+
+***********/
+
+void open_files(param_t *p)
+{
+ /* for all modes, open the input file */
+
+ if (strncmp(p->infilename,"-",2) == 0) {
+ p->in = stdin;
+ } else {
+ p->in = fopen(p->infilename, "rb");
+ }
+ if (p->in == NULL) {
+ fprintf(stderr,
+ "Error opening input file '%s'.\n",
+ p->infilename);
+ exit(1);
+ }
+
+ if (p->mode == MODE_WRITE) {
+
+ /* open output for write mode */
+
+ if (strncmp(p->outfilename,"-",2) == 0) {
+ p->out = stdout;
+ } else {
+ p->out = fopen(p->outfilename, "wb");
+ }
+ if(p->out == NULL) {
+ fprintf(stderr,
+ "Error opening output file '%s'.\n",
+ p->outfilename);
+ exit(1);
+ }
+
+ /* commentfile is input */
+
+ if ((p->commentfilename == NULL) ||
+ (strncmp(p->commentfilename,"-",2) == 0)) {
+ p->com = stdin;
+ } else {
+ p->com = fopen(p->commentfilename, "rb");
+ }
+ if (p->com == NULL) {
+ fprintf(stderr,
+ "Error opening comment file '%s'.\n",
+ p->commentfilename);
+ exit(1);
+ }
+
+ } else {
+
+ /* in list mode, commentfile is output */
+
+ if ((p->commentfilename == NULL) ||
+ (strncmp(p->commentfilename,"-",2) == 0)) {
+ p->com = stdout;
+ } else {
+ p->com = fopen(p->commentfilename, "wb");
+ }
+ if (p->com == NULL) {
+ fprintf(stderr,
+ "Error opening comment file '%s'\n",
+ p->commentfilename);
+ exit(1);
+ }
+ }
+
+ /* all done */
}
+/**********
+ close_files()
+
+ Do some quick clean-up.
+
+***********/
+
+void close_files(param_t *p)
+{
+ /* FIXME: should handle stdin/out */
+
+ if (p->in != NULL) fclose(p->in);
+ if (p->out != NULL) fclose(p->out);
+ if (p->com != NULL) fclose(p->com);
+}
--- >8 ----
List archives: http://www.xiph.org/archives/
Ogg project homepage: http://www.xiph.org/ogg/
To unsubscribe from this list, send a message to 'cvs-request at xiph.org'
containing only the word 'unsubscribe' in the body. No subject is needed.
Unsubscribe messages sent to the list will be ignored/filtered.
More information about the commits
mailing list