Commit de31f430 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

getopt: use stack instead of global variables, fixes #3366

parent 8c390d9b
...@@ -49,19 +49,18 @@ ...@@ -49,19 +49,18 @@
* @param p_this object to write command line options as variables to * @param p_this object to write command line options as variables to
* @param i_argc number of command line arguments * @param i_argc number of command line arguments
* @param ppsz_args commandl ine arguments [IN/OUT] * @param ppsz_args commandl ine arguments [IN/OUT]
* @param b_ignore_errors whether to ignore parsing errors * @param pindex NULL to ignore unknown options,
* otherwise index of the first non-option argument [OUT]
* @return 0 on success, -1 on error. * @return 0 on success, -1 on error.
*
* @warning This function is not re-entrant (because of getopt_long()).
* It must be called with the module bank initialization global lock held.
*/ */
int config_LoadCmdLine( vlc_object_t *p_this, int i_argc, int config_LoadCmdLine( vlc_object_t *p_this, int i_argc,
const char *ppsz_argv[], bool b_ignore_errors ) const char *ppsz_argv[], int *pindex )
{ {
int i_cmd, i_index, i_opts, i_shortopts, flag, i_verbose = 0; int i_cmd, i_index, i_opts, i_shortopts, flag, i_verbose = 0;
module_t *p_parser; module_t *p_parser;
struct vlc_option *p_longopts; struct vlc_option *p_longopts;
const char **argv_copy = NULL; const char **argv_copy = NULL;
#define b_ignore_errors (pindex == NULL)
/* Short options */ /* Short options */
module_config_t *pp_shortopts[256]; module_config_t *pp_shortopts[256];
...@@ -200,10 +199,11 @@ int config_LoadCmdLine( vlc_object_t *p_this, int i_argc, ...@@ -200,10 +199,11 @@ int config_LoadCmdLine( vlc_object_t *p_this, int i_argc,
/* /*
* Parse the command line options * Parse the command line options
*/ */
vlc_optind = 0; /* set to 0 to tell GNU getopt to reinitialize */ vlc_getopt_t state;
state.optind = 0 ; /* set to 0 to tell GNU getopt to reinitialize */
while( ( i_cmd = vlc_getopt_long( i_argc, (char **)ppsz_argv, while( ( i_cmd = vlc_getopt_long( i_argc, (char **)ppsz_argv,
psz_shortopts, psz_shortopts,
p_longopts, &i_index ) ) != -1 ) p_longopts, &i_index, &state ) ) != -1 )
{ {
/* A long option has been recognized */ /* A long option has been recognized */
if( i_cmd == 0 ) if( i_cmd == 0 )
...@@ -252,21 +252,21 @@ int config_LoadCmdLine( vlc_object_t *p_this, int i_argc, ...@@ -252,21 +252,21 @@ int config_LoadCmdLine( vlc_object_t *p_this, int i_argc,
case CONFIG_ITEM_MODULE_LIST_CAT: case CONFIG_ITEM_MODULE_LIST_CAT:
case CONFIG_ITEM_MODULE_CAT: case CONFIG_ITEM_MODULE_CAT:
var_Create( p_this, psz_name, VLC_VAR_STRING ); var_Create( p_this, psz_name, VLC_VAR_STRING );
var_SetString( p_this, psz_name, vlc_optarg ); var_SetString( p_this, psz_name, state.optarg );
break; break;
case CONFIG_ITEM_INTEGER: case CONFIG_ITEM_INTEGER:
var_Create( p_this, psz_name, VLC_VAR_INTEGER ); var_Create( p_this, psz_name, VLC_VAR_INTEGER );
var_SetInteger( p_this, psz_name, var_SetInteger( p_this, psz_name,
strtol(vlc_optarg, NULL, 0)); strtol(state.optarg, NULL, 0));
break; break;
case CONFIG_ITEM_FLOAT: case CONFIG_ITEM_FLOAT:
var_Create( p_this, psz_name, VLC_VAR_FLOAT ); var_Create( p_this, psz_name, VLC_VAR_FLOAT );
var_SetFloat( p_this, psz_name, us_atof(vlc_optarg) ); var_SetFloat( p_this, psz_name, us_atof(state.optarg) );
break; break;
case CONFIG_ITEM_KEY: case CONFIG_ITEM_KEY:
var_Create( p_this, psz_name, VLC_VAR_INTEGER ); var_Create( p_this, psz_name, VLC_VAR_INTEGER );
var_SetInteger( p_this, psz_name, var_SetInteger( p_this, psz_name,
ConfigStringToKey( vlc_optarg ) ); ConfigStringToKey( state.optarg ) );
break; break;
case CONFIG_ITEM_BOOL: case CONFIG_ITEM_BOOL:
var_Create( p_this, psz_name, VLC_VAR_BOOL ); var_Create( p_this, psz_name, VLC_VAR_BOOL );
...@@ -292,7 +292,7 @@ int config_LoadCmdLine( vlc_object_t *p_this, int i_argc, ...@@ -292,7 +292,7 @@ int config_LoadCmdLine( vlc_object_t *p_this, int i_argc,
case CONFIG_ITEM_MODULE_LIST: case CONFIG_ITEM_MODULE_LIST:
case CONFIG_ITEM_MODULE_LIST_CAT: case CONFIG_ITEM_MODULE_LIST_CAT:
var_Create( p_this, name, VLC_VAR_STRING ); var_Create( p_this, name, VLC_VAR_STRING );
var_SetString( p_this, name, vlc_optarg ); var_SetString( p_this, name, state.optarg );
break; break;
case CONFIG_ITEM_INTEGER: case CONFIG_ITEM_INTEGER:
var_Create( p_this, name, VLC_VAR_INTEGER ); var_Create( p_this, name, VLC_VAR_INTEGER );
...@@ -304,7 +304,7 @@ int config_LoadCmdLine( vlc_object_t *p_this, int i_argc, ...@@ -304,7 +304,7 @@ int config_LoadCmdLine( vlc_object_t *p_this, int i_argc,
else else
{ {
var_SetInteger( p_this, name, var_SetInteger( p_this, name,
strtol(vlc_optarg, NULL, 0) ); strtol(state.optarg, NULL, 0) );
} }
break; break;
case CONFIG_ITEM_BOOL: case CONFIG_ITEM_BOOL:
...@@ -321,13 +321,13 @@ int config_LoadCmdLine( vlc_object_t *p_this, int i_argc, ...@@ -321,13 +321,13 @@ int config_LoadCmdLine( vlc_object_t *p_this, int i_argc,
{ {
fputs( "vlc: unknown option" fputs( "vlc: unknown option"
" or missing mandatory argument ", stderr ); " or missing mandatory argument ", stderr );
if( vlc_optopt ) if( state.optopt )
{ {
fprintf( stderr, "`-%c'\n", vlc_optopt ); fprintf( stderr, "`-%c'\n", state.optopt );
} }
else else
{ {
fprintf( stderr, "`%s'\n", ppsz_argv[vlc_optind-1] ); fprintf( stderr, "`%s'\n", ppsz_argv[state.optind-1] );
} }
fputs( "Try `vlc --help' for more information.\n", stderr ); fputs( "Try `vlc --help' for more information.\n", stderr );
goto out; goto out;
...@@ -335,6 +335,8 @@ int config_LoadCmdLine( vlc_object_t *p_this, int i_argc, ...@@ -335,6 +335,8 @@ int config_LoadCmdLine( vlc_object_t *p_this, int i_argc,
} }
ret = 0; ret = 0;
if( pindex != NULL )
*pindex = state.optind;
out: out:
/* Free allocated resources */ /* Free allocated resources */
for( i_index = 0; p_longopts[i_index].name; i_index++ ) for( i_index = 0; p_longopts[i_index].name; i_index++ )
......
...@@ -36,7 +36,7 @@ int config_AutoSaveConfigFile( vlc_object_t * ); ...@@ -36,7 +36,7 @@ int config_AutoSaveConfigFile( vlc_object_t * );
void config_Free( module_t * ); void config_Free( module_t * );
int config_LoadCmdLine ( vlc_object_t *, int, const char *[], bool ); int config_LoadCmdLine ( vlc_object_t *, int, const char *[], int * );
int config_LoadConfigFile( vlc_object_t *, const char * ); int config_LoadConfigFile( vlc_object_t *, const char * );
#define config_LoadCmdLine(a,b,c,d) config_LoadCmdLine(VLC_OBJECT(a),b,c,d) #define config_LoadCmdLine(a,b,c,d) config_LoadCmdLine(VLC_OBJECT(a),b,c,d)
#define config_LoadConfigFile(a,b) config_LoadConfigFile(VLC_OBJECT(a),b) #define config_LoadConfigFile(a,b) config_LoadConfigFile(VLC_OBJECT(a),b)
......
This diff is collapsed.
...@@ -22,13 +22,13 @@ ...@@ -22,13 +22,13 @@
#ifndef VLC_GETOPT_H #ifndef VLC_GETOPT_H
#define VLC_GETOPT_H 1 #define VLC_GETOPT_H 1
typedef struct vlc_getopt_s
{
/* For communication from `getopt' to the caller. /* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument, When `getopt' finds an option that takes an argument,
the argument value is returned here. the argument value is returned here. */
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
extern char *vlc_optarg; char *optarg;
/* Index in ARGV of the next element to be scanned. /* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller This is used for communication to and from the caller
...@@ -42,11 +42,31 @@ extern char *vlc_optarg; ...@@ -42,11 +42,31 @@ extern char *vlc_optarg;
Otherwise, `optind' communicates from one call to the next Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */ how much of ARGV has been scanned so far. */
extern int vlc_optind; int optind;
/* Set to an option character which was unrecognized. */ /* Set to an option character which was unrecognized. */
extern int vlc_optopt; int optopt;
/* The next char to be scanned in the option-element
in which the last option character we returned was found.
This allows us to pick up the scan where we left off.
If this is zero, or a null string, it means resume the scan
by advancing to the next ARGV-element. */
char *nextchar;
/* Handle permutation of arguments. */
/* Describe the part of ARGV that contains non-options that have
been skipped. `first_nonopt' is the index in ARGV of the first of them;
`last_nonopt' is the index after the last of them. */
int first_nonopt;
int last_nonopt;
} vlc_getopt_t;
/* Describe the long-named options requested by the application. /* Describe the long-named options requested by the application.
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
...@@ -77,6 +97,7 @@ struct vlc_option ...@@ -77,6 +97,7 @@ struct vlc_option
}; };
extern int vlc_getopt_long(int argc, char *const *argv, const char *shortopts, extern int vlc_getopt_long(int argc, char *const *argv, const char *shortopts,
const struct vlc_option *longopts, int *longind); const struct vlc_option *longopts, int *longind,
vlc_getopt_t *restrict state);
#endif /* VLC_GETOPT_H */ #endif /* VLC_GETOPT_H */
...@@ -321,7 +321,7 @@ int libvlc_InternalInit( libvlc_int_t *p_libvlc, int i_argc, ...@@ -321,7 +321,7 @@ int libvlc_InternalInit( libvlc_int_t *p_libvlc, int i_argc,
* options) */ * options) */
module_InitBank( p_libvlc ); module_InitBank( p_libvlc );
if( config_LoadCmdLine( p_libvlc, i_argc, ppsz_argv, true ) ) if( config_LoadCmdLine( p_libvlc, i_argc, ppsz_argv, NULL ) )
{ {
module_EndBank( p_libvlc, false ); module_EndBank( p_libvlc, false );
return VLC_EGENERIC; return VLC_EGENERIC;
...@@ -534,10 +534,8 @@ int libvlc_InternalInit( libvlc_int_t *p_libvlc, int i_argc, ...@@ -534,10 +534,8 @@ int libvlc_InternalInit( libvlc_int_t *p_libvlc, int i_argc,
/* /*
* Override configuration with command line settings * Override configuration with command line settings
*/ */
/* config_LoadCmdLine(), DBus (below) and Win32-specific use vlc_optind, int vlc_optind;
* vlc_optarg and vlc_optopt globals. This is not thread-safe!! */ if( config_LoadCmdLine( p_libvlc, i_argc, ppsz_argv, &vlc_optind ) )
#warning BUG!
if( config_LoadCmdLine( p_libvlc, i_argc, ppsz_argv, false ) )
{ {
#ifdef WIN32 #ifdef WIN32
ShowConsole( false ); ShowConsole( false );
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment