/
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/
/* /global/virtual/compiler.c

 * Originally by person or persons unknown (finkpish@discworld?)
 *               Maybe by Zellski@discworld
 *
 * 12/93-1/94 Bannor@NewMoon
 *            Fixed the Class and Include keywords.
 */

#include "virtual.h"
#include "compiler.h"

void    initialize_methods();
string  strip_string( string str );


#define WHITESPACE(c) (c == 10 || c == 32 || c == '\n')


mapping o_funcs, r_funcs, arm_funcs, wep_funcs, mon_funcs;
object  return_ob;
int     tmp_file_no;
int     debug_file;		/* don't rm .c file if non-zero */

void    create()
{
    initialize_methods();
    seteuid( getuid() );
    o_funcs = O_FUN;
    r_funcs = O_FUN + R_FUN;
    arm_funcs = ARM_FUN + O_FUN;
    wep_funcs = WEP_FUN + O_FUN;
    mon_funcs = MON_FUN + O_FUN;
}				/* create() */

object  query_return_ob()
{
    return return_ob;
}
void    set_return_ob( object ob )
{
    return_ob = ob;
}

void    initialize_methods()
{
    SERVER->add_method( "r", file_name( this_object() ), "compile_r" );
    SERVER->add_method( "ob", file_name( this_object() ), "compile_ob" );
    SERVER->add_method( "arm", file_name( this_object() ), "compile_arm" );
    SERVER->add_method( "wep", file_name( this_object() ), "compile_wep" );
    SERVER->add_method( "mon", file_name( this_object() ), "compile_mon" );
}				/* initialize_methods() */

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

mixed  *extract_arguments( string str );

void    do_clone( object dest, string str )
{
    object  ob;

    ob = clone_object( str );
    if( ob )
	ob->move( dest );
}				/* do_clone() */

object  prop_to_fun( string file, mapping funs, string class, int clone )
{
    string *segments, *ind, data, s1, dir, tmp_name, tmp_val;
    mixed  *val;
    int     i;


/*
 * Ok...  what we do is stick it in the same dir as the file we start
 * with, with the same name, but a nice number on ze end.
 */
    debug_file = 0;		/* debugging off */
    tmp_name = file + "-" + (tmp_file_no++) + ".c";
    if( find_object( tmp_name ) )
	tmp_name->dest_me();
    ind = explode( file, "/" );
    dir = implode( ind[ 0..sizeof( ind ) - 2 ], "/" );
    rm( tmp_name );
    write_file( tmp_name,
		"#include \"virtual.h\"\n\n" +
		"void dest_me() { destruct( this_object() ); }\n\n" +
		"void create()\n{\n" +
		"object clone;\n\n" +
		"  seteuid( (string)\"/secure/master\"->creator_file( this_object() ) );\n" );
    data = read_file( file );
    if( !data )
    {
	Error( "prop_to_fun() : file " + file + " not found\n" );
    }

    /* Lines beinging with a # are a comment... */

    segments = explode( "$\n" + data, "\n#" );
    if( !segments )
    {
	Error( "prop_to_fun() : Nothing but comments?\n" );
    }
    segments[ 0 ] = segments[ 0 ][ 1..1000 ];
    for( i = 1; i < sizeof( segments ); i++ )
	if( sscanf( segments[ i ], "%s\n%s", s1, segments[ i ] ) != 2 )
	    segments[ i ] = "";
    data = implode( segments, "\n" );

    /* See example file for explanation of syntax. */

    segments = explode( strip_string( data ), "::" );
    ind = allocate( sizeof( segments ) / 2 );
    val = allocate( sizeof( segments ) / 2 );

    for( i = 0; i < sizeof( segments ) / 2; i++ )
    {
	ind[ i ] = segments[ i * 2 ];
	val[ i ] = replace( segments[ i * 2 + 1 ], "\n", " " );
	/* look for virtual compiler meta char */
	if( ind[ i ][ 0..0 ] == "#" )
	{
	    ind[ i ] = lower_case( ind[ i ] );
	    if( ind[ i ] == "#debug" )
	    {
		/* debug errent virtual programs, ie, don't rm */
		/* the .c file if debug_file is non-zero */
		sscanf( val[ i ], "%d", debug_file );
	    }
	    else
		if( ind[ i ] == "#class" )
		{
		    /* use new base object for cloneing */
		    class = replace( segments[ i * 2 + 1 ], "\n", "" );
		    /* remove any leading (or trailing) spaces */
		    class = replace( class, " ", "" );
		}
		else
		    if( ind[ i ] == "#include" )
		    {
			/* include the file in setup(), just before the */
			/* object is cloned.  */
			tmp_val = replace( segments[ i * 2 + 1 ], "\n", "" );
			write_file( tmp_name, "#include " +
				    replace( tmp_val, " ", "" ) +
				    "\n" );
		    }
	}			/* if( ..# ) */
    }
    write_file( tmp_name,
		"  clone = (object)SERVER->create_virtual_object( " +
		class + ", 1 );\n" );
    write_file( tmp_name, "  clone->add_property( \"virtual name\", \""
		+ file + (clone ? "#1" : "") + "\" );\n" );

    for( i = 0; i < sizeof( ind ); i++ )
    {
	ind[ i ] = lower_case( ind[ i ] );
	if( ind[ i ][ 0..0 ] == "#" )
	{
	    /* it's a virtual keyword don't stick it in the .c file */
	    continue;
	}
	if( ind[ i ][ 0..0 ] == "$" )
	{
	    /* stuff that starts with "$" are 'undefined' function
	     * names in the base object */
	    {
		write_file( tmp_name, "  call_other( clone, \"" +
			    ind[ i ][ 1..100 ] + "\", " + val[ i ] +
			    " );\n" );
	    }
	    continue;
	}			/* if( ...$ ) */
	if( funs[ ind[ i ] ] )
	{
	    if( !pointerp( funs[ ind[ i ] ] ) )
	    {
		write_file( tmp_name, "  call_other( clone, \"" +
			    funs[ ind[ i ] ] + "\", " + val[ i ] + " );\n" );
/*
   "val[i][1], val[i][2], val[i][3], val[i][4], val[i][5]);
 */
	    }
	    else
		write_file( tmp_name, "  call_other( " + funs[ ind[ i ] ][ 1 ] +
			    ", " + funs[ ind[ i ] ][ 0 ] + ", " + val[ i ] +
			    " );\n" );
/*
   call_other( funs[ind[i]][1], funs[ind[i]][0], clone,
   val[i][0], val[i][1], val[i][2],
   val[i][3], val[i][4], val[i][5]);
 */
	}
	else
	{
	    write( "Error: Unknown index " + ind[ i ] + "\n" );
	}
    }
    write_file( tmp_name, "  \"" + file_name( this_object() ) + "\"->" +
		"set_return_ob( clone );\n} /* create() */\n" );
    if( data = catch( tmp_name->bing() ) )
    {
	write( "Error loading " + file + ", " + data + "\n" );
	if( debug_file )
	{
	    write( "File not removed.\n" );
	}
	else
	    rm( tmp_name );
    }
    else
    {
	tmp_name->dest_me();
	rm( tmp_name );
	return return_ob;
    }
}				/* prop_to_fun() */


string  strip_string( string str )
{
    int     i, j;

    j = strlen( str ) - 1;
    for( ; WHITESPACE( str[ i ] ) && i < j; i++ ) ;

    for( ; WHITESPACE( str[ j ] ) && j > i; j-- ) ;

    return str[ i..j ];
}				/* strip_space() */


mixed   str_to_var( string str )
{
    /* We deal with a few different situations here. If our first character is
     * a linefeed, we have a chunk of text that we will take "as is" but strip
     * the linefeeds (for discworld) ignoring the fact that spaces make exist
     * between end-of-line and lf... fuck it, that's a creator problem. :)
     * 
     * After many attempts with explodes and implodes and shit, I am now
     * doing this in a LPC loop. too
     * slow? I dunno. *shrug* */
    int     i;

    str = strip_string( str );
    switch( str[ 0 ] )
    {
	case '{':
	    {
		str = str[ 1..strlen( str ) - 2 ];
		return map_array( explode( str, "," ), "str_to_var",
				  this_object() );
	    }
	case '"':
	    {
		str = str[ 1..strlen( str ) - 2 ];
		return replace( str, "\n", " " ) + "\n";
	    }
	case '0'..'9':
	case '-':
	    {
		sscanf( str, "%d", i );
		return i;
	    }
    }
    return str;
}				/* str_to_var() */


mixed  *extract_arguments( string str )
{
    return map_array( explode( str, "//" ), "str_to_var", this_object() );
}				/* extract_arguments() */


object  compile_r( string name, int clone )
{
    return prop_to_fun( name, r_funcs, "\"/std/room.c\"", clone );
}				/* compile_r() */


object  compile_ob( string name, int clone )
{
    return prop_to_fun( name, o_funcs, "\"/std/object.c\"", clone );
}				/* compile_ob() */


object  compile_arm( string name, int clone )
{
    return prop_to_fun( name, arm_funcs, "\"/obj/armour.c\"", clone );
}				/* compile_ob() */


object  compile_wep( string name, int clone )
{
    return prop_to_fun( name, wep_funcs, "\"/obj/weapon.c\"", clone );
}				/* compile_ob() */


object  compile_mon( string name, int clone )
{
    return prop_to_fun( name, mon_funcs, "\"/obj/monster.c\"", clone );
}				/* compile_ob() */