ncurses:Linux 的可移植屏幕处理

作者:Eric S. Raymond

既然您已经足够了解情况,订阅了Linux Journal,您可能已经知道 Linux 包含 Unix 屏幕处理库 curses(3) 的克隆版本。您可能也知道,Linux 的 ncurses(3) 像其前辈一样,是一个通用的屏幕处理库,支持所有流行的异步终端类型,包括大多数 Linux 控制台的彩色 ANSI 和 vt100 类似的功能。您肯定运行过使用 curses 的程序,例如 vi,或者许多面向屏幕的游戏中的任何一个。

您可能不知道实际上 curses 有两种主要的风格,它们的差异对于可移植性非常重要。您可能也不知道(除非您预先阅读过),1.9 版本之后的 ncurses 版本包含引人注目的新功能,这些功能将使其比其前身更可靠、更强大和更有用。

curses 历史

第一个 curses 库大约在 1980 年在加州大学伯克利分校被拼凑起来,以支持一个名为 rogue 的面向屏幕的地下城游戏。它利用了一个早期的工具,称为 termcap,即终端功能库,它在 vi 编辑器和其他地方被使用。

Termcap 由一个简单的文本数据库格式组成,用于描述串行终端的控制序列和功能。在 ANSI 标准之前,市场上竞争着数百种互不兼容的终端类型;termcap 以标准方式描述了它们,这使得 vi 的屏幕绘制代码能够独立于终端。

curses 库更进一步,定义了一个相对清晰的 C API(应用程序编程接口),以隐藏基于 termcap 的屏幕绘制的细节。这个工具非常成功,几乎完全归功于将 Unix 从其早期在 ASR-33 电传打字机上继承的面向行的界面风格中解放出来。

增强功能和争议

curses 的成功并没有被贝尔实验室忽视。后来的 System III 版本和 System V Release 1 包含了一个增强的 curses 库,具有许多新功能。这些功能包括:

  • 支持多个屏幕高亮显示(BSD curses 只能处理一个“突出”高亮显示,通常是反相视频)。

  • 支持使用表单字符进行线条和方框绘制。

  • 识别输入的功能键。

  • 颜色支持(在后来的版本中)。

  • 完全支持子窗口。

  • 支持 pads(大于屏幕尺寸的窗口,屏幕或子窗口在其中定义视口)。

贝尔实验室的 curses 与 BSD curses 向上兼容,并且功能更强大。然而,其设计者做了一个有争议的重大改变;他们放弃了用于终端功能描述的全文本 termcap 格式,转而选择了一种名为 terminfo 的二进制格式。

更改格式的最重要原因是 BSD termcap 数据库变得如此之大,以至于顺序搜索花费了大量的开销。相比之下,terminfo 格式(二进制功能块位于树状目录结构中)针对快速查找和快速加载进行了优化。

然而,在更改为二进制格式时,贝尔实验室的 curses 放弃了两个有价值的功能:可扩展性以及使用标准文本工具编辑终端描述的能力。termcap 例程实际上从不在意功能对使用它们的程序意味着什么,无论是 curses 还是其他东西。因此,很容易添加新的功能和新的解释;事实上,后来的 BSD 版本将相同的代码用于打印机和调制解调器功能数据库。相比之下,在 terminfo 中,对数据库格式的添加需要重新编译库。

AT&T 的无源代码政策意味着贝尔实验室的 curses 本身从未有机会在黑客社区中胜过 BSD 版本。更糟糕的是,terminfo 格式的权衡意味着主要以 BSD 为中心的黑客文化有一个说得过去的借口来贬低贝尔实验室 curses 中的主要新功能。

因此,在五年多的时间里,编写面向屏幕的程序的自由软件作者一直处于令人烦恼的境地,即使在支持贝尔实验室 curses 的机器上,也不得不围绕较旧、功能较弱的 BSD 接口进行设计。

源代码自由

大约在 1982 年,著名的黑客 Pavel Curtis(前 Xerox PARC 员工,现在可能因其 MOO 项目而闻名)正面解决了这个问题,开始着手开发贝尔实验室 curses 的自由软件克隆版本。这个软件包是 Pavel 个人工具包的一部分;它没有被广泛分发,甚至不太为人所知,直到 Zeyd Ben-Halim,zmbenhal@netcom.com,在 1991 年末接手了开发工作。我在 1993 年末参与进来,以支持我正在开发的面向屏幕的多用户 Unix BBS。

早期的 ncurses 版本有一些严重的缺点。最大的问题是,许多重要的贝尔实验室 curses 功能缺失,在 API 中留下了令人恼火和不可预测的空白。文档很差,不适合在线浏览。针对贝尔实验室 curses 几乎没有进行系统的兼容性测试。最后但并非最不重要的是,所有 1.8.5 版本之前的版本都有严重的错误。

质量改进

在过去一年中,在 Linux 社区的视野之外,发生了很大的变化。我们修复了许多错误,并完善了 API。我们编写了更完整的文档,包括 man 页面。我们针对 SVR4 进行了广泛的兼容性测试,将相同的程序链接到两个库并比较行为。我们仔细审核了代码的跨平台可移植性,并将相当笨拙的自制配置系统替换为 GNU autoconf。我们使用 Purify 测试了代码的内存泄漏,并改进了许多关键函数中的参数验证。代码的整体质量得到了显着提高。

我们还添加了旧版本 ncurses 中缺少的几个类似贝尔实验室的实用程序,包括:

  • infocmp(1) 一个 terminfo 条目列表器和比较器。

  • captoinfo(1) 一个 termcap 到 terminfo 的转换器。

  • clear(1) 一个简单的屏幕清除器。

  • tput(1) 用于 shell 脚本的 terminfo 功能访问。

captoinfo、clear 和 tput 实用程序基于 Ross Ridge 的 mytinfo 软件包(我们已有效地包含在内)的代码。

我们选择 System V Release 4.0 curses 作为我们的模拟目标,现在支持其所有非常广泛的功能。我们还包括 SVR4 面板库的克隆版本,这是一个 curses 扩展,可以轻松地对具有后备存储的窗口堆栈进行编程。

新的 ncurses 软件包还包括一套完整且最新的 man 页面,其组织方式与 SVR4 的类似。

在少数几个方面,我们超越了 SVR4 curses,例如:

  • 新的光标移动优化器和增量屏幕更新算法比贝尔实验室版本更智能(并且比 BSD 版本 智能),从而显着提高了慢速终端的更新速度。

  • 与以前的 curses 版本不同,ncurses 可以写入具有自动换行功能的终端的右下角单元格(前提是它具有插入字符功能)。

  • 在 Intel 机器上,curses 允许您不仅显示 IBM 高半区字符,还可以显示字符 0-31 中的 ROM 图形。

  • 我们的 terminfo 工具识别 GNU termcap、mytinfo 和滑铁卢大学库中找到的所有 terminfo 和 termcap 扩展。

  • 我们提供了一个从 libg++ CursesWindow 类派生的 C++ 类,但针对 ncurses 进行了增强。

  • ncurses 套件现在包含一个 ncurses 程序,它允许您在任何新平台上显式测试 ncurses 的大多数功能。

  • 我们改进了跟踪功能。现在可以从多个级别的输出跟踪中选择一个,并且跟踪日志更容易解释(使用屏幕属性、颜色等的符号转储)。

  • 对于没有 terminfo 树的系统,可以编译自动回退到 /etc/termcap 文件。此功能既不快速也不便宜,因此除非您必须使用它,否则您不会想使用它。

与 ncurses 一起,您将获得一个非常完整的 terminfo 文件。我于 1995 年 1 月从 John Kunze 手中接过了 4.4BSD 主 termcap 文件的维护者接力棒;此后,我将其翻译成 terminfo,并从 SCO、数字设备公司和 Wyse 等供应商处添加了大量信息。(terminfo 文件可从我的 WWW 主页单独获得,www.ccil.org/~esr/home.html。)

我如何使用 ncurses?

列表 1 给出了一个程序框架,说明了如何设置以使用一些新功能。

请注意我们安排 endwin() 由信号捕获器调用的方式。这是必要的,否则,一个意外的信号可能会使 tty 模式处于不太有用的状态。

我们的下一个程序片段说明了键盘映射功能的使用。此代码来自 ncurses 附带的实际测试程序,如 列表 2 所示。

示例代码说明了如何从 getch() 中获取超出 ASCII 范围的功能键令牌作为单个值。调用 keypad(stdscr, TRUE) 可以设置此功能。

ncurses 发行版包含 HTML 格式的更详细的教程,并且在 test 目录中还有几个代码示例。

ncurses 的未来

ncurses 库似乎在 1.9.1 和 1.9.2 版本中达到了适合生产使用的稳定平台。我们正在展望一些有趣的可能性——最值得注意的是支持 XPG4 Curses 扩展级功能,用于宽字符和多字节字符集。我们也在考虑 MS-DOS 和 MS-Windows 端口。

有了我们已经在自由软件库中拥有的功能,您可能想知道 BSD curses 是否有充分的理由继续存在。答案是“可能没有”。

BSD curses 的维护者 Keith Bostic 同意,如果 ncurses 1.9 被证明是稳定且可与 nvi(新 vi)一起使用的,他将切换到 ncurses 用于 nvi 发行版,并宣布 BSD curses 正式死亡。ncurses 库已被成功用于支持生产中的 nvi,因此很有可能在您阅读本文时,Keith 将完成他的测试——BSD curses 将成为历史。

反过来,这意味着 Unix 世界最终将获得一个通用的自由软件 API,该 API 支持颜色、多重高亮显示以及 PC 控制台和当今字符单元终端通用的所有其他功能。

更新

自从这篇文章撰写以来,Keith Bostic 使用 nvi 测试了 ncurses,并正式宣布旧的 BSD curses 死亡。这意味着 ncurses 将成为 Linux 以及所有无数 BSD Unix 自由版本的官方标准 curses。

Eric S. Raymondesr@snark.thyrsus.com,是 Jargon File 的志愿者编辑,一位多产的自由软件和 FAQ 作者,以及最近 Linux 的皈依者。他的 WWW 主页可在 www.ccil.org/~esr/home.html 上找到。

加载 Disqus 评论