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