#ifndef lint
static char *rcsid =
   "$Header: lamr.c 1.2 89/09/21 $";
#endif

/*					-[Sat Jan 29 13:09:59 1983 by jkf]-
 * 	lamr.c				$Locker:  $
 * lambda functions
 *
 * (c) copyright 1982, Regents of the University of California
 */

# include "global.h"

/*
 *
 *  Lalloc
 *
 *  This lambda allows allocation of pages from lisp.  The first
 *  argument is the name of a space, n pages of which are allocated,
 *  if possible.  Returns the number of pages allocated.
 */

lispval
Lalloc()
	{
	long n;
	chkarg(2,"alloc");
	if(TYPE((lbot+1)->val) != INT && (lbot+1)->val != nil )
		error("2nd argument to allocate must be an integer",FALSE);
	n = 1;
	if((lbot+1)->val != nil) n = (lbot+1)->val->i;
	return(alloc((lbot)->val,n));	/*  call alloc to do the work  */
	}

lispval
Lsizeof()
	{
	chkarg(1,"sizeof");
	return(inewint(csizeof(lbot->val)));
	}

lispval
Lsegment()
	{
	chkarg(2,"segment");
chek:	while(TYPE(np[-1].val) != INT )
		np[-1].val=error("LENGTH ARG TO SEGMENT MUST BE INTEGER",TRUE);
	if( np[-1].val->i < 0 )
		{
		np[-1].val = error("LENGTH ARG TO SEGMENT MUST BE POSITIVE",TRUE);
		goto chek;
		}
	return(csegment(typenum((lbot)->val),(int)(np[-1].val->i),FALSE));
	}

/*  Lforget  *************************************************************/
/*									*/
/*  This function removes an atom from the hash table.			*/

lispval
Lforget()
	{
	char *name;
	struct atom *buckpt;
	int hash;
	chkarg(1,"forget");
	if(TYPE(lbot->val) != ATOM)
		error("remob: non-atom argument",FALSE);
	name = lbot->val->a.pname;
	hash = hashfcn(name);

	/*  We have found the hash bucket for the atom, now we remove it  */

	if( hasht[hash] == (struct atom *)lbot->val )
		{
		hasht[hash] = lbot->val->a.hshlnk;
		lbot->val->a.hshlnk = (struct atom *)CNIL;
		return(lbot->val);
		}

	buckpt = hasht[hash];
	while(buckpt != (struct atom *)CNIL)
		{
		if(buckpt->hshlnk == (struct atom *)lbot->val)
			{
			buckpt->hshlnk = lbot->val->a.hshlnk;
			lbot->val->a.hshlnk = (struct atom *)CNIL;
			return(lbot->val);
			}
		buckpt = buckpt->hshlnk;
		}

	/*  Whoops!  Guess it wasn't in the hash table after all.  */

	return(lbot->val);
	}

lispval
Lgetl()
	{
	chkarg(1,"getlength");
	if(TYPE(lbot->val) != ARRAY)
		error("ARG TO GETLENGTH MUST BE AN ARRAY",TRUE);
	return(lbot->val->ar.length);
	}

lispval
Lputl()
	{
	chkarg(2,"putlength");
	if(TYPE((lbot)->val) != ARRAY)
		error("ARG TO PUTLENGTH MUST BE AN ARRAY",FALSE);
chek:	while(TYPE(np[-1].val) != INT)
		np[-1].val = error("ARRAY LENGTH MUST BE AN INTEGER",FALSE);
	if(np[-1].val->i <= 0)
		{
		np[-1].val = error("ARRAY LENGTH MUST BE POSITIVE",TRUE);
		goto chek;
		}
	return((lbot)->val->ar.length = np[-1].val);
	}
lispval
Lgetdel()
	{
	chkarg(1,"getdelta");
	if(TYPE(lbot->val) != ARRAY)
		error("ARG TO GETDELTA MUST BE AN ARRAY",FALSE);
	return(lbot->val->ar.delta);
	}

lispval
Lputdel()
	{
	chkarg(2,"putdelta");
	if(TYPE((np-2)->val) != ARRAY)
		error("ARG TO PUTDELTA MUST BE AN ARRAY",FALSE);
chek:	while(TYPE(np[-1].val) != INT)
		np[-1].val = error("ARRAY LENGTH MUST BE AN INTEGER",TRUE);
	if(np[-1].val->i <= 0)
		{
		np[-1].val = error("Array delta must be positive",TRUE);
		goto chek;
		}
	return((lbot)->val->ar.delta = np[-1].val);
	}

lispval
Lgetaux()
	{
	chkarg(1,"getaux");
	if(TYPE(lbot->val)!=ARRAY)
		error("Arg to getaux must be an array", FALSE);
	return(lbot->val->ar.aux);
	}

lispval
Lputaux()
	{
	chkarg(2,"putaux");

	if(TYPE((lbot)->val)!=ARRAY)
		error("1st Arg to putaux must be array", FALSE);
	return((lbot)->val->ar.aux = np[-1].val);
	}

lispval
Lgetdata()
	{
	chkarg(1,"getdata");
	if(TYPE(lbot->val)!=ARRAY)
		error("Arg to getdata must be an array", FALSE);
	return((lispval)lbot->val->ar.data);
	}

lispval
Lputdata()
	{
	chkarg(2,"putdata");

	if(TYPE(lbot->val)!=ARRAY)
		error("1st Arg to putaux must be array", FALSE);
	return((lispval)(lbot->val->ar.data = (char *)(lbot[1].val)));
	}

lispval
Lgeta()
	{
	chkarg(1,"getaccess");
	if(TYPE(lbot->val) != ARRAY)
		error("ARG TO GETACCESS MUST BE AN ARRAY",FALSE);
	return(lbot->val->ar.accfun);
	}

lispval
Lputa()
	{
	chkarg(2,"putaccess");
	if(TYPE((lbot)->val) != ARRAY)
		error("ARG TO PUTACCESS MUST BE ARRAY",FALSE);
	return((lbot)->val->ar.accfun = np[-1].val);
	}

lispval
Lmarray()
{
	register lispval handy;

	chkarg(5,"marray");

	(handy = newarray());		/*  get a new array cell  */
	handy->ar.data=(char *)lbot->val;/*  insert data address  */
	handy->ar.accfun = lbot[1].val;	/*  insert access function  */
	handy->ar.aux = lbot[2].val;	/*  insert aux data  */
	handy->ar.length = lbot[3].val;	/*  insert length  */
	handy->ar.delta = lbot[4].val;	/*  push delta arg  */
	return(handy);
	}

lispval
Lgtentry()
	{
	chkarg(1,"getentry");
	if( TYPE(lbot->val) != BCD )
		error("ARG TO GETENTRY MUST BE FUNCTION",FALSE);
	return((lispval)(lbot->val->bcd.start));
	}

lispval
Lgetlang()
	{
	chkarg(1,"getlang");
	while(TYPE(lbot->val)!=BCD)
		lbot->val = error("ARG TO GETLANG MUST BE FUNCTION DESCRIPTOR",TRUE);
	return(lbot->val->bcd.language);
	}

lispval
Lputlang()
	{
	chkarg(2,"putlang");
	while(TYPE((lbot)->val)!=BCD)
		lbot->val = error("FIRST ARG TO PUTLANG MUST BE FUNCTION DESCRIPTOR",TRUE);
	(lbot)->val->bcd.language = np[-1].val;
	return(np[-1].val);
	}

lispval
Lgetparams()
	{
	chkarg(1,"getparams");
	if(TYPE(np[-1].val)!=BCD)
		error("ARG TO GETPARAMS MUST BE A FUNCTION DESCRIPTOR",FALSE);
	return(np[-1].val->bcd.params);
	}

lispval
Lputparams()
	{
	chkarg(2,"putparams");
	if(TYPE((lbot)->val)!=BCD)
		error("1st ARG TO PUTPARAMS MUST BE FUNCTION DESCRIPTOR",FALSE);
	return((lbot)->val->bcd.params = np[-1].val);
	}

lispval
Lgetdisc()
	{
	chkarg(1,"getdisc");
	if(TYPE(np[-1].val) != BCD)
		error("ARGUMENT OF GETDISC MUST BE FUNCTION",FALSE);
	return(np[-1].val->bcd.discipline);
	}

lispval
Lputdisc()
	{
	chkarg(2,"putdisc");
	if(TYPE(np[-2].val) != BCD)
		error("ARGUMENT OF PUTDISC MUST BE FUNCTION",FALSE);
	return((np-2)->val->bcd.discipline  = np[-1].val);
	}

lispval
Lgetloc()
	{
	chkarg(1,"getloc");
	if(TYPE(lbot->val)!=BCD)
		error("ARGUMENT TO GETLOC MUST BE FUNCTION",FALSE);
	return(lbot->val->bcd.loctab);
	}

lispval
Lputloc()
	{
	chkarg(2,"putloc");
	if(TYPE((lbot+1)->val)!=BCD)
		error("FIRST ARGUMENT TO PUTLOC MUST BE FUNCTION",FALSE);
	(lbot)->val->bcd.loctab = (lbot+1)->val;
	return((lbot+1)->val);
	}

lispval
Lmfunction()
	{
	register lispval handy;
	chkarg(2,"mfunction");
	handy = (newfunct());	/*  get a new function cell  */
	handy->bcd.start = (lispval (*)())((lbot)->val);	/* insert entry point */
	handy->bcd.discipline = ((lbot+1)->val); /*  insert discipline  */
	return(handy);
	}

/** Lreplace ************************************************************/
/*									*/
/*  Destructively modifies almost any kind of data.		 	*/

lispval
Lreplace()
	{
	register lispval a1, a2;
	register int t;
	chkarg(2,"replace");

	if((t = TYPE(a1 = (lbot)->val)) != TYPE(a2 = np[-1].val))
		error("REPLACE ARGS MUST BE SAME TYPE",FALSE);

	switch( t )
		{

	case VALUE:	a1->l = a2->l;
			return( a1 );

	case INT:	a1->i = a2->i;
			return( a1 );


	case ARRAY:	a1->ar.data = a2->ar.data;
			a1->ar.accfun = a2->ar.accfun;
			a1->ar.length = a2->ar.length;
			a1->ar.delta = a2->ar.delta;
			return( a1 );

	case DOUB:	a1->r = a2->r;
			return( a1 );

	case SDOT:
	case DTPR:	a1->d.car = a2->d.car;
			a1->d.cdr = a2->d.cdr;
			return( a1 );
	case BCD:	a1->bcd.start = a2->bcd.start;
			a1->bcd.discipline = a2->bcd.discipline;
			return( a1 );
	default:
			errorh1(Vermisc,"Replace: cannot handle the type of this arg",
						 nil,FALSE,0,a1);
		}
	/* NOTREACHED */
	}

/* Lvaluep */

lispval
Lvaluep()
	{
	chkarg(1,"valuep");
	if( TYPE(lbot->val) == VALUE ) return(tatom); else return(nil);
	}

CNTTYP() { return; /* HI! COUNT ONE TYPE CALL! */ }

lispval
Lod()
	{
	int i;
	chkarg(2,"od");

	while( TYPE(np[-1].val) != INT )
		np[-1].val = error("2nd ARG TO OD MUST BE INTEGER",TRUE);

	for( i = 0; i < np->val->i; ++i )
		printf(copval(odform,CNIL)->a.pname,((int *)(np[-2].val))[i]);

	dmpport(poport);
	return(nil);
	}
lispval
Lfake()
	{
	chkarg(1,"fake");

	if( TYPE(lbot->val) != INT )
		error("ARG TO FAKE MUST BE INTEGER",TRUE);

	return((lispval)(lbot->val->i));
	}

	/* this used to be Lwhat, but was changed to Lmaknum for maclisp
	   compatiblity
	*/
lispval
Lmaknum()
	{
	chkarg(1,"maknum");
	return(inewint((int)(lbot->val)));
	}
lispval
Lderef()
	{
	chkarg(1,"deref");

	if( TYPE(lbot->val) != INT )
		error("arg to deref must be integer",TRUE);

	return(inewint(*(int *)(lbot->val->i)));
	}

lispval
Lpname()
	{
	chkarg(1,"pname");
	if(TYPE(lbot->val) != ATOM)
		error("ARG TO PNAME MUST BE AN ATOM",FALSE);
	return((lispval)(lbot->val->a.pname));
	}

lispval
Larayref()
	{
	chkarg(2,"arrayref");
	if(TYPE((lbot)->val) != ARRAY)
		error("FIRST ARG TO ARRAYREF MUST BE ARRAY",FALSE);
	vtemp = (lbot + 1)->val;
chek:	while(TYPE(vtemp) != INT)
		vtemp = error("SECOND ARG TO ARRAYREF MUST BE INTEGER",TRUE);
	if( vtemp->i < 0 )
		{
		vtemp = error("NEGATIVE ARRAY OFFSET",TRUE);
		goto chek;
		}
	if( vtemp->i >= (np-2)->val->ar.length->i )
		{
		vtemp = error("ARRAY OFFSET TOO LARGE",TRUE);
		goto chek;
		}
	vtemp = (lispval)((np-2)->val->ar.data + ((np-2)->val->ar.delta->i)*(vtemp->i));
		/*  compute address of desired item  */
	return(vtemp);
			
	}

lispval
Lptr()
	{
	chkarg(1,"ptr");
	return(inewval(lbot->val));
	}

lispval
Llctrace()
	{
	chkarg(1,"lctrace");
	lctrace = (int)(lbot->val->a.clb);
	return((lispval)lctrace);
	}

lispval
Lslevel()
	{
	return(inewint(np-orgnp-2));
	}

lispval
Lsimpld()
	{
	register lispval pt;
	register char *cpt = strbuf;

	chkarg(1,"simpld");

	for(atmlen=1, pt=np->val; NOTNIL(pt); ++atmlen, pt = pt->d.cdr);

	if( atmlen > STRBLEN )
		{
		error("LCODE WAS TOO LONG",TRUE);
		return((lispval)inewstr(""));
		}

	for(pt=np->val; NOTNIL(pt); pt = pt->d.cdr) *(cpt++) = pt->d.car->i;
	*cpt = 0;

	return((lispval)newstr(1));
	}
	
	
/*  Lopval  *************************************************************/
/*									*/
/*  Routine which allows system registers and options to be examined	*/
/*  and modified.  Calls copval, the routine which is called by c code	*/
/*  to do the same thing from inside the system.			*/

lispval 
Lopval()
{
	lispval quant;

	if( lbot == np )
		return(error("bad call to opval",TRUE));
	quant = lbot->val;	 /*  get name of sys variable  */
	while( TYPE(quant) != ATOM )
		quant = error("first arg to opval must be an atom",TRUE);

	if(np > lbot+1)  vtemp = (lbot+1)->val ;
	else vtemp = CNIL;
	return(copval(quant,vtemp));
}
