/*  C K M T I O  --  interrupt, console, and port functions for Mac Kermit  */

/*
 Copyright (C) 1985, Trustees of Columbia University in the City of New York.
 Permission is granted to any individual or institution to use, copy, or
 redistribute this software so long as it is not sold for profit, provided this
 copyright notice is retained. 
*/

/*
 Variables:

   dftty  -- Pointer to default tty name string, like "/dev/tty".
   dfloc  -- 0 if dftty is console, 1 if external line.
   dfprty -- Default parity
   dfflow -- Default flow control
   ckxech -- Flag for who echoes console typein:
     1 - The program (system echo is turned off)
     0 - The system (or front end, or terminal).
   functions that want to do their own echoing should check this flag
   before doing so.

 Functions for assigned communication line (either external or console tty):

   ttopen(ttname,local,modem) -- Open the named tty for exclusive access.
   ttclos()                -- Close & reset the tty, releasing any access lock.
   ttpkt(speed,flow)       -- Put the tty in packet mode and set the speed.
   ttvt(speed,flow)        -- Put the tty in virtual terminal mode.
   ttinl(dest,max,timo)    -- Timed read line from the tty.
   ttinc(timo)             -- Timed read character from tty.
   ttchk()                 -- See how many characters in tty input buffer.
   ttxin(n,buf)            -- Read n characters from tty (untimed).
   ttol(string,length)     -- Write a string to the tty.
   ttoc(c)                 -- Write a character to the tty.
   ttflui()                -- Flush tty input buffer.

Functions for console terminal:

   congm()   -- Get console terminal modes.
   concb()   -- Put the console in single-character wakeup mode with no echo.
   conbin()  -- Put the console in binary (raw) mode.
   conres()  -- Restore the console to mode obtained by congm().
   conoc(c)  -- Unbuffered output, one character to console.
   conol(s)  -- Unbuffered output, null-terminated string to the console.
   conxo(n,s) -- Unbuffered output, n characters to the console.
   conchk()  -- Check if characters available at console.
   coninc()  -- Get a character from the console.
   conint()  -- Enable terminal interrupts on the console.
   connoi()  -- Disable terminal interrupts on the console.
   
Time functions

   msleep(m) -- Millisecond sleep
   ztime(&s) -- Return pointer to date/time string
*/

#include "ckcdeb.h"			/* Formats for debug() */
#include "ckmdef.h"			/* macintosh defs */
#include "mac/quickdraw.h"
#include "mac/osintf.h"
#include "mac/toolintf.h"		/* TE types defined here */

char *dftty = "";

/* dfloc is 0 if dftty is the user's console terminal, 1 if an external line */

int dfloc = 1;

/* Other defaults */

int dfprty = 0;				/* No parity */
int dfflow = 1;				/* Xon/Xoff flow control */

/* buffer and pointer for input processing */

#define TTBUFL 200			/* good size (it's RBUFL guys!) */
unsigned char ttbuf[TTBUFL+1];
int ttbufi = 0,
    ttbufm = 0;				/* input pointer, max */


/*  S Y S I N I T  --  System-dependent program initialization.  */

sysinit() {

/* for now, nothing... */

}

/*  T T O P E N  --  Open a tty for exclusive access.  */

/*  Returns 0 on success, -1 on failure.  */

ttopen(ttname,lcl,modem) char *ttname; int *lcl, modem; {
  ttbufi = ttbufm = 0;			/* init buffer */
  if (*lcl < 0) *lcl = 1;		/* always in local mode */
  return(0);
}


/*  T T C L O S  --  Close the TTY, releasing any lock.  */

ttclos()
{
  ttbufi = ttbufm = 0;			/* init buffer */  
  return;
}

/*  T T P K T  --  Condition the communication line for packets. */

/*  If called with speed > -1, also set the speed.  */

/*  Returns 0 on success, -1 on failure.  */

ttpkt(speed,flow)
int speed, flow;
{
    return(0);
}

/*  T T F L U I  --  Flush tty input buffer */

ttflui()
{
  int err;

  err = KillIO(-6);
  if (err)
    printerr("Bad input clear",err);
  ttbufi = ttbufm = 0;			/* init buffer */      
  return(0);
}


/* Interrupt Functions */

/* Set up terminal interrupts on console terminal */

conint(f)
int (*f)();
{					/* Set an interrupt trap. */
    return;
}

/* Reset console terminal interrupts */

connoi()
{
    return;
}

/*  T T O L  --  Similar to "ttinl", but for writing.  */

ttol(s,n)
char *s;
int n;
{
    int err;
    PLONG wrcnt;			/* pascal long */

    wrcnt = n;
    err = FSWrite(outnum,&wrcnt,s);
    if (err) printerr("Bad Writeout:",err);
    return(n);
}


/*  T T I N L  --  Read a record (up to break character) from comm line.  */
/*
  If no break character encountered within "max", return "max" characters,
  with disposition of any remaining characters undefined.  Otherwise, return
  the characters that were read, including the break character, in "dest" and
  the number of characters read as the value of function, or 0 upon end of
  file, or -1 if an error occurred.  Times out & returns error if not completed
  within "timo" seconds.
*/


ttinl(dest,max,timo,eol)
int max, timo;
char *dest, eol;
{
    register int x,c;

    for (x = c = 0; (x < max) && (c != eol); x++)
    {
      dest[x] = c = ttinc(timo);
      if (c < 0)
       return(-1);			/* timeout */
    }
    return(++x);			/* else return the count. */
}

/* ttinc(timo) - read a character with timeout.  Return -1 on timeout. */

/* DELAYTICKS is the dismiss value in 60th of a second when the input */
/* buffer goes empty.  Setting this value too small causes more overhead */
/* since we'll get very few character on the read.  Setting this value */
/* too large causes a slowdown if characters are on their way... */

#define DELAYTICKS 15			/* 15/60th of second retry */

ttinc(timo)
int timo;
{

    int avcnt, finaltics, intim=0, err;
  
    if (ttbufi < ttbufm) return(ttbuf[ttbufi++]);   /* Return char quickly */
     
/* Refill buffer with available bytes, if none left retry until timo */

    for (;;)
    {
	SerGetBuf(innum,&avcnt);	/* Get available count */        
	if (avcnt > 0)			/* Have something? */
	{
	    ttbufi = 0;			/* Init input buffer ptr */
	    ttbufm = (avcnt > TTBUFL) ? TTBUFL : avcnt; /* Set max */
	    err = FSRead(innum,&ttbufm,ttbuf);	/* Into our buffer */
	    if (err != noErr) printerr("Serial input error: ",err);
	    return(ttbuf[ttbufi++]);	/* And return first character */
	}
	if (protocmd != 0)		/* if we're running protocol */
	{
	  miniparser(TRUE);		/* keep mac running */
	  if (sstate == 'a')		/* abort occured? */
	   return(-1);			/* ugh, look like timeout */
	}
	Delay(DELAYTICKS,&finaltics);	/* Delay for a little */
	if (timo > 0)			/* Want to do timeout? */
	{				/* Yes... */
	    if (intim == 0)		/* Do we know time in? */
	    	intim = finaltics - DELAYTICKS;	/* no, initialize it */
	    if (intim+timo*60 < finaltics) return(-1);	/* Too long, give up */
	}
    }
}

ttchk()
{
  PLONG avcnt;				/* pascal long */

  SerGetBuf(innum,&avcnt);		/* get available */
  return(avcnt+(ttbufm-ttbufi));	/* return avail plus our own */
}

ttres()
{
    return(1);
}

/*  R T I M E R --  Reset elapsed time counter  */

rtimer() {
}


/*  G T I M E R --  Get current value of elapsed time counter in seconds  */

gtimer() {
    return(0);
}


/*  Z T I M E  --  Return date/time string  */

ztime(s)
char **s;
{
/***** Should call GetTime(daterec); and then convert by hand to a string */

    *s = "Unknown date/time";
}

/* Console IO routines.  The console is implemented as a text edit structure.
 * These routines are supported:
 *
 * conoc(c)   -- output one character to TE record at insertion point
 * conol(s)   -- output null terminated string to TE record " "
 * conoll(s)  -- same but with CR on the end 
 * conxo(n,s) -- n character to TE record " "
 *
 */

#define NILTE ((TEHandle ) NILPTR) 
#define LF 012
#define CR 015

TEHandle consoleTE = NILTE;		/* storage for console TE ptr */

consette(t)
TEHandle t;
{
  
 if (consoleTE != NILTE)		/* already have TE record */
  printerr("TE record present at consette! ",0);
 consoleTE = t;
}

/*  C O N O C  --  Output a character to the console text edit record */

conoc(c)
char c;
{
 int len = 1;

 debug(F101,"conoc here: ","",c);
 
 if (c == LF)				/* we don't support this */
  return;
 if (consoleTE != NILTE)		/* is it present? */
 {
/*  TEKey(c,consoleTE);			/* yes, simple */
  TEInsert(&c,len,consoleTE);		/* insert the char */  
  if (c == CR)				/* if CR */
   rcdwscroll();			/* then possibly scroll it */
 }
}

conopen()
{
 if (consoleTE == NILTE)
  printerr("Tried to open console before TE set",0);
 return(0);
}


/*  C O N O L  --  Write a line to the console text edit record  */

conol(s)
char *s;
{
  int len = strlen(s);			/* fetch length */
  
 debug(F101,"conol here: ",s,0);  
 if (consoleTE != NILTE)		/* is it present? */  
  TEInsert(s,len,consoleTE);		/* insert the string */
 return(0);
}

conxo(s,len)
char *s;
{
 debug(F101,"conxo here: ",s,len);    
 if (consoleTE != NILTE)		/* is it present? */  
  TEInsert(s,len,consoleTE);		/* insert the string */
 return(0);
}

/*  C O N O L L  --  Output a string followed by CRLF  */

conoll(s)
char *s;
{
  conol(s);				/* first the string */
  conoc(CR);				/* now the return */
  return(0);
}

