628 lines · 13.7 KB · C
RawDownload
/* vi:set ts=8 sts=4 sw=4: *//* * 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 for use with VIM - Vi Improved. *//* A few bugs removed by Olaf 'Rhialto' Seibert. */ /* TERMLIB: Terminal independent database. */ #include "vim.h"#include "termlib.pro" #if !defined(AMIGA) && !defined(VMS) && !defined(MACOS) && !defined(RISCOS)# include <sgtty.h>#endif static int  getent __ARGS((char *, char *, FILE *, int));static int  nextent __ARGS((char *, FILE *, int));static int  _match __ARGS((char *, char *));static char *_addfmt __ARGS((char *, char *, int));static char *_find __ARGS((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[TBUFSZ+], 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. */ #ifndef TERMCAPFILE# ifdef AMIGA#  define TERMCAPFILE "s:termcap"# else#  ifdef VMS#   define TERMCAPFILE "VIMRUNTIME:termcap"#  else#   define TERMCAPFILE "/etc/termcap"#  endif# endif#endif     inttgetent(tbuf, term)    char    *tbuf;		/* Buffer to hold termcap entry, TBUFSZ bytes max */    char    *term;		/* Name of terminal */{    char    tcbuf[32];		/* Temp buffer to handle */    char    *tcptr = tcbuf;	/* extended entries */    char    *tcap = TERMCAPFILE; /* Default termcap file */    char    *tmp;    FILE    *termcap;    int	    retval = 0;    int	    len;     if ((tmp = (char *)mch_getenv((char_u *)"TERMCAP")) != NULL)    {	if (*tmp == '/')		/* TERMCAP = name of termcap file */	{	    tcap = tmp ;#if defined(AMIGA)	    /* Convert /usr/share/lib/termcap to usr:share/lib/termcap */	    tcap++;	    tmp = strchr(tcap, '/');	    if (tmp)		*tmp = ':';#endif	}	else				/* TERMCAP = termcap entry itself */	{	    int tlen = strlen(term); 	    while (*tmp && *tmp != ':')		/* Check if TERM matches */	    {		char *nexttmp; 		while (*tmp == '|')		    tmp++;		nexttmp  = _find(tmp, ":|");	/* Rhialto */		if (tmp+tlen == nexttmp && _match(tmp, term) == tlen)		{		    strcpy(tbuf, tmp);		    tent = tbuf;		    return 1;		}		else		    tmp = nexttmp;	    }	}    }    if (!(termcap = mch_fopen(tcap, "r")))    {	strcpy(tbuf, tcap);	return -1;    }     len = 0;    while (getent(tbuf + len, term, termcap, TBUFSZ - len))    {	tcptr = tcbuf;				/* Rhialto */	if ((term = tgetstr("tc", &tcptr)))	/* extended entry */	{	    rewind(termcap);	    len = strlen(tbuf);	}	else	{	    retval = 1;	    tent = tbuf;	/* reset it back to the beginning */	    break;	}    }    fclose(termcap);    return retval;}     static intgetent(tbuf, term, termcap, buflen)    char    *tbuf, *term;    FILE    *termcap;    int	    buflen;{    char    *tptr;    int	    tlen = strlen(term);     while (nextent(tbuf, termcap, buflen))	/* For each possible entry */    {	tptr = tbuf;	while (*tptr && *tptr != ':')		/* : terminates name field */	{	    char    *nexttptr; 	    while (*tptr == '|')		/* | separates names */		tptr++;	    nexttptr = _find(tptr, ":|");	/* Rhialto */	    if (tptr + tlen == nexttptr &&		_match(tptr, term) == tlen)	/* FOUND! */	    {		tent = tbuf;		return 1;	    }	    else				/* Look for next name */		tptr = nexttptr;	}    }    return 0;}     static intnextent(tbuf, termcap, buflen)		/* Read 1 entry from TERMCAP file */    char    *tbuf;    FILE    *termcap;    int	    buflen;{    char *lbuf = tbuf;				/* lbuf=line buffer */				/* read lines straight into buffer */     while (lbuf < tbuf+buflen &&		/* There's room and */	  fgets(lbuf, (int)(tbuf+buflen-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. */     inttgetflag(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. */     inttgetnum(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;    int		i;     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)++ = ESC;			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;			    /* get up to three digits */			for (i = 0; i < 3 && VIM_ISDIGIT(*tmp); ++i)			    **buf = **buf * 8 + *tmp++ - '0';			(*buf)++;			tmp--;			break;		    default:			/* \x, for all other x */			*(*buf)++= *tmp;		    }		    break;		case '^':			/* control characters */		    ++tmp;		    *(*buf)++ = Ctrl_chr(*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 (VIM_ISDIGIT(*ptr) || *ptr == '.')		ptr++;	    if (*ptr == '*')		ptr++;	    while (*ptr)		*bufp++ = *ptr++;	}     if (addbak)					/* add backspace */	if (BC) {	    ptr=BC;	    while (VIM_ISDIGIT(*ptr) || *ptr == '.')		ptr++;	    if (*ptr == '*')		ptr++;	    while (*ptr)		*bufp++ = *ptr++;	}

Lines 1–500 of 628.