substitution problem with plain tex

Can anyone please tell me what I did wrong?? I cann't get the second number of tests to work correctly (and the command appears to be the same argument as done manually)

\magnification\magstep1
\hsize 5.5 true in
\hoffset 0.5 true in
\vsize 8.25 true in
\voffset = 2\baselineskip

\parskip\smallskipamount  \tolerance1000
\font\narbold=cmb10                       %% Bold non-extended
\font\titlefont=cmbx10 scaled \magstep3   %% For heading

\parindent=0pt

\centerline{\titlefont What is wrong with this implementation}
\nobreak\bigskip\hrule\bigskip

\global\newcount\containsnum%
\global\containsnum=0 % 1 they contain that number
% 0 they don't contain that number

\def\endpiece{xxx}%

%based on the following code
%TeX by Topic unknown number of arguments p105
%\White(K1a,Q2b,3c,P4d)%
\def\xContains#1,{\def\temp{#1}%
\ifx\temp\endpiece% no more to process
\else
\ifx\temp\tosearch
\global\containsnum=1%
% we no longer need the rest of the row it has been found
\else
\fi%
\expandafter\xxContains%
\fi}%

\def\Contains(#1)#2{\let\xxContains=\xContains\global\containsnum=0%\foundfalse
\def\tosearch{#2}\expandafter\xxContains#1,xxx,}%

This is a list of test for contains where the row (4,5,6,7,9,10,11) is input manually
as an argument (this works correctly)
\Contains(4,5,6,7,9,10,11){1}
1 is \ifodd\containsnum \else NOT \fi found
\Contains(4,5,6,7,9,10,11){2}
2 is \ifodd\containsnum \else NOT \fi found
\Contains(4,5,6,7,9,10,11){5}
5 is \ifodd\containsnum \else NOT \fi found
\Contains(4,5,6,7,9,10,11){11}
11 is \ifodd\containsnum \else NOT \fi found
\Contains(4,5,6,7,9,10,11){15}
15 is \ifodd\containsnum \else NOT \fi found
\def\listtypeno{1}
\expandafter\def\csname giveAttToFile\listtypeno\endcsname{4,5,6,7,9,10,11}
\def\testrow{(\expandafter\csname giveAttToFile\listtypeno\endcsname)}
This is a list of test for contains where the row is input from a command \testrow
and for some reason this doesn't work correctly?? why??
\expandafter\Contains\testrow{1}
1 is \ifodd\containsnum \else NOT \fi found
\expandafter\Contains\testrow{2}
2 is \ifodd\containsnum \else NOT \fi found
\expandafter\Contains\testrow{5}
5 is \ifodd\containsnum \else NOT \fi found
\expandafter\Contains\testrow{11}
11 is \ifodd\containsnum \else NOT \fi found
\expandafter\Contains\testrow{15}
15 is \ifodd\containsnum \else NOT \fi found

\bye

• In (\expandafter\csname the \expandafter does nothing, instead you need two expansion steps to reach the list. – egreg Mar 19 '15 at 12:54
• \testrow has the value (4,5,6,7,9,10,11) when I look at the output but the cutting in chunks for determining if the value is in it doesn't appear to happen with the second test while in the first tests by done manually it happens ok (5 and 11 are in the row while in the second test they all have NOT) – lampter Mar 19 '15 at 13:04

You have too few \expandafter tokens, but the one you have is even misplaced: with \expandafter\csname giveAttToFile\listtypeno\endcsname, \expandafter is trying to expand g.

You need two expansion steps to get from \csname ...\endcsname to the first level expansion of the built macro: one for expanding \csname, the second for expanding the macro. So you need three \expandafter's before \Contents and, of course, to exchange \expandafter and (.

\magnification\magstep1
\hsize 5.5 true in
\hoffset 0.5 true in
\vsize 8.25 true in
\voffset = 2\baselineskip

\parskip\smallskipamount  \tolerance1000
\font\narbold=cmb10                       %% Bold non-extended
\font\titlefont=cmbx10 scaled \magstep3   %% For heading

\parindent=0pt

\centerline{\titlefont What is wrong with this implementation}
\nobreak\bigskip\hrule\bigskip

\newcount\containsnum % initialized to 0

\def\endpiece{xxx}%

%based on the following code
%TeX by Topic unknown number of arguments p105
%\White(K1a,Q2b,3c,P4d)%
\def\xContains#1,{\def\temp{#1}%
\ifx\temp\endpiece% no more to process
\else
\ifx\temp\tosearch
\global\containsnum=1%
% we no longer need the rest of the row it has been found
\else
\fi%
\expandafter\xxContains%
\fi}%

\def\Contains(#1)#2{\let\xxContains=\xContains\global\containsnum=0%\foundfalse
\def\tosearch{#2}\expandafter\xxContains#1,xxx,}%

This is a list of test for contains where the row (4,5,6,7,9,10,11) is input manually
as an argument (this works correctly)

\Contains(4,5,6,7,9,10,11){1}

1 is \ifodd\containsnum \else NOT \fi found

\Contains(4,5,6,7,9,10,11){2}

2 is \ifodd\containsnum \else NOT \fi found

\Contains(4,5,6,7,9,10,11){5}

5 is \ifodd\containsnum \else NOT \fi found

\Contains(4,5,6,7,9,10,11){11}

11 is \ifodd\containsnum \else NOT \fi found

\Contains(4,5,6,7,9,10,11){15}

15 is \ifodd\containsnum \else NOT \fi found

\def\listtypeno{1}
\expandafter\def\csname giveAttToFile\listtypeno\endcsname{4,5,6,7,9,10,11}
\def\testrow{\expandafter(\csname giveAttToFile\listtypeno\endcsname)}

This is a list of test for contains where the row is input from a command {\tt\string\testrow}
and for some reason this doesn't work correctly?? why??

\expandafter\expandafter\expandafter\Contains\testrow{1}

1 is \ifodd\containsnum \else NOT \fi found

\expandafter\expandafter\expandafter\Contains\testrow{2}

2 is \ifodd\containsnum \else NOT \fi found

\expandafter\expandafter\expandafter\Contains\testrow{5}

5 is \ifodd\containsnum \else NOT \fi found

\expandafter\expandafter\expandafter\Contains\testrow{11}

11 is \ifodd\containsnum \else NOT \fi found

\expandafter\expandafter\expandafter\Contains\testrow{15}

15 is \ifodd\containsnum \else NOT \fi found

\bye


Of course I'd do it differently, using expl3 (that can be used with Plain, but requires an e-TeX engine like pdftex).

\input expl3-generic

\ExplSyntaxOn
\cs_new_protected:Npn \Contains(#1)#2#3#4
{
\lampter_contains:nnnn { #1 } { #2 } { #3 } { #4 }
}

\cs_new_protected:Npn \lampter_contains:nnnn #1 #2 #3 #4
{
\clist_if_in:nnTF { #1 } { #2 } { #3 } { #4 }
}

\cs_generate_variant:Nn \lampter_contains:nnnn { f }

\cs_new_protected:Npn \xContains#1#2#3#4
{
\lampter_contains:fnnn { #1 } { #2 } { #3 } { #4 }
}
\ExplSyntaxOff

\parindent=0pt

This is a list of test for contains where the row {\tt\string\testrow} is input manually
as an argument (this works correctly)

1 is \Contains(4,5,6,7,9,10,11){1}{}{NOT} found

2 is \Contains(4,5,6,7,9,10,11){2}{}{NOT} found

5 is \Contains(4,5,6,7,9,10,11){5}{}{NOT} found

11 is \Contains(4,5,6,7,9,10,11){11}{}{NOT} found

15 is \Contains(4,5,6,7,9,10,11){15}{}{NOT} found

\def\listtypeno{1}
\expandafter\def\csname giveAttToFile\listtypeno\endcsname{4,5,6,7,9,10,11}
\def\testrow{\csname giveAttToFile\listtypeno\endcsname}

This is a list of test for contains where the row is input from a command {\tt\string\testrow}
and it works as well

1 is \xContains\testrow{1}{}{NOT} found

2 is \xContains\testrow{2}{}{NOT} found

5 is \xContains\testrow{5}{}{NOT} found

11 is \xContains\testrow{11}{}{NOT} found

15 is \xContains\testrow{15}{}{NOT} found

\bye


Your macro seems to me overcomplicated. If you need to test the result by

\ifodd\containsnum


then you can use this:

\newcount\containsnum
\def\contains(#1)#2{\def\tmpa{#2}\containsnum=0 \containsA#1,,\relax}
\def\containsA#1,{\def\tmpb{#1}%
\ifx\tmpb\empty
\else \ifx\tmpa\tmpb \containsB \fi
\expandafter\containsA \fi
}
\def\containsB#1,\relax{\fi\fi \containsnum=1 }

\def\containsCS#1#2{\def\tmpa{#2}\containsnum=0
\expandafter\expandafter\expandafter\containsA\csname#1\endcsname,,\relax}

\contains(4,5,6,7,9,10,11){1}
1 is \ifodd\containsnum \else NOT \fi found
\contains(4,5,6,7,9,10,11){2}
2 is \ifodd\containsnum \else NOT \fi found
\contains(4,5,6,7,9,10,11){5}
5 is \ifodd\containsnum \else NOT \fi found
\contains(4,5,6,7,9,10,11){11}
11 is \ifodd\containsnum \else NOT \fi found
\contains(4,5,6,7,9,10,11){15}
15 is \ifodd\containsnum \else NOT \fi found

\def\listtypeno{1}
\expandafter\def\csname giveAttToFile\listtypeno\endcsname{4,5,6,7,9,10,11}

\containsCS{giveAttToFile\listtypeno}{1}
1 is \ifodd\containsnum \else NOT \fi found
\containsCS{giveAttToFile\listtypeno}{2}
2 is \ifodd\containsnum \else NOT \fi found
\containsCS{giveAttToFile\listtypeno}{5}
5 is \ifodd\containsnum \else NOT \fi found
\containsCS{giveAttToFile\listtypeno}{11}
11 is \ifodd\containsnum \else NOT \fi found
\containsCS{giveAttToFile\listtypeno}{15}
15 is \ifodd\containsnum \else NOT \fi found

\bye


Perhaps you intend \containsnum to count number of occurrences? if not, then it is a waste to use a \count register for that. You can use simply a macro.

It is possible to code it even more economically.

update I add support for having spaces in the comma separated values (the methods with an \ifx\temp etc... either in the OP or the other answers -- apart from the second part of egreg's answer -- did not support either the possibility of spaces before the commas, hence I didn't feel compelled to account for that possibility in my answer, but the issue arose in comments).

\long\def\ZapSpaces #1 #2{#1#2\ZapSpaces }%
% TO BE USED IN A COMPLETE EXPANSION AS \ZapSpaces foo bar<SPACE>\Gobble
\long\def\Gobble #1{}%

% this will not work with an empty (or expanding to empty) #1
% feature can be added if needed
\def\contains (#1)#2{%
\def\containsi ##1,#2,##2##3\containsi
{\ifx\relax##2\def\containsnum{0}\else\def\containsnum{1}\fi}%
\edef\containsLIST
{\expandafter\ZapSpaces\romannumeral-0#1 \Gobble }%
\expandafter\containsi\expandafter,\containsLIST,#2,\relax\containsi
}

\def\containsCS #1{\contains (\csname #1\endcsname)}

\contains (4,5,6,7,9,10,11){1}
1 is \if0\containsnum NOT \fi found
\contains (4,5,6,7,9,10,11){2}
2 is \if0\containsnum NOT \fi found
\contains (4,5,6,7,9,10,11){4}
4 is \if0\containsnum NOT \fi found
\contains (4,5,6,7,9,10,11){7}
7 is \if0\containsnum NOT \fi found
\contains (4,5,6,7,9,10,11){11}
11 is \if0\containsnum NOT \fi found
\contains (4,5,6,7,9,10,11){15}
15 is \if0\containsnum NOT \fi found

\def\mylist {  4, 5, 6, 7 , 9  , 10  , 11 }% trying out with spaces

\contains (\mylist){1}
1 is \if0\containsnum NOT \fi found
\contains (\mylist){2}
2 is \if0\containsnum NOT \fi found
\contains (\mylist){4}
4 is \if0\containsnum NOT \fi found
\tracingmacros1
\contains (\mylist){7}
\tracingmacros0
7 is \if0\containsnum NOT \fi found
\contains (\mylist){11}
11 is \if0\containsnum NOT \fi found
\contains (\mylist){15}
15 is \if0\containsnum NOT \fi found

\def\listtypeno{1}
\expandafter\def\csname giveAttToFile\listtypeno\endcsname {4,5,6,7,9,10,11}

\containsCS {giveAttToFile\listtypeno}{1}
1 is \if0\containsnum NOT \fi found
\containsCS {giveAttToFile\listtypeno}{2}
2 is \if0\containsnum NOT \fi found
\containsCS {giveAttToFile\listtypeno}{4}
4 is \if0\containsnum NOT \fi found
\containsCS {giveAttToFile\listtypeno}{7}
7 is \if0\containsnum NOT \fi found
\containsCS {giveAttToFile\listtypeno}{11}
11 is \if0\containsnum NOT \fi found
\containsCS {giveAttToFile\listtypeno}{15}
15 is \if0\containsnum NOT \fi found

\nopagenumbers
\bye


• @wipet Thanks. I will remove my erroneous comment, and then remove this one too. I had a bad feeling about what I was writing in a hurry in that comment on stackoverflow. I tested it but got fooled by the indentation box which came from inside the \vbox` and gave me the wrong impression. This contradicted my inner feelings about it but I was not careful enough. Thanks again. – user4686 Mar 19 '15 at 19:40
• \def\four{4} \def\five{5} \def\six{6} \def\seven{7} \def\nine{9} \def\ten{10} \def\eleven{11} \def\mylist{\four, \five, \six, \seven, \nine, \ten, \eleven} \expandafter\edef\csname giveAttToFile\listtypeno\endcsname{\mylist} – lampter Mar 20 '15 at 17:38
• @lampter ?????? – user4686 Mar 20 '15 at 17:47
• when the bottom is changed to that it doesn't work anymore and I cann't explain why... – lampter Mar 20 '15 at 17:47
• @lampter because of the spaces after the commas. Do you want me to change my macros to first filter out spaces? – user4686 Mar 20 '15 at 17:49