[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