# \IfFileExists is acting inconsistently when testing another boolean in conjunction with \input

I've been refactoring some code and clearing out obsolete commands.

I don't understand what's happening here:

\begin{filecontents}{mkif}
\newif\ifaeRoughDraft
\def\testforRoughDraft
{\ifaeRoughDraft
\lfoot{testing}
\rfoot{proof}
\fi
}
\end{filecontents}
\documentclass{article}
\usepackage{fancyhdr}
\pagestyle{fancy}

\IfFileExists{.ae.proof}
{
\input{mkif}
\IfFileExists{.ae.draft}
{\aeRoughDrafttrue}
{}
\testforRoughDraft
%%\ifaeRoughDraft\lfoot{testing}\rfoot{proof}\fi
}{}

\begin{document}

testing

\end{document}


Assuming you create .ae.proof and .ae.draft, the MWE as provided above compiles fine. However, if you try to compile

\begin{filecontents}{mkif}
\newif\ifaeRoughDraft
\def\testforRoughDraft
{\ifaeRoughDraft
\lfoot{testing}
\rfoot{proof}
\fi
}
\end{filecontents}
\documentclass{article}
\usepackage{fancyhdr}
\pagestyle{fancy}

\IfFileExists{.ae.proof}
{
\input{mkif}
\IfFileExists{.ae.draft}
{\aeRoughDrafttrue}
{}
%%\testforRoughDraft
\ifaeRoughDraft\lfoot{testing}\rfoot{proof}\fi
}{}

\begin{document}

testing

\end{document}


I get the following error:

(/usr/local/texlive/2013/texmf-dist/tex/latex/fancyhdr/fancyhdr.sty)
! Extra \else.
\IfFileExists ...ileonpath {#1}{#2}{#3}}\fi \else
\closein \@inputcheck \ede...
l.22       }{}


It seems to me the code is equivalent. But, obviously LaTeX doesn't think so.

If I change how I input the file mkif---such as removing it from within the \IfFileExists---things work once more regardless of when I use \testforRoughDraft or \ifaeRoughDraft.

What gives?

The code in the second argument of \IfFileExists is absorbed before \input{mkif} is executed and the \fi is thus paired improperly to a conditional deriving from the expansion of \IfFileExists. Let's see.

The expansion of

\IfFileExists{.ae.proof}
{
\input{mkif}
\IfFileExists{.ae.draft}
{\aeRoughDrafttrue}
{}
\ifaeRoughDraft\lfoot{testing}\rfoot{proof}\fi
}{}


is

\openin\@inputcheck .ae.proof
\ifeof\@inputcheck
\ifx\input@path\@undefined
\def\reserved@a{}%
\else
\def\reserved@a{%
\@iffileonpath{.ae.proof}%
{\input{mkif}\IfFileExists{.ae.draft}{\aeRoughDrafttrue}{}%
\ifaeRoughDraft\lfoot{testing}\rfoot{proof}\fi}{}}%
\fi
\else
\closein\@inputcheck
\edef\@filef@und{.ae.proof }%
\def\reserved@a{%
\input{mkif}\IfFileExists{.ae.draft}{\aeRoughDrafttrue}{}%
\ifaeRoughDraft\lfoot{testing}\rfoot{proof}\fi
}%
\fi
\reserved@a


Since .ae.proof is found, the "true" branch of \ifeof is skipped; it's the first \fi that is seen to stop this branch and it is the wrong one. So the next \fi ends the true branch of \ifeof and an extra \else is scanned. The error message tells precisely that the extra \else comes just before \closein.

TeX doesn't keep track of braces when skipping text in a conditional. And it's not sufficient that a control sequence starts with \if... to be considered a conditional: only control sequences \let to a primitive conditional are marked with a special flag that makes TeX pair them with \else or \fi when skipping tokens in a branch of a conditional. So, until \newif\ifaeRoughDraft is not executed, \ifaeRoughDraft is just an undefined control sequence.

In the other case, the \fi is not there, because TeX doesn't expand macros when skipping tokens in a conditional, so what's seen is just \testforRoughDraft.

A better way to proceed, but this a matter of opinions, is to always input mkif; thus you won't be risking a conditional to be undefined. Or use a better macro instead of \testforRoughDraft:

\begin{filecontents}{mkif}
\newif\ifaeRoughDraft
\makeatletter
\newcommand\doifaeRoughDraft{%
\ifaeRoughDraft
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
}
\makeatother
\end{filecontents}


so that you can say

\IfFileExists{ae.proof}
{\input{mkif}%
\IfFileExists{ae.draft}{\aeRoughDrafttrue}{}%
\doifaeRoughDraft{\lfoot{testing}\rfoot{proof}}{}%
}{}


which is more flexible.

• I'm not sure I follow. From what you're saying, it seems like things shouldn't work whether or not \input{mkif} is present. Jul 26 '13 at 0:09
• Also, are you suggesting that the only way I can hide the \fi from the overzealous reach of the expansion process is to bury it in a macro as in my first example? Jul 26 '13 at 0:11
• @A.Ellett Yes, that's the trick. Jul 26 '13 at 0:13
• @A.Ellett Tomorrow I'll add a different workaround. Jul 26 '13 at 0:20
• I'll look forward to your answer. Jul 26 '13 at 0:24