/
driver3.2@242/autoconf/
driver3.2@242/doc/LPC/
driver3.2@242/hosts/
driver3.2@242/hosts/amiga/NetIncl/
driver3.2@242/hosts/amiga/NetIncl/netinet/
driver3.2@242/hosts/amiga/NetIncl/sys/
driver3.2@242/hosts/atari/
driver3.2@242/hosts/fcrypt/
driver3.2@242/mudlib/
driver3.2@242/mudlib/sys/
driver3.2@242/util/
driver3.2@242/util/indent/hosts/next/
driver3.2@242/util/make_docs/
#include <stdio.h>

#include "lint.h"
#include "interpret.h"
#include "object.h"
#include "exec.h"
#include "lex.h"
#include "lang.h"
#include "instrs.h"
#include "stralloc.h"

struct function *simul_efunp = 0;
static int num_simul_efun    = 0;
static int total_simul_efun  = 0;

/* Don't release this pointer ever. It is used elsewhere. */
static char *simul_efun_file_name = 0;
struct object *simul_efun_object  = 0;
struct program *simul_efun_program= 0;
struct vector *simul_efun_vector  = 0;

struct simul_efun_table_s simul_efun_table[256];

static struct ident *all_simul_efuns = 0;
short all_discarded_simul_efun = -1;

/*
 * If there is a simul_efun file, then take care of it and extract all
 * information we need.
 */
struct object *get_simul_efun_object()
{
    extern struct ident *all_efuns;

    struct svalue *svp;
    extern void free_defines();
    struct object *ob;
    struct program *progp;
    char *name;
    int i, j, num_fun;
    struct ident *id;
    struct simul_efun_table_s *entry;
    char *visible;

    for(entry = simul_efun_table, i=256; --i >= 0; ) {
	entry->funstart = 0;
	entry++;
    }
    free_defines(); /* to prevent #defines hideing places for globals */
    for(id = all_efuns; id; id = id->next_all) {
        id->u.global.sim_efun |= -0x8000;
    }
    for(id = all_simul_efuns; id; id = id->next_all) {
        id->u.global.sim_efun |= -0x8000;
    }
    if (simul_efun_program) {
	free_prog(simul_efun_program, 1);
	simul_efun_program = 0;
    }
    if (simul_efun_vector) {
	free_vector(simul_efun_vector);
	simul_efun_vector = 0;
    }
    svp = apply_master_ob("get_simul_efun", 0);
    if (svp == 0) {
	fprintf(stderr, "No simul_efun\n");
	return 0;
    }
    if (svp->type == T_POINTER) {
	simul_efun_vector = svp->u.vec;
	svp->type = T_NUMBER;
	if (svp->u.vec->size)
	    svp = svp->u.vec->item;
    }
    if (svp->type != T_STRING) {
	fprintf(stderr, "No simul_efun\n");
	return 0;
    }
    name = svp->u.string;
    while (*name == '/') name++;
    if (simul_efun_file_name) free_string(simul_efun_file_name);
    simul_efun_file_name = make_shared_string(name);

    ob = find_object2(simul_efun_file_name);

    if (ob == 0) {
	fprintf(stderr, "The simul_efun file %s was not loaded.\n",
		simul_efun_file_name);
	fprintf(stderr, "The function get_simul_efun in master.c must load it.\n");
	exit(1);
    }
    reference_prog( (simul_efun_program = ob->prog), "get_simul_efun");
    num_fun = ob->prog->num_function_names;
    if (num_fun == 0)
	return 0;
    if (!simul_efunp) {
	simul_efunp = (struct function *)
	  xalloc(sizeof (struct function) * num_fun);
    } else num_fun = total_simul_efun;
    free_defines(); /* to prevent #defines hideing places for globals */
    /* locals and defines are freed now. There are still reserved words,
     * but it is impossible to define a function with the name being
     * a reserved word, thus, there will be no clashes with higher-priority
     * shared identifiers.
     */
    progp = ob->prog;
    visible = alloca(i = ob->prog->num_functions);
    bzero(visible, i);
    i = ob->prog->num_function_names;
    while(--i >= 0)
	visible[progp->function_names[i]] = 1;
    for (i=0; i < ob->prog->num_functions; i++) {
	int ix;
	uint32 flags, flags2;
	unsigned char *funstart;
	mp_int fun_ix_offs, var_ix_offs;
	struct program *inherit_progp;

	if (!visible[i])
	    continue;
	ix = i;
	flags2 = flags = progp->functions[ix];
	flags &= ~FUNSTART_MASK;
	fun_ix_offs = ix;
	var_ix_offs = 0;
	inherit_progp = progp;
	while (flags2 & NAME_INHERITED) {
	    struct inherit *inheritp;

	    inheritp = &inherit_progp->inherit[flags2 & INHERIT_MASK];
	    ix -= inheritp->function_index_offset;
	    var_ix_offs += inheritp->variable_index_offset;
	    inherit_progp = inheritp->prog;
	    flags2 = inherit_progp->functions[ix];
	}
	fun_ix_offs -= ix;
	funstart = inherit_progp->program + (flags2 & FUNSTART_MASK);
	if (funstart[2] == F_ESCAPE-F_OFFSET &&
	    funstart[3] == F_UNDEF - F_OFFSET - 0x100)
	{
	    flags |= NAME_UNDEFINED;
	}
	if ( !(flags & (TYPE_MOD_STATIC|TYPE_MOD_PRIVATE|NAME_UNDEFINED)) )
	{
	    char *function_name;
	    struct ident *p;
	    unsigned char type, num_arg, num_locals;

	    memcpy(
	      (char *)&function_name,
	      funstart - 1 - sizeof function_name,
	      sizeof function_name
	    );
	    type = funstart[-1];
	    num_arg = funstart[0];
	    num_locals = funstart[1];
	    p = make_shared_identifier(function_name, I_TYPE_GLOBAL);
	    if (p->type == I_TYPE_UNKNOWN) {
		p->type = I_TYPE_GLOBAL;
		p->u.global.function = -2;
		p->u.global.variable = -2;
		p->u.global.efun     = -1;
		p->u.global.sim_efun = -1;
		p->next_all = all_simul_efuns;
		all_simul_efuns = p;
	    }
	    if (flags & TYPE_MOD_VARARGS) num_arg = -1;
	    switch(0) { default:
		if ((j=p->u.global.sim_efun) != -1) {
		    j &= ~-0x8000;
		    if (simul_efunp[j].num_arg != num_arg) {
			int last;

			simul_efunp[j].offset.func = all_discarded_simul_efun;
			all_discarded_simul_efun = j;
			while ( (j = simul_efunp[last=j].offset.func) >= 0) {
			    if (num_arg != simul_efunp[j].num_arg)
				continue;
			    if (strcmp(function_name, simul_efunp[j].name))
				continue;
			    simul_efunp[last].offset.func =
			      simul_efunp[j ].offset.func;
			    break;
			}
		        if (j >= 0) break; /* switch */
		    } else break;          /* switch */
		}
		increment_string_ref(function_name);
		j = num_simul_efun++;
		if (num_simul_efun > num_fun) {
		    num_fun = num_simul_efun + 12;
		    simul_efunp = (struct function *) rexalloc(
	  		(char *)simul_efunp,
	  		sizeof (struct function) * num_fun
	  	    );
		}
	        simul_efunp[j].num_arg = num_arg;
	    }
	    p->u.global.sim_efun = j;
	    simul_efunp[j].name    = function_name;
	    simul_efunp[j].flags   = flags;
	    simul_efunp[j].type    = type;

	    if (j < sizeof simul_efun_table / sizeof simul_efun_table[0]) {
		simul_efun_table[j].funstart = funstart;
		simul_efun_table[j].program = inherit_progp;
		simul_efun_table[j].function_index_offset = fun_ix_offs;
		simul_efun_table[j].variable_index_offset = var_ix_offs;
	    }
	}
    }
    total_simul_efun = num_fun;
    simul_efun_object = ob;
    return ob;
}

#if 0
/*
 * Test if 'name' is a simul_efun. The string pointer MUST be a pointer to
 * a shared string.
 */
struct function *find_simul_efun(name)
    char *name;
{
    int i;
    for (i=0; i < num_simul_efun; i++) {
	if (name == simul_efunp[i].name)
	    return &simul_efunp[i];
    }
    return 0;
}
#endif

char *query_simul_efun_file_name() {
#ifdef DEBUG
    if (simul_efunp == 0)
	fatal("query_simul_efun_file_name called when non exists!\n");
#endif
    return simul_efun_file_name;
}

#ifdef MALLOC_smalloc
void clear_simul_efun_refs() {
    if (simul_efun_vector && simul_efun_vector->ref) {
	simul_efun_vector->ref = 0;
	clear_ref_in_vector(simul_efun_vector->item, simul_efun_vector->size);
    }
    if (simul_efun_program)
	simul_efun_program->ref = 0;
}

void count_simul_efun_refs() {
    extern void mark_program_ref PROT((struct program *));

    if (simul_efun_file_name)
	count_ref_from_string(simul_efun_file_name);
    if (simul_efunp) {
	int i;

	note_malloced_block_ref((char *)simul_efunp);
	for (i = num_simul_efun; --i >= 0; )
	    count_ref_from_string(simul_efunp[i].name);
    }
    if (simul_efun_vector && !simul_efun_vector->ref++) {
	note_malloced_block_ref((char *)simul_efun_vector);
	count_ref_in_vector(simul_efun_vector->item, simul_efun_vector->size);
    }
    if (simul_efun_program)
	mark_program_ref(simul_efun_program);
}
#endif /* MALLOC_smalloc */

#ifdef DEBUG
void count_simul_efun_extra_refs() {
    extern int register_pointer PROT((char *));

    if (simul_efun_vector) {
	simul_efun_vector->extra_ref++;
        if ( !register_pointer( (char *)(simul_efun_vector) ) )
	    count_extra_ref_in_vector(
	      simul_efun_vector->item,
	      simul_efun_vector->size
	    );
    }
    if (simul_efun_program) {
	simul_efun_program->extra_ref++;
	if (register_pointer((char *)simul_efun_program))
	    return;
	simul_efun_program->extra_ref = 1;
	count_inherits(simul_efun_program);
    }
}
#endif