1

In the following MWE

\documentclass{article}

\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage[utf8]{inputenc}

\usepackage[pdftex,unicode,final]{hyperref}
\input{glyphtounicode}
\pdfgentounicode=1

\makeatletter
\newcommand*{\boilerplate}{\@ifstar\@@boilerplate\@boilerplate}
\newcommand*{\@boilerplate}{Boilerplate for running text}
\newcommand*{\@@boilerplate}{Boilerplate for headings in capalized form}
\makeatother

\begin{document}

\section{\boilerplate*}

\end{document}

the star is used to obtain an alternative variant of the boilerplate. The MWE fails with

Token not allowed in a PDF string (Unicode):
(hyperref)                removing `\@ifnextchar' on input line 19.

Obviously, the problem is the order of macro expansions. I have already tried to play around with \expandafter but did not find a solution.

Remark: If possibly, I would like to keep the starred-version to select the variant of the boilerplate. This design has been agreed upon some time ago and is used at myriads of places. In other words changing the macro definition to something like \boilerplateNormal and \boilerplateVariant is not an option, because that would break compatibility with other authors using the sty-file.

nagmat84
  • 1,115
  • Try \section{$\setminus$boilerplate*} – M S May 28 '19 at 10:35
  • 1
    The problem is that \@ifnextchar (used in \@ifstar) is not expandable, and text in pdf strings (such as section titles) must expand completely. It is possible to make the command expandable but your \boilerplate command would require at least a final mandatory argument: \section{\boilerplate*{}} or \section{\boilerplate{}}. – Phelype Oleinik May 28 '19 at 10:37
  • 1
    You can probably use \texorpdfstring, see https://tex.stackexchange.com/questions/53513/hyperref-token-not-allowed. – Marijn May 28 '19 at 10:49
  • 1
    Don't add the pdftex option. – egreg May 28 '19 at 10:49

1 Answers1

2

The command \boilerplate is fragile, with the current definition.

Either use \protect\boilerplate when in a moving argument, or do

\DeclareRobustCommand{\boilerplate}{\@ifstar\@@boilerplate\@boilerplate}

instead of \newcommand.

Alternatively, add \usepackage{xparse} and change the definition into

\NewDocumentCommand{\boilerplate}{s}{%
  \IfBooleanTF{#1}{%
    Boilerplate for headings in capitalized form% \boilerplate*
  }{%
    Boilerplate for running text% \boilerplate (with no *)
  }%
}

Don't expect the expansion of \boilerplate (with or without *) finds its way in the bookmarks, though. It can be done if the macro \boilerplate takes a regular argument.

Assuming that in moving arguments you use the *-variant, you can use \pdfstringdefDisableCommand:

\documentclass{article}

\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{lmodern}
\usepackage{xparse}

\usepackage[unicode,final]{hyperref}
\input{glyphtounicode}
\pdfgentounicode=1

\NewDocumentCommand{\boilerplate}{s}{%
  \IfBooleanTF{#1}{%
    Boilerplate for headings in capitalized form% \boilerplate*
  }{%
    Boilerplate for running text% \boilerplate (with no *)
  }%
}
\pdfstringdefDisableCommands{\def\boilerplate*{Boilerplate for bookmark}}

\begin{document}

\section{\boilerplate*}

\boilerplate

\end{document}

enter image description here

egreg
  • 1,121,712
  • "Don't expect the expansion of \boilerplate (with or without *) finds its way in the bookmarks" --> Unfortunately, this is not an option. I tried your solution, but then the bookmarks only contain an asterisk. – nagmat84 May 28 '19 at 11:17
  • @nagmat84 This can be adjusted, but something more about the real use case is needed. – egreg May 28 '19 at 11:51
  • @nagmat84 As Phelype wrote in his comment, if will probably only work if there is e.g. a {} after the input, (so \boilerplate{}). – Ulrike Fischer May 28 '19 at 11:53
  • @egreg What information do you miss about the real use case? – nagmat84 May 28 '19 at 15:32
  • @nagmat84 Is the addition something you like? – egreg May 28 '19 at 15:53
  • @egreg: Yes, it is. It exactly does what I need. I never have heard of \pdfstringdefDisableCommands before. However, after I have read the documentation, it feels more like a nasty hack, because \pdfstringdefDisableCommands slows down compilation linearly in the number of disabled commands. But I can live with that. It is still an easier solution than to redefine all arguments such that they avoid using a star-variant and then crawl through all existing documents and fix macros there. Nonetheless, (La)TeX macro definition and expansion always feels "flawed" to me. – nagmat84 May 28 '19 at 16:11