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 "efuns.h"

#ifdef HAVE_SYS_RUSAGE
#include <sys/rusage.h>
#endif

#ifdef GETRUSAGE_THROUGH_PROCFS
#include <sys/types.h>
#include <sys/procfs.h>
#endif

#include "stralloc.h"
#include "array.h"
#include "simulate.h"
#include "save_objectII.h"
#include "operators.h"
#include "main.h"

void f_aggregate(int num_arg,struct svalue *argp)
{
  int i;
  struct vector *v;
  v = allocate_array_no_init(num_arg,0);
#if 0
  for (i=0; i < num_arg; i++) v->item[i]=argp[i];
  sp-=num_arg-1;
#else
  for (i=0; i < num_arg; i++)
  {
    v->item[i]=argp[i];
#ifdef WARN
    argp[i].type=2000;
#endif
  }
  sp-=num_arg-1;
#endif
  sp->type = T_POINTER;
  sp->u.vec = v;		/* Ref count already initialized */
}

void f_sum_arrays(int num_arg,struct svalue *argp)
{
  struct svalue *s;
  struct vector *v;
  extern struct vector *sum_arrays(int,struct svalue *,struct svalue *);
  int values,e;
  s=argp+1;
  values=num_arg-1;
  for(e=0;e<values;e++) if(s[e].type!=T_POINTER) bad_arg(e+1,F_SUM_ARRAYS);
  v=sum_arrays(values,s,argp);
  pop_n_elems(num_arg);
  push_vector(v);
  v->ref--;
}

void string_replace(struct svalue *str,struct svalue *del,struct svalue *to)
{
  char *str_s,*del_s,*to_s;
  int str_l,del_l,to_l;
  int e,num;
  char *buff,*q;

  /* find number of delimeters */

  str_s=strptr(str);
  del_s=strptr(del);
  to_s=strptr(to);

  str_l=my_strlen(str);
  del_l=my_strlen(del);
  to_l=my_strlen(to);

  
  for (num=e=0; e<str_l;)
  {
    if (e+del_l<=str_l && !MEMCMP(str_s+e, del_s, del_l))
    {
      num++;
      e+=del_l?del_l:1;
    }else{
      e+=1;
    }
  }

  if(!num) return;

  q = buff = begin_shared_string(str_l+num*(to_l-del_l));

  for (e=0;e<str_l;)
  {
    if(e+del_l<=str_l && !MEMCMP(str_s+e, del_s, del_l))
    {
      MEMCPY(q,to_s,to_l);
      e += del_l?del_l:1;
      q += to_l;
    } else {
      *(q++)=str_s[e++];
    }
  }
  buff=end_shared_string(buff);
  free_svalue(str);
  SET_STR(str,buff);
}

struct tupel
{
  struct svalue ind,val;
};

typedef int (*cmpfuntyp) (const void *,const void *);

void replace_many(struct svalue *str,struct vector *from,struct vector *to)
{
  extern int batch_mode;
  extern int max_eval_cost;
  char *str_s;
  int str_l;
  struct tupel *v;
  int e,a,b,c;
  char set[256];

  str_s=strptr(str);
  str_l=my_strlen(str);

  if(from->size!=to->size)
    error("replace must have equal-sized from and to arrays.\n");
  eval_cost+=from->size;
  v=(struct tupel *)xalloc(sizeof(struct tupel)*from->size);
  for(e=0;e<256;e++) set[e]=0;
  for(e=0;e<from->size;e++)
  {
    if(from->item[e].type!=T_STRING)
      error("replace: from array not string *.\n");
    if(to->item[e].type!=T_STRING)
      error("replace: to array not string *.\n");
    set[EXTRACT_UCHAR(strptr(from->item+e))]=1;
    v[e].ind=from->item[e];
    v[e].val=to->item[e];
  }
  msort(v,from->size,sizeof(struct tupel),(cmpfuntyp)my_strcmp);

  init_buf();
  for(e=0;e<str_l;)
  {
    if(set[EXTRACT_UCHAR(str_s+e)])
    {
      eval_cost++;
      if(!batch_mode && eval_cost>max_eval_cost)
      {
	free((char *)v);
	error("Eval cost to big in replace.\n");
      }
      a=0;
      b=from->size;
      while(a<b)
      {
	c=(a+b)/2;
	if(strcmp(strptr(&v[c].ind),str_s+e)<=0)
	{
	  if(a==c) break;
	  a=c;
	}else{
	  b=c;
	}
      }
      if(a<from->size && 
	 !strncmp(strptr(&v[a].ind),str_s+e,my_strlen(&(v[a].ind))))
      {
	c=my_strlen(&(v[a].ind));
	if(!c) c++;
	e+=c;
	my_binary_strcat(strptr(&v[a].val),my_strlen(&(v[a].val)));
	continue;
      }
    }
    my_putchar(str_s[e++]);
  }

  free_svalue(str);
  SET_STR(str,free_buf());
  free((char *)v);
}

void f_replace(int num_arg,struct svalue *argp)
{
  extern struct vector *array_replace PROT((struct vector *,struct svalue *, struct svalue *));

  if(argp[0].type==T_STRING)
  {
    if(argp[1].type==T_STRING &&
     argp[2].type==T_STRING)
    {
      string_replace(argp,argp+1,argp+2);
      pop_n_elems(2);
      return;
    }else if(argp[1].type==T_POINTER &&
     argp[2].type==T_POINTER)
    {
      replace_many(argp,argp[1].u.vec,argp[2].u.vec);
      pop_n_elems(2);
      return;
    }
  }else if(argp[0].type==T_POINTER){
    struct vector *v;
    v=array_replace(argp[0].u.vec,argp+1,argp+2);
    pop_n_elems(3);
    push_vector(v);
    v->ref--;
    return ;
  }
  error("Wrong arguments to replace()\n");
}

void f_regexp(int num_arg,struct svalue *argp)
{
  struct vector *v;
  v = match_regexp((sp-1)->u.vec, sp->u.regexp);
  pop_n_elems(2);
  if (v == 0)
  {
    push_zero();
  }else{
    push_vector(v);
    v->ref--;			/* Will make ref count == 1 */
  }
}

void f_explode(int num_arg,struct svalue *argp)
{
  struct vector *v;
  v = explode(sp-1, sp);
  pop_n_elems(2);
  push_vector(v);		/* This will make ref count == 2 */
  v->ref--;
}

void f_filter_array(int num_arg,struct svalue *argp)
{
  struct vector *v;
  v=argp[0].u.vec;
  check_vector_for_destruct(v);
  v=filter(v,argp+1,argp+2,num_arg-2);
  pop_n_elems(num_arg);
  if (v)
  {
    push_vector(v);		/* This will make ref count == 2 */
    v->ref--;
  }else{
    push_zero();
  }
  check_eval_cost();
}

void f_implode(int num_arg,struct svalue *argp)
{
  struct svalue tmp;
  check_vector_for_destruct(sp[-1].u.vec);
  implode(&tmp,sp[-1].u.vec,sp);
  pop_n_elems(2);
  sp++;
  *sp=tmp;
}

#ifdef F_INHERIT_LIST
void f_inherit_list(int num_arg,struct svalue *argp)
{
  struct vector *vec;
  extern struct vector *inherit_list PROT((struct object *));

  vec = inherit_list(sp->u.ob);
  pop_stack();
  push_vector(vec);
}
#endif				/* F_INHERIT_LIST */

void f_member_array(int num_arg,struct svalue *argp)
{
  struct vector *v;
  int i;

  v = sp->u.vec;
  check_vector_for_destruct(v);
  if(!IS_TYPE(*argp,v->types))
  {
    i=-1;
  }else{
    for (i=0; i < v->size; i++)
    {
      if(is_eq(v->item+i,argp))
	break;
    }
    if (i == v->size) i = -1; /* Return -1 for failure */
  }
  pop_stack();
  pop_stack();
  push_number(i);
}

void f_allocate(int num_arg,struct svalue *argp)
{
  extern int batch_mode;
  extern int max_eval_cost;
  struct vector *v;
  v=allocate_n_array(argp,num_arg);
  pop_n_elems(num_arg);
  push_vector(v);
  v->ref--;
  if (eval_cost > max_eval_cost && !batch_mode)
    error("Too big allocation. Execution aborted.\n");
}

void f_sizeof(int num_arg,struct svalue *argp)
{
  int i;
  if(sp->type==T_OBJECT)
    i=data_size(sp->u.ob);
  else
    i = sp->u.vec->size;
  pop_stack();
  push_number(i);
}

void f_get_dir(int num_arg,struct svalue *argp)
{
  struct vector *v;
  v=get_dir(simple_check_valid_path(argp,"get_dir",0),argp[1].u.number);
  pop_n_elems(2);

  if (v)
  {
    push_vector(v);
    v->ref--;			/* Will now be 1. */
  } else{
    push_zero();
  }
}

#ifdef F_RUSAGE

#ifdef GETRUSAGE_THROUGH_PROCFS

static INLINE int get_time_int(timestruc_t * val) 
{
  return val->tv_sec * 1000 + val->tv_nsec/1000000;
}
 
void f_rusage(int num_arg,struct svalue *argp)
{
  struct vector *v;
  prusage_t  pru;
  prstatus_t prs;
  extern int proc_fd;

  if(ioctl(proc_fd, PIOCUSAGE, &pru) < 0)
  {
    push_number(0);
    return;
  }

  
  if(ioctl(proc_fd, PIOCSTATUS, &prs) < 0)
  {
    push_number(0);
    return;
  }
  
  v = allocate_array(29);

  v->item[0].u.number = get_time_int(&pru.pr_utime);  /* user time */
  v->item[1].u.number = get_time_int(&pru.pr_stime);  /* system time */
  v->item[2].u.number = 0;                           /* maxrss */
  v->item[3].u.number = 0;                           /* idrss */
  v->item[4].u.number = 0;                           /* isrss */
  v->item[5].u.number = 0;                           /* minflt */
  v->item[6].u.number = pru.pr_minf;           /* minor pagefaults */
  v->item[7].u.number = pru.pr_majf;           /* major pagefaults */
  v->item[8].u.number = pru.pr_nswap;          /* swaps */
  v->item[9].u.number = pru.pr_inblk;          /* block input op. */
  v->item[10].u.number = pru.pr_oublk;         /* block outout op. */
  v->item[11].u.number = pru.pr_msnd;          /* messages sent */
  v->item[12].u.number = pru.pr_mrcv;          /* messages received */
  v->item[13].u.number = pru.pr_sigs;          /* signals received */
  v->item[14].u.number = pru.pr_vctx;          /* voluntary context switches */
  v->item[15].u.number = pru.pr_ictx;         /* involuntary  "        " */
  v->item[16].u.number = pru.pr_sysc;
  v->item[17].u.number = pru.pr_ioch;
  v->item[18].u.number = get_time_int(&pru.pr_rtime);
  v->item[19].u.number = get_time_int(&pru.pr_ttime);
  v->item[20].u.number = get_time_int(&pru.pr_tftime);
  v->item[21].u.number = get_time_int(&pru.pr_dftime);
  v->item[22].u.number = get_time_int(&pru.pr_kftime);
  v->item[23].u.number = get_time_int(&pru.pr_ltime);
  v->item[24].u.number = get_time_int(&pru.pr_slptime);
  v->item[25].u.number = get_time_int(&pru.pr_wtime);
  v->item[26].u.number = get_time_int(&pru.pr_stoptime);
  v->item[27].u.number = prs.pr_brksize;
  v->item[28].u.number = prs.pr_stksize;
  push_vector(v);
  v->ref--;
}

#else /* GETRUSAGE_THROUGH_PROCFS */

void f_rusage(int num_arg,struct svalue *argp)
{
  struct vector *v;
  struct rusage rus;
  long utime, stime;
  int maxrss;

  if (getrusage(RUSAGE_SELF, &rus) < 0)
  {
    push_zero();
  }else{
    v=allocate_array(16);
    utime = rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000;
    stime = rus.ru_stime.tv_sec * 1000 + rus.ru_stime.tv_usec / 1000;

    maxrss = rus.ru_maxrss;
#ifdef sun
    maxrss *= getpagesize() / 1024;
#endif
    v->item[0].u.number=utime;
    v->item[1].u.number=stime;
    v->item[2].u.number=maxrss;
    v->item[3].u.number=rus.ru_ixrss;
    v->item[4].u.number=rus.ru_idrss;
    v->item[5].u.number=rus.ru_isrss;
    v->item[6].u.number=rus.ru_minflt;
    v->item[7].u.number=rus.ru_majflt;
    v->item[8].u.number=rus.ru_nswap;
    v->item[9].u.number=rus.ru_inblock;
    v->item[10].u.number=rus.ru_oublock;
    v->item[11].u.number=rus.ru_msgsnd;
    v->item[12].u.number=rus.ru_msgrcv;
    v->item[13].u.number=rus.ru_nsignals;
    v->item[14].u.number=rus.ru_nvcsw;
    v->item[15].u.number=rus.ru_nivcsw;
    push_vector(v);
    v->ref--;
  }
}
#endif /* SOLARIS */
#endif /* F_RUSAGE */

void f_map_array(int num_arg,struct svalue *argp)
{
  struct vector *v;
  check_eval_cost();
  v=argp[0].u.vec;
  check_vector_for_destruct(v);
  v=map_array(v,argp+1,argp+2,num_arg-2);
  pop_n_elems(num_arg);
  if (v)
  {
    push_vector(v);		/* This will make ref count == 2 */
    v->ref--;
  }else{
    push_number(0);
  }
}

void f_search_array(int num_arg,struct svalue *argp)
{
  int i;
  check_eval_cost();
  check_vector_for_destruct(argp[0].u.vec);
  i=search_array(argp[0].u.vec,argp+1,argp+2,num_arg-2);
  pop_n_elems(num_arg);
  push_number(i);
}

void f_sort_array(int num_arg,struct svalue *argp)
{
  extern struct vector *sort_array
    PROT((struct vector *,struct svalue *,struct svalue *,int));
  struct vector *res;

  check_eval_cost();

  check_vector_for_destruct(argp[0].u.vec);
  if(num_arg<2)
  {
    res = sort_array (argp->u.vec,0,0,0);
  }else{
    res = sort_array (argp->u.vec,argp+1,argp+2,num_arg-2);
  }
  pop_n_elems (num_arg);
  push_vector(res);
  res->ref--;
}

void f_file_stat(int num_arg,struct svalue *argp)
{
  extern struct vector *file_stat(char *f,int raw);
  struct vector *v;
	  
  v = file_stat(strptr(argp),argp[1].u.number);
  pop_n_elems(2);
  if(!v) 
    push_number(0);
  else {
    push_vector(v);
    sp->u.vec->ref--;		/* Was set to 1 at allocation */
  }
}


struct find_tmp
{
  int seenfrom;
  int next;
};

void f_find_shortest_path(int num_arg,struct svalue *argp)
{
  struct find_tmp *tmp;
  struct vector *v,*w;
  int e,d,from,to,next;

  check_argument(2,T_NUMBER,F_FIND_SHORTEST_PATH);

  from=argp[1].u.number;
  to=argp[2].u.number;

  if(to==from)
  {
    pop_n_elems(3);
    push_vector(v=allocate_array(0));
    v->ref--;
    return;
  }

  v=argp[0].u.vec;

  if(from<0 || from>=v->size)
    error("'from' argument out of range.\n");

  if(to<0 || to>=v->size)
    error("'to' argument out of range.\n");

  tmp=(struct find_tmp *)xalloc(sizeof(struct find_tmp)*v->size);

  for(e=0;e<v->size;e++)
  {
    tmp[e].seenfrom=-1;
    tmp[e].next=-1;
  }

  tmp[from].seenfrom=-2;

  for(;from!=-1;from=next)
  {
    for(next=-1;from!=-1;from=tmp[from].next)
    {
      if(v->item[from].type!=T_POINTER)
      {
        free((char *)tmp);
        error("graph should be array of array.\n");
        
      }
      w=v->item[from].u.vec;
      for(d=0;d<w->size;d++)
      {
        if(w->item[d].type!=T_NUMBER)
        {
          free((char *)tmp);
          error("graph should be array of array of int.\n");
        }
        e=w->item[d].u.number;
        if(e<0 || e>=v->size)
        {
          free((char *)tmp);
          error("graph contains indexes out of range.\n");
        }
        if(tmp[e].seenfrom!=-1) continue;

        tmp[e].seenfrom=from;
        tmp[e].next=next;
        next=e;

        if(e==to)
        {
          for(e=0,d=to;d!=-2;d=tmp[d].seenfrom) e++;
          w=allocate_array(e);
          for(d=to;d!=-2;d=tmp[d].seenfrom)
          {
            e--;
            w->item[e].type=T_NUMBER;
            w->item[e].u.number=d;
          }
          free((char *)tmp);
          pop_n_elems(3);
          push_vector(w);
          w->ref--;
	  return;
        }
      }
    }
  }
  free((char *)tmp);  /* no path found */
  pop_n_elems(3);
  push_zero();
}