31

I want to write in the preamble of a LaTeX document code that should be take into account by different compilers when the document is typeset. There are fragments that should be used:

  • only by xelatex
  • only by lualatex
  • only by xelatex or lualatex
  • only by pdflatex

I am using the packages ifxetex and ifluatex that provide the commands \ifxetex and \ifluatex, respectively.

How can I logically combine these commands in a disjunction (or operation)?

The code would be something like:

\ifxetex
  % code used only by xetex
\else
  \ifluatex
    % code used only by luatex
  \fi
\fi

\ifxetex OR \ifluatex     % I do not know how to express this conditional <--------
  % code used by both xetex and luatex
\else
  % code used by other (pdflatex, say)
\fi

Any help?

36
\usepackage{ifxetex,ifluatex}
\newif\ifxetexorluatex
\ifxetex
  \xetexorluatextrue
\else
  \ifluatex
    \xetexorluatextrue
  \else
    \xetexorluatexfalse
  \fi
\fi

Now \ifxetexorluatex will do what you want. For instance, for loading fontspec and setting input normalization:

\ifxetexorluatex
   \usepackage{fontspec}
   \setmainfont{TeX Gyre Pagella}
\else
   \usepackage[T1]{fontenc}
   \usepackage{tgpagella}
\fi

\ifxetex
  \XeTeXinputnormalization=1
\fi

A different implementation, just for fun, is

\newif\ifxetexorluatex
\begingroup\catcode94=7 \catcode0=9 % ASCII 94 is ^
\def\empty{}\def\next{^^^^0000}\expandafter\endgroup
\ifx\next\empty\xetexorluatextrue\else\xetexorluatexfalse\fi

It exploits the fact that the XeTeX and LuaTeX engines have the ^^^^ convention for inputting character with their Unicode point. If the engine is Unicode aware, ^^^^0000 counts as a unique token which, by the assignment \catcode0=9 is ignored, so that \next expands to nothing and is equivalent to \empty. In case an 8-bit engine is used, the expansion of \next would contain six tokens (^^^ counts as one, then ^0000) and \ifx will follow the "false" path.

Another way of doing it, without defining an \ifxetexorluatex conditional, is to say

\ifnum 0\ifxetex 1\fi\ifluatex 1\fi>0
   % code for XeTeX or LuaTeX
\else
   % code for pdfLaTeX
\fi

There must be no space between 0 and \ifxetex and between 1 and \fi. This exploits the fact that TeX expands tokens when looking for numbers. So if one of the two inner conditionals is true, the engine will see 01, which is greater than zero. If both are false it will see 0.

So a shorter way to set \ifxetexorluatex can be

\newif\ifxetexorluatex % a new conditional starts as false
\ifnum 0\ifxetex 1\fi\ifluatex 1\fi>0
   \xetexorluatextrue
\fi

A much more general implementation using expl3.

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\cs_new_eq:NN \pdftexengine \sys_if_engine_pdftex_p:
\cs_new_eq:NN \xetexengine  \sys_if_engine_xetex_p:
\cs_new_eq:NN \luatexengine \sys_if_engine_luatex_p:
\cs_new_eq:NN \ptexengine   \sys_if_engine_ptex_p:
\cs_new_eq:NN \uptexengine  \sys_if_engine_uptex_p:

\NewExpandableDocumentCommand{\ifengineTF}{mmm}
 {
  \bool_if:nTF { #1 } { #2 } { #3 }
 }
\ExplSyntaxOff

\begin{document}

\ifengineTF{\pdftexengine}
  {\typeout{pdf}}
  {\typeout{not pdf}}

\ifengineTF{\xetexengine || \luatexengine}
  {\typeout{either xe or lua}}
  {\typeout{neither xe nor lua}}

\ifengineTF{\pdftexengine || \xetexengine || \luatexengine}
 {\typeout{pdf or xe or lua}}
 {\typeout{ptex or uptex}}

\end{document}

Running from the shell the following commands

> pdflatex engines >> engines.out
> xelatex engines >> engines.out
> lualatex engines >> engines.out
> platex engines >> engines.out

results in the following engines.out file (edited to show only the relevant parts)

This is pdfTeX, Version 3.14159265-2.6-1.40.19 (TeX Live 2018) (preloaded format=pdflatex)
 restricted \write18 enabled.
entering extended mode
(./engines.tex
[...]
pdf
neither xe nor lua
pdf or xe or lua
[...]

This is XeTeX, Version 3.14159265-2.6-0.99999 (TeX Live 2018) (preloaded format=xelatex)
 restricted \write18 enabled.
entering extended mode
(./engines.tex
[...]
not pdf
either xe or lua
pdf or xe or lua
[...]

This is LuaTeX, Version 1.07.0 (TeX Live 2018) 
 restricted system commands enabled.
(./engines.tex
[...]
not pdf
either xe or lua
pdf or xe or lua
[...]

This is e-pTeX, Version 3.14159265-p3.8.1-180226-2.6 (utf8.euc) (TeX Live 2018) (preloaded format=platex)
 restricted \write18 enabled.
entering extended mode
(./engines.tex
[...]
not pdf
neither xe nor lua
ptex or uptex
(./engines.aux) )
[...]

A different solution, with perhaps a better syntax, at the expense of expandability (until we will have e-expansion available).

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\ifengineTF}{mmm}
 {
  \bool_if:xTF
   {
    \clist_map_function:nN { #1 } \__egreg_predicate:f \c_true_bool
   }
   { #2 } { #3 }
 }
\cs_generate_variant:Nn \bool_if:nTF { x }

\cs_new:Nn \__egreg_predicate:n
 {
  \use:c { sys_if_engine_#1_p: } ||
 }
\cs_generate_variant:Nn \__egreg_predicate:n { f }
\ExplSyntaxOff

\begin{document}

\ifengineTF{pdftex}
  {\typeout{pdf}}
  {\typeout{not pdf}}

\ifengineTF{xetex,luatex}
  {\typeout{either xe or lua}}
  {\typeout{neither xe nor lua}}

\ifengineTF{pdftex,xetex,luatex}
 {\typeout{pdf or xe or lua}}
 {\typeout{ptex or uptex}}

\end{document}

The output is the same as before.

  • Sorry, but \ifxetexorluatex will not distinguish between XeTeX and LuaTeX - which Romildo wants. – Martin Schröder Mar 10 '12 at 23:40
  • 7
    @MartinSchröder Of course it won't, how could it? For XeTeX or LuaTeX specific code, \ifxetex and \ifluatex can still be used; where's the problem? Romildo wanted a conditional to distinguish between (XeTeX or LuaTeX) and pdfTeX. – egreg Mar 10 '12 at 23:46
  • 3
    A safer version of the catcode trick (only if \scantokens is available) is \begingroup\catcode94=7\catcode0=9\catcode30=12\catcode48=12\everyeof{\noexpand}\expandafter\endgroup\if\scantokens{^^^^0000}??\xetexorluatextrue\else\xetexorluatexfalse\fi. – Bruno Le Floch Mar 11 '12 at 10:49
12

In such situations, the generic \ifboolexpr wrapper provided by the etoolbox package comes in handy:

\usepackage{etoolbox,ifxetex,ifluatex}

\ifboolexpr{bool{xetex} or bool{luatex}}{%
  <true-code>%
}{%
  <false-code>%
}

The bool operator that works with the \ifboolexpr syntax to perform boolean tests operates on all primitive style TeX conditionals. Note that it omits the \if prefix of the original \ifxetex and \ifluatex commands.

9

Sometimes this sort of issue is easier to solve by changing the order of checking things.

\documentclass{article}
\usepackage{ifpdf,ifluatex,ifxetex}
\begin{document}
\ifpdf
      I am in pdf
   \else
       common code for lualatex and xelatex
    \ifluatex  ...    \fi
    \ifxetex   ...    \fi
\fi
\end{document}
  • 2
    Won't this approach fail if the tex file happens to be compiled under a TeX format other than pdflatex, xelatex, or lualatex? – Mico Mar 11 '12 at 3:14
  • @Mico The OP only wanted to check for this, but in general it wouldn't, provided your code is common to all, otherwise you build more checks \ifvtex etc... – Yiannis Lazarides Mar 11 '12 at 3:59
  • 1
    IIRC, \ifpdf checks the output mode not the engine, so it is true for pdftex or luatex in pdf mode and false otherwise. – Khaled Hosny Mar 11 '12 at 5:26
  • @KhaledHosny The example compiles correctly for the pdfLaTeX, LuaLaTeX and XeLaTeX. It will fail in all other cases due to the documentclass{}. – Yiannis Lazarides Mar 11 '12 at 5:40
  • 3
    lualatex '\RequirePackage{ifpdf}\show\ifpdf' produces \ifpdf=\iftrue – egreg Mar 11 '12 at 9:26
9

probably I'd advise going with @egreg's answer but an alternative way of combining \if conditionals (which essentially isthe way \ifthenelse \OR works) is shown as follows, using \ifA and \ifB as it works generally not for the engine tests.

\newif\ifA
\newif\ifB

\Atrue\Btrue\typeout{true true}

\if!\ifA!\else\ifB!\else?\fi\fi

\typeout{A or B}

\else

\typeout {neither A nor B}

\fi

\Atrue\Bfalse\typeout{true false}

\if!\ifA!\else\ifB!\else?\fi\fi

\typeout{A or B}

\else

\typeout {neither A nor B}

\fi


\Afalse\Btrue\typeout{false true}

\if!\ifA!\else\ifB!\else?\fi\fi

\typeout{A or B}

\else

\typeout {neither A nor B}

\fi

\Afalse\Bfalse\typeout{false false}

\if!\ifA!\else\ifB!\else?\fi\fi

\typeout{A or B}

\else

\typeout {neither A nor B}

\fi



\stop
  • What is the meaning of the characters ! and ? that appear in \if!\ifA!\else\ifB!\else?\fi\fi? – Romildo Mar 11 '12 at 11:33
  • any two characters will do so long as they are not the same. If for example ifA is true and ifB is false \ifA!\else\ifB!\else?\fi\fi expands to ! so the outer \if is \if!! which is true. By adjusting which characters are returned you can make other logical connectives such as and or exclusive or – David Carlisle Mar 11 '12 at 11:36
6

For the fun of it, possibly the shortest way:

\documentclass{article}
\usepackage{ifxetex,ifluatex}
\begin{document}

hello

\ifx\ifxetex\ifluatex\else
   xetex or luatex is true
\fi

\end{document}

Indeed, xetex and luatex are mutually exclusive. If the two conditionals coïncide, this must be because both are false. So the opposite is that one of the two is true, which was what was asked for.


As pointed out by egreg in a comment, this construction can not be used as is inside other conditionals (in case it ends up in the skipped branch). This alternative formulation does not have this defect:

\expandafter\ifx\csname ifxetex\expandafter\endcsname \csname ifluatex\endcsname\else 
xetex or luatex is true\fi
  • Hehe, I particularly like this one, very clever! (Unless someone comes up with a luaxetex engine, of course...) – Daniel Oct 22 '13 at 21:49
  • @Daniel I would be more scared by an egreglisle mix... – user4686 Oct 22 '13 at 21:51
  • 1
    This is nice, of course, but it can't be used in conditional text, if it belongs to the skipped over branch. Probably it should be used in the preamble to set a new conditional. – egreg Feb 13 '14 at 18:42
  • 1
    @egreg \ifx\ifxetex\ifluatex\else xetex or luatex is true \fi\@gobbletwo \fi \fi should do it but this is less simple. – user4686 Feb 14 '14 at 17:30
  • @egreg or perhaps \expandafter\ifx\csname ifxetex\expandafter\endcsname \csname ifluatex\endcsname\else xetex or luatex is true\fi. – user4686 Feb 14 '14 at 17:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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