Disallowing \textbf, \it, \sffamily, … in argument of macro or environment

I would like to have a command \newcommand{\restricted}[1]{...} which doesn't allow you to call it with something like

\restricted{calling me {\bf like} this \textit{is} not allowed}


i.e., the use of \bf, \textbf, \tt, and friends inside its argument should be forbidden.

Of course, I could, as suggested in Allow only certain commands in own environment, redefined all these commands to throw an error inside my command, but this would be very unelegant.

As they are all font changing commands, I hope that there is some internal command that they all call, so that locally redefining this one command can give me the behavior I want.

Unfortunately I don't know how \textbf is implemented, couldn't find any documentation on its internal workings with google and \show\textbf isn't very informative.

To clarify: I don't just want to suppress the effect of these macros, but really disallow them. The background is that I am writing a documentclass, and as the content of \title{} should always look the same and is also used to automatically set pdf metadata, authors should not be able to say something like \title{\textbf{I want my title bold}}.

• Presumably, your class will never be used for, say, book reviews and titles will not be permitted to include acronyms (at least, not acronyms set in small-caps)? – cfr Jan 8 '17 at 0:33
• I don't expect anything like that. Titles might contain math, but that seems to be compatible with egreg's solution. At least \restricted{$\mathrm{a}$} works as expected. – cgogolin Jan 9 '17 at 10:30

There's no list of the font changing commands available, but you can redefine \selectfont, inside a group, to do nothing except issuing an error message.

\documentclass{article}

\makeatletter
\newcommand{\restricted}[1]{%
\begingroup
\let\selectfont\cgogolin@error
#1%
\endgroup
}
\newcommand{\cgogolin@error}{%
\@latex@error{Font change not allowed}
{You used a font changing command, which is\MessageBreak
not permitted here}%
}
\makeatother

\begin{document}

\restricted{calling me {\bfseries like} this \textit{is} not allowed}

\end{document}


Here's the output on the terminal:

! LaTeX Error: Font change not allowed.

See the LaTeX manual or LaTeX Companion for explanation.
Type  H <return>  for immediate help.
...

l.19 ...series like} this \textit{is} not allowed}


• This solution still allows font changes in math mode - which is actually what I want. Just thought it would be good to mention that. – cgogolin Jan 9 '17 at 10:31

The following minimal example provides a selective font switch check by using etoolbox's \patchcmd. Each font switch is used to patch the argument of \restricted. If it is successful, an error is generated, otherwise nothing happens.

\documentclass{article}

\usepackage{etoolbox}

\makeatletter
\newcommand{\restricted}[1]{%
\def\restricted@arg{#1}%
\renewcommand{\do}[1]{%
\patchcmd{\restricted@arg}% <cmd>
{##1}{##1}% <search><replace>
{\cgogolin@error}{}% <success><failure>
}
\docsvlist{\bfseries,\textit}% Check for certain font uses... add more
% <do stuff with #1>
}
\newcommand{\cgogolin@error}{%
\@latex@error{Font change not allowed}
{You used a font changing command, which is\MessageBreak
not permitted here}%
}
\makeatother

\begin{document}

Calling me {\bfseries like} this \textit{is} allowed.

\restricted{Calling me {\bfseries like} this \textit{is} not allowed.}

\end{document}


This comes with the caveat that it tests for explicit use of any particular font switch. For example, \bfseries my be allowed if only checking for \textbf, say. Also, no expansion is performed on the argument, so hidden font switches won't be picked up (for example, if \let\mybfseries\bfseries is used).