% % \iffalse /!\ this file contains non-ascii -- encoding is utf-8 /!\ % % xargs package by Manuel P\'egouri\'e-Gonnard % ------------------------------------------------------------- % % This work may be distributed and/or modified under the conditions of % the LaTeX Project Public License, either version 1.3c 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.3c or later is part of all distributions of LaTeX % version 2006/05/20 or later. % % This work has the LPPL maintenance status `maintained'. % % The current maintainer of this work is Manuel P\'egouri\'e-Gonnard. % % This work consists of the file xargs.dtx and the derived files % xargs.sty, xargs.pdf and xargs-fr.pdf. % % %<*gobble> \ProvidesFile{xargs.dtx} % %\NeedsTeXFormat{LaTeX2e} %\ProvidesPackage{xargs} %<*package> % \fi % \ProvidesFile{xargs.dtx} [2008/03/22 v1.1 \space extended macro definitions \space (mpg)] % \iffalse % % \fi % \CheckSum{782} % \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 \~} % \iffalse %<*gobble> \begingroup % %<*batchfile> \input docstrip \keepsilent \preamble xargs package by Manuel P\string\'egouri\string\'e-Gonnard % This is a generated file. See xargs.dtx for license information. \endpreamble \askforoverwritefalse %\generate{\file{xargs.ins}{\from{xargs.dtx}{batchfile}}} %\generate{\file{xargs.drv}{\from{xargs.dtx}{driver}}} \generate{\file{xargs.sty}{\from{xargs.dtx}{package}}} \generate{\file{xargs-fr.drv}{\from{xargs.dtx}{pilote}}} % %<*gobble> \endgroup % %<*driver|pilote> \documentclass[oneside, a4paper]{ltxdoc} \usepackage[utf8]{inputenc} \usepackage[T1]{fontenc} \usepackage{lmodern} \usepackage{fixltx2e, mparhack} \usepackage[babel=true, expansion=false]{microtype} \usepackage{xargs} \expandafter\newif\csname iffrenchdoc\endcsname % cachez ce if que je ne... %\frenchdoctrue % %<*gobble> \iffrenchdoc % %<*pilote> \usepackage[lmargin=4.5cm, rmargin=3cm]{geometry} \OnlyDescription \usepackage[english, frenchb]{babel} \FrenchFootnotes \AddThinSpaceBeforeFootnotes \newcommand*\eng[1]{\emph{\foreignlanguage{english}{#1}}} \usepackage[colorlinks=true, bookmarks=true, bookmarksnumbered=true, bookmarksopen=true, bookmarksopenlevel=3, pdfauthor={Manuel Pégourié-Gonnard}, pdftitle={L'extension xargs}, pdfsubject={Définitions de macros étendues pour LaTeX2e}, ]{hyperref} % %<*gobble> \else % %<*driver> \AlsoImplementation \usepackage[english]{babel} \usepackage[colorlinks=true, bookmarks=true, bookmarksnumbered=true, bookmarksopen=true, bookmarksopenlevel=3, pdfauthor={Manuel Pégourié-Gonnard}, pdftitle={The xargs package}, pdfsubject={Extended macro definitions for LaTeX2e}, ]{hyperref} \settowidth\MacroIndent{\rmfamily\scriptsize 000\ } \setlength\MacroTopsep{0pt} \usepackage[nohints, english]{minitoc} \mtcsetpagenumbers{secttoc}{off} \mtcsetrules{secttoc}{off} \mtcsetdepth{secttoc}{3} \setlength{\stcindent}{0pt} \mtcsetfont{secttoc}{subsection}{\normalfont} \newcommand\tocwithmini{% \dosecttoc[n] \setcounter{tocdepth}{1}\tableofcontents \setcounter{tocdepth}{3}\faketableofcontents} % %<*gobble> \fi % %<*driver|pilote> \newcommand\pf{\textsf} \newcommand\optstar{\meta{$*$}} \newcommand\topcs[1]{\texorpdfstring{\cs{#1}}{#1}} \newcommand\eTeX{$\varepsilon$-\TeX} \begin{document} \DocInput{xargs.dtx} \end{document} % %<*package> % \fi % % \GetFileInfo{xargs.dtx} % % \title{\iffrenchdoc L'extension \pf{xargs}\else The \pf{xargs} package\fi} % \author{Manuel Pégourié-Gonnard\\ % \href{mailto:mpg@elzevir.fr}{mpg@elzevir.fr}} % \date{\fileversion\ (\filedate)} % % \maketitle % \iffrenchdoc\else \tocwithmini \fi % % \iffrenchdoc\else % \medskip % \emph{Important note for French users}: a French version of the user % documentation is included in the \nolinkurl{xargs-fr.pdf} file. % \fi % % \section{Introduction} % % \iffrenchdoc % % \LaTeXe{} permet de définir facilement des commandes ayant un argument % optionel. Cependant, il y a deux restrictions : il peut y avoir au plus un % argument optionel, et ce doit être le premier. L'extension \pf{xargs} % fournit des versions étendues de \cs{newcommand} et de ses analogues % standard, qui ne présentent pas ces restrictions : il est désormais % facile de définir des commandes avec plusieurs arguments optionnels, % placés où l'on veut, par une syntaxe agréable du style % \meta{clé}=\meta{valeur}. Par exemple, voici comment définir une % commande avec deux arguments optionnels. % % \begin{center} % |\newcommandx*\coord[3][1=1, 3=n]{(#2_{#1},\ldots,#2_{#3})}| % \newcommandx*\coord[3][1=1, 3=n]{(#2_{#1},\ldots,#2_{#3})} % \par\medskip % \begin{tabular}{ll} % |$\coord{x}$| & $\coord{x}$ \\ % |$\coord[0]{y}$| & $\coord[0]{y}$ \\ % |$\coord{z}[m]$| & $\coord{z}[m]$ \\ % |$\coord[0]{t}[m]$| & $\coord[0]{t}[m]$ \\ % \end{tabular} % \end{center} % % \else % % Defining commands with an optional argument is easy in \LaTeXe{}. % There is, however, two limitations: you can make only one argument % optional and it must be the first one. The \pf{xargs} package provide % extended variants of \cs{newcommand} \& friends, for which these % limitations no longer hold: It is now easy to define commands with % many (and freely placed) optional arguments, using a nice % \meta{key}=\meta{value} syntax. For example, the following defines a % command with two optional arguments. % % \begin{center} % |\newcommandx*\coord[3][1=1, 3=n]{(#2_{#1},\ldots,#2_{#3})}| % \newcommandx*\coord[3][1=1, 3=n]{(#2_{#1},\ldots,#2_{#3})} % \par\medskip % \begin{tabular}{ll} % |$\coord{x}$| & $\coord{x}$ \\ % |$\coord[0]{y}$| & $\coord[0]{y}$ \\ % |$\coord{z}[m]$| & $\coord{z}[m]$ \\ % |$\coord[0]{t}[m]$| & $\coord[0]{t}[m]$ \\ % \end{tabular} % \end{center} % % \fi % % \section{Usage} % % \iffrenchdoc % % \subsection{Les bases} % % L'extension \pf{xargs} fournit des analogues de toutes les macros de % \LaTeXe{} relatives à la définition de macros. Les macros de \pf{xargs} ont % le même nom que leur analogue standard, mais avec un |x| supplémentaire à la % fin. En voici la liste complète. % % \begin{center} % \begin{tabular}{ll} % \cs{newcommandx} & \cs{renewcommandx} \\ % \cs{newenvironmentx} & \cs{renewenvironmentx} \\ % \cs{providecommandx} & \cs{DeclareRobustCommandx} \\ % \cs{CheckCommandx} % \end{tabular} % \end{center} % % Si vous ne connaissez pas toutes ces commandes, ne vous inquiétez pas. % Vous pouvez utiliser seulement les analogues des macros que vous % connaissez ; ou apprendre les autres par exemple dans le livre de % \bsc{Lamport}, le \LaTeX{} Companion, ou tout autre manuel sur \LaTeXe. % % \medskip % % Ces commandes partageant toutes la même syntaxe, je parlerai seulement % de |\newcommandx| par la suite, mais gardez à l'esprit que les % explications sont valables pour les autres commandes. (Bien sûr, pour % les environnements, il y a un dernier argument en plus, pour la % définition de fin.) Voici la syntaxe complète de |\newcommand|. % % \begin{center} % \cs{newcommandx}\optstar\marg{commande}\oarg{nombre}\oarg{liste}^^A % \marg{définition} % \end{center} % % Rappelons brièvement tout ce qui est commun avec la syntaxe usuelle, à % savoir tout sauf \meta{liste}. Si une $*$ est présente, elle signifie % que la macro crée est \emph{courte} au sens de \TeX{}, c'est-à-dire % que ses arguments ne peuvent pas contenir de saut de paragraphe % (\cs{par} ou ligne vide). La \meta{commande} est n'importe quelle % séquence de contrôle, que vous pouvez ou non entourer d'accolades % suivant vos goûts. Le \meta{nombre} définit le nombre total d'argument % de la \meta{commande}, c'est un entier compris entre $0$ et $9$. La % \meta{définition} est un texte équilibré en accolades, et où chaque % caractère |#| est suivi soit d'un chiffre représentant un des % arguments, soit d'un autre caractère |#|. Les arguments \meta{nombre} % et \meta{liste} sont optionnels. % % \medskip % % La partie intéressante maintenant. La \meta{liste} est une\ldots{} % liste (!) d'éléments de la forme \meta{chiffre}=\meta{valeur}, séparés % par des virgules. Le \meta{chiffre} doit être un entier compris entre % $1$ et le nombre d'arguments, donné par \meta{nombre}. La % \meta{valeur} est n'importe quelle texte équilibré en accolades. Il % peut être vide si vous le souhaitez : le signe égal qui le précède % peut alors être omis. Tous les arguments dont le numéro figure en tant % que \meta{chiffre} dans la \meta{liste} seront optionnels, avec pour % valeur par défaut celle donnée par la \meta{valeur} correspondante. % % Quelques remarques supplémentaires sur la syntaxe de la \meta{liste}, % que vous pouvez sauter si vous êtes familiers avec la syntaxe fournie % par \pf{xkeyval}. Vu que les éléments sont séparés par des virgules, % si une \meta{valeur} doit contenir une virgule, il faut entourer la % valeur par des accolades pour protéger la virgule. (Cette précaution % est également indispensable si la \meta{valeur} contient une accolade % fermante.) Ne vous inquiétez pas, cette parie d'accolade sera retirée % ultérieurement. D'ailleurs, jusqu'à trois paires d'accolades seront % retirées ainsi, et si vous voulez vraiment que votre valeur reste % entourée d'accolades, il vous faudra écrire quelque chose % comme~|1={{{{\large blabla}}}}|. % % \medskip % % C'est tout pour les bases : vous en savez maintenant assez pour % utiliser \pf{xargs}, et vous pouvez laisser la fin de la documentation % pour plus tard si vous voulez. Si, au contraire, vous vous demandez ce % qui se passe avec plusieurs arguments optionnels à la suite, que vous % voulez effectuer des définitions globales, ou que vous aves besoin de % connaître les limites précises de \pf{xargs}, vous pouvez lire les % sections suivantes. % % \subsection{La clé \texttt{usedefault}} % % Voyons donc se qui se passe quand plusieurs arguments optionnels se % suivent. Le comportement par défaut est calqué sur celui de commandes % \LaTeX{} comme \cs{makebox} et \cs{parbox} : on ne peut spécifier une % valeur pour le troisième argument optionnel que si on l'a fait pour % les deux premiers. Par exemple, dans l'exemple du début, remarquez % comment j'avais pris soin de placer l'argument obligatoire au milieu % pour séparer les arguments optionnels. % % Cependant, ce n'est pas très pratique, et on aimerait pouvoir choisir % l'ordre des arguments plutôt selon leur sens, sans se poser de % questions. Bien, la clé |usedefault| est justement là pour ça : % incluez-la dans la \meta{liste}, et vous pouvez désormais utiliser % |[]| pour sauter un argument optionnel, en utilisant sa valeur par % défaut. % % \begin{center} % |\newcommandx*\coord[3][2=1,3=n,usedefault]{(#2_{#1},\ldots,#2_{#3})}| % \newcommandx*\coord[3][2=1, 3=n, usedefault]{(#2_{#1},\ldots,#2_{#3})} % \par\medskip % \begin{tabular}{ll} % |$\coord{x}$| & $\coord{x}$ \\ % |$\coord{y}[0]$| & $\coord{y}[0]$ \\ % |$\coord{z}[][m]$| & $\coord{z}[][m]$ \\ % |$\coord{t}[0][m]$| & $\coord{t}[0][m]$ \\ % \end{tabular} % \end{center} % % Bien sûr, sur cet exemple simple, c'est surtout une histoire de goût, % mais parfois |usedefault| peut vous épargner pas mal de frappe % inutile, car la valeur par défaut d'un argument est parfois longue, et % qu'on a pas toujours assez d'arguments obligatoires pour séparer les % arguments optionnels comme plus haut. % % Cette utilisation simple de |usedefault| présente un inconvénient : % vous ne pouvez plus spécifier la valeur vide pour un argument % optionnel. En fait, il faut nécessairement une valeur spéciale de % l'argument pour dire \og utiliser la valeur par défaut \fg{}, mais ce % n'est pas nécessairement la chaîne vide : en fait, on peut choisir % cette valeur en disant |usedefault=|\meta{valeur}. L'exemple suivant % ne sert à rien, à part illustrer ceci. % % \begin{center} % |\newcommandx*\test[2][1=A, 2=B, usedefault=@]{(#1,#2)}| % \newcommandx*\test[2][1=A, 2=B, usedefault=@]{(#1,#2)} % \par\medskip % \begin{tabular}{ll} % |\test[b]| & \test[b] \\ % |\test[][b]| & \test[][b] \\ % |\test[@][b]| & \test[@][b] \\ % \end{tabular} % \end{center} % % \subsection{Ajouter un préfixe} % % La commande |\newcommand| standard permet de définir au choix des % macros \og longues \fg{} (dont les arguments peuvent contenir des % \cs{par}) ou \og courtes \fg{} (les \cs{par} ou lignes vides sont % interdits dans les arguments) au moyen de l'étoile optionnelle. C'est % une partie de ce que \TeX{} appelle un préfixe, plus précisément la % composante \cs{long}. Les autres composantes d'un préfixe peuvent être % \cs{global}, \cs{outer}, ou (avec \eTeX) \cs{protected}. Il n'y a pas % de moyen d'utiliser ces composantes avec \cs{newcommand}, bien que, % par exemple, \cs{global} puisse être utile pour qu'une définition % faite à l'intérieur d'un groupe (comme un environnement) ne soit pas % \og oubliée \fg{} à la fin. (Pour des détails sur les autres, voir le % \TeX book ou le manuel d'\eTeX.) % % Avec \pf{xargs}, vous pouvez utiliser la clé |addprefix|, \emph{sauf} % pour la composante \cs{outer}, qui n'est pas et ne sera pas supportée % (et, à ma connaissance n'est jamais utilisée dans \LaTeXe). Remarquons % que cette clé \emph{ajoute} une préfixe à celui en cours, elle % n'écrase rien. Au début, le préfixe par défaut est \cs{long}, ou vide % si une étoile a été utilisée. Par exemple, les deux instructions % suivantes ont exactement le même effet. % % \begin{quote} % |\newcommandx*\truc[0][addprefix=\global, addprefix=\long,|\\ % | addprefix=\protected]{machin}|\\ % |\newcommandx\truc[0][addprefix=\global\protected]{machin}| % \end{quote} % % En passant, les macros avec au moins un argument optionnel sont % définies de façon robuste au sens que \LaTeXe{} donne à ce mot, je ne % sais donc pas si le préfixe \cs{protected} est très utile. Je pense % que la possibilité d'effectuer des définitions globales est l'usage % principale de la clé |usedefault|. % % \subsection{Compatibilité et limitations connues} % % La mauvaise nouvelle (les limitations) en premier. Il y en a % essentiellement une : on ne peut pas utiliser dans la \meta{liste} % certaines choses, qui ne sont pas gérées correctement par % \pf{xkeyval}. Précisément, il s'agit des signes |#| (les lexèmes de % \cs{catcode} $6$) et des lexèmes \cs{par}. Aussi, aucune composante % de la \meta{liste} ne doit avoir l'air mal équilibrée en \cs{if}s aux % yeux de \TeX. Seule la première de ces limitations est partagée pas le % \cs{newcommand} standard, qui n'accepte pas non plus de |#| dans les % valeurs par défaut. Autrement, vous pouvez utiliser ce que vous % voulez, où vous voulez (autant que je sache). % % Maintenant les bonnes nouvelles. J'ai pris grand soin que les macros % définies avec \pf{xargs} ressemblent autant que possibles à celles % définies avec les commandes standard de \LaTeX. En fait, quand on % demande à \cs{newcommandx} d'effectuer une définition que % \cs{newcommand} aurait pu faire, la commande sera définie exactement % comme si on avait utilisé ce dernier. Plus précisément, le code % suivant (et les tests similaires) ne renvoie pas d'avertissement. % % \begin{quote} % |\newcommandx\truc[2][1=default]{def-truc}|\\ % |\CheckCommand\truc[2][default]{def-truc}|\\ % |\newcommand\chose{def-chose}|\\ % |\CheckCommandx*\chose[0][addprefix=\long]{def-chose}| % \end{quote} % % De plus, il y a seulement trois points (à ma connaissance) sur % lesquels les commandes d'\pf{xargs} diffèrent de celles de \LaTeX{}. % Le premier a déjà été évoqué, c'est la limitation sur le \meta{liste} % due à \pf{xkeyval}. Les deuxièmes et troisièmes points, par contre, % sont censés être positifs. Le deuxième est donc, que j'ai essayé % d'éviter de reproduire dans \cs{CheckCommandx} deux % problèmes\footnote{% % \url{http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/3971}} % dont souffre l'implémentation actuelle de \cs{CheckCommand} dans % \LaTeX. % % Le dernier point concerne la gestion des espaces, lors de la recherche % du prochain caractère, pour déterminer s'il s'agit ou non d'un crocher % carré, quand on teste la présence d'un argument optionnel. Pour ceci, % je n'utilise ni la version du noyau, ni celle d'\pf{amsmath}, de % \cs{@ifnextchar}, mais la mienne, qui a le comportement suivant : elle % avale les espaces jusqu'à trouver le prochain caractère, puis les % restitue si ce n'était pas le début d'un argument optionnel. Je ne % suis plus tout à fait sûr que ce soit la bonne façon de faire, et il % est probable que je ferai une option à ce sujet dans une prochaine % version, afin que l'utilisateur puisse choisir son comportement % préféré. % % \bigskip % % \begin{quote} % Vous savez maintenant absolument tout ce qu'il y a à savoir sur % l'utilisation de \pf{xargs}. Si vous souhaitez vous pencher sur son % implémentation, il vous faudra lire les commentaires en anglais car je % n'ai pas eu le courage de commenter mon code en deux langues. % \end{quote} % % \begin{center}\large % C'est tout pour cette fois ! \\ % Amusez-vous bien avec \LaTeX{} ! % \end{center} % % \else % % \subsection{Basics} % % ^^A \DescribeMacro{\newcommandx} % ^^A \DescribeMacro{\renewcommandx} % ^^A \DescribeMacro{\newenvironmentx} % ^^A \DescribeMacro{\renewenvironmentx} % ^^A \DescribeMacro{\providecommandx} % ^^A \DescribeMacro{\DeclareRobustCommandx} % ^^A \DescribeMacro{\CheckCommandx} % The \pf{xargs} package defines an extended variant for every \LaTeX{} % macro related to macro definition. \pf{xargs}'s macro are named after % their \LaTeX{} counterparts, just adding an |x| at end (see the list % in the margin). Here is the complete list: % % \begin{center} % \begin{tabular}{ll} % \cs{newcommandx} & \cs{renewcommandx} \\ % \cs{newenvironmentx} & \cs{renewenvironmentx} \\ % \cs{providecommandx} & \cs{DeclareRobustCommandx} \\ % \cs{CheckCommandx} % \end{tabular} % \end{center} % % If you are not familiar with all of them, you can either just keep % using the commands you already know, or check Lamport's book or the % \LaTeX{} Companion (or any \LaTeXe{} manual) to learn the others. % % \medbreak % % Since these commands all share the same syntax, I'll always use % \cs{newcommandx} in the following, but remember it works the same for % all seven commands. (Of course, command about environments take one % more argument, for the end definition.) Here is |\newcommandx|'s % complete syntax. % % \begin{center} % \cs{newcommandx}\optstar\marg{command}\oarg{number}\oarg{list}^^A % \marg{definition} % \end{center} % % Everything here is the same as the usual \cs{newcommand} syntax, % except \meta{list}. Let's recall this briefly. The optional $*$ make % \LaTeX{} define a ``short'' macro, that is a macro that won't accept a % paragraph break (\cs{par} or an empty line) inside its argument; if % you don't put it, the macro will be long. \meta{command} is any % control sequence, and can but need not be enclosed in braces, as you % like. The \meta{number} specifies how many arguments your macro will % take (including optional ones): it should be a non-negative integer, % and at most $9$. The macro's \meta{definition} is a balanced text, % where every |#| sign must be followed by a number, thus representing % an argument, or by another |#| sign. The two arguments \meta{number} % and \meta{list} are optionals. % % \medskip % % Now comes the new and funny part. \meta{list} is a coma-separated list % of element \meta{digit}=\meta{value}. Here, \meta{digit} should be % non-zero, and at most \meta{number} (the total number of arguments). % The \meta{value} is any balanced text, and can be empty. If so, the % |=| sign becomes optional: You only need to write \meta{digit} if you % want the \meta{digit}th argument to be optional, with empty default % value. Of course, every argument whose number is a \meta{digit} in the % \meta{list} becomes optional, with \meta{value} as its default value. % % If you are not very familiar with some aspects of the syntax provided % by the \pf{xkeyval} package, you may be interested in the following % remarks about the syntax of \meta{list}. Since \meta{list} is % coma-separated, if you want to use a coma inside a \meta{value}, you % need to enclose it (either the coma or the whole \meta{value}) in % braces. The same applies if you want to use a closing square bracket % inside the \meta{list}. Don't worry about those unwanted braces, they % will be removed later. Actually, \pf{xkeyval} removes up to $3$ braces % set: If you really want braces around a value, you need to type % something like |1={{{{\large stuff}}}}|. % % \medskip % % That's all for the basics: you are now ready to use \pf{xargs}, and % can stop reading this doc now if you want. If, however, you are % wondering about what happens if you have many successive optional % arguments, or care about doing global definitions, or even need to % know precisely the limitations of \pf{xargs}, go on with the next % subsections. % % \subsection{The \texttt{usedefault} key} % % So, what happens with many successive optional arguments? The default % behaviour is that of \LaTeX's commands like \cs{makebox} or % \cs{parbox}: you can't specify the third argument if you didn't % specify the first two ones. For example, in my first example, please % notice how I used the mandatory argument to separate the two optional % ones. % % However, maybe you don't like this and prefer choosing your argument's % order as you want, according to their logical meaning. Ok. That's % exactly what the |usedefault| key is for. Just include it in the % \meta{list}, and you can now use |[]| to skip one optional argument % (using its default value) and go to the next one. % % \begin{center} % |\newcommandx*\coord[3][2=1,3=n,usedefault]{(#2_{#1},\ldots,#2_{#3})}| % \newcommandx*\coord[3][2=1, 3=n, usedefault]{(#2_{#1},\ldots,#2_{#3})} % \par\medskip % \begin{tabular}{ll} % |$\coord{x}$| & $\coord{x}$ \\ % |$\coord{y}[0]$| & $\coord{y}[0]$ \\ % |$\coord{z}[][m]$| & $\coord{z}[][m]$ \\ % |$\coord{t}[0][m]$| & $\coord{t}[0][m]$ \\ % \end{tabular} % \end{center} % % Of course, on this simple example, this is merely a matter of % taste, but sometimes the |usedefault| key can save you a lot of % typing, since the optional value for an argument can be rather long, % and you don't always have enough mandatory arguments to separate the % optional ones. % % This simple way of using |usedefault| has one problem: you can no more % specify an empty value for an optional argument. Of course you need a % special value of the argument to mean ``please use the default value % there'', but it doesn't need to be always the empty string. Actually, % you can say |usedefaut=|\meta{flag} to choose this special value. The % following example has no other purpose that illustrating this. % % \begin{center} % |\newcommandx*\test[2][1=A, 2=B, usedefault=@]{(#1,#2)}| % \newcommandx*\test[2][1=A, 2=B, usedefault=@]{(#1,#2)} % \par\medskip % \begin{tabular}{ll} % |\test[b]| & \test[b] \\ % |\test[][b]| & \test[][b] \\ % |\test[@][b]| & \test[@][b] \\ % \end{tabular} % \end{center} % % \subsection{Using a prefix} % % Standard |\newcommand| allows you to define so-called ``long'' (i. e. % the arguments may contain a \cs{par} token) or ``short'' (they % may not) macros with the optional star. This is part of what \TeX{} % calls a ``prefix'' for the definition, namely the \cs{long} prefix. % Other components of the prefix are \cs{global}, \cs{outer}, and % \eTeX's \cs{protected}. There is no way to use them with % |\newcommand|, though \cs{global} can be specially interesting in % order to avoid definitions made inside a group (e. g. an environment) % ``disappear'' at the end of the group. (For details about the other % possible components, see the \TeX book and \eTeX's manual.) % % With \pf{xargs}, you can use the |addprefix| key, \emph{except} for % the \cs{outer} prefix, which is not and will not be supported (and not % used anywhere I know in \LaTeXe, either). Please note that it % \emph{adds} a prefix to the current one, which by default is \cs{long} % for the unstarred form, and empty for the starred form. You can also % use this key many times: all prefixes will be merged together. For % example, the following two instructions do the exactly the same thing. % % \begin{quote} % |\newcommandx*\foo[0][addprefix=\global, addprefix=\long,|\\ % | addprefix=\protected]{bar}|\\ % |\newcommandx\foo[0][addprefix=\global\protected]{bar}| % \end{quote} % % By the way, macros with at least one optional argument are already % robust in \LaTeXe's meaning of the word, so I don't know if the % \cs{protected} prefix is very interesting there. Maybe the ability to % perform global definitions is the main use of the |addprefix| key. % % \subsection{Compatibility and known limitations} % % Okay, let's see the bad things (the limitations) first. There is % essentially one: you cannot use in the \meta{list} some elements, % because \pf{xkeyval} won't handle them properly. Namely, hash signs % (tokens with \cs{catcode} $6$), and \cs{par} tokens are forbidden, and % any part of the list should look properly \cs{if}-balanced to \TeX. % Only the first limitation is shared by the standard \cs{newcommand}: % it accepts no hash signs in a default value. Apart from this, you can % use anything you want, everywhere you want, as far as I know. % % Now the ``good'' features. I've tried hard to make macros defined with % \pf{xargs} as much similar as possible with those defined with % standard \LaTeX's commands. Actually, when \cs{newcommandx} is asked % to perform a definition which \cs{newcommand} can do, the resulting % macro will be defined exactly as the latter would have done. More % precisely, the following code (and similar tests) issues no warning. % % \begin{quote} % |\newcommandx\foo[2][1=default]{def-foo}|\\ % |\CheckCommand\foo[2][default]{def-foo}|\\ % |\newcommand\baz{def-baz}|\\ % |\CheckCommandx*\baz[0][addprefix=\long]{def-baz}| % \end{quote} % % Moreover, there are only three points (to my knowledge) where % \pf{xargs}'s commands differ from the kernel ones. The first one was % already mentioned, it is due to using \pf{xkeyval} for precessing the % \meta{list}. The second and third points are meant to be good one. % Second point is: There is a bug\footnote{% % \url{http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/3971}} % in the current implementation of \cs{CheckCommand}, that I obviously % tried to avoid. % % Last, I don't use kernel's (nor \pf{amsmath}'s) version of % \cs{@ifnextchar}. Indeed, a problem arises when the last argument of a % command is optional: we have to make a choice about what to do with % spaces while scanning ahead for a left square bracket. I chose to scan % over them, and the put them back in the text in there were no % optional argument. I'm no more sure it is the right thing to do, and % I'll probably make an option to let the user decide in a future % version. % % \fi % % \StopEventually{} % % \section{Implementation} % % First, I'd like to recall the way \LaTeXe{} handles optional % arguments. For example, a command \cs{foo} defined with % |\newcommand*\foo[2][bar]{baz}| is implemented as the pair: % \begin{quote} % |\foo=macro:->\@protected@testopt\foo\\foo{bar}| \\ % |\\foo=macro:[#1]#2->baz| % \end{quote} % There is one ``external'' macro \cs{foo}, which is merely an argument % grabber or a parser, and an internal macro \cs{\string\foo}, which is % the ``real'' one. In \pf{xargs} this is quite the same, except that % the external macro is a bit more sophisticated. This idea of the % external macro being a parser, giving the arguments to the internal % one in a standard form, reflects in the name of \LaTeX3's experimental % package for extended argument syntax: \pf{xparse}. % % Here the approach is a bit different. Of course, the idea is still to % build a parser for the specified syntax, but since \cs{newcommandx} % user syntax is based on \pf{xkeyval}, we also have to care about keys % and there default values, and to put the whole thing in the correct % order before we build up the parser. We also seek for compatibility % with existing \LaTeXe{} commands, which adds a few tests. The % organisation is as follows. % % \begingroup \def\leaders#1#2{} % \secttoc[n] % \endgroup % % Before we really begin, just a few preliminaries. % First, load the \pf{xkeyval} package for it's nice key=value syntax. % \begin{macrocode} \RequirePackage{xkeyval} % \end{macrocode} % % \begin{macro}{\xargs@max} % \begin{macro}{\xargs@temp} % \begin{macro}{\xargs@toksa} % \begin{macro}{\xargs@toksb} % Then allocate a few registers and make sure the name of our private scratch % macro is free for use. Note that for certain uses, we really need a % \cs{toks} register because the string used can possibly contain |#| % characters. Sometimes I also use a \cs{toks} register instead of a macro % just for ease of use (writing less \cs{expandafter}s). % \begin{macrocode} \@ifdefinable\xargs@max{\newcount\xargs@max} % \end{macrocode} % \begin{macrocode} \@ifdefinable\xargs@temp\relax \@ifdefinable\xargs@toksa{\newtoks\xargs@toksa} \@ifdefinable\xargs@toksb{\newtoks\xargs@toksb} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Parser} % % Let's begin with a simple, concrete example. Recall that we defined a % command \cs{vect} with % |\newcommandx\vect[3]{1=0,3=n}{(#2_{#1},\ldots,#2_{#3}}| and have a % look at its implementation. % \begin{quote} % |\vect=macro:->\@protected@testopt@xargs\vect\\vect|\\ % \hspace*{1em}|{\xargs@test@opt{0},\xargs@put@arg,\xargs@test@opt{n},}|\\ % |\\vect=macro:[#1]#2[#3]->(#2_{#1},\ldots ,#2_{#3})| % \end{quote} % % As you can see, the parser is stored as a coma-separated list of % ``actions''. Here the only actions are to grab a mandatory argument or % to check for the presence of of an optional one. In this case, special % care is taken about spaces. Actually, there can be one more action, % associated with the |usedefaut| user key: \cs{xargs@setdefflag}, which % specifies the flag that says ``use the default value''. % % The parsing is done by a loop that read and executes each action from % the originating list, and concurrently builds an argument list such as % |[0]{x}[m]| to be passed to |\\vect| for example. All of this happens % inside a group. % % \begin{macro}{\@protected@testop@xargs} % This first macro closely resembles kernel's \cs{@protected@testopt} % (similarity in their names is intentional, see \cs{CheckCommandx}). It % just checks the protection context and call the real argument grabbing % macro. % \begin{macrocode} \newcommand*\@protected@testopt@xargs[1]{% \ifx\protect\@typeset@protect \expandafter\xargs@read \else \@x@protect#1% \fi} % \end{macrocode} % \end{macro} % \begin{macro}{\xargs@read} % Initiate the loop. \cs{xargs@toksa} will become the call to the % internal macro with all arguments, \cs{xargs@toksb} contains the % actions list for arguments grabbing. % \begin{macrocode} \newcommand*\xargs@read[2]{% \begingroup \xargs@toksa{#1}% \xargs@toksb{#2}% \xargs@continue} % \end{macrocode} % \end{macro} % \begin{macro}{\xargs@continue} % \begin{macro}{\xargs@pick@next} % Each iteration of the loop consist of two steps: pick the next action % (and remove it from the list), and execute it. When there is no more % action in the list, it means the arguments grabbing stage is over, and % it's time to execute the internal macro by expanding the contents of % \cs{xargs@toksa}. % \begin{macrocode} \newcommand\xargs@continue{% \expandafter\xargs@pick@next\the\xargs@toksb,\@nil \xargs@temp} % \end{macrocode} % \begin{macrocode} \@ifdefinable\xargs@pick@next{% \def\xargs@pick@next#1,#2\@nil{% \def\xargs@temp{#1}% \xargs@toksb{#2}% \ifx\xargs@temp\empty \def\xargs@temp{\expandafter\endgroup\the\xargs@toksa}% \fi}} % \end{macrocode} % \end{macro} % \end{macro} % \begin{macro}{\xargs@set@defflag} % Let's begin with the most simple action. % \begin{macrocode} \newcommand*\xargs@set@defflag[1]{% \def\xargs@default@flag{#1}} % \end{macrocode} % \end{macro} % \begin{macro}{\xargs@put@arg} % \begin{macro}{\xargs@test@opt} % \begin{macro}{\xargs@put@opt} % Now have a look at the argument grabbing macros. The first one, % \cs{xargs@put@arg}, just reads an undelimited argument in the input stack % and add it to the arguments list. \cs{xargs@testopt} checks if the next % non-space token is a square bracket to decide if it have to read an argument % from the input or use the default value, and takes care to enclose it in % square brackets. % \begin{macrocode} \newcommand\xargs@put@arg[1]{% \xargs@toksa\expandafter{\the\xargs@toksa{#1}}% \xargs@continue} % \end{macrocode} % \begin{macrocode} \newcommand*\xargs@test@opt[1]{% \xargs@ifnextchar[%] {\xargs@grab@opt{#1}}% {\xargs@put@opt{#1}}} % \end{macrocode} % \begin{macrocode} \newcommand\xargs@put@opt[1]{% \xargs@toksa\expandafter{\the\xargs@toksa[{#1}]}% \xargs@continue} % \end{macrocode} % \begin{macrocode} \@ifdefinable\xargs@grab@opt{% \long\def\xargs@grab@opt#1[#2]{% \toks@{#2}\edef\xargs@temp{\the\toks@}% \ifx\xargs@temp\xargs@default@flag \expandafter\@firstoftwo \else \expandafter\@secondoftwo \fi{% \xargs@put@opt{#1}% }{% \xargs@put@opt{#2}}}} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \begin{macro}{\xargs@ifnextchar} % \begin{macro}{\xargs@ifnch} % \begin{macro}{\xargs@xifnch} % Here comes a modified version of \cs{@ifnextchar}, that works like % kernel's one, except that it remembers how many spaces it gobbles and % puts them back in case the next non-space character isn't a match. Not % sure whether this is the better way to do, may change in future % versions. % \begin{macrocode} \newcommand\xargs@ifnextchar[3]{% \let\xargs@temp\empty \let\reserved@d=#1% \def\reserved@a{#2}% \def\reserved@b{#3}% \futurelet\@let@token\xargs@ifnch} % \end{macrocode} % \begin{macrocode} \newcommand\xargs@ifnch{% \ifx\@let@token\@sptoken \edef\xargs@temp{\xargs@temp\space}% \let\reserved@c\xargs@xifnch \else \ifx\@let@token\reserved@d \let\reserved@c\reserved@a \else \def\reserved@c{\expandafter\reserved@b\xargs@temp}% \fi \fi \reserved@c} % \end{macrocode} % \begin{macrocode} \@ifdefinable\xargs@xifnch{% \expandafter\def\expandafter\xargs@xifnch\space{% \futurelet\@let@token\xargs@ifnch}} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Keys} % % Okay, we are done with the parsing related macros. Now define stuff % for the definition of macros. In this part we use \pf{xkeyval}. Let's % start with the particular keys for options |addprefix| and |default|. % Like all \pf{xargs} key, we use the prefix |xargs| and the familly % |key|. The |addprefix| key can be used many times : each value is % appended at the end of the current prefix. Actually, we also construct % a ``short'' prefix (without any \cs{long}), for the external macro. We % define them globally, since key processing will happen inside a group, % and the definition outside. % \begin{macrocode} \@ifdefinable\xargs@key@addprefix{% \define@key[xargs]{key}{addprefix}[]{% \global\expandafter\def\expandafter\xargs@prefix\expandafter{% \xargs@prefix#1}% \xargs@makeshort#1\long\@nil}} % \end{macrocode} % The \cs{long} tokens are removed from the prefix in a fast and easy % way, assuming the input is a correct prefix. (It will crash e.g. if % the input contains an undefined CS or braces, but this will make all % crash later anyway. By the way, we also assume the prefix contains no % macro parameter token\ldots) % \begin{macrocode} \@ifdefinable\xargs@makeshort{% \def\xargs@makeshort#1\long#2{% \expandafter\gdef\expandafter\xargs@shortpref\expandafter{% \xargs@shortpref#1}% \ifx#2\@nil \else \expandafter\xargs@makeshort\expandafter#2% \fi}} % \end{macrocode} % The initial prefixes will be fixed by \cs{newcommandx} and its friends % when they check the star: empty in the stared version, \cs{long} % otherwise. For this, they use \pf{xargs}'s variant or % \cs{@star@or@long}: % \begin{macrocode} \newcommand\xargs@star@or@long[1]{% \global\let\xargs@shortpref\@empty \@ifstar{\gdef\xargs@prefix{}#1}{\gdef\xargs@prefix{\long}#1}} % \end{macrocode} % % Now, another particular key is the |usedefault| key. When used, it % just sets \cs{xargs@default@flag} and the corresponding boolean. Later % on, this will be used to possibly introduce a \cs{xargs@set@default} % action at the beginning of the actions list. % \begin{macrocode} \define@key[xargs]{key}{usedefault}[]{% \xargs@toksa{#1}\edef\xargs@default@flag{\the\xargs@toksa}} % \end{macrocode} % % \medskip % % Let's continue with the more important keys. We have to collect % through \pf{xkeyval} at most 9 actions numbered 1 to \cs{xargs@max} % (the total number of arguments), each of them being % \cs{xargs@test@opt} or \cs{xargs@put@arg}. Latter, we will use them to % build up the parser. % % \begin{macro}{\@namenewc} \begin{macro}{\xargs@action@1} % \begin{macro}{\xargs@action@2} \begin{macro}{\xargs@action@3} % \begin{macro}{\xargs@action@4} \begin{macro}{\xargs@action@5} % \begin{macro}{\xargs@action@6} \begin{macro}{\xargs@action@7} % \begin{macro}{\xargs@action@8} \begin{macro}{\xargs@action@9} % So our first task is to define container macros for the at most nine % actions which represent arguments parsing, with default value % \cs{xargs@put@arg} since every argument is mandatory unless specified. % \begin{macrocode} \providecommand\@namenewc[1]{% \expandafter\newcommand\csname #1\endcsname} % \end{macrocode} % \begin{macrocode} \@namenewc{xargs@action@1}{\xargs@put@arg} \@namenewc{xargs@action@2}{\xargs@put@arg} \@namenewc{xargs@action@3}{\xargs@put@arg} \@namenewc{xargs@action@4}{\xargs@put@arg} \@namenewc{xargs@action@5}{\xargs@put@arg} \@namenewc{xargs@action@6}{\xargs@put@arg} \@namenewc{xargs@action@7}{\xargs@put@arg} \@namenewc{xargs@action@8}{\xargs@put@arg} \@namenewc{xargs@action@9}{\xargs@put@arg} % \end{macrocode} % \end{macro} \end{macro} % \end{macro} \end{macro} % \end{macro} \end{macro} % \end{macro} \end{macro} % \end{macro} \end{macro} % \begin{macro}{\xargs@def@key} % The next macro will define the keys. Its first argument is the key's % number. The second argument will be discussed later. % \begin{macrocode} \newcommand*\xargs@def@key[2]{% \expandafter\@ifdefinable\csname xargs@key@#1\endcsname{% \define@key[xargs]{key}{#1}[]{% % \end{macrocode} % The first thing do to, before setting any action, is to check whether % this key can be used for this command, and complain if not. % \begin{macrocode} \ifnum\xargs@max<#1 \PackageError{xargs}{% Illegal argument label in\MessageBreak optional arguments description% }{% You are trying to make optional an argument whose label (#1) \MessageBreak is higher than the total number (\the\xargs@max) of parameters. \MessageBreak This can't be done and your demand will be ignored.}% \else % \end{macrocode} % If the key number is correct, it may be that the user is trying to use % it twice for the same command. Since it's probably a mistake, issue a % warning in such case. % \begin{macrocode} \expandafter\expandafter\expandafter \ifx\csname xargs@action@#1\endcsname\xargs@put@arg \else \PackageWarning{xargs}{% Argument #1 was allready given a default value.\MessageBreak Previous value will be overriden.\MessageBreak}% \fi % \end{macrocode} % If everything looks okay, define the action to be \cs{xargs@test@opt} % with the given value, and execute the (for now) mysterious second % argument. % \begin{macrocode} \@namedef{xargs@action@#1}{\xargs@test@opt{##1}}% #2% \fi}}} % \end{macrocode} % \end{macro} % \begin{macro}{\ifxargs@firstopt@} % \begin{macro}{\ifxargs@otheropt@} % \begin{macro}{\xargs@key@1} % \begin{macro}{\xargs@key@2} \begin{macro}{\xargs@key@3} % \begin{macro}{\xargs@key@4} \begin{macro}{\xargs@key@5} % \begin{macro}{\xargs@key@6} \begin{macro}{\xargs@key@7} % \begin{macro}{\xargs@key@8} \begin{macro}{\xargs@key@9} % The second argument is used to set the value for some \cs{if} which % will keep track of the existence of an optional argument other than % the first one, and the of the possibly optional nature of the first. % Such information will be useful when we will have to decide if we use % the \LaTeXe{} standard way or \pf{xargs} custom one to define the % macro. % \begin{macrocode} \newif\ifxargs@firstopt@ \newif\ifxargs@otheropt@ % \end{macrocode} % Now actually define the keys. % \begin{macrocode} \xargs@def@key1\xargs@firstopt@true \xargs@def@key2\xargs@otheropt@true \xargs@def@key3\xargs@otheropt@true \xargs@def@key4\xargs@otheropt@true \xargs@def@key5\xargs@otheropt@true \xargs@def@key6\xargs@otheropt@true \xargs@def@key7\xargs@otheropt@true \xargs@def@key8\xargs@otheropt@true \xargs@def@key9\xargs@otheropt@true % \end{macrocode} % \end{macro} \end{macro} \end{macro} % \end{macro} \end{macro} \end{macro} % \end{macro} \end{macro} \end{macro} % \end{macro} \end{macro} % \begin{macro}{\xargs@setkeys} % \begin{macro}{\xargs@check@keys} % We set the keys with the starred version of \cs{setkeys}, so we can % check if there were some strange keys we cannot handle, and issue a % meaningful warning if there are some. % \begin{macrocode} \newcommand\xargs@setkeys[1]{% \setkeys*[xargs]{key}{#1}% \xargs@check@keys} % \end{macrocode} % \begin{macrocode} \newcommand\xargs@check@keys{% \ifx\XKV@rm\empty \else \xargs@toksa\expandafter{\XKV@rm}% \PackageError{xargs}{% Illegal key or argument label in\MessageBreak optional arguments description% }{% You can only use non-zero digits as argument labels.\MessageBreak Other allowed keys are usedefault and addprefix.\MessageBreak You wrote: "\the\xargs@toksa".\MessageBreak I can't understand this and I'm going to ignore it.}% \fi} % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Definition} % % \begin{macro}{\xargs@add@args} % Now our goal is to build two lists from our up to nine argument % grabbers, the special action |\xargs@setdefflag| and not forgetting % the prefix. The first list is the coma-separated list of actions % already discussed. The second is the parameter text for use in the % definition on the internal macro, for example |[#1]#2[#3]|. The next % macro takes the content of a \cs{xargs@action@X} macro for argument % and adds the corresponding items to this lists. It checks if the first % token of its parameter is \cs{xargs@testopt} in order to know if the % |#n| has to be enclosed in square brackets. % \begin{macrocode} \newcommand\xargs@add@args[1]{% \xargs@toksa\expandafter{\the\xargs@toksa #1,}% \expandafter \ifx\@car#1\@nil\xargs@put@arg \xargs@toksb\expandafter\expandafter\expandafter{% \the\expandafter\xargs@toksb\expandafter##\the\count@}% \else \xargs@toksb\expandafter\expandafter\expandafter{% \the\expandafter\xargs@toksb\expandafter [\expandafter##\the\count@]}% \fi} % \end{macrocode} % \end{macro} % \begin{macro}{\xargs@process@keys} % Here comes the main input processing macro, which prepares the % information needed to define the final macro, and expands it to the % defining macro. % \begin{macrocode} \@ifdefinable\xargs@process@keys{% \long\def\xargs@process@keys#1[#2]{% % \end{macrocode} % Some initialisations. We work inside a group so that the default % values for the \cs{xargs@action@X} macros and the \cs{xargs@XXXopt@} % be automatically restored for the next time. % \begin{macrocode} \begingroup \xargs@setkeys{#2}% \xargs@toksa{}\xargs@toksb{}% % \end{macrocode} % Let's begin with the |usedefault| part. % \begin{macrocode} \@ifundefined{xargs@default@flag}{}{% \xargs@toksa\expandafter{% \expandafter\xargs@set@defflag\expandafter{% \xargs@default@flag}}} % \end{macrocode} % Then the main loop actually builds up the two lists in the correct % order. % \begin{macrocode} \count@\z@ \@whilenum\xargs@max>\count@ \do{% \advance\count@\@ne \expandafter\expandafter\expandafter\xargs@add@args \expandafter\expandafter\expandafter{% \csname xargs@action@\the\count@\endcsname}}% % \end{macrocode} % Then we need to address a special case: if only the first argument is % optional, we use \LaTeXe's standard \cs{newcommand} construct, and we % dont need an actions list like the one just build, but only the % default value for the first argument. In this case, we extract this % value from \cs{xargs@action@1} by expanding it two times with a % modified \cs{xargs@testopt} (and one more expansion step for the % |\csname| gives $3$, hence the $2^3-1 = 7$ \cs{expandafter}s). % \begin{macrocode} \ifxargs@otheropt@ \else \ifxargs@firstopt@ \let\xargs@test@opt\@firstofone \xargs@toksa\expandafter\expandafter\expandafter \expandafter\expandafter\expandafter\expandafter{% \csname xargs@action@1\endcsname}% \fi \fi % \end{macrocode} % Finally expand the stuff to the next macro and, while we're at it, % choose the next macro : depending of the existence and place of an % optional argument, use \LaTeX's or \pf{xargs}'s way. In the \LaTeX{} % case, however, we don't use \cs{@argdef} or \cs{xargdef} since we want % to be able to use a prefix (and we have more work done allready, too). % \begin{macrocode} \edef\xargs@temp{% \ifxargs@otheropt@ \noexpand\xargs@xargsdef \else \ifxargs@firstopt@ \noexpand\xargs@xargdef \else \noexpand\xargs@argdef \fi\fi \noexpand#1% \expandafter\noexpand\csname\string#1\endcsname {\the\xargs@toksa}{\the\xargs@toksb}}% % \end{macrocode} % Now we can close the group and forget all about key values, etc. Time % to conclude and actually define the macro. (The only thing not passed % as an argument is the prefix, which is globally set.) We also take % care to execute \cs{xargs@drc@hook} just outside the group. % \begin{macrocode} \expandafter\endgroup \expandafter\xargs@drc@hook \xargs@temp}} % \end{macrocode} % \end{macro} % \begin{macro}{\xargs@argdef} % \begin{macro}{\xargs@xargdef} % \begin{macro}{\xargs@xargsdef} % The first two next macros are modified versions of kernel's % \cs{@argdef} and \cs{@xargdef}, that do the same work, but use the % prefix we built, and also are simpler since they get the internal name % as an argument. The last one is the only new macro. % \begin{macrocode} \newcommand\xargs@argdef[5]{% \@ifdefinable#1{% \xargs@prefix\def#1#4{#5}}} % \end{macrocode} % \begin{macrocode} \newcommand\xargs@xargdef[5]{% \@ifdefinable#1{% \xargs@shortpref\def#1{\@protected@testopt#1#2{#3}}% \xargs@prefix\def#2#4{#5}}} % \end{macrocode} % \begin{macrocode} \newcommand\xargs@xargsdef[5]{% \@ifdefinable#1{% \xargs@shortpref\def#1{\@protected@testopt@xargs#1#2{#3}}% \xargs@prefix\def#2#4{#5}}} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \subsection{User macros} % % \begin{macro}{\newcommandx} % \begin{macro}{\xargs@newc} % All the internal macros are ready. It's time to define the user % commands, beginning with \cs{newcommandx}. Like its standard version, % it just checks the star and call the next macro wich grabs the number % of arguments. % \begin{macrocode} \newcommand\newcommandx{% \xargs@star@or@long\xargs@newc} % \end{macrocode} % \begin{macrocode} \newcommand*\xargs@newc[1]{% \@testopt{\xargs@set@max{#1}}{0}} % \end{macrocode} % \end{macro} % \end{macro} % \begin{macro}{\xargs@set@max} % Set the value of \cs{xargs@max}. If no optional arguments description % follows, simply call \cs{argdef} because all the complicated stuff is % useless here. % \begin{macrocode} \@ifdefinable\xargs@set@max{% \def\xargs@set@max#1[#2]{% \kernel@ifnextchar[%] {\xargs@max=#2 \xargs@check@max{#1}}% {\@argdef#1[#2]}}} % \end{macrocode} % \end{macro} % \begin{macro}{\xargs@check@max} % To avoid possible problems later, check right now that \cs{xargs@max} % value is valid. If not, warn the user and treat this value as zero. % Then begin the key processing. % \begin{macrocode} \newcommand\xargs@check@max{% \ifcase\xargs@max \or\or\or\or\or\or\or\or\or\else \PackageError{xargs}{Illegal number, treated as zero}{The total number of arguments must be in the 0..9 range.\MessageBreak Since your value is illegal, i'm going to use 0 instead.} \xargs@max0 \fi \xargs@process@keys} % \end{macrocode} % \end{macro} % % \medskip % % The other macros (\cs{renewcommandx} etc.) closely resemble their kernel % homologues, since they are mostly wrappers around some call to % \cs{xargs@newc}. There is however two exceptions: \cs{CheckCommand} % and \cs{DeclareRobustCommandx}. Indeed, the current implementation of % \cs{CheckCommand} in the kernel suffers from two bugs (see % \href{http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/3971} % {PR/3971}) which I'm trying to avoid. For \cs{DeclareRobustCommandx}, % the problem is to handle the prefix correctly: for that we use a hook, % in order to delay the external macro's definition until we get the % prefix right. So, let's see those two commands first. % % \begin{macro}{\CheckCommandx} % We begin as usual detecting the possible star. % \begin{macrocode} \newcommand\CheckCommandx{% \xargs@star@or@long\xargs@CheckC} \@onlypreamble\CheckCommandx % \end{macrocode} % \end{macro} % \begin{macro}{\xargs@CheckC} % \begin{macro}{\xargs@check@a} % \begin{macro}{\xargs@check@b} % First, we don't use the |#2#| trick from the kernel, since it can fail % if there are braces in the default values. Instead, we follow the % argument grabing method used for \cs{new@environment}, ie calling % \cs{kernel@ifnextchar} explicitly. % \begin{macrocode} \newcommand\xargs@CheckC[1]{% \@testopt{\xargs@check@a#1}0} \@onlypreamble\xargs@CheckC % \end{macrocode} % \begin{macrocode} \@ifdefinable\xargs@check@a{% \def\xargs@check@a#1[#2]{% \kernel@ifnextchar[%] {\xargs@check@b#1[#2]}% {\xargs@check@c#1{[#2]}}}} \@onlypreamble\xargs@check@a % \end{macrocode} % \begin{macrocode} \@ifdefinable\xargs@check@b{% \def\xargs@check@b#1[#2][#3]{% \xargs@check@c{#1}{[#2][{#3}]}}} \@onlypreamble\xargs@check@b % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \begin{macro}{\xargs@CheckC} % Here comes the major difference with the kernel version. If % |\\reserved@a| is defined, we not only check that it is equal to % |\\foo| (assuming \cs{foo} is the macro being tested), we also check % that \cs{foo} makes something sensible, with \cs{xargs@check@d}. % \begin{macrocode} \newcommand\xargs@check@c[3]{% \xargs@toksa{#1}% \expandafter\let\csname\string\reserved@a\endcsname\relax \xargs@renewc\reserved@a#2{#3}% \@ifundefined{\string\reserved@a}{% \ifx#1\reserved@a \else \xargs@check@complain \fi }{% \expandafter \ifx\csname\string#1\expandafter\endcsname \csname\string\reserved@a\endcsname \xargs@check@d \else \xargs@check@complain \fi}} \@onlypreamble\xargs@check@c % \end{macrocode} % \end{macro} % So, what do we want \cs{foo} to do? If |\\foo| is defined, \cs{foo} % should begin with one of the followings: % \begin{quote} % |\@protected@testopt \foo \\foo| \\ % |\@protected@testopt@xargs \foo \\foo| % \end{quote} % Since I'm to lazy to really check this, the \cs{xargs@check@d} macro % only checks if the \cs{meaning} of \cs{foo} begins with % \cs{@protected@test@opt} (without a space after it). It does this % using a macro with delimited argument. Here are preliminaries to this % definition: We need to have this string in \cs{catcode} 12 tokens. % \begin{macrocode} \def\xargs@temp{\@protected@testopt} \expandafter\xargs@toksa\expandafter{\meaning\xargs@temp} \def\xargs@temp#1 {\def\xargs@temp{#1}} \expandafter\xargs@temp\the\xargs@toksa % \end{macrocode} % \begin{macro}{\xargs@check@d} % \begin{macro}{\xargs@check@e} % Now, \cs{xargs@check@c} just pass the \cs{meaning} of the command % \cs{foo} being checked to the allready mentionned macro with delimited % arguments, which will check if its first argument is empty (ie, if % \cs{foo}'s \cs{meaning} starts with what we want) and complain % otherwise. % \begin{macrocode} \expandafter\newcommand\expandafter\xargs@check@d\expandafter{% \expandafter\expandafter\expandafter\xargs@check@e \expandafter\meaning\expandafter\reserved@a\xargs@temp\@nil} \@onlypreamble\xargs@check@d % \end{macrocode} % \begin{macrocode} \@ifdefinable\xargs@check@e{% \expandafter\def\expandafter\xargs@check@e \expandafter#\expandafter1\xargs@temp#2\@nil{% \ifx\empty#1\empty \else \xargs@check@complain \fi}} \@onlypreamble\xargs@check@e % \end{macrocode} % \end{macro} % \end{macro} % \begin{macro}{\xargs@check@complain} % The complaining macro uses the name saved by \cs{xargs@check@c} in % \cs{xargs@toksa} in order to complain about the correct macro. % \begin{macrocode} \newcommand\xargs@check@complain{% \PackageWarningNoLine{xargs}{Command \the\xargs@toksa has changed. \MessageBreak Check if current package is valid}} \@onlypreamble\xargs@check@complain % \end{macrocode} % \end{macro} % % \begin{macro}{\DeclareRobustCommandx} % \begin{macro}{\xargs@DRC} % The \pf{xargs} version of \cs{DeclareRobustCommand}, and related % internal macros. % \begin{macrocode} \newcommand\DeclareRobustCommandx{% \xargs@star@or@long\xargs@DRC} % \end{macrocode} % \begin{macrocode} \newcommand*\xargs@DRC[1]{% \ifx#1\@undefined\else\ifx#1\relax\else \PackageInfo{xargs}{Redefining \string#1}% \fi\fi \edef\reserved@a{\string#1}% \def\reserved@b{#1}% \edef\reserved@b{\expandafter\strip@prefix\meaning\reserved@b}% % \end{macrocode} % Here is the difference from kernel's code: instead of doing the % definition of the user macro now, we just set the hook to do it % latter, when the correct prefix will be set, then disable itself for % next time. % \begin{macrocode} \edef\xargs@drc@hook{% \noexpand\xargs@shortpref\def\noexpand#1{% \ifx\reserved@a\reserved@b \noexpand\x@protect \noexpand#1% \fi \noexpand\protect \expandafter\noexpand\csname \expandafter\@gobble\string#1 \endcsname}% \expandafter\let\noexpand\xargs@drc@hook\relax}% \let\@ifdefinable\@rc@ifdefinable \expandafter\xargs@newc\csname \expandafter\@gobble\string#1 \endcsname} % \end{macrocode} % And finally set a default empty hook. % \begin{macrocode} \let\xargs@drc@hook\relax % \end{macrocode} % \end{macro} % \end{macro} % % \medskip % % From now on, there is absolutely nothing to comment, since the next % macros are mainly wrappers around \cs{xargs@newc}, just as kernel's % ones are wrappers around \cs{new@command}. So the code below is only % copy/paste with search\&replace from the kernel code. % % \begin{macro}{\renewcommandx} % \begin{macro}{\xargs@renewc} % The \pf{xargs} version of \cs{renewcommand}, and it's related internal % macro. % \begin{macrocode} \newcommand\renewcommandx{% \xargs@star@or@long\xargs@renewc} % \end{macrocode} % \begin{macrocode} \newcommand*\xargs@renewc[1]{% \begingroup\escapechar\m@ne \xdef\@gtempa{{\string#1}}% \endgroup \expandafter\@ifundefined\@gtempa{% \PackageError{xargs}{\noexpand#1undefined}{% Try typing \space \space to proceed.\MessageBreak If that doesn't work, type \space X \space to quit.}}% \relax \let\@ifdefinable\@rc@ifdefinable \xargs@newc#1} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\providecommandx} % \begin{macro}{\xargs@providec} % The \pf{xargs} version of \cs{providecommand}, and the related % internal macro. % \begin{macrocode} \newcommand\providecommandx{% \xargs@star@or@long\xargs@providec} % \end{macrocode} % \begin{macrocode} \newcommand*\xargs@providec[1]{% \begingroup\escapechar\m@ne \xdef\@gtempa{{\string#1}}% \endgroup \expandafter\@ifundefined\@gtempa {\def\reserved@a{\xargs@newc#1}}% {\def\reserved@a{\renew@command\reserved@a}}% \reserved@a} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\newenvironment} % \begin{macro}{\xargs@newenv} % \begin{macro}{\xargs@newenva} % \begin{macro}{\xargs@newenvb} % \begin{macro}{\xargs@new@env} % The \pf{xargs} version of \cs{newenvironment}, and related internal % macros. % \begin{macrocode} \newcommand\newenvironmentx{% \xargs@star@or@long\xargs@newenv} % \end{macrocode} % \begin{macrocode} \newcommand*\xargs@newenv[1]{% \@testopt{\xargs@newenva#1}0} % \end{macrocode} % \begin{macrocode} \@ifdefinable\xargs@newenva{% \def\xargs@newenva#1[#2]{% \kernel@ifnextchar[%] {\xargs@newenvb#1[#2]}% {\xargs@new@env{#1}{[#2]}}}} % \end{macrocode} % \begin{macrocode} \@ifdefinable\xargs@newenvb{% \def\xargs@newenvb#1[#2][#3]{% \xargs@new@env{#1}{[#2][{#3}]}}} % \end{macrocode} % \begin{macrocode} \newcommand\xargs@new@env[4]{% \@ifundefined{#1}{% \expandafter\let\csname#1\expandafter\endcsname \csname end#1\endcsname}% \relax \expandafter\xargs@newc \csname #1\endcsname#2{#3}% \xargs@shortpref\expandafter\def\csname end#1\endcsname{#4}} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\renewenvironment} % \begin{macro}{\xargs@renewenv} % The \pf{xargs} version of \cs{renewenvironment}, and the related % internal macro. % \begin{macrocode} \newcommand\renewenvironmentx{% \xargs@star@or@long\xargs@renewenv} % \end{macrocode} % \begin{macrocode} \newcommand*\xargs@renewenv[1]{% \@ifundefined{#1}{% \PackageError{xargs}{\noexpand#1undefined}{% Try typing \space \space to proceed.\MessageBreak If that doesn't work, type \space X \space to quit.}}% \relax \expandafter\let\csname#1\endcsname\relax \expandafter\let\csname end#1\endcsname\relax \xargs@newenv{#1}} % \end{macrocode} % \end{macro} % \end{macro} % % \bigskip % \begin{center}\Large % That's all folks!\\ % Happy \TeX ing! % \end{center} % % \Finale % % \iffalse % %<*batchfile> % \fi % \typeout{**************************************************} % \typeout{*} % \typeout{* To finish the installation you have to move the} % \typeout{* following file into a directory searched by TeX:} % \typeout{*} % \typeout{* \space\space\space\space xargs.sty} % \typeout{*} % \typeout{* Documentation is in xargs.dvi or xargs.pdf} % \typeout{*} % \typeout{* To produce french documentation, run} % \typeout{* \space\space \space\space (pdf)latex xargs-fr.drv} % \typeout{*} % \typeout{* Happy TeXing!} % \typeout{*} % \typeout{**************************************************} % \iffalse % % \fi \endinput