shithub: sox

Download patch

ref: 1ecccdb9ae2721fd209b9af872987a3efa7278a7
parent: 7d66951a4e92e5fd78e9fbe843c82d4ab5992bd5
author: robs <robs>
date: Sun May 6 13:32:09 EDT 2007

Protection against concurrent use of stdin/stdout.
Don't allow noiseprof to use stderr (it's for diagnostics).
Allow noisered filename to be optional; fail if threshold out of range.

--- a/src/biquad.c
+++ b/src/biquad.c
@@ -66,7 +66,7 @@
   p->a2 = p->a2/p->a0;
   p->a1 = p->a1/p->a0;
 
-  if (effp->globalinfo->plot == sox_plot_octave) {
+  if (effp->global_info->plot == sox_plot_octave) {
     printf(
       "%% GNU Octave file (may also work with MATLAB(R) )\n"
       "title('SoX effect: %s gain=%g frequency=%g %s=%g (rate=%u)')\n"
@@ -86,7 +86,7 @@
       );
     return SOX_EOF;
   }
-  if (effp->globalinfo->plot == sox_plot_gnuplot) {
+  if (effp->global_info->plot == sox_plot_gnuplot) {
     printf(
       "# gnuplot file\n"
       "set title 'SoX effect: %s gain=%g frequency=%g %s=%g (rate=%u)'\n"
--- a/src/compand.c
+++ b/src/compand.c
@@ -137,7 +137,7 @@
   for (i = 0; i < l->expectedChannels; ++i)
     sox_debug("Channel %i: attack = %g decay = %g", i,
         l->channels[i].attack_times[0], l->channels[i].attack_times[1]);
-  if (!sox_compandt_show(&l->transfer_fn, effp->globalinfo->plot))
+  if (!sox_compandt_show(&l->transfer_fn, effp->global_info->plot))
     return SOX_EOF;
 
   /* Convert attack and decay rates using number of samples */
--- a/src/noiseprof.c
+++ b/src/noiseprof.c
@@ -59,33 +59,34 @@
  */
 static int sox_noiseprof_start(eff_t effp)
 {
-    profdata_t data = (profdata_t) effp->priv;
-    unsigned channels = effp->ininfo.channels;
-    unsigned i;
+  profdata_t data = (profdata_t) effp->priv;
+  unsigned channels = effp->ininfo.channels;
+  unsigned i;
    
-    if (data->output_filename != NULL) {
-        if (strcmp(data->output_filename, "-") != 0)
-          data->output_file = fopen(data->output_filename, "w");
-        else
-          data->output_file = stdout;
-        if (data->output_file == NULL) {
-            sox_fail("Couldn't open output file %s: %s",
-                    data->output_filename, strerror(errno));            
-        }
-    } else {
-        /* FIXME: We should detect output to stdout, and redirect to stderr. */
-        data->output_file = stderr;
+  /* Note: don't fall back to stderr if stdout is unavailable
+   * since we already use stderr for diagnostics. */
+  if (!data->output_filename || !strcmp(data->output_filename, "-")) {
+    if (effp->global_info->global_info->stdout_in_use_by) {
+      sox_fail("stdout already in use by '%s'", effp->global_info->global_info->stdout_in_use_by);
+      return SOX_EOF;
     }
+    effp->global_info->global_info->stdout_in_use_by = effp->name;
+    data->output_file = stdout;
+  }
+  else if ((data->output_file = fopen(data->output_filename, "w")) == NULL) {
+    sox_fail("Couldn't open profile file %s: %s", data->output_filename, strerror(errno));
+    return SOX_EOF;
+  }
 
-    data->chandata = (chandata_t*)xcalloc(channels, sizeof(*(data->chandata)));
-    data->bufdata = 0;
-    for (i = 0; i < channels; i ++) {
-        data->chandata[i].sum = (float*)xcalloc(FREQCOUNT, sizeof(float));
-        data->chandata[i].profilecount = (int*)xcalloc(FREQCOUNT, sizeof(int));
-        data->chandata[i].window = (float*)xcalloc(WINDOWSIZE, sizeof(float));
-    }
+  data->chandata = (chandata_t*)xcalloc(channels, sizeof(*(data->chandata)));
+  data->bufdata = 0;
+  for (i = 0; i < channels; i ++) {
+    data->chandata[i].sum = (float*)xcalloc(FREQCOUNT, sizeof(float));
+    data->chandata[i].profilecount = (int*)xcalloc(FREQCOUNT, sizeof(int));
+    data->chandata[i].window = (float*)xcalloc(WINDOWSIZE, sizeof(float));
+  }
 
-    return SOX_SUCCESS;
+  return SOX_SUCCESS;
 }
 
 /* Collect statistics from the complete window on channel chan. */
@@ -192,8 +193,9 @@
         fprintf(data->output_file, "Channel %d: ", i);
 
         for (j = 0; j < FREQCOUNT; j ++) {
-            fprintf(data->output_file, "%s%f", j == 0 ? "" : ", ",
-                    chan->sum[j] / chan->profilecount[j]);
+            double r = chan->profilecount[j] != 0 ?
+                    chan->sum[j] / chan->profilecount[j] : 0;
+            fprintf(data->output_file, "%s%f", j == 0 ? "" : ", ", r);
         }
         fprintf(data->output_file, "\n");
 
@@ -203,7 +205,7 @@
 
     free(data->chandata);
 
-    if (data->output_file != stderr && data->output_file != stdout)
+    if (data->output_file != stdout)
         fclose(data->output_file);
     
     return (SOX_SUCCESS);
--- a/src/noisered.c
+++ b/src/noisered.c
@@ -16,6 +16,21 @@
 #include <string.h>
 #include <assert.h>
 
+#define NUMERIC_PARAMETER(p, min, max) { \
+  char * end_ptr; \
+  double d; \
+  if (argc == 0) break; \
+  d = strtod(*argv, &end_ptr); \
+  if (end_ptr != *argv) { \
+    if (d < min || d > max || *end_ptr != '\0') { \
+      sox_fail(effp->h->usage); \
+      return SOX_EOF; \
+    } \
+    this->p = d; \
+    --argc, ++argv; \
+  } \
+}
+
 static sox_effect_t sox_noisered_effect;
 
 typedef struct chandata {
@@ -35,32 +50,29 @@
 } * reddata_t;
 
 /*
- * Get the options. Filename is mandatory, though a reasonable default would
- * be stdin (if the input file isn't coming from there, of course!)
+ * Get the options. Default file is stdin (if the audio
+ * input file isn't coming from there, of course!)
  */
-static int sox_noisered_getopts(eff_t effp, int n, char **argv) 
+static int sox_noisered_getopts(eff_t effp, int argc, char **argv)
 {
-    reddata_t data = (reddata_t) effp->priv;
+  reddata_t this = (reddata_t) effp->priv;
 
-    if (n > 2 || n < 1) {
-            sox_fail(sox_noisered_effect.usage);
-            return (SOX_EOF);
-    }
-    data->threshold = 0.5;
-    data->profile_filename = argv[0];
-    if (n == 2)
-    {
-        data->threshold = atof(argv[1]);
+  if (argc > 0) {
+    this->profile_filename = argv[0];
+    ++argv;
+    --argc;
+  }
 
-        if (data->threshold > 1)
-        {
-            data->threshold = 1;
-        } else if (data->threshold < 0)
-        {
-            data->threshold = 0;
-        }
-    }
-    return (SOX_SUCCESS);
+  this->threshold = 0.5;
+  do {     /* break-able block */
+    NUMERIC_PARAMETER(threshold, 0, 1);
+  } while (0);
+
+  if (argc != 0) {
+    sox_fail(effp->h->usage);
+    return SOX_EOF;
+  }
+  return SOX_SUCCESS;
 }
 
 /*
@@ -84,13 +96,17 @@
     }
 
     /* Here we actually open the input file. */
-    if (strcmp(data->profile_filename, "-") == 0)
+    if (!data->profile_filename || !strcmp(data->profile_filename, "-")) {
+      if (effp->global_info->global_info->stdin_in_use_by) {
+        sox_fail("stdin already in use by '%s'", effp->global_info->global_info->stdin_in_use_by);
+        return SOX_EOF;
+      }
+      effp->global_info->global_info->stdin_in_use_by = effp->name;
       ifp = stdin;
-    else
-      ifp = fopen(data->profile_filename, "r");
-    if (ifp == NULL) {
+    }
+    else if ((ifp = fopen(data->profile_filename, "r")) == NULL) {
         sox_fail("Couldn't open profile file %s: %s",
-                data->profile_filename, strerror(errno));            
+                data->profile_filename, strerror(errno));
         return SOX_EOF;
     }
 
@@ -121,7 +137,7 @@
                 channels, fchannels);
         return SOX_EOF;
     }
-    if (strcmp(data->profile_filename, "-") != 0)
+    if (ifp != stdin)
       fclose(ifp);
 
     return (SOX_SUCCESS);
--- a/src/rabbit.c
+++ b/src/rabbit.c
@@ -89,8 +89,8 @@
   /* The next line makes the "speed" effect accurate; it's needed because
    * ininfo.rate (sox_rate_t) isn't floating point (but it's probably not worth
    * changing sox_rate_t just because of this): */
-  double in_rate = floor(effp->ininfo.rate / effp->globalinfo->speed + .5)
-    * effp->globalinfo->speed;
+  double in_rate = floor(effp->ininfo.rate / effp->global_info->speed + .5)
+    * effp->global_info->speed;
 
   if (in_rate == effp->outinfo.rate)
     return SOX_EFF_NULL;
--- a/src/resample.c
+++ b/src/resample.c
@@ -201,8 +201,8 @@
   /* The next line makes the "speed" effect accurate; it's needed because
    * ininfo.rate (sox_rate_t) isn't floating point (but it's probably not worth
    * changing sox_rate_t just because of this): */
-  double in_rate = floor(effp->ininfo.rate / effp->globalinfo->speed + .5)
-    * effp->globalinfo->speed;
+  double in_rate = floor(effp->ininfo.rate / effp->global_info->speed + .5)
+    * effp->global_info->speed;
 
   if (in_rate == effp->outinfo.rate)
     return SOX_EFF_NULL;
--- a/src/sox.c
+++ b/src/sox.c
@@ -63,7 +63,7 @@
 static sox_size_t mixing_clips = 0;
 static sox_bool repeatable_random = sox_false;  /* Whether to invoke srand. */
 static sox_bool interactive = sox_false;
-static sox_globalinfo_t globalinfo = {sox_false, 1};
+static sox_effects_global_info_t effects_global_info = {sox_false, 1, &sox_global_info};
 static sox_bool uservolume = sox_false;
 typedef enum {RG_off, RG_track, RG_album} rg_mode;
 static rg_mode replay_gain_mode = RG_off;
@@ -807,7 +807,7 @@
         break;
 
       case 7:
-        globalinfo.plot = enum_option(option_index, plot_methods);
+        effects_global_info.plot = enum_option(option_index, plot_methods);
         break;
 
       case 8:
@@ -1124,7 +1124,7 @@
   if (ofile->signal.channels == 0)
     ofile->signal.channels = combiner.channels;
 
-  combiner.rate = combiner.rate * globalinfo.speed + .5;
+  combiner.rate = combiner.rate * effects_global_info.speed + .5;
 
   for (i = 0; i < nuser_effects; i++)
     known_length = known_length && !(user_efftab[i].h->flags & SOX_EFF_LENGTH);
@@ -1321,7 +1321,7 @@
       sox_warn("Effect `%s' is deprecated and may be removed in a future release; please refer to the manual sox(1) for an alternative effect", e->name);
 
     optind++; /* Skip past effect name */
-    e->globalinfo = &globalinfo;
+    e->global_info = &effects_global_info;
     getopts = e->h->getopts?  e->h->getopts : sox_effect_nothing_getopts;
     if (getopts(e, argc_effect, &argv[optind]) == SOX_EOF)
       exit(2);
@@ -1355,7 +1355,7 @@
   sox_geteffect(e, name);
 
   /* Set up & give default opts for added effects */
-  e->globalinfo = &globalinfo;
+  e->global_info = &effects_global_info;
   getopts = e->h->getopts?  e->h->getopts : sox_effect_nothing_getopts;
   if (getopts(e, 0, NULL) == SOX_EOF)
     exit(2);
--- a/src/sox.h
+++ b/src/sox.h
@@ -186,16 +186,26 @@
   SOX_ENCODINGS            /* End of list marker */
 } sox_encoding_t;
 
+typedef struct sox_global_info /* Global parameters (for effects & formats) */
+{
+  char const * stdin_in_use_by;
+  char const * stdout_in_use_by;
+} sox_global_info_t;
+
 typedef enum {sox_plot_off, sox_plot_octave, sox_plot_gnuplot} sox_plot_t;
 
-/* Global parameters (for effects) */
-
-typedef struct  sox_globalinfo
+typedef struct sox_effects_global_info /* Global parameters (for effects) */
 {
   sox_plot_t plot;         /* To help the user choose effect & options */
   double speed;            /* Gather up all speed changes here, then resample */
-} sox_globalinfo_t;
+  sox_global_info_t * global_info;
+} sox_effects_global_info_t;
 
+typedef struct sox_formats_global_info /* Global parameters (for formats) */
+{
+  sox_global_info_t * global_info;
+} sox_formats_global_info_t;
+
 typedef enum {SOX_OPTION_NO, SOX_OPTION_YES, SOX_OPTION_DEFAULT} sox_option_t;
 
 /* Signal parameters */
@@ -380,7 +390,7 @@
 struct sox_effect
 {
     char const *name;               /* effect name */
-    struct sox_globalinfo * globalinfo;/* global parameters */
+    struct sox_effects_global_info * global_info;/* global parameters */
     struct sox_signalinfo ininfo;    /* input signal specifications */
     struct sox_signalinfo outinfo;   /* output signal specifications */
     const sox_effect_t *h;           /* effects driver */
--- a/src/sox_i.h
+++ b/src/sox_i.h
@@ -210,6 +210,7 @@
  * data to get max performance.
  */
 extern sox_size_t sox_bufsiz;
+extern sox_global_info_t sox_global_info;
 
 extern const char sox_readerr[];
 extern const char sox_writerr[];
--- a/src/soxio.c
+++ b/src/soxio.c
@@ -26,6 +26,7 @@
 #endif
 
 sox_size_t sox_bufsiz = 8192;
+sox_global_info_t sox_global_info;
 
 void set_endianness_if_not_already_set(ft_t ft)
 {
@@ -129,10 +130,14 @@
         /* Open file handler based on input name.  Used stdin file handler
          * if the filename is "-"
          */
-        if (!strcmp(ft->filename, "-"))
-        {
-            SET_BINARY_MODE(stdin);
-            ft->fp = stdin;
+        if (!strcmp(ft->filename, "-")) {
+          if (sox_global_info.stdin_in_use_by) {
+            sox_fail("'-' (stdin) already in use by '%s'", sox_global_info.stdin_in_use_by);
+            goto input_error;
+          }
+          sox_global_info.stdin_in_use_by = "audio input";
+          SET_BINARY_MODE(stdin);
+          ft->fp = stdin;
         }
         else if ((ft->fp = xfopen(ft->filename, "rb")) == NULL)
         {
@@ -241,8 +246,12 @@
         /* Open file handler based on output name.  Used stdout file handler
          * if the filename is "-"
          */
-        if (!strcmp(ft->filename, "-"))
-        {
+        if (!strcmp(ft->filename, "-")) {
+          if (sox_global_info.stdout_in_use_by) {
+            sox_fail("'-' (stdout) already in use by '%s'", sox_global_info.stdout_in_use_by);
+            goto output_error;
+          }
+          sox_global_info.stdout_in_use_by = "audio output";
             SET_BINARY_MODE(stdout);
             ft->fp = stdout;
         }
--- a/src/speed.c
+++ b/src/speed.c
@@ -42,7 +42,7 @@
     if (scanned == 1 || (scanned == 2 && c == 'c')) {
       is_cents |= scanned == 2;
       if (is_cents || speed > 0) {
-        effp->globalinfo->speed *= is_cents? pow(2., speed/1200) : speed;
+        effp->global_info->speed *= is_cents? pow(2., speed/1200) : speed;
         return SOX_SUCCESS;
       }
     }