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