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