% \iffalse %% %% (C) Copyright 1999 Frank Mittelbach %% All rights reserved. %% %% Not for general distribution. In its present form it is not allowed %% to put this package onto CD or an archive without consulting the %% the authors. %% % \begin{macrocode} \def\next#1: #2.dtx,v #3 #4 #5 #6 #7$#8{ %<*dtx> \ProvidesFile{#2.dtx} % %\ProvidesPackage{#2} %\ProvidesFile{#2.drv} [#4 #3 #8 (#6)]} \next$Id: xmarks.dtx,v 1.6 2000/06/13 20:47:23 latex3 Exp $ {multiple marks} % \end{macrocode} % %<*driver> \documentclass{ltxdoc} % \begin{document} \DocInput{xmarks.dtx} \end{document} % % % \fi % % % \GetFileInfo{xmarks.dtx} % % \title{The \textsf{xmarks} package\thanks{This file % has version number \fileversion, last % revised \filedate.}} % \author{FMi} % \date{\filedate} % % \maketitle % % \tableofcontents % % % % \section{Mark algorithm} % % To allow for completely independent marks we use the following % procedure: % \begin{itemize} % \item % For every mark of type \meta{type} we have a queue that holds every mark % info found in memory. Every info is associated with a unique number, % i.e., we simply count them. The queue always holds at least one item % which is the previous mark info, i.e., the last mark for that type on % the previous page. % % \item % We use \TeX's internal mark mechanism only to record the associated % numbers for marks for every type on the current page. % % \item % For every \meta{type} we record the info-number that belongs to the last % mark of the previous page. % % \item % By looking at \TeX's internal |\botmark| we can determine the % info-number of the last mark for every \meta{type} that is on the current % page. % % \item % The difference between this number and the info-number from the last % page gives us the number of marks for every \meta{type} on the current page. % % \item % That way we are able to decide how to extract items from the queue so % that first, last, and previous mark for every type can be accessed. % \begin{itemize} % \item % If the difference is zero, no new marks have been added on the % current page, therefore the only item on the corresponding mark type % queue holds the info that should be previous, first, and last mark of % this type for the current page. % \item % If the difference is one, then the first item in the queue represents % the info that should become the previous mark (it will be popped off) % and the second item (which will be kept, since it will become the % previous mark for the next page) should become first and last mark for % the current page. % \item % Otherwise we had at least two marks for this type on the current page. % Therefore, the first item in the queue will become previous mark (popped % off), the second will become first mark (popped off), then we pop off % all but the last item in the queue, which will become last mark, by only % looking at it. % \end{itemize} % In other words every queue should hold only one item after this part of % the algorithm has acted. % After this is done we save the info-numbers given by |\botmark| % as the info-numbers of the last page, so that they are available next time. % % \item % Putting a mark into the galley therefore means to put its info to the % right of the corresponding queue, increment the current info-number for % \meta{type} by one and putting a \TeX{} mark into the galley holding the % current info-numbers for all \meta{types}. % % \end{itemize} % % % \subsection{Restrictions} % % One restriction in using this algorithm without further refinements % is that for every \meta{type} there will be an upper limit of marks allowed % within one document. This upper limit is given by |\maxdimen| which is % probably high enough to ignore it, but it could be improved by resetting % the info numbers whenever all marks have found their way onto the % current page. % % Another restriction is that one better not changes from linearily % processing the data for the main galley, or, if one modifies that % processing one needs to carefully adjust the data structures for the % marks as well. The problem being that the individual marks within a % preprocessed galley will stay there forever (and thus can be parsed % several times), the external data structures, e.g., the plists and % the sequences however need manual corrections in that case. % % \subsection{Implementation} % % The original implementation was done on a portable PC in a train % sometime in 1992/93 and is just a straight implementation of the % above algorithm using plists to hold the current and the last % info-numbers. The whole stuff could be done much better by analysing % the algorithm combining common parts (a lot of thing have be done % twice, etc.) and recoding the rest in a better way. % % The implementation below is more or less a straight adaption % of that code, so it still needs a rewrite one day. It is based on % modules implementing ``queues'', ``property lists'', and ``quarks'' % most of which have been published as experimental code with a % slightly different surface syntax, i.e., as \texttt{l3seq.sty}, % \texttt{l3prop.sty}, and \texttt{l3quark.sty}. % % New stuff: % \begin{macrocode} \RequirePackage{ldcsetup} \IgnoreWhiteSpace % \end{macrocode} % % \begin{macrocode} \long\def\@firstofthree#1#2#3{#1} \long\def\@secondofthree#1#2#3{#2} \long\def\@thirdofthree#1#2#3{#3} % \end{macrocode} % % \begin{macrocode} \def \tlp@to@str@N {\expandafter \tlp@to@str@aux \meaning} \def \tlp@to@str@aux #1>{} \def \tlp@to@str@c #1 {\expandafter \tlp@to@str@N \csname#1\endcsname} % \end{macrocode} % % % % % % \subsection{Commands for manipulating queues} % % \begin{macro}{\trace@queue} % \begin{macro}{\trace@queue@internal} % \begin{macro}{\tracingqueues} % \begin{macrocode} %<*trace> \def\trace@queue#1{\ifnum \tracingqueues > \z@ \typeout{Queues:~ #1~ \on@line}\fi} \def\trace@queue@internal#1{\ifnum\tracingqueues>\@ne \typeout{Queues:~ #1~ \on@line}\fi} \newcount\tracingqueues % % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\queue@new@c} % \begin{macrocode} \def\queue@new@c#1{\@namedef{#1}{}} % \end{macrocode} % \end{macro} % % \begin{macro}{\queue@gadd@Nn} % \begin{macrocode} \def\queue@gadd@Nn#1#2{\expandafter\gdef\expandafter#1\expandafter {#1\queue@elt#2\queue@eelt} %<*trace> \trace@queue@internal{add~ `#2'~ to~ queue~ \string#1} % } % \end{macrocode} % \end{macro} % % % \begin{macro}{\queue@gadd@cn} % \begin{macrocode} \def\queue@gadd@cn#1{\expandafter\queue@gadd@Nn\csname#1\endcsname} % \end{macrocode} % \end{macro} % % \begin{macro}{\queue@top@NN} % \begin{macrocode} \def\queue@top@NN#1#2{ \queue@empty@err@N#1 \expandafter\queue@top@split@w#1\q@stop{\def#2} %<*trace> \trace@queue@internal{top~ of~ queue~\string#1:~`\tlp@to@str@N#2'} % } % \end{macro} % % \begin{macro}{\queue@top@split@w} \def\queue@top@split@w\queue@elt#1\queue@eelt#2\q@stop#3{#3{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\queue@top@cN} % \begin{macrocode} \def\queue@top@cN#1{\expandafter\queue@top@NN\csname#1\endcsname} % \end{macrocode} % \end{macro} % % % % \begin{macro}{\queue@pop@aux@nnNN} % \begin{macro}{\queue@pop@aux@w} % \begin{macrocode} \def \queue@pop@aux@nnNN #1#2#3{ \queue@empty@err@N #3 \expandafter\queue@pop@aux@w #3\q@stop #1#2#3} \def \queue@pop@aux@w \queue@elt#1\queue@eelt #2\q@stop #3#4#5#6{#3#5{#2}#4#6{#1}} % \end{macrocode} % \end{macro} % \end{macro} % % % \begin{macro}{\queue@gpop@NN} % \begin{macrocode} \def \queue@gpop@NN #1#2{\queue@pop@aux@nnNN \gdef \def #1 #2 %<*trace> \trace@queue@internal{pop~ of~ queue~\string#1:~`\tlp@to@str@N #2'} % } % \end{macrocode} % \end{macro} % % % \begin{macro}{\queue@gpop@cN} % \begin{macrocode} \def \queue@gpop@cN #1{\expandafter\queue@gpop@NN\csname#1\endcsname} % \end{macrocode} % \end{macro} % % % \begin{macro}{\queue@empty@err@N} % \begin{macrocode} \def\queue@empty@err@N #1{\ifx#1\@empty \ERROR \fi} % \end{macrocode} % \end{macro} % % % % % % % % % % \subsection {Quarks} % % A quark is a control sequence that expands into itself@ |\def| % |\foo{\foo}|. Quarks provide a cheap way of generating distinct % constants. Also, they permit the following ingenious trick: when % you pick up a token in a temporary, and you want to know whether you % have picked up a particular quark, all you have to do is compare the % temporary to the quark using |\ifx|. % % \begin{macro}{\quark@new@N} % Allocate a new quark. % \begin{macrocode} \def \quark@new@N #1{\def #1{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\q@stop} % \begin{macro}{\q@no@value} % \begin{macro}{\q@nil} % |\q@stop| is often used as a marker in parameter text, % |\q@no@value| is the canonical missing value, and |\q@nil| % represents a nil pointer in some data structures. % \begin{macrocode} \quark@new@N \q@stop \quark@new@N \q@no@value \quark@new@N \q@nil % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\q@error} % \begin{macro}{\q@mark} % We need two additional quarks. |\q@error| delimits the end of % the computation for purposes of error recovery. |\q@mark| is % used in parameter text when we need a scanning boundary that is % distinct from |\q@stop|. % \begin{macrocode} \quark@new@N\q@error \quark@new@N\q@mark % \end{macrocode} % \end{macro} % \end{macro} % % % \begin{macro}{\quark@if@no@value@NTF} % \begin{macro}{\quark@if@no@value@NF} % \begin{macro}{\quark@if@no@value@nTF} % \begin{macro}{\quark@if@no@value@nT} % \begin{macro}{\quark@if@no@value@nF} % Here we test if we found a special quark as the first argument. % The argument might contain an arbitrary list of tokens, therefore % we have to wrap it up in a token list pointer. % \begin{macrocode} \def \quark@if@no@value@NTF #1{ % \end{macrocode} % We better start with |\q@no@value| as the first argument since % the whole thing may otherwise loop if |#1| is wrongly given % a string like |aabc| instead of a single token.\footnote{It may % still loop in special circumstances however!} % \begin{macrocode} \ifx\q@no@value#1 \expandafter\@firstoftwo \else \expandafter\@secondoftwo \fi} % \end{macrocode} % It would be possible to speed up the following commands by % providing individual implementations similar to the one above. % Should perhaps be done if they are used often! % \begin{macrocode} \def \quark@if@no@value@NF #1{\quark@if@no@value@NTF {#1}\@empty} \def \quark@if@no@value@nTF #1{\gdef \@gtempa {#1} \quark@if@no@value@NTF\@gtempa} \def \quark@if@no@value@nF #1{\quark@if@no@value@nTF {#1}\@empty} \def \quark@if@no@value@nT #1#2{\quark@if@no@value@nTF {#1} {#2}\@empty} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\quark@if@nil@NTF} % A function to check for the presence of |\q@nil|. % \begin{macrocode} \def\quark@if@nil@NTF#1{ \ifx#1\q@nil \expandafter\@firstoftwo \else \expandafter\@secondoftwo\fi} % \end{macrocode} % \end{macro} % % % % % \subsection{Commands for manipulating property lists} % % % \begin{macro}{\prop@new@N} % \begin{macrocode} \def \prop@new@N #1{\def #1{}} % \end{macrocode} % \end{macro} % % \begin{macro}{\prop@put@NNn} % \begin{macro}{\prop@gput@NNn} % \begin{macro}{\prop@gput@NNo} % \begin{macro}{\prop@gput@cco} % \begin{macro}{\prop@gput@ccn} % \begin{macrocode} \long\def \prop@put@NNn #1#2{\prop@split@aux@NNn #1#2{\prop@put@aux@w {\def #1}#2}} \long\def \prop@gput@NNn #1#2{\prop@split@aux@NNn #1#2{\prop@put@aux@w {\gdef #1}#2}} % missing commands for galley stuff... \def \prop@gput@NNo #1#2#3{ \expandafter\prop@gput@NNn \expandafter #1 \expandafter #2 \expandafter { #3 } } \def \prop@gput@cco #1#2#3{ \expandafter\prop@gput@NNn \csname #1\expandafter\endcsname \csname #2\expandafter\endcsname \expandafter { #3 } } \def \prop@gput@ccn #1#2{ \expandafter\prop@gput@NNn \csname #1\expandafter\endcsname \csname #2\endcsname } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % % \begin{macro}{\prop@put@aux@w} % \begin{macrocode} \long\def \prop@put@aux@w #1#2#3#4#5#6{ \quark@if@no@value@nTF {#4} {#1{#2{#6}#3}} {\def\tmp@w ##1#2\q@no@value {#1{#3#2{#6}##1}} \tmp@w #5}} % \end{macrocode} % \end{macro} % % \begin{macro}{\prop@split@aux@NNn} % \begin{macrocode} \long\def \prop@split@aux@NNn #1#2#3{ \def\tmp@w ##1#2##2##3\q@stop {#3{##1}{##2}{##3}} % ^ ^ needed! \expandafter\tmp@w #1#2\q@no@value \q@stop} % \end{macrocode} % \end{macro} % % % \begin{macro}{\prop@get@NNN} % \begin{macrocode} \long\def \prop@get@NNN #1#2{\prop@split@aux@NNn #1#2\prop@get@aux@w} % \end{macrocode} % \end{macro} % % % \begin{macro}{\prop@get@aux@w} % \begin{macrocode} \long\def \prop@get@aux@w #1#2#3#4{\def#4{#2}} % \end{macrocode} % \end{macro} % % % \begin{macro}{\prop@map@funct@Nn} % \begin{macrocode} \let \prop@map@funct@Nn \@gobbletwo % \end{macrocode} % \end{macro} % % % \begin{macro}{\prop@map@NN} % \begin{macrocode} \def \prop@map@NN #1#2{ \let \prop@map@funct@Nn #2 \expandafter\prop@map@aux@w #1\q@stop \q@stop} % \end{macrocode} % \end{macro} % % % \begin{macro}{\prop@map@aux@w} % \begin{macrocode} \def \prop@map@aux@w #1#2{ \ifx #1\q@stop \else \prop@map@funct@Nn #1{#2} \expandafter\prop@map@aux@w \fi} % \end{macrocode} % \end{macro} % % \begin{macro}{\prop@map@cN} % \begin{macrocode} \def \prop@map@cN #1{ \expandafter \prop@map@NN \csname #1\endcsname } % \end{macrocode} % \end{macro} % % % % % % % % \subsection{Commands for manipulating marks} % % % % \begin{macro}{\trace@mark} % \begin{macro}{\trace@mark@internal} % \begin{macro}{\tracingmarks} % Tracing is done when |\tracingmarks| is positive. % \begin{macrocode} %<*trace> \def\trace@mark#1{\ifnum \tracingmarks > \z@ \typeout{Marks:~ #1~ \on@line}\fi} \def\trace@mark@internal#1{\ifnum\tracingmarks>\@ne \typeout{Marks:~ #1}\fi} \newcount\tracingmarks % % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\mark@new} % Defines a new mark label and retrieval token list pointer. % \begin{macrocode} \def\mark@new#1{ %<*trace> \trace@mark {new~mark:~\string#1} % % \end{macrocode} % We make sure that the argument is still free and allocate the % corresponding queue. To avoid problems with the use of such tlp's % when they are used before the first |\mark@update@structure| we initialize % them in a way that |\mark@previous| and the like will accept them even % then. % \begin{macrocode} \newcommand* #1 {{}{}{}} \queue@new@c{\string#1@seq} % \end{macrocode} % The last info-number for this type will be set to |1| This value % is actually arbitrary and we could use |-\maxdimen+1| to get the % range doubled. % \begin{macrocode} \prop@gput@NNn\mark@last@plist#1{1} % \end{macrocode} % More important is that the starting value for the current % info-number is one less then the one used above. % \begin{macrocode} \prop@gput@NNn\mark@curr@plist#1{0} % \end{macrocode} % We now put the very first mark of this type in. This mark will be % empty. This will initialize the queue (now holding the empty previous % mark) increment the current info number, so that last and current are % now equal and also puts a \TeX{} mark into the galley will the % additional type present. % \begin{macrocode} \mark@put@Nn#1{}% % \end{macrocode} % \begin{macrocode} \expandafter\g@addto@macro\expandafter\mark@save@state\expandafter{% \expandafter\global\expandafter\let \csname saved\string#1@seq\expandafter\endcsname \csname\string#1@seq\endcsname} \expandafter\g@addto@macro\expandafter\mark@restore@state@internal\expandafter{% \expandafter\global\expandafter\let \csname\string#1@seq\expandafter\endcsname \csname saved\string#1@seq\endcsname} } % \end{macrocode} % \end{macro} % % % % \begin{macro}{\mark@save@state} % \begin{macro}{\mark@restore@state@internal} % Save and restore the current state of the mark data % structure. The commands will be extended by |\mark@new|. They are % needed if part of the main galley is being reused or several % times parsed. % \begin{macrocode} \def\mark@save@state{% \global\let\saved@mark@curr@plist\mark@curr@plist \global\let\saved@mark@last@plist\mark@last@plist} \def\mark@restore@state@internal{% \global\let\mark@curr@plist\saved@mark@curr@plist \global\let\mark@last@plist\saved@mark@last@plist} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\mark@restore@state} % |\mark@restore@state| will restore the state of the mark % mechanism to the one saved by |\mark@save@state|. It has to be % called inside an output routine and as it needs an output routine % of its own to restore the |\mark| status of the bottom mark (so % that \TeX{} correctly updates the mark registers in case it % doesn't find a mark in box 255) it has an argument which is % executed inside that output routine to regain control. % % The code in the argument has to set |\output| to a new output % routine! If not you are in trouble. % % \begin{macrocode} \def\mark@restore@state#1{% %<*trace> \@tracepush{mark@restore@state} % % \end{macrocode} % We first restore the external data structures by calling % |\mark@restore@sate@internal|. Then we have to ensure that \TeX's % idea of what the current |\botmark| is, corresponds to what it % was when we saved the state. Back then it was the contents of % |\mark@last@plist| so we are now adding an empty box and then % mark with is contents % onto the MVL followed by a penalty that ensures we trigger the % output routine and then specify a tiny little output routine % whose sole purpose is to get that mark processed. % \begin{macrocode} \mark@restore@state@internal \hbox{}% % \end{macrocode} % We have to protect |\mark@last@plist| from expanding too far % inside the |\mark| so we first put it into a token register % before applying |\mark|. % \begin{macrocode} \@temptokena\expandafter{\mark@last@plist}% %<*trace> \trace@mark@internal{restoring~ botmark~ \the\@temptokena}% % \mark {\the\@temptokena} \penalty-20203\relax % \end{macrocode} % We are not setting |\vsize| assuming its positive. So the moment % we return from the current output routine (we are hopefully in % right now) we should very very soon find the above penalty and % then trigger the output routine we are about to define now. % % In that output routine we have a quick test for the % |\outputpenalty| just to ensure that we really grabbed what we % are supposed to grab. Then we throw away the contents of box 255 % since all we wanted todo is to get |\botmark| set back to the % value of our mark above. Finally we execute whatever got passed % along as argument one to regain control. Since current |\output| % has a rather funny definition the code in that argument better % change that back to something that does a little bit more % typesetting. % \begin{macrocode} \global\output{% %<*trace> \@tracepush{mark@restore@state@or} % \ifnum-20203=\outputpenalty\else \ERROR \fi \global\setbox\@cclv\box\voidb@x #1% %<*trace> \@tracepop{mark@restore@state@or} % }% %<*trace> \@tracepop{mark@restore@state} % } % \end{macrocode} % \end{macro} % % % \begin{macro}{\mark@put@Nn} % To put a mark into the current horizontal or vertical \TeX{} list % we first update |\mark@curr@plist| and then put its value into the % mark without any further expansion. (The code could be % optimized!) % \begin{macrocode} %<-trace>\def\mark@put@Nn#1{% % wtest hack } %<*trace> \def\mark@put@Nn#1#2{ \def\l@tmpa@tlp{#2} \trace@mark {set~\string#1~<-~\tlp@to@str@N\l@tmpa@tlp} % % \end{macrocode} % First we have to update the current info number for this type. The % code is a bit complicated because we have to get the number from the % the plist update it and then put it back. If we would keep the numbers % differently this could be improved, probably at the cost of more macro % names. % \begin{macrocode} \@temptokena\expandafter{\mark@curr@plist} \prop@get@NNN\mark@curr@plist#1\@tempa %<*debug> \ifx\q@no@value\@tempa \ERROR \fi % \@tempcnta\@tempa \advance\@tempcnta\@ne \expandafter \prop@gput@NNn\expandafter\mark@curr@plist\expandafter#1\expandafter {\the\@tempcnta} % \end{macrocode} % Now we want to put this plist into a \TeX{} mark. We need a % one-level expansion, otherwise our pkeys would expand which would % produce chaos. So we save it in a toks register. % \begin{macrocode} \@temptokena\expandafter{\mark@curr@plist} \mark {\the\@temptokena} % \end{macrocode} % Finally we shouldn't forget to put the info at the right of the % corresponding queue. % Without tracing we can omit the second argument to % this function. % \begin{macrocode} %<*trace> \queue@gadd@cn{\string#1@seq}{#2} % %<-trace> \queue@gadd@cn{\string#1@seq}% } % \end{macrocode} % \end{macro} % % % % % \begin{macro}{\mark@put@Nnn} % \begin{macrocode} \def\mark@put@Nnn#1#2#3{ \mark@put@Nn#1{#2#3}} % \end{macrocode} % \end{macro} % % % % % \begin{macro}{\mark@update@structure} % This function is for use in output routines to initialize the marks % at the beginning. It is only useful after \TeX{} internally has % updated |\botmark|. % \begin{macrocode} \def\mark@update@structure{ % \end{macrocode} % We map a function over all keys in |\mark@last@plist|, in other % words over all types of marks. This routine will set the marks for % all types. Finally we set the plist |\mark@last@plist| to the % plist that was stored in |\botmark|, i.e., to the % info-numbers from this page. % \begin{macrocode} \prop@map@NN\mark@last@plist\mark@retrieve@single@Nn \expandafter\gdef\expandafter\mark@last@plist\expandafter{\botmark} } % \end{macrocode} % \end{macro} % % % % \begin{macro}{\mark@retrieve@single@Nn} % This function will be mapped over the plist containing the info-numbers % from the last page. This means that |#1| will be the key (which is % simply our type token list pointer and |#2| is the value, i.e. the % info-number from the last page for this type. % \begin{macrocode} \def\mark@retrieve@single@Nn#1#2{ %<*trace> \trace@mark@internal {queue~for~\string#1~ before:~`\tlp@to@str@c{\string#1@seq}'} % % \end{macrocode} % We retrieve the info number for this type from |\botmark| % and store the difference in |\@tempcnta|. % \begin{macrocode} \@temptokena\expandafter{\botmark}% %<*trace> \trace@mark@internal{picking~ up~ from~ output~ \the\@temptokena}% % \prop@get@NNN\botmark#1\@tempa %<*debug> \ifx\q@no@value\@tempa \ERROR \fi % \@tempcnta\@tempa \advance\@tempcnta-#2\relax %<*trace> \trace@mark@internal {found~\the\@tempcnta\space entries~ for~ \string#1~ (new~\@tempa;~old~#2)} % % \end{macrocode} % Then we decide what to do depending on its value. % We use |\@tempa|, |\@tempb|, and |\@tempc| to % temporarily hold the previous, first and last mark for this type. % \begin{macrocode} \ifcase\@tempcnta % \end{macrocode} % If there haven't been any new marks we leave the queue alone, % peeking only at its top element and using it for all three marks. % \begin{macrocode} \queue@top@cN{\string#1@seq}\@tempa \let\@tempb\@tempa \let\@tempc\@tempa \or % \end{macrocode} % When there was one mark of this type, we pop one item for the % previous mark of this type, and use the remaining item for first % and last mark. % \begin{macrocode} \queue@gpop@cN{\string#1@seq}\@tempa \queue@top@cN{\string#1@seq}\@tempb \let\@tempc\@tempb \else % \end{macrocode} % If we had more than one mark for this type we pop one mark for the % previous mark of this type, then pop another mark for the first % mark of this type, then pop all but the last item and use the last % item as the last mark of this type, keeping it as before on the % queue. % \begin{macrocode} \queue@gpop@cN{\string#1@seq}\@tempa \queue@top@cN{\string#1@seq}\@tempb \@whilenum \@tempcnta>\@ne\do {\advance\@tempcnta\m@ne \queue@gpop@cN{\string#1@seq} \@tempc } \queue@top@cN{\string#1@seq}\@tempc \fi % \end{macrocode} % After this process all values for previous, first and last mark for % this type are found so that we can store them in the tlp % representing this type for further processing. % \begin{macrocode} \@temptokena\expandafter{\@tempa} \@temptokenb\expandafter{\@tempb} \@temptokenc\expandafter{\@tempc} \edef#1{{\the\@temptokena}{\the\@temptokenb}{\the\@temptokenc}} %<*trace> \trace@mark {in~output:~\string#1~->~\tlp@to@str@N#1} % \end{macrocode} % At this point the queue should show only one item. % \begin{macrocode} \trace@mark@internal {queue~ for~\string#1~after:~`\tlp@to@str@c{\string#1@seq}'} % } % \end{macrocode} % \end{macro} % % \begin{macro}{\@temptokenb} % \begin{macro}{\@temptokenc} % \begin{macrocode} \newtoks\@temptokenb \newtoks\@temptokenc % \end{macrocode} % \end{macro} % \end{macro} % % % \begin{macro}{\mark@curr@plist} % \begin{macro}{\mark@last@plist} % Here are the allocations for the two plists used. % \begin{macrocode} \prop@new@N\mark@curr@plist \prop@new@N\mark@last@plist % \end{macrocode} % \end{macro} % \end{macro} % % % % % % % \begin{macro}{\mark@get@first@N} % \begin{macro}{\mark@get@last@N} % \begin{macro}{\mark@get@previous@N} % To retrieve the first, last or previous page mark, we % grap the appropriate value stored in the tlp. The marks are stored % in the tlp in the order previous, first, last mark. These functions % should be used only in output routines after |\mark@retrieve| has % acted, otherwise their value will be wrong. They are all fully % expandable. % % Actually, they may bomb when tracing is included and we have % material that doesn't work corretly within a write. % \begin{macrocode} %<*trace> \def\mark@get@first@N#1{ \expandafter\@secondofthree#1 \trace@mark@internal{use~first~\string#1~=~ `\expandafter\@secondofthree#1'} } \def\mark@get@last@N#1{ \expandafter\@thirdofthree#1 \trace@mark@internal{use~ last~ \string#1~ =~ `\expandafter\@thirdofthree#1'} } \def\mark@get@previous@N#1{ \expandafter\@firstofthree#1 \trace@mark@internal{use~prev~\string#1~ =~ `\expandafter\@firstofthree#1'} } % %<-trace>\def\mark@get@first@N{% %<-trace> \expandafter\@secondofthree} %<-trace>\def\mark@get@last@N{% %<-trace> \expandafter\@thirdofthree} %<-trace>\def\mark@get@previous@N{% %<-trace> \expandafter\@firstofthree} % \end{macrocode} % above version in trace case doesn't work alway! % \begin{macrocode} \def\mark@get@first@N{% \expandafter\@secondofthree} \def\mark@get@last@N{% \expandafter\@thirdofthree} \def\mark@get@previous@N{% \expandafter\@firstofthree} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % % \begin{macro}{\DeclareMarkType} % \begin{macrocode} \def\DeclareMarkType#1{ \expandafter\mark@new\csname mark@#1\endcsname} % \end{macrocode} % \end{macro} % % \begin{macro}{\PutMark} % \begin{macrocode} \def\PutMark#1{ \@ifundefined{mark@#1}{\ERROR}{} \expandafter\mark@put@Nn\csname mark@#1\endcsname} % \end{macrocode} % \end{macro} % % % \begin{macro}{\PreviousMark} % \begin{macrocode} \def\PreviousMark#1{ \expandafter\mark@get@previous@N\csname mark@#1\endcsname} % \end{macrocode} % \end{macro} % % \begin{macro}{\FirstMark} % \begin{macrocode} \def\FirstMark#1{ \expandafter\mark@get@first@N\csname mark@#1\endcsname} % \end{macrocode} % \end{macro} % % \begin{macro}{\LastMark} % \begin{macrocode} \def\LastMark#1{ \expandafter\mark@get@last@N\csname mark@#1\endcsname} % \end{macrocode} % \end{macro} % % \Finale % \endinput % % $Log: xmarks.dtx,v $ % Revision 1.6 2000/06/13 20:47:23 latex3 % docu update % inlined quarks code %