synced with 1.80
[mplayer/greg.git] / m_config.c
blob56f3ab2f6d10a773eb72b0cad1e07f30cf86c5c6
1 #include "config.h"
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <errno.h>
6 #include <string.h>
7 #ifdef MP_DEBUG
8 #include <assert.h>
9 #endif
11 #include "m_config.h"
12 #include "m_option.h"
13 #include "mp_msg.h"
14 #include "help_mp.h"
16 #define MAX_PROFILE_DEPTH 20
18 static int
19 parse_profile(m_option_t* opt,char *name, char *param, void* dst, int src);
21 static void
22 set_profile(m_option_t *opt, void* dst, void* src);
24 static int
25 show_profile(m_option_t *opt, char* name, char *param);
27 static void
28 m_config_add_option(m_config_t *config, m_option_t *arg, char* prefix);
30 static int
31 list_options(m_option_t *opt, char* name, char *param);
33 m_config_t*
34 m_config_new(void) {
35 m_config_t* config;
36 static int inited = 0;
37 static m_option_type_t profile_opt_type;
38 static m_option_t ref_opts[] = {
39 { "profile", NULL, &profile_opt_type, CONF_NOSAVE, 0, 0, NULL },
40 { "show-profile", show_profile, CONF_TYPE_PRINT_FUNC, CONF_NOCFG, 0, 0, NULL },
41 { "list-options", list_options, CONF_TYPE_PRINT_FUNC, CONF_NOCFG, 0, 0, NULL },
42 { NULL, NULL, NULL, 0, 0, 0, NULL }
44 int i;
46 config = (m_config_t*)calloc(1,sizeof(m_config_t));
47 config->lvl = 1; // 0 Is the defaults
48 if(!inited) {
49 inited = 1;
50 profile_opt_type = m_option_type_string_list;
51 profile_opt_type.parse = parse_profile;
52 profile_opt_type.set = set_profile;
54 config->self_opts = malloc(sizeof(ref_opts));
55 memcpy(config->self_opts,ref_opts,sizeof(ref_opts));
56 for(i = 0 ; config->self_opts[i].name ; i++)
57 config->self_opts[i].priv = config;
58 m_config_register_options(config,config->self_opts);
60 return config;
63 void
64 m_config_free(m_config_t* config) {
65 m_config_option_t *i = config->opts, *ct;
66 m_config_save_slot_t *sl,*st;
67 m_profile_t *p,*pn;
68 int j;
70 #ifdef MP_DEBUG
71 assert(config != NULL);
72 #endif
74 while(i) {
75 if (i->flags & M_CFG_OPT_ALIAS)
76 sl = NULL;
77 else
78 sl = i->slots;
79 while(sl) {
80 m_option_free(i->opt,sl->data);
81 st = sl->prev;
82 free(sl);
83 sl = st;
85 if(i->name != i->opt->name)
86 free(i->name);
87 ct = i->next;
88 free(i);
89 i = ct;
91 for(p = config->profiles ; p ; p = pn) {
92 pn = p->next;
93 free(p->name);
94 if(p->desc) free(p->desc);
95 for(j = 0 ; j < p->num_opts ; j++) {
96 free(p->opts[2*j]);
97 if(p->opts[2*j+1]) free(p->opts[2*j+1]);
99 free(p->opts);
100 free(p);
102 free(config->self_opts);
103 free(config);
106 void
107 m_config_push(m_config_t* config) {
108 m_config_option_t *co;
109 m_config_save_slot_t *slot;
111 #ifdef MP_DEBUG
112 assert(config != NULL);
113 assert(config->lvl > 0);
114 #endif
116 config->lvl++;
118 for(co = config->opts ; co ; co = co->next ) {
119 if(co->opt->type->flags & M_OPT_TYPE_HAS_CHILD)
120 continue;
121 if(co->opt->flags & (M_OPT_GLOBAL|M_OPT_NOSAVE))
122 continue;
123 if((co->opt->flags & M_OPT_OLD) && !(co->flags && M_CFG_OPT_SET))
124 continue;
125 if(co->flags & M_CFG_OPT_ALIAS)
126 continue;
128 // Update the current status
129 m_option_save(co->opt,co->slots->data,co->opt->p);
131 // Allocate a new slot
132 slot = (m_config_save_slot_t*)calloc(1,sizeof(m_config_save_slot_t) + co->opt->type->size);
133 slot->lvl = config->lvl;
134 slot->prev = co->slots;
135 co->slots = slot;
136 m_option_copy(co->opt,co->slots->data,co->slots->prev->data);
137 // Reset our set flag
138 co->flags &= ~M_CFG_OPT_SET;
141 mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Config pushed level is now %d\n",config->lvl);
144 void
145 m_config_pop(m_config_t* config) {
146 m_config_option_t *co;
147 m_config_save_slot_t *slot;
149 #ifdef MP_DEBUG
150 assert(config != NULL);
151 assert(config->lvl > 1);
152 #endif
154 for(co = config->opts ; co ; co = co->next ) {
155 int pop = 0;
156 if(co->opt->type->flags & M_OPT_TYPE_HAS_CHILD)
157 continue;
158 if(co->opt->flags & (M_OPT_GLOBAL|M_OPT_NOSAVE))
159 continue;
160 if(co->flags & M_CFG_OPT_ALIAS)
161 continue;
162 if(co->slots->lvl > config->lvl)
163 mp_msg(MSGT_CFGPARSER, MSGL_WARN,MSGTR_SaveSlotTooOld,config->lvl,co->slots->lvl);
165 while(co->slots->lvl >= config->lvl) {
166 m_option_free(co->opt,co->slots->data);
167 slot = co->slots;
168 co->slots = slot->prev;
169 free(slot);
170 pop++;
172 if(pop) // We removed some ctx -> set the previous value
173 m_option_set(co->opt,co->opt->p,co->slots->data);
176 config->lvl--;
177 mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Config poped level=%d\n",config->lvl);
180 static void
181 m_config_add_option(m_config_t *config, m_option_t *arg, char* prefix) {
182 m_config_option_t *co;
183 m_config_save_slot_t* sl;
185 #ifdef MP_DEBUG
186 assert(config != NULL);
187 assert(config->lvl > 0);
188 assert(arg != NULL);
189 #endif
191 // Allocate a new entry for this option
192 co = (m_config_option_t*)calloc(1,sizeof(m_config_option_t) + arg->type->size);
193 co->opt = arg;
195 // Fill in the full name
196 if(prefix && strlen(prefix) > 0) {
197 int l = strlen(prefix) + 1 + strlen(arg->name) + 1;
198 co->name = (char*) malloc(l);
199 sprintf(co->name,"%s:%s",prefix,arg->name);
200 } else
201 co->name = arg->name;
203 // Option with childs -> add them
204 if(arg->type->flags & M_OPT_TYPE_HAS_CHILD) {
205 m_option_t *ol = arg->p;
206 int i;
207 co->slots = NULL;
208 for(i = 0 ; ol[i].name != NULL ; i++)
209 m_config_add_option(config,&ol[i], co->name);
210 } else {
211 m_config_option_t *i;
212 // Check if there is alredy an option pointing to this address
213 if(arg->p) {
214 for(i = config->opts ; i ; i = i->next ) {
215 if(i->opt->p == arg->p) { // So we don't save the same vars more than 1 time
216 co->slots = i->slots;
217 co->flags |= M_CFG_OPT_ALIAS;
218 break;
222 if(!(co->flags & M_CFG_OPT_ALIAS)) {
223 // Allocate a slot for the defaults
224 sl = (m_config_save_slot_t*)calloc(1,sizeof(m_config_save_slot_t) + arg->type->size);
225 m_option_save(arg,sl->data,(void**)arg->p);
226 // Hack to avoid too much trouble with dynamicly allocated data :
227 // We always use a dynamic version
228 if((arg->type->flags & M_OPT_TYPE_DYNAMIC) && arg->p && (*(void**)arg->p)) {
229 *(void**)arg->p = NULL;
230 m_option_set(arg,arg->p,sl->data);
232 sl->lvl = 0;
233 sl->prev = NULL;
234 co->slots = (m_config_save_slot_t*)calloc(1,sizeof(m_config_save_slot_t) + arg->type->size);
235 co->slots->prev = sl;
236 co->slots->lvl = config->lvl;
237 m_option_copy(co->opt,co->slots->data,sl->data);
238 } // !M_OPT_ALIAS
240 co->next = config->opts;
241 config->opts = co;
245 m_config_register_options(m_config_t *config, m_option_t *args) {
246 int i;
248 #ifdef MP_DEBUG
249 assert(config != NULL);
250 assert(config->lvl > 0);
251 assert(args != NULL);
252 #endif
254 for(i = 0 ; args[i].name != NULL ; i++)
255 m_config_add_option(config,&args[i],NULL);
257 return 1;
260 static m_config_option_t*
261 m_config_get_co(m_config_t *config, char* arg) {
262 m_config_option_t *co;
264 for(co = config->opts ; co ; co = co->next ) {
265 int l = strlen(co->name) - 1;
266 if((co->opt->type->flags & M_OPT_TYPE_ALLOW_WILDCARD) &&
267 (co->name[l] == '*')) {
268 if(strncasecmp(co->name,arg,l) == 0)
269 return co;
270 } else if(strcasecmp(co->name,arg) == 0)
271 return co;
273 return NULL;
276 static int
277 m_config_parse_option(m_config_t *config, char* arg, char* param,int set) {
278 m_config_option_t *co;
279 int r = 0;
281 #ifdef MP_DEBUG
282 assert(config != NULL);
283 assert(config->lvl > 0);
284 assert(arg != NULL);
285 #endif
287 co = m_config_get_co(config,arg);
288 if(!co){
289 // mp_msg(MSGT_CFGPARSER, MSGL_ERR,"Unknown option: %s\n",arg);
290 return M_OPT_UNKNOWN;
293 #ifdef MP_DEBUG
294 // This is the only mandatory function
295 assert(co->opt->type->parse);
296 #endif
298 // Check if this option isn't forbiden in the current mode
299 if((config->mode == M_CONFIG_FILE) && (co->opt->flags & M_OPT_NOCFG)) {
300 mp_msg(MSGT_CFGPARSER, MSGL_ERR,MSGTR_InvalidCfgfileOption,arg);
301 return M_OPT_INVALID;
303 if((config->mode == M_COMMAND_LINE) && (co->opt->flags & M_OPT_NOCMD)) {
304 mp_msg(MSGT_CFGPARSER, MSGL_ERR,MSGTR_InvalidCmdlineOption,arg);
305 return M_OPT_INVALID;
308 // Option with childs are a bit different to parse
309 if(co->opt->type->flags & M_OPT_TYPE_HAS_CHILD) {
310 char** lst = NULL;
311 int i,sr;
312 // Parse the child options
313 r = m_option_parse(co->opt,arg,param,&lst,M_COMMAND_LINE);
314 // Set them now
315 if(r >= 0)
316 for(i = 0 ; lst && lst[2*i] ; i++) {
317 int l = strlen(co->name) + 1 + strlen(lst[2*i]) + 1;
318 if(r >= 0) {
319 // Build the full name
320 char n[l];
321 sprintf(n,"%s:%s",co->name,lst[2*i]);
322 sr = m_config_parse_option(config,n,lst[2*i+1],set);
323 if(sr < 0){
324 if(sr == M_OPT_UNKNOWN){
325 mp_msg(MSGT_CFGPARSER, MSGL_ERR,MSGTR_InvalidSuboption,co->name,lst[2*i]);
326 r = M_OPT_INVALID;
327 } else
328 if(sr == M_OPT_MISSING_PARAM){
329 mp_msg(MSGT_CFGPARSER, MSGL_ERR,MSGTR_MissingSuboptionParameter,lst[2*i],co->name);
330 r = M_OPT_INVALID;
331 } else
332 r = sr;
335 free(lst[2*i]);
336 free(lst[2*i+1]);
338 if(lst) free(lst);
339 } else
340 r = m_option_parse(co->opt,arg,param,set ? co->slots->data : NULL,config->mode);
342 // Parsing failed ?
343 if(r < 0)
344 return r;
345 // Set the option
346 if(set) {
347 m_option_set(co->opt,co->opt->p,co->slots->data);
348 co->flags |= M_CFG_OPT_SET;
351 return r;
355 m_config_set_option(m_config_t *config, char* arg, char* param) {
356 mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Setting %s=%s\n",arg,param);
357 return m_config_parse_option(config,arg,param,1);
361 m_config_check_option(m_config_t *config, char* arg, char* param) {
362 int r;
363 mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Checking %s=%s\n",arg,param);
364 r=m_config_parse_option(config,arg,param,0);
365 if(r==M_OPT_MISSING_PARAM){
366 mp_msg(MSGT_CFGPARSER, MSGL_ERR,MSGTR_MissingOptionParameter,arg);
367 return M_OPT_INVALID;
369 return r;
373 m_option_t*
374 m_config_get_option(m_config_t *config, char* arg) {
375 m_config_option_t *co;
377 #ifdef MP_DEBUG
378 assert(config != NULL);
379 assert(config->lvl > 0);
380 assert(arg != NULL);
381 #endif
383 co = m_config_get_co(config,arg);
384 if(co)
385 return co->opt;
386 else
387 return NULL;
390 void*
391 m_config_get_option_ptr(m_config_t *config, char* arg) {
392 m_option_t* conf;
394 #ifdef MP_DEBUG
395 assert(config != NULL);
396 assert(arg != NULL);
397 #endif
399 conf = m_config_get_option(config,arg);
400 if(!conf) return NULL;
401 return conf->p;
404 void
405 m_config_print_option_list(m_config_t *config) {
406 char min[50],max[50];
407 m_config_option_t* co;
408 int count = 0;
410 if(!config->opts) return;
412 mp_msg(MSGT_CFGPARSER, MSGL_INFO, MSGTR_OptionListHeader);
413 for(co = config->opts ; co ; co = co->next) {
414 m_option_t* opt = co->opt;
415 if(opt->type->flags & M_OPT_TYPE_HAS_CHILD) continue;
416 if(opt->flags & M_OPT_MIN)
417 sprintf(min,"%-8.0f",opt->min);
418 else
419 strcpy(min,"No");
420 if(opt->flags & M_OPT_MAX)
421 sprintf(max,"%-8.0f",opt->max);
422 else
423 strcpy(max,"No");
424 mp_msg(MSGT_CFGPARSER, MSGL_INFO, " %-20.20s %-15.15s %-10.10s %-10.10s %-3.3s %-3.3s %-3.3s\n",
425 co->name,
426 co->opt->type->name,
427 min,
428 max,
429 opt->flags & CONF_GLOBAL ? "Yes" : "No",
430 opt->flags & CONF_NOCMD ? "No" : "Yes",
431 opt->flags & CONF_NOCFG ? "No" : "Yes");
432 count++;
434 mp_msg(MSGT_CFGPARSER, MSGL_INFO, MSGTR_TotalOptions,count);
437 m_profile_t*
438 m_config_get_profile(m_config_t* config, char* name) {
439 m_profile_t* p;
440 for(p = config->profiles ; p ; p = p->next)
441 if(!strcmp(p->name,name)) return p;
442 return NULL;
445 m_profile_t*
446 m_config_add_profile(m_config_t* config, char* name) {
447 m_profile_t* p = m_config_get_profile(config,name);
448 if(p) return p;
449 p = calloc(1,sizeof(m_profile_t));
450 p->name = strdup(name);
451 p->next = config->profiles;
452 config->profiles = p;
453 return p;
456 void
457 m_profile_set_desc(m_profile_t* p, char* desc) {
458 if(p->desc) free(p->desc);
459 p->desc = desc ? strdup(desc) : NULL;
463 m_config_set_profile_option(m_config_t* config, m_profile_t* p,
464 char* name, char* val) {
465 int i = m_config_check_option(config,name,val);
466 if(i < 0) return i;
467 if(p->opts) p->opts = realloc(p->opts,2*(p->num_opts+2)*sizeof(char*));
468 else p->opts = malloc(2*(p->num_opts+2)*sizeof(char*));
469 p->opts[p->num_opts*2] = strdup(name);
470 p->opts[p->num_opts*2+1] = val ? strdup(val) : NULL;
471 p->num_opts++;
472 p->opts[p->num_opts*2] = p->opts[p->num_opts*2+1] = NULL;
475 static void
476 m_config_set_profile(m_config_t* config, m_profile_t* p) {
477 int i;
478 if(config->profile_depth > MAX_PROFILE_DEPTH) {
479 mp_msg(MSGT_CFGPARSER, MSGL_WARN, MSGTR_TooDeepProfileInclusion);
480 return;
482 config->profile_depth++;
483 for(i = 0 ; i < p->num_opts ; i++)
484 m_config_set_option(config,p->opts[2*i],p->opts[2*i+1]);
485 config->profile_depth--;
488 static int
489 parse_profile(m_option_t* opt,char *name, char *param, void* dst, int src) {
490 m_config_t* config = opt->priv;
491 char** list = NULL;
492 int i,r;
493 if(param && !strcmp(param,"help")) {
494 m_profile_t* p;
495 if(!config->profiles) {
496 mp_msg(MSGT_CFGPARSER, MSGL_INFO, MSGTR_NoProfileDefined);
497 return M_OPT_EXIT-1;
499 mp_msg(MSGT_CFGPARSER, MSGL_INFO, MSGTR_AvailableProfiles);
500 for(p = config->profiles ; p ; p = p->next)
501 mp_msg(MSGT_CFGPARSER, MSGL_INFO, "\t%s\t%s\n",p->name,
502 p->desc ? p->desc : "");
503 mp_msg(MSGT_CFGPARSER, MSGL_INFO, "\n");
504 return M_OPT_EXIT-1;
507 r = m_option_type_string_list.parse(opt,name,param,&list,src);
508 if(r < 0) return r;
509 if(!list || !list[0]) return M_OPT_INVALID;
510 for(i = 0 ; list[i] ; i++)
511 if(!m_config_get_profile(config,list[i])) {
512 mp_msg(MSGT_CFGPARSER, MSGL_WARN, MSGTR_UnknownProfile,
513 list[i]);
514 r = M_OPT_INVALID;
516 if(dst)
517 m_option_copy(opt,dst,&list);
518 else
519 m_option_free(opt,&list);
520 return r;
523 static void
524 set_profile(m_option_t *opt, void* dst, void* src) {
525 m_config_t* config = opt->priv;
526 m_profile_t* p;
527 char** list = NULL;
528 int i;
529 if(!src || !*(char***)src) return;
530 m_option_copy(opt,&list,src);
531 for(i = 0 ; list[i] ; i++) {
532 p = m_config_get_profile(config,list[i]);
533 if(!p) continue;
534 m_config_set_profile(config,p);
536 m_option_free(opt,&list);
539 static int
540 show_profile(m_option_t *opt, char* name, char *param) {
541 m_config_t* config = opt->priv;
542 m_profile_t* p;
543 int i,j;
544 if(!param) return M_OPT_MISSING_PARAM;
545 if(!(p = m_config_get_profile(config,param))) {
546 mp_msg(MSGT_CFGPARSER, MSGL_ERR, MSGTR_UnknownProfile, param);
547 return M_OPT_EXIT-1;
549 if(!config->profile_depth)
550 mp_msg(MSGT_CFGPARSER, MSGL_INFO, MSGTR_Profile, param,
551 p->desc ? p->desc : "");
552 config->profile_depth++;
553 for(i = 0 ; i < p->num_opts ; i++) {
554 char spc[config->profile_depth+1];
555 for(j = 0 ; j < config->profile_depth ; j++)
556 spc[j] = ' ';
557 spc[config->profile_depth] = '\0';
559 mp_msg(MSGT_CFGPARSER, MSGL_INFO, "%s%s=%s\n", spc,
560 p->opts[2*i], p->opts[2*i+1]);
563 if(config->profile_depth < MAX_PROFILE_DEPTH &&
564 !strcmp(p->opts[2*i],"profile")) {
565 char* e,*list = p->opts[2*i+1];
566 while((e = strchr(list,','))) {
567 int l = e-list;
568 char tmp[l+1];
569 if(!l) continue;
570 memcpy(tmp,list,l);
571 tmp[l] = '\0';
572 show_profile(opt,name,tmp);
573 list = e+1;
575 if(list[0] != '\0')
576 show_profile(opt,name,list);
579 config->profile_depth--;
580 if(!config->profile_depth) mp_msg(MSGT_CFGPARSER, MSGL_INFO, "\n");
581 return M_OPT_EXIT-1;
584 static int
585 list_options(m_option_t *opt, char* name, char *param) {
586 m_config_t* config = opt->priv;
587 m_config_print_option_list(config);
588 return M_OPT_EXIT;