Mercurial > mplayer.hg
view m_config.c @ 26883:a365271c97a5
Revert commit r26897.
XviD is the correct spelling of the codec.
You can see it written in the codec own
documentation and header files.
Prefered name capitalization confirmed
in conversation with XviD developer (prunedtree).
author | iive |
---|---|
date | Wed, 28 May 2008 23:04:41 +0000 |
parents | 7a36d5941fd8 |
children | 0f1b5b68af32 |
line wrap: on
line source
/// \file /// \ingroup Config #include "config.h" #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #ifdef MP_DEBUG #include <assert.h> #endif #include "m_config.h" #include "m_option.h" #include "mp_msg.h" #include "help_mp.h" #define MAX_PROFILE_DEPTH 20 static int parse_profile(const m_option_t *opt, const char *name, char *param, void *dst, int src); static void set_profile(const m_option_t *opt, void* dst, void* src); static int show_profile(m_option_t *opt, char* name, char *param); static void m_config_add_option(m_config_t *config, const m_option_t *arg, const char* prefix); static int list_options(m_option_t *opt, char* name, char *param); m_config_t* m_config_new(void) { m_config_t* config; static int initialized = 0; static m_option_type_t profile_opt_type; static m_option_t ref_opts[] = { { "profile", NULL, &profile_opt_type, CONF_NOSAVE, 0, 0, NULL }, { "show-profile", show_profile, CONF_TYPE_PRINT_FUNC, CONF_NOCFG, 0, 0, NULL }, { "list-options", list_options, CONF_TYPE_PRINT_FUNC, CONF_NOCFG, 0, 0, NULL }, { NULL, NULL, NULL, 0, 0, 0, NULL } }; int i; config = calloc(1,sizeof(m_config_t)); config->lvl = 1; // 0 Is the defaults if(!initialized) { initialized = 1; profile_opt_type = m_option_type_string_list; profile_opt_type.parse = parse_profile; profile_opt_type.set = set_profile; } config->self_opts = malloc(sizeof(ref_opts)); memcpy(config->self_opts,ref_opts,sizeof(ref_opts)); for(i = 0 ; config->self_opts[i].name ; i++) config->self_opts[i].priv = config; m_config_register_options(config,config->self_opts); return config; } void m_config_free(m_config_t* config) { m_config_option_t *i = config->opts, *ct; m_config_save_slot_t *sl,*st; m_profile_t *p,*pn; int j; #ifdef MP_DEBUG assert(config != NULL); #endif while(i) { if (i->flags & M_CFG_OPT_ALIAS) sl = NULL; else sl = i->slots; while(sl) { m_option_free(i->opt,sl->data); st = sl->prev; free(sl); sl = st; } if(i->name != i->opt->name) free(i->name); ct = i->next; free(i); i = ct; } for(p = config->profiles ; p ; p = pn) { pn = p->next; free(p->name); if(p->desc) free(p->desc); for(j = 0 ; j < p->num_opts ; j++) { free(p->opts[2*j]); if(p->opts[2*j+1]) free(p->opts[2*j+1]); } free(p->opts); free(p); } free(config->self_opts); free(config); } void m_config_push(m_config_t* config) { m_config_option_t *co; m_config_save_slot_t *slot; #ifdef MP_DEBUG assert(config != NULL); assert(config->lvl > 0); #endif config->lvl++; for(co = config->opts ; co ; co = co->next ) { if(co->opt->type->flags & M_OPT_TYPE_HAS_CHILD) continue; if(co->opt->flags & (M_OPT_GLOBAL|M_OPT_NOSAVE)) continue; if((co->opt->flags & M_OPT_OLD) && !(co->flags & M_CFG_OPT_SET)) continue; if(co->flags & M_CFG_OPT_ALIAS) continue; // Update the current status m_option_save(co->opt,co->slots->data,co->opt->p); // Allocate a new slot slot = calloc(1,sizeof(m_config_save_slot_t) + co->opt->type->size); slot->lvl = config->lvl; slot->prev = co->slots; co->slots = slot; m_option_copy(co->opt,co->slots->data,co->slots->prev->data); // Reset our set flag co->flags &= ~M_CFG_OPT_SET; } mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Config pushed level is now %d\n",config->lvl); } void m_config_pop(m_config_t* config) { m_config_option_t *co; m_config_save_slot_t *slot; #ifdef MP_DEBUG assert(config != NULL); assert(config->lvl > 1); #endif for(co = config->opts ; co ; co = co->next ) { int pop = 0; if(co->opt->type->flags & M_OPT_TYPE_HAS_CHILD) continue; if(co->opt->flags & (M_OPT_GLOBAL|M_OPT_NOSAVE)) continue; if(co->flags & M_CFG_OPT_ALIAS) continue; if(co->slots->lvl > config->lvl) mp_msg(MSGT_CFGPARSER, MSGL_WARN,MSGTR_SaveSlotTooOld,config->lvl,co->slots->lvl); while(co->slots->lvl >= config->lvl) { m_option_free(co->opt,co->slots->data); slot = co->slots; co->slots = slot->prev; free(slot); pop++; } if(pop) // We removed some ctx -> set the previous value m_option_set(co->opt,co->opt->p,co->slots->data); } config->lvl--; mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Config poped level=%d\n",config->lvl); } static void m_config_add_option(m_config_t *config, const m_option_t *arg, const char* prefix) { m_config_option_t *co; m_config_save_slot_t* sl; #ifdef MP_DEBUG assert(config != NULL); assert(config->lvl > 0); assert(arg != NULL); #endif // Allocate a new entry for this option co = calloc(1,sizeof(m_config_option_t) + arg->type->size); co->opt = arg; // Fill in the full name if(prefix && strlen(prefix) > 0) { int l = strlen(prefix) + 1 + strlen(arg->name) + 1; co->name = malloc(l); sprintf(co->name,"%s:%s",prefix,arg->name); } else co->name = arg->name; // Option with children -> add them if(arg->type->flags & M_OPT_TYPE_HAS_CHILD) { const m_option_t *ol = arg->p; int i; co->slots = NULL; for(i = 0 ; ol[i].name != NULL ; i++) m_config_add_option(config,&ol[i], co->name); } else { m_config_option_t *i; // Check if there is already an option pointing to this address if(arg->p) { for(i = config->opts ; i ; i = i->next ) { if(i->opt->p == arg->p) { // So we don't save the same vars more than 1 time co->slots = i->slots; co->flags |= M_CFG_OPT_ALIAS; break; } } } if(!(co->flags & M_CFG_OPT_ALIAS)) { // Allocate a slot for the defaults sl = calloc(1,sizeof(m_config_save_slot_t) + arg->type->size); m_option_save(arg,sl->data,(void**)arg->p); // Hack to avoid too much trouble with dynamically allocated data : // We always use a dynamic version if((arg->type->flags & M_OPT_TYPE_DYNAMIC) && arg->p && (*(void**)arg->p)) { *(void**)arg->p = NULL; m_option_set(arg,arg->p,sl->data); } sl->lvl = 0; sl->prev = NULL; co->slots = calloc(1,sizeof(m_config_save_slot_t) + arg->type->size); co->slots->prev = sl; co->slots->lvl = config->lvl; m_option_copy(co->opt,co->slots->data,sl->data); } // !M_OPT_ALIAS } co->next = config->opts; config->opts = co; } int m_config_register_options(m_config_t *config, const m_option_t *args) { int i; #ifdef MP_DEBUG assert(config != NULL); assert(config->lvl > 0); assert(args != NULL); #endif for(i = 0 ; args[i].name != NULL ; i++) m_config_add_option(config,&args[i],NULL); return 1; } static m_config_option_t* m_config_get_co(m_config_t *config, char* arg) { m_config_option_t *co; for(co = config->opts ; co ; co = co->next ) { int l = strlen(co->name) - 1; if((co->opt->type->flags & M_OPT_TYPE_ALLOW_WILDCARD) && (co->name[l] == '*')) { if(strncasecmp(co->name,arg,l) == 0) return co; } else if(strcasecmp(co->name,arg) == 0) return co; } return NULL; } static int m_config_parse_option(m_config_t *config, char* arg, char* param,int set) { m_config_option_t *co; int r = 0; #ifdef MP_DEBUG assert(config != NULL); assert(config->lvl > 0); assert(arg != NULL); #endif co = m_config_get_co(config,arg); if(!co){ // mp_msg(MSGT_CFGPARSER, MSGL_ERR,"Unknown option: %s\n",arg); return M_OPT_UNKNOWN; } #ifdef MP_DEBUG // This is the only mandatory function assert(co->opt->type->parse); #endif // Check if this option isn't forbidden in the current mode if((config->mode == M_CONFIG_FILE) && (co->opt->flags & M_OPT_NOCFG)) { mp_msg(MSGT_CFGPARSER, MSGL_ERR,MSGTR_InvalidCfgfileOption,arg); return M_OPT_INVALID; } if((config->mode == M_COMMAND_LINE) && (co->opt->flags & M_OPT_NOCMD)) { mp_msg(MSGT_CFGPARSER, MSGL_ERR,MSGTR_InvalidCmdlineOption,arg); return M_OPT_INVALID; } // During command line preparse set only pre-parse options // Otherwise only set pre-parse option if they were not already set. if(((config->mode == M_COMMAND_LINE_PRE_PARSE) && !(co->opt->flags & M_OPT_PRE_PARSE)) || ((config->mode != M_COMMAND_LINE_PRE_PARSE) && (co->opt->flags & M_OPT_PRE_PARSE) && (co->flags & M_CFG_OPT_SET))) set = 0; // Option with children are a bit different to parse if(co->opt->type->flags & M_OPT_TYPE_HAS_CHILD) { char** lst = NULL; int i,sr; // Parse the child options r = m_option_parse(co->opt,arg,param,&lst,M_COMMAND_LINE); // Set them now if(r >= 0) for(i = 0 ; lst && lst[2*i] ; i++) { int l = strlen(co->name) + 1 + strlen(lst[2*i]) + 1; if(r >= 0) { // Build the full name char n[l]; sprintf(n,"%s:%s",co->name,lst[2*i]); sr = m_config_parse_option(config,n,lst[2*i+1],set); if(sr < 0){ if(sr == M_OPT_UNKNOWN){ mp_msg(MSGT_CFGPARSER, MSGL_ERR,MSGTR_InvalidSuboption,co->name,lst[2*i]); r = M_OPT_INVALID; } else if(sr == M_OPT_MISSING_PARAM){ mp_msg(MSGT_CFGPARSER, MSGL_ERR,MSGTR_MissingSuboptionParameter,lst[2*i],co->name); r = M_OPT_INVALID; } else r = sr; } } free(lst[2*i]); free(lst[2*i+1]); } if(lst) free(lst); } else r = m_option_parse(co->opt,arg,param,set ? co->slots->data : NULL,config->mode); // Parsing failed ? if(r < 0) return r; // Set the option if(set) { m_option_set(co->opt,co->opt->p,co->slots->data); co->flags |= M_CFG_OPT_SET; } return r; } int m_config_set_option(m_config_t *config, char* arg, char* param) { mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Setting %s=%s\n",arg,param); return m_config_parse_option(config,arg,param,1); } int m_config_check_option(m_config_t *config, char* arg, char* param) { int r; mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Checking %s=%s\n",arg,param); r=m_config_parse_option(config,arg,param,0); if(r==M_OPT_MISSING_PARAM){ mp_msg(MSGT_CFGPARSER, MSGL_ERR,MSGTR_MissingOptionParameter,arg); return M_OPT_INVALID; } return r; } const m_option_t* m_config_get_option(m_config_t *config, char* arg) { m_config_option_t *co; #ifdef MP_DEBUG assert(config != NULL); assert(config->lvl > 0); assert(arg != NULL); #endif co = m_config_get_co(config,arg); if(co) return co->opt; else return NULL; } const void* m_config_get_option_ptr(m_config_t *config, char* arg) { const m_option_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; } void m_config_print_option_list(m_config_t *config) { char min[50],max[50]; m_config_option_t* co; int count = 0; if(!config->opts) return; mp_msg(MSGT_CFGPARSER, MSGL_INFO, MSGTR_OptionListHeader); for(co = config->opts ; co ; co = co->next) { const m_option_t* opt = co->opt; if(opt->type->flags & M_OPT_TYPE_HAS_CHILD) continue; if(opt->flags & M_OPT_MIN) sprintf(min,"%-8.0f",opt->min); else strcpy(min,"No"); if(opt->flags & M_OPT_MAX) sprintf(max,"%-8.0f",opt->max); else strcpy(max,"No"); mp_msg(MSGT_CFGPARSER, MSGL_INFO, " %-20.20s %-15.15s %-10.10s %-10.10s %-3.3s %-3.3s %-3.3s\n", co->name, co->opt->type->name, min, max, opt->flags & CONF_GLOBAL ? "Yes" : "No", opt->flags & CONF_NOCMD ? "No" : "Yes", opt->flags & CONF_NOCFG ? "No" : "Yes"); count++; } mp_msg(MSGT_CFGPARSER, MSGL_INFO, MSGTR_TotalOptions,count); } m_profile_t* m_config_get_profile(m_config_t* config, char* name) { m_profile_t* p; for(p = config->profiles ; p ; p = p->next) if(!strcmp(p->name,name)) return p; return NULL; } m_profile_t* m_config_add_profile(m_config_t* config, char* name) { m_profile_t* p = m_config_get_profile(config,name); if(p) return p; p = calloc(1,sizeof(m_profile_t)); p->name = strdup(name); p->next = config->profiles; config->profiles = p; return p; } void m_profile_set_desc(m_profile_t* p, char* desc) { if(p->desc) free(p->desc); p->desc = desc ? strdup(desc) : NULL; } int m_config_set_profile_option(m_config_t* config, m_profile_t* p, char* name, char* val) { int i = m_config_check_option(config,name,val); if(i < 0) return i; if(p->opts) p->opts = realloc(p->opts,2*(p->num_opts+2)*sizeof(char*)); else p->opts = malloc(2*(p->num_opts+2)*sizeof(char*)); p->opts[p->num_opts*2] = strdup(name); p->opts[p->num_opts*2+1] = val ? strdup(val) : NULL; p->num_opts++; p->opts[p->num_opts*2] = p->opts[p->num_opts*2+1] = NULL; return 1; } void m_config_set_profile(m_config_t* config, m_profile_t* p) { int i; if(config->profile_depth > MAX_PROFILE_DEPTH) { mp_msg(MSGT_CFGPARSER, MSGL_WARN, MSGTR_ProfileInclusionTooDeep); return; } config->profile_depth++; for(i = 0 ; i < p->num_opts ; i++) m_config_set_option(config,p->opts[2*i],p->opts[2*i+1]); config->profile_depth--; } static int parse_profile(const m_option_t *opt, const char *name, char *param, void *dst, int src) { m_config_t* config = opt->priv; char** list = NULL; int i,r; if(param && !strcmp(param,"help")) { m_profile_t* p; if(!config->profiles) { mp_msg(MSGT_CFGPARSER, MSGL_INFO, MSGTR_NoProfileDefined); return M_OPT_EXIT-1; } mp_msg(MSGT_CFGPARSER, MSGL_INFO, MSGTR_AvailableProfiles); for(p = config->profiles ; p ; p = p->next) mp_msg(MSGT_CFGPARSER, MSGL_INFO, "\t%s\t%s\n",p->name, p->desc ? p->desc : ""); mp_msg(MSGT_CFGPARSER, MSGL_INFO, "\n"); return M_OPT_EXIT-1; } r = m_option_type_string_list.parse(opt,name,param,&list,src); if(r < 0) return r; if(!list || !list[0]) return M_OPT_INVALID; for(i = 0 ; list[i] ; i++) if(!m_config_get_profile(config,list[i])) { mp_msg(MSGT_CFGPARSER, MSGL_WARN, MSGTR_UnknownProfile, list[i]); r = M_OPT_INVALID; } if(dst) m_option_copy(opt,dst,&list); else m_option_free(opt,&list); return r; } static void set_profile(const m_option_t *opt, void *dst, void *src) { m_config_t* config = opt->priv; m_profile_t* p; char** list = NULL; int i; if(!src || !*(char***)src) return; m_option_copy(opt,&list,src); for(i = 0 ; list[i] ; i++) { p = m_config_get_profile(config,list[i]); if(!p) continue; m_config_set_profile(config,p); } m_option_free(opt,&list); } static int show_profile(m_option_t *opt, char* name, char *param) { m_config_t* config = opt->priv; m_profile_t* p; int i,j; if(!param) return M_OPT_MISSING_PARAM; if(!(p = m_config_get_profile(config,param))) { mp_msg(MSGT_CFGPARSER, MSGL_ERR, MSGTR_UnknownProfile, param); return M_OPT_EXIT-1; } if(!config->profile_depth) mp_msg(MSGT_CFGPARSER, MSGL_INFO, MSGTR_Profile, param, p->desc ? p->desc : ""); config->profile_depth++; for(i = 0 ; i < p->num_opts ; i++) { char spc[config->profile_depth+1]; for(j = 0 ; j < config->profile_depth ; j++) spc[j] = ' '; spc[config->profile_depth] = '\0'; mp_msg(MSGT_CFGPARSER, MSGL_INFO, "%s%s=%s\n", spc, p->opts[2*i], p->opts[2*i+1]); if(config->profile_depth < MAX_PROFILE_DEPTH && !strcmp(p->opts[2*i],"profile")) { char* e,*list = p->opts[2*i+1]; while((e = strchr(list,','))) { int l = e-list; char tmp[l+1]; if(!l) continue; memcpy(tmp,list,l); tmp[l] = '\0'; show_profile(opt,name,tmp); list = e+1; } if(list[0] != '\0') show_profile(opt,name,list); } } config->profile_depth--; if(!config->profile_depth) mp_msg(MSGT_CFGPARSER, MSGL_INFO, "\n"); return M_OPT_EXIT-1; } static int list_options(m_option_t *opt, char* name, char *param) { m_config_t* config = opt->priv; m_config_print_option_list(config); return M_OPT_EXIT; }