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