Home | History | Annotate | Line # | Download | only in larn
      1 /*	$NetBSD: io.c,v 1.31 2024/03/26 20:50:29 andvar Exp $	*/
      2 
      3 /*
      4  * io.c			Larn is copyrighted 1986 by Noah Morgan.
      5  *
      6  * Below are the functions in this file:
      7  *
      8  * setupvt100()		Subroutine to set up terminal in correct mode for game
      9  * clearvt100()		Subroutine to clean up terminal when the game is over
     10  * ttgetch()		Routine to read in one character from the terminal
     11  * scbr()		Function to set cbreak -echo for the terminal
     12  * sncbr()		Function to set -cbreak echo for the terminal
     13  * newgame()		Subroutine to save the initial time and seed rnd()
     14  *
     15  * FILE OUTPUT ROUTINES
     16  *
     17  * lprintf(format,args . . .)	printf to the output buffer
     18  * lprint(integer)		send binary integer to output buffer
     19  * lwrite(buf,len)		write a buffer to the output buffer
     20  * lprcat(str)			append a string to the output buffer
     21  *
     22  * FILE OUTPUT MACROS (in header.h)
     23  *
     24  * lprc(character)		put the character into the output buffer
     25  *
     26  * FILE INPUT ROUTINES
     27  *
     28  * long lgetc()			read one character from input buffer
     29  * long larn_lrint()		read one integer from input buffer
     30  * lrfill(address,number)	put input bytes into a buffer char
     31  * *lgetw()			get a whitespace ended word from
     32  * input char *lgetl()		get a \n or EOF ended line from input
     33  *
     34  * FILE OPEN / CLOSE ROUTINES
     35  *
     36  * lcreat(filename)		create a new file for write
     37  * lopen(filename)		open a file for read
     38  * lappend(filename)		open for append to an existing file
     39  * lrclose()			close the input file
     40  * lwclose()			close output file
     41  * lflush()			flush the output buffer
     42  *
     43  * Other Routines
     44  *
     45  * cursor(x,y)			position cursor at [x,y]
     46  * cursors()			position cursor at [1,24] (saves memory)
     47  * cl_line(x,y)			clear line at [1,y] and leave cursor at [x,y]
     48  * cl_up(x,y)			clear screen from [x,1] to current line
     49  * cl_dn(x,y)			clear screen from [1,y] to end of display
     50  * standout(str)		print the string in standout mode
     51  * set_score_output()		called when output should be literally printed
     52  * ttputch(ch)			print one character in decoded output buffer
     53  * flush_buf()			flush buffer with decoded output
     54  * init_term()			terminal initialization -- setup termcap info
     55  * char *tmcapcnv(sd,ss)	routine to convert VT100 \33's to termcap format
     56  * beep()			routine to emit a beep if enabled
     57  * 				(see no-beep in .larnopts)
     58  *
     59  * Note: ** entries are available only in termcap mode.
     60  */
     61 #include <sys/cdefs.h>
     62 #ifndef lint
     63 __RCSID("$NetBSD: io.c,v 1.31 2024/03/26 20:50:29 andvar Exp $");
     64 #endif /* not lint */
     65 
     66 #include "header.h"
     67 #include "extern.h"
     68 #include <string.h>
     69 #include <unistd.h>
     70 #include <stdio.h>
     71 #include <stdlib.h>
     72 #include <time.h>
     73 #include <term.h>
     74 #include <fcntl.h>
     75 #include <errno.h>
     76 #include <ctype.h>
     77 
     78 #ifdef TERMIO
     79 #include <termio.h>
     80 #define sgttyb termio
     81 #define stty(_a,_b) ioctl(_a,TCSETA,_b)
     82 #define gtty(_a,_b) ioctl(_a,TCGETA,_b)
     83 #endif
     84 #ifdef TERMIOS
     85 #include <termios.h>
     86 #define sgttyb termios
     87 #define stty(_a,_b) tcsetattr(_a,TCSADRAIN,_b)
     88 #define gtty(_a,_b) tcgetattr(_a,_b)
     89 #endif
     90 
     91 #if defined(TERMIO) || defined(TERMIOS)
     92 static int      rawflg = 0;
     93 static char     saveeof, saveeol;
     94 #define doraw(_a) \
     95 	if(!rawflg) { \
     96 		++rawflg; \
     97 		saveeof = _a.c_cc[VMIN]; \
     98 		saveeol = _a.c_cc[VTIME]; \
     99 	} \
    100     	_a.c_cc[VMIN] = 1; \
    101 	_a.c_cc[VTIME] = 1; \
    102 	_a.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL)
    103 #define unraw(_a) \
    104 	_a.c_cc[VMIN] = saveeof; \
    105 	_a.c_cc[VTIME] = saveeol; \
    106 	_a.c_lflag |= ICANON|ECHO|ECHOE|ECHOK|ECHONL
    107 
    108 #else	/* not TERMIO or TERMIOS */
    109 
    110 #ifndef BSD
    111 #define CBREAK RAW		/* V7 has no CBREAK */
    112 #endif
    113 
    114 #define doraw(_a) (_a.sg_flags |= CBREAK,_a.sg_flags &= ~ECHO)
    115 #define unraw(_a) (_a.sg_flags &= ~CBREAK,_a.sg_flags |= ECHO)
    116 #include <sgtty.h>
    117 #endif	/* not TERMIO or TERMIOS */
    118 
    119 #ifndef NOVARARGS	/* if we have varargs */
    120 #include <stdarg.h>
    121 #else	/* NOVARARGS */	/* if we don't have varargs */
    122 typedef char   *va_list;
    123 #define va_dcl int va_alist;
    124 #define va_start(plist) plist = (char *) &va_alist
    125 #define va_end(plist)
    126 #define va_arg(plist,mode) ((mode *)(plist += sizeof(mode)))[-1]
    127 #endif	/* NOVARARGS */
    128 
    129 static int ttputch(int ch);
    130 static void flush_buf(void);
    131 
    132 #define LINBUFSIZE 128	/* size of the lgetw() and lgetl() buffer */
    133 int             io_outfd; /* output file numbers */
    134 int             io_infd; /* input file numbers */
    135 static struct sgttyb ttx;/* storage for the tty modes */
    136 static int      ipoint = MAXIBUF, iepoint = MAXIBUF;	/* input buffering
    137 							 * pointers    */
    138 static char     lgetwbuf[LINBUFSIZE];	/* get line (word) buffer */
    139 
    140 /*
    141  *	setupvt100() Subroutine to set up terminal in correct mode for game
    142  *
    143  *	Attributes off, clear screen, set scrolling region, set tty mode
    144  */
    145 void
    146 setupvt100(void)
    147 {
    148 	clear();
    149 	setscroll();
    150 	scbr();			/* system("stty cbreak -echo"); */
    151 }
    152 
    153 /*
    154  *	clearvt100() 	Subroutine to clean up terminal when the game is over
    155  *
    156  *	Attributes off, clear screen, unset scrolling region, restore tty mode
    157  */
    158 void
    159 clearvt100(void)
    160 {
    161 	resetscroll();
    162 	clear();
    163 	sncbr();		/* system("stty -cbreak echo"); */
    164 }
    165 
    166 /*
    167  *	ttgetch() 	Routine to read in one character from the terminal
    168  */
    169 int
    170 ttgetch(void)
    171 {
    172 	char            byt;
    173 #ifdef EXTRA
    174 	c[BYTESIN]++;
    175 #endif
    176 	lflush();		/* be sure output buffer is flushed */
    177 	read(0, &byt, 1);	/* get byte from terminal */
    178 	return (byt);
    179 }
    180 
    181 /*
    182  *	scbr()		Function to set cbreak -echo for the terminal
    183  *
    184  *	like: system("stty cbreak -echo")
    185  */
    186 void
    187 scbr(void)
    188 {
    189 	gtty(0, &ttx);
    190 	doraw(ttx);
    191 	stty(0, &ttx);
    192 }
    193 
    194 /*
    195  *	sncbr()		Function to set -cbreak echo for the terminal
    196  *
    197  *	like: system("stty -cbreak echo")
    198  */
    199 void
    200 sncbr(void)
    201 {
    202 	gtty(0, &ttx);
    203 	unraw(ttx);
    204 	stty(0, &ttx);
    205 }
    206 
    207 /*
    208  *	newgame() 	Subroutine to save the initial time and seed rnd()
    209  */
    210 void
    211 newgame(void)
    212 {
    213 	long  *p, *pe;
    214 	for (p = c, pe = c + 100; p < pe; *p++ = 0);
    215 	time(&initialtime);
    216 	seedrand(initialtime);
    217 	srandom(initialtime);
    218 	lcreat((char *) 0);	/* open buffering for output to terminal */
    219 }
    220 
    221 /*
    222  *	lprintf(format,args . . .)		printf to the output buffer
    223  *		char *format;
    224  *		??? args . . .
    225  *
    226  *	Enter with the format string in "format", as per printf() usage
    227  *		and any needed arguments following it
    228  *	Note: lprintf() only supports %s, %c and %d, with width modifier and left
    229  *		or right justification.
    230  *	No correct checking for output buffer overflow is done, but flushes
    231  *		are done beforehand if needed.
    232  *	Returns nothing of value.
    233  */
    234 void
    235 lprintf(const char *fmt, ...)
    236 {
    237 	va_list ap;
    238 	char buf[BUFBIG/2];
    239 
    240 	va_start(ap, fmt);
    241 	vsnprintf(buf, sizeof(buf), fmt, ap);
    242 	va_end(ap);
    243 
    244 	if (lpnt >= lpend)
    245 		lflush();
    246 
    247 	lprcat(buf);
    248 }
    249 
    250 /*
    251  *	lprint(long-integer)	send binary integer to output buffer
    252  *		long integer;
    253  *
    254  *		+---------+---------+---------+---------+
    255  *		|   high  |	    |	      |	  low	|
    256  *		|  order  |	    |	      |  order	|
    257  *		|   byte  |	    |	      |	  byte	|
    258  *		+---------+---------+---------+---------+
    259  *	        31  ---  24 23 --- 16 15 ---  8 7  ---   0
    260  *
    261  *	The save order is low order first, to high order (4 bytes total)
    262  *	and is written to be system independent.
    263  *	No checking for output buffer overflow is done, but flushes if needed!
    264  *	Returns nothing of value.
    265  */
    266 void
    267 lprint(long x)
    268 {
    269 	if (lpnt >= lpend)
    270 		lflush();
    271 	*lpnt++ = 255 & x;
    272 	*lpnt++ = 255 & (x >> 8);
    273 	*lpnt++ = 255 & (x >> 16);
    274 	*lpnt++ = 255 & (x >> 24);
    275 }
    276 
    277 /*
    278  *	lwrite(buf,len)		write a buffer to the output buffer
    279  *		char *buf;
    280  *		int len;
    281  *
    282  *	Enter with the address and number of bytes to write out
    283  *	Returns nothing of value
    284  */
    285 void
    286 lwrite(char *buf, int len)
    287 {
    288 	char *s;
    289 	u_char *t;
    290 	int num2;
    291 
    292 	if (len > 399) {	/* don't copy data if can just write it */
    293 #ifdef EXTRA
    294 		c[BYTESOUT] += len;
    295 #endif
    296 
    297 #ifndef VT100
    298 		for (s = buf; len > 0; --len)
    299 			lprc(*s++);
    300 #else	/* VT100 */
    301 		lflush();
    302 		write(io_outfd, buf, len);
    303 #endif	/* VT100 */
    304 	} else
    305 		while (len) {
    306 			if (lpnt >= lpend)
    307 				lflush();	/* if buffer is full flush it	 */
    308 			num2 = lpbuf + BUFBIG - lpnt;	/* # bytes left in
    309 							 * output buffer	 */
    310 			if (num2 > len)
    311 				num2 = len;
    312 			t = lpnt;
    313 			len -= num2;
    314 			while (num2--)
    315 				*t++ = *buf++;	/* copy in the bytes */
    316 			lpnt = t;
    317 		}
    318 }
    319 
    320 /*
    321  *	long lgetc()	Read one character from input buffer
    322  *
    323  *  Returns 0 if EOF, otherwise the character
    324  */
    325 long
    326 lgetc(void)
    327 {
    328 	int    i;
    329 	if (ipoint != iepoint)
    330 		return (inbuffer[ipoint++]);
    331 	if (iepoint != MAXIBUF)
    332 		return (0);
    333 	if ((i = read(io_infd, inbuffer, MAXIBUF)) <= 0) {
    334 		if (i != 0)
    335 			write(1, "error reading from input file\n", 30);
    336 		iepoint = ipoint = 0;
    337 		return (0);
    338 	}
    339 	ipoint = 1;
    340 	iepoint = i;
    341 	return (*inbuffer);
    342 }
    343 
    344 /*
    345  *	long lrint()	Read one integer from input buffer
    346  *
    347  *		+---------+---------+---------+---------+
    348  *		|   high  |	    |	      |	  low	|
    349  *		|  order  |	    |	      |  order	|
    350  *		|   byte  |	    |	      |	  byte	|
    351  *		+---------+---------+---------+---------+
    352  *	       31  ---  24 23 --- 16 15 ---  8 7  ---   0
    353  *
    354  *	The save order is low order first, to high order (4 bytes total)
    355  *	Returns the int read
    356  */
    357 long
    358 larn_lrint(void)
    359 {
    360 	unsigned long i;
    361 	i = 255 & lgetc();
    362 	i |= (255 & lgetc()) << 8;
    363 	i |= (255 & lgetc()) << 16;
    364 	i |= (255 & lgetc()) << 24;
    365 	return (i);
    366 }
    367 
    368 /*
    369  *	lrfill(address,number)		put input bytes into a buffer
    370  *		char *address;
    371  *		int number;
    372  *
    373  *	Reads "number" bytes into the buffer pointed to by "address".
    374  *	Returns nothing of value
    375  */
    376 void
    377 lrfill(char *adr, int num)
    378 {
    379 	u_char  *pnt;
    380 	int    num2;
    381 
    382 	while (num) {
    383 		if (iepoint == ipoint) {
    384 			if (num > 5) {	/* fast way */
    385 				if (read(io_infd, adr, num) != num)
    386 					write(2, "error reading from input file\n", 30);
    387 				num = 0;
    388 			} else {
    389 				*adr++ = lgetc();
    390 				--num;
    391 			}
    392 		} else {
    393 			num2 = iepoint - ipoint;	/* # of bytes left in
    394 							 * the buffer	 */
    395 			if (num2 > num)
    396 				num2 = num;
    397 			pnt = inbuffer + ipoint;
    398 			num -= num2;
    399 			ipoint += num2;
    400 			while (num2--)
    401 				*adr++ = *pnt++;
    402 		}
    403 	}
    404 }
    405 
    406 /*
    407  *	char *lgetw()			Get a whitespace ended word from input
    408  *
    409  *	Returns pointer to a buffer that contains word.  If EOF, returns a NULL
    410  */
    411 char *
    412 lgetw(void)
    413 {
    414 	char  *lgp, cc;
    415 	int    n = LINBUFSIZE, quote = 0;
    416 	lgp = lgetwbuf;
    417 	do
    418 		cc = lgetc();
    419 	while ((cc <= 32) && (cc > '\0'));	/* eat whitespace */
    420 	for (;; --n, cc = lgetc()) {
    421 		if ((cc == '\0') && (lgp == lgetwbuf))
    422 			return (NULL);	/* EOF */
    423 		if ((n <= 1) || ((cc <= 32) && (quote == 0))) {
    424 			*lgp = '\0';
    425 			return (lgetwbuf);
    426 		}
    427 		if (cc != '"')
    428 			*lgp++ = cc;
    429 		else
    430 			quote ^= 1;
    431 	}
    432 }
    433 
    434 /*
    435  *	char *lgetl()	Function to read in a line ended by newline or EOF
    436  *
    437  * Returns pointer to a buffer that contains the line.  If EOF, returns NULL
    438  */
    439 char *
    440 lgetl(void)
    441 {
    442 	int    i = LINBUFSIZE, ch;
    443 	char  *str = lgetwbuf;
    444 	for (;; --i) {
    445 		if ((*str++ = ch = lgetc()) == '\0') {
    446 			if (str == lgetwbuf + 1)
    447 				return (NULL);	/* EOF */
    448 	ot:		*str = '\0';
    449 			return (lgetwbuf);	/* line ended by EOF */
    450 		}
    451 		if ((ch == '\n') || (i <= 1))
    452 			goto ot;/* line ended by \n */
    453 	}
    454 }
    455 
    456 /*
    457  *	lcreat(filename)			Create a new file for write
    458  *		char *filename;
    459  *
    460  *	lcreat((char*)0); means to the terminal
    461  *	Returns -1 if error, otherwise the file descriptor opened.
    462  */
    463 int
    464 lcreat(char *str)
    465 {
    466 	lflush();
    467 	lpnt = lpbuf;
    468 	lpend = lpbuf + BUFBIG;
    469 	if (str == NULL)
    470 		return (io_outfd = 1);
    471 	if ((io_outfd = creat(str, 0644)) < 0) {
    472 		io_outfd = 1;
    473 		lprintf("error creating file <%s>: %s\n", str,
    474 			strerror(errno));
    475 		lflush();
    476 		return (-1);
    477 	}
    478 	return (io_outfd);
    479 }
    480 
    481 /*
    482  *	lopen(filename)			Open a file for read
    483  *		char *filename;
    484  *
    485  *	lopen(0) means from the terminal
    486  *	Returns -1 if error, otherwise the file descriptor opened.
    487  */
    488 int
    489 lopen(char *str)
    490 {
    491 	ipoint = iepoint = MAXIBUF;
    492 	if (str == NULL)
    493 		return (io_infd = 0);
    494 	if ((io_infd = open(str, O_RDONLY)) < 0) {
    495 		lwclose();
    496 		io_outfd = 1;
    497 		lpnt = lpbuf;
    498 		return (-1);
    499 	}
    500 	return (io_infd);
    501 }
    502 
    503 /*
    504  *	lappend(filename)		Open for append to an existing file
    505  *		char *filename;
    506  *
    507  *	lappend(0) means to the terminal
    508  *	Returns -1 if error, otherwise the file descriptor opened.
    509  */
    510 int
    511 lappend(char *str)
    512 {
    513 	lpnt = lpbuf;
    514 	lpend = lpbuf + BUFBIG;
    515 	if (str == NULL)
    516 		return (io_outfd = 1);
    517 	if ((io_outfd = open(str, 2)) < 0) {
    518 		io_outfd = 1;
    519 		return (-1);
    520 	}
    521 	lseek(io_outfd, 0, SEEK_END);	/* seek to end of file */
    522 	return (io_outfd);
    523 }
    524 
    525 /*
    526  *	lrclose() close the input file
    527  *
    528  *	Returns nothing of value.
    529  */
    530 void
    531 lrclose(void)
    532 {
    533 	if (io_infd > 0) {
    534 		close(io_infd);
    535 		io_infd = 0;
    536 	}
    537 }
    538 
    539 /*
    540  *	lwclose() close output file flushing if needed
    541  *
    542  *	Returns nothing of value.
    543  */
    544 void
    545 lwclose(void)
    546 {
    547 	lflush();
    548 	if (io_outfd > 2) {
    549 		close(io_outfd);
    550 		io_outfd = 1;
    551 	}
    552 }
    553 
    554 /*
    555  *	lprcat(string)	append a string to the output buffer
    556  *			    	avoids calls to lprintf (time consuming)
    557  */
    558 void
    559 lprcat(const char *str)
    560 {
    561 	u_char  *str2;
    562 	if (lpnt >= lpend)
    563 		lflush();
    564 	str2 = lpnt;
    565 	while ((*str2++ = *str++) != '\0')
    566 		continue;
    567 	lpnt = str2 - 1;
    568 }
    569 
    570 #ifdef VT100
    571 /*
    572  *	cursor(x,y) 		Subroutine to set the cursor position
    573  *
    574  *	x and y are the cursor coordinates, and lpbuff is the output buffer where
    575  *	escape sequence will be placed.
    576  */
    577 static char    *y_num[] = {
    578 "\33[", "\33[", "\33[2", "\33[3", "\33[4", "\33[5", "\33[6",
    579 "\33[7", "\33[8", "\33[9", "\33[10", "\33[11", "\33[12", "\33[13", "\33[14",
    580 "\33[15", "\33[16", "\33[17", "\33[18", "\33[19", "\33[20", "\33[21", "\33[22",
    581 "\33[23", "\33[24"};
    582 
    583 static char    *x_num[] = {
    584 "H", "H", ";2H", ";3H", ";4H", ";5H", ";6H", ";7H", ";8H", ";9H",
    585 ";10H", ";11H", ";12H", ";13H", ";14H", ";15H", ";16H", ";17H", ";18H", ";19H",
    586 ";20H", ";21H", ";22H", ";23H", ";24H", ";25H", ";26H", ";27H", ";28H", ";29H",
    587 ";30H", ";31H", ";32H", ";33H", ";34H", ";35H", ";36H", ";37H", ";38H", ";39H",
    588 ";40H", ";41H", ";42H", ";43H", ";44H", ";45H", ";46H", ";47H", ";48H", ";49H",
    589 ";50H", ";51H", ";52H", ";53H", ";54H", ";55H", ";56H", ";57H", ";58H", ";59H",
    590 ";60H", ";61H", ";62H", ";63H", ";64H", ";65H", ";66H", ";67H", ";68H", ";69H",
    591 ";70H", ";71H", ";72H", ";73H", ";74H", ";75H", ";76H", ";77H", ";78H", ";79H",
    592 ";80H"};
    593 
    594 void
    595 cursor(x, y)
    596 	int             x, y;
    597 {
    598 	char  *p;
    599 	if (lpnt >= lpend)
    600 		lflush();
    601 
    602 	p = y_num[y];		/* get the string to print */
    603 	while (*p)
    604 		*lpnt++ = *p++;	/* print the string */
    605 
    606 	p = x_num[x];		/* get the string to print */
    607 	while (*p)
    608 		*lpnt++ = *p++;	/* print the string */
    609 }
    610 #else	/* VT100 */
    611 /*
    612  * cursor(x,y)	  Put cursor at specified coordinates staring at [1,1] (termcap)
    613  */
    614 void
    615 cursor(int x, int y)
    616 {
    617 	if (lpnt >= lpend)
    618 		lflush();
    619 
    620 	*lpnt++ = CURSOR;
    621 	*lpnt++ = x;
    622 	*lpnt++ = y;
    623 }
    624 #endif	/* VT100 */
    625 
    626 /*
    627  *	Routine to position cursor at beginning of 24th line
    628  */
    629 void
    630 cursors(void)
    631 {
    632 	cursor(1, 24);
    633 }
    634 
    635 #ifndef VT100
    636 /*
    637  * Warning: ringing the bell is control code 7. Don't use in defines.
    638  * Don't change the order of these defines.
    639  * Also used in helpfiles. Codes used in helpfiles should be \E[1 to \E[7 with
    640  * obvious meanings.
    641  */
    642 
    643 static char    *outbuf = 0;     /* translated output buffer */
    644 /*
    645  * init_term()		Terminal initialization -- setup termcap info
    646  */
    647 void
    648 init_term(void)
    649 {
    650 	setupterm(NULL, 0, NULL); /* will exit if invalid term */
    651 	if (!cursor_address) {
    652 		fprintf(stderr, "term does not have cursor_address.\n");
    653 		exit(1);
    654 	}
    655 	if (!clr_eol) {
    656 		fprintf(stderr, "term does not have clr_eol.\n");
    657 		exit(1);
    658 	}
    659 	if (!clear_screen) {
    660 		fprintf(stderr, "term does not have clear_screen.\n");
    661 		exit(1);
    662 	}
    663 	if ((outbuf = malloc(BUFBIG + 16)) == 0) {      /* get memory for
    664 							 * decoded output buffer */
    665 	    fprintf(stderr, "Error malloc'ing memory for decoded output buffer\n");
    666 	    died(-285);     /* malloc() failure */
    667 	}
    668 
    669 }
    670 #endif	/* VT100 */
    671 
    672 /*
    673  * cl_line(x,y)  Clear the whole line indicated by 'y' and leave cursor at [x,y]
    674  */
    675 void
    676 cl_line(int x, int y)
    677 {
    678 #ifdef VT100
    679 	cursor(x, y);
    680 	lprcat("\33[2K");
    681 #else	/* VT100 */
    682 	cursor(1, y);
    683 	*lpnt++ = CL_LINE;
    684 	cursor(x, y);
    685 #endif	/* VT100 */
    686 }
    687 
    688 /*
    689  * cl_up(x,y) Clear screen from [x,1] to current position. Leave cursor at [x,y]
    690  */
    691 void
    692 cl_up(int x, int y)
    693 {
    694 #ifdef VT100
    695 	cursor(x, y);
    696 	lprcat("\33[1J\33[2K");
    697 #else	/* VT100 */
    698 	int    i;
    699 	cursor(1, 1);
    700 	for (i = 1; i <= y; i++) {
    701 		*lpnt++ = CL_LINE;
    702 		*lpnt++ = '\n';
    703 	}
    704 	cursor(x, y);
    705 #endif	/* VT100 */
    706 }
    707 
    708 /*
    709  * cl_dn(x,y) 	Clear screen from [1,y] to end of display. Leave cursor at [x,y]
    710  */
    711 void
    712 cl_dn(int x, int y)
    713 {
    714 #ifdef VT100
    715 	cursor(x, y);
    716 	lprcat("\33[J\33[2K");
    717 #else	/* VT100 */
    718 	int    i;
    719 	cursor(1, y);
    720 	if (!clr_eos) {
    721 		*lpnt++ = CL_LINE;
    722 		for (i = y; i <= 24; i++) {
    723 			*lpnt++ = CL_LINE;
    724 			if (i != 24)
    725 				*lpnt++ = '\n';
    726 		}
    727 		cursor(x, y);
    728 	} else
    729 		*lpnt++ = CL_DOWN;
    730 	cursor(x, y);
    731 #endif	/* VT100 */
    732 }
    733 
    734 /*
    735  * standout(str)	Print the argument string in inverse video (standout mode).
    736  */
    737 void
    738 standout(const char *str)
    739 {
    740 #ifdef VT100
    741 	setbold();
    742 	while (*str)
    743 		*lpnt++ = *str++;
    744 	resetbold();
    745 #else	/* VT100 */
    746 	*lpnt++ = ST_START;
    747 	while (*str)
    748 		*lpnt++ = *str++;
    749 	*lpnt++ = ST_END;
    750 #endif	/* VT100 */
    751 }
    752 
    753 /*
    754  * set_score_output() 	Called when output should be literally printed.
    755  */
    756 void
    757 set_score_output(void)
    758 {
    759 	enable_scroll = -1;
    760 }
    761 
    762 /*
    763  *	lflush()	Flush the output buffer
    764  *
    765  *	Returns nothing of value.
    766  *	for termcap version: Flush output in output buffer according to output
    767  *	status as indicated by `enable_scroll'
    768  */
    769 #ifndef VT100
    770 static int      scrline = 18;	/* line # for wraparound instead of scrolling
    771 				 * if no DL */
    772 void
    773 lflush(void)
    774 {
    775 	int    lpoint;
    776 	u_char  *str;
    777 	static int      curx = 0;
    778 	static int      cury = 0;
    779 
    780 	if ((lpoint = lpnt - lpbuf) > 0) {
    781 #ifdef EXTRA
    782 		c[BYTESOUT] += lpoint;
    783 #endif
    784 		if (enable_scroll <= -1) {
    785 			flush_buf();
    786 			if (write(io_outfd, lpbuf, lpoint) != lpoint)
    787 				write(2, "error writing to output file\n", 29);
    788 			lpnt = lpbuf;	/* point back to beginning of buffer */
    789 			return;
    790 		}
    791 		for (str = lpbuf; str < lpnt; str++) {
    792 			if (*str >= 32) {
    793 				ttputch(*str);
    794 				curx++;
    795 			} else
    796 				switch (*str) {
    797 				case CLEAR:
    798 					tputs(clear_screen, 0, ttputch);
    799 					curx = cury = 0;
    800 					break;
    801 
    802 				case CL_LINE:
    803 					tputs(clr_eol, 0, ttputch);
    804 					break;
    805 
    806 				case CL_DOWN:
    807 					tputs(clr_eos, 0, ttputch);
    808 					break;
    809 
    810 				case ST_START:
    811 					tputs(enter_standout_mode, 0, ttputch);
    812 					break;
    813 
    814 				case ST_END:
    815 					tputs(exit_standout_mode, 0, ttputch);
    816 					break;
    817 
    818 				case CURSOR:
    819 					curx = *++str - 1;
    820 					cury = *++str - 1;
    821 					tputs(tiparm(cursor_address,
    822 						    cury, curx), 0, ttputch);
    823 					break;
    824 
    825 				case '\n':
    826 					if ((cury == 23) && enable_scroll) {
    827 						if (!delete_line ||
    828 						    !insert_line)
    829 						{	/* wraparound or scroll? */
    830 							if (++scrline > 23)
    831 								scrline = 19;
    832 
    833 							if (++scrline > 23)
    834 								scrline = 19;
    835 							tputs(tiparm(
    836 							    cursor_address,
    837 							    scrline, 0),
    838 							    0, ttputch);
    839 							tputs(clr_eol, 0,
    840 							    ttputch);
    841 
    842 							if (--scrline < 19)
    843 								scrline = 23;
    844 							tputs(tiparm(
    845 							    cursor_address,
    846 							    scrline, 0),
    847 							    0, ttputch);
    848 							tputs(clr_eol, 0,
    849 							    ttputch);
    850 						} else {
    851 							tputs(tiparm(
    852 							    cursor_address,
    853 							    19, 0),
    854 							    0, ttputch);
    855 							tputs(delete_line, 0,
    856 							    ttputch);
    857 							tputs(tiparm(
    858 							    cursor_address,
    859 							    23, 0),
    860 							    0, ttputch);
    861 							/*
    862 							 * tputs (AL, 0,
    863 							 * ttputch);
    864 							 */
    865 						}
    866 					} else {
    867 						ttputch('\n');
    868 						cury++;
    869 					}
    870 					curx = 0;
    871 					break;
    872 
    873 				default:
    874 					ttputch(*str);
    875 					curx++;
    876 				};
    877 		}
    878 	}
    879 	lpnt = lpbuf;
    880 	flush_buf();		/* flush real output buffer now */
    881 }
    882 #else	/* VT100 */
    883 /*
    884  *	lflush()		flush the output buffer
    885  *
    886  *	Returns nothing of value.
    887  */
    888 void
    889 lflush()
    890 {
    891 	int    lpoint;
    892 	if ((lpoint = lpnt - lpbuf) > 0) {
    893 #ifdef EXTRA
    894 		c[BYTESOUT] += lpoint;
    895 #endif
    896 		if (write(io_outfd, lpbuf, lpoint) != lpoint)
    897 			write(2, "error writing to output file\n", 29);
    898 	}
    899 	lpnt = lpbuf;		/* point back to beginning of buffer */
    900 }
    901 #endif	/* VT100 */
    902 
    903 #ifndef VT100
    904 static int      vindex = 0;
    905 /*
    906  * ttputch(ch)		Print one character in decoded output buffer.
    907  */
    908 static int
    909 ttputch(int ch)
    910 {
    911 	outbuf[vindex++] = ch;
    912 	if (vindex >= BUFBIG)
    913 		flush_buf();
    914 	return (0);
    915 }
    916 
    917 /*
    918  * flush_buf()			Flush buffer with decoded output.
    919  */
    920 static void
    921 flush_buf(void)
    922 {
    923 	if (vindex)
    924 		write(io_outfd, outbuf, vindex);
    925 	vindex = 0;
    926 }
    927 
    928 /*
    929  *	char *tmcapcnv(sd,ss)  Routine to convert VT100 escapes to termcap
    930  *	format
    931  *	Processes only the \33[#m sequence (converts . files for termcap use
    932  */
    933 char *
    934 tmcapcnv(char *sd, char *ss)
    935 {
    936 	int    tmstate = 0;	/* 0=normal, 1=\33 2=[ 3=# */
    937 	char            tmdigit = 0;	/* the # in \33[#m */
    938 	while (*ss) {
    939 		switch (tmstate) {
    940 		case 0:
    941 			if (*ss == '\33') {
    942 				tmstate++;
    943 				break;
    944 			}
    945 	ign:		*sd++ = *ss;
    946 	ign2:		tmstate = 0;
    947 			break;
    948 		case 1:
    949 			if (*ss != '[')
    950 				goto ign;
    951 			tmstate++;
    952 			break;
    953 		case 2:
    954 			if (isdigit((u_char)*ss)) {
    955 				tmdigit = *ss - '0';
    956 				tmstate++;
    957 				break;
    958 			}
    959 			if (*ss == 'm') {
    960 				*sd++ = ST_END;
    961 				goto ign2;
    962 			}
    963 			goto ign;
    964 		case 3:
    965 			if (*ss == 'm') {
    966 				if (tmdigit)
    967 					*sd++ = ST_START;
    968 				else
    969 					*sd++ = ST_END;
    970 				goto ign2;
    971 			}
    972 		default:
    973 			goto ign;
    974 		};
    975 		ss++;
    976 	}
    977 	*sd = 0;		/* NULL terminator */
    978 	return (sd);
    979 }
    980 #endif	/* VT100 */
    981 
    982 /*
    983  *	beep()	Routine to emit a beep if enabled (see no-beep in .larnopts)
    984  */
    985 void
    986 beep(void)
    987 {
    988 	if (!nobeep)
    989 		*lpnt++ = '\7';
    990 }
    991