Reformat vd.c
[mplayer.git] / m_config.c
blobe32fcfd024353003734ff0463bdc24049f052bdc
2 /// \file
3 /// \ingroup Config
5 #include "config.h"
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <errno.h>
10 #include <string.h>
11 #ifdef MP_DEBUG
12 #include <assert.h>
13 #endif
15 #include "m_config.h"
16 #include "m_option.h"
17 #include "mp_msg.h"
18 #include "help_mp.h"
20 #define MAX_PROFILE_DEPTH 20
22 static int
23 parse_profile(const m_option_t *opt, const char *name, char *param, void *dst, int src);
25 static void
26 set_profile(const m_option_t *opt, void* dst, void* src);
28 static int
29 show_profile(m_option_t *opt, char* name, char *param);
31 static void
32 m_config_add_option(m_config_t *config, const m_option_t *arg, const char* prefix);
34 static int
35 list_options(m_option_t *opt, char* name, char *param);
37 static void m_option_save(const m_config_t *config, const m_option_t *opt,
38 void *dst)
40 if (opt->type->save) {
41 void *src = opt->new ? (char*)config->optstruct + opt->offset : opt->p;
42 opt->type->save(opt, dst, src);
46 static void m_option_set(const m_config_t *config, const m_option_t *opt,
47 void *src)
49 if (opt->type->set) {
50 void *dst = opt->new ? (char*)config->optstruct + opt->offset : opt->p;
51 opt->type->set(opt, dst, src);
57 m_config_t*
58 m_config_new(void *optstruct) {
59 m_config_t* config;
60 static int initialized = 0;
61 static m_option_type_t profile_opt_type;
62 static m_option_t ref_opts[] = {
63 { "profile", NULL, &profile_opt_type, CONF_NOSAVE, 0, 0, NULL },
64 { "show-profile", show_profile, CONF_TYPE_PRINT_FUNC, CONF_NOCFG, 0, 0, NULL },
65 { "list-options", list_options, CONF_TYPE_PRINT_FUNC, CONF_NOCFG, 0, 0, NULL },
66 { NULL, NULL, NULL, 0, 0, 0, NULL }
68 int i;
70 config = calloc(1,sizeof(m_config_t));
71 config->lvl = 1; // 0 Is the defaults
72 if(!initialized) {
73 initialized = 1;
74 profile_opt_type = m_option_type_string_list;
75 profile_opt_type.parse = parse_profile;
76 profile_opt_type.set = set_profile;
78 config->self_opts = malloc(sizeof(ref_opts));
79 memcpy(config->self_opts,ref_opts,sizeof(ref_opts));
80 for(i = 0 ; config->self_opts[i].name ; i++)
81 config->self_opts[i].priv = config;
82 m_config_register_options(config,config->self_opts);
83 config->optstruct = optstruct;
85 return config;
88 void
89 m_config_free(m_config_t* config) {
90 m_config_option_t *i = config->opts, *ct;
91 m_config_save_slot_t *sl,*st;
92 m_profile_t *p,*pn;
93 int j;
95 #ifdef MP_DEBUG
96 assert(config != NULL);
97 #endif
99 while(i) {
100 if (i->flags & M_CFG_OPT_ALIAS)
101 sl = NULL;
102 else
103 sl = i->slots;
104 while(sl) {
105 m_option_free(i->opt,sl->data);
106 st = sl->prev;
107 free(sl);
108 sl = st;
110 if(i->name != i->opt->name)
111 free(i->name);
112 ct = i->next;
113 free(i);
114 i = ct;
116 for(p = config->profiles ; p ; p = pn) {
117 pn = p->next;
118 free(p->name);
119 if(p->desc) free(p->desc);
120 for(j = 0 ; j < p->num_opts ; j++) {
121 free(p->opts[2*j]);
122 if(p->opts[2*j+1]) free(p->opts[2*j+1]);
124 free(p->opts);
125 free(p);
127 free(config->self_opts);
128 free(config);
131 void
132 m_config_push(m_config_t* config) {
133 m_config_option_t *co;
134 m_config_save_slot_t *slot;
136 #ifdef MP_DEBUG
137 assert(config != NULL);
138 assert(config->lvl > 0);
139 #endif
141 config->lvl++;
143 for(co = config->opts ; co ; co = co->next ) {
144 if(co->opt->type->flags & M_OPT_TYPE_HAS_CHILD)
145 continue;
146 if(co->opt->flags & (M_OPT_GLOBAL|M_OPT_NOSAVE))
147 continue;
148 if((co->opt->flags & M_OPT_OLD) && !(co->flags & M_CFG_OPT_SET))
149 continue;
150 if(co->flags & M_CFG_OPT_ALIAS)
151 continue;
153 // Update the current status
154 m_option_save(config, co->opt, co->slots->data);
156 // Allocate a new slot
157 slot = calloc(1,sizeof(m_config_save_slot_t) + co->opt->type->size);
158 slot->lvl = config->lvl;
159 slot->prev = co->slots;
160 co->slots = slot;
161 m_option_copy(co->opt,co->slots->data,co->slots->prev->data);
162 // Reset our set flag
163 co->flags &= ~M_CFG_OPT_SET;
166 mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Config pushed level is now %d\n",config->lvl);
169 void
170 m_config_pop(m_config_t* config) {
171 m_config_option_t *co;
172 m_config_save_slot_t *slot;
174 #ifdef MP_DEBUG
175 assert(config != NULL);
176 assert(config->lvl > 1);
177 #endif
179 for(co = config->opts ; co ; co = co->next ) {
180 int pop = 0;
181 if(co->opt->type->flags & M_OPT_TYPE_HAS_CHILD)
182 continue;
183 if(co->opt->flags & (M_OPT_GLOBAL|M_OPT_NOSAVE))
184 continue;
185 if(co->flags & M_CFG_OPT_ALIAS)
186 continue;
187 if(co->slots->lvl > config->lvl)
188 mp_msg(MSGT_CFGPARSER, MSGL_WARN,MSGTR_SaveSlotTooOld,config->lvl,co->slots->lvl);
190 while(co->slots->lvl >= config->lvl) {
191 m_option_free(co->opt,co->slots->data);
192 slot = co->slots;
193 co->slots = slot->prev;
194 free(slot);
195 pop++;
197 if(pop) // We removed some ctx -> set the previous value
198 m_option_set(config, co->opt, co->slots->data);
201 config->lvl--;
202 mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Config poped level=%d\n",config->lvl);
205 static void
206 m_config_add_option(m_config_t *config, const m_option_t *arg, const char* prefix) {
207 m_config_option_t *co;
208 m_config_save_slot_t* sl;
210 #ifdef MP_DEBUG
211 assert(config != NULL);
212 assert(config->lvl > 0);
213 assert(arg != NULL);
214 #endif
216 // Allocate a new entry for this option
217 co = calloc(1,sizeof(m_config_option_t) + arg->type->size);
218 co->opt = arg;
220 // Fill in the full name
221 if(prefix && strlen(prefix) > 0) {
222 int l = strlen(prefix) + 1 + strlen(arg->name) + 1;
223 co->name = malloc(l);
224 sprintf(co->name,"%s:%s",prefix,arg->name);
225 } else
226 co->name = arg->name;
228 // Option with children -> add them
229 if(arg->type->flags & M_OPT_TYPE_HAS_CHILD) {
230 const m_option_t *ol = arg->p;
231 int i;
232 co->slots = NULL;
233 for(i = 0 ; ol[i].name != NULL ; i++)
234 m_config_add_option(config,&ol[i], co->name);
235 } else {
236 m_config_option_t *i;
237 // Check if there is already an option pointing to this address
238 if(arg->p || arg->new && arg->offset >= 0) {
239 for(i = config->opts ; i ; i = i->next ) {
240 if (arg->new ? (i->opt->new && i->opt->offset == arg->offset)
241 : (!i->opt->new && i->opt->p == arg->p)) {
242 // So we don't save the same vars more than 1 time
243 co->slots = i->slots;
244 co->flags |= M_CFG_OPT_ALIAS;
245 break;
249 if(!(co->flags & M_CFG_OPT_ALIAS)) {
250 // Allocate a slot for the defaults
251 sl = calloc(1,sizeof(m_config_save_slot_t) + arg->type->size);
252 m_option_save(config, arg, sl->data);
253 // Hack to avoid too much trouble with dynamically allocated data :
254 // We always use a dynamic version
255 if((arg->type->flags & M_OPT_TYPE_DYNAMIC) && arg->p && (*(void**)arg->p)) {
256 *(void**)arg->p = NULL;
257 m_option_set(config, arg, sl->data);
259 sl->lvl = 0;
260 sl->prev = NULL;
261 co->slots = calloc(1,sizeof(m_config_save_slot_t) + arg->type->size);
262 co->slots->prev = sl;
263 co->slots->lvl = config->lvl;
264 m_option_copy(co->opt,co->slots->data,sl->data);
265 } // !M_OPT_ALIAS
267 co->next = config->opts;
268 config->opts = co;
272 m_config_register_options(m_config_t *config, const m_option_t *args) {
273 int i;
275 #ifdef MP_DEBUG
276 assert(config != NULL);
277 assert(config->lvl > 0);
278 assert(args != NULL);
279 #endif
281 for(i = 0 ; args[i].name != NULL ; i++)
282 m_config_add_option(config,&args[i],NULL);
284 return 1;
287 static m_config_option_t*
288 m_config_get_co(m_config_t *config, char* arg) {
289 m_config_option_t *co;
291 for(co = config->opts ; co ; co = co->next ) {
292 int l = strlen(co->name) - 1;
293 if((co->opt->type->flags & M_OPT_TYPE_ALLOW_WILDCARD) &&
294 (co->name[l] == '*')) {
295 if(strncasecmp(co->name,arg,l) == 0)
296 return co;
297 } else if(strcasecmp(co->name,arg) == 0)
298 return co;
300 return NULL;
303 static int
304 m_config_parse_option(m_config_t *config, char* arg, char* param,int set) {
305 m_config_option_t *co;
306 int r = 0;
308 #ifdef MP_DEBUG
309 assert(config != NULL);
310 assert(config->lvl > 0);
311 assert(arg != NULL);
312 #endif
314 co = m_config_get_co(config,arg);
315 if(!co){
316 // mp_msg(MSGT_CFGPARSER, MSGL_ERR,"Unknown option: %s\n",arg);
317 return M_OPT_UNKNOWN;
320 #ifdef MP_DEBUG
321 // This is the only mandatory function
322 assert(co->opt->type->parse);
323 #endif
325 // Check if this option isn't forbidden in the current mode
326 if((config->mode == M_CONFIG_FILE) && (co->opt->flags & M_OPT_NOCFG)) {
327 mp_msg(MSGT_CFGPARSER, MSGL_ERR,MSGTR_InvalidCfgfileOption,arg);
328 return M_OPT_INVALID;
330 if((config->mode == M_COMMAND_LINE) && (co->opt->flags & M_OPT_NOCMD)) {
331 mp_msg(MSGT_CFGPARSER, MSGL_ERR,MSGTR_InvalidCmdlineOption,arg);
332 return M_OPT_INVALID;
334 // During command line preparse set only pre-parse options
335 // Otherwise only set pre-parse option if they were not already set.
336 if(((config->mode == M_COMMAND_LINE_PRE_PARSE) &&
337 !(co->opt->flags & M_OPT_PRE_PARSE)) ||
338 ((config->mode != M_COMMAND_LINE_PRE_PARSE) &&
339 (co->opt->flags & M_OPT_PRE_PARSE) && (co->flags & M_CFG_OPT_SET)))
340 set = 0;
342 // Option with children are a bit different to parse
343 if(co->opt->type->flags & M_OPT_TYPE_HAS_CHILD) {
344 char** lst = NULL;
345 int i,sr;
346 // Parse the child options
347 r = m_option_parse(co->opt,arg,param,&lst,M_COMMAND_LINE);
348 // Set them now
349 if(r >= 0)
350 for(i = 0 ; lst && lst[2*i] ; i++) {
351 int l = strlen(co->name) + 1 + strlen(lst[2*i]) + 1;
352 if(r >= 0) {
353 // Build the full name
354 char n[l];
355 sprintf(n,"%s:%s",co->name,lst[2*i]);
356 sr = m_config_parse_option(config,n,lst[2*i+1],set);
357 if(sr < 0){
358 if(sr == M_OPT_UNKNOWN){
359 mp_msg(MSGT_CFGPARSER, MSGL_ERR,MSGTR_InvalidSuboption,co->name,lst[2*i]);
360 r = M_OPT_INVALID;
361 } else
362 if(sr == M_OPT_MISSING_PARAM){
363 mp_msg(MSGT_CFGPARSER, MSGL_ERR,MSGTR_MissingSuboptionParameter,lst[2*i],co->name);
364 r = M_OPT_INVALID;
365 } else
366 r = sr;
369 free(lst[2*i]);
370 free(lst[2*i+1]);
372 if(lst) free(lst);
373 } else
374 r = m_option_parse(co->opt,arg,param,set ? co->slots->data : NULL,config->mode);
376 // Parsing failed ?
377 if(r < 0)
378 return r;
379 // Set the option
380 if(set) {
381 m_option_set(config, co->opt, co->slots->data);
382 co->flags |= M_CFG_OPT_SET;
385 return r;
389 m_config_set_option(m_config_t *config, char* arg, char* param) {
390 mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Setting %s=%s\n",arg,param);
391 return m_config_parse_option(config,arg,param,1);
395 m_config_check_option(m_config_t *config, char* arg, char* param) {
396 int r;
397 mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Checking %s=%s\n",arg,param);
398 r=m_config_parse_option(config,arg,param,0);
399 if(r==M_OPT_MISSING_PARAM){
400 mp_msg(MSGT_CFGPARSER, MSGL_ERR,MSGTR_MissingOptionParameter,arg);
401 return M_OPT_INVALID;
403 return r;
407 const m_option_t*
408 m_config_get_option(m_config_t *config, char* arg) {
409 m_config_option_t *co;
411 #ifdef MP_DEBUG
412 assert(config != NULL);
413 assert(config->lvl > 0);
414 assert(arg != NULL);
415 #endif
417 co = m_config_get_co(config,arg);
418 if(co)
419 return co->opt;
420 else
421 return NULL;
424 const void*
425 m_config_get_option_ptr(m_config_t *config, char* arg) {
426 const m_option_t* conf;
428 #ifdef MP_DEBUG
429 assert(config != NULL);
430 assert(arg != NULL);
431 #endif
433 conf = m_config_get_option(config,arg);
434 if(!conf) return NULL;
435 return conf->p;
438 void
439 m_config_print_option_list(m_config_t *config) {
440 char min[50],max[50];
441 m_config_option_t* co;
442 int count = 0;
444 if(!config->opts) return;
446 mp_msg(MSGT_CFGPARSER, MSGL_INFO, MSGTR_OptionListHeader);
447 for(co = config->opts ; co ; co = co->next) {
448 const m_option_t* opt = co->opt;
449 if(opt->type->flags & M_OPT_TYPE_HAS_CHILD) continue;
450 if(opt->flags & M_OPT_MIN)
451 sprintf(min,"%-8.0f",opt->min);
452 else
453 strcpy(min,"No");
454 if(opt->flags & M_OPT_MAX)
455 sprintf(max,"%-8.0f",opt->max);
456 else
457 strcpy(max,"No");
458 mp_msg(MSGT_CFGPARSER, MSGL_INFO, " %-20.20s %-15.15s %-10.10s %-10.10s %-3.3s %-3.3s %-3.3s\n",
459 co->name,
460 co->opt->type->name,
461 min,
462 max,
463 opt->flags & CONF_GLOBAL ? "Yes" : "No",
464 opt->flags & CONF_NOCMD ? "No" : "Yes",
465 opt->flags & CONF_NOCFG ? "No" : "Yes");
466 count++;
468 mp_msg(MSGT_CFGPARSER, MSGL_INFO, MSGTR_TotalOptions,count);
471 m_profile_t*
472 m_config_get_profile(m_config_t* config, char* name) {
473 m_profile_t* p;
474 for(p = config->profiles ; p ; p = p->next)
475 if(!strcmp(p->name,name)) return p;
476 return NULL;
479 m_profile_t*
480 m_config_add_profile(m_config_t* config, char* name) {
481 m_profile_t* p = m_config_get_profile(config,name);
482 if(p) return p;
483 p = calloc(1,sizeof(m_profile_t));
484 p->name = strdup(name);
485 p->next = config->profiles;
486 config->profiles = p;
487 return p;
490 void
491 m_profile_set_desc(m_profile_t* p, char* desc) {
492 if(p->desc) free(p->desc);
493 p->desc = desc ? strdup(desc) : NULL;
497 m_config_set_profile_option(m_config_t* config, m_profile_t* p,
498 char* name, char* val) {
499 int i = m_config_check_option(config,name,val);
500 if(i < 0) return i;
501 if(p->opts) p->opts = realloc(p->opts,2*(p->num_opts+2)*sizeof(char*));
502 else p->opts = malloc(2*(p->num_opts+2)*sizeof(char*));
503 p->opts[p->num_opts*2] = strdup(name);
504 p->opts[p->num_opts*2+1] = val ? strdup(val) : NULL;
505 p->num_opts++;
506 p->opts[p->num_opts*2] = p->opts[p->num_opts*2+1] = NULL;
507 return 1;
510 void
511 m_config_set_profile(m_config_t* config, m_profile_t* p) {
512 int i;
513 if(config->profile_depth > MAX_PROFILE_DEPTH) {
514 mp_msg(MSGT_CFGPARSER, MSGL_WARN, MSGTR_ProfileInclusionTooDeep);
515 return;
517 config->profile_depth++;
518 for(i = 0 ; i < p->num_opts ; i++)
519 m_config_set_option(config,p->opts[2*i],p->opts[2*i+1]);
520 config->profile_depth--;
523 static int
524 parse_profile(const m_option_t *opt, const char *name, char *param, void *dst, int src)
526 m_config_t* config = opt->priv;
527 char** list = NULL;
528 int i,r;
529 if(param && !strcmp(param,"help")) {
530 m_profile_t* p;
531 if(!config->profiles) {
532 mp_msg(MSGT_CFGPARSER, MSGL_INFO, MSGTR_NoProfileDefined);
533 return M_OPT_EXIT-1;
535 mp_msg(MSGT_CFGPARSER, MSGL_INFO, MSGTR_AvailableProfiles);
536 for(p = config->profiles ; p ; p = p->next)
537 mp_msg(MSGT_CFGPARSER, MSGL_INFO, "\t%s\t%s\n",p->name,
538 p->desc ? p->desc : "");
539 mp_msg(MSGT_CFGPARSER, MSGL_INFO, "\n");
540 return M_OPT_EXIT-1;
543 r = m_option_type_string_list.parse(opt,name,param,&list,src);
544 if(r < 0) return r;
545 if(!list || !list[0]) return M_OPT_INVALID;
546 for(i = 0 ; list[i] ; i++)
547 if(!m_config_get_profile(config,list[i])) {
548 mp_msg(MSGT_CFGPARSER, MSGL_WARN, MSGTR_UnknownProfile,
549 list[i]);
550 r = M_OPT_INVALID;
552 if(dst)
553 m_option_copy(opt,dst,&list);
554 else
555 m_option_free(opt,&list);
556 return r;
559 static void
560 set_profile(const m_option_t *opt, void *dst, void *src) {
561 m_config_t* config = opt->priv;
562 m_profile_t* p;
563 char** list = NULL;
564 int i;
565 if(!src || !*(char***)src) return;
566 m_option_copy(opt,&list,src);
567 for(i = 0 ; list[i] ; i++) {
568 p = m_config_get_profile(config,list[i]);
569 if(!p) continue;
570 m_config_set_profile(config,p);
572 m_option_free(opt,&list);
575 static int
576 show_profile(m_option_t *opt, char* name, char *param) {
577 m_config_t* config = opt->priv;
578 m_profile_t* p;
579 int i,j;
580 if(!param) return M_OPT_MISSING_PARAM;
581 if(!(p = m_config_get_profile(config,param))) {
582 mp_msg(MSGT_CFGPARSER, MSGL_ERR, MSGTR_UnknownProfile, param);
583 return M_OPT_EXIT-1;
585 if(!config->profile_depth)
586 mp_msg(MSGT_CFGPARSER, MSGL_INFO, MSGTR_Profile, param,
587 p->desc ? p->desc : "");
588 config->profile_depth++;
589 for(i = 0 ; i < p->num_opts ; i++) {
590 char spc[config->profile_depth+1];
591 for(j = 0 ; j < config->profile_depth ; j++)
592 spc[j] = ' ';
593 spc[config->profile_depth] = '\0';
595 mp_msg(MSGT_CFGPARSER, MSGL_INFO, "%s%s=%s\n", spc,
596 p->opts[2*i], p->opts[2*i+1]);
599 if(config->profile_depth < MAX_PROFILE_DEPTH &&
600 !strcmp(p->opts[2*i],"profile")) {
601 char* e,*list = p->opts[2*i+1];
602 while((e = strchr(list,','))) {
603 int l = e-list;
604 char tmp[l+1];
605 if(!l) continue;
606 memcpy(tmp,list,l);
607 tmp[l] = '\0';
608 show_profile(opt,name,tmp);
609 list = e+1;
611 if(list[0] != '\0')
612 show_profile(opt,name,list);
615 config->profile_depth--;
616 if(!config->profile_depth) mp_msg(MSGT_CFGPARSER, MSGL_INFO, "\n");
617 return M_OPT_EXIT-1;
620 static int
621 list_options(m_option_t *opt, char* name, char *param) {
622 m_config_t* config = opt->priv;
623 m_config_print_option_list(config);
624 return M_OPT_EXIT;