% \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} % % % \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