[XeTeX] newcommand with optional arguments

Bruno Voisin bvoisin at mac.com
Tue Mar 4 11:37:08 CET 2008


Le 4 mars 08 à 08:58, Morten Høgholm a écrit :

> *The* bulletproof (and purely expandable) method of testing whether an
> argument is empty is this:
>
> \long\def\tlist at if@empty at nTF #1{%
> \expandafter\ifx\expandafter\\\detokenize{#1}\\%
>   \expandafter\@firstoftwo
> \else
>   \expandafter\@secondoftwo
> \fi
> }
>
> See l3tlp.dtx for details. It also contains a bullet-proof test for
> testing if an argument is blank.


Given finding out the meaning of l3tlp.dtx took me some time, here's  
for other interested people to use:

- <ftp://ftp.cam.ctan.org/macros/latex/exptl/project/expl3.zip>

- Unzip, run LaTeX on l3.ins then on l3tlp.dtx.

But still, that doesn't help a mere mortal at understanding how the  
above works. The closest to this code in the commented code inside  
l3tlp.dtx is:

% \begin{macro}{\tlist_if_empty_p:n}
%   It would be tempting to just use "\if_meaning:NN\q_nil#1\q_nil" as
%   a test since this works really well. However it fails on a token
%   list starting with "\q_nil" of course but more troubling is the
%   case where argument is a complete conditional such as "\if_true:"
%   a "\else:" b "\fi:" because then "\if_true:" is used by
%   "\if_meaning:NN", the test turns out false, the "\else:" executes
%   the false branch, the "\fi:" ends it and the "\q_nil" at the end
%   starts executing\dots{} A safer route is to convert the entire
%   token list into harmless characters first and then compare
%   that. This way the test will even accept "\q_nil" as the first
%   token.
%    \begin{macrocode}
\def_long_new:Npn \tlist_if_empty_p:n #1{
  \exp_after:NN\if_meaning:NN\exp_after:NN\q_nil 
\tlist_to_str:n{#1}\q_nil
    \c_true
  \else:
    \c_false
  \fi:
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\tlist_if_empty_p:o}
% \begin{macro}{\tlist_if_empty:nTF}
% \begin{macro}{\tlist_if_empty:nT}
% \begin{macro}{\tlist_if_empty:nF}
% \begin{macro}{\tlist_if_empty:oTF}
% \begin{macro}{\tlist_if_empty:oT}
% \begin{macro}{\tlist_if_empty:oF}
%    \begin{macrocode}
\def_new:Npn \tlist_if_empty_p:o {\exp_args:No\tlist_if_empty_p:n}
\def_long_test_function_new:npn{tlist_if_empty:n}#1{
  \if:w\tlist_if_empty_p:n{#1}}
\def_long_test_function_new:npn{tlist_if_empty:o}#1{
  \if:w\tlist_if_empty_p:o{#1}}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}

Even after reading this several times, and trying to figure out how  
the LaTeX 3 experimental code converts to LaTeX 2e, I still don't get  
it: why all these \expandafter, what \\ (which in LaTeX means carriage  
return I think and in plain TeX can mean anything) is doing here  
(twice), and why a \long definition (in plain TeX a long def is one  
that includes carriage returns as part of its definition if I'm not  
mistaken, or one whose argument can include a carriage return, I'm not  
sure).

I'm also surprised at seeing

\expandafter\ifx\expandafter\\\detokenize{#1}\\

I thought in such situations a cascade of \expandafter was needed, like

\expandafter\expandafter\expandafter\ifx\expandafter\\\detokenize{#1}\\

to get \detokenize{#1} expanded first, then \\, then \ifx.

But I must confess I never really got the hang of this \expandafter  
stuff, even after reading Appendix D of the TeXBook several times.

If higher-level abstractions allowing that type of construction aren't  
provided to the user, I doubt the above will ever be used.

Bruno


More information about the XeTeX mailing list