ltcntrl.dtx

Johannes Braams  David Carlisle  Alan Jeffrey
Leslie Lamport  Frank Mittelbach  Chris Rowley

Rainer Schöpf

1995/08/16

1 Program control structure

This section defines a number of control structure macros, such as while-loops and for-loops.

1 ⟨∗2ekernel⟩

2 \message{control,}
\@whilenum TEST \do {BODY}

\@whiledim TEST \do {BODY} : These implement the loop

while TEST do BODY od where TEST is a TeX \ifnum or \ifdim test, respectively. They are optimized for the normal case of TEST initially false.

\@whilesw SWITCH \fi {BODY} : Implements the loop

while SWITCH do BODY od

Optimized for normal case of SWITCH initially false.

\@for NAME := LIST \do {BODY} : Assumes that LIST expands to A1,A2,

... ,An . Executes BODY n times, with NAME = Ai on the i-th

iteration.

Optimized for the normal case of n = 1. Works for n=0.

\@tfor NAME := LIST \do {BODY} if, before expansion, LIST = T1 ... Tn where each Ti is a token or {...}, then executes BODY n times, with NAME = Ti on the i-th iteration. Works for n=0.

NOTES: 1. These macros use no \@temp sequences. 2. These macros do not work if the body contains anything that looks syntactically to TeX like an improperly balanced \if

     \else \fi.
\@whilenum TEST \do {BODY} ==

BEGIN

if TEST

then BODY

        \@iwhilenum{TEST \relax BODY}

END

\@iwhilenum {TEST BODY} ==

BEGIN

if TEST

then BODY

        \@nextwhile = def(\@iwhilenum)
  else \@nextwhile = def(\@whilenoop)

fi

\@nextwhile {TEST BODY}

END

\@whilesw SWITCH \fi {BODY} ==

BEGIN

if SWITCH

then BODY

       \@iwhilesw {SWITCH BODY}\fi

fi END

\@iwhilesw {SWITCH BODY} \fi ==

BEGIN

if SWITCH

then BODY

       \@nextwhile = def(\@iwhilesw)
  else \@nextwhile = def(\@whileswnoop)

fi

\@nextwhile {SWITCH BODY} \fi

END

\@whilenoop \@whilenum \@iwhilenum
3 \long\def\@whilenum#1\do #2{\ifnum #1\relax #2\relax\@iwhilenum{#1\relax
4  #2\relax}\fi}
5 \long\def\@iwhilenum#1{\ifnum #1\expandafter\@iwhilenum
6  \else\expandafter\@gobble\fi{#1}}
\@whiledim \@iwhiledim
7 \long\def\@whiledim#1\do #2{\ifdim #1\relax#2\@iwhiledim{#1\relax#2}\fi}

8 \long\def\@iwhiledim#1{\ifdim #1\expandafter\@iwhiledim
9  \else\expandafter\@gobble\fi{#1}}
\@whileswnoop
\@whilesw
\@iwhilesw

10 \long\def\@whilesw#1\fi#2{#1#2\@iwhilesw{#1#2}\fi\fi}
11 \long\def\@iwhilesw#1\fi{#1\expandafter\@iwhilesw
12  \else\@gobbletwo\fi{#1}\fi}

\@for NAME := LIST \do {BODY} ==

BEGIN \@forloop expand(LIST),\@nil,\@nil \@@ NAME {BODY} END

\@forloop CAR, CARCDR, CDRCDR \@@ NAME {BODY} ==

BEGIN NAME = CAR if def(NAME) = def(\@nnil)

else BODY; NAME = CARCDR if def(NAME) = def(\@nnil)

else BODY

              \@iforloop CDRCDR \@@ NAME \do {BODY}

fi fi

END

\@iforloop CAR, CDR \@@ NAME {BODY} = NAME = CAR if def(NAME) = def(\@nnil)

   then \@nextwhile = def(\@fornoop)

else BODY ;

         \@nextwhile = def(\@iforloop)

fi

\@nextwhile name cdr {body}

\@tfor NAME := LIST \do {BODY}

= \@tforloop LIST \@nil \@@ NAME {BODY}
\@tforloop car cdr \@@ name {body} =

name = car if def(name) = def(\@nnil)

   then \@nextwhile == \@fornoop

else body ;

         \@nextwhile == \@forloop

fi

\@nextwhile name cdr {body}

\@nnil
13 \def\@nnil{\@nil}
\@empty
14 \def\@empty{}
\@fornoop
15 \def\@fornoop#1\@@#2#3{}
\@for
16 \long\def\@for#1:=#2\do#3{%
17 \expandafter\def\expandafter\@fortmp\expandafter{#2}%
18 \ifx\@fortmp\@empty \else
19  \expandafter\@forloop#2,\@nil,\@nil\@@#1{#3}\fi}
\@forloop
20 \long\def\@forloop#1,#2,#3\@@#4#5{\def#4{#1}\ifx #4\@nnil \else
21  #5\def#4{#2}\ifx #4\@nnil \else#5\@iforloop #3\@@#4{#5}\fi\fi}
\@iforloop
22 \long\def\@iforloop#1,#2\@@#3#4{\def#3{#1}\ifx #3\@nnil
23  \expandafter\@fornoop \else
24  #4\relax\expandafter\@iforloop\fi#2\@@#3{#4}}
\@tfor
25 \def\@tfor#1:={\@tf@r#1 }
26 \long\def\@tf@r#1#2\do#3{\def\@fortmp{#2}\ifx\@fortmp\space\else
27  \@tforloop#2\@nil\@nil\@@#1{#3}\fi}
28 \long\def\@tforloop#1#2\@@#3#4{\def#3{#1}\ifx #3\@nnil
29  \expandafter\@fornoop \else
30  #4\relax\expandafter\@tforloop\fi#2\@@#3{#4}}

\@break@tfor Break out of a \@tfor loop. This should be called inside the scope of an \if. See

\@iffileonpath for an example.
31 \long\def\@break@tfor#1\@@#2#3{\fi\fi}

\@removeelement Removes an element from a comma-separated list and puts it into a control sequence, called as \@removeelement{⟨element⟩}{⟨list⟩}{⟨cs⟩}.

32 \def\@removeelement#1#2#3{%
33 \def\reserved@a##1,#1,##2\reserved@a{##1,##2\reserved@b}%
34 \def\reserved@b##1,\reserved@b##2\reserved@b{%
35  \ifx,##1\@empty\else##1\fi}%
36 \edef#3{%
37  \expandafter\reserved@b\reserved@a,#2,\reserved@b,#1,\reserved@a}}

38 ⟨/2ekernel⟩