mirror of
http://mpg123.de/trunk/.git
synced 2025-10-23 16:48:31 +03:00
getlopt: Machinery to avoid leaking strdup() memory.
Hm, why are we using strdup, anyway? git-svn-id: svn://scm.orgis.org/mpg123/trunk@4657 35dc7657-300d-0410-a2e5-dc2837fedb53
This commit is contained in:
2
NEWS
2
NEWS
@@ -7,6 +7,8 @@
|
|||||||
It is an open question how that should be developed in relation to the
|
It is an open question how that should be developed in relation to the
|
||||||
external regression and compliance test suite. Maybe some really small
|
external regression and compliance test suite. Maybe some really small
|
||||||
example streams and decode tests will follow.
|
example streams and decode tests will follow.
|
||||||
|
- Finally silenced memory checkers about leaking memory from getlopt()
|
||||||
|
(main code overwriting values without freeing strdup() strings).
|
||||||
- AUTORS now in UTF-8;-)
|
- AUTORS now in UTF-8;-)
|
||||||
- CMake build files in ports/cmake, as an alternative to create MSVC
|
- CMake build files in ports/cmake, as an alternative to create MSVC
|
||||||
project files and the like (thanks to Vitaly Kirsanov)
|
project files and the like (thanks to Vitaly Kirsanov)
|
||||||
|
@@ -33,7 +33,32 @@ topt *findopt (int islong, char *opt, topt *opts)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int performoption (int argc, char *argv[], topt *opt)
|
static void setcharoption(topt *opt, char *value)
|
||||||
|
{
|
||||||
|
if(!opt->var)
|
||||||
|
{
|
||||||
|
merror("Option %s has no argument pointer!", opt->lname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(opt->flags & GLO_VAR_MEM)
|
||||||
|
free(*((char**)opt->var));
|
||||||
|
if(value)
|
||||||
|
{
|
||||||
|
*((char **) opt->var) = compat_strdup(value);
|
||||||
|
opt->flags |= GLO_VAR_MEM;
|
||||||
|
} else
|
||||||
|
opt->flags &= ~GLO_VAR_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
void getlopt_set_char(topt *opts, char *name, char *value)
|
||||||
|
{
|
||||||
|
topt *opt = findopt(1, name, opts);
|
||||||
|
if(!opt)
|
||||||
|
return;
|
||||||
|
setcharoption(opt, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int performoption (int argc, char *argv[], topt *opt, topt *opts)
|
||||||
{
|
{
|
||||||
int result = GLO_CONTINUE;
|
int result = GLO_CONTINUE;
|
||||||
/* this really is not supposed to happen, so the exit may be justified to create asap ficing pressure */
|
/* this really is not supposed to happen, so the exit may be justified to create asap ficing pressure */
|
||||||
@@ -50,7 +75,7 @@ static int performoption (int argc, char *argv[], topt *opt)
|
|||||||
if (opt->flags & GLO_CHAR) /* var is *char */
|
if (opt->flags & GLO_CHAR) /* var is *char */
|
||||||
{
|
{
|
||||||
debug1("char at %p", opt->var);
|
debug1("char at %p", opt->var);
|
||||||
*((char *) opt->var) = (char) opt->value;\
|
*((char *) opt->var) = (char) opt->value;
|
||||||
}
|
}
|
||||||
else if(opt->flags & GLO_LONG)
|
else if(opt->flags & GLO_LONG)
|
||||||
{
|
{
|
||||||
@@ -80,7 +105,7 @@ static int performoption (int argc, char *argv[], topt *opt)
|
|||||||
loptchr = 0;
|
loptchr = 0;
|
||||||
if (opt->var) {
|
if (opt->var) {
|
||||||
if (opt->flags & GLO_CHAR) /* var is *char */
|
if (opt->flags & GLO_CHAR) /* var is *char */
|
||||||
*((char **) opt->var) = compat_strdup(loptarg); /* valgrind claims lost memory here */
|
setcharoption(opt, loptarg);
|
||||||
else if(opt->flags & GLO_LONG)
|
else if(opt->flags & GLO_LONG)
|
||||||
*((long *) opt->var) = atol(loptarg);
|
*((long *) opt->var) = atol(loptarg);
|
||||||
else if(opt->flags & GLO_INT)
|
else if(opt->flags & GLO_INT)
|
||||||
@@ -95,7 +120,7 @@ static int performoption (int argc, char *argv[], topt *opt)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (opt->func)
|
if (opt->func)
|
||||||
opt->func(loptarg);
|
opt->func(loptarg, opts);
|
||||||
debug4("result: %i (%p, %li, %i)", result, opt->var, opt->value, opt->sname);
|
debug4("result: %i (%p, %li, %i)", result, opt->var, opt->value, opt->sname);
|
||||||
return (result);
|
return (result);
|
||||||
}
|
}
|
||||||
@@ -120,7 +145,7 @@ int getsingleopt (int argc, char *argv[], topt *opts)
|
|||||||
if (!(opt = findopt(1, thisopt+2, opts)))
|
if (!(opt = findopt(1, thisopt+2, opts)))
|
||||||
return (GLO_UNKNOWN);
|
return (GLO_UNKNOWN);
|
||||||
else
|
else
|
||||||
return (performoption(argc, argv, opt));
|
return (performoption(argc, argv, opt, opts));
|
||||||
}
|
}
|
||||||
else { /* "--" == end of options */
|
else { /* "--" == end of options */
|
||||||
loptind++;
|
loptind++;
|
||||||
@@ -140,7 +165,7 @@ int getsingleopt (int argc, char *argv[], topt *opts)
|
|||||||
if (!opt)
|
if (!opt)
|
||||||
return (GLO_UNKNOWN);
|
return (GLO_UNKNOWN);
|
||||||
else
|
else
|
||||||
return (performoption(argc, argv, opt));
|
return (performoption(argc, argv, opt, opts));
|
||||||
}
|
}
|
||||||
|
|
||||||
int getlopt (int argc, char *argv[], topt *opts)
|
int getlopt (int argc, char *argv[], topt *opts)
|
||||||
|
@@ -18,14 +18,16 @@ extern int loptind; /* index in argv[] */
|
|||||||
extern int loptchr; /* index in argv[loptind] */
|
extern int loptchr; /* index in argv[loptind] */
|
||||||
extern char *loptarg; /* points to argument if present, else to option */
|
extern char *loptarg; /* points to argument if present, else to option */
|
||||||
|
|
||||||
typedef struct {
|
struct topt;
|
||||||
|
typedef struct topt topt;
|
||||||
|
struct topt {
|
||||||
char sname; /* short option name, can be 0 */
|
char sname; /* short option name, can be 0 */
|
||||||
char *lname; /* long option name, can be 0 */
|
char *lname; /* long option name, can be 0 */
|
||||||
int flags; /* see below */
|
int flags; /* see below */
|
||||||
void (*func)(char *); /* called if != 0 (after setting of var) */
|
void (*func)(char *, topt *); /* called if != 0 (after setting of var) */
|
||||||
void *var; /* type is *long, *char or **char, see below */
|
void *var; /* type is *long, *char or **char, see below */
|
||||||
long value;
|
long value;
|
||||||
} topt;
|
};
|
||||||
|
|
||||||
/* ThOr: make this clear; distict long from int (since this is != on my Alpha) and really use a flag for every case (spare the 0 case
|
/* ThOr: make this clear; distict long from int (since this is != on my Alpha) and really use a flag for every case (spare the 0 case
|
||||||
for .... no flag) */
|
for .... no flag) */
|
||||||
@@ -34,6 +36,8 @@ for .... no flag) */
|
|||||||
#define GLO_INT 4
|
#define GLO_INT 4
|
||||||
#define GLO_LONG 8
|
#define GLO_LONG 8
|
||||||
#define GLO_DOUBLE 16
|
#define GLO_DOUBLE 16
|
||||||
|
/* This is set if getlopt allocates memory for var. */
|
||||||
|
#define GLO_VAR_MEM 32
|
||||||
|
|
||||||
/* flags:
|
/* flags:
|
||||||
* bit 0 = 0 - no argument
|
* bit 0 = 0 - no argument
|
||||||
@@ -64,7 +68,8 @@ for .... no flag) */
|
|||||||
#define GLO_CONTINUE -3
|
#define GLO_CONTINUE -3
|
||||||
|
|
||||||
int getlopt (int argc, char *argv[], topt *opts);
|
int getlopt (int argc, char *argv[], topt *opts);
|
||||||
|
// Helper to set a char parameter, avoiding memory leaks.
|
||||||
|
void getlopt_set_char(topt *opts, char *name, char *value);
|
||||||
/* return values:
|
/* return values:
|
||||||
* GLO_END (0) end of options
|
* GLO_END (0) end of options
|
||||||
* GLO_UNKNOWN (-1) unknown option *loptarg
|
* GLO_UNKNOWN (-1) unknown option *loptarg
|
||||||
|
@@ -46,12 +46,12 @@ static void usage(int err)
|
|||||||
exit(err);
|
exit(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void want_usage(char* bla)
|
static void want_usage(char* bla, topt *opts)
|
||||||
{
|
{
|
||||||
usage(0);
|
usage(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_verbose (char *arg)
|
static void set_verbose (char *arg, topt *opts)
|
||||||
{
|
{
|
||||||
param.verbose++;
|
param.verbose++;
|
||||||
}
|
}
|
||||||
|
70
src/mpg123.c
70
src/mpg123.c
@@ -45,11 +45,11 @@
|
|||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
static void usage(int err);
|
static void usage(int err);
|
||||||
static void want_usage(char* arg);
|
static void want_usage(char* arg, topt *);
|
||||||
static void long_usage(int err);
|
static void long_usage(int err);
|
||||||
static void want_long_usage(char* arg);
|
static void want_long_usage(char* arg, topt *);
|
||||||
static void print_title(FILE* o);
|
static void print_title(FILE* o);
|
||||||
static void give_version(char* arg);
|
static void give_version(char* arg, topt *);
|
||||||
|
|
||||||
struct parameter param = {
|
struct parameter param = {
|
||||||
FALSE , /* aggressiv */
|
FALSE , /* aggressiv */
|
||||||
@@ -328,7 +328,7 @@ static void check_fatal_output(int code)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_output_module( char *arg )
|
static void set_output_module(char *arg, topt *opts)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
@@ -336,7 +336,7 @@ static void set_output_module( char *arg )
|
|||||||
for(i=0; i< strlen( arg ); i++) {
|
for(i=0; i< strlen( arg ); i++) {
|
||||||
if (arg[i] == ':') {
|
if (arg[i] == ':') {
|
||||||
arg[i] = 0;
|
arg[i] = 0;
|
||||||
param.output_device = &arg[i+1];
|
getlopt_set_char(opts, "audiodevice", &arg[i+1]);
|
||||||
debug1("Setting output device: %s", param.output_device);
|
debug1("Setting output device: %s", param.output_device);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -352,38 +352,38 @@ static void set_output_flag(int flag)
|
|||||||
else param.output_flags |= flag;
|
else param.output_flags |= flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_output_h(char *a)
|
static void set_output_h(char *a, topt *opts)
|
||||||
{
|
{
|
||||||
set_output_flag(OUT123_HEADPHONES);
|
set_output_flag(OUT123_HEADPHONES);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_output_s(char *a)
|
static void set_output_s(char *a, topt *opts)
|
||||||
{
|
{
|
||||||
set_output_flag(OUT123_INTERNAL_SPEAKER);
|
set_output_flag(OUT123_INTERNAL_SPEAKER);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_output_l(char *a)
|
static void set_output_l(char *a, topt *opts)
|
||||||
{
|
{
|
||||||
set_output_flag(OUT123_LINE_OUT);
|
set_output_flag(OUT123_LINE_OUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_output(char *arg)
|
static void set_output(char *arg, topt *opts)
|
||||||
{
|
{
|
||||||
/* If single letter, it's the legacy output switch for AIX/HP/Sun.
|
/* If single letter, it's the legacy output switch for AIX/HP/Sun.
|
||||||
If longer, it's module[:device] . If zero length, it's rubbish. */
|
If longer, it's module[:device] . If zero length, it's rubbish. */
|
||||||
if(strlen(arg) <= 1) switch(arg[0])
|
if(strlen(arg) <= 1) switch(arg[0])
|
||||||
{
|
{
|
||||||
case 'h': set_output_h(arg); break;
|
case 'h': set_output_h(arg, opts); break;
|
||||||
case 's': set_output_s(arg); break;
|
case 's': set_output_s(arg, opts); break;
|
||||||
case 'l': set_output_l(arg); break;
|
case 'l': set_output_l(arg, opts); break;
|
||||||
default:
|
default:
|
||||||
error1("\"%s\" is no valid output", arg);
|
error1("\"%s\" is no valid output", arg);
|
||||||
safe_exit(1);
|
safe_exit(1);
|
||||||
}
|
}
|
||||||
else set_output_module(arg);
|
else set_output_module(arg, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_resample(char *arg)
|
static void set_resample(char *arg, topt *opts)
|
||||||
{
|
{
|
||||||
if(!strcasecmp("ntom", arg))
|
if(!strcasecmp("ntom", arg))
|
||||||
param.resample = 0;
|
param.resample = 0;
|
||||||
@@ -398,51 +398,51 @@ static void set_resample(char *arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_verbose (char *arg)
|
static void set_verbose (char *arg, topt *opts)
|
||||||
{
|
{
|
||||||
param.verbose++;
|
param.verbose++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_quiet (char *arg)
|
static void set_quiet (char *arg, topt *opts)
|
||||||
{
|
{
|
||||||
param.verbose=0;
|
param.verbose=0;
|
||||||
param.quiet=TRUE;
|
param.quiet=TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_out_wav(char *arg)
|
static void set_out_wav(char *arg, topt *opts)
|
||||||
{
|
{
|
||||||
param.output_module = "wav";
|
param.output_module = "wav";
|
||||||
param.output_device = arg;
|
getlopt_set_char(opts, "audiodevice", arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_out_cdr(char *arg)
|
void set_out_cdr(char *arg, topt *opts)
|
||||||
{
|
{
|
||||||
param.output_module = "cdr";
|
param.output_module = "cdr";
|
||||||
param.output_device = arg;
|
getlopt_set_char(opts, "audiodevice", arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_out_au(char *arg)
|
void set_out_au(char *arg, topt *opts)
|
||||||
{
|
{
|
||||||
param.output_module = "au";
|
param.output_module = "au";
|
||||||
param.output_device = arg;
|
getlopt_set_char(opts, "audiodevice", arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_out_test(char *arg)
|
void set_out_test(char *arg, topt *opts)
|
||||||
{
|
{
|
||||||
param.output_module = "test";
|
param.output_module = "test";
|
||||||
param.output_device = NULL;
|
getlopt_set_char(opts, "audiodevice", NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_out_file(char *arg)
|
static void set_out_file(char *arg, topt *opts)
|
||||||
{
|
{
|
||||||
param.output_module = "raw";
|
param.output_module = "raw";
|
||||||
param.output_device = arg;
|
getlopt_set_char(opts, "audiodevice", arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_out_stdout(char *arg)
|
static void set_out_stdout(char *arg, topt *opts)
|
||||||
{
|
{
|
||||||
param.output_module = "raw";
|
param.output_module = "raw";
|
||||||
param.output_device = NULL;
|
getlopt_set_char(opts, "audiodevice", NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined (HAVE_SCHED_SETSCHEDULER) && !defined (HAVE_WINDOWS_H)
|
#if !defined (HAVE_SCHED_SETSCHEDULER) && !defined (HAVE_WINDOWS_H)
|
||||||
@@ -453,24 +453,24 @@ static void realtime_not_compiled(char *arg)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int frameflag; /* ugly, but that's the way without hacking getlopt */
|
static int frameflag; /* ugly, but that's the way without hacking getlopt */
|
||||||
static void set_frameflag(char *arg)
|
static void set_frameflag(char *arg, topt *opts)
|
||||||
{
|
{
|
||||||
/* Only one mono flag at a time! */
|
/* Only one mono flag at a time! */
|
||||||
if(frameflag & MPG123_FORCE_MONO) param.flags &= ~MPG123_FORCE_MONO;
|
if(frameflag & MPG123_FORCE_MONO) param.flags &= ~MPG123_FORCE_MONO;
|
||||||
param.flags |= frameflag;
|
param.flags |= frameflag;
|
||||||
}
|
}
|
||||||
static void unset_frameflag(char *arg)
|
static void unset_frameflag(char *arg, topt *opts)
|
||||||
{
|
{
|
||||||
param.flags &= ~frameflag;
|
param.flags &= ~frameflag;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int appflag; /* still ugly, but works */
|
static int appflag; /* still ugly, but works */
|
||||||
static void set_appflag(char *arg)
|
static void set_appflag(char *arg, topt *opts)
|
||||||
{
|
{
|
||||||
param.appflags |= appflag;
|
param.appflags |= appflag;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void list_output_modules(char *arg)
|
static void list_output_modules(char *arg, topt *opts)
|
||||||
{
|
{
|
||||||
char **names = NULL;
|
char **names = NULL;
|
||||||
char **descr = NULL;
|
char **descr = NULL;
|
||||||
@@ -1556,7 +1556,7 @@ static void usage(int err) /* print syntax & exit */
|
|||||||
safe_exit(err);
|
safe_exit(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void want_usage(char* arg)
|
static void want_usage(char* arg, topt *opts)
|
||||||
{
|
{
|
||||||
usage(0);
|
usage(0);
|
||||||
}
|
}
|
||||||
@@ -1707,12 +1707,12 @@ static void long_usage(int err)
|
|||||||
safe_exit(err);
|
safe_exit(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void want_long_usage(char* arg)
|
static void want_long_usage(char* arg, topt *opts)
|
||||||
{
|
{
|
||||||
long_usage(0);
|
long_usage(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void give_version(char* arg)
|
static void give_version(char* arg, topt *opts)
|
||||||
{
|
{
|
||||||
fprintf(stdout, PACKAGE_NAME" "PACKAGE_VERSION"\n");
|
fprintf(stdout, PACKAGE_NAME" "PACKAGE_VERSION"\n");
|
||||||
safe_exit(0);
|
safe_exit(0);
|
||||||
|
Reference in New Issue
Block a user