diff options
Diffstat (limited to 'Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/output/progtexcode.txt')
-rw-r--r-- | Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/output/progtexcode.txt | 9712 |
1 files changed, 9712 insertions, 0 deletions
diff --git a/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/output/progtexcode.txt b/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/output/progtexcode.txt new file mode 100644 index 00000000000..fcd1a19ec7c --- /dev/null +++ b/Master/texmf-dist/doc/plain/apprendre-a-programmer-en-tex/output/progtexcode.txt @@ -0,0 +1,9712 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% %% +%% Codes donnés dans le livre %% +%% « Apprendre à programmer en TeX » %% +%% %% +%% Encodage ISO 8859-1 %% +%% _____ %% +%% %% +%% © 2014 Christian Tellechea %% +%% %% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Les codes et les macros commentés donnés dans ce fichier sont diffusés sous +% la licence LaTeX project public license (LPPL) 1.2 +% +% https://www.latex-project.org/lppl/lppl-1-2/ +% https://www.latex-project.org/lppl/lppl-1-2.txt +% +% Attention : ce fichier n'a pas vocation à être compilé +\endinput + + +****************** Code 1 ****************** +Voici le code en \TeX{} du premier exemple.% ceci est un commentaire + +On peut observer l'affichage qu'il produit juste au-dessous ! +****************** Fin code ****************** + + +****************** Code 2 ****************** +3 tailles : $% entre en mode mathématique (espaces ignorés) +1^{2^3}% 2 est en taille "\scriptstyle" et 3 en taille "\scriptscriptstyle" +$% fin du mode math + +normal $1$, petit $\scriptstyle 2$, très petit $\scriptscriptstyle 3$. +****************** Fin code ****************** + + +****************** Code 3 ****************** +%%% comportement normal %%% +a) comportement normal : +Ligne 1 +Ligne 2 + +Ligne 3 +\medbreak +b) Aucun caractère de fin de ligne : +%%% aucune insertion en fin de ligne %%% +\endlinechar=-1 +Ligne 1 +Ligne 2 + +Ligne 3\endlinechar13 + +\medbreak +c) "X" comme caractère de fin de ligne : +%%% "X" est inséré à chaque fin de ligne +\endlinechar=88 +Ligne 1 +Ligne 2 + +Ligne 3 +****************** Fin code ****************** + + +****************** Code 4 ****************** +a) \number"1A \qquad b) \number"AB3FE \qquad c) \number"78 +****************** Fin code ****************** + + +****************** Code 5 ****************** +a) \number'15 \qquad b) \number'674 \qquad c) \number'46 +****************** Fin code ****************** + + +****************** Code 6 ****************** +a) \number`\a \quad %code de caractère de "a" +b) \number`\\ \quad % code de caractère de "\" +c) \number`\$ \quad % code de caractère de "$" +d) \number`\ \quad % code de caractère de l'espace +e) \number`\5 \quad % code de caractère de "5" +f) \number`\{ \quad % code de caractère de l'accolade ouvrante +g) \number`\} % code de caractère de accolade fermante +****************** Fin code ****************** + + +****************** Code 7 ****************** +a) \number\catcode`\a \quad %code de catégorie de "a" +b) \number\catcode`\\ \quad % code de catégorie de "\" +c) \number\catcode`\$ \quad % code de catégorie de "$" +d) \number\catcode`\ \quad % code de catégorie de l'espace +e) \number\catcode`\5 \quad % code de catégorie de "5" +f) \number\catcode`\{ \quad % code de catégorie de l'accolade ouvrante +g) \number\catcode`\} % code de catégorie de accolade fermante +****************** Fin code ****************** + + +****************** Code 8 ****************** +Ici, W est une lettre...\par +\catcode`\W=3 % W devient le signe de bascule en mode math +Wx+y=3W\par +$a+b=cW\par +W2^3=8$\par +\catcode`\W=11 % W redevient une lettre +De nouveau, W est une lettre... +****************** Fin code ****************** + + +****************** Code 9 ****************** +$3+4=7$ \par % $ est la bascule math +\catcode`\$=12 % $ devient un caractère affichable +$ s'affiche sans problème : $\par +\catcode`\$=3 % $ redevient la bascule math +$4+3=7$ +****************** Fin code ****************** + + +****************** Code 10 ****************** +Voici les premiers mots de chaque ligne : + +\catcode`\ =5 % l'espace est déormais de catcode 5 +Cette première ligne sera tronquée... + +La deuxième aussi ! + +Et la dernière également. +\catcode`\ =10 % l'espace reprend son catcode + +Le comportement normal est restauré. +****************** Fin code ****************** + + +****************** Code 11 ****************** +\def\foo{Bonjour}% définit le texte de remplacement de \foo +a) \foo Alice.\qquad% espace ignoré +b) {\foo} Bob.\qquad% espace non ignoré +c) \foo{} Chris.\qquad% espace non ignoré +d) \foo\space Daniel.% \space est remplacé par un espace +****************** Fin code ****************** + + +****************** Code 12 ****************** +\def\startbold{\begingroup \bf} +\def\stopbold{\endgroup} +Voici \startbold du texte en gras\stopbold{} et la suite. +****************** Fin code ****************** + + +****************** Code 13 ****************** +\def\foo{foo} +\begingroup A\aftergroup\foo B\endgroup\par +{A\aftergroup X\aftergroup\foo B} +****************** Fin code ****************** + + +****************** Code 14 ****************** +1) (un {\it cheval})\par% sans correction d'italique +2) (un {\it\aftergroup\/cheval})\par% avec correction d'italique +% on peut définir une macro \itacorr qui effectue automatiquement la correction +\def\itacorr{\it\aftergroup\/} +3) (un {\itacorr cheval})% avec correction d'italique +****************** Fin code ****************** + + +****************** Code 15 ****************** +\def\bar{Je suis bar.} +\let\foo\bar % \foo devient égal à \bar +\def\bar{ABC}% \bar est redéfinie +\foo\par% affiche "Je suis bar" +\bar% affiche "ABC" +****************** Fin code ****************** + + +****************** Code 16 ****************** +Initialement, c'est \TeX.\par +\let\TeXsauve\TeX% sauvegarde +\def\TeX{tEx}% redéfinition +Ici, on a modifié \TeX.\par +\let\TeX\TeXsauve% retauration +De nouveau, c'est \TeX. +****************** Fin code ****************** + + +****************** Code 17 ****************** +\let\sptoken= %2 espaces avant le "%" + +La commande \sptoken compose le paragraphe +****************** Fin code ****************** + + +****************** Code 18 ****************** +{% début du groupe +\catcode`\W=13 \def W{wagons} +Les W constituent le train. +}% fin du groupe +****************** Fin code ****************** + + +****************** Code 19 ****************** +\begingroup \catcode`\W=13 +\gdef\actiw{% + \catcode`\W=13 + \def W{wagons}} +\endgroup +a) Les trains ne sont pas constitués de W !\par +b) \begingroup\actiw Ici, les W forment les trains.\endgroup\par +c) Ici, les W sont redevenus des lettres. +****************** Fin code ****************** + + +****************** Code 20 ****************** +\begingroup + \catcode`\ =13 % rend l'espace actif + \gdef\>{\begingroup + \catcode`\ =13 + \def {\hskip5mm\relax}} +\endgroup +\let\<=\endgroup +a) Du texte normal\par +b) \>Des mots très espacés\<\par +c) Du texte normal +****************** Fin code ****************** + + +****************** Code 21 ****************** +\begingroup + \catcode`\,=13 \def,{\unskip\string,\space\ignorespaces} + La rue assourdissante autour de moi hurlait. + + Longue , mince,en grand deuil , douleur majestueuse , + + Une femme passa ,d'une main fastueuse + + Soulevant,balançant le feston et l'ourlet ; + +\endgroup\medbreak\hfill Charles {\sc Baudelaire} +****************** Fin code ****************** + + +****************** Code 22 ****************** +\begingroup + \catcode`\,=13 \def,{\unskip\string, \ignorespaces} + \catcode`\^^M=13 \let ^^M\par % rend le retour charriot égal à \par + La rue assourdissante autour de moi hurlait. + Longue , mince,en grand deuil , douleur majestueuse , + Une femme passa , d'une main fastueuse + Soulevant,balançant le feston et l'ourlet ; +\endgroup\medbreak\hfill Charles {\sc Baudelaire} +****************** Fin code ****************** + + +****************** Code 23 ****************** +{% ouvre un groupe + \let\AA=a \let\EE=e \let\II=i \let\OO=o \let\UU=u \let\YY=y + % sauvegarder avant de modifier le catcode de a et e : + \let\lEt=\let \let\cAtcOdE=\catcode + \cAtcOdE`\a=13 \lEt a=\EE \cAtcOdE`\e=13 \lEt e=\II + \cAtcOdE`\i=13 \lEt i=\OO \cAtcOdE`\o=13 \lEt o=\UU + \cAtcOdE`\u=13 \lEt u=\YY \cAtcOdE`\y=13 \lEt y=\AA + Ce texte devenu \`a peine reconnaissable montre que le r\'esultat + contient des sonorit\'es catalanes, corses ou grecques assez + inattendues. +}% ferme le groupe +****************** Fin code ****************** + + +****************** Code 24 ****************** +{% + \let\AA=a \let\lEt=\let \let~=\catcode + ~`a=13 \lEt a=e ~`e=13 \lEt e=i ~`i=13 \lEt i=o + ~`o=13 \lEt o=u ~`u=13 \lEt u=y ~`y=13 \lEt y=\AA + Ce texte devenu \`a peine reconnaissable... +} +****************** Fin code ****************** + + +****************** Code 25 ****************** +a) \def\foo{Bonjour}\meaning\foo\par +b) \let\bar=\foo\meaning\bar\par% \foo est "copiée" vers \bar +c) \def\baz{\foo}\meaning\baz\par +d) \catcode`\W=13 \def W{Wagons}% W est un caractère actif + \meaning W\par +e) \meaning\def% \def est une primitive +****************** Fin code ****************** + + +****************** Code 26 ****************** +a) \def\foo{ + +}Signification de \string\foo{} : \meaning\foo + +b) Signification de deux retours charriots consécutifs : \meaning + +****************** Fin code ****************** + + +****************** Code 27 ****************** +a) \meaning\relax\par% primitive +b) \meaning {\par% catcode 1 +c) \meaning }\par% catcode 2 +d) \meaning $\par% catcode 3 +e) \meaning &\par% catcode 4 +g) \meaning #\par% catcode 6 +h) \meaning ^\par% catcode 7 +i) \meaning _\par% catcode 8 +j) \meaning a\par% catcode 11 (une lettre) +k) \meaning +\par% catcode 12 (caractère "autre") +l) \meaning ~\par% catcode 13 (caractère actif) +****************** Fin code ****************** + + +****************** Code 28 ****************** +\begingroup% dans un groupe + \let\*=\meaning% rendre \* égal à \meaning + \* %<- espace pris en compte +\endgroup% fermer le groupe +****************** Fin code ****************** + + +****************** Code 29 ****************** +\begingroup +\catcode`\*0 +\catcode`\\12 % \ n'est plus un caractère d'échappement +*def*foo{bar} +*LaTeX{} et la macro *string*foo : *foo. + +L'ancien caractère d'échappement "\" et \TeX. +*endgroup +****************** Fin code ****************** + + +****************** Code 30 ****************** +\def\foo{\bar} +\begingroup +a) \escapechar=-1 \meaning\foo\qquad% pas de caractère d'échappement +b) \escapechar=`\@ \meaning\foo\qquad% "@" est le caractère d'échappement +\endgroup +c) \meaning\foo% caractère d'échappement par défaut +****************** Fin code ****************** + + +****************** Code 31 ****************** +\begingroup + \catcode`\|=0 |catcode`|\=11 |catcode`|2=11 |catcode`|1=11 + |gdef|1\2\a{foo} +|endgroup +Voici la macro : \csname 1\string\2\string\a\endcsname +****************** Fin code ****************** + + +****************** Code 32 ****************** +\newtoks\foo% allocation d'un nouveau registre +\foo={Bonjour le monde}% assignation +Contenu du registre {\tt\string\foo} : \the\foo. + +\newtoks\bar% allocation d'un autre registre +\bar=\foo% assigne à \bar les tokens du registre \foo +Contenu du registre {\tt\string\bar} : \the\bar. +****************** Fin code ****************** + + +****************** Code 33 ****************** +\def\hello#1#2{Bonjour #1 et #2.\par}% définition +\hello ab% #1=a et #2=b +\hello a b% #1=a et #2=b +\hello{foo}{bar}% #1=foo et #2=bar +\hello foobar% #1=f et #2=o +% (le reste "obar" est lu après que la macro est terminée) +****************** Fin code ****************** + + +****************** Code 34 ****************** +\def\tenlist#1#2#3#4#5#6#7#8#9{(#1,#2,#3,#4,#5,#6,#7,#8,#9\endlist} +\def\endlist#1{,#1)} +Une liste \tenlist abcdefghij de lettres. +****************** Fin code ****************** + + +****************** Code 35 ****************** +\def\foo#1#2{Bonjour #1 et #2.\par} +\begingroup\tt% passer en fonte à chasse fixe +a) \foo{monsieur}{madame} +b) \foo{{\bf toi}}{moi} +c) \foo{}{{}} +d) \foo{ }{ } +e) \foo{$\pi$} {$\delta$} +f) \foo ab +g) \foo X Y +\endgroup% fin de la fonte à chasse fixe +****************** Fin code ****************** + + +****************** Code 36 ****************** +\def\foo{Programmer en \TeX {} est facile} +\meaning\foo\par +\def\foo{Program^^6der en \TeX{} est facile} +\meaning\foo +****************** Fin code ****************** + + +****************** Code 37 ****************** +a) \gobone XY - \secondoftwo XY\par +b) \gobone{ab}{xy} - \secondoftwo{ab}{xy}\par +c) \gobone{123}4 - \secondoftwo{123}4\par +d) \gobone A{BCD} - \secondoftwo A{BCD} +****************** Fin code ****************** + + +****************** Code 38 ****************** +\gobone {a}{\catcode`\~12 Le <<~>> est un espace ?} Et ici <<~>> ? + +\secondoftwo{a}{\catcode`\~12 Le <<~>> est un espace ?} Et ici <<~>> ? +****************** Fin code ****************** + + +****************** Code 39 ****************** +\def\visible{\let\choix=\firstoftwo} +\def\cache{\let\choix=\secondoftwo} +\def\?#1{\choix{#1}{...}}% +\def\interro{J'ai ét\?{é} invit\?{é} à gout\?{er} chez Max. Après s'être + bien amus\?{é}, nous avons rang\?{é} et il a fallu rentr\?{er}.} +Compléter avec << é >> ou << er >> :\par +\cache\interro\par\medskip +Correction :\par +\visible\interro +****************** Fin code ****************** + + +****************** Code 40 ****************** +\def\visible{\let\?=\identity} +\def\cache{\def\?##1{...}} +\def\interro{J'ai ét\?{é} invit\?{é} à goût\?{er} chez Max. On s'est + bien amus\?{é} et ensuite, il a fallu rentr\?{er}.} +Compléter avec << é >> ou << er >> :\par +\cache\interro\par\medskip +Correction :\par +\visible\interro +****************** Fin code ****************** + + +****************** Code 41 ****************** +\def\makemacro#1#2{\def#1##1{##1 #2}} +\makemacro\LL{Lamport} +\makemacro\juin{juin 2014} +Paris, le \juin{3}.\medbreak +\LL{Cher Monsieur},\smallbreak +Vous êtes convoqué à un examen sur \TeX{} le \juin{21} à +9h00 précise dans le bureau de D. Knuth.\smallbreak +Veuillez croire, \LL{Monsieur}, en mes sentiments \TeX iens. +****************** Fin code ****************** + + +****************** Code 42 ****************** +\def\showcodes#1{\string#1 : $\number`#1 \rightarrow \number\lccode`#1$} +\showcodes A\qquad \showcodes B\qquad +\showcodes a\qquad \showcodes b\qquad \showcodes ^ +****************** Fin code ****************** + + +****************** Code 43 ****************** +\lowercase{CACAO foobar}\par +\lowercase{\def\foo{Bonjour}}% définit une commande \foo +\foo % la commande définie précédemment +****************** Fin code ****************** + + +****************** Code 44 ****************** +\begingroup + \lccode`A=`* % change le code minuscule de A + \lowercase{CACAO ABRACADABRA}\par +\endgroup +\lowercase{CACAO ABRACADABRA} +****************** Fin code ****************** + + +****************** Code 45 ****************** +\def\defactive#1{% + \catcode`#1=13 + \begingroup + \lccode`~=`#1 + \lowercase{\endgroup\def~}% +} +\begingroup% les modifications restent locales + \defactive W{wagons}% définit le caractère actif "W" + Les W constituent les trains. +\endgroup %fermeture du groupe, "W" redevient une lettre +\par Les W sont des lettres +****************** Fin code ****************** + + +****************** Code 46 ****************** +\defactive W{wagon} +1) Les W constituent le train.\par +2) \catcode`W=11 Les W sont des lettres.\par +3) \catcode`\W=13 Les W constituent-ils le train ? +****************** Fin code ****************** + + +****************** Code 47 ****************** +\def\defactive#1#2{% + \catcode`#1=13 % #1 sera actif après la fin du texte de remplacement + \begingroup + \lccode`~=`#1 % dans \lowercase, changer les ~ (actifs) en "#1", ceux-ci étant actifs + \lowercase{\endgroup\def~}{#2}% + } +\defactive W{Wagon} +Un W. +****************** Fin code ****************** + + +****************** Code 48 ****************** +\def\defactive#1{% + \catcode`#1=13 % #1 sera actif après la fin du texte de remplacement + \begingroup + \lccode`~=`#1 % dans \lowercase, changer les ~ (actifs) en "#1", ceux-ci étant actifs + \lowercase{\endgroup\def~}% + } +\defactive W{Wagon} +Un W. +****************** Fin code ****************** + + +****************** Code 49 ****************** +\def\defactive#1#2{% + \catcode`#1=13 % #1 sera actif après la fin du texte de remplacement + \begingroup + \uccode`~=`#1 % dans \uppercase, changer les ~ (actifs) en "#1", ceux-ci étant actifs + \uppercase{\endgroup\def~}{#2}% +} +\defactive W{Wagon} +Un W. +****************** Fin code ****************** + + +****************** Code 50 ****************** +\def\letactive#1{% + \catcode`#1=13 % #1 sera actif après la fin du texte de remplacement + \begingroup + \uccode`~=`#1 % dans \uppercase, changer les ~ (actifs) en "#1", ceux-ci étant actifs + \uppercase{\endgroup\let~}% +} +\def\W{wagon}% +\letactive X\W +Un X. +****************** Fin code ****************** + + +****************** Code 51 ****************** +\def\litterate#1{% #1=lit le token frontière choisi + \begingroup% ouvre un groupe pour y faire les modifications + \def\do##1{\catcode`##1=12 }% \do change le catcode de son argument à 12 + \dospecials% rend inoffensifs tous les tokens spéciaux + \defactive\^^M{\leavevmode\par}% définit le retour charriot + \letactive#1\endgroup% définit #1 qui sera un \endgroup + \tt% passe en fonte à chasse fixe +} +essai 1 : \litterate*\foo # #34{ } &_\ * +\medbreak +essai 2 : \litterate/une première ligne ,, >> + +un saut de ligne et la seconde --/ +****************** Fin code ****************** + + +****************** Code 52 ****************** +\def\litterate#1{% #1=lit le token frontière choisi + \begingroup% ouvre un groupe pour y faire les modifications + \def\do##1{\catcode`##1=12 }% \do change le catcode de son argument à 12 + \dospecials% rend inoffensifs tous les tokens spéciaux + \defactive\^^M{\leavevmode\par}% définit le retour charriot + \defactive\ {\ }% l'espace est actif et devient "\ " + \defactive<{\string<{}}\defactive>{\string>{}}% empêche + \defactive-{\string-{}}\defactive`{\string`{}}% les + \defactive,{\string,{}}\defactive'{\string'{}}% ligatures + \letactive#1\endgroup% #1 sera un \endgroup + \tt% passe en fonte à chasse fixe +} +essai 1 : \litterate*\foo # #34{ %} &_\ * +\medbreak +essai 2 : \litterate/une première ligne ,, >> + +un saut de ligne et la seconde --/ +****************** Fin code ****************** + + +****************** Code 53 ****************** +\def\baz#1#2#3#{"#1", puis "#2" et enfin "#3".} +\baz{abc}def{gh}ij +****************** Fin code ****************** + + +****************** Code 54 ****************** +\catcode`\@11 +\long\def\firstto@nil#1#2\@nil{#1} +\long\def\remainto@nil#1#2\@nil{#2} +a) \firstto@nil foobar\@nil \qquad b) \remainto@nil foobar\@nil \par +c) \firstto@nil {foo}bar\@nil \qquad d) \remainto@nil {foo}bar\@nil +****************** Fin code ****************** + + +****************** Code 55 ****************** +\catcode`\@=11 % "@" devient une lettre +\def\rightof#1#2{% + \def\right@of##1#2##2\@nil{##2}% définit la macro auxiliaire + \right@of#1\@nil% appelle la macro auxiliaire où #1 est la <chaine> +} +\catcode`\@=12 %"@" redevient un signe +--\rightof{Programmation}{g}--\par +--\rightof{Programmation}{gram}--\par +--\rightof{Programmation}{on}-- +****************** Fin code ****************** + + +****************** Code 56 ****************** +\catcode`\@=11 % "@" devient une lettre +\def\rightof#1#2{% + \def\right@of##1#2##2\@nil{##2}% définit la macro auxiliaire + \right@of#1\@nil% appelle la macro auxiliaire +} +\catcode`\@=12 %"@" redevient un signe +--\rightof{Programmation}{z}--\par +--\rightof{Programmation}{Gram} +****************** Fin code ****************** + + +****************** Code 57 ****************** +\catcode`\@=11 % "@" devient une lettre +\def\rightof#1#2{% + \def\right@of##1#2##2\@nil{##2}% définit la macro auxiliaire + \right@of#1#2\@nil% appelle la macro auxiliaire avec le motif #2 +} +\catcode`\@=12 %"@" redevient un signe +--\rightof{Programmation}{g}--\par +--\rightof{Programmation}{ti}--\par +--\rightof{Programmation}{z}--\par +--\rightof{Programmation}{Gram}-- +****************** Fin code ****************** + + +****************** Code 58 ****************** +\catcode`\@=11 % "@" devient une lettre +\def\gobto@@nil#1\@@nil{} +\def\rightof#1#2{% + \def\right@of##1#2##2\@nil{##2}% définit la macro auxiliaire + \right@of#1\gobto@@nil#2\gobto@@nil\@@nil\@nil% appelle la macro auxiliaire +} +\catcode`\@=12 %"@" redevient un signe +--\rightof{Programmation}{g}--\par +--\rightof{Programmation}{ti}--\par +--\rightof{Programmation}{z}--\par +--\rightof{Programmation}{Gram}-- +****************** Fin code ****************** + + +****************** Code 59 ****************** +\catcode`\@=11 % "@" devient une lettre + +\def\rightof#1#2{% + \ifin{#1}{#2}% + {% si #1 contient le #2 + \def\right@of##1#2##2\@nil{##2}% définit la macro auxiliaire + \right@of#1\@nil% appelle la macro auxiliaire + }% + {}% sinon, ne rien faire +} +\catcode`\@=12 %"@" redevient un signe +--\rightof{Programmation}{g}--\par +--\rightof{Programmation}{z}--\par +--\rightof{Programmation}{o}-- +****************** Fin code ****************** + + +****************** Code 60 ****************** +\catcode`\@=11 +\def\leftof#1#2{% + \def\leftof@i##1#2##2\@nil{##1}% renvoie ce qui est à gauche de #2 + \leftof@i #1#2\@nil% ajoute #2 après #1 +} +\catcode`\@=12 +--\leftof{Programmation}{ram}--\par +--\leftof{Programmation}{zut}-- +****************** Fin code ****************** + + +****************** Code 61 ****************** +\catcode`\@=11 +\def\leftof#1#2{% + \def\leftof@i##1#2##2\@nil{\leftof@ii##1#1\@nil}% + \def\leftof@ii##1#1##2\@nil{##1}% + \leftof@i #1#2\@nil +} +\catcode`\@=12 +--\leftof{Programmation}{ram}--\par +--\leftof{Programmation}{zut}-- +****************** Fin code ****************** + + +****************** Code 62 ****************** +\catcode`\@=11 +\def\rightof#1#2{% + \def\rightof@i##1#2##2\@nil{\rightof@ii##2#2\@nil}% + \def\rightof@ii##1#2##2\@nil{##1}% + \rightof@i#1#2\@nil +} +\catcode`\@=12 +--\rightof{Programmation}{g}--\par +--\rightof{Programmation}{z}-- +****************** Fin code ****************** + + +****************** Code 63 ****************** +\catcode`\@=11 +\def\gobto@@nil#1\@@nil{} +\def\rightof#1#2{% + \def\right@of##1#2##2\@nil{##2}% définit la macro auxiliaire + \right@of#1\gobto@@nil#2\gobto@@nil\@@nil\@nil% appelle la macro auxiliaire +} +\catcode`\@=12 +\rightof{abc{1}def}{c{1}d}% affiche ce qui est à droite de "c{1}d" +****************** Fin code ****************** + + +****************** Code 64 ****************** +\expandafter\def\csname ab1c\endcsname{Bonjour} +Texte de remplacement de la macro : \csname ab1c\endcsname +****************** Fin code ****************** + + +****************** Code 65 ****************** +\def\defname#1{\expandafter\def\csname#1\endcsname} +\defname{ab1c}{Bonjour} +Texte de remplacement de \litterate|\abc1| : \csname ab1c\endcsname\par +\def\letname#1{\expandafter\let\csname#1\endcsname} +\def\foo{abc}\letname{foo1}=\foo% rend la macro "\foo1" égale à \foo +Texte de remplacement de \litterate|\foo1| : \csname foo1\endcsname +****************** Fin code ****************** + + +****************** Code 66 ****************** + \def\foo{Bonjour}\catcode`@=11 +Résultat : \firstto@nil\foo\@nil +\catcode`@=12 +****************** Fin code ****************** + + +****************** Code 67 ****************** +\def\foo{Bonjour}\catcode`@=11 +Résultat : \expandafter\firstto@nil\foo\@nil +\catcode`@=12 +****************** Fin code ****************** + + +****************** Code 68 ****************** +\newtoks\testtoks \testtoks={Bonjour} +\catcode`@=11 +Résultat : \expandafter\firstto@nil\the\testtoks\@nil +\catcode`@=12 +****************** Fin code ****************** + + +****************** Code 69 ****************** +\def\foo{bonjour} +a) \>\csname foo\endcsname< \par +b) \>\foo< \par +c) \expandafter\>\foo< \par +d) \>\foo\foo< \par +e) \expandafter\>\foo\foo< +****************** Fin code ****************** + + +****************** Code 70 ****************** +\def\foo{Bonjour} \expandafter\>\expandafter\foo\foo< +****************** Fin code ****************** + + +****************** Code 71 ****************** +\def\foo{Bonjour} +\expandafter\def\expandafter\bar\expandafter{\expandafter\foo\foo} +\meaning\bar +****************** Fin code ****************** + + +****************** Code 72 ****************** +\def\foo{\foo Bonjour}% définition récursive +\foo% l'exécution provoque un dépassement de la capacité de la pile +****************** Fin code ****************** + + +****************** Code 73 ****************** +\long\def\addtomacro#1#2{% + \expandafter\def\expandafter#1\expandafter{#1#2}% +} +\def\foo{Bonjour} +\addtomacro\foo{ le monde} +\meaning\foo +****************** Fin code ****************** + + +****************** Code 74 ****************** +\long\def\eaddtomacro#1#2{% + \expandafter\addtomacro\expandafter#1\expandafter{#2}% +} +\def\foo{Bonjour} \def\world{ le monde} +\eaddtomacro\foo\world +\meaning\foo +****************** Fin code ****************** + + +****************** Code 75 ****************** +\long\def\addtotoks#1#2{#1= \expandafter{\the#1#2}} +\newtoks\bar +\bar={Bonjour}% met "Bonjour" dans le registre +\addtotoks\bar{ le monde}% ajoute " le monde" +\the\bar% affiche le registre +****************** Fin code ****************** + + +****************** Code 76 ****************** +\long\def\eaddtotoks#1#2{\expandafter\addtotoks\expandafter#1\expandafter{#2}} +\bar={Bonjour} +\def\macrofoo{ le monde} +\eaddtotoks\bar\macrofoo +\the\bar +****************** Fin code ****************** + + +****************** Code 77 ****************** +\def\X{Bonjour} \def\Y{\X} +\expandafter\expandafter\expandafter\>\Y< +****************** Fin code ****************** + + +****************** Code 78 ****************** +\long\def\swaparg#1#2{#2{#1}} +\long\def\expsecond#1#2{\expandafter\swaparg\expandafter{#2}{#1}} +\def\X{Bonjour} +\expandafter\expandafter\expandafter\expandafter +\expandafter\expandafter\expandafter +\>\expsecond{\X}{\X}< +****************** Fin code ****************** + + +****************** Code 79 ****************** +\expsecond{\def\foo}\secondoftwo{A}{B} +****************** Fin code ****************** + + +****************** Code 80 ****************** +\expsecond{\def\foo}{\secondoftwo{A}{B}} +\meaning\foo +****************** Fin code ****************** + + +****************** Code 81 ****************** +\def\exptwoargs#1#2{\expsecond{\expsecond{#1}{#2}}} +\def\foo{Bonjour}\def\bar{ le monde} +\def\displaytwoargs#1#2{\detokenize{#1#2}}% affiche tels quels les arguments +\exptwoargs\displaytwoargs\foo\bar +****************** Fin code ****************** + + +****************** Code 82 ****************** +\def\aa{Bonjour}\def\bb{\aa} +\def\cc{ le monde} +\edef\foo{\bb\cc} +\meaning\foo +****************** Fin code ****************** + + +****************** Code 83 ****************** +\def\aa{Bonjour } \def\bb{\aa} \def\cc{le } \def\dd{ monde} +\edef\ee#1{\bb\cc#1 !!!} +\meaning\ee\par +\expandafter\>\ee{\dd}< +****************** Fin code ****************** + + +****************** Code 84 ****************** +\def\foo{123xyz} +a) signification du 1-développement d'un \litterate-\noexpand- : + \expandafter\meaning\noexpand\foo + +b) exécution d'un \litterate-\noexpand- : \noexpand\foo% identique à \relax + +c) 1-développement de \litterate-\noexpand- dans le texte de remplacement de + \litterate-\bar- : + \expandafter\def\expandafter\bar\expandafter{\noexpand\foo} + \meaning\bar +****************** Fin code ****************** + + +****************** Code 85 ****************** +\def\aa{Bonjour}\def\bb{\aa}\def\cc{\bb} +a) \edef\foo{\aa\noexpand\bb\cc}\meaning\foo \qquad b) exécution : \foo\par +c) \edef\foo{\aa\noexpand{\aa\cc}}\meaning\foo\qquad d) exécution : \foo +****************** Fin code ****************** + + +****************** Code 86 ****************** +\def\aa{Bonjour}\def\bb{Au revoir} +a) \edef\truc{\aa\noexpand\bb\noexpand\aa\bb}\meaning\truc \par +b) \edef\truc{\aa\unexpanded{\bb\aa}\bb}\meaning\truc +****************** Fin code ****************** + + +****************** Code 87 ****************** +\def\aa{Bonjour}\def\bb{Au revoir} +\toks0={\aa\bb} +\edef\foo{\aa\the\toks0 \bb} +\meaning\foo +****************** Fin code ****************** + + +****************** Code 88 ****************** +\def\aa{Bonjour} +\protected\def\bb{ le}% \ bb est protégée ! +\def\cc{ monde} + +\edef\foo{\aa\bb\cc} +Signification de \string\foo~: \meaning\foo \par +Exécution de \string\foo~: \foo +****************** Fin code ****************** + + +****************** Code 89 ****************** +\def\aa{Bonjour} +\protected\def\bb{ le} +\def\cc{ monde} + +\edef\foo{\expandafter\aa\bb\cc}% le \expandafter 1-développe \bb +\meaning\foo +****************** Fin code ****************** + + +****************** Code 90 ****************** +\def\foo{Bonjour}% définition +\foo% exécution +****************** Fin code ****************** + + +****************** Code 91 ****************** +\def\foo{abc} +\edef\bar{\def\foo{Bonjour}\foo} +\meaning\bar +****************** Fin code ****************** + + +****************** Code 92 ****************** +\def\foo{abc} +\edef\bar{\def\noexpand\foo{Bonjour}\noexpand\foo} +Signification : \meaning\bar\par +Exécution : \bar +****************** Fin code ****************** + + +****************** Code 93 ****************** +\long\def\>#1<{\detokenize{#1}} +\expandafter\>% provoque le 1-développement de : +\csname foo\expandafter\endcsname +\csname bar\expandafter\endcsname +\csname wee\expandafter\endcsname +\csname fin\endcsname< +****************** Fin code ****************** + + +****************** Code 94 ****************** +\long\def\>#1<{\detokenize{#1}} +\def\fin{YY} \def\wee{\weeA} \def\weeA{XX} +\expandafter\>% +\csname foo\expandafter\endcsname +\csname bar\expandafter\expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\endcsname +\csname wee\expandafter\expandafter\expandafter\endcsname +\csname fin\endcsname< +****************** Fin code ****************** + + +****************** Code 95 ****************** +\long\def\>#1<{\detokenize{#1}} +\def\fin{YYY} \def\wee{\weeA} \def\weeA{XXX} +\expandafter\expandafter\expandafter\expandafter +\expandafter\expandafter\expandafter +\>% +\expandafter\expandafter\expandafter\expandafter +\expandafter\expandafter\expandafter +\foo +\expandafter\expandafter\expandafter\expandafter +\expandafter\expandafter\expandafter +\bar +\expandafter\wee\fin< +****************** Fin code ****************** + + +****************** Code 96 ****************** +\chardef\foo65 +a) |\foo|\qquad % employée seule, \foo affiche un A +b) |\number\foo|\qquad % si TeX lit un nombre, \foo est le nombre 65 +****************** Fin code ****************** + + +****************** Code 97 ****************** +\mathchardef\foo4944 +a) |$\foo$|\qquad % en mode math, affiche le signe "somme" (uniquement en mode maths) +b) |\number\foo|\qquad % si TeX lit un nombre, \foo est 4944 +****************** Fin code ****************** + + +****************** Code 98 ****************** +a) "\romannumeral 27 "\quad +b) "\romannumeral 4687 "\quad +c) "\romannumeral 0 "\quad% 0 donc développement vide +d) "\romannumeral -2014 "\quad% négatif donc développement vide +e) \def\foo{7}\def\bar{\foo}% + "\romannumeral \foo\foo\bar"\quad% 777 +f) "\romannumeral 1\bar8\foo"\quad% 1787 +g) "\romannumeral 1\bar8 \foo"% 178 (stoppé par l'espace) puis 7 +****************** Fin code ****************** + + +****************** Code 99 ****************** +\long\def\>#1<{\detokenize{#1}} +\def\swaparg#1#2{#2{#1}} +\def\expsecond#1#2{\expandafter\swaparg\expandafter{#2}{#1}} +\def\X{Bonjour} +\expandafter\expandafter\expandafter\expandafter +\expandafter\expandafter\expandafter +\>\expsecond\X\X< +****************** Fin code ****************** + + +****************** Code 100 ****************** +\long\def\>#1<{\detokenize{#1}} +\def\swaparg#1#2{0 #2{#1}}% le "0 " stoppe ici le développement maximal +\def\expsecond#1#2{\expandafter\swaparg\expandafter{#2}{#1}} +\def\X{Bonjour} +\expandafter\>\romannumeral\expsecond\X\X< +****************** Fin code ****************** + + +****************** Code 101 ****************** +\long\def\>#1<{\detokenize{#1}} +\def\swaparg#1#2{#2{#1}} +\def\expsecond#1#2{\expandafter\swaparg\expandafter{#2}{#1}} +\def\X{Bonjour} +\expandafter\>\romannumeral\expsecond{0 \X}\X< +****************** Fin code ****************** + + +****************** Code 102 ****************** +\long\def\>#1<{\detokenize{#1}} +\def\X{Bonjour} +\catcode`\@=11 +\expandafter\>\romannumeral\expsecond{\z@\X}{\X}< +\catcode`\@=12 +****************** Fin code ****************** + + +****************** Code 103 ****************** +\def\newunivar#1{\def#1[##1]{\csname\string#1[##1]\endcsname}} +\def\defunivar#1[#2]{\defname{\string#1[#2]}} +\newunivar\foobar +\defunivar\foobar[0]{abcd} +\defunivar\foobar[1]{1 23} +\defunivar\foobar[3]{XY Z} +Cellule 0 : \foobar[0]\par +Cellule 1 : \foobar[1]\par +Cellule 2 : \foobar[2]\par% cellule non définie : \foobar[2] donne \relax +Cellule 3 : \foobar[3]\bigbreak + +\newunivar\client +\defunivar\client[nom]{M. Raymond {\sc Tartempion}} +\defunivar\client[adr]{5 rue de la paix} +\defunivar\client[cod_post]{75000} +\defunivar\client[ville]{Paris} +% fin des définitions, affichage de l'adresse : +\client[nom]\par +\client[adr]\par +\client[cod_post] \client[ville] +****************** Fin code ****************** + + +****************** Code 104 ****************** +\newcount\foo \newcount\bar +\foo=42 \bar=\foo \string\bar\ vaut : \the\bar \par +\bar=\foo57 \string\bar\ vaut : \number\bar\par +\bar=2014 \string\bar\ vaut : \romannumeral\bar +****************** Fin code ****************** + + +****************** Code 105 ****************** +\newcount\foo +\def\fonction#1{% + \foo=#1 % assigne l'entier #1 au compteur puis + \multiply\foo3 % multiplie par 3 + \advance\foo-4 % soustrait 4 + \multiply\foo\foo% élève au carré (lmultiplie \foo par lui même) + \number\foo% enfin, afficher le résultat +} +a) \fonction5\qquad b) \fonction{-13} +****************** Fin code ****************** + + +****************** Code 106 ****************** +\newcount\foo +\def\fonction#1{% + \foo=#1 \multiply\foo3 \advance\foo-4 \multiply\foo\foo + \number\foo} +\edef\bar{\fonction{5}}% +a) Signification : \meaning\bar\par +b) Exécution : \bar +****************** Fin code ****************** + + +****************** Code 107 ****************** +a) \number\numexpr2+3*4\relax\qquad +b) \romannumeral\numexpr2*3\relax\qquad +c) \number\numexpr(6-2*4)*(1-(2-6))\relax\qquad +d) \number\numexpr7/4\relax\qquad %7/4 vaut 1,75 +e) \edef\foo{\number\numexpr2+3*4\relax}\meaning\foo +****************** Fin code ****************** + + +****************** Code 108 ****************** +\number\numexpr3*\numexpr1+2*5\relax+2\relax +****************** Fin code ****************** + + +****************** Code 109 ****************** +\def\fonction#1{\number\numexpr(3*#1-4)*(3*#1-4)\relax} +a) \fonction5\qquad +b) \fonction{-13}\qquad +c) \edef\bar{\fonction5}\meaning\bar +****************** Fin code ****************** + + +****************** Code 110 ****************** +\def\fonction#1{\exparg\carre{\number\numexpr3*#1-4\relax}} +\def\carre#1{\number\numexpr#1*#1\relax} +a) \fonction{5}\qquad +b) \fonction{-13}\qquad +c) \edef\bar{\fonction5}\meaning\bar +****************** Fin code ****************** + + +****************** Code 111 ****************** +\def\truncdiv#1#2{\numexpr(#1-(#2-1)/2)/#2\relax} +8/3 : +a) \number\truncdiv83\qquad % doit donner 2 +b) \number\truncdiv{-8}3\qquad % doit donner -2 +c) \number\truncdiv8{-3}\qquad % doit donner -2 +d) \number\truncdiv{-8}{-3}\par % doit donner 2 +4/3 : +e) \number\truncdiv43\qquad % doit donner 1 +f) \number\truncdiv{-4}3\qquad % doit donner -1 +g) \number\truncdiv4{-3}\qquad % doit donner -1 +h) \number\truncdiv{-4}{-3} % doit donner 1 +****************** Fin code ****************** + + +****************** Code 112 ****************** +a) \ifnum 15=14 vrai\else faux\fi\qquad% test faux +b) \ifnum4<200 vrai\else faux\fi\qquad% test vrai +c) \newcount\foo \foo=9 + \ifnum\foo>9 nombre\else chiffre\fi% test faux +****************** Fin code ****************** + + +****************** Code 113 ****************** +\long\def\>#1<{\detokenize{#1}} +\expandafter\>\ifnum5=5 vrai\else faux\fi<\par% test vrai +\expandafter\>\ifnum5=6 vrai\else faux\fi<% test faux +\fi\fi% rétablir l'équilibre \ifnum et \fi +****************** Fin code ****************** + + +****************** Code 114 ****************** +\def\numtest#1{% + \ifnum#1>-10 + \ifnum#1<10 + chiffre% + \else + nombre positif% + \fi + \else + nombre négatif% + \fi +} +a) \numtest{3}\qquad +b) \numtest{-67}\qquad +c) \numtest{-8}\qquad +d) \numtest{21}\qquad +e) \edef\foo{\numtest{2014}}\meaning\foo +****************** Fin code ****************** + + +****************** Code 115 ****************** +\def\normalise#1{% + \ifnum#1>-1 % ne faire quelque chose que si #1 est positif ou nul + \ifnum#1<100 % si <100 + 0% afficher un 0 + \ifnum#1<10 % si <10 + 0%afficher un autre 0 + \fi + \fi + \number#1 %afficher le nombre + \fi}% affiche le nombre +a) \normalise{749}\qquad +b) \normalise{0017}\qquad +c) \normalise8\qquad +d) \normalise{1789}\qquad +e) \normalise{-18}\qquad +f) \normalise{0} +****************** Fin code ****************** + + +****************** Code 116 ****************** +\def\mois#1{% + \ifcase#1\relax + \char`\#\char`\#% afficher "##" si argument = 0 + \or janvier\or f\'evrier\or mars\or avril% + \or mai\or juin\or juillet\or aout% + \or septembre\or octobre\or novembre\or d\'ecembre% + \else + \char`\#\char`\#% afficher "##" sinon + \fi +} +a) \mois{-4}\qquad +b) \mois{3}\qquad +c) \mois{11}\qquad +d) \mois{20}\qquad +e) \edef\foo{\mois{\month}}\meaning\foo% mois en cours +****************** Fin code ****************** + + +****************** Code 117 ****************** +\def\ifletter#1#2#3{% + \ifnum`#1<`a% si le caractère est avant "a" + #3% exécuter "<code faux>" + \else% sinon + \ifnum`#1>`z% si le caractère est après "z" + #3% exécuter "<code faux>" + \else% dans tous les autres cas + #2% "#1" est une lettre : exécuter "<code vrai>" + \fi + \fi} +a) \ifletter{4}{vrai}{faux}\qquad +b) \ifletter{t}{vrai}{faux}\qquad +c) \ifletter{D}{vrai}{faux} +****************** Fin code ****************** + + +****************** Code 118 ****************** +\def\ifletter#1{% + \ifnum`#1<`a + \expandafter\secondoftwo% \expandafter 1-développe "\else...\fi" + \else + \ifnum`#1>`z + \expandafter\expandafter\expandafter% 1-développe "\else...\fi" puis "\fi" + \secondoftwo + \else + \expandafter\expandafter\expandafter%1-développe "\fi" puis "\fi" + \firstoftwo + \fi + \fi} +a) \ifletter{4}{vrai}{faux}\qquad +b) \ifletter{t}{vrai}{faux}\qquad +c) \ifletter{D}{vrai}{faux} +****************** Fin code ****************** + + +****************** Code 119 ****************** +\def\ifletter#1#2#3{% + \romannumeral % <- initie le développement maximal + \ifnum`#1<`a + \expandafter\secondoftwo + \else + \ifnum`#1>`z + \expandafter\expandafter\expandafter\secondoftwo + \else + \expandafter\expandafter\expandafter\firstoftwo + \fi + \fi{0 #2}{0 #3}% <- "0 " stoppe le développement maximal +} +\long\def\>#1<{\detokenize{#1}} +a) \expandafter\expandafter\expandafter\>\ifletter{0}{vrai}{faux}<\qquad +b) \expandafter\expandafter\expandafter\>\ifletter{x}{vrai}{faux}< +****************** Fin code ****************** + + +****************** Code 120 ****************** +\def\ifletter#1{% + \ifnum`#1<`a + \let\donext=\secondoftwo + \else + \ifnum`#1>`z + \let\donext=\secondoftwo + \else + \let\donext=\firstoftwo + \fi + \fi + \donext% exécuter l'action décidée ci-dessus +} +a) \ifletter{4}{vrai}{faux}\qquad +b) \ifletter{t}{vrai}{faux}\qquad +c) \ifletter{D}{vrai}{faux} +****************** Fin code ****************** + + +****************** Code 121 ****************** +\def\ifletter#1{% + \csname + \ifnum`#1<`a + second% <- commenter la fin de ligne pour éviter un + \else% espace parasite dans le nom de la macro créée + \ifnum`#1>`z + second% + \else + first% + \fi + \fi + oftwo% + \endcsname +} +a) \ifletter{4}{vrai}{faux}\qquad +b) \ifletter{t}{vrai}{faux}\qquad +c) \ifletter{D}{vrai}{faux} +****************** Fin code ****************** + + +****************** Code 122 ****************** +\def\ifletter#1{% + \lowercase{\csname + \ifnum`#1<`a second% + \else + \ifnum`#1>`z second\else first\fi + \fi + oftwo\endcsname + }% +} +a) \ifletter{4}{vrai}{faux}\qquad +b) \ifletter{t}{vrai}{faux}\qquad +c) \ifletter{D}{vrai}{faux} +****************** Fin code ****************** + + +****************** Code 123 ****************** +\edef\foo{\lowercase{AbCd}}\meaning\foo +****************** Fin code ****************** + + +****************** Code 124 ****************** +\def\ifletter#1{% + \csname + \ifnum`#1<`A second% + \else + \ifnum`#1<`Z first% + \else + \ifnum`#1>`a + \ifnum`#1<`z + first% + \else + second% + \fi + \else + second% + \fi + \fi + \fi + oftwo% + \endcsname +} +a) \ifletter{4}{vrai}{faux}\qquad +b) \ifletter{t}{vrai}{faux}\qquad +c) \ifletter{D}{vrai}{faux}\qquad +d) \edef\foo{\ifletter{x}{vrai}{faux}}\meaning\foo\qquad +e) \edef\foo{\ifletter{=}{vrai}{faux}}\meaning\foo +****************** Fin code ****************** + + +****************** Code 125 ****************** +\def\ifinside#1[#2,#3]{% + \csname + \ifnum#1<#2 second% si n<a, <code faux> + \else + \ifnum#1>#3 second% si n>b, <code faux> + \else first% sinon, <code vrai> + \fi + \fi + oftwo% + \endcsname +} +a) \ifinside 3[1,8]{oui}{non}\qquad +b) \ifinside -7[-20,-11]{oui}{non}\qquad +c) \ifinside 9[0,6]{oui}{non}\qquad +d) \ifinside -1[-5,1]{oui}{non} +****************** Fin code ****************** + + +****************** Code 126 ****************** +\def\ifinside#1[#2,#3]{% + \ifnum\numexpr(#1-#2)*(#1-#3)\relax>0 + \expandafter\secondoftwo + \else + \expandafter\firstoftwo + \fi +} +a) \ifinside 3[1,8]{oui}{non}\qquad +b) \ifinside -7[-20,-11]{oui}{non}\qquad +c) \ifinside 9[0,6]{oui}{non}\qquad +d) \ifinside -1[-5,1]{oui}{non} +****************** Fin code ****************** + + +****************** Code 127 ****************** +\def\absval#1{% + \ifnum#1<0 \number-#1 + \else \number#1 + \fi} +a) \absval{-87}\qquad b) \absval{75}\qquad c) \absval{0} +****************** Fin code ****************** + + +****************** Code 128 ****************** +\def\absval#1{\number\ifnum#1<0 -\fi#1 } +a) \absval{-87}\qquad b) \absval{75}\qquad c) \absval{0} +****************** Fin code ****************** + + +****************** Code 129 ****************** +\def\absval#1{\number\ifnum\numexpr#1\relax<0 -\fi\numexpr#1\relax} +a) \absval{-87}\qquad +b) \absval{75}\qquad +c) \absval{0}\qquad +d) \absval{-20+13}\qquad% -7 affiché 7 +e) \absval{5-3*(-4)+10-50}% -23 affiché 23 +****************** Fin code ****************** + + +****************** Code 130 ****************** +\catcode`\@11 +\def\absval#1{\exparg\absval@i{\number\numexpr#1\relax}} +\def\absval@i#1{\number\ifnum#1<\z@-\fi#1 } +\catcode`\@12 +a) \absval{-87}\qquad +b) \absval{75}\qquad +c) \absval{0}\qquad +d) \absval{-20+13}\qquad% résultat -7 qui est affiché 7 +e) \absval{5-3*(-4)+10-50}% résultat -23 qui est affiché 23 +****************** Fin code ****************** + + +****************** Code 131 ****************** +\def\sgn#1{\ifnum#1<0 -\fi} +\def\truncdiv#1#2{% + \numexpr + \sgn{#1}\sgn{#2}1*% multiplie le quotient ci-dessous par +1 ou -1 + (2*\absval{#1}-\absval{#2}+1)/(2*\absval{#2}) + \relax +} +a) \number\truncdiv{-8}3\qquad +b) \number\truncdiv{-8}{-3}\qquad +c) \number\truncdiv8{-3}\qquad +d) \number\truncdiv{0}{-5} +****************** Fin code ****************** + + +****************** Code 132 ****************** +\catcode`\@11 +\def\sgn#1{\ifnum#1<\z@-\fi} +\def\truncdiv#1#2{% + \exptwoargs\truncdiv@i{\number\numexpr#1\relax}{\number\numexpr#2\relax}% +} +\def\truncdiv@i#1#2{% + \numexpr(2*\sgn{#1}#1-\sgn{#2}#2+1)/(\sgn{#1}2*#2)\relax +} +\catcode`\@12 +a) \number\truncdiv{-8}3\qquad +b) \number\truncdiv{-8}{-3}\qquad +c) \number\truncdiv8{-3}\qquad +d) \number\truncdiv{0}{-5}\qquad +e) \number\truncdiv{20+2*3}{4-5*2}% 26/(-6) doit donner -4 +****************** Fin code ****************** + + +****************** Code 133 ****************** +\def\siecle#1{% + \unless\ifnum#1=0 % ne faire quelque chose que si #1 différent de 0 + \uppercase\expandafter{\romannumeral\absval{#1}}% chiffres romains majuscules + \raise 1ex \hbox{e\ifnum\absval{#1}=1 r\fi} siècle% affiche l'exposant puis "siècle" + \ifnum#1<0 {} av. J.-C.\fi% affiche si besoin "av. J.-C." + \fi +} +a) \siecle{19}\qquad +b) \siecle{-3}\qquad +c) \siecle{1}\qquad +d) \siecle{0}\qquad +e) \siecle{-1} +****************** Fin code ****************** + + +****************** Code 134 ****************** +\catcode`\@11 +\edef\saved@catcode{\number\catcode`\:}% sauvegarde du catcode de ":" +\catcode`\:12 % ":" est désormais un caractère non actif normal +\def\hdif{% + \begingroup% ouvrir un groupe semi-simple + \catcode`\:12 % modifier le catcode de ":" + \hdif@i% aller lire les deux arguments +} + +\def\hdif@i#1#2{% lit les 2 arguments + \hdif@ii#1-#2\@nil% et les transmet à la macro à argument délimités +} + +\def\hdif@ii#1:#2:#3-#4:#5:#6\@nil{% + %%%%%% calcul des nombres à afficher %%%%%% + \edef\nb@hrs{\number\numexpr#1-#4\relax}% différence des heures + \edef\nb@min{\number\numexpr#2-#5\relax}% différence des minutes + \edef\nb@sec{\number\numexpr#3-#6\relax}% différence des secondes + \ifnum\nb@sec<\z@ % si la différence des secondes est <0 + \edef\nb@sec{\number\numexpr\nb@sec+60\relax}% ajouter 60 sec + \edef\nb@min{\number\numexpr\nb@min-1\relax}% enlever 1 aux minutes + \fi + \ifnum\nb@min<\z@ % si les minutes sont <0 + \edef\nb@min{\number\numexpr\nb@min+60\relax}% ajouter 60 min + \edef\nb@hrs{\number\numexpr\nb@hrs-1\relax}% enlever 1 aux heures + \fi + %%%%%% affichage du résultat %%%%%% + \let\inter@space\empty% pas d'espace avant un nombre pour l'instant + \ifnum\nb@hrs>\z@ % si les heures sont >0 + \nb@hrs h% afficher les heures et "h" + \let\inter@space\space% espace pour plus tard + \fi + \ifnum\nb@min>\z@ % si les minutes sont >0 + \inter@space% afficher une espace éventuelle + \nb@min min% afficher les minutes et "min" + \let\inter@space\space + \fi + \ifnum\nb@sec>\z@ % si les secondes sont >0 + \inter@space% afficher une espace éventuelle + \nb@sec s% afficher les secondes et "s" + \fi + \endgroup% fermer le groupe ouvert au début +} +\catcode`\:=\saved@catcode\relax% restaure le code de catégorie de ":" +\catcode`\@12 +a) \hdif{10:51:20}{9:20:10}\par +b) \hdif{14:20:0}{13:50:0}\par +c) \hdif{7:50:20}{5:50:20}\par +d) \hdif{7:50:10}{6:50:20}\par +e) \hdif{20:00:00}{19:59:15}\par +f) \hdif{17:13:15}{14:12:45} +****************** Fin code ****************** + + +****************** Code 135 ****************** +\newcount\ii +\catcode`\@=11 +\def\ncar#1#2{% + \ii=0 % initialise le compteur à 0 + \def\val@max{#1}% stocke la valeur maximale + \def\car@save{#2}% stocke le caractère à afficher + \ncar@i% appelle la macro récursive +} +\def\ncar@i{% + \ifnum\ii<\val@max% si la valeur maxi n'est pas atteinte + \car@save% afficher le caractère + \advance\ii 1 % incrémenter le compteur + \ncar@i% recommencer + \fi +} +\catcode`\@=12 +\ncar{7}{*}\par +\ncar{13}W\par +\ncar{10}{foobar } +****************** Fin code ****************** + + +****************** Code 136 ****************** +\newcount\ii +\catcode`\@=11 +\def\ncar#1#2{% + \ii=0 % initialise le compteur à 0 + \def\val@max{#1}% stocke la valeur maximale + \def\car@save{#2}% stocke le caractère à afficher + \ncar@i% appelle la macro récursive +} +\def\ncar@i{% + \ifnum\ii<\val@max% si la valeur maxi n'est pas atteinte + \car@save% afficher le caractère + \advance\ii 1 % incrémenter le compteur + \ncar@i% recommencer + \fi +} +\catcode`\@=12 +\ncar{2}{3a} +****************** Fin code ****************** + + +****************** Code 137 ****************** +a) \romannumeral 9600 \qquad b) \romannumeral 12000 +****************** Fin code ****************** + + +****************** Code 138 ****************** +\def\ncar#1#2{% + \begingroup + \lccode`\m=`#2 % dans \lowercase, les "m" deviennent des "#2" + \lowercase\expandafter{\expandafter\endgroup\romannumeral#1000 }% +} +a) \ncar{7}{*}\qquad +b) \ncar{15}{\%}\qquad +c) \ncar{10}{4} +****************** Fin code ****************** + + +****************** Code 139 ****************** +\def\ncar#1#2{% + \ifnum#1>0 % <- espace après le "0" + #2% affiche le caractère + \exparg\ncar{\number\numexpr#1-1}{#2}% appel récursif + \fi +} +a) \ncar{7}{*}\qquad +b) \ncar{13}{W}\qquad +c) \edef\foo{\ncar{5}{7}}\meaning\foo +****************** Fin code ****************** + + +****************** Code 140 ****************** +\def\ncar#1#2{% + \ifnum#1>0 \expandafter\identity% si #1>0 exécuter... + \else \expandafter\gobone% ...sinon manger + \fi% ce qui est entre ces accolades : + {#2% afficher le caractère + \exparg\ncar{\number\numexpr#1-1}{#2}% appel récursif + }% +} +a) \ncar{7}{*}\qquad +b) \ncar{13}{W}\qquad +c) \edef\foo{\ncar{5}X}\meaning\foo +****************** Fin code ****************** + + +****************** Code 141 ****************** +\long\def\antefi#1\fi{\fi#1} +\def\ncar#1#2{% + \ifnum#1>0 + \antefi% comme si le \fi était "déplacé" ici + #2% affiche le caractère + \exparg\ncar{\number\numexpr#1-1}{#2}% appel récursif + \fi +} +a) \ncar{7}{*}\qquad +b) \ncar{13}{W}\qquad +c) \edef\foo{\ncar{5}X}\meaning\foo +****************** Fin code ****************** + + +****************** Code 142 ****************** +\long\def\afterfi#1#2\fi{#2\fi#1} +\def\ncar#1#2{% + \ifnum#1>0 + \afterfi{\exparg\ncar{\number\numexpr#1-1}{#2}}% <- argument renvoyé après le \fi + #2% <- ceci reste avant le \fi + \fi +} +a) \ncar{7}{*}\qquad +b) \ncar{13}{W}\qquad +c) \edef\foo{\ncar{5}X}\meaning\foo +****************** Fin code ****************** + + +****************** Code 143 ****************** +\def\ncar#1#2{% + \ifnum#1>0 + #2% afficher le caractère + \expandafter\ncar\expandafter% le pont d'\expandafter lance \number et \numexpr + {\number\numexpr#1-1\expandafter}% le dernier \expandafter mange "\else...\fi" + \else + \expandafter\gobone% si le test est faux, manger {#2} ci-dessous + \fi{#2}% +} +a) \ncar{7}{*}\qquad +b) \ncar{13}{W}\qquad +c) \edef\foo{\ncar{5}X}\meaning\foo +****************** Fin code ****************** + + +****************** Code 144 ****************** +\catcode`\@11 +\def\ncar#1#2{% + \def\ncar@i##1{% + \ifnum##1<#1 % si i < valeur maxi + #2% afficher le caractère + \exparg\ncar@i{\number\numexpr##1+1\expandafter}% puis recommencer avec i+1 + \fi% \fi mangé par le \expandafter en fin de zone de \numexpr + }% + \ncar@i{0}% commence avec la valeur "compteur" 0 +} +\catcode`\@12 +a) \ncar{7}{*}\qquad +b) \ncar{13}{W}\qquad +c) \ncar{5}{X} +****************** Fin code ****************** + + +****************** Code 145 ****************** +\catcode`\@11 \newcount\compte@cnt +\def\compte#1{% + \def\val@max{#1}\compte@cnt=0 % effectue les initialisations + \compte@i% appelle la macro principale +} +\def\compte@i{% + \ifnum\compte@cnt<\val@max% si compteur < valeur maxi + \advance\compte@cnt1 % incrémenter le compteur + \number\compte@cnt, % afficher le nombre, la virgule et l'espace + \expandafter\compte@i %recommencer + \fi +} +\catcode`\@12 +a) \compte{9}\qquad +b) \compte{-4}\qquad +c) \compte{2} +****************** Fin code ****************** + + +****************** Code 146 ****************** +\catcode`\@11 \newcount\compte@cnt +\def\compte#1{\def\val@max{#1}\compte@cnt=0 \compte@i} +\def\compte@i{% + \ifnum\compte@cnt<\val@max\relax + \advance\compte@cnt1 + \number\compte@cnt + \ifnum\compte@cnt<\val@max , \fi% afficher ", " si le maxi n'est pas atteint + \expandafter\compte@i + \fi +} +\catcode`\@12 +a) \compte{9}\qquad +b)\compte{-4}\qquad +c) \compte{2} +****************** Fin code ****************** + + +****************** Code 147 ****************** +\catcode`\@11 \newcount\compte@cnt +\def\compte#1{% + \ifnum#1>0 % ne faire quelque chose que si l'argument est positif + \def\val@max{#1}\compte@cnt=1 % faire les initialisations + \expandafter\compte@i% appeller la macro récrusive + \fi +} +\def\compte@i{% + \number\compte@cnt\relax % afficher le nombre + \ifnum\compte@cnt<\val@max\relax % si valeur maxi n'est pas atteinte + , % afficher la virgule et l'espace + \advance\compte@cnt1 % incrémenter le compteur + \expandafter\compte@i % recommencer + \fi +} +\catcode`\@12 +a) \compte{9}\qquad +b) \compte{-4}\qquad +c) \compte{2} +****************** Fin code ****************** + + +****************** Code 148 ****************** +\catcode`\@11 +\def\compte#1{% + \ifnum#1>\z@% ne faire quelque chose que si #1 > 0 + \antefi\compte@i{1}{#1}% + \fi +} + +\def\compte@i#1#2{% + #1% afficher le nombre + \ifnum#1<#2 % si le maxi n'est pas atteint + \expandafter\identity% exécuter... + \else + \expandafter\gobone% sinon, manger... + \fi% le code entre accolades ci-dessous + {, % afficher la virgule et l'espace + \exparg\compte@i{\number\numexpr#1+1}{#2}% appel récursif + }% +} +\catcode`\@12 +a) \compte{9}\qquad +b) \compte{-4}\qquad +c) \edef\foo{\compte{2}}\meaning\foo +****************** Fin code ****************** + + +****************** Code 149 ****************** +\catcode`\@11 +\def\compte#1{% + \ifnum#1>\z@% ne faire quelque chose que si #1 > 0 + \antefi\compte@i{1}{#1}% + \fi +} + +\def\compte@i#1#2{% + #1% afficher le nombre + \ifnum#1<#2 % si le maxi n'est pas atteint + \antefi% déplace le \fi ici + , % affiche la virgule et l'espace + \exparg\compte@i{\number\numexpr#1+1}{#2}% appel récursif + \fi +} +\catcode`\@12 +a) \compte{9}\qquad +b) \compte{-4}\qquad +c) \edef\foo{\compte{2}}\meaning\foo +****************** Fin code ****************** + + +****************** Code 150 ****************** +\catcode`\@11 +\def\for#1=#2to#3\do#4{% #1=\<macro> #2=n1 #3=n2 #4=<code> + \def#1{#2}% initialise la \<macro> à l'entier n1 + \def\val@max{#3}% stocke n2 + \def\loop@code{#4}% stocke le <code> + \for@i#1% appelle la macro récursive et passe la \<macro> en argument +} +\def\for@i#1{% + \unless\ifnum#1>\val@max\relax% tant que la \<macro> est <= n2 + \loop@code% effectue le code précédemment sauvegardé + \edef#1{\number\numexpr#1+1}% incrémenter la \<macro> + \expandafter\for@i\expandafter#1% et recommencer après avoir mangé le \fi + \fi +} +\catcode`\@=12 +\for\ii=1to5\do{Maintenant \string\ii\ vaut : \ii.\endgraf}\medbreak +"\for\ii=1to0\do{A}"\medbreak% boucle parcourue 0 fois +"\for\ii=1to1\do{A}"\medbreak% boucle parcourue 1 fois +\for\ii = 0 to 10 \do {[\ii]}. +****************** Fin code ****************** + + +****************** Code 151 ****************** +\catcode`\@11 +\long\def\for#1=#2to#3\do#4{% + \def\for@i{% + \unless\ifnum#1>\val@max\relax% tant que la \<macro> <= n2 + #4% code à exécuter + \edef#1{\number\numexpr#1+1}% incrémenter \<macro> + \expandafter\for@i% et recommencer après avoir mangé le \fi + \fi + }% + \edef#1{\number\numexpr#2\relax}% initialise la variable à n1 + \edef\val@max{\number\numexpr#3\relax}% stocke n2 + \for@i% appelle la sous-macro récursive +} +\catcode`\@=12 +\for\ii = 1 to 5 \do {Maintenant \string\ii\ vaut : \ii.\par}\medbreak +"\for\ii=1to0\do{A}"\medbreak% boucle parcourue 0 fois +"\for\ii=1to1\do{A}"\medbreak% boucle parcourue 1 fois +\for\ii = 0 to 10 \do {[\ii]}. +****************** Fin code ****************** + + +****************** Code 152 ****************** +\catcode`\@11 +\def\for#1=#2to#3\do#4#{% + \edef\for@increment{\number\numexpr0#4}% lit et normalise l'argument optionnel + \ifnum\for@increment=\z@% s'il est nul, + \edef\for@increment{% le redéfinir : + \ifnum\numexpr#3\relax<\numexpr#2\relax + -% ajoute un signe - si #3<#2 + \fi + 1% devant "1" + }% \for@increment vaut donc 1 ou -1 + \fi + \ifnum\numexpr\for@increment*(#3-#2)\relax<\z@% si l'argument est incompatible + \expandafter\firstoftwo% exécuter le 1er argument qui suit + \else + \expandafter\secondoftwo% sinon le second + \fi + {Incrément incompatible !\gobone %\gobone mangera le <code> qui à lire + }% + {\edef#1{\number\numexpr#2\relax}% initialise la \<macro> + \edef\cmp@sgn{\ifnum\for@increment<\z@<\else>\fi}% stocke "<" ou ">" pour plus tard + \expandafter\for@i\expandafter#1\expandafter% appelle la macro récursive + {\number\numexpr#3\relax}% et lui lui passe la \<macro> (#1) et n2 (#3) + }% +} + +% #1 = \<macro> #2 = n2 +\long\def\for@i#1#2#3{% l'argument #3 (le <code>) est lu à ce moment-là + \def\for@ii{% + \unless\ifnum#1\cmp@sgn#2\relax% tant que la \<macro> n'a pas dépassé n2 + #3% exécute le <code> + \edef#1{\number\numexpr#1+\for@increment}% incrémente la \<macro> + \expandafter\for@ii% recommence après avoir mangé le \fi + \fi + }% + \for@ii% appelle la sous-macro récursive +}% +\catcode`\@=12 +a) \for\ii = -4 to 7 \do{(\ii)}\par +b) \for\jj = 20 to -50\do-10 {(\jj)}\par +c) \for\xx = 8 to 185\do 20 {[\xx]}\par +d) \for\yy = 0 to 10\do -2{(\yy)}\par +e) "\for\ii = 1 to 0 \do1{XX}"\par +f) "\for\ii = 1 to 1 \do{A}"\par% boucle parcourue 1 fois +g) \for\ii=1to4\do{\for\jj=0to2\do{(\ii,\jj)}\par}% imbrication de boucles +****************** Fin code ****************** + + +****************** Code 153 ****************** +\catcode`\@11 +\def\for#1=#2to#3\do#4#{% + \edef\for@increment{\number\numexpr0#4}% lit et normalise l'argument optionnel + \ifnum\for@increment=\z@% s'il est nul, + \edef\for@increment{% le redéfinir à -1 (si #3<#2) et 1 sinon + \ifnum\numexpr#3-#2\relax<\z@ -1\else 1\fi + }% \for@increment vaut donc 1 ou -1 + \fi + \ifnum\numexpr\for@increment*(#3-#2)\relax<\z@ + \expandafter\gobone% si argument optionnel incompatible, manger le {<code>} + \else + \edef#1{\number\numexpr#2}% initialise la \<macro> + \edef\macro@args{% définit et développe les arguments à passer à \for@i + %#1=nom de la macro récursive : + \expandafter\noexpand\csname for@ii@\string#1\endcsname + \ifnum\for@increment<\z@ <\else >\fi% #2=signe de comparaison + {\for@increment}% #3=incrément + \noexpand#1% #4=\<macro> + {\number\numexpr#3\relax}% #5=entier n2 + }% + \antefi% externalise la ligne ci-dessous de la portée du test + \expandafter\for@i\macro@args% appelle \for@i avec les arguments définis ci-dessus + \fi +} + +% #1=nom de la macro récursive de type "\for@ii@\<macro>" +% #2=signe de comparaison % #3=incrément +% #4=\<macro> % #5=entier n2 % #6=<code> à exécuter +\long\def\for@i#1#2#3#4#5#6{% + \def#1{% définit la sous macro récursive + \unless\ifnum#4#2#5\relax% tant que la \<macro> variable n'a pas dépassé n2 + \afterfi{% rendre la récursivité terminale + #6% exécute le code + \edef#4{\number\numexpr#4+#3\relax}% incrémente la \<macro> + #1% recommence + }% + \fi + }% + #1% appelle la sous-macro récursive +}% +\catcode`\@=12 +\for\ii=1to4\do{\for\jj=0to2\do{(\ii,\jj)}\par}\medbreak + +\for\carA= `\A to `\E \do{\for\carB= `w to `z \do{\char\carA\char\carB}\quad} +****************** Fin code ****************** + + +****************** Code 154 ****************** +\catcode`\@11 +\long\def\for@i#1#2#3#4#5#6{% + \def\exitfor{\def#1{}}% + \def#1{% définit la sous macro récursive + \unless\ifnum#4#2#5\relax% tant que la variable n'a pas dépassé l'entier max + \afterfi{% rendre la récursivité terminale + #6% exécute le code + \edef#4{\number\numexpr#4+#3\relax}% incrémente la variable #1 + #1% recommence + }% + \fi + }% + #1% appelle la sous-macro récursive +}% +\catcode`\@=12 +\for\ii= 1 to 9 \do{\string\ii{} vaut \ii.\ifnum\ii=5 \exitfor\fi\par} +****************** Fin code ****************** + + +****************** Code 155 ****************** +\def\exitfor#1{% #1=\<macro> correspondant à la boucle de laquelle on veut sortir + \defname{for@ii@\string#1}{} +} + +\def\ifexitfor#1{% envoie vrai si on est prématurément sorti de la boucle de \<macro> #1 + % si la macro récursive est égale à la macro "\empty" + \expandafter\ifx\csname for@ii@\string#1\endcsname\empty + \expandafter\firstoftwo% c'est qu'on est sortir prématurément, renvoyer "vrai" + \else + \expandafter\secondoftwo% sinon, renvoyer "faux" + \fi +} + +% on ne sort QUE de la boucle intérieure quand \ii=3 donc +% les boucles sont normalement exécutées pour \ii=4 et \ii=5 +a. \for\ii=1 to 5\do1{% + \for\jj=1 to 3\do1{(\ii,\jj) \ifnum\ii=3 \exitfor\jj\fi}% + \qquad + } + +% on sort de la boucle extérieure lorsque \ii=3 donc la boucle +% intérieure est faite entièrement même lorsque \ii=3 +b. \for\ii=1 to 5\do1{% + \for\jj=1 to 3\do1{(\ii,\jj) \ifnum\ii=3 \exitfor\ii\fi}% + \qquad + } + +% on sort de la boucle intérieure lorsque \ii=3 +% et aussi de la boucle extérieure à l'aide de \ifexitfor +c. \for\ii=1 to 5\do1{% + \for\jj=1 to 3\do1{(\ii,\jj) \ifnum\ii=3 \exitfor\jj\fi}% + \ifexitfor\jj{\exitfor\ii}{}% si on est sorti de \jj, sortir aussi de \ii + \qquad + } +****************** Fin code ****************** + + +****************** Code 156 ****************** +\def\foo{a}\ifx a\foo vrai\else faux\fi +****************** Fin code ****************** + + +****************** Code 157 ****************** +1) \meaning9\par% un caractère de catcode 12 +2) \meaning a\par% une lettre +3) \def\foo{a}\meaning\foo\par% une macro +4) \long\def\foo{a}\meaning\foo\par% une macro déclarée \long +5) \meaning\sdlkfj\par% une macro indéfinie +6) \edef\foo{\string a}\meaning\foo\par%\foo contient un "a" de catcode 12 +7) \def\foo{a}\meaning\foo\par%\foo contient un "a" de catcode 11 +****************** Fin code ****************** + + +****************** Code 158 ****************** +a) \ifx abvrai\else faux\fi\quad% a est n'est pas égal à b +b) \ifx++vrai\else faux\fi\quad% le caractère "+" est égal à "+" +c) \ifx\relax\par vrai\else faux\fi\quad% \relax n'est pas la même primitive que \par +d) \ifx\par\par vrai\else faux\fi\quad% \par et \par sont les mêmes primitives +e) \ifx\sdfk\qlms vrai\else faux\fi\quad% 2 macros non définies sont égales +f) \def\foo{abcd}\def\bar{abc}% \foo et \bar ont des textes de remplacement différents + \ifx\foo\bar vrai\else faux\fi\quad +g) \def\foo{abcd}\def\bar{abcd }% \foo et \bar ont des textes de remplacement différents + \ifx\foo\bar vrai\else faux\fi\quad +h) \def\foo{abcd}\def\bar{abcd} + \ifx\foo\bar vrai\else faux\fi\quad% \foo et \bar ont les mêmes textes de remplacement +i) \long\def\foo{a}\def\bar{a} + \ifx\foo\bar vrai\else faux\fi\quad% \foo est \long, \bar ne l'est pas +j) \edef\foo{\string a}% \foo contient un "a" de catcode 12 + \def\bar{a}% \bar contient un "a" de catcode 11 + \ifx\foo\bar vrai\else faux\fi +****************** Fin code ****************** + + +****************** Code 159 ****************** +\def\cmpmacro#1#2{% + \begingroup + \edef\tempa{\detokenize\expandafter{#1}}\edef\tempb{\detokenize\expandafter{#2}}% + \ifx\tempa\tempb% si égalité + \endgroup\expandafter\firstoftwo% ferme le groupe et lit 1er argument + \else + \endgroup\expandafter\secondoftwo% sinon, ferme le groupe et lit le 2e argument + \fi +} +a) \edef\foo{\string a}\def\bar{a} + \cmpmacro\foo\bar{vrai}{faux}\qquad +b) \edef\foo{\detokenize{$i^2=-1$\relax}}\def\bar{$i^2=-1$\relax} + \cmpmacro\foo\bar{vrai}{faux} +****************** Fin code ****************** + + +****************** Code 160 ****************** +a) \let\rien\relax \ifx\rien\relax vrai\else faux\fi\qquad +b) \let\AA=a \ifx a\AA vrai\else faux\fi\qquad +c) \let\foo=_\let\bar=_ \ifx\foo\bar vrai\else faux\fi +****************** Fin code ****************** + + +****************** Code 161 ****************** +\def\quark{\quark}% définit un quark +1) \def\test{\quark} \ifx\quark\test vrai\else faux\fi +\qquad +2) \let\test=\quark \ifx\quark\test vrai\else faux\fi +****************** Fin code ****************** + + +****************** Code 162 ****************** +\def\ifempty#1{% + \def\tempa{#1}% stocke l'argument #1 dans \tempa + \ifx\tempa\empty% si \tempa = \empty + \expandafter\firstoftwo% 1er argument + \else + \expandafter\secondoftwo% sinon, second + \fi +} +a) \ifempty{abc}{vide}{pas vide}\qquad +b) \ifempty{}{vide}{pas vide}\qquad +c) \ifempty{ }{vide}{pas vide}\qquad +d) \ifempty{\empty}{vide}{pas vide} +****************** Fin code ****************** + + +****************** Code 163 ****************** +\def\empty{} +\long\def\ifempty#1{% + \ifx_#1_\expandafter\firstoftwo + \else\expandafter\secondoftwo + \fi} +a) \ifempty{abc}{vide}{pas vide}\qquad +b) \ifempty{}{vide}{pas vide}\qquad +c) \ifempty{ }{vide}{pas vide}\qquad +d) \ifempty{\empty}{vide}{pas vide}\qquad +e) \edef\foo{\ifempty{abc}{vide}{pas vide}}\meaning\foo +****************** Fin code ****************** + + +****************** Code 164 ****************** +\long\def\ifempty#1{% + \ifx W#1W\expandafter\firstoftwo + \else \expandafter\secondoftwo + \fi} +1) \ifempty{foobar}{vide}{pas vide}\qquad +2) \ifempty{}{vide}{pas vide}\qquad +2) \ifempty{\empty}{vide}{pas vide}\qquad +4) \ifempty{Wagons}{vide}{pas vide} +****************** Fin code ****************** + + +****************** Code 165 ****************** +\long\def\ifempty#1{% + \expandafter\ifx\expandafter\relax\detokenize{#1}\relax + \expandafter\firstoftwo + \else + \expandafter\secondoftwo + \fi +} +a) \ifempty{abc}{vide}{pas vide}\qquad +b) \ifempty{}{vide}{pas vide}\qquad +c) \ifempty{ }{vide}{pas vide}\qquad +d) \ifempty{\relax}{vide}{pas vide}\qquad +e) \edef\foo{\ifempty{abc}{vide}{pas vide}}\meaning\foo +****************** Fin code ****************** + + +****************** Code 166 ****************** +\catcode`\@11 +\def\reverse#1{% + \ifempty{#1} + {}% s'il n'y a rien à inverse, ne rien faire + {\reverse@i#1\@nil\@nil}% initialisation des réservoirs et appeler \reverse@i +} +\def\reverse@i#1#2\@nil#3\@nil{% #1 est le 1er caractère du réservoir A + \ifempty{#2}% si ce qui reste après ce 1er caractère est vide + {#1#3}% renvoyer #1#3 qui est le résultat final + {\reverse@i#2\@nil#1#3\@nil}% sinon, recommencer en déplaçant #1 + % en 1re position du réservoir B +} +\catcode`\@12 +a) \reverse{foobar}\qquad +b) \edef\foo{\reverse{Bonjour}}\meaning\foo\qquad +c) \reverse{Bonjour le monde}\qquad +d) \reverse{Bonjour{ }le{ }monde} +****************** Fin code ****************** + + +****************** Code 167 ****************** +\catcode`\@11 +\def\ifin#1#2{% + \def\ifin@i##1#2##2\@nil{% définit la macro auxiliaire + \ifempty{##2}% si ce qu'il y a derrière le motif est vide + \secondoftwo% aller à "faux" + \firstoftwo% sinon à "vrai" + }% + \ifin@i#1#2\@nil% appel de la macro auxiliaire +} +\catcode`\@12 +a) \ifin{abc\relax1}{bc}{vrai}{faux}\qquad +b) \ifin{abc \relax1}{c\relax}{vrai}{faux}\qquad +c) \ifin{abc \relax1}{ }{vrai}{faux}\qquad +d) \ifin{abc \relax1}{}{vrai}{faux}\qquad +e) \ifin{}{a}{vrai}{faux} +****************** Fin code ****************** + + +****************** Code 168 ****************** +\catcode`\@11 +\def\ifstart#1#2{% + \def\ifstart@i##1#2##2\@nil{\ifempty{##1}}% + \ifstart@i#1#2\@nil +} +\catcode`\@12 +a) \ifstart{abc}{bc}{vrai}{faux}\qquad +b) \ifstart{abc}{ab}{vrai}{faux}\qquad +c) \ifstart{ abc}{ }{vrai}{faux}\qquad +d) \ifstart{abc}{}{vrai}{faux}\qquad +e) \ifstart{}{a}{vrai}{faux} +****************** Fin code ****************** + + +****************** Code 169 ****************** +\catcode`\@11 +\def\ifstart#1#2{% + \def\ifstart@i##1#2##2\@nil{\ifempty{##1}}% + \ifempty{#2}% si motif vide + \firstoftwo% exécuter code "vrai" + {\ifstart@i#1\relax#2\@nil}% sinon, aller à la macro auxiliaire +} +\catcode`\@12 +a) \ifstart{abc}{bc}{vrai}{faux}\qquad +b) \ifstart{abc}{ab}{vrai}{faux}\qquad +c) \ifstart{ abc}{ }{vrai}{faux}\qquad +d) \ifstart{abc}{}{vrai}{faux}\qquad +e) \ifstart{}{a}{vrai}{faux} +****************** Fin code ****************** + + +****************** Code 170 ****************** +\catcode`\@11 +\def\ifend#1#2{% + \def\ifend@i##1#2##2\@nil{% ##2 = ce qui reste après le motif + \ifempty{##2}% si ##2 est vide + \firstoftwo% exécuter l'argument "vrai" + {\ifin{##2}{#2}% sinon, si ##2 contient le <motif> + {\ifend@i##2\@nil}% appeler \ifend@i avec ce qui reste + \secondoftwo% sinon, exécuter l'argument "faux" + }% + }% + \ifend@i#2#1\@nil% appelle la macro récursive +} +\catcode`\@12 +1) \ifend{abc de}{de}{vrai}{faux}\qquad +2) \ifend{abd de }{de}{vrai}{faux}\qquad +3) \ifend{abc de }{ }{vrai}{faux}\qquad +4) \ifend{}{a}{vrai}{faux}\qquad +5) \ifend{abc de}{}{vrai}{faux} +****************** Fin code ****************** + + +****************** Code 171 ****************** +\catcode`\@11 +\def\ifend#1#2{% + \def\ifend@i##1#2##2\@nil{% ##2 = ce qui reste après le motif + \ifempty{##2}% si ##2 est vide + \firstoftwo% exécuter l'argument "vrai" + {\ifin{##2}{#2}% sinon, si ##2 contient le <motif> + {\ifend@i##2\@nil}% appeler \ifend@i avec ce qui reste + \secondoftwo% sinon, exécuter l'argument "faux" + }% + }% + \ifempty{#2}% si le motif est vide + \firstoftwo% exécuter "vrai" + {\ifend@i#2\relax#1\@nil}% sinon, appelle la macro récursive +} +\catcode`\@12 +1) \ifend{abc de}{de}{vrai}{faux}\qquad +2) \ifend{abd de }{de}{vrai}{faux}\qquad +3) \ifend{abc de }{ }{vrai}{faux}\qquad +4) \ifend{}{a}{vrai}{faux}\qquad +5) \ifend{abc de}{}{vrai}{faux} +****************** Fin code ****************** + + +****************** Code 172 ****************** +\catcode`\@11 +\def\substin#1#2#3{% + \def\substin@i##1{% + \ifempty{##1}% si le <code> est vide + \relax% ne rien faire -> fin du processus + {\ifin{##1}{#2}% sinon, si le <code> contient <motif1> + {\substin@ii##1\@nil}% appeler la macro à argument délimités + {##1}% sinon, afficher le <code> + }% + }% + \def\substin@ii##1#2##2\@nil{% + ##1#3% afficher ##1 et #3 (qui est <motif2>) + \substin@i{##2}% et recommencer avec ce qui reste + }% + \substin@i{#1}% +} +\catcode`\@12 +a) \substin{abracadabra}{a}{A}\qquad +b) \substin{abracadabra}{x}{W}\qquad +c) \substin{abracadabra}{br}{}\qquad +d) \substin{1\relax3}\relax{222}\qquad +****************** Fin code ****************** + + +****************** Code 173 ****************** +\catcode`\@11 +\def\substtocs#1#2#3#4{% + \def\substtocs@i##1{% + \ifempty{##1}% si le <code> est vide + \relax% ne rien faire -> fin du processus + {\ifin{##1}{#3}% sinon, si le <code> contient <motif1> + {\substtocs@ii##1\@nil}% appeler la macro à argument délimités + {\addtomacro#1{##1}}% sinon, ajouter le <code> + }% + }% + \def\substtocs@ii##1#3##2\@nil{% + \addtomacro#1{##1#4}% ajouter ##1#4 + \substtocs@i{##2}% et recommencer avec ce qui reste + }% + \let#1=\empty% initialise la macro à vide + \substtocs@i{#2}% +} +\catcode`\@12 +\substtocs\foo{abracadabra}{a}{A}\meaning\foo\par +\substtocs\foo{abracadabra}{x}{W}\meaning\foo\par +\substtocs\foo{abracadabra}{br}{}\meaning\foo\par +\substtocs\foo{1\relax3}\relax{222}\meaning\foo\par +\substtocs\foo{\ifnum1=2 test vrai\fi}{2}{1}\meaning\foo +****************** Fin code ****************** + + +****************** Code 174 ****************** +\def\majuscule#1{\uppercase{#1}} +\def\majmot#1{\substin{\majuscule#1}{ }{ \majuscule}} +\majmot{un petit texte}\par +\majmot{Un grand texte sans importance} +****************** Fin code ****************** + + +****************** Code 175 ****************** +\def\majuscule#1{\uppercase{#1}} +\def\majmot#1{% + \begingroup + \substtocs\temp{\majuscule#1}{ }{ \majuscule}% + \temp% exécute la macro temporaire + \endgroup +} +\majmot{un petit texte}\par +\majmot{Un grand texte Sans importance} +****************** Fin code ****************** + + +****************** Code 176 ****************** +\catcode`\@11 +\newcount\cnt@occ +\def\cnttimes#1#2{% + \def\cnttimes@i##1{% + \ifempty{##1}% si le <code> est vide + {\number\cnt@occ}% afficher le nombre d'occurrences + {\ifin{##1}{#2}% sinon, si le <code> contient <motif1> + {\cnttimes@ii##1\@nil}% appeler la macro à argument délimités + {\number\cnt@occ}% sinon, afficher le nombre d'occurrences + }% + }% + \def\cnttimes@ii##1#2##2\@nil{% + \advance\cnt@occ1 + \cnttimes@i{##2}% et recommencer avec ce qui reste + }% + \cnt@occ=0 % initialise le compteur + \cnttimes@i{#1}% +} +\catcode`\@12 +a) \cnttimes{abracadabra}{a}\qquad +b) \cnttimes{abracadabra}{ra}\qquad +c) \cnttimes{abracadabra}{w}\qquad +d) \cnttimes{abc def ghijk l }{ }\qquad +e) \cnttimes{\ifnum1=2 vrai\else faux\fi}{\ifnum} +****************** Fin code ****************** + + +****************** Code 177 ****************** +\catcode`\@11 +\long\def\cnttimestocs#1#2#3{% #3=macro recevant le résultat + \long\def\cnttimestocs@i##1\@nil##2#2##3\@nil{% + % ##1=nb d'occurrences rencontrées jusqu'alors + % ##2 et ##3=ce qui est avant/après le <motif> + \ifin{##3}{#2}% si le <motif> est dans ce qui reste + {\expandafter\cnttimestocs@i% appeler la macro récursive + \number\numexpr##1+1\relax\@nil% avec une occurrence de plus + ##3\@nil% et ce qui reste + }% + {\edef#3{\number\numexpr##1+1\relax}}% sinon, stocker 1 occurrence de plus dans #3 + }% + \ifin{#1}{#2}% si le <motif> est dans le <code> + {\cnttimestocs@i 0\@nil#1\@nil}% appeler la macro récursive avec 0 occurrence + {\def#3{0}}% sinon, mettre 0 dans #3 +} +\catcode`\@12 +a) \cnttimestocs{abracadabra}{a}\foo \meaning\foo\qquad +b) \cnttimestocs{abracadabra}{ra}\foo \meaning\foo\qquad +c) \cnttimestocs{abracadabra}{w}\foo \meaning\foo\qquad +d) \cnttimestocs{abc def ghijk l }{ }\foo \meaning\foo\qquad +e) \cnttimestocs{\ifnum1=2 vrai\else faux\fi}{\ifnum}\foo \meaning\foo +****************** Fin code ****************** + + +****************** Code 178 ****************** +\catcode`\@11 +\def\multisubst#1#2{% + \def\subst@code{#1}% stocke le <code> + \multisubst@i#2\@nil% appelle la macro récursive avec la liste de motifs +} + +\def\multisubst@i#1#2#3\@nil{% #1 et #2=paire de motifs #3=motifs restants + \expandafter\substtocs\expandafter\subst@code\expandafter% 1-développe + {\subst@code}{#1}{#2}% le <code> et effectue la substitution en cours + \ifempty{#3}% si la liste des motifs est vide + \subst@code% exécuter le <code> obtenu + {\multisubst@i#3\@nil}% recommencer avec les motifs qui restent +} +\catcode`\@12 +1) \multisubst{abracadabra}{aA rR}\par +2) \multisubst{Ce texte devenu \`a peine reconnaissable montre que le + r\'esultat contient des sonorit\'es catalanes, corses ou grecques + assez inattendues.}{a{AA} ya uy ou io ei {AA}e} +****************** Fin code ****************** + + +****************** Code 179 ****************** +\catcode`\@11 +\def\quark{\quark} + +\def\multisubst#1#2{% #1 = <code> #2 = <liste des paires> + \def\subst@code{#1}% stocke le <code> + \multisubst@i#2\quark\quark% appelle la macro récursive avec + % 2 arguments spéciaux en fin de liste +} + +\def\multisubst@i#1#2{% #1#2 = paire de motifs en cours + \def\arg@a{#1}% stocke le <motif1> dans une macro + \ifx\arg@a\quark% si le motif spécial est atteint + \expandafter\subst@code% exécuter le code obtenu + \else + \expandafter\substtocs\expandafter\subst@code\expandafter% 1-développe + {\subst@code}{#1}{#2}% le <code> et effectue la substitution en cours + \expandafter\multisubst@i% puis lis la paire de motifs suivants + \fi +} +\catcode`\@12 +\multisubst{abracadabra}{aA rR}\par +\multisubst{Ce texte devenu \`a peine reconnaissable montre que le r\'esultat contient des + sonorit\'es catalanes, corses ou grecques assez inattendues.}{a{AA} ya uy ou io ei {AA}e} +****************** Fin code ****************** + + +****************** Code 180 ****************** +\iftrue foobar\else ceci n'est jamais lu par \TeX\fi\par +\iffalse ceci n'est jamais lu par \TeX\else foobar\fi +****************** Fin code ****************** + + +****************** Code 181 ****************** +\newif\ifhomme +\def\debutlettre{Ch\ifhomme er Monsieur\else ère Madame\fi}% + +\hommetrue +\debutlettre +\medbreak + +\hommefalse +\debutlettre +****************** Fin code ****************** + + +****************** Code 182 ****************** +\catcode`\*=13 \catcode`\+=13 % "*" et "+" sont actifs +1) \def*{xyz}\def+{abc}% définit les caractères actifs + \ifcat *+vrai\else faux\fi\qquad +2) \ifcat \noexpand *\noexpand +vrai\else faux\fi\qquad +3) \def\foo{foobar}% + \ifcat \noexpand\foo\relax vrai\else faux\fi\qquad% \foo et \relax sont vus égaux +4) \ifcat = vrai\else faux\fi\qquad% "=" et " " n'ont pas le même catcode +5) \ifcat _^vrai\else faux\fi\qquad% "_" et "^" n'ont pas le même catcode +6) \let\foo=& + \ifcat &\foo vrai\else faux\fi% "&" et \foo (let-égal à "&") sont vus égaux +****************** Fin code ****************** + + +****************** Code 183 ****************** +\catcode`\@11 +\def\ifcs#1{% + \ifcat\noexpand#1\relax\expandafter\firstoftwo + \else \expandafter\secondoftwo + \fi +} +\catcode`\@12 +1) \def\foo{bar}\ifcs\foo{vrai}{faux}\qquad +2) \ifcs\def{vrai}{faux}\qquad +3) \ifcs A{vrai}{faux}\qquad +\catcode`\*=13 +4) \let*=W \ifcs*{vrai}{faux}\qquad +5) \let*=\relax \ifcs*{vrai}{faux}\qquad +6) \let\foo=A \ifcs\foo{vrai}{faux}\qquad +7) \ifcs\bgroup{vrai}{faux} +****************** Fin code ****************** + + +****************** Code 184 ****************** +1) \def\foo{xxy}\def\bar{aab} + \if\foo\bar vrai\else faux\fi\qquad +2) \if aA vrai\else faux\fi\qquad% "a" et "A" n'ont pas les mêmes charcode +3) \if\relax\noexpand\foo vrai\else faux\fi\qquad% \relax et \foo ont un charcode=256 +4) \let\foo=&\if\foo &vrai\else faux\fi\qquad% \foo est vue comme "&" +5) \if\string~\noexpand~vrai\else faux\fi +****************** Fin code ****************** + + +****************** Code 185 ****************** +\catcode`\@11 +\def\ifcs#1{% + \begingroup + \escapechar=`\@ % prend "@" comme caractère d'échappement + \if% les premiers caractères de + \expandafter\firstto@nil\string#1a\@nil% "#1a" + \expandafter\firstto@nil\string\relax\@nil% et "\relax" sont-ils égaux ? + \endgroup\expandafter\firstoftwo% si oui, fermer le groupe et renvoyer "vrai" + \else% sinon, fermer le groupe et renvoyer "faux" + \endgroup\expandafter\secondoftwo + \fi +} +\catcode`\@12 +1) \def\foo{bar}\ifcs\foo{vrai}{faux}\qquad +2) \ifcs\def{vrai}{faux}\qquad +3) \ifcs A{vrai}{faux}\qquad +\catcode`\*=13 +4) \let*=W \ifcs*{vrai}{faux}\qquad +5) \let*=\relax \ifcs*{vrai}{faux}\qquad +6) \let\foo=A \ifcs\foo{vrai}{faux}\qquad +7) \ifcs\bgroup{vrai}{faux} +****************** Fin code ****************** + + +****************** Code 186 ****************** +\edef\specialrelax{\ifnum1=1\fi} +\meaning\specialrelax +****************** Fin code ****************** + + +****************** Code 187 ****************** +\edef\specialrelax{\ifnum1=1\fi}% texte de remplacement = \relax spécial +\edef\normalrelax{\relax}% texte de remplacement = \relax normal +\meaning\specialrelax\par +\meaning\normalrelax\par +Les 2 \string\relax{} sont \ifx\specialrelax\normalrelax identiques\else différents\fi. +****************** Fin code ****************** + + +****************** Code 188 ****************** +\edef\specialrelax{\ifnum1=1\fi} +\expandafter\def\specialrelax{foobar}% redéfinition un \relax spécial +****************** Fin code ****************** + + +****************** Code 189 ****************** +\catcode`\@11 +\def\ifnumcase#1{% + \begingroup + \def\elseif{\elseif}\def\endif{\endif}% définir deux "quarks" locaux + \def\nombre@{#1}% stocker le nombre à comparer dans \nombre@ + \ifnumcase@i% appeller la macro récursive +} + +\def\ifnumcase@i#1{% + \def\nxt@arg{#1}% stocker l'argument suivant + \ifx\nxt@arg\elseif% si c'est \elseif + \def\next@todo{\endgroup\idto@endif}% fermer le groupe et aller à \idto@endif + \else + \ifx\nxt@arg\endif% si c'est \endif + \let\next@todo\endgroup% fermer le groupe + \else + \ifnum\nombre@=\nxt@arg% s'il y a égalité + \def\next@todo{\endgroup\firstto@endif}% fermer le groupe puis \firstto@endif + \else% sinon + \let\next@todo=\ifnumcase@ii% aller à \ifnumcase@ii + \fi + \fi + \fi + \next@todo% exécuter l'action décidée ci-dessus +} + +\def\ifnumcase@ii#1{\ifnumcase@i} +\def\idto@endif#1\endif{#1} +\def\firstto@endif#1#2\endif{#1} +\catcode`\@12 +\def\swaptwo#1#2{#2#1} +\def\testenombre#1{% + \ifnumcase{#1} + {1}{C'est "un" et je prends le premier argument: \firstoftwo} + {3}{J'ai vu un "trois" et je mange les deux arguments : \gobtwo} + {15}{L'argument est "15" et je prends le second argument : \secondoftwo} + \elseif + ni 1, ni 3, ni 5 et j'inverse les deux arguments : \swaptwo + \endif +} +\testenombre{3}{foo}{bar}\par +\testenombre{16}{foo}{bar}\par +\testenombre{15}{foo}{bar}\par +\testenombre{1}{foo}{bar} +****************** Fin code ****************** + + +****************** Code 190 ****************** +\catcode`\@11 +\def\endif{\endif}\def\elseif{\elseif}% définit les quarks + +\def\ifnumcase#1#2{% #1=<nombre> #2=prochain argument + \ifx\elseif#2% si #2 est \elseif + \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + \idto@endif% aller à \idto@endif, sinon : + {\ifx\endif#2% si #2 est \endif + \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {}% ne rien faire. Sinon #2 est une <valeur i>: + {\ifnum#1=#2 % s'il y a égalité entre <nombre> et <valeur i> + \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + \firstto@endif% aller à \firstto@endif + {\ifnumcase@i{#1}}% sinon aller à \ifnumcase@i + }% + }% +} + +\def\ifnumcase@i#1#2{% #1=<nombre> #2=<code i> à suivre qui est mangé + \ifnumcase{#1}% retourner à \ifnumcase en transmettant #1 +} + +\def\idto@endif#1\endif{#1} +\def\firstto@endif#1#2\endif{#1} +\catcode`\@12 +\def\swaptwo#1#2{#2#1} +\def\testenombre#1{% + \ifnumcase{#1} + {1}{C'est "un" et je prends le premier argument: \firstoftwo} + {3}{J'ai vu un "trois" et je mange les deux arguments : \gobtwo} + {15}{L'argument est "15" et je prends le second argument : \secondoftwo} + \elseif + ni 1, ni 3, ni 5 et j'inverse les deux arguments : \swaptwo + \endif +} +\testenombre{3}{foo}{bar}\par +\testenombre{16}{foo}{bar}\par +\testenombre{15}{foo}{bar}\par +\edef\macro{\testenombre{1}{foo}{bar}}\meaning\macro +****************** Fin code ****************** + + +****************** Code 191 ****************** +\catcode`\@11 +\def\endif{\endif}\def\elseif{\elseif}% +\def\ifxcase#1#2{% #1=<token> #2=prochain argument + \ifx\elseif#2% si #2 est \elseif + \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + \idto@endif% aller à \idto@endif, sinon : + {\ifx\endif#2% si #2 est \endif + \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {}% ne rien faire. Sinon #2 est un <token i>: + {\ifx#1#2% s'il y a égalité entre <token> et <token i> + \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + \firstto@endif% aller à \firstto@endif + {\ifxcase@i{#1}}% sinon aller à \ifnumcase@i + }% + }% +} +\def\ifxcase@i#1#2{% #1=<token> #2=<code i> à suivre (qui est mangé) + \ifxcase{#1}% retourner à \ifxcase en transmettant #1 +} +\def\idto@endif#1\endif{#1} +\def\firstto@endif#1#2\endif{#1} +\catcode`\@12 +\def\testtoken#1{% + \ifxcase{#1} + a{Le token est "a"} + +{J'ai vu un "+"} + \relax{L'argument est "\string\relax"} + \elseif + Tous les tests sont négatifs% + \endif +} +1) \testtoken a\par +2) \let\foo=a\testtoken\foo\par +3) \testtoken+\par +4) \testtoken\relax\par +5) \edef\foo{\testtoken\relax}\meaning\foo\par +6) \edef\foo{\testtoken W}\meaning\foo +****************** Fin code ****************** + + +****************** Code 192 ****************** +\newcount\xx % définit un compteur utilisé dans la boucle +\def\compte#1{% + \xx=0 % initialise le compteur + \loop% début de la boucle + \advance\xx1 % incrémente le compteur + \ifnum\xx<#1 % s'il est inférieur à la borne + \number\xx , % affiche le nombre et la virgule + \repeat% et recommence + \ifnum#1>0 \number\xx\relax\fi% si le nombre #1 est >0, afficher le dernier nombre + } +a) \compte{1}.\qquad b) \compte{-3}.\qquad c) \compte{7}. +****************** Fin code ****************** + + +****************** Code 193 ****************** +\catcode`\@11 +\newcount\cnt@repeat % définit le compteur de \xrepeat + +\def\xloop{% + \def\xiterate{}% initialiser \xiterate à vide + \cnt@repeat\z@% initialiser le compteur de \xrepeat + \xloop@i% aller à la macro récursive +} + +\long\def\xloop@i#1\xrepeat{% + \addtomacro\xiterate{#1}% ajoute ce qui est avant le premier \xrepeat + \exparg\cnttimestocs{\xiterate}\xloop\cnt@loop + % combien de \xloop dans \xiterate + \ifnum\cnt@loop=\cnt@repeat\relax + \expandafter\firstoftwo\else\expandafter\secondoftwo + \fi + {% autant que de \xrepeat -> \detokenize pour afficher + "\detokenize\expandafter{\xiterate}"% + } + {\addtomacro\xiterate\xrepeat% sinon, ajouter ce \xrepeat + \advance\cnt@repeat by 1% incrémenter le compteutr de \xrepeat + \xloop@i% et chercher le prochain \xrepeat + }% +} +\let\xrepeat\fi +\catcode`\@12 +\xloop a\xloop b\xloop 12\xrepeat c\xrepeat \xloop X\xrepeat\xrepeat +****************** Fin code ****************** + + +****************** Code 194 ****************** +\catcode`\@11 +\newcount\cnt@repeat +\newcount\cnt@nested +\cnt@nested=0 % compteur d'imbrications +\def\xloop{% + \global\advance\cnt@nested by 1 % augmente le compteur d'imbrications + \expandafter\def\csname xiterate@\number\cnt@nested\endcsname{}% + \cnt@repeat\z@% initialise le compteur de \xrepeat à 0 + \xloop@i% aller à la macro \xloop@i +} +\long\def\xloop@i#1\xrepeat{% + \expandafter\addtomacro\csname xiterate@\number\cnt@nested\endcsname{#1}% + \expandafter\expandafter\expandafter\cnttimestocs\expandafter\expandafter\expandafter + {\csname xiterate@\number\cnt@nested\endcsname}\xloop\cnt@loop + \ifnum\cnt@loop=\cnt@repeat\relax + \expandafter\firstoftwo\else\expandafter\secondoftwo + \fi + {\expandafter\eaddtomacro\csname xiterate@\number\cnt@nested\expandafter\endcsname + {\expandafter\expandafter\csname xiterate@\number\cnt@nested\endcsname\fi}% + %\expandafter\show\csname xiterate@\number\cnt@nested\endcsname + \csname xiterate@\number\cnt@nested\endcsname + \letname{xiterate@\number\cnt@nested}\relax + \global\advance\cnt@nested by -1 + } + {\expandafter\addtomacro\csname xiterate@\number\cnt@nested\endcsname\xrepeat + \advance\cnt@repeat by 1 + \xloop@i + }% +}% +\let\xrepeat\fi +\catcode`\@12 + +\newcount\cntxx \cntxx=1 % compteur des lignes +\newcount\cntyy +\xloop + \cntyy=1 % compteur des colonnes + \xloop + (\number\cntxx,\number\cntyy)% affiche "(ligne,colonne)" + \ifnum\cntyy<5 % tant que colonne<5 + \advance\cntyy1 % incrémente colonne + , % <- affiche ", " + \xrepeat% et recommence + \ifnum\cntxx<3 % tant que ligne<3 + \advance\cntxx1 % incrémente ligne + \par % va à la ligne +\xrepeat% et recommence +****************** Fin code ****************** + + +****************** Code 195 ****************** +\catcode`\@11 +\def\end@foreach{\end@foreach}% définit un quark +\long\def\doforeach#1\in#2#3{% + \def\loop@code{#3}% assigne le <code> à \loop@code + % appel à \doforeach@i : mettre la macro #1 en premier, puis la liste de valeurs #2 + \doforeach@i#1#2,\end@foreach,% ajouter à la fin ",\end@foreach," + % une fois les boucles finies, neutraliser les macros déjà définies + \let#1\relax \let\loop@code\relax +} + +\long\def\doforeach@i#1#2,{% #1=\<macro> #2=valeur courante + \def#1{#2}% stocke la valeur en cours dans la \<macro> + \unless\ifx\end@foreach#1% si \end@foreach n'est pas atteint + \antefi% amène le \fi ici + \loop@code% exécute le code + \doforeach@i#1% et recommencer + \fi +} +\catcode`@12 +\doforeach\x\in{a,bcd,{efg},hi}{\meaning\x.\par} +****************** Fin code ****************** + + +****************** Code 196 ****************** +\catcode`\@11 +\def\end@foreach{\end@foreach} +\def\defseplist#1{% + \long\def\doforeach##1\in##2##3{% + \def\loop@code{##3}% assigne le <code> à \loop@code + \doforeach@i##1##2#1\end@foreach#1% ajouter ",\end@foreach," et aller à \doforeach@i + % après être sorti des boucles, neutraliser les macros déjà définies + \let\loop@code\relax \let##1\relax + }% + \long\def\doforeach@i##1##2#1{% + \def##1{##2}% stocke la valeur en cours dans la \<macro> + \unless\ifx\end@foreach##1% si la fin n'est pas atteinte + \antefi% amène le \fi ici + \loop@code% exécute le code + \doforeach@i##1% et recommencer + \fi + }% +} +\defseplist{,}% définit les macros avec le séparateur par défaut +\catcode`@12 + +\doforeach\x\in{a,bcd,efg}{Argument courant : "\x".\par}\medbreak + +\defseplist{--}% séparateur "--" +\doforeach\nn\in{4,19--0,5--8,575}{Nombre lu : "\nn"\par} +****************** Fin code ****************** + + +****************** Code 197 ****************** +\catcode`\@11 +\newcount\cnt@nest \cnt@nest=0 % définit et initialise le compteur d'imbrication +\def\end@foreach{\end@foreach} + +\def\defseplist#1{% + \long\def\doforeach##1\in##2##3{% + \global\advance\cnt@nest1 % entrée de boucle : incrémenter le compteur d'imbrication + \defname{loop@code@\number\cnt@nest}{##3}% assigne le <code> à \loop@code@<n> + \doforeach@i##1##2#1\end@foreach#1% ajouter ",\end@foreach," et aller à \doforeach@i + % une fois fini : + \let##1\empty% dans ce cas, neutraliser les macros déjà définies + \letname{loop@code@\number\cnt@nest}\empty% + \global\advance\cnt@nest-1 %sortie de boucle : décrémenter le compteur d'imbrication + }% + \long\def\doforeach@i##1##2#1{% + \def##1{##2}% stocke la valeur en cours dans la \<macro> + \unless\ifx\end@foreach##1% tant que la fin n'est pas atteinte + \antefi% amène le \fi ici + \csname loop@code@\number\cnt@nest\endcsname% exécute le code + \doforeach@i##1% et recommencer + \fi + }% +} +\catcode`@12 +\defseplist{,} + +\doforeach\xxx\in{1,2,3}{% + Ligne \xxx{} : \doforeach\yyy\in{a,b,c,d,e}{(\xxx,\yyy)}.\par +} +****************** Fin code ****************** + + +****************** Code 198 ****************** +\catcode`\@11 +\newcount\cnt@nest \cnt@nest=0 % définit et initialise le compteur d'imbrication +\def\end@foreach{\end@foreach} +\long\def\save@macro#1{% sauvegarde la macro #1 + \ifdefined#1% si la macro #1 est déjà définie... + \letname{saved@var@\number\cnt@nest}#1% ...la sauvegarder + \fi +} +\long\def\restore@macro#1{% restaure la macro #1 +% le \csname donne \relax si la sauvegarde n'a pas été faite + \expandafter\let\expandafter#1\csname saved@var@\number\cnt@nest\endcsname +} +\def\defseplist#1{% + \long\def\doforeach##1\in##2##3{% + \global\advance\cnt@nest1 % entrée de boucle : incrémenter le compteur d'imbrication + \save@macro##1% sauvegarde la macro ##1 + \defname{loop@code@\number\cnt@nest}{##3}% assigne le <code> à \loop@code@<n> + \doforeach@i##1##2#1\end@foreach#1% ajouter ",\end@foreach," et aller à \doforeach@i + % une fois fini, neutraliser la macro contenant le <code> + \letname{loop@code@\number\cnt@nest}\empty + \restore@macro##1% restaurer la \<macro> + \global\advance\cnt@nest-1 % et décrémenter le compteur d'imbrication + }% + \long\def\doforeach@i##1##2#1{% + \def##1{##2}% stocke la valeur en cours dans la \<macro> + \unless\ifx\end@foreach##1% si la fin n'est pas atteinte + \antefi% amène le \fi ici + \csname loop@code@\number\cnt@nest\endcsname% exécute le code + \doforeach@i##1% et recommencer + \fi% + }% +} +\catcode`@12 +\defseplist{,} +\doforeach\par\in{a,b,c,y,z}{$\par_i$} + +\meaning\par% \par doit être redevenu une primitive + +\doforeach\xxx\in{1,2,3}{% + Ligne \xxx{} : \doforeach\yyy\in{a,b,c,d,e}{(\xxx,\yyy)}.\par +} +****************** Fin code ****************** + + +****************** Code 199 ****************** +\let\foo=\djfhdsldv% \foo est rendue \let-égale à une macro indéfinie +a) \meaning\foo\par +% puis \djfhdsldv est rendue \let-égale à \foo (ou \foo est construit avec \csname) +\expandafter\let\expandafter\djfhdsldv\csname foo\endcsname +b) \meaning\djfhdsldv +****************** Fin code ****************** + + +****************** Code 200 ****************** +\catcode`\@11 +\newcount\cnt@nest \cnt@nest=0 % définit et initialise le compteur d'imbrication +\def\end@foreach{\end@foreach} +\long\def\save@macro#1#2{\letname{saved@var@\number\cnt@nest#1}#2} +\long\def\save@macro@i#1/#2{\save@macro{a}#1\save@macro{b}#2} +\long\def\restore@macro#1#2{% + \expandafter\let\expandafter#2\csname saved@var@\number\cnt@nest#1\endcsname +} +\long\def\restore@macro@i#1/#2{\restore@macro{a}#1\restore@macro{b}#2} +\def\defseplist#1{% + \long\def\doforeach##1\in##2##3{% + \global\advance\cnt@nest1 % entrée de boucle : incrémenter le compteur d'imbrication + \global\let\allow@recurse\identity% permet l'appel récursif plus bas + \ifin{##1}{/}% si ##1 contient "/" + {\save@macro@i##1% sauvegarde les macros + \doforeach@ii% appeler la macro récursive avec les arguments + {##3}% 1) code à exécuter + ##1% 2) variables sous la forme \<macro1>/\<macro2> + ##2#1\end@foreach/\end@foreach#1% puis la liste ##2 suivie de + % ",\end@foreach/\end@foreach," + \restore@macro@i##1% une fois sorti de toutes les boucles, restaurer les macros + }% si ##1 ne contient pas "/" + {\save@macro{}##1% sauvegarde la macro + \doforeach@i% appeler la macro récursive + {##3}% mettre en premier le <code> + ##1% puis la variable ##1 en 2e position + ##2#1\end@foreach#1% enfin la liste ##2 suivie de ",\end@foreach," + \restore@macro{}##1% une fois sorti de toutes les boucles, restaurer la macro + }% + \global\advance\cnt@nest-1 % décrémente le compteur d'imbrications + }% + % ##1 = code à exécuter, ##2= variable, ##3=valeur courante + \long\def\doforeach@i##1##2##3#1{% + \ifx\end@foreach##3% si la fin est atteinte + \expandafter\gobone\else\expandafter\identity\fi% manger sinon exécuter: + {\def##2{##3}% fait l'assignation à la variable + ##1% le code puis + \allow@recurse{\doforeach@i{##1}##2}% recommencer + }% + }% + % ##1 = code à exécuter, ##2/##3= variables, ##4/##5=valeurs courantes + \long\def\doforeach@ii##1##2/##3##4/##5#1{% + \ifx\end@foreach##4% si la fin est atteinte + \expandafter\gobone\else\expandafter\identity\fi% manger sinon exécuter: + {\def##2{##4}\def##3{##5}% fait l'assignation des deux variables + ##1% le code puis + \allow@recurse{\doforeach@ii{##1}##2/##3}% recommencer + }% + }% + % macro qui, si elle remplace \allow@recurse, annule l'appel récursif + \long\def\forbid@recurse##1\end@foreach#1{}% tout manger jusqu'à "\end@foreach," +} +\def\doforeachexit{\global\let\allow@recurse\forbid@recurse} +\catcode`\@12 +\defseplist{,} +\doforeach\par\in{a,b,c,y,z}{$\par_i$}\medskip + +\doforeach\sujet/\terminaison\in{Je/e,Tu/es,Il/e,Nous/ons,Vous/ez,Ils/ent} + {\sujet\ programm\terminaison{} en \TeX\par}\medskip + +Les voyelles lues sont : +\doforeach\ii\in{a,e,i,o,u,y}{\ii\if o\ii\doforeachexit\fi}.\medskip + +\doforeach\xx\in{a,b,c,d,e,f} + {\doforeach\ii\in{1,2,3,4}{\xx\ii{} \ifnum\ii=3 \doforeachexit\fi}\par} +****************** Fin code ****************** + + +****************** Code 201 ****************** +\newdimen\dimA \newdimen\dimB% alloue deux registres de dimension +a) \dimA=59.5pt + \the\dimA\qquad% doit afficher 59.5pt +b) \dimA=1.5cm + \the\dimA\qquad% convertit à l'affichage 1.5cm en pt +c) \dimB=7pt % assigne 7pt à \dimB + \dimA\dimB% rend \dimA égal à dimB + \the\dimA\qquad +d) \dimA=6\dimB% rend \dimA égal à 6 fois \dimB + \the\dimA +****************** Fin code ****************** + + +****************** Code 202 ****************** +\newdimen\foo +\foo=25pt % assigne 25pt au registre \foo +\divide\foo 4 % le multiplie par 4 +\advance\foo1.72pt % lui ajoute 1.72pt +\multiply\foo3 % le multiplie par 3 +\the\foo% affiche la dimension obtenue +****************** Fin code ****************** + + +****************** Code 203 ****************** +\begingroup% ouvrir un groupe + \edef\temp{\endgroup\def\noexpand\removept##1.##2\string p\string t}% +\temp{#1\ifnum#2>0 .#2\fi}% et le fermer avant de définir \removept +\newdimen\foo +a) \foo=15pt \expandafter\removept\the\foo\qquad +b) \foo=3.14pt \expandafter\removept\the\foo +****************** Fin code ****************** + + +****************** Code 204 ****************** +\def\dimtodec{\expandafter\removept\the} +\newdimen\foo +a) \foo=15pt \dimtodec\foo \qquad +b) \foo=3.14pt \dimtodec\foo +****************** Fin code ****************** + + +****************** Code 205 ****************** +a) \the\dimexpr 1cm + 0.5cm\relax \qquad +b) \the\dimexpr 1pt + 1pt\relax \qquad +c) \the\dimexpr 1pt + 2pt * 3\relax\qquad +d) \the\dimexpr (1pt + 2pt) * 3\relax\qquad +e) \the\dimexpr (1.2pt + 0.8pt) * 5\relax\qquad +f) \newdimen\foo \foo=15pt + \the\dimexpr\foo-(\foo + 1pt) / 4\relax +****************** Fin code ****************** + + +****************** Code 206 ****************** +\the\dimexpr0,7pt + 0.4pt\relax +****************** Fin code ****************** + + +****************** Code 207 ****************** +a) \newdimen\foodim \foodim=1cm \number\foodim\relax\qquad +b) \number\dimexpr 0.7pt + 0.4pt\relax\qquad +c) \number\dimexpr 1.1pt\relax +****************** Fin code ****************** + + +****************** Code 208 ****************** +\catcode`\@11 +\def\FOR#1=#2to#3\do#4#{% + \ifempty{#4} + {\let\FOR@increment\z@} + {\edef\FOR@increment{\the\dimexpr#4pt\relax}}% lit et normalise l'argument optionnel + \ifdim\FOR@increment=\z@% s'il est nul, + \edef\FOR@increment{% le redéfinir à -1pt (si #3<#2) et 1pt sinon + \ifdim\dimexpr#3pt-#2pt\relax<\z@ -1\else 1\fi pt + }% \FOR@increment vaut donc 1 ou -1 + \fi + \ifdim\dimtodec\dimexpr#3pt-#2pt\relax\dimexpr\FOR@increment\relax<\z@ + \expandafter\gobone% si argument optionnel incompatible, manger le {<code>} + \else + \edef#1{\dimtodec\dimexpr#2pt\relax}% initialise la \<macro> + \edef\macro@args{% définit et développe les arguments à passer à \FOR@i + %#1=nom de la macro récursive : + \expandafter\noexpand\csname FOR@ii@\string#1\endcsname + \ifdim\FOR@increment<\z@ <\else >\fi% #2=signe de comparaison + {\FOR@increment}% #3=incrément + \noexpand#1% #4=\<macro> + {\the\dimexpr#3pt\relax}% #5=dimension n2 + }% + \antefi% externalise la ligne ci-dessous de la portée du test + \expandafter\FOR@i\macro@args% appelle \FOR@i avec les arguments définis ci-dessus + \fi +} + +% #1=nom de la macro récursive de type "\FOR@ii@\<macro>" +% #2=signe de comparaison % #3=incrément +% #4=\<macro> % #5=dimension n2 % #6=<code> à exécuter +\long\def\FOR@i#1#2#3#4#5#6{% + \def#1{% définit la sous macro récursive + \unless\ifdim#4pt#2#5\relax% tant que la \<macro> variable n'a pas dépassé n2 + \afterfi{% rendre la récursivité terminale + #6% exécute le code + \edef#4{\dimtodec\dimexpr#4pt+#3\relax}% incrémente la \<macro> + #1% recommence + }% + \fi + }% + #1% appelle la sous-macro récursive +}% +\def\exitFOR#1{% #1=\<macro> correspondant à la boucle de laquelle on veut sortir + \defname{FOR@ii@\string#1}{}% +} + +\def\ifexitFOR#1{% envoie vrai si on est prématurément sorti de la boucle de \<macro> #1 + % si la macro récursive est \empty + \expandafter\ifx\csname FOR@ii@\string#1\endcsname\empty + \expandafter\firstoftwo% c'est qu'on est sortir prématurément, renvoyer "vrai" + \else + \expandafter\secondoftwo% sinon, renvoyer "faux" + \fi +} +\catcode`\@=12 +a) \FOR\xx=1.5 to -5\do-1{"\xx" }\par + +b) \FOR\ii=1 to 2.742\do.25{"\ii" }\par + +c) \FOR\ii=0 to 1\do0.1{"\ii" \ifdim\ii pt>0.5pt \exitFOR\ii\fi} +****************** Fin code ****************** + + +****************** Code 209 ****************** +\newdimen\foo +\foo=15.2pt \foo=1.5\foo \the\foo% vaut 15.2*1.5 +****************** Fin code ****************** + + +****************** Code 210 ****************** +\catcode`\@11 +\newdimen\dim@a +\def\decmul#1#2{% + \dim@a=#2pt % range la dimension #2pt dans le registre de dimension + \dim@a=#1\dim@a% multiplier le registre par le décimal #1 + \dimtodec\dim@a% convertir la dimension en décimal +} +\catcode`\@12 +a) \decmul{15.2}{1.5}\qquad +b) \decmul{48.2}{.375} +****************** Fin code ****************** + + +****************** Code 211 ****************** +\def\decmul#1#2{\dimtodec\dimexpr#1\dimexpr#2pt\relax\relax} + +a) \decmul{15.2}{1.5}\qquad +b) \edef\foo{\decmul{48.2}{.375}}\meaning\foo +****************** Fin code ****************** + + +****************** Code 212 ****************** +\def\decdiv#1#2{% divise le décimal #1 par le décimal #2 + \dimtodec + \dimexpr + \numexpr + \dimexpr #1pt \relax * 65536 / \dimexpr #2pt \relax + \relax + sp + \relax +} + +1) \decdiv{4.5}{0.075}\qquad% doit donner 60 +2) \decdiv{8}{0.1}\qquad% doit donner 80 +3) \decdiv{3.14}{1.6}\qquad% doit donner 1.9625 +4) \decdiv{687.59829}{5.29871}\qquad% doit donner 129.76706 +4) \edef\foo{\decdiv{0.37}{2.5}}\foo% doit donner 0.148 +****************** Fin code ****************** + + +****************** Code 213 ****************** +\def\convertunit#1#2{% + \dimtodec + \dimexpr + \numexpr + \dimexpr #1 \relax * 65536 / \dimexpr 1#2 \relax + \relax + sp + \relax +} + +a) \convertunit{15cm}{mm}\qquad +b) \convertunit{9,14in}{cm}\qquad +c) \convertunit{100000sp}{mm}\qquad +d) \convertunit{160.5pt}{cm}\qquad +e) \edef\foo{\convertunit{2,5cm}{cc}}\meaning\foo +****************** Fin code ****************** + + +****************** Code 214 ****************** +\the\glueexpr 5pt plus 2pt minus 1.5pt + 7pt plus0.5pt minus 3pt\relax \par +\the\glueexpr 25pt plus2fil + 35pt plus 0.1fill\relax +****************** Fin code ****************** + + +****************** Code 215 ****************** +foo% les caractères font entrer TeX en mode horizontal +\kern0.5cm % espace insérée en mode horizontal +bar\par% \par fait passer en mode vertical +\kern0.5cm % espace insérée en mode vertical +boo +****************** Fin code ****************** + + +****************** Code 216 ****************** +Une première ligne\par +\nointerlineskip% n'insère pas de ressort d'interligne ici +Un second paragraphe constitué de plusieurs lignes. +Un second paragraphe constitué de plusieurs lignes. +Un second paragraphe constitué de plusieurs lignes. +\par% le ressort d'interligne sera inséré ici +Une dernière ligne +****************** Fin code ****************** + + +****************** Code 217 ****************** +\begingroup +\offinterlineskip +La macro \litterate-\offinterlineskip-, en modifiant de façon appropriée les trois +primitives \litterate-\baselineskip-, \litterate-\lineskip- et +\litterate-\lineskiplimit-, rend les boites consécutives jointives. + +On peut constater dans ces deux paragraphes où \litterate-\offinterlineskip- a été +appelée, que les lignes sont placées verticalement au plus près les unes des autres ce +qui rend la lecture très pénible et démontre que le ressort d'interligne est une +nécessité typographique !\par +\endgroup +Désactiver le ressort d'interligne ne se justifie que lorsque l'on doit composer +des boites contenant autre chose que du texte, sauf à vouloir des effets +typographiques spéciaux. +****************** Fin code ****************** + + +****************** Code 218 ****************** +\baselineskip=12pt +début \vtop{\hbox{ligne du haut ligne du haut ligne du haut} +\hbox{ligne du bas ligne du bas ligne du bas} +} +\par +Et la suite du texte suite du texte suite du texte +****************** Fin code ****************** + + +****************** Code 219 ****************** +\baselineskip=12pt +début \vtop{\hbox{ligne du haut ligne du haut ligne du haut} +\hbox{ligne du bas ligne du bas ligne du bas} +\xdef\sprevdepth{\the\prevdepth}% sauvegarde la valeur de \prevdepth +} +\par\prevdepth=\sprevdepth\relax% ment sur la boite précédente +Et la suite du texte suite du texte suite du texte +****************** Fin code ****************** + + +****************** Code 220 ****************** +\def\dummytext{Voici un texte qui ne revêt aucune importance + et dont le seul but est de meubler artificiellement un paragraphe. } +\begingroup% à l'intérieur d'un groupe, + \leftskip=0pt plus 0.5\hsize\relax + \rightskip=\leftskip\relax % modifier les ressort d'extrémités + \spaceskip=0.3em plus 0.05em\relax% dimension de l'espace intermot + \parfillskip=0pt \relax% annuler le ressort de fin de paragraphe + \dummytext\dummytext\dummytext% corps du paragraphe + \par% compose la paragraphe courant + Juste une phrase% + \par% compose la paragraphe courant +\endgroup% avant de sortir du groupe +****************** Fin code ****************** + + +****************** Code 221 ****************** +\def\narrowtext{% + \par + \begingroup + \advance\leftskip 0.1\hsize + \advance\rightskip 0.1\hsize +} +\def\endnarrowtext{\par\endgroup} +\def\dummytext{Ceci est un texte sans + importance destiné à meubler un paragraphe. } + +\dummytext\dummytext\dummytext +\narrowtext + \dummytext\dummytext\dummytext + \narrowtext + \dummytext\dummytext\dummytext + \endnarrowtext + \dummytext\dummytext\dummytext +\endnarrowtext +****************** Fin code ****************** + + +****************** Code 222 ****************** +a) \hfill Composition au fer à droite\par +b) Composition au fer à gauche\hfill\kern0pt\par +c) \hfill Centrage\hfill\kern0pt\par +d) Des \hfill mots\hfill régulièrement\hfill espacés +****************** Fin code ****************** + + +****************** Code 223 ****************** +a% le caractère "a" fait passer en mode horizontal +\hbox{b}c\hbox{d}% les \hbox sont ajoutées en mode horizontal +\medbreak +...à comparer avec... +\medbreak +a \par% \par fait passer en mode vertical +\hbox{b}% \hbox est ajoutée à la liste verticale +c% "c" fait passer en mode horizontal +\hbox{d}% la \hbox est ajoutée en mode horizontal +****************** Fin code ****************** + + +****************** Code 224 ****************** +Ligne de base : .........% +\vbox{\hbox{ligne du haut}\hbox{ligne du milieu}\hbox{ligne du bas}}% +.........% +\vtop{\hbox{ligne du haut}\hbox{ligne du milieu}\hbox{ligne du bas}}......... +****************** Fin code ****************** + + +****************** Code 225 ****************** +\def\dummytext{Bla, bla, bla, un texte sans importance. } +Ligne de base.........% +\vbox{\hsize=4cm \dummytext\dummytext}% +.........% +\vtop{\hsize=4cm \dummytext\dummytext}......... +****************** Fin code ****************** + + +****************** Code 226 ****************** +\newbox\foobox +a) \setbox\foobox=\hbox{foobar}% registre non vide + Le registre est \ifvoid\foobox vide\else non vide\fi\par +b) \setbox\foobox=\hbox{foobar} + "\box\foobox" et le registre est \ifvoid\foobox vide\else non vide\fi\par +c) \setbox\foobox=\hbox{foobar} + "\copy\foobox" et le registre est \ifvoid\foobox vide\else non vide\fi\par +d) \setbox\foobox=\hbox{} + Le registre est \ifvoid\foobox vide\else non vide\fi +****************** Fin code ****************** + + +****************** Code 227 ****************** +\newbox\foobox +\setbox\foobox=\hbox{Programmer est facile.} +<<\copy\foobox>> +mesure \the\wd\foobox\ de long, \the\dp\foobox\ de profondeur et \the\ht\foobox\ de haut. +\medbreak + +\setbox\foobox=\vbox{\hbox{Programmer}\hbox{est}\hbox{facile.}} +<<\copy\foobox>> +mesure \the\wd\foobox\ de long, \the\dp\foobox\ de profondeur et \the\ht\foobox\ de haut. +\medbreak + +\setbox\foobox=\vtop{\hbox{Programmer}\hbox{est}\hbox{facile.}} +<<\copy\foobox>> +mesure \the\wd\foobox\ de long, \the\dp\foobox\ de profondeur et \the\ht\foobox\ de haut. +****************** Fin code ****************** + + +****************** Code 228 ****************** +\def\vdim#1{\dimexpr\ht#1+\dp#1\relax} +a) \setbox\foobox=\vbox{\hbox{Programmer}\hbox{est}\hbox{facile.}} + Verticalité de la \litterate-\vbox- = \the\vdim\foobox\par +b) \setbox\foobox=\vtop{\hbox{Programmer}\hbox{est}\hbox{facile.}} + Verticalité de la \litterate-\vtop- = \the\vdim\foobox +****************** Fin code ****************** + + +****************** Code 229 ****************** +\def\countallchar#1{% + Il y a % + \setbox0=\hbox{\tt#1}% met #1 dans la boite + \edef\arglength{\number\wd0 }% stocke la largeur de la boite en sp + \setbox0=\hbox{\tt A}% met "A" dans la boite + \edef\charlength{\number\wd0 }% stocke la largeur d'un caractère + $\number\arglength/\charlength % affiche la division + =\number\numexpr\arglength/\charlength\relax$ % affiche le quotient + caractères% +} +\countallchar{abcd efgh}\par +\countallchar{A5 xW5 64 a1}\par +\countallchar{affligeant} +****************** Fin code ****************** + + +****************** Code 230 ****************** +\catcode`@11 +\def\countchar#1#2{% + \setbox\z@\hbox{\tt#2}% met #2 dans boite 0 + \edef\len@a{\number\wd\z@}% mesure la boite + \setbox\z@\hbox{\tt\substin{#2}{#1}{}}% recommencer sans "#1" + \edef\len@b{\number\wd\z@}% mesure la boite + \setbox\z@\hbox{\tt A}% met "A" dans la boite + \edef\charlength{\number\wd\z@}% stocke la largeur du caractère + \number\numexpr(\len@a-\len@b)/\charlength% et affiche le quotient +} +\catcode`@12 +a) \countchar{a}{abracadabra}\qquad +b) \countchar{b}{zigzag}\qquad +c) \countchar{ }{a bc de f ghi j k } +****************** Fin code ****************** + + +****************** Code 231 ****************** +Programmer \raise1ex\hbox{en} \lower1ex\hbox{\TeX} \lower2ex\hbox{est} facile. +****************** Fin code ****************** + + +****************** Code 232 ****************** +\def\cbox#1{% + \setbox0\vbox{#1}% met le contenu dans une \vbox + \lower\dimexpr(\ht0-\dp0)/2\relax\box0 % l'abaisse +} + +......\cbox{\hbox{$x^2$}}......\cbox{\hbox{foo}\hbox{et bar}}......% +\cbox{\hbox{Programmer}\hbox{en \TeX}\hbox{est facile}}....... +****************** Fin code ****************** + + +****************** Code 233 ****************** +......\cbox{\hbox{foo}\hbox{et bar}}......$\vcenter{\hbox{foo}\hbox{et bar}}$...... +****************** Fin code ****************** + + +****************** Code 234 ****************** +\def\htmath{\begingroup + \setbox0=\hbox{$\vcenter{}$}\the\ht0 +\endgroup +} +L'axe mathématique se trouve à \htmath{} de la ligne de base. +****************** Fin code ****************** + + +****************** Code 235 ****************** +1) \hbox{foobar}\par +2) \hbox spread 5pt{foo\hfil bar}\par +3) \hbox spread10pt{foo\hfil bar} +****************** Fin code ****************** + + +****************** Code 236 ****************** +foobar|\rlap{/////}123456\qquad foobar|\llap{/////}123456 +****************** Fin code ****************** + + +****************** Code 237 ****************** +\def\clap#1{\hbox to0pt{\hss#1\hss}} +a) avant la macro|\clap{SURIMPRESSION}après la macro\medbreak +b) avant la macro|\raise2.5ex\clap{Au-dessus}\lower2.5ex\clap{Au-dessous}% + après la macro\medbreak +c) avant la macro|\raise2.5ex\llap{Au-dessus avant}\lower2.5ex\rlap{Au-dessous après}% + après la macro +****************** Fin code ****************** + + +****************** Code 238 ****************** +\setbox0=\hbox{\tt//////////} +\wd0=0pt % fait croire à TeX que la larguer de la boite est nulle +Voici \copy0 du texte partiellement barré... +****************** Fin code ****************** + + +****************** Code 239 ****************** +\def\printdim{largeur=\the\wd0 \qquad hauteur=\the\ht0 \qquad profondeur = \the\dp0 } +\setbox0=\hbox{Programmer en \TeX{} est facile} +a) \printdim\par +b) \wd0=0pt \ht0=0pt \dp0=0pt% rend toutes le dimensions nulles + \printdim\par +c) \setbox0=\hbox{\unhbox0 }% reprend les dimensions d'origine + \printdim +****************** Fin code ****************** + + +****************** Code 240 ****************** +\setbox0=\hbox{}% le registre 0 contient une boite vide +Le registre \ifvoid0 est vide\else n'est pas vide\fi +****************** Fin code ****************** + + +****************** Code 241 ****************** +\catcode`\@11 +\def\ifzerodimbox#1{% #1=registre de boite +% revoie vrai si le registre est vide ou contient une boite de dimensions nulles + \csname% former la macro "\firstoftwo" ou "\secondoftwo" + \ifvoid#1first%% si le registre est vide "first" + \else% sinon + \ifdim\wd#1=\z@% si la largeur + \ifdim\ht#1=\z@% la hauteur + \ifdim\dp#1=\z@ first% et la profondeur=0pt, "first" + \else second% dans les autres cas "second" + \fi + \else second% + \fi + \else second% + \fi + \fi + oftwo% compléter avec "oftwo" + \endcsname +} +\catcode`\@12 +a) \setbox0=\hbox{}\ifzerodimbox0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par +b) \box0 % affiche la boite vide, le registre est maintenant "void" + \ifzerodimbox0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par +c) \setbox0=\hbox{x}\ifzerodimbox0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par +d) \wd0=0pt \ht0=0pt \dp0=0pt % rend toutes les dimensions nulles + \ifzerodimbox0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par +e) \setbox0=\vbox{}\ifzerodimbox0{vrai}{faux} (et \ifvoid0 void\else non void\fi) +****************** Fin code ****************** + + +****************** Code 242 ****************** +\def\ifvoidorempty#1{% teste si le registre #1 est vide ou contient une boite vide + \ifvoid#1\relax + \expandafter\firstoftwo + \else + \begingroup% dans un groupe + \setbox0=% affecter à la boite 0 + \ifhbox#1\hbox\bgroup\unhcopy% un boite horizontale + \else \vbox\bgroup\unvcopy% ou verticale + \fi% dans laquelle on compose + #1\relax% #1 en dimensions naturelles + \expandafter\egroup% sauter la fin de la boite + \expandafter% et le \endgroup + \endgroup + \ifnum\lastnodetype=-1 % et tester si le dernier noeud est vide + \expandafter\expandafter\expandafter\firstoftwo + \else + \expandafter\expandafter\expandafter\secondoftwo + \fi + \fi +} +a) \setbox0=\hbox{}\ifvoidorempty0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par +b) \box0 % affiche la boite vide, le registre est maintenant "void" + \ifvoidorempty0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par +c) \setbox0=\hbox{x}\ifvoidorempty0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par +d) \wd0=0pt \ht0=0pt \dp0=0pt % rend toutes les dimensions nulles + \ifvoidorempty0{vrai}{faux} (et \ifvoid0 void\else non void\fi)\par +e) \setbox0=\vbox{}\ifvoidorempty0{vrai}{faux} (et \ifvoid0 void\else non void\fi) +****************** Fin code ****************** + + +****************** Code 243 ****************** +\newdimen\hmaxsize +\def\cvtop#1{% + \hmaxsize=-\maxdimen% initialise à la plus petite longueur + \doforeach\htext\in{#1}% pour chaque élément : + {\setbox0=\hbox{\htext}% stocker l'élément "\htext" dans une \hbox + \ifdim\wd0 >\hmaxsize% si sa longueur est supérieure à \hmaxsize + \hmaxsize=\wd0 % mettre à jour \hmaxsize + \fi + }% + \vtop{% dans une \vtop... + \doforeach\htext\in{#1}% pour chaque élément : + {\hbox to\hmaxsize{\hss\htext\hss}% le centrer dans une \hbox de longueur \hmaxsize + }% + }% +} + +texte avant...\cvtop{Ligne du haut,Très grande ligne du milieu,Ligne du bas pour finir}% +...texte après +****************** Fin code ****************** + + +****************** Code 244 ****************** +\newdimen\hmaxsize +\def\cvtop#1{% + \hmaxsize=-\maxdimen% initialise à la plus petite longueur + \doforeach\htext\in{#1}% pour chaque élément : + {\setbox0=\hbox{\htext}% stocker l'élément "\htext" dans une \hbox + \ifdim\wd0 >\hmaxsize% si sa longueur est supérieure à \hmaxsize + \hmaxsize=\wd0 % mettre à jour \hmaxsize + \fi + }% + \vtop{% dans une \vtop... + \hsize\hmaxsize % longueur de la \vtop = \maxhsize + \parindent=0pt % pas d'indentation + \leftskip=0pt plus1fil minus0pt \rightskip=\leftskip% ressorts de centrage + \doforeach\htext\in{#1}% pour chaque élément : + {\htext\par}% le composer et finir le paragraphe + }% +} + +texte avant...\cvtop{Ligne du haut,Très grande ligne du milieu,Ligne du bas pour finir}% +...texte après +****************** Fin code ****************** + + +****************** Code 245 ****************** +\halign{X#**\ignorespaces&#&\hfil #\cr % préambule +foo &foo bar&123 456\cr % première ligne +deuxième ligne &1 &12\cr % deuxième ligne +a &\TeX &1 2 3 4 5 6\cr % troisième ligne +\crcr} +****************** Fin code ****************** + + +****************** Code 246 ****************** +\def\cvtop#1{% + \vtop{% \vtop assure que l'on est en mode vertical + \substtocs\temp{#1}{,}{\cr}% dans \temp, remplacer les "," par "\cr" + \halign{% + \hfil##\hfil\cr% préambule : centrer le contenu + \temp\crcr}% mettre \temp dans l'alignement + }% \temp est détruite en sortant de la boite +} + +texte avant...\cvtop{Ligne du haut,Très grande ligne du milieu,Ligne du bas pour finir}% +...texte après +****************** Fin code ****************** + + +****************** Code 247 ****************** +\def\calcmaxdim#1#2{% + \setbox0=\vtop{% \vtop assure que l'on est en mode vertical (interne) + \substtocs\temp{#2}{,}{\cr}% dans \temp, remplacer les "," par "\cr" + \halign{##\hfil\cr% préambule : composer au fer à gauche + \temp\crcr}% mettre \temp dans l'alignement + }% \temp est détruite en sortant de la boite + \edef#1{\the\wd0 }% +} +a) La plus grande longueur vaut + \calcmaxdim\foo{Ligne du haut,Très grande ligne du milieu,Ligne du bas pour finir}\foo + +b) Vérification : \setbox0=\hbox{Très grande ligne du milieu}\the\wd0 +****************** Fin code ****************** + + +****************** Code 248 ****************** +a) .......\vbox{\hrule\hbox{foo}\hbox{ligne du bas}\hrule}.......\medbreak +b) .......\vrule\vtop{\hbox{foo}\hbox{ligne du bas}}\vrule....... +****************** Fin code ****************** + + +****************** Code 249 ****************** +Une réglure de 1.5cm :\hrule width1.5cm +foo\vrule width 2pt height .5cm depth .2cm bar +****************** Fin code ****************** + + +****************** Code 250 ****************** +\def\showdim#1{% + \vrule width 0.4pt height 1ex depth 0pt % trait vertical gauche + \vrule width #1 height0.4pt depth 0pt % réglure horizontale de longueur #1 + \vrule width 0.4pt height 1ex depth 0pt % trait vertical droit + \relax% stoppe la lecture de la précédente dimension +} + +a) une longueur de 1 cm : \showdim{1cm}\par +b) une longueur de 137,4 pt : \showdim{137,4pt}\par +c) une longueur de 2 mm : \showdim{2mm} +****************** Fin code ****************** + + +****************** Code 251 ****************** + +\frboxsep=5pt \frboxrule=1pt +\leavevmode +...% +\vbox{% + \hrule height\frboxrule% réglure supérieure + \kern\frboxsep% espace verticale haute + \hbox{\kern\frboxsep Programmation\kern\frboxsep}% contenu + espaces horizontales + \kern\frboxsep% espace verticale basse + \hrule height\frboxrule% réglure inférieure + }% +... +****************** Fin code ****************** + + +****************** Code 252 ****************** + +\frboxsep=5pt \frboxrule=0.6pt +\def\FRbox#1{% /!\ ne change pas le mode H ou V en cours + \hbox{% mettre à la suite horizontalement les 3 choses suivantes : + \vrule width\frboxrule% 1) réglure gauche + \vbox{% 2) un empilement vertical comprenant + \hrule height\frboxrule% a) réglure supérieure + \kern\frboxsep% b) espace verticale haute + \hbox{% c) contenu + espaces en mode H + \kern\frboxsep#1\kern\frboxsep + }% + \kern\frboxsep% d) espace verticale basse + \hrule height\frboxrule% e)réglure inférieure + }% + \vrule width\frboxrule% 3) réglure droite + }% +} +Ligne de base : ...\FRbox{Programmation}...% +\frboxrule=2pt \FRbox{Programmation}...% +\frboxsep=0pt \FRbox{Programmation}...% +\frboxrule0.4pt \FRbox{Programmation}... +****************** Fin code ****************** + + +****************** Code 253 ****************** +Persuadez-vous que : +\vtop{ + \vbox{ + \hbox{Programmer} + \hbox{en} + \hbox{\TeX} + \hbox{est}% <- ligne de base de la \vtop + } + \hbox{\it tout sauf} + \hbox{facile.} +} +****************** Fin code ****************** + + +****************** Code 254 ****************** +%\newdimen\frboxrule \newdimen\frboxsep +\frboxrule=0.4pt \frboxsep=2pt +\def\frbox#1{% ne pas changer le mode H ou V en cours + \hbox{% enferme dans une \hbox + \vrule width\frboxrule% réglure gauche + \vtop{% + \vbox{% 1er élément de la \vtop + \hrule height\frboxrule% réglure supérieure + \kern\frboxsep% espace haut + \hbox{% + \kern\frboxsep% espace gauche + #1% contenu + \kern\frboxsep% espace droite + }% + }% puis autres éléments de la \vtop, sous la ligne de base + \kern\frboxsep% espace bas + \hrule height\frboxrule% réglure inférieure + }% + \vrule width\frboxrule% réglure droite + }% +} +Ligne de base : ......\frbox{Programmation}......% +\frboxrule=2pt \frbox{Programmation}......% +\frboxsep=0pt \frbox{Programmation}......% +\frboxrule0.4pt \frbox{Programmation}...... +****************** Fin code ****************** + + +****************** Code 255 ****************** +\def\centretitre#1{% + \medbreak% passe en mode v puis saute une espace verticale + \noindent% pas d'indentation et passe en mode horizontal + \frbox{% encadre + \vbox{% une boite verticale + \hsize=\dimexpr\hsize-2\frboxrule-2\frboxsep\relax + \parindent=0pt % pas d'indentation + \leftskip=0pt plus1fil \rightskip=\leftskip% ressorts de centrage + \parfillskip=0pt % annule le ressort de fin de paragraphe + #1% insère le titre + \endgraf% et le compose + }% + }% + \medbreak% passe en mode v puis saute une espace verticale + \ignorespaces% mange les espaces situés après la macro \centretitre +} +\frboxrule=0.8pt \frboxsep=5pt +Voici un +\centretitre{Titre} +puis un +\centretitre{Texte très long pour composer un titre qui va prendre plusieurs +lignes et pour s'assurer que la composition s'effectue correctement} +****************** Fin code ****************** + + +****************** Code 256 ****************** +Une réglure en hauteur : \vrule width 1cm height 10.4pt depth -10pt +****************** Fin code ****************** + + +****************** Code 257 ****************** +Une réglure en dessous: \vrule width 1cm depth 2.4pt height -2pt +****************** Fin code ****************** + + +****************** Code 258 ****************** +\def\souligne#1{% + \setbox0=\hbox{#1}% stocke le contenu dans le registre no 0 + \setbox0=\hbox{% puis, dans une \hbox, construit une réglure + \vrule width\wd0 % de la longueur du contenu + depth\dimexpr\dp0 + 1.4pt\relax % dp = profondeur texte + 1.4pt + height\dimexpr-\dp0 - 1pt\relax % ht = -profondeux texte - 1pt + }% + \wd0=0pt \dp0=0pt \ht0=0pt % annule toutes les dimensions + \leavevmode \box0 % affiche la réglure + #1% puis le contenu +} +Voici \souligne{du texte normal}.\par +Voici \souligne{du texte profond}. +****************** Fin code ****************** + + +****************** Code 259 ****************** +\def\Souligne#1{% + \setbox0=\hbox{#1}% + \setbox0=\hbox{\vrule width\wd0 depth1.4pt height-1pt }% + \wd0=0pt \dp0=0pt \ht0=0pt + \leavevmode \box0 #1% +} +Voici \Souligne{du texte normal}.\par +Voici \Souligne{du texte profond}. +****************** Fin code ****************** + + +****************** Code 260 ****************** +\def\Souligne#1{% + \setbox0=\hbox{#1}% + \lower 1pt % abaisser à 1pt sous la ligne de base + \rlap{% une \hbox en surimpression vers la droite + \vrule width\wd0 height0pt depth0.4pt % contenant le soulignement + }% + #1% puis afficher le <texte> +} +Voici \Souligne{du texte normal}.\par +Voici \Souligne{du texte profond}. +****************** Fin code ****************** + + +****************** Code 261 ****************** +\newdimen\stackwd \stackwd=3em % dimension horizontale interne des cadres +\catcode`@11 +\def\stackbox#1{% + \par% termine le paragraphe en cours + \noindent + \stackbox@i#1\\\quark\\% ajoute "\\\quark\\" à la fin et appelle \stackbox@i + \par +} + +\def\stackbox@i#1\\{% #1=ligne courante + \def\temp@{#1}% stocke la ligne courante + \unless\ifx\quark\temp@% si ce n'est pas la fin + \hfill % ressort infini de centrage (et fait passer en mode horizontal) + \noindent + \doforeach\current@item\in{#1}% pour chaque élément dans la ligne courante... + {\frbox{% ...encadrer + \hbox to\stackwd{% une \hbox de largeur \stackwd + \hss% ressort de centrage + \current@item% l'élément courant + \hss% ressort de centrage + } + }% fin de la \frbox + }% fin \doforeach + \hfill% ressort infini de centrage + \null% assure que le dernier ressort est pris en compte + \par% finir le paragraphe + \nobreak% interdire une coupure de page + \nointerlineskip% ne pas insérer le ressort d'interligne + \expandafter\stackbox@i% et recommencer + \fi +} +\catcode`@12 + +\frboxrule=0.5pt \frboxsep=3pt +\stackbox{a,bc,,d\\e,foobar,g\\123,456,$\alpha$,$x+y$,} +****************** Fin code ****************** + + +****************** Code 262 ****************** +a\vrule width0.2pt height15pt depth0pt \quad +a\vrule width0.2pt height0pt depth5pt \quad +a\vrule width0.2pt height10pt depth10pt \quad +a\vrule width1cm height0.2pt depth0pt +****************** Fin code ****************** + + +****************** Code 263 ****************** +\frboxsep0pt %encadrement au plus proche +\leavevmode +\frbox{a\vrule width0pt height15pt depth0pt }\quad +\frbox{a\vrule width0pt height0pt depth5pt }\quad +\frbox{a\vrule width0pt height10pt depth10pt }\quad +\frbox{a\vrule width1cm height0pt depth0pt } +****************** Fin code ****************** + + +****************** Code 264 ****************** +\def\rectangle#1#2{% + \begingroup% dans un groupe + \frboxsep = 0pt % encadrer au plus proche + \frboxrule= 0.4pt % en traits assez fins + \frbox{% + \vrule width#1 height0pt depth0pt %strut horizontal + \vrule width0pt height#2 depth0pt %strut vertical + }% + \endgroup% fermer le groupe +} +Carré de 0.5 cm : \rectangle{0.5cm}{0.5cm}\smallskip + +Rectangle de 2.5cm par 3pt : \rectangle{2.5cm}{3pt} +****************** Fin code ****************** + + +****************** Code 265 ****************** +\newdimen\stackwd \stackwd=3em +\catcode`\@11 +\def\stackbox#1{% + \par% termine le paragraphe en cours + \begingroup% dans un groupe semi-simple + \parindent=0pt% pas d'indentation + \parskip=0pt% annuler le \parskip + \setbox0\hbox{Àgjp}% boite pour le strut + \edef\stack@strut{\vrule width\z@ height\the\ht0 depth\the\dp0 }% définit le strut + \stackbox@i#1\\\quark\\% ajoute "\\\quark\\" à la fin et appelle \stackbox@i + \unkern% annule la dernière compensation verticale + \par + \endgroup +} +\def\stackbox@i#1\\{% #1=ligne courante + \def\temp@{#1}% stocke la ligne courante + \unless\ifx\quark\temp@% si ce n'est pas la fin + \hfill % ressort infini de centrage (passe en mode horizontal) + \doforeach\current@item\in{#1}% pour chaque élément dans la ligne courante... + {\frbox{% ...encadrer + \hbox to\stackwd{% une \hbox de largeur \stackwd contenant + \hss% 1) ressort de centrage + \stack@strut% 2) strut de dimension verticale + \current@item%3) l'élement courant + \hss}% 4)ressort de centrage + }% fin de la \fbox + \kern-\frboxrule% revenir en arrière pour superposer les réglures verticales + }% fin de \doforeach + \unkern% annuler la dernière compensation horizontale + \hfill% ressort infini de centrage + \null% fait prendre en compte le dernier ressort + \par% termine le paragraphe + \nobreak% interdit une coupure de page + \nointerlineskip% sinon, ne pas ajouter le ressort d'interligne + \kern-\frboxrule% superposer les réglures horizontales + \expandafter\stackbox@i% et recommencer + \fi +} +\frboxrule=0.5pt +\frboxsep=3pt +\stackbox{a,bc,,d\\e,foobar,g\\123,456,$\alpha$,$x+y$,} +****************** Fin code ****************** + + +****************** Code 266 ****************** +\catcode`\@11 +\def\lineboxed#1{% + \par% termine le paragraphe en cours + \begingroup% dans un groupe semi-simple + \parindent=0pt% pas d'indentation + \parskip=0pt% annuler le \parskip + \setbox0\hbox{Àgjp}% boite pour le strut + \edef\stack@strut{\vrule width\z@ height\the\ht0 depth\the\dp0 }% définit le strut + \lineboxed@i#1\\\quark\\% ajoute "\\\quark\\" à la fin et appelle la macro récursive + \unkern% annule la dernière compensation verticale + \par + \endgroup +} +\def\lineboxed@i#1\\{% #1=ligne courante + \def\temp@{#1}% stocke la ligne courante + \unless\ifx\quark\temp@% si ce n'est pas la fin + \cnttimestocs{#1,}{,}\nb@args% reçoit le nombre d'arguments dans la ligne courante + \edef\dim@box{\the\dimexpr(\hsize-\frboxrule*(\nb@args+1)- + \frboxsep*2*\nb@args)/\nb@args}% + \hbox{% + \doforeach\current@item\in{#1}% pour chaque élément dans la ligne courante... + {\frbox{% ...encadrer + \hbox to\dim@box{% une \hbox de largeur \dim@box contenant + \hss% 1) ressort de centrage + \stack@strut% 2) strut de dimension verticale + \current@item%3) l'élement courant + \hss}% 4)ressort de centrage + }% fin de la \fbox + \kern-\frboxrule% revenir en arrière pour superposer les réglures verticales + }% fin de \doforeach + \unkern% annuler la dernière compensation horizontale + }% + \par% termine le paragraphe + \nobreak% interdit une coupure de page + \nointerlineskip% sinon, ne pas ajouter le ressort d'interligne + \kern-\frboxrule% superposer les réglures horizontales + \expandafter\lineboxed@i% et recommencer + \fi +} +\catcode`\@12 +\lineboxed{a,bc,,d\\e,foobar,g\\123,456,$\alpha$,$x+y$,}\medbreak + +\frboxrule=1.5pt +\frboxsep=3pt +\lineboxed{,,,,,,,\\,,\\,,,,,,} +****************** Fin code ****************** + + +****************** Code 267 ****************** +\xunit=0.5cm \yunit=0.5cm \mainrule=0.8pt \subrule=0.2pt +\def\vlap#1{\vbox to0pt{\vss#1\vss}} +\catcode`@11 +\def\grid#1#2#3#4{% + \vbox{% empiler les éléments verticalement + \offinterlineskip% pas de ressort d'interligne + \edef\total@wd{\the\dimexpr\xunit*#1\relax}% largeur totale ds réglures + \for\ii = 1 to #3 \do1% pour chaque carreau vertical (\ii=variable muette) + {\vlap{\hrule width\total@wd height\mainrule}% tracer la réglure horizontale + \kern\yunit% insérer l'espace vertical + }% + \vlap{\hrule width\total@wd height\mainrule}% dernière réglure horizontale + }% +} +\catcode`@12 +\setbox0\hbox{\grid{4}{}{3}{}}% range la quadrillage dans le registre no 0 +Essai \copy0{} qui a pour +largeur=\convertunit{\wd0}{cm} cm et pour hauteur=\convertunit{\ht0}{cm} cm +****************** Fin code ****************** + + +****************** Code 268 ****************** +Début\vbox to0pt{\hbox{sous}\hbox{la ligne de base}\vss}suite +****************** Fin code ****************** + + +****************** Code 269 ****************** +\xunit=0.5cm \yunit=0.5cm \mainrule=0.8pt \subrule=0.2pt +\def\vlap#1{\vbox to0pt{\vss#1\vss}} +\catcode`@11 +\def\grid#1#2#3#4{% + \vbox{% empiler les éléments verticalement + \offinterlineskip% pas de ressort d'interligne + \edef\total@wd{\the\dimexpr\xunit*#1\relax}% largeur totale de la boite + \edef\sub@unit{\the\dimexpr\yunit/#4\relax}% hauteur verticale de la subdivision + \for\ii = 1 to #3 \do% pour chaque unité verticale en partant du haut, tracer : + {\vlap{\hrule width\total@wd height\mainrule}% la réglure horizontale principale + % et dessous, les réglures horizontales secondaires : + \vbox to\z@{% dans une \vbox de hauteur nulle, + \for\jj = 2 to #4 \do 1% insérer #4-1 fois sous la position courante : + {\kern\sub@unit % l'espace verticale + \vlap{\hrule width\total@wd height\subrule}% et la réglure secondaire + }% + \vss% ressort qui se comprime pour satisfaire la hauteur nulle + }% + \kern\yunit% insérer l'espace vertical entre réglures principales + }% + \vlap{\hrule width\total@wd height\mainrule}% dernière réglure principale du bas + }% +} +\catcode`@12 +\setbox0=\hbox{\grid{4}{}{3}{5}} +Essai \copy0{} qui a pour +largeur=\convertunit{\wd0}{cm} cm et pour hauteur=\convertunit{\ht0}{cm} cm +****************** Fin code ****************** + + +****************** Code 270 ****************** +\mainrule=0.8pt \subrule=0.2pt +\def\vlap#1{\vbox to0pt{\vss#1\vss}} +\catcode`@11 +\def\grid#1#2#3#4{% + \vbox{% empiler les éléments verticalement + \offinterlineskip% pas de ressort d'interligne + % #################### Tracé des réglures verticales #################### + \vbox to\z@{% dans une \vbox de hauteur nulle + \edef\total@ht{\the\dimexpr\yunit*#3\relax}% hauteur totale + \edef\sub@unit{\the\dimexpr\xunit/#2\relax}% espace entre 2 subdivisions + \rlap{% mettre à droite de la position sans bouger + \for\ii = 1 to #1 \do 1% pour chaque unité horizontale + {\clap{\vrule width\dimexpr\mainrule height\total@ht}% réglure principale + \rlap{% mettre à droite de la position sans bouger + \for\jj = 2 to #2 \do 1% insérer #2-1 fois + {\kern\sub@unit % l'espace horizontal + \clap{\vrule width\subrule height\total@ht}% et la réglure verticale + }% + }% + \kern\xunit % insérer l'espace entre réglures horizontales + }% + \clap{\vrule width\mainrule height\total@ht}% dernière réglure principale + }% + \vss% compense la hauteur=0pt de la \vbox + }% + % #################### Tracé des réglures horizontales #################### + \edef\total@wd{\the\dimexpr\xunit*#1\relax}% largeur totale de la boite + \edef\sub@unit{\the\dimexpr\yunit/#4\relax}% espace entre 2 subdivisions + \for\ii = 1 to #3 \do 1% pour chaque carreau vertical en partant du haut : + {\vlap{\hrule width\total@wd height\mainrule}% réglure horizontale principale + % et dessous, les réglures secondaires : + \vbox to\z@{% dans une \vbox de hauteur nulle, + \for\jj = 2 to #4 \do 1% insérer #4-1 fois sous la position courante : + {\kern\sub@unit % l'espace vertical + \vlap{\hrule width\total@wd height\subrule}% et la réglure secondaire + }% + \vss% ressort qui se comprime pour satisfaire la hauteur nulle + }% + \kern\yunit% insérer l'espace vertical entre réglures principales + }% + \vlap{\hrule width\total@wd height\mainrule}% dernière réglure horizontale + }% +} +\catcode`@12 +Grille 1 : \xunit=1cm \yunit=1cm \grid{5}{10}{2}{10}\smallskip + +Grille 2 : \xunit=0.5cm \yunit=0.5cm \grid{7}{1}{3}{1}\smallskip + +Grille 3 : \xunit=1.5cm \yunit=0.5cm \grid{4}{3}{3}{2} +****************** Fin code ****************** + + +****************** Code 271 ****************** +\vrule\hbox to10cm{\leaders\hbox to1.5cm{\hss A\hss}\hfill}\vrule +****************** Fin code ****************** + + +****************** Code 272 ****************** +\frboxsep=-\frboxrule \def~{\leavevmode\raise.75ex\hbox{\vrule height.2pt width1em}} +~\hbox to10cm{\leaders\hbox{\frbox{\hbox to1.5cm{\hss A\hss}}}\hfill}~ + +~\hbox to10cm{\cleaders\hbox{\frbox{\hbox to1.5cm{\hss A\hss}}}\hfill}~ + +~\hbox to10cm{\xleaders\hbox{\frbox{\hbox to1.5cm{\hss A\hss}}}\hfill}~ +****************** Fin code ****************** + + +****************** Code 273 ****************** +a) \leavevmode\hbox to10cm{\leaders\hrule\hfill}\smallskip + +b) \hbox to10cm{\leaders\hbox{\vrule height0.2pt width2.5mm \kern1.5mm}\hfill} + +c) \vrule width0.2pt height1ex depth0pt % première réglure verticale + \hbox to10cm{% puis répétition de "_|" + \leaders\hbox{\vrule width2em height0.2pt \vrule width0.2pt height1ex}\hfill} + +d) \hbox to10cm{\leaders\hbox{% + \vrule height.2pt width.5em% 1/2 palier bas + \vrule height5pt width0.2pt% montée au palier haut + \vrule height5pt depth-4.8pt width1em% palier haut + \vrule height5pt width0.2pt% descente au palier bas + \vrule height.2pt width.5em% 1/2 palier bas + }\hfill} +****************** Fin code ****************** + + +****************** Code 274 ****************** +\mainrule=0.8pt \subrule=0.2pt +\def\carreau#1#2{% #1=nb subdiv H #2=nb subdiv V + \vbox to\yunit{% dans un \vbox de hauteur \yunit + \offinterlineskip% pas de ressort d'interligne + \vlap{\hrule height\mainrule width\xunit}% réglure principale du haut + \leaders% répéter (ici ce sera donc #2-1 fois) + \vbox to\dimexpr\yunit/#2\relax% une \vbox de hauteur \yunit/#2 + {\vss% ressort qui va s'étirer à \yunit/#2 + \vlap{\hrule height\subrule width\xunit}% réglure de subdiv de dim 0pt + }\vfill + \kern\dimexpr\yunit/#2\relax% dernière espace verticale + \vlap{\hrule height\mainrule width\xunit}% réglure principale du bas + }% +} +\yunit=1cm +\leavevmode \carreau{}{4} puis \carreau{}{10} +****************** Fin code ****************** + + +****************** Code 275 ****************** +\mainrule=0.8pt \subrule=0.2pt +\def\carreau#1#2{% #1=nb subdiv H #2=nb subdiv V + % ######## réglures horizontales ######## + \rlap{% mettre à droite de la position sans bouger + \vbox to\yunit{% dans un \vbox de hauteur \yunit + \offinterlineskip% pas de ressort d'interligne + \vlap{\hrule height\mainrule width\xunit}% réglure principale du haut + \leaders% répéter (ici ce sera #2-1 fois) + \vbox to\dimexpr\yunit/#2\relax% une \vbox de hauteur \yunit/#2 + {\vss% ressort qui va s'étirer à \yunit/#2 + \vlap{\hrule height\subrule width\xunit}% réglure de subdiv de dim 0pt + }\vfill% ressort de \leaders + \kern\dimexpr\yunit/#2\relax% derniere espace verticale + \vlap{\hrule height\mainrule width\xunit}% réglure principale du bas + }% + }% + % ######## réglures verticales ######## + \hbox to\xunit{% dans une \hbox de longueur \xunit + \clap{\vrule height\yunit width\mainrule}% réglure principale de gauche + \leaders% répéter (ici ce sera #1-1 fois) + \hbox to\dimexpr\xunit/#1\relax + {\hss% ressort qui va s'étirer à \xunit/#1 + \clap{\vrule height\yunit width\subrule}% réglure H de dimension 0 + }\hfill% ressort de \leaders + \kern\dimexpr\xunit/#1\relax% dernière espace H + \clap{\vrule height\yunit width\mainrule}% réglure principale de droite + }% +} +\yunit=1cm \xunit=2cm +\leavevmode \carreau{3}{4} puis \carreau{8}{10} +****************** Fin code ****************** + + +****************** Code 276 ****************** +\mainrule=0.8pt \subrule=0.2pt +\def\grid#1#2#3#4{% + \vbox to#3\yunit{% dans une boite verticale de hauteur #3*\yunit + \leaders% répéter verticalement + \hbox to#1\xunit{% une boite de longueur #1*\xunit + \leaders% dans laquelle se répète horizontalement + \hbox{\carreau{#2}{#4}}% le carreau de largeur \xunit + \hfill}% + \vfill + }% +} +Grille 1 : \xunit=1cm \yunit=1cm \grid{5}{10}{2}{10}\smallskip + +Grille 2 : \xunit=0.5cm \yunit=0.5cm \grid{7}{1}{3}{1}\smallskip + +Grille 3 : \xunit=1.5cm \yunit=0.5cm \grid{4}{3}{3}{2} +****************** Fin code ****************** + + +****************** Code 277 ****************** +\outer\def\foo{Bonjour} +\def\bar{\foo} +****************** Fin code ****************** + + +****************** Code 278 ****************** +\outer\def\foo{Bonjour} +\expandafter\def\expandafter\bar\expandafter{\noexpand\foo} +\meaning\bar + +\edef\baz{\noexpand\foo} +\meaning\baz +****************** Fin code ****************** + + +****************** Code 279 ****************** +\catcode`\@11 +\long\def\filedef#1#2{% + \begingroup + \let\input\@@input% <- utilisateurs de latex uniquement + \everyeof{\eof@nil\noexpand}% insère "\eof@nil\noexpand" à la fin du fichier + \expandafter\filedef@i\expandafter#1% développe \input #2 + \expandafter\relax\input #2 +} +\long\def\filedef@i#1#2\eof@nil{% + \endgroup + \expandafter\def\expandafter#1\expandafter{\gobone#2}% mange le \relax +} +\catcode`\@12 +\filedef\foo{test.txt} +\meaning\foo +****************** Fin code ****************** + + +****************** Code 280 ****************** +% canal de lecture employé dans tout ce chapitre +\def\iffileexists#1#2{% #1=canal de lecture #2=nom du fichier + \openin#1=#2 + \ifeof#1% le fichier n'existe pas + \closein#1 + \expandafter\secondoftwo% renvoyer faux + \else + \closein#1 + \expandafter\firstoftwo% sinon renvoyer vrai + \fi +} +a) \iffileexists\rtest{test.txt}{vrai}{faux}\qquad +b) \iffileexists\rtest{foobar.txt}{vrai}{faux} +****************** Fin code ****************** + + +****************** Code 281 ****************** +\openin\rtest =filetest.txt +\read\rtest to \foo% lit la première ligne +1) Signification : \meaning\foo.\par% signification de ce qui a été lu +1) Exécution : \foo\par +\read\rtest to \foo% lit la deuxième ligne +2) Signification : \meaning\foo.\par +2) Exécution : \foo\par +\read\rtest to \foo% lit la dernière ligne +3) Signification : \meaning\foo.\par +3) Exécution : \foo +\closein\rtest +****************** Fin code ****************** + + +****************** Code 282 ****************** +\openin\rtest =filetest.txt +\readline\rtest to \foo% lit la première ligne +1) Signification : \meaning\foo.\par% signification de ce qui a été lu +1) Exécution : \foo\par +\readline\rtest to \foo% lit la deuxième ligne +2) Signification : \meaning\foo.\par +2) Exécution : \foo\par +\readline\rtest to \foo% lit la dernière ligne +3) Signification : \meaning\foo.\par +3) Exécution : \foo +\closein\rtest +****************** Fin code ****************** + + +****************** Code 283 ****************** +Valeur de \string\endlinechar = \number\endlinechar\par +Caractère correspondant : << \char\endlinechar{} >> +****************** Fin code ****************** + + +****************** Code 284 ****************** +\openin\rtest =filetest.txt +Ligne 1 : {\endlinechar=-1 \global\read\rtest to \foo}% lit la première ligne +\meaning\foo.\par% donne ce qui a été lu +Ligne 2 : {\endlinechar=-1 \global\read\rtest to \foo}% lit la deuxième ligne +\meaning\foo.\par +Ligne 3 : {\endlinechar=-1 \global\read\rtest to \foo}% lit la dernière ligne +\meaning\foo. +\closein\rtest +****************** Fin code ****************** + + +****************** Code 285 ****************** +\def\xread#1to#2{% + \ifcs{#2}% si #2 est une séquence de contrôle + {\edef\restoreendlinechar{\endlinechar=\the\endlinechar}% + \endlinechar=-1 % supprime le caractère mis en fin de ligne + \read#1to#2% lit la ligne et l'assigne à la macro #2 + \restoreendlinechar\relax% restaure le \endlinechar + }% si #2 n'est pas une séquence de contrôle, + {\xread#1to}% ignorer #2, et recommencer +} + +\openin\rtest =filetest.txt +Ligne 1 : \xread\rtest to \foo% lit la première ligne +\meaning\foo.\par% donne ce qui a été lu +Ligne 2 : \xread\rtest to \foo% lit la deuxième ligne +\meaning\foo.\par +Ligne 3 : \xread\rtest to \foo% lit la dernière ligne +\meaning\foo. +\closein\rtest +****************** Fin code ****************** + + +****************** Code 286 ****************** +\def\xread{% doit être suivie de "<nombre> to \<macro>" + \edef\restoreendlinechar{\endlinechar=\the\endlinechar}% + \endlinechar=-1 % neutralise \endlinechar + \afterassignment\restoreendlinechar% après l'assignation, restaurer \endlinechar + \read% attend <nombre> to \<macro> pour effectuer l'assignation +} +\catcode`\@12 + +\openin\rtest =filetest.txt +Ligne 1 : \xread\rtest to \foo% lit la première ligne +\meaning\foo.\par% donne ce qui a été lu +Ligne 2 : \xread\rtest to \foo% lit la deuxième ligne +\meaning\foo.\par +Ligne 3 : \xread\rtest to \foo% lit la dernière ligne +\meaning\foo. +\closein\rtest +****************** Fin code ****************** + + +****************** Code 287 ****************** +\def\macroname{% se développe en le nom de la macro qui suit sans + % le caractère d'échappement + \ifnum\escapechar>-1 % si le caractère d'échappement est positif + \ifnum\escapechar<256 % et inférieur à 256, développer les 2 "\fi" + \expandafter\expandafter\expandafter\expandafter% et le "\string", puis + \expandafter\expandafter\expandafter\gobone% manger le "\" avec \gobone + \fi + \fi + \string% doit être suivi d'une macro +} +\catcode`\@11 +\newcount\field@cnt +\def\searchitem#1#2#3#4{% #1= canal #2=nom fichier #3=référence #4=macro à définir + \let#4\gobone% pour l'instant, #4=\gobone + \openin#1=#2\relax + \unless\ifeof#1% si le fichier existe + \lowercase{\def\sought@firstfield{#3}}% stocke le 1er champ à chercher + \edef\macro@name{\macroname#4}% nom de la macro sans "\" + \xread#1 to \current@line% lire la première ligne + \field@cnt=0 % initialiser le compteur de champs + % ################ sauvegarde du nom des champs ################ + \expsecond{\doforeach\current@field\in}\current@line% pour chaque champ + {\advance\field@cnt1 % incrémenter le compteur de champs + \lowercase\expandafter{% e texte de remplacement de \current@field en minuscule + \expandafter\def\expandafter\current@field\expandafter{\current@field}% + }% + % sauvegarder chaque champ de la 1re ligne (qui sont les intitulés) dans une macro + \letname{fieldname\number\field@cnt}=\current@field + }% + \edef\field@num{\number\field@cnt}% nombre de champs + % ################ lecture des lignes de données ################ + \loop% tant que... + \unless\ifeof#1\relax% ...la fin du fichier n'est pas atteinte + \xread#1 to \current@line% lire une ligne + \unless\ifx\current@line\empty% si elle n'est pas vide + % examniner les champs qu'elle contient (aller à \test@field) + \expsecond{\expandafter\test@field\current@line\@nil}\macro@name% + \fi + \repeat + \fi + \closein#1\relax +} + +\def\test@field#1,#2\@nil#3{% #1=champ no 1 #2=autres champs #3=nom de la macro sans "\" + \def\current@firstfield{#1}% stocke le premier champ de la ligne en cours + \ifx\current@firstfield\sought@firstfield% s'il est égal à celui cherché + \defname{#3.\csname fieldname1\endcsname}{#1}% définir la macros \<#3."champ 1"> + \field@cnt=1 % initialiser le compteur de champ + \doforeach\current@field\in{#2}% puis, pour i>2, définir les macros \<#3."champ i"> + {\advance\field@cnt1 % incrémenter le compteur de champ + \letname{#3.\csname fieldname\number\field@cnt\endcsname}=\current@field + }% + \defname{#3}##1{% et définir la macro \<#3> + \ifcsname#3.##1\endcsname% si la macro \<#3."argument"> existe déjà + \csname#3.##1\expandafter\endcsname% l'exécuter après avoir mangé le \fi + \fi + }% + \fi +} +\catcode`\@12 + +\searchitem\rtest{fournitures.txt}{4562u}\monarticle +réf = \monarticle{ref}, +dénomination = \monarticle{item}, +prix = \monarticle{prix}, +fournisseur = \monarticle{fournisseur}, +champ non existant = \monarticle{foobar}. + +\searchitem\rtest{fournitures.txt}{truc}\essai% référence "truc" n'existe pas +réf = \essai{ref}, +dénomination = \essai{item}, +prix = \essai{prix}, +fournisseur = \essai{fournisseur}. +****************** Fin code ****************** + + +****************** Code 288 ****************** +\def\macroname{% se développe en le nom de la macro qui suit sans + % le caractère d'échappement + \ifnum\escapechar>-1 % si le caractère d'échappement est positif + \ifnum\escapechar<256 % et inférieur à 256, développer les 2 "\fi" + \expandafter\expandafter\expandafter\expandafter% et le "\string", puis + \expandafter\expandafter\expandafter\gobone% manger le "\" avec \gobone + \fi + \fi + \string% doit être suivi d'une macro +} +\catcode`\@11 +\newcount\field@cnt +\newif\ifsearch@repeat +\def\assign@arg#1=#2\@nil{% + \def\sought@fieldnumber{#1}% no du champ à chercher + \def\sought@fielvalue{#2}% et sa valeur +} +\def\searchitem#1#2#3#4{% #1= canal #2=nom fichier #3=champ cherché #4=macro à définir + \let#4\gobone% pour l'instant, #4=\gobone + \openin#1=#2\relax% + \unless\ifeof#1% si le fichier existe + \edef\macro@name{\macroname#4}% nom de la macro sans "\" + \xread#1 to \current@line% lire et ignorer la première ligne + \ifin{#3}{=}% si #3 contient = + {\assign@arg#3\@nil}% trouver le no de champ et sa valeur + {\def\sought@fieldnumber{1}% sinon, no du champ = 1 + \def\sought@fielvalue{#3}% et sa valeur = #3 + }% + % ################ lecture des lignes de données ################ + \search@repeattrue% poursuite de la boucle loop : vraie + \loop% tant que... + \ifeof#1\relax% ...la fin du fichier n'est pas atteinte + \search@repeatfalse% sortir de la boucle loop + \else + \xread#1 to \current@line% lire une ligne + \unless\ifx\current@line\empty% si elle n'est pas vide + % examniner les champs qu'elle contient (aller à \test@field) + \expsecond{\expandafter\test@field\current@line\@nil}\macro@name% + \fi + \fi + \ifsearch@repeat% ne poursuivre que si le booléen en vrai + \repeat + \fi + \closein#1\relax +} + +\def\test@field#1\@nil#2{% #1=champs #2=nom de la macro sans "\" + \field@cnt=0 % initialiser le compteur de champ + \doforeach\current@field\in{#1}% parcourir les champs de la ligne en cours + {\advance\field@cnt1 % incrémenter le compteur de champ + \ifnum\field@cnt=\sought@fieldnumber\relax% si c'est le bon numéro de champ + \ifx\current@field\sought@fielvalue% et si le champ correspond à celui cherché + \search@repeatfalse% sortir de la boucle loop + \doforeachexit% sortir de la boucle \doforeach en cours + \fi + \fi + }% + \unless\ifsearch@repeat% si la ligne a été trouvée + \field@cnt=0 % initialiser le compteur de champ + \doforeach\current@field\in{#1}% parcourir à nouveau les champs de la ligne + {\advance\field@cnt1 % incrémenter le compteur de champ + \letname{#2.\number\field@cnt}=\current@field% faire l'assignation + }% + \defname{#2}##1{% et définir la macro \<#2> + \ifcsname#2.##1\endcsname% si la macro \<#2."argument"> existe déjà + \csname#2.##1\expandafter\endcsname% l'exécuter après avoir mangé le \fi + \fi + }% + \fi +} +\catcode`\@12 +a) \searchitem\rtest{basecourse.txt}{3=283}\foo + "\foo1", "\foo2", "\foo3", "\foo4", "\foo5", "\foo6", "\foo7" + +b) \searchitem\rtest{basecourse.txt}{Valet}\bar + "\bar1", "\bar2", "\bar3", "\bar4", "\bar5", "\bar6", "\bar{abcd}" +****************** Fin code ****************** + + +****************** Code 289 ****************** +\def\showfilecontent#1#2{% #1=canal de lecture #2=nom de fichier + \begingroup + \tt% sélectionner la fonte à chasse fixe + \openin#1=#2\relax + \ifeof#1% si la fin du fichier est déjà atteinte, il n'existe pas et + Le fichier n'existe pas% afficher le message + \else% le fichier existe + \def\do##1{\catcode`##1=12 }% + \dospecials% neutraliser tous les tokens spéciaux + \obeyspaces% rendre l'espace actif + \loop + \xread#1 to \currline% lire une ligne + \unless\ifeof#1% si la fin du fichier n'est pas atteinte + \leavevmode\par% aller à la ligne + \currline% afficher la ligne lue + \repeat% recommencer + \fi + \closein#1\relax + \endgroup +} + +Contenu du fichier : "\showfilecontent\rtest{readtest.txt}", affiché tel quel +****************** Fin code ****************** + + +****************** Code 290 ****************** +\def\showfilecontent#1#2{% #1=canal de lecture #2=nom de fichier + \begingroup + \tt% sélectionner la fonte à chasse fixe + \openin#1=#2\relax + \ifeof#1% si la fin du fichier est déjà atteinte, il n'existe pas et + Le fichier n'existe pas% afficher le message + \else% le fichier existe + \def\do##1{\catcode`##1=12 }% + \dospecials% neutraliser tous les tokens spéciaux + \obeyspaces% rendre l'espace actif + \def\magicpar{\let\magicpar=\par}% + \loop + \xread#1 to \currline% lire une ligne + \unless\ifeof#1% si la fin du fichier n'est pas atteinte + \leavevmode\magicpar% former le paragraphe (sauf à la 1er itération) + \currline% afficher la ligne + \repeat% recommencer + \fi + \closein#1\relax + \endgroup +} + +Contenu du fichier : "\showfilecontent\rtest{readtest.txt}", affiché tel quel +****************** Fin code ****************** + + +****************** Code 291 ****************** +% sera le canal d'écriture dans tout ce chapitre +\immediate\openout\wtest=writetest.txt % lie \wtest au fichier +\immediate\write\wtest{Programmer en \noexpand\TeX{} est facile.}% écrit une ligne +\immediate\write\wtest{Et utile...}% puis une autre +\immediate\closeout\wtest% défait la liaison +a) Contenu du fichier :\par +"\showfilecontent\rtest{writetest.txt}"% affiche le contenu du fichier +\medbreak +% 2e tentative : +b) Contenu du fichier :\par +\immediate\openout\wtest=writetest.txt % lie \wtest au fichier +\immediate\write\wtest{Essai d'écriture}% écrit une ligne +\immediate\closeout\wtest% défait la liaison +"\showfilecontent\rtest{writetest.txt}"% affiche le contenu du fichier +****************** Fin code ****************** + + +****************** Code 292 ****************** +\def\noexpwrite#1#2{% #1=numéro de canal #2=texte à écrire + \write#1{\unexpanded{#2}}% +} +\immediate\openout\wtest=writetest.txt +\immediate\noexpwrite\wtest{Programmer en \TeX{} est facile.}% +\immediate\noexpwrite\wtest{Et utile...}% +\immediate\closeout\wtest +Contenu du fichier :\par +\showfilecontent\rtest{writetest.txt}% affiche le contenu du fichier +****************** Fin code ****************** + + +****************** Code 293 ****************** +\catcode`\@11 +\def\exactwrite#1{% #1=numéro de canal + \begingroup + \def\canal@write{#1}% sauvegarde le numéro de canal + \for\xx=0 to 255\do{\catcode\xx=12 }% donne à tous les octets le catcode 12 + \exactwrite@i% aller lire le <car> +} + +\def\exactwrite@i#1{% #1 est le <car> de catcode 12 + \def\exactwrite@ii##1#1{% ##1 est le <texte> à envoyer vers le fichier + \exactwrite@iii##1\@nil% envoyer <texte> à \exactwrite@iii + }% + \exactwrite@ii% va lire tout ce qui se trouve jusqu'au prochain <car> +} + +{\catcode`\^^M 12 \gdef\EOL@char{^^M}}% définit le caractère <EOL> de catcode 12 + +\def\exactwrite@iii#1\@nil{% #1 = <texte> à écrire dans le fichier + \expsecond{\ifin{#1}}\EOL@char% si #1 contient "retour charriot" + {\write@line#1\@nil% écrire la première ligne de #1 + } + {\immediate\write\canal@write{#1}% sinon : dernière ligne atteinte, l'écrire + \endgroup% puis sortir du groupe + }% +} + +% les \expandafter provoquent le 1-développement de \EOL@char : +\expandafter\def\expandafter\write@line\expandafter#\expandafter1\EOL@char#2\@nil{% + \immediate\write\canal@write{#1}% écrit la ligne (ce qui se trouve avant ^^M) + \exactwrite@iii#2\@nil% recommencer avec ce qui se trouve après "^^M" +} +\catcode`\@12 + +\immediate\openout\wtest=writetest.txt % lie le canal \wtest au fichier +\exactwrite\wtest|Programmer en \TeX{} est facile ! + +Et très utile.| +\immediate\closeout\wtest% et fermer le fichier + +Le contenu du fichier "writetest.txt" est :\par +"\showfilecontent\rtest{writetest.txt}" +****************** Fin code ****************** + + +****************** Code 294 ****************** +\catcode`\@11 +\newcount\exo@number% compteur pour le numéro d'exercice + +\def\exocalctotal#1\endtotal{\edef\total@points{\dimtodec\dimexpr#1}} + +\def\initexo#1{% + \def\exo@canal{#1}% sauvegarde le canal d'écriture + \exo@number=0 % initialiser le compteur d'exo + \iffileexists\exo@canal{\jobname.pts}% si le fichier .pts existe + {\input \jobname.pts }% le lire et exécuter son contenu + {\def\total@points{\char`\#\char`\#}}% sinon, définir un total alternatif + \immediate\openout\exo@canal=\jobname.pts % ouvrir le fichier .pts + \immediate\write\exo@canal{\noexpand\exocalctotal}% et commencer à y écrire dedans +} + +\def\exo#1{% définti la macro qui affiche l'exercice + \bigbreak% sauter une grande espace verticale + \immediate\write\exo@canal{+#1}% écrire "+#1" dans le fichier .pts + \advance\exo@number by 1 % incrémenter le numéro de l'exercice + \noindent\vrule height1ex width1ex depth0pt % trace le carré + \kern1ex% insérer une espace horizontale + {\bf Exercice \number\exo@number}% afficher "Exercice <nombre>" + \leaders\hbox to.5em{\hss.\hss}\hfill% afficher les pointillés + #1/\total@points% puis #1/<total> + \smallbreak% composer la ligne précédente et sauter une espace verticale +} + +\def\stopexo{% + \immediate\write\exo@canal{\relax\noexpand\endtotal}% + \immediate\closeout\exo@canal +} +\catcode`\@12 +\initexo\wtest + +\hfill{\bf Interrogation écrite. Sujet : \TeX{}}\hfill\null +\par +\leavevmode\hfill\vrule height.4pt width 2cm depth0pt\hfill\null +\exo{3pt} +Élaborer un test \litterate/\ifonebyte{<texte>}{<vrai>}{<faux>}/ qui teste, pour une +compilation avec un moteur 8 bits, si le \litterate/<texte>/ est codé sur un seul +octet. Ce test pourrait être utilisé pour déterminer si l'encodage d'un document +est à plusieurs octets (comme l'est UTF8) en prenant comme \litterate/<texte>/ +les caractères <<~é~>>, <<~à~>>, etc. + +\exo{5,5pt} +Si \verb-#1- est un nombre entier, quel est le test fait par ce code ? +\smallbreak +\hfill +\litterate/\if\string l\expandafter\firstto@nil\romannumeral#1\relax\@nil/ +\hfill\null + +\exo{4,5pt} +On a vu que pour provoquer un $n$-développement, les \litterate/\expandafter/se plaçaient +en nombre égal à $2^n-1$ devant chaque token précédant celui que l'on veut développer. +Or, ce nombre est {\it impair\/}. Trouver un exemple ou un cas particulier où il faut +placer un nombre {\it pair\/} d'\litterate/\expandafter/ devant un token (on pourra +envisager le cas de 2 \litterate/\expandafter/). +\stopexo +****************** Fin code ****************** + + +****************** Code 295 ****************** +\def\identite{Foo Bar}% Prénom Nom +\def\beforespace#1 #2\nil{#1} +\def\afterspace#1 #2\nil{#2} +\def\prenom{\beforespace\identite\nil} +\def\nom{\afterspace\identite\nil} +Mon prénom : \expandafter\expandafter\prenom + +Mon nom : \expandafter\expandafter\nom +****************** Fin code ****************** + + +****************** Code 296 ****************** +\newlinechar`\^^J +\immediate\openout\wtest=test1.txt +\immediate\write\wtest{Une première ligne^^JEt une seconde.} +\immediate\closeout\wtest +\showfilecontent\rtest{test1.txt} +****************** Fin code ****************** + + +****************** Code 297 ****************** +\newlinechar`\^^J +\immediate\openout\wtest=test2.txt +\immediate\write\wtest{Une première ligne^^JEt une seconde.} +\immediate\write\wtest{Et la dernière.} +\immediate\closeout\wtest + +{\endlinechar`\X % insère "X" à chaque fin de ligne +\openin\rtest=test2.txt % les fins de lignes sont commentées +\loop% pour éviter que \endlinechar + \read\rtest to \foo% ne soit inséré à chaque fin de + \unless\ifeof\rtest% ligne du code source + \meaning\foo\par% affiche le texte de remplacement de \foo +\repeat% +\closein\rtest}% +****************** Fin code ****************** + + +****************** Code 298 ****************** +\catcode`\@11 +\def\exactwrite#1{% #1=numéro de canal + \begingroup + \for\xx=0 to 255\do{\catcode\xx=12 }% donne à tous les octets le catcode 12 + \newlinechar=`\^^M % caractère de fin de ligne = retour charriot + \exactwrite@i{#1}% donne le <canal> d'écriture comme premier argument +} + +\def\exactwrite@i#1#2{% #2 est le caractère délimiteur de catcode 12 + \def\exactwrite@ii##1#2{% ##1 est le <texte> à envoyer vers le fichier + \immediate\write#1{##1}% écrire le <texte> dans le fichier + \endgroup% puis, sortir du groupe + }% + \exactwrite@ii% traiter tout ce qui se trouve jusqu'au prochain #2 +} +\catcode`\@12 + +\immediate\openout\wtest=writetest.txt % lie le canal \wtest au fichier +\exactwrite\wtest|Programmer en \TeX{} est facile ! + +Et très utile.| +\immediate\closeout\wtest% et fermer le fichier + +Le contenu du fichier "writetest.txt" est :\par +"\showfilecontent\rtest{writetest.txt}" +****************** Fin code ****************** + + +****************** Code 299 ****************** +\newlinechar`\^^J +\message{^^JQuel est votre nom ? } +\xread-1 to \username +\message{Bonjour \username.^^J% +Depuis combien d'années pratiquez-vous TeX ? } +\read-1 to \yeartex +\message{% + \ifnum\yeartex<5 Cher \username, vous êtes encore un débutant ! + \else\ifnum\yeartex<10 Bravo \username, vous êtes un TeXpert ! + \else\ifnum\yeartex<15 Félicitations \username, vous êtes un TeXgourou. + \else Passez à autre chose, par exemple à Metafont et Metapost ! + \fi\fi\fi^^J} +****************** Fin code ****************** + + +****************** Code 300 ****************** +\catcode`\@11 +\def\answer@plus{+}\def\answer@minus{-}\def\answer@equal{=}% +\def\nb@found#1{% macro appelée lorsque le nombre (argument #1) est trouvé + \message{^^JVotre nombre est #1.^^JMerci d'avoir joué avec moi.^^J}% +} + +\def\nbguess#1#2{% + \message{Choisissez un nombre entre #1 et #2.^^J + Tapez entrée lorsque c'est fait.}% + \read-1 to \tex@guess% attend que l'on tape sur "entrée" + \nbguess@i{#1}{#2}% +} + +\def\nbguess@i#1#2{% + \ifnum#1<#2 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + % si #1<#2 (donc le nombre n'est pas trouvé), + % mettre dans \tex@guess la troncature de la moyenne de #1 et #2 + {\edef\tex@guess{\number\truncdiv{\numexpr#1+#2\relax}2}% + \message{Je propose \tex@guess.^^J% afficher sur le terminal + Votre nombre est-il plus grand (+), plus petit (-) ou égal (=) : }% + \read -1 to \user@answer% lire la réponse de l'utilisateur + \edef\user@answer{% + \expandafter\firstto@nil\user@answer\relax\@nil% ne garder que le 1er caractère + }% + \ifxcase\user@answer% envisager les cas "+", "-" et "=" + \answer@plus{\exparg\nbguess@i{\number\numexpr\tex@guess+1\relax}{#2}}% + \answer@minus{\expsecond{\nbguess@i{#1}}{\number\numexpr\tex@guess-1\relax}}% + \answer@equal{\nb@found\tex@guess}% + \elseif% si la réponse ne commence pas par "+", "-" ou "=" + \message{Je n'ai pas compris votre réponse}% afficher message erreur + \nbguess@i{#1}{#2}% et recommencer avec les mêmes nombres + \endif + } + % si #1>=#2, le nombre est trouvé + {\nb@found{#1}}% +} +\catcode`\@12 + +\nbguess{1}{100} +****************** Fin code ****************** + + +****************** Code 301 ****************** +\def\syracuse#1{% + #1% affiche le nombre + \ifnum#1>1 % si le nombre est >1 + , % afficher une virgule+espace + \ifodd#1 % s'il est pair + \exparg\syracuse% appeler la macro \syracuse + {\number\numexpr3*#1+1% avec 3*n+1 + \expandafter\expandafter\expandafter}% après avoir rendu la macro terminale + \else % s'il est pair + \expandafter\syracuse\expandafter% appeler la macro \syracuse + {\number\numexpr#1/2% avec n/2 + \expandafter\expandafter\expandafter}% après avoir rendu la macro terminale + \fi + \else% si le nombre est 1 + .% afficher un point + \fi +} +a) \syracuse{20}\par +b) \syracuse{14}\par +c) \syracuse{99}\par +d) \edef\foo{\syracuse{15}}\meaning\foo +****************** Fin code ****************** + + +****************** Code 302 ****************** +\def\syracuse#1{% + #1% afficher le nombre + \ifnum#1>1 % si le nombre est >1 + , % afficher une virgule+espace + \exparg\syracuse{% appeler la macro \syracuse + \number\numexpr% avec le nombre : + \ifodd#1 3*#1+1% 3n+1 si #1 est impair + \else #1/2% n/2 sinon + \fi% + \expandafter}% avant de rendre la récursivité terminale + \else + .% si #1=1, afficher un point + \fi +} +a) \syracuse{20}\par +b) \syracuse{14}\par +c) \syracuse{99}\par +d) \edef\foo{\syracuse{15}}\meaning\foo +****************** Fin code ****************** + + +****************** Code 303 ****************** +\def\factorielle#1{% + \ifnum#1=0 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {1}% "1" si #1=0} + {#1*\exparg\factorielle{\number\numexpr#1-1}}% +} +a) \factorielle{0}\qquad +b) \factorielle{3}\qquad +c) \edef\foo{\factorielle{8}}\meaning\foo +****************** Fin code ****************** + + +****************** Code 304 ****************** +\catcode`\@11 +\def\factorielle#1{% + \number\numexpr\factorielle@i{#1}\relax% appelle \factorielle@i + % en lançant le développement maximal +} +\def\factorielle@i#1{% + \ifnum#1=0 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {1}% "1" si #1= + {#1*\exparg\factorielle@i{\number\numexpr#1-1}}% +} +\catcode`\@12 +a) \factorielle{0}\qquad +b) \factorielle{3}\qquad +c) \edef\foo{\factorielle{8}}\meaning\foo +****************** Fin code ****************** + + +****************** Code 305 ****************** +\catcode`\@11 +\def\PGCD#1#2{% + \ifnum#1<#2 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {\PGCD@i{#2}{#1}}% si #1<#2, mettre #2 (le grand) dans le premier argument + {\PGCD@i{#1}{#2}}% +} + +\def\PGCD@i#1#2{% #1=a #2=b avec a>b + \exptwoargs\PGCD@ii% appeler la macro récursive avec + {\number\numexpr#1-#2*\truncdiv{#1}{#2}}% le reste de a/b + {#2}% et le divisieur b +} + +\def\PGCD@ii#1#2{% #1=reste r #2=diviseur b + \ifnum#1=\z@\expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {#2}% si le reste est nul, renvoyer b + {\PGCD@i{#2}{#1}}% sinon, recommencer avec b et r +} +\catcode`\@12 +a) \PGCD{120}{75}\qquad +b) \PGCD{64}{180}\qquad +c) \PGCD{145}{64}\qquad +d) \edef\foo{\PGCD{1612}{299}}\meaning\foo +****************** Fin code ****************** + + +****************** Code 306 ****************** +\catcode`\@11 +\def\calcPGCD#1#2{% + \ifhmode\par\fi% si en mode horizontal, former le paragraphe + \ifnum#1<#2 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {\calcPGCD@i{#2}{#1}}% si #1<#2, mettre #2 (le grand) dans le premier argument + {\calcPGCD@i{#1}{#2}}% +} + +\def\calcPGCD@i#1#2{% #1=a #2=b avec a>b + \edef\calcPGCD@quotient{\number\truncdiv{#1}{#2}}% stocke le quotient + $#1=\calcPGCD@quotient\times#2% en mode maths, afficher "a=q*b" (à suivre) + \exptwoargs\calcPGCD@ii% appeler la macro récursive avec + {\number\numexpr#1-#2*\calcPGCD@quotient}% le reste de a/b + {#2}% et le divisieur b +} + +\def\calcPGCD@ii#1#2{% #1=reste r #2=diviseur b + +#1$\par% (suite du mode math) afficher "+r", fermer le mode math et \par + \ifnum#1=\z@\expandafter\firstoftwo\else\expandafter\secondoftwo\fi% + {}% si le reste est nul, ne rien faire + {\calcPGCD@i{#2}{#1}}% sinon, recommencer avec b et r +} +\catcode`\@12 +\calcPGCD{39}{15}\medbreak +\calcPGCD{1612}{299} +****************** Fin code ****************** + + +****************** Code 307 ****************** +\frboxsep=0pt % encadrer au plus proche +\leavevmode\frbox{$=$} n'est pas identique à \frbox{${}={}$} +****************** Fin code ****************** + + +****************** Code 308 ****************** +\catcode`\@11 +\def\calcPGCD#1#2{% + \vtop{% mettre l'alignement dans une \vtop + \halign{% les "#" doivent être doublés puisqu'à l'intérieur d'une macro + $\hfil##$&${}=\hfil##$&${}\times##\hfil$&${}+##\hfil$% préambule + \cr% fin du préambule et début de la première cellule + \ifnum#1<#2 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {\calcPGCD@i{#2}{#1}}% si #1<#2, mettre #2 (le grand) dans le premier argument + {\calcPGCD@i{#1}{#2}}% + \crcr% fin de l'alignement + }% + }% +} + +\def\calcPGCD@i#1#2{% #1=a #2=b avec a>b + \xdef\calcPGCD@quotient{\number\truncdiv{#1}{#2}}% stocke le quotient + #1 & \calcPGCD@quotient & #2 &% afficher "a=q*b" (à suivre) + \exptwoargs\calcPGCD@ii% appeler la macro récursive avec + {\number\numexpr#1-#2*\calcPGCD@quotient}% le reste de a/b + {#2}% et le divisieur b +} + +\def\calcPGCD@ii#1#2{% #1=reste r #2=diviseur b + #1% (suite de l'alignement) afficher "+r" + \cr% et terminer la ligne en cours + \ifnum#1=\z@\expandafter\firstoftwo\else\expandafter\secondoftwo\fi% + {}% si le reste est nul, ne rien faire + {\calcPGCD@i{#2}{#1}}% sinon, recommencer avec b et r +} +\catcode`\@12 +a) \calcPGCD{39}{15}\medbreak +b) \calcPGCD{1612}{299} +****************** Fin code ****************** + + +****************** Code 309 ****************** +\catcode`\@11 +\def\baseconv#1{% + \unless\ifnum#1=\z@ % si #1 est différent de 0 + \number\numexpr#1-2*\truncdiv{#1}2\relax% écrire le reste + \exparg\baseconv{\number\truncdiv{#1}2\expandafter}% recommencer avec #1/2 + \fi% après que le \fi ait été lu +} +\catcode`\@12 +a) \baseconv{43}\qquad +b) \baseconv{32}\qquad +c) \edef\foo{\baseconv{159}}\meaning\foo +****************** Fin code ****************** + + +****************** Code 310 ****************** +\catcode`\@11 +\def\baseconv#1{% + \baseconv@i{}{#1}% +} + +\def\baseconv@i#1#2{% #1=restes #2=n + \ifnum#2=\z@\expandafter\firstoftwo\else\expandafter\secondoftwo\fi% si n=0 + {#1}% si <n>=0, afficher tous les restes + {% sinon, recommencer en + \exptwoargs\baseconv@i% ajoutant le reste courant avant #1 + {\number\numexpr#2-2*\truncdiv{#2}2\relax #1} + {\number\truncdiv{#2}2}% et en prenant n:=n/2 + }% +} + +\catcode`\@12 +a) \baseconv{43}\qquad +b) \baseconv{32}\qquad +c) \edef\foo{\baseconv{159}}\meaning\foo +****************** Fin code ****************** + + +****************** Code 311 ****************** +\catcode`\@11 +\def\z@@{\expandafter\z@\expandafter} +\def\basedigit#1{% + \ifcase#1 + \z@@ 0% + \or\z@@ 1\or\z@@ 2\or\z@@ 3\or\z@@ 4\or\z@@ 5\or\z@@ 6\or\z@@ 7% + \or\z@@ 8\or\z@@ 9\or\z@@ A\or\z@@ B\or\z@@ C\or\z@@ D\or\z@@ E% + \or\z@@ F\or\z@@ G\or\z@@ H\or\z@@ I\or\z@@ J\or\z@@ K\or\z@@ L% + \or\z@@ M\or\z@@ N\or\z@@ O\or\z@@ P\or\z@@ Q\or\z@@ R\or\z@@ S% + \or\z@@ T\or\z@@ U\or\z@@ V\or\z@@ W\or\z@@ X\or\z@@ Y\or\z@@ Z% + \fi +} +\long\def\>#1<{\detokenize{#1}} +a) \expandafter\>\romannumeral\basedigit{23}<\quad +b) \expandafter\>\romannumeral\basedigit{6}< +\catcode`@12 +****************** Fin code ****************** + + +****************** Code 312 ****************** +\catcode`\@11 +\def\baseconv#1#2{% #1=base #2=nombre à convertir + \ifnum#1<37 % base maxi = 36 (10 signes chiffres + 26 signes lettres) + \antefi + \baseconv@i{}{#2}{#1}% + \fi +} +\def\baseconv@i#1#2#3{% #1=restes #2=n #3=base + \ifnum#2=\z@ \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {#1}% si n=0, afficher tous les restes + {% si non, transmettre en dernier argument + \expsecond{\baseconv@ii{#1}{#2}{#3}}% + {\number\truncdiv{#2}{#3}}% le quotient + }% +} +\def\baseconv@ii#1#2#3#4{% #1=restes #2=n #3=base #4=q + \exparg\baseconv@i% recommencer, en ajoutant le <chiffre> avant les restes + {\romannumeral\basedigit{\number\numexpr#2-#4*#3\relax}#1}% + {#4}% et en remplaçant n par q + {#3}% +} +\def\z@@{\expandafter\z@\expandafter}% +\def\basedigit#1{% + \ifcase#1 + \z@@ 0% + \or\z@@ 1\or\z@@ 2\or\z@@ 3\or\z@@ 4\or\z@@ 5\or\z@@ 6\or\z@@ 7% + \or\z@@ 8\or\z@@ 9\or\z@@ A\or\z@@ B\or\z@@ C\or\z@@ D\or\z@@ E% + \or\z@@ F\or\z@@ G\or\z@@ H\or\z@@ I\or\z@@ J\or\z@@ K\or\z@@ L% + \or\z@@ M\or\z@@ N\or\z@@ O\or\z@@ P\or\z@@ Q\or\z@@ R\or\z@@ S% + \or\z@@ T\or\z@@ U\or\z@@ V\or\z@@ W\or\z@@ X\or\z@@ Y\or\z@@ Z% + \fi +} +\catcode`\@12 +a) "\baseconv{20}{21587}"\qquad +b) "\baseconv{16}{32}"\qquad +c) \edef\foo{\baseconv{16}{159}}% + "\meaning\foo"\qquad +d) "\baseconv{2}{43}" +****************** Fin code ****************** + + +****************** Code 313 ****************** +\catcode`\@11 +\def\quark@list{\quark@list}% quark de fin de liste +\def\finditem#1{% #1 = \<macrolist>, la position est lue plus tard par \finditem@i + \exparg\finditem@i{#1}% 1-développe la \<macrolist> +} +\def\finditem@i#1#2{% #1 = liste #2=position cherchée + \finditem@ii{1}{#2}#1,\quark@list,% appelle la macro récursive +} +\def\finditem@ii#1#2#3,{% #1=position courante #2=position cherchée #3=élément courant + \ifx\quark@list#3\expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {}% si la fin de liste est atteinte, ne rien renvoyer + {% sinon + \ifnum#1=#2 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {% si la position est la bonne + \finditem@iii{#3}% renvoyer #3 et manger les éléments restants + } + {% si la position n'est pas la bonne, recommencer en incrémentant #1 + \exparg\finditem@ii{\number\numexpr#1+1}{#2}% + }% + }% +} +\def\finditem@iii#1#2\quark@list,{% renvoyer #1 et manger le reste de la liste + #1% +} +\catcode`\@12 +\def\liste{a,bcd,{ef},g,hij,kl} +a) \edef\foo{\finditem\liste5}\meaning\foo\qquad +b) \edef\bar{\finditem\liste3}\meaning\bar +****************** Fin code ****************** + + +****************** Code 314 ****************** +\catcode`\@11 +\def\quark@list{\quark@list}% quark de fin de liste +\def\finditem#1{% #1 = \<macro>, la position est lue plus tard par \finditem@i + \exparg\finditem@i{#1}% 1-développe la \<macro> +} +\def\finditem@i#1#2{% #1 = liste #2=position cherchée + \ifnum#2>\z@% ne faire quelque chose que si la position est >0 + \antefi + \finditem@ii{1}{#2}\relax#1,\quark@list,% appelle la macro récursive + \fi +} +\def\finditem@ii#1#2#3,{% #1=position courante #2=position cherché #3=élément courant + \expandafter\ifx\expandafter\quark@list\gobone#3% + \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {}% si la fin de liste est atteinte, ne rien renvoyer + {% sinon + \ifnum#1=#2 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {% si la position est la bonne + \finditem@iii{#3}% renvoyer #3 et manger les éléments restants + } + {% si la position n'est pas la bonne, recommencer en incrémentant #1 + \exparg\finditem@ii{\number\numexpr#1+1}{#2}\relax + }% + }% +} +\def\finditem@iii#1#2\quark@list,{% renvoyer #1 et manger le reste de la liste + \gobone#1% +} +\def\finditemtocs#1#2#3{% #1 = \<macro> #2=position #3=macro à définir + \def\finditemtocs@iii##1##2\quark@list,{% renvoyer #1 et manger le reste de la liste + \expandafter\def\expandafter#3\expandafter{\gobone##1}% + }% + \let#3=\empty + \exparg\finditemtocs@i{#1}{#2}% 1-développe la \<macro> +} +\def\finditemtocs@i#1#2{% #1 = liste #2=position cherchée + \ifnum#2>\z@% ne faire quelque chose que si la position est >0 + \antefi\finditemtocs@ii{1}{#2}\relax#1,\quark@list,% appelle la macro récursive + \fi +} +\def\finditemtocs@ii#1#2#3,{% +% #1=position courante #2=position cherché #3=\relax + élément courant + \expandafter\ifx\expandafter\quark@list\gobone#3% + \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {}% si fin de liste ne rien faire. Sinon, si position bonne + {\ifnum#1=#2 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {\finditemtocs@iii{#3}% renvoyer #3 et manger les éléments restants + }% si la position n'est pas la bonne, recommencer en incrémentant #1 + {\exparg\finditemtocs@ii{\number\numexpr#1+1}{#2}\relax% + }% + }% +} +\catcode`\@12 +\def\liste{a,bcd,{ef},g,hij,kl} +a) "\finditem\liste5"\qquad +b) \edef\bar{\finditem\liste3}\meaning\bar\qquad +c) \finditemtocs\liste{3}\foo\meaning\foo +****************** Fin code ****************** + + +****************** Code 315 ****************** +\catcode`\@11 +\def\quark@list{\quark@list}% quark de fin de liste +\def\positem#1{% #1 = \<macrolist>, la position est lue plus tard par \positem@i + \def\positem@endprocess{\pos@item}% hook : afficher la position + \exparg\positem@i{#1}% 1-développe la \<macrolist> +} +\def\positem@i#1#2{% #1 = liste #2=élément cherché + \def\sought@item{#2}% définir l'élément cherché + \positem@ii{1}\relax#1,\quark@list,% appelle la macro récursive +} +\def\positem@ii#1#2,{% #1=position courante #2=\relax + élément courant + \expandafter\def\expandafter\current@item\expandafter{\gobone#2}% + \ifx\current@item\quark@list\expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {\def\pos@item{0}% si la fin de liste est atteinte, renvoyer 0 + \positem@endprocess% et aller au hook + }% sinon + {\ifx\current@item\sought@item\expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {\def\pos@item{#1}% si la position est la bonne, définir la position + \positem@goblist% et manger les éléments restants + }% si la position n'est pas la bonne, recommencer en incrémentant #1 + {\exparg\positem@ii{\number\numexpr#1+1}\relax + }% + }% +} +\def\positem@goblist#1\quark@list,{\positem@endprocess}% manger la liste et aller au hook + +\def\positemtocs#1#2#3{% #1=\<macrolist> #2=élément à chercher #3=macro à définir + \def\positem@endprocess{\let#3=\pos@item}% hook : mettre le résultat dans #3 + \exparg\positem@i{#1}{#2}% 1-développe la \<macrolist> +} + +\catcode`\@12 +\def\liste{a,bcd,{ef},g,hij,,kl} +a) \positem\liste{g}\qquad +b) \positem\liste{ef}\qquad +c) \positem\liste{{ef}}\qquad +d) \positem\liste{}\medbreak + +\def\liste{a,bcd,{ef},g,hij,,kl} +a) \positemtocs\liste{g}\foo\meaning\foo\qquad +b) \positemtocs\liste{ef}\foo\meaning\foo\qquad +c) \positemtocs\liste{{ef}}\foo\meaning\foo\qquad +d) \positemtocs\liste{}\foo\meaning\foo\qquad +****************** Fin code ****************** + + +****************** Code 316 ****************** +\catcode`\@11 +\def\quark@list{\quark@list}% quark de fin de liste +\def\insitem#1#2#3{% #1 = macro #2=position cherchée #3=élément à insérer + \let\item@list=\empty + \ifnum#2<1 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + % si position < 1 + {\addtomacro\item@list{#3,}% ajouter l'élement à insérer en premier + \eaddtomacro\item@list#1% puis la liste entière + } + % si la position > 1 + {% définir la macro récursive + \def\insitem@i##1##2,{% ##1 = position courante ##2=\relax + élément courant + \expandafter\ifx\expandafter\quark@list\gobone##2% + \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {\addtomacro\item@list{#3}}% si fin de liste, ajouter l'élément en dernier + {% sinon, si la position cherchée est atteinte + \ifnum##1=#2 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {\addtomacro\item@list{#3,}% ajouter l'élement + \add@remainlist##2,% et ##2 (en supprimant le \relax) et le reste + }% si la position n'est pas atteinte + {\eaddtomacro\item@list{\gobone##2,}% ajouter l'élément + \exparg\insitem@i{\number\numexpr##1+1}\relax% et recommencer + }% + }% + }% + % appel de la macro récursive + \expandafter\insitem@i\expandafter1\expandafter\relax#1,\quark@list,% + }% + \let#1=\item@list% rendre #1 égal au résultat +} + +\def\add@remainlist#1,\quark@list,{% + \eaddtomacro\item@list{\gobone#1}% ajouter #1 ainsi que les autres +} +\catcode`\@12 +\def\liste{a,bra,{cA},da,brA}\insitem\liste3{XX}\meaning\liste\par +\def\liste{a,bra,{cA},da,brA}\insitem\liste0{XX}\meaning\liste\par +\def\liste{a,bra,{cA},da,brA}\insitem\liste9{XX}\meaning\liste +****************** Fin code ****************** + + +****************** Code 317 ****************** +\catcode`\@11 +\def\quark@list{\quark@list}% quark de fin de liste +\def\delitem#1#2{% #1 = macro #2=position cherchée + \ifnum#2>0 % ne faire quelque chose que si la position est >0 + \def\delitem@i##1##2,{% ##1 = position courante ##2=\relax + élément courant + \expandafter\ifx\expandafter\quark@list\gobone##2% + \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {}% si fin de liste, ne rien faire + {% sinon, si la position cherchée est atteinte + \ifnum##1=#2 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {\add@reaminingitems% et ##2 (en supprimant le \relax) et le reste + }% si la position n'est pas la bonne + {\eaddtomacro\item@list{\gobone##2,}% ajouter l'élément + \exparg\delitem@i{\number\numexpr##1+1}\relax% et recommencer + }% + }% + }% + \let\item@list=\empty% initialiser la macro tempporaire + % appel de la macro récursive + \expandafter\delitem@i\expandafter1\expandafter\relax#1,\quark@list,% + \let#1=\item@list% rendre #1 égal au résultat + \fi +} + +\def\add@reaminingitems#1\quark@list,{% + \eaddtomacro\item@list{#1}% ajouter tout jusqu'au quark +} +\catcode`\@12 +\for\xx=0 to 8 \do{% +\def\liste{a,bcd,{ef},g,hij,kl} +position \xx{} : \expandafter\delitem\expandafter\liste\xx\meaning\liste.\par +} +****************** Fin code ****************** + + +****************** Code 318 ****************** +\catcode`\@11 +\def\moveitem#1#2#3{% #1 = liste, #2=position départ, #3=position arrivée + \ifnum#2>0 % ne faire quemque chose que si #2>0 + \finditemtocs#1{#2}\temp@item% sauvegarder l'élément + \delitem#1{#2}% supprimer l'élément + \expsecond{\insitem#1{#3}}\temp@item% insérer l'élément + \fi +} +\catcode`\@12 +% déplace "b" en 5e position +a) \def\liste{a,b,c,d,e,f} \moveitem\liste25 "\liste"\par +% déplace "d" en 1e position +b) \def\liste{a,b,c,d,e,f} \moveitem\liste41 "\liste"\par +% déplace "c" en 9e position +c) \def\liste{a,b,c,d,e,f} \moveitem\liste39 \liste"\par +% position départ=0 -> sans effet +d) \def\liste{a,b,c,d,e,f} \moveitem\liste02 "\liste" +****************** Fin code ****************** + + +****************** Code 319 ****************** +\catcode`\@11 +\def\runlist#1\with#2{% #1=liste #2=macro + \def\runlist@i##1,{% + \ifx\quark@list##1\relax\else% si la fin n'est pas atteinte + \addtomacro\collect@run{#2{##1}}% ajouter "\<macro>{<élément>}"" + \expandafter\runlist@i% et recommencer en lisant l'élément suivant + \fi + }% + \begingroup% fait la collecte dans un groupe + \let\collect@run=\empty% initialiser la macro + \expandafter\runlist@i#1,\quark@list,% appeler \runlist@i + \expandafter\endgroup% ferme le groupe et détruit \collect@run + \collect@run% après l'avoir développé ! +} +\catcode`\@12 +\newcount\foocnt +\foocnt=0 % compteur utilisé pour numéroter les éléments dans la macro \foo +\def\foo#1{% la macro qui va exécuter chaque élément de la liste. #1 = l'élément + \advance\foocnt1 % incrémente le compteur + L'argument \number\foocnt\ est : {\bf #1}\par% +} +\def\liste{a,bra,ca,da,BRA}% +\runlist\liste\with\foo% +****************** Fin code ****************** + + +****************** Code 320 ****************** +\catcode`\@11 +\def\ifspacefirst#1{% + \expandafter\ifspacefirst@i\detokenize{#1W} \@nil% "W" se prémunit d'un argument vide +} +\def\ifspacefirst@i#1 #2\@nil{\ifempty{#1}}% renvoyer vrai s'il n'y a rien avant " " +\catcode`\@12 +a) \ifspacefirst{a bc d}{vrai}{faux}\qquad +b) \ifspacefirst{ a bc d}{vrai}{faux}\qquad +c) \ifspacefirst{ }{vrai}{faux}\qquad +d) \ifspacefirst{}{vrai}{faux}\qquad +e) \ifspacefirst{{ } }{vrai}{faux}\qquad +f) \ifspacefirst{ {x} }{vrai}{faux} +****************** Fin code ****************** + + +****************** Code 321 ****************** +\catcode`\@11 +\expandafter\def\expandafter\gobspace\space{} + +\def\removefirstspaces#1{% + \ifspacefirst{#1}% si #1 commence par un espace + {\exparg\removefirstspaces{\gobspace#1}}% recommencer sans le 1er espace + {#1}% sinon, renvoyer l'argument +} +\catcode`\@12 +a) "\removefirstspaces{12 {\bf3}4 567}"\qquad +b) "\removefirstspaces{ 12 {\bf3}4 567}"\qquad +c) \edef\foo{\space\space\space 12 34 567} + "\exparg\removefirstspaces\foo" +****************** Fin code ****************** + + +****************** Code 322 ****************** +\catcode`\@11 +\def\removefirstspaces{% + \romannumeral% lance le développement maximal + \removefirstspaces@i% et passe la main à la macro récursive +} + +\def\removefirstspaces@i#1{% + \ifspacefirst{#1}% si #1 commence par un espace + {\exparg\removefirstspaces@i{\gobspace#1}}% recommencer sans le 1er espace + {\z@#1}% sinon, renvoyer l'argument où \z@ stoppe l'action de \romannumeral +} +\catcode`\@12 +\long\def\>#1<{"\detokenize{#1}"} + +a) \expandafter\expandafter\expandafter\>\removefirstspaces{12 {\bf3}4 567}<\qquad +b) \expandafter\expandafter\expandafter\>\removefirstspaces{ 12 {\bf3}4 567}<\qquad +c) "\removefirstspaces{ 12 {\bf3}4 }" +****************** Fin code ****************** + + +****************** Code 323 ****************** +\catcode`\@11 +\edef\catcodezero@saved{\number\catcode0 }% stocke le catcode de ^^00 +\catcode0=12 % le modifie à 12 +\def\removelastspaces#1{% + \romannumeral% lance le développement maximal + \removelastspaces@i\relax#1^^00 ^^00\@nil% mettre un \relax au début + % et passer la main à \removelastspaces@i +} +\def\removelastspaces@i#1 ^^00{% prendre ce qui est avant " W" + \removelastspaces@ii#1^^00% ajouter "W" +} +\def\removelastspaces@ii#1^^00#2\@nil{% #1=ce qui est avant "W" #2=reliquat + \ifspacefirst{#2}% si le reliquat commence par un espace + {\removelastspaces@i#1^^00 ^^00\@nil}% recommencer sans passer par \removelastspaces + {\expandafter\z@\gobone#1}% sinon supprimer le \relax ajouté au début + % et stopper l'action de \romannumeral avec \z@ +} +\catcode0=\catcodezero@saved\relax% restaure le catcode de ^^00 +\catcode`\@12 +\long\def\>#1<{"\detokenize{#1}"} + +a) \expandafter\expandafter\expandafter\>\removelastspaces{ 12 {\bf3}4 }<\qquad +b) \expandafter\expandafter\expandafter\>\removelastspaces{12 {\bf3}4}<\qquad +c) "\removelastspaces{ 12 {\bf3}4 }" +****************** Fin code ****************** + + +****************** Code 324 ****************** +\catcode`\@11 +\def\removetrailspaces#1{% + \romannumeral% lance le développement maximal + \expandafter\expandafter\expandafter% le pont d'\expandafter + \removelastspaces + \expandafter\expandafter\expandafter% fait agir \removefirstspaces en premier + {% + \expandafter\expandafter\expandafter + \z@% stoppe le développement initié par \romannumeral + \removefirstspaces{#1}% + }% +} +\catcode`\@12 +\long\def\>#1<{"\detokenize{#1}"} + +a) \expandafter\expandafter\expandafter\>\removetrailspaces{ 12 {\bf3}4 }<\qquad +b) \expandafter\expandafter\expandafter\>\removetrailspaces{12 {\bf3}4}<\par +c) \expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter + \foo\expandafter\expandafter\expandafter{\removetrailspaces{ 12 {\bf3}4 }}% + signification : \meaning\foo.\par +c) exécution : "\foo"\par +d) "\removetrailspaces{ 12 {\bf3}4 }" +****************** Fin code ****************** + + +****************** Code 325 ****************** +\catcode`\@11 +\def\sanitizelist#1{% #1 = liste + \let\item@list\empty% initialise le réceptacle de la liste assainie + \def\sanitizelist@endprocess{% définit le hook de fin + \expandafter\remove@lastcomma\item@list\@nil% supprimer dernière virgule + \let#1=\item@list% et assigner le résultat à #1 + }% + \expandafter\sanitizelist@i\expandafter\relax#1,\quark@list,% aller à la macro récursive +} + +\def\sanitizelist@i#1,{% #1="\relax" + élément courant + \expandafter\ifx\expandafter\quark@list\gobone#1% + \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {\sanitizelist@endprocess% si fin de liste, hook de fin + }% si la fin de la liste n'est pas atteinte : + {\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter + \addtomacro% 1-développer \gobone pour retirer \relax + \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter + \item@list% puis 2-développer \removetrailspaces + \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter + {\expandafter\removetrailspaces\expandafter{\gobone#1},}% "#1" + \sanitizelist@i\relax% et continuer avec l'élément suivant + }% +} + +\catcode`\@12 +\frboxsep=0pt % encadrer au plus proche +\def\foo#1{\frbox{\tt\strut#1} }% boite avec un strut et en fonte "tt" puis espace +\def\liste{ Programmer, en \TeX{} ,est ,{\bf facile}, et utile } +a) \runlist\liste\with\foo% encadrer les items + +b) \sanitizelist\liste% supprimer les espaces inutiles des items + \runlist\liste\with\foo +****************** Fin code ****************** + + +****************** Code 326 ****************** +\catcode`\@11 +\def\boxsentence#1{% + \leavevmode% se mettre en mode horizontal + \boxsentence@i#1\quark% transmet "#1+\quark" à boxsentence@i +} +\def\boxsentence@i#1{% #1= argument lu + \def\current@arg{#1}% stocke l'argument dans une macro temporaire + \unless\ifx\quark\current@arg% si la fin n'est pas atteinte + \frbox{#1}% encadrer cet argument + \expandafter\boxsentence@i% lire l'argument suivant + \fi +} +\catcode`@12 +\frboxsep=1pt \frboxrule=0.2pt +\boxsentence{Programmer en \TeX\ est facile} +****************** Fin code ****************** + + +****************** Code 327 ****************** +\catcode`\@11 +\edef\star@macro{\string *}% stocke une étoile de catcode 12 +\def\expo#1{% + \def\temp@arg{#1}% stocke l'argument lu + \ifx\star@macro\temp@arg\expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {% si l'argument est une étoile de catcode 12 + $^\dag$% affiche une dague + }% sinon + {$^\ddag$% affiche une double dague + {#1}% puis ré-écrit l'argument {#1} + }% +} +A\expo B\expo*C +****************** Fin code ****************** + + +****************** Code 328 ****************** +\def\boxsentence#1{% + \readtok#1\quark% met le token d'arrêt \quark à la fin de #1 +} +\def\readtok{\afterassignment\cmptok\let\nxttok= } +\def\cmptok{% + \unless\ifx\nxttok\quark% si la fin n'est pas atteinte + \frbox{\nxttok}% encadrer le token lu + \expandafter\readtok% puis aller lire le suivant + \fi +} +\frboxsep=1pt \frboxrule=0.2pt +\leavevmode\boxsentence{Programmer en \TeX\ est facile} +****************** Fin code ****************** + + +****************** Code 329 ****************** +\def\permutstart{\afterassignment\cmptok\let\nxttok= } +\def\permutend{\permutend}% +\def\cmptok{% + \unless\ifx\permutend\nxttok% tant que la fin n'est pas atteinte : + \ifxcase\nxttok + ae% si le token lu est "a", afficher un "e" + ei io ou uy ya% etc pour les autres lettres + \elseif + \nxttok% si ce n'est aucune voyelle, afficher le token + \endif + \expandafter\permutstart% aller lire le token suivant + \fi +} +\permutstart Un "a" puis "e puis "i" ensuite, un "o", un "u" et "y".\permutend +****************** Fin code ****************** + + +****************** Code 330 ****************** +\def\boxsentence#1{\readtok#1\boxsentence} +\def\readtok{\afterassignment\cmptok\let\nxttok= } +\def\cmptok{% + %\show\nxttok% à décommenter pour débogage + \unless\ifx\nxttok\boxsentence + \frbox{\nxttok}% + \expandafter\readtok + \fi +} +\frboxsep=1pt \frboxrule=0.2pt +\leavevmode\boxsentence{Pro{gra}mmer en \TeX\ est facile} +****************** Fin code ****************** + + +****************** Code 331 ****************** +\catcode`\@11 +\def\Litterate{% + \begingroup% ouvrir un groupe + \tt% et adopter une fonte à chasse fixe + \afterassignment\Litterate@i% après l'assignation, aller à \Litterate@i + \expandafter\let\expandafter\lim@tok\expandafter=\string% \lim@tok = token délimiteur +} +\def\Litterate@i{% + \afterassignment\Litterate@ii%après avoir lu le prochain token, aller à \Litterate@ii + \expandafter\let\expandafter\nxttok\expandafter=\string% lit le token suivant +} +\def\Litterate@ii{% + \ifx\nxttok\lim@tok% si le token suivant="token délimiteur" + \endgroup% fermer le groupe et finir + \else + \nxttok% sinon, afficher ce token + \expandafter\Litterate@i% et lire le token suivant + \fi +} +\catcode`\@12 +\Litterate|Programmer en \TeX {} est << facile >> !| +****************** Fin code ****************** + + +****************** Code 332 ****************** +\catcode`\@11 +\def\Litterate{% + \begingroup% ouvrir un groupe + \tt% et adopter une fonte à chasse fixe + \afterassignment\Litterate@i% après l'assignation, aller à \Litterate@i + \expandafter\let\expandafter\lim@tok\expandafter=\string% \lim@tok = token délimiteur +} +\def\Litterate@i{% + \afterassignment\Litterate@ii% après avoir lu un token, aller à \Litterate@ii + \expandafter\expandafter\expandafter% 1-développer \string + \let + \expandafter\expandafter\expandafter% puis 1-développer \space en " " + \nxttok + \expandafter\expandafter\expandafter + =\expandafter\space\string% et lire le token obtenu +} +\def\Litterate@ii{% + \ifx\nxttok\lim@tok% si le token suivant="token délimiteur" + \endgroup% fermer le groupe et finir + \else + \nxttok% sinon, afficher ce token + \expandafter\Litterate@i% et lire le token suivant + \fi +} +\catcode`\@12 +\Litterate|Programmer en \TeX {} est << facile >> : $~$^_#| +****************** Fin code ****************** + + +****************** Code 333 ****************** +\catcode`@11 +\newskip\ltr@spc +\def\letterspace#1#2{% + \ltr@spc=#1\relax % assigne le ressort + \letterspace@i#2\letterspace@i% appelle la macro \letterspace@i +} +\def\letterspace@i{% + \afterassignment\letterspace@ii + \let\nxttok= +} +\def\letterspace@ii{% + \ifx\nxttok\letterspace@i% si la fin est atteinte + \unskip% supprimer le dernier ressort qui est de trop + \else + \nxttok% afficher le token + \hskip\ltr@spc\relax% insère le ressort + \expandafter\letterspace@i% va lire le token suivant + \fi +} +\catcode`@12 +Voici "\letterspace{0.3em}{des lettres espacées}" +et voici "\letterspace{-0.075em}{de la compression}". +****************** Fin code ****************** + + +****************** Code 334 ****************** +\catcode`@11 +\newcount\test@cnt +\def\ifinteger#1{% + \ifstart{#1}{-}% si "-" est au début de #1 + {\exparg\ifinteger{\gobone#1}% l'enlever et recommencer + } + {\ifempty{#1}% sinon, si #1 est vide + \secondoftwo% lire l'argument <faux> + {\afterassignment\after@number% sinon, après l'assignation, aller à \after@number + \test@cnt=0#1\relax% faire l'assignation + %(\relax termine le nombre et n'est pas mangé) + }% + }% +} +\def\after@number#1\relax{% #1 est ce qui reste après l'assignation + \ifempty{#1}% teste si #1 est vide et lit l'argument <vrai> ou <faux> qui suit +} + +\catcode`@12 +1) \ifinteger{5644}{oui}{non}\qquad +2) \ifinteger{-987}{oui}{non}\qquad +3) \ifinteger{6a87}{oui}{non}\qquad +4) \ifinteger{abcd}{oui}{non}\qquad +5) \ifinteger{-a}{oui}{non}\qquad +6) \ifinteger{-}{oui}{non}\qquad +7) \ifinteger{3.14}{oui}{non} +****************** Fin code ****************** + + +****************** Code 335 ****************** +\catcode`\@11 +\def\teststar{% + \futurelet\nxttok\teststar@i% % pioche le token suivant puis aller à \teststar@i +} +\def\teststar@i{% + \ifx *\nxttok\expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {% si le token suivant est une étoile + \afterassignment\teststar@bf% après avoir lu "*", aller à \teststar@bf + \let\nxttok= % lire l'étoile + }% si le token n'est pas une étoile + {\teststar@it% aller à \teststar@it + }% +} +\def\teststar@bf#1{{\bf#1}}% lit l'argument et le compose en gras dans un groupe +\def\teststar@it#1{{\it#1\/}}% lit l'argument et le compose en italique +\catcode`\@12 +Un essai \teststar{réussi} et un essai \teststar*{étoilé} réussi aussi. +****************** Fin code ****************** + + +****************** Code 336 ****************** +\catcode`@11 +\def\deftok#1#2{\let#1= #2\empty}% définit le token #1 (\empty au cas où #2 est vide) +\deftok\sptoken{ } +\def\ifnexttok#1#2#3{% lit les 3 arguments : #1=token #2=code vrai #3=code faux + \deftok\test@tok{#1}% stocke le token cherché + \def\true@code{#2}\def\false@code{#3}% et les codes à exécuter + \ifnexttok@i% aller à la macro récursive +} +\def\ifnexttok@i{% + \futurelet\nxttok\ifnexttok@ii% piocher le token d'après et aller à \ifnexttok@ii +} +\def\ifnexttok@ii{% + \ifx\nxttok\sptoken% si le prochain token est un espace + \def\donext{% + \afterassignment\ifnexttok@i% recommencer après + \let\nxttok= % après avoir absorbé cet espace + }% + \else + \ifx\nxttok\test@tok% si le prochain token est celui cherché + \let\donext\true@code% exécuter le code vrai + \else + \let\donext\false@code% sinon code faux + \fi + \fi + \donext% faire l'action décidée ci-dessus +} +\catcode`@12 +\ifnexttok W{je vais lire un W : }{je ne vais pas lire un W : }W.\par +\ifnexttok W{je vais lire un W : }{je ne vais pas lire un W : }a.\par +\ifnexttok *{je vais lire une étoile : }{je ne vais pas lire une étoile : } *.\par +\ifnexttok *{je vais lire une étoile : }{je ne vais pas lire une étoile : }a. +****************** Fin code ****************** + + +****************** Code 337 ****************** +\catcode`@11 +\newif\iftestspace \testspacefalse +\def\deftok#1#2{\let#1= #2}\deftok\sptoken{ } +\def\ifnexttok#1#2#3{% #1=token #2=code vrai #3=code faux + \let\test@tok= #1% stocke le token à tester + \def\true@code{#2}\def\false@code{#3}% et les codes à exécuter + \iftestspace \def\ifnexttok@i{\futurelet\nxttok\ifnexttok@ii}% + \else \def\ifnexttok@i{\futurelet\nxttok\ifnexttok@iii}% + \fi% après avoir défini la macro récursive selon le booléen, + \ifnexttok@i% l'exécuter +} +\def\ifnexttok@ii{% macro "normale" qui ne teste pas les espaces + \ifx\nxttok\test@tok \expandafter\true@code% exécuter le code vrai + \else \expandafter\false@code% sinon code faux + \fi +} +\def\ifnexttok@iii{% macro qui ignore les espaces + \ifx\nxttok\sptoken% si le prochain token est un espace + \def\donext{% + \afterassignment\ifnexttok@i% lire le token d'après + \let\nxttok= % après avoir absorbé l'espace + }% + \else + \let\donext\ifnexttok@ii% sinon, faire le test "normal" + \fi + \donext% faire l'action décidée ci-dessus +} +\catcode`@12 +\testspacefalse +\ifnexttok W{je vais lire un W : }{je ne vais pas lire un W : }W.\par +\ifnexttok W{je vais lire un W : }{je ne vais pas lire un W : } W.\medbreak +\testspacetrue +\ifnexttok W{je vais lire un W : }{je ne vais pas lire un W : }W.\par +\ifnexttok W{je vais lire un W : }{je ne vais pas lire un W : } W. +****************** Fin code ****************** + + +****************** Code 338 ****************** +\def\ifstarred#1{\ifnexttok*{\firstoftwo{#1}}} +\catcode`\@11 +\def\teststar{\ifstarred{\teststar@bf}{\teststar@it}} +\def\teststar@bf#1{{\bf#1}} +\def\teststar@it#1{{\it#1\/}} +\catcode`\@12 + +Un essai \teststar{réussi} et un essai \teststar*{étoilé} réussi aussi. +****************** Fin code ****************** + + +****************** Code 339 ****************** +\catcode`\@11 +\def\parsestop{\parsestop}% définit la macro-quark se trouvant en fin de code +\newtoks\code@toks% registre contenant le code lu +\def\parseadd{\addtotoks\code@toks} +\def\parse{% + \code@toks={}% initialise \code@toks à vide + \parse@i% et passe la main à \parse@i +} +\def\parse@i{\futurelet\nxttok\parse@ii}% lit le prochain token et va à \parse@ii +\def\parse@ii{% + \ifxcase\nxttok + \parsestop\parsestop@i% si la fin va être atteinte, aller à \parsestop@i + \sptoken\read@space% si un espace va être lu, aller à \read@space + \bgroup\read@bracearg% si une accolade ouvrante aller à \read@bracearg + \elseif + \testtoken% dans les autres cas, aller à \testtoken + \endif +} + +\def\parsestop@i\parsestop{% la fin est atteinte : manger \parsestop + \the\code@toks% afficher le registre de tokens +} +\expandafter\def\expandafter\read@space\space{% manger un espace dans le code + \testtoken{ }% et aller à \testtoken +} +\def\read@bracearg#1{% l'argument entre accolades est lu + \parseadd{{#1}}% puis ajouté (entre accolades) tel quel à \code@toks + \parse@i% ensuite, lire le prochain token +} +\catcode`@12 + +{\bf Exemple 1 :} +\catcode`@11 +\def\testtoken#1{% macro qui teste le token + \ifxcase{#1} + a{\parseadd{e}}% remplacer a par e + e{\parseadd{i}}% e par i + i{\parseadd{o}}% i par o + o{\parseadd{u}}% o par u + u{\parseadd{y}}% u par y + y{\parseadd{a}}% y par a + \elseif + \parseadd{#1}% sinon, ajouter le token tel quel + \endif + \parse@i% aller lire le token suivant +}% +\catcode`@12 +\parse +Ce texte devenu \`a peine reconnaissable montre que le r\'esultat contient des sonorit\'es +{\bf catalanes, corses ou grecques} assez inattendues. +\parsestop\medbreak + +{\bf Exemple 2 :} +\leavevmode \frboxsep=1pt +\catcode`@11 +\def\testtoken#1{% + \ifxcase{#1}% si #1 est un espace + { }{\parseadd{\hskip 0.75em }}% ajouter un espace + \ {\parseadd{\hskip 0.75em }} + \elseif + \parseadd{\frbox{#1}}% sinon, l'encadrer + \endif + \parse@i}% +\catcode`@12 +\parse Programmer en \TeX\ est facile\parsestop\medbreak + +{\bf Exemple 3 :} +\catcode`@11 +\def\testtoken#1{% + \ifx a#1\parseadd{X}\else\parseadd{#1}\fi% remplace les "a" par des "X" + \parse@i +} +\catcode`@12 +\parse a\bgroup\bf braca\egroup dabra\parsestop +****************** Fin code ****************** + + +****************** Code 340 ****************** +\catcode`\@11 +\def\ifbracefirst#1{% + \ifnum\catcode\expandafter\expandafter\expandafter + `\expandafter\firstto@nil\detokenize{#1W}\@nil=1 % tester si son catcode est 1 + \expandafter\firstoftwo\else\expandafter\secondoftwo\fi +} +\catcode`\@12 + +a) \ifbracefirst{123 456}{vrai}{faux}\qquad +b) \ifbracefirst{\bgroup12\egroup3 456}{vrai}{faux}\qquad +c) \ifbracefirst{{12}3 456}{vrai}{faux}\qquad +d) \ifbracefirst{1{2}3 456}{vrai}{faux}\qquad +\begingroup +\catcode`[=1 \catcode`]=2 % les crochets deviennent des accolades +e) \ifbracefirst[[]123 456][vrai][faux] +\endgroup +****************** Fin code ****************** + + +****************** Code 341 ****************** +\catcode`\@11 +\def\ifbracefirst#1{% teste si #1 commence par un token de catcode 1 + \ifspacefirst{#1}% si #1 commence par un espace + {\secondoftwo}% renvoyer faux + {\ifnum\catcode\expandafter\expandafter\expandafter + `\expandafter\firstto@nil\detokenize{#1W}\@nil=1 % tester si son catcode est 1 + \expandafter\firstoftwo + \else + \expandafter\secondoftwo + \fi + }% +} + +\catcode`\@12 +a) \ifbracefirst{}{vrai}{faux}\qquad b) \ifbracefirst{ }{vrai}{faux}\qquad +c) \ifbracefirst{ {}}{vrai}{faux} +****************** Fin code ****************** + + +****************** Code 342 ****************** +\catcode`\@11 +\def\parsestop@i\parsestop{% la fin va être atteinte + \detokenize\expandafter{\the\code@toks}% afficher le contenu du registre +} +\def\read@bracearg{% + \read@bracearg@i\relax% ajoute un \relax avant de passer la main à \read@bracearg@i +} +\def\read@bracearg@i#1\parsestop{% #1 = tout jusqu'à \parsestop + \exparg\ifbracefirst{\gobone#1}% retire le \relax et teste si #1 commence par "{" + {\expandafter\read@bracearg@ii\gobone#1\parsestop}% si oui, aller à \readbrace@ii + {\expandafter\testtoken\gobone#1\parsestop}% sinon, aller à \testtoken +} +\def\read@bracearg@ii#1{% lit l'argument entre accolades + \parseadd{{#1}}% ajoute cet argument entre accolades + \parse@i% aller lire le token suivant +} + +\def\testtoken#1{% + \parseadd{#1}% ajouter le token tel quel + \parse@i% aller lire le token suivant +} +\catcode`\@12 +\parse a\hbox\bgroup\bf braca\egroup {da}{}b{ra}\parsestop +****************** Fin code ****************** + + +****************** Code 343 ****************** +\catcode`\@11 +\def\parsestop{\parsestop}% définit le quark se trouvant en fin de code +\newtoks\code@toks% alloue le registre contenant le code lu +\def\parseadd#1{\code@toks\expandafter{\the\code@toks#1}} +\newif\ifparse@group +\def\parse{% + \code@toks{}% initialise le collecteur de tokens + \ifstarred% teste si la macro est étoilée + {\parse@grouptrue\parse@i}% mettre le booléen à vrai + {\parse@groupfalse\parse@i}% sinon à faux +} +\def\parse@i{\futurelet\nxttok\parse@ii}% lit le prochain token + % et va à \parse@ii +\def\parse@ii{% + \ifxcase\nxttok + \parsestop\parsestop@i% si la fin va être atteinte, aller à \parsestop@i + \sptoken\read@space% si un espace va être lu, aller à \read@space + \bgroup\read@bracearg% si une accolade ouvrante aller à \read@bracearg + \elseif + \testtoken% dans les autres cas, aller à \testtoken + \endif +} +\def\parsestop@i\parsestop{% la fin est atteinte + \the\code@toks% afficher le registre de tokens +} +\expandafter\def\expandafter\read@space\space{% \read@space mange un espace dans le code + \testtoken{ }% et va à \testtoken +} +\def\read@bracearg{% + \read@bracearg@i\relax% ajoute un \relax avant de passer la main à \read@bracearg@i +} +\def\read@bracearg@i#1\parsestop{% l'argument tout jusqu'à \parsestop + \expsecond\ifbracefirst{\gobone#1}% retire le \relax et teste si #1 commence par "{" + {\expandafter\read@bracearg@ii\gobone#1\parsestop}% lire l'argument entre accolades + {\expandafter\testtoken\gobone#1\parsestop}% sinon, tester le token +} +\def\read@bracearg@ii#1{% l'argument entre accolades est lu + \ifparse@group\expandafter\firstoftwo\else\expandafter\secondoftwo\fi% si macro étoilée + {\begingroup% ouvre un groupe pour parser l'intérieur de l'accolade + \def\parsestop@i\parsestop{% redéfinir localement \parsestop@i pour + \expandafter\endgroup% ne fermer le groupe qu'après avoir + \expandafter\parseadd% 1-développé à l'extérieur du groupe + \expandafter{\expandafter{\the\code@toks}}% + \parse@i% puis va lire le token suivant + }% + \parse*#1\parsestop% <- le \parsestop@i fermera le groupe semi-simple + } + {\parseadd{{#1}}% macro non étoilée, on ajoute #1 tel quel entre accolades + \parse@i% puis va lire le token suivant + }% +} +\def\testtoken#1{% macro qui teste le token + \ifxcase{#1} + a{\parseadd{e}} + e{\parseadd{i}} + i{\parseadd{o}} + o{\parseadd{u}} + u{\parseadd{y}} + y{\parseadd{a}} + \elseif + \parseadd{#1}% + \endif + \parse@i% aller lire le token suivant +} +\catcode`@12 +\frboxsep=1pt +a) \parse +Ce texte devenu \`a peine reconnaissable montre que le r\'esultat contient des sonorit\'es +{\bf catalanes, \frbox{corses} ou grecques} assez inattendues. +\parsestop\medbreak + +b) \parse* +Ce texte devenu \`a peine reconnaissable montre que le r\'esultat contient des sonorit\'es +{\bf catalanes, \frbox{corses} ou grecques} assez inattendues. +\parsestop +****************** Fin code ****************** + + +****************** Code 344 ****************** +\catcode`\@11 +\def\parse{% + \code@toks{}% initialise le collecteur de tokens + \ifstarred + {\parse@grouptrue + \ifnexttok{ }% si un espace suit l'étoile + {\afterassignment\parse@i% aller à \parse@i + \let\nxttok= }% après l'avoir mangé + {\parse@i}% sinon, aller à \parse@i + } + {\parse@groupfalse + \parse@i + }% +} +\def\testtoken#1{% macro qui teste le token + \ifxcase{#1} + a{\parseadd{e}}e{\parseadd{i}}i{\parseadd{o}}o{\parseadd{u}} + u{\parseadd{y}}y{\parseadd{a}} + \elseif + \parseadd{#1}% + \endif + \parse@i% aller lire le token suivant +} +\catcode`@12 +\frboxsep=1pt +a) \parse +Ce texte devenu \`a peine reconnaissable montre que le r\'esultat contient des sonorit\'es +{\bf catalanes, \frbox{corses} ou grecques} assez inattendues. +\parsestop\medbreak +b) \parse* +Ce texte devenu \`a peine reconnaissable montre que le r\'esultat contient des sonorit\'es +{\bf catalanes, \frbox{corses} ou grecques} assez inattendues. +\parsestop +****************** Fin code ****************** + + +****************** Code 345 ****************** +\catcode`\@11 +\def\grab@first#1#2{% + \ifx#1\empty\expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {\let#2\empty% si #1 est vide, ne rien faire et assigner <vide> à #2 + }% si #1 n'est pas vide + {\def\arg@b{#2}% stocke la macro #2 dans \arg@b + \exparg\ifbracefirst#1% si le 1er token de #1 est "{" + {\expandafter\grab@arg#1\@nil#1% aller lire l'argument avec \grab@arg + } + {% sinon, développer #1 avant de le regarder avec \futurelet : + \expandafter\futurelet\expandafter\nxttok\expandafter\test@nxttok#1\@nil#1% + % puis aller à \test@nxttok + }% + }% +} +\def\test@nxttok{% si le premier token de l'arg #1 de \grab@first est + \ifx\nxttok\sptoken% un espace + \expandafter\grab@spc% aller le lire avec \grab@spc + \else + \expandafter\grab@tok% sinon, lire le token avec \grab@tok + \fi +} +\def\grab@arg#1{% assigne l'argument de \grab@first (mis entre accolades) + \expandafter\def\arg@b{{#1}}% à #2 + \assign@tonil\relax% puis, assigne le reste à #1 de \grab@first +} +\expandafter\def\expandafter\grab@spc\space{% + \expandafter\def\arg@b{ }% assigne un espace à #2 de \grab@first + \assign@tonil\relax% puis, assigne le reste à #1 de \grab@first +} +\def\grab@tok#1{%% assigne le premier token de l'arg #1 de \grab@first + \expandafter\def\arg@b{#1}% à la macro #2 de \grab@first + \assign@tonil\relax% puis, assigne le reste à #1 de \grab@first +} +% assigne tout ce qui reste à lire (moins le "\relax") à la macro +% #1 de \grab@first +\def\assign@tonil#1\@nil#2{\expsecond{\def#2}{\gobone#1}} +\tt +a) \def\foo{1 {2 3} 4}\grab@first\foo\bar + "\meaning\bar"\qquad"\meaning\foo" + +b) \def\foo{ 1 {2 3} 4}\grab@first\foo\bar + "\meaning\bar"\qquad"\meaning\foo"" + +c) \def\foo{{1 2} 3 4}\grab@first\foo\bar + "\meaning\bar"\qquad"\meaning\foo" +****************** Fin code ****************** + + +****************** Code 346 ****************** +\catcode`\@11 +\def\ifstartwith#1#2{% #1=<texte> #2=<motif> + \ifempty{#2} + \firstoftwo% si <motif> est vide, renvoyer vrai + {\ifempty{#1}% si <code> est vide et <motif> non vide + \secondoftwo% renvoyer faux + {\def\startwith@code{#1}\def\startwith@pattern{#2}% + \ifstartwith@i% dans les autres cas, aller à \ifstartwith@i + }% + }% +} +\def\ifstartwith@i{% + \grab@first\startwith@code\first@code% extrait le premier "argument" de <texte> + \grab@first\startwith@pattern\first@pattern% et celui de <motif> + \ifx\first@code\first@pattern\expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {% si les deux arguments élargis sont égaux + \exparg\ifempty\startwith@pattern + \firstoftwo% et que <motif> ne contient plus rien => vrai + {\exparg\ifempty\startwith@code + \secondoftwo% si <texte> ne contient plus rien => faux + \ifstartwith@i% sinon poursuivre les tests + }% + } + \secondoftwo% si les deux argument élargis sont différents, renvoyer faux +} +\catcode`\@12 + +1) \ifstartwith{a b c}{a b}{oui}{non}\quad 2) \ifstartwith{a b}{a b c}{oui}{non}\quad +3) \ifstartwith{ 123 }{ }{oui}{non}\quad 4) \ifstartwith{ 123 }{1}{oui}{non}\quad +5) \ifstartwith{1{2} 3}{12}{oui}{non}\quad 6) \ifstartwith{1{2} 3}{1{2} }{oui}{non}\quad +7) \ifstartwith{{} {}}{ }{oui}{non}\quad 8) \ifstartwith{{} {}}{{} }{oui}{non}\quad +9) \ifstartwith{ {12} a}{ }{oui}{non}\quad10) \ifstartwith{ {12} a}{ {1}}{oui}{non} +****************** Fin code ****************** + + +****************** Code 347 ****************** +\catcode`\@11 +\def\ifcontain#1#2{% #1 contient-il #2? + \def\main@arg{#1}\def\pattern@arg{#2}% stocke le <code> et le <motif> + \ifempty{#2} + \firstoftwo% si #2 est vide => vrai + {\ifempty{#1} + \secondoftwo% si #1 est vide et pas #2 => faux + \ifcontain@i% sinon, aller faire les tests + }% +} +\def\ifcontain@i{% + \exptwoargs\ifstartwith\main@arg\pattern@arg + \firstoftwo% si motif est au début de code => vrai + {\exparg\ifempty\main@arg + \secondoftwo% sinon, si code est vide => faux + {\grab@first\main@arg\aux@arg% autrement, manger le 1er "argument" de code + \ifcontain@i% et recommencer + }% + }% +} +\catcode`\@12 +1) \ifcontain{abc def}{c }{oui}{non}\quad 2) \ifcontain{abc def}{cd}{oui}{non}\quad +3) \ifcontain{12 34 5}{1 }{oui}{non}\quad 4) \ifcontain{12 34 5}{ }{oui}{non}\quad +5) \ifcontain{a{b c}d}{b c}{oui}{non}\quad 6) \ifcontain{a{b c}d}{{b c}}{oui}{non}\quad +7) \ifcontain{{} {}}{ }{oui}{non}\quad 8) \ifcontain{{} {}}{{}}{oui}{non} +****************** Fin code ****************** + + +****************** Code 348 ****************** +\catcode`@11 +\newif\ifin@group +\def\ifcontain{% + \ifstarred + {\in@groupfalse\ifcontain@i\ifcontain@star}% + {\ifcontain@i\ifcontain@nostar}} + +\def\ifcontain@i#1#2#3{% #1 = macro à appeler selon étoile ou pas. #2 = code. #3 = motif + \def\main@arg{#2}\def\pattern@arg{#3}% + \ifempty{#3} + \firstoftwo + {\ifempty{#2} + \secondoftwo + #1% aller à \ifcontain@star ou \ifcontain@nostar + }% +} +\def\ifcontain@nostar{% + \exptwoargs\ifstartwith\main@arg\pattern@arg + \firstoftwo% si motif est au début de code => vrai + {\exparg\ifempty\main@arg + \secondoftwo% sinon, si code est vide => faux + {\grab@first\main@arg\aux@arg% autrement, manger le 1er "argument" de code + \ifcontain@nostar% et recommencer + }% + }% +} +\def\ifcontain@star{% + \expandafter\ifbracefirst\expandafter{\main@arg}% si code commence par "{" + {\grab@first\main@arg\aux@arg% enlever {<argument>} de main@arg + \begingroup% ouvrir un groupe + \in@grouptrue% mettre le booléen à vrai + \expandafter\def\expandafter\main@arg\aux@arg% assigner "argument" à \main@arg + \ifcontain@star% et recommencer avec ce nouveau \main@arg + }% si code ne commence pas par "{" + {\exptwoargs\ifstartwith\main@arg\pattern@arg% si motif est au début de code + \return@true% renvoyer vrai + {\expandafter\ifempty\expandafter{\main@arg}% si code est vide + {\ifin@group% et que l'on est dans un groupe + \endgroup \expandafter\ifcontain@star% en sortir et recommencer + \else% si on n'est pas dans un groupe, le code a été parcouru + \expandafter\secondoftwo% sans trouver <motif> => renvoyer faux + \fi + }% si code n'est pas vide + {\grab@first\main@arg\startwith@code% manger le 1er "argument" de code + \ifcontain@star% et recommencer + }% + }% + }% +} +\def\return@true{% + \ifin@group% tant qu'on est dans un groupe + \endgroup \expandafter\return@true% en sortir et recommencer + \else + \expandafter\firstoftwo% sinon, renvoyer vrai + \fi +} +\catcode`@12 +1) \ifcontain{ab {c d}ef}{c}{oui}{non}\quad 2) \ifcontain*{ab {c d}ef}{c}{oui}{non} +****************** Fin code ****************** + + +****************** Code 349 ****************** +\catcode`@11 +\newtoks\subst@toks% registre de tokens pour stocker le <texte> modifié +\def\substitute{% + \def\substitute@end{\the\subst@toks}% macro exécutée à la fin + \ifstarred + {\let\recurse@macro\substitute@star \substitute@i}% + {\let\recurse@macro\substitute@nostar\substitute@i}% +} +\def\substitute@i#1#2#3#4{% #1=macro à appeler selon étoile ou pas. + % #2=<texte> #3=<motif> #4=<motif de substi> + \def\code@arg{#2}\def\pattern@arg{#3}\def\subst@arg{#4}% + \subst@toks={}% initialiser le collecteur à vide + #1% aller à \substitute@star ou \substitute@nostar +} +\def\substitute@nostar{% + \exptwoargs\ifstartwith\code@arg\pattern@arg% si le <texte> commence par <motif> + {\eaddtotoks\subst@toks\subst@arg% ajouter <motif subst> + \grab@first\code@arg\aux@code% manger le 1er "argument" de <texte> + \substitute@nostar% et recommencer + } + {\expandafter\ifempty\expandafter{\code@arg}% + {\substitute@end% sinon, si <texte> est vide => afficher le registre de tokens + } + {\grab@first\code@arg\aux@arg% autrement, manger le 1er "argument" de <texte> + \eaddtotoks\subst@toks\aux@arg% et l'ajouter au registre de tokens + \substitute@nostar% et recommencer + }% + }% +} +\def\substitute@star{% + \expandafter\ifbracefirst\expandafter{\code@arg}% si <texte> commence par "{" + {\grab@first\code@arg\aux@arg% enlever {<argument>} de \code@arg + \begingroup% ouvrir un groupe + \def\substitute@end{% modifier localement la macro exécutée à la fin + \expandafter\endgroup\expandafter% avant de fermer le groupe + \addtotoks\expandafter\subst@toks\expandafter% ajouter au registre hors du groupe + {\expandafter{\the\subst@toks}}% ce qui est collecté localement, mis entre {} + \substitute@star% puis recommencer + }% + \subst@toks{}% initialiser à vide + \expandafter\def\expandafter\code@arg\aux@arg% % assigner "argument" au <texte> + \substitute@star% et recommencer avec ce nouveau \code@arg + }% si code ne commence pas par "{" + {\exptwoargs\ifstartwith\code@arg\pattern@arg% si <motif> est au début de <texte> + {\eaddtotoks\subst@toks\subst@arg% ajouter <motif subst> + \grab@first\code@arg\aux@code% manger le 1er "argument" de <texte> + \substitute@star% et recommencer + } + {\expandafter\ifempty\expandafter{\code@arg}% si <texte> est vide + {\substitute@end% aller à la macro de fin + }% si <texte> n'est pas vide + {\grab@first\code@arg\aux@code% manger le 1er "argument" de <texte> + \eaddtotoks\subst@toks\aux@code% et l'ajouter au registre + \substitute@star% et recommencer + }% + }% + }% +} +\catcode`@12 +1) \substitute{ab{\bf racada}bra}{a}{W}\qquad +2) \substitute*{ab{\bf racada}bra}{a}{W}\qquad +3) \substitute{12\frbox{\bf 34}56}{\bf}{\it}\qquad +4) \substitute*{12\frbox{\bf 34}56}{\bf}{\it} +****************** Fin code ****************** + + +****************** Code 350 ****************** +\catcode`@11 +\newtoks\subst@toks% registre de tokens pour stocker le <texte> modifié +\def\substitute{% + \def\substitute@end{\the\subst@toks}% macro exécutée à la fin + \ifstarred + {\let\recurse@macro\substitute@star \substitute@i}% + {\let\recurse@macro\substitute@nostar\substitute@i}% +} +\def\substitute@i#1#2#3{% #1=<texte> #2=<motif> #3=<motif de substi> + \def\code@arg{#1}\def\pattern@arg{#2}\def\subst@arg{#3}% + \subst@toks={}% initialiser à vide + \recurse@macro% aller à \substitute@star ou \substitute@nostar +} +\def\substitute@nostar{% + \exptwoargs\ifstartwith\code@arg\pattern@arg% si le <texte> commence par <motif> + {\eaddtotoks\subst@toks\subst@arg% ajouter <motif subst> + \grab@first\code@arg\aux@code% manger le 1er "argument" de <texte> + \recurse@macro% et recommencer + } + {\expandafter\ifempty\expandafter{\code@arg}% + \substitute@end% sinon, si <texte> est vide => afficher le registre de tokens + {\grab@first\code@arg\aux@arg% autrement, manger le 1er "argument" de <texte> + \eaddtotoks\subst@toks\aux@arg% et l'ajouter au registre de tokens + \recurse@macro% et recommencer + }% + }% +} +\def\substitute@star{% + \expandafter\ifbracefirst\expandafter{\code@arg}% si <texte> commence par "{" + {\grab@first\code@arg\aux@arg% enlever {<argument>} de \code@arg + \begingroup% ouvrir un groupe + \def\substitute@end{% modifier localement la macro exécutée à la fin + \expandafter\endgroup\expandafter% avant de fermer le groupe + \addtotoks\expandafter\subst@toks\expandafter% ajouter au registre hors du groupe + {\expandafter{\the\subst@toks}}% ce qui est collecté localement, mis entre {} + \recurse@macro% puis recommencer + }% + \subst@toks{}% initialiser à vide + \expandafter\def\expandafter\code@arg\aux@arg% % assigner "argument" au <texte> + \recurse@macro% et recommencer avec ce nouveau \code@arg + }% si <texte> ne commence pas par "{" : + \substitute@nostar% exécuter macro non étoilée pour une seule itération +} +\def\substitutetocs{% + \ifstarred + {\let\recurse@macro\substitute@star \substitutetocs@i}% + {\let\recurse@macro\substitute@nostar\substitutetocs@i}% +} +\def\substitutetocs@i#1#2#3#4{% #1=<texte> #2=<motif> #3=<motif de substi> #4=\<macro> + \def\substitute@end{\edef#4{\the\subst@toks}}% macro exécutée à la fin + \substitute@i{#1}{#2}{#3}% continuer comme avec \substitute +} +\catcode`@12 +\frboxsep=1pt +1) \substitute{ab{\bf racada}bra}{a}{W}\qquad +2) \substitute*{ab{\bf racada}bra}{a}{W}\qquad +3) \substitute{12\frbox{\bf 34}56}{\bf}{\it}\qquad +4) \substitute*{12\frbox{\bf 34}56}{\bf}{\it} +\medbreak + +1) \substitutetocs{ab{\bf racada}bra}{a}{W}\foo \meaning\foo\par +2) \substitutetocs*{ab{\bf racada}bra}{a}{W}\foo \meaning\foo\par +3) \substitutetocs{12\frbox{\bf 34}56}{\bf}{\it}\foo \meaning\foo\par +4) \substitutetocs*{12\frbox{\bf 34}56}{\bf}{\it}\foo \meaning\foo +****************** Fin code ****************** + + +****************** Code 351 ****************** +\catcode`@11 +\def\vecteur{% + \ifnexttok[% si la macro est suivie d'un crochet + \vecteur@i% aller à la macro à arguments délimités + {\vecteur@i[1]}% sinon, ajouter l'argument optionnel par défaut entre crochets +} +\def\vecteur@i[#1]#2{% #1=arg optionnel #2=arg obligatoire + $(x_{#1},\ldots,x_{#2})$ +} +\catcode`@12 +1) \vecteur{n}\qquad 2) \vecteur[0]{k}\qquad 3) \vecteur[i]j \qquad4) \vecteur[]n +****************** Fin code ****************** + + +****************** Code 352 ****************** +\catcode`@11 +\def\forcemath#1{% compose #1 en mode math, quel que soit le mode en cours + \ifmmode\expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {#1}{$#1$}% +} +\def\vecteur{% + \ifnexttok[% si la macro est suivie d'un crochet + \vecteur@i% aller à la macro à arguments délimités + {\vecteur@i[1]}% sinon, ajouter l'argument optionnel par défaut entre crochets +} +\def\vecteur@i[#1]{% + \ifnexttok(% si une parenthèse vient ensuite + {\vecteur@ii[#1]}% aller à la macro à argument délimités + {\vecteur@ii[#1](x)}% sinon, rajouter "x" comme argument optionnel +} +\def\vecteur@ii[#1](#2)#3{% #1 et #2=arg optionnel #3=arg obligatoire + \forcemath{({#2}_{#1},\ldots,{#2}_{#3})}% +} +\catcode`@12 +1) \vecteur{n}\qquad 2) \vecteur[0]{k}\qquad +3) \vecteur[i](y)j \qquad4) \vecteur[](\alpha)n +****************** Fin code ****************** + + +****************** Code 353 ****************** +\catcode`@11 +\def\vecteur{% + \ifnexttok[% si la macro est suivie d'un crochet + \vecteur@bracket% lire cet argument entre crochet + {\ifnexttok(% sinon, si elle est suivie d'une parenthèse + \vecteur@paren % lire cet argument entre parenthèses + {\vecteur@i[1](x)}% sinon, transmettre les arguments par défaut + }% +} +\def\vecteur@bracket[#1]{% + \ifnexttok(% s'il y a une parenthèse après + {\vecteur@i[#1]}% lire la parenthèse + {\vecteur@i[#1](x)}% sinon, donne "x" comme argument par défaut +} +\def\vecteur@paren(#1){% + \ifnexttok[% si le caractère suivant est un crochet + {\vecteur@ii(#1)}% lire l'argument entre crochets + {\vecteur@ii(#1)[1]}% sinon, donner "1" comme argument par défaut +} +\def\vecteur@i[#1](#2)#3{\forcemath{({#2}_{#1},\ldots,{#2}_{#3})}} +\def\vecteur@ii(#1)[#2]{\vecteur@i[#2](#1)}% met les arg optionnels dans l'ordre +\catcode`@12 +1) \vecteur{n}\qquad 2) \vecteur[i](y){j}\qquad 3) \vecteur(y)[i]{j}\qquad +4) \vecteur[0]{k}\qquad 5) \vecteur(\alpha){n} +****************** Fin code ****************** + + +****************** Code 354 ****************** +\catcode`\@11 +\def\foo#1{% #1 -> lit le premier argument obligatoire + \ifnexttok[% si le token suivant est un crochet + {\foo@i{#1}}% aller à \foo@i qui va lire cet argument + {\foo@i{#1}[xxx]}% sinon, transmettre [xxx] à foo@i +} + +\def\foo@i#1[#2]#3#4{% lit l'arg obligatoire + arg optionnel + 2 arg obligatoires + \ifnexttok[ + {\foo@ii{#1}[#2]{#3}{#4}}% + {\foo@ii{#1}[#2]{#3}{#4}[y]}% +} + +\def\foo@ii#1[#2]#3#4[#5]#6{% lit tous les arguments + 1="#1" 2="#2" 3="#3" 4="#4" 5="#5" 6="#6"% +} + +\catcode`\@12 +1) \foo{arg1}{arg2}{arg3}{arg4}\par +2) \foo{arg1}[OPT\_A]{arg2}{arg3}{arg4}\par +3) \foo{arg1}{arg2}{arg3}[OPT\_B]{arg4}\par +4) \foo{arg1}[OPT\_A]{arg2}{arg3}[OPT\_B]{arg4}\medbreak +****************** Fin code ****************** + + +****************** Code 355 ****************** +\catcode`\@11 +\newcount\macro@cnt% numéro à mettre dans le nom des sous macros +\newcount\arg@cnt% compte le nombre d'arguments +\newtoks\param@text% texte de paramètre des macros sous forme "#x" et/ou "[#x]" +\newtoks\arg@text% arguments sous forme "{#x}" et/ou "[#x]" + +\def\newmacro#1{% + % \macro@name construit le <nom> de la macro et éventuellement "@[<chiffre romain>]" + \def\macro@name##1{\expandafter\gobone\string#1\ifnum##1>0 @[\romannumeral##1]\fi}% + \macro@cnt=0 \arg@cnt=0 % initialise les compteurs + \param@text{}\arg@text{}% vide les registres de texte de paramètre et d'argument + \newmacro@i% va voir le prochain token +} + +\def\newmacro@i{\futurelet\nxttok\newmacro@ii}% met le prochain token dans \nxttok... +% ...puis va à la macro : +\def\newmacro@ii{% + \ifxcase\nxttok + [\newmacro@optarg% si le prochain token est un crochet aller à \newmacro@optarg + \bgroup% si c'est un accolade ouvrante + % le texte de paramètre est fini et il faut définir la macro + {\defname{\macro@name\macro@cnt\expandafter}% + \the\param@text}% <- le {<code>} est juste après, il n'est pas encore lu + \elseif% sinon, c'est donc un chiffre + \newmacro@arg% aller à \newmacro@arg + \endif +} + +\def\newmacro@optarg[#1]{% lit la valeur par défaut de l'argument optionnel + % Définit la macro \<nom>@[<nbre>] qui lit tous les arguments (optionnels ou pas) + % jusqu'alors définis à l'aide de \param@text. Puis, cette macro testera si le prochain + % token est un crochet + \expandafter\edef\csname\macro@name\macro@cnt\expandafter\endcsname\the\param@text{% + \noexpand\ifnexttok[% + % si oui : la macro \<nom>@<nbr+1> le lira + {\expandafter\noexpand\csname\macro@name{\numexpr\macro@cnt+1}\expandafter\endcsname + \the\arg@text}% + % si non : transmettre à \<nom>@<nbr+1> l'argument optionnel par défaut lu + {\expandafter\noexpand\csname\macro@name{\numexpr\macro@cnt+1}\expandafter\endcsname + \the\arg@text[\unexpanded{#1}]}% + }% + \advance\arg@cnt 1 % incrémenter le numéro d'argument + % pour ajouter "[#<x>]" à \param@text et à \arg@text + \eaddtotoks\param@text{\expandafter[\expandafter##\number\arg@cnt]}% + \eaddtotoks\arg@text {\expandafter[\expandafter##\number\arg@cnt]}% + \advance\macro@cnt 1 % incrémenter le numéro de nom de macro + \newmacro@i% va voir le token suivant +} + +\def\newmacro@arg#1{% #1=nombre d'arguments obligatoires à ajouter + % boucle qui ajoute "#<x>#<x+1>etc" dans \param@text + % et "{#<x>}{#<x+1>}etc" dans \arg@text + \ifnum#1>\z@ % tant qu'on n'a pas ajouté le nombre de #x nécessaire + \advance\arg@cnt 1 % incrémenter le numéro d'argument + % pour ajouter #x à \param@text et {#x} à \arg@text + \eaddtotoks\param@text{\expandafter##\number\arg@cnt}% + \eaddtotoks\arg@text {\expandafter{\expandafter##\number\arg@cnt}}% + \expandafter\newmacro@arg\expandafter{\number\numexpr#1-1\expandafter}% boucler + \else% si les arguments sont tous ajoutés + \expandafter\newmacro@i% lire le token suivant + \fi +} +\catcode`\@12 +\newmacro\foo 1[xxx]2[y]1{1="#1" 2="#2" 3="#3" 4="#4" 5="#5" 6="#6"} +a) \foo{arg1}{arg2}{arg3}{arg4}\par +b) \foo{arg1}[OPT\_A]{arg2}{arg3}{arg4}\par +c) \foo{arg1}{arg2}{arg3}[OPT\_B]{arg4}\par +d) \foo{arg1}[OPT\_A]{arg2}{arg3}[OPT\_B]{arg4}\medbreak + +\meaning\foo\par +\expandafter\meaning\csname foo@[i]\endcsname\par +\expandafter\meaning\csname foo@[ii]\endcsname +****************** Fin code ****************** + + +****************** Code 356 ****************** +\newmacro\framebox[ULRD]1{% #1 = ULRD (Up, Down, Right, Left) +% ne pas changer le mode H ou V en cours + \hbox{% enferme dans une \hbox + \uppercase{\ifin{#1}L}{\vrule width\frboxrule}{}% réglure gauche + \vtop{% + \vbox{% 1er élément de la \vtop + \uppercase{\ifin{#1}U}{% si la réglure sup doit être tracée + \hrule height\frboxrule% réglure supérieure + \kern\frboxsep% espace haut + } + {}% + \hbox{% + \uppercase{\ifin{#1}L}{\kern\frboxsep}{}% espace gauche + #2% contenu + \uppercase{\ifin{#1}R}{\kern\frboxsep}{}% espace droite + }% + }% puis autres éléments de la \vtop, sous la ligne de base + \uppercase{\ifin{#1}D}{% + \kern\frboxsep% espace bas + \hrule height\frboxrule% réglure inférieure + }% + {}% + }% + \uppercase{\ifin{#1}R}{\vrule width\frboxrule}{}% réglure droite + }% +} +\frboxsep=1pt +Boite \framebox{entière}, \framebox[ud]{Up down}, \framebox[LR]{Left Right}, +\framebox[LU]{Left Up} et \framebox[rd]{Right Down}. +****************** Fin code ****************** + + +****************** Code 357 ****************** +\catcode`\@11 +\newtoks\eargs@toks +\newtoks\eargs@temptoks +\def\eargs[#1]#2{% #1=liste des développements #2=macro + \eargs@toks{#2}% mettre la macro dans le collecteur de tokens + \expandafter\eargs@i\detokenize{#1}\@nil% appeler \eargs@i avec + % la liste des developpements +} + +\def\eargs@i#1\@nil{% #1=liste des n-développements restant + \ifempty{#1}% s'il n' y plus de n-développements + {\the\eargs@toks}% exécuter la macro et ses arguments développés + {\eargs@ii#1\@nil}% sinon appeller la macro qui lit un argument +} + +% #1=n-développement actuel #2=liste des n-développements restants #3=argument lu +\def\eargs@ii#1#2\@nil#3{% + \if+#1% si #1="+", un \edef est demandé pour cet argument + \edef\eargs@tempmacro{{#3}}% le stocker dans une macro temporaire + \else% sinon + \eargs@temptoks={#3}% stocker l'argument dans un registre temporaire + \for\eargs@loop = 1 to #1\do 1 % faire #1 fois : + {\eargs@temptoks=% 1-développer le 1er token du registre temporaire + \expandafter\expandafter\expandafter{\the\eargs@temptoks}% + }% puis le stocker dans la macro temporaire + \edef\eargs@tempmacro{{\the\eargs@temptoks}}% + \fi + \eaddtotoks\eargs@toks\eargs@tempmacro% ajouter le contenu de la macro au collecteur + \eargs@i#2\@nil% appeler \eargs@i avec les n-développements restants +} +\catcode`\@12 +\def\foo#1#2#3#4#5{\detokenize{1="#1" 2="#2" 3="#3" 4="#4" 5="#5"}} +\def\aaa{\bbb}\def\bbb{\ccc}\def\ccc{Bonjour} + +\eargs[0123+]\foo{\aaa\bbb}{\aaa\bbb}{\aaa\bbb}{\aaa\bbb}{\aaa\bbb}. +****************** Fin code ****************** + + +****************** Code 358 ****************** +\catcode`\@11 +\def\detectmark#1{% #1 est le marqueur + \begingroup + \catcode`#1=13 % rendra #1 actif après la macro + \begingroup% pour les besoins du \lccode + \lccode`\~=`#1 % transforme "~" en " #1 actif" + \lowercase{\endgroup\def~##1~}{\markeffect{##1}}% + \detectmark@i +} +\def\detectmark@i#1{% + #1% exécute le code + \endgroup% ferme le groupe, le marqueur perd son catcode actif +} +\catcode`\@12 +a) \def\markeffect#1{{\bf #1}}% met en gras +\detectmark+{Un +argument+ où les +marqueurs+ sont détectés} +\medskip + +b) \def\markeffect#1{% met dans une boite + \begingroup + \frboxsep=1pt % modifie l'espacement entre texte et encadrement + \frbox{\strut#1}% encadre + \endgroup +} +\detectmark|{Un |argument| où les |marqueurs| sont détectés} +\medskip + +c) \def\markeffect#1{$\vcenter{\hbox{#1}\hbox{#1}}$}% superpose 2 fois +\detectmark`{Un `argument` où les `marqueurs` sont détectés} +****************** Fin code ****************** + + +****************** Code 359 ****************** +\catcode`\@11 +\def\detectmark#1{% + \begingroup + \catcode`#1=13 % rendra #1 actif après la macro + \begingroup% pour les besoins du \lccode + \lccode`\~=`#1 % transforme "~" en " #1 actif" + \lowercase{\endgroup\def~##1~}{\markeffect{##1}}%% + \detectmark@i +} +\def\detectmark@i#1{% + #1% lit le code + \endgroup% ferme le groupe, le marqueur perd son catcode actif +} +\catcode`\@12 +\def\markeffect#1{{\bf #1}}% met en gras +\frbox{\detectmark+{Un +argument+ où les +marqueurs+ sont détectés}} +****************** Fin code ****************** + + +****************** Code 360 ****************** +\catcode`\@11 +\newtoks\alter@toks% collecteur de tokens + +\def\alter#1#2{% #1= délimiteur #2 = macro à altérer + \let\alter@macro#2% sauvegarde la macro + \edef\alter@restorecatcode{% restaurera le catcode de #1 + \catcode`\noexpand#1=\the\catcode`#1 }% + \edef\alter@tmp{\let\noexpand\alter@markertoks= \string#1}% + \alter@tmp% et sauvegarder le délimiteur après avoir mis son catcode à 12 + \edef\alter@tmp{\def\noexpand\alter@readlitterate@i\string#1####1\string#1}% + % développe les \string#1 pour que les arguments délimités aient + % des délimiteurs de catcode 12 + \alter@tmp{% <- comme si on écrivait "\def\alter@readlitterate@i#1##1#1" + \endgroup% après avoir lu ##1 (tokens rendus inoffensifs), fermer le groupe + \addtotoks\alter@toks{{\tt##1}}% ajouter ces tokens + \alter@i% et aller lire le prochain token + }% + \alter@toks{}% initialise le collecteur de tokens + \afterassignment\alter@i% aller lire le premier token après avoir + \let\alter@tmptok= % mangé l'accolade ouvrante de l'<argument> qui suit +} + +\def\alter@i{% lit le prochain token et va à \alter@ii + \futurelet\alter@nxttok\alter@ii}% + +\def\alter@ii{% teste le token qui doit être lu + \ifxcase\alter@nxttok% si le token à lire est + \egroup \alter@stop% "}" : aller à \alterstop@i + \sptoken \alter@readspc% " " : aller à \alter@readspc + \bgroup \alter@readarg% "{" : aller à \alter@readarg + \alter@markertoks \alter@readlitterate% "<delimiteur>" : aller à \alter@readlitterate + \elseif + \alter@readtok% dans les autres cas, aller à \alter@readtok + \endif +} + +\def\alter@readlitterate{% le prochain token est le délimiteur + \begingroup% ouvrir un groupe + \for\alter@tmp=0to255\do{\catcode\alter@tmp=12 }% + % mettre tous les catcodes à 12 + \defactive{ }{\ }% sauf l'espace rendu actif + \doforeach\alter@tmp\in{<,>,-,`,{,},'}% pour chaque motif de ligature + {\unless\if\alter@tmp\alter@markertoks% s'il est différent du délimiteur + % le rendre actif pour éviter la ligature + \expandafter\alter@defligchar\alter@tmp + \fi + }% + \alter@readlitterate@i% puis aller à \alter@readlitterate@i... + % ...qui a été définie dans \alter +} + +\def\alter@defligchar#1{% définit le caractère pour ne pas provoquer de ligature + \defactive#1{\string#1{}}% +} + +\expandafter\def\expandafter\alter@readspc\space{% mange un espace dans le code + \addtotoks\alter@toks{ }% ajoute l'espace + \alter@i% puis lire le token suivant +} + +\def\alter@readarg{% le token qui suit est "{" + \begingroup% ouvrir un groupe + \def\alter@stop@ii{% et modifier localement la macro appelée à la toute fin, + % après que l'accolade fermante ait été mangée (par \alterstop@i) + \expandafter\endgroup% retarder la fermeture de groupe ouvert ci-dessus + \expandafter\addtotoks\expandafter\alter@toks\expandafter + {\expandafter{\the\alter@toks}}% + % pour ajouter hors du groupe ce qui a été collecté à l'intérieur, + % le tout mis entre accolades + \alter@i% puis, lire le token suivant + }% + \alter@toks{}% au début du groupe, initialiser le collecteur + \afterassignment\alter@i% aller lire le prochain token après + \let\alter@tmptok= % avoir mangé l'accolade ouvrante +} + +\def\alter@readtok#1{% le prochain token ne demande pas une action spéciale + \addtotoks\alter@toks{#1}% l'ajouter au collecteur + \alter@i% et aller lire le token suivant +} + +\def\alter@stop{% le token à lire est "}" + \afterassignment\alter@stop@ii% aller à \alter@stop@ii après + \let\alter@tmptok= % avoir mangé l'accolade fermante +} + +\def\alter@stop@ii{% donner à la \<macro> tout ce qui a été récolté + \expandafter\alter@macro\expandafter{\the\alter@toks}% + \alter@restorecatcode% puis restaure le catcode du délimiteur +} +\catcode`@12 + +\frboxsep=1pt +\alter|\frbox{Texte normal - |#& }| - texte normal - |_^ ##| - texte normal} +\alter=\frbox{La macro =\alter= autorise du verbatim dans +des commandes imbriquées \frbox{comme ici =\alter=}.} +****************** Fin code ****************** + + +****************** Code 361 ****************** +\def\hello#1#2{Bonjour #1 et #2 !} +\hello{foo}{bar}\par +\alter|\identity{\hello{macro |{{{\foo|}{macro |\bar}|}} +****************** Fin code ****************** + + +****************** Code 362 ****************** +\def\retokenize#1{% + \immediate\openout\wtest=retokenize.tex % ouvre le fichier + \immediate\write\wtest{\unexpanded{#1}}% y écrit l'argument + \immediate\closeout\wtest% ferme le fichier + \input retokenize.tex % lit le fichier selon les catcodes en vigueur + \unskip% mange l'espace précédemment ajouté qui provient de la fin du fichier +} +\frboxsep=1pt +1) \frbox{Programmer en \catcode`\~=12 \TeX{} est~facile et~utile.}\par +2) \frbox{Programmer en \retokenize{\catcode`\~=12 \TeX{} est~facile} et~utile.}\par +3) \frbox{Programmer en \catcode`\~=12 \retokenize{\TeX{} est~facile} et~utile.} +****************** Fin code ****************** + + +****************** Code 363 ****************** +\frboxsep=1pt +1) \frbox{Programmer \retokenize{\litterate|en \TeX {} est |}facile et utile.}\par +2) \frbox{Programmer \retokenize{\litterate|en \TeX{} est |}facile et utile.} +****************** Fin code ****************** + + +****************** Code 364 ****************** +\frboxsep=1pt +1) \frbox{Programmer en \catcode`\~=12 \TeX{} est~facile et~utile.}\par +2) \frbox{Programmer en \scantokens{\catcode`\~=12 \TeX{} est~facile} et~utile.}\par +3) \frbox{Programmer en \catcode`\~=12 \scantokens{\TeX{} est~facile} et~utile.}\par +4) \frbox{Programmer \scantokens{\litterate|en \TeX {} est facile|} et utile.}\par +5) \frbox{Programmer \scantokens{\litterate|en \TeX{} est facile|} et utile.} +****************** Fin code ****************** + + +****************** Code 365 ****************** +\scantokens{a}b +****************** Fin code ****************** + + +****************** Code 366 ****************** +\begingroup\endlinechar=-1 \scantokens{a}b\endgroup +****************** Fin code ****************** + + +****************** Code 367 ****************** +\edef\foo{\scantokens{Bonjour le monde}}% produit une erreur +****************** Fin code ****************** + + +****************** Code 368 ****************** +\expandafter\def\expandafter\foo\expandafter + {\scantokens{Bonjour le monde}}% produit une erreur +****************** Fin code ****************** + + +****************** Code 369 ****************** + +Voici la macro \string\foo\ : \foo. +****************** Fin code ****************** + + +****************** Code 370 ****************** +\catcode`\@11 +\def\scandef#1#2{% #1=\<macro> #2=<texte> + \begingroup + \endlinechar=-1 % pas de caractère de fin de ligne + \everyeof{\@nil#1\noexpand}% ajoute "\@nil\<macro>\noexpand" avant la fin du fichier + \expandafter\scandef@i\expandafter\relax\scantokens{#2}% +} +\def\scandef@i#1\@nil#2{% "\@nil#2" ont été ajouté par \everyeof + \endgroup% ferme le groupe + \expandafter\def\expandafter#2\expandafter{\gobone#1}% et définit la \<macro> +} +\catcode`@12 +\def\foo{% + Dans tout l'argument de \string\foo, <<~>> est actif + sauf + \catcode`\~12 + \scandef\bar{dans celui de \string\bar : <<~>>}% + \catcode`~13 + \bar +} +\foo +****************** Fin code ****************** + + +****************** Code 371 ****************** +{% +\endlinechar=`\d% insère la lettre "d" à chaque fin de ligne +% le \noexpan(d) est incomplet +Voici la macro \string\foo\ : \foo.% fins de ligne... +}% ...commentées pour éviter le "d" +****************** Fin code ****************** + + +****************** Code 372 ****************** +\catcode`\@11 +\def\cprotect#1{% #1 est la \<macro> + \def\cprotect@i##1{% ##1 est l'<argument> + \endgroup% ferme le groupe précédemment ouvert + #1{\scantokens{##1\noexpand}}% + }% + \begingroup% rend tous les octets de catcode12 + \for\cprotect@temp=0to255\do{\catcode\cprotect@temp=12 }% + \catcode`\{=1 \catcode`\}=2 % sauf "{" et "}" + \cprotect@i% puis, lit l'argument +} +\catcode`@12 +\frboxsep=1.5pt +1) \cprotect\frbox{foo \litterate-&# #^ ^_%- bar}\par +2) \cprotect\frbox{\catcode`\~=12 a~b~c~d}\par +3) \cprotect\frbox{foo \litterate-\bar- \cprotect\frbox{\litterate-&# #-} fin} +****************** Fin code ****************** + + +****************** Code 373 ****************** +\catcode`@11 +\def\Cprotect#1{% #1 est la \<macro> + \def\Cprotect@i##1{% ##1 est la liste des arguments + \endgroup% ferme le groupe précédemment ouvert + \toks0={#1}% met la \<macro> dans le registre de tokens + \Cprotect@ii##1\quark% \quark est mis à la fin des arguments + \the\toks0 % exécute le registre + }% + \begingroup% rend tous les octets de catcode12 + \for\temp@arg= 0 to 255 \do{% changer à 12 tous les catcodes + \unless\ifnum\catcode\temp@arg=1 % sauf si catcode=1 + \unless\ifnum\catcode\temp@arg=2 % ou 2 + \catcode\temp@arg=12 + \fi + \fi}% + \Cprotect@i% puis, lit l'argument +} +\def\Cprotect@ii#1{% #1 est l'argument courant (dépouillé de ses accolades) + \def\temp@arg{#1}% stocke l'argument pour le tester ci dessous : + \unless\ifx\quark\temp@arg% si la fin n'est pas atteinte + % ajouter "{\scantokens{#1\noexpand}}" au registre + \addtotoks{\toks0}{{\scantokens{#1\noexpand}}}% + \expandafter\Cprotect@ii% et recommencer + \fi +} +\catcode`@12 + +\def\test#1#2{Bonjour #1 et #2} +\Cprotect\test{{argument 1 : \litterate-\foo-}{argument 2 : \litterate-\bar-}} +****************** Fin code ****************** + + +****************** Code 374 ****************** +\newdimen\pixelsize \newdimen\pixelsep +\def\pixel{\vrule height\pixelsize width\pixelsize depth0pt } +\def\vblankpixel{\vrule height\pixelsize width0pt depth0pt } +\def\blankpixel{\vblankpixel \vrule height0pt width\pixelsize depth0pt } +\def\gap{\kern\pixelsep} +\pixelsize=3pt \pixelsep=1pt +Essai : +\vbox{% aligne verticalement + \offinterlineskip% annule le ressort d'interligne + \lineskip=\pixelsep\relax% pour le mettre à \pixelsep + \hbox{\pixel\gap\blankpixel\gap\blankpixel\gap\blankpixel\gap\pixel}% 1re ligne + \hbox{\pixel\gap\pixel \gap\blankpixel\gap\pixel \gap\pixel}% 2e ligne +} +****************** Fin code ****************** + + +****************** Code 375 ****************** +\pixelsize=3pt \pixelsep=1pt +Essai : +\vtop{% + \offinterlineskip \lineskip=\pixelsep\relax + \vbox{% + \hbox{\blankpixel\gap\pixel \gap\pixel \gap\pixel}% *** + \hbox{\pixel \gap\blankpixel\gap\blankpixel\gap\pixel}% * * + \hbox{\pixel \gap\blankpixel\gap\blankpixel\gap\pixel}% * * + \hbox{\pixel \gap\blankpixel\gap\blankpixel\gap\pixel}% * * + \hbox{\blankpixel\gap\pixel \gap\pixel \gap\pixel}% *** + }% ----ligne de base + \hbox {\blankpixel\gap\blankpixel\gap\blankpixel\gap\pixel}% * + \hbox {\blankpixel\gap\pixel \gap\pixel }% ** +} +****************** Fin code ****************** + + +****************** Code 376 ****************** +\catcode`\@11 +\begingroup% dans ce groupe : +\catcode`\ =12\relax% l'espace devient un "caractère autre" +\catcode`\^^M=13\relax% le retour à la ligne est actif +\edef^^M{\string,}% et se développe en une virgule (de catcode 12) +\global\deftok\otherspc{ }% définit un espace de catcode 12 +\xdef\letter@code{% macro contenant le dessin de la lettre "e" + ** +* * +*** +* + ***}% +\endgroup + +\def\makecar@i#1{% #1 = dessin de la lettre avec les caractères "," "*" et " " + \doforeach\current@line\in{#1}% pour chaque ligne dans #1 : + {\ifx\empty\current@line% si la ligne est vide + \addtomacro\pixabove{\hbox{\vblankpixel}}% ajouter une fausse ligne + \else% sinon + \let\pix@line\empty% initialiser le code de la ligne à vide + \expandafter\makecar@ii\current@line\quark% et la construire + \fi + }% +} + +\def\makecar@ii#1{% #1=caractère de dessin de la ligne en cours + \ifxcase#1% si le caractère est + * {\addtomacro\pix@line\pixel}% + \otherspc{\addtomacro\pix@line\blankpixel}% + \endif + \ifx#1\quark% si la fin est atteinte + \addtomacro\pix@line\unkern% annuler le dernier espace interpixel + \eaddtomacro\pixabove{% et encapsuler \pix@line dans une \hbox + \expandafter\hbox\expandafter{\pix@line}}% + \else% si la fin n'est pas atteinte, ajouter l'espace interpixel + \addtomacro\pix@line\gap + \expandafter\makecar@ii% recommencer avec le caractère suivant + \fi +} +\pixelsize=3pt \pixelsep=1pt +\let\pixabove\empty% initialisation de la macro finale à vide +\exparg\makecar@i\letter@code% appelle la macro qui construit \pixabove +La lettre +\vtop{% enferme le tout dans une \vtop : + \offinterlineskip\lineskip=\pixelsep% ajuste l'espace interligne + \vbox{\pixabove}% affiche le caractère créé +}. +****************** Fin code ****************** + + +****************** Code 377 ****************** +\catcode`\@11 +\begingroup% dans ce groupe : +\catcode`\ =12\relax% l'espace devient un "caractère autre" +\catcode`\^^M=13\relax% le retour à la ligne est actif +\edef^^M{\string,}% et se développe en une virgule (de catcode 12) +\global\deftok\otherspc{ }% définit un espace de catcode 12 +\xdef\letter@code{% macro contenant le dessin de la lettre "g" + *** +* * +* * +* * + ***_ + * + **}% +\endgroup + +\def\makecar#1#2{% #1=nom recevant le code final #2=macro contenant le dessin + \let\pixabove\empty \let\pixbelow\empty \let\pix@line\empty% initialise à vide + \exparg\ifin{#2}_% si le code contient _ + {\expandafter\makecar@iii#2\@nil}% aller à \makecar@iii + {\exparg\makecar@i{#2}}% sinon, à \makecar@i + \edef#1{% définit la macro #1 comme + \vtop{% une \vtop contenant : + \unexpanded{\offinterlineskip\lineskip\pixelsep}% réglage d'espace inter ligne + \vbox{\unexpanded\expandafter{\pixabove}}% \vbox des pixels au-dessus + % de la ligne de base + \unless\ifx\pixbelow\empty% s'il y a des pixels au-dessous de la baseline + \unexpanded\expandafter{\pixbelow}% les ajouter dans la \vtop + \fi + }% + }% +} + +\def\makecar@iii#1_,#2\@nil{% + \makecar@i{#2}% construit la partie au-dessous de la baseline + \let\pixbelow\pixabove% et affecte le code à \pixbelow + \let\pixabove\empty \let\pix@line\empty% ré-initialise + \makecar@i{#1}% construit la partie au-dessus de la baseline +} + +\makecar\lettreg\letter@code +\catcode`\@12 +\pixelsize=3pt \pixelsep=1pt + +Essai : \lettreg +****************** Fin code ****************** + + +****************** Code 378 ****************** +\catcode`\@11 +\begingroup +\expandafter\gdef\csname impact@" "\endcsname{% définit la lettre "espace" + \hskip 4\pixelsize plus.5\pixelsize minus.5\pixelsize\relax}% +\catcode`\^^M=13\relax% le retour à la ligne est actif +\edef^^M{\string,}% et se développe en une virgule (de catcode 12) +\catcode`\ =12\relax% l'espace devient un "caractère autre" +\gdef\impact@alphabet{ +a/ +*** + * + *** +* * +****, +b/ +* +* +*** +* * +* * +* * +***, +% beaucoup de caractères omis +9/ + *** +* * +* * + **** + * + * + ***, +0/ + *** +* * +* * +* * * +* * +* * + ***, +error/ +* * * + * * +* * * + * * +* * * + * * +* * *}% <- commenter la fin de ligne +\endgroup% +% On parcourt le texte de remplacement de \impact@alphabet +\edef\saved@crcatcode{\catcode13=\the\catcode13\relax}% +\catcode`\^^M=13\relax% le retour à la ligne est actif +\edef^^M{\string,}% et se développe en une virgule (de catcode 12) +\expsecond{\doforeach\letter@name/\letter@code\in}\impact@alphabet% + {\edef\letter@name{\letter@name}% développe la lettre (^^M devient ",") + \edef\letter@code{\letter@code}% développe le code (^^M devient ",") + \exparg\ifstart\letter@name,% si la lettre commence par "," + {\edef\letter@name{\expandafter\gobone\letter@name}}% la retirer + {}% + \exparg\ifstart\letter@code,% si le code commence par "," + {\edef\letter@code{\expandafter\gobone\letter@code}}% la retirer + {}% + \expandafter\makecar\csname impact@"\letter@name"\endcsname\letter@code% + }% +\saved@crcatcode% redonne le catcode de ^^M +% % définit l'espace +\pixelsize=3pt \pixelsep=1pt +% puis, on affiche ce qui a été défini : +a = \csname impact@"a"\endcsname\qquad b = \csname impact@"b"\endcsname\qquad +9 = \csname impact@"9"\endcsname \qquad 0 = \csname impact@"0"\endcsname\qquad +error = \csname impact@"error"\endcsname +****************** Fin code ****************** + + +****************** Code 379 ****************** +\catcode`\@11 +\newskip\letter@skip% ressort mis entre chaque lettre +\def\impactend{\impactend}% définit le quark de fin + +\newmacro\impact[0.2ex][0pt]{% définit la macro à arguments optionnels + \leavevmode% passer en mode horizontal + \begingroup% dans un groupe semi-simple : + \pixelsize=#1\relax \pixelsep=#2\relax% définir ces deux dimensions + \letter@skip=#1 plus.1\pixelsize minus.1\pixelsize\relax% définir espace inter-lettre + \baselineskip=% définir la distance entre les lignes de base + \dimexpr12\pixelsize+7\pixelsep\relax% à 12\pixelsize+7\pixelsep + \lineskiplimit=0pt % si lignes trop serrées + \lineskip=2\pixelsize\relax% les espacer de 2\pixelsize + \impact@i% puis aller voir le prochain token +} + +% va voir le prochain token puis va le tester à \impact@ii +\def\impact@i{\futurelet\nxtletter\impact@ii} + +\def\impact@ii{% + \ifx\nxtletter\impactend% si le token est \let égal à \impactend + \let\donext\impact@endprocess% aller à al macro de fin + \else + \ifx\nxtletter\sptoken% si c'est un espace + \let\donext\impact@spc% aller à \impact@spc + \else + \let\donext\impact@arg% sinon, aller à \impact@arg + \fi + \fi + \donext% faire l'action décidée ci-dessus +} + +% mange un espace (argument délimité) et affiche "\letter@<spc>" +\expandafter\def\expandafter\impact@spc\space{% + \csname impact@" "\endcsname + \impact@i% puis va voir le prochain token +} +% +% lit l'argument suivant +\def\impact@arg#1{% + \csname impact@% affiche + \ifcsname impact@"#1"\endcsname + "#1"% le caractère \impact@"#1" s'il est défini + \else + "error"% sinon \impact@"error" + \fi + \endcsname + \hskip\letter@skip% insérer le ressort inter-lettre + \impact@i% puis, aller voir le prochain token +} +\def\impact@endprocess\impactend{% macro exécuté lorsqque le quark \impactend va être lu + \unskip% annuler le dernier ressort + \par% composer le paragraphe pour prendre en compte + % \baselineskip, \lineskip et \lineskiplimit + \endgroup% et fermer le groupe +} +\catcode`\!=12 % rend le point d'exclamation "gentil" +\impact Programmer en {TEX} est facile et tr{e`}s utile !\impactend\par +\impact[2pt][0.5pt]Programmer en {TEX} est facile et tr{e`}s utile !\impactend +****************** Fin code ****************** + + +****************** Code 380 ****************** +\newdimen\maingraddim \maingraddim=4pt % hauteur des graduations principales +\newdimen\maingradwd \maingradwd=0.5pt % épaisseur des graduations principales +\def\maingradx#1{% + \lower1.5ex\clap{$\scriptscriptstyle#1$}% afficher l'argument au dessous + \clap{\vrule height\maingraddim width\maingradwd depth0pt }% et la réglure +} +Début\maingradx{1}suite\maingradx{2}conclusion\maingradx{3}fin. +****************** Fin code ****************** + + +****************** Code 381 ****************** +\maingraddim=4pt \maingradwd=0.5pt +\newdimen\axiswd \axiswd=0.5pt +\newmacro\xaxis[1cm]1[1]1[4]{%% #1= dist #2=xmin #3=inc #4=xmax #5=subdiv + \hbox{% mettre le tout dans une \hbox + \rlap{% en débordement à droite : + \FOR\xx = #2 to #4 \do #3{% pour chaque graduation principale + \maingradx{\xx}% tracer la graduation et écrire l'abscisse + \kern#1\relax% puis se déplacer vers la droite + }% + }% + \vrule% tracer l'axe des abscisses + height\axiswd% d'epaisseur \axiswd, de longueur #1*(#4-#2)/#3 + width\dimexpr#1*\decdiv{\dimtodec\dimexpr#4pt-#2pt\relax}{#3}\relax + depth 0pt\relax % et de profondeur nulle + }% +} +a) \xaxis{-2}{5}suite + +b) \frboxsep=0pt\frbox{\xaxis[1.25cm]{-1}[0.25]{1}}suite +****************** Fin code ****************** + + +****************** Code 382 ****************** +\maingraddim=4pt \maingradwd=0.5pt \axiswd=0.5pt +\newdimen\subgraddim \subgraddim=2.5pt +\newdimen\subgradwd \subgradwd=0.2pt +% trace un trait de subdivision +\def\subgradx{\clap{\vrule height\subgraddim width\subgradwd depth0pt }} + +\newmacro\xaxis[1cm]1[1]1[4]{% #1= dist #2=xmin #3=inc #4=xmax #5=subdiv + \hbox{% tout mettre dans une \hbox + \setbox0=\hbox{% stocke dans une \hbox les grad secondaires entre 2 unités + \edef\dimsubgrad{\the\dimexpr#1/#5\relax}% dimension entre 2 subdivisions + \for\xx=1 to #5-1 \do{% insérer #5-1 fois + \kern\dimsubgrad% une espace secondaire + \subgradx% une graduation secondaire + }% + }% + \rlap{% en débordement à droite : + \FOR\xx = #2 to #4 \do #3{% pour chaque graduation principale + \maingradx{\xx}% imprimer l'abscisse + \ifdim\xx pt<#4pt % et en débordement à droite, + \rlap{\copy0 }% les réglures secondaires, sauf pour la dernière + \fi + \kern#1\relax% se déplacer vers la droite + }% + }% + \vrule% tracer l'axe des abscisses + height\axiswd% d'epaisseur \axiswd, de longueur #1*(#4-#2)/#3 + width\dimexpr#1*\decdiv{\dimtodec\dimexpr#4pt-#2pt\relax}{#3}\relax + depth 0pt\relax % et de profondeur nulle + }% +} +a) \xaxis{-2}{5}[2] + +)b \xaxis[1.25cm]{-1}[0.25]{1}[5] +****************** Fin code ****************** + + +****************** Code 383 ****************** +\maingraddim=4pt \maingradwd=0.5pt \axiswd=0.5pt +\subgraddim=2.5pt \subgradwd=0.2pt +\def\maingrady#1{% affiche... + \vlap{\llap{$\scriptscriptstyle#1$\kern2pt }}% l'ordonnée... + \vbox to0pt{\vss\hrule height\maingradwd width\maingraddim depth0pt }% et la réglure +} + +% affiche une subdiv +\def\subgrady{\vlap{\hrule height\subgradwd width\subgraddim depth0pt }} +\newmacro\yaxis[1cm]1[1]1[4]{% +% #1= dist #2=ymin #3=inc #4=ymax #5=subdiv + \vbox{% + \offinterlineskip% désactiver le ressort d'interligne + \setbox0=\vbox{% stocke dans une \hbox les grad secondaires entre 2 unités + \edef\dimsubgrad{\the\dimexpr#1/#5\relax}% dimension entre 2 subdivisions + \for\xx=1 to #5-1 \do{% insérer #5-1 fois + \kern\dimsubgrad% une espace secondaire + \subgrady% une graduation secondaire + }% + }% + \edef\dimsubgrad{\the\dimexpr#1/#5\relax}% distance entre 2 subdivisions + \vbox to 0pt{% en débordement vers le bas + \FOR\xx = #4to#2\do-#3{% + \maingrady{\xx}% imprimer l'abscisse + \ifdim\xx pt>#2pt % et en débordement à droite, + \vbox to 0pt{\copy0 \vss}% les réglures secondaires, sauf pour la dernière + \fi + \kern#1\relax% se déplacer vers la droite + }% + \vss% assure le débordement vers le bas + }% + \clap{\vrule% tracer l'axe des ordonnées + width\axiswd% d'épaisseur \axiwd, et de hauteur (#4-#2)/#3*#1 + height\decdiv{\dimtodec\dimexpr(#4pt-#2pt)\relax}{#3}\dimexpr#1\relax + depth 0pt\relax % profondeur nulle + }% + }% +} + +Essai : \yaxis{-2}{5}[2]\qquad \frboxsep=0pt \frbox{\yaxis[0.75cm]{-1}[0.5]{3}[5]} +****************** Fin code ****************** + + +****************** Code 384 ****************** +\newdimen\xunit \xunit=1cm +\newdimen\yunit \yunit=0.75cm +\maingraddim=4pt \maingradwd=0.5pt \axiswd=0.5pt +\subgraddim=2.5pt \subgradwd=0.2pt +\catcode`@11 +\newmacro\graphzone1[1]1[4]1[1]1[4]{% + \leavevmode% quitter le mode vertical + \begingroup% travailler dans un groupe semi-simple + \def\graphxmin{#1}\def\graphxmax{#3}% sauvegarder + \def\graphymin{#5}\def\graphymax{#7}% les + \def\xincrement{#2}\def\yincrement{#6}% arguments + \setbox0\hbox{\yaxis[\yunit]{#5}[#6]{#7}[#8]}% axe "y" dans boite 0 + \setbox1\hbox{\xaxis[\xunit]{#1}[#2]{#3}[#4]}% axe "x" dans boite 1 + \edef\graphboxht{\the\ht0 }% \graphboxh est la hauteur de la zone + \edef\graphboxwd{\the\wd1 }% \graphboxw est la largeur de la zone + \rlap{% annuler la dimension horizontale, et... + \box1 % ...afficher l'axe (Ox) puis + % le trait vertical à l'extrême droite de la zone + \clap{\vrule height\dimexpr\graphboxht+\axiswd\relax width\axiswd depth0pt }% + }% + \rlap{\box0 }% afficher l'axe (Oy) en annulant sa dimension horizontale + \raise\graphboxht% puis monter tout en haut de la zone + % pour tracer le trait horizontal en annulant sa longueur + \rlap{\kern-0.5\axiswd% et en rattrapant le centrage de l'axe des ordonnées + \vrule height\axiswd width\dimexpr\graphboxwd+\axiswd}% + \begingroup% pour lire l'argument "<code>" : + \catcode`\^^M=9\relax % ignorer les retours à la ligne + \graphzone@i% appeler \graphzone@i +} +\def\graphzone@i#1{% lire le <code>... + \endgroup% et fermer le groupe précédemment ouvert + \setbox0\hbox{#1}% mettre les instructions graphique dans la boite 0 + \wd0=\dimexpr\graphboxwd+\axiswd\relax% forcer sa dim horizontale + \ht0=\dimexpr\graphboxht+\axiswd\relax% et verticale + % pour correspondre aux dimension de la zone graphique + \box0 % l'afficher + \endgroup% sortir du groupe initial +} +\catcode`@12 +essai\graphzone{-1}[0.5]{1.5}[5]{-20}[10]{10}[2]{\relax}fin +****************** Fin code ****************** + + +****************** Code 385 ****************** +\def\putat#1#2#3{% + \leavevmode\rlap{\kern#1\vbox to0pt{\vss\hbox{#3}\kern#2}}% +} +Essai\putat{0.5cm}{0.3cm}{A}\putat{-0.2cm}{-0.1cm}{B}\putat{0pt}{0.2cm}{C}suite +****************** Fin code ****************** + + +****************** Code 386 ****************** +\def\ifinside#1[#2,#3]{% + \ifnum\sgn{\dimexpr#1pt-#2pt\relax}\sgn{\dimexpr#1pt-#3pt}1=1 + \expandafter\secondoftwo + \else + \expandafter\firstoftwo + \fi +} +1) \ifinside3.5[0.5,4]{vrai}{faux}\qquad +2) \ifinside-0.2[-0.4,-0.3]{vrai}{faux}\qquad +3) \ifinside-0.999[-1,-0.5]{vrai}{faux} +****************** Fin code ****************** + + +****************** Code 387 ****************** +\def\fonction#1{\dimtodec\dimexpr + \decmul{#1}{\decmul{#1}{#1}}pt% x^3 + -\decmul{#1}{#1}pt% -x^2 + -#1pt*3% -3x + +2pt\relax}% +2 +1) \fonction{-4}\qquad% doit afficher -66 +2) \fonction{-1.7}\qquad % doit afficher -0.703 +3) \fonction{1}\qquad% doit afficher -1 +4) \fonction{1.35}% doit afficher -1.412125 +****************** Fin code ****************** + + +****************** Code 388 ****************** +\newmacro\cross[2pt][0.2pt]{% + % #1=dimensions de traits depuis le centre de la croix + % #2=épaisseur des traits + \leavevmode + \vlap{% + \clap{% + \vrule height#2 depth0pt width#1 % 1/2 trait horizontal gauche + \vrule height#1 depth#1 width#2 % trait vertical + \vrule height#2 depth0pt width#1 % 1/2 trait horizontal droit + }% + }% +} +Une croix : \cross{}puis une autre\cross[8pt][0.8pt] +****************** Fin code ****************** + + +****************** Code 389 ****************** +\maingraddim=4pt \maingradwd=0.5pt \axiswd=0.5pt +\subgraddim=2.5pt \subgradwd=0.2pt +\xunit=1.25cm \yunit=0.75cm + +\def\maingradx#1{% + \lower1.5ex\clap{$\scriptscriptstyle#1$}% afficher l'argument au dessous + \clap{\vrule height\maingraddim width\maingradwd depth0pt }% et la réglure +} + +\def\subgradx{\clap{\vrule height\subgraddim width\subgradwd depth0pt }} + +\newmacro\xaxis[1cm]1[1]1[4]{% + \hbox{% tout mettre dans une \hbox + \setbox0=\hbox{% stocke dans une \hbox les grad secondaires entre 2 unités + \edef\dimsubgrad{\the\dimexpr#1/#5\relax}% dimension entre 2 subdivisions + \for\xx=1 to #5-1 \do{% insérer #5-1 fois + \kern\dimsubgrad% une espace secondaire + \subgradx% une graduation secondaire + }% + }% + \rlap{% en débordement à droite : + \FOR\xx = #2 to #4 \do #3{% pour chaque graduation principale + \maingradx{\xx}% imprimer l'abscisse + \ifdim\xx pt<#4pt % et en débordement à droite, + \rlap{\copy0 }% les réglures secondaires, sauf pour la dernière + \fi + \kern#1\relax% se déplacer vers la droite + }% + }% + \vrule% tracer l'axe des abscisses + height\axiswd% d'epaisseur \axiswd, de longueur #1*(#4-#2)/#3 + width\dimexpr#1*\decdiv{\dimtodec\dimexpr#4pt-#2pt\relax}{#3}\relax + depth 0pt\relax % et de profondeur nulle + }% +} + +\def\maingrady#1{% affiche... + \vlap{\llap{$\scriptscriptstyle#1$\kern2pt }}% l'ordonnée... + \vbox to0pt{\vss\hrule height\maingradwd width\maingraddim depth0pt }% et la réglure +} + +% affiche une subdiv +\def\subgrady{\vlap{\hrule height\subgradwd width\subgraddim depth0pt }} +% #1= dim entre 2 grad principales #2=abscisse départ #3=incrément +% #4=abscisse arrivée #5=nb intervalles secondaires +\newmacro\yaxis[1cm]1[1]1[4]{% + \vbox{% + \offinterlineskip% désactiver le ressort d'interligne + \setbox0=\vbox{% stocke dans une \hbox les grad secondaires entre 2 unités + \edef\dimsubgrad{\the\dimexpr#1/#5\relax}% dimension entre 2 subdivisions + \for\xx=1 to #5-1 \do{% insérer #5-1 fois + \kern\dimsubgrad% une espace secondaire + \subgrady% une graduation secondaire + }% + }% + \edef\dimsubgrad{\the\dimexpr#1/#5\relax}% distance entre 2 subdivisions + \vbox to 0pt{% en débordement vers le bas + \FOR\xx = #4to#2\do-#3{% + \maingrady{\xx}% imprimer l'abscisse + \ifdim\xx pt>#2pt % et en débordement à droite, + \vbox to 0pt{\copy0 \vss}% les réglures secondaires, sauf pour la dernière + \fi + \kern#1\relax% se déplacer vers la droite + }% + \vss% assure le débordement vers le bas + }% + \clap{\vrule% tracer l'axe des ordonnées + width\axiswd% d'épaisseur \axiwd, et de hauteur (#4-#2)/#3*#1 + height\decdiv{\dimtodec\dimexpr(#4pt-#2pt)\relax}{#3}\dimexpr#1\relax + depth 0pt\relax % profondeur nulle + }% + }% +} + +\catcode`@11 +\newmacro\graphzone1[1]1[4]1[1]1[4]{% + \leavevmode% quitter le mode vertical + \begingroup% travailler dans un groupe semi-simple + \def\graphxmin{#1}\def\graphxmax{#3}% sauvegarder + \def\graphymin{#5}\def\graphymax{#7}% les + \def\xincrement{#2}\def\yincrement{#6}% arguments + \setbox0\hbox{\yaxis[\yunit]{#5}[#6]{#7}[#8]}% axe "y" dans boite 0 + \setbox1\hbox{\xaxis[\xunit]{#1}[#2]{#3}[#4]}% axe "x" dans boite 1 + \edef\graphboxht{\the\ht0 }% \graphboxh est la hauteur de la zone + \edef\graphboxwd{\the\wd1 }% \graphboxw est la largeur de la zone + \rlap{% annuler la dimension horizontale, et... + \box1 % ...afficher l'axe (Ox) puis + % le trait vertical à l'extrême droite de la zone + \clap{\vrule height\dimexpr\graphboxht+\axiswd\relax width\axiswd depth0pt }% + }% + \rlap{\box0 }% afficher l'axe (Oy) en annulant sa dimension horizontale + \raise\graphboxht% puis monter tout en haut de la zone + % pour tracer le trait horizontal en annulant sa longueur + \rlap{\kern-0.5\axiswd% et en rattrapant le centrage de l'axe des ordonnées + \vrule height\axiswd width\dimexpr\graphboxwd+\axiswd}% + \begingroup% pour lire l'argument "<code>" : + \catcode`\^^M=9\relax % ignorer les retours à la ligne + \graphzone@i% appeler \graphzone@i +} +\def\graphzone@i#1{% lire le <code>... + \endgroup% et fermer le groupe précédemment ouvert + \xunit=\decdiv1\xincrement\xunit% divise les unités par l'incrément + \yunit=\decdiv1\yincrement\yunit + \setbox0\hbox{#1}% mettre les instructions graphique dans la boite 0 + \wd0=\dimexpr\graphboxwd+\axiswd\relax% forcer sa dim horizontale + \ht0=\dimexpr\graphboxht+\axiswd\relax% et verticale + % pour correspondre aux dimension de la zone graphique + \box0 % l'afficher + \endgroup% sortir du groupe initial +} + +\def\putat#1#2#3{% + \leavevmode\rlap{\kern#1\vbox to0pt{\vss\hbox{#3}\kern#2}}% +} + +\newmacro\cross[2pt][0.2pt]{% + \leavevmode + \vlap{% + \clap{% + \vrule height#2 depth0pt width#1 % 1/2 terait horizontal gauche + \vrule height#1 depth#1 width#2 % trait vertical + \vrule height#2 depth0pt width#1 % 1/2 trait horizontal droit + }% + }% +} + +\def\plot(#1,#2){% place "\plotstuff" aux coordonnées #1,#2 + \edef\x@plot{#1}\edef\y@plot{#2}% développer au cas où + \ifinside\x@plot[\graphxmin,\graphxmax]% si #1 est dans les limites + {\ifinside\y@plot[\graphymin,\graphymax]% et si #2 l'est aussi + {\putat% placer aux coordonnées + {\dimexpr\x@plot\xunit-\graphxmin\xunit\relax}% X=(x-xmin)/xinc + {\dimexpr\y@plot\yunit-\graphymin\yunit\relax}% Y=(y-ymin)/yinc + \plotstuff% le contenu de \plotstuff + }% + \relax + } + \relax +} + +\def\showxaxis{% affiche l'axe (Ox) + \ifinside0[\graphymin,\graphymax]% + {\putat\z@{-\graphymin\yunit}{\vlap{\vrule width\graphboxwd height\axiswd}}}% + \relax +} + +\def\showyaxis{% affiche l'axe (Oy) + \ifinside0[\graphxmin,\graphxmax]% + {\putat{-\graphxmin\xunit}\z@{\clap{\vrule width\axiswd height\graphboxht}}}% + \relax +} + +\def\showaxis{\showxaxis\showyaxis}% affiche les deux axes +\catcode`@12 + +%%%%%%%%%%%%%%% 1er exemple : +\xunit=1cm \yunit=0.5cm +\def\fonction#1{\dimtodec\dimexpr\decmul{#1}{\decmul{#1}{#1}}pt-% + \decmul{#1}{#1}pt-#1pt*3+2pt\relax} +Exemple 1 :\qquad +\graphzone{-2}[0.5]{2.5}[5]{-5}{5}[2]{% + \let\plotstuff\cross% définit ce qu'il faut afficher comme point + \FOR\xx=-2 to 2.5 \do 0.1{% + \plot(\xx,\fonction{\xx})% afficher les points de coordonnées (x ; f(x)) + }% + \putat{5pt}{\dimexpr\graphboxht-10pt\relax}% afficher + {$f(x)=x^3-x^2-3x+2$}% la fonction tracée + \showaxis% et les axes +}\par\medskip +%%%%%%%%%%%%% 2e exemple +\xunit=0.7cm \yunit=\xunit +\def\foncx#1{\dimtodec\dimexpr\decmul{#1}{\decmul{#1}{#1}}pt-% + \decmul{4}{\decmul{#1}{#1}}pt-#1pt+4pt} +\def\foncy#1{\dimtodec\dimexpr\decmul{#1}{#1}pt-#1pt*2-6pt} +Exemple 2 :\qquad +\graphzone{-12}[2]{12}[2]{-8}[2]{8}[2]{% + \def\plotstuff{\cross[1.25pt]} + \FOR\tt = -5 to 5 \do 0.1 {% + \plot(\foncx\tt,\foncy\tt)% + }% + \putat{5pt}{\dimexpr\graphboxht-20pt\relax}% afficher la fonction paramétrique tracée + {$\left\{\vcenter{\hbox{$x(t)=t^3-4t^2-t-4$}\hbox{$y(t)=t^2-2t-6$}}\right.$}% + \showaxis +} +****************** Fin code ****************** + + +****************** Code 390 ****************** +\def\mandeltest#1#2{% + \def\zx{0}\def\zy{0}% zn=0 + i*0 + \def\zxx{0}\def\zyy{0}% carrés de \zx et \zy + \def\mandelresult{1}% le point appartient à M a priori + \for\ii=1to\maxiter\do1{% + \advance\count255 by1 + \edef\zy{\dimtodec\dimexpr\decmul{\decmul2\zx}\zy pt+#2pt\relax}% + \edef\zx{\dimtodec\dimexpr\zxx pt-\zyy pt+#1pt\relax}%% + \edef\zxx{\decmul\zx\zx}% + \edef\zyy{\decmul\zy\zy}% + \ifdim\dimexpr\zxx pt+\zyy pt\relax>4pt + \def\mandelresult{0}% + \exitfor\ii + \fi + }% +} +\def\mandel#1#2{% #1=points par unité #2=nombre maximal d'itérations + \graphzone{-2}[1]{1}[2]{-1}[1]{1}[2]{% + \def\maxiter{#2}% + \edef\plotstuff{\the\dimexpr\xunit/#1\relax}% taille d'un pixel + \edef\plotstuff{\vrule height\plotstuff width\plotstuff}% + \edef\increment{\decdiv{1}{#1}}% incrément + \count255=0 % compteur des itérations + \FOR\xxx = -2 to 1 \do \increment{% pour chaque + \FOR\yyy = 0 to 1 \do \increment{% pixel du domaine + \mandeltest\xxx\yyy% tester s'il est dans M + \ifnum\mandelresult=1 % si oui, + \plot(\xxx,\yyy)\plot(\xxx,-\yyy)% afficher les 2 points + \fi + }% + }% + \edef\plotstuff{$\scriptstyle\number\count255 $}% affiche la valeur du compteur + \plot(-1.99,0.92)% aux coordonnées (-1.99 ; 0.92) + }% +} +\xunit=3cm \yunit=3cm \mandel{400}{500} +****************** Fin code ****************** + + +****************** Code 391 ****************** +\catcode`\@11 +\protected\def\numsep{\kern0.2em }% \numsep est le séparateur mis tous les 3 chiffres + +\def\formatdecpart#1{% #1=série de chiffres + \ifempty{#1}% si la partie décimale est vide + {}% ne rien afficher + {{,}\formatdecpart@i 1.#1..}% sinon, afficher la virgule et mettre en forme +} + +% #1=compteur de caractères #2= chiffre courant +% #3= chiffres restants #4 = chiffres déjà traités +\def\formatdecpart@i#1.#2#3.#4.{% + \ifempty{#3}% si #2 est le dernier chiffre + {#4#2}% le mettre en dernière position et tout afficher, sinon + {\ifnum#1=3 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + % si 3 chiffres sont atteint, rendre #1 égal à 1 et + {\formatdecpart@i 1.#3.#4#2\numsep.}% mettre #2\numsep en dernier puis recommencer + % sinon, mettre #2 en dernière position et recommencer + % tout en incrémentant #1 de 1 + {\expandafter\formatdecpart@i \number\numexpr#1+1.#3.#4#2.}% + }% +} +a) \formatdecpart{1234567}\qquad +b) \formatdecpart{987125}\qquad +c) \formatdecpart{56}\qquad +d) \edef\foo{\formatdecpart{2014}}\meaning\foo +****************** Fin code ****************** + + +****************** Code 392 ****************** +\catcode`\@11 +\protected\def\numsep{\kern0.2em }% \numsep est le séparateur mis tous les 3 chiffres +\def\formatintpart#1{% #1=série de chiffres + \formatintpart@i 1.#1..% appelle la macro récursive +} + +% #1=compteur de caractères #2= chiffre courant +% #3= chiffres restants #4 = chiffres déjà traités +\def\formatintpart@i#1.#2#3.#4.{% + \ifempty{#3}% si #2 est le dernier chiffre + {#2#4}% le mettre en première position et tout afficher, sinon + {\ifnum#1=3 \expandafter\firstoftwo\else\expandafter\secondoftwo + \fi% si 3 chiffres sont atteint, rendre #1 égal à 1 et + {\formatintpart@i 1.#3.\numsep#2#4.}% mettre "\numsep#2" en premier et recommencer + % sinon, mettre #2 en première position et recommencer + % tout en incrémentant #1 de 1 + {\expandafter\formatintpart@i \number\numexpr#1+1.#3.#2#4.}% + }% +} +\catcode`\@12 +a) \formatintpart{1234567}\qquad b) \formatintpart{987125}\qquad +c) \formatintpart{56}\qquad +d) \edef\foo{\formatintpart{2014}}\meaning\foo +****************** Fin code ****************** + + +****************** Code 393 ****************** +\catcode`\@11 +\def\formatintpart#1{% #1=série de chiffres + \expandafter\formatintpart@i\expandafter1\expandafter.\romannumeral\reverse{#1\z@}..% +} + +\catcode`\@12 +a) \formatintpart{1234567}\qquad b) \formatintpart{987125}\qquad +c) \formatintpart{56}\qquad +d) \edef\foo{\formatintpart{2014}}\meaning\foo +****************** Fin code ****************** + + +****************** Code 394 ****************** +\catcode`\@11 +\def\ifnodecpart#1{\if@nodecpart#1.\@nil}% teste si #1 est un entier +\def\if@nodecpart#1.#2\@nil{\ifempty{#2}} + +\def\formatnum#1{% + \ifnodecpart{#1}% s'il n'y a pas de partie décimale + {\formatintpart{#1}}% formatter la partie entière + {\formatnum@i#1\@nil}% sinon, formatter les deux parties +} + +\def\formatnum@i#1.#2\@nil{% + \formatintpart{#1}% formatte la partie entière + \formatdecpart{#2}% et la partie décimale +} + +\catcode`\@12 +a) \formatnum{3.1415926}\qquad +b) \formatnum{1987654.12301}\qquad +c) \edef\foo{\formatnum{0987654.12300}}$\foo$ +****************** Fin code ****************** + + +****************** Code 395 ****************** +\catcode`\@11 +\def\removefirstzeros#1{% + \removefirstzeros@i#1\quark% ajoute "\quark" en dernier +} +\def\removefirstzeros@i#1{% #1=chiffre courant + \ifx\quark#1% fin atteinte donc nombre = 0 + \expandafter0% laisser un zéro + \else + \ifx0#1% si le chiffre lu est un 0 + \expandafter\expandafter\expandafter\removefirstzeros@i% recommencer + \else% sinon remettre le chiffre #1 et tout afficher jusqu'à \removefirstzeros@i + \expandafter\expandafter\expandafter\removefirstzeros@ii + \expandafter\expandafter\expandafter#1% + \fi + \fi +} +\def\removefirstzeros@ii#1\quark{#1} +\catcode`\@12 +a) \removefirstzeros{000325478}\qquad +b) \removefirstzeros{00000}\qquad +c) \edef\foo{\removefirstzeros{001000}}\meaning\foo\qquad +d) \long\def\>#1<{\detokenize{#1}} + \expandafter\>\romannumeral\removefirstzeros{0123}< +****************** Fin code ****************** + + +****************** Code 396 ****************** +\long\def\>#1<{\detokenize{#1}} +\expandafter\>\romannumeral-`\@\removefirstzeros{000123}< +****************** Fin code ****************** + + +****************** Code 397 ****************** +\catcode`\@11 +\def\removelastzeros#1{% + \exparg\reverse% inverser après + {\romannumeral-`\.% tout développer + \expandafter\removelastzeros@i% enlever les 0 de gauche après + \romannumeral\reverse{#1\z@}\quark% avoir inversé #1 + }% +} +\def\removelastzeros@i#1{% enlève tous les 0 de gauche + \unless\ifx\quark#1% si la fin n'est pas atteinte + \ifx0#1% si le chiffre lu est un 0 + \expandafter\expandafter\expandafter\removelastzeros@i% recommencer + \else% sinon remettre le chiffre et tout afficher jusqu'à \removefirstzeros@i + \expandafter\expandafter\expandafter\removelastzeros@ii + \expandafter\expandafter\expandafter#1% + \fi + \fi +} +\def\removelastzeros@ii#1\quark{#1} +\catcode`\@12 +a) \removelastzeros{0003254780}\qquad +b) \removelastzeros{00000}\qquad +c) \edef\foo{\removelastzeros{001000}}\foo\qquad +\long\def\>#1<{\detokenize{#1}} +d) \expandafter\>\romannumeral-`\.\removelastzeros{012300}< +****************** Fin code ****************** + + +****************** Code 398 ****************** +\catcode`\@11 +\protected\def\numsep{\kern0.2em }% \numsep est le séparateur mis tous les 3 chiffres + +\def\formatdecpart#1{% #1=série de chiffres + \ifempty{#1}% si la partie décimale est vide + {}% ne rien afficher + {{,}\formatdecpart@i 1.#1..}% sinon, afficher la virgule et mettre en forme +} + +% #1=compteur de caractères #2= chiffre courant +% #3= chiffres restants #4 = chiffres déjà traités +\def\formatdecpart@i#1.#2#3.#4.{% + \ifempty{#3}% si #2 est le dernier chiffre + {#4#2}% le mettre en dernière position et tout afficher, sinon + {\ifnum#1=3 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + % si 3 chiffres sont atteint, rendre #1 égal à 1 et + {\formatdecpart@i 1.#3.#4#2\numsep.}% mettre #2\numsep en dernier puis recommencer + % sinon, mettre #2 en dernière position et recommencer + % tout en incrémentant #1 de 1 + {\expandafter\formatdecpart@i \number\numexpr#1+1.#3.#4#2.}% + }% +} + +\def\formatintpart#1{% #1=série de chiffres + \expandafter\formatintpart@i\expandafter1\expandafter.% + \romannumeral\reverse{#1\z@}..% appelle la macro récursive +} + +% #1=compteur de caractères #2= chiffre à déplacer +% #3= chiffres restants #4 = chiffres déjà traités +\def\formatintpart@i#1.#2#3.#4.{% + \ifempty{#3}% si #2 est le dernier chiffre à traiter + {#2#4}% le mettre en première position et tout afficher, sinon + {\ifnum#1=3 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + % si 3 chiffres sont atteint, rendre #1 égal à 1 et + {\formatintpart@i 1.#3.\numsep#2#4.}% mettre \numsep#2 en premier puis recommencer + % sinon, mettre #2 en dernière position et recommencer + % tout en incrémentant #1 de 1 + {\expandafter\formatintpart@i\number\numexpr#1+1.#3.#2#4.}% + }% +} +\def\removefirstzeros#1{% + \removefirstzeros@i#1\quark% ajoute "\quark" en dernier +} +\def\removefirstzeros@i#1{% #1=chiffre courant + \ifx\quark#1% fin atteinte donc nombre = 0 + \expandafter0% laisser un zéro + \else + \ifx0#1% si le chiffre lu est un 0 + \expandafter\expandafter\expandafter\removefirstzeros@i% recommencer + \else% sinon remettre le chiffre #1 et tout afficher jusqu'à \removefirstzeros@i + \expandafter\expandafter\expandafter\removefirstzeros@ii + \expandafter\expandafter\expandafter#1% + \fi + \fi +} +\def\removefirstzeros@ii#1\quark{#1} + +\def\removelastzeros#1{% + \exparg\reverse% inverser après + {\romannumeral-`\.% tout développer + \expandafter\removelastzeros@i% enlever les 0 de gauche après + \romannumeral\reverse{#1\z@}\quark% avoir inversé #1 + }% +} +\def\removelastzeros@i#1{% enlève tous les 0 de gauche + \unless\ifx\quark#1% si la fin n'est pas atteinte + \ifx0#1% si le chiffre lu est un 0 + \expandafter\expandafter\expandafter\removelastzeros@i% recommencer + \else% sinon remettre le chiffre et tout afficher jusqu'à \removefirstzeros@i + \expandafter\expandafter\expandafter\removelastzeros@ii + \expandafter\expandafter\expandafter#1% + \fi + \fi +} +\def\removelastzeros@ii#1\quark{#1} + +% renvoie vrai s'il n'y a pas de partie décimale +\def\if@nodecpart#1.#2\@nil{\ifempty{#2}} + +\def\formatnum#1{\formatnum@i1!#1!} + +% #1 = <série de signes> suivie de "1" +% #2 = caractère courant +% #3 = caractères non traités +\def\formatnum@i#1!#2#3!{% + \ifx+#2\expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {\ifempty{#3}% si #2=+ et #3 est vide + {\number#1 }% afficher "+1" ou "-1" (il n'y avait que des signes) + {\formatnum@i#2#1!#3!}% sinon, mettre le signe #2 devant #1 + } + {\ifx-#2\expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {\ifempty{#3}% si #2=- et #3 est vide + {\number#1 }% afficher "+1" ou "-1" (il n'y avait que des signes) + {\formatnum@i#2#1!#3!}% sinon, mettre le signe #2 devant #1 + }% #2 est le dernier caractère qui n'est pas un signe + ou - + {\ifnum#1<0 -\fi% si "<signes>1" est <0 afficher un "-" + \formatnum@ii{#2#3}% formatter le nombre formé avec "#2#3"" + }% + }% +} + +\def\formatnum@ii#1{% + \if@comma{#1}% si #1 comporte une virgule + {\formatnum@iii#1\@nil}% la remplacer par un "." et recommencer + {\if@nodecpart#1.\@nil% puis si les chiffres restants sont un entier + {\formatintpart{#1}}% formatter l'entier + {\formatnum@iv#1\@nil}% sinon, formatter le nombre + }% +} + +\def\formatnum@iii#1,#2\@nil{\formatnum@ii{#1.#2}} + +\def\formatnum@iv#1.#2\@nil{% formatte le nombre décimal #1.#2 + \exparg\formatintpart{\romannumeral-`\.\removefirstzeros{#1}}% + \exparg\formatdecpart{\romannumeral-`\.\removelastzeros{#2}}% +} + +\def\if@comma#1{\if@comma@i#1,\@nil}% teste la présence d'un virgule dans #1 +\def\if@comma@i#1,#2\@nil{\ifempty{#2}\secondoftwo\firstoftwo} +\catcode`\@12 + +a) \formatnum{3,141592653589793238462643383279502884197169399375105820974944592}\par +b) \formatnum{---+69874}\qquad +c) \formatnum{0032100,98000}\qquad +d) \formatnum{+++010.01100}\qquad +e) \formatnum{-+--+}\qquad +f) \formatnum{---00.0000}\qquad +g) \formatnum{+99,0000}\qquad +h) \formatnum{.123456}\par +i) \edef\foo{\formatnum{-+-+-010500,090900}}\meaning\foo +****************** Fin code ****************** + + +****************** Code 399 ****************** +\setbox0=\vbox{% + \hbox{Première ligne} + \hbox{Deuxième ligne} + \hbox{Avant-dernière ligne} + \hbox{Dernière ligne} +} + +\frboxsep=0pt % aucun espace entre le contenu et l'encadrement +Boite initiale de hauteur \the\ht0 {} : \frbox{\copy0 } +\splittopskip0pt % ne rajouter aucun espace au sommet de la boite restante +\setbox1=\vsplit0 to 22pt % couper la boite à 22pt de hauteur + +Boite 1 de hauteur \the\ht1 {} : \frbox{\box1 } + +Boite 0 de hauteur \the\ht0 {} : \frbox{\box0 } +****************** Fin code ****************** + + +****************** Code 400 ****************** +\setbox0=\vbox{% + \hbox{Première ligne} + \hbox{Deuxième ligne} + \hbox{Avant-dernière ligne} + \hbox{Dernière ligne} +} + +\edef\restorevbadness{\vbadness=\the\vbadness\relax}% restaurera le \vbadness +\vbadness=10000 % plus d'avertissement pour boite verticale +\frboxsep=0pt % aucun espace entre le contenu et l'encadrement +Boite initiale de hauteur \the\ht0 {} : \frbox{\copy0 } +\splittopskip0pt % ne rajouter aucun espace au sommet de la boite restante +\setbox1=\vsplit0 to 22pt % couper la boite à 22pt de hauteur +\setbox1=\vbox{\unvbox1 }% la boite 1 prend la hauteur naturelle +\restorevbadness\relax% restaure le \vbadness + +Boite 1 de hauteur \the\ht1 {} : \frbox{\box1 } + +Boite 0 de hauteur \the\ht0 {} : \frbox{\box0 } +****************** Fin code ****************** + + +****************** Code 401 ****************** +\catcode`@11 +\newbox\remainbox +\newbox\partialbox +\newdimen\cut@ht + +\def\breakpar{% + \par\nointerlineskip% termine le paragraphe précédent + \vskip\frboxsep\relax% et saute une petite espace verticale + \begingroup + \splittopskip\topskip% \topskip en haut des boites coupées + \topskip=0pt % neutraliser le \topskip + % nbre de réglures horizontales contribuant à l'encadrement restant (2 au début) + \def\coeff@rule{2}% + \setbox\remainbox=\vbox\bgroup% compose la boite après avoir... + \advance\hsize by -2\dimexpr\frboxrule+\frboxsep\relax% ajusté sa largeur +} + +\def\endbreakpar{% + \egroup% fin de la composition de la boite + \def\rule@arg{ULR}% prendre l\cut@htes réglures d'encadrement haute, gauche et droite + \splitbox% puis, aller à l'algorithme de coupure + \endgroup% une fois fini, sortir du groupe semi-simple +} + +\def\splitbox{% + \ifvoid\remainbox% si la boite est vide, c'est la fin du processus + \par\nointerlineskip% termine le paragraphe précédent + \vskip\frboxsep\relax% et saute un petit espace vertical + \else% sinon + \expandafter\splitbox@i% aller à \splitbox@i + \fi +} + +\def\splitbox@i{% + \hbox{}% composer un noeud en mode vertical + \nointerlineskip% pas de ressort d'interligne + % calculer la dimension verticale disponible dans la page pour le texte de la boite + \cut@ht=\dimexpr\pagegoal-\pagetotal-(\frboxsep+\frboxrule)*\coeff@rule\relax + % si dimension totale du texte > dimension disponible pour le texte + \ifdim\dimexpr\ht\remainbox+\dp\remainbox>\cut@ht% si une coupure doit être faite + \advance\cut@ht\dimexpr% augmenter Dv de l'espace verticale libérée + +\frboxsep+\frboxrule% par la réglure inférieure qui n'est pas sur cette page + \relax + \edef\old@vbadness{\the\vbadness}% sauvegarder \badness + \vbadness=10000 % désactive les avertissement lors de la coupure + \def\coeff@rule{1}% ne prendre en compte que réglure D + espace D + \setbox\partialbox=\vsplit\remainbox to\cut@ht% coupe à la hauteur calculée + % \partialbox retrouve sa hauteur naturelle + \setbox\partialbox=\vbox{\unvbox\partialbox}% + \vbadness=\old@vbadness\relax% restaure \vbadness + \printpartialbox% imprime la boite partielle + \vfill\eject% et compose la page en cours + \else% si une coupure n'est pas nécessaire : + \setbox\remainbox\vbox{\unvbox\remainbox}% reprendre la hauteur naturelle + \setbox\partialbox=\box\remainbox% \partialbox devient \remainbox + % et cette dernière devient vide + \cut@ht=\dimexpr\ht\partialbox+\dp\partialbox\relax% hauteur à encadrer + \edef\rule@arg{\rule@arg D}% ajouter "D" aux réglures à tracer + \printpartialbox% afficher la boite restante + \fi + \splitbox +} + +\def\printpartialbox{% imprime \partialbox + \expandafter\framebox\expandafter[\rule@arg]{% + \vbox to\cut@ht{\unvbox\partialbox\vss}}% + \def\rule@arg{LR}% ne mettre que les réglures d et g +} + +\def\dummytext#1{% + \for\xx=1to#1\do% composer #1 fois la phrase suivante : + {Ceci est un texte sans aucun int\'er\^et dont le seul but est de meubler + la page artificiellement. + }% +} + +\catcode`@12 +\dummytext{5} +\frboxsep=5pt + +\breakpar + \dummytext{70} +\endbreakpar + +\dummytext{5} +****************** Fin code ****************** + + +****************** Code 402 ****************** +\setbox0=\vbox{% + \hsize=5cm + Ceci est un texte sans aucun intérêt dont le seul but est de meubler + la page de façon artificielle. +} + +Boite 0 : \copy0 % affiche la boite totale +\medbreak + +\edef\restorevfuzz{\vfuzz=\the\vfuzz\relax}% appelée après la coupure +\vfuzz=\maxdimen% annule les avertissements pour débordement +\splittopskip=0pt % ne rajouter aucun espace au sommet de la boite restante +\setbox1=\vsplit0 to 0pt % couper la boite à 0pt de hauteur +\restorevfuzz% restaurer \vfuzz +\setbox1=\vbox{\unvbox1}% redonner à la boite sa hauteur d'origine + +Boites 1+0 : \vbox{% + \offinterlineskip% annule le ressort d'interligne + \box1 % affiche la première ligne + \box0 %affiche les lignes restantes +} +****************** Fin code ****************** + + +****************** Code 403 ****************** +\def\vdim#1{\dimexpr\ht#1+\dp#1\relax}% hauteur totale de la boite #1 +\setbox0=\vbox{% + \hsize=5cm Ceci est un texte sans aucun intérêt dont le seul but est + de meubler la page de façon artificielle. +} +\edef\htbefore{\the\vdim0}% hauteur de la boite 0 + +Boite 0 : \copy0 % affiche la boite totale +\medbreak + +\edef\restoreparam{% + \vfuzz=\the\vfuzz\relax% sauvegarde le \vfuzz + \splittopskip=\the\splittopskip% et \splittopskip +}% +\vfuzz=\maxdimen% annule les avertissements pour débordement +\splittopskip=0pt % ne rajouter aucun espace au sommet de la boite restante +\setbox1=\vsplit0 to 0pt % couper la boite à 0pt de hauteur +\restoreparam +\setbox1=\vbox{\unvbox1}% redonner à la boite sa hauteur d'origine + +\edef\intersplitspace{\the\dimexpr\htbefore-(\vdim0+\vdim1)\relax}% +Boites 1+0 : \vbox{% + \offinterlineskip% annule le ressort d'interligne + \box1 % affiche la première ligne + \vskip\intersplitspace\relax% ajoute le ressort perdu à la coupure + \box0 % affiche les lignes restantes +} +****************** Fin code ****************** + + +****************** Code 404 ****************** +\setbox0=\vbox{% + \hsize=5cm Ceci est un texte sans aucun intérêt dont le seul but est + de meubler la page de façon artificielle. +} + +Boite 0 : \copy0 % affiche la boite totale +\medbreak + +\edef\restoreparam{% + \vfuzz=\the\vfuzz\relax% sauvegarde le \vfuzz + \splittopskip=\the\splittopskip\relax% , le \splittopskip + \savingvdiscards=\the\savingvdiscards\relax% et le \savingvdiscards + }% +\vfuzz=\maxdimen% annule les avertissements pour débordement +\splittopskip=0pt % ne rajouter aucun espace au sommet de la boite restante +\savingvdiscards=1 % autorise la sauvagarde des éléments supprimés +\setbox1=\vsplit0 to 0pt % couper la boite à 0pt de hauteur +\setbox1=\vbox{\unvbox1}% redonner à la boite sa hauteur d'origine +\restoreparam + +Boites 1+0 : \vbox{% + \offinterlineskip% annule le ressort d'interligne + \box1 % affiche la première ligne + \splitdiscards% affiche les éléments ignorés + \box0 % affiche les lignes restantes +} +****************** Fin code ****************** + + +****************** Code 405 ****************** +\catcode`@11 +\newbox\remainbox% boite contenant le texte total +\newbox\currentline% boite contenant le ligne en cours +\newcount\linecnt% compteur pour numéroter les lignes + +\def\vdim#1{\dimexpr\ht#1+\dp#1\relax}% hauteur totale de la boite #1 + +\newmacro\leftline[0pt]{% définit ce qui se trouve à gauche de chaque ligne + \def\wd@left{#1}% + \def\stuff@left +} + +\newmacro\rightline[0pt]{% définit ce qui se trouve à droite de chaque ligne + \def\wd@right{#1}% + \def\stuff@right +} + +\let\formatline=\identity% par défaut, afficher chaque ligne telle quelle + +% Par défaut : +\leftline[11pt]{$\scriptscriptstyle\number\linecnt$\kern3pt }% numérotation à gauche +\rightline{}% rien à droite + +\def\numlines{% + \par\smallskip + \begingroup% dans un groupe semi-simple + \splittopskip=0pt % ne rajouter aucun espace au sommet de la boite restante + \linecnt=0 % initialiser le compteur de lignes + \savingvdiscards=1 % autorise la sauvagarde des éléments supprimés + \setbox\remainbox=\vbox\bgroup% compose la boite... + \advance\hsize by% diminuer la \hsize + -\dimexpr\wd@left+\wd@right\relax% de la largeur des contenus +} + +\def\endnumlines{% + \egroup + \offinterlineskip + \split@line +} + +\def\split@line{% + \ifvoid\remainbox% si la boite est vide + \par% fin du processus + \endgroup% fermer le groupe ouvert au début + \else% sinon + \advance\linecnt 1 % incrémente le compteur de lignes + \edef\htbefore{\the\vdim\remainbox}% + \edef\restorevfuzz{\vfuzz=\the\vfuzz\relax}% sauvegarde le \vfuzz + \vfuzz=\maxdimen% annule les avertissements pour débordement + \setbox\currentline=\vsplit\remainbox to 0pt % couper la boite à 0pt de hauteur + \restorevfuzz + \setbox\currentline=\vbox{\unvbox\currentline}% redonner à la boite sa hauteur + \edef\intersplitspace{% calcul de l'espace vertical perdu à la coupure + \the\dimexpr\htbefore-(\vdim\remainbox+\vdim\currentline)\relax + }% + \hbox{% en mode vertical et dans une hbox, afficher : + \hbox to\wd@left{\hss\stuff@left}% 1) ce qui est à gauche + \formatline{\box\currentline}% 2) la ligne courante + \hbox to\wd@right{\stuff@right\hss}% 3) ce qui est à droite + }% + \splitdiscards% affiche ce qui a été ignoré à la coupure + \expandafter\split@line% recommencer + \fi +} + +\def\dummytext#1{% + \for\xx=1to#1\do% composer #1 fois la phrase suivante : + {Ceci est un texte sans aucun intérêt dont le seul but est de meubler + la page de façon artificielle. }% +} + +\catcode`@12 +\parindent=2em + +ESSAI 1 : +\numlines + \dummytext{2}\par% 2 phrases + $$1+1=2$$\par% des maths + \dummytext{1}\par% une phrase + \hrulefill\par% un leaders + \dummytext{2}% 2 phrases + \hrule height2pt depth 2pt %une \hrule + \vskip10pt % saute 10pt verticalement + \dummytext{1}% une phrase +\endnumlines\medbreak + +ESSAI 2 : +\leftline{}\rightline{}% rien à gauche et rien à droite +\frboxsep=-\frboxrule% encadrer vers "l'intérieur" +\let\formatline\frbox% lignes encadrées +\numlines + \dummytext{4} +\endnumlines\medbreak + +ESSAI 3 : +\let\formatline\identity +\leftline[7pt]{% + \for\xx= 1 to 2 \do{% insérer 2 fois + \setbox0=\hbox{% % mettre dans une \hbox une \vrule de "bonnes dimensions" + \vrule height\ht\currentline depth\dimexpr\dp\currentline+\intersplitspace + width0.5pt }% + \dp0=\dp\currentline% réajuster la profondeur (c-à-d enlever \intersplitspace) + \box0 % afficher le boite + \kern2pt % et insérer un espace horizontal de 2pt après chaque réglure verticale + }% + \kern2pt % ajouter 2pt de plus entre les lignes et le texte +} + +\rightline[10pt]{\kern5pt $\scriptscriptstyle\number\linecnt$}% numéroter à droite + +\numlines + \dummytext{2} + + $$a^2+b^2=c^2$$ + + \dummytext{2} +\endnumlines +****************** Fin code ****************** + + +****************** Code 406 ****************** +% définition des ressorts "inter-lettre" et "inter-mot" +\newskip\interletterskip \interletterskip=0.25em plus0.05em minus0.05em +\newskip\interwordskip \interwordskip=3\interletterskip\catcode`\@11 +\catcode`@11 +\def\spreadtxt@testtoken#1{% macro qui teste le token + \ifcat\noexpand#1\sptoken% si le token est un espace + \parseadd{% + \unskip% retirer le précédent ressort + \hskip\interwordskip}% et ajouter le ressort inter-mot + \else + \ifcat\noexpand#1a% si le token est une lettre + \parseadd{#1\hskip\interletterskip}% ajouter le ressort inter-lettre + \else + \ifcat\noexpand#1.% si le token est "autre", comme le "." + \parseadd{#1\hskip\interletterskip}% ajouter le ressort inter-lettre + \else% sinon + \parseadd{#1}% ajouter le token lu + \fi + \fi + \fi + \parse@i +} +\def\spreadtxt{% + \ifstarred% si étoilée + {\spreadtxt@i{\parse*}}% appeler \parse* + {\spreadtxt@i{\parse}}% sinon, appeler \parse +} +\def\spreadtxt@i#1#2{% #1= appel "\parse*" ou "\parse" #2 = texte à espacer + \begingroup% dans un groupe + \let\testtoken=\spreadtxt@testtoken% modifier \testtoken + #1#2\parsestop% et appeler \parse + \endgroup +} +\catcode`@12 + +\spreadtxt{Comme on le voit sur cet exemple, une espace est insérée après +{\it chaque} caractère de catcode 10, 11 ou 12.} +\medbreak + +\spreadtxt*{Comme on le voit sur cet exemple, une espace est insérée après +{\it chaque} caractère de catcode 10, 11 ou 12.} +****************** Fin code ****************** + + +****************** Code 407 ****************** +\newskip\interletterskip +\newskip\interwordskip +\catcode`\@11 +\newtoks\spacetxt@toks% le registre qui contient le texte final + +\def\spacetxt{% + \let\spacetxt@endprocess\spacetxt@endnormal + % définit la macro appelée en fin de processus -> a priori : fin normale + \ifstarred% si la macro est étoilée + {\let\spacetxt@recurse\spacetxt@star% définir la macro récursive + \spacetxt@i% et aller à \spacetxt@i + }% sinon + {\let\spacetxt@recurse\spacetxt@nostar% définir la macro récursive + \spacetxt@i% et aller à \spacetxt@i + }% +} + +\newmacro\spacetxt@i[0.3em plus0.07em minus.07em][3\interletterskip]1{% +% arg optionnel #1 et #2 = ressorts inter-lettre et inter--mot +% #3 = texte à espacer + \interletterskip=#1\relax + \interwordskip=#2\relax + \def\spacetxt@code{#3}% met le texte à espacer dans \spacetxt@code + \spacetxt@toks{}% initialiser le registre contenant le texte final + \spacetxt@recurse% aller à la macro récursive précédemment définie +} + +\newif\if@indivifound% booléen qui sera vrai si un motif spécial est rencontré + +\def\rightofsc#1#2{% + \exparg\ifin{#1}{#2}% si #1 contient le #2 + {\def\right@of##1#2##2\@nil{\def#1{##2}}% + \expandafter\right@of#1\@nil% appelle la macro auxiliaire + }% + {\let#1=\empty}% sinon, #1 est vide +} + +\def\spacetxt@nostar{% + \exparg\ifempty{\spacetxt@code}% si texte restant est vide + \spacetxt@endprocess% aller à la fin du processus + {\@indivifoundfalse% sinon, a priori, les motifs non réguliers ne sont pas trouvés + % pour chaque \indivi@tmp dans \indivilist + \expsecond{\doforeach\indivi@tmp\in}{\indivilist}% pour chaque motif indivisible + {% si le code commence par le motif courant + \exptwoargs\ifstartwith\spacetxt@code\indivi@tmp + {% l'ajouter dans le registre ainsi que l'espace inter-lettre + \eaddtotoks\spacetxt@toks{\indivi@tmp\hskip\interletterskip}% + % et enlever le motif du texte restant à lire + \expsecond{\rightofsc\spacetxt@code}{\indivi@tmp}% + \@indivifoundtrue% marquer qu'un motif a été trouvé + \doforeachexit% et sortir prématurément de la boucle + }% + \relax% si le code ne commence pas le motif courant -> ne rien faire + }% + \unless\if@indivifound% si aucun motif n'a été trouvé + \grab@first\spacetxt@code\spacetxt@temp% retirer le 1er caractère du texte + \ifx\spacetxt@temp\space% si le 1er caractère est un espace + \addtotoks\spacetxt@toks{% + \unskip% annuler le précédent ressort + \hskip\interwordskip}% ajouter l'espace inter-mot au registre de token + \else% si le 1er caractère n'est pas un espace + % ajouter ce caractère et l'espace inter-lettre au registre de token + \eaddtotoks\spacetxt@toks{\spacetxt@temp\hskip\interletterskip}% + \fi + \fi + \spacetxt@recurse% enfin, continuer le processus + }% +} + +\def\spacetxt@star{% + \exparg\ifempty{\spacetxt@code}% si texte restant est vide + \spacetxt@endprocess% aller à la fin du processus + {% sinon, si texte commence par "{" + \exparg\ifbracefirst{\spacetxt@code}% + {\grab@first\spacetxt@code\spacetxt@temp + % mettre {<argument} dans \spacetxt@temp + \begingroup% ouvrir un groupe + % mettre le contenu de l'argument dans \spacetxt@code + \expandafter\def\expandafter\spacetxt@code\spacetxt@temp + \let\spacetxt@endprocess\spacetxt@endingroup% changer le processus de fin + \spacetxt@toks{}% initialiser + \spacetxt@recurse% exécuter le processus avec ce nouveau texte + }% si le code ne commence pas par "{", aller à \spacetxt@nostar mais comme + \spacetxt@nostar% \spacetxt@recurse vaut \spacetxt@star, n'y faire qu'1 boucle + }% +} + +\def\spacetxt@endnormal{% fin de processus normal + \the\spacetxt@toks% afficher le registre à token + \unskip% et supprimer le dernier ressort +} + +\def\spacetxt@endingroup{% fin du processus dans un groupe : + \expandafter\endgroup\expandafter% avant de fermer le groupe + \addtotoks\expandafter\spacetxt@toks\expandafter% ajouter au registre hors du groupe + {\expandafter{\the\spacetxt@toks}}% ce qui est collecté localement mis entre {} + \spacetxt@recurse% puis aller à la macro récursive +} + +\catcode`\@12 +\def\indivilist{é,è}% liste des motifs spéciaux +\spacetxt*{Comme on le voit sur cet exemple, une espace est insérée après +{\it chaque} caractère.} +\medbreak + +\def\indivilist{é,es,au,<<,>>} +\spacetxt[4pt plus.7pt minus.7pt][12pt plus2pt minus2pt]{Ici, les motifs <<es>> et <<au>> +restent indivisibles et la ligature des guillemets devient possible en déclarant "<<" et +">>" comme motifs.} +****************** Fin code ****************** + + +****************** Code 408 ****************** +\catcode`\@11 +\def\ttcode#1{% lit #1, le <délimiteur> de début + \def\ttcode@i##1#1{% ##1 = <texte> entre délimiteurs + \tt% passe en fonte à chasse fixe + \setbox0=\hbox{ }% + \edef\spc@wd{\the\wd0 }% longueur d'un espace + \spacetxt + [.1pt plus0pt minus.1pt]% espace inter-lettre + [\glueexpr\wd0+.3pt plus.1pt minus.1pt\relax]% espace inter-mot + {##1}% le <texte> est composé par \spacetxt + \endgroup + }% + \begingroup + \def\indivilist{<<,>>,{,,},--}% (rajouter à, é, è, etc. en codage UTF8) + \def\do##1{\catcode`##1=12 }% + \dospecials% rend inoffensifs tous les tokens spéciaux + \letactive\ =\space % rend l'espace actif + \ttcode@i% va lire le <texte> et le délimiteur de fin +} +\catcode`\@12 + +\hfill\vrule\vbox{% + \hsize=.75\hsize + Avec \ttcode/\ttcode/, on peut insérer une adresse internet << + \ttcode-http://www.gutenberg.eu.org/Typographie- >> puis repasser en fonte normale + puis \ttcode+même composer un court passage en fonte à chasse fixe -- même si les + coupures de mots se font n'importe où -- et aussi afficher tous les caractères + spéciaux <<{$^ _$#}&+>>, et finir en fonte normale\ldots +}\vrule\hfill\null +****************** Fin code ****************** + + +****************** Code 409 ****************** +\def\ttwide{0.7}% coefficient pour la largeur de composition +\def\ttindent{5}% nombre de caractères d'indentation +\hfill\vrule +\vbox{% + \ttfamily% en TeX, on écrirait "\tt" + \setbox0\hbox{0}% \wd0 est donc la largeur d'un caractère + \parindent=\ttindent\wd0 % réglage de l'indentation + \hsize=\ttwide\hsize % compose sur 70% de la largeur + Dans ce paragraphe, composé en fonte à chasse fixe et où les limites gauches + et droites du texte ont été tracées, on constate que les caractères sont + exactement les uns au-dessous d'une ligne à l'autre. Des débordements dans + la marge deviennent alors inévitables, car la largeur de composition (ici + \the\hsize) n'est pas un multiple de la largeur d'un caractère (\the\wd0 ), + le quotient des deux valant environ + \xdef\ttratio{\decdiv{\dimtodec\hsize}{\dimtodec\wd0 }}\ttratio. +}% +\vrule\hfill\null +****************** Fin code ****************** + + +****************** Code 410 ****************** +Fonte normale : \fontname\font\par +{\bf Fonte grasse : \fontname\font\par} +{\it Fonte italique : \fontname\font\par} +{\sc Fonte petites majuscules : \fontname\font} +****************** Fin code ****************** + + +****************** Code 411 ****************** +\font\gras=LinLibertineTB-tlf-t1 at 8pt +\font\ital= LinLibertineTI-tlf-t1 at 8pt +\font\itgras=LinLibertineTBI-tlf-t1 at 8pt +Du texte normal {\gras puis en gras, \ital en italique, +\itgras en italique gras} et retour à la normale. +****************** Fin code ****************** + + +****************** Code 412 ****************** +Code du caractère de coupure = \number\hyphenchar\font\par +Caractère de coupure : "\char\hyphenchar\font" +****************** Fin code ****************** + + +****************** Code 413 ****************** +\def\longtext{Voici une phrase écrite avec des mots insignifiants mais terriblement, + épouvantablement, horriblement et indéniablement longs.} +% créér une macro restaurant le \hyphenchar +\edef\restorehyphenchar{\hyphenchar\font=\number\hyphenchar\font}% + +%comportement normal, caractère de coupure "-" +1) \vrule\vbox{\hsize=5cm \longtext}\vrule\hfill +% modification du caractère de coupure "W" +2) \vrule\vbox{\hsize=5cm \hyphenchar\font=`W \longtext}\vrule +\medbreak +% interdiction des coupures de mots +3) \vrule\vbox{\hsize=5cm \hyphenchar\font=-1 \longtext}\vrule +\restorehyphenchar +****************** Fin code ****************** + + +****************** Code 414 ****************** +\def\longtext{Voici une phrase écrite avec des mots insignifiants mais terriblement, + épouvantablement, horriblement et indéniablement longs.} + +\edef\restorehyphenchar{\hyphenchar\font=\number\hyphenchar\font}% +\vrule\vbox{\hsize=5cm \hyphenchar\font=-1 \sloppy \longtext}\vrule +\restorehyphenchar +****************** Fin code ****************** + + +****************** Code 415 ****************** +a) \texttt{\number\hyphenchar\font}\qquad +b) {\ttfamily\number\hyphenchar\font} +****************** Fin code ****************** + + +****************** Code 416 ****************** +\leavevmode +\vbox{% + \hsize=.4\hsize + \Souligne{Police à chasse variable}% + \vskip5pt + espace inter-mot = \the\fontdimen2\font\par + étrirement inter-mot = \the\fontdimen3\font\par + compression inter-mot = \the\fontdimen4\font +}\hfill +\vbox{% + \tt + \hsize=.4\hsize + \Souligne{Police à chasse fixe}% + \vskip5pt + espace inter-mot = \the\fontdimen2\font\par + étrirement inter-mot = \the\fontdimen3\font\par + compression inter-mot = \the\fontdimen4\font +} +****************** Fin code ****************** + + +****************** Code 417 ****************** +\def\ttwide{0.7}\def\ttindent{5}% +\hfill\vrule +\vbox{% + \ttfamily + \hyphenchar\font=`\- % change le caractère de coupure de la fonte en cours + \setbox0\hbox{0}\parindent=\ttindent\wd0 + \hsize=\ttwide\hsize % compose sur 70% de la largeur + Dans ce paragraphe, composé en fonte à chasse fixe et où les limites gauche + et droite du texte ont été tracées, on constate que les caractères sont + exactement les uns au-dessous des autres d'une ligne à l'autre. Des débordements + dans la marge deviennent inévitables même si les coupures des mots sont + à nouveau rendues possibles.% +}% +\vrule\hfill\null +****************** Fin code ****************** + + +****************** Code 418 ****************** +\frboxsep=0.5pt +\def\printallchars{% + \leavevmode + \for\xx=0 to255\do{% + \vbox{% empiler verticalement + \offinterlineskip% en désactivant le ressort d'interligne + \setbox0\hbox{\frbox{\char\xx}}% + \copy0 % la boite contenant le caractère encadré + \kern1pt% saute 1pt vertical + \hbox to\wd0{\hss$\scriptscriptstyle\xx$\hss}% le numéro + }\hskip0.5em plus1pt minus1pt % saute 0.5em horizontalement + }% +} +\tt +Nom de la fonte = \fontname\font\par +\printallchars +****************** Fin code ****************** + + +****************** Code 419 ****************** +\setbox0=\hbox{\tt\char23} +Largeur = \the\wd0 \qquad Hauteur = \the\ht0 \qquad Profondeur = \the\dp0 +****************** Fin code ****************** + + +****************** Code 420 ****************** +{\tt\xdef\nfont{\the\font}} +Largeur = \the\fontcharwd\nfont23 \qquad Hauteur = \the\fontcharht\nfont23 +\qquad Profondeur = \the\fontchardp\nfont23 +****************** Fin code ****************** + + +****************** Code 421 ****************** +\newmacro\ttstart[5]{% + \begingroup + \tt + \edef\restorefontsettings{% stocke les paramètres de fonte + \hyphenchar\font=\the\hyphenchar\font\relax% le \hyphenchar + \fontdimen2\font=\the\fontdimen2\font\relax% et les paramètres d'espacement + \fontdimen3\font=\the\fontdimen3\font\relax + \fontdimen4\font=\the\fontdimen4\font\relax + }% + \fontdimen3\font=0.30\fontdimen2\font% composante + = 30% de la dimension naturelle + \fontdimen4\font=0.20\fontdimen2\font% composante - = 20% de la dimension naturelle + \hyphenchar\font=`\- % on autorise la coupure des mots (au cas où on utilise latex) + \setbox0\hbox{0}% largeur d'un caractère + \parindent=#1\wd0 % indentation (en nombre de caractères) + \ignorespaces +} +\def\ttstop{% + \restorefontsettings% restaure les paramètres de fonte + \endgroup% et ferme le groupe +} +\hfill\vrule +\def\ttwide{0.70}% +\vbox{% + \hsize=\ttwide\hsize % compose sur 70% de la largeur + \ttstart[5] + Dans ce paragraphe, composé en fonte à chasse fixe et où les limites gauche + et droite du texte ont été tracées, on constate que les caractères ne sont pas + exactement les uns au-dessous des autres entre les lignes du paragraphe. + Puisque les espaces sont redevenus étirables, les débordements dans la marge + (même s'ils restent possibles), sont bien plus rares et ce d'autant plus que + le nombre d'espaces dans une ligne est grand.% + \ttstop +}% +\vrule\hfill\null +****************** Fin code ****************** + + +****************** Code 422 ****************** +\catcode`\@11 +\newcount\brktt@cnt +\newdimen\brktt@interletter +\newif\ifline@start% booléen vrai lorsqu'aucun caractère n'est encore affiché +\newif\if@indivifound% booléen qui sera vrai si un motif spécial est rencontré + +\def\insert@blankchar{% + \ifstarred\insert@blankchar@ii\insert@blankchar@i +} + +\def\insert@blankchar@i#1{% insère une espace de largeur #1 caractères complets + \ifnum\numexpr#1\relax>0 + \kern\numexpr#1\relax\dimexpr\ttchar@width+\brktt@interletter\relax + \fi +} + +\def\insert@blankchar@ii#1{% insère #1-1 caractères complets + 1 largeur de caractère + \ifnum\numexpr#1\relax>0 + \insert@blankchar@i{#1-1}\kern\ttchar@width + \fi +} + +\def\restart@hbox#1{% + \egroup% feerme la \hbox précédente + \hbox\bgroup% ouvre la suivante + \expsecond{\def\tt@remaintext} + {\romannumeral\removefirstspaces@i{#1}}% initialiser le code à composer + \let\previous@char\space% initialise le caractère précédent + \line@starttrue% aucun caractère n'a encore été imprimé + \brktt@cnt=0\relax% remettre le compteur à 0 +} + +\newmacro\breaktt[0.3em][\hsize]1{% +% arg optionnel #1 et #2 = ressorts inter-lettre et dimension horizontale texte +% #3 = texte à espacer + \begingroup% ouvrir un groupe et le fermer à la toute fin + \par% commencer un nouveau paragraphe -> passage en mode vertical + \parindent=0pt% empêche l'indentation + \tt% passer en fonte à chasse fixe + \setbox0 = \hbox{M}% la boite 0 contient un caractère + \edef\ttchar@width{\the\wd0 }% largeur de chaque caractère en fonte \tt + \edef\text@width{\the\dimexpr#2\relax}% largeur de composition + % les 2 lignes suivantes rendent le compteur égal à E((L-l)/(l+Delta)) + \brktt@cnt=\numexpr\dimexpr#2-\wd0 \relax\relax% largeur diminuée du 1er caractère + \divide\brktt@cnt by \numexpr\dimexpr\wd0 + #1 \relax\relax + % le nombre de caractère par ligne est égal à 1 de plus : + \edef\maxchar@num{\number\numexpr\brktt@cnt+1\relax}% + % calcul de la dimension inter-lettre + \brktt@interletter=\dimexpr(\text@width-\ttchar@width*\maxchar@num)/\brktt@cnt\relax + % stocke le texte après avoir enlevé les éventuels espaces extremes : + \expsecond{\expsecond{\def\tt@remaintext}}{\removetrailspaces{#3}}% + \unless\ifx\tt@remaintext\empty% si le texte à composer n'est pas vide + \hbox\bgroup% démarrer la boite horizontale contenant la première ligne + \insert@blankchar\ttindent% insérer une espace d'indentation + \brktt@cnt=\ttindent\relax% tenir compte du nombre de caractères indentés + \line@starttrue% il s'agit du début d'une ligne + \expandafter\breaktt@i% aller à la macro récursive + \fi +} + +\def\breaktt@i{% + \print@nchar\maxchar@num% afficher \maxchar@num caractères + \ifx\tt@remaintext\empty% si texte restant est vide + \egroup% fermer la hbox + \par% aller à la ligne + \endgroup% fermer le groupe ouvert au début + \else + \unless\ifnum\brktt@cnt<\maxchar@num\relax% si la ligne est remplie + \exparg\restart@hbox{\tt@remaintext}% ferme la hbox et en ré-ouvre une + \fi + \expandafter\breaktt@i% enfin, continuer le processus + \fi +} + +\def\print@nchar#1{% affiche #1 caractères pris dans \tt@remaintext + \for\xxx= 1 to #1 \do 1{% + \ifx\tt@remaintext\empty% si le code restant à composer est vide + \exitfor\xxx%sortir de la boucle prématurément + \else + \@indivifoundfalse% sinon, a priori, les motifs de ligature ne sont pas trouvés + % pour chaque \indivi@tmp dans la liste de ligatures + \expsecond{\doforeach\indivi@tmp\in}{\liglist}% + {% si le code commence par la ligature courante + \exptwoargs\ifstartwith\tt@remaintext\indivi@tmp + {\let\previous@char\indivi@tmp% prendre le motif pour caractère courant, + \expsecond{\rightofsc\tt@remaintext}{\indivi@tmp}% l'enlever du texte restant + \@indivifoundtrue% marquer qu'un motif a été trouvé + \doforeachexit% et sortir prématurément de la boucle + }% + {}% si le code ne commence pas le motif courant -> ne rien faire + }% + \unless\if@indivifound% si aucun motif trouvé, + \grab@first\tt@remaintext\previous@char% lire le premier caractère + \fi + \advance\brktt@cnt by 1 % incrémenter le compteur de caractères + \hbox to\ttchar@width{\hss\previous@char\hss}% afficher le caractère lu + \line@startfalse% nous ne sommes plus au début d'une ligne + \ifnum\brktt@cnt<\maxchar@num\relax% si la ligne n'est pas encore remplie + \kern\brktt@interletter% insérer le ressort inter-lettre + \else + \exitfor\xxx% sinon, sortir de la boucle prématurément + \fi + \fi + }% +} +\catcode`\@12 + +\def\liglist{<<,>>}% liste des motifs de ligature + % ajouter à, é, etc si codage UTF8 + moteur 8 bits +\def\ttindent{3}% valeur de l'indentation' +\vrule\vbox{\breaktt[4pt][.7\hsize]{% +Dans ce paragraphe, composé en fonte à chasse fixe et où les limites gauche +et droite du texte ont été tracées, on constate que les caractères sont +exactement les uns au-dessous des autres d'une ligne à l'autre. Plus aucun +débordement n'a lieu, car une espace correctement calculée est insérée entre +chaque caractère. Les mots, en revanche, sont toujours coupés <<sauvagement>>.% +}% +}\vrule\smallbreak + +\vrule\vbox{\breaktt[1pt][6cm]{% +Dans ce paragraphe, composé en fonte à chasse fixe et où les limites gauche +et droite du texte ont été tracées, on constate que les caractères sont +exactement les uns au-dessous des autres d'une ligne à l'autre. Plus aucun +débordement n'a lieu, car une espace correctement calculée est insérée entre +chaque caractère. Les mots, en revanche, sont toujours coupés <<sauvagement>>.% +}% +}\vrule +****************** Fin code ****************** + + +****************** Code 423 ****************** +\catcode`\@11 +\newcount\brktt@cnt +\newdimen\brktt@interletter +\newif\ifline@start% booléen vrai lorsqu'aucun caractère n'est encore affiché +\newif\if@indivifound% booléen qui sera vrai si un motif spécial est rencontré + +\newmacro\breakttA[0.3em][\hsize]1{% +% arg optionnel #1 et #2 = ressorts inter-lettre et dimension horizontale texte +% #3 = texte à espacer + \begingroup% ouvrir un groupe et le fermer à la toute fin + \par% commencer un nouveau paragraphe -> passage en mode vertical + \parindent=0pt% empêche l'indentation + \tt% passer en fonte à chasse fixe + \setbox0 = \hbox{M}% la boite 0 contient un caractère + \edef\ttchar@width{\the\wd0 }% largeur de chaque caractère en fonte \tt + \edef\text@width{\the\dimexpr#2\relax}% largeur de composition + % les 2 lignes suivantes rendent le compteur égal à E((L-l)/(l+Delta)) + \brktt@cnt=\numexpr\dimexpr#2-\wd0 \relax\relax% largeur diminuée du 1er caractère + \divide\brktt@cnt by \numexpr\dimexpr\wd0 + #1 \relax\relax + % le nombre de caractères par ligne est égal à 1 de plus : + \edef\maxchar@num{\number\numexpr\brktt@cnt+1\relax}% + % calcul de la dimension inter-lettre + \brktt@interletter=\dimexpr(\text@width-\ttchar@width*\maxchar@num)/\brktt@cnt\relax + % stocke le texte après avoir enlevé les éventuels espaces extremes : + \expsecond{\expsecond{\def\tt@remaintext}}{\removetrailspaces{#3}}% + \unless\ifx\tt@remaintext\empty% si le texte à composer n'est pas vide + \hbox\bgroup% démarrer la boite horizontale contenant la première ligne + \insert@blankchar\ttindent% insérer une espace d'indentation + \brktt@cnt=\ttindent\relax% tenir compte du nombre de caractères indentés + \line@starttrue% il s'agit du début d'une ligne + \expandafter\breakttA@i% aller à la macro récursive + \fi +} + +\def\breakttA@i{% + \edef\remaining@chars{% calculer le nombre de caractères restant à placer sur la ligne + \numexpr\maxchar@num-\brktt@cnt\relax}% + \len@tonextword% \next@len contient le nombre de caractères du prochain mot + % si le mot + l'eventuel "-" qui le suit ne peut pas loger sur la ligne en cours + \ifnum\numexpr\next@len+\extra@char\relax>\remaining@chars\relax + \ifline@start% et si c'est le début d'une ligne + % avertir l'utilisateur + \message{Largeur de composition trop faible pour + \unexpanded\expandafter{\next@word}^^J}% + % et composer tout de même "à la sauvage" jusqu'à la fin de la ligne + \exparg\print@nchar{\number\numexpr\maxchar@num-\brktt@cnt}% + \else% si la ligne en cours n'est pas au début + \insert@blankchar*{\maxchar@num-\brktt@cnt}% remplir la ligne d'espaces + \fi + \exparg\restart@hbox{\tt@remaintext}% commencer une nouvelle ligne + \expandafter\breakttA@i% et poursuivre le processus + % s'il y a assez de place pour accueillir ce qui est avant la prochaine coupure + \else + \print@nchar\next@len% afficher le mot + \ifx\tt@remaintext\empty% si texte restant est vide + \insert@blankchar*{\maxchar@num-\brktt@cnt}% remplir la ligne + \egroup% fermer la hbox en cours + \par% aller à la ligne + \endgroup% fermer le groupe ouvert au début. Fin du processus + \else% si le texte restant n'est pas vide + \ifnum\brktt@cnt<\maxchar@num\relax% si la ligne n'est pas remplie + \print@nchar{1}% afficher le caractère qui suit le mot (" " ou "-") + \else% si la ligne est remplie + \exparg\restart@hbox{\tt@remaintext}% ferme la hbox et en ré-ouvre une + \fi + \expandafter\expandafter\expandafter\breakttA@i% enfin, continuer le processus + \fi + \fi +} + +\def\leftofsc#1#2{% dans la macro #1, garde ce qui est à gauche de #2 + \def\leftofsc@i##1#2##2\@nil{\def#1{##1}}% + \expandafter\leftofsc@i#1#2\@nil +} + +\def\len@tonextword{% stocke dans \next@len le nombre de caractères avant + % le prochain point de coupure dans \tt@remaintext + \let\next@word\tt@remaintext% copie \tt@remaintext dans la macro temporaire \next@word + \leftofsc\next@word{ }% ne prend que ce qui est avant le prochain espace + \exparg\ifin\next@word{-}% si le mot contient un tiret + {\leftofsc\next@word{-}% prendre ce qui est à gauche de ce tiret + \def\extra@char{1}% il y a un caractère de plus à loger après le mot + }% sinon, le caractère après le mot est un espace + {\def\extra@char{0}% qu'il ne faut pas compter + }% + \setbox0=\hbox{\next@word}% enfermer le mot dans une boite + % et en calculer le nombre de caractères = dim(boite)/dim(caractère) + \edef\next@len{\number\numexpr\dimexpr\wd0 \relax/\dimexpr\ttchar@width\relax\relax}% +} +\catcode`\@12 + +\def\liglist{<<,>>}% liste des motifs de ligature (mettre à, é, etc si codage UTF8) +\def\ttindent{3} + +\vrule\vbox{\breakttA[3pt][8cm]{% +Dans ce paragraphe, composé en fonte à chasse fixe et où les limites gauche +et droite du texte ont été tracées, on constate que les caractères sont +exactement les uns au-dessous d'une ligne à l'autre. Plus aucun débordement +n'a lieu, car une espace correctement calculée est insérée entre chaque +caractère. Dorénavant, les mots ne sont plus coupés <<~sauvagement~>>. +}}\vrule\medbreak + +\leavevmode\vrule\vbox{\breakttA[1pt][5cm]{% +Dans ce paragraphe, composé en fonte à chasse fixe et où les limites gauche +et droite du texte ont été tracées, on constate que les caractères sont +exactement les uns au-dessous d'une ligne à l'autre. Plus aucun débordement +n'a lieu, car une espace correctement calculée est insérée entre chaque +caractère. Dorénavant, les mots ne sont plus coupés <<~sauvagement~>>. +}}\vrule\qquad\def\ttindent{0}% +\vrule\vbox{\breakttA[0.6pt][2cm]{mot-composé mot-clé passe-droit au-dessus +là-bas remonte-pente vingt-huit Notre-Dame-de-Lourdes Mont-Blanc +Saint-Jean-de-Luz}}\vrule +****************** Fin code ****************** + + +****************** Code 424 ****************** +\newmacro\zerocompose[]2{% +% #1=code à exécuter avant la composition +% #2=registre de boite recevant le résultat +% #3= texte à composer en largeur 0pt + \setbox#2=\vbox{% + #1% code a exécuter (changement de fonte par exemple) + \hfuzz=\maxdimen% annule les avertissements pour débordement horizontaux + \hbadness=10000 % annule les avertissements pour mauvaise boite horizontale + \pretolerance=-1 % désactive la première passe (celle sans coupures) + \tolerance=10000 % passe avec coupures acceptée + \hyphenpenalty=-10000 % favorise fortement les copures de mots + \lefthyphenmin=2 \righthyphenmin=3 % longueur mini des fragments de début et fin + \clubpenalty=0 % pas de pénalité supplémentaire après la première ligne + \interlinepenalty=0 % pas de pénalité inter-ligne + \widowpenalty=0 % pas de pénalité supplémentaire avant la dernière ligne + \exhyphenpenalty=0 % ne pas pénaliser une coupure explicite + \leftskip=0pt \rightskip=0pt % désactive les éventuels ressorts latéraux + \everypar={}% désactive l'éventuel \everypar + \parfillskip=0pt plus1fil % règle le \parfillskip par défaut + \hsize=0pt % largeur de composition = 0pt + \edef\restorehyphenchar{\hyphenchar\font=\number\hyphenchar\font}% + \hyphenchar\font=`\- % impose "-" comme caractère de coupure + \noindent % pas d'indentation + passage en mode horizontal + \hskip0pt \relax% premier noeud horizontal pour permettre la coupure de la suite + #3\par% compose #3 + \restorehyphenchar% restaure le caractère de coupure + }% +} +\zerocompose{0}{Programmation}% +\leavevmode\box0 +\hskip 5cm +\zerocompose{0}{Composer en largeur nulle}% +\box0 +****************** Fin code ****************** + + +****************** Code 425 ****************** +\def\dummytext{Ceci est un texte sans aucun intérêt dont le seul but est de meubler + la page de façon artificielle. } +\setbox0=\vtop{% définit la boite 0 + \hsize=8cm + \dummytext\dummytext +} + +a) Boite pleine : \copy0 + +b) \setbox0=\vtop{% + \unvbox0 % boite précédemment composée + \global\setbox1=\lastbox% et capture la dernière ligne dans la boite 1 + }% + Dernière ligne = |\hbox{\unhbox1 }|\par% redonne à box1 sa largeur naturelle + Boite restante = \box0 +****************** Fin code ****************** + + +****************** Code 426 ****************** +\def\dummytext{Ceci est un texte sans aucun intérêt dont le seul but est de meubler + la page de façon artificielle. } +\setbox0=\vtop{% définit la boite 0 + \hsize=8cm + \dummytext\dummytext +} + +\setbox0=\vtop{\unvbox0 \global\setbox1=\lastbox} +\setbox1=\hbox{\unhbox1 } +1) |\box1| + +\setbox0=\vtop{\unvbox0 \global\setbox1=\lastbox} +\setbox1=\hbox{\unhbox1 } +2) |\box1| + +\setbox0=\vtop{\unvbox0 \global\setbox1=\lastbox} +\setbox1=\hbox{\unhbox1 } +3) |\box1| +****************** Fin code ****************** + + +****************** Code 427 ****************** +\setbox0=\vbox{\hsize=2.5cm Programmer en TeX est facile}% +\showboxbreadth=5 \showboxdepth=3 \tracingonline=1 +\showbox0 +****************** Fin code ****************** + + +****************** Code 428 ****************** +\newbox\tempbox +\def\reversebox#1{% affiche le contenu de la boite verticale #1 + \setbox#1=\vbox{% + \unvbox#1% composer la boite #1 + \unskip\unpenalty% retirer ce qui n'est pas capturable par \lastbox + \global\setbox0=\lastbox% la boite 1 devient la dernière ligne + }% + |\hbox{\unhbox0 }|\par% afficher la boite 1 dans sa largeur d'origine + \ifvoidorempty{#1}% si le registre #1 contient une boite vide + \relax% ne rien faire + {\reversebox{#1}}% sinon, rencommencer +} +\def\dummytext{Ceci est un texte sans aucun intérêt dont le seul but est de meubler + la page de façon artificielle. } +\setbox\tempbox=\vbox{% définit la boite 0 + \hsize=8cm \dummytext\dummytext +} + +\reversebox\tempbox +****************** Fin code ****************** + + +****************** Code 429 ****************** +% compose "Programmation" en largeur 0 dans la boite 0 : +\zerocompose{0}{Programmation}% +Boite initiale : \copy0 \par% compose la boite résultante +\vfuzz=\maxdimen% annule les avertissements pour débordements +\splittopskip=0pt % ne rajouter aucun espace au sommet de la boite restante +\setbox1 =\vsplit0 to 0pt % coupe la boite 0 à 0pt +{% dans un groupe (où la boite 0 sert de brouillon) + \setbox0 =\vbox{% affecter à la boite brouillon + \unvbox1 % la boite 1 composée dans sa largeur naturelle + \unskip\unpenalty% annule ce qui n'est pas une boite + \global\setbox2 =\lastbox% affecte globalement la dernière (et unique) ligne + % à la boite 1 + }% +}% ferme le groupe +\setbox2=\hbox{\unhbox2}% rend à la boite 2 sa largeur naturelle +Première ligne = "\box2 "% compose la boite 2 +****************** Fin code ****************** + + +****************** Code 430 ****************** +\catcode`@11 +\def\hyphlengths#1#2{%#2 = macro contenant les longueurs de coupures du mot #1 + \begingroup + \zerocompose + [\tt% passer en fonte à chasse fixe + \setbox\z@\hbox{M}\xdef\ttwidth{\the\wd\z@}% mesurer la largeur des caractères + ]\z@{#1}% compose en 0pt dans la boite 0 + \let#2 = \empty% initialise la macro #2 + \def\cumul@length{0}% le cumul des longueurs initialisé à 0 + \vfuzz=\maxdimen% annule les avertissements pour débordement + \splittopskip=\z@ % ne rajouter aucun espace au sommet de la boite restante + \loop + \setbox1=\vsplit\z@ to \z@% couper la boite à 0pt de hauteur + {\setbox\z@=\vbox{\unvbox1 \unskip\unpenalty\global\setbox1=\lastbox}}% + \setbox1=\hbox{\unhbox1 }% + \unless\ifvoid\z@% si la boite 0 n'est pas encore vide + \edef\cumul@length{% mettre à jour \cumul@length + \number\numexpr + \cumul@length + +% ajouter le quotient "largeur syllabe/largeur d'1 caractère" + \wd1/\dimexpr\ttwidth\relax + -1% et soustraire 1 (le caractère "-") + \relax + }% + % ajouter à #2 la virgule et le cumul actuel +1 + \edef#2{% définir la macro #2 : + #2% reprendre le contenu de #2 + \ifx#2\empty\else,\fi% ajouter "," si #2 non vide + \number\numexpr\cumul@length+1\relax% et le cumul + }% + \repeat% et recommencer + \expsecond{% avant de fermer le groupe + \endgroup + \def#2}{#2}% définit #2 hors du groupe +} +\catcode`\@12 +a) \hyphlengths{programmation}\foo liste = "\foo"\par +b) \hyphlengths{typographie}\foo liste ="\foo"\par +c) \hyphlengths{j'entendrai}\foo liste ="\foo"\par +d) \hyphlengths{vite}\foo liste ="\foo" +****************** Fin code ****************** + + +****************** Code 431 ****************** +\catcode`\@11 +\newcount\brktt@cnt +\newdimen\brktt@interletter +\newif\ifline@start% booléen vrai lorsqu'aucun caractère n'est encore affiché +\newif\if@indivifound% booléen qui sera vrai si un motif spécial est rencontré + +\let\breakttB=\breakttA + +\def\breakttA@i{% + \edef\remaining@chars{% calculer le nombre de caractères restant à placer sur la ligne + \numexpr\maxchar@num-\brktt@cnt\relax}% + \len@tonextword% calculer dans \next@len le nombre de caractères avant le prochain mot + \def\next@hyphlen{0}% initialiser la longueur de coupure possible du mot + % si le mot + l'eventuel "-" qui le suit ne rentre pas sur ce qui reste de la ligne + \ifnum\numexpr\next@len+\extra@char\relax>\remaining@chars\relax + \hyphlengths\next@word\list@hyphlengths% bâtir la liste des longueurs de coupures + \unless\ifx\list@hyphlengths\empty% si une coupure est possible + \expsecond{\doforeach\xx\in}{\list@hyphlengths}% les examiner toutes + {% si la coupure examinée peut loger sur la ligne + \unless\ifnum\xx>\remaining@chars\relax% + \let\next@hyphlen\xx% la stocker + \fi% pour que \next@hyphlen soit maximal + }% + \fi + \fi + \ifnum\next@hyphlen>0 % si une coupure est nécessaire et a été trouvée + \let\next@len\next@hyphlen% mettre à jour la longueur du mot à placer + \fi + % si le mot + l'eventuel "-" qui le suit ne peut pas loger sur la ligne en cours + \ifnum\numexpr\next@len+\extra@char\relax>\remaining@chars\relax + \ifline@start% si c'est le début d'une ligne + % avertir l'utilisateur + \message{Largeur de composition trop faible pour + \unexpanded\expandafter{\next@word}^^J}% + % et composer tout de même jusqu'à la fin de la ligne + \exparg\print@nchar{\number\numexpr\maxchar@num-\brktt@cnt}% + \else% sinon + \insert@blankchar*{\maxchar@num-\brktt@cnt}% remplir la ligne + \fi + \exparg\restart@hbox{\tt@remaintext}% ré-ouvrir une boite + \expandafter\breakttA@i% et poursuivre le processus + % s'il y a la place pour accueillir ce qui est avant la prochaine coupure + \else + \ifnum\next@hyphlen>0 % si une coupure de mot doit être faite + \exparg\print@nchar{\number\numexpr\next@len-1}% afficher les lettres de la syllabe + \print@hyphchar% et le caractère de coupure + \insert@blankchar*{\maxchar@num-\brktt@cnt}% remplir la ligne + \exparg\restart@hbox{\tt@remaintext}% ré-ouvrir une boite + \expandafter\expandafter\expandafter\breakttA@i% et continuer le processus + \else% si pas de coupure dans le mot + \print@nchar\next@len% afficher le mot + \ifx\tt@remaintext\tt@emptytext% si texte restant est vide + \insert@blankchar*{\maxchar@num-\brktt@cnt}% remplir la ligne + \egroup% fermer la hbox + \par% aller à la ligne + \endgroup% fermer le groupe ouvert au début. Fin du processus + \else% si le texte restant n'est pas vide + \ifnum\brktt@cnt<\maxchar@num\relax% si la ligne n'est pas remplie + \print@nchar{1}% afficher le caractère qui suit le mot + \else% si la ligne est remplie + \exparg\restart@hbox{\tt@remaintext}% ferme la hbox et en ré-ouvre une + \fi + \expandafter\expandafter\expandafter\breakttA@i% enfin, continuer le processus + \fi + \fi + \fi +} + +\def\print@hyphchar{% + \advance\brktt@cnt by 1 % augmenter le compteur de caractères + \hbox to\ttchar@width{\hss-\hss}% afficher "-" + \ifnum\brktt@cnt<\maxchar@num\relax% si la ligne n'est pas encore remplie + \kern\brktt@interletter\relax% insérer le ressort inter-lettre + \fi +} + +\catcode`\@12 + +\def\liglist{<<,>>}% liste des motifs de ligature (mettre à, é, etc si codage UTF8) +\def\ttindent{3} + +\vrule\vbox{\breakttB[3pt][8cm]{% +Dans ce paragraphe, composé en fonte à chasse fixe et où les limites gauche +et droite du texte ont été tracées, on constate que les caractères sont +exactement les uns au-dessous d'une ligne à l'autre. Plus aucun débordement +n'a lieu, car une espace correctement calculée est insérée entre chaque +caractère. Dorénavant, les mots ne sont plus coupés <<sauvagement>>. +}% +}\vrule + +\vrule\vbox{\breakttB[1pt][5cm]{% +Dans ce paragraphe, composé en fonte à chasse fixe et où les limites gauche +et droite du texte ont été tracées, on constate que les caractères sont +exactement les uns au-dessous d'une ligne à l'autre. Plus aucun débordement +n'a lieu, car une espace correctement calculée est insérée entre chaque +caractère. Dorénavant, les mots ne sont plus coupés <<sauvagement>>. +}% +}\vrule +****************** Fin code ****************** + + +****************** Code 432 ****************** +Voici un algorithme élémentaire : +\algorithm[\#]{Algorithme {\bf MinMax}}| +macro ~Min_Max~ (#1) % afficher la valeur max et min d'une liste de valeurs #1 + $V_{max}:=-\infty$ % $-\infty$ ou la plus petite valeur possible + $V_{min}:=+\infty$ % $+\infty$ ou la plus grande valeur possible + ~Pour~ chaque $x$ dans (#1) + ~Si~ $x>V_{max}$ + ~alors~ $V_{max}:=x$ + ~FinSi~ + ~Si~ $x<V_{min}$ + ~alors~ $V_{min}:=x$ + ~FinSi~ + ~FinPour~ + Afficher "$V_{min}$ et $V_{max}$" +~FinMin_Max~| +Suite du texte... +****************** Fin code ****************** + + +****************** Code 433 ****************** +\def\algoindent{1cm}% +\begingroup +\parindent=0pt % pas d'indentation +\defactive\^^M{\leavevmode\par}% rend le retour charriot actif +\defactive\^^I{\hskip\algoindent\relax}% tabulation active +Pas d'indentation ici\ldots + Voici une première ligne + une seconde plus indentée + retour à l'indentation normale + \for\xx=1to10\do{un long texte } + pour terminer, la dernière ligne +\endgroup +****************** Fin code ****************** + + +****************** Code 434 ****************** +\def\algoindent{1cm}% +\begingroup +\leftskip=0pt \rightskip=0pt plus1fil \relax % initialise les ressorts latéraux +\parindent=0pt % pas d'indentation +\defactive\^^M{\leavevmode\par\leftskip=0pt }% rend le retour charriot actif +\defactive\^^I{\advance\leftskip by \algoindent\relax}% tabulation active +Pas d'indentation ici\ldots + Voici une première ligne + une seconde plus indentée + retour à l'indentation normale + \for\xx=1to10\do{un long texte } + pour terminer, la dernière ligne +\endgroup +****************** Fin code ****************** + + +****************** Code 435 ****************** + % compteur de lignes pour l'algorithme +\def\algoindent{1cm}% +\begingroup +\algocnt=1 % initialise le compteur à 1 +\leftskip=0pt \rightskip=0pt plus1fil\relax% initialise les ressorts à 0pt +\parindent=0pt % pas d'indentation +\everypar={\llap{$\scriptstyle\number\algocnt$\kern\dimexpr4pt+\leftskip\relax}}% + +\defactive\^^M{\leavevmode\par\advance\algocnt by1 \leftskip=0pt }% retour charriot actif +\defactive\^^I{\advance\leftskip by \algoindent\relax}% tabulation active +Pas d'indentation ici\ldots + Voici une première ligne + une seconde plus indentée + retour à l'indentation normale + \for\xx=1to10\do{un long texte } + pour terminer, la dernière ligne +\endgroup +****************** Fin code ****************** + + +****************** Code 436 ****************** +\newif\ifnumalgo +\newcount\algocnt +\numalgotrue + +\def\algoindent{2em} +\def\algorule{.4pt}% épaisseur des réglures de début et de fin + +\def\algohrulefill{% remplit avec une ligne horizontale + \leavevmode + \leaders\hrule height\algorule\hfill + \kern0pt % rajoute un noeud au cas où la commande est en fin de ligne +} + +\newmacro\algorithm[\\,\#,\{,\}]2{% + \medbreak + \begingroup% ouvre un groupe (sera fermé à la fin de l'algorithme) + \algocnt=1 % initialise le compteur de lignes + \leftskip=0pt \rightskip=0pt plus1fil\relax% initialise les ressorts latéraux + \parindent=0pt % pas d'indentation + %%%%%%%%%%%% affichage du titre %%%%%%% + \algohrulefill% remplir avec une ligne horizontale + \ifempty{#2}% si #2 est vide + {}% ne rien insérer + {% sinon + \lower.5ex\hbox{ #2 }% insérer le titre abaissé de 0.5ex + \algohrulefill% insérer une ligne horizontale + }% + \par% aller à la ligne + \nointerlineskip% ne pas insérer le ressort d'interligne + \kern7pt % et sauter 7pt verticalement + \nobreak% empêcher une coupure de page + %%%%%%%%%%%%%% fin du titre %%%%%%%%%% + % + %%%%%%%%%%%%%% rend les caractères actifs %%%%%%%%%%%%%% + \def~##1~{\begingroup\bf##1\endgroup}% + \defactive:{% rend ":" actif + \futurelet\nxttok\algoassign% \nxttok = token suivant + }% + \def\algoassign{% suite du code de ":" + \ifx=\nxttok% si ":" est suivi de "=" + \ifmmode% si mode math + \leftarrow% afficher "\leftarrow" + \else% si mode texte + ${}\leftarrow{}$% passer en mode math pour "\leftarrow" + \fi + \expandafter\gobone% manger le signe "=" + \else% si ":" n'est pas suivi de "="' + \string:% afficher ":" + \fi + }% + \ifnumalgo% si la numérotation est demandée, + \everypar={% définir le \everypar + \llap{$\scriptstyle\number\algocnt$\kern\dimexpr4pt+\leftskip\relax}% + }% + \fi + \doforeach\currentchar\in{#1}{\catcode\expandafter`\currentchar=12 }% + \def\algocr{% définit ce que fait ^^M + \color{black}% repasse en couleur noire + \rm% fonte droite + \leavevmode\par% termine le paragraphe + \advance\algocnt by1 % incrémente le compteur de lignes + \leftskip=0pt % initialise le ressort gauche + } + \letactive\^^M=\algocr% + \defactive\^^I{\advance\leftskip by \algoindent\relax}% + \defactive\ {\hskip1.25\fontdimen2\font\relax}% espace = 25% de + que + % la largeur naturelle + \defactive\%{\it\color{gray}\char`\%}% passe en italique et gris puis affiche "%" + \defactive_{\ifmmode_\else\string_\fi}% + \defactive#3{% rend le token #3 actif (il sera rencontré à la fin de l'algorithme) + \everypar{}% neutralise le \everypar + \par% aller à la ligne + \nointerlineskip% ne pas insérer le ressort d'interligne + \kern7pt % et sauter 7pt verticalement + \nobreak% empêcher une coupure de page + \algohrulefill% tracer la ligne de fin + \endgroup% ferme le groupe ouvert au début de l'algorithme + \smallbreak% saute un petit espace vertical + }% + %%%%%%%%%%%%%%%%% fin des caractères actifs %%%%%%%%%%%%%%%% + \sanitizealgo% va manger les espaces et les ^^M au début de l'algo +} + +\def\sanitizealgo{\futurelet\nxttok\checkfirsttok}% récupère le prochain token + +\def\checkfirsttok{% teste le prochaun token + \def\nextaction{% a priori, on considère que la suite est " " ou "^^M" donc + \afterassignment\sanitizealgo% aller à \sanitizealgo + \let\nexttok= % après avoir mangé ce "^^M" ou cet espace + }% + \unless\ifx\nxttok\algocr% si le prochain token n'est pas un ^^M + \unless\ifx\space\nxttok% et si le prochain token n'est pas un espace + \let\nextaction\relax% ne rien faire ensuite + \fi + \fi + \nextaction% faire l'action décidée ci-dessus +} + +Voici un algorithme élémentaire +\algorithm[\#]{Algorithme {\bf MinMax}}| +macro ~Min_Max~ (#1) % afficher la valeur max et min d'une liste de valeurs #1 +W$V_{max}:=-\infty$ % $-\infty$ ou la plus petite valeur possible +W$V_{min}:=+\infty$ % $+\infty$ ou la plus grande valeur possible +W~Pour~ chaque $x$ dans (#1) +WW~Si~ $x>V_{max}$ +WWW~alors~ $V_{max}:=x$ +WW~FinSi~ +WW~Si~ $x<V_{min}$ +WWW~alors~ $V_{min}:=x$ +WW~FinSi~ +W~FinPour~ +WAfficher "$V_{min}$ et $V_{max}$" +~FinMin_Max~| +Suite du texte... +****************** Fin code ****************** + + +****************** Code 437 ****************** +a) \meaning a\par +b) \meaning {\par +c) \meaning _\par +d) \meaning\def\par % une primitive +e) \meaning\baselineskip\par% une primitive +f) \long\def\foo#1#2.#3{#1 puis #2 et #3 !}\meaning\foo +****************** Fin code ****************** + + +****************** Code 438 ****************** +\def\foo#1#2{% + \def\argA{#1}\show\argA% débogage + Bonjour #1 et #2} +\foo{{\bf X}}{Y} +****************** Fin code ****************** + + +****************** Code 439 ****************** +\def\foo#1#2{% + \showtokens{#1}% débogage + Bonjour #1 et #2} +\foo{{\bf X}}{Y} +****************** Fin code ****************** + + +****************** Code 440 ****************** +\newtoks\footoks +\footoks={foo bar} +\show\footoks +****************** Fin code ****************** + + +****************** Code 441 ****************** +\showthe\baselineskip% registre-primitive +\newtoks\footoks \footoks={foo bar} \showthe\footoks +\newcount\foocount \foocount=987 \showthe\foocount +\newdimen\foodimen \foodimen=3.14pt \showthe\foodimen +\newskip\fooskip \fooskip=10 pt plus 1pt minus 1fil \showthe\fooskip +\newbox\foobox \foobox\hbox{foo} \showthe\foobox +****************** Fin code ****************** + + +****************** Code 442 ****************** +\def\foo#1,#2\endfoo{Bonjour #1 et #2} +\tracingmacros=1 +\foo moi,toi\endfoo +\tracingmacros=0 +****************** Fin code ****************** + + +****************** Code 443 ****************** +\tracingcommands=2 +Foo \hbox{et \ifnum2>1 bar\else toi\fi}\par +Suite +\tracingcommands=0 +****************** Fin code ****************** + + +****************** Code 444 ****************** +\def\i{\advance\count255 1 } +\tracingrestores=1 +\count255=2 {\i\i\i} +\tracingrestores=0 +****************** Fin code ****************** + + +****************** Code 445 ****************** +\def\i{\advance\count255 1 } \def\gi{\global\i} +\tracingrestores=1 +\count255=2 {\i\i\gi\i\gi\i} +\tracingrestores=0 +****************** Fin code ****************** + + +****************** Code 446 ****************** +\catcode`@11 +\def\ifnodecpart#1{\ifnodecpart@i#1.\@nil} +\def\ifnodecpart@i#1.#2\@nil{\ifempty{#2}} +\def\decadd#1#2{% #1 et #2=nombre à additionner + \ifnodecpart{#1}% si #1 est un entier + {\ifnodecpart{#2}% et #2 aussi, les additionner avec \numexpr + {\number\numexpr#1+#2\relax}% + {\decadd@i#1.0\@nil#2\@nil}% sinon, ajouter ".0" après #1 + } + {\ifnodecpart{#2}% si #1 a une partie entière mais pas #2 + {\decadd@i#1\@nil#2.0\@nil}% ajouter ".0" à #2 + {\decadd@i#1\@nil#2\@nil}% sinon, les 2 parties entières sont présentes + }% +} +\def\decadd@i#1.#2\@nil#3.#4\@nil{% affiche les parties entières et décimales reçues + $x_a=#1\quad y_a=#2\qquad x_b=#3\quad y_b=#4$ +} +\catcode`@12 +a) \decadd{5}{9.4}\par +b) \decadd{-3.198}{-6.02}\par +c) \decadd{0.123}{123} +****************** Fin code ****************** + + +****************** Code 447 ****************** +\def\addzeros#1#2/#3.#4#5/#6.#7/{% + Arguments reçus : #1#2/#3.#4#5/#6.#7/\par% afficher ce que la macro reçoit + \ifempty{#2}% si #1 est le dernier chiffre de y + {\ifempty{#5}% et si #4 est le dernier chiffre de y2 + {Résultat final : \detokenize{{#3#1}{#6#4}{#70}}}% afficher le résultat final + {\addzeros0/#3#1.#5/#6#4.#70/}% sinon alimenter #1 avec un 0 + } + {\ifempty{#5}% si #4 est le dernier chiffre de y2 + {\addzeros#2/#3#1.0/#6#4.#70/}% alimenter #4 avec un 0 + {\addzeros#2/#3#1.#5/#6#4.#70/}% #2 et #5 non vides + }% +} +\addzeros457/.689714/.1/ +****************** Fin code ****************** + + +****************** Code 448 ****************** +\catcode`\@11 +\def\addzeros#1#2/#3.#4#5/#6.#7/{% + \ifempty{#2}% si #1 est le dernier chiffre de y1 + {\ifempty{#5}% et si #4 est le dernier chiffre de y2 + {{#3#1}{#6#4}{#70}}% redonner les 3 arguments + {\addzeros0/#3#1.#5/#6#4.#70/}% sinon alimenter #1 avec un 0 + } + {\ifempty{#5}% si #4 est le dernier chiffre de y2 + {\addzeros#2/#3#1.0/#6#4.#70/}% alimenter #4 avec un 0 + {\addzeros#2/#3#1.#5/#6#4.#70/}% #2 et #5 non vides + }% +} +\def\decadd#1#2{% #1 et #2=nombre à additionner + \ifnodecpart{#1} + {\ifnodecpart{#2}{\number\numexpr#1+#2\relax}{\decadd@i#1.0\@nil#2\@nil}} + {\ifnodecpart{#2}{\decadd@i#1\@nil#2.0\@nil}{\decadd@i#1\@nil#2\@nil}}% +} +\def\decadd@i#1.#2\@nil#3.#4\@nil{% + \expandafter\decadd@ii + \romannumeral-`\0\addzeros#2/.#4/.1/% se développe en 3 arguments + {#1} + {#3}% +} +\def\decadd@ii#1#2#3#4#5{% +% #1 et #2=parties décimales (mêmes longueurs); +% #3=seuil de retenue; #4 et #5=parties entières + \exptwoargs{\decadd@iii{#3}}% envoyer le seuil de retenue tel quel + % sommer les parties décimales signées + {\number\numexpr\true@sgn{#4}#1+\true@sgn{#5}#2\relax}% + % et les parties entières + {\number\numexpr#4+#5\relax}% +} +\def\decadd@iii#1#2#3{% + seuil de retenue = #1 \qquad nombre = "#3"."#2"% +} +\catcode`\@12 +a) \decadd{6.7}{3.498}\par +b) \decadd{1.67}{-4.9}\par +c) \decadd{3.95}{2.0005}\par +d) \decadd{1.007}{2.008}\par +e) \decadd{-7.123}{3.523} +****************** Fin code ****************** + + +****************** Code 449 ****************** +\catcode`\@11 +\def\format@dec#1#2{% #1=partie décimale #2=seuil de retenue + \expandafter\gobone% le \gobone agira en dernier, + \romannumeral-`\0% mais avant, tout développer + \expandafter\reverse\expandafter% et retarder le \reverse de fin + % pour développer son argument qui + {\number% développe tout et évalue avec \number + \expandafter\reverse\expandafter% l'inversion de + {\number\numexpr\abs{#1}+#2\relax}% |#1|+#2 + }% +} +a) \format@dec{710}{100000}\par +b) \format@dec{6}{100}\par +c) \format@dec{-12300}{1000000} +\catcode`\@12 +****************** Fin code ****************** + + +****************** Code 450 ****************** +\catcode`@11 +\def\true@sgn#1{\ifnum#11<\z@-\fi} +\def\decadd#1#2{% #1 et #2=nombre à additionner + \romannumeral-`\.% tout développer jusqu'à l'affichage du nombre (\decadd@iv) + \ifnodecpart{#1}% si #1 est un entier + {\ifnodecpart{#2}% et #2 aussi, les additionner avec \numexpr + {\numexpr#1+#2\relax}% + {\decadd@i#1.0\@nil#2\@nil}% sinon, ajouter ".0" après #1 + } + {\ifnodecpart{#2}% si #1 a une partie entière mais pas #2 + {\decadd@i#1\@nil#2.0\@nil}% ajouter ".0" à #2 + {\decadd@i#1\@nil#2\@nil}% sinon, les 2 parties entières sont présentes + }% +} +\def\decadd@i#1.#2\@nil#3.#4\@nil{% + \expandafter\decadd@ii + \romannumeral-`\0\addzeros#2/.#4/.10/% se développe en 3 arguments + {#1} + {#3}% +} +\def\decadd@ii#1#2#3#4#5{% +% #1 et #2=parties décimales (mêmes longueurs) +% #3=seuil de retenue; #4 et #5=parties entières + \exptwoargs{\decadd@iii{#3}}% envoyer le seuil de retenue tel quel + % sommer les parties décimales signées + {\number\numexpr\true@sgn{#4}#1+\true@sgn{#5}#2\relax}% + % et les parties entières + {\number\numexpr#4+#5\relax}% +} +\def\decadd@iii#1#2#3{% #1=seuil de retenue #2=partie décimale #3= partie entière + \ifnum\true@sgn{#2}\true@sgn{\ifnum#3=\z@#2\else#3\fi}1=-1 % si les signes sont + % différents + \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {\exptwoargs\decadd@iv% transmettre les arguments modifiés : + {\number\numexpr#3-\true@sgn{#3}1}% #3:=#3-sgn(#3)1 + {\number\numexpr#2-\true@sgn{#2}#1}% #2:=#2-sgn(#2)10^n + {#1}% + }% si les signes sont égaux + {\ifnum\abs{#2}<#1 % et si abs(y)<10^n + \expandafter\firstoftwo\else\expandafter\secondoftwo\fi + {\decadd@iv{#3}{#2}{#1}% tranmettre les arguments tels quels + } + {\exptwoargs\decadd@iv% sinon + {\number\numexpr#3+\true@sgn{#3}1}% #3:=#3+sgn(#3)1 + {\number\numexpr#2-\true@sgn{#2}#1}% #2:=#2-sgn(#2)10^n + {#1}% + }% + }% +} +\def\decadd@iv#1#2#3{% affiche le décimal "#1.#2" + % le développement maximal initié par le \romannumeral de \decadd est actif + \ifnum#1=\z@\ifnum#2<\z@% si #1=0 et #2<0 + \expandafter\expandafter\expandafter% transmettre le développement à \number + -% puis afficher le signe "-" + \fi\fi + \number#1% affiche #1 qui est la somme des parties entières + % poursuivre le développement initié par \number + \unless\ifnum#2=\z@% si la partie décimale est différente de 0 + \antefi% se débarrasser de \fi + \expandafter.% afficher le "." décimal après avoir + \romannumeral-`\0\format@dec{#2}{#3}% correctement géré les 0 de #2 + \fi +} +\def\addzeros#1#2/#3.#4#5/#6.#7/{% + \ifempty{#2}% si #1 est le dernier chiffre de y1 + {\ifempty{#5}% et si #4 est le dernier chiffre de y2 + {{#3#1}{#6#4}{#7}}% redonner les 3 arguments + {\addzeros0/#3#1.#5/#6#4.#70/}% sinon alimenter #1 avec un 0 + } + {\ifempty{#5}% si #4 est le dernier chiffre de y2 + {\addzeros#2/#3#1.0/#6#4.#70/}% alimenter #4 avec un 0 + {\addzeros#2/#3#1.#5/#6#4.#70/}% #2 et #5 non vides + }% +} +\def\format@dec#1#2{% #1=partie décimale #2=seuil de retenue + \expandafter\gobone% le \gobone agira en dernier, + \romannumeral-`\0% mais avant, tout développer + \expandafter\reverse\expandafter% et retarder le \reverse de fin + % pour développer son argument qui + {\number% développe tout et évalue avec \number + \expandafter\reverse\expandafter% l'inversion de + {\number\numexpr\abs{#1}+#2\relax}% abs(#1)+#2 + }% +} +\catcode`@12 +a) $-3.78+1.6987=\decadd{-3.78}{1.6987}$\par +b) $3.56-3.06=\decadd{3.56}{-3.06}$\par +c) $4.125+13.49=\decadd{4.125}{13.49}$\par +d) $-0.99+1.005=\decadd{-0.99}{1.005}$\par +e) $16.6-19.879=\decadd{16.6}{-19.879}$\par +f) $5.789-0.698=\decadd{5.789}{-0.698}$\par +g) $0.123-0.123=\decadd{0.123}{-0.123}$\par +h) $3.14-16.4912=\decadd{3.14}{-16.4912}$\par +i) $0.1-0.98=\decadd{0.1}{-0.98}$\par +j) $2.43+7.57=\decadd{2.43}{7.57}$\par +h) \edef\foo{\decadd{1.23}{9.78}}\meaning\foo\par +j) \detokenize\expandafter\expandafter\expandafter{\decadd{3.14}{-8.544}} +****************** Fin code ****************** + + +****************** Code 451 ****************** +a) \pdfstrcmp{foo}{bar}\qquad +b) \pdfstrcmp{bar}{foo}\qquad +c) \def\foo{ABC}\pdfstrcmp{\foo}{ABC}\qquad +d) \edef\foo{\string_}\pdfstrcmp{1_2}{1\foo2}\qquad +e) \pdfstrcmp{\string\relax}{\relax} +****************** Fin code ****************** + + +****************** Code 452 ****************** +\edef\tempcompil{\number\pdfelapsedtime}% +Depuis le début de la compilation, il s'est écoulé \tempcompil{} secondes d'échelle, +soit \convertunit{\tempcompil sp}{pt} secondes. +****************** Fin code ****************** + + +****************** Code 453 ****************** +%%%%%%%%%% definition de \loop...\repeat comme plain-TeX %%%%%%%%%% +\def\loop#1\repeat{\def\body{#1}\iterate} +\def\iterate{\body \let\next\iterate \else\let\next\relax\fi \next} +\let\repeat=\fi +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\newcount\testcnt +\pdfresettimer% remet le compteur à 0 + \testcnt=0 + \loop % Test no 1 + \ifnum\testcnt<100000 \advance\testcnt 1 + \repeat +Temps 1 = \convertunit{\pdfelapsedtime sp}{pt} s (boucle loop de \TeX)\par +%%%%%%%%%%%% definition de \loop...\repeat comme LaTeX %%%%%%%%%%%% +\def\loop#1\repeat{\def\iterate{#1\relax\expandafter\iterate\fi}% + \iterate \let\iterate\relax} +\let\repeat\fi +\pdfresettimer% remet le compteur à 0 + \testcnt=0 + \loop % Test no 2 + \ifnum\testcnt<100000 + \advance\testcnt 1 + \repeat +Temps 2 = \convertunit{\pdfelapsedtime sp}{pt} s (boucle loop de \LaTeX)\par +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\pdfresettimer% remet le compteur à 0 + \for\ii=1 to 100000\do{}% Test no 3 +Temps 3 = \convertunit{\pdfelapsedtime sp}{pt} s (boucle for) +****************** Fin code ****************** + + +****************** Code 454 ****************** +%%%%%%%%%%%% definition de \loop...\repeat comme LaTeX %%%%%%%%%%%% +\def\loop#1\repeat{\def\iterate{#1\relax\expandafter\iterate\fi}% + \iterate \let\iterate\relax} +\let\repeat\fi +\pdfresettimer% remet le compteur à 0 + \def\ii{0}% + \loop % Test no 1 + \ifnum\ii<100000 + \edef\ii{\number\numexpr\ii+1\relax}% + \repeat +Temps 1 = \convertunit{\pdfelapsedtime sp}{pt} s (boucle loop de \LaTeX)\par +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\pdfresettimer% remet le compteur à 0 + \for\ii=1 to 100000\do{}% Test no 2 +Temps 2 = \convertunit{\pdfelapsedtime sp}{pt} s (boucle for) +****************** Fin code ****************** + + +****************** Code 455 ****************** +\newcount\testcnt +\pdfresettimer +\testcnt=0 +\for\ii=1 to 100000\do{\advance\testcnt1 } +Temps 1 : \convertunit{\pdfelapsedtime sp}{pt} s (incrémentation compteur) + +\pdfresettimer +\def\foo{0}% +\for\ii=1 to 100000\do{\edef\foo{\number\numexpr\foo+1\relax}}% +Temps 2 : \convertunit{\pdfelapsedtime sp}{pt} s (incrémentation du texte de remplacement) +****************** Fin code ****************** |