home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / games / larn / io.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-03-05  |  21.9 KB  |  916 lines

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