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