3

I'd like to construct a conditional \iffalse and \fi. Specifically, I'd like to define a counter and a macro such that if the counter set to one,the macro would either set an \iffalse, if the argument to the macro were "on", or a \fi, if the argument to the macro were "off". Similar questions have been asked in this thread and this one but both involve more complicated constructions than my simple one.

In the code below, I define a counter Skip and a macro \mySkip which, if correctly defined, would, if \Skip were set to 1, would return \iffalse in response to the line \mySkip{on} and \fi in response to the line \mySkip{off}. If \Skip were set to 0, the macro would be ignored. In this way, I could alter one line of my code, and thus display or not display large sections of text.

The macro, instead of suppressing the text between \mySkip{on} and \mySkip{off} merely postpones printing the text between \mySkip{on} and \mySkip{off} until after the \mySkip{\off}. Is there a way to fix this?

Thanks for any advice.

\documentclass{article}
\usepackage{pdftexcmds}
\usepackage{ifthen}
\makeatother
\newif\ifstrcmp
\makeatletter
\def\isstrcmp#1#2{
        \ifnum\pdf@strcmp{#1}{#2}=0
                \strcmptrue
        \else
                \strcmpfalse
        \fi
}
\makeatother
\newcounter{Skip}
\def\mySkip#1{\ifthenelse{\theSkip=1}{
        \isstrcmp{#1}{on}
        \ifstrcmp
            \iffalse
        \else
            \fi
            Text should resume after this\\
        \fi
        }{
        }}
\begin{document}
\setcounter{Skip}{1}
\mySkip{on}
This line should be skipped because it's between an ``iffalse'' and a ``fi''\\
In fact it's ``postponed" till immediately after the macro is ``closed"\\ \\
\mySkip{off}
This is the first line after the macro has been closed
\end{document}
  • 2
    Have you seen comment.sty? It offers a more user-friendly interface than having to fiddle with counters. – jon May 8 '16 at 3:48
  • Is switching from pdfLaTeX to LuaLaTeX an option for you? – Mico May 8 '16 at 5:50
  • Please do not use minimal for examples. – cfr May 8 '16 at 12:31
5

It is not possible to emulate conditionals (\iftrue, \iffalse, \else, \fi) by macros, because TeX's scanning for \else and \fi does not involve macro expansion. The conditional commands can only be assigned to other names (via \let). The starting conditional can be hidden inside macros as long as it is not inside the branch of another conditional.

Example for a macro setting the counter:

\documentclass{article}

\newcounter{Skip}% default is zero

\newcommand*{\mySkipOn}{%
  \setcounter{Skip}{1}%
  \iffalse
}
\newcommand*{\mySkipOff}{%
  \setcounter{Skip}{0}%
  \iftrue
}
\let\mySkipEnd=\fi

\begin{document}
\mySkipOn
This line should be skipped because it's between an \verb|\iffalse\verb|
and \verb|\fi|.\\
\mySkipEnd
This is the first line after the macro has been closed.
\end{document}

Result

Caution: \mySkipOn/\mySkipOff cannot be nested, because TeX will not recognize macros as conditionals, when it ignores the token of a conditional branch, which is not selected.

Example for a macro using a counter:

\documentclass{article}

\newcounter{Skip}% default is zero

\newcommand*{\mySkipBegin}{%
  \ifnum\value{Skip}=1 %
    \csname iffalse\expandafter\endcsname
  \else
    \csname iftrue\expandafter\endcsname
  \fi
}
\let\mySkipEnd=\fi

\begin{document}
\setcounter{Skip}{1}
\mySkipBegin
This line should be skipped because it's between an \verb|\iffalse\verb|
and \verb|\fi|.\\
\mySkipEnd
This is the first line after the macro has been closed.
\end{document}

Again \mySkipBegin should not appear inside other conditional branches. Its definition shows, how unmatched conditionals can be hidden via \csname inside outer branches. The \expandafter commands ends the outer conditional branches, leaving \iftrue or \iffalse at the end.

  • If I understood your answer correctly, the actions of \mySkipOn and \mySkipOn are not conditional on the value of Skip. Is this correct? – Mico May 8 '16 at 5:45
  • 1
    @Mico You are right, I have now added an example the other way round. But I do not know, what the purpose of the counter is. Two values (0 and 1) can be easily expressed by a simple boolean switch defined by \newif. – Heiko Oberdiek May 8 '16 at 5:58
0

Delimited arguments might be your friends.

Ulrich

\documentclass{minimal}

\makeatletter
%%-------------------------------------------------------------------------
%% Check whether argument is empty:
%%.........................................................................
%% \CheckWhetherNull{<Argument which is to be checked>}%
%%                  {<Tokens to be delivered in case that
%%                    argument which is to be checked is empty>}%
%%                  {<Tokens to be delivered in case that
%%                    argument which is to be checked is not empty>}%
\newcommand\@CheckWhetherNull[1]{%
  \expandafter\@secondoftwo\string{\expandafter\@secondoftwo
  \expandafter{\expandafter{\string#1}\expandafter\@secondoftwo
  \string}\expandafter\@firstoftwo\expandafter{\expandafter
  \@firstoftwo\expandafter\@secondoftwo\expandafter}\string
  }\@firstoftwo
}%
%%-------------------------------------------------------------------------
%% Check whether argument contains no exclamation-mark on top-brace-level:
%%.........................................................................
%% \CheckWhetherNoExclamationMark{<Argument which is to be checked>}%
%%                  {<Tokens to be delivered in case that
%%                    argument which is to be checked does not contain !>}%
%%                  {<Tokens to be delivered in case that
%%                    argument which is to be checked does contain !>}%
\newcommand\@RemoveToExclamationMark{}%
\long\def\@RemoveToExclamationMark#1!{}%
\newcommand\@CheckWhetherNoExclamationMark[1]{%
  \expandafter\@CheckWhetherNull\expandafter{\@RemoveToExclamationMark#1!}%
}%
%%-------------------------------------------------------------------------
%% \mySkip{ON/TRUE/1} AND Skip = 1 -> Things until next \mySkip{...}
%%                                    within the same brace-level 
%%                                    will be skkipped.
%% !!The material to be skipped must not contain \outer tokens.!!
%%.........................................................................
\newcommand\@mySkipFork{}%
\long\def\@mySkipFork#1!!ON!TRUE!1!#2#3!!!!{#2}%
\newcommand\mySkip[1]{%
  \ifnum\number\value{Skip}=1 %
    \expandafter\@firstofone
  \else
    \expandafter\@gobble
  \fi
  {%
    \@CheckWhetherNoExclamationMark{#1}{%
      \uppercase{%
        \@mySkipFork
        !!#1!TRUE!1!{\removeToNextMySkip}%<-ON
        !!ON!#1!1!{\removeToNextMySkip}%<-TRUE
        !!ON!TRUE!#1!{\removeToNextMySkip}%<-1
        !!ON!TRUE!1!{}%<-ELSE
        !!!!%
      }%
    }{}%<-ELSE
  }%
  \ignorespaces
}%
%
\newcommand\removeToNextMySkip{}%
\long\def\removeToNextMySkip#1\mySkip#2{\ignorespaces}%
%
\newcounter{Skip}%
%
\makeatother


\begin{document}
\setcounter{Skip}{1}
This is the first phrase that should definitely not be skipped.
\mySkip{oN}
This phrase should probably be skipped.
\mySkip{off}
This is the second phrase that should definitely not be skipped.
\end{document}
0

The following approach allows skipping of \outer tokens and skipping things like instances of the verbatim environment as well. Be aware that you cannot hide \mySkip{...} within other macros or within macros' arguments and that \mySkip should not be "renamed" (via \let).

Matching \mySkip{...}-pairs must not come from macro-expansion but they must occur within the same .tex-input-file.

This time the code comes without any \if..-switches within the macro code.

Instead of wasting a \count-register for the Skip-counter, a simple macro \Skipflag is invented. If that is not defined to expand to the phrase "1", nothing will be skipped.

Ulrich

\documentclass{minimal}
\usepackage{verbatim}

\makeatletter
%%-------------------------------------------------------------------------
%% Check whether argument is empty:
%%.........................................................................
%% \CheckWhetherNull{<Argument which is to be checked>}%
%%                  {<Tokens to be delivered in case that
%%                    argument which is to be checked is empty>}%
%%                  {<Tokens to be delivered in case that
%%                    argument which is to be checked is not empty>}%
\newcommand\@CheckWhetherNull[1]{%
  \expandafter\@secondoftwo\string{\expandafter\@secondoftwo
  \expandafter{\expandafter{\string#1}\expandafter\@secondoftwo
  \string}\expandafter\@firstoftwo\expandafter{\expandafter
  \@firstoftwo\expandafter\@secondoftwo\expandafter}\string
  }\@firstoftwo
}%
%%-------------------------------------------------------------------------
%% Check whether argument contains no exclamation-mark on top-brace-level:
%%.........................................................................
%% \CheckWhetherNoExclamationMark{<Argument which is to be checked>}%
%%                  {<Tokens to be delivered in case that
%%                    argument which is to be checked does not contain !>}%
%%                  {<Tokens to be delivered in case that
%%                    argument which is to be checked does contain !>}%
\newcommand\@RemoveToExclamationMark{}%
\long\def\@RemoveToExclamationMark#1!{}%
\newcommand\@CheckWhetherNoExclamationMark[1]{%
  \expandafter\@CheckWhetherNull\expandafter{\@RemoveToExclamationMark#1!}%
}%
%%-------------------------------------------------------------------------
%% \mySkip{ON/TRUE/1} AND \Skipflag = 1 -> Things until next \mySkip{...}
%%                                         will be skkipped.
%%.........................................................................
\newcommand\@mySkipFork{}%
\long\def\@mySkipFork#1!!1.ON!1.TRUE!1.1!#2#3!!!!{#2}%
\newcommand\mySkip[1]{%
  \expandafter\@mySkip\expandafter{\number0\Skipflag.#1}%
}%
\newcommand\@mySkip[1]{%
    \@CheckWhetherNoExclamationMark{#1}{%
      \uppercase{%
        \@mySkipFork
        !!#1!1.TRUE!1.1!{\removeToNextMySkip}%<-ON
        !!1.ON!#1!1.1!{\removeToNextMySkip}%<-TRUE
        !!1.ON!1.TRUE!#1!{\removeToNextMySkip}%<-1
        !!1.ON!1.TRUE!1.1!{}%<-ELSE
        !!!!%
      }%
    }{}%<-ELSE
  \ignorespaces
}%
%
\newcommand\removeToNextMySkip{%
  \begingroup
  \let\do\@makeother
  \dospecials
  \@removeToNextMySkip
}%
\begingroup
\newcommand\@removeToNextMySkip{%
   \endgroup
   \begingroup
   \newcommand\@removeToNextMySkip[1]{%
     \endgroup
     \long\def\@removeToNextMySkip####1##1{%
       \endgroup\@firstoftwo{\ignorespaces}%
     }%
   }%
   \let\do\@makeother
   \dospecials
   \catcode`\{=1 %
   \catcode`\}=2 %
   \@removeToNextMySkip%
}%
\@removeToNextMySkip{\mySkip}%
%
\makeatother

\outer\def\outerphrase{%
  This phrase comes from an outer-deffed token and it should
  probably be skipped as well. %
}%


\begin{document}
\newcommand\Skipflag{1}%
%\renewcommand\Skipflag{0}%
This is the first phrase that should definitely not be skipped.
\mySkip{oN}
This phrase should probably be skipped.
\outerphrase
\begin{verbatim}
And this is some verbatim stuff that also should probably be skipped.
\end{verbatim}
\mySkip{off}
This is the second phrase that should definitely not be skipped.
\end{document}

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.