2

我正在 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)意思,它在说什么长度?

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

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

4

1 回答 1

2

尽管页面标题为“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源代码)中,它逐步遍历字符串以查看哪个参数将被压入堆栈,当它看到一个%lor时%s,将数组p_is_s[]中的该位置标记为字符串。
  2. 然后在第二遍中,ncurses 使用_nc_tparm_internal(分别由 varargs- 和一个固定长度的参数列表函数tiparm和共享tparm)。使用数组,它知道是将零参数处理为数字零还是空字符串。参考源代码,如果要求弹出一个给出数字的字符串(或者如果堆栈上没有任何内容),ncurses 会传回一个空字符串。

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

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

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

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

%p1%l%{1}%+

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

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

%p1%l%d:%p1%s

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

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

于 2017-07-29T19:10:47.097 回答