[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