10

I would like to define kind of an own index, that collects certain information and one counter value - in the following small example the \addstuff-command that may get the value of a counter as its first argument and a description as its second. The first entry might also be text itself or even empty.

I want to collect all these value-text entries and create an output at the end. In the following example the description always reflects, what i want the counter value to be in that entry.

\documentclass[a4paper]{scrartcl}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}

\newcommand{\collect}{}

\newcounter{mycounter}\setcounter{mycounter}{1}

\makeatletter
\newcommand{\addstuff}[2]{\g@addto@macro\collect{#1 & #2\\}}
\makeatother
\newcommand{\generateOutput}{%
    Output of collection\par%
    \begin{tabular}{rl}\collect\end{tabular}%
}

\begin{document}
    \addstuff{normal}{Entry}
    \addstuff{\themycounter}{save the 1 it should have here}
    \refstepcounter{mycounter} %incement -> 2

    \addstuff{\arabic{mycounter}}{<-save the 2 of the counter}
    \refstepcounter{mycounter} %incement -> 3

    % Print all saved data
    \generateOutput
\end{document}

So my question is, how can i evaluate the first parameter to obtain the actual value of the counter at the moment, \addstuff is called? Because in this code, both lines that i save in my collection end up having the value 3 instead of 1 or 2 respectively.

lockstep
  • 250,273
Ronny
  • 6,110
  • You need to evaluate the first argument at the time you add it to the macro, not add the code directly. Have a look at \eappto from the etoolbox package. I will post an answer in a while if no one else posted one. – Martin Scharrer Jan 04 '12 at 09:23
  • @Martin: Maybe you can extend your answer by the approaches with edef or with newtoks. – Marco Daniel Jan 04 '12 at 09:48
  • @MarcoDaniel: I was planning to give other people a chance to post their answers. That wasn't meant as a "I'm currently writing my answer" note. – Martin Scharrer Jan 04 '12 at 09:55
  • @Martin Though there are answers using edef and newtoks i would also be interested in a version using the etoolbox, just because I tried your ideas and didn't have any success in using \eappto. – Ronny Jan 05 '12 at 07:30

2 Answers2

12

A problem with complete expansion in LaTeX is that some commands are "dangerous"; so a two pass approach is needed. In your \addstuff command you want that the first argument is expanded to the maximum possible and the second argument is taken "as is".

\makeatletter
\newcommand{\addstuff}[2]{%
  \protected@edef\@tempa{#1}%
  \expandafter\g@addto@macro\expandafter\collect\expandafter{%
    \@tempa & #2 \\}}
\makeatother

It would be more complicated if the argument to expand wasn't the first. A different approach might be

\makeatletter
\newcommand{\addstuff}[2]{%
  \protected@edef\@tempa{#1 & \unexpanded{#2} \noexpand\\}
  \expandafter\g@addto@macro\expandafter\collect\expandafter{\@tempa}}
\makeatother

where it's clearer what gets expanded and what doesn't.

If there's more control on what is allowed in the first argument, that is, nothing that could need "protection", one can do it in one step:

\makeatletter
\newcommand{\addstuff}[2]{%
  \begingroup\edef\x{\endgroup
    \noexpand\g@addto@macro\noexpand\collect
      {#1 & \unexpanded{#2} \noexpand\\}}\x}
\makeatother

But with this definition, something as seemingly innocent as \addstuff{\bfseries special}{stuff} would fail miserably.

egreg
  • 1,121,712
  • I like the second solution, can you explain why that works if i use \themycounter or \arabic{mycounter} but not if i use \value{mycounter} as first parameter? – Ronny Jan 04 '12 at 10:46
  • 1
    \themycounter or \arabic{mycounter} are representations of the counter's value; think to \value{mycounter} as the abstract number. – egreg Jan 04 '12 at 10:52
  • Could you explain what exactly is expanded after {\@tempa} in \expandafter\g@addto@macro\expandafter\collect\expandafter{\@tempa}? – cfr Oct 07 '16 at 01:44
  • 1
    @cfr What gets expanded is \@tempa, because \expandafter jumps over the brace. – egreg Oct 07 '16 at 08:11
  • Ah, thank you. So it is the {} which are expanded after the \@tempa. I must be very dumb because I really find expansion difficult to understand :(. – cfr Oct 07 '16 at 14:52
  • @cfr { is never expanded. You're looking at this from the wrong perspective. Let's assume \@tempa expands to x; then when the code is processed, the first \expandafter expands the second which expands the third which expands \@tempa (each \expandafter triggers expansion of the token after the one that follows it, then disappears). So, after the first \expandafter disappears (with the effects described above) the input stream contains \g@addto@macro\collect{x} – egreg Oct 07 '16 at 14:56
  • So nothing is expanded after at all? – cfr Oct 07 '16 at 16:01
  • @cfr Uh? The action of \expandafter is: “Dear TeX, before examining the next token, please expand the token after it”. – egreg Oct 07 '16 at 17:39
  • Yes, but that's not how I always read it. I read it as 'Dear TeX, before expanding the next token, please expand the one after it'. Probably that's dumb, but that's me. – cfr Oct 07 '16 at 21:17
2

use a token register, makes live easier.

\documentclass[a4paper]{scrartcl}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\newtoks\tabtoks
\newcommand\addstuff[2]{%
  \begingroup\edef\x{\endgroup
    \noexpand\tabtoks{\the\tabtoks
      #1 & \noexpand#2 \noexpand\\}}\x}
\newcommand*\resettabtoks{\tabtoks{}}

\newcounter{mycounter}
\setcounter{mycounter}{1}

\newcommand\generateOutput{%
  Output of collection\par%
  \begin{tabular}{ll}\the\tabtoks\end{tabular}}

\begin{document}
\resettabtoks
\addstuff{normal}{Entry}
\addstuff{\themycounter}{save the 1 it should have here}
\refstepcounter{mycounter} %incement -> 2

\addstuff{\themycounter}{<-save the 2 of the counter}
\refstepcounter{mycounter} %incement -> 3

\addstuff{\noexpand\bfseries foo}{a test}
\addstuff{\themycounter}{is three}

\generateOutput
\end{document}
  • Shouldn't it be \unexpanded{#2} instead of \noexpand#2? Without \unexpanded one has to do it in two steps. – egreg Jan 04 '12 at 10:48
  • So i gave both attempts a try. Your attempt has one disadvantage, the other one (from egreg) does not have: If you define a new environment and call \addstuff from inside the first block, i.e. the code executed before the environment, your solution does somehow calls \adstuff (even running through it - i checked with some ouptut inside that command) without adding something to the token register. I used \newenvironmentx from xargs to define the environment. – Ronny Jan 04 '12 at 14:08