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