I am implementing a parser in C++ for parameterized strings(which are used for specifying some terminal capabilities for a terminal). Then I came across this % encoding
on the man page of terminfo:
%l push strlen(pop)
So, my question is, that whenever we are pushing anything onto the stack, it is when any these following % encodings
are encountered:
%p[1-9] push ith parm
%’c’ push char constant c
%{nn} push decimal constant nn
%l push strlen(pop)
%+ %− %* %/ %m (arithmetic): push(pop integer2 op pop integer1)
%& %| %^ (bit operations): push(pop integer2 op pop integer1)
%= %> %< (logical operations): push(pop integer2 op pop integer1)
%A %O (logical operations): and, or
%! %~ (unary operations): push(op pop)
And whenever these are encountered and their results are computed and when the results are about to be pushed onto the stack, then either an integer(including 0 or 1 for bool results) or a character are going to be pushed onto the stack, then does %l encoding
mean any or none of the following:
pop a single value from the stack and if a character push 1 onto stack
and if an integer push #digits_in_that_integer onto the stack
.
(since %l
is written in manpages using strlen
) pop a string from the stack (to pop a string: keep popping untill the stack is empty), and then push back the length of popped string onto the stack.
So, my question is what does %l push strlen(pop)
mean, which length is it talking about ?
Bonus question: Is the way to pop a string in case of parameterized strings of terminfo (in the 2nd bullet point mentioned above), correct ?
Edit: As pointed by Thomas Dickey, now I am referring to this man page of terminfo.
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:
tparm
are "long". But some of the parameters have to be strings (i.e., char*
), to support the label capabilities.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
.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.terminfo
manual page).Actually, ncurses uses two passes over the capability string:
_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._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
%p1
(to refer to the first parameter of tparm
after the capability string), andstrlen
to get its length andThat 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.