/* unixtuff.c - unix interface routines for xlisp

 * HISTORY
 * 28-Jun-95	Dannenberg
 *	removed buffering (which could overflow) from ostgetc.
 *
 * 2-Aprl-88	Dale Amon at CMU-CSD
 *	Upgraded to xlisp 2.0. Used msstuff.c as a template.
 *
 * 20-Apr-87	Dale Amon at CMU-CSD
 *	Added control-c interrupt handler. Puts user in breakloop and allows
 *	continue. Prints line at which the interrupt occured. Interrupt
 *	occurs at first eval after ^C has been typed.
 *
 * 19-APR-87	Dale Amon at CMU-CSD
 *	switched from rand to random package. Corrected bug in osrand(). It
 *	did not use the argument n to calculate a rand in range 0 to n-1 as
 *	advertised.
 */

#include <stdio.h>
#include "xlisp.h"

#define LBSIZE 200

/* external variables */
extern LVAL s_unbound,s_true;
extern FILE *tfp;
extern int errno;

/* local variables */
static char lbuf[LBSIZE];
static int lpos[LBSIZE];
static int lindex;
static int lcount = 0;
static int lposition;

/* forward declarations */
FORWARD LOCAL xflush();
FORWARD LOCAL xinfo();

/*==========================================================================*/
/* control-c interrupt handling routines and variables. Uses B4.2 signal
   handling. Previous SIGINT handler is saved just in case someday we want
   to play with turning control c on and off.
*/

#include	<signal.h>

static int		ctc = FALSE;
static void control_c(int x)	{ctc = TRUE;}
static ctcinit()	{signal ( SIGINT, control_c );}
static ctcreset()	{signal ( SIGINT, control_c );}


/*==========================================================================*/

/* osinit - initialize */
osinit(banner)
  char *banner;
{	printf("%s\n",banner);

	/* start the random number generator. Older version was srand(1)
	   seed of 1 makes the sequence repeatable. Random gives better
	   pseudo randomness than does rand().
	*/
#ifdef MACINTOSH
        srand(1);
#else
	srandom(1);
#endif
	/* set control c trap to local routine */
	ctcinit();

	lposition = 0;
	lindex = 0;
	lcount = 0;
}

/* osfinish - clean up before returning to the operating system */
osfinish() {}

/* oserror - print an error message */
oserror(msg) char *msg; {printf("error: %s\n",msg);}

extern long	random();
extern		srandom();
#ifdef MACINTOSH
int osrand(n) int n;	 {return (((int) rand()) % n);}
#else
int osrand(n) int n;	 {return (((int) random()) % n);}
#endif

/* osaopen - open an ascii file */
FILE *osaopen(name,mode) char *name,*mode; {
    FILE *fp;
/*    printf("aopening %s\n", name);*/
    fp = fopen(name,mode);
/*    printf("FILE is %x\n", fp);*/
    return fp;
}

/* osbopen - open a binary file */
FILE *osbopen(name,mode) char *name,*mode;
 {  char bmode[10];
    FILE *fp;
    strcpy(bmode,mode); strcat(bmode,"b");
/*    printf("bopening %s\n", name);*/
    fp = fopen(name,bmode);
/*    printf("FILE is %x\n", fp);*/
    return fp;
 }

/* osclose - close a file */
int osclose(fp) FILE *fp; {
/*    printf("closing FILE %x\n", fp);*/
    return (fclose(fp));}

/* osagetc - get a character from an ascii file */
int osagetc(fp) FILE *fp; {return (getc(fp));}

/* osaputc - put a character to an ascii file */
int osaputc(ch,fp) int ch; FILE *fp; {return (putc(ch,fp));}

extern int dbgflg;

/* osbgetc - get a character from a binary file */
/* int osbgetc(fp) FILE *fp; {return (getc(fp));} */
int osbgetc(fp) FILE *fp; {int c; c = (getc(fp));
/*	if (dbgflg) printf("osbgetc: got %d from FILE %x\n", c, fp);
 *	return c;
 */
}

/* osbputc - put a character to a binary file */
int osbputc(ch,fp) int ch; FILE *fp; {return (putc(ch,fp));}

#ifdef OLD_OSTGETC
/* ostgetc - get a character from the terminal */
int ostgetc()
{   int ch;

    switch (ch = getchar()) {
	case '\n':
		lbuf[lcount++] = '\n';
		lposition = 0;
		if (tfp)
		    for (lindex = 0; lindex < lcount; ++lindex)
			osaputc(lbuf[lindex],tfp);
		lindex = 0; lcount = 0;
		return (ch);
	case '\010':
	case '\177':
		if (lcount) {
		    lcount--;
		    while (lposition > lpos[lcount]) {
			lposition--;
		    }
		}
		break;
	case '\032':
		xflush();
		return (EOF);
	default:
		if (ch == '\t' || (ch >= 0x20 && ch < 0x7F)) {
		    lbuf[lcount] = ch;
		    lpos[lcount] = lposition;
		    if (ch == '\t')
			do {} while (++lposition & 7);
		    else {lposition++;}
		    lcount++;
		    return (ch);
		}
		else {
		    xflush();
		    switch (ch) {
		    case '\003':	xltoplevel();	/* control-c */
		    case '\007':	xlcleanup();	/* control-g */
		    case '\020':	xlcontinue();	/* control-p */
		    case '\032':	return (EOF);	/* control-z */

		    /* moved from oscheck until I figure out how to
		       set up interrupt to handle these two */
		    case '\002':	xflush(); xlbreak("BREAK",s_unbound);
					break;		/* control-b */
		    case '\024':	xinfo(); break;	/* control-t */

		    default:		return (ch);
		    }
		}
	}
}
#else
/* ostgetc - get a character from the terminal */
int ostgetc()
{   int ch;

    for (;;) {
	ch = getchar();
	oscheck();
	switch (ch) {
	  case '\003':	xltoplevel();	/* control-c */
	  case '\007':	xlcleanup();	/* control-g */
	  case '\020':	xlcontinue();	/* control-p */
	  case '\032':	return EOF;	/* control-z */
	  case '\002':	xflush(); xlbreak("BREAK",s_unbound);
			break;		/* control-b */
	  case '\024':	xinfo(); break;	/* control-t */
	  case '\t':
	  case '\n':
	  default:
	    if (tfp) osaputc(ch, tfp);
	    return ch;
	}
    }
}
#endif


/* ostputc - put a character to the terminal */
ostputc(ch) int ch;
 {     
    oscheck();		/* check for control characters */

    /* output the character */
    if (ch == '\n') {lposition = 0;}
    else	    {lposition++;}

    /* output the character to the transcript file */
    if (tfp) osaputc(ch,tfp);
    putchar(((char) ch));
 }

/* osflush - flush the terminal input buffer */
osflush() {lindex = lcount = lposition = 0;}

/* oscheck - check for control characters during execution */
oscheck()
{
#ifdef FOOBAZ
    int ch;
#endif
    if (ctc) {ctc=FALSE; ctcreset();
	      xflush(); xltoplevel(); return;} /* control-c */
#ifdef FOOBAZ
    if (ch = xcheck())
	switch (ch) {
	case '\002':	xflush(); xlbreak("BREAK",s_unbound);
			break;			/* control-b */
	case '\024':	xinfo(); break;		/* control-t */
	}
#endif

}

/* xinfo - show information on control-t */
LOCAL xinfo()
 {
    extern int nfree,gccalls;
    extern long total;
    char buf[80];

    sprintf(buf,"\n[ Free: %d, GC calls: %d, Total: %ld ]",
	    nfree,gccalls,total);
    errputstr(buf);
 }

/* xflush - flush the input line buffer and start a new line */
LOCAL xflush() {osflush(); ostputc('\n');}

/* xsystem - execute a system command */
LVAL xsystem()
{   /*LVAL strval;*/
    unsigned char *cmd;

    if (moreargs())
	cmd = (unsigned char *)getstring(xlgastring());
    xllastarg();
    return (system((char *) cmd) == -1 ? cvfixnum((FIXTYPE)errno) : s_true);
}


/* xgetkey - get a key from the keyboard */
LVAL xgetkey() {xllastarg(); return (cvfixnum((FIXTYPE)getchar()));}

/* ossymbols - enter os specific symbols */
ossymbols() {}
