4

When looking inside the filecontents environment in the file latex.ltx (or the similar version in filecontents.sty), I have found this code that I can not understand:

  \edef\E{\@backslashchar end\string{\@currenvir\string}}%
  \edef\reserved@b{%
    \def\noexpand\reserved@b%
         ####1\E####2\E####3\relax}%
  \reserved@b{%
    \ifx\relax##3\relax%
      \immediate\write\reserved@c{##1}%
    \else%
      \edef^^M{\noexpand\end{\@currenvir}}%
      \ifx\relax##1\relax%
      \else%
          \@latex@warning{Writing text `##1' before %
             \string\end{\@currenvir}\MessageBreak as last line of #1}%
        \immediate\write\reserved@c{##1}%
      \fi%
      \ifx\relax##2\relax%
      \else%
         \@latex@warning{%
           Ignoring text `##2' after \string\end{\@currenvir}}%
      \fi%
    \fi%
    ^^M}%
  \catcode`\^^L\active%
  \let\L\@undefined%
  \def^^L{\expandafter\ifx\csname L\endcsname\relax\fi ^^J^^J}%
  \catcode`\^^I\active%
  \let\I\@undefined%
  \def^^I{\expandafter\ifx\csname I\endcsname\relax\fi\space}%
  \catcode`\^^M\active%
  \edef^^M##1^^M{%
    \noexpand\reserved@b##1\E\E\relax}}%

This environment is provided to write some text in a file. After transforming all catcode to 12 (characters) the text is written in the file with the command \reserved@b. I have a lot of trouble with this coding:

  1. Why there is some recursive coding?

    \edef\reserved@b{%
        \def\noexpand\reserved@b%
             ####1\E####2\E####3\relax}%
    
  2. What is the role of the parameter delimiter \E which is \end{filecontents}

  3. Why the end of line (^^L) is transformed in \end{filecontents}

Any help about the fine tricks used in this code will be greatly appreciated.

Joseph Wright
  • 259,911
  • 34
  • 706
  • 1,036
Alan
  • 41

1 Answers1

4

Taking the three questions in order:

Historically, the number of macro names available was quite limited. It was therefore useful to re-use the same names over and over again. In the LaTeX kernel, \reserved@a, etc., are meant to be 'for the team only, with \@tempa (see What macros should be used as 'scratch space'? and @tempdima, reserved@a, @tempcnta, what else? for more on this). The fragment

\edef\reserved@b{%
    \def\noexpand\reserved@b%
         ####1\E####2\E####3\relax}%

uses \reserved@b as a throw-away macro to define \reserved@b in a different way: it could be done with a different name and is not recursive. The idea is that we need to \edef 'something' to set up \reserved@b correctly.

That leads us nicely to the second question. In the above, \E has been defined a little earlier by

\edef\E{\@backslashchar end\string{\@currenvir\string}}

Thus when it expands, we get \E replaced by \end{<envname>}. That is used in creating a \reserved@b that looks like

> \reserved@b=macro:
->\def \reserved@b ####1\end{<envname>}####2\end{<envname>}####3\relax .

As you can see, the \edef means that \E is no longer there: it's another throw-away macro name, and could have been done using something else.

The strange definition of ^^L is to allow a warning message to be produced from a setting in an expansion context. We have later

\gdef\endfilecontents{|
  \immediate\closeout\reserved@c
  \def\T##1##2##3{|
  \ifx##1\@undefined\else
    \@latex@warning@no@line{##2 has been converted to Blank ##3e}|
  \fi}|
  \T\L{Form Feed}{Lin}|
  \T\I{Tab}{Spac}|
  \immediate\write\@unused{}}

which means that if \L is defined there is a warning. But how to define \L? Tha's done with

\def^^L{\expandafter\ifx\csname L\endcsname\relax\fi ^^J^^J}%

As \csname will turn an undefined control sequence to \relax, this lets us set a 'flag' that a line feed was seen even though it happens in a \write. (We have a similar trick in expl3 in a general form.)

Joseph Wright
  • 259,911
  • 34
  • 706
  • 1,036