2

To extract text from huge LaTeX-files in a safe and controllable manner, I am having LaTeX itself write to a textfile. To retain and adapt some formatting informations and structural elements I have given the file a new header where I redefine the commands for this special purpose. This works fine until I need commands with optional arguments.

Using newfile for convenience:

\documentclass{minimal}

\usepackage{newfile}
\newoutputstream{out}
\openoutputfile{out.text}{out}


\newcommand{\standardexample}[3]{#1:#2(#3)}
\newcommand{\optionalexample}[3][default]{#1:#2(#3)}

\begin{document}

text \standardexample{1}{2}{3} and \optionalexample[not default]{2}{3} or \optionalexample{2}{3}

\addtostream{out}{
text \standardexample{1}{2}{3} and \optionalexample[not default]{2}{3} or \optionalexample{2}{3}
}

\closeoutputstream{out}

\end{document}

I get

text 1:2(3) and not default:2(3) or default:2(3)

in the pdf as expected, but

text 1:2(3) and \optionalexample[not default]{2}{3} or \optionalexample{2}{3}

in the text-file with no errors in the log.

Testing without newfile, e.g.

\documentclass{minimal}

\newcommand{\standardexample}[3]{#1:#2(#3)}
\newcommand{\optionalexample}[3][default]{#1:#2(#3)}


\newwrite\tempfile

\begin{document}
\immediate\openout\tempfile=\jobname.tmp
\immediate\write\tempfile{text \standardexample{1}{2}{3} and \optionalexample[not default]{2}{3} or \optionalexample{2}{3}}
\immediate\closeout\tempfile


text \standardexample{1}{2}{3} and \optionalexample[not default]{2}{3} or \optionalexample{2}{3}


\end{document}

the typesetting is broken off by a couple of error messages (some of which are even included in the tmp-file), but I can't really make sense of them.

Both an expanation and a workaround would be great.

3

Commands defined with an optional argument are automatically robustified, but this means they survive \protected@write; they definitely don't survive \write exactly because of the protection mechanism.

It mostly depends on what you want to write to the auxiliary file; if you need the expansion of those commands you're out of luck, because they must perform assignments in order to produce their replacement text.

With \protected@write, an input such as

\protected@write\tempfile{}{\optionalexample[not default]{2}{3} or \optionalexample{2}{3}}

would write

text \optionalexample [not default]{2}{3} or \optionalexample {2}{3}

You can find an \immediate version in Writing \\ to a File

If you instead need the full expansion of the commands, you can use xparse:

\usepackage{xparse}
\DeclareExpandableDocumentCommand{\optionalexample}{O{default}mm}{#1:#2(#3)}

and this will work in \immediate\write.


You can find some discussion about a macro with optional argument defined with \newcommand at Are commands defined by \newcommand[.][.]{.} robust?

There you can see that your \optionalexample macro becomes, when TeX expands it

\@protected@testopt \optionalexample \\optionalexample {default}

Now the problem starts: when you do \immediate\write, the value of \protect is \@typeset@protect (which in turn means \relax, but it's irrelevant. Here's the definition of \@protected@testopt:

% latex.ltx, line 619:
\def\@protected@testopt#1{%%
  \ifx\protect\@typeset@protect
    \expandafter\@testopt
  \else
    \@x@protect#1%
  \fi}

In this case the conditional returns true, so TeX is presented with

\@testopt \optionalexample \\optionalexample {default}

What does \@testopt do? Here it is:

% latex.ltx, line 617:
\long\def\@testopt#1#2{%
  \kernel@ifnextchar[{#1}{#1[{#2}]}}

and this is the culprit! During a \write only macro expansion is performed, not assignments, so \kernel@ifnextchar cannot work, because it does \futurelet in order to scan the following token.

  • "they must perform assignments in order to produce their replacement text" isn't really clear to me. Is there a comprehensive description of what is going on internally when defining optional arguments anywhere on SE? Anyway: xparse is doing precisely what I need. Thanks a lot! – Florian Jun 4 '15 at 8:52
  • 1
    @Florian I added some comments and a link – egreg Jun 4 '15 at 9:08

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.