# Read command with varying input arguments

Out of curiosity I'd like to define a LaTeX command that looks like:

\newcommand{\trigger}{out1,out2,...,outn}

with a rather strange function (at least, I couldn't find anything like this elsewhere):

First of all, the number of arguments out1,out2,... etc. are variables. Then, every time the \trigger command is used in the document's content, a different string is printed: first out1, then out2, etc. and finally outn. After outn is printed, the whole thing should be reset such that the next string will be out1 again.

So the first problem I have is to make a command that can read the comma separated list between {} and the second problem is how to print just one them every time the newly defined command is called.

-

Nothing wrong with the earlier answers, but here's another one

\documentclass{article}

\newcommand{\triggerlist}{out1,out2,...,outn}
\def\trigger{\expandafter\xtrigger\triggerlist\xtrigger}
\def\xtrigger#1,#2\xtrigger{#1\def\triggerlist{#2,#1}}

\begin{document}

\trigger

\trigger

\trigger

\trigger

\trigger

\trigger

\trigger

\trigger

\end{document}

-
Such an elegant solution, thanks! – Frits Mar 20 '12 at 5:53

It's quite easy with expl3:

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\newsetcommand}{mm}
{
\seq_new:c { g_setcommand_ \cs_to_str:N #1 _seq }
\seq_gset_split:cnn { g_setcommand_ \cs_to_str:N #1 _seq } {,} {#2}
\cs_new:Npn #1
{
\seq_gpop_left:cN { g_setcommand_ \cs_to_str:N #1 _seq } \l_setcommand_temp_tl
\seq_gput_right:cV { g_setcommand_ \cs_to_str:N #1 _seq } \l_setcommand_temp_tl
\tl_use:N \l_setcommand_temp_tl
}
}
\tl_new:N \l_setcommand_temp_tl
\cs_generate_variant:Nn \seq_gset_split:Nnn { c }
\ExplSyntaxOff

\newsetcommand{\trigger}{out1,out2,out3,out4}

\begin{document}

\trigger

\trigger

\trigger

\trigger

\trigger

\end{document}


You see that \newsetcommand defines a new macro that expands to the successive elements of the list and as many commands of the same type can be defined.

Here's the output:

## How it works

\newsetcommand{\trigger}{<list>} defines

1. A new sequence called \g_setcommand_trigger_seq, containing the ordered list got from the comma separated <list>

2. A new macro \trigger that at each call pops the leftmost element from the associated sequence, adds it on the right of the sequence and prints it.

Since the popped element is added back at the other end of the sequence, when the last original element is printed, the next will be again the first.

## "Classical" implementation

\makeatletter
\newcommand{\newsetcommand}[2]{%
\toks@{}%
\@for\next:=#2\do{%
\toks@=\expandafter{\the\expandafter\toks@\expandafter{\next}}%
}
\expandafter\gdef\csname setcommand\string#1\expandafter\endcsname\expandafter{\the\toks@}%
\edef#1{\noexpand\@usecommand{\string#1}}%
}
\def\@usecommand#1{%
\expandafter\expandafter\expandafter\@@usecommand\csname setcommand#1\endcsname\@nil{#1}\@nil}
\def\@@usecommand#1#2\@nil#3\@nil{%
#1%
\expandafter\gdef\csname setcommand#3\endcsname{#2{#1}}%
}
\makeatother


The syntax is the same as before.

EDIT

Thanks to David Carlisle's answer, this can be simplified:

\makeatletter
\newcommand{\newsetcommand}[2]{%
\global\@namedef{@setcommand\string#1}{#2}%
\edef#1{\noexpand\@usecommand{\string#1}}%
}
\def\@usecommand#1{%
\expandafter\expandafter\expandafter\@@usecommand\csname @setcommand#1\endcsname\@nil#1\@nil
}
\def\@@usecommand#1,#2\@nil#3\@nil{%
\global\@namedef{@setcommand#3}{#2,#1}%
}
\makeatother

-
Thanks for the fast answer. However, it doesn't work. What is printed is ',out1,out2,out3,out4' (all on the same line). Also, I edited my original question a little: I'd like to reset the loop after the last string is printed, such that a fifth \trigger would produce 'out1' again. – Frits Mar 19 '12 at 22:24
I changed the implementation to fulfill your request. You perhaps have an outdated version of the expl3 packages. I may try a "classical" implementation, but this one is surely more efficient. – egreg Mar 19 '12 at 22:40
Thanks! It was indeed an outdated version I had. Next thing to do is taking a good look at expl3, as its possibilities look very promising! – Frits Mar 20 '12 at 5:52

My humble attempt with etoolbox, thanks to one of Leo Liu's answers. I used \csdef and \csuse to store and use the values, and \DeclareListParser to iterate through the items in the comma-separated list. Finally, the modulo feature is provided by the intcalc package.

\documentclass{article}

\usepackage{etoolbox}
\usepackage{intcalc}

\DeclareListParser*{\myforeach}{,}

\newcounter{helpercounter}
\newcommand{\savethistext}[1]{%
\stepcounter{helpercounter}%
\csdef{triggerval\thehelpercounter}{#1}}

\newcounter{progresscounter}
\newcommand{\trigger}[1]{%
\setcounter{progresscounter}{\intcalcMod{\value{progresscounter} + 1}{\value{helpercounter} + 1}}%
\csuse{triggerval\theprogresscounter}\par%
}

\myforeach{\savethistext}{out1, out2, out3, out4}

\begin{document}

\trigger

\trigger

\trigger

\trigger

\trigger

\trigger

\trigger

\trigger

\trigger

\trigger

\end{document}


-

Here is an implementation using high-level ConTeXt features: counters and conversion.

\defineconversion[trigger][out1, out2, out3, out4]
\definestructurecounter[trigger][numberconversion=trigger]
\setstructurecounter[trigger]{0}

\def\trigger%
{\incrementstructurecounter[trigger]%
\convertedstructurecounter[trigger]}

\starttext
\startlines
\trigger
\trigger
\trigger
\trigger
\trigger
\stoplines
\stoptext

-
ConTeXt seems to make complicated things look so easy. :) – Paulo Cereda Mar 21 '12 at 11:29
@PauloCereda: The reason is that the internal code is modular. For example, this feature is needed when you use symbols to denote footnotes (\star, \daggar, \ddaggar, etc). Both LaTeX and ConTeXt have internal mechanisms for that; the difference is that in LaTeX it is hidden from the user, while ConTeXt provides a user API for it. – Aditya Mar 21 '12 at 14:24
Ah I see. Providing a consistent user API is really a great approach, so the internal structures can be easily modified in a higher level. Now I'm more tempted to try ConTeXt. :) – Paulo Cereda Mar 21 '12 at 14:31