summaryrefslogtreecommitdiff
path: root/lib/libcurses/tinfo
diff options
context:
space:
mode:
authorNicholas Marriott <nicm@cvs.openbsd.org>2009-10-18 13:51:45 +0000
committerNicholas Marriott <nicm@cvs.openbsd.org>2009-10-18 13:51:45 +0000
commiteba2773a6849471a227d9646c175e73dc43e7948 (patch)
treef532f60e41eb45dd6c63b167c2698c9b48cc111b /lib/libcurses/tinfo
parentb8e3e2e5c2c722c3846a4cf56102962bdedc8a0f (diff)
terminfo supports the use= capability (tc= in termcap), to allow one
description to reference another. If this is used, any capabilities in the parent terminal description should override those pulled in by use=. When cap_mkdb is building terminfo.db, it concatenates any use= references together so each description is self-contained. However, the ncurses terminfo implementation doesn't expect this - it assumes it will have to resolve use= itself, and picks the last entry in the description created by cap_mkdb rather than the first. read_bsd_terminfo.c already makes some transformations to make ncurses happy with the format in the database. So, extend this to trim out duplicate entries, leaving only the first. (Interestingly, ncurses already has code to correctly handle merged tc= capabilities in termcap.db (used if terminfo.db is missing).) "go ahead" deraadt@
Diffstat (limited to 'lib/libcurses/tinfo')
-rw-r--r--lib/libcurses/tinfo/read_bsd_terminfo.c91
1 files changed, 73 insertions, 18 deletions
diff --git a/lib/libcurses/tinfo/read_bsd_terminfo.c b/lib/libcurses/tinfo/read_bsd_terminfo.c
index d916460217a..310925d25d4 100644
--- a/lib/libcurses/tinfo/read_bsd_terminfo.c
+++ b/lib/libcurses/tinfo/read_bsd_terminfo.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: read_bsd_terminfo.c,v 1.15 2009/08/28 11:43:50 nicm Exp $ */
+/* $OpenBSD: read_bsd_terminfo.c,v 1.16 2009/10/18 13:51:44 nicm Exp $ */
/*
* Copyright (c) 1998, 1999, 2000 Todd C. Miller <Todd.Miller@courtesan.com>
@@ -17,7 +17,7 @@
*/
#ifndef lint
-static const char rcsid[] = "$OpenBSD: read_bsd_terminfo.c,v 1.15 2009/08/28 11:43:50 nicm Exp $";
+static const char rcsid[] = "$OpenBSD: read_bsd_terminfo.c,v 1.16 2009/10/18 13:51:44 nicm Exp $";
#endif
#include <curses.priv.h>
@@ -119,9 +119,9 @@ _nc_lookup_bsd_terminfo_entry(tn, filename, tp)
TERMTYPE *const tp;
{
char *pathvec[2];
- char *capbuf, *cptr, *infobuf, *iptr, ch;
+ char *capbuf, *cptr, *infobuf, *iptr, *ifind, *istart, ch;
int error;
- size_t len;
+ size_t len, clen, cnamelen;
pathvec[0] = (char *)filename;
pathvec[1] = NULL;
@@ -161,24 +161,79 @@ _nc_lookup_bsd_terminfo_entry(tn, filename, tp)
iptr = infobuf + len;
*iptr++ = ',';
*iptr++ = '\n';
+ istart = iptr;
- /* Copy the rest of capbuf, converting ':' -> ',' */
+ /*
+ * cap_mkdb(1) expands use=, but ncurses doesn't know this and uses the
+ * last defined cap instead of the first. Step though capbuf skipping
+ * duplicates and replacing ':' with ','.
+ */
cptr++;
while (*cptr != '\0') {
- switch (ch = *cptr++) {
- case '^':
- case '\\':
- *iptr++ = ch;
- if (*cptr != '\0')
- *iptr++ = *cptr++;
- break;
- case ':':
- *iptr++ = ',';
- break;
- default:
- *iptr++ = ch;
- break;
+ /* Find the length of the source cap. */
+ clen = 0;
+ while (cptr[clen] != '\0' && cptr[clen] != ':') {
+ ch = cptr[clen++];
+ if ((ch == '^' || ch == '\\') && cptr[clen] != '\0')
+ clen++;
+ }
+ if (clen == 0) { /* ignore empty caps */
+ if (*cptr == ':')
+ cptr++;
+ continue;
+ }
+
+ /* Find the length of the cap name. */
+ cnamelen = strcspn(cptr, "=@#");
+ if (cnamelen > clen)
+ cnamelen = clen;
+
+ /* Is the cap already in the output buffer? */
+ ifind = istart;
+ while (iptr - ifind > cnamelen) {
+ if (memcmp(ifind, cptr, cnamelen) == 0
+ && strchr(",=@#", ifind[cnamelen]) != NULL)
+ break;
+
+ /*
+ * Move to the next cap, in the output buffer this is
+ * terminated by an unescaped comma.
+ */
+ while (ifind != iptr && *ifind != ',') {
+ ch = *ifind++;
+ if ((ch == '^' || ch == '\\') && ifind != iptr)
+ ifind++;
+ }
+ if (ifind != iptr && *ifind == ',')
+ ifind++;
}
+
+ /* Copy if it isn't already there, replacing ':' -> ','. */
+ if (iptr - ifind <= cnamelen) {
+ while (clen-- != 0) {
+ switch (ch = *cptr++) {
+ case '^':
+ case '\\':
+ *iptr++ = ch;
+ if (clen != 0) {
+ clen--;
+ *iptr++ = *cptr++;
+ }
+ break;
+ case ':':
+ *iptr++ = ',';
+ break;
+ default:
+ *iptr++ = ch;
+ break;
+ }
+ }
+ if (*cptr == ':')
+ *iptr++ = ',';
+ } else
+ cptr += clen;
+ if (*cptr == ':')
+ cptr++;
}
*iptr++ = '\n';
*iptr = '\0';