% \iffalse %% %% perpage is part of the bigfoot bundle for critical typesetting %% Copyright 2002, 03, 04, 05, 06 David Kastrup %% % This program is free software; you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by % the Free Software Foundation; either version 2 of the License, or % (at your option) any later version. % % This program is distributed in the hope that it will be useful, % but WITHOUT ANY WARRANTY; without even the implied warranty of % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the % GNU General Public License for more details. % % You should have received a copy of the GNU General Public License % along with this program; if not, write to the Free Software % Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA % \fi % \CheckSum{363} % \GetFileInfo{perpage.sty} % \date{\filedate} % \author{David Kastrup\thanks{\texttt{dak@gnu.org}}} % \title{The \texttt{perpage} package\\Version \fileversion} % \maketitle % \section{Description} % % The \texttt{perpage} package adds the ability to reset counters per % page and/or keep their occurences sorted in order of appearance on % the page. % % It works by attaching itself to the code for \cmd{\stepcounter} and % will then modify the given counter according to information written % to the |.aux| file, which means that multiple passes may be needed. % Since it uses the internals of the \cmd{\label} mechanism, the need % for additional passes will get announced by \LaTeX\ as ``labels may % have changed''. % % \DescribeMacro{\MakePerPage} % \begin{quote} % |\MakePerPage[2]{footnote}| % \end{quote} % will start footnote numbers with~2 on each page (the optional % argument defaults to~1). 2~might be a strange number, unless you % have used something like % \begin{quote} % |\renewcommand\thefootnote{\fnsymbol{footnote}}| % \end{quote} % and want to start off with a dagger. The starting value must not be % less than~1 so that the counter logic can detect the reset of a % counter % reliably.\footnote{This unfortunately means that you can't just use % \cmd{\alph} in order to get figures on page~10 numbered as ``10'', % ``10a'', ``10b''.} % It could be a good idea to redefine |\@cnterr| if you use a format % with limited range: at the first pass, footnotes are not reset % across pages and things like |\fnsymbol| will quickly run out of % characters to use. % % \DescribeMacro{\theperpage} % If you want to label things also on a per page base, for example % with % \begin{quote} % |\renewcommand{\thefigure}{\thepage-\arabic{figure}}| % \end{quote} % you'll have the problem that \thepage is updated asynchronously with % the real page, since \TeX\ does not know which page the figure will % end up. If you have used the |perpage| package for modifying the % figure counter, however, at the point where the counter is % incremented, the macro \cmd{\theperpage} will be set to the correct % value corresponding to the actual page location. Note that this % macro is shared between all counters, so advancing a different % counter under control of |perpage| will render \cmd{\thefigure} % incorrect. % % \DescribeMacro{\MakeSorted} % \begin{quote} % |\MakeSorted{figure}| % \end{quote} % will make the |figure| counter get `sorted': this means that counter % values will be assigned in order of appearance in the output, not in % order of appearance in the source code. For example, the order of % interspersed one- and two-column figures might get mixed up by % \LaTeX\ in the output. Making the counter sorted will fix the order % to match the order of appearance. A similar problem is when % ordinary footnotes are present in floating material (this does not % work in standard \LaTeX, but might do so when using |manyfoot.sty| % or |bigfoot.sty|): this might jumble their order in the output, and % making their counter sorted will make things appear fine again. % % While this would not fix the order in the table of figures, % fortunately the respective entries actually get written out in order % of appearance in the output anyway, so this indeed fixes the % problem. % % Manually setting the counter does not lead to reliable results in % general; as a special case, however, resetting it to zero is % recognized (this can also happen automatically when the counter is % dependent on some other counter). The point where it is reset in % the source code separates `count groups': everything in the source % before that point is assigned sorted numbers separately from % everything appearing behind it, and the sequence numbers start again % with~1 with the first item appearing in the output (not the source) % from the new count group. % % \DescribeMacro{\MakeSortedPerPage} % \begin{quote} % |\MakeSortedPerPage[2]{table}| % \end{quote} % will make the table numbers restart at 2 on each page \emph{and} % will keep them sorted, to boot. Introducing new count groups by % resetting the counter to~0 manually will not work, as it is not % clear how to handle count groups scattered between pages. You will % usually want to use something like % \begin{quote} % |\renewcommand{\thefigure}{\theperpage-\arabic{figure}}| % \end{quote} % to go along with a page-wise figure % number.\footnote{Note the use of \cmd{\theperpage} here, see above.} % Note that it would be quite silly to start the ranges with~2: this % is just an example for the optional argument in case that you ever % need it. % % \DescribeMacro{\AddAbsoluteCounter} % \begin{quote} % |\AddAbsoluteCounter{equation}| % \end{quote} % will create a counter |absequation| that will advance together with % the counter |equation| but will not get reset along with it. This % is not sorted into output order, but just runs along with the % sequence in the source file. As a special case, the counter % |abspage| is created in this manner and \cmd{\theabspage} is defined % as an arabic number that works in the same contexts as \cmd{\page} % (namely, gets properly deferred by \cmd{\protected@write}). % % \StopEventually{} % \section{The documentation driver} % This is the default driver for typesetting the docs. Running it % through as a separate file will include the code section. Running % the original |.dtx| file through will omit the code. % \begin{macrocode} %<*driver> \documentclass{ltxdoc} \usepackage{perpage} \MakePerPage{footnote} \begin{document} \OnlyDescription % \AlsoImplementation \DocInput{perpage.dtx} \end{document} % % \end{macrocode} % % \section{The package interfaces} % First identification. We just use date and version from CVS. % \begin{macrocode} %<*style> \NeedsTeXFormat{LaTeX2e} \def\next$#1: #2 #3${#2} \ProvidesPackage{perpage}[\next$Date: 2006/07/15 21:43:23 $ \next$Revision: 1.12 $ Reset/sort counters per page] % \end{macrocode} % \begin{macro}{\AddAbsoluteCounter} % adds a counter with prefix |abs| to a given counter. It typesets as % an arabic number and never gets reset. And it is advanced with the % unprefixed counter. % \begin{macrocode} \newcommand\AddAbsoluteCounter[1] {\@ifundefined{c@abs#1}{% \expandafter\newcount\csname c@abs#1\endcsname \global\value{abs#1}\@ne \global\expandafter\let\csname cl@abs#1\endcsname\@empty \expandafter\xdef\csname theabs#1\endcsname{% \noexpand\number \csname c@abs#1\endcsname}% \global\@namedef{c@pabs@#1}{\z@=\z@{% \stepcounter{abs#1}% \afterassignment}\count@}% \@addtoreset{pabs@#1}{#1}}{}} % \end{macrocode} % \end{macro} % \begin{macro}{\c@perpage} % We now create the absolute counter |perpage|: % \begin{macrocode} \AddAbsoluteCounter{page} % \end{macrocode} % \end{macro} % \begin{macro}{\theabspage} % This has to be specially defined so that it will expand as late as % \cmd{\thepage} does. Several commands set the latter temporarily % to \cmd{\relax} in order to inhibit expansion, and we will more or % less imitate its behavior when found set in that manner. % \begin{macrocode} \def\theabspage{\ifx\thepage\relax \noexpand\theabspage \else \number\c@abspage \fi} % \end{macrocode} % \end{macro} % Here follow the three commands for defining counters per page: % \begin{macro}{\MakePerPage} % This creates a counter reset per page. An optional second % argument specifies the starting point of the sequence. % \begin{macrocode} \newcommand*\MakePerPage[2][\@ne]{% \pp@makeperpage{#2}\c@pchk@{#1}} % \end{macrocode} % \end{macro} % \begin{macro}{\MakeSorted} % This will create a counter sorted in appearance on the page. No % optional argument is given: set the counter to a desired starting % value manually if you need to. Resetting it to zero will start a % new count group, setting it to other values is probably not reliable. % \begin{macrocode} \newcommand*\MakeSorted[1]{% \setcounter{#1}{\z@}% \pp@makeperpage{#1}\c@schk@{\@ne}} % \end{macrocode} % \end{macro} % \begin{macro}{\MakeSortedPerPage} % This will create output in sorted order, reset on each page. Use % an optional argument to specify the starting value per page. This % must not be~0, unfortunately. % \begin{macrocode} \newcommand*\MakeSortedPerPage[2][\@ne]{% \pp@makeperpage{#2}\c@spchk@{#1}} % \end{macrocode} % \end{macro} % All of those must only occur in the preamble since we can't do the % initialization of the counter values otherwise. % \begin{macrocode} \@onlypreamble\MakePerPage \@onlypreamble\MakeSorted \@onlypreamble\MakeSortedPerPage % \end{macrocode} % \section{Internals} % % It works in the following manner: The basic work is done through % attaching help code to the counter's reset list. Each counter has % an associated absolute id that is counted through continuously and % is never reset, thus providing a unique frame of reference. Sorted % and perpage counters work by writing out information to the % |.aux| file. % % The information we maintain for each counter while processing the % source file are: % \begin{itemize} % \item The absolute counter id. % \item The last counter value so that we can check whether the % sequence has been interrupted. % \item The current scope id. % \item Its starting value. % \end{itemize} % % The information written to the file consists of: % \begin{itemize} % \item The absolute counter id. % \item The current scope id. % \item The scope's starting value. % \item The absolute counter id of a superior counter. % \end{itemize} % % Sorted counters work by writing out the current absolute id and % range id into the |.aux| file each time the counter gets incremented. % Whenever the counter is changed in a manner different from being % incremented, a new counter scope gets started. Each counter scope % has its own independently assigned counter numbers and is associated % with its absolute id starting value. So as each counter is % incremented, we write out the triple of current absolute id, counter % scope and initial value for the scope. Scope changes when a value % assigned from the file differs from the `natural' value. When the % file is read in, counter movements are tracked. Each counter that % does not have its `natural' value, is having a counter setting % recorded. % % The stuff works by adding a pseudo-reset counter to the counter's % dependent counter list. % % \begin{macro}{\pp@makeperpage} % This does the relevant things for modifying a counter. It defines % its reset value, it defines the correspoding absolute counter. % The absolute counter serves a double function: it is also used for % assigning numbers while reading the |.aux| file. For this purpose % it is assigned the initialized values here and in the enddocument % hook (which is called before rereading the |.aux| file and % checking for changed labels), while the counter is reset to zero % at the start of the document. % \begin{macrocode} \def\pp@makeperpage#1#2#3{% \global\expandafter\mathchardef\csname c@pp@r@#1\endcsname=#3\relax \global\@namedef{c@pchk@#1}{#2{#1}}% \newcounter{pp@a@#1}% \setcounter{pp@a@#1}{#3}% \addtocounter{pp@a@#1}\m@ne \@addtoreset{pchk@#1}{#1}% \AtBeginDocument{\setcounter{pp@a@#1}\z@}% \edef\next{\noexpand\AtEndDocument{\noexpand\setcounter{pp@a@#1}{% \number\value{pp@a@#1}}}}\next} \@onlypreamble\pp@makeperpage % \end{macrocode} % \end{macro} % \begin{macro}{\pp@chkvlist} % Check for an empty vertical list. If we have one, that is worth % warning about. % \begin{macrocode} \def\pp@chkvlist{% \ifcase \ifvmode \ifx\lastnodetype\@undefined \ifdim-\@m\p@=\prevdepth\ifdim\lastskip=\z@\ifnum\lastpenalty=\z@ \@ne \fi\fi\fi \else \ifnum\lastnodetype=\m@ne \@ne \fi \fi \fi \z@ \or \PackageWarning{perpage}{\string\stepcounter\space probably at start of vertical list:^^JYou might need to use \string\leavevmode\space before it to avoid vertical shifts}% \fi} % \end{macrocode} % \end{macro} % \begin{macro}{\pp@fetchctr} % \begin{macro}{\theperpage} % This fetches the counter information and puts it into % \cmd{\pp@label}, \cmd{\pp@page} and (globally) into % \cmd{\theperpage}. % \begin{macrocode} \def\pp@fetchctr#1{\expandafter\expandafter\expandafter\pp@fetchctrii \csname pp@r@#1@\number\value{pp@a@#1}\endcsname \@empty\@empty} \global\let\theperpage\@empty \def\pp@fetchctrii#1#2#3{\edef\pp@label{#1}% \edef\pp@page{#2}% \gdef\theperpage{#3}} % \end{macrocode} % \end{macro} % \end{macro} % Ok, let's put together all the stuff for the simplest case, counters % numbered per page without sorting: % \begin{macro}{\c@pchk@} % This is the code buried into to the reset list. When the reset % list is executed in the context of advancing a counter, we call % something like % \begin{verbatim} %\global\c@pchk@{countername}\z@ % \end{verbatim} % since the reset list expected a counter here instead of some % generic command. That is the reason we start off this command by % giving \cmd{\global} something to chew on. % \begin{macrocode} \def\c@pchk@#1{\z@=\z@ \begingroup % \end{macrocode} % Now we fetch the page value corresponding to the not yet adjusted % value of the absolute counter to see whether the previous counter % advance happened on the same page. % \begin{macrocode} \pp@fetchctr{#1}\let\next\pp@page \addtocounter{pp@a@#1}\@ne \pp@fetchctr{#1}% % \end{macrocode} % We compare the pages for current and last advance of the counter. % If they differ, we reset the counter to its starting value. We do % the same if the counter has been reset to zero manually, likely by % being in the reset list of some other counter. % \begin{macrocode} \ifcase\ifx\next\pp@page\else\@ne\fi \ifnum\value{#1}=\z@\@ne\fi\z@ \else \setcounter{#1}{\value{pp@r@#1}}% \fi \pp@writectr\pp@pagectr{#1}{\noexpand\theabspage}} % \end{macrocode} % \end{macro} % \begin{macro}{\pp@writectr} % This is the common ending of all pseudo reset counters. It writes % out an appropriate command to the |.aux| file with all required % information. % \begin{macrocode} \def\pp@writectr#1#2#3{\edef\next{% \string#1{#2}{\number\value{pp@a@#2}}{#3}{\noexpand\thepage}}% \pp@chkvlist \dimen@=\lastkern \ifdim\dimen@=\z@ \else \unkern\fi \protected@write\@auxout{}{\next}% \ifdim\dimen@=\z@ \nobreak \else \kern\dimen@\fi \afterassignment\endgroup\count@} % \end{macrocode} % \end{macro} % \begin{macro}{\pp@pagectr} % This is the workhorse for normal per page counters. It is called % whenever the |.aux| file is read in and establishes the % appropriate information for each counter advancement in a % pseudolabel. % \begin{macrocode} \def\pp@pagectr#1#2#3#4{\@ifundefined{c@pp@a@#1}{}{% \addtocounter{pp@a@#1}\@ne \edef\next{\noexpand \@newl@bel{pp@r@#1}{#2}{{\number\value{pp@a@#1}}{#3}% {#4}}}\next}} % \end{macrocode} % \end{macro} % \begin{macro}{\c@schk@} % This is called for implementing sorted counters. Sorted counters % maintain a ``count group'', and the values in each count group are % numbered independently from that of other count groups. Whenever % a counter is found to have been reset, it will start a new count % group. At the end of document, the count group counters need to % get reset, too, so that the check for changed |.aux| files will % still work. % \begin{macrocode} \def\c@schk@#1{\z@=\z@ \begingroup \addtocounter{pp@a@#1}\@ne \ifnum\value{#1}=\@ne \expandafter\xdef\csname pp@g@#1\endcsname{\number\value{pp@a@#1}}% \edef\next{\noexpand\AtEndDocument{\global\let \expandafter\noexpand\csname pp@g@#1@\number\value{pp@a@#1}\endcsname \relax}}\next \fi \pp@fetchctr{#1}% \ifx\pp@page\@empty \else \setcounter{#1}{\pp@label}\fi \pp@writectr\pp@spagectr{#1}{\csname pp@g@#1\endcsname}}% % \end{macrocode} % \end{macro} % \begin{macro}{\pp@spagectr} % This is the code advancing the respective value of the appropriate % count group and assigning the label. % \begin{macrocode} \def\pp@spagectr#1#2#3#4{\@ifundefined{c@pp@a@#1}{}{% \count@0\csname pp@g@#1@#3\endcsname \advance\count@\@ne \expandafter\xdef\csname pp@g@#1@#3\endcsname{\number\count@}% \edef\next{\noexpand \@newl@bel{pp@r@#1}{#2}{{\number\count@}{#3}% {#4}}}\next}} % \end{macrocode} % \end{macro} % \begin{macro}{\c@spchk@} % And this finally is the counter advance code for sorted counters % per page. Basically, we just use one count group per page. % Resetting a counter manually will not introduce a new count group, % and it would be hard to decide what to do in case count groups and % page positions overlap. % \begin{macrocode} \def\c@spchk@#1{\z@=\z@ \begingroup \addtocounter{pp@a@#1}\@ne \pp@fetchctr{#1}% \ifx\pp@page\@empty \else \setcounter{#1}{\pp@label}\fi \pp@writectr\pp@ppagectr{#1}{\noexpand\theabspage}} % % \end{macrocode} % \end{macro} % \begin{macro}{\pp@ppagectr} % \begin{macrocode} \def\pp@ppagectr#1#2#3#4{\@ifundefined{c@pp@a@#1}{}{% \def\next{#3}% \expandafter\ifx\csname pp@page@#1\endcsname\next \addtocounter{pp@a@#1}\@ne \else \setcounter{pp@a@#1}{\value{pp@r@#1}}% \fi \global\expandafter\let\csname pp@page@#1\endcsname\next \edef\next{\noexpand \@newl@bel{pp@r@#1}{#2}{{\number\value{pp@a@#1}}{#3}% {#4}}}\next}} % \end{macrocode} % \end{macro} % % \Finale{} % \endinput % Local Variables: % mode: doctex % TeX-master: "perpage.drv" % End: