shithub: sox

Download patch

ref: cc9a8199368f829a4eb666232fb60384fee3cfec
parent: 2a5393e9cae6161ab39345f01a66233393b24b78
author: cbagwell <cbagwell>
date: Thu Aug 23 23:16:22 EDT 2001

Cleaning up init code so that its easier to handle multiple
input files.  Also happens to be easier to read.

--- a/src/sox.c
+++ b/src/sox.c
@@ -48,14 +48,6 @@
 #endif
 #endif
 
-#if defined(VMS)
-#define LASTCHAR	']'
-#elif defined(DOS) || defined(WIN32)
-#define LASTCHAR	'\\'
-#else
-#define LASTCHAR        '/'
-#endif
-
 /*
  * SOX main program.
  *
@@ -78,6 +70,10 @@
 
 /* local forward declarations */
 static void doopts(ft_t, int, char **);
+static void copy_input(ft_t);
+static void open_input(ft_t);
+static void copy_output(ft_t);
+static void open_output(ft_t);
 static void usage(char *) NORET;
 static int filetype(int);
 static void process(void);
@@ -88,8 +84,13 @@
 static int flow_effect(int);
 static int drain_effect(int);
 
-static ft_t informat = 0, outformat = 0;
+#define MAX_INPUT_FILES 1
+#define REQUIRED_INPUT_FILES 1
+static ft_t informat[MAX_INPUT_FILES] = { 0 };
+static int input_count = 0;
 
+static ft_t outformat = 0;
+
 /* We parse effects into a temporary effects table and then place into
  * the real effects table.  This makes it easier to reorder some effects
  * as needed.  For instance, we can run a resampling effect before
@@ -121,9 +122,9 @@
 int argc;
 char **argv;
 {
-
         int argc_effect;
 	ft_t ft;
+	int parsing_output = 0;
 
 	myname = argv[0];
 
@@ -132,75 +133,101 @@
 	{
 	
 	    /* 
-	     * Its possible to not specify the output filename by using "-e" option.
-	     * This allows effects to be ran on data but no output file to be
-	     * written.  This loop basically ingores the "-e" option for input files.
+	     * Its possible to not specify the output filename by using 
+	     * "-e" option. This allows effects to be ran on data but 
+	     * no output file to be written.
 	     */
 	    if (strcmp(argv[optind], "-e"))
-		writing = 1;
-	    else {
-		writing = 0;
-		optind++;  /* Move passed -e */
+	    {
+		/* No -e option appears to be set.  Attempt to see if
+		 * this is the last filename or not.  If we see no more
+		 * options or an effect name then we assume this is
+		 * the last filename.
+		 */
+		if (optind == (argc-1) || 
+		    st_checkeffect(argv[optind+1]) == ST_SUCCESS ||
+		    input_count >= MAX_INPUT_FILES)
+		{
+		    parsing_output = 1;
+		}
+
+		if (parsing_output)
+		    writing = 1;
 	    }
+	    else 
+	    {
+		/* -e option found.  Make sure this was done on the
+		 * output side.  Should be no more parameters or
+		 * a valid effects name.
+		 */
+		if (optind == (argc-1) || 
+		    st_checkeffect(argv[optind+1]) == ST_SUCCESS ||
+		    input_count >= MAX_INPUT_FILES)
+		{
+		    parsing_output = 1;
+		}
 
+		if (parsing_output)
+		{
+		    writing = 0;
+		    optind++;  /* Move passed -e */
+		}
+		else
+		{
+		    usage("Can only specify \"-e\" for output filenames");
+		}
+	    }
+
 	    ft = (ft_t)malloc(sizeof(struct st_soundstream));
 	    st_initformat(ft);
 
 	    doopts(ft, argc, argv);
 
-	    if (optind < argc && writing)
+	    /* See if we have all the input filenames we need.  
+	     * If not, then parse this as input filenames.
+	     *
+	     * If we have enough but haven't reached the max #
+	     * of inputs, then only treat this as an input filename
+	     * if it looks like we have more filenames left.
+	     */
+	    if (input_count < REQUIRED_INPUT_FILES ||
+		(input_count < MAX_INPUT_FILES &&
+		 optind < argc && 
+		 st_checkeffect(argv[optind]) != ST_SUCCESS))
 	    {
 		ft->filename = argv[optind];
 		optind++;
-	    }
-	    else
-	    {
-		ft->filename = 0;
-	    }
 
-	    /* 
-	     * Determine if we will need to loop around again.  If we don't
-	     * then we know we just grabbed the output file information.
-	     */
-	    /* FIXME: When this file handles multiple input filenames,
-	     * remove the check for !informat.  Instead store next empty
-	     * slot in array of input filename.
-	     */
-	    if (!informat && optind < argc && 
-		st_checkeffect(argv[optind]) != ST_SUCCESS)
-	    {
-		informat = ft;
-
-		if (! strcmp(informat->filename, "-"))
-		    informat->fp = stdin;
-		else if ((informat->fp = fopen(informat->filename, READBINARY)) == NULL)
-		    st_fail("Can't open input file '%s': %s", 
-			    informat->filename, strerror(errno));
-#if	defined(DUMB_FILESYSTEM)
-		informat->seekable = 0;
-#else
-		informat->seekable  = (filetype(fileno(informat->fp)) == S_IFREG);
-#endif
+		copy_input(ft);
+		open_input(ft);
 	    }
 	    else
 	    {
-		outformat = ft;
-		if (writing)
+		if (optind < argc && writing)
 		{
-		    /* Hold off on opening file until the very last minute.
-		     * This allows us to verify header in input files are
-		     * what they should be and parse effect command lines.
-		     * That way if anything is found invalid, we will abort
-		     * without truncating any existing file that has the same
-		     * output filename.
-		     */
+		    ft->filename = argv[optind];
+		    optind++;
 		}
+		else
+		{
+		    ft->filename = 0;
+		}
+
+		copy_output(ft);
+		/* Hold off on opening file until the very last minute.
+		 * This allows us to verify header in input files are
+		 * what they should be and parse effect command lines.
+		 * That way if anything is found invalid, we will abort
+		 * without truncating any existing file that has the same
+		 * output filename.
+		 */
 	    }
 	}
 
-	/* Make sure we got all required filenames */
-	if (!informat || !informat->filename)
-	    usage("No input file?");
+	/* Make sure we got at least the required # of input filename */
+	if (!informat[REQUIRED_INPUT_FILES-1] || 
+	    !informat[REQUIRED_INPUT_FILES-1]->filename)
+	    usage("Not enough input files not specified");
 
 	if (!outformat || (!outformat->filename && writing))
 	    usage("No output file?");
@@ -241,43 +268,123 @@
 	    nuser_effects++;
 	}
 
-	/* Check global arguments */
+	if (dovolume)
+	    st_report("Volume factor: %f\n", volume);
 
-	/* negative volume is phase-reversal */
 	if (dovolume && volume < 0.0)
 	    st_report("Volume adjustment is negative.  This will result in a phase change\n");
-
-	/* If file types have not been set with -t, set from file names. */
-	if (! informat->filetype) {
-		if ((informat->filetype = strrchr(informat->filename, LASTCHAR)) != NULL)
-			informat->filetype++;
-		else
-			informat->filetype = informat->filename;
-		if ((informat->filetype = strrchr(informat->filetype, '.')) != NULL)
-			informat->filetype++;
-		else /* Default to "auto" */
-			informat->filetype = "auto";
-	}
-	if (writing && ! outformat->filetype) {
-		if ((outformat->filetype = strrchr(outformat->filename, LASTCHAR)) != NULL)
-			outformat->filetype++;
-		else
-			outformat->filetype = outformat->filename;
-		if ((outformat->filetype = strrchr(outformat->filetype, '.')) != NULL)
-			outformat->filetype++;
-	}
-	/* Default the input comment to the filename. 
-	 * The output comment will be assigned when the informat 
-	 * structure is copied to the outformat. 
-	 * FIXME: Should be a memory copy, not a pointer asignment.
-	 */
-	informat->comment = informat->filename;
-
+ 
 	process();
 	statistics();
 	return(0);
 }
 
+static void copy_input(ft_t ft)
+{
+    informat[input_count] = ft;
+
+    /* If filetype has not been set by command line options then
+     * attempt to get it from filename extension.
+     */
+    if (!ft->filetype) 
+    {
+	if ((ft->filetype = strrchr(ft->filename, '.')) != NULL)
+	    ft->filetype++;
+	else /* Default to "auto" */
+	    ft->filetype = "auto";
+    }
+
+    /* See if we understand this type of file */
+    if( st_gettype(ft) )
+	st_fail("Unknown input file format for '%s'.  Use -t option to override",ft->filename);	
+
+    /* Default the input comment to the filename if not set from
+     * command line.
+     * FIXME: Should be a memory copy, not a pointer asignment.
+     */
+    if (!ft->comment)
+    	ft->comment = ft->filename;
+
+    input_count++;
+}
+
+static void open_input(ft_t ft)
+{
+    /* Open file handler based on input name.  Used stdin file handler
+     * if the filename is "="
+     */
+    if (! strcmp(ft->filename, "-"))
+	ft->fp = stdin;
+    else if ((ft->fp = fopen(ft->filename, READBINARY)) == NULL)
+	st_fail("Can't open input file '%s': %s", ft->filename, 
+		strerror(errno));
+
+    /* See if this file is seekable or not */
+#if	defined(DUMB_FILESYSTEM)
+    ft->seekable = 0;
+#else
+    ft->seekable = (filetype(fileno(ft->fp)) == S_IFREG);
+#endif
+}
+
+static void copy_output(ft_t ft)
+{
+    outformat = ft;
+
+    if (writing && !ft->filetype) {
+	if ((ft->filetype = strrchr(ft->filename, '.')) != NULL)
+	    ft->filetype++;
+	else
+	    ft->filetype = ft->filename;
+    }
+
+    if ( st_gettype(ft) )
+	st_fail("Unknown output file format for '%s'.  Use -t option to override",ft->filename);
+}
+
+static void open_output(ft_t ft)
+{
+    if (writing) {
+	/*
+	 * There are two choices here:
+	 *	1) stomp the old file - normal shell "> file" behavior
+	 *	2) fail if the old file already exists - csh mode
+	 */
+	if (! strcmp(ft->filename, "-"))
+	{
+	    ft->fp = stdout;
+
+	    /* stdout tends to be line-buffered.  Override this */
+	    /* to be Full Buffering. */
+	    if (setvbuf (ft->fp,NULL,_IOFBF,sizeof(char)*BUFSIZ))
+	    {
+		st_fail("Can't set write buffer");
+	    }
+	}
+	else {
+
+	    ft->fp = fopen(ft->filename, WRITEBINARY);
+
+	    if (ft->fp == NULL)
+		st_fail("Can't open output file '%s': %s", 
+			ft->filename, strerror(errno));
+
+	    /* stdout tends to be line-buffered.  Override this */
+	    /* to be Full Buffering. */
+	    if (setvbuf (ft->fp,NULL,_IOFBF,sizeof(char)*BUFSIZ))
+	    {
+		st_fail("Can't set write buffer");
+	    }
+
+	} /* end of else != stdout */
+#if	defined(DUMB_FILESYSTEM)
+	ft->seekable = 0;
+#else
+	ft->seekable  = (filetype(fileno(ft->fp)) == S_IFREG);
+#endif
+    }
+}
+
 #ifdef HAVE_GETOPT_H
 static char *getoptstr = "+r:v:t:c:phsuUAaigbwlfdDxV";
 #else
@@ -407,79 +514,43 @@
 static void process(void) {
     int e, f, flowstatus;
 
-    if( st_gettype(informat) )
-		st_fail("Unknown input file format for '%s'.  Use -t option to override",informat->filename);	
-    if (writing)
-	if ( st_gettype(outformat) )
-		st_fail("Unknown output file format for '%s'.  Use -t option to override",outformat->filename);
-    
+   
     /* Read and write starters can change their formats. */
-    if ((* informat->h->startread)(informat) == ST_EOF)
+    if ((* informat[0]->h->startread)(informat[0]) == ST_EOF)
     {
-        st_fail(informat->st_errstr);
+        st_fail(informat[0]->st_errstr);
     }
 
-    /* Go a head and assume 1 channel audio if nothing is detected. */
-    if (informat->info.channels == -1)
-	informat->info.channels = 1;
+    /* Go a head and assume 1 channel audio if nothing is detected. 
+     * This is because libst usually doesn't set this for mono file
+     * formats (for historical reasons).
+     */
+    if (informat[0]->info.channels == -1)
+	informat[0]->info.channels = 1;
 
-    if ( st_checkformat(informat) )
+    if ( st_checkformat(informat[0]) )
 		st_fail("bad input format");
     
-    if (dovolume)
-	st_report("Volume factor: %f\n", volume);
-    
+   
     st_report("Input file: using sample rate %lu\n\tsize %s, encoding %s, %d %s",
-	   informat->info.rate, st_sizes_str[informat->info.size], 
-	   st_encodings_str[informat->info.encoding], informat->info.channels, 
-	   (informat->info.channels > 1) ? "channels" : "channel");
-    if (informat->comment)
-	st_report("Input file: comment \"%s\"\n", informat->comment);
-	
-    if (writing) {
-        /*
-         * There are two choices here:
-	 *	1) stomp the old file - normal shell "> file" behavior
-	 *	2) fail if the old file already exists - csh mode
-	 */
-	 if (! strcmp(outformat->filename, "-"))
-	 {
-	    outformat->fp = stdout;
+	   informat[0]->info.rate, st_sizes_str[informat[0]->info.size], 
+	   st_encodings_str[informat[0]->info.encoding], informat[0]->info.channels, 
+	   (informat[0]->info.channels > 1) ? "channels" : "channel");
 
-	    /* stdout tends to be line-buffered.  Override this */
-	    /* to be Full Buffering. */
-	    if (setvbuf (outformat->fp,NULL,_IOFBF,sizeof(char)*BUFSIZ))
-	    {
-	        st_fail("Can't set write buffer");
-	    }
-	 }
-         else {
+    if (informat[0]->comment)
+	st_report("Input file: comment \"%s\"\n", informat[0]->comment);
 
-	     outformat->fp = fopen(outformat->filename, WRITEBINARY);
+    if (writing)
+    {
+	open_output(outformat);
 
-	     if (outformat->fp == NULL)
-	         st_fail("Can't open output file '%s': %s", 
-		      outformat->filename, strerror(errno));
+	st_copyformat(informat[0], outformat);
 
-	     /* stdout tends to be line-buffered.  Override this */
-	     /* to be Full Buffering. */
-	     if (setvbuf (outformat->fp,NULL,_IOFBF,sizeof(char)*BUFSIZ))
-	     {
-	         st_fail("Can't set write buffer");
-	     }
-
-        } /* end of else != stdout */
-#if	defined(DUMB_FILESYSTEM)
-	outformat->seekable = 0;
-#else
-	outformat->seekable  = (filetype(fileno(outformat->fp)) == S_IFREG);
-#endif
-
-	st_copyformat(informat, outformat);
-	if ((* outformat->h->startwrite)(outformat) == ST_EOF)
+	if ((*outformat->h->startwrite)(outformat) == ST_EOF)
 	{
 	    st_fail(outformat->st_errstr);
 	}
+
 	if (st_checkformat(outformat))
 		st_fail("bad output format");
 
@@ -487,6 +558,7 @@
 	       outformat->info.rate, st_sizes_str[outformat->info.size], 
 	       st_encodings_str[outformat->info.encoding], outformat->info.channels, 
 	       (outformat->info.channels > 1) ? "channels" : "channel");
+
 	if (outformat->comment)
 	    st_report("Output file: comment \"%s\"\n", outformat->comment);
     }
@@ -524,12 +596,12 @@
      * Just like errno, we must set st_errno to known values before
      * calling I/O operations.
      */
-    informat->st_errno = 0;
+    informat[0]->st_errno = 0;
     outformat->st_errno = 0;
 
     /* Run input data through effects and get more until olen == 0 */
     do {
-        efftab[0].olen = (*informat->h->read)(informat, 
+        efftab[0].olen = (*informat[0]->h->read)(informat[0], 
                                               efftab[0].obuf, (LONG) BUFSIZ);
         efftab[0].odone = 0;
 
@@ -553,8 +625,8 @@
 
     } while (1); /* break; efftab[0].olen == 0 */
 
-    if (informat->st_errno)
-	st_fail(informat->st_errstr);
+    if (informat[0]->st_errno)
+	st_fail(informat[0]->st_errstr);
 
     /* Drain the effects out first to last, 
      * pushing residue through subsequent effects */
@@ -587,9 +659,9 @@
 	    (* efftabR[e].h->stop)(&efftabR[e]);
     }
 
-    if ((* informat->h->stopread)(informat) == ST_EOF)
-	st_fail(informat->st_errstr);
-    fclose(informat->fp);
+    if ((* informat[0]->h->stopread)(informat[0]) == ST_EOF)
+	st_fail(informat[0]->st_errstr);
+    fclose(informat[0]->fp);
 
     if (writing)
     {
@@ -761,8 +833,8 @@
 	int needchan = 0, needrate = 0, haschan = 0, hasrate = 0;
 	int effects_mask = 0;
 
-	needrate = (informat->info.rate != outformat->info.rate);
-	needchan = (informat->info.channels != outformat->info.channels);
+	needrate = (informat[0]->info.rate != outformat->info.rate);
+	needchan = (informat[0]->info.channels != outformat->info.channels);
 
 	for (i = 0; i < nuser_effects; i++)
 	{
@@ -804,7 +876,7 @@
 	 * after the avg effect.
 	 */
         if (needchan && !(haschan) &&
-	    (informat->info.channels > outformat->info.channels))
+	    (informat[0]->info.channels > outformat->info.channels))
         {
 	    /* Find effect and update initial pointers */
 	    st_geteffect(&efftab[neffects], "avg");
@@ -814,7 +886,7 @@
 					    (char **)0);
 
 	    /* Copy format info to effect table */
-	    effects_mask = st_updateeffect(&efftab[neffects], informat, 
+	    effects_mask = st_updateeffect(&efftab[neffects], informat[0], 
 		                           outformat, effects_mask);
 
 	    neffects++;
@@ -824,7 +896,7 @@
 	 * after the resample effect.
 	 */
 	if (needrate && !(hasrate) &&
-	    (informat->info.rate > outformat->info.rate))
+	    (informat[0]->info.rate > outformat->info.rate))
 	{
 	    if (soxpreview)
 	        st_geteffect(&efftab[neffects], "rate");
@@ -836,7 +908,7 @@
 					    (char **)0);
 
 	    /* Copy format info to effect table */
-	    effects_mask = st_updateeffect(&efftab[neffects], informat, 
+	    effects_mask = st_updateeffect(&efftab[neffects], informat[0], 
 		                           outformat, effects_mask);
 
 	    /* Rate can't handle multiple channels so be sure and
@@ -858,7 +930,7 @@
 		   sizeof(struct st_effect));
 
 	    /* Copy format info to effect table */
-	    effects_mask = st_updateeffect(&efftab[neffects], informat, 
+	    effects_mask = st_updateeffect(&efftab[neffects], informat[0], 
 		                           outformat, effects_mask);
 
 	    /* If this effect can't handle multiple channels then
@@ -890,7 +962,7 @@
 					    (char **)0);
 
 	    /* Copy format info to effect table */
-	    effects_mask = st_updateeffect(&efftab[neffects], informat, 
+	    effects_mask = st_updateeffect(&efftab[neffects], informat[0], 
 		                           outformat, effects_mask);
 
 	    /* Rate can't handle multiple channels so be sure and
@@ -917,7 +989,7 @@
 					    (char **)0);
 
 	    /* Copy format info to effect table */
-	    effects_mask = st_updateeffect(&efftab[neffects], informat, 
+	    effects_mask = st_updateeffect(&efftab[neffects], informat[0], 
 		                           outformat, effects_mask);
 
 	    neffects++;
@@ -1001,8 +1073,8 @@
 /* called from util.c:fail */
 void cleanup(void) {
 	/* Close the input file and outputfile before exiting*/
-	if (informat && informat->fp)
-		fclose(informat->fp);
+	if (informat[0] && informat[0]->fp)
+		fclose(informat[0]->fp);
 	if (outformat && outformat->fp) {
 		fclose(outformat->fp);
 		/* remove the output file because we failed, if it's ours. */