3

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}
Heiko Oberdiek
  • 271,626
gdolle
  • 329
  • 1
  • 7
  • 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 –  Aug 22 '16 at 17:03
  • @ChristianHupfer Yes of course, it's just to illustrate the problem here. – gdolle Aug 22 '16 at 17:40
  • @gdolle: Well, I don't understand what you're asking really then. I don't see any purpose in putting such a test in the document hooks ... –  Aug 22 '16 at 17:41
  • @touhami can you explain how ? – gdolle Aug 22 '16 at 17:42
  • 4
    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
  • @HeikoOberdiek Could you write an answer with a little more detail? What counts as being hidden, for example? Obviously, it is OK to use these in macro definitions, for example, where they are 'hidden' from the end user. – cfr Aug 22 '16 at 22:56
  • @cfr Done. I have also added a workaround. – Heiko Oberdiek Aug 23 '16 at 17:29

1 Answers1

6

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
  {%
    \Addto@Envbody{#1}%
  }{%
    \Addto@Envbody{#1\end{#2}}%
  }%
  \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}

Result

GuM
  • 21,558
Heiko Oberdiek
  • 271,626