
Ich möchte einige einfache Makros für die Handhabung von Dingen wie Querverweisen schreiben, um sie in reinem TeX zu verwenden. (Ich weiß, dass es bereits Makros dafür gibt, wie die in Eplain, aber ich möchte selbst etwas anderes ausprobieren.) Ich muss also wissen, wie man aus einer Datei liest und wie man in eine Datei schreibt. Welche TeX-Grundelemente tun solche Dinge? Wie funktionieren sie?
Eine weitere Frage: Kann TeX während der Ausführung andere Programme „aufrufen“? Ich meine: Gibt es in TeX ein Äquivalent zur Systemfunktion, die in der Sprache C vorhanden ist?
Antwort1
TeX verfügt über die \read
und \write
Primitive zum Lesen und Schreiben in Dateien und natürlich auch \input
zum Eingeben einer ganzen Datei „hier“. Wenn Sie sich beispielsweise den Querverweismechanismus von LaTeX ansehen, wird dieser verwendet, \write
vermeidet jedoch die Verwendung \read
(zeilenweise) zugunsten der Verwendung von \input
mit entsprechend gestalteten sekundären Dateien.
Da \input
dies leicht zu verstehen ist, konzentrieren wir uns auf \read
und \write
. Beide arbeiten mit einem Dateistream, der eine Nummer erhält, aber normalerweise mit zugewiesen wird \new...
. Zum Beispiel
\newread\myread
\openin\myread=myinput %
\newwrite\mywrite
\immediate\openout\mywrite=myoutput %
richtet einen Lesevorgang namens \myread
und einen Schreibvorgang namens ein. Beachten Sie, dass ich mit \mywrite
verwendet habe : Aufgrund der asynchronen Natur des TeX-Seitenerstellers müssen Sie sicherstellen, dass die Vorgänge an der „richtigen“ Stelle stattfinden. (Weitere Informationen hierzu finden Sie weiter unten.)\immediate
\write
\write
Mit zwei geöffneten Streams können wir beispielsweise in die Ausgabe schreiben. Wenn wir zwei Schreibvorgänge durchführen, einen „jetzt“ und einen „verzögert“
\def\foo{a}
\immediate\write\mywrite{\foo}
\write\mywrite{\foo}
\def\foo{b}
Hello
\bye
Das Ergebnis myoutput.tex
lautet
a
b
Das liegt daran, dass \write\mywrite
ein Dingsbums erzeugt wird, das nur ausgeführt wird, wenn eine Seite ausgeliefert wird. Das ist beispielsweise nützlich, wenn das, was Sie schreiben müssen, eine Seitenzahl enthält, da diese nur während der Ausgabephase bekannt ist. Beachten Sie auch, dass \write
sich wie verhält \edef
: Alles wird erweitert, sofern Sie es nicht mit \noexpand
oder einem verhindern toks
. Beachten Sie jedoch, dass diese Erweiterung in dem Moment durchgeführt wird \write
, in dem die Operation tatsächlich ausgeführt wird. Daher muss sichergestellt werden, dass Makros bei Verwendung eines verzögerten korrekt definiert sind \write
.
Das \read
Primitiv liest jeweils eine Zeile (sofern keine Klammern übereinstimmen) und tokenisiert auf die normale TeX-Art. Sie können eine Datei zeilenweise durchlaufen lassen, indem Sie den \ifeof
Test auf verwenden \myread
, aber wie ich schon sagte, ist es oft einfacher, einfach \input
eine Datei mit Querverweisen zu verwenden.
Wenn Sie einen Systemaufruf durchführen möchten, hilft Ihnen „reines“ TeX nicht wirklich weiter. Web2c verfügt jedoch schon seit langem über einen speziellen „Stream“, der das Verlassen des Systems ermöglicht: \write18
. Dies stellt ein Sicherheitsrisiko dar, und standardmäßig ist bei einem solchen Verlassen nur eine begrenzte Anzahl von Befehlen zulässig. Sie können beispielsweise
pdftex --shell-escape myfile
um alles entkommen zu lassen: das Risiko, wenn Sie den gesamten Code selbst geschrieben haben, besteht nur darin, dass Sie Fehler machen! Wenn Sie ein ausführen, \write18
wird nichts an TeX zurückgegeben: Sie müssen dafür sorgen, dass das Ergebnis irgendwie gelesen wird, wahrscheinlich mithilfe \read
einer sekundären Datei.
Wie in einem Kommentar erwähnt, ist eine zusätzliche Syntaxerweiterung verfügbar \input|"<command>"
. Diese ist zwar wieder eingeschränkt, \write18
bietet aber eine erweiterbare Methode, um Eingaben von Shell-Befehlen abzurufen.
Antwort2
Eine weitere Besonderheit beim Umgang mit Querverweisen über externe Dateien ist die Reihenfolge des Lesens, Öffnens, Schreibens und Schließens dieser Datei. Das grundlegende Schema ist:
\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
Das obige Schema zeigt, dass Sie ein Makro erstellen müssen, das die Datei \input
nur liest, wenn diese Datei vorhanden ist. Sie können für solche Zwecke das folgende \softinput
Makro verwenden:
\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}