terminfo 参数化字符串中的“%l”编码

`%l` encoding in terminfo parameterized strings

我正在用 C++ 为参数化字符串(用于指定终端的某些终端功能)实现解析器。然后我在 terminfo 的 man page 上遇到了这个 % encoding

                                 %l   push strlen(pop)

所以,我的问题是,每当我们将任何东西压入堆栈时,都会遇到以下 % encodings

%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)

并且每当遇到这些并计算它们的结果并且当结果将要被压入堆栈时,然后一个整数(包括布尔结果的 0 或 1)或一个字符将被压入堆栈 ,那么 %l encoding 是指以下任何一项还是 none:

所以,我的问题是 %l push strlen(pop) 是什么意思,它指的是哪个长度?

奖金问题:在 terminfo 的参数化字符串(在上面提到的第二个要点中)的情况下,弹出字符串的方法是否正确?

编辑:正如 Thomas Dickey 所指出的,现在我指的是 this man page of terminfo

尽管页面标题为 "Linux Manpages Online",但参考的手册页是 Solaris (SVr4),已被X/Open诅咒。两者都没有提供必要的细节; ncurses的解释填写详情:

  • SVr4(和 X/Open,在没有增加清晰度的情况下重复了该信息)说 tparm 的参数是 "long"。但是一些参数必须是字符串(即 char*),以支持标签功能。
  • 在首次记录 tparm 时,long 似乎大到足以容纳一个指针(即 char*、一个 字符串 ), <stdarg.h> 不是常见的做法。关于 "big enough" 的假设不一定正确(请参阅 20-year-old 64-Bit Programming Models: Why LP64? 中的讨论),但这是对 tparm.
  • 的假设
  • 对于您最感兴趣的平台,假设您有 LP64(或 LP32)。
  • 当您调用 tparm 时,ncurses 会分析功能字符串以确定特定参数是否将被解释为字符串(是否匹配 %l%s ),并且每当使用该参数时,它都会提供字符串。
  • ncurses 使用堆栈进行一系列操作(参考Parameterized Strings in the terminfo manual page)。

实际上,ncurses 在能力字符串上使用了两次遍历:

  1. 在第一遍中(参见 source-code 中的 _nc_tparm_analyze),它遍历字符串以查看哪个参数将被压入堆栈,当它看到 %l%s,将数组 p_is_s[] 中的位置标记为字符串。
  2. 然后在第二遍中,ncurses 使用 _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,如果要求弹出一个 string 给定数字的地方(或者如果堆栈上没有任何内容), ncurses 返回一个空字符串。

所有这些都依赖于对 tparm 的正确调用,因为没有可移植的方法来确定传递给 函数的参数数量,实际上也没有确定它们的参数数量类型。与 printf 不同,编译器没有帮助。但是如果参数列表匹配能力字符串,ncurses 将(可能...)匹配它。 SVr4 curses 不会这样做(参见示例 tparm.c on illumos-gate)。

在给定的示例中,%p1%l

  • ncurses 期望 string 被压入堆栈,例如,使用 %p1(指代能力之后 tparm 的第一个参数字符串)和
  • ncurses 从堆栈中弹出字符串值,
  • 调用 strlen 获取它的长度并且
  • 将该长度(作为数字)压入堆栈。

堆栈上的那个数字可以用于计算,例如

%p1%l%{1}%+

将其加 1(将结果压入堆栈),或者通过 %d,等等

要输出一个字符串和它的长度,同样假设字符串是第一个参数,那么你可以像这样在能力字符串中多次引用它

%p1%l%d:%p1%s

输出字符串的长度、冒号(:)分隔符和字符串本身。 tparm 的 "output" 当然是另一个字符串,打算使用 putptputs 打印,因为它可能嵌入了 padding information (see Output Functions in the terminfo function manual page).

为terminfo定义的操作来自SVr4,它于1988年正式宣布,但实际上花了几年时间才成为现实。没有为字符串连接或子字符串定义操作;应用程序必须自己做这类事情。什么 terminfo does 是参数化数字,并且(不完全是事后的想法)提供在适当的地方插入字符串。