diff -r 6183aa8dcdf4 lib/libterminfo/term.c --- a/lib/libterminfo/term.c Sun Feb 01 13:15:54 2026 +0000 +++ b/lib/libterminfo/term.c Tue Feb 17 10:50:05 2026 +0000 @@ -47,8 +47,18 @@ /* * Although we can read v1 structure (which includes v2 alias records) * we really want a v3 structure to get numerics of type int rather than short. + * In the future, we may want to use /usr/share/terminfo as a directory + * and have each terminal description compiled to it's own .cdb file within. */ -#define _PATH_TERMINFO "/usr/share/misc/terminfo" +#ifndef PATH_SYS_TERMINFO +#define PATH_SYS_TERMINFO "/usr/share/misc/terminfo" +#endif +#ifndef PATH_PKG_TERMINFO +#define PATH_PKG_TERMINFO "/usr/pkg/share/terminfo" +#endif +#ifndef PATH_TERMINFO +#define PATH_TERMINFO PATH_PKG_TERMINFO ":" PATH_SYS_TERMINFO +#endif #ifdef TERMINFO_DB static char __ti_database[PATH_MAX]; @@ -274,13 +284,24 @@ size_t len, klen; int r; - r = snprintf(__ti_database, sizeof(__ti_database), "%s.cdb", path); - if (r < 0 || (size_t)r > sizeof(__ti_database)) { + /* Prefer a specific database */ + r = snprintf(__ti_database, sizeof(__ti_database), "%s/%c/%s.cdb", path, + name[0], name); + if (r < 0 || (size_t)r > sizeof(__ti_database)) db = NULL; - errno = ENOENT; /* To fall back to a non extension. */ - } else + else db = cdbr_open(__ti_database, CDBR_DEFAULT); + if (db == NULL) { + r = snprintf(__ti_database, sizeof(__ti_database), "%s.cdb", + path); + if (r < 0 || (size_t)r > sizeof(__ti_database)) { + db = NULL; + errno = ENOENT; /* To fall back to a non extension. */ + } else + db = cdbr_open(__ti_database, CDBR_DEFAULT); + } + /* Target file *may* be a cdb file without the extension. */ if (db == NULL && errno == ENOENT) { len = strlcpy(__ti_database, path, sizeof(__ti_database)); @@ -424,7 +445,7 @@ r = _ti_dbgetterm(term, homepath, name, flags); } if (r != 1) - r = _ti_dbgettermp(term, _PATH_TERMINFO, name, flags); + r = _ti_dbgettermp(term, PATH_TERMINFO, name, flags); #endif return r; diff -r 6183aa8dcdf4 lib/libterminfo/terminfo.5.in --- a/lib/libterminfo/terminfo.5.in Sun Feb 01 13:15:54 2026 +0000 +++ b/lib/libterminfo/terminfo.5.in Tue Feb 17 10:50:05 2026 +0000 @@ -27,7 +27,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd October 18, 2025 +.Dd February 9, 2026 .Dt TERMINFO 5 .Os .Sh NAME @@ -195,11 +195,13 @@ .Ed .Ss Fetching Compiled Descriptions This implementation uses hashed databases managed by -.Xr cdb 5 -instead of directories. +.Xr cdb 5 . To maintain compatibility with other implementations, .Pa .cdb is appended to each file checked. +If the file is a directory then we lookup a subdirectory +starting with the first letter of the terminal name and then +the terminal name as the file to actually use. .Pp If the environment variable .Ev TERMINFO @@ -229,6 +231,8 @@ will first look for .Pa $HOME/.terminfo , followed by +.Pa /usr/pkg/share/terminfo +and .Pa /usr/share/misc/terminfo unless .Ev TERMINFO_DIRS @@ -240,22 +244,13 @@ .Bl -tag -width /usr/share/misc/terminfo.cdb -compact .It Pa $HOME/.terminfo.cdb Database of terminal descriptions for personal use. +.It Pa /usr/pkg/share/terminfo +Directory containing terminfo databases per terminal description. .It Pa /usr/share/misc/terminfo File containing terminal descriptions. .It Pa /usr/share/misc/terminfo.cdb Database of terminal descriptions. .El -.Sh COMPATIBILITY -Please note that -.Ev TERMINFO_DIRS -in -.Nx -.Nm -must point to -.Nm -files. -When using ncurses, it must point to directories instead, since -ncurses splits out the information into a directory tree. .Sh SEE ALSO .Xr infocmp 1 , .Xr tic 1 , @@ -287,6 +282,8 @@ .Nm files to search for .Ev TERM . +If unset, defaults to +.Pa /usr/pkg/share/terminfo:/usr/share/misc/terminfo . .El .Sh STANDARDS .Nm diff -r 6183aa8dcdf4 usr.bin/tic/tic.1 --- a/usr.bin/tic/tic.1 Sun Feb 01 13:15:54 2026 +0000 +++ b/usr.bin/tic/tic.1 Tue Feb 17 10:50:05 2026 +0000 @@ -27,7 +27,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd June 3, 2012 +.Dd February 9, 2026 .Dt TIC 1 .Os .Sh NAME @@ -36,7 +36,7 @@ .Sh SYNOPSIS .Nm tic .Op Fl acSsx -.Op Fl o Ar file +.Op Fl o Ar path .Ar source .Op Ar term1 term2 ... .Sh DESCRIPTION @@ -53,10 +53,11 @@ Do not discard commented out capabilities. .It Fl c Only check for errors, don't write the final database. -.It Fl o Ar file -Write the database to -.Ar file -instead of +.It Fl o Ar path +If +.Ar path +is a directory then terminal descriptions will be split out into separate +databases, otherwise the file to write to instead of .Ar source Ns .cdb . .It Fl S For diff -r 6183aa8dcdf4 usr.bin/tic/tic.c --- a/usr.bin/tic/tic.c Sun Feb 01 13:15:54 2026 +0000 +++ b/usr.bin/tic/tic.c Tue Feb 17 10:50:05 2026 +0000 @@ -567,11 +567,10 @@ } static void -write_database(const char *dbname) +write_database(const char *dbname, TERM *term) { struct cdbw *db; char *tmp_dbname; - TERM *term; int fd; mode_t m; @@ -579,8 +578,12 @@ if (db == NULL) err(EXIT_FAILURE, "cdbw_open failed"); /* Save the terms */ - STAILQ_FOREACH(term, &terms, next) + if (term != NULL) save_term(db, term); + else { + STAILQ_FOREACH(term, &terms, next) + save_term(db, term); + } easprintf(&tmp_dbname, "%s.XXXXXX", dbname); fd = mkstemp(tmp_dbname); @@ -603,6 +606,24 @@ cdbw_close(db); } +static void +write_databases(const char *dir) +{ + TERM *term; + char *db, subdir[2] = { '\0', '\0' }, *d; + + STAILQ_FOREACH(term, &terms, next) { + subdir[0] = *term->tic->name; + easprintf(&d, "%s/%s", dir, subdir); + if (mkdir(d, 0755) == -1 && errno != EEXIST) + err(EXIT_FAILURE, "mkdir %s failed", d); + free(d); + easprintf(&db, "%s/%s/%s.cdb", dir, subdir, term->tic->name); + write_database(db, term); + free(db); + } +} + int main(int argc, char **argv) { @@ -700,13 +721,21 @@ if (ofile == NULL) easprintf(&dbname, "%s.cdb", source); - else - dbname = ofile; - write_database(dbname); + else { + struct stat sb; + + if (stat(ofile, &sb) != -1 && S_ISDIR(sb.st_mode)) { + dbname = NULL; + write_databases(ofile); + } else + dbname = ofile; + } + if (dbname != NULL) + write_database(dbname, NULL); if (sflag != 0) fprintf(stderr, "%zu entries and %zu aliases written to %s\n", - nterm, nalias, dbname); + nterm, nalias, dbname ? dbname : ofile); if (ofile == NULL) free(dbname);