# Conditional \if \fi using hooks \AtBeginDocument and \AtEndDocument

I wonder if there's a way in LaTeX to create a conditional in the whole document from the preamble? Something similar to this sample (which obviously does not work):

\documentclass{article}

\AtBeginDocument
{
\if 1
}
\AtEndDocument
{
\fi
}

\begin{document}
My test 1
\fi\if 2
My test 2
\fi\if 3
My test 3
\end{document}

• What do you want to achieve with such a construction? – gernot Aug 22 '16 at 15:18
• Just wonder if it is possible, I updated this very simple example, maybe it will be more explanatory. (I imagine it could be use for example to hide some part of the text using a variable.) – gdolle Aug 22 '16 at 15:24
• yes this is possible. – touhami Aug 22 '16 at 16:14
• Wouldn't a counter be more useful for this, i.e. the counter value can be queried with \ifnum\value then – user31729 Aug 22 '16 at 17:03
• It is not possible, because \or, \else, \fi, and nested \if... cannot be hidden inside macros. If TeX is skipping a branch, all other command tokens with different meanings are skipped and macros are not expanded. – Heiko Oberdiek Aug 22 '16 at 18:30

The problem with the approach in the question is the parsing rules for conditionals in TeX. If TeX expands an \if... expression, it evaluates it to \iftrue or \iffalse. If true, then it keeps expanding until it finds a \else. Then TeX goes in skipping mode until it finds the closing \fi. If \if... evaluates to \iffalse, TeX skips all until the next \else or \fi.

In skipping mode, TeX checks each token, whether it has the meaning of a conditional: \else, \fi and inner \if... constructs. The crucial point is that macros are not expanded. If \fi is hidden inside a macro, then the macro is skipped and TeX will never see the \fi inside its definition.

This exactly happens with

\AtEndDocument{\fi}


Then TeX will not see the \fi in:

\iffalse
\end{document}


and will continue reading beyond \end{document}.

## Workaround

The following example uses package environ can catch the contents of an environment, document in this case. A limitation is that category changes inside the document in the same file (included files are fine) are not supported.

\documentclass{article}

\usepackage{environ}

% Patches to support arguments with conditionals out of order
\makeatletter
\long\def\Collect@@Body#1\end#2{%
\edef\begin@stack{%
\Push@Begins#1\begin\end\expandafter\@gobble\begin@stack}%
\ifx\@empty\begin@stack
\endgroup
\@checkend{#2}%
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
{%
}{%
}%
\process@envbody
}
\long\def\Push@Begins#1\begin#2{%
\expandafter\ifx\expandafter\end\@car#2\@empty\@nil
\else
b\expandafter\Push@Begins
\fi
}
\makeatother

\let\OrgDocument\document
\let\endOrgDocument\enddocument
\let\document\relax
\let\enddocument\relax
\NewEnviron{document}{%
\global\let\document\OrgDocument
\global\let\enddocument\endOrgDocument
\expandafter\endgroup
\expandafter\WrapDocument\expandafter{\BODY}%
}
\newcommand{\WrapDocument}[1]{%
\begin{document}%
\iffalse
#1%
\fi
\end{document}%
}

\begin{document}
My test 1
\fi\iftrue
\begin{center}
My test 2
\end{center}
\fi\iffalse
My test 3
\end{document}


• Absorbing the entire document as the argument to a command? No, thanks. ;-) – egreg Aug 23 '16 at 19:25