From a8313d1d7bc7774a95f17646587669488918504e Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Tue, 30 Sep 2008 23:19:37 +0000 Subject: xstring update (30sep08) git-svn-id: svn://tug.org/texlive/trunk@10806 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/tex/generic/xstring/xstring.tex | 740 +++++++++++++++++++++ Master/texmf-dist/tex/latex/xstring/xstring.tex | 771 ---------------------- 2 files changed, 740 insertions(+), 771 deletions(-) create mode 100644 Master/texmf-dist/tex/generic/xstring/xstring.tex delete mode 100644 Master/texmf-dist/tex/latex/xstring/xstring.tex (limited to 'Master/texmf-dist/tex') diff --git a/Master/texmf-dist/tex/generic/xstring/xstring.tex b/Master/texmf-dist/tex/generic/xstring/xstring.tex new file mode 100644 index 00000000000..fc87bcb824a --- /dev/null +++ b/Master/texmf-dist/tex/generic/xstring/xstring.tex @@ -0,0 +1,740 @@ +% __________________________________________________ +% | | +% | | +% | xstring v1.3a | +% | | +% | September 29 2008 | +% | | +% |__________________________________________________| +% +% This is xtring.tex +% +% Christian Tellechea 2008 +% email : unbonpetit@gmail.com +% ------------------------------------------------------------------- +% This work may be distributed and/or modified under the +% conditions of the LaTeX Project Public License, either version 1.3 +% 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.3 or later is part of all distributions of LaTeX +% version 2005/12/01 or later. +% ------------------------------------------------------------------- +% This work has the LPPL maintenance status `maintained'. +% +% 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.3a} +\def\xstringdate {2008/09/29} +\def\xstringfrenchdate {29 septembre 2008} +\def\xstringenglishdate{September $29^{\mathrm{th}}$ 2008} +\edef\CurrentAtCatcode{\the\catcode`\@} +\catcode`\@=11 +\newwrite\@xs@unused% pour les messages +\newcount\integerpart% pour les tests sur les nombres +\newcount\decimalpart + +\expandafter\ifx\csname @latexerr\endcsname\relax% on n'utilise pas LaTeX ? + \immediate\write\m@ne{Package: xstring \xstringdate\space\space v\xstringversion\space\space String manipulations (C Tellechea)}% + \long\def\@firstoftwo#1#2{#1} + \long\def\@secondoftwo#1#2{#2} + \long\def\@ifnextchar#1#2#3{% + \let\reserved@d=#1% + \def\reserved@a{#2}% + \def\reserved@b{#3}% + \futurelet\@let@token\@ifnch} + \def\@ifnch{% + \ifx\@let@token\@sptoken + \let\reserved@c\@xifnch + \else + \ifx\@let@token\reserved@d + \let\reserved@c\reserved@a + \else + \let\reserved@c\reserved@b + \fi + \fi + \reserved@c} + \def\:{\let\@sptoken= } \: + \def\:{\@xifnch} \expandafter\def\: {\futurelet\@let@token\@ifnch} + \def\@ifstar#1{\@ifnextchar *{\@firstoftwo{#1}}} + \long\def\@testopt#1#2{\@ifnextchar[{#1}{#1[{#2}]}} + \def\@empty{} +\fi% fin des définitions LaTeX + +% Gestion des messages d'erreur +\def\@xs@linenumber{on input line \the\inputlineno} +\def\@xs@errorwrite#1#2{% + \begingroup + \newlinechar`\^^J% + \errhelp{#2}% + \errmessage{Package xstring Error: \@xs@linenumber\space#1^^J% + See user manual for further information.^^J% + Type \space H \space for immediate help.}% + \endgroup} + +\def\@xs@warningwrite#1{% + \begingroup + \newlinechar`\^^J% + \immediate\write\@xs@unused{Package xstring Warning: #1 \@xs@linenumber^^J}% + \endgroup} + +\def\@xs@infowrite#1{% + \begingroup + \newlinechar`\^^J% + \immediate\write\m@ne{Package xstring Info: #1}% + \endgroup} + +% Messages d'information pour situations particulières +\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 +\def\@xs@MakeVerb{% lit 1 argument et le transforme en verb + \begingroup% groupe où les catcodes sont à 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 + \expandafter\ifx\expandafter\@empty\@xs@gobblefirstchar#1\@nil\@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 + \endgroup% on ferme le groupe + \@xs@afterreadverb{##2}}}% on appelle l'exécution de fin + +% Assigne l'argument entre délimiteur 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 lexèmes de #1 puis et assigne le résultat à \@xs@result@expandallonelevel +\def\@xs@expandallonelevel#1#2\@nil{% + \expandafter\expandafter\expandafter\def% plein d'expandafter + \expandafter\expandafter\expandafter\@xs@result@expandallonelevel% pour développer #1 d'un niveau + \expandafter\expandafter\expandafter{\expandafter\@xs@result@expandallonelevel#1}% et l'ajouter à \@xs@result@expandallonelevel + \ifx\@empty#2\@empty + \else + \def\@xs@next{\@xs@expandallonelevel#2\@nil}% + \expandafter\@xs@next + \fi}% s'il reste des sc, on boucle + +\def\@xs@notestcs#1\@nil{\relax}% +\def\@xs@testcs#1#2\@nil{% + \ifx\@empty#2\@empty + \else% si la séquence de contrôle 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 +\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}% + \def\@xs@testornot{\@xs@notestcs}% + \@xs@scancs}% + {\def\@xs@testornot{\@xs@testcs}% + \@xs@scancs}} +\def\@xs@scancs{\@ifnextchar[{\@xs@scancs@}{\@xs@scancs@[1]}} +\def\@xs@scancs@[#1]#2#3{% +% #1 : profondeur à développer 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\@nil{% développe de #1 niveaux toutes les sc de #3 et l'assigne à \@xs@result@scancs + \def\@xs@result@expandallonelevel{}% + \ifnum##1<#1\relax% tant que la profondeur de développement n'est pas atteinte + \expandafter\@xs@testornot\@xs@result@scancs\@nil% on teste éventuellement si le développement comporte 1 seule sc + \expandafter\@xs@expandallonelevel\@xs@result@scancs\@nil% on développe tout d'un niveau + \expandafter\def\expandafter\@xs@result@scancs\expandafter{\@xs@result@expandallonelevel}% + \def\@xs@next{\expandafter\@xs@expandalltodepth\number\numexpr##1+1\relax\@nil}% + \expandafter\@xs@next% et on recommence + \fi}% + \def\@xs@result@scancs{#3}% + \@xs@expandalltodepth0\@nil + \expandafter\def\expandafter#2\expandafter{\detokenize\expandafter{\@xs@result@scancs}}} + +% Cette macro développe #2 au maximum (ce qui doit donner du texte), +% puis le transforme en token et l'assigne à #1 +% On ouvre un groupe dans lequel un \@nil est inséré à la fin du fichier virtuel +% lu avec \scantokens. Ce \@nil sert à l'argument délimité de \@xs@AssignResult +\def\tokenize#1#2{% + \begingroup + %\expandafter\@xs@def\expandafter\@xs@expansion@tokenize\expandafter{#2}% on développe en accord avec \fullexpandarg ou \noexpandarg + \@xs@def\@xs@expansion@tokenize{#2}% on développe en accord avec \fullexpandarg ou \noexpandarg ## Correction [v1.1] ## + \def\@xs@AssignResult##1\@nil{\def#1{##1}}% on assigne en tenant compte du \@nil qui vient de la fin du fichier virtuel + \everyeof{\@nil}% met un \@nil à la fin du fichier virtuel + \endlinechar\m@ne + \expandafter\expandafter\expandafter\endgroup% on retarde la fermeture du groupe + \expandafter\@xs@AssignResult\scantokens\expandafter{\@xs@expansion@tokenize}}% pout faire l'assignation + +% 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 +\def\@xs@ReturnResult#1#2{% + \expandafter\ifx\expandafter\@empty\detokenize{#2}\@empty% pas de nom ? + #1% on affiche #1 + \else% il y a un nom donc + \edef#2{#1}% on assigne #1 dans #3 avec edef + \fi} + +% Pas d'expansion des arguments +\def\normalexpandarg{% + \let\@xs@def\def% on définit \@xs@call avec \def + \def\@xs@expand##1{\expandafter\unexpanded\expandafter{##1}}} + +% Expansion des arguments +\def\fullexpandarg{% + \let\@xs@def\edef% on définit\@xs@call avec \edef + \def\@xs@expand##1{##1}}% et on neutralise \@xs@expand + +% Cette macro interne renvoie le 1er caractère de la chaine passée en argument +\def\@xs@firstchar#1{% + \expandafter\ifx\expandafter\@empty\@xs@beforespace#1 \@nil\@empty + \ifx\@empty#1\@empty\else\space\fi + \else + \@xs@returnfirstchar#1\@nil + \fi} + +% Cette macro interne enlève le 1er caractère de la chaine passée en argument +\def\@xs@removefirstchar#1{% + \expandafter\ifx\expandafter\@empty\@xs@beforespace#1 \@nil\@empty + \ifx\@empty#1\@empty\else\@xs@afterspace#1\@nil\fi + \else + \@xs@gobblefirstchar#1\@nil + \fi} +\def\@xs@beforespace#1 #2\@nil{#1} +\def\@xs@afterspace#1 #2\@nil{#2} +\def\@xs@gobblefirstchar#1#2\@nil{#2} +\def\@xs@returnfirstchar#1#2\@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 +% des catcodes de 10 pour les espaces et 12 pour le reste. +\def\@xs@expand@and@detokenize#1#2{% + \@xs@def#1{#2}% on développe #2 selon \fullexpandarg ou \normalexpandarg + \edef#1{\detokenize\expandafter{#1}}}% puis on détokenize et on assigne à #1 + +\def\@xs@expand@and@assign#1#2{% + \@xs@def#1{#2}}% on développe #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} +% \@xs@DefArg{3} met dans la sc \@xs@myarg le texte "####1####2####3" +\def\@xs@DefArg#1{\def\@xs@defarg0##1#1##2\@nil{\def\@xs@myarg{##1#1}}\expandafter\@xs@defarg\@xs@argstring\@nil} +% \@xs@DefArg@{3} met dans la sc \@xs@myarg le texte "[####1]####2####3####4" +\def\@xs@DefArg@#1{\expandafter\@xs@defarg@\expandafter{\number\numexpr#1+1}} +\def\@xs@defarg@#1{\def\@xs@defarg0##11##2#1##3\@nil{\def\@xs@myarg{[##11]##2#1}}\expandafter\@xs@defarg\@xs@argstring\@nil} +% \@xs@OneArg{3} met dans la sc \@xs@myarg le texte "####3" +\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\@nil{\def\@xs@myarg{##2#2}}\expandafter\@xs@defarg\@xs@argstring\@nil} + +\def\@xs@BuildLines#1#2{% #1 : numéro du 1er argument et % #2 : nombre de lignes + \def\@xs@newlines{}% + \def\@xs@newargs{}% + \def\@xs@buildlines##1\@nil{% + \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}}% + \@xs@expand@and@addtomacro\@xs@newargs{{\noexpand\@xs@expand\expandafter\noexpand\csname @xs@arg@\romannumeral\numexpr##1\endcsname}}% + \ifnum##1<#2\relax + \def\@xs@next{\expandafter\@xs@buildlines\number\numexpr##1+1\relax\@nil}% + \expandafter\@xs@next + \fi} + \@xs@buildlines1\@nil} + +\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@macronameroot{@xs@\expandafter\@xs@gobblefirstchar\string#1\@nil}% + \edef\@macro@name{\expandafter\noexpand\csname\@xs@macronameroot @\ifx\@empty#2\@empty @\fi\endcsname}% + \edef\@xs@temp@{% + \def\noexpand#1{\noexpand\@ifstar + {\noexpand\let\noexpand\@xs@assign\noexpand\@xs@expand@and@detokenize\expandafter\noexpand\@macro@name}% + {\noexpand\let\noexpand\@xs@assign\noexpand\@xs@expand@and@assign\expandafter\noexpand\@macro@name}}% + \ifx\@empty#2\@empty + \else + \def\expandafter\noexpand\@macro@name{\noexpand\@ifnextchar[% + {\expandafter\noexpand\csname\@xs@macronameroot @@\endcsname}% + {\expandafter\noexpand\csname\@xs@macronameroot @@\endcsname[#2]}}% + \fi}% +% Que fait \@xs@temp@ ? 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]}} + \@xs@temp@ + \ifx\@empty#2\@empty + \@xs@BuildLines{1}{#3}% + \@xs@DefArg{#3}% + \else + \@xs@BuildLines{2}{#3}% + \@xs@DefArg@{#3}% + \fi + \edef\@xs@temp@{\def\expandafter\noexpand\csname\@xs@macronameroot @@\endcsname\@xs@myarg}% + \edef\@xs@temp@@{\unexpanded\expandafter{\@xs@newlines}\edef\noexpand\@xs@call}% + \edef\@xs@temp@@@{\noexpand\noexpand\expandafter\noexpand\csname\@xs@macronameroot\endcsname\ifx\@empty#2\@empty\else[\unexpanded{\@xs@expand{##1}}]\fi\unexpanded\expandafter{\@xs@newargs}}% + \ifnum#4=\@ne\edef\@xs@temp@@@{\noexpand\noexpand\noexpand\@testopt{\unexpanded\expandafter{\@xs@temp@@@}}\unexpanded{{}}}\fi + \@xs@expand@and@addtomacro\@xs@temp@@{{\unexpanded\expandafter{\@xs@temp@@@}}\noexpand\@xs@call}% + \@xs@expand@and@addtomacro\@xs@temp@{{\unexpanded\expandafter{\@xs@temp@@}}}% +% Que fait \@xs@temp@ ? Il définit par exemple pour 3 arguments obligatoires et 1 facultatif : +% \def\@xs@NOM@@[##1]##2##3##4{% +% \@xs@assign{\@xs@arg@i}{##2}% +% \@xs@assign{\@xs@arg@ii}{##3}% +% \@xs@assign{\@xs@arg@iii}{##4}% +% si #4=0: \edef\@xs@call{\noexpand\@xs@NOM[\@xs@expand{##1}]{\@xs@expand\@xs@arg@i}{\@xs@expand\@xs@arg@ii}{\@xs@expand\@xs@arg@iii}}% +% si #4=1: \edef\@xs@call{\noexpand\@testopt{\noexpand\@xs@NOM[\@xs@expand{##1}]{\@xs@expand\@xs@arg@i}{\@xs@expand\@xs@arg@ii}{\@xs@expand\@xs@arg@iii}}{}}% +% \@xs@call} + \@xs@temp@ + \edef\@xs@temp@{\def\expandafter\noexpand\csname\@xs@macronameroot\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@temp@ ? Il définit par exemple pour 3 arguments obligatoires et 1 facultatif : +% \def \@xs@NOM[##1]##2##3##4[##5]{#5} + \@xs@temp@} + +\def\@xs@strip@delimit#1\@delimit#2\@nil{#1} +% Cette macro coupe la chaine #1 après la #3ème occurrence de la sous chaine #2 +% \@xs@beforeoccurwith : contient ce qui se trouve avant cette occurrence y compris l'occurrence +% \@xs@beforeoccurwithout : idem mais sans l'occurrence +% \@xs@behindoccur : 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 +\def\@xs@cutafteroccur#1#2#3{% #1 est la chaine, #2 est le pattern, #3 est la nième occurence souhaitée + \def\@xs@cutafteroccur@i##1\@nil##2#2##3\@nil{% ##1 est le compteur + \def\@xs@next{\relax}% + \ifx\@empty##3\@empty% rien après cette occurrence ? + \def\@xs@beforeoccurwith{}\def\@xs@beforeoccurwithout{}\def\@xs@behindoccur{}% occurrence non trouvée -> on met tout à \empty + \else + \ifnum##1<#3\relax% tant que le nombre d'occurrence n'est pas atteint + \expandafter\def\expandafter\@xs@beforeoccurwith\expandafter{\@xs@beforeoccurwith##2#2}% on ajoute la chaine restante + \def\@xs@next{\expandafter\@xs@cutafteroccur@i\number\numexpr##1+1\relax\@nil##3\@nil}% on recommence après être sorti des \if...\fi + \else + \expandafter\def\expandafter\@xs@beforeoccurwithout\expandafter{\@xs@beforeoccurwith##2}% on ajoute la chaine restante une dernière fois sans le pattern ici + \expandafter\def\expandafter\@xs@beforeoccurwith\expandafter{\@xs@beforeoccurwith##2#2}% et avec le pattern ici + \expandafter\def\expandafter\@xs@behindoccur\expandafter{\@xs@strip@delimit##3\@nil}% + \fi + \fi + \@xs@next}% + \def\@xs@beforeoccurwith{}\def\@xs@beforeoccurwithout{}\def\@xs@behindoccur{}% + \ifnum#3>\z@ + \ifx\@empty#2\@empty\@xs@ArgEmpty\else\@xs@cutafteroccur@i\@ne\@nil#1\@delimit#2\@nil\fi + \else\@xs@BadNumArg\fi} + +\@xs@newmacro\IfSubStr{1}{2}{0}{% + \@xs@cutafteroccur{#2}{#3}{#1}% + \ifx\@xs@behindoccur\@xs@beforeoccurwith + \expandafter\@secondoftwo + \else + \expandafter\@firstoftwo + \fi} + +\@xs@newmacro\IfBeginWith{}{2}{0}{% + \@xs@cutafteroccur{#1}{#2}{\@ne}% + \def\@xs@next{#2}% + \ifx\@xs@next\@xs@beforeoccurwith + \expandafter\@firstoftwo + \else + \expandafter\@secondoftwo + \fi} + +\@xs@newmacro\IfEndWith{}{2}{0}{% + \@xs@StrCount{#1}{#2}[\@xs@result@If]% + \ifnum\@xs@result@If=\z@ + \let\@xs@result@If\@secondoftwo% + \else + \ifx\@empty\@xs@after@StrCount + \let\@xs@result@If\@firstoftwo% + \else + \let\@xs@result@If\@secondoftwo% + \fi + \fi + \@xs@result@If} + +\@xs@newmacro\IfSubStrBefore{1,1}{3}{0}{\@xs@IfSubStrBefore@i[#1]{#2}{#3}{#4}} +\def\@xs@IfSubStrBefore@i[#1,#2]#3#4#5{% + \@xs@cutafteroccur{#3}{#5}{#2}% + \expandafter\@xs@cutafteroccur\expandafter{\@xs@beforeoccurwithout}{#4}{#1}% + \ifx\@xs@behindoccur\@xs@beforeoccurwith + \expandafter\@secondoftwo + \else + \expandafter\@firstoftwo + \fi} + +\@xs@newmacro\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}} + +% tests sur les nombres \IfInteger et \IfDecimal +\def\@xs@putXifempty#1{#1\ifx\@empty#1\@empty X\fi} +\def\@xs@formatnumber#1{% + \ifx\@empty#1\@empty + 0X% si vide, renvoie 0X + \else + \expandafter\ifx\@xs@returnfirstchar#1\@nil+% si commence par un +, renvoie +0 + +0\expandafter\@xs@putXifempty\expandafter{\@xs@gobblefirstchar#1\@nil}% + \else + \expandafter\ifx\@xs@returnfirstchar#1\@nil-% si commence par un -, renvoie -0 + -0\expandafter\@xs@putXifempty\expandafter{\@xs@gobblefirstchar#1\@nil}% + \else + 0#1% si ne commence ni par + ni par -, renvoie 0 + \fi + \fi + \fi} + +\@xs@newmacro\IfInteger{}{1}{0}{% + \@xs@def\@xs@formattednumber{\@xs@formatnumber{#1}}% + \decimalpart\z@ + \afterassignment\@xs@defafterinteger\integerpart=\@xs@formattednumber\relax\@nil + \if\relax\@xs@afterinteger + \expandafter\@firstoftwo + \else + \expandafter\@secondoftwo + \fi} + +\@xs@newmacro\IfDecimal{}{1}{0}{% + \@xs@def\@xs@formattednumber{\@xs@formatnumber{#1}}% + \decimalpart\z@ + \afterassignment\@xs@defafterinteger\integerpart=\@xs@formattednumber\relax\@nil + \expandafter\@xs@testdot\@xs@afterinteger\@nil + \if\relax\@xs@afterdecimal + \expandafter\@firstoftwo + \else + \expandafter\@secondoftwo + \fi} + +\def\@xs@defafterinteger#1\@nil{\def\@xs@afterinteger{#1}}% +\def\@xs@testdot{\@ifnextchar.{\@xs@readdecimalpart}{\@xs@testcomma}} +\def\@xs@testcomma{\@ifnextchar,{\@xs@readdecimalpart}{\@xs@endnumber}} +\def\@xs@readdecimalpart#1#2\@nil{% + \if\relax#2\def\@xs@formattednumber{0X}\else\def\@xs@formattednumber{0#2}\fi + \afterassignment\@xs@defafterinteger\decimalpart=\@xs@formattednumber\@nil + \expandafter\@xs@endnumber\@xs@afterinteger\@nil} +\def\@xs@endnumber#1\@nil{\def\@xs@afterdecimal{#1}} + +% test d'égalité sur des chaines (et des chaines contenant des nombres) +\def\@xs@IfStrEqFalse@#1#2{\let\@xs@result@If\@secondoftwo} +\def\@xs@IfStrEqFalse@@#1#2{% renvoie vrai si les 2 arg sont décimaux et s'ils sont égaux, faux sinon + \@xs@IfDecimal{#1}% + {\@xs@IfDecimal{#2}% + {\ifdim#1pt=#2pt\let\@xs@result@If\@firstoftwo\else\let\@xs@result@If\@secondoftwo\fi}% les 2 sont décimaux : on fait le test + {\let\@xs@result@If\@secondoftwo}}% un seul est décimal + {\let\@xs@result@If\@secondoftwo}}% #1 n'est pas décimal + +\def\@xs@TestEqu@l#1#2{% teste si les 2 arguments sont égaux + \def\@xs@tempa{#1}\def\@xs@tempb{#2}% + \ifx\@xs@tempa\@xs@tempb + \let\@xs@result@If\@firstoftwo% égalité parfaite des 2 chaines + \else + \@xs@IfStrEqFalse{#1}{#2}% + \fi + \@xs@result@If} + +\@xs@newmacro\IfStrEq{}{2}{0}{% teste si les deux chaines sont égales + \let\@xs@IfStrEqFalse\@xs@IfStrEqFalse@ + \@xs@TestEqu@l{#1}{#2}} +\@xs@newmacro\IfEq{}{2}{0}{% teste si les 2 arguments (chaine ou nombre) sont égaux + \let\@xs@IfStrEqFalse\@xs@IfStrEqFalse@@ + \@xs@TestEqu@l{#1}{#2}} + +\def\IfStrEqCase{\@ifstar{\def\@xs@IfEqName{\IfStrEq*}\@xs@IfStrCase@@}{\def\@xs@IfEqName{\IfStrEq}\@xs@IfStrCase@@}} +\def\@xs@IfStrCase@@#1#2{\@testopt{\@xs@IfStringCase{#1}{#2}}{}} + +\def\IfEqCase{\@ifstar{\def\@xs@IfEqName{\IfEq*}\@xs@IfEqCase@@}{\def\@xs@IfEqName{\IfEq}\@xs@IfEqCase@@}} +\def\@xs@IfEqCase@@#1#2{\@testopt{\@xs@IfStringCase{#1}{#2}}{}} + +\def\@xs@IfStringCase#1#2[#3]{% + \def\@xs@testcase##1##2##3\@nil{% lit les 2 premiers lexèmes dans ##1 et ##2. Les autres dans ##3 + \@xs@IfEqName{#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 + \else + \def\@xs@next{\@xs@testcase##3\@nil}% sinon, on recommence avec ce qui reste + \fi + \@xs@next}}% + \@xs@testcase#2\@nil} + +% 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@ReturnResult{\@xs@beforeoccurwithout}{#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@ReturnResult{\@xs@behindoccur}{#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]} +\def\@xs@StrBetween@i[#1,#2]#3#4#5[#6]{% + \@xs@cutafteroccur{#3}{#5}{#2}% + \expandafter\@xs@cutafteroccur\expandafter{\@xs@beforeoccurwithout}{#4}{#1}% + \@xs@ReturnResult{\@xs@behindoccur}{#6}} + +% Remplace les #1 premières occurences de la chaine #3 +% par la chaine #4 dans la chaine #2 +\@xs@newmacro\StrSubstitute{0}{3}{1}{% + \ifx\@empty#3\@empty% si #3 est vide, on ne fait rien + \@xs@ArgEmpty% warning + \edef\@xs@result@StrSubstitute{#2}% + \else + \edef\@xs@result@StrSubstitute{}% on initialise à vide, histoire d'enlever le statut undefined + \ifnum#1>\z@ + \def\@xs@StrSubstitute@i##1\@nil##2#3##3\@nil{% ici, on compte les occurrences : ##1 est le compteur + \edef\@xs@result@StrSubstitute{\@xs@result@StrSubstitute##2#4}% on recopie jusqu'à la 1ere occurrence, et on remplace #3 par #4 + \@xs@IfSubStr[1]{##3}{#3}% tant que la chaine restante contient #3 + {\ifnum##1<#1\relax% tant qu'on n'a pas atteint la bonne occurrence, + \def\@xs@next{\expandafter\@xs@StrSubstitute@i\number\numexpr##1+1\relax\@nil##3\@nil}% + \else + \def\@xs@next{\edef\@xs@result@StrSubstitute{\@xs@result@StrSubstitute##3}}% + \fi + \@xs@next} + {\edef\@xs@result@StrSubstitute{\@xs@result@StrSubstitute##3}}}% si on ne peut plus substituter, on rajoute ce qui reste + \@xs@IfSubStr[1]{#2}{#3}% + {\@xs@StrSubstitute@i1\@nil#2\@nil}% si #2 contient #3, on exécute la macro + {\edef\@xs@result@StrSubstitute{#2}}% sinon, on renvoie la chaine #2 + \else + \def\@xs@StrSubstitute@i##1#3##2\@nil{% ici, on ne compte pas les occurrences + \edef\@xs@result@StrSubstitute{\@xs@result@StrSubstitute##1#4}% on recopie jusqu'à la 1ere occurrence, et on remplace #3 par #4 + \@xs@IfSubStr[1]{##2}{#3}% ...tant que la chaine restante contient #3 + {\@xs@StrSubstitute@i##2\@nil}% on recommence + {\edef\@xs@result@StrSubstitute{\@xs@result@StrSubstitute##2}}}% si on ne peut plus substituter, on rajoute ce qui reste + \@xs@IfSubStr[1]{#2}{#3}% + {\@xs@StrSubstitute@i#2\@nil}% si #2 contient #3, on exécute la macro + {\edef\@xs@result@StrSubstitute{#2}}% sinon, on renvoie la chaine #2 + \fi + \fi + \@xs@ReturnResult{\@xs@result@StrSubstitute}{#5}} + +% Supprime les #1 premières occurrences de #3 dans #2 +\@xs@newmacro\StrDel{0}{2}{1}{\@xs@StrSubstitute[#1]{#2}{#3}{}[#4]} + +% Compte combien de caractères contient la chaine #1 ? +\@xs@newmacro\StrLen{}{1}{1}{% + \def\@xs@StrLen@i##1{% ##1 est le compteur + \ifx\@empty\@xs@remain@StrLen + \@xs@ReturnResult{\number\numexpr##1}{#2}% + \else + \edef\@xs@remain@StrLen{\expandafter\@xs@removefirstchar\expandafter{\@xs@remain@StrLen}}% + \def\@xs@next{\expandafter\@xs@StrLen@i\expandafter{\number\numexpr##1+1}}% + \expandafter\@xs@next + \fi}% + \def\@xs@remain@StrLen{#1}% + \@xs@StrLen@i\z@} + +\@xs@newmacro\StrSplit{}{2}{0}{\@xs@StrSplit@i{#2}{#1}} +\def\@xs@StrSplit@i#1#2#3#4{% +% Cette macro coupe la chaine #2 après le caractère n°#1 +% Le début est assigné dans #3 et la fin dans #4 + \def\@xs@StrSplit@ii##1\@nil{% + \def\@xs@next{\relax}% + \ifnum##1<#1\relax% tant que c'est pas fini + \edef#3{#3\expandafter\@xs@firstchar\expandafter{#4}}% prend le 1er caractère l'ajoute au résultat final + \edef#4{\expandafter\@xs@removefirstchar\expandafter{#4}}% puis l'enlève de la chaine + \ifx\@empty#4\@empty + \else + \def\@xs@next{\expandafter\@xs@StrSplit@ii\number\numexpr##1+1\relax\@nil}% on recommence sauf s'il ne reste plus rien + \fi + \fi + \@xs@next}% + \def#3{}\def#4{#2}% + \@xs@StrSplit@ii0\@nil} + +% De la chaine #1, renvoie ce qui se trouve entre les positions +% #2 et #3, caractères aux positions compris ! +\@xs@newmacro\StrMid{}{3}{1}{% + \@xs@StrSplit{#1}{#3}\@xs@BeforeMid\@xs@BehindMid + \expandafter\expandafter\expandafter\@xs@StrSplit\expandafter\expandafter\expandafter{\expandafter\@xs@BeforeMid\expandafter}\expandafter{\number\numexpr#2-1}\@xs@BeforeMid\@xs@BehindMid + \@xs@ReturnResult{\@xs@BehindMid}{#4}} + +% supprime #2 caractères à gauche dans la chaine #1 +\@xs@newmacro\StrGobbleLeft{}{2}{1}{% + \@xs@StrSplit@i{#2}{#1}\@xs@call\@xs@result@StrGobbleLeft + \@xs@ReturnResult{\@xs@result@StrGobbleLeft}{#3}} + +% extrait de #1 la chaine à gauche de longueur #2 +\@xs@newmacro\StrLeft{}{2}{1}{% + \@xs@StrSplit@i{#2}{#1}\@xs@result@StrLeft\@xs@call + \@xs@ReturnResult{\@xs@result@StrLeft}{#3}} + +% supprime #2 caractères à droite dans la chaine #1 +\@xs@newmacro\StrGobbleRight{}{2}{1}{% + \@xs@StrLen{#1}[\@xs@Len@StrGobbleRight]% + \expandafter\@xs@StrSplit@i\expandafter{\numexpr\@xs@Len@StrGobbleRight-#2}{#1}\@xs@result@StrGobbleRight\@xs@call + \@xs@ReturnResult{\@xs@result@StrGobbleRight}{#3}} + +% renvoie #2 caractères à la droite de la chaine #1 +\@xs@newmacro\StrRight{}{2}{1}{% + \@xs@StrLen{#1}[\@xs@Len@StrRight]% + \expandafter\@xs@StrSplit@i\expandafter{\numexpr\@xs@Len@StrRight-#2}{#1}\@xs@call\@xs@result@StrRight + \@xs@ReturnResult{\@xs@result@StrRight}{#3}} + +\@xs@newmacro\StrChar{}{2}{1}{% + \ifnum#2<\@ne + \@xs@ReturnResult{}{#3}% + \else + \expandafter\@xs@StrSplit@i\expandafter{\numexpr#2-1}{#1}\@xs@call\@xs@result@StrChar + \@xs@ReturnResult{\expandafter\@xs@firstchar\expandafter{\@xs@result@StrChar}}{#3}% + \fi} + +% Combien de fois compte t-on #2 dans #1 ? +\@xs@newmacro\StrCount{}{2}{1}{% + \ifx\@empty#2\@empty + \@xs@ArgEmpty + \edef\@xs@after@StrCount{}% + \@xs@ReturnResult{0}{#3}% + \else + \def\@xs@StrCount@i##1\@nil##2#2##3\@nil{% ##1 est le compteur + \ifx\@empty##3\@empty + \edef\@xs@after@StrCount{\ifnum\numexpr##1=\z@\else\@xs@strip@delimit##2\@nil\fi}% + \@xs@ReturnResult{##1}{#3}% + \else + \def\@xs@next{\expandafter\@xs@StrCount@i\number\numexpr##1+1\relax\@nil##3\@nil}% + \expandafter\@xs@next + \fi}% + \@xs@StrCount@i0\@nil#1\@delimit#2\@nil + \fi} + +% 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}% + \ifx\@xs@beforeoccurwith\@xs@afteroccur + \@xs@ReturnResult{0}{#4}% + \else + \expandafter\@xs@StrLen\expandafter{\@xs@beforeoccurwithout}[\@xs@next]% + \@xs@ReturnResult{\number\numexpr\@xs@next+1}{#4}% + \fi} + +\def\comparestrict{\let\@xs@comparecoeff\@ne} +\def\comparenormal{\let\@xs@comparecoeff\z@} +% Compare les deux arguments #1 et #2 +% Renvoie 0 s'ils sont égaux et renvoie la position +% du premier caractère différent sinon +\@xs@newmacro\StrCompare{}{2}{1}{% + \@xs@IfStrEq{#1}{#2}% + {\@xs@ReturnResult{0}{#3}}% + {\ifx\@empty\@xs@stringB + \def\@xs@next{\@xs@ReturnResult{0}{#3}}% si la plus petite chaîne est vide, on renvoie 0 + \else + \def\@xs@next{\@xs@StrCompare@i{#1}{#2}{#3}}% + \fi + \@xs@next}} +\def\@xs@StrCompare@i#1#2#3{% + \def\@xs@StrCompare@ii##1\@nil{% ##1 est la position + \ifx\@empty\@xs@stringB% il n'y a plus de caractères à tester... + \def\@xs@next{\@xs@ReturnResult{\number\numexpr##1*\@xs@comparecoeff}{#3}}% ...on a passé tous les tests : #2 *en entier* apparaît exactement au début de #1 et on renvoie donc 0 ou la position + \else + \expandafter\@xs@StrSplit@i\expandafter\@ne\expandafter{\@xs@stringA}\@xs@currentcharA\@xs@stringA + \expandafter\@xs@StrSplit@i\expandafter\@ne\expandafter{\@xs@stringB}\@xs@currentcharB\@xs@stringB + \ifx\@xs@currentcharB\@xs@currentcharA + \def\@xs@next{\expandafter\@xs@StrCompare@ii\number\numexpr##1+1\relax\@nil}% les 2 caractères sont égaux, on recommence + \else + \def\@xs@next{\@xs@ReturnResult{##1}{#3}}% les 2 caractères sont différents : on renvoie la position + \fi + \fi + \@xs@next}% + \@xs@StrLen{#1}[\@xs@LenA@StrCompare]% + \@xs@StrLen{#2}[\@xs@LenB@StrCompare]% + \ifnum\@xs@LenB@StrCompare<\@xs@LenA@StrCompare\relax + \def\@xs@stringA{#1}\def\@xs@stringB{#2}% + \else + \def\@xs@stringA{#2}\def\@xs@stringB{#1}% + \fi + \@xs@StrCompare@ii1\@nil} + +% Restaure le code de @ +\catcode`\@=\CurrentAtCatcode\relax +% Définit le délimiteur verb et le développement des arguments par défaut et le mode de comparaison +\setverbdelim{|} +\fullexpandarg +\comparenormal +\endinput +% +% Historique +%------------------------------------------------------------ +%% v1.0 4/7/2008 : - Package achevé. +% 7/7/2008 : - Package publié sur CTAN. +%------------------------------------------------------------ +% v1.1 15/8/2008 +% - Le package ne nécessite plus LaTeX et est désormais +% 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 +% - 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 : +% \IfSubStr +% ajout des chaines se trouvant avant et après +% l'occurrence testée 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@after@StrCount +% b) la macro ne dépend 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 +% - 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} +%------------------------------------------------------------ +% 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@TestEqu@l 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 +% - Nouvelle macro \StrCompare +% Compare 2 chaînes et renvoie la position du +% 1er caractère différent. Renvoie 0 si elles sont +% égales +%------------------------------------------------------------ +% 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@firstchar et \@xs@gobblefirstchar +% qui deviennent purement développables. +% - Ré écriture 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 \ No newline at end of file diff --git a/Master/texmf-dist/tex/latex/xstring/xstring.tex b/Master/texmf-dist/tex/latex/xstring/xstring.tex deleted file mode 100644 index 27ab19f1b6c..00000000000 --- a/Master/texmf-dist/tex/latex/xstring/xstring.tex +++ /dev/null @@ -1,771 +0,0 @@ -% __________________________________________________ -% | | -% | | -% | xstring v1.3 | -% | | -% | September 21 2008 | -% | | -% |__________________________________________________| -% -% This is xtring.tex -% -% Christian Tellechea 2008 -% email : unbonpetit@gmail.com -% ------------------------------------------------------------------- -% This work may be distributed and/or modified under the -% conditions of the LaTeX Project Public License, either version 1.3 -% 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.3 or later is part of all distributions of LaTeX -% version 2005/12/01 or later. -% ------------------------------------------------------------------- -% This work has the LPPL maintenance status `maintained'. -% -% 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.3} -\def\xstringdate {2008/09/21} -\def\xstringfrenchdate {21 septembre 2008} -\def\xstringenglishdate{September $21^{\mathrm{st}}$ 2008} -\edef\CurrentAtCatcode{\the\catcode`\@} -\catcode`\@=11 -\newwrite\@xs@unused% pour les messages -\newcount\integerpart% pour les tests sur les nombres -\newcount\decimalpart - -\expandafter\ifx\csname @latexerr\endcsname\relax% on n'utilise pas LaTeX ? - \immediate\write\m@ne{Package: xstring \xstringdate\space\space v\xstringversion\space\space String manipulations (C Tellechea)}% - \long\def\@firstoftwo#1#2{#1} - \long\def\@secondoftwo#1#2{#2} - \long\def\@ifnextchar#1#2#3{% - \let\reserved@d=#1% - \def\reserved@a{#2}% - \def\reserved@b{#3}% - \futurelet\@let@token\@ifnch} - \def\@ifnch{% - \ifx\@let@token\@sptoken - \let\reserved@c\@xifnch - \else - \ifx\@let@token\reserved@d - \let\reserved@c\reserved@a - \else - \let\reserved@c\reserved@b - \fi - \fi - \reserved@c} - \def\:{\let\@sptoken= } \: - \def\:{\@xifnch} \expandafter\def\: {\futurelet\@let@token\@ifnch} - \def\@ifstar#1{\@ifnextchar *{\@firstoftwo{#1}}} - \long\def\@testopt#1#2{\@ifnextchar[{#1}{#1[{#2}]}} - \def\@empty{} -\fi% fin des définitions LaTeX - -\def\@xs@gobblefirstchar#1#2\@nil{#2} -\def\@xs@returnfirstchar#1#2\@nil{#1} - -% Gestion des messages d'erreur -\def\@xs@linenumber{on input line \the\inputlineno} -\def\@xs@errorwrite#1#2{% - \begingroup - \newlinechar`\^^J% - \errhelp{#2}% - \errmessage{Package xstring Error: \@xs@linenumber\space#1^^J% - See user manual for further information.^^J% - Type \space H \space for immediate help.}% - \endgroup} - -\def\@xs@warningwrite#1{% - \begingroup - \newlinechar`\^^J% - \immediate\write\@xs@unused{Package xstring Warning: #1 \@xs@linenumber^^J}% - \endgroup} - -\def\@xs@infowrite#1{% - \begingroup - \newlinechar`\^^J% - \immediate\write\m@ne{Package xstring Info: #1}% - \endgroup} - -% Messages d'information pour situations particulières -\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 -\def\@xs@MakeVerb{% lit 1 argument et le transforme en verb - \begingroup% groupe où les catcodes sont à 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 - \expandafter\ifx\expandafter\@empty\@xs@gobblefirstchar#1\@nil\@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 - \endgroup% on ferme le groupe - \@xs@afterreadverb{##2}}}% on appelle l'exécution de fin - -% Assigne l'argument entre délimiteur 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 lexèmes de #1 puis et assigne le résultat à \@xs@result@expandallonelevel -\def\@xs@expandallonelevel#1#2\@nil{% - \expandafter\expandafter\expandafter\def% plein d'expandafter - \expandafter\expandafter\expandafter\@xs@result@expandallonelevel% pour développer #1 d'un niveau - \expandafter\expandafter\expandafter{\expandafter\@xs@result@expandallonelevel#1}% et l'ajouter à \@xs@result@expandallonelevel - \ifx\@empty#2\@empty - \else - \def\@xs@next{\@xs@expandallonelevel#2\@nil}% - \expandafter\@xs@next - \fi}% s'il reste des sc, on boucle - -\def\@xs@notestcs#1\@nil{\relax}% -\def\@xs@testcs#1#2\@nil{% - \ifx\@empty#2\@empty - \else% si la séquence de contrôle 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 -\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}% - \def\@xs@testornot{\@xs@notestcs}% - \@xs@scancs}% - {\def\@xs@testornot{\@xs@testcs}% - \@xs@scancs}} -\def\@xs@scancs{\@ifnextchar[{\@xs@scancs@}{\@xs@scancs@[1]}} -\def\@xs@scancs@[#1]#2#3{% -% #1 : profondeur à développer 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\@nil{% développe de #1 niveaux toutes les sc de #3 et l'assigne à \@xs@result@scancs - \def\@xs@result@expandallonelevel{}% - \ifnum##1<#1\relax% tant que la profondeur de développement n'est pas atteinte - \expandafter\@xs@testornot\@xs@result@scancs\@nil% on teste éventuellement si le développement comporte 1 seule sc - \expandafter\@xs@expandallonelevel\@xs@result@scancs\@nil% on développe tout d'un niveau - \expandafter\def\expandafter\@xs@result@scancs\expandafter{\@xs@result@expandallonelevel}% - \def\@xs@next{\expandafter\@xs@expandalltodepth\number\numexpr##1+1\relax\@nil}% - \expandafter\@xs@next% et on recommence - \fi}% - \def\@xs@result@scancs{#3}% - \@xs@expandalltodepth0\@nil - \expandafter\def\expandafter#2\expandafter{\detokenize\expandafter{\@xs@result@scancs}}} - -% Cette macro développe #2 au maximum (ce qui doit donner du texte), -% puis le transforme en token et l'assigne à #1 -% On ouvre un groupe dans lequel un \@nil est inséré à la fin du fichier virtuel -% lu avec \scantokens. Ce \@nil sert à l'argument délimité de \@xs@AssignResult -\def\tokenize#1#2{% - \begingroup - %\expandafter\@xs@def\expandafter\@xs@expansion@tokenize\expandafter{#2}% on développe en accord avec \fullexpandarg ou \noexpandarg - \@xs@def\@xs@expansion@tokenize{#2}% on développe en accord avec \fullexpandarg ou \noexpandarg ## Correction [v1.1] ## - \def\@xs@AssignResult##1\@nil{\def#1{##1}}% on assigne en tenant compte du \@nil qui vient de la fin du fichier virtuel - \everyeof{\@nil}% met un \@nil à la fin du fichier virtuel - \endlinechar\m@ne - \expandafter\expandafter\expandafter\endgroup% on retarde la fermeture du groupe - \expandafter\@xs@AssignResult\scantokens\expandafter{\@xs@expansion@tokenize}}% pout faire l'assignation - -% 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 -\def\@xs@ReturnResult#1#2{% - \expandafter\ifx\expandafter\@empty\detokenize{#2}\@empty% pas de nom ? - #1% on affiche #1 - \else% il y a un nom donc - \edef#2{#1}% on assigne #1 dans #3 avec edef - \fi} - -% Pas d'expansion des arguments -\def\normalexpandarg{% - \let\@xs@def\def% on définit \@xs@call avec \def - \def\@xs@expand##1{\expandafter\unexpanded\expandafter{##1}}} - -% Expansion des arguments -\def\fullexpandarg{% - \let\@xs@def\edef% on définit\@xs@call avec \edef - \def\@xs@expand##1{##1}}% et on neutralise \@xs@expand - - -% Cette macro interne enlève le 1er caractère de la chaine passée en argument -\def\@xs@RemoveFirst#1[#2]{% - \ifx\@empty#1\@empty - \edef#2{}% - \else - \@xs@IfBeginWith{#1}{ }% - {\@xs@StrBehind[1]{#1}{ }[#2]}% - {\def\@xs@RemoveFirst@ii##1##2\@nil{\edef#2{##2}}% - \@xs@RemoveFirst@ii#1\@nil}% - \fi} - -% Cette macro interne renvoie le 1er caractère de la chaine passée en argument -\def\@xs@ReturnFirst#1[#2]{% - \ifx\@empty#1\@empty% - \edef#2{}% - \else - \@xs@IfBeginWith{#1}{ }% - {\edef#2{ }}% - {\def\@xs@ReturnFirst@ii##1##2\@nil{\edef#2{##1}}% - \@xs@ReturnFirst@ii#1\@nil}% - \fi} - -% 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 -% des catcodes de 10 pour les espaces et 12 pour le reste. -\def\@xs@expand@and@detokenize#1#2{% - \@xs@def#1{#2}% on développe #2 selon \fullexpandarg ou \normalexpandarg - \edef#1{\detokenize\expandafter{#1}}}% puis on détokenize et on assigne à #1 - -\def\@xs@expand@and@assign#1#2{% - \@xs@def#1{#2}}% on développe #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} -% \@xs@DefArg{3} met dans la sc \@xs@myarg le texte "####1####2####3" -\def\@xs@DefArg#1{\def\@xs@defarg0##1#1##2\@nil{\def\@xs@myarg{##1#1}}\expandafter\@xs@defarg\@xs@argstring\@nil} -% \@xs@DefArg@{3} met dans la sc \@xs@myarg le texte "[####1]####2####3####4" -\def\@xs@DefArg@#1{\expandafter\@xs@defarg@\expandafter{\number\numexpr#1+1}} -\def\@xs@defarg@#1{\def\@xs@defarg0##11##2#1##3\@nil{\def\@xs@myarg{[##11]##2#1}}\expandafter\@xs@defarg\@xs@argstring\@nil} -% \@xs@OneArg{3} met dans la sc \@xs@myarg le texte "####3" -\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\@nil{\def\@xs@myarg{##2#2}}\expandafter\@xs@defarg\@xs@argstring\@nil} - -\def\@xs@BuildLines#1#2{% #1 : numéro du 1er argument et % #2 : nombre de lignes - \def\@xs@newlines{}% - \def\@xs@newargs{}% - \def\@xs@buildlines##1\@nil{% - \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}}% - \@xs@expand@and@addtomacro\@xs@newargs{{\noexpand\@xs@expand\expandafter\noexpand\csname @xs@arg@\romannumeral\numexpr##1\endcsname}}% - \ifnum##1<#2 - \def\@xs@next{\expandafter\@xs@buildlines\number\numexpr##1+1\relax\@nil}% - \expandafter\@xs@next - \fi} - \@xs@buildlines1\@nil} - -\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@macronameroot{@xs@\expandafter\@xs@gobblefirstchar\string#1\@nil}% - \edef\@macro@name{\expandafter\noexpand\csname\@xs@macronameroot @\ifx\@empty#2\@empty @\fi\endcsname}% - \edef\@xs@temp@{% - \def\noexpand#1{\noexpand\@ifstar - {\noexpand\let\noexpand\@xs@assign\noexpand\@xs@expand@and@detokenize\expandafter\noexpand\@macro@name}% - {\noexpand\let\noexpand\@xs@assign\noexpand\@xs@expand@and@assign\expandafter\noexpand\@macro@name}}% - \ifx\@empty#2\@empty - \else - \def\expandafter\noexpand\@macro@name{\noexpand\@ifnextchar[% - {\expandafter\noexpand\csname\@xs@macronameroot @@\endcsname}% - {\expandafter\noexpand\csname\@xs@macronameroot @@\endcsname[#2]}}% - \fi}% -% Que fait \@xs@temp@ ? 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]}} - \@xs@temp@ - \ifx\@empty#2\@empty - \@xs@BuildLines{1}{#3}% - \@xs@DefArg{#3}% - \else - \@xs@BuildLines{2}{#3}% - \@xs@DefArg@{#3}% - \fi - \edef\@xs@temp@{\def\expandafter\noexpand\csname\@xs@macronameroot @@\endcsname\@xs@myarg}% - \edef\@xs@temp@@{\unexpanded\expandafter{\@xs@newlines}\edef\noexpand\@xs@call}% - \edef\@xs@temp@@@{\noexpand\noexpand\expandafter\noexpand\csname\@xs@macronameroot\endcsname\ifx\@empty#2\@empty\else[\unexpanded{\@xs@expand{##1}}]\fi\unexpanded\expandafter{\@xs@newargs}}% - \ifnum#4=\@ne\edef\@xs@temp@@@{\noexpand\noexpand\noexpand\@testopt{\unexpanded\expandafter{\@xs@temp@@@}}\unexpanded{{}}}\fi - \@xs@expand@and@addtomacro\@xs@temp@@{{\unexpanded\expandafter{\@xs@temp@@@}}\noexpand\@xs@call}% - \@xs@expand@and@addtomacro\@xs@temp@{{\unexpanded\expandafter{\@xs@temp@@}}}% -% Que fait \@xs@temp@ ? Il définit par exemple pour 3 arguments obligatoires et 1 facultatif : -% \def\@xs@NOM@@[##1]##2##3##4{% -% \@xs@assign{\@xs@arg@i}{##2}% -% \@xs@assign{\@xs@arg@ii}{##3}% -% \@xs@assign{\@xs@arg@iii}{##4}% -% si #4=0: \edef\@xs@call{\noexpand\@xs@NOM[\@xs@expand{##1}]{\@xs@expand\@xs@arg@i}{\@xs@expand\@xs@arg@ii}{\@xs@expand\@xs@arg@iii}}% -% si #4=1: \edef\@xs@call{\noexpand\@testopt{\noexpand\@xs@NOM[\@xs@expand{##1}]{\@xs@expand\@xs@arg@i}{\@xs@expand\@xs@arg@ii}{\@xs@expand\@xs@arg@iii}}{}}% -% \@xs@call} - \@xs@temp@ - \edef\@xs@temp@{\def\expandafter\noexpand\csname\@xs@macronameroot\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@temp@ ? Il définit par exemple pour 3 arguments obligatoires et 1 facultatif : -% \def \@xs@NOM[##1]##2##3##4[##5]{#5} - \@xs@temp@} - -% Cette macro teste si une chaine (#2) en contient au moins (#1) fois une autre (#3) -% Au final, \@xs@behind@IfSubStr et \@xs@before@IfSubStr contiennent -% ce qui se trouve après et avant la (#1)èmé occurrence de la chaine (#2) -% si elle existe,et contiennent des chaines vides sinon. -\def\@xs@strip@delimit#1\@delimit#2\@nil{#1} -\def\@xs@IfSubStr@case@false{% - \let\@xs@result@If\@secondoftwo% on exécute #5 - \def\@xs@behind@IfSubStr{}% - \def\@xs@before@IfSubStr{}} -\@xs@newmacro\IfSubStr{1}{2}{0}{% - \ifnum#1<\@ne% on gère les cas spéciaux - \@xs@BadNumArg - \@xs@IfSubStr@case@false - \else - \ifx\@empty#2\@empty\@xs@ArgEmpty\fi - \ifx\@empty#3\@empty - \@xs@ArgEmpty - \@xs@IfSubStr@case@false - \else - \def\@xs@before@IfSubStr{}% - \def\@xs@IfSubStr@i##1\@nil##2#3##3\@nil{% ##1 est le compteur - \def\@xs@next{\relax}% - \ifx\@empty##3\@empty% rien après la sous chaine ? - \@xs@IfSubStr@case@false - \else% si ce qu'il est reste n'est pas vide - \ifnum##1<#1% tant que le nombre d'occurrence n'est pas atteint - \edef\@xs@before@IfSubStr{\@xs@before@IfSubStr##2#3}% on ajoute la chaine restante à \@xs@before@IfSubStr - \def\@xs@next{\expandafter\@xs@IfSubStr@i\number\numexpr##1+1\relax\@nil##3\@nil}% on recommence après être sorti de \if...\fi - \else - \let\@xs@result@If\@firstoftwo% nombre d'occurrences atteint : on renvoie #4 - \edef\@xs@before@IfSubStr{\@xs@before@IfSubStr##2}% - \edef\@xs@behind@IfSubStr{\@xs@strip@delimit##3\@nil}% - \fi - \fi - \@xs@next}% - \@xs@IfSubStr@i1\@nil#2\@delimit#3\@nil% \@delimit pour éviter le cas de \IfSubStr{a}{aa}{V}{F} qui renverrait V - \fi - \fi - \@xs@result@If} - -\@xs@newmacro\IfBeginWith{}{2}{0}{% - \@xs@IfSubStr[\@ne]{#1}{#2}% - {\ifx\@empty\@xs@before@IfSubStr\@empty - \let\@xs@result@If\@firstoftwo% - \else - \let\@xs@result@If\@secondoftwo% - \fi}% - {\let\@xs@result@If\@secondoftwo}% - \@xs@result@If} - -\@xs@newmacro\IfEndWith{}{2}{0}{% - \@xs@StrCount{#1}{#2}[\@xs@result@If]% - \ifnum\@xs@result@If=\z@ - \let\@xs@result@If\@secondoftwo% - \else - \ifx\@empty\@xs@after@StrCount\@empty - \let\@xs@result@If\@firstoftwo% - \else - \let\@xs@result@If\@secondoftwo% - \fi - \fi - \@xs@result@If} - -\@xs@newmacro\IfSubStrBefore{1,1}{3}{0}{\@xs@IfSubStrBefore@i[#1]{#2}{#3}{#4}} -\def\@xs@IfSubStrBefore@i[#1,#2]#3#4#5{% - \@xs@IfSubStr[#2]{#3}{#5}% - {\expandafter\@xs@IfSubStr\expandafter[\expandafter#1\expandafter]\expandafter{\@xs@before@IfSubStr}{#4}% - {\let\@xs@result@If\@firstoftwo}% - {\let\@xs@result@If\@secondoftwo}% - }% - {\let\@xs@result@If\@secondoftwo}% - \@xs@result@If} - -\@xs@newmacro\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}} - -% tests sur les nombres \IfInteger et \IfDecimal -\def\@xs@putXifempty#1{#1\ifx\@empty#1\@empty X\fi} -\def\@xs@formatnumber#1{% - \ifx\@empty#1\@empty - 0X% si vide, renvoie 0X - \else - \expandafter\ifx\@xs@returnfirstchar#1\@nil+% si commence par un +, renvoie +0 - +0\expandafter\@xs@putXifempty\expandafter{\@xs@gobblefirstchar#1\@nil}% - \else - \expandafter\ifx\@xs@returnfirstchar#1\@nil-% si commence par un -, renvoie -0 - -0\expandafter\@xs@putXifempty\expandafter{\@xs@gobblefirstchar#1\@nil}% - \else - 0#1% si ne commence ni par + ni par -, renvoie 0 - \fi - \fi - \fi} - -\@xs@newmacro\IfInteger{}{1}{0}{% - \@xs@def\@xs@formattednumber{\@xs@formatnumber{#1}}% - \decimalpart\z@ - \afterassignment\@xs@defafterinteger\integerpart=\@xs@formattednumber\relax\@nil - \if\relax\@xs@afterinteger - \expandafter\@firstoftwo - \else - \expandafter\@secondoftwo - \fi} - -\@xs@newmacro\IfDecimal{}{1}{0}{% - \@xs@def\@xs@formattednumber{\@xs@formatnumber{#1}}% - \decimalpart\z@ - \afterassignment\@xs@defafterinteger\integerpart=\@xs@formattednumber\relax\@nil - \expandafter\@xs@testdot\@xs@afterinteger\@nil - \if\relax\@xs@afterdecimal - \expandafter\@firstoftwo - \else - \expandafter\@secondoftwo - \fi} - -\def\@xs@defafterinteger#1\@nil{\def\@xs@afterinteger{#1}}% -\def\@xs@testdot{\@ifnextchar.{\@xs@readdecimalpart}{\@xs@testcomma}} -\def\@xs@testcomma{\@ifnextchar,{\@xs@readdecimalpart}{\@xs@endnumber}} -\def\@xs@readdecimalpart#1#2\@nil{% - \if\relax#2\def\@xs@formattednumber{0X}\else\def\@xs@formattednumber{0#2}\fi - \afterassignment\@xs@defafterinteger\decimalpart=\@xs@formattednumber\@nil - \expandafter\@xs@endnumber\@xs@afterinteger\@nil} -\def\@xs@endnumber#1\@nil{\def\@xs@afterdecimal{#1}} - -% test d'égalité sur des chaines (et des chaines contenant des nombres) -\def\@xs@IfStrEqFalse@#1#2{\let\@xs@result@If\@secondoftwo} -\def\@xs@IfStrEqFalse@@#1#2{% renvoie vrai si les 2 arg sont décimaux et s'ils sont égaux, faux sinon - \@xs@IfDecimal{#1}% - {\@xs@IfDecimal{#2}% - {\ifdim#1pt=#2pt\let\@xs@result@If\@firstoftwo\else\let\@xs@result@If\@secondoftwo\fi}% les 2 sont décimaux : on fait le test - {\let\@xs@result@If\@secondoftwo}}% un seul est décimal - {\let\@xs@result@If\@secondoftwo}}% #1 n'est pas décimal - -\def\@xs@TestEqu@l#1#2{% teste si les 2 arguments sont égaux - \def\@xs@tempa{#1}\def\@xs@tempb{#2}% - \ifx\@xs@tempa\@xs@tempb - \let\@xs@result@If\@firstoftwo% égalité parfaite des 2 chaines - \else - \@xs@IfStrEqFalse{#1}{#2}% - \fi - \@xs@result@If} - -\@xs@newmacro\IfStrEq{}{2}{0}{% teste si les deux chaines sont égales - \let\@xs@IfStrEqFalse\@xs@IfStrEqFalse@ - \@xs@TestEqu@l{#1}{#2}} -\@xs@newmacro\IfEq{}{2}{0}{% teste si les 2 arguments (chaine ou nombre) sont égaux - \let\@xs@IfStrEqFalse\@xs@IfStrEqFalse@@ - \@xs@TestEqu@l{#1}{#2}} - -\def\IfStrEqCase{\@ifstar{\def\@xs@IfEqName{\IfStrEq*}\@xs@IfStrCase@@}{\def\@xs@IfEqName{\IfStrEq}\@xs@IfStrCase@@}} -\def\@xs@IfStrCase@@#1#2{\@testopt{\@xs@IfStringCase{#1}{#2}}{}} - -\def\IfEqCase{\@ifstar{\def\@xs@IfEqName{\IfEq*}\@xs@IfEqCase@@}{\def\@xs@IfEqName{\IfEq}\@xs@IfEqCase@@}} -\def\@xs@IfEqCase@@#1#2{\@testopt{\@xs@IfStringCase{#1}{#2}}{}} - -\def\@xs@IfStringCase#1#2[#3]{% - \def\@xs@testcase##1##2##3\@nil{% lit les 2 premiers lexèmes dans ##1 et ##2. Les autres dans ##3 - \@xs@IfEqName{#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 - \else - \def\@xs@next{\@xs@testcase##3\@nil}% sinon, on recommence avec ce qui reste - \fi - \@xs@next}}% - \@xs@testcase#2\@nil} - -% 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@IfSubStr[#1]{#2}{#3}% - {\@xs@ReturnResult{\@xs@before@IfSubStr}{#4}}% - {\@xs@ReturnResult{}{#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@IfSubStr[#1]{#2}{#3}% - {\@xs@ReturnResult{\@xs@behind@IfSubStr}{#4}}% - {\@xs@ReturnResult{}{#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]} -\def\@xs@StrBetween@i[#1,#2]#3#4#5[#6]{% - \@xs@IfSubStr[#2]{#3}{#5}% - {\expandafter\@xs@IfSubStr\expandafter[\expandafter#1\expandafter]\expandafter{\@xs@before@IfSubStr}{#4}% - {\@xs@ReturnResult{\@xs@behind@IfSubStr}{#6}}% - {\@xs@ReturnResult{}{#6}}% - }% - {\@xs@ReturnResult{}{#6}}} - -% Remplace les #1 premières occurences de la chaine #3 -% par la chaine #4 dans la chaine #2 -\@xs@newmacro\StrSubstitute{0}{3}{1}{% - \ifx\@empty#3\@empty% si #3 est vide, on ne fait rien - \@xs@ArgEmpty% warning - \edef\@xs@result@StrSubstitute{#2}% - \else - \edef\@xs@result@StrSubstitute{}% on initialise à vide, histoire d'enlever le statut undefined - \ifnum#1>\z@ - \def\@xs@StrSubstitute@i##1\@nil##2#3##3\@nil{% ici, on compte les occurrences : ##1 est le compteur - \edef\@xs@result@StrSubstitute{\@xs@result@StrSubstitute##2#4}% on recopie jusqu'à la 1ere occurrence, et on remplace #3 par #4 - \@xs@IfSubStr[1]{##3}{#3}% tant que la chaine restante contient #3 - {\ifnum##1<#1% tant qu'on n'a pas atteint la bonne occurrence, - \def\@xs@next{\expandafter\@xs@StrSubstitute@i\number\numexpr##1+1\relax\@nil##3\@nil}% - \else - \def\@xs@next{\edef\@xs@result@StrSubstitute{\@xs@result@StrSubstitute##3}}% - \fi - \@xs@next} - {\edef\@xs@result@StrSubstitute{\@xs@result@StrSubstitute##3}}}% si on ne peut plus substituter, on rajoute ce qui reste - \@xs@IfSubStr[1]{#2}{#3}% - {\@xs@StrSubstitute@i1\@nil#2\@nil}% si #2 contient #3, on exécute la macro - {\edef\@xs@result@StrSubstitute{#2}}% sinon, on renvoie la chaine #2 - \else - \def\@xs@StrSubstitute@i##1#3##2\@nil{% ici, on ne compte pas les occurrences - \edef\@xs@result@StrSubstitute{\@xs@result@StrSubstitute##1#4}% on recopie jusqu'à la 1ere occurrence, et on remplace #3 par #4 - \@xs@IfSubStr[1]{##2}{#3}% ...tant que la chaine restante contient #3 - {\@xs@StrSubstitute@i##2\@nil}% on recommence - {\edef\@xs@result@StrSubstitute{\@xs@result@StrSubstitute##2}}}% si on ne peut plus substituter, on rajoute ce qui reste - \@xs@IfSubStr[1]{#2}{#3}% - {\@xs@StrSubstitute@i#2\@nil}% si #2 contient #3, on exécute la macro - {\edef\@xs@result@StrSubstitute{#2}}% sinon, on renvoie la chaine #2 - \fi - \fi - \@xs@ReturnResult{\@xs@result@StrSubstitute}{#5}} - -% Supprime les #1 premières occurrences de #3 dans #2 -\@xs@newmacro\StrDel{0}{2}{1}{\@xs@StrSubstitute[#1]{#2}{#3}{}[#4]} - -% Compte combien de caractères contient la chaine #1 ? -\@xs@newmacro\StrLen{}{1}{1}{\@xs@StrLen@i#1\@nil0\@nil#2\@nil} -\def\@xs@StrLen@i#1\@nil#2\@nil#3\@nil{% #2 est le compteur - \ifx\@empty#1\@empty - \@xs@ReturnResult{\number\numexpr#2}{#3}% - \else - \@xs@RemoveFirst{#1}[\@xs@remain@StrLen]% - \def\@xs@next{\expandafter\expandafter\expandafter\@xs@StrLen@i\expandafter\@xs@remain@StrLen\expandafter\@nil\number\numexpr#2+1\relax\@nil#3\@nil}% - \expandafter\@xs@next - \fi} - -\@xs@newmacro\StrSplit{}{2}{0}{\@xs@StrSplit@i{#2}{#1}} -\def\@xs@StrSplit@i#1#2#3#4{% -% Cette macro coupe la chaine #2 après le caractère n°#1 -% Le début est assigné dans #3 et la fin dans #4 - \def\@xs@StrSplit@ii##1\@nil{% - \def\@xs@next{\relax}% - \ifnum##1<#1\relax% tant que c'est pas fini - \expandafter\@xs@ReturnFirst\expandafter{#4}[\@xs@next]% prend le 1er caractère - \edef#3{#3\@xs@next}% l'ajoute au résultat final - \expandafter\@xs@RemoveFirst\expandafter{#4}[#4]% puis l'enlève de la chaine - \ifx\@empty#4\@empty - \else - \def\@xs@next{\expandafter\@xs@StrSplit@ii\number\numexpr##1+1\relax\@nil}% on recommence sauf s'il ne reste plus rien - \fi - \fi - \@xs@next}% - \def#3{}\def#4{#2}% - \@xs@StrSplit@ii0\@nil} - -\def\StrMid{\@ifstar{\let\@xs@assign\@xs@expand@and@detokenize\@xs@StrMid@@}{\let\@xs@assign\@xs@expand@and@assign\@xs@StrMid@@}} -\def\@xs@StrMid@@#1#2#3{% - \@xs@def\@xs@First@StrMid{\@xs@expand#2}% - \@xs@def\@xs@Last@StrMid{\@xs@expand#3}% position début et fin - \ifnum#2>#3\@xs@BadNumArg\fi - \@xs@assign{\@xs@arg@i}{#1}% - \edef\@xs@call{\noexpand\@testopt{\noexpand\@xs@StrMid{\@xs@expand\@xs@arg@i}}{}}% - \@xs@call} - -\def\@xs@StrMid#1[#2]{% -% renvoie la sous chaine de #1 comprise entre les positions \@xs@First@StrMid et \@xs@Last@StrMid - \@xs@StrLen{#1}[\@len@StrMid]% - \ifnum\@xs@First@StrMid>\@xs@Last@StrMid% mauvais ordre ? - \@xs@ReturnResult{}{#2}% on renvoie rien - \else - \ifnum\@xs@First@StrMid<\@ne% 1ère position trop petite ? - \edef\@xs@First@StrMid{1}% on limite à 1 - \@xs@BadNumArg% avertissement - \fi - \ifnum\@xs@Last@StrMid>\@len@StrMid% dernière position trop grande ? - \edef\@xs@Last@StrMid{\@len@StrMid}% on limite à la longueur de la chaine - \@xs@BadNumArg% avertissement - \fi - \expandafter\@xs@StrSplit@i\expandafter{\numexpr\@xs@First@StrMid-1}{#1}\@xs@before@StrMid\@xs@behind@StrMid - \expandafter\expandafter\expandafter - \@xs@StrSplit@i\expandafter\expandafter\expandafter - {\expandafter\expandafter\expandafter - \numexpr\@xs@Last@StrMid-\@xs@First@StrMid+2\relax\expandafter}\expandafter{\@xs@behind@StrMid}\@xs@result@StrMid\@xs@before@StrMid - \@xs@ReturnResult{\@xs@result@StrMid}{#2}% - \fi} - -% supprime #2 caractères à gauche dans la chaine #1 -\@xs@newmacro\StrGobbleLeft{}{2}{1}{% - \@xs@StrSplit@i{#2}{#1}\@xs@call\@xs@result@StrGobbleLeft - \@xs@ReturnResult{\@xs@result@StrGobbleLeft}{#3}} - -% extrait de #1 la chaine à gauche de longueur #2 -\@xs@newmacro\StrLeft{}{2}{1}{% - \@xs@StrSplit@i{#2}{#1}\@xs@result@StrLeft\@xs@call - \@xs@ReturnResult{\@xs@result@StrLeft}{#3}} - -% supprime #2 caractères à droite dans la chaine #1 -\@xs@newmacro\StrGobbleRight{}{2}{1}{% - \@xs@StrLen{#1}[\@xs@Len@StrGobbleRight]% - \expandafter\@xs@StrSplit@i\expandafter{\numexpr\@xs@Len@StrGobbleRight-#2}{#1}\@xs@result@StrGobbleRight\@xs@call - \@xs@ReturnResult{\@xs@result@StrGobbleRight}{#3}} - -% renvoie #2 caractères à la droite de la chaine #1 -\@xs@newmacro\StrRight{}{2}{1}{% - \@xs@StrLen{#1}[\@xs@Len@StrRight]% - \expandafter\@xs@StrSplit@i\expandafter{\numexpr\@xs@Len@StrRight-#2}{#1}\@xs@call\@xs@result@StrRight - \@xs@ReturnResult{\@xs@result@StrRight}{#3}} - -\@xs@newmacro\StrChar{}{2}{1}{% - \ifnum#2<\@ne - \@xs@ReturnResult{}{#3}% - \else - \expandafter\@xs@StrSplit@i\expandafter{\numexpr#2-1}{#1}\@xs@call\@xs@result@StrChar - \expandafter\@xs@ReturnFirst\expandafter{\@xs@result@StrChar}[\@xs@result@StrChar@]% - \@xs@ReturnResult{\@xs@result@StrChar@}{#3}% - \fi} - -% Combien de fois compte t-on #2 dans #1 ? -\@xs@newmacro\StrCount{}{2}{1}{% - \ifx\@empty#2\@empty - \@xs@ArgEmpty - \edef\@xs@after@StrCount{}% - \@xs@ReturnResult{0}{#3}% - \else - \def\@xs@StrCount@i##1\@nil##2#2##3\@nil{% ##1 est le compteur - \ifx\@empty##3\@empty - \edef\@xs@after@StrCount{\ifnum\numexpr##1=\z@\else\@xs@strip@delimit##2\@nil\fi}% - \@xs@ReturnResult{##1}{#3}% - \else - \def\@xs@next{\expandafter\@xs@StrCount@i\number\numexpr##1+1\relax\@nil##3\@nil}% - \expandafter\@xs@next - \fi}% - \@xs@StrCount@i0\@nil#1\@delimit#2\@nil - \fi} - -% renvoie la position de l'occurrence #1 de la sous chaine #3 dans la chaine #2 -\@xs@newmacro\StrPosition{1}{2}{1}{% - \ifx\@empty#3\@empty% - \@xs@ArgEmpty - \@xs@ReturnResult{0}{#4}% - \else - \@xs@IfSubStr[#1]{#2}{#3}% - {\expandafter\@xs@StrLen\expandafter{\@xs@before@IfSubStr}[\@xs@lenbefore@StrPosition]% - \@xs@ReturnResult{\number\numexpr\@xs@lenbefore@StrPosition+1}{#4}% - }% - {\@xs@ReturnResult{0}{#4}}% - \fi} - -\def\comparestrict{\let\@xs@comparecoeff\@ne} -\def\comparenormal{\let\@xs@comparecoeff\z@} -% Compare les deux arguments #1 et #2 -% Renvoie 0 s'ils sont égaux et renvoie la position -% du premier caractère différent sinon -\@xs@newmacro\StrCompare{}{2}{1}{% - \@xs@IfStrEq{#1}{#2}% - {\@xs@ReturnResult{0}{#3}}% - {\ifx\@empty\@xs@stringB - \def\@xs@next{\@xs@ReturnResult{0}{#3}}% si la plus petite chaîne est vide, on renvoie 0 - \else - \def\@xs@next{\@xs@StrCompare@i{#1}{#2}{#3}}% - \fi - \@xs@next}} -\def\@xs@StrCompare@i#1#2#3{% - \def\@xs@StrCompare@ii##1\@nil{% ##1 est la position - \ifx\@empty\@xs@stringB% il n'y a plus de caractères à tester... - \def\@xs@next{\@xs@ReturnResult{\number\numexpr##1*\@xs@comparecoeff}{#3}}% ...on a passé tous les tests : #2 *en entier* apparaît exactement au début de #1 et on renvoie donc 0 ou la position - \else - \expandafter\@xs@StrSplit@i\expandafter\@ne\expandafter{\@xs@stringA}\@xs@currentcharA\@xs@stringA - \expandafter\@xs@StrSplit@i\expandafter\@ne\expandafter{\@xs@stringB}\@xs@currentcharB\@xs@stringB - \ifx\@xs@currentcharB\@xs@currentcharA - \def\@xs@next{\expandafter\@xs@StrCompare@ii\number\numexpr##1+1\relax\@nil}% les 2 caractères sont égaux, on recommence - \else - \def\@xs@next{\@xs@ReturnResult{##1}{#3}}% les 2 caractères sont différents : on renvoie la position - \fi - \fi - \@xs@next}% - \@xs@StrLen{#1}[\@xs@LenA@StrCompare]% - \@xs@StrLen{#2}[\@xs@LenB@StrCompare]% - \ifnum\@xs@LenB@StrCompare<\@xs@LenA@StrCompare - \def\@xs@stringA{#1}\def\@xs@stringB{#2}% - \else - \def\@xs@stringA{#2}\def\@xs@stringB{#1}% - \fi - \@xs@StrCompare@ii1\@nil} - -% Restaure le code de @ -\catcode`\@=\CurrentAtCatcode\relax -% Définit le délimiteur verb et le développement des arguments par défaut et le mode de comparaison -\setverbdelim{|} -\fullexpandarg -\comparenormal -\endinput -% -% Historique -%------------------------------------------------------------ -%% v1.0 4/7/2008 : - Package achevé. -% 7/7/2008 : - Package publié sur CTAN. -%------------------------------------------------------------ -% v1.1 15/8/2008 -% - Le package ne nécessite plus LaTeX et est désormais -% 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 -% - 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 : -% \IfSubStr -% ajout des chaines se trouvant avant et après -% l'occurrence testée 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@after@StrCount -% b) la macro ne dépend 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 -% - 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} -%------------------------------------------------------------ -% 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@TestEqu@l 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 -% - Nouvelle macro \StrCompare -% Compare 2 chaînes et renvoie la position du -% 1er caractère différent. Renvoie 0 si elles sont -% égales \ No newline at end of file -- cgit v1.2.3