/
LIB3/
LIB3/D/ADMIN/
LIB3/D/ADMIN/OBJ/
LIB3/D/ADMIN/ROOM/W/
LIB3/D/HOME/
LIB3/D/HOME/CITY/ARENA/
LIB3/D/HOME/CITY/ITEMS/
LIB3/D/HOME/CITY/POSTOFFI/
LIB3/DOC/
LIB3/GLOBAL/SPECIAL/
LIB3/GLOBAL/VIRTUAL/
LIB3/NET/
LIB3/NET/CONFIG/
LIB3/NET/DAEMON/CHARS/
LIB3/NET/GOPHER/
LIB3/NET/INHERIT/
LIB3/NET/OBJ/
LIB3/NET/SAVE/
LIB3/NET/VIRTUAL/
LIB3/OBJ/B_DAY/
LIB3/OBJ/HANDLERS/TERM_TYP/
LIB3/PLAYERS/B/
LIB3/PLAYERS/N/
LIB3/ROOM/
LIB3/SAVE/
LIB3/SAVE/BOARDS/
LIB3/SAVE/ENVIRON/
LIB3/SAVE/POST/
LIB3/STD/COMMANDS/SHADOWS/
LIB3/STD/CREATOR/
LIB3/STD/DOM/
LIB3/STD/EFFECTS/
LIB3/STD/EFFECTS/HEALING/
LIB3/STD/EFFECTS/OTHER/
LIB3/STD/EFFECTS/POISONS/
LIB3/STD/ENVIRON/
LIB3/STD/GUILDS/
LIB3/STD/LIQUIDS/
LIB3/STD/ROOM/
LIB3/STD/TRIGGER/SHADOW/
LIB3/W/
LIB3/W/BANNOR/
LIB3/W/NEWSTYLE/
/*
 * This is an experimental virtual-object server, written for DiscWorld
 * by Zellski. The frontend to the mudlib consists of the two functions
 * virtual_{clone, load}() which will return an object, with a 'real'
 * object as 'program' and 'variable space' but with state of properties
 * defined in some fashion by the contents of the file virtual-cloned/loaded.
 *
 * Drawbacks as yet:
 *  * The actual compilation methods are barely enough even for testing
 *    purposes but that is simple enough to expand.
 *  * The use of explode() for skipping whitespace is pathetically stupid. 
 *  * There is no support for comments in the virtual-files in prop-to-fun.
 *
 * A quick explanation of masters/clones.
 * There is no distinction as in LPC, the only one made is for finding
 * the object pointers from a virtual filename. For this there IS a 
 * virtual_clone and virtual_load that should be used. they produce much
 * the same objects, except they CAN choose to make a diff - the clone/load
 * flag is passed along to compilation. This is needed for .c files of course.
 * Remember though that even a 'master' BO, /foo/bar.x IS a clone in the end,
 * of some LPC-file. There is no support for using LPC masterobjects.
 * You can find a virtual 'master' but not a clone, you may only get a list
 * of clones made of a given file.
 */


#include "virtual.h"

mapping virtual_objects;
mapping methods;

/*
 * Each entry in virtual_objects is of the form ({ master, clone1, ... }).
 * Each entry in methods on ({ object, function }).
 */

#define OB  0
#define FUN 1

void    create()
{
    seteuid( getuid() );
    virtual_objects = ([ ]);
  methods = ([ "c":({ "/global/virtual/c_compiler.c", "compile_c" }) ]);
}

object  create_virtual_object( string name, int clone );

void    add_method( string suffix, object ob, string fun )
{
    /*
     * teach us how to compile a new kind of file..
     */
    if( !methods[ suffix ] )
    {
	methods[ suffix ] = ({ ob, fun });
    }
}

void    remove_method( string suffix )
{
    methods = m_delete( methods, suffix );
}

object  find_virtual_object( string name )
{
    string  str;
    int     num;

    if( name[ 0 ] != '/' )
    {
	name = "/" + name;
    }
    if( sscanf( name, "%s#%d", str, num ) == 2 )
    {
	if( sizeof( virtual_objects[ name ] ) >= num || !num )
	    return 0;
	return virtual_objects[ name ][ num ];
    }
    if( virtual_objects[ name ] )
    {
	return virtual_objects[ name ][ 0 ];
    }
    return 0;
}

/* Added by Newstyle, 16/09/93, for the new ls function. */
int     count_virtual_object( string name )
{
    return sizeof( virtual_objects[ name ] );
}

object *query_clones( string name )
{
    if( virtual_objects[ name ] )
    {
	return virtual_objects[ name ][ 1..1000 ];
    }
    return({ });
}

varargs object virtual_clone( string name )
{
    object  ob;
    int     i;

    ob = create_virtual_object( name, 1 );
/* Don't add it into the array if it failed! */
    if( !ob || ob->query_property( "virtual name" ) )
	return ob;
    if( virtual_objects[ name ] )
    {
	virtual_objects[ name ] = ((object *)virtual_objects[ name ] - ({ 0 })) +
	    ({ ob });
    }
    else
    {
	virtual_objects[ name ] = ({ 0, ob });
    }
    return ob;
}

varargs object virtual_load( string name, mapping handler )
{
    object  ob;
    object *master_data;

    master_data = virtual_objects[ name ];

    if( master_data && master_data[ 0 ] )
    {
	/*
	 * Have we compiled this VO before? Is the 'master' still around?
	 */
	return master_data[ 0 ];
    }

    ob = create_virtual_object( name, 0 );

    if( ob && ob->query_property( "virtual name" ) )
    {
	if( master_data )
	{
	    /*
	     * Clean up the clone-array too, remove dested clones.
	     */
	    master_data = ({ ob }) +master_data[ 1..1000 ];
	}
	else
	{
	    master_data = ({ ob });
	}
	virtual_objects[ name ] = master_data;
    }
    return ob;
}

#define Error(s) write(s); log_file("VO_HANDLER", s); return 0;

object  create_virtual_object( string name, int clone )
{
    string *split;
    mixed * method;

    split = explode( name, "." );
    method = methods[ split[ sizeof( split ) - 1 ] ];
    if( method )
    {
	return( object ) call_other( method[ OB ], method[ FUN ], name, clone );
    }
    Error( "create_virtual_object() : unknown suffix to " + name + "\n" );
}