/* utilities - basic utility functions                                 */
/* XLISP-STAT 2.1 Copyright (c) 1990, by Luke Tierney                  */
/* Additions to Xlisp 2.1, Copyright (c) 1989 by David Michael Betz    */
/* You may give out copies of this software; for conditions see the    */
/* file COPYING included with this distribution.                       */

/****** ///// clean this stuff up */

#include "xlisp.h"
#include "xlstat.h"

typedef LVAL (*subrfun)(V);

/************************************************************************/
/**                           Basic Utilities                          **/
/************************************************************************/

/* return list of two elements */
LVAL list2 P2C(LVAL, x1, LVAL, x2)
{
  LVAL list, y1, y2;
  
  /* protect some pointers */
  xlstkcheck(3);
  xlsave(list);
  xlsave(y1);
  xlsave(y2);
  
  y1 = x1;
  y2 = x2;
  list = consa(y2);
  list = cons(y1, list);
  
  /* restore the stack frame */
  xlpopn(3);
  
  return(list);
}

/* return list of three elements */
LVAL list3 P3C(LVAL, x1, LVAL, x2, LVAL, x3)
{
  LVAL list, y1, y2, y3;
  
  /* protect some pointers */
  xlstkcheck(4);
  xlsave(list);
  xlsave(y1);
  xlsave(y2);
  xlsave(y3);

  y1 = x1;
  y2 = x2;
  y3 = x3;
  list = consa(y3);
  list = cons(y2, list);
  list = cons(y1, list);
  
  /* restore the stack frame */
  xlpopn(4);
  
  return(list);
}

/* return the i-th argument, without popping it; signal an error if needed. */
LVAL peekarg P1C(int, i)
{
  if (xlargc <= i) xltoofew();
  return(xlargv[i]);
}

/* Get the next element in the sequence; cdr the pointer if it is a list */
LVAL getnextelement P2C(LVAL *, pseq, int, i)
{
  LVAL value;

  switch (ntype(*pseq)) {
  case VECTOR:
    value = getelement(*pseq, i);
    break;
  case TVEC:
  case STRING:
    value = gettvecelement(*pseq, i);
    break;
  case CONS:  
    value = car(*pseq);
    *pseq = cdr(*pseq);
    break;
  default:
    xlbadtype(*pseq);
    value = NIL;
  }
  return(value);
}

/* Set the next element in the sequence; cdr the pointer if it is a list */
VOID setnextelement P3C(LVAL *, pseq, int, i, LVAL, value)
{
  switch (ntype(*pseq)) {
  case VECTOR:
    setelement(*pseq, i, value);
    break;
  case TVEC:
  case STRING:
    settvecelement(*pseq, i, value);
    break;
  case CONS:
    rplaca(*pseq, value);
    *pseq = cdr(*pseq);
    break;
  default:
    xlbadtype(*pseq);
  }
}


/************************************************************************/
/**                  Function Applicaiton Utilities                    **/
/************************************************************************/

VOID pushargvec P3C(LVAL, fun, int, argc, LVAL *, argv)
{
  LVAL *newfp, *oldsp;
  int i;

  /* build a new argument stack frame */
  newfp = oldsp = xlsp;
  pusharg(NIL); /* place holder for stack frame increment */
  pusharg(fun);
  pusharg(NIL); /* place holder for argc */

  /* push the arguments */
  for (i = 0; i < argc; i++)
    pusharg(argv[i]);

  /* establish the new stack frame */
  oldsp[0] = cvfixnum((FIXTYPE)(newfp - xlfp));
  oldsp[2] = cvfixnum((FIXTYPE) argc);
  xlfp = newfp;
}

LVAL xsapplysubr P2C(subrfun, f, LVAL, args)
{
  LVAL *oldargv, val;
  int argc, oldargc;
   
  xlprot1(args); /* protect arguments while pushing */
  argc = pushargs(NIL, args);
  xlpop();       /* now they are protected since they are on the stack */

  oldargc = xlargc;
  oldargv = xlargv;
  xlargc = argc;
  xlargv = xlfp + 3;
  val = (*f)();
  xlargc = oldargc;
  xlargv = oldargv;

  /* remove the call frame */
  xlsp = xlfp;
  xlfp = xlfp - (int)getfixnum(*xlfp);
  return(val);
}

LVAL xscallsubrvec P3C(subrfun, f, int, argc, LVAL *, argv)
{
  LVAL *oldargv, val;
  int oldargc;
   
  pushargvec(NIL, argc, argv);
  oldargc = xlargc;
  oldargv = xlargv;
  xlargc = argc;
  xlargv = xlfp + 3;
  val = (*f)();
  xlargc = oldargc;
  xlargv = oldargv;

  /* remove the call frame */
  xlsp = xlfp;
  xlfp = xlfp - (int)getfixnum(*xlfp);
  return(val);
}

LVAL xsfuncall0 P1C(LVAL, fun)
{
  pushargvec(fun, 0, NULL);
  return(xlapply(0));
}

LVAL xsfuncall1 P2C(LVAL, fun, LVAL, x)
{
  pushargvec(fun, 1, &x);
  return(xlapply(1));
}

LVAL xsfuncall2 P3C(LVAL, fun, LVAL, x, LVAL, y)
{
  LVAL args[2];
  
  args[0] = x;
  args[1] = y;
  pushargvec(fun, 2, args);
  return(xlapply(2));
}

/* replicates a list n times */ 
int xsboolkey P2C(LVAL, key, int, dflt)
{
  LVAL val;
  int result = dflt;
  
  if (xlgetkeyarg(key, &val)) result = ((val != NIL) ? TRUE : FALSE);
  return(result);
}


syntax highlighted by Code2HTML, v. 0.9.1