ref: fbcad60e3523e7525f4c7ca49b2c9d3666d98f46
parent: 4cb7d826e03ac02689c8c5240e7af5931b10a257
author: Rob Sykes <robs@users.sourceforge.net>
date: Sun Apr 24 16:52:34 EDT 2011
Fix lock-up when a special-file option is given with another option in the same argv string (e.g. sox -np synth ...).
--- a/src/sox.c
+++ b/src/sox.c
@@ -106,6 +106,9 @@
/*#define MORE_INTERACTIVE 1*/
+#define SOX_OPTS "SOX_OPTS"
+static lsx_getopt_t optstate;
+
/* argv[0] options */
static char const * myname = NULL;
@@ -131,7 +134,6 @@
{0, 0}};
static rg_mode replay_gain_mode = RG_default;
static sox_option_t show_progress = SOX_OPTION_DEFAULT;
-#define SOX_OPTS "SOX_OPTS"
/* Input & output files */
@@ -742,9 +744,9 @@
return sox_false;
} /* is_pseudo_effect */
-static void parse_effects(int * argi, int argc, char ** argv)
+static void parse_effects(int argc, char ** argv)
{
- while (*argi < argc) {
+ while (optstate.ind < argc) {
unsigned eff_offset;
int j;
int newline_mode = 0;
@@ -756,7 +758,7 @@
}
/* psuedo-effect ":" is used to create a new effects chain */
- if (strcmp(argv[*argi], ":") == 0)
+ if (strcmp(argv[optstate.ind], ":") == 0)
{
/* Only create a new chain if current one has effects.
* Error checking will be done when loop is restarted.
@@ -766,15 +768,15 @@
eff_chain_count++;
add_eff_chain();
}
- (*argi)++;
+ optstate.ind++;
continue;
}
- if (strcmp(argv[*argi], "newfile") == 0)
+ if (strcmp(argv[optstate.ind], "newfile") == 0)
{
/* Start a new effect chain for newfile if user doesn't
* manually do it. Restart loop without advancing
- * argi to do error checking.
+ * optstate.ind to do error checking.
*/
if (nuser_effects[eff_chain_count] != 0)
{
@@ -784,11 +786,11 @@
}
newline_mode = 1;
}
- else if (strcmp(argv[*argi], "restart") == 0)
+ else if (strcmp(argv[optstate.ind], "restart") == 0)
{
/* Start a new effect chain for restart if user doesn't
* manually do it. Restart loop without advancing
- * argi to do error checking.
+ * optstate.ind to do error checking.
*/
if (nuser_effects[eff_chain_count] != 0)
{
@@ -800,13 +802,13 @@
}
/* Name should always be correct! */
- user_effargs[eff_chain_count][eff_offset].name = strdup(argv[(*argi)++]);
- for (j = 0; j < argc - *argi && !sox_find_effect(argv[*argi + j]) &&
- !is_pseudo_effect(argv[*argi + j]); ++j)
- user_effargs[eff_chain_count][eff_offset].argv[j] = strdup(argv[*argi + j]);
+ user_effargs[eff_chain_count][eff_offset].name = strdup(argv[optstate.ind++]);
+ for (j = 0; j < argc - optstate.ind && !sox_find_effect(argv[optstate.ind + j]) &&
+ !is_pseudo_effect(argv[optstate.ind + j]); ++j)
+ user_effargs[eff_chain_count][eff_offset].argv[j] = strdup(argv[optstate.ind + j]);
user_effargs[eff_chain_count][eff_offset].argc = j;
- *argi += j; /* Skip past the effect arguments */
+ optstate.ind += j; /* Skip past the effect arguments */
nuser_effects[eff_chain_count]++;
if (newline_mode)
{
@@ -877,8 +879,6 @@
argv = strtoargv(s, &argc);
if (argv) {
- int argi;
-
/* Make sure first option is an effect name. */
if (!sox_find_effect(argv[0]) && !is_pseudo_effect(argv[0]))
{
@@ -886,8 +886,12 @@
exit(1);
}
- argi = 0;
- parse_effects(&argi, argc, argv);
+ /* parse_effects normally parses options from command line.
+ * Reset opt index so it thinks its back at beginning of
+ * main()'s argv[].
+ */
+ optstate.ind = 0;
+ parse_effects(argc, argv);
/* Advance to next effect but only if current chain has been
* filled in. This recovers from side affects of psuedo-effects.
@@ -2138,11 +2142,9 @@
return p->value;
}
-static char parse_gopts_and_fopts(file_t * f, int * argi, int argc, char **argv)
+static char parse_gopts_and_fopts(file_t * f)
{
- lsx_getopt_t optstate;
const sox_version_info_t* info = sox_version_info();
- lsx_getopt_init(argc, argv, getoptstr, long_options, lsx_getopt_flag_opterr, *argi, &optstate);
while (sox_true) {
int c;
int i; /* sscanf silently accepts negative numbers for %u :( */
@@ -2150,7 +2152,6 @@
switch (c=lsx_getopt(&optstate)) {
case -1: /* @ one of: file-name, effect name, end of arg-list. */
- *argi = optstate.ind;
return '\0'; /* i.e. not device. */
case 0: /* Long options with no short equivalent. */
@@ -2240,7 +2241,7 @@
break;
case 'd': case 'n': case 'p':
- *argi = optstate.ind;
+ optstate.ind = optstate.ind;
return c;
case 'h':
@@ -2466,7 +2467,7 @@
f->replay_gain = HUGE_VAL;
}
-static void parse_options_and_filenames(int * argi, int argc, char **argv)
+static void parse_options_and_filenames(int argc, char **argv)
{
char const * env_opts = getenv(SOX_OPTS);
file_t opts, opts_none;
@@ -2478,12 +2479,12 @@
if (env_opts && *env_opts) {
char * * argv2, * str = lsx_malloc(strlen(argv[0]) + strlen(env_opts) + 2);
int argc2;
- int argi2 = 1;
strcpy(str, argv[0]);
strcat(str, " ");
strcat(str, env_opts);
argv2 = strtoargv(str, &argc2);
- if (parse_gopts_and_fopts(&opts, &argi2, argc2, argv2)) {
+ lsx_getopt_init(argc2, argv2, getoptstr, long_options, lsx_getopt_flag_opterr, 1, &optstate);
+ if (parse_gopts_and_fopts(&opts)) {
lsx_fail("invalid option for "SOX_OPTS);
exit(1);
}
@@ -2491,8 +2492,9 @@
free(argv2);
}
- for (; *argi < argc && !sox_find_effect(argv[*argi]); init_file(&opts)) {
- char c = parse_gopts_and_fopts(&opts, argi, argc, argv);
+ lsx_getopt_init(argc, argv, getoptstr, long_options, lsx_getopt_flag_opterr, 1, &optstate);
+ for (; optstate.ind < argc && !sox_find_effect(argv[optstate.ind]); init_file(&opts)) {
+ char c = parse_gopts_and_fopts(&opts);
if (c == 'n') { /* is null file? */
if (opts.filetype != NULL && strcmp(opts.filetype, "null") != 0)
lsx_warn("ignoring `-t %s'.", opts.filetype);
@@ -2507,11 +2509,11 @@
opts.filetype = "sox";
add_file(&opts, "-");
}
- else if (*argi >= argc || sox_find_effect(argv[*argi]))
+ else if (optstate.ind >= argc || sox_find_effect(argv[optstate.ind]))
break;
- else if (!sox_is_playlist(argv[*argi]))
- add_glob_file(&opts, argv[(*argi)++]);
- else if (sox_parse_playlist((sox_playlist_callback_t)add_file, &opts, argv[(*argi)++]) != SOX_SUCCESS)
+ else if (!sox_is_playlist(argv[optstate.ind]))
+ add_glob_file(&opts, argv[optstate.ind++]);
+ else if (sox_parse_playlist((sox_playlist_callback_t)add_file, &opts, argv[optstate.ind++]) != SOX_SUCCESS)
exit(1);
}
if (env_opts && *env_opts) {
@@ -2594,17 +2596,16 @@
exit(return_code);
}
-static int soxi(int * argi, int argc, char * const * argv)
+static int soxi(int argc, char * const * argv)
{
static char const opts[] = "trcsdDbBea?TV::";
soxi_t type = Full;
int opt, num_errors = 0;
sox_bool do_total = sox_false;
- lsx_getopt_t optstate;
- if (argc - *argi < 1)
+ if (argc < 2)
soxi_usage(0);
- lsx_getopt_init(argc, argv, opts, NULL, lsx_getopt_flag_opterr, *argi, &optstate);
+ lsx_getopt_init(argc, argv, opts, NULL, lsx_getopt_flag_opterr, 1, &optstate);
while ((opt = lsx_getopt(&optstate)) > 0) /* act only on last option */
if (opt == 'V') {
int i; /* sscanf silently accepts negative numbers for %u :( */
@@ -2700,7 +2701,6 @@
int main(int argc, char **argv)
{
size_t i;
- int argi = 1;
myname = argv[0];
sox_globals.output_message_handler = output_message;
@@ -2714,7 +2714,7 @@
if (!sox_mode && argc > 1 &&
(!strcmp(argv[1], "--i") || !strcmp(argv[1], "--info")))
- ++argi, sox_mode = sox_soxi;
+ --argc, ++argv, sox_mode = sox_soxi;
if (sox_init() != SOX_SUCCESS)
exit(1);
@@ -2725,9 +2725,9 @@
atexit(cleanup);
if (sox_mode == sox_soxi)
- exit(soxi(&argi, argc, argv));
+ exit(soxi(argc, argv));
- parse_options_and_filenames(&argi, argc, argv);
+ parse_options_and_filenames(argc, argv);
#if defined(__CYGWIN__) || defined(__MINGW32__)
/* Workarounds for a couple of cygwin/mingw problems: */
@@ -2835,7 +2835,7 @@
init_eff_chains();
/* Loop through the rest of the arguments looking for effects */
- parse_effects(&argi, argc, argv);
+ parse_effects(argc, argv);
if (eff_chain_count == 0 || nuser_effects[eff_chain_count] > 0)
{
eff_chain_count++;