/*
* command line and config file parser
* by Szabolcs Berecz <szabi@inf.elte.hu>
* (C) 2001
*
* subconfig support by alex
*/
//#define DEBUG
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include "config.h"
#include "mp_msg.h"
#define COMMAND_LINE 0
#define CONFIG_FILE 1
#define LIST_SEPARATOR ','
#define CONFIG_GLOBAL (1<<0)
#define CONFIG_RUNNING (1<<1)
#define SET_GLOBAL(c) (c->flags |= CONFIG_GLOBAL)
#ifdef GLOBAL_OPTIONS_ONLY
#define UNSET_GLOBAL(c)
#else
#define UNSET_GLOBAL(c) (c->flags &= (!CONFIG_GLOBAL))
#endif
#define IS_GLOBAL(c) (c->flags & CONFIG_GLOBAL)
#define SET_RUNNING(c) (c->flags |= CONFIG_RUNNING)
#define IS_RUNNING(c) (c->flags & CONFIG_RUNNING)
#define MAX_RECURSION_DEPTH 8
#ifdef MP_DEBUG
#include <assert.h>
#endif
#include "cfgparser.h"
static void m_config_list_options(m_config_t *config);
static void m_config_error(int err,char* opt,char* val);
static void
m_config_save_option(m_config_t* config, config_t* conf,char* opt, char *param) {
config_save_t* save;
int sl=0;
#ifdef MP_DEBUG
assert(config != NULL);
assert(config->cs_level >= 0);
assert(conf != NULL);
assert(opt != NULL);
assert( ! (conf->flags & CONF_NOSAVE));
#endif
switch(conf->type) {
case CONF_TYPE_PRINT :
case CONF_TYPE_SUBCONFIG :
return;
default :
;
}
mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Saving option %s\n",opt);
save = config->config_stack[config->cs_level];
if(save) {
for(sl = 0; save[sl].opt != NULL; sl++){
// Check to not save the same arg two times
if(save[sl].opt == conf && (save[sl].opt_name == NULL || strcasecmp(save[sl].opt_name,opt) == 0))
break;
}
if(save[sl].opt)
return;
}
save = (config_save_t*)realloc(save,(sl+2)*sizeof(config_save_t));
if(save == NULL) {
mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Can't allocate %d bytes of memory : %s\n",(sl+2)*sizeof(config_save_t),strerror(errno));
return;
}
memset(&save[sl],0,2*sizeof(config_save_t));
save[sl].opt = conf;
switch(conf->type) {
case CONF_TYPE_FLAG :
case CONF_TYPE_INT :
save[sl].param.as_int = *((int*)conf->p);
break;
case CONF_TYPE_FLOAT :
save[sl].param.as_float = *((float*)conf->p);
break;
case CONF_TYPE_STRING :
save[sl].param.as_pointer = *((char**)conf->p);
break;
case CONF_TYPE_FUNC_FULL :
if(strcasecmp(conf->name,opt) != 0) save->opt_name = strdup(opt);
case CONF_TYPE_FUNC_PARAM :
if(param)
save->param.as_pointer = strdup(param);
case CONF_TYPE_FUNC :
break;
case CONF_TYPE_STRING_LIST :
save[sl].param.as_pointer = *((char***)conf->p);
break;
case CONF_TYPE_POSITION :
save[sl].param.as_off_t = *((off_t*)conf->p);
break;
default :
mp_msg(MSGT_CFGPARSER,MSGL_ERR,"Should never append in m_config_save_option : conf->type=%d\n",conf->type);
}
config->config_stack[config->cs_level] = save;
}
static int
m_config_revert_option(m_config_t* config, config_save_t* save) {
char* arg = NULL;
config_save_t* iter=NULL;
int i=-1;
#ifdef MP_DEBUG
assert(config != NULL);
assert(config->cs_level >= 0);
assert(save != NULL);
#endif
arg = save->opt_name ? save->opt_name : save->opt->name;
mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Reverting option %s\n",arg);
if(save->opt->default_func)
save->opt->default_func(save->opt,arg);
switch(save->opt->type) {
case CONF_TYPE_FLAG :
case CONF_TYPE_INT :
*((int*)save->opt->p) = save->param.as_int;
break;
case CONF_TYPE_FLOAT :
*((float*)save->opt->p) = save->param.as_float;
break;
case CONF_TYPE_STRING :
*((char**)save->opt->p) = save->param.as_pointer;
break;
case CONF_TYPE_STRING_LIST :
*((char***)save->opt->p) = save->param.as_pointer;
break;
case CONF_TYPE_FUNC_PARAM :
case CONF_TYPE_FUNC_FULL :
case CONF_TYPE_FUNC :
if(config->cs_level > 0) {
for(i = config->cs_level - 1 ; i >= 0 ; i--){
if(config->config_stack[i] == NULL) continue;
for(iter = config->config_stack[i]; iter != NULL && iter->opt != NULL ; iter++) {
if(iter->opt == save->opt &&
((save->param.as_pointer == NULL || iter->param.as_pointer == NULL) || strcasecmp(save->param.as_pointer,iter->param.as_pointer) == 0) &&
(save->opt_name == NULL ||
(iter->opt_name && strcasecmp(save->opt_name,iter->opt_name)))) break;
}
}
}
free(save->param.as_pointer);
if(save->opt_name) free(save->opt_name);
save->opt_name = save->param.as_pointer = NULL;
if(i < 0) break;
arg = iter->opt_name ? iter->opt_name : iter->opt->name;
switch(iter->opt->type) {
case CONF_TYPE_FUNC :
if ((((cfg_func_t) iter->opt->p)(iter->opt)) < 0)
return -1;
break;
case CONF_TYPE_FUNC_PARAM :
if (iter->param.as_pointer == NULL) {
mp_msg(MSGT_CFGPARSER,MSGL_ERR,"We lost param for option %s?\n",iter->opt->name);
return -1;
}
if ((((cfg_func_param_t) iter->opt->p)(iter->opt, (char*)iter->param.as_pointer)) < 0)
return -1;
break;
case CONF_TYPE_FUNC_FULL :
if (iter->param.as_pointer != NULL && ((char*)iter->param.as_pointer)[0]=='-'){
if( ((cfg_func_arg_param_t) iter->opt->p)(iter->opt, arg, NULL) < 0)
return -1;
}else {
if (((cfg_func_arg_param_t) save->opt->p)(iter->opt, arg, (char*)iter->param.as_pointer) < 0)
return -1;
}
break;
}
break;
case CONF_TYPE_POSITION :
*((off_t*)save->opt->p) = save->param.as_off_t;
break;
default :
mp_msg(MSGT_CFGPARSER,MSGL_WARN,"Why do we reverse this : name=%s type=%d ?\n",save->opt->name,save->opt->type);
}
return 1;
}
void
m_config_push(m_config_t* config) {
#ifdef MP_DEBUG
assert(config != NULL);
assert(config->cs_level >= 0);
#endif
config->cs_level++;
config->config_stack = (config_save_t**)realloc(config->config_stack ,sizeof(config_save_t*)*(config->cs_level+1));
if(config->config_stack == NULL) {
mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Can't allocate %d bytes of memory : %s\n",sizeof(config_save_t*)*(config->cs_level+1),strerror(errno));
config->cs_level = -1;
return;
}
config->config_stack[config->cs_level] = NULL;
mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Config pushed level=%d\n",config->cs_level);
}
int
m_config_pop(m_config_t* config) {
int i,ret= 1;
config_save_t* cs;
#ifdef MP_DEBUG
assert(config != NULL);
//assert(config->cs_level > 0);
#endif
if(config->config_stack[config->cs_level] != NULL) {
cs = config->config_stack[config->cs_level];
for(i=0; cs[i].opt != NULL ; i++ ) {
if (m_config_revert_option(config,&cs[i]) < 0)
ret = -1;
}
free(config->config_stack[config->cs_level]);
}
config->config_stack = (config_save_t**)realloc(config->config_stack ,sizeof(config_save_t*)*config->cs_level);
config->cs_level--;
if(config->cs_level > 0 && config->config_stack == NULL) {
mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Can't allocate %d bytes of memory : %s\n",sizeof(config_save_t*)*conf
|