xref: /netbsd-src/games/larn/io.c (revision 8f8b6fe67935084a12ff1cbe58c6b2eaca42993a)
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
setupvt100(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
clearvt100(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
ttgetch(void)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
scbr(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
sncbr(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
newgame(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
lprintf(const char * fmt,...)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
lprint(long x)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
lwrite(char * buf,int len)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
lgetc(void)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
larn_lrint(void)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
lrfill(char * adr,int num)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 *
lgetw(void)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 *
lgetl(void)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
lcreat(char * str)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
lopen(char * str)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
lappend(char * str)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
lrclose(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
lwclose(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
lprcat(const char * str)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
cursor(x,y)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
cursor(int x,int y)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
cursors(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
init_term(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
cl_line(int x,int y)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
cl_up(int x,int y)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
cl_dn(int x,int y)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
standout(const char * str)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
set_score_output(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
lflush(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
lflush()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
ttputch(int ch)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
flush_buf(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 *
tmcapcnv(char * sd,char * ss)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
beep(void)986 beep(void)
987 {
988 	if (!nobeep)
989 		*lpnt++ = '\7';
990 }
991