/* io.c	
 *
 *	Below are the functions in this file:
 *
 *	setupvt100() 	Subroutine to set up terminal in correct mode for game
 *	clearvt100()  	Subroutine to clean up terminal when the game is over
 *	getvfdchar() 	Routine to read in characters from the terminal until match
 *	getcharacter() 	Routine to read in one character from the terminal
 *	scbr()			Function to set cbreak -echo for the terminal
 *	sncbr()			Function to set -cbreak echo for the terminal
 *	newgame() 	Subroutine to save the initial time and seed rnd()
 *
 *	FILE OUTPUT ROUTINES
 *
 *	lprintf(format,args . . .)	printf to the output buffer
 *	lprint(integer)			send binary integer to output buffer
 *	lwrite(buf,len)			write a buffer to the output buffer
 *	lprcat(str)			sent string to output buffer
 *
 *	FILE OUTPUT MACROS (in header.h)
 *
 *	lprc(character)			put the character into the output buffer
 *
 *	FILE INPUT ROUTINES
 *
 *	long lgetc()			read one character from input buffer
 *	long lrint()			read one integer from input buffer
 *	lrfill(address,number)		put input bytes into a buffer
 *	char *lgetw()			get a whitespace ended word from input
 *	char *lgetl()			get a \n or EOF ended line from input
 *
 *	FILE OPEN / CLOSE ROUTINES
 *
 *	lcreat(filename, mode)		create a new file for write
 *	lopen(filename, mode)		open a file for read
 *	lappend(filename, mode)		open for append to an existing file
 *	lrclose()			close the input file
 *	lwclose()			close output file
 *	lflush()			flush the output buffer
 *
 *	Other Routines
 *
 *	cursor(x,y)		position cursor at [x,y]
 *	cursors()		position cursor at [1,24] (saves memory)
 *  cl_line(x,y)         	Clear line at [1,y] and leave cursor at [x,y]
 *  cl_up(x,y)    		Clear screen from [x,1] to current line.
 *  cl_dn(x,y) 			Clear screen from [1,y] to end of display. 
 *  standout(str)	 	Print the string in standout mode.
 *  set_score_output() 		Called when output should be literally printed.
 ** putcharacter(ch)		Print one character in decoded output buffer.
 ** flush_buf()			Flush buffer with decoded output.
 ** init_term()			Terminal initialization -- setup termcap info
 **char *tmcapcnv(sd,ss)  	Routine to convert vt100 \33's to termcap format
 *	beep() 	  Routine to emit a beep if enabled (see no-beep in .Ularnopts)
 *
 * Note: ** entries are available only in termcap mode.
 */

#include "header.h"
#ifdef __MSDOS__
# include <dos.h>

static short inittyb, curttyb;
# define GTTY(arg) (-((*(arg)=(ioctl(0, 0, arg)&0xff)) == ((-1)&0xff)))
# define STTY(arg) (-(ioctl(0, 1, (int *)(*(arg)))==-1))

int keypad=0, rawio=0, nansi=0;
int fg_color = 7, bg_color = 0;
static int echo = 1;

#else /* __MSDOS__ */

#  ifdef BSD
#    define	GTTY(arg)	(ioctl(0, TIOCGETP, arg))
#    define	STTY(arg)	(ioctl(0, TIOCSETP, arg))
static struct sgttyb inittyb, curttyb;
#  else /* SYSV */
#    define GTTY(arg)		(ioctl(0, TCGETA, arg))
#    define STTY(arg)		(ioctl(0, TCSETAW, arg))
#    define SPEED(x)	((x).c_cflag & CBAUD)
static struct termio inittyb, curttyb;
#  endif /* BSD */
#endif /* __MSDOS__ */

#define	ON	1
#define OFF	0

extern short ospeed;

#define LINBUFSIZE 128		/* size of the lgetw() and lgetl() buffer */
int lfd;			/*  output file numbers	*/
int fd;				/*  input file numbers	*/
static int ipoint=MAXIBUF,iepoint=MAXIBUF;	/*  input buffering pointers  */
static char lgetwbuf[LINBUFSIZE];	/* get line (word) buffer*/
     
     /*
      *	setupvt100() 		
      *		Subroutine to set up terminal in correct mode for game
      *	Attributes off, clear screen, set scrolling region, set tty mode 
      */
     setupvt100()
{
  clear();  
  setscroll();  
  gettty();
}

/*
 *	clearvt100() 	 	
 *		Subroutine to clean up terminal when the game is over
 *	Attributes off, clear screen, unset scrolling region, restore tty mode 
 */
clearvt100()
{
  resetscroll();  
  clear();  
  settty();
}

/*
 **	gettty
 **
 ** Get initial state of terminal, set ospeed (for termcap routines)
 ** and switch off tab expansion
 */
gettty()
{
  if(GTTY(&inittyb) < 0) {
    fprintf(stderr, "OOPS: gettty failed\n");
    fflush(stderr);
    return;
  }
  curttyb = inittyb;
#ifndef BSD
# ifndef __MSDOS__
  ospeed = SPEED(inittyb);
  /* do not expand tabs - they might be needed inside a cm sequence */
  if(curttyb.c_oflag & TAB3) {
    curttyb.c_oflag &= ~TAB3;
    setctty();
  }
# endif /* __MSDOS__ */
#endif /* BSD */
  setuptty();
}

/*
 **	settty
 **
 ** 		reset terminal to original state 
 */
settty() 
{
  if(STTY(&inittyb) < 0) {
    fprintf(stderr, "OOPS: settty failed\n");
    fflush(stderr);
  }
}

/*
 **	setctty
 **
 **		set current tty
 */
setctty(){
  if(STTY(&curttyb) < 0) {
    fprintf(stderr, "OOPS: setctty failed\n");
    fflush(stderr);
  }
}


/*
 **
 **	function to setup all required terminal modes for game
 */
setuptty(){
#ifdef BSD
  scbr();
#else
# ifdef SYSV
  int change = 0;
  if((curttyb.c_lflag & ECHO) != OFF){
    curttyb.c_lflag &= ~ECHO;
    change++;
  }
  if((curttyb.c_lflag & ICANON) != !(ICANON)){
    curttyb.c_lflag &= ~ICANON;
    curttyb.c_lflag |= !(ICANON);
    /* be satisfied with one character; no timeout */
    curttyb.c_cc[VMIN] = 1;		/* was VEOF */
    curttyb.c_cc[VTIME] = 0;	/* was VEOL */
    change++;
  }
  if(change)
    setctty();
# else /* __MSDOS__ */
  scbr();
  if (rawio) {
    curttyb |= 0x20;
    setctty();
  }
# endif
#endif /* BSD */
}

/*
 *	scbr()		Function to set cbreak -echo for the terminal
 *
 *	like: system("stty cbreak -echo")
 */
scbr()
{
#ifdef __MSDOS__
  echo = 0;
#else
# ifdef BSD
  curttyb.sg_flags |= CBREAK;
  curttyb.sg_flags &= ~ECHO;
# else /* SYSV */
  curttyb.c_lflag &= ~ECHO;
  curttyb.c_lflag &= ~ICANON;
# endif /* BSD */
  setctty();
#endif /* __MSDOS__ */
}

/*
 *	sncbr()		Function to set -cbreak echo for the terminal
 *
 *	like: system("stty -cbreak echo")
 */
sncbr()
{
#ifdef __MSDOS__
  echo = 1;
#else
# ifdef BSD
  curttyb.sg_flags &= ~CBREAK;
  curttyb.sg_flags |= ECHO;
# else /* SYSV */
  curttyb.c_lflag |= ECHO;
  curttyb.c_lflag |= ICANON;
# endif /* BSD */
  setctty();
#endif /* not __MSDOS__ */
}

/*
 *	getvfdchar() 	Routine to read in characters from the terminal until match
 */
getvfdchar(string)
char *string;
{
  int i;

  do {
    i = getcharacter(i);
  } while ( ! index(string, (char) i) );
  return ( i );
}

/*
 *	getcharacter() 	Routine to read in one character from the terminal
 */
getcharacter()
{
  char byt;
  
#ifdef __MSDOS__
  static int kpd_trans[] = {
    'y', 'k', 'u', -1,
    'h', '.', 'l', -1,
    'b', 'j', 'n',
    'i', '.',
  };
  static int kpd_shift_trans[] = {
    'i', 'B', 'J', 'N', 'H', '.', 'L', 'Y', 'K', 'U',
  };
  
  lflush();		/* be sure output buffer is flushed */
 try_again:
  byt = echo ? getche() : getch();
  if (byt == '\r') byt = '\n';
  if (echo) return byt;
  if (keypad && byt == '\0') { /* translate extended scan codes */
    byt = getch();
    if (byt < 71 || byt >= 71 + sizeof(kpd_trans)/sizeof(kpd_trans[0]))
      goto try_again;
    byt = kpd_trans[byt-71];
    if (byt == -1) goto try_again;
  }
  else if (keypad && isdigit(byt)) {
    union REGS regs;
    regs.h.ah = 2;
    int86(0x16, &regs, &regs);  /* get shift state */
    if (regs.h.al & 0x03)  /* is either shift key down? */
      byt = kpd_shift_trans[byt-'0'];
  }
  
#else
  static char * arrin ={"BDGCA461532"}; /* chars after ESC [  on numeric keypad */
  static char * arrout={"jh.lkbnyud\33"}; /* . is 5, \33 is 0, d is , */
  char *cinx;
  
  lflush();		/* be sure output buffer is flushed */
  read(0,&byt,1); 	/* get byte from terminal */
  if ( byt == '\33' ){
    read(0,&byt,1); 	/* get byte from terminal */ 
    if( byt == '[' ){
      read(0,&byt,1); 	/* get byte from terminal */
      if( cinx=index(arrin, byt) ){
	if( (((*cinx) & 0xF0) == 0x30) ){
	  read(0,&byt,1); 	/* discard byte from terminal, should be ~ */
	};
	byt = arrout[cinx-arrin];
      };
    };
  };
#endif
  return(byt);
}

/*
 *	newgame() 		
 *		Subroutine to save the initial time and seed rnd()
 */
newgame()
{
  register long *p,*pe;
  
  for (p=c,pe=c+100; p<pe; *p++ =0)
    ;
  time(&initialtime);		
  srand(initialtime);
  lcreat((char*)0);	/* open buffering for output to terminal */
}

/*
 *	lprintf(format,args . . .)		printf to the output buffer
 *		char *format;
 *		??? args . . .
 *
 *	Enter with the format string in "format", as per printf() usage
 *		and any needed arguments following it
 *Note: lprintf() only supports %s, %c and %d, with width modifier and left
 *	or right justification.
 *	No correct checking for output buffer overflow is done, but flushes 
 *		are done beforehand if needed.
 *	Returns nothing of value.
 */
/*VARARGS*/
#ifdef __TURBOC__
lprintf(char *fmt, ...)
#else
     lprintf(va_alist)
     va_dcl
#endif
{
  va_list ap;	/* pointer for variable argument list */
#ifndef __TURBOC__
  char *fmt;
#endif
  char *outb,*tmpb;
  long wide,left,cont,n;		/* data for lprintf	*/
  char db[12];			/* %d buffer in lprintf	*/
  
#ifdef __TURBOC__
  va_start(ap, fmt); /* initialize the varargs pointer */
#else
  va_start(ap);	/* initialize the var args pointer */
#endif
  
#ifndef __TURBOC__        
  fmt = va_arg(ap, char *);	/* pointer to format string */
#endif
  if (lpnt >= lpend) lflush(); 
  outb = lpnt;
  for ( ; ; ) {
    while (*fmt != '%')
      if (*fmt) *outb++ = *fmt++;  
      else { 
	lpnt=outb;  
	return; 
      }
    wide = 0;	
    left = 1;	
    cont=1;
    while (cont)
      switch(*(++fmt)) {
      case 'd':	
	        n = va_arg(ap, long);
		if (n<0) { 
		  n = -n;  
		  *outb++ = '-';  
		  if (wide) --wide; 
		}
		tmpb = db+11;	
		*tmpb = (char)(n % 10 + '0');
		while (n>9)  
		  *(--tmpb) = (char)((n /= 10) % 10+'0');
		if (wide==0)  
		  while (tmpb < db+12) 
		    *outb++ = *tmpb++;
		else {
		  wide -= db-tmpb+12;
		  if (left)  
		    while (wide-- > 0) 
		      *outb++ = ' ';
		  while (tmpb < db+12) 
		    *outb++ = *tmpb++;
		  if (left==0)  
		    while (wide-- > 0) 
		      *outb++ = ' ';
		}
		cont=0;	
		break;
		
      case 's':	
		tmpb = va_arg(ap, char *);
		if (wide==0)  { 
		  while ((*outb++ = *tmpb++)!=0);  
		  --outb; 
		} 
		else {
		  n = wide - strlen(tmpb);
		  if (left)  
		    while (n-- > 0) 
		      *outb++ = ' ';
		  while ((*outb++ = *tmpb++)!=0)
						;  
		  --outb;
		  if (left==0)  
		    while (n-- > 0) 
		      *outb++ = ' ';
		}
		cont=0;	
		break;
		
      case 'c':	
		*outb++ = va_arg(ap, int);	
		cont=0;  
		break;

      case '0':
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':	
		wide = 10*wide + *fmt - '0';	
		break;
      case '-':	
		left = 0;	
		break;
      default:	
		*outb++ = *fmt;  
		cont=0;	
		break;
      };
    fmt++;
  }
  va_end(ap);
}

/*
 *	lprint(long-integer)				
 *		long integer;
 *
 *		send binary integer to output buffer
 *
 *	+---------+---------+---------+---------+
 *	|   high  |	    |	      |	  low	|
 *	|  order  |	    |	      |  order	|
 *	|   byte  |	    |	      |	  byte	|
 *	+---------+---------+---------+---------+
 *	 31 --- 24 23 --- 16 15 ---  8 7  ---  0
 *
 *	The save order is low order first, to high order (4 bytes total)
 *		and is written to be system independent.
 *	No checking for output buffer overflow is done, but flushes if needed!
 *	Returns nothing of value.
 */
lprint(x)
long x;
{
	if (lpnt >= lpend) 
	  lflush();
	*lpnt++ =  255 & x;			
	*lpnt++ =  255 & (x>>8);
	*lpnt++ =  255 & (x>>16);	
	*lpnt++ =  255 & (x>>24);
}

/*
 *	lwrite(buf,len)					
 *		char *buf;
 *		int len;
 *	
 *		write a buffer to the output buffer
 *
 *	Enter with the address and number of bytes to write out
 *	Returns nothing of value
 */
lwrite(buf,len)
char *buf;
int len;
{
  register char *str;
  register int num2;
  
  if (len > 399)  /* don't copy data if can just write it */
  {
    for (str=buf;  len>0; --len)
      lprc(*str++);
    lflush();
    write(lfd,buf,len);
  } 
  else while (len) {
    if (lpnt >= lpend) 
      lflush();	/* if buffer is full flush it	*/
    
    /*	# bytes left in output buffer	*/
    num2 = lpbuf+BUFBIG-lpnt;	
    
    if (num2 > len) num2=len;
    str = lpnt;  
    len -= num2;
    while (num2--)  *str++ = *buf++;	/* copy in the bytes */
    lpnt = str;
  }
}

/*
 *	long lgetc()			Read one character from input buffer
 *
 *  Returns 0 if EOF, otherwise the character
 */
long lgetc()
{
  int i;
  
  if (ipoint != iepoint)  
    return(inbuffer[ipoint++]);
  if ((i=read(fd,inbuffer,MAXIBUF))<=0) {
    if (i!=0)  
      fprintf(stderr,"error reading from input file\n");
    iepoint = ipoint = 0;		
    return(0);
  }
  ipoint=1;  
  iepoint=i;  
  return(*inbuffer);
}

/*
 *	long lrint()			Read one integer from input buffer
 *
 *		+---------+---------+---------+---------+
 *		|  high   |	    |	      |   low   |
 *		|  order  |	    |	      |  order	|
 *		|   byte  |	    |	      |	  byte	|
 *		+---------+---------+---------+---------+
 *	        31  ---  24 23 --- 16 15 ---  8 7  ---   0
 *
 *	The save order is low order first, to high order (4 bytes total)
 *	Returns the int read
 */
long lrint()
{
  unsigned long i;
  
  i  = 255 & lgetc();				
  i |= (255 & lgetc()) << 8;
  i |= (255 & lgetc()) << 16;		
  i |= (255 & lgetc()) << 24;
  return(i);
}

/*
 *	lrfill(address,number)			put input bytes into a buffer
 *		char *address;
 *		int number;
 *
 *	Reads "number" bytes into the buffer pointed to by "address".
 *	Returns nothing of value
 */
lrfill(adr,num)
     char *adr;
     int num;
{
  char *pnt;
  int num2;
  
  while (num) {
    if (iepoint == ipoint) {
      if (num>5) {
	if (read(fd,adr,num) != num)
	  fprintf(stderr,"error reading from input file\n");
	num=0;
      }
      else { 
	*adr++ = lgetc();  
	--num; 
      }
    }
    else {
      /*	# of bytes left in the buffer	*/
      num2 = iepoint-ipoint;	
      
      if (num2 > num) 
	num2=num;
      pnt = inbuffer+ipoint;	
      num -= num2;  
      ipoint += num2;
      while (num2--)  
	*adr++ = *pnt++;
    }
  }
}

/*
 *	char *lgetw()			Get a whitespace ended word from input
 *
 *	Returns pointer to a buffer that contains word.  If EOF, returns a 0
 */
char *lgetw()
{
  char *lgp,cc;
  int n=LINBUFSIZE,quote=0;
  
  lgp = lgetwbuf;
  
  do 
    cc=lgetc();
  while ((cc <= ' ') && (cc > 0));  /* eat whitespace */
  
  for ( ; ; --n,cc=lgetc()) {
    if ((cc==0) && (lgp==lgetwbuf))  return(0);	/* EOF */
    if ((n<=1) || ((cc<=32) && (quote==0))) { 
      *lgp=0; 
      return(lgetwbuf); 
    }
    if (cc != '"') *lgp++ = cc;   
    else quote ^= 1;
  }
}

/*
 *	char *lgetl()	
 * 		Function to read in a line ended by newline or EOF
 *
 *Returns pointer to a buffer that contains the line.  If EOF, returns 0
 */
char *lgetl()
{
  int i=LINBUFSIZE,ch;
  char *str=lgetwbuf;
  
  for ( ; ; --i) {
    if ((*str++ = ch = lgetc()) == 0) {
      if (str == lgetwbuf+1)  return(0); /* EOF */
    ot:	
      *str = 0;	
      return(lgetwbuf);	/* line ended by EOF */
    }
    if ((ch=='\n') || (i<=1))  
      goto ot; /* line ended by \n */
  }
}

/*
 *	lcreat(filename, mode)			Create a new file for write
 *		char *filename;
 *		int mode;
 *
 *	mode is 0 for text files and 1 for binary files.
 *	lcreat((char*)0); means to the terminal
 *	Returns -1 if error, otherwise the file descriptor opened.
 */
lcreat(str, mode)
     char *str;
     int mode;
{
  lpnt = lpbuf;	
  lpend = lpbuf+BUFBIG;
  if (str==0) return(lfd=1);
#ifdef __MSDOS__
  mode = (mode ? O_BINARY : O_TEXT) | O_WRONLY | O_CREAT | O_TRUNC;
#else
  mode = O_WRONLY | O_CREAT | O_TRUNC;
#endif
  if ((lfd=open(str,mode,0644)) < 0) {
    lfd=1; 
    lprintf("error creating file <%s>\n",str); 
    lflush(); 
    return(-1);
  }
  return(lfd);
}

/*
 *	lopen(filename, mode)		Open a file for read
 *		char *filename;
 *		int mode;
 *
 *	mode is 0 for text files and 1 for binary files.
 *	lopen(0) means from the terminal
 *	Returns -1 if error, otherwise the file descriptor opened.
 */
lopen(str, mode)
     char *str;
     int mode;
{
  ipoint = iepoint = MAXIBUF;
  if (str==0) return(fd=0);
#ifdef __MSDOS__
  mode = (mode ? O_BINARY : O_TEXT) | O_RDONLY;
#else
  mode = O_RDONLY;
#endif
  if ((fd=open(str,mode)) < 0) {
    lwclose(); 
    lfd=1; 
    lpnt=lpbuf; 
    return(-1);
  }
  return(fd);
}

/*
 *	lappend(filename, mode)		Open for append to an existing file
 *		char *filename;
 *		int mode;
 *
 *	mode is 0 for text files and 1 for binary files.
 *	lappend(0) means to the terminal
 *	Returns -1 if error, otherwise the file descriptor opened.
 */
lappend(str, mode)
     char *str;
     int mode;
{
  lpnt = lpbuf;	
  lpend = lpbuf+BUFBIG;
  if (str==0) return(lfd=1);
#ifdef __MSDOS__
  mode = (mode ? O_BINARY : O_TEXT) | O_WRONLY | O_APPEND;
#else
  mode = O_WRONLY | O_APPEND;
#endif
  if ((lfd=open(str,mode)) < 0) {
    lfd=1; 
    return(-1);
  }
  lseek(lfd,0,2);	/* seek to end of file */
  return(lfd);
}

/*
 *	lrclose()						
 *			close the input file
 *
 *	Returns nothing of value.
 */
lrclose()
{
  if (fd > 0) close(fd);
}

/*
 *	lwclose()			close output file flushing if needed
 *
 *	Returns nothing of value.
 */
lwclose()
{
  lflush();	
  if (lfd > 2) close(lfd);
}

/*
 *	lprcat(string)			append a string to the output buffer
 *					avoids calls to lprintf (time consuming)
 */
lprcat(str)
     char *str;
{
  char *str2;
  
  if (lpnt >= lpend) 
    lflush(); 
  str2 = lpnt;
  while ((*str2++ = *str++)!=0)
    ;
  lpnt = str2 - 1;
}

/*
 * cursor(x,y)	  Put cursor at specified coordinates staring at [1,1] (termcap)
 */
cursor (x,y)
     int x,y;
{
  if (lpnt >= lpend) lflush ();
  
  *lpnt++ = CURSOR;		
  *lpnt++ = x;		
  *lpnt++ = y;
}

/*
 *	Routine to position cursor at beginning of 24th line
 */
cursors()
{
  cursor(1,24);
}

/*
 * Warning: ringing the bell is control code 7. Don't use in defines.
 * Don't change the order of these defines.
 * Also used in helpfiles. Codes used in helpfiles should be \E[1 to \E[7 with
 * obvious meanings.
 */

static char cap[256];
char *CM, *CE, *CD, *CL, *SO, *SE, *AL, *DL;/* Termcap capabilities */
static char *outbuf=0;	/* translated output buffer */

int putcharacter ();

/*
 * init_term()		Terminal initialization -- setup termcap info
 */
init_term()
{
#ifndef __MSDOS__
  char termbuf[1024];
  char *capptr = cap+10;
  char *term;
  
  switch (tgetent(termbuf, term = getenv("TERM"))) {
  case -1: 
            fprintf(stderr, "Cannot open termcap file.\n"); 
	    fflush(stderr);
	    exit(1);
  case 0: 
	    fprintf(stderr, "Cannot find entry of ");
	    fprintf(stderr, term);
	    fprintf(stderr, " in termcap\n");
	    fflush(stderr);
	    exit(1);
  };

  CM = tgetstr("cm", &capptr);  /* Cursor motion */
  CE = tgetstr("ce", &capptr);  /* Clear to eoln */
  CL = tgetstr("cl", &capptr);  /* Clear screen */

  /* OPTIONAL */
  AL = tgetstr("al", &capptr);  /* Insert line */
  DL = tgetstr("dl", &capptr);  /* Delete line */
  SO = tgetstr("so", &capptr);  /* Begin standout mode */
  SE = tgetstr("se", &capptr);  /* End standout mode */
  CD = tgetstr("cd", &capptr);  /* Clear to end of display */
  
  if (!CM)	/* can't find cursor motion entry */
  {
    fprintf(stderr, "Sorry, for a ");		
    fprintf(stderr, term);
    fprintf(stderr, ", I can't find the cursor motion entry in termcap\n");
    fflush(stderr);
    exit(1);
  }
  if (!CE)	/* can't find clear to end of line entry */
  {
    fprintf(stderr, "Sorry, for a ");		
    fprintf(stderr, term);
    fprintf(stderr,", I can't find the clear to end of line entry in termcap\n");
    fflush(stderr);
    exit(1);
  }
  if (!CL)	/* can't find clear entire screen entry */
  {
    fprintf(stderr, "Sorry, for a ");		
    fprintf(stderr, term);
    fprintf(stderr, ", I can't find the clear entire screen entry in termcap\n");
    fflush(stderr);
    exit(1);
  }
#else /* __MSDOS__ */
  
  static char sobuf[20], sebuf[20];
  
  CM = "\033[%d;%dH";  /* Cursor motion */
  CE = "\033[K";       /* Clear to eoln */
  CL = "\033[2J";      /* Clear screen */
  
  /* OPTIONAL */
  if (nansi) {
    AL = "\033[L";       /* Insert line */
    DL = "\033[M";       /* Delete line */
  }
  else {
    AL = NULL;           /* Insert line */
    DL = NULL;           /* Delete line */
  }
  
  sprintf(sobuf, "\033[1;%d;%dm", fg_color + 30, bg_color + 40);
  sprintf(sebuf, "\033[0;%d;%dm", fg_color + 30, bg_color + 40);
  
  SO = sobuf;      /* Begin standout mode */
  SE = sebuf;      /* End standout mode */
  CD = NULL;  /* Clear to end of display */
  
  puts(sebuf);
#endif /* __MSDOS__ */
  
  /* get memory for decoded output buffer*/
  if ((outbuf=malloc(BUFBIG+16))==0) {
    fprintf(stderr,"Error malloc'ing memory for decoded output buffer\n");
    fflush(stderr);
    died(-285);	/* malloc() failure */
  }
}

/*
 * cl_line(x,y)  Clear the whole line indicated by 'y' and leave cursor at [x,y]
 */
cl_line(x,y)
     int x,y;
{
  cursor(1,y);		
  *lpnt++ = CL_LINE;		
  cursor(x,y);
}

/*
 * cl_up(x,y) Clear screen from [x,1] to current position. Leave cursor at [x,y]
 */
cl_up(x,y)
     register int x,y;
{
  register int i;
  cursor(1,1);
  for (i=1; i<=y; i++)   { 
    *lpnt++ = CL_LINE;  
    *lpnt++ = '\n'; 
  }
  cursor(x,y);
}

/*
 * cl_dn(x,y) 	Clear screen from [1,y] to end of display. Leave cursor at [x,y]
 */
cl_dn(x,y)
     int x,y;
{
  int i;
  
  cursor(1,y);
  if (!CD) {
    *lpnt++ = CL_LINE;
    for (i=y; i<=24; i++) { 
      *lpnt++ = CL_LINE;  
      if (i!=24) *lpnt++ = '\n'; 
    }
    cursor(x,y);
  }
  else
    *lpnt++ = CL_DOWN;
  cursor(x,y);
}

/*
 * standout(str)  Print the argument string in inverse video (standout mode).
 */
standout(str)
     register char *str;
{
  if (boldon == 0) {
    lprcat(str);
    return;
  }
  *lpnt++ = ST_START;
  while (*str)
    *lpnt++ = *str++;
  *lpnt++ = ST_END;
}

/*
 * set_score_output() 	Called when output should be literally printed.
 */
set_score_output()
{
  enable_scroll = -1;
}

#ifdef __MSDOS__

void tputs(char *s, int x, int (*outch)())
{
  while (*s) (*outch)(*s++);
  ++x;
}

char *tgoto(char *s, int x, int y)
{
  static char buf[12];
  
  sprintf(buf, s, y+1, x+1);
  return buf;
}

#endif  /* __MSDOS__ */

/*
 *	lflush()					Flush the output buffer
 *
 *	Returns nothing of value.
 *	for termcap version: Flush output in output buffer according to output
 *					status as indicated by `enable_scroll'
 */
static int scrline=18; /* line # for wraparound instead of scrolling if no DL */
lflush ()
{
  int lpoint;
  char *str;
  static int curx = 0;
  static int cury = 0;
  
  if ((lpoint = lpnt - lpbuf) > 0) {
    if (enable_scroll <= -1) {
      flush_buf();
      if (write(lfd,lpbuf,lpoint) != lpoint) {
	fprintf(stderr,"error writing to output file\n");
	fflush(stderr);
      }
      lpnt = lpbuf;	/* point back to beginning of buffer */
      return;
    }
    for (str = lpbuf; str < lpnt; str++) {
      if (*str>=32)	{ 
	putcharacter (*str); 
	curx++; 
      }
      else switch (*str) {
      case CLEAR:		
	      tputs (CL, 0, putcharacter);		
	      curx = cury = 0;
	      break;

      case CL_LINE:	
	      tputs (CE, 0, putcharacter);
	      break;

      case CL_DOWN:	
	      tputs (CD, 0, putcharacter);
	      break;

      case ST_START:	
	      tputs (SO, 0, putcharacter);
	      break;

      case ST_END:	
	      tputs (SE, 0, putcharacter);
	      break;

      case CURSOR:	
	      curx = *++str - 1;		
	      cury = *++str - 1;
	      tputs (tgoto (CM, curx, cury), 0, putcharacter);
	      break;

      case '\n':		
	      if ((cury == 23) && enable_scroll) {
		if (!DL || !AL) {
		  if (++scrline > 23) scrline=19;
		  if (++scrline > 23) scrline=19;
		  tputs (tgoto (CM, 0, scrline), 0, putcharacter);
		  tputs (CE, 0, putcharacter);
		  
		  if (--scrline < 19) scrline=23;
		  tputs (tgoto (CM, 0, scrline), 0, putcharacter);
		  tputs (CE, 0, putcharacter);
		}
		else {
		  tputs (tgoto (CM, 0, 19), 0, putcharacter);
		  tputs (DL, 0, putcharacter);
		  tputs (tgoto (CM, 0, 23), 0, putcharacter);
		}
	      }
	      else {
		putcharacter ('\n');		
		cury++;
	      }
	      curx = 0;
	      break;

      default:		
	      putcharacter (*str); 
	      curx++;
      };
    }
  }
  lpnt = lpbuf;
  flush_buf();	/* flush real output buffer now */
}

static int inx=0;

/*
 * putcharacter(ch)		Print one character in decoded output buffer.
 */
int putcharacter(c)
int c;
{
	outbuf[inx++] = c;
	if (inx >= BUFBIG)  
	  flush_buf();
}

/*
 * flush_buf()			Flush buffer with decoded output.
 */
flush_buf()
{
	if (inx) 
	  write(lfd, outbuf, inx);
	inx = 0;
}

/*
 *	char *tmcapcnv(sd,ss)  
 *		Routine to convert vt100 escapes to termcap format
 *
 *	Processes only the \33[#m sequence (converts . files for termcap use 
 */
char *tmcapcnv(sd,ss)
char *sd,*ss;
{
	int tmstate=0;	/* 0=normal, 1=\33 2=[ 3=# */
	char tmdigit=0;	/* the # in \33[#m */

	while (*ss) {
	  switch(tmstate) {
	  case 0:	
	          if (*ss=='\33')  { 
		    tmstate++; 
		    break; 
		  }
ign:  
		  *sd++ = *ss;
ign2: 
		  tmstate = 0;
		  break;
	  case 1: 
		  if (*ss!='[') goto ign;
		  tmstate++;
		  break;
	  case 2: 
		  if (isdigit(*ss)) { 
		    tmdigit= *ss-'0'; 
		    tmstate++; 
		    break; 
		  }
		  if (*ss == 'm') { 
		    *sd++ = ST_END; 
		    goto ign2; 
		  }
		  goto ign;
	  case 3: 
		  if (*ss == 'm') {
		    if (tmdigit) *sd++ = ST_START;
		    else *sd++ = ST_END;
		    goto ign2;
		  }
	  default: 
		  goto ign;
	  };
	  ss++;
	}
	*sd=0; /* 0 terminator */
	return(sd);
}

/*
 *	beep()	Routine to emit a beep if enabled (see no-beep in .Ularnopts)
 */
beep()
{
	if (!nobeep) *lpnt++ = '\7';
}







