termlib.c
上传用户:gddssl
上传日期:2007-01-06
资源大小:1003k
文件大小:14k
源码类别:

编辑器/阅读器

开发平台:

DOS

  1. /* vi:set ts=8 sts=4 sw=4: */
  2. /*
  3.  * The following software is (C) 1984 Peter da Silva, the Mad Australian, in
  4.  * the public domain. It may be re-distributed for any purpose with the
  5.  * inclusion of this notice.
  6.  */
  7. /* Modified by Bram Moolenaar for use with VIM - Vi Improved. */
  8. /* A few bugs removed by Olaf 'Rhialto' Seibert. */
  9. /* TERMLIB: Terminal independant database. */
  10. #include "vim.h"
  11. #include "termlib.pro"
  12. #if !defined(AMIGA) && !defined(VMS) && !defined(macintosh) && !defined(RISCOS)
  13. # include <sgtty.h>
  14. #endif
  15. static int  getent __ARGS((char *, char *, FILE *, int));
  16. static int  nextent __ARGS((char *, FILE *, int));
  17. static int  _match __ARGS((char *, char *));
  18. static char *_addfmt __ARGS((char *, char *, int));
  19. static char *_find __ARGS((char *, char *));
  20. /*
  21.  * Global variables for termlib
  22.  */
  23. char *tent;       /* Pointer to terminal entry, set by tgetent */
  24. char PC = 0;       /* Pad character, default NULL */
  25. char *UP = 0, *BC = 0;     /* Pointers to UP and BC strings from database */
  26. short ospeed;       /* Baud rate (1-16, 1=300, 16=19200), as in stty */
  27. /*
  28.  * Module: tgetent
  29.  *
  30.  * Purpose: Get termcap entry for <term> into buffer at <tbuf>.
  31.  *
  32.  * Calling conventions: char tbuf[TBUFSZ+], term=canonical name for terminal.
  33.  *
  34.  * Returned values: 1 = success, -1 = can't open file,
  35.  *     0 = can't find terminal.
  36.  *
  37.  * Notes:
  38.  * - Should probably supply static buffer.
  39.  * - Uses environment variables "TERM" and "TERMCAP". If TERM = term (that is,
  40.  *   if the argument matches the environment) then it looks at TERMCAP.
  41.  * - If TERMCAP begins with a slash, then it assumes this is the file to
  42.  *   search rather than /etc/termcap.
  43.  * - If TERMCAP does not begin with a slash, and it matches TERM, then this is
  44.  *   used as the entry.
  45.  * - This could be simplified considerably for non-UNIX systems.
  46.  */
  47. #ifndef TERMCAPFILE
  48. # ifdef AMIGA
  49. #  define TERMCAPFILE "s:termcap"
  50. # else
  51. #  define TERMCAPFILE "/etc/termcap"
  52. # endif
  53. #endif
  54. tgetent(tbuf, term)
  55.     char    *tbuf; /* Buffer to hold termcap entry, TBUFSZ bytes max */
  56.     char    *term; /* Name of terminal */
  57. {
  58.     char    tcbuf[32]; /* Temp buffer to handle */
  59.     char    *tcptr = tcbuf; /* extended entries */
  60.     char    *tcap = TERMCAPFILE; /* Default termcap file */
  61.     char    *tmp;
  62.     FILE    *termcap;
  63.     int     retval = 0;
  64.     int     len;
  65.     if ((tmp = (char *)mch_getenv((char_u *)"TERMCAP")) != NULL)
  66.     {
  67. if (*tmp == '/') /* TERMCAP = name of termcap file */
  68. {
  69.     tcap = tmp ;
  70. #if defined(AMIGA)
  71.     /* Convert /usr/share/lib/termcap to usr:share/lib/termcap */
  72.     tcap++;
  73.     tmp = strchr(tcap, '/');
  74.     if (tmp)
  75. *tmp = ':';
  76. #endif
  77. }
  78. else /* TERMCAP = termcap entry itself */
  79. {
  80.     int tlen = strlen(term);
  81.     while (*tmp && *tmp != ':') /* Check if TERM matches */
  82.     {
  83. char *nexttmp;
  84. while (*tmp == '|')
  85.     tmp++;
  86. nexttmp  = _find(tmp, ":|"); /* Rhialto */
  87. if (tmp+tlen == nexttmp && _match(tmp, term) == tlen)
  88. {
  89.     strcpy(tbuf, tmp);
  90.     tent = tbuf;
  91.     return 1;
  92. }
  93. else
  94.     tmp = nexttmp;
  95.     }
  96. }
  97.     }
  98.     if (!(termcap = fopen(tcap, "r")))
  99.     {
  100. strcpy(tbuf, tcap);
  101. return -1;
  102.     }
  103.     len = 0;
  104.     while (getent(tbuf + len, term, termcap, TBUFSZ - len))
  105.     {
  106. tcptr = tcbuf; /* Rhialto */
  107. if ((term = tgetstr("tc", &tcptr))) /* extended entry */
  108. {
  109.     rewind(termcap);
  110.     len = strlen(tbuf);
  111. }
  112. else
  113. {
  114.     retval = 1;
  115.     tent = tbuf; /* reset it back to the beginning */
  116.     break;
  117. }
  118.     }
  119.     fclose(termcap);
  120.     return retval;
  121. }
  122.     static int
  123. getent(tbuf, term, termcap, buflen)
  124.     char    *tbuf, *term;
  125.     FILE    *termcap;
  126.     int     buflen;
  127. {
  128.     char    *tptr;
  129.     int     tlen = strlen(term);
  130.     while (nextent(tbuf, termcap, buflen)) /* For each possible entry */
  131.     {
  132. tptr = tbuf;
  133. while (*tptr && *tptr != ':') /* : terminates name field */
  134. {
  135.     char    *nexttptr;
  136.     while (*tptr == '|') /* | seperates names */
  137. tptr++;
  138.     nexttptr = _find(tptr, ":|"); /* Rhialto */
  139.     if (tptr + tlen == nexttptr &&
  140. _match(tptr, term) == tlen) /* FOUND! */
  141.     {
  142. tent = tbuf;
  143. return 1;
  144.     }
  145.     else /* Look for next name */
  146. tptr = nexttptr;
  147. }
  148.     }
  149.     return 0;
  150. }
  151.     static int
  152. nextent(tbuf, termcap, buflen) /* Read 1 entry from TERMCAP file */
  153.     char    *tbuf;
  154.     FILE    *termcap;
  155.     int     buflen;
  156. {
  157.     char *lbuf = tbuf; /* lbuf=line buffer */
  158. /* read lines straight into buffer */
  159.     while (lbuf < tbuf+buflen && /* There's room and */
  160.   fgets(lbuf, (int)(tbuf+buflen-lbuf), termcap)) /* another line */
  161.     {
  162. int llen = strlen(lbuf);
  163. if (*lbuf == '#') /* eat comments */
  164.     continue;
  165. if (lbuf[-1] == ':' && /* and whitespace */
  166.     lbuf[0] == 't' &&
  167.     lbuf[1] == ':')
  168. {
  169.     strcpy(lbuf, lbuf+2);
  170.     llen -= 2;
  171. }
  172. if (lbuf[llen-2] == '\') /* and continuations */
  173.     lbuf += llen-2;
  174. else
  175. {
  176.     lbuf[llen-1]=0; /* no continuation, return */
  177.     return 1;
  178. }
  179.     }
  180.     return 0; /* ran into end of file */
  181. }
  182. /*
  183.  * Module: tgetflag
  184.  *
  185.  * Purpose: returns flag true or false as to the existence of a given entry.
  186.  * used with 'bs', 'am', etc...
  187.  *
  188.  * Calling conventions: id is the 2 character capability id.
  189.  *
  190.  * Returned values: 1 for success, 0 for failure.
  191.  */
  192. tgetflag(id)
  193.     char *id;
  194. {
  195.     char    buf[256], *ptr = buf;
  196.     return tgetstr(id, &ptr) ? 1 : 0;
  197. }
  198. /*
  199.  * Module: tgetnum
  200.  *
  201.  * Purpose: get numeric value such as 'li' or 'co' from termcap.
  202.  *
  203.  * Calling conventions: id = 2 character id.
  204.  *
  205.  * Returned values: -1 for failure, else numerical value.
  206.  */
  207. tgetnum(id)
  208.     char *id;
  209. {
  210.     char *ptr, buf[256];
  211.     ptr = buf;
  212.     if (tgetstr(id, &ptr))
  213. return atoi(buf);
  214.     else
  215. return 0;
  216. }
  217. /*
  218.  * Module: tgetstr
  219.  *
  220.  * Purpose: get terminal capability string from database.
  221.  *
  222.  * Calling conventions: id is the two character capability id.
  223.  *     (*buf) points into a hold buffer for the
  224.  *     id. the capability is copied into the buffer
  225.  *     and (*buf) is advanced to point to the next
  226.  *     free byte in the buffer.
  227.  *
  228.  * Returned values: 0 = no such entry, otherwise returns original
  229.  *     (*buf) (now a pointer to the string).
  230.  *
  231.  * Notes
  232.  * It also decodes certain escape sequences in the buffer.
  233.  *  they should be obvious from the code:
  234.  * E = escape.
  235.  * n, r, t, f, b match the 'c' escapes.
  236.  * ^x matches control-x (^@...^_).
  237.  * nnn matches nnn octal.
  238.  * x, where x is anything else, matches x. I differ
  239.  *  from the standard library here, in that I allow ^: to match
  240.  *  :.
  241.  *
  242.  */
  243.     char *
  244. tgetstr(id, buf)
  245.     char *id, **buf;
  246. {
  247.     int len = strlen(id);
  248.     char *tmp=tent;
  249.     char *hold;
  250.     int i;
  251.     do {
  252. tmp = _find(tmp, ":"); /* For each field */
  253. while (*tmp == ':') /* skip empty fields */
  254.     tmp++;
  255. if (!*tmp)
  256.     break;
  257. if (_match(id, tmp) == len) {
  258.     tmp += len; /* find '=' '@' or '#' */
  259.     if (*tmp == '@') /* :xx@: entry for tc */
  260. return 0; /* deleted entry */
  261.     hold= *buf;
  262.     while (*++tmp && *tmp != ':') { /* not at end of field */
  263. switch(*tmp) {
  264. case '\': /* Expand escapes here */
  265.     switch(*++tmp) {
  266.     case 0: /* ignore backslashes */
  267. tmp--; /* at end of entry */
  268. break; /* shouldn't happen */
  269.     case 'e':
  270.     case 'E': /* ESC */
  271. *(*buf)++ = '33';
  272. break;
  273.     case 'n': /* n */
  274. *(*buf)++ = 'n';
  275. break;
  276.     case 'r': /* r */
  277. *(*buf)++ = 'r';
  278. break;
  279.     case 't': /* t */
  280. *(*buf)++ = 't';
  281. break;
  282.     case 'b': /* b */
  283. *(*buf)++ = 'b';
  284. break;
  285.     case 'f': /* f */
  286. *(*buf)++ = 'f';
  287. break;
  288.     case '0': /* nnn */
  289.     case '1':
  290.     case '2':
  291.     case '3':
  292.     case '4':
  293.     case '5':
  294.     case '6':
  295.     case '7':
  296.     case '8':
  297.     case '9':
  298. **buf = 0;
  299.     /* get up to three digits */
  300. for (i = 0; i < 3 && isdigit(*tmp); ++i)
  301.     **buf = **buf * 8 + *tmp++ - '0';
  302. (*buf)++;
  303. tmp--;
  304. break;
  305.     default: /* x, for all other x */
  306. *(*buf)++= *tmp;
  307.     }
  308.     break;
  309. case '^': /* control characters */
  310.     *(*buf)++ = *++tmp - '@';
  311.     break;
  312. default:
  313.     *(*buf)++ = *tmp;
  314. }
  315.     }
  316.     *(*buf)++ = 0;
  317.     return hold;
  318. }
  319.     } while (*tmp);
  320.     return 0;
  321. }
  322. /*
  323.  * Module: tgoto
  324.  *
  325.  * Purpose: decode cm cursor motion string.
  326.  *
  327.  * Calling conventions: cm is cursor motion string.  line, col, are the
  328.  * desired destination.
  329.  *
  330.  * Returned values: a string pointing to the decoded string, or "OOPS" if it
  331.  * cannot be decoded.
  332.  *
  333.  * Notes
  334.  * The accepted escapes are:
  335.  * %d  as in printf, 0 origin.
  336.  * %2, %3   like %02d, %03d in printf.
  337.  * %.  like %c
  338.  * %+x  adds <x> to value, then %.
  339.  * %>xy     if value>x, adds y. No output.
  340.  * %i  increments line& col, no output.
  341.  * %r  reverses order of line&col. No output.
  342.  * %%  prints as a single %.
  343.  * %n  exclusive or row & col with 0140.
  344.  * %B  BCD, no output.
  345.  * %D  reverse coding (x-2*(x%16)), no output.
  346.  */
  347.     char *
  348. tgoto(cm, col, line)
  349.     char *cm; /* cm string, from termcap */
  350.     int col, /* column, x position */
  351.     line; /* line, y position */
  352. {
  353.     char    gx, gy, /* x, y */
  354. *ptr, /* pointer in 'cm' */
  355. reverse = 0, /* reverse flag */
  356. *bufp, /* pointer in returned string */
  357. addup = 0, /* add upline */
  358. addbak = 0, /* add backup */
  359. c;
  360.     static char buffer[32];
  361.     if (!cm)
  362. return "OOPS"; /* Kludge, but standard */
  363.     bufp = buffer;
  364.     ptr = cm;
  365.     while (*ptr) {
  366. if ((c = *ptr++) != '%') { /* normal char */
  367.     *bufp++ = c;
  368. } else { /* % escape */
  369.     switch(c = *ptr++) {
  370.     case 'd': /* decimal */
  371. bufp = _addfmt(bufp, "%d", line);
  372. line = col;
  373. break;
  374.     case '2': /* 2 digit decimal */
  375. bufp = _addfmt(bufp, "%02d", line);
  376. line = col;
  377. break;
  378.     case '3': /* 3 digit decimal */
  379. bufp = _addfmt(bufp, "%03d", line);
  380. line = col;
  381. break;
  382.     case '>': /* %>xy: if >x, add y */
  383. gx = *ptr++;
  384. gy = *ptr++;
  385. if (col>gx) col += gy;
  386. if (line>gx) line += gy;
  387. break;
  388.     case '+': /* %+c: add c */
  389. line += *ptr++;
  390.     case '.': /* print x/y */
  391. if (line == 't' || /* these are */
  392.    line == 'n' || /* chars that */
  393.    line == '04' || /* UNIX hates */
  394.    line == '') {
  395.     line++; /* so go to next pos */
  396.     if (reverse == (line == col))
  397. addup=1; /* and mark UP */
  398.     else
  399. addbak=1; /* or BC */
  400. }
  401. *bufp++=line;
  402. line = col;
  403. break;
  404.     case 'r': /* r: reverse */
  405. gx = line;
  406. line = col;
  407. col = gx;
  408. reverse = 1;
  409. break;
  410.     case 'i': /* increment (1-origin screen) */
  411. col++;
  412. line++;
  413. break;
  414.     case '%': /* %%=% literally */
  415. *bufp++='%';
  416. break;
  417.     case 'n': /* magic DM2500 code */
  418. line ^= 0140;
  419. col ^= 0140;
  420. break;
  421.     case 'B': /* bcd encoding */
  422. line = line/10<<4+line%10;
  423. col = col/10<<4+col%10;
  424. break;
  425.     case 'D': /* magic Delta Data code */
  426. line = line-2*(line&15);
  427. col = col-2*(col&15);
  428. break;
  429.     default: /* Unknown escape */
  430. return "OOPS";
  431.     }
  432. }
  433.     }
  434.     if (addup) /* add upline */
  435. if (UP) {
  436.     ptr=UP;
  437.     while (isdigit(*ptr) || *ptr == '.')
  438. ptr++;
  439.     if (*ptr == '*')
  440. ptr++;
  441.     while (*ptr)
  442. *bufp++ = *ptr++;
  443. }
  444.     if (addbak) /* add backspace */
  445. if (BC) {
  446.     ptr=BC;
  447.     while (isdigit(*ptr) || *ptr == '.')
  448. ptr++;
  449.     if (*ptr == '*')
  450. ptr++;
  451.     while (*ptr)
  452. *bufp++ = *ptr++;
  453. }
  454. else
  455.     *bufp++='b';
  456.     *bufp = 0;
  457.     return(buffer);
  458. }
  459. /*
  460.  * Module: tputs
  461.  *
  462.  * Purpose: decode padding information
  463.  *
  464.  * Calling conventions: cp = string to be padded, affcnt = # of items affected
  465.  * (lines, characters, whatever), outc = routine to output 1 character.
  466.  *
  467.  * Returned values: none
  468.  *
  469.  * Notes
  470.  * cp has padding information ahead of it, in the form
  471.  *  nnnTEXT or nnn*TEXT. nnn is the number of milliseconds to delay,
  472.  *  and may be a decimal (nnn.mmm). If the asterisk is given, then
  473.  *  the delay is multiplied by afcnt. The delay is produced by outputting
  474.  *  a number of nulls (or other padding char) after printing the
  475.  *  TEXT.
  476.  *
  477.  */
  478. long _bauds[16]={
  479.     0, 50, 75, 110,
  480.     134,    150,    200,    300,
  481.     600,    1200,   1800,   2400,
  482.     4800,   9600,   19200,  19200 };
  483. tputs(cp, affcnt, outc)
  484.     char *cp; /* string to print */
  485.     int affcnt; /* Number of lines affected */
  486.     void (*outc) __ARGS((unsigned int));/* routine to output 1 character */
  487. {
  488.     long    frac, /* 10^(#digits after decimal point) */
  489. counter, /* digits */
  490. atol __ARGS((const char *));
  491.     if (isdigit(*cp)) {
  492. counter = 0;
  493. frac = 1000;
  494. while (isdigit(*cp))
  495.     counter = counter * 10L + (long)(*cp++ - '0');
  496. if (*cp == '.')
  497.     while (isdigit(*++cp)) {
  498. counter = counter * 10L + (long)(*cp++ - '0');
  499. frac = frac * 10;
  500.     }
  501. if (*cp!='*') { /* multiply by affected lines */
  502.     if (affcnt>1) affcnt = 1;
  503. }
  504. else
  505.     cp++;
  506. /* Calculate number of characters for padding counter/frac ms delay */
  507. if (ospeed)
  508.     counter = (counter * _bauds[ospeed] * (long)affcnt) / frac;
  509. while (*cp) /* output string */
  510.     (*outc)(*cp++);
  511. if (ospeed)
  512.     while (counter--) /* followed by pad characters */
  513. (*outc)(PC);
  514.     }
  515.     else
  516. while (*cp)
  517.     (*outc)(*cp++);
  518.     return 0;
  519. }
  520. /*
  521.  * Module: tutil.c
  522.  *
  523.  * Purpose: Utility routines for TERMLIB functions.
  524.  *
  525.  */
  526.     static int
  527. _match(s1, s2) /* returns length of text common to s1 and s2 */
  528.     char *s1, *s2;
  529. {
  530.     int i = 0;
  531.     while (s1[i] && s1[i] == s2[i])
  532. i++;
  533.     return i;
  534. }
  535. /*
  536.  * finds next c in s that's a member of set, returns pointer
  537.  */
  538.     static char *
  539. _find(s, set)
  540.     char *s, *set;
  541. {
  542.     for(; *s; s++)
  543.     {
  544. char *ptr = set;
  545. while (*ptr && *s != *ptr)
  546.     ptr++;
  547. if (*ptr)
  548.     return s;
  549.     }
  550.     return s;
  551. }
  552. /*
  553.  * add val to buf according to format fmt
  554.  */
  555.     static char *
  556. _addfmt(buf, fmt, val)
  557.     char *buf, *fmt;
  558.     int val;
  559. {
  560.     sprintf(buf, fmt, val);
  561.     while (*buf)
  562. buf++;
  563.     return buf;
  564. }