% ====================================================================== % scrlfile.tex % Copyright (c) Markus Kohm, 2001-2019 % % This file is part of the LaTeX2e KOMA-Script bundle. % % This work may be distributed and/or modified under the conditions of % the LaTeX Project Public License, version 1.3c of the license. % The latest version of this license is in % http://www.latex-project.org/lppl.txt % and version 1.3c or later is part of all distributions of LaTeX % version 2005/12/01 or later and of this work. % % This work has the LPPL maintenance status "author-maintained". % % The Current Maintainer and author of this work is Markus Kohm. % % This work consists of all files listed in manifest.txt. % ---------------------------------------------------------------------- % scrlfile.tex % Copyright (c) Markus Kohm, 2001-2019 % % Dieses Werk darf nach den Bedingungen der LaTeX Project Public Lizenz, % Version 1.3c, verteilt und/oder veraendert werden. % Die neuste Version dieser Lizenz ist % http://www.latex-project.org/lppl.txt % und Version 1.3c ist Teil aller Verteilungen von LaTeX % Version 2005/12/01 oder spaeter und dieses Werks. % % Dieses Werk hat den LPPL-Verwaltungs-Status "author-maintained" % (allein durch den Autor verwaltet). % % Der Aktuelle Verwalter und Autor dieses Werkes ist Markus Kohm. % % Dieses Werk besteht aus den in manifest.txt aufgefuehrten Dateien. % ====================================================================== % % Chapter about scrlfile of the KOMA-Script guide % Maintained by Markus Kohm % % ---------------------------------------------------------------------------- % % Kapitel über scrlfile in der KOMA-Script-Anleitung % Verwaltet von Markus Kohm % % ============================================================================ \KOMAProvidesFile{scrlfile.tex}% [$Date: 2019-10-10 10:04:30 +0200 (Thu, 10 Oct 2019) $ KOMA-Script guide (chapter: scrlfile)] \chapter{Paketabhängigkeiten mit \Package{scrlfile} beherrschen} \labelbase{scrlfile} \BeginIndexGroup \BeginIndex{Package}{scrlfile} Die Einführung von \LaTeXe{} brachte 1994 eine Menge Neuerungen im Umgang mit \LaTeX-Erweiterungen. So stehen dem Paketautor heute eine ganze Reihe von Befehlen zur Verfügung, um festzustellen, ob ein anderes Paket oder eine bestimmte Klasse verwendet wird und ob dabei bestimmte Optionen zur Anwendung kommen. Der Paketautor kann selbst andere Pakete laden oder diesen Optionen mit auf den Weg geben für den Fall, dass sie später noch geladen werden. Es bestand daher die Hoffnung, dass es künftig unerheblich wäre, in welcher Reihenfolge Pakete geladen werden. Diese Hoffnung hat sich leider nicht erfüllt. \section{Die Sache mit den Paketabhängigkeiten} \seclabel{dependency} %\begin{Explain} Immer häufiger definieren unterschiedliche Pakete den gleichen Befehl neu oder um. Dabei ist es dann sehr entscheidend, in welcher Reihenfolge die Pakete geladen werden. Manchmal ist das für den Anwender kaum zu überschauen. Teilweise ist es auch notwendig, in irgendeiner Form auf das Laden eines anderen Pakets zu reagieren. Nehmen wir als einfaches Beispiel das Laden des \Package{longtable}-Pakets bei Verwendung von \KOMAScript{}. Das \Package{longtable}-Paket definiert seine eigene Form von Tabellenüberschriften. Diese passen perfekt zu den Standardklassen. Sie passen aber überhaupt nicht zu den Voreinstellungen für die Tabellenüberschriften von \KOMAScript{} und reagieren auch nicht auf die entsprechenden Möglichkeiten der Konfiguration. Um dieses Problem zu lösen, müssen die Befehle von \Package{longtable}, die für die Tabellenüberschriften zuständig sind, von \KOMAScript{} umdefiniert werden. Allerdings sind die \KOMAScript{}-Klassen bereits abgearbeitet, wenn das Paket geladen wird. Bisher bestand die einzige Möglichkeit, dieses Problem zu lösen darin, die Umdefinierung mit Hilfe von \Macro{AtBeginDocument} auf einen späteren Zeitpunkt zu verschieben. Will der Anwender die entsprechende Anweisung jedoch selbst umdefinieren, so sollte er dies eigentlich ebenfalls in der Präambel tun. Das kann er jedoch nicht, weil \KOMAScript{} ihm dabei in die Quere kommt. Er müsste die Umdefinierung also ebenfalls mit Hilfe von \Macro{AtBeginDocument} durchführen. Aber eigentlich müsste \KOMAScript{} die Abarbeitung gar nicht auf den Zeitpunkt von \Macro{begin}\PParameter{document} verschieben. Es würde genügen, wenn sie bis unmittelbar nach dem Laden von \Package{longtable} verzögert werden könnte. Leider fehlen entsprechende Anweisungen im \LaTeX-Kern. Das Paket \Package{scrlfile} bringt hier Abhilfe. Ebenso wäre es denkbar, dass man vor dem Laden eines bestimmten Pakets gerne die Bedeutung eines Makros in einem Hilfsmakro retten und nach dem Laden des Pakets wieder restaurieren will. Auch das geht mit \Package{scrlfile}. Die Anwendung von \Package{scrlfile} ist nicht auf die Abhängigkeit von Paketen beschränkt. Auch Abhängigkeiten von anderen Dateien können berücksichtigt werden. So kann beispielsweise dafür gesorgt werden, dass das nicht unkritische Laden einer Datei wie \File{french.ldf} automatisch zu einer Warnung führt. Obwohl das Paket in erster Linie für andere Paketautoren interessant sein dürfte, gibt es durchaus auch Anwendungen für normale \LaTeX-Benutzer. Deshalb sind in diesem Kapitel auch für beide Gruppen Beispiele aufgeführt. %\end{Explain} \section{Aktionen vor und nach dem Laden} \seclabel{macros} Mit \Package{scrlfile} können vor und nach dem Laden von Dateien Aktionen ausgelöst werden. Bei den dazu verwendeten Befehlen wird zwischen allgemeinen Dateien, Klassen und Paketen unterschieden. \begin{Declaration} \Macro{BeforeFile}\Parameter{Datei}\Parameter{Anweisungen} \Macro{AfterFile}\Parameter{Datei}\Parameter{Anweisungen} \end{Declaration}% Mit Hilfe von \Macro{BeforeFile} kann dafür gesorgt werden, dass die \PName{Anweisungen} vor dem nächsten Laden einer bestimmten \PName{Datei} ausgeführt werden. Vergleichbar arbeitet \Macro{AfterFile}. Nur werden die \PName{Anweisungen} hier erst nach dem Laden der \PName{Datei} ausgeführt. Wird die Datei nie geladen, so werden die \PName{Anweisungen} in beiden Fällen natürlich auch nie ausgeführt. Bei \PName{Datei} sind etwaige Dateiendungen wie bei \Macro{input} als Teil des Dateinamens anzugeben. Um die Funktionalität bereitstellen zu können, bedient sich \Package{scrlfile} der bekannten \LaTeX-Anweisung \Macro{InputIfFileExists}. Diese\textnote{Achtung!} wird hierzu umdefiniert. Falls die Anweisung nicht die erwartete Definition hat, gibt \Package{scrlfile} eine Warnung aus. Dies geschieht für den Fall, dass die Anweisung in späteren \LaTeX-Versionen geändert wird oder bereits von einem anderen Paket umdefiniert wurde. Die Anweisung \Macro{InputIfFileExists} wird von \LaTeX{} immer verwendet, wenn eine Datei geladen werden soll. Dies geschieht unabhängig davon, ob die Datei mit \Macro{LoadClass}, \Macro{documentclass}, \Macro{usepackage}, \Macro{RequirePackage}, \Macro{include} oder vergleichbaren Anweisungen geladen wird. Lediglich % Umbruchkorrektur: listings korrigieren \begin{lstcode} \input foo \end{lstcode} lädt die Datei \texttt{foo} ohne Verwendung von \Macro{InputIfFileExists}. Sie sollten daher stattdessen immer % Umbruchkorrektur: listings korrigieren \begin{lstcode} \input{foo} \end{lstcode} verwenden. Beachten Sie die Klammern um den Dateinamen!% % \EndIndexGroup \begin{Declaration} \Macro{BeforeClass}\Parameter{Klasse}\Parameter{Anweisungen} \Macro{BeforePackage}\Parameter{Paket}\Parameter{Anweisungen} \end{Declaration}% Diese beiden Befehle arbeiten vergleichbar zu \DescRef{\LabelBase.cmd.BeforeFile} mit dem einen Unterschied, dass die \PName{Klasse} beziehungsweise das \PName{Paket} mit seinem Namen und nicht mit seinem Dateinamen angegeben wird. Die Endungen »\File{.cls}« und »\File{.sty}« entfallen hier also.% % \EndIndexGroup \begin{Declaration} \Macro{AfterClass}\Parameter{Klasse}\Parameter{Anweisungen} \Macro{AfterClass*}\Parameter{Klasse}\Parameter{Anweisungen} \Macro{AfterClass+}\Parameter{Klasse}\Parameter{Anweisungen} \Macro{AfterClass!}\Parameter{Klasse}\Parameter{Anweisungen} \Macro{AfterAtEndOfClass}\Parameter{Klasse}\Parameter{Anweisungen} \Macro{AfterPackage}\Parameter{Paket}\Parameter{Anweisungen} \Macro{AfterPackage*}\Parameter{Paket}\Parameter{Anweisungen} \Macro{AfterPackage+}\Parameter{Paket}\Parameter{Anweisungen} \Macro{AfterPackage!}\Parameter{Paket}\Parameter{Anweisungen} \Macro{AfterAtEndOfPackage}\Parameter{Paket}\Parameter{Anweisungen} \end{Declaration}% Die Anweisungen \Macro{AfterClass} und \Macro{AfterPackage} arbeiten weitgehend wie \DescRef{\LabelBase.cmd.AfterFile}, mit dem winzigen Unterschied, dass die \PName{Klasse} beziehungsweise das \PName{Paket} mit seinem Namen und nicht mit seinem Dateinamen angegeben wird. Die Endungen »\File{.cls}« und »\File{.sty}« entfallen hier also. Bei\important[i]{\Macro{AfterClass*}\\\Macro{AfterPackage*}} den Sternvarianten gibt es eine zusätzliche Funktionalität. Wurde oder wird die entsprechende Klasse oder das entsprechende Paket bereits geladen, so werden die \PName{Anweisungen} nicht nach dem nächsten Laden, sondern unmittelbar ausgeführt. Bei\important[i]{\Macro{AfterClass+}\\\Macro{AfterPackage+}} der Plusvariante\ChangedAt{v3.09}{\Package{scrlfile}} werden die \PName{Anweisungen} sicher erst dann ausgeführt, wenn die Klasse oder das Paket vollständig geladen wurde. Der Unterschied zwischen der Stern- und der Plusvariante kommt nur zum Tragen, falls die Anweisung verwendet wird, während das Laden der Klassen bzw. des Pakets zwar bereits begonnen hat, aber noch nicht beendet wurde. Wenn das Laden der Klasse bzw. des Pakets noch nicht abgeschlossen wurde, werden die \PName{Anweisungen} in allen Fällen vor den in der Klasse bzw. dem Paket mit \Macro{AtEndOfClass} oder \Macro{AtEndOfPackage} verzögerten Anweisungen ausgeführt. Um\important[i]{\Macro{AfterClass!}\\\Macro{AfterPackage!}} eine Ausführung nach den in der Klasse oder dem Paket selbst mit \Macro{AtEndOfClass} oder \Macro{AtEndOfPackage} verzögerten Anweisungen sicherzustellen, ist die Variante mit Ausrufezeichen\ChangedAt{v3.09}{\Package{scrlfile}} zu verwenden. Bei dieser Spielart werden die \PName{Anweisungen} nicht mehr im Kontext der angegebenen Klasse oder des angegebenen Pakets ausgeführt. Will\important[i]{\Macro{AfterAtEndOfClass}\\\Macro{AfterAtEndOfPackage}} man nur für den Fall, dass die Klasse bzw. das Paket noch nicht geladen wurde, erreichen, dass \PName{Anweisungen} nach der Klasse bzw. dem Paket und außerhalb des Kontextes der angegebenen Klasse bzw. des angegebenen Pakets ausgeführt werden, so verwendet man für Klassen die Anweisung \Macro{AfterAtEndOfClass}\ChangedAt{v3.09}{\Package{scrlfile}} und für Pakete \Macro{AfterAtEndOfPackage}.% % \begin{Example} Als Beispiel für Paket- oder Klassenautoren will ich zunächst erklären, wie \KOMAScript{} selbst Gebrauch von den neuen Anweisungen macht. Dazu findet sich beispielsweise in \Class{scrbook} Folgendes: \begin{lstcode} \AfterPackage{hyperref}{% \@ifpackagelater{hyperref}{2001/02/19}{}{% \ClassWarningNoLine{scrbook}{% You are using an old version of hyperref package!\MessageBreak% This version has a buggy hack at many drivers\MessageBreak% causing \string\addchap\space to behave strange.\MessageBreak% Please update hyperref to at least version 6.71b}% }% } \end{lstcode} Alte Versionen von \Package{hyperref} definierten ein Makro von \Class{scrbook} in einer Weise um, die mit neueren Versionen von \KOMAScript{} nicht mehr funktioniert. Neuere Versionen von \Package{hyperref} unterlassen dies, wenn sie eine neuere Version von \KOMAScript{} erkennen. Für den Fall, dass \Package{hyperref} zu einem späteren Zeitpunkt geladen wird, sorgt also \Class{scrbook} dafür, dass unmittelbar nach dem Laden des Pakets überprüft wird, ob es sich um eine verträgliche Version handelt. Falls dies nicht der Fall ist, wird eine Warnung ausgegeben. An anderer Stelle findet sich in drei der \KOMAScript-Klassen Folgendes: \begin{lstcode} \AfterPackage{caption2}{% \renewcommand*{\setcapindent}{% \end{lstcode}% }} Nach dem Laden von \Package{caption2} und nur falls das Paket geladen wird, wird hier die \KOMAScript{} eigene Anweisung \DescRef{maincls.cmd.setcapindent} umdefiniert. Der Inhalt der Umdefinierung ist für dieses Beispiel unerheblich. Es sei nur erwähnt, dass \Package{caption2} die Kontrolle über die \DescRef{maincls.cmd.caption}-Anweisung übernimmt und daher die normale Definition von \DescRef{maincls.cmd.setcapindent} keinerlei Wirkung mehr hätte. Die Umdefinierung verbessert dann die Zusammenarbeit mit \Package{caption2}. Es gibt aber auch Beispiele für den sinnvollen Einsatz der neuen Anweisungen durch normale Anwender. Angenommen, Sie erstellen ein Dokument, aus dem sowohl eine PS-Datei mit \LaTeX{} und dvips als auch eine PDF-Datei mit \mbox{pdf\LaTeX} erstellt werden soll. Das Dokument soll außerdem Hyperlinks aufweisen. Im Tabellenverzeichnis haben Sie Einträge, die über mehrere Zeilen gehen. Nun gibt es zwar mit \mbox{pdf\LaTeX} bei der PDF-Ausgabe keine Probleme, da dort Links umbrochen werden können. Bei Verwendung des \Package{hyperref}-Treibers für dvips oder \mbox{hyper\TeX} ist dies jedoch nicht möglich. In diesem Fall hätten Sie gerne, dass bei \Package{hyperref} die Einstellung \Option{linktocpage} verwendet wird. Die Entscheidung, welcher Treiber geladen wird, wird von \Package{hyperref} automatisch getroffen. Alles weitere kann nun \DescRef{\LabelBase.cmd.AfterFile} überlassen werden: \begin{lstcode}[moretexcs={hypersetup}] \documentclass{article} \usepackage[ngerman]{babel} \usepackage{scrlfile} \AfterFile{hdvips.def}{\hypersetup{linktocpage}} \AfterFile{hypertex.def}{\hypersetup{linktocpage}} \usepackage{hyperref} \begin{document} \listoffigures \clearpage \begin{figure} \caption{Dies ist ein Beispiel mit einer Abbildungsunterschrift, die mehrere Zeile umfasst und bei der trotzdem auf die Verwendung des optionalen Arguments verzichtet wurde.} \end{figure} \end{document} \end{lstcode} Egal, ob nun der \Package{hyperref}-Treiber \Option{hypertex} oder \Option{dvips} zu Anwendung kommt, wird die dann nützliche Einstellung \Option{linktocpage} verwendet. Wenn Sie jedoch mit \mbox{pdf\LaTeX} eine PDF-Datei erstellen, wird darauf verzichtet, da dann der \Package{hyperref}-Treiber \File{hpdftex.def} verwendet wird. Das bedeutet, dass weder die Treiberdatei \File{hdvips.def} noch \File{hypertex.def} geladen wird. \end{Example} \iffalse% Umbruchkorrekturtext (der besser nicht mehr verwendet wird!) Übrigens\textnote{Tipp!} können Sie das Laden von \Package{scrlfile} und die obigen Anweisungen \DescRef{\LabelBase.cmd.AfterFile} auch in Ihre private \File{hyperref.cfg} (siehe oben) einfügen. Verwenden Sie dabei jedoch zum Laden des Pakets besser \Macro{RequirePackage} anstelle von \Macro{usepackage} (siehe \cite{latex:clsguide}). Die neuen Zeilen müssen in obigem Beispiel unmittelbar nach der \Macro{ProvidesFile}-Zeile, also unbedingt vor der Ausführung der Optionen \Option{dvips} oder \Option{pdftex}, eingefügt werden.% \fi% Übrigens\textnote{Tipp!} kann \Package{scrlfile} auch bereits vor \DescRef{maincls.cmd.documentclass}\IndexCmd{documentclass} geladen werden. In diesem Fall ist allerdings \Macro{RequirePackage}\IndexCmd{RequirePackage} anstelle von \DescRef{maincls.cmd.usepackage} zu verwenden (siehe \cite{latex:clsguide}).% \EndIndexGroup \begin{Declaration} \Macro{BeforeClosingMainAux}\Parameter{Anweisungen} \Macro{AfterReadingMainAux}\Parameter{Anweisungen} \end{Declaration} Diese Anweisungen unterscheiden sich in einem Detail von den zuvor erklärten Anweisungen. Jene ermöglichen Aktionen vor und nach dem Laden von Dateien. Das ist hier nicht der Fall. Paketautoren haben des Öfteren das Problem, dass sie Anweisungen in die \File{aux}-Datei schreiben wollen, nachdem die letzte Seite des Dokuments ausgegeben wurde. Dazu wird -- in Unkenntnis der dadurch verursachten Probleme -- häufig Code wie der folgende eingesetzt: \begin{lstcode}[escapechar=\$] \AtEndDocument{%$\textnote{Nicht nachmachen!}$ \if@filesw \write\@auxout{% \protect\writethistoaux% }% \fi } \end{lstcode} Dies ist jedoch keine wirkliche Lösung. Wurde die letzte Seite vor \Macro{end}\PParameter{document} bereits ausgegeben, so führt obiges zu keiner Ausgabe in die \File{aux}-Datei. Würde man zur Lösung dieses Problems nun ein \Macro{immediate} vor \Macro{write} setzen, so hätte man das umgekehrte Problem: wurde die letzte Seite bei \Macro{end}\PParameter{document} noch nicht ausgegeben, so wird \Macro{writethistoaux} zu früh in die \File{aux}-Datei geschrieben. Man sieht daher häufig auch Lösungsversuche wie: \begin{lstcode}[escapechar=\$] \AtEndDocument{%$\textnote{Nicht nachmachen!}$ \if@filesw \clearpage \immediate\write\@auxout{% \protect\writethistoaux% }% \fi } \end{lstcode} Diese Lösung hat jedoch den Nachteil, dass damit die Ausgabe der letzten Seite erzwungen wird. Eine Anweisung wie \begin{lstcode} \AtEndDocument{% \par \vspace*{\fill}% Hinweis am Ende des Dokuments. \par } \end{lstcode} führt dann nicht mehr dazu, dass der Hinweis am Ende der letzten Seite des Dokuments ausgegeben wird, sie würde stattdessen am Ende der nächsten Seite ausgegeben. Gleichzeitig würde \Macro{writethistoaux} wieder eine Seite zu früh in die \File{aux}-Datei geschrieben. Die beste Lösung des Problems wäre nun, wenn man unmittelbar in die \File{aux}-Datei schreiben könnte, nachdem das finale \DescRef{maincls.cmd.clearpage} innerhalb von \Macro{end}\PParameter{document} ausgeführt, aber bevor die \File{aux}-Datei geschlossen wird. Dies ist das Ziel von \Macro{BeforeClosingMainAux}: \begin{lstcode} \BeforeClosingMainAux{% \if@filesw \immediate\write\@auxout{% \protect\writethistoaux% }% \fi } \end{lstcode} Das ist auch dann erfolgreich, wenn das finale \DescRef{maincls.cmd.clearpage} innerhalb von \Macro{end}\PParameter{document} tatsächlich zu keiner Ausgabe einer Seite mehr führt oder wenn -- sei es korrekt verwendet oder in Unkenntnis der oben erläuterten Probleme -- \DescRef{maincls.cmd.clearpage} innerhalb einer \Macro{AtEndDocument}-Anweisung zum Einsatz kam. Es gibt jedoch für \Macro{BeforeClosingMainAux} eine Einschränkung: Im Argument \PName{Anweisungen} sollte keine Satzanweisung verwendet werden. Es darf also mit \Macro{BeforeClosingMainAux} kein zusätzliches Material gesetzt werden! Wird diese Einschränkung nicht beachtet, so ist das Ergebnis ebenso unvorhersehbarer wie bei den gezeigten Problemen mit \Macro{AtEndDocument}. Die Anweisung \Macro{AfterReadingMainAux}\ChangedAt{v3.03}{\Package{scrlfile}} führt sogar \PName{Anweisungen} nach dem Schließen und Einlesen der \File{aux}-Datei innerhalb von \Macro{end}\PParameter{document} aus. Dies ist nur in einigen wenigen, sehr seltenen Fällen sinnvoll, beispielsweise, wenn man statistische Informationen in die \File{log}-Datei schreiben will, die erst nach dem Einlesen der \File{aux}-Datei gültig sind, oder zur Implementierung zusätzlicher \emph{Rerun}-Aufforderungen. Satzanweisungen sind an dieser Stelle noch kritischer zu betrachten als bei \Macro{BeforeClosingMainAux}.% % \EndIndexGroup \section{Dateien beim Einlesen ersetzen} \seclabel{replace} In den bisherigen Abschnitten wurden Anweisungen erklärt, mit denen es möglich ist, vor oder nach dem Einlesen einer bestimmten Datei, eines bestimmten Pakets oder einer Klasse Aktionen auszuführen. Es ist mit \Package{scrlfile} aber auch möglich, eine ganz andere Datei als die angeforderte einzulesen. \begin{Declaration} \Macro{ReplaceInput}\Parameter{Dateiname}\Parameter{Ersatzdatei} \end{Declaration} Mit\ChangedAt{v2.96}{\Package{scrlfile}} dieser Anweisung wird eine Ersetzung der Datei mit dem als erstes angegebenen \PName{Dateiname} definiert. Wenn \LaTeX{} anschließend angewiesen wird, diese Datei zu laden, wird stattdessen \PName{Ersatzdatei} geladen. Die Definition der Ersatzdatei wirkt sich auf alle Dateien aus, die vom Anwender oder intern von \LaTeX{} mit Hilfe von \Macro{InputIfFileExists} geladen werden. Dazu ist es allerdings erforderlich, dass \Package{scrlfile} diese Anweisung umdefiniert. \begin{Example} Sie wollen, dass anstelle der Datei \File{\Macro{jobname}.aux}, die Datei \File{\Macro{jobname}.xua} geladen wird. Dazu verwenden Sie: \begin{lstcode} \ReplaceInput{\jobname.aux}{\jobname.xua} \end{lstcode} Wenn Sie nun zusätzlich \File{\Macro{jobname}.xua} auch noch durch \File{\Macro{jobname}.uxa} ersetzen: \begin{lstcode} \ReplaceInput{\jobname.xua}{\jobname.uxa} \end{lstcode} dann wird \File{\Macro{jobname}.aux} am Ende durch \File{\Macro{jobname}.uxa} ersetzt. Es wird also die komplette Ersetzungskette abgearbeitet. Einer Ersetzung im Kreis: \begin{lstcode} \ReplaceInput{\jobname.aux}{\jobname.xua} \ReplaceInput{\jobname.xua}{\jobname.aux} \end{lstcode} würde jedoch zu einem \emph{stack size error} führen. Es ist also nicht möglich, eine einmal ersetzte Datei wieder durch ihren Ursprung zu ersetzen. \end{Example} Theoretisch wäre es auch möglich, auf diesem Wege ein Paket durch ein anderes oder eine Klasse durch eine andere zu ersetzen. Dabei würde \LaTeX{} aber erkennen, dass die angeforderten Dateinamen nicht zum Namen des Pakets oder der Klasse passen. Eine Lösung dieses Problems finden Sie nachfolgend. % \EndIndexGroup \begin{Declaration} \Macro{ReplaceClass}\Parameter{Klasse}\Parameter{Ersatzklasse} \Macro{ReplacePackage}\Parameter{Paket}\Parameter{Ersatzpaket} \end{Declaration} Eine\ChangedAt{v2.96}{\Package{scrlfile}}\textnote{Achtung!} Klasse oder ein Paket sollte niemals mit Hilfe der oben erklärten Anweisung \DescRef{\LabelBase.cmd.ReplaceInput} ersetzt werden. In diesem Fall würde \LaTeX{} eine Warnung über nicht übereinstimmende Klassen- oder Paketnamen melden. Auch echte Fehler sind möglich, wenn eine Klasse oder ein Paket unter einem falschen Dateinamen geladen wird. \begin{Example} Sie ersetzen das Paket \Package{scrpage2} durch dessen offiziellen Nachfolger \Package{scrlayer-scrpage}, indem Sie \begin{lstcode}[escapechar=\$] \ReplaceInput{scrpage2.sty}{scrlayer-scrpage.sty}$\textnote{Nicht nachmachen!}$ \end{lstcode} verwenden. Dies wird beim Laden von \Package{scrpage2} zu der Warnung \begin{lstcode} LaTeX warning: You have requested `scrpage2', but the package provides `scrlayer-scrpage'. \end{lstcode} führen. Für den Anwender wäre diese Warnung mehr als verwirrend, hat er doch gar nicht \Package{scrlayer-scrpage}, sondern tatsächlich \Package{scrpage2} angefordert, das jedoch durch \Package{scrlayer-scrpage} ersetzt wurde. \end{Example} Eine Lösung dieser Probleme besteht nun darin, statt \DescRef{\LabelBase.cmd.ReplaceInput} eine der Anweisungen \Macro{ReplaceClass} oder \Macro{ReplacePackage} zu verwenden. Es ist zu beachten, dass wie bei \Macro{documentclass} und \Macro{usepackage} der Name der Klasse oder des Pakets und nicht deren kompletter Dateiname anzugeben ist. Die Ersetzung funktioniert für Klassen, die mit \Macro{documentclass}, \Macro{LoadClassWithOptions} oder \Macro{LoadClass} geladen werden. Für Pakete funktioniert die Ersetzung beim Laden mit \Macro{usepackage}, \Macro{RequirePackageWithOptions} und \Macro{RequirePackage}. Es\textnote{Achtung!} ist zu beachten, dass die \PName{Ersatzklasse} oder das \PName{Ersatzpaket} mit denselben Optionen geladen wird, mit denen die ursprünglich geforderte Klasse oder das ursprünglich geforderte Paket geladen würden. Wird ein Paket oder eine Klasse durch ein Paket oder eine Klasse ersetzt, die eine geforderte Option nicht unterstützt, würde das zu den üblichen Warnungen und Fehlern führen. Es ist jedoch möglich, solche in der \PName{Ersatzklasse} oder dem \PName{Ersatzpaket} fehlenden Optionen per \DescRef{\LabelBase.cmd.BeforeClass} oder \DescRef{\LabelBase.cmd.BeforePackage} neu zu definieren. \begin{Example} Angenommen, das Paket \Package{oldfoo} soll beim Laden durch das Paket \Package{newfoo} ersetzt werden. Dies wird mit \begin{lstcode} \ReplacePackage{oldfoo}{newfoo} \end{lstcode} erreicht. Das alte Paket hat eine Option \Option{oldopt}, die das neue Paket jedoch nicht hat. Mit \begin{lstcode} \BeforePackage{newfoo}{% \DeclareOption{oldopt}{% \PackageInfo{newfoo}% {option `oldopt' not supported}% }% }% \end{lstcode} wird diese Option nun für das Paket \Package{newfoo} nachdefiniert. Dadurch wird vermieden, dass beim Laden des Pakets \Package{oldfoo} ein Fehler über die im Paket \Package{newfoo} nicht unterstützte Option gemeldet wird. Existiert hingegen eine Option \Option{newopt}, die anstelle der Option \Option{oldopt} verwendet werden soll, so kann dies ebenfalls erreicht werden: \begin{lstcode} \BeforePackage{newfoo}{% \DeclareOption{oldopt}{% \ExecuteOptions{newopt}% }% }% \end{lstcode} Es ist sogar möglich, festzulegen, dass beim Laden des neuen Pakets andere Voreinstellung gelten sollen: \begin{lstcode} \BeforePackage{newfoo}{% \DeclareOption{oldopt}{% \ExecuteOptions{newopt}% }% \PassOptionsToPackage{newdefoptA,newdefoptB}% {newfoo}% } \end{lstcode} oder auch direkt: \begin{lstcode} \BeforePackage{newfoo}{% \DeclareOption{oldopt}{% \ExecuteOptions{newopt}% }% }% \PassOptionsToPackage{newdefoptA,newdefoptB}% {newfoo}% \end{lstcode} Man beachte, dass im letzten Beispiel der Aufruf von \Macro{PassOptionsToPackage} nicht innerhalb, sondern erst nach \Macro{BeforePackage} erfolgt. \end{Example} Damit Klassen ersetzt werden können, ist es natürlich erforderlich \Package{scrlfile} vor der Klasse zu laden. Dazu ist \Macro{RequirePackage}\IndexCmd{RequirePackage} anstelle von \DescRef{maincls.cmd.usepackage} zu verwenden (siehe \cite{latex:clsguide}).% \EndIndexGroup \begin{Declaration} \Macro{UnReplaceInput}\Parameter{Dateinamen} \Macro{UnReplacePackage}\Parameter{Paket} \Macro{UnReplaceClass}\Parameter{Klasse} \end{Declaration} Eine\ChangedAt{v3.12}{\Package{scrlfile}} Ersetzung kann auch wieder aufgehoben werden. Dabei sollten Ersetzungen von Dateien immer mit \Macro{UnReplaceInput}, Ersetzungen von Paketen mit \Macro{UnReplacePackage} und Ersetzungen von Klassen mit \Macro{UnReplaceClass} aufgehoben werden. Nach der Aufhebung der Ersetzung führen Ladebefehle für den entsprechenden \PName{Dateiname}, das entsprechende \PName{Paket} oder die entsprechende \PName{Klasse} dann wieder dazu, dass die Datei, das Paket oder die Klasse selbst anstelle der Ersatzdatei, des Ersatzpakets oder der Ersatzklasse geladen wird.% \EndIndexGroup \section{Dateien gar nicht erst einlesen} \seclabel{prevent} Gerade\ChangedAt{v3.08}{\Package{scrlfile}} in Klassen und Paketen, die innerhalb von Firmen oder Instituten verwendet werden, findet man häufig, dass sehr viele Pakete nur deshalb geladen werden, weil die Anwender diese Pakete oft verwenden. Wenn es dann mit einem dieser automatisch geladenen Paketen zu einem Problem kommt, muss man irgendwie das Laden des problematischen Pakets verhindern. Auch hier bietet \Package{scrlfile} eine einfache Lösung. \begin{Declaration} \Macro{PreventPackageFromLoading}\OParameter{Stattdessencode} \Parameter{Paketliste} \Macro{PreventPackageFromLoading*}\OParameter{Stattdessencode} \Parameter{Paketliste} \end{Declaration} Wird diese Anweisung\ChangedAt{v3.08}{\Package{scrlfile}} vor dem Laden eines Paket mit \Macro{usepackage}\IndexCmd{usepackage}, \Macro{RequirePackage}\IndexCmd{RequirePackage} oder \Macro{RequirePackageWithOptions}\IndexCmd{RequirePackageWithOptions} aufgerufen, so wird das Laden des Pakets effektiv verhindert, falls es in der \PName{Paketliste} zu finden ist. % \begin{Example} Angenommen, Sie arbeiten in einer Firma, in der alle Dokumente mit Latin~Modern erzeugt werden. In der Firmenklasse, \Class{firmenci}, befinden sich daher die Zeilen: \begin{lstcode} \RequirePackage[T1]{fontenc} \RequirePackage{lmodern} \end{lstcode} Nun wollen Sie zum ersten Mal ein Dokument mit X\kern-.125em\lower.5ex\hbox{\reflectbox{E}}\LaTeX{} oder Lua\LaTeX{} setzen. Da beim hierbei empfohlenen Paket \Package{fontspec} ohnehin Latin-Modern voreingestellt ist und das Laden von \Package{fontenc} eher störend wäre, wollen Sie das Laden beider Pakete verhindern. Sie laden die Klasse deshalb nun in Ihrem eigenen Dokument wie folgt: \begin{lstcode} \RequirePackage{scrlfile} \PreventPackageFromLoading{fontenc,lmodern} \documentclass{firmenci} \end{lstcode} \end{Example} Wie im Beispiel zu sehen ist, kann man das Paket \Package{scrlfile} auch bereits vor der Klasse laden. In diesem Fall muss das Laden dann aber mit Hilfe von \Macro{RequirePackage}\IndexCmd{RequirePackage} erfolgen, da \Macro{usepackage} vor \Macro{documentclass} verboten ist (siehe \cite{latex:clsguide}). Wird eine leere \PName{Paketliste} angegeben oder wird ein Paket angegeben, das bereits geladen ist, gibt \Macro{PreventPackageFromLoading} eine Warnung aus, während \Macro{PreventPackageFromLoading*}\ChangedAt{v3.12}{\Package{scrlfile}} lediglich einen entsprechenden Hinweis in die Log-Datei schreibt. Das optionale Argument\ChangedAt{v3.12}{\Package{scrlfile}} kann verwendet werden, wenn anstelle des Ladens des Pakets etwas anderes getan werden soll. Innerhalb des \PName{Stattdessencode}s dürfen jedoch keine anderen Pakete und keine Dateien geladen werden. Zum Laden eines anderen Pakets siehe \DescRef{\LabelBase.cmd.ReplacePackage} in \autoref{sec:scrlfile.replace} auf \DescPageRef{\LabelBase.cmd.ReplacePackage}. Beachten\textnote{Achtung!} Sie bitte auch, dass der \PName{Stattdessencode} mehrfach ausgeführt wird, falls Sie versuchen, das Paket mehrfach zu laden!% \EndIndexGroup \begin{Declaration} \Macro{StorePreventPackageFromLoading}\Parameter{\textMacro{Anweisung}} \Macro{ResetPreventPackageFromLoading} \end{Declaration} \Macro{Anweisung} wird mit \Macro{StorePreventPackageFromLoading}\ChangedAt{v3.08}{\Package{scrlfile}} als die aktuelle Liste der Pakete definiert, für die das Laden verhindert werden soll. Dagegen setzt \Macro{ResetPreventPackageFromLoading}\ChangedAt{v3.08}{\Package{scrlfile}} die Liste der Pakete, für die das Laden verhindert werden soll, zurück. Danach können wieder alle Pakete geladen werden. \begin{Example} Angenommen, Sie sind innerhalb eines Pakets unbedingt auf das Laden eines anderen Pakets angewiesen und wollen nicht, dass der Anwender das Laden dieses Pakets mit \DescRef{\LabelBase.cmd.PreventPackageFromLoading}% \IndexCmd{PreventPackageFromLoading} verhindern kann. Also setzen Sie die Paketliste für die Ausnahmen zuvor zurück: \begin{lstcode} \ResetPreventPackageFromLoading \RequirePackage{foo} \end{lstcode} Allerdings hat dies den Nachteil, dass ab diesem Zeitpunkt die komplette Ausnahmeliste des Anwenders verloren ist. Also speichern Sie die Liste zunächst zwischen und reaktivieren sie später wieder: \begin{lstcode} \newcommand*{\Users@PreventList}{}% \StorePreventPackageFromLoading\Users@PreventList \ResetPreventPackageFromLoading \RequirePackage{foo} \PreventPackageFromLoading{\Users@PreventList} \end{lstcode} Es ist zu beachten, dass\textnote{Achtung!} \Macro{Users@PreventList} durch die Anweisung \Macro{StorePreventPackageFromLoading} auch definiert werden würde, wenn diese bereits anderweitig definiert wäre. Eine vorhandene Definition würde also ohne Rücksicht überschrieben werden. In diesem Beispiel wurde deshalb mit einem vorherigen \Macro{newcommand*} sichergestellt, dass in dem Fall zur Sicherheit eine Fehlermeldung ausgegeben wird. \end{Example} An dieser Stelle sei darauf hingewiesen, dass Sie bei Manipulationen an der mit \Macro{StorePreventPackageFromLoading} zwischengespeicherten Liste selbst die Verantwortung für eine korrekte Wiederherstellbarkeit tragen. So muss die Liste unbedingt mit Komma separiert sein, sollte keine Leerzeichen oder Gruppenklammern enthalten und muss voll expandierbar sein.% Beachten\textnote{Achtung!} Sie bitte, dass \Macro{ResetPreventPackageFromLoading} den \PName{Stattdessencode} für ein Paket nicht löscht, sondern nur vorübergehend dessen Ausführung nicht mehr erfolgt.% \EndIndexGroup \begin{Declaration} \Macro{UnPreventPackageFromLoading}\Parameter{Paketliste} \Macro{UnPreventPackageFromLoading*}\Parameter{Paketliste} \end{Declaration} Statt\ChangedAt{v3.12}{\Package{scrlfile}} die Liste der Pakete, für die das Laden verhindert werden soll, komplett zurück zu setzen, kann man auch einzelne oder mehrere Pakete gezielt von dieser Liste entfernen. Die Sternvariante des Befehls löscht außerdem den \PName{Stattdessencode}, der für das Paket gespeichert ist. Falls die Verhinderungsliste beispielsweise aus einer gespeicherten Liste wiederhergestellt wird, wird dann der \PName{Stattdessencode} trotzdem nicht mehr ausgeführt.% % \begin{Example} Angenommen, Sie wollen zwar verhindern, dass ein Paket \Package{foo} geladen wird, wollen aber nicht, dass ein eventuell bereits gespeicherter \PName{Stattdessencode} ausgeführt wird. Stattdessen soll nur Ihr neuer \PName{Stattdessencode} ausgeführt werden. Dies ist wie folgt möglich: \begin{lstcode} \UnPreventPackageFromLoading*{foo} \PreventPackageFromLoading[% \typeout{Stattdessencode}% ]{foo} \end{lstcode} Für die Anweisung \Macro{UnPreventPackageFromLoading*} ist es unerheblich, ob das Paket zuvor überhaupt vom Laden ausgenommen war. Natürlich können Sie die Anweisung indirekt auch nutzen, um den \PName{Stattdessencode} aller Pakete zu löschen: \begin{lstcode} \StorePreventPackageFromLoading\TheWholePreventList \UnPreventPackageFromLoading*{\TheWholePreventList} \PreventPackageFromLoading{\TheWholePreventList} \end{lstcode} Die Pakete werden dann zwar noch immer nicht geladen, ihr \PName{Stattdessencode} existiert aber nicht mehr und wird nicht mehr ausgeführt.% \end{Example}% \EndIndexGroup % \EndIndexGroup %%% Local Variables: %%% mode: latex %%% coding: utf-8 %%% TeX-master: "../guide" %%% End: