Terminfo
Terminfo is a compiled database that describes the capabilities of various computer terminals, enabling screen-oriented programs such as editors and libraries like ncurses to interact with diverse display devices in a device-independent manner.[1] It specifies features including cursor movement, screen clearing, color support, and initialization sequences, organized into boolean, numeric, and string capabilities for efficient retrieval.[1] Originally developed as a successor to the termcap system, terminfo uses a structured, binary format that allows for faster access and larger string tables compared to termcap's text-based limitations.[2]
The terminfo system originated in the early 1980s, when Mary Ann Horton implemented it at Bell Labs as part of AT&T's UNIX System V, evolving from the Berkeley Software Distribution's (BSD) termcap database to provide a more efficient and extensible framework for terminal handling in curses-based applications.[2] It was integrated into the ncurses library, a free implementation of the System V curses API, with significant maintenance beginning in 1996 under Thomas E. Dickey, who has overseen updates for modern terminals and emulators like xterm and VTE.[3] Contributions from developers such as Eric S. Raymond and vendors including DEC and Wyse have expanded the database to cover hundreds of terminal models, incorporating features like 256-color support and mouse tracking over time.[2]
In practice, terminfo entries are compiled from human-readable source files using the tic utility and stored in hashed directories such as /usr/share/terminfo, allowing programs to query capabilities via the TERM environment variable.[1] Tools like infocmp facilitate comparison and decompilation of entries, while low-level routines in ncurses handle output padding and flow control to ensure compatibility across hardware from legacy devices like the VT100 to contemporary terminal emulators.[4] This architecture has made terminfo a foundational component in Unix-like systems for over four decades, supporting portable text-based user interfaces.[3]
Overview
History
Terminfo was developed by Mary Ann Horton in 1981–1982 at Bell Labs, following her PhD and building upon her contributions to Berkeley Software Distribution (BSD) UNIX as a graduate student at the University of California, Berkeley, which included enhancements to the vi editor and maintenance of the termcap system for terminal descriptions. This work addressed limitations in termcap's text-based parsing, introducing a compiled binary format for faster loading and more efficient capability lookups, particularly beneficial for screen-oriented applications like curses. Horton's initial implementation laid the foundation for terminfo's use in optimizing terminal control libraries.
Following her PhD in 1981, Horton joined Bell Labs, where she developed terminfo and integrated it into AT&T's UNIX System V, replacing termcap as the primary terminal database. The first major commercial release came with UNIX System V Release 2 (SVr2) in 1983, marking terminfo's debut in a production UNIX environment and establishing it as the preferred mechanism for terminal handling in System V derivatives. Concurrently, Pavel Curtis adapted terminfo for his pcurses library between 1982 and 1984, an early open-source curses implementation that ported the technology to non-AT&T systems and influenced subsequent community-driven developments.
By the late 1980s, terminfo saw widespread adoption across Unix-like operating systems, supplanting termcap in many environments due to its performance advantages. It achieved formal standardization in 1988 through the X/Open Portability Guide Issue 3 (XPG3), which incorporated terminfo as part of the X/Open Curses specification, ensuring portability and consistency in terminal database usage for compliant systems. This milestone solidified terminfo's role in POSIX-aligned environments, with ongoing maintenance through later X/Open and Single UNIX Specification versions.
Purpose and Comparison to Termcap
Terminfo serves as a comprehensive database and associated library for describing the capabilities of diverse terminals, facilitating the creation of portable screen-oriented applications such as text editors like vi and libraries like curses. By encapsulating terminal-specific features—such as cursor addressing, color attributes, and keypad mappings—into queryable entries, terminfo allows programs to operate consistently across varying hardware without custom adaptations. This abstraction promotes device independence, enabling developers to write code that queries standardized capabilities rather than embedding hardware-dependent escape sequences.
Developed in 1981 as an enhancement to the earlier termcap system, terminfo addresses several limitations of its predecessor through key structural improvements. Unlike termcap, which relies on a plain-text file parsed at runtime, terminfo compiles descriptions into efficient binary files, significantly reducing access overhead and improving performance for applications on complex terminals. Terminfo also employs descriptive capability names up to 128 characters long, contrasting with termcap's cryptic two-character codes, and supports advanced string formatting with conditional expressions (e.g., using %? for if-then-else logic), allowing more flexible and readable capability definitions. Additionally, terminfo introduces hierarchical inheritance via the use= directive in source files, where a terminal entry can extend another by inheriting its capabilities, whereas termcap maintains flat, self-contained entries without such modularity.
Introduced in UNIX System V Release 2, terminfo gained prominence in AT&T-derived systems, while termcap persisted in BSD lineages, leading to a period of coexistence. By the 1990s, however, terminfo emerged as the dominant standard, particularly with the adoption of X/Open specifications, due to its efficiency and extensibility; termcap is now largely obsolete and maintained only for backward compatibility with legacy software. These advantages make terminfo particularly suitable for modern environments with intricate terminal features, minimizing runtime parsing costs and enhancing overall system portability.
Data Model
Terminal Names and Aliases
In the terminfo database, each terminal entry is identified by a set of names listed in the header line of its source description, separated by vertical bar (|) characters. The first name is the primary name, which is the most common abbreviation and typically used as the value for the $TERM environment variable. Subsequent names function as aliases, providing alternative identifiers that map to the same entry, while the final name is the long descriptive name, often including spaces and capitalization for readability, serving as the canonical identifier that fully describes the terminal type. For instance, the entry for the X Terminal Emulator begins with xterm|xterm-debian|xterm-256color|xterm-new|terminal emulator for X with ANSI color and graphics, where "xterm" is the primary name, "xterm-debian", "xterm-256color", and "xterm-new" are aliases, and "terminal emulator for X with ANSI color and graphics" is the descriptive canonical name.[2][5][6]
Aliases enable compatibility across different systems and historical terminal designations by allowing multiple short names to resolve to a single entry, with implementations required to support unique aliases up to at least 14 characters in length to ensure portability. These aliases must consist of portable filename characters, excluding whitespace, slashes, or leading hyphens, to conform to file system constraints in the compiled database. The search mechanism relies on the [TERM](/page/Term) variable: applications, such as those using the [ncurses](/page/Ncurses) library, query the terminfo database by matching the TERM value against the primary name and all aliases of available entries, retrieving the associated description upon a match. If no exact match is found, some implementations fall back to a default like "dumb", but the process prioritizes exact alias resolution for accurate terminal behavior.[5][7][6]
Naming conventions emphasize lowercase letters for brevity and consistency, typically following a vendor-model format such as "vt100" for the DEC VT100 or "hp2621" for the Hewlett-Packard 2621, with optional hyphenated suffixes to denote variants like "-rv" for reverse video support or "-256color" for extended color capabilities, as seen in "xterm-256color". Root names avoid hyphens or punctuation to prevent parsing issues, and the overall structure ensures names are descriptive yet concise, with an informal recommendation to limit primary names to around five characters. These names act as keys in the database's hashed index structure, where entries are organized into subdirectories based on the first character of the name (e.g., /usr/share/terminfo/x/xterm), facilitating efficient lookups during runtime.[7][5][6]
Capabilities
Terminfo entries describe terminal capabilities through three primary types: boolean, numeric, and string. These capabilities encapsulate the features and behaviors of a terminal, enabling applications to interact with diverse hardware in a standardized way. Boolean capabilities act as flags to indicate the presence or absence of specific features, numeric capabilities provide integer values for quantifiable attributes, and string capabilities define sequences of characters or escape codes to invoke terminal functions. The X/Open Curses standard defines approximately 457 such capabilities in total, including around 33 boolean, 33 numeric, and 391 string types in its core specification, with extensions in implementations like ncurses adding more (e.g., up to 57 boolean, 47 numeric, and 353 string).[5]
Boolean capabilities are simple flags that are either present (true) or absent (false) in a terminal description, with no associated value. They denote binary features such as whether the terminal supports automatic margin wrapping, represented by the am capability, which indicates that the cursor automatically wraps to the next line when reaching the right margin.[5][6] Other examples include capabilities for features like reverse video or protected attributes, allowing applications to query and adapt to terminal limitations without sending unnecessary commands.[5]
Numeric capabilities specify integer values that quantify terminal properties, such as dimensions or limits, and are limited to a maximum of 32,767 to align with 16-bit signed integer storage in compiled entries. For instance, the cols capability denotes the number of columns in the terminal screen, typically set to 80 for standard displays, while lines indicates the number of rows, often 24.[6] These values help applications determine screen layout and avoid exceeding hardware constraints, with negative values sometimes used to signify absent or cancelled features in extensions beyond the core standard.[5]
String capabilities represent the most complex type, consisting of escape sequences, control codes, or commands sent to the terminal to perform actions, often incorporating parameter substitution and padding for flexibility. They support a substitution syntax using % modifiers, such as %p1%d to insert the first parameter as a decimal number, enabling dynamic generation of sequences based on runtime arguments. For example, the cup capability for cursor positioning uses the string \E[%i%p1%d;%p2%dH, where \E is the escape character, %i adds 1 if needed for zero-based indexing, %p1%d inserts the row number, and %p2%d inserts the column number. Similarly, the cm capability for general cursor movement employs \E[%i%p1%d;%p2%dH. Padding is integrated into these strings to account for transmission delays, using notations like $<50> for a fixed 50-millisecond delay or %p1%c for variable padding proportional to the first parameter (e.g., repeating a character for insert operations).[5][6]
Capabilities are further categorized by function to organize terminal interactions. Output capabilities handle screen manipulation, such as the clear string \E[2J\E[H to erase the entire display and home the cursor. Input capabilities define key sequences returned by the terminal, like kcuu1 for the up-arrow key, often \E[A, allowing applications to map user inputs portably. Attribute capabilities control text rendering, exemplified by bold with a string like \E[1m to enter bold mode. These categories ensure comprehensive coverage of terminal operations, from display control to user interaction.[5][6]
Hierarchy and Inheritance
The use= directive in terminfo source files enables a terminal entry to inherit capabilities from one or more base entries, facilitating the reuse of descriptions for similar terminals. This mechanism allows a variant entry to reference another terminal's name after use=, incorporating all capabilities from the base into the variant during compilation. For instance, the xterm entry might be defined as xterm|...:use=vt100, thereby inheriting the core capabilities of the VT100 terminal while allowing additional or modified definitions specific to xterm.[8]
Inheritance follows specific rules to merge capabilities: those from the base entry are copied verbatim unless explicitly overridden by a capability definition in the variant or suppressed to prevent inclusion. Overriding occurs when the variant provides its own value for a capability, such as redefining a string or numeric value; for suppression, the @ suffix cancels a capability entirely (e.g., smkx@ removes the enter-keypad-transmit-mode string even if present in the base), while the ! prefix negates boolean capabilities (e.g., !am sets auto-right-margin to false, countering a true value from the base). Capabilities defined before the use= directive in the source take precedence over those from the base, ensuring precise control over the final merged description.[8]
Multiple use= directives support chaining, where a variant can inherit from several bases, processed in reverse order (rightmost first) to resolve conflicts by later overrides. This creates hierarchical family trees, such as ANSI serving as a base for VT100, which in turn bases xterm, allowing incremental extensions like enhanced cursor controls or escape sequences across terminal evolutions. The approach reduces redundancy by avoiding duplication of common capabilities, for example, basing a color-enabled terminal on a monochrome ancestor and adding only color-specific strings like set_a_foreground.[8]
However, the use= directive operates solely within source files and has no runtime effect; the terminfo compiler ([tic](/page/Tic)) resolves all inheritance into a flat, self-contained compiled entry, eliminating any ongoing hierarchy for efficiency in database lookups. This compilation-time resolution limits flexibility, as changes to a base entry require recompiling dependents, but it ensures consistent, portable access without dependency chains at execution.[8]
Storage Model
Terminfo source files are plain text files that contain one or more terminal descriptions, known as entries, with each entry separated by a blank line or the end of the file.[9] Each entry begins with a field specifying the primary terminal name followed by pipe-separated aliases, terminated by a colon, after which capabilities are listed as comma-separated fields until the end of the entry.[6] Newlines and leading whitespace within an entry are ignored by the parser, allowing capabilities to span multiple lines for readability, though embedded blanks in strings are preserved.[6]
Capabilities in source entries fall into three categories: booleans, numerics, and strings. Boolean capabilities indicate the presence or absence of a feature and are simply listed by name followed by a comma, such as am, for automatic margins.[6] Numeric capabilities specify integer values prefixed with #, followed by the unsigned decimal number and a comma, for example, cols#80, to denote 80 columns.[6] String capabilities are defined with an equals sign followed by the string value and a comma, often including escape sequences; for instance, cup=\E[%i%p1%d;%p2%dH, represents a cursor positioning string where \E denotes an escape character, %i inserts a parameter value, and %p1%d formats the first parameter as a decimal.[6] Within strings, commas and backslashes must be escaped with a backslash to include them literally, such as \, for a comma or \\ for a backslash.[6]
Comments in source files begin with a # in the first column and extend to the end of the line, allowing explanatory notes without affecting the entry.[6] The use= directive enables inclusion of capabilities from another terminal entry, specified as use=termname,, which merges those capabilities into the current entry in reverse order of appearance, with local definitions overriding inherited ones; this supports hierarchy but is processed during compilation.[6]
Strings may incorporate conditional expressions for dynamic behavior, using a syntax like %?ifpart%tthenpart%eelsepart%; to evaluate conditions based on parameters.[6] For example, %?%p1%{6}%tbold%t%; checks if the first parameter equals 6 and outputs "bold" if true, demonstrating if-then logic without an else clause.[6]
Source files are typically organized into multiple files for modularity, with common locations including /usr/share/terminfo.src on Unix-like systems or vendor-specific directories like /usr/share/lib/terminfo/*.ti on others, though users can define custom paths for additional entries.[10] While source files themselves have no inherent size limits, allowing flexible descriptions, the resulting compiled entries are constrained by byte limits such as a 4096-byte string table to ensure efficient storage.[6]
The compiled terminfo format is a compact binary representation optimized for rapid access by terminal-handling libraries, contrasting with the human-readable source format that requires parsing during compilation. It organizes terminal descriptions into a structured layout consisting of a fixed header, followed by dedicated sections for names, boolean flags, numeric values, string offsets, and the actual string data. This design minimizes overhead in runtime queries, allowing applications to load only the necessary portions without processing extraneous text.[11][12]
The file begins with a 12-byte header comprising six 16-bit little-endian short integers: the magic number (octal 0432 for the standard legacy format or 01036 for the extended format), the byte size of the terminal names section, the byte size of the boolean flags section, the count of numeric capabilities (each as a short), the count of string capabilities (each as an offset short), and the byte size of the string table.[11][12] The terminal names section immediately follows, containing one or more null-terminated strings delimited by '|' characters, with the combined length limited to 128 bytes.[12] Boolean capabilities appear next as a contiguous array of single bytes (0 for false, 1 for true, or 0376 for canceled), ordered as defined in the system's <term.h> header.[11] Numeric capabilities are stored as little-endian 16-bit shorts (-1 denotes absence, -2 denotes cancellation), while string capabilities use 16-bit offsets into the trailing string table (-1 for absence); the string table holds null-terminated sequences, often incorporating escape codes and padding for alignment.[11][12] Null bytes pad sections as needed to maintain even-byte alignment, ensuring portability across little-endian architectures and avoiding hardware-specific alignment traps.[12]
Each compiled entry is constrained to a maximum of 4,096 bytes in the legacy format, though extensions like those in ncurses support up to 32,768 bytes to accommodate larger descriptions with additional capabilities.[11] These limits apply to the entire file, including all sections, promoting efficient storage while bounding resource usage in shared system directories.[12]
Compiled files reside in a hierarchical directory structure, typically under /usr/share/terminfo/, with subdirectories named for the first lowercase letter of the terminal name and the file itself named identically to the primary terminal alias (e.g., /usr/share/terminfo/x/[xterm](/page/Xterm)).[12] This organization facilitates quick location by name prefix. Alternatively, some implementations store the full database in a single hashed file using Berkeley DB, where entries are keyed by primary names and linked via aliases, enhancing lookup speed for systems with extensive aliasing or frequent queries.[11][12]
The binary layout supports direct, low-latency reads from disk or memory, bypassing the textual parsing and validation steps inherent to the source format, which enables seamless integration in performance-sensitive applications like curses-based interfaces.[11][12]
Compilation and Utilities
tic Compiler
The tic utility compiles terminfo source files, typically with a .ti extension, into binary format for storage in the terminfo database, enabling efficient access by applications such as those using the ncurses library.[13] By default, compiled entries are installed in the system-wide directory /usr/share/terminfo, organized by the first letter of the terminal name (e.g., running tic xterm.ti places the entry in /usr/share/terminfo/x/xterm), though this can be overridden by the TERMINFO environment variable or user-specific paths like $HOME/.terminfo.[13] Compiling terminfo source files into the database is part of X/Open standards for implementations providing terminfo support, though the facility for doing so is implementation-defined.[5]
Key features of tic include resolving inheritance via the use= clause in source files, where it recursively incorporates capabilities from referenced entries found in the source, the TERMINFO directory, or system paths, ensuring complete terminal descriptions without duplication.[13] It also validates source syntax against the terminfo grammar, checking for proper field separation (e.g., booleans, numerics, strings), use-link consistency, and overall entry size limits (up to 4096 bytes for terminfo entries).[13] Ncurses extensions enhance this by supporting user-defined capabilities.[14]
Common options include -o dir to specify a custom output directory for the compiled database, -x to treat unrecognized capabilities as user-defined (allowing extensions without errors), and -I to force output in terminfo format even when processing termcap-compatible sources.[13] The -c option enables rigorous checking mode, which reports potential issues like syntax errors or inconsistent links without fully compiling, aiding debugging.[13] For path resolution during inheritance, tic searches include directories specified in the source or via environment variables, briefly referencing the source format's structure for capability definitions.[13]
Error handling in [tic](/page/Tic) follows GNU C standards, issuing warnings or fatal errors for issues such as invalid syntax (e.g., malformed strings or duplicate capability names), unresolved use= references, or entries exceeding size limits, while X/Open compliance ensures basic portability but does not mandate the full tic feature set.[13] Duplicate terminal names across files trigger conflicts, preventing installation until resolved.[13]
A typical usage example for custom installations is tic -x -o /custom/terminfo foo.ti, which compiles foo.ti with user-defined capabilities enabled and outputs to /custom/terminfo, creating subdirectories as needed (e.g., /custom/terminfo/f/foo for a terminal named "foo").[13]
The infocmp utility is a key tool for managing and analyzing terminfo entries, primarily used to decompile compiled binary terminfo descriptions into a human-readable source-like format and to compare multiple entries for differences. It outputs the capabilities of a specified terminal entry, allowing users to inspect or rewrite descriptions to optimize inheritance via the use= field.[15] For example, running infocmp [xterm](/page/Xterm) [vt100](/page/VT100) displays a side-by-side comparison highlighting differing capabilities between the xterm and vt100 terminals. Useful options include -D to show database search paths, -u to list entries that inherit from a given one (revealing dependency hierarchies), and -x to include non-standard or experimental extensions in the output.[16] These features make infocmp essential for debugging terminal mismatches and refining terminfo databases.[4]
Several other utilities complement infocmp for terminfo database maintenance and interoperability with legacy systems. The captoinfo command converts termcap source files— an older format predating terminfo—into equivalent terminfo source format, facilitating migration of terminal descriptions from termcap-based systems.[17] Conversely, infotocap performs the reverse operation, translating terminfo source or compiled entries into termcap format while handling use= capabilities directly as termcap equivalents.[18] For runtime queries, tput retrieves and executes individual terminfo capabilities from the shell, such as tput cup 10 20 to move the cursor to row 10, column 20, or tput clear to clear the screen.[19] The toe utility generates a table listing all available terminal entries in the database, including primary names and descriptions, which aids in inventorying and verifying the completeness of the terminfo collection.[20]
Collectively, these utilities support debugging, format conversions for legacy compatibility, and ongoing maintenance of the terminfo database without requiring recompilation via tools like tic.
Usage in Applications
Integration with Curses
The curses library integrates with terminfo to provide portable terminal control by loading and querying terminal descriptions at runtime, enabling applications to output escape sequences and handle input without hardcoding terminal-specific details.[21] The primary interface begins with the setupterm() function, which reads the terminfo database for a specified terminal name (or defaults to the $TERM environment variable if null), initializes terminfo structures with boolean, numeric, and string capabilities, and sets up low-level output handling while leaving higher-level curses virtualization (such as screen buffering) for subsequent calls.[22] This function is invoked implicitly by high-level curses initialization routines like initscr(), which determines the terminal type, calls setupterm(), and establishes the curses data structures including the standard screen window.[23] For programs managing multiple terminals, set_curterm() allows switching between TERMINAL structures by updating the global cur_term pointer and redirecting capability variables accordingly.[24]
Access to terminfo capabilities within curses occurs through dedicated functions that retrieve and process values from the loaded database. String capabilities, such as those for cursor movement, are obtained via tigetstr(), which returns the capability string or NULL if unavailable, allowing applications to format and output them using tputs() for padding-aware emission.[25] Parameter expansion for capabilities with placeholders (e.g., %p1 for row/column in cursor addressing) is handled by tiparm() in ncurses, a variadic extension to the standard tparm() that converts format specifiers to integers and generates the final escape sequence.[21] Input capabilities, including key definitions like arrow keys, are queried through curses macros such as KEY_UP (corresponding to the terminfo kcuu1 capability), which provide symbolic constants for getch() and related input functions to map raw terminal input to application events.[26]
This integration enhances portability by abstracting terminal differences, allowing curses-based applications to run across diverse hardware like VT100 emulators or modern xterm variants without modification, as terminfo handles variations in escape sequences and features. Ncurses, a widely used implementation, extends this with support for wide characters (via the ncursesw variant, using terminfo capabilities like enacs for alternate character sets) and mouse events (leveraging kmous for tracking), enabling Unicode text and interactive input in internationalized or GUI-like terminal apps.[8]
For programs not using the full curses framework, direct access is available through the terminfo library header <terminfo.h>, which exposes functions like setupterm() and tigetstr() independently of curses windows or screens, suitable for simple scripts or embedded output routines.[22] A representative C example demonstrates retrieving and using the cursor positioning capability:
c
#include <stdio.h>
#include <curses.h>
#include <term.h>
int main() {
setupterm((char *)0, 1, (int *)0); // Initialize terminfo for stdout
char *cup_str = tigetstr("cup"); // Get cursor address string
if (cup_str != (char *)-1 && cup_str != 0) {
char *formatted = tiparm(cup_str, 10, 20); // Format for row 10, col 20
if (formatted) {
printf("%s", formatted); // Output the escape sequence
}
}
return 0;
}
#include <stdio.h>
#include <curses.h>
#include <term.h>
int main() {
setupterm((char *)0, 1, (int *)0); // Initialize terminfo for stdout
char *cup_str = tigetstr("cup"); // Get cursor address string
if (cup_str != (char *)-1 && cup_str != 0) {
char *formatted = tiparm(cup_str, 10, 20); // Format for row 10, col 20
if (formatted) {
printf("%s", formatted); // Output the escape sequence
}
}
return 0;
}
This code loads the terminfo entry, fetches the cup (cursor to position) string, expands its parameters, and prints the resulting sequence to move the cursor.[21]
Environment Variables and Access
Applications access the Terminfo database at runtime primarily through environment variables that specify the terminal type and database locations. The TERM environment variable indicates the name of the terminal type, such as "xterm-256color", which is used to look up the corresponding entry in the database; for example, a user might set it with `export [TERM](/page/Term)=xterm-256color` to ensure proper terminal capabilities are loaded.[6] If TERM is unset or specifies an unknown terminal, the library may default to a basic "dumb" terminal entry that assumes minimal capabilities, or in some implementations, fall back to the older Termcap database if available.[1]
The TERMINFO [environment variable](/page/Environment_variable) allows overriding the default path to the compiled Terminfo database, typically located at /usr/share/terminfo on [Unix-like](/page/Unix-like) systems, enabling the use of custom databases in a specified directory.[6] For more flexible searching across multiple directories, the TERMPATH environment variable provides a colon-separated list of paths where the system looks for Terminfo source files, particularly in configurations supporting Termcap compatibility.[27] In modern implementations like ncurses, this is supplemented or replaced by TERMINFO_DIRS, which serves a similar purpose for compiled entries, but TERMPATH remains relevant for legacy or hybrid setups.[28]
To initialize the terminal description programmatically, applications use the setupterm() function from the Terminfo library (libterminfo or ncurses), declared as int setupterm(char *term, int fildes, int *errret), where term (if non-null) specifies the terminal name overriding $TERM, fildes is the output file descriptor (often 1 for stdout), and errret returns status codes such as 0 for unknown terminal or -1 for database access failure.[29] This function handles loading the description for the primary screen and supports multiple screens via cur_term management, allowing applications to switch terminals dynamically without reinitializing.[30]
Security considerations arise when handling untrusted values in these variables, as a malicious TERM could reference a crafted Terminfo entry leading to buffer overflows or memory corruption during parsing; for instance, vulnerabilities in ncurses have been exploited via malformed entries in user-controlled paths like HOME/.terminfo.[31] Such issues, documented in CVEs like CVE-2023-29491, highlight the risks of local privilege escalation if an attacker controls the environment, underscoring the need for validation and sandboxing in untrusted contexts.[32]
Limitations and Extensions
Standard Limitations
The X/Open specification for terminfo imposes strict limits on terminal names and aliases to ensure portability across conforming implementations. Terminal aliases are restricted to a maximum of 14 characters, a legacy constraint originating from filesystem limitations in older systems that restricted filenames to 14 characters. The canonical terminal name, however, can extend up to 128 characters. These limits apply to the source format, where alias names must use portable characters without leading hyphens, whitespace, or slashes.[5]
Compiled terminfo entries are constrained to a maximum size of 4,096 bytes, a limit enforced by the tic compiler in X/Open-compliant systems to maintain compatibility with the binary format expectations. The source format has no overall size limit, but practical constraints arise from the predefined set of capabilities in the standard and extensions, with major implementations supporting several hundred capabilities (e.g., 527 in ncurses). Individual source lines are limited to 1,023 bytes, and string values to 1,000 bytes, while single fields cannot exceed 128 bytes. These bounds ensure efficient compilation and runtime access while preventing excessive resource use.[5][33][11]
Numeric capabilities in terminfo are restricted to the range 0–32,767, corresponding to the capacity of an unsigned short integer (16 bits). This limitation applies to all quantifiable terminal features, such as the number of columns or lines, and exceeding it results in compilation errors or truncation in conforming implementations.[5][6]
String capabilities employ a parameterized format with conditional expressions using %? constructs, but these do not support loops or recursive evaluation, restricting complexity to linear if-then-else chains. Padding delays, specified within <...> brackets in milliseconds, are further limited by suffixes like * for proportional timing or / for mandatory execution, and are suppressed under certain conditions such as baud rates below a threshold or when xon_xoff flow control is enabled. These rules prevent infinite computations and ensure predictable timing in terminal output.[5][6]
Portability challenges stem from vendor-specific handling of undefined capabilities, as X/Open only mandates support for a core set (33 booleans, 33 numerics, and 508 strings), allowing extensions that vary across implementations. Additionally, the absence of built-in versioning in the terminfo format means entries lack metadata to indicate compatibility levels, potentially leading to mismatches when sharing databases across systems. The specification dates to 1997 and has not been updated, with modern terminfo usage depending on implementation-specific extensions.[5][6]
Several aspects of these limits are outdated in modern contexts. The 14-character alias restriction, tied to legacy filesystems like those in early UNIX variants, is irrelevant on post-1990s systems with support for longer filenames up to 255 characters or more. Furthermore, terminfo lacks native support for Unicode metadata, with source files restricted to the ISO 8859-1 codeset and unspecified behavior for other encodings, limiting its applicability to internationalized terminals without extensions.[5][6]
Vendor-Specific Extensions
Ncurses, a widely used open-source implementation of the curses library, introduces several extensions to the terminfo database to address limitations in the standard format, particularly for handling larger entries and modern terminal features. One key enhancement allows terminfo entries to exceed the traditional 4KB size limit by supporting long capability names and extended string tables, enabled through a proprietary "master" format that ncurses compiles into standard format using the tic compiler.[34] This format permits detailed descriptions for complex terminals, such as extended function keys beyond the standard 60, while maintaining compatibility with older systems by truncating at the header-specified size.[34]
Ncurses also supports user-defined capabilities since version 5.0 (1999), allowing developers to add custom Boolean, numeric, or string entries for terminal-specific behaviors not covered by the SVr4/X/Open standards.[35] These are compiled and retrieved using the -x flag with tic and infocmp, ensuring they are stored only if the capability name avoids predefined ones; examples include AX (asserts SGR 39/49 for default colors), E3 (clears scrollback buffer), RGB (indicates direct color support with bit depths for red, green, and blue), and U8 (enables UTF-8 encoding for line-drawing characters in locales using UTF-8).[35] Additionally, ncurses extends wide-character support through UTF-8 string capabilities and mouse tracking via entries like kmous (for basic mouse reporting) or XM (overrides mouse mode), accommodating SGR-style protocols in terminals like xterm.[2]
Xterm, a popular terminal emulator maintained alongside ncurses, includes terminfo entries that extend color support and dynamic features. The xterm-256color entry adds capabilities for 256-color mode, building on ANSI standards with escape sequences for the full palette.[36] For truecolor, the RGB capability—introduced in ncurses 6.1—enables 24-bit direct color specification, as seen in entries like xterm-direct, which reports RGB bit depths for precise color rendering without palette limitations.[36] Xterm also supports dynamic resizing through capabilities like resize and extended mouse tracking (e.g., modes 1000-1006 via xterm+sm+1006), allowing applications to adapt to window changes and capture precise events.[2]
Other vendors have contributed terminfo extensions tailored to their environments. In Solaris and SVR4 systems, the Extended Terminal Interface (ETI) builds on terminfo by providing additional library routines for advanced screen manipulation, such as enhanced color and attribute handling, integrated with the standard database for compatibility.[37] For Linux consoles, terminfo entries like linux-basic include extensions for framebuffer support, enabling capabilities for Unicode rendering (e.g., UTF-8 via U8#1) and console-specific modes like bold and dim attributes on framebuffer devices.[2][38]
These extensions maintain backward compatibility with the standard terminfo format; the -x flag in tic and infocmp explicitly enables user-defined features without affecting standard entries, allowing mixed use in portable applications.[35] In 2025, ncurses version 6.5 continues to evolve with patches supporting new terminals such as modern emulators with direct framebuffer access.[8]