%D \module
%D   [      file=t-ltenv,
%D        version=2005.07.xx,
%D          title=\CONTEXT\ User Module,
%D       subtitle=\LaTeX\ compatibility environments,
%D         author=Brooks Moses,
%D           date=\currentdate,
%D      copyright={Brooks Moses; The LaTeX3 Project}]

%D This \ConTeXt\ module is part of the \LaTeX-compatibility
%D module set.  It provides \type{\begin} and \type{\end}
%D interfaces to environments, including ones which use 
%D \type{\grabuntil}.

\usemodule[ltbase]
\unprotect

%D \section{Environments}
%D
%D \ConTeXt\ uses the \type{\start...} / \type{\stop...} idiom for 
%D delineating environments, while \LaTeX\ uses the \type{\begin{...}}
%D / \type{\end{...}} idiom.  The following code provides a translation
%D between these two idioms, allowing many (but not all) \ConTeXt\
%D environments to also be used in \LaTeX\ form.

%D The \end of a \begin,\end pair is problematic, since \stoptext
%D depends on TeX's \end.  We fix that as follows, using the 
%D \type{\everystoptext} hook.  (Note that some versions of \ConTeXt\
%D have already redefined \type{\end}, but this should all work out.

\let\@@end=\end
\appendtoks
  \let\end=\@@end
\to \everystoptext

%D Some environments use a macro which collects the body of the
%D environment, and passes it as an argument to another macro.  Since
%D these depend on the literal text ending the environment, they do not
%D translate automatically from one form to the other.  Thus, we need
%D to redefine \ConTeXt's \type{\grabuntil} to handle the situation.

%D First, save the \ConTeXt\ definition so that we can return to it.

\let\@contextgrabuntil\grabuntil

%D Redefining \type{\grabuntil} is a tricky business when we consider
%D nesting environments, as it needs to be reset to the \ConTeXt\ 
%D version before any \ConTeXt environments enclosed in the body of
%D the environment are processed, but after the \type{\start...}
%D command -- but we cannot place anything after the \type{\start...}
%D command in \type{\begin}, because that will interfere with 
%D argument processing.
%D
%D The only place, then, that we can reliably place the hook to do the
%D redefinition is in the next \type{\grabuntil} to be processed after
%D the beginning of the \type{\start...} macro.  It is important to note,
%D however, that this may very well not occur in the environment being
%D accessed via \type{\begin}, but may be in an enclosed \ConTeXt-form
%D environment!  Thus, \type{\latexgrabuntil} is not really the \LaTeX\
%D form, but a switch that determines whether it is being called in 
%D the \LaTeX-form environment (by comparing \type{\@currentenv} to its
%D argument), and then switches between the two forms.
%D
%D This appears to fail in the case where one embeds a \ConTeXt\ form
%D of an environment inside a \LaTeX\ form of the same environment, but
%D we note that this will only cause a problem if the former uses 
%D \type{grabuntil} but the latter does not -- otherwise, either the 
%D former will not use \type{\grabuntil} at all, or else the latter will
%D have already restored it before the former is expanded.

\def\@switchgrabuntil#1{%
  \let\grabuntil\@contextgrabuntil
  \bgroup
  \edef\reserved@a{stop\@currenvir}%
  \edef\reserved@b{#1}%
  \ifx\reserved@a\reserved@b
    \def\reserved@a{\@latexgrabuntil{#1}}%
  \else
    \def\reserved@a{\@contextgrabuntil{#1}}%
  \fi
  \expandafter\egroup\reserved@a}

%D The \LaTeX\ version of \type{\grabuntil}, then, uses code borrowed
%D from AMSmath's \type{\collect@body} function.  The following comments
%D are directly from \type{amsmath.dtx}, version 2.13, with only minor
%D changes.
%D
%D [Note that \type{\@EA} is ConTeXt's abbreviation for
%D \type{\expandafter}, replacing AMStex's \type{\@xp}.]

%D We start by defining a token register to contain the body.  Also, we
%D duplicate the definition of \type{\@emptytoks} from \type{amsgen.tex}.

\newtoks\@emptytoks
\newtoks\@envbody

%D Then we define a macro to add something (i.e. its argument) to the
%D token register \type{\@envbody}.

\def\addto@envbody#1{\global\@envbody\@EA{\the\@envbody#1}}

%D The macro \type{\grab@@until} starts the scan for the 
%D \type{\end{...}} command of the current environment. It takes a macro
%D name as argument. This macro is supposed to take the whole body of the
%D environment as its argument. For example, \type{\begin{align}} would
%D call \type{\grab@@until\@align} if \type{\@align#1{...}} is the macro
%D that sets the alignment with body \type{#1}.
%D
%D [Note that we take the name of the \type{\stop...} command as an 
%D argument, and discard it in favor of \type{\@currenvir}.]
%D
%D [Also, the AMSmath version of this runs the \type{\end{...}} command
%D after the body, whereas the \ConTeXt version does not.  For
%D consistency, we have changed this version so that it explicitly
%D \type{\let}s the \type{\stop...} command to relax, so that there will
%D not be errors when \type{\end{...}} calls it.  (Earlier, we simply
%D didn't call the \type{\end{...} macro, but now it has other things in
%D it besides the \type{\egroup} that need to be called.)]

\def\@latexgrabuntil#1#2{%
  \@envbody{\@EA#2\@EA{\the\@envbody}}%
  \expandafter\let\csname stop\@currenvir\endcsname\relax
  \edef\process@envbody{\the\@envbody\noexpand\end{\@currenvir}}%
  \@envbody\@emptytoks \def\begin@stack{b}%
%
%D [Skip notes on clever error-message hack.]
%
  \begingroup
  \@EA\let\csname\@currenvir\endcsname\collect@@body
  \edef\process@envbody{\@EA\noexpand\csname\@currenvir\endcsname}%
  \process@envbody
}

%D When adding a piece of the current environment's contents to 
%D \type{\@envbody}, we scan it to check for additional \type{\begin}
%D tokens, and add a `b' to the stack for any that we find.

\def\push@begins#1\begin#2{%
  \ifx\end#2\else b\@EA\push@begins\fi
}

%D \type{\collect@@body takes two arguments: the first will consist of
%D all text up to the next \type{\end} command, the second will be the 
%D \type{\end} command's argument.  If there are any extra \type{\begin}
%D commands in the body text, a marker is pushed onto the stack by the
%D \type{\push@begins} function.  Empty state for this stack means that
%D we have reached the \type{\end} that matches our original
%D \type{\begin}.  Otherwise we need to include the \type{\end} and its
%D argument in the material that we are adding to our environment body
%D accumulator.

\def\collect@@body#1\end#2{%
  \edef\begin@stack{\push@begins#1\begin\end \@EA\@gobble\begin@stack}%
  \ifx\@empty\begin@stack
    \endgroup
    \@checkend{#2}%
    \addto@envbody{#1}%
  \else
    \addto@envbody{#1\end{#2}}%
  \fi
  \process@envbody % A little tricky! Note the grouping
}

%D With that out of the way, the actual translation macros are 
%D relatively straightforward.  (Much of this is taken from
%D \type{ltmiscen.dtx), though the \type{\grabuntil} part is
%D new.)  We leave out the \LaTeX-specific error messages, for
%D simplicity and to avoid unneeded dependencies.

\def\begin#1{%
  \def\reserved@a{%
    \def\@currenvir{#1}%
    \edef\@currenvline{ on input line \the\inputlineno}%
    \let\grabuntil\@switchgrabuntil
%    \let\grabuntil\@latexgrabuntil
    \csname start#1\endcsname}%
  \@ignorefalse 
  \begingroup\@endpefalse\reserved@a}

\def\end#1{%
  \csname stop#1\endcsname\@checkend{#1}%
  \expandafter\endgroup\if@endpe\@doendpe\fi
  \if@ignore\@ignorefalse\ignorespaces\fi}

\def\@checkend#1{\def\reserved@a{#1}\ifx
      \reserved@a\@currenvir \else\@@badend{#1}\fi}

%D We put in a \type{\@@badend} command that will use the error
%D message from \type{t-lterr} if loaded, or a generic and not
%D particularly useful error message if not.
%D
%D ### To Do: is this better than nothing?  Doesn't \ConTeXt\
%D have a better way?

\def\@@badend#1{%
  \ifundefined{@badend}
    \errmessage{Mismatched LaTex-compatibility environment end.}
  \else
    \@badend
  \fi}

%D We need to bring in the \type{\if@endpe} from \type{ltlists.dtx},
%D so that we don't require dependency on \type{t-ltlist}.

\newif\if@endpe
\@endpefalse

%D These are apparently not done with \type{\newif} so that they
%D can be global.
%D
%D ### To Do: \ConTeXt\ probably has a built-in handler for this.

\def\@ignorefalse{\global\let\if@ignore\iffalse}
\def\@ignoretrue {\global\let\if@ignore\iftrue}
\@ignorefalse

\let\ignorespacesafterend\@ignoretrue 


\protect