/** * Parse command line for configuration options. * * Now that the module_bank has been initialized, we can dynamically * generate the longopts structure used by getops. We have to do it this way * because we don't know (and don't want to know) in advance the configuration * options used (ie. exported) by each module. * * @param p_this object to write command line options as variables to * @param i_argc number of command line arguments * @param ppsz_args commandl ine arguments [IN/OUT] * @param pindex NULL to ignore unknown options, * otherwise index of the first non-option argument [OUT] * @return 0 on success, -1 on error. */ int config_LoadCmdLine( vlc_object_t *p_this, int i_argc, const char *ppsz_argv[], int *pindex ) { int i_cmd, i_index, i_opts, i_shortopts, flag, i_verbose = 0; module_t *p_parser; struct vlc_option *p_longopts; const char **argv_copy = NULL; #define b_ignore_errors (pindex == NULL) /* Short options */ module_config_t *pp_shortopts[256]; char *psz_shortopts; /* List all modules */ module_t **list = module_list_get (NULL); /* * Generate the longopts and shortopts structures used by getopt_long */ i_opts = 0; for (size_t i = 0; (p_parser = list[i]) != NULL; i++) /* count the number of exported configuration options (to allocate * longopts). We also need to allocate space for two options when * dealing with boolean to allow for --foo and --no-foo */ i_opts += p_parser->i_config_items + 2 * p_parser->i_bool_items; p_longopts = malloc( sizeof(*p_longopts) * (i_opts + 1) ); if( p_longopts == NULL ) { module_list_free (list); return -1; } psz_shortopts = malloc( 2 * i_opts + 1 ); if( psz_shortopts == NULL ) { free( p_longopts ); module_list_free (list); return -1; } /* If we are requested to ignore errors, then we must work on a copy * of the ppsz_argv array, otherwise getopt_long will reorder it for * us, ignoring the arity of the options */ if( b_ignore_errors ) { argv_copy = (const char**)malloc( i_argc * sizeof(char *) ); if( argv_copy == NULL ) { free( psz_shortopts ); free( p_longopts ); module_list_free (list); return -1; } memcpy( argv_copy, ppsz_argv, i_argc * sizeof(char *) ); ppsz_argv = argv_copy; } i_shortopts = 0; for( i_index = 0; i_index < 256; i_index++ ) { pp_shortopts[i_index] = NULL; } /* Fill the p_longopts and psz_shortopts structures */ i_index = 0; for (size_t i = 0; (p_parser = list[i]) != NULL; i++) { module_config_t *p_item, *p_end; if( !p_parser->i_config_items ) continue; for( p_item = p_parser->p_config, p_end = p_item + p_parser->confsize; p_item < p_end; p_item++ ) { /* Ignore hints */ if( p_item->i_type & CONFIG_HINT ) continue; /* Add item to long options */ p_longopts[i_index].name = strdup( p_item->psz_name ); if( p_longopts[i_index].name == NULL ) continue; p_longopts[i_index].has_arg = (p_item->i_type != CONFIG_ITEM_BOOL); p_longopts[i_index].flag = &flag; p_longopts[i_index].val = 0; i_index++; /* When dealing with bools we also need to add the --no-foo * option */ if( p_item->i_type == CONFIG_ITEM_BOOL ) { char *psz_name = malloc( strlen(p_item->psz_name) + 3 ); if( psz_name == NULL ) continue; strcpy( psz_name, "no" ); strcat( psz_name, p_item->psz_name ); p_longopts[i_index].name = psz_name; p_longopts[i_index].has_arg = false; p_longopts[i_index].flag = &flag; p_longopts[i_index].val = 1; i_index++; psz_name = malloc( strlen(p_item->psz_name) + 4 ); if( psz_name == NULL ) continue; strcpy( psz_name, "no-" ); strcat( psz_name, p_item->psz_name ); p_longopts[i_index].name = psz_name; p_longopts[i_index].has_arg = false; p_longopts[i_index].flag = &flag; p_longopts[i_index].val = 1; i_index++; } /* If item also has a short option, add it */ if( p_item->i_short ) { pp_shortopts[(int)p_item->i_short] = p_item; psz_shortopts[i_shortopts] = p_item->i_short; i_shortopts++; if( p_item->i_type != CONFIG_ITEM_BOOL && p_item->i_short != 'v' ) { psz_shortopts[i_shortopts] = ':'; i_shortopts++; } } } } /* We don't need the module list anymore */ module_list_free( list ); /* Close the longopts and shortopts structures */ memset( &p_longopts[i_index], 0, sizeof(*p_longopts) ); psz_shortopts[i_shortopts] = '\0'; int ret = -1; /* * Parse the command line options */ 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, psz_shortopts, p_longopts, &i_index, &state ) ) != -1 ) { /* A long option has been recognized */ if( i_cmd == 0 ) { module_config_t *p_conf; const char *psz_name = p_longopts[i_index].name; /* Check if we deal with a --nofoo or --no-foo long option */ if( flag ) psz_name += psz_name[2] == '-' ? 3 : 2; /* Store the configuration option */ p_conf = config_FindConfig( p_this, psz_name ); if( p_conf ) { /* Check if the option is deprecated */ if( p_conf->b_removed ) { fprintf(stderr, "Warning: option --%s no longer exists.\n", psz_name); continue; } if( p_conf->psz_oldname && !strcmp( p_conf->psz_oldname, psz_name) ) { if( !b_ignore_errors ) { fprintf( stderr, "Error: option --%s is deprecated. " "Use --%s instead.\n", psz_name, p_conf->psz_name ); goto out; } psz_name = p_conf->psz_name; } switch( p_conf->i_type ) { case CONFIG_ITEM_STRING: case CONFIG_ITEM_PASSWORD: case CONFIG_ITEM_FILE: case CONFIG_ITEM_DIRECTORY: case CONFIG_ITEM_MODULE: case CONFIG_ITEM_MODULE_LIST: case CONFIG_ITEM_MODULE_LIST_CAT: case CONFIG_ITEM_MODULE_CAT: var_Create( p_this, psz_name, VLC_VAR_STRING ); var_SetString( p_this, psz_name, state.optarg ); break; case CONFIG_ITEM_INTEGER: var_Create( p_this, psz_name, VLC_VAR_INTEGER ); var_SetInteger( p_this, psz_name, strtol(state.optarg, NULL, 0)); break; case CONFIG_ITEM_FLOAT: var_Create( p_this, psz_name, VLC_VAR_FLOAT ); var_SetFloat( p_this, psz_name, us_atof(state.optarg) ); break; case CONFIG_ITEM_KEY: var_Create( p_this, psz_name, VLC_VAR_INTEGER ); var_SetInteger( p_this, psz_name, ConfigStringToKey( state.optarg ) ); break; case CONFIG_ITEM_BOOL: var_Create( p_this, psz_name, VLC_VAR_BOOL ); var_SetBool( p_this, psz_name, !flag ); break; } continue; } } /* A short option has been recognized */ if( pp_shortopts[i_cmd] != NULL ) { const char *name = pp_shortopts[i_cmd]->psz_name; switch( pp_shortopts[i_cmd]->i_type ) { case CONFIG_ITEM_STRING: case CONFIG_ITEM_PASSWORD: case CONFIG_ITEM_FILE: case CONFIG_ITEM_DIRECTORY: case CONFIG_ITEM_MODULE: case CONFIG_ITEM_MODULE_CAT: case CONFIG_ITEM_MODULE_LIST: case CONFIG_ITEM_MODULE_LIST_CAT: var_Create( p_this, name, VLC_VAR_STRING ); var_SetString( p_this, name, state.optarg ); break; case CONFIG_ITEM_INTEGER: var_Create( p_this, name, VLC_VAR_INTEGER ); if( i_cmd == 'v' ) { i_verbose++; /* -v */ var_SetInteger( p_this, name, i_verbose ); } else { var_SetInteger( p_this, name, strtol(state.optarg, NULL, 0) ); } break; case CONFIG_ITEM_BOOL: var_Create( p_this, name, VLC_VAR_BOOL ); var_SetBool( p_this, name, true ); break; } continue; } /* Internal error: unknown option */ if( !b_ignore_errors ) { fputs( "vlc: unknown option" " or missing mandatory argument ", stderr ); if( state.optopt ) { fprintf( stderr, "`-%c'\n", state.optopt ); } else { fprintf( stderr, "`%s'\n", ppsz_argv[state.optind-1] ); } fputs( "Try `vlc --help' for more information.\n", stderr ); goto out; } } ret = 0; if( pindex != NULL ) *pindex = state.optind; out: /* Free allocated resources */ for( i_index = 0; p_longopts[i_index].name; i_index++ ) free( (char *)p_longopts[i_index].name ); free( p_longopts ); free( psz_shortopts ); free( argv_copy ); return ret; }
/***************************************************************************** * config_LoadConfigFile: loads the configuration file. ***************************************************************************** * This function is called to load the config options stored in the config * file. *****************************************************************************/ int __config_LoadConfigFile( vlc_object_t *p_this, const char *psz_module_name ) { FILE *file; file = config_OpenConfigFile (p_this); if (file == NULL) return VLC_EGENERIC; /* Look for the selected module, if NULL then save everything */ module_t **list = module_list_get (NULL); /* Look for UTF-8 Byte Order Mark */ char * (*convert) (const char *) = strdupnull; char bom[3]; if ((fread (bom, 1, 3, file) != 3) || memcmp (bom, "\xEF\xBB\xBF", 3)) { convert = FromLocaleDup; rewind (file); /* no BOM, rewind */ } module_t *module = NULL; char line[1024], section[1022]; section[0] = '\0'; /* Ensure consistent number formatting... */ locale_t loc = newlocale (LC_NUMERIC_MASK, "C", NULL); locale_t baseloc = uselocale (loc); while (fgets (line, 1024, file) != NULL) { /* Ignore comments and empty lines */ switch (line[0]) { case '#': case '\n': case '\0': continue; } if (line[0] == '[') { char *ptr = strchr (line, ']'); if (ptr == NULL) continue; /* syntax error; */ *ptr = '\0'; /* New section ( = a given module) */ strcpy (section, line + 1); module = NULL; if ((psz_module_name == NULL) || (strcmp (psz_module_name, section) == 0)) { for (int i = 0; list[i]; i++) { module_t *m = list[i]; if ((strcmp (section, m->psz_object_name) == 0) && (m->i_config_items > 0)) /* ignore config-less modules */ { module = m; if (psz_module_name != NULL) msg_Dbg (p_this, "loading config for module \"%s\"", section); break; } } } continue; } if (module == NULL) continue; /* no need to parse if there is no matching module */ char *ptr = strchr (line, '\n'); if (ptr != NULL) *ptr = '\0'; /* look for option name */ const char *psz_option_name = line; ptr = strchr (line, '='); if (ptr == NULL) continue; /* syntax error */ *ptr = '\0'; const char *psz_option_value = ptr + 1; /* try to match this option with one of the module's options */ for (size_t i = 0; i < module->confsize; i++) { module_config_t *p_item = module->p_config + i; if ((p_item->i_type & CONFIG_HINT) || strcmp (p_item->psz_name, psz_option_name)) continue; /* We found it */ errno = 0; vlc_mutex_lock( p_item->p_lock ); switch( p_item->i_type ) { case CONFIG_ITEM_BOOL: case CONFIG_ITEM_INTEGER: { long l = strtoi (psz_option_value); if (errno) msg_Warn (p_this, "Integer value (%s) for %s: %m", psz_option_value, psz_option_name); else p_item->saved.i = p_item->value.i = (int)l; break; } case CONFIG_ITEM_FLOAT: if( !*psz_option_value ) break; /* ignore empty option */ p_item->value.f = (float)atof (psz_option_value); p_item->saved.f = p_item->value.f; break; case CONFIG_ITEM_KEY: if( !*psz_option_value ) break; /* ignore empty option */ p_item->value.i = ConfigStringToKey(psz_option_value); p_item->saved.i = p_item->value.i; break; default: /* free old string */ free( (char*) p_item->value.psz ); free( (char*) p_item->saved.psz ); p_item->value.psz = convert (psz_option_value); p_item->saved.psz = strdupnull (p_item->value.psz); break; } vlc_mutex_unlock( p_item->p_lock ); break; } } if (ferror (file)) { msg_Err (p_this, "error reading configuration: %m"); clearerr (file); } fclose (file); module_list_free (list); if (loc != (locale_t)0) { uselocale (baseloc); freelocale (loc); } return 0; }