Notwithstanding the page title "Linux Manpages Online", the manual page referred to is Solaris (SVr4), which was obsoleted by X/Open Curses. Neither gives the necessary details; ncurses' interpretation fills in the details:
- SVr4 (and X/Open, which regurgitates that information without adding clarity) says that the parameters for
tparm
are "long". But some of the parameters have to be strings (i.e., char*
), to support the label capabilities.
- at the time that
tparm
was first documented, long
seemed big enough to hold a pointer (i.e., char*
, a string), and <stdarg.h>
was not common practice. That assumption about "big enough" isn't necessarily true (see the discussion in the 20-year-old 64-Bit Programming Models: Why LP64?), but it's the assumption made for tparm
.
- for the platforms you're most interested in, assume you have LP64 (or LP32).
- when you call
tparm
, ncurses analyzes the capability string to determine whether a particular parameter is going to be interpreted as a string (whether it matches up with %l
or %s
), and whenever that parameter is used, it provides the string.
- ncurses uses a stack for the series of operations (refer to Parameterized Strings in the
terminfo
manual page).
Actually, ncurses uses two passes over the capability string:
- In the first pass (see
_nc_tparm_analyze
in source-code), it steps through the string to see which parameter would be pushed onto the stack, and when it sees a %l
or %s
, marks that position in an array p_is_s[]
as a string.
- Then in the second pass, ncurses uses
_nc_tparm_internal
(shared by varargs- and a fixed-length argument list functions tiparm
and tparm
, respectively). Using the array, it knows whether to handle a zero-parameter as a numeric zero, or an empty string. Referring to the source-code, if asked to pop a string where a number was given (or if nothing remains on the stack), ncurses passes back an empty string.
All of that relies upon a correct call to tparm
, since there is no portable way to determine the number of parameters passed to a function, nor actually their types. Unlike printf
, there is no help from the compiler. But if the parameter list matches the capability string, ncurses will (probably...) match it. SVr4 curses does not do this (see for example tparm.c
on illumos-gate).
In the given example, %p1%l
- ncurses expects that a string was pushed onto the stack, e.g., using
%p1
(to refer to the first parameter of tparm
after the capability string), and
- ncurses pops the string value off the stack,
- calls
strlen
to get its length and
- pushes that length (as a number) onto the stack.
That number on the stack can be used in a calculation, e.g.,
%p1%l%{1}%+
to add 1 to it (pushing the result onto the stack), or just used (nothing on the stack) by formatting a number with %d
, etc.
To output a string and its length, again suppose the string is the first parameter, then you can refer to it more than once in the capability string like this
%p1%l%d:%p1%s
to output a string's length, a colon (:
) separator and the string itself. The "output" of tparm
is of course another string, intended to be printed using putp
or tputs
because it may have embedded padding information (see Output Functions in the terminfo function manual page).
The operations defined for terminfo came from SVr4, which was officially announced in 1988, though in practice it took several years to become an actuality. There are no operations defined for string concatenation or substrings; applications have to do that sort of thing for themselves. What terminfo does is to parameterize the numbers, and (not quite as an afterthought) provide for inserting strings in appropriate places.