什么是 GNU

作者:Arnold Robbins
groff

本月专栏讨论的是 groff,GNU 版本的 troff。要完整解释 troff,可能需要(并且已经有了!)不止一本书。现在,我们将提供一些历史背景,并概述 groff 是什么,输入通常是什么样的,以及您将如何使用它。

作者:Arnold Robbins

什么是 troff

虽然市面上有很多 WYSIWYG 字处理程序,其中一些功能非常强大,另一些则可用且免费,但许多长期“高级用户”仍然更喜欢像 troff 和 TeX 这样的文本格式化工具,因为它们能提供更好的控制。这些程序的另一个优点是,您可以使用任何文本编辑器编辑输入,即使是通过 2400 波特调制解调器连接的 edvi,或者在不支持 X windows 的笔记本电脑系统上也可以。

nrofftroff 是 Unix 文本格式化工具。它们本质上是双胞胎;每个都接受相同的输入“语言”。区别在于它们产生的输出。 nroff 旨在为具有固定宽度和固定大小字符的设备生成输出,例如终端和行式打印机。 troff 专为照相排字机而设计。 nroff 只是忽略它无法满足的请求。从现在开始,我们将遵循长期以来的惯例,将这两个程序都称为 troff,以简化事情。

troff 是由已故的 Joseph Osanna 在贝尔实验室编写的。它模仿了当时的文本格式化工具,特别是名为 runoff 的一个。(runoff 是由 Jerry Saltzer 为 MIT 的 CTSS 系统编写的,运行在经过修改的 IBM 7094 上,时间大约在 1960 年代中期。)有趣的是,nroff 是先编写的;名称代表“新的 runoff”。后来,当研究小组获得了一台照相排字机时,nroff 得到了增强,以处理新获得的功能,因此 troff 诞生了。在 1980 年代初期,在 Osanna 先生去世后,Brian Kernighan 接管了 troff,对其进行了清理和增强。 troff 语言现在已经冻结。它不会再进一步发展。

troff 的功能

troff 的输入是文本和格式化命令的混合。您可以将其视为“您想说什么”和“您想怎么说”。通常,命令本身位于单独的行上。 troff 能够区分命令和文本,因为命令行以点或句点开头。必须使用特殊的技巧才能使 troff 将以点开头的行视为真正的文本。

troff 中有大量的命令。一些更重要的命令用于以下任务:

  • 填充。这意味着将尽可能多的输入文本单词放在一个输出行上。

  • 调整。这意味着用空格填充行,使两侧的页边距均匀。书籍和杂志文本通常既填充又调整。

  • 字体更改。印刷文本通常使用多种字体。斜体通常用于强调。粗体文本用于强烈强调和标题。 troff 通常至少支持四种字体,并且可以轻松添加其他字体。

  • 尺寸更改。照相排字机使您可以打印不同尺寸的字符。大多数文本都设置为 10 磅字体,其中 1 磅是 1/72 英寸。可以根据需要将文本放大或缩小。例如,脚注通常以比正常文本更小的磅值大小设置。

  • 页边距控制。 troff 为您提供单独的命令来控制纸张上所有四个页边距的大小。这通常通过以下组合完成:

    • - 行长,一行中可以有多少个字符或英寸的文本

    • - 页面偏移,整个行向右移动多远,以及

    • - 缩进,从行首实际放置文本的左侧或右侧的距离。例如,在书中,段落的第一行通常缩进 1/2 英寸。

  • 居中。任意数量的输入行都可以在输出文本中居中。

  • 划线。 troff 可以绘制水平线和垂直线,以及任意曲线。

  • 水平和垂直移动。您可以将文本向上或向下移动任意量。考虑数学公式中的下标和上标,或脚注指示符,它们通常向上半行并以较小的磅值大小显示。

您可以向 troff 源代码添加注释。它们以 \" 开头,并持续到行尾。我们将在示例中使用注释,以帮助解释正在发生的事情。

许多功能既可以作为独立命令完成,也可以使用内联转义序列完成。例如,要更改为粗体字体,您可能会有这样的文本:

        Here is some regular text.
        .ft B  \" now switch to bold
        This is bold.
        .ft    \" switch back to earlier font
        This will be regular again.

您可以使用内联转义序列做同样的事情。对于字体更改,您可以使用 \f 和单个字母字体名称,或 ( 和两个字母字体名称。一个类似的例子是:

        Here is some regular text. \fBThis is bold.\fP This will
        be regular again.

字母 P 是特殊的。它表示使用之前的字体。

troff 提供了两个不错的功能:字符串和数字寄存器。字符串是一些文本的简写。例如,如果您不想一遍又一遍地键入 the Linux Operating System,您可以定义一个字符串 LX,然后在文本中使用该字符串。此功能可以节省大量键入。

        .ds LX the Linux Operating System \" ds means define string
        If you are new to \*(LX, then you should subscribe to
        \fILinux Journal\fP. It covers \*(LX in great detail,
        month after month.

数字寄存器类似于编程语言中的变量。它们可以包含数值。它们也可以以“自动递增”和“自动递减”的方式使用。这意味着每次使用时,值都会增加一或减少一。您为什么需要这样的东西?想想自动编号章节、节和小节,以及图形和脚注。您将拥有一个用于章节编号的寄存器,另一个用于节编号的寄存器,依此类推。对于每个新章节,节寄存器重置为一。对于每个新节,小节寄存器也重置为一,依此类推。

正如您希望开始看到的那样,troff 为您提供了完全控制文档格式所需的所有机制。不幸的是,这通常比您需要的控制更多。使用裸 troff 编写文档虽然是可能的,但可能会非常痛苦。这非常像用汇编语言编程:您拥有完全的控制权,当结果有效时,效果非常好,但是有很多细节需要跟踪,而且可能会很乏味和困难。

为了使普通用户更容易管理细节,troff 允许您定义宏。宏就像编程语言中的子例程。您可以将命令组合在一起以执行更大的任务,并使用宏名称,而不是每次都写出整个命令序列。

考虑开始一个新的段落。您必须执行以下任务:

  • 1. 查看页面上是否至少有两行文本的空间。

  • 2. 在上一个段落后跳过一个空格。

  • 3. 将文本的第一行缩进 1/2 英寸。

您可以一遍又一遍地编写命令来执行此操作。但这 (a) 很乏味,(b) 如果您更改段落的方式,则很难更新。相反,您可以定义一个宏,例如 .P,为您执行此操作。

        .de P   \" DEfine paragraph macro
        .ne 3   \" we NEed at least three lines
        .sp     \" SPace down one line
        .ti .5i \" Temporary Indent .5 inches
        ..      \" end the macro definition

然后,在您的文本中,您只需在要段落的任何位置将 .P 放在单独的一行上。

        .ds LX the Linux Operating System
        .ds LJ \fILinux Journal\fP
        If you are new to \*(LX, then you should subscribe to
        \*(LJ. It covers \*(LX in great detail,
        month after month.
        .P
        And even if you are an experienced user of \*(LX,
        \*(LJ will bring you valuable tips and tricks to keep
        your Linux system up and running.

标准 troff 的一个不太吸引人的功能是,命令、宏、字符串和寄存器名称的长度不能超过两个字符。幸运的是,groff 允许更长的名称,并使用不同的语法来访问它们。事实上,grofftroff 有许多不错的扩展,这使得编写宏包的任务变得容易得多。扩展记录在 gtroff(1) 手册页中。

流行的宏包

有许多流行的 troff 宏包。使用它们就像用 FORTRAN 编程;它比汇编语言好得多,但不如 C 或 Modula-3 那么好。

常见的宏包有:

  • -ms - 手稿宏。起源于 V7,在 Berkeley Unix 上很流行。

  • -man - 手册页宏。

  • -mm - 备忘录宏。非常强大的宏,在 System V 上很流行。

  • -me - Berkeley 技术论文宏。一个丑陋的包。

  • -mdoc - 来自 Berkeley 的新文档宏。

  • -mandoc - 一个动态判断您想要 -man 还是 -mdoc 的包。

如果您有这些宏包,groff 将直接支持它们,特别是使用 -C 兼容模式选项。它也有许多这些包的自己的版本。

-ms-mm 是最方便使用的可移植包。 -mm-ms 具有更多功能,因此更难学习。但从长远来看,努力是值得的,因为您可以做很多事情。

troff 的预处理器

多年来,人们发现宏有所帮助,但即使使用宏包,也有一些事情太难用裸 troff 来完成。开发的方法是编写一种“小语言”来解决特定任务,并将该语言预处理为原始 troff。常见的预处理器有:

  • tbl - 格式化表格

  • eqn - 格式化公式

  • pic - 格式化图片(图表)

  • grap - 格式化图形

例如,这是我参与制作的参考卡中的一部分表格:

        .TS
        tab(~);
        lfB l lfB l.
        abs~absolute value~int~integer part
        acos~arc cosine~log~natural logarithm
        asin~arc sine~sin~sine
        atan~arc tangent~sinh~hyperbolic sine
        cos~cosine~sqrt~square root
        cosh~hyperbolic cosine~tan~tangent
        .TE

我们将逐行解释它。首先,tbl 只查看 .TS(表格开始)和 .TE(表格结束)之间的行。其他一切都保持不变。这使得在与其他预处理器的管道中使用 tbl 变得容易。第一行将制表符设置为 ~。通常,输入中的制表符分隔表格的每一列。对于此表,使用 ~ 可以更轻松地标记列。

然后,对于表格中的每一行数据,您提供一行描述布局信息。 l 表示左对齐,r 表示右对齐,c 表示居中。此表中的所有列都左对齐。第一列和第三列也使用不同的字体 (f)。在这里,它们使用的是粗体字体。

在此示例中,只有一个控制行,因此它应用于所有数据行。对于更复杂的表格,您每行数据都有一行控制行,最后一行控制行应用于任何剩余的数据行。

其他预处理器在功能上类似。 grap 实际上是 pic 的预处理器。

通常,命令在管道中使用:

        grap doc.tr pic  tbl eqn  troff -mm -Tps > doc.ps

实际用法因机器而异;我们将在下面看到如何运行 groff

输出设备

nroff 最初是为终端和行式打印机设计的,这些设备具有固定宽度的字符。 troff 是为 Wang CAT 照相排字机设计的,该排字机最多可以使用四种不同的字体,并且有许多不同的磅值大小。

大约在 1980 年,Brian Kernighan 修改了 troff 以创建 ditroff,即设备无关的 troff。此版本接受了增强的语言,并生成了 ASCII 输出,该输出描述了输出设备应在页面周围进行的移动、字符的大小和位置等等。然后,要添加新的输出设备(激光打印机、照相排字机或其他设备),您需要为设备无关的输出编写一个后处理器,该后处理器将正确驱动您的设备。最近版本的 troff 是设备无关的版本,通常支持 PostScript(TM) 输出。

ditroff 的传奇故事可以在贝尔实验室计算科学技术报告 #97 中找到。您可以通过匿名 ftp 连接到 netlib.att.com 来获取此报告的 PostScript 版本。切换到 /netlib/att/cs/cstr,使用 binary 模式,并检索 97.ps.Z

GNU troff

现在您已经了解了 troff 是什么,我们将讨论 GNU 版本 groff 的具体细节。 groff 是用 C++ 编写的。这有点不寻常;大多数 GNU 程序都是用 C 编写的。要编译它,您需要一个 C++ 编译器。 GNU C++ 编译器 g++ 通常可以轻松完成编译。您将需要 g++ 和 GNU C++ 库 libg++ 才能编译 groff 程序套件。

该套件中的程序包括:

        gtroff - the actual troff clone
        gtbl - the tbl clone
        geqn - the eqn clone
        gpic - the pic clone
        groff - the driver for the other programs

没有 grap 克隆。任何希望编写克隆的人都应联系 gnu@prep.ai.mit.edu

groff 比 Unix troff 有大量的扩展。特别是,groff 支持命令、字符串和寄存器的长名称,并具有许多附加命令。它还具有兼容模式,其中所有扩展都被关闭。当使用为原始 troff 设计的宏包时,偶尔需要这样做。

上面描述的 groff 预处理器不能与原始 troff 一起使用;它们利用了 groff 的扩展。

groff 使用 ditroff 的不同设备的后处理器模型,具有相同的中间格式。默认情况下,groff 生成 PostScript 输出。另一个最有用的输出格式是纯 ASCII。这实际上是 nroff 的提供方式;通过一个 shell 脚本调用 groff -Tascii(即,输出类型 [-T] 是 ASCII)。一个有趣的输出类型是 TeX DVI,它可以在许多不支持 PostScript 的旧激光打印机上使用。 groff 带有两个用于 X windows 的预览器,使用不同密度的字体(75 和 100 dpi)。

groff 附带了许多宏包。它有自己的 -man 宏版本。 -mgs 包是 GNU 版本的 -ms-mgm 是 GNU 版本的 -mm。应优先使用这些包而不是原始包,因为它们也可以利用 groff 扩展。 Berkeley -me-mdoc-mandoc 包本身是可自由分发的,并且包含在 groff 发行版中。

groff 真正出色之处在于它就像 lint 对于您的 troff 文档一样。这些程序检查*所有内容*。 Unix troff 静默忽略的许多事情,groff 会警告您。通常,您的文件中存在细微的错误,groff 将帮助您发现问题。虽然偶尔确实没有问题,但您需要改为使用兼容模式。

不幸的是,groff 发行版中一个主要的不足之处是没有全面的手册。《第十版研究 Unix 程序员手册》详细描述了 troff 及其朋友。 groff 基于此规范。其他信息可以在 groff 附带的手册页中找到。

有关 pic 的信息可以通过匿名 ftp 从上面提到的同一站点和目录中获取,文件名为 116.ps.Z。有关 grap 的描述可以在 114.ps.Z 中找到。

总结

GNU troffgrofftroff 软件套件的一个功能强大且完整的实现。如果您要使用 troff 做任何事情,那么它绝对是您应该获取的版本。它默认生成 PostScript,会发现您文档中的错误,并支持所有流行的宏包。源代码可在 prep.ai.mit.edu/pub/gnu 目录中找到,文件名为 groff-1.09.tar.gz。它也应该在所有 GNU 镜像站点上找到。

社论

时不时地,退后一步,停下来思考您每天与 Linux 一起使用的自由软件,这是一项有价值的练习。 Linux 内核只是其中的一部分。有数百个实用程序,其中大多数是由自由软件基金会工作人员和志愿者制作的。 GNU 通用公共许可证的条款涵盖了这些实用程序和 Linux 内核,它来自 FSF。 Linux 证明了可自由分发的软件可以是可用的,并且具有高质量。如果 Linux 不是免费的,并且如果没有 GNU 实用程序来完善整个图景,Linux 就永远不会发生。

自由软件基金会信息

向为您做了这么多事的组织 FSF “回馈一些东西”,这才是良好的体育精神和公平竞争。您可以通过多种方式直接和间接地帮助进一步推动 FSF 的事业。

如果您是程序员或作家,或两者都是,FSF 有软件*和*文档需要编写。始终欢迎认真的志愿者。

如果您想在经济上帮助支持 FSF,您也可以这样做。您可以从他们那里购买软件和/或文档。 FSF 出售包含其软件的磁带和 CD-ROM。您可能已经拥有大部分软件,但您可能希望拥有随附的印刷文档。 GNU 手册印刷精美且装订精良,而且价格并不昂贵。直接购买软件和手册有助于生产更多高质量的自由软件。

在美国,您可以向 FSF 进行免税捐款。根据美国法律,它被认为是非营利组织。这也有帮助。

间接地,您可以选择从声明将一定比例捐赠给 FSF 的经销商处购买 Linux 发行版。如果您最喜欢的经销商没有这样做,那么请询问他们*为什么*不这样做,并鼓励他们这样做。

考虑您可以做些什么来帮助 FSF,然后去做吧!

Arnold Robbins 是一位专业程序员和半专业作家。自 1987 年以来,他一直在为 GNU 项目做志愿者工作,自 1981 年以来一直在使用 Unix 和类 Unix 系统。

加载 Disqus 评论