summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/source/progtexmacro.tex
diff options
context:
space:
mode:
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.tex2734
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