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"
#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include "array.h"
#include "interpret.h"
#include "object.h"
#include "regexp.h"
#include "exec.h"
#include "main.h"
#include "stralloc.h"
#include "simulate.h"
#include "operators.h"


#define VECTOR_SIZE(nelem) (sizeof(struct vector) +sizeof(struct svalue) * (nelem-1))
#define ALLOC_VECTOR(nelem)  (struct vector *)xalloc(VECTOR_SIZE(nelem))

/*
 * This file contains functions used to manipulate arrays.
 * Some of them are connected to efuns, and some are only used internally
 * by the game driver.
 */

extern int d_flag;

int num_arrays;
int total_array_size;

/*
 * Make an empty vector for everyone to use, never to be deallocated.
 * It is cheaper to reuse it, than to use malloc() and allocate.
 */
struct vector null_vector = {
    1,	/* Ref count, which will ensure that it will never be deallocated */
    0,	/* size */
    0,  /* malloced size */
    1   /* is clean */
};

struct vector *allocate_array_no_init(int n,int overhead)
{
  int i;
  struct vector *p;

  if (!batch_mode && (n < 0 || n > MAX_ARRAY_SIZE))
    error("Illegal array size.\n");

  if (n == 0)
  {
    p = &null_vector;
    p->ref++;
  }else{
    num_arrays++;
    total_array_size += VECTOR_SIZE(n);

    /* overhead stuff */
    i=n+overhead;
    if(i>MAX_ARRAY_SIZE && !batch_mode) i=MAX_ARRAY_SIZE;
    p = ALLOC_VECTOR(i);
    p->malloced_size=i;
    p->ref = 1;
    p->size = n;
    p->flags=ref_cycle;
    p->types=-1;

#ifdef DEBUG
    p->next=null_vector.next;
    null_vector.next=p;
#endif
  }
  return p;
}

/*
 * Allocate an array of size 'n'.
 * Observe that the overhead is not guarateed.
 */
struct vector *allocate_array_with_overhead(int n,int overhead)
{
  struct vector *p;
  int i;
  p=allocate_array_no_init(n,overhead);
  for (i=0; i<n; i++) SET_TO_ZERO(p->item[i]);
  return p;
}

struct vector *allocate_array(int n)
{
  return allocate_array_with_overhead(n,0);
}

#ifdef DEBUG
void free_vector(struct vector *p)
{
#ifdef MALLOC_DEBUG
  check_sfltable();
#endif
  p->ref--;
  if (p->ref > 0)
    return;
  if(p->size>p->malloced_size)
  {
    fatal("Impossible array.");
  }
  if(p->ref<0) fatal("Freeing array too many times.\n");
#else

void real_free_vector(struct vector *p)
{  
#endif

#ifdef DEBUG
  if (p == &null_vector)
    fatal("Tried to free the zero-size shared vector.\n");

{
  struct vector *v;
  for(v=&null_vector;v;v=v->next)
  {
    if(v->next==p)
    {
      v->next=p->next;
      break;
    }
  }
  if(!v) fatal("Array not found in linked list.\n");
  if((v=null_vector.next))
  {
    do{
      if(!v->ref)
	fatal("Extremely fatal error in arrays.\n");
    }while(v->size && v->item[0].type==T_POINTER && (v=v->item[0].u.vec));
  }
}
#endif

  free_svalues(p->item,p->size);
  num_arrays--;
  total_array_size -= sizeof (struct vector) + sizeof (struct svalue) *
    (p->size-1);
  free((char *)p);
}

/* OBS, destructive */
struct vector *resize_array(struct vector *p,int n)
{
  struct vector *res;
  int e;
  if(p->size==n) return p;
  if(n>p->size)
  {
    /* we should grow the array */
    if(n<=p->malloced_size)
    {
      /* it fits */
      p->types|=BT_NUMBER;
      for(e=p->size+1;e<n;e++) SET_TO_ZERO(p->item[e]);
      e=n-p->size;
      total_array_size +=sizeof(struct svalue) *e ;
      p->size=n;
      return p;
    }
    res=allocate_array_no_init(n,(n>>4)+1);
    
    for(e=0;e<p->size;e++) res->item[e]=p->item[e];
    for(;e<n;e++) SET_TO_ZERO(res->item[e]);
    res->types=p->types | BT_NUMBER;
    p->size=0; /* ugly trick */
    free_vector(p);
    return res;
  }else{
    /* we should shrink the array */
    if(n<=(p->malloced_size>>11))
    {
      /* overhead to big, reallocate the array */
      res = slice_array(p, 0, n-1);
      free_vector(p);
      return res;
    }
    e=n-p->size;
    total_array_size += sizeof (struct svalue) * e;
    while(p->size>n) free_svalue(p->item+--(p->size));
    p->size = n;
    return p;
  }
}

struct vector *shrink_array(struct vector *p,int n)
{
  struct vector *res;
  int e;
  if(p->size==n) return p;
  if(n<=(p->malloced_size>>11))
  {
    /* overhead to big, reallocate the array */
    res = slice_array(p, 0, n-1);
    free_vector(p);
    return res;
  }
  e=n-p->size;
  total_array_size += sizeof (struct svalue) * e;
  p->size = n;
  return p;
}

static struct vector *insert_array(struct vector *v,int n,struct svalue *s)
{
  struct vector *res;
  int e;
#ifdef DEBUG
  if(n<0 || n>v->size) fatal("Illegal insert.\n");
#endif

  if(v->size<v->malloced_size)
  {
    /* it fits */
    for(e=v->size;e>n;e--) v->item[e]=v->item[e-1];
    v->size++;
    SET_TO_ZERO(v->item[n]);
  }else{
    res=allocate_array_no_init(v->size+1,(v->size>>4)+1);
    for(e=0;e<n;e++) res->item[e]=v->item[e];
    SET_TO_ZERO(res->item[e]);
    for(;e<v->size;e++) res->item[e+1]=v->item[e];
    v->size=0; /* ugly trick */
    free_vector(v);
    v=res;
  }
  assign_svalue(v->item+n,s);
  v->types |= 1<< (s->type);
  return v;
}

/* Rewritten by Profezzorn */

/* a binary string capable explode */

struct vector *explode(struct svalue *str,struct svalue *del)
{
  int str_len,del_len,e,tmp,begin;
  struct vector *v;
  char *s,*d;

  s=strptr(str);
  d=strptr(del);

  str_len=my_strlen(str);
  del_len=my_strlen(del);

  if(!del_len)
  {
    v=allocate_array_no_init(str_len,0);
    for(e=0;e<str_len;e++)
    {
      SET_STR(v->item+e,make_shared_binary_string(s+e,1));
    }
  }else{
    for(tmp=e=0;e<=str_len-del_len;)
    {
      if(!MEMCMP(s+e,d,del_len))
      {
        tmp++;
        e+=del_len;
      }else{
        e++;
      }
    }

    v=allocate_array_no_init(tmp+1,0);
    if(!tmp)
    {
      assign_svalue_no_free(v->item,str);
      return v;
    }
    for(begin=tmp=e=0;e<=str_len-del_len;)
    {
      if(!MEMCMP(s+e,d,del_len))
      {
	SET_STR(v->item+tmp,make_shared_binary_string(s+begin,e-begin));
        tmp++;
        e+=del_len;
        begin=e;
      }else{
        e++;
      }
    }
    SET_STR(v->item+tmp,make_shared_binary_string(s+begin,str_len-begin));
  }
  v->types=BT_STRING; /* nothing but us strings here */
  return v;
}

/* a binary implode */

void implode(struct svalue *to,struct vector *v,struct svalue *del)
{
  int del_len,len,e;
  char *s,*s2,*del_str;
  
  del_len=my_strlen(del);
  del_str=strptr(del);

  len=del_len*(v->size-1);
  for(e=0;e<v->size;e++)
  {
    if(v->item[e].type!=T_STRING) continue;
    len+=my_strlen(v->item+e);
  }

  if(len<=0)
  {
    assign_svalue_no_free(to,&const_empty_string);
  }else{
    s2=s=begin_shared_string(len);
    
    for(e=0;e<v->size;e++)
    {
      if(e)
      {
        MEMCPY(s2,del_str,del_len);
        s2+=del_len;
      }
      if(v->item[e].type!=T_STRING) continue;

      len=my_strlen(v->item+e);
      MEMCPY(s2,strptr(v->item+e),len);
      s2+=len;
    }
    SET_STR(to,end_shared_string(s)); /* may or may not use same area */
  }
}


/* The following two functions are for the replace() efun....
 *   Profezzorn
 */

struct vector *array_replace(struct vector *from,struct svalue *what,struct svalue *to)
{
  int e;
  struct vector *ret;
  check_vector_for_destruct(from);
  ret=allocate_array_no_init(from->size,0);
  for(e=0;e<from->size;e++)
  {
    if(is_eq(what,&(from->item[e])))
      assign_svalue_no_free(&(ret->item[e]),to);
    else
      assign_svalue_raw(&(ret->item[e]),&(from->item[e]));
  }
  return ret;
}

/*
 * Slice of an array.
 */
struct vector *slice_array(struct vector *p,int from,int to)
{
  struct vector *d;
    
  if (from < 0) from = 0;
  if (from >= p->size)  return allocate_array(0);	/* Slice starts above array */
  if (to >= p->size)  to = p->size-1;
  if (to < from)  return allocate_array(0); 
    
  d = allocate_array_no_init(to-from+1,0);
  d->types=p->types;

  copy_svalues_no_free(d->item,p->item+from,to-from+1);
  return d;
}

/* EFUN: filter_array
   
   Runs all elements of an array through ob->func()
   and returns an array holding those elements that ob->func
   returned 1 for.
   Hacking a little: if ob==0 then we call in the object in the array
                     instead.......
   */
struct vector *filter(p, lambda, extra, num_extra_arg)
  struct vector *p;
  struct svalue *lambda;
  struct svalue *extra;
  int num_extra_arg;
{
  struct vector *v,*r;
  int e,num;

  if (p->size<1) return allocate_array(0);
  v=map_array(p,lambda,extra,num_extra_arg);
  for(num=e=0;e<v->size;e++)
    if(v->item[e].type!=T_NUMBER || (v->item[e].u.number!=0)) num++;

  r=allocate_array_no_init(num,0);
  num=0;
  for(e=0;e<v->size;e++)
    if(v->item[e].type!=T_NUMBER || (v->item[e].u.number!=0))
      assign_svalue_no_free(&r->item[num++], &p->item[e]);
  free_vector(v);
  return r;
}

/* Concatenation of two arrays into one
 */
struct vector *add_array(struct vector *p,struct vector *r)
{
  struct vector *d;
    
  d = allocate_array_no_init(p->size+r->size,0);
  copy_svalues_no_free(d->item,p->item,p->size);
  copy_svalues_no_free(d->item+p->size,p->item,p->size);
  return d;
}

int search_alist(struct svalue *key,struct vector * keylist)
{
  int a,b,c,d;
  a=0;
  b=keylist->size;
  while(a<b)
  {
    c=(a+b)>>1;
    d=alist_cmp(key,keylist->item+c);
    if(d<0) b=c;
    else if(d>0) a=c+1;
    else return c;
  }
  if(a<keylist->size && alist_cmp(key,keylist->item+a)>0) a++;
  return a;
}

int assoc(struct svalue *key,struct vector *keylist)
{
  int a,b,c,d;
  a=0;
  b=keylist->size;
  while(a!=b)
  {
    c=(a+b)>>1;
    d=alist_cmp(key,keylist->item+c);
    if(d<0) b=c;
    else if(d>0) a=c+1;
    else return c;
  }
  return -1;
}

struct vector *subtract_array(struct vector *minuend,
			      struct vector * subtrahend)
{
  struct vector *vtmp;
  struct vector *difference;
  struct svalue *source,*dest;
  int i;

  vtmp=allocate_array(1);
  vtmp->item[0].type=T_ALIST_PART;
  if(subtrahend->ref==1)
  {
    vtmp->item[0].u.vec = subtrahend;
    subtrahend->ref++;
  }else{
    vtmp->item[0].u.vec = slice_array(subtrahend,0,subtrahend->size);
  }
  order_alist(vtmp);
  subtrahend = vtmp->item[0].u.vec;
  difference = allocate_array(minuend->size);
  check_vector_for_destruct(minuend);
  for (source = minuend->item, dest = difference->item, i = minuend->size;
       i--; source++)
  {
    if ( assoc(source, subtrahend) < 0 )
      assign_svalue_raw(dest++, source);
  }
  free_vector(vtmp);
  return shrink_array(difference, dest-difference->item);
}


/* Returns an array of all objects contained in 'ob'
 */
struct vector *all_inventory(struct object *ob)
{
  struct vector *d;
  struct object *cur;
  int cnt,res;
    
  cnt=0;
  for (cur=ob->contains; cur; cur = cur->next_inv)
    cnt++;
    
  if (!cnt)
    return allocate_array(0);

  d = allocate_array_no_init(cnt,0);
  cur=ob->contains;
    
  for (res=0;res<cnt;res++)
  {
    d->item[res].type=T_OBJECT;
    d->item[res].u.ob = cur;
    add_ref(cur,"all_inventory");
    cur=cur->next_inv;
  }
  return d;
}


/* Runs all elements of an array through ob::func
   and replaces each value in arr by the value returned by ob::func
   Hacking a little: if ob==0 then we call in the object in the array
                     instead.......
   */
struct vector *map_array(
	struct vector *p,
	struct svalue *lambda,
	struct svalue *extra,
	int num_extra_arg)
{
  struct vector *r;
  struct svalue *v;
  char *func=0; /* make gcc happy */
  int cnt,no;
    
  r=0;
  switch(lambda->type)
  {
  case T_STRING:
    func=strptr(lambda);
    break;

  case T_FUNCTION:
    if(lambda->u.ob->flags & O_DESTRUCTED)
      error("Invalid lambda to map_array.\n");
    break;

  case T_NUMBER:
    break;

  default:
    error("Bad arg to map_array.\n");
  }

  if (p->size<1) return allocate_array(0);
 
  r = allocate_array(p->size);
 
  for (cnt=0;cnt<p->size;cnt++)
  {
    check_eval_cost();
    switch(lambda->type)
    {
    case T_NUMBER:
      if(lambda->subtype!=NUMBER_NUMBER)
      {
	v=0;
	continue;
      }
      if(lambda->u.number<0)
      {
        if(p->item[cnt].type!=T_FUNCTION ||
	   (p->item[cnt].u.ob->flags & O_DESTRUCTED)) continue;
        for(no=0;no<num_extra_arg;no++) push_svalue(extra+no);
        v=apply_lambda(p->item+cnt,no,0);
      }else{
	if(p->item[cnt].type!=T_OBJECT ||
	   (p->item[cnt].u.ob->flags & O_DESTRUCTED)) continue;
	for(no=0;no<num_extra_arg;no++) push_svalue(extra+no);
	v=apply_lfun(lambda->u.number,p->item[cnt].u.ob,no,0);
      }
      break;

    case T_STRING:
      if(p->item[cnt].type!=T_OBJECT ||
	 (p->item[cnt].u.ob->flags & O_DESTRUCTED)) continue;
      for(no=0;no<num_extra_arg;no++) push_svalue(extra+no);
      v=apply_shared(func,p->item[cnt].u.ob,no,0);
      break;

    case T_FUNCTION:
      if(lambda->u.ob->flags & O_DESTRUCTED)
	error("object used by map_array destructed\n");
      push_svalue(&p->item[cnt]);
      for(no=0;no<num_extra_arg;no++) push_svalue(extra+no);
      v=apply_lambda(lambda,no+1,0);
      break;

    default:
      fatal("Fatal error in map_array.\n");
      return 0;
    }
    if(v) assign_svalue_no_free(&r->item[cnt], v);
  }
  return r;
}

int search_array(
	struct vector *p,
	struct svalue *lambda,
	struct svalue *extra,
	int num_extra_arg)
{
  struct svalue *v;
  char *func=0;  /* make gcc happy */
  int cnt,no;
    
  if(lambda->type==T_STRING)
  {
    func=strptr(lambda);
  }else if(lambda->type==T_FUNCTION){
    if(lambda->u.ob->flags & O_DESTRUCTED)
    {
      error("Invalid lambda to map_array.\n");
    }
  }else if(lambda->type==T_NUMBER){
    /* no action here */
  }else{
    error("Bad arg to map_array.\n");
  }

  if (p->size<1) return -1;
 
  for (cnt=0;cnt<p->size;cnt++)
  {
    check_eval_cost();
    switch(lambda->type)
    {
      case T_NUMBER:
        if(p->item[cnt].type!=T_FUNCTION ||
          (p->item[cnt].u.ob->flags & O_DESTRUCTED)) continue;
        for(no=0;no<num_extra_arg;no++) push_svalue(extra+no);
        v=apply_lambda(p->item+cnt,no,0);
        break;

      case T_STRING:
        if(p->item[cnt].type!=T_OBJECT ||
          (p->item[cnt].u.ob->flags & O_DESTRUCTED)) continue;
        for(no=0;no<num_extra_arg;no++) push_svalue(extra+no);
        v=apply_shared(func,p->item[cnt].u.ob,no,0);
        break;

      case T_FUNCTION:
        if(lambda->u.ob->flags & O_DESTRUCTED)
          error("object used by map_array destructed\n");
        push_svalue(&p->item[cnt]);
        for(no=0;no<num_extra_arg;no++) push_svalue(extra+no);
        v=apply_lambda(lambda,no+1,0);
        break;

      default:
	fatal("Fatal error in search_array.\n");
	return 0;
    }
    if(!IS_ZERO(v)) return cnt;
  }
  return -1;
}

static struct svalue *func;
static struct svalue *extra_arg;
static int num_extra_arg;

static int sort_array_cmp(struct svalue *p1,struct svalue *p2)
{
  struct svalue *d;
  int e;
  if(!func || func->type!=T_FUNCTION)
  {
    if(p1->type>p2->type) return 1;
    if(p1->type<p2->type) return -1;
    return is_gt(p1,p2);
  }

  if (func->u.ob->flags & O_DESTRUCTED)
    error("object used by sort_array destructed");

  push_svalue(p1);
  push_svalue(p2);
  for(e=0;e<num_extra_arg;e++)
  {
    push_svalue(extra_arg+e);
  }
  d = apply_lambda(func,num_extra_arg+2,0);
  if (!d) return 0;
  if(d->type!=T_NUMBER) return 1;
  return d->u.number;
}
typedef int (*cmpfuntyp) (const void *,const void *);

struct vector *sort_array(
	struct vector *v,
	struct svalue *fun,
	struct svalue *extra,
	int num)
{
  struct vector *outlist;
  int n;

  func=fun;
  extra_arg=extra;
  num_extra_arg=num;

  n=v->size;
  outlist=slice_array(v,0,n-1);
  msort(outlist->item,n,sizeof(struct svalue),(cmpfuntyp)sort_array_cmp);
  return outlist;
}

/*
 * deep_inventory()
 *
 * This function returns the recursive inventory of an object. The returned 
 * array of objects is flat, ie there is no structure reflecting the 
 * internal containment relations.
 *
 */
int number_deep_inv(struct object *ob)
{
  int num;
  num=1;
  for(ob=ob->contains;ob;ob=ob->next_inv)
    num+=number_deep_inv(ob);
  return num;
}

/* This one is faster, but the array is even more scrambled compared to
 * the normal deep_inventory() /Profezzorn
 */
struct vector *deep_inventory(struct object *ob,int take_top)
{
  int num;
  struct vector *res;
  struct svalue *curr,*next;
  num=number_deep_inv(ob);
  if(take_top)
  {
    res=allocate_array_no_init(num,0);
    add_ref(ob,"deep_inventory");
    res->item[0].type=T_OBJECT;
    res->item[0].u.ob=ob;
    next=curr=res->item+1;
  }else{
    res=allocate_array(num-1);
    curr=next=res->item;
  }
  for(;curr<=next;curr++)
  {
    for(ob=ob->contains;ob;ob=ob->next_inv)
    {
      add_ref(ob,"deep_inventory");
      next->type=T_OBJECT;
      next->u.ob=ob;
      next++;
    }
    ob=curr->u.ob;
  }
  return res;
}

INLINE int alist_cmp(struct svalue *p1,struct svalue *p2)
{
    register int d;

    if ((d = p1->type - p2->type)) return d;
    switch(p1->type)
    {
      case T_FLOAT:
        if(p1->u.fnum>p2->u.fnum) return 1;
        if(p1->u.fnum<p2->u.fnum) return -1;
        return 0;

      case T_FUNCTION:
        if ((d = p1->u.number - p2->u.number)) return d;
        if ((d = p1->subtype - p2->subtype)) return d;
        return 0;

      default:
        if(p1->u.number>p2->u.number) return 1;
        if(p1->u.number<p2->u.number) return -1;
        return 0;

    }
}

struct vector *globber;

int new_alist_cmp(int *a,int *b)
{
  return alist_cmp(globber->item+*a,globber->item+*b);
}

void order_alist(struct vector *inlist)
{
  int *tmp;
  struct vector *tmplist,*tmptmplist;
  int e,d;
  globber=inlist->item[0].u.vec;
  if(!globber->size) return;
  tmp=(int *)malloc(globber->size*sizeof(int));

  for(e=0;e<globber->size;e++) tmp[e]=e;
  fsort(tmp,globber->size,sizeof(int),(cmpfuntyp)new_alist_cmp);

  tmplist=allocate_array_no_init(globber->size,0);
  for(e=0;e<inlist->size;e++)
  {
    if(inlist->item[e].type==T_ALIST_PART)
    {
      tmptmplist=inlist->item[e].u.vec;
      for(d=0;d<tmplist->size;d++) tmplist->item[d]=tmptmplist->item[tmp[d]];
      inlist->item[e].u.vec=tmplist;
      tmplist=tmptmplist;
    }
  }
  /* for(e=0;e<tmplist->size;e++) tmplist->item[e].type=T_INVALID; */
  tmplist->size=0; /* instead of setting all the items in it to const0 */
  free_vector(tmplist);
  free((char *)tmp);
}


/* obs, destructive /Profezzorn */

struct vector *insert_alist(
	struct svalue *key,
	struct svalue *key_data,
	struct vector *list)
{
  int i,ix;
  int keynum;
  int insert;
  struct vector *tmp;
  struct svalue *sv;

#if 0
  for(i=0;i<list->size;i++)
  {
    if(list->item[i].type!=T_ALIST_PART) continue;
    sv= i ? key_data+i-1 : key;
    if(IS_TYPE(*sv,BT_VECTOR))
      if(check_for_circularity(sv->u.vec,list))
	error("Trying to make circular alist.\n");
  }
#endif

  keynum = list->item[0].u.vec->size;
  ix = search_alist(key,list->item[0].u.vec);
  insert=ix==keynum || alist_cmp(key, &list->item[0].u.vec->item[ix]);

  for (i=0; i < list->size; i++)
  {
    if(list->item[i].type==T_ALIST_PART)
    {
      tmp = list->item[i].u.vec;
#ifdef DEBUG
      if(tmp->size!=keynum)
	fatal("If this is an alist, then I'll be buggered.\n");
#endif
      if(insert)
      {
	sv= i ? key_data+i-1 : key;
	list->item[i].u.vec=insert_array(list->item[i].u.vec,ix,sv);
      }else{
        if(i)
	{
	  sv= key_data+i-1;
          assign_svalue(tmp->item+ix, sv);
	  tmp->types|=sv->type;
	}
      }
    }
  }
#ifdef DEBUG
  for(i=0;i<list->size;i++)
  {
    if(list->item[i].type==T_ALIST_PART && list->item[0].u.vec->size!=
       list->item[i].u.vec->size)
      fatal("Hmm, this is _not_ what I had in mind....\n");
  }
#endif
  return list;
}

struct vector *match_regexp(struct vector *v,regexp *reg)
{
  char *res;
  int i, num_match;
  struct vector *ret;
  extern int eval_cost;

  if (v->size == 0)
    return allocate_array(0);
  
  res = (char *)alloca(v->size);
  for (num_match=i=0; i < v->size; i++)
  {
    res[i] = 0;
    if (v->item[i].type != T_STRING)
      continue;
    eval_cost++;
    if (regexec(reg, strptr(v->item+i)) == 0)
      continue;
    res[i] = 1;
    num_match++;
  }
  ret = allocate_array_no_init(num_match,0);
  for (num_match=i=0; i < v->size; i++)
  {
    if (!res[i]) continue;
    assign_svalue_raw(&ret->item[num_match], &v->item[i]);
    num_match++;
  }
  return ret;
}

/*
 * Returns a list of all inherited files.
 *
 * Must be fixed so that any number of files can be returned, now max 256
 * (Sounds like a contradiction to me /Lars).
 * Now it can return any number of files. /Profezzorn
 */
struct vector *inherit_list(struct object *ob)
{
  struct vector *ret;
  struct program *pr;
  int e;

  pr=ob->prog;
  ret=allocate_array_no_init(pr->num_inherited,0);
  for(e=0;e<pr->num_inherited;e++)
  {
    SET_STR(ret->item+e,copy_shared_string(pr->inherit[e].prog->name));
  }
  return ret;
}

/*
 * When a vector is given as argument to an efun, all items has to be
 * checked if there would be an destructed object.
 * A bad problem currently is that a vector can contain another vector, so this
 * should be tested too. But, there is currently no prevention against
 * recursive vectors, which means that this can not be tested. Thus, the game
 * may crash if a vector contains a vector that contains a destructed object
 * and this top-most vector is used as an argument to an efun.
 */
/* The game won't crash when doing simple operations like assign_svalue
 * on a destructed object. You have to watch out, of course, that you don't
 * apply a function to it.
 * to save space it is preferable that destructed objects are freed soon.
 *   amylaar
 */

void donk_alist_item(struct vector *m,int i)
{
  int e,d,s;
  for(s=e=0;e<m->size;e++)
  {
    if(m->item[e].type!=T_ALIST_PART) continue;
    free_svalue(m->item[e].u.vec->item+i);
    for(d=i+1;d<m->item[e].u.vec->size;d++)
      m->item[e].u.vec->item[d-1]=m->item[e].u.vec->item[d];
    m->item[e].u.vec->size--;
  }
  total_array_size -= s*sizeof (struct svalue);
}

/* I'm a big beleiver in lazy evaluation algorithms */

void check_vector_for_destruct(struct vector *v)
{
  int types,e;
  /* if there are no objects or function, why check? */
  if(!(v->types & (BT_OBJECT | BT_FUNCTION)))
    return;

  types=0;
  for(e=v->size-1;e>=0;e--)
  {
    if(IS_TYPE(v->item[e],BT_OBJECT | BT_FUNCTION))
    {
      if(v->item[e].u.ob->flags & O_DESTRUCTED)
      {
	short tmp;
	tmp=v->item[e].type=T_OBJECT;
        free_svalue(v->item+e);
	v->item[e].subtype=tmp?NUMBER_DESTRUCTED_OBJECT:NUMBER_DESTRUCTED_FUNCTION;
      }
    }

    types|=1<<v->item[e].type;
  }
  v->types=types;
}

/* { 0,1,1,0,0,1 }
   { 1,0,0,1,1,0 }
*/
void check_alist_for_destruct(struct vector *v)
{
  int e,types;
  struct vector *w;
  check_vector_for_destruct(v);
  w=v->item[0].u.vec;

  if(w->types & (BT_OBJECT | BT_FUNCTION))
  {
    types=0;
    for(e=0;e<w->size;e++)
    {
      if(IS_TYPE(w->item[e],BT_OBJECT | BT_FUNCTION) &&
        (w->item[e].u.ob->flags & O_DESTRUCTED))
      {
        donk_alist_item(v,e);
        e--;
      }else{
        types|=1<<w->item[e].type;
      }
    }
    w->types=types;
  }

  for(e=1;e<v->size;e++)
    if(v->item[e].type==T_ALIST_PART)
      check_vector_for_destruct(v->item[e].u.vec);
}

/* check if v2 is in v */
int check_for_circularity(struct vector *v,struct vector *v2)
{
  int types,e;

  if(v==v2) return 1;
  /* if there are no vectors, why search? */
  if(!(v->types & BT_VECTOR))
    return 0;

  types=0;
  for(e=v->size-1;e>=0;e--)
  {
    if(IS_TYPE(v->item[e],BT_VECTOR))
      if(check_for_circularity(v->item[e].u.vec,v2))
        return 1;

    types|=1<<v->item[e].type;
  }

  /* if we reach this, types is updated.
   * as recursive arrays gives errors, we should come here
   * almost every time.
   */
  v->types=types;
  return 0;
}


struct vector *allocate_n_array(struct svalue *sp,int t)
{
  struct vector *v;
  int e;
  extern int eval_cost;
  if(sp->type!=T_NUMBER)
    error("Non-numeric array dimension.\n");
  v=allocate_array(sp->u.number);
  eval_cost+=sp->u.number*AVERAGE_COST;
  t--;
  v->types=BT_NUMBER;
  if(!t) return v;
  sp++;
  v->types=BT_POINTER;
  for(e=0;e<v->size && eval_cost<MAX_COST;e++)
  {
    v->item[e].type=T_POINTER;
    v->item[e].u.vec=allocate_n_array(sp,t);
  }
  return v;
}

struct vector *sum_arrays(
	int num_of_arrays,
	struct svalue *arrays,
	struct svalue *fun)
{
  int d,e,size;
  struct vector *res;
  struct svalue *ret;

  size=arrays->u.vec->size;

  res=allocate_array_no_init(size,0);
  for(e=0;e<size;e++)
  {
    for(d=0;d<num_of_arrays;d++)
    {
      if(arrays[d].u.vec->size>e)
        push_svalue(& arrays[d].u.vec->item[e]);
      else
        push_number(0);
    }
    if(fun->u.ob->flags & O_DESTRUCTED)
    {
      free_vector(res);
      error("Object used by sum_arrays destructed.\n");
    }
    ret=apply_lambda(fun,num_of_arrays,0);
    if(!ret)
    {
      free_vector(res);
      error("Function used by sum_arrays() not found.\n");
    }
    assign_svalue_no_free(& res->item[e],ret);
  }
  return res;
}


struct vector *file_stat(char *file,int raw)
{
  struct vector *tmp;
  struct stat    stbuf;  
  char          *p;

  p = file;
  if(!batch_mode)
    while(*p && *p == '/')
      p++;

  if(raw)
  {
    if(lstat(p, &stbuf) == -1)
      return 0;
  }else{
    if(stat(p, &stbuf) == -1)
      return 0;
  }
    
  tmp = allocate_array(5);
  
  tmp->item[0].u.number = stbuf.st_mode;
  tmp->item[1].u.number =
    (S_IFDIR == (S_IFMT & stbuf.st_mode)) ? -2 :
      (S_IFLNK == (S_IFMT & stbuf.st_mode)) ? -3 : stbuf.st_size;
  tmp->item[2].u.number = stbuf.st_atime;
  tmp->item[3].u.number = stbuf.st_mtime;
  tmp->item[4].u.number = stbuf.st_ctime;
  
  tmp->types=BT_NUMBER;
  return tmp;
}