/
2.0.4beta/doc/
2.0.4beta/gnu/
2.0.4beta/sha/
/* prims.c */

#include "config.h"

/*
 *		       This file is part of TeenyMUD II.
 *		 Copyright(C) 1993, 1994, 1995 by Jason Downs.
 *                           All rights reserved.
 * 
 * TeenyMUD II is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * TeenyMUD II is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program (see the file 'COPYING'); if not, write to
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 * MA 02111-1307, USA.
 *
 */

/* AIX requires this to be the first thing in the file. */
#ifdef __GNUC__
#define alloca	__builtin_alloca
#else	/* not __GNUC__ */
#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#else	/* not HAVE_ALLOCA_H */
#ifdef _AIX
 #pragma alloca
#endif	/* not _AIX */
#endif	/* not HAVE_ALLOCA_H */
#endif 	/* not __GNUC__ */

#include <stdio.h>
#include <sys/types.h>
#ifdef HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif			/* HAVE_STRING_H */
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#else
#include <time.h>
#endif			/* HAVE_SYS_TIME_H */
#include <ctype.h>
#include <math.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif			/* HAVE_STDLIB_H */

#include "conf.h"
#include "teeny.h"
#include "prims.h"
#include "sha/sha_wrap.h"
#include "externs.h"

Hash_Table Prim_Table;

static const char *errors[] = {
  "#-1 ILLEGAL OBJECT", "#-1 DATABASE ERROR",
  "#-1 PERMISSION DENIED", "#-1 TOO FEW ARGUMENTS",
  "#-1 DIVIDE BY ZERO", "#-1 VARIABLE NAME TOO LONG",
  "#-1 NO SUCH VARIABLE", "#-1 NUMERICAL ARGUMENT EXPECTED",
  "#-1 OBJECT ARGUMENT EXPECTED", "#-1 TOO MANY ARGUMENTS"
};
#define ERR_ILLOBJ	errors[0]
#define ERR_DB		errors[1]
#define ERR_PERM	errors[2]
#define ERR_FEWARGS	errors[3]
#define ERR_DIVZERO	errors[4]
#define ERR_VARLONG	errors[5]
#define ERR_NOVAR	errors[6]
#define ERR_NUM		errors[7]
#define ERR_OBJ		errors[8]
#define ERR_TOOARGS	errors[9]

/* local util prototypes. */
static int strtonum _ANSI_ARGS_((char *, char **));
static void fval _ANSI_ARGS_((char *, double));

/* local utility functions. */

static int strtonum(str, ptr)
    char *str, **ptr;
{
  register int ret;

  if((strlen(str) > 1) && (str[0] == '#')) {
    str++;
    ret = (int)strtol(str, ptr, 10);
    if(*ptr == str) {	/* return the old value. */
      *ptr = &str[-1];
      return(0);
    }
    return(ret);
  }
  *ptr = str;
  return(0);
}

static void fval(buffer, val)
    char *buffer;
    double val;
{
  register char *ptr;

  sprintf(buffer, "%.6f", val);
  ptr = &buffer[strlen(buffer)-1];
  while(((ptr >= buffer) && (*ptr == '0')) || (*ptr == '.'))
    ptr--;
  ptr[1] = '\0';
}

/* primitives. */

static PRIM(prim_getattr)
{
  register int obj;
  char *attr, *ptr;
  int aflags, asource;

  obj = strtonum(argv[1], &ptr);
  if(ptr == argv[1]) {
    strcpy(buffer, ERR_OBJ);
    return;
  }
  if(!exists_object(obj)) {
    strcpy(buffer, ERR_ILLOBJ);
    return;
  }
  if (attr_get_parent(obj, argv[2], &attr, &aflags, &asource) == -1) {
    strcpy(buffer, ERR_DB);
    return;
  }
  if(!can_see_attr(player, cause, obj, aflags)) {
    strcpy(buffer, ERR_PERM);
    return;
  }
  if (attr == (char *)NULL)
    buffer[0] = '\0';
  else
    ty_strncpy(buffer, attr, MEDBUFFSIZ);
}

static PRIM(prim_getlock)
{
  register int obj;
  struct boolexp *lock;
  char *ptr;
  int aflags, asource;

  obj = strtonum(argv[1], &ptr);
  if(ptr == argv[1]) {
    strcpy(buffer, ERR_OBJ);
    return;
  }
  if(!exists_object(obj)) {
    strcpy(buffer, ERR_ILLOBJ);
    return;
  }
  if(attr_getlock_parent(obj, argv[2], &lock, &aflags, &asource) == -1) {
    strcpy(buffer, ERR_DB);
    return;
  }
  if(!can_see_attr(player, cause, obj, aflags)) {
    strcpy(buffer, ERR_PERM);
    return;
  }
  if(lock == (struct boolexp *)NULL)
    buffer[0] = '\0';
  else
    ty_strncpy(buffer, unparse_boolexp(player, cause, lock), MEDBUFFSIZ);
}

static PRIM(prim_contents)
{
  register int obj;
  int list;
  register int count = 0;
  char *ptr, sbuff[32];

  obj = strtonum(argv[1], &ptr);
  if(ptr == argv[1]) {
    strcpy(buffer, ERR_OBJ);
    return;
  }
  if(!exists_object(obj) || !has_contents(obj)){
    strcpy(buffer, ERR_ILLOBJ);
    return;
  }
  if(!controls(player, cause, obj) && !isVISUAL(obj) && !nearby(player, obj)
     &&	(cause != obj)) {
    strcpy(buffer, ERR_PERM);
    return;
  }
  if (get_int_elt(obj, CONTENTS, &list) == -1) {
    strcpy(buffer, ERR_DB);
    return;
  }

  if(list == -1) {
    strcpy(buffer, "{}");	/* fake out the list */
    return;
  }
  while(list != -1) {
    if ((list == player) || can_see(player, cause, list)) {
      snprintf(sbuff, sizeof(sbuff), "#%d", list);
      slist_add(sbuff, buffer, MEDBUFFSIZ);

      count++;
    }

    if (get_int_elt(list, NEXT, &list) == -1) {
      strcpy(buffer, ERR_DB);
      return;
    }
  }
  if(!count)
    strcpy(buffer, "{}");	/* fake out the list */
}

static PRIM(prim_exits)
{
  register int obj;
  int list;
  register int count = 0;
  char *ptr, sbuff[32];

  obj = strtonum(argv[1], &ptr);
  if(ptr == argv[1]) {
    strcpy(buffer, ERR_OBJ);
    return;
  }
  if(!exists_object(obj) || !has_exits(obj)){
    strcpy(buffer, ERR_ILLOBJ);
    return;
  }
  if(!controls(player, cause, obj) && !isVISUAL(obj) && !nearby(player, obj)
     &&	(cause != obj)){
    strcpy(buffer, ERR_PERM);
    return;
  }
  if (get_int_elt(obj, EXITS, &list) == -1) {
    strcpy(buffer, ERR_DB);
    return;
  }

  if(list == -1) {
    strcpy(buffer, "{}");	/* fake out the list */
    return;
  }
  while(list != -1) {
    if(isOBVIOUS(list) || controls(player, cause, list)) {
      snprintf(sbuff, sizeof(sbuff), "#%d", list);
      slist_add(sbuff, buffer, MEDBUFFSIZ);

      count++;
    }
    if(get_int_elt(list, NEXT, &list) == -1) {
      strcpy(buffer, ERR_DB);
      return;
    }
  }
  if(!count)
    strcpy(buffer, "{}");	/* fake out the list */
}

static PRIM(prim_rooms)
{
  register int obj;
  int list;
  register int count = 0;
  char *ptr, sbuff[32];

  obj = strtonum(argv[1], &ptr);
  if(ptr == argv[1]) {
    strcpy(buffer, ERR_OBJ);
    return;
  }
  if(!exists_object(obj) || !has_rooms(obj)){
    strcpy(buffer, ERR_ILLOBJ);
    return;
  }
  if(!isABODE(obj) && !controls(player, cause, obj)){
    strcpy(buffer, ERR_PERM);
    return;
  }
  if (get_int_elt(obj, ROOMS, &list) == -1) {
    strcpy(buffer, ERR_DB);
    return;
  }

  if(list == -1) {
    strcpy(buffer, "{}");	/* fake out the list */
    return;
  }
  while(list != -1) {
    if(isABODE(list) || controls(player, cause, list)) {
      snprintf(sbuff, sizeof(sbuff), "#%d", list);
      slist_add(sbuff, buffer, MEDBUFFSIZ);

      count++;
    }
    if(get_int_elt(list, NEXT, &list) == -1) {
      strcpy(buffer, ERR_DB);
      return;
    }
  }
  if(!count)
    strcpy(buffer, "{}");	/* fake out the list */
}

static PRIM(prim_owner)
{
  register int obj;
  int dat;
  char *ptr;

  obj = strtonum(argv[1], &ptr);
  if(ptr == argv[1]){
    strcpy(buffer, ERR_OBJ);
    return;
  }
  if(!exists_object(obj)) {
    strcpy(buffer, ERR_ILLOBJ);
    return;
  }
  if(get_int_elt(obj, OWNER, &dat) == -1){
    strcpy(buffer, ERR_DB);
    return;
  }
  sprintf(buffer, "#%d", dat);
}

static PRIM(prim_quota)
{
  register int obj;
  int dat;
  char *ptr;

  if (mudconf.enable_quota) {
    obj = strtonum(argv[1], &ptr);
    if(ptr == argv[1]) {
      strcpy(buffer, ERR_OBJ);
      return;
    }
    if(!exists_object(obj) || !has_quota(obj)) {
      strcpy(buffer, ERR_ILLOBJ);
      return;
    }
    if(!controls(player, cause, obj) && !isVISUAL(obj)) {
      strcpy(buffer, ERR_PERM);
      return;
    }
    if(get_int_elt(obj, QUOTA, &dat) == -1){
      strcpy(buffer, ERR_DB);
      return;
    }
    sprintf(buffer, "%d", dat);
  } else
    strcpy(buffer, "#-1 QUOTA NOT SUPPORTED");
}

static PRIM(prim_pennies)
{
  register int obj;
  int dat;
  char *ptr;

  if(mudconf.enable_money) {
    obj = strtonum(argv[1], &ptr);
    if(ptr == argv[1]) {
      strcpy(buffer, ERR_OBJ);
      return;
    }
    if(!exists_object(obj) || !has_pennies(obj)){
      strcpy(buffer, ERR_ILLOBJ);
      return;
    }
    if(!controls(player, cause, obj) && !isVISUAL(obj)) {
      strcpy(buffer, ERR_PERM);
      return;
    }
    if(get_int_elt(obj, PENNIES, &dat) == -1){
      strcpy(buffer, ERR_DB);
      return;
    }
    sprintf(buffer, "%d", dat);
  } else
    strcpy(buffer, "#-1 PENNIES NOT SUPPORTED");
}

static PRIM(prim_loc)
{
  register int obj;
  int dat;
  char *ptr;

  obj = strtonum(argv[1], &ptr);
  if(ptr == argv[1]){
    strcpy(buffer, ERR_OBJ);
    return;
  }
  if(!exists_object(obj)) {
    strcpy(buffer, ERR_ILLOBJ);
    return;
  }
  if(isHIDDEN(obj) && !controls(player, cause, obj) && !nearby(player, obj)) {
    strcpy(buffer, ERR_PERM);
    return;
  }
  if(get_int_elt(obj, LOC, &dat) == -1){
    strcpy(buffer, ERR_DB);
    return;
  }
  sprintf(buffer, "#%d", dat);
}

static PRIM(prim_rloc)
{
  register int i;
  int levels, obj, prev;
  char *ptr;

  obj = strtonum(argv[1], &ptr);
  if(ptr == argv[1]){
    strcpy(buffer, ERR_OBJ);
    return;
  }
  if(!exists_object(obj)) {
    strcpy(buffer, ERR_ILLOBJ);
    return;
  }
  levels = (int)strtol(argv[2], &ptr, 10);
  if(ptr == argv[2]){
    strcpy(buffer, ERR_NUM);
    return;
  }
  if(levels > mudconf.room_depth)	/* seems logical enough... */
    levels = mudconf.room_depth;

  prev = -1;
  if(!isHIDDEN(obj) || controls(player, cause, obj) || nearby(player, obj)){
    for(i = 0; i < levels; i++) {
      if(!exists_object(obj) || isROOM(obj))
	break;
      prev = obj;
      if(get_int_elt(prev, LOC, &obj) == -1){
	strcpy(buffer, ERR_DB);
	return;
      }
    }
  }
  sprintf(buffer, "#%d", prev);
}

static PRIM(prim_controls)
{
  int obj1, obj2;
  char *ptr;

  obj1 = strtonum(argv[1], &ptr);
  if(ptr == argv[1]) {
    strcpy(buffer, ERR_OBJ);
    return;
  }
  obj2 = strtonum(argv[2], &ptr);
  if(ptr == argv[2]) {
    strcpy(buffer, ERR_OBJ);
    return;
  }
  if(!exists_object(obj1) || !exists_object(obj2)){
    strcpy(buffer, ERR_ILLOBJ);
    return;
  }

  sprintf(buffer, "%d", controls(obj1, cause, obj2));
}

static PRIM(prim_dropto)
{
  register int obj;
  int dropto;
  char *ptr;

  obj = strtonum(argv[1], &ptr);
  if(ptr == argv[1]) {
    strcpy(buffer, ERR_OBJ);
    return;
  }
  if(!exists_object(obj) || !has_dropto(obj)) {
    strcpy(buffer, ERR_ILLOBJ);
    return;
  }
  if(!controls(player, cause, obj) && !isVISUAL(obj)) {
    strcpy(buffer, ERR_PERM);
    return;
  }
  if(get_int_elt(obj, DROPTO, &dropto) == -1) {
    strcpy(buffer, ERR_DB);
    return;
  }
  sprintf(buffer, "#%d", dropto);
}

static PRIM(prim_home)
{
  register int obj;
  int home;
  char *ptr;

  obj = strtonum(argv[1], &ptr);
  if(ptr == argv[1]) {
    strcpy(buffer, ERR_OBJ);
    return;
  }
  if(!exists_object(obj) || !has_home(obj)) {
    strcpy(buffer, ERR_ILLOBJ);
    return;
  }
  if(!controls(player, cause, obj) && !isVISUAL(obj)) {
    strcpy(buffer, ERR_PERM);
    return;
  }
  if(get_int_elt(obj, HOME, &home) == -1) {
    strcpy(buffer, ERR_DB);
    return;
  }
  sprintf(buffer, "#%d", home);
}

static PRIM(prim_dests)
{
  register int obj, indx;
  register int count = 0;
  int *dests;
  char *ptr, sbuff[32];

  obj = strtonum(argv[1], &ptr);
  if(ptr == argv[1]){
    strcpy(buffer, ERR_OBJ);
    return;
  }
  if(!exists_object(obj) || !has_dests(obj)) {
    strcpy(buffer, ERR_ILLOBJ);
    return;
  }
  if(!controls(player, cause, obj) && !isVISUAL(obj)) {
    strcpy(buffer, ERR_PERM);
    return;
  }
  if(get_array_elt(obj, DESTS, &dests) == -1){
    strcpy(buffer, ERR_DB);
    return;
  }

  if (dests != (int *)NULL) {
    for(indx = 1; indx <= dests[0]; indx++) {
      snprintf(sbuff, sizeof(sbuff), "#%d", dests[indx]);
      slist_add(sbuff, buffer, MEDBUFFSIZ);

      count++;
    }
  }
  if(!count)
    strcpy(buffer, "{}");	/* fake out the list */
}

static PRIM(prim_timestamp)
{
  register int obj;
  int dat;
  char *ptr;

  obj = strtonum(argv[1], &ptr);
  if(ptr == argv[1]){
    strcpy(buffer, ERR_OBJ);
    return;
  }
  if(!exists_object(obj)){
    strcpy(buffer, ERR_ILLOBJ);
    return;
  }
  if(!controls(player, cause, obj) && !isVISUAL(obj)) {
    strcpy(buffer, ERR_PERM);
    return;
  }
  if(get_int_elt(obj, TIMESTAMP, &dat) == -1){
    strcpy(buffer, ERR_DB);
    return;
  }
  sprintf(buffer, "%d", dat);
}

static PRIM(prim_createstamp)
{
  register int obj;
  int dat;
  char *ptr;

  obj = strtonum(argv[1], &ptr);
  if(ptr == argv[1]){
    strcpy(buffer, ERR_OBJ);
    return;
  }
  if(!exists_object(obj)){
    strcpy(buffer, ERR_ILLOBJ);
    return;
  }
  if(!controls(player, cause, obj) && !isVISUAL(obj)) {
    strcpy(buffer, ERR_PERM);
    return;
  }
  if(get_int_elt(obj, CREATESTAMP, &dat) == -1){
    strcpy(buffer, ERR_DB);
    return;
  }
  sprintf(buffer, "%d", dat);
}

static PRIM(prim_parent)
{
  register int obj;
  int dat;
  char *ptr;

  obj = strtonum(argv[1], &ptr);
  if(ptr == argv[1]){
    strcpy(buffer, ERR_OBJ);
    return;
  }
  if(!exists_object(obj)){
    strcpy(buffer, ERR_ILLOBJ);
    return;
  }
  if(!controls(player, cause, obj) && !isVISUAL(obj)) {
    strcpy(buffer, ERR_PERM);
    return;
  }
  if(get_int_elt(obj, PARENT, &dat) == -1){
    strcpy(buffer, ERR_DB);
    return;
  }
  sprintf(buffer, "#%d", dat);
}

static PRIM(prim_uses)
{
  register int obj;
  int dat;
  char *ptr;

  obj = strtonum(argv[1], &ptr);
  if(ptr == argv[1]){
    strcpy(buffer, ERR_OBJ);
    return;
  }
  if(!exists_object(obj)){
    strcpy(buffer, ERR_ILLOBJ);
    return;
  }
  if(!controls(player, cause, obj) && !isVISUAL(obj)) {
    strcpy(buffer, ERR_PERM);
    return;
  }
  if(get_int_elt(obj, USES, &dat) == -1){
    strcpy(buffer, ERR_DB);
    return;
  }
  sprintf(buffer, "%d", dat);
}

static PRIM(prim_name)
{
  register int obj;
  char *name, *ptr;

  obj = strtonum(argv[1], &ptr);
  if(ptr == argv[1]){
    strcpy(buffer, ERR_OBJ);
    return;
  }
  if(!exists_object(obj)){
    strcpy(buffer, ERR_ILLOBJ);
    return;
  }
  if(get_str_elt(obj, NAME, &name) == -1) {
    strcpy(buffer, ERR_DB);
    return;
  }
  strcpy(buffer, (name == (char *)NULL) ? "" : name);
}

static PRIM(prim_flags)
{
  register int obj;
  int flags[FLAGS_LEN];
  char *ptr;

  obj = strtonum(argv[1], &ptr);
  if(ptr == argv[1]){
    strcpy(buffer, ERR_OBJ);
    return;
  }
  if(!exists_object(obj)) {
    strcpy(buffer, ERR_ILLOBJ);
    return;
  }

  if(get_flags_elt(obj, FLAGS, flags) == -1) {
    strcpy(buffer, ERR_DB);
    return;
  }
  strcpy(buffer, display_objflags(flags, controls(player, cause, obj)));
}

static PRIM(prim_type)
{
  register int obj;
  char *ptr;

  obj = strtonum(argv[1], &ptr);
  if(ptr == argv[1]) {
    strcpy(buffer, ERR_OBJ);
    return;
  }
  if(!exists_object(obj)) {
    strcpy(buffer, ERR_ILLOBJ);
    return;
  }

  switch(Typeof(obj)) {
  case TYP_PLAYER:
    strcpy(buffer, "Player");
    break;
  case TYP_ROOM:
    strcpy(buffer, "Room");
    break;
  case TYP_EXIT:
    strcpy(buffer, "Exit");
    break;
  case TYP_THING:
    strcpy(buffer, "Thing");
    break;
  default:
    strcpy(buffer, ERR_ILLOBJ);
  }
}

static PRIM(prim_rand)
{
  register int num;
  char *ptr;

  num = (int)strtol(argv[1], &ptr, 10);
  if(ptr == argv[1]) {
    strcpy(buffer, ERR_NUM);
  } else {
    if(num < 0)
      strcpy(buffer, "0");
    else
      sprintf(buffer, "%ld", random() % num);
  }
}

static PRIM(prim_abs)
{
  double num;
  char *ptr;

  num = strtod(argv[1], &ptr);
  if(ptr != argv[1]) {
    if (num == 0.0) {
      strcpy(buffer, "0.0");
    } else if (num < 0.0) {
      fval(buffer, -num);
    } else {
      fval(buffer, num);
    }
  } else
    strcpy(buffer, ERR_NUM);
}

static PRIM(prim_sqrt)
{
  double num;
  char *ptr;

  num = strtod(argv[1], &ptr);
  if(ptr != argv[1]) {
    if (num < 0.0) {
      strcpy(buffer, "#-1 SQUARE ROOT OF NEGATIVE");
    } else if(num == 0.0) {
      strcpy(buffer, "0");
    } else {
      fval(buffer, sqrt(num));
    }
  } else
    strcpy(buffer, ERR_NUM);
}

static PRIM(prim_add)
{
  double num = 0.0;
  char *ptr;
  register int i, got_one;

  for(i = 1,got_one = 0; i < argc; i++) {
    num += strtod(argv[i], &ptr);
    if(ptr == argv[i]) {
      strcpy(buffer, ERR_NUM);
      return;
    }
    if(i > 1)
      got_one++;
  }
  if(!got_one)
    strcpy(buffer, "#-1 TOO FEW ARGUMENTS");
  else
    fval(buffer, num);
}

static PRIM(prim_sub)
{
  double num1, num2;
  char *ptr;

  num1 = strtod(argv[1], &ptr);
  if(ptr == argv[1]) {
    strcpy(buffer, ERR_NUM);
    return;
  }
  num2 = strtod(argv[2], &ptr);
  if(ptr == argv[2]) {
    strcpy(buffer, ERR_NUM);
    return;
  }
  fval(buffer, num1 - num2);
}

static PRIM(prim_mul)
{
  double num, val;
  char *ptr;
  register int i, got_one;

  for(i = 1,got_one = 0,num = 0.0; i < argc; i++) {
    val = strtod(argv[i], &ptr);
    if(ptr == argv[i]) {
      strcpy(buffer, ERR_NUM);
      return;
    }
    if(i > 1) {
      num *= val;
      got_one++;
    } else
      num = val;
  }
  if(!got_one)
    strcpy(buffer, "#-1 TOO FEW ARGUMENTS");
  else
    fval(buffer, num);
}

static PRIM(prim_floor)
{
  double num;
  char *ptr;

  num = strtod(argv[1], &ptr);
  if(ptr == argv[1])
    strcpy(buffer, ERR_NUM);
  else
    sprintf(buffer, "%.0f", floor(num));
}

static PRIM(prim_ceil)
{
  double num;
  char *ptr;

  num = strtod(argv[1], &ptr);
  if(ptr == argv[1])
    strcpy(buffer, ERR_NUM);
  else
    sprintf(buffer, "%.0f", ceil(num));
}

static PRIM(prim_round)
{
  register const char *fstr;
  double num;
  int digits;
  char *ptr;

  digits = (int)strtol(argv[2], &ptr, 10);
  if(ptr == argv[2]){
    strcpy(buffer, ERR_NUM);
    return;
  }

  switch (digits) {
  case 1:         fstr = "%.1f"; break;
  case 2:         fstr = "%.2f"; break;
  case 3:         fstr = "%.3f"; break;
  case 4:         fstr = "%.4f"; break;
  case 5:         fstr = "%.5f"; break;
  case 6:         fstr = "%.6f"; break;
  default:        fstr = "%.0f"; break;
  }
  num = strtod(argv[1], &ptr);
  if(ptr == argv[1]){
    strcpy(buffer, ERR_NUM);
    return;
  }
  sprintf(buffer, fstr, num);

  if (!strcmp(buffer, "-0")) {
    strcpy(buffer, "0");
  }
}

static PRIM(prim_trunc)
{
  sprintf(buffer, "%d", atoi(argv[1]));
}

static PRIM(prim_div)
{
  double val1, val2;
  char *ptr;

  val1 = strtod(argv[1], &ptr);
  if(ptr == argv[1]) {
    strcpy(buffer, ERR_NUM);
    return;
  }
  val2 = strtod(argv[2], &ptr);
  if(ptr == argv[2]) {
    strcpy(buffer, ERR_NUM);
    return;
  }
  if(val2 == 0) {
    strcpy(buffer, ERR_DIVZERO);
  } else {
    fval(buffer, (val1 / val2));
  }
}

static PRIM(prim_mod)
{
#ifdef HAVE_FMOD
  double val1, val2;
  char *ptr;

  val1 = strtod(argv[1], &ptr);
  if(ptr == argv[1]){
    strcpy(buffer, ERR_NUM);
    return;
  }
  val2 = strtod(argv[2], &ptr);
  if(ptr == argv[2]){
    strcpy(buffer, ERR_NUM);
    return;
  }
  if(val2 == 0.0)
    val2 = 1;
  fval(buffer, fmod(val1, val2));
#else
  register int num;

  if((num = atoi(argv[2])) == 0)
    num = 1;
  sprintf(buffer, "%d", atoi(argv[1]) % num);
#endif			/* HAVE_FMOD */
}

static PRIM(prim_pi)
{
  strcpy(buffer, "3.141592654");
}

static PRIM(prim_e)
{
  strcpy(buffer, "2.718281828");
}

static PRIM(prim_sin)
{
  double num;
  char *ptr;

  num = strtod(argv[1], &ptr);
  if(ptr == argv[1]) {
    strcpy(buffer, ERR_NUM);
  } else {
    fval(buffer, sin(num));
  }
}

static PRIM(prim_cos)
{
  double num;
  char *ptr;

  num = strtod(argv[1], &ptr);
  if(ptr == argv[1]) {
    strcpy(buffer, ERR_NUM);
  } else {
    fval(buffer, cos(num));
  }
}

static PRIM(prim_tan)
{
  double num;
  char *ptr;

  num = strtod(argv[1], &ptr);
  if(ptr == argv[1]) {
    strcpy(buffer, ERR_NUM);
  } else {
    fval(buffer, tan(num));
  }
}

static PRIM(prim_exp)
{
  double num;
  char *ptr;

  num = strtod(argv[1], &ptr);
  if(ptr == argv[1]) {
    strcpy(buffer, ERR_NUM);
  } else {
    fval(buffer, exp(num));
  }
}

static PRIM(prim_power)
{
  double arg1, arg2;
  char *ptr;

  arg1 = strtod(argv[1], &ptr);
  if(ptr == argv[1]) {
    strcpy(buffer, ERR_NUM);
    return;
  }
  arg2 = strtod(argv[2], &ptr);
  if(ptr == argv[2]) {
    strcpy(buffer, ERR_NUM);
    return;
  }
  if (arg1 < 0)
    strcpy(buffer, "#-1 POWER OF NEGATIVE");
  else
    fval(buffer, pow(arg1, arg2));
}

static PRIM(prim_ln)
{
  double val;
  char *ptr;

  val = strtod(argv[1], &ptr);
  if(ptr == argv[1]) {
    strcpy(buffer, ERR_NUM);
    return;
  }
  if(val > 0)
    fval(buffer, log(val));
  else
    strcpy(buffer, "#-1 LN OF NEGATIVE OR ZERO");
}

static PRIM(prim_log)
{
  double val;
  char *ptr;

  val = strtod(argv[1], &ptr);
  if(ptr == argv[1]) {
    strcpy(buffer, ERR_NUM);
    return;
  }
  if(val > 0)
    fval(buffer, log10(val));
  else
    strcpy(buffer, "#-1 LOG OF NEGATIVE OR ZERO");
}

static PRIM(prim_asin)
{
  double val;
  char *ptr;

  val = strtod(argv[1], &ptr);
  if(ptr == argv[1]) {
    strcpy(buffer, ERR_NUM);
    return;
  }
  if((val < -1) || (val > 1))
    strcpy(buffer, "#-1 ASIN ARGUMENT OUT OF RANGE");
  else
    fval(buffer, asin(val));
}

static PRIM(prim_acos)
{
  double val;
  char *ptr;

  val = strtod(argv[1], &ptr);
  if(ptr == argv[1]) {
    strcpy(buffer, ERR_NUM);
    return;
  }
  if((val < -1) || (val > 1))
    strcpy(buffer, "#-1 ACOS ARGUMENT OUT OF RANGE");
  else
    fval(buffer, acos(val));
}

static PRIM(prim_atan)
{
  double val;
  char *ptr;

  val = strtod(argv[1], &ptr);
  if(ptr == argv[1])
    strcpy(buffer, ERR_NUM);
  else
    fval(buffer, atan(val));
}

static PRIM(prim_min)
{
  register int i;
  int ret, num;
  char *ptr;

  for(i = 1,ret = 0; i < argc; i++) {
    num = (int)strtol(argv[i], &ptr, 10);
    if(ptr == argv[i]) {
      strcpy(buffer, ERR_NUM);
      return;
    }

    if((num < ret) || (i == 1))
      ret = num;
  }
  sprintf(buffer, "%d", ret);
}

static PRIM(prim_max)
{
  register int i;
  int ret, num;
  char *ptr;

  for(i = 1,ret = 0; i < argc; i++) {
    num = (int)strtol(argv[i], &ptr, 10);
    if(ptr == argv[i]) {
      strcpy(buffer, ERR_NUM);
      return;
    }

    if((num > ret) || (i == 1))
      ret = num;
  }
  sprintf(buffer, "%d", ret);
}

static PRIM(prim_expr)
{
  long ret;
  int error;

  ret = expr_parse(argv[1], &error);
  if(error)
    strcpy(buffer, "#-1 BAD EXPRESSION SYNTAX");
  else
    sprintf(buffer, "%ld", ret);
}

static PRIM(prim_if)
{
  if((argc < 3) || (argc > 5) || ((argc == 5)
      				  && strcasecmp(argv[3], "else"))) {
    strcpy(buffer, "#-1 WRONG NUMBER OF ARGUMENTS");
    return;
  }
  if (atoi(argv[1])) {
    strcpy(buffer, argv[2]);
  } else if(argc == 4){
    strcpy(buffer, argv[3]);
  } else if(argc == 5){
    strcpy(buffer, argv[4]);
  } else
    buffer[0] = '\0';
}

static PRIM(prim_setvar)
{
  int owner;
  register char *val;

  if((argc < 2) || (argc > 3)) {
    strcpy(buffer, "#-1 WRONG NUMBER OF ARGUMENTS");
    return;
  }

  if(get_int_elt(player, OWNER, &owner) == -1) {
    strcpy(buffer, ERR_DB);
    return;
  }

  if(argc == 3) {
    var_set(owner, argv[1], argv[2]);
    strcpy(buffer, argv[2]);
  } else {
    val = var_get(owner, argv[1]);
    if(val == (char *)NULL) {
      strcpy(buffer, ERR_NOVAR);
      return;
    }
    strcpy(buffer, val);
    var_delete(owner, argv[1]);
  }
}

static PRIM(prim_getvar)
{
  int owner;
  register char *val;

  if(get_int_elt(player, OWNER, &owner) == -1) {
    strcpy(buffer, ERR_DB);
    return;
  }

  val = var_get(owner, argv[1]);
  if(val != (char *)NULL) {
    strcpy(buffer, val);
  } else
    buffer[0] = '\0';
}

/* time primitives */

static PRIM(prim_time)
{
  sprintf(buffer, "%ld", mudstat.now);
}

static PRIM(prim_ctime)
{
  time_t when;
  char *ptr;

  when = (time_t)strtol(argv[1], &ptr, 10);
  if((when < 0) || (ptr == argv[1]))
    strcpy(buffer, "#-1 ILLEGAL TIME VALUE");
  else
    strftime(buffer, MEDBUFFSIZ, "%a %b %e %H:%M:%S %Z %Y", localtime(&when));
}

static PRIM(prim_cnvtime)
{
  extern char ty_getdate_err[];
  register time_t ret;

  if((ret = get_date(argv[1], mudstat.now)) == -1)
    snprintf(buffer, blen, "#-1 %s", ty_getdate_err);
  else
    snprintf(buffer, blen, "%ld", ret);
}

/* string/list primitives */

/* format is loosely based on the public domain vsprintf(). */
static PRIM(prim_format)
{
  register char *dp = buffer;
  register char *format;
  register char c;
  register char *tp, *sa;
  char tempfmt[64], tempbuf[128], *sptr;
#if (SIZEOF_INT != SIZEOF_LONG)
  int longflag;
#endif
  int outspace = 0, curarg = 2;
  int nbase;
  const char *formaterr = "#-1 FORMAT ARGUMENT TYPE ERROR";

  format = argv[1];

  tempfmt[0] = '%';
  while((c = *format++) && !outspace) {
    if(c == '%') {
      tp = &tempfmt[1];
#if (SIZEOF_INT != SIZEOF_LONG)
      longflag = 0;
#endif

continue_format:
      nbase = 10;

      switch((c = *format++)) {
        /* String. */
	case 'c':
        case 's': {
	  int padding;
	  register char *ptr, *buff;

	  *tp++ = c;
	  *tp = '\0';

	  /* Scan for padding. */
	  for(ptr = tempfmt; *ptr && !isdigit(*ptr); ptr++);
	  if(isdigit(*ptr)) {
	    padding = (int)strtol(ptr, NULL, 10);
	    if(padding < 0)
	      padding = abs(padding);
	  } else
	    padding = 0;

	  sa = argv[curarg++];

	  if(padding) {
	    padding = (padding > strlen(sa)) ? padding : strlen(sa);

	    /* Allocate a buffer to hold the return. */
	    buff = (char *)alloca(padding+1);
	    if(buff == (char *)NULL) {
	      strcpy(buffer, "#-1 STACK ALLOCATION FAILED");
	      return;
	    }

	    /* Call sprintf() in order to get padding right. */
	    sprintf(buff, tempfmt, sa);

	    if(strlen(buff) >= (blen - (dp - buffer))) {
	      buff[blen - ((dp - buffer)+1)] = '\0';
	      outspace++;
	    }
	    strcpy(dp, buff);
	    dp += strlen(buff);
	  } else {
	    ptr = sa;
	    while(*ptr && ((dp - buffer) < (blen-1)))
	      *dp++ = *ptr++;
	    /* We don't terminate, but we do check for overflow. */
	    if((dp - buffer) >= blen)
	      outspace++;
	  }
	} break;
	/* Unsigned values. */
	case 'p':
	case 'x':
	case 'X':
	  nbase = 16;
	case 'o':
	  nbase = 8;
	case 'u': {
	  *tp++ = c;
	  *tp = '\0';

	  sa = argv[curarg++];

#if (SIZEOF_INT != SIZEOF_LONG)
	  if(longflag) {
	    unsigned long val;

	    val = strtoul(sa, &sptr, nbase);
	    if(sptr == sa) {
	      strcpy(buffer, formaterr);
	      return;
	    }
	    sprintf(tempbuf, tempfmt, val);
	  } else
#endif
	  {
	    unsigned int val;

	    val = (int)strtoul(sa, &sptr, nbase);
	    if(sptr == sa) {
	      strcpy(buffer, formaterr);
	      return;
	    }
	    sprintf(tempbuf, tempfmt, val);
	  }
	  if(strlen(tempbuf) >= (blen - (dp - buffer))) {
	    tempbuf[blen - ((dp - buffer)+1)] = '\0';
	    outspace++;
	  }
	  strcpy(dp, tempbuf);
	  dp += strlen(tempbuf);
	} break;
	/* Signed values. */
	case 'd': {
	  *tp++ = c;
	  *tp = '\0';

	  sa = argv[curarg++];

#if (SIZEOF_INT != SIZEOF_LONG)
	  if(longflag) {
	    long val;

	    val = strtol(sa, &sptr, 10);
	    if(sptr == sa) {
	      strcpy(buffer, formaterr);
	      return;
	    }
	    sprintf(tempbuf, tempfmt, val);
	  } else
#endif
	  {
	    int val;

	    val = strtol(sa, &sptr, 10);
	    if(sptr == sa) {
	      strcpy(buffer, formaterr);
	      return;
	    }
	    sprintf(tempbuf, tempfmt, val);
	  }
	  if(strlen(tempbuf) >= (blen - (dp - buffer))) {
	    tempbuf[blen - ((dp - buffer)+1)] = '\0';
	    outspace++;
	  }
	  strcpy(dp, tempbuf);
	  dp += strlen(tempbuf);
	} break;
	case 'f':
	case 'e':
	case 'E':
	case 'g':
	case 'G': {
	  double val;

	  *tp++ = c;
	  *tp = '\0';

	  sa = argv[curarg++];

	  val = strtod(sa, &sptr);
	  if(sa == sptr) {
	    strcpy(buffer, formaterr);
	    return;
	  }

	  sprintf(tempbuf, tempfmt, val);
	  if(strlen(tempbuf) >= (blen - (dp - buffer))) {
	    tempbuf[blen - ((dp - buffer)+1)] = '\0';
	    outspace++;
	  }
	  strcpy(dp, tempbuf);
	  dp += strlen(tempbuf);
	} break;
	case '-':
	case '+':
	case '0':
	case '1':
	case '2':
	case '3':
	case '4':
	case '5':
	case '6':
	case '7':
	case '8':
	case '9':
	case '.':
	case ' ':
	case '#':
	case 'h':
	  *tp++ = c;
	  goto continue_format;
	case 'l':
#if (SIZEOF_INT != SIZEOF_LONG)
	  longflag = 1;
	  *tp++ = c;
#endif
	  goto continue_format;
	case '*': {
	  register char *ptr;

	  sa = argv[curarg++];

	  for(ptr = sa; *ptr && isdigit(*ptr); ptr++);
	  if(*ptr) {
	    strcpy(buffer, formaterr);
	    return;
	  }
	  strcpy(tp, sa);
	  tp += strlen(sa);
	  goto continue_format;
	} break;
	case 'n':
	  strcpy(buffer, "#-1 FORMAT TYPE 'n' NOT SUPPORTED");
	  return;
	case '%':
	default:
	  if((blen - (dp - buffer)) > 1)
	    *dp++ = c;
	  else
	    outspace++;
	  break;
      }
    } else {
      if((blen - (dp - buffer)) > 1)
	*dp++ = c;
      else
	outspace++;
    }
  }
  *dp = '\0';
}

static PRIM(prim_mid)
{
  register char *str;
  char *ptr;
  int pos, len;

  str = argv[1];
  pos = (int)strtol(argv[2], &ptr, 10);
  if(ptr == argv[2]) {
    strcpy(buffer, ERR_NUM);
    return;
  }
  len = (int)strtol(argv[3], &ptr, 10);
  if(ptr == argv[3]) {
    strcpy(buffer, ERR_NUM);
    return;
  }

  if((pos < 0) || (len < 0) || (pos > strlen(str))) {
    strcpy(buffer, "#-1 OUT OF RANGE");
    return;
  }
  ty_strncpy(buffer, &str[pos], len);
}

static PRIM(prim_first)
{
  register char sep = ' ';
  register char *ptr, *bptr;

  if(argc == 3) {
    sep = (argv[2])[0];		/* we only care about the fist char. */
  } else if(argc != 2) {
    strcpy(buffer, ERR_TOOARGS);
    return;
  }

  ptr = argv[1];
  while((*ptr != '\0') && (*ptr == sep))	/* trim leading sep */
    ptr++;

  bptr = buffer;
  while((*ptr != '\0') && (*ptr != sep))
    *bptr++ = *ptr++;
  *bptr = '\0';
}

static PRIM(prim_rest)
{
  register char sep = ' ';
  register char *ptr, *bptr;

  if(argc == 3) {
    sep = (argv[2])[0];		/* we only care about the first char. */
  } else if(argc != 2) {
    strcpy(buffer, ERR_TOOARGS);
    return;
  }

  ptr = argv[1];
  while((*ptr != '\0') && (*ptr == sep))	/* trim leading sep */
    ptr++;
  while((*ptr != '\0') && (*ptr != sep))	/* skip first word */
    ptr++;
  while((*ptr != '\0') && (*ptr == sep))	/* skip sep */
    ptr++;

  /* copy the rest */
  bptr = buffer;
  while(*ptr != '\0')
    *bptr++ = *ptr++;
  *bptr = '\0';
}

static PRIM(prim_last)
{
  register char sep = ' ';
  register char *ptr, *bptr;

  if(argc == 3) {
    sep = (argv[2])[0];		/* we only care about the first char. */
  } else if(argc != 2) {
    strcpy(buffer, ERR_TOOARGS);
    return;
  }

  ptr = argv[1];
  while(*ptr != '\0')
    ptr++;
  while((ptr > argv[1]) && (*ptr == sep))
    ptr--;
  while((ptr > argv[1]) && (*ptr != sep))
    ptr--;
  
  bptr = buffer;
  while((*ptr != '\0') && (*ptr != sep))
    *bptr++ = *ptr++;
  *bptr = '\0';
}

static PRIM(prim_words)
{
  register char sep= ' ';
  register char *ptr;
  int count = 0;

  if(argc == 3) {
    sep = (argv[2])[0];		/* we only care about the first char. */
  } else if(argc != 2) {
    strcpy(buffer, ERR_TOOARGS);
    return;
  }

  ptr = argv[1];
  while((*ptr != '\0') && (*ptr == sep))	/* trim leading sep */
    ptr++;

  while(*ptr != '\0') {
    if(*ptr == sep) {				/* update count */
      while((*ptr != '\0') && (*ptr == sep))
	ptr++;
      if(*ptr != '\0')
	count++;
    } else
      ptr++;
  }
  sprintf(buffer, "%d", count);
}

static PRIM(prim_strlen)
{
  sprintf(buffer, "%ld", strlen(argv[1]));
}

static PRIM(prim_strcmp)
{
  sprintf(buffer, "%d", !strcasecmp(argv[1], argv[2]));
}

static PRIM(prim_strmatch)
{
  sprintf(buffer, "%d", quick_wild(argv[1], argv[2]));
}

static PRIM(prim_strprefix)
{
  sprintf(buffer, "%d", !strncasecmp(argv[1], argv[2], strlen(argv[1])));
}

static PRIM(prim_strncmp)
{
  int len;
  char *ptr;

  len = (int)strtol(argv[3], &ptr, 10);
  if(ptr == argv[3]) {
    strcpy(buffer, ERR_NUM);
    return;
  }
  sprintf(buffer, "%d", !strncasecmp(argv[1], argv[2], len));
}

static PRIM(prim_wrdmatch)
{
  register char sep = ' ';
  register char *str, *ptr;
  int count = 1;

  if(argc == 4) {
    sep = (argv[3])[0];		/* we only care about the first char. */
  } else if(argc != 3) {
    strcpy(buffer, ERR_TOOARGS);
    return;
  }

  str = argv[2];
  while((*str != '\0') && (*str == sep))
    str++;
  do {
    /* find the next word */
    for(ptr = str; (*ptr != '\0') && (*ptr != sep); ptr++);
    if(*ptr != '\0') {
      *ptr++ = '\0';
      while((*ptr != '\0') && (*ptr == sep))
	ptr++;
    }

    if(quick_wild(argv[1], str)) {
      sprintf(buffer, "%d", count);
      return;
    }
    str = ptr;
    count++;
  } while(*str != '\0');
  strcpy(buffer, "0");
}

static PRIM(prim_strcat)
{
  register int i;

  buffer[0] = '\0';
  for(i = 1; i < argc; i++) {
    if(i > 1)
      strcat(buffer, " ");
    strcat(buffer, argv[i]);
  }
}

static PRIM(prim_crypt)
{
  strcpy(buffer, sha_crypt(argv[1]));
}

static PRIM(prim_upcase)
{
  register int i, j, k;
  register char *ptr;

  k = 0;
  for(i = 1; i < argc; i++) {
    if(i > 1)
      buffer[k++] = ' ';
    ptr = argv[i];
    for(j = 0; ptr[j] != '\0'; j++) {
      buffer[k++] = to_upper(ptr[j]);
    }
  }
  buffer[k] = '\0';
}

static PRIM(prim_lowcase)
{
  register int i, j, k;
  register char *ptr;

  k = 0;
  for(i = 1; i < argc; i++) {
    if(i > 1)
      buffer[k++] = ' ';
    ptr = argv[i];
    for(j = 0; ptr[j] != '\0'; j++) {
      buffer[k++] = to_lower(ptr[j]);
    }
  }
  buffer[k] = '\0';
}

static PRIM(prim_swapcase)
{
  register int i, j, k;
  register char *ptr;

  k = 0;
  for(i = 1; i < argc; i++) {
    if(i > 1)
      buffer[k++] = ' ';
    ptr = argv[i];
    for(j = 0; ptr[j] != '\0'; j++) {
      buffer[k++] = (isupper(ptr[j]) ? to_lower(ptr[j]) : to_upper(ptr[j]));
    }
  }
  buffer[k] = '\0';
}

static Prim PTable[] = {
  /* database primitives */
  {"getattr", prim_getattr, 2, 0, 0},
  {"getlock", prim_getlock, 2, 0, 0},
  {"contents", prim_contents, 1, 0, 0},
  {"exits", prim_exits, 1, 0, 0},
  {"rooms", prim_rooms, 1, 0, 0},
  {"owner", prim_owner, 1, 0, 0},
  {"quota", prim_quota, 1, 0, 0},
  {"pennies", prim_pennies, 1, 0, 0},
  {"loc", prim_loc, 1, 0, 0},
  {"rloc", prim_rloc, 2, 0, 0},
  {"controls", prim_controls, 2, 0, 0},
  {"home", prim_home, 1, 0, 0},
  {"dropto", prim_dropto, 1, 0, 0},
  {"dests", prim_dests, 1, 0, 0},
  {"timestamp", prim_timestamp, 1, 0, 0},
  {"createstamp", prim_createstamp, 1, 0, 0},
  {"parent", prim_parent, 1, 0, 0},
  {"uses", prim_uses, 1, 0, 0},
  {"name", prim_name, 1, 0, 0},
  {"flags", prim_flags, 1, 0, 0},
  {"type", prim_type, 1, 0, 0},
  /* math primitives */
  {"rand", prim_rand, 1, 0, 0},
  {"abs", prim_abs, 1, 0, 0},
  {"sqrt", prim_sqrt, 1, 0, 0},
  {"add", prim_add, -1, PRIM_VARARGS, 0},
  {"sub", prim_sub, 2, 0, 0},
  {"mul", prim_mul, -1, PRIM_VARARGS, 0},
  {"floor", prim_floor, 1, 0, 0},
  {"ceil", prim_ceil, 1, 0, 0},
  {"round", prim_round, 2, 0, 0},
  {"trunc", prim_trunc, 1, 0, 0},
  {"div", prim_div, 2, 0, 0},
  {"mod", prim_mod, 2, 0, 0},
  {"pi", prim_pi, 0, 0, 0},
  {"e", prim_e, 0, 0, 0},
  {"sin", prim_sin, 1, 0, 0},
  {"cos", prim_cos, 1, 0, 0},
  {"tan", prim_tan, 1, 0, 0},
  {"exp", prim_exp, 1, 0, 0},
  {"power", prim_power, 2, 0, 0},
  {"ln", prim_ln, 1, 0, 0},
  {"log", prim_log, 1, 0, 0},
  {"asin", prim_asin, 1, 0, 0},
  {"acos", prim_acos, 1, 0, 0},
  {"atan", prim_atan, 1, 0, 0},
  {"min", prim_min, 2, PRIM_VARARGS, 0},
  {"max", prim_max, 2, PRIM_VARARGS, 0},
  /* conditionals */
  {"expr", prim_expr, 1, 0, 0},
  {"if", prim_if, -1, PRIM_VARARGS, 0},
  /* variables */
  {"setvar", prim_setvar, -1, PRIM_VARARGS, 0},
  {"getvar", prim_getvar, 1, 0, 0},
  /* time prims */
  {"time", prim_time, 0, 0, 0},
  {"ctime", prim_ctime, 1, 0, 0},
  {"cnvtime", prim_cnvtime, 1, 0, 0},
  /* strings */
  {"format", prim_format, 1, PRIM_VARARGS, 0},
  {"mid", prim_mid, 3, 0, 0},
  {"first", prim_first, 1, PRIM_VARARGS, 0},
  {"rest", prim_rest, 1, PRIM_VARARGS, 0},
  {"last", prim_last, 1, PRIM_VARARGS, 0},
  {"words", prim_words, 1, PRIM_VARARGS, 0},
  {"strlen", prim_strlen, 1, 0, 0},
  {"strcmp", prim_strcmp, 2, 0, 0},
  {"strmatch", prim_strmatch, 2, 0, 0},
  {"strprefix", prim_strprefix, 2, 0, 0},
  {"strncmp", prim_strncmp, 3, 0, 0},
  {"wrdmatch", prim_wrdmatch, 2, PRIM_VARARGS, 0},
  {"strcat", prim_strcat, 1, PRIM_VARARGS, 0},
  {"crypt", prim_crypt, 1, 0, 0},
  {"upcase", prim_upcase, 1, PRIM_VARARGS, 0},
  {"lowcase", prim_lowcase, 1, PRIM_VARARGS, 0},
  {"swapcase", prim_swapcase, 1, PRIM_VARARGS, 0},
  {(char *)NULL, NULL, 0, 0, 0}
};

void prims_init()
{
  register int i = 0;
  Hash_Entry *entry;
  int new;

  Hash_InitTable(&Prim_Table, sizeof(PTable)/sizeof(Prim), HASH_STRCASE_KEYS);
  while(PTable[i].name != (char *)NULL) {
    entry = Hash_CreateEntry(&Prim_Table, (char *)PTable[i].name, &new);
    Hash_SetValue(entry, (char *)&PTable[i]);

    i++;
  }
}