static char rcsid[] = "$Header:lam3.c 12.0$";
#ifndef lint
static char *rcsid =
   "$Header:lam3.c 12.0$";
   "$ACIS:lam3.c 12.0$";
#endif

/*					-[Fri Aug  5 12:47:19 1983 by jkf]-
 * 	lam3.c				$Locker:  $
 * lambda functions
 *
 * (c) copyright 1982, Regents of the University of California
 */

# include "global.h"
# include "chars.h"
# include "chkrtab.h"

lispval
Lalfalp()
{
	register char  *first, *second;

	chkarg(2,"alphalessp");
	first = (char *) verify(lbot->val,"alphalessp: non symbol or string arg");
	second = (char *) verify((lbot+1)->val,"alphalessp: non symbol or string arg");
	if(strcmp(first,second) < 0)
		return(tatom);
	else
		return(nil);
}

lispval
Lncons()
{
	register lispval handy;

	chkarg(1,"ncons");
	handy = newdot();
	handy->d.cdr = nil;
	handy->d.car = lbot->val;
	return(handy);
}
lispval
Lzerop()
{
	register lispval handy;

	chkarg(1,"zerop");
	handy = lbot->val;
	switch(TYPE(handy)) {
	case INT:
		return(handy->i==0?tatom:nil);
	case DOUB:
		return(handy->r==0.0?tatom:nil);
	}
	return(nil);
}
lispval
Lonep()
{
	register lispval handy; 
	lispval Ladd();

	handy = lbot->val;
	switch(TYPE(handy)) {
	case INT:
		return(handy->i==1?tatom:nil);
	case DOUB:
		return(handy->r==1.0?tatom:nil);
	case SDOT:
		protect(inewint(0));
		handy = Ladd();
		if(TYPE(handy)!=INT || handy->i !=1)
			return(nil);
		else
			return(tatom);
	}
	return(nil);
}

lispval
cmpx(lssp)
{
	register struct argent *argp;
	register struct argent *outarg;
	register struct argent *onp = np;
	Savestack(3);


	argp = lbot + 1;
	outarg = np;
	while(argp < onp) {

		np = outarg + 2;
		lbot = outarg;
		if(lssp)
			*outarg = argp[-1], outarg[1]  = *argp++;
		else
			outarg[1]  = argp[-1], *outarg = *argp++;
		lbot->val = Lsub();
		np = lbot + 1;
		if(Lnegp()==nil) 
		{
		    Restorestack();
		    return(nil);
		}
	}
	Restorestack();
	return(tatom);
}

lispval
Lgreaterp()
{
	register int typ;
	/* do the easy cases first */
	if(np-lbot == 2)
	{   if((typ=TYPE(lbot->val)) == INT)
	    {    if((typ=TYPE(lbot[1].val)) == INT)
		   return((lbot[0].val->i - lbot[1].val->i) > 0 ? tatom : nil);
		 else if(typ == DOUB)
		  return((lbot[0].val->i - lbot[1].val->r) > 0.0 ? tatom : nil);
	    }
	    else if(typ == DOUB)
	    {    if((typ=TYPE(lbot[1].val)) == INT)
		  return((lbot[0].val->r - lbot[1].val->i) > 0.0 ? tatom : nil);
		 else if(typ == DOUB)
		  return((lbot[0].val->r - lbot[1].val->r) > 0.0 ? tatom : nil);
	    }
	}
		  
	return(cmpx(FALSE));
}

lispval
Llessp()
{
	register int typ;
	/* do the easy cases first */
	if(np-lbot == 2)
	{   if((typ=TYPE(lbot->val)) == INT)
	    {    if((typ=TYPE(lbot[1].val)) == INT)
		   return((lbot[0].val->i - lbot[1].val->i) < 0 ? tatom : nil);
		 else if(typ == DOUB)
		  return((lbot[0].val->i - lbot[1].val->r) < 0.0 ? tatom : nil);
	    }
	    else if(typ == DOUB)
	    {    if((typ=TYPE(lbot[1].val)) == INT)
		  return((lbot[0].val->r - lbot[1].val->i) < 0.0 ? tatom : nil);
		 else if(typ == DOUB)
		  return((lbot[0].val->r - lbot[1].val->r) < 0.0 ? tatom : nil);
	    }
	}
		  
	return(cmpx(TRUE));
}

lispval
Ldiff()
{
	register lispval arg1,arg2; 
	register handy = 0;


	chkarg(2,"Ldiff");
	arg1 = lbot->val;
	arg2 = (lbot+1)->val;
	if(TYPE(arg1)==INT && TYPE(arg2)==INT) {
		handy=arg1->i - arg2->i;
	}
	else error("non-numeric argument",FALSE);
	return(inewint(handy));
}

lispval
Lmod()
{
	register lispval arg1,arg2;
	lispval  handy;
	struct sdot fake1, fake2;
	fake2.CDR = 0;
	fake1.CDR = 0;

	chkarg(2,"mod");
	handy = arg1 = lbot->val;
	arg2 = (lbot+1)->val;
	switch(TYPE(arg1)) {
	case SDOT:
		switch(TYPE(arg2)) {
		case SDOT:			/* both are already bignums */
			break;
		case INT:			/* convert arg2 to bignum   */
			fake2.I = arg2->i;
			arg2 =(lispval) &fake2;
			break;
		default:
			error("non-numeric argument",FALSE);
		}
		break;
	case INT:
		switch(TYPE(arg2)) {
		case SDOT:			/* convert arg1 to bignum */
			fake1.I = arg1->i;
			arg1 =(lispval) &fake1;
			break;
		case INT:			/* both are fixnums 	  */
			return( inewint ((arg1->i) % (arg2->i)) );
		default:
			error("non-numeric argument",FALSE);
		}
		break;
	default:
		error("non-numeric argument",FALSE);
	}
	if(TYPE((lbot+1)->val)==INT && lbot[1].val->i==0)
		return(handy);
	divbig(arg1,arg2,(lispval *)0,&handy);
	if(handy==((lispval)&fake1))
		handy = inewint(fake1.I);
	if(handy==((lispval)&fake2))
		handy = inewint(fake2.I);
	return(handy);
}
lispval
Ladd1()
{
	register lispval handy;
	lispval Ladd();
	Savestack(1); /* fixup entry mask */
	chkarg(1,"add1");

	/* simple test first */
	if((TYPE(lbot->val) == INT) && (lbot->val->i < MaxINT))
	{
	    Restorestack();
	    return(inewint(lbot->val->i + 1));
	}
	
	handy = rdrint;
	handy->i = 1;
	protect(handy);
	handy=Ladd();
	Restorestack();
	return(handy);

}



lispval
Lsub1()
{
	register lispval handy;
	lispval Ladd();
	Savestack(1); /* fixup entry mask */
	chkarg(1,"sub1");
	
	if((TYPE(lbot->val) == INT) && (lbot->val->i > MinINT))
	{
	    Restorestack();
	    return(inewint(lbot->val->i - 1));
	}

	handy = rdrint;
	handy->i = - 1;
	protect(handy);
	handy=Ladd();
	Restorestack();
	return(handy);
}

lispval
Lminus()
{
	register lispval arg1, handy;
	lispval subbig();

	chkarg(1,"minus");
	arg1 = lbot->val;
	handy = nil;
	switch(TYPE(arg1)) {
	case INT:
		handy= inewint(0 - arg1->i);
		break;
	case DOUB:
		handy = newdoub();
		handy->r = -arg1->r;
		break;
	case SDOT: { struct sdot dummyb;
		handy = (lispval) &dummyb;
		handy->s.I = 0;
		handy->s.CDR = (lispval) 0;
		handy = subbig(handy,arg1);
		break; }

	default:
		error("non-numeric argument",FALSE);
	}
	return(handy);
}

lispval
Lnegp()
{
	register lispval handy = np[-1].val, work;
	register flag = 0;

loop:
	switch(TYPE(handy)) {
	case INT:
		if(handy->i < 0) flag = TRUE;
		break;
	case DOUB:
		if(handy->r < 0) flag = TRUE;
		break;
	case SDOT:
		for(work = handy;
		    work->s.CDR!=(lispval) 0;
		    work = work->s.CDR) {;}
		if(work->s.I < 0) flag = TRUE;
		break;
	default:
		handy = errorh1(Vermisc,
				  "minusp: Non-(int,real,bignum) arg: ",
				  nil,
				  TRUE,
				  0,
				  handy);
		goto loop;
	}
	if(flag) return(tatom);
	return(nil);
}

lispval
Labsval()
{
	register lispval arg1;

	chkarg(1,"absval");
	arg1 = lbot->val;
	if(Lnegp()!=nil) return(Lminus());

	return(arg1);
}

/*
 *
 * (oblist)
 *
 * oblist returns a list of all symbols in the oblist
 *
 * written by jkf.
 */
lispval
Loblist()
{
    int indx;
    lispval headp, tailp ;
    struct atom *symb ;
    extern int hashtop;
    Savestack(0);

    headp = tailp = newdot(); /* allocate first DTPR */
    protect(headp);		/*protect the list from garbage collection*/
				/*line added by kls			  */

    for( indx=0 ; indx <= hashtop-1 ; indx++ ) /* though oblist */
    {
	for( symb = hasht[indx] ;
	     symb != (struct atom *) CNIL ;
	     symb = symb-> hshlnk)
	{
	    if(TYPE(symb) != ATOM) 
	    {   printf(" non symbol in hasht[%d] = %x: ",indx,symb);
		printr((lispval) symb,stdout);
		printf(" \n");
		fflush(stdout);
	    }
	    tailp->d.car = (lispval) symb  ; /* remember this atom */
	    tailp = tailp->d.cdr = newdot() ; /* link to next DTPR */
	}
    }

    tailp->d.cdr = nil ; /* close the list unfortunately throwing away
			  the last DTPR
			  */
    Restorestack();
    return(headp);
}

/*
 * Maclisp setsyntax function:
 *    (setsyntax c s x)
 * c represents character either by fixnum or atom
 * s is the atom "macro" or the atom "splicing" (in which case x is the
 * macro to be invoked); or nil (meaning don't change syntax of c); or
 * (well thats enough for now) if s is a fixnum then we modify the bits
 * for c in the readtable.
 */

lispval
Lsetsyn()
{
	register lispval s, c;
	register struct argent *mynp;
	register index;
	lispval x   /*  ,debugmode  */;
	extern unsigned char *ctable;
	extern lispval Istsrch();

	switch(np-lbot) {
	case 2:
		x= nil;			/* only 2 args given */
	case 3:
		x = lbot[2].val;	/* all three args given */
		break;
	default:
		argerr("setsyntax");
	}
	s = Vreadtable->a.clb;
	chkrtab(s);
	/* debugging code 
	debugmode = Istsrch(matom("debugging"))->d.cdr->d.cdr->d.cdr;
	if(debugmode)  printf("Readtable addr: %x\n",ctable);
	  end debugging code */
	mynp = lbot;
	c = (mynp++)->val;
	s = (mynp++)->val;

	switch(TYPE(c)) {
	default:
		error("neither fixnum, atom or string as char to setsyntax",FALSE);

	case ATOM:
		index = *(c->a.pname);
		if((c->a.pname)[1])
		    errorh1(Vermisc,"Only 1 char atoms to setsyntax",
		         nil,FALSE,0,c);
		break;

	case INT:
		index = c->i;
		break;

	case STRNG:
		index = (int) *((char *) c);
	}
	switch(TYPE(s)) {
	case ATOM:
		if(s==splice || s==macro) {
		    if(s==splice)
			    ctable[index] = VSPL;
		    else if(s==macro)
			    ctable[index] = VMAC;
		    if(TYPE(c)!=ATOM) {
			    strbuf[0] = index;
			    strbuf[1] = 0;
			    c = (getatom(TRUE));
		    }
		    Iputprop(c,x,lastrtab);
		    return(tatom);
		}

		/* ... fall into */
	default:  errorh1(Vermisc,"int:setsyntax : illegal second argument ",
				nil,FALSE,0,s);
		/* not reached */
		
	case INT:
		switch(synclass(s->i)) {
		case CESC: Xesc = (char) index; break;
		case CDQ: Xdqc = (char) index; break;
		case CSD: Xsdc = (char) index;	/* string */
		}

		if(synclass(ctable[index])==CESC   /* if we changed the current esc */
		  && (synclass(s->i)!=CESC)          /* to something else, pick current */
		  && Xesc == (char) index) {
	       		ctable[index] = s->i;
			rpltab(CESC,&Xesc);
		}
		else if(synclass(ctable[index])==CDQ   /*  likewise for double quote */
		       && synclass(s->i) != CDQ
		       && Xdqc == (char) index)  {
			ctable[index] = s->i;
			rpltab(CDQ,&Xdqc);
		}
		else if(synclass(ctable[index]) == CSD  /* and for string delimiter */
			&& synclass(s->i) != CSD
			&& Xsdc == (char) index) {
			 ctable[index] = s->i;
			 rpltab(CSD,&Xsdc);
		}
		else ctable[index] = s->i;

		break;

	}
	return(tatom);
}

/*
 * this aux function is used by setsyntax to determine the new current
 * escape or double quote character.  It scans the character table for
 * the first character with the given class (either VESC or VDQ) and
 * puts that character in Xesc or Xdqc (whichever is pointed to by
 * addr).
 */
rpltab(cclass,addr)
char cclass;
unsigned char *addr;
{
	register int i;
	extern unsigned char *ctable;
	for(i=0; i<=127 && synclass(ctable[i]) != cclass; i++);
	if(i<=127) *addr = (unsigned char) i;
	else *addr = '\0';
}


/*
 * int:getsyntax from lisp.
 * returns the fixnum syntax code from the readtable for the given character.
 * to be used by the lisp-code function getsyntax, not to be used by 
 * joe user.
 */
lispval
Lgetsyntax()
{
    register char *name;
    int number, typ;
    lispval handy;
    
    chkarg(1,"int:getsyntax");
    handy = lbot[0].val;
    while (1)
    {
	if((typ = TYPE(handy)) == ATOM)
	{
	    name = handy->a.pname;
	}
	else if (typ == STRNG)
	{
	    name = (char *)handy;
	}
	else if(typ == INT)
	{
	    number = handy->i;
	    break;
	}
	else {
	    handy =
	      errorh1(Vermisc,"int:getsyntax : bad character ",
	      		nil,TRUE,0,handy);
	    continue;	/* start at the top */
	}
	/* figure out the number of the first byte */
	number = (int) name[0];
	if(name[1] != '\0')
	{
	    handy = errorh1(Vermisc,
	    "int:getsyntax : only single character allowed ",
	    nil,TRUE,0,handy);
	}
	else break;
    }
    /* see if number is within range */
    if(number < 0 || number > 255)
    	errorh1(Vermisc,"int:getsyntax : character number out of range ",nil,
		FALSE,0,inewint(number));
    chkrtab(Vreadtable->a.clb);  /* make sure readtable is correct */
    return(inewint(ctable[number]));
}
    
    
	
    
lispval
Lzapline()
{
	register FILE *port;
	extern FILE * rdrport;

	port = rdrport;
	while (!feof(port) && (getc(port)!='\n') );
	return(nil);
}
