/*							=====> SLINK.C	     */
/* TIPC Scheme Runtime Support - Lattice C/Assembly Language Linkage
   (C) Copyright 1985 by Texas Instruments Incorporated.
   All rights reserved.

   Author:  John C. Jensen
   Installation:  Texas Instruments Incorporated, Dallas, Texas
   Division:  Central Research Laboratories
   Cost Center:  Computer Science Laboratory
   Project:  Computer Architecture Branch
   Date Written:  21 June 1985
   Last Modification:  18 October 1985
*/
#include "slink.h"
#include "ctype.h"
/************************************************************************/
/*	   Scheme to Lattice C (or assembly langauge) Interface 	*/
/*									*/
/* Purpose:  To provide the ability for a Scheme user to link to low	*/
/*		level routines not written in Scheme.			*/
/*									*/
/* Description:  This interface allows linkage to routines written in	*/
/*		Lattice C, or assembly langauge routines which use the	*/
/*		Lattice C linkage conventions.				*/
/*									*/
/* Limitations:  This interface may be used to call routines which	*/
/*		accept up to six (6) arguments of the Lattice C types:	*/
/*									*/
/*				int					*/
/*				long					*/
/*				char					*/
/*				char * (zero terminated string) 	*/
/*				float					*/
/*				double					*/
/*				unsigned (16 bit integer)		*/
/*									*/
/*		and which return a single Scheme value of one of the	*/
/*		following types:					*/
/*									*/
/*				fixnum (up to 32 bits)			*/
/*				flonum					*/
/*				character				*/
/*				string					*/
/*				't or '()                               */
/*									*/
/*		The C and/or assembly language routines may have side	*/
/*		effects and save state information, but they may not	*/
/*		have access to, or modify, the state of the Scheme	*/
/*		runtime (except through the passing of parameters).	*/
/*									*/
/* How to Use:								*/
/*									*/
/*	1.  Compile the routine you wish to call using the small model	*/
/*	    (small code, small data) Lattice C compiler.		*/
/*									*/
/*	2.  Modify this routine (SLINK.C) as follows, and compile it	*/
/*	    with the small model Lattice C compiler.			*/
/*									*/
/*	    a.	Add a declaration to indicate the type of the value to	*/
/*		be returned by your external routine (if no value is	*/
/*		declared, it will default to "int").  e.g.,             */
/*									*/
/*				char *dir1();				*/
/*		Here, the function "dir1" is declared to return         */
/*		(char *), which is the C representation for a character */
/*		string. 						*/
/*									*/
/*	    b.	Add an entry in the "switch" statement to call your     */
/*		routine.  You must explicitly indicate the type of each */
/*		argument you pass, as well as the value you wish to be	*/
/*		returned to Scheme.  e.g.,				*/
/*									*/
/*		   case 0:  RETURN_STRING( dir1( STRING(arg1) ) );	*/
/*									*/
/*		In this example, the function "dir1" is called using    */
/*		the first argument, which is a character string.  The	*/
/*		result of the "dir1" call is returned as a character    */
/*		string to Scheme.					*/
/*									*/
/*		Argument values may be obtained and converted to the	*/
/*		appropriate type using one of the following functions:	*/
/*									*/
/*				INTEGER(argn)				*/
/*				LONG_INTEGER(argn)			*/
/*				CHARACTER(argn) 			*/
/*				FLOAT(argn)				*/
/*				DOUBLE(argn)				*/
/*				STRING(argn)				*/
/*				UNSIGNED(argn)				*/
/*									*/
/*		Values must be returned using one of the following	*/
/*		functions:						*/
/*									*/
/*				RETURN_INTEGER(value);			*/
/*				RETURN_FLONUM(value);			*/
/*				RETURN_CHARACTER(value);		*/
/*				RETURN_STRING(value);			*/
/*				RETURN_T_OR_NIL(value); 		*/
/*									*/
/*	    c.	The case number in step b is the "function code" which  */
/*		is used to invoke the function.  The function code must */
/*		always be an integer and must be the first operand	*/
/*		passed to one of the "escape" Scheme functions.  The    */
/*		other operands follow the function code in the order	*/
/*		expected by the called routine.  The Scheme escape	*/
/*		functions are named %esc1, %esc2, .., %esc7, where the	*/
/*		number following the "%esc" designation is the total    */
/*		number of operands, INCLUDING the function code.	*/
/*		For example, to call the "dir1" function with one       */
/*		operand, we code:					*/
/*									*/
/*				(%esc2 0 "string")                      */
/*									*/
/*		where the first operand (0) is the function code and	*/
/*		"string" is the character string to be passed as the    */
/*		only argument.						*/
/*									*/
/*	    d.	To provide a more meaningful calling sequence and to	*/
/*		check for correct parameters, a Scheme routine should	*/
/*		be defined for each function to be called.  These	*/
/*		functions are normally placed in the SCHEME.INI file,	*/
/*		but may be installed "permanently" for a given          */
/*		application by converting them to fast-load format and	*/
/*		appending them to the FRONT of the COMPILER.FSL file,	*/
/*		which is automatically loaded when PCS begins.		*/
/*									*/
/*		A sample Scheme function for the "dir1" function is:    */
/*									*/
/*		    (define dir1					*/
/*		      (lambda (filespec)				*/
/*			 (if (string? filespec) 			*/
/*			    (%esc2 0 filespec)				*/
/*			    (error "Invalid Parameter to 'dir1'"        */
/*				   filespec)))) 			*/
/*									*/
/*		Here, the Scheme function "dir1" checks its argument    */
/*		to make sure that it's a string and, if it is, uses the */
/*		escape (%esc2) opcode to invoke the function.  If the	*/
/*		argument is not a string, an error is reported through	*/
/*		the Scheme error procedure.				*/
/*									*/
/*	    e.	The Scheme runtime must be re-linked with your Lattice	*/
/*		C and/or assembly language routines included.  Modify	*/
/*		the file SCHEME.LNK file (the link edit control file)	*/
/*		to include your modules by adding them to the end of	*/
/*		the "includes" (e.g., ...+YOUROBJ).                     */
/*									*/
/* Comments:								*/
/*									*/
/*	1.  The Scheme/C interface loses all typing information.  All	*/
/*	    arguments must be of the correct type or the results will	*/
/*	    be unpredictable.  Scheme functions (such as the "dir1"     */
/*	    example in d. (above)) should be used to force arguments	*/
/*	    to the expected types.					*/
/*									*/
/*	2.  There is a limited amout of procedure (code) and data	*/
/*	    memory available to user supplied functions.  Very large	*/
/*	    functions (in terms of either code space or data space)	*/
/*	    may cause linking to fail or Scheme to overflow its runtime */
/*	    stack.							*/
/************************************************************************/
link(result, fc, arg1, arg2, arg3, arg4, arg5, arg6)
long **result,*fc,*arg1,*arg2,*arg3,*arg4,*arg5,*arg6;
 {
  int ftncode;			/* function code */
  int status;			/* return code */
  int int_number;		/* software int number */
  char *t_;			/* local temporary */
  char* strng;			/* Used by function 8 */

  extern unsigned zapcurs;    	/* Denote cursor no longer in use */	
  extern int compact_every;	/* Indicates when to compact	  */

  /**************************************************************/
  /* a.  Declare each function which is to be called so that	*/
  /*	 its type is known by the Lattice C compiler.		*/
  /**************************************************************/
  char *dir1(); 	/* dir1 returns a character string */
  char *dir2(); 	/* dir2 returns a character string */
  long int freesp();
  long int filesize();
  char *chgdir();
#ifndef PROMEM
  long int isw_int();	/* software interrupt - return integer	*/
  int	   tsw_int();	/* software interrupt - return t or nil */
  char	  *ssw_int();	/* software interrupt - return string	*/
  double   fsw_int();	/* software interrupt - return float	*/
  char	  *flo2hex();	/* return hex representation of float	*/
#endif
  int hash();		/* return hash value of symbol		*/
  void randomiz();	/* seed random number generator 	*/
  #ifndef PROMEM
     unsigned xlidbg();	/* XLI debug hook			*/
  #endif

  ftncode = *fc;	/* make a local copy of the function code */

  strng = "0000000000000000";


  /**************************************************************/
  /* b.  Add a case entry in the following "switch" statement   */
  /*	 to call your external procedure.  The "case" number    */
  /*	 is the function code which you must use to invoke your */
  /*	 function.						*/
  /**************************************************************/
  switch (ftncode)
   {
    case 0:  /* function code 0:  find file match */
	     RETURN_STRING(dir1(STRING(arg1)));

    case 1:  /* function code 1:  step through directory, matching files */
	     RETURN_STRING(dir2());

    case 2:  /* function code 2:  bid another MS-DOS task */
	     status = bid(STRING(arg1),STRING(arg2),INTEGER(arg3),INTEGER(arg4));

	     if (status < 0) print_and_exit(
       "[VM FATAL ERROR] DOS-CALL error: unable to restore PC Scheme memory\n");
	     RETURN_INTEGER(status);

    case 3:  /* function code 3:  get the free space of heap */
	     RETURN_INTEGER(freesp());

    case 4:  /* function code 4:  scroll window up one line */
	     zscroll(INTEGER(arg1),INTEGER(arg2),INTEGER(arg3),
		     INTEGER(arg4),INTEGER(arg5));
	     RETURN_T_OR_NIL(1);

    case 5:  /* function code 5:  scroll window down one line */
	     scroll_d(INTEGER(arg1),INTEGER(arg2),INTEGER(arg3),
		      INTEGER(arg4),INTEGER(arg5));
	     RETURN_T_OR_NIL(1);

    case 6:  /* function code 6:  copy protect test - This function was  */
	     /* removed in version 2.0 and always returns True. 	 */
	     RETURN_T_OR_NIL(1);

    case 7: 
#ifndef PROMEM 
	    /* function code 7:  software interrupt */
	    int_number = *arg1;   /* 1st arg = interrupt number   */
	    status     = *arg2;   /* 2nd arg = return result type */
	    switch (status)
	    {
	    case 0: /* return integer result */
	      RETURN_INTEGER(isw_int(int_number,arg3,arg4,arg5,arg6));

	    case 1: /* return t or nil result */
	      RETURN_T_OR_NIL(tsw_int(int_number,arg3,arg4,arg5,arg6));

	    case 2: /* return string result */
	      RETURN_STRING(ssw_int(int_number,arg3,arg4,arg5,arg6));

	    case 3: /* return string result */
	      RETURN_FLONUM(fsw_int(int_number,arg3,arg4,arg5,arg6));

	    default: return(-1);  /* unrecognized return type */
	     }
#endif
    case 8:  /* function code 8: float->hex conversion */
	    RETURN_STRING(flo2hex(strng,arg1,INTEGER(arg2)));

    case 9:  /* function code 9: return hash value of symbol */
	    RETURN_INTEGER(hash(STRING(arg1),strlen(arg1)));

    case 10: /* function code 10: delete a file */
	     RETURN_INTEGER(delete(STRING(arg1)));

    case 11: /* function code 11: copy a file */
	     RETURN_INTEGER(copy_fil(STRING(arg1),STRING(arg2)));

    case 12: /* function code 12: rename files under current directory */
	     RETURN_INTEGER(rename(STRING(arg1),STRING(arg2)));

    case 13: /* function code 13: turn the cursor on */
	     zapcurs = 0;
	     zcuron();
	     RETURN_T_OR_NIL(1);

    case 14: /* function code 14: turn the cursor off */
	     zcuron(); zcuroff();
	     zapcurs = 1;
	     RETURN_T_OR_NIL(1);

    case 15: /* function code 15: get the file size */
	     RETURN_INTEGER(filesize(STRING(arg1)));

    case 16: /* function code 16: change current directory */
	     RETURN_STRING(chgdir(STRING(arg1)));

    case 17: /* function code 17: change current drive */
	     chgdrv(toupper(CHARACTER(arg1)));
	     RETURN_T_OR_NIL(1);
#ifndef PROMEM
    case 18: /* function code 18: XLI debug hook */
	     RETURN_INTEGER(xlidbg(INTEGER(arg1)));
#endif

    case 19: /* function code 19: unused */
	     return(-1);

    case 20: /* function code 20: seed random number generator */
	     randomiz(INTEGER(arg1));
	     RETURN_T_OR_NIL(1);

    case 21: /* function code 21: return compaction variable */
	     RETURN_INTEGER(compact_every);

    case 22: /* function code 22: set compaction variable */
	     compact_every = (INTEGER(arg1));
	     RETURN_INTEGER(compact_every);

    default:  return(-1); /* unrecognized function code */
   } /* end:  switch (ftncode) */
 } /* end of function:	link(result,fc,arg1,arg2,arg3,arg4,arg5,arg6) */

  /**************************************************************/
  /* Note:  If you wish, your Lattice C functions may be	*/
  /*	    included in this file following this message.	*/
  /**************************************************************/
