[Tex/LaTex] Write environment body verbatim to a file

verbatimwrite 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?

Best Answer

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).