Le mpg-blog

LaTeX et autres geekeries

Tester si une commande est définie en (La)TeX

without comments

Reprise d’un de mes articles récents sur fctt, qui fait le point sur les mille-et-une (en fait, un peu moins) façons de savoir si une séquence de contrôle est définie ou non : en TeX pur, en LaTeX, en e-TeX, en distinguant ou pas \relax de undefined

Pour commencer, précisons que « non défini » et \relax c’est pas pareil en général :

This is TeX, Version 3.1415926 (Web2C 7.5.7)
**\show\relax
> \relax=\relax.
<*> \show\relax
 
? 
 
*\show\cettecommandenexistepas
> \cettecommandenexistepas=undefined.
<*> \show\cettecommandenexistepas
 
? x
No pages of output.
Transcript written on texput.log.

\ifx compare toujours les significations (« meaning ») des trucs : deux trucs sont \ifx-égaux si et seulement si il ont la même signification. La signification est à peu près ce qui est affiché par \show, sauf qu’avec \show on perd les catcodes alors que bien sûr en vrai ils comptent.

Deuxième point : quand on forme avec \csname une séquence de contrôle dont la signification était précedemment undefined, la séquence est immédiatement rendue \let-égale à \relax. La porté de cette opération est limité comme celle de toute assignation. Exemple :

\begingroup
\show\undefined     % \undefined=undefined
\csname undefined\endcsname
\show\undefined     % \undefined=\relax
\endgroup
\show\undefined     % \undefined=undefined

Application, extraite de latex.ltx (ou de source2e) :

\def\@ifundefined#1{%
  \expandafter\ifx\csname#1\endcsname\relax
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi}

Usage :

\@ifundefined{newcommand}{Pas LaTeX}{LaTeX}

Particularité : \@ifundefined{relax}{Non}{Oui} répond non. En LaTeX, on met donc dans le même sac \relax et undefined, mais c’est un choix propre à LaTeX. (Autre) inconvénient : dans le cas où on exécute la ligne ci-dessus en Plain, c’est comme si on avait aussi fait \let\newcommand\relax.

Autres tests qui ne présentent pas ces inconvénients :

\ifx\truc\undefined % par convention, on suppose que \undefined est non
% définie, mais rien ne le garantit (on utilise aussi \@undefined)
 
\ifx\truc\undefined
  non def
\else
  \ifx\truc\relax
    non def % au sens de LaTeX
  \else  
    def
  \fi
\fi

Le deuxième est vachement préférable dans un milieu plus ou moins LaTeXien, car il y a vraiment un risque que quelqu’un ait fait un \@ifundefined avant… Ces deux tests ne marchent que si on peut écrire la séquence de contrôle sans problème (pas de caractères zarbis dans le nom). Sinon, on peut utiliser :

\begingroup\expandafter\expandafter\expandafter\endgroup
\expandfater\ifx\csname nom+bien/chelou\endcsname\relax

qui a l’avantage de ne pas faire passer à \relax un truc qui était undefined, mais l’inconvénient de ne plus être développable. En TeX Knuthien, on ne peut pas faire mieux. En e-TeX, si.

On a d’abord \ifdefined\truc qui est l’exact équivalent de \ifx\truc\undefined sauf qu’on a plus besoin de supposer que \undefined est vraiment non définie. Ensuite, on a \ifcsname truc+che/lou\endcsname qui fonctionne pareil et ne présente pas l’inconvénient de rendre \truc égal à \relax s’il était précédemment non défini. Bref, le pied. (Le tout était bien sûr développable, cela va sans dire.)

Comme souvent, la solution e-TeX est la meilleure techniquement, mais elle n’etre pas très vite dans les mœurs, en particulier elle n’entrera pas dans le noyau LaTeX avant la sortie de LaTeX3 (c’est-à-dire pas tout de suite). Pour une interface LaTeXienne aux fonctionnalités d’e-TeX (et bien d’autres choses), je recommande le paquet etoolbox. Voir par exemple la section 3.5.1 de son manuel, concernant des points discutés ici.

Written by mpg

juillet 14th, 2008 at 6:47

Posted in TeX et compagnie

Tagged with ,