% \AddToCheckSum{309} % % \begin{warning} % This code has not been well tested yet. The output routine of \LaTeX{} is % very complicated, and unforseen problems might arise. % \end{warning} % % \DescribeMacro\NextAux % \DescribeMacro\DynamicAux % \DescribeMacro\StaticAux % The macro \cs\NextAux changes \cname{@auxout} to a new stream if one is % available, and gives an error otherwise. The macro is implemented in % dynamic and static ways which can be selected with \cs\DynamicAux and % \cs\StaticAux\marg{number of streams}. The number of streams can be from 2 % to~16. The dynamic implementation is the default; I do not see much use % for the static implementation at present. The \option{static} option is % the equivalent of the declaration |\StaticAux{10}|. The \option{dynamic} % selects the dynamic implementation. % % \cs\StaticAux can be invoked after \cs\DynamicAux, but not the other way % around (at least, the streams allocated by \cs\StaticAux are not % recovered). Macros which use \cs\NextAux do not have to know whether the % implementation is static or dynamic. % % \subsubsection{Wheels} % % The output streams are manipulated with the help of a data structure I call a % \word{wheel}. % % A \term{wheel} has 0 or more \term{spokes} and can be \term{rolled}. Each % spoke is a \TeX{} token, probably a control sequence name, and has an % internal name. You can access the spoke at the 12 o'clock or ``top'' % position of a wheel. In computerese, a wheel is a circularly linked list of % tokens, and the operation of rolling moves a pointer along it in a certain % direction by one element. % % Wheels and operations on wheels are local. % % \DescribeMacro\InitWheel % \DescribeMacro\DefWheel % You make a wheel either with \cs\InitWheel\marg{\\csname}, which makes % \meta{\\csname} a wheel with no spokes, or % \cs\DefWheel\marg{\\csname}\marg{spokes}, which makes a wheel with % \meta{spokes} for spokes. The first spoke in \meta{spokes} is the top, the % second will be top after one roll, and the first will be top again after % $n$ rolls, if there are $n$ spokes. % % \DescribeMacro\Roll % \DescribeMacro\Top % \DescribeMacro\AddSpokes % Wheels are rolled by \cs\Roll\marg{wheel}. Spokes can be added to a % wheel with \cs\AddSpokes\marg{wheel}\marg{spokes}. When $n$ spokes are % added, the previous top will be at the top after $n$ rolls. % \cs\Top\marg{wheel} expands eventually to the top spoke, which then can % further expand, and so on. % % \DescribeMacro\IfTop % \cs\IfTop\marg{wheel}\marg{spoke}\marg{true clause}\marg{false clause} % compares the top of \meta{wheel} with \meta{spoke} using \cname{ifx}, and % executes either \meta{true clause} or \meta{false clause} as appropriate. % (The \package{newclude} package doesn't actually use this command; it's % provided to ``round out'' the wheel data structure.) % % \caveat{Don't put more than one token as the second argument to \cs\IfTop.} % % \subsubsection{Preliminaries} % % We require the \package{afterpage} package. The intuitive justification is % that \cs\write{}s are delayed until the current page is shipped out. We need % to keep an output stream open until its last \cs\write has been actually % handled; after that, the stream can be made available again. % \begin{macrocode} \RequirePackage{afterpage} % \end{macrocode} % % \begin{macro}{\nc@aux@wheel} % We use the wheel structure to handle both the static case and the dynamic % case. The spokes of the wheel are macros |\nc@auxout@|\meta{n}. Their % first-level expansion is \meta{n}, a positive integer from 0 to~15. Each % spoke has two corresponding macros. |\nc@auxout@|\meta{n}|@stream| is a % stream name allocated by \cs\newwrite. |\nc@auxout@|\meta{n}|@inuse| is a % global boolean which is |true| iff the corresponding stream is currently in % use. % \begin{macrocode} \InitWheel\nc@aux@wheel % \end{macrocode} % \end{macro} % % \begin{macro}{\nc@count} % We need an internal counter. Notice that the stream numbers used in the % auxwheel start at 0, so the stream associated with with the numeral 4 is % the fifth stream. % \begin{macrocode} \newcounter{nc@count} % \end{macrocode} % \end{macro} % % \begin{macro}{\nc@aux@wheel@size} % \cname{nc@aux@wheel@size} is a pseudo-counter that holds the present size % of the aux wheel. In the static case it never changes and is set only for % consistency. % \begin{macrocode} \ReserveCS\nc@aux@wheel@size % \end{macrocode} % \end{macro} % % \begin{macro}{\NextAux} % \mbox{} % \begin{macrocode} \ReserveCS\NextAux % \end{macrocode} % \end{macro} % % The kernel allocates two streams for the include system, \cname{@mainaux} and % \cname{@partaux}. The auxwheel is initialized with these two streams. The % first, corresponding to the principle source, is always marked in use. % % \todo{Reserve the stream names.} % \begin{macrocode} \newboolean{@nc@auxout@1@inuse@} \ReserveName{nc@auxout@1} \NewName*{nc@auxout@1} {} {1} \ReserveName{nc@auxout@1@stream} \expandafter\let\csname nc@auxout@1@stream\endcsname\@partaux % \end{macrocode} % % \begin{macro}{\nc@init@aux@wheel} % We initialize the wheel with the first spoke. % \begin{macrocode} \newcommand\nc@init@aux@wheel {% \EExpand\csname nc@auxout@1\endcsname\In {% \AddSpokes\nc@aux@wheel##1% } } % \end{macrocode} % \end{macro} % % \subsubsection{Static allocation} % % \begin{macro}{\StaticAux} % nonpositive numbers are treated the same as~1. \todo{bounds check; the % counter's max should be one less than the number, since we have stream 0.} % \begin{macrocode} \newcommand\StaticAux [1] {% \def\nc@aux@wheel@size {#1} \setcounter{nc@count}{2} \nc@init@aux@wheel \@whilenum \value{nc@count} <= \nc@aux@wheel@size \do {% % \end{macrocode} % First define the macros that make up the wheel itself to be their spoke % numbers. % \begin{macrocode} \eExpand*\thenc@count\In {% \NewName*{nc@auxout@\thenc@count} {} {% ##1% }% } % \end{macrocode} % Next allocate the corresponding stream. % \begin{macrocode} \EExpand\csname nc@auxout@\thenc@count@stream\endcsname\In {% \@nameuse{newwrite}##1% } % \end{macrocode} % Next create the corresponding flag (they start |false|). % \begin{macrocode} \provideboolean{@nc@auxout@\thenc@count @inuse@} % \end{macrocode} % Now add the spoke itself. % \begin{macrocode} \EExpand\csname nc@auxout@\thenc@count\endcsname\In {% \ReserveCS#1% \AddSpokes\nc@aux@wheel##1% } \stepcounter{nc@count} } \def\NextAux {% \Roll\nc@aux@wheel \@nameuse{if@nc@auxout@\Top\nc@aux@wheel @inuse@}% \MonsterError{newclude} {% You can't nest \protect\include this deeply!% }% \else \Elet\@auxout\csname nc@auxout@\Top\nc@aux@wheel @stream\endcsname \fi }% } % \end{macrocode} % \end{macro} % % \subsubsection{Dynamic allocation} % % \begin{macro}{\DynamicAux} % \begin{macro}{\nc@addnewauxstream} % \mbox{} % \begin{macrocode} \newcommand\DynamicAux {% \def\nc@aux@wheel@size {1} \nc@init@aux@wheel \def\NextAux {% \Roll\nc@aux@wheel \@nameuse{if@nc@auxout@\Top\nc@aux@wheel @inuse@}% \nc@addnewauxstream \fi % \end{macrocode} % Either the top spoke was not in use, or we have added a fresh spoke at the % top -- so the top spoke represents what we want. % \begin{macrocode} \Elet\@auxout\csname nc@auxout@\Top\nc@aux@wheel @stream\endcsname \typeout{NextAux has just set auxout to stream \the\csname nc@auxout@\Top\nc@aux@wheel @stream\endcsname. We are using spoke number \csname nc@auxout@\Top\nc@aux@wheel\endcsname.} }% } % \end{macrocode} % It works out that the new spoke should have a spoke number one greater than % the current wheel size. We use the |nc@count| counter to find this number. % \begin{macrocode} \newcommand\nc@addnewauxstream {% \setcounter{nc@count}{\nc@aux@wheel@size}% \stepcounter{nc@count}% \typeout{Allocating another spoke (spoke number \thenc@count)}% % \end{macrocode} % First we add the spoke itself, then initialize the corresponding objects. % \begin{macrocode} \EExpand*\csname nc@auxout@\thenc@count\endcsname\In {% \AddSpokes\nc@aux@wheel##1% }% \EExpand*\thenc@count\In {% \DefName*{nc@auxout@##1} {} {##1}% \provideboolean{@nc@auxout@##1@inuse@}% \def\nc@aux@wheel@size {##1}% \EExpand*\csname nc@auxout@##1@stream\endcsname\In {% \@nameuse{newwrite}####1% }% }% } \DynamicAux % \end{macrocode} % \end{macro} % \end{macro} % % \subsubsection{Including} % % \begin{macro}{\nc@include} % The only way I see how to set the |inuse| flag to |false| at the proper % time is to use the \package{afterpage} package. What I would really like % is to \cs\write something with side effects. % \begin{macrocode} \newcommand\nc@include [2][] {% \if@filesw \immediate\write\@mainaux{\string\@input{#2.aux}}% \fi \@tempswatrue \if@partsw \@tempswafalse \edef\reserved@b{#2}% \@for\reserved@a:=\@partlist\do {\ifx\reserved@a\reserved@b\@tempswatrue\fi}% \fi \if@tempswa \stepcounter{IncludeDepth}% % \end{macrocode} % \cname{nc@t@c} is going to preserve the current \ext{aux} stream number to % restore \cname{@auxout}, in case there is a nested \cs\include. % \begin{macrocode} \edef\nc@t@c {% \the\@auxout }% \if@filesw \NextAux \openout\@auxout #2.aux \write\@auxout{\relax}% \expandafter\global \csname @nc@auxout@\Top\nc@aux@wheel @inuse@true\endcsname % \end{macrocode} % \begin{macro}{\nc@include@finish@} % The next line defines the macro |\nc@include@finish@|\meta{n} to close the % output stream that is presently open. We have an interesting task here of % getting certain unique information to macros after the \cname{@input} when we % might end up recursing during the \cname{@input}. To do this, we immediately % expand the variables we need and store them in a macro which will \emph{not} % be altered by a recursion of \cs\include. We have set up the |IncludeDepth| % counter to allow us to define such a macro, which is unique to \emph{this} % instance of \cs\include. % % \begin{warning} % The macro names |\nc@include@finish@|\meta{n} where \meta{n} is an % integer are overwritten, that is, they are not allocated in a safe way. % \end{warning} % % The following lines are intended to make this definition, where || % represents the current value of |IncludeDepth|, |

| represents the spoke % number of the current top of \cname{nc@aux@wheel}, and || represents the % stream number for the current part, i.e., the current value of % \cname{@auxout}, and || represents the stream number that was current % before \cs\include got called (this is saved in \cname{nc@t@c}). % \begin{codeexample} % \def\nc@include@finish@ {% % \closeout% % \global\chardef\@auxout=% % \afterpage{\global\@nc@auxout@

@inuse@false} % } % \end{codeexample} % \begin{macrocode} \EExpand\theIncludeDepth\In {% ##1 \EExpand\the\@auxout\In {% ####1 \DefName{nc@include@finish@##1} {} {% \closeout####1% \global\chardef\@auxout=\nc@t@c \typeout{Restored auxout to stream number \nc@t@c \space (old: \the\@auxout)} \typeout{executing afterpage}% \EExpand\csname @nc@auxout@\Top\nc@aux@wheel @inuse@false\endcsname\In {% ########1 \afterpage{% \typeout{Finishing. auxout is now \the\@auxout; current spoke is \csname nc@auxout@\Top\nc@aux@wheel\endcsname\space with stream number \the\csname nc@auxout@\Top\nc@aux@wheel @stream\endcsname }% \global########1% }% Afterpage }% EExpand }% DefName }}% EExpand \fi % \if@filesw \nc@t@b % surround the \include with something % \end{macrocode} % Now execute the text of the optional argument to \cs\include. Notice that if % we change to a new \ext{aux} file, we should do it before the optional % argument. This is important so that sectioning commands will appear in the % right order. If the sectioning command were to write to \cname{@mainaux}, % then it would come \emph{after} the whole included \ext{aux} file, instead of % before it. % \begin{macrocode} #1% \@input@{#2.tex}% \@writeckpt{#2}% \if@filesw \csname nc@include@finish@\theIncludeDepth\endcsname \fi \nc@t@b % surround the \include with something % \end{macrocode} % We mustn't restore the counter before we have finished using it. % \begin{macrocode} \addtocounter{IncludeDepth}{\m@ne}% % \end{macrocode} % If the file is excluded by the \cs\includeonly command, we don't load it and % execute the file's checkpoint instead. % \begin{macrocode} \else \@nameuse{cp@#2}% \fi } % \end{macrocode} % \end{macro} % \end{macro} % % \subsubsection{Checkpoints} % % \begin{macro}{\@writeckpt} % \begin{macro}{\@wckptelt} % We must redefine the macros which write the checkpoints. \cname{@auxout} % is substituted for \cname{@partaux}; I think this change should be in the % kernel anyway! And we remove the \cs\immediate{}s. % \begin{macrocode} \defcommand\@writeckpt [1] {% \if@filesw \write\@auxout{\string\@setckpt{#1}\@charlb}% \begingroup \let\@elt\@wckptelt \cl@@ckpt \endgroup \write\@auxout{\@charrb}% \fi } \defcommand\@wckptelt [1] {% \protected@write\@auxout{}{\string\setcounter{#1}{\the\@nameuse{c@#1}}}% } % \end{macrocode} % \end{macro} % \end{macro} % % \subsubsection{Wheels} % % \begin{macro}{\InitWheel} % \begin{macro}{\Roll} % \begin{macro}{\IfTop} % \begin{macro}{\Top} % \begin{macro}{\AddSpokes} % A wheel is implemented as a macro. The tokens of its first-level expansion % are the spokes, the top being the first. % \begin{macrocode} \newcommand\InitWheel [1] {% args: wheel \InitCS#1% } \newcommand\Roll [1] {% args: wheel \edef #1{% \expandafter\nc@roll #1\nc@llor }% } \ReserveCS\nc@llor \NewNameDef{nc@roll} {#1\nc@llor} {% \@cdr#1\@nil\@car#1\@nil } \newcommand\Top [1] {% args: wheel \E@car #1\@nil } \newcommand\IfTop [4] {% args: wheel token true false \EExpand#1\In {% \edef\nc@t@b {% \expandafter\noexpand\@car##1\@nil }% }% % \end{macrocode} % At this point, the first-level expansion of \cname{nc@t@b} is a single token, % the top of the wheel. We \cs\let \cname{nc@t@a} to this token. % \begin{macrocode} \Elet\nc@t@a\nc@t@b \let\nc@t@b #2% \ifx\nc@t@a\nc@t@b \expandafter\@firstoftwo \else \expandafter\@secondoftwo \fi } \newcommand\AddSpokes [2] {% args: wheel spokes \EExpand#1\In {% \def #1{#2##1}% }% } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro}