changeset 4156:22fadd4022b5

playtree-based config patch by Alban Bedel <albeu@free.fr>
author arpi
date Mon, 14 Jan 2002 23:38:49 +0000
parents 7c0b4665668d
children 9ff9f6ce6799
files Makefile cfgparser.c cfgparser.h dec_video.c mencoder.c mplayer.c playtree.c playtree.h playtreeparser.c
diffstat 9 files changed, 743 insertions(+), 211 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Mon Jan 14 23:06:43 2002 +0000
+++ b/Makefile	Mon Jan 14 23:38:49 2002 +0000
@@ -27,9 +27,9 @@
 # a BSD compatible 'install' program
 INSTALL = install
 
-SRCS_COMMON = cyuv.c adpcm.c xacodec.c cpudetect.c mp_msg.c ac3-iec958.c dec_audio.c dec_video.c msvidc.c cinepak.c fli.c qtrle.c codec-cfg.c cfgparser.c my_profile.c RTjpegN.c minilzo.c nuppelvideo.c spudec.c
+SRCS_COMMON = cyuv.c adpcm.c xacodec.c cpudetect.c mp_msg.c ac3-iec958.c dec_audio.c dec_video.c msvidc.c cinepak.c fli.c qtrle.c codec-cfg.c cfgparser.c my_profile.c RTjpegN.c minilzo.c nuppelvideo.c spudec.c playtree.c playtreeparser.c asxparser.c
 SRCS_MENCODER = mencoder.c $(SRCS_COMMON) libao2/afmt.c divx4_vbr.c libvo/aclib.c libvo/img_format.c libvo/osd.c
-SRCS_MPLAYER = mplayer.c $(SRCS_COMMON) find_sub.c subreader.c lirc_mp.c mixer.c playtree.c playtreeparser.c asxparser.c vobsub.c
+SRCS_MPLAYER = mplayer.c $(SRCS_COMMON) find_sub.c subreader.c lirc_mp.c mixer.c vobsub.c
 
 OBJS_MENCODER = $(SRCS_MENCODER:.c=.o)
 OBJS_MPLAYER = $(SRCS_MPLAYER:.c=.o)
--- a/cfgparser.c	Mon Jan 14 23:06:43 2002 +0000
+++ b/cfgparser.c	Mon Jan 14 23:38:49 2002 +0000
@@ -15,6 +15,7 @@
 #include <fcntl.h>
 #include <string.h>
 #include <errno.h>
+#include "config.h"
 
 #include "mp_msg.h"
 
@@ -23,84 +24,345 @@
 
 #define MAX_RECURSION_DEPTH	8
 
-#ifdef DEBUG
+#ifdef MP_DEBUG
 #include <assert.h>
 #endif
 
 #include "cfgparser.h"
 
-static struct config *config;
-static int nr_options;		/* number of options in 'conf' */
-static int parser_mode;		/* COMMAND_LINE or CONFIG_FILE */
-static int recursion_depth = 0;
+
+
+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_SUBCONFIG :
+    return;
+  default :
+  }
+
+  mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Saving option %s\n",opt);
+
+  save = config->config_stack[config->cs_level];
 
-static int init_conf(struct config *conf, int mode)
-{
-#ifdef DEBUG
-	assert(conf != NULL);
+  if(save) {
+    for(sl = 0; save[sl].opt != NULL; sl++){
+      // Check to not allocate 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 == NULL || save[sl].opt == NULL) {
+    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 :
+    save->param.as_pointer = strdup(param);
+  case CONF_TYPE_FUNC :    
+    break;
+  default :
+    printf("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
 
-	/* calculate the number of options in 'conf' */
-	for (nr_options = 0; conf[nr_options].name != NULL; nr_options++)
-		/* NOTHING */;
+
+  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_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 && 
+	     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) {
+	printf("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;
+  default :
+    printf("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 = conf;
-#ifdef DEBUG
+  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;
+  }
+  config->global = 1; // 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
-	parser_mode = mode;
+	config->parser_mode = mode;
+	config->global = 1;
 	return 1;
 }
 
-static int read_option(struct config *conf, int conf_optnr, char *opt, char *param)
+
+static int config_read_option(m_config_t *config,config_t** conf_list, char *opt, char *param)
 {
-	int i;
+	int i=0,nconf = 0;
 	long tmp_int;
 	double tmp_float;
 	int ret = -1;
 	char *endptr;
+	config_t* conf=NULL;
 
-	mp_msg(MSGT_CFGPARSER, MSGL_DBG3, "read_option: conf=%p optnr=%d opt='%s' param='%s'\n",
-	    conf, conf_optnr, opt, param);
-	for (i = 0; i < conf_optnr; 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))
-		        break;
-	    
-	    
-		if (!strcasecmp(opt, conf[i].name))
+#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&& 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))
+			        break;
+			if (!strcasecmp(opt, conf[i].name))
 			break;
+		}
 	}
-	if (i == conf_optnr) {
-		if (parser_mode == CONFIG_FILE)
-			mp_msg(MSGT_CFGPARSER, MSGL_ERR, "invalid option: %s\n", opt);
+	if (conf[i].name == NULL) {
+		if (config->parser_mode == CONFIG_FILE)
+			mp_msg(MSGT_CFGPARSER, MSGL_ERR, "invalid option:\n");
 		ret = ERR_NOT_AN_OPTION;
 		goto out;
 	}
 	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 && parser_mode == CONFIG_FILE) {
-		mp_msg(MSGT_CFGPARSER, MSGL_ERR, "this option can only be used on command line: %s\n", opt);
+	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;
 	}
-	if (conf[i].flags & CONF_NOCMD && parser_mode == COMMAND_LINE) {
-		mp_msg(MSGT_CFGPARSER, MSGL_ERR, "this option can only be used in config file: %s\n", opt);
-		ret = ERR_NOT_AN_OPTION;
-		goto out;
+	if(strcasecmp(opt,"playlist") == 0) { // We handle playlist here
+	  play_tree_t* list;
+#ifdef MP_DEBUG
+	  assert(config->pt != NULL);
+#endif
+	  if(!param) {
+	    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "playlist option need a filename\n");
+	    ret = ERR_MISSING_PARAM;
+	    goto out;
+	  }
+	  list = parse_playlist_file(param);
+	  if(list) {
+	    if(config->last_entry) {
+	      play_tree_append_entry(config->last_entry,list);
+	    }
+	    else
+	      play_tree_set_child(config->pt,list);
+	    config->last_entry = list;
+	  }
+	  if(config->parser_mode == COMMAND_LINE)
+	    config->global = 0;
+	  return 1;	
 	}
-
+	if(config->global == 0 && ! (conf[i].flags & CONF_GLOBAL) )
+	  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 (parser_mode == CONFIG_FILE) {
+			if (config->parser_mode == CONFIG_FILE) {
 				if (!strcasecmp(param, "yes") ||	/* any other language? */
 				    !strcasecmp(param, "ja") ||
 				    !strcasecmp(param, "si") ||
@@ -214,7 +476,7 @@
 		case CONF_TYPE_FUNC_PARAM:
 			if (param == NULL)
 				goto err_missing_param;
-			if ((((cfg_func_param_t) conf[i].p)(config + i, param)) < 0) {
+			if ((((cfg_func_param_t) conf[i].p)(conf + i, param)) < 0) {
 				ret = ERR_FUNC_ERR;
 				goto out;
 			}
@@ -222,17 +484,17 @@
 			break;
 		case CONF_TYPE_FUNC_FULL:
 			if (param!=NULL && param[0]=='-'){
-			    ret=((cfg_func_arg_param_t) conf[i].p)(config + i, opt, NULL);
+			    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)(config + i, opt, param);
+			    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)(config + i)) < 0) {
+			if ((((cfg_func_t) conf[i].p)(conf + i)) < 0) {
 				ret = ERR_FUNC_ERR;
 				goto out;
 			}
@@ -243,9 +505,9 @@
 			char *subparam;
 			char *subopt;
 			int subconf_optnr;
-			struct config *subconf;
+			config_t *subconf;
+			config_t *sublist[] = { NULL , NULL };
 			char *token;
-			int sscanf_ret;
 
 			if (param == NULL)
 				goto err_missing_param;
@@ -254,16 +516,17 @@
 			subopt = malloc(strlen(param)+1);
 
 			subconf = conf[i].p;
+			sublist[0] = subconf;
 			for (subconf_optnr = 0; subconf[subconf_optnr].name != NULL; subconf_optnr++)
 			    /* NOTHING */;
 
 			token = strtok(param, (char *)&(":"));
 			while(token)
 			{
+			    int sscanf_ret;
 			    /* clear out */
 			    subopt[0] = subparam[0] = 0;
 			    
-//			    sscanf_ret = sscanf(token, "%[^=]=%[^\n\0]", subopt, subparam);
 			    sscanf_ret = sscanf(token, "%[^=]=%s", 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);
@@ -272,7 +535,7 @@
 				case 1:
 				    subparam[0] = 0;
 				case 2:
-				    if ((ret = read_option((struct config *)subconf, subconf_optnr, subopt, subparam)) < 0)
+				    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);
@@ -300,6 +563,17 @@
 			break;
 	}
 out:
+	if(config->global == 0 && ! (conf[i].flags & CONF_GLOBAL)) {
+	  play_tree_t* dest = config->last_entry ? config->last_entry : config->last_parent;
+#ifdef MP_DEBUG
+	  assert(dest != NULL);
+#endif
+	  if(ret == 0)
+	    play_tree_set_param(dest,opt,NULL);
+	  else if(ret > 0)
+	    play_tree_set_param(dest,opt,param);
+	  m_config_pop(config); 
+	}
 	return ret;
 err_missing_param:
 	mp_msg(MSGT_CFGPARSER, MSGL_ERR, "missing parameter for option: %s\n", opt);
@@ -307,7 +581,17 @@
 	goto out;
 }
 
-int parse_config_file(struct config *conf, char *conffile)
+int m_config_set_option(m_config_t *config,char *opt, char *param) {
+
+#ifdef MP_DEBUG
+  assert(config != NULL);
+  assert(opt != NULL);
+#endif
+  mp_msg(MSGT_CFGPARSER, MSGL_DBG2, "Setting option %s=%s\n",opt,param);
+  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	printf("%s(%d): ", conffile, line_num)
 #define MAX_LINE_LEN	1000
@@ -326,19 +610,20 @@
 	int ret = 1;
 	int errors = 0;
 
-#ifdef DEBUG
-	assert(conffile != NULL);
+#ifdef MP_DEBUG
+	assert(config != NULL);
+	//	assert(conf_list != NULL);
 #endif
-	if (++recursion_depth > 1)
+	if (++config->recursion_depth > 1)
 		printf("Reading config file: %s", conffile);
 
-	if (recursion_depth > MAX_RECURSION_DEPTH) {
+	if (config->recursion_depth > MAX_RECURSION_DEPTH) {
 		printf(": too deep 'include'. check your configfiles\n");
 		ret = -1;
 		goto out;
 	}
 
-	if (init_conf(conf, CONFIG_FILE) == -1) {
+	if (init_conf(config, CONFIG_FILE) == -1) {
 		ret = -1;
 		goto out;
 	}
@@ -350,13 +635,13 @@
 	}
 
 	if ((fp = fopen(conffile, "r")) == NULL) {
-		if (recursion_depth > 1)
+		if (config->recursion_depth > 1)
 			printf(": %s\n", strerror(errno));
 		free(line);
 		ret = 0;
 		goto out;
 	}
-	if (recursion_depth > 1)
+	if (config->recursion_depth > 1)
 		printf("\n");
 
 	while (fgets(line, MAX_LINE_LEN, fp)) {
@@ -399,7 +684,7 @@
 		}
 		opt[opt_pos] = '\0';
 
-#ifdef DEBUG
+#ifdef MP_DEBUG
 		PRINT_LINENUM;
 		printf("option: %s\n", opt);
 #endif
@@ -460,7 +745,7 @@
 			continue;
 		}
 
-#ifdef DEBUG
+#ifdef MP_DEBUG
 		PRINT_LINENUM;
 		printf("parameter: %s\n", param);
 #endif
@@ -477,7 +762,7 @@
 			ret = -1;
 		}
 
-		tmp = read_option(config, nr_options, opt, param);
+		tmp = m_config_set_option(config, opt, param);
 		switch (tmp) {
 		case ERR_NOT_AN_OPTION:
 		case ERR_MISSING_PARAM:
@@ -497,33 +782,34 @@
 	free(line);
 	fclose(fp);
 out:
-	--recursion_depth;
+	--config->recursion_depth;
 	return ret;
 }
 
-int parse_command_line(struct config *conf, int argc, char **argv, char **envp, char ***filenames)
+int m_config_parse_command_line(m_config_t *config, int argc, char **argv, char **envp)
 {
 	int i;
-	char **f = NULL;
-	int f_nr = 0;
 	int tmp;
 	char *opt;
 	int no_more_opts = 0;
 
-#ifdef DEBUG
+#ifdef MP_DEBUG
+	assert(config != NULL);
+	assert(config->pt != NULL);
 	assert(argv != NULL);
 	assert(envp != NULL);
 	assert(argc >= 1);
 #endif
-
-	if (init_conf(conf, COMMAND_LINE) == -1)
-		return -1;
-
+	
+	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 */
-	++recursion_depth;
+	++config->recursion_depth;
 
 	for (i = 1; i < argc; i++) {
-next:
+	  //next:
 		opt = argv[i];
 		/* check for -- (no more options id.) except --help! */
 		if ((*opt == '-') && (*(opt+1) == '-') && (*(opt+2) != 'h'))
@@ -534,9 +820,32 @@
 			    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "You added '--' but no filenames presented!\n");
 			    goto err_out;
 			}
-			i++;
-			goto next;
+			continue;
 		}
+		if((opt[0] == '{') && (opt[1] == '\0'))
+		  {
+		    play_tree_t* entry = play_tree_new();
+		    config->global = 0;		    
+		    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 */
 		{
@@ -544,8 +853,7 @@
 		    opt++;
 
 		    mp_msg(MSGT_CFGPARSER, MSGL_DBG3, "this_opt = option: %s\n", opt);
-
-		    tmp = read_option(config, nr_options, opt, argv[i + 1]);
+		    tmp = m_config_set_option(config, opt, argv[i + 1]);
 
 		    switch (tmp) {
 		    case ERR_NOT_AN_OPTION:
@@ -562,26 +870,82 @@
 		}
 		else /* filename */
 		{
-		    mp_msg(MSGT_CFGPARSER, MSGL_DBG3, "this_opt = filename: %s\n", opt);
-
+		    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]);
 		    /* opt is not an option -> treat it as a filename */
-		    if (!(f = (char **) realloc(f, sizeof(*f) * (f_nr + 2))))
-			goto err_out_mem;
-
-		    f[f_nr++] = argv[i];
+		    config->global = 0; // 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;
 		}
 	}
 
-	if (f)
-		f[f_nr] = NULL;
-	if (filenames)
-		*filenames = f;
-	--recursion_depth;
-	return f_nr; //filenames_nr;
+	--config->recursion_depth;
+	if(config->last_parent != config->pt)
+	  mp_msg(MSGT_CFGPARSER, MSGL_ERR,"Missing }- ?\n");
+	config->global = 1;
+	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:
-	--recursion_depth;
+	--config->recursion_depth;
+	config->global = 1;
 	mp_msg(MSGT_CFGPARSER, MSGL_ERR, "command line: %s\n", argv[i]);
 	return -1;
 }
+
+void
+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;
+  }
+  conf_list[list_len] = args;
+  conf_list[list_len+1] = NULL;
+
+  config->opt_list = conf_list;
+}
+
+config_t*
+m_config_get_option(m_config_t *config, char* arg) {
+  int i;
+  config_t *conf;
+  config_t **conf_list;
+
+#ifdef MP_DEBUG
+  assert(config != NULL);
+  assert(arg != NULL);
+#endif
+
+  conf_list = config->opt_list;
+  if(conf_list) {
+    for(conf = conf_list[0]; conf != NULL ; conf ++) {
+      for(i=0; conf[i].name != NULL; i++) {
+	if(strcasecmp(conf[i].name,arg) == 0)
+	  return &conf[i];
+      }
+    }
+  }
+  return NULL;
+}
+
+
--- a/cfgparser.h	Mon Jan 14 23:06:43 2002 +0000
+++ b/cfgparser.h	Mon Jan 14 23:38:49 2002 +0000
@@ -28,6 +28,17 @@
 #define CONF_RANGE		(CONF_MIN|CONF_MAX)
 #define CONF_NOCFG		(1<<2)
 #define CONF_NOCMD		(1<<3)
+#define CONF_GLOBAL		(1<<4)
+#define CONF_NOSAVE                            (1<<5)
+
+
+typedef struct config config_t;
+typedef struct m_config m_config_t;
+typedef struct config_save config_save_t;
+
+#include "playtree.h"
+
+typedef void (*cfg_default_func_t)(config_t *, char*);
 
 struct config {
 	char *name;
@@ -35,24 +46,64 @@
 	unsigned int type;
 	unsigned int flags;
 	float min,max;
+	cfg_default_func_t default_func;
 };
 
-typedef int (*cfg_func_arg_param_t)(struct config *, char *, char *);
-typedef int (*cfg_func_param_t)(struct config *, char *);
-typedef int (*cfg_func_t)(struct config *);
+
+
+struct m_config {
+  config_t** opt_list;
+  config_save_t** config_stack;
+  int cs_level;
+  int parser_mode;  /* COMMAND_LINE or CONFIG_FILE */
+  int global; // Are we parsing global option
+  play_tree_t* pt; // play tree we use for playlist option, etc
+  play_tree_t* last_entry; // last added entry
+  play_tree_t* last_parent; // if last_entry is NULL we must create child of this
+  int recursion_depth;
+};
+
+struct config_save {
+  config_t* opt;
+  union {
+    int as_int;
+    float as_float;
+    void* as_pointer;
+  } param;
+  char* opt_name;
+};
+
+
+typedef int (*cfg_func_arg_param_t)(config_t *, char *, char *);
+typedef int (*cfg_func_param_t)(config_t *, char *);
+typedef int (*cfg_func_t)(config_t *);
 
 /* parse_config_file returns:
  * 	-1 on error (can't malloc, invalid option...)
  * 	 0 if can't open configfile
  * 	 1 on success
  */
-int parse_config_file(struct config *conf, char *conffile);
+int m_config_parse_config_file(m_config_t *config, char *conffile);
 
 /* parse_command_line returns:
  * 	-1 on error (invalid option...)
  * 	 0 if there was no filename on command line
- * 	 >=1 if there were filenames
+ * 	 1 if there were filenames
  */
-int parse_command_line(struct config *conf, int argc, char **argv, char **envp, char ***filenames);
+int m_config_parse_command_line(m_config_t* config, int argc, char **argv, char **envp);
+
+
+void m_config_register_options(m_config_t *config,config_t *args);
+
+int m_config_set_option(m_config_t *config,char *opt, char *param);
+
+config_t* m_config_get_option(m_config_t *config, char* arg);
 
+m_config_t* m_config_new(play_tree_t* pt);
+
+void m_config_free(m_config_t* config);
+
+void m_config_push(m_config_t* config);
+
+int m_config_pop(m_config_t* config);
 #endif /* __CONFIG_H */
--- a/dec_video.c	Mon Jan 14 23:06:43 2002 +0000
+++ b/dec_video.c	Mon Jan 14 23:38:49 2002 +0000
@@ -331,6 +331,10 @@
 	xacodec_exit();
 	break;
 #endif
+    case VFM_DIVX4:
+    case VFM_ODIVX:
+      decore(0x123,DEC_OPT_RELEASE,NULL,NULL);
+      break;
     }
     if(sh_video->our_out_buffer){
 	free(sh_video->our_out_buffer);
--- a/mencoder.c	Mon Jan 14 23:06:43 2002 +0000
+++ b/mencoder.c	Mon Jan 14 23:38:49 2002 +0000
@@ -31,6 +31,7 @@
 #include "stream.h"
 #include "demuxer.h"
 #include "stheader.h"
+#include "playtree.h"
 
 #include "aviwrite.h"
 
@@ -171,10 +172,12 @@
 
 #include "cfgparser.h"
 
+m_config_t* mconfig;
+
 static int cfg_inc_verbose(struct config *conf){ ++verbose; return 0;}
 
 static int cfg_include(struct config *conf, char *filename){
-	return parse_config_file(conf, filename);
+	return m_config_parse_config_file(mconfig, filename);
 }
 
 #include "get_path.c"
@@ -340,9 +343,9 @@
 double v_pts_corr=0;
 double v_timer_corr=0;
 
-char** filenames=NULL;
+play_tree_t* playtree;
+play_tree_iter_t* playtree_iter;
 char* filename=NULL;
-int num_filenames;
 
 int decoded_frameno=0;
 
@@ -378,16 +381,30 @@
 divx4_param.rc_reaction_ratio  = 20;
 #endif
 
-  num_filenames=parse_command_line(conf, argc, argv, envp, &filenames);
-  if(num_filenames<0) exit(1); // error parsing cmdline
-  if(!num_filenames && !vcd_track && !dvd_title && !tv_param_on){
+  playtree = play_tree_new();
+  mconfig = m_config_new(playtree);
+  m_config_register_options(mconfig,mencoder_opts);
+
+  if(m_config_parse_command_line(mconfig, argc, argv, envp) < 0) exit(1); // error parsing cmdline
+  playtree = play_tree_cleanup(playtree);
+  if(playtree) {
+    playtree_iter = play_tree_iter_new(playtree,mconfig);
+    if(playtree_iter) {  
+      if(play_tree_iter_step(playtree_iter,0,0) != PLAY_TREE_ITER_ENTRY) {
+	play_tree_iter_free(playtree_iter);
+	playtree_iter = NULL;
+      }
+      filename = play_tree_iter_get_file(playtree_iter,1);
+    }
+  }
+
+  if(!filename && !vcd_track && !dvd_title && !tv_param_on){
 	printf("\nMissing filename!\n\n");
 	exit(1);
   }
 
   mp_msg_init(verbose+MSGL_STATUS);
 
-  filename=(num_filenames>0)?filenames[0]:NULL;
   stream=open_stream(filename,vcd_track,&file_format);
 
   if(!stream){
--- a/mplayer.c	Mon Jan 14 23:06:43 2002 +0000
+++ b/mplayer.c	Mon Jan 14 23:38:49 2002 +0000
@@ -97,6 +97,19 @@
 
 play_tree_t* playtree;
 
+#define PT_NEXT_ENTRY 1
+#define PT_PREV_ENTRY -1
+#define PT_NEXT_SRC 2
+#define PT_PREV_SRC -2
+#define PT_UP_NEXT 3
+#define PT_UP_PREV -3
+
+//**************************************************************************//
+//             Config
+//**************************************************************************//
+
+m_config_t* mconfig;
+
 //**************************************************************************//
 //             Config file
 //**************************************************************************//
@@ -104,7 +117,7 @@
 static int cfg_inc_verbose(struct config *conf){ ++verbose; return 0;}
 
 static int cfg_include(struct config *conf, char *filename){
-	return parse_config_file(conf, filename);
+	return m_config_parse_config_file(mconfig, filename);
 }
 
 #include "get_path.c"
@@ -234,6 +247,10 @@
 static int vidmode=0;
 static int softzoom=0;
 static int flip=-1;
+// We need this opt_* because the values are then calculated so the options use the opt_*
+// and before each file we reset the calculated value using this opt_* values
+static int opt_screen_size_x=0;//SCREEN_SIZE_X;
+static int opt_screen_size_y=0;//SCREEN_SIZE_Y;
 static int screen_size_x=0;//SCREEN_SIZE_X;
 static int screen_size_y=0;//SCREEN_SIZE_Y;
 static int screen_size_xy=0;
@@ -373,11 +390,11 @@
 #include "mixer.h"
 #include "cfg-mplayer.h"
 
-void parse_cfgfiles( void )
+void parse_cfgfiles( m_config_t* conf )
 {
 char *conffile;
 int conffile_fd;
-if (parse_config_file(conf, "/etc/mplayer.conf") < 0)
+if (m_config_parse_config_file(conf, "/etc/mplayer.conf") < 0)
   exit(1);
 if ((conffile = get_path("")) == NULL) {
   mp_msg(MSGT_CPLAYER,MSGL_WARN,MSGTR_NoHomeDir);
@@ -392,7 +409,7 @@
       write(conffile_fd, default_config, strlen(default_config));
       close(conffile_fd);
     }
-    if (parse_config_file(conf, conffile) < 0)
+    if (m_config_parse_config_file(conf, conffile) < 0)
       exit(1);
     free(conffile);
   }
@@ -417,13 +434,10 @@
 
 // for multifile support:
 play_tree_iter_t* playtree_iter = NULL;
-char **filenames=NULL;
-int num_filenames=0;
-int curr_filename=0;
 
 char* filename=NULL; //"MI2-Trailer.avi";
 int file_format=DEMUXER_TYPE_UNKNOWN;
-//
+
 int delay_corrected=1;
 char* title="MPlayer";
 
@@ -493,36 +507,20 @@
       (strrchr(argv[0],'/') && !strcmp(strrchr(argv[0],'/'),"/gmplayer") ) )
           use_gui=1;
 
-    parse_cfgfiles();
-    num_filenames=parse_command_line(conf, argc, argv, envp, &filenames);
-    if(num_filenames<0) exit(1); // error parsing cmdline
+    playtree = play_tree_new();
 
-    playtree = play_tree_new();
-    {
-      play_tree_t* list = NULL;
-      int i;
-      play_tree_t *entry = NULL, *tree = play_tree_new();
-      for(i= 0; i < num_filenames ; i++) {
-	entry = entry != NULL ? play_tree_new() : tree;
-	play_tree_add_file(entry,filenames[i]);
-	play_tree_append_entry(tree,entry);
-      }
-     
-      entry = play_tree_new();
-      play_tree_set_child(entry,tree);
-      list = entry;
-      if(playlist_file!=NULL) {
-	entry = parse_playlist_file(playlist_file);
-	if(entry != NULL){
-	  if(list) play_tree_append_entry(list,entry);
-	  else list = entry;
-	}
-      }
-      if(list) play_tree_set_child(playtree,list);
-    }
+    mconfig = m_config_new(playtree);
+    m_config_register_options(mconfig,mplayer_opts);
+    // TODO : add something to let modules register their options
+    parse_cfgfiles(mconfig);
+
+
+
+    if(m_config_parse_command_line(mconfig, argc, argv, envp) < 0) exit(1); // error parsing cmdline
+
     playtree = play_tree_cleanup(playtree);
     if(playtree) {
-      playtree_iter = play_tree_iter_new(playtree);
+      playtree_iter = play_tree_iter_new(playtree,mconfig);
       if(playtree_iter) {  
 	if(play_tree_iter_step(playtree_iter,0,0) != PLAY_TREE_ITER_ENTRY) {
 	  play_tree_iter_free(playtree_iter);
@@ -606,7 +604,6 @@
       printf("CommandLine:");
       for(i=1;i<argc;i++)printf(" '%s'",argv[i]);
       printf("\n");
-      printf("num_filenames: %d\n",num_filenames);
     }
 
     mp_msg_init(verbose+MSGL_STATUS);
@@ -1172,7 +1169,7 @@
 for(i=0;i<CODECS_MAX_OUTFMT;i++){
 //    int ret;
     out_fmt=sh_video->codec->outfmt[i];
-    if(out_fmt==0xFFFFFFFF) continue;
+    if(out_fmt==(signed int)0xFFFFFFFF) continue;
 #ifdef USE_LIBVO2
     vo_flags=vo2_query_format(video_out);
 #else
@@ -1223,10 +1220,12 @@
      if(!screen_size_xy) screen_size_xy=vo_screenwidth; // scale with asp.ratio
    }
 #endif
+   
   // Set default VGA 1:1 aspect as fallback ::atmos
   if(movie_aspect>-1.0) sh_video->aspect = movie_aspect; // cmdline overrides autodetect
 //  if(!sh_video->aspect) sh_video->aspect=1.0;
-
+  screen_size_x = opt_screen_size_x;
+  screen_size_y = opt_screen_size_y;
   if(screen_size_xy||screen_size_x||screen_size_y){
    if(screen_size_xy>0){
      if(screen_size_xy<=8){
@@ -1829,7 +1828,9 @@
 #endif
 
   if(osd_function==OSD_PAUSE){
+#ifdef HAVE_NEW_GUI
       int gui_pause_flag=0; // gany!
+#endif
       mp_msg(MSGT_CPLAYER,MSGL_STATUS,"\n------ PAUSED -------\r");fflush(stdout);
 #ifdef HAVE_NEW_GUI
       if(use_gui) mplShMem->Playing=2;
@@ -1963,18 +1964,10 @@
       break;
     // quit
     case KEY_ESC: // ESC
-    case 'q': exit_player(MSGTR_Exit_quit);
-    case '>':
-	if(curr_filename>=num_filenames-1)
-		break;
+    case 'q': 
+      exit_player(MSGTR_Exit_quit);
     case KEY_ENTER: // ESC
-      eof=2;  // jump to next file
-      break;
-    case '<':
-	if(curr_filename < 1)
-		break;
-        curr_filename-=2;
-	eof=2;
+      eof=1;  // force jump to next file : quit if no next file
       break;
     case 'g': grab_frames=2;break;
     // pause
@@ -1985,26 +1978,42 @@
     case KEY_HOME:
       {
 	play_tree_iter_t* i = play_tree_iter_new_copy(playtree_iter);
-	if(play_tree_iter_step(i,1,0) == PLAY_TREE_ITER_ENTRY)
-	  eof = 1;
+	if(play_tree_iter_up_step(i,1,0) == PLAY_TREE_ITER_ENTRY)
+	  eof = PT_UP_NEXT;
 	play_tree_iter_free(i);
       }
       break;
     case KEY_END:
       {
 	play_tree_iter_t* i = play_tree_iter_new_copy(playtree_iter);
+	if(play_tree_iter_up_step(i,-1,0) == PLAY_TREE_ITER_ENTRY)
+	  eof = PT_UP_PREV;
+	play_tree_iter_free(i);
+      }
+      break;
+    case '>':
+      {
+	play_tree_iter_t* i = play_tree_iter_new_copy(playtree_iter);
+	if(play_tree_iter_step(i,1,0) == PLAY_TREE_ITER_ENTRY)
+	  eof = PT_NEXT_ENTRY;
+	play_tree_iter_free(i);
+      }
+      break;
+    case '<':
+      {
+	play_tree_iter_t* i = play_tree_iter_new_copy(playtree_iter);
 	if(play_tree_iter_step(i,-1,0) == PLAY_TREE_ITER_ENTRY)
-	  eof = -1;
+	  eof = PT_PREV_ENTRY;
 	play_tree_iter_free(i);
       }	
       break;
     case KEY_INS:
       if(playtree_iter->num_files > 1 && playtree_iter->file < playtree_iter->num_files)
-	eof = 2;
+	eof = PT_NEXT_SRC;
       break;
     case KEY_DEL:      
       if(playtree_iter->num_files > 1 && playtree_iter->file > 1)
-	eof = -2;
+	eof = PT_PREV_SRC;
       break;
     case 'o':  // toggle OSD
       osd_level=(osd_level+1)%3;
@@ -2345,7 +2354,7 @@
 
 goto_next_file:  // don't jump here after ao/vo/getch initialization!
 
-if(eof == 1 || eof == -1) {
+if(eof == PT_NEXT_ENTRY || eof == PT_PREV_ENTRY) {
   if(play_tree_iter_step(playtree_iter,eof,0) == PLAY_TREE_ITER_ENTRY) {
     uninit_player(INITED_ALL-(INITED_GUI+INITED_LIRC));
     eof = 1;
@@ -2353,9 +2362,18 @@
     play_tree_iter_free(playtree_iter);
     playtree_iter = NULL;
   }
-} else {
+} else if (eof == PT_UP_NEXT || eof == PT_UP_PREV) {
+  eof = eof == PT_UP_NEXT ? 1 : -1;
+  if(play_tree_iter_up_step(playtree_iter,eof,0) == PLAY_TREE_ITER_ENTRY) {
+    uninit_player(INITED_ALL-(INITED_GUI+INITED_LIRC));
+    eof = 1;
+  } else {
+    play_tree_iter_free(playtree_iter);
+    playtree_iter = NULL;
+  }
+}else { // NEXT PREV SRC
      uninit_player(INITED_ALL-(INITED_GUI+INITED_LIRC));
-     eof = eof == -2 ? -1 : 1;
+     eof = eof == PT_PREV_SRC ? -1 : 1;
 }
 
 goto_next_file_src: // When we have multiple src for file
--- a/playtree.c	Mon Jan 14 23:06:43 2002 +0000
+++ b/playtree.c	Mon Jan 14 23:38:49 2002 +0000
@@ -1,9 +1,12 @@
 
+#include "config.h"
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <unistd.h>
+#ifdef MP_DEBUG
 #include <assert.h>
+#endif
 #include "playtree.h"
 #include "mp_msg.h"
 
@@ -22,7 +25,7 @@
 play_tree_free(play_tree_t* pt, int childs) {
   play_tree_t* iter;
 
-#ifdef DEBUG
+#ifdef MP_DEBUG
   assert(pt != NULL);
 #endif
 
@@ -52,7 +55,7 @@
 play_tree_free_list(play_tree_t* pt, int childs) {
   play_tree_t* iter;
 
-#ifdef DEBUG
+#ifdef MP_DEBUG
   assert(pt != NULL);
 #endif
 
@@ -69,7 +72,7 @@
 play_tree_append_entry(play_tree_t* pt, play_tree_t* entry) {
   play_tree_t* iter;
 
-#ifdef DEBUG
+#ifdef MP_DEBUG
   assert(pt != NULL);
   assert(entry != NULL);
 #endif
@@ -90,7 +93,7 @@
 play_tree_prepend_entry(play_tree_t* pt, play_tree_t* entry) {
   play_tree_t* iter;
 
-#ifdef DEBUG
+#ifdef MP_DEBUG
   assert(pt != NULL);
   assert(entry != NULL);
 #endif
@@ -104,7 +107,7 @@
 
   iter->prev = entry;
   if(entry->parent) {
-#ifdef DEBUG
+#ifdef MP_DEBUG
     assert(entry->parent->child == iter);
 #endif
     entry->parent->child = entry;
@@ -114,7 +117,7 @@
 void
 play_tree_insert_entry(play_tree_t* pt, play_tree_t* entry) {
   
-#ifdef DEBUG
+#ifdef MP_DEBUG
   assert(pt != NULL);
   assert(entry != NULL);
 #endif
@@ -122,7 +125,7 @@
   entry->parent = pt->parent;
   entry->prev = pt;
   if(pt->next) {
-#ifdef DEBUG
+#ifdef MP_DEBUG
     assert(pt->next->prev == pt);
 #endif
     entry->next = pt->next;
@@ -136,13 +139,13 @@
 void
 play_tree_remove(play_tree_t* pt, int free_it,int with_childs) {
 
-#ifdef DEBUG
+#ifdef MP_DEBUG
   assert(pt != NULL);
 #endif
 
   // Middle of list
   if(pt->prev && pt->next) {
-#ifdef DEBUG
+#ifdef MP_DEBUG
     assert(pt->prev->next == pt);
     assert(pt->next->prev == pt);
 #endif
@@ -150,25 +153,25 @@
     pt->next->prev = pt->prev;
   } // End of list
   else if(pt->prev) { 
-#ifdef DEBUG
+#ifdef MP_DEBUG
     assert(pt->prev->next == pt);
 #endif
     pt->prev->next = NULL;
   } // Begining of list
   else if(pt->next) {
-#ifdef DEBUG
+#ifdef MP_DEBUG
     assert(pt->next->prev == pt);
 #endif
     pt->next->prev = NULL;
     if(pt->parent) {
-#ifdef DEBUG
+#ifdef MP_DEBUG
       assert(pt->parent->child == pt);
 #endif
       pt->parent->child = pt->next;
     } 
   } // The only one
   else if(pt->parent) {
-#ifdef DEBUG
+#ifdef MP_DEBUG
     assert(pt->parent->child == pt);
 #endif
     pt->parent->child = NULL;
@@ -184,7 +187,7 @@
 play_tree_set_child(play_tree_t* pt, play_tree_t* child) {
   play_tree_t* iter;
 
-#ifdef DEBUG
+#ifdef MP_DEBUG
   assert(pt != NULL);
   assert(pt->files == NULL);
 #endif
@@ -207,7 +210,7 @@
 play_tree_set_parent(play_tree_t* pt, play_tree_t* parent) {
   play_tree_t* iter;
 
-#ifdef DEBUG
+#ifdef MP_DEBUG
   assert(pt != NULL);
 #endif
 
@@ -232,7 +235,7 @@
 play_tree_add_file(play_tree_t* pt,char* file) {
   int n = 0;
 
-#ifdef DEBUG
+#ifdef MP_DEBUG
   assert(pt != NULL);
   assert(pt->child == NULL);
   assert(file != NULL);
@@ -257,7 +260,7 @@
 play_tree_remove_file(play_tree_t* pt,char* file) {
   int n,f = -1;
 
-#ifdef DEBUG
+#ifdef MP_DEBUG
   assert(pt != NULL);
   assert(file != NULL);
   assert(pt->files != NULL);
@@ -271,7 +274,7 @@
   if(f < 0) // Not found
     return 0;
 
-#ifdef DEBUG
+#ifdef MP_DEBUG
   assert(n > f);
 #endif
 
@@ -292,12 +295,11 @@
   return 1;
 }
 
-#if 0
 void
 play_tree_set_param(play_tree_t* pt, char* name, char* val) {
   int n = 0,ni = -1;
 
-#ifdef DEBUG
+#ifdef MP_DEBUG
   assert(pt != NULL);
   assert(name != NULL);
 #endif
@@ -325,9 +327,9 @@
 
 int
 play_tree_unset_param(play_tree_t* pt, char* name) {
-  int n,ni = 0;
+  int n,ni = -1;
 
-#ifdef DEBUG
+#ifdef MP_DEBUG
   assert(pt != NULL);
   assert(name != NULL);
   assert(pt->params != NULL);
@@ -341,10 +343,16 @@
   if(ni < 0)
     return 0;
 
+  if(pt->params[ni].name) free(pt->params[ni].name);
+  if(pt->params[ni].value) free(pt->params[ni].value);
+
   if(n > 1) {
     memmove(&pt->params[ni],&pt->params[ni+1],(n-ni)*sizeof(play_tree_param_t));
     pt->params = (play_tree_param_t*)realloc(pt->params,n*sizeof(play_tree_param_t));
-    assert(pt->params != NULL);
+    if(pt->params == NULL) {
+      mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Can't allocate %d bytes of memory\n",n*sizeof(play_tree_param_t));
+      return -1;
+    }
   } else {
     free(pt->params);
     pt->params = NULL;
@@ -353,14 +361,53 @@
   return 1;
 }
 
+static int 
+play_tree_iter_push_params(play_tree_iter_t* iter) {
+  int n;
+  play_tree_t* pt;
+#ifdef MP_DEBUG
+  assert(iter != NULL);
+  assert(iter->config != NULL);
+  assert(iter->tree != NULL);
 #endif
 
+  pt = iter->tree;
+
+  if(pt->params == NULL)
+    return 0;
+
+  m_config_push(iter->config);
+  for(n = 0; pt->params[n].name != NULL ; n++) {
+    if(m_config_set_option(iter->config,pt->params[n].name,pt->params[n].value) < 0) {
+      mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Error while setting option '%s' with value '%s'\n",
+	     pt->params[n].name,pt->params[n].value);      
+    }
+  }
+  //printf("Param pushed\n");
+  return 1;
+}
+
+static void
+play_tree_iter_pop_params(play_tree_iter_t* iter) {
+  
+#ifdef MP_DEBUG
+  assert(iter != NULL);
+  assert(iter->config != NULL);
+#endif
+
+  if(iter->tree->params == NULL)
+    return;
+  //printf("Poping params\n");
+  m_config_pop(iter->config);
+}
+
 play_tree_iter_t*
-play_tree_iter_new(play_tree_t* pt) {
+play_tree_iter_new(play_tree_t* pt,m_config_t* config) {
   play_tree_iter_t* iter;
 
-#ifdef DEBUG
+#ifdef MP_DEBUG
   assert(pt != NULL);
+  assert(config != NULL);
 #endif
   
   if( ! play_tree_is_valid(pt))
@@ -370,6 +417,7 @@
   if(! iter) return NULL;
   iter->root = pt;
   iter->tree = NULL;
+  iter->config = config;
  
   if(pt->parent)
     iter->loop = pt->parent->loop;
@@ -380,12 +428,12 @@
 void
 play_tree_iter_free(play_tree_iter_t* iter) {
   
-#ifdef DEBUG
+#ifdef MP_DEBUG
   assert(iter != NULL);
 #endif
 
   if(iter->status_stack) {
-#ifdef DEBUG
+#ifdef MP_DEBUG
     assert(iter->stack_size > 0);
 #endif
     free(iter->status_stack);
@@ -398,9 +446,10 @@
 play_tree_iter_step(play_tree_iter_t* iter, int d,int with_nodes) {
   play_tree_t* pt;
 
-#ifdef DEBUG
+#ifdef MP_DEBUG
   assert(iter != NULL);
   assert(iter->root != NULL);
+  //printf("PT : Stepping = %d\n",d);
 #endif
 
   if(iter->tree == NULL) {
@@ -408,6 +457,11 @@
     return play_tree_iter_step(iter,0,with_nodes);
   }
 
+  if(iter->config && iter->entry_pushed) {
+    play_tree_iter_pop_params(iter);
+    iter->entry_pushed = 0;
+  }
+
   iter->file = 0;
   if( d > 0 )
     pt = iter->tree->next;
@@ -454,14 +508,17 @@
     return play_tree_iter_step(iter,d,with_nodes);
   }
 
-#ifdef DEBUG
-  assert(iter->tree->files != NULL);
+#ifdef MP_DEBUG
+  assert(pt->files != NULL);
 #endif
   
   iter->tree = pt;
   for(d = 0 ; iter->tree->files[d] != NULL ; d++)
     /* NOTHING */;
   iter->num_files = d;
+  
+  if(iter->config)
+    iter->entry_pushed = play_tree_iter_push_params(iter);
 
   return PLAY_TREE_ITER_ENTRY;
 
@@ -471,7 +528,7 @@
 play_tree_is_valid(play_tree_t* pt) {
   play_tree_t* iter;
 
-#ifdef DEBUG
+#ifdef MP_DEBUG
   assert(pt != NULL);
 #endif
 
@@ -489,22 +546,22 @@
 int
 play_tree_iter_up_step(play_tree_iter_t* iter, int d,int with_nodes) {
 
-#ifdef DEBUG
+#ifdef MP_DEBUG
   assert(iter != NULL);
   assert(iter->tree != NULL);
+  //printf("PT : Go UP\n");
 #endif
   
   iter->file = 0;
   if(iter->tree->parent == iter->root->parent)
     return PLAY_TREE_ITER_END;
 
-#ifdef DEBUG
+#ifdef MP_DEBUG
   assert(iter->tree->parent != NULL);
   assert(iter->stack_size > 0);
   assert(iter->status_stack != NULL);
 #endif
-  
-  // Pop status
+
   iter->stack_size--;
   iter->loop = iter->status_stack[iter->stack_size];
   iter->status_stack = (int*)realloc(iter->status_stack,iter->stack_size*sizeof(int));
@@ -513,20 +570,30 @@
     return PLAY_TREE_ITER_ERROR;
   }
   iter->tree = iter->tree->parent;
+
+  // Pop subtree params
+  if(iter->config)
+    play_tree_iter_pop_params(iter);
+
   return play_tree_iter_step(iter,d,with_nodes);
 }
   
 int
 play_tree_iter_down_step(play_tree_iter_t* iter, int d,int with_nodes) {
 
-#ifdef DEBUG
+#ifdef MP_DEBUG
   assert(iter->tree->files == NULL);
   assert(iter->tree->child != NULL);
   assert(iter->tree->child->parent == iter->tree);
+  //printf("PT : Go DOWN\n");
 #endif
 
   iter->file = 0;
-  //  Push status
+
+  //  Push subtree params
+  if(iter->config)
+    play_tree_iter_push_params(iter);
+
   iter->stack_size++;
   iter->status_stack = (int*)realloc(iter->status_stack,iter->stack_size*sizeof(int));
   if(iter->status_stack == NULL) {
@@ -544,13 +611,14 @@
       /*NOTING*/;
     iter->tree = pt;
   }
+
   return play_tree_iter_step(iter,0,with_nodes);
 }
 
 char*
 play_tree_iter_get_file(play_tree_iter_t* iter, int d) {
   
-#ifdef DEBUG
+#ifdef MP_DEBUG
   assert(iter != NULL);
   assert(iter->tree->child == NULL);
 #endif
@@ -574,7 +642,7 @@
 play_tree_cleanup(play_tree_t* pt) {
   play_tree_t* iter, *tmp, *first;
 
-#ifdef DEBUG
+#ifdef MP_DEBUG
   assert(pt != NULL);
 #endif
 
@@ -608,7 +676,7 @@
 play_tree_iter_new_copy(play_tree_iter_t* old) {
   play_tree_iter_t* iter;
 
-#ifdef DEBUG
+#ifdef MP_DEBUG
   assert(old != NULL);
 #endif
 
@@ -628,5 +696,7 @@
     }
     memcpy(iter->status_stack,old->status_stack,iter->stack_size*sizeof(int));
   }
+  iter->config = NULL;
+
   return iter;
 }
--- a/playtree.h	Mon Jan 14 23:06:43 2002 +0000
+++ b/playtree.h	Mon Jan 14 23:38:49 2002 +0000
@@ -1,6 +1,10 @@
+
+#ifndef __PLAYTREE_H
+#define __PLAYTREE_H
 
 #include "libmpdemux/stream.h"
 
+
 #define PLAY_TREE_ITER_ERROR 0
 #define PLAY_TREE_ITER_ENTRY 1
 #define PLAY_TREE_ITER_NODE  2
@@ -8,11 +12,12 @@
 
 typedef struct play_tree play_tree_t;
 typedef struct play_tree_iter play_tree_iter_t;
+typedef struct play_tree_param play_tree_param_t;
+
+#include "cfgparser.h"
 
 #if 0
 typedef struct play_tree_info play_tree_info_t;
-typedef struct play_tree_param play_tree_param_t;
-
 // TODO : a attrib,val pair system and not something hardcoded
 struct play_tree_info {
   char* title;
@@ -21,12 +26,13 @@
   char* abstract;
   // Some more ??
 }
+#endif
 
 struct play_tree_param {
   char* name;
   char* value;
-}
-#endif
+};
+
 
 struct play_tree {
   play_tree_t* parent;
@@ -35,8 +41,7 @@
   play_tree_t* prev;
 
   //play_tree_info_t info;
-  //int n_param;
-  //play_tree_param_t* params;
+  play_tree_param_t* params;
   int loop;
   char** files;
 };
@@ -44,10 +49,11 @@
 struct play_tree_iter {
   play_tree_t* root; // Iter root tree
   play_tree_t* tree; // Current tree
-  // struct m_config* config; 
+  m_config_t* config; 
   int loop;  // Looping status
   int file;
   int num_files;
+  int entry_pushed;
  
   int* status_stack; //  loop/valid stack to save/revert status when we go up/down
   int stack_size;  // status stack size
@@ -97,7 +103,6 @@
 play_tree_remove_file(play_tree_t* pt,char* file);
 
 
-#if 0
 // Val can be NULL
 void
 play_tree_set_param(play_tree_t* pt, char* name, char* val);
@@ -105,13 +110,11 @@
 int
 play_tree_unset_param(play_tree_t* pt, char* name);
 
-#endif
-
 
 /// Iterator
 
 play_tree_iter_t*
-play_tree_iter_new(play_tree_t* pt);
+play_tree_iter_new(play_tree_t* pt, m_config_t* config);
 
 play_tree_iter_t*
 play_tree_iter_new_copy(play_tree_iter_t* old);
@@ -142,3 +145,5 @@
 
 play_tree_t*
 parse_playlist_file(char* file);
+
+#endif
--- a/playtreeparser.c	Mon Jan 14 23:06:43 2002 +0000
+++ b/playtreeparser.c	Mon Jan 14 23:38:49 2002 +0000
@@ -1,8 +1,11 @@
 
+#include "config.h"
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#ifdef MP_DEBUG
 #include <assert.h>
+#endif
 #include <errno.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -240,7 +243,7 @@
 parse_playtree(stream_t *stream) {
   play_tree_t* tree = NULL;
   
-#ifdef DEBUG
+#ifdef MP_DEBUG
   assert(stream != NULL);
   assert(stream->type == STREAMTYPE_PLAYLIST);
 #endif