Correct dumping hint (vc dummy faster than null).
[mplayer/greg.git] / cfgparser.c
blobe9f71a4fa2d10501b8b77b919683c483bdb0042b
1 /*
2 * command line and config file parser
3 * by Szabolcs Berecz <szabi@inf.elte.hu>
4 * (C) 2001
6 * subconfig support by alex
7 */
9 //#define DEBUG
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <ctype.h>
14 #include <unistd.h>
15 #include <fcntl.h>
16 #include <string.h>
17 #include <errno.h>
18 #include <math.h>
20 #include "config.h"
22 #ifndef NEW_CONFIG
24 #ifdef USE_SETLOCALE
25 #include <locale.h>
26 #endif
28 #include "mp_msg.h"
30 #define COMMAND_LINE 0
31 #define CONFIG_FILE 1
33 #define LIST_SEPARATOR ','
35 #define CONFIG_GLOBAL (1<<0)
36 #define CONFIG_RUNNING (1<<1)
38 #define SET_GLOBAL(c) (c->flags |= CONFIG_GLOBAL)
39 #ifdef GLOBAL_OPTIONS_ONLY
40 #define UNSET_GLOBAL(c)
41 #else
42 #define UNSET_GLOBAL(c) (c->flags &= (!CONFIG_GLOBAL))
43 #endif
44 #define IS_GLOBAL(c) (c->flags & CONFIG_GLOBAL)
45 #define SET_RUNNING(c) (c->flags |= CONFIG_RUNNING)
46 #define IS_RUNNING(c) (c->flags & CONFIG_RUNNING)
48 #define MAX_RECURSION_DEPTH 8
50 #ifdef MP_DEBUG
51 #include <assert.h>
52 #endif
54 #include "cfgparser.h"
55 #include "playtree.h"
57 static void m_config_list_options(m_config_t *config);
58 static void m_config_error(int err,char* opt,char* val);
60 static void
61 m_config_save_option(m_config_t* config, config_t* conf,char* opt, char *param) {
62 config_save_t* save;
63 int sl=0;
65 #ifdef MP_DEBUG
66 assert(config != NULL);
67 assert(config->cs_level >= 0);
68 assert(conf != NULL);
69 assert(opt != NULL);
70 assert( ! (conf->flags & CONF_NOSAVE));
71 #endif
73 switch(conf->type) {
74 case CONF_TYPE_PRINT :
75 case CONF_TYPE_SUBCONFIG :
76 return;
77 default :
81 mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Saving option %s\n",opt);
83 save = config->config_stack[config->cs_level];
85 if(save) {
86 for(sl = 0; save[sl].opt != NULL; sl++){
87 // Check to not save the same arg two times
88 if(save[sl].opt == conf && (save[sl].opt_name == NULL || strcasecmp(save[sl].opt_name,opt) == 0))
89 break;
91 if(save[sl].opt)
92 return;
95 save = (config_save_t*)realloc(save,(sl+2)*sizeof(config_save_t));
96 if(save == NULL) {
97 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Can't allocate %d bytes of memory : %s\n",(sl+2)*sizeof(config_save_t),strerror(errno));
98 return;
100 memset(&save[sl],0,2*sizeof(config_save_t));
101 save[sl].opt = conf;
103 switch(conf->type) {
104 case CONF_TYPE_FLAG :
105 case CONF_TYPE_INT :
106 save[sl].param.as_int = *((int*)conf->p);
107 break;
108 case CONF_TYPE_FLOAT :
109 save[sl].param.as_float = *((float*)conf->p);
110 break;
111 case CONF_TYPE_STRING :
112 save[sl].param.as_pointer = *((char**)conf->p);
113 break;
114 case CONF_TYPE_FUNC_FULL :
115 if(strcasecmp(conf->name,opt) != 0) save->opt_name = strdup(opt);
116 case CONF_TYPE_FUNC_PARAM :
117 if(param)
118 save->param.as_pointer = strdup(param);
119 case CONF_TYPE_FUNC :
120 break;
121 case CONF_TYPE_STRING_LIST :
122 save[sl].param.as_pointer = *((char***)conf->p);
123 break;
124 case CONF_TYPE_POSITION :
125 save[sl].param.as_off_t = *((off_t*)conf->p);
126 break;
127 default :
128 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"Should never append in m_config_save_option : conf->type=%d\n",conf->type);
131 config->config_stack[config->cs_level] = save;
134 static int
135 m_config_revert_option(m_config_t* config, config_save_t* save) {
136 char* arg = NULL;
137 config_save_t* iter=NULL;
138 int i=-1;
140 #ifdef MP_DEBUG
141 assert(config != NULL);
142 assert(config->cs_level >= 0);
143 assert(save != NULL);
144 #endif
147 arg = save->opt_name ? save->opt_name : save->opt->name;
148 mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Reverting option %s\n",arg);
150 if(save->opt->default_func)
151 save->opt->default_func(save->opt,arg);
153 switch(save->opt->type) {
154 case CONF_TYPE_FLAG :
155 case CONF_TYPE_INT :
156 *((int*)save->opt->p) = save->param.as_int;
157 break;
158 case CONF_TYPE_FLOAT :
159 *((float*)save->opt->p) = save->param.as_float;
160 break;
161 case CONF_TYPE_STRING :
162 *((char**)save->opt->p) = save->param.as_pointer;
163 break;
164 case CONF_TYPE_STRING_LIST :
165 *((char***)save->opt->p) = save->param.as_pointer;
166 break;
167 case CONF_TYPE_FUNC_PARAM :
168 case CONF_TYPE_FUNC_FULL :
169 case CONF_TYPE_FUNC :
170 if(config->cs_level > 0) {
171 for(i = config->cs_level - 1 ; i >= 0 ; i--){
172 if(config->config_stack[i] == NULL) continue;
173 for(iter = config->config_stack[i]; iter != NULL && iter->opt != NULL ; iter++) {
174 if(iter->opt == save->opt &&
175 ((save->param.as_pointer == NULL || iter->param.as_pointer == NULL) || strcasecmp(save->param.as_pointer,iter->param.as_pointer) == 0) &&
176 (save->opt_name == NULL ||
177 (iter->opt_name && strcasecmp(save->opt_name,iter->opt_name)))) break;
181 free(save->param.as_pointer);
182 if(save->opt_name) free(save->opt_name);
183 save->opt_name = save->param.as_pointer = NULL;
184 if(i < 0) break;
185 arg = iter->opt_name ? iter->opt_name : iter->opt->name;
186 switch(iter->opt->type) {
187 case CONF_TYPE_FUNC :
188 if ((((cfg_func_t) iter->opt->p)(iter->opt)) < 0)
189 return -1;
190 break;
191 case CONF_TYPE_FUNC_PARAM :
192 if (iter->param.as_pointer == NULL) {
193 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"We lost param for option %s?\n",iter->opt->name);
194 return -1;
196 if ((((cfg_func_param_t) iter->opt->p)(iter->opt, (char*)iter->param.as_pointer)) < 0)
197 return -1;
198 break;
199 case CONF_TYPE_FUNC_FULL :
200 if (iter->param.as_pointer != NULL && ((char*)iter->param.as_pointer)[0]=='-'){
201 if( ((cfg_func_arg_param_t) iter->opt->p)(iter->opt, arg, NULL) < 0)
202 return -1;
203 }else {
204 if (((cfg_func_arg_param_t) save->opt->p)(iter->opt, arg, (char*)iter->param.as_pointer) < 0)
205 return -1;
208 break;
210 break;
211 case CONF_TYPE_POSITION :
212 *((off_t*)save->opt->p) = save->param.as_off_t;
213 break;
214 default :
215 mp_msg(MSGT_CFGPARSER,MSGL_WARN,"Why do we reverse this : name=%s type=%d ?\n",save->opt->name,save->opt->type);
218 return 1;
221 void
222 m_config_push(m_config_t* config) {
224 #ifdef MP_DEBUG
225 assert(config != NULL);
226 assert(config->cs_level >= 0);
227 #endif
229 config->cs_level++;
230 config->config_stack = (config_save_t**)realloc(config->config_stack ,sizeof(config_save_t*)*(config->cs_level+1));
231 if(config->config_stack == NULL) {
232 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));
233 config->cs_level = -1;
234 return;
236 config->config_stack[config->cs_level] = NULL;
237 mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Config pushed level=%d\n",config->cs_level);
241 m_config_pop(m_config_t* config) {
242 int i,ret= 1;
243 config_save_t* cs;
245 #ifdef MP_DEBUG
246 assert(config != NULL);
247 //assert(config->cs_level > 0);
248 #endif
250 if(config->config_stack[config->cs_level] != NULL) {
251 cs = config->config_stack[config->cs_level];
252 for(i=0; cs[i].opt != NULL ; i++ ) {
253 if (m_config_revert_option(config,&cs[i]) < 0)
254 ret = -1;
256 free(config->config_stack[config->cs_level]);
258 config->config_stack = (config_save_t**)realloc(config->config_stack ,sizeof(config_save_t*)*config->cs_level);
259 config->cs_level--;
260 if(config->cs_level > 0 && config->config_stack == NULL) {
261 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Can't allocate %d bytes of memory : %s\n",sizeof(config_save_t*)*config->cs_level,strerror(errno));
262 config->cs_level = -1;
263 return -1;
265 mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Config poped level=%d\n",config->cs_level);
266 return ret;
269 m_config_t*
270 m_config_new(play_tree_t* pt) {
271 m_config_t* config;
273 #ifdef MP_DEBUG
274 assert(pt != NULL);
275 #endif
277 config = (m_config_t*)calloc(1,sizeof(m_config_t));
278 if(config == NULL) {
279 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Can't allocate %d bytes of memory : %s\n",sizeof(m_config_t),strerror(errno));
280 return NULL;
282 config->config_stack = (config_save_t**)calloc(1,sizeof(config_save_t*));
283 if(config->config_stack == NULL) {
284 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Can't allocate %d bytes of memory : %s\n",sizeof(config_save_t*),strerror(errno));
285 free(config);
286 return NULL;
288 SET_GLOBAL(config); // We always start with global options
289 config->pt = pt;
290 return config;
293 void
294 m_config_free(m_config_t* config) {
296 #ifdef MP_DEBUG
297 assert(config != NULL);
298 #endif
300 free(config->opt_list);
301 free(config->config_stack);
302 free(config);
306 static int init_conf(m_config_t *config, int mode)
308 #ifdef MP_DEBUG
309 assert(config != NULL);
310 assert(config->pt != NULL);
311 assert(config->last_entry == NULL || config->last_entry->parent == config->pt);
313 if (mode != COMMAND_LINE && mode != CONFIG_FILE) {
314 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "init_conf: wrong mode!\n");
315 return -1;
317 #endif
318 config->parser_mode = mode;
319 return 1;
322 static int config_is_entry_option(m_config_t *config, char *opt, char *param) {
323 play_tree_t* entry = NULL;
325 #ifdef MP_DEBUG
326 assert(config->pt != NULL);
327 #endif
329 if(strcasecmp(opt,"playlist") == 0) { // We handle playlist here
330 if(!param)
331 return ERR_MISSING_PARAM;
332 entry = parse_playlist_file(param);
333 if(!entry) {
334 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Playlist parsing failed: %s\n",param);
335 return 1;
339 if(! IS_RUNNING(config)) {
340 if(strcasecmp(opt,"vcd") == 0) {
341 char* s;
342 if(!param)
343 return ERR_MISSING_PARAM;
344 s = (char*)malloc((strlen(param) + 6 + 1)*sizeof(char));
345 sprintf(s,"vcd://%s",param);
346 entry = play_tree_new();
347 play_tree_add_file(entry,s);
348 free(s);
349 } else if(strcasecmp(opt,"dvd") == 0) {
350 char* s;
351 if(!param)
352 return ERR_MISSING_PARAM;
353 s = (char*)malloc((strlen(param) + 6 + 1)*sizeof(char));
354 sprintf(s,"dvd://%s",param);
355 entry = play_tree_new();
356 play_tree_add_file(entry,s);
357 free(s);
358 } else if(strcasecmp(opt,"tv") == 0) {
359 char *s,*pr,*prs;
360 char *ps,*pe,*channel=NULL;
361 char *as;
362 int on=0;
363 if(!param)
364 return ERR_MISSING_PARAM;
365 ps = param;
366 pe = strchr(param,':');
367 pr = prs = (char*)malloc((strlen(param)+1)*sizeof(char));
368 pr[0] = '\0';
369 while(ps) {
370 if(!pe)
371 pe = ps + strlen(ps);
373 as = strchr(ps,'=');
374 if(as && as[1] != '\0' && pe-as > 0)
375 as++;
376 else
377 as = NULL;
378 if( !as && pe-ps == 2 && strncasecmp("on",ps,2) == 0 )
379 on = 1;
380 else if(as && as-ps == 8 && strncasecmp("channel",ps,6) == 0 && pe-as > 0) {
381 channel = (char*)realloc(channel,(pe-as+1)*sizeof(char));
382 strncpy(channel,as,pe-as);
383 channel[pe-as] = '\0';
384 } else if(pe-ps > 0) {
385 if(prs != pr) {
386 prs[0] = ':';
387 prs++;
389 strncpy(prs,ps,pe-ps);
390 prs += pe-ps;
391 prs[0] = '\0';
394 if(pe[0] != '\0') {
395 ps = pe+1;
396 pe = strchr(ps,':');
397 } else
398 ps = NULL;
401 if(on) {
402 int l=5;
404 if(channel)
405 l += strlen(channel);
406 s = (char*) malloc((l+1)*sizeof(char));
407 if(channel)
408 sprintf(s,"tv://%s",channel);
409 else
410 sprintf(s,"tv://");
411 entry = play_tree_new();
412 play_tree_add_file(entry,s);
413 if(strlen(pr) > 0)
414 play_tree_set_param(entry,"tv",pr);
415 free(s);
417 free(pr);
418 if(channel)
419 free(channel);
424 if(entry) {
425 if(config->last_entry)
426 play_tree_append_entry(config->last_entry,entry);
427 else
428 play_tree_set_child(config->pt,entry);
429 config->last_entry = entry;
430 if(config->parser_mode == COMMAND_LINE)
431 UNSET_GLOBAL(config);
432 return 1;
433 } else
434 return 0;
439 static int config_read_option(m_config_t *config,config_t** conf_list, char *opt, char *param)
441 int i=0,nconf = 0;
442 long tmp_int;
443 off_t tmp_off;
444 double tmp_float;
445 int dummy;
446 int ret = -1;
447 char *endptr;
448 config_t* conf=NULL;
450 #ifdef MP_DEBUG
451 assert(config != NULL);
452 assert(conf_list != NULL);
453 assert(opt != NULL);
454 #endif
456 mp_msg(MSGT_CFGPARSER, MSGL_DBG3, "read_option: conf=%p opt='%s' param='%s'\n",
457 conf, opt, param);
458 for(nconf = 0 ; conf_list[nconf] != NULL; nconf++) {
459 conf = conf_list[nconf];
460 for (i = 0; conf[i].name != NULL; i++) {
461 int namelength;
462 /* allow 'aa*' in config.name */
463 namelength=strlen(conf[i].name);
464 if ( (conf[i].name[namelength-1]=='*') &&
465 !memcmp(opt, conf[i].name, namelength-1))
466 goto option_found;
467 if (!strcasecmp(opt, conf[i].name))
468 goto option_found;
471 if (config->parser_mode == CONFIG_FILE)
472 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "invalid option: %s\n",opt);
473 ret = ERR_NOT_AN_OPTION;
474 goto out;
475 option_found :
476 mp_msg(MSGT_CFGPARSER, MSGL_DBG3, "read_option: name='%s' p=%p type=%d\n",
477 conf[i].name, conf[i].p, conf[i].type);
479 if (conf[i].flags & CONF_NOCFG && config->parser_mode == CONFIG_FILE) {
480 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "this option can only be used on command line:\n", opt);
481 ret = ERR_NOT_AN_OPTION;
482 goto out;
484 if (conf[i].flags & CONF_NOCMD && config->parser_mode == COMMAND_LINE) {
485 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "this option can only be used in config file:\n", opt);
486 ret = ERR_NOT_AN_OPTION;
487 goto out;
489 ret = config_is_entry_option(config,opt,param);
490 if(ret != 0)
491 return ret;
492 else
493 ret = -1;
494 if(! IS_RUNNING(config) && ! IS_GLOBAL(config) &&
495 ! (conf[i].flags & CONF_GLOBAL) && conf[i].type != CONF_TYPE_SUBCONFIG )
496 m_config_push(config);
497 if( !(conf[i].flags & CONF_NOSAVE) && ! (conf[i].flags & CONF_GLOBAL) )
498 m_config_save_option(config,&conf[i],opt,param);
499 switch (conf[i].type) {
500 case CONF_TYPE_FLAG:
501 /* flags need a parameter in config file */
502 if (config->parser_mode == CONFIG_FILE) {
503 if (!strcasecmp(param, "yes") || /* any other language? */
504 !strcasecmp(param, "ja") ||
505 !strcasecmp(param, "si") ||
506 !strcasecmp(param, "igen") ||
507 !strcasecmp(param, "y") ||
508 !strcasecmp(param, "j") ||
509 !strcasecmp(param, "i") ||
510 !strcmp(param, "1"))
511 *((int *) conf[i].p) = conf[i].max;
512 else if (!strcasecmp(param, "no") ||
513 !strcasecmp(param, "nein") ||
514 !strcasecmp(param, "nicht") ||
515 !strcasecmp(param, "nem") ||
516 !strcasecmp(param, "n") ||
517 !strcmp(param, "0"))
518 *((int *) conf[i].p) = conf[i].min;
519 else {
520 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "invalid parameter for flag: %s\n", param);
521 ret = ERR_OUT_OF_RANGE;
522 goto out;
524 ret = 1;
525 } else { /* parser_mode == COMMAND_LINE */
526 *((int *) conf[i].p) = conf[i].max;
527 ret = 0;
529 break;
530 case CONF_TYPE_INT:
531 if (param == NULL)
532 goto err_missing_param;
534 tmp_int = strtol(param, &endptr, 0);
535 if (*endptr) {
536 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "parameter must be an integer: %s\n", param);
537 ret = ERR_OUT_OF_RANGE;
538 goto out;
541 if (conf[i].flags & CONF_MIN)
542 if (tmp_int < conf[i].min) {
543 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "parameter must be >= %d: %s\n", (int) conf[i].min, param);
544 ret = ERR_OUT_OF_RANGE;
545 goto out;
548 if (conf[i].flags & CONF_MAX)
549 if (tmp_int > conf[i].max) {
550 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "parameter must be <= %d: %s\n", (int) conf[i].max, param);
551 ret = ERR_OUT_OF_RANGE;
552 goto out;
555 *((int *) conf[i].p) = tmp_int;
556 ret = 1;
557 break;
558 case CONF_TYPE_FLOAT:
559 if (param == NULL)
560 goto err_missing_param;
561 /* <olo@altkom.com.pl> Use portable C locale for parsing floats: */
562 #ifdef USE_SETLOCALE
563 setlocale(LC_NUMERIC, "C");
564 #endif
565 tmp_float = strtod(param, &endptr);
567 switch(*endptr) {
568 case ':':
569 case '/':
570 tmp_float /= strtod(endptr+1, &endptr);
571 default:
572 break;
574 #ifdef USE_SETLOCALE
575 setlocale(LC_NUMERIC, "");
576 #endif
578 if (*endptr) {
579 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "parameter must be a floating point number"
580 " or a ratio (numerator[:/]denominator): %s\n", param);
581 ret = ERR_MISSING_PARAM;
582 goto out;
585 if (conf[i].flags & CONF_MIN)
586 if (tmp_float < conf[i].min) {
587 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "parameter must be >= %f: %s\n", conf[i].min, param);
588 ret = ERR_OUT_OF_RANGE;
589 goto out;
592 if (conf[i].flags & CONF_MAX)
593 if (tmp_float > conf[i].max) {
594 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "parameter must be <= %f: %s\n", conf[i].max, param);
595 ret = ERR_OUT_OF_RANGE;
596 goto out;
599 *((float *) conf[i].p) = tmp_float;
600 ret = 1;
601 break;
602 case CONF_TYPE_STRING:
603 if (param == NULL)
604 goto err_missing_param;
606 if (conf[i].flags & CONF_MIN)
607 if (strlen(param) < conf[i].min) {
608 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "parameter must be >= %d chars: %s\n",
609 (int) conf[i].min, param);
610 ret = ERR_OUT_OF_RANGE;
611 goto out;
614 if (conf[i].flags & CONF_MAX)
615 if (strlen(param) > conf[i].max) {
616 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "parameter must be <= %d chars: %s\n",
617 (int) conf[i].max, param);
618 ret = ERR_OUT_OF_RANGE;
619 goto out;
621 *((char **) conf[i].p) = strdup(param);
622 ret = 1;
623 break;
624 case CONF_TYPE_STRING_LIST:
625 if (param == NULL)
626 goto err_missing_param;
627 else {
628 int n = 0,len;
629 char *ptr = param, *last_ptr, **res;
631 while(ptr[0] != '\0') {
632 last_ptr = ptr;
633 ptr = strchr(ptr,LIST_SEPARATOR);
634 if(!ptr) {
635 // if(strlen(last_ptr) > 0)
636 n++;
637 break;
639 ptr++;
640 n++;
642 if(n == 0)
643 goto err_missing_param;
644 else if( (conf[i].flags & CONF_MIN && n < conf[i].min) ||
645 (conf[i].flags & CONF_MAX && n > conf[i].max) ) {
646 ret = ERR_OUT_OF_RANGE;
647 goto out;
649 ret = 1;
650 res = malloc((n+2)*sizeof(char*));
651 ptr = param;
652 n = 0;
653 // while(ptr[0] != '\0') {
654 while(1) {
655 last_ptr = ptr;
656 ptr = strchr(ptr,LIST_SEPARATOR);
657 if(!ptr) {
658 //if(strlen(last_ptr) > 0)
660 res[n] = strdup(last_ptr);
661 n++;
663 break;
665 len = ptr - last_ptr;
666 res[n] = (char*)malloc(len + 1);
667 if(len) strncpy(res[n],last_ptr,len);
668 res[n][len] = '\0';
669 ptr++;
670 n++;
672 res[n] = NULL;
673 *((char ***) conf[i].p) = res;
675 break;
676 case CONF_TYPE_FUNC_PARAM:
677 if (param == NULL)
678 goto err_missing_param;
679 if ((((cfg_func_param_t) conf[i].p)(conf + i, param)) < 0) {
680 ret = ERR_FUNC_ERR;
681 goto out;
683 ret = 1;
684 break;
685 case CONF_TYPE_FUNC_FULL:
686 if (param!=NULL && param[0]=='-'){
687 ret=((cfg_func_arg_param_t) conf[i].p)(conf + i, opt, NULL);
688 if (ret>=0) ret=0;
689 /* if we return >=0: param is processed again (if there is any) */
690 }else{
691 ret=((cfg_func_arg_param_t) conf[i].p)(conf + i, opt, param);
692 /* if we return 0: need no param, precess it again */
693 /* if we return 1: accepted param */
695 break;
696 case CONF_TYPE_FUNC:
697 if ((((cfg_func_t) conf[i].p)(conf + i)) < 0) {
698 ret = ERR_FUNC_ERR;
699 goto out;
701 ret = 0;
702 break;
703 case CONF_TYPE_SUBCONFIG:
705 char *subparam;
706 char *subopt;
707 int subconf_optnr;
708 config_t *subconf;
709 config_t *sublist[] = { NULL , NULL };
710 char *token;
711 char *p;
713 if (param == NULL)
714 goto err_missing_param;
716 subparam = malloc(strlen(param)+1);
717 subopt = malloc(strlen(param)+1);
718 p = strdup(param); // In case that param is a static string (cf man strtok)
720 subconf = conf[i].p;
721 sublist[0] = subconf;
722 for (subconf_optnr = 0; subconf[subconf_optnr].name != NULL; subconf_optnr++)
723 /* NOTHING */;
724 config->sub_conf = opt;
725 token = strtok(p, (char *)&(":"));
726 while(token)
728 int sscanf_ret;
729 /* clear out */
730 subopt[0] = subparam[0] = 0;
732 sscanf_ret = sscanf(token, "%[^=]=%[^:]", subopt, subparam);
734 mp_msg(MSGT_CFGPARSER, MSGL_DBG3, "token: '%s', i=%d, subopt='%s', subparam='%s' (ret: %d)\n", token, i, subopt, subparam, sscanf_ret);
735 switch(sscanf_ret)
737 case 1:
738 subparam[0] = 0;
739 case 2:
740 if ((ret = config_read_option(config,sublist, subopt, subparam)) < 0)
742 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Subconfig parsing returned error: %d in token: %s\n",
743 ret, token);
744 goto out;
746 break;
747 default:
748 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Invalid subconfig argument! ('%s')\n", token);
749 ret = ERR_NOT_AN_OPTION;
750 goto out;
752 token = strtok(NULL, (char *)&(":"));
754 config->sub_conf = NULL;
755 free(subparam);
756 free(subopt);
757 free(p);
758 ret = 1;
759 break;
761 case CONF_TYPE_PRINT:
762 mp_msg(MSGT_CFGPARSER, MSGL_INFO, "%s", (char *) conf[i].p);
763 exit(1);
764 case CONF_TYPE_POSITION:
765 if (param == NULL)
766 goto err_missing_param;
768 if (sscanf(param, sizeof(off_t) == sizeof(int) ?
769 "%d%c" : "%lld%c", &tmp_off, (char *)&dummy) != 1) {
770 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "parameter must be an integer: %s\n", param);
771 ret = ERR_OUT_OF_RANGE;
772 goto out;
775 if (conf[i].flags & CONF_MIN)
776 if (tmp_off < conf[i].min) {
777 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
778 (sizeof(off_t) == sizeof(int) ?
779 "parameter must be >= %d: %s\n" :
780 "parameter must be >= %lld: %s\n"),
781 (off_t) conf[i].min, param);
782 ret = ERR_OUT_OF_RANGE;
783 goto out;
786 if (conf[i].flags & CONF_MAX)
787 if (tmp_off > conf[i].max) {
788 mp_msg(MSGT_CFGPARSER, MSGL_ERR,
789 (sizeof(off_t) == sizeof(int) ?
790 "parameter must be <= %d: %s\n" :
791 "parameter must be <= %lld: %s\n"),
792 (off_t) conf[i].max, param);
793 ret = ERR_OUT_OF_RANGE;
794 goto out;
797 *((off_t *) conf[i].p) = tmp_off;
798 ret = 1;
799 break;
800 default:
801 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Unknown config type specified in conf-mplayer.h!\n");
802 break;
804 out:
805 if(ret >= 0 && ! IS_RUNNING(config) && ! IS_GLOBAL(config) && ! (conf[i].flags & CONF_GLOBAL) && conf[i].type != CONF_TYPE_SUBCONFIG ) {
806 play_tree_t* dest = config->last_entry ? config->last_entry : config->last_parent;
807 char* o;
808 #ifdef MP_DEBUG
809 assert(dest != NULL);
810 #endif
811 if(config->sub_conf) {
812 o = (char*)malloc((strlen(config->sub_conf) + 1 + strlen(opt) + 1)*sizeof(char));
813 sprintf(o,"%s:%s",config->sub_conf,opt);
814 } else
815 o =strdup(opt);
817 if(ret == 0)
818 play_tree_set_param(dest,o,NULL);
819 else if(ret > 0)
820 play_tree_set_param(dest,o,param);
821 free(o);
822 m_config_pop(config);
824 return ret;
825 err_missing_param:
826 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "missing parameter for option: %s\n", opt);
827 ret = ERR_MISSING_PARAM;
828 goto out;
831 int m_config_set_option(m_config_t *config,char *opt, char *param) {
832 char *e;
833 #ifdef MP_DEBUG
834 assert(config != NULL);
835 assert(config->opt_list != NULL);
836 assert(opt != NULL);
837 #endif
838 mp_msg(MSGT_CFGPARSER, MSGL_DBG2, "Setting option %s=%s\n",opt,param);
839 e = strchr(opt,':');
840 if(e && e[1] != '\0') {
841 int ret;
842 config_t* opt_list[] = { NULL, NULL };
843 char* s = (char*)malloc((e-opt+1)*sizeof(char));
844 strncpy(s,opt,e-opt);
845 s[e-opt] = '\0';
846 opt_list[0] = m_config_get_option_ptr(config,s);
847 if(!opt_list[0]) {
848 mp_msg(MSGT_CFGPARSER, MSGL_ERR,"m_config_set_option %s=%s : no %s subconfig\n",opt,param,s);
849 free(s);
850 return ERR_NOT_AN_OPTION;
852 e++;
853 s = (char*)realloc(s,strlen(e) + 1);
854 strcpy(s,e);
855 ret = config_read_option(config,opt_list,s,param);
856 free(s);
857 return ret;
860 return config_read_option(config,config->opt_list,opt,param);
863 int m_config_parse_config_file(m_config_t *config, char *conffile)
865 #define PRINT_LINENUM mp_msg(MSGT_CFGPARSER,MSGL_INFO,"%s(%d): ", conffile, line_num)
866 #define MAX_LINE_LEN 10000
867 #define MAX_OPT_LEN 1000
868 #define MAX_PARAM_LEN 1000
869 FILE *fp;
870 char *line;
871 char opt[MAX_OPT_LEN + 1];
872 char param[MAX_PARAM_LEN + 1];
873 char c; /* for the "" and '' check */
874 int tmp;
875 int line_num = 0;
876 int line_pos; /* line pos */
877 int opt_pos; /* opt pos */
878 int param_pos; /* param pos */
879 int ret = 1;
880 int errors = 0;
882 #ifdef MP_DEBUG
883 assert(config != NULL);
884 // assert(conf_list != NULL);
885 #endif
886 if (++config->recursion_depth > 1)
887 mp_msg(MSGT_CFGPARSER,MSGL_INFO,"Reading config file: %s", conffile);
889 if (config->recursion_depth > MAX_RECURSION_DEPTH) {
890 mp_msg(MSGT_CFGPARSER,MSGL_ERR,": too deep 'include'. check your configfiles\n");
891 ret = -1;
892 goto out;
895 if (init_conf(config, CONFIG_FILE) == -1) {
896 ret = -1;
897 goto out;
900 if ((line = (char *) malloc(MAX_LINE_LEN + 1)) == NULL) {
901 mp_msg(MSGT_CFGPARSER,MSGL_FATAL,"\ncan't get memory for 'line': %s", strerror(errno));
902 ret = -1;
903 goto out;
906 if ((fp = fopen(conffile, "r")) == NULL) {
907 if (config->recursion_depth > 1)
908 mp_msg(MSGT_CFGPARSER,MSGL_ERR,": %s\n", strerror(errno));
909 free(line);
910 ret = 0;
911 goto out;
913 if (config->recursion_depth > 1)
914 mp_msg(MSGT_CFGPARSER,MSGL_INFO,"\n");
916 while (fgets(line, MAX_LINE_LEN, fp)) {
917 if (errors >= 16) {
918 mp_msg(MSGT_CFGPARSER,MSGL_FATAL,"too many errors\n");
919 goto out;
922 line_num++;
923 line_pos = 0;
925 /* skip whitespaces */
926 while (isspace(line[line_pos]))
927 ++line_pos;
929 /* EOL / comment */
930 if (line[line_pos] == '\0' || line[line_pos] == '#')
931 continue;
933 /* read option. */
934 for (opt_pos = 0; isprint(line[line_pos]) &&
935 line[line_pos] != ' ' &&
936 line[line_pos] != '#' &&
937 line[line_pos] != '='; /* NOTHING */) {
938 opt[opt_pos++] = line[line_pos++];
939 if (opt_pos >= MAX_OPT_LEN) {
940 PRINT_LINENUM;
941 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"too long option\n");
942 errors++;
943 ret = -1;
944 goto nextline;
947 if (opt_pos == 0) {
948 PRINT_LINENUM;
949 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"parse error\n");
950 ret = -1;
951 errors++;
952 continue;
954 opt[opt_pos] = '\0';
956 #ifdef MP_DEBUG
957 PRINT_LINENUM;
958 mp_msg(MSGT_CFGPARSER,MSGL_INFO,"option: %s\n", opt);
959 #endif
961 /* skip whitespaces */
962 while (isspace(line[line_pos]))
963 ++line_pos;
965 /* check '=' */
966 if (line[line_pos++] != '=') {
967 PRINT_LINENUM;
968 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"option without parameter\n");
969 ret = -1;
970 errors++;
971 continue;
974 /* whitespaces... */
975 while (isspace(line[line_pos]))
976 ++line_pos;
978 /* read the parameter */
979 if (line[line_pos] == '"' || line[line_pos] == '\'') {
980 c = line[line_pos];
981 ++line_pos;
982 for (param_pos = 0; line[line_pos] != c; /* NOTHING */) {
983 param[param_pos++] = line[line_pos++];
984 if (param_pos >= MAX_PARAM_LEN) {
985 PRINT_LINENUM;
986 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"too long parameter\n");
987 ret = -1;
988 errors++;
989 goto nextline;
992 line_pos++; /* skip the closing " or ' */
993 } else {
994 for (param_pos = 0; isprint(line[line_pos]) && !isspace(line[line_pos])
995 && line[line_pos] != '#'; /* NOTHING */) {
996 param[param_pos++] = line[line_pos++];
997 if (param_pos >= MAX_PARAM_LEN) {
998 PRINT_LINENUM;
999 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"too long parameter\n");
1000 ret = -1;
1001 errors++;
1002 goto nextline;
1006 param[param_pos] = '\0';
1008 /* did we read a parameter? */
1009 if (param_pos == 0) {
1010 PRINT_LINENUM;
1011 mp_msg(MSGT_CFGPARSER,MSGL_ERR,"option without parameter\n");
1012 ret = -1;
1013 errors++;
1014 continue;
1017 #ifdef MP_DEBUG
1018 PRINT_LINENUM;
1019 mp_msg(MSGT_CFGPARSER,MSGL_INFO,"parameter: %s\n", param);
1020 #endif
1022 /* now, check if we have some more chars on the line */
1023 /* whitespace... */
1024 while (isspace(line[line_pos]))
1025 ++line_pos;
1027 /* EOL / comment */
1028 if (line[line_pos] != '\0' && line[line_pos] != '#') {
1029 PRINT_LINENUM;
1030 mp_msg(MSGT_CFGPARSER,MSGL_WARN,"extra characters on line: %s\n", line+line_pos);
1031 ret = -1;
1034 tmp = m_config_set_option(config, opt, param);
1035 switch (tmp) {
1036 case ERR_NOT_AN_OPTION:
1037 case ERR_MISSING_PARAM:
1038 case ERR_OUT_OF_RANGE:
1039 case ERR_FUNC_ERR:
1040 PRINT_LINENUM;
1041 mp_msg(MSGT_CFGPARSER,MSGL_INFO,"%s\n", opt);
1042 ret = -1;
1043 errors++;
1044 continue;
1045 /* break */
1047 nextline:
1051 free(line);
1052 fclose(fp);
1053 out:
1054 --config->recursion_depth;
1055 return ret;
1058 int m_config_parse_command_line(m_config_t *config, int argc, char **argv)
1060 int i;
1061 int tmp;
1062 char *opt;
1063 int no_more_opts = 0;
1065 #ifdef MP_DEBUG
1066 assert(config != NULL);
1067 assert(config->pt != NULL);
1068 assert(argv != NULL);
1069 assert(argc >= 1);
1070 #endif
1072 if (init_conf(config, COMMAND_LINE) == -1)
1073 return -1;
1074 if(config->last_parent == NULL)
1075 config->last_parent = config->pt;
1076 /* in order to work recursion detection properly in parse_config_file */
1077 ++config->recursion_depth;
1079 for (i = 1; i < argc; i++) {
1080 //next:
1081 opt = argv[i];
1082 /* check for -- (no more options id.) except --help! */
1083 if ((*opt == '-') && (*(opt+1) == '-') && (*(opt+2) != 'h'))
1085 no_more_opts = 1;
1086 if (i+1 >= argc)
1088 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "You added '--' but no filenames presented!\n");
1089 goto err_out;
1091 continue;
1093 if((opt[0] == '{') && (opt[1] == '\0'))
1095 play_tree_t* entry = play_tree_new();
1096 UNSET_GLOBAL(config);
1097 if(config->last_entry == NULL) {
1098 play_tree_set_child(config->last_parent,entry);
1099 } else {
1100 play_tree_append_entry(config->last_entry,entry);
1101 config->last_entry = NULL;
1103 config->last_parent = entry;
1104 continue;
1107 if((opt[0] == '}') && (opt[1] == '\0'))
1109 if( ! config->last_parent || ! config->last_parent->parent) {
1110 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "too much }-\n");
1111 goto err_out;
1113 config->last_entry = config->last_parent;
1114 config->last_parent = config->last_entry->parent;
1115 continue;
1118 if ((no_more_opts == 0) && (*opt == '-') && (*(opt+1) != 0)) /* option */
1120 /* remove trailing '-' */
1121 opt++;
1123 mp_msg(MSGT_CFGPARSER, MSGL_DBG3, "this_opt = option: %s\n", opt);
1124 // We handle here some specific option
1125 if(strcasecmp(opt,"list-options") == 0) {
1126 m_config_list_options(config);
1127 exit(1);
1128 // Loop option when it apply to a group
1129 } else if(strcasecmp(opt,"loop") == 0 &&
1130 (! config->last_entry || config->last_entry->child) ) {
1131 int l;
1132 char* end;
1133 l = strtol(argv[i+1],&end,0);
1134 if(!end)
1135 tmp = ERR_OUT_OF_RANGE;
1136 else {
1137 play_tree_t* pt = config->last_entry ? config->last_entry : config->last_parent;
1138 l = l <= 0 ? -1 : l;
1139 pt->loop = l;
1140 tmp = 1;
1142 } else // All normal options
1143 tmp = m_config_set_option(config, opt, argv[i + 1]);
1145 switch (tmp) {
1146 case ERR_NOT_AN_OPTION:
1147 case ERR_MISSING_PARAM:
1148 case ERR_OUT_OF_RANGE:
1149 case ERR_FUNC_ERR:
1150 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Error: ");
1151 m_config_error(tmp,opt,argv[i+1]);
1152 goto err_out;
1153 default:
1154 i += tmp;
1155 break;
1158 else /* filename */
1160 play_tree_t* entry = play_tree_new();
1161 mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Adding file %s\n",argv[i]);
1162 play_tree_add_file(entry,argv[i]);
1163 if(strcasecmp(argv[i],"-") == 0)
1164 m_config_set_option(config,"use-stdin",NULL);
1165 /* opt is not an option -> treat it as a filename */
1166 UNSET_GLOBAL(config); // We start entry specific options
1167 if(config->last_entry == NULL)
1168 play_tree_set_child(config->last_parent,entry);
1169 else
1170 play_tree_append_entry(config->last_entry,entry);
1171 config->last_entry = entry;
1175 --config->recursion_depth;
1176 if(config->last_parent != config->pt)
1177 mp_msg(MSGT_CFGPARSER, MSGL_ERR,"Missing }- ?\n");
1178 config->flags &= (!CONFIG_GLOBAL);
1179 SET_RUNNING(config);
1180 return 1;
1181 #if 0
1182 err_out_mem:
1183 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "can't allocate memory for filenames (%s)\n", strerror(errno));
1184 #endif
1185 err_out:
1186 --config->recursion_depth;
1187 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "command line: %s\n", argv[i]);
1188 return -1;
1192 m_config_register_options(m_config_t *config,config_t *args) {
1193 int list_len = 0;
1194 config_t** conf_list = config->opt_list;
1196 #ifdef MP_DEBUG
1197 assert(config != NULL);
1198 assert(args != NULL);
1199 #endif
1201 if(conf_list) {
1202 for ( ; conf_list[list_len] != NULL; list_len++)
1203 /* NOTHING */;
1206 conf_list = (config_t**)realloc(conf_list,sizeof(struct conf*)*(list_len+2));
1207 if(conf_list == NULL) {
1208 mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Can't allocate %d bytes of memory : %s\n",sizeof(struct conf*)*(list_len+2),strerror(errno));
1209 return 0;
1211 conf_list[list_len] = args;
1212 conf_list[list_len+1] = NULL;
1214 config->opt_list = conf_list;
1216 return 1;
1219 config_t*
1220 m_config_get_option(m_config_t *config, char* arg) {
1221 int i,j;
1222 char *e;
1223 config_t *conf;
1224 config_t **conf_list;
1225 config_t* cl[] = { NULL, NULL };
1227 #ifdef MP_DEBUG
1228 assert(config != NULL);
1229 assert(arg != NULL);
1230 #endif
1232 e = strchr(arg,':');
1234 if(e) {
1235 char *s;
1236 s = (char*)malloc((e-arg+1)*sizeof(char));
1237 strncpy(s,arg,e-arg);
1238 s[e-arg] = '\0';
1239 cl[0] = m_config_get_option(config,s);
1240 conf_list = cl;
1241 free(s);
1242 } else
1243 conf_list = config->opt_list;
1245 if(conf_list) {
1246 for(j = 0 ; conf_list[j] != NULL ; j++) {
1247 conf = conf_list[j];
1248 for(i=0; conf[i].name != NULL; i++) {
1249 if(strcasecmp(conf[i].name,arg) == 0)
1250 return &conf[i];
1254 return NULL;
1257 void*
1258 m_config_get_option_ptr(m_config_t *config, char* arg) {
1259 config_t* conf;
1261 #ifdef MP_DEBUG
1262 assert(config != NULL);
1263 assert(arg != NULL);
1264 #endif
1266 conf = m_config_get_option(config,arg);
1267 if(!conf) return NULL;
1268 return conf->p;
1272 m_config_get_int (m_config_t *config, char* arg,int* err_ret) {
1273 int *ret;
1275 #ifdef MP_DEBUG
1276 assert(config != NULL);
1277 assert(arg != NULL);
1278 #endif
1280 ret = m_config_get_option_ptr(config,arg);
1281 if(err_ret)
1282 *err_ret = 0;
1283 if(!ret) {
1284 if(err_ret)
1285 *err_ret = 1;
1286 return -1;
1287 } else
1288 return (*ret);
1291 float
1292 m_config_get_float (m_config_t *config, char* arg,int* err_ret) {
1293 float *ret;
1295 #ifdef MP_DEBUG
1296 assert(config != NULL);
1297 assert(arg != NULL);
1298 #endif
1300 ret = m_config_get_option_ptr(config,arg);
1301 if(err_ret)
1302 *err_ret = 0;
1303 if(!ret) {
1304 if(err_ret)
1305 *err_ret = 1;
1306 return -1;
1307 } else
1308 return (*ret);
1311 #define AS_INT(c) (*((int*)c->p))
1314 m_config_set_int(m_config_t *config, char* arg,int val) {
1315 config_t* opt;
1317 #ifdef MP_DEBUG
1318 assert(config != NULL);
1319 assert(arg != NULL);
1320 #endif
1322 opt = m_config_get_option(config,arg);
1324 if(!opt || opt->type != CONF_TYPE_INT)
1325 return ERR_NOT_AN_OPTION;
1327 if(opt->flags & CONF_MIN && val < opt->min)
1328 return ERR_OUT_OF_RANGE;
1329 if(opt->flags & CONF_MAX && val > opt->max)
1330 return ERR_OUT_OF_RANGE;
1332 m_config_save_option(config,opt,arg,NULL);
1333 AS_INT(opt) = val;
1335 return 1;
1339 m_config_set_float(m_config_t *config, char* arg,float val) {
1340 config_t* opt;
1342 #ifdef MP_DEBUG
1343 assert(config != NULL);
1344 assert(arg != NULL);
1345 #endif
1347 opt = m_config_get_option(config,arg);
1349 if(!opt || opt->type != CONF_TYPE_FLOAT)
1350 return ERR_NOT_AN_OPTION;
1352 if(opt->flags & CONF_MIN && val < opt->min)
1353 return ERR_OUT_OF_RANGE;
1354 if(opt->flags & CONF_MAX && val > opt->max)
1355 return ERR_OUT_OF_RANGE;
1357 m_config_save_option(config,opt,arg,NULL);
1358 *((float*)opt->p) = val;
1360 return 1;
1365 m_config_switch_flag(m_config_t *config, char* opt) {
1366 config_t *conf;
1368 #ifdef MP_DEBUG
1369 assert(config != NULL);
1370 assert(opt != NULL);
1371 #endif
1373 conf = m_config_get_option(config,opt);
1374 if(!conf || conf->type != CONF_TYPE_FLAG) return 0;
1375 if( AS_INT(conf) == conf->min) AS_INT(conf) = conf->max;
1376 else if(AS_INT(conf) == conf->max) AS_INT(conf) = conf->min;
1377 else return 0;
1379 return 1;
1383 m_config_set_flag(m_config_t *config, char* opt, int state) {
1384 config_t *conf;
1386 #ifdef MP_DEBUG
1387 assert(config != NULL);
1388 assert(opt != NULL);
1389 #endif
1391 conf = m_config_get_option(config,opt);
1392 if(!conf || conf->type != CONF_TYPE_FLAG) return 0;
1393 if(state) AS_INT(conf) = conf->max;
1394 else AS_INT(conf) = conf->min;
1395 return 1;
1399 m_config_get_flag(m_config_t *config, char* opt) {
1400 config_t *conf;
1402 #ifdef MP_DEBUG
1403 assert(config != NULL);
1404 assert(opt != NULL);
1405 #endif
1407 conf = m_config_get_option(config,opt);
1408 if(!conf || conf->type != CONF_TYPE_FLAG) return -1;
1409 if(AS_INT(conf) == conf->max)
1410 return 1;
1411 else if(AS_INT(conf) == conf->min)
1412 return 0;
1413 else
1414 return -1;
1417 int m_config_is_option_set(m_config_t *config, char* arg) {
1418 config_t* opt;
1419 config_save_t* save;
1420 int l,i;
1422 #ifdef MP_DEBUG
1423 assert(config != NULL);
1424 assert(arg != NULL);
1425 #endif
1427 opt = m_config_get_option(config,arg);
1429 if(!opt)
1430 return -1;
1432 for(l = config->cs_level ; l >= 0 ; l--) {
1433 save = config->config_stack[l];
1434 if(!save)
1435 continue;
1436 for(i = 0 ; save[i].opt != NULL ; i++) {
1437 if(save[i].opt == opt)
1438 return 1;
1442 return 0;
1445 #undef AS_INT
1447 static void m_config_print_option_list(char* prefix, config_t* opt_list) {
1448 char* pf = NULL;
1449 config_t* opt;
1450 char min[50],max[50],*type;
1453 for(opt = opt_list ; opt->name != NULL ; opt++) {
1454 if(opt->type == CONF_TYPE_SUBCONFIG) {
1455 if(prefix) {
1456 pf = (char*)malloc(strlen(prefix) + strlen(opt->name) + 1);
1457 sprintf(pf,"%s:%s",prefix,opt->name);
1458 } else
1459 pf = strdup(opt->name);
1460 m_config_print_option_list(pf,(config_t*)opt->p);
1461 free(pf);
1462 continue;
1464 if(prefix)
1465 printf("%1.15s:",prefix);
1466 if(opt->flags & CONF_MIN)
1467 sprintf(min,"%-8.0f",opt->min);
1468 else
1469 strcpy(min,"No");
1470 if(opt->flags & CONF_MAX)
1471 sprintf(max,"%-8.0f",opt->max);
1472 else
1473 strcpy(max,"No");
1474 switch(opt->type) {
1475 case CONF_TYPE_FLAG:
1476 type = "Flag";
1477 break;
1478 case CONF_TYPE_INT:
1479 type = "Integer";
1480 break;
1481 case CONF_TYPE_FLOAT:
1482 type = "Float";
1483 break;
1484 case CONF_TYPE_STRING:
1485 type = "String";
1486 break;
1487 case CONF_TYPE_FUNC:
1488 case CONF_TYPE_FUNC_PARAM:
1489 case CONF_TYPE_FUNC_FULL:
1490 type = "Function";
1491 break;
1492 case CONF_TYPE_PRINT:
1493 type = "Print";
1494 break;
1495 case CONF_TYPE_STRING_LIST:
1496 type = "String list";
1497 break;
1498 default:
1499 type = "";
1500 break;
1502 printf("%-*.15s %-13.13s %-10.10s %-10.10s %-3.3s %-3.3s %-3.3s\n",
1503 30 - (prefix ? strlen(prefix) + 1 : 0),
1504 opt->name,
1505 type,
1506 min,
1507 max,
1508 opt->flags & CONF_GLOBAL ? "Yes" : "No",
1509 opt->flags & CONF_NOCMD ? "No" : "Yes",
1510 opt->flags & CONF_NOCFG ? "No" : "Yes");
1516 static void m_config_list_options(m_config_t *config) {
1517 int i;
1519 printf("\nName Type Min Max Glob CL Cfg\n\n");
1520 for(i = 0; config->opt_list[i] ; i++)
1521 m_config_print_option_list(NULL,config->opt_list[i]);
1526 static void m_config_error(int err,char* opt,char* val) {
1527 switch(err) {
1528 case ERR_NOT_AN_OPTION:
1529 mp_msg(MSGT_CFGPARSER, MSGL_ERR,"'%s' is not a mplayer/mencoder option\n",opt);
1530 break;
1531 case ERR_MISSING_PARAM:
1532 mp_msg(MSGT_CFGPARSER, MSGL_ERR,"option '%s' need a parameter\n",opt);
1533 break;
1534 case ERR_OUT_OF_RANGE:
1535 mp_msg(MSGT_CFGPARSER, MSGL_ERR,"value '%s' of option '%s' is out of range\n",val,opt);
1536 break;
1537 case ERR_FUNC_ERR:
1538 mp_msg(MSGT_CFGPARSER, MSGL_ERR,"while parsing option '%s'\n",opt);
1539 break;
1543 #endif