在阅读有关允许钩宏到某些事件时,我遇到了这个命令,\shipout
。在互联网上搜索并没有太大帮助,但如果我没错的话,它与创建新页面有某种关系(或者是吗?)。
我的问题是,它到底是什么\shipout
,它做什么以及它是如何做到的?(即在后台低层发生了什么)
答案1
这很简单:\shipout
是一个原语。它的语法是
\shipout ⟨盒子⟩
其中 ⟨box⟩ 在 TeXbook 第 278 页有完整说明:
⟨盒子⟩ →
\box
⟨8 位数⟩ |\copy
⟨8 位数⟩
|\lastbox
|\vsplit
⟨8 位数⟩to
⟨dimen⟩
| ⟨盒子规范⟩ ⟨横模式材质⟩ | ⟨盒子规范⟩ ⟨竖模式材质⟩ |\hbox
⟨盒子规范⟩ ⟨竖 模式材质⟩ ⟨盒子规范⟩ → ⟨dimen⟩⟨填充物⟩ | ⟨dimen⟩⟨填充物⟩ | ⟨填充物⟩{
}
\vbox
{
}
\vtop
{
}
to
spread
例如,可以说
\shipout\hbox{Hello world}
并将在 DVI 或 PDF 文件中创建一页。当然没有人想使用\shipout
这种方式。它的主要用途是在输出例程中,当 TeX 决定它有足够的材料来弹出整页时调用该例程。当前主垂直列表在所选分页符处被分割,其内容被打包到 中\box255
,输出例程可以对其采取行动。例如,Plain TeX 输出例程会
\shipout\vbox{
\makeheadline
\pagebody
\makefootline
}
\advancepageno
\ifnum\outputpenalty>-\@MM
\else
\dosupereject
\fi
因此,将输出带有页眉和页脚的整页。 的内容\box255
由 修改\pagebody
。 LaTeX 中的输出程序要复杂得多。
我们可以做的是重新定义,\shipout
以便它能完成其他工作。最古老的宏集可以完成这样的工作quire.tex
(在 CTAN 和 TeX Live 上仍然可用)
\def\q_init
{\global\q_sheetnr=0\global\q_qnr=0
\global\let\q_oldship=\shipout
\global\let\shipout=\q_boat
\xdef\q_cycles{\the\deadcycles}%
\global\let\endquire=\q_endquire
}
\shipout
它保存命令中的 的原始含义\q_oldship
(宏用作_
“私有”标记)并将其重新定义为\q_boat
,这将执行一些工作并最终调用\q_oldship
。例如,它可以设置为在同一物理页面上放置两个输出页面,或者制作 16 页查询(包名称由此而来)。
该包也atbegshi
做了类似的事情。它重新定义\shipout
,以便能够挂接在调用\shipout
和实际页面输出之间。
该原语\shipout
所做的就是将输入的垂直列表转换为低级打印指令(根据\pdfoutput
是否使用pdftex
或的值,使用 DVI 或 PDF 格式;如果使用 XDV,则仅使用 Knuth TeX 的 DVI)。同时,它执行所有延迟操作,并在执行过程中扩展标记:这样,对页码的引用就可以保证正确,因为它们是在页面被发送时计算出来的。luatex
xetex
\write
答案2
从电子书,第 23 章:输出例程,第 254 页:
TeX 的原始命令
\shipout
<box> 才是真正导致输出的命令。它将盒子的内容发送到文件dvi
,这是 TeX 的主要输出文件;在 TeX 完成后,dvi
文件将包含一个紧凑的设备无关的指令编码,这些指令精确指定了应该打印什么。当一个盒子被运出时,TeX 会在终端上显示 到 的值,如第 15 章所述;这十个计数器也记录在文件中\count0
,可以用来识别页面。所有出现在盒子内的、和命令都会按照盒子被运出的自然顺序执行。由于命令会扩展宏,如第 21 章所述,TeX 的扫描机制可能会在正在进行时检测到语法错误。如果在 时非零,则正在运出的盒子的内容将以符号形式写入你的日志文件。你可以在任何地方说,而不仅仅是在输出例程中。\count9
dvi
\openout
\closeout
\write
\write
\shipout
\tracingoutput
\shipout
\shipout