Sie sind hier

Problem mit scrwfile-package und den durch hyperref automatisch erzeugten Bookmarks/Lesezeichen

Hallo!

In Zusammenhang mit dem scrwfile-package und dem hyperref-Package bin ich, was die Bookmarks/Lesezeichen in .pdf-Dateien angeht, auf eine Seltsamkeit gestoßen:

Ich habe spaßeshalber in unten stehendem "Minimalbeispiel, das das Problem zeigt" einen \section-Befehl für eine Abschnittsüberschrift per \addtocontents in eine externe Datei "auslagern" und dann per \@starttoc wieder einlesen lassen.

Ich dachte, das hätte nur den Effekt, dass man einmal öfter compilieren müsste, um die entsprechende Überschrift in den Dokumenttext und ins Inhaltsverzeichnis und als Bookmark/Lesezeichen in die .pdf-Datei zu bekommen, als man hätte compilieren müssen, wenn ich diesen Befehl nicht hätte "auslagern", sondern direkt aus der Hauptdatei heraus hätte verarbeiten lassen.

Wenn ich das "Minimalbeispiel, das das Problem zeigt" unter pdflatex compilieren lasse, ohne scrwfile verwenden zu lassen, ist das auch so ziemlich der einzige leicht wahrnehmbare Effekt. Jedenfalls bekomme ich dann eine .pdf-Datei, bei der die "Ausgelagerte Ueberschrift" in den Bookmarks/Lesezeichen erscheint.

Aber wenn ich das "Minimalbeispiel, das das Problem zeigt" unter pdflatex compilieren lasse, und dabei scrwfile verwenden lasse, dann bekomme ich eine .pdf-Datei, bei der die "Ausgelagerte Ueberschrift" nicht in den Bookmarks/Lesezeichen erscheint.
Nicht mehr ganz so, wie ich es erwartet habe.

Um 20:33 Uhr hatte ich geschrieben:

Im Moment bin ich zwar versucht, alles um mich herum vergessend in einen Zustand der "Coding-Trance" zu fallen und Ursachenforschung zu betreiben, denn ich hätte gerne zusammen mit dem Phänomen auch gleich die Ursache und evtl einen Behebungsvorschlag genannt, aber im Moment erlaubt mein enger Zeitplan mir das nicht.

Sollte mir diesbezüglich niemand zuvorkommen oder niemand bereits zuvorgekommen sein, werde ich mich aber wohl irgendwann wieder melden wenn ich mehr herausgefunden habe.

Soeben, als ich schon im Bettchen lag und einschlummern wollte, bin ich nochmal hochgeschreckt, denn zur Definition des Makros \scrwfile@@starttoc in scrwfile.sty ist mir etwas aufgefallen.

\scrwfile@@starttoc ist wie folgt definiert:

\newcommand*{\scrwfile@@starttoc}[1]{%
  \typeout{Use my own \string\@starttoc\space for #1}%
  \begingroup
    \if@filesw
      \xdef\scrwfile@writefilelist{\scrwfile@writefilelist,#1}%
    \fi
    \@fileswfalse
    \scrwfile@saved@starttoc{#1}%
  \endgroup
}

Da steht also \@filesw auf "false" während die externe Datei durch \scrwfile@saved@starttoc, also das ursprüngliche \@starttoc-Makro, gelesen wird.

Wenn nun diese externe Datei Dinge enthält, die in Abhängigkeit von \@iffilesw eventuell in externe Dateien geschrieben werden sollen -- zB Absatzgliederungsbefehle wie \section, die dank des durch hyperref gepatchten \refstepcounter in Abhängigkeit von \if@filesw Bookmark-Infos ins .out-file schreiben lassen --, dann werden diese Dinge mit Sicherheit nicht geschrieben, denn dank \@fileswfalse ist das unterbunden.

Wie könnte man der Sache begegnen?

Das \@starttoc-Makro des LaTeX-Kerns ist laut \show\@starttoc wie folgt definiert:

\@starttoc=macro:
#1->\begingroup \makeatletter \@input {\jobname .#1}\if@filesw \expandafter \ne
wwrite \csname tf@#1\endcsname \immediate \openout \csname tf@#1\endcsname \job
name .#1\relax \fi \@nobreakfalse \endgroup .

Ich nehme an, \@fileswfalse in \scrwfile@@starttoc dient dazu, das Allozieren des \write-Handle "innerhalb von" \@starttoc, was ja in Abhängigkeit von \if@filesw passiert, zu unterbinden.

Wenn man das obige \scrwfile@@starttoc-Makro ersetzt durch die Zeilen:

  \newcommand{\scrwfile@replace@if@filesw}{}%
  \long\def\scrwfile@replace@if@filesw#1\if@filesw{#1\iffalse}%
  %
  \newcommand*{\scrwfile@@starttoc}[1]{%
    \typeout{Use my own \string\@starttoc\space for #1}%
    \if@filesw
      \xdef\scrwfile@writefilelist{\scrwfile@writefilelist,#1}%
    \fi
    \expandafter\scrwfile@replace@if@filesw\scrwfile@saved@starttoc{#1}%
  }%

, dann funktioniert - zumindest bei mir beim Compilieren des "Minimalbeispiels mit integrierter Änderung" - alles erwartungsgemäß.

Hier das Minimalbeispiel, das das Problem zeigt:
(Je nachdem, ob scrwfile nicht verwendet wird oder verwendet wird, landet die "Ausgelagerte Ueberschrift" in den Bookmarks/Lesezeichen oder landet sie nicht in den Bookmarks/Lesezeichen.)

\documentclass[a4paper]{article}
\usepackage{hyperref}
%\usepackage{scrwfile} 
\begin{document}
\tableofcontents
\section{Nicht ausgelagerte Ueberschrift}
\addtocontents{tst}{\protect\section{Ausgelagerte Ueberschrift}}%
\csname @starttoc\endcsname{tst}%
\end{document}

Hier das Minimalbeispiel mit integrierter Änderung, mit der das Problem behoben scheint:
(Egal ob scrwfile nicht verwendet wird oder verwendet wird, landet die "Ausgelagerte Ueberschrift" immer in den Bookmarks/Lesezeichen.)

\documentclass[a4paper]{article}
\usepackage{scrwfile}
 
\begingroup
\makeatletter
\@firstofone{%
  \endgroup % Den dank \makeatletter geänderten Kategoriecode von
            % @ auf seinen vorigen Wert zurücksetzen.
  \newcommand{\scrwfile@replace@if@filesw}{}%
  \long\def\scrwfile@replace@if@filesw#1\if@filesw{#1\iffalse}%
  %
  \renewcommand*{\scrwfile@@starttoc}[1]{%
    \typeout{Use my own \string\@starttoc\space for #1}%
    \if@filesw
      \xdef\scrwfile@writefilelist{\scrwfile@writefilelist,#1}%
    \fi
    \expandafter\scrwfile@replace@if@filesw\scrwfile@saved@starttoc{#1}%
  }%
}%
 
\usepackage{hyperref}
\begin{document}
\tableofcontents
\section{Nicht ausgelagerte Ueberschrift}
\addtocontents{tst}{\protect\section{Ausgelagerte Ueberschrift}}%
\csname @starttoc\endcsname{tst}%
\end{document}

Mit freundlichem Gruß

Ulrich

Bild von Markus Kohm

Das ist in der Tat ein Problem. Allerdings ist Deine Lösung keine allgemeine Lösung. Tatsächlich hatte ich mir die damals auch schon überlegt und sogar die Verwendung von etoolbox oder xpatch erwogen. Allerdings gibt es sehr viele Pakete, die \@starttoc patchen und dabei teilweise auch Dinge wie

\let\saved@starttoc\@starttoc
\def\@starttoc#1{\typeout{Hilfsdatei `#1' lesen und neu öffnen}%
  \saved@starttoc{#1}}

machen. Solcherart veränderte Definitionen von \@starttoc führen dann mit Deinem Code zu Fehler.

Sowohl das Allozieren des Handles, als auch das Öffnen der Datei anders zu verhindern ist nicht so ganz trivial. Eventuell wäre die bessere Lösung:

\documentclass[a4paper]{article}
 
\makeatletter
\let\saved@starttoc\@starttoc
\def\@starttoc#1{\typeout{Hilfsdatei `#1' lesen und neu öffnen}%
  \saved@starttoc{#1}}
\makeatother
 
\usepackage{scrwfile}
 
\makeatletter
% In scrwfile dann natürlich mit \newcommand statt \renewcommand!
\renewcommand*{\scrwfile@@starttoc}[1]{%
  \typeout{Use my own \string\@starttoc\space for #1}%
  \begingroup
    \if@filesw
      \xdef\scrwfile@writefilelist{\scrwfile@writefilelist,#1}%
    \fi
    \let\scrwfile@saved@input\@input
    \def\@input##1{\let\@input\scrwfile@saved@input\@input{##1}\@fileswfalse}%
    \scrwfile@saved@starttoc{#1}%
  \endgroup
}
\makeatother
 
 
\usepackage{hyperref}
\begin{document}
\tableofcontents
\section{Nicht ausgelagerte Ueberschrift}
\addtocontents{tst}{\protect\section{Ausgelagerte Ueberschrift}}%
\csname @starttoc\endcsname{tst}%
\end{document}

Das funktioniert dann zumindest so lange, solange keiner eine zusätzliche Gruppe für das Lesen der Hilfsdatei einfügt und die Hilfsdatei auch wirklich (als einzige) gelesen wird. Eventuell sollte man sogar einen Schritt weiter gehen und sicherheitshalber \@input gar nicht selbst zurückdefinieren, sondern das dem \endgroup überlassen.

Ich würde es nicht dem \endgroup überlassen, denn dann gilt die Umdefinition des innerhalb von \scrwfile@@starttoc verwendeten \@input-Befehls auch während die durch diesen \@input-Befehl einzulesende Datei eingelesen wird. Wenn diese einzulesende Datei ihrerseits einen nicht in Gruppen verschachtelten \@input-Befehl enthält, um eine weitere Datei einzulesen, steht dank der geltenden Umdefinition spätestens nach dem Einlesen dieser weiteren Datei der @filesw-Schalter in jedem Fall auf false, was innerhalb desjenigen loacal scope, innerhalb dessen \scrwfile@@starttoc das umdefinierte \@input aufgerufen hat, in dem Moment zu Problemen führen könnte, wo dort nach dem Einlesen der besagten weiteren Datei noch andere Dinge in Abhängigkeit von \if@filesw passieren.

In der Hoffnung, dass \@starttoc-Patcher \@starttoc allenfalls so patchen, dass von \@starttoc nach wie vor \@input genau einmal verwendet wird, um die einzulesende Datei einzulesen, könnte man vielleicht ohne eine weitere Gruppe auskommen und statt dessen innerhalb von \scrwfile@@starttoc \@input zurücksetzen.

\documentclass[a4paper]{article}
 
\makeatletter
\let\saved@starttoc\@starttoc
\def\@starttoc#1{\typeout{Hilfsdatei `#1' lesen und neu öffnen}%
  \saved@starttoc{#1}}
\makeatother
 
\usepackage{scrwfile}
 
\makeatletter
% In scrwfile dann natürlich mit \newcommand statt \renewcommand!
\renewcommand*{\scrwfile@@starttoc}[1]{%
  \typeout{Use my own \string\@starttoc\space for #1}%
  \if@filesw
    \xdef\scrwfile@writefilelist{\scrwfile@writefilelist,#1}%
  \fi
  \let\scrwfile@saved@input\@input
  \def\@input##1{\let\@input\scrwfile@saved@input\@input{##1}\@fileswfalse}%
  \scrwfile@saved@starttoc{#1}%
  \let\@input\scrwfile@saved@input
}
\makeatother
 
 
\usepackage{hyperref}
\begin{document}
\tableofcontents
\section{Nicht ausgelagerte Ueberschrift}
\addtocontents{tst}{\protect\section{Ausgelagerte Ueberschrift}}%
\csname @starttoc\endcsname{tst}%
\end{document}

Mit freundlichem Gruß

Ulrich

Comments for "Problem mit scrwfile-package und den durch hyperref automatisch erzeugten Bookmarks/Lesezeichen" abonnieren