summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/output/progtexcode.txt
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/output/progtexcode.txt')
-rw-r--r--Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/output/progtexcode.txt9712
1 files changed, 9712 insertions, 0 deletions
diff --git a/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/output/progtexcode.txt b/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/output/progtexcode.txt
new file mode 100644
index 00000000000..fcd1a19ec7c
--- /dev/null
+++ b/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/output/progtexcode.txt
@@ -0,0 +1,9712 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% %%
+%% Codes donnés dans le livre %%
+%% « Apprendre à programmer en TeX » %%
+%% %%
+%% Encodage ISO 8859-1 %%
+%% _____ %%
+%% %%
+%% © 2014 Christian Tellechea %%
+%% %%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Les codes et les macros commentés donnés dans ce fichier sont diffusés sous
+% la licence LaTeX project public license (LPPL) 1.2
+%
+% https://www.latex-project.org/lppl/lppl-1-2/
+% https://www.latex-project.org/lppl/lppl-1-2.txt
+%
+% Attention : ce fichier n'a pas vocation à être compilé
+\endinput
+
+
+****************** Code 1 ******************
+Voici le code en \TeX{} du premier exemple.% ceci est un commentaire
+
+On peut observer l'affichage qu'il produit juste au-dessous !
+****************** Fin code ******************
+
+
+****************** Code 2 ******************
+3 tailles : $% entre en mode mathématique (espaces ignorés)
+1^{2^3}% 2 est en taille "\scriptstyle" et 3 en taille "\scriptscriptstyle"
+$% fin du mode math
+
+normal $1$, petit $\scriptstyle 2$, très petit $\scriptscriptstyle 3$.
+****************** Fin code ******************
+
+
+****************** Code 3 ******************
+%%% comportement normal %%%
+a) comportement normal :
+Ligne 1
+Ligne 2
+
+Ligne 3
+\medbreak
+b) Aucun caractère de fin de ligne :
+%%% aucune insertion en fin de ligne %%%
+\endlinechar=-1
+Ligne 1
+Ligne 2
+
+Ligne 3\endlinechar13
+
+\medbreak
+c) "X" comme caractère de fin de ligne :
+%%% "X" est inséré à chaque fin de ligne
+\endlinechar=88
+Ligne 1
+Ligne 2
+
+Ligne 3
+****************** Fin code ******************
+
+
+****************** Code 4 ******************
+a) \number"1A \qquad b) \number"AB3FE \qquad c) \number"78
+****************** Fin code ******************
+
+
+****************** Code 5 ******************
+a) \number'15 \qquad b) \number'674 \qquad c) \number'46
+****************** Fin code ******************
+
+
+****************** Code 6 ******************
+a) \number`\a \quad %code de caractère de "a"
+b) \number`\\ \quad % code de caractère de "\"
+c) \number`\$ \quad % code de caractère de "$"
+d) \number`\ \quad % code de caractère de l'espace
+e) \number`\5 \quad % code de caractère de "5"
+f) \number`\{ \quad % code de caractère de l'accolade ouvrante
+g) \number`\} % code de caractère de accolade fermante
+****************** Fin code ******************
+
+
+****************** Code 7 ******************
+a) \number\catcode`\a \quad %code de catégorie de "a"
+b) \number\catcode`\\ \quad % code de catégorie de "\"
+c) \number\catcode`\$ \quad % code de catégorie de "$"
+d) \number\catcode`\ \quad % code de catégorie de l'espace
+e) \number\catcode`\5 \quad % code de catégorie de "5"
+f) \number\catcode`\{ \quad % code de catégorie de l'accolade ouvrante
+g) \number\catcode`\} % code de catégorie de accolade fermante
+****************** Fin code ******************
+
+
+****************** Code 8 ******************
+Ici, W est une lettre...\par
+\catcode`\W=3 % W devient le signe de bascule en mode math
+Wx+y=3W\par
+$a+b=cW\par
+W2^3=8$\par
+\catcode`\W=11 % W redevient une lettre
+De nouveau, W est une lettre...
+****************** Fin code ******************
+
+
+****************** Code 9 ******************
+$3+4=7$ \par % $ est la bascule math
+\catcode`\$=12 % $ devient un caractère affichable
+$ s'affiche sans problème : $\par
+\catcode`\$=3 % $ redevient la bascule math
+$4+3=7$
+****************** Fin code ******************
+
+
+****************** Code 10 ******************
+Voici les premiers mots de chaque ligne :
+
+\catcode`\ =5 % l'espace est déormais de catcode 5
+Cette première ligne sera tronquée...
+
+La deuxième aussi !
+
+Et la dernière également.
+\catcode`\ =10 % l'espace reprend son catcode
+
+Le comportement normal est restauré.
+****************** Fin code ******************
+
+
+****************** Code 11 ******************
+\def\foo{Bonjour}% définit le texte de remplacement de \foo
+a) \foo Alice.\qquad% espace ignoré
+b) {\foo} Bob.\qquad% espace non ignoré
+c) \foo{} Chris.\qquad% espace non ignoré
+d) \foo\space Daniel.% \space est remplacé par un espace
+****************** Fin code ******************
+
+
+****************** Code 12 ******************
+\def\startbold{\begingroup \bf}
+\def\stopbold{\endgroup}
+Voici \startbold du texte en gras\stopbold{} et la suite.
+****************** Fin code ******************
+
+
+****************** Code 13 ******************
+\def\foo{foo}
+\begingroup A\aftergroup\foo B\endgroup\par
+{A\aftergroup X\aftergroup\foo B}
+****************** Fin code ******************
+
+
+****************** Code 14 ******************
+1) (un {\it cheval})\par% sans correction d'italique
+2) (un {\it\aftergroup\/cheval})\par% avec correction d'italique
+% on peut définir une macro \itacorr qui effectue automatiquement la correction
+\def\itacorr{\it\aftergroup\/}
+3) (un {\itacorr cheval})% avec correction d'italique
+****************** Fin code ******************
+
+
+****************** Code 15 ******************
+\def\bar{Je suis bar.}
+\let\foo\bar % \foo devient égal à \bar
+\def\bar{ABC}% \bar est redéfinie
+\foo\par% affiche "Je suis bar"
+\bar% affiche "ABC"
+****************** Fin code ******************
+
+
+****************** Code 16 ******************
+Initialement, c'est \TeX.\par
+\let\TeXsauve\TeX% sauvegarde
+\def\TeX{tEx}% redéfinition
+Ici, on a modifié \TeX.\par
+\let\TeX\TeXsauve% retauration
+De nouveau, c'est \TeX.
+****************** Fin code ******************
+
+
+****************** Code 17 ******************
+\let\sptoken= %2 espaces avant le "%"
+
+La commande \sptoken compose le paragraphe
+****************** Fin code ******************
+
+
+****************** Code 18 ******************
+{% début du groupe
+\catcode`\W=13 \def W{wagons}
+Les W constituent le train.
+}% fin du groupe
+****************** Fin code ******************
+
+
+****************** Code 19 ******************
+\begingroup \catcode`\W=13
+\gdef\actiw{%
+ \catcode`\W=13
+ \def W{wagons}}
+\endgroup
+a) Les trains ne sont pas constitués de W !\par
+b) \begingroup\actiw Ici, les W forment les trains.\endgroup\par
+c) Ici, les W sont redevenus des lettres.
+****************** Fin code ******************
+
+
+****************** Code 20 ******************
+\begingroup
+ \catcode`\ =13 % rend l'espace actif
+ \gdef\>{\begingroup
+ \catcode`\ =13
+ \def {\hskip5mm\relax}}
+\endgroup
+\let\<=\endgroup
+a) Du texte normal\par
+b) \>Des mots très espacés\<\par
+c) Du texte normal
+****************** Fin code ******************
+
+
+****************** Code 21 ******************
+\begingroup
+ \catcode`\,=13 \def,{\unskip\string,\space\ignorespaces}
+ La rue assourdissante autour de moi hurlait.
+
+ Longue , mince,en grand deuil , douleur majestueuse ,
+
+ Une femme passa ,d'une main fastueuse
+
+ Soulevant,balançant le feston et l'ourlet ;
+
+\endgroup\medbreak\hfill Charles {\sc Baudelaire}
+****************** Fin code ******************
+
+
+****************** Code 22 ******************
+\begingroup
+ \catcode`\,=13 \def,{\unskip\string, \ignorespaces}
+ \catcode`\^^M=13 \let ^^M\par % rend le retour charriot égal à \par
+ La rue assourdissante autour de moi hurlait.
+ Longue , mince,en grand deuil , douleur majestueuse ,
+ Une femme passa , d'une main fastueuse
+ Soulevant,balançant le feston et l'ourlet ;
+\endgroup\medbreak\hfill Charles {\sc Baudelaire}
+****************** Fin code ******************
+
+
+****************** Code 23 ******************
+{% ouvre un groupe
+ \let\AA=a \let\EE=e \let\II=i \let\OO=o \let\UU=u \let\YY=y
+ % sauvegarder avant de modifier le catcode de a et e :
+ \let\lEt=\let \let\cAtcOdE=\catcode
+ \cAtcOdE`\a=13 \lEt a=\EE \cAtcOdE`\e=13 \lEt e=\II
+ \cAtcOdE`\i=13 \lEt i=\OO \cAtcOdE`\o=13 \lEt o=\UU
+ \cAtcOdE`\u=13 \lEt u=\YY \cAtcOdE`\y=13 \lEt y=\AA
+ Ce texte devenu \`a peine reconnaissable montre que le r\'esultat
+ contient des sonorit\'es catalanes, corses ou grecques assez
+ inattendues.
+}% ferme le groupe
+****************** Fin code ******************
+
+
+****************** Code 24 ******************
+{%
+ \let\AA=a \let\lEt=\let \let~=\catcode
+ ~`a=13 \lEt a=e ~`e=13 \lEt e=i ~`i=13 \lEt i=o
+ ~`o=13 \lEt o=u ~`u=13 \lEt u=y ~`y=13 \lEt y=\AA
+ Ce texte devenu \`a peine reconnaissable...
+}
+****************** Fin code ******************
+
+
+****************** Code 25 ******************
+a) \def\foo{Bonjour}\meaning\foo\par
+b) \let\bar=\foo\meaning\bar\par% \foo est "copiée" vers \bar
+c) \def\baz{\foo}\meaning\baz\par
+d) \catcode`\W=13 \def W{Wagons}% W est un caractère actif
+ \meaning W\par
+e) \meaning\def% \def est une primitive
+****************** Fin code ******************
+
+
+****************** Code 26 ******************
+a) \def\foo{
+
+}Signification de \string\foo{} : \meaning\foo
+
+b) Signification de deux retours charriots consécutifs : \meaning
+
+****************** Fin code ******************
+
+
+****************** Code 27 ******************
+a) \meaning\relax\par% primitive
+b) \meaning {\par% catcode 1
+c) \meaning }\par% catcode 2
+d) \meaning $\par% catcode 3
+e) \meaning &\par% catcode 4
+g) \meaning #\par% catcode 6
+h) \meaning ^\par% catcode 7
+i) \meaning _\par% catcode 8
+j) \meaning a\par% catcode 11 (une lettre)
+k) \meaning +\par% catcode 12 (caractère "autre")
+l) \meaning ~\par% catcode 13 (caractère actif)
+****************** Fin code ******************
+
+
+****************** Code 28 ******************
+\begingroup% dans un groupe
+ \let\*=\meaning% rendre \* égal à \meaning
+ \* %<- espace pris en compte
+\endgroup% fermer le groupe
+****************** Fin code ******************
+
+
+****************** Code 29 ******************
+\begingroup
+\catcode`\*0
+\catcode`\\12 % \ n'est plus un caractère d'échappement
+*def*foo{bar}
+*LaTeX{} et la macro *string*foo : *foo.
+
+L'ancien caractère d'échappement "\" et \TeX.
+*endgroup
+****************** Fin code ******************
+
+
+****************** Code 30 ******************
+\def\foo{\bar}
+\begingroup
+a) \escapechar=-1 \meaning\foo\qquad% pas de caractère d'échappement
+b) \escapechar=`\@ \meaning\foo\qquad% "@" est le caractère d'échappement
+\endgroup
+c) \meaning\foo% caractère d'échappement par défaut
+****************** Fin code ******************
+
+
+****************** Code 31 ******************
+\begingroup
+ \catcode`\|=0 |catcode`|\=11 |catcode`|2=11 |catcode`|1=11
+ |gdef|1\2\a{foo}
+|endgroup
+Voici la macro : \csname 1\string\2\string\a\endcsname
+****************** Fin code ******************
+
+
+****************** Code 32 ******************
+\newtoks\foo% allocation d'un nouveau registre
+\foo={Bonjour le monde}% assignation
+Contenu du registre {\tt\string\foo} : \the\foo.
+
+\newtoks\bar% allocation d'un autre registre
+\bar=\foo% assigne à \bar les tokens du registre \foo
+Contenu du registre {\tt\string\bar} : \the\bar.
+****************** Fin code ******************
+
+
+****************** Code 33 ******************
+\def\hello#1#2{Bonjour #1 et #2.\par}% définition
+\hello ab% #1=a et #2=b
+\hello a b% #1=a et #2=b
+\hello{foo}{bar}% #1=foo et #2=bar
+\hello foobar% #1=f et #2=o
+% (le reste "obar" est lu après que la macro est terminée)
+****************** Fin code ******************
+
+
+****************** Code 34 ******************
+\def\tenlist#1#2#3#4#5#6#7#8#9{(#1,#2,#3,#4,#5,#6,#7,#8,#9\endlist}
+\def\endlist#1{,#1)}
+Une liste \tenlist abcdefghij de lettres.
+****************** Fin code ******************
+
+
+****************** Code 35 ******************
+\def\foo#1#2{Bonjour #1 et #2.\par}
+\begingroup\tt% passer en fonte à chasse fixe
+a) \foo{monsieur}{madame}
+b) \foo{{\bf toi}}{moi}
+c) \foo{}{{}}
+d) \foo{ }{ }
+e) \foo{$\pi$} {$\delta$}
+f) \foo ab
+g) \foo X Y
+\endgroup% fin de la fonte à chasse fixe
+****************** Fin code ******************
+
+
+****************** Code 36 ******************
+\def\foo{Programmer en \TeX {} est facile}
+\meaning\foo\par
+\def\foo{Program^^6der en \TeX{} est facile}
+\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 37 ******************
+a) \gobone XY - \secondoftwo XY\par
+b) \gobone{ab}{xy} - \secondoftwo{ab}{xy}\par
+c) \gobone{123}4 - \secondoftwo{123}4\par
+d) \gobone A{BCD} - \secondoftwo A{BCD}
+****************** Fin code ******************
+
+
+****************** Code 38 ******************
+\gobone {a}{\catcode`\~12 Le <<~>> est un espace ?} Et ici <<~>> ?
+
+\secondoftwo{a}{\catcode`\~12 Le <<~>> est un espace ?} Et ici <<~>> ?
+****************** Fin code ******************
+
+
+****************** Code 39 ******************
+\def\visible{\let\choix=\firstoftwo}
+\def\cache{\let\choix=\secondoftwo}
+\def\?#1{\choix{#1}{...}}%
+\def\interro{J'ai ét\?{é} invit\?{é} à gout\?{er} chez Max. Après s'être
+ bien amus\?{é}, nous avons rang\?{é} et il a fallu rentr\?{er}.}
+Compléter avec << é >> ou << er >> :\par
+\cache\interro\par\medskip
+Correction :\par
+\visible\interro
+****************** Fin code ******************
+
+
+****************** Code 40 ******************
+\def\visible{\let\?=\identity}
+\def\cache{\def\?##1{...}}
+\def\interro{J'ai ét\?{é} invit\?{é} à goût\?{er} chez Max. On s'est
+ bien amus\?{é} et ensuite, il a fallu rentr\?{er}.}
+Compléter avec << é >> ou << er >> :\par
+\cache\interro\par\medskip
+Correction :\par
+\visible\interro
+****************** Fin code ******************
+
+
+****************** Code 41 ******************
+\def\makemacro#1#2{\def#1##1{##1 #2}}
+\makemacro\LL{Lamport}
+\makemacro\juin{juin 2014}
+Paris, le \juin{3}.\medbreak
+\LL{Cher Monsieur},\smallbreak
+Vous êtes convoqué à un examen sur \TeX{} le \juin{21} à
+9h00 précise dans le bureau de D. Knuth.\smallbreak
+Veuillez croire, \LL{Monsieur}, en mes sentiments \TeX iens.
+****************** Fin code ******************
+
+
+****************** Code 42 ******************
+\def\showcodes#1{\string#1 : $\number`#1 \rightarrow \number\lccode`#1$}
+\showcodes A\qquad \showcodes B\qquad
+\showcodes a\qquad \showcodes b\qquad \showcodes ^
+****************** Fin code ******************
+
+
+****************** Code 43 ******************
+\lowercase{CACAO foobar}\par
+\lowercase{\def\foo{Bonjour}}% définit une commande \foo
+\foo % la commande définie précédemment
+****************** Fin code ******************
+
+
+****************** Code 44 ******************
+\begingroup
+ \lccode`A=`* % change le code minuscule de A
+ \lowercase{CACAO ABRACADABRA}\par
+\endgroup
+\lowercase{CACAO ABRACADABRA}
+****************** Fin code ******************
+
+
+****************** Code 45 ******************
+\def\defactive#1{%
+ \catcode`#1=13
+ \begingroup
+ \lccode`~=`#1
+ \lowercase{\endgroup\def~}%
+}
+\begingroup% les modifications restent locales
+ \defactive W{wagons}% définit le caractère actif "W"
+ Les W constituent les trains.
+\endgroup %fermeture du groupe, "W" redevient une lettre
+\par Les W sont des lettres
+****************** Fin code ******************
+
+
+****************** Code 46 ******************
+\defactive W{wagon}
+1) Les W constituent le train.\par
+2) \catcode`W=11 Les W sont des lettres.\par
+3) \catcode`\W=13 Les W constituent-ils le train ?
+****************** Fin code ******************
+
+
+****************** Code 47 ******************
+\def\defactive#1#2{%
+ \catcode`#1=13 % #1 sera actif après la fin du texte de remplacement
+ \begingroup
+ \lccode`~=`#1 % dans \lowercase, changer les ~ (actifs) en "#1", ceux-ci étant actifs
+ \lowercase{\endgroup\def~}{#2}%
+ }
+\defactive W{Wagon}
+Un W.
+****************** Fin code ******************
+
+
+****************** Code 48 ******************
+\def\defactive#1{%
+ \catcode`#1=13 % #1 sera actif après la fin du texte de remplacement
+ \begingroup
+ \lccode`~=`#1 % dans \lowercase, changer les ~ (actifs) en "#1", ceux-ci étant actifs
+ \lowercase{\endgroup\def~}%
+ }
+\defactive W{Wagon}
+Un W.
+****************** Fin code ******************
+
+
+****************** Code 49 ******************
+\def\defactive#1#2{%
+ \catcode`#1=13 % #1 sera actif après la fin du texte de remplacement
+ \begingroup
+ \uccode`~=`#1 % dans \uppercase, changer les ~ (actifs) en "#1", ceux-ci étant actifs
+ \uppercase{\endgroup\def~}{#2}%
+}
+\defactive W{Wagon}
+Un W.
+****************** Fin code ******************
+
+
+****************** Code 50 ******************
+\def\letactive#1{%
+ \catcode`#1=13 % #1 sera actif après la fin du texte de remplacement
+ \begingroup
+ \uccode`~=`#1 % dans \uppercase, changer les ~ (actifs) en "#1", ceux-ci étant actifs
+ \uppercase{\endgroup\let~}%
+}
+\def\W{wagon}%
+\letactive X\W
+Un X.
+****************** Fin code ******************
+
+
+****************** Code 51 ******************
+\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 }% \do change le catcode de son argument à 12
+ \dospecials% rend inoffensifs tous les tokens spéciaux
+ \defactive\^^M{\leavevmode\par}% définit le retour charriot
+ \letactive#1\endgroup% définit #1 qui sera un \endgroup
+ \tt% passe en fonte à chasse fixe
+}
+essai 1 : \litterate*\foo # #34{ } &_\ *
+\medbreak
+essai 2 : \litterate/une première ligne ,, >>
+
+un saut de ligne et la seconde --/
+****************** Fin code ******************
+
+
+****************** Code 52 ******************
+\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 }% \do change le catcode de son argument à 12
+ \dospecials% rend inoffensifs tous les tokens spéciaux
+ \defactive\^^M{\leavevmode\par}% définit le retour charriot
+ \defactive\ {\ }% l'espace est actif et devient "\ "
+ \defactive<{\string<{}}\defactive>{\string>{}}% empêche
+ \defactive-{\string-{}}\defactive`{\string`{}}% les
+ \defactive,{\string,{}}\defactive'{\string'{}}% ligatures
+ \letactive#1\endgroup% #1 sera un \endgroup
+ \tt% passe en fonte à chasse fixe
+}
+essai 1 : \litterate*\foo # #34{ %} &_\ *
+\medbreak
+essai 2 : \litterate/une première ligne ,, >>
+
+un saut de ligne et la seconde --/
+****************** Fin code ******************
+
+
+****************** Code 53 ******************
+\def\baz#1#2#3#{"#1", puis "#2" et enfin "#3".}
+\baz{abc}def{gh}ij
+****************** Fin code ******************
+
+
+****************** Code 54 ******************
+\catcode`\@11
+\long\def\firstto@nil#1#2\@nil{#1}
+\long\def\remainto@nil#1#2\@nil{#2}
+a) \firstto@nil foobar\@nil \qquad b) \remainto@nil foobar\@nil \par
+c) \firstto@nil {foo}bar\@nil \qquad d) \remainto@nil {foo}bar\@nil
+****************** Fin code ******************
+
+
+****************** Code 55 ******************
+\catcode`\@=11 % "@" devient une lettre
+\def\rightof#1#2{%
+ \def\right@of##1#2##2\@nil{##2}% définit la macro auxiliaire
+ \right@of#1\@nil% appelle la macro auxiliaire où #1 est la <chaine>
+}
+\catcode`\@=12 %"@" redevient un signe
+--\rightof{Programmation}{g}--\par
+--\rightof{Programmation}{gram}--\par
+--\rightof{Programmation}{on}--
+****************** Fin code ******************
+
+
+****************** Code 56 ******************
+\catcode`\@=11 % "@" devient une lettre
+\def\rightof#1#2{%
+ \def\right@of##1#2##2\@nil{##2}% définit la macro auxiliaire
+ \right@of#1\@nil% appelle la macro auxiliaire
+}
+\catcode`\@=12 %"@" redevient un signe
+--\rightof{Programmation}{z}--\par
+--\rightof{Programmation}{Gram}
+****************** Fin code ******************
+
+
+****************** Code 57 ******************
+\catcode`\@=11 % "@" devient une lettre
+\def\rightof#1#2{%
+ \def\right@of##1#2##2\@nil{##2}% définit la macro auxiliaire
+ \right@of#1#2\@nil% appelle la macro auxiliaire avec le motif #2
+}
+\catcode`\@=12 %"@" redevient un signe
+--\rightof{Programmation}{g}--\par
+--\rightof{Programmation}{ti}--\par
+--\rightof{Programmation}{z}--\par
+--\rightof{Programmation}{Gram}--
+****************** Fin code ******************
+
+
+****************** Code 58 ******************
+\catcode`\@=11 % "@" devient une lettre
+\def\gobto@@nil#1\@@nil{}
+\def\rightof#1#2{%
+ \def\right@of##1#2##2\@nil{##2}% définit la macro auxiliaire
+ \right@of#1\gobto@@nil#2\gobto@@nil\@@nil\@nil% appelle la macro auxiliaire
+}
+\catcode`\@=12 %"@" redevient un signe
+--\rightof{Programmation}{g}--\par
+--\rightof{Programmation}{ti}--\par
+--\rightof{Programmation}{z}--\par
+--\rightof{Programmation}{Gram}--
+****************** Fin code ******************
+
+
+****************** Code 59 ******************
+\catcode`\@=11 % "@" devient une lettre
+
+\def\rightof#1#2{%
+ \ifin{#1}{#2}%
+ {% si #1 contient le #2
+ \def\right@of##1#2##2\@nil{##2}% définit la macro auxiliaire
+ \right@of#1\@nil% appelle la macro auxiliaire
+ }%
+ {}% sinon, ne rien faire
+}
+\catcode`\@=12 %"@" redevient un signe
+--\rightof{Programmation}{g}--\par
+--\rightof{Programmation}{z}--\par
+--\rightof{Programmation}{o}--
+****************** Fin code ******************
+
+
+****************** Code 60 ******************
+\catcode`\@=11
+\def\leftof#1#2{%
+ \def\leftof@i##1#2##2\@nil{##1}% renvoie ce qui est à gauche de #2
+ \leftof@i #1#2\@nil% ajoute #2 après #1
+}
+\catcode`\@=12
+--\leftof{Programmation}{ram}--\par
+--\leftof{Programmation}{zut}--
+****************** Fin code ******************
+
+
+****************** Code 61 ******************
+\catcode`\@=11
+\def\leftof#1#2{%
+ \def\leftof@i##1#2##2\@nil{\leftof@ii##1#1\@nil}%
+ \def\leftof@ii##1#1##2\@nil{##1}%
+ \leftof@i #1#2\@nil
+}
+\catcode`\@=12
+--\leftof{Programmation}{ram}--\par
+--\leftof{Programmation}{zut}--
+****************** Fin code ******************
+
+
+****************** Code 62 ******************
+\catcode`\@=11
+\def\rightof#1#2{%
+ \def\rightof@i##1#2##2\@nil{\rightof@ii##2#2\@nil}%
+ \def\rightof@ii##1#2##2\@nil{##1}%
+ \rightof@i#1#2\@nil
+}
+\catcode`\@=12
+--\rightof{Programmation}{g}--\par
+--\rightof{Programmation}{z}--
+****************** Fin code ******************
+
+
+****************** Code 63 ******************
+\catcode`\@=11
+\def\gobto@@nil#1\@@nil{}
+\def\rightof#1#2{%
+ \def\right@of##1#2##2\@nil{##2}% définit la macro auxiliaire
+ \right@of#1\gobto@@nil#2\gobto@@nil\@@nil\@nil% appelle la macro auxiliaire
+}
+\catcode`\@=12
+\rightof{abc{1}def}{c{1}d}% affiche ce qui est à droite de "c{1}d"
+****************** Fin code ******************
+
+
+****************** Code 64 ******************
+\expandafter\def\csname ab1c\endcsname{Bonjour}
+Texte de remplacement de la macro : \csname ab1c\endcsname
+****************** Fin code ******************
+
+
+****************** Code 65 ******************
+\def\defname#1{\expandafter\def\csname#1\endcsname}
+\defname{ab1c}{Bonjour}
+Texte de remplacement de \litterate|\abc1| : \csname ab1c\endcsname\par
+\def\letname#1{\expandafter\let\csname#1\endcsname}
+\def\foo{abc}\letname{foo1}=\foo% rend la macro "\foo1" égale à \foo
+Texte de remplacement de \litterate|\foo1| : \csname foo1\endcsname
+****************** Fin code ******************
+
+
+****************** Code 66 ******************
+ \def\foo{Bonjour}\catcode`@=11
+Résultat : \firstto@nil\foo\@nil
+\catcode`@=12
+****************** Fin code ******************
+
+
+****************** Code 67 ******************
+\def\foo{Bonjour}\catcode`@=11
+Résultat : \expandafter\firstto@nil\foo\@nil
+\catcode`@=12
+****************** Fin code ******************
+
+
+****************** Code 68 ******************
+\newtoks\testtoks \testtoks={Bonjour}
+\catcode`@=11
+Résultat : \expandafter\firstto@nil\the\testtoks\@nil
+\catcode`@=12
+****************** Fin code ******************
+
+
+****************** Code 69 ******************
+\def\foo{bonjour}
+a) \>\csname foo\endcsname< \par
+b) \>\foo< \par
+c) \expandafter\>\foo< \par
+d) \>\foo\foo< \par
+e) \expandafter\>\foo\foo<
+****************** Fin code ******************
+
+
+****************** Code 70 ******************
+\def\foo{Bonjour} \expandafter\>\expandafter\foo\foo<
+****************** Fin code ******************
+
+
+****************** Code 71 ******************
+\def\foo{Bonjour}
+\expandafter\def\expandafter\bar\expandafter{\expandafter\foo\foo}
+\meaning\bar
+****************** Fin code ******************
+
+
+****************** Code 72 ******************
+\def\foo{\foo Bonjour}% définition récursive
+\foo% l'exécution provoque un dépassement de la capacité de la pile
+****************** Fin code ******************
+
+
+****************** Code 73 ******************
+\long\def\addtomacro#1#2{%
+ \expandafter\def\expandafter#1\expandafter{#1#2}%
+}
+\def\foo{Bonjour}
+\addtomacro\foo{ le monde}
+\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 74 ******************
+\long\def\eaddtomacro#1#2{%
+ \expandafter\addtomacro\expandafter#1\expandafter{#2}%
+}
+\def\foo{Bonjour} \def\world{ le monde}
+\eaddtomacro\foo\world
+\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 75 ******************
+\long\def\addtotoks#1#2{#1= \expandafter{\the#1#2}}
+\newtoks\bar
+\bar={Bonjour}% met "Bonjour" dans le registre
+\addtotoks\bar{ le monde}% ajoute " le monde"
+\the\bar% affiche le registre
+****************** Fin code ******************
+
+
+****************** Code 76 ******************
+\long\def\eaddtotoks#1#2{\expandafter\addtotoks\expandafter#1\expandafter{#2}}
+\bar={Bonjour}
+\def\macrofoo{ le monde}
+\eaddtotoks\bar\macrofoo
+\the\bar
+****************** Fin code ******************
+
+
+****************** Code 77 ******************
+\def\X{Bonjour} \def\Y{\X}
+\expandafter\expandafter\expandafter\>\Y<
+****************** Fin code ******************
+
+
+****************** Code 78 ******************
+\long\def\swaparg#1#2{#2{#1}}
+\long\def\expsecond#1#2{\expandafter\swaparg\expandafter{#2}{#1}}
+\def\X{Bonjour}
+\expandafter\expandafter\expandafter\expandafter
+\expandafter\expandafter\expandafter
+\>\expsecond{\X}{\X}<
+****************** Fin code ******************
+
+
+****************** Code 79 ******************
+\expsecond{\def\foo}\secondoftwo{A}{B}
+****************** Fin code ******************
+
+
+****************** Code 80 ******************
+\expsecond{\def\foo}{\secondoftwo{A}{B}}
+\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 81 ******************
+\def\exptwoargs#1#2{\expsecond{\expsecond{#1}{#2}}}
+\def\foo{Bonjour}\def\bar{ le monde}
+\def\displaytwoargs#1#2{\detokenize{#1#2}}% affiche tels quels les arguments
+\exptwoargs\displaytwoargs\foo\bar
+****************** Fin code ******************
+
+
+****************** Code 82 ******************
+\def\aa{Bonjour}\def\bb{\aa}
+\def\cc{ le monde}
+\edef\foo{\bb\cc}
+\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 83 ******************
+\def\aa{Bonjour } \def\bb{\aa} \def\cc{le } \def\dd{ monde}
+\edef\ee#1{\bb\cc#1 !!!}
+\meaning\ee\par
+\expandafter\>\ee{\dd}<
+****************** Fin code ******************
+
+
+****************** Code 84 ******************
+\def\foo{123xyz}
+a) signification du 1-développement d'un \litterate-\noexpand- :
+ \expandafter\meaning\noexpand\foo
+
+b) exécution d'un \litterate-\noexpand- : \noexpand\foo% identique à \relax
+
+c) 1-développement de \litterate-\noexpand- dans le texte de remplacement de
+ \litterate-\bar- :
+ \expandafter\def\expandafter\bar\expandafter{\noexpand\foo}
+ \meaning\bar
+****************** Fin code ******************
+
+
+****************** Code 85 ******************
+\def\aa{Bonjour}\def\bb{\aa}\def\cc{\bb}
+a) \edef\foo{\aa\noexpand\bb\cc}\meaning\foo \qquad b) exécution : \foo\par
+c) \edef\foo{\aa\noexpand{\aa\cc}}\meaning\foo\qquad d) exécution : \foo
+****************** Fin code ******************
+
+
+****************** Code 86 ******************
+\def\aa{Bonjour}\def\bb{Au revoir}
+a) \edef\truc{\aa\noexpand\bb\noexpand\aa\bb}\meaning\truc \par
+b) \edef\truc{\aa\unexpanded{\bb\aa}\bb}\meaning\truc
+****************** Fin code ******************
+
+
+****************** Code 87 ******************
+\def\aa{Bonjour}\def\bb{Au revoir}
+\toks0={\aa\bb}
+\edef\foo{\aa\the\toks0 \bb}
+\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 88 ******************
+\def\aa{Bonjour}
+\protected\def\bb{ le}% \ bb est protégée !
+\def\cc{ monde}
+
+\edef\foo{\aa\bb\cc}
+Signification de \string\foo~: \meaning\foo \par
+Exécution de \string\foo~: \foo
+****************** Fin code ******************
+
+
+****************** Code 89 ******************
+\def\aa{Bonjour}
+\protected\def\bb{ le}
+\def\cc{ monde}
+
+\edef\foo{\expandafter\aa\bb\cc}% le \expandafter 1-développe \bb
+\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 90 ******************
+\def\foo{Bonjour}% définition
+\foo% exécution
+****************** Fin code ******************
+
+
+****************** Code 91 ******************
+\def\foo{abc}
+\edef\bar{\def\foo{Bonjour}\foo}
+\meaning\bar
+****************** Fin code ******************
+
+
+****************** Code 92 ******************
+\def\foo{abc}
+\edef\bar{\def\noexpand\foo{Bonjour}\noexpand\foo}
+Signification : \meaning\bar\par
+Exécution : \bar
+****************** Fin code ******************
+
+
+****************** Code 93 ******************
+\long\def\>#1<{\detokenize{#1}}
+\expandafter\>% provoque le 1-développement de :
+\csname foo\expandafter\endcsname
+\csname bar\expandafter\endcsname
+\csname wee\expandafter\endcsname
+\csname fin\endcsname<
+****************** Fin code ******************
+
+
+****************** Code 94 ******************
+\long\def\>#1<{\detokenize{#1}}
+\def\fin{YY} \def\wee{\weeA} \def\weeA{XX}
+\expandafter\>%
+\csname foo\expandafter\endcsname
+\csname bar\expandafter\expandafter\expandafter\expandafter
+ \expandafter\expandafter\expandafter\endcsname
+\csname wee\expandafter\expandafter\expandafter\endcsname
+\csname fin\endcsname<
+****************** Fin code ******************
+
+
+****************** Code 95 ******************
+\long\def\>#1<{\detokenize{#1}}
+\def\fin{YYY} \def\wee{\weeA} \def\weeA{XXX}
+\expandafter\expandafter\expandafter\expandafter
+\expandafter\expandafter\expandafter
+\>%
+\expandafter\expandafter\expandafter\expandafter
+\expandafter\expandafter\expandafter
+\foo
+\expandafter\expandafter\expandafter\expandafter
+\expandafter\expandafter\expandafter
+\bar
+\expandafter\wee\fin<
+****************** Fin code ******************
+
+
+****************** Code 96 ******************
+\chardef\foo65
+a) |\foo|\qquad % employée seule, \foo affiche un A
+b) |\number\foo|\qquad % si TeX lit un nombre, \foo est le nombre 65
+****************** Fin code ******************
+
+
+****************** Code 97 ******************
+\mathchardef\foo4944
+a) |$\foo$|\qquad % en mode math, affiche le signe "somme" (uniquement en mode maths)
+b) |\number\foo|\qquad % si TeX lit un nombre, \foo est 4944
+****************** Fin code ******************
+
+
+****************** Code 98 ******************
+a) "\romannumeral 27 "\quad
+b) "\romannumeral 4687 "\quad
+c) "\romannumeral 0 "\quad% 0 donc développement vide
+d) "\romannumeral -2014 "\quad% négatif donc développement vide
+e) \def\foo{7}\def\bar{\foo}%
+ "\romannumeral \foo\foo\bar"\quad% 777
+f) "\romannumeral 1\bar8\foo"\quad% 1787
+g) "\romannumeral 1\bar8 \foo"% 178 (stoppé par l'espace) puis 7
+****************** Fin code ******************
+
+
+****************** Code 99 ******************
+\long\def\>#1<{\detokenize{#1}}
+\def\swaparg#1#2{#2{#1}}
+\def\expsecond#1#2{\expandafter\swaparg\expandafter{#2}{#1}}
+\def\X{Bonjour}
+\expandafter\expandafter\expandafter\expandafter
+\expandafter\expandafter\expandafter
+\>\expsecond\X\X<
+****************** Fin code ******************
+
+
+****************** Code 100 ******************
+\long\def\>#1<{\detokenize{#1}}
+\def\swaparg#1#2{0 #2{#1}}% le "0 " stoppe ici le développement maximal
+\def\expsecond#1#2{\expandafter\swaparg\expandafter{#2}{#1}}
+\def\X{Bonjour}
+\expandafter\>\romannumeral\expsecond\X\X<
+****************** Fin code ******************
+
+
+****************** Code 101 ******************
+\long\def\>#1<{\detokenize{#1}}
+\def\swaparg#1#2{#2{#1}}
+\def\expsecond#1#2{\expandafter\swaparg\expandafter{#2}{#1}}
+\def\X{Bonjour}
+\expandafter\>\romannumeral\expsecond{0 \X}\X<
+****************** Fin code ******************
+
+
+****************** Code 102 ******************
+\long\def\>#1<{\detokenize{#1}}
+\def\X{Bonjour}
+\catcode`\@=11
+\expandafter\>\romannumeral\expsecond{\z@\X}{\X}<
+\catcode`\@=12
+****************** Fin code ******************
+
+
+****************** Code 103 ******************
+\def\newunivar#1{\def#1[##1]{\csname\string#1[##1]\endcsname}}
+\def\defunivar#1[#2]{\defname{\string#1[#2]}}
+\newunivar\foobar
+\defunivar\foobar[0]{abcd}
+\defunivar\foobar[1]{1 23}
+\defunivar\foobar[3]{XY Z}
+Cellule 0 : \foobar[0]\par
+Cellule 1 : \foobar[1]\par
+Cellule 2 : \foobar[2]\par% cellule non définie : \foobar[2] donne \relax
+Cellule 3 : \foobar[3]\bigbreak
+
+\newunivar\client
+\defunivar\client[nom]{M. Raymond {\sc Tartempion}}
+\defunivar\client[adr]{5 rue de la paix}
+\defunivar\client[cod_post]{75000}
+\defunivar\client[ville]{Paris}
+% fin des définitions, affichage de l'adresse :
+\client[nom]\par
+\client[adr]\par
+\client[cod_post] \client[ville]
+****************** Fin code ******************
+
+
+****************** Code 104 ******************
+\newcount\foo \newcount\bar
+\foo=42 \bar=\foo \string\bar\ vaut : \the\bar \par
+\bar=\foo57 \string\bar\ vaut : \number\bar\par
+\bar=2014 \string\bar\ vaut : \romannumeral\bar
+****************** Fin code ******************
+
+
+****************** Code 105 ******************
+\newcount\foo
+\def\fonction#1{%
+ \foo=#1 % assigne l'entier #1 au compteur puis
+ \multiply\foo3 % multiplie par 3
+ \advance\foo-4 % soustrait 4
+ \multiply\foo\foo% élève au carré (lmultiplie \foo par lui même)
+ \number\foo% enfin, afficher le résultat
+}
+a) \fonction5\qquad b) \fonction{-13}
+****************** Fin code ******************
+
+
+****************** Code 106 ******************
+\newcount\foo
+\def\fonction#1{%
+ \foo=#1 \multiply\foo3 \advance\foo-4 \multiply\foo\foo
+ \number\foo}
+\edef\bar{\fonction{5}}%
+a) Signification : \meaning\bar\par
+b) Exécution : \bar
+****************** Fin code ******************
+
+
+****************** Code 107 ******************
+a) \number\numexpr2+3*4\relax\qquad
+b) \romannumeral\numexpr2*3\relax\qquad
+c) \number\numexpr(6-2*4)*(1-(2-6))\relax\qquad
+d) \number\numexpr7/4\relax\qquad %7/4 vaut 1,75
+e) \edef\foo{\number\numexpr2+3*4\relax}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 108 ******************
+\number\numexpr3*\numexpr1+2*5\relax+2\relax
+****************** Fin code ******************
+
+
+****************** Code 109 ******************
+\def\fonction#1{\number\numexpr(3*#1-4)*(3*#1-4)\relax}
+a) \fonction5\qquad
+b) \fonction{-13}\qquad
+c) \edef\bar{\fonction5}\meaning\bar
+****************** Fin code ******************
+
+
+****************** Code 110 ******************
+\def\fonction#1{\exparg\carre{\number\numexpr3*#1-4\relax}}
+\def\carre#1{\number\numexpr#1*#1\relax}
+a) \fonction{5}\qquad
+b) \fonction{-13}\qquad
+c) \edef\bar{\fonction5}\meaning\bar
+****************** Fin code ******************
+
+
+****************** Code 111 ******************
+\def\truncdiv#1#2{\numexpr(#1-(#2-1)/2)/#2\relax}
+8/3 :
+a) \number\truncdiv83\qquad % doit donner 2
+b) \number\truncdiv{-8}3\qquad % doit donner -2
+c) \number\truncdiv8{-3}\qquad % doit donner -2
+d) \number\truncdiv{-8}{-3}\par % doit donner 2
+4/3 :
+e) \number\truncdiv43\qquad % doit donner 1
+f) \number\truncdiv{-4}3\qquad % doit donner -1
+g) \number\truncdiv4{-3}\qquad % doit donner -1
+h) \number\truncdiv{-4}{-3} % doit donner 1
+****************** Fin code ******************
+
+
+****************** Code 112 ******************
+a) \ifnum 15=14 vrai\else faux\fi\qquad% test faux
+b) \ifnum4<200 vrai\else faux\fi\qquad% test vrai
+c) \newcount\foo \foo=9
+ \ifnum\foo>9 nombre\else chiffre\fi% test faux
+****************** Fin code ******************
+
+
+****************** Code 113 ******************
+\long\def\>#1<{\detokenize{#1}}
+\expandafter\>\ifnum5=5 vrai\else faux\fi<\par% test vrai
+\expandafter\>\ifnum5=6 vrai\else faux\fi<% test faux
+\fi\fi% rétablir l'équilibre \ifnum et \fi
+****************** Fin code ******************
+
+
+****************** Code 114 ******************
+\def\numtest#1{%
+ \ifnum#1>-10
+ \ifnum#1<10
+ chiffre%
+ \else
+ nombre positif%
+ \fi
+ \else
+ nombre négatif%
+ \fi
+}
+a) \numtest{3}\qquad
+b) \numtest{-67}\qquad
+c) \numtest{-8}\qquad
+d) \numtest{21}\qquad
+e) \edef\foo{\numtest{2014}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 115 ******************
+\def\normalise#1{%
+ \ifnum#1>-1 % ne faire quelque chose que si #1 est positif ou nul
+ \ifnum#1<100 % si <100
+ 0% afficher un 0
+ \ifnum#1<10 % si <10
+ 0%afficher un autre 0
+ \fi
+ \fi
+ \number#1 %afficher le nombre
+ \fi}% affiche le nombre
+a) \normalise{749}\qquad
+b) \normalise{0017}\qquad
+c) \normalise8\qquad
+d) \normalise{1789}\qquad
+e) \normalise{-18}\qquad
+f) \normalise{0}
+****************** Fin code ******************
+
+
+****************** Code 116 ******************
+\def\mois#1{%
+ \ifcase#1\relax
+ \char`\#\char`\#% afficher "##" si argument = 0
+ \or janvier\or f\'evrier\or mars\or avril%
+ \or mai\or juin\or juillet\or aout%
+ \or septembre\or octobre\or novembre\or d\'ecembre%
+ \else
+ \char`\#\char`\#% afficher "##" sinon
+ \fi
+}
+a) \mois{-4}\qquad
+b) \mois{3}\qquad
+c) \mois{11}\qquad
+d) \mois{20}\qquad
+e) \edef\foo{\mois{\month}}\meaning\foo% mois en cours
+****************** Fin code ******************
+
+
+****************** Code 117 ******************
+\def\ifletter#1#2#3{%
+ \ifnum`#1<`a% si le caractère est avant "a"
+ #3% exécuter "<code faux>"
+ \else% sinon
+ \ifnum`#1>`z% si le caractère est après "z"
+ #3% exécuter "<code faux>"
+ \else% dans tous les autres cas
+ #2% "#1" est une lettre : exécuter "<code vrai>"
+ \fi
+ \fi}
+a) \ifletter{4}{vrai}{faux}\qquad
+b) \ifletter{t}{vrai}{faux}\qquad
+c) \ifletter{D}{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 118 ******************
+\def\ifletter#1{%
+ \ifnum`#1<`a
+ \expandafter\secondoftwo% \expandafter 1-développe "\else...\fi"
+ \else
+ \ifnum`#1>`z
+ \expandafter\expandafter\expandafter% 1-développe "\else...\fi" puis "\fi"
+ \secondoftwo
+ \else
+ \expandafter\expandafter\expandafter%1-développe "\fi" puis "\fi"
+ \firstoftwo
+ \fi
+ \fi}
+a) \ifletter{4}{vrai}{faux}\qquad
+b) \ifletter{t}{vrai}{faux}\qquad
+c) \ifletter{D}{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 119 ******************
+\def\ifletter#1#2#3{%
+ \romannumeral % <- initie le développement maximal
+ \ifnum`#1<`a
+ \expandafter\secondoftwo
+ \else
+ \ifnum`#1>`z
+ \expandafter\expandafter\expandafter\secondoftwo
+ \else
+ \expandafter\expandafter\expandafter\firstoftwo
+ \fi
+ \fi{0 #2}{0 #3}% <- "0 " stoppe le développement maximal
+}
+\long\def\>#1<{\detokenize{#1}}
+a) \expandafter\expandafter\expandafter\>\ifletter{0}{vrai}{faux}<\qquad
+b) \expandafter\expandafter\expandafter\>\ifletter{x}{vrai}{faux}<
+****************** Fin code ******************
+
+
+****************** Code 120 ******************
+\def\ifletter#1{%
+ \ifnum`#1<`a
+ \let\donext=\secondoftwo
+ \else
+ \ifnum`#1>`z
+ \let\donext=\secondoftwo
+ \else
+ \let\donext=\firstoftwo
+ \fi
+ \fi
+ \donext% exécuter l'action décidée ci-dessus
+}
+a) \ifletter{4}{vrai}{faux}\qquad
+b) \ifletter{t}{vrai}{faux}\qquad
+c) \ifletter{D}{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 121 ******************
+\def\ifletter#1{%
+ \csname
+ \ifnum`#1<`a
+ second% <- commenter la fin de ligne pour éviter un
+ \else% espace parasite dans le nom de la macro créée
+ \ifnum`#1>`z
+ second%
+ \else
+ first%
+ \fi
+ \fi
+ oftwo%
+ \endcsname
+}
+a) \ifletter{4}{vrai}{faux}\qquad
+b) \ifletter{t}{vrai}{faux}\qquad
+c) \ifletter{D}{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 122 ******************
+\def\ifletter#1{%
+ \lowercase{\csname
+ \ifnum`#1<`a second%
+ \else
+ \ifnum`#1>`z second\else first\fi
+ \fi
+ oftwo\endcsname
+ }%
+}
+a) \ifletter{4}{vrai}{faux}\qquad
+b) \ifletter{t}{vrai}{faux}\qquad
+c) \ifletter{D}{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 123 ******************
+\edef\foo{\lowercase{AbCd}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 124 ******************
+\def\ifletter#1{%
+ \csname
+ \ifnum`#1<`A second%
+ \else
+ \ifnum`#1<`Z first%
+ \else
+ \ifnum`#1>`a
+ \ifnum`#1<`z
+ first%
+ \else
+ second%
+ \fi
+ \else
+ second%
+ \fi
+ \fi
+ \fi
+ oftwo%
+ \endcsname
+}
+a) \ifletter{4}{vrai}{faux}\qquad
+b) \ifletter{t}{vrai}{faux}\qquad
+c) \ifletter{D}{vrai}{faux}\qquad
+d) \edef\foo{\ifletter{x}{vrai}{faux}}\meaning\foo\qquad
+e) \edef\foo{\ifletter{=}{vrai}{faux}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 125 ******************
+\def\ifinside#1[#2,#3]{%
+ \csname
+ \ifnum#1<#2 second% si n<a, <code faux>
+ \else
+ \ifnum#1>#3 second% si n>b, <code faux>
+ \else first% sinon, <code vrai>
+ \fi
+ \fi
+ oftwo%
+ \endcsname
+}
+a) \ifinside 3[1,8]{oui}{non}\qquad
+b) \ifinside -7[-20,-11]{oui}{non}\qquad
+c) \ifinside 9[0,6]{oui}{non}\qquad
+d) \ifinside -1[-5,1]{oui}{non}
+****************** Fin code ******************
+
+
+****************** Code 126 ******************
+\def\ifinside#1[#2,#3]{%
+ \ifnum\numexpr(#1-#2)*(#1-#3)\relax>0
+ \expandafter\secondoftwo
+ \else
+ \expandafter\firstoftwo
+ \fi
+}
+a) \ifinside 3[1,8]{oui}{non}\qquad
+b) \ifinside -7[-20,-11]{oui}{non}\qquad
+c) \ifinside 9[0,6]{oui}{non}\qquad
+d) \ifinside -1[-5,1]{oui}{non}
+****************** Fin code ******************
+
+
+****************** Code 127 ******************
+\def\absval#1{%
+ \ifnum#1<0 \number-#1
+ \else \number#1
+ \fi}
+a) \absval{-87}\qquad b) \absval{75}\qquad c) \absval{0}
+****************** Fin code ******************
+
+
+****************** Code 128 ******************
+\def\absval#1{\number\ifnum#1<0 -\fi#1 }
+a) \absval{-87}\qquad b) \absval{75}\qquad c) \absval{0}
+****************** Fin code ******************
+
+
+****************** Code 129 ******************
+\def\absval#1{\number\ifnum\numexpr#1\relax<0 -\fi\numexpr#1\relax}
+a) \absval{-87}\qquad
+b) \absval{75}\qquad
+c) \absval{0}\qquad
+d) \absval{-20+13}\qquad% -7 affiché 7
+e) \absval{5-3*(-4)+10-50}% -23 affiché 23
+****************** Fin code ******************
+
+
+****************** Code 130 ******************
+\catcode`\@11
+\def\absval#1{\exparg\absval@i{\number\numexpr#1\relax}}
+\def\absval@i#1{\number\ifnum#1<\z@-\fi#1 }
+\catcode`\@12
+a) \absval{-87}\qquad
+b) \absval{75}\qquad
+c) \absval{0}\qquad
+d) \absval{-20+13}\qquad% résultat -7 qui est affiché 7
+e) \absval{5-3*(-4)+10-50}% résultat -23 qui est affiché 23
+****************** Fin code ******************
+
+
+****************** Code 131 ******************
+\def\sgn#1{\ifnum#1<0 -\fi}
+\def\truncdiv#1#2{%
+ \numexpr
+ \sgn{#1}\sgn{#2}1*% multiplie le quotient ci-dessous par +1 ou -1
+ (2*\absval{#1}-\absval{#2}+1)/(2*\absval{#2})
+ \relax
+}
+a) \number\truncdiv{-8}3\qquad
+b) \number\truncdiv{-8}{-3}\qquad
+c) \number\truncdiv8{-3}\qquad
+d) \number\truncdiv{0}{-5}
+****************** Fin code ******************
+
+
+****************** Code 132 ******************
+\catcode`\@11
+\def\sgn#1{\ifnum#1<\z@-\fi}
+\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
+}
+\catcode`\@12
+a) \number\truncdiv{-8}3\qquad
+b) \number\truncdiv{-8}{-3}\qquad
+c) \number\truncdiv8{-3}\qquad
+d) \number\truncdiv{0}{-5}\qquad
+e) \number\truncdiv{20+2*3}{4-5*2}% 26/(-6) doit donner -4
+****************** Fin code ******************
+
+
+****************** Code 133 ******************
+\def\siecle#1{%
+ \unless\ifnum#1=0 % ne faire quelque chose que si #1 différent de 0
+ \uppercase\expandafter{\romannumeral\absval{#1}}% chiffres romains majuscules
+ \raise 1ex \hbox{e\ifnum\absval{#1}=1 r\fi} siècle% affiche l'exposant puis "siècle"
+ \ifnum#1<0 {} av. J.-C.\fi% affiche si besoin "av. J.-C."
+ \fi
+}
+a) \siecle{19}\qquad
+b) \siecle{-3}\qquad
+c) \siecle{1}\qquad
+d) \siecle{0}\qquad
+e) \siecle{-1}
+****************** Fin code ******************
+
+
+****************** Code 134 ******************
+\catcode`\@11
+\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 ":"
+\catcode`\@12
+a) \hdif{10:51:20}{9:20:10}\par
+b) \hdif{14:20:0}{13:50:0}\par
+c) \hdif{7:50:20}{5:50:20}\par
+d) \hdif{7:50:10}{6:50:20}\par
+e) \hdif{20:00:00}{19:59:15}\par
+f) \hdif{17:13:15}{14:12:45}
+****************** Fin code ******************
+
+
+****************** Code 135 ******************
+\newcount\ii
+\catcode`\@=11
+\def\ncar#1#2{%
+ \ii=0 % initialise le compteur à 0
+ \def\val@max{#1}% stocke la valeur maximale
+ \def\car@save{#2}% stocke le caractère à afficher
+ \ncar@i% appelle la macro récursive
+}
+\def\ncar@i{%
+ \ifnum\ii<\val@max% si la valeur maxi n'est pas atteinte
+ \car@save% afficher le caractère
+ \advance\ii 1 % incrémenter le compteur
+ \ncar@i% recommencer
+ \fi
+}
+\catcode`\@=12
+\ncar{7}{*}\par
+\ncar{13}W\par
+\ncar{10}{foobar }
+****************** Fin code ******************
+
+
+****************** Code 136 ******************
+\newcount\ii
+\catcode`\@=11
+\def\ncar#1#2{%
+ \ii=0 % initialise le compteur à 0
+ \def\val@max{#1}% stocke la valeur maximale
+ \def\car@save{#2}% stocke le caractère à afficher
+ \ncar@i% appelle la macro récursive
+}
+\def\ncar@i{%
+ \ifnum\ii<\val@max% si la valeur maxi n'est pas atteinte
+ \car@save% afficher le caractère
+ \advance\ii 1 % incrémenter le compteur
+ \ncar@i% recommencer
+ \fi
+}
+\catcode`\@=12
+\ncar{2}{3a}
+****************** Fin code ******************
+
+
+****************** Code 137 ******************
+a) \romannumeral 9600 \qquad b) \romannumeral 12000
+****************** Fin code ******************
+
+
+****************** Code 138 ******************
+\def\ncar#1#2{%
+ \begingroup
+ \lccode`\m=`#2 % dans \lowercase, les "m" deviennent des "#2"
+ \lowercase\expandafter{\expandafter\endgroup\romannumeral#1000 }%
+}
+a) \ncar{7}{*}\qquad
+b) \ncar{15}{\%}\qquad
+c) \ncar{10}{4}
+****************** Fin code ******************
+
+
+****************** Code 139 ******************
+\def\ncar#1#2{%
+ \ifnum#1>0 % <- espace après le "0"
+ #2% affiche le caractère
+ \exparg\ncar{\number\numexpr#1-1}{#2}% appel récursif
+ \fi
+}
+a) \ncar{7}{*}\qquad
+b) \ncar{13}{W}\qquad
+c) \edef\foo{\ncar{5}{7}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 140 ******************
+\def\ncar#1#2{%
+ \ifnum#1>0 \expandafter\identity% si #1>0 exécuter...
+ \else \expandafter\gobone% ...sinon manger
+ \fi% ce qui est entre ces accolades :
+ {#2% afficher le caractère
+ \exparg\ncar{\number\numexpr#1-1}{#2}% appel récursif
+ }%
+}
+a) \ncar{7}{*}\qquad
+b) \ncar{13}{W}\qquad
+c) \edef\foo{\ncar{5}X}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 141 ******************
+\long\def\antefi#1\fi{\fi#1}
+\def\ncar#1#2{%
+ \ifnum#1>0
+ \antefi% comme si le \fi était "déplacé" ici
+ #2% affiche le caractère
+ \exparg\ncar{\number\numexpr#1-1}{#2}% appel récursif
+ \fi
+}
+a) \ncar{7}{*}\qquad
+b) \ncar{13}{W}\qquad
+c) \edef\foo{\ncar{5}X}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 142 ******************
+\long\def\afterfi#1#2\fi{#2\fi#1}
+\def\ncar#1#2{%
+ \ifnum#1>0
+ \afterfi{\exparg\ncar{\number\numexpr#1-1}{#2}}% <- argument renvoyé après le \fi
+ #2% <- ceci reste avant le \fi
+ \fi
+}
+a) \ncar{7}{*}\qquad
+b) \ncar{13}{W}\qquad
+c) \edef\foo{\ncar{5}X}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 143 ******************
+\def\ncar#1#2{%
+ \ifnum#1>0
+ #2% afficher le caractère
+ \expandafter\ncar\expandafter% le pont d'\expandafter lance \number et \numexpr
+ {\number\numexpr#1-1\expandafter}% le dernier \expandafter mange "\else...\fi"
+ \else
+ \expandafter\gobone% si le test est faux, manger {#2} ci-dessous
+ \fi{#2}%
+}
+a) \ncar{7}{*}\qquad
+b) \ncar{13}{W}\qquad
+c) \edef\foo{\ncar{5}X}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 144 ******************
+\catcode`\@11
+\def\ncar#1#2{%
+ \def\ncar@i##1{%
+ \ifnum##1<#1 % si i < valeur maxi
+ #2% afficher le caractère
+ \exparg\ncar@i{\number\numexpr##1+1\expandafter}% puis recommencer avec i+1
+ \fi% \fi mangé par le \expandafter en fin de zone de \numexpr
+ }%
+ \ncar@i{0}% commence avec la valeur "compteur" 0
+}
+\catcode`\@12
+a) \ncar{7}{*}\qquad
+b) \ncar{13}{W}\qquad
+c) \ncar{5}{X}
+****************** Fin code ******************
+
+
+****************** Code 145 ******************
+\catcode`\@11 \newcount\compte@cnt
+\def\compte#1{%
+ \def\val@max{#1}\compte@cnt=0 % effectue les initialisations
+ \compte@i% appelle la macro principale
+}
+\def\compte@i{%
+ \ifnum\compte@cnt<\val@max% si compteur < valeur maxi
+ \advance\compte@cnt1 % incrémenter le compteur
+ \number\compte@cnt, % afficher le nombre, la virgule et l'espace
+ \expandafter\compte@i %recommencer
+ \fi
+}
+\catcode`\@12
+a) \compte{9}\qquad
+b) \compte{-4}\qquad
+c) \compte{2}
+****************** Fin code ******************
+
+
+****************** Code 146 ******************
+\catcode`\@11 \newcount\compte@cnt
+\def\compte#1{\def\val@max{#1}\compte@cnt=0 \compte@i}
+\def\compte@i{%
+ \ifnum\compte@cnt<\val@max\relax
+ \advance\compte@cnt1
+ \number\compte@cnt
+ \ifnum\compte@cnt<\val@max , \fi% afficher ", " si le maxi n'est pas atteint
+ \expandafter\compte@i
+ \fi
+}
+\catcode`\@12
+a) \compte{9}\qquad
+b)\compte{-4}\qquad
+c) \compte{2}
+****************** Fin code ******************
+
+
+****************** Code 147 ******************
+\catcode`\@11 \newcount\compte@cnt
+\def\compte#1{%
+ \ifnum#1>0 % ne faire quelque chose que si l'argument est positif
+ \def\val@max{#1}\compte@cnt=1 % faire les initialisations
+ \expandafter\compte@i% appeller la macro récrusive
+ \fi
+}
+\def\compte@i{%
+ \number\compte@cnt\relax % afficher le nombre
+ \ifnum\compte@cnt<\val@max\relax % si valeur maxi n'est pas atteinte
+ , % afficher la virgule et l'espace
+ \advance\compte@cnt1 % incrémenter le compteur
+ \expandafter\compte@i % recommencer
+ \fi
+}
+\catcode`\@12
+a) \compte{9}\qquad
+b) \compte{-4}\qquad
+c) \compte{2}
+****************** Fin code ******************
+
+
+****************** Code 148 ******************
+\catcode`\@11
+\def\compte#1{%
+ \ifnum#1>\z@% ne faire quelque chose que si #1 > 0
+ \antefi\compte@i{1}{#1}%
+ \fi
+}
+
+\def\compte@i#1#2{%
+ #1% afficher le nombre
+ \ifnum#1<#2 % si le maxi n'est pas atteint
+ \expandafter\identity% exécuter...
+ \else
+ \expandafter\gobone% sinon, manger...
+ \fi% le code entre accolades ci-dessous
+ {, % afficher la virgule et l'espace
+ \exparg\compte@i{\number\numexpr#1+1}{#2}% appel récursif
+ }%
+}
+\catcode`\@12
+a) \compte{9}\qquad
+b) \compte{-4}\qquad
+c) \edef\foo{\compte{2}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 149 ******************
+\catcode`\@11
+\def\compte#1{%
+ \ifnum#1>\z@% ne faire quelque chose que si #1 > 0
+ \antefi\compte@i{1}{#1}%
+ \fi
+}
+
+\def\compte@i#1#2{%
+ #1% afficher le nombre
+ \ifnum#1<#2 % si le maxi n'est pas atteint
+ \antefi% déplace le \fi ici
+ , % affiche la virgule et l'espace
+ \exparg\compte@i{\number\numexpr#1+1}{#2}% appel récursif
+ \fi
+}
+\catcode`\@12
+a) \compte{9}\qquad
+b) \compte{-4}\qquad
+c) \edef\foo{\compte{2}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 150 ******************
+\catcode`\@11
+\def\for#1=#2to#3\do#4{% #1=\<macro> #2=n1 #3=n2 #4=<code>
+ \def#1{#2}% initialise la \<macro> à l'entier n1
+ \def\val@max{#3}% stocke n2
+ \def\loop@code{#4}% stocke le <code>
+ \for@i#1% appelle la macro récursive et passe la \<macro> en argument
+}
+\def\for@i#1{%
+ \unless\ifnum#1>\val@max\relax% tant que la \<macro> est <= n2
+ \loop@code% effectue le code précédemment sauvegardé
+ \edef#1{\number\numexpr#1+1}% incrémenter la \<macro>
+ \expandafter\for@i\expandafter#1% et recommencer après avoir mangé le \fi
+ \fi
+}
+\catcode`\@=12
+\for\ii=1to5\do{Maintenant \string\ii\ vaut : \ii.\endgraf}\medbreak
+"\for\ii=1to0\do{A}"\medbreak% boucle parcourue 0 fois
+"\for\ii=1to1\do{A}"\medbreak% boucle parcourue 1 fois
+\for\ii = 0 to 10 \do {[\ii]}.
+****************** Fin code ******************
+
+
+****************** Code 151 ******************
+\catcode`\@11
+\long\def\for#1=#2to#3\do#4{%
+ \def\for@i{%
+ \unless\ifnum#1>\val@max\relax% tant que la \<macro> <= n2
+ #4% code à exécuter
+ \edef#1{\number\numexpr#1+1}% incrémenter \<macro>
+ \expandafter\for@i% et recommencer après avoir mangé le \fi
+ \fi
+ }%
+ \edef#1{\number\numexpr#2\relax}% initialise la variable à n1
+ \edef\val@max{\number\numexpr#3\relax}% stocke n2
+ \for@i% appelle la sous-macro récursive
+}
+\catcode`\@=12
+\for\ii = 1 to 5 \do {Maintenant \string\ii\ vaut : \ii.\par}\medbreak
+"\for\ii=1to0\do{A}"\medbreak% boucle parcourue 0 fois
+"\for\ii=1to1\do{A}"\medbreak% boucle parcourue 1 fois
+\for\ii = 0 to 10 \do {[\ii]}.
+****************** Fin code ******************
+
+
+****************** Code 152 ******************
+\catcode`\@11
+\def\for#1=#2to#3\do#4#{%
+ \edef\for@increment{\number\numexpr0#4}% lit et normalise l'argument optionnel
+ \ifnum\for@increment=\z@% s'il est nul,
+ \edef\for@increment{% le redéfinir :
+ \ifnum\numexpr#3\relax<\numexpr#2\relax
+ -% ajoute un signe - si #3<#2
+ \fi
+ 1% devant "1"
+ }% \for@increment vaut donc 1 ou -1
+ \fi
+ \ifnum\numexpr\for@increment*(#3-#2)\relax<\z@% si l'argument est incompatible
+ \expandafter\firstoftwo% exécuter le 1er argument qui suit
+ \else
+ \expandafter\secondoftwo% sinon le second
+ \fi
+ {Incrément incompatible !\gobone %\gobone mangera le <code> qui à lire
+ }%
+ {\edef#1{\number\numexpr#2\relax}% initialise la \<macro>
+ \edef\cmp@sgn{\ifnum\for@increment<\z@<\else>\fi}% stocke "<" ou ">" pour plus tard
+ \expandafter\for@i\expandafter#1\expandafter% appelle la macro récursive
+ {\number\numexpr#3\relax}% et lui lui passe la \<macro> (#1) et n2 (#3)
+ }%
+}
+
+% #1 = \<macro> #2 = n2
+\long\def\for@i#1#2#3{% l'argument #3 (le <code>) est lu à ce moment-là
+ \def\for@ii{%
+ \unless\ifnum#1\cmp@sgn#2\relax% tant que la \<macro> n'a pas dépassé n2
+ #3% exécute le <code>
+ \edef#1{\number\numexpr#1+\for@increment}% incrémente la \<macro>
+ \expandafter\for@ii% recommence après avoir mangé le \fi
+ \fi
+ }%
+ \for@ii% appelle la sous-macro récursive
+}%
+\catcode`\@=12
+a) \for\ii = -4 to 7 \do{(\ii)}\par
+b) \for\jj = 20 to -50\do-10 {(\jj)}\par
+c) \for\xx = 8 to 185\do 20 {[\xx]}\par
+d) \for\yy = 0 to 10\do -2{(\yy)}\par
+e) "\for\ii = 1 to 0 \do1{XX}"\par
+f) "\for\ii = 1 to 1 \do{A}"\par% boucle parcourue 1 fois
+g) \for\ii=1to4\do{\for\jj=0to2\do{(\ii,\jj)}\par}% imbrication de boucles
+****************** Fin code ******************
+
+
+****************** Code 153 ******************
+\catcode`\@11
+\def\for#1=#2to#3\do#4#{%
+ \edef\for@increment{\number\numexpr0#4}% lit et normalise l'argument optionnel
+ \ifnum\for@increment=\z@% s'il est nul,
+ \edef\for@increment{% le redéfinir à -1 (si #3<#2) et 1 sinon
+ \ifnum\numexpr#3-#2\relax<\z@ -1\else 1\fi
+ }% \for@increment vaut donc 1 ou -1
+ \fi
+ \ifnum\numexpr\for@increment*(#3-#2)\relax<\z@
+ \expandafter\gobone% si argument optionnel incompatible, manger le {<code>}
+ \else
+ \edef#1{\number\numexpr#2}% 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
+ \ifnum\for@increment<\z@ <\else >\fi% #2=signe de comparaison
+ {\for@increment}% #3=incrément
+ \noexpand#1% #4=\<macro>
+ {\number\numexpr#3\relax}% #5=entier 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=entier n2 % #6=<code> à exécuter
+\long\def\for@i#1#2#3#4#5#6{%
+ \def#1{% définit la sous macro récursive
+ \unless\ifnum#4#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{\number\numexpr#4+#3\relax}% incrémente la \<macro>
+ #1% recommence
+ }%
+ \fi
+ }%
+ #1% appelle la sous-macro récursive
+}%
+\catcode`\@=12
+\for\ii=1to4\do{\for\jj=0to2\do{(\ii,\jj)}\par}\medbreak
+
+\for\carA= `\A to `\E \do{\for\carB= `w to `z \do{\char\carA\char\carB}\quad}
+****************** Fin code ******************
+
+
+****************** Code 154 ******************
+\catcode`\@11
+\long\def\for@i#1#2#3#4#5#6{%
+ \def\exitfor{\def#1{}}%
+ \def#1{% définit 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
+}%
+\catcode`\@=12
+\for\ii= 1 to 9 \do{\string\ii{} vaut \ii.\ifnum\ii=5 \exitfor\fi\par}
+****************** Fin code ******************
+
+
+****************** Code 155 ******************
+\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 égale à la macro "\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
+}
+
+% on ne sort QUE de la boucle intérieure quand \ii=3 donc
+% les boucles sont normalement exécutées pour \ii=4 et \ii=5
+a. \for\ii=1 to 5\do1{%
+ \for\jj=1 to 3\do1{(\ii,\jj) \ifnum\ii=3 \exitfor\jj\fi}%
+ \qquad
+ }
+
+% on sort de la boucle extérieure lorsque \ii=3 donc la boucle
+% intérieure est faite entièrement même lorsque \ii=3
+b. \for\ii=1 to 5\do1{%
+ \for\jj=1 to 3\do1{(\ii,\jj) \ifnum\ii=3 \exitfor\ii\fi}%
+ \qquad
+ }
+
+% on sort de la boucle intérieure lorsque \ii=3
+% et aussi de la boucle extérieure à l'aide de \ifexitfor
+c. \for\ii=1 to 5\do1{%
+ \for\jj=1 to 3\do1{(\ii,\jj) \ifnum\ii=3 \exitfor\jj\fi}%
+ \ifexitfor\jj{\exitfor\ii}{}% si on est sorti de \jj, sortir aussi de \ii
+ \qquad
+ }
+****************** Fin code ******************
+
+
+****************** Code 156 ******************
+\def\foo{a}\ifx a\foo vrai\else faux\fi
+****************** Fin code ******************
+
+
+****************** Code 157 ******************
+1) \meaning9\par% un caractère de catcode 12
+2) \meaning a\par% une lettre
+3) \def\foo{a}\meaning\foo\par% une macro
+4) \long\def\foo{a}\meaning\foo\par% une macro déclarée \long
+5) \meaning\sdlkfj\par% une macro indéfinie
+6) \edef\foo{\string a}\meaning\foo\par%\foo contient un "a" de catcode 12
+7) \def\foo{a}\meaning\foo\par%\foo contient un "a" de catcode 11
+****************** Fin code ******************
+
+
+****************** Code 158 ******************
+a) \ifx abvrai\else faux\fi\quad% a est n'est pas égal à b
+b) \ifx++vrai\else faux\fi\quad% le caractère "+" est égal à "+"
+c) \ifx\relax\par vrai\else faux\fi\quad% \relax n'est pas la même primitive que \par
+d) \ifx\par\par vrai\else faux\fi\quad% \par et \par sont les mêmes primitives
+e) \ifx\sdfk\qlms vrai\else faux\fi\quad% 2 macros non définies sont égales
+f) \def\foo{abcd}\def\bar{abc}% \foo et \bar ont des textes de remplacement différents
+ \ifx\foo\bar vrai\else faux\fi\quad
+g) \def\foo{abcd}\def\bar{abcd }% \foo et \bar ont des textes de remplacement différents
+ \ifx\foo\bar vrai\else faux\fi\quad
+h) \def\foo{abcd}\def\bar{abcd}
+ \ifx\foo\bar vrai\else faux\fi\quad% \foo et \bar ont les mêmes textes de remplacement
+i) \long\def\foo{a}\def\bar{a}
+ \ifx\foo\bar vrai\else faux\fi\quad% \foo est \long, \bar ne l'est pas
+j) \edef\foo{\string a}% \foo contient un "a" de catcode 12
+ \def\bar{a}% \bar contient un "a" de catcode 11
+ \ifx\foo\bar vrai\else faux\fi
+****************** Fin code ******************
+
+
+****************** Code 159 ******************
+\def\cmpmacro#1#2{%
+ \begingroup
+ \edef\tempa{\detokenize\expandafter{#1}}\edef\tempb{\detokenize\expandafter{#2}}%
+ \ifx\tempa\tempb% si égalité
+ \endgroup\expandafter\firstoftwo% ferme le groupe et lit 1er argument
+ \else
+ \endgroup\expandafter\secondoftwo% sinon, ferme le groupe et lit le 2e argument
+ \fi
+}
+a) \edef\foo{\string a}\def\bar{a}
+ \cmpmacro\foo\bar{vrai}{faux}\qquad
+b) \edef\foo{\detokenize{$i^2=-1$\relax}}\def\bar{$i^2=-1$\relax}
+ \cmpmacro\foo\bar{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 160 ******************
+a) \let\rien\relax \ifx\rien\relax vrai\else faux\fi\qquad
+b) \let\AA=a \ifx a\AA vrai\else faux\fi\qquad
+c) \let\foo=_\let\bar=_ \ifx\foo\bar vrai\else faux\fi
+****************** Fin code ******************
+
+
+****************** Code 161 ******************
+\def\quark{\quark}% définit un quark
+1) \def\test{\quark} \ifx\quark\test vrai\else faux\fi
+\qquad
+2) \let\test=\quark \ifx\quark\test vrai\else faux\fi
+****************** Fin code ******************
+
+
+****************** Code 162 ******************
+\def\ifempty#1{%
+ \def\tempa{#1}% stocke l'argument #1 dans \tempa
+ \ifx\tempa\empty% si \tempa = \empty
+ \expandafter\firstoftwo% 1er argument
+ \else
+ \expandafter\secondoftwo% sinon, second
+ \fi
+}
+a) \ifempty{abc}{vide}{pas vide}\qquad
+b) \ifempty{}{vide}{pas vide}\qquad
+c) \ifempty{ }{vide}{pas vide}\qquad
+d) \ifempty{\empty}{vide}{pas vide}
+****************** Fin code ******************
+
+
+****************** Code 163 ******************
+\def\empty{}
+\long\def\ifempty#1{%
+ \ifx_#1_\expandafter\firstoftwo
+ \else\expandafter\secondoftwo
+ \fi}
+a) \ifempty{abc}{vide}{pas vide}\qquad
+b) \ifempty{}{vide}{pas vide}\qquad
+c) \ifempty{ }{vide}{pas vide}\qquad
+d) \ifempty{\empty}{vide}{pas vide}\qquad
+e) \edef\foo{\ifempty{abc}{vide}{pas vide}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 164 ******************
+\long\def\ifempty#1{%
+ \ifx W#1W\expandafter\firstoftwo
+ \else \expandafter\secondoftwo
+ \fi}
+1) \ifempty{foobar}{vide}{pas vide}\qquad
+2) \ifempty{}{vide}{pas vide}\qquad
+2) \ifempty{\empty}{vide}{pas vide}\qquad
+4) \ifempty{Wagons}{vide}{pas vide}
+****************** Fin code ******************
+
+
+****************** Code 165 ******************
+\long\def\ifempty#1{%
+ \expandafter\ifx\expandafter\relax\detokenize{#1}\relax
+ \expandafter\firstoftwo
+ \else
+ \expandafter\secondoftwo
+ \fi
+}
+a) \ifempty{abc}{vide}{pas vide}\qquad
+b) \ifempty{}{vide}{pas vide}\qquad
+c) \ifempty{ }{vide}{pas vide}\qquad
+d) \ifempty{\relax}{vide}{pas vide}\qquad
+e) \edef\foo{\ifempty{abc}{vide}{pas vide}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 166 ******************
+\catcode`\@11
+\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
+}
+\catcode`\@12
+a) \reverse{foobar}\qquad
+b) \edef\foo{\reverse{Bonjour}}\meaning\foo\qquad
+c) \reverse{Bonjour le monde}\qquad
+d) \reverse{Bonjour{ }le{ }monde}
+****************** Fin code ******************
+
+
+****************** Code 167 ******************
+\catcode`\@11
+\def\ifin#1#2{%
+ \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
+}
+\catcode`\@12
+a) \ifin{abc\relax1}{bc}{vrai}{faux}\qquad
+b) \ifin{abc \relax1}{c\relax}{vrai}{faux}\qquad
+c) \ifin{abc \relax1}{ }{vrai}{faux}\qquad
+d) \ifin{abc \relax1}{}{vrai}{faux}\qquad
+e) \ifin{}{a}{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 168 ******************
+\catcode`\@11
+\def\ifstart#1#2{%
+ \def\ifstart@i##1#2##2\@nil{\ifempty{##1}}%
+ \ifstart@i#1#2\@nil
+}
+\catcode`\@12
+a) \ifstart{abc}{bc}{vrai}{faux}\qquad
+b) \ifstart{abc}{ab}{vrai}{faux}\qquad
+c) \ifstart{ abc}{ }{vrai}{faux}\qquad
+d) \ifstart{abc}{}{vrai}{faux}\qquad
+e) \ifstart{}{a}{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 169 ******************
+\catcode`\@11
+\def\ifstart#1#2{%
+ \def\ifstart@i##1#2##2\@nil{\ifempty{##1}}%
+ \ifempty{#2}% si motif vide
+ \firstoftwo% exécuter code "vrai"
+ {\ifstart@i#1\relax#2\@nil}% sinon, aller à la macro auxiliaire
+}
+\catcode`\@12
+a) \ifstart{abc}{bc}{vrai}{faux}\qquad
+b) \ifstart{abc}{ab}{vrai}{faux}\qquad
+c) \ifstart{ abc}{ }{vrai}{faux}\qquad
+d) \ifstart{abc}{}{vrai}{faux}\qquad
+e) \ifstart{}{a}{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 170 ******************
+\catcode`\@11
+\def\ifend#1#2{%
+ \def\ifend@i##1#2##2\@nil{% ##2 = ce qui reste après le motif
+ \ifempty{##2}% si ##2 est vide
+ \firstoftwo% exécuter l'argument "vrai"
+ {\ifin{##2}{#2}% sinon, si ##2 contient le <motif>
+ {\ifend@i##2\@nil}% appeler \ifend@i avec ce qui reste
+ \secondoftwo% sinon, exécuter l'argument "faux"
+ }%
+ }%
+ \ifend@i#2#1\@nil% appelle la macro récursive
+}
+\catcode`\@12
+1) \ifend{abc de}{de}{vrai}{faux}\qquad
+2) \ifend{abd de }{de}{vrai}{faux}\qquad
+3) \ifend{abc de }{ }{vrai}{faux}\qquad
+4) \ifend{}{a}{vrai}{faux}\qquad
+5) \ifend{abc de}{}{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 171 ******************
+\catcode`\@11
+\def\ifend#1#2{%
+ \def\ifend@i##1#2##2\@nil{% ##2 = ce qui reste après le motif
+ \ifempty{##2}% si ##2 est vide
+ \firstoftwo% exécuter l'argument "vrai"
+ {\ifin{##2}{#2}% sinon, si ##2 contient le <motif>
+ {\ifend@i##2\@nil}% appeler \ifend@i avec ce qui reste
+ \secondoftwo% sinon, exécuter l'argument "faux"
+ }%
+ }%
+ \ifempty{#2}% si le motif est vide
+ \firstoftwo% exécuter "vrai"
+ {\ifend@i#2\relax#1\@nil}% sinon, appelle la macro récursive
+}
+\catcode`\@12
+1) \ifend{abc de}{de}{vrai}{faux}\qquad
+2) \ifend{abd de }{de}{vrai}{faux}\qquad
+3) \ifend{abc de }{ }{vrai}{faux}\qquad
+4) \ifend{}{a}{vrai}{faux}\qquad
+5) \ifend{abc de}{}{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 172 ******************
+\catcode`\@11
+\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}%
+}
+\catcode`\@12
+a) \substin{abracadabra}{a}{A}\qquad
+b) \substin{abracadabra}{x}{W}\qquad
+c) \substin{abracadabra}{br}{}\qquad
+d) \substin{1\relax3}\relax{222}\qquad
+****************** Fin code ******************
+
+
+****************** Code 173 ******************
+\catcode`\@11
+\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}%
+}
+\catcode`\@12
+\substtocs\foo{abracadabra}{a}{A}\meaning\foo\par
+\substtocs\foo{abracadabra}{x}{W}\meaning\foo\par
+\substtocs\foo{abracadabra}{br}{}\meaning\foo\par
+\substtocs\foo{1\relax3}\relax{222}\meaning\foo\par
+\substtocs\foo{\ifnum1=2 test vrai\fi}{2}{1}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 174 ******************
+\def\majuscule#1{\uppercase{#1}}
+\def\majmot#1{\substin{\majuscule#1}{ }{ \majuscule}}
+\majmot{un petit texte}\par
+\majmot{Un grand texte sans importance}
+****************** Fin code ******************
+
+
+****************** Code 175 ******************
+\def\majuscule#1{\uppercase{#1}}
+\def\majmot#1{%
+ \begingroup
+ \substtocs\temp{\majuscule#1}{ }{ \majuscule}%
+ \temp% exécute la macro temporaire
+ \endgroup
+}
+\majmot{un petit texte}\par
+\majmot{Un grand texte Sans importance}
+****************** Fin code ******************
+
+
+****************** Code 176 ******************
+\catcode`\@11
+\newcount\cnt@occ
+\def\cnttimes#1#2{%
+ \def\cnttimes@i##1{%
+ \ifempty{##1}% si le <code> est vide
+ {\number\cnt@occ}% afficher le nombre d'occurrences
+ {\ifin{##1}{#2}% sinon, si le <code> contient <motif1>
+ {\cnttimes@ii##1\@nil}% appeler la macro à argument délimités
+ {\number\cnt@occ}% sinon, afficher le nombre d'occurrences
+ }%
+ }%
+ \def\cnttimes@ii##1#2##2\@nil{%
+ \advance\cnt@occ1
+ \cnttimes@i{##2}% et recommencer avec ce qui reste
+ }%
+ \cnt@occ=0 % initialise le compteur
+ \cnttimes@i{#1}%
+}
+\catcode`\@12
+a) \cnttimes{abracadabra}{a}\qquad
+b) \cnttimes{abracadabra}{ra}\qquad
+c) \cnttimes{abracadabra}{w}\qquad
+d) \cnttimes{abc def ghijk l }{ }\qquad
+e) \cnttimes{\ifnum1=2 vrai\else faux\fi}{\ifnum}
+****************** Fin code ******************
+
+
+****************** Code 177 ******************
+\catcode`\@11
+\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
+}
+\catcode`\@12
+a) \cnttimestocs{abracadabra}{a}\foo \meaning\foo\qquad
+b) \cnttimestocs{abracadabra}{ra}\foo \meaning\foo\qquad
+c) \cnttimestocs{abracadabra}{w}\foo \meaning\foo\qquad
+d) \cnttimestocs{abc def ghijk l }{ }\foo \meaning\foo\qquad
+e) \cnttimestocs{\ifnum1=2 vrai\else faux\fi}{\ifnum}\foo \meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 178 ******************
+\catcode`\@11
+\def\multisubst#1#2{%
+ \def\subst@code{#1}% stocke le <code>
+ \multisubst@i#2\@nil% appelle la macro récursive avec la liste de motifs
+}
+
+\def\multisubst@i#1#2#3\@nil{% #1 et #2=paire de motifs #3=motifs restants
+ \expandafter\substtocs\expandafter\subst@code\expandafter% 1-développe
+ {\subst@code}{#1}{#2}% le <code> et effectue la substitution en cours
+ \ifempty{#3}% si la liste des motifs est vide
+ \subst@code% exécuter le <code> obtenu
+ {\multisubst@i#3\@nil}% recommencer avec les motifs qui restent
+}
+\catcode`\@12
+1) \multisubst{abracadabra}{aA rR}\par
+2) \multisubst{Ce texte devenu \`a peine reconnaissable montre que le
+ r\'esultat contient des sonorit\'es catalanes, corses ou grecques
+ assez inattendues.}{a{AA} ya uy ou io ei {AA}e}
+****************** Fin code ******************
+
+
+****************** Code 179 ******************
+\catcode`\@11
+\def\quark{\quark}
+
+\def\multisubst#1#2{% #1 = <code> #2 = <liste des paires>
+ \def\subst@code{#1}% stocke le <code>
+ \multisubst@i#2\quark\quark% appelle la macro récursive avec
+ % 2 arguments spéciaux en fin de liste
+}
+
+\def\multisubst@i#1#2{% #1#2 = paire de motifs en cours
+ \def\arg@a{#1}% stocke le <motif1> dans une macro
+ \ifx\arg@a\quark% si le motif spécial est atteint
+ \expandafter\subst@code% exécuter le code obtenu
+ \else
+ \expandafter\substtocs\expandafter\subst@code\expandafter% 1-développe
+ {\subst@code}{#1}{#2}% le <code> et effectue la substitution en cours
+ \expandafter\multisubst@i% puis lis la paire de motifs suivants
+ \fi
+}
+\catcode`\@12
+\multisubst{abracadabra}{aA rR}\par
+\multisubst{Ce texte devenu \`a peine reconnaissable montre que le r\'esultat contient des
+ sonorit\'es catalanes, corses ou grecques assez inattendues.}{a{AA} ya uy ou io ei {AA}e}
+****************** Fin code ******************
+
+
+****************** Code 180 ******************
+\iftrue foobar\else ceci n'est jamais lu par \TeX\fi\par
+\iffalse ceci n'est jamais lu par \TeX\else foobar\fi
+****************** Fin code ******************
+
+
+****************** Code 181 ******************
+\newif\ifhomme
+\def\debutlettre{Ch\ifhomme er Monsieur\else ère Madame\fi}%
+
+\hommetrue
+\debutlettre
+\medbreak
+
+\hommefalse
+\debutlettre
+****************** Fin code ******************
+
+
+****************** Code 182 ******************
+\catcode`\*=13 \catcode`\+=13 % "*" et "+" sont actifs
+1) \def*{xyz}\def+{abc}% définit les caractères actifs
+ \ifcat *+vrai\else faux\fi\qquad
+2) \ifcat \noexpand *\noexpand +vrai\else faux\fi\qquad
+3) \def\foo{foobar}%
+ \ifcat \noexpand\foo\relax vrai\else faux\fi\qquad% \foo et \relax sont vus égaux
+4) \ifcat = vrai\else faux\fi\qquad% "=" et " " n'ont pas le même catcode
+5) \ifcat _^vrai\else faux\fi\qquad% "_" et "^" n'ont pas le même catcode
+6) \let\foo=&
+ \ifcat &\foo vrai\else faux\fi% "&" et \foo (let-égal à "&") sont vus égaux
+****************** Fin code ******************
+
+
+****************** Code 183 ******************
+\catcode`\@11
+\def\ifcs#1{%
+ \ifcat\noexpand#1\relax\expandafter\firstoftwo
+ \else \expandafter\secondoftwo
+ \fi
+}
+\catcode`\@12
+1) \def\foo{bar}\ifcs\foo{vrai}{faux}\qquad
+2) \ifcs\def{vrai}{faux}\qquad
+3) \ifcs A{vrai}{faux}\qquad
+\catcode`\*=13
+4) \let*=W \ifcs*{vrai}{faux}\qquad
+5) \let*=\relax \ifcs*{vrai}{faux}\qquad
+6) \let\foo=A \ifcs\foo{vrai}{faux}\qquad
+7) \ifcs\bgroup{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 184 ******************
+1) \def\foo{xxy}\def\bar{aab}
+ \if\foo\bar vrai\else faux\fi\qquad
+2) \if aA vrai\else faux\fi\qquad% "a" et "A" n'ont pas les mêmes charcode
+3) \if\relax\noexpand\foo vrai\else faux\fi\qquad% \relax et \foo ont un charcode=256
+4) \let\foo=&\if\foo &vrai\else faux\fi\qquad% \foo est vue comme "&"
+5) \if\string~\noexpand~vrai\else faux\fi
+****************** Fin code ******************
+
+
+****************** Code 185 ******************
+\catcode`\@11
+\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
+}
+\catcode`\@12
+1) \def\foo{bar}\ifcs\foo{vrai}{faux}\qquad
+2) \ifcs\def{vrai}{faux}\qquad
+3) \ifcs A{vrai}{faux}\qquad
+\catcode`\*=13
+4) \let*=W \ifcs*{vrai}{faux}\qquad
+5) \let*=\relax \ifcs*{vrai}{faux}\qquad
+6) \let\foo=A \ifcs\foo{vrai}{faux}\qquad
+7) \ifcs\bgroup{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 186 ******************
+\edef\specialrelax{\ifnum1=1\fi}
+\meaning\specialrelax
+****************** Fin code ******************
+
+
+****************** Code 187 ******************
+\edef\specialrelax{\ifnum1=1\fi}% texte de remplacement = \relax spécial
+\edef\normalrelax{\relax}% texte de remplacement = \relax normal
+\meaning\specialrelax\par
+\meaning\normalrelax\par
+Les 2 \string\relax{} sont \ifx\specialrelax\normalrelax identiques\else différents\fi.
+****************** Fin code ******************
+
+
+****************** Code 188 ******************
+\edef\specialrelax{\ifnum1=1\fi}
+\expandafter\def\specialrelax{foobar}% redéfinition un \relax spécial
+****************** Fin code ******************
+
+
+****************** Code 189 ******************
+\catcode`\@11
+\def\ifnumcase#1{%
+ \begingroup
+ \def\elseif{\elseif}\def\endif{\endif}% définir deux "quarks" locaux
+ \def\nombre@{#1}% stocker le nombre à comparer dans \nombre@
+ \ifnumcase@i% appeller la macro récursive
+}
+
+\def\ifnumcase@i#1{%
+ \def\nxt@arg{#1}% stocker l'argument suivant
+ \ifx\nxt@arg\elseif% si c'est \elseif
+ \def\next@todo{\endgroup\idto@endif}% fermer le groupe et aller à \idto@endif
+ \else
+ \ifx\nxt@arg\endif% si c'est \endif
+ \let\next@todo\endgroup% fermer le groupe
+ \else
+ \ifnum\nombre@=\nxt@arg% s'il y a égalité
+ \def\next@todo{\endgroup\firstto@endif}% fermer le groupe puis \firstto@endif
+ \else% sinon
+ \let\next@todo=\ifnumcase@ii% aller à \ifnumcase@ii
+ \fi
+ \fi
+ \fi
+ \next@todo% exécuter l'action décidée ci-dessus
+}
+
+\def\ifnumcase@ii#1{\ifnumcase@i}
+\def\idto@endif#1\endif{#1}
+\def\firstto@endif#1#2\endif{#1}
+\catcode`\@12
+\def\swaptwo#1#2{#2#1}
+\def\testenombre#1{%
+ \ifnumcase{#1}
+ {1}{C'est "un" et je prends le premier argument: \firstoftwo}
+ {3}{J'ai vu un "trois" et je mange les deux arguments : \gobtwo}
+ {15}{L'argument est "15" et je prends le second argument : \secondoftwo}
+ \elseif
+ ni 1, ni 3, ni 5 et j'inverse les deux arguments : \swaptwo
+ \endif
+}
+\testenombre{3}{foo}{bar}\par
+\testenombre{16}{foo}{bar}\par
+\testenombre{15}{foo}{bar}\par
+\testenombre{1}{foo}{bar}
+****************** Fin code ******************
+
+
+****************** Code 190 ******************
+\catcode`\@11
+\def\endif{\endif}\def\elseif{\elseif}% définit les quarks
+
+\def\ifnumcase#1#2{% #1=<nombre> #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 #2 est une <valeur i>:
+ {\ifnum#1=#2 % s'il y a égalité entre <nombre> et <valeur i>
+ \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+ \firstto@endif% aller à \firstto@endif
+ {\ifnumcase@i{#1}}% sinon aller à \ifnumcase@i
+ }%
+ }%
+}
+
+\def\ifnumcase@i#1#2{% #1=<nombre> #2=<code i> à suivre qui est mangé
+ \ifnumcase{#1}% retourner à \ifnumcase en transmettant #1
+}
+
+\def\idto@endif#1\endif{#1}
+\def\firstto@endif#1#2\endif{#1}
+\catcode`\@12
+\def\swaptwo#1#2{#2#1}
+\def\testenombre#1{%
+ \ifnumcase{#1}
+ {1}{C'est "un" et je prends le premier argument: \firstoftwo}
+ {3}{J'ai vu un "trois" et je mange les deux arguments : \gobtwo}
+ {15}{L'argument est "15" et je prends le second argument : \secondoftwo}
+ \elseif
+ ni 1, ni 3, ni 5 et j'inverse les deux arguments : \swaptwo
+ \endif
+}
+\testenombre{3}{foo}{bar}\par
+\testenombre{16}{foo}{bar}\par
+\testenombre{15}{foo}{bar}\par
+\edef\macro{\testenombre{1}{foo}{bar}}\meaning\macro
+****************** Fin code ******************
+
+
+****************** Code 191 ******************
+\catcode`\@11
+\def\endif{\endif}\def\elseif{\elseif}%
+\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 #2 est un <token i>:
+ {\ifx#1#2% s'il y a égalité entre <token> et <token i>
+ \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+ \firstto@endif% aller à \firstto@endif
+ {\ifxcase@i{#1}}% sinon aller à \ifnumcase@i
+ }%
+ }%
+}
+\def\ifxcase@i#1#2{% #1=<token> #2=<code i> à suivre (qui est mangé)
+ \ifxcase{#1}% retourner à \ifxcase en transmettant #1
+}
+\def\idto@endif#1\endif{#1}
+\def\firstto@endif#1#2\endif{#1}
+\catcode`\@12
+\def\testtoken#1{%
+ \ifxcase{#1}
+ a{Le token est "a"}
+ +{J'ai vu un "+"}
+ \relax{L'argument est "\string\relax"}
+ \elseif
+ Tous les tests sont négatifs%
+ \endif
+}
+1) \testtoken a\par
+2) \let\foo=a\testtoken\foo\par
+3) \testtoken+\par
+4) \testtoken\relax\par
+5) \edef\foo{\testtoken\relax}\meaning\foo\par
+6) \edef\foo{\testtoken W}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 192 ******************
+\newcount\xx % définit un compteur utilisé dans la boucle
+\def\compte#1{%
+ \xx=0 % initialise le compteur
+ \loop% début de la boucle
+ \advance\xx1 % incrémente le compteur
+ \ifnum\xx<#1 % s'il est inférieur à la borne
+ \number\xx , % affiche le nombre et la virgule
+ \repeat% et recommence
+ \ifnum#1>0 \number\xx\relax\fi% si le nombre #1 est >0, afficher le dernier nombre
+ }
+a) \compte{1}.\qquad b) \compte{-3}.\qquad c) \compte{7}.
+****************** Fin code ******************
+
+
+****************** Code 193 ******************
+\catcode`\@11
+\newcount\cnt@repeat % définit le compteur de \xrepeat
+
+\def\xloop{%
+ \def\xiterate{}% initialiser \xiterate à vide
+ \cnt@repeat\z@% initialiser le compteur de \xrepeat
+ \xloop@i% aller à la macro récursive
+}
+
+\long\def\xloop@i#1\xrepeat{%
+ \addtomacro\xiterate{#1}% ajoute ce qui est avant le premier \xrepeat
+ \exparg\cnttimestocs{\xiterate}\xloop\cnt@loop
+ % combien de \xloop dans \xiterate
+ \ifnum\cnt@loop=\cnt@repeat\relax
+ \expandafter\firstoftwo\else\expandafter\secondoftwo
+ \fi
+ {% autant que de \xrepeat -> \detokenize pour afficher
+ "\detokenize\expandafter{\xiterate}"%
+ }
+ {\addtomacro\xiterate\xrepeat% sinon, ajouter ce \xrepeat
+ \advance\cnt@repeat by 1% incrémenter le compteutr de \xrepeat
+ \xloop@i% et chercher le prochain \xrepeat
+ }%
+}
+\let\xrepeat\fi
+\catcode`\@12
+\xloop a\xloop b\xloop 12\xrepeat c\xrepeat \xloop X\xrepeat\xrepeat
+****************** Fin code ******************
+
+
+****************** Code 194 ******************
+\catcode`\@11
+\newcount\cnt@repeat
+\newcount\cnt@nested
+\cnt@nested=0 % compteur d'imbrications
+\def\xloop{%
+ \global\advance\cnt@nested by 1 % augmente le compteur d'imbrications
+ \expandafter\def\csname xiterate@\number\cnt@nested\endcsname{}%
+ \cnt@repeat\z@% initialise le compteur de \xrepeat à 0
+ \xloop@i% aller à la macro \xloop@i
+}
+\long\def\xloop@i#1\xrepeat{%
+ \expandafter\addtomacro\csname xiterate@\number\cnt@nested\endcsname{#1}%
+ \expandafter\expandafter\expandafter\cnttimestocs\expandafter\expandafter\expandafter
+ {\csname xiterate@\number\cnt@nested\endcsname}\xloop\cnt@loop
+ \ifnum\cnt@loop=\cnt@repeat\relax
+ \expandafter\firstoftwo\else\expandafter\secondoftwo
+ \fi
+ {\expandafter\eaddtomacro\csname xiterate@\number\cnt@nested\expandafter\endcsname
+ {\expandafter\expandafter\csname xiterate@\number\cnt@nested\endcsname\fi}%
+ %\expandafter\show\csname xiterate@\number\cnt@nested\endcsname
+ \csname xiterate@\number\cnt@nested\endcsname
+ \letname{xiterate@\number\cnt@nested}\relax
+ \global\advance\cnt@nested by -1
+ }
+ {\expandafter\addtomacro\csname xiterate@\number\cnt@nested\endcsname\xrepeat
+ \advance\cnt@repeat by 1
+ \xloop@i
+ }%
+}%
+\let\xrepeat\fi
+\catcode`\@12
+
+\newcount\cntxx \cntxx=1 % compteur des lignes
+\newcount\cntyy
+\xloop
+ \cntyy=1 % compteur des colonnes
+ \xloop
+ (\number\cntxx,\number\cntyy)% affiche "(ligne,colonne)"
+ \ifnum\cntyy<5 % tant que colonne<5
+ \advance\cntyy1 % incrémente colonne
+ , % <- affiche ", "
+ \xrepeat% et recommence
+ \ifnum\cntxx<3 % tant que ligne<3
+ \advance\cntxx1 % incrémente ligne
+ \par % va à la ligne
+\xrepeat% et recommence
+****************** Fin code ******************
+
+
+****************** Code 195 ******************
+\catcode`\@11
+\def\end@foreach{\end@foreach}% définit un quark
+\long\def\doforeach#1\in#2#3{%
+ \def\loop@code{#3}% assigne le <code> à \loop@code
+ % appel à \doforeach@i : mettre la macro #1 en premier, puis la liste de valeurs #2
+ \doforeach@i#1#2,\end@foreach,% ajouter à la fin ",\end@foreach,"
+ % une fois les boucles finies, neutraliser les macros déjà définies
+ \let#1\relax \let\loop@code\relax
+}
+
+\long\def\doforeach@i#1#2,{% #1=\<macro> #2=valeur courante
+ \def#1{#2}% stocke la valeur en cours dans la \<macro>
+ \unless\ifx\end@foreach#1% si \end@foreach n'est pas atteint
+ \antefi% amène le \fi ici
+ \loop@code% exécute le code
+ \doforeach@i#1% et recommencer
+ \fi
+}
+\catcode`@12
+\doforeach\x\in{a,bcd,{efg},hi}{\meaning\x.\par}
+****************** Fin code ******************
+
+
+****************** Code 196 ******************
+\catcode`\@11
+\def\end@foreach{\end@foreach}
+\def\defseplist#1{%
+ \long\def\doforeach##1\in##2##3{%
+ \def\loop@code{##3}% assigne le <code> à \loop@code
+ \doforeach@i##1##2#1\end@foreach#1% ajouter ",\end@foreach," et aller à \doforeach@i
+ % après être sorti des boucles, neutraliser les macros déjà définies
+ \let\loop@code\relax \let##1\relax
+ }%
+ \long\def\doforeach@i##1##2#1{%
+ \def##1{##2}% stocke la valeur en cours dans la \<macro>
+ \unless\ifx\end@foreach##1% si la fin n'est pas atteinte
+ \antefi% amène le \fi ici
+ \loop@code% exécute le code
+ \doforeach@i##1% et recommencer
+ \fi
+ }%
+}
+\defseplist{,}% définit les macros avec le séparateur par défaut
+\catcode`@12
+
+\doforeach\x\in{a,bcd,efg}{Argument courant : "\x".\par}\medbreak
+
+\defseplist{--}% séparateur "--"
+\doforeach\nn\in{4,19--0,5--8,575}{Nombre lu : "\nn"\par}
+****************** Fin code ******************
+
+
+****************** Code 197 ******************
+\catcode`\@11
+\newcount\cnt@nest \cnt@nest=0 % définit et initialise le compteur d'imbrication
+\def\end@foreach{\end@foreach}
+
+\def\defseplist#1{%
+ \long\def\doforeach##1\in##2##3{%
+ \global\advance\cnt@nest1 % entrée de boucle : incrémenter le compteur d'imbrication
+ \defname{loop@code@\number\cnt@nest}{##3}% assigne le <code> à \loop@code@<n>
+ \doforeach@i##1##2#1\end@foreach#1% ajouter ",\end@foreach," et aller à \doforeach@i
+ % une fois fini :
+ \let##1\empty% dans ce cas, neutraliser les macros déjà définies
+ \letname{loop@code@\number\cnt@nest}\empty%
+ \global\advance\cnt@nest-1 %sortie de boucle : décrémenter le compteur d'imbrication
+ }%
+ \long\def\doforeach@i##1##2#1{%
+ \def##1{##2}% stocke la valeur en cours dans la \<macro>
+ \unless\ifx\end@foreach##1% tant que la fin n'est pas atteinte
+ \antefi% amène le \fi ici
+ \csname loop@code@\number\cnt@nest\endcsname% exécute le code
+ \doforeach@i##1% et recommencer
+ \fi
+ }%
+}
+\catcode`@12
+\defseplist{,}
+
+\doforeach\xxx\in{1,2,3}{%
+ Ligne \xxx{} : \doforeach\yyy\in{a,b,c,d,e}{(\xxx,\yyy)}.\par
+}
+****************** Fin code ******************
+
+
+****************** Code 198 ******************
+\catcode`\@11
+\newcount\cnt@nest \cnt@nest=0 % définit et initialise le compteur d'imbrication
+\def\end@foreach{\end@foreach}
+\long\def\save@macro#1{% sauvegarde la macro #1
+ \ifdefined#1% si la macro #1 est déjà définie...
+ \letname{saved@var@\number\cnt@nest}#1% ...la sauvegarder
+ \fi
+}
+\long\def\restore@macro#1{% restaure la macro #1
+% le \csname donne \relax si la sauvegarde n'a pas été faite
+ \expandafter\let\expandafter#1\csname saved@var@\number\cnt@nest\endcsname
+}
+\def\defseplist#1{%
+ \long\def\doforeach##1\in##2##3{%
+ \global\advance\cnt@nest1 % entrée de boucle : incrémenter le compteur d'imbrication
+ \save@macro##1% sauvegarde la macro ##1
+ \defname{loop@code@\number\cnt@nest}{##3}% assigne le <code> à \loop@code@<n>
+ \doforeach@i##1##2#1\end@foreach#1% ajouter ",\end@foreach," et aller à \doforeach@i
+ % une fois fini, neutraliser la macro contenant le <code>
+ \letname{loop@code@\number\cnt@nest}\empty
+ \restore@macro##1% restaurer la \<macro>
+ \global\advance\cnt@nest-1 % et décrémenter le compteur d'imbrication
+ }%
+ \long\def\doforeach@i##1##2#1{%
+ \def##1{##2}% stocke la valeur en cours dans la \<macro>
+ \unless\ifx\end@foreach##1% si la fin n'est pas atteinte
+ \antefi% amène le \fi ici
+ \csname loop@code@\number\cnt@nest\endcsname% exécute le code
+ \doforeach@i##1% et recommencer
+ \fi%
+ }%
+}
+\catcode`@12
+\defseplist{,}
+\doforeach\par\in{a,b,c,y,z}{$\par_i$}
+
+\meaning\par% \par doit être redevenu une primitive
+
+\doforeach\xxx\in{1,2,3}{%
+ Ligne \xxx{} : \doforeach\yyy\in{a,b,c,d,e}{(\xxx,\yyy)}.\par
+}
+****************** Fin code ******************
+
+
+****************** Code 199 ******************
+\let\foo=\djfhdsldv% \foo est rendue \let-égale à une macro indéfinie
+a) \meaning\foo\par
+% puis \djfhdsldv est rendue \let-égale à \foo (ou \foo est construit avec \csname)
+\expandafter\let\expandafter\djfhdsldv\csname foo\endcsname
+b) \meaning\djfhdsldv
+****************** Fin code ******************
+
+
+****************** Code 200 ******************
+\catcode`\@11
+\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{\letname{saved@var@\number\cnt@nest#1}#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
+ \global\let\allow@recurse\identity% permet l'appel récursif plus bas
+ \ifin{##1}{/}% si ##1 contient "/"
+ {\save@macro@i##1% sauvegarde les macros
+ \doforeach@ii% appeler la macro récursive avec les arguments
+ {##3}% 1) code à exécuter
+ ##1% 2) variables sous la forme \<macro1>/\<macro2>
+ ##2#1\end@foreach/\end@foreach#1% puis la liste ##2 suivie de
+ % ",\end@foreach/\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{%
+ \ifx\end@foreach##3% si la fin est atteinte
+ \expandafter\gobone\else\expandafter\identity\fi% manger sinon exécuter:
+ {\def##2{##3}% fait l'assignation à la variable
+ ##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{%
+ \ifx\end@foreach##4% si la fin est atteinte
+ \expandafter\gobone\else\expandafter\identity\fi% manger sinon exécuter:
+ {\def##2{##4}\def##3{##5}% fait l'assignation des deux variables
+ ##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,"
+}
+\def\doforeachexit{\global\let\allow@recurse\forbid@recurse}
+\catcode`\@12
+\defseplist{,}
+\doforeach\par\in{a,b,c,y,z}{$\par_i$}\medskip
+
+\doforeach\sujet/\terminaison\in{Je/e,Tu/es,Il/e,Nous/ons,Vous/ez,Ils/ent}
+ {\sujet\ programm\terminaison{} en \TeX\par}\medskip
+
+Les voyelles lues sont :
+\doforeach\ii\in{a,e,i,o,u,y}{\ii\if o\ii\doforeachexit\fi}.\medskip
+
+\doforeach\xx\in{a,b,c,d,e,f}
+ {\doforeach\ii\in{1,2,3,4}{\xx\ii{} \ifnum\ii=3 \doforeachexit\fi}\par}
+****************** Fin code ******************
+
+
+****************** Code 201 ******************
+\newdimen\dimA \newdimen\dimB% alloue deux registres de dimension
+a) \dimA=59.5pt
+ \the\dimA\qquad% doit afficher 59.5pt
+b) \dimA=1.5cm
+ \the\dimA\qquad% convertit à l'affichage 1.5cm en pt
+c) \dimB=7pt % assigne 7pt à \dimB
+ \dimA\dimB% rend \dimA égal à dimB
+ \the\dimA\qquad
+d) \dimA=6\dimB% rend \dimA égal à 6 fois \dimB
+ \the\dimA
+****************** Fin code ******************
+
+
+****************** Code 202 ******************
+\newdimen\foo
+\foo=25pt % assigne 25pt au registre \foo
+\divide\foo 4 % le multiplie par 4
+\advance\foo1.72pt % lui ajoute 1.72pt
+\multiply\foo3 % le multiplie par 3
+\the\foo% affiche la dimension obtenue
+****************** Fin code ******************
+
+
+****************** Code 203 ******************
+\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
+\newdimen\foo
+a) \foo=15pt \expandafter\removept\the\foo\qquad
+b) \foo=3.14pt \expandafter\removept\the\foo
+****************** Fin code ******************
+
+
+****************** Code 204 ******************
+\def\dimtodec{\expandafter\removept\the}
+\newdimen\foo
+a) \foo=15pt \dimtodec\foo \qquad
+b) \foo=3.14pt \dimtodec\foo
+****************** Fin code ******************
+
+
+****************** Code 205 ******************
+a) \the\dimexpr 1cm + 0.5cm\relax \qquad
+b) \the\dimexpr 1pt + 1pt\relax \qquad
+c) \the\dimexpr 1pt + 2pt * 3\relax\qquad
+d) \the\dimexpr (1pt + 2pt) * 3\relax\qquad
+e) \the\dimexpr (1.2pt + 0.8pt) * 5\relax\qquad
+f) \newdimen\foo \foo=15pt
+ \the\dimexpr\foo-(\foo + 1pt) / 4\relax
+****************** Fin code ******************
+
+
+****************** Code 206 ******************
+\the\dimexpr0,7pt + 0.4pt\relax
+****************** Fin code ******************
+
+
+****************** Code 207 ******************
+a) \newdimen\foodim \foodim=1cm \number\foodim\relax\qquad
+b) \number\dimexpr 0.7pt + 0.4pt\relax\qquad
+c) \number\dimexpr 1.1pt\relax
+****************** Fin code ******************
+
+
+****************** Code 208 ******************
+\catcode`\@11
+\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{% définit 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
+}
+\catcode`\@=12
+a) \FOR\xx=1.5 to -5\do-1{"\xx" }\par
+
+b) \FOR\ii=1 to 2.742\do.25{"\ii" }\par
+
+c) \FOR\ii=0 to 1\do0.1{"\ii" \ifdim\ii pt>0.5pt \exitFOR\ii\fi}
+****************** Fin code ******************
+
+
+****************** Code 209 ******************
+\newdimen\foo
+\foo=15.2pt \foo=1.5\foo \the\foo% vaut 15.2*1.5
+****************** Fin code ******************
+
+
+****************** Code 210 ******************
+\catcode`\@11
+\newdimen\dim@a
+\def\decmul#1#2{%
+ \dim@a=#2pt % range la dimension #2pt dans le registre de dimension
+ \dim@a=#1\dim@a% multiplier le registre par le décimal #1
+ \dimtodec\dim@a% convertir la dimension en décimal
+}
+\catcode`\@12
+a) \decmul{15.2}{1.5}\qquad
+b) \decmul{48.2}{.375}
+****************** Fin code ******************
+
+
+****************** Code 211 ******************
+\def\decmul#1#2{\dimtodec\dimexpr#1\dimexpr#2pt\relax\relax}
+
+a) \decmul{15.2}{1.5}\qquad
+b) \edef\foo{\decmul{48.2}{.375}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 212 ******************
+\def\decdiv#1#2{% divise le décimal #1 par le décimal #2
+ \dimtodec
+ \dimexpr
+ \numexpr
+ \dimexpr #1pt \relax * 65536 / \dimexpr #2pt \relax
+ \relax
+ sp
+ \relax
+}
+
+1) \decdiv{4.5}{0.075}\qquad% doit donner 60
+2) \decdiv{8}{0.1}\qquad% doit donner 80
+3) \decdiv{3.14}{1.6}\qquad% doit donner 1.9625
+4) \decdiv{687.59829}{5.29871}\qquad% doit donner 129.76706
+4) \edef\foo{\decdiv{0.37}{2.5}}\foo% doit donner 0.148
+****************** Fin code ******************
+
+
+****************** Code 213 ******************
+\def\convertunit#1#2{%
+ \dimtodec
+ \dimexpr
+ \numexpr
+ \dimexpr #1 \relax * 65536 / \dimexpr 1#2 \relax
+ \relax
+ sp
+ \relax
+}
+
+a) \convertunit{15cm}{mm}\qquad
+b) \convertunit{9,14in}{cm}\qquad
+c) \convertunit{100000sp}{mm}\qquad
+d) \convertunit{160.5pt}{cm}\qquad
+e) \edef\foo{\convertunit{2,5cm}{cc}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 214 ******************
+\the\glueexpr 5pt plus 2pt minus 1.5pt + 7pt plus0.5pt minus 3pt\relax \par
+\the\glueexpr 25pt plus2fil + 35pt plus 0.1fill\relax
+****************** Fin code ******************
+
+
+****************** Code 215 ******************
+foo% les caractères font entrer TeX en mode horizontal
+\kern0.5cm % espace insérée en mode horizontal
+bar\par% \par fait passer en mode vertical
+\kern0.5cm % espace insérée en mode vertical
+boo
+****************** Fin code ******************
+
+
+****************** Code 216 ******************
+Une première ligne\par
+\nointerlineskip% n'insère pas de ressort d'interligne ici
+Un second paragraphe constitué de plusieurs lignes.
+Un second paragraphe constitué de plusieurs lignes.
+Un second paragraphe constitué de plusieurs lignes.
+\par% le ressort d'interligne sera inséré ici
+Une dernière ligne
+****************** Fin code ******************
+
+
+****************** Code 217 ******************
+\begingroup
+\offinterlineskip
+La macro \litterate-\offinterlineskip-, en modifiant de façon appropriée les trois
+primitives \litterate-\baselineskip-, \litterate-\lineskip- et
+\litterate-\lineskiplimit-, rend les boites consécutives jointives.
+
+On peut constater dans ces deux paragraphes où \litterate-\offinterlineskip- a été
+appelée, que les lignes sont placées verticalement au plus près les unes des autres ce
+qui rend la lecture très pénible et démontre que le ressort d'interligne est une
+nécessité typographique !\par
+\endgroup
+Désactiver le ressort d'interligne ne se justifie que lorsque l'on doit composer
+des boites contenant autre chose que du texte, sauf à vouloir des effets
+typographiques spéciaux.
+****************** Fin code ******************
+
+
+****************** Code 218 ******************
+\baselineskip=12pt
+début \vtop{\hbox{ligne du haut ligne du haut ligne du haut}
+\hbox{ligne du bas ligne du bas ligne du bas}
+}
+\par
+Et la suite du texte suite du texte suite du texte
+****************** Fin code ******************
+
+
+****************** Code 219 ******************
+\baselineskip=12pt
+début \vtop{\hbox{ligne du haut ligne du haut ligne du haut}
+\hbox{ligne du bas ligne du bas ligne du bas}
+\xdef\sprevdepth{\the\prevdepth}% sauvegarde la valeur de \prevdepth
+}
+\par\prevdepth=\sprevdepth\relax% ment sur la boite précédente
+Et la suite du texte suite du texte suite du texte
+****************** Fin code ******************
+
+
+****************** Code 220 ******************
+\def\dummytext{Voici un texte qui ne revêt aucune importance
+ et dont le seul but est de meubler artificiellement un paragraphe. }
+\begingroup% à l'intérieur d'un groupe,
+ \leftskip=0pt plus 0.5\hsize\relax
+ \rightskip=\leftskip\relax % modifier les ressort d'extrémités
+ \spaceskip=0.3em plus 0.05em\relax% dimension de l'espace intermot
+ \parfillskip=0pt \relax% annuler le ressort de fin de paragraphe
+ \dummytext\dummytext\dummytext% corps du paragraphe
+ \par% compose la paragraphe courant
+ Juste une phrase%
+ \par% compose la paragraphe courant
+\endgroup% avant de sortir du groupe
+****************** Fin code ******************
+
+
+****************** Code 221 ******************
+\def\narrowtext{%
+ \par
+ \begingroup
+ \advance\leftskip 0.1\hsize
+ \advance\rightskip 0.1\hsize
+}
+\def\endnarrowtext{\par\endgroup}
+\def\dummytext{Ceci est un texte sans
+ importance destiné à meubler un paragraphe. }
+
+\dummytext\dummytext\dummytext
+\narrowtext
+ \dummytext\dummytext\dummytext
+ \narrowtext
+ \dummytext\dummytext\dummytext
+ \endnarrowtext
+ \dummytext\dummytext\dummytext
+\endnarrowtext
+****************** Fin code ******************
+
+
+****************** Code 222 ******************
+a) \hfill Composition au fer à droite\par
+b) Composition au fer à gauche\hfill\kern0pt\par
+c) \hfill Centrage\hfill\kern0pt\par
+d) Des \hfill mots\hfill régulièrement\hfill espacés
+****************** Fin code ******************
+
+
+****************** Code 223 ******************
+a% le caractère "a" fait passer en mode horizontal
+\hbox{b}c\hbox{d}% les \hbox sont ajoutées en mode horizontal
+\medbreak
+...à comparer avec...
+\medbreak
+a \par% \par fait passer en mode vertical
+\hbox{b}% \hbox est ajoutée à la liste verticale
+c% "c" fait passer en mode horizontal
+\hbox{d}% la \hbox est ajoutée en mode horizontal
+****************** Fin code ******************
+
+
+****************** Code 224 ******************
+Ligne de base : .........%
+\vbox{\hbox{ligne du haut}\hbox{ligne du milieu}\hbox{ligne du bas}}%
+.........%
+\vtop{\hbox{ligne du haut}\hbox{ligne du milieu}\hbox{ligne du bas}}.........
+****************** Fin code ******************
+
+
+****************** Code 225 ******************
+\def\dummytext{Bla, bla, bla, un texte sans importance. }
+Ligne de base.........%
+\vbox{\hsize=4cm \dummytext\dummytext}%
+.........%
+\vtop{\hsize=4cm \dummytext\dummytext}.........
+****************** Fin code ******************
+
+
+****************** Code 226 ******************
+\newbox\foobox
+a) \setbox\foobox=\hbox{foobar}% registre non vide
+ Le registre est \ifvoid\foobox vide\else non vide\fi\par
+b) \setbox\foobox=\hbox{foobar}
+ "\box\foobox" et le registre est \ifvoid\foobox vide\else non vide\fi\par
+c) \setbox\foobox=\hbox{foobar}
+ "\copy\foobox" et le registre est \ifvoid\foobox vide\else non vide\fi\par
+d) \setbox\foobox=\hbox{}
+ Le registre est \ifvoid\foobox vide\else non vide\fi
+****************** Fin code ******************
+
+
+****************** Code 227 ******************
+\newbox\foobox
+\setbox\foobox=\hbox{Programmer est facile.}
+<<\copy\foobox>>
+mesure \the\wd\foobox\ de long, \the\dp\foobox\ de profondeur et \the\ht\foobox\ de haut.
+\medbreak
+
+\setbox\foobox=\vbox{\hbox{Programmer}\hbox{est}\hbox{facile.}}
+<<\copy\foobox>>
+mesure \the\wd\foobox\ de long, \the\dp\foobox\ de profondeur et \the\ht\foobox\ de haut.
+\medbreak
+
+\setbox\foobox=\vtop{\hbox{Programmer}\hbox{est}\hbox{facile.}}
+<<\copy\foobox>>
+mesure \the\wd\foobox\ de long, \the\dp\foobox\ de profondeur et \the\ht\foobox\ de haut.
+****************** Fin code ******************
+
+
+****************** Code 228 ******************
+\def\vdim#1{\dimexpr\ht#1+\dp#1\relax}
+a) \setbox\foobox=\vbox{\hbox{Programmer}\hbox{est}\hbox{facile.}}
+ Verticalité de la \litterate-\vbox- = \the\vdim\foobox\par
+b) \setbox\foobox=\vtop{\hbox{Programmer}\hbox{est}\hbox{facile.}}
+ Verticalité de la \litterate-\vtop- = \the\vdim\foobox
+****************** Fin code ******************
+
+
+****************** Code 229 ******************
+\def\countallchar#1{%
+ Il y a %
+ \setbox0=\hbox{\tt#1}% met #1 dans la boite
+ \edef\arglength{\number\wd0 }% stocke la largeur de la boite en sp
+ \setbox0=\hbox{\tt A}% met "A" dans la boite
+ \edef\charlength{\number\wd0 }% stocke la largeur d'un caractère
+ $\number\arglength/\charlength % affiche la division
+ =\number\numexpr\arglength/\charlength\relax$ % affiche le quotient
+ caractères%
+}
+\countallchar{abcd efgh}\par
+\countallchar{A5 xW5 64 a1}\par
+\countallchar{affligeant}
+****************** Fin code ******************
+
+
+****************** Code 230 ******************
+\catcode`@11
+\def\countchar#1#2{%
+ \setbox\z@\hbox{\tt#2}% met #2 dans boite 0
+ \edef\len@a{\number\wd\z@}% mesure la boite
+ \setbox\z@\hbox{\tt\substin{#2}{#1}{}}% recommencer sans "#1"
+ \edef\len@b{\number\wd\z@}% mesure la boite
+ \setbox\z@\hbox{\tt A}% met "A" dans la boite
+ \edef\charlength{\number\wd\z@}% stocke la largeur du caractère
+ \number\numexpr(\len@a-\len@b)/\charlength% et affiche le quotient
+}
+\catcode`@12
+a) \countchar{a}{abracadabra}\qquad
+b) \countchar{b}{zigzag}\qquad
+c) \countchar{ }{a bc de f ghi j k }
+****************** Fin code ******************
+
+
+****************** Code 231 ******************
+Programmer \raise1ex\hbox{en} \lower1ex\hbox{\TeX} \lower2ex\hbox{est} facile.
+****************** Fin code ******************
+
+
+****************** Code 232 ******************
+\def\cbox#1{%
+ \setbox0\vbox{#1}% met le contenu dans une \vbox
+ \lower\dimexpr(\ht0-\dp0)/2\relax\box0 % l'abaisse
+}
+
+......\cbox{\hbox{$x^2$}}......\cbox{\hbox{foo}\hbox{et bar}}......%
+\cbox{\hbox{Programmer}\hbox{en \TeX}\hbox{est facile}}.......
+****************** Fin code ******************
+
+
+****************** Code 233 ******************
+......\cbox{\hbox{foo}\hbox{et bar}}......$\vcenter{\hbox{foo}\hbox{et bar}}$......
+****************** Fin code ******************
+
+
+****************** Code 234 ******************
+\def\htmath{\begingroup
+ \setbox0=\hbox{$\vcenter{}$}\the\ht0
+\endgroup
+}
+L'axe mathématique se trouve à \htmath{} de la ligne de base.
+****************** Fin code ******************
+
+
+****************** Code 235 ******************
+1) \hbox{foobar}\par
+2) \hbox spread 5pt{foo\hfil bar}\par
+3) \hbox spread10pt{foo\hfil bar}
+****************** Fin code ******************
+
+
+****************** Code 236 ******************
+foobar|\rlap{/////}123456\qquad foobar|\llap{/////}123456
+****************** Fin code ******************
+
+
+****************** Code 237 ******************
+\def\clap#1{\hbox to0pt{\hss#1\hss}}
+a) avant la macro|\clap{SURIMPRESSION}après la macro\medbreak
+b) avant la macro|\raise2.5ex\clap{Au-dessus}\lower2.5ex\clap{Au-dessous}%
+ après la macro\medbreak
+c) avant la macro|\raise2.5ex\llap{Au-dessus avant}\lower2.5ex\rlap{Au-dessous après}%
+ après la macro
+****************** Fin code ******************
+
+
+****************** Code 238 ******************
+\setbox0=\hbox{\tt//////////}
+\wd0=0pt % fait croire à TeX que la larguer de la boite est nulle
+Voici \copy0 du texte partiellement barré...
+****************** Fin code ******************
+
+
+****************** Code 239 ******************
+\def\printdim{largeur=\the\wd0 \qquad hauteur=\the\ht0 \qquad profondeur = \the\dp0 }
+\setbox0=\hbox{Programmer en \TeX{} est facile}
+a) \printdim\par
+b) \wd0=0pt \ht0=0pt \dp0=0pt% rend toutes le dimensions nulles
+ \printdim\par
+c) \setbox0=\hbox{\unhbox0 }% reprend les dimensions d'origine
+ \printdim
+****************** Fin code ******************
+
+
+****************** Code 240 ******************
+\setbox0=\hbox{}% le registre 0 contient une boite vide
+Le registre \ifvoid0 est vide\else n'est pas vide\fi
+****************** Fin code ******************
+
+
+****************** Code 241 ******************
+\catcode`\@11
+\def\ifzerodimbox#1{% #1=registre de boite
+% revoie vrai si le registre est vide ou contient une boite de dimensions nulles
+ \csname% former la macro "\firstoftwo" ou "\secondoftwo"
+ \ifvoid#1first%% si le registre est vide "first"
+ \else% sinon
+ \ifdim\wd#1=\z@% si la largeur
+ \ifdim\ht#1=\z@% la hauteur
+ \ifdim\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
+}
+\catcode`\@12
+a) \setbox0=\hbox{}\ifzerodimbox0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par
+b) \box0 % affiche la boite vide, le registre est maintenant "void"
+ \ifzerodimbox0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par
+c) \setbox0=\hbox{x}\ifzerodimbox0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par
+d) \wd0=0pt \ht0=0pt \dp0=0pt % rend toutes les dimensions nulles
+ \ifzerodimbox0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par
+e) \setbox0=\vbox{}\ifzerodimbox0{vrai}{faux} (et \ifvoid0 void\else non void\fi)
+****************** Fin code ******************
+
+
+****************** Code 242 ******************
+\def\ifvoidorempty#1{% teste si le registre #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% #1 en dimensions naturelles
+ \expandafter\egroup% sauter la fin de la boite
+ \expandafter% et le \endgroup
+ \endgroup
+ \ifnum\lastnodetype=-1 % et tester si le dernier noeud est vide
+ \expandafter\expandafter\expandafter\firstoftwo
+ \else
+ \expandafter\expandafter\expandafter\secondoftwo
+ \fi
+ \fi
+}
+a) \setbox0=\hbox{}\ifvoidorempty0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par
+b) \box0 % affiche la boite vide, le registre est maintenant "void"
+ \ifvoidorempty0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par
+c) \setbox0=\hbox{x}\ifvoidorempty0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par
+d) \wd0=0pt \ht0=0pt \dp0=0pt % rend toutes les dimensions nulles
+ \ifvoidorempty0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par
+e) \setbox0=\vbox{}\ifvoidorempty0{vrai}{faux} (et \ifvoid0 void\else non void\fi)
+****************** Fin code ******************
+
+
+****************** Code 243 ******************
+\newdimen\hmaxsize
+\def\cvtop#1{%
+ \hmaxsize=-\maxdimen% initialise à la plus petite longueur
+ \doforeach\htext\in{#1}% pour chaque élément :
+ {\setbox0=\hbox{\htext}% stocker l'élément "\htext" dans une \hbox
+ \ifdim\wd0 >\hmaxsize% si sa longueur est supérieure à \hmaxsize
+ \hmaxsize=\wd0 % mettre à jour \hmaxsize
+ \fi
+ }%
+ \vtop{% dans une \vtop...
+ \doforeach\htext\in{#1}% pour chaque élément :
+ {\hbox to\hmaxsize{\hss\htext\hss}% le centrer dans une \hbox de longueur \hmaxsize
+ }%
+ }%
+}
+
+texte avant...\cvtop{Ligne du haut,Très grande ligne du milieu,Ligne du bas pour finir}%
+...texte après
+****************** Fin code ******************
+
+
+****************** Code 244 ******************
+\newdimen\hmaxsize
+\def\cvtop#1{%
+ \hmaxsize=-\maxdimen% initialise à la plus petite longueur
+ \doforeach\htext\in{#1}% pour chaque élément :
+ {\setbox0=\hbox{\htext}% stocker l'élément "\htext" dans une \hbox
+ \ifdim\wd0 >\hmaxsize% si sa longueur est supérieure à \hmaxsize
+ \hmaxsize=\wd0 % mettre à jour \hmaxsize
+ \fi
+ }%
+ \vtop{% dans une \vtop...
+ \hsize\hmaxsize % longueur de la \vtop = \maxhsize
+ \parindent=0pt % pas d'indentation
+ \leftskip=0pt plus1fil minus0pt \rightskip=\leftskip% ressorts de centrage
+ \doforeach\htext\in{#1}% pour chaque élément :
+ {\htext\par}% le composer et finir le paragraphe
+ }%
+}
+
+texte avant...\cvtop{Ligne du haut,Très grande ligne du milieu,Ligne du bas pour finir}%
+...texte après
+****************** Fin code ******************
+
+
+****************** Code 245 ******************
+\halign{X#**\ignorespaces&#&\hfil #\cr % préambule
+foo &foo bar&123 456\cr % première ligne
+deuxième ligne &1 &12\cr % deuxième ligne
+a &\TeX &1 2 3 4 5 6\cr % troisième ligne
+\crcr}
+****************** Fin code ******************
+
+
+****************** Code 246 ******************
+\def\cvtop#1{%
+ \vtop{% \vtop assure que l'on est en mode vertical
+ \substtocs\temp{#1}{,}{\cr}% dans \temp, remplacer les "," par "\cr"
+ \halign{%
+ \hfil##\hfil\cr% préambule : centrer le contenu
+ \temp\crcr}% mettre \temp dans l'alignement
+ }% \temp est détruite en sortant de la boite
+}
+
+texte avant...\cvtop{Ligne du haut,Très grande ligne du milieu,Ligne du bas pour finir}%
+...texte après
+****************** Fin code ******************
+
+
+****************** Code 247 ******************
+\def\calcmaxdim#1#2{%
+ \setbox0=\vtop{% \vtop assure que l'on est en mode vertical (interne)
+ \substtocs\temp{#2}{,}{\cr}% dans \temp, remplacer les "," par "\cr"
+ \halign{##\hfil\cr% préambule : composer au fer à gauche
+ \temp\crcr}% mettre \temp dans l'alignement
+ }% \temp est détruite en sortant de la boite
+ \edef#1{\the\wd0 }%
+}
+a) La plus grande longueur vaut
+ \calcmaxdim\foo{Ligne du haut,Très grande ligne du milieu,Ligne du bas pour finir}\foo
+
+b) Vérification : \setbox0=\hbox{Très grande ligne du milieu}\the\wd0
+****************** Fin code ******************
+
+
+****************** Code 248 ******************
+a) .......\vbox{\hrule\hbox{foo}\hbox{ligne du bas}\hrule}.......\medbreak
+b) .......\vrule\vtop{\hbox{foo}\hbox{ligne du bas}}\vrule.......
+****************** Fin code ******************
+
+
+****************** Code 249 ******************
+Une réglure de 1.5cm :\hrule width1.5cm
+foo\vrule width 2pt height .5cm depth .2cm bar
+****************** Fin code ******************
+
+
+****************** Code 250 ******************
+\def\showdim#1{%
+ \vrule width 0.4pt height 1ex depth 0pt % trait vertical gauche
+ \vrule width #1 height0.4pt depth 0pt % réglure horizontale de longueur #1
+ \vrule width 0.4pt height 1ex depth 0pt % trait vertical droit
+ \relax% stoppe la lecture de la précédente dimension
+}
+
+a) une longueur de 1 cm : \showdim{1cm}\par
+b) une longueur de 137,4 pt : \showdim{137,4pt}\par
+c) une longueur de 2 mm : \showdim{2mm}
+****************** Fin code ******************
+
+
+****************** Code 251 ******************
+
+\frboxsep=5pt \frboxrule=1pt
+\leavevmode
+...%
+\vbox{%
+ \hrule height\frboxrule% réglure supérieure
+ \kern\frboxsep% espace verticale haute
+ \hbox{\kern\frboxsep Programmation\kern\frboxsep}% contenu + espaces horizontales
+ \kern\frboxsep% espace verticale basse
+ \hrule height\frboxrule% réglure inférieure
+ }%
+...
+****************** Fin code ******************
+
+
+****************** Code 252 ******************
+
+\frboxsep=5pt \frboxrule=0.6pt
+\def\FRbox#1{% /!\ ne change pas le mode H ou V en cours
+ \hbox{% mettre à la suite horizontalement les 3 choses suivantes :
+ \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
+ }%
+}
+Ligne de base : ...\FRbox{Programmation}...%
+\frboxrule=2pt \FRbox{Programmation}...%
+\frboxsep=0pt \FRbox{Programmation}...%
+\frboxrule0.4pt \FRbox{Programmation}...
+****************** Fin code ******************
+
+
+****************** Code 253 ******************
+Persuadez-vous que :
+\vtop{
+ \vbox{
+ \hbox{Programmer}
+ \hbox{en}
+ \hbox{\TeX}
+ \hbox{est}% <- ligne de base de la \vtop
+ }
+ \hbox{\it tout sauf}
+ \hbox{facile.}
+}
+****************** Fin code ******************
+
+
+****************** Code 254 ******************
+%\newdimen\frboxrule \newdimen\frboxsep
+\frboxrule=0.4pt \frboxsep=2pt
+\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
+ }%
+}
+Ligne de base : ......\frbox{Programmation}......%
+\frboxrule=2pt \frbox{Programmation}......%
+\frboxsep=0pt \frbox{Programmation}......%
+\frboxrule0.4pt \frbox{Programmation}......
+****************** Fin code ******************
+
+
+****************** Code 255 ******************
+\def\centretitre#1{%
+ \medbreak% passe en mode v puis saute une espace verticale
+ \noindent% pas d'indentation et passe en mode horizontal
+ \frbox{% encadre
+ \vbox{% une boite verticale
+ \hsize=\dimexpr\hsize-2\frboxrule-2\frboxsep\relax
+ \parindent=0pt % pas d'indentation
+ \leftskip=0pt plus1fil \rightskip=\leftskip% ressorts de centrage
+ \parfillskip=0pt % annule le ressort de fin de paragraphe
+ #1% insère le titre
+ \endgraf% et le compose
+ }%
+ }%
+ \medbreak% passe en mode v puis saute une espace verticale
+ \ignorespaces% mange les espaces situés après la macro \centretitre
+}
+\frboxrule=0.8pt \frboxsep=5pt
+Voici un
+\centretitre{Titre}
+puis un
+\centretitre{Texte très long pour composer un titre qui va prendre plusieurs
+lignes et pour s'assurer que la composition s'effectue correctement}
+****************** Fin code ******************
+
+
+****************** Code 256 ******************
+Une réglure en hauteur : \vrule width 1cm height 10.4pt depth -10pt
+****************** Fin code ******************
+
+
+****************** Code 257 ******************
+Une réglure en dessous: \vrule width 1cm depth 2.4pt height -2pt
+****************** Fin code ******************
+
+
+****************** Code 258 ******************
+\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
+}
+Voici \souligne{du texte normal}.\par
+Voici \souligne{du texte profond}.
+****************** Fin code ******************
+
+
+****************** Code 259 ******************
+\def\Souligne#1{%
+ \setbox0=\hbox{#1}%
+ \setbox0=\hbox{\vrule width\wd0 depth1.4pt height-1pt }%
+ \wd0=0pt \dp0=0pt \ht0=0pt
+ \leavevmode \box0 #1%
+}
+Voici \Souligne{du texte normal}.\par
+Voici \Souligne{du texte profond}.
+****************** Fin code ******************
+
+
+****************** Code 260 ******************
+\def\Souligne#1{%
+ \setbox0=\hbox{#1}%
+ \lower 1pt % abaisser à 1pt sous la ligne de base
+ \rlap{% une \hbox en surimpression vers la droite
+ \vrule width\wd0 height0pt depth0.4pt % contenant le soulignement
+ }%
+ #1% puis afficher le <texte>
+}
+Voici \Souligne{du texte normal}.\par
+Voici \Souligne{du texte profond}.
+****************** Fin code ******************
+
+
+****************** Code 261 ******************
+\newdimen\stackwd \stackwd=3em % dimension horizontale interne des cadres
+\catcode`@11
+\def\stackbox#1{%
+ \par% termine le paragraphe en cours
+ \noindent
+ \stackbox@i#1\\\quark\\% ajoute "\\\quark\\" à la fin et appelle \stackbox@i
+ \par
+}
+
+\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 (et fait passer en mode horizontal)
+ \noindent
+ \doforeach\current@item\in{#1}% pour chaque élément dans la ligne courante...
+ {\frbox{% ...encadrer
+ \hbox to\stackwd{% une \hbox de largeur \stackwd
+ \hss% ressort de centrage
+ \current@item% l'élément courant
+ \hss% ressort de centrage
+ }
+ }% fin de la \frbox
+ }% fin \doforeach
+ \hfill% ressort infini de centrage
+ \null% assure que le dernier ressort est pris en compte
+ \par% finir le paragraphe
+ \nobreak% interdire une coupure de page
+ \nointerlineskip% ne pas insérer le ressort d'interligne
+ \expandafter\stackbox@i% et recommencer
+ \fi
+}
+\catcode`@12
+
+\frboxrule=0.5pt \frboxsep=3pt
+\stackbox{a,bc,,d\\e,foobar,g\\123,456,$\alpha$,$x+y$,}
+****************** Fin code ******************
+
+
+****************** Code 262 ******************
+a\vrule width0.2pt height15pt depth0pt \quad
+a\vrule width0.2pt height0pt depth5pt \quad
+a\vrule width0.2pt height10pt depth10pt \quad
+a\vrule width1cm height0.2pt depth0pt
+****************** Fin code ******************
+
+
+****************** Code 263 ******************
+\frboxsep0pt %encadrement au plus proche
+\leavevmode
+\frbox{a\vrule width0pt height15pt depth0pt }\quad
+\frbox{a\vrule width0pt height0pt depth5pt }\quad
+\frbox{a\vrule width0pt height10pt depth10pt }\quad
+\frbox{a\vrule width1cm height0pt depth0pt }
+****************** Fin code ******************
+
+
+****************** Code 264 ******************
+\def\rectangle#1#2{%
+ \begingroup% dans un groupe
+ \frboxsep = 0pt % encadrer au plus proche
+ \frboxrule= 0.4pt % en traits assez fins
+ \frbox{%
+ \vrule width#1 height0pt depth0pt %strut horizontal
+ \vrule width0pt height#2 depth0pt %strut vertical
+ }%
+ \endgroup% fermer le groupe
+}
+Carré de 0.5 cm : \rectangle{0.5cm}{0.5cm}\smallskip
+
+Rectangle de 2.5cm par 3pt : \rectangle{2.5cm}{3pt}
+****************** Fin code ******************
+
+
+****************** Code 265 ******************
+\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 d'interligne
+ \kern-\frboxrule% superposer les réglures horizontales
+ \expandafter\stackbox@i% et recommencer
+ \fi
+}
+\frboxrule=0.5pt
+\frboxsep=3pt
+\stackbox{a,bc,,d\\e,foobar,g\\123,456,$\alpha$,$x+y$,}
+****************** Fin code ******************
+
+
+****************** Code 266 ******************
+\catcode`\@11
+\def\lineboxed#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
+ \lineboxed@i#1\\\quark\\% ajoute "\\\quark\\" à la fin et appelle la macro récursive
+ \unkern% annule la dernière compensation verticale
+ \par
+ \endgroup
+}
+\def\lineboxed@i#1\\{% #1=ligne courante
+ \def\temp@{#1}% stocke la ligne courante
+ \unless\ifx\quark\temp@% si ce n'est pas la fin
+ \cnttimestocs{#1,}{,}\nb@args% reçoit le nombre d'arguments dans la ligne courante
+ \edef\dim@box{\the\dimexpr(\hsize-\frboxrule*(\nb@args+1)-
+ \frboxsep*2*\nb@args)/\nb@args}%
+ \hbox{%
+ \doforeach\current@item\in{#1}% pour chaque élément dans la ligne courante...
+ {\frbox{% ...encadrer
+ \hbox to\dim@box{% une \hbox de largeur \dim@box 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
+ }%
+ \par% termine le paragraphe
+ \nobreak% interdit une coupure de page
+ \nointerlineskip% sinon, ne pas ajouter le ressort d'interligne
+ \kern-\frboxrule% superposer les réglures horizontales
+ \expandafter\lineboxed@i% et recommencer
+ \fi
+}
+\catcode`\@12
+\lineboxed{a,bc,,d\\e,foobar,g\\123,456,$\alpha$,$x+y$,}\medbreak
+
+\frboxrule=1.5pt
+\frboxsep=3pt
+\lineboxed{,,,,,,,\\,,\\,,,,,,}
+****************** Fin code ******************
+
+
+****************** Code 267 ******************
+\xunit=0.5cm \yunit=0.5cm \mainrule=0.8pt \subrule=0.2pt
+\def\vlap#1{\vbox to0pt{\vss#1\vss}}
+\catcode`@11
+\def\grid#1#2#3#4{%
+ \vbox{% empiler les éléments verticalement
+ \offinterlineskip% pas de ressort d'interligne
+ \edef\total@wd{\the\dimexpr\xunit*#1\relax}% largeur totale ds réglures
+ \for\ii = 1 to #3 \do1% pour chaque carreau vertical (\ii=variable muette)
+ {\vlap{\hrule width\total@wd height\mainrule}% tracer la réglure horizontale
+ \kern\yunit% insérer l'espace vertical
+ }%
+ \vlap{\hrule width\total@wd height\mainrule}% dernière réglure horizontale
+ }%
+}
+\catcode`@12
+\setbox0\hbox{\grid{4}{}{3}{}}% range la quadrillage dans le registre no 0
+Essai \copy0{} qui a pour
+largeur=\convertunit{\wd0}{cm} cm et pour hauteur=\convertunit{\ht0}{cm} cm
+****************** Fin code ******************
+
+
+****************** Code 268 ******************
+Début\vbox to0pt{\hbox{sous}\hbox{la ligne de base}\vss}suite
+****************** Fin code ******************
+
+
+****************** Code 269 ******************
+\xunit=0.5cm \yunit=0.5cm \mainrule=0.8pt \subrule=0.2pt
+\def\vlap#1{\vbox to0pt{\vss#1\vss}}
+\catcode`@11
+\def\grid#1#2#3#4{%
+ \vbox{% empiler les éléments verticalement
+ \offinterlineskip% pas de ressort d'interligne
+ \edef\total@wd{\the\dimexpr\xunit*#1\relax}% largeur totale de la boite
+ \edef\sub@unit{\the\dimexpr\yunit/#4\relax}% hauteur verticale de la subdivision
+ \for\ii = 1 to #3 \do% pour chaque unité verticale en partant du haut, tracer :
+ {\vlap{\hrule width\total@wd height\mainrule}% la réglure horizontale principale
+ % et dessous, les réglures horizontales secondaires :
+ \vbox to\z@{% dans une \vbox de hauteur nulle,
+ \for\jj = 2 to #4 \do 1% insérer #4-1 fois sous la position courante :
+ {\kern\sub@unit % l'espace verticale
+ \vlap{\hrule width\total@wd height\subrule}% et la réglure secondaire
+ }%
+ \vss% ressort qui se comprime pour satisfaire la hauteur nulle
+ }%
+ \kern\yunit% insérer l'espace vertical entre réglures principales
+ }%
+ \vlap{\hrule width\total@wd height\mainrule}% dernière réglure principale du bas
+ }%
+}
+\catcode`@12
+\setbox0=\hbox{\grid{4}{}{3}{5}}
+Essai \copy0{} qui a pour
+largeur=\convertunit{\wd0}{cm} cm et pour hauteur=\convertunit{\ht0}{cm} cm
+****************** Fin code ******************
+
+
+****************** Code 270 ******************
+\mainrule=0.8pt \subrule=0.2pt
+\def\vlap#1{\vbox to0pt{\vss#1\vss}}
+\catcode`@11
+\def\grid#1#2#3#4{%
+ \vbox{% empiler les éléments verticalement
+ \offinterlineskip% pas de ressort d'interligne
+ % #################### Tracé des réglures verticales ####################
+ \vbox to\z@{% dans une \vbox de hauteur nulle
+ \edef\total@ht{\the\dimexpr\yunit*#3\relax}% hauteur totale
+ \edef\sub@unit{\the\dimexpr\xunit/#2\relax}% espace entre 2 subdivisions
+ \rlap{% mettre à droite de la position sans bouger
+ \for\ii = 1 to #1 \do 1% pour chaque unité horizontale
+ {\clap{\vrule width\dimexpr\mainrule height\total@ht}% réglure principale
+ \rlap{% mettre à droite de la position sans bouger
+ \for\jj = 2 to #2 \do 1% insérer #2-1 fois
+ {\kern\sub@unit % l'espace horizontal
+ \clap{\vrule width\subrule height\total@ht}% et la réglure verticale
+ }%
+ }%
+ \kern\xunit % insérer l'espace entre réglures horizontales
+ }%
+ \clap{\vrule width\mainrule height\total@ht}% dernière réglure principale
+ }%
+ \vss% compense la hauteur=0pt de la \vbox
+ }%
+ % #################### Tracé des réglures horizontales ####################
+ \edef\total@wd{\the\dimexpr\xunit*#1\relax}% largeur totale de la boite
+ \edef\sub@unit{\the\dimexpr\yunit/#4\relax}% espace entre 2 subdivisions
+ \for\ii = 1 to #3 \do 1% pour chaque carreau vertical en partant du haut :
+ {\vlap{\hrule width\total@wd height\mainrule}% réglure horizontale principale
+ % et dessous, les réglures secondaires :
+ \vbox to\z@{% dans une \vbox de hauteur nulle,
+ \for\jj = 2 to #4 \do 1% insérer #4-1 fois sous la position courante :
+ {\kern\sub@unit % l'espace vertical
+ \vlap{\hrule width\total@wd height\subrule}% et la réglure secondaire
+ }%
+ \vss% ressort qui se comprime pour satisfaire la hauteur nulle
+ }%
+ \kern\yunit% insérer l'espace vertical entre réglures principales
+ }%
+ \vlap{\hrule width\total@wd height\mainrule}% dernière réglure horizontale
+ }%
+}
+\catcode`@12
+Grille 1 : \xunit=1cm \yunit=1cm \grid{5}{10}{2}{10}\smallskip
+
+Grille 2 : \xunit=0.5cm \yunit=0.5cm \grid{7}{1}{3}{1}\smallskip
+
+Grille 3 : \xunit=1.5cm \yunit=0.5cm \grid{4}{3}{3}{2}
+****************** Fin code ******************
+
+
+****************** Code 271 ******************
+\vrule\hbox to10cm{\leaders\hbox to1.5cm{\hss A\hss}\hfill}\vrule
+****************** Fin code ******************
+
+
+****************** Code 272 ******************
+\frboxsep=-\frboxrule \def~{\leavevmode\raise.75ex\hbox{\vrule height.2pt width1em}}
+~\hbox to10cm{\leaders\hbox{\frbox{\hbox to1.5cm{\hss A\hss}}}\hfill}~
+
+~\hbox to10cm{\cleaders\hbox{\frbox{\hbox to1.5cm{\hss A\hss}}}\hfill}~
+
+~\hbox to10cm{\xleaders\hbox{\frbox{\hbox to1.5cm{\hss A\hss}}}\hfill}~
+****************** Fin code ******************
+
+
+****************** Code 273 ******************
+a) \leavevmode\hbox to10cm{\leaders\hrule\hfill}\smallskip
+
+b) \hbox to10cm{\leaders\hbox{\vrule height0.2pt width2.5mm \kern1.5mm}\hfill}
+
+c) \vrule width0.2pt height1ex depth0pt % première réglure verticale
+ \hbox to10cm{% puis répétition de "_|"
+ \leaders\hbox{\vrule width2em height0.2pt \vrule width0.2pt height1ex}\hfill}
+
+d) \hbox to10cm{\leaders\hbox{%
+ \vrule height.2pt width.5em% 1/2 palier bas
+ \vrule height5pt width0.2pt% montée au palier haut
+ \vrule height5pt depth-4.8pt width1em% palier haut
+ \vrule height5pt width0.2pt% descente au palier bas
+ \vrule height.2pt width.5em% 1/2 palier bas
+ }\hfill}
+****************** Fin code ******************
+
+
+****************** Code 274 ******************
+\mainrule=0.8pt \subrule=0.2pt
+\def\carreau#1#2{% #1=nb subdiv H #2=nb subdiv V
+ \vbox to\yunit{% dans un \vbox de hauteur \yunit
+ \offinterlineskip% pas de ressort d'interligne
+ \vlap{\hrule height\mainrule width\xunit}% réglure principale du haut
+ \leaders% répéter (ici ce sera donc #2-1 fois)
+ \vbox to\dimexpr\yunit/#2\relax% une \vbox de hauteur \yunit/#2
+ {\vss% ressort qui va s'étirer à \yunit/#2
+ \vlap{\hrule height\subrule width\xunit}% réglure de subdiv de dim 0pt
+ }\vfill
+ \kern\dimexpr\yunit/#2\relax% dernière espace verticale
+ \vlap{\hrule height\mainrule width\xunit}% réglure principale du bas
+ }%
+}
+\yunit=1cm
+\leavevmode \carreau{}{4} puis \carreau{}{10}
+****************** Fin code ******************
+
+
+****************** Code 275 ******************
+\mainrule=0.8pt \subrule=0.2pt
+\def\carreau#1#2{% #1=nb subdiv H #2=nb subdiv V
+ % ######## réglures horizontales ########
+ \rlap{% mettre à droite de la position sans bouger
+ \vbox to\yunit{% dans un \vbox de hauteur \yunit
+ \offinterlineskip% pas de ressort d'interligne
+ \vlap{\hrule height\mainrule width\xunit}% réglure principale du haut
+ \leaders% répéter (ici ce sera #2-1 fois)
+ \vbox to\dimexpr\yunit/#2\relax% une \vbox de hauteur \yunit/#2
+ {\vss% ressort qui va s'étirer à \yunit/#2
+ \vlap{\hrule height\subrule width\xunit}% réglure de subdiv de dim 0pt
+ }\vfill% ressort de \leaders
+ \kern\dimexpr\yunit/#2\relax% derniere espace verticale
+ \vlap{\hrule height\mainrule width\xunit}% réglure principale du bas
+ }%
+ }%
+ % ######## réglures verticales ########
+ \hbox to\xunit{% dans une \hbox de longueur \xunit
+ \clap{\vrule height\yunit width\mainrule}% réglure principale de gauche
+ \leaders% répéter (ici ce sera #1-1 fois)
+ \hbox to\dimexpr\xunit/#1\relax
+ {\hss% ressort qui va s'étirer à \xunit/#1
+ \clap{\vrule height\yunit width\subrule}% réglure H de dimension 0
+ }\hfill% ressort de \leaders
+ \kern\dimexpr\xunit/#1\relax% dernière espace H
+ \clap{\vrule height\yunit width\mainrule}% réglure principale de droite
+ }%
+}
+\yunit=1cm \xunit=2cm
+\leavevmode \carreau{3}{4} puis \carreau{8}{10}
+****************** Fin code ******************
+
+
+****************** Code 276 ******************
+\mainrule=0.8pt \subrule=0.2pt
+\def\grid#1#2#3#4{%
+ \vbox to#3\yunit{% dans une boite verticale de hauteur #3*\yunit
+ \leaders% répéter verticalement
+ \hbox to#1\xunit{% une boite de longueur #1*\xunit
+ \leaders% dans laquelle se répète horizontalement
+ \hbox{\carreau{#2}{#4}}% le carreau de largeur \xunit
+ \hfill}%
+ \vfill
+ }%
+}
+Grille 1 : \xunit=1cm \yunit=1cm \grid{5}{10}{2}{10}\smallskip
+
+Grille 2 : \xunit=0.5cm \yunit=0.5cm \grid{7}{1}{3}{1}\smallskip
+
+Grille 3 : \xunit=1.5cm \yunit=0.5cm \grid{4}{3}{3}{2}
+****************** Fin code ******************
+
+
+****************** Code 277 ******************
+\outer\def\foo{Bonjour}
+\def\bar{\foo}
+****************** Fin code ******************
+
+
+****************** Code 278 ******************
+\outer\def\foo{Bonjour}
+\expandafter\def\expandafter\bar\expandafter{\noexpand\foo}
+\meaning\bar
+
+\edef\baz{\noexpand\foo}
+\meaning\baz
+****************** Fin code ******************
+
+
+****************** Code 279 ******************
+\catcode`\@11
+\long\def\filedef#1#2{%
+ \begingroup
+ \let\input\@@input% <- utilisateurs de latex uniquement
+ \everyeof{\eof@nil\noexpand}% insère "\eof@nil\noexpand" à la fin du fichier
+ \expandafter\filedef@i\expandafter#1% développe \input #2
+ \expandafter\relax\input #2
+}
+\long\def\filedef@i#1#2\eof@nil{%
+ \endgroup
+ \expandafter\def\expandafter#1\expandafter{\gobone#2}% mange le \relax
+}
+\catcode`\@12
+\filedef\foo{test.txt}
+\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 280 ******************
+% canal de lecture employé dans tout ce chapitre
+\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
+}
+a) \iffileexists\rtest{test.txt}{vrai}{faux}\qquad
+b) \iffileexists\rtest{foobar.txt}{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 281 ******************
+\openin\rtest =filetest.txt
+\read\rtest to \foo% lit la première ligne
+1) Signification : \meaning\foo.\par% signification de ce qui a été lu
+1) Exécution : \foo\par
+\read\rtest to \foo% lit la deuxième ligne
+2) Signification : \meaning\foo.\par
+2) Exécution : \foo\par
+\read\rtest to \foo% lit la dernière ligne
+3) Signification : \meaning\foo.\par
+3) Exécution : \foo
+\closein\rtest
+****************** Fin code ******************
+
+
+****************** Code 282 ******************
+\openin\rtest =filetest.txt
+\readline\rtest to \foo% lit la première ligne
+1) Signification : \meaning\foo.\par% signification de ce qui a été lu
+1) Exécution : \foo\par
+\readline\rtest to \foo% lit la deuxième ligne
+2) Signification : \meaning\foo.\par
+2) Exécution : \foo\par
+\readline\rtest to \foo% lit la dernière ligne
+3) Signification : \meaning\foo.\par
+3) Exécution : \foo
+\closein\rtest
+****************** Fin code ******************
+
+
+****************** Code 283 ******************
+Valeur de \string\endlinechar = \number\endlinechar\par
+Caractère correspondant : << \char\endlinechar{} >>
+****************** Fin code ******************
+
+
+****************** Code 284 ******************
+\openin\rtest =filetest.txt
+Ligne 1 : {\endlinechar=-1 \global\read\rtest to \foo}% lit la première ligne
+\meaning\foo.\par% donne ce qui a été lu
+Ligne 2 : {\endlinechar=-1 \global\read\rtest to \foo}% lit la deuxième ligne
+\meaning\foo.\par
+Ligne 3 : {\endlinechar=-1 \global\read\rtest to \foo}% lit la dernière ligne
+\meaning\foo.
+\closein\rtest
+****************** Fin code ******************
+
+
+****************** Code 285 ******************
+\def\xread#1to#2{%
+ \ifcs{#2}% si #2 est une séquence de contrôle
+ {\edef\restoreendlinechar{\endlinechar=\the\endlinechar}%
+ \endlinechar=-1 % supprime le caractère mis en fin de ligne
+ \read#1to#2% lit la ligne et l'assigne à la macro #2
+ \restoreendlinechar\relax% restaure le \endlinechar
+ }% si #2 n'est pas une séquence de contrôle,
+ {\xread#1to}% ignorer #2, et recommencer
+}
+
+\openin\rtest =filetest.txt
+Ligne 1 : \xread\rtest to \foo% lit la première ligne
+\meaning\foo.\par% donne ce qui a été lu
+Ligne 2 : \xread\rtest to \foo% lit la deuxième ligne
+\meaning\foo.\par
+Ligne 3 : \xread\rtest to \foo% lit la dernière ligne
+\meaning\foo.
+\closein\rtest
+****************** Fin code ******************
+
+
+****************** Code 286 ******************
+\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> pour effectuer l'assignation
+}
+\catcode`\@12
+
+\openin\rtest =filetest.txt
+Ligne 1 : \xread\rtest to \foo% lit la première ligne
+\meaning\foo.\par% donne ce qui a été lu
+Ligne 2 : \xread\rtest to \foo% lit la deuxième ligne
+\meaning\foo.\par
+Ligne 3 : \xread\rtest to \foo% lit la dernière ligne
+\meaning\foo.
+\closein\rtest
+****************** Fin code ******************
+
+
+****************** Code 287 ******************
+\def\macroname{% se développe en le nom de la macro qui suit sans
+ % le caractère d'échappement
+ \ifnum\escapechar>-1 % si le caractère d'échappement est positif
+ \ifnum\escapechar<256 % et inférieur à 256, développer les 2 "\fi"
+ \expandafter\expandafter\expandafter\expandafter% et le "\string", puis
+ \expandafter\expandafter\expandafter\gobone% manger le "\" avec \gobone
+ \fi
+ \fi
+ \string% doit être suivi d'une macro
+}
+\catcode`\@11
+\newcount\field@cnt
+\def\searchitem#1#2#3#4{% #1= canal #2=nom fichier #3=référence #4=macro à définir
+ \let#4\gobone% pour l'instant, #4=\gobone
+ \openin#1=#2\relax
+ \unless\ifeof#1% si le fichier existe
+ \lowercase{\def\sought@firstfield{#3}}% stocke le 1er champ à chercher
+ \edef\macro@name{\macroname#4}% nom de la macro sans "\"
+ \xread#1 to \current@line% lire la première ligne
+ \field@cnt=0 % initialiser le compteur de champs
+ % ################ sauvegarde du nom des champs ################
+ \expsecond{\doforeach\current@field\in}\current@line% pour chaque champ
+ {\advance\field@cnt1 % incrémenter le compteur de champs
+ \lowercase\expandafter{% e texte de remplacement de \current@field en minuscule
+ \expandafter\def\expandafter\current@field\expandafter{\current@field}%
+ }%
+ % sauvegarder chaque champ de la 1re ligne (qui sont les intitulés) dans une macro
+ \letname{fieldname\number\field@cnt}=\current@field
+ }%
+ \edef\field@num{\number\field@cnt}% nombre de champs
+ % ################ lecture des lignes de données ################
+ \loop% tant que...
+ \unless\ifeof#1\relax% ...la fin du fichier n'est pas atteinte
+ \xread#1 to \current@line% lire une ligne
+ \unless\ifx\current@line\empty% si elle n'est pas vide
+ % examniner les champs qu'elle contient (aller à \test@field)
+ \expsecond{\expandafter\test@field\current@line\@nil}\macro@name%
+ \fi
+ \repeat
+ \fi
+ \closein#1\relax
+}
+
+\def\test@field#1,#2\@nil#3{% #1=champ no 1 #2=autres champs #3=nom de la macro sans "\"
+ \def\current@firstfield{#1}% stocke le premier champ de la ligne en cours
+ \ifx\current@firstfield\sought@firstfield% s'il est égal à celui cherché
+ \defname{#3.\csname fieldname1\endcsname}{#1}% définir la macros \<#3."champ 1">
+ \field@cnt=1 % initialiser le compteur de champ
+ \doforeach\current@field\in{#2}% puis, pour i>2, définir les macros \<#3."champ i">
+ {\advance\field@cnt1 % incrémenter le compteur de champ
+ \letname{#3.\csname fieldname\number\field@cnt\endcsname}=\current@field
+ }%
+ \defname{#3}##1{% et définir la macro \<#3>
+ \ifcsname#3.##1\endcsname% si la macro \<#3."argument"> existe déjà
+ \csname#3.##1\expandafter\endcsname% l'exécuter après avoir mangé le \fi
+ \fi
+ }%
+ \fi
+}
+\catcode`\@12
+
+\searchitem\rtest{fournitures.txt}{4562u}\monarticle
+réf = \monarticle{ref},
+dénomination = \monarticle{item},
+prix = \monarticle{prix},
+fournisseur = \monarticle{fournisseur},
+champ non existant = \monarticle{foobar}.
+
+\searchitem\rtest{fournitures.txt}{truc}\essai% référence "truc" n'existe pas
+réf = \essai{ref},
+dénomination = \essai{item},
+prix = \essai{prix},
+fournisseur = \essai{fournisseur}.
+****************** Fin code ******************
+
+
+****************** Code 288 ******************
+\def\macroname{% se développe en le nom de la macro qui suit sans
+ % le caractère d'échappement
+ \ifnum\escapechar>-1 % si le caractère d'échappement est positif
+ \ifnum\escapechar<256 % et inférieur à 256, développer les 2 "\fi"
+ \expandafter\expandafter\expandafter\expandafter% et le "\string", puis
+ \expandafter\expandafter\expandafter\gobone% manger le "\" avec \gobone
+ \fi
+ \fi
+ \string% doit être suivi d'une macro
+}
+\catcode`\@11
+\newcount\field@cnt
+\newif\ifsearch@repeat
+\def\assign@arg#1=#2\@nil{%
+ \def\sought@fieldnumber{#1}% no du champ à chercher
+ \def\sought@fielvalue{#2}% et sa valeur
+}
+\def\searchitem#1#2#3#4{% #1= canal #2=nom fichier #3=champ cherché #4=macro à définir
+ \let#4\gobone% pour l'instant, #4=\gobone
+ \openin#1=#2\relax%
+ \unless\ifeof#1% si le fichier existe
+ \edef\macro@name{\macroname#4}% nom de la macro sans "\"
+ \xread#1 to \current@line% lire et ignorer la première ligne
+ \ifin{#3}{=}% si #3 contient =
+ {\assign@arg#3\@nil}% trouver le no de champ et sa valeur
+ {\def\sought@fieldnumber{1}% sinon, no du champ = 1
+ \def\sought@fielvalue{#3}% et sa valeur = #3
+ }%
+ % ################ lecture des lignes de données ################
+ \search@repeattrue% poursuite de la boucle loop : vraie
+ \loop% tant que...
+ \ifeof#1\relax% ...la fin du fichier n'est pas atteinte
+ \search@repeatfalse% sortir de la boucle loop
+ \else
+ \xread#1 to \current@line% lire une ligne
+ \unless\ifx\current@line\empty% si elle n'est pas vide
+ % examniner les champs qu'elle contient (aller à \test@field)
+ \expsecond{\expandafter\test@field\current@line\@nil}\macro@name%
+ \fi
+ \fi
+ \ifsearch@repeat% ne poursuivre que si le booléen en vrai
+ \repeat
+ \fi
+ \closein#1\relax
+}
+
+\def\test@field#1\@nil#2{% #1=champs #2=nom de la macro sans "\"
+ \field@cnt=0 % initialiser le compteur de champ
+ \doforeach\current@field\in{#1}% parcourir les champs de la ligne en cours
+ {\advance\field@cnt1 % incrémenter le compteur de champ
+ \ifnum\field@cnt=\sought@fieldnumber\relax% si c'est le bon numéro de champ
+ \ifx\current@field\sought@fielvalue% et si le champ correspond à celui cherché
+ \search@repeatfalse% sortir de la boucle loop
+ \doforeachexit% sortir de la boucle \doforeach en cours
+ \fi
+ \fi
+ }%
+ \unless\ifsearch@repeat% si la ligne a été trouvée
+ \field@cnt=0 % initialiser le compteur de champ
+ \doforeach\current@field\in{#1}% parcourir à nouveau les champs de la ligne
+ {\advance\field@cnt1 % incrémenter le compteur de champ
+ \letname{#2.\number\field@cnt}=\current@field% faire l'assignation
+ }%
+ \defname{#2}##1{% et définir la macro \<#2>
+ \ifcsname#2.##1\endcsname% si la macro \<#2."argument"> existe déjà
+ \csname#2.##1\expandafter\endcsname% l'exécuter après avoir mangé le \fi
+ \fi
+ }%
+ \fi
+}
+\catcode`\@12
+a) \searchitem\rtest{basecourse.txt}{3=283}\foo
+ "\foo1", "\foo2", "\foo3", "\foo4", "\foo5", "\foo6", "\foo7"
+
+b) \searchitem\rtest{basecourse.txt}{Valet}\bar
+ "\bar1", "\bar2", "\bar3", "\bar4", "\bar5", "\bar6", "\bar{abcd}"
+****************** Fin code ******************
+
+
+****************** Code 289 ******************
+\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
+ \loop
+ \xread#1 to \currline% lire une ligne
+ \unless\ifeof#1% si la fin du fichier n'est pas atteinte
+ \leavevmode\par% aller à la ligne
+ \currline% afficher la ligne lue
+ \repeat% recommencer
+ \fi
+ \closein#1\relax
+ \endgroup
+}
+
+Contenu du fichier : "\showfilecontent\rtest{readtest.txt}", affiché tel quel
+****************** Fin code ******************
+
+
+****************** Code 290 ******************
+\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
+}
+
+Contenu du fichier : "\showfilecontent\rtest{readtest.txt}", affiché tel quel
+****************** Fin code ******************
+
+
+****************** Code 291 ******************
+% sera le canal d'écriture dans tout ce chapitre
+\immediate\openout\wtest=writetest.txt % lie \wtest au fichier
+\immediate\write\wtest{Programmer en \noexpand\TeX{} est facile.}% écrit une ligne
+\immediate\write\wtest{Et utile...}% puis une autre
+\immediate\closeout\wtest% défait la liaison
+a) Contenu du fichier :\par
+"\showfilecontent\rtest{writetest.txt}"% affiche le contenu du fichier
+\medbreak
+% 2e tentative :
+b) Contenu du fichier :\par
+\immediate\openout\wtest=writetest.txt % lie \wtest au fichier
+\immediate\write\wtest{Essai d'écriture}% écrit une ligne
+\immediate\closeout\wtest% défait la liaison
+"\showfilecontent\rtest{writetest.txt}"% affiche le contenu du fichier
+****************** Fin code ******************
+
+
+****************** Code 292 ******************
+\def\noexpwrite#1#2{% #1=numéro de canal #2=texte à écrire
+ \write#1{\unexpanded{#2}}%
+}
+\immediate\openout\wtest=writetest.txt
+\immediate\noexpwrite\wtest{Programmer en \TeX{} est facile.}%
+\immediate\noexpwrite\wtest{Et utile...}%
+\immediate\closeout\wtest
+Contenu du fichier :\par
+\showfilecontent\rtest{writetest.txt}% affiche le contenu du fichier
+****************** Fin code ******************
+
+
+****************** Code 293 ******************
+\catcode`\@11
+\def\exactwrite#1{% #1=numéro de canal
+ \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
+ \exactwrite@i% aller lire le <car>
+}
+
+\def\exactwrite@i#1{% #1 est le <car> de catcode 12
+ \def\exactwrite@ii##1#1{% ##1 est le <texte> à envoyer vers le fichier
+ \exactwrite@iii##1\@nil% envoyer <texte> à \exactwrite@iii
+ }%
+ \exactwrite@ii% va lire tout ce qui se trouve jusqu'au prochain <car>
+}
+
+{\catcode`\^^M 12 \gdef\EOL@char{^^M}}% définit le caractère <EOL> de catcode 12
+
+\def\exactwrite@iii#1\@nil{% #1 = <texte> à écrire dans le fichier
+ \expsecond{\ifin{#1}}\EOL@char% si #1 contient "retour charriot"
+ {\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% recommencer avec ce qui se trouve après "^^M"
+}
+\catcode`\@12
+
+\immediate\openout\wtest=writetest.txt % lie le canal \wtest au fichier
+\exactwrite\wtest|Programmer en \TeX{} est facile !
+
+Et très utile.|
+\immediate\closeout\wtest% et fermer le fichier
+
+Le contenu du fichier "writetest.txt" est :\par
+"\showfilecontent\rtest{writetest.txt}"
+****************** Fin code ******************
+
+
+****************** Code 294 ******************
+\catcode`\@11
+\newcount\exo@number% compteur pour le numéro d'exercice
+
+\def\exocalctotal#1\endtotal{\edef\total@points{\dimtodec\dimexpr#1}}
+
+\def\initexo#1{%
+ \def\exo@canal{#1}% sauvegarde le canal d'écriture
+ \exo@number=0 % initialiser le compteur d'exo
+ \iffileexists\exo@canal{\jobname.pts}% si le fichier .pts existe
+ {\input \jobname.pts }% le lire et exécuter son contenu
+ {\def\total@points{\char`\#\char`\#}}% sinon, définir un total alternatif
+ \immediate\openout\exo@canal=\jobname.pts % ouvrir le fichier .pts
+ \immediate\write\exo@canal{\noexpand\exocalctotal}% et commencer à y écrire dedans
+}
+
+\def\exo#1{% définti la macro qui affiche l'exercice
+ \bigbreak% sauter une grande espace verticale
+ \immediate\write\exo@canal{+#1}% écrire "+#1" dans le fichier .pts
+ \advance\exo@number by 1 % incrémenter le numéro de l'exercice
+ \noindent\vrule height1ex width1ex depth0pt % trace le carré
+ \kern1ex% insérer une espace horizontale
+ {\bf Exercice \number\exo@number}% afficher "Exercice <nombre>"
+ \leaders\hbox to.5em{\hss.\hss}\hfill% afficher les pointillés
+ #1/\total@points% puis #1/<total>
+ \smallbreak% composer la ligne précédente et sauter une espace verticale
+}
+
+\def\stopexo{%
+ \immediate\write\exo@canal{\relax\noexpand\endtotal}%
+ \immediate\closeout\exo@canal
+}
+\catcode`\@12
+\initexo\wtest
+
+\hfill{\bf Interrogation écrite. Sujet : \TeX{}}\hfill\null
+\par
+\leavevmode\hfill\vrule height.4pt width 2cm depth0pt\hfill\null
+\exo{3pt}
+Élaborer un test \litterate/\ifonebyte{<texte>}{<vrai>}{<faux>}/ qui teste, pour une
+compilation avec un moteur 8 bits, si le \litterate/<texte>/ est codé sur un seul
+octet. Ce test pourrait être utilisé pour déterminer si l'encodage d'un document
+est à plusieurs octets (comme l'est UTF8) en prenant comme \litterate/<texte>/
+les caractères <<~é~>>, <<~à~>>, etc.
+
+\exo{5,5pt}
+Si \verb-#1- est un nombre entier, quel est le test fait par ce code ?
+\smallbreak
+\hfill
+\litterate/\if\string l\expandafter\firstto@nil\romannumeral#1\relax\@nil/
+\hfill\null
+
+\exo{4,5pt}
+On a vu que pour provoquer un $n$-développement, les \litterate/\expandafter/se plaçaient
+en nombre égal à $2^n-1$ devant chaque token précédant celui que l'on veut développer.
+Or, ce nombre est {\it impair\/}. Trouver un exemple ou un cas particulier où il faut
+placer un nombre {\it pair\/} d'\litterate/\expandafter/ devant un token (on pourra
+envisager le cas de 2 \litterate/\expandafter/).
+\stopexo
+****************** Fin code ******************
+
+
+****************** Code 295 ******************
+\def\identite{Foo Bar}% Prénom Nom
+\def\beforespace#1 #2\nil{#1}
+\def\afterspace#1 #2\nil{#2}
+\def\prenom{\beforespace\identite\nil}
+\def\nom{\afterspace\identite\nil}
+Mon prénom : \expandafter\expandafter\prenom
+
+Mon nom : \expandafter\expandafter\nom
+****************** Fin code ******************
+
+
+****************** Code 296 ******************
+\newlinechar`\^^J
+\immediate\openout\wtest=test1.txt
+\immediate\write\wtest{Une première ligne^^JEt une seconde.}
+\immediate\closeout\wtest
+\showfilecontent\rtest{test1.txt}
+****************** Fin code ******************
+
+
+****************** Code 297 ******************
+\newlinechar`\^^J
+\immediate\openout\wtest=test2.txt
+\immediate\write\wtest{Une première ligne^^JEt une seconde.}
+\immediate\write\wtest{Et la dernière.}
+\immediate\closeout\wtest
+
+{\endlinechar`\X % insère "X" à chaque fin de ligne
+\openin\rtest=test2.txt % les fins de lignes sont commentées
+\loop% pour éviter que \endlinechar
+ \read\rtest to \foo% ne soit inséré à chaque fin de
+ \unless\ifeof\rtest% ligne du code source
+ \meaning\foo\par% affiche le texte de remplacement de \foo
+\repeat%
+\closein\rtest}%
+****************** Fin code ******************
+
+
+****************** Code 298 ******************
+\catcode`\@11
+\def\exactwrite#1{% #1=numéro de canal
+ \begingroup
+ \for\xx=0 to 255\do{\catcode\xx=12 }% donne à tous les octets le catcode 12
+ \newlinechar=`\^^M % caractère de fin de ligne = retour charriot
+ \exactwrite@i{#1}% donne le <canal> d'écriture comme premier argument
+}
+
+\def\exactwrite@i#1#2{% #2 est le caractère délimiteur de catcode 12
+ \def\exactwrite@ii##1#2{% ##1 est le <texte> à envoyer vers le fichier
+ \immediate\write#1{##1}% écrire le <texte> dans le fichier
+ \endgroup% puis, sortir du groupe
+ }%
+ \exactwrite@ii% traiter tout ce qui se trouve jusqu'au prochain #2
+}
+\catcode`\@12
+
+\immediate\openout\wtest=writetest.txt % lie le canal \wtest au fichier
+\exactwrite\wtest|Programmer en \TeX{} est facile !
+
+Et très utile.|
+\immediate\closeout\wtest% et fermer le fichier
+
+Le contenu du fichier "writetest.txt" est :\par
+"\showfilecontent\rtest{writetest.txt}"
+****************** Fin code ******************
+
+
+****************** Code 299 ******************
+\newlinechar`\^^J
+\message{^^JQuel est votre nom ? }
+\xread-1 to \username
+\message{Bonjour \username.^^J%
+Depuis combien d'années pratiquez-vous TeX ? }
+\read-1 to \yeartex
+\message{%
+ \ifnum\yeartex<5 Cher \username, vous êtes encore un débutant !
+ \else\ifnum\yeartex<10 Bravo \username, vous êtes un TeXpert !
+ \else\ifnum\yeartex<15 Félicitations \username, vous êtes un TeXgourou.
+ \else Passez à autre chose, par exemple à Metafont et Metapost !
+ \fi\fi\fi^^J}
+****************** Fin code ******************
+
+
+****************** Code 300 ******************
+\catcode`\@11
+\def\answer@plus{+}\def\answer@minus{-}\def\answer@equal{=}%
+\def\nb@found#1{% macro appelée lorsque le nombre (argument #1) est trouvé
+ \message{^^JVotre nombre est #1.^^JMerci d'avoir joué avec moi.^^J}%
+}
+
+\def\nbguess#1#2{%
+ \message{Choisissez un nombre entre #1 et #2.^^J
+ Tapez entrée lorsque c'est fait.}%
+ \read-1 to \tex@guess% attend que l'on tape sur "entrée"
+ \nbguess@i{#1}{#2}%
+}
+
+\def\nbguess@i#1#2{%
+ \ifnum#1<#2 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+ % si #1<#2 (donc le nombre n'est pas trouvé),
+ % mettre dans \tex@guess la troncature de la moyenne de #1 et #2
+ {\edef\tex@guess{\number\truncdiv{\numexpr#1+#2\relax}2}%
+ \message{Je propose \tex@guess.^^J% afficher sur le terminal
+ Votre nombre est-il plus grand (+), plus petit (-) ou égal (=) : }%
+ \read -1 to \user@answer% lire la réponse de l'utilisateur
+ \edef\user@answer{%
+ \expandafter\firstto@nil\user@answer\relax\@nil% ne garder que le 1er caractère
+ }%
+ \ifxcase\user@answer% envisager les cas "+", "-" et "="
+ \answer@plus{\exparg\nbguess@i{\number\numexpr\tex@guess+1\relax}{#2}}%
+ \answer@minus{\expsecond{\nbguess@i{#1}}{\number\numexpr\tex@guess-1\relax}}%
+ \answer@equal{\nb@found\tex@guess}%
+ \elseif% si la réponse ne commence pas par "+", "-" ou "="
+ \message{Je n'ai pas compris votre réponse}% afficher message erreur
+ \nbguess@i{#1}{#2}% et recommencer avec les mêmes nombres
+ \endif
+ }
+ % si #1>=#2, le nombre est trouvé
+ {\nb@found{#1}}%
+}
+\catcode`\@12
+
+\nbguess{1}{100}
+****************** Fin code ******************
+
+
+****************** Code 301 ******************
+\def\syracuse#1{%
+ #1% affiche le nombre
+ \ifnum#1>1 % si le nombre est >1
+ , % afficher une virgule+espace
+ \ifodd#1 % s'il est pair
+ \exparg\syracuse% appeler la macro \syracuse
+ {\number\numexpr3*#1+1% avec 3*n+1
+ \expandafter\expandafter\expandafter}% après avoir rendu la macro terminale
+ \else % s'il est pair
+ \expandafter\syracuse\expandafter% appeler la macro \syracuse
+ {\number\numexpr#1/2% avec n/2
+ \expandafter\expandafter\expandafter}% après avoir rendu la macro terminale
+ \fi
+ \else% si le nombre est 1
+ .% afficher un point
+ \fi
+}
+a) \syracuse{20}\par
+b) \syracuse{14}\par
+c) \syracuse{99}\par
+d) \edef\foo{\syracuse{15}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 302 ******************
+\def\syracuse#1{%
+ #1% afficher le nombre
+ \ifnum#1>1 % si le nombre est >1
+ , % afficher une virgule+espace
+ \exparg\syracuse{% appeler la macro \syracuse
+ \number\numexpr% avec le nombre :
+ \ifodd#1 3*#1+1% 3n+1 si #1 est impair
+ \else #1/2% n/2 sinon
+ \fi%
+ \expandafter}% avant de rendre la récursivité terminale
+ \else
+ .% si #1=1, afficher un point
+ \fi
+}
+a) \syracuse{20}\par
+b) \syracuse{14}\par
+c) \syracuse{99}\par
+d) \edef\foo{\syracuse{15}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 303 ******************
+\def\factorielle#1{%
+ \ifnum#1=0 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+ {1}% "1" si #1=0}
+ {#1*\exparg\factorielle{\number\numexpr#1-1}}%
+}
+a) \factorielle{0}\qquad
+b) \factorielle{3}\qquad
+c) \edef\foo{\factorielle{8}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 304 ******************
+\catcode`\@11
+\def\factorielle#1{%
+ \number\numexpr\factorielle@i{#1}\relax% appelle \factorielle@i
+ % en lançant le développement maximal
+}
+\def\factorielle@i#1{%
+ \ifnum#1=0 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+ {1}% "1" si #1=
+ {#1*\exparg\factorielle@i{\number\numexpr#1-1}}%
+}
+\catcode`\@12
+a) \factorielle{0}\qquad
+b) \factorielle{3}\qquad
+c) \edef\foo{\factorielle{8}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 305 ******************
+\catcode`\@11
+\def\PGCD#1#2{%
+ \ifnum#1<#2 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+ {\PGCD@i{#2}{#1}}% si #1<#2, mettre #2 (le grand) dans le premier argument
+ {\PGCD@i{#1}{#2}}%
+}
+
+\def\PGCD@i#1#2{% #1=a #2=b avec a>b
+ \exptwoargs\PGCD@ii% appeler la macro récursive avec
+ {\number\numexpr#1-#2*\truncdiv{#1}{#2}}% le reste de a/b
+ {#2}% et le divisieur b
+}
+
+\def\PGCD@ii#1#2{% #1=reste r #2=diviseur b
+ \ifnum#1=\z@\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+ {#2}% si le reste est nul, renvoyer b
+ {\PGCD@i{#2}{#1}}% sinon, recommencer avec b et r
+}
+\catcode`\@12
+a) \PGCD{120}{75}\qquad
+b) \PGCD{64}{180}\qquad
+c) \PGCD{145}{64}\qquad
+d) \edef\foo{\PGCD{1612}{299}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 306 ******************
+\catcode`\@11
+\def\calcPGCD#1#2{%
+ \ifhmode\par\fi% si en mode horizontal, former le paragraphe
+ \ifnum#1<#2 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+ {\calcPGCD@i{#2}{#1}}% si #1<#2, mettre #2 (le grand) dans le premier argument
+ {\calcPGCD@i{#1}{#2}}%
+}
+
+\def\calcPGCD@i#1#2{% #1=a #2=b avec a>b
+ \edef\calcPGCD@quotient{\number\truncdiv{#1}{#2}}% stocke le quotient
+ $#1=\calcPGCD@quotient\times#2% en mode maths, afficher "a=q*b" (à suivre)
+ \exptwoargs\calcPGCD@ii% appeler la macro récursive avec
+ {\number\numexpr#1-#2*\calcPGCD@quotient}% le reste de a/b
+ {#2}% et le divisieur b
+}
+
+\def\calcPGCD@ii#1#2{% #1=reste r #2=diviseur b
+ +#1$\par% (suite du mode math) afficher "+r", fermer le mode math et \par
+ \ifnum#1=\z@\expandafter\firstoftwo\else\expandafter\secondoftwo\fi%
+ {}% si le reste est nul, ne rien faire
+ {\calcPGCD@i{#2}{#1}}% sinon, recommencer avec b et r
+}
+\catcode`\@12
+\calcPGCD{39}{15}\medbreak
+\calcPGCD{1612}{299}
+****************** Fin code ******************
+
+
+****************** Code 307 ******************
+\frboxsep=0pt % encadrer au plus proche
+\leavevmode\frbox{$=$} n'est pas identique à \frbox{${}={}$}
+****************** Fin code ******************
+
+
+****************** Code 308 ******************
+\catcode`\@11
+\def\calcPGCD#1#2{%
+ \vtop{% mettre l'alignement dans une \vtop
+ \halign{% les "#" doivent être doublés puisqu'à l'intérieur d'une macro
+ $\hfil##$&${}=\hfil##$&${}\times##\hfil$&${}+##\hfil$% préambule
+ \cr% fin du préambule et début de la première cellule
+ \ifnum#1<#2 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+ {\calcPGCD@i{#2}{#1}}% si #1<#2, mettre #2 (le grand) dans le premier argument
+ {\calcPGCD@i{#1}{#2}}%
+ \crcr% fin de l'alignement
+ }%
+ }%
+}
+
+\def\calcPGCD@i#1#2{% #1=a #2=b avec a>b
+ \xdef\calcPGCD@quotient{\number\truncdiv{#1}{#2}}% stocke le quotient
+ #1 & \calcPGCD@quotient & #2 &% afficher "a=q*b" (à suivre)
+ \exptwoargs\calcPGCD@ii% appeler la macro récursive avec
+ {\number\numexpr#1-#2*\calcPGCD@quotient}% le reste de a/b
+ {#2}% et le divisieur b
+}
+
+\def\calcPGCD@ii#1#2{% #1=reste r #2=diviseur b
+ #1% (suite de l'alignement) afficher "+r"
+ \cr% et terminer la ligne en cours
+ \ifnum#1=\z@\expandafter\firstoftwo\else\expandafter\secondoftwo\fi%
+ {}% si le reste est nul, ne rien faire
+ {\calcPGCD@i{#2}{#1}}% sinon, recommencer avec b et r
+}
+\catcode`\@12
+a) \calcPGCD{39}{15}\medbreak
+b) \calcPGCD{1612}{299}
+****************** Fin code ******************
+
+
+****************** Code 309 ******************
+\catcode`\@11
+\def\baseconv#1{%
+ \unless\ifnum#1=\z@ % si #1 est différent de 0
+ \number\numexpr#1-2*\truncdiv{#1}2\relax% écrire le reste
+ \exparg\baseconv{\number\truncdiv{#1}2\expandafter}% recommencer avec #1/2
+ \fi% après que le \fi ait été lu
+}
+\catcode`\@12
+a) \baseconv{43}\qquad
+b) \baseconv{32}\qquad
+c) \edef\foo{\baseconv{159}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 310 ******************
+\catcode`\@11
+\def\baseconv#1{%
+ \baseconv@i{}{#1}%
+}
+
+\def\baseconv@i#1#2{% #1=restes #2=n
+ \ifnum#2=\z@\expandafter\firstoftwo\else\expandafter\secondoftwo\fi% si n=0
+ {#1}% si <n>=0, afficher tous les restes
+ {% sinon, recommencer en
+ \exptwoargs\baseconv@i% ajoutant le reste courant avant #1
+ {\number\numexpr#2-2*\truncdiv{#2}2\relax #1}
+ {\number\truncdiv{#2}2}% et en prenant n:=n/2
+ }%
+}
+
+\catcode`\@12
+a) \baseconv{43}\qquad
+b) \baseconv{32}\qquad
+c) \edef\foo{\baseconv{159}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 311 ******************
+\catcode`\@11
+\def\z@@{\expandafter\z@\expandafter}
+\def\basedigit#1{%
+ \ifcase#1
+ \z@@ 0%
+ \or\z@@ 1\or\z@@ 2\or\z@@ 3\or\z@@ 4\or\z@@ 5\or\z@@ 6\or\z@@ 7%
+ \or\z@@ 8\or\z@@ 9\or\z@@ A\or\z@@ B\or\z@@ C\or\z@@ D\or\z@@ E%
+ \or\z@@ F\or\z@@ G\or\z@@ H\or\z@@ I\or\z@@ J\or\z@@ K\or\z@@ L%
+ \or\z@@ M\or\z@@ N\or\z@@ O\or\z@@ P\or\z@@ Q\or\z@@ R\or\z@@ S%
+ \or\z@@ T\or\z@@ U\or\z@@ V\or\z@@ W\or\z@@ X\or\z@@ Y\or\z@@ Z%
+ \fi
+}
+\long\def\>#1<{\detokenize{#1}}
+a) \expandafter\>\romannumeral\basedigit{23}<\quad
+b) \expandafter\>\romannumeral\basedigit{6}<
+\catcode`@12
+****************** Fin code ******************
+
+
+****************** Code 312 ******************
+\catcode`\@11
+\def\baseconv#1#2{% #1=base #2=nombre à convertir
+ \ifnum#1<37 % base maxi = 36 (10 signes chiffres + 26 signes lettres)
+ \antefi
+ \baseconv@i{}{#2}{#1}%
+ \fi
+}
+\def\baseconv@i#1#2#3{% #1=restes #2=n #3=base
+ \ifnum#2=\z@ \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+ {#1}% si n=0, afficher tous les restes
+ {% si non, transmettre en dernier argument
+ \expsecond{\baseconv@ii{#1}{#2}{#3}}%
+ {\number\truncdiv{#2}{#3}}% le quotient
+ }%
+}
+\def\baseconv@ii#1#2#3#4{% #1=restes #2=n #3=base #4=q
+ \exparg\baseconv@i% recommencer, en ajoutant le <chiffre> avant les restes
+ {\romannumeral\basedigit{\number\numexpr#2-#4*#3\relax}#1}%
+ {#4}% et en remplaçant n par q
+ {#3}%
+}
+\def\z@@{\expandafter\z@\expandafter}%
+\def\basedigit#1{%
+ \ifcase#1
+ \z@@ 0%
+ \or\z@@ 1\or\z@@ 2\or\z@@ 3\or\z@@ 4\or\z@@ 5\or\z@@ 6\or\z@@ 7%
+ \or\z@@ 8\or\z@@ 9\or\z@@ A\or\z@@ B\or\z@@ C\or\z@@ D\or\z@@ E%
+ \or\z@@ F\or\z@@ G\or\z@@ H\or\z@@ I\or\z@@ J\or\z@@ K\or\z@@ L%
+ \or\z@@ M\or\z@@ N\or\z@@ O\or\z@@ P\or\z@@ Q\or\z@@ R\or\z@@ S%
+ \or\z@@ T\or\z@@ U\or\z@@ V\or\z@@ W\or\z@@ X\or\z@@ Y\or\z@@ Z%
+ \fi
+}
+\catcode`\@12
+a) "\baseconv{20}{21587}"\qquad
+b) "\baseconv{16}{32}"\qquad
+c) \edef\foo{\baseconv{16}{159}}%
+ "\meaning\foo"\qquad
+d) "\baseconv{2}{43}"
+****************** Fin code ******************
+
+
+****************** Code 313 ******************
+\catcode`\@11
+\def\quark@list{\quark@list}% quark de fin de liste
+\def\finditem#1{% #1 = \<macrolist>, la position est lue plus tard par \finditem@i
+ \exparg\finditem@i{#1}% 1-développe la \<macrolist>
+}
+\def\finditem@i#1#2{% #1 = liste #2=position cherchée
+ \finditem@ii{1}{#2}#1,\quark@list,% appelle la macro récursive
+}
+\def\finditem@ii#1#2#3,{% #1=position courante #2=position cherchée #3=élément courant
+ \ifx\quark@list#3\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+ {}% si la fin de liste est atteinte, ne rien renvoyer
+ {% sinon
+ \ifnum#1=#2 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+ {% si la position est la bonne
+ \finditem@iii{#3}% renvoyer #3 et manger les éléments restants
+ }
+ {% si la position n'est pas la bonne, recommencer en incrémentant #1
+ \exparg\finditem@ii{\number\numexpr#1+1}{#2}%
+ }%
+ }%
+}
+\def\finditem@iii#1#2\quark@list,{% renvoyer #1 et manger le reste de la liste
+ #1%
+}
+\catcode`\@12
+\def\liste{a,bcd,{ef},g,hij,kl}
+a) \edef\foo{\finditem\liste5}\meaning\foo\qquad
+b) \edef\bar{\finditem\liste3}\meaning\bar
+****************** Fin code ******************
+
+
+****************** Code 314 ******************
+\catcode`\@11
+\def\quark@list{\quark@list}% quark de fin de liste
+\def\finditem#1{% #1 = \<macro>, la position est lue plus tard par \finditem@i
+ \exparg\finditem@i{#1}% 1-développe la \<macro>
+}
+\def\finditem@i#1#2{% #1 = liste #2=position cherchée
+ \ifnum#2>\z@% ne faire quelque chose que si la position est >0
+ \antefi
+ \finditem@ii{1}{#2}\relax#1,\quark@list,% appelle la macro récursive
+ \fi
+}
+\def\finditem@ii#1#2#3,{% #1=position courante #2=position cherché #3=élément courant
+ \expandafter\ifx\expandafter\quark@list\gobone#3%
+ \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+ {}% si la fin de liste est atteinte, ne rien renvoyer
+ {% sinon
+ \ifnum#1=#2 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+ {% si la position est la bonne
+ \finditem@iii{#3}% renvoyer #3 et manger les éléments restants
+ }
+ {% si la position n'est pas la bonne, recommencer en incrémentant #1
+ \exparg\finditem@ii{\number\numexpr#1+1}{#2}\relax
+ }%
+ }%
+}
+\def\finditem@iii#1#2\quark@list,{% renvoyer #1 et manger le reste de la liste
+ \gobone#1%
+}
+\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%
+ }%
+ }%
+}
+\catcode`\@12
+\def\liste{a,bcd,{ef},g,hij,kl}
+a) "\finditem\liste5"\qquad
+b) \edef\bar{\finditem\liste3}\meaning\bar\qquad
+c) \finditemtocs\liste{3}\foo\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 315 ******************
+\catcode`\@11
+\def\quark@list{\quark@list}% quark de fin de liste
+\def\positem#1{% #1 = \<macrolist>, la position est lue plus tard par \positem@i
+ \def\positem@endprocess{\pos@item}% hook : afficher la position
+ \exparg\positem@i{#1}% 1-développe la \<macrolist>
+}
+\def\positem@i#1#2{% #1 = liste #2=élément cherché
+ \def\sought@item{#2}% définir l'élément cherché
+ \positem@ii{1}\relax#1,\quark@list,% appelle la macro récursive
+}
+\def\positem@ii#1#2,{% #1=position courante #2=\relax + élément courant
+ \expandafter\def\expandafter\current@item\expandafter{\gobone#2}%
+ \ifx\current@item\quark@list\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+ {\def\pos@item{0}% si la fin de liste est atteinte, renvoyer 0
+ \positem@endprocess% et aller au hook
+ }% sinon
+ {\ifx\current@item\sought@item\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+ {\def\pos@item{#1}% si la position est la bonne, définir la position
+ \positem@goblist% et manger les éléments restants
+ }% si la position n'est pas la bonne, recommencer en incrémentant #1
+ {\exparg\positem@ii{\number\numexpr#1+1}\relax
+ }%
+ }%
+}
+\def\positem@goblist#1\quark@list,{\positem@endprocess}% manger la liste et aller au hook
+
+\def\positemtocs#1#2#3{% #1=\<macrolist> #2=élément à chercher #3=macro à définir
+ \def\positem@endprocess{\let#3=\pos@item}% hook : mettre le résultat dans #3
+ \exparg\positem@i{#1}{#2}% 1-développe la \<macrolist>
+}
+
+\catcode`\@12
+\def\liste{a,bcd,{ef},g,hij,,kl}
+a) \positem\liste{g}\qquad
+b) \positem\liste{ef}\qquad
+c) \positem\liste{{ef}}\qquad
+d) \positem\liste{}\medbreak
+
+\def\liste{a,bcd,{ef},g,hij,,kl}
+a) \positemtocs\liste{g}\foo\meaning\foo\qquad
+b) \positemtocs\liste{ef}\foo\meaning\foo\qquad
+c) \positemtocs\liste{{ef}}\foo\meaning\foo\qquad
+d) \positemtocs\liste{}\foo\meaning\foo\qquad
+****************** Fin code ******************
+
+
+****************** Code 316 ******************
+\catcode`\@11
+\def\quark@list{\quark@list}% quark de fin de liste
+\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
+}
+\catcode`\@12
+\def\liste{a,bra,{cA},da,brA}\insitem\liste3{XX}\meaning\liste\par
+\def\liste{a,bra,{cA},da,brA}\insitem\liste0{XX}\meaning\liste\par
+\def\liste{a,bra,{cA},da,brA}\insitem\liste9{XX}\meaning\liste
+****************** Fin code ******************
+
+
+****************** Code 317 ******************
+\catcode`\@11
+\def\quark@list{\quark@list}% quark de fin de liste
+\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,%
+ \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
+}
+\catcode`\@12
+\for\xx=0 to 8 \do{%
+\def\liste{a,bcd,{ef},g,hij,kl}
+position \xx{} : \expandafter\delitem\expandafter\liste\xx\meaning\liste.\par
+}
+****************** Fin code ******************
+
+
+****************** Code 318 ******************
+\catcode`\@11
+\def\moveitem#1#2#3{% #1 = liste, #2=position départ, #3=position arrivée
+ \ifnum#2>0 % ne faire quemque chose que si #2>0
+ \finditemtocs#1{#2}\temp@item% sauvegarder l'élément
+ \delitem#1{#2}% supprimer l'élément
+ \expsecond{\insitem#1{#3}}\temp@item% insérer l'élément
+ \fi
+}
+\catcode`\@12
+% déplace "b" en 5e position
+a) \def\liste{a,b,c,d,e,f} \moveitem\liste25 "\liste"\par
+% déplace "d" en 1e position
+b) \def\liste{a,b,c,d,e,f} \moveitem\liste41 "\liste"\par
+% déplace "c" en 9e position
+c) \def\liste{a,b,c,d,e,f} \moveitem\liste39 \liste"\par
+% position départ=0 -> sans effet
+d) \def\liste{a,b,c,d,e,f} \moveitem\liste02 "\liste"
+****************** Fin code ******************
+
+
+****************** Code 319 ******************
+\catcode`\@11
+\def\runlist#1\with#2{% #1=liste #2=macro
+ \def\runlist@i##1,{%
+ \ifx\quark@list##1\relax\else% si la fin n'est pas atteinte
+ \addtomacro\collect@run{#2{##1}}% ajouter "\<macro>{<élément>}""
+ \expandafter\runlist@i% et recommencer en lisant l'élément suivant
+ \fi
+ }%
+ \begingroup% fait la collecte dans un groupe
+ \let\collect@run=\empty% initialiser la macro
+ \expandafter\runlist@i#1,\quark@list,% appeler \runlist@i
+ \expandafter\endgroup% ferme le groupe et détruit \collect@run
+ \collect@run% après l'avoir développé !
+}
+\catcode`\@12
+\newcount\foocnt
+\foocnt=0 % compteur utilisé pour numéroter les éléments dans la macro \foo
+\def\foo#1{% la macro qui va exécuter chaque élément de la liste. #1 = l'élément
+ \advance\foocnt1 % incrémente le compteur
+ L'argument \number\foocnt\ est : {\bf #1}\par%
+}
+\def\liste{a,bra,ca,da,BRA}%
+\runlist\liste\with\foo%
+****************** Fin code ******************
+
+
+****************** Code 320 ******************
+\catcode`\@11
+\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}}% renvoyer vrai s'il n'y a rien avant " "
+\catcode`\@12
+a) \ifspacefirst{a bc d}{vrai}{faux}\qquad
+b) \ifspacefirst{ a bc d}{vrai}{faux}\qquad
+c) \ifspacefirst{ }{vrai}{faux}\qquad
+d) \ifspacefirst{}{vrai}{faux}\qquad
+e) \ifspacefirst{{ } }{vrai}{faux}\qquad
+f) \ifspacefirst{ {x} }{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 321 ******************
+\catcode`\@11
+\expandafter\def\expandafter\gobspace\space{}
+
+\def\removefirstspaces#1{%
+ \ifspacefirst{#1}% si #1 commence par un espace
+ {\exparg\removefirstspaces{\gobspace#1}}% recommencer sans le 1er espace
+ {#1}% sinon, renvoyer l'argument
+}
+\catcode`\@12
+a) "\removefirstspaces{12 {\bf3}4 567}"\qquad
+b) "\removefirstspaces{ 12 {\bf3}4 567}"\qquad
+c) \edef\foo{\space\space\space 12 34 567}
+ "\exparg\removefirstspaces\foo"
+****************** Fin code ******************
+
+
+****************** Code 322 ******************
+\catcode`\@11
+\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
+ {\exparg\removefirstspaces@i{\gobspace#1}}% recommencer sans le 1er espace
+ {\z@#1}% sinon, renvoyer l'argument où \z@ stoppe l'action de \romannumeral
+}
+\catcode`\@12
+\long\def\>#1<{"\detokenize{#1}"}
+
+a) \expandafter\expandafter\expandafter\>\removefirstspaces{12 {\bf3}4 567}<\qquad
+b) \expandafter\expandafter\expandafter\>\removefirstspaces{ 12 {\bf3}4 567}<\qquad
+c) "\removefirstspaces{ 12 {\bf3}4 }"
+****************** Fin code ******************
+
+
+****************** Code 323 ******************
+\catcode`\@11
+\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\relax#1^^00 ^^00\@nil% mettre un \relax au début
+ % et passer la main à \removelastspaces@i
+}
+\def\removelastspaces@i#1 ^^00{% prendre ce qui est avant " W"
+ \removelastspaces@ii#1^^00% ajouter "W"
+}
+\def\removelastspaces@ii#1^^00#2\@nil{% #1=ce qui est avant "W" #2=reliquat
+ \ifspacefirst{#2}% si le reliquat commence par un espace
+ {\removelastspaces@i#1^^00 ^^00\@nil}% recommencer sans passer par \removelastspaces
+ {\expandafter\z@\gobone#1}% sinon supprimer le \relax ajouté au début
+ % et stopper l'action de \romannumeral avec \z@
+}
+\catcode0=\catcodezero@saved\relax% restaure le catcode de ^^00
+\catcode`\@12
+\long\def\>#1<{"\detokenize{#1}"}
+
+a) \expandafter\expandafter\expandafter\>\removelastspaces{ 12 {\bf3}4 }<\qquad
+b) \expandafter\expandafter\expandafter\>\removelastspaces{12 {\bf3}4}<\qquad
+c) "\removelastspaces{ 12 {\bf3}4 }"
+****************** Fin code ******************
+
+
+****************** Code 324 ******************
+\catcode`\@11
+\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}%
+ }%
+}
+\catcode`\@12
+\long\def\>#1<{"\detokenize{#1}"}
+
+a) \expandafter\expandafter\expandafter\>\removetrailspaces{ 12 {\bf3}4 }<\qquad
+b) \expandafter\expandafter\expandafter\>\removetrailspaces{12 {\bf3}4}<\par
+c) \expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter
+ \foo\expandafter\expandafter\expandafter{\removetrailspaces{ 12 {\bf3}4 }}%
+ signification : \meaning\foo.\par
+c) exécution : "\foo"\par
+d) "\removetrailspaces{ 12 {\bf3}4 }"
+****************** Fin code ******************
+
+
+****************** Code 325 ******************
+\catcode`\@11
+\def\sanitizelist#1{% #1 = liste
+ \let\item@list\empty% initialise le réceptacle de la liste assainie
+ \def\sanitizelist@endprocess{% définit le hook de fin
+ \expandafter\remove@lastcomma\item@list\@nil% supprimer dernière virgule
+ \let#1=\item@list% et assigner le résultat à #1
+ }%
+ \expandafter\sanitizelist@i\expandafter\relax#1,\quark@list,% aller à la macro récursive
+}
+
+\def\sanitizelist@i#1,{% #1="\relax" + élément courant
+ \expandafter\ifx\expandafter\quark@list\gobone#1%
+ \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+ {\sanitizelist@endprocess% si fin de liste, hook de fin
+ }% si la fin de la liste n'est pas atteinte :
+ {\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter
+ \addtomacro% 1-développer \gobone pour retirer \relax
+ \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter
+ \item@list% puis 2-développer \removetrailspaces
+ \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter
+ {\expandafter\removetrailspaces\expandafter{\gobone#1},}% "#1"
+ \sanitizelist@i\relax% et continuer avec l'élément suivant
+ }%
+}
+
+\catcode`\@12
+\frboxsep=0pt % encadrer au plus proche
+\def\foo#1{\frbox{\tt\strut#1} }% boite avec un strut et en fonte "tt" puis espace
+\def\liste{ Programmer, en \TeX{} ,est ,{\bf facile}, et utile }
+a) \runlist\liste\with\foo% encadrer les items
+
+b) \sanitizelist\liste% supprimer les espaces inutiles des items
+ \runlist\liste\with\foo
+****************** Fin code ******************
+
+
+****************** Code 326 ******************
+\catcode`\@11
+\def\boxsentence#1{%
+ \leavevmode% se mettre en mode horizontal
+ \boxsentence@i#1\quark% transmet "#1+\quark" à boxsentence@i
+}
+\def\boxsentence@i#1{% #1= argument lu
+ \def\current@arg{#1}% stocke l'argument dans une macro temporaire
+ \unless\ifx\quark\current@arg% si la fin n'est pas atteinte
+ \frbox{#1}% encadrer cet argument
+ \expandafter\boxsentence@i% lire l'argument suivant
+ \fi
+}
+\catcode`@12
+\frboxsep=1pt \frboxrule=0.2pt
+\boxsentence{Programmer en \TeX\ est facile}
+****************** Fin code ******************
+
+
+****************** Code 327 ******************
+\catcode`\@11
+\edef\star@macro{\string *}% stocke une étoile de catcode 12
+\def\expo#1{%
+ \def\temp@arg{#1}% stocke l'argument lu
+ \ifx\star@macro\temp@arg\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+ {% si l'argument est une étoile de catcode 12
+ $^\dag$% affiche une dague
+ }% sinon
+ {$^\ddag$% affiche une double dague
+ {#1}% puis ré-écrit l'argument {#1}
+ }%
+}
+A\expo B\expo*C
+****************** Fin code ******************
+
+
+****************** Code 328 ******************
+\def\boxsentence#1{%
+ \readtok#1\quark% met le token d'arrêt \quark à la fin de #1
+}
+\def\readtok{\afterassignment\cmptok\let\nxttok= }
+\def\cmptok{%
+ \unless\ifx\nxttok\quark% si la fin n'est pas atteinte
+ \frbox{\nxttok}% encadrer le token lu
+ \expandafter\readtok% puis aller lire le suivant
+ \fi
+}
+\frboxsep=1pt \frboxrule=0.2pt
+\leavevmode\boxsentence{Programmer en \TeX\ est facile}
+****************** Fin code ******************
+
+
+****************** Code 329 ******************
+\def\permutstart{\afterassignment\cmptok\let\nxttok= }
+\def\permutend{\permutend}%
+\def\cmptok{%
+ \unless\ifx\permutend\nxttok% tant que la fin n'est pas atteinte :
+ \ifxcase\nxttok
+ ae% si le token lu est "a", afficher un "e"
+ ei io ou uy ya% etc pour les autres lettres
+ \elseif
+ \nxttok% si ce n'est aucune voyelle, afficher le token
+ \endif
+ \expandafter\permutstart% aller lire le token suivant
+ \fi
+}
+\permutstart Un "a" puis "e puis "i" ensuite, un "o", un "u" et "y".\permutend
+****************** Fin code ******************
+
+
+****************** Code 330 ******************
+\def\boxsentence#1{\readtok#1\boxsentence}
+\def\readtok{\afterassignment\cmptok\let\nxttok= }
+\def\cmptok{%
+ %\show\nxttok% à décommenter pour débogage
+ \unless\ifx\nxttok\boxsentence
+ \frbox{\nxttok}%
+ \expandafter\readtok
+ \fi
+}
+\frboxsep=1pt \frboxrule=0.2pt
+\leavevmode\boxsentence{Pro{gra}mmer en \TeX\ est facile}
+****************** Fin code ******************
+
+
+****************** Code 331 ******************
+\catcode`\@11
+\def\Litterate{%
+ \begingroup% ouvrir un groupe
+ \tt% et adopter une fonte à chasse fixe
+ \afterassignment\Litterate@i% après l'assignation, aller à \Litterate@i
+ \expandafter\let\expandafter\lim@tok\expandafter=\string% \lim@tok = token délimiteur
+}
+\def\Litterate@i{%
+ \afterassignment\Litterate@ii%après avoir lu le prochain token, aller à \Litterate@ii
+ \expandafter\let\expandafter\nxttok\expandafter=\string% lit le token suivant
+}
+\def\Litterate@ii{%
+ \ifx\nxttok\lim@tok% si le token suivant="token délimiteur"
+ \endgroup% fermer le groupe et finir
+ \else
+ \nxttok% sinon, afficher ce token
+ \expandafter\Litterate@i% et lire le token suivant
+ \fi
+}
+\catcode`\@12
+\Litterate|Programmer en \TeX {} est << facile >> !|
+****************** Fin code ******************
+
+
+****************** Code 332 ******************
+\catcode`\@11
+\def\Litterate{%
+ \begingroup% ouvrir un groupe
+ \tt% et adopter une fonte à chasse fixe
+ \afterassignment\Litterate@i% après l'assignation, aller à \Litterate@i
+ \expandafter\let\expandafter\lim@tok\expandafter=\string% \lim@tok = token délimiteur
+}
+\def\Litterate@i{%
+ \afterassignment\Litterate@ii% après avoir lu un token, aller à \Litterate@ii
+ \expandafter\expandafter\expandafter% 1-développer \string
+ \let
+ \expandafter\expandafter\expandafter% puis 1-développer \space en " "
+ \nxttok
+ \expandafter\expandafter\expandafter
+ =\expandafter\space\string% et lire le token obtenu
+}
+\def\Litterate@ii{%
+ \ifx\nxttok\lim@tok% si le token suivant="token délimiteur"
+ \endgroup% fermer le groupe et finir
+ \else
+ \nxttok% sinon, afficher ce token
+ \expandafter\Litterate@i% et lire le token suivant
+ \fi
+}
+\catcode`\@12
+\Litterate|Programmer en \TeX {} est << facile >> : $~$^_#|
+****************** Fin code ******************
+
+
+****************** Code 333 ******************
+\catcode`@11
+\newskip\ltr@spc
+\def\letterspace#1#2{%
+ \ltr@spc=#1\relax % assigne le ressort
+ \letterspace@i#2\letterspace@i% appelle la macro \letterspace@i
+}
+\def\letterspace@i{%
+ \afterassignment\letterspace@ii
+ \let\nxttok=
+}
+\def\letterspace@ii{%
+ \ifx\nxttok\letterspace@i% si la fin est atteinte
+ \unskip% supprimer le dernier ressort qui est de trop
+ \else
+ \nxttok% afficher le token
+ \hskip\ltr@spc\relax% insère le ressort
+ \expandafter\letterspace@i% va lire le token suivant
+ \fi
+}
+\catcode`@12
+Voici "\letterspace{0.3em}{des lettres espacées}"
+et voici "\letterspace{-0.075em}{de la compression}".
+****************** Fin code ******************
+
+
+****************** Code 334 ******************
+\catcode`@11
+\newcount\test@cnt
+\def\ifinteger#1{%
+ \ifstart{#1}{-}% si "-" est au début de #1
+ {\exparg\ifinteger{\gobone#1}% l'enlever et recommencer
+ }
+ {\ifempty{#1}% sinon, si #1 est vide
+ \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
+}
+
+\catcode`@12
+1) \ifinteger{5644}{oui}{non}\qquad
+2) \ifinteger{-987}{oui}{non}\qquad
+3) \ifinteger{6a87}{oui}{non}\qquad
+4) \ifinteger{abcd}{oui}{non}\qquad
+5) \ifinteger{-a}{oui}{non}\qquad
+6) \ifinteger{-}{oui}{non}\qquad
+7) \ifinteger{3.14}{oui}{non}
+****************** Fin code ******************
+
+
+****************** Code 335 ******************
+\catcode`\@11
+\def\teststar{%
+ \futurelet\nxttok\teststar@i% % pioche le token suivant puis aller à \teststar@i
+}
+\def\teststar@i{%
+ \ifx *\nxttok\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+ {% si le token suivant est une étoile
+ \afterassignment\teststar@bf% après avoir lu "*", aller à \teststar@bf
+ \let\nxttok= % lire l'étoile
+ }% si le token n'est pas une étoile
+ {\teststar@it% aller à \teststar@it
+ }%
+}
+\def\teststar@bf#1{{\bf#1}}% lit l'argument et le compose en gras dans un groupe
+\def\teststar@it#1{{\it#1\/}}% lit l'argument et le compose en italique
+\catcode`\@12
+Un essai \teststar{réussi} et un essai \teststar*{étoilé} réussi aussi.
+****************** Fin code ******************
+
+
+****************** Code 336 ******************
+\catcode`@11
+\def\deftok#1#2{\let#1= #2\empty}% définit le token #1 (\empty au cas où #2 est vide)
+\deftok\sptoken{ }
+\def\ifnexttok#1#2#3{% lit les 3 arguments : #1=token #2=code vrai #3=code faux
+ \deftok\test@tok{#1}% stocke le token cherché
+ \def\true@code{#2}\def\false@code{#3}% et les codes à exécuter
+ \ifnexttok@i% aller à la macro récursive
+}
+\def\ifnexttok@i{%
+ \futurelet\nxttok\ifnexttok@ii% piocher le token d'après et aller à \ifnexttok@ii
+}
+\def\ifnexttok@ii{%
+ \ifx\nxttok\sptoken% si le prochain token est un espace
+ \def\donext{%
+ \afterassignment\ifnexttok@i% recommencer après
+ \let\nxttok= % après avoir absorbé cet espace
+ }%
+ \else
+ \ifx\nxttok\test@tok% si le prochain token est celui cherché
+ \let\donext\true@code% exécuter le code vrai
+ \else
+ \let\donext\false@code% sinon code faux
+ \fi
+ \fi
+ \donext% faire l'action décidée ci-dessus
+}
+\catcode`@12
+\ifnexttok W{je vais lire un W : }{je ne vais pas lire un W : }W.\par
+\ifnexttok W{je vais lire un W : }{je ne vais pas lire un W : }a.\par
+\ifnexttok *{je vais lire une étoile : }{je ne vais pas lire une étoile : } *.\par
+\ifnexttok *{je vais lire une étoile : }{je ne vais pas lire une étoile : }a.
+****************** Fin code ******************
+
+
+****************** Code 337 ******************
+\catcode`@11
+\newif\iftestspace \testspacefalse
+\def\deftok#1#2{\let#1= #2}\deftok\sptoken{ }
+\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 "normale" qui ne teste pas 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{% macro qui ignore les espaces
+ \ifx\nxttok\sptoken% si le prochain token est un espace
+ \def\donext{%
+ \afterassignment\ifnexttok@i% lire le token d'après
+ \let\nxttok= % après avoir absorbé l'espace
+ }%
+ \else
+ \let\donext\ifnexttok@ii% sinon, faire le test "normal"
+ \fi
+ \donext% faire l'action décidée ci-dessus
+}
+\catcode`@12
+\testspacefalse
+\ifnexttok W{je vais lire un W : }{je ne vais pas lire un W : }W.\par
+\ifnexttok W{je vais lire un W : }{je ne vais pas lire un W : } W.\medbreak
+\testspacetrue
+\ifnexttok W{je vais lire un W : }{je ne vais pas lire un W : }W.\par
+\ifnexttok W{je vais lire un W : }{je ne vais pas lire un W : } W.
+****************** Fin code ******************
+
+
+****************** Code 338 ******************
+\def\ifstarred#1{\ifnexttok*{\firstoftwo{#1}}}
+\catcode`\@11
+\def\teststar{\ifstarred{\teststar@bf}{\teststar@it}}
+\def\teststar@bf#1{{\bf#1}}
+\def\teststar@it#1{{\it#1\/}}
+\catcode`\@12
+
+Un essai \teststar{réussi} et un essai \teststar*{étoilé} réussi aussi.
+****************** Fin code ******************
+
+
+****************** Code 339 ******************
+\catcode`\@11
+\def\parsestop{\parsestop}% définit la macro-quark se trouvant en fin de code
+\newtoks\code@toks% registre contenant le code lu
+\def\parseadd{\addtotoks\code@toks}
+\def\parse{%
+ \code@toks={}% initialise \code@toks à vide
+ \parse@i% et passe la main à \parse@i
+}
+\def\parse@i{\futurelet\nxttok\parse@ii}% lit le prochain token et va à \parse@ii
+\def\parse@ii{%
+ \ifxcase\nxttok
+ \parsestop\parsestop@i% si la fin va être atteinte, aller à \parsestop@i
+ \sptoken\read@space% si un espace va être lu, aller à \read@space
+ \bgroup\read@bracearg% si une accolade ouvrante aller à \read@bracearg
+ \elseif
+ \testtoken% dans les autres cas, aller à \testtoken
+ \endif
+}
+
+\def\parsestop@i\parsestop{% la fin est atteinte : manger \parsestop
+ \the\code@toks% afficher le registre de tokens
+}
+\expandafter\def\expandafter\read@space\space{% manger un espace dans le code
+ \testtoken{ }% et aller à \testtoken
+}
+\def\read@bracearg#1{% l'argument entre accolades est lu
+ \parseadd{{#1}}% puis ajouté (entre accolades) tel quel à \code@toks
+ \parse@i% ensuite, lire le prochain token
+}
+\catcode`@12
+
+{\bf Exemple 1 :}
+\catcode`@11
+\def\testtoken#1{% macro qui teste le token
+ \ifxcase{#1}
+ a{\parseadd{e}}% remplacer a par e
+ e{\parseadd{i}}% e par i
+ i{\parseadd{o}}% i par o
+ o{\parseadd{u}}% o par u
+ u{\parseadd{y}}% u par y
+ y{\parseadd{a}}% y par a
+ \elseif
+ \parseadd{#1}% sinon, ajouter le token tel quel
+ \endif
+ \parse@i% aller lire le token suivant
+}%
+\catcode`@12
+\parse
+Ce texte devenu \`a peine reconnaissable montre que le r\'esultat contient des sonorit\'es
+{\bf catalanes, corses ou grecques} assez inattendues.
+\parsestop\medbreak
+
+{\bf Exemple 2 :}
+\leavevmode \frboxsep=1pt
+\catcode`@11
+\def\testtoken#1{%
+ \ifxcase{#1}% si #1 est un espace
+ { }{\parseadd{\hskip 0.75em }}% ajouter un espace
+ \ {\parseadd{\hskip 0.75em }}
+ \elseif
+ \parseadd{\frbox{#1}}% sinon, l'encadrer
+ \endif
+ \parse@i}%
+\catcode`@12
+\parse Programmer en \TeX\ est facile\parsestop\medbreak
+
+{\bf Exemple 3 :}
+\catcode`@11
+\def\testtoken#1{%
+ \ifx a#1\parseadd{X}\else\parseadd{#1}\fi% remplace les "a" par des "X"
+ \parse@i
+}
+\catcode`@12
+\parse a\bgroup\bf braca\egroup dabra\parsestop
+****************** Fin code ******************
+
+
+****************** Code 340 ******************
+\catcode`\@11
+\def\ifbracefirst#1{%
+ \ifnum\catcode\expandafter\expandafter\expandafter
+ `\expandafter\firstto@nil\detokenize{#1W}\@nil=1 % tester si son catcode est 1
+ \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+}
+\catcode`\@12
+
+a) \ifbracefirst{123 456}{vrai}{faux}\qquad
+b) \ifbracefirst{\bgroup12\egroup3 456}{vrai}{faux}\qquad
+c) \ifbracefirst{{12}3 456}{vrai}{faux}\qquad
+d) \ifbracefirst{1{2}3 456}{vrai}{faux}\qquad
+\begingroup
+\catcode`[=1 \catcode`]=2 % les crochets deviennent des accolades
+e) \ifbracefirst[[]123 456][vrai][faux]
+\endgroup
+****************** Fin code ******************
+
+
+****************** Code 341 ******************
+\catcode`\@11
+\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 % tester si son catcode est 1
+ \expandafter\firstoftwo
+ \else
+ \expandafter\secondoftwo
+ \fi
+ }%
+}
+
+\catcode`\@12
+a) \ifbracefirst{}{vrai}{faux}\qquad b) \ifbracefirst{ }{vrai}{faux}\qquad
+c) \ifbracefirst{ {}}{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 342 ******************
+\catcode`\@11
+\def\parsestop@i\parsestop{% la fin va être atteinte
+ \detokenize\expandafter{\the\code@toks}% afficher le contenu du registre
+}
+\def\read@bracearg{%
+ \read@bracearg@i\relax% ajoute un \relax avant de passer la main à \read@bracearg@i
+}
+\def\read@bracearg@i#1\parsestop{% #1 = tout jusqu'à \parsestop
+ \exparg\ifbracefirst{\gobone#1}% retire le \relax et teste si #1 commence par "{"
+ {\expandafter\read@bracearg@ii\gobone#1\parsestop}% si oui, aller à \readbrace@ii
+ {\expandafter\testtoken\gobone#1\parsestop}% sinon, aller à \testtoken
+}
+\def\read@bracearg@ii#1{% lit l'argument entre accolades
+ \parseadd{{#1}}% ajoute cet argument entre accolades
+ \parse@i% aller lire le token suivant
+}
+
+\def\testtoken#1{%
+ \parseadd{#1}% ajouter le token tel quel
+ \parse@i% aller lire le token suivant
+}
+\catcode`\@12
+\parse a\hbox\bgroup\bf braca\egroup {da}{}b{ra}\parsestop
+****************** Fin code ******************
+
+
+****************** Code 343 ******************
+\catcode`\@11
+\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% teste si la macro est étoilée
+ {\parse@grouptrue\parse@i}% mettre le booléen à vrai
+ {\parse@groupfalse\parse@i}% sinon à faux
+}
+\def\parse@i{\futurelet\nxttok\parse@ii}% lit le prochain token
+ % et va à \parse@ii
+\def\parse@ii{%
+ \ifxcase\nxttok
+ \parsestop\parsestop@i% si la fin va être atteinte, aller à \parsestop@i
+ \sptoken\read@space% si un espace va être lu, aller à \read@space
+ \bgroup\read@bracearg% si une accolade ouvrante aller à \read@bracearg
+ \elseif
+ \testtoken% dans les autres cas, aller à \testtoken
+ \endif
+}
+\def\parsestop@i\parsestop{% la fin est atteinte
+ \the\code@toks% afficher le registre de tokens
+}
+\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% si macro étoilée
+ {\begingroup% ouvre un groupe pour parser l'intérieur de l'accolade
+ \def\parsestop@i\parsestop{% redéfinir localement \parsestop@i pour
+ \expandafter\endgroup% ne fermer le groupe qu'après avoir
+ \expandafter\parseadd% 1-développé à l'extérieur du groupe
+ \expandafter{\expandafter{\the\code@toks}}%
+ \parse@i% puis va lire le token suivant
+ }%
+ \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
+ \ifxcase{#1}
+ a{\parseadd{e}}
+ e{\parseadd{i}}
+ i{\parseadd{o}}
+ o{\parseadd{u}}
+ u{\parseadd{y}}
+ y{\parseadd{a}}
+ \elseif
+ \parseadd{#1}%
+ \endif
+ \parse@i% aller lire le token suivant
+}
+\catcode`@12
+\frboxsep=1pt
+a) \parse
+Ce texte devenu \`a peine reconnaissable montre que le r\'esultat contient des sonorit\'es
+{\bf catalanes, \frbox{corses} ou grecques} assez inattendues.
+\parsestop\medbreak
+
+b) \parse*
+Ce texte devenu \`a peine reconnaissable montre que le r\'esultat contient des sonorit\'es
+{\bf catalanes, \frbox{corses} ou grecques} assez inattendues.
+\parsestop
+****************** Fin code ******************
+
+
+****************** Code 344 ******************
+\catcode`\@11
+\def\parse{%
+ \code@toks{}% initialise le collecteur de tokens
+ \ifstarred
+ {\parse@grouptrue
+ \ifnexttok{ }% si un espace suit l'étoile
+ {\afterassignment\parse@i% aller à \parse@i
+ \let\nxttok= }% après l'avoir mangé
+ {\parse@i}% sinon, aller à \parse@i
+ }
+ {\parse@groupfalse
+ \parse@i
+ }%
+}
+\def\testtoken#1{% macro qui teste le token
+ \ifxcase{#1}
+ a{\parseadd{e}}e{\parseadd{i}}i{\parseadd{o}}o{\parseadd{u}}
+ u{\parseadd{y}}y{\parseadd{a}}
+ \elseif
+ \parseadd{#1}%
+ \endif
+ \parse@i% aller lire le token suivant
+}
+\catcode`@12
+\frboxsep=1pt
+a) \parse
+Ce texte devenu \`a peine reconnaissable montre que le r\'esultat contient des sonorit\'es
+{\bf catalanes, \frbox{corses} ou grecques} assez inattendues.
+\parsestop\medbreak
+b) \parse*
+Ce texte devenu \`a peine reconnaissable montre que le r\'esultat contient des sonorit\'es
+{\bf catalanes, \frbox{corses} ou grecques} assez inattendues.
+\parsestop
+****************** Fin code ******************
+
+
+****************** Code 345 ******************
+\catcode`\@11
+\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}}
+\tt
+a) \def\foo{1 {2 3} 4}\grab@first\foo\bar
+ "\meaning\bar"\qquad"\meaning\foo"
+
+b) \def\foo{ 1 {2 3} 4}\grab@first\foo\bar
+ "\meaning\bar"\qquad"\meaning\foo""
+
+c) \def\foo{{1 2} 3 4}\grab@first\foo\bar
+ "\meaning\bar"\qquad"\meaning\foo"
+****************** Fin code ******************
+
+
+****************** Code 346 ******************
+\catcode`\@11
+\def\ifstartwith#1#2{% #1=<texte> #2=<motif>
+ \ifempty{#2}
+ \firstoftwo% si <motif> est vide, renvoyer vrai
+ {\ifempty{#1}% si <code> est vide et <motif> non vide
+ \secondoftwo% renvoyer faux
+ {\def\startwith@code{#1}\def\startwith@pattern{#2}%
+ \ifstartwith@i% dans les autres cas, aller à \ifstartwith@i
+ }%
+ }%
+}
+\def\ifstartwith@i{%
+ \grab@first\startwith@code\first@code% extrait le premier "argument" de <texte>
+ \grab@first\startwith@pattern\first@pattern% et celui de <motif>
+ \ifx\first@code\first@pattern\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+ {% si les deux arguments élargis sont égaux
+ \exparg\ifempty\startwith@pattern
+ \firstoftwo% et que <motif> ne contient plus rien => vrai
+ {\exparg\ifempty\startwith@code
+ \secondoftwo% si <texte> ne contient plus rien => faux
+ \ifstartwith@i% sinon poursuivre les tests
+ }%
+ }
+ \secondoftwo% si les deux argument élargis sont différents, renvoyer faux
+}
+\catcode`\@12
+
+1) \ifstartwith{a b c}{a b}{oui}{non}\quad 2) \ifstartwith{a b}{a b c}{oui}{non}\quad
+3) \ifstartwith{ 123 }{ }{oui}{non}\quad 4) \ifstartwith{ 123 }{1}{oui}{non}\quad
+5) \ifstartwith{1{2} 3}{12}{oui}{non}\quad 6) \ifstartwith{1{2} 3}{1{2} }{oui}{non}\quad
+7) \ifstartwith{{} {}}{ }{oui}{non}\quad 8) \ifstartwith{{} {}}{{} }{oui}{non}\quad
+9) \ifstartwith{ {12} a}{ }{oui}{non}\quad10) \ifstartwith{ {12} a}{ {1}}{oui}{non}
+****************** Fin code ******************
+
+
+****************** Code 347 ******************
+\catcode`\@11
+\def\ifcontain#1#2{% #1 contient-il #2?
+ \def\main@arg{#1}\def\pattern@arg{#2}% stocke le <code> et le <motif>
+ \ifempty{#2}
+ \firstoftwo% si #2 est vide => vrai
+ {\ifempty{#1}
+ \secondoftwo% si #1 est vide et pas #2 => faux
+ \ifcontain@i% sinon, aller faire les tests
+ }%
+}
+\def\ifcontain@i{%
+ \exptwoargs\ifstartwith\main@arg\pattern@arg
+ \firstoftwo% si motif est au début de code => vrai
+ {\exparg\ifempty\main@arg
+ \secondoftwo% sinon, si code est vide => faux
+ {\grab@first\main@arg\aux@arg% autrement, manger le 1er "argument" de code
+ \ifcontain@i% et recommencer
+ }%
+ }%
+}
+\catcode`\@12
+1) \ifcontain{abc def}{c }{oui}{non}\quad 2) \ifcontain{abc def}{cd}{oui}{non}\quad
+3) \ifcontain{12 34 5}{1 }{oui}{non}\quad 4) \ifcontain{12 34 5}{ }{oui}{non}\quad
+5) \ifcontain{a{b c}d}{b c}{oui}{non}\quad 6) \ifcontain{a{b c}d}{{b c}}{oui}{non}\quad
+7) \ifcontain{{} {}}{ }{oui}{non}\quad 8) \ifcontain{{} {}}{{}}{oui}{non}
+****************** Fin code ******************
+
+
+****************** Code 348 ******************
+\catcode`@11
+\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
+ {\exparg\ifempty\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 {<argument>} de main@arg
+ \begingroup% ouvrir un groupe
+ \in@grouptrue% mettre le booléen à vrai
+ \expandafter\def\expandafter\main@arg\aux@arg% assigner "argument" à \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\startwith@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
+}
+\catcode`@12
+1) \ifcontain{ab {c d}ef}{c}{oui}{non}\quad 2) \ifcontain*{ab {c d}ef}{c}{oui}{non}
+****************** Fin code ******************
+
+
+****************** Code 349 ******************
+\catcode`@11
+\newtoks\subst@toks% registre de tokens pour stocker le <texte> modifié
+\def\substitute{%
+ \def\substitute@end{\the\subst@toks}% macro exécutée à la fin
+ \ifstarred
+ {\let\recurse@macro\substitute@star \substitute@i}%
+ {\let\recurse@macro\substitute@nostar\substitute@i}%
+}
+\def\substitute@i#1#2#3#4{% #1=macro à appeler selon étoile ou pas.
+ % #2=<texte> #3=<motif> #4=<motif de substi>
+ \def\code@arg{#2}\def\pattern@arg{#3}\def\subst@arg{#4}%
+ \subst@toks={}% initialiser le collecteur à vide
+ #1% aller à \substitute@star ou \substitute@nostar
+}
+\def\substitute@nostar{%
+ \exptwoargs\ifstartwith\code@arg\pattern@arg% si le <texte> commence par <motif>
+ {\eaddtotoks\subst@toks\subst@arg% ajouter <motif subst>
+ \grab@first\code@arg\aux@code% manger le 1er "argument" de <texte>
+ \substitute@nostar% et recommencer
+ }
+ {\expandafter\ifempty\expandafter{\code@arg}%
+ {\substitute@end% sinon, si <texte> est vide => afficher le registre de tokens
+ }
+ {\grab@first\code@arg\aux@arg% autrement, manger le 1er "argument" de <texte>
+ \eaddtotoks\subst@toks\aux@arg% et l'ajouter au registre de tokens
+ \substitute@nostar% et recommencer
+ }%
+ }%
+}
+\def\substitute@star{%
+ \expandafter\ifbracefirst\expandafter{\code@arg}% si <texte> commence par "{"
+ {\grab@first\code@arg\aux@arg% enlever {<argument>} de \code@arg
+ \begingroup% ouvrir un groupe
+ \def\substitute@end{% modifier localement la macro exécutée à la fin
+ \expandafter\endgroup\expandafter% avant de fermer le groupe
+ \addtotoks\expandafter\subst@toks\expandafter% ajouter au registre hors du groupe
+ {\expandafter{\the\subst@toks}}% ce qui est collecté localement, mis entre {}
+ \substitute@star% puis recommencer
+ }%
+ \subst@toks{}% initialiser à vide
+ \expandafter\def\expandafter\code@arg\aux@arg% % assigner "argument" au <texte>
+ \substitute@star% et recommencer avec ce nouveau \code@arg
+ }% si code ne commence pas par "{"
+ {\exptwoargs\ifstartwith\code@arg\pattern@arg% si <motif> est au début de <texte>
+ {\eaddtotoks\subst@toks\subst@arg% ajouter <motif subst>
+ \grab@first\code@arg\aux@code% manger le 1er "argument" de <texte>
+ \substitute@star% et recommencer
+ }
+ {\expandafter\ifempty\expandafter{\code@arg}% si <texte> est vide
+ {\substitute@end% aller à la macro de fin
+ }% si <texte> n'est pas vide
+ {\grab@first\code@arg\aux@code% manger le 1er "argument" de <texte>
+ \eaddtotoks\subst@toks\aux@code% et l'ajouter au registre
+ \substitute@star% et recommencer
+ }%
+ }%
+ }%
+}
+\catcode`@12
+1) \substitute{ab{\bf racada}bra}{a}{W}\qquad
+2) \substitute*{ab{\bf racada}bra}{a}{W}\qquad
+3) \substitute{12\frbox{\bf 34}56}{\bf}{\it}\qquad
+4) \substitute*{12\frbox{\bf 34}56}{\bf}{\it}
+****************** Fin code ******************
+
+
+****************** Code 350 ******************
+\catcode`@11
+\newtoks\subst@toks% registre de tokens pour stocker le <texte> modifié
+\def\substitute{%
+ \def\substitute@end{\the\subst@toks}% macro exécutée à la fin
+ \ifstarred
+ {\let\recurse@macro\substitute@star \substitute@i}%
+ {\let\recurse@macro\substitute@nostar\substitute@i}%
+}
+\def\substitute@i#1#2#3{% #1=<texte> #2=<motif> #3=<motif de substi>
+ \def\code@arg{#1}\def\pattern@arg{#2}\def\subst@arg{#3}%
+ \subst@toks={}% initialiser à vide
+ \recurse@macro% aller à \substitute@star ou \substitute@nostar
+}
+\def\substitute@nostar{%
+ \exptwoargs\ifstartwith\code@arg\pattern@arg% si le <texte> commence par <motif>
+ {\eaddtotoks\subst@toks\subst@arg% ajouter <motif subst>
+ \grab@first\code@arg\aux@code% manger le 1er "argument" de <texte>
+ \recurse@macro% et recommencer
+ }
+ {\expandafter\ifempty\expandafter{\code@arg}%
+ \substitute@end% sinon, si <texte> est vide => afficher le registre de tokens
+ {\grab@first\code@arg\aux@arg% autrement, manger le 1er "argument" de <texte>
+ \eaddtotoks\subst@toks\aux@arg% et l'ajouter au registre de tokens
+ \recurse@macro% et recommencer
+ }%
+ }%
+}
+\def\substitute@star{%
+ \expandafter\ifbracefirst\expandafter{\code@arg}% si <texte> commence par "{"
+ {\grab@first\code@arg\aux@arg% enlever {<argument>} de \code@arg
+ \begingroup% ouvrir un groupe
+ \def\substitute@end{% modifier localement la macro exécutée à la fin
+ \expandafter\endgroup\expandafter% avant de fermer le groupe
+ \addtotoks\expandafter\subst@toks\expandafter% ajouter au registre hors du groupe
+ {\expandafter{\the\subst@toks}}% ce qui est collecté localement, mis entre {}
+ \recurse@macro% puis recommencer
+ }%
+ \subst@toks{}% initialiser à vide
+ \expandafter\def\expandafter\code@arg\aux@arg% % assigner "argument" au <texte>
+ \recurse@macro% et recommencer avec ce nouveau \code@arg
+ }% si <texte> ne commence pas par "{" :
+ \substitute@nostar% exécuter macro non étoilée pour une seule itération
+}
+\def\substitutetocs{%
+ \ifstarred
+ {\let\recurse@macro\substitute@star \substitutetocs@i}%
+ {\let\recurse@macro\substitute@nostar\substitutetocs@i}%
+}
+\def\substitutetocs@i#1#2#3#4{% #1=<texte> #2=<motif> #3=<motif de substi> #4=\<macro>
+ \def\substitute@end{\edef#4{\the\subst@toks}}% macro exécutée à la fin
+ \substitute@i{#1}{#2}{#3}% continuer comme avec \substitute
+}
+\catcode`@12
+\frboxsep=1pt
+1) \substitute{ab{\bf racada}bra}{a}{W}\qquad
+2) \substitute*{ab{\bf racada}bra}{a}{W}\qquad
+3) \substitute{12\frbox{\bf 34}56}{\bf}{\it}\qquad
+4) \substitute*{12\frbox{\bf 34}56}{\bf}{\it}
+\medbreak
+
+1) \substitutetocs{ab{\bf racada}bra}{a}{W}\foo \meaning\foo\par
+2) \substitutetocs*{ab{\bf racada}bra}{a}{W}\foo \meaning\foo\par
+3) \substitutetocs{12\frbox{\bf 34}56}{\bf}{\it}\foo \meaning\foo\par
+4) \substitutetocs*{12\frbox{\bf 34}56}{\bf}{\it}\foo \meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 351 ******************
+\catcode`@11
+\def\vecteur{%
+ \ifnexttok[% si la macro est suivie d'un crochet
+ \vecteur@i% aller à la macro à arguments délimités
+ {\vecteur@i[1]}% sinon, ajouter l'argument optionnel par défaut entre crochets
+}
+\def\vecteur@i[#1]#2{% #1=arg optionnel #2=arg obligatoire
+ $(x_{#1},\ldots,x_{#2})$
+}
+\catcode`@12
+1) \vecteur{n}\qquad 2) \vecteur[0]{k}\qquad 3) \vecteur[i]j \qquad4) \vecteur[]n
+****************** Fin code ******************
+
+
+****************** Code 352 ******************
+\catcode`@11
+\def\forcemath#1{% compose #1 en mode math, quel que soit le mode en cours
+ \ifmmode\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+ {#1}{$#1$}%
+}
+\def\vecteur{%
+ \ifnexttok[% si la macro est suivie d'un crochet
+ \vecteur@i% aller à la macro à arguments délimités
+ {\vecteur@i[1]}% sinon, ajouter l'argument optionnel par défaut entre crochets
+}
+\def\vecteur@i[#1]{%
+ \ifnexttok(% si une parenthèse vient ensuite
+ {\vecteur@ii[#1]}% aller à la macro à argument délimités
+ {\vecteur@ii[#1](x)}% sinon, rajouter "x" comme argument optionnel
+}
+\def\vecteur@ii[#1](#2)#3{% #1 et #2=arg optionnel #3=arg obligatoire
+ \forcemath{({#2}_{#1},\ldots,{#2}_{#3})}%
+}
+\catcode`@12
+1) \vecteur{n}\qquad 2) \vecteur[0]{k}\qquad
+3) \vecteur[i](y)j \qquad4) \vecteur[](\alpha)n
+****************** Fin code ******************
+
+
+****************** Code 353 ******************
+\catcode`@11
+\def\vecteur{%
+ \ifnexttok[% si la macro est suivie d'un crochet
+ \vecteur@bracket% lire cet argument entre crochet
+ {\ifnexttok(% sinon, si elle est suivie d'une parenthèse
+ \vecteur@paren % lire cet argument entre parenthèses
+ {\vecteur@i[1](x)}% sinon, transmettre les arguments par défaut
+ }%
+}
+\def\vecteur@bracket[#1]{%
+ \ifnexttok(% s'il y a une parenthèse après
+ {\vecteur@i[#1]}% lire la parenthèse
+ {\vecteur@i[#1](x)}% sinon, donne "x" comme argument par défaut
+}
+\def\vecteur@paren(#1){%
+ \ifnexttok[% si le caractère suivant est un crochet
+ {\vecteur@ii(#1)}% lire l'argument entre crochets
+ {\vecteur@ii(#1)[1]}% sinon, donner "1" comme argument par défaut
+}
+\def\vecteur@i[#1](#2)#3{\forcemath{({#2}_{#1},\ldots,{#2}_{#3})}}
+\def\vecteur@ii(#1)[#2]{\vecteur@i[#2](#1)}% met les arg optionnels dans l'ordre
+\catcode`@12
+1) \vecteur{n}\qquad 2) \vecteur[i](y){j}\qquad 3) \vecteur(y)[i]{j}\qquad
+4) \vecteur[0]{k}\qquad 5) \vecteur(\alpha){n}
+****************** Fin code ******************
+
+
+****************** Code 354 ******************
+\catcode`\@11
+\def\foo#1{% #1 -> lit le premier argument obligatoire
+ \ifnexttok[% si le token suivant est un crochet
+ {\foo@i{#1}}% aller à \foo@i qui va lire cet argument
+ {\foo@i{#1}[xxx]}% sinon, transmettre [xxx] à foo@i
+}
+
+\def\foo@i#1[#2]#3#4{% lit l'arg obligatoire + arg optionnel + 2 arg obligatoires
+ \ifnexttok[
+ {\foo@ii{#1}[#2]{#3}{#4}}%
+ {\foo@ii{#1}[#2]{#3}{#4}[y]}%
+}
+
+\def\foo@ii#1[#2]#3#4[#5]#6{% lit tous les arguments
+ 1="#1" 2="#2" 3="#3" 4="#4" 5="#5" 6="#6"%
+}
+
+\catcode`\@12
+1) \foo{arg1}{arg2}{arg3}{arg4}\par
+2) \foo{arg1}[OPT\_A]{arg2}{arg3}{arg4}\par
+3) \foo{arg1}{arg2}{arg3}[OPT\_B]{arg4}\par
+4) \foo{arg1}[OPT\_A]{arg2}{arg3}[OPT\_B]{arg4}\medbreak
+****************** Fin code ******************
+
+
+****************** Code 355 ******************
+\catcode`\@11
+\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{%
+ % \macro@name construit 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{%
+ \ifxcase\nxttok
+ [\newmacro@optarg% si le prochain token est un crochet aller à \newmacro@optarg
+ \bgroup% si c'est un accolade ouvrante
+ % le texte de paramètre est fini et il faut définir la macro
+ {\defname{\macro@name\macro@cnt\expandafter}%
+ \the\param@text}% <- le {<code>} est juste après, il n'est pas encore lu
+ \elseif% sinon, c'est donc un chiffre
+ \newmacro@arg% aller à \newmacro@arg
+ \endif
+}
+
+\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, cette macro 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=nombre d'arguments obligatoires à ajouter
+ % boucle qui ajoute "#<x>#<x+1>etc" dans \param@text
+ % et "{#<x>}{#<x+1>}etc" dans \arg@text
+ \ifnum#1>\z@ % 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}% boucler
+ \else% si les arguments sont tous ajoutés
+ \expandafter\newmacro@i% lire le token suivant
+ \fi
+}
+\catcode`\@12
+\newmacro\foo 1[xxx]2[y]1{1="#1" 2="#2" 3="#3" 4="#4" 5="#5" 6="#6"}
+a) \foo{arg1}{arg2}{arg3}{arg4}\par
+b) \foo{arg1}[OPT\_A]{arg2}{arg3}{arg4}\par
+c) \foo{arg1}{arg2}{arg3}[OPT\_B]{arg4}\par
+d) \foo{arg1}[OPT\_A]{arg2}{arg3}[OPT\_B]{arg4}\medbreak
+
+\meaning\foo\par
+\expandafter\meaning\csname foo@[i]\endcsname\par
+\expandafter\meaning\csname foo@[ii]\endcsname
+****************** Fin code ******************
+
+
+****************** Code 356 ******************
+\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
+ }%
+}
+\frboxsep=1pt
+Boite \framebox{entière}, \framebox[ud]{Up down}, \framebox[LR]{Left Right},
+\framebox[LU]{Left Up} et \framebox[rd]{Right Down}.
+****************** Fin code ******************
+
+
+****************** Code 357 ******************
+\catcode`\@11
+\newtoks\eargs@toks
+\newtoks\eargs@temptoks
+\def\eargs[#1]#2{% #1=liste des développements #2=macro
+ \eargs@toks{#2}% mettre la macro dans le collecteur de tokens
+ \expandafter\eargs@i\detokenize{#1}\@nil% appeler \eargs@i avec
+ % la liste des developpements
+}
+
+\def\eargs@i#1\@nil{% #1=liste des n-développements restant
+ \ifempty{#1}% s'il n' y plus de n-développements
+ {\the\eargs@toks}% exécuter la macro et ses arguments développés
+ {\eargs@ii#1\@nil}% sinon appeller la macro qui lit un argument
+}
+
+% #1=n-développement actuel #2=liste des n-développements restants #3=argument lu
+\def\eargs@ii#1#2\@nil#3{%
+ \if+#1% si #1="+", un \edef est demandé pour cet argument
+ \edef\eargs@tempmacro{{#3}}% le stocker dans une macro temporaire
+ \else% sinon
+ \eargs@temptoks={#3}% stocker l'argument dans un registre temporaire
+ \for\eargs@loop = 1 to #1\do 1 % faire #1 fois :
+ {\eargs@temptoks=% 1-développer le 1er token du registre temporaire
+ \expandafter\expandafter\expandafter{\the\eargs@temptoks}%
+ }% puis le stocker dans la macro temporaire
+ \edef\eargs@tempmacro{{\the\eargs@temptoks}}%
+ \fi
+ \eaddtotoks\eargs@toks\eargs@tempmacro% ajouter le contenu de la macro au collecteur
+ \eargs@i#2\@nil% appeler \eargs@i avec les n-développements restants
+}
+\catcode`\@12
+\def\foo#1#2#3#4#5{\detokenize{1="#1" 2="#2" 3="#3" 4="#4" 5="#5"}}
+\def\aaa{\bbb}\def\bbb{\ccc}\def\ccc{Bonjour}
+
+\eargs[0123+]\foo{\aaa\bbb}{\aaa\bbb}{\aaa\bbb}{\aaa\bbb}{\aaa\bbb}.
+****************** Fin code ******************
+
+
+****************** Code 358 ******************
+\catcode`\@11
+\def\detectmark#1{% #1 est le marqueur
+ \begingroup
+ \catcode`#1=13 % rendra #1 actif après la macro
+ \begingroup% pour les besoins du \lccode
+ \lccode`\~=`#1 % transforme "~" en " #1 actif"
+ \lowercase{\endgroup\def~##1~}{\markeffect{##1}}%
+ \detectmark@i
+}
+\def\detectmark@i#1{%
+ #1% exécute le code
+ \endgroup% ferme le groupe, le marqueur perd son catcode actif
+}
+\catcode`\@12
+a) \def\markeffect#1{{\bf #1}}% met en gras
+\detectmark+{Un +argument+ où les +marqueurs+ sont détectés}
+\medskip
+
+b) \def\markeffect#1{% met dans une boite
+ \begingroup
+ \frboxsep=1pt % modifie l'espacement entre texte et encadrement
+ \frbox{\strut#1}% encadre
+ \endgroup
+}
+\detectmark|{Un |argument| où les |marqueurs| sont détectés}
+\medskip
+
+c) \def\markeffect#1{$\vcenter{\hbox{#1}\hbox{#1}}$}% superpose 2 fois
+\detectmark`{Un `argument` où les `marqueurs` sont détectés}
+****************** Fin code ******************
+
+
+****************** Code 359 ******************
+\catcode`\@11
+\def\detectmark#1{%
+ \begingroup
+ \catcode`#1=13 % rendra #1 actif après la macro
+ \begingroup% pour les besoins du \lccode
+ \lccode`\~=`#1 % transforme "~" en " #1 actif"
+ \lowercase{\endgroup\def~##1~}{\markeffect{##1}}%%
+ \detectmark@i
+}
+\def\detectmark@i#1{%
+ #1% lit le code
+ \endgroup% ferme le groupe, le marqueur perd son catcode actif
+}
+\catcode`\@12
+\def\markeffect#1{{\bf #1}}% met en gras
+\frbox{\detectmark+{Un +argument+ où les +marqueurs+ sont détectés}}
+****************** Fin code ******************
+
+
+****************** Code 360 ******************
+\catcode`\@11
+\newtoks\alter@toks% collecteur de tokens
+
+\def\alter#1#2{% #1= délimiteur #2 = macro à altérer
+ \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
+ \ifxcase\alter@nxttok% si le token à lire est
+ \egroup \alter@stop% "}" : aller à \alterstop@i
+ \sptoken \alter@readspc% " " : aller à \alter@readspc
+ \bgroup \alter@readarg% "{" : aller à \alter@readarg
+ \alter@markertoks \alter@readlitterate% "<delimiteur>" : aller à \alter@readlitterate
+ \elseif
+ \alter@readtok% dans les autres cas, aller à \alter@readtok
+ \endif
+}
+
+\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 rendu actif
+ \doforeach\alter@tmp\in{<,>,-,`,{,},'}% pour chaque motif de ligature
+ {\unless\if\alter@tmp\alter@markertoks% s'il est différent du délimiteur
+ % le rendre actif 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{% 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\alter@stop@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 ne demande pas 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\alter@stop@ii% aller à \alter@stop@ii après
+ \let\alter@tmptok= % avoir mangé l'accolade fermante
+}
+
+\def\alter@stop@ii{% donner à la \<macro> tout ce qui a été récolté
+ \expandafter\alter@macro\expandafter{\the\alter@toks}%
+ \alter@restorecatcode% puis restaure le catcode du délimiteur
+}
+\catcode`@12
+
+\frboxsep=1pt
+\alter|\frbox{Texte normal - |#& }| - texte normal - |_^ ##| - texte normal}
+\alter=\frbox{La macro =\alter= autorise du verbatim dans
+des commandes imbriquées \frbox{comme ici =\alter=}.}
+****************** Fin code ******************
+
+
+****************** Code 361 ******************
+\def\hello#1#2{Bonjour #1 et #2 !}
+\hello{foo}{bar}\par
+\alter|\identity{\hello{macro |{{{\foo|}{macro |\bar}|}}
+****************** Fin code ******************
+
+
+****************** Code 362 ******************
+\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
+}
+\frboxsep=1pt
+1) \frbox{Programmer en \catcode`\~=12 \TeX{} est~facile et~utile.}\par
+2) \frbox{Programmer en \retokenize{\catcode`\~=12 \TeX{} est~facile} et~utile.}\par
+3) \frbox{Programmer en \catcode`\~=12 \retokenize{\TeX{} est~facile} et~utile.}
+****************** Fin code ******************
+
+
+****************** Code 363 ******************
+\frboxsep=1pt
+1) \frbox{Programmer \retokenize{\litterate|en \TeX {} est |}facile et utile.}\par
+2) \frbox{Programmer \retokenize{\litterate|en \TeX{} est |}facile et utile.}
+****************** Fin code ******************
+
+
+****************** Code 364 ******************
+\frboxsep=1pt
+1) \frbox{Programmer en \catcode`\~=12 \TeX{} est~facile et~utile.}\par
+2) \frbox{Programmer en \scantokens{\catcode`\~=12 \TeX{} est~facile} et~utile.}\par
+3) \frbox{Programmer en \catcode`\~=12 \scantokens{\TeX{} est~facile} et~utile.}\par
+4) \frbox{Programmer \scantokens{\litterate|en \TeX {} est facile|} et utile.}\par
+5) \frbox{Programmer \scantokens{\litterate|en \TeX{} est facile|} et utile.}
+****************** Fin code ******************
+
+
+****************** Code 365 ******************
+\scantokens{a}b
+****************** Fin code ******************
+
+
+****************** Code 366 ******************
+\begingroup\endlinechar=-1 \scantokens{a}b\endgroup
+****************** Fin code ******************
+
+
+****************** Code 367 ******************
+\edef\foo{\scantokens{Bonjour le monde}}% produit une erreur
+****************** Fin code ******************
+
+
+****************** Code 368 ******************
+\expandafter\def\expandafter\foo\expandafter
+ {\scantokens{Bonjour le monde}}% produit une erreur
+****************** Fin code ******************
+
+
+****************** Code 369 ******************
+
+Voici la macro \string\foo\ : \foo.
+****************** Fin code ******************
+
+
+****************** Code 370 ******************
+\catcode`\@11
+\def\scandef#1#2{% #1=\<macro> #2=<texte>
+ \begingroup
+ \endlinechar=-1 % pas de caractère de fin de ligne
+ \everyeof{\@nil#1\noexpand}% ajoute "\@nil\<macro>\noexpand" avant la fin du fichier
+ \expandafter\scandef@i\expandafter\relax\scantokens{#2}%
+}
+\def\scandef@i#1\@nil#2{% "\@nil#2" ont été ajouté par \everyeof
+ \endgroup% ferme le groupe
+ \expandafter\def\expandafter#2\expandafter{\gobone#1}% et définit la \<macro>
+}
+\catcode`@12
+\def\foo{%
+ Dans tout l'argument de \string\foo, <<~>> est actif
+ sauf
+ \catcode`\~12
+ \scandef\bar{dans celui de \string\bar : <<~>>}%
+ \catcode`~13
+ \bar
+}
+\foo
+****************** Fin code ******************
+
+
+****************** Code 371 ******************
+{%
+\endlinechar=`\d% insère la lettre "d" à chaque fin de ligne
+% le \noexpan(d) est incomplet
+Voici la macro \string\foo\ : \foo.% fins de ligne...
+}% ...commentées pour éviter le "d"
+****************** Fin code ******************
+
+
+****************** Code 372 ******************
+\catcode`\@11
+\def\cprotect#1{% #1 est la \<macro>
+ \def\cprotect@i##1{% ##1 est l'<argument>
+ \endgroup% ferme le groupe précédemment ouvert
+ #1{\scantokens{##1\noexpand}}%
+ }%
+ \begingroup% rend tous les octets de catcode12
+ \for\cprotect@temp=0to255\do{\catcode\cprotect@temp=12 }%
+ \catcode`\{=1 \catcode`\}=2 % sauf "{" et "}"
+ \cprotect@i% puis, lit l'argument
+}
+\catcode`@12
+\frboxsep=1.5pt
+1) \cprotect\frbox{foo \litterate-&# #^ ^_%- bar}\par
+2) \cprotect\frbox{\catcode`\~=12 a~b~c~d}\par
+3) \cprotect\frbox{foo \litterate-\bar- \cprotect\frbox{\litterate-&# #-} fin}
+****************** Fin code ******************
+
+
+****************** Code 373 ******************
+\catcode`@11
+\def\Cprotect#1{% #1 est la \<macro>
+ \def\Cprotect@i##1{% ##1 est la liste des arguments
+ \endgroup% ferme le groupe précédemment ouvert
+ \toks0={#1}% met la \<macro> dans le registre de tokens
+ \Cprotect@ii##1\quark% \quark est mis à la fin des arguments
+ \the\toks0 % exécute le registre
+ }%
+ \begingroup% rend tous les octets de catcode12
+ \for\temp@arg= 0 to 255 \do{% changer à 12 tous les catcodes
+ \unless\ifnum\catcode\temp@arg=1 % sauf si catcode=1
+ \unless\ifnum\catcode\temp@arg=2 % ou 2
+ \catcode\temp@arg=12
+ \fi
+ \fi}%
+ \Cprotect@i% puis, lit l'argument
+}
+\def\Cprotect@ii#1{% #1 est l'argument courant (dépouillé de ses accolades)
+ \def\temp@arg{#1}% stocke l'argument pour le tester ci dessous :
+ \unless\ifx\quark\temp@arg% si la fin n'est pas atteinte
+ % ajouter "{\scantokens{#1\noexpand}}" au registre
+ \addtotoks{\toks0}{{\scantokens{#1\noexpand}}}%
+ \expandafter\Cprotect@ii% et recommencer
+ \fi
+}
+\catcode`@12
+
+\def\test#1#2{Bonjour #1 et #2}
+\Cprotect\test{{argument 1 : \litterate-\foo-}{argument 2 : \litterate-\bar-}}
+****************** Fin code ******************
+
+
+****************** Code 374 ******************
+\newdimen\pixelsize \newdimen\pixelsep
+\def\pixel{\vrule height\pixelsize width\pixelsize depth0pt }
+\def\vblankpixel{\vrule height\pixelsize width0pt depth0pt }
+\def\blankpixel{\vblankpixel \vrule height0pt width\pixelsize depth0pt }
+\def\gap{\kern\pixelsep}
+\pixelsize=3pt \pixelsep=1pt
+Essai :
+\vbox{% aligne verticalement
+ \offinterlineskip% annule le ressort d'interligne
+ \lineskip=\pixelsep\relax% pour le mettre à \pixelsep
+ \hbox{\pixel\gap\blankpixel\gap\blankpixel\gap\blankpixel\gap\pixel}% 1re ligne
+ \hbox{\pixel\gap\pixel \gap\blankpixel\gap\pixel \gap\pixel}% 2e ligne
+}
+****************** Fin code ******************
+
+
+****************** Code 375 ******************
+\pixelsize=3pt \pixelsep=1pt
+Essai :
+\vtop{%
+ \offinterlineskip \lineskip=\pixelsep\relax
+ \vbox{%
+ \hbox{\blankpixel\gap\pixel \gap\pixel \gap\pixel}% ***
+ \hbox{\pixel \gap\blankpixel\gap\blankpixel\gap\pixel}% * *
+ \hbox{\pixel \gap\blankpixel\gap\blankpixel\gap\pixel}% * *
+ \hbox{\pixel \gap\blankpixel\gap\blankpixel\gap\pixel}% * *
+ \hbox{\blankpixel\gap\pixel \gap\pixel \gap\pixel}% ***
+ }% ----ligne de base
+ \hbox {\blankpixel\gap\blankpixel\gap\blankpixel\gap\pixel}% *
+ \hbox {\blankpixel\gap\pixel \gap\pixel }% **
+}
+****************** Fin code ******************
+
+
+****************** Code 376 ******************
+\catcode`\@11
+\begingroup% dans ce groupe :
+\catcode`\ =12\relax% l'espace devient un "caractère autre"
+\catcode`\^^M=13\relax% le retour à la ligne est actif
+\edef^^M{\string,}% et se développe en une virgule (de catcode 12)
+\global\deftok\otherspc{ }% définit un espace de catcode 12
+\xdef\letter@code{% macro contenant le dessin de la lettre "e"
+ **
+* *
+***
+*
+ ***}%
+\endgroup
+
+\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
+}
+\pixelsize=3pt \pixelsep=1pt
+\let\pixabove\empty% initialisation de la macro finale à vide
+\exparg\makecar@i\letter@code% appelle la macro qui construit \pixabove
+La lettre
+\vtop{% enferme le tout dans une \vtop :
+ \offinterlineskip\lineskip=\pixelsep% ajuste l'espace interligne
+ \vbox{\pixabove}% affiche le caractère créé
+}.
+****************** Fin code ******************
+
+
+****************** Code 377 ******************
+\catcode`\@11
+\begingroup% dans ce groupe :
+\catcode`\ =12\relax% l'espace devient un "caractère autre"
+\catcode`\^^M=13\relax% le retour à la ligne est actif
+\edef^^M{\string,}% et se développe en une virgule (de catcode 12)
+\global\deftok\otherspc{ }% définit un espace de catcode 12
+\xdef\letter@code{% macro contenant le dessin de la lettre "g"
+ ***
+* *
+* *
+* *
+ ***_
+ *
+ **}%
+\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@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
+}
+
+\makecar\lettreg\letter@code
+\catcode`\@12
+\pixelsize=3pt \pixelsep=1pt
+
+Essai : \lettreg
+****************** Fin code ******************
+
+
+****************** Code 378 ******************
+\catcode`\@11
+\begingroup
+\expandafter\gdef\csname impact@" "\endcsname{% définit la lettre "espace"
+ \hskip 4\pixelsize plus.5\pixelsize minus.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"
+\gdef\impact@alphabet{
+a/
+***
+ *
+ ***
+* *
+****,
+b/
+*
+*
+***
+* *
+* *
+* *
+***,
+% beaucoup de caractères omis
+9/
+ ***
+* *
+* *
+ ****
+ *
+ *
+ ***,
+0/
+ ***
+* *
+* *
+* * *
+* *
+* *
+ ***,
+error/
+* * *
+ * *
+* * *
+ * *
+* * *
+ * *
+* * *}% <- commenter la fin de ligne
+\endgroup%
+% 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
+% % définit l'espace
+\pixelsize=3pt \pixelsep=1pt
+% puis, on affiche ce qui a été défini :
+a = \csname impact@"a"\endcsname\qquad b = \csname impact@"b"\endcsname\qquad
+9 = \csname impact@"9"\endcsname \qquad 0 = \csname impact@"0"\endcsname\qquad
+error = \csname impact@"error"\endcsname
+****************** Fin code ******************
+
+
+****************** Code 379 ******************
+\catcode`\@11
+\newskip\letter@skip% ressort mis entre chaque lettre
+\def\impactend{\impactend}% définit le quark de fin
+
+\newmacro\impact[0.2ex][0pt]{% définit la macro à arguments optionnels
+ \leavevmode% passer en mode horizontal
+ \begingroup% dans un groupe semi-simple :
+ \pixelsize=#1\relax \pixelsep=#2\relax% définir ces deux dimensions
+ \letter@skip=#1 plus.1\pixelsize minus.1\pixelsize\relax% définir espace inter-lettre
+ \baselineskip=% définir la distance entre les lignes de base
+ \dimexpr12\pixelsize+7\pixelsep\relax% à 12\pixelsize+7\pixelsep
+ \lineskiplimit=0pt % si lignes trop serrées
+ \lineskip=2\pixelsize\relax% les espacer de 2\pixelsize
+ \impact@i% puis aller voir le prochain token
+}
+
+% va voir le prochain token puis va le tester à \impact@ii
+\def\impact@i{\futurelet\nxtletter\impact@ii}
+
+\def\impact@ii{%
+ \ifx\nxtletter\impactend% si le token est \let égal à \impactend
+ \let\donext\impact@endprocess% aller à al macro de fin
+ \else
+ \ifx\nxtletter\sptoken% si c'est un espace
+ \let\donext\impact@spc% aller à \impact@spc
+ \else
+ \let\donext\impact@arg% sinon, aller à \impact@arg
+ \fi
+ \fi
+ \donext% faire l'action décidée ci-dessus
+}
+
+% mange un espace (argument délimité) et affiche "\letter@<spc>"
+\expandafter\def\expandafter\impact@spc\space{%
+ \csname impact@" "\endcsname
+ \impact@i% puis va voir le prochain token
+}
+%
+% lit l'argument suivant
+\def\impact@arg#1{%
+ \csname impact@% affiche
+ \ifcsname impact@"#1"\endcsname
+ "#1"% le caractère \impact@"#1" s'il est défini
+ \else
+ "error"% sinon \impact@"error"
+ \fi
+ \endcsname
+ \hskip\letter@skip% insérer le ressort inter-lettre
+ \impact@i% puis, aller voir le prochain token
+}
+\def\impact@endprocess\impactend{% macro exécuté lorsqque le quark \impactend va être lu
+ \unskip% annuler le dernier ressort
+ \par% composer le paragraphe pour prendre en compte
+ % \baselineskip, \lineskip et \lineskiplimit
+ \endgroup% et fermer le groupe
+}
+\catcode`\!=12 % rend le point d'exclamation "gentil"
+\impact Programmer en {TEX} est facile et tr{e`}s utile !\impactend\par
+\impact[2pt][0.5pt]Programmer en {TEX} est facile et tr{e`}s utile !\impactend
+****************** Fin code ******************
+
+
+****************** Code 380 ******************
+\newdimen\maingraddim \maingraddim=4pt % hauteur des graduations principales
+\newdimen\maingradwd \maingradwd=0.5pt % épaisseur des graduations principales
+\def\maingradx#1{%
+ \lower1.5ex\clap{$\scriptscriptstyle#1$}% afficher l'argument au dessous
+ \clap{\vrule height\maingraddim width\maingradwd depth0pt }% et la réglure
+}
+Début\maingradx{1}suite\maingradx{2}conclusion\maingradx{3}fin.
+****************** Fin code ******************
+
+
+****************** Code 381 ******************
+\maingraddim=4pt \maingradwd=0.5pt
+\newdimen\axiswd \axiswd=0.5pt
+\newmacro\xaxis[1cm]1[1]1[4]{%% #1= dist #2=xmin #3=inc #4=xmax #5=subdiv
+ \hbox{% mettre le tout dans une \hbox
+ \rlap{% en débordement à droite :
+ \FOR\xx = #2 to #4 \do #3{% pour chaque graduation principale
+ \maingradx{\xx}% tracer la graduation et écrire l'abscisse
+ \kern#1\relax% puis 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
+ }%
+}
+a) \xaxis{-2}{5}suite
+
+b) \frboxsep=0pt\frbox{\xaxis[1.25cm]{-1}[0.25]{1}}suite
+****************** Fin code ******************
+
+
+****************** Code 382 ******************
+\maingraddim=4pt \maingradwd=0.5pt \axiswd=0.5pt
+\newdimen\subgraddim \subgraddim=2.5pt
+\newdimen\subgradwd \subgradwd=0.2pt
+% trace un trait de subdivision
+\def\subgradx{\clap{\vrule height\subgraddim width\subgradwd depth0pt }}
+
+\newmacro\xaxis[1cm]1[1]1[4]{% #1= dist #2=xmin #3=inc #4=xmax #5=subdiv
+ \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
+ }%
+}
+a) \xaxis{-2}{5}[2]
+
+)b \xaxis[1.25cm]{-1}[0.25]{1}[5]
+****************** Fin code ******************
+
+
+****************** Code 383 ******************
+\maingraddim=4pt \maingradwd=0.5pt \axiswd=0.5pt
+\subgraddim=2.5pt \subgradwd=0.2pt
+\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 }}
+\newmacro\yaxis[1cm]1[1]1[4]{%
+% #1= dist #2=ymin #3=inc #4=ymax #5=subdiv
+ \vbox{%
+ \offinterlineskip% désactiver le ressort d'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 ordonnées
+ 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
+ }%
+ }%
+}
+
+Essai : \yaxis{-2}{5}[2]\qquad \frboxsep=0pt \frbox{\yaxis[0.75cm]{-1}[0.5]{3}[5]}
+****************** Fin code ******************
+
+
+****************** Code 384 ******************
+\newdimen\xunit \xunit=1cm
+\newdimen\yunit \yunit=0.75cm
+\maingraddim=4pt \maingradwd=0.5pt \axiswd=0.5pt
+\subgraddim=2.5pt \subgradwd=0.2pt
+\catcode`@11
+\newmacro\graphzone1[1]1[4]1[1]1[4]{%
+ \leavevmode% quitter le mode vertical
+ \begingroup% travailler dans un groupe semi-simple
+ \def\graphxmin{#1}\def\graphxmax{#3}% sauvegarder
+ \def\graphymin{#5}\def\graphymax{#7}% les
+ \def\xincrement{#2}\def\yincrement{#6}% arguments
+ \setbox0\hbox{\yaxis[\yunit]{#5}[#6]{#7}[#8]}% axe "y" dans boite 0
+ \setbox1\hbox{\xaxis[\xunit]{#1}[#2]{#3}[#4]}% axe "x" dans boite 1
+ \edef\graphboxht{\the\ht0 }% \graphboxh est la hauteur de la zone
+ \edef\graphboxwd{\the\wd1 }% \graphboxw est la largeur de la zone
+ \rlap{% annuler la dimension horizontale, et...
+ \box1 % ...afficher l'axe (Ox) puis
+ % le trait vertical à l'extrême droite de la zone
+ \clap{\vrule height\dimexpr\graphboxht+\axiswd\relax width\axiswd depth0pt }%
+ }%
+ \rlap{\box0 }% afficher l'axe (Oy) en annulant sa dimension horizontale
+ \raise\graphboxht% puis monter tout en haut de la zone
+ % pour tracer le trait horizontal en annulant sa longueur
+ \rlap{\kern-0.5\axiswd% et en rattrapant le centrage de l'axe des ordonnées
+ \vrule height\axiswd width\dimexpr\graphboxwd+\axiswd}%
+ \begingroup% pour lire l'argument "<code>" :
+ \catcode`\^^M=9\relax % ignorer les retours à la ligne
+ \graphzone@i% appeler \graphzone@i
+}
+\def\graphzone@i#1{% lire le <code>...
+ \endgroup% et fermer le groupe précédemment ouvert
+ \setbox0\hbox{#1}% mettre les instructions graphique dans la boite 0
+ \wd0=\dimexpr\graphboxwd+\axiswd\relax% forcer sa dim horizontale
+ \ht0=\dimexpr\graphboxht+\axiswd\relax% et verticale
+ % pour correspondre aux dimension de la zone graphique
+ \box0 % l'afficher
+ \endgroup% sortir du groupe initial
+}
+\catcode`@12
+essai\graphzone{-1}[0.5]{1.5}[5]{-20}[10]{10}[2]{\relax}fin
+****************** Fin code ******************
+
+
+****************** Code 385 ******************
+\def\putat#1#2#3{%
+ \leavevmode\rlap{\kern#1\vbox to0pt{\vss\hbox{#3}\kern#2}}%
+}
+Essai\putat{0.5cm}{0.3cm}{A}\putat{-0.2cm}{-0.1cm}{B}\putat{0pt}{0.2cm}{C}suite
+****************** Fin code ******************
+
+
+****************** Code 386 ******************
+\def\ifinside#1[#2,#3]{%
+ \ifnum\sgn{\dimexpr#1pt-#2pt\relax}\sgn{\dimexpr#1pt-#3pt}1=1
+ \expandafter\secondoftwo
+ \else
+ \expandafter\firstoftwo
+ \fi
+}
+1) \ifinside3.5[0.5,4]{vrai}{faux}\qquad
+2) \ifinside-0.2[-0.4,-0.3]{vrai}{faux}\qquad
+3) \ifinside-0.999[-1,-0.5]{vrai}{faux}
+****************** Fin code ******************
+
+
+****************** Code 387 ******************
+\def\fonction#1{\dimtodec\dimexpr
+ \decmul{#1}{\decmul{#1}{#1}}pt% x^3
+ -\decmul{#1}{#1}pt% -x^2
+ -#1pt*3% -3x
+ +2pt\relax}% +2
+1) \fonction{-4}\qquad% doit afficher -66
+2) \fonction{-1.7}\qquad % doit afficher -0.703
+3) \fonction{1}\qquad% doit afficher -1
+4) \fonction{1.35}% doit afficher -1.412125
+****************** Fin code ******************
+
+
+****************** Code 388 ******************
+\newmacro\cross[2pt][0.2pt]{%
+ % #1=dimensions de traits depuis le centre de la croix
+ % #2=épaisseur des traits
+ \leavevmode
+ \vlap{%
+ \clap{%
+ \vrule height#2 depth0pt width#1 % 1/2 trait horizontal gauche
+ \vrule height#1 depth#1 width#2 % trait vertical
+ \vrule height#2 depth0pt width#1 % 1/2 trait horizontal droit
+ }%
+ }%
+}
+Une croix : \cross{}puis une autre\cross[8pt][0.8pt]
+****************** Fin code ******************
+
+
+****************** Code 389 ******************
+\maingraddim=4pt \maingradwd=0.5pt \axiswd=0.5pt
+\subgraddim=2.5pt \subgradwd=0.2pt
+\xunit=1.25cm \yunit=0.75cm
+
+\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 }}
+
+\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 d'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 ordonnées
+ 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
+ }%
+ }%
+}
+
+\catcode`@11
+\newmacro\graphzone1[1]1[4]1[1]1[4]{%
+ \leavevmode% quitter le mode vertical
+ \begingroup% travailler dans un groupe semi-simple
+ \def\graphxmin{#1}\def\graphxmax{#3}% sauvegarder
+ \def\graphymin{#5}\def\graphymax{#7}% les
+ \def\xincrement{#2}\def\yincrement{#6}% arguments
+ \setbox0\hbox{\yaxis[\yunit]{#5}[#6]{#7}[#8]}% axe "y" dans boite 0
+ \setbox1\hbox{\xaxis[\xunit]{#1}[#2]{#3}[#4]}% axe "x" dans boite 1
+ \edef\graphboxht{\the\ht0 }% \graphboxh est la hauteur de la zone
+ \edef\graphboxwd{\the\wd1 }% \graphboxw est la largeur de la zone
+ \rlap{% annuler la dimension horizontale, et...
+ \box1 % ...afficher l'axe (Ox) puis
+ % le trait vertical à l'extrême droite de la zone
+ \clap{\vrule height\dimexpr\graphboxht+\axiswd\relax width\axiswd depth0pt }%
+ }%
+ \rlap{\box0 }% afficher l'axe (Oy) en annulant sa dimension horizontale
+ \raise\graphboxht% puis monter tout en haut de la zone
+ % pour tracer le trait horizontal en annulant sa longueur
+ \rlap{\kern-0.5\axiswd% et en rattrapant le centrage de l'axe des ordonnées
+ \vrule height\axiswd width\dimexpr\graphboxwd+\axiswd}%
+ \begingroup% pour lire l'argument "<code>" :
+ \catcode`\^^M=9\relax % ignorer les retours à la ligne
+ \graphzone@i% appeler \graphzone@i
+}
+\def\graphzone@i#1{% lire le <code>...
+ \endgroup% et fermer le groupe précédemment ouvert
+ \xunit=\decdiv1\xincrement\xunit% divise les unités par l'incrément
+ \yunit=\decdiv1\yincrement\yunit
+ \setbox0\hbox{#1}% mettre les instructions graphique dans la boite 0
+ \wd0=\dimexpr\graphboxwd+\axiswd\relax% forcer sa dim horizontale
+ \ht0=\dimexpr\graphboxht+\axiswd\relax% et verticale
+ % pour correspondre aux dimension de la zone graphique
+ \box0 % l'afficher
+ \endgroup% sortir du groupe initial
+}
+
+\def\putat#1#2#3{%
+ \leavevmode\rlap{\kern#1\vbox to0pt{\vss\hbox{#3}\kern#2}}%
+}
+
+\newmacro\cross[2pt][0.2pt]{%
+ \leavevmode
+ \vlap{%
+ \clap{%
+ \vrule height#2 depth0pt width#1 % 1/2 terait horizontal gauche
+ \vrule height#1 depth#1 width#2 % trait vertical
+ \vrule height#2 depth0pt width#1 % 1/2 trait horizontal droit
+ }%
+ }%
+}
+
+\def\plot(#1,#2){% place "\plotstuff" aux coordonnées #1,#2
+ \edef\x@plot{#1}\edef\y@plot{#2}% développer au cas où
+ \ifinside\x@plot[\graphxmin,\graphxmax]% si #1 est dans les limites
+ {\ifinside\y@plot[\graphymin,\graphymax]% et si #2 l'est aussi
+ {\putat% placer aux coordonnées
+ {\dimexpr\x@plot\xunit-\graphxmin\xunit\relax}% X=(x-xmin)/xinc
+ {\dimexpr\y@plot\yunit-\graphymin\yunit\relax}% Y=(y-ymin)/yinc
+ \plotstuff% le contenu de \plotstuff
+ }%
+ \relax
+ }
+ \relax
+}
+
+\def\showxaxis{% affiche l'axe (Ox)
+ \ifinside0[\graphymin,\graphymax]%
+ {\putat\z@{-\graphymin\yunit}{\vlap{\vrule width\graphboxwd height\axiswd}}}%
+ \relax
+}
+
+\def\showyaxis{% affiche l'axe (Oy)
+ \ifinside0[\graphxmin,\graphxmax]%
+ {\putat{-\graphxmin\xunit}\z@{\clap{\vrule width\axiswd height\graphboxht}}}%
+ \relax
+}
+
+\def\showaxis{\showxaxis\showyaxis}% affiche les deux axes
+\catcode`@12
+
+%%%%%%%%%%%%%%% 1er exemple :
+\xunit=1cm \yunit=0.5cm
+\def\fonction#1{\dimtodec\dimexpr\decmul{#1}{\decmul{#1}{#1}}pt-%
+ \decmul{#1}{#1}pt-#1pt*3+2pt\relax}
+Exemple 1 :\qquad
+\graphzone{-2}[0.5]{2.5}[5]{-5}{5}[2]{%
+ \let\plotstuff\cross% définit ce qu'il faut afficher comme point
+ \FOR\xx=-2 to 2.5 \do 0.1{%
+ \plot(\xx,\fonction{\xx})% afficher les points de coordonnées (x ; f(x))
+ }%
+ \putat{5pt}{\dimexpr\graphboxht-10pt\relax}% afficher
+ {$f(x)=x^3-x^2-3x+2$}% la fonction tracée
+ \showaxis% et les axes
+}\par\medskip
+%%%%%%%%%%%%% 2e exemple
+\xunit=0.7cm \yunit=\xunit
+\def\foncx#1{\dimtodec\dimexpr\decmul{#1}{\decmul{#1}{#1}}pt-%
+ \decmul{4}{\decmul{#1}{#1}}pt-#1pt+4pt}
+\def\foncy#1{\dimtodec\dimexpr\decmul{#1}{#1}pt-#1pt*2-6pt}
+Exemple 2 :\qquad
+\graphzone{-12}[2]{12}[2]{-8}[2]{8}[2]{%
+ \def\plotstuff{\cross[1.25pt]}
+ \FOR\tt = -5 to 5 \do 0.1 {%
+ \plot(\foncx\tt,\foncy\tt)%
+ }%
+ \putat{5pt}{\dimexpr\graphboxht-20pt\relax}% afficher la fonction paramétrique tracée
+ {$\left\{\vcenter{\hbox{$x(t)=t^3-4t^2-t-4$}\hbox{$y(t)=t^2-2t-6$}}\right.$}%
+ \showaxis
+}
+****************** Fin code ******************
+
+
+****************** Code 390 ******************
+\def\mandeltest#1#2{%
+ \def\zx{0}\def\zy{0}% zn=0 + i*0
+ \def\zxx{0}\def\zyy{0}% carrés de \zx et \zy
+ \def\mandelresult{1}% le point appartient à M a priori
+ \for\ii=1to\maxiter\do1{%
+ \advance\count255 by1
+ \edef\zy{\dimtodec\dimexpr\decmul{\decmul2\zx}\zy pt+#2pt\relax}%
+ \edef\zx{\dimtodec\dimexpr\zxx pt-\zyy pt+#1pt\relax}%%
+ \edef\zxx{\decmul\zx\zx}%
+ \edef\zyy{\decmul\zy\zy}%
+ \ifdim\dimexpr\zxx pt+\zyy pt\relax>4pt
+ \def\mandelresult{0}%
+ \exitfor\ii
+ \fi
+ }%
+}
+\def\mandel#1#2{% #1=points par unité #2=nombre maximal d'itérations
+ \graphzone{-2}[1]{1}[2]{-1}[1]{1}[2]{%
+ \def\maxiter{#2}%
+ \edef\plotstuff{\the\dimexpr\xunit/#1\relax}% taille d'un pixel
+ \edef\plotstuff{\vrule height\plotstuff width\plotstuff}%
+ \edef\increment{\decdiv{1}{#1}}% incrément
+ \count255=0 % compteur des itérations
+ \FOR\xxx = -2 to 1 \do \increment{% pour chaque
+ \FOR\yyy = 0 to 1 \do \increment{% pixel du domaine
+ \mandeltest\xxx\yyy% tester s'il est dans M
+ \ifnum\mandelresult=1 % si oui,
+ \plot(\xxx,\yyy)\plot(\xxx,-\yyy)% afficher les 2 points
+ \fi
+ }%
+ }%
+ \edef\plotstuff{$\scriptstyle\number\count255 $}% affiche la valeur du compteur
+ \plot(-1.99,0.92)% aux coordonnées (-1.99 ; 0.92)
+ }%
+}
+\xunit=3cm \yunit=3cm \mandel{400}{500}
+****************** Fin code ******************
+
+
+****************** Code 391 ******************
+\catcode`\@11
+\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@i 1.#1..}% sinon, afficher la virgule et mettre en forme
+}
+
+% #1=compteur de caractères #2= chiffre courant
+% #3= chiffres restants #4 = chiffres déjà traités
+\def\formatdecpart@i#1.#2#3.#4.{%
+ \ifempty{#3}% si #2 est le dernier chiffre
+ {#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.}%
+ }%
+}
+a) \formatdecpart{1234567}\qquad
+b) \formatdecpart{987125}\qquad
+c) \formatdecpart{56}\qquad
+d) \edef\foo{\formatdecpart{2014}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 392 ******************
+\catcode`\@11
+\protected\def\numsep{\kern0.2em }% \numsep est le séparateur mis tous les 3 chiffres
+\def\formatintpart#1{% #1=série de chiffres
+ \formatintpart@i 1.#1..% appelle la macro récursive
+}
+
+% #1=compteur de caractères #2= chiffre courant
+% #3= chiffres restants #4 = chiffres déjà traités
+\def\formatintpart@i#1.#2#3.#4.{%
+ \ifempty{#3}% si #2 est le dernier chiffre
+ {#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 et recommencer
+ % sinon, mettre #2 en première position et recommencer
+ % tout en incrémentant #1 de 1
+ {\expandafter\formatintpart@i \number\numexpr#1+1.#3.#2#4.}%
+ }%
+}
+\catcode`\@12
+a) \formatintpart{1234567}\qquad b) \formatintpart{987125}\qquad
+c) \formatintpart{56}\qquad
+d) \edef\foo{\formatintpart{2014}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 393 ******************
+\catcode`\@11
+\def\formatintpart#1{% #1=série de chiffres
+ \expandafter\formatintpart@i\expandafter1\expandafter.\romannumeral\reverse{#1\z@}..%
+}
+
+\catcode`\@12
+a) \formatintpart{1234567}\qquad b) \formatintpart{987125}\qquad
+c) \formatintpart{56}\qquad
+d) \edef\foo{\formatintpart{2014}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 394 ******************
+\catcode`\@11
+\def\ifnodecpart#1{\if@nodecpart#1.\@nil}% teste si #1 est un entier
+\def\if@nodecpart#1.#2\@nil{\ifempty{#2}}
+
+\def\formatnum#1{%
+ \ifnodecpart{#1}% s'il n'y a pas de partie décimale
+ {\formatintpart{#1}}% formatter la partie entière
+ {\formatnum@i#1\@nil}% sinon, formatter les deux parties
+}
+
+\def\formatnum@i#1.#2\@nil{%
+ \formatintpart{#1}% formatte la partie entière
+ \formatdecpart{#2}% et la partie décimale
+}
+
+\catcode`\@12
+a) \formatnum{3.1415926}\qquad
+b) \formatnum{1987654.12301}\qquad
+c) \edef\foo{\formatnum{0987654.12300}}$\foo$
+****************** Fin code ******************
+
+
+****************** Code 395 ******************
+\catcode`\@11
+\def\removefirstzeros#1{%
+ \removefirstzeros@i#1\quark% ajoute "\quark" en dernier
+}
+\def\removefirstzeros@i#1{% #1=chiffre courant
+ \ifx\quark#1% fin atteinte donc nombre = 0
+ \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 #1 et tout afficher jusqu'à \removefirstzeros@i
+ \expandafter\expandafter\expandafter\removefirstzeros@ii
+ \expandafter\expandafter\expandafter#1%
+ \fi
+ \fi
+}
+\def\removefirstzeros@ii#1\quark{#1}
+\catcode`\@12
+a) \removefirstzeros{000325478}\qquad
+b) \removefirstzeros{00000}\qquad
+c) \edef\foo{\removefirstzeros{001000}}\meaning\foo\qquad
+d) \long\def\>#1<{\detokenize{#1}}
+ \expandafter\>\romannumeral\removefirstzeros{0123}<
+****************** Fin code ******************
+
+
+****************** Code 396 ******************
+\long\def\>#1<{\detokenize{#1}}
+\expandafter\>\romannumeral-`\@\removefirstzeros{000123}<
+****************** Fin code ******************
+
+
+****************** Code 397 ******************
+\catcode`\@11
+\def\removelastzeros#1{%
+ \exparg\reverse% inverser après
+ {\romannumeral-`\.% tout développer
+ \expandafter\removelastzeros@i% enlever les 0 de gauche après
+ \romannumeral\reverse{#1\z@}\quark% avoir inversé #1
+ }%
+}
+\def\removelastzeros@i#1{% enlève tous les 0 de gauche
+ \unless\ifx\quark#1% si la fin n'est pas atteinte
+ \ifx0#1% si le chiffre lu est un 0
+ \expandafter\expandafter\expandafter\removelastzeros@i% recommencer
+ \else% sinon remettre le chiffre et tout afficher jusqu'à \removefirstzeros@i
+ \expandafter\expandafter\expandafter\removelastzeros@ii
+ \expandafter\expandafter\expandafter#1%
+ \fi
+ \fi
+}
+\def\removelastzeros@ii#1\quark{#1}
+\catcode`\@12
+a) \removelastzeros{0003254780}\qquad
+b) \removelastzeros{00000}\qquad
+c) \edef\foo{\removelastzeros{001000}}\foo\qquad
+\long\def\>#1<{\detokenize{#1}}
+d) \expandafter\>\romannumeral-`\.\removelastzeros{012300}<
+****************** Fin code ******************
+
+
+****************** Code 398 ******************
+\catcode`\@11
+\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@i 1.#1..}% sinon, afficher la virgule et mettre en forme
+}
+
+% #1=compteur de caractères #2= chiffre courant
+% #3= chiffres restants #4 = chiffres déjà traités
+\def\formatdecpart@i#1.#2#3.#4.{%
+ \ifempty{#3}% si #2 est le dernier chiffre
+ {#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.{%
+ \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\quark% ajoute "\quark" en dernier
+}
+\def\removefirstzeros@i#1{% #1=chiffre courant
+ \ifx\quark#1% fin atteinte donc nombre = 0
+ \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 #1 et tout afficher jusqu'à \removefirstzeros@i
+ \expandafter\expandafter\expandafter\removefirstzeros@ii
+ \expandafter\expandafter\expandafter#1%
+ \fi
+ \fi
+}
+\def\removefirstzeros@ii#1\quark{#1}
+
+\def\removelastzeros#1{%
+ \exparg\reverse% inverser après
+ {\romannumeral-`\.% tout développer
+ \expandafter\removelastzeros@i% enlever les 0 de gauche après
+ \romannumeral\reverse{#1\z@}\quark% avoir inversé #1
+ }%
+}
+\def\removelastzeros@i#1{% enlève tous les 0 de gauche
+ \unless\ifx\quark#1% si la fin n'est pas atteinte
+ \ifx0#1% si le chiffre lu est un 0
+ \expandafter\expandafter\expandafter\removelastzeros@i% recommencer
+ \else% sinon remettre le chiffre et tout afficher jusqu'à \removefirstzeros@i
+ \expandafter\expandafter\expandafter\removelastzeros@ii
+ \expandafter\expandafter\expandafter#1%
+ \fi
+ \fi
+}
+\def\removelastzeros@ii#1\quark{#1}
+
+% renvoie vrai s'il n'y a pas de partie décimale
+\def\if@nodecpart#1.#2\@nil{\ifempty{#2}}
+
+\def\formatnum#1{\formatnum@i1!#1!}
+
+% #1 = <série de signes> suivie de "1"
+% #2 = caractère courant
+% #3 = caractères non traités
+\def\formatnum@i#1!#2#3!{%
+ \ifx+#2\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+ {\ifempty{#3}% si #2=+ et #3 est vide
+ {\number#1 }% afficher "+1" ou "-1" (il n'y avait que des signes)
+ {\formatnum@i#2#1!#3!}% sinon, mettre le signe #2 devant #1
+ }
+ {\ifx-#2\expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+ {\ifempty{#3}% si #2=- et #3 est vide
+ {\number#1 }% afficher "+1" ou "-1" (il n'y avait que des signes)
+ {\formatnum@i#2#1!#3!}% sinon, mettre le signe #2 devant #1
+ }% #2 est le dernier caractère qui n'est pas un signe + ou -
+ {\ifnum#1<0 -\fi% si "<signes>1" est <0 afficher un "-"
+ \formatnum@ii{#2#3}% formatter le nombre formé avec "#2#3""
+ }%
+ }%
+}
+
+\def\formatnum@ii#1{%
+ \if@comma{#1}% si #1 comporte une virgule
+ {\formatnum@iii#1\@nil}% la remplacer par un "." et recommencer
+ {\if@nodecpart#1.\@nil% puis si les chiffres restants sont un entier
+ {\formatintpart{#1}}% formatter l'entier
+ {\formatnum@iv#1\@nil}% sinon, formatter le nombre
+ }%
+}
+
+\def\formatnum@iii#1,#2\@nil{\formatnum@ii{#1.#2}}
+
+\def\formatnum@iv#1.#2\@nil{% formatte le nombre décimal #1.#2
+ \exparg\formatintpart{\romannumeral-`\.\removefirstzeros{#1}}%
+ \exparg\formatdecpart{\romannumeral-`\.\removelastzeros{#2}}%
+}
+
+\def\if@comma#1{\if@comma@i#1,\@nil}% teste la présence d'un virgule dans #1
+\def\if@comma@i#1,#2\@nil{\ifempty{#2}\secondoftwo\firstoftwo}
+\catcode`\@12
+
+a) \formatnum{3,141592653589793238462643383279502884197169399375105820974944592}\par
+b) \formatnum{---+69874}\qquad
+c) \formatnum{0032100,98000}\qquad
+d) \formatnum{+++010.01100}\qquad
+e) \formatnum{-+--+}\qquad
+f) \formatnum{---00.0000}\qquad
+g) \formatnum{+99,0000}\qquad
+h) \formatnum{.123456}\par
+i) \edef\foo{\formatnum{-+-+-010500,090900}}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 399 ******************
+\setbox0=\vbox{%
+ \hbox{Première ligne}
+ \hbox{Deuxième ligne}
+ \hbox{Avant-dernière ligne}
+ \hbox{Dernière ligne}
+}
+
+\frboxsep=0pt % aucun espace entre le contenu et l'encadrement
+Boite initiale de hauteur \the\ht0 {} : \frbox{\copy0 }
+\splittopskip0pt % ne rajouter aucun espace au sommet de la boite restante
+\setbox1=\vsplit0 to 22pt % couper la boite à 22pt de hauteur
+
+Boite 1 de hauteur \the\ht1 {} : \frbox{\box1 }
+
+Boite 0 de hauteur \the\ht0 {} : \frbox{\box0 }
+****************** Fin code ******************
+
+
+****************** Code 400 ******************
+\setbox0=\vbox{%
+ \hbox{Première ligne}
+ \hbox{Deuxième ligne}
+ \hbox{Avant-dernière ligne}
+ \hbox{Dernière ligne}
+}
+
+\edef\restorevbadness{\vbadness=\the\vbadness\relax}% restaurera le \vbadness
+\vbadness=10000 % plus d'avertissement pour boite verticale
+\frboxsep=0pt % aucun espace entre le contenu et l'encadrement
+Boite initiale de hauteur \the\ht0 {} : \frbox{\copy0 }
+\splittopskip0pt % ne rajouter aucun espace au sommet de la boite restante
+\setbox1=\vsplit0 to 22pt % couper la boite à 22pt de hauteur
+\setbox1=\vbox{\unvbox1 }% la boite 1 prend la hauteur naturelle
+\restorevbadness\relax% restaure le \vbadness
+
+Boite 1 de hauteur \the\ht1 {} : \frbox{\box1 }
+
+Boite 0 de hauteur \the\ht0 {} : \frbox{\box0 }
+****************** Fin code ******************
+
+
+****************** Code 401 ******************
+\catcode`@11
+\newbox\remainbox
+\newbox\partialbox
+\newdimen\cut@ht
+
+\def\breakpar{%
+ \par\nointerlineskip% termine le paragraphe précédent
+ \vskip\frboxsep\relax% et saute une petite espace verticale
+ \begingroup
+ \splittopskip\topskip% \topskip en haut des boites coupées
+ \topskip=0pt % neutraliser le \topskip
+ % nbre de réglures horizontales contribuant à l'encadrement restant (2 au début)
+ \def\coeff@rule{2}%
+ \setbox\remainbox=\vbox\bgroup% compose la boite après avoir...
+ \advance\hsize by -2\dimexpr\frboxrule+\frboxsep\relax% ajusté sa largeur
+}
+
+\def\endbreakpar{%
+ \egroup% fin de la composition de la boite
+ \def\rule@arg{ULR}% prendre l\cut@htes réglures d'encadrement haute, gauche et droite
+ \splitbox% puis, aller à l'algorithme de coupure
+ \endgroup% une fois fini, sortir du groupe semi-simple
+}
+
+\def\splitbox{%
+ \ifvoid\remainbox% si la boite est vide, c'est la fin du processus
+ \par\nointerlineskip% termine le paragraphe précédent
+ \vskip\frboxsep\relax% et saute un petit espace vertical
+ \else% sinon
+ \expandafter\splitbox@i% aller à \splitbox@i
+ \fi
+}
+
+\def\splitbox@i{%
+ \hbox{}% composer un noeud en mode vertical
+ \nointerlineskip% pas de ressort d'interligne
+ % calculer la dimension verticale disponible dans la page pour le texte de la boite
+ \cut@ht=\dimexpr\pagegoal-\pagetotal-(\frboxsep+\frboxrule)*\coeff@rule\relax
+ % si dimension totale du texte > dimension disponible pour le texte
+ \ifdim\dimexpr\ht\remainbox+\dp\remainbox>\cut@ht% si une coupure doit être faite
+ \advance\cut@ht\dimexpr% augmenter Dv de l'espace verticale libérée
+ +\frboxsep+\frboxrule% par la réglure inférieure qui n'est pas sur cette page
+ \relax
+ \edef\old@vbadness{\the\vbadness}% sauvegarder \badness
+ \vbadness=10000 % désactive les avertissement lors de la coupure
+ \def\coeff@rule{1}% ne prendre en compte que réglure D + espace D
+ \setbox\partialbox=\vsplit\remainbox to\cut@ht% coupe à la hauteur calculée
+ % \partialbox retrouve sa hauteur naturelle
+ \setbox\partialbox=\vbox{\unvbox\partialbox}%
+ \vbadness=\old@vbadness\relax% restaure \vbadness
+ \printpartialbox% imprime la boite partielle
+ \vfill\eject% et compose la page en cours
+ \else% si une coupure n'est pas nécessaire :
+ \setbox\remainbox\vbox{\unvbox\remainbox}% reprendre la hauteur naturelle
+ \setbox\partialbox=\box\remainbox% \partialbox devient \remainbox
+ % et cette dernière devient vide
+ \cut@ht=\dimexpr\ht\partialbox+\dp\partialbox\relax% hauteur à encadrer
+ \edef\rule@arg{\rule@arg D}% ajouter "D" aux réglures à tracer
+ \printpartialbox% afficher la boite restante
+ \fi
+ \splitbox
+}
+
+\def\printpartialbox{% imprime \partialbox
+ \expandafter\framebox\expandafter[\rule@arg]{%
+ \vbox to\cut@ht{\unvbox\partialbox\vss}}%
+ \def\rule@arg{LR}% ne mettre que les réglures d et g
+}
+
+\def\dummytext#1{%
+ \for\xx=1to#1\do% composer #1 fois la phrase suivante :
+ {Ceci est un texte sans aucun int\'er\^et dont le seul but est de meubler
+ la page artificiellement.
+ }%
+}
+
+\catcode`@12
+\dummytext{5}
+\frboxsep=5pt
+
+\breakpar
+ \dummytext{70}
+\endbreakpar
+
+\dummytext{5}
+****************** Fin code ******************
+
+
+****************** Code 402 ******************
+\setbox0=\vbox{%
+ \hsize=5cm
+ Ceci est un texte sans aucun intérêt dont le seul but est de meubler
+ la page de façon artificielle.
+}
+
+Boite 0 : \copy0 % affiche la boite totale
+\medbreak
+
+\edef\restorevfuzz{\vfuzz=\the\vfuzz\relax}% appelée après la coupure
+\vfuzz=\maxdimen% annule les avertissements pour débordement
+\splittopskip=0pt % ne rajouter aucun espace au sommet de la boite restante
+\setbox1=\vsplit0 to 0pt % couper la boite à 0pt de hauteur
+\restorevfuzz% restaurer \vfuzz
+\setbox1=\vbox{\unvbox1}% redonner à la boite sa hauteur d'origine
+
+Boites 1+0 : \vbox{%
+ \offinterlineskip% annule le ressort d'interligne
+ \box1 % affiche la première ligne
+ \box0 %affiche les lignes restantes
+}
+****************** Fin code ******************
+
+
+****************** Code 403 ******************
+\def\vdim#1{\dimexpr\ht#1+\dp#1\relax}% hauteur totale de la boite #1
+\setbox0=\vbox{%
+ \hsize=5cm Ceci est un texte sans aucun intérêt dont le seul but est
+ de meubler la page de façon artificielle.
+}
+\edef\htbefore{\the\vdim0}% hauteur de la boite 0
+
+Boite 0 : \copy0 % affiche la boite totale
+\medbreak
+
+\edef\restoreparam{%
+ \vfuzz=\the\vfuzz\relax% sauvegarde le \vfuzz
+ \splittopskip=\the\splittopskip% et \splittopskip
+}%
+\vfuzz=\maxdimen% annule les avertissements pour débordement
+\splittopskip=0pt % ne rajouter aucun espace au sommet de la boite restante
+\setbox1=\vsplit0 to 0pt % couper la boite à 0pt de hauteur
+\restoreparam
+\setbox1=\vbox{\unvbox1}% redonner à la boite sa hauteur d'origine
+
+\edef\intersplitspace{\the\dimexpr\htbefore-(\vdim0+\vdim1)\relax}%
+Boites 1+0 : \vbox{%
+ \offinterlineskip% annule le ressort d'interligne
+ \box1 % affiche la première ligne
+ \vskip\intersplitspace\relax% ajoute le ressort perdu à la coupure
+ \box0 % affiche les lignes restantes
+}
+****************** Fin code ******************
+
+
+****************** Code 404 ******************
+\setbox0=\vbox{%
+ \hsize=5cm Ceci est un texte sans aucun intérêt dont le seul but est
+ de meubler la page de façon artificielle.
+}
+
+Boite 0 : \copy0 % affiche la boite totale
+\medbreak
+
+\edef\restoreparam{%
+ \vfuzz=\the\vfuzz\relax% sauvegarde le \vfuzz
+ \splittopskip=\the\splittopskip\relax% , le \splittopskip
+ \savingvdiscards=\the\savingvdiscards\relax% et le \savingvdiscards
+ }%
+\vfuzz=\maxdimen% annule les avertissements pour débordement
+\splittopskip=0pt % ne rajouter aucun espace au sommet de la boite restante
+\savingvdiscards=1 % autorise la sauvagarde des éléments supprimés
+\setbox1=\vsplit0 to 0pt % couper la boite à 0pt de hauteur
+\setbox1=\vbox{\unvbox1}% redonner à la boite sa hauteur d'origine
+\restoreparam
+
+Boites 1+0 : \vbox{%
+ \offinterlineskip% annule le ressort d'interligne
+ \box1 % affiche la première ligne
+ \splitdiscards% affiche les éléments ignorés
+ \box0 % affiche les lignes restantes
+}
+****************** Fin code ******************
+
+
+****************** Code 405 ******************
+\catcode`@11
+\newbox\remainbox% boite contenant le texte total
+\newbox\currentline% boite contenant le ligne en cours
+\newcount\linecnt% compteur pour numéroter les lignes
+
+\def\vdim#1{\dimexpr\ht#1+\dp#1\relax}% hauteur totale de la boite #1
+
+\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% par défaut, afficher chaque ligne telle quelle
+
+% Par défaut :
+\leftline[11pt]{$\scriptscriptstyle\number\linecnt$\kern3pt }% 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
+ \linecnt=0 % initialiser le compteur de lignes
+ \savingvdiscards=1 % autorise la sauvagarde des éléments supprimés
+ \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
+ \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
+}
+
+\def\dummytext#1{%
+ \for\xx=1to#1\do% composer #1 fois la phrase suivante :
+ {Ceci est un texte sans aucun intérêt dont le seul but est de meubler
+ la page de façon artificielle. }%
+}
+
+\catcode`@12
+\parindent=2em
+
+ESSAI 1 :
+\numlines
+ \dummytext{2}\par% 2 phrases
+ $$1+1=2$$\par% des maths
+ \dummytext{1}\par% une phrase
+ \hrulefill\par% un leaders
+ \dummytext{2}% 2 phrases
+ \hrule height2pt depth 2pt %une \hrule
+ \vskip10pt % saute 10pt verticalement
+ \dummytext{1}% une phrase
+\endnumlines\medbreak
+
+ESSAI 2 :
+\leftline{}\rightline{}% rien à gauche et rien à droite
+\frboxsep=-\frboxrule% encadrer vers "l'intérieur"
+\let\formatline\frbox% lignes encadrées
+\numlines
+ \dummytext{4}
+\endnumlines\medbreak
+
+ESSAI 3 :
+\let\formatline\identity
+\leftline[7pt]{%
+ \for\xx= 1 to 2 \do{% insérer 2 fois
+ \setbox0=\hbox{% % mettre dans une \hbox une \vrule de "bonnes dimensions"
+ \vrule height\ht\currentline depth\dimexpr\dp\currentline+\intersplitspace
+ width0.5pt }%
+ \dp0=\dp\currentline% réajuster la profondeur (c-à-d enlever \intersplitspace)
+ \box0 % afficher le boite
+ \kern2pt % et insérer un espace horizontal de 2pt après chaque réglure verticale
+ }%
+ \kern2pt % ajouter 2pt de plus entre les lignes et le texte
+}
+
+\rightline[10pt]{\kern5pt $\scriptscriptstyle\number\linecnt$}% numéroter à droite
+
+\numlines
+ \dummytext{2}
+
+ $$a^2+b^2=c^2$$
+
+ \dummytext{2}
+\endnumlines
+****************** Fin code ******************
+
+
+****************** Code 406 ******************
+% définition des ressorts "inter-lettre" et "inter-mot"
+\newskip\interletterskip \interletterskip=0.25em plus0.05em minus0.05em
+\newskip\interwordskip \interwordskip=3\interletterskip\catcode`\@11
+\catcode`@11
+\def\spreadtxt@testtoken#1{% macro qui teste le token
+ \ifcat\noexpand#1\sptoken% si le token est un espace
+ \parseadd{%
+ \unskip% retirer le précédent ressort
+ \hskip\interwordskip}% et ajouter le ressort inter-mot
+ \else
+ \ifcat\noexpand#1a% si le token est une lettre
+ \parseadd{#1\hskip\interletterskip}% ajouter le ressort inter-lettre
+ \else
+ \ifcat\noexpand#1.% si le token est "autre", comme le "."
+ \parseadd{#1\hskip\interletterskip}% ajouter le ressort inter-lettre
+ \else% sinon
+ \parseadd{#1}% ajouter le token lu
+ \fi
+ \fi
+ \fi
+ \parse@i
+}
+\def\spreadtxt{%
+ \ifstarred% si étoilée
+ {\spreadtxt@i{\parse*}}% appeler \parse*
+ {\spreadtxt@i{\parse}}% sinon, appeler \parse
+}
+\def\spreadtxt@i#1#2{% #1= appel "\parse*" ou "\parse" #2 = texte à espacer
+ \begingroup% dans un groupe
+ \let\testtoken=\spreadtxt@testtoken% modifier \testtoken
+ #1#2\parsestop% et appeler \parse
+ \endgroup
+}
+\catcode`@12
+
+\spreadtxt{Comme on le voit sur cet exemple, une espace est insérée après
+{\it chaque} caractère de catcode 10, 11 ou 12.}
+\medbreak
+
+\spreadtxt*{Comme on le voit sur cet exemple, une espace est insérée après
+{\it chaque} caractère de catcode 10, 11 ou 12.}
+****************** Fin code ******************
+
+
+****************** Code 407 ******************
+\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 -> a 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 plus0.07em minus.07em][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\rightofsc#1#2{%
+ \exparg\ifin{#1}{#2}% si #1 contient le #2
+ {\def\right@of##1#2##2\@nil{\def#1{##2}}%
+ \expandafter\right@of#1\@nil% appelle la macro auxiliaire
+ }%
+ {\let#1=\empty}% sinon, #1 est vide
+}
+
+\def\spacetxt@nostar{%
+ \exparg\ifempty{\spacetxt@code}% si texte restant est vide
+ \spacetxt@endprocess% aller à la fin du processus
+ {\@indivifoundfalse% sinon, a priori, les motifs non réguliers ne sont pas trouvés
+ % pour chaque \indivi@tmp dans \indivilist
+ \expsecond{\doforeach\indivi@tmp\in}{\indivilist}% pour chaque motif indivisible
+ {% si le code commence par le motif courant
+ \exptwoargs\ifstartwith\spacetxt@code\indivi@tmp
+ {% l'ajouter dans le registre ainsi que l'espace inter-lettre
+ \eaddtotoks\spacetxt@toks{\indivi@tmp\hskip\interletterskip}%
+ % et enlever le motif du texte restant à lire
+ \expsecond{\rightofsc\spacetxt@code}{\indivi@tmp}%
+ \@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
+ }%
+ \unless\if@indivifound% si aucun motif n'a été trouvé
+ \grab@first\spacetxt@code\spacetxt@temp% retirer le 1er caractère du texte
+ \ifx\spacetxt@temp\space% si le 1er caractère est un espace
+ \addtotoks\spacetxt@toks{%
+ \unskip% annuler le précédent ressort
+ \hskip\interwordskip}% ajouter l'espace inter-mot au registre de token
+ \else% si le 1er caractère n'est pas un espace
+ % ajouter ce caractère et l'espace inter-lettre au registre de token
+ \eaddtotoks\spacetxt@toks{\spacetxt@temp\hskip\interletterskip}%
+ \fi
+ \fi
+ \spacetxt@recurse% enfin, continuer le processus
+ }%
+}
+
+\def\spacetxt@star{%
+ \exparg\ifempty{\spacetxt@code}% si texte restant est vide
+ \spacetxt@endprocess% aller à la fin du processus
+ {% sinon, si texte commence par "{"
+ \exparg\ifbracefirst{\spacetxt@code}%
+ {\grab@first\spacetxt@code\spacetxt@temp
+ % mettre {<argument} dans \spacetxt@temp
+ \begingroup% ouvrir un groupe
+ % mettre le contenu de l'argument dans \spacetxt@code
+ \expandafter\def\expandafter\spacetxt@code\spacetxt@temp
+ \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
+}
+
+\catcode`\@12
+\def\indivilist{é,è}% liste des motifs spéciaux
+\spacetxt*{Comme on le voit sur cet exemple, une espace est insérée après
+{\it chaque} caractère.}
+\medbreak
+
+\def\indivilist{é,es,au,<<,>>}
+\spacetxt[4pt plus.7pt minus.7pt][12pt plus2pt minus2pt]{Ici, les motifs <<es>> et <<au>>
+restent indivisibles et la ligature des guillemets devient possible en déclarant "<<" et
+">>" comme motifs.}
+****************** Fin code ******************
+
+
+****************** Code 408 ******************
+\catcode`\@11
+\def\ttcode#1{% lit #1, le <délimiteur> de début
+ \def\ttcode@i##1#1{% ##1 = <texte> entre délimiteurs
+ \tt% passe en fonte à chasse fixe
+ \setbox0=\hbox{ }%
+ \edef\spc@wd{\the\wd0 }% longueur d'un espace
+ \spacetxt
+ [.1pt plus0pt minus.1pt]% espace inter-lettre
+ [\glueexpr\wd0+.3pt plus.1pt minus.1pt\relax]% espace inter-mot
+ {##1}% le <texte> est composé par \spacetxt
+ \endgroup
+ }%
+ \begingroup
+ \def\indivilist{<<,>>,{,,},--}% (rajouter à, é, è, etc. en codage UTF8)
+ \def\do##1{\catcode`##1=12 }%
+ \dospecials% rend inoffensifs tous les tokens spéciaux
+ \letactive\ =\space % rend l'espace actif
+ \ttcode@i% va lire le <texte> et le délimiteur de fin
+}
+\catcode`\@12
+
+\hfill\vrule\vbox{%
+ \hsize=.75\hsize
+ Avec \ttcode/\ttcode/, on peut insérer une adresse internet <<
+ \ttcode-http://www.gutenberg.eu.org/Typographie- >> puis repasser en fonte normale
+ puis \ttcode+même composer un court passage en fonte à chasse fixe -- même si les
+ coupures de mots se font n'importe où -- et aussi afficher tous les caractères
+ spéciaux <<{$^ _$#}&+>>, et finir en fonte normale\ldots
+}\vrule\hfill\null
+****************** Fin code ******************
+
+
+****************** Code 409 ******************
+\def\ttwide{0.7}% coefficient pour la largeur de composition
+\def\ttindent{5}% nombre de caractères d'indentation
+\hfill\vrule
+\vbox{%
+ \ttfamily% en TeX, on écrirait "\tt"
+ \setbox0\hbox{0}% \wd0 est donc la largeur d'un caractère
+ \parindent=\ttindent\wd0 % réglage de l'indentation
+ \hsize=\ttwide\hsize % compose sur 70% de la largeur
+ Dans ce paragraphe, composé en fonte à chasse fixe et où les limites gauches
+ et droites du texte ont été tracées, on constate que les caractères sont
+ exactement les uns au-dessous d'une ligne à l'autre. Des débordements dans
+ la marge deviennent alors inévitables, car la largeur de composition (ici
+ \the\hsize) n'est pas un multiple de la largeur d'un caractère (\the\wd0 ),
+ le quotient des deux valant environ
+ \xdef\ttratio{\decdiv{\dimtodec\hsize}{\dimtodec\wd0 }}\ttratio.
+}%
+\vrule\hfill\null
+****************** Fin code ******************
+
+
+****************** Code 410 ******************
+Fonte normale : \fontname\font\par
+{\bf Fonte grasse : \fontname\font\par}
+{\it Fonte italique : \fontname\font\par}
+{\sc Fonte petites majuscules : \fontname\font}
+****************** Fin code ******************
+
+
+****************** Code 411 ******************
+\font\gras=LinLibertineTB-tlf-t1 at 8pt
+\font\ital= LinLibertineTI-tlf-t1 at 8pt
+\font\itgras=LinLibertineTBI-tlf-t1 at 8pt
+Du texte normal {\gras puis en gras, \ital en italique,
+\itgras en italique gras} et retour à la normale.
+****************** Fin code ******************
+
+
+****************** Code 412 ******************
+Code du caractère de coupure = \number\hyphenchar\font\par
+Caractère de coupure : "\char\hyphenchar\font"
+****************** Fin code ******************
+
+
+****************** Code 413 ******************
+\def\longtext{Voici une phrase écrite avec des mots insignifiants mais terriblement,
+ épouvantablement, horriblement et indéniablement longs.}
+% créér une macro restaurant le \hyphenchar
+\edef\restorehyphenchar{\hyphenchar\font=\number\hyphenchar\font}%
+
+%comportement normal, caractère de coupure "-"
+1) \vrule\vbox{\hsize=5cm \longtext}\vrule\hfill
+% modification du caractère de coupure "W"
+2) \vrule\vbox{\hsize=5cm \hyphenchar\font=`W \longtext}\vrule
+\medbreak
+% interdiction des coupures de mots
+3) \vrule\vbox{\hsize=5cm \hyphenchar\font=-1 \longtext}\vrule
+\restorehyphenchar
+****************** Fin code ******************
+
+
+****************** Code 414 ******************
+\def\longtext{Voici une phrase écrite avec des mots insignifiants mais terriblement,
+ épouvantablement, horriblement et indéniablement longs.}
+
+\edef\restorehyphenchar{\hyphenchar\font=\number\hyphenchar\font}%
+\vrule\vbox{\hsize=5cm \hyphenchar\font=-1 \sloppy \longtext}\vrule
+\restorehyphenchar
+****************** Fin code ******************
+
+
+****************** Code 415 ******************
+a) \texttt{\number\hyphenchar\font}\qquad
+b) {\ttfamily\number\hyphenchar\font}
+****************** Fin code ******************
+
+
+****************** Code 416 ******************
+\leavevmode
+\vbox{%
+ \hsize=.4\hsize
+ \Souligne{Police à chasse variable}%
+ \vskip5pt
+ espace inter-mot = \the\fontdimen2\font\par
+ étrirement inter-mot = \the\fontdimen3\font\par
+ compression inter-mot = \the\fontdimen4\font
+}\hfill
+\vbox{%
+ \tt
+ \hsize=.4\hsize
+ \Souligne{Police à chasse fixe}%
+ \vskip5pt
+ espace inter-mot = \the\fontdimen2\font\par
+ étrirement inter-mot = \the\fontdimen3\font\par
+ compression inter-mot = \the\fontdimen4\font
+}
+****************** Fin code ******************
+
+
+****************** Code 417 ******************
+\def\ttwide{0.7}\def\ttindent{5}%
+\hfill\vrule
+\vbox{%
+ \ttfamily
+ \hyphenchar\font=`\- % change le caractère de coupure de la fonte en cours
+ \setbox0\hbox{0}\parindent=\ttindent\wd0
+ \hsize=\ttwide\hsize % compose sur 70% de la largeur
+ Dans ce paragraphe, composé en fonte à chasse fixe et où les limites gauche
+ et droite du texte ont été tracées, on constate que les caractères sont
+ exactement les uns au-dessous des autres d'une ligne à l'autre. Des débordements
+ dans la marge deviennent inévitables même si les coupures des mots sont
+ à nouveau rendues possibles.%
+}%
+\vrule\hfill\null
+****************** Fin code ******************
+
+
+****************** Code 418 ******************
+\frboxsep=0.5pt
+\def\printallchars{%
+ \leavevmode
+ \for\xx=0 to255\do{%
+ \vbox{% empiler verticalement
+ \offinterlineskip% en désactivant le ressort d'interligne
+ \setbox0\hbox{\frbox{\char\xx}}%
+ \copy0 % la boite contenant le caractère encadré
+ \kern1pt% saute 1pt vertical
+ \hbox to\wd0{\hss$\scriptscriptstyle\xx$\hss}% le numéro
+ }\hskip0.5em plus1pt minus1pt % saute 0.5em horizontalement
+ }%
+}
+\tt
+Nom de la fonte = \fontname\font\par
+\printallchars
+****************** Fin code ******************
+
+
+****************** Code 419 ******************
+\setbox0=\hbox{\tt\char23}
+Largeur = \the\wd0 \qquad Hauteur = \the\ht0 \qquad Profondeur = \the\dp0
+****************** Fin code ******************
+
+
+****************** Code 420 ******************
+{\tt\xdef\nfont{\the\font}}
+Largeur = \the\fontcharwd\nfont23 \qquad Hauteur = \the\fontcharht\nfont23
+\qquad Profondeur = \the\fontchardp\nfont23
+****************** Fin code ******************
+
+
+****************** Code 421 ******************
+\newmacro\ttstart[5]{%
+ \begingroup
+ \tt
+ \edef\restorefontsettings{% stocke les paramètres de fonte
+ \hyphenchar\font=\the\hyphenchar\font\relax% le \hyphenchar
+ \fontdimen2\font=\the\fontdimen2\font\relax% et les paramètres d'espacement
+ \fontdimen3\font=\the\fontdimen3\font\relax
+ \fontdimen4\font=\the\fontdimen4\font\relax
+ }%
+ \fontdimen3\font=0.30\fontdimen2\font% composante + = 30% de la dimension naturelle
+ \fontdimen4\font=0.20\fontdimen2\font% composante - = 20% de la dimension naturelle
+ \hyphenchar\font=`\- % on autorise la coupure des mots (au cas où on utilise latex)
+ \setbox0\hbox{0}% largeur d'un caractère
+ \parindent=#1\wd0 % indentation (en nombre de caractères)
+ \ignorespaces
+}
+\def\ttstop{%
+ \restorefontsettings% restaure les paramètres de fonte
+ \endgroup% et ferme le groupe
+}
+\hfill\vrule
+\def\ttwide{0.70}%
+\vbox{%
+ \hsize=\ttwide\hsize % compose sur 70% de la largeur
+ \ttstart[5]
+ Dans ce paragraphe, composé en fonte à chasse fixe et où les limites gauche
+ et droite du texte ont été tracées, on constate que les caractères ne sont pas
+ exactement les uns au-dessous des autres entre les lignes du paragraphe.
+ Puisque les espaces sont redevenus étirables, les débordements dans la marge
+ (même s'ils restent possibles), sont bien plus rares et ce d'autant plus que
+ le nombre d'espaces dans une ligne est grand.%
+ \ttstop
+}%
+\vrule\hfill\null
+****************** Fin code ******************
+
+
+****************** Code 422 ******************
+\catcode`\@11
+\newcount\brktt@cnt
+\newdimen\brktt@interletter
+\newif\ifline@start% booléen vrai lorsqu'aucun caractère n'est encore affiché
+\newif\if@indivifound% booléen qui sera vrai si un motif spécial est rencontré
+
+\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% feerme la \hbox précédente
+ \hbox\bgroup% ouvre la suivante
+ \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
+}
+
+\newmacro\breaktt[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 fonte à chasse fixe
+ \setbox0 = \hbox{M}% la boite 0 contient un caractère
+ \edef\ttchar@width{\the\wd0 }% largeur de chaque caractère en fonte \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ère 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
+ % stocke le texte après avoir enlevé les éventuels espaces extremes :
+ \expsecond{\expsecond{\def\tt@remaintext}}{\removetrailspaces{#3}}%
+ \unless\ifx\tt@remaintext\empty% 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
+ \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\breaktt@i% aller à la macro récursive
+ \fi
+}
+
+\def\breaktt@i{%
+ \print@nchar\maxchar@num% afficher \maxchar@num caractères
+ \ifx\tt@remaintext\empty% si texte restant est vide
+ \egroup% fermer la hbox
+ \par% aller à la ligne
+ \endgroup% fermer le groupe ouvert au début
+ \else
+ \unless\ifnum\brktt@cnt<\maxchar@num\relax% si la ligne est remplie
+ \exparg\restart@hbox{\tt@remaintext}% ferme la hbox et en ré-ouvre une
+ \fi
+ \expandafter\breaktt@i% enfin, continuer le processus
+ \fi
+}
+
+\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, a 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 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}% l'enlever du texte restant
+ \@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
+ }%
+}
+\catcode`\@12
+
+\def\liglist{<<,>>}% liste des motifs de ligature
+ % ajouter à, é, etc si codage UTF8 + moteur 8 bits
+\def\ttindent{3}% valeur de l'indentation'
+\vrule\vbox{\breaktt[4pt][.7\hsize]{%
+Dans ce paragraphe, composé en fonte à chasse fixe et où les limites gauche
+et droite du texte ont été tracées, on constate que les caractères sont
+exactement les uns au-dessous des autres d'une ligne à l'autre. Plus aucun
+débordement n'a lieu, car une espace correctement calculée est insérée entre
+chaque caractère. Les mots, en revanche, sont toujours coupés <<sauvagement>>.%
+}%
+}\vrule\smallbreak
+
+\vrule\vbox{\breaktt[1pt][6cm]{%
+Dans ce paragraphe, composé en fonte à chasse fixe et où les limites gauche
+et droite du texte ont été tracées, on constate que les caractères sont
+exactement les uns au-dessous des autres d'une ligne à l'autre. Plus aucun
+débordement n'a lieu, car une espace correctement calculée est insérée entre
+chaque caractère. Les mots, en revanche, sont toujours coupés <<sauvagement>>.%
+}%
+}\vrule
+****************** Fin code ******************
+
+
+****************** Code 423 ******************
+\catcode`\@11
+\newcount\brktt@cnt
+\newdimen\brktt@interletter
+\newif\ifline@start% booléen vrai lorsqu'aucun caractère n'est encore affiché
+\newif\if@indivifound% booléen qui sera vrai si un motif spécial est rencontré
+
+\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 fonte à chasse fixe
+ \setbox0 = \hbox{M}% la boite 0 contient un caractère
+ \edef\ttchar@width{\the\wd0 }% largeur de chaque caractère en fonte \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
+ % stocke le texte après avoir enlevé les éventuels espaces extremes :
+ \expsecond{\expsecond{\def\tt@remaintext}}{\removetrailspaces{#3}}%
+ \unless\ifx\tt@remaintext\empty% 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
+ \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\breakttA@i{%
+ \edef\remaining@chars{% calculer le nombre de caractères restant à placer sur la ligne
+ \numexpr\maxchar@num-\brktt@cnt\relax}%
+ \len@tonextword% \next@len contient le nombre de caractères du prochain mot
+ % si le mot + l'eventuel "-" qui le suit ne peut pas loger sur la ligne en cours
+ \ifnum\numexpr\next@len+\extra@char\relax>\remaining@chars\relax
+ \ifline@start% et si c'est le début d'une ligne
+ % avertir l'utilisateur
+ \message{Largeur de composition trop faible pour
+ \unexpanded\expandafter{\next@word}^^J}%
+ % et composer tout de même "à la sauvage" jusqu'à la fin de la ligne
+ \exparg\print@nchar{\number\numexpr\maxchar@num-\brktt@cnt}%
+ \else% si la ligne en cours n'est pas au début
+ \insert@blankchar*{\maxchar@num-\brktt@cnt}% remplir la ligne d'espaces
+ \fi
+ \exparg\restart@hbox{\tt@remaintext}% commencer une nouvelle ligne
+ \expandafter\breakttA@i% et poursuivre le processus
+ % s'il y a assez de place pour accueillir ce qui est avant la prochaine coupure
+ \else
+ \print@nchar\next@len% afficher le mot
+ \ifx\tt@remaintext\empty% si texte restant est vide
+ \insert@blankchar*{\maxchar@num-\brktt@cnt}% remplir la ligne
+ \egroup% fermer la hbox en cours
+ \par% aller à la ligne
+ \endgroup% fermer le groupe ouvert au début. Fin du processus
+ \else% si le texte restant n'est pas vide
+ \ifnum\brktt@cnt<\maxchar@num\relax% si la ligne n'est pas remplie
+ \print@nchar{1}% afficher le caractère qui suit le mot (" " ou "-")
+ \else% si la ligne est remplie
+ \exparg\restart@hbox{\tt@remaintext}% ferme la hbox et en ré-ouvre une
+ \fi
+ \expandafter\expandafter\expandafter\breakttA@i% enfin, continuer le processus
+ \fi
+ \fi
+}
+
+\def\leftofsc#1#2{% dans la macro #1, garde ce qui est à gauche de #2
+ \def\leftofsc@i##1#2##2\@nil{\def#1{##1}}%
+ \expandafter\leftofsc@i#1#2\@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 = dim(boite)/dim(caractère)
+ \edef\next@len{\number\numexpr\dimexpr\wd0 \relax/\dimexpr\ttchar@width\relax\relax}%
+}
+\catcode`\@12
+
+\def\liglist{<<,>>}% liste des motifs de ligature (mettre à, é, etc si codage UTF8)
+\def\ttindent{3}
+
+\vrule\vbox{\breakttA[3pt][8cm]{%
+Dans ce paragraphe, composé en fonte à chasse fixe et où les limites gauche
+et droite du texte ont été tracées, on constate que les caractères sont
+exactement les uns au-dessous d'une ligne à l'autre. Plus aucun débordement
+n'a lieu, car une espace correctement calculée est insérée entre chaque
+caractère. Dorénavant, les mots ne sont plus coupés <<~sauvagement~>>.
+}}\vrule\medbreak
+
+\leavevmode\vrule\vbox{\breakttA[1pt][5cm]{%
+Dans ce paragraphe, composé en fonte à chasse fixe et où les limites gauche
+et droite du texte ont été tracées, on constate que les caractères sont
+exactement les uns au-dessous d'une ligne à l'autre. Plus aucun débordement
+n'a lieu, car une espace correctement calculée est insérée entre chaque
+caractère. Dorénavant, les mots ne sont plus coupés <<~sauvagement~>>.
+}}\vrule\qquad\def\ttindent{0}%
+\vrule\vbox{\breakttA[0.6pt][2cm]{mot-composé mot-clé passe-droit au-dessus
+là-bas remonte-pente vingt-huit Notre-Dame-de-Lourdes Mont-Blanc
+Saint-Jean-de-Luz}}\vrule
+****************** Fin code ******************
+
+
+****************** Code 424 ******************
+\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 pénalité supplémentaire après la première ligne
+ \interlinepenalty=0 % pas de pénalité inter-ligne
+ \widowpenalty=0 % pas de 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
+ }%
+}
+\zerocompose{0}{Programmation}%
+\leavevmode\box0
+\hskip 5cm
+\zerocompose{0}{Composer en largeur nulle}%
+\box0
+****************** Fin code ******************
+
+
+****************** Code 425 ******************
+\def\dummytext{Ceci est un texte sans aucun intérêt dont le seul but est de meubler
+ la page de façon artificielle. }
+\setbox0=\vtop{% définit la boite 0
+ \hsize=8cm
+ \dummytext\dummytext
+}
+
+a) Boite pleine : \copy0
+
+b) \setbox0=\vtop{%
+ \unvbox0 % boite précédemment composée
+ \global\setbox1=\lastbox% et capture la dernière ligne dans la boite 1
+ }%
+ Dernière ligne = |\hbox{\unhbox1 }|\par% redonne à box1 sa largeur naturelle
+ Boite restante = \box0
+****************** Fin code ******************
+
+
+****************** Code 426 ******************
+\def\dummytext{Ceci est un texte sans aucun intérêt dont le seul but est de meubler
+ la page de façon artificielle. }
+\setbox0=\vtop{% définit la boite 0
+ \hsize=8cm
+ \dummytext\dummytext
+}
+
+\setbox0=\vtop{\unvbox0 \global\setbox1=\lastbox}
+\setbox1=\hbox{\unhbox1 }
+1) |\box1|
+
+\setbox0=\vtop{\unvbox0 \global\setbox1=\lastbox}
+\setbox1=\hbox{\unhbox1 }
+2) |\box1|
+
+\setbox0=\vtop{\unvbox0 \global\setbox1=\lastbox}
+\setbox1=\hbox{\unhbox1 }
+3) |\box1|
+****************** Fin code ******************
+
+
+****************** Code 427 ******************
+\setbox0=\vbox{\hsize=2.5cm Programmer en TeX est facile}%
+\showboxbreadth=5 \showboxdepth=3 \tracingonline=1
+\showbox0
+****************** Fin code ******************
+
+
+****************** Code 428 ******************
+\newbox\tempbox
+\def\reversebox#1{% affiche le contenu de la boite verticale #1
+ \setbox#1=\vbox{%
+ \unvbox#1% composer la boite #1
+ \unskip\unpenalty% retirer ce qui n'est pas capturable par \lastbox
+ \global\setbox0=\lastbox% la boite 1 devient la dernière ligne
+ }%
+ |\hbox{\unhbox0 }|\par% afficher la boite 1 dans sa largeur d'origine
+ \ifvoidorempty{#1}% si le registre #1 contient une boite vide
+ \relax% ne rien faire
+ {\reversebox{#1}}% sinon, rencommencer
+}
+\def\dummytext{Ceci est un texte sans aucun intérêt dont le seul but est de meubler
+ la page de façon artificielle. }
+\setbox\tempbox=\vbox{% définit la boite 0
+ \hsize=8cm \dummytext\dummytext
+}
+
+\reversebox\tempbox
+****************** Fin code ******************
+
+
+****************** Code 429 ******************
+% compose "Programmation" en largeur 0 dans la boite 0 :
+\zerocompose{0}{Programmation}%
+Boite initiale : \copy0 \par% compose la boite résultante
+\vfuzz=\maxdimen% annule les avertissements pour débordements
+\splittopskip=0pt % ne rajouter aucun espace au sommet de la boite restante
+\setbox1 =\vsplit0 to 0pt % coupe la boite 0 à 0pt
+{% dans un groupe (où la boite 0 sert de brouillon)
+ \setbox0 =\vbox{% affecter à la boite brouillon
+ \unvbox1 % la boite 1 composée dans sa largeur naturelle
+ \unskip\unpenalty% annule ce qui n'est pas une boite
+ \global\setbox2 =\lastbox% affecte globalement la dernière (et unique) ligne
+ % à la boite 1
+ }%
+}% ferme le groupe
+\setbox2=\hbox{\unhbox2}% rend à la boite 2 sa largeur naturelle
+Première ligne = "\box2 "% compose la boite 2
+****************** Fin code ******************
+
+
+****************** Code 430 ******************
+\catcode`@11
+\def\hyphlengths#1#2{%#2 = macro contenant les longueurs de coupures du mot #1
+ \begingroup
+ \zerocompose
+ [\tt% passer en fonte à chasse fixe
+ \setbox\z@\hbox{M}\xdef\ttwidth{\the\wd\z@}% mesurer la largeur des caractères
+ ]\z@{#1}% compose en 0pt dans la boite 0
+ \let#2 = \empty% initialise la macro #2
+ \def\cumul@length{0}% le cumul des longueurs initialisé à 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
+}
+\catcode`\@12
+a) \hyphlengths{programmation}\foo liste = "\foo"\par
+b) \hyphlengths{typographie}\foo liste ="\foo"\par
+c) \hyphlengths{j'entendrai}\foo liste ="\foo"\par
+d) \hyphlengths{vite}\foo liste ="\foo"
+****************** Fin code ******************
+
+
+****************** Code 431 ******************
+\catcode`\@11
+\newcount\brktt@cnt
+\newdimen\brktt@interletter
+\newif\ifline@start% booléen vrai lorsqu'aucun caractère n'est encore affiché
+\newif\if@indivifound% booléen qui sera vrai si un motif spécial est rencontré
+
+\let\breakttB=\breakttA
+
+\def\breakttA@i{%
+ \edef\remaining@chars{% calculer le nombre de caractères restant à placer sur la ligne
+ \numexpr\maxchar@num-\brktt@cnt\relax}%
+ \len@tonextword% calculer dans \next@len le nombre de caractères avant le prochain mot
+ \def\next@hyphlen{0}% initialiser la longueur de coupure possible du mot
+ % si le mot + l'eventuel "-" qui le suit ne rentre pas sur ce qui reste de la ligne
+ \ifnum\numexpr\next@len+\extra@char\relax>\remaining@chars\relax
+ \hyphlengths\next@word\list@hyphlengths% bâtir la liste des longueurs de coupures
+ \unless\ifx\list@hyphlengths\empty% si une coupure est possible
+ \expsecond{\doforeach\xx\in}{\list@hyphlengths}% les examiner toutes
+ {% si la coupure examinée peut loger sur la ligne
+ \unless\ifnum\xx>\remaining@chars\relax%
+ \let\next@hyphlen\xx% la stocker
+ \fi% pour que \next@hyphlen soit maximal
+ }%
+ \fi
+ \fi
+ \ifnum\next@hyphlen>0 % si une coupure est nécessaire et a été trouvée
+ \let\next@len\next@hyphlen% mettre à jour la longueur du mot à placer
+ \fi
+ % si le mot + l'eventuel "-" qui le suit ne peut pas loger sur la ligne en cours
+ \ifnum\numexpr\next@len+\extra@char\relax>\remaining@chars\relax
+ \ifline@start% si c'est le début d'une ligne
+ % avertir l'utilisateur
+ \message{Largeur de composition trop faible pour
+ \unexpanded\expandafter{\next@word}^^J}%
+ % et composer tout de même jusqu'à la fin de la ligne
+ \exparg\print@nchar{\number\numexpr\maxchar@num-\brktt@cnt}%
+ \else% sinon
+ \insert@blankchar*{\maxchar@num-\brktt@cnt}% remplir la ligne
+ \fi
+ \exparg\restart@hbox{\tt@remaintext}% ré-ouvrir une boite
+ \expandafter\breakttA@i% et poursuivre le processus
+ % s'il y a la place pour accueillir ce qui est avant la prochaine coupure
+ \else
+ \ifnum\next@hyphlen>0 % si une coupure de mot doit être faite
+ \exparg\print@nchar{\number\numexpr\next@len-1}% afficher les lettres de la syllabe
+ \print@hyphchar% et le caractère de coupure
+ \insert@blankchar*{\maxchar@num-\brktt@cnt}% remplir la ligne
+ \exparg\restart@hbox{\tt@remaintext}% ré-ouvrir une boite
+ \expandafter\expandafter\expandafter\breakttA@i% et continuer le processus
+ \else% si pas de coupure dans le mot
+ \print@nchar\next@len% afficher le mot
+ \ifx\tt@remaintext\tt@emptytext% si texte restant est vide
+ \insert@blankchar*{\maxchar@num-\brktt@cnt}% remplir la ligne
+ \egroup% fermer la hbox
+ \par% aller à la ligne
+ \endgroup% fermer le groupe ouvert au début. Fin du processus
+ \else% si le texte restant n'est pas vide
+ \ifnum\brktt@cnt<\maxchar@num\relax% si la ligne n'est pas remplie
+ \print@nchar{1}% afficher le caractère qui suit le mot
+ \else% si la ligne est remplie
+ \exparg\restart@hbox{\tt@remaintext}% ferme la hbox et en ré-ouvre une
+ \fi
+ \expandafter\expandafter\expandafter\breakttA@i% enfin, continuer le processus
+ \fi
+ \fi
+ \fi
+}
+
+\def\print@hyphchar{%
+ \advance\brktt@cnt by 1 % augmenter le compteur de caractères
+ \hbox to\ttchar@width{\hss-\hss}% afficher "-"
+ \ifnum\brktt@cnt<\maxchar@num\relax% si la ligne n'est pas encore remplie
+ \kern\brktt@interletter\relax% insérer le ressort inter-lettre
+ \fi
+}
+
+\catcode`\@12
+
+\def\liglist{<<,>>}% liste des motifs de ligature (mettre à, é, etc si codage UTF8)
+\def\ttindent{3}
+
+\vrule\vbox{\breakttB[3pt][8cm]{%
+Dans ce paragraphe, composé en fonte à chasse fixe et où les limites gauche
+et droite du texte ont été tracées, on constate que les caractères sont
+exactement les uns au-dessous d'une ligne à l'autre. Plus aucun débordement
+n'a lieu, car une espace correctement calculée est insérée entre chaque
+caractère. Dorénavant, les mots ne sont plus coupés <<sauvagement>>.
+}%
+}\vrule
+
+\vrule\vbox{\breakttB[1pt][5cm]{%
+Dans ce paragraphe, composé en fonte à chasse fixe et où les limites gauche
+et droite du texte ont été tracées, on constate que les caractères sont
+exactement les uns au-dessous d'une ligne à l'autre. Plus aucun débordement
+n'a lieu, car une espace correctement calculée est insérée entre chaque
+caractère. Dorénavant, les mots ne sont plus coupés <<sauvagement>>.
+}%
+}\vrule
+****************** Fin code ******************
+
+
+****************** Code 432 ******************
+Voici un algorithme élémentaire :
+\algorithm[\#]{Algorithme {\bf MinMax}}|
+macro ~Min_Max~ (#1) % afficher la valeur max et min d'une liste de valeurs #1
+ $V_{max}:=-\infty$ % $-\infty$ ou la plus petite valeur possible
+ $V_{min}:=+\infty$ % $+\infty$ ou la plus grande valeur possible
+ ~Pour~ chaque $x$ dans (#1)
+ ~Si~ $x>V_{max}$
+ ~alors~ $V_{max}:=x$
+ ~FinSi~
+ ~Si~ $x<V_{min}$
+ ~alors~ $V_{min}:=x$
+ ~FinSi~
+ ~FinPour~
+ Afficher "$V_{min}$ et $V_{max}$"
+~FinMin_Max~|
+Suite du texte...
+****************** Fin code ******************
+
+
+****************** Code 433 ******************
+\def\algoindent{1cm}%
+\begingroup
+\parindent=0pt % pas d'indentation
+\defactive\^^M{\leavevmode\par}% rend le retour charriot actif
+\defactive\^^I{\hskip\algoindent\relax}% tabulation active
+Pas d'indentation ici\ldots
+ Voici une première ligne
+ une seconde plus indentée
+ retour à l'indentation normale
+ \for\xx=1to10\do{un long texte }
+ pour terminer, la dernière ligne
+\endgroup
+****************** Fin code ******************
+
+
+****************** Code 434 ******************
+\def\algoindent{1cm}%
+\begingroup
+\leftskip=0pt \rightskip=0pt plus1fil \relax % initialise les ressorts latéraux
+\parindent=0pt % pas d'indentation
+\defactive\^^M{\leavevmode\par\leftskip=0pt }% rend le retour charriot actif
+\defactive\^^I{\advance\leftskip by \algoindent\relax}% tabulation active
+Pas d'indentation ici\ldots
+ Voici une première ligne
+ une seconde plus indentée
+ retour à l'indentation normale
+ \for\xx=1to10\do{un long texte }
+ pour terminer, la dernière ligne
+\endgroup
+****************** Fin code ******************
+
+
+****************** Code 435 ******************
+ % compteur de lignes pour l'algorithme
+\def\algoindent{1cm}%
+\begingroup
+\algocnt=1 % initialise le compteur à 1
+\leftskip=0pt \rightskip=0pt plus1fil\relax% initialise les ressorts à 0pt
+\parindent=0pt % pas d'indentation
+\everypar={\llap{$\scriptstyle\number\algocnt$\kern\dimexpr4pt+\leftskip\relax}}%
+
+\defactive\^^M{\leavevmode\par\advance\algocnt by1 \leftskip=0pt }% retour charriot actif
+\defactive\^^I{\advance\leftskip by \algoindent\relax}% tabulation active
+Pas d'indentation ici\ldots
+ Voici une première ligne
+ une seconde plus indentée
+ retour à l'indentation normale
+ \for\xx=1to10\do{un long texte }
+ pour terminer, la dernière ligne
+\endgroup
+****************** Fin code ******************
+
+
+****************** Code 436 ******************
+\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
+}
+
+\newmacro\algorithm[\\,\#,\{,\}]2{%
+ \medbreak
+ \begingroup% ouvre un groupe (sera fermé à la fin de l'algorithme)
+ \algocnt=1 % initialise le compteur de lignes
+ \leftskip=0pt \rightskip=0pt plus1fil\relax% 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 d'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
+ }%
+ \ifnumalgo% si la numérotation est demandée,
+ \everypar={% définir le \everypar
+ \llap{$\scriptstyle\number\algocnt$\kern\dimexpr4pt+\leftskip\relax}%
+ }%
+ \fi
+ \doforeach\currentchar\in{#1}{\catcode\expandafter`\currentchar=12 }%
+ \def\algocr{% définit ce que fait ^^M
+ \color{black}% repasse en couleur noire
+ \rm% fonte droite
+ \leavevmode\par% termine le paragraphe
+ \advance\algocnt by1 % incrémente le compteur de lignes
+ \leftskip=0pt % initialise le ressort gauche
+ }
+ \letactive\^^M=\algocr%
+ \defactive\^^I{\advance\leftskip by \algoindent\relax}%
+ \defactive\ {\hskip1.25\fontdimen2\font\relax}% espace = 25% de + que
+ % la largeur naturelle
+ \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{}% neutralise le \everypar
+ \par% aller à la ligne
+ \nointerlineskip% ne pas insérer le ressort d'interligne
+ \kern7pt % et sauter 7pt verticalement
+ \nobreak% empêcher une coupure de page
+ \algohrulefill% tracer la ligne de fin
+ \endgroup% ferme le groupe ouvert au début de l'algorithme
+ \smallbreak% saute un petit espace vertical
+ }%
+ %%%%%%%%%%%%%%%%% 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{% a 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\algocr% 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
+}
+
+Voici un algorithme élémentaire
+\algorithm[\#]{Algorithme {\bf MinMax}}|
+macro ~Min_Max~ (#1) % afficher la valeur max et min d'une liste de valeurs #1
+W$V_{max}:=-\infty$ % $-\infty$ ou la plus petite valeur possible
+W$V_{min}:=+\infty$ % $+\infty$ ou la plus grande valeur possible
+W~Pour~ chaque $x$ dans (#1)
+WW~Si~ $x>V_{max}$
+WWW~alors~ $V_{max}:=x$
+WW~FinSi~
+WW~Si~ $x<V_{min}$
+WWW~alors~ $V_{min}:=x$
+WW~FinSi~
+W~FinPour~
+WAfficher "$V_{min}$ et $V_{max}$"
+~FinMin_Max~|
+Suite du texte...
+****************** Fin code ******************
+
+
+****************** Code 437 ******************
+a) \meaning a\par
+b) \meaning {\par
+c) \meaning _\par
+d) \meaning\def\par % une primitive
+e) \meaning\baselineskip\par% une primitive
+f) \long\def\foo#1#2.#3{#1 puis #2 et #3 !}\meaning\foo
+****************** Fin code ******************
+
+
+****************** Code 438 ******************
+\def\foo#1#2{%
+ \def\argA{#1}\show\argA% débogage
+ Bonjour #1 et #2}
+\foo{{\bf X}}{Y}
+****************** Fin code ******************
+
+
+****************** Code 439 ******************
+\def\foo#1#2{%
+ \showtokens{#1}% débogage
+ Bonjour #1 et #2}
+\foo{{\bf X}}{Y}
+****************** Fin code ******************
+
+
+****************** Code 440 ******************
+\newtoks\footoks
+\footoks={foo bar}
+\show\footoks
+****************** Fin code ******************
+
+
+****************** Code 441 ******************
+\showthe\baselineskip% registre-primitive
+\newtoks\footoks \footoks={foo bar} \showthe\footoks
+\newcount\foocount \foocount=987 \showthe\foocount
+\newdimen\foodimen \foodimen=3.14pt \showthe\foodimen
+\newskip\fooskip \fooskip=10 pt plus 1pt minus 1fil \showthe\fooskip
+\newbox\foobox \foobox\hbox{foo} \showthe\foobox
+****************** Fin code ******************
+
+
+****************** Code 442 ******************
+\def\foo#1,#2\endfoo{Bonjour #1 et #2}
+\tracingmacros=1
+\foo moi,toi\endfoo
+\tracingmacros=0
+****************** Fin code ******************
+
+
+****************** Code 443 ******************
+\tracingcommands=2
+Foo \hbox{et \ifnum2>1 bar\else toi\fi}\par
+Suite
+\tracingcommands=0
+****************** Fin code ******************
+
+
+****************** Code 444 ******************
+\def\i{\advance\count255 1 }
+\tracingrestores=1
+\count255=2 {\i\i\i}
+\tracingrestores=0
+****************** Fin code ******************
+
+
+****************** Code 445 ******************
+\def\i{\advance\count255 1 } \def\gi{\global\i}
+\tracingrestores=1
+\count255=2 {\i\i\gi\i\gi\i}
+\tracingrestores=0
+****************** Fin code ******************
+
+
+****************** Code 446 ******************
+\catcode`@11
+\def\ifnodecpart#1{\ifnodecpart@i#1.\@nil}
+\def\ifnodecpart@i#1.#2\@nil{\ifempty{#2}}
+\def\decadd#1#2{% #1 et #2=nombre à additionner
+ \ifnodecpart{#1}% si #1 est un entier
+ {\ifnodecpart{#2}% et #2 aussi, les additionner avec \numexpr
+ {\number\numexpr#1+#2\relax}%
+ {\decadd@i#1.0\@nil#2\@nil}% sinon, ajouter ".0" après #1
+ }
+ {\ifnodecpart{#2}% si #1 a une partie entière mais pas #2
+ {\decadd@i#1\@nil#2.0\@nil}% ajouter ".0" à #2
+ {\decadd@i#1\@nil#2\@nil}% sinon, les 2 parties entières sont présentes
+ }%
+}
+\def\decadd@i#1.#2\@nil#3.#4\@nil{% affiche les parties entières et décimales reçues
+ $x_a=#1\quad y_a=#2\qquad x_b=#3\quad y_b=#4$
+}
+\catcode`@12
+a) \decadd{5}{9.4}\par
+b) \decadd{-3.198}{-6.02}\par
+c) \decadd{0.123}{123}
+****************** Fin code ******************
+
+
+****************** Code 447 ******************
+\def\addzeros#1#2/#3.#4#5/#6.#7/{%
+ Arguments reçus : #1#2/#3.#4#5/#6.#7/\par% afficher ce que la macro reçoit
+ \ifempty{#2}% si #1 est le dernier chiffre de y
+ {\ifempty{#5}% et si #4 est le dernier chiffre de y2
+ {Résultat final : \detokenize{{#3#1}{#6#4}{#70}}}% afficher le résultat final
+ {\addzeros0/#3#1.#5/#6#4.#70/}% sinon alimenter #1 avec un 0
+ }
+ {\ifempty{#5}% si #4 est le dernier chiffre de y2
+ {\addzeros#2/#3#1.0/#6#4.#70/}% alimenter #4 avec un 0
+ {\addzeros#2/#3#1.#5/#6#4.#70/}% #2 et #5 non vides
+ }%
+}
+\addzeros457/.689714/.1/
+****************** Fin code ******************
+
+
+****************** Code 448 ******************
+\catcode`\@11
+\def\addzeros#1#2/#3.#4#5/#6.#7/{%
+ \ifempty{#2}% si #1 est le dernier chiffre de y1
+ {\ifempty{#5}% et si #4 est le dernier chiffre de y2
+ {{#3#1}{#6#4}{#70}}% redonner les 3 arguments
+ {\addzeros0/#3#1.#5/#6#4.#70/}% sinon alimenter #1 avec un 0
+ }
+ {\ifempty{#5}% si #4 est le dernier chiffre de y2
+ {\addzeros#2/#3#1.0/#6#4.#70/}% alimenter #4 avec un 0
+ {\addzeros#2/#3#1.#5/#6#4.#70/}% #2 et #5 non vides
+ }%
+}
+\def\decadd#1#2{% #1 et #2=nombre à additionner
+ \ifnodecpart{#1}
+ {\ifnodecpart{#2}{\number\numexpr#1+#2\relax}{\decadd@i#1.0\@nil#2\@nil}}
+ {\ifnodecpart{#2}{\decadd@i#1\@nil#2.0\@nil}{\decadd@i#1\@nil#2\@nil}}%
+}
+\def\decadd@i#1.#2\@nil#3.#4\@nil{%
+ \expandafter\decadd@ii
+ \romannumeral-`\0\addzeros#2/.#4/.1/% se développe en 3 arguments
+ {#1}
+ {#3}%
+}
+\def\decadd@ii#1#2#3#4#5{%
+% #1 et #2=parties décimales (mêmes longueurs);
+% #3=seuil de retenue; #4 et #5=parties entières
+ \exptwoargs{\decadd@iii{#3}}% envoyer le seuil de retenue tel quel
+ % sommer les parties décimales signées
+ {\number\numexpr\true@sgn{#4}#1+\true@sgn{#5}#2\relax}%
+ % et les parties entières
+ {\number\numexpr#4+#5\relax}%
+}
+\def\decadd@iii#1#2#3{%
+ seuil de retenue = #1 \qquad nombre = "#3"."#2"%
+}
+\catcode`\@12
+a) \decadd{6.7}{3.498}\par
+b) \decadd{1.67}{-4.9}\par
+c) \decadd{3.95}{2.0005}\par
+d) \decadd{1.007}{2.008}\par
+e) \decadd{-7.123}{3.523}
+****************** Fin code ******************
+
+
+****************** Code 449 ******************
+\catcode`\@11
+\def\format@dec#1#2{% #1=partie décimale #2=seuil de retenue
+ \expandafter\gobone% le \gobone agira en dernier,
+ \romannumeral-`\0% mais avant, tout développer
+ \expandafter\reverse\expandafter% et retarder le \reverse de fin
+ % pour développer son argument qui
+ {\number% développe tout et évalue avec \number
+ \expandafter\reverse\expandafter% l'inversion de
+ {\number\numexpr\abs{#1}+#2\relax}% |#1|+#2
+ }%
+}
+a) \format@dec{710}{100000}\par
+b) \format@dec{6}{100}\par
+c) \format@dec{-12300}{1000000}
+\catcode`\@12
+****************** Fin code ******************
+
+
+****************** Code 450 ******************
+\catcode`@11
+\def\true@sgn#1{\ifnum#11<\z@-\fi}
+\def\decadd#1#2{% #1 et #2=nombre à additionner
+ \romannumeral-`\.% tout développer jusqu'à l'affichage du nombre (\decadd@iv)
+ \ifnodecpart{#1}% si #1 est un entier
+ {\ifnodecpart{#2}% et #2 aussi, les additionner avec \numexpr
+ {\numexpr#1+#2\relax}%
+ {\decadd@i#1.0\@nil#2\@nil}% sinon, ajouter ".0" après #1
+ }
+ {\ifnodecpart{#2}% si #1 a une partie entière mais pas #2
+ {\decadd@i#1\@nil#2.0\@nil}% ajouter ".0" à #2
+ {\decadd@i#1\@nil#2\@nil}% sinon, les 2 parties entières sont présentes
+ }%
+}
+\def\decadd@i#1.#2\@nil#3.#4\@nil{%
+ \expandafter\decadd@ii
+ \romannumeral-`\0\addzeros#2/.#4/.10/% se développe en 3 arguments
+ {#1}
+ {#3}%
+}
+\def\decadd@ii#1#2#3#4#5{%
+% #1 et #2=parties décimales (mêmes longueurs)
+% #3=seuil de retenue; #4 et #5=parties entières
+ \exptwoargs{\decadd@iii{#3}}% envoyer le seuil de retenue tel quel
+ % sommer les parties décimales signées
+ {\number\numexpr\true@sgn{#4}#1+\true@sgn{#5}#2\relax}%
+ % et les parties entières
+ {\number\numexpr#4+#5\relax}%
+}
+\def\decadd@iii#1#2#3{% #1=seuil de retenue #2=partie décimale #3= partie entière
+ \ifnum\true@sgn{#2}\true@sgn{\ifnum#3=\z@#2\else#3\fi}1=-1 % si les signes sont
+ % différents
+ \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+ {\exptwoargs\decadd@iv% transmettre les arguments modifiés :
+ {\number\numexpr#3-\true@sgn{#3}1}% #3:=#3-sgn(#3)1
+ {\number\numexpr#2-\true@sgn{#2}#1}% #2:=#2-sgn(#2)10^n
+ {#1}%
+ }% si les signes sont égaux
+ {\ifnum\abs{#2}<#1 % et si abs(y)<10^n
+ \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
+ {\decadd@iv{#3}{#2}{#1}% tranmettre les arguments tels quels
+ }
+ {\exptwoargs\decadd@iv% sinon
+ {\number\numexpr#3+\true@sgn{#3}1}% #3:=#3+sgn(#3)1
+ {\number\numexpr#2-\true@sgn{#2}#1}% #2:=#2-sgn(#2)10^n
+ {#1}%
+ }%
+ }%
+}
+\def\decadd@iv#1#2#3{% affiche le décimal "#1.#2"
+ % le développement maximal initié par le \romannumeral de \decadd est actif
+ \ifnum#1=\z@\ifnum#2<\z@% si #1=0 et #2<0
+ \expandafter\expandafter\expandafter% transmettre le développement à \number
+ -% puis afficher le signe "-"
+ \fi\fi
+ \number#1% affiche #1 qui est la somme des parties entières
+ % poursuivre le développement initié par \number
+ \unless\ifnum#2=\z@% si la partie décimale est différente de 0
+ \antefi% se débarrasser de \fi
+ \expandafter.% afficher le "." décimal après avoir
+ \romannumeral-`\0\format@dec{#2}{#3}% correctement géré les 0 de #2
+ \fi
+}
+\def\addzeros#1#2/#3.#4#5/#6.#7/{%
+ \ifempty{#2}% si #1 est le dernier chiffre de y1
+ {\ifempty{#5}% et si #4 est le dernier chiffre de y2
+ {{#3#1}{#6#4}{#7}}% redonner les 3 arguments
+ {\addzeros0/#3#1.#5/#6#4.#70/}% sinon alimenter #1 avec un 0
+ }
+ {\ifempty{#5}% si #4 est le dernier chiffre de y2
+ {\addzeros#2/#3#1.0/#6#4.#70/}% alimenter #4 avec un 0
+ {\addzeros#2/#3#1.#5/#6#4.#70/}% #2 et #5 non vides
+ }%
+}
+\def\format@dec#1#2{% #1=partie décimale #2=seuil de retenue
+ \expandafter\gobone% le \gobone agira en dernier,
+ \romannumeral-`\0% mais avant, tout développer
+ \expandafter\reverse\expandafter% et retarder le \reverse de fin
+ % pour développer son argument qui
+ {\number% développe tout et évalue avec \number
+ \expandafter\reverse\expandafter% l'inversion de
+ {\number\numexpr\abs{#1}+#2\relax}% abs(#1)+#2
+ }%
+}
+\catcode`@12
+a) $-3.78+1.6987=\decadd{-3.78}{1.6987}$\par
+b) $3.56-3.06=\decadd{3.56}{-3.06}$\par
+c) $4.125+13.49=\decadd{4.125}{13.49}$\par
+d) $-0.99+1.005=\decadd{-0.99}{1.005}$\par
+e) $16.6-19.879=\decadd{16.6}{-19.879}$\par
+f) $5.789-0.698=\decadd{5.789}{-0.698}$\par
+g) $0.123-0.123=\decadd{0.123}{-0.123}$\par
+h) $3.14-16.4912=\decadd{3.14}{-16.4912}$\par
+i) $0.1-0.98=\decadd{0.1}{-0.98}$\par
+j) $2.43+7.57=\decadd{2.43}{7.57}$\par
+h) \edef\foo{\decadd{1.23}{9.78}}\meaning\foo\par
+j) \detokenize\expandafter\expandafter\expandafter{\decadd{3.14}{-8.544}}
+****************** Fin code ******************
+
+
+****************** Code 451 ******************
+a) \pdfstrcmp{foo}{bar}\qquad
+b) \pdfstrcmp{bar}{foo}\qquad
+c) \def\foo{ABC}\pdfstrcmp{\foo}{ABC}\qquad
+d) \edef\foo{\string_}\pdfstrcmp{1_2}{1\foo2}\qquad
+e) \pdfstrcmp{\string\relax}{\relax}
+****************** Fin code ******************
+
+
+****************** Code 452 ******************
+\edef\tempcompil{\number\pdfelapsedtime}%
+Depuis le début de la compilation, il s'est écoulé \tempcompil{} secondes d'échelle,
+soit \convertunit{\tempcompil sp}{pt} secondes.
+****************** Fin code ******************
+
+
+****************** Code 453 ******************
+%%%%%%%%%% definition de \loop...\repeat comme plain-TeX %%%%%%%%%%
+\def\loop#1\repeat{\def\body{#1}\iterate}
+\def\iterate{\body \let\next\iterate \else\let\next\relax\fi \next}
+\let\repeat=\fi
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\newcount\testcnt
+\pdfresettimer% remet le compteur à 0
+ \testcnt=0
+ \loop % Test no 1
+ \ifnum\testcnt<100000 \advance\testcnt 1
+ \repeat
+Temps 1 = \convertunit{\pdfelapsedtime sp}{pt} s (boucle loop de \TeX)\par
+%%%%%%%%%%%% definition de \loop...\repeat comme LaTeX %%%%%%%%%%%%
+\def\loop#1\repeat{\def\iterate{#1\relax\expandafter\iterate\fi}%
+ \iterate \let\iterate\relax}
+\let\repeat\fi
+\pdfresettimer% remet le compteur à 0
+ \testcnt=0
+ \loop % Test no 2
+ \ifnum\testcnt<100000
+ \advance\testcnt 1
+ \repeat
+Temps 2 = \convertunit{\pdfelapsedtime sp}{pt} s (boucle loop de \LaTeX)\par
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\pdfresettimer% remet le compteur à 0
+ \for\ii=1 to 100000\do{}% Test no 3
+Temps 3 = \convertunit{\pdfelapsedtime sp}{pt} s (boucle for)
+****************** Fin code ******************
+
+
+****************** Code 454 ******************
+%%%%%%%%%%%% definition de \loop...\repeat comme LaTeX %%%%%%%%%%%%
+\def\loop#1\repeat{\def\iterate{#1\relax\expandafter\iterate\fi}%
+ \iterate \let\iterate\relax}
+\let\repeat\fi
+\pdfresettimer% remet le compteur à 0
+ \def\ii{0}%
+ \loop % Test no 1
+ \ifnum\ii<100000
+ \edef\ii{\number\numexpr\ii+1\relax}%
+ \repeat
+Temps 1 = \convertunit{\pdfelapsedtime sp}{pt} s (boucle loop de \LaTeX)\par
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\pdfresettimer% remet le compteur à 0
+ \for\ii=1 to 100000\do{}% Test no 2
+Temps 2 = \convertunit{\pdfelapsedtime sp}{pt} s (boucle for)
+****************** Fin code ******************
+
+
+****************** Code 455 ******************
+\newcount\testcnt
+\pdfresettimer
+\testcnt=0
+\for\ii=1 to 100000\do{\advance\testcnt1 }
+Temps 1 : \convertunit{\pdfelapsedtime sp}{pt} s (incrémentation compteur)
+
+\pdfresettimer
+\def\foo{0}%
+\for\ii=1 to 100000\do{\edef\foo{\number\numexpr\foo+1\relax}}%
+Temps 2 : \convertunit{\pdfelapsedtime sp}{pt} s (incrémentation du texte de remplacement)
+****************** Fin code ******************