% \iffalse meta-comment
%<=*COPYRIGHT>
%% Copyright (C) 2012 by Martin Scharrer <martin@scharrer-online.de>
%% --------------------------------------------------------------------
%% This work may be distributed and/or modified under the
%% conditions of the LaTeX Project Public License, either version 1.3
%% of this license or (at your option) any later version.
%% The latest version of this license is in
%%   http://www.latex-project.org/lppl.txt
%% and version 1.3 or later is part of all distributions of LaTeX
%% version 2005/12/01 or later.
%%
%% This work has the LPPL maintenance status `maintained'.
%%
%% The Current Maintainer of this work is Martin Scharrer.
%%
%% This work consists of the files multienv.dtx and multienv.ins
%% and the derived filebase multienv.sty.
%%
%<=/COPYRIGHT>
% \fi
%
% \iffalse
%<*driver>
\ProvidesFile{multienv.dtx}[%
%<=*DATE>
    2012/05/20
%<=/DATE>
%<=*VERSION>
    v1.0
%<=/VERSION>
    DTX file for multienv.sty]
\documentclass{ydoc}
\GetFileInfo{multienv.dtx}
\usepackage{multienv}[\filedate]
\providecommand\enquote[1]{``#1''}
\EnableCrossrefs
\CodelineIndex
\RecordChanges
\OnlyDescription
\optionaloff
\begin{document}
  \DocInput{\jobname.dtx}
  \PrintChanges
  \PrintIndex
\end{document}
%</driver>
% \fi
%
% \CheckSum{297}
%
% \CharacterTable
%  {Upper-case    \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
%   Lower-case    \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
%   Digits        \0\1\2\3\4\5\6\7\8\9
%   Exclamation   \!     Double quote  \"     Hash (number) \#
%   Dollar        \$     Percent       \%     Ampersand     \&
%   Acute accent  \'     Left paren    \(     Right paren   \)
%   Asterisk      \*     Plus          \+     Comma         \,
%   Minus         \-     Point         \.     Solidus       \/
%   Colon         \:     Semicolon     \;     Less than     \<
%   Equals        \=     Greater than  \>     Question mark \?
%   Commercial at \@     Left bracket  \[     Backslash     \\
%   Right bracket \]     Circumflex    \^     Underscore    \_
%   Grave accent  \`     Left brace    \{     Vertical bar  \|
%   Right brace   \}     Tilde         \~}
%
%
% \changes{v1.0}{2012/05/20}{First release.}
%
% \DoNotIndex{\newcommand,\newenvironment}
%
% \GetFileInfo{multienv.dtx}
% \author{Martin Scharrer}
% \email{martin@scharrer-scharrer.de}
% \ifdefined\repository
%   \repository{https://bitbucket.org/martin_scharrer/multienv}
% \fi
%
% \maketitle
%
% \begin{abstract}\noindent
% This package provides a \env{multienv} environment which allows to
% easily add multiple environments using a key=value syntax.
% Macros to define environments using this syntax are also provided.
% \end{abstract}
%
% \section{Introduction}
% It is sometimes required to add multiple environments around some text
% in order to achieve a specific format. This macro simplifies this task
% especially for larger number of environments by allowing the environments
% and their arguments to be specified using a key=value syntax.
% A special \Key{add code} key is also provided to allow arbitrary code being
% added before and after the environment content.
% Furthermore macros are provided to allow the definition of new environments
% which contain multiple other environments and code.
%
% \section{Usage}
% \vspace{-3ex}
% \DescribeEnv[<content>]{multienv}{<env=arg>','<key=value>,\ldots}
% This environment takes a comma separated list of key=values where the keys are usually environment
% names and the values the arguments to this environment.
% The environments are added around the content in the given order, i.e.\ the first environment
% is the most outer one and further environments are placed inside it.
%
% At the moment only the following key is defined. Any other key is taken as an environment name.
%
% \DescribeKey{add code}={<code before>}{<code after>}
% This adds the given code before and after the content.
% Any code is permitted including macro argument tokens like `|#1|'.
%
% \DescribeKey{\meta{environment}}
% \DescribeKey{\meta{environment}}=<arguments>
% Any unknown key is taken as environment name and the value as argument(s) to the environment.
% If the value does not start with a brace `|{|', bracket `|[|' or angle `|<|' it is taken
% as a single mandatory argument and is placed inside braces after the environment,
% otherwise it is placed unchanged after the environment:
% \par\medskip\par\noindent
% \begin{tabular}{@{}l@{ $\Rightarrow$ }l@{}}
%   \Key{\meta{env}}         & \Macro\begin{<env>}\ldots\Macro\end{<env>} \\
%   \Key{\meta{env}}=        & \Macro\begin{<env>}\ldots\Macro\end{<env>} \\
%   \Key{\meta{env}}=<arg>   & \Macro\begin{<env>}{<arg>}\ldots\Macro\end{<env>} \\
%   \Key{\meta{env}}={<arg>} & \Macro\begin{<env>}{<arg>}\ldots\Macro\end{<env>} \\
%   \Key{\meta{env}}={<arg1>}{<arg2>} & \Macro\begin{<env>}{<arg1>}{<arg2>}\ldots\Macro\end{<env>} \\
%   \Key{\meta{env}}=[<oarg>] & \Macro\begin{<env>}[<oarg>]\ldots\Macro\end{<env>} \\
%   \Key{\meta{env}}=[<oarg>]{<marg>} & \Macro\begin{<env>}[<oarg>]{<marg>}\ldots\Macro\end{<env>} \\
%   \Key{\meta{env}}=<< <aarg> >> & \Macro\begin{<env>}<< <aarg> >>\ldots\Macro\end{<env>} \\
%   \Key{\meta{env}}=<< <aarg> >>{<marg>} & \Macro\begin{<env>}<< <aarg> >>{<marg>}\ldots\Macro\end{<env>} \\
%   \multicolumn{2}{@{}l@{}}{etc.} \\
% \end{tabular}
% \par\bigskip\par
%
% \DescribeEnv[<content>]{multienv*}{<env=arg>','<key=value>,\ldots}
% This environment is identical to \env{multienv} but will apply the keys in the reverse order,
% i.e.\ every environment or code is added around the existing environments or code.
%
%
% \DescribeMacro\newmultienvironment{<env name>}[<number of args>][<default value>]{<env=arg>,\ldots}
% This macro defines a new environment like \Macro\newenvironment does but uses the \env{multienv}
% syntax. The resulting environment will contain all given environments and code.
% The environment can have arguments including one leading optional argument.
% The arguments can be used as part of the keys and values.
% It should be noted that it is not allowed to use arguments in the second argument of
% the \Key{add code} key, because that code will be part of \Macro\end{<env name>}.
%
% An error is raised if the environment already exists.
%
% \DescribeMacro\renewmultienvironment{<env name>}[<number of args>][<default value>]{<env=arg>,\ldots}
% Like \Macro\newmultienvironment but can be used to redefine existing environments.
% It is is not relevant \emph{how} the environment was defined previously.
% An error is raised if the environment does not already exist.
%
%
% \DescribeMacro\providemultienvironment{<env name>}[<number of args>][<default value>]{<env=arg>,\ldots}
% Like \Macro\newmultienvironment but the environment is only defined if it is not already defined.
% The environment is also not defined if there a macro with the same name exists.
%
% \section{Examples}
% \lstset{gobble=4,language=[latex]tex}
% The following \env{multienv} environment usage:
% \begin{lstlisting}
%   \begin{multienv}{enva,envb=arg,add code={code before}{code after},
%       envc=[oarg]{marg}}
%     content
%   \end{multienv}
% \end{lstlisting}
% \noindent is basically identical to:
% \begin{lstlisting}
%   \begin{enva}
%     \begin{envb}{arg}
%       code before
%       \begin{enc}[oarg]{marg}
%          content
%       \end{enc}
%       code after
%     \end{envb}
%   \end{enva}
% \end{lstlisting}
% \noindent Using \env{multienv*} the order the environments can be given in the opposite order:
% \begin{lstlisting}
%   \begin{multienv}{envc=[oarg]{marg},add code={code before}{code after},
%       envb=arg,enva}
%     content
%   \end{multienv}
% \end{lstlisting}
%
% \par\bigskip\par\noindent
% The following code defines a \env{centeredminipage} environment which content is placed
% in a centered \env{minipage} which inner content is also centered.
% \begin{lstlisting}
%   \newmultienvironment{centeredminipage}[1]
%     {center,minipage=#1,add code={\centering}{}}
% \end{lstlisting}
% \par\noindent
% This is basically identical to:\par
% \begin{lstlisting}
%   \newenvironment{centeredminipage}[1]
%     {\begin{center}\begin{minipage}{#1}\centering}
%     {\end{minipage}\end{center}}
% \end{lstlisting}
% \par\noindent
% However actually the \enquote{plain} form of the environment are used, because it is more efficient
% and will also produce a correct error message if an incorrect \cs{end} macro is found:\par
% \begin{lstlisting}
%   \newenvironment{centeredminipage}[1]
%     {\begingroup\center\begingroup\minipage{#1}\centering}
%     {\endminipage\endgroup\endcenter\endgroup}
% \end{lstlisting}
% \par\noindent
% The groups are added because some environments require to be placed in a group by themselves,
% which is normally done by |\begin| and |\end|.
%
% \StopEventually{}
% \clearpage
% \section{Implementation}
%
% \iffalse
%<*multienv.sty>
% \fi
%    \begin{macrocode}
%<!COPYRIGHT>
\NeedsTeXFormat{LaTeX2e}[1999/12/01]
\ProvidesPackage{multienv}[%
%<!DATE>
%<!VERSION>
%<*DRIVER>
    2099/01/01 develop
%</DRIVER>
    Add multiple environments using a Key=value syntax]
%    \end{macrocode}
%
%
% \begin{macro}{\multienv}
%    \begin{macrocode}
\newcommand{\multienv}{%
    \begingroup
    \@ifstar{%
        \let\multienv@addcode\multienv@addcode@out
        \multienv@readkeys
    }{%
        \let\multienv@addcode\multienv@addcode@in
        \multienv@readkeys
    }%
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\endmultienv}
%    \begin{macrocode}
\def\endmultienv{\end@multienv\endgroup}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{environment}{multienv*}
%    \begin{macrocode}
\newenvironment{multienv*}{%
    \begingroup
    \let\multienv@addcode\multienv@addcode@out
    \multienv@readkeys
}{%
    \end@multienv\endgroup
}
%    \end{macrocode}
% \end{environment}
%
%
% \begin{macro}{\newmultienvironment}
%    \begin{macrocode}
\newcommand\newmultienvironment{%
    \let\@multi@environment\newenvironment
    \@multienvironment
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\renewmultienvironment}
%    \begin{macrocode}
\newcommand\renewmultienvironment{%
    \let\@multi@environment\renewenvironment
    \@multienvironment
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\providemultienvironment}
%    \begin{macrocode}
\newcommand\providemultienvironment{%
    \@ifstar
        {\@providemultienvironment*}%
        {\@providemultienvironment{}}%
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@providemultienvironment}
%    \begin{macrocode}
\def\@providemultienvironment#1#2{%
    \@ifundefined{#2}%
        {\newmultienvironment#1{#2}}%
        {\begingroup\tracingall\renewcommand\@tempa[1][]{\renewcommand\@tempa[1][]{\expandafter\endgroup\@gobble}\@tempa}\@tempa}%
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@multienvironment}
%    \begin{macrocode}
\def\@multienvironment{%
    \@ifstar{%
        \let\multienv@addcode\multienv@addcode@out
        \newmultienvironment@marg
    }{%
        \let\multienv@addcode\multienv@addcode@in
        \newmultienvironment@marg
    }%
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\newmultienvironment@marg}
%    \begin{macrocode}
\long\def\newmultienvironment@marg#1{%
    \@testopt{\newmultienvironment@oarg{#1}}{[0]}%
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\newmultienvironment@oarg}
%    \begin{macrocode}
\long\def\newmultienvironment@oarg#1[#2]{%
    \@ifnextchar[{%
        \newmultienvironment@oargb{#1}{#2}%
    }{%
        \newmultienvironment@def{#1}{[#2]}%
    }%
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\newmultienvironment@oargb}
%    \begin{macrocode}
\long\def\newmultienvironment@oargb#1#2[#3]{%
    \newmultienvironment@def{#1}{[#2][#3]}%
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\newmultienvironment@def}
%    \begin{macrocode}
\long\def\newmultienvironment@def#1#2#3{%
    \begingroup
    \multienv@readkeys@{#3}%
    \def\@tempa{\@multi@environment*{#1}#2}%
    \@temptokena\expandafter\expandafter\expandafter{\expandafter\expandafter\expandafter{\expandafter\begin@multienv\expandafter}\expandafter{\end@multienv}}%
    \expandafter\expandafter\expandafter
    \endgroup
    \expandafter\@tempa\the\@temptokena
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\multienv@readkeys}
%    \begin{macrocode}
\long\def\multienv@readkeys#1{%
    \multienv@readkeys@{#1}%
    \begin@multienv
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\multienv@readkeys@}
%    \begin{macrocode}
\long\def\multienv@readkeys@#1{%
    \let\begin@multienv\@empty
    \let\end@multienv\@empty
    \multienv@readkeyval#1,\@nnil,\@nnil
}
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\let\begin@multienv\@empty
\let\end@multienv\@empty
%    \end{macrocode}
%
% \begin{macro}{\multienv@readkeyval}
%    \begin{macrocode}
\long\def\multienv@readkeyval#1,{%
    \ifx\@nnil#1\relax
        \expandafter\@gobble
    \else
        \multienv@sepkeyval#1=\@nnil=\@nnil\relax
        \expandafter\multienv@readkeyval
    \fi
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\multienv@sepkeyval}
%    \begin{macrocode}
\long\def\multienv@sepkeyval#1=#2={%
    \ifx\@nnil#2\relax
        \multienv@handlekeyval{#1}{}%
        \expandafter\@gobble
    \else
        \multienv@handlekeyval{#1}{#2}%
        \expandafter
        \@gobblefour
    \fi
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\multienv@handlekeyval}
%    \begin{macrocode}
\long\def\multienv@handlekeyval#1#2{%
    \@ifundefined{multienv@key@#1}{%
        \multienv@addenv{#1}{#2}%
    }{%
        \@nameuse{multienv@key@#1}#2\@nnil
    }%
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\multienv@addenv}
%    \begin{macrocode}
\long\def\multienv@addenv#1#2{%
    \@ifnextchar\bgroup{%
        \multienv@@addenv
    }{%
        \ifcase0%
            \expandafter\ifx\csname @let@token\endcsname\@nnil1\else
            \expandafter\ifx\csname @let@token\endcsname[1\else
            \expandafter\ifx\csname @let@token\endcsname<1\fi\fi\fi
        \relax
            \expandafter\multienv@@addenv@
        \else
            \expandafter\multienv@@addenv
        \fi
    }#2\@nnil{#1}%
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\multienv@@addenv@}
%    \begin{macrocode}
\long\def\multienv@@addenv@#1\@nnil{%
    \multienv@@addenv{{#1}}\@nnil
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\multienv@@addenv}
%    \begin{macrocode}
\long\def\multienv@@addenv#1\@nnil#2{%
     \multienv@addcode{\multi@env{#2}#1}{\endmulti@env{#2}}%
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\multi@env}
%    \begin{macrocode}
\long\def\multi@env#1{%
  \begingroup
  \@ifundefined{#1}%
    {\@latex@error{Environment #1 undefined}\@eha}%
    {\csname #1\endcsname}%
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\endmulti@env}
%    \begin{macrocode}
\def\endmulti@env#1{\csname end#1\endcsname\endgroup}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\multienv@addcode@out}
%    \begin{macrocode}
\long\def\multienv@addcode@out#1#2{%
    \@temptokena{#1}%
    \@temptokena\expandafter\expandafter\expandafter{\expandafter\the\expandafter\@temptokena\begin@multienv}%
    \edef\begin@multienv{\the\@temptokena}%
    \@temptokena\expandafter{\end@multienv#2}%
    \edef\end@multienv{\the\@temptokena}%
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\multienv@addcode@in}
%    \begin{macrocode}
\long\def\multienv@addcode@in#1#2{%
    \@temptokena\expandafter{\begin@multienv#1}%
    \edef\begin@multienv{\the\@temptokena}%
    \@temptokena{#2}%
    \@temptokena\expandafter\expandafter\expandafter{\expandafter\the\expandafter\@temptokena\end@multienv}%
    \edef\end@multienv{\the\@temptokena}%
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\multienv@key@add}
%    \begin{macrocode}
\long\@namedef{multienv@key@add code}#1\@nnil{%
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
    \multienv@addcode#1{}{}%
}
%    \end{macrocode}
%
% \begin{macro}{\multienv@key@adjustbox}
%    \begin{macrocode}
\long\@namedef{multienv@key@adjustbox}#1\@nnil{%
    \multienv@addcode{\csname adjustbox@noindent\endcsname\adjustbox{#1}\bgroup\ignorespaces}{\ifhmode\unskip\fi\egroup}%
}
%    \end{macrocode}
% \end{macro}
%
% \iffalse
%</multienv.sty>
% \fi
%
% \Finale
\endinput
