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