home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 8 / FreshFishVol8-CD1.bin / useful / util / edit / vim / src / termlib.c < prev    next >
C/C++ Source or Header  |  1994-08-09  |  16KB  |  648 lines

  1. /* vi:sw=4:ts=4:
  2.    The following software is (C) 1984 Peter da Silva,
  3.    the Mad Australian, in the public domain. It may
  4.    be re-distributed for any purpose with the inclusion
  5.    of this notice. */
  6.  
  7. /* modified by Bram Moolenaar for use with VIM - Vi Improved */
  8.  
  9. /* TERMLIB: Terminal independant database. */
  10.  
  11. #include "vim.h"
  12. #include "proto.h"
  13. #include "proto/termlib.pro"
  14.  
  15. #ifndef AMIGA
  16. # include <sgtty.h>
  17. #endif
  18.  
  19. static int    getent __PARMS((char *, char *, FILE *, int));
  20. static int    nextent __PARMS((char *, FILE *, int));
  21. static int    _match __PARMS((char *, char *));
  22. static char    *_addfmt __PARMS((char *, char *, int));
  23. static char    *_find __PARMS((char *, char *));
  24.  
  25. /*
  26.  * Global variables for termlib
  27.  */
  28.  
  29. char    *tent;                /* Pointer to terminal entry, set by tgetent */
  30. char    PC = 0;               /* Pad character, default NULL */
  31. char    *UP = 0, *BC = 0;     /* Pointers to UP and BC strings from database */
  32. short    ospeed;               /* Baud rate (1-16, 1=300, 16=19200), as in stty */
  33.  
  34. /*
  35.  * Module: tgetent
  36.  *
  37.  * Purpose: Get termcap entry for <term> into buffer at <tbuf>.
  38.  *
  39.  * Calling conventions: char tbuf[TBUFSZ+], term=canonical name for
  40.  *            terminal.
  41.  *
  42.  * Returned values: 1 = success, -1 = can't open file,
  43.  *            0 = can't find terminal.
  44.  *
  45.  * Notes
  46.  *        Should probably supply static buffer.
  47.  *
  48.  *        Uses environment variables "TERM" and
  49.  *    "TERMCAP". If TERM = term (that is, if the argument
  50.  *    matches the environment) then it looks at TERMCAP.
  51.  *        If TERMCAP begins with a slash, then it assumes
  52.  *    this is the file to search rather than /etc/termcap.
  53.  *        If TERMCAP does not begin with a slash, and it
  54.  *    matches TERM, then this is used as the entry.
  55.  *
  56.  *        This could be simplified considerably for non-UNIX
  57.  *    systems.
  58.  */
  59.  
  60. #ifdef AMIGA
  61. # define TERMCAPFILE "s:termcap"
  62. #else
  63. # define TERMCAPFILE "/etc/termcap"
  64. #endif
  65.  
  66. tgetent(tbuf, term)
  67.     char    *tbuf;               /* Buffer to hold termcap entry, TBUFSZ bytes max */
  68.     char    *term;               /* Name of terminal */
  69. {
  70.     char    tcbuf[32];           /* Temp buffer to handle */
  71.     char    *tcptr = tcbuf;      /* extended entries */
  72.     char    *tcap = TERMCAPFILE; /* Default termcap file */
  73.     char    *tmp;
  74.     FILE    *termcap;
  75.     int        retval = 0;
  76.     int        len;
  77.  
  78.     if ((tmp = (char *)vimgetenv("TERMCAP")) != NULL)
  79.     {
  80.         if (*tmp == '/')            /* TERMCAP = name of termcap file */
  81.             tcap = tmp ;
  82.         else                        /* TERMCAP = termcap entry itself */
  83.         {
  84.             int tlen = strlen(term);
  85.  
  86.             while (*tmp && *tmp != ':') /* Check if TERM matches */
  87.             {
  88.                 while (*tmp == '|')
  89.                     tmp++;
  90.                 if (_match(tmp, term) == tlen)
  91.                 {
  92.                     strcpy(tbuf, tmp);
  93.                     tent = tbuf;
  94.                     return 1;
  95.                 } 
  96.                 else
  97.                     tmp = _find(tmp, ":|");
  98.             }
  99.         }
  100.     }
  101.     if (!(termcap = fopen(tcap, "r")))
  102.     {
  103.         strcpy(tbuf, tcap);
  104.         return -1;
  105.     }
  106.  
  107.     len = 0;
  108.     while (getent(tbuf + len, term, termcap, TBUFSZ - len))
  109.     {
  110.         if ((term = tgetstr("tc", &tcptr)))         /* extended entry */
  111.         {
  112.             rewind(termcap);
  113.             len = strlen(tbuf);
  114.         }
  115.         else
  116.         {
  117.             retval = 1; 
  118.             tent = tbuf;
  119.             break;
  120.         }
  121.     }
  122.     fclose(termcap);
  123.     return retval;
  124. }
  125.  
  126.     static int
  127. getent(tbuf, term, termcap, buflen)
  128.     char    *tbuf, *term;
  129.     FILE    *termcap;
  130.     int        buflen;
  131. {
  132.     char    *tptr;
  133.     int        tlen = strlen(term);
  134.  
  135.     while (nextent(tbuf, termcap, buflen))   /* For each possible entry */
  136.     {
  137.         tptr = tbuf;
  138.         while (*tptr && *tptr != ':')    /* : terminates name field */
  139.         {
  140.             while (*tptr == '|')             /* | seperates names */
  141.                 tptr++;
  142.             if (_match(tptr, term) == tlen)             /* FOUND! */
  143.             {
  144.                 tent = tbuf;
  145.                 return 1;
  146.             } 
  147.             else                           /* Look for next name */
  148.                 tptr = _find(tptr, ":|");
  149.         }
  150.     }
  151.     return 0;
  152. }
  153.  
  154.     static int
  155. nextent(tbuf, termcap, buflen)         /* Read 1 entry from TERMCAP file */
  156.     char    *tbuf;
  157.     FILE    *termcap;
  158.     int        buflen;
  159. {
  160.     char *lbuf = tbuf;           /* lbuf=line buffer */
  161.                                  /* read lines straight into buffer */
  162.  
  163.     while (lbuf < tbuf+buflen &&                        /* There's room and */
  164.           fgets(lbuf, (int)(tbuf+buflen-lbuf), termcap))        /* another line */
  165.     {
  166.         int llen = strlen(lbuf);
  167.  
  168.         if (*lbuf == '#')                               /* eat comments */
  169.             continue;
  170.         if (lbuf[-1] == ':' &&                        /* and whitespace */
  171.             lbuf[0] == '\t' &&
  172.             lbuf[1] == ':')
  173.         {
  174.             strcpy(lbuf, lbuf+2);
  175.             llen -= 2;
  176.         }
  177.         if (lbuf[llen-2] == '\\')                  /* and continuations */
  178.             lbuf += llen-2;
  179.         else
  180.         {
  181.             lbuf[llen-1]=0;           /* no continuation, return */
  182.             return 1;
  183.         }
  184.     }
  185.  
  186.     return 0;                                    /* ran into end of file */
  187. }
  188.  
  189. /*
  190.  * Module: tgetflag
  191.  *
  192.  * Purpose: returns flag true or false as to the existence of a given
  193.  *        entry. used with 'bs', 'am', etc...
  194.  *
  195.  * Calling conventions: id is the 2 character capability id.
  196.  *
  197.  * Returned values: 1 for success, 0 for failure.
  198.  */
  199.  
  200. tgetflag(id)
  201.     char *id;
  202. {
  203.     char    buf[256], *ptr = buf;
  204.  
  205.     return tgetstr(id, &ptr) ? 1 : 0;
  206. }
  207.  
  208. /*
  209.  * Module: tgetnum
  210.  *
  211.  * Purpose: get numeric value such as 'li' or 'co' from termcap.
  212.  *
  213.  * Calling conventions: id = 2 character id.
  214.  *
  215.  * Returned values: -1 for failure, else numerical value.
  216.  */
  217.  
  218. tgetnum(id)
  219. char *id;
  220. {
  221.     char *ptr, buf[256];
  222.     ptr = buf;
  223.  
  224.     if (tgetstr(id, &ptr))
  225.         return atoi(buf);
  226.     else
  227.         return 0;
  228. }
  229.  
  230. /*
  231.  * Module: tgetstr
  232.  *
  233.  * Purpose: get terminal capability string from database.
  234.  *
  235.  * Calling conventions: id is the two character capability id.
  236.  *            (*buf) points into a hold buffer for the
  237.  *            id. the capability is copied into the buffer
  238.  *            and (*buf) is advanced to point to the next
  239.  *            free byte in the buffer.
  240.  *
  241.  * Returned values: 0 = no such entry, otherwise returns original
  242.  *            (*buf) (now a pointer to the string).
  243.  *
  244.  * Notes
  245.  *        It also decodes certain escape sequences in the buffer.
  246.  *    they should be obvious from the code:
  247.  *        \E = escape.
  248.  *        \n, \r, \t, \f, \b match the 'c' escapes.
  249.  *        ^x matches control-x (^@...^_).
  250.  *        \nnn matches nnn octal.
  251.  *        \x, where x is anything else, matches x. I differ
  252.  *    from the standard library here, in that I allow ^: to match
  253.  *    :.
  254.  *
  255.  */
  256.  
  257. char *
  258. tgetstr(id, buf)
  259. char    *id, **buf;
  260. {
  261.     int    len = strlen(id);
  262.     char *tmp=tent;
  263.     char *hold;
  264.     int        i;
  265.  
  266.     do {
  267.         tmp = _find(tmp, ":");                     /* For each field */
  268.         while (*tmp == ':')                        /* skip empty fields */
  269.             tmp++;
  270.         if (!*tmp)
  271.             break;
  272.  
  273.         if (_match(id, tmp) == len) {
  274.             tmp += len;                   /* find '=' '@' or '#' */
  275.             if (*tmp == '@')                  /* :xx@: entry for tc */
  276.                 return 0;                   /* deleted entry */
  277.             hold= *buf;
  278.             while (*++tmp && *tmp != ':') {/* not at end of field */
  279.                 switch(*tmp) {
  280.                 case '\\':            /* Expand escapes here */
  281.                     switch(*++tmp) {
  282.                     case 0:        /* ignore backslashes */
  283.                         tmp--;    /* at end of entry */
  284.                         break;   /* shouldn't happen */
  285.                     case 'e':
  286.                     case 'E':                     /* ESC */
  287.                         *(*buf)++ = '\033'; 
  288.                         break;
  289.                     case 'n':                      /* \n */
  290.                         *(*buf)++ = '\n'; 
  291.                         break;
  292.                     case 'r':                      /* \r */
  293.                         *(*buf)++ = '\r'; 
  294.                         break;
  295.                     case 't':                      /* \t */
  296.                         *(*buf)++ = '\t'; 
  297.                         break;
  298.                     case 'b':                      /* \b */
  299.                         *(*buf)++ = '\b'; 
  300.                         break;
  301.                     case 'f':                      /* \f */
  302.                         *(*buf)++ = '\f'; 
  303.                         break;
  304.                     case '0':                    /* \nnn */
  305.                     case '1': 
  306.                     case '2': 
  307.                     case '3': 
  308.                     case '4':
  309.                     case '5': 
  310.                     case '6': 
  311.                     case '7': 
  312.                     case '8': 
  313.                     case '9':
  314.                         **buf = 0;
  315.                             /* get up to three digits */
  316.                         for (i = 0; i < 3 && isdigit(*tmp); ++i)
  317.                             **buf = **buf * 8 + *tmp++ - '0';
  318.                         (*buf)++;
  319.                         tmp--;
  320.                         break;
  321.                     default:      /* \x, for all other x */
  322.                         *(*buf)++= *tmp;
  323.                     }
  324.                     break;
  325.                 case '^':              /* control characters */
  326.                     *(*buf)++ = *++tmp - '@'; 
  327.                     break;
  328.                 default: 
  329.                     *(*buf)++ = *tmp;
  330.                 }
  331.             }
  332.             *(*buf)++ = 0;
  333.             return hold;
  334.         }
  335.     } while (*tmp);
  336.  
  337.     return 0;
  338. }
  339.  
  340. /*
  341.  * Module: tgoto
  342.  *
  343.  * Purpose: decode cm cursor motion string.
  344.  *
  345.  * Calling conventions: cm is cursor m