From 6cd0243de7b3c69971e9b28712b6aa797c107952 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Fri, 2 Jan 2009 00:43:24 +0000 Subject: xstring 1.5 (31dec08) git-svn-id: svn://tug.org/texlive/trunk@11796 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/tex/generic/xstring/xstring.tex | 957 ++++++++++++---------- 1 file changed, 529 insertions(+), 428 deletions(-) (limited to 'Master/texmf-dist/tex/generic/xstring') diff --git a/Master/texmf-dist/tex/generic/xstring/xstring.tex b/Master/texmf-dist/tex/generic/xstring/xstring.tex index 9da9444bb2c..7e2b35779e5 100644 --- a/Master/texmf-dist/tex/generic/xstring/xstring.tex +++ b/Master/texmf-dist/tex/generic/xstring/xstring.tex @@ -1,15 +1,24 @@ % __________________________________________________ % | | % | | -% | xstring v1.4b | +% | xstring v1.5 | % | | -% | November 16 2008 | +% | December 31 2008 | % | | % |__________________________________________________| % % This is xtring.tex % -% Christian Tellechea 2008 +% "xstring" package consists of the 11 following files: +% xstring.tex (this file) +% xstring.sty +% README +% xstring_doc_fr.tex, xstring_doc_fr.pdf (manual in french) +% xstring_doc_en.tex, xstring_doc_en.pdf (manual in english) +% test_latex.tex, test_latex.pdf (test file with LaTeX) +% test_etex.tex, test_etex.pdf (test file with Plain eTeX) +% +% Christian Tellechea 2008-2009 % email : unbonpetit@gmail.com % ------------------------------------------------------------------- % This work may be distributed and/or modified under the @@ -26,19 +35,10 @@ % % The Current Maintainer of this work is Christian Tellechea % ------------------------------------------------------------------- -% This work consists of the files -% xstring.tex (this file) -% xstring.sty -% README -% xstring_doc_fr.tex, xstring_doc_fr.pdf (manual in french) -% xstring_doc_en.tex, xstring_doc_en.pdf (manual in english) -% test_latex.tex, test_latex.pdf (test file with LaTeX) -% test_etex.tex, test_etex.pdf (test file with Plain eTeX) -% -\def\xstringversion {1.4b} -\def\xstringdate {2008/11/16} -\def\xstringfrenchdate {16 novembre 2008} -\def\xstringenglishdate{November $16^{\mathrm{th}}$ 2008} +\def\xstringversion {1.5} +\def\xstringdate {2008/12/31} +\def\xstringfrenchdate {31 d\'ecembre 2008} +\def\xstringenglishdate{December $31^{\mathrm{st}}$ 2008} \edef\CurrentAtCatcode{\the\catcode`\@} \catcode`\@=11 \newwrite\@xs@unused% pour les messages @@ -71,7 +71,7 @@ \def\@ifstar#1{\@ifnextchar *{\@firstoftwo{#1}}} \long\def\@testopt#1#2{\@ifnextchar[{#1}{#1[{#2}]}} \def\@empty{} -\fi% fin des définitions LaTeX +\fi% fin des d\'efinitions LaTeX % Gestion des messages d'erreur \def\@xs@linenumber{on input line \the\inputlineno} @@ -97,37 +97,37 @@ \immediate\write\m@ne{Package xstring Info: #1}% \endgroup} -% Messages d'information pour situations particulières +% Messages d'information pour situations particuli\`eres \def\@xs@BadNumArg {\@xs@infowrite{numerical argument out of range}} \def\@xs@ArgNotFound {\@xs@infowrite{substring not found in string}} \def\@xs@ArgEmpty {\@xs@infowrite{empty argument}} -% Ouvre un groupe où les catcodes sont à 12 et à 10 pour les espaces -% ensuite, appelle \@xs@ReadVerb qui lit un argument entre délimiteurs verb +% Ouvre un groupe o\`u les catcodes sont \`a 12 et \`a 10 pour les espaces +% ensuite, appelle \@xs@ReadVerb qui lit un argument entre d\'elimiteurs verb \def\@xs@MakeVerb{% lit 1 argument et le transforme en verb - \begingroup% groupe où les catcodes sont à 12 pour la lecture suivante + \begingroup% groupe o\`u les catcodes sont \`a 12 pour la lecture suivante \def\do##1{\catcode`##112\relax}% \dospecials% on entre dans le mode verb \obeyspaces% et on tient compte des espaces \@xs@ReadVerb}% et on va lire l'argument -% Définit \@xs@ReadVerb qui lit un argument entre délimiteurs verb -\def\setverbdelim#1{% définit quel est le délimiteur de verb +% D\'efinit \@xs@ReadVerb qui lit un argument entre d\'elimiteurs verb +\def\setverbdelim#1{% d\'efinit quel est le d\'elimiteur de verb \expandafter\ifx\expandafter\@empty\detokenize\expandafter{\@xs@gobblefirstchar#1}\@empty \else \@xs@warningwrite{verb delimiter is not a single char}% \fi - \def\@xs@ReadVerb##1#1##2#1{% lit ##2 qui est entre les délimiteurs de verb + \def\@xs@ReadVerb##1#1##2#1{% lit ##2 qui est entre les d\'elimiteurs de verb \endgroup% on ferme le groupe - \@xs@afterreadverb{##2}}}% on appelle l'exécution de fin + \@xs@afterreadverb{##2}}}% on appelle l'ex\'ecution de fin -% Assigne l'argument entre délimiteur verb dans la sc #1 +% Assigne l'argument entre d\'elimiteur verb dans la sc #1 \def\verbtocs#1{% \def\@xs@afterreadverb##1{\edef#1{##1}}% \@xs@MakeVerb} -% A l'aide d'un pont d'\expandafter, développe d'un niveau toutes -% les uneités syntaxiques de #1 puis et assigne le résultat à \@xs@reserved@A +% D\'eveloppe d'un niveau toutes les unit\'es syntaxiques +% de #1 puis et assigne le r\'esultat \`a \@xs@reserved@A \def\@xs@expandallonelevel#1#2\@xs@nil{% \expandafter\@xs@addtomacro\expandafter\@xs@reserved@A\expandafter{#1}% \ifx\@empty#2\@empty @@ -139,14 +139,14 @@ \def\@xs@notestcs#1\@xs@nil{\relax}% \def\@xs@testcs#1#2\@xs@nil{% \ifx\@empty#2\@empty - \else% si la séquence de contrôle n'est pas seule, on gueule + \else% si la s\'equence de contr\^ole n'est pas seule, on gueule \@xs@errorwrite{third argument or its expansion^^Jis not a single control sequence! Use \string\scancs* instead of \string\scancs (see manual).}{With \scancs, the third argument (or one of its expansion) cannot contain^^Jmore than one control sequence. If so, use the starred version \scancs*,^^Jand read manual for more information about this starred version...}% \fi} -% \scancs développe #3 autant de fois que spécifié en #1 -% puis le développement obtenu est verbatimisé. -% On utilise \@xs@expandalltodepth autant de fois que #1 le spécifie -% puis on invoque \detokenize à la fin +% \scancs d\'eveloppe #3 autant de fois que sp\'ecifi\'e en #1 +% puis le d\'eveloppement obtenu est verbatimis\'e. +% On utilise \@xs@expandalltodepth autant de fois que #1 le sp\'ecifie +% puis on invoque \detokenize \`a la fin \def\scancs{% \@ifstar% {\@xs@warningwrite{\string\scancs* has limitations: ^^Jif third argument or its expansion have braces or spaces,^^Jthey will be removed when scanned}% @@ -156,15 +156,15 @@ \@xs@scancs}} \def\@xs@scancs{\@ifnextchar[{\@xs@scancs@}{\@xs@scancs@[1]}} \def\@xs@scancs@[#1]#2#3{% -% #1 : profondeur à développer avant de verbatimiser +% #1 : profondeur \`a d\'evelopper avant de verbatimiser % #2 : nom de la sc recevant la chaine verb -% #3 : nom de la sc à développer et à transformer en verb - \def\@xs@expandalltodepth##1{% développe de #1 niveaux toutes les sc de #3 et l'assigne à \@xs@reserved@B - \let\@xs@reserved@A\@empty%\def\@xs@reserved@A{}% - \ifnum##1<#1\relax% tant que la profondeur de développement n'est pas atteinte - \expandafter\@xs@testornot\@xs@reserved@B\@xs@nil% on teste éventuellement si le développement comporte 1 seule sc - \expandafter\@xs@expandallonelevel\@xs@reserved@B\@xs@nil% on développe tout d'un niveau - \let\@xs@reserved@B\@xs@reserved@A%\expandafter\def\expandafter\@xs@reserved@B\expandafter{\@xs@reserved@A}% +% #3 : nom de la sc \`a d\'evelopper et \`a transformer en verb + \def\@xs@expandalltodepth##1{% d\'eveloppe de #1 niveaux toutes les sc de #3 et l'assigne \`a \@xs@reserved@B + \let\@xs@reserved@A\@empty% + \ifnum##1<#1\relax% tant que la profondeur de d\'eveloppement n'est pas atteinte + \expandafter\@xs@testornot\@xs@reserved@B\@xs@nil% on teste \'eventuellement si le d\'eveloppement comporte 1 seule sc + \expandafter\@xs@expandallonelevel\@xs@reserved@B\@xs@nil% on d\'eveloppe tout d'un niveau + \let\@xs@reserved@B\@xs@reserved@A% \def\@xs@next{\expandafter\@xs@expandalltodepth\expandafter{\number\numexpr##1+1}}% \expandafter\@xs@next% et on recommence \fi}% @@ -172,23 +172,23 @@ \@xs@expandalltodepth\z@ \expandafter\def\expandafter#2\expandafter{\detokenize\expandafter{\@xs@reserved@B}}} -% Cette macro développe éventuellement #2 -% puis le transforme en token et l'assigne à #1 -\begingroup% on ouvre un groupe où... -\catcode\z@12\relax% ...le caractère 0 a 12 pour catcode +% Cette macro d\'eveloppe \'eventuellement #2 +% puis le transforme en token et l'assigne \`a #1 +\begingroup% on ouvre un groupe o\`u... +\catcode\z@12\relax% ...le caract\`ere 0 a 12 pour catcode \gdef\tokenize#1#2{% \begingroup - \@xs@def\@xs@reserved@A{#2}% on développe en accord avec \fullexpandarg ou \noexpandarg + \@xs@def\@xs@reserved@A{#2}% on d\'eveloppe en accord avec \fullexpandarg ou \noexpandarg \def\@xs@AssignResult^^00##1^^00\@xs@nil{\gdef#1{##1}}% on assigne en tenant compte du \@xs@nil qui vient de la fin du fichier virtuel - \everyeof{\@xs@nil}% met un \@xs@nil à la fin du fichier virtuel + \everyeof{\@xs@nil}% met un \@xs@nil \`a la fin du fichier virtuel \endlinechar\m@ne \catcode\z@12\relax \expandafter\@xs@AssignResult\scantokens\expandafter{\expandafter^^00\@xs@reserved@A^^00}% on fait l'assignation \endgroup}% \endgroup -% Macro très simple qui assigne ou affiche le résultat, selon la présence -% ou non de #2 qui est l'argument optionnel venant en dernière position des macros +% Macro tr\`es simple qui assigne ou affiche le r\'esultat, selon la pr\'esence +% ou non de #2 qui est l'argument optionnel venant en derni\`ere position des macros \def\@xs@ReturnResult#1#2{% \expandafter\ifx\expandafter\@empty\detokenize{#2}\@empty% pas de nom ? #1% on affiche #1 @@ -198,31 +198,31 @@ % Pas d'expansion des arguments \def\normalexpandarg{% - \let\@xs@def\def% on définit \@xs@call avec \def + \let\@xs@def\def% on d\'efinit \@xs@call avec \def \def\@xs@expand##1{\unexpanded\expandafter{##1}}} \let\noexpandarg\normalexpandarg% synonyme -% 1-développement de la 1è sc des arguments et non développement des autres +% 1-d\'eveloppement du premier token des arguments \def\expandarg{% - \let\@xs@def\def% on définit \@xs@call avec \def + \let\@xs@def\def% on d\'efinit \@xs@call avec \def \def\@xs@expand##1{\unexpanded\expandafter\expandafter\expandafter{##1}}} -% Développement maximum des arguments +% D\'eveloppement maximum des arguments \def\fullexpandarg{% - \let\@xs@def\edef% on définit\@xs@call avec \edef + \let\@xs@def\edef% on d\'efinit\@xs@call avec \edef \def\@xs@expand##1{##1}}% et on neutralise \@xs@expand \def\saveexpandmode{\let\@xs@saved@def\@xs@defarg\let\@xs@saved@expand\@xs@expand} \def\restoreexpandmode{\let\@xs@defarg\@xs@saved@def\let\@xs@expand\@xs@saved@expand} -% Cette macro interne prend la 1ere unité syntaxique de #1 et assigne le résultat à #2 +% Cette macro interne prend la 1ere unit\'e syntaxique de #1 et assigne le r\'esultat \`a #2 \def\@xs@returnfirstsyntaxunit#1#2{% \def\@xs@returnfirstsyntaxunit@i##1##2\@xs@nil{% \ifx\@xs@toks\bgroup \begingroup - \escapechar48\relax% 0 est le caractère d'échappement + \escapechar48\relax% 0 est le caract\`ere d'\'echappement \expandafter\expandafter\expandafter\ifx\expandafter\@xs@returnfirstsyntaxunit@ii\detokenize{#1}\@xs@nil0% - \def\@xs@reserved@A{\def#2{##1}\let\@xs@toks0\relax}% si commence par 0, ##1 est un «\bgroup» + \def\@xs@reserved@A{\def#2{##1}\let\@xs@toks0}% si commence par 0, ##1 est un «\bgroup» \else \def\@xs@reserved@A{\def#2{{##1}}}% si ne commence pas par 0, ##1 est un groupe {...} \fi @@ -238,7 +238,7 @@ \futurelet\@xs@toks\@xs@returnfirstsyntaxunit@i#1\@xs@nil \fi} -% Cette macro interne enlève la 1ere unité syntaxique de #1 et assigne le résultat à #2 +% Cette macro interne enl\`eve la 1ere unit\'e syntaxique de #1 et assigne le r\'esultat \`a #2 \def\@xs@removefirstsyntaxunit#1#2{% \expandafter\ifx\expandafter\@empty\@xs@beforespace#1 \@xs@nil\@empty \ifx\@empty#1\@empty\def#2{}\else\expandafter\def\expandafter#2\expandafter{\@xs@behindspace#1\@xs@nil}\fi @@ -246,23 +246,23 @@ \expandafter\def\expandafter#2\expandafter{\@xs@gobblefirstchar#1}% \fi} -% Macros à arguments délimités pour les macros ci dessus +% Macros \`a arguments d\'elimit\'es pour les macros ci dessus \def\@xs@beforespace#1 #2\@xs@nil{#1} \def\@xs@behindspace#1 #2\@xs@nil{#2} \def\@xs@gobblefirstchar#1{} \def\@xs@returnfirstsyntaxunit@ii#1#2\@xs@nil{#1} -% Cette macro interne est utilisée dans les macros étoilées pour : -% 1) développer l'argument selon qu'on a choisit \fullexpandarg -% ou \normalexpandarg, et ceci à l'aide de la macro \@xs@def -% 2) Ensuite, on détokenize ce développement de façon n'avoir plus que +% Cette macro interne est utilis\'ee dans les macros \'etoil\'ees pour : +% 1) d\'evelopper l'argument selon qu'on a choisit \fullexpandarg +% ou \normalexpandarg, et ceci \`a l'aide de la macro \@xs@def +% 2) Ensuite, on d\'etokenize ce d\'eveloppement de façon n'avoir plus que % des catcodes de 10 pour les espaces et 12 pour le reste. \def\@xs@expand@and@detokenize#1#2{% \def#1{#2}% - \expandafter\edef\expandafter#1\expandafter{\@xs@expand#1}% on développe #2 selon le mode de développement - \edef#1{\detokenize\expandafter{#1}}}% puis on détokenize et on assigne à #1 + \expandafter\edef\expandafter#1\expandafter{\@xs@expand#1}% on d\'eveloppe #2 selon le mode de d\'eveloppement + \edef#1{\detokenize\expandafter{#1}}}% puis on d\'etokenize et on assigne \`a #1 -\def\@xs@expand@and@assign#1#2{\@xs@def#1{#2}}% on développe #2 selon \fullexpandarg ou \normalexpandarg +\def\@xs@expand@and@assign#1#2{\@xs@def#1{#2}}% on d\'eveloppe #2 selon \fullexpandarg ou \normalexpandarg \def\@xs@expand@and@addtomacro#1#2{\edef#1{\unexpanded\expandafter{#1}#2}} \def\@xs@argstring{0########1########2########3########4########5########6########7########8########9} @@ -275,160 +275,227 @@ \def\@xs@OneArg#1{\expandafter\@xs@onearg\expandafter{\number\numexpr#1-1}{#1}} \def\@xs@onearg#1#2{\def\@xs@defarg##1#1##2#2##3\@xs@nil{\def\@xs@myarg{##2#2}}\expandafter\@xs@defarg\@xs@argstring\@xs@nil} -\def\@xs@BuildLines#1#2#3{% #1 : numéro du 1er argument; #2 : nombre de lignes; #3 argument optionnel +% #1 : num\'ero du 1er argument; #2 : nombre de lignes; #3 argument optionnel; #4 : dernier num\'ero de l'argument devant être d\'etokenis\'e si \'etoile +\def\@xs@BuildLines#1#2#3#4{% \def\@xs@newlines{}% \def\@xs@newargs{}% \def\@xs@buildlines##1{% \expandafter\@xs@OneArg\expandafter{\number\numexpr##1+#1-1}% - \@xs@expand@and@addtomacro\@xs@newlines{\noexpand\@xs@assign\expandafter\noexpand\csname @xs@arg@\romannumeral\numexpr##1\endcsname{\@xs@myarg}}% + \def\@xs@reserved@B{\noexpand\@xs@expand\csname @xs@arg@\romannumeral\numexpr##1\endcsname}% \ifnum##1=\@ne% si c'est le premier argument \ifx\@empty#3\@empty - \@xs@expand@and@addtomacro\@xs@newargs{{\noexpand\@xs@expand\expandafter\noexpand\csname @xs@arg@\romannumeral\numexpr##1\endcsname}}% + \@xs@expand@and@addtomacro\@xs@newargs{{\@xs@reserved@B}}% + \edef\@xs@reserved@B{\ifnum##1>#4 @xs@def\else @xs@assign\fi}% \else% et s'il y a un argument optionnel alors, on met des crochets - \@xs@expand@and@addtomacro\@xs@newargs{[\noexpand\@xs@expand\expandafter\noexpand\csname @xs@arg@\romannumeral\numexpr##1\endcsname]}% + \@xs@expand@and@addtomacro\@xs@newargs{[\@xs@reserved@B]}% + \def\@xs@reserved@B{@xs@def}% ne pas d\'etok\'eniser l'argument optionnel grace au \@xs@def \fi \else - \@xs@expand@and@addtomacro\@xs@newargs{{\noexpand\@xs@expand\expandafter\noexpand\csname @xs@arg@\romannumeral\numexpr##1\endcsname}}% + \@xs@expand@and@addtomacro\@xs@newargs{{\@xs@reserved@B}}% + \edef\@xs@reserved@B{\ifnum##1>#4 @xs@def\else @xs@assign\fi}% \fi + \@xs@expand@and@addtomacro\@xs@newlines{\csname\@xs@reserved@B\endcsname\csname @xs@arg@\romannumeral\numexpr##1\endcsname{\@xs@myarg}}% \ifnum##1<#2\relax \def\@xs@next{\expandafter\@xs@buildlines\expandafter{\number\numexpr##1+1}}% \expandafter\@xs@next \fi}% \@xs@buildlines\@ne} -\def\@xs@newmacro#1#2#3#4#5{% -% #1 : nom de la macro publique -% #2 : argument optionnel (vide si pas d'arg optionnel) -% #3 : nombre d'arguments obligatoires -% #4 : utilisation de testopt (1 si oui, 0 si non) -% #5 : code de la macro - \edef\@xs@reserved@A{@xs@\expandafter\@xs@gobblefirstchar\string#1}% - \edef\@xs@reserved@C{\expandafter\noexpand\csname\@xs@reserved@A @\ifx\@empty#2\@empty @\fi\endcsname}% +\def\@xs@newmacro{\@ifstar{\let\@xs@reserved@D\@empty\@xs@newmacro@}{\let\@xs@reserved@D\relax\@xs@newmacro@0}} +% #1 : dernier num\'ero de l'argument devant être d\'etokenis\'e si \'etoile +% #2 : nom de la macro publique +% #3 : argument optionnel (vide si pas d'arg optionnel) +% #4 : nombre d'arguments obligatoires +% #5 : utilisation de testopt (1 si oui, 0 si non) +% #6 : code de la macro +\def\@xs@newmacro@#1#2#3#4#5#6{% + \edef\@xs@reserved@A{@xs@\expandafter\@xs@gobblefirstchar\string#2}% + \edef\@xs@reserved@C{\csname\@xs@reserved@A @\ifx\@empty#3\@empty @\fi\endcsname}% \edef\@xs@reserved@B{% - \def\noexpand#1{\noexpand\@ifstar + \ifx\@empty\@xs@reserved@D + \def\noexpand#2{\noexpand\@ifstar {\let\noexpand\@xs@assign\noexpand\@xs@expand@and@detokenize\expandafter\noexpand\@xs@reserved@C}% {\let\noexpand\@xs@assign\noexpand\@xs@expand@and@assign\expandafter\noexpand\@xs@reserved@C}}% - \ifx\@empty#2\@empty \else - \def\expandafter\noexpand\@xs@reserved@C{\noexpand\@ifnextchar[% - {\expandafter\noexpand\csname\@xs@reserved@A @@\endcsname}% - {\expandafter\noexpand\csname\@xs@reserved@A @@\endcsname[#2]}}% + \def\noexpand#2{\let\noexpand\@xs@assign\noexpand\@xs@expand@and@assign\expandafter\noexpand\@xs@reserved@C}% + \fi + \ifx\@empty#3\@empty + \else + \def\expandafter\noexpand\@xs@reserved@C{% + \noexpand\@testopt{\csname\@xs@reserved@A @@\endcsname}{\ifx\@xs@def\edef#3\else\unexpanded{#3}\fi}}% \fi}% - % Que fait \@xs@reserved@B ? Il définit : - % si #2 est vide : \NOM{\@ifstar{\let\@xs@assign\@xs@expand@and@detokenize\@xs@NOM@@}{\let\@xs@assign\@xs@expand@and@assign\@xs@NOM@@}} - % si #2 existe : \NOM{\@ifstar{\let\@xs@assign\@xs@expand@and@detokenize\@xs@NOM@}{\let\@xs@assign\@xs@expand@and@assign\@xs@NOM@}} - % \@xs@NOM@{\@ifnextchar[{\@xs@NOM@@}{\@xs@NOM@@[#2]}} + % Que fait \@xs@reserved@B ? Il d\'efinit : + % si #3 est vide : \NOM{\@ifstar{\let\@xs@assign\@xs@expand@and@detokenize\@xs@NOM@@}{\let\@xs@assign\@xs@expand@and@assign\@xs@NOM@@}} + % si #3 existe : \NOM{\@ifstar{\let\@xs@assign\@xs@expand@and@detokenize\@xs@NOM@}{\let\@xs@assign\@xs@expand@and@assign\@xs@NOM@}} + % \@xs@NOM@{\@testopt{\@xs@NOM@@}{#3}}} \@xs@reserved@B - \ifx\@empty#2\@empty - \@xs@BuildLines1{#3}{#2}% - \@xs@DefArg{#3}% + \ifx\@empty#3\@empty + \@xs@BuildLines1{#4}{#3}{#1}% + \@xs@DefArg{#4}% \else - \expandafter\@xs@BuildLines\expandafter1\expandafter{\number\numexpr#3+1}{#2}% - \@xs@DefArg@{#3}% + \expandafter\@xs@BuildLines\expandafter1\expandafter{\number\numexpr#4+1}{#3}{#1}% + \@xs@DefArg@{#4}% \fi - \edef\@xs@reserved@B{\def\expandafter\noexpand\csname\@xs@reserved@A @@\endcsname\@xs@myarg}% + \edef\@xs@reserved@B{\def\csname\@xs@reserved@A @@\endcsname\@xs@myarg}% \edef\@xs@reserved@C{\unexpanded\expandafter{\@xs@newlines}\edef\noexpand\@xs@call}% - \edef\@xs@reserved@D{\noexpand\noexpand\expandafter\noexpand\csname\@xs@reserved@A\endcsname\unexpanded\expandafter{\@xs@newargs}}% - \ifnum#4=\@ne\edef\@xs@reserved@D{\noexpand\noexpand\noexpand\@testopt{\unexpanded\expandafter{\@xs@reserved@D}}\unexpanded{{}}}\fi + \edef\@xs@reserved@D{\noexpand\noexpand\csname\@xs@reserved@A\endcsname\unexpanded\expandafter{\@xs@newargs}}% + \ifnum#5=\@ne\edef\@xs@reserved@D{\noexpand\noexpand\noexpand\@testopt{\unexpanded\expandafter{\@xs@reserved@D}}\unexpanded{{}}}\fi \@xs@expand@and@addtomacro\@xs@reserved@C{{\unexpanded\expandafter{\@xs@reserved@D}}\noexpand\@xs@call}% \@xs@expand@and@addtomacro\@xs@reserved@B{{\unexpanded\expandafter{\@xs@reserved@C}}}% - % Que fait \@xs@reserved@B ? Il définit par exemple pour 3 arguments obligatoires et 1 facultatif : - % \def\@xs@NOM@@[##1]##2##3##4{% - % \@xs@def\@xs@arg@i{##1}\@xs@assign\@xs@arg@ii{##2}\@xs@assign\@xs@arg@iii{##3}\@xs@asign\@xs@arg@iv{##4}% - % si #4=0: \edef\@xs@call{\noexpand\@xs@NOM[\@xs@expand\@xs@arg@i]{\@xs@expand\@xs@arg@ii}{\@xs@expand\@xs@arg@iii}{\@xs@expand\@xs@arg@iv}}% - % si #4=1: \edef\@xs@call{\noexpand\@testopt{\noexpand\@xs@NOM[\@xs@expand\@xs@arg@i]{\@xs@expand\@xs@arg@i}{\@xs@expand\@xs@arg@ii}{\@xs@expand\@xs@arg@iii}{\@xs@expand\@xs@arg@iv}}{}}% + % Que fait \@xs@reserved@B ? Il d\'efinit par exemple pour 3 arguments obligatoires et 1 facultatif : + % \def\@xs@NOM@@[##2]##3##4##5{% + % \@xs@def\@xs@arg@i{##2}\@xs@assign\@xs@arg@ii{##3}\@xs@assign\@xs@arg@iii{##4}\@xs@asign\@xs@arg@iv{##5}% + % si #5=0: \edef\@xs@call{\noexpand\@xs@NOM[\@xs@expand\@xs@arg@i]{\@xs@expand\@xs@arg@ii}{\@xs@expand\@xs@arg@iii}{\@xs@expand\@xs@arg@iv}}% + % si #5=1: \edef\@xs@call{\noexpand\@testopt{\noexpand\@xs@NOM[\@xs@expand\@xs@arg@i]{\@xs@expand\@xs@arg@i}{\@xs@expand\@xs@arg@ii}{\@xs@expand\@xs@arg@iii}{\@xs@expand\@xs@arg@iv}}{}}% % \@xs@call} \@xs@reserved@B - \edef\@xs@reserved@B{\def\expandafter\noexpand\csname\@xs@reserved@A\endcsname\@xs@myarg\ifnum#4=\@ne[\unexpanded{##}\number\numexpr\ifx\@empty#2\@empty#3+1\else#3+2\fi]\fi{\unexpanded{#5}}}% - % Que fait \@xs@reserved@B ? Il définit par exemple pour 3 arguments obligatoires et 1 facultatif : - % \def \@xs@NOM[##1]##2##3##4[##5]{#5} + \edef\@xs@reserved@B{\def\expandafter\noexpand\csname\@xs@reserved@A\endcsname\@xs@myarg\ifnum#5=\@ne[\unexpanded{##}\number\numexpr\ifx\@empty#3\@empty#4+1\else#4+2\fi]\fi{\unexpanded{#6}}}% + % Que fait \@xs@reserved@B ? Il d\'efinit par exemple pour 3 arguments obligatoires et 1 facultatif : + % \def \@xs@NOM[##2]##3##4##5[##6]{#6} \@xs@reserved@B} -\@xs@newmacro\StrRemoveBraces{}{1}{1}{% - \let\@xs@reserved@C\@empty - \def\@xs@reserved@A{#1}% - \@xs@StrRemoveBraces@i - \expandafter\@xs@ReturnResult\expandafter{\@xs@reserved@C}{#2}} -\def\@xs@StrRemoveBraces@i{% - \expandafter\@xs@returnfirstsyntaxunit\expandafter{\@xs@reserved@A}\@xs@reserved@B - \expandafter\@xs@removefirstsyntaxunit\expandafter{\@xs@reserved@A}\@xs@reserved@A - \ifx\bgroup\@xs@toks - \ifx\@xs@exploregroups\@empty% on explore les groupes ? +% macro g\'en\'erique qui lit \@xs@reserved@C lex\`eme par lex\`eme +% 3 sous-routines sont appel\'ees \`a des moments cl\'e : +% \@xs@atendofgroup (un groupe se finit, appel r\'ecursif) +% \@xs@atbegingroup (un groupe vient d'être ouvert) +% \@xs@atnextsyntaxunit (la future US n'est pas un groupe) +\def\@xs@read@reserved@C{% + \ifx\@xs@reserved@C\@empty + \ifnum\@xs@nestlevel=\z@ + \let\@xs@next\relax + \else + \let\@xs@next\@xs@atendofgroup + \fi + \else + \expandafter\@xs@returnfirstsyntaxunit\expandafter{\@xs@reserved@C}\@xs@reserved@A + \expandafter\@xs@removefirstsyntaxunit\expandafter{\@xs@reserved@C}\@xs@reserved@C + \let\@xs@next\@xs@read@reserved@C + \@xs@exploregroups + \ifx\bgroup\@xs@toks + \advance\integerpart\@ne \begingroup - \let\@xs@reserved@C\@empty - \expandafter\def\expandafter\@xs@reserved@A\@xs@reserved@B - \@xs@StrRemoveBraces@i - \expandafter - \endgroup - \expandafter\@xs@addtomacro\expandafter\@xs@reserved@C\expandafter{\@xs@reserved@C}% + \expandafter\def\expandafter\@xs@reserved@C\@xs@reserved@A + \@xs@manage@groupID + \let\@xs@nestlevel\@ne + \integerpart\z@ + \@xs@atbegingroup \else - \expandafter\@xs@addtomacro\expandafter\@xs@reserved@C\@xs@reserved@B + \global\advance\@xs@count\@ne + \@xs@atnextsyntaxunit + \fi + \fi + \@xs@next} + +% macro g\'en\'erique qui lit \@xs@reserved@D en proc\'edant \`a des tests avec \IfBeginWith +% 2 sous-routines sont appel\'ees \`a des moments cl\'e : +% \@xs@atendofgroup (un groupe se finit, appel r\'ecursif) +% \@xs@atoccurfound (une occurrence a \'et\'e trouv\'ee) +\def\@xs@read@reserved@D{% + \ifx\@xs@reserved@D\@empty + \ifnum\@xs@nestlevel=\z@ + \let\@xs@next\relax + \else + \let\@xs@next\@xs@atendofgroup \fi \else - \expandafter\@xs@addtomacro\expandafter\@xs@reserved@C\expandafter{\@xs@reserved@B}% + \expandafter\expandafter\expandafter\@xs@IfBeginWith@i\expandafter\expandafter\expandafter{\expandafter\@xs@reserved@D\expandafter}\expandafter{\@xs@reserved@E}% + {\global\advance\@xs@count\@ne + \let\@xs@reserved@D\@xs@reserved@A + \@xs@atoccurfound}% + {\expandafter\@xs@returnfirstsyntaxunit\expandafter{\@xs@reserved@D}\@xs@reserved@A + \expandafter\@xs@removefirstsyntaxunit\expandafter{\@xs@reserved@D}\@xs@reserved@D + \let\@xs@next\@xs@read@reserved@D + \@xs@exploregroups + \ifx\bgroup\@xs@toks + \advance\integerpart\@ne + \begingroup + \expandafter\def\expandafter\@xs@reserved@D\@xs@reserved@A + \@xs@manage@groupID + \let\@xs@reserved@C\@empty + \let\@xs@nestlevel\@ne + \integerpart\z@ + \else + \expandafter\@xs@addtomacro\expandafter\@xs@reserved@C\expandafter{\@xs@reserved@A}% + \fi}% \fi - \expandafter\let\expandafter\@xs@next\ifx\@empty\@xs@reserved@A\relax\else\@xs@StrRemoveBraces@i\fi - \@xs@next}% + \@xs@next} -\def\@xs@strip@delimit#1\@delimit#2\@xs@nil{#1} -% \@xs@cutafteroccur coupe l'argument #1 après la #3ème occurrence de #2 -% #4 : contient ce qui se trouve avant cette occurrence y compris l'occurrence -% #5 : idem mais sans l'occurrence -% #6 : contient ce qui se trouve après l'occurrence -% si l'occurrence n'existe pas ou qu'un des arguments est vide, toutes les chaines renvoyées sont vides -% utilise \@xs@reserved@A -> \@xs@reserved@B -\def\@xs@cutafteroccur#1#2#3#4#5#6{% - \def\@xs@cutafteroccur@i{% - \ifx#6\@empty% on a fini de parcourir #6 ? - \let\@xs@next\relax% on sort de la macro +\@xs@newmacro\StrRemoveBraces{}{1}{1}{% + \def\@xs@reserved@C{#1}% + \let\@xs@reserved@B\@empty + \let\@xs@nestlevel\z@ + \@xs@StrRemoveBraces@i + \expandafter\@xs@ReturnResult\expandafter{\@xs@reserved@B}{#2}} +\def\@xs@StrRemoveBraces@i{% + \let\@xs@next\@xs@StrRemoveBraces@i + \ifx\@xs@reserved@C\@empty + \ifnum\@xs@nestlevel=\z@ + \let\@xs@next\relax \else - \expandafter\@xs@IfBeginWith@i\expandafter{#6}{#2}% - {\global\advance\@xs@count\@ne - \ifnum\@xs@count<#3\relax\@xs@addtomacro#5{#2}\@xs@gaddtomacro\@xs@beforeoccur{#2}\fi - \let#6\@xs@reserved@A}% on enlève le motif à #6 - {\expandafter\@xs@returnfirstsyntaxunit\expandafter{#6}\@xs@reserved@A% #6 ne commence pas par le motif : on prend la 1ere unité syntaxique - \expandafter\@xs@removefirstsyntaxunit\expandafter{#6}#6% puis on l'enlève - \@xs@exploregroups - \ifx\bgroup\@xs@toks% si cette unité syntaxique est un groupe {...} - \begingroup% alors on ouvre un groupe - \expandafter\def\expandafter#6\@xs@reserved@A% - \let#4\@empty\let#5\@empty% on initialise dans ce nouveau groupe - \@xs@cutafteroccur@i% puis une récursivité - \ifx#4\@empty% si l'occurrence n'est pas trouvée dans ce groupe - \def\@xs@next{% on en sort après avoir rajouté à #5 du groupe de niveau au dessus le #5 de ce groupe - \expandafter\endgroup - \expandafter\@xs@addtomacro\expandafter#5\expandafter{\expandafter{#5}}}% - \else - \let\@xs@next\endgroup% sinon, on sort du groupe - \fi - \@xs@next - \else - \expandafter\@xs@gaddtomacro\expandafter\@xs@beforeoccur\expandafter{\@xs@reserved@A}% - \expandafter\@xs@addtomacro\expandafter#5\expandafter{\@xs@reserved@A}% - \fi}% - \ifnum\@xs@count=#3\relax% l'occurrence est atteinte... - \global\let#5#5\global\let#6#6% on passe à la globalité si jamais on est dans un groupe - \expandafter\gdef\expandafter#4\expandafter{#5#2}% on rajoute le pattern à #5 - \let\@xs@next\relax% et on sort de la macro + \expandafter\endgroup + \expandafter\@xs@addtomacro\expandafter\@xs@reserved@B\expandafter{\@xs@reserved@B}% + \fi + \else + \expandafter\@xs@returnfirstsyntaxunit\expandafter{\@xs@reserved@C}\@xs@reserved@A + \expandafter\@xs@removefirstsyntaxunit\expandafter{\@xs@reserved@C}\@xs@reserved@C + \ifx\bgroup\@xs@toks + \ifx\@xs@exploregroups\relax% on explore les groupes ? + \begingroup + \expandafter\def\expandafter\@xs@reserved@C\@xs@reserved@A + \let\@xs@nestlevel\@ne + \integerpart\z@ + \let\@xs@reserved@B\@empty \else - \let\@xs@next\@xs@cutafteroccur@i% + \expandafter\@xs@addtomacro\expandafter\@xs@reserved@B\@xs@reserved@A \fi + \else + \expandafter\@xs@addtomacro\expandafter\@xs@reserved@B\expandafter{\@xs@reserved@A}% \fi - \@xs@next}% - \let#4\@empty\let#5\@empty\def#6{#1}\let\@xs@beforeoccur\@empty\@xs@count\z@ - \@xs@cutafteroccur@i - \ifx\@empty#4\let#5#4\let#6#4\fi}% occurrence pas trouvée + \fi + \@xs@next} -% utilise \@xs@reserved@A -> \@xs@reserved@D -\@xs@newmacro\IfSubStr{1}{2}{0}{% - \@xs@cutafteroccur{#2}{#3}{#1}\@xs@reserved@C\@xs@reserved@D\@xs@reserved@E - \ifx\@xs@reserved@C\@empty +\def\@xs@strip@delimit#1\@delimit#2\@xs@nil{#1} + +% \@xs@cutafteroccur coupe l'argument #1 apr\`es la #3\`eme occurrence de #2 +% \@xs@reserved@C : contient ce qui se trouve avant cette occurrence +% \@xs@reserved@D : contient ce qui se trouve avant cette occurrence y compris cette occurrence +% \@xs@reserved@E : contient ce qui se trouve apr\`es l'occurrence +% si l'occurrence n'existe pas ou qu'un des arguments est vide, toutes les chaines renvoy\'ees sont vides +\def\@xs@cutafteroccur#1#2#3{% + \def\@xs@reserved@D{#1}\let\@xs@reserved@C\@empty\def\@xs@reserved@E{#2}% + \@xs@count\z@\integerpart\z@\decimalpart#3\def\groupID{0}\let\@xs@nestlevel\z@ + \def\@xs@atendofgroup{% + \expandafter\endgroup + \expandafter\@xs@addtomacro\expandafter\@xs@reserved@C\expandafter{\expandafter{\@xs@reserved@C}}% + \@xs@read@reserved@D}% + \def\@xs@atoccurfound{% + \ifnum\@xs@count=\decimalpart + \global\let\@xs@reserved@D\@xs@reserved@D + \global\let\@xs@reserved@C\@xs@reserved@C + \global\let\groupID\groupID + \@xs@exitallgroups + \let\@xs@next\relax + \else + \expandafter\@xs@addtomacro\expandafter\@xs@reserved@C\expandafter{\@xs@reserved@E}% + \let\@xs@next\@xs@read@reserved@D + \fi}% + \@xs@read@reserved@D + \ifnum\@xs@count=\decimalpart% occurrence trouv\'ee ? + \let\@xs@reserved@E\@xs@reserved@D + \expandafter\def\expandafter\@xs@reserved@D\expandafter{\@xs@reserved@C#2}% + \else + \let\@xs@reserved@C\@empty\let\@xs@reserved@E\@empty\let\groupID\@empty + \fi} + +\@xs@newmacro*3\IfSubStr{1}{2}{0}{% + \@xs@cutafteroccur{#2}{#3}{#1}% + \ifx\@xs@reserved@D\@empty \expandafter\@secondoftwo \else \expandafter\@firstoftwo \fi} -\@xs@newmacro\IfBeginWith{}{2}{0}{% +\@xs@newmacro*2\IfBeginWith{}{2}{0}{% \ifx\@empty#2\@empty \let\@xs@next\@secondoftwo \else @@ -436,7 +503,7 @@ \fi \@xs@next} \def\@xs@IfBeginWith@i#1#2{% - \ifx\@empty#2\@empty% #2 est vide, tous les tests sont passés avec succès : on renvoie #3 + \ifx\@empty#2\@empty% #2 est vide, tous les tests sont pass\'es avec succ\`es : on renvoie #3 \let\@xs@next\@firstoftwo \else \ifx\@empty#1\@empty @@ -444,8 +511,8 @@ \else \@xs@returnfirstsyntaxunit{#1}\@xs@reserved@A \@xs@returnfirstsyntaxunit{#2}\@xs@reserved@B - \ifx\@xs@reserved@A\@xs@reserved@B% il y a égalité... - \@xs@removefirstsyntaxunit{#1}\@xs@reserved@A% on enlève les 1ere unités syntaxiques + \ifx\@xs@reserved@A\@xs@reserved@B% il y a \'egalit\'e... + \@xs@removefirstsyntaxunit{#1}\@xs@reserved@A% on enl\`eve les 1ere unit\'es syntaxiques \@xs@removefirstsyntaxunit{#2}\@xs@reserved@B \def\@xs@next{% et on recommence avec ces arguments racourcis d'1 token \expandafter\expandafter\expandafter\@xs@IfBeginWith@i @@ -457,31 +524,36 @@ \fi \@xs@next} -\@xs@newmacro\IfEndWith{}{2}{0}{% - \@xs@StrCount{#1}{#2}[\@xs@reserved@A]% - \ifnum\@xs@reserved@A=\z@ - \let\@xs@reserved@A\@secondoftwo% +\@xs@newmacro*2\IfEndWith{}{2}{0}{% + \ifx\@empty#2\@empty + \let\@xs@reserved@A\@secondoftwo \else - \ifx\@empty\@xs@StrCount@afterlastocccur - \let\@xs@reserved@A\@firstoftwo% + \@xs@StrCount{#1}{#2}[\@xs@reserved@A]% + \ifnum\@xs@reserved@A=\z@ + \let\@xs@reserved@A\@secondoftwo \else - \let\@xs@reserved@A\@secondoftwo% + \ifx\@xs@reserved@C\@empty + \let\@xs@reserved@A\@firstoftwo + \else + \let\@xs@reserved@A\@secondoftwo + \fi \fi \fi \@xs@reserved@A} -\@xs@newmacro\IfSubStrBefore{1,1}{3}{0}{\@xs@IfSubStrBefore@i[#1]{#2}{#3}{#4}} +\@xs@newmacro*4\IfSubStrBefore{1,1}{3}{0}{\@xs@IfSubStrBefore@i[#1]{#2}{#3}{#4}} \def\@xs@IfSubStrBefore@i[#1,#2]#3#4#5{% - \ifx\@xs@exploregroups\@empty\let\@xs@reserved@C\@empty\def\@xs@reserved@A{#3}\@xs@StrRemoveBraces@i\else\def\@xs@reserved@C{#3}\fi - \expandafter\@xs@cutafteroccur\expandafter{\@xs@reserved@C}{#5}{#2}\@xs@reserved@C\@xs@reserved@D\@xs@reserved@E - \expandafter\@xs@cutafteroccur\expandafter{\@xs@reserved@D}{#4}{#1}\@xs@reserved@C\@xs@reserved@D\@xs@reserved@E + \ifx\@xs@exploregroups\relax\let\@xs@reserved@C\@empty\def\@xs@reserved@A{#3}\@xs@StrRemoveBraces@i\else\def\@xs@reserved@C{#3}\fi + \expandafter\@xs@cutafteroccur\expandafter{\@xs@reserved@C}{#5}{#2}% + \expandafter\@xs@cutafteroccur\expandafter{\@xs@reserved@C}{#4}{#1}% + \let\groupID\@empty \ifx\@xs@reserved@C\@empty \expandafter\@secondoftwo \else \expandafter\@firstoftwo \fi} -\@xs@newmacro\IfSubStrBehind{1,1}{3}{0}{\@xs@IfSubStrBehind@i[#1]{#2}{#3}{#4}} +\@xs@newmacro*4\IfSubStrBehind{1,1}{3}{0}{\@xs@IfSubStrBehind@i[#1]{#2}{#3}{#4}} \def\@xs@IfSubStrBehind@i[#1,#2]#3#4#5{\@xs@IfSubStrBefore@i[#2,#1]{#3}{#5}{#4}} \def\@xs@formatnumber#1#2{% @@ -544,28 +616,28 @@ \expandafter\@xs@endnumber\@xs@afterinteger\@xs@nil} \def\@xs@endnumber#1\@xs@nil{\def\@xs@afterdecimal{#1}} -% test d'égalité sur des chaines (et des chaines contenant des nombres) +% test d'\'egalit\'e sur des chaines (et des chaines contenant des nombres) \def\@xs@IfStrEqFalse@i#1#2{\let\@xs@reserved@A\@secondoftwo} -\def\@xs@IfStrEqFalse@ii#1#2{% renvoie vrai si les 2 arg sont décimaux et s'ils sont égaux, faux sinon +\def\@xs@IfStrEqFalse@ii#1#2{% renvoie vrai si les 2 arg sont d\'ecimaux et s'ils sont \'egaux, faux sinon \@xs@IfDecimal{#1}% {\@xs@IfDecimal{#2}% - {\ifdim#1pt=#2pt\let\@xs@reserved@A\@firstoftwo\else\let\@xs@reserved@A\@secondoftwo\fi}% les 2 sont décimaux : on fait le test - {\let\@xs@reserved@A\@secondoftwo}}% un seul est décimal - {\let\@xs@reserved@A\@secondoftwo}}% #1 n'est pas décimal + {\ifdim#1pt=#2pt\let\@xs@reserved@A\@firstoftwo\else\let\@xs@reserved@A\@secondoftwo\fi}% les 2 sont d\'ecimaux : on fait le test + {\let\@xs@reserved@A\@secondoftwo}}% un seul est d\'ecimal + {\let\@xs@reserved@A\@secondoftwo}}% #1 n'est pas d\'ecimal -\def\@xs@TestEqual#1#2{% teste si les 2 arguments sont égaux +\def\@xs@TestEqual#1#2{% teste si les 2 arguments sont \'egaux \def\@xs@reserved@A{#1}\def\@xs@reserved@B{#2}% \ifx\@xs@reserved@A\@xs@reserved@B - \let\@xs@reserved@A\@firstoftwo% égalité parfaite des 2 chaines + \let\@xs@reserved@A\@firstoftwo% \'egalit\'e parfaite des 2 chaines \else \@xs@reserved@D{#1}{#2}% \fi \@xs@reserved@A} -\@xs@newmacro\IfStrEq{}{2}{0}{% teste si les deux chaines sont égales +\@xs@newmacro*2\IfStrEq{}{2}{0}{% teste si les deux chaines sont \'egales \let\@xs@reserved@D\@xs@IfStrEqFalse@i \@xs@TestEqual{#1}{#2}} -\@xs@newmacro\IfEq{}{2}{0}{% teste si les 2 arguments (chaine ou nombre) sont égaux +\@xs@newmacro*2\IfEq{}{2}{0}{% teste si les 2 arguments (chaine ou nombre) sont \'egaux \let\@xs@reserved@D\@xs@IfStrEqFalse@ii \@xs@TestEqual{#1}{#2}} @@ -576,259 +648,227 @@ \def\@xs@IfEqCase#1#2{\@testopt{\@xs@IfStringCase{#1}{#2}}{}} \def\@xs@IfStringCase#1#2[#3]{% - \def\@xs@testcase##1##2##3\@xs@nil{% lit les 2 premieres unités syntaxiques dans ##1 et ##2. Les autres dans ##3 + \def\@xs@testcase##1##2##3\@xs@nil{% lit les 2 premieres unit\'es syntaxiques dans ##1 et ##2. Les autres dans ##3 \@xs@reserved@E{#1}{##1}% - {##2}% le test est positif, on exécute le code correspondant - {\ifx\@empty##3\@empty% le test est négatif - \def\@xs@next{#3}% s'il n'y a plus de cas, on exécute le code + {##2}% le test est positif, on ex\'ecute le code correspondant + {\ifx\@empty##3\@empty% le test est n\'egatif + \def\@xs@next{#3}% s'il n'y a plus de cas, on ex\'ecute le code \else \def\@xs@next{\@xs@testcase##3\@xs@nil}% sinon, on recommence avec ce qui reste \fi \@xs@next}}% \@xs@testcase#2\@xs@nil} +% Renvoie ce qui est \`a gauche de l'occurence n°#1 de la sous chaine #3 dans la chaine +\@xs@newmacro*3\StrBefore{1}{2}{1}{% + \@xs@cutafteroccur{#2}{#3}{#1}% + \expandafter\@xs@ReturnResult\expandafter{\@xs@reserved@C}{#4}} -% Renvoie ce qui est à gauche de l'occurence n°#1 de la sous chaine #3 dans la chaine -\@xs@newmacro\StrBefore{1}{2}{1}{% - \@xs@cutafteroccur{#2}{#3}{#1}\@xs@reserved@C\@xs@reserved@D\@xs@reserved@E - \expandafter\@xs@ReturnResult\expandafter{\@xs@reserved@D}{#4}} - -% Renvoie ce qui est à droite de l'occurence n°#1 de la sous chaine #3 dans la chaine #2 -\@xs@newmacro\StrBehind{1}{2}{1}{% - \@xs@cutafteroccur{#2}{#3}{#1}\@xs@reserved@C\@xs@reserved@D\@xs@reserved@E +% Renvoie ce qui est \`a droite de l'occurence n°#1 de la sous chaine #3 dans la chaine #2 +\@xs@newmacro*3\StrBehind{1}{2}{1}{% + \@xs@cutafteroccur{#2}{#3}{#1}% \expandafter\@xs@ReturnResult\expandafter{\@xs@reserved@E}{#4}} % Renvoie ce qui est strictement compris entre les occurrences n°#1 et n°#2 % des chaines #4 et #5 dans la chaine #3 -\@xs@newmacro\StrBetween{1,1}{3}{1}{\@xs@StrBetween@i[#1]{#2}{#3}{#4}[#5]} +\@xs@newmacro*4\StrBetween{1,1}{3}{1}{\@xs@StrBetween@i[#1]{#2}{#3}{#4}[#5]} \def\@xs@StrBetween@i[#1,#2]#3#4#5[#6]{% \begingroup \noexploregroups - \@xs@cutafteroccur{#3}{#5}{#2}\@xs@reserved@C\@xs@reserved@D\@xs@reserved@E - \expandafter\@xs@cutafteroccur\expandafter{\@xs@reserved@D}{#4}{#1}\@xs@reserved@C\@xs@reserved@D\@xs@reserved@E + \@xs@cutafteroccur{#3}{#5}{#2}% + \expandafter\@xs@cutafteroccur\expandafter{\@xs@reserved@C}{#4}{#1}% \expandafter \endgroup - \expandafter\@xs@ReturnResult\expandafter{\@xs@reserved@E}{#6}} + \expandafter\@xs@ReturnResult\expandafter{\@xs@reserved@E}{#6}% + \let\groupID\@empty} \def\@xs@addtomacro#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}} -\def\@xs@gaddtomacro#1#2{\expandafter\gdef\expandafter#1\expandafter{#1#2}} -\def\exploregroups{\def\@xs@exploregroups{}} + +\def\exploregroups{\let\@xs@exploregroups\relax} \def\noexploregroups{\def\@xs@exploregroups{\let\@xs@toks0\relax}} \def\saveexploremode{\let\@xs@saveexploremode\@xs@exploregroups} \def\restoreexploremode{\let\@xs@exploregroups\@xs@saveexploremode} -% Remplace les #1 premières occurences de la chaine #3 + +% Remplace les #1 premi\`eres occurences de la chaine #3 % par la chaine #4 dans la chaine #2 -% utilise \@xs@reserved@A -> \@xs@reserved@E \@xs@newmacro\StrSubstitute{0}{3}{1}{% - \ifx\@empty#3\@empty% si #4 est vide, on ne fait rien - \@xs@ArgEmpty% warning - \@xs@ReturnResult{#2}{#5}% - \else - \@xs@StrSubstitute@i[#1]{#2}{#3}{#4}{#5}% - \fi}% -\def\@xs@StrSubstitute@i[#1]#2#3#4#5{% - \def\@xs@StrSubstitute@ii{% - \ifx\@xs@reserved@C\@empty% on a fini de parcourir \@xs@reserved@C ? - \let\@xs@next\relax% on sort de la macro + \def\@xs@reserved@D{#2}\let\@xs@reserved@C\@empty\def\@xs@reserved@E{#3}% + \@xs@count\z@\integerpart\z@\def\groupID{0}\let\@xs@nestlevel\z@ + \def\@xs@atendofgroup{% + \expandafter\endgroup + \expandafter\@xs@addtomacro\expandafter\@xs@reserved@C\expandafter{\expandafter{\@xs@reserved@C}}% + \@xs@read@reserved@D}% + \def\@xs@atoccurfound{% + \ifnum#1=\z@ + \def\@xs@reserved@A{#4}% \else - \ifnum\@xs@count=#1\relax - \expandafter\@xs@addtomacro\expandafter\@xs@reserved@D\expandafter{\@xs@reserved@C}% - \let\@xs@next\relax + \ifnum\@xs@count>#1 + \def\@xs@reserved@A{#3}% \else - \expandafter\@xs@IfBeginWith@i\expandafter{\@xs@reserved@C}{#3}% - {\@xs@addtomacro\@xs@reserved@D{#4}% \@xs@reserved@C commence par le motif --> on substitue - \global\advance\@xs@count\@ne - \let\@xs@reserved@C\@xs@reserved@A}% on enlève le motif à \@xs@reserved@C - {\expandafter\@xs@returnfirstsyntaxunit\expandafter{\@xs@reserved@C}\@xs@reserved@A% \@xs@reserved@C ne commence pas par le motif : on prend la 1ere unité syntaxique - \expandafter\@xs@removefirstsyntaxunit\expandafter{\@xs@reserved@C}\@xs@reserved@C% puis on l'enlève - \@xs@exploregroups - \ifx\bgroup\@xs@toks% si cette unité syntaxique est un groupe {...} - \begingroup% alors on ouvre un groupe - \expandafter\def\expandafter\@xs@reserved@C\@xs@reserved@A% \@xs@reserved@C devient l'intérieur de {...} - \let\@xs@reserved@D\@empty% #4 est initialisé à vide dans ce nouveau groupe - \@xs@StrSubstitute@ii% on lance la macro avec ces nouvelles définitions - \expandafter% on retarde la fermeture du groupe - \endgroup% pour ajouter \@xs@reserved@D de ce groupe au \@xs@reserved@D du groupe supérieur - \expandafter\@xs@addtomacro\expandafter\@xs@reserved@D\expandafter{\expandafter{\@xs@reserved@D}}% - \else - \expandafter\@xs@addtomacro\expandafter\@xs@reserved@D\expandafter{\@xs@reserved@A}% - \fi}% - \let\@xs@next\@xs@StrSubstitute@ii% + \def\@xs@reserved@A{#4}% \fi \fi - \@xs@next}% - \def\@xs@reserved@D{}\def\@xs@reserved@C{#2}% - \@xs@count\ifnum#1>\z@\z@\else\@ne\fi - \@xs@StrSubstitute@ii - \expandafter\@xs@ReturnResult\expandafter{\@xs@reserved@D}{#5}} + \expandafter\@xs@addtomacro\expandafter\@xs@reserved@C\expandafter{\@xs@reserved@A}% + \@xs@read@reserved@D}% + \ifx\@empty#3\@empty + \@xs@ReturnResult{#2}{#5}% + \else + \@xs@read@reserved@D + \expandafter\@xs@ReturnResult\expandafter{\@xs@reserved@C}{#5}% + \fi} -% Supprime les #1 premières occurrences de #3 dans #2 +% Supprime les #1 premi\`eres occurrences de #3 dans #2 \@xs@newmacro\StrDel{0}{2}{1}{\@xs@StrSubstitute[#1]{#2}{#3}{}[#4]} -% Compte combien d'unités syntaxiques contient la chaine #1 ? +\def\@xs@exitallgroups{\ifnum\@xs@nestlevel>\z@\endgroup\expandafter\@xs@exitallgroups\fi} + +% Compte combien d'unit\'es syntaxiques contient la chaine #1 ? \@xs@newmacro\StrLen{}{1}{1}{% \def\@xs@reserved@C{#1}% \@xs@count\z@ - \@xs@StrLen@i + \let\@xs@nestlevel\z@ + \def\groupID{0}% + \let\@xs@atbegingroup\relax + \def\@xs@atendofgroup{\endgroup\@xs@read@reserved@C}% + \let\@xs@atnextsyntaxunit\relax + \@xs@read@reserved@C \expandafter\@xs@ReturnResult\expandafter{\number\@xs@count}{#2}} -\def\@xs@StrLen@i{% + +% Macro interne fermant autant de groupes que n\'ecessaire pour trouver une unit\'e syntaxique derri\`ere +\def\@xs@continuetonext{% \ifx\@xs@reserved@C\@empty + \ifnum\@xs@nestlevel>\z@ + \expandafter\endgroup\expandafter\@xs@addtomacro\expandafter\@xs@reserved@B\expandafter{\expandafter{\@xs@reserved@B}}% on concat\`ene + \expandafter\expandafter\expandafter\@xs@continuetonext% on recommence + \fi + \fi}% + +\def\@xs@manage@groupID{% + \begingroup\def\@xs@reserved@A{0}% + \ifx\@xs@reserved@A\groupID% si on arrive du groupe de niveau 0 + \endgroup\edef\groupID{\number\integerpart}% on met simplement le niveau \else - \expandafter\@xs@returnfirstsyntaxunit\expandafter{\@xs@reserved@C}\@xs@reserved@A - \expandafter\@xs@removefirstsyntaxunit\expandafter{\@xs@reserved@C}\@xs@reserved@C - \@xs@exploregroups - \ifx\bgroup\@xs@toks - \begingroup - \expandafter\def\expandafter\@xs@reserved@C\@xs@reserved@A - \@xs@StrLen@i - \endgroup - \else - \global\advance\@xs@count\@ne - \fi% - \expandafter\@xs@StrLen@i + \endgroup\expandafter\@xs@addtomacro\expandafter\groupID\expandafter{\expandafter,\number\integerpart}% \fi} -% % Cette macro coupe la chaine #2 après l'unité syntaxique n°#1 -% % Le début est assigné dans #3 et la fin dans #4 -\@xs@newmacro\StrSplit{}{2}{0}{\@xs@StrSplit@i{#2}{#1}} -\def\@xs@StrSplit@i#1#2#3#4{% - \def\@xs@StrSplit@ii{% - \ifx#4\@empty - \let\@xs@next\relax - \else - \expandafter\@xs@returnfirstsyntaxunit\expandafter{#4}\@xs@reserved@A - \expandafter\@xs@removefirstsyntaxunit\expandafter{#4}#4% - \@xs@exploregroups - \ifx\bgroup\@xs@toks - \begingroup - \expandafter\def\expandafter#4\@xs@reserved@A - \let#3\@empty - \@xs@StrSplit@ii - \ifx#4\@empty - \def\@xs@next{% - \expandafter\endgroup - \expandafter\@xs@addtomacro\expandafter#3\expandafter{\expandafter{#3}}}% - \else - \let\@xs@next\endgroup - \fi - \@xs@next - \else - \global\advance\@xs@count\@ne - \expandafter\@xs@addtomacro\expandafter#3\expandafter{\@xs@reserved@A}% - \fi - \ifnum\@xs@count=#1\relax - \global\let#3#3\global\let#4#4% - \let\@xs@next\relax - \else - \let\@xs@next\@xs@StrSplit@ii - \fi - \fi - \@xs@next}% - \def#4{#2}\let#3\@empty +% Cette macro coupe la chaine #1 apr\`es l'unit\'e syntaxique n°#2 +\def\StrSplit{\@ifstar{\let\@xs@reserved@E\@xs@continuetonext\StrSpl@t}{\let\@xs@reserved@E\relax\StrSpl@t}} +\@xs@newmacro\StrSpl@t{}{2}{0}{\@xs@StrSplit@i{#2}{#1}\@xs@StrSplit@ii} +% Cette macro interne coupe la chaine #2 apr\`es l'unit\'e syntaxique n°#1 +% Le d\'ebut est assign\'e dans \@xs@reserved@B et la fin dans \@xs@reserved@C +\def\@xs@StrSplit@i#1#2{% + \def\@xs@reserved@D{#1}\def\@xs@reserved@C{#2}\let\@xs@reserved@B\@empty\let\groupID\@empty \ifnum#1>\z@ - \@xs@count\z@ - \@xs@StrSplit@ii + \@xs@count\z@\integerpart\z@\def\groupID{0}\let\@xs@nestlevel\z@ + \def\@xs@atendofgroup{% + \expandafter\endgroup + \expandafter\@xs@addtomacro\expandafter\@xs@reserved@B\expandafter{\expandafter{\@xs@reserved@B}}% + \@xs@read@reserved@C}% + \def\@xs@atbegingroup{\let\@xs@reserved@B\@empty}% + \def\@xs@atnextsyntaxunit{% + \expandafter\@xs@addtomacro\expandafter\@xs@reserved@B\expandafter{\@xs@reserved@A}% + \ifnum\@xs@count=\@xs@reserved@D\relax + \ifx\@xs@reserved@C\@empty\@xs@reserved@E\fi + \global\let\@xs@reserved@B\@xs@reserved@B + \global\let\@xs@reserved@C\@xs@reserved@C + \global\let\groupID\groupID + \@xs@exitallgroups + \let\@xs@next\relax + \fi}% + \@xs@read@reserved@C \fi} +\def\@xs@StrSplit@ii#1#2{\let#1\@xs@reserved@B\let#2\@xs@reserved@C} % De la chaine #1, renvoie ce qui se trouve entre les positions -% #2 et #3, caractères aux positions compris ! +% #2 et #3, unit\'es syntaxiques aux positions compris ! \@xs@newmacro\StrMid{}{3}{1}{% \begingroup \noexploregroups - \@xs@StrSplit{#1}{#3}\@xs@reserved@B\@xs@reserved@C - \expandafter\expandafter\expandafter\@xs@StrSplit\expandafter\expandafter\expandafter{\expandafter\@xs@reserved@B\expandafter}\expandafter{\number\numexpr#2-1}\@xs@reserved@B\@xs@reserved@C + \@xs@StrSplit@i{#3}{#1}% + \edef\@xs@reserved@C{\number\numexpr#2-1}% + \expandafter\expandafter\expandafter\@xs@StrSplit@i\expandafter\expandafter\expandafter{\expandafter\@xs@reserved@C\expandafter}\expandafter{\@xs@reserved@B}% \expandafter\endgroup - \expandafter\@xs@ReturnResult\expandafter{\@xs@reserved@C}{#4}} + \expandafter\@xs@ReturnResult\expandafter{\@xs@reserved@C}{#4}% + \let\groupID\@empty} -% supprime #2 caractères à gauche dans la chaine #1 +% supprime #2 unit\'es syntaxiques \`a gauche dans la chaine #1 \@xs@newmacro\StrGobbleLeft{}{2}{1}{% - \@xs@StrSplit@i{#2}{#1}\@xs@reserved@B\@xs@reserved@C + \@xs@StrSplit@i{#2}{#1}% \expandafter\@xs@ReturnResult\expandafter{\@xs@reserved@C}{#3}} -% extrait de #1 la chaine à gauche de longueur #2 +% extrait de #1 la chaine \`a gauche de longueur #2 \@xs@newmacro\StrLeft{}{2}{1}{% - \@xs@StrSplit@i{#2}{#1}\@xs@reserved@B\@xs@reserved@C + \@xs@StrSplit@i{#2}{#1}% \expandafter\@xs@ReturnResult\expandafter{\@xs@reserved@B}{#3}} -% supprime #2 caractères à droite dans la chaine #1 +% supprime #2 unit\'es syntaxiques \`a droite dans la chaine #1 \@xs@newmacro\StrGobbleRight{}{2}{1}{% \@xs@StrLen{#1}[\@xs@reserved@E]% - \expandafter\@xs@StrSplit@i\expandafter{\number\numexpr\@xs@reserved@E-#2}{#1}\@xs@reserved@C\@xs@reserved@D - \expandafter\@xs@ReturnResult\expandafter{\@xs@reserved@C}{#3}} + \expandafter\@xs@StrSplit@i\expandafter{\number\numexpr\@xs@reserved@E-#2}{#1}% + \expandafter\@xs@ReturnResult\expandafter{\@xs@reserved@B}{#3}} -% renvoie #2 caractères à la droite de la chaine #1 +% renvoie #2 unit\'es syntaxiques \`a la droite de la chaine #1 \@xs@newmacro\StrRight{}{2}{1}{% \@xs@StrLen{#1}[\@xs@reserved@E]% - \expandafter\@xs@StrSplit@i\expandafter{\number\numexpr\@xs@reserved@E-#2}{#1}\@xs@reserved@C\@xs@reserved@D - \expandafter\@xs@ReturnResult\expandafter{\@xs@reserved@D}{#3}} + \expandafter\@xs@StrSplit@i\expandafter{\number\numexpr\@xs@reserved@E-#2}{#1}% + \expandafter\@xs@ReturnResult\expandafter{\@xs@reserved@C}{#3}} \@xs@newmacro\StrChar{}{2}{1}{% - \ifnum#2<\@ne - \@xs@ReturnResult{}{#3}% - \else - \expandafter\@xs@StrSplit@i\expandafter{\number\numexpr#2-1}{#1}\@xs@reserved@C\@xs@reserved@D - \expandafter\@xs@StrSplit@i\expandafter{\expandafter1\expandafter}\expandafter{\@xs@reserved@D}\@xs@reserved@C\@xs@reserved@D - \expandafter\@xs@ReturnResult\expandafter{\@xs@reserved@C}{#3}% - \fi} + \let\@xs@reserved@B\@empty + \ifnum#2>\z@ + \def\@xs@reserved@C{#1}\def\@xs@reserved@D{#2}\@xs@count\z@ + \def\groupID{0}\let\@xs@nestlevel\z@\integerpart\z@ + \let\@xs@atbegingroup\relax + \def\@xs@atendofgroup{\endgroup\@xs@read@reserved@C}% + \def\@xs@atnextsyntaxunit{% + \ifnum\@xs@count=\@xs@reserved@D% la n i\`eme US est atteinte ? + \global\let\@xs@reserved@B\@xs@reserved@A% on capture l'US en cours qui est celle cherch\'ee + \global\let\groupID\groupID + \@xs@exitallgroups + \let\@xs@next\relax + \fi}% + \@xs@read@reserved@C + \fi + \ifx\@xs@reserved@B\@empty\let\groupID\@empty\fi + \expandafter\@xs@ReturnResult\expandafter{\@xs@reserved@B}{#3}} % Combien de fois compte t-on #2 dans #1 ? -% utilise \@xs@reserved@A -> \@xs@reserved@C en mode arg \@xs@newmacro\StrCount{}{2}{1}{% \ifx\@empty#2\@empty - \@xs@ArgEmpty - \def\@xs@StrCount@afterlastocccur{}% \@xs@ReturnResult{0}{#3}% \else - \@xs@StrCount@i{#1}{#2}{#3}% + \def\@xs@reserved@D{#1}\def\@xs@reserved@E{#2}\let\@xs@reserved@C\@empty + \@xs@count\z@\integerpart\z@\def\groupID{0}\let\@xs@nestlevel\z@ + \def\@xs@atendofgroup{% + \expandafter\endgroup + \expandafter\@xs@addtomacro\expandafter\@xs@reserved@C\expandafter{\expandafter{\@xs@reserved@C}}% + \@xs@read@reserved@D}% + \def\@xs@atoccurfound{\let\@xs@reserved@C\@empty\@xs@read@reserved@D}% + \@xs@read@reserved@D + \expandafter\@xs@ReturnResult\expandafter{\number\@xs@count}{#3}% \fi} -\def\@xs@StrCount@i#1#2#3{% - \def\@xs@StrCount@ii{% - \ifx\@xs@reserved@C\@empty% on a fini de parcourir \@xs@reserved@C ? - \let\@xs@next\relax% on sort de la macro - \else - \expandafter\@xs@IfBeginWith@i\expandafter{\@xs@reserved@C}{#2}% - {\global\advance\@xs@count\@ne - \let\@xs@StrCount@afterlastocccur\@xs@reserved@A - \let\@xs@reserved@C\@xs@reserved@A}% on enlève le motif à \@xs@reserved@C - {\expandafter\@xs@returnfirstsyntaxunit\expandafter{\@xs@reserved@C}\@xs@reserved@A% \@xs@reserved@C ne commence pas par le motif : on prend la 1ere unité syntaxique - \expandafter\@xs@removefirstsyntaxunit\expandafter{\@xs@reserved@C}\@xs@reserved@C% puis on l'enlève - \@xs@exploregroups - \ifx\bgroup\@xs@toks% si cette unité syntaxique est un groupe {...} - \begingroup% alors on ouvre un groupe - \expandafter\def\expandafter\@xs@reserved@C\@xs@reserved@A% \@xs@reserved@C devient l'intérieur de {...} - \@xs@StrCount@ii% on lance la macro avec ces nouvelles définitions - \endgroup - \fi}% - \let\@xs@next\@xs@StrCount@ii - \fi - \@xs@next}% - \def\@xs@reserved@C{#1}\def\@xs@StrCount@afterlastocccur{#1}% - \@xs@count\z@ - \@xs@StrCount@ii - \expandafter\@xs@ReturnResult\expandafter{\number\@xs@count}{#3}} % renvoie la position de l'occurrence #1 de la sous chaine #3 dans la chaine #2 \@xs@newmacro\StrPosition{1}{2}{1}{% - \@xs@cutafteroccur{#2}{#3}{#1}\@xs@reserved@C\@xs@reserved@D\@xs@reserved@E + \@xs@cutafteroccur{#2}{#3}{#1}% + \let\@xs@reserved@E\groupID \ifx\@xs@reserved@C\@xs@reserved@D \@xs@ReturnResult{0}{#4}% + \let\@xs@reserved@E\@empty \else - \ifx\@empty\@xs@exploregroups% on explore les groupes ? - \expandafter\@xs@StrLen\expandafter{\@xs@beforeoccur}[\@xs@reserved@D]% - \else - \expandafter\@xs@StrLen\expandafter{\@xs@reserved@D}[\@xs@reserved@D]% - \fi - \expandafter\@xs@ReturnResult\expandafter{\number\numexpr\@xs@reserved@D+1}{#4}% - \fi} + \expandafter\@xs@StrLen\expandafter{\@xs@reserved@C}[\@xs@reserved@C]% + \expandafter\@xs@ReturnResult\expandafter{\number\numexpr\@xs@reserved@C+1}{#4}% + \fi + \let\groupID\@xs@reserved@E} -\def\comparestrict{\def\@xs@comparecoeff{1}} -\def\comparenormal{\def\@xs@comparecoeff{0}} +\def\comparestrict{\let\@xs@comparecoeff\@ne} +\def\comparenormal{\let\@xs@comparecoeff\z@} \def\savecomparemode{\let\@xs@saved@comparecoeff\@xs@comparecoeff} \def\restorecomparemode{\let\@xs@comparecoeff\@xs@saved@comparecoeff} % Compare les deux arguments #1 et #2 -% Renvoie 0 s'ils sont égaux et renvoie la -% position du premier token différent sinon -\@xs@newmacro\StrCompare{}{2}{1}{% +% Renvoie 0 s'ils sont \'egaux et renvoie la +% position de la premiere unit\'e syntaxiques diff\'erente sinon +\@xs@newmacro*2\StrCompare{}{2}{1}{% \def\@xs@reserved@A{#1}% \def\@xs@reserved@B{#2}% \ifx\@xs@reserved@B\@xs@reserved@A @@ -848,23 +888,66 @@ \expandafter\@xs@returnfirstsyntaxunit\expandafter{\@xs@reserved@D}\@xs@reserved@B \ifx\@xs@reserved@B\@xs@reserved@A \ifx\@xs@reserved@A\@empty - \@xs@StrCompare@iii{##1}% les 2 unités syntaxiques sont égales, on renvoie la position + \@xs@StrCompare@iii{##1}% les 2 unit\'es syntaxiques sont \'egales, on renvoie la position \else - \def\@xs@next{\expandafter\@xs@StrCompare@ii\expandafter{\number\numexpr##1+1}}% les 2 unités syntaxiques sont égales et non vides, on recommence + \def\@xs@next{\expandafter\@xs@StrCompare@ii\expandafter{\number\numexpr##1+1}}% les 2 unit\'es syntaxiques sont \'egales et non vides, on recommence \expandafter\@xs@removefirstsyntaxunit\expandafter{\@xs@reserved@C}\@xs@reserved@C \expandafter\@xs@removefirstsyntaxunit\expandafter{\@xs@reserved@D}\@xs@reserved@D \fi - \else% les 2 caractères sont différents : on renvoie la position + \else% les 2 unit\'es syntaxiques sont diff\'erentes : on renvoie la position \@xs@StrCompare@iii{##1}% \fi \@xs@next}% \def\@xs@reserved@C{#1}\def\@xs@reserved@D{#2}% \@xs@StrCompare@ii1} +\@xs@newmacro\StrFindGroup{}{2}{1}{% + \def\@xs@reserved@A{#2}\def\@xs@reserved@B{0}% + \ifx\@xs@reserved@A\@xs@reserved@B + \def\@xs@next{\@xs@ReturnResult{{#1}}{#3}}% + \else + \def\@xs@next{\@xs@StrFindGroup@i{#1}{#2}[#3]}% + \fi + \@xs@next} +\def\@xs@StrFindGroup@i#1#2[#3]{% + \def\@xs@StrFindGroup@ii{% + \ifx\@xs@reserved@C\@empty + \def\@xs@next{\@xs@ReturnResult{}{#3}}% s'il ne reste plus rien, on renvoie vide + \else + \expandafter\@xs@returnfirstsyntaxunit\expandafter{\@xs@reserved@C}\@xs@reserved@D + \ifx\bgroup\@xs@toks% si la 1\`ere unit\'e syntaxique est un groupe explicite + \advance\@xs@count\@ne% on augmente le compteur + \ifnum\@xs@count=\@xs@reserved@A% on est au groupe cherch\'e lors de la profondeur courante ? + \ifx\@empty\@xs@reserved@B% on est \`a la profondeur maximale ? + \def\@xs@next{\expandafter\@xs@ReturnResult\expandafter{\@xs@reserved@D}{#3}}% on renvoie ce groupe + \else% sinon + \expandafter\def\expandafter\@xs@next\expandafter{\expandafter\@xs@StrFindGroup@i\@xs@reserved@D}% on recommence avec ce groupe + \expandafter\@xs@addtomacro\expandafter\@xs@next\expandafter{\expandafter{\@xs@reserved@B}[#3]}% et les profondeurs de recherche restantes + \fi + \else + \expandafter\@xs@removefirstsyntaxunit\expandafter{\@xs@reserved@C}\@xs@reserved@C + \let\@xs@next\@xs@StrFindGroup@ii + \fi + \else + \expandafter\@xs@removefirstsyntaxunit\expandafter{\@xs@reserved@C}\@xs@reserved@C + \let\@xs@next\@xs@StrFindGroup@ii + \fi + \fi + \@xs@next}% + \@xs@extractgroupnumber{#2}\@xs@reserved@A\@xs@reserved@B + \@xs@count\z@ + \ifnum\@xs@reserved@A>\z@\def\@xs@reserved@C{#1}\else\let\@xs@reserved@C\@empty\fi + \@xs@StrFindGroup@ii} + +\def\@xs@extractgroupnumber#1#2#3{% + \def\@xs@extractgroupnumber@i##1,##2\@xs@nil{\def#2{##1}\def#3{##2}}% + \@xs@extractgroupnumber@i#1,\@xs@nil + \ifx\@empty#3\else\@xs@extractgroupnumber@i#1\@xs@nil\fi} + % Restaure le code de @ \catcode`\@=\CurrentAtCatcode\relax -% Définit le délimiteur verb -% définit les différents modes et les mémorise +% D\'efinit le d\'elimiteur verb +% d\'efinit les diff\'erents modes et les m\'emorise \setverbdelim{|}% \fullexpandarg\saveexpandmode \comparenormal\savecomparemode @@ -873,83 +956,101 @@ % % Historique %------------------------------------------------------------------------------ -%% v1.0 4/7/2008 : - Package achevé. -% 7/7/2008 : - Package publié sur CTAN. +%% v1.0 4/7/2008 : - Package achev\'e. +% 7/7/2008 : - Package publi\'e sur CTAN. %------------------------------------------------------------------------------ % v1.1 15/8/2008 -% - Le package ne nécessite plus LaTeX et est désormais utilisable sous Plain -% eTeX. +% - Le package ne n\'ecessite plus LaTeX et est d\'esormais utilisable sous +% Plain eTeX. % - Ajout des macros \IfInteger et \IfDecimal. -% Pour cette dernière, la partie entière et la partie décimale sont -% récupérables dans les compteurs \integerpart et \decimalpart. Ce qu'il -% reste après qu'un caractère non attendu soit rencontré est dispo dans -% \@xs@remainafterdecimal +% Pour cette derni\`ere, la partie enti\`ere et la partie d\'ecimale sont +% r\'ecup\'erables dans les compteurs \integerpart et \decimalpart. Ce +% qu'il reste apr\`es qu'un caract\`ere non attendu soit rencontr\'e est +% dispo dans \@xs@remainafterdecimal % - Correction d'un bug dans \tokenize : -% suppression de l'expansion avec \normalexpandarg pour éviter le bug -% avec les lettres accentuées dans l'exemple : \tokenize\aa{éù} -% - Amélioration du code de la plupart des macros. -% - Écriture d'une routine \@xs@newmacro définissant les macros. -% - Suppression de tous les compteurs grace à \numexpr. -% - Nouvelles fonctionnalités internes dans : +% suppression de l'expansion avec \normalexpandarg pour \'eviter le bug +% avec les lettres accentu\'ees dans l'exemple : \tokenize\aa{\'e\`u} +% - Am\'elioration du code de la plupart des macros. +% - \'Ecriture d'une routine \@xs@newmacro d\'efinissant les macros. +% - Suppression de tous les compteurs grace \`a \numexpr. +% - Nouvelles fonctionnalit\'es internes dans : % \IfSubStr -% ajout des chaines se trouvant avant et après l'occurrence testée dans -% les sc \@xs@behind@IfSubStr et \@xs@before@IfSubStr +% ajout des chaines se trouvant avant et apr\`es l'occurrence test\'ee +% dans les sc \@xs@behind@IfSubStr et \@xs@before@IfSubStr % \StrCount -% a) ajout de ce qui se trouve après la dernière occurrence dans la sc% -% \@xs@StrCount@afterlastocccur -% b) la macro ne dépend plus d'aucune autre +% a) ajout de ce qui se trouve apr\`es la derni\`ere occurrence dans la +% sc \@xs@StrCount@afterlastocccur +% b) la macro ne d\'epend plus d'aucune autre %------------------------------------------------------------------------------ % v1.2 23/8/2008 -% - Amélioration du code de \StrMid \StrGobbleLeft, \StrLeft, \StrGobbleRight -% et \StrRight à l'aide de la nouvelle macro \@xs@StrSplit@i +% - Am\'elioration du code de \StrMid \StrGobbleLeft, \StrLeft, +% \StrGobbleRight et \StrRight \`a l'aide de la nouvelle macro +% \@xs@StrSplit@i % - Nouveau test \IfStrEq qui compare 2 chaines % - Nouveau test \IfEq qui compare 2 chaines (ou 2 nombres si les 2 chaines % contiennent un nombre) % - Correction d'un bug dans \@xs@formatnumber. La macro n'envisageait pas le -% cas où son argument était vide ce qui faiasait planter \IfDecimal{}{V}{F} -% et \IfInteger{}{V}{F} +% cas o\`u son argument \'etait vide ce qui faiasait planter +% \IfDecimal{}{V}{F} et \IfInteger{}{V}{F} %------------------------------------------------------------------------------ % v1.3 21/9/2008 -% - Amélioration du code, mise en place de récursivités terminales dans toutes -% les macros récursives, simplification de \@xs@TestEqual en utilisant \ifx +% - Am\'elioration du code, mise en place de r\'ecursivit\'es terminales dans +% toutes les macros r\'ecursives, simplification de \@xs@TestEqual en +% utilisant \ifx % - Nouvelles macros \IfStrEqCase et \IfEqCase -% Teste si une chaîne est égale à plusieurs chaînes donnée et exécute un -% code spécifique -% - Création de la macro publique \StrSplit -% Coupe la chaine en 2 à une position donnée +% Teste si une chaîne est \'egale \`a plusieurs chaînes donn\'ee et +% ex\'ecute un code sp\'ecifique +% - Cr\'eation de la macro publique \StrSplit +% Coupe la chaine en 2 \`a une position donn\'ee % - Nouvelle macro \StrCompare -% Compare 2 chaînes et renvoie la position du 1er caractère différent. -% Renvoie 0 si elles sont égales. +% Compare 2 chaînes et renvoie la position du 1er caract\`ere diff\'erent. +% Renvoie 0 si elles sont \'egales. %------------------------------------------------------------------------------ % v1.3a 29/9/2008 % - Correction d'un bug : \expandafter#1 % dans les macros \IfSubStrBefore et \StrBetween qui buggue si #1 est un % nombre > 9 ! -% - Ré écriture de \@xs@returnfirstsyntaxunit et \@xs@gobblefirstchar qui -% deviennent purement développables. -% - Ré écriture de \StrLen +% - R\'e \'ecriture de \@xs@returnfirstsyntaxunit et \@xs@gobblefirstchar qui +% deviennent purement d\'eveloppables. +% - R\'e \'ecriture de \StrLen % - Nouvelle macro interne \@xs@cutafteroccur -% Coupe la chaine après la nième occurrence d'une sous chaine. -% - Code amélioré de \StrMid, \StrLeft, \StrGobbleLeft, \StrRight, -% \StrGobbleRight grace à \@xs@cutafteroccur +% Coupe la chaine apr\`es la ni\`eme occurrence d'une sous chaine. +% - Code am\'elior\'e de \StrMid, \StrLeft, \StrGobbleLeft, \StrRight, +% \StrGobbleRight grace \`a \@xs@cutafteroccur %------------------------------------------------------------------------------ % v1.4 4/11/2008 -% - xstring traite ses arguments par unité syntaxique, et donc toutes les -% macros internes ont été ré-écrites à cette fin. -% - Le manuel a été ré-écrit, rendu plus clair et mieux structuré. -% - Nouvelle fonctionnalité : \expandarg -% le 1er lexème de chaque argument est 1-développé avant que la macro ne -% soit appelée. Si un argument comporte plus qu'1 lexème, il faut passer -% par \scancs*[1] pour 1-développer toutes les unités syntaxiques. +% - xstring traite ses arguments par unit\'e syntaxique, et donc toutes les +% macros internes ont \'et\'e r\'e-\'ecrites \`a cette fin. +% - Le manuel a \'et\'e r\'e-\'ecrit, rendu plus clair et mieux structur\'e. +% - Nouvelle fonctionnalit\'e : \expandarg +% le 1er lex\`eme de chaque argument est 1-d\'evelopp\'e avant que la +% macro ne soit appel\'ee. Si un argument comporte plus qu'1 lex\`eme, +% il faut passer par \scancs*[1] pour 1-d\'evelopper toutes les unit\'es +% syntaxiques. % - Correction de 2 erreurs dans le manuel anglais : 0 est la valeur par -% défaut dans \StrSubstitute et \StrDel -% - Cohérence dans les nom des séquences de contrôles temporaires qui sont -% \@xs@reserved@A -> \@xs@reserved@E +% d\'efaut dans \StrSubstitute et \StrDel +% - Coh\'erence dans les nom des s\'equences de contr\^oles temporaires qui +% sont d\'esormais : \@xs@reserved@A \`a \@xs@reserved@E %------------------------------------------------------------------------------ % v1.4a 12/11/2008 -% - Correction d'un bug dans \@xs@StrSplit dans le cas où l'argument numérique -% est <1 : la 1ere coupure doit être vide et le seconde doit être égale à -% l'argument. +% - Correction d'un bug dans \@xs@StrSplit dans le cas o\`u l'argument +% num\'erique est <1 : la 1ere coupure doit être vide et le seconde doit +% être \'egale \`a l'argument. %------------------------------------------------------------------------------ % v1.4b 16/11/2008 -% - Correction de 2 bugs dans \@xs@returnfirstsyntaxunit \ No newline at end of file +% - Correction de 2 bugs dans \@xs@returnfirstsyntaxunit +%------------------------------------------------------------------------------ +% v1.5 31/12/2008 +% - Nouvelles fonctionnalit\'es dans la recherche de groupes par un +% identificateur caract\'erisant leur imbrication. Impl\'ementation de : +% 1) \StrFindGroup +% 2) \groupID +% - Ajout des nouvelles macros g\'en\'eriques \@xs@read@reserved@C et +% \@xs@read@reserved@D +% - Correction d'un bug dans \StrSplit : \StrSplit{{a}bc}{1}[\truc] faisait +% que \truc contenait «a{a}». +% - Correction d'un bug dans \@xs@newmacro : l'argument optionnel \'etait +% d\'etok\'enis\'e \`a tort dans les macros \'etoil\'ees. +% - Dans \@xs@newmacro, on doit choisir le num\'ero du dernier argument devant +% être d\'etok\'enis\'e dans le cas d'une macro \'etoil\'ee (sachant que +% l'argument optionnel ne l'est jamais) \ No newline at end of file -- cgit v1.2.3