34

I would like to create new command with functionality like this (pseudo code):

\newcommand{\myCommand}[numOfParameters]  { 
  for (i = 0; i < numOfParameters / 3; i++) {
     \somecommand1{#(i*3 + 1)}
     \somecommand1{#(i*3 + 2)}
     \somecommand1{#(i*3 + 3)}
  }
}

Is it possible to implement such like this in LaTeX ?

Here is example of usage (by request):

Here is a macros to show 2 images per row ...

\newcommand{\twoimages}[6] {
    \begin{figure}[htb!]
        \begin{minipage}[h]{0.49\linewidth}
            \begin{center}
                \includegraphics[width=#3\linewidth]{#1} \\ 
                \caption{#2} 
                \label{ris:#1}
            \end{center}
        \end{minipage}
        \hfill
        \begin{minipage}[h]{0.49\linewidth}
            \begin{center}
                \includegraphics[width=#6\linewidth]{#4} \\ 
                \caption{#5}
                \label{ris:#4}
            \end{center}
        \end{minipage}
    \end{figure}
}

I'd like to make macros for N (user-defined number) images

2
  • 1
    A command with a variable number of arguments is not possible as-is. LaTeX usually employs comma-separated lists for this kind of thing. See “For loop” in newcommand. But you also can make a command with one argument which gets an arbitrarily long list of macro calls like this: \images{\image{foo}{bar}{.4}\image{baz}{quux}{.5}...}. Sep 17, 2012 at 14:38
  • According to the first part of the question you could just map an amount of numOfParameters arguments to \somecommand1. Am I right when I suppose that it should not be \somecommand1 three times but \somecommand1, \somecommand2 and \somecommand3? Jul 16, 2021 at 15:05

3 Answers 3

38

You can define recursive macros that call themselves until some termination is found; a solution to your problem can be as follows:

\makeatletter % we need to use kernel commands
\newcommand{\twoimages}{%
  \begin{figure}[!htb]
  \@twoimagesi
}
\newcommand\@twoimagesi{\@ifnextchar\stopimages{\@twoimagesend}{\@twoimagesii}}

\newcommand\@twoimagesii[6]{%
  \@twoimagesiii{#1}{#2}{#3}\hfill
  \@twoimagesiii{#4}{#5}{#6}\\[\bigskipamount]
  \@twoimagesi % restart the recursion
}
\newcommand\@twoimagesiii[3]{%
  \begin{minipage}{0.49\linewidth}
    \centering
    \includegraphics[width=#3\linewidth]{#1}
    \caption{#2}\label{ris:#1}
  \end{minipage}}
\newcommand\@twoimagesend[1]{% The argument is \stopimages
  \vspace*{-\bigskipamount}
  \end{figure}}
\makeatother

The macro \twoimages really has no argument; it simply starts the business by opening the figure environment and calls the real command, \@twoimagesi. This command checks whether it's followed by \stopimages; if it is, it calls \@twoimagesend that ends the environment; otherwise it executes \@twoimagesii that has the job of printing a row, after having absorbed its six arguments. It does so in an indirect way, so that we can write only once the same minipage, using the first three arguments and the last three.

Then \@twoimagesii restarts the recursion by calling \@twoimagesi again.


Let's see a complete example (I use the demo option to graphicx that draws a black blob instead of requiring external files).

\documentclass{article}
\usepackage[demo]{graphicx}

\makeatletter % we need to use kernel commands
\newcommand{\twoimages}{%
  \begin{figure}[!htb]
  \@twoimagesi
}
\newcommand\@twoimagesi{\@ifnextchar\stopimages{\@twoimagesend}{\@twoimagesii}}

\newcommand\@twoimagesii[6]{%
  \@twoimagesiii{#1}{#2}{#3}\hfill
  \@twoimagesiii{#4}{#5}{#6}\\[\bigskipamount]
  \@twoimagesi % restart the recursion
}
\newcommand\@twoimagesiii[3]{%
  \begin{minipage}{0.49\linewidth}
    \centering
    \includegraphics[width=#3\linewidth]{#1}
    \caption{#2}\label{ris:#1}
  \end{minipage}}
\newcommand\@twoimagesend[1]{% The argument is \stopimages
  \vspace*{-\bigskipamount}
  \end{figure}}
\makeatother

\begin{document}
\twoimages
  {a}{Caption left}{.5}
  {b}{Caption right}{.5}
  {c}{Caption left}{.5}
  {d}{Caption right}{.5}
\stopimages
\end{document}

enter image description here


A quite different approach is via the expl3 macros. Also the syntax will be different; I'll present the example, which is almost self-explanatory: the main macro splits its argument at the commas and each chunk is processed in a very similar way as before.

\documentclass{article}
\usepackage[demo]{graphicx}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\twoimages}{ >{ \SplitList {,} } m }
 {
  \begin{figure}[!htb]
  \centering
  \ProcessList { #1 } { \davs__twoimages_row:n }
  \vspace{-\bigskipamount}
  \end{figure}
 }
\cs_new_protected:Nn \davs__twoimages_row:n
 {
  \davs__twoimages_row:nnnnnn #1
 }
\cs_new_protected:Nn \davs__twoimages_row:nnnnnn
 {
  \davs__twoimages_do:nnn { #1 } { #2 } { #3 } 
  \hfill
  \davs__twoimages_do:nnn { #4 } { #5 } { #6 }
  \\[\bigskipamount]
 }
\cs_new_protected:Nn \davs__twoimages_do:nnn
 {
  \begin{minipage}{0.49\linewidth}
    \centering
    \includegraphics[width=#3\linewidth]{#1}
    \caption{#2}\label{ris:#1}
  \end{minipage}
 }
\ExplSyntaxOff
\begin{document}

\twoimages{
  {a}{Caption left}{.5}
  {b}{Caption right}{.5},
  {c}{Caption left}{.5}
  {d}{Caption right}{.5}
}

\end{document}

The result is exactly the same as before. There can be any number of sixtuples of arguments, separated by a comma.


Just for completeness, a version that accepts any number of images; now each triple should be separated by a comma; if the number of images is odd, the last one will be centered.

\documentclass{article}
\usepackage[demo]{graphicx}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\twoimages}{ >{ \SplitList {,} } m }
 {
  \begin{figure}[!htb]
  \centering
  \leftskip=\fill \rightskip=\fill
  \lineskip=\baselineskip % to compensate for the minipages
  \ProcessList { #1 } { \__davs_process_argument:n }
  \end{figure}
 }
\cs_new_protected:Nn \__davs_process_argument:n
 {
  \__davs_image:nnn #1
 }
\cs_new_protected:Nn \__davs_image:nnn
 {
  \hspace*{\fill}
  \begin{minipage}{0.49\linewidth}
    \centering
    \includegraphics[width=#3\linewidth]{#1}
    \caption{#2}\label{ris:#1}
  \end{minipage}
  \hspace*{\fill}
  \penalty0 % we provide a break point
 }
\ExplSyntaxOff
\begin{document}

\twoimages{
  {a}{Caption left}{.5},
  {b}{Caption right}{.5},
  {c}{Caption left}{.5},
  {d}{Caption right}{.5},
  {e}{Caption center}{.5}
}

\end{document}
0
20

The following example uses the syntax that the arguments are given inside the argument for the command: \images{{...}{...}{...}{...}{...}{...}...}. The macro \images then parses its argument and catches three arguments at a time:

\documentclass{article}

\newif\ifimagesSep
\newcommand*{\images}[1]{%
  \par\noindent[begin images]\\\relax
  \imagesSepfalse
  \imagesScan#1\relax\relax\relax
  [end images]\par
}
\newcommand{\imagesScan}[3]{%
  \ifx\relax#1\empty
  \else
    \ifimagesSep
      [separation]\\\relax
    \else
      \imagesSeptrue
    \fi
    [image: #1 #2 #3]\\\relax
    \expandafter\imagesScan
  \fi
}

\begin{document}

\images{
  {w1}{l1}{c1}
  {w2}{l2}{c2}
  {w3}{l3}{c3}
}
\end{document}

Result

0
1

I just wrote a macro \WrapKArgsBetweenTokens which is driven by \romannumeral-expansion and therefore delivers the result after two expansion-steps.

Syntax:

\WrapKArgsBetweenTokens{%
  ⟨TeX-⟨number⟩-quantity of value K⟩
}{%
  ⟨tokens in case of error, 
   i.e., in case 
   amount of arguments with tokens to prepend 
   =/=
   amount of arguments with tokens to append⟩
}{%
  {⟨tokens to prepend to ⟨argument i⟩ in case i == 1 (mod n)⟩}% <- case 1
  {⟨tokens to prepend to ⟨argument i⟩ in case i == 2 (mod n)⟩}% <- case 2
  ... 
  {⟨tokens to prepend to ⟨argument i⟩ in case i == n (mod n)⟩}% <- case n
}{%
  {⟨tokens to append to ⟨argument i⟩ in case i == 1 (mod n)⟩}% <- case 1
  {⟨tokens to append to ⟨argument i⟩ in case i == 2 (mod n)⟩}% <- case 2
  ... 
  {⟨tokens to append to ⟨argument i⟩ in case i == n (mod n)⟩}% <- case n
}%
{⟨argument 1⟩}%
{⟨argument 2⟩}%
...
{⟨argument K⟩}%

In case the amount of arguments of pattern

{⟨tokens to prepend to ⟨argument i⟩ in case i == m (mod n)⟩}% <- case m

does not equal the amount of arguments of pattern

{⟨tokens to append to ⟨argument i⟩ in case i == m (mod n)⟩}% <- case m

you get

⟨tokens in case of error, i.e., in case  amount of arguments with tokens to prepend =/= amount of arguments with tokens to append&rangle

and

{⟨argument 1⟩}%
{⟨argument 2⟩}%
...
{⟨argument K⟩}%
are not gathered from the token-stream.

 

Otherwise an amount of K subsequent undelimited arguments is gathered from the token-stream and you get this:

⟨tokens to prepend to ⟨argument i⟩ in case i == 1 (mod n)⟩%
{⟨argument 1⟩}%
⟨tokens to append to ⟨argument i⟩ in case i == 1 (mod n)⟩%
⟨tokens to prepend to ⟨argument i⟩ in case i == 2 (mod n)⟩%
{⟨argument 2⟩}%
⟨tokens to append to ⟨argument i⟩ in case i == 2 (mod n)⟩%
...
⟨tokens to prepend to ⟨argument i⟩ in case i == n (mod n)⟩%
{⟨argument n⟩}%
⟨tokens to append to ⟨argument i⟩ in case i == n (mod n)⟩%
⟨tokens to prepend to ⟨argument i⟩ in case i == 1 (mod n)⟩%
{⟨argument n+1⟩}%
⟨tokens to append to ⟨argument i⟩ in case i == 1 (mod n)⟩%
⟨tokens to prepend to ⟨argument i⟩ in case i == 2 (mod n)⟩%
{⟨argument n+2⟩}%
⟨tokens to append to ⟨argument i⟩ in case i == 2 (mod n)⟩%
...
⟨tokens to prepend to ⟨argument i⟩ in case i == ... (mod n)⟩%
{⟨argument K⟩}%
⟨tokens to append to ⟨argument i⟩ in case i == ... (mod n)⟩%
\errorcontextlines=10000
\documentclass[a4paper]{article}
%===================[adjust margins/layout for the example]====================
\csname @ifundefined\endcsname{pagewidth}{}{\pagewidth=\paperwidth}%
\csname @ifundefined\endcsname{pdfpagewidth}{}{\pdfpagewidth=\paperwidth}%
\csname @ifundefined\endcsname{pageheight}{}{\pageheight=\paperheight}%
\csname @ifundefined\endcsname{pdfpageheight}{}{\pdfpageheight=\paperheight}%
\textwidth=\paperwidth
\oddsidemargin=1.25cm
\marginparsep=.2\oddsidemargin
\marginparwidth=\oddsidemargin
\advance\marginparwidth-2\marginparsep
\advance\textwidth-2\oddsidemargin
\advance\oddsidemargin-1in
\evensidemargin=\oddsidemargin
\textheight=\paperheight
\topmargin=1.25cm
\footskip=.5\topmargin
{\normalfont\global\advance\footskip.5\ht\strutbox}%
\advance\textheight-2\topmargin
\advance\topmargin-1in
\headheight=0ex
\headsep=0ex
\pagestyle{plain}
\parindent=0ex
\parskip=0ex 
\topsep=0ex
\partopsep=0ex
%==================[eof margin-adjustments]====================================
%==================[Print long lines nicely]===================================
\usepackage{seqsplit}
\newcommand\PRINTtempa{%

  \noindent
  \textit{yields:}

  \noindent
  {%
    \ttfamily
    \string\tempa=%
    \expandafter\seqsplit\expandafter{\meaning\tempa}%
  }%
}%
\makeatother
%==================[Eof print long lines nicely]===============================


\makeatletter
%% Code for \ExtractKthArg:
%%=============================================================================
%% Paraphernalia:
%%    \UD@firstoftwo, \UD@secondoftwo, \UD@PassFirstToSecond, \UD@Exchange,
%%    \UD@stopromannumeral, \UD@CheckWhetherNull
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
\newcommand\UD@Exchange[2]{#2#1}%
\@ifdefinable\UD@stopromannumeral{\chardef\UD@stopromannumeral=`\^^00}%
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UD@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>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\UD@CheckWhetherNull[1]{%
  \romannumeral\expandafter\UD@secondoftwo\string{\expandafter
  \UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
  \UD@secondoftwo\string}\expandafter\UD@stopromannumeral\UD@secondoftwo}{%
  \expandafter\UD@stopromannumeral\UD@firstoftwo}%
}%
%%=============================================================================
%% Extract K-th inner undelimited argument:
%%
%% \ExtractKthArg{<integer K>}%
%%               {<tokens in case list of undelimited args doesn't have a k-th argument>}%
%%               {<list of undelimited args>}%
%% 
%% In case there is no K-th argument in <list of indelimited args> : 
%%   Does deliver <tokens in case list of undelimited args doesn't have a k-th argument.
%% In case there is a K-th argument in <list of undelimited args> : 
%%   Does deliver that K-th argument with one level of braces removed.
%%
%% Examples:
%%
%%   \ExtractKthArg{0}{not available}{ABCDE} yields: not available
%%
%%   \ExtractKthArg{3}{not available}{ABCDE} yields:  C
%%
%%   \ExtractKthArg{3}{not available}{AB{CD}E} yields:  CD
%%
%%   \ExtractKthArg{4}{not available}{{001}{002}{003}{004}{005}} yields: 004
%%
%%   \ExtractKthArg{6}{not available}{{001}{002}{003}} yields: not available 
%% 
%%=============================================================================
\newcommand\ExtractKthArg[2]{%
  \romannumeral%
  % #1: <integer number K>
  % #2: <action if there is no K-th argument>
  \expandafter\UD@ExtractKthArgCheck
  \expandafter{\romannumeral\number\number#1 000}{#2}%
}%
\newcommand\UD@ExtractKthArgCheck[3]{%
  \UD@CheckWhetherNull{#1}{\UD@stopromannumeral#2}{% empty
    \expandafter\UD@ExtractKthArgLoop\expandafter{\UD@firstoftwo{}#1}{#2}{#3}%
  }%
}%
\begingroup
\def\UD@ExtractFirstArgLoop#1{%
  \endgroup
  \@ifdefinable\UD@RemoveTillFrozenrelax{%
    \long\def\UD@RemoveTillFrozenrelax##1##2#1{{##1}}%
  }%
  \newcommand\UD@ExtractKthArgLoop[3]{%
    \expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo##3{}.}{\UD@stopromannumeral##2}{%
      \UD@CheckWhetherNull{##1}{%
        \UD@ExtractFirstArgLoop{##3#1}%
      }{%
        \expandafter\UD@PassFirstToSecond\expandafter{\UD@firstoftwo{}##3}%
        {\expandafter\UD@ExtractKthArgLoop\expandafter{\UD@firstoftwo{}##1}{##2}}%
      }%
    }%
  }%
}%
\expandafter\expandafter\expandafter\UD@ExtractFirstArgLoop
\expandafter\expandafter\expandafter{%
\expandafter\expandafter\ifnum0=0\fi}%
%% Usage of frozen-\relax as delimiter is for speeding things up by reducing the
%% amount of iterations needed. I chose frozen-\relax because David Carlisle 
%% pointed out in   <https://tex.stackexchange.com/a/578877>
%% that frozen-\relax cannot be (re)defined in terms of \outer and cannot be
%% affected by \uppercase/\lowercase.
%%
%% \UD@ExtractFirstArg's argument may contain frozen-\relax:
%% The only effect is that internally more iterations are needed for
%% obtaining the result.
\newcommand\UD@ExtractFirstArgLoop[1]{%
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}#1}%
  {\expandafter\UD@stopromannumeral\UD@firstoftwo#1{}}%
  {\expandafter\UD@ExtractFirstArgLoop\expandafter{\UD@RemoveTillFrozenrelax#1}}%
}%
%% End of code for \ExtractKthArg.
%% Code for \WrapKArgsBetweenTokens:
%%=============================================================================
%% Wrap K undelimited macro arguments between tokens
%%-----------------------------------------------------------------------------
%%
%% Syntax:
%% 
%% \WrapKArgsBetweenTokens{%
%%    <TeX-<number>-quantity of value K>
%% }{%
%%   <Tokens in case of error, i.e., 
%%    in case amount of arguments with tokens to prepend =/= 
%%    amount of arguments with tokens to append>
%% }{%
%%   {<Tokens to prepend to <argument i> in case i == 1 (mod n)>}% <- case 1
%%   {<Tokens to prepend to <argument i> in case i == 2 (mod n)>}% <- case 2
%%   ... 
%%   {<Tokens to prepend to <argument i> in case i == n (mod n)>}% <- case n
%% }{%
%%   {<Tokens to append to <argument i> in case i == 1 (mod n)>}% <- case 1
%%   {<Tokens to append to <argument i> in case i == 2 (mod n)>}% <- case 2
%%   ... 
%%   {<Tokens to append to <argument i> in case i == n (mod n)>}% <- case n
%% }%
%% {<argument 1>}{<argument 2>}...{<argument K>}
%%=============================================================================
\newcommand\WrapKArgsBetweenTokens[4]{%
  \romannumeral
  \UD@WrapKArgsBetweenTokensCountcasesloop{#3}{#4}{}%
    {\UD@stopromannumeral#2}%
    {%
      \expandafter\UD@WrapKArgsBetweenTokensLoopStart
      \expandafter{\romannumeral\number\number#1 000}{#3}{#4}%
    }%
}%
%===========================================================================
\newcommand\UD@WrapKArgsBetweenTokensCountcasesloop[3]{%
  % #1 - <remaining prepend cases>
  % #2 - <remaining append cases>
  % #3 - <amount of m>
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo#1{}{}}{%
    \expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo#2{}{}}{%
      \expandafter\UD@PassFirstToSecond\UD@firstoftwo{{#3}}%
    }{%
      \UD@firstoftwo
    }%
  }{%
    \expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo#2{}{}}{%
      \UD@firstoftwo
    }{%
      \expandafter\UD@PassFirstToSecond\expandafter{\UD@firstoftwo{}#2}{%
        \expandafter\UD@WrapKArgsBetweenTokensCountcasesloop
        \expandafter{\UD@firstoftwo{}#1}%
      }{#3m}%
    }%
  }%
}%
%===========================================================================
\newcommand\UD@WrapKArgsBetweenTokensLoopStart[4]{%
  % #1 - <m in amount of args still to gather>
  % #2 - <prepend cases>
  % #3 - <append cases>
  % #4 - <m in amount of modulo-cases>
  \UD@CheckWhetherNull{#4}{%
    \UD@WrapKArgsBetweenTokensLoopCheckEnd{#2}{#3}{m}{}{#1}{m}{m}%
  }{%
    \UD@WrapKArgsBetweenTokensLoopCheckEnd{#2}{#3}{#4}{}{#1}{#4}{m}%
  }%
}%
\newcommand\UD@WrapKArgsBetweenTokensLoopCheckEnd[7]{%
  % #1 - <prepend cases>
  % #2 - <append cases>
  % #3 - <m in amount of modulo-cases>
  % #4 - <Accumulated>
  % #5 - <m in amount of args still to gather>
  % #6 - <m in amount of modulo-cases - i>
  % #7 - <m in amount of i>
  \UD@CheckWhetherNull{#5}{%
    \UD@stopromannumeral#4%
  }{%
     \UD@CheckWhetherNull{#6}{\UD@Exchange{{#3}{m}}}%
                             {\UD@Exchange{{#6}{#7}}}%
     {\UD@WrapKArgsBetweenTokensLoopGatherArgs{#1}{#2}{#3}{#4}{#5}}%
  }%
}%
%===========================================================================
\newcommand\UD@WrapKArgsBetweenTokensLoopGatherArgs[8]{%
  % #1 - <prepend cases>
  % #2 - <append cases>
  % #3 - <m in amount of modulo-cases>
  % #4 - <Accumulated>
  % #5 - <m in amount of args still to gather>
  % #6 - <m in amount of modulo-cases - i>
  % #7 - <m in amount of i>
  % #8 - <Gathered Arg>
  \UD@PassFirstToSecond{#7m}{%
    \expandafter\UD@PassFirstToSecond\expandafter{\UD@firstoftwo{}#6}{%
      \expandafter\UD@PassFirstToSecond\expandafter{\UD@firstoftwo{}#5}{%
        \expandafter\UD@PassFirstToSecond\expandafter{%
           \romannumeral%
           \expandafter\UD@Exchange\expandafter{%
             \romannumeral\UD@ExtractKthArgCheck{#7}{}{#2}%
           }{%
             \UD@Exchange{{#8}}{%
               \expandafter\UD@Exchange\expandafter{%
                 \romannumeral\UD@ExtractKthArgCheck{#7}{}{#1}%
               }{%
                 \UD@stopromannumeral#4%
               }%
             }%
           }%
        }{%
           \UD@WrapKArgsBetweenTokensLoopCheckEnd{#1}{#2}{#3}%
        }%
      }%
    }%
  }%
}%
%===========================================================================
%% End of code for \WrapKArgsBetweenTokens.
\makeatother

\begin{document}

\noindent\hrulefill

\begin{verbatim}
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\tempa
\expandafter\expandafter\expandafter{%
  \WrapKArgsBetweenTokens{17}{Error!}{{1}{2}{3}}{{A\\}{B\\}{C\\}}%
  {one}{two}{three}{four}{five}{six}{seven}{eight}{nine}{ten}{eleven}%
  {twelve}{thirteen}{fourteen}{fifteen}{sixteen}{seventeen}%
}%
\end{verbatim}

\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\tempa
\expandafter\expandafter\expandafter{%
  \WrapKArgsBetweenTokens{17}{Error!}{{1}{2}{3}}{{A\\}{B\\}{C\\}}%
  {one}{two}{three}{four}{five}{six}{seven}{eight}{nine}{ten}{eleven}%
  {twelve}{thirteen}{fourteen}{fifteen}{sixteen}{seventeen}%
}%
\PRINTtempa

\noindent\hrulefill

\begin{verbatim}
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\tempa
\expandafter\expandafter\expandafter{%
  \WrapKArgsBetweenTokens{17}{Error!}{}{}%
  {one}{two}{three}{four}{five}{six}{seven}{eight}{nine}{ten}{eleven}%
  {twelve}{thirteen}{fourteen}{fifteen}{sixteen}{seventeen}%
}%
\end{verbatim}

\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\tempa
\expandafter\expandafter\expandafter{%
  \WrapKArgsBetweenTokens{17}{Error!}{}{}%
  {one}{two}{three}{four}{five}{six}{seven}{eight}{nine}{ten}{eleven}%
  {twelve}{thirteen}{fourteen}{fifteen}{sixteen}{seventeen}%
}%
\PRINTtempa

\noindent\hrulefill

\begin{verbatim}
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\tempa
\expandafter\expandafter\expandafter{%
  \WrapKArgsBetweenTokens{17}{Error!}{{1}{2}}{{A\\}{B\\}{C\\}}%
  {one}{two}{three}{four}{five}{six}{seven}{eight}{nine}{ten}{eleven}%
  {twelve}{thirteen}{fourteen}{fifteen}{sixteen}{seventeen}%
}%
\end{verbatim}

\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\tempa
\expandafter\expandafter\expandafter{%
  \WrapKArgsBetweenTokens{17}{Error!}{{1}{2}}{{A\\}{B\\}{C\\}}%
  {one}{two}{three}{four}{five}{six}{seven}{eight}{nine}{ten}{eleven}%
  {twelve}{thirteen}{fourteen}{fifteen}{sixteen}{seventeen}%
}%
\PRINTtempa

\noindent\hrulefill

\begin{verbatim}
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\tempa
\expandafter\expandafter\expandafter{%
  \WrapKArgsBetweenTokens{17}{Error!}{{1}}{{A\\}}%
  {one}{two}{three}{four}{five}{six}{seven}{eight}{nine}{ten}{eleven}%
  {twelve}{thirteen}{fourteen}{fifteen}{sixteen}{seventeen}%
}%
\end{verbatim}

\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\tempa
\expandafter\expandafter\expandafter{%
  \WrapKArgsBetweenTokens{17}{Error!}{{1}}{{A\\}}%
  {one}{two}{three}{four}{five}{six}{seven}{eight}{nine}{ten}{eleven}%
  {twelve}{thirteen}{fourteen}{fifteen}{sixteen}{seventeen}%
}%
\PRINTtempa

\noindent\hrulefill

\begin{verbatim}
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\tempa
\expandafter\expandafter\expandafter{%
  \WrapKArgsBetweenTokens{17}{Error!}{{\macroA}{\macroB}{\macroC}}{{&}{&}{\\}}%
  {one}{two}{three}{four}{five}{six}{seven}{eight}{nine}{ten}{eleven}%
  {twelve}{thirteen}{fourteen}{fifteen}{sixteen}{seventeen}%
}%
\end{verbatim}

\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\tempa
\expandafter\expandafter\expandafter{%
  \WrapKArgsBetweenTokens{17}{Error!}{{\macroA}{\macroB}{\macroC}}{{&}{&}{\\}}%
  {one}{two}{three}{four}{five}{six}{seven}{eight}{nine}{ten}{eleven}%
  {twelve}{thirteen}{fourteen}{fifteen}{sixteen}{seventeen}%
}%
\PRINTtempa

\end{document}

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .