Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I use the following code to check if a package is loaded:

\RequirePackage{ltxcmds}
\newcommand{\IfPackageLoaded}[2]{\ltx@ifpackageloaded{#1}{#2}{}}

However, sometimes I want to check if more than one package is loaded. Therefore I would like to generalise the command, such that more than one package can be added in a list separated with commas:

\IfPackagesLoaded{xcolor, colortbl, hyperref}{
...
}%

What would the typical implementation of the processing of such a list look like?

share|improve this question
add comment

3 Answers 3

up vote 6 down vote accepted

You can use the LaTeX kernel's \@for macro, which processes a comma-separated list, in conjunction with an if switch. The \IfPackagesLoaded macro initially sets the switch to true, then goes through the list and sets the switch to false if a package is missing.

\documentclass{article}

\usepackage{ltxcmds}

\usepackage{fixltx2e}
\usepackage{doc}

\makeatletter
\newif\ifallloaded
\newcommand{\IfPackagesLoaded}[3]{%
  \allloadedtrue
  \@for\@tempa:=#1\do{%
    \ltx@ifpackageloaded{\@tempa}{}{\allloadedfalse}}%
  \ifallloaded #2\else #3\fi}
\makeatother

\begin{document}

\IfPackagesLoaded{fixltx2e,doc}{yes}{no}
\IfPackagesLoaded{hyperref,fixltx2e}{yes}{no}

\end{document}
share|improve this answer
1  
how robust is this for list for the occurrence of spaces before or after commas and a comma at the beginning or end of the list? –  Matthias Pospiech Nov 18 '11 at 12:31
    
Note that \@ifpackageloaded only works in the preamble, while \ltx@ifpackageloaded also works in the document body. –  Martin Scharrer Nov 18 '11 at 12:35
    
@MatthiasPospiech: Spaces are taken as part of an element. Preceding or trailing commas create empty elements. So, not robust in this sense. The list should be a normal comma-separated list. –  Andrey Vihrov Nov 18 '11 at 12:36
    
@MartinScharrer: Not with the pkgindoc package :-P –  Andrey Vihrov Nov 18 '11 at 12:39
    
@AndreyVihrov: Well, just check if \ver@<package>.sty exits yourself. Easy enough. –  Martin Scharrer Nov 18 '11 at 12:42
show 5 more comments

As Andrey stated you can use the LaTeX internal macro \@for to go through a comma separated list. Another useful macro is \zap@space, which is normally used to remove spaces from a package option list.

I would define a \next macro which is usually true, i.e. expands to the first of the next two arguments but is that to expand to the second instead if any not-loaded package is encountered. I then redefine an internal macro (inside a group) to skip all other packages. The package-loaded-test done by \lxt@ifpackageloaded (ltxcmds package) and \@ifpackageloaded (LaTeX core, but only-in-preamble) is to check if the macro \ver@<package>.sty is define, which holds the version of the package (but can be empty). I added this code here directly to not be dependent to a package just for this small code.

\documentclass{article}

\usepackage{fixltx2e}
\usepackage{doc}

\makeatletter
\newcommand{\IfPackagesLoaded}[1]{%
    \begingroup
    \let\next\@firstoftwo
    \@for\@tempa:=#1\do{%
        \expandafter\@IfPackagesLoaded\expandafter{\@tempa}%
    }%
    \expandafter\endgroup
    \next
}
\def\@IfPackagesLoaded#1{%
    \edef\@tempa{\zap@space#1 \@empty}% remove any spaces
    \expandafter\ifx\csname ver@\@tempa.sty\endcsname\relax% package not loaded?
        \let\next\@secondoftwo
        \let\@IfPackagesLoaded\@gobble% No need for further checks
    \fi
}
\makeatother

\begin{document}

\IfPackagesLoaded{fixltx2e,doc}{\typeout{yes}}{\typeout{no}}
\IfPackagesLoaded{ fixltx2e , doc }{\typeout{yes}}{\typeout{no}}
\IfPackagesLoaded{hyperref,fixltx2e}{\typeout{yes}}{\typeout{no}}

\end{document}
share|improve this answer
    
can you comment, in the best case line after line, what this code does? I understand that the for does an iteration, and in each \@IfPackageLoaded is called with \@tempa. But what is the meaning of next, what do you do with \@firstoftwo and \@secondoftwo and why can you rename \@IfPackagesLoaded within the command itself? I would assume that it is not available in the second iteration in that case. So basically I do not understand most of this code... –  Matthias Pospiech Nov 20 '11 at 18:52
add comment

As others have remarked, the kernel provides \@ifpackageloaded and ltxcmds also \ltx@ifpackageloaded that can be used in the document.

\usepackage{ltxcmds,etoolbox}

\makeatletter
\newcommand{\IfPackagesLoaded}[1]{%
  \@tempswatrue
  \def\do##1{\edef\@tempa{\zap@space##1 \@empty}%
    \ltx@ifpackageloaded{\@tempa}{}{\@tempswafalse}}%
  \docsvlist{#1}%
  \if@tempswa\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi}
\makeatother

Processing the list element through \zap@space ensures that no spaces around the package name remain also if the call is

\IfPackagesLoaded{ abc , xyz }

The conditional \if@tempswa is predefined by LaTeX and is used as a "scratch conditional"; it should be relied on only on immediate application, as other macros might change its truth value. The idea is that the conditional is set to true at the beginning and each "not already loaded" package in the list sets it to false. Therefore it will be still true at the end only if all packages in the list are already loaded.

The final line uses this fact and uses the code in the second or third arguments to \IfPackagesLoaded. Actually they aren't really arguments to \IfPackagesLoaded, but from the user's point of view it makes no difference. I might have defined \IfPackagesLoaded with three arguments by using as the last instruction

\if@tempswa#2\else#3\fi

but the way chosen is better as it leaves no trailing \else or \fi when the code in the second and third argument is executed.

share|improve this answer
    
As I understand \docsvlist processed for each index in the csv list the \do command. But what are these predefined if sequences \@tempswatrue and what does the last line with \if@tempswa –  Matthias Pospiech Nov 20 '11 at 18:56
    
@MatthiasPospiech See edited message with explanations; you can use the idea of \zap@space also in Andrey's code, by putting \edef\@tempa{\xp\xp\xp\zap@space\xp\@tempa\space\@empty} just after the opening brace following \do; here \xp stands for \expandafter. –  egreg Nov 20 '11 at 20:25
    
Actually I would have expected that there are 2 or three arguments such that there is an if and an else branch. You say that you get around this by using \if@tempswa\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi` but now I completely fail to understand how many argument the command has? –  Matthias Pospiech Nov 20 '11 at 20:30
    
The command has one argument, but the call must be \IfPackagesLoaded{list}{true}{false}; actually {true} and {false} will be absorbed as arguments either by \@firstoftwo or \@secondoftwo, depending on the test. It's very common in LaTeX; for example \section is defined as having no argument as you can easily check doing \show\section. It's not relevant for the user, though, who can think to \section as taking an optional and a mandatory argument. You can see here for a discussion about \@firstoftwo and \@secondoftwo. –  egreg Nov 20 '11 at 20:36
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.