diff options
Diffstat (limited to 'cfgparser.c')
-rw-r--r-- | cfgparser.c | 1548 |
1 files changed, 0 insertions, 1548 deletions
diff --git a/cfgparser.c b/cfgparser.c deleted file mode 100644 index 1872c203f9..0000000000 --- a/cfgparser.c +++ /dev/null @@ -1,1548 +0,0 @@ -/* - * 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 <math.h> - -#include "config.h" - -#ifndef NEW_CONFIG - -#ifdef USE_SETLOCALE -#include <locale.h> -#endif - -#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" -#include "playtree.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_PRINT_INDIRECT : - 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*)*config->cs_level,strerror(errno)); - config->cs_level = -1; - return -1; - } - mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Config poped level=%d\n",config->cs_level); - return ret; -} - -m_config_t* -m_config_new(play_tree_t* pt) { - m_config_t* config; - -#ifdef MP_DEBUG - assert(pt != NULL); -#endif - - config = (m_config_t*)calloc(1,sizeof(m_config_t)); - if(config == NULL) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Can't allocate %d bytes of memory : %s\n",sizeof(m_config_t),strerror(errno)); - return NULL; - } - config->config_stack = (config_save_t**)calloc(1,sizeof(config_save_t*)); - if(config->config_stack == NULL) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Can't allocate %d bytes of memory : %s\n",sizeof(config_save_t*),strerror(errno)); - free(config); - return NULL; - } - SET_GLOBAL(config); // We always start with global options - config->pt = pt; - return config; -} - -void -m_config_free(m_config_t* config) { - -#ifdef MP_DEBUG - assert(config != NULL); -#endif - - free(config->opt_list); - free(config->config_stack); - free(config); -} - - -static int init_conf(m_config_t *config, int mode) -{ -#ifdef MP_DEBUG - assert(config != NULL); - assert(config->pt != NULL); - assert(config->last_entry == NULL || config->last_entry->parent == config->pt); - - if (mode != COMMAND_LINE && mode != CONFIG_FILE) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "init_conf: wrong mode!\n"); - return -1; - } -#endif - config->parser_mode = mode; - return 1; -} - -static int config_is_entry_option(m_config_t *config, char *opt, char *param) { - play_tree_t* entry = NULL; - -#ifdef MP_DEBUG - assert(config->pt != NULL); -#endif - - if(strcasecmp(opt,"playlist") == 0) { // We handle playlist here - if(!param) - return ERR_MISSING_PARAM; - entry = parse_playlist_file(param); - if(!entry) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Playlist parsing failed: %s\n",param); - return 1; - } - } - - if(! IS_RUNNING(config)) { - if(strcasecmp(opt,"vcd") == 0) { - char* s; - if(!param) - return ERR_MISSING_PARAM; - s = (char*)malloc((strlen(param) + 6 + 1)*sizeof(char)); - sprintf(s,"vcd://%s",param); - entry = play_tree_new(); - play_tree_add_file(entry,s); - free(s); - } else if(strcasecmp(opt,"dvd") == 0) { - char* s; - if(!param) - return ERR_MISSING_PARAM; - s = (char*)malloc((strlen(param) + 6 + 1)*sizeof(char)); - sprintf(s,"dvd://%s",param); - entry = play_tree_new(); - play_tree_add_file(entry,s); - free(s); - } else if(strcasecmp(opt,"tv") == 0) { - char *s,*pr,*prs; - char *ps,*pe,*channel=NULL; - char *as; - int on=0; - if(!param) - return ERR_MISSING_PARAM; - ps = param; - pe = strchr(param,':'); - pr = prs = (char*)malloc((strlen(param)+1)*sizeof(char)); - pr[0] = '\0'; - while(ps) { - if(!pe) - pe = ps + strlen(ps); - - as = strchr(ps,'='); - if(as && as[1] != '\0' && pe-as > 0) - as++; - else - as = NULL; - if( !as && pe-ps == 2 && strncasecmp("on",ps,2) == 0 ) - on = 1; - else if(as && as-ps == 8 && strncasecmp("channel",ps,6) == 0 && pe-as > 0) { - channel = (char*)realloc(channel,(pe-as+1)*sizeof(char)); - strncpy(channel,as,pe-as); - channel[pe-as] = '\0'; - } else if(pe-ps > 0) { - if(prs != pr) { - prs[0] = ':'; - prs++; - } - strncpy(prs,ps,pe-ps); - prs += pe-ps; - prs[0] = '\0'; - } - - if(pe[0] != '\0') { - ps = pe+1; - pe = strchr(ps,':'); - } else - ps = NULL; - } - - if(on) { - int l=5; - - if(channel) - l += strlen(channel); - s = (char*) malloc((l+1)*sizeof(char)); - if(channel) - sprintf(s,"tv://%s",channel); - else - sprintf(s,"tv://"); - entry = play_tree_new(); - play_tree_add_file(entry,s); - if(strlen(pr) > 0) - play_tree_set_param(entry,"tv",pr); - free(s); - } - free(pr); - if(channel) - free(channel); - - } - } - - if(entry) { - if(config->last_entry) - play_tree_append_entry(config->last_entry,entry); - else - play_tree_set_child(config->pt,entry); - config->last_entry = entry; - if(config->parser_mode == COMMAND_LINE) - UNSET_GLOBAL(config); - return 1; - } else - return 0; -} - - - -static int config_read_option(m_config_t *config,config_t** conf_list, char *opt, char *param) -{ - int i=0,nconf = 0; - long tmp_int; - off_t tmp_off; - double tmp_float; - int dummy; - int ret = -1; - char *endptr; - config_t* conf=NULL; - -#ifdef MP_DEBUG - assert(config != NULL); - assert(conf_list != NULL); - assert(opt != NULL); -#endif - - mp_msg(MSGT_CFGPARSER, MSGL_DBG3, "read_option: conf=%p opt='%s' param='%s'\n", - conf, opt, param); - for(nconf = 0 ; conf_list[nconf] != NULL; nconf++) { - conf = conf_list[nconf]; - for (i = 0; conf[i].name != NULL; i++) { - int namelength; - /* allow 'aa*' in config.name */ - namelength=strlen(conf[i].name); - if ( (conf[i].name[namelength-1]=='*') && - !memcmp(opt, conf[i].name, namelength-1)) - goto option_found; - if (!strcasecmp(opt, conf[i].name)) - goto option_found; - } - } - if (config->parser_mode == CONFIG_FILE) - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "invalid option: %s\n",opt); - ret = ERR_NOT_AN_OPTION; - goto out; - option_found : - mp_msg(MSGT_CFGPARSER, MSGL_DBG3, "read_option: name='%s' p=%p type=%d\n", - conf[i].name, conf[i].p, conf[i].type); - - if (conf[i].flags & CONF_NOCFG && config->parser_mode == CONFIG_FILE) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "this option can only be used on command line:\n", opt); - ret = ERR_NOT_AN_OPTION; - goto out; - } - if (conf[i].flags & CONF_NOCMD && config->parser_mode == COMMAND_LINE) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "this option can only be used in config file:\n", opt); - ret = ERR_NOT_AN_OPTION; - goto out; - } - ret = config_is_entry_option(config,opt,param); - if(ret != 0) - return ret; - else - ret = -1; - if(! IS_RUNNING(config) && ! IS_GLOBAL(config) && - ! (conf[i].flags & CONF_GLOBAL) && conf[i].type != CONF_TYPE_SUBCONFIG ) - m_config_push(config); - if( !(conf[i].flags & CONF_NOSAVE) && ! (conf[i].flags & CONF_GLOBAL) ) - m_config_save_option(config,&conf[i],opt,param); - switch (conf[i].type) { - case CONF_TYPE_FLAG: - /* flags need a parameter in config file */ - if (config->parser_mode == CONFIG_FILE) { - if (!strcasecmp(param, "yes") || /* any other language? */ - !strcasecmp(param, "ja") || - !strcasecmp(param, "si") || - !strcasecmp(param, "igen") || - !strcasecmp(param, "y") || - !strcasecmp(param, "j") || - !strcasecmp(param, "i") || - !strcmp(param, "1")) - *((int *) conf[i].p) = conf[i].max; - else if (!strcasecmp(param, "no") || - !strcasecmp(param, "nein") || - !strcasecmp(param, "nicht") || - !strcasecmp(param, "nem") || - !strcasecmp(param, "n") || - !strcmp(param, "0")) - *((int *) conf[i].p) = conf[i].min; - else { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "invalid parameter for flag: %s\n", param); - ret = ERR_OUT_OF_RANGE; - goto out; - } - ret = 1; - } else { /* parser_mode == COMMAND_LINE */ - *((int *) conf[i].p) = conf[i].max; - ret = 0; - } - break; - case CONF_TYPE_INT: - if (param == NULL) - goto err_missing_param; - - tmp_int = strtol(param, &endptr, 0); - if (*endptr) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "parameter must be an integer: %s\n", param); - ret = ERR_OUT_OF_RANGE; - goto out; - } - - if (conf[i].flags & CONF_MIN) - if (tmp_int < conf[i].min) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "parameter must be >= %d: %s\n", (int) conf[i].min, param); - ret = ERR_OUT_OF_RANGE; - goto out; - } - - if (conf[i].flags & CONF_MAX) - if (tmp_int > conf[i].max) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "parameter must be <= %d: %s\n", (int) conf[i].max, param); - ret = ERR_OUT_OF_RANGE; - goto out; - } - - *((int *) conf[i].p) = tmp_int; - ret = 1; - break; - case CONF_TYPE_FLOAT: - if (param == NULL) - goto err_missing_param; - /* <olo@altkom.com.pl> Use portable C locale for parsing floats: */ -#ifdef USE_SETLOCALE - setlocale(LC_NUMERIC, "C"); -#endif - tmp_float = strtod(param, &endptr); - - switch(*endptr) { - case ':': - case '/': - tmp_float /= strtod(endptr+1, &endptr); - default: - break; - } -#ifdef USE_SETLOCALE - setlocale(LC_NUMERIC, ""); -#endif - - if (*endptr) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "parameter must be a floating point number" - " or a ratio (numerator[:/]denominator): %s\n", param); - ret = ERR_MISSING_PARAM; - goto out; - } - - if (conf[i].flags & CONF_MIN) - if (tmp_float < conf[i].min) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "parameter must be >= %f: %s\n", conf[i].min, param); - ret = ERR_OUT_OF_RANGE; - goto out; - } - - if (conf[i].flags & CONF_MAX) - if (tmp_float > conf[i].max) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "parameter must be <= %f: %s\n", conf[i].max, param); - ret = ERR_OUT_OF_RANGE; - goto out; - } - - *((float *) conf[i].p) = tmp_float; - ret = 1; - break; - case CONF_TYPE_STRING: - if (param == NULL) - goto err_missing_param; - - if (conf[i].flags & CONF_MIN) - if (strlen(param) < conf[i].min) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "parameter must be >= %d chars: %s\n", - (int) conf[i].min, param); - ret = ERR_OUT_OF_RANGE; - goto out; - } - - if (conf[i].flags & CONF_MAX) - if (strlen(param) > conf[i].max) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "parameter must be <= %d chars: %s\n", - (int) conf[i].max, param); - ret = ERR_OUT_OF_RANGE; - goto out; - } - *((char **) conf[i].p) = strdup(param); - ret = 1; - break; - case CONF_TYPE_STRING_LIST: - if (param == NULL) - goto err_missing_param; - else { - int n = 0,len; - char *ptr = param, *last_ptr, **res; - - while(ptr[0] != '\0') { - last_ptr = ptr; - ptr = strchr(ptr,LIST_SEPARATOR); - if(!ptr) { -// if(strlen(last_ptr) > 0) - n++; - break; - } - ptr++; - n++; - } - if(n == 0) - goto err_missing_param; - else if( (conf[i].flags & CONF_MIN && n < conf[i].min) || - (conf[i].flags & CONF_MAX && n > conf[i].max) ) { - ret = ERR_OUT_OF_RANGE; - goto out; - } - ret = 1; - res = malloc((n+2)*sizeof(char*)); - ptr = param; - n = 0; -// while(ptr[0] != '\0') { - while(1) { - last_ptr = ptr; - ptr = strchr(ptr,LIST_SEPARATOR); - if(!ptr) { - //if(strlen(last_ptr) > 0) - { - res[n] = strdup(last_ptr); - n++; - } - break; - } - len = ptr - last_ptr; - res[n] = (char*)malloc(len + 1); - if(len) strncpy(res[n],last_ptr,len); - res[n][len] = '\0'; - ptr++; - n++; - } - res[n] = NULL; - *((char ***) conf[i].p) = res; - } - break; - case CONF_TYPE_FUNC_PARAM: - if (param == NULL) - goto err_missing_param; - if ((((cfg_func_param_t) conf[i].p)(conf + i, param)) < 0) { - ret = ERR_FUNC_ERR; - goto out; - } - ret = 1; - break; - case CONF_TYPE_FUNC_FULL: - if (param!=NULL && param[0]=='-'){ - ret=((cfg_func_arg_param_t) conf[i].p)(conf + i, opt, NULL); - if (ret>=0) ret=0; - /* if we return >=0: param is processed again (if there is any) */ - }else{ - ret=((cfg_func_arg_param_t) conf[i].p)(conf + i, opt, param); - /* if we return 0: need no param, precess it again */ - /* if we return 1: accepted param */ - } - break; - case CONF_TYPE_FUNC: - if ((((cfg_func_t) conf[i].p)(conf + i)) < 0) { - ret = ERR_FUNC_ERR; - goto out; - } - ret = 0; - break; - case CONF_TYPE_SUBCONFIG: - { - char *subparam; - char *subopt; - int subconf_optnr; - config_t *subconf; - config_t *sublist[] = { NULL , NULL }; - char *token; - char *p; - - if (param == NULL) - goto err_missing_param; - - subparam = malloc(strlen(param)+1); - subopt = malloc(strlen(param)+1); - p = strdup(param); // In case that param is a static string (cf man strtok) - - subconf = conf[i].p; - sublist[0] = subconf; - for (subconf_optnr = 0; subconf[subconf_optnr].name != NULL; subconf_optnr++) - /* NOTHING */; - config->sub_conf = opt; - token = strtok(p, (char *)&(":")); - while(token) - { - int sscanf_ret; - /* clear out */ - subopt[0] = subparam[0] = 0; - - sscanf_ret = sscanf(token, "%[^=]=%[^:]", subopt, subparam); - - mp_msg(MSGT_CFGPARSER, MSGL_DBG3, "token: '%s', i=%d, subopt='%s', subparam='%s' (ret: %d)\n", token, i, subopt, subparam, sscanf_ret); - switch(sscanf_ret) - { - case 1: - subparam[0] = 0; - case 2: - if ((ret = config_read_option(config,sublist, subopt, subparam)) < 0) - { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Subconfig parsing returned error: %d in token: %s\n", - ret, token); - goto out; - } - break; - default: - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Invalid subconfig argument! ('%s')\n", token); - ret = ERR_NOT_AN_OPTION; - goto out; - } - token = strtok(NULL, (char *)&(":")); - } - config->sub_conf = NULL; - free(subparam); - free(subopt); - free(p); - ret = 1; - break; - } - case CONF_TYPE_PRINT: - mp_msg(MSGT_CFGPARSER, MSGL_INFO, "%s", (char *) conf[i].p); - exit(1); - case CONF_TYPE_PRINT_INDIRECT: - mp_msg(MSGT_CFGPARSER, MSGL_INFO, "%s", *(char **) conf[i].p); - exit(1); - case CONF_TYPE_POSITION: - if (param == NULL) - goto err_missing_param; - - if (sscanf(param, sizeof(off_t) == sizeof(int) ? - "%d%c" : "%lld%c", &tmp_off, (char *)&dummy) != 1) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "parameter must be an integer: %s\n", param); - ret = ERR_OUT_OF_RANGE; - goto out; - } - - if (conf[i].flags & CONF_MIN) - if (tmp_off < conf[i].min) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - (sizeof(off_t) == sizeof(int) ? - "parameter must be >= %d: %s\n" : - "parameter must be >= %lld: %s\n"), - (off_t) conf[i].min, param); - ret = ERR_OUT_OF_RANGE; - goto out; - } - - if (conf[i].flags & CONF_MAX) - if (tmp_off > conf[i].max) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, - (sizeof(off_t) == sizeof(int) ? - "parameter must be <= %d: %s\n" : - "parameter must be <= %lld: %s\n"), - (off_t) conf[i].max, param); - ret = ERR_OUT_OF_RANGE; - goto out; - } - - *((off_t *) conf[i].p) = tmp_off; - ret = 1; - break; - default: - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Unknown config type specified in conf-mplayer.h!\n"); - break; - } -out: - if(ret >= 0 && ! IS_RUNNING(config) && ! IS_GLOBAL(config) && ! (conf[i].flags & CONF_GLOBAL) && conf[i].type != CONF_TYPE_SUBCONFIG ) { - play_tree_t* dest = config->last_entry ? config->last_entry : config->last_parent; - char* o; -#ifdef MP_DEBUG - assert(dest != NULL); -#endif - if(config->sub_conf) { - o = (char*)malloc((strlen(config->sub_conf) + 1 + strlen(opt) + 1)*sizeof(char)); - sprintf(o,"%s:%s",config->sub_conf,opt); - } else - o =strdup(opt); - - if(ret == 0) - play_tree_set_param(dest,o,NULL); - else if(ret > 0) - play_tree_set_param(dest,o,param); - free(o); - m_config_pop(config); - } - return ret; -err_missing_param: - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "missing parameter for option: %s\n", opt); - ret = ERR_MISSING_PARAM; - goto out; -} - -int m_config_set_option(m_config_t *config,char *opt, char *param) { - char *e; -#ifdef MP_DEBUG - assert(config != NULL); - assert(config->opt_list != NULL); - assert(opt != NULL); -#endif - mp_msg(MSGT_CFGPARSER, MSGL_DBG2, "Setting option %s=%s\n",opt,param); - e = strchr(opt,':'); - if(e && e[1] != '\0') { - int ret; - config_t* opt_list[] = { NULL, NULL }; - char* s = (char*)malloc((e-opt+1)*sizeof(char)); - strncpy(s,opt,e-opt); - s[e-opt] = '\0'; - opt_list[0] = m_config_get_option_ptr(config,s); - if(!opt_list[0]) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR,"m_config_set_option %s=%s : no %s subconfig\n",opt,param,s); - free(s); - return ERR_NOT_AN_OPTION; - } - e++; - s = (char*)realloc(s,strlen(e) + 1); - strcpy(s,e); - ret = config_read_option(config,opt_list,s,param); - free(s); - return ret; - } - - return config_read_option(config,config->opt_list,opt,param); -} - -int m_config_parse_config_file(m_config_t *config, char *conffile) -{ -#define PRINT_LINENUM mp_msg(MSGT_CFGPARSER,MSGL_INFO,"%s(%d): ", conffile, line_num) -#define MAX_LINE_LEN 10000 -#define MAX_OPT_LEN 1000 -#define MAX_PARAM_LEN 1000 - FILE *fp; - char *line; - char opt[MAX_OPT_LEN + 1]; - char param[MAX_PARAM_LEN + 1]; - char c; /* for the "" and '' check */ - int tmp; - int line_num = 0; - int line_pos; /* line pos */ - int opt_pos; /* opt pos */ - int param_pos; /* param pos */ - int ret = 1; - int errors = 0; - -#ifdef MP_DEBUG - assert(config != NULL); - // assert(conf_list != NULL); -#endif - if (++config->recursion_depth > 1) - mp_msg(MSGT_CFGPARSER,MSGL_INFO,"Reading config file: %s", conffile); - - if (config->recursion_depth > MAX_RECURSION_DEPTH) { - mp_msg(MSGT_CFGPARSER,MSGL_ERR,": too deep 'include'. check your configfiles\n"); - ret = -1; - goto out; - } - - if (init_conf(config, CONFIG_FILE) == -1) { - ret = -1; - goto out; - } - - if ((line = (char *) malloc(MAX_LINE_LEN + 1)) == NULL) { - mp_msg(MSGT_CFGPARSER,MSGL_FATAL,"\ncan't get memory for 'line': %s", strerror(errno)); - ret = -1; - goto out; - } - - if ((fp = fopen(conffile, "r")) == NULL) { - if (config->recursion_depth > 1) - mp_msg(MSGT_CFGPARSER,MSGL_ERR,": %s\n", strerror(errno)); - free(line); - ret = 0; - goto out; - } - if (config->recursion_depth > 1) - mp_msg(MSGT_CFGPARSER,MSGL_INFO,"\n"); - - while (fgets(line, MAX_LINE_LEN, fp)) { - if (errors >= 16) { - mp_msg(MSGT_CFGPARSER,MSGL_FATAL,"too many errors\n"); - goto out; - } - - line_num++; - line_pos = 0; - - /* skip whitespaces */ - while (isspace(line[line_pos])) - ++line_pos; - - /* EOL / comment */ - if (line[line_pos] == '\0' || line[line_pos] == '#') - continue; - - /* read option. */ - for (opt_pos = 0; isprint(line[line_pos]) && - line[line_pos] != ' ' && - line[line_pos] != '#' && - line[line_pos] != '='; /* NOTHING */) { - opt[opt_pos++] = line[line_pos++]; - if (opt_pos >= MAX_OPT_LEN) { - PRINT_LINENUM; - mp_msg(MSGT_CFGPARSER,MSGL_ERR,"too long option\n"); - errors++; - ret = -1; - goto nextline; - } - } - if (opt_pos == 0) { - PRINT_LINENUM; - mp_msg(MSGT_CFGPARSER,MSGL_ERR,"parse error\n"); - ret = -1; - errors++; - continue; - } - opt[opt_pos] = '\0'; - -#ifdef MP_DEBUG - PRINT_LINENUM; - mp_msg(MSGT_CFGPARSER,MSGL_INFO,"option: %s\n", opt); -#endif - - /* skip whitespaces */ - while (isspace(line[line_pos])) - ++line_pos; - - /* check '=' */ - if (line[line_pos++] != '=') { - PRINT_LINENUM; - mp_msg(MSGT_CFGPARSER,MSGL_ERR,"option without parameter\n"); - ret = -1; - errors++; - continue; - } - - /* whitespaces... */ - while (isspace(line[line_pos])) - ++line_pos; - - /* read the parameter */ - if (line[line_pos] == '"' || line[line_pos] == '\'') { - c = line[line_pos]; - ++line_pos; - for (param_pos = 0; line[line_pos] != c; /* NOTHING */) { - param[param_pos++] = line[line_pos++]; - if (param_pos >= MAX_PARAM_LEN) { - PRINT_LINENUM; - mp_msg(MSGT_CFGPARSER,MSGL_ERR,"too long parameter\n"); - ret = -1; - errors++; - goto nextline; - } - } - line_pos++; /* skip the closing " or ' */ - } else { - for (param_pos = 0; isprint(line[line_pos]) && !isspace(line[line_pos]) - && line[line_pos] != '#'; /* NOTHING */) { - param[param_pos++] = line[line_pos++]; - if (param_pos >= MAX_PARAM_LEN) { - PRINT_LINENUM; - mp_msg(MSGT_CFGPARSER,MSGL_ERR,"too long parameter\n"); - ret = -1; - errors++; - goto nextline; - } - } - } - param[param_pos] = '\0'; - - /* did we read a parameter? */ - if (param_pos == 0) { - PRINT_LINENUM; - mp_msg(MSGT_CFGPARSER,MSGL_ERR,"option without parameter\n"); - ret = -1; - errors++; - continue; - } - -#ifdef MP_DEBUG - PRINT_LINENUM; - mp_msg(MSGT_CFGPARSER,MSGL_INFO,"parameter: %s\n", param); -#endif - - /* now, check if we have some more chars on the line */ - /* whitespace... */ - while (isspace(line[line_pos])) - ++line_pos; - - /* EOL / comment */ - if (line[line_pos] != '\0' && line[line_pos] != '#') { - PRINT_LINENUM; - mp_msg(MSGT_CFGPARSER,MSGL_WARN,"extra characters on line: %s\n", line+line_pos); - ret = -1; - } - - tmp = m_config_set_option(config, opt, param); - switch (tmp) { - case ERR_NOT_AN_OPTION: - case ERR_MISSING_PARAM: - case ERR_OUT_OF_RANGE: - case ERR_FUNC_ERR: - PRINT_LINENUM; - mp_msg(MSGT_CFGPARSER,MSGL_INFO,"%s\n", opt); - ret = -1; - errors++; - continue; - /* break */ - } -nextline: - ; - } - - free(line); - fclose(fp); -out: - --config->recursion_depth; - return ret; -} - -int m_config_parse_command_line(m_config_t *config, int argc, char **argv) -{ - int i; - int tmp; - char *opt; - int no_more_opts = 0; - -#ifdef MP_DEBUG - assert(config != NULL); - assert(config->pt != NULL); - assert(argv != NULL); - assert(argc >= 1); -#endif - - if (init_conf(config, COMMAND_LINE) == -1) - return -1; - if(config->last_parent == NULL) - config->last_parent = config->pt; - /* in order to work recursion detection properly in parse_config_file */ - ++config->recursion_depth; - - for (i = 1; i < argc; i++) { - //next: - opt = argv[i]; - /* check for -- (no more options id.) except --help! */ - if ((*opt == '-') && (*(opt+1) == '-') && (*(opt+2) != 'h')) - { - no_more_opts = 1; - if (i+1 >= argc) - { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "You added '--' but no filenames presented!\n"); - goto err_out; - } - continue; - } - if((opt[0] == '{') && (opt[1] == '\0')) - { - play_tree_t* entry = play_tree_new(); - UNSET_GLOBAL(config); - if(config->last_entry == NULL) { - play_tree_set_child(config->last_parent,entry); - } else { - play_tree_append_entry(config->last_entry,entry); - config->last_entry = NULL; - } - config->last_parent = entry; - continue; - } - - if((opt[0] == '}') && (opt[1] == '\0')) - { - if( ! config->last_parent || ! config->last_parent->parent) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "too much }-\n"); - goto err_out; - } - config->last_entry = config->last_parent; - config->last_parent = config->last_entry->parent; - continue; - } - - if ((no_more_opts == 0) && (*opt == '-') && (*(opt+1) != 0)) /* option */ - { - /* remove trailing '-' */ - opt++; - - mp_msg(MSGT_CFGPARSER, MSGL_DBG3, "this_opt = option: %s\n", opt); - // We handle here some specific option - if(strcasecmp(opt,"list-options") == 0) { - m_config_list_options(config); - exit(1); - // Loop option when it apply to a group - } else if(strcasecmp(opt,"loop") == 0 && - (! config->last_entry || config->last_entry->child) ) { - int l; - char* end; - l = strtol(argv[i+1],&end,0); - if(!end) - tmp = ERR_OUT_OF_RANGE; - else { - play_tree_t* pt = config->last_entry ? config->last_entry : config->last_parent; - l = l <= 0 ? -1 : l; - pt->loop = l; - tmp = 1; - } - } else // All normal options - tmp = m_config_set_option(config, opt, argv[i + 1]); - - switch (tmp) { - case ERR_NOT_AN_OPTION: - case ERR_MISSING_PARAM: - case ERR_OUT_OF_RANGE: - case ERR_FUNC_ERR: - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Error: "); - m_config_error(tmp,opt,argv[i+1]); - goto err_out; - default: - i += tmp; - break; - } - } - else /* filename */ - { - play_tree_t* entry = play_tree_new(); - mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Adding file %s\n",argv[i]); - play_tree_add_file(entry,argv[i]); - if(strcasecmp(argv[i],"-") == 0) - m_config_set_option(config,"use-stdin",NULL); - /* opt is not an option -> treat it as a filename */ - UNSET_GLOBAL(config); // We start entry specific options - if(config->last_entry == NULL) - play_tree_set_child(config->last_parent,entry); - else - play_tree_append_entry(config->last_entry,entry); - config->last_entry = entry; - } - } - - --config->recursion_depth; - if(config->last_parent != config->pt) - mp_msg(MSGT_CFGPARSER, MSGL_ERR,"Missing }- ?\n"); - config->flags &= (!CONFIG_GLOBAL); - SET_RUNNING(config); - return 1; -#if 0 -err_out_mem: - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "can't allocate memory for filenames (%s)\n", strerror(errno)); -#endif -err_out: - --config->recursion_depth; - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "command line: %s\n", argv[i]); - return -1; -} - -int -m_config_register_options(m_config_t *config,config_t *args) { - int list_len = 0; - config_t** conf_list = config->opt_list; - -#ifdef MP_DEBUG - assert(config != NULL); - assert(args != NULL); -#endif - - if(conf_list) { - for ( ; conf_list[list_len] != NULL; list_len++) - /* NOTHING */; - } - - conf_list = (config_t**)realloc(conf_list,sizeof(struct conf*)*(list_len+2)); - if(conf_list == NULL) { - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Can't allocate %d bytes of memory : %s\n",sizeof(struct conf*)*(list_len+2),strerror(errno)); - return 0; - } - conf_list[list_len] = args; - conf_list[list_len+1] = NULL; - - config->opt_list = conf_list; - - return 1; -} - -config_t* -m_config_get_option(m_config_t *config, char* arg) { - int i,j; - char *e; - config_t *conf; - config_t **conf_list; - config_t* cl[] = { NULL, NULL }; - -#ifdef MP_DEBUG - assert(config != NULL); - assert(arg != NULL); -#endif - - e = strchr(arg,':'); - - if(e) { - char *s; - s = (char*)malloc((e-arg+1)*sizeof(char)); - strncpy(s,arg,e-arg); - s[e-arg] = '\0'; - cl[0] = m_config_get_option(config,s); - conf_list = cl; - free(s); - } else - conf_list = config->opt_list; - - if(conf_list) { - for(j = 0 ; conf_list[j] != NULL ; j++) { - conf = conf_list[j]; - for(i=0; conf[i].name != NULL; i++) { - if(strcasecmp(conf[i].name,arg) == 0) - return &conf[i]; - } - } - } - return NULL; -} - -void* -m_config_get_option_ptr(m_config_t *config, char* arg) { - config_t* conf; - -#ifdef MP_DEBUG - assert(config != NULL); - assert(arg != NULL); -#endif - - conf = m_config_get_option(config,arg); - if(!conf) return NULL; - return conf->p; -} - -int -m_config_get_int (m_config_t *config, char* arg,int* err_ret) { - int *ret; - -#ifdef MP_DEBUG - assert(config != NULL); - assert(arg != NULL); -#endif - - ret = m_config_get_option_ptr(config,arg); - if(err_ret) - *err_ret = 0; - if(!ret) { - if(err_ret) - *err_ret = 1; - return -1; - } else - return (*ret); -} - -float -m_config_get_float (m_config_t *config, char* arg,int* err_ret) { - float *ret; - -#ifdef MP_DEBUG - assert(config != NULL); - assert(arg != NULL); -#endif - - ret = m_config_get_option_ptr(config,arg); - if(err_ret) - *err_ret = 0; - if(!ret) { - if(err_ret) - *err_ret = 1; - return -1; - } else - return (*ret); -} - -#define AS_INT(c) (*((int*)c->p)) - -int -m_config_set_int(m_config_t *config, char* arg,int val) { - config_t* opt; - -#ifdef MP_DEBUG - assert(config != NULL); - assert(arg != NULL); -#endif - - opt = m_config_get_option(config,arg); - - if(!opt || opt->type != CONF_TYPE_INT) - return ERR_NOT_AN_OPTION; - - if(opt->flags & CONF_MIN && val < opt->min) - return ERR_OUT_OF_RANGE; - if(opt->flags & CONF_MAX && val > opt->max) - return ERR_OUT_OF_RANGE; - - m_config_save_option(config,opt,arg,NULL); - AS_INT(opt) = val; - - return 1; -} - -int -m_config_set_float(m_config_t *config, char* arg,float val) { - config_t* opt; - -#ifdef MP_DEBUG - assert(config != NULL); - assert(arg != NULL); -#endif - - opt = m_config_get_option(config,arg); - - if(!opt || opt->type != CONF_TYPE_FLOAT) - return ERR_NOT_AN_OPTION; - - if(opt->flags & CONF_MIN && val < opt->min) - return ERR_OUT_OF_RANGE; - if(opt->flags & CONF_MAX && val > opt->max) - return ERR_OUT_OF_RANGE; - - m_config_save_option(config,opt,arg,NULL); - *((float*)opt->p) = val; - - return 1; -} - - -int -m_config_switch_flag(m_config_t *config, char* opt) { - config_t *conf; - -#ifdef MP_DEBUG - assert(config != NULL); - assert(opt != NULL); -#endif - - conf = m_config_get_option(config,opt); - if(!conf || conf->type != CONF_TYPE_FLAG) return 0; - if( AS_INT(conf) == conf->min) AS_INT(conf) = conf->max; - else if(AS_INT(conf) == conf->max) AS_INT(conf) = conf->min; - else return 0; - - return 1; -} - -int -m_config_set_flag(m_config_t *config, char* opt, int state) { - config_t *conf; - -#ifdef MP_DEBUG - assert(config != NULL); - assert(opt != NULL); -#endif - - conf = m_config_get_option(config,opt); - if(!conf || conf->type != CONF_TYPE_FLAG) return 0; - if(state) AS_INT(conf) = conf->max; - else AS_INT(conf) = conf->min; - return 1; -} - -int -m_config_get_flag(m_config_t *config, char* opt) { - config_t *conf; - -#ifdef MP_DEBUG - assert(config != NULL); - assert(opt != NULL); -#endif - - conf = m_config_get_option(config,opt); - if(!conf || conf->type != CONF_TYPE_FLAG) return -1; - if(AS_INT(conf) == conf->max) - return 1; - else if(AS_INT(conf) == conf->min) - return 0; - else - return -1; -} - -int m_config_is_option_set(m_config_t *config, char* arg) { - config_t* opt; - config_save_t* save; - int l,i; - -#ifdef MP_DEBUG - assert(config != NULL); - assert(arg != NULL); -#endif - - opt = m_config_get_option(config,arg); - - if(!opt) - return -1; - - for(l = config->cs_level ; l >= 0 ; l--) { - save = config->config_stack[l]; - if(!save) - continue; - for(i = 0 ; save[i].opt != NULL ; i++) { - if(save[i].opt == opt) - return 1; - } - } - - return 0; -} - -#undef AS_INT - -static void m_config_print_option_list(char* prefix, config_t* opt_list) { - char* pf = NULL; - config_t* opt; - char min[50],max[50],*type; - - - for(opt = opt_list ; opt->name != NULL ; opt++) { - if(opt->type == CONF_TYPE_SUBCONFIG) { - if(prefix) { - pf = (char*)malloc(strlen(prefix) + strlen(opt->name) + 1); - sprintf(pf,"%s:%s",prefix,opt->name); - } else - pf = strdup(opt->name); - m_config_print_option_list(pf,(config_t*)opt->p); - free(pf); - continue; - } - if(prefix) - printf("%1.15s:",prefix); - if(opt->flags & CONF_MIN) - sprintf(min,"%-8.0f",opt->min); - else - strcpy(min,"No"); - if(opt->flags & CONF_MAX) - sprintf(max,"%-8.0f",opt->max); - else - strcpy(max,"No"); - switch(opt->type) { - case CONF_TYPE_FLAG: - type = "Flag"; - break; - case CONF_TYPE_INT: - type = "Integer"; - break; - case CONF_TYPE_FLOAT: - type = "Float"; - break; - case CONF_TYPE_STRING: - type = "String"; - break; - case CONF_TYPE_FUNC: - case CONF_TYPE_FUNC_PARAM: - case CONF_TYPE_FUNC_FULL: - type = "Function"; - break; - case CONF_TYPE_PRINT: - case CONF_TYPE_PRINT_INDIRECT: - type = "Print"; - break; - case CONF_TYPE_STRING_LIST: - type = "String list"; - break; - default: - type = ""; - break; - } - printf("%-*.15s %-13.13s %-10.10s %-10.10s %-3.3s %-3.3s %-3.3s\n", - 30 - (prefix ? strlen(prefix) + 1 : 0), - opt->name, - type, - min, - max, - opt->flags & CONF_GLOBAL ? "Yes" : "No", - opt->flags & CONF_NOCMD ? "No" : "Yes", - opt->flags & CONF_NOCFG ? "No" : "Yes"); - } - -} - - -static void m_config_list_options(m_config_t *config) { - int i; - - printf("\nName Type Min Max Glob CL Cfg\n\n"); - for(i = 0; config->opt_list[i] ; i++) - m_config_print_option_list(NULL,config->opt_list[i]); -} - - - -static void m_config_error(int err,char* opt,char* val) { - switch(err) { - case ERR_NOT_AN_OPTION: - mp_msg(MSGT_CFGPARSER, MSGL_ERR,"'%s' is not a mplayer/mencoder option\n",opt); - break; - case ERR_MISSING_PARAM: - mp_msg(MSGT_CFGPARSER, MSGL_ERR,"option '%s' need a parameter\n",opt); - break; - case ERR_OUT_OF_RANGE: - mp_msg(MSGT_CFGPARSER, MSGL_ERR,"value '%s' of option '%s' is out of range\n",val,opt); - break; - case ERR_FUNC_ERR: - mp_msg(MSGT_CFGPARSER, MSGL_ERR,"while parsing option '%s'\n",opt); - break; - } -} - -#endif |