#include "global.h"
#include <sys/types.h>
#include <sys/stat.h>
#include "simulate.h"
#include "interpret.h"
#include "object.h"
#include "sent.h"
#include "exec.h"
#include "main.h"
#include "stralloc.h"
#include "array.h"
extern int d_flag;
extern int total_num_prog_blocks, total_prog_block_size;
int tot_alloc_object, tot_alloc_object_size;
/*
* Send a message to an object.
*/
void vtell_object(char *str,...)
{
va_list args;
char buf[10000];
struct object *save_command_giver;
if(command_giver && !(command_giver->flags && O_DESTRUCTED))
{
if(current_object->flags & O_DESTRUCTED)
return;
va_start(args,str);
VSPRINTF(buf,str,args);
va_end(args);
if(strlen(buf)>9500)
error("Too long message\n");
save_command_giver = command_giver;
push_new_shared_string(buf);
apply_lfun(LF_CATCH_TELL,command_giver,1,0);
command_giver = save_command_giver;
}
}
#ifdef DEBUG
void free_object(struct object *ob, char *from)
{
ob->ref--;
if (d_flag > 1)
fprintf(stderr,"Subtr ref to ob %s: %d (%s)\n",
ob->prog?ob->prog->name:"DESTRUCTED",
ob->ref, from);
#else
void real_free_object(struct object *ob,char *from)
{
#endif
if(ob->ref==1 && (ob->flags & O_EXPUNGE) && !(ob->flags & O_DESTRUCTED))
{
destruct_object(ob);
return;
}
if (ob->ref > 0) return;
if (d_flag) fprintf(stderr,"free_object: %s.\n",
ob->prog?ob->prog->name:"DESTRUCTED");
if (!(ob->flags & O_DESTRUCTED))
{
/* This is fatal, and should never happen. */
fatal("FATAL: Object %p %s ref count 0, but not destructed (from %s).\n",
ob,
ob->prog?ob->prog->name:"DESTRUCTED",
from);
}
tot_alloc_object_size -= sizeof (struct object);
tot_alloc_object--;
free((char *)ob);
}
#ifdef DEBUG
void add_ref(struct object *ob,char *from)
{
ob->ref++;
if (d_flag > 1)
fprintf(stderr,"Add reference to object %s: %d (%s)\n", ob->prog->name,
ob->ref, from);
}
#endif
/*
* Allocate an empty object, and set all variables to 0. Note that a
* 'struct object' already has space for one variable. So, if no variables
* are needed, we allocate a space that is smaller than 'struct object'. This
* unused (last) part must of course (and will not) be referenced.
*/
struct object *get_empty_object(struct program *p)
{
extern int new_clone_number,current_time;
struct object *ob;
int size = sizeof (struct object) + (p->num_variables- 1) * sizeof(union storage_union);
int e;
tot_alloc_object++;
tot_alloc_object_size += size;
ob = (struct object *)calloc(size,1);
ob->ref = 1;
ob->clone_number=(++new_clone_number);
ob->flags = p->flags & ( O_APPROVED | O_WILL_CLEAN_UP | O_REF_CYCLE) ;
ob->created =current_time;
ob->prog = p;
reference_prog (p, "new_object");
ob->next_all = obj_list;
obj_list = ob;
for(e=0;e<p->num_variables;e++)
{
if(p->variable_names[e].rttype==T_ANY)
{
SET_TO_ZERO(*(struct svalue *)(ob->variables+e));
e++;
}else{
ob->variables[e].number=0;
}
}
return ob;
}
void remove_all_objects()
{
struct object *ob;
while(obj_list)
{
ob = obj_list;
destruct_object(ob);
if (ob == obj_list) break;
}
remove_destructed_objects();
}
void reference_prog (struct program *progp,char *from)
{
progp->ref++;
if (d_flag)
printf("reference_prog: %s ref %d (%s)\n",
progp->name, progp->ref, from);
}
/*
* Decrement reference count for a program. If it is 0, then free the prgram.
* The flag free_sub_strings tells if the propgram plus all used strings
* should be freed.
*/
void free_prog(struct program *progp, int free_sub_strings)
{
progp->ref--;
if (d_flag)
printf("free_prog: %s (%d)\n", progp->name,progp->ref);
if (progp->ref > 0)
return;
if (progp->ref < 0)
fatal("Negative ref count for prog ref.\n");
total_prog_block_size -= progp->total_size;
total_num_prog_blocks -= 1;
if (free_sub_strings) {
int i;
/* Free all function names. */
for (i=0; i < progp->num_functions; i++)
if (progp->functions[i].name)
free_string(progp->functions[i].name);
/* Free all strings */
for (i=0; i < progp->num_strings; i++)
free_string(progp->strings[i]);
/* Free all variable names */
for (i=0; i < progp->num_variables; i++)
free_string(progp->variable_names[i].name);
/* Free all inherited objects */
/* Remember that the first index is just ourselves */
for (i=1; i < progp->num_inherited; i++)
free_prog(progp->inherit[i].prog, 1);
/* Free all switch mappings */
for (i=0; i < progp->num_switch_mappings; i++)
free_vector(progp->switch_mappings[i]);
/* Free all constants */
for (i=0; i < progp->num_constants; i++)
free_svalue(progp->constants+i);
/* Free the name of the program */
free_string(progp->name);
}
free((char *)progp);
}
void reset_object(struct object *ob,int arg)
{
extern int current_time;
extern void push_shared_string(char *);
/* Be sure to update time first ! */
ob->next_reset = current_time + TIME_TO_RESET/2 +
random_number(TIME_TO_RESET/2);
if(!arg)
{
apply("__INIT", ob, 0,1);
if(!(ob->flags & O_DESTRUCTED)) apply("create", ob, 0,1);
} else {
apply("reset", ob, 0,1);
}
ob->flags |= O_RESET_STATE;
}