4

I tried to define a macro myself, which outputs different strings according to the input variable (like select-case statements in other programming languages).

The problem:

If I use the code in headings, captions, etc., I get error messages and no pdf, unless I put a \protect before the macro (see example below).

I'd like to avoid that - can I redefine the macro to make it "robust" also in such environments?

Example file

\documentclass[11pt, a4paper]{scrbook}

\usepackage{color}
\usepackage{xstring}

\newcommand{\ed}[1]{% source: http://tex.stackexchange.com/q/64131/4009, needs package xstring
\textcolor{magenta}{
\,\bfseries\itshape\IfStrEqCase{#1}{{1}{A}
    {8}{B}
    {5}{C}
{3}{D}
{7}{E}
{11}{F}
{14}{G}
{16}{H}
{19}{J}}
    [??]
}} 

\listfiles

\begin{document}


1 \ed{1}

2 \ed{2}

3 \ed{3}

4 \ed{4} 

test

\section{in headings it does not work like \ed{11}, at leat in the main document}



\end{document}
  • 1
    \DeclareRobustCommand perhaps? ;-) – user31729 Mar 16 '15 at 16:11
  • 1
    See tex.stackexchange.com/questions/61503/… for a discussion on \newcommand vs. \DeclareRobustCommand. – user31729 Mar 16 '15 at 16:16
7

\DeclareRobustCommand can be used for such cases, however, there are expansion issues (i.e. it's not expandible).

The code uses the original version and a \DeclareRobustCommand version.

In addition one could use

  • \newrobustcmd from etoolbox package
  • \NewDocumentCommand from xparse package

\documentclass[11pt, a4paper]{scrbook}

\usepackage{etoolbox}
\usepackage{xparse}

\usepackage{color}
\usepackage{xstring}

\newcommand{\ed}[1]{% source: http://tex.stackexchange.com/q/64131/4009, needs package xstring
\textcolor{magenta}{
\,\bfseries\itshape\IfStrEqCase{#1}{{1}{A}
    {8}{B}
    {5}{C}
{3}{D}
{7}{E}
{11}{F}
{14}{G}
{16}{H}
{19}{J}}
    [??]
}} 

\newrobustcmd{\edetoolbox}[1]{% source: http://tex.stackexchange.com/q/64131/4009, needs package xstring
\textcolor{magenta}{
\,\bfseries\itshape\IfStrEqCase{#1}{{1}{A}
    {8}{B}
    {5}{C}
{3}{D}
{7}{E}
{11}{F}
{14}{G}
{16}{H}
{19}{J}}
    [??]
}} 


\NewDocumentCommand{\edxparse}{m}{% source: http://tex.stackexchange.com/q/64131/4009, needs package xstring
\textcolor{magenta}{
\,\bfseries\itshape\IfStrEqCase{#1}{{1}{A}
    {8}{B}
    {5}{C}
{3}{D}
{7}{E}
{11}{F}
{14}{G}
{16}{H}
{19}{J}}
    [??]
}} 




\DeclareRobustCommand{\edother}[1]{% source: http://tex.stackexchange.com/q/64131/4009, needs package xstring
\textcolor{magenta}{
\,\bfseries\itshape\IfStrEqCase{#1}{{1}{A}
    {8}{B}
    {5}{C}
{3}{D}
{7}{E}
{11}{F}
{14}{G}
{16}{H}
{19}{J}}
    [??]
}} 


\listfiles

\begin{document}


1 \ed{1}

2 \ed{2}

3 \ed{3}

4 \ed{4} 

test

\section{in headings it does not work like \protect\ed{11}, at leat in the main document}

\section{in headings it does not work like \edother{11}, at leat in the main document}

\section{in headings it does not work like \edetoolbox{11}, at leat in the main document}

\section{in headings it does not work like \edxparse{11}, at leat in the main document}



\end{document}
  • There's also \robustify from etoolbox. – Manuel Mar 17 '15 at 10:36
  • @Manuel: I know, but I never used it so far. Thanks – user31729 Mar 17 '15 at 12:59
2

When we are using plain TeX then we have two ways how to protect the macro. First one is possible by eTeX extension (commonly used). Instead of \def\macro we must say

\protected\def\macro 

This technique is possible in LaTeX too.

The second more comfortable way is available when OPmac macro package is used. We can say

\addprotect\macro 

which registers the control sequence \macro as protected. We needn't to change the definition of the \macro itself. The \addprotect declaration from OPmac works in classical TeX and we can use it before definition of the macro or after it. This doesn't matter.

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.