/*-=-=-=-=-=-=-=-=-=-=-=- RCCL/RCI Notice of Copyright -=-=-=-=-=-=-=-=-=-=-*
 *									    *
 *	Copyright (C) 1987, 1991 by John E. Lloyd and Mike Parker.	    *
 *									    *
 *	Information on copyright permissions, as well as a complete	    *
 *	disclaimer of warranty, is given in the file COPYRIGHT.		    *
 *									    *
 *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/

/*---------McGill-Computer-Vision-and-Robotics-Laboratory--C-Module---------
 *		
 * NAME:	callv() -- calls a function with a vector of arguments
 *
 * USAGE:	#include "callv.h"
 *
 * 		callv (function, arglist, argdesc)
 *		 (*function)();
 *		 ARG *arglist;
 *		 char *argdesc;
 *
 * DESCRIPTION: This routine is mostly useful in implementing table driven
 *		programs. The implementation, is, unfortuneately, machine
 *		dependant. Implementations have been provided for the VAX
 *		and the SUN (68000).
 *
 * ARGUMENTS:   'function'	-- pointer to the function to be called.
 *
 *		'arglist'	-- array of arguments. Each argument is 
 *				   stored as a member of the union ARG,
 *				   which at the moment supports the types
 *				   int, double, char *, and void *.
 *
 *		'argdesc'	-- a character string describing the
 *				   contents of the arglist. The type of
 *				   each argument is described by a character:
 *				   'i': int, 'd': double, 's': char *,
 *				   'p': void *.
 *				   The number of arguments is inferred from
 *				   the length of argdesc.
 *
 * EXAMPLE:	call the function foobar with an integer, double, and
 *		a string:
 *		
 *			ARG args[3];
 *
 *			args[0].intVal = 10;
 *			args[1].doubleVal = 23.;
 *			args[2].strVal = "hello"
 *			
 *			callv (foobar, args, "ids");
 *
 * AUTHOR:      John Lloyd, April 6, 1986. Sun (68000) assembly code provided
 *		by the mouse (Mike Parker).
 *
 *-------------McGill-Computer-Vision-and-Robotics-Laboratory--------------*/

#include "../h/callv.h"

callv (function, arglist, argdesc)
register (*function)();			/* r11 (vax), a5 (sun) */
register ARG *arglist;			/* r10 (vax), a4 (sun) */
char *argdesc;			
{
	register int argSizeCount = 0;  /* r9  (vax), d7 (sun) */
	int count = 0;

	/* start by going to the end of the list */

	while (*argdesc != 0)
	 { count++;
	   argdesc++;
	 }
	arglist += count;

	while (count)
	 { argdesc--;
	   arglist--;
	   count--;

#ifdef vax
#define CPUOK	1
	   switch (*argdesc)
	    { default:
		 abort();
	      case 'i':
		 asm ("movl (r10), -(sp)");
		 argSizeCount += 1;
		 break;
	      case 'd':
		 asm ("movd (r10), -(sp)");
		 argSizeCount += 2;
		 break;
	      case 's':
	      case 'p':
		 asm ("movl (r10), -(sp)");
		 argSizeCount += 1;
		 break;
	    }
	 }
	asm ("calls r9, (r11)");
#endif
#ifdef sun
#ifndef sparc
#define CPUOK	1
	   switch (*argdesc)
	    { case 'i':
		 asm ("movl a4@, sp@-");
		 argSizeCount += 1;
		 break;
	      case 'd':
		 asm ("movl a4@(4), sp@-");
		 asm ("movl a4@, sp@-");
		 argSizeCount += 2;
		 break;
	      case 's':
	      case 'p':
		 asm ("movl a4@, sp@-");
		 argSizeCount += 1;
		 break;
	    }
	 }
	asm ("jbsr a5@");
	argSizeCount <<= 2;
	asm ("addl d7,sp");
#endif 
#endif /*sun*/
#ifndef	CPUOK
	   printf ("Error: Callv() not implemented on this CPU\n");
	   exit (-1);
	 }
#endif
}

#ifdef TEST

foobar (i, a, s, j)
int i, j;
double a;
char *s;
{
	printf ("%d %lf %s %d\n", i, a, s, j);
}

main ()
{
	ARG args[10];
	char cbuf[256];

	printf ("Enter i, a, s, and j: \n");
	scanf ("%d%lf%s%d", &args[0].intVal, &args[1].doubleVal,
			    cbuf, &args[3].intVal);
	args[2].strVal = cbuf;
	
	callv (foobar, args, "idsi");
}

#endif /*TEST*/
