changeset 8164:487cfc28525d

New config system + cleanup of header inter dependency
author albeu
date Tue, 12 Nov 2002 01:56:42 +0000
parents 51e5033ee687
children 388263fa5a11
files Makefile asxparser.c asxparser.h cfg-mplayer.h cfgparser.c cfgparser.h configure input/input.c libmpdemux/stream.h libvo/vo_aa.c m_config.c m_config.h m_option.c m_option.h mencoder.c mplayer.c parser-cfg.c parser-mecmd.c parser-mecmd.h parser-mpcmd.c playtree.c playtree.h playtreeparser.c playtreeparser.h
diffstat 24 files changed, 2441 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Tue Nov 12 00:19:14 2002 +0000
+++ b/Makefile	Tue Nov 12 01:56:42 2002 +0000
@@ -26,9 +26,9 @@
 # a BSD compatible 'install' program
 INSTALL = install
 
-SRCS_COMMON = cpudetect.c codec-cfg.c cfgparser.c my_profile.c spudec.c playtree.c playtreeparser.c asxparser.c vobsub.c subreader.c sub_cc.c find_sub.c
-SRCS_MENCODER = mencoder.c mp_msg-mencoder.c $(SRCS_COMMON) libao2/afmt.c divx4_vbr.c libvo/aclib.c libvo/osd.c libvo/sub.c libvo/font_load.c libvo/font_load_ft.c xvid_vbr.c
-SRCS_MPLAYER = mplayer.c mp_msg.c $(SRCS_COMMON) mixer.c
+SRCS_COMMON = cpudetect.c codec-cfg.c cfgparser.c my_profile.c spudec.c playtree.c playtreeparser.c asxparser.c vobsub.c subreader.c sub_cc.c find_sub.c m_config.c m_option.c parser-cfg.c
+SRCS_MENCODER = mencoder.c mp_msg-mencoder.c $(SRCS_COMMON) libao2/afmt.c divx4_vbr.c libvo/aclib.c libvo/osd.c libvo/sub.c libvo/font_load.c libvo/font_load_ft.c xvid_vbr.c parser-mecmd.c
+SRCS_MPLAYER = mplayer.c mp_msg.c $(SRCS_COMMON) mixer.c parser-mpcmd.c
 
 ifeq ($(UNRARLIB),yes)
 SRCS_COMMON += unrarlib.c
--- a/asxparser.c	Tue Nov 12 00:19:14 2002 +0000
+++ b/asxparser.c	Tue Nov 12 01:56:42 2002 +0000
@@ -1,3 +1,4 @@
+#include "config.h"
 
 #include <stdlib.h>
 #include <stdio.h>
@@ -5,7 +6,9 @@
 #include <string.h>
 #include <unistd.h>
 
+#include "playtree.h"
 #include "playtreeparser.h"
+#include "libmpdemux/stream.h"
 #include "asxparser.h"
 #include "mp_msg.h"
 #include "cfgparser.h"
--- a/asxparser.h	Tue Nov 12 00:19:14 2002 +0000
+++ b/asxparser.h	Tue Nov 12 01:56:42 2002 +0000
@@ -1,5 +1,4 @@
 
-#include "playtree.h"
 
 typedef struct _ASX_Parser_t ASX_Parser_t;
 
--- a/cfg-mplayer.h	Tue Nov 12 00:19:14 2002 +0000
+++ b/cfg-mplayer.h	Tue Nov 12 01:56:42 2002 +0000
@@ -252,8 +252,8 @@
 	{"x", &opt_screen_size_x, CONF_TYPE_INT, CONF_RANGE, 0, 4096, NULL},
 	{"y", &opt_screen_size_y, CONF_TYPE_INT, CONF_RANGE, 0, 4096, NULL},
 	// set screen dimensions (when not detectable or virtual!=visible)
-	{"screenw", &vo_screenwidth, CONF_TYPE_INT, CONF_RANGE, 0, 4096, NULL},
-	{"screenh", &vo_screenheight, CONF_TYPE_INT, CONF_RANGE, 0, 4096, NULL},
+	{"screenw", &vo_screenwidth, CONF_TYPE_INT, CONF_RANGE|CONF_OLD, 0, 4096, NULL},
+	{"screenh", &vo_screenheight, CONF_TYPE_INT, CONF_RANGE|CONF_OLD, 0, 4096, NULL},
 	// Geometry string
 	{"geometry", &vo_geometry, CONF_TYPE_STRING, 0, 0, 0, NULL},
 	// set aspect ratio of monitor - usefull for 16:9 TVout
--- a/cfgparser.c	Tue Nov 12 00:19:14 2002 +0000
+++ b/cfgparser.c	Tue Nov 12 01:56:42 2002 +0000
@@ -19,6 +19,8 @@
 
 #include "config.h"
 
+#ifndef NEW_CONFIG
+
 #ifdef USE_SETLOCALE
 #include <locale.h>
 #endif
@@ -50,6 +52,7 @@
 #endif
 
 #include "cfgparser.h"
+#include "playtree.h"
 
 static void m_config_list_options(m_config_t *config);
 static void m_config_error(int err,char* opt,char* val);
@@ -1536,3 +1539,5 @@
     break;
   }
 }
+
+#endif
--- a/cfgparser.h	Tue Nov 12 00:19:14 2002 +0000
+++ b/cfgparser.h	Tue Nov 12 01:56:42 2002 +0000
@@ -2,6 +2,14 @@
  * command line and config file parser
  */
 
+#ifdef NEW_CONFIG
+#ifdef MP_DEBUG
+#warning "NEW_CONFIG defined but still using the old cfgparser.h"
+#endif
+#include "m_config.h"
+#include "m_option.h"
+#else
+
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
@@ -32,13 +40,14 @@
 #define CONF_NOCMD		(1<<3)
 #define CONF_GLOBAL		(1<<4)
 #define CONF_NOSAVE                            (1<<5)
+#define CONF_OLD                                  (1<<6)
 
 
 typedef struct config config_t;
 typedef struct m_config m_config_t;
 typedef struct config_save config_save_t;
 
-#include "playtree.h"
+struct play_tree;
 
 typedef void (*cfg_default_func_t)(config_t *, char*);
 
@@ -62,9 +71,9 @@
   int parser_mode;  /* COMMAND_LINE or CONFIG_FILE */
   int flags;
   char* sub_conf; // When we save a subconfig
-  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
+  struct play_tree* pt; // play tree we use for playlist option, etc
+  struct play_tree* last_entry; // last added entry
+  struct play_tree* last_parent; // if last_entry is NULL we must create child of this
   int recursion_depth;
 };
 
@@ -97,7 +106,7 @@
  */
 int m_config_parse_command_line(m_config_t* config, int argc, char **argv);
 
-m_config_t* m_config_new(play_tree_t* pt);
+m_config_t* m_config_new(struct play_tree* pt);
 
 void m_config_free(m_config_t* config);
 
@@ -190,3 +199,5 @@
 m_config_get_float (m_config_t *config, char* arg,int* err_ret);
 
 #endif /* __CONFIG_H */
+
+#endif /* NEW_CONFIG */
--- a/configure	Tue Nov 12 00:19:14 2002 +0000
+++ b/configure	Tue Nov 12 01:56:42 2002 +0000
@@ -151,6 +151,7 @@
   --disable-cdparanoia   Disable cdparanoia support [autodetect]
   --enable-freetype      Enable freetype2 font rendering support [disabled]
   --disable-unrarlib     Disable Unique RAR File Library [enabled]
+  --enable-new-conf      Enable new config stuff [disabled]
 
 Codecs:
   --enable-gif		 enable gif89a output support [autodetect]
@@ -1013,6 +1014,7 @@
 _big_endian=auto
 _freetype=no
 _shared_pp=no
+_new_conf=no
 
 for ac_option do
   case "$ac_option" in
@@ -1193,6 +1195,9 @@
   --enable-shared-pp) _shared_pp=yes ;;
   --disable-shared-pp) _shared_pp=no ;;
 
+  --enable-new-conf) _new_conf=yes ;;
+  --disable-new-conf) _new_conf=no ;;
+
   --language=*)
     LINGUAS=`echo $ac_option | cut -d '=' -f 2`
     ;;
@@ -4235,6 +4240,14 @@
 fi
 echores "$_shared_pp"
 
+echocheck "New config"
+if test "$_new_conf" = yes ; then
+    _def_new_conf='#define NEW_CONFIG 1'
+else
+    _def_new_conf='#undef NEW_CONFIG'
+fi
+echores "$_new_conf"
+
 # --------------- GUI specific tests begin -------------------
 echocheck "GUI"
 echo "$_gui"
@@ -4969,6 +4982,9 @@
 /* enables / disables new input joystick support */
 $_def_joystick
 
+/* enables / disables new config */
+$_def_new_conf
+
 /* Extension defines */
 $_def_3dnow	// only define if you have 3DNOW (AMD k6-2, AMD Athlon, iDT WinChip, etc.)
 $_def_3dnowex	// only define if you have 3DNOWEX (AMD Athlon, etc.)
--- a/input/input.c	Tue Nov 12 00:19:14 2002 +0000
+++ b/input/input.c	Tue Nov 12 01:56:42 2002 +0000
@@ -24,6 +24,7 @@
 #include "../linux/getch2.h"
 #include "../linux/keycodes.h"
 #include "../linux/timer.h"
+#include "../mp_msg.h"
 #include "../cfgparser.h"
 
 #include "joystick.h"
--- a/libmpdemux/stream.h	Tue Nov 12 00:19:14 2002 +0000
+++ b/libmpdemux/stream.h	Tue Nov 12 01:56:42 2002 +0000
@@ -31,7 +31,7 @@
 int vcd_seek_to_track(int fd,int track);
 void vcd_read_toc(int fd);
 
-typedef struct {
+typedef struct stream_st {
   int fd;   // file descriptor, see man open(2)
   int type; // see STREAMTYPE_*
   unsigned int buf_pos,buf_len;
--- a/libvo/vo_aa.c	Tue Nov 12 00:19:14 2002 +0000
+++ b/libvo/vo_aa.c	Tue Nov 12 01:56:42 2002 +0000
@@ -510,7 +510,7 @@
 
     if (strstr(c->driver->name,"Curses") || strstr(c->driver->name,"Linux")){
 	freopen("/dev/tty", "w", stderr);
-	m_config_set_flag(mconfig,"quiet",0); /* enable mplayer outputs */
+	m_config_set_option(mconfig,"quiet",NULL); /* enable mplayer outputs */
     }
 #ifdef USE_OSD
     if(vo_font_save) {
@@ -729,7 +729,7 @@
 
     if ((strstr(c->driver->name,"Curses")) || (strstr(c->driver->name,"Linux"))){
 	freopen("/dev/null", "w", stderr);
-	m_config_set_flag(mconfig,"quiet",0); /* disable mplayer outputs */
+	m_config_set_option(mconfig,"noquiet",NULL); /* disable mplayer outputs */
 	/* disable console blanking */
 	printf("\033[9;0]");
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m_config.c	Tue Nov 12 01:56:42 2002 +0000
@@ -0,0 +1,347 @@
+
+#include "config.h"
+
+#ifdef NEW_CONFIG
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#ifdef MP_DEBUG
+#include <assert.h>
+#endif
+
+
+#include "m_config.h"
+#include "m_option.h"
+#include "mp_msg.h"
+
+m_config_t*
+m_config_new(void) {
+  m_config_t* config;
+
+  config = (m_config_t*)calloc(1,sizeof(m_config_t));
+  config->lvl = 1; // 0 Is the defaults
+  return config;
+}
+
+void
+m_config_free(m_config_t* config) {
+  m_config_option_t *i = config->opts, *ct;
+  m_config_save_slot_t *sl,*st;
+
+#ifdef MP_DEBUG
+  assert(config != NULL);
+#endif
+  
+  while(i) {
+    sl = i->slots;
+    while(sl) {
+      m_option_free(i->opt,sl->data);
+      st = sl->prev;
+      free(sl);
+      sl = st;
+    }
+    if(i->name != i->opt->name)
+      free(i->name);
+    ct = i->next;
+    free(i);
+    ct = i;
+  }
+  free(config);  
+}
+
+void
+m_config_push(m_config_t* config) {
+  m_config_option_t *co;
+  m_config_save_slot_t *slot;
+
+#ifdef MP_DEBUG
+  assert(config != NULL);
+  assert(config->lvl > 0);
+#endif
+
+  config->lvl++;
+
+  for(co = config->opts ; co ; co = co->next ) {
+    if(co->opt->type->flags & M_OPT_TYPE_HAS_CHILD)
+      continue;
+    if(co->opt->flags & (M_OPT_GLOBAL|M_OPT_NOSAVE))
+      continue;
+    if((co->opt->flags & M_OPT_OLD) && !co->flags)
+      continue;
+
+    // Update the current status
+    m_option_save(co->opt,co->slots->data,co->opt->p);
+    
+    // Allocate a new slot    
+    slot = (m_config_save_slot_t*)calloc(1,sizeof(m_config_save_slot_t) + co->opt->type->size);
+    slot->lvl = config->lvl;
+    slot->prev = co->slots;
+    co->slots = slot;
+    m_option_copy(co->opt,co->slots->data,co->slots->prev->data);
+    // Reset our flags
+    co->flags=0;
+  }
+  
+  mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Config pushed level is now %d\n",config->lvl);
+}
+
+void
+m_config_pop(m_config_t* config) {
+  m_config_option_t *co;
+  m_config_save_slot_t *slot;
+
+#ifdef MP_DEBUG
+  assert(config != NULL);
+  assert(config->lvl > 1);
+#endif
+
+  for(co = config->opts ; co ; co = co->next ) {
+    int pop = 0;
+    if(co->opt->type->flags & M_OPT_TYPE_HAS_CHILD)
+      continue;
+    if(co->opt->flags & (M_OPT_GLOBAL|M_OPT_NOSAVE))
+      continue;
+    if(co->slots->lvl > config->lvl)
+      mp_msg(MSGT_CFGPARSER, MSGL_WARN,"Too old save slot found from lvl %d : %d !!!\n",config->lvl,co->slots->lvl);
+    
+    while(co->slots->lvl >= config->lvl) {
+      m_option_free(co->opt,co->slots->data);
+      slot = co->slots;
+      co->slots = slot->prev;
+      free(slot);
+      pop++;
+    }
+    if(pop) // We removed some ctx -> set the previous value
+      m_option_set(co->opt,co->opt->p,co->slots->data);
+  }
+
+  config->lvl--;
+  mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Config poped level=%d\n",config->lvl);
+}
+
+static void
+m_config_add_option(m_config_t *config, m_option_t *arg, char* prefix) {
+  m_config_option_t *co;
+  m_config_save_slot_t* sl;
+
+#ifdef MP_DEBUG
+  assert(config != NULL);
+  assert(config->lvl > 0);
+  assert(arg != NULL);
+#endif
+
+  // Allocate a new entry for this option
+  co = (m_config_option_t*)calloc(1,sizeof(m_config_option_t) + arg->type->size);
+  co->opt = arg;
+
+  // Fill in the full name
+  if(prefix && strlen(prefix) > 0) {
+    int l = strlen(prefix) + 1 + strlen(arg->name) + 1;
+    co->name = (char*) malloc(l);
+    sprintf(co->name,"%s:%s",prefix,arg->name);
+  } else
+    co->name = arg->name;
+
+  // Option with childs -> add them
+  if(arg->type->flags & M_OPT_TYPE_HAS_CHILD) {
+    m_option_t *ol = arg->p;
+    int i;
+    for(i = 0 ; ol[i].name != NULL ; i++)
+      m_config_add_option(config,&ol[i], co->name);
+  } else {
+    // Allocate a slot for the defaults
+    sl = (m_config_save_slot_t*)calloc(1,sizeof(m_config_save_slot_t) + arg->type->size);
+    m_option_save(arg,sl->data,(void**)arg->p);
+    // Hack to avoid too much trouble with dynamicly allocated data :
+    // We always use a dynamic version
+    if((arg->type->flags & M_OPT_TYPE_DYNAMIC) && arg->p && (*(void**)arg->p)) {
+      *(void**)arg->p = NULL;
+      m_option_set(arg,arg->p,sl->data);
+    }
+    sl->lvl = 0;
+    co->slots = (m_config_save_slot_t*)calloc(1,sizeof(m_config_save_slot_t) + arg->type->size);
+    co->slots->prev = sl;
+    co->slots->lvl = config->lvl;
+    m_option_copy(co->opt,co->slots->data,sl->data);
+  }
+  co->next = config->opts;
+  config->opts = co;
+}
+
+int
+m_config_register_options(m_config_t *config, m_option_t *args) {
+  int i;
+
+#ifdef MP_DEBUG
+  assert(config != NULL);
+  assert(config->lvl > 0);
+  assert(args != NULL);
+#endif
+
+  for(i = 0 ; args[i].name != NULL ; i++)
+    m_config_add_option(config,&args[i],NULL);
+
+  return 1;
+}
+
+static m_config_option_t* 
+m_config_get_co(m_config_t *config, char* arg) {
+  m_config_option_t *co;
+
+  for(co = config->opts ; co ; co = co->next ) {
+    int l = strlen(co->name) - 1;
+    if((co->opt->type->flags & M_OPT_TYPE_ALLOW_WILDCARD) && 
+       (co->name[l] == '*')) {
+      if(strncasecmp(co->name,arg,l) == 0)
+	return co;
+    } else if(strcasecmp(co->name,arg) == 0)
+      return co;
+  }
+  return NULL;
+}
+
+static int
+m_config_parse_option(m_config_t *config, char* arg, char* param,int set) {
+  m_config_option_t *co;
+  int r = 0;
+
+#ifdef MP_DEBUG
+  assert(config != NULL);
+  assert(config->lvl > 0);
+  assert(arg != NULL);
+#endif
+
+  co = m_config_get_co(config,arg);
+  if(!co)
+    return M_OPT_UNKNOW;
+
+#ifdef MP_DEBUG
+  // This is the only mandatory function
+  assert(co->opt->type->parse);
+#endif
+
+  // Check if this option isn't forbiden in the current mode
+  if((config->mode == M_CONFIG_FILE) && (co->opt->flags & M_OPT_NOCFG)) {
+    mp_msg(MSGT_CFGPARSER, MSGL_ERR,"The %s option can't be used in a config file\n",config->lvl);
+    return M_OPT_INVALID;
+  }
+  if((config->mode == M_COMMAND_LINE) && (co->opt->flags & M_OPT_NOCMD)) {
+    mp_msg(MSGT_CFGPARSER, MSGL_ERR,"The %s option can't be used on the command line\n",config->lvl);
+    return M_OPT_INVALID;
+  }
+
+  // Option with childs are a bit different to parse
+  if(co->opt->type->flags & M_OPT_TYPE_HAS_CHILD) {
+    char** lst = NULL;
+    int i,sr;
+    // Parse the child options
+    r = m_option_parse(co->opt,arg,param,&lst,config->mode);
+    // Set them now
+    for(i = 0 ; lst && lst[2*i] ; i++) {
+      int l = strlen(co->name) + 1 + strlen(lst[2*i]) + 1;
+      if(r >= 0) {
+	// Build the full name
+	char n[l];
+	sprintf(n,"%s:%s",co->name,lst[2*i]);
+	sr = m_config_parse_option(config,n,lst[2*i+1],set);
+	if(sr < 0) r = sr;
+      }
+      free(lst[2*i]);
+      free(lst[2*i+1]);
+    }
+    if(lst) free(lst);      
+  } else
+    r = m_option_parse(co->opt,arg,param,set ? co->slots->data : NULL,config->mode);
+
+  // Parsing failed ?
+  if(r < 0)
+    return r;
+  // Set the option
+  if(set) {
+    m_option_set(co->opt,co->opt->p,co->slots->data);
+    co->flags = 1;
+  }
+
+  return r;
+}
+
+int
+m_config_set_option(m_config_t *config, char* arg, char* param) {
+  mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Setting %s=%s\n",arg,param);
+  return m_config_parse_option(config,arg,param,1);
+}
+
+int
+m_config_check_option(m_config_t *config, char* arg, char* param) {
+  mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Checking %s=%s\n",arg,param);
+  return m_config_parse_option(config,arg,param,0);
+}
+
+
+m_option_t*
+m_config_get_option(m_config_t *config, char* arg) {
+  m_config_option_t *co;
+
+#ifdef MP_DEBUG
+  assert(config != NULL);
+  assert(config->lvl > 0);
+  assert(arg != NULL);
+#endif
+
+  co = m_config_get_co(config,arg);
+  if(co)
+    return co->opt;
+  else
+    return NULL;
+}
+
+void*
+m_config_get_option_ptr(m_config_t *config, char* arg) {
+  m_option_t* conf;
+
+#ifdef MP_DEBUG
+  assert(config != NULL);
+  assert(arg != NULL);
+#endif
+
+  conf = m_config_get_option(config,arg);
+  if(!conf) return NULL;
+  return conf->p;
+}
+
+void
+m_config_print_option_list(m_config_t *config) {
+  char min[50],max[50];
+  m_config_option_t* co;
+  int count = 0;
+
+  if(!config->opts) return;
+
+  printf("\n Name                 Type            Min        Max      Global  CL    Cfg\n\n");
+  for(co = config->opts ; co ; co = co->next) {
+    m_option_t* opt = co->opt;
+    if(opt->type->flags & M_OPT_TYPE_HAS_CHILD) continue;
+    if(opt->flags & M_OPT_MIN)
+      sprintf(min,"%-8.0f",opt->min);
+    else
+      strcpy(min,"No");
+    if(opt->flags & M_OPT_MAX)
+      sprintf(max,"%-8.0f",opt->max);
+    else
+      strcpy(max,"No");
+    printf(" %-20.20s %-15.15s %-10.10s %-10.10s %-3.3s   %-3.3s   %-3.3s\n",
+	   co->name,
+	   co->opt->type->name,
+	   min,
+	   max,
+	   opt->flags & CONF_GLOBAL ? "Yes" : "No",
+	   opt->flags & CONF_NOCMD ? "No" : "Yes",
+	   opt->flags & CONF_NOCFG ? "No" : "Yes");
+    count++;
+  }
+  printf("\nTotal: %d options\n",count);
+}
+
+#endif // NEW_CONFIG
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m_config.h	Tue Nov 12 01:56:42 2002 +0000
@@ -0,0 +1,87 @@
+
+#ifndef NEW_CONFIG
+#warning "Including m_config.h but NEW_CONFIG is disabled"
+#else
+
+typedef struct m_config_option m_config_option_t;
+typedef struct m_config_save_slot m_config_save_slot_t;
+struct m_option;
+struct m_option_type;
+
+struct m_config_save_slot {
+  m_config_save_slot_t* prev;
+  int lvl;
+  unsigned char data[0];
+};
+
+struct m_config_option {
+  m_config_option_t* next;
+  char* name; // Full name (ie option:subopt)
+  struct m_option* opt;
+  m_config_save_slot_t* slots;
+  unsigned int flags; // currently it only tell if the option was set
+};
+
+typedef struct m_config {
+  m_config_option_t* opts;
+  int lvl; // Current stack level
+  int mode;
+} m_config_t;
+
+
+//////////////////////////// Functions ///////////////////////////////////
+
+m_config_t*
+m_config_new(void);
+
+void
+m_config_free(m_config_t* config);
+
+void
+m_config_push(m_config_t* config);
+
+void
+m_config_pop(m_config_t* config);
+
+int
+m_config_register_options(m_config_t *config, struct m_option *args);
+
+int
+m_config_set_option(m_config_t *config, char* arg, char* param);
+
+int
+m_config_check_option(m_config_t *config, char* arg, char* param);
+
+struct m_option*
+m_config_get_option(m_config_t *config, char* arg);
+
+/////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////// Backward compat. stuff ////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+
+typedef struct config config_t;
+struct config {
+  char *name;
+  void *p; 
+  struct m_option_type* type;
+  unsigned int flags;
+  float min,max;
+  void* priv;
+};
+
+
+#define CONF_MIN		(1<<0)
+#define CONF_MAX		(1<<1)
+#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)
+#define CONF_OLD		(1<<6)
+
+#define ERR_NOT_AN_OPTION	 -1
+#define ERR_MISSING_PARAM	 -2
+#define ERR_OUT_OF_RANGE	 -3
+#define ERR_FUNC_ERR	 -4
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m_option.c	Tue Nov 12 01:56:42 2002 +0000
@@ -0,0 +1,1008 @@
+
+#include "config.h"
+
+#ifdef NEW_CONFIG
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <inttypes.h>
+
+#include "m_option.h"
+//#include "m_config.h"
+#include "mp_msg.h"
+
+// Default function that just do a memcpy
+
+static void copy_opt(m_option_t* opt,void* dst,void* src) {
+  if(dst && src)
+    memcpy(dst,src,opt->type->size);
+}
+
+// Helper for the print funcs (from man printf)
+static char* dup_printf(const char *fmt, ...) {       
+  /* Guess we need no more than 50 bytes. */
+  int n, size = 50;
+  char *p;
+  va_list ap;
+  if ((p = malloc (size)) == NULL)
+    return NULL;
+  while (1) {
+    /* Try to print in the allocated space. */
+    va_start(ap, fmt);
+    n = vsnprintf (p, size, fmt, ap);
+    va_end(ap);
+    /* If that worked, return the string. */
+    if (n > -1 && n < size)      
+      return p;
+    /* Else try again with more space. */
+    if (n > -1)    /* glibc 2.1 */
+      size = n+1; /* precisely what is needed */
+    else           /* glibc 2.0 */
+      size *= 2;  /* twice the old size */
+    if ((p = realloc (p, size)) == NULL)
+      return NULL;
+  }
+}
+
+
+// Flag
+
+#define VAL(x) (*(int*)(x))
+
+static int parse_flag(m_option_t* opt,char *name, char *param, void* dst, int src) {
+  if (src == M_CONFIG_FILE) {
+    if (!strcasecmp(param, "yes") ||	/* any other language? */
+	!strcasecmp(param, "ja") ||
+	!strcasecmp(param, "si") ||
+	!strcasecmp(param, "igen") ||
+	!strcasecmp(param, "y") ||
+	!strcasecmp(param, "j") ||
+	!strcasecmp(param, "i") ||
+	!strcmp(param, "1")) {
+      if(dst) VAL(dst) = opt->max;
+    } else if (!strcasecmp(param, "no") ||
+	       !strcasecmp(param, "nein") ||
+	       !strcasecmp(param, "nicht") ||
+	       !strcasecmp(param, "nem") ||
+	       !strcasecmp(param, "n") ||
+	       !strcmp(param, "0")) {
+      if(dst) VAL(dst) = opt->min;
+    } else {
+      mp_msg(MSGT_CFGPARSER, MSGL_ERR, "invalid parameter for %s flag: %s\n",name, param);
+      return M_OPT_INVALID;
+    }
+    return 1;
+  } else {
+    if(dst) VAL(dst) = opt->max;
+    return 0;
+  }
+}
+
+static char* print_flag(m_option_t* opt,  void* val) {
+  if(VAL(val) == opt->min)
+    return strdup("no");
+  else
+    return strdup("yes");
+}
+
+m_option_type_t m_option_type_flag = {
+  "Flag",
+  "need yes or no in config files",
+  sizeof(int),
+  0,
+  parse_flag,
+  print_flag,
+  copy_opt,
+  copy_opt,
+  NULL,
+  NULL
+};
+
+// Integer
+
+static int parse_int(m_option_t* opt,char *name, char *param, void* dst, int src) {
+  long tmp_int;
+  char *endptr;
+  src = 0;
+
+  if (param == NULL)
+    return M_OPT_MISSING_PARAM;
+
+  tmp_int = strtol(param, &endptr, 0);
+  if (*endptr) {
+    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "The %s option must be an integer: %s\n",name, param);
+    return M_OPT_INVALID;
+  }
+
+  if ((opt->flags & M_OPT_MIN) && (tmp_int < opt->min)) {
+    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "The %s option must be >= %d: %s\n", name, (int) opt->min, param);
+    return M_OPT_OUT_OF_RANGE;
+  }
+
+  if ((opt->flags & M_OPT_MAX) && (tmp_int > opt->max)) {
+    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "The %s option must be <= %d: %s\n",name, (int) opt->max, param);
+    return M_OPT_OUT_OF_RANGE;
+  }
+
+  if(dst) VAL(dst) = tmp_int;
+
+  return 1;
+}
+
+static char* print_int(m_option_t* opt,  void* val) {
+  opt = NULL;
+  return dup_printf("%d",VAL(val));
+}
+
+m_option_type_t m_option_type_int = {
+  "Integer",
+  "",
+  sizeof(int),
+  0,
+  parse_int,
+  print_int,
+  copy_opt,
+  copy_opt,
+  NULL,
+  NULL
+};
+
+// Float
+
+#undef VAL
+#define VAL(x) (*(float*)(x))
+
+static int parse_float(m_option_t* opt,char *name, char *param, void* dst, int src) {
+  float tmp_float;
+  char* endptr;
+  src = 0;
+
+  if (param == NULL)
+    return M_OPT_MISSING_PARAM;
+
+  tmp_float = strtod(param, &endptr);
+
+  switch(*endptr) {
+  case ':':
+  case '/':
+    tmp_float /= strtod(endptr+1, &endptr);
+    break;
+  case '.':
+  case ',':
+    /* we also handle floats specified with
+     * non-locale decimal point ::atmos
+     */
+    if(tmp_float<0)
+      tmp_float -= 1.0/pow(10,strlen(endptr+1)) * strtod(endptr+1, &endptr);
+    else
+      tmp_float += 1.0/pow(10,strlen(endptr+1)) * strtod(endptr+1, &endptr);
+    break;
+  }
+
+  if (*endptr) {
+    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "The %s option must be a floating point "
+	   "number or a ratio (numerator[:/]denominator): %s\n",name, param);
+    return M_OPT_INVALID;
+  }
+
+  if (opt->flags & M_OPT_MIN)
+    if (tmp_float < opt->min) {
+      mp_msg(MSGT_CFGPARSER, MSGL_ERR, "The %s option must be >= %f: %s\n", name, opt->min, param);
+      return M_OPT_OUT_OF_RANGE;
+    }
+
+  if (opt->flags & M_OPT_MAX)
+    if (tmp_float > opt->max) {
+      mp_msg(MSGT_CFGPARSER, MSGL_ERR, "The %s option must be <= %f: %s\n", name, opt->max, param);
+      return M_OPT_OUT_OF_RANGE;
+    }
+
+  if(dst) VAL(dst) = tmp_float;
+  return 1;
+}
+
+static char* print_float(m_option_t* opt,  void* val) {
+  opt = NULL;
+  return dup_printf("%f",VAL(val));
+}
+
+m_option_type_t m_option_type_float = {
+  "Float",
+  "floating point number or ratio (numerator[:/]denominator)",
+  sizeof(float),
+  0,
+  parse_float,
+  print_float,
+  copy_opt,
+  copy_opt,
+  NULL,
+  NULL
+};
+
+///////////// Position
+#undef VAL
+#define VAL(x) (*(off_t*)(x))
+
+static int parse_position(m_option_t* opt,char *name, char *param, void* dst, int src) {
+  off_t tmp_off;
+  char dummy;
+
+  if (param == NULL)
+    return M_OPT_MISSING_PARAM;
+  if (sscanf(param, sizeof(off_t) == sizeof(int) ?
+	     "%d%c" : "%lld%c", &tmp_off, &dummy) != 1) {
+    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "The %s option must be an integer: %s\n",opt->name,param);
+    return M_OPT_INVALID;
+  }
+
+  if (opt->flags & M_OPT_MIN)
+    if (tmp_off < opt->min) {
+      mp_msg(MSGT_CFGPARSER, MSGL_ERR,
+	     (sizeof(off_t) == sizeof(int) ?
+	      "The %s option must be >= %d: %s\n" :
+	      "The %s option must be >= %lld: %s\n"),
+	     (off_t) opt->min, param);
+      return M_OPT_OUT_OF_RANGE;
+    }
+
+  if (opt->flags & M_OPT_MAX)
+    if (tmp_off > opt->max) {
+      mp_msg(MSGT_CFGPARSER, MSGL_ERR,
+	     (sizeof(off_t) == sizeof(int) ?
+	      "The %s option must be <= %d: %s\n" :
+	      "The %s option must be <= %lld: %s\n"),
+	     (off_t) opt->max, param);
+      return M_OPT_OUT_OF_RANGE;
+    }
+
+  if(dst)
+    VAL(dst) = tmp_off;
+  return 1;
+}
+
+static char* print_position(m_option_t* opt,  void* val) {
+  return dup_printf(sizeof(off_t) == sizeof(int) ?  "%d" : "%lld",VAL(val));
+}
+
+m_option_type_t m_option_type_position = {
+  "Position",
+  "Integer (off_t)",
+  sizeof(off_t),
+  0,
+  parse_position,
+  print_position,
+  copy_opt,
+  copy_opt,
+  NULL,
+  NULL
+};
+
+
+///////////// String
+
+#undef VAL
+#define VAL(x) (*(char**)(x))
+
+static int parse_str(m_option_t* opt,char *name, char *param, void* dst, int src) {
+  
+
+  if (param == NULL)
+      return M_OPT_MISSING_PARAM;
+
+  if ((opt->flags & M_OPT_MIN) && (strlen(param) < opt->min)) {
+    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "parameter must be >= %d chars: %s\n",
+	   (int) opt->min, param);
+    return M_OPT_OUT_OF_RANGE;
+  }
+
+  if ((opt->flags & M_OPT_MAX) && (strlen(param) > opt->max)) {
+    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "parameter must be <= %d chars: %s\n",
+	   (int) opt->max, param);
+    return M_OPT_OUT_OF_RANGE;
+  }
+
+  if(dst) {
+    if(VAL(dst))
+      free(VAL(dst));
+    VAL(dst) = strdup(param);
+  }
+
+  return 1;
+
+}
+
+static char* print_str(m_option_t* opt,  void* val) {
+  return (val && VAL(val) && strlen(VAL(val)) > 0) ? strdup(VAL(val)) : strdup("(empty)");
+}
+
+static void copy_str(m_option_t* opt,void* dst, void* src) {
+  if(dst && src) {
+    if(VAL(dst)) free(VAL(dst));
+    VAL(dst) = VAL(src) ? strdup(VAL(src)) : NULL;
+  }
+}
+  
+static void free_str(void* src) {
+  if(src && VAL(src)){ 
+    free(VAL(src));
+    VAL(src) = NULL;
+  }
+}
+
+m_option_type_t m_option_type_string = {
+  "String",
+  "",
+  sizeof(char*),
+  M_OPT_TYPE_DYNAMIC,
+  parse_str,
+  print_str,
+  copy_str,
+  copy_str,
+  copy_str,
+  free_str
+};
+  
+//////////// String list
+
+#define LIST_SEPARATOR ','
+#undef VAL
+#define VAL(x) (*(char***)(x))
+
+#define OP_NONE 0
+#define OP_ADD 1
+#define OP_PRE 2
+#define OP_DEL 3
+#define OP_CLR 4
+
+static void free_str_list(void* dst) {
+  char** d;
+  int i;
+
+  if(!dst || !VAL(dst)) return;
+  d = VAL(dst);
+
+
+  for(i = 0 ; d[i] != NULL ; i++)
+    free(d[i]);
+  free(d);
+  VAL(dst) = NULL;
+}
+
+static int str_list_add(char** add, int n,void* dst,int pre) {
+  char** lst = VAL(dst);
+  int ln;
+
+  if(!dst) return M_OPT_PARSER_ERR;
+  lst = VAL(dst);
+
+  for(ln = 0 ; lst && lst[ln] ; ln++)
+    /**/;
+
+  lst = realloc(lst,(n+ln+1)*sizeof(char*));
+  
+  if(pre) {
+    memmove(&lst[n],lst,(ln+1)*sizeof(char*));
+    memcpy(lst,add,n*sizeof(char*));
+  } else 
+    memcpy(&lst[ln],add,(n+1)*sizeof(char*));
+
+  free(add);
+
+  VAL(dst) = lst;
+  
+  return 1;
+}
+
+static int str_list_del(char** del, int n,void* dst) {
+  char **lst,*ep,**d;
+  int i,ln,s;
+  long idx;
+  
+  if(!dst) return M_OPT_PARSER_ERR;
+  lst = VAL(dst);
+
+  for(ln = 0 ; lst && lst[ln] ; ln++)
+    /**/;
+  s = ln;
+
+  for(i = 0 ; del[i] != NULL ; i++) {
+    idx = strtol(del[i], &ep, 0);
+    if(*ep) {
+      mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Invalid index: %s\n",del[i]);
+      free(del[i]);
+      continue;
+    }
+    free(del[i]);
+    if(idx < 0 || idx >= ln) {
+      mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Index %d is out of range\n",idx);
+      continue;
+    } else if(!lst[idx])
+      continue;
+    free(lst[idx]);
+    lst[idx] = NULL;
+    s--;
+  }
+  free(del);
+
+  if(s == 0) {
+    if(lst) free(lst);
+    VAL(dst) = NULL;
+    return 1;
+  }
+
+  d = calloc(s+1,sizeof(char*));
+  for(i = 0, n = 0 ; i < ln ; i++) {
+    if(!lst[i]) continue;
+    d[n] = lst[i];
+    n++;
+  }
+  d[s] = NULL;
+
+  if(lst) free(lst);
+  VAL(dst) = d;
+
+  return 1;
+}
+  
+
+static int parse_str_list(m_option_t* opt,char *name, char *param, void* dst, int src) {
+  int n = 0,len = strlen(opt->name);
+  char *ptr = param, *last_ptr, **res;
+  int op = OP_NONE;
+
+  if(opt->name[len-1] == '*' && ((int)strlen(name) > len - 1)) {
+    char* n = &name[len-1];
+    if(strcasecmp(n,"-add") == 0)
+      op = OP_ADD;
+    else if(strcasecmp(n,"-pre") == 0)
+      op = OP_PRE;
+    else if(strcasecmp(n,"-del") == 0)
+      op = OP_DEL;
+    else if(strcasecmp(n,"-clr") == 0)
+      op = OP_CLR;
+    else
+      return M_OPT_UNKNOW;
+  }
+
+  // Clear the list ??
+  if(op == OP_CLR) {
+    if(dst)
+      free_str_list(dst);
+    return 0;
+  }
+
+  // All other op need a param
+  if (param == NULL || strlen(param) == 0)
+      return M_OPT_MISSING_PARAM;
+
+
+  while(ptr[0] != '\0') {
+    last_ptr = ptr;
+    ptr = strchr(ptr,LIST_SEPARATOR);
+    if(!ptr) {
+      n++;
+      break;
+    }
+    ptr++;
+    n++;
+  }
+  if(n == 0)
+    return M_OPT_INVALID;
+  if( ((opt->flags & M_OPT_MIN) && (n < opt->min)) || 
+      ((opt->flags & M_OPT_MAX) && (n > opt->max)) )
+    return M_OPT_OUT_OF_RANGE;
+
+  if(!dst) return 1;
+
+  res = malloc((n+1)*sizeof(char*));
+  ptr = param;
+  n = 0;
+
+  while(1) {
+    last_ptr = ptr;
+    ptr = strchr(ptr,LIST_SEPARATOR);
+    if(!ptr) {
+      res[n] = strdup(last_ptr);
+      n++;
+      break;
+    }
+    len = ptr - last_ptr;
+    res[n] = (char*)malloc(len + 1);
+    if(len) strncpy(res[n],last_ptr,len);
+    res[n][len] = '\0';
+    ptr++;
+    n++;
+  }
+  res[n] = NULL;
+
+  switch(op) {
+  case OP_ADD:
+    return str_list_add(res,n,dst,0);
+  case OP_PRE:
+    return str_list_add(res,n,dst,1);
+  case OP_DEL:
+    return str_list_del(res,n,dst);
+  }
+
+  if(VAL(dst))
+    free_str_list(dst);
+  VAL(dst) = res;
+
+  return 1;
+}
+  
+static void copy_str_list(m_option_t* opt,void* dst, void* src) {
+  int n;
+  char **d,**s;
+
+  if(!(dst && src)) return;
+  s = VAL(src);
+
+  if(VAL(dst))
+    free_str_list(dst);
+
+  if(!s) {
+    VAL(dst) = NULL;
+    return;
+  }
+
+  for(n = 0 ; s[n] != NULL ; n++)
+    /* NOTHING */;
+  d = (char**)malloc((n+1)*sizeof(char*));
+  for( ; n >= 0 ; n--)
+    d[n] = s[n] ? strdup(s[n]) : NULL;
+
+  VAL(dst) = d;
+}
+
+static char* print_str_list(m_option_t* opt, void* src) {
+  return strdup("TODO ;)");
+}
+
+m_option_type_t m_option_type_string_list = {
+  "String list",
+  "A list of string separated by ','\n"
+  "Option with name that finish by an * allow to use the following suffix : \n"
+  "\t-add : add the given parameters at the end of list\n"
+  "\t-pre : add the given parameters at the begining of list\n"
+  "\t-del : remove the entry at the given indexs\n"
+  "\t-clr : clear the list\n"
+  "e.g: -vop-add flip,mirror -vop-del 2,5\n",  
+  sizeof(char**),
+  M_OPT_TYPE_DYNAMIC | M_OPT_TYPE_ALLOW_WILDCARD,
+  parse_str_list,
+  print_str_list,
+  copy_str_list,
+  copy_str_list,
+  copy_str_list,
+  free_str_list
+};
+ 
+ 
+///////////////////  Func based options
+
+// A chained list to save the various calls for func_param and func_full
+typedef struct m_func_save m_func_save_t;
+struct m_func_save {
+  m_func_save_t* next;
+  char* name;
+  char* param;
+};
+
+#undef VAL
+#define VAL(x) (*(m_func_save_t**)(x))
+
+static void free_func_pf(void* src) {
+  m_func_save_t *s,*n;
+
+  if(!src) return;
+
+  s = VAL(src);
+  
+  while(s) {
+    n = s->next;
+    free(s->name);
+    if(s->param) free(s->param);
+    free(s);
+    s = n;
+  }
+  VAL(src) = NULL;
+}
+
+// Parser for func_param and func_full
+static int parse_func_pf(m_option_t* opt,char *name, char *param, void* dst, int src) {
+  m_func_save_t *s,*p;
+
+  if(!dst)
+    return 1;
+
+  s = (m_func_save_t*)calloc(1,sizeof(m_func_save_t));
+  s->name = strdup(name);
+  s->param = param ? strdup(param) : NULL;
+
+  p = VAL(dst);
+  if(p) {
+    for( ; p->next != NULL ; p = p->next)
+      /**/;
+    p->next = s;
+  } else
+    VAL(dst) = s;
+
+  return 1;
+}
+
+static void copy_func_pf(m_option_t* opt,void* dst, void* src) {
+  m_func_save_t *d = NULL, *s,* last = NULL;
+
+  if(!(dst && src)) return;
+  s = VAL(src);
+
+  if(VAL(dst))
+    free_func_pf(dst);
+
+  while(s) {
+    d = (m_func_save_t*)malloc(sizeof(m_func_save_t));
+    d->name = strdup(s->name);
+    d->param = s->param ? strdup(s->param) : NULL;
+    if(last)
+      last->next = d;
+    else
+      VAL(dst) = d;
+    last = d;
+    s = s->next;
+  }
+  
+    
+}
+
+/////////////////// Func_param
+
+static void set_func_param(m_option_t* opt, void* dst, void* src) {
+  m_func_save_t* s;
+
+  if(!src) return;
+  s = VAL(src);
+  
+  if(!s) return;
+
+  // Revert if needed
+  if(opt->priv) ((m_opt_default_func_t)opt->priv)(opt,opt->name);
+  for( ; s != NULL ; s = s->next)
+    ((m_opt_func_param_t) opt->p)(opt,s->param);
+}
+
+m_option_type_t m_option_type_func_param = {
+  "Func param",
+  "",
+  sizeof(m_func_save_t*),
+  M_OPT_TYPE_INDIRECT,
+  parse_func_pf,
+  NULL,
+  NULL, // Nothing to do on save
+  set_func_param,
+  copy_func_pf,
+  free_func_pf
+};
+
+/////////////////// Func_full
+
+static void set_func_full(m_option_t* opt, void* dst, void* src) {
+  m_func_save_t* s;
+
+  if(!src) return;
+
+  for(s = VAL(src) ; s ; s = s->next) {
+    // Revert if needed
+    if(opt->priv) ((m_opt_default_func_t)opt->priv)(opt,s->name);
+    ((m_opt_func_full_t) opt->p)(opt,s->name,s->param);
+  }
+}
+
+m_option_type_t m_option_type_func_full = {
+  "Func full",
+  "",
+  sizeof(m_func_save_t*),
+  M_OPT_TYPE_ALLOW_WILDCARD|M_OPT_TYPE_INDIRECT,
+  parse_func_pf,
+  NULL,
+  NULL, // Nothing to do on save
+  set_func_full,
+  copy_func_pf,
+  free_func_pf
+};
+
+/////////////// Func
+
+#undef VAL
+#define VAL(x) (*(int*)(x))
+
+static int parse_func(m_option_t* opt,char *name, char *param, void* dst, int src) {
+  if(dst)
+    VAL(dst) += 1;
+  return 0;
+}
+
+static void set_func(m_option_t* opt,void* dst, void* src) {
+  int i;
+  if(opt->priv) ((m_opt_default_func_t)opt->priv)(opt,opt->name);
+  for(i = 0 ; i < VAL(src) ; i++)
+    ((m_opt_func_t) opt->p)(opt);
+}
+
+m_option_type_t m_option_type_func = {
+  "Func",
+  "",
+  sizeof(int),
+  M_OPT_TYPE_INDIRECT,
+  parse_func,
+  NULL,
+  NULL, // Nothing to do on save
+  set_func,
+  NULL,
+  NULL
+};
+
+/////////////////// Print
+
+static int parse_print(m_option_t* opt,char *name, char *param, void* dst, int src) {
+  mp_msg(MSGT_CFGPARSER, MSGL_INFO, "%s", (char *) opt->p);
+  if(opt->priv == NULL)
+    exit(1); // Call something else instead ??
+  return 1;
+}
+
+m_option_type_t m_option_type_print = {
+  "Print",
+  "",
+  0,
+  0,
+  parse_print,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL
+};
+
+/////////////////////// Subconfig
+#undef VAL
+#define VAL(x) (*(char***)(x))
+
+static int parse_subconf(m_option_t* opt,char *name, char *param, void* dst, int src) {
+  char *subparam;
+  char *subopt;
+  int nr = 0;
+  m_option_t *subopts;
+  char *token;
+  char *p;
+  char** lst = NULL;
+
+  if (param == NULL || strlen(param) == 0)
+    return M_OPT_MISSING_PARAM;
+
+  subparam = malloc(strlen(param)+1);
+  subopt = malloc(strlen(param)+1);
+  p = strdup(param); // In case that param is a static string (cf man strtok)
+
+  subopts = opt->p;
+
+  token = strtok(p, (char *)&(":"));
+  while(token)
+    {
+      int sscanf_ret;
+      /* clear out */
+      subopt[0] = subparam[0] = 0;
+			    
+      sscanf_ret = sscanf(token, "%[^=]=%[^:]", subopt, subparam);
+
+      mp_msg(MSGT_CFGPARSER, MSGL_DBG3, "token: '%s', subopt='%s', subparam='%s' (ret: %d)\n", token, subopt, subparam, sscanf_ret);
+      switch(sscanf_ret)
+	{
+	case 1:
+	  subparam[0] = 0;
+	case 2:
+	  if(dst) {
+	    lst = (char**)realloc(lst,2 * (nr+2) * sizeof(char*));
+	    lst[2*nr] = strdup(subopt);
+	    lst[2*nr+1] = subparam[0] == 0 ? NULL : strdup(subparam);
+	    memset(&lst[2*(nr+1)],0,2*sizeof(char*));
+	    nr++;
+	  }
+	  break;
+	default:
+	  mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Invalid subconfig argument! ('%s')\n", token);
+	  return M_OPT_INVALID;
+	}
+      token = strtok(NULL, (char *)&(":"));
+    }
+
+  free(subparam);
+  free(subopt);
+  free(p);
+  VAL(dst) = lst;
+
+  return 1;
+}
+
+m_option_type_t m_option_type_subconfig = {
+  "Subconfig",
+  "The syntax is -option opt1=foo:flag:opt2=blah",
+  sizeof(int),
+  M_OPT_TYPE_HAS_CHILD,
+  parse_subconf,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL
+};
+
+#include "libmpcodecs/img_format.h"
+// TODO : use an array so we parse/print easily
+
+static int parse_imgfmt(m_option_t* opt,char *name, char *param, void* dst, int src) {
+  uint32_t fmt = 0;
+
+  if (param == NULL || strlen(param) == 0)
+    return M_OPT_MISSING_PARAM;
+
+  // From vf_format
+  if(!strcasecmp(param,"444p")) fmt=IMGFMT_444P; else
+  if(!strcasecmp(param,"422p")) fmt=IMGFMT_422P; else
+  if(!strcasecmp(param,"411p")) fmt=IMGFMT_411P; else
+  if(!strcasecmp(param,"yuy2")) fmt=IMGFMT_YUY2; else
+  if(!strcasecmp(param,"yv12")) fmt=IMGFMT_YV12; else
+  if(!strcasecmp(param,"i420")) fmt=IMGFMT_I420; else
+  if(!strcasecmp(param,"yvu9")) fmt=IMGFMT_YVU9; else
+  if(!strcasecmp(param,"if09")) fmt=IMGFMT_IF09; else
+  if(!strcasecmp(param,"iyuv")) fmt=IMGFMT_IYUV; else
+  if(!strcasecmp(param,"uyvy")) fmt=IMGFMT_UYVY; else
+  if(!strcasecmp(param,"bgr24")) fmt=IMGFMT_BGR24; else
+  if(!strcasecmp(param,"bgr32")) fmt=IMGFMT_BGR32; else
+  if(!strcasecmp(param,"bgr16")) fmt=IMGFMT_BGR16; else
+  if(!strcasecmp(param,"bgr15")) fmt=IMGFMT_BGR15; else
+  if(!strcasecmp(param,"bgr8")) fmt=IMGFMT_BGR8; else
+  if(!strcasecmp(param,"bgr4")) fmt=IMGFMT_BGR4; else
+  if(!strcasecmp(param,"bgr1")) fmt=IMGFMT_BGR1; else
+  if(!strcasecmp(param,"rgb24")) fmt=IMGFMT_RGB24; else
+  if(!strcasecmp(param,"rgb32")) fmt=IMGFMT_RGB32; else
+  if(!strcasecmp(param,"rgb16")) fmt=IMGFMT_RGB16; else
+  if(!strcasecmp(param,"rgb15")) fmt=IMGFMT_RGB15; else
+  if(!strcasecmp(param,"rgb8")) fmt=IMGFMT_RGB8; else
+  if(!strcasecmp(param,"rgb4")) fmt=IMGFMT_RGB4; else
+  if(!strcasecmp(param,"rgb1")) fmt=IMGFMT_RGB1; else { 
+    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: unknown format name: '%s'\n",param);
+    return M_OPT_INVALID;
+  }
+
+  if(dst)
+    *((uint32_t*)dst) = fmt;
+
+  return 1;
+}
+
+m_option_type_t m_option_type_imgfmt = {
+  "Image format (aka colorspace)",
+  "Pls report any missing colorspace",
+  sizeof(uint32_t),
+  0,
+  parse_imgfmt,
+  NULL,
+  copy_opt,
+  copy_opt,
+  NULL,
+  NULL
+};
+
+/// Span stuff : Not finished
+static int parse_play_pos(m_play_pos_t* pos,char* opt, char *s) {
+  char *ep;
+  long tmp;
+  int i;
+
+  memset(pos,0,sizeof(m_play_pos_t));
+
+  if(!s || s[0] == '\0')
+    return M_OPT_MISSING_PARAM;
+
+  // Track index
+  tmp = strtol(s, &ep, 0);
+  if(ep != s) {
+    if(tmp < 1) {
+      mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: Track/Chapter index must be > 0\n", opt);
+      return M_OPT_OUT_OF_RANGE;
+    }
+    pos->idx = tmp;
+    if(ep[0] == '\0')
+      return 1;
+    s = ep;
+  }
+
+  // Span
+  tmp = strlen(s);
+  if(s[0] != '[' || s[tmp-1] != ']') {
+    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: invalid argument ?\n", opt);
+    return M_OPT_INVALID;
+  }
+  s[tmp-1] = '\0';
+  s++;
+
+  // hh:mm:ss
+  for( i = 2 ; i >= 0 && s[0] != 0 ; i--) {
+    if(s[0] == ':') {
+      tmp = 0;
+      s++;
+    } else {
+      tmp = strtol(s, &ep, 0);
+      if(tmp < 0 || (ep[0] != '\0' && ep[0] != (i > 0 ? ':' : '.') )) {
+	mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: invalid argument ?\n", opt);
+	return M_OPT_INVALID;
+      }
+      pos->seconds += tmp * pow(60,i);
+      s = ep;
+      if(s[0] != '\0')
+	s++;
+
+    }
+  }
+
+  // sectors
+  if(s[0]) {
+    tmp = strtol(s, &ep, 0);
+    if(tmp < 0 || ep[0] != '\0') {
+      mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: invalid argument ?\n", opt);
+      return M_OPT_INVALID;
+    }
+    pos->sectors = tmp;
+  }
+
+  return 1;
+}
+
+
+static int parse_span(m_option_t* opt,char *name, char *param, void* dst, int src) {
+  m_span_t* span = dst;
+  char *s = param,*e = NULL;
+  int r = M_OPT_INVALID;
+
+  if(param == NULL)
+    return M_OPT_MISSING_PARAM;
+
+  e = strchr(param,'-');
+  if(e) {
+    e[0] = '\0';
+    e++;
+  }
+
+  if(s[0] == '\0' && e[0] == '\0') {
+    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Option %s: invalid argument\n");
+    return M_OPT_INVALID;
+  }
+
+  if(s[0]) {
+    r = parse_play_pos(&span->start,name,s);
+    if(r < 0) return r;
+  }
+  if(e && e[0] != '\0')
+    r = parse_play_pos(&span->end,name,s);
+  
+  return r;  
+}
+
+m_option_type_t m_option_type_span = {
+  "Span",
+  "The syntax is 1[hh:mm:ss.zz]-5[hh:mm:ss.zz]",
+  sizeof(m_span_t),
+  0,
+  parse_span,
+  NULL,
+  copy_opt,
+  copy_opt,
+  NULL,
+  NULL
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m_option.h	Tue Nov 12 01:56:42 2002 +0000
@@ -0,0 +1,222 @@
+
+#ifndef NEW_CONFIG
+#warning "Including m_option.h but NEW_CONFIG is disabled"
+#else
+
+typedef struct m_option_type m_option_type_t;
+typedef struct m_option m_option_t;
+
+///////////////////////////// Options types declarations ////////////////////////////
+
+// Simple types
+extern m_option_type_t m_option_type_flag;
+extern m_option_type_t m_option_type_int;
+extern m_option_type_t m_option_type_float;
+extern m_option_type_t m_option_type_string;
+extern m_option_type_t m_option_type_string_list;
+extern m_option_type_t m_option_type_position;
+
+extern m_option_type_t m_option_type_print;
+extern m_option_type_t m_option_type_subconfig;
+extern m_option_type_t m_option_type_imgfmt;
+
+// Func based types 
+extern m_option_type_t m_option_type_func_full;
+extern m_option_type_t m_option_type_func_param;
+extern m_option_type_t m_option_type_func;
+
+typedef void (*m_opt_default_func_t)(m_option_t *, char*);
+typedef int (*m_opt_func_full_t)(m_option_t *, char *, char *);
+typedef int (*m_opt_func_param_t)(m_option_t *, char *);
+typedef int (*m_opt_func_t)(m_option_t *);
+///////////// Backward compat
+typedef m_opt_default_func_t cfg_default_func_t;
+typedef m_opt_func_full_t cfg_func_arg_param_t;
+typedef m_opt_func_param_t cfg_func_param_t;
+typedef m_opt_func_t cfg_func_t;
+
+// Track/Chapter range
+// accept range in the form 1[hh:mm:ss.zz]-5[hh:mm:ss.zz]
+// ommited fields are assumed to be 0
+// Not finished !!!!
+typedef struct {
+  int idx; // in the e.g 1 or 5
+  unsigned int seconds; // hh:mm:ss converted in seconds
+  unsigned int sectors; // zz
+} m_play_pos_t;
+
+typedef struct {
+  m_play_pos_t start;
+  m_play_pos_t end;
+} m_span_t;
+extern m_option_type_t m_option_type_span;
+
+// Don't be stupid keep tho old names ;-)
+#define CONF_TYPE_FLAG		(&m_option_type_flag)
+#define CONF_TYPE_INT		(&m_option_type_int)
+#define CONF_TYPE_FLOAT		(&m_option_type_float)
+#define CONF_TYPE_STRING		(&m_option_type_string)
+#define CONF_TYPE_FUNC		(&m_option_type_func)
+#define CONF_TYPE_FUNC_PARAM	(&m_option_type_func_param)
+#define CONF_TYPE_PRINT		(&m_option_type_print)
+#define CONF_TYPE_FUNC_FULL	(&m_option_type_func_full)
+#define CONF_TYPE_SUBCONFIG	(&m_option_type_subconfig)
+#define CONF_TYPE_STRING_LIST           (&m_option_type_string_list)
+#define CONF_TYPE_POSITION	(&m_option_type_position)
+#define CONF_TYPE_IMGFMT		(&m_option_type_imgfmt)
+#define CONF_TYPE_SPAN		(&m_option_type_span)
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////
+
+struct m_option_type {
+  char* name;
+  char* comments; // syntax desc, etc
+  unsigned int size; // size needed for a save slot
+  unsigned int flags;
+
+  // parse is the only requiered function all others can be NULL
+  // If dst if non-NULL it should create/update the save slot
+  // If dst is NULL it should just test the validity of the arg if possible
+  // Src tell from where come this setting (ie cfg file, command line, playlist, ....
+  // It should return 1 if param was used, 0 if not.
+  // On error it must return 1 of the error code below
+  int (*parse)(m_option_t* opt,char *name, char *param, void* dst, int src);
+  // Print back a value in human form
+  char* (*print)(m_option_t* opt,  void* val);
+
+  // These 3 will be a memcpy in 50% of the case, it's called to save/restore the status of
+  // the var it's there for complex type like CONF_TYPE_FUNC*
+  // update a save slot (dst) from the current value in the prog (src)
+  void (*save)(m_option_t* opt,void* dst, void* src);
+  // set the current value (dst) from a save slot
+  void (*set)(m_option_t* opt,void* dst, void* src);
+  // Copy betewen 2 slot (if NULL and size > 0 a memcpy will be used
+  void (*copy)(m_option_t* opt,void* dst, void* src);
+  // Free the data allocated for a save slot if needed
+  void (*free)(void* dst);
+};
+
+/// This is the same thing as a struct config it have been renamed
+/// to remove this config_t, m_config_t mess. Sorry about that,
+/// config_t is still provided for backward compat.
+struct m_option {
+  char *name;
+  void *p; 
+  m_option_type_t* type;
+  unsigned int flags;
+  float min,max;
+  // This used to be function pointer to hold a 'reverse to defaults' func.
+  // Nom it can be used to pass any type of extra args.
+  // Passing a 'default func' is still valid for all func based option types
+  void* priv; // Type dependent data (for all kind of extended setting)
+};
+
+
+//////////////////////////////// Option flags /////////////////////////////////
+
+// Option flags
+#define M_OPT_MIN		(1<<0)
+#define M_OPT_MAX		(1<<1)
+#define M_OPT_RANGE		(M_OPT_MIN|M_OPT_MAX)
+#define M_OPT_NOCFG		(1<<2)
+#define M_OPT_NOCMD		(1<<3)
+// This option is global : it won't be saved on push and the command
+// line parser will set it when it's parsed (ie. it won't be set later)
+// e.g options : -v, -quiet
+#define M_OPT_GLOBAL		(1<<4)
+// Do not save this option : it won't be saved on push but the command
+// line parser will put it with it's entry (ie : it may be set later)
+// e.g options : -include
+#define M_OPT_NOSAVE		(1<<5)
+// Emulate old behaviour by pushing the option only if it was set by the user
+#define M_OPT_OLD		(1<<6)
+
+
+///////////////////////////// Option type flags ///////////////////////////////////
+
+// These flags are for the parsers. The description here apply to the m_config_t
+// based parsers (ie. cmd line and config file parsers)
+// Some parser will refuse option types that have some of these flags
+
+// This flag is used for the subconfig
+// When this flag is set, opt->p should point to another m_option_t array
+// Only the parse function will be called. If dst is set, it should create/update
+// an array of char* containg opt/val pairs.
+// Then the options in the child array will then be set automaticly.
+// You can only affect the way suboption are parsed.
+// Also note that suboptions may be directly accessed by using -option:subopt blah :-)
+#define M_OPT_TYPE_HAS_CHILD		(1<<0)
+// If this flag is set the option type support option name with * at the end (used for -aa*)
+// This only affect the option name matching, the option type have to implement
+// the needed stuff.
+#define M_OPT_TYPE_ALLOW_WILDCARD	(1<<1)
+// This flag indicate that the data is dynamicly allocated (opt->p point to a pointer)
+// It enable a little hack wich replace the initial value by a dynamic copy
+// in case the initial value is staticly allocated (pretty common with strings)
+#define M_OPT_TYPE_DYNAMIC		(1<<2)
+/// If this is set the parse function doesn't directly return
+// the wanted thing. Options use this if for some reasons they have to wait
+// until the set call to be able to correctly set the target var.
+// So for those types you have to first parse and then set the target var
+// If this flag isn't set you can parse directly to the target var
+// It's used for the callback based option as the callback call may append
+// later on.
+#define M_OPT_TYPE_INDIRECT		(1<<3)
+
+
+///////////////////////////// Parser flags ////////////////////////////////////////
+
+// Config mode : some parser type behave differently depending
+// on config->mode value wich is passed in the src param of parse()
+#define M_CONFIG_FILE 0
+#define M_COMMAND_LINE 1
+
+// Option parser error code
+#define M_OPT_UNKNOW		-1
+#define M_OPT_MISSING_PARAM	-2
+#define M_OPT_INVALID		-3
+#define M_OPT_OUT_OF_RANGE	-4
+#define M_OPT_PARSER_ERR		-5
+
+
+inline static int
+m_option_parse(m_option_t* opt,char *name, char *param, void* dst, int src) {
+  return opt->type->parse(opt,name,param,dst,src);
+}
+
+inline static  char*
+m_option_print(m_option_t* opt,  void* val_ptr) {
+  if(opt->type->print)
+    return opt->type->print(opt,val_ptr);
+  else
+    return NULL;
+}
+
+inline static  void
+m_option_save(m_option_t* opt,void* dst, void* src) {
+  if(opt->type->save)
+    opt->type->save(opt,dst,src);
+}
+
+inline static  void
+m_option_set(m_option_t* opt,void* dst, void* src) {
+  if(opt->type->set)
+    opt->type->set(opt,dst,src);
+}
+
+inline  static void
+m_option_copy(m_option_t* opt,void* dst, void* src) {
+  if(opt->type->copy)
+    opt->type->set(opt,dst,src);
+  else if(opt->type->size > 0)
+    memcpy(dst,src,opt->type->size);
+}
+
+inline static void
+m_option_free(m_option_t* opt,void* dst) {
+  if(opt->type->free)
+    opt->type->free(dst);
+}
+
+#endif
--- a/mencoder.c	Tue Nov 12 00:19:14 2002 +0000
+++ b/mencoder.c	Tue Nov 12 01:56:42 2002 +0000
@@ -33,7 +33,14 @@
 #include "cpudetect.h"
 
 #include "codec-cfg.h"
+#ifdef NEW_CONFIG
+#include "m_option.h"
+#include "m_config.h"
+#include "parser-mecmd.h"
+#else
 #include "cfgparser.h"
+#include "playtree.h"
+#endif
 
 #include "libmpdemux/stream.h"
 #include "libmpdemux/demuxer.h"
@@ -41,7 +48,6 @@
 #include "libmpdemux/mp3_hdr.h"
 #include "libmpdemux/aviwrite.h"
 
-#include "playtree.h"
 
 #include "libvo/video_out.h"
 
@@ -196,6 +202,12 @@
 
 m_config_t* mconfig;
 
+#ifdef NEW_CONFIG
+extern int
+m_config_parse_config_file(m_config_t* config, char *conffile);
+#endif
+
+
 static int cfg_inc_verbose(struct config *conf){ ++verbose; return 0;}
 
 static int cfg_include(struct config *conf, char *filename){
@@ -326,8 +338,12 @@
 double v_pts_corr=0;
 double v_timer_corr=0;
 
+#ifdef NEW_CONFIG
+m_entry_t* filelist = NULL;
+#else
 play_tree_t* playtree;
 play_tree_iter_t* playtree_iter;
+#endif
 char* filename=NULL;
 char* frameno_filename="frameno.avi";
 
@@ -357,13 +373,24 @@
   }
 }
 
-  // FIXME: get rid of -dvd and other tricky options and config/playtree
+  // FIXME: get rid of -dvd and other tricky options
   stream2=open_stream(frameno_filename,0,&i);
   if(stream2){
     demuxer2=demux_open(stream2,DEMUXER_TYPE_AVI,-1,-1,-2);
     if(demuxer2) printf(MSGTR_UsingPass3ControllFile,frameno_filename);
   }
 
+  // New config code
+#ifdef NEW_CONFIG
+ mconfig = m_config_new();
+ m_config_register_options(mconfig,mencoder_opts);
+ parse_cfgfiles(mconfig);
+ filelist = m_config_parse_me_command_line(mconfig, argc, argv);
+ if(!filelist) mencoder_exit(1, "error parsing cmdline");
+ m_entry_set_options(mconfig,&filelist[0]);
+ filename = filelist[0].name;
+ // Warn the user if he put more than 1 filename ?
+#else
   playtree = play_tree_new();
   mconfig = m_config_new(playtree);
   m_config_register_options(mconfig,mencoder_opts);
@@ -381,6 +408,7 @@
       filename = play_tree_iter_get_file(playtree_iter,1);
     }
   }
+#endif
 
   if(!filename && !vcd_track && !dvd_title && !tv_param_on){
 	printf(MSGTR_MissingFilename);
--- a/mplayer.c	Tue Nov 12 00:19:14 2002 +0000
+++ b/mplayer.c	Tue Nov 12 01:56:42 2002 +0000
@@ -26,7 +26,12 @@
 #define HELP_MP_DEFINE_STATIC
 #include "help_mp.h"
 
+#ifdef NEW_CONFIG
+#include "m_option.h"
+#include "m_config.h"
+#else
 #include "cfgparser.h"
+#endif
 #include "cfg-mplayer-def.h"
 
 #ifdef USE_SUB
@@ -101,6 +106,13 @@
 
 m_config_t* mconfig;
 
+#ifdef NEW_CONFIG
+extern play_tree_t*
+m_config_parse_mp_command_line(m_config_t *config, int argc, char **argv);
+extern int
+m_config_parse_config_file(m_config_t* config, char *conffile);
+#endif
+
 //**************************************************************************//
 //             Config file
 //**************************************************************************//
@@ -584,9 +596,13 @@
       (strrchr(argv[0],'/') && !strcmp(strrchr(argv[0],'/'),"/gmplayer") ) )
           use_gui=1;
 
+#ifdef NEW_CONFIG
+    mconfig = m_config_new();
+#else
     playtree = play_tree_new();
 
     mconfig = m_config_new(playtree);
+#endif
     m_config_register_options(mconfig,mplayer_opts);
     // TODO : add something to let modules register their options
     mp_input_register_options(mconfig);
@@ -596,7 +612,13 @@
     if ( use_gui ) cfg_read();
 #endif
 
+#ifdef NEW_CONFIG
+    playtree = m_config_parse_mp_command_line(mconfig, argc, argv);
+    if(playtree == NULL)
+      exit(1);
+#else
     if(m_config_parse_command_line(mconfig, argc, argv) < 0) exit(1); // error parsing cmdline
+#endif
 
     playtree = play_tree_cleanup(playtree);
     if(playtree) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/parser-cfg.c	Tue Nov 12 01:56:42 2002 +0000
@@ -0,0 +1,211 @@
+
+#include "config.h"
+
+#ifdef NEW_CONFIG
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#ifdef MP_DEBUG
+#include <assert.h>
+#endif
+
+#include "mp_msg.h"
+#include "m_option.h"
+#include "m_config.h"
+
+#define MAX_RECURSION_DEPTH	8
+
+static int recursion_depth = 0;
+
+int m_config_parse_config_file(m_config_t* config, char *conffile)
+{
+#define PRINT_LINENUM	mp_msg(MSGT_CFGPARSER,MSGL_V,"%s(%d): ", conffile, line_num)
+#define MAX_LINE_LEN	1000
+#define MAX_OPT_LEN	100
+#define MAX_PARAM_LEN	100
+	FILE *fp;
+	char *line;
+	char opt[MAX_OPT_LEN + 1];
+	char param[MAX_PARAM_LEN + 1];
+	char c;		/* for the "" and '' check */
+	int tmp;
+	int line_num = 0;
+	int line_pos;	/* line pos */
+	int opt_pos;	/* opt pos */
+	int param_pos;	/* param pos */
+	int ret = 1;
+	int errors = 0;
+	int prev_mode = config->mode;
+
+#ifdef MP_DEBUG
+	assert(config != NULL);
+	//	assert(conf_list != NULL);
+#endif
+	mp_msg(MSGT_CFGPARSER,MSGL_INFO,"Reading config file %s", conffile);
+
+	if (recursion_depth > MAX_RECURSION_DEPTH) {
+		mp_msg(MSGT_CFGPARSER,MSGL_ERR,": too deep 'include'. check your configfiles\n");
+		ret = -1;
+		goto out;
+	} else
+	  
+	config->mode = M_CONFIG_FILE;
+
+	if ((line = (char *) malloc(MAX_LINE_LEN + 1)) == NULL) {
+		mp_msg(MSGT_CFGPARSER,MSGL_FATAL,"\ncan't get memory for 'line': %s", strerror(errno));
+		ret = -1;
+		goto out;
+	}
+
+	if ((fp = fopen(conffile, "r")) == NULL) {
+	  mp_msg(MSGT_CFGPARSER,MSGL_ERR,": %s\n", strerror(errno));
+		free(line);
+		ret = 0;
+		goto out;
+	}
+	mp_msg(MSGT_CFGPARSER,MSGL_INFO,"\n");
+
+	while (fgets(line, MAX_LINE_LEN, fp)) {
+		if (errors >= 16) {
+			mp_msg(MSGT_CFGPARSER,MSGL_FATAL,"too many errors\n");
+			goto out;
+		}
+
+		line_num++;
+		line_pos = 0;
+
+		/* skip whitespaces */
+		while (isspace(line[line_pos]))
+			++line_pos;
+
+		/* EOL / comment */
+		if (line[line_pos] == '\0' || line[line_pos] == '#')
+			continue;
+
+		/* read option. */
+		for (opt_pos = 0; isprint(line[line_pos]) &&
+				line[line_pos] != ' ' &&
+				line[line_pos] != '#' &&
+				line[line_pos] != '='; /* NOTHING */) {
+			opt[opt_pos++] = line[line_pos++];
+			if (opt_pos >= MAX_OPT_LEN) {
+				PRINT_LINENUM;
+				mp_msg(MSGT_CFGPARSER,MSGL_ERR,"too long option\n");
+				errors++;
+				ret = -1;
+				goto nextline;
+			}
+		}
+		if (opt_pos == 0) {
+			PRINT_LINENUM;
+			mp_msg(MSGT_CFGPARSER,MSGL_ERR,"parse error\n");
+			ret = -1;
+			errors++;
+			continue;
+		}
+		opt[opt_pos] = '\0';
+
+#ifdef MP_DEBUG
+		PRINT_LINENUM;
+		mp_msg(MSGT_CFGPARSER,MSGL_V,"option: %s\n", opt);
+#endif
+
+		/* skip whitespaces */
+		while (isspace(line[line_pos]))
+			++line_pos;
+
+		/* check '=' */
+		if (line[line_pos++] != '=') {
+			PRINT_LINENUM;
+			mp_msg(MSGT_CFGPARSER,MSGL_ERR,"option without parameter\n");
+			ret = -1;
+			errors++;
+			continue;
+		}
+
+		/* whitespaces... */
+		while (isspace(line[line_pos]))
+			++line_pos;
+
+		/* read the parameter */
+		if (line[line_pos] == '"' || line[line_pos] == '\'') {
+			c = line[line_pos];
+			++line_pos;
+			for (param_pos = 0; line[line_pos] != c; /* NOTHING */) {
+				param[param_pos++] = line[line_pos++];
+				if (param_pos >= MAX_PARAM_LEN) {
+					PRINT_LINENUM;
+					mp_msg(MSGT_CFGPARSER,MSGL_ERR,"too long parameter\n");
+					ret = -1;
+					errors++;
+					goto nextline;
+				}
+			}
+			line_pos++;	/* skip the closing " or ' */
+		} else {
+			for (param_pos = 0; isprint(line[line_pos]) && !isspace(line[line_pos])
+					&& line[line_pos] != '#'; /* NOTHING */) {
+				param[param_pos++] = line[line_pos++];
+				if (param_pos >= MAX_PARAM_LEN) {
+					PRINT_LINENUM;
+					mp_msg(MSGT_CFGPARSER,MSGL_ERR,"too long parameter\n");
+					ret = -1;
+					errors++;
+					goto nextline;
+				}
+			}
+		}
+		param[param_pos] = '\0';
+
+		/* did we read a parameter? */
+		if (param_pos == 0) {
+			PRINT_LINENUM;
+			mp_msg(MSGT_CFGPARSER,MSGL_ERR,"option without parameter\n");
+			ret = -1;
+			errors++;
+			continue;
+		}
+
+#ifdef MP_DEBUG
+		PRINT_LINENUM;
+		mp_msg(MSGT_CFGPARSER,MSGL_V,"parameter: %s\n", param);
+#endif
+
+		/* now, check if we have some more chars on the line */
+		/* whitespace... */
+		while (isspace(line[line_pos]))
+			++line_pos;
+
+		/* EOL / comment */
+		if (line[line_pos] != '\0' && line[line_pos] != '#') {
+			PRINT_LINENUM;
+			mp_msg(MSGT_CFGPARSER,MSGL_WARN,"extra characters on line: %s\n", line+line_pos);
+			ret = -1;
+		}
+
+		tmp = m_config_set_option(config, opt, param);
+		if (tmp < 0) {
+			PRINT_LINENUM;
+			mp_msg(MSGT_CFGPARSER,MSGL_INFO,"%s\n", opt);
+			ret = -1;
+			errors++;
+			continue;
+			/* break */
+		}	
+nextline:
+		;
+	}
+
+	free(line);
+	fclose(fp);
+out:
+	config->mode = prev_mode;
+	--recursion_depth;
+	return ret;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/parser-mecmd.c	Tue Nov 12 01:56:42 2002 +0000
@@ -0,0 +1,153 @@
+
+#include "config.h"
+
+#ifdef NEW_CONFIG
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef MP_DEBUG
+#include <assert.h>
+#endif
+
+#include "mp_msg.h"
+#include "m_option.h"
+#include "m_config.h"
+#include "parser-mecmd.h"
+
+
+void
+m_entry_list_free(m_entry_t* lst) {
+  int i,j;
+
+  for(i = 0 ; lst[i].name != NULL ; i++){
+    free(lst[i].name);
+    for(j = 0 ; lst[i].opts[2*j] != NULL ; j++) {
+      free(lst[i].opts[2*j]);
+      free(lst[i].opts[2*j+1]);
+    }
+    free(lst[i].opts);
+  }
+  free(lst);
+}
+
+int
+m_entry_set_options(m_config_t *config, m_entry_t* entry) {
+  int i,r;
+
+  for(i = 0 ; entry->opts[2*i] != NULL ; i++){
+    r = m_config_set_option(config,entry->opts[2*i],entry->opts[2*i+1]);
+    if(r < 0)
+      return 0;
+  }
+  return 1;
+}
+
+
+  
+
+m_entry_t*
+m_config_parse_me_command_line(m_config_t *config, int argc, char **argv)
+{
+  int i,nf = 0,no = 0;
+  int tmp;
+  char *opt;
+  int no_more_opts = 0;
+  m_entry_t *lst = NULL, *entry = NULL;
+  void add_file(char* file) {
+    mp_msg(MSGT_CFGPARSER, MSGL_DBG2,"Adding file %s\n",argv[i]);
+    lst = realloc(lst,(nf+2)*sizeof(m_entry_t));
+    lst[nf].name = strdup(file);
+    lst[nf].opts = calloc(2,sizeof(char*));
+    entry = &lst[nf];
+    no = 0;
+    memset(&lst[nf+1],0,sizeof(m_entry_t));
+    nf++;
+  }
+	
+#ifdef MP_DEBUG
+  assert(config != NULL);
+  assert(argv != NULL);
+  assert(argc >= 1);
+#endif
+
+  config->mode = M_COMMAND_LINE;
+
+  lst = calloc(1,sizeof(m_entry_t));
+
+  for (i = 1; i < argc; i++) {
+    //next:
+    opt = argv[i];
+    /* check for -- (no more options id.) except --help! */
+    if ((*opt == '-') && (*(opt+1) == '-') && (*(opt+2) != 'h'))
+      {
+	no_more_opts = 1;
+	if (i+1 >= argc)
+	  {
+	    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "You added '--' but no filenames presented!\n");
+	    goto err_out;
+	  }
+	continue;
+      }
+			
+    if ((no_more_opts == 0) && (*opt == '-') && (*(opt+1) != 0)) /* option */
+      {
+	m_option_t* mp_opt = NULL;
+	/* remove trailing '-' */
+	opt++;
+	mp_msg(MSGT_CFGPARSER, MSGL_DBG3, "this_opt = option: %s\n", opt);
+	mp_opt = m_config_get_option(config,opt);
+	if(!mp_opt) {
+	  tmp = M_OPT_UNKNOW;
+	  mp_msg(MSGT_CFGPARSER, MSGL_ERR, "%s in not an MEncoder option\n",opt);
+	  goto err_out;
+	}
+	// Hack for the -vcd ... options
+	if(strcasecmp(opt,"vcd") == 0)
+	  add_file("VCD Track");
+	if(strcasecmp(opt,"dvd") == 0)
+	  add_file("DVD Title");
+	if(strcasecmp(opt,"tv") == 0 && argv[i + 1]) { // TV is a bit more tricky
+	  char* param = argv[i + 1];
+	  char* on = strstr(param,"on");
+	  for( ; on ; on = strstr(on + 1,"on")) {
+	    if(on[2] != ':' && on[2] != '\0') continue;
+	    if(on != param && *(on - 1) != ':') continue;
+	    add_file("TV Channel");
+	    break;
+	  }
+	}
+	if(!entry || (mp_opt->flags & M_OPT_GLOBAL))
+	  tmp = m_config_set_option(config, opt, argv[i + 1]);
+	else {
+	  tmp = m_config_check_option(config, opt, argv[i + 1]);
+	  if(tmp >= 0) {
+	    entry->opts = realloc(entry->opts,(no+2)*2*sizeof(char*));
+	    entry->opts[2*no] = strdup(opt);
+	    entry->opts[2*no+1] = argv[i + 1] ? strdup(argv[i + 1]) : NULL;
+	    entry->opts[2*no+2] =  entry->opts[2*no+3] = NULL;
+	    no++;
+	  }
+	}
+	if (tmp < 0)
+	  goto err_out;
+	i += tmp;
+      } else /* filename */
+	add_file(argv[i]);
+  }
+
+  if(nf == 0) {
+    m_entry_list_free(lst);
+    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "No file given\n");
+    return NULL;
+  }
+  return lst;
+
+ err_out:
+   m_entry_list_free(lst);
+  return NULL;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/parser-mecmd.h	Tue Nov 12 01:56:42 2002 +0000
@@ -0,0 +1,18 @@
+
+/// A simple parser with per-entry settings.
+
+typedef struct m_entry_st {
+  char* name; // Filename, url or whatever
+  char** opts; // NULL terminated list of name,val pairs 
+} m_entry_t;
+
+// Free a list returned by m_config_parse_command_line
+void
+m_entry_list_free(m_entry_t* lst);
+// Use this when you switch to another entry
+int
+m_entry_set_options(m_config_t *config, m_entry_t* entry);
+
+m_entry_t*
+m_config_parse_me_command_line(m_config_t *config, int argc, char **argv);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/parser-mpcmd.c	Tue Nov 12 01:56:42 2002 +0000
@@ -0,0 +1,284 @@
+
+#include "config.h"
+
+#ifdef NEW_CONFIG
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef MP_DEBUG
+#include <assert.h>
+#endif
+
+#include "mp_msg.h"
+#include "m_option.h"
+#include "m_config.h"
+#include "playtree.h"
+
+static int recursion_depth = 0;
+static int mode = 0;
+
+#define GLOBAL 0
+#define LOCAL 1
+#define DROP_LOCAL 2
+
+#define UNSET_GLOBAL (mode = LOCAL)
+// Use this 1 if you want to have only global option (no per file option)
+// #define UNSET_GLOBAL (mode = GLOBAL)
+
+
+static int is_entry_option(char *opt, char *param, play_tree_t** ret) {
+  play_tree_t* entry = NULL;
+
+  *ret = NULL;
+
+  if(strcasecmp(opt,"playlist") == 0) { // We handle playlist here
+    if(!param)
+      return M_OPT_MISSING_PARAM;
+    entry = parse_playlist_file(param);
+    if(!entry)
+      return 1;
+  } else if(strcasecmp(opt,"vcd") == 0) {
+    char* s;
+    if(!param)
+      return M_OPT_MISSING_PARAM;
+    s = (char*)malloc((strlen(param) + 6 + 1)*sizeof(char));
+    sprintf(s,"vcd://%s",param);
+    entry = play_tree_new();
+    play_tree_add_file(entry,s);
+    free(s);
+  } else if(strcasecmp(opt,"dvd") == 0) {
+    char* s;
+    if(!param)
+      return M_OPT_MISSING_PARAM;
+    s = (char*)malloc((strlen(param) + 6 + 1)*sizeof(char));
+    sprintf(s,"dvd://%s",param);
+    entry = play_tree_new();
+    play_tree_add_file(entry,s);
+    free(s);
+  } else if(strcasecmp(opt,"tv") == 0) {
+    char *s,*pr,*prs;
+    char *ps,*pe,*channel=NULL;
+    char *as;
+    int on=0;
+
+    if(!param)
+      return M_OPT_MISSING_PARAM;
+    ps = param;
+    pe = strchr(param,':');
+    pr = prs = (char*)malloc((strlen(param)+1)*sizeof(char));
+    pr[0] = '\0';
+    while(ps) {
+      if(!pe)
+	pe = ps + strlen(ps);
+
+      as = strchr(ps,'=');
+      if(as && as[1] != '\0' && pe-as > 0)
+	as++;
+      else
+	as = NULL;
+      if( !as && pe-ps == 2 &&  strncasecmp("on",ps,2) == 0 )
+	on = 1;
+      else if(as  && as-ps == 8  && strncasecmp("channel",ps,6) == 0 && pe-as > 0) {
+	channel = (char*)realloc(channel,(pe-as+1)*sizeof(char));
+	strncpy(channel,as,pe-as);
+	channel[pe-as] = '\0';
+      } else if(pe-ps > 0) {
+	if(prs != pr) {
+	  prs[0] = ':';
+	  prs++;
+	}
+	strncpy(prs,ps,pe-ps);
+	prs += pe-ps;
+	prs[0] = '\0';
+      }
+
+      if(pe[0] != '\0') {
+	ps = pe+1;
+	pe = strchr(ps,':');
+      } else
+	ps = NULL;
+    }
+
+    if(on) {
+      int l=5;
+	
+      if(channel)
+	l += strlen(channel);
+      s = (char*) malloc((l+1)*sizeof(char));
+      if(channel)
+	sprintf(s,"tv://%s",channel);
+      else
+	sprintf(s,"tv://");
+      entry = play_tree_new();
+      play_tree_add_file(entry,s);
+      if(strlen(pr) > 0)
+	play_tree_set_param(entry,"tv",pr);
+      free(s);
+    }
+    free(pr);
+    if(channel)
+      free(channel);
+	  
+  }
+
+  if(entry) {
+    *ret = entry;
+    return 1;
+  } else
+    return 0;
+}
+
+play_tree_t*
+m_config_parse_mp_command_line(m_config_t *config, int argc, char **argv)
+{
+  int i;
+  int tmp = 0;
+  char *opt;
+  int no_more_opts = 0;
+  play_tree_t *last_parent, *last_entry = NULL, *root;
+  void add_entry(play_tree_t *entry) {
+    if(last_entry == NULL)
+      play_tree_set_child(last_parent,entry);		      
+    else 
+      play_tree_append_entry(last_entry,entry);
+    last_entry = entry;
+  }
+
+#ifdef MP_DEBUG
+  assert(config != NULL);
+  assert(argv != NULL);
+  assert(argc >= 1);
+#endif
+
+  config->mode = M_COMMAND_LINE;
+  mode = GLOBAL;
+  last_parent = root = play_tree_new();
+  /* in order to work recursion detection properly in parse_config_file */
+  ++recursion_depth;
+
+  for (i = 1; i < argc; i++) {
+    //next:
+    opt = argv[i];
+    /* check for -- (no more options id.) except --help! */
+    if ((*opt == '-') && (*(opt+1) == '-') && (*(opt+2) != 'h'))
+      {
+	no_more_opts = 1;
+	if (i+1 >= argc)
+	  {
+	    mp_msg(MSGT_CFGPARSER, MSGL_ERR, "You added '--' but no filenames presented!\n");
+	    goto err_out;
+	  }
+	continue;
+      }
+    if((opt[0] == '{') && (opt[1] == '\0'))
+      {
+	play_tree_t* entry = play_tree_new();
+	UNSET_GLOBAL;
+	if(last_entry == NULL) {
+	  play_tree_set_child(last_parent,entry);
+	} else {
+	  play_tree_append_entry(last_entry,entry);
+	  last_entry = NULL;
+	}
+	last_parent = entry;
+	continue;
+      }
+
+    if((opt[0] == '}') && (opt[1] == '\0'))
+      {
+	if( ! last_parent || ! last_parent->parent) {
+	  mp_msg(MSGT_CFGPARSER, MSGL_ERR, "too much }-\n");
+	  goto err_out;
+	}
+	last_entry = last_parent;
+	last_parent = last_entry->parent;
+	continue;
+      }
+			
+    if ((no_more_opts == 0) && (*opt == '-') && (*(opt+1) != 0)) /* option */
+      {
+	/* remove trailing '-' */
+	opt++;
+
+	mp_msg(MSGT_CFGPARSER, MSGL_DBG3, "this_opt = option: %s\n", opt);
+	// We handle here some specific option
+	if(strcasecmp(opt,"list-options") == 0) {
+	  m_config_print_option_list(config);
+	  exit(1);
+	  // Loop option when it apply to a group
+	} else if(strcasecmp(opt,"loop") == 0 &&
+		  (! last_entry || last_entry->child) ) {
+	  int l;
+	  char* end;
+	  l = strtol(argv[i+1],&end,0);
+	  if(!end)
+	    tmp = ERR_OUT_OF_RANGE;
+	  else {
+	    play_tree_t* pt = last_entry ? last_entry : last_parent;
+	    l = l <= 0 ? -1 : l;
+	    pt->loop = l;
+	    tmp = 1;
+	  }
+	} else {
+	  m_option_t* mp_opt = NULL;
+	  play_tree_t* entry = NULL;
+
+	  tmp = is_entry_option(opt,argv[i + 1],&entry);
+	  if(tmp > 0)  { // It's an entry
+	    if(entry) {
+	      add_entry(entry);
+	      UNSET_GLOBAL;
+	    } else if(mode == LOCAL) // Entry is empty we have to drop his params
+	      mode = DROP_LOCAL;
+	  } else if(tmp == 0) { // 'normal' options
+	    mp_opt = m_config_get_option(config,opt);
+	    if (mp_opt != NULL) { // Option exist
+	      if(mode == GLOBAL || (mp_opt->flags & M_OPT_GLOBAL))
+		tmp = m_config_set_option(config, opt, argv[i + 1]);
+	      else {
+		tmp = m_config_check_option(config, opt, argv[i + 1]);
+		if(tmp >= 0 && mode != DROP_LOCAL) {
+		  play_tree_t* pt = last_entry ? last_entry : last_parent;
+		  play_tree_set_param(pt,opt, argv[i + 1]);
+		}
+	      }
+	    } else {
+	      tmp = M_OPT_UNKNOW;
+	      mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Unknow option on the command line: %s\n",opt);
+	    }
+	  }
+	}
+
+	if (tmp < 0)
+	  goto err_out;
+	i += tmp;
+      }
+    else /* filename */
+      {
+	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]);
+	// Lock stdin if it will be used as input
+	if(strcasecmp(argv[i],"-") == 0)
+	  m_config_set_option(config,"use-stdin",NULL);
+	add_entry(entry);
+	UNSET_GLOBAL; // We start entry specific options
+
+      }
+  }
+
+  --recursion_depth;
+  if(last_parent != root)
+    mp_msg(MSGT_CFGPARSER, MSGL_ERR,"Missing }- ?\n");
+  return root;
+
+ err_out:
+  --recursion_depth;
+  play_tree_free(root,1);
+  return NULL;
+}
+
+#endif
--- a/playtree.c	Tue Nov 12 00:19:14 2002 +0000
+++ b/playtree.c	Tue Nov 12 01:56:42 2002 +0000
@@ -8,6 +8,7 @@
 #ifdef MP_DEBUG
 #include <assert.h>
 #endif
+#include "cfgparser.h"
 #include "playtree.h"
 #include "mp_msg.h"
 
--- a/playtree.h	Tue Nov 12 00:19:14 2002 +0000
+++ b/playtree.h	Tue Nov 12 01:56:42 2002 +0000
@@ -2,8 +2,8 @@
 #ifndef __PLAYTREE_H
 #define __PLAYTREE_H
 
-#include "libmpdemux/stream.h"
-
+struct stream_st;
+struct m_config;
 
 #define PLAY_TREE_ITER_ERROR 0
 #define PLAY_TREE_ITER_ENTRY 1
@@ -20,7 +20,6 @@
 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;
@@ -56,7 +55,7 @@
 struct play_tree_iter {
   play_tree_t* root; // Iter root tree
   play_tree_t* tree; // Current tree
-  m_config_t* config; 
+  struct m_config* config; 
   int loop;  // Looping status
   int file;
   int num_files;
@@ -124,7 +123,7 @@
 /// Iterator
 
 play_tree_iter_t*
-play_tree_iter_new(play_tree_t* pt, m_config_t* config);
+play_tree_iter_new(play_tree_t* pt, struct m_config* config);
 
 play_tree_iter_t*
 play_tree_iter_new_copy(play_tree_iter_t* old);
@@ -148,7 +147,7 @@
 play_tree_iter_get_file(play_tree_iter_t* iter, int d);
 
 play_tree_t*
-parse_playtree(stream_t *stream);
+parse_playtree(struct stream_st *stream);
 
 play_tree_t*
 play_tree_cleanup(play_tree_t* pt);
--- a/playtreeparser.c	Tue Nov 12 00:19:14 2002 +0000
+++ b/playtreeparser.c	Tue Nov 12 01:56:42 2002 +0000
@@ -11,6 +11,7 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include "cfgparser.h"
 #include "playtree.h"
 #include "playtreeparser.h"
 #include "libmpdemux/stream.h"
--- a/playtreeparser.h	Tue Nov 12 00:19:14 2002 +0000
+++ b/playtreeparser.h	Tue Nov 12 01:56:42 2002 +0000
@@ -2,11 +2,10 @@
 #ifndef __PLAYTREEPARSER_H
 #define __PLAYTREEPARSER_H
 
-#include "playtree.h"
-#include "libmpdemux/stream.h"
+struct stream_st;
 
 typedef struct play_tree_parser {
-  stream_t* stream;
+  struct stream_st* stream;
   char *buffer,*iter,*line;
   int buffer_size , buffer_end;
   int deep,keep;
@@ -14,7 +13,7 @@
 
 
 play_tree_parser_t*
-play_tree_parser_new(stream_t* stream,int deep);
+play_tree_parser_new(struct stream_st* stream,int deep);
 
 void
 play_tree_parser_free(play_tree_parser_t* p);