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