( In my previous posting I overlooked that brace-checking might be needed,
so I superseded with this one. )
Jeffrey Goldberg wrote:
> Well that sucks. Basically it means that I need to, in effect, create something
> that checks to see if \eTeXversion is defined without using \ifdefined.
> And then,
> presumably, define an equivalent to \ifdefine if needed.
The problem is: \ifdefined can be applied to any token,
even to an \outer-token or to a single catcode-1-character-token
like an opening brace or to a single catcode-2-token like a
closing brace.
So you cannot define an equivalent to \ifdefined by means of
processing macro arguments as macro arguments cannot
contain \outer-tokens or single unbalanced brace-tokens.
If you don't mind about affecting the hash-table, and if testing is
only about control-sequence-tokens, not also character-tokens,
you can have the token in question constructed in terms of
\csname..\endcsname in order to see whether the meaning
of the token in question equals \relax.
When you can rely on some really bizarre Token not being defined,
e.g. \UnDeFINedAndBIzaRREe , you can do something like
\ifx\UnDeFINedAndBIzaRREe<Token to test> .. \else .. \fi
If you don't like at all to rely on some bizarre token being undefined,
and if you don't care about \outer-token or single unbalanced braces
and the like, you can apply \meaning to the token in question
and check whether the result starts with the
catcode-12-character-token-sequence "undefined".
That won't affect the hash table with each test that is to be carried
out, which is nice when such testing is done very often.
(Nonetheless doing the thing below instead of relying on a really
bizarre token not being defined seems like overkill to me...)
%%-----------------------------------------------------------------------------
%% Paraphernalia:
%%.............................................................................
\long\def\firstoftwo#1#2{#1}%
\long\def\secondoftwo#1#2{#2}%
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \CheckWhetherNull{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that
%% argument which is to be checked is empty>}%
%% {<Tokens to be delivered in case that
%% argument which is to be checked is not empty>}%
%% ( Test is based on Robert R Schneck's \ifempty-macro.
%% Newsgroup: comp.text.tex
%% Subject: Macro puzzle: maximally general \ifempty
%% Google-Groups-URL:
%%
https://groups.google.com/forum/#!topic/comp.text.tex/kuOEIQIrElc )
\long\def\CheckWhetherNull#1{%
\expandafter\secondoftwo\string{\expandafter\secondoftwo
\expandafter{\expandafter{\string#1}\expandafter\secondoftwo
\string}\expandafter\firstoftwo\expandafter{\expandafter
\firstoftwo\expandafter\secondoftwo\expandafter}\string
}\firstoftwo
}
%%---------------------------------------------------------------
%% Check whether brace-balanced argument starts with a
%% catcode-1-character-token, e.g., an opening brace:
%%...............................................................
\long\def\CheckWhetherLeadingBrace#1{%
\expandafter\secondoftwo\expandafter{\expandafter{\string#1.%
}\expandafter\firstoftwo\expandafter{\expandafter\firstoftwo
\expandafter\firstoftwo\expandafter}\string}\secondoftwo
}
%%---------------------------------------------------------------
%% Check whether macro argument has an undefined token as
%% it's first token:
%%...............................................................
\begingroup
\long\def\CheckWhetherArgumentHasAFirstTokenThatIsUndefined#1{%
\endgroup
\long\def\CheckWhetherArgumentHasAFirstTokenThatIsUndefined##1{%
\CheckWhetherLeadingBrace{##1}{\secondoftwo}{%
\expandafter\secondoftwo
\string{\expandafter\CheckWhetherArgumentHasAFirstTokenThatIsUndefinedB
\meaning##1.#1}{}%
}%
}%
\long\def\CheckWhetherArgumentHasAFirstTokenThatIsUndefinedB##1#1{%
\CheckWhetherNull{##1}%
{\expandafter\expandafter\expandafter\firstoftwo}%
{\expandafter\expandafter\expandafter\secondoftwo}%
\expandafter\secondoftwo\expandafter{\string}%
}%
}%
\begingroup
\edef\CheckWhetherArgumentHasAFirstTokenThatIsUndefined{%
\endgroup
\noexpand\CheckWhetherArgumentHasAFirstTokenThatIsUndefined{%
\string u\string n\string d\string e\string f%
\string i\string n\string e\string d%
}%
}%
\CheckWhetherArgumentHasAFirstTokenThatIsUndefined
\long\def\ArgumentHasAFirstTokenThatIsUndefined#1{%
0\CheckWhetherArgumentHasAFirstTokenThatIsUndefined{#1}{0}{1}%
}%
\tt
Using \string\CheckWhetherArgumentHasAFirstTokenThatIsUndefined
\medskip
a\ $\to$
\CheckWhetherArgumentHasAFirstTokenThatIsUndefined{a}{true}{false}
\string\TeX\ $\to$
\CheckWhetherArgumentHasAFirstTokenThatIsUndefined{\TeX}{true}{false}
\string\uNdEfInED\ $\to$
\CheckWhetherArgumentHasAFirstTokenThatIsUndefined{\uNdEfInED}{true}{false}
\medskip
\string a\string\biZarre\string\fi\ $\to$
\CheckWhetherArgumentHasAFirstTokenThatIsUndefined{a\biZarre\fi}{true}{false}
\string\TeX\string\biZarre\string\fi\ $\to$
\CheckWhetherArgumentHasAFirstTokenThatIsUndefined{\TeX\biZarre\fi}{true}{false}
\string\uNdEfInED\string\biZarre\string\fi\ $\to$
\CheckWhetherArgumentHasAFirstTokenThatIsUndefined{\uNdEfInED\biZarre\fi}{true}{false}
\medskip
\string{in braces\string} $\to$
\CheckWhetherArgumentHasAFirstTokenThatIsUndefined{{in braces}}{true}{false}
\medskip
<emptiness> $\to$
\CheckWhetherArgumentHasAFirstTokenThatIsUndefined{}{true}{false}
\bigskip
Using \string\if\string\ArgumentHasAFirstTokenThatIsUndefined
\medskip
\string a\ $\to$
\if\ArgumentHasAFirstTokenThatIsUndefined{a}true\else false\fi
\string\TeX\ $\to$
\if\ArgumentHasAFirstTokenThatIsUndefined{\TeX}true\else false\fi
\string\uNdEfInED\ $\to$
\if\ArgumentHasAFirstTokenThatIsUndefined{\uNdEfInED}true\else false\fi
\medskip
\string a\string\biZarre\string\fi\ $\to$
\if\ArgumentHasAFirstTokenThatIsUndefined{a\biZarre\fi}true\else false\fi
\string\TeX\string\biZarre\string\fi\ $\to$
\if\ArgumentHasAFirstTokenThatIsUndefined{\TeX\biZarre\fi}true\else false\fi
\string\uNdEfInED\string\biZarre\string\fi\ $\to$
\if\ArgumentHasAFirstTokenThatIsUndefined{\uNdEfInED\biZarre\fi}true\else false\fi
\medskip
\string{in braces\string} $\to$
\if\ArgumentHasAFirstTokenThatIsUndefined{{in braces}}true\else false\fi
\medskip
<emptiness> $\to$
\if\ArgumentHasAFirstTokenThatIsUndefined{}true\else false\fi
% \ifdefined a defined \else undefined\fi
% \ifdefined \TeX defined \else undefined\fi
% \ifdefined \uNdEfInED defined \else undefined\fi
\bye
The code above looks rather cumbersome and long.
I'd prefer \ifx-checking with some bizarre control sequence token that
can be assumed to be undefined.
Only plain TeX is used.
Any \if .. \else ..\fi is avoided.
\CheckWhetherArgumentHasAFirstTokenThatIsUndefined also deals the cases
of the argument being empty / consisting of several tokens.
Carrying out \CheckWhetherArgumentHasAFirstTokenThatIsUndefined won't
affect the hash-table.
\CheckWhetherArgumentHasAFirstTokenThatIsUndefined can also be carried
out in expansion-contexts, e.g. inside \csname..\endcsname, e.g., within \edef,
e.g., when \romannumeral-expansion takes place.
Ulrich