diff --git a/lib/libterm/Makefile b/lib/libterm/Makefile index 384e87293ba9..ca494c36d338 100644 --- a/lib/libterm/Makefile +++ b/lib/libterm/Makefile @@ -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 diff --git a/lib/libterm/termcap.3 b/lib/libterm/termcap.3 index 87f8f5bfe0ea..f40f0c63092d 100644 --- a/lib/libterm/termcap.3 +++ b/lib/libterm/termcap.3 @@ -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 diff --git a/lib/libterm/termcap.c b/lib/libterm/termcap.c index 4b36640c0f39..0d8e3572c1e0 100644 --- a/lib/libterm/termcap.c +++ b/lib/libterm/termcap.c @@ -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 #include #include +#include #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); } diff --git a/lib/libterm/termcap.h b/lib/libterm/termcap.h index a9d42a7338f6..c04ccaef5c1b 100644 --- a/lib/libterm/termcap.h +++ b/lib/libterm/termcap.h @@ -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; diff --git a/lib/libterm/tgoto.c b/lib/libterm/tgoto.c index b6beab7f5754..0c8cb25cf324 100644 --- a/lib/libterm/tgoto.c +++ b/lib/libterm/tgoto.c @@ -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 #include #include @@ -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; } diff --git a/lib/libterm/tputs.c b/lib/libterm/tputs.c index 87458314751c..a3290ff1ade0 100644 --- a/lib/libterm/tputs.c +++ b/lib/libterm/tputs.c @@ -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 #include +#include #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; +}