7

Although I've been a LaTeX user for years, this is the first time that I've been unable to find the answer to a LaTeX issue, so this is my first posted question.

I'm defining a command (\QPreparation) that will redefine the command \QInput. The command \QInput{N} should input code into my document based on number N that I send it. With each call of the \QPreparation command, I want the base path \QInput looks in to change as well as the total number of cases that \QInput will consider. The input files are named "C0.tex","C1.tex","C2.tex",... so that in redefining \QInput, the new file options are easy to update.

In the code that I've been working on (below), the 2 inputs to \QPreparation are (a) the base path to update \QInput and (b) the number of cases that I want \QInput to consider.

Because my next step is to modify the \QPreparation command so that the calls \QInput{0}, \QInput{1}, ... \QInput{N} load all N files in a random order, I DO NOT believe that it is feasible to make \QPreparation define \QInput in a manner like \input{#1/C##1.tex}.

If you are curious about how I plan to do the randomization, consider randomize the order of text lines in a .tex file .

It seems to me that the easiest way to solve this problem is to define \QInput with an \ifcase that is generated by a loop. The sample code (below) shows my attempt at this, but the additional \or in the loop throws errors such as:

! Extra \or. \iterate ->\ifnum \the \QIternum <4\relax \or                                                \input {./Q1/C\the \QIternum ....

My sample code:

\newcommand{\QPreparation}[2]{%
  \expandafter\renewcommand\csname QInput\endcsname[1]{%
    \ifcase##1
      \input{#1/C0.tex}
      \QIternum=1
      \loop\ifnum\the\QIternum<#2\relax
        \or
        \input{#1/C\the\QIternum.tex}
      \advance\QIternum by 1
      \repeat
    \fi
  }
}

Any help would be greatly appreciated.

Thanks!

2 Answers2

7

An alternative way of building up the ifcase

\documentclass{article}


\def\QInput{}
\def\afterfi#1\fi{\fi#1}
\def\QPreparation#1#2{\bgroup
\let\or\relax\let\input\relax
\XQPreparation{#1}{#2}%
\edef\x{\egroup\def\noexpand\QInput####1{%
  \noexpand\ifcase####1\relax\input{#1/C0.tex}\QInput\noexpand\fi}}%
\x
}
\def\XQPreparation#1#2{%
\ifnum#2>0 \afterfi
\edef\QInput{\or\input{#1/C#2.tex}\QInput}%
\XQPreparation{#1}{\the\numexpr#2-1\relax}%
\fi}


\begin{document}
\QPreparation{foo}{5}

\show\QInput
\end{document}

produces

> \QInput=macro:
#1->\ifcase #1\relax \input {foo/C0.tex}\or \input {foo/C1.tex}\or \input {foo/
C2.tex}\or \input {foo/C3.tex}\or \input {foo/C4.tex}\or \input {foo/C5.tex}\fi
 .
l.23 \show\QInput
David Carlisle
  • 757,742
5

The replacement text is not executed when the replacement text is absorbed.

You can build the macro in an indirect way:

\documentclass{article}

\newcommand{\QInput}{} % initialization

\makeatletter
\newcount\QIteration
\newcommand{\QPreparation}[2]{%
  \QIteration=\z@
  \gdef\tempa{\ifcase####1\relax\input{#1/C0.tex}}%
  \loop\ifnum\QIteration<#2
    \advance\QIteration\@ne
    \edef\tempb{%
      \expandafter\noexpand\csname or\endcsname
      \noexpand\input{#1/C\the\QIteration.tex}%
    }%
    \expandafter\g@addto@macro\expandafter\tempa\expandafter{\tempb}%
  \repeat
  \g@addto@macro\tempa{\fi}
  \def\tempb{\renewcommand\QInput[1]}%
  \expandafter\tempb\expandafter{\tempa}
}
\makeatother
\QPreparation{foo}{5}

\show\QInput

The \show command will output

> \QInput=\long macro:
#1->\ifcase #1\relax \input {foo/C0.tex}\or \input {foo/C1.tex}\or \input {foo/
C2.tex}\or \input {foo/C3.tex}\or \input {foo/C4.tex}\or \input {foo/C5.tex}\fi
 .

which seems to be what you want.

It's necessary to hide \or in the loop, because otherwise we'd get a “misplaced \or” error.

An alternative without global definitions:

\documentclass{article}

\newcommand{\QInput}{} % initialization

\makeatletter
\newcount\QIteration
\toks@={}
\newcommand{\QPreparation}[2]{%
  \QIteration=\z@
  \toks@={\ifcase##1\relax\input{#1/C0.tex}}%
  \loop\ifnum\QIteration<#2
    \advance\QIteration\@ne
    \edef\temp{%
      \expandafter\noexpand\csname or\endcsname
      \noexpand\input{#1/C\the\QIteration.tex}%
    }%
    \toks@=\expandafter{\the\expandafter\toks@\temp}%
  \repeat
  \toks@=\expandafter{\the\toks@\fi}%
  \begingroup\edef\x{\endgroup
    \noexpand\renewcommand\noexpand\QInput[1]{\the\toks@}%
  }\x
}
\makeatother
\QPreparation{foo}{5}

\show\QInput

An equivalent solution if xparse is used:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\tl_new:N \l_strickland_temp_tl
\NewDocumentCommand{\QPreparation}{mm}
 {
  \tl_clear:N \l_strickland_temp_tl
  \int_step_inline:nnnn { 0 } { 1 } { #2 }
   {
    \tl_put_right:Nn \l_strickland_temp_tl { {##1}{\input{#1/C##1.tex}} }
   }
  \use:x
   {
    \exp_not:N \DeclareDocumentCommand \exp_not:N \QInput { m }
     {
      \exp_not:N \int_case:nn { ####1 } { \exp_not:V \l_strickland_temp_tl }
     }
   }
 }
\ExplSyntaxOff
egreg
  • 1,121,712