#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