Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

Say I have a writer and an environment (actually an Environ) defined as

\documentclass{article}
\usepackage{environ} % www.ctan.org/pkg/environ
\newwrite\mywriter
\NewEnviron{writethis}
    {\immediate\write\mywriter{\BODY}}
\begin{document}
\immediate\openout\mywriter=writehere.txt
...
\immediate\closeout\mywriter
\input{writehere.txt}
\begin{document}

What I want to do is copy everything in a writethis environment to writehere.txt and include it in the document later on.

It becomes problematic when I want to write a backslash. Not just a \textbackslash or $\backslash$ (in math mode) but one that can be used to write commands such as in \textbf{abc}. (The compiler refuses to write a \ via \textbackslash.)

I know of the solution

\makeatletter
\begin{writethis}\@backslashchar textbf{abc}\end{writethis}
\makeatother

but it would be really tedious to write \makeatletter...\makeatother every time I need a \. Somewhat naively, I tried to define a command to replace the above:

\newcommand\back
    {\makeatletter\@backslashchar\makeatother}

for the sake of writing simply

\begin{writethis}\back textbf{abc}\end{writethis}

but the compiler refuses. (It says Improper alphabetic constant. \spacefactor, I have no clue why this \spacefactor pops up.)

So here is my question:

Is there a way to write a \ to a file, shorter than \makeatletter\@backslashchar\makeatother?

This may have something to do with this question (perhaps even a duplicate?). I read it but didn't understand how to use Philippe Goutet's solution.

share|improve this question
2  
Isn't \immediate\write\mywriter{\detokenize\expandafter{\BODY}} what you need? –  egreg Jul 16 at 14:11
    
@egreg works perfect! You can post an answer if you want. –  barto Jul 16 at 14:14

2 Answers 2

up vote 9 down vote accepted

You want an “almost verbatim” write:

\documentclass{article}
\usepackage{environ} % www.ctan.org/pkg/environ

\newwrite\mywriter
\NewEnviron{writethis}
    {\immediate\write\mywriter{\unexpanded\expandafter{\BODY}}}
\begin{document}

\immediate\openout\mywriter=\jobname-later.tex
\begin{writethis}\textbf{abc}\end{writethis}
\immediate\closeout\mywriter

Something

\input{\jobname-later}
\end{document}

Here's the contents of \jobname-later (I use \jobname not to clobber my files, use whatever name you prefer):

\textbf {abc}

The space will be ignored in input.

If you want to add fixed text before and after the contents of the environment, do

\NewEnviron{writethis}{%
  \immediate\write\mywriter{%
    \unexpanded{<before>}%
    \unexpanded\expandafter{\BODY}}%
    \unexpanded{<after>}%
  }%
}

where <before> and <after> stand for arbitrary TeX code. You don't want \expandafter for them, in general, which is needed in the middle term in order to get the expansion of \BODY.

share|improve this answer
    
I was playing around a bit, and strangely things like \immediate\write\mywriter{\unexpanded\expandafter{\textbf{abc}\BODY}} do not work. But it's just a remark, I don't need it for my purposes. (It can be solved by placing the \textbf{abc} in a seperate \unexpanded\expandafter.) –  barto Jul 16 at 14:35
    
@barto Of course it doesn't work: you're just expanding \textbf and not \BODY, which is then written literally in the output file. You don't need \expandafter for writing \textbf{abc} before the body; I'd rather say you don't want it. –  egreg Jul 16 at 14:37
    
Oh well. I'm not such a TeXpert –  barto Jul 16 at 17:51

You've already given egreg the tick for the easy part-) so I'll answer

I have no clue why this \spacefactor pops up.)

You have

\newcommand\back
    {\makeatletter\@backslashchar\makeatother}

\makeatletter changes the catcode of @ to make it a letter but catcodes affect the conversion of input characters to tokens. they have no effect on tokens that have already been read.

The argument to \newcommand has already been read tokenized and stored using the catcodes in force at this point so the definition is (showing one token per line)

\makeatletter
\@
b%
a%
a%
c%
k%
s%
l%
a%
s%
h%
c%
h%
a%
r%
\makeatother

so when \back is used \makeatletter executes but it has no effect on following tokens so the next token to execute is \@ which is designed to be used next to a . to affect the sentence space, its definition is

\def\@{\spacefactor\@m}

so you end up trying to assign 10000 to \spacefactor in vertical mode. the solution (in general, although in this case the problem can be avoided in different ways) is to change the catcodes while making the definition not while using it so:

\makeatletter
    \newcommand\back
        {\@backslashchar}
\makeatother
share|improve this answer
    
wouldn't \protect\xxx or \string\xxx work? or would it only survive just one expansion when more are needed? (no time to experiment.) –  barbara beeton Jul 16 at 15:03
    
Waw, I didn't expect that to work. I'd think the compiler refuses when being asked to write (or being referenced to) \@backslashchar in a non-atletter 'environment', but apparently we can just do this. I'll keep egreg's answer as the accepted because it is the easiest way, but thanks for shedding light on this approach! –  barto Jul 16 at 17:50
    
@barto it's just the same as (say) \section that expands to a definition based on \@startsection it doesn't stop working when @ is not a letter, so long as it's a letter when \section is defined. You should give the tick to me, egreg is always so happy when I steal a tick from him. –  David Carlisle Jul 16 at 18:22

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.