Added new interface to termcap that allows the manipulation of multiple

termcap entries simultaneously and lifts the 1024 byte limit on the termcap
entry.  The original termcap api is unchanged but also no longer has
the 1024 byte limit if the termcap functions are used.
This commit is contained in:
blymn 1999-08-15 10:59:01 +00:00
parent 59873a18ee
commit 1bb0398527
6 changed files with 497 additions and 94 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.20 1999/02/12 11:34:07 lukem Exp $
# $NetBSD: Makefile,v 1.21 1999/08/15 10:59:01 blymn Exp $
# @(#)Makefile 8.1 (Berkeley) 6/4/93
LIB= termcap
@ -7,7 +7,10 @@ SRCS= termcap.c tgoto.c tputs.c
MAN= termcap.3
MLINKS= termcap.3 tgetent.3 termcap.3 tgetflag.3 termcap.3 tgetnum.3 \
termcap.3 tgetstr.3 termcap.3 tgoto.3 termcap.3 tputs.3
termcap.3 tgetstr.3 termcap.3 tgoto.3 termcap.3 tputs.3 \
termcap.3 t_getent.3 termcap.3 t_getflag.3 termcap.3 t_getnum.3 \
termcap.3 t_getstr.3 termcap.3 t_goto.3 termcap.3 t_puts.3 \
termcap.3 t_freent.3
INCS= termcap.h
INCSDIR=/usr/include

View File

@ -1,4 +1,4 @@
.\" $NetBSD: termcap.3,v 1.12 1999/07/02 15:46:05 simonb Exp $
.\" $NetBSD: termcap.3,v 1.13 1999/08/15 10:59:01 blymn Exp $
.\"
.\" Copyright (c) 1980, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
@ -52,6 +52,7 @@
.Vt char *BC;
.Vt char *UP;
.Vt short ospeed;
.Vt struct tinfo *info;
.Ft int
.Fn tgetent "char *bp" "char *name"
.Ft int
@ -64,6 +65,20 @@
.Fn tgoto "char *cm" "int destcol" "int destline"
.Ft void
.Fn tputs "char *cp" "int affcnt" "void (*outc)(int)"
.Ft int
.Fn t_getent "struct tinfo **info" "char *name"
.Ft int
.Fn t_getnum "struct tinfo *info" "char *id"
.Ft int
.Fn t_getflag "struct tinfo *info" "char *id"
.Ft char *
.Fn t_getstr "struct tinfo *info" "char *id" "char **area" "int *limit"
.Ft int
.Fn t_goto "struct tinfo *info" "char *id" "int destcol" "int destline" "char *buffer" "int limit"
.Ft int
.Fn t_puts "struct tinfo *info" "char *cp" "int affcnt" "void (*outc)(char, void *)" "void *args"
.Ft void
.Fn t_freent "char *info"
.Sh DESCRIPTION
These functions extract and use capabilities from a terminal capability data
base, usually
@ -241,6 +256,133 @@ capability)
if a null
.Pq Sy ^@
is inappropriate.
.Pp
The
.Fn t_getent
function operates in a similar manner to the
.Fn tgetent
function excepting that the
.Fa info
argument is a pointer to a pointer of the opaque type
.Va tinfo .
If the call to
.Fn t_getent
succeeds then the argument
.Fa info
will be updated with the address of an object that contains the termcap
entry. This pointer can then be passed to calls of
.Fn t_getnum ,
.Fn t_getflag
and
.Fn t_getstr .
When the information pointed to by
.Fa info
is no longer required any storage associated with the object can be
released by calling
.Fn t_freent .
The functions
.Fn t_getnum
and
.Fn t_getflag
operate in the same manner as
.Fn tgetnum
and
.Fn tgetflag
with the exception that the pointer to the termcap object is passed along
with the id of the capability required. The function
.Fn t_getstr
performs the same function as
.Fn tgetstr
but has a
.Fa limit
parameter that gives the number of characters that can be inserted in to
the array pointed to by
.Fa area .
The
.Fa limit
argument is updated by the
.Fn t_getstr
call to give the number of characters that remain available in
.Fa area .
If the t_getstr call fails then
.Sy NULL
will be returned and errno set to indicate the failure, ENOENT indicates
there was no termcap entry for the given
.Fa id ,
E2BIG indicates the retrieved entry would have overflowed
.Fa area .
.Pp
The
.Fn t_goto
function is the same as the
.Fn tgoto
function excepting that the capabilities for
.Sy up
and
.Sy bc
are extracted from the
.Fa info
object and that the string formed by
.Fn t_goto
is placed in the
.Fa buffer
argument, the number of characters allowed to be placed in
.Fa buffer
is controlled by
.Fa limit .
If the expansion performed by
.Fn t_goto
would exceed the space in
.Fa buffer
then
.Fn t_goto
will return -1 and set errno to
.Sy E2BIG .
The function
.Fn t_puts
is similar to the
.Fn tputs
function excepting that
.Fa info
holds a pointer to the termcap object that was returned by a previous
.Fn t_getent
call, this object will be used to retrieve the
.Sy pc
attribute for the terminal. The
.Fa outc
function is a pointer to a function that will be called by
.Fn t_puts
to output each character in the
.Fa cp
string. The
.Fa outc
function will be called with two parameters. The first is the character
to be printed and the second is an optional argument that was passed to
.Fn t_puts
in the
.Fa args
argument. The interpretation of the contents of
.Fa args
is dependent soley on the implementation of
.Fa outc.
.Pp
NOTE: If the termcap entry would exceed the 1024 buffer passed to
.Fa tgetent
then a special capability of
.Fa ZZ
is added to the end of the termcap. The number that follows this entry
is the address of the buffer allocated to hold the full termcap entry. The
caller may retrieve the pointer to the extended buffer by performing a
.Fn tgetstr
to retrieve the
.Fa ZZ
capability, the string is the output of a
.Fn printf
%p and may be converted back to a pointer using
.Fn sscanf
or similar. The ZZ capability is only necessary if the caller wishes to
directly manipulate the termcap entry, all the termcap function calls
automatically use the extended buffer to retrieve terminal capabilities.
.Sh FILES
.Bl -tag -width /usr/share/misc/termcap -compact
.It Pa /usr/lib/libtermcap.a

View File

@ -1,4 +1,4 @@
/* $NetBSD: termcap.c,v 1.17 1999/07/02 15:46:05 simonb Exp $ */
/* $NetBSD: termcap.c,v 1.18 1999/08/15 10:59:01 blymn Exp $ */
/*
* Copyright (c) 1980, 1993
@ -38,7 +38,7 @@
#if 0
static char sccsid[] = "@(#)termcap.c 8.1 (Berkeley) 6/4/93";
#else
__RCSID("$NetBSD: termcap.c,v 1.17 1999/07/02 15:46:05 simonb Exp $");
__RCSID("$NetBSD: termcap.c,v 1.18 1999/08/15 10:59:01 blymn Exp $");
#endif
#endif /* not lint */
@ -50,8 +50,17 @@ __RCSID("$NetBSD: termcap.c,v 1.17 1999/07/02 15:46:05 simonb Exp $");
#include <stdlib.h>
#include <string.h>
#include <termcap.h>
#include <errno.h>
#include "pathnames.h"
/* internal definition of tinfo structure - just a pointer to the malloc'ed
* buffer for now.
*/
struct tinfo
{
char *info;
};
/*
* termcap - routines for dealing with the terminal capability data base
*
@ -67,18 +76,21 @@ __RCSID("$NetBSD: termcap.c,v 1.17 1999/07/02 15:46:05 simonb Exp $");
*/
static char *tbuf; /* termcap buffer */
static struct tinfo *fbuf; /* untruncated termcap buffer */
/*
* Get an entry for terminal name in buffer bp from the termcap file.
* Get an extended entry for the terminal name. This differs from
* tgetent only in a) the buffer is malloc'ed for the caller and
* b) the termcap entry is not truncated to 1023 characters.
*/
int
tgetent(bp, name)
char *bp;
t_getent(bp, name)
struct tinfo **bp;
const char *name;
{
char *p;
char *cp;
char *dummy;
char **fname;
char *home;
int i;
@ -86,8 +98,9 @@ tgetent(bp, name)
char *pathvec[PVECSIZ]; /* to point to names in pathbuf */
char *termpath;
if ((*bp = malloc(sizeof(struct tinfo))) == NULL) return 0;
fname = pathvec;
tbuf = bp;
p = pathbuf;
cp = getenv("TERMCAP");
/*
@ -143,31 +156,58 @@ tgetent(bp, name)
* user had setup name to be built from a path they can not
* normally read.
*/
dummy = NULL;
i = cgetent(&dummy, pathvec, name);
(*bp)->info = NULL;
i = cgetent(&((*bp)->info), pathvec, name);
if (i == 0) {
/*
* If the entry is too long, truncate to the last whole cap.
*/
strncpy(bp, dummy, 1024);
if (strlen(dummy) > 1023 && bp[1023] != ':' ) {
for (cp = bp+1022 ; cp > bp && *cp != ':' ; --cp)
;
if (cp > bp)
cp[1] = 0;
}
bp[1023] = '\0';
}
if (dummy)
free(dummy);
/* no tc reference loop return code in libterm XXX */
if (i == -3)
return (-1);
return (i + 1);
}
/*
* Get an entry for terminal name in buffer bp from the termcap file.
*/
int
tgetent(bp, name)
char *bp;
const char *name;
{
int i, plen, elen, c;
char *ptrbuf = NULL;
i = t_getent(&fbuf, name);
if (i == 1) {
/* stash the full buffer pointer as the ZZ capability
in the termcap buffer passed.
*/
plen = asprintf(&ptrbuf, ":ZZ=%p", fbuf->info);
strncpy(bp, fbuf->info, 1024);
bp[1023] = '\0';
elen = strlen(bp);
/* backup over the entry if the addition of the full
buffer pointer will overflow the buffer passed. We
want to truncate the termcap entry on a capability
boundary.
*/
if ((elen + plen) > 1023) {
bp[1023 - plen] = '\0';
for (c = (elen - plen); c > 0; c--) {
if (bp[c] == ':') {
bp[c] = '\0';
break;
}
}
}
strcat(bp, ptrbuf);
tbuf = bp;
}
return i;
}
/*
* Return the (numeric) option id.
* Numeric options look like
@ -177,28 +217,44 @@ tgetent(bp, name)
* Note that we handle octal numbers beginning with 0.
*/
int
tgetnum(id)
t_getnum(info, id)
struct tinfo *info;
const char *id;
{
long num;
if (cgetnum(tbuf, id, &num) == 0)
if (cgetnum(info->info, id, &num) == 0)
return (int)(num);
else
return (-1);
}
int
tgetnum(id)
const char *id;
{
return t_getnum(fbuf, id);
}
/*
* Handle a flag option.
* Flag options are given "naked", i.e. followed by a : or the end
* of the buffer. Return 1 if we find the option, or 0 if it is
* not given.
*/
int t_getflag(info, id)
struct tinfo *info;
const char *id;
{
return (cgetcap(info->info, id, ':') != NULL);
}
int
tgetflag(id)
const char *id;
{
return (cgetcap(tbuf, id, ':') != NULL);
return t_getflag(fbuf, id);
}
/*
@ -207,12 +263,15 @@ tgetflag(id)
* cl=^Z
* Much decoding is done on the strings, and the strings are
* placed in area, which is a ref parameter which is updated.
* No checking on area overflow.
* limit is the number of characters allowed to be put into
* area, this is updated.
*/
char *
tgetstr(id, area)
t_getstr(info, id, area, limit)
struct tinfo *info;
const char *id;
char **area;
int *limit;
{
char ids[3];
char *s;
@ -227,10 +286,55 @@ tgetstr(id, area)
ids[1] = id[1];
ids[2] = '\0';
if ((i = cgetstr(tbuf, ids, &s)) < 0)
if ((i = cgetstr(info->info, ids, &s)) < 0) {
errno = ENOENT;
return NULL;
}
/* check if there is room for the new entry to be put into area */
if (limit != NULL && (*limit < i)) {
errno = E2BIG;
return NULL;
}
strcpy(*area, s);
*area += i + 1;
return (s);
if (limit != NULL) *limit -= i;
return (s);
}
/*
* Get a string valued option.
* These are given as
* cl=^Z
* Much decoding is done on the strings, and the strings are
* placed in area, which is a ref parameter which is updated.
* No checking on area overflow.
*/
char *
tgetstr(id, area)
const char *id;
char **area;
{
struct tinfo dummy;
if ((id[0] == 'Z') && (id[1] == 'Z')) {
dummy.info = tbuf;
return t_getstr(&dummy, id, area, NULL);
}
else
return t_getstr(fbuf, id, area, NULL);
}
/*
* Free the buffer allocated by t_getent
*
*/
void
t_freent(info)
struct tinfo *info;
{
free(info->info);
free(info);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: termcap.h,v 1.5 1999/08/14 13:56:48 tron Exp $ */
/* $NetBSD: termcap.h,v 1.6 1999/08/15 10:59:01 blymn Exp $ */
/*-
* Copyright (c) 1992, 1993
@ -41,6 +41,8 @@
#ifndef _TERMCAP_H_
#define _TERMCAP_H_
struct tinfo;
__BEGIN_DECLS
int tgetent __P((char *, const char *));
char *tgetstr __P((const char *, char **));
@ -49,6 +51,18 @@ int tgetnum __P((const char *));
char *tgoto __P((const char *, int, int));
void tputs __P((const char *, int, void (*)(int)));
/*
* New interface
*/
int t_getent __P((struct tinfo **, const char *));
int t_getnum __P((struct tinfo *, const char *));
int t_getflag __P((struct tinfo *, const char *));
char *t_getstr __P((struct tinfo *, const char *, char **, int *));
int t_goto __P((struct tinfo *, const char *, int, int, char *, int));
int t_puts __P((struct tinfo *, const char *, int,
void (*)(char, void *), void *));
void t_freent __P((struct tinfo *));
extern char PC;
extern char *BC;
extern char *UP;

View File

@ -1,4 +1,4 @@
/* $NetBSD: tgoto.c,v 1.12 1999/07/02 15:46:05 simonb Exp $ */
/* $NetBSD: tgoto.c,v 1.13 1999/08/15 10:59:02 blymn Exp $ */
/*
* Copyright (c) 1980, 1993
@ -38,10 +38,11 @@
#if 0
static char sccsid[] = "@(#)tgoto.c 8.1 (Berkeley) 6/4/93";
#else
__RCSID("$NetBSD: tgoto.c,v 1.12 1999/07/02 15:46:05 simonb Exp $");
__RCSID("$NetBSD: tgoto.c,v 1.13 1999/08/15 10:59:02 blymn Exp $");
#endif
#endif /* not lint */
#include <errno.h>
#include <string.h>
#include <termcap.h>
@ -82,27 +83,63 @@ tgoto(CM, destcol, destline)
int destcol, destline;
{
static char result[MAXRETURNSIZE];
if (t_goto(NULL, CM, destcol, destline, result, MAXRETURNSIZE) >= 0)
return result;
else
return ("OOPS");
}
/*
* New interface. Functionally the same as tgoto but uses the tinfo struct
* to set UP and BC. The arg buffer is filled with the result string, limit
* defines the maximum number of chars allowed in buffer. The function
* returns 0 on success, -1 otherwise.
*/
int
t_goto(info, CM, destcol, destline, buffer, limit)
struct tinfo *info;
const char *CM;
int destcol;
int destline;
char *buffer;
int limit;
{
static char added[10];
const char *cp = CM;
char *dp = result;
int c;
char *dp = buffer;
char *old_up = UP, *old_bc = BC;
char new_up[MAXRETURNSIZE], new_bc[MAXRETURNSIZE], *up_ptr, *bc_ptr;
int c, count = MAXRETURNSIZE;
int oncol = 0;
int which = destline;
if (info != NULL)
{
up_ptr = new_up;
bc_ptr = new_bc;
UP = t_getstr(info, "up", &up_ptr, &count);
count = MAXRETURNSIZE;
BC = t_getstr(info, "bc", &bc_ptr, &count);
}
if (cp == 0) {
errno = EINVAL;
toohard:
/*
* ``We don't do that under BOZO's big top''
*/
return ("OOPS");
UP = old_up;
BC = old_bc;
return -1;
}
added[0] = '\0';
while ((c = *cp++) != '\0') {
if (c != '%') {
copy:
*dp++ = c;
if (dp >= &result[MAXRETURNSIZE])
goto toohard;
if (dp >= &buffer[limit])
{
errno = E2BIG;
goto toohard;
}
continue;
}
switch (c = *cp++) {
@ -122,23 +159,32 @@ copy:
/* FALLTHROUGH */
case '3':
if (which >= 1000)
goto toohard;
*dp++ = (which / 100) | '0';
if (dp >= &result[MAXRETURNSIZE])
goto toohard;
if (which >= 1000) {
errno = E2BIG;
goto toohard;
}
*dp++ = (which / 100) | '0';
if (dp >= &buffer[limit]) {
errno = E2BIG;
goto toohard;
}
which %= 100;
/* FALLTHROUGH */
case '2':
two:
*dp++ = which / 10 | '0';
if (dp >= &result[MAXRETURNSIZE])
goto toohard;
if (dp >= &buffer[limit]) {
errno = E2BIG;
goto toohard;
}
one:
*dp++ = which % 10 | '0';
if (dp >= &result[MAXRETURNSIZE])
goto toohard;
if (dp >= &buffer[limit]) {
errno = E2BIG;
goto toohard;
}
swap:
oncol = 1 - oncol;
setwhich:
@ -188,15 +234,22 @@ setwhich:
*/
do {
if (strlen(added) + strlen(add) >= sizeof(added))
goto toohard;
(void)strcat(added, add);
{
errno = E2BIG;
goto toohard;
}
(void)strcat(added, add);
which++;
} while (which == '\n');
}
}
*dp++ = which;
if (dp >= &result[MAXRETURNSIZE])
goto toohard;
if (dp >= &buffer[limit])
{
errno = E2BIG;
goto toohard;
}
goto swap;
case 'r':
@ -225,11 +278,18 @@ setwhich:
#endif
default:
goto toohard;
errno = EINVAL;
goto toohard;
}
}
if (dp + strlen(added) >= &result[MAXRETURNSIZE])
goto toohard;
(void)strcpy(dp, added);
return (result);
if (dp + strlen(added) >= &buffer[limit])
{
errno = E2BIG;
goto toohard;
}
(void)strcpy(dp, added);
UP = old_up;
BC = old_bc;
return 0;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: tputs.c,v 1.9 1999/02/02 12:34:56 christos Exp $ */
/* $NetBSD: tputs.c,v 1.10 1999/08/15 10:59:02 blymn Exp $ */
/*
* Copyright (c) 1980, 1993
@ -38,14 +38,18 @@
#if 0
static char sccsid[] = "@(#)tputs.c 8.1 (Berkeley) 6/4/93";
#else
__RCSID("$NetBSD: tputs.c,v 1.9 1999/02/02 12:34:56 christos Exp $");
__RCSID("$NetBSD: tputs.c,v 1.10 1999/08/15 10:59:02 blymn Exp $");
#endif
#endif /* not lint */
#include <ctype.h>
#include <termcap.h>
#include <stdio.h>
#undef ospeed
/* internal functions */
int _tputs_convert __P((const char **, int));
/*
* The following array gives the number of tens of milliseconds per
* character for each speed as returned by gtty. Thus since 300
@ -59,6 +63,43 @@ short tmspc10[] = {
short ospeed;
char PC;
int
_tputs_convert(ptr, affcnt)
const char **ptr;
int affcnt;
{
int i = 0;
/*
* Convert the number representing the delay.
*/
if (isdigit(*(*ptr))) {
do
i = i * 10 + *(*ptr)++ - '0';
while (isdigit(*(*ptr)));
}
i *= 10;
if (*(*ptr) == '.') {
(*ptr)++;
if (isdigit(*(*ptr)))
i += *(*ptr) - '0';
/*
* Only one digit to the right of the decimal point.
*/
while (isdigit(*(*ptr)))
(*ptr)++;
}
/*
* If the delay is followed by a `*', then
* multiply by the affected lines count.
*/
if (*(*ptr) == '*')
(*ptr)++, i *= affcnt;
return i;
}
/*
* Put the character string cp out, with padding.
* The number of affected lines is affcnt, and the routine
@ -76,33 +117,9 @@ tputs(cp, affcnt, outc)
if (cp == 0)
return;
/*
* Convert the number representing the delay.
*/
if (isdigit(*cp)) {
do
i = i * 10 + *cp++ - '0';
while (isdigit(*cp));
}
i *= 10;
if (*cp == '.') {
cp++;
if (isdigit(*cp))
i += *cp - '0';
/*
* Only one digit to the right of the decimal point.
*/
while (isdigit(*cp))
cp++;
}
/*
* If the delay is followed by a `*', then
* multiply by the affected lines count.
*/
if (*cp == '*')
cp++, i *= affcnt;
/* scan and convert delay digits (if any) */
i = _tputs_convert(&cp, affcnt);
/*
* The guts of the string.
*/
@ -130,3 +147,66 @@ tputs(cp, affcnt, outc)
for (i /= mspc10; i > 0; i--)
(*outc)(PC);
}
int
t_puts(info, cp, affcnt, outc, args)
struct tinfo *info;
const char *cp;
int affcnt;
void (*outc) __P((char, void *));
void *args;
{
int i = 0, limit = 2;
int mspc10;
char pad[2], *pptr;
if (info != NULL)
{
/*
* if we have info then get the pad char from the
* termcap entry if it exists, otherwise use the
* default NUL char.
*/
pptr = pad;
if (t_getstr(info, "pc", &pptr, &limit) == NULL)
{
pad[0] = '\0';
}
}
if (cp == 0)
return -1;
/* scan and convert delay digits (if any) */
i = _tputs_convert(&cp, affcnt);
/*
* The guts of the string.
*/
while (*cp)
(*outc)(*cp++, args);
/*
* If no delay needed, or output speed is
* not comprehensible, then don't try to delay.
*/
if (i == 0)
return 0;
if (ospeed <= 0 || ospeed >= (sizeof tmspc10 / sizeof tmspc10[0]))
return 0;
/*
* Round up by a half a character frame,
* and then do the delay.
* Too bad there are no user program accessible programmed delays.
* Transmitting pad characters slows many
* terminals down and also loads the system.
*/
mspc10 = tmspc10[ospeed];
i += mspc10 / 2;
for (i /= mspc10; i > 0; i--)
(*outc)(pad[0], args);
return 0;
}