diff options
author | Nicholas Marriott <nicm@cvs.openbsd.org> | 2009-10-18 13:51:45 +0000 |
---|---|---|
committer | Nicholas Marriott <nicm@cvs.openbsd.org> | 2009-10-18 13:51:45 +0000 |
commit | eba2773a6849471a227d9646c175e73dc43e7948 (patch) | |
tree | f532f60e41eb45dd6c63b167c2698c9b48cc111b /lib/libcurses/tinfo | |
parent | b8e3e2e5c2c722c3846a4cf56102962bdedc8a0f (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.c | 91 |
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'; |