%\iffalse % xfor.dtx generated using makedtx version 0.94b (c) Nicola Talbot % Command line args: % -src "xfor.sty\Z=>xfor.sty" % -src "sample.tex\Z=>sample.tex" % -doc "xfor-manual.tex" % -author "Nicola Talbot" % -dir "source" % xfor % Created on 2009/2/5 16:02 %\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) 2009 Nicola Talbot, all rights reserved. % \fi % \iffalse %<*driver> \documentclass[a4paper]{ltxdoc} \usepackage{xfor} \usepackage{ifthen} \usepackage{alltt} \usepackage[colorlinks, bookmarks, hyperindex=false, pdfauthor={Nicola L.C. Talbot}, pdftitle={xfor: redefinition of \string\@for}, pdfkeywords={LaTeX,package development}]{hyperref} \CheckSum{197} \PageIndex \RecordChanges \newcommand*{\sty}[1]{\textsf{#1}} \begin{document} \DocInput{xfor.dtx} \end{document} % %\fi %\MakeShortVerb{"} % % \title{xfor v1.05: 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{5th February 2009} %\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}. % %As from version 1.02, there is also provision for looking ahead. %At each iteration in the loop, the next element is stored in %\cs{@xfor@nextelement}\DescribeMacro{\@xfor@nextelement}. %On the last iteration, this value %will be \cs{@nil}, and so can be checked using %\begin{verbatim} % \ifx\@xfor@nextelement\@nnil % % last iteration % \else % % not last iteration % \fi %\end{verbatim} % %\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{}% new list initially empty % \@for\n:=#2\do{% % % store new list in \toks@ % \expandafter\toks@\expandafter{\nlst}% % % test current value against new value % \ifnum\n>#1\relax % % new value needs to be inserted before current value % \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 % % so 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. % %\subsection{Example (looking ahead)} % %This example checks the next value to determine if the loop %is on the last iteration, if it is, it does nothing, otherwise %it does a semi-colon: %\begin{verbatim} %\makeatletter %\def\mylist{1,2,3,4,5}% %\@for\val:=\mylist\do{\val %\ifx\@xfor@nextelement\@nnil \else ;\fi} %\makeatother %\end{verbatim} %which produces: %\makeatletter %\def\mylist{1,2,3,4,5}\relax %\@for\val:=\mylist\do{\val %\ifx\@xfor@nextelement\@nnil \else ;\fi} %\makeatother % %\section{Acknowledgements} % %Many thanks to Morten~H\o gholm for providing code to improve %efficiency. % % \StopEventually{\phantomsection %\addcontentsline{toc}{section}{Change History} %\PrintChanges\phantomsection %\addcontentsline{toc}{section}{Index} %\PrintIndex} % % % %\section{The Code} %\iffalse % \begin{macrocode} %<*xfor.sty> % \end{macrocode} %\fi % Note that the internal macros used by \cs{@for} have changed % in version 1.04. % % \begin{macrocode} \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{xfor}[2009/02/05 v1.05 (NLCT)] % \end{macrocode} %\begin{macro}{\if@endfor} % Define a switch to determine if the for loop should be % stopped prematurely. % \begin{macrocode} \newif\if@endfor % \end{macrocode} %\end{macro} %\begin{macro}{\@gobbleseven} %\changes{1.04}{2009 January 25}{added by Morten H\o gholm} % Ignore seven arguments. % \begin{macrocode} \long\def\@gobbleseven#1#2#3#4#5#6#7{} % \end{macrocode} %\end{macro} %\begin{macro}{\@for} % \cs{@for}\meta{cmd}":="\meta{list}\cs{do}\marg{body} % test if the list is empty and then re-arrange %\changes{1.04}{2009 January 25}{Modified by Morten H\o gholm to % improve efficiency} % \begin{macrocode} \long\def\@for#1:=#2\do{% % \end{macrocode} % Initialise % \begin{macrocode} \@endforfalse \def\@forremainder{}% \expandafter\def\expandafter\@fortmp\expandafter{#2}% % \end{macrocode} % If list is empty do nothing % \begin{macrocode} \ifx\@fortmp\@empty \expandafter\@gobbleseven \fi \expandafter\@@for\expandafter#1\expandafter{#2}% } % \end{macrocode} %\end{macro} % %\begin{macro}{\@@for} % Initialise for loop %\changes{1.04}{2009 January 25}{Added by Morten H\o gholm} % \begin{macrocode} \long\def\@@for#1#2#3{% \@xforloop#1{#3}#2,\@nil,\@nil,% \@xfor@endmarker% magic end marker } % \end{macrocode} %\end{macro} % %\begin{macro}{\@xfornoop} %\changes{1.04}{2009 January 25}{second and third arguments dropped (MH)} %\changes{1.04}{2009 January 25}{\cs{@fornoop} replaced by % \cs{@xfornoop} to prevent conflict with \cs{@tfor}} % Read up until magic end marker. % \begin{macrocode} \long\def\@xfornoop#1\@xfor@endmarker{} % \end{macrocode} %\end{macro} %\begin{macro}{\@xforloop} %\cs{@forloop}\marg{var}\marg{action} %\changes{1.04}{2009 January 25}{Modified by Morten H\o gholm to % improve efficiency} %\changes{1.05}{2009 February 5}{\cs{@forloop} replaced by % \cs{@xforloop} to prevent conflict with other packages that % use \cs{@forloop}} % \begin{macrocode} \long\def\@xforloop#1#2#3,#4,{% \def#1{#3}% \ifx#1\@nnil % \end{macrocode} % Grab the \cs{@xfor@endmarker} at the very end % \begin{macrocode} \expandafter\@xfornoop \fi % \end{macrocode} % Removed |\@xfor@storenext#4,\@nil|. Instead store next element % in \cs{@xfor@nextelement}. % \begin{macrocode} \def\@xfor@nextelement{#4}% #2% \if@endfor \expandafter\@iforgatherrest \fi \@xforloop#1{#2}{#4},% } % \end{macrocode} %\end{macro} % %\begin{macro}{\@iforgatherrest} % Gather the remainder (and store in \cs{@forremainder}) %\changes{1.01}{2007 July 11}{made long}% %\changes{1.04}{2009 January 25}{argument syntax changed (MH)} % \begin{macrocode} \long\def\@iforgatherrest \@xforloop#1#2#3,#4\@xfor@endmarker{% \def\@fortmp{#3}% \ifx\@fortmp\@nnil \def\@forremainder{}% \else \@forgatherrest{#3},#4\@xfor@endmarker% \fi } % \end{macrocode} %\end{macro} % %\begin{macro}{\@forgatherrest} % Get remainder of list (stored in \cs{@forremainder}): %\changes{1.01}{2007 July 11}{made long}% %\changes{1.04}{2009 January 25}{argument syntax changed (MH)} % \begin{macrocode} \long\def\@forgatherrest#1,\@nil,\@nil,\@xfor@endmarker{% \def\@forremainder{#1}% } % \end{macrocode} %\end{macro} % %\changes{1.02}{2007 August 16}{Added \cs{@xfor@storenext}}% %\changes{1.04}{2009 January 25}{Removed \cs{\@xfor@storenext}}% %\changes{1.04}{2009 January 25}{removed \cs{@iforloop}} %\iffalse % \begin{macrocode} % % \end{macrocode} %\fi %\iffalse % \begin{macrocode} %<*sample.tex> % \end{macrocode} %\fi %\section{Sample Document (sample.tex)} % \begin{macrocode} \listfiles \documentclass{article} \usepackage{xfor} \makeatletter % \insertinto{new value}{list} \newtoks\tmptok \newcommand{\insertinto}[2]{% \def\nlst{}% \@for\n:=#2\do{% % store new list in \tmptok \expandafter\tmptok\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\tmptok,\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\tmptok\expandafter{\nlst}% \edef\nlst{\the\tmptok,\@forremainder}% \fi \else % wasn't prematurely terminated, so new value hasn't been added. % Add now. \expandafter\tmptok\expandafter{\nlst}% \ifx\nlst\@empty \edef\nlst{\number#1}% \else \edef\nlst{\the\tmptok,\number#1}% \fi \fi \global\let#2=\nlst } % \insertionsort{list} % replaces list with sorted list \newcommand{\insertionsort}[1]{% \def\sortedlist{}% \@for\val:=#1\do{{\insertinto{\val}{\sortedlist}}}% \let#1=\sortedlist} \makeatother \begin{document} Unsorted list: \def\mylist{4,2,7,1,10,11,20,15}\mylist. \insertionsort{\mylist}% Sorted list: \mylist. Iterate through the list (next element in parentheses): \makeatletter \@for\n:=\mylist\do{% \n \ifx\@xfor@nextelement\@nnil % last iteration \else (\@xfor@nextelement); \fi }. \end{document} % \end{macrocode} %\iffalse % \begin{macrocode} % % \end{macrocode} %\fi %\Finale \endinput