8

I have a local class that a number of people use. One of the new things I want it to do is write out various user-defined data to a file, so that a follow-up LaTeX document can do something different, but with the same user-defined parameters. I'm somewhat new to reading and writing external files, so my question may be elementary.

Here's an MWE that demonstrates the problem:

\documentclass{article}
\begin{document}
%% USER CONTROLS THIS DEFINITION
\def\userdef{abc}        % Works Great
%\def\userdef{abc\\def}  % Breaks \write
%% I CONTROL THE FOLLOWING
\def\userdefContent{\noexpand\def\noexpand\userdef{\userdef}}%
\newwrite\tempfile%
\immediate\openout\tempfile=userdata.tex
\immediate\write\tempfile{\userdefContent}
\immediate\closeout\tempfile
\end{document}

The user defines some known variable using a \def and I'd like to write it to a file in the form of \def\userdef{blah blah blah} where blah blah blah is how the user defined it. In this way, I can \input it into another file and have that second document pre-initialized with the same data the user defined for the first round.

The problem is that there are some user variables I want to write that may be populated with \\ characters which, apparently, break the \write. Uncomment the one line in the MWE to demonstrate this.

I am flexible on a solution. Ideally, I would like my output file to contain

\def \userdef {abc\\def}

but I would be willing to settle for

\def \userdef {abc*LINEFEED*def}

where *LINEFEED* is an arbitrary string sequence to alert me that I will later need to stick back in a \\. I would even, as a last resort, settle for

\def \userdef {abc def}

where the \\ has been stripped.

I suppose I would, if there were no other solution, instruct the userbase not to use \\ in their \def but some other macro that I define (which I can then redefine prior to the \write). But I think they might resist this last approach. I also would resist it, because it would break backward compatibility to older documents.

I am also open to a totally different approach, if there is a standard LaTeX way of transferring data between different documents. I would add that I have a stringstings solution that works when \userdef is composed purely of catcode 11 and 12 material and \\ characters, but I can't guarantee in advance that the user won't stick some other macros in his \def.

1 Answer 1

11

You have to disable the expandability of \\ when doing the write. But in general \write is problematic when "free" input is allowed: \textbf or similar commands will surely break.

It's better to build an "immediate" version of \protected@write:

\documentclass{article}
\usepackage{xpatch}
\makeatletter
% get a copy of `\protected@write
\let\protected@iwrite\protected@write
% patch the copy to add \immediate
\xpatchcmd{\protected@iwrite}{\write}{\immediate\write}{}{}
\makeatother

\newwrite\tempfile

\begin{document}
\def\userdef{abc\\def}  % Breaks \write

\immediate\openout\tempfile=userdata.tex
\makeatletter
\protected@iwrite\tempfile{\let\\\relax}{\userdef}
\immediate\closeout\tempfile
\makeatother

\end{document}

Note that \protected@iwrite has, like its sibling, a second argument where declarations can be performed to change the meaning of commands for the scope of the write; in this case I set \\ equal to \relax so it becomes unexpandable. Without this the output would be

abc\protect \\def

With the temporary assignment it is

abc\\def

as desired.

A possible simplification is using the same method LaTeX uses for \typeout (thanks to David Carlisle for suggesting it):

\documentclass{article}
\makeatletter
\def\protected@iwrite#1#2#3{%
  \begingroup\set@display@protect
  #2% local assignments
  \immediate\write#1{#3}\endgroup}
\makeatother

\begin{document}
\def\userdef{abc\\\textbf{def}}

\immediate\openout\tempfile=userdata.tex
\makeatletter
\protected@iwrite\tempfile{}{\def\protect\userdef{\userdef}}
\immediate\closeout\tempfile
\makeatother

\end{document}

The output is \def\userdef{abc\\\textbf {def}}. Notice that also \textbf is OK. Fragile commands need \protect, of course.

7
  • I am still not able to overcome one impediment with this approach. When I give the argument to the iwrite as {\noexpand\def\noexpand\userdef{\userdef}} hoping to get \def\userdef{abc\\def} in the file, I instead get \def abc\\def{abc\\def} Apr 26, 2013 at 15:02
  • @StevenB.Segletes {\def\noexpand\noexpand\noexpand\userdef{\userdef}}
    – egreg
    Apr 26, 2013 at 15:08
  • @StevenB.Segletes \noexpand isn't a LaTeX command, use \protect (also \def isn't expandable anyway) so \protected@iwrite\tempfile{\let\\\relax}{\def\protect\userdef{\userdef}} Apr 26, 2013 at 15:11
  • @StevenB.Segletes oops our comments crossed I told you not to use \noexpand and egreg said to use three of them. (we said same thing really though). Apr 26, 2013 at 15:13
  • @DavidCarlisle "Ditto." Indeed, I thought a Clash of the Titans was about to unfold. Apr 26, 2013 at 15:13

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .