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