# Structuring a collection of patches for various classes and packages

I develop a package whose main part consists of fixes and patches to other document classes and packages. Naturally, I only want to apply a patch if the class or package in question has been loaded. Furthermore, there can be patches that apply to several classes/packages, and there can be patches that apply to a class/package only if some other class/package has not been loaded (for example, hyperref modifies many things in the standard classes, and if I were to modify them too, I would have to use two versions, depending on if hyperref has been loaded). Since I don't want to force any particular loading order, I also want to run the package detection/patching part AtBeginDocument.

One thing that comes to mind is to extend the \@ifclassloaded and \@ifpackageloaded commands to accept a comma-separated list of names using \@for. Then I would say

\PatchClassIfLoaded{article,report,book}{<commands>}


and so on. But then <commands> have to be inside an argument and will be "read" twice (pardon my insufficient TeX knowledge to describe it better), which I don't like. While this would be necessary for package patches because of \AtBeginDocument, this is not required for classes.

I would better like a construct such as

\IfClassLoaded{article,report,book}
<commands>
\fi


I know I can program it if I go one level lower than \@ifclassloaded. But this feels more like a hack which shouldn't be relied on.

The above was just an example of what I'm trying to achieve. The question itself is broader: Are there different solutions to the problem? Is there a package implementing similar things? What methods do packages like hyperref and caption use to accommodate for a large variety of classes and packages?

-
Please also notify the authors of the patched packages directly, even if it is just a compatibility patch with a different package. They might want to integrate this code into the packages directly. – Martin Scharrer Jul 14 '11 at 11:52
@Martin: I described the generalized problem, but the real thing I'm doing is adjusting the classes/packages to work with a certain foreign language. While some authors do incorporate internationalization infrastructure in their packages (in this case I can use it directly), most generally don't (you can partially count in the LaTeX2e base here, too). My patches would be meaningless to those who don't have internationalization at all; and the job of my package is to fix the goofs from this end. – Andrey Vihrov Jul 14 '11 at 15:41
@Martin: Also, the difference from babel/polyglossia is that I'm doing heavier things which are not supposed to be reverted by another language switch. That is, the code is supposed to be for the case where this language is the main language of the document. (I also plan to contact the polyglossia author to enquire whether it's possible to integrate this type of code in polyglossia). – Andrey Vihrov Jul 14 '11 at 16:02
Languages switches don't revert things automatically. So you only need to check if your language is \xpg@main@language, set up your code and hope that not other language does something that interferes. – Ulrike Fischer Jul 14 '11 at 16:54
@Ulrike: I did not know about \xpg@main@language. This could prove really useful! – Andrey Vihrov Jul 14 '11 at 17:01

The caption package version <= 3.0 patched existing macros, i.e. the new code worked on top of the old, existing macro code. Because there are so many document classes and packages around that offer or patch caption related code, too (for example some babel packages) this approach has not proved satisfactory. There were always incompatibilities I was not able to handle.

So for version 3.1 I changed this: I do not patch caption related macros anymore, but replace them instead, usually \AtBeginDocument. Obviously this has some advantages and disadvantages.

• I have to integrate stuff from other packages into my code to make my package compatible to the other package. If the internals of the other package change, my package does not work anymore and therefore I have to adopt my code, too.
• My package is only compatible with the document classes or packages whose (caption related) code it has integrated. To all other, it's not (anymore).
• It only works if I'm the only one who is patching caption related macros this way.

• I'm now fully compatible with the document classes and packages I support. (They are listed in the caption package.)
• The caption package removes incompatibilities between the packages I support. For example the fltpage package is not compatible with the hyperref package. But when loading the caption package additionally, the caption-relevant code of both packages will be completely replaced with my code, and therefore this combination will now work fine. (The caption package is even able to offer some extra settings regarding the combination of fltpage and hyperref.)

In the end I'm very happy with this change. But the new approach is only successful because LaTeX and most of the packages I support are "dead"; they have not been changed for years and hopefully never will. The only packages "alive" I have to take care of are KOMA-Script and hyperref. (And of course I'm in contact with the authors of those.)

Regarding the question of how to detect document classes or packages: This differs in the caption package code, i.e. I'm not using the same strategy all the time. Sometimes I check for a loaded package, sometimes I check for the existence of a specific macro. I know that this can be improved but unless I get bug reports because of this I will not change it ;-)

Addendum: The reason for this inconsistency is simply that I never formed a concept about this. And I never planned to patch so many document classes and packages when I started writing the package in 1994.

Regarding how do I deal with hyperref etc: I have encapsulated the hyperref functionality into macros which do nothing if the hyperref package isn't loaded:


\newcommand*\caption@makecurrent[2]{}
\let\caption@makeanchor\@firstofone
\let\caption@start\relax
\let\caption@@start\relax
\let\caption@freezeHref\relax
\let\caption@defrostHref\relax


These macros will be used by my caption code. If the hyperref package is detected, the main caption code will not be changed but the helper macros above will be. (I use the same mechanism for other packages as well, e.g. the float package.)

-
It's exciting to get an answer from the caption author himself. Thanks! – Andrey Vihrov Jul 21 '11 at 18:23

I would say: Try to avoid to write such a package. You only need to read the section about compability and problems in the documentation of hyperref to see that it is already not easy to use and manage a package which has to maintain compability with a lot of other packages. Adding another bunch of "fixes and patches" will lead to crowded \AtBeginDocument-hook, chicken-and-egg-races about who inserts its code later and puzzling problems for user which use a package combination you didn't consider.

-