% \iffalse meta-comment
%
% Copyright (C) 2012 by Shengjun Pan <panshengjun@gmail.com>
% -------------------------------------------------------
% 
% This file may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.2
% 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.2 or later is part of all distributions of LaTeX 
% version 1999/12/01 or later.
%
% \fi
%
% \iffalse
%<*driver>
\ProvidesFile{lmake.dtx}
%</driver>
%<package>\NeedsTeXFormat{LaTeX2e}[1999/12/01]
%<package>\ProvidesPackage{lmake}
%<*package>
    [2012/02/29 v1.0 .dtx lmake file]
%</package>
%
%<*driver>
\documentclass{ltxdoc}
\usepackage{amsmath,amssymb}
\usepackage[width=5.5in,height=8.6in]{geometry}
\usepackage{multirow}
\usepackage{graphicx}
\usepackage{makeidx}
\usepackage[usenames]{color}
\usepackage{lmake}[2012/02/29]
\EnableCrossrefs         
\CodelineIndex
\RecordChanges
\begin{document}
  \DocInput{lmake.dtx}
  \PrintChanges
  \PrintIndex
\end{document}
%</driver>
% \fi
%
% \CheckSum{412}
%
% \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}{\filedate}{Initial version}
%
% \GetFileInfo{lmake.dtx}
%
% \DoNotIndex{\newcommand,\newenvironment}
% \DoNotIndex{\#,\$,\%,\&,\@,\\,\{,\},\^,\_,\~,\ }
% \DoNotIndex{\def,\edef,\if,\else,\fi,\begingroup,\endgroup}
% \DoNotIndex{\@ifpackageloaded,\advance,\cdots,\csname,\endcsname}
% \DoNotIndex{\dotsb,\dotsc,\empty,\end,\expandafter,\global}
% \DoNotIndex{\i,\ifcase,\ifnum,\ifx,\or,\relax,\string,\the,\let}
% \DoNotIndex{\ldots,\newcount,\newif,\noexpand,\protected@edef}
% 
%
% \title{The \texttt{lmake} package\thanks{This document
%   corresponds to \texttt{lmake}~\fileversion, dated \filedate.}}
% \author{Shengjun Pan \\ \texttt{panshengjun@gmail.com}}
% \date{}
% \maketitle
% \newcommand{\bs}{\char`\\}
% \newcommand{\us}{\char`\_}
% \newcommand{\ur}{\char`\^}
% \renewcommand{\arraystretch}{1.2}
% \setlength{\fboxsep}{1ex}
% \definecolor{lightGray}{rgb}{0.85,0.85,0.85}
% \definecolor{lightBlue}{rgb}{0.75,0.75,1}
% \noindent\hspace*{-0.075\textwidth}\colorbox{lightGray}{\begin{minipage}{1.15\textwidth}
% \[
% \lcmd{\hat}{h}{X,A,B,F,\mu,\phi,\sigma}
% \lmake[\int_{\hX_\i=\hA_\i}^{\hB_\i},\empty]
% \binom{N}{\lmake[\i\hphi_\i,,m]}
% \lmake[e^{-\frac{(\hX_\i-\hmu_\i)^2}{2\hsigma_\i^2}},c=]
% \lmake[d\hX_\i,\,]
% \]
% \tt
% \bs lcmd\{\bs hat\}\{h\}\{X,A,B,F,\bs mu,\bs phi,\bs sigma\}\\
% \bs lmake[\bs in\us\{\bs hX\us\bs i=\bs hA\us\bs i\}\ur\{\bs hB\us\bs i\},\bs empty]\\
% \bs binom\{N\}\{\bs lmake[\bs i\bs hphi\us\bs i,,m]\}\\
% \bs lmake[e\ur\{-\bs frac\{(\bs hX\us\bs i-\bs hmu\us\bs i)\ur2\}\{2\bs hsigma\us\bs i\ur2\}\},c=]\\
% \bs lmake[d\bs hX\us\bs i,\bs,]
% \end{minipage}}
% \section{Introduction}
% This package provides macros for \LaTeX2e to simplify typesetting a
% list of phrases that fit a pattern.\\
% \begin{tabular}{ll}
% \tt \char`\\lcmd
%   & makes a list of new commands by adding a prefix to existing
%     commands.\\
% \tt\char`\\lmake
%   & makes a list of the form $p(i_1),p(i_2),\dotsc,p(i_n)$, where
%     $p(.)$ stands for \emph{pattern}.
% \end{tabular}
% \section{Usage and examples}
% \label{sec:usage}
% \DescribeMacro{\lcmd}
% \fcolorbox{black}{lightBlue}{\tt \char`\\lcmd\{command\}\{prefix\}\{list\}}\\[2ex]
% makes a list of new commands from \texttt{command} by adding \texttt{prefix}
% to each item in the comma-separated \texttt{list}. If an item in the
% list is a macro, only its name is prefixed; the backslash is stripped away.\\[3ex]
% \textbf{Examples}:
% \footnote{The examples used in this document require packages {\tt amsmath,
%   amssymb} and {\tt graphicx}.}\\[1ex]
% \lcmd{\mathcal}{c}{A,X,P}
% \lcmd{\mathbb}{bb}{Z,R,E}
% \lcmd{\overline}{vct}{x,\phi,psi}
% \begin{tabular}{l@{ defines: }lll}
% \hline
% \verb|\lcmd{\mathcal}{c}{A,X,P}|
%   &\texttt{\char`\\ cA} $\to \cA$
%   &\texttt{\char`\\ cX} $\to \cX$
%   &\texttt{\char`\\ cP} $\to \cP$
% \\
% \verb|\lcmd{\mathbb}{c}{A,X,P}|
%   &\texttt{\char`\\ bbZ} $\to \bbZ$
%   &\texttt{\char`\\ bbR} $\to \bbR$
%   &\texttt{\char`\\ bbE} $\to \bbE$\\
% \verb|\lcmd{\overline}{vct}{x,psi,\phi}|
%   &\texttt{\char`\\ vctx} $\to \vctx$
%   &\texttt{\char`\\ vctpsi} $\to \vctpsi$
%   &\texttt{\char`\\ vctphi} $\to \vctphi$\\
% \hline
% \end{tabular}\\[2ex]
% In the last example the new command for \verb|\phi| is
% \verb|\vctphi|, not \verb|\vct\phi|. Notice the difference between
% \verb|\vctphi| and \verb|\vctpsi|.\\[4ex]
% \DescribeMacro{\lmake}
% \fcolorbox{black}{lightBlue}{\tt\bs lmake[[key1=]value1,[key2=]value2,...]}\\[2ex]
%  makes a list of symbols by key-value pairs. Valid keys are
%  described in the following table.\\[3ex]
% \begin{tabular}{@{\tt }rll}
% \hline
% keys & default & description\\
% \hline
% p & \verb|\i| & Pattern. All occurrences of \verb|\i| will be replaced
% by the corresponding index.\\
% c & \verb|,| & Separator.\\
% n &\verb|n| & Last index.\\
% 1 & \verb|1| & First index.\\
% 2 & \verb|2| & Second index.\\
% d & \verb|\ldots|, \verb|\cdots| & Dots. If the separator is comma,
% \verb|\ldots| is used; otherwise \verb|\cdots| is used.\\
%   & \verb|\dotsc|, \verb|\dotsb| & If \verb|amsmath| is loaded,
%   \verb|\dotsc| and \verb|\dotsb| are used respectively.\\
% $\ell$ & \verb|{}| & List of comma-separated symbols.\\
% \hline
% \end{tabular}\\[3ex]
% \textbf{Examples}:\\[1ex]
% \begin{tabular}{ll}
% \hline
% what you type & what you see\\
% \hline
% \verb|\lmake[]| & $\lmake[]$\\
% \verb|\lmake[2=]| & $\lmake[2=]$\\
% \verb|\lmake[x_\i,c=]| & $\lmake[x_\i,c=]$\\
% \verb|\lmake[x_\i,,N]| & $\lmake[x_\i,,N]$\\
% \verb|\lmake[x_\i,\ge,k]| & $\lmake[x_\i,\ge,k]$\\
% \verb|\lmake[\bar x_{\i},\circ,1=i,i+1]| & $\lmake[\bar x_{\i},\circ,1=i,i+1]$\\
% \verb|\lmake[p_\i^{\mu_\i},c=,m]| & $\lmake[p_\i^{\mu_\i},c=,m]$\\
% \verb|\lmake[N_\i!,\,,\Gamma,\alpha,\beta]| & $\lmake[N_\i!,\,,\Gamma,\alpha,\beta]$\\
% \verb|\lmake[\left(\frac{\i}{\i+1}\right),\!]|
% & $\lmake[\left(\frac{\i}{\i+1}\right),\!]$\\
% \verb|\lmake[(e_\i+1),c=,k,1,2]| & $\lmake[(e_\i+1),c=,k,1,2]$\\[1ex]
% \verb|\lmake[x_{\i},l={1,3,5,11}]|
% & $\lmake[x_{\i},l={1,3,5,11}]$\\
% \verb|\lmake[\rotatebox{-30}{\i},\to,l={A,B,C,D}]|
% & $\lmake[\rotatebox{-30}{\i},\to,l={A,B,C,D}]$\\
% \hline
% \end{tabular}\\[2ex]
% \emph{Remarks:}
% \begin{itemize}
% \item If $\tt \ell$ is empty, the resulting list has the following form:\\
% \verb|p(1) c p(2) c d c p(n)|
%
% If $\tt \ell$ is not empty, the resulting list has the
%   following form, for the example $\tt \ell=\{x,y,z,u\}$:\\
% \verb|p(x) c p(y) c p(z) c p(u)|
% \item A \underline{non-empty item without \texttt{=}} in the argument
%   list is treated as a value. Normally the key-value pairs can appear
%   out of order in the argument list to \verb|\lmake|. For fast typing
%   the key can be omitted. The missing key is searched, starting from
%   the key that would follow the previous key in the table-order. Only
%   keys without values are searched.
%
%   For example, in \verb|\lmake[\bar x_{\i},\circ,1=i,i+1]|, the
%   missing key for \verb|\bar x_{\i}| is \verb|p|, the missing key for
%   \verb|\circ| is \verb|c| since it follows \verb|p| in the
%   table. Similarly, the missing key for \verb|i+1| is \verb|2| since
%   it follows the previous key \verb|1| in the able.
% \item A key not appearing or skipped in the argument list takes its
%   default value, unless it's been searched as a missing key and given
%   a value.
% 
%   For example, in \verb|\lamke[x_\i,,N]|, all keys except for \verb|p|
%   and \verb|n| take default values. Particularly, the key \verb|c| is
%   skipped and it is treated as missing.
% 
%   Note that a skipped key does not take value \emph{empty}. To force a
%   value to be empty, use one of the following workarounds:
%   {\tt \char`\\empty}, {\tt key=}, {\tt key=\char`\\empty}, or {\tt
%     key=\{\}}.
% \end{itemize}
%
% \StopEventually{}
%
% \section{Implementation}
% This section explains in details how verb|\lmake|, \verb|\lcmd| and
% necessary internal macros are implemented.
% \begin{macro}{\L@Compare}
% \verb|\L@Compare{string1}{string2}|\\
% compares two strings. The two arguments are fully expanded before compassion.
% \verb|\ifL@Equal| is a Boolean variable for storing the result.
%    \begin{macrocode}
\newif\ifL@Equal
\def\L@Compare#1#2{%
    \protected@edef\L@a{#1}\protected@edef\L@b{#2}%
    \ifx\L@a\L@b\L@Equaltrue\else\L@Equalfalse\fi}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\L@FuzzyCompare}
% \verb|\L@FuzzyCompare{string1}{string2}|\\
% tests if two strings are the same, where white spaces preceding the
% second argument are ignores. This allows flexible writing of
% the comma-separated argument to \verb|\lmake| so that spaces may be inserted
% between an item and the previous comma.
%    \begin{macrocode}
\def\L@FuzzyCompare#1#2{%
    \L@Compare{#1}{#2}\ifL@Equal\else\L@Compare{#1}{ #2}\fi}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\L@SoftCompare}
%   \verb|\L@SoftCompare{string1}{string2}|\\
%   similar to \verb|\L@Compare|, but does not expand the two
%   strings. This is usefully if either argument contains undefined
%   macros, for example, the value to the key \verb|p| in the argument to \verb|\lmake|.
%    \begin{macrocode}
\def\L@SoftCompare#1#2{%
    \def\L@a{#1}\def\L@b{#2}%
    \ifx\L@a\L@b\L@Equaltrue\else\L@Equalfalse\fi}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\L@FuzzySoftCompare}
% \verb|\L@FuzzySoftCompare{string1}{string2}|\\
% similar to \verb|L@FuzzyCompare|, but uses \verb|\L@SoftCompare|
% instead of \verb|\L@Compare|.
%    \begin{macrocode}
\def\L@FuzzySoftCompare#1#2{%
    \L@SoftCompare{#1}{#2}\ifL@Equal\else\L@SoftCompare{#1}{ #2}\fi}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\L@HasEqualSign}
%   \verb|\L@HasEqualSign{string}|\\
%   tests if a string has an equal sign \verb|=|. This is used to test
%   if an argument to \verb|\lmake| is a key-value pair or just a
%   value. It is defined indirectly via \verb|\L@HES|, which is a tail
%   recursion for scanning the tokens in its argument.\\[1ex]
%   \verb|\L@Ignore| is an auxiliary macro that simply ignores its
%   argument. The test result is stored in \verb|\ifL@HasEqualSign|.
%    \begin{macrocode}
\def\L@Ignore#1\end{}
\newif\ifL@HasEqualSign
\def\L@HasEqualSign#1{%
    \L@HasEqualSignfalse\L@HES#1\end}
\def\L@HES#1{%
    \ifx#1=\L@HasEqualSigntrue\let\L@Next=\L@Ignore%
    \else\ifx#1\end\let\L@Next=\relax\else\let\L@Next=\L@HES\fi%
    \fi\L@Next}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\L@ArName}
% \verb|\L@ArName[index]|\\
% returns the name of a macro via a numeric index.
%    \begin{macrocode}
\def\L@ArName[#1]{\ifcase#1 L@Pattern\or L@Comma\or L@Last\or%
L@First\or L@Second\or L@Dots\or L@List\else L@Other\fi}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\L@Set,\L@Get}
% \verb|\L@Set[index]=value;|\\
% \verb|\L@Get[Index]|\\
% set and get the value of a macro by a numeric index. Numeric indices are
% used to locate missing keys in the argument to \verb|\lmake|.
%    \begin{macrocode}
\def\L@Set[#1]=#2;{\global\expandafter\let\csname\L@ArName[#1]\endcsname=#2}
\def\L@Get[#1]{\csname\L@ArName[#1]\endcsname}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\L@LDots,\L@Cdots}
% denotes the default macro for low dots. If \verb|amsmath| is loaded before
% \verb|\lmake|, \verb|\L@LDots| is set to \verb|\dotsc| and
% \verb|\L@Cdots| is set to \verb|\dotsb|. Otherwise \verb|\L@LDots|
% is set to \verb|\ldots| and \verb|\L@Cdots| is set to \verb|\cdots|.
%    \begin{macrocode}
\@ifpackageloaded{amsmath}
    {\def\L@Ldots{\dotsc}\def\L@Cdots{\dotsb}}
    {\def\L@Ldots{\ldots}\def\L@Cdots{\cdots}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\L@Map}
%   \verb|\L@Map{function}{list}{new separator}|\\
%   maps a list of comma-separated items to a new list, so that each
%   item is transformed using the given function, and the commas are
%   replaced with the new separator. It is defined indirectly
%   indirectly via \verb|\L@Iterate|, which is a tail recursion for
%   scanning the comma-separated list.\\[1ex]
%   \verb|\ifL@Start| is used to indicate if the current item is the
%   first item, which is not preceded by a comma, unlike the remaining
%   items.\\[1ex]
%   \verb|\L@Map|
%    \begin{macrocode}
\newif\ifL@Start
\def\L@Map#1#2#3{%
    \def\L@Sym{\empty}\def\LM@Func{#1}\def\L@Sep{#3}%
     \L@Starttrue\expandafter\L@Iterate#2,\end}
\def\L@Iterate#1,#2{%
    \LM@Func{#1}%
    \ifx#2\end\let\L@Next=\relax\def\L@Nextarg{\empty}%
    \else\L@Sep\let\L@Next=\L@Iterate\def\L@Nextarg{#2}\fi%
    \expandafter\L@Next\L@Nextarg}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\L@GetKeyValue}
% \verb|\L@GetKeyValue{key-value pair}|\\
% extracts the key and value from a string, and store them in
% \verb|\L@Key| and \verb|\L@Value| respectively. If the argument has no
% equal sign, it is used as a value and the key is set to empty. Otherwise,
% \verb|\L@GetKV| is called to extract the key and value.
%    \begin{macrocode}
\def\L@GetKeyValue#1{%
    \def\L@Key{}\def\L@Value{}\L@HasEqualSign{#1}%
    \ifL@HasEqualSign\L@GetKV#1\end%
    \else\def\L@Key{}\def\L@Value{#1}%
    \fi}
\def\L@GetKV#1=#2\end{%
    \def\L@Key{#1}\def\L@Value{#2}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\L@Parse}
% \verb|\L@Parse{list}|\\
% parses a list of comma-separated items, extracts each item,
% extract its key and value, looks for keys \verb|p|, \verb|c|,
% \verb|n|, \verb|1|, \verb|2|, \verb|d| and \verb|l|, and finally assigns the
% corresponding values to \verb|\L@Pattern|, \verb|\L@Comma|,
% \verb|\L@Last|, \verb|\L@First|, \verb|\l@Second|, \verb|\L@Dots|
% and \verb|\L@List| respectively.\\[1ex]
% The counter \verb|\L@idx| is the index of the next key yet to be assigned
% with an value.
%    \begin{macrocode}
\newcount\L@idx
%    \end{macrocode}
% If the list is not empty, then it calls a tail recursion \verb|\l@PRS|.
%    \begin{macrocode}
\def\L@Parse#1{\L@idx=0%
    \L@FuzzySoftCompare{#1}{}%
    \ifL@Equal\else\def\L@Extra{}\L@PRS#1,\end,\fi}
%    \end{macrocode}
% An artificial item \verb|,\end,|
% is added to the end of the actual list, which terminates the
% recursion when encountered.
%    \begin{macrocode}
\def\L@PRS#1,{%
    \L@SoftCompare{#1}{\end}\ifL@Equal%
        \let\L@Next=\relax%
    \else%
%    \end{macrocode}
% If an item is empty, the missing key is searched and
% the corresponding default value is used.
%    \begin{macrocode}
        \L@FuzzySoftCompare{#1}{}\ifL@Equal%
            \ifnum\L@idx<7%
                \ifcase\the\L@idx%
                    \def\L@Default{\i}%
                    \or\def\L@Default{,}%
                    \or\def\L@Default{n}%
                    \or\def\L@Default{1}%
                    \or\def\L@Default{2}%
                    \or\def\L@Default{}%
                    \or\def\L@Default{}%
                \fi%
                \L@Set[\the\L@idx]=\L@Default;%
                \advance \L@idx by 1%
            \fi%
%    \end{macrocode}
% If the item is not empty, the key and value are extracted. Depending
% on what the key is, the value is assigned to the approximate macro.
%    \begin{macrocode}
        \else%
            \L@GetKeyValue{#1}\let\L@CV=\L@Value%
            \L@FuzzyCompare{\L@Key}{p}\ifL@Equal\L@idx=1\L@Set[0]=\L@CV;%
            \else\L@FuzzyCompare{\L@Key}{c}\ifL@Equal\L@idx=2\L@Set[1]=\L@CV;%
            \else\L@FuzzyCompare{\L@Key}{n}\ifL@Equal\L@idx=3\L@Set[2]=\L@CV;%
            \else\L@FuzzyCompare{\L@Key}{1}\ifL@Equal\L@idx=4\L@Set[3]=\L@CV;%
            \else\L@FuzzyCompare{\L@Key}{2}\ifL@Equal\L@idx=5\L@Set[4]=\L@CV;%
            \else\L@FuzzyCompare{\L@Key}{d}\ifL@Equal\L@idx=6\L@Set[5]=\L@CV;%
            \else\L@FuzzyCompare{\L@Key}{l}\ifL@Equal\L@idx=7\L@Set[6]=\L@CV;%
%    \end{macrocode}
% If an item is a value without a key, the missing key is searched and
% given the current value.
%    \begin{macrocode}
            \else\L@FuzzyCompare{\L@Key}{}\ifL@Equal%
                 \ifnum\L@idx<7%
                     \L@Set[\the\L@idx]=\L@CV;%
                 \fi%
                 \advance \L@idx by 1%
            \fi\fi\fi\fi\fi\fi\fi\fi\fi%
            \let\L@Next=\L@PRS%
         \fi%
         \L@Next}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\lmake}
%   \verb|\lmake[key-value list]|\\
%   makes a list of symbols using the given key-value
%   pairs. \verb|\ifL@FoundFirst| is used to indicate if the first
%   non-empty symbol is encountered; the first symbol is not preceded
%   by a separator.
%    \begin{macrocode}
\newif\ifL@FoundFirst
%    \end{macrocode}
% \verb|\L@Parse| is used twice. The first time it is used to set the
% default values. The second time it is used to set the values
% supplied by the argument list.
%    \begin{macrocode}
\newcommand{\lmake}[1][]{%
\begingroup%
    \L@Parse{p=\i,c={,},d=,1=1,2=2,n=n,l=}%
    \L@Parse{#1}%
%    \end{macrocode}
% The pattern is used to define the transforming function
% \verb|\L@Func| by replacing all occurrences of \verb|\i| by the
% actual argument.
%    \begin{macrocode}
    \def\L@Func##1{\def\i{##1}\L@Get[0]}%
%    \end{macrocode}
% If the key \verb|d| is not given a value, its value is automatically determined by
% the value of the separator.
%    \begin{macrocode}
    \L@Compare{\L@Dots}{\empty}\ifL@Equal%
        \L@Compare{\L@Comma}{,}\ifL@Equal%
            \def\L@Dots{\L@Ldots}\else\def\L@Dots{\L@Cdots}%
        \fi
    \fi
%    \end{macrocode}
% The last step is to typeset the list of symbols. If the value to the key $\ell$ is
% missing, the typeset list starts with two symbols followed by the dots and
% ends with the last symbol. The symbols and dots are separated by the
% separator.
%    \begin{macrocode}
    \L@Compare{\L@List}{\empty}\ifL@Equal%
        \L@FoundFirstfalse%
         \L@Compare{\L@First}{\empty}\ifL@Equal\else%
             \L@Func{\L@First}\L@FoundFirsttrue%
         \fi%
         \L@Compare{\L@Second}{\empty}\ifL@Equal\else%
             \ifL@FoundFirst\L@Comma\fi%
             \L@Func{\L@Second}\L@FoundFirsttrue%
         \fi%
         \L@Compare{\L@Dots}{\empty}\ifL@Equal\else%
             \ifL@FoundFirst\L@Comma\fi\L@Dots%
         \fi%
         \L@Compare{\L@Last}{\empty}\ifL@Equal\else%
             \L@Comma\L@Func{\L@Last}%
         \fi%
%    \end{macrocode}
% If a non-empty value to the key $\ell$ is given, the typeset list
% consists of symbols from the items in the value of $\ell$,
% transformed by the pattern function.
%    \begin{macrocode}
     \else%
         \L@Map{\L@Func}{\L@List}{\L@Comma}%
     \fi%
\endgroup}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\L@CmdName}
% \verb|\L@CmdName{string}|\\
% returns the string itself if it is not a macro, otherwise returns
% the macro name with the backslash stripped away. This is an
% auxiliary function to \verb|\lcmd|.
%    \begin{macrocode}
\def\L@CmdName#1{%
    \if\noexpand#1\noexpand\L@anycmd\expandafter\L@StripFirst\string#1\else#1\fi}
\def\L@StripFirst#1#2{#2}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\lcmd}
% \verb|\lcmd{command}{prefix}{list}|\\
% makes a list of new commands. See Section~\ref{sec:usage} for more details.
%    \begin{macrocode}
\def\lcmd#1#2#3{%
    \def\L@MakeCmd##1{%
        \expandafter\def\csname #2\L@CmdName##1\endcsname{#1{##1}}}%
     \L@Map{\L@MakeCmd}{#3}{}}
%    \end{macrocode}
% \end{macro}
% \Finale
\endinput