Mime-Version: |
1.0 |
Content-Type: |
text/plain; charset=iso-8859-1 |
Date: |
Sun, 26 Apr 2009 12:22:31 +0200 |
Content-Disposition: |
inline |
Reply-To: |
|
Subject: |
|
From: |
|
In-Reply-To: |
|
Content-Transfer-Encoding: |
8bit |
Sender: |
|
Parts/Attachments: |
|
|
On Sun, Apr 26, 2009 at 08:27:38AM +0200, Uwe Lück wrote:
> The difference in safety is that other proposals can be fooled by \in@ or
> \in@@ in \in@ arguments. The "safe" proposal still can be fooled by \@nil
> or so in \in@ arguments.
This can be fixed without a new command token:
> Right, on the other hand \in@{a}{a#} and \in@{b}{a#} work with the
> expandable tests only.
This can be fixed using token registers, see below.
`#' cannot be used in the first substring argument, because
it cannot be used as ordinary delimiter in the parameter text of a
definition (except as last token, but this doesn't help here).
Then `#' should be a better token than \@nil or \[log in to unmask]
==> \in@@#2###1\in@\in@@
> 1. LaTeX-so-far,
We are currently discussing the bugs of this version.
> 2.changing it by just inserting a separator in the last
> line according to Morten:
>
> \def\in@#1#2{%
> \def\in@@##1#1##2##3\in@@{%
> \ifx\in@##2\in@false\else\in@true\fi}%
> \in@@#2\@nil#1\in@\in@@}
It can be broken like the original macro by
\in@{}{}
Then the call of \in@@ is one argument too short.
This can be fixed by preceding the string by a token.
==> \in@@###2###1\in@\in@@
> (where I proposed to use \@in@ in place of \@nil), and
(or `#', see above.)
> 3. mine (expandable
> test without \in@). (Attached is a file with testing tools for the four
> versions.)
The expandable tests can be broken by conditionals, e.g.:
\in@{a}{a{\fi\fi}}
> In favour of Morten's: it is the least change (compatibility).
Then I would prefer the following modification:
% Version M:
\def\in@#1#2{%
\def\in@@##1#1##2##3\in@@{%
\ifx\in@##2\relax % \relax added for the case that ##2 is empty
\in@false
\else
\in@true
\fi
}%
\in@@###2###1\in@\in@@
}
I think, a little more robust is, but longer is:
% Version H:
\def\in@#1#2{%
\def\in@@{#1}%
\ifx\in@@\@empty
\in@true
\expandafter\@gobble
\else
\expandafter\@firstofone
\fi
{%
\def\in@@##1#1##2\in@@{%
\begingroup
\toks@{##2}%
\edef\in@@{\the\toks@}%
\expandafter\endgroup
\ifx\in@@\@empty
\in@false
\else
\in@true
\fi
}%
\in@@#2###1\in@@
}%
}
There are some cases to discuss, if the first argument is empty.
The kernel version behaves the following way:
\in@{}{} breaks
and
\in@{}{a} -> false
\in@{}{ab} -> true
is inconsistent.
I would like a more standardized behaviour (e.g. Perl's `index' function
for substring searching): If the first argument is empty, then the
result is always true:
\in@{}{} -> true
\in@{}{a} -> true
\in@{}{ab} -> true
Both versions M and H behave in this way.
Test file:
\catcode`\@=11 %
\def\@empty{}% (for testing with plain-TeX)
\long\def\@gobble#1{}
\long\def\@firstofone#1{#1}
\def\kernel@in@#1#2{%
\def\in@@##1#1##2##3\in@@{%
\ifx\in@##2%
\in@false
\else
\in@true
\fi
}%
\in@@#2#1\in@\in@@
}
%%% Variant M begin %%%
\def\M@in@#1#2{%
\def\in@@##1#1##2##3\in@@{%
\ifx\in@##2\relax
\in@false
\else
\in@true
\fi
}%
\in@@###2###1\in@\in@@
}
%%% Variant M end %%%
%%% Variant H begin %%%
\def\H@in@#1#2{%
\def\in@@{#1}%
\ifx\in@@\@empty
\in@true
\expandafter\@gobble
\else
\expandafter\@firstofone
\fi
{%
\def\in@@##1#1##2\in@@{%
\begingroup
\toks@{##2}%
\edef\in@@{\the\toks@}%
\expandafter\endgroup
\ifx\in@@\@empty
\in@false
\else
\in@true
\fi
}%
\in@@#2###1\in@@
}%
}
%%% Variant H end %%%
\expandafter\ifx\csname ifin@\endcsname\relax
\expandafter\newif\csname ifin@\endcsname
\fi
\def\msg#{\immediate\write16}
\def\@test#1#2#3#4{%
#4{#1}{#2}%
\edef\@result{%
\ifin@ yes\else no\fi
}%
\def\@expected{#3}%
\toks@={{#1}{#2}}%
\msg{%
[\string#4\the\toks@\space = \@result\space] => %
\ifx\@result\@expected OK.\else FAILED!\fi
}%
}
\def\test#1#2#3{%
\@test{#1}{#2}{#3}\in@
}
\msg{}
\msg{* Inconsistent behaviour of the kernel}
\@test{}{a}{yes}\kernel@in@
\@test{}{ab}{yes}\kernel@in@
\@test{a}{}{no}\kernel@in@
\@test{\iftrue}{\iftrue}{yes}\kernel@in@
\@test{\iffalse}{\iffalse}{yes}\kernel@in@
\@test{\iftrue}{\iffalse}{no}\kernel@in@
% \let\M@in@
\let\in@\H@in@
\msg{}
\msg{* Tests for fixed version of \string\in@}
\test{}{a}{yes}
\test{}{}{yes}
\test{a}{}{no}
\test{a}{{}}{no}
\test{a}{a{}}{yes}
\test{a}{{}a}{yes}
\test{a}{b{}}{no}
\test{a}{{}b}{no}
\test{bon}{#bon}{yes}
\expandafter\test\expandafter{\string#bon}{#bon}{no}
\test{bon\@in}{bon}{no}
\test{bon\@in}{bon\@in}{yes}
\test{\@in}{\@in}{yes}
\test{\@in bon}{\@in\@in bon}{yes}
\test{\iftrue}{\iftrue}{yes}
\test{\iftrue}{\iffalse}{no}
\test{\iffalse}{\iftrue}{no}
\test{\iffalse}{\iffalse}{yes}
\test{\else}{\else}{yes}
\test{\else}{\fi}{no}
\test{\fi}{\else}{no}
\test{\fi}{\fi}{yes}
\test{a}{a{\fi\fi}}{yes}
\test{bonbon}{bon}{no}
\test{bon}{bonbon}{yes}
\test{bona}{bon}{no}
\test{bon}{bona}{yes}
\test{ionization}{ionizat}{no}
\test{client-to-client}{client-to-}{no}
\csname @@end\endcsname\end
Yours sincerely
Heiko <[log in to unmask]>
|
|
|