lima-1.0b5/
lima-1.0b5/driver/
lima-1.0b5/driver/ChangeLog.old/
lima-1.0b5/driver/Win32/
lima-1.0b5/driver/compat/
lima-1.0b5/driver/include/
lima-1.0b5/driver/testsuite/
lima-1.0b5/driver/testsuite/clone/
lima-1.0b5/driver/testsuite/command/
lima-1.0b5/driver/testsuite/data/
lima-1.0b5/driver/testsuite/etc/
lima-1.0b5/driver/testsuite/include/
lima-1.0b5/driver/testsuite/inherit/
lima-1.0b5/driver/testsuite/inherit/master/
lima-1.0b5/driver/testsuite/log/
lima-1.0b5/driver/testsuite/single/
lima-1.0b5/driver/testsuite/single/tests/compiler/
lima-1.0b5/driver/testsuite/single/tests/efuns/
lima-1.0b5/driver/testsuite/single/tests/operators/
lima-1.0b5/driver/testsuite/u/
lima-1.0b5/driver/tmp/
lima-1.0b5/etc/
lima-1.0b5/lib/WWW/help/
lima-1.0b5/lib/cmds/
lima-1.0b5/lib/cmds/create/
lima-1.0b5/lib/cmds/player/attic/
lima-1.0b5/lib/contrib/bboard/
lima-1.0b5/lib/contrib/boards/
lima-1.0b5/lib/contrib/marriage/
lima-1.0b5/lib/contrib/roommaker/
lima-1.0b5/lib/contrib/transient_effect/
lima-1.0b5/lib/daemons/channel/
lima-1.0b5/lib/daemons/imud/
lima-1.0b5/lib/data/
lima-1.0b5/lib/data/config/
lima-1.0b5/lib/data/links/
lima-1.0b5/lib/data/news/
lima-1.0b5/lib/data/players/
lima-1.0b5/lib/data/secure/
lima-1.0b5/lib/domains/
lima-1.0b5/lib/domains/std/2.4.5/maze1/
lima-1.0b5/lib/domains/std/2.4.5/npc/
lima-1.0b5/lib/domains/std/2.4.5/post_dir/
lima-1.0b5/lib/domains/std/2.4.5/sub/
lima-1.0b5/lib/domains/std/camera/
lima-1.0b5/lib/domains/std/config/
lima-1.0b5/lib/domains/std/cult/
lima-1.0b5/lib/domains/std/effects/
lima-1.0b5/lib/domains/std/misc/
lima-1.0b5/lib/domains/std/monsters/
lima-1.0b5/lib/domains/std/recorder/
lima-1.0b5/lib/domains/std/rooms/
lima-1.0b5/lib/domains/std/rooms/beach/
lima-1.0b5/lib/domains/std/rooms/labyrinth/
lima-1.0b5/lib/domains/std/school/
lima-1.0b5/lib/domains/std/school/O/
lima-1.0b5/lib/domains/std/spells/
lima-1.0b5/lib/domains/std/spells/stock-mage/
lima-1.0b5/lib/domains/std/spells/stock-priest/
lima-1.0b5/lib/help/
lima-1.0b5/lib/help/admin/
lima-1.0b5/lib/help/hints/General_Questions/
lima-1.0b5/lib/help/hints/Pirate_Quest/
lima-1.0b5/lib/help/player/
lima-1.0b5/lib/help/player/bin/
lima-1.0b5/lib/help/player/quests/
lima-1.0b5/lib/help/wizard/
lima-1.0b5/lib/help/wizard/coding/guilds/
lima-1.0b5/lib/help/wizard/coding/rooms/
lima-1.0b5/lib/help/wizard/lib/daemons/
lima-1.0b5/lib/help/wizard/lib/lfun/
lima-1.0b5/lib/help/wizard/lib/std/
lima-1.0b5/lib/help/wizard/mudos_doc/
lima-1.0b5/lib/help/wizard/mudos_doc/applies/
lima-1.0b5/lib/help/wizard/mudos_doc/applies/interactive/
lima-1.0b5/lib/help/wizard/mudos_doc/applies/parsing/
lima-1.0b5/lib/help/wizard/mudos_doc/concepts/
lima-1.0b5/lib/help/wizard/mudos_doc/driver/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/arrays/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/buffers/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/compile/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/filesystem/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/floats/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/functions/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/general/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/mappings/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/mixed/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/numbers/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/parsing/
lima-1.0b5/lib/help/wizard/mudos_doc/lpc/constructs/
lima-1.0b5/lib/help/wizard/mudos_doc/lpc/types/
lima-1.0b5/lib/include/driver/
lima-1.0b5/lib/log/
lima-1.0b5/lib/obj/admtool/
lima-1.0b5/lib/obj/admtool/internal/
lima-1.0b5/lib/obj/admtool/mudinfo/
lima-1.0b5/lib/obj/admtool/secure/
lima-1.0b5/lib/obj/secure/
lima-1.0b5/lib/obj/secure/cmd/
lima-1.0b5/lib/obj/secure/mailers/
lima-1.0b5/lib/obj/secure/shell/
lima-1.0b5/lib/obj/secure/shell/classes/
lima-1.0b5/lib/obj/tasktool/
lima-1.0b5/lib/obj/tasktool/internal/
lima-1.0b5/lib/open/
lima-1.0b5/lib/secure/
lima-1.0b5/lib/secure/cgi/
lima-1.0b5/lib/secure/modules/
lima-1.0b5/lib/secure/simul_efun/
lima-1.0b5/lib/std/adversary/
lima-1.0b5/lib/std/adversary/advancement/
lima-1.0b5/lib/std/adversary/armor/
lima-1.0b5/lib/std/adversary/blows/
lima-1.0b5/lib/std/adversary/death/
lima-1.0b5/lib/std/adversary/formula/
lima-1.0b5/lib/std/adversary/health/
lima-1.0b5/lib/std/adversary/pulse/
lima-1.0b5/lib/std/adversary/wield/
lima-1.0b5/lib/std/classes/event_info/
lima-1.0b5/lib/std/container/
lima-1.0b5/lib/std/living/
lima-1.0b5/lib/std/modules/contrib/
lima-1.0b5/lib/std/patterns/
lima-1.0b5/lib/std/race/
lima-1.0b5/lib/std/race/restricted/
lima-1.0b5/lib/std/room/
lima-1.0b5/lib/tmp/
lima-1.0b5/lib/trans/
lima-1.0b5/lib/trans/admincmds/
lima-1.0b5/lib/trans/obj/
lima-1.0b5/lib/wiz/
#define SUPPRESS_COMPILER_INLINES
#include "std.h"
#include "lpc_incl.h"
#include "swap.h"
#include "eoperators.h"
#include "compiler.h"
#include "replace_program.h"

INLINE void
dealloc_funp P1(funptr_t *, fp)
{
    program_t *prog = 0;

    switch (fp->hdr.type) {
	case FP_LOCAL | FP_NOT_BINDABLE:
	    if (fp->hdr.owner)
		prog = fp->hdr.owner->prog;
	    break;
	case FP_FUNCTIONAL:
	case FP_FUNCTIONAL | FP_NOT_BINDABLE:
	    prog = fp->f.functional.prog;
	    break;
    }

    if (fp->hdr.owner)
        free_object(fp->hdr.owner, "free_funp");
    if (fp->hdr.args)
	free_array(fp->hdr.args);

    if (prog) {
    	prog->func_ref--;
	debug(d_flag, ("subtr func ref /%s: now %i\n",
		    prog->name, prog->func_ref));
	if (!prog->func_ref && !prog->ref)
	    deallocate_program(prog);
    }

    FREE(fp);
}

INLINE void
free_funp P1(funptr_t *, fp)
{
    fp->hdr.ref--;
    if (fp->hdr.ref > 0) {
	return;
    }
    dealloc_funp(fp);
}

INLINE void
push_refed_funp P1(funptr_t *, fp)
{
    STACK_INC;
    sp->type = T_FUNCTION;
    sp->u.fp = fp;
}

INLINE void
push_funp P1(funptr_t *, fp)
{
    STACK_INC;
    sp->type = T_FUNCTION;
    sp->u.fp = fp;
    fp->hdr.ref++;
}

/* num_arg args are on the stack, and the args from the array vec should be
 * put in front of them.  This is so that the order of arguments is logical.
 * 
 * evaluate( (: f, a :), b) -> f(a,b) and not f(b, a) which would happen
 * if we simply pushed the args from vec at this point.  (Note that the
 * old function pointers are broken in this regard)
 */
int merge_arg_lists P3(int, num_arg, array_t *, arr, int, start) {
    int num_arr_arg = arr->size - start;
    svalue_t *sptr;
    
    if (num_arr_arg) {
	CHECK_STACK_OVERFLOW(num_arr_arg);
	sptr = (sp += num_arr_arg);
	if (num_arg) {
	    /* We need to do some stack movement so that the order
	       of arguments is logical */
	    while (num_arg--) {
		*sptr = *(sptr - num_arr_arg);
		sptr--;
	    }
	}
	num_arg = arr->size;
	while (--num_arg >= start)
	    assign_svalue_no_free(sptr--, &arr->item[num_arg]);
	/* could just return num_arr_arg if num_arg is 0 but .... -Sym */
	return (sp - sptr);
    }	    
    return num_arg;
}

INLINE funptr_t *
make_efun_funp P2(int, opcode, svalue_t *, args)
{
    funptr_t *fp;
    
    fp = (funptr_t *)DXALLOC(sizeof(funptr_hdr_t) + sizeof(efun_ptr_t),
			     TAG_FUNP, "make_efun_funp");
    fp->hdr.owner = current_object;
    add_ref( current_object, "make_efun_funp" );
    fp->hdr.type = FP_EFUN;
    
    fp->f.efun.index = opcode;
    
    if (args->type == T_ARRAY) {
	fp->hdr.args = args->u.arr;
	args->u.arr->ref++;
    } else
	fp->hdr.args = 0;
    
    fp->hdr.ref = 1;
    return fp;
}

INLINE funptr_t *
make_lfun_funp P2(int, index, svalue_t *, args)
{
    funptr_t *fp;
    int newindex;

    if (replace_program_pending(current_object))
	error("cannot bind an lfun fp to an object with a pending replace_program()\n");

    fp = (funptr_t *)DXALLOC(sizeof(funptr_hdr_t) + sizeof(local_ptr_t),
			     TAG_FUNP, "make_lfun_funp");
    fp->hdr.owner = current_object;
    add_ref( current_object, "make_lfun_funp" );
    fp->hdr.type = FP_LOCAL | FP_NOT_BINDABLE;
    
    fp->hdr.owner->prog->func_ref++;
    debug(d_flag, ("add func ref /%s: now %i\n",
		fp->hdr.owner->prog->name,
		fp->hdr.owner->prog->func_ref));
    
    newindex = index + function_index_offset;
    if (current_object->prog->function_flags[newindex] & FUNC_ALIAS)
	newindex = current_object->prog->function_flags[newindex] & ~FUNC_ALIAS;
    fp->f.local.index = newindex;
    
    if (args->type == T_ARRAY) {
	fp->hdr.args = args->u.arr;
	args->u.arr->ref++;
    } else
	fp->hdr.args = 0;
    
    fp->hdr.ref = 1;
    return fp;
}

INLINE funptr_t *
make_simul_funp P2(int, index, svalue_t *, args)
{
    funptr_t *fp;
    
    fp = (funptr_t *)DXALLOC(sizeof(funptr_hdr_t) + sizeof(simul_ptr_t),
			     TAG_FUNP, "make_simul_funp");
    fp->hdr.owner = current_object;
    add_ref( current_object, "make_simul_funp" );
    fp->hdr.type = FP_SIMUL;
    
    fp->f.simul.index = index;
    
    if (args->type == T_ARRAY) {
	fp->hdr.args = args->u.arr;
	args->u.arr->ref++;
    } else
	fp->hdr.args = 0;
    
    fp->hdr.ref = 1;
    return fp;
}

INLINE funptr_t *
make_functional_funp P5(short, num_arg, short, num_local, short, len, svalue_t *, args, int, flag)
{
    funptr_t *fp;

    if (replace_program_pending(current_object))
	error("cannot bind a functional to an object with a pending replace_program()\n");
    
    fp = (funptr_t *)DXALLOC(sizeof(funptr_hdr_t) + sizeof(functional_t), 
			     TAG_FUNP, "make_functional_funp");
    fp->hdr.owner = current_object;
    add_ref( current_object, "make_functional_funp" );
    fp->hdr.type = FP_FUNCTIONAL + flag;
    
    current_prog->func_ref++;
    debug(d_flag, ("add func ref /%s: now %i\n",
	       current_prog->name,
	       current_prog->func_ref));
    
    fp->f.functional.prog = current_prog;
    fp->f.functional.offset = pc - current_prog->program;
    fp->f.functional.num_arg = num_arg;
    fp->f.functional.num_local = num_local;
    fp->f.functional.fio = function_index_offset;
    fp->f.functional.vio = variable_index_offset;
    pc += len;
    
    if (args && args->type == T_ARRAY) {
	fp->hdr.args = args->u.arr;
	args->u.arr->ref++;
	fp->f.functional.num_arg += args->u.arr->size;
    } else
	fp->hdr.args = 0;
    
    fp->hdr.ref = 1;
    return fp;
}

typedef void (*func_t) PROT((void));
extern func_t efun_table[];

svalue_t *
call_function_pointer P2(funptr_t *, funp, int, num_arg)
{
    static func_t *oefun_table = efun_table - BASE;
    
    if (!funp->hdr.owner || (funp->hdr.owner->flags & O_DESTRUCTED))
	error("Owner (/%s) of function pointer is destructed.\n",
	      (funp->hdr.owner ? funp->hdr.owner->name : "(null)"));
    
    setup_fake_frame(funp);
    if (current_object->flags & O_SWAPPED)
	load_ob_from_swap(current_object);

    switch (funp->hdr.type) {
    case FP_SIMUL:
	if (funp->hdr.args) {
	    check_for_destr(funp->hdr.args);
	    num_arg = merge_arg_lists(num_arg, funp->hdr.args, 0);
	}
	call_simul_efun(funp->f.simul.index, num_arg);
	break;
    case FP_EFUN:
	{
	    int i, def;
	    
	    fp = sp - num_arg + 1;
	    if (funp->hdr.args) {
		check_for_destr(funp->hdr.args);
		num_arg = merge_arg_lists(num_arg, funp->hdr.args, 0);
	    }
	    i = funp->f.efun.index;
	    if (num_arg == instrs[i].min_arg - 1 && 
		((def = instrs[i].Default) != DEFAULT_NONE)) {
		if (def == DEFAULT_THIS_OBJECT) {
		    push_object(current_object);
		} else {
		    push_number(def);
		}
		num_arg++;
	    } else
		if (num_arg < instrs[i].min_arg) {
		    error("Too few arguments to efun %s in efun pointer.\n", query_instr_name(i));
		} else if (num_arg > instrs[i].max_arg && instrs[i].max_arg != -1) {
		    error("Too many arguments to efun %s in efun pointer.\n", query_instr_name(i));
		}
	    /* possibly we should add TRACE, OPC, etc here;
	       also on eval_cost here, which is ok for just 1 efun */
	    {
		int j, n = num_arg;
		st_num_arg = num_arg;

		if (n >= 4 || instrs[i].max_arg == -1)
		    n = instrs[i].min_arg;

		for (j = 0; j < n; j++) {
		    CHECK_TYPES(sp - num_arg + j + 1, instrs[i].type[j], j + 1, i);
		}
		(*oefun_table[i])();

		free_svalue(&apply_ret_value, "call_function_pointer");
		if (instrs[i].ret_type == TYPE_NOVALUE)
		    apply_ret_value = const0;
		else
		    apply_ret_value = *sp--;
		remove_fake_frame();
		return &apply_ret_value;
	    }
	}
    case FP_LOCAL | FP_NOT_BINDABLE: {
        function_t *func;

	fp = sp - num_arg + 1;

	if (current_object->prog->function_flags[funp->f.local.index] & (FUNC_PROTOTYPE|FUNC_UNDEFINED))
	    error("Undefined lfun pointer called: %s\n", function_name(current_object->prog, funp->f.local.index));

	push_control_stack(FRAME_FUNCTION);
	current_prog = funp->hdr.owner->prog;
	
	caller_type = ORIGIN_LOCAL;

	if (funp->hdr.args) {
	    array_t *v = funp->hdr.args;

	    check_for_destr(v);
	    num_arg = merge_arg_lists(num_arg, v, 0);
	}

	csp->num_local_variables = num_arg;
	func = setup_new_frame(funp->f.local.index);

	call_program(current_prog, func->address);
	break;
    }
    case FP_FUNCTIONAL: 
    case FP_FUNCTIONAL | FP_NOT_BINDABLE: {
	fp = sp - num_arg + 1;

	push_control_stack(FRAME_FUNP);
	current_prog = funp->f.functional.prog;
	csp->fr.funp = funp;
	
	caller_type = ORIGIN_FUNCTIONAL;

	if (funp->hdr.args) {
	    array_t *v = funp->hdr.args;

	    check_for_destr(v);
	    num_arg = merge_arg_lists(num_arg, v, 0);
	}

	setup_variables(num_arg, funp->f.functional.num_local,
			funp->f.functional.num_arg);

	function_index_offset = funp->f.functional.fio;
	variable_index_offset = funp->f.functional.vio;
	call_program(funp->f.functional.prog, funp->f.functional.offset);
	break;
    }
    default:
	error("Unsupported function pointer type.\n");
    }
    free_svalue(&apply_ret_value, "call_function_pointer");
    apply_ret_value = *sp--;
    remove_fake_frame();
    return &apply_ret_value;
}

svalue_t *
safe_call_function_pointer P2(funptr_t *, funp, int, num_arg)
{
    error_context_t econ;
    svalue_t *ret;

    if (!save_context(&econ))
	return 0;
    if (!SETJMP(econ.context)) {
	ret = call_function_pointer(funp, num_arg);
    } else {
	restore_context(&econ);
	/* condition was restored to where it was when we came in */
	pop_n_elems(num_arg);
	ret = 0;
    }
    pop_context(&econ);
    return ret;
}