Convert a Termcap File to Terminfo Safely with captoinfo
captoinfo turns a legacy termcap file into readable terminfo source without touching the original. The examples use the captoinfo command found on this machine, which reports ncurses 6.6.20251230.
The route
Jump straight to the step you need, or tick off Done means at the end.
The Debian package record for ncurses-bin is 6.4+20240113-1ubuntu2.2, but this shell resolves captoinfo to the Homebrew ncurses binary, so check your own path before trusting version-specific output. Allow about ten minutes. You need a readable termcap text file and a shell. The conversion writes terminfo source to standard output; it does not install a compiled database unless you separately run tic. Ordinary conversion and checking do not need sudo.
1. Check the binary and its version
Start with two read-only checks. They confirm which implementation will process the file, which makes later troubleshooting less ambiguous:
$ command -v captoinfo
/home/linuxbrew/.linuxbrew/bin/captoinfo
$ captoinfo -V
ncurses 6.6.20251230
Your path and version may differ. captoinfo is implemented as a link to tic, with input translated to terminfo format, so the diagnostics and defaults you get belong to the ncurses build you are actually running, not necessarily the distribution package you expected.
Checkpoint
If command -v prints an unexpected location, stop and decide whether to adjust PATH or use an absolute path. Do not mix output from two ncurses installations while investigating a conversion.
2. Inspect the input without changing it
A termcap file normally holds one terminal entry per line: an entry starts with one or more names, followed by colon-separated capabilities. Numeric values use #, strings use =, and a tc capability inherits from another entry. The following commands only read the file:
$ test -r /path/to/legacy.termcap && echo readable
readable
$ sed -n '1,12p' /path/to/legacy.termcap
Replace the path with your real file. Do not treat a file copied from an untrusted source as harmless merely because it is text: review the terminal names and capabilities before feeding it into another tool, and keep the original available until the converted output has passed your checks.
3. Convert to a reviewable output file
Write to a new name so a failed conversion cannot truncate a useful result. This translates every entry in the input file and sends terminfo source to the new file:
$ captoinfo /path/to/legacy.termcap > converted.terminfo.new
$ test -s converted.terminfo.new && echo conversion-produced-output
conversion-produced-output
Shell redirection creates or truncates its destination before captoinfo even runs, which is why the example uses .new rather than the final name. If the command errors, retain the original and inspect the diagnostic; remove the incomplete converted.terminfo.new only after checking you do not need it, then rerun with a new output name. No elevated privilege is needed for reading and writing in your own working directory.
Open the new file as text. A small entry should now look like this, though the names and escape sequences depend on your input:
demo|demo terminal,
cols#80, lines#24,
clear=\\E[H\\E[2J, cup=\\E[%%i%%d;%%dH,
Termcap's tc=base becomes terminfo's use=base. That is an inheritance reference, not a copied expansion: the base entry must still be available when the converted source is later validated or compiled.
4. Make long entries easier to review
Use -1 when the default comma-separated layout is hard to scan. It asks the underlying tic translator to put one capability per line:
$ captoinfo -1 /path/to/legacy.termcap > converted.terminfo.new
$ sed -n '1,20p' converted.terminfo.new
demo|demo terminal,
cols#80,
lines#24,
clear=\\E[H\\E[2J,
cup=\\E[%%i%%d;%%dH,
This changes presentation, not the terminal definition. Keep the one-per-line form for a large migration or when comparing changes in version control. If parameterised strings are hard to read, -f formats complex terminfo expressions for readability: it does not repair an invalid expression.
5. Validate inheritance and syntax
Run tic -c against the converted source for validation with no compiled output. Also read-only:
$ tic -c converted.terminfo.new
$ printf 'validation exit: %s\n' "$?"
validation exit: 0
A non-zero status means read the diagnostic before going further. Common causes are malformed capability syntax and a use reference whose target entry is missing. A warning about a legacy or non-standard capability deserves review even on a successful exit, because ncurses may translate, discard or reinterpret compatibility extensions.
If your source deliberately uses inheritance, include the file containing the base entries in the same validation input, or combine everything into one reviewed source file. A successful text conversion is not proof of a complete terminal definition: captoinfo translates references, it does not silently invent missing parents.
6. Review compatibility warnings before installing anything
- Obsolete names get translated. The converter recognises several and maps them to standard terminfo names.
- Some XENIX extensions get composed. Certain box-drawing capabilities can be folded into
acsc. - Some are dropped with a warning. A few double-line capabilities and the old
GGfield are discarded. - AIX extensions map where possible. Ncurses uses a corresponding standard capability when one exists.
- HP-UX
memlandmemuare discarded, with a warning, since ncurses has nowhere to put them.
Do not redirect standard error away on that first conversion. A warning is a prompt to compare old terminal behaviour with the generated entry, not proof the result is safe to deploy: save the diagnostic alongside your review notes for a migration. Only once the output and warnings are understood should you replace .new with the intended filename:
$ mv converted.terminfo.new converted.terminfo
That mv only renames a file in your working directory, and is reversible while the old file remains. Do not overwrite a system terminfo database as part of this guide: compiling or installing an entry is a separate operational change that may affect applications using that terminal name.
7. Understand the no-file default
Running captoinfo with no file does not mean "read standard input". Per the installed manual, it treats TERMCAP as a file name and extracts only the entry named by TERM. If TERMCAP is unset, it reads /etc/termcap. Check those variables explicitly before relying on the shorthand:
$ printf 'TERM=%s\nTERMCAP=%s\n' "$TERM" "${TERMCAP-}"
TERM=xterm-256color
TERMCAP=/path/to/legacy.termcap
$ captoinfo > selected.terminfo.new
For repeatable scripts, pass the input file explicitly. The environment-based form depends on the current terminal and can select a different entry from the one you intended. If you need one terminal from a multi-entry file, filter or prepare a reviewed input file first, then convert that deliberately.
Done means
- Binary and version confirmed. You know the actual
captoinfobinary and ncurses version in play. - Original untouched. The source termcap file remains as it was.
- Output reviewed separately. The conversion produced readable terminfo source in its own file.
- Inheritance understood. Any
tcreference became a resolvedusereference, not a guess. - Validated and read.
tic -caccepted the reviewed source, and its warnings were investigated, not ignored. - Nothing installed by accident. No system database, service or terminal configuration changed.