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