changeset 9:1885a9080f2a

Joystick button input now works with config. committer: Diggory Hardy <diggory.hardy@gmail.com>
author Diggory Hardy <diggory.hardy@gmail.com>
date Wed, 30 Jan 2008 11:33:56 +0000
parents f63f4f41a2dc
children 4c3575400769
files conf/input.mtt doc/jobs mde/init.d mde/input/config.d mde/input/input.d mde/input/joystick.d mde/mde.d mde/mergetag/dataset.d mde/mergetag/defaultdata.d mde/mergetag/read.d
diffstat 10 files changed, 307 insertions(+), 75 deletions(-) [+]
line wrap: on
line diff
--- a/conf/input.mtt	Fri Jan 25 18:17:38 2008 +0000
+++ b/conf/input.mtt	Wed Jan 30 11:33:56 2008 +0000
@@ -1,4 +1,4 @@
 {MT01}
-!<string[]|Configs=["Std"]>
+<char[][]|Configs=["Std"]>
 {Default}
-<uint[][uint]|B=[0x20000000 : [0x100, 3] ]>
+<uint[][uint]|B=[0x20000000 : [0x100, 3], 0x20000001 : [0x100, 5] ]>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/jobs	Wed Jan 30 11:33:56 2008 +0000
@@ -0,0 +1,9 @@
+In progress:
+*	Why doesn't input.config filtering via headers "Configs" work?
+
+To do:
+*	change init threads (should catch own exceptions)
+*	finish event callback support
+*	add remaining SDL event support
+*	add options support; in particular for whether or not to use threads (and adjust Init to use this).
+*	OutOfMemoryException is not currently checked for − it should be at least in critical places (use high-level catching of all errors?).
--- a/mde/init.d	Fri Jan 25 18:17:38 2008 +0000
+++ b/mde/init.d	Wed Jan 30 11:33:56 2008 +0000
@@ -87,8 +87,8 @@
                 return;
             }
             logger.info ("Derelict: loaded SDL");
-        
-            if (SDL_Init (SDL_INIT_VIDEO | SDL_INIT_JOYSTICK)) {
+            
+            if (SDL_Init (SDL_INIT_VIDEO | SDL_INIT_JOYSTICK /+| SDL_INIT_EVENTTHREAD+/)) {
                 logger.fatal ("SDL initialisation failed:");
                 char* msg = SDL_GetError ();
                 logger.fatal (msg ? fromUtf8z(msg) : "no reason available");
@@ -97,7 +97,7 @@
                 return;
             }
             
-            SDL_SetVideoMode (800, 600, 32, 0);
+            SDL_SetVideoMode (800, 600, 0, 0);
             
             addCleanupFct (&cleanupSDL);
             logger.info ("SDL initialised");
--- a/mde/input/config.d	Fri Jan 25 18:17:38 2008 +0000
+++ b/mde/input/config.d	Wed Jan 30 11:33:56 2008 +0000
@@ -81,7 +81,6 @@
     outQueue[uint] button;
     outQueue[uint] axis;	/// ditto
     outQueue[uint] mouse;	/// ditto
-    debug uint dnbc;		// debug num button configs
     
     char[] name;		/// Name for user to save this under.
     uint[] inheritants;		/// Other profiles to inherit.
@@ -98,7 +97,9 @@
     static void load (char[] filename) {
         if (loadedFiles.contains (filename)) return;	// forget it; already done that
         loadedFiles.add (filename);
+        
         MT.Reader file;
+        
         try {
             file = new MT.Reader(filename, null, true);	// open and read header
             // TODO: also load user-config file
@@ -108,33 +109,30 @@
             
             // D2.0: enum MT.ID CONFIGS = "Configs";
             const MT.ID CONFIGS = cast(MT.ID)"Configs";
-            MT.ID[] configs;	// active config sections (may not exist)
-            MT.ID[]* configs_p = cast(MT.ID[]*) (CONFIGS in file.dataset.header._stringA);
+            MT.ID[] file_configs;	// active config sections (may not exist)
+            MT.ID[]* file_configs_p = cast(MT.ID[]*) (CONFIGS in file.dataset.header._charAA);
             
-            if (configs_p)	file.read(*configs_p);	// restrict to this set IF a restriction was given
-            else		file.read();		// otherwise read all
+            if (file_configs_p)	file.read(*file_configs_p);	// restrict to this set IF a restriction was given
+            else		file.read();			// otherwise read all
         }
         catch (MT.MTException) {
             logger.error ("Unable to load configs from: " ~ filename);
             throw new ConfigLoadException;
         }
         
-        // NOTE: It is in some ways a bad idea assuming all DataSections are Configs, but they should be.
-        if (!configs) {		// these are the first Configs loaded
-            configs = cast (Config[char[]]) file.dataset.sec;
-        } else {		// add to existing Configs, replacing ones with same ID
-            foreach (i, sec; file.dataset.sec) {
-                Config c = cast(Config) sec;
-                if (c) configs[i] = c;		// Check, because we don't want null entries in configs
-                else debug logger.warn ("Ended up with DataSection of wrong type; this should never happen.");
-            }
+        // Trying to directly cast dataset.sec to configs resulted in the Configs losing their data.
+        // Also this is safer since it checks types (and must be done if configs wasn't previously empty).
+        foreach (i, sec; file.dataset.sec) {
+            Config c = cast(Config) sec;
+            if (c) configs[i] = c;		// Check, because we don't want null entries in configs
+            else debug logger.warn ("Ended up with DataSection of wrong type; this should never happen.");
         }
         
         debug {
             char tmp[128] = void;
             logger.trace (logger.format (tmp, "Loaded {} config sections.", configs.length));
             foreach (id, cfg; configs) {
-                logger.trace ("Section "~format!(uint)(id)~": " ~ format!(uint[][uint])(cfg.button) ~ " (" ~ format!(uint)(cfg.dnbc) ~ ")");
+                logger.trace ("Section "~id~": " ~ format!(uint[][uint])(cfg.button));
             }
         }
     }
@@ -147,11 +145,7 @@
     
     void addTag (char[] tp, MT.ID id, char[] dt) {
         if (tp == "uint[][uint]") {
-            if (id == QUEUE.BUTTON) {
-                button = cast(outQueue[uint]) parse!(uint[][uint]) (dt);
-                debug logger.trace ("Added button config: " ~ format!(uint[][uint])(button));
-                debug ++dnbc;
-            }
+            if (id == QUEUE.BUTTON) button = cast(outQueue[uint]) parse!(uint[][uint]) (dt);
             else if (id == QUEUE.AXIS) axis = cast(outQueue[uint]) parse!(uint[][uint]) (dt);
             else if (id == QUEUE.MOUSE) mouse = cast(outQueue[uint]) parse!(uint[][uint]) (dt);
             else logger.warn ("Unexpected tag encountered with ID " ~ cast(char[])id);
@@ -161,8 +155,5 @@
     void writeAll (ItemDelg) {
         // FIXME
     }
-    debug void debugFunc () {
-        logger.trace ("After parse: " ~ format!(uint[][uint])(button) ~ " (" ~ format!(uint)(dnbc) ~ ")");
-    }
 //END File loading/saving code
 }
--- a/mde/input/input.d	Fri Jan 25 18:17:38 2008 +0000
+++ b/mde/input/input.d	Wed Jan 30 11:33:56 2008 +0000
@@ -13,13 +13,9 @@
 
 import tango.util.log.Log : Log, Logger;
 
-Input input;			/// Global instance of input.
-private Logger logger;
-
+public Input input;			/// Global instance of input.
 static this() {
-    input = new Input;
-    
-    logger = Log.getLogger ("mde.input.config");
+    input = new Input();
 }
 
 /// Class encapsulating all input functionality.
@@ -35,7 +31,8 @@
     *
     * Returns: value (true = down, false = up) or false if no value at this ID. */
     bool getButton (inputID id) {
-        bool* retp = cast(inputID) id in button;
+        assert (this is input);
+        bool* retp = id in button;
         if (retp) return *retp;
         else return false;
     }
@@ -43,7 +40,7 @@
     *
     * Returns: value (range -1.0 .. 1.0) or 0.0 if no value at this ID. */
     real getAxis (inputID id) {
-        real* retp = cast(inputID) id in axis;
+        real* retp = id in axis;
         if (retp) return *retp;
         else return 0.0;
     }
@@ -65,7 +62,7 @@
     * positions.
     */
     void mouseRelativePos (inputID id, out real x = 0.0, out real y = 0.0) {
-        RelPair* rp = cast(inputID) id in axis_rel;
+        RelPair* rp = id in axis_rel;
         if (rp) {
             x = rp.x;	y = rp.y;
         }
@@ -104,17 +101,14 @@
     * Other types of event functions may be added. Returns true if the event was used, false if not.
     */
     bool opCall (ref SDL_Event event) {
+        assert (this is input);
         switch (event.type) {
             case SDL_JOYBUTTONDOWN:
             case SDL_JOYBUTTONUP:
-                debug {
-                    char tmp[128] = void;
-                    logger.trace (logger.format (tmp, "Got a joystick button event: ({}, {}) - {}", event.jbutton.which, event.jbutton.button, event.jbutton.state));
-                }
                 outQueue* p = (Config.B.JOYBUTTON | (event.jbutton.which << 12) | event.jbutton.button) in config.button;
                 if (p) bEventOut (event.jbutton.state == 0x1, readOutQueue(*p));
                 break;
-        
+            
             /+
             case SDL_KEYDOWN:
             case SDL_KEYUP:
@@ -154,7 +148,6 @@
         if (c_p) {
             config = *c_p;
             return false;
-            debug logger.trace ("Succesfully loaded config.");
         }
         debug logger.warn ("Config \"Default\" not found.");
         return true;
@@ -164,6 +157,8 @@
     // Static constructor for event stream (fills es_*_fcts tables).
     static this () {
         es_b_fcts = [ ES_B_OUT : &es_b_out ];
+        
+        logger = Log.getLogger ("mde.input.input.Input");
     }
     
     struct RelPair {	// for mouse/joystick ball motion
@@ -175,6 +170,8 @@
         }
     }
     
+    static Logger logger;
+
     Config config;			// Configuration
     
     bool[inputID] button;		// Table of button states
@@ -213,19 +210,24 @@
             ret._q = q;
             return ret;
         }
-        uint next () {			// Get the next element. Throws an exception if there isn't another.
+        uint pop () {			// Get the next element and advance. Throws an exception if there isn't another.
             if (p >= _q.length)
                 throw new InputClassException ("Input: Invalid configuration: incomplete config stack");
             uint ret = _q[p];
             ++p;
             return ret;
         }
+        debug uint next () {		// Get the next element. No checks; for debug use only.
+            return _q[p];
+        }
     }
     
     // These aliases are for pointers to the event functions.
-    alias void function (bool, readOutQueue) ES_B_Func;
-    alias void function (short, readOutQueue) ES_A_Func;
-    alias void function (short, short, readOutQueue) ES_M_Func;
+    // These need to use "this", but cannot be delegates because they musn't be bound to a
+    // particular instance of Input, hence this must be passed when called.
+    alias void function (Input, bool, readOutQueue) ES_B_Func;
+    alias void function (Input, short, readOutQueue) ES_A_Func;
+    alias void function (Input, short, short, readOutQueue) ES_M_Func;
     
     // These are the codes allowing the config to specify event functions:
     enum : uint {
@@ -244,44 +246,49 @@
     //BEGIN ES Functions
     // These 3 functions pass an event to the appropriate event function (adjuster or output func).
     // They are used to start and continue an event stream.
+    const EVCONF_ERR = "Input: Invalid configuration: bad event function code";
     void bEventOut (bool b, readOutQueue s)
     {
-        ES_B_Func* func = (s.next() in es_b_fcts);
-        if (func != null) (*func)(b,s);
-        else throw new InputClassException ("Input: Invalid configuration: bad event function code");
+        ES_B_Func* func = (s.pop() in es_b_fcts);
+        if (func != null) (*func)(this, b, s);
+        else throw new InputClassException (EVCONF_ERR);
     }
     void aEventOut (short x, readOutQueue s)
     {
-        ES_A_Func* func = (s.next() in es_a_fcts);
-        if (func != null) (*func)(x,s);
-        else throw new InputClassException ("Input: Invalid configuration: bad event function code");
+        ES_A_Func* func = (s.pop() in es_a_fcts);
+        if (func != null) (*func)(this, x, s);
+        else throw new InputClassException (EVCONF_ERR);
     }
     void mEventOut (short x, short y, readOutQueue s)
     {
-        ES_M_Func* func = (s.next() in es_m_fcts);
-        if (func != null) (*func)(x,y,s);
-        else throw new InputClassException ("Input: Invalid configuration: bad event function code");
+        ES_M_Func* func = (s.pop() in es_m_fcts);
+        if (func != null) (*func)(this, x, y, s);
+        else throw new InputClassException (EVCONF_ERR);
     }
     
     // The remaining functions are the stream functions, for adjusting and outputting an event.
+    // They need to work like non-static functions, but are called via a function pointer, hencne
+    // should be static with their first parameter being instead of this.
     
     // Simple output function
-    void es_b_out (bool b, readOutQueue s) {
-        inputID id = cast(inputID) s.next();
-        button[id] = b;
-        ButtonCallback* cb_p = id in buttonCallbacks;
+    static void es_b_out (Input myThis, bool b, readOutQueue s) {
+        inputID id = cast(inputID) s.pop();
+        
+        myThis.button[id] = b;
+        
+        ButtonCallback* cb_p = id in myThis.buttonCallbacks;
         if (cb_p) (*cb_p) (id, b);
     }
     // Adjuster to check modifier keys
-    void es_b_modifier (bool b, readOutQueue s);
+    void es_b_modifier (Input myThis, bool b, readOutQueue s);
 
     /* Simple output function
 
     Adds 1-2 items on the stack.
     */
-    void es_a_out (short x, readOutQueue s) {
+    void es_a_out (Input myThis, short x, readOutQueue s) {
         real y = x;
-        uint conf = s.next();
+        uint conf = s.pop();
         enum : uint {
             HALF_RANGE	= 0x8000_0000u,
             SENSITIVITY	= 0x0080_0000u,
@@ -290,16 +297,16 @@
         if (conf & HALF_RANGE) y = (y + 32767.0) * 1.5259254737998596e-05;	// range  0.0 - 1.0
         else y *= 3.0518509475997192e-05;					// range -1.0 - 1.0
         real a;
-        if (conf & SENSITIVITY) a = s.next();
+        if (conf & SENSITIVITY) a = s.pop();
         /+ When a global sensitivity is available (possibly only use if it's enabled)...
         else a = axis.sensitivity;
         y = sign(y) * pow(abs(y), a);		// sensitivity adjustment by a +/
-        axis[cast(inputID) s.next()] = y;
+        myThis.axis[cast(inputID) s.pop()] = y;
     }
 
     // Simple output function
-    void es_m_out (short x, short y, readOutQueue s) {
-        axis_rel[cast(inputID) s.next()] = RelPair(x,y);
+    void es_m_out (Input myThis, short x, short y, readOutQueue s) {
+        myThis.axis_rel[cast(inputID) s.pop()] = RelPair(x,y);
     }
     //END ES Functions
     //END Event stream functionality
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mde/input/joystick.d	Wed Jan 30 11:33:56 2008 +0000
@@ -0,0 +1,41 @@
+/** Opens SDL joysticks ready for use.
+* May be extended later to include other input devices and remap devices as per config.
+*/
+module mde.input.joystick;
+
+import tango.util.log.Log : Log, Logger;
+
+import derelict.sdl.joystick;
+
+private Logger logger;
+static this() {
+    logger = Log.getLogger ("mde.input.config");
+}
+private SDL_Joystick*[] joysticks;	// pointers to all joystick structs, whether successfully opened or not
+
+/** Open joysticks ready for use.
+*
+* This is simply required for SDL to handle joystick events. It can fail, but won't affect anything
+* else, except for the controller not working.
+*
+* closeJoysticks must be run to cleanup afterwards.
+*/
+void openJoysticks () {
+    joysticks = new SDL_Joystick*[SDL_NumJoysticks ()];
+    char tmp[128] = void;
+    
+    for (int i = 0; i < joysticks.length; ++i) {
+        if ((joysticks[i] = SDL_JoystickOpen (i)) is null) {	// null on failure
+            logger.warn (logger.format (tmp, "Unable to open joystick {} via SDL", i));
+        }
+    }
+    
+    logger.info (logger.format (tmp, "Opened {} joysticks via SDL, succesfully unless preceding warnings say otherwise.", joysticks.length));
+}
+
+/// Cleanup fct.
+void closeJoysticks () {
+    foreach (js; joysticks) {
+        if(js) SDL_JoystickClose(js);	// only close if successfully opened
+    }
+}
--- a/mde/mde.d	Fri Jan 25 18:17:38 2008 +0000
+++ b/mde/mde.d	Wed Jan 30 11:33:56 2008 +0000
@@ -34,11 +34,11 @@
         return 1;
     }
     
-    input.addButtonCallback (cast(Input.inputID) 3u, delegate void(Input.inputID i, bool b) {
+    input.addButtonCallback (cast(Input.inputID) 5u, delegate void(Input.inputID i, bool b) {
         Stdout ("Event: ")(i)(" changed to: ")(b).newline;
     } );
+    
     bool oldb = false;
-    
     while (run)
     /+for (ulong t = 0; t < 100; ++t)+/ {
         Scheduler.run (Clock.now());
@@ -49,7 +49,7 @@
             Stdout ("Button 3 changed to: ")(b).newline;
         }
         
-        Thread.sleep (0.010);	// 10 ms
+        Thread.sleep (0.050);	// sleep this many seconds
     }
     
     return 0;		// cleanup handled by init's DTOR
--- a/mde/mergetag/dataset.d	Fri Jan 25 18:17:38 2008 +0000
+++ b/mde/mergetag/dataset.d	Wed Jan 30 11:33:56 2008 +0000
@@ -90,7 +90,6 @@
      * calling addTag. */
     void addTag (char[],ID,char[]);
     void writeAll (ItemDelg);	/// TBD
-    debug void debugFunc ();		/// Run in debug builds after parseSection.
 }
 
 unittest {	// Only covers DataSet really.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mde/mergetag/defaultdata.d	Wed Jan 30 11:33:56 2008 +0000
@@ -0,0 +1,189 @@
+/// This module contains the DefaultData class, and some notes possibly useful for implementing
+/// other types of DataSection.
+module mde.mergetag.defaultdata;
+
+public import mde.mergetag.dataset;
+
+import mde.text.util;
+import mde.text.parse : parse;
+import mde.text.format : format;
+
+/**
+* Default DataSection class.
+*
+* Supports all the basic types currently supported and array versions of
+* each (except no arrays of binary, but arrays of strings are supported).
+* Doesn't support custom types, but inheriting classes may add support.
+*/
+/* Note: I wrote this comment when the code looked rather worse. It's still partially applicable though.
+*
+* Due to a failure to use generic programming techniques for most of this (maybe because it's not
+* possible or maybe just because I don't know how to use templates properly) a lot of this code is
+* really horrible and has to refer to EVERY data member.
+* Be really careful if you add any items to this class.
+*
+* I really don't like having to do things like this, but it provides a lot of benefits such as no
+* need to store types and no need to check an argument's type for every access (this could be done
+* by throwing errors, but then an incorrect (perhaps hand-edited) data file could cause a lot of
+* errors to be thrown).
+*/
+class DefaultData : DataSection
+{
+    //BEGIN DATA
+    /** Data Members
+    *
+    * These names are available for direct access.
+    *
+    * An alternative access method is to use the provided templates:
+    * --------------------
+    * template Arg(T) {
+    *     alias Name Arg;
+    * }
+    * --------------------
+    *
+    * Use with a mixin or directly:
+    * --------------------
+    * mixin Arg!(type);
+    * auto x = Arg;
+    *
+    * type y = Arg!(type).Arg;
+    * --------------------
+    * Note: trying to use Arg!(type) to implicitly refer to Arg!(type).Arg causes compiler errors due to
+    * --- alias Name Arg; ---
+    * actually being a mixin.
+    */
+     
+    bool	[ID]	_bool;
+    byte	[ID]	_byte;		/// ditto
+    short	[ID]	_short;		/// ditto
+    int		[ID]	_int;		/// ditto
+    long	[ID]	_long;		/// ditto
+    ubyte	[ID]	_ubyte;		/// ditto
+    ushort	[ID]	_ushort;	/// ditto
+    uint	[ID]	_uint;		/// ditto
+    ulong	[ID]	_ulong;		/// ditto
+    
+    char	[ID]	_char;		/// ditto
+    
+    float	[ID]	_float;		/// ditto
+    double	[ID]	_double;	/// ditto
+    real	[ID]	_real;		/// ditto
+    
+    bool[]	[ID]	_boolA;		/// ditto
+    byte[]	[ID]	_byteA;		/// ditto
+    short[]	[ID]	_shortA;	/// ditto
+    int[]	[ID]	_intA;		/// ditto
+    long[]	[ID]	_longA;		/// ditto
+    ubyte[]	[ID]	_ubyteA;	/// ditto
+    ushort[]	[ID]	_ushortA;	/// ditto
+    uint[]	[ID]	_uintA;		/// ditto
+    ulong[]	[ID]	_ulongA;	/// ditto
+    
+    char[]	[ID]	_charA;		/// ditto
+    
+    float[]	[ID]	_floatA;	/// ditto
+    double[]	[ID]	_doubleA;	/// ditto
+    real[]	[ID]	_realA;		/// ditto
+    
+    char[][]	[ID]	_charAA;	/// ditto
+    
+    /** Alias names */
+    alias	_ubyteA	_binary;
+    alias	_charA	_string;	/// ditto
+    alias	_charAA	_stringA;	/// ditto
+    //END DATA
+    
+    void addTag (char[] tp, ID id, char[] dt) {	/// Supports all standard types.
+        if (tp.length == 0) throw new MTUnknownTypeException;
+        // split list up a bit for performance:
+        if (tp[0] < 'l') {
+            if (tp[0] < 'd') {
+                mixin ( `if (tp == "binary") addTag_add!(ubyte[]) (id, dt);`
+                ~ addTag_elifIsType_add!(bool)
+                ~ addTag_elifIsType_add!(bool[])
+                ~ addTag_elifIsType_add!(byte)
+                ~ addTag_elifIsType_add!(byte[])
+                ~ addTag_elifIsType_add!(char)
+                ~ addTag_elifIsType_add!(char[])
+                ~ addTag_elifIsType_add!(char[][])
+                ~ `else throw new MTUnknownTypeException;` );
+            } else {
+                mixin ( `if (tp == "double") addTag_add!(double) (id, dt);`
+                ~ addTag_elifIsType_add!(double[])
+                ~ addTag_elifIsType_add!(float)
+                ~ addTag_elifIsType_add!(float[])
+                ~ addTag_elifIsType_add!(int)
+                ~ addTag_elifIsType_add!(int[])
+                ~ `else throw new MTUnknownTypeException;` );
+            }
+        } else {
+            if (tp[0] < 'u') {
+                mixin ( `if (tp == "long") addTag_add!(long) (id, dt);`
+                ~ addTag_elifIsType_add!(long[])
+                ~ addTag_elifIsType_add!(real)
+                ~ addTag_elifIsType_add!(real[])
+                ~ addTag_elifIsType_add!(short)
+                ~ addTag_elifIsType_add!(short[])
+                ~ `else if (tp == "string") addTag_add!(char[]) (id, dt);`
+                ~ `else throw new MTUnknownTypeException;` );
+            } else {
+                mixin ( `if (tp == "ubyte") addTag_add!(ubyte) (id, dt);`
+                ~ addTag_elifIsType_add!(ubyte[])
+                ~ addTag_elifIsType_add!(ushort)
+                ~ addTag_elifIsType_add!(ushort[])
+                ~ addTag_elifIsType_add!(uint)
+                ~ addTag_elifIsType_add!(uint[])
+                ~ addTag_elifIsType_add!(ulong)
+                ~ addTag_elifIsType_add!(ulong[])
+                ~ `else throw new MTUnknownTypeException;` );
+            }
+        }
+        // try-catch block removed (caught by read)
+    }
+    private template addTag_elifIsType_add(T) {
+        const addTag_elifIsType_add =
+        `else if (tp == "`~T.stringof~`")`
+        `addTag_add!(`~T.stringof~`) (id, dt);` ;
+    }
+    private void addTag_add(T) (ID id, char[] dt) {
+        Arg!(T).Arg[id] = parse!(T) (dt);
+    }
+    
+    void writeAll (ItemDelg itemdlg) {
+        foreach (id, dt; _charA) itemdlg ("char[]", id, format!(char[])(dt));
+    }
+    
+    /* These make no attempt to check Arg is valid.
+    * But if the symbol doesn't exist the complier will throw an error anyway, e.g.:
+    * Error: identifier '_boolAA' is not defined
+    */
+    template Arg(T : T[]) {
+        const ArgString = Arg!(T).ArgString ~ `A`;
+        mixin(`alias `~ArgString~` Arg;`);
+    }
+    template Arg(T) {
+        const ArgString = `_` ~ T.stringof;
+        mixin(`alias `~ArgString~` Arg;`);
+    }
+}
+
+/+class DynamicData : DataSection
+{
+void*[TypeInfo] data;
+    
+}+/
+
+/+
+class TemplateData : DataSection
+{
+void addTag (char[] tp, ID id, char[] dt) {
+// runtime deduction of tp and aliasing?
+// CANNOT add data at runtime though.
+}
+// will this work? no idea.
+// templates can't be used to add non-static elements, so use a static array at index: this
+template Data(T,TemplateData* p) {
+static T[ID][TemplateData*] Data;
+}
+}
++/
--- a/mde/mergetag/read.d	Fri Jan 25 18:17:38 2008 +0000
+++ b/mde/mergetag/read.d	Wed Jan 30 11:33:56 2008 +0000
@@ -226,7 +226,6 @@
                     if (psmd && !psmd.read) {			// may not exist
                         DataSection ds = getOrCreateSec (id);
                         parseSection (psmd.pos, &ds);
-                        debug ds.debugFunc ();
                         psmd.read = true;
                     }
                 }
@@ -237,7 +236,6 @@
                     if (secSet.contains(id)) {
                         DataSection ds = getOrCreateSec (id);
                         pos = parseSection (pos, &ds);
-                        debug ds.debugFunc ();
                         secTable[id].read = true;
                     }
                 }
@@ -248,7 +246,6 @@
                     if (!smd.read) {
                         DataSection ds = getOrCreateSec (id);
                         parseSection (smd.pos, &ds);
-                        debug ds.debugFunc ();
                         smd.read = true;
                     }
                 }
@@ -257,7 +254,6 @@
                     ID id = fbufReadSecMarker (pos);
                     DataSection ds = getOrCreateSec (id);
                     pos = parseSection (pos, &ds);
-                    debug ds.debugFunc ();
                 }
             }
             allRead = true;