Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I am trying to test an if-condition, where the name of the condition depends on a macro argument. To do this, I use \csname ifcondition#1 \endcsname. This works fine in a simple macro like this:

\newif\ifconditionA
\conditionAtrue
\def\test#1{
    \csname ifcondition#1\endcsname
        A: True
    \fi
}
\test{A}

However, in my real use case, this test is part of an \ifcase branch, like so:

\documentclass{article}
\begin{document}
\newif\ifconditionA
\conditionAtrue

\def\test#1#2{
\ifcase#2
    Case 0
\or
    %\ifconditionA % This works
    \csname ifcondition#1\endcsname
        Case 1, A: true
    \fi
\fi
}

\test{A}{0}
%\test{A}{1} % This works

\end{document}

This fails with the error message ! Extra \fi. \test ...tion#1\endcsname Case 1, A: true \fi \fi.

If I use the name of the condition directly, without \csname, it works fine, and it also works if the branch containing the condition is executed.

What's going on, and how do I fix this?

share|improve this question

2 Answers 2

up vote 8 down vote accepted

The restriction is that the conditions must match, otherwise the skipping of unused branches does not work as expected.

There are several methods. The following exampe uses \ifx and compares the constructed conditional with \iftrue. Because we have already \ifx, the latter is also masked by \csname:

\documentclass{article}
\begin{document}
\newif\ifconditionA
\conditionAtrue

\def\test#1#2{%
  \ifcase#2
    Case 0
  \or
    \expandafter
    \ifx\csname ifcondition#1\expandafter\endcsname
        \csname iftrue\endcsname
      Case 1, A: true
    \fi
  \fi
}

\test{A}{0}
\test{A}{1}

\end{document}

If you want to have something clearer to use inside macro \test, then the magic can be hidden in a macro, e.g.:

\documentclass{article}
\begin{document}
\newif\ifconditionA
\conditionAtrue

\newcommand*{\getcondition}[1]{%
  T\expandafter
  \ifx\csname ifcondition#1\endcsname\iftrue
    \expandafter T%
  \else
    \expandafter F%
  \fi
}

\def\test#1#2{%
  \ifcase#2
    Case 0%
  \or
    \if\getcondition{#1}%
      Case 1, #1: true%
    \else
      Case 1, #1: false%
    \fi
  \else
    Other case%
  \fi
}

[\test{A}{0}]
[\test{A}{1}]
[\test{B}{0}]
[\test{B}{1}]
[\test{A}{2}]

\end{document}

Result

share|improve this answer
    
Ah, excellent, thank you! It seems like using \iftrue directly (without the \csname) also works? –  Jake Jul 16 '13 at 15:03
    
@Jake: No, it will not work, if the \or branch is skipped. TeX would see two \if... commands and would steal the \fi of \ifcase to match them. –  Heiko Oberdiek Jul 16 '13 at 15:05
    
Indeed. Thanks again! –  Jake Jul 16 '13 at 15:08

You can use the fact that \if expands tokens until finding unexpandable ones:

\documentclass{article}
\begin{document}
\newif\ifconditionA
\conditionAtrue

\def\testcondition#1{\expandafter\TTfi\csname ifcondition#1\endcsname}
\def\TTfi{TT\fi}

\def\test#1#2{%
  \ifcase#2
    Case 0
  \or
    \if\testcondition{#1}%
      Case 1, A: true
    \fi
  \fi
}

\test{A}{0}
\test{A}{1}

\end{document}

Let's see how it works. If we are in a skipped over text, that is, the false branch of a conditional or an \or branch to be ignored, TeX will match \if with the \fi (and the possible \else) that really corresponds to \ifconditionA. If it's in a true branch, then the expansions are

\if\testcondition{A}
\if\expandafter\TTfi\csname ifconditionA\endcsname
\if\TTfi\ifconditionA
\if TT\fi\ifconditionA
\ifconditionA

so the \if is matched to the first \fi and the entire group \if TT\fi disappears without doing nothing. Then the constructed \ifconditionA is matched to its \else and \fi.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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