[comp.os.minix] v1.4 termcap

holm@ubc-bdcvax.UUCP (Terrence W. Holm) (02/02/89)

EFTH MINIX report #64  - February 1989 -  termcap(3)


As previously mentioned in this news group, the V1.4a
termcap(3) is unsatisfactory. Starting with the
V1.3 termcap(3) I have, hopefully, generated a source
containing all the known patches.

		Terrence W. Holm
		  holm@bdc.ubc.ca


----------------------------------------------------------
/*
 *	termcap.c	V1.1	20/7/87		agc	Joypace Ltd
 *
 *	Copyright Joypace Ltd, London, UK, 1987. All rights reserved.
 *	This file may be freely distributed provided that this notice
 *	remains attached.
 *
 *	A public domain implementation of the termcap(3) routines.
 *
 *
 *
 *	 Klamer Schutte	      V1.2    Nov. 1988
 *
 *   - Can match multiple terminal names		 [tgetent]
 *   - Removal of **area assignments			 [tgetstr]
 *
 *	 Terrence W. Holm     V1.3    May, Sep, Oct.  1988
 *
 *   - Correct when TERM != name and TERMCAP is defined	 [tgetent]
 *   - Correct the comparison for the terminal name 	 [tgetent]
 *   - Correct the value of ^x escapes              	 [tgetstr]
 *   - Added %r to reverse row/column			 [tgoto]
 *   - Fixed end of definition test			 [tgetnum/flag/str]
 *
 *	 Terrence W. Holm     V1.4    Jan. 1989
 *
 *   - Incorporated Klamer's V1.2 fixes into V1.3
 *   - Added %d, (old %d is now %2)			 [tgoto]
 *   - Allow '#' comments in definition file		 [tgetent]
 */

#include <ctype.h>
#include <stdio.h>


char	*capab = NULL;		/* the capability itself */

/*  The following are not yet used.  */
extern short	ospeed;		/* output speed */
extern char	PC;		/* padding character */
extern char	*BC;		/* back cursor movement */
extern char	*UP;		/* up cursor movement */


extern char	*getenv();
extern FILE	*fopen();



/*
 *	tgetent - get the termcap entry for terminal name, and put it
 *	in bp (which must be an array of 1024 chars). Returns 1 if
 *	termcap entry found, 0 if not found, and -1 if file not found.
 */

int
tgetent(bp, name)
char	*bp;
char	*name;
{
	FILE	*fp;
	char	*file;
	char 	*term;
	short	len = strlen(name);

	capab = bp;

	/*  If TERMCAP begins with a '/' then use TERMCAP as the path	*/
	/*  name of the termcap definitions file. If TERMCAP is a	*/
	/*  definition and TERM equals "name" then use TERMCAP as the	*/
	/*  definition. Otherwise use "/etc/termcap" as the path name.	*/

	if ( (file = getenv("TERMCAP")) == NULL )
	    file = "/etc/termcap";
	else if ( *file != '/' )
	    if ( (term = getenv("TERM")) != NULL && strcmp(term, name) == 0 ) {
		*bp = '\0';
		strncat( bp, file, 1023 );
		return(1);
	    } else
		file = "/etc/termcap";

	if ((fp = fopen(file, "r")) == (FILE *) NULL) {
		capab = NULL;		/* no valid termcap  */
		return(-1);
	}

 	for (;;) {
		/*  Read in each definition */
		int def_len = 0;
		char *cp = bp;

		do {
			if ( fgets(&bp[def_len], 1024-def_len, fp) == NULL ) {
				fclose(fp);
				capab = NULL;	/* no valid termcap */
				return(0);
			}

			def_len = strlen(bp) - 2;
		} while( bp[def_len] == '\\' );

		while ( isspace(*cp) )
			cp++;

		/*  Comment lines start with a '#'  */
		if ( *cp == '#' )
			continue;

		/*  See if any of the terminal names in this definition */
		/*  match "name".					*/

		do {
			if ( strncmp(name, cp, len) == 0  &&
			    ( cp[len] == '|'  ||  cp[len] == ':' ) ) {
 				fclose(fp);
				return(1);
			}

			while( (*cp) && (*cp != '|') && (*cp != ':'))
				cp++;
		} while( *cp++ == '|');
	}
}



/*
 *	tgetnum - get the numeric terminal capability corresponding
 *	to id. Returns the value, -1 if invalid.
 */

int
tgetnum(id)
char	*id;
{
	register  char *cp = capab;

	if (cp == NULL || id == NULL)
		return(-1);

	for(;;) {
		while (*cp++ != ':')
			if (cp[-1] == '\0')
				return(-1);

		while (isspace(*cp))
			cp++;

		if (strncmp(cp, id, 2) == 0  &&  cp[2] == '#' )
			return( atoi(cp+3) );
	}
}



/*
 *	tgetflag - get the boolean flag corresponding to id. Returns -1
 *	if invalid, 0 if the flag is not in termcap entry, or 1 if it is
 *	present.
 */

int
tgetflag(id)
char	*id;
{
	register  char *cp = capab;

	if (cp == NULL || id == NULL)
		return(-1);

	for (;;) {
		while (*cp++ != ':')
			if (cp[-1] == '\0')
				return(0);

		while (isspace(*cp))
			cp++;

		if (strncmp(cp, id, 2) == 0)
			return(1);
	}
}



/*
 *	tgetstr - get the string capability corresponding to id and place
 *	it in area (advancing area at same time). Expand escape sequences
 *	etc. Returns the string, or NULL if it can't do it.
 */

char *
tgetstr(id, area)
char	*id;
char	**area;
{
	register  char *cp  = capab;
	register  char *wsp = *area;	/*  workspace pointer  */

	if (cp == NULL || id == NULL)
		return(NULL);

	for (;;) {
		while (*cp++ != ':')
			if (cp[-1] == '\0')
				return(NULL);

		while (isspace(*cp))
			cp++;

		if (strncmp(cp, id, 2) == 0  &&  cp[2] == '=' ) {
			for (cp+=3;  *cp && *cp != ':'  ; wsp++, cp++)
				switch(*cp) {
				case '^' :
					*wsp = *++cp - '@';
					break;

				case '\\' :
					switch(*++cp) {
					case 'E' :
						*wsp = '\033';
						break;
					case 'n' :
						*wsp = '\n';
						break;
					case 'r' :
						*wsp = '\r';
						break;
					case 't' :
						*wsp = '\t';
						break;
					case 'b' :
						*wsp = '\b';
						break;
					case 'f' :
						*wsp = '\f';
						break;
					case '0' :
					case '1' :
					case '2' :
					case '3' :
						{
						int i;
						int t = 0;
						for (i=0; i<3  &&
						    isdigit(*cp) ; ++i, ++cp)
						       t = t * 8 + *cp - '0';
						*wsp = t;
						cp--;
						break;
						}
					default:
						*wsp = *cp;
					}
					break;

				default :
					*wsp = *cp;
				}

			*wsp++ = '\0';

			{
			char *ret = *area;
			*area = wsp;
			return(ret);
			}
		}
	} /* end for(;;) */
}



/*
 *	tgoto - given the cursor motion string cm, make up the string
 *	for the cursor to go to (destcol, destline), and return the string.
 *	Returns "OOPS" if something's gone wrong, or the string otherwise.
 */

char *
tgoto(cm, destcol, destline)
char	*cm;
int	destcol;
int	destline;
{
	static  char  ret[24];
	char   *rp    = ret;
	int	incr  = 0;
	int 	argno = 0;
	int	numval;

	for ( ; *cm ; cm++) {
		if ( *cm == '%' ) {
			switch(*++cm) {
			case 'i' :
				incr = 1;
				break;

			case 'r' :
				argno = 1;
				break;

			case '+' :
				numval = (argno == 0 ? destline : destcol);
				*rp++ = numval + incr + *++cm;
				argno = 1 - argno;
				break;

			case '2' :
				numval = (argno == 0 ? destline : destcol);
				numval = (numval + incr) % 100;
				*rp++ = '0' + (numval/10);
				*rp++ = '0' + (numval%10);
				argno = 1 - argno;
				break;

			case 'd' :
				numval = (argno == 0 ? destline : destcol);
				numval = (numval + incr) % 1000;
				if ( numval > 99 )
				    *rp++ = '0' + (numval/100);
				if ( numval > 9 )
				    *rp++ = '0' + (numval/10) % 10;
				*rp++ = '0' + (numval%10);
				argno = 1 - argno;
				break;

			case '%' :
				*rp++ = '%';
				break;

			default :
				return( "OOPS" );
			}

		} else
			*rp++ = *cm;
	}

	*rp = '\0';
	return(ret);
}



/*
 *	tputs - put the string cp out onto the terminal, using the function
 *	outc. This should do padding for the terminal, but I can't find a
 *	terminal that needs padding at the moment...
 */

int
tputs(cp, affcnt, outc)
register char	*cp;
int		affcnt;
int		(*outc)();
{
	if (cp == NULL)
		return(1);
	/* do any padding interpretation - left null for MINIX just now */
	while (*cp)
		(*outc)(*cp++);
	return(1);
}
----------------------------------------------------------