diff options
Diffstat (limited to 'Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/source/progtexmacro.tex')
-rw-r--r-- | Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/source/progtexmacro.tex | 2734 |
1 files changed, 2734 insertions, 0 deletions
diff --git a/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/source/progtexmacro.tex b/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/source/progtexmacro.tex new file mode 100644 index 00000000000..e6547c0c2da --- /dev/null +++ b/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/source/progtexmacro.tex @@ -0,0 +1,2734 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% %% +%% Macros définies dans le livre %% +%% « Apprendre à programmer en TeX » %% +%% et nécessaires à sa compilation %% +%% %% +%% Encodage ISO 8859-1 %% +%% _____ %% +%% %% +%% © 2014 Christian Tellechea %% +%% %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% %% +%% Ce fichier contient celles des macros définies dans le livre qui sont %% +%% nécessaires à sa compilation. %% +%% %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Les codes et les macros donnés dans ce fichier sont diffusés sous licence +% libre « Creative Commons "BY-SA" ». +% +% https://creativecommons.org/licenses/by-sa/4.0/ +% https://creativecommons.org/licenses/by-sa/4.0/legalcode +% +% Vous êtes autorisé à +% +% * partager : copier, distribuer et communiquer le matériel par tous moyens +% et sous tous formats ; +% * adapter : remixer, transformer et créer à partir du matériel pour toute +% utilisation, y compris commerciale +% +% selon les conditions suivantes +% +% * paternité : vous devez citer le nom de l'auteur de façon appropriée, +% fournir un lien vers la licence, et indiquer si des modifications ont +% été apportées. Vous pouvez le faire de manière raisonnable, mais pas +% d'une façon qui suggère le donneur de licence vous approuve ou approuve +% l'utilisation que vous en faites ; +% * partage dans les mêmes conditions : dans le cas où vous effectuez un +% remix, que vous transformez, ou créez à partir du matériel composant +% l'Oeuvre originale, vous devez diffuser l'Oeuvre modifiée dans les mêmes +% conditions, c'est-à-dire avec la même licence avec laquelle l'Oeuvre +% originale a été diffusée. +% +% +% Les commentaires dont sont assorties les macros dans le livre ne sont pas +% sous licence libre et ne sont pas reproduits dans ce fichier. + +\edef\restoreatcoatcode{\catcode`\noexpand\@=\the\catcode`\@} +\catcode`\@11 +{\def\:{\let\sptoken= }\expandafter}\: % + +\long\def\gobone#1{} + +\long\def\identity#1{#1} + +\long\def\firstoftwo#1#2{#1} + +\long\def\secondoftwo#1#2{#2} + +\def\gobtwo#1#2{}% + +\def\defactive#1{% + \catcode`#1=13 + \begingroup + \lccode`~=`#1 + \lowercase{\endgroup\def~}} + +\def\letactive#1{% + \catcode`#1=13 + \begingroup + \lccode`~=`#1 + \lowercase{\endgroup\let~}} + +\def\litterate#1{% #1=lit le token frontière choisi + \begingroup% ouvre un groupe pour y faire les modifications + \def\do##1{\catcode`##1=12 }% + \dospecials% rend inoffensifs tous les tokens spéciaux + \defactive\^^M{\leavevmode\par}% + \defactive\ {\space}% + \defactive<{\string<{}}\defactive>{\string>{}}% + \defactive-{\string-{}}\defactive`{\string`{}}% + \defactive,{\string,{}}\defactive'{\string'{}}% + \defactive#1{\endgroup}% #1 sera un \endgroup + \tt% passe en police à chasse fixe +} + +\long\def\firstto@nil#1#2\@nil{#1} + +\long\def\remainto@nil#1#2\@nil{#2} + +\def\rightofsc#1#2{% + \exparg\ifin{#1}{#2}% + {% si #1 contient le #2 + \def\right@of##1#2##2\@nil{\def#1{##2}}% définit la macro auxiliaire + \expandafter\right@of#1\@nil% appelle la macro auxiliaire + }% + {\let#1=\empty}% sinon, ne rien faire +} + +\def\defname#1{\expandafter\def\csname#1\endcsname} + +\def\letname#1{\expandafter\let\csname#1\endcsname} + +\long\def\addtomacro#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}} + +\long\def\eaddtomacro#1#2{\expandafter\addtomacro\expandafter#1\expandafter{#2}} + +\long\def\addtotoks#1#2{#1\expandafter{\the#1#2}} + +\long\def\eaddtotoks#1#2{\expandafter\addtotoks\expandafter#1\expandafter{#2}} + +\long\def\swaparg#1#2{#2{#1}} + +\long\def\expsecond#1#2{\expandafter\swaparg\expandafter{#2}{#1}} +\let\exparg\expsecond + +\def\exptwoargs#1#2{\expsecond{\expsecond{#1}{#2}}} + +\def\sgn#1{\ifnum#1<0 -\fi} + +\def\abs#1{\sgn{#1}#1 } + +\def\truncdiv#1#2{% + \exptwoargs\truncdiv@i{\number\numexpr#1\relax}{\number\numexpr#2\relax}% +} +\def\truncdiv@i#1#2{% + \numexpr(2*\sgn{#1}#1-\sgn{#2}#2+1)/(\sgn{#1}2*#2)\relax +} + +\def\ifinside#1[#2,#3]{% + \ifnum\sgn{\dimexpr#1pt-#2pt\relax}\sgn{\dimexpr#1pt-#3pt}1=1 + \expandafter\secondoftwo + \else + \expandafter\firstoftwo + \fi +} + +\def\absval#1{\expandafter\absval@i\expandafter{\number\numexpr#1\relax}} +\def\absval@i#1{\number\ifnum#1<\z@-\fi#1 } + +\edef\saved@catcode{\number\catcode`\:}% sauvegarde du catcode de ":" +\catcode`\:12 % ":" est désormais un caractère non actif normal +\def\hdif{% + \begingroup% ouvrir un groupe semi-simple + \catcode`\:12 % modifier le catcode de ":" + \hdif@i% aller lire les deux arguments +} + +\def\hdif@i#1#2{% lit les 2 arguments + \hdif@ii#1-#2\@nil% et les transmet à la macro à argument délimités +} + +\def\hdif@ii#1:#2:#3-#4:#5:#6\@nil{% + %%%%%% calcul des nombres à afficher %%%%%% + \edef\nb@hrs{\number\numexpr#1-#4\relax}% différence des heures + \edef\nb@min{\number\numexpr#2-#5\relax}% différence des minutes + \edef\nb@sec{\number\numexpr#3-#6\relax}% différence des secondes + \ifnum\nb@sec<\z@ % si la différence des secondes est <0 + \edef\nb@sec{\number\numexpr\nb@sec+60\relax}% ajouter 60 sec + \edef\nb@min{\number\numexpr\nb@min-1\relax}% enlever 1 aux minutes + \fi + \ifnum\nb@min<\z@ % si les minutes sont <0 + \edef\nb@min{\number\numexpr\nb@min+60\relax}% ajouter 60 min + \edef\nb@hrs{\number\numexpr\nb@hrs-1\relax}% enlever 1 aux heures + \fi + %%%%%% affichage du résultat %%%%%% + \let\inter@space\empty% pas d'espace avant un nombre pour l'instant + \ifnum\nb@hrs>\z@ % si les heures sont >0 + \nb@hrs h% afficher les heures et "h" + \let\inter@space\space% espace pour plus tard + \fi + \ifnum\nb@min>\z@ % si les minutes sont >0 + \inter@space% afficher une espace éventuelle + \nb@min min% afficher les minutes et "min" + \let\inter@space\space + \fi + \ifnum\nb@sec>\z@ % si les secondes sont >0 + \inter@space% afficher une espace éventuelle + \nb@sec s% afficher les secondes et "s" + \fi + \endgroup% fermer le groupe ouvert au début +} +\catcode`\:=\saved@catcode\relax% restaure le code de catégorie de ":" + +\long\def\afterfi#1#2\fi{#2\fi#1} + +\long\def\antefi#1\fi{\fi#1} + +\def\for#1=#2to#3\do#4#{% + \edef\temp@increment{\number\numexpr0#4}% lit et normalise l'argument optionnel + \ifnum\temp@increment=\z@% s'il est nul, + \edef\temp@increment{% le redéfinir à -1 (si #3<#2) et 1 sinon + \ifnum\numexpr#3-#2\relax<\z@ -1\else 1\fi + }% \temp@increment vaut donc 1 ou -1 + \fi + \ifnum\numexpr\temp@increment*(#3-#2)\relax<\z@ + \expandafter\gobone% si argument optionnel incompatible, manger le {<code>} + \else + \edef#1{\number\numexpr#2}% initialise la variable + \edef\macro@args{% définit et développe les arguments de la macro + %#1=nom de la macro à définir : + \expandafter\noexpand\csname for@ii@\string#1\endcsname + \ifnum\temp@increment<\z@ <\else >\fi% #2=signe de comparaison + {\temp@increment}% #3=incrément + \noexpand#1% #4=variable + {\number\numexpr#3\relax}% #5=entier max + }% + \antefi + \expandafter\for@i\macro@args + \fi +} + +% #1=nom de la macro récursive de type "\for@ii@<variable>" +% #2=signe de comparaison % #3=incrément +% #4=variable % #5=entier max % #6=code à exécuter +\long\def\for@i#1#2#3#4#5#6{% + \def#1{% dfinit la sous macro récursive + \unless\ifnum#4#2#5\relax% tant que la variable n'a pas dépassé l'entier max + \afterfi{% rendre la récursivité terminale + #6% exécute le code + \edef#4{\number\numexpr#4+#3\relax}% incrémente la variable #1 + #1% recommence + }% + \fi + }% + #1% appelle la sous-macro récursive +} + +\def\exitfor#1{% #1=variable correspondant à la boucle de laquelle on veut sortir + \expandafter\let\csname for@ii@\string#1\endcsname\empty +} + +\def\quark{\quark} + +\long\def\ifempty#1{% + \expandafter\ifx\expandafter\relax\detokenize{#1}\relax + \expandafter\firstoftwo + \else + \expandafter\secondoftwo + \fi} + +\def\reverse#1{% + \ifempty{#1} + {}% s'il n'y a rien à inverse, ne rien faire + {\reverse@i#1\@nil\@nil}% initialisation des réservoirs et appeler \reverse@i +} +\def\reverse@i#1#2\@nil#3\@nil{% #1 est le 1er caractère du réservoir A + \ifempty{#2}% si ce qui reste après ce 1er caractère est vide + {#1#3}% renvoyer #1#3 qui est le résultat final + {\reverse@i#2\@nil#1#3\@nil}% sinon, recommencer en déplaçant #1 + % en 1re position du réservoir B +} +\long\def\ifin#1#2{% + \long\def\ifin@i##1#2##2\@nil{% définit la macro auxiliaire + \ifempty{##2}% si ce qu'il y a derrière le motif est vide + \secondoftwo% aller à "faux" + \firstoftwo% sinon à "vrai" + }% + \ifin@i#1#2\@nil% appel de la macro auxiliaire +} + +\def\ifstart#1#2{% + \def\if@start##1#2##2\@nil{\ifempty{##1}}% + \ifempty{#2}\firstoftwo{\if@start#1\relax#2\@nil}} + +\def\substin#1#2#3{% + \def\substin@i##1{% + \ifempty{##1}% si le code est vide + \relax% ne rien faire -> fin du processus + {\ifin{##1}{#2}% sinon, si le code contient motif1 + {\substin@ii##1\@nil}% appeler la macro à argument délimités + {##1}% sinon, afficher le code + }% + }% + \def\substin@ii##1#2##2\@nil{% + ##1#3% afficher ##1 et #3 (qui est <motif2>) + \substin@i{##2}% et recommencer avec ce qui reste + }% + \substin@i{#1}% +} + +\def\substtocs#1#2#3#4{% + \def\substtocs@i##1{% + \ifempty{##1}% si le code est vide + \relax% ne rien faire -> fin du processus + {\ifin{##1}{#3}% sinon, si le code contient motif1 + {\substtocs@ii##1\@nil}% appeler la macro à argument délimités + {\addtomacro#1{##1}}% sinon, ajouter le code + }% + }% + \def\substtocs@ii##1#3##2\@nil{% + \addtomacro#1{##1#4}% ajouter ##1#4 + \substtocs@i{##2}% et recommencer avec ce qui reste + }% + \let#1=\empty% initialise la macro à vide + \substtocs@i{#2}% +} + +\long\def\cnttimestocs#1#2#3{% #3=macro recevant le résultat + \long\def\cnttimestocs@i##1\@nil##2#2##3\@nil{% + % ##1=nb d'occurrences rencontrées jusqu'alors + % ##2 et ##3=ce qui est avant/après le <motif> + \ifin{##3}{#2}% si le <motif> est dans ce qui reste + {\expandafter\cnttimestocs@i% appeler la macro récursive + \number\numexpr##1+1\relax\@nil% avec une occurrence de plus + ##3\@nil% et ce qui reste + }% + {\edef#3{\number\numexpr##1+1\relax}}% sinon, stocker 1 occurrence de plus dans #3 + }% + \ifin{#1}{#2}% si le <motif> est dans le <code> + {\cnttimestocs@i 0\@nil#1\@nil}% appeler la macro récursive avec 0 occurrence + {\def#3{0}}% sinon, mettre 0 dans #3 +} + +\def\ifcs#1{% + \begingroup + \escapechar=`\@ % prend "@" comme caractère d'échappement + \if% les premiers caractères de + \expandafter\firstto@nil\string#1a\@nil% "#1a" + \expandafter\firstto@nil\string\relax\@nil% et "\relax" sont-ils égaux ? + \endgroup\expandafter\firstoftwo% si oui, fermer le groupe et renvoyer "vrai" + \else% sinon, fermer le groupe et renvoyer "faux" + \endgroup\expandafter\secondoftwo + \fi +} + +\def\endif{\endif}\def\elseif{\elseif} +\def\idto@endif#1\endif{#1} +\def\firstto@endif#1#2\endif{#1} +\def\ifxcase#1#2{% #1=<token> #2=prochain argument + \ifx\elseif#2% si #2 est \elseif + \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + \idto@endif% aller à \idto@endif, sinon : + {\ifx\endif#2% si #2 est \endif + \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {}% ne rien faire, sinon : + {\ifx#1#2% s'il y a égalité + \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + \firstto@endif% aller à \firstto@endif + {\ifxcase@i{#1}}% sinon aller à \ifxcase@i + }% + }% +} +\def\ifxcase@i#1#2{% #1=<nombre> #2=<code> + \ifxcase{#1}% manger le <code> et aller à \ifxcase en transmettant #1 +} + +\newcount\cnt@nest \cnt@nest=0 % définit et initialise le compteur d'imbrication +\def\end@foreach{\end@foreach} +\long\def\save@macro#1#2{\expandafter\let\csname saved@var@\number\cnt@nest#1\endcsname#2} +\long\def\save@macro@i#1/#2{\save@macro{a}#1\save@macro{b}#2} +\long\def\restore@macro#1#2{% + \expandafter\let\expandafter#2\csname saved@var@\number\cnt@nest#1\endcsname +} +\long\def\restore@macro@i#1/#2{\restore@macro{a}#1\restore@macro{b}#2} +\def\defseplist#1{% + \long\def\doforeach##1\in##2##3{% + \global\advance\cnt@nest1 % entrée de boucle : incrémenter le compteur d'imbrication + \ifin{##1}{/}% si ##1 contient "/" + {\save@macro@i##1% sauvegarde les macros + \doforeach@ii% appeler la macro récursive après avoir + {##3}%\csname loop@code@\number\cnt@nest\endcsname% formé la macro contenant le code + ##1% mettre les variables ##1 en 2e position + ##2#1\end@foreach/\end@foreach#1% puis la liste ##2 suivie de ",\end@foreach," + \restore@macro@i##1% une fois sorti de toutes les boucles, restaurer les macros + }% si ##1 ne contient pas "/" + {\save@macro{}##1% sauvegarde la macro + \doforeach@i% appeler la macro récursive + {##3}% mettre en premier le <code> + ##1% puis la variable ##1 en 2e position + ##2#1\end@foreach#1% enfin la liste ##2 suivie de ",\end@foreach," + \restore@macro{}##1% une fois sorti de toutes les boucles, restaurer la macro + }% + \global\advance\cnt@nest-1 % décrémente le compteur d'imbrications + }% + % ##1 = code à exécuter, ##2= variable, ##3=valeur courante + \long\def\doforeach@i##1##2##3#1{% + \def##2{##3}% fait l'assignation à la variable + \global\let\allow@recurse\identity% permet l'appel récursif plus bas + \ifx\end@foreach##2% si la fin est atteinte + \expandafter\gobone\else\expandafter\identity\fi% manger sinon exécuter: + {##1% le code puis + \allow@recurse{\doforeach@i{##1}##2}% recommencer + }% + }% + % ##1 = code à exécuter, ##2/##3= variables, ##4/##5=valeurs courantes + \long\def\doforeach@ii##1##2/##3##4/##5#1{% + \def##2{##4}\def##3{##5}% fait l'assignation des deux variables + \global\let\allow@recurse\identity% permet l'appel récursif plus bas + \ifx\end@foreach##2% si la fin est atteinte + \expandafter\gobone\else\expandafter\identity\fi% manger sinon exécuter: + {##1% le code puis + \allow@recurse{\doforeach@ii{##1}##2/##3}% recommencer + }% + }% + % macro qui, si elle remplace \allow@recurse, annule l'appel récursif + \long\def\forbid@recurse##1\end@foreach#1{}% tout manger jusqu'à "\end@foreach," +} +% macro pour annuler le prochain appel récursif +\def\doforeachexit{\global\let\allow@recurse\forbid@recurse} +\defseplist{,} + +\begingroup% ouvrir un groupe + \edef\temp{\endgroup\def\noexpand\removept##1.##2\string p\string t}% +\temp{#1\ifnum#2>0 .#2\fi}% et le fermer avant de définir \removept + +\def\dimtodec{\expandafter\removept\the} + +\def\FOR#1=#2to#3\do#4#{% + \ifempty{#4} + {\let\FOR@increment\z@} + {\edef\FOR@increment{\the\dimexpr#4pt\relax}}% lit et normalise l'argument optionnel + \ifdim\FOR@increment=\z@% s'il est nul, + \edef\FOR@increment{% le redéfinir à -1pt (si #3<#2) et 1pt sinon + \ifdim\dimexpr#3pt-#2pt\relax<\z@ -1\else 1\fi pt + }% \FOR@increment vaut donc 1 ou -1 + \fi + \ifdim\dimtodec\dimexpr#3pt-#2pt\relax\dimexpr\FOR@increment\relax<\z@ + \expandafter\gobone% si argument optionnel incompatible, manger le {<code>} + \else + \edef#1{\dimtodec\dimexpr#2pt\relax}% initialise la \<macro> + \edef\macro@args{% définit et développe les arguments à passer à \FOR@i + %#1=nom de la macro récursive : + \expandafter\noexpand\csname FOR@ii@\string#1\endcsname + \ifdim\FOR@increment<\z@ <\else >\fi% #2=signe de comparaison + {\FOR@increment}% #3=incrément + \noexpand#1% #4=\<macro> + {\the\dimexpr#3pt\relax}% #5=dimension n2 + }% + \antefi% externalise la ligne ci-dessous de la portée du test + \expandafter\FOR@i\macro@args% appelle \FOR@i avec les arguments définis ci-dessus + \fi +} + +% #1=nom de la macro récursive de type "\FOR@ii@\<macro>" +% #2=signe de comparaison % #3=incrément +% #4=\<macro> % #5=dimension n2 % #6=<code> à exécuter +\long\def\FOR@i#1#2#3#4#5#6{% + \def#1{% dfinit la sous macro récursive + \unless\ifdim#4pt#2#5\relax% tant que la \<macro> variable n'a pas dépassé n2 + \afterfi{% rendre la récursivité terminale + #6% exécute le code + \edef#4{\dimtodec\dimexpr#4pt+#3\relax}% incrémente la \<macro> + #1% recommence + }% + \fi + }% + #1% appelle la sous-macro récursive +}% +\def\exitFOR#1{% #1=\<macro> correspondant à la boucle de laquelle on veut sortir + \defname{FOR@ii@\string#1}{}% +} + +\def\ifexitFOR#1{% envoie vrai si on est prématurément sorti de la boucle de \<macro> #1 + % si la macro récursive est \empty + \expandafter\ifx\csname FOR@ii@\string#1\endcsname\empty + \expandafter\firstoftwo% c'est qu'on est sortir prématurément, renvoyer "vrai" + \else + \expandafter\secondoftwo% sinon, renvoyer "faux" + \fi +} + +\def\decmul#1#2{\dimtodec\dimexpr#1\dimexpr#2pt\relax\relax} + +\def\decdiv#1#2{% divise le décimal #1 par le décimal #2 + \dimtodec\dimexpr 1pt*\dimexpr#1pt\relax/\dimexpr#2pt\relax\relax +} + +\def\convertunit#1#2{% + \dimtodec + \dimexpr + \numexpr + \dimexpr #1 \relax * 65536 / \dimexpr 1#2 \relax + \relax + sp + \relax +} + +\def\vdim#1{\dimexpr\ht#1+\dp#1\relax}% hauteur totale de la boite #1 + +\def\cbox#1{\setbox0\vbox{#1}\lower\dimexpr(\ht0-\dp0)/2\relax\box0 } + +\def\clap#1{\hbox to\z@{\hss#1\hss}} + +\def\ifzerodimbox#1{% #1=registre de boite +% revoie vrai si le registre est vide ou contient une boite vide + \csname% former le nom "\firstoftwo" ou "secondoftwo" + \ifvoid#1first%% si le registre est vide "first" + \else% sinon + \ifnum\wd#1=\z@% si la largeur + \ifnum\ht#1=\z@% la hauteur + \ifnum\dp#1=\z@ first% et la profondeur=0pt, "first" + \else second% dans les autres cas "second" + \fi + \else second% + \fi + \else second% + \fi + \fi + oftwo% compléter avec "oftwo" + \endcsname +} + +\def\ifvoidorempty#1{% teste si le registre de boite #1 est vide ou contient une boite vide + \ifvoid#1\relax + \expandafter\firstoftwo + \else + \begingroup% dans un groupe + \setbox0=% affecter à la boite 0 + \ifhbox#1\hbox\bgroup\unhcopy% un boite horizontale + \else \vbox\bgroup\unvcopy% ou verticale + \fi% dans laquelle on compose + #1\relax% composer #1 en dimensions naturelles + \expandafter\egroup% sauter la fin de la boite + \expandafter% et le \endgroup + \endgroup + \ifnum\lastnodetype<0 % pour tester si le dernier noeud est vide + \expandafter\expandafter\expandafter\firstoftwo + \else + \expandafter\expandafter\expandafter\secondoftwo + \fi + \fi +} + +\def\showdim#1{% + \vrule width0.2pt height 1ex depth 0pt + \vrule width#1 height0.4pt depth 0pt + \vrule width0.2pt height 1ex depth 0pt \relax} + + +\newdimen\frboxrule \frboxrule0.4pt +\newdimen\frboxsep \frboxsep5pt +\def\FRbox#1{% ne pas changer le mode H ou V en cours + \hbox{% mettre à la suite horizontalement + \vrule width\frboxrule% 1) réglure gauche + \vbox{% 2) un empilement vertical comprenant + \hrule height\frboxrule% a) réglure supérieure + \kern\frboxsep% b) espace verticale haute + \hbox{% c) contenu + espaces en mode H + \kern\frboxsep#1\kern\frboxsep + }% + \kern\frboxsep% d) espace verticale basse + \hrule height\frboxrule% e)réglure inférieure + }% + \vrule width\frboxrule% 3) réglure droite + }% +} +\def\frbox#1{% ne pas changer le mode H ou V en cours + \hbox{% enferme dans une \hbox + \vrule width\frboxrule% réglure gauche + \vtop{% + \vbox{% 1er élément de la \vtop + \hrule height\frboxrule% réglure supérieure + \kern\frboxsep% espace haut + \hbox{% + \kern\frboxsep% espace gauche + #1% contenu + \kern\frboxsep% espace droite + }% + }% puis autres éléments de la \vtop, sous la ligne de base + \kern\frboxsep% espace bas + \hrule height\frboxrule% réglure inférieure + }% + \vrule width\frboxrule% réglure droite + }% +} +\def\souligne#1{% + \setbox0=\hbox{#1}% stocke le contenu dans le registre no 0 + \setbox0=\hbox{% puis, dans une \hbox, construit une réglure + \vrule width\wd0 % de la longueur du contenu + depth\dimexpr\dp0 + 1.4pt\relax % dp = profondeur texte + 1.4pt + height\dimexpr-\dp0 - 1pt\relax % ht = -profondeux texte - 1pt + }% + \wd0=0pt \dp0=0pt \ht0=0pt % annule toutes les dimensions + \leavevmode \box0 % affiche la réglure + #1% puis le contenu +} + +\def\Souligne#1{% + \setbox0=\hbox{#1}% + \setbox0=\hbox{\vrule width\wd0 depth1.4pt height-1pt }% + \wd0=0pt \dp0=0pt \ht0=0pt + \leavevmode \box0 #1% +} + +\newdimen\stackwd \stackwd=3em +\catcode`\@11 +\def\stackbox#1{% + \par% termine le paragraphe en cours + \begingroup% dans un groupe semi-simple + \parindent=0pt% pas d'indentation + \parskip=0pt% annuler le \parskip + \setbox0\hbox{Àgjp}% boite pour le strut + \edef\stack@strut{\vrule width\z@ height\the\ht0 depth\the\dp0 }% définit le strut + \stackbox@i#1\\\quark\\% ajoute "\\\quark\\" à la fin et appelle \stackbox@i + \unkern% annule la dernière compensation verticale + \par + \endgroup +} +\def\stackbox@i#1\\{% #1=ligne courante + \def\temp@{#1}% stocke la ligne courante + \unless\ifx\quark\temp@% si ce n'est pas la fin + \hfill % ressort infini de centrage (passe en mode horizontal) + \doforeach\current@item\in{#1}% pour chaque élément dans la ligne courante... + {\frbox{% ...encadrer + \hbox to\stackwd{% une \hbox de largeur \stackwd contenant + \hss% 1) ressort de centrage + \stack@strut% 2) strut de dimension verticale + \current@item%3) l'élement courant + \hss}% 4)ressort de centrage + }% fin de la \fbox + \kern-\frboxrule% revenir en arrière pour superposer les réglures verticales + }% fin de \doforeach + \unkern% annuler la dernière compensation horizontale + \hfill% ressort infini de centrage + \null% fait prendre en compte le dernier ressort + \par% termine le paragraphe + \nobreak% interdit une coupure de page + \nointerlineskip% sinon, ne pas ajouter le ressort interligne + \kern-\frboxrule% superposer les réglures horizontales + \expandafter\stackbox@i% et recommencer + \fi +} + +\def\vlap#1{\vbox to\z@{\vss#1\vss}} +\newdimen\xunit \newdimen\yunit +\newdimen\mainrule \newdimen\subrule +\xunit=1cm \yunit=1cm \mainrule=0.8pt \subrule=0.2pt +\def\grid#1#2#3#4{% #1=nb xunit #2=nb xsubunit #3=nb yunit #4=nb ysubunit + \vbox{% + \offinterlineskip + \edef\total@wd{\the\dimexpr\xunit*#1\relax}% + \edef\sub@unit{\the\dimexpr\yunit/#4\relax}% + \for\iii=1to#3\do + {\ifnum#4>1 + \vbox to\z@{% + \for\jjj=2to#4\do + {\kern\sub@unit + \vlap{\hrule width\total@wd height\subrule}% + }% + \vss + }% + \fi + \vlap{\hrule width\total@wd height\mainrule}% + \kern\yunit + }% + \vlap{\hrule width\total@wd height\mainrule}% + \vbox to\z@{% + \vss + \hbox to\total@wd{% + \edef\total@ht{\the\dimexpr\yunit*#3\relax}% + \edef\sub@unit{\the\dimexpr\xunit/#2\relax}% + \for\iii=1to#1\do + {\ifnum#2>1 + \rlap{% + \for\jjj=2to#2\do + {\kern\sub@unit + \clap{\vrule width\subrule height\total@ht}% + }% + }% + \fi + \clap{\vrule width\dimexpr\mainrule height\total@ht}% + \kern\xunit + }% + \clap{\vrule width\mainrule height\total@ht}% + }% + }% + }% +} + +\def\iffileexists#1#2{% #1=canal de lecture #2=nom du fichier + \openin#1=#2 % + \ifeof#1% le fichier n'existe pas + \closein#1% + \expandafter\secondoftwo% renvoyer faux + \else + \closein#1 + \expandafter\firstoftwo% sinon renvoyer vrai + \fi +} + +\def\xread{% doit être suivie de "<nombre> to \<macro>" + \edef\restoreendlinechar{\endlinechar=\the\endlinechar}% + \endlinechar=-1 % neutralise \endlinechar + \afterassignment\restoreendlinechar% après l'assignation restaurer \endlinechar + \read% attend <nombre> to \<macro> +} + +\def\showfilecontent#1#2{% #1=canal de lecture #2=nom de fichier + \begingroup + \tt% sélectionner la fonte à chasse fixe + \openin#1=#2\relax + \ifeof#1% si la fin du fichier est déjà atteinte, il n'existe pas et + Le fichier n'existe pas% afficher le message + \else% le fichier existe + \def\do##1{\catcode`##1=12 }% + \dospecials% neutraliser tous les tokens spéciaux + \obeyspaces% rendre l'espace actif + \def\magicpar{\let\magicpar=\par}% + \loop + \xread#1 to \currline% lire une ligne + \unless\ifeof#1% si la fin du fichier n'est pas atteinte + \leavevmode\magicpar% former le paragraphe (sauf à la 1er itération) + \currline% afficher la ligne + \repeat% recommencer + \fi + \closein#1\relax% + \endgroup +} + +\def\exactwrite#1#2{% #1=numéro de canal #2=caractère délimiteur + \begingroup + \def\canal@write{#1}% sauvegarde le numéro de canal + \for\xx=0 to 255\do{\catcode\xx=12 }% donne à tous les octets le catcode 12 + \expandafter\exactwrite@i\expandafter{\string#2}% rend #2 de catcode 12 +} + +\def\exactwrite@i#1{% #1=caractère frontière (de catcode 12) + % la macro \exactwrite@ii lit tout jusqu'au caractère #2 et passe + % ce qu'elle a lu à la macro \exactwrite@iii en mettant un \@nil à la fin + \def\exactwrite@ii##1#1{\exactwrite@iii##1\@nil}% + \exactwrite@ii% va lire tout ce qui se trouve jusqu'au prochain #2 +} + +{\catcode`\^^M 12 \gdef\EOL@char{^^M}}% définit le caractère <EOL> de catcode 12 + +\def\exactwrite@iii#1\@nil{% #1 = contenu à écrire + \expsecond{\ifin{#1}}\EOL@char% si #1 contient "retour chariot" + {\write@line#1\@nil}% écrire la première ligne de #1 + {\immediate\write\canal@write{#1}% sinon : dernière ligne atteinte, l'écrire + \endgroup% puis sortir du groupe + }% +} + +% les \expandafter provoquent le 1-développement de \EOL@char : +\expandafter\def\expandafter\write@line\expandafter#\expandafter1\EOL@char#2\@nil{% + \immediate\write\canal@write{#1}% écrit la ligne (ce qui se trouve avant ^^M) + \exactwrite@iii#2\@nil% continue avec ce qui se trouve après ^^M +} + +\def\quark@list{\quark@list}% quark de fin de liste + +\def\finditemtocs#1#2#3{% #1 = \<macro> #2=position #3=macro à définir + \def\finditemtocs@iii##1##2\quark@list,{% renvoyer #1 et manger le reste de la liste + \expandafter\def\expandafter#3\expandafter{\gobone##1}% + }% + \let#3=\empty% + \exparg\finditemtocs@i{#1}{#2}% 1-développe la \<macro> +} +\def\finditemtocs@i#1#2{% #1 = liste #2=position cherchée + \ifnum#2>\z@% ne faire quelque chose que si la position est >0 + \antefi\finditemtocs@ii{1}{#2}\relax#1,\quark@list,% appelle la macro récursive + \fi +} +\def\finditemtocs@ii#1#2#3,{% +% #1=position courante #2=position cherché #3=\relax + élément courant + \expandafter\ifx\expandafter\quark@list\gobone#3% + \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {}% si fin de liste ne rien faire. Sinon, si position bonne + {\ifnum#1=#2 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {\finditemtocs@iii{#3}% renvoyer #3 et manger les éléments restants + }% si la position n'est pas la bonne, recommencer en incrémentant #1 + {\exparg\finditemtocs@ii{\number\numexpr#1+1}{#2}\relax% + }% + }% +} + +\def\insitem#1#2#3{% #1 = macro #2=position cherchée #3=élément à insérer + \let\item@list=\empty + \ifnum#2<1 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + % si position < 1 + {\addtomacro\item@list{#3,}% ajouter l'élement à insérer en premier + \eaddtomacro\item@list#1% puis la liste entière + } + % si la position > 1 + {% définir la macro récursive + \def\insitem@i##1##2,{% ##1 = position courante ##2=\relax + élément courant + \expandafter\ifx\expandafter\quark@list\gobone##2% + \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {\addtomacro\item@list{#3}}% si fin de liste, ajouter l'élément en dernier + {% sinon, si la position cherchée est atteinte + \ifnum##1=#2 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {\addtomacro\item@list{#3,}% ajouter l'élement + \add@remainlist##2,% et ##2 (en supprimant le \relax) et le reste + }% si la position n'est pas atteinte + {\eaddtomacro\item@list{\gobone##2,}% ajouter l'élément + \exparg\insitem@i{\number\numexpr##1+1}\relax% et recommencer + }% + }% + }% + % appel de la macro récursive + \expandafter\insitem@i\expandafter1\expandafter\relax#1,\quark@list,% + }% + \let#1=\item@list% rendre #1 égal au résultat +} + +\def\add@remainlist#1,\quark@list,{% + \eaddtomacro\item@list{\gobone#1}% ajouter #1 ainsi que les autres +} +\def\delitem#1#2{% #1 = macro #2=position cherchée + \ifnum#2>0 % ne faire quelque chose que si la position est >0 + \def\delitem@i##1##2,{% ##1 = position courante ##2=\relax + élément courant + \expandafter\ifx\expandafter\quark@list\gobone##2% + \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {}% si fin de liste, ne rien faire + {% sinon, si la position cherchée est atteinte + \ifnum##1=#2 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {\add@reaminingitems% et ##2 (en supprimant le \relax) et le reste + }% si la position n'est pas la bonne + {\eaddtomacro\item@list{\gobone##2,}% ajouter l'élément + \exparg\delitem@i{\number\numexpr##1+1}\relax% et recommencer + }% + }% + }% + \let\item@list=\empty% initialiser la macro tempporaire + % appel de la macro récursive + \expandafter\delitem@i\expandafter1\expandafter\relax#1,\quark@list,% + \expandafter\remove@lastcomma\item@list\@nil + \let#1=\item@list% rendre #1 égal au résultat + \fi +} + +\def\add@reaminingitems#1\quark@list,{% + \eaddtomacro\item@list{#1}% ajouter tout jusqu'au quark +} +\def\remove@lastcomma#1,\@nil{\def\item@list{#1}} + +\def\runlist#1\with#2{% #1=liste #2=macro + \def\runlist@i##1,##2\@nil{% + \addtomacro\collect@run{#2{##1}}% ajouter "\<macro>{<élément>}"" + \ifempty{##2}% plus d'élément ? + \relax% ne rien faire (donc terminer le processus) + {\runlist@i##2\@nil}% sinon, recommencer avec les éléments restants + }% + \begingroup% fait la collecte dans un groupe + \let\collect@run=\empty% initialiser la macro + \ifcs{#1}% si #1 est une séquence de contrôle + {\expandafter\runlist@i#1,\@nil%% aller à \runlist@i + }% sinon, former la sc + {\expandafter\expandafter\expandafter\runlist@i\csname#1\endcsname,\@nil + }% + \expandafter\endgroup% ferme le groupe et détruit \collect@run + \collect@run% après l'avoir développé ! +} + +\def\ifspacefirst#1{% + \expandafter\ifspacefirst@i\detokenize{#1W} \@nil% "W" se prémunit d'un argument vide +} +\def\ifspacefirst@i#1 #2\@nil{\ifempty{#1}} + +\expandafter\def\expandafter\gobspace\space{} + +\def\removefirstspaces{% + \romannumeral% lance le développement maximal + \removefirstspaces@i% et passe la main à la macro récursive +} + +\def\removefirstspaces@i#1{% + \ifspacefirst{#1}% si #1 commence par un espace + {\expandafter\removefirstspaces@i\expandafter% recommencer + {\gobspace#1}% après avoir supprimé cet espace + } + {\z@#1}% sinon, renvoyer l'argument où \z@ stoppe l'action de \romannumeral +} + +\edef\catcodezero@saved{\number\catcode0 }% stocke le catcode de ^^00 +\catcode0=12 % le modifie à 12 +\def\removelastspaces#1{% + \romannumeral% lance le développement maximal + \removelastspaces@i#1^^00 ^^00\@nil% et passe la main à \removelastspaces@i +} +\def\removelastspaces@i#1 ^^00{% + \removelastspaces@ii#1^^00% +} +\def\removelastspaces@ii#1^^00#2\@nil{% + \ifspacefirst{#2}% si le reliquat commence par un espace + {\removelastspaces@i#1^^00 ^^00\@nil}% recommencer sans passer par \removelastspaces + {\z@#1}% sinon "\z@" stoppe l'action de \romannumeral +} +\catcode0=\catcodezero@saved\relax% restaure le catcode de ^^00 + +\def\removetrailspaces#1{% + \romannumeral% lance le développement maximal + \expandafter\expandafter\expandafter% le pont d'\expandafter + \removelastspaces + \expandafter\expandafter\expandafter% fait agir \removefirstspaces en premier + {% + \expandafter\expandafter\expandafter + \z@% stoppe le développement initié par \romannumeral + \removefirstspaces{#1}% + }% +} + +\newcount\test@cnt +\def\ifinteger#1{% + \ifstart{#1}{-}% si "-" est au début de #1 + {\expandafter\ifinteger\expandafter{\gobone#1}% l'enlever et recommencer + } + {\ifempty{#1}% sinon, si #1 est vide, lire l'argument <faux> + \secondoftwo% lire l'argument <faux> + {\afterassignment\after@number% sinon, après l'assignation, aller à \after@number + \test@cnt=0#1\relax% faire l'assignation (\relax termine le nombre et n'est pas mangé) + }% + }% +} +\def\after@number#1\relax{% #1 est ce qui reste après l'assignation + \ifempty{#1}% teste si #1 est vide et lit l'argument <vrai> ou <faux> qui suit +} + +\newif\iftestspace \testspacefalse + +\def\deftok#1#2{\let#1= #2\empty} + +\def\ifnexttok#1#2#3{% #1=token #2=code vrai #3=code faux + \let\test@tok= #1% stocke le token à tester + \def\true@code{#2}\def\false@code{#3}% et les codes à exécuter + \iftestspace \def\ifnexttok@i{\futurelet\nxttok\ifnexttok@ii}% + \else \def\ifnexttok@i{\futurelet\nxttok\ifnexttok@iii}% + \fi% après avoir défini la macro récursive selon le booléen + \ifnexttok@i% l'exécuter +} + +\def\ifnexttok@ii{% macro qui teste aussi les espaces + \ifx\nxttok\test@tok \expandafter\true@code% exécuter le code vrai + \else \expandafter\false@code% sinon code faux + \fi +} + +\def\ifnexttok@iii{% + \ifx\nxttok\sptoken% si le prochain token est un espace + \def\donext{% + \afterassignment\ifnexttok@i% aller "sentir" le token d'après + \let\nxttok= }% après avoir absorbé l'espace + \else \let\donext\ifnexttok@ii% sinon, faire le test + \fi + \donext% faire l'action décidée ci-dessus +} + +\def\ifstarred#1{\ifnexttok*{\firstoftwo{#1}}} + +\def\parsestop{\parsestop}% définit le quark se trouvant en fin de code +\newtoks\code@toks% alloue le registre contenant le code lu +\def\parseadd#1{\code@toks\expandafter{\the\code@toks#1}} +\newif\ifparse@group +\def\parse{% + \code@toks{}% initialise le collecteur de tokens + \ifstarred + {\parse@grouptrue + \ifnexttok{ }% si un espace suit l'étoile + {\afterassignment\parse@i \let\nxttok= }% le manger et aller à \parse@i + {\parse@i}% sinon, aller à \parse@i + } + {\parse@groupfalse + \parse@i + }% +} +\def\parse@i{\futurelet\nxttok\parse@ii}% lit le prochain token et va à \parse@ii +\def\parse@ii{% + \ifx\nxttok\parsestop% si la fin va être atteinte, aller à \parsestop@i + \let\next@action\parsestop@i + \else + \ifx\nxttok\@sptoken% si un espace va être lu, aller à \read@space + \let\next@action\read@space + \else + \ifx\nxttok\bgroup% si une accolade ouvrante va être lue + \let\next@action\read@bracearg% aller à \read@bracearg + \else + \let\next@action\testtoken% dans les autres cas, aller à \testtoken + \fi + \fi + \fi + \next@action% faire l'action décidée ci-dessus +} +\def\parsestop@i{% la fin est atteinte + \expandafter\the\expandafter\code@toks% afficher le registre de tokens + \gobone% après avoir mangé \parsestop +} +\expandafter\def\expandafter\read@space\space{% \read@space mange un espace dans le code + \testtoken{ }% et va à \testtoken +} +\def\read@bracearg{% + \read@bracearg@i\relax% ajoute un \relax avant de passer la main à \read@bracearg@i +} +\def\read@bracearg@i#1\parsestop{% l'argument tout jusqu'à \parsestop + \expsecond\ifbracefirst{\gobone#1}% retire le \relax et teste si #1 commence par "{" + {\expandafter\read@bracearg@ii\gobone#1\parsestop}% lire l'argument entre accolades + {\expandafter\testtoken\gobone#1\parsestop}% sinon, tester le token +} +\def\read@bracearg@ii#1{% l'argument entre accolades est lu + \ifparse@group\expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {\begingroup% ouvre un groupe pour parser l'intérieur de l'accolade + \def\parsestop@i{% redéfinir localement \parsestop@i pour + \expandafter% retarde \endgroup + \endgroup% pour ajouter le contenu local de \code@toks entre accolades + \expandafter% au contenu de ce même registre avant le groupe + \parseadd + \expandafter + {\expandafter{\the\code@toks}}% + \expandafter\parse@i% puis va lire le token suivant + \gobone% après avoir mangé le \parsestop + }% + \parse*#1\parsestop% <- le \parsestop@i fermera le groupe semi simple + } + {\parseadd{{#1}}% macro non étoilée, on ajoute #1 tel quel entre accolades + \parse@i% puis va lire le token suivant + }% +} +\def\testtoken#1{% macro qui teste le token + \parseadd{#1}% ici, ne rien faire à part ajouter le token + \parse@i% aller lire le token suivant +} +\def\ifbracefirst#1{% teste si #1 commence par un token de catcode 1 + \ifspacefirst{#1}% si #1 commence par un espace + {\secondoftwo}% renvoyer faux + {\ifnum + \catcode + \expandafter\expandafter\expandafter + `% + \expandafter + \firstto@nil\detokenize{#1W}\@nil=1 + \expandafter\firstoftwo + \else + \expandafter\secondoftwo + \fi + }% +} + +\def\grab@first#1#2{% + \ifx#1\empty\expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {\let#2\empty% si #1 est vide, ne rien faire et assigner <vide> à #2 + }% si #1 n'est pas vide + {\def\arg@b{#2}% stocke la macro #2 dans \arg@b + \exparg\ifbracefirst#1% si le 1er token de #1 est "{" + {\expandafter\grab@arg#1\@nil#1% aller lire l'argument avec \grab@arg + } + {% sinon, développer #1 avant de le regarder avec \futurelet : + \expandafter\futurelet\expandafter\nxttok\expandafter\test@nxttok#1\@nil#1% + % puis aller à \test@nxttok + }% + }% +} +\def\test@nxttok{% si le premier token de l'arg #1 de \grab@first est + \ifx\nxttok\sptoken% un espace + \expandafter\grab@spc% aller le lire avec \grab@spc + \else + \expandafter\grab@tok% sinon, lire le token avec \grab@tok + \fi +} +\def\grab@arg#1{% assigne l'argument de \grab@first (mis entre accolades) + \expandafter\def\arg@b{{#1}}% à #2 + \assign@tonil\relax% puis, assigne le reste à #1 de \grab@first +} +\expandafter\def\expandafter\grab@spc\space{% + \expandafter\def\arg@b{ }% assigne un espace à #2 de \grab@first + \assign@tonil\relax% puis, assigne le reste à #1 de \grab@first +} +\def\grab@tok#1{%% assigne le premier token de l'arg #1 de \grab@first + \expandafter\def\arg@b{#1}% à la macro #2 de \grab@first + \assign@tonil\relax% puis, assigne le reste à #1 de \grab@first +} +% assigne tout ce qui reste à lire (moins le "\relax") à la macro +% #1 de \grab@first +\def\assign@tonil#1\@nil#2{\expsecond{\def#2}{\gobone#1}} + +\def\ifstartwith#1#2{% + \def\startwith@code{#1}\def\startwith@pattern{#2}% + \ifempty{#2} + \firstoftwo% renvoyer vrai si #2 est vide + {\ifempty{#1} + \secondoftwo% renvoyer faux si #1 est vide et pas #2 + \ifstartwith@i% dans les autres cas, aller à \ifstartwith@i + }% +} + +\def\ifstartwith@i{% + \grab@first\startwith@code\first@code% extrait le premier "argument" de <code> + \grab@first\startwith@pattern\first@pattern% et celui de <motif> + \ifx\first@code\first@pattern% s'il sont égaux + \expandafter\ifempty\expandafter{\startwith@pattern} + {\expandafter\firstoftwo}% et que <motif> ne contient plus rien => vrai + {\expandafter\ifempty\expandafter{\startwith@code} + {\expandafter\secondoftwo}% si <code> ne contient plus rien => faux + {\expandafter\ifstartwith@i}% sinon poursuivre les tests + }% + \else% s'ils ne sont pas égaux + \expandafter\secondoftwo% renvoyer faux + \fi +} + +\newif\ifin@group +\def\ifcontain{% + \ifstarred + {\in@groupfalse\ifcontain@i\ifcontain@star}% + {\ifcontain@i\ifcontain@nostar}% +} + +\def\ifcontain@i#1#2#3{% #1 = macro à appeler selon étoile ou pas. #2 = code. #3 = motif + \def\main@arg{#2}\def\pattern@arg{#3}% + \ifempty{#3}% + \firstoftwo + {\ifempty{#2} + \secondoftwo + #1% aller à \ifcontain@star ou \ifcontain@nostar + }% +} + +\def\ifcontain@nostar{% + \exptwoargs\ifstartwith\main@arg\pattern@arg + \firstoftwo% si motif est au début de code => vrai + {\expandafter\ifempty\expandafter{\main@arg} + \secondoftwo% sinon, si code est vide => faux + {\grab@first\main@arg\aux@arg% autrement, manger le 1er "argument" de code + \ifcontain@nostar% et recommencer + }% + }% +} + +\def\ifcontain@star{% + \expandafter\ifbracefirst\expandafter{\main@arg}% si code commence par "{" + {\grab@first\main@arg\aux@arg% enlever {<sous code>} de main@arg + \begingroup% ouvrir un groupe + \in@grouptrue% mettre le booléen à vrai + \expandafter\assign@main@arg\aux@arg\@nil% assigner "sous code" à \main@arg + \ifcontain@star% et recommencer avec ce nouveau \main@arg + }% si code ne commence pas par "{" + {\exptwoargs\ifstartwith\main@arg\pattern@arg% si motif est au début de code + \return@true% renvoyer vrai + {\expandafter\ifempty\expandafter{\main@arg}% si code est vide + {\ifin@group% et que l'on est dans un groupe + \endgroup \expandafter\ifcontain@star% en sortir et recommencer + \else% si on n'est pas dans un groupe, le code a été parcouru + \expandafter\secondoftwo% sans trouver <motif> => renvoyer faux + \fi + }% si code n'est pas vide + {\grab@first\main@arg\arg@code% manger le 1er "argument" de code + \ifcontain@star% et recommencer + }% + }% + }% +} + +\def\return@true{% + \ifin@group% tant qu'on est dans un groupe + \endgroup \expandafter\return@true% en sortir et recommencer + \else + \expandafter\firstoftwo% sinon, renvoyer vrai + \fi +} + +\def\forcemath#1{% compose #1 en mode math, quel que soit le mode en cours + \ifmmode\expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {#1}{$#1$}% +} + +\newcount\macro@cnt% numéro à mettre dans le nom des sous macros +\newcount\arg@cnt% compte le nombre d'arguments +\newtoks\param@text% texte de paramètre des macros sous forme #x et/ou [#x] +\newtoks\arg@text% arguments sous forme {#x} et/ou [#x] + +\def\newmacro#1{% + % stocke le nom de la macro et éventuellement "@[<chiffre romain>]" + \def\macro@name##1{\expandafter\gobone\string#1\ifnum##1>0 @[\romannumeral##1]\fi}% + \macro@cnt=0 \arg@cnt=0 % initialise les compteurs + \param@text{}\arg@text{}% vide les registres de texte de paramètre et d'argument + \newmacro@i% va voir le prochain token +} + +\def\newmacro@i{\futurelet\nxttok\newmacro@ii}% met le prochain token dans \nxttok... +% ...puis va à la macro : +\def\newmacro@ii{% + \ifx\nxttok[% si le prochain token est un crochet + \let\donext\newmacro@optarg% aller à \newmacro@optarg + \else + \ifx\nxttok\bgroup% si c'est un accolade ouvrante + % le texte de paramètre est fini et il faut définir la macro + \def\donext{% + \expandafter\def + \csname\macro@name\macro@cnt\expandafter\endcsname + \the\param@text}% <- code juste après non encore lu + \else% sinon, c'est donc un chiffre + \let\donext\newmacro@arg% aller à \newmacro@arg + \fi + \fi + \donext% faire l'action décidée ci-dessus +} + +\def\newmacro@optarg[#1]{% lit la valeur par défaut de l'argument optionnel + % définit la macro \<nom>@<nbre> qui lit tous les arguments (optionnels ou pas) jusqu'alors définis + % à l'aide de \param@text. Puis, elle testera si le prochain token est un crochet + \expandafter\edef\csname\macro@name\macro@cnt\expandafter\endcsname\the\param@text{% + \noexpand\ifnexttok[% + % si oui : la macro \<nom>@<nbr+1> le lira + {\expandafter\noexpand\csname\macro@name{\numexpr\macro@cnt+1}\expandafter\endcsname + \the\arg@text}% + % si non : transmettre à \<nom>@<nbr+1> l'argument optionnel par défaut lu + {\expandafter\noexpand\csname\macro@name{\numexpr\macro@cnt+1}\expandafter\endcsname + \the\arg@text[\unexpanded{#1}]}% + }% + \advance\arg@cnt 1 % incrémenter le numéro d'argument + % pour ajouter "[#<x>]" à \param@text et à \arg@text + \eaddtotoks\param@text{\expandafter[\expandafter##\number\arg@cnt]}% + \eaddtotoks\arg@text{\expandafter[\expandafter##\number\arg@cnt]}% + \advance\macro@cnt 1 % incrémenter le numéro de nom de macro + \newmacro@i% va voir le token suivant +} + +\def\newmacro@arg#1{% #1=nb arguments obligatoires à ajouter + % boucle qui ajoute "#<x>#<x+1>etc" dans \param@text + % et "{#<x>}{#<x+1>}etc" dans \arg@text + \ifnum#1>0 % tant qu'on n'a pas ajouté le nombre de #x nécessaire + \advance\arg@cnt 1 % incrémenter le numéro d'argument + % pour ajouter #x à \param@text et {#x} à \arg@text + \eaddtotoks\param@text{\expandafter##\number\arg@cnt}% + \eaddtotoks\arg@text{\expandafter{\expandafter##\number\arg@cnt}}% + \expandafter\newmacro@arg\expandafter{\number\numexpr#1-1\expandafter}% reboucler + \else% après avoir rajouté e qu'il fallait à \param@text et à \arg@text + \expandafter\newmacro@i% lire le token suivant + \fi +} + +% encadrement avec les réglures où l'on veut +\newmacro\framebox[ULRD]1{% #1 = ULRD (Up, Down, Right, Left) +% ne pas changer le mode H ou V en cours + \hbox{% enferme dans une \hbox + \uppercase{\ifin{#1}L}{\vrule width\frboxrule}{}% réglure gauche + \vtop{% + \vbox{% 1er élément de la \vtop + \uppercase{\ifin{#1}U}{% si la réglure sup doit être tracée + \hrule height\frboxrule% réglure supérieure + \kern\frboxsep% espace haut + } + {}% + \hbox{% + \uppercase{\ifin{#1}L}{\kern\frboxsep}{}% espace gauche + #2% contenu + \uppercase{\ifin{#1}R}{\kern\frboxsep}{}% espace droite + }% + }% puis autres éléments de la \vtop, sous la ligne de base + \uppercase{\ifin{#1}D}{% + \kern\frboxsep% espace bas + \hrule height\frboxrule% réglure inférieure + }% + {}% + }% + \uppercase{\ifin{#1}R}{\vrule width\frboxrule}{}% réglure droite + }% +} + +\def\retokenize#1{% + \immediate\openout\wtest=retokenize.tex % ouvre le fichier + \immediate\write\wtest{\unexpanded{#1}}% y écrit l'argument + \immediate\closeout\wtest% ferme le fichier + \input retokenize.tex % lit le fichier selon les catcodes en vigueur + \unskip% mange l'espace précédemment ajouté qui provient de la fin du fichier +} + +\newtoks\alter@toks% collecteur de tokens + +\def\alter#1#2{% #1= délimiteur #2 = macro altérée + \let\alter@macro#2% sauvegarde la macro + \edef\alter@restorecatcode{% restaurera le catcode de #1 + \catcode`\noexpand#1=\the\catcode`#1 }% + \edef\alter@tmp{\let\noexpand\alter@markertoks= \string#1}% + \alter@tmp% et sauvegarder le délimiteur après avoir mis son catcode à 12 + \edef\alter@tmp{\def\noexpand\alter@readlitterate@i\string#1####1\string#1}% + % développe les \string#1 pour que les arguments délimités aient + % des délimiteurs de catcode 12 + \alter@tmp{% <- comme si on écrivait "\def\alter@readlitterate@i#1##1#1" + \endgroup% après avoir lu ##1 (tokens rendus inoffensifs), fermer le groupe + \addtotoks\alter@toks{{\tt##1}}% ajouter ces tokens + \alter@i% et aller lire le prochain token + }% + \alter@toks{}% initialise le collecteur de tokens + \afterassignment\alter@i% aller lire le premier token après avoir + \let\alter@tmptok= % mangé l'accolade ouvrante de l'argument qui suit +} + +\def\alter@i{% lit le prochain token et va à \alter@ii + \futurelet\alter@nxttok\alter@ii} + +\def\alter@ii{% + % teste le token qui doit être lu (car \futurelet ne l'a pas mangé) + \ifx\alter@nxttok\egroup% si la fin va être atteinte + \let\alter@next\alter@stop% aller à \alterstop@i + \else + \ifx\alter@nxttok\@sptoken% si un espace va être lu + \let\alter@next\alter@readspc% aller à \alter@readspc + \else + \ifx\alter@nxttok\bgroup% si une accolade ouvrante av être lue + \let\alter@next\alter@readarg% aller à \alter@readarg + \else + \ifx\alter@nxttok\alter@markertoks% si le délimiteur va être lu + \let\alter@next\alter@readlitterate% aller à \alter@readlitterate + \else + \let\alter@next\alter@readtok% dans les autres cas, aller à \alter@readtok + \fi + \fi + \fi + \fi + \alter@next% faire l'action décidée ci-dessus +} + +\def\alter@readlitterate{% + % le prochain token est le délimiteur + \begingroup% ouvrir un groupe + \for\alter@tmp=0to255\do{\catcode\alter@tmp=12 }% + % mettre tous les catcodes à 12 + \defactive{ }{\ }% sauf l'espace + \doforeach\alter@tmp\in{<,>,-,`,{,},'}% pour chaque motif de ligature + {\unless\if\alter@tmp\alter@markertoks% s'il est différent du délimiteur + % le définir pour éviter la ligature + \expandafter\alter@defligchar\alter@tmp + \fi + }% + \alter@readlitterate@i% puis aller à \alter@readlitterate@i... + % ...qui a été définie dans \alter +} + +\def\alter@defligchar#1{% définit le caractère pour ne pas provoquer de ligature + \defactive#1{\string#1{}}% +} + +\expandafter\def\expandafter\alter@readspc\space{% \alter@readspc mange un espace dans le code + \addtotoks\alter@toks{ }% ajoute l'espace + \alter@i% puis lire le token suivant +} + +\def\alter@readarg{% + % le token qui suit est "{" + \begingroup% ouvrir un groupe + \def\alterstop@ii{% et modifier localement la macro appelée à la toute fin, + % après que l'accolade fermante ait été mangée (par \alterstop@i) + \expandafter\endgroup% retarder la fermeture de groupe ouvert ci-dessus + \expandafter\addtotoks\expandafter\alter@toks\expandafter + {\expandafter{\the\alter@toks}}% + % pour ajouter hors du groupe ce qui a été collecté à l'intérieur, + % le tout mis entre accolades + \alter@i% puis, lire le token suivant + }% + \alter@toks{}% au début du groupe, initialiser le collecteur + \afterassignment\alter@i% aller lire le prochain token après + \let\alter@tmptok= % avoir mangé l'accolade ouvrante +} + +\def\alter@readtok#1{% + % le prochain token n'est pas un token demandant une action spéciale + \addtotoks\alter@toks{#1}% l'ajouter au collecteur + \alter@i% et aller lire le token suivant +} + +\def\alter@stop{% + % le token à lire est "}" + \afterassignment\alterstop@ii% aller à \alterstop@ii après + \let\alter@tmptok= % avoir mangé l'accolade fermante +} + +\def\alterstop@ii{% + % donner à la macro #2 de \alter tout ce qui a été récolté + \expandafter\alter@macro\expandafter{\the\alter@toks}% + \alter@restorecatcode% puis restaure le catcode du délimiteur +} + +\newdimen\pixelsize +\newdimen\pixelsep +\pixelsize=.9pt \pixelsep=0pt +\def\pixel{\vrule height\pixelsize width\pixelsize} +\def\blankpixel{\vrule height\pixelsize width0pt \vrule height0pt width\pixelsize} +\def\vblankpixel{\vrule height\pixelsize width0pt} +\def\gap{\kern\pixelsep} + +\newskip\letter@skip + +\begingroup% dans ce groupe : +\expandafter\gdef\csname impact@" "\endcsname{\hskip4\pixelsize plus0.5\pixelsize minus0.5\pixelsize\relax}% +\catcode`\^^M=13\relax% le retour à la ligne est actif +\edef^^M{\string,}% et se développe en une virgule (de catcode 12) +\catcode`\ =12\relax% l'espace devient un "caractère autre" +\global\deftok\otherspc{ }% définit un espace de catcode 12 +\gdef\impact@alphabet{ +a/ +*** + * + *** +* * +****, +a`/ +* + * + +*** + * + *** +* * +****, +b/ +* +* +*** +* * +* * +* * +***, +c/ + *** +* +* +* + ***, +d/ + * + * + *** +* * +* * +* * + ***, +e/ + ** +* * +*** +* + ***, +e'/ + * + * + + ** +* * +*** +* + ***, +e^/ + * + * * + + ** +* * +*** +* + ***, +e`/ + * + * + + ** +* * +*** +* + ***, +f/ + ** +* +*** +* +* +* +*, +g/ + *** +* * +* * +* * + ***_ + * + **, +h/ +* +* +* +*** +* * +* * +* * +* *, +i/ +* + +* +* +* +* +*, +j/ + * + + * + * + * + * + *_ + * +**, +k/ +* +* +* * +* * +** +* * +* *, +l/ +* +* +* +* +* +* + *, +m/ +** * +* * * +* * * +* * * +* * *, +n/ +*** +* * +* * +* * +* *, +o/ + ** +* * +* * +* * + **, +o^/ + * + * * + + ** +* * +* * +* * + **, +p/ +*** +* * +* * +* * +***_ +* +*, +q/ + *** +* * +* * +* * + ***_ + * + *, +r/ +* ** +** +* +* +*, +s/ + *** +* + ** + * +***, +t/ +* +* +** +* +* +* + **, +u/ +* * +* * +* * +* * + ***, +u`/ + * + * + +* * +* * +* * +* * + ***, +v/ +* * +* * +* * + * * + *, +w/ +* * +* * +* * * +* * * + * *, +x/ +* * + * * + * + * * +* *, +y/ +* * +* * + * * + ** + *_ + * + **, +z/ +**** + * + * +* +****, +TEX/ +***** * * + * * * + * * * + * ***** * + * * * * + * * * * + * *** * *_ + * + * + *****, +A/ + *** +* * +* * +* * +***** +* * +* *, +B/ +*** +* * +* * +**** +* * +* * +****, +C/ + **** +* +* +* +* +* + ****, +D/ +**** +* * +* * +* * +* * +* * +****, +E/ +***** +* +* +*** +* +* +*****, +F/ +***** +* +* +*** +* +* +*, +G/ + *** +* * +* +* ** +* * +* * + ***, +H/ +* * +* * +* * +***** +* * +* * +* *, +I/ +* +* +* +* +* +* +*, +J/ + * + * + * + * + * +* * + **, +K/ +* * +* * +* * +** +* * +* * +* *, +L/ +* +* +* +* +* +* +****, +M/ +* * +** ** +* * * +* * * +* * +* * +* *, +N/ +* * +** * +** * +* * * +* ** +* ** +* *, +O/ + *** +* * +* * +* * +* * +* * + ***, +P/ +**** +* * +* * +**** +* +* +*, +Q/ + *** +* * +* * +* * +* * * +* ** + ***, +R/ +**** +* * +* * +**** +* * +* * +* *, +S/ + *** +* * + * + * + * +* * + ***, +T/ +***** + * + * + * + * + * + *, +U/ +* * +* * +* * +* * +* * +* * + ***, +V/ +* * +* * +* * +* * +* * + * * + *, +W/ +* * +* * +* * +* * +* * * +** ** +* *, +X/ +* * +* * + * * + * + * * +* * +* *, +Y/ +* * +* * + * * + * + * + * + *, +Z/ +***** + * + * + * + * +* +*****, +?/ + *** +* * + * + * + * + + *, +!/ +* +* +* +* +* + +*, +'/ + * +* + + + +, +./ +*, +{,}/ + *_ +*, +1/ + * + ** +* * + * + * + * + *, +2/ + *** +* * + * + * + * + * +*****, +3/ + *** +* * + * + ** + * +* * + ***, +4/ + * + ** + * * +* * +***** + * + *, +5/ +***** +* +**** + * + * + * +****, +6/ + *** +* +* +**** +* * +* * + ***, +7/ +***** + * + * + * + * + * + *, +8/ + *** +* * +* * + *** +* * +* * + ***, +9/ + *** +* * +* * + **** + * + * + ***, +0/ + *** +* * +* * +* * * +* * +* * + ***, +@/ + ** + * * +* ** +* * * +* * + * * + ***, +error/ +* * * + * * +* * * + * * +* * * + * * +* * *}% +\endgroup% + +\def\makecar#1#2{% #1=nom recevant le code final #2=macro contenant le dessin + \let\pixabove\empty \let\pixbelow\empty \let\pix@line\empty% initialise à vide + \exparg\ifin{#2}_% si le code contient _ + {\expandafter\makecar@iii#2\@nil}% aller à \makecar@iii + {\exparg\makecar@i{#2}}% sinon, à \makecar@i + \edef#1{% définit la macro #1 comme + \vtop{% une \vtop contenant : + \unexpanded{\offinterlineskip\lineskip\pixelsep}% réglage d'espace inter ligne + \vbox{\unexpanded\expandafter{\pixabove}}% \vbox des pixels au-dessus + % de la ligne de base + \unless\ifx\pixbelow\empty% s'il y a des pixels au-dessous de la baseline + \unexpanded\expandafter{\pixbelow}% les ajouter dans la \vtop + \fi + }% + }% +} + +\def\makecar@i#1{% #1 = dessin de la lettre avec les caractères "," "*" et " " + \doforeach\current@line\in{#1}% pour chaque ligne dans #1 : + {\ifx\empty\current@line% si la ligne est vide + \addtomacro\pixabove{\hbox{\vblankpixel}}% ajouter une fausse ligne + \else% sinon + \let\pix@line\empty% initialiser le code de la ligne à vide + \expandafter\makecar@ii\current@line\quark% et la construire + \fi + }% +} + +\def\makecar@ii#1{% #1=caractère de dessin de la ligne en cours + \ifxcase#1% si le caractère est + * {\addtomacro\pix@line\pixel}% + \otherspc{\addtomacro\pix@line\blankpixel}% + \endif + \ifx#1\quark% si la fin est atteinte + \addtomacro\pix@line\unkern% annuler le dernier espace interpixel + \eaddtomacro\pixabove{% et encapsuler \pix@line dans une \hbox + \expandafter\hbox\expandafter{\pix@line}}% + \else% si la fin n'est pas atteinte, ajouter l'espace interpixel + \addtomacro\pix@line\gap% + \expandafter\makecar@ii% recommencer avec le caractère suivant + \fi +} + +\def\makecar@iii#1_,#2\@nil{% + \makecar@i{#2}% construit la partie au-dessous de la baseline + \let\pixbelow\pixabove% et affecte le code à \pixbelow + \let\pixabove\empty \let\pix@line\empty% ré-initialise + \makecar@i{#1}% construit la partie au-dessus de la baseline +} + +% On parcourt le texte de remplacement de \impact@alphabet +\edef\saved@crcatcode{\catcode13=\the\catcode13\relax}% +\catcode`\^^M=13\relax% le retour à la ligne est actif +\edef^^M{\string,}% et se développe en une virgule (de catcode 12) +\expsecond{\doforeach\letter@name/\letter@code\in}\impact@alphabet% + {\edef\letter@name{\letter@name}% développe la lettre (^^M devient ",") + \edef\letter@code{\letter@code}% développe le code (^^M devient ",") + \exparg\ifstart\letter@name,% si la lettre commence par "," + {\edef\letter@name{\expandafter\gobone\letter@name}}% la retirer + {}% + \exparg\ifstart\letter@code,% si le code commence par "," + {\edef\letter@code{\expandafter\gobone\letter@code}}% la retirer + {}% + \expandafter\makecar\csname impact@"\letter@name"\endcsname\letter@code% +}% +\saved@crcatcode% redonne le catcode de ^^M +\def\end@process{\end@process}% + +\def\impactend{\endgroup} + +\newmacro\impact[0.2ex][0pt]{% + \begingroup + \pixelsize#1 \pixelsep#2 + \letter@skip=#1 plus.1pt minus.1pt + \catcode`\!12 \catcode`\?12 + \impact@i +} + +\def\impact@i{\futurelet\nxtletter\impact@ii} + +\def\impact@ii{% + \ifx\nxtletter\impactend + \let\next\unskip + \else + \leavevmode + \ifx\nxtletter\sptoken + \let\next\impact@spc + \else + \let\next\impact@arg + \fi + \fi + \next +} + +\expandafter\def\expandafter\impact@spc\space{% + \csname impact@" "\endcsname + \impact@i +} + +\def\impact@arg#1{% + \ifcsname impact@"#1"\endcsname + \csname impact@"#1"\endcsname + \else + \csname impact@"error"\endcsname + \fi + \hskip\letter@skip + \impact@i +} + +\newdimen\maingraddim \maingraddim=4pt +\newdimen\maingradwd \maingradwd=0.5pt +\newdimen\subgraddim \subgraddim=2.5pt +\newdimen\subgradwd \subgradwd=0.2pt +\newdimen\axiswd \axiswd=0.5pt +\newdimen\plotincrement \plotincrement=0.1pt +\newdimen\tmpdim + +\def\maingradx#1{% + \lower1.5ex\clap{$\scriptscriptstyle#1$}% afficher l'argument au dessous + \clap{\vrule height\maingraddim width\maingradwd depth0pt }% et la réglure +} + +\def\subgradx{\clap{\vrule height\subgraddim width\subgradwd depth0pt }} + +% #1= dim entre 2 grad principales #2=nb départ #3=incrément #4=nb arrivée #4=nb intervalles secondaires +\newmacro\xaxis[1cm]1[1]1[4]{% + \hbox{% tout mettre dans une \hbox + \setbox0=\hbox{% stocke dans une \hbox les grad secondaires entre 2 unités + \edef\dimsubgrad{\the\dimexpr#1/#5\relax}% dimension entre 2 subdivisions + \for\xx=1 to #5-1 \do{% insérer #5-1 fois + \kern\dimsubgrad% une espace secondaire + \subgradx% une graduation secondaire + }% + }% + \rlap{% en débordement à droite : + \FOR\xx = #2 to #4 \do #3{% pour chaque graduation principale + \maingradx{\xx}% imprimer l'abscisse + \ifdim\xx pt<#4pt % et en débordement à droite, + \rlap{\copy0 }% les réglures secondaires, sauf pour la dernière + \fi + \kern#1\relax% se déplacer vers la droite + }% + }% + \vrule% tracer l'axe des abscisses + height\axiswd% d'epaisseur \axiswd, de longueur #1*(#4-#2)/#3 + width\dimexpr#1*\decdiv{\dimtodec\dimexpr#4pt-#2pt\relax}{#3}\relax + depth 0pt\relax % et de profondeur nulle + }% +} + +\def\maingrady#1{% affiche... + \vlap{\llap{$\scriptscriptstyle#1$\kern2pt }}% l'ordonnée... + \vbox to0pt{\vss\hrule height\maingradwd width\maingraddim depth0pt }% et la réglure +} + +% affiche une subdiv +\def\subgrady{\vlap{\hrule height\subgradwd width\subgraddim depth0pt }} +% #1= dim entre 2 grad principales #2=abscisse départ #3=incrément +% #4=abscisse arrivée #5=nb intervalles secondaires +\newmacro\yaxis[1cm]1[1]1[4]{% + \vbox{% + \offinterlineskip% désactiver le ressort interligne + \setbox0=\vbox{% stocke dans une \hbox les grad secondaires entre 2 unités + \edef\dimsubgrad{\the\dimexpr#1/#5\relax}% dimension entre 2 subdivisions + \for\xx=1 to #5-1 \do{% insérer #5-1 fois + \kern\dimsubgrad% une espace secondaire + \subgrady% une graduation secondaire + }% + }% + \edef\dimsubgrad{\the\dimexpr#1/#5\relax}% distance entre 2 subdivisions + \vbox to 0pt{% en débordement vers le bas + \FOR\xx = #4to#2\do-#3{% + \maingrady{\xx}% imprimer l'abscisse + \ifdim\xx pt>#2pt % et en débordement à droite, + \vbox to 0pt{\copy0 \vss}% les réglures secondaires, sauf pour la dernière + \fi + \kern#1\relax% se déplacer vers la droite + }% + \vss% assure le débordement vers le bas + }% + \clap{\vrule% tracer l'axe des abscisses + width\axiswd% d'épaisseur \axiwd, et de hauteur (#4-#2)/#3*#1 + height\decdiv{\dimtodec\dimexpr(#4pt-#2pt)\relax}{#3}\dimexpr#1\relax + depth 0pt\relax % profondeur nulle + } + }% +} + +\newdimen\xunit \xunit=1cm +\newdimen\yunit \yunit=1cm +\newmacro\graphzone1[1]1[4]1[1]1[4]{% + \quitvmode + \begingroup + \def\graphxmin{#1}\def\graphxmax{#3}% + \def\graphymin{#5}\def\graphymax{#7}% + \def\xincrement{#2}\def\yincrement{#6}% + \setbox0\hbox{\yaxis[\yunit]{#5}[#6]{#7}[#8]}% + \setbox1\hbox{\xaxis[\xunit]{#1}[#2]{#3}[#4]}% + \edef\graphboxht{\the\ht0 }% + \edef\graphboxwd{\the\wd1 }% + \rlap{\box1 \clap{\vrule height\dimexpr\graphboxht+\axiswd\relax width\axiswd depth0pt }}% + \rlap{\box0 }% + \raise\graphboxht\rlap{\kern-.5\axiswd\vrule height\axiswd width\dimexpr\graphboxwd+\axiswd}% + \begingroup + \catcode`\^^M=9\relax + \graphzone@i +} + +\def\graphzone@i#1{% + \endgroup + \xunit=\decdiv1\xincrement\xunit + \yunit=\decdiv1\yincrement\yunit + \setbox0\hbox{#1}% + \wd0=\dimexpr\graphboxwd+\axiswd\relax + \ht0=\dimexpr\graphboxht+\axiswd\relax + \box0 + \endgroup + \ignorespaces +} + +\def\plot(#1,#2){% + \edef\x@plot{#1}\edef\y@plot{#2}% + \ifinside\x@plot[\graphxmin,\graphxmax]% + {\ifinside\y@plot[\graphymin,\graphymax]% + {\putat{\dimexpr\x@plot\xunit-\graphxmin\xunit\relax}{\dimexpr\y@plot\yunit-\graphymin\yunit\relax}\plotstuff}% + \relax + } + \relax +} + +\def\showyaxis{% + \ifinside0[\graphymin,\graphymax]% + {\putat\z@{-\graphymin\yunit}{\vrule width\graphboxwd height\axiswd}}% + \relax +} + +\def\showxaxis{% + \ifinside0[\graphxmin,\graphxmax]% + {\putat{-\graphxmin\xunit}\z@{\clap{\vrule width\axiswd height\graphboxht}}}% + \relax +} + +\def\showaxis{\showxaxis\showyaxis} + +\def\putat#1#2#3{% + \leavevmode\rlap{\kern#1\vbox to0pt{\vss\hbox{#3}\kern#2}}% +} + +\newmacro\cross[2pt][0.2pt]{% + \quitvmode + \vlap{% + \clap{% + \vrule height#2 depth0pt width#1 + \vrule height#1 depth#1 width#2 + \vrule height#2 depth0pt width#1 + }% + }% +} + +\protected\def\numsep{\kern0.2em }% \numsep est le séparateur mis tous les 3 chiffres + +\def\formatdecpart#1{% #1=série de chiffres + \ifempty{#1}% si la partie décimale est vide + {}% ne rien afficher + {{,}\formatdecpart@i1.#1..}% sinon, afficher la virgule et mettre en forme +} + +% #1=compteur de caractères #2= chiffre à déplacer +% #3= chiffres restants #4 = chiffres déjà traités +\def\formatdecpart@i#1.#2#3.#4.{% #1=compteur de caractères #2= chiffres traité #3= chiffres traités + \ifempty{#3}% si #2 est le dernier chiffre à traiter + {#4#2}% le mettre en dernière position et tout afficher, sinon + {\ifnum#1=3 \expandafter\firstoftwo + \else\expandafter\secondoftwo + \fi% si 3 chiffres sont atteint, rendre #1 égal à 1 et + {\formatdecpart@i 1.#3.#4#2\numsep.}% mettre #2\numsep en dernier puis recommencer + % sinon, mettre #2 en dernière position et recommencer + % tout en incrémentant #1 de 1 + {\expandafter\formatdecpart@i\number\numexpr#1+1.#3.#4#2.}% + }% +} + +\def\formatintpart#1{% #1=série de chiffres + \expandafter\formatintpart@i\expandafter1\expandafter.% + \romannumeral\reverse{#1\z@}..% appelle la macro récursive +} + +% #1=compteur de caractères #2= chiffre à déplacer +% #3= chiffres restants #4 = chiffres déjà traités +\def\formatintpart@i#1.#2#3.#4.{% #1=compteur de caractères #2= chiffres traité #3= chiffres traités + \ifempty{#3}% si #2 est le dernier chiffre à traiter + {#2#4}% le mettre en première position et tout afficher, sinon + {\ifnum#1=3 \expandafter\firstoftwo + \else\expandafter\secondoftwo + \fi% si 3 chiffres sont atteint, rendre #1 égal à 1 et + {\formatintpart@i 1.#3.\numsep#2#4.}% mettre \numsep#2 en premier puis recommencer + % sinon, mettre #2 en dernière position et recommencer + % tout en incrémentant #1 de 1 + {\expandafter\formatintpart@i\number\numexpr#1+1.#3.#2#4.}% + }% +} + +\def\removefirstzeros#1{% + \removefirstzeros@i#1\removefirstzeros@i +} +\def\removefirstzeros@i#1{% + \ifx\removefirstzeros@i#1% \removefirstzeros@i est lu donc tout le nombre a été parcouru + \expandafter0% laisser un zéro + \else + \ifx0#1% si le chiffre lu est un 0 + \expandafter\expandafter\expandafter\removefirstzeros@i% recommencer + \else% sinon remettre le chiffre et tout afficher jusqu'à \removefirstzeros@i + \expandafter\expandafter\expandafter\removefirstzeros@ii\expandafter\expandafter\expandafter#1% + \fi + \fi +} +\def\removefirstzeros@ii#1\removefirstzeros@i{#1} + +\def\ifnodecpart#1{\ifnodecpart@i#1.\@nil} +\def\ifnodecpart@i#1.#2\@nil{\ifempty{#2}} + +\newbox\remainbox% boite contenant le texte total +\newbox\currentline% boite contenant le ligne en cours +\newcount\linecnt% compteur pour numéroter les lignes + +\newmacro\leftline[0pt]{% définit ce qui se trouve à gauche de chaque ligne + \def\wd@left{#1}% + \def\stuff@left +} + +\newmacro\rightline[0pt]{% définit ce qui se trouve à droite de chaque ligne + \def\wd@right{#1}% + \def\stuff@right +} + +\let\formatline=\identity + +\leftline[15pt]{$\scriptscriptstyle\number\linecnt$\kern5pt }% numérotation à gauche +\rightline{}% rien à droite + +\def\numlines{% + \par\smallskip + \begingroup% dans un groupe semi simple + \splittopskip=0pt % ne rajouter aucun espace au sommet de la boite restante + \savingvdiscards=1 % autorise la sauvagarde des éléments supprimés + \linecnt=0 % initialiser le compteur de lignes + \setbox\remainbox=\vbox\bgroup% compose la boite... + \advance\hsize by% diminuer la \hsize + -\dimexpr\wd@left+\wd@right\relax% de la largeur des contenus +} + +\def\endnumlines{% + \egroup + \offinterlineskip + \split@line +} + +\def\split@line{% + \ifvoid\remainbox% si la boite est vide + \par% fin du processus + \endgroup% fermer le groupe ouvert au début + \else% sinon + \advance\linecnt 1 % incrémente le compteur de lignes + \edef\htbefore{\the\vdim\remainbox}% + \edef\restorevfuzz{\vfuzz=\the\vfuzz\relax}% sauvegarde le \vfuzz + \vfuzz=\maxdimen% annule les avertissements pour débordement + \setbox\currentline=\vsplit\remainbox to 0pt % couper la boite à 0pt de hauteur + \restorevfuzz + \setbox\currentline=\vbox{\unvbox\currentline}% redonner à la boite sa hauteur + \let\savedsplitdiscards\splitdiscards + \edef\intersplitspace{% calcul de l'espace vertical perdu à la coupure + \the\dimexpr\htbefore-(\vdim\remainbox+\vdim\currentline)\relax + }% + \hbox{% en mode vertical et dans une hbox, afficher : + \hbox to\wd@left{\hss\stuff@left}% 1) ce qui est à gauche + \formatline{\box\currentline}% 2) la ligne courante + \hbox to\wd@right{\stuff@right\hss}% 3) ce qui est à droite + }% + \splitdiscards% affiche ce qui a été ignoré à la coupure + \expandafter\split@line% recommencer + \fi +} + +\newskip\interletterskip +\newskip\interwordskip +\catcode`\@11 +\newtoks\spacetxt@toks% le registre qui contient le texte final + +\def\spacetxt{% + \let\spacetxt@endprocess\spacetxt@endnormal + % définit la macro appelée en fin de processus -> à priori : fin normale + \ifstarred% si la macro est étoilée + {\let\spacetxt@recurse\spacetxt@star% définir la macro récursive + \spacetxt@i% et aller à \spacetxt@i + }% sinon + {\let\spacetxt@recurse\spacetxt@nostar% définir la macro récursive + \spacetxt@i% et aller à \spacetxt@i + }% +} + +\newmacro\spacetxt@i[0.3em][3\interletterskip]1{% +% arg optionnel #1 et #2 = ressorts inter-lettre et inter--mot +% #3 = texte à espacer + \interletterskip=#1\relax + \interwordskip=#2\relax + \def\spacetxt@code{#3}% met le texte à espacer dans \spacetxt@code + \spacetxt@toks{}% initialiser le registre contenant le texte final + \spacetxt@recurse% aller à la macro récursive précédemment définie +} + +\newif\if@indivifound% booléen qui sera vrai si un motif spécial est rencontré + +\def\spacetxt@nostar{% + \expandafter\ifempty\expandafter{\spacetxt@code}% si texte restant est vide + \spacetxt@endprocess% aller à la fin du processus + {\@indivifoundfalse% sinon, à priori, les motifs non réguliers ne sont pas trouvés + \expandafter\doforeach\expandafter\indivi@tmp\expandafter\in\expandafter{\indivilist} + % pour chaque \indivi@tmp dans \indivilist + {\exptwoargs\ifstartwith\spacetxt@code\indivi@tmp + % si le code commence par le motif courant + {\eaddtotoks\spacetxt@toks{\indivi@tmp\hskip\interletterskip}% + % l'ajouter dans le registre ainsi que l'espace inter-lettre + \expandafter\rightofsc\expandafter\spacetxt@code\expandafter{\indivi@tmp}% + % et enlever le motif du texte restant à lire + \@indivifoundtrue + % marquer qu'un motif a été trouvé + \doforeachexit + % et sortir prématurément de la boucle + }% + \relax + % si le code ne commence pas le motif courant -> ne rien faire + }% + \if@indivifound + \else% si aucun motif n'a été trouvé + \grab@first\spacetxt@code\spacetxt@temp + % retirer le 1er caractère du texte +% \ifcat\noexpand\spacetxt@temp\sptoken + \ifx\spacetxt@temp\space + % si le 1er caractère est un espace + \addtotoks\spacetxt@toks{\hskip\interwordskip}% + % ajouter l'espace inter-mot au registre de token + \else + % si le 1er caractère n'est pas un espace + \eaddtotoks\spacetxt@toks{\spacetxt@temp\hskip\interletterskip}% + % ajouter ce caractère et l'espace inter-lettre au registre de token + \fi + \fi + \spacetxt@recurse% enfin, continuer le processus + }% +} + +\def\spacetxt@star{% + \expandafter\ifempty\expandafter{\spacetxt@code}% si texte restant est vide + \spacetxt@endprocess% aller à la fin du processus + {\expandafter\ifbracefirst\expandafter{\spacetxt@code}% + % sinon, si texte commence par "{" + {\grab@first\spacetxt@code\spacetxt@temp + % mettre {<argument} dans \spacetxt@temp + \begingroup% ouvrir un groupe + \expandafter\def\expandafter\spacetxt@code\spacetxt@temp + % mettre le contenu de l'argument dans \spacetxt@code + \let\spacetxt@endprocess\spacetxt@endingroup% changer le processus de fin + \spacetxt@toks{}% initialiser + \spacetxt@recurse% exécuter le processus avec ce nouveau texte + }% si le code ne commence pas par "{", aller à \spacetxt@nostar mais comme + \spacetxt@nostar% \spacetxt@recurse vaut \spacetxt@star, n'y faire qu'1 boucle + }% +} + +\def\spacetxt@endnormal{% fin de processus normal + \the\spacetxt@toks% afficher le registre à token + \unskip% et supprimer le dernier ressort +} + +\def\spacetxt@endingroup{% fin du processus dans un groupe : + \expandafter\endgroup\expandafter% avant de fermer le groupe + \addtotoks\expandafter\spacetxt@toks\expandafter% ajouter au registre hors du groupe + {\expandafter{\the\spacetxt@toks}}% ce qui est collecté localement mis entre {} + \spacetxt@recurse% puis aller à la macro récursive +} + +\def\indivilist{<<,>>}% liste des motifs spéciaux + +\def\insert@blankchar{% + \ifstarred\insert@blankchar@ii\insert@blankchar@i +} + +\def\insert@blankchar@i#1{% insère une espace de largeur #1 caractères complets + \ifnum\numexpr#1\relax>0 + \kern\numexpr#1\relax\dimexpr\ttchar@width+\brktt@interletter\relax + \fi +} + +\def\insert@blankchar@ii#1{% insère #1-1 caractères complets + 1 largeur de caractère + \ifnum\numexpr#1\relax>0 + \insert@blankchar@i{#1-1}\kern\ttchar@width + \fi +} + +\def\restart@hbox#1{% + \egroup + \hbox\bgroup + \expsecond{\def\tt@remaintext} + {\romannumeral\removefirstspaces@i{#1}}% initialiser le code à composer + \let\previous@char\space% initialise le caractère précédent + \line@starttrue% aucun caractère n'a encore été imprimé + \brktt@cnt=0\relax% remettre le compteur à 0 +} + +\def\print@nchar#1{% affiche #1 caractères pris dans \tt@remaintext + \for\xxx= 1 to #1 \do 1{% + \ifx\tt@remaintext\empty% si le code restant à composer est vide + \exitfor\xxx%sortir de la boucle prématurément + \else + \@indivifoundfalse% sinon, à priori, les motifs de ligature ne sont pas trouvés + % pour chaque \indivi@tmp dans la liste de ligatures + \expsecond{\doforeach\indivi@tmp\in}{\liglist}% + {% si le code commence par la \idx{ligature} courante + \exptwoargs\ifstartwith\tt@remaintext\indivi@tmp% + {\let\previous@char\indivi@tmp% prendre le motif pour caractère courant + \expsecond{\rightofsc\tt@remaintext}{\indivi@tmp}% et l'enlever du texte restant à lire% + \@indivifoundtrue% marquer qu'un motif a été trouvé + \doforeachexit% et sortir prématurément de la boucle + }% + {}% si le code ne commence pas le motif courant -> ne rien faire + }% + \unless\if@indivifound% si aucun motif trouvé, + \grab@first\tt@remaintext\previous@char% lire le premier caractère + \fi + \advance\brktt@cnt by 1 % incrémenter le compteur de caractères + \hbox to\ttchar@width{\hss\previous@char\hss}% afficher le caractère lu + \line@startfalse% nous ne sommes plus au début d'une ligne + \ifnum\brktt@cnt<\maxchar@num\relax% si la ligne n'est pas encore remplie + \kern\brktt@interletter% insérer le ressort inter-lettre + \else + \exitfor\xxx% sinon, sortir de la boucle prématurément + \fi + \fi + }% +} + +\newmacro\breakttA[0.3em][\hsize]1{% +% arg optionnel #1 et #2 = ressorts inter-lettre et dimension horizontale texte +% #3 = texte à espacer + \begingroup% ouvrir un groupe et le fermer à la toute fin + \par% commencer un nouveau paragraphe -> passage en mode vertical + \parindent=0pt% empêche l'indentation + \tt% passer en police à chasse fixe + \setbox0 = \hbox{M}% la boite 0 contient un caractère + \edef\ttchar@width{\the\wd0 }% largeur de chaque caractère en police \tt + \edef\text@width{\the\dimexpr#2\relax}% largeur de composition + % les 2 lignes suivantes rendent le compteur égal à E((L-l)/(l+Delta)) + \brktt@cnt=\numexpr\dimexpr#2-\wd0 \relax\relax% largeur diminuée du 1er caractère + \divide\brktt@cnt by \numexpr\dimexpr\wd0 + #1 \relax\relax + % le nombre de caractères par ligne est égal à 1 de plus : + \edef\maxchar@num{\number\numexpr\brktt@cnt+1\relax}% + % calcul de la dimension inter-lettre + \brktt@interletter=\dimexpr(\text@width-\ttchar@width*\maxchar@num)/\brktt@cnt\relax + \expsecond{\expsecond{\def\tt@remaintext}}{\removetrailspaces{#3}}% met le texte à espacer dans \tt@remaintext + \addtomacro\tt@remaintext{ \relax}% ajouter " \relax" à la fin : le code finit donc par " \relax" + \def\tt@emptytext{ \relax}% sera le code lorsque tout est composé + \unless\ifx\tt@remaintext\tt@emptytext% si le texte à composer n'est pas vide + \hbox\bgroup% démarrer la boite horizontale contenant la première ligne + \insert@blankchar\ttindent% insérer une espace d'indentation de longueur (l+Delta')*\ttindent + \brktt@cnt=\ttindent\relax% tenir compte du nombre de caractères indentés + \line@starttrue% il s'agit du début d'une ligne + \expandafter\breakttA@i% aller à la macro récursive + \fi +} + +\def\leftofsc#1#2{% dans la sc #1, garde ce qui est à gauche de #2 + \def\leftofsc@i##1#2##2\@nil{\def#1{##1}}% + \expandafter\leftofsc@i#1\@nil +} + +\def\len@tonextword{% stocke dans \next@len le nombre de caractères avant + % le prochain point de coupure dans \tt@remaintext + \let\next@word\tt@remaintext% copie \tt@remaintext dans la macro temporaire \next@word + \leftofsc\next@word{ }% ne prend que ce qui est avant le prochain espace + \exparg\ifin{\next@word}{-}% si le mot contient un tiret + {\leftofsc\next@word{-}% prendre ce qui est à gauche de ce tiret + \def\extra@char{1}% il y a un caractère de plus à loger après le mot + } + {% sinon, le caractère après le mot est un espace + \def\extra@char{0}% qu'il ne faut pas compter + }% + \setbox0=\hbox{\next@word}% enfermer le mot dans une boite + % et en calculer le nombre de caractères + \edef\next@len{\number\numexpr\dimexpr\wd0 \relax/\dimexpr\ttchar@width\relax\relax}% +} + +\newmacro\zerocompose[]2{% +% #1=code à exécuter avant la composition +% #2=registre de boite recevant le résultat +% #3= texte à composer en largeur 0pt + \setbox#2=\vbox{% + #1% code a exécuter (changement de fonte par exemple) + \hfuzz=\maxdimen% annule les avertissements pour débordement horizontaux + \hbadness=10000 % annule les avertissements pour mauvaise boite horizontale + \pretolerance=-1 % désactive la première passe (celle sans coupures) + \tolerance=10000 % passe avec coupures acceptée + \hyphenpenalty=-10000 % favorise fortement les copures de mots + \lefthyphenmin=2 \righthyphenmin=3 % longueur mini des fragments de début et fin + \clubpenalty=0 % pas de \idx{pénalité} supplémentaire après la première ligne + \interlinepenalty=0 % pas de \idx{pénalité} inter-ligne + \widowpenalty=0 % pas de \idx{pénalité} supplémentaire avant la dernière ligne + \exhyphenpenalty=0 % ne pas pénaliser une coupure explicite + \leftskip=0pt \rightskip=0pt % désactive les éventuels ressorts latéraux + \everypar={}% désactive l'éventuel \everypar + \parfillskip=0pt plus1fil % règle le \parfillskip par défaut + \hsize=0pt % largeur de composition = 0pt + \edef\restorehyphenchar{\hyphenchar\font=\number\hyphenchar\font}% + \hyphenchar\font=`\- % impose "-" comme caractère de coupure + \noindent % pas d'indentation + passage en mode horizontal + \hskip0pt \relax% premier noeud horizontal pour permettre la coupure de la suite + #3\par% compose #3 + \restorehyphenchar% restaure le caractère de coupure + }% +} + +\def\hyphlengths#1#2{%#2 = macro contenant les longueurs de coupures du mot #1 + \begingroup + \zerocompose + [\tt% passer en police à chasse fixe + \setbox\z@\hbox{M}\xdef\ttwidth{\the\wd\z@}% mesurer la largeur des caractères + \hyphenchar\font=`\- % choisit "-" comme caractère de coupure + ]\z@{#1}% compose en 0pt dans la boite 0 + \let#2 = \empty% initialise la macro #2 + \def\cumul@length{0}% + \vfuzz=\maxdimen% annule les avertissements pour débordement + \splittopskip=\z@ % ne rajouter aucun espace au sommet de la boite restante + \loop + \setbox1=\vsplit\z@ to \z@% couper la boite à 0pt de hauteur + {\setbox\z@=\vbox{\unvbox1 \unskip\unpenalty\global\setbox1=\lastbox}}% + \setbox1=\hbox{\unhbox1 }% + \unless\ifvoid\z@% si la boite 0 n'est pas encore vide + \edef\cumul@length{% mettre à jour \cumul@length + \number\numexpr + \cumul@length + +% ajouter le quotient "largeur syllabe/largeur d'1 caractère" + \wd1/\dimexpr\ttwidth\relax + -1% et soustraire 1 (le caractère "-") + \relax + }% + % ajouter à #2 la virgule et le cumul actuel +1 + \edef#2{% définir la macro #2 : + #2% reprendre le contenu de #2 + \ifx#2\empty\else,\fi% ajouter "," si #2 non vide + \number\numexpr\cumul@length+1\relax% et le cumul + }% + \repeat% et recommencer + \expsecond{% avant de fermer le groupe + \endgroup + \def#2}{#2}% définit #2 hors du groupe +} + +\newif\ifnumalgo +\newcount\algocnt +\numalgotrue + +\def\algoindent{2em} +\def\algorule{.4pt}% épaisseur des réglures de début et de fin + +\def\algohrulefill{% remplit avec une ligne horizontale + \leavevmode + \leaders\hrule height\algorule\hfill + \kern0pt % rajoute un noeud au cas où la commande est en fin de ligne +} + +\def\algoleftskip{10pt} +\def\algorightskip{10pt} + +\newmacro\algorithm[\\,\#,\{,\}]2{% + \medbreak + \begingroup% ouvre un groupe (sera fermé à la fin de l'algorithme) + \footnotesize + \algocnt=1 % initialise le compteur de lignes + \leftskip=\algoleftskip \rightskip=\algorightskip% initialise les ressorts latéraux + \parindent=0pt % pas d'indentation + %%%%%%%%%%%% affichage du titre %%%%%%% + \algohrulefill% remplir avec une ligne horizontale + \ifempty{#2}% si #2 est vide + {}% ne rien insérer + {% sinon + \lower.5ex\hbox{ #2 }% insérer le titre abaissé de 0.5ex + \algohrulefill% insérer une ligne horizontale + }% + \par% aller à la ligne + \nointerlineskip% ne pas insérer le ressort interligne + \kern7pt % et sauter 7pt verticalement + \nobreak% empêcher une coupure de page + %%%%%%%%%%%%%% fin du titre %%%%%%%%%% + % + %%%%%%%%%%%%%% rend les caractères actifs %%%%%%%%%%%%%% + \def~##1~{\begingroup\bf##1\endgroup}% + \defactive:{% rend ":" actif + \futurelet\nxttok\algoassign% \nxttok = token suivant + }% + \def\algoassign{% suite du code de ":" + \ifx=\nxttok% si ":" est suivi de "=" + \ifmmode% si mode math + \leftarrow% afficher "\leftarrow" + \else% si mode texte + ${}\leftarrow{}$% passer en mode math pour "\leftarrow" + \fi + \expandafter\gobone% manger le signe "=" + \else% si ":" n'est pas suivi de "="' + \string:% afficher ":" + \fi + }% + \expandafter\def\expandafter\oldeverypar\expandafter% sauvegarder... + {\the\everypar}% ... l'action effectuée à chaque paragraphe + \ifnumalgo% si la numérotation est demandée, + \everypar\expandafter{% à chaque paragraphe + \the\everypar% reprendre le contenu précédent + \llap{% et à droite du début de la ligne, + $\scriptstyle\number\algocnt$% afficher le numéro + \kern\dimexpr4pt+\leftskip-\algoleftskip\relax% en tenant compte de l'indentation + }% + }% + \fi + \def\algopar{% actions effectués par ^^M + \advance\algocnt by 1 % incrémente le compteur de lignes + \color{black}% repasse en couleur noire + \rm% fonte droite + \par% termine le paragraphe + \leftskip=\algoleftskip % initialise le ressort gauche + }% + \doforeach\currentchar\in{#1}{\expandafter\catcode\expandafter`\currentchar=12 }% + \defactive\^^I{\advance\leftskip by \algoindent\relax}% + \defactive\ {\hskip1.25\fontdimen2\font\relax}% espace = 25% de + que la largeur naturelle + \letactive\^^M\algopar + \defactive\%{\it\color{gray}\char`\%}% passe en italique et gris puis affiche "%" + \defactive_{\ifmmode_\else\string_\fi}% + \defactive#3{% rend le token #3 actif (il sera rencontré à la fin de l'algorithme) + \everypar\expandafter{\oldeverypar}% restaurer l'ancien \everypar + \par% aller à la ligne + \nointerlineskip% ne pas insérer le ressort interligne + \kern7pt % et sauter 7pt verticalement + \nobreak% empêcher une coupure de page + \algohrulefill% tracer la ligne de fin + \smallbreak% saute un petit espace vertical + \endgroup% ferme le groupe ouvert au début de l'algorithme + }% + %%%%%%%%%%%%%%%%% fin des caractères actifs %%%%%%%%%%%%%%%% + % + \sanitizealgo% va manger les espaces et les ^^M au début de l'algo +} + +\def\sanitizealgo{\futurelet\nxttok\checkfirsttok}% récupère le prochain token + +\def\checkfirsttok{% teste le prochaun token + \def\nextaction{% à priori, on considère que la suite est " " ou "^^M" donc + \afterassignment\sanitizealgo% aller à \sanitizealgo + \let\nexttok= % après avoir mangé ce "^^M" ou cet espace + }% + \unless\ifx\nxttok\algopar% si le prochain token n'est pas un ^^M + \unless\ifx\space\nxttok% et si le prochain token n'est pas un espace + \let\nextaction\relax% ne rien faire ensuite + \fi + \fi + \nextaction% faire l'action décidée ci-dessus +} + +\def\true@sgn#1{\ifnum#11<\z@-\fi} + +\restoreatcoatcode\relax +\endinput
\ No newline at end of file |