home *** CD-ROM | disk | FTP | other *** search
- /* The following software is (C) 1984 Peter da Silva,
- the Mad Australian, in the public domain. It may
- be re-distributed for any purpose with the inclusion
- of this notice. */
- /* modified by Bram Moolenaar */
-
- /* TERMLIB: Terminal independant database. */
-
- #include "vim.h"
- #include "proto/termlib.pro"
-
- #ifndef AMIGA
- #include <sgtty.h>
- #endif
-
- static int _match __PARMS((char *, char *));
- static char *_addfmt __PARMS((char *, char *, int));
- static char *_find __PARMS((char *, char *));
-
- /*
- * Global variables for termlib
- */
-
- char *tent; /* Pointer to terminal entry, set by tgetent */
- char PC = 0; /* Pad character, default NULL */
- char *UP = 0, *BC = 0; /* Pointers to UP and BC strings from database */
- short ospeed; /* Baud rate (1-16, 1=300, 16=19200), as in stty */
-
- /*
- * Module: tgetent
- *
- * Purpose: Get termcap entry for <term> into buffer at <tbuf>.
- *
- * Calling conventions: char tbuf[1024+], term=canonical name for
- * terminal.
- *
- * Returned values: 1 = success, -1 = can't open file,
- * 0 = can't find terminal.
- *
- * Notes
- * Should probably supply static buffer.
- *
- * Uses environment variables "TERM" and
- * "TERMCAP". If TERM = term (that is, if the argument
- * matches the environment) then it looks at TERMCAP.
- * If TERMCAP begins with a slash, then it assumes
- * this is the file to search rather than /etc/termcap.
- * If TERMCAP does not begin with a slash, and it
- * matches TERM, then this is used as the entry.
- *
- * This could be simplified considerably for non-UNIX
- * systems.
- */
-
- #ifdef AMIGA
- #define TERMCAPFILE "s:termcap"
- #else
- #define TERMCAPFILE "/etc/termcap"
- #endif
-
- tgetent(tbuf, term)
- char *tbuf, /* Buffer to hold termcap entry, 1024 bytes max */
- *term; /* Name of terminal */
- {
- char tcbuf[32], /* Temp buffer to handle */
- *tc, /* :tc=: entry for */
- *tcptr = tcbuf; /* extended entries */
- char *tcap = TERMCAPFILE, /* Default termcap file */
- *getenv();
- char *tmp;
- FILE *termcap;
-
- if((tmp=getenv("TERMCAP")) != NULL) {
- if(*tmp == '/') /* TERMCAP = name of termcap file */
- tcap = tmp ;
- else { /* TERMCAP = termcap entry itself */
- int tlen = strlen(term);
- while(*tmp && *tmp != ':') {/* Check if TERM matches */
- while(*tmp == '|')
- tmp++;
- if(_match(tmp, term)==tlen) {
- strcpy(tbuf, tmp);
- tent=tbuf;
- return 1;
- }
- else
- tmp = _find(tmp, ":|");
- }
- }
- }
- if(!(termcap=fopen(tcap, "r"))) {
- strcpy(tbuf, tcap);
- return -1;
- }
-
- if(getent(tbuf, term, termcap)) {
- if(tc=tgetstr("tc", &tcptr)) { /* extended entry */
- rewind(termcap);
- if(getent(tbuf+strlen(tbuf), tc, termcap)) {
- fclose(termcap); /* Completed */
- return 1;
- }
- else {
- fclose(termcap); /* Incomplete */
- return 0;
- }
- } else {
- fclose(termcap); /* non-extended entry */
- return 1;
- }
- } else {
- fclose(termcap); /* No entry */
- return 0;
- }
- }
-
- getent(tbuf, term, termcap)
- char *tbuf, *term;
- FILE *termcap;
- {
- char *tptr;
- int tlen = strlen(term);
-
- while(nextent(tbuf, termcap)) { /* For each possible entry */
- tptr = tbuf;
- while(*tptr && *tptr != ':') { /* : terminates name field */
- while(*tptr == '|') /* | seperates names */
- tptr++;
- if(_match(tptr, term)==tlen) { /* FOUND! */
- fclose(termcap);
- tent=tbuf;
- return 1;
- }
- else /* Look for next name */
- tptr = _find(tptr, ":|");
- }
- }
-
- return 0;
- }
-
- nextent(tbuf, termcap) /* Read 1 entry from TERMCAP file */
- char *tbuf;
- FILE *termcap;
- {
- char *lbuf = /* lbuf=line buffer */
- tbuf; /* read lines straight into buffer */
-
- while(lbuf < tbuf+1024 && /* There's room and */
- fgets(lbuf, (int)(tbuf+1024-lbuf), termcap)) { /* another line */
- int llen = strlen(lbuf);
-
- if(*lbuf=='#') /* eat comments */
- continue;
- if(lbuf[-1]==':' && /* and whitespace */
- lbuf[0]=='\t' &&
- lbuf[1]==':') {
- strcpy(lbuf, lbuf+2);
- llen -= 2;
- }
- if(lbuf[llen-2]=='\\') /* and continuations */
- lbuf += llen-2;
- else {
- lbuf[llen-1]=0; /* no continuation, return */
- return 1;
- }
- }
-
- return 0; /* ran into end of file */
- }
-
- /*
- * Module: tgetflag
- *
- * Purpose: returns flag true or false as to the existence of a given
- * entry. used with 'bs', 'am', etc...
- *
- * Calling conventions: id is the 2 character capability id.
- *
- * Returned values: 1 for success, 0 for failure.
- */
-
- tgetflag(id)
- char *id;
- {
- char buf[256], *ptr = buf;
-
- return tgetstr(id, &ptr) ? 1 : 0;
- }
-
- /*
- * Module: tgetnum
- *
- * Purpose: get numeric value such as 'li' or 'co' from termcap.
- *
- * Calling conventions: id = 2 character id.
- *
- * Returned values: -1 for failure, else numerical value.
- */
-
- tgetnum(id)
- char *id;
- {
- char *ptr, buf[256];
- ptr = buf;
-
- if(tgetstr(id, &ptr))
- return atoi(buf);
- else
- return 0;
- }
- /*
- * Module: tgetstr
- *
- * Purpose: get terminal capability string from database.
- *
- * Calling conventions: id is the two character capability id.
- * (*buf) points into a hold buffer for the
- * id. the capability is copied into the buffer
- * and (*buf) is advanced to point to the next
- * free byte in the buffer.
- *
- * Returned values: 0 = no such entry, otherwise returns original
- * (*buf) (now a pointer to the string).
- *
- * Notes
- * It also decodes certain escape sequences in the buffer.
- * they should be obvious from the code:
- * \E = escape.
- * \n, \r, \t, \f, \b match the 'c' escapes.
- * ^x matches control-x (^@...^_).
- * \nnn matches nnn octal.
- * \x, where x is anything else, matches x. I differ
- * from the standard library here, in that I allow ^: to match
- * :.
- *
- */
-
- char *
- tgetstr(id, buf)
- char *id, **buf;
- {
- int len = strlen(id);
- char *tmp=tent;
- char *hold;
-
- do {
- tmp = _find(tmp, ":"); /* For each field */
- while(*tmp==':') /* skip empty fields */
- tmp++;
- if(!*tmp)
- break;
-
- if(_match(id, tmp)==len) {
- tmp += len; /* find '=' '@' or '#' */
- if(*tmp=='@') /* :xx@: entry for tc */
- return 0; /* deleted entry */
- hold= *buf;
- while(*++tmp && *tmp != ':') {/* not at end of field */
- switch(*tmp) {
- case '\\': /* Expand escapes here */
- switch(*++tmp) {
- case 0: /* ignore backslashes */
- tmp--; /* at end of entry */
- break; /* shouldn't happen */
- case 'e':
- case 'E': /* ESC */
- *(*buf)++ = '\033';
- break;
- case 'n': /* \n */
- *(*buf)++ = '\n';
- break;
- case 'r': /* \r */
- *(*buf)++ = '\r';
- break;
- case 't': /* \t */
- *(*buf)++ = '\t';
- break;
- case 'b': /* \b */
- *(*buf)++ = '\b';
- break;
- case 'f': /* \f */
- *(*buf)++ = '\f';
- break;
- case '0': /* \nnn */
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- **buf = 0;
- while(isdigit(*tmp))
- **buf = **buf * 8 + *tmp++ - '0';
- (*buf)++;
- tmp--;
- break;
- default: /* \x, for all other x */
- *(*buf)++= *tmp;
- }
- break;
- case '^': /* control characters */
- *(*buf)++ = *++tmp - '@';
- break;
- default:
- *(*buf)++ = *tmp;
- }
- }
- *(*buf)++ = 0;
- return hold;
- }
- } while(*tmp);
-
- return 0;
- }
-
- /*
- * Module: tgoto
- *
- * Purpose: decode cm cursor motion string.
- *
- * Calling conventions: cm is cursor motion string.
- * line, col, are the desired destination.
- *
- * Returned values: a string pointing to the decoded string, or
- * "OOPS" if it cannot be decoded.
- *
- * Notes
- * The accepted escapes are:
- * %d as in printf, 0 origin.
- * %2, %3 like %02d, %03d in printf.
- * %. like %c
- * %+x adds <x> to value, then %.
- * %>xy if value>x, adds y. No output.
- * %i increments line& col, no output.
- * %r reverses order of line&col. No output.
- * %% prints as a single %.
- * %n exclusive or row & col with 0140.
- * %B BCD, no output.
- * %D reverse coding (x-2*(x%16)), no output.
- */
-
- char *
- tgoto(cm, col, line)
- char *cm; /* cm string, from termcap */
- int col, /* column, x position */
- line; /* line, y position */
- {
- char gx, gy, /* x, y */
- *ptr, /* pointer in 'cm' */
- reverse = 0, /* reverse flag */
- *bufp, /* pointer in returned string */
- addup = 0, /* add upline */
- addbak = 0, /* add backup */
- c;
- static char buffer[32];
-
- if(!cm)
- return "OOPS"; /* Kludge, but standard */
-
- bufp = buffer;
- ptr = cm;
-
- while(*ptr) {
- if((c = *ptr++) != '%') { /* normal char */
- *bufp++ = c;
- } else { /* % escape */
- switch(c = *ptr++) {
- case 'd': /* decimal */
- bufp = _addfmt(bufp, "%d", line);
- line = col;
- break;
- case '2': /* 2 digit decimal */
- bufp = _addfmt(bufp, "%02d", line);
- line = col;
- break;
- case '3': /* 3 digit decimal */
- bufp = _addfmt(bufp, "%03d", line);
- line = col;
- break;
- case '>': /* %>xy: if >x, add y */
- gx = *ptr++;
- gy = *ptr++;
- if(col>gx) col += gy;
- if(line>gx) line += gy;
- break;
- case '+': /* %+c: add c */
- line += *ptr++;
- case '.': /* print x/y */
- if(line=='\t' || /* these are */
- line == '\n' || /* chars that */
- line=='\004' || /* UNIX hates */
- line=='\0') {
- line++; /* so go to next pos */
- if(reverse==(line==col))
- addup=1; /* and mark UP */
- else
- addbak=1; /* or BC */
- }
- *bufp++=line;
- line = col;
- break;
- case 'r': /* r: reverse */
- gx = line;
- line = col;
- col = gx;
- reverse = 1;
- break;
- case 'i': /* increment (1-origin screen) */
- col++;
- line++;
- break;
- case '%': /* %%=% literally */
- *bufp++='%';
- break;
- case 'n': /* magic DM2500 code */
- line ^= 0140;
- col ^= 0140;
- break;
- case 'B': /* bcd encoding */
- line = line/10<<4+line%10;
- col = col/10<<4+col%10;
- break;
- case 'D': /* magic Delta Data code */
- line = line-2*(line&15);
- col = col-2*(col&15);
- break;
- default: /* Unknown escape */
- return "OOPS";
- }
- }
- }
-
- if(addup) /* add upline */
- if(UP) {
- ptr=UP;
- while(isdigit(*ptr) || *ptr=='.')
- ptr++;
- if(*ptr=='*')
- ptr++;
- while(*ptr)
- *bufp++ = *ptr++;
- }
-
- if(addbak) /* add backspace */
- if(BC) {
- ptr=BC;
- while(isdigit(*ptr) || *ptr=='.')
- ptr++;
- if(*ptr=='*')
- ptr++;
- while(*ptr)
- *bufp++ = *ptr++;
- }
- else
- *bufp++='\b';
-
- *bufp = 0;
-
- return(buffer);
- }
-
- /*
- * Module: tinit
- *
- * Purpose: simplified terminal initialisation.
- *
- * Calling conventions: name is name of terminal.
- *
- * Returned values: none.
- *
- * Notes
- * tinit calls tgetent, then sets up the global
- * variables PC, UP, BC, ospeed appropriately.
- *
- */
-
- #if 0 /* already included in term.c */
-
- char tbuf[1024]; /* Buffer for termcap entry */
- char junkbuf[1024]; /* Big buffer for junk */
- char *junkptr;
-
- tinit(name)
- char *name;
- {
- #ifndef AMIGA
- struct sgttyb sgbuf;
- #endif
- char *ps;
-
- junkptr = junkbuf;
-
- tgetent(tbuf, name);
-
- ps = tgetstr("pc", &junkptr);
- if(ps) PC = *ps;
- UP = tgetstr("up", &junkptr);
- BC = tgetstr("bc", &junkptr);
-
- #ifdef AMIGA
- ospeed=0;
- #else
- gtty(1, &sgbuf);
- ospeed=sgbuf.sg_ospeed;
- #endif
- return 0;
- }
- #endif
-
- /*
- * Module: tputs
- *
- * Purpose: decode padding information
- *
- * Calling conventions: cp = string to be padded, affcnt = # of items
- * affected (lines, characters, whatever),
- * outc = routine to output 1 character.
- *
- * Returned values: none
- *
- * Notes
- * cp has padding information ahead of it, in the form
- * nnnTEXT or nnn*TEXT. nnn is the number of milliseconds to delay,
- * and may be a decimal (nnn.mmm). If the asterisk is given, then
- * the delay is multiplied by afcnt. The delay is produced by outputting
- * a number of nulls (or other padding char) after printing the
- * TEXT.
- *
- */
-
- long _bauds[16]={
- 0, 50, 75, 110,
- 134, 150, 200, 300,
- 600, 1200, 1800, 2400,
- 4800, 9600, 19200, 19200 };
-
- tputs(cp, affcnt, outc)
- char *cp; /* string to print */
- int affcnt; /* Number of lines affected */
- void (*outc) __ARGS((unsigned int)); /* routine to output 1 character */
- {
- long frac, /* 10^(#digits after decimal point) */
- counter, /* digits */
- atol();
-
- if(isdigit(*cp)) {
- counter = 0;
- frac = 1000;
- while(isdigit(*cp))
- counter = counter * 10L + (long)(*cp++ - '0');
- if(*cp=='.')
- while(isdigit(*++cp)) {
- counter = counter * 10L + (long)(*cp++ - '0');
- frac = frac * 10;
- }
- if(*cp!='*') { /* multiply by affected lines */
- if(affcnt>1) affcnt = 1;
- }
- else
- cp++;
-
- /* Calculate number of characters for padding counter/frac ms delay */
- if(ospeed)
- counter = (counter * _bauds[ospeed] * (long)affcnt) / frac;
-
- while(*cp) /* output string */
- (*outc)(*cp++);
- if(ospeed)
- while(counter--) /* followed by pad characters */
- (*outc)(PC);
- }
- else
- while(*cp)
- (*outc)(*cp++);
- return 0;
- }
-
- /*
- * Module: tutil.c
- *
- * Purpose: Utility routines for TERMLIB functions.
- *
- */
-
- static int
- _match(s1, s2) /* returns length of text common to s1 and s2 */
- char *s1, *s2;
- {
- int i = 0;
-
- while(s1[i] && s1[i] == s2[i])
- i++;
-
- return i;
- }
-
- static char *
- _find(s, set) /* finds next c in s that's a member of set, returns pointer */
- char *s, *set;
- {
- for(; *s; s++) {
- char *ptr = set;
-
- while(*ptr && *s != *ptr)
- ptr++;
-
- if(*ptr)
- return s;
- }
-
- return s;
- }
-
- static char *
- _addfmt(buf, fmt, val) /* add val to buf according to format fmt */
- char *buf, *fmt;
- int val;
- {
- sprintf(buf, fmt, val);
- while(*buf)
- buf++;
- return buf;
- }
-