]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - larn/io.c
Convert to something resembling KNF.
[bsdgames-darwin.git] / larn / io.c
1 /* $NetBSD: io.c,v 1.7 1997/10/18 20:03:26 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 * getchar() 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.7 1997/10/18 20:03:26 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 * getchar() Routine to read in one character from the terminal
168 */
169 int
170 getchar()
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[256];
767 char *CM, *CE, *CD, *CL, *SO, *SE, *AL, *DL; /* Termcap capabilities */
768 static char *outbuf = 0; /* translated output buffer */
769
770 /*
771 * init_term() Terminal initialization -- setup termcap info
772 */
773 void
774 init_term()
775 {
776 char termbuf[1024];
777 char *capptr = cap + 10;
778 char *term;
779
780 switch (tgetent(termbuf, term = getenv("TERM"))) {
781 case -1:
782 write(2, "Cannot open termcap file.\n", 26);
783 exit(1);
784 case 0:
785 write(2, "Cannot find entry of ", 21);
786 write(2, term, strlen(term));
787 write(2, " in termcap\n", 12);
788 exit(1);
789 };
790
791 CM = tgetstr("cm", &capptr); /* Cursor motion */
792 CE = tgetstr("ce", &capptr); /* Clear to eoln */
793 CL = tgetstr("cl", &capptr); /* Clear screen */
794
795 /* OPTIONAL */
796 AL = tgetstr("al", &capptr); /* Insert line */
797 DL = tgetstr("dl", &capptr); /* Delete line */
798 SO = tgetstr("so", &capptr); /* Begin standout mode */
799 SE = tgetstr("se", &capptr); /* End standout mode */
800 CD = tgetstr("cd", &capptr); /* Clear to end of display */
801
802 if (!CM) { /* can't find cursor motion entry */
803 write(2, "Sorry, for a ", 13);
804 write(2, term, strlen(term));
805 write(2, ", I can't find the cursor motion entry in termcap\n", 50);
806 exit(1);
807 }
808 if (!CE) { /* can't find clear to end of line entry */
809 write(2, "Sorry, for a ", 13);
810 write(2, term, strlen(term));
811 write(2, ", I can't find the clear to end of line entry in termcap\n", 57);
812 exit(1);
813 }
814 if (!CL) { /* can't find clear entire screen entry */
815 write(2, "Sorry, for a ", 13);
816 write(2, term, strlen(term));
817 write(2, ", I can't find the clear entire screen entry in termcap\n", 56);
818 exit(1);
819 }
820 if ((outbuf = malloc(BUFBIG + 16)) == 0) { /* get memory for
821 * decoded output buffer */
822 write(2, "Error malloc'ing memory for decoded output buffer\n", 50);
823 died(-285); /* malloc() failure */
824 }
825 }
826 #endif /* VT100 */
827
828 /*
829 * cl_line(x,y) Clear the whole line indicated by 'y' and leave cursor at [x,y]
830 */
831 void
832 cl_line(x, y)
833 int x, y;
834 {
835 #ifdef VT100
836 cursor(x, y);
837 lprcat("\33[2K");
838 #else /* VT100 */
839 cursor(1, y);
840 *lpnt++ = CL_LINE;
841 cursor(x, y);
842 #endif /* VT100 */
843 }
844
845 /*
846 * cl_up(x,y) Clear screen from [x,1] to current position. Leave cursor at [x,y]
847 */
848 void
849 cl_up(x, y)
850 int x, y;
851 {
852 #ifdef VT100
853 cursor(x, y);
854 lprcat("\33[1J\33[2K");
855 #else /* VT100 */
856 int i;
857 cursor(1, 1);
858 for (i = 1; i <= y; i++) {
859 *lpnt++ = CL_LINE;
860 *lpnt++ = '\n';
861 }
862 cursor(x, y);
863 #endif /* VT100 */
864 }
865
866 /*
867 * cl_dn(x,y) Clear screen from [1,y] to end of display. Leave cursor at [x,y]
868 */
869 void
870 cl_dn(x, y)
871 int x, y;
872 {
873 #ifdef VT100
874 cursor(x, y);
875 lprcat("\33[J\33[2K");
876 #else /* VT100 */
877 int i;
878 cursor(1, y);
879 if (!CD) {
880 *lpnt++ = CL_LINE;
881 for (i = y; i <= 24; i++) {
882 *lpnt++ = CL_LINE;
883 if (i != 24)
884 *lpnt++ = '\n';
885 }
886 cursor(x, y);
887 } else
888 *lpnt++ = CL_DOWN;
889 cursor(x, y);
890 #endif /* VT100 */
891 }
892
893 /*
894 * standout(str) Print the argument string in inverse video (standout mode).
895 */
896 void
897 standout(str)
898 char *str;
899 {
900 #ifdef VT100
901 setbold();
902 while (*str)
903 *lpnt++ = *str++;
904 resetbold();
905 #else /* VT100 */
906 *lpnt++ = ST_START;
907 while (*str)
908 *lpnt++ = *str++;
909 *lpnt++ = ST_END;
910 #endif /* VT100 */
911 }
912
913 /*
914 * set_score_output() Called when output should be literally printed.
915 */
916 void
917 set_score_output()
918 {
919 enable_scroll = -1;
920 }
921
922 /*
923 * lflush() Flush the output buffer
924 *
925 * Returns nothing of value.
926 * for termcap version: Flush output in output buffer according to output
927 * status as indicated by `enable_scroll'
928 */
929 #ifndef VT100
930 static int scrline = 18; /* line # for wraparound instead of scrolling
931 * if no DL */
932 void
933 lflush()
934 {
935 int lpoint;
936 u_char *str;
937 static int curx = 0;
938 static int cury = 0;
939
940 if ((lpoint = lpnt - lpbuf) > 0) {
941 #ifdef EXTRA
942 c[BYTESOUT] += lpoint;
943 #endif
944 if (enable_scroll <= -1) {
945 flush_buf();
946 if (write(lfd, lpbuf, lpoint) != lpoint)
947 write(2, "error writing to output file\n", 29);
948 lpnt = lpbuf; /* point back to beginning of buffer */
949 return;
950 }
951 for (str = lpbuf; str < lpnt; str++) {
952 if (*str >= 32) {
953 xputchar(*str);
954 curx++;
955 } else
956 switch (*str) {
957 case CLEAR:
958 tputs(CL, 0, xputchar);
959 curx = cury = 0;
960 break;
961
962 case CL_LINE:
963 tputs(CE, 0, xputchar);
964 break;
965
966 case CL_DOWN:
967 tputs(CD, 0, xputchar);
968 break;
969
970 case ST_START:
971 tputs(SO, 0, xputchar);
972 break;
973
974 case ST_END:
975 tputs(SE, 0, xputchar);
976 break;
977
978 case CURSOR:
979 curx = *++str - 1;
980 cury = *++str - 1;
981 tputs(tgoto(CM, curx, cury), 0, xputchar);
982 break;
983
984 case '\n':
985 if ((cury == 23) && enable_scroll) {
986 if (!DL || !AL) { /* wraparound or scroll? */
987 if (++scrline > 23)
988 scrline = 19;
989
990 if (++scrline > 23)
991 scrline = 19;
992 tputs(tgoto(CM, 0, scrline), 0, xputchar);
993 tputs(CE, 0, xputchar);
994
995 if (--scrline < 19)
996 scrline = 23;
997 tputs(tgoto(CM, 0, scrline), 0, xputchar);
998 tputs(CE, 0, xputchar);
999 } else {
1000 tputs(tgoto(CM, 0, 19), 0, xputchar);
1001 tputs(DL, 0, xputchar);
1002 tputs(tgoto(CM, 0, 23), 0, xputchar);
1003 /*
1004 * tputs (AL, 0,
1005 * xputchar);
1006 */
1007 }
1008 } else {
1009 xputchar('\n');
1010 cury++;
1011 }
1012 curx = 0;
1013 break;
1014
1015 default:
1016 xputchar(*str);
1017 curx++;
1018 };
1019 }
1020 }
1021 lpnt = lpbuf;
1022 flush_buf(); /* flush real output buffer now */
1023 }
1024 #else /* VT100 */
1025 /*
1026 * lflush() flush the output buffer
1027 *
1028 * Returns nothing of value.
1029 */
1030 void
1031 lflush()
1032 {
1033 int lpoint;
1034 if ((lpoint = lpnt - lpbuf) > 0) {
1035 #ifdef EXTRA
1036 c[BYTESOUT] += lpoint;
1037 #endif
1038 if (write(lfd, lpbuf, lpoint) != lpoint)
1039 write(2, "error writing to output file\n", 29);
1040 }
1041 lpnt = lpbuf; /* point back to beginning of buffer */
1042 }
1043 #endif /* VT100 */
1044
1045 #ifndef VT100
1046 static int vindex = 0;
1047 /*
1048 * xputchar(ch) Print one character in decoded output buffer.
1049 */
1050 void
1051 xputchar(c)
1052 int c;
1053 {
1054 outbuf[vindex++] = c;
1055 if (vindex >= BUFBIG)
1056 flush_buf();
1057 }
1058
1059 /*
1060 * flush_buf() Flush buffer with decoded output.
1061 */
1062 void
1063 flush_buf()
1064 {
1065 if (vindex)
1066 write(lfd, outbuf, vindex);
1067 vindex = 0;
1068 }
1069
1070 /*
1071 * char *tmcapcnv(sd,ss) Routine to convert VT100 escapes to termcap
1072 * format
1073 * Processes only the \33[#m sequence (converts . files for termcap use
1074 */
1075 char *
1076 tmcapcnv(sd, ss)
1077 char *sd, *ss;
1078 {
1079 int tmstate = 0; /* 0=normal, 1=\33 2=[ 3=# */
1080 char tmdigit = 0; /* the # in \33[#m */
1081 while (*ss) {
1082 switch (tmstate) {
1083 case 0:
1084 if (*ss == '\33') {
1085 tmstate++;
1086 break;
1087 }
1088 ign: *sd++ = *ss;
1089 ign2: tmstate = 0;
1090 break;
1091 case 1:
1092 if (*ss != '[')
1093 goto ign;
1094 tmstate++;
1095 break;
1096 case 2:
1097 if (isdigit((u_char)*ss)) {
1098 tmdigit = *ss - '0';
1099 tmstate++;
1100 break;
1101 }
1102 if (*ss == 'm') {
1103 *sd++ = ST_END;
1104 goto ign2;
1105 }
1106 goto ign;
1107 case 3:
1108 if (*ss == 'm') {
1109 if (tmdigit)
1110 *sd++ = ST_START;
1111 else
1112 *sd++ = ST_END;
1113 goto ign2;
1114 }
1115 default:
1116 goto ign;
1117 };
1118 ss++;
1119 }
1120 *sd = 0; /* NULL terminator */
1121 return (sd);
1122 }
1123 #endif /* VT100 */
1124
1125 /*
1126 * beep() Routine to emit a beep if enabled (see no-beep in .larnopts)
1127 */
1128 void
1129 beep()
1130 {
1131 if (!nobeep)
1132 *lpnt++ = '\7';
1133 }