%\iffalse % xfor.dtx generated using makedtx version 0.91b (c) Nicola Talbot % Command line args: % -src "xfor.sty=>xfor.sty" % -doc "manual.tex" % -author "Nicola Talbot" % -dir "source" % xfor % Created on 2007/6/27 17:32 %\fi %\iffalse %<*package> %% \CharacterTable %% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z %% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z %% Digits \0\1\2\3\4\5\6\7\8\9 %% Exclamation \! Double quote \" Hash (number) \# %% Dollar \$ Percent \% Ampersand \& %% Acute accent \' Left paren \( Right paren \) %% Asterisk \* Plus \+ Comma \, %% Minus \- Point \. Solidus \/ %% Colon \: Semicolon \; Less than \< %% Equals \= Greater than \> Question mark \? %% Commercial at \@ Left bracket \[ Backslash \\ %% Right bracket \] Circumflex \^ Underscore \_ %% Grave accent \` Left brace \{ Vertical bar \| %% Right brace \} Tilde \~} % %\fi % \iffalse % Doc-Source file to use with LaTeX2e % Copyright (C) 2007 Nicola Talbot, all rights reserved. % \fi % \iffalse %<*driver> \documentclass[a4paper]{ltxdoc} \usepackage{ifthen} \usepackage{alltt} \usepackage[colorlinks, bookmarks, hyperindex=false, pdfauthor={Nicola L.C. Talbot}, pdftitle={xfor: redefinition of '@for}, pdfkeywords={LaTeX,package development}]{hyperref} \CheckSum{102} \PageIndex \RecordChanges \newcommand*{\sty}[1]{\textsf{#1}} \begin{document} \DocInput{xfor.dtx} \end{document} % %\fi %\MakeShortVerb{"} % % \title{xfor v1.0: Reimplementation of \cs{@for} to allow %premature termination of the loop} % \author{Nicola L.C. Talbot\\[10pt] %School of Computing Sciences\\ %University of East Anglia\\ %Norwich. Norfolk\\ %NR4 7TJ. United Kingdom.\\ %\url{http://theoval.cmp.uea.ac.uk/~nlct/}} % %\date{27th June 2007} %\maketitle %\tableofcontents % %\section{Introduction} %\changes{1.0}{2007 June 27}{Initial version} %The \sty{xfor} package redefines \cs{@for} so that the loop can %be prematurely terminated, akin to C/Java's \texttt{break} statement %except that the loop will terminate at the \emph{end} of the %current iteration. The syntax for \DescribeMacro{\@for}\cs{@for} %remains the same: %\begin{quote} %\cs{@for}\meta{cmd}":="\meta{list}"\do"\marg{body} %\end{quote} %where \meta{cmd} is a command name that is assigned to the current %element of the list given by \meta{list} at each iteration. % %To terminate the loop at the end of the current %iteration, use the command \DescribeMacro{\@endfortrue}\cs{@endfortrue}. %This command may be used anywhere in \meta{body}, but will only %take effect at the end of the current iteration. %The remainder of the list is stored in %\DescribeMacro{\@forremainder}\cs{@forremainder}. You can test %whether the loop was prematurely terminated using the conditional %\DescribeMacro{\if@endfor}\cs{if@endfor}. % %\subsection{Example (ordered insertion)} % %Suppose you have list of sorted numbers stored in the command %\cs{mylist}, e.g.: %\begin{verbatim} %\def\mylist{1,3,5,7,8,12,15,20} %\end{verbatim} %and you want to insert a new value given by the command %\cs{newval}, e.g. %\begin{verbatim} %\def\newval{11} %\end{verbatim} %in the correct order. You can use \cs{@for} to iterate through %each element in the sorted list, testing the value against the %new value to be inserted. Once the new value has been inserted, %the loop can be terminated, and any remaining elements can be %appended to the new list. The following %defines the command \cs{insertinto}\marg{new val}\marg{list} %which uses this method: %\begin{verbatim} %\newcommand{\insertinto}[2]{% %\def\nlst{}% %\@for\n:=#2\do{% %% store new list in \toks@ %\expandafter\toks@\expandafter{\nlst}% %% test current value against new value %\ifnum\n>#1\relax % \edef\newstuff{\number#1,\n}% % % end for loop at the end of this iteration % \@endfortrue %\else % \edef\newstuff{\n}% %\fi %% append new stuff to new list %\ifx\nlst\@empty % \edef\nlst{\newstuff}% %\else % \edef\nlst{\the\toks@,\newstuff}% %\fi %}% %% check to see if for loop was prematurely terminated %\if@endfor % % loop may have been terminated during final iteration, in % % which case \@forremainder is empty. % \ifx\@forremainder\@empty % % do nothing % \else % % loop prematurely ended, append remainder of original list % % to new list % \expandafter\toks@\expandafter{\nlst}% % \edef\nlst{\the\toks@,\@forremainder}% % \fi %\else % % wasn't prematurely terminated, so new value hasn't been added % % add now. % \expandafter\toks@\expandafter{\nlst}% % \ifx\nlst\@empty % \edef\nlst{\number#1}% % \else % \edef\nlst{\the\toks@,\number#1}% % \fi %\fi %\let#2=\nlst %} %\end{verbatim} %The \cs{insertinto} macro can then be used as follows: %\begin{verbatim} %\def\mylist{1,2,5,9,12,15,18,20}% %\def\newval{11}% %Original list: \mylist. New value: \newval. % %\insertinto{\newval}{\mylist} %New list: \mylist. %\end{verbatim} % %\subsection{Example (numerical insertion sort)} % %Care needs to be taken when nesting \cs{@for}-loops. %Suppose you have a list of unsorted numbers, say %\begin{verbatim} %\def\mylist{4,2,7,1,10,11,20,15} %\end{verbatim} %and you want to sort the list in numerical order using an insertion %sort method. To do this, a macro needs to be defined which iterates %through each element in the unordered list, and the element %is then inserted into an ordered list. The previous example %described the macro \cs{insertinto} which does this, but this results %in nested \cs{@for} commands. The \cs{insertinto} command will need %to be grouped to avoid errors: %\begin{verbatim} %\newcommand*{\insertionsort}[1]{% %\def\sortedlist{}% %\@for\val:=#1\do{{\insertinto{\val}{\sortedlist}}}% %\let#1=\sortedlist %} %\end{verbatim} %This won't work with the definition of \cs{insertinto} as %given in the previous section, as the grouping causes the %definition of the sorted list to be localised to that group. %Replacing %\begin{verbatim} %\let#2=\nlst %\end{verbatim} %with %\begin{verbatim} %\global\let#2=\nlst %\end{verbatim} %at the end of the definition of \cs{insertinto} will fix that. % %\changes{1.0}{2007 June 27}{Initial version} % % \StopEventually{\phantomsection\addcontentsline{toc}{section}{Index}\PrintIndex} % % % %\section{The Code} %\iffalse % \begin{macrocode} %<*xfor.sty> % \end{macrocode} %\fi % Declare package: % \begin{macrocode} \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{xfor}[2007/06/27 v1.0 (NLCT)] % \end{macrocode} % Define a switch to determine if the for loop should be % terminated: %\begin{macro}{\if@endfor} % \begin{macrocode} \newif\if@endfor % \end{macrocode} %\end{macro} % Redefine \cs{@for}, so that it resets \cs{if@endfor} % and \cs{@forremainder}: %\begin{macro}{\@for} % \begin{macrocode} \long\def\@for#1:=#2\do#3{% \@endforfalse \def\@forremainder{}% \expandafter\def\expandafter\@fortmp\expandafter{#2}% \ifx\@fortmp\@empty \else \expandafter\@forloop#2,\@nil,\@nil\@@#1{#3}% \fi } % \end{macrocode} %\end{macro} % Redefine \cs{@fornoop} to be a long command: %\begin{macro}{\@fornoop} % \begin{macrocode} \long\def\@fornoop#1\@@#2#3{} % \end{macrocode} %\end{macro} % Redefine \cs{@forloop} to check for \cs{if@endfor}: %\begin{macro}{\@forloop} % \begin{macrocode} \long\def\@forloop#1,#2,#3\@@#4#5{% \def#4{#1}% \ifx#4\@nnil \else #5% \if@endfor \@iforgatherrest#2,#3% \else \def#4{#2}% \ifx#4\@nnil \else #5% \if@endfor \@iforgatherrest#3% \else \@iforloop#3\@@#4{#5}% \fi \fi \fi \fi } % \end{macrocode} %\end{macro} % Get remainder of list (stores in \cs{@forremainder}): %\begin{macro}{\@forgatherrest} % \begin{macrocode} \def\@forgatherrest#1,\@nil,\@nil{\def\@forremainder{#1}} % \end{macrocode} %\end{macro} % As above, but there may not be anything before \cs{@nil}: %\begin{macro}{\@iforgatherrest} % \begin{macrocode} \def\@iforgatherrest#1\@nil,\@nil{% \def\@fortmp{#1}% \ifx\@fortmp\@empty \def\@forremainder{}% \else \@forgatherrest#1\@nil,\@nil \fi } % \end{macrocode} %\end{macro} % Redefine \cs{@iforloop} to check \cs{if@endfor}: %\begin{macro}{\@iforloop} % \begin{macrocode} \long\def\@iforloop#1,#2\@@#3#4{% \def#3{#1}% \ifx#3\@nnil \let\@ifornext\@fornoop \else #4\relax \if@endfor \@iforgatherrest#2\relax \let\@ifornext\@fornoop \else \let\@ifornext\@iforloop \fi \fi \@ifornext#2\@@#3{#4}% } % \end{macrocode} %\end{macro} %\iffalse % \begin{macrocode} % % \end{macrocode} %\fi %\Finale \endinput