/*
 * term.c: all the routines we need to do our stuff with the screen.
 *
 * Copyright(c) 1997,1998 - All Rights Reserved
 *
 * See the COPYRIGHT file.
 */

#ifndef lint
static char rcsid[] = "@(#)$Id: term.c,v 1.13 1998/06/12 22:42:34 kalt Exp $";
#endif

#include "os.h"

#include "term.h"

int		tty_fd;
struct termios	oldattr, newattr;

int	LI, CO, SG		/* number of garbage chars left by so or se */;
char    *CM,			/* screen-relative cursor motion */
	*CE,			/* clear to end of line */
	*CL,			/* clear screen and home cursor */
	*CR,			/* carriage return character */
	*NL,			/* newline character */
#ifdef NEED_ALTERNATE_SCOLL_FUNCTION
	*AL,			/* add 1 blank line (al), n blank lines (AL) */
	*DL,			/* delete line (dl) or n lines (DL) */
#endif
	*CS,			/* change scrolling region (vt100) */
	*DC,			/* delete character */
	*IC,			/* insert character */
#ifdef NEED_ALTERNATE_INSERT_CHARACTER
	*IM, *EI,		/* insert mode & end insert mode */
#endif
	*SO, *SE,		/* begin and end standout mode */
	*US, *UE,		/* start and end underscore mode */
	*MD,			/* turn on extra bright (bold) */
#ifdef UGLY
	*MB, *MH,		/* turn on blink, half bright attribute */
#endif
	*ME,			/* turn off all attributes */
	*SF,			/* scroll text up */
	*SR,			/* scroll text down */
	*ND,			/* non destructive space (cursor right) */
	*LE,			/* move cursor left one position */
	*BL;			/* bell */

/*
 * terminal initialization
 *	read termcap, and uses few curses commands
 */
void
term_init()
{
/*  char	bp[1024], area[1024], *term;*/
  char area[1024], *ptr;

  /* this makes getch() fail on systems where it is a macro for wgetch() */
  delwin(initscr());
  cbreak();
  noecho();

  ptr=area;

/* tgetent() screws up the terminal, I don't know why..
   things look find without it, so let's drop it.
  if ((term = getenv("TERM")) == NULL)
    {
      fprintf(stderr, "TERM variable is not set!\n");
      exit(1);
    }
  if (tgetent(bp, term) < 1)
    {
      fprintf(stderr, "No TERMCAP entry for ``%s''.\n", term);
      exit(1);
    }
*/
  if ((CO = tgetnum("co")) == -1)
      CO = 80;
  if ((LI = tgetnum("li")) == -1)
      LI = 24;
#ifdef TTERM
  /*printf("TERM=%s CO=%d LI=%d", term, CO, LI);*/
#endif
  SG = tgetnum("sg");
  CM = (char *) tgetstr("cm", &ptr);
  CL = (char *) tgetstr("cl", &ptr);
  if (CM == NULL || CL == NULL)
    {
      fprintf(stderr,
	      "This terminal does not have the necessary capabilities.\n");
      exit(1);
    }
  if ((CR = (char *) tgetstr("cr", &ptr)) == NULL)
      CR = "\r";
  if ((NL = (char *) tgetstr("nl", &ptr)) == NULL)
      NL = "\n";
  CE = (char *) tgetstr("ce", &ptr);
#ifdef TTERM
  if (CE == NULL)
      fprintf(stderr, "ce is undefined for this terminal. (critical)\n");
#endif
  ND = (char *) tgetstr("nd", &ptr);
#ifdef TTERM
  if (ND == NULL)
      fprintf(stderr, "nd is undefined for this terminal.\n");
#endif
  LE = (char *) tgetstr("le", &ptr);
#ifdef TTERM
  if (LE == NULL)
    {
      fprintf(stderr, "le is undefined for this terminal.\n");
      if (tgetstr("bs", &ptr))
	  fprintf(stderr, "\tcould be emulated using ``bs''.\n");
    }
#endif
  SF = (char *) tgetstr("sf", &ptr);
#ifdef TTERM
  if (SF == NULL)
      fprintf(stderr,
	      "sf is undefined for this terminal.\n");
#endif
  SR = (char *) tgetstr("sr", &ptr);
#ifdef TTERM
  if (SR == NULL)
      fprintf(stderr, "sr is undefined for this terminal. (critical)\n");
#endif
  CS = (char *) tgetstr("cs", &ptr);
#ifdef TTERM
  if (CS == NULL)
      fprintf(stderr, "cs is undefined for this terminal. (critical)\n");
#endif
  IC = (char *) tgetstr("ic", &ptr);
#ifdef TTERM
  if (IC == NULL)
    {
      fprintf(stderr, "ic is undefined for this terminal.\n");
      if (tgetstr("im", &ptr) && tgetstr("ei", (char **) &area))
	  fprintf(stderr, "\tcould be emulated using ``em'' and ``ei''.\n");
    }
#endif
  DC = (char *) tgetstr("dc", &ptr);
#ifdef TTERM
  if (DC == NULL)
      fprintf(stderr, "dc is undefined for this terminal.\n");
#endif

  SO = (char *) tgetstr("so", &ptr);
  SE = (char *) tgetstr("se", &ptr);
  if (SO == NULL || SE == NULL)
    {
      SO = "";
      SE = "";
#ifdef TTERM
      fprintf(stderr, "``so'' or ``se'' undefined\n");
#endif
    }
  US = (char *) tgetstr("us", &ptr);
  UE = (char *) tgetstr("ue", &ptr);
  if (US == NULL || UE == NULL)
    {
      US = "";
      UE = "";
#ifdef TTERM
      fprintf(stderr, "``so'' or ``se'' undefined\n");
#endif
    }
  MD = (char *) tgetstr("md", &ptr);
  ME = (char *) tgetstr("me", &ptr);
  if (MD == NULL || ME == NULL)
    {
      MD = "";
      ME = "";
#ifdef TTERM
      fprintf(stderr, "``mb'' or ``me'' undefined. (bold unavailable)\n");
#endif
    }
  if ((BL = (char *) tgetstr("bl", &ptr)) == (char *) 0)
    {
      BL = "\007";
#ifdef TTERM
      fprintf(stderr, "``bl'' undefined\n");
#endif
    }

  term_clear();
}

/* restore the terminal to what it was before */
void
term_end()
{
  endwin();
}

/* display a character on the screen.
 *	control characters are displayed in reverse video uppercase letters
 */
void
term_putchar(c)
  unsigned int c;
{
  if (c < 32)
    {
      term_standout_on();
      c = (c & 127) | 64;
      fputc(c, stdout);
      term_standout_off();
    }
  else if (c == '\177')
    {
      term_standout_on();
      c = '?';
      fputc(c, stdout);
      term_standout_off();
    }
  else
      fputc(c, stdout);
 }

/* display up to len characters from the string str on the screen */
int
term_puts(str, len)
  char    *str;
  int     len;
{
  int     i;
  
  for (i = 0; *str && (i < len); str++, i++)
      term_putchar(*str);
  return (i);
}

/* display up to len characters from the string str on the screen
 * the last argument is optional, it's used for video attributes
 */
int
term_putes(str, len, attr)
  char    *str, *attr;
  int     len;
{
  int	i;
  char	*ap = attr;
  unsigned int video = 0;
  
  for (i = 0; *str && (i < len); ap++, str++, i++)
    {
      if (attr)
	{
	  if (*ap & TERM_BOLD)
	    {
	      if (!(video & TERM_BOLD))
		{
		  term_bold_on();
		  video |= TERM_BOLD;
		}
	    }
	  else
	      if (video & TERM_BOLD)
		{
		  term_bold_off();
		  video ^= TERM_BOLD;
		}
	  
	  if (*ap & TERM_STANDOUT)
	    {
	      if (!(video & TERM_STANDOUT))
		{
		  term_standout_on();
		  video |= TERM_STANDOUT;
		}
	    }
	  else
	      if (video & TERM_STANDOUT)
		{
		  term_standout_off();
		  video ^= TERM_STANDOUT;
		}
	  if (*ap & TERM_UNDERLINE)
	    {
	      if (!(video & TERM_UNDERLINE))
		{
		  term_underline_on();
		  video |= TERM_UNDERLINE;
		}
	    }
	  else
	      if (video & TERM_UNDERLINE)
		{
		  term_underline_off();
		  video ^= TERM_UNDERLINE;
		}
	}
      term_putchar(*str);
    }
  if (video & TERM_BOLD)
      term_bold_off();
  if (video & TERM_STANDOUT)
      term_standout_off();
  if (video & TERM_UNDERLINE)
      term_underline_off();
  return (i);
}

/* flush the standard output */
void
term_flush()
{
  fflush(stdout);
}

/* scroll n lines from line1 to line2 */
void
term_scroll(line1, line2, n)
  int     line1, line2, n;
{
  int     i;
  char    *code = NULL;
  
  if (n > 0)
      code = SF ? SF : NL;
  else if (n < 0)
      code = SR;

  assert(code); /* a little bit excessive, but makes a point */

  sic_tputs(tgoto(CS, line2, line1));
  if (n < 0)
    {
      term_move_cursor(0, line1);
      n = -n;
    }
  else
      term_move_cursor(0, line2);
  for (i = 0; i < n; i++)
      sic_tputs(code);
  sic_tputs(tgoto(CS, LI - 1, 0));
}

void
term_status(str, bold)
  char *str;
  int bold;
{
  static int i;

  term_move_cursor(0, LI-2);
  if (bold)
      term_bold_on();
  else
    {
      term_standout_on();
      for (i = strlen(str); i < CO-1; i++)
	str[i] = ' ';
      str[CO] = '\0';
    }
  term_puts(str, CO-1);
  if (bold)
      term_bold_off();
  else
      term_standout_off();
}

/* displays the string at the bottom of the screen (input line) */
void
term_input(str, pos)
  char	*str;
  int	pos;
{
  static	c = 0;

  if (str)
    {
      term_move_cursor(0, LI-1);
      term_puts(str, CO-1);
      term_clreol();
      c = pos;
    }
  term_move_cursor(c, LI-1);
}

#ifdef TTERM
void
main()
{
  unsigned int i = 0;

  printf("Checking term.c in test mode\n");
  term_init();

  sleep(10);
  term_puts("normal", 6);  term_standout_on();  term_puts(" reverse ", 9);
  term_bold_on();  term_puts(" r+b ", 5);  term_standout_off();
  term_puts(" bold ", 6);  term_bold_off();  term_nl();

  term_puts("esc: del: blah:", 18);  term_nl();
  term_flush();
/*
  sleep(1);
  term_scroll(1, 3, 3);
  term_flush();
  sleep(2);
  term_scroll(10, 15, -2);
  term_flush();
  sleep(2);
*/
  
  term_end();

  exit(0);
}
#endif
