% \iffalse meta-comment
%
% Copyright
%<*driver>
\documentclass{ltxdoc}
\usepackage{doc}
\usepackage{multidef-save}
\usepackage{dsfont}

\def\sty#1{\textsf{#1.sty}}
\def\pack#1{\textsf{#1}}
\def\ttt#1{\texttt{#1}}

%%%\AtBeginDocument{\CodelineIndex\EnableCrossrefs}
%%%\AtEndDocument{\PrintIndex}
\begin{document} 
 \def\docdate{2016/04/20}
 \def\filedate{2016/04/20}
 \def\fileversion{1.10}
 \DocInput{multidef.dtx}
\end{document}
%</driver>
% 
% \fi
%
%
% \changes{1.00}{2016/03/14}{Initial release}
% \changes{1.10}{2016/04/20}{Added def. of robust commands}
%
%
% \CheckSum{329}
%% \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         \~}
%%
%
% \title{\pack{multidef}: quick definition \\ 
%  of multiple similar \LaTeX\ macros}
% \author{Nicolas Markey}
% \date{\docdate}
% \maketitle
% \StopEventually{}
%
% \begin{abstract}
% \pack{multidef} provides a succinct way of defining series of macros having
% similar definitions. While this can be achieved quite easily with a little of
% \TeX\ programming, I~found no package offering a command similar to
% the \cs{multidef} command defined in the present package.
% \end{abstract}
%
%
% \section{Usage}
%
% The command \cs{multidef} can be used to quickly define several
% similar macros. For~instance: 
%\begin{verbatim}
%\multidef{\textit{#1}}{apple,banana,strb->strawberry}
%\end{verbatim}
% \multidef{\textit{#1}}{apple,banana,strb->strawberry}
% After this single line, you can use commands \cs{apple}, \cs{banana} and
% \cs{strb} to write their names in italics: \apple, \banana, and \strb. 
%
%
% The package has several features, such as
% \begin{itemize}
% \item adding prefix\slash suffix to all command names;
% \item raising errors and\slash or warnings if some commands are already
% defined; 
% \item allowing commands with arguments.
% \end{itemize}
%
% For example, after writing
%\begin{verbatim}
%\multidef[arg=1]{\ensuremath{\mathsf{#1}(##1)}}{fst->first,lst->last}
%\end{verbatim}
% \multidef[arg=1]{\ensuremath{\mathsf{#1}(##1)}}{fst->first,lst->last} 
% so that you can write \verb+\fst{w}+ to write \fst{w}. 
%
% \section{Examples}
%
% I very often use the \cs{mathcal} command to get
% calligraphic-font letters in math mode. With \pack{multidef} I now
% simply write 
%\begin{verbatim}
%\multidef[prefix=cal]{\ensuremath{\mathcal{#1}}}{A-Z}
%\end{verbatim}
% \multidef[prefix=cal]{\ensuremath{\mathcal{#1}}}{A-Z}
% and write \cs{calG} to write~\calG. Here \texttt{A-Z} is a shorthand for the
% 26 letters of the basic Latin alphabet. 
%
% \medskip
% In~the same way, I can define
% \let\mathbb\mathds
% \makeatletter
% \def\optbb#1{\@ifnextchar+
%     {\ensuremath{\mathbb{#1}_{\geq 0}}\@gobble}%
%     {\@ifnextchar*{\ensuremath{\mathbb{#1}_{>0}}\@gobble}%
%                   {\ensuremath{\mathbb{#1}}}}}%
% \makeatother
% \multidef[prefix=bb]{\optbb{#1}}{A-Z,one->1}%
%\begin{verbatim}
%\usepackage{dsfonts}
%\let\mathbb\mathds
%\makeatletter
%\newcommand\optbb[1]{%
%  \@ifnextchar+{\ensuremath{\mathbb{#1}_{\geq 0}}\@gobble}
%    {\@ifnextchar*{\ensuremath{\mathbb{#1}_{>0}}\@gobble}
%      {\ensuremath{\mathbb{#1}}}}}
%\makeatother
%\multidef[prefix=bb]{\optbb{#1}}{A-Z,one->1}
%\end{verbatim}
% and then \cs{bbR+} writes \bbR+, while \verb+$\bbone_{S}$+ outputs $\bbone_S$.
%
% \medskip
% As a last example, we can use \pack{multidef} to redefine all \cs{...name}
% (e.g. \cs{refname}, \cs{partname},~...) commands succinctly. For this,
% we~would deactivate the error and warning mechanisms, as we know we are
% redefining those macros: 
%\begin{verbatim}
%\multidef[noerr,nowarn,suffix=name]{#1}{ref->R\'ef\'erences,
%  part->Partie, appendix->Annexe,...}
%\end{verbatim}
%\multidef[noerr,nowarn,suffix=name]{#1}{ref->R\'ef\'erences,
%  part->Partie, appendix->Annexe}
% Then \cs{refname} contains '\refname'.
%
% \section{The code}
%
%    \begin{macrocode}
\NeedsTeXFormat{LaTeX2e}[1994/12/01]
\ProvidesPackage{multidef}[2016/04/20 v1.10  definition of multiple commands]
%    \end{macrocode}
%
% We begin with importing package \pack{trimspaces}, or to define its command
% \cs{trim@spaces}, in order to trim unwanted spaces in arguments:
%\begin{macro}{\trim@spaces}
%    \begin{macrocode}
\IfFileExists{trimspaces.sty}
  {\RequirePackage{trimspaces}}
  {}
%% borrowing code from trimspaces, if package was not found.
\catcode`\Q=3
\@ifundefined{trim@spaces}
   {\PackageWarning{multidef}
     {Package trimspaces.sty not found.^^JDefining \noexpand\trim@spaces myself}
    \newcommand\trim@spaces[1]{%
     \romannumeral-`\q\trim@trim@\noexpand#1Q Q%
    }
    \long\def\trim@trim@#1 Q{\trim@trim@@#1Q}
    \long\def\trim@trim@@#1Q#2{#1}}
   {}
\catcode`\Q=11
%%
%    \end{macrocode}
%\end{macro}
%
% We use \pack{xkeyval} to handle package and command options. The package has
% two options, \ttt{noerr} and~\ttt{nowarn}. The former tells
% \pack{multidef} not to raise an error when redefining a command (default to
% true). The latter tells not to raise a warning (defaults to false). Thus the
% default behaviour is to only raise a warning when redefining a command.
% Notice that the keys \ttt{noerr} and \ttt{nowarn} are also available as
% arguments of the \cs{multidef} command, to change the selected behaviour
% locally.
%\begin{macro}{noerr}
%\begin{macro}{nowarn} 
%    \begin{macrocode}
\RequirePackage{xkeyval}
\define@boolkeys{mdef}{noerr,nowarn}[true]
\DeclareOptionX{noerr}[true]{\setkeys{mdef}{noerr=#1}}
\DeclareOptionX{nowarn}[true]{\setkeys{mdef}{nowarn=#1}}
\ExecuteOptionsX{noerr=false,nowarn=false}
\ProcessOptionsX
\ifKV@mdef@noerr
\presetkeys{mdef}{noerr=true}{}
\else
\presetkeys{mdef}{noerr=false}{}
\fi
\ifKV@mdef@nowarn
\presetkeys{mdef}{nowarn=true}{}
\else
\presetkeys{mdef}{nowarn=false}{}
\fi
%    \end{macrocode}
%\end{macro}
%\end{macro}
% We have five main other keys to be used by the \cs{multidef} command:
% \begin{itemize}
% \item \ttt{prefix} and \ttt{suffix} define the prefix and suffix to be
% used in the name of the command. These keys have equivalent shorthands
% \ttt{p} and \ttt{s}. 
% \item \ttt{arg} (and the equivalent \ttt{args}) can be used to define the
% number of arguments of the series of commands to be defined.
% \item \ttt{long} and \ttt{global} can be used to define \cs{long} and
% \cs{global} macros,
% \item \ttt{robust} can be used to define robust commands.
% \end{itemize}
%\begin{macro}{prefix}
%\begin{macro}{suffix} 
%\begin{macro}{arg}
%\begin{macro}{long}
%\begin{macro}{global} 
%\begin{macro}{robust} 
% \begin{macrocode}
\define@key{mdef}{prefix}{\def\@mdprefix{#1}}
\define@key{mdef}{p}{\def\@mdprefix{#1}}
\define@key{mdef}{suffix}{\def\@mdsuffix{#1}}
\define@key{mdef}{s}{\def\@mdsuffix{#1}}
\define@key{mdef}{arg}{\def\@mdargs{#1}}
\define@key{mdef}{args}{\def\@mdargs{#1}}
\define@boolkeys{mdef}{long,global,robust}[true]
\presetkeys{mdef}
           {p=,s=,prefix=,suffix=,long=false,global=false,robust=false,
            arg=0,args=0}{}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%
%
% We define shorthands for defining series of commands indexed by letters of
% the alphabet. Can be useful sometimes...
%\begin{macro}{\@mdef@az}
%\begin{macro}{\@mdef@AZ}
%\begin{macro}{\@mdef@alphabet}
%\begin{macro}{\@mdef@Alphabet}
% \begin{macrocode}
\def\@mdef@az{a-z}
\def\@mdef@AZ{A-Z}
\def\@mdef@alphabet{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}
\def\@mdef@Alphabet{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}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%
% We now define \cs{multidef}: it~will first deal with option keys, store the
% definition of the commands being defined, and then call its friend
% \cs{@mdef}, whose role is to deal with each entry in the comma-separated
% list. 
%\begin{macro}{\multidef}
% \begin{macrocode}
\newcommand\multidef[3][]{%
  \setkeys{mdef}{#1}%
  \def\@mdef@com##1{#2}%
  \@mdef#3,\@end}
%    \end{macrocode}
%\end{macro}
%
% Command \cs{@mdef} takes the first item in the comma-separated list,
% and first checks if it is a shorthand \ttt{a-z} or \ttt{A-Z}. 
% If not, it~calls \cs{@@mdef} on the first item, and \cs{@mdef} on
% the remainder of the list. 
%\begin{macro}{\@mdef}
% \begin{macrocode}
\def\@mdef #1,#2\@end{%
  \edef\@mdef@arg{\trim@spaces{#1}}%
  \ifx\@mdef@arg\@mdef@az
    \expandafter\@mdef \@mdef@alphabet,\@end
  \else
    \ifx\@mdef@arg\@mdef@AZ
      \expandafter\@mdef \@mdef@Alphabet,\@end
    \else
      \expandafter\@@mdef\@mdef@arg->->->\@end
    \fi
  \fi
  \def\@mdef@arg{#2}%
  \ifx\@mdef@arg\@empty\else\@mdef #2\@end\fi}
%    \end{macrocode}
%\end{macro}
%
% Now, command \cs{@@mdef} checks if the command name already exists, and
% issues errors and warning if needed. It~also calls \cs{@@@mdef} with two
% arguments: the first one is the string to be used in the name of the
% command, the second one is the string to be used in the definition.
% The~latter might be the empty string in case both strings are supposed to be
% the same.
%\begin{macro}{\@@mdef}
%\begin{macro}{\@mdef@redeftok}
%\begin{macro}{\@mdef@comma}
%\begin{macro}{\@mdef@finalwarn}
% \begin{macrocode}
\newtoks\@mdef@redeftok
\def\@mdef@comma{}
\def\@@mdef#1->#2->#3\@end{%
  \@ifundefined{\@mdprefix#1\@mdsuffix}
    {\@@@mdef{#1}{#2}}
    {\ifKV@mdef@nowarn\else
       \edef\@mdef@redef{\the\@mdef@redeftok\@mdef@comma
         \@backslashchar\@mdprefix#1\@mdsuffix}
       \def\@mdef@comma{, }
       \global\@mdef@redeftok=\expandafter{\@mdef@redef}
     \fi
     \ifKV@mdef@noerr
       \@@@mdef{#1}{#2}%
       \ifKV@mdef@nowarn\else
         \PackageWarning{multidef}
           {command \expandafter\noexpand\csname\@mdprefix#1\@mdsuffix\endcsname
             redefined}
       \fi
     \else
       \PackageError{multidef}
         {command \expandafter\noexpand\csname\@mdprefix#1\@mdsuffix\endcsname
           already defined}\@ehc
     \fi
     \ifKV@mdef@nowarn\else
       \@ifundefined{@mdwarnonce}
         {\def\@mdwarnonce{}%
          \@mdef@finalwarn}
         {}
     \fi}
}
\def\@mdef@finalwarn{%
  \AtEndDocument{\PackageWarningNoLine{multidef}{There were
     redefined commands (\the\@mdef@redeftok)}}}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%
% Finally, \cs{@@@mdef} calls \cs{@mdef@def} or \cs{@mdef@robdef} (if option
% \ttt{robust} was passed) with the appropriate arguments. This is where the
% commands are really defined. The definitions of \cs{@mdef@def} and
% \cs{@mdef@robdef} use \cs{@yargd@f}, following the definition of
% \cs{newcommand} and \cs{DeclareRobustCommand} in \LaTeX.
%\begin{macro}{\@@@mdef}
%\begin{macro}{\@mdef@def}
%\begin{macro}{\@mdef@robdef}
% \begin{macrocode}
\def\@@@mdef#1#2{\def\@arg@{#2}%
  \ifx\@arg@\@empty
    \ifKV@mdef@robust
      \expandafter\def\expandafter\@mdef@cmdname
        \expandafter{\csname\@mdprefix#1\@mdsuffix\endcsname}%
      \expandafter\@mdef@robdef\@mdef@cmdname{#1}%
    \else
      \@mdef@def{#1}{#1}%
    \fi
  \else
    \ifKV@mdef@robust
      \expandafter\def\expandafter\@mdef@cmdname
        \expandafter{\csname\@mdprefix#1\@mdsuffix\endcsname}
      \expandafter\@mdef@robdef\@mdef@cmdname{#2}%
    \else
      \@mdef@def{#1}{#2}%
    \fi
  \fi}
\def\@mdef@def#1#2{%
  \let\reserved@b\@gobble
  \ifKV@mdef@global\let\@mdglobal\global\else\let\@mdglobal\relax\fi
  \ifKV@mdef@long\let\@mdlong\long\else\let\@mdlong\relax\fi
  \def\l@ngrel@x{\@mdlong\@mdglobal}
  \expandafter\expandafter\expandafter\@yargd@f\expandafter\@mdargs\csname
  \@mdprefix#1\@mdsuffix\expandafter\endcsname\expandafter{\@mdef@com{#2}}
}
\def\@mdef@robdef#1#2{%
  \edef\reserved@a{\string#1}%
  \def\reserved@b{#1}%
  \edef\reserved@b{\expandafter\strip@prefix\meaning\reserved@b}%
  \global\edef#1{%
     \ifx\reserved@a\reserved@b
        \noexpand\x@protect
        \noexpand#1%
     \fi
     \noexpand\protect
     \expandafter\noexpand\csname
        \expandafter\@gobble\string#1 \endcsname
  }%
  \let\reserved@b\@gobble
  \ifKV@mdef@global\let\@mdglobal\global\else\let\@mdglobal\relax\fi
  \ifKV@mdef@long\let\@mdlong\long\else\let\@mdlong\relax\fi
  \def\l@ngrel@x{\@mdlong\@mdglobal}
  \expandafter\expandafter\expandafter\@yargd@f\expandafter\@mdargs\csname
    \expandafter\@gobble\string#1 \expandafter\endcsname
    \expandafter{\@mdef@com{#2}}
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
% \Finale
\endinput
