Merge branch 'vendor/LESS'
[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                 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
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
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
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
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
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 *
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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
1025 beep(void)
1026 {
1027         if (!nobeep)
1028                 *lpnt++ = '\7';
1029 }