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