TeX 的輸入/輸出原語

TeX 的輸入/輸出原語

我想編寫一些簡單的巨集來處理交叉引用之類的事情,以便在純 TeX 中使用它們。 (我知道已經有專門用於此目的的宏,例如 Eplain 中的宏,但我想自己嘗試不同的東西。)所以我需要知道如何從文件中讀取以及如何寫入文件。執行此類操作的 TeX 原語是什麼?它們如何運作?

另一個問題:TeX 運行時可以「呼叫」其他程式嗎?我的意思是:TeX 中是否存在與 C 語言中的系統函數等效的函數?

答案1

TeX 具有用於讀取和寫入檔案的\read\write原語,當然還有\input用於「此處」輸入整個檔案的原語。例如,如果您查看 LaTeX 交叉引用機制,請使用\write但避免使用\read(逐行),而有利於使用\input適當設計的輔助文件。

由於\input很容易理解,讓我們重點關注\read\write。這兩者都在文件流上工作,文件流有一個編號,但通常使用\new....例如

\newread\myread
\openin\myread=myinput %

\newwrite\mywrite
\immediate\openout\mywrite=myoutput %

將設定一個名為 的讀取\myread和一個名為 的寫入\mywrite。請注意,我使用了\immediate\write由於 TeX 頁面建立器的非同步特性,您需要確保\write操作發生在「正確」的位置。 (下面有更多相關內容。)

打開兩個流後,我們可以寫入輸出。如果我們進行兩次寫入,一次“立即”,一次“延遲”

\def\foo{a}
\immediate\write\mywrite{\foo}
\write\mywrite{\foo}
\def\foo{b}
Hello
\bye

結果正在myoutput.tex閱讀

a
b

這是因為\write\mywrite產生的 Whatsit 僅在頁面發出時執行。例如,如果您需要編寫的內容包含頁碼,那麼這很有用,因為只有在輸出階段才知道頁碼。另請注意,其\write行為如下\edef:除非您使用\noexpand或阻止它,否則所有內容都會擴展toks。但請注意,此擴充功能是在實際執行操作時執行的\write,因此在使用延遲的時必須確保巨集具有正確的定義\write

\read語一次讀取一行(除非大括號不匹配)並以正常的 TeX 方式標記化。您可以使用\ifeofon 的測試安排一次一行地循環文件,但正如我所說,簡單地包含交叉引用的文件\myread通常更容易。\input

如果你想做一個系統調用,「純」TeX 並沒有真正的幫助。然而,Web2c 長期以來一直有一個特殊的「流」來允許逃逸到系統:\write18.這是一個安全風險,因此作為標準,在這種轉義中只允許使用一組有限的命令。例如你可以這樣做

pdftex --shell-escape myfile

允許所有逃逸:如果您自己編寫了所有程式碼,那麼風險就只是造成混亂!執行 a\write18不會向 TeX 回饋任何內容:您需要安排以某種方式讀取結果,可能\read在輔助文件上使用。

正如評論中所指出的,可用的附加語法擴展是\input|"<command>".這再次受到限制,\write18但確實提供了一種可擴展的方法來從 shell 命令獲取輸入。

答案2

透過外部文件處理交叉引用時的另一個特殊問題是讀取、開啟、寫入和關閉該文件的順序。基本方案是:

\newwrite\fileout  % allocations of the file number

\def...     ... all macros which can be used in the file must be defined
\input file ... input only when file exists (the file doesn't exist at the first run)
            ... this input stores the data from file into internal macros
\immediate\openout\fileout=file  ... this removes the data from file
                                  ... the file has zero length now

... document ... macros used in the document write (typically not immediately) 
                 data to the file

\end ... this closes the file automatically, 
         but if you need to use the data from the file at the end of the document
         (for example the TOC at the end of the document):
\vfil\eject  
\immediate\closeout\fileout
\input file ... this creates the TOC at the end of the file.
\end

上面的方案表明,您需要建立一個宏,\input並且僅當該檔案存在時才讀取該檔案。您可以使用以下\softinput巨集來實現此類目的:

\newread\testin
\def\softinput #1 {\let\next=\relax \openin\testin=#1
   \ifeof\testin \message{Warning: the file #1 does not exist}%
   \else \closein\testin \def\next{\input #1 }\fi
   \next}

相關內容