术语信息参数化字符串中的"%l"编码



我正在为参数化字符串(用于为终端指定一些终端功能)在C++中实现解析器。然后我在terminfo的手册页上看到了这个% 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意味着以下任何或没有

  • 从堆栈中弹出单个值,然后if a character push 1 onto stackif an integer push #digits_in_that_integer onto the stack.

  • (因为%l是使用strlen在手册页中编写的)从堆栈中弹出一个字符串(弹出字符串:继续弹出直到堆栈为空),然后将弹出字符串的长度推回堆栈。

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

奖励问题:在术语信息的参数化字符串的情况下弹出字符串的方法是否正确(在上面提到的第二个项目符号中)?

编辑:正如Thomas Dickey所指出的,现在我指的是terminfo的这个手册页。

尽管页面标题为"Linux Manpages Online">,但所引用的手册页是 Solaris (SVr4),它已被 X/Open curses 淘汰。 两者都没有提供必要的细节;NCURSES的解释填补了细节:

  • SVr4(和 X/Open,它反刍该信息而不增加清晰度)表示tparm参数是"长"的。 但是一些参数必须是字符串(即char*),以支持标签功能。
  • tparm首次被记录下来的时候,long似乎足够大,可以容纳一个指针(即char*,一个字符串),<stdarg.h>并不常见。 关于"足够大"的假设不一定是正确的(参见20年前的64位编程模型:为什么是LP64?)中的讨论),但这是为tparm做出的假设。
  • 对于您最感兴趣的平台,假设您有 LP64(或 LP32)。
  • 调用tparm时,ncurses 会分析功能字符串以确定特定参数是否要解释为字符串(无论它与%l匹配还是%s匹配),并且每当使用该参数时,它都会提供字符串。
  • ncurses 使用堆栈进行一系列操作(请参阅terminfo手册页中的参数化字符串)。

实际上,ncurses 在功能字符串上使用两次传递:

  1. 在第一次传递中(参见源代码中的_nc_tparm_analyze),它遍历字符串以查看哪个参数将被推送到堆栈上,当它看到%l%s时,将该位置标记为字符串p_is_s[]数组中的位置。
  2. 然后在第二遍中,ncurses 使用_nc_tparm_internal(分别由 varargs 和固定长度的参数列表函数共享tiparmtparm)。 使用该数组,它知道是将零参数处理为数字零还是空字符串。 参考源代码,如果要求弹出一个给定数字的字符串(或者如果堆栈上没有任何东西),ncurses 会传回一个空字符串。

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

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

  • ncurses 期望将字符串推送到堆栈上,例如,使用%p1(引用功能字符串后的第一个参数tparm),以及
  • ncurses 从堆栈中弹出字符串值,
  • 调用strlen以获取其长度和
  • 将该长度(作为数字)推到堆栈上。

堆栈上的该数字可用于计算,例如,

%p1%l%{1}%+

将 1 添加到它(将结果推送到堆栈上),或者通过使用%d格式化数字来使用它(堆栈上没有任何内容),等等。

要输出字符串及其长度,再次假设字符串是第一个参数,那么您可以在功能字符串中多次引用它,如下所示

%p1%l%d:%p1%s

要输出字符串的长度,请使用冒号 (:) 分隔符和字符串本身。tparm的"输出"当然是另一个字符串,旨在使用putptputs打印,因为它可能具有嵌入的填充信息(请参阅 terminfo 函数手册页中的输出函数)。

为 terminfo 定义的操作来自 SVr4,该 SVr4 于 1988 年正式宣布,尽管在实践中它花了几年时间才成为现实。 没有为字符串串联或子字符串定义任何操作;应用程序必须自己做这种事情。 terminfo所做的是参数化数字,并且(不是事后的想法)提供在适当位置插入字符串。

最新更新