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