xref: /dragonfly/games/larn/io.c (revision 0fdb7d01c1d7a00967eac4d56eca8dad80b7d642)
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