Copyright © 2011-2018,2022 by Thomas E. Dickey


Tack is a program that can be used to verify or refine a terminfo (terminal information) description of a terminal.


The program's early history is summarized in the HISTORY file in the sources:

Daniel Weaver sent me email in October 1997, suggesting that it might be incorporated into the ncurses project. We discussed this over the next few months, with an unexpected conclusion: RMS persuaded Daniel Weaver to GPL-license tack.

Based on Daniel's initial request, I agreed to make some minor changes to ncurses to allow tack to use some of the undocumented entrypoints and symbols in the ncurses library.

License versus Packaging

Given suitable disclaimers, RMS saw no problem in distributing tack along with ncurses. So I agreed to do this.

I added tack to the ncurses snapshots starting in April 1999, noting in the NEWS file that it is not part of ncurses.

I designed the ncurses configure script so that it would check for the existence of the tack subdirectory before deciding whether to build it. Thus, tack was simply bundled into the same tar ball, and since it was clearly marked as not being part of ncurses, it was not a problem for ncurses for some time.

Due to its license difference versus ncurses, I made relatively few changes to tack for some time (932 insertions, 653 deletions, less than 10% of the program). Like the Ada95 binding and terminfo database, tack resides in a separate source archive. However, there is a break in its change-log, since it was maintained for some time within the ncurses source repository.

However, early in 2007 I happened to notice more than one of my programs marked with an incorrect license, e.g., diffstat and xterm both as "GPL". That prompted me to look for more cases, and I found several. One was tack (more than one instance).

I discussed this with the package maintainers, pointing out that

During the discussion I noted that tack relied on being built within the ncurses source tree. For one packager, it was enough to provide a way to build it outside the tree (done January 2007. That did not work for openSUSE, so I removed tack from the ncurses tree a few weeks later.

After further discussion, openSUSE moved tack to its own package, as shown here.

As the maintainer for tack, I cannot simply remove it from ncurses without providing for keeping it working. I wrote a configure script. Early on, Daniel Weaver had proposed writing one, but that never happened, since we integrated it directly as a subdirectory of the ncurses tree. To make tack build outside the ncurses tree (and also address the concerns of packagers such as openSUSE who did not want to revise their packages), there were several things to consider:

Depending on the system and configuration, tack may use several private symbols from the ncurses library:

Symbol First used Optional library
_nc_copy_termtype 2006/06/24 ncurses, tinfo
_nc_fallback 2007/01/28 ncurses, tinfo
_nc_find_entry 1.00 (1997) ncurses, tinfo
_nc_free_termtype 2007/04/08 ncurses, tinfo
_nc_free_tic 2007/04/08 ncurses, tic
cur_term or _nc_get_curterm 1.00 (1997) ncurses, tinfo
_nc_get_hash_table 1.00 (1997) ncurses, tinfo
_nc_get_tty_mode 1999/02/07 ncurses, tinfo
_nc_init_acs 2006/11/25 ncurses, tinfo
_nc_read_entry 1.00 (1997) ncurses, tinfo
_nc_reset_input 1.00 (1997) ncurses, tic
_nc_strstr 2007/01/28 ncurses, tinfo
_nc_tic_expand 1.00 (1997) ncurses, tic
_nc_trans_string 1.00 (1997) ncurses, tic

That is, the list doubled in size since the first release of tack. I added a third of the entrypoints to this list after moving tack from the ncurses snapshots to a separate tarball.

Packaging does not stop with a configure script. Starting in early 2010, I began creating package scripts (RPM and Debian) for most of the programs that I maintain. Those use a more restricted build environment than the other test-builds, and help me see dependency issues from the packager's perspective. I added that to tack in September 2010. But right before that, I spent some time on code-cleanup, and reformatted it throughout with the same indentation as that which I use in other programs.

Portability Issues

I revisited the problems raised by tack's use of ncurses's internal interfaces while preparing the release for ncurses 6.1 in mid-2017. In that release, I extended the TERMINAL data structure, adding a new TERMTYPE2 to hold “extended numbers” (larger than 32768). That changed the size of TERMINAL, which would not be a problem for applications that used the documented API. To discourage developers from using the details (including the size) of this structure, I made it opaque. Tack was using TERMINAL directly to modify the terminal I/O modes. There is an API for that; modifying tack was simple.

Reconsidering it, eliminating the use of ncurses internals would be an improvement. Daniel Weaver had indicated that he used these functions mainly for convenience. In practice, that was partly true:

The calls to _nc_free_termtype and _nc_free_tic would go away away easily once the other functions were addressed. However, the remaining functions:

_nc_copy_termtype, _nc_find_entry, and _nc_get_hash_table

required some effort. Those were used to allow a user of tack to modify a terminal capability in memory, test the change and write the altered terminal description to a file on exit. You can do this with ncurses, but not with other implementations:

Actually term.h is defined, but X/Open Curses does not go into enough detail to ensure that different implementations are compatible. Quoting from Issue 7, X/Open Curses says

   The following data type is defined through typedef:

   TERMINAL An opaque representation of the capabilities for a single terminal from the
            terminfo database.

   The <term.h> header provides a declaration for the following object: cur_term. It represents the
   current terminal record from the terminfo database that the application has selected by calling

   The <term.h> header defines the variable names listed in the Variable column in the table in
   Section 7.1.3 (on page 342).

The table referred to is too long to quote here. It is the basis for a large part of the terminfo(5) manual page, i.e., Predefined Capabilities. The manner in which the “variable names” are related to cur_term (which happens to point to a TERMINAL object) is left for the implementor. Oddly enough, the Unix implementations that the writers had in mind all did it the same way (either directly based on the AT&T sources, or imitating it). They could have been more specific. But ncurses and NetBSD curses do it in two different ways. Both Unix and NetBSD have (different) problems:

Complying to a standard by eliminating features is not very productive. The feature is supported in ncurses; the array indexes for the names match the indexes used for the variables defined in term.h.

Without arrays, tack cannot edit the terminfo data unless someone builds a large table to relate the structures to the capability names.

The problem with NetBSD is similar: it has arrays of capabilities, but no arrays of names. Editing the terminfo data as done in tack with NetBSD is not possible, since the developer declared all of the terminfo variables as const (i.e., symbols rather than variables).

Working within these limitations, I

NetBSD has no array of names. I constructed a workable table at runtime using the output of infocmp. This is necessarily more limited than that built with Unix curses, since tack would not be able to determine the datatype for cancelled capabilities.

For a fully functional tack, you will need the ncurses version, since neither Unix nor NetBSD provide the ability to modify terminal capabilities readily at runtime. Likewise, the test-screens for padding rely on the ability to modify the terminal capabilities.

Bug Reports

You should report bugs either to me. or to the ncurses mailing list

See the ncurses FAQ