/* screenio.c - display functions
   $Id: screenio.c,v 0.2 1997/03/28 03:17:23 tjchol01 Exp $
   Authors: Andrew Trevorrow, Ian Dall, Geoffrey Tobin, Tomasz J. Cholewo
 */

#include "dvgt.h"
#include "screenio.h"
#include "unixio.h"
#include "vdu.h"

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

char TeXtoASCII[XXX];


/* IMPORT InitVDU, ClearScreen, 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 */

/*--------------------------------------------------------------------*/

int 
MesgChar (int ch)
{
  int status;
  /* 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
    {
      status = putchar (ch);
      ++textcolumn;
    }
  return status;
}
/* MesgChar */

/*--------------------------------------------------------------------*/

int 
MesgString (const char *s)
{
  int status;
  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, "");
    }
  else
    {
      strncpy (message, s, maxcol - textcolumn);
      message[maxcol - textcolumn] = '\0';
    }

  status = fputs (message, stdout);
  textcolumn += strlen (message);
  return status;
}
/* MesgString */

/*--------------------------------------------------------------------*/

int 
MesgFlush ()
{
  int status = fflush (stdout);
  textcolumn = 0;
  return status;
}
/* MesgFlush */

/*--------------------------------------------------------------------*/

void 
MesgLine ()
{
  save_temp_tty ();
  rawoutoff ();			/* Enable NL to CR+LF mapping */
  /*!!!    putchar (CR); *//* SYSDEP:  Really an NL */
  putchar ('\r');		/* SYSDEP:  Really an NL */
  putchar ('\n');		/* SYSDEP:  Really an NL */
  MesgFlush ();			/* MesgLine also updates terminal */
  restore_temp_tty ();
}
/* MesgLine */

/*--------------------------------------------------------------------*/

static int 
MesgCard (int c)
{
  /* 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 */

/*--------------------------------------------------------------------*/

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

/*--------------------------------------------------------------------*/

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

/*--------------------------------------------------------------------*/

static void 
WriteCard (int c)
{
  /* 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 */

/*--------------------------------------------------------------------*/

void 
WriteInt (int i)
{
  if (i < 0)
    {
      WriteChar ('-');
      i = abs (i);
    }
  WriteCard (i);
}
/* WriteInt */

/*--------------------------------------------------------------------*/

static void 
Restore_Temp_Terminal ()
{
  /* 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 ()
{
  /* 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 
ReadChar (char *ch)
{
  /* gt - if cbreak's off, turn it on */
  singlecharon ();
  /* gt - if echo's on, turn it off */
  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 ();
      ClearScreen ();
      MesgLine ();
      ResetVDU ();
      Restore_Temp_Terminal ();

      suspend ();
      save_temp_tty ();

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

      InitVDU ();
      StartText ();
      ClearScreen ();

      *ch = CR;			/* return to Command: level */
    }
  else
    {
      putchar (*ch = getchar ());
    }
}
/* ReadChar */

/*--------------------------------------------------------------------*/

void 
ReadString (char *s)
{
  /* Read a string of characters.
     The routine is terminated upon carriage return.
   */

  char ch;
  int i;

  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';
	  break;
	}
      if (sig_flags.tstop)
	{
	  /* suspend */
	  sig_flags.tstop = 0;	/* reset tstop flag */

	  StartText ();
	  ClearScreen ();
	  MesgLine ();
	  ResetVDU ();
	  Restore_Temp_Terminal ();

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

	  InitVDU ();
	  StartText ();
	  ClearScreen ();

	  s[0] = '\0';
	  break;
	}
      ch = getchar ();
      if (ch == CR)
	{
	  s[i] = '\0';
	  break;
	}
      s[i] = ch;
      if (i == maxstring)
	{
	  s[i] = '\0';
	  break;
	}
    }
  singlecharon ();		/* return to cbreak mode */
  rawouton ();
  echooff ();			/* and no echo */
}
/* ReadString */

/*--------------------------------------------------------------------*/

boolean 
BusyRead (char *ch)
{
  /* 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 ();
      ClearScreen ();
      MesgLine ();
      ResetVDU ();
      Restore_Temp_Terminal ();

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

      InitVDU ();
      StartText ();
      ClearScreen ();

      *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 ();
      return true;
    }
}
/* BusyRead */

/*--------------------------------------------------------------------*/

static void 
InitTeXtoASCII ()
{
  /* 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 ()
{
  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 ();
  atexit (RestoreTerminal);

  singlecharon ();		/* cbreak mode for ReadChar and BusyRead */
  echooff ();			/* no echo for BusyRead */
  rawouton ();
  /* was _IOFBF */
#ifdef SETVBUF_REVERSED
  if (setvbuf (stdout, _IONBF, NULL, BUFSIZ / 4) != 0)
    {
#else
  if (setvbuf (stdout, NULL, _IONBF, BUFSIZ / 4) != 0)
    {
#endif
      MesgString ("screenio.c: InitScreenIO: setvbuf failed!");
      MesgLine ();
    }
}
/* InitScreenIO */

/*--------------------------------------------------------------------*/

/* end screenio.c */