在 web2cTeX (TeX Live) 中我观察到了这种行为:
(在运行以下每个 perl 命令之后:“tex xyz.tex;xdvi xyz.dvi”)
- 每个\r和\n分别产生一行:
perl -e 'print "\\obeylines a\rb\\bye"' > xyz.tex
perl -e 'print "\\obeylines a\nb\\bye"' > xyz.tex
- \r和\n以各种方式组合起来产生两行(因此 - 一个段落),正如预期的那样,除了一种情况:
perl -e 'print "a\r\rb\\bye"' > xyz.tex
perl -e 'print "a\r\nb\\bye"' > xyz.tex # why?
perl -e 'print "a\n\rb\\bye"' > xyz.tex
perl -e 'print "a\n\nb\\bye"' > xyz.tex
--
\r = ASCII '15
\n = ASCII '12
在我看来,底层 C 库(如果与此有关的话)不应该\r\n作为行尾,因为我使用的是 Linux,而不是 Windows。
所以请有人解释一下为什么\r\n不被单独处理。
答案1
使用TeX输入行有三个步骤。
- 使用系统相关程序从文件中读取该行
readln
。 - 行尾标记(如果存在)被删除,其前的空格(如果存在)也被删除,其余部分保存到行缓冲区。
\endlinechar
如果行缓冲区为非负数(^^M
默认情况下为 ASCII 13 别名),则按值附加行缓冲区。请注意^^M
,默认情况下,catcode 为 5,这就是为什么行尾在 TeX 中的行为与行为相同。
系统相关readln
程序在 web2c TeX 文件中实现,src/texk/web2c/lib/eofeoln.c
其中:
void
readln (FILE *f)
{
int c;
while ((c = getc (f)) != '\n' && c != '\r' && c != EOF)
;
if (c == '\r' && (c = getc (f)) != '\n' && c != EOF)
ungetc (c, f);
}
请注意,这里处理特殊情况 CRLF。
答案2
TeX 依靠“更改文件”进行系统相关的调整。这些调整之一是让 TeX 知道操作系统使用什么方法来标记记录的结尾(不太正式地说,是文本文件中的一行)。
不同的操作系统对此有不同的想法:
- CR+LF(例如 MS-DOS)
- CR(例如,Mac OS 10 之前的版本)
- LF(例如,Unix)
- 对于使用固定长度记录的系统,没有任何内容
在 TeX 的最初实现中,这是按字面意思理解的;例如 OzTeX 使用 CR 作为记录终止符,而来自 DOS 系统且未经转换的文件可能会被错误编译,因为某些 DOS 编辑器使用 LF+CR 作为记录终止符。
为了提高不同文件系统之间的可移植性,Web2C 的开发人员决定“记录终止符不可知”。当 TeX 打开文件时,会检查其第一行并确定使用的记录终止符;然后将其更改为 LF 并传递给 TeX 进行进一步处理。
如果你
perl -e 'print "\\obeylines a\rb\r\\input zzz \\bye"' > xyz.tex
perl -e 'print "\\obeylines c\nd\\bye"' > zzz.tex
输出pdftex xyz
将是
A
B
C
D
但的输出也pdftex '\catcode`^^L=12 \input xyz'
不会有所不同(请plain.tex
注意
\catcode`\^^L=\active \outer\def^^L{\par}
因此^^L
将被解释为外部\par
;通过将其 catcode 设置为 12,我们告诉它是可打印的,但即使\n
在中用作记录终止符,也不会出现任何内容zzz.tex
。
因此,人们不必知道文件来自哪个操作系统:输入它就会做“正确的事”。
因此,任何基于 Web2C 的 TeX 发行版在输入相同文件时都会表现相同。
哪个源文件可以做到这一点?我不知道,但我不会阅读完整的资料。