Post by Ekkart Kleinodich habe folgendes Problem: ich schreibe während des LaTeX-Laufs
Informationen in eine Datei (konkret: die Liste der Änderungen) und will
sie wieder einlesen.
Je nach benutzter TeX-Plattform könnte es evtl sein, dass
irgendwelche "TeX-Character-Translation"-Dateien (tcx-files)
nachbearbeitet werden müssen, damit TeX beim Schreiben von
Zeichen in externe Dateien nicht die ^^-Notation verwendet.
(Mehr dazu unter:
http://docs.miktex.org/manual/texfeatures.html)
Du inputenc verwendet wird, vermute ich aber, dass das Problem
eher woanders liegt und irgendwelche aktiven Character beim
unverzögerten Schreiben zur Unzeit expandiert werden.
Um dem abzuhelfen würde ich beim Schreiben der externen Datei
mittels des \addtocontents-\@starttoc-Mechanismus des
LaTeX2e-Kernel über die aux-Datei gehen.
Der Vorteil dabei ist, dass man ab dem zweiten LaTeX-Lauf
während des LaTeX-Laufes jederzeit auf die fragliche Datei
zugreifen kann -- wenn man möchte auch mehrmals, weil sie ja
erst am Ende des jeweiligen LaTeX-Laufes, wenn die während des
LaTeX-Laufes neu geschriebene aux-Datei ausgelesen wird,
gelöscht und neu geschrieben wird.
Der besagte Mechanismus bzw das \addtocontents-Makro arbeitet
übrigens intern mit \***@write, sodass man sich nicht um
Expansionsverhinderung kümmern mus. Allerdings ist es erforderlich,
dass die \output-Routine "ansprimgt", damit das verzögerte Schreiben
auch stattfindet.
Beim Auslesen der Datei kommt es darauf an, wie die geschriebenen
Daten verarbeitet werden sollen:
Für den Fall, dass die Daten alle "auf einen Rutsch" verarbeitet werden
sollen, würde ich einfach den \addtocontents-\@starttoc-Mechanismus
verwenden und Aufrufe für Zeilenverarbeitende Makros wie \testchopline
oder Makros, welche dazu dienen, \testchopline aufzurufen, mit in die
externe Datei schreiben.
Das könnte dann wie folgt aussehen:
\documentclass[11pt, a4paper, ngerman]{article}
\usepackage[ngerman]{babel}
\usepackage[utf8]{inputenc}
\makeatletter
\DeclareRobustCommand\testlineinbox[1]{%
\noindent\fbox{\vtop{\noindent\testchopline#1\\}}%
}%
\@ifdefinable\testchopline{%
\def\testchopline#1;#2\\{%
Erster Teil: #1\\%
Zweiter Teil: #2%
}%
}%
\newcommand\testfileausgabe{\@starttoc{tst}}%
% Es sollte mindestens einmal die \output-Routine laufen
% damit \addtocontents-Einträge auch geschrieben werden:
\AtEndDocument{\clearpage}
\makeatother
\begin{document}
bla bla bla
\addtocontents{tst}{\testlineinbox{Test1;Test2}}
Ausgabe der Datei \jobname.tst:
\testfileausgabe
bla bla bla
\addtocontents{tst}{\testlineinbox{Täst1;Täst2}}
bla bla bla
\end{document}
Sofern das nicht geht, bspw, weil die externen Dateien nicht von
LaTeX stammen und die ausgebende Software keine
LaTeX-Kontrollsequenzen dazuschreiben kann, oder wenn freier
Zugriff auf einzelne Zeilen gegeben sein soll, wird es ein wenig
komplexer weil man auf das Erreichen des Dateiendes hin
übberwachen sollte und per \addtocontents auf jeden Fall ein
Zeilenvorschub in eine Datei geschrieben wird.
Beim Einlesen wird von TeX ein einsamer Zeilenvorschub als leere
Zeile betrachtet, sodass man beim Verarbeiten von Textzeilen
mittels \read immer den Sonderfall einer leeren Textzeile vor
dem Erreichen des Dateiendes im Auge haben sollte.
Ausserdem steht im TeXBook einiges zu dem Integer-Parameter
\endlinechar.
Ich empfehle dringendst, vor dem Lesen mit \read diesem
Parameter einen Nicht-positiven Wert zu geben. Ansonsten hängt
TeX nämlich beim Lesen einer Zeile selbiger noch einen Character
an, dessen charcode dem Wert des \endlinechar-Parameter
entspricht, in der Regel Nummer 13, also Character Nummer 13 =
Return = ^^M, während dieser Character 13 wiederum in der Regel
den catcode 5 (end of line) hat, sodass man nicht weiss, ob man
beim Tokenizen dafür dann ein \par-Token oder ein Space-Token
oder gar kein Token bekommt (und somit auch nicht weiss, wie der
Delimiter eines Makro mit begrenztem Argument für den jeweiligen
Fall grade aussehen müsste), weil das bei catcode-5-Character
davon abhängt, in welchem Zustand (new-line oder mid-line oder
skipping blanks) der Leseapparatus von TeX gerade ist.
Ich würde ich etwas wie folgt versuchen:
\documentclass[11pt, a4paper, ngerman]{article}
\usepackage[ngerman]{babel}
\usepackage[utf8]{inputenc}
\makeatletter
%Hilfsmakros, nicht User-Ebene
\newcommand\@ifnull[3]{%
\romannumeral\iffalse{\fi\expandafter\@secondoftwo\expandafter
{\expandafter{\string#1}\expandafter\@secondoftwo\string}%
\expandafter\@firstoftwo\expandafter{\iffalse}\fi0 #3}{0 #2}%
} %
\newcommand\PassFirstToSecond[2]{#2{#1}}%
% User-Makro zum Lese-Öffnen einer Datei:
% \openfile{<Extension>}
% (Es wird angenommen, dass alle Dateien nach dem Schema
% \jobname.<Extension> benannt sind.)
\newcommand*\openfile[1]{%
\begingroup
\let\***@path\@undefined
\IfFileExists{\jobname.#1}{%
\endgroup
\@ifundefined{inp@#1}{%
\expandafter\newread\csname inp@#1\endcsname%
}{}%
\expandafter\ifeof\csname inp@#1\endcsname
\immediate\openin\csname inp@#1\endcsname\jobname.#1\relax
\else
%Datei kann nicht geöffnet werden weil das \read-handle
%schon für eine bereits geöffnete Datei benutzt wird,
%evtl hier Fehlermeldung einbauen.
\fi
}{\endgroup}%
}%
% User-Makro zum Schliessen einer lesegeöffneten Datei:
% \closefile{<Extension>}
% (Es wird angenommen, dass alle Dateien nach dem Schema
% \jobname.<Extension> benannt sind.)
\newcommand*\closefile[1]{%
\@ifundefined{inp@#1}{}{\immediate\closein\csname inp@#1\endcsname}%
}%
% User-Makro zum Lesen der nächsten Zeile einer lesegeöffneten
% Datei:
% \processfileline{<Extension>}{<Makro>}%
% (Es wird angenommen, dass alle Dateien nach dem Schema
% \jobname.<Extension> benannt sind.)
% Die gelesene Zeile wird als in geschweifte Klammern
% eingefasstes Argument an <Makro> übergeben, sodass sie
% von <Makro> weiterverarbeitet werden kann.
\newcommand*\processfileline[2]{%
\@ifundefined{inp@#1}{}{%
\expandafter\ifeof\csname inp@#1\endcsname
\expandafter\@gobble
\else
\expandafter\@firstofone
\fi
{%
\begingroup
\endlinechar=-1\relax
\immediate\read\csname inp@#1\endcsname to\@***@line
\expandafter\PassFirstToSecond
\expandafter{\@***@line}{\endgroup#2}%
}%
}%
}%
% User-Makro zum Lesen ener bestimmten Zeile einer dafür zum
% Lesen zu öffnenden Datei:
% \processfileline{<Extension>}{<Makro>}{<Zeilennummer>}%
% (Es wird angenommen, dass alle Dateien nach dem Schema
% \jobname.<Extension> benannt sind.)
% Es wird, sofern existent, die <Zeilennummer>-te Zeile
% der Datei \jobname.<Extension> gelesen und als in
% geschweifte Klammern eingefasstes Argument an <Makro>
% übergeben, sodass sie von <Makro> weiterverarbeitet
% werden kann.
\newcommand\ProcessFileLineNumber[3]{%
\ifnum1>#3 %
% evtl Fehlermeldung weil Zeilenangaben größer 0 sein müssen
\expandafter\@gobble
\else
\expandafter\@firstofone
\fi
{%
\begingroup
\let\***@path\@undefined
\IfFileExists{\jobname.#1}{%
\endgroup
\immediate\openin\@inputcheck\jobname.#1\relax
\ProcessFileLineNumberloop{#3}{#1}{#2}%
\immediate\closein\@inputcheck
}{\endgroup}%
}%
}%
\newcommand\ProcessFileLineNumberloop[3]{%
\ifeof\@inputcheck
\expandafter\@gobble
\else
\expandafter\@firstofone
\fi
{%
\begingroup
\endlinechar=-1\relax
\immediate\read\@inputcheck to\@***@line
\ifnum1=#1 %
\expandafter\@firstoftwo
\else
\expandafter\endgroup\expandafter\@secondoftwo
\fi
{%
\expandafter\PassFirstToSecond
\expandafter{\@***@line}{\endgroup#3}%
}{%
\expandafter\ProcessFileLineNumberloop{%
\expandafter\number\numexpr#1-1\relax}{#2}{#3}%
}%
}%
}%
% Spezifisches Makro zum Verarbeiten von Zeilen, die aus
% Dateien mit der Extension ".tst" kommen - #1 beinhaltet
% die gelesene Zeile:
\newcommand\processnextlineoftstfile[1]{%
\@ifnull{#1}{}{%
\testchopline#1\\%
Erster Teil: \first\\%
Zweiter Teil: \second
}%
}%
\@ifdefinable\testchopline{%
\def\testchopline#1;#2\\{%
\def\first{#1}%
\def\second{#2}%
}%
}%
% Es soll nach dem LaTeX-Lauf aus den per \addtocontents
% bewerkstelligten aux-file-Einträgen eine tst-Datei
% erzeugt werden:
\AtEndDocument{%
\begingroup\let\@input\@gobble\@starttoc{tst}\endgroup
}
% Es sollte mindestens einmal die \output-Routine laufen
% damit \addtocontents-Einträge auch geschrieben werden:
\AtEndDocument{\clearpage}
\makeatother
\begin{document}
%Schreibe Zeile 1:
\addtocontents{tst}{Test1;Test2}
\openfile{tst}
Zeile 1:
\fbox{\vtop{\noindent
\processfileline{tst}{\processnextlineoftstfile}%
}}
Zeile 2:
\fbox{\vtop{\noindent
\processfileline{tst}{\processnextlineoftstfile}%
}}
%Schreibe Zeile 2:
\addtocontents{tst}{Täst1;Täst2}
% Das hier produziert eine leere \fbox, weil Zeile 3
% in \jobname.tst nicht existiert:
Zeile 3:
\fbox{\vtop{\noindent
\processfileline{tst}{\processnextlineoftstfile}%
}}
\closefile{tst}
Nochmal Zeile 2:
\fbox{\vtop{\noindent
\ProcessFileLineNumber{tst}{\processnextlineoftstfile}{2}%
}}
Nochmal Zeile 1:
\fbox{\vtop{\noindent
\ProcessFileLineNumber{tst}{\processnextlineoftstfile}{1}%
}}
Nochmal Zeile 3:
\fbox{\vtop{\noindent
\ProcessFileLineNumber{tst}{\processnextlineoftstfile}{3}%
}}
\end{document}
Ulrich