muse1.7b4/
muse1.7b4/config/
muse1.7b4/doc/
muse1.7b4/run/
muse1.7b4/run/db/
muse1.7b4/src/
muse1.7b4/src/db/
muse1.7b4/src/files/
muse1.7b4/src/io/
muse1.7b4/src/prog/
muse1.7b4/src/util/
/* eval.c */
/* $Id: eval.c,v 1.16 1993/10/18 01:14:50 nils Exp $ */

/* Expression parsing module created by Lawrence Foard */

#include <sys/types.h>
#include <time.h>
#include <ctype.h>
#include <math.h>

#include "db.h"
#include "interface.h"
#include "config.h"
#include "externs.h"
#include "hash.h"
#include "nalloc.h"
#ifdef USE_SPACE /* Included by Michael Majere */
#include "space.h"
#endif
#ifdef DEBUGEVAL
extern FILE *command_log;
#endif

/* functions for the string expressions */
extern NALLOC *glurp;

dbref match_thing(player,name)
     dbref player;
     char *name;
{
  init_match(player, name, NOTYPE);
  match_everything();
  
  return(noisy_match_result());
}

void fun_rand(buff,args)
     char *buff;
     char *args[10];
{
  int mod=atoi(args[0]);
  if (mod<1)
    mod=1;
  sprintf(buff,"%d",(rand() & 65535) % mod);
}
void fun_switch(buff,args, player, doer, nargs)
     char *buff;
     char *args[10];
     dbref player;
     dbref doer;
     int nargs;
{
  char thing[1024];
  int i;
  char *ptrsrv[10];

  if (nargs<2) {
    strcpy(buff,"WRONG NUMBER OF ARGS");
    return;
  }
  for(i=0;i<10;i++)
    ptrsrv[i]=wptr[i];
  strcpy(thing,args[0]);
  for (i=1; (i+1)<nargs; i+=2) {
    if (wild_match(args[i],thing)) {
      strcpy(buff, args[i+1]);
      for(i=0;i<10;i++)
	wptr[i]=ptrsrv[i];
      
      return;
    }
  }
  if (i<nargs)
    strcpy (buff,args[i]);
  else
    *buff = '\0';
  for(i=0;i<10;i++)
    wptr[i]=ptrsrv[i];
  return;
}

void fun_attropts(buff, args, player, doer, nargs)
     char *buff;
     char *args[10];
     dbref player;
     dbref doer;
     int nargs;
{
  dbref thing;
  char buf[1024];
  ATTR *attrib;
  
  if (nargs >2 || nargs < 1) {
    strcpy(buff,"WRONG NUMBER OF ARGS");
    return;
  }
  if (nargs == 2) {
    char *k;
    static char *g[1];
    k=tprintf("%s/%s",args[0],args[1]);
    args = g;
    g[0] = k;
  }
  
  if (!parse_attrib(player,args[0],&thing,&attrib,0)) {
    strcpy(buff,"NO MATCH");
    return;
  }
  if (!can_see_atr(player, thing, attrib)) {
    strcpy(buff,"Permission denied.");
    return;
  }
  *buf = '\0';
  buf[1] = '\0';
  if (attrib->flags & AF_WIZARD)
    strcat(buf, " wizard");
  if (attrib->flags & AF_UNIMP)
    strcat(buf, " unsaved");
  if (attrib->flags & AF_OSEE)
    strcat(buf, " osee");
  if (attrib->flags & AF_INHERIT)
    strcat(buf, " inherit");
  if (attrib->flags & AF_DARK)
    strcat(buf, " dark");
  if (attrib->flags & AF_DATE)
    strcat(buf, " date");
  if (attrib->flags & AF_LOCK)
    strcat(buf, " lock");
  if (attrib->flags & AF_FUNC)
    strcat(buf, " function");
  strcpy (buff, buf+1);
}

void fun_foreach(buff,args,privs,doer)
     char *buff;
     char *args[10];
     dbref privs;
     dbref doer;
{
  char *k;
  char buff1[1024];
  char *ptrsrv;
  int i=0,j=0;
  ptrsrv=wptr[0];
  if(!args[0] || !strcmp(args[0],"")) {
    buff[0]=NULL;
    return;
  }
  while((k=parse_up(&args[0], ' ')) && i<1000) {
    wptr[0] = k;
    pronoun_substitute(buff1,doer,args[1],privs);
    for(j=strlen(db[doer].name)+1;buff1[j] && i<1000;i++,j++)
      buff[i]=buff1[j];
    buff[i++]=' ';
    buff[i]='\0';
  }
  if(i>0) buff[i-1]='\0';
  wptr[0] = ptrsrv;
}

void fun_get(buff,args,player, doer, nargs)
     char *buff;
     char *args[10];
     dbref player;
     dbref doer;
     int nargs;
{
  dbref thing;
  ATTR *attrib;
  if (nargs >2 || nargs < 1) {
    strcpy(buff,"WRONG NUMBER OF ARGS");
    return;
  }
  if (nargs == 2) {
    char *k;
    static char *g[1];
    k=tprintf("%s/%s",args[0],args[1]);
    args = g;
    g[0] = k;
  }

  if (!parse_attrib(player,args[0],&thing,&attrib,0)) {
    strcpy(buff,"NO MATCH");
    return;
  }
  if (can_see_atr (player, thing, attrib))
    strcpy(buff,atr_get(thing,attrib));
  else
    strcpy(buff,"Permission denied");
  /*
  if (!controls(player,thing,POW_SEEATR) && !(attrib->flags&AF_OSEE)) {
    strcpy(buff,"Permission denied");
    return;
  }
  if (attrib->flags&AF_DARK && !controls(player,attrib->obj,POW_SECURITY)) {
    strcpy(buff,"Permission denied");
    return;
  }
  strcpy(buff,atr_get(thing,attrib));
  */
}

void fun_time(buff,args,privs,doer,nargs)
     char *buff;
     char *args[10];
     dbref privs;
     dbref doer;
     int nargs;
{
  time_t cl;

  /* use supplied x-value if one is given */
  /* otherwise get the current x-value of time */
  if ( nargs == 2 )
    cl = atol(args[1]);
  else
    time(&cl);

  if ( nargs == 0 )
    strcpy(buff, mktm(cl, "D", privs));
  else
    strcpy(buff, mktm(cl, args[0], privs));
}

void fun_xtime(buff,args,privs,doer,nargs)
     char *buff;
     char *args[];
     dbref privs;
     dbref doer;
     int nargs;
{
  time_t cl;

  if ( nargs == 0 )
    time(&cl);
  else  {
    cl = mkxtime(args[0], privs, (nargs > 1) ? args[1] : "");
    if ( cl == -1L )  {
      strcpy(buff,"#-1");
      return;
    }
  }
  sprintf(buff, "%ld", cl);
}

int mem_usage(thing)
     dbref thing;
{
  int k;
  ALIST *m;
  ATRDEF *j;

  k = sizeof(struct object);
  k += strlen(db[thing].name)+1;
  for (m=db[thing].list; m; m=AL_NEXT(m))
    if (AL_TYPE(m))
      if (AL_TYPE(m) != A_DOOMSDAY) {
	k += sizeof(ALIST);
	if (AL_STR(m))
	  k += strlen(AL_STR(m));
      }
  for (j=db[thing].atrdefs; j; j=j->next) {
    k += sizeof(ATRDEF);
    if (j->a.name)
      k += strlen(j->a.name);
  }
  return k;
}

void fun_objmem(buff, args, privs)
     char *buff;
     char *args[10];
     dbref privs;
{
  dbref thing;
  thing = match_thing (privs, args[0]);
  if (thing == NOTHING || !controls (privs, thing, POW_STATS)) {
    strcpy(buff,"#-1");
    return;
  }
  sprintf(buff,"%d",mem_usage(thing));
}

void fun_playmem (buff, args, privs)
     char *buff;
     char *args[10];
     dbref privs;
{
  int tot=0;
  dbref thing;
  dbref j;

  thing = match_thing (privs, args[0]);
  if (thing == NOTHING || !controls (privs, thing, POW_STATS) || !power (privs, POW_STATS)) {
    strcpy(buff,"#-1");
    return;
  }
  for (j = 0; j<db_top; j++)
    if (db[j].owner == thing)
      tot += mem_usage (j);
  sprintf (buff,"%d",tot);
}
void fun_mid(buff,args)
     char *buff;
     char *args[10];
{
  int l=atoi(args[1]),len=atoi(args[2]);
  if ((l<0) || (len<0) || ((len+l)>1000))
    {
      strcpy(buff,"OUT OF RANGE");
      return;
    }
  if (l<strlen(args[0]))
    strcpy(buff,args[0]+l);
  else
    *buff=0;
  buff[len]=0;
}


void fun_add(buff,args)
     char *buff;
     char *args[10];
{
  sprintf(buff,"%d",atoi(args[0])+atoi(args[1]));
}

void fun_band(buff,args)
     char *buff;
     char *args[10];
{
  sprintf(buff,"%d",atoi(args[0]) & atoi(args[1]));
}

void fun_bor(buff,args)
     char *buff;
     char *args[10];
{
  sprintf(buff,"%d",atoi(args[0]) | atoi(args[1]));
}

void fun_bxor(buff,args)
     char *buff;
     char *args[10];
{
  sprintf(buff,"%d",atoi(args[0]) ^ atoi(args[1]));
}

void fun_bnot(buff,args)
     char *buff;
     char *args[10];
{
  sprintf(buff,"%d",~atoi(args[0]));
}

int istrue(str)
     char *str;
{
  return (((strcmp(str,"#-1") == 0) || (strcmp(str,"") == 0) ||
	  ((atoi(str) == 0) && isdigit(str[0]))) ? 0 : 1);
}

void fun_land(buff,args)
     char *buff;
     char *args[10];
{
  sprintf(buff,"%d",istrue(args[0]) && istrue(args[1]));
}

void fun_lor(buff,args)
     char *buff;
     char *args[10];
{
  sprintf(buff,"%d",istrue(args[0]) || istrue(args[1]));
}

void fun_lxor(buff,args)
     char *buff;
     char *args[10];
{
  sprintf(buff,"%d",(istrue(args[0]) == 0 ? (istrue(args[1]) == 0 ? 0 : 1) :
		                          (istrue(args[1]) == 0 ? 1 : 0)));
}

void fun_lnot(buff,args)
     char *buff;
     char *args[10];
{
  sprintf(buff,"%d", (istrue(args[0]) == 0 ? 1 : 0));
}

void fun_truth(buff,args)
     char *buff;
     char *args[10];
{
  sprintf(buff,"%d", (istrue(args[0]) ? 1 : 0));
}

void fun_base(buff,args)
     char *buff;
     char *args[10];
{
  
  int i, digit, decimal, neg, oldbase, newbase;
  char tmpbuf[1000];

  oldbase = atoi(args[1]);
  newbase = atoi(args[2]);

  if ((oldbase < 2) || (oldbase > 36) || (newbase < 2) || (newbase > 36)) {
    strcpy(buff, "BASES MUST BE BETWEEN 2 AND 36");
    return;
  }
  
  neg = 0;
  if (args[0][0]=='-') {
    neg = 1;
    args[0][0] = '0';
  }

  decimal = 0;
  for (i=0; args[0][i] != 0; i++) {

    decimal *= oldbase;

    if (('0' <= args[0][i]) && (args[0][i] <= '9'))
      digit = args[0][i] - '0';
    else if (('a' <= args[0][i]) && (args[0][i] <= 'z'))
      digit = args[0][i] + 10 - 'a';
    else if (('A' <= args[0][i]) && (args[0][i] <= 'Z'))
      digit = args[0][i] + 10  - 'A';
    else {
      strcpy(buff, "ILLEGAL DIGIT");
      return;
    }

    if (digit >= oldbase) {
      strcpy(buff, "DIGIT OUT OF RANGE");
      return;
    }
    decimal += digit;
  }

  strcpy(buff,"");
  strcpy(tmpbuf,"");

  i = 0;
  while (decimal > 0) {
    strcpy(tmpbuf,buff);
    digit = (decimal % newbase);

    if (digit < 10)
      sprintf(buff,"%d%s", digit, tmpbuf);
    else
      sprintf(buff,"%c%s", digit+'a'-10, tmpbuf);

    decimal /= newbase;
    i++;
  }
  if (neg) {
    strcpy(tmpbuf,buff);
    sprintf(buff,"-%s",tmpbuf);
  }
}

void fun_sgn(buff,args)
     char *buff;
     char *args[10];
{
  sprintf(buff,"%d",atoi(args[0]) > 0 ? 1 : atoi(args[0]) < 0 ? -1 : 0);
}

void fun_sqrt(buff, args)
     char *buff;
     char *args[10];
{
  extern double sqrt P((double));
  int k;
  k= atoi(args[0]);
  if (k<0)
    k= (-k);
  sprintf(buff,"%d",(int)sqrt((double)k));
}

void fun_abs(buff,args)
     char *buff;
     char *args[10];
{
  extern int abs P((int));

  sprintf(buff,"%d",abs(atoi(args[0])));
}

void fun_mul(buff,args)
     char *buff;
     char *args[10];
{
  sprintf(buff,"%d",atoi(args[0])*atoi(args[1]));
}


void fun_div(buff,args)
     char *buff;
     char *args[10];
{
  int bot=atoi(args[1]);
  if (bot==0)
    bot=1;
  sprintf(buff,"%d",atoi(args[0])/bot);
}

void fun_mod(buff,args)
     char *buff;
     char *args[10];
{
  int bot=atoi(args[1]);
  if (bot==0)
    bot=1;
  sprintf(buff,"%d",atoi(args[0]) % bot);
}

/* read first word from a string */
void fun_first(buff,args)
     char *buff;
     char *args[10];
{
  char *s=args[0];
  char *b;
  /* get rid of leading space */
  while(*s && (*s==' ')) s++;
  b=s;
  while(*s && (*s!=' ')) s++;
  *s++=0;
  strcpy(buff,b);
}

void fun_rest(buff,args)
     char *buff;
     char *args[10];
{
  char *s=args[0];
  /* skip leading space */
  while(*s && (*s==' ')) s++;
  /* skip firsts word */
  while(*s && (*s!=' ')) s++;
  /* skip leading space */
  while(*s && (*s==' ')) s++;
  strcpy(buff,s);
}

void fun_flags(buff,args,privs,owner)
     char *buff;
     char *args[10];
     dbref privs;
     dbref owner;
{
  dbref thing;
  int oldflags;			/* really kludgy. */
  
  init_match(privs, args[0], NOTYPE);
  match_me();
  match_here();
  match_neighbor();
  match_absolute();
  match_possession();
  match_player();
  thing = match_result();
  
  if ( thing == NOTHING || thing == AMBIGUOUS )  {
    *buff = '\0';
    return;
  }
  
/*
    if ( ! controls(owner, thing, POW_FUNCTIONS) )  {
    *buff = '\0';
    return;
    }
*/
  oldflags = db[thing].flags;	/* grr, this is kludgy. */
  if (!controls(privs,thing,POW_WHO) &&
      !could_doit(privs, thing, A_LHIDE))
    db[thing].flags &= ~(PLAYER_CONNECT);
  strcpy(buff, unparse_flags(thing));
  db[thing].flags = oldflags;
}

void fun_mtime(buff, args, player)
     char *buff;
     char *args[10];
     dbref player;
{
  dbref thing;
  thing = match_thing(player,args[0]);
  if (thing == NOTHING)
    strcpy(buff,"#-1");
  else
    sprintf(buff,"%d",db[thing].mod_time);
}

void fun_ctime(buff, args, player)
     char *buff;
     char *args[10];
     dbref player;
{
  dbref thing;
  thing = match_thing(player,args[0]);
  if (thing == NOTHING)
    strcpy(buff,"#-1");
  else
    sprintf(buff,"%d",db[thing].create_time);
}


void fun_credits(buff,args,player)
     char *buff;
     char *args[10];
     dbref player;
{
  dbref who;
  
  init_match(player, args[0], TYPE_PLAYER);
  match_me();
  match_player();
  match_neighbor();
  match_absolute();
  if ( (who = match_result()) == NOTHING )  {
    strcpy(buff,"#-1");
    return;
  }
  
  if (!power(player,POW_FUNCTIONS)&&!controls(player, who, POW_FUNCTIONS) ) {
    strcpy(buff,"#-1");
    return;
  }
  
  sprintf(buff,"%d",Pennies(who));
}

void fun_quota_left(buff,args,player)
     char *buff;
     char *args[10];
     dbref player;
{
  dbref who;
  
  init_match(player, args[0], TYPE_PLAYER);
  match_me();
  match_player();
  match_neighbor();
  match_absolute();
  if ( (who = match_result()) == NOTHING )  {
    strcpy(buff,"#-1");
    return;
  }
  
  if ( ! controls(player, who,POW_FUNCTIONS) )  {
    strcpy(buff,"#-1");
    return;
  }
  
  sprintf(buff,"%d", atoi(atr_get(who, A_RQUOTA)));
}

void fun_quota(buff,args,player)
     char *buff;
     char *args[10];
     dbref player;
{
  dbref who;
  
  init_match(player, args[0], TYPE_PLAYER);
  match_me();
  match_player();
  match_neighbor();
  match_absolute();
  if ( (who = match_result()) == NOTHING )  {
    strcpy(buff,"#-1");
    return;
  }
  
  if ( ! controls(player, who,POW_FUNCTIONS) )  {
    strcpy(buff,"#-1");
    return;
  }
  
  /* count up all owned objects */
  /*  owned = -1;  * a player is never included in his own quota */
  /*  for ( thing = 0; thing < db_top; thing++ )  {
      if ( db[thing].owner == who )
      if ((db[thing].flags & (TYPE_THING|GOING)) != (TYPE_THING|GOING))
      ++owned;
      }*/
  strcpy(buff,atr_get(who,A_QUOTA));
  /*  sprintf(buff,"%d", (owned + atoi(atr_get(who, A_RQUOTA))));*/
}

void fun_stat(buff,args,player)
     char *buff;
     char *args[10];
     dbref player;
{
  int owned;
  dbref who, thing;
  
  init_match(player, args[0], TYPE_PLAYER);
  match_me();
  match_player();
  match_neighbor();
  match_absolute();
  if ( (who = match_result()) == NOTHING )  {
    strcpy(buff,"#-1");
    return;
  }
  
  if ( ! controls(player, who,POW_FUNCTIONS) )  {
    strcpy(buff,"#-1");
    return;
  }
  
  /* count up all owned objects */
  owned = -1;  /* a player is never included in his own quota */
  for ( thing = 0; thing < db_top; thing++ )  {
    if ( db[thing].owner == who )
      if ((db[thing].flags & (TYPE_THING|GOING)) != (TYPE_THING|GOING))
	++owned;
  }
  sprintf(buff,"%d", owned);
}

void fun_strlen(buff,args)
     char *buff;
     char *args[10];
{
  sprintf(buff,"%d",strlen(args[0]));
}

void fun_comp(buff, args)
     char *buff;
     char *args[10];
{
  int x;
  
  x = (atoi(args[0]) - atoi(args[1]));
  if ( x > 0 )
    strcpy(buff, "1");
  else if ( x < 0 )
    strcpy(buff, "-1");
  else
    strcpy(buff, "0");
}

void fun_scomp(buff, args)
     char *buff;
     char *args[10];
{
  int x;
  
  x = strcmp(args[0], args[1]);
  if ( x > 0 )
    strcpy(buff, "1");
  else if ( x < 0 )
    strcpy(buff, "-1");
  else
    strcpy(buff, "0");
}

/* handle 0-9,va-vz,n,# */
void fun_v(buff,args,privs,doer)
     char *buff;
     char *args[10];
     dbref privs;
     dbref doer;
{
  int c;
  if (args[0][0] && args[0][1]) {
    /* not a null or 1-character string. */
    ATTR *attrib;
    
    if (!(attrib=atr_str(privs,privs,args[0]))) {
      *buff = '\0';
      return;
    }
    strcpy(buff,atr_get(privs,attrib));
    return;
  }
  switch(c=args[0][0]) {
  case '0': case '1': case '2': case '3': case '4': case '5': case '6':
  case '7': case '8': case '9':
    if (!wptr[c-'0']) {
      *buff=0;
      return;
    }
    strcpy(buff,wptr[c-'0']);
    break;
  case 'v':
  case 'V': {
    int a;
    
    a=to_upper(args[0][1]);
    if ((a<'A') || (a>'Z')) {
      *buff=0;
      return;
    }
    strcpy(buff,atr_get(privs,A_V[a-'A']));
  }
    break;
  case 'n':
  case 'N':
    strcpy(buff,db[doer].name);
    break;
  case '#':
    sprintf(buff,"#%d",doer);
    break;
    /* info about location and stuff */
    /* objects # */
  case '!':
    sprintf(buff,"#%d",privs);
    break;
  default:
    *buff = '\0';
    break;
  }
}

void fun_s(buff,args,privs,doer)
     char *buff;
     char *args[10];
     dbref privs;
     dbref doer;
{
  char buff1[1024];

  pronoun_substitute(buff1,doer,args[0],privs);
  strcpy(buff,buff1+strlen(db[doer].name)+1);
}

void fun_s_with(buff,args,privs,doer,nargs)
     char *buff;
     char *args[10];
     dbref privs;
     dbref doer;
     int nargs;
{
  char buff1[1024];
  char *tmp[10];
  int a;

  if (nargs < 1) {
    strcpy(buff,"#-1");
    return;
  }

  for (a=0; a<10; a++)
    tmp[a] = wptr[a];

  wptr[9] = 0;
  for (a=1; a<10; a++)
    wptr[a-1] = args[a];

  for (a=nargs; a<10; a++)
    wptr[a-1] = 0;

  pronoun_substitute(buff1,doer,args[0],privs);
  strcpy(buff,buff1+strlen(db[doer].name)+1);

  for (a=0; a<10; a++)
    wptr[a] = tmp[a];
}

void fun_s_as(buff, args, privs, doer)
     char *buff;
     char *args[10];
     dbref privs;
     dbref doer;
{
  char buff1[1024];
  dbref newprivs;
  dbref newdoer;

  newdoer = match_thing(privs, args[1]);
  newprivs = match_thing(privs, args[2]);

  if (!controls(privs, newdoer, POW_MODIFY)) {
    strcpy(buff,"Permission denid.");
    return;
  }

  pronoun_substitute(buff1,newdoer, args[0], newprivs);
  strcpy(buff,buff1+strlen(db[newdoer].name)+1);
}

void fun_s_as_with(buff,args,privs,doer,nargs)
     char *buff;
     char *args[10];
     dbref privs;
     dbref doer;
     int nargs;
{
  char buff1[1024];
  char *tmp[10];
  int a;
  dbref newprivs;
  dbref newdoer;

  if (nargs < 3) {
    strcpy(buff,"#-1");
    return;
  }

  newdoer = match_thing(privs, args[1]);
  newprivs = match_thing(privs, args[2]);

  if (!controls(privs, newdoer, POW_MODIFY)) {
    strcpy(buff,"Permission denid.");
    return;
  }
  for (a=0; a<10; a++)
    tmp[a] = wptr[a];

  wptr[9] = wptr[8] = wptr[7] = 0;
  for (a=3; a<10; a++)
    wptr[a-3] = args[a];

  for (a=nargs; a<10; a++)
    wptr[a-3] = 0;

  pronoun_substitute(buff1,newdoer, args[0], newprivs);
  strcpy(buff,buff1+strlen(db[newdoer].name)+1);

  for (a=0; a<10; a++)
    wptr[a] = tmp[a];
}

void fun_num(buff,args,privs)
     char *buff;
     char *args[];
     dbref privs;
{
  sprintf(buff,"#%d",match_thing(privs,args[0]));
}

void fun_con(buff,args,privs,doer)
     char *buff;
     char *args[];
     dbref privs;
     dbref doer;
{
  dbref it=match_thing(privs,args[0]);
  if ((it!=NOTHING) && (controls(privs,it,POW_FUNCTIONS) ||
			(db[privs].location==it) || (it==doer)))
    {
      sprintf(buff,"#%d",db[it].contents);
      return;
    }
  strcpy(buff,"#-1");
  return;
}

/* return next exit that is ok to see */
dbref next_exit(player,this)
     dbref player;
     dbref this;
{
  while( (this!=NOTHING) &&
	(db[this].flags & DARK) && !controls(player,this,POW_FUNCTIONS) )
    this=db[this].next;
  return(this);
}

void fun_exit(buff,args,privs,doer)
     char *buff;
     char *args[];
     dbref privs;
     dbref doer;
{
  dbref it=match_thing(privs,args[0]);
  if ((it!=NOTHING) && (controls(privs,it,POW_FUNCTIONS) ||
			(db[privs].location==it) || (it==doer))) {
    sprintf(buff,"#%d",next_exit(privs,
				 db[it].exits));
    return;
  }
  strcpy(buff,"#-1");
  return;
}

void fun_next(buff,args,privs,doer)
     char *buff;
     char *args[];
     dbref privs;
     dbref doer;
{
  dbref it=match_thing(privs,args[0]);
  if (it!=NOTHING) {
    if (Typeof(it)!=TYPE_EXIT) {
      if ( controls(privs,db[it].location,POW_FUNCTIONS) ||
	  (db[it].location==doer) || (db[it].location==db[privs].location) ) {
	sprintf(buff,"#%d",db[it].next);
	return;
      }
    } else {
      sprintf(buff,"#%d",next_exit(privs,db[it].next));
      return;
    }
  }
  strcpy(buff,"#-1");
  return;
}

void fun_loc(buff,args,privs,doer)
     char *buff;
     char *args[];
     dbref privs;
     dbref doer;
{
  dbref it=match_thing(privs,args[0]);
  if ((it!=NOTHING) &&
      (controls(privs,it,POW_FUNCTIONS) ||
       controls(privs,db[it].location,POW_FUNCTIONS) ||
       controls_a_zone(privs,it,POW_FUNCTIONS) ||
       power(privs,POW_FUNCTIONS) ||
       (it==doer) ||
       (Typeof(it) == TYPE_PLAYER && !(db[it].flags&DARK))))
    {
      sprintf(buff,"#%d",db[it].location);
      return;
    }
  strcpy(buff,"#-1");
  return;
}

void fun_link(buff,args,privs,doer)
     char *buff;
     char *args[];
     dbref privs;
     dbref doer;
{
  dbref it=match_thing(privs,args[0]);
  if((it!=NOTHING) &&
     (controls(privs,it,POW_FUNCTIONS) ||
      controls(privs,db[it].location,POW_FUNCTIONS) || (it==doer))) {
    sprintf(buff,"#%d",db[it].link);
    return;
  }
  strcpy(buff,"#-1");
  return;
}

void fun_linkup (buff, args, privs)
     char *buff;
     char *args[10];
     dbref privs;
{
  dbref it=match_thing(privs, args[0]);
  dbref i;
  int len=0;
  if(!(controls(privs, it, POW_FUNCTIONS) ||
       controls(privs, db[it].location,POW_FUNCTIONS) || (it==privs))) {
    strcpy(buff,"#-1");
    return;
  }
  *buff = '\0';
  for (i=0; i<db_top; i++)
    if (db[i].link == it)
      if(len) {
        static char smbuf[30]; 
	  sprintf(smbuf, " #%d", i);
	  if((strlen(smbuf)+len)>990) {
	    strcat(buff," #-1");
	    return;
	  }
	  strcat (buff, smbuf);
	  len += strlen(smbuf);
	} else {
	  sprintf(buff, "#%d", i);
	  len = strlen(buff);
	}
}

void fun_class(buff,args,privs)
     char *buff;
     char *args[];
     dbref privs;
{
  dbref it=match_thing(privs,args[0]);
  if(it==NOTHING || !power(privs,POW_WHO))
    *buff = '\0';
  else
    strcpy(buff,get_class(it));
}

void fun_is_a(buff,args,privs)
     char *buff;
     char *args[];
     dbref privs;
{
  dbref thing, parent;

  thing = match_thing(privs,args[0]);
  parent = match_thing(privs,args[1]);
  if (thing == NOTHING || parent == NOTHING)
    strcpy(buff,"#-1");
  else
    strcpy(buff,is_a(thing,parent)?"1":"0");
}

void fun_has(buff,args,privs)
     char *buff;
     char *args[];
     dbref privs;
{
  dbref user, obj;
  dbref i;

  user = match_thing(privs,args[0]);
  obj = match_thing(privs,args[1]);
  if (obj == NOTHING || user == NOTHING)
    strcpy(buff,"#-1");
  else {
    strcpy(buff,"0");
    for (i=db[user].contents; i!=NOTHING; i=db[i].next)
      if (i==obj)
	strcpy(buff,"1");
  }
}

void fun_has_a(buff,args,privs)
     char *buff;
     char *args[];
     dbref privs;
{
  dbref user, parent;
  dbref i;

  user = match_thing(privs,args[0]);
  parent = match_thing(privs,args[1]);
  if (parent == NOTHING || user == NOTHING)
    strcpy(buff,"#-1");
  else {
    strcpy(buff,"0");
    for (i=db[user].contents; i!=NOTHING; i=db[i].next)
      if (is_a(i,parent))
	strcpy(buff,"1");
  }
}

void fun_owner(buff,args,privs)
     char *buff;
     char *args[];
     dbref privs;
{
  dbref it=match_thing(privs,args[0]);
  if (it!=NOTHING) it=db[it].owner;
  sprintf(buff,"#%d",it);
}

void fun_name(buff,args,privs)
     char *buff;
     char *args[];
     dbref privs;
{
  dbref it=match_thing(privs,args[0]);
  if (it==NOTHING)
    strcpy(buff,"");
  else
    if (Typeof(it)==TYPE_EXIT)
      strcpy(buff,main_exit_name(it));
    else
      strcpy(buff,db[it].name);
}

void fun_pos(buff,args)
     char *buff;
     char *args[10];
{
  int i = 1;
  char *t, *u, *s = args[1];
  
  while ( *s )  {
    u = s;
    t = args[0];
    while ( *t && *t == *u )
      ++t, ++u;
    if ( *t == '\0' )  {
      sprintf(buff, "%d", i);
      return;
    }
    
    ++i, ++s;
  }
  
  strcpy(buff, "0");
  return;
}

void fun_delete(buff,args)
     char *buff;
     char *args[10];
{
  char *s = buff, *t = args[0];
  int i, l = atoi(args[1]), len = atoi(args[2]);
  int a0len = strlen(args[0]);
  
  if ( (l < 0) || (len < 0) || (len+l >= 1000) ) {
    strcpy(buff,"OUT OF RANGE");
    return;
  }
  for(i = 0; i < l && *s; i++)
    *s++ = *t++;
  if (len+l >= a0len) {
    *s = '\0';
    return;
  }
  t += len;
  while((*s++ = *t++));
  return;
}

void fun_remove(buff,args)
     char *buff;
     char *args[10];
{
  char *s = buff, *t = args[0];
  int w = atoi(args[1]), num = atoi(args[2]), i;
  
  if (w < 1) {
    strcpy(buff,"OUT OF RANGE");
    return;
  }
  for(i = 1; i < w; i++) {
    while(*t && *t != ' ') *s++ = *t++;
    while(*t && *t == ' ') *s++ = *t++;
  }
  if (!*t) return;
  for(i = 0; i < num; i++) {
    while(*t && *t != ' ') t++;
    while(*t && *t == ' ') t++;
  }
  if (!*t) {
    if (s != buff) s--;
    *s = '\0';
    return;
  }
  while ((*s++ = *t++));
  return;
}

void fun_match(buff,args)
     char *buff;
     char *args[10];
{
  int a;
  int wcount=1;
  char *s=args[0];
  char *ptrsrv[10];
  
  for( a = 0; a < 10; a++)
    ptrsrv[a] = wptr[a];
  
  do  {
    char *r;
    
    /* trim off leading space */
    while ( *s && (*s == ' ') )
      s++;
    r=s;
    
    /* scan to next space and truncate if necessary */
    while ( *s && (*s != ' ') )
      s++;
    if ( *s )
      *s++ = 0;
    
    if ( wild_match(args[1],r) )  {
      sprintf(buff, "%d", wcount);
      for( a=0; a<10; a++ )
	wptr[a] = ptrsrv[a];
      return;
    }
    wcount++;
  }
  
  while(*s)
    ;
  
  strcpy(buff,"0");
  
  for(a=0;a<10;a++)
    wptr[a]=ptrsrv[a];
}

void fun_extract(buff,args)
     char *buff;
     char *args[10];
{
  int start=atoi(args[1]),len=atoi(args[2]);
  char *s=args[0],*r;
  if ((start<1) || (len<1))
    {
      *buff=0;
      return;
    }
  start--;
  while(start && *s)
    {
      while(*s && (*s==' '))
	s++;
      while(*s && (*s!=' '))
	s++;
      start--;
    }
  while(*s && (*s==' '))
    s++;
  r=s;
  while(len && *s)
    {
      while(*s && (*s==' '))
	s++;
      while(*s && (*s!=' '))
	s++;
      len--;
    }
  *s=0;
  strcpy(buff,r);
}

void fun_parents(buff, args, privs)
     char *buff;
     char *args[10];
     dbref privs;
{
  dbref it;
  int i;

  it = match_thing(privs, args[0]);

  if (it == NOTHING) {
    strcpy(buff, "#-1");
    return;
  }
  
  *buff = '\0';

  for (i=0; db[it].parents && db[it].parents[i]!=NOTHING; i++)
    if (controls (privs, it, POW_EXAMINE) || controls(privs, it, POW_FUNCTIONS)
	|| controls (privs, db[it].parents[i], POW_EXAMINE) ||
	controls(privs, db[it].parents[i], POW_FUNCTIONS))
      if (*buff)
	sprintf(buff+strlen(buff)," #%d",db[it].parents[i]);
      else
	sprintf(buff,"#%d",db[it].parents[i]);
}

void fun_children(buff, args, privs)
     char *buff;
     char *args[10];
     dbref privs;
{
  dbref it;
  int i;

  it = match_thing(privs, args[0]);

  if (it == NOTHING) {
    strcpy(buff, "#-1");
    return;
  }
  
  *buff = '\0';

  for (i=0; db[it].children && db[it].children[i]!=NOTHING; i++)
    if (controls (privs, it, POW_EXAMINE) || controls(privs, it, POW_FUNCTIONS)
	|| controls (privs, db[it].children[i], POW_EXAMINE) ||
	controls(privs, db[it].children[i], POW_FUNCTIONS))
      if (*buff) {
	sprintf(buff+strlen(buff)," #%d",db[it].children[i]);
	buff[990] = '\0';
      } else
	sprintf(buff,"#%d",db[it].children[i]);
}
    
void fun_zone(buff, args, privs)
     char *buff;
     char *args[10];
     dbref privs;
{
  dbref thing;

  thing=match_thing (privs, args[0]);
  if (thing == NOTHING) {
    strcpy(buff, "#-1");
    return;
  }
  sprintf(buff, "#%d", db[thing].zone);
}

void fun_getzone(buff, args, privs)
     char *buff;
     char *args[10];
     dbref privs;
{
  dbref thing;

  thing=match_thing (privs, args[0]);
  if (thing == NOTHING) {
    strcpy(buff, "#-1");
    return;
  }
  sprintf(buff, "#%d", get_zone_first(thing));
}

void fun_wmatch(buff, args)
     char *buff;
     char *args[10];
{
  char *string = args[0], *word = args[1], *s, *t;
  int count = 0, done = 0;

  for (s = string; *s && !done; s++) {
    count++;
    while (isspace(*s) && *s) s++;
    t = s;
    while (!isspace(*t) && *t) t++;
    done = (!*t) ? 1 : 0;
    *t = '\0';
    if (!string_compare(s, word)) {
      sprintf(buff, "%d", count);
      return;
    }
    s = t;
  }
  sprintf(buff, "0");
  return;
}

void fun_inzone (buff, args, privs)
     char *buff;
     char *args[10];
     dbref privs;
{
  dbref it=match_thing(privs, args[0]);
  dbref i;
  int len=0;
  if(!controls(privs, it, POW_EXAMINE)) {
    strcpy(buff,"#-1");
    return;
  }
  *buff = '\0';
  for (i=0; i<db_top; i++)
    if (Typeof(i)==TYPE_ROOM)
      if (is_in_zone (i, it))
	if(len) {
	  static char smbuf[30]; /* eek, i hope it's not gunna be this long */
	  sprintf(smbuf, " #%d", i);
	  if((strlen(smbuf)+len)>990) {
	    strcat(buff," #-1");
	    return;
	  }
	  strcat (buff, smbuf);
	  len += strlen(smbuf);
	} else {
	  sprintf(buff, "#%d", i);
	  len = strlen(buff);
	}
}

void fun_zwho (buff, args, who)
     char *buff;
     char *args[10];
     dbref who;
{
  dbref it=match_thing(who, args[0]);
  dbref i;
  int len=0;
  if(!controls(who, it, POW_FUNCTIONS)) {
    strcpy(buff,"#-1");
    return;
  }
  *buff = '\0';
  for (i=0; i<db_top; i++)
    if (Typeof(i)==TYPE_PLAYER)
      if (is_in_zone(i, it))
	if(len) {
	  static char smbuf[30]; /* eek, i hope it's not gunna be this long */
	  sprintf(smbuf, " #%d", i);
	  if((strlen(smbuf)+len)>990) {
	    strcat(buff," #-1");
	    return;
	  }
	  strcat (buff, smbuf);
	  len += strlen(smbuf);
	} else {
	  sprintf(buff, "#%d", i);
	  len = strlen(buff);
	}
}

void fun_objlist(buff, args, privs, doer)
     char *buff;
     char *args[10];
     dbref privs;
     dbref doer;
{
  dbref it=match_thing(privs,args[0]);

  *buff = '\0';
  if (it == NOTHING)
    return;
  if (Typeof(it)!=TYPE_EXIT)
    if (!(controls(privs, db[it].location, POW_FUNCTIONS) ||
	  (db[it].location == doer) ||
	  (db[it].location == db[privs].location) ||
	  (db[it].location == privs)))
      return;
  while (it != NOTHING) {
    if (*buff)
      strcpy(buff, tprintf("%s #%d",buff, it));
    else
      sprintf(buff,"#%d", it);
    it = (Typeof(it)==TYPE_EXIT)?next_exit(privs, db[it].next):db[it].next;
  }
}

void fun_lzone(buff, args, privs, doer)
     char *buff;
     char *args[10];
     dbref privs;
     dbref doer;
{
  dbref it=match_thing(privs,args[0]);
  int depth=10;

  *buff = '\0';
  if (it == NOTHING)
    return;
  it = get_zone_first(it);
  while (it != NOTHING) {
    if (*buff)
      strcpy(buff, tprintf("%s #%d", buff, it));
    else
      sprintf(buff,"#%d", it);
    it = get_zone_next(it);
    depth--;
    if (depth <= 0) return;
  }
}

void fun_strcat(buff, args)
     char *buff;
     char *args[10];
{
  strcpy(buff,tprintf("%s%s", args[0], args[1]));
}

void fun_controls(buff, args, privs)
     char *buff;
     char *args[10];
     dbref privs;
{
  dbref player, object;
  ptype power;

  player = match_thing(privs, args[0]);
  object = match_thing(privs, args[1]);
  power = name_to_pow(args[2]);

  if (player == NOTHING || object == NOTHING || !power) {
    strcpy(buff,"#-1");
    return;
  }

  sprintf(buff, "%d", controls(player, object, power));
}

void fun_entrances(buff, args, privs)
     char *buff;
     char *args[10];
     dbref privs;
{
  dbref it=match_thing(privs,args[0]);
  dbref i;
  int control_here;


  *buff = '\0';

  if (it == NOTHING)
    strcpy(buff, "#-1");
  else {
    control_here = controls(privs, it, POW_EXAMINE);
    for (i=0; i<db_top; i++)
      if (Typeof(i)==TYPE_EXIT && db[i].link == it)
	if (controls(privs, i, POW_FUNCTIONS) || controls(privs,i, POW_EXAMINE) || control_here)
	  if (*buff)
	    strcpy(buff, tprintf("%s #%d", buff, i));
	  else
	    sprintf(buff,"#%d", i);
  }
}

void fun_fadd (buff, args)
     char *buff;
     char *args[10];
{
  sprintf (buff, "%f", atof(args[0])+atof(args[1]));
}
void fun_fsub (buff, args)
     char *buff;
     char *args[10];
{
  sprintf (buff, "%f", atof(args[0])-atof(args[1]));
}

void fun_sub (buff, args)
     char *buff;
     char *args[10];
{
  sprintf (buff, "%d", atoi(args[0])-atoi(args[1]));
}

void fun_fmul (buff, args)
     char *buff;
     char *args[10];
{
  sprintf (buff, "%f", atof(args[0])*atof(args[1]));
}
void fun_fdiv (buff, args)
     char *buff;
     char *args[10];
{
  sprintf (buff, "%f", atof(args[0])/atof(args[1]));
}
void fun_fsgn (buff, args)
     char *buff;
     char *args[10];
{
  if (atof(args[0])<0)
    sprintf(buff,"-1");
  else if(atof(args[0])>0)
    sprintf(buff,"1");
  else
    strcpy(buff,"0");
}
void fun_fsqrt (buff, args)
     char *buff;
     char *args[10];
{
  sprintf(buff,"%f",sqrt(atof(args[0])));
}

void fun_fabs (buff, args)
     char *buff;
     char *args[10];
{
  if (atof(args[0])<0)
    sprintf(buff,"%f",-atof(args[0]));
  else
    strcpy(buff,args[0]);
}
void fun_fcomp (buff, args)
     char *buff;
     char *args[10];
{
  char buf[90];
  char *k=buf;
  sprintf(buf,"%f",atof(args[0])-atof(args[1]));
  fun_fsgn(buff,&k);
}

void fun_exp (buff, args)
     char *buff;
     char *args[10];
{
  sprintf (buff,"%f", exp(atof(args[0])));
}
void fun_pow (buff, args)
     char *buff;
     char *args[10];
{
  sprintf(buff,"%f",pow(atof(args[0]),atof(args[1])));
}

void fun_log (buff, args)
     char *buff;
     char *args[10];
{
  sprintf(buff,"%f",log10(atof(args[0])));
}

void fun_ln (buff, args)
     char *buff;
     char *args[10];
{
  sprintf(buff,"%f",log(atof(args[0])));
}

void fun_arctan (buff, args)
     char *buff;
     char *args[10];
{
  sprintf(buff,"%f",atan(atof(args[0])));
}

void fun_arccos (buff, args)
     char *buff;
     char *args[10];
{
  sprintf(buff,"%f",acos(atof(args[0])));
}

void fun_arcsin (buff, args)
     char *buff;
     char *args[10];
{
  sprintf(buff,"%f",asin(atof(args[0])));
}

void fun_tan (buff, args)
     char *buff;
     char *args[10];
{
  sprintf(buff,"%f",tan(atof(args[0])));
}

void fun_cos (buff, args)
     char *buff;
     char *args[10];
{
  sprintf(buff,"%f",cos(atof(args[0])));
}

void fun_sin (buff, args)
     char *buff;
     char *args[10];
{
  sprintf(buff,"%f",sin(atof(args[0])));
}

void fun_if(buff, args)
     char *buff;
     char *args[10];
{
  if (istrue(args[0]))
    sprintf(buff,"%s",args[1]);
  else
    *buff = '\0';
  return;
}

void fun_ifelse(buff, args)
     char *buff;
     char *args[10];
{
  if (istrue(args[0]))
    sprintf(buff,"%s",args[1]);
  else
    sprintf(buff,"%s",args[2]);
  return;
}

void fun_rmatch (buff, args, privs, doer)
     char *buff;
     char *args[10];
     dbref privs;
     dbref doer;
{
  dbref who;
  who = match_thing (privs, args[0]);
  if (!controls (privs, who, POW_EXAMINE) && who != doer) {
    strcpy (buff,"#-1");
    notify (privs, "Permission denied.");
    return;
  }
  init_match (who, args[1], NOTYPE);
  match_everything();
  sprintf (buff,"#%d", match_result());
}

void fun_wcount(buff, args)
     char *buff;
     char *args[10];
{
  char *p = args[0];
  int num = 0;
  
  while (*p) {
    while (*p && isspace(*p)) p++;
    if (*p) num++;
    while (*p && !isspace(*p)) p++;
  }
  sprintf(buff,"%d",num);
  return;
}

/* MERLMOD */

void fun_lwho (buff, privs, owner)
     char *buff;
     dbref privs;
     dbref owner;
{
  char buf[1024];
  struct descriptor_data *d;
 
   if( Typeof(owner) != TYPE_PLAYER && ! payfor(owner, 50) ) {
    notify(owner, "You don't have enough pennies.");
    return;
  }
  *buf = '\0';
  for (d = descriptor_list; d; d = d->next) {
    if (d->state==CONNECTED && d->player>0) {
    if ((controls(owner, d->player, POW_WHO)) ||
	could_doit(owner, d->player, A_LHIDE))
      {
	if(*buf)
	  strcpy(buf, tprintf("%s #%d",buf, d->player));
	else
	  sprintf(buf, "#%d", d->player);
      }
  }}
  strcpy(buff,buf);
}

void fun_spc(buff, args, dumm1, dumm2)
     char *buff;
     char *args[10];
     dbref dumm1, dumm2;
{
  char tbuf1[1024];
  int i;
  int s = atoi(args[0]);

  if (s <= 0 ) {
    strcpy(buff, "");
    return;
  }

  if (s > 950)
    s = 950;

  for (i = 0; i < s; i++)
    tbuf1[i] = ' ';
  tbuf1[i] = '\0';
  strcpy(buff, tbuf1);
}

void do_flip(s, r)
     char *s;
     char *r;
  /* utility function to reverse a string */
{
  char *p;

  p = strlen(s) + r;
  for (*p-- = '\0'; *s; p--, s++)
       *p = *s;
}

void fun_flip(buff, args, dumm1, dumm2)
     char *buff;
     char *args[10];
     dbref dumm1, dumm2;
{
  do_flip(args[0], buff);
}

void fun_lnum(buff, args, dumm1, dumm2)
    char *buff;
    char *args[10];
    dbref dumm1, dumm2;
{
  int x, i;
  x = atoi(args[0]);
  if ((x > 250) || (x < 0)) {
    strcpy(buff, "#-1 Number Out Of Range");
    return;
  }
  else {
    strcpy(buff,"0");
    for (i = 1; i < x; i++)
      sprintf(buff, "%s %d", buff, i);
  }
}


void fun_string (buf, args, privs)
     char *buf;
     char *args[10];
     dbref privs;
{
  int num, i;
  char *letter;
  *buf = '\0';
  num=atoi(args[1]);
  letter=args[0];

  if (((num*strlen(letter)) <= 0) || ((num*strlen(letter)) > 950)) {
    strcpy(buf, "#-1 Out Of Range");
    return;
  }

  *buf = '\0';
  for (i = 0; i < num; i++)
    strcat(buf,letter);
}

void fun_ljust (buff, args, privs)
     char *buff;
     char *args[10];
     dbref privs;
{
  int number=atoi(args[1]);
  char *text;
  int leader;
  char tbuf1[1000];
  char buf[1000];
  int i;

  if (number <= 0 || number > 950) {
    sprintf(buff, "#-1 Number out of range.");
    return;
  }

  text=args[0];
  leader=number-strlen(text);

  if (leader <= 0) {
    strcpy(buff, text);
    buff[number]=0;
    return;
  }

  if (leader > 950)
    leader = 950;

  for (i = 0; i < leader; i++)
    tbuf1[i] = ' ';
  tbuf1[i] = '\0';
  sprintf(buf,"%s%s",text,tbuf1);
  strcpy(buff,buf);
}

void fun_rjust (buff, args, privs)
     char *buff;
     char *args[10];
     dbref privs;
{
  int number=atoi(args[1]);
  char *text;
  int leader;
  char tbuf1[1000];
  char buf[1000];
  int i;

  if (number <= 0 || number > 950) {
    sprintf(buff, "#-1 Number out of range.");
    return;
  }

  text=args[0];
  leader=number-strlen(text);

  if (leader <= 0) {
    strcpy(buff, text);
    buff[number]=0;
    return;
  }

  if (leader > 950)
    leader = 950 - 1;

  for (i = 0; i < leader; i++)
    tbuf1[i] = ' ';
  tbuf1[i] = '\0';
  sprintf(buf,"%s%s",tbuf1,text);
  strcpy(buff,buf);
}

void fun_lattrdef(buff, args, privs)
     char *buff;
     char *args[10];
     dbref privs;
{
  dbref it=match_thing(privs, args[0]);
  int len=0;
  ATRDEF *k;
  *buff = '\0';
  if ((db[it].atrdefs) && (controls(privs,it,POW_EXAMINE) || (db[it].flags & SEE_OK))) {
    for (k=db[it].atrdefs; k; k=k->next) {
	if(len) {
	  static char smbuf[100];
	  sprintf(smbuf, " %s", k->a.name);
	  if((strlen(smbuf)+len)>990) {
	    strcat(buff, " #-1");
	    return;
	  }
	  strcat(buff, smbuf);
	  len += strlen(smbuf);
	} else {
	  sprintf(buff, "%s", k->a.name);
	  len=strlen(buff);
	}
    }
  }
}

void fun_lattr(buff, args, privs)
     char *buff;
     char *args[10];
     dbref privs;
{
  dbref it=match_thing(privs, args[0]);
  int len=0;
  ALIST *a;
  char temp[1024];
  *buff = '\0';
  if (db[it].list) {
    for (a=db[it].list; a; a=AL_NEXT(a)) {
      if (AL_TYPE(a) && can_see_atr(privs, it, AL_TYPE(a))) {
	sprintf(temp, (*buff)?" %s":"%s", unparse_attr(AL_TYPE(a),0));
	if ((len+strlen(temp))>960) {
	  strcat(buff," #-1");
	  return;
	}
	strcpy(buff+len,temp);
	len += strlen(temp);
      }
    }
  }
}

void fun_type(buff, args, privs, dumm1)
     char *buff;
     char *args[10];
     dbref privs;
     dbref dumm1;
{
  extern char *type_to_name();
  dbref it = match_thing(privs, args[0]);
  if (it == NOTHING) {
    strcpy(buff, "#-1");
    return;
  }
  strcpy(buff, type_to_name(Typeof(it)));
}

void fun_idle (buff, args, owner)
     char *buff;
     char *args[10];
     dbref owner;
{
  char buf[1024];
  struct descriptor_data *d;
  dbref who=0;
  time_t now;
  time(&now);

  if (!string_compare(args[0], "me"))
    who=owner;
  else
    who=lookup_player(args[0]);
  if ( !who ) {
    sprintf(buff, "#-1");
    return;
  }
  sprintf(buf,"#-1");
  for (d = descriptor_list; d; d = d->next) {
    if (d->state==CONNECTED && d->player>0) {
    if ((controls(owner, d->player, POW_WHO)) ||
	could_doit(owner, d->player, A_LHIDE))
      {
	if ( d->player == who ) {
	  sprintf(buf,"%d",(now - d->last_time));
	  break; }
      }
  }}
  if ( buf == NULL)
    sprintf(buf,"#-1");
  strcpy(buff,buf);
}

void fun_onfor (buff, args, owner)
     char *buff;
     char *args[10];
     dbref owner;
{
  char buf[1024];
  struct descriptor_data *d;
  dbref who=0;
  time_t now;

  time(&now);

  if ( !(string_compare(args[0], "me")))
    who=owner;
  else
    who=lookup_player(args[0]);
  if (!who) {
    sprintf(buff, "#-1");
    return;
  }
  sprintf(buf,"#-1");
  for (d = descriptor_list; d; d = d->next) {
    if (d->state==CONNECTED && d->player>0) {
    if ((controls(owner, d->player, POW_WHO)) ||
	could_doit(owner, d->player, A_LHIDE))
      {
	if ( d->player == who ) {
	  sprintf(buf,"%d",(now - d->connected_at));
	  break; }
      }
  }}
  if ( buf == NULL)
    sprintf(buf,"#-1");
  strcpy(buff,buf);
}

void fun_host(buff, args, owner)
     char *buff;
     char *args[10];
     dbref owner;
{
  char buf[1024];
  struct descriptor_data *d;
  dbref who=0;
  time_t now;

  time(&now);
  
  if ( !(string_compare(args[0], "me")))
    who=owner;
  else
    who=lookup_player(args[0]);
  if ( (!who) || !(controls(owner, who, POW_HOST))) {
    strcpy(buff,"#-1");
    return;
  }

  sprintf(buf,"#-1");
  for (d = descriptor_list; d; d = d->next) {
    if (d->state==CONNECTED && d->player>0) {
    if ((controls(owner, d->player, POW_WHO)) ||
	could_doit(owner, d->player, A_LHIDE))
      {
	if ( d->player == who ) {
	  sprintf(buf,"%s", d->addr);
	  break; }
      }
  }}
  if ( buf == NULL)
    sprintf(buf,"#-1");
  strcpy(buff,buf);
}


void fun_tms(buff,args)
     char *buff;
     char *args[10];
{
  int num=atoi(args[0]);
  if (num <0 ) {
    sprintf(buff,"#-1"); } else {
      sprintf(buff,"%s",time_format_2(num)); }
}

void fun_tml(buff,args)
     char *buff;
     char *args[10];
{
  int num=atoi(args[0]);
  if (num <0 ) {
    sprintf(buff,"#-1"); } else {
      sprintf(buff,"%s",time_format_1(num)); }
}

typedef struct fun FUN;

struct fun {
  char *name;
  void (*fun)();
  int nargs;
};

FUN flist[]={
  {"IS_A",   fun_is_a,   2},
  {"RAND",   fun_rand,   1},
  {"TIME",   fun_time,  -1},
  {"XTIME",  fun_xtime, -1},
  {"CLASS",  fun_class,  1},
  {"FOREACH",fun_foreach,2},
  {"GET",    fun_get,   -1},
  {"HAS_A",  fun_has_a,  2},
  {"HAS",    fun_has,    2},
  {"ATTROPTS",fun_attropts, -1},
  {"SWITCH", fun_switch,-1},
  {"PLAYMEM",fun_playmem,1},
  {"OBJMEM", fun_objmem, 1},
  {"MID",    fun_mid,    3},
  {"DELETE", fun_delete, 3},
  {"ADD",    fun_add,    2},
  {"MUL",    fun_mul,    2},
  {"DIV",    fun_div,    2},
  {"MOD",    fun_mod,    2},
  {"SUB",    fun_sub,    2},
  {"RMATCH", fun_rmatch, 2},
  {"FADD",   fun_fadd,   2},
  {"FMUL",   fun_fmul,   2},
  {"FDIV",   fun_fdiv,   2},
  {"FSUB",   fun_fsub,   2},
  {"BAND",   fun_band,   2},
  {"BOR",    fun_bor,    2},
  {"BXOR",   fun_bxor,   2},
  {"BNOT",   fun_bnot,   1},
  {"LAND",   fun_land,   2},
  {"LOR",    fun_lor,    2},
  {"LXOR",   fun_lxor,   2},
  {"LNOT",   fun_lnot,   1},
  {"TRUTH",  fun_truth,  1},
  {"BASE",   fun_base,   3},
  {"PARENTS",fun_parents,1},
  {"CHILDREN",fun_children,1},
  {"SQRT",   fun_sqrt,   1},
  {"SGN",    fun_sgn,    1},
  {"ABS",    fun_abs,    1},
  {"FSQRT",  fun_fsqrt,   1},
  {"FSGN",   fun_fsgn,    1},
  {"FABS",   fun_fabs,    1},
  {"FIRST",  fun_first,  1},
  {"STRCAT", fun_strcat, 2},
  {"REST",   fun_rest,   1},
  {"FLAGS",  fun_flags,  1},
  {"STRLEN", fun_strlen, 1},
  {"COMP",   fun_comp,   2},
  {"FCOMP",  fun_fcomp,  2},
  {"SCOMP",  fun_scomp,  2},
  {"V",      fun_v,      1},
  {"S",      fun_s,      1},
  {"S_AS",   fun_s_as,   3},
  {"S_WITH", fun_s_with, -1},
  {"S_AS_WITH",fun_s_as_with,-1},
  {"QUOTA",  fun_quota  ,1},
  {"ENTRANCES", fun_entrances, 1},
  {"QUOTA_LEFT",fun_quota_left,1},
  {"CREDITS",fun_credits,1},
  {"CTIME",  fun_ctime,  1},
  {"MTIME",  fun_mtime,  1},
  {"POS",    fun_pos,    2},
  {"MATCH",  fun_match,  2},
  {"EXTRACT",fun_extract,3},
  {"REMOVE", fun_remove, 3},
  {"NUM",    fun_num,    1},
  {"CON",    fun_con,    1},
  {"NEXT",   fun_next,   1},
  {"OWNER",  fun_owner,  1},
  {"LOC",    fun_loc,    1},
  {"LINK",   fun_link,   1},
  {"LINKUP", fun_linkup, 1},
  {"EXIT",   fun_exit,   1},
  {"NAME",   fun_name,   1},
  {"ZONE",   fun_zone,   1},
  {"GETZONE",fun_getzone,1},
  {"LZONE",  fun_lzone,  1},
  {"WMATCH", fun_wmatch, 2},
  {"INZONE", fun_inzone, 1},
  {"ZWHO",   fun_zwho,   1},
  {"OBJLIST", fun_objlist, 1},
  {"CONTROLS", fun_controls, 3},
  {"SIN",    fun_sin,    1},
  {"COS",    fun_cos,    1},
  {"TAN",    fun_tan,    1},
  {"ARCSIN", fun_arcsin, 1},
  {"ARCCOS", fun_arccos, 1},
  {"ARCTAN", fun_arctan, 1},
  {"LOG",    fun_log,    1},
  {"LN",     fun_ln,     1},
  {"EXP",    fun_exp,    1},
  {"POW",    fun_pow,    2},
  {"IF",     fun_if,     2},
  {"IFELSE", fun_ifelse, 3},
  {"WCOUNT", fun_wcount, 1},
#ifdef USE_SPACE /* by Michael Majere */
  {"DG2RD",  fun_dg2rd,  1},
  {"RD2DG",  fun_rd2dg,  1},
  {"KM2AU",  fun_km2au,  1},
  {"AU2KM",  fun_au2km,  1},
  {"KM2PS",  fun_km2ps,  1},
  {"PS2KM",  fun_ps2km,  1},
  {"KM2LY",  fun_km2ly,  1},
  {"LY2KM",  fun_ly2km,  1},
  {"KS2LS",  fun_ks2ls,  1},
  {"LS2KS",  fun_ls2ks,  1},
  {"DIST3D", fun_dist3d, 6},
  {"HEAD3D", fun_head3d, 6},
  {"RELHEAD",fun_relhead,4},
  {"VELHDG", fun_velhdg, 3},
  {"VELMAG", fun_velmag, 3},
  {"RELPHI", fun_relphi, 6},
  {"ORBIT",  fun_orbit,  4}, 
  {"SYNC",   fun_sync,   1},
  {"UPDATES", fun_updates,-1},
  {"INRANGE", fun_inrange, 1},
  {"INSIGHT", fun_insight, 2},
  {"INSPACE", fun_inspace, 1},
  {"INDIST", fun_indist, 2},
#endif
  {"LWHO",   fun_lwho,   0},
  {"SPC",    fun_spc,    1},
  {"FLIP",   fun_flip,   1},
  {"LNUM",   fun_lnum,   1},
  {"STRING", fun_string, 2},
  {"LJUST",  fun_ljust,  2},
  {"RJUST",  fun_rjust,  2},
  {"LATTRDEF",fun_lattrdef,1},
  {"LATTR",  fun_lattr,  1},
  {"TYPE",   fun_type,   1},
  {"IDLE",   fun_idle,   1},
  {"ONFOR",  fun_onfor,  1},
  {"HOST",   fun_host,   1},
  {"TMS",    fun_tms,    1},
  {"TML",    fun_tml,    1},
  {NULL,     NULL,       0}
};

void exec();

int udef_fun(str, buff, privs, doer)
     char **str;
     char *buff;
     dbref privs;
     dbref doer;
{
  ATTR *attr;
  dbref tmp, defed_on = NOTHING;
  char obuff[1024], *args[10], *s;
  int a;

  /* check for explicit redirection */
  if ((buff[0] == '#') && ((s = strchr(buff,':')) != NULL)) {
    *s = '\0';
    tmp = (dbref) atoi(buff + 1);
    *s++ = ':';
    if (((attr = atr_str(privs, tmp, s)) != NULL) &&
	(attr->flags & AF_FUNC) &&
	can_see_atr(privs, tmp, attr))
      defed_on = tmp;
  } 
  /* check the object doing it */
  else if (((attr = atr_str(privs, tmp = privs, buff)) != NULL) &&
	   (attr->flags & AF_FUNC))
    defed_on = tmp;

  /* check that object's zone */
  else {
    DOZONE(tmp, privs)
      if (((attr = atr_str(privs, tmp, buff)) != NULL) &&
	  (attr->flags & AF_FUNC)) {
	defed_on = tmp;
	break;
      }
  }
  if (defed_on != NOTHING) {
    char result[1024], ftext[1024], *saveptr[10];
    for (a = 0; a < 10; a++) args[a] = "";
    for(a=0;(a<10) && **str &&  (**str!=')');a++) {
      if (**str==',') (*str)++;
      exec(str,obuff,privs,doer,1);
      strcpy(args[a]=na_alloc(glurp,strlen(obuff)+1),obuff);
    }
    for(a = 0; a < 10; a++) {
      saveptr[a] = wptr[a];
      wptr[a] = args[a];
    }
    if (**str) (*str)++;
    strcpy(ftext,atr_get(defed_on, attr));
    pronoun_substitute(result,doer,ftext,privs);
    for(--a; a >= 0; a--) {
/*      na_unalloc(glurp,wptr[a]);. this is an example of something that
	seems to be done often. (i commented this out. it was wrong.).
	you do *not* unallocate things from glurp, especially static
	strings. glurp is freed at the beginning of each command anyways.
	at the for(a=0;a<10;a++) args[a]="";, it was assigning them all
	to "", then it was freeing them here. not good. -shkoo */
      wptr[a] = saveptr[a];
    }
    strcpy(buff, result + strlen(db[doer].name) + 1);
    return 1;
  } else return 0;
}

static char *disp_func (func)
     void *func;
{
  return tprintf("args %d",((FUN *)func)->nargs);
}

void do_fun(str,buff,privs,doer)
     char **str;
     char *buff;
     dbref privs;
     dbref doer;
{
  FUN *fp;
  char *args[10];
  char obuff[1024];
  int a;
  static struct hashtab *funchash=NULL;

  if (!funchash)
    funchash = make_hashtab (207, flist, sizeof(FUN), "funcs", disp_func);
  
  /* look for buff in flist */
  strcpy(obuff,buff);
  fp = lookup_hash (funchash, hash_name (buff), buff);
  if (!fp)
    if (udef_fun(str, buff, privs, doer))
      return;
    else {
      int deep=2;
      char *s=buff+strlen(obuff);
      strcpy(buff,obuff);
      *s++='(';
      while(**str && deep)
	switch(*s++= *(*str)++) {
	case '(':
	  deep++;
	  break;
	case ')':
	  deep--;
	  break;
	}
      if (**str) {
	(*str)--;
	s--;
      }
      *s=0;
      return;
    }
  /* now get the arguments to the function */
  for(a=0;(a<10) && **str &&  (**str!=')');a++) {
    if (**str==',')
      (*str)++;
#ifdef DEBUGEVAL
#define DOLOG(str) do { if(command_log) { fprintf(command_log,str); fflush(command_log); } } while(0)
#else
#define DOLOG(str) do {} while(0)
#endif
    exec(str,obuff,privs,doer,1);
    DOLOG("got back from exec\n");
    strcpy(args[a]=(char *)na_alloc(glurp,strlen(obuff)+1),obuff);
  }
  if (**str)
    (*str)++;
  if ((fp->nargs!=-1) && (fp->nargs!=a))
    strcpy(buff,tprintf("Function (%s) only expects %d arguments",
			fp->name,fp->nargs));
  else {
    extern int floating_x;
    
    DOLOG("trying function ");
    DOLOG(fp->name);
    floating_x = 0;
    fp->fun(buff,args,privs,doer,a);
    if (floating_x)
      strcpy (buff,"Floating exception.");
  }
}

static int lev=0; /* the in depth level which we're at. */
void func_zerolev()
{lev=0;} /* called from process_command just in case this goes
	    bezerko */
/* execute a string expression, return result in buff */
void exec(str,buff,privs,doer,coma)
     char **str;
     char *buff;
     dbref privs;
     dbref doer;
     int coma;
{
  char *s,*e=buff;
#ifdef DEBUGEVAL
  extern FILE *command_log;
#endif
  lev++; /* enter the func. */
  if(lev>20) {
    strcpy(buff,"Too many levels of recursion.");
    lev--;return;
  }
  *buff=0;
DOLOG("execing:");
DOLOG(*str);
DOLOG("\n");
  /* eat preceding space */
  for(s= *str;*s && isspace(*s);s++);
  /* parse until (,],) or , */
  for(;*s;s++)
    switch(*s) {
      case ',': /* comma in list of function arguments */
      case ')': /* end of arguments */
	if (!coma)
	  goto cont;
      case ']': /* end of expression */
	/* eat trailing space */
	while((--e>=buff) && isspace(*e));
	e[1]=0;
	*str=s;
	lev--;return;
      case '(': /* this is a function */
	while((--e>=buff) && isspace(*e));
	e[1]=0;
	*str=s+1;
	/* if just ()'s by them self then it is quoted */
	if (*buff)
	  do_fun(str,buff,privs,doer);
	lev--;return;
      case '{':
	if (e==buff) {
	  int deep=1;
	  e=buff;
	  s++;
	  while(deep && *s)
	    switch(*e++= *s++) {
	    case '{':
	      deep++;
	      break;
	    case '}':
	      deep--;
	      break;
	    }
	  if ((e>buff) && (e[-1]=='}'))
	    e--;
	  while((--e>=buff) && isspace(*e));
	  e[1]=0;
	  *str=s;
	  lev--;return;
	} else {
	  /* otherwise is a quote in middle, search for other end */
	  int deep=1;
	  *e++= *s++;
	  while(deep && *s)
	    switch(*e++= *s++) {
	    case '{':
	      deep++;
	      break;
	    case '}':
	      deep--;
	      break;
	    }
	  s--;
	}
	break;
      default:
      cont:
	*e++= *s;
	break;
      }
  while((--e>=buff) && isspace(*e));
  e[1]=0;
  *str=s;
  lev--;return;
}

/* function to split up a list given a seperator */
/* note str will get hacked up */
char *parse_up(str,delimit)
     char **str;
     int delimit;
{
  int deep=0;
  char *s= *str,*os= *str;
  if (!*s)
    return(NULL);
  while(*s && (*s!=delimit))
    if (*s++=='{') {
      deep=1;
      while(deep && *s)
	switch(*s++) {
	case '{':
	  deep++;
	  break;
	case '}':
	  deep--;
	  break;
	}
    }
  if (*s)
    *s++=0;
  *str=s;
  return(os);
}