/* screenio.c - 16:00 GMT +10:00 Wed 4 Aug 1993 - modifier Geoffrey Tobin */

/* From input file "../include/globals.p" */

#include "config.h"
#include "globals.h"
#include "screenio.h"
#include "unixio.h"
#include "vdu.h"

/* Variables Exported, via "screenio.h" */

Char TeXtoASCII[XXX];


/* IMPORT InitVDU, LogClearScreen, StartText, ClearScreen, ResetVDU.
   To handle ^Z suspension properly, ScreenIO needs to use some VDU routines.
*/

/* SYSDEP: We need to use the Unix write routine.
   In particular, using Pascal's write/writeln has some nasty side-effect
   that prevents BusyRead from working!
*/

int textlinewidth;    /* text characters (columns) per line */
int textcolumn = 0;   /* column number in current text line */

/******************************************************************************/

#ifdef __STDC__
int MesgChar (int ch)
#else
int MesgChar (ch)
  int ch;
#endif
{
  int status = 0;
  /* maxcol <= both size of a string, and width of a line */
  int maxcol = (maxstring < textlinewidth ? maxstring : textlinewidth);

  /* Keep messages within maxcol columns */
  if (textcolumn >= maxcol)
    status = EOF;
  else
  {
    if (vdu_unixio) 
      status = putchar (ch);
    else
      WriteTextChar (ch);
    if (logfile != NULL)
      putc (ch, logfile);

    ++ textcolumn;
  }
#ifdef COLUMN_LOG
  fflush (logfile);
  fprintf (logfile, "%% MesgChar:  textcolumn = %d\n", textcolumn);
  fflush (logfile);
#endif
  return status;
}
/* MesgChar */

/******************************************************************************/

#ifdef __STDC__
int MesgString (const char * s)
#else
int MesgString (s)
  char * s;
#endif
{
  int i, status = 0;
  string message;
  /* maxcol <= both size of a string, and width of a line */
  int maxcol = (maxstring < textlinewidth ? maxstring : textlinewidth);

  /* Keep messages within maxcol columns */
  if (textcolumn < 0 || textcolumn >= maxcol)
  {
    strcpy (message, "");
    if (logfile != NULL)
    {
      fprintf (logfile,
        "textcolumn = %d : must be 0 <= textcolumn < maxcol = %d\n",
        textcolumn, maxcol);
    }
  }
  else
  {
    strncpy (message, s, maxcol-textcolumn);
    message[maxcol-textcolumn] = '\0';
  }

  if (vdu_unixio) 
    status = fputs(message, stdout);
  else 
    for (i = 0; message[i] != '\0'; i++)
      WriteTextChar (message[i]);

  if (logfile != NULL)
    fputs (message, logfile);

  textcolumn += strlen (message);
#ifdef COLUMN_LOG
  fflush (logfile);
  fprintf (logfile, "%% MesgString:  textcolumn = %d\n", textcolumn);
  fflush (logfile);
#endif
  return status;
}
/* MesgString */

/******************************************************************************/

int MesgFlush (VOID)
{
  int status = fflush (stdout);
  textcolumn = 0;

  if (logfile != NULL)
  {
    fflush (logfile);
#ifdef COLUMN_LOG
    fprintf (logfile, "%% MesgFlush:  textcolumn = %d\n", textcolumn);
    fflush (logfile);
#endif
  }
  return status;
}
/* MesgFlush */

/******************************************************************************/

Void MesgLine (VOID)
{
  save_temp_tty();
  rawoutoff();   /* Enable NL to CR+LF mapping */
  if (vdu_unixio)
    putchar (CR); /* SYSDEP:  Really an NL */
  else
    WriteTextChar (CR);
  if (logfile != NULL)
    fprintf (logfile, "\n");
  MesgFlush();   /* MesgLine also updates terminal */
  restore_temp_tty();
}
/* MesgLine */

/******************************************************************************/

#ifdef __STDC__
Static int MesgCard (int c)
#else
Static int MesgCard (c)
    int c;
#endif
{
  /* Since the vast majority of given values will be small numbers, we avoid
     recursion until c >= 100.
  */

  int len = 0;
  if (c < 10)
  {
    MesgChar (c + '0');
    ++ len;
  }
  else if (c < 100)
  {
    MesgChar (c / 10 + '0');
    MesgChar (c % 10 + '0');
    len += 2;
  }
  else  /* c >= 100 */
  {
    len += MesgCard (c / 100);   /* recursive if c >= 100 */
    c %= 100;
    MesgChar (c / 10 + '0');
    MesgChar (c % 10 + '0');
    len += 2;
  }
  return (len);
}
/* MesgCard */

/******************************************************************************/

#ifdef __STDC__
int MesgInt (int i)
#else
int MesgInt (i)
    int i;
#endif
{
  int len = 0;
  if (i < 0)
  {
    MesgChar ('-');
    ++ len;
    i = abs (i);
  }
  len += MesgCard (i);
  return (len);
}
/* MesgInt */

/******************************************************************************/

Void WriteLine (VOID)
{
  WriteChar (CR);
  WriteFlush();   /* WriteLine also updates terminal */
}
/* WriteLine */

/******************************************************************************/

#ifdef __STDC__
Static Void WriteCard (int c)
#else
Static Void WriteCard (c)
    int c;
#endif
{
  /* Since the vast majority of given values will be small numbers, we avoid
     recursion until c >= 100.
  */

  if (c < 10)
  {
    WriteChar (c + '0');
    return;
  }
  if (c < 100)
  {
    WriteChar (c / 10 + '0');
    WriteChar (c % 10 + '0');
    return;
  }
  else
  {
    WriteCard (c / 100);   /* recursive if c >= 100 */
    c %= 100;
    WriteChar (c / 10 + '0');
    WriteChar (c % 10 + '0');
  }
}
/* WriteCard */

/******************************************************************************/

#ifdef __STDC__
Void WriteInt (int i)
#else
Void WriteInt (i)
    int i;
#endif
{
  if (i < 0)
  {
    WriteChar ('-');
    i = abs (i);
  }
  WriteCard (i);
}
/* WriteInt */

/******************************************************************************/

static Void Restore_Temp_Terminal (VOID)
{
  /* Restore_Temp_Terminal is for screenio.c only. */

  MesgFlush();   /* make sure terminal is up-to-date */
  restore_temp_tty();   /* restore terminal characteristics saved below */
}
/* Restore_Temp_Terminal */

/******************************************************************************/

Void RestoreTerminal (VOID)
{
  /* RestoreTerminal restores the initial terminal setting. */
  /* It should be called before any client module terminates. */

  MesgFlush();   /* make sure terminal is up-to-date */
  restore_init_tty();   /* restore terminal characteristics saved below */
}
/* RestoreTerminal */

/******************************************************************************/

Void BreakGraphics (VOID)
{
    StartText();
    LogClearScreen();
    MesgLine();
    ResetVDU();
    Restore_Temp_Terminal();
  }

Void RestoreGraphics (VOID)
{
    save_temp_tty();
    singlecharon();
    rawouton();
    echooff();
    InitVDU();
    StartText();
    LogClearScreen();
  }

/******************************************************************************/

#ifdef __STDC__
Void ReadChar (Char *ch)
#else
Void ReadChar (ch)
    Char * ch;
#endif
{
  /* gt - if cbreak's off, turn it on */
  if (cmode_flags.cbreak == 0)
    singlecharon();

  /* gt - if echo's on, turn it off */
  if (cmode_flags.echo == 1)
    echooff();

  /* gt - at this point, we need singlechar (cbreak) on and echo off. */
  /* gt - BUT WHY? */

  /* check for CTRL-C or CTRL-Z */

  /* Interrupted by user?  (CTRL-C) */
  if (sig_flags.intr)   /* echo ch since echooff has been called */
  {
    /* interrupt */
    sig_flags.intr = 0;   /* reset intr flag */
    *ch = CR;   /* return to "Command: " prompt level */
  }
  else if (sig_flags.tstop)  /* Suspended by user? (CTRL-Z) */
  {
    /* suspend */
    sig_flags.tstop = 0;   /* reset tstop flag */

/*    StartText();
    LogClearScreen();
    MesgLine();
    ResetVDU();
    Restore_Temp_Terminal();*/

    BreakGraphics ();
    suspend();
    RestoreGraphics ();

/*    save_temp_tty();

    singlecharon();
    rawouton();
    echooff();

    InitVDU();
    StartText();
    LogClearScreen(); */

    *ch = CR;   /* return to Command: level */
  }
  else
  {
    if (vdu_unixio) 
      (void) putchar (*ch = getchar());
    else
      WriteTextChar (*ch = getchar());
    if (logfile != NULL)
      putc (*ch, logfile);
  }
}
/* ReadChar */

/******************************************************************************/

#ifdef __STDC__
Void ReadString (Char *s)
#else
Void ReadString (s)
    Char * s;
#endif
{
  /* Read a string of characters.
     The routine is terminated upon carriage return.
  */

  Char ch;
  int i;

  if (vdu_unixio) {
    singlecharoff();   /* read string in cooked mode */
    rawoutoff();
    echoon();          /* echo characters */
    
    for (i=0;  true;  i++)
      {
	if (sig_flags.intr)
	  {
	    /* interrupt */
	    sig_flags.intr = 0;  /* reset intr flag */
	    s[0] = '\0';
	    printf("BREAK\n");
	    break;
	  }
	if (sig_flags.tstop)
	  {
	    /* suspend */
	    sig_flags.tstop = 0;  /* reset tstop flag */
	    
/*	    StartText();
	    LogClearScreen();
	    MesgLine();
	    ResetVDU();
	    Restore_Temp_Terminal(); */

	    printf("STOP\n");

            BreakGraphics ();
            suspend();
	    RestoreGraphics ();
	    
/*	    suspend();
	    save_temp_tty(); */
	    /* singlecharon and echooff are called below */
	    
/*	    InitVDU();
	    StartText();
	    LogClearScreen();*/
	    
	    s[0] = '\0';
	    break;
	  }
	ch = getchar();
	if (ch == CR)
	  {
	    s[i] = 0;
	    if (logfile != NULL)
	      fprintf (logfile, "\n");
	    break;
	  }
	s[i] = ch;
	if (logfile != NULL)
	  putc (ch, logfile);
	if (i == maxstring)
	  {
	    s[i] = '\0';
	    break;
	  }
      }
    singlecharon();   /* return to cbreak mode */
    rawouton();
    echooff();        /* and no echo */
  } else {
    ReadTextString(s);
  }
}
/* ReadString */

/******************************************************************************/

#ifdef __STDC__
boolean BusyRead (Char *ch)
#else
boolean BusyRead (ch)
    Char * ch;
#endif
{
  /* Return TRUE if ch is waiting in input buffer or if a ^C or ^Z has been
     typed.  Set ch to CR or the character read (no echo).
     If nothing in input buffer, then ch is undefined and we return FALSE.
  */

    if (sig_flags.intr)
    {
      /* interrupt */
      sig_flags.intr = 0;
      *ch = CR;   /* main module will return to Command: level */
      return true;
    }
    if (sig_flags.tstop)
    {
      /* suspend */
      sig_flags.tstop = 0;

      StartText();
      LogClearScreen();
      MesgLine();
      ResetVDU();
      Restore_Temp_Terminal();

      suspend();
      save_temp_tty();
      /* singlecharon and echooff are called below */

      InitVDU();
      StartText();
      LogClearScreen();

      *ch = CR;   /* after suspend, return to Command: level */
      return true;
    }
  /* SYSDEP: buffercount assumes singlecharon and echooff have been called */

  /* gt - check whether singlecharon and echooff have been called */

  if (cmode_flags.cbreak == 0)
    singlecharon();

  if (cmode_flags.echo == 1)
    echooff();

  if (buffercount() == 0)
    return false;
  else
  {
    *ch = getchar();
    if (logfile != NULL)
      putc (*ch, logfile);
    return true;
  }
}
/* BusyRead */

/******************************************************************************/

Static Void InitTeXtoASCII (VOID)
{
  /* Initialize TeXtoASCII array used in specific ShowChar/Rectangle routines
     to map a given TeX char into a similar, displayable ASCII char.
  */

  int i;

  for (i = 0; i <= 0xa; i++)   /* Greek letters */
    TeXtoASCII[i] = '?';
  for (i = 0xb; i <= 0xf; i++)   /* ligatures */
    TeXtoASCII[i] = '?';
  TeXtoASCII[0x10] = 'i';   /* dotless i */
  TeXtoASCII[0x11] = 'j';   /* dotless j */
  TeXtoASCII[0x12] = '`';   /* grave accent */
  TeXtoASCII[0x13] = '\'';   /* acute accent */
  for (i = 0x14; i <= 0x17; i++)   /* high accents */
    TeXtoASCII[i] = '~';
  TeXtoASCII[0x18] = ',';   /* cedilla */
  for (i = 0x19; i <= 0x20; i++)   /* foreigns */
    TeXtoASCII[i] = '?';
  for (i = 0x21; i <= 0x5b; i++)   /* same */
    TeXtoASCII[i] = i;
  TeXtoASCII[0x5c] = '"';   /* open dble quote */
  TeXtoASCII[0x5d] = ']';   /* same */
  for (i = 0x5e; i <= 0x5f; i++)   /* more accents */
    TeXtoASCII[i] = '^';
  for (i = 0x60; i <= 0x7a; i++)   /* same */
    TeXtoASCII[i] = i;
  for (i = 0x7b; i <= 0x7c; i++)   /* en & em dash */
    TeXtoASCII[i] = '-';
  for (i = 0x7d; i <= 0x7f; i++)   /* more accents */
    TeXtoASCII[i] = '~';
  for (i = 0x80; i <= 0xff; i++)   /* non-ASCII, but 8-bit: 128 to 255 */
    TeXtoASCII[i] = '?';
}
/* InitTeXtoASCII */

/******************************************************************************/

Void InitScreenIO (VOID)
{
  InitTeXtoASCII();
  /* We first save the current terminal characteristics.
     save_init_tty also calls save_temp_tty, which
     sets up ^C/^Z interrupt handlers; see unixio.c.
  */
  save_init_tty();
  singlecharon();   /* cbreak mode for ReadChar and BusyRead */
  echooff();   /* no echo for BusyRead */
  rawouton();
  if (setvbuf (stdout, NULL, _IOFBF, BUFSIZ/4) != 0)
  {
    MesgString ("screenio.c: InitScreenIO: setvbuf failed!");
    MesgLine();
  }
}
/* InitScreenIO */

/*****************************************************************************/

#ifdef __STDC__
Void FatalError (const char * s)
#else
Void FatalError (s)
  char * s;
#endif
{
  StartText();
  ResetVDU();  /* let message stay */

  MesgString (s);
  MesgLine();

  RestoreTerminal();
  exit (1);
}

/*****************************************************************************/
/* end screenio.c */
