%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% %% Codes donn�s dans le livre %% %% � Apprendre � programmer en TeX � %% %% %% %% Encodage ISO 8859-1 %% %% _____ %% %% %% %% � 2014-2020 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 ******************