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