重新定义 \input 本身会导致意外行为

重新定义 \input 本身会导致意外行为

我正在尝试拦截\input某些文件类型的功能调用和分支。但是,我遇到了以下奇怪的错误:

考虑下面给出的 M(n)WE,其中宏\input已经以一种几乎不引人注目且简单的方式重新定义。

\documentclass{scrbook}

\let\oldinput=\input

\RenewDocumentCommand{\input}{ o }{
    \message{*** DEBUG: (#1)}
    \oldinput{#1}
}

\usepackage{tikz}



\begin{document}
Just some random content.
\end{document}

当我尝试加载tikz包时,编译暂停并显示以下错误消息:

pdflatex mwe
...
(/usr/local/texlive/2023/texmf-dist/tex/latex/pgf/utilities/pgfrcs.sty
*** DEBUG: (-NoValue-)

! LaTeX Error: File `-NoValue-.tex' not found.

Type X to quit or <RETURN> to proceed,
or enter new name. (Default extension: tex)

当然,~NoValue~.tex源于xparse参数指定。在以前的版本中,我指定了\RenewDocumentCommand{\input}{m}{...},但错误消息更加不清楚,并要求文件p.tex

此错误与 无关tikz,我可以使用其他各种包来生成此错误,例如lipsum。浏览这些相应的包,我找不到\input没有参数的调用。

因此,有些观点我未能看到和理解:

  1. \input为什么在那些特定实例中没有传递参数?
  2. 为什么它有时会起作用,例如在文档正文中?
  3. 我是否做了一些明显错误的事情(除了连接到核心宏)?
  4. 我该如何尝试进一步调试此问题(但这主要与 1. 再次相关)?

答案1

TeX 按照你的要求执行。根据你的定义,任何指令

\input{file}

将导致

\message{*** DEBUG: (-NoValue-)} \oldinput{-NoValue-} {file}

因为如果没有可选参数,您就会得到这样的结果。

假设我们这样做

\NewDocumentCommand{\foo}{o}{...#1...}

在处理 时\foo,TeX 会测试后面的标记是否为[(跳过空格)。如果是,它会确定存在可选参数,因此它会转到匹配]以捕获参数并用#1其替换。根据规则,如果[后面没有 并且参数以 指定,则将使用o特殊字符串。-NoValue-#1

你想要一个正常的mandatory 参数,但这不是向 中添加动作的最佳方式\input,因为它会破坏其他构造。为什么?因为原始\input原语有点奇怪,因为它必须应对多个操作系统及其特性。原语期望无支架在其后查找文件名扩展标记,直到找到不可扩展且不是字符的东西(宏扩展后)。因此,LaTeX 重新定义\input查找括号,如果找不到,LaTeX 会切换到原始基元。由于(不幸的是)包可能使用\input filename,因此进一步重新定义\input应该可以解决这个问题。

在引擎的最新实现中,原语\input实际上会检查后面的括号,但这是我们无法依赖的行为。

作为一般建议,o论点需要测试代码-NoValue-

\IfNoValueTF{#1}{%
  do something when the optional argument is not present%
}{%
  do something else with #1 when the optional argument is specified%
}

并要小心终点线。

已经有一个内置机制(不过,您需要一个较新版本的 LaTeX)。此机制还处理\input filename

\documentclass{scrbook}

\AddToHook{file/before}{\typeout{*** DEBUG: \CurrentFile}}

\usepackage{tikz}

\begin{document}

Just some random content.

\input{knuth}

\end{document}

但是,您可能希望在加载包后延迟添加 DEBUG 信息,因为您会得到很多关于文件输入的无用信息,例如,通过 TiZ。

\documentclass{scrbook}
\usepackage{tikz}

\AddToHook{file/before}{\typeout{*** DEBUG: \CurrentFile}}

\begin{document}

Just some random content.

\input{knuth}

\end{document}

该文件knuth.tex包含一些文本,对于此类实验很有用。

以下是控制台输出的摘录(Ti 加载的大量文件Z 被省略)

This is pdfTeX, Version 3.141592653-2.6-1.40.25 (TeX Live 2023) (preloaded format=pdflatex)
 restricted \write18 enabled.
entering extended mode
(./marc.tex
LaTeX2e <2023-06-01> patch level 1
L3 programming layer <2023-10-10>
(/usr/local/texlive/2023/texmf-dist/tex/latex/koma-script/scrbook.cls
Document Class: scrbook 2023/07/07 v3.41 KOMA-Script document class (book)
(/usr/local/texlive/2023/texmf-dist/tex/latex/koma-script/scrkbase.sty
(/usr/local/texlive/2023/texmf-dist/tex/latex/koma-script/scrbase.sty
(/usr/local/texlive/2023/texmf-dist/tex/latex/koma-script/scrlfile.sty
(/usr/local/texlive/2023/texmf-dist/tex/latex/koma-script/scrlfile-hook.sty
(/usr/local/texlive/2023/texmf-dist/tex/latex/koma-script/scrlogo.sty)))
(/usr/local/texlive/2023/texmf-dist/tex/latex/graphics/keyval.sty)))
(/usr/local/texlive/2023/texmf-dist/tex/latex/koma-script/tocbasic.sty)
(/usr/local/texlive/2023/texmf-dist/tex/latex/koma-script/scrsize11pt.clo)
(/usr/local/texlive/2023/texmf-dist/tex/latex/koma-script/typearea.sty))
(/usr/local/texlive/2023/texmf-dist/tex/latex/pgf/frontendlayer/tikz.sty
[...omissis...]
(/usr/local/texlive/2023/texmf-dist/tex/generic/pgf/frontendlayer/tikz/librarie
s/tikzlibrarytopaths.code.tex)))
*** DEBUG: l3backend-pdftex.def
(/usr/local/texlive/2023/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def)
(./marc.aux)
*** DEBUG: supp-pdf.mkii
(/usr/local/texlive/2023/texmf-dist/tex/context/base/mkii/supp-pdf.mkii
[Loading MPS to PDF converter (version 2006.09.02).]
)
*** DEBUG: epstopdf-base.sty
(/usr/local/texlive/2023/texmf-dist/tex/latex/epstopdf-pkg/epstopdf-base.sty
*** DEBUG: epstopdf-sys.cfg
(/usr/local/texlive/2023/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg))
*** DEBUG: knuth.tex
(/usr/local/texlive/2023/texmf-dist/tex/context/sample/common/knuth.tex)
[1{/usr/local/texlive/2023/texmf-var/fonts/map/pdftex/updmap/pdftex.map}]
(./marc.aux) )</usr/local/texlive/2023/texmf-dist/fonts/type1/public/amsfonts/c
m/cmr10.pfb>
Output written on marc.pdf (1 page, 19830 bytes).
Transcript written on marc.log.

相关内容