# Verbatim in environ’s \BODY

I’d like to print a TeX install guide for different OS, but the most text is the same for all OS. So I build the following

\documentclass{article}

\usepackage{environ}
\newcommand{\mlw}[3]{}
\NewEnviron{multichaps}{%
\renewcommand{\mlw}[3]{##1}%
\BODY
\renewcommand{\mlw}[3]{##2}%
\BODY
\renewcommand{\mlw}[3]{##3}%
\BODY
}

\begin{document}
\begin{multichaps}
\section{Installation on \mlw{Mac}{Windows}{Linux}}
Now it's time to test the system. Create a file
test.tex with the follwoing content.
\begin{verbatim}
\documentclass{article}

\begin{document}
Hallo World!
\end{document}
\end{verbatim}
and call \verb+pdflatex test+
\end{multichaps}
\end{document}


With \mwl I can set text to appear only in the text of one OS or different texts for different OS. Everything works fine but it crashes when I try to use verbatim inside the body.

Is it possible to do this or are there other ways to do something like this?

-
I get an error even without all of \mlw. Perhaps newverbs is a solution. Instead of \renewcommanding I think it would be better to define a keycommand with boolean options. The \BODY will IMHO be printed thrice, is this correct? –  Speravir Apr 9 '12 at 2:19
BTW I would appreciate a more realistic MWE (more related to your real code). Now I cannot really imagine your aim. –  Speravir Apr 9 '12 at 2:37
Is there a requirement to use verbatim? Or, why wouldn't \ttfamily suffice? –  Werner Apr 9 '12 at 4:48
@Speravir: I changed the example, hope it’s ok now. The problem isn’t the \mlw it’s {verbatim} together with environ. The \mwl think works fine but I wanted to show it and ask for other ideas besides environ. –  Tobi Apr 9 '12 at 8:13
environ environments are no real environments. I call the pseudo-environments. They actually read the whole content like a macro, so verbatim material does not work inside them. –  Martin Scharrer Apr 9 '12 at 9:41

The environ environments read their content in one go like a macro and are therefore no "real" environments, but rather pseudo-environments (looks like an environment, works like a macro). This does not allow for verbatim content, as with normal macros. The content is read before the verbatim mode can be enables, so all code is already parsed and categorized.

Instead you need to use a normal environment and then replicate the content several times. Usually this can be done by storing the content in a savebox, but your three alternatives do not allow for this, because boxing will fix the content. Instead you should write the content to an external file and read it in multiple times. This can be done automatically without the need for manual filecontents environments. An easy way is provided by the listings package as shown by me in Write environment body verbatim to a file.

\documentclass{article}

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

\newcommand{\mlw}[3]{}
\newcommand{\mlwa}[3]{#1}
\newcommand{\mlwb}[3]{#2}
\newcommand{\mlwc}[3]{#3}

\lstnewenvironment{multichaps}{%
% Write file to given filename
\lst@BeginWriteFile{\jobname.mul}%
}
{%
\lst@EndWriteFile% closes output file
\let\mlw\mlwa
\input{\jobname.mul}%
\let\mlw\mlwb
\input{\jobname.mul}%
\let\mlw\mlwc
\input{\jobname.mul}%
}
\makeatother

\begin{document}

\begin{multichaps}
\section{Installation on \mlw{Mac}{Windows}{Linux}}
Now it's time to test the system. Create a file
test.tex with the follwoing content.
\begin{verbatim}
\documentclass{article}

\begin{document}
Hallo World!
\end{document}
\end{verbatim}
and call \verb+pdflatex test+
\end{multichaps}

\end{document}


Alternative, you can store the content verbatim in a macro and reevaluate it using e-TeX's \scantokens, which is basically the same as to write it into an external file and rereading it, but more efficient. One issue here seems the handling of end-of-line (EOF) characters. The content can be stored in a macro e.g. using my newverbs package. However, it does not provide an environment variant yet, so you need to use the macro version:

\documentclass{article}

\usepackage{newverbs}

\newcommand{\mlw}[3]{}
\newcommand{\mlwa}[3]{#1}
\newcommand{\mlwb}[3]{#2}
\newcommand{\mlwc}[3]{#3}

\makeatletter
\newcommand{\multichaps}{%
\begingroup
\expandafter\Collectverb\expandafter\@multichaps\expandafter
}

% The EOL character must be active to work with 'verbatim'.
% By default it should produce a space.
% This will break implicit paragraphs!
\begingroup
\catcode13=\active%
\gdef\activenl{%
\catcode13=\active%
\let^^M\space%
}%
\endgroup%

\newcommand{\@multichaps}[1]{%
\activenl
\let\mlw\mlwa
\scantokens{#1}%
\let\mlw\mlwb
\scantokens{#1}%
\let\mlw\mlwc
\scantokens{#1}%
\endgroup
}
\makeatother

\begin{document}

\multichaps=
\section{Installation on \mlw{Mac}{Windows}{Linux}}
Now it's time to test the system. Create a file
test.tex with the follwoing content.
\begin{verbatim}
\documentclass{article}

\begin{document}
Hallo World!
\end{document}
\end{verbatim}
and call \verb+pdflatex test+
=

\end{document}

-
Thanks! Especially for the explanation for about environ :-) –  Tobi Apr 9 '12 at 11:13
@Tobi: This environ issue was, what I thought of), and therefore suggested the use of newverbs. Fortunately Martin as the author himself provided a solution, because I did not understand all of the documentation. (@Martin: Maybe some examples for the several commands?) –  Speravir Apr 9 '12 at 16:06

In ConTeXt, the standard way to store and manipulate body environment without storing it as a macro is to use buffers. For example, this is how the same macro could be written in ConTeXt and it works as expected.

\let\mlw\gobblethreearguments

\def\startmultichapters
{\grabbufferdata[multichapters][startmultichapters][stopmultichapters]}

\def\stopmultichapters
{\let\mlw\firstofthreearguments
\getbuffer[multichapters]%
\let\mlw\secondofthreearguments
\getbuffer[multichapters]%
\let\mlw\thirdofthreearguments
\getbuffer[multichapters]%
\let\mlw\gobblethreearguments}

\starttext
\startmultichapters
\startsection[title={\mlw{foo}{bar}{baz}}]
This is some text in section \mlw{foo}{bar}{baz}
\starttyping
Crash
\stoptyping
\stopsection
\stopmultichapters
\stoptext


Note: If you are using an older version of ConTeXt (before Feb, 2012), then you need to replace \grabbufferdata with \dostartbuffer.

AFAIK, LaTeX does not have an equivalent of ConTeXt buffers. The closest approximation is to use the filecontents environment to write the contents to an external file (In MkII, ConTeXt buffers also wrote content to external files; but in MkIV, the content is kept in memory). See Taco Hoekwater's answer to LaTeX equivalent of ConTeXt buffers.

-

Sometime one misses the forest for the trees … I didn’t thougt about putting the contets to an external file an include it three times …

\begin{filecontents}{multichapsbody.tex}
\section{Installation on \mlw{Mac}{Windows}{Linux}}
Now it's time to test the system. Create a file
test.tex with the follwoing content.
\begin{verbatim}
\documentclass{article}

\begin{document}
Hallo World!
\end{document}
\end{verbatim}
and call \verb+pdflatex test+
\end{filecontents}

\documentclass{article}

\newcommand{\mlw}[3]{}

\begin{document}
\renewcommand{\mlw}[3]{#1}
\input{multichapsbody}

\renewcommand{\mlw}[3]{#2}
\input{multichapsbody}

\renewcommand{\mlw}[3]{#3}
\input{multichapsbody}
\end{document}

-