lpc4/lib/
lpc4/lib/doc/efun/
lpc4/lib/doc/lfun/
lpc4/lib/doc/operators/
lpc4/lib/doc/simul_efuns/
lpc4/lib/doc/types/
lpc4/lib/etc/
lpc4/lib/include/
lpc4/lib/include/arpa/
lpc4/lib/obj/d/
lpc4/lib/save/
lpc4/lib/secure/
lpc4/lib/std/
lpc4/lib/std/living/
#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;
}