# Write environment body verbatim to a file

How can one write the body of an environment verbatim to an external file. I tried the following but get problems if the body contains undefined macros (error) or e.g. a % (disappears in the output).

Try 1
Using environ to get the environment content.

\ProvidesPackage{tofile1}

\RequirePackage{environ}

% counter for external files
\newcounter{TF@File}

\newwrite\TF@out

\NewEnviron{tofile}{%
\stepcounter{TF@File}
\edef\TF@outFile{ext-\jobname-\theTF@File.tex}
\typeout{Name: \TF@outFile}
\immediate\openout\TF@out=\TF@outFile
\typeout{\TF@outFile\space opened}
\immediate\write\TF@out{\BODY}
\typeout{\TF@outFile\space written}
\immediate\closeout\TF@out
\typeout{\TF@outFile\space closed}
}


% test.tex
\documentclass{article}

\usepackage{tofile1}

\begin{document}
Test

\begin{tofile}
That's {a short Test}
which works
but ignores line breaks
\end{tofile}

Text

\begin{tofile}
\xx That's {another Test}%
This one doesn't work ...
it gives an error because \xx is undefined
\end{tofile}
\end{document}


This one creates the two desired files ext-test-1.tex and ext-test-1.tex but linebreaks are ignored and an undefined control sequence (\xx) causes an error. Furthermore the percent char is interpreted as comment not as simple character. I guess come catcode magic could help.

Try 2
Using the filecontents package.

\ProvidesPackage{tofile2}

\RequirePackage{environ}
\RequirePackage{filecontents}

% counter for external files
\newcounter{TF@File}

\newwrite\TF@out

\newenvironment{tofile}{%
\stepcounter{TF@File}
\edef\TF@outFile{ext-\jobname-\theTF@File.tex}
\begin{filecontents}{\TF@outFile}
}{
\end{filecontents}
}


Same test file as above ...


This one creates only the first file ext-test-1.tex and the an error occurs because the end of filecontens can’t be determined correctly.

Is there another way do do this, maybe a package?

-
The reason why the filecontents solutions doesn't work is that it looks for \end{filecontents} verbatim and can't find it inside \end{tofile}. In general you can't include verbatim macros or environments in other macros or environments. –  Martin Scharrer Dec 10 '11 at 11:43
@MartinScharrer: Yea, I thought so … –  Tobi Dec 10 '11 at 14:58
have a look at the answers package too –  cmhughes Dec 10 '11 at 16:14
About writing % into a file see also tex.stackexchange.com/q/34390/6865 –  Stephen Dec 10 '11 at 17:13

You can look at the definition of verbatimwrite in verbatim.sty or use the facilities provided by the fancyvrb package:

\documentclass{article}

\usepackage{fancyvrb}
\newenvironment{tobiwrite}[1]
{\typeout{Writing file #1}\VerbatimOut{#1}}
{\endVerbatimOut}

\begin{document}
\begin{tobiwrite}{tobi.txt}
a

b
c
\end{tobiwrite}
\end{document}


Instead of \typeout you can do whatever you want (for example, checking whether the file already exists with \IfFileExists).

-
@MartinScharrer, egreg: Thank you both seems like both answers math my questions. Could you pleas figure out the differences if there are any? –  Tobi Dec 10 '11 at 14:59
@Tobi A very late answer, but it seems I missed seeing your comment. What are the differences? Well, listings loads fancyvrb, first of all. However, the definition of \lst@BeginWriteFile is different from \VerbatimOut, since many more settings are necessary for supporting the full power of listings. If you're only interested in verbatim copy, \VerbatimOut is more efficient. –  egreg Feb 2 '13 at 16:28
Thank you :-) ... –  Tobi Feb 2 '13 at 16:56

It is possible to use internal macros from the listings package to do this.

\documentclass{article}

\makeatletter
\RequirePackage{listings}
\lst@RequireAspects{writefile}

\lstnewenvironment{yourenv}{%
% some code before
% including \lstset{..}
% Write file to given filename
\lst@BeginWriteFile{\jobname.txt}%
}
{%
\lst@EndWriteFile% closes output file
}
\makeatother

\begin{document}
% ...
\end{document}


Compare with the similar code I provided in my answers to the following questions:
LaTeX documentation with verbatim environment
How to use a \write command inside a \newenvironment ?

-
Hi, is it possible to remove an indention (white space at the beginning of the line) while writing the file? –  Tobi Nov 10 '14 at 22:55
@Tobi: Have a look at listings gobble option. Not sure if it works with writting files. –  Martin Scharrer Nov 11 '14 at 17:43
Hm … Seems like the gobble function is hard wired with the user level macros and can’t be used with \lst@BeginWriteFile –  Tobi Nov 13 '14 at 12:44