v02i077: termcap implementation: works under MS-DOS, 4.xBSD

Norman H. Azadian azadian at hslrswi.UUCP
Wed Mar 16 22:13:56 AEST 1988


Submitted-By: "Norman H. Azadian" <azadian at hslrswi.UUCP>

Archive-Name: termcap


comp.sources.misc: Volume 2, Issue 77
Submitted-By: "Norman H. Azadian" <azadian at hslrswi.UUCP>
Archive-Name: termcap

[Also looks like it works under System V, although why you'd want to I don't
know....  Needs either Henry Spenser's strings package or a set of System III
or System V libraries.  ++bsa]

This is an implementation of termcap(3X) for PC's using MS-DOS.  Not having
access to the unix sources, I hauled off and wrote my own.  While I was at
it I developed complete /etc/termcap profiles for the PC.  The color monitor
profile is completely untested, and the monochrome one is only partially
tested.  I am using this termcap package with less, which I have ported
to the PC and hacked up.  Since I hope someday to distribute my "improved"
less, this termcap package is a necessary pre-requisite.


#--------------------------------CUT HERE-------------------------------------
#! /bin/sh
#
# This is a shell archive.  Save this into a file, edit it
# and delete all lines above this comment.  Then give this
# file to sh by executing the command "sh file".  The files
# will be extracted into the current directory owned by
# you with default permissions.
#
# The files contained herein are:
#
# -rw-r--r--  1 azadian      1079 Mar 16 12:59 README
# -rw-r--r--  1 azadian      3370 Mar 16 11:52 termcap.pc
# -rw-r--r--  1 azadian     20209 Mar 16 12:13 termcap.c
#
echo 'x - README'
if test -f README; then echo 'shar: not overwriting README'; else
sed 's/^X//' << '________This_Is_The_END________' > README
XI wrote termcap(3X) for use on my PC clone under MS-DOS.  Additionally, I
Xhave developed complete termcap profiles for the PC, starting with the
Xtermcap provided by Darren Friedlein.
X
XTermcap.c was written with the Aztec C compiler (4.1), but it also works
Xwith the 4.3bsd C compiler.  A simple test program is provided at the end
Xof termcap.c.  Pay no attention to the printd() calls, they're part of my
Xdebugging package, and they are effectively neutered by defining DEBUG as 0.
X
XI made good use of some of the functions from Henry Spencer's excellent
Xstandard string library.  If you don't have it, get it!
X
XIn the not-too-distant future I hope to be unleashing my hacked version
Xof Mark Nudelman's less program.  It requires a termcap(3X) such as this.
X
XI welcome your problems, suggestions, and bug fixes.
X
XNorman Azadian, 80A;  Hasler AG;  Belpstrasse 23;  3000 Berne 14;  Switzerland
XX.400:    azadian at hslrswi.hasler                   Telephone:   +41 31 63 2178
XUucp:     ... {uunet,ukc,mcvax, ... }!cernvax!hslrswi!azadian
XBitnet:   azadian%hslrswi.UUCP at cernvax.BITNET
________This_Is_The_END________
if test `wc -c < README` -ne 1079; then
	echo 'shar: README was damaged during transit (should have been 1079 bytes)'
fi
fi		; : end of overwriting check
echo 'x - termcap.pc'
if test -f termcap.pc; then echo 'shar: not overwriting termcap.pc'; else
sed 's/^X//' << '________This_Is_The_END________' > termcap.pc
X#
X#	/etc/termcap for IBM PC's and friends.
X#	Gratiously supplied by Darren Friedlein.
X#	Completed by Norman H. Azadian.
X#
X
X#
X# Monochrome IBMPC.
X#	This is a termcap for the NANSI.SYS device driver.
X#	It is the same as the ANSI termcap, except NANSI supports additionally
X#	line & char insert & delete (AL,al, DL,dl, DC,dc, IC,ic).
X#
Xnansi-mono|mono:\
X	:AL=\E[%dL:al=\E[1L:\
X	:DC=\E[%dP:dc=\E[1P:DL=\E[%dM:dl=\E[1M:\
X	:IC=\E[%d@:ic=\E[1@:\
X	:tc=ansi-mono:
X
X
X#
X# monochrome ANSI
X#
Xansi-mono:\
X	:am:\
X	:bc=\E[1D:bl=^G:bs:\
X	:cd=\E[2J:ce=\E[K:cl=\E[2J\E[H:cm=\E[%i%2;%i%2H:co#80:\
X	:ho=\E[H:\
X	:K1=\200G:K2=\200I:K4=\200O:K5=\200Q:\
X	:k0=\200;:k1=\200<:k2=\200=:k3=\200>:k4=\200?:k5=\200@:\
X	:k6=\200A:k7=\200B:k8=\200C:k9=\200D:\
X	:kb=^H:kC=\200w:kD=\200S:kd=\200H:kE=\200u:kH=\200O:kh=\200G:\
X	:kI=\200R:kl=\200K:kN=\200Q:kP=\200I:kr=\200M:kS=\200v:ku=\200P:\
X	:LE=\E[%dD:le=\E[1D:li#25:\
X	:mb=\E[5m:md=\E[1m:me=\E[0m:mk=\E[8m:mr=\E[7m:ms:\
X	:nd=\E[C:\
X	:RI=\E[%dC:rc=\E[u:\
X	:sc=\E[s:se=\E[0m:so=\E[7m:\
X	:te=\E[0m:ti=\E[0m:\
X	:UP=\E[%dA:ue=\E[0m:up=\E[A:us=\E[4m:\
X	:xd=\E[B:xs:
X
X
X#
X# Color IBMPC.
X#	This is a termcap for the NANSI.SYS device driver.
X#	It is the same as the ANSI termcap, except NANSI supports
X#	character & line insert & delete, while ANSI does not.
X#
Xnansi-color|color:\
X	:AL=\E[%dL:al=\E[1L:\
X	:DC=\E[%dP:dc=\E[1P:DL=\E[%dM:dl=\E[1M:\
X	:IC=\E[%d@:ic=\E[1@:\
X	:tc=ansi-color:
X
X#
X# ANSI Color
X#
Xansi-color:\
X	:bc=\E[1D:bl=^G:bs:\
X	:cd=\E[2J:ce=\E[K:cl=\E[2J\E[H:cm=\E[%i%2;%i%2H:co#80:\
X	:ho=\E[H:\
X	:K1=\200G:K2=\200I:K4=\200O:K5=\200Q:\
X	:k0=\200;:k1=\200<:k2=\200=:k3=\200>:k4=\200?:k5=\200@:\
X	:k6=\200A:k7=\200B:k8=\200C:k9=\200D:\
X	:kb=^H:kC=\200w:kD=\200S:kd=\200H:kE=\200u:kH=\200O:kh=\200G:\
X	:kI=\200R:kl=\200K:kN=\200Q:kP=\200I:kr=\200M:kS=\200v:ku=\200P:\
X	:LE=\E[%dD:le=\E[1D:li#25:\
X	:mb=\E[5m:md=\E[1m:me=\E[0m:mk=\E[8m:mr=\E[7m:ms:\
X	:nd=\E[C:\
X	:RI=\E[%dC:rc=\E[u:\
X	:sc=\E[s:se=\E[44;37m:so=\E[31m:\
X	:te=\E[0m:ti=\E[44;37m:\
X	:UP=\E[%dA:ue=\E[0m:up=\E[A:us=\E[4m:\
X	:xd=\E[B:xs:
X
X
X
X#
X# alternative nansi color
X#
Xalt-nansi-color:\
X	:co#80:\
X	:li#25:\
X	:cl=\E[2J:\
X	:bs:\
X	:ho=\E[H:\
X	:cm=\E[%i%2;%2H:\
X	:up=\E[A:\
X	:xd=\E[B:\
X	:nd=\E[C:\
X	:bc=\E[D:\
X	:ce=\E[K:\
X	:ti=\E[44;37m:\
X	:te=\E[0m:\
X	:so=\E[31m:\
X	:se=\E[44;37m:\
X	:us=\E[1m:\
X	:ue=\E[m:\
X	:hi=\E[32m:\
X	:he=\E[44;37m:\
X	:al=\E[L:\
X	:dl=\E[M:
X
X#
X# Monochrome IBMPC, especially lobotomized for /usr/games/larn.
X#	Each capability (that larn requires) must start on a new line.
X#	Must not use 2nd %i in :cm capability, although it should be there.
X#
Xlarn-mono|hack-mono:\
X	:al=\E[L:\
X	:bc=\E[D:\
X	:bs:\
X	:ce=\E[K:\
X	:cl=\E[2J:\
X	:cm=\E[%i%2;%2H:\
X	:co#80:\
X	:dc=\E[P:\
X	:dl=\E[M:\
X	:ho=\E[H:\
X	:ic=\E[@:\
X	:li#25:\
X	:mb=\E[5m:\
X	:md=\E[7m:\
X	:me=\E[0m:\
X	:mk=\E[8m:\
X	:mr=\E[7m:\
X	:nd=\E[C:\
X	:se=\E[0m:\
X	:so=\E[1m:\
X	:te=\E[0m:\
X	:ti=\E[0m:\
X	:ue=\E[0m:\
X	:up=\E[A:\
X	:us=\E[4m:\
X	:xd=\E[B:\
X	:xs:
X	
X#
X# Color IBMPC, especially lobotomized for /usr/games/larn.
X#	Each capability (that larn requires) must start on a new line.
X#	Must not use 2nd %i in :cm capability, although it should be there.
X#
Xlarn-color|hack-color:\
X	:bc=\E[D:\
X	:bs:\
X	:ce=\E[K:\
X	:cl=\E[2J:\
X	:cm=\E[%i%2;%2H:\
X	:co#80:\
X	:he=\E[44;37m:\
X	:hi=\E[32m:\
X	:ho=\E[H:\
X	:li#25:\
X	:nd=\E[C:\
X	:se=\E[44;37m:\
X	:so=\E[31m:\
X	:te=\E[0m:\
X	:ti=\E[44;37m:\
X	:ue=\E[m:\
X	:up=\E[A:\
X	:us=\E[1m:\
X	:xd=\E[B:\
X	:xs:
________This_Is_The_END________
if test `wc -c < termcap.pc` -ne 3370; then
	echo 'shar: termcap.pc was damaged during transit (should have been 3370 bytes)'
fi
fi		; : end of overwriting check
echo 'x - termcap.c'
if test -f termcap.c; then echo 'shar: not overwriting termcap.c'; else
sed 's/^X//' << '________This_Is_The_END________' > termcap.c
X/*	termcap.c	880204	NHA	*/
X/* My implementation of the termcap(3X) library routines.
X * All specs lifted straight from 4.3bsd Programmers Reference Manual.
X * These functions extract and use capabilities from the terminal
X * capability database termcap(5).  These are low level routines;
X * see curses(3X) for a higher level package.
X ** You'll find it looks a lot nicer if you use a tab interval of 4.
X */
X
X#define	DEBUG	0
X
X#if DEBUG
X#define	MAJOR	'L'							/* major module identifier */
X#define	MINOR	'T'							/* minor module identifier */
X#include	<gen.h>							/* my all-purpose include file */
X#else DEBUG
X#include	<stdio.h>
X#include	<fcntl.h>
X#define		export
X#define		import		extern
X#define		local		static
X#define		bool		int
X#define		abs(x)		( (x < 0) ? (-(x)) : (x) )
X#define		YES			1
X#define		NO			0
X#define		error(s)	{perror(s);  exit(99);}
X#define		initdebug(pac, pav, confile, listfile, initstring)
Xstatic		printd(lvl, fmt) {}
X#endif DEBUG
X
X#define	BUFSIZE	1024
X
X/* external variables (supplied by user) required by this package */
Ximport char		PC;							/* pad char, default ^@ */
Ximport char		BC;							/* backspace char if not ^H */
Ximport char		UP;							/* char for Upline (cursor up) */
Ximport char		ospeed;						/* output speed, see stty(3) */
X
X#ifdef __STDC__
Ximport char		*getenv(char *id);
Ximport int		open(char *name, unsigned mode);
Ximport unsigned	strlen(char *str);
Ximport unsigned	strspn(char *str1, char *str2);
Ximport int		strcmp(char *str1, char *str2);
Ximport int		strncmp(char *str1, char *str2, unsigned n);
Ximport char		*strncpy(char *buf, char *str, unsigned n);
Ximport char		*strchr(char *string, char ch);
Ximport char		*strpbrk(char *string, char *delimiters);
X#else __STDC__
Ximport char		*getenv();
Ximport int		open();
Ximport unsigned	strlen();
Ximport unsigned	strspn();
Ximport int		strcmp();
Ximport int		strncmp();
Ximport char		*strncpy();
Ximport char		*strchr();
Ximport char		*strpbrk();
X#endif __STDC__
X
X/* milliseconds per character, for each of the possible baud rates of ospeed */
X/* here multiplied by 10 for computational convenience */
Xlocal unsigned	delayFactor[] = {
X								   0,		/* B0 */	/* hang up dataphone */
X								1920,		/* B50 */
X								1280,		/* B75 */
X								 872,		/* B110 */
X								 730,		/* B134 */
X								 640,		/* B150 */
X								 480,		/* B200 */
X								 320,		/* B300 */
X								 160,		/* B600 */
X								  80,		/* B1200 */
X								  50,		/* B1800 */
X								  40,		/* B2400 */
X								  20,		/* B4800 */
X								  10,		/* B9600 */
X								   5,		/* EXTA (19200 here) */
X								   2,		/* EXTB (34800 here) */
X								};
X/* remember where user's terminal entry buffer is */
Xlocal char		*ebuf = NULL;				/* pointer to entry buffer */
X
X
X
X/*+		f i n d C a p
X * Returns pointing to the character immediately following the capability id.
X * Returns NULL if tgetent() has not yet been called successfully.
X * Returns NULL if capability not found.
X */
Xlocal char *findCap(id)
Xchar	*id;								/* name of the capability to find */
X	{
X	char	*p;								/* pointer into the entry buffer */
X
X	printd(5, "findCap(\"%s\"), ebuf=%p\n", id, ebuf);
X	if (ebuf == NULL)
X		return NULL;
X	for (p = ebuf   ;   *p   ;   ++p)
X		{
X		printd(9, " %02x", *p);
X		if ( (p[0] == ':')  &&  (p[1] == id[0])  &&  (p[2] == id[1]) )
X			{
X			printd(7, "findCap(): SUCCESS, p=%.15s...\n", p);
X			p = &p[3];
X			break;
X			}
X		}
X	if ( ! *p)
X		p = NULL;
X	printd(5, "findCap(): returning %p (%.11s...)\n", p, p);
X	return p;
X	}
X
X
X
X/*+		g e t E n t r y
X * Gets the named entry from the already-opened termcap file into the buffer.
X * The size of the buffer is BUFSIZE, and it is considered to be an
X * error if the size of the entry equals or exceeds this.
X * We place a terminating NULL character at the end of the entry.
X * Call error() on any irregularities.
X * Return 0 if the named entry not found, else 1.
X * Removes terminal names and all newlines from the entry.
X **If this is called for a 2nd time from tgetent(), then the length checking
X **is useless.
X */
Xlocal int getEntry(fd, outbuf, name)
Xint		fd;									/* FileDescriptor for termcap file*/
Xchar	*outbuf;							/* where we put the entry */
Xchar	*name;								/* terminal type name we seek */
X	{
X	unsigned	namlen;						/* # chars in name */
X	int			cnt;						/* # unprocessed chars in inbuf[] */
X	char		*ip;						/* pointer into input buffer */
X	char		*op;						/* pointer into output buffer */
X	char		*ptmp;						/* temporary pointer */
X	int			stat;						/* status of read(), etc */
X	char		inbuf[BUFSIZE];				/* termcap file is read into here */
X
X	printd(5, "getEntry(%d, %p, \"%s\")\n", fd, inbuf, name);
X	op = outbuf;
X	namlen = strlen(name);
X	cnt = read(fd, inbuf, BUFSIZE-1);
X	if (cnt == -1)
X		error("getEntry(): file is empty\n");
X	inbuf[cnt] = '\0';						/* maintain inbuf[] as a string */
X	for (ip = inbuf   ;   0 < cnt   ;   ++ip, --cnt)
X		{
X		printd(7, "cnt=%d, ip='%.55s...'\n", cnt, ip);
X		stat = strspn(ip, "\r\n \t\b\f");
X		if (0 < stat)
X			{
X			printd(8, "skipping %d whitespace characters\n", stat);
X			ip = &ip[--stat];
X			cnt -= stat;
X			}
X		else if (*ip == '#')
X			{
X			printd(6, "comment line '%.11s...'\n", ip);
X			ptmp = ip;
X			ip = strchr(ip, (char)'\n');
X			cnt  -=  (ip == NULL) ? cnt : (int)(ip - ptmp);
X			}
X		else if (strncmp(name, ip, namlen) == 0)
X			{
X			printd(6, "getEntry(): SUCCESS, ip = '%.22s...', cnt=%u\n", ip,cnt);
X			ip = strchr(ip, (char)':');		/* skip over namelist */
X			printd(7, "getEntry(): raw entry is: '%s'\n", ip);
X			/* copy entry into output buffer */
X			/* eliminate non-space whitespace and continuation \ */
X			for (op = outbuf   ;   ip != NULL  &&  *ip != '\0'   ;   ++ip)
X				{
X				printd(9, " %02x", *ip);
X				if (ip[0] == '\\'   &&   ip[1] == '\r'   &&   ip[2] == '\n')
X					ip = &ip[2];
X				else if (ip[0] == '\\'   &&   ip[1] == '\n')
X					++ip;
X				else if (strchr("\t\r\b\f", *ip) != NULL)
X					continue;
X				else if (*ip == '\n')
X					break;
X				else
X					*op++  =  *ip;
X				}
X			if (*ip != '\n')
X				error("getEntry(): entry too long\n");
X			*op = '\0';
X			printd(6, "getEntry(): outbuf='%s'\n", outbuf);
X			printd(5, "getEntry(): returning 1  [SUCCESS]\n");
X			return 1;
X			}
X		else
X			{								/* advance to next name in list */
X			ptmp = ip;
X			ip = strpbrk(ip, "|:");			/* find name delimiter */
X			if (ip == NULL)
X				error("getEntry(): bad format\n");
X			cnt -= ip - ptmp;
X			if (*ip != '|')
X				{							/* at end of namelist for entry */
X				/* dispose of entire entry */
X				printd(8, "end of namelist, cnt=%d\n", cnt);
X				for (++ip, --cnt   ;   0 < cnt   ;   ++ip, --cnt)
X					if ( ip[0] == '\n'   && 
X						  ( (ip[-1] == '\r'  &&   ip[-2] != '\\')
X						  					||
X						    (ip[-1] != '\r'  &&   ip[-1] != '\\') )
X					   )
X						{				/* skip to next entry in file */
X						/* delete this entry from inbuf */
X						for (ptmp = inbuf   ;   *ip != '\0'   ;   ++ptmp, ++ip)
X							*ptmp = *ip;
X						*ptmp = *ip;		/* string stopper character */
X						ip = inbuf;
X						if (strlen(ip) != cnt)
X							error("getEntry(): bad strlen(ip)\n");
X						/* fill inbuf with more characters */
X						stat = read(fd, ptmp, BUFSIZE - cnt - 1);
X						if (0 < stat)
X							{
X							cnt += stat;
X							inbuf[cnt] = '\0';
X							}
X						break;
X						}
X				if (cnt <= 0)
X					error("getEntry(): entry too long!\n");
X				}
X			}
X		}
X	outbuf[0] = '\0';						/* not found */
X	printd(6, "getEntry(): outbuf='%s'\n", outbuf);
X	printd(5, "getEntry(): returning 0  [FAILURE]\n");
X	return 0;
X	}
X
X
X	
X/*+		t g e t e n t
X * Extracts the entry for terminal name into the buffer at bp.
X * Bp should be a character array of size 1024 and must be retained through
X * all subsequent calls to tgetnum(), tgetflag(), and tgetstr().
X * Returns -1 if it cannot open the termcap file, 0 if the terminal name
X * given does not have an entry, and 1 if all goes well.
X * Looks in the environment for a TERMCAP variable.  If found, and the value
X * does not begin with a slash, and the terminal type name is the same as
X * the environment string TERM, the TERMCAP string is used instead of reading
X * the termcap file.  If it does begin with a slash, the string is used
X * as a pathname rather than /etc/termcap.  This can speed up entry into
X * programs that call tgetent(), as well as to help debug new terminal
X * descriptions  or to make one for your terminal if you can't write the
X * file /etc/termcap.
X */
Xexport int tgetent(bp, name)
Xchar	*bp;								/* pointer to user's buffer */
Xchar	*name;								/* terminal type name */
X	{
X	char	*termcap;						/* pointer to $TERMCAP string */
X	int		fd;								/* File Descriptor, termcap file */
X	int		retval;							/* return value */
X	
X	printd(3, "tgetent(%p, \"%s\")\n", bp, name);
X	termcap = getenv("TERMCAP");
X	if (termcap != NULL   &&   termcap[0] != '/'   &&
X	    strcmp(name, getenv("TERM")) == 0)
X		{									/* use $TERMCAP as the entry */
X		printd(6, "tgetent(): using contents of $EXINIT\n");
X		strncpy(bp, termcap, (BUFSIZE-1));
X		bp[BUFSIZE] = '\0';
X		termcap = "/etc/termcap";			/* in case :tc capability found */
X		retval = 1;
X		}
X	else
X		{									/* look for entry in termcap file */
X		if (termcap[0] != '/')
X			termcap = "/etc/termcap";		/* use default termcap file */
X		printd(6, "tgetent(): opening file %s\n", termcap);
X		fd = open(termcap, O_RDONLY);
X		if (fd == -1)
X			retval = -1;
X		else
X			{
X			retval = getEntry(fd, bp, name);
X			close(fd);
X			}
X		}
X	if (retval == 1)
X		ebuf = bp;							/* for our use in future pkg calls*/
X	
X	/* deal with the :tc= capability */
X	bp = findCap("tc");
X	if (bp != NULL)
X		{
X		char	newname[88];
X		
X		printd(6, "tgetent(): :tc found at %p, is '%s'\n", &bp[-3], &bp[-3]);
X		strncpy(newname, &bp[1], sizeof newname);
X		if (strchr(newname, (char)':') != NULL)
X			*(strchr(newname, (char)':'))  =  '\0';
X		fd = open(termcap, O_RDONLY);
X		if (fd == -1)
X			{
X			printd(2, "tgetent(%s): can't open :tc file '%s'\n", name, newname);
X			retval = -1;
X			}
X		else
X			{
X			retval = getEntry(fd, &bp[-2], newname);
X			close(fd);
X			}
X		}
X		
X	printd(3, "tgetent(): returning %d\n", retval);
X	return retval;
X	}
X
X
X	
X/*+		t g e t n u m
X * Gets the numeric value of capability id, returning -1 if it is not given
X * for the terminal.
X */
Xexport int tgetnum(id)
Xchar	*id;								/* capability name */
X	{
X	int		retval;
X	char	*p;
X
X	printd(3, "tgetnum(\"%s\")\n", id);
X	p = findCap(id);
X	if (p == NULL   ||   *p != '#')
X		retval = -1;						/* not found, or not numeric */
X	else
X		{
X		retval = 0;
X		for (++p   ;   *p != ':'   ;   ++p)
X			retval  =  (retval * 10) + (*p - '0');
X		}
X	printd(3, "tgetnum(): returning %d\n", retval);
X	return retval;
X	}
X
X
X
X/*+		t g e t f l a g
X * Returns 1 if the specified capability is present in the terminal's entry,
X * 0 if it is not.
X **This implementation requires that the capability be a boolean one.
X */
Xexport int tgetflag(id)
Xchar	*id;								/* capability name */
X	{
X	int		retval;
X	char	*p;
X
X	printd(3, "tgetflag(\"%s\")\n", id);
X	p = findCap(id);
X	retval  =  (p != NULL  &&  *p == ':');
X	printd(3, "tgetflag(): returning %d\n", retval);
X	return retval;
X	}
X
X
X
X/*+		t g e t s t r
X * Returns the string value of the capability id, places it in the buffer
X * at area, and advances the area pointer [past the terminating '\0' char].
X * It decodes the abbreviations for this field described in termcap(5),
X * except for cursor addressing and padding information.
X * Returns NULL if the capability was not found.
X */
Xexport char *tgetstr(id, area)
Xchar	*id;								/* capability name */
Xchar	**area;								/* pointer to output pointer */
X	{
X	char		*retval;					/* return value */
X	char		*p;							/* pointer into capability string */
X	unsigned	sum;						/* for chars given in octal */
X
X	printd(3, "tgetstr(\"%s\", %p): *area=%p\n", id, area, *area);
X	p = findCap(id);
X	if (p == NULL   ||   *p != '=')
X		retval = NULL;
X	else
X		{
X		retval = *area;
X		for (++p   ;   *p != ':'   ;   ++p)
X			{
X			printd(9, "p=%p,  *p=%02x\n", p, *p);
X			if (*p == '\\')
X				switch (*++p)
X					{						/* special */
X				case '0': case '1': case '2': case '3':
X				case '4': case '5': case '6': case '7':
X					sum = (p[0] - '0') << 6  +
X						  (p[1] - '0') << 3  +
X						  (p[2] - '0');
X					++p;
X					++p;
X					*(*area)++  =  (char)(sum & 0377);
X					/** will \200 really end up as \000 like it should ? **/
X					/** see termcap(5), top of page 6 **/
X					break;
X				case '^':	*(*area)++  =  '^';		break;
X				case '\\':	*(*area)++  =  '\\';	break;
X				case 'E':	*(*area)++  =  '\033';	break;		/* escape */
X				case 'b':	*(*area)++  =  '\b';	break;
X				case 'f':	*(*area)++  =  '\f';	break;
X				case 'n':	*(*area)++  =  '\n';	break;
X				case 'r':	*(*area)++  =  '\r';	break;
X				case 't':	*(*area)++  =  '\t';	break;
X				default:	*(*area)++  =  *p;		break;
X					}
X			else if (*p == '^')
X				*(*area)++  =  *++p - '@';	/* control */
X			else
X				*(*area)++  =  *p;			/* normal */
X			}
X		*(*area)++ = '\0';					/* NULL-terminate the string */
X		}
X	printd(3, "tgetstr(): returning ");
X	if (retval == NULL)
X		{									/* these must be here for print() */
X		printd(3, "NULL");
X		}									/* these must be here for print() */
X	else
X		{
X		printd(3, "%p  [", retval);
X		for (p = retval   ;   p != *area   ;   ++p)
X			printd(3, " %02x", (unsigned)*p);
X		printd(3, "]");
X		}
X	printd(3, ",  *area=%p\n",  *area);
X	return retval;
X	}
X
X
X	
X/*+		t g o t o
X * Returns a cursor addressing string decoded from cm to go to column destcol
X * in line destline. It uses the external variables UP (from the up capability)
X * and BC (if bc is given rather than bs) if necessary to avoid placing
X * \n, ^D, or ^@ in the returned string.  (Programs which call tgoto() should
X * be sure to turn off the XTABS bit(s), since tgoto() may not output a tab.
X * Note that programs using termcap should in general turn off XTABS anyway
X * since some terminals use control I for other functions, such as non-
X * destructive space.)  If a % sequence is given which is not understood,
X * then tgoto() returns "OOPS".
X **Output buffer is local, so don't try any recursion.
X **No error checking here.
X */
Xexport char *tgoto(cm, destcol, destline)
Xchar	*cm;								/* cm capability string */
Xint		destcol;							/* destination column (left is 0) */
Xint		destline;							/* destination line (top is 0) */
X	{
X	char		*outp;						/* pointer into answer[] */
X	local char	answer[88];					/* result stashed here */
X	bool		reversed;					/* YES when should send col 1st */
X	int			value;						/* next value to output */
X
X	printd(3, "tgoto(\"%s\", %d, %d)\n", cm, destcol, destline);
X	reversed = NO;
X	value = destline;
X	outp = answer;
X	for (   ;   *cm   ;   ++cm)
X		{
X		printd(9, " %02x", *cm);
X		if (*cm == '%')
X			{
X			switch (*++cm)
X				{
X			case '%':	*outp++ = '%';
X						break;
X			case 'd':	sprintf(outp, "%d", value);
X						if (value < 0)
X							++outp;
X						++outp;
X						if (9 < abs(value))
X							++outp;
X						if (99 < abs(value))
X							++outp;
X						value = (reversed) ? destline : destcol;
X						break;
X			case '2':	sprintf(outp, "%02d", value);
X						outp += 2;
X						value = (reversed) ? destline : destcol;
X						break;
X			case '3':	sprintf(outp, "%03d", value);
X						outp += 3;
X						value = (reversed) ? destline : destcol;
X						break;
X			case '.':	*outp++ = value;
X						value = (reversed) ? destline : destcol;
X						break;
X			case '+':	*outp++ = value + *++cm;
X						value = (reversed) ? destline : destcol;
X						break;
X			case '>':	if (value > *++cm)
X							value += *++cm;
X						else
X							++cm;
X						break;
X			case 'r':	value = (reversed) ? destline : destcol;
X						reversed ^= YES;
X						break;
X			case 'i':	++value;
X						break;
X			case 'n':	destcol  ^= 0140;
X						destline ^= 0140;
X						break;
X			case 'B':	value = (16 * (value / 10))  +  (value % 10);
X						break;
X			case 'D':	value = (value - (2 * (value % 16)));
X						break;
X			default:	sprintf(outp, "OOPS");
X						outp += 4;
X						break;
X				}
X			printd(8, "reversed=%b, value=%d\n", reversed, value);
X			}
X		else
X			*outp++ = *cm;
X		}
X	*outp = '\0';
X	printd(3, "tgoto(): returning '%s'\n", answer);
X	return answer;
X	}
X
X
X
X/*+		t p u t s
X * Decodes the leading pad information of the string cp; affcnt gives the
X * number of lines affected by the operation, or 1 if this is not applicable.
X * Outc is a routine which is called with each character in turn.
X * The external variable ospeed should contain the output speed of
X * the terminal as encoded by stty(3).
X * The external variable PC should contain a pad character to be used
X * (from the pc capability) if a null (^@) is inappropriate.
X */
Xexport void tputs(cp, affcnt, outc)
Xchar	*cp;								/* leading pad information string */
Xint		affcnt;								/* number lines affected, or 1 */
Xint		(*outc)();							/*output function to call per char*/
X	{
X	char		*p;
X	bool		decimalFlag;				/* delay had a decimal point */
X	unsigned	delay;
X	unsigned	cnt;
X	
X	printd(3, "tputs(\"%s\", %d, %p):  ospeed=%u\n", cp, affcnt, outc, ospeed);
X
X	/* calculate delay, if any */
X	/* currently no guard against having more than 1 digit after decimal point*/
X	decimalFlag = NO;
X	delay = 0;
X	for (p = cp   ;   strchr("0123456789.", *p)   ;   ++p)
X		if (*p == '.')
X			decimalFlag = YES;
X		else
X			delay  =  (delay * 10) + (*p - '0');
X	if ( ! decimalFlag)
X		delay *= 10;						/* units are really 10ms */
X	if (*p == '*')
X		delay *= affcnt;
X	printd(6, "tputs(): delay = %u.%u milliseconds\n", delay/10, delay%10);
X	delay += (delayFactor[ospeed] + 1) / 2;	/* round up */
X	delay /= delayFactor[ospeed];
X	printd(5, "tputs(): delay = %u characters,  [delayFactor is %u]\n",
X	  delay, delayFactor[ospeed]);
X
X	for (   ;   *cp != '\0'   ;   ++cp)
X		outc(*cp);							/* output string */
X	for (cnt = delay   ;   cnt   ;   --cnt)
X		outc(PC);							/* output delay characters */
X	printd(3, "tputs(): returning\n");
X	}
X
X
X
X#if		TEST
X
Xexport char		PC;							/* pad char, default ^@ */
Xexport char		BC;							/* backspace char if not ^H */
Xexport char		UP;							/* char for Upline (cursor up) */
Xexport char		ospeed = 13;				/* output speed, see stty(3) */
X
Xlocal char	buf[1024];						/* holds termcap entry */
Xlocal char	strbuf[512];					/* for output of tgetstr() */
Xlocal char	*strptr;						/* ptr to strbuf[] */
X
X
X/*+		o c
X * Tiny test routine to simulate putting out a character.
X */
Xlocal void oc(c)
Xchar	c;
X	{
X	putc(c, stdout);
X	}
X
X
X/*+		m a i n
X * Test program for the termcap routines.
X * Command line parameters:
X *	1st is terminal name, defaulted to "mono".
X *	2nd is name of numeric capability, default "co".
X *	3rd is name of boolean capability, default "bs".
X *	4th is name of string capability, default "so".
X *	5th is test string for tgoto(), default is "6\\E&%r%2c%2Y".
X *	6th is test string for tputs(), default is "3.5*123".
X */
Xexport int main(ac, av)
Xint		ac;
Xchar	**av;
X	{
X	int		stat;							/* integer return value */
X	char	*instr;							/* input string value */
X	char	*outstr;						/* string return value */
X	char	*ttype;							/* terminal type string */
X	char	*capability;					/* capability name string */
X	
X	/* setup */
X	initdebug(&ac, &av, "/dev/con", "debug.out", "LB3LT8");
X	PC = '@';
X	BC = 'H';
X	UP = 'B';
X	
X	/* test tgetent() */
X	ttype = (ac < 2) ? "mono" : av[1];
X	stat = tgetent(buf, ttype);
X	printf("main: tgetent(buf, \"%s\") returned %d\n", ttype, stat);
X	if (stat != 1)
X		exit (99);
X		
X	/* test tgetnum() */
X	capability = (ac < 3) ? "co" : av[2];
X	stat = tgetnum(capability);
X	printf("main: tgetnum(%s) returned %d\n", capability, stat);
X
X	/* test tgetflag() */
X	capability = (ac < 4) ? "bs" : av[3];
X	stat = tgetflag(capability);
X	printf("main: tgetflag(%s) returned %d\n", capability, stat);
X
X	/* test tgetstr() */
X	capability = (ac < 5) ? "so" : av[4];
X	strptr = strbuf;
X	outstr = tgetstr(capability, &strptr);
X	printf("main: tgetstr(%s, 0x%lx) returned '%s'  [strbuf=0x%lx, strptr=0x%lx]\n",
X	  capability, &strptr, outstr, strbuf, strptr);
X	if (strcmp(capability, "so") == 0)
X		{
X		strptr = strbuf;
X		tgetstr("se", &strptr);
X		printf(strbuf);
X		}
X
X	/* test tgoto() */
X	instr = (ac < 6) ? "6\\E&%r%2c%2Y" : av[5];
X	outstr = tgoto(instr, 12, 3);
X	printf("main: tgoto(\"%s\", 12, 3) returned '%s'\n", instr, outstr);
X	
X	/* test tputs() */
X	instr = (ac < 7) ? "3.5*123" : av[6];
X	printf("main: tputs(\"%s\", 3, oc) returned '", instr);
X	tputs(instr, 3, oc);
X	printf("'\n");
X	
X	return 0;
X	}
X
X#endif	TEST
________This_Is_The_END________
if test `wc -c < termcap.c` -ne 20209; then
	echo 'shar: termcap.c was damaged during transit (should have been 20209 bytes)'
fi
fi		; : end of overwriting check
exit 0
--------------------------------------------------------------------------
NHA
---
Norman Azadian, 80A;  Hasler AG;  Belpstrasse 23;  3000 Berne 14;  Switzerland
X.400:  azadian at hslrswi.hasler                     Telephone:   +41 31 63 2178
Uucp:   ... {uunet,ukc,mcvax, ... }!cernvax!hslrswi!azadian
Bitnet: azadian%hslrswi.UUCP at cernvax.BITNET



More information about the Comp.sources.misc mailing list