/* -> c.ckatio
 */

/*  C K A T I O  */

#include "ckcdeb.h"
#ifdef ANSI
#include <signal.h>
#include <time.h>
#include "ckatio.h"
#include "ckafio.h"
#include "ckamis.h"
#include <string.h>
#endif

#ifdef ARTHUR
#include "plib.h"
#endif

#ifdef ARTHUR
#define SIGQUIT SIGTERM
#endif

#ifdef PANOS
extern int XSetEventStatus() asm;
#define SIGon 1
#define SIGoff 0
extern     XStandardTime() asm;
extern     XCloseStream() asm;
extern     XSFlushOutput() asm;
extern int XSWriteByte() asm; 
extern int XSBlockWrite() asm;
extern int XSBlockRead() asm;
extern int XSReadByte() asm;
extern int XBytesOutstanding() asm;
extern int XFindInput() asm;
extern int XFindOutput() asm;
#endif

char *ckxv   = "Arthur tty I/O, July 23 1985";
char *ckxsys = "Acorn Computers Arthur";

/* C-Kermit interrupt, terminal control & i/o functions for Arthur */

/*
Author: Graham Toal & Richard Cownie, VLSI Tools Group (graham%acorn@ukc)
Copyright (C) 1986, Acorn Computers Plc

Based on originial code & interface by: Frank da Cruz (SY.FDC@CU20B),
Columbia University Center for Computing Activities, January 1985.
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. 

Modified by Cosmos Nicolaou 26/8/87 to run over Arthur 

*/

/*
 Variables available to outside world:

  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.
  backgrd -- Flag indicating program executing in background
              - not applicable

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

  ttopen(ttname,local,mdmtyp) -- Open the named tty for exclusive access.
  ttclos()               -- Close & reset the tty, releasing any access lock.
  tthang()               -- Hangup phone line
  ttsndb()               -- Send a break signal
  ttpkt(speed,flow)      -- Put the tty in packet mode and set the speed.
  ttvt(speed,flow)       -- Put the tty in virtual terminal mode.
        or in DIALING or CONNECTED modem control state.
  ttres()                -- Restore terminal to normal 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(esc) -- Put the console in single-character wakeup mode with no echo.
  conbin(esc) -- 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.
  conoll(s) -- Unbuffered output, string + CR LF to the console.
  conola(s) -- Unbuffered output, array of strings to the console.
  conxo(n,s) -- Unbuffered output, n characters to the console.
  conchk()  -- Check if characters available at console (bsd 4.2).
    Check if escape char (^\) typed at console (System III/V).
  coninc(timo)  -- Timed get a character from the console.
  conin()   -- untimed get from console (new)
  conint()  -- Enable terminal interrupts on the console if not background.
  connoi()  -- Disable terminal interrupts on the console if not background.

Time functions

  msleep(m) -- Millisecond sleep
  ztime(&s) -- Return pointer to date/time string
*/


/* Declarations */

#include <stdio.h>

    char *dftty = "RS423:";             /* dftty is the device name of
                                           the default device for file
                                           transfer */
    int dfloc = 1;                      /* dfloc: 0 if dftty is the user's
                                           console terminal, 1 if an
                                           external line */
    int dfprty = 0;         /* Parity (0 = none) */
    int dfflow = 1;         /* Xon/Xoff flow control */
    int backgrd = 0;            /* Assume in foreground (no '&' ) */

    int ckxech = 0;                     /* 0 if system normally echoes 
                                           console characters, else 1 */
 /* Arthur - changed from 0 to -1 */
    int hostin = -1;
    int hostout = -1; /* Handles to RS423: in each direction. */
    int OldMode;      /* old ckxech */
    int ConsoleIn = -1;
    int ConsoleOut = -1; /* Currently selected console IO streams */
    int OldConsoleIn;    /* Save-variable for changing stdin from
                             raw to cooked... */
    int rawkb;
    int filteredkb;     /* handles to raw & filtered kb streams */

#ifdef ANSI
static int
    conif = 0, conesc = 0;  /* conesc - has <esc> been typed? */
#else
static int
    conif = 0; conesc = 0;  /* conesc - has <esc> been typed? */
#endif

/*******************************************************/
/*  T T O P E N  --  Open a tty for exclusive access.  */
/*  Returns 0 on success, -1 on failure.               */
/*******************************************************/

#ifdef ANSI
int
#endif
ttopen(ttname,lcl,modem) char *ttname; int *lcl, modem; {
/*
  If called with lcl < 0, sets value of lcl as follows:
  0: the terminal named by ttname is the job's controlling terminal.
  1: the terminal named by ttname is not the job's controlling terminal.
*/
  hostin  = XFindInput(ttname, strlen(ttname));
  hostout = XFindOutput(ttname, strlen(ttname));
  if ((hostin > 0) && (hostout > 0)) {
    *lcl = 1;      /* RS423: <> TT: */
    return(0);
  } else {
    return(-1);
  }
}

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

#ifdef ANSI
void
#endif
ttclos() {
    if (hostin >= 0)
    {
        XCloseStream(hostin);
        hostin = -1;
    }

    if (hostout >= 0)
    {
        XCloseStream(hostout);
        hostout = -1;
    }
  
}

/*************************************/
/*  T T H A N G -- Hangup phone line */
/*************************************/
#ifdef ANSI
void
#endif
tthang() {}

/*******************************************************/
/*  T T R E S  --  Restore terminal to "normal" mode.  */
/*******************************************************/
#ifdef ANSI
void
#endif
ttres() {}

/*****************************************************************/
/*  T T P K T  --  Condition the communication line for packets. */
/*                 or for modem dialing                          */
/*  If called with speed > -1, also set the speed.               */
/*  Returns 0 on success, -1 on failure.                         */
/*****************************************************************/

#ifdef ANSI
int
#endif
ttpkt(speed,flow) int speed, flow; {
  if (speed > -1) setbaud(speed);
  return(0);
}

/*************************************************************************/
/*  T T V T -- Condition communication line for use as virtual terminal  */
/*************************************************************************/

#ifdef ANSI
void
#endif
ttvt(speed,flow) int speed, flow; {
  if (speed > -1) setbaud(speed);
}

/********************************************/
/*  T T F L U I  --  Flush tty input buffer */
/********************************************/

#ifdef ANSI
void
#endif
ttflui() {
  /* loop around testing XBytesOutstanding() until none left */
  while (XBytesOutstanding(hostin) > 0) XSReadByte(hostin);
}

/***********************************************/
/*  C O N I N T  --  Console Interrupt setter  */
/***********************************************/

#ifdef ANSI
void
#endif
#ifdef ANSI
esctrp( i ) int i; {                      /* trap console escapes */
#else
esctrp() {                       /* trap console escapes */
#endif
    conesc = 1; signal(SIGQUIT,0);
}

#ifdef ANSI
void
#endif
#ifdef ANSI
conint(f) void (*f)(); {         /* Set an interrupt trap. */
#else
conint(f) int (*f)(); {         /* Set an interrupt trap. */
#endif
    signal(SIGINT, &esctrp);       /* console escape in pkt modes */
    conesc = 0;                      /* clear out pending escapes */
    signal(SIGQUIT, f);           /* Function to trap to. */
    conif = 1;             /* Flag console interrupts on. */
}

/*******************************************************/
/*  C O N N O I  --  Reset console terminal interrupts */
/*******************************************************/

#ifdef ANSI
void
#endif
connoi() {
  signal(SIGQUIT, 0);
  conif = 0;
}

/****************************************************************************/
/*  T T C H K  --  Tell how many characters are waiting in tty input buffer */
/****************************************************************************/

#ifdef ANSI
int
#endif
ttchk() {
  return(XBytesOutstanding(hostin));
}

/***********************************************************/
/*  T T X I N  --  Get n characters from tty input buffer  */
/***********************************************************/

#ifdef ANSI
void
#endif
ttxin(n,buf) int n; char *buf; {
  /* XSBlockRead(hostin, n, buf); may not work in Arthur v1.1 */
#ifdef ANSI
  while (n-- > 0) *buf++ = XSReadByte(hostin);
#else
  while (n-- > 0) XSReadByte(hostin, *buf++);
#endif
}

/*******************************************************/
/*  T T O L  --  Similar to "ttinl", but for writing.  */
/*******************************************************/

#ifdef ANSI
void
#endif
ttol(s,n) int n; char *s; {

  XSBlockWrite(hostout, n, s); /*may not work in Arthur v1.1 */
/*  while (n-- > 0) XSWriteByte(hostout, *s++);*/
  XSFlushOutput(hostout);
}

/***************************************************************/
/*  T T O C  --  Output a character to the communication line  */
/***************************************************************/

#ifdef ANSI
void
#endif
ttoc(
#ifdef ANSI
char c)
#else
c) char c;
#endif
{
  XSWriteByte(hostout, c); XSFlushOutput(hostout);
}

/**************************************************************************/
/*  T T I N L  --  Read a record (up to break character) from comm line.  */
/**************************************************************************/

#ifdef ANSI
int
#endif
ttinl(dest,max,timo,eol) int max,timo,eol; char *dest; 
{
/*
  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.
*/
  int zone, ch, i, j, n, ngot = 0;
  timeval start,now;
  if (timo) gettimeofday(&start, &zone);
  if (max == 0) return(0);
  for (;;) {
    for (i = 0; i < 16; i++) {
      n = XBytesOutstanding(hostin);
      for (j = 0; j < n; j++) {
        if ((dest[ngot++] = XSReadByte(hostin)) == eol) return(ngot);
    if (ngot >= max) return(ngot);
      }
    }
    if (timo) {
      gettimeofday(&now, &zone);
      if (timerdiff(start, now) > (100*timo)) return(-1); /* timed out */
    }
  }
}

/****************************************************************/
/*  T T I N C --  Read a character from the communication line  */
/****************************************************************/

#ifdef ANSI
int
#endif
ttinc(timo) int timo; 
{
  int zone,j; timeval start,now;
  if (timo) gettimeofday(&start, &zone);
  for(;;) {
    for(j = 0; j < 32; j++) {
      if (XBytesOutstanding(hostin)) return(XSReadByte(hostin)); /* got ch */
    }
    if (timo) {
      gettimeofday(&now, &zone);
      if (timerdiff(start, now) > (100*timo)) return(-1); /* timed out */
    }
  }
}

/******************************************/
/*  T T S N D B  --  Send a BREAK signal  */
/******************************************/

#ifdef ANSI
void
#endif
ttsndb() {}

/******************************************************/
/*  M S L E E P  --  Millisecond version of sleep().  */
/******************************************************/

#ifdef ANSI
int
#endif
msleep(m) int m; 
{
  int zone; timeval start,now;
  gettimeofday(&start, &zone);
  for(;;) {
    gettimeofday(&now, &zone);
    if ((10 * timerdiff(start, now)) > m) return(0);
  }
}

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

#ifdef ANSI
void
#endif
ztime(s) char **s; 
{ static char timestring[32];
  XStandardTime(timestring, 32); *s = timestring;
}

/************************************************/
/*  C O N G M  --  Get console terminal modes.  */
/************************************************/

#ifdef ANSI
void
#endif
congm() {
/*
 Saves current console mode, and establishes variables for switching between 
 current (presumably normal) mode and other modes.
*/
/* Arthur version does this by assigning stdout to local saved copy */
#ifndef ARTHUR
/* What's the point when there is no difference in mode! */
OldConsoleIn = ConsoleIn;
#endif
OldMode = ckxech;
}

/***********************************************/
/*  C O N C B --  Put console in cbreak mode.  */
/***********************************************/

#ifdef ANSI
int
#endif
concb(
#ifdef ANSI
char esc)
#else
esc) char esc;
#endif
{

#ifdef ARTHUR
  if( ConsoleIn == -1 )
    ConsoleIn = XFindInput("RAWKB:", 6);

  if( ConsoleOut == -1 )
    ConsoleOut = XFindOutput("VDU:", 4);

#else
  ConsoleIn = XFindInput("RAWKB:", 6);
  ConsoleOut = XFindOutput("VDU:", 4);
#endif

  ckxech = 1; /* no echo */
  return(0);
}

/*************************************************/
/*  C O N B I N  --  Put console in binary mode  */
/*************************************************/

#ifdef ANSI
int
#endif
conbin(
#ifdef ANSI
char esc)
#else
esc) char esc;
#endif
{

#ifdef ARTHUR
  if( ConsoleIn == -1 )
    ConsoleIn = XFindInput("RAWKB:", 6);

  if( ConsoleOut == -1 )
    ConsoleOut = XFindOutput("VDU:", 4);
#else
  ConsoleIn = XFindInput("RAWKB:", 6);
  ConsoleOut = XFindOutput("VDU:", 4);
#endif

  ckxech = 1; /* No echo */
  return(0);
}

/***************************************************/
/*  C O N R E S  --  Restore the console terminal  */
/***************************************************/

#ifdef ANSI
int
#endif
conres() {
#ifndef ARTHUR
/* What's the point when there is no difference in mode! */
  ConsoleIn = OldConsoleIn;
#endif
  ckxech = OldMode;
  return(0);
}

/***************************************************************/
/*  C O N O C  --  Output a character to the console terminal  */
/***************************************************************/

#ifdef ANSI
void
#endif
conoc(
#ifdef ANSI
char c)
#else
c) char c;
#endif
{
  XSWriteByte(ConsoleOut, c); XSFlushOutput(ConsoleOut);
}

/***************************************************************/
/*  C O N X O  --  Write x characters to the console terminal  */
/***************************************************************/

#ifdef ANSI
void
#endif
conxo(x,s) char *s; int x; {
  XSBlockWrite(ConsoleOut, x, s); XSFlushOutput(ConsoleOut);
}

/*********************************************************/
/*  C O N O L  --  Write a line to the console terminal  */
/*********************************************************/

#ifdef ANSI
void
#endif
conol(s) char *s; {
  conxo(strlen(s), s);
}

/*********************************************************************/
/*  C O N O L A  --  Write an array of lines to the console terminal */
/*********************************************************************/

#ifdef ANSI
void
#endif
conola(s) char *s[]; {
  int i;
  for (i=0; *s[i]; i++) conol(s[i]);
}

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

#ifdef ANSI
void
#endif
conoll(s) char *s; {
  conol(s); conoc('\r'); conoc('\n');
}

/***************************************************************/
/*  C O N C H K  --  Check if characters available at console  */
/***************************************************************/

#ifdef ANSI
int
#endif
conchk() {
  if (conesc) { conesc = 0; return(1); }
  return(XBytesOutstanding(ConsoleIn));
}

/*******************************************************/
/*  C O N I N C  --  Get a character from the console  */
/*******************************************************/

#ifdef ANSI
int
#endif
coninc(timo) int timo; 
{
  int zone,j; timeval start,now;
  if (timo) gettimeofday(&start, &zone);
  for(;;) {
    for(j = 0; j < 32; j++) { if (conchk()) return(conin()); }
    if (timo) {
      gettimeofday(&now, &zone);
      if (timerdiff(start, now) > (100*timo)) return(-1); /* timed out */
    }
  }
}

/*******************************************************/
/*  C O N I N    --  Get a character from the console  */
/*******************************************************/

#ifdef ANSI
int
#endif
conin() {
  return(XSReadByte(ConsoleIn));
}
