From e0c6872cf40896c7be36b11dcc744620f10adf1d Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Mon, 2 Sep 2019 13:46:59 +0900 Subject: Initial commit --- macros/latex/contrib/bigfoot/COPYING | 339 +++ macros/latex/contrib/bigfoot/Makefile | 49 + macros/latex/contrib/bigfoot/README | 72 + macros/latex/contrib/bigfoot/bigfoot.dtx | 3605 ++++++++++++++++++++++++++++++ macros/latex/contrib/bigfoot/bigfoot.ins | 21 + macros/latex/contrib/bigfoot/bigfoot.pdf | Bin 0 -> 405835 bytes macros/latex/contrib/bigfoot/perpage.dtx | 547 +++++ macros/latex/contrib/bigfoot/perpage.pdf | Bin 0 -> 203798 bytes macros/latex/contrib/bigfoot/suffix.dtx | 236 ++ macros/latex/contrib/bigfoot/suffix.pdf | Bin 0 -> 183403 bytes 10 files changed, 4869 insertions(+) create mode 100644 macros/latex/contrib/bigfoot/COPYING create mode 100644 macros/latex/contrib/bigfoot/Makefile create mode 100644 macros/latex/contrib/bigfoot/README create mode 100644 macros/latex/contrib/bigfoot/bigfoot.dtx create mode 100644 macros/latex/contrib/bigfoot/bigfoot.ins create mode 100644 macros/latex/contrib/bigfoot/bigfoot.pdf create mode 100644 macros/latex/contrib/bigfoot/perpage.dtx create mode 100644 macros/latex/contrib/bigfoot/perpage.pdf create mode 100644 macros/latex/contrib/bigfoot/suffix.dtx create mode 100644 macros/latex/contrib/bigfoot/suffix.pdf (limited to 'macros/latex/contrib/bigfoot') diff --git a/macros/latex/contrib/bigfoot/COPYING b/macros/latex/contrib/bigfoot/COPYING new file mode 100644 index 0000000000..d159169d10 --- /dev/null +++ b/macros/latex/contrib/bigfoot/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/macros/latex/contrib/bigfoot/Makefile b/macros/latex/contrib/bigfoot/Makefile new file mode 100644 index 0000000000..eb4867d555 --- /dev/null +++ b/macros/latex/contrib/bigfoot/Makefile @@ -0,0 +1,49 @@ +TEX=tex +PDFLATEX=pdflatex +DTX=bigfoot.dtx suffix.dtx perpage.dtx +DIST=README COPYING $(DTX) Makefile bigfoot.ins +DOC=$(DTX:.dtx=.pdf) + +all: $(DIST) $(DTX:.dtx=.sty) $(DOC) + +bigfoot-mk.ins: bigfoot.dtx Makefile + $(TEX) '\nonstopmode \def\jobname{.ins}\input docstrip ' \ + '\askforoverwritefalse \nopreamble' \ + '\generate{\file{bigfoot-mk.ins}{\from{bigfoot.dtx}{installer,make}}}' \ + '\endbatchfile' + +# Not generated by bigfoot-mk.ins in order to allow for hand-editing, +# like putting debug options in +bigfoot.ins: bigfoot.dtx Makefile + $(TEX) '\nonstopmode \def\jobname{.ins}\input docstrip ' \ + '\askforoverwritefalse \nopreamble' \ + '\generate{\file{bigfoot.ins}{\from{bigfoot.dtx}{installer}}}' \ + '\endbatchfile' + +bigfoot.drv bigfoot.sty perpage.drv perpage.sty suffix.drv suffix.sty: bigfoot-mk.ins + $(TEX) bigfoot-mk.ins + +bigfoot.drv bigfoot.sty: bigfoot.dtx +perpage.drv perpage.sty: perpage.dtx +suffix.drv suffix.sty: suffix.dtx + +bigfoot.pdf: bigfoot.dtx bigfoot.drv bigfoot.sty perpage.sty suffix.sty + $(PDFLATEX) '\nonstopmode\input{bigfoot.drv}' + $(PDFLATEX) '\nonstopmode\input{bigfoot.drv}' + $(PDFLATEX) '\nonstopmode\input{bigfoot.drv}' + +perpage.pdf: perpage.dtx perpage.drv + $(PDFLATEX) '\nonstopmode\input{perpage.drv}' + $(PDFLATEX) '\nonstopmode\input{perpage.drv}' + $(PDFLATEX) '\nonstopmode\input{perpage.drv}' + +suffix.pdf: suffix.dtx suffix.drv + $(PDFLATEX) '\nonstopmode\input{suffix.drv}' + $(PDFLATEX) '\nonstopmode\input{suffix.drv}' + $(PDFLATEX) '\nonstopmode\input{suffix.drv}' + +bigfoot.tar.gz: $(DIST) + tar czf $@ $(DIST) + +bigfoot-ctan.tar.gz: $(DIST) $(DOC) + tar czf $@ --transform 's,^\(\./\)\?,bigfoot/,' $(DIST) $(DOC) diff --git a/macros/latex/contrib/bigfoot/README b/macros/latex/contrib/bigfoot/README new file mode 100644 index 0000000000..1ce209de09 --- /dev/null +++ b/macros/latex/contrib/bigfoot/README @@ -0,0 +1,72 @@ +This is the bigfoot bundle for critical edition typesetting and other +concerns, written by David Kastrup (mailto:dak@gnu.org). The complete +package in development can be accessed using the CVS instructions at +, and +CTAN:/macros/latex/contrib/bigfoot provides released versions. + +The whole bundle is released under the GPL version 2 (or later), see +the file COPYING for details. Part of the work has been sponsored or +commissioned by various parties (including TUG), but further +functionality and development depends on your support, financially or +by participation. The author has a Paypal account which you might +consider contributing to. + +All of the files (except perpage.sty, for historical reasons) need +eTeX 2 as the LaTeX engine. All modern distributions provide this by +default. + +A Makefile is provided for generating most files. In case the +platform does not support Make, the distribution tarball includes the +file bigfoot.ins pregenerated from bigfoot.dtx. + +File descriptions for available files: + +bigfoot.ins: This is a generated file and not in the Git repository (but + on CTAN). Generating it can be done by running `tex docstrip' and + answering the prompts + + \infileext=dtx + \outfileext=ins + \Options=installer + \filelist=bigfoot + + If you instead use + + \Options=installer,make + + you will get a version of `bigfoot.ins' which will not ask before + overwriting files, but will only place them in the current + directory even if your docstrip configuration contains target + directory declarations. + + Running TeX on bigfoot.ins will generate a number of style files + (with the extension .sty) and a number of documentation driver + files (with the extension .drv). + + +Here come the source files themselves: + +suffix.dtx: This is the doc source for `suffix.sty', a package that + makes it very easy to define command variants like \macro* or + \macro\!. It is included in the critical bundle since typical + document classes for real critical editions documents will tend to + want weird signs under handy abbreviations, like \< and \<<, or + \=>, or things like \footnote' macros, or \footnote<...\footnote> + with different formatting/numbering and so on. + +perpage.dtx: This is the doc source for `perpage.sty'. Used for + keeping counters sorted in order of page appearance and making + numbering per page possible. + +bigfoot.dtx: This is the doc source for `bigfoot.sty'. Used for + solving every problem around footnotes and then some. Deals with + nested footnotes in several apparatus, uses a backtracking + algorithm for finding the optimal break across several footnotes, + automatically breaks in-paragraph style footnotes across pages, + uses fuzzy logic for deciding about when to prefer in-paragraph + layout to one-footnote-per-paragraph layout on a per-note and + per-block basis, deals with colors in footnotes even when broken + across pages, adapts the document class's footnote style to + in-paragraph footnotes as good as it can, allows customization of + styles differing across footnote blocks, allows verbatim text in + footnotes and so on. diff --git a/macros/latex/contrib/bigfoot/bigfoot.dtx b/macros/latex/contrib/bigfoot/bigfoot.dtx new file mode 100644 index 0000000000..769653fe78 --- /dev/null +++ b/macros/latex/contrib/bigfoot/bigfoot.dtx @@ -0,0 +1,3605 @@ +% \iffalse +%% +%% bigfoot is part of the bigfoot bundle for critical typesetting +%% Copyright 2004--2015 David Kastrup +%% +%% The license notice and corresponding source code for this file are +%% contained in bigfoot.dtx. +%% +% 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{4580} +% \GetFileInfo{bigfoot.sty} +% \title{The \texttt{bigfoot} package\\version \fileversion} +% \date{\filedate} +% \author{David Kastrup\thanks{dak@gnu.org}} +% \maketitle +% Purpose of this package is to provide a one-stop solution to almost +% all problems related to footnotes. You can use it as a drop-in +% replacement of the \texttt{manyfoot} package, but without many of +% its shortcomings, and quite a few features of its own. It uses the +% existing document class layouts for footnotes, so you can usually +% use it without having to worry about the looks. +% +% Features are: +% \begin{itemize} +% \item You can specify and use multiple footnote apparatus. +% Footnotes for an apparatus lower on the +% page\footnoteB{like this one} can be anchored in an +% apparatus\footnote{The plural of ``apparatus'' is actually +% ``apparatus''\footnoteB{Well, actually ``apparat\=us'' with a +% long ``u'', but that's just obvious in spoken Latin.}} +% that is higher on the page. +% \item The last footnote in each apparatus may be broken to the next +% page.\footnote{This will probably be interesting for footnotes +% that contain stuff like math equations\footnoteB+{Like +% \begin{equation} +% \label{eq:1} +% \sum_{k=1}^\infty \frac{1}{k^2} = \frac{\pi^2}{6} +% \end{equation}} or lists\footnoteB+{Like +% \begin{itemize} +% \item This, or +% \item this. +% \end{itemize}}.} +% Any subordinate footnote anchors that get moved to the next page +% will take the corresponding footnote with them. +% \item The order of footnotes in an apparatus is `natural': it starts +% with any footnote that may have been broken from the next page, +% followed by footnotes from the current page in the order of the +% appearance of their footnote +% marks.\footnoteB{This footnote appears above notes on notes.} +% Where the order of appearance in the document differs from the +% order in the source code, you will usually want to use the +% \cmd{\MakeSorted} command from the |perpage| package to get the +% numbering fixed appropriately. +% \item Footnotes can be formatted in separate paragraphs, or be run +% into a single paragraph. The choice is made per footnote +% apparatus, but can be overridden for single +% footnotes.\footnote{I.e., footnotes with display +% math\footnoteB{We had this already, right?} or list +% environments\footnoteB{And this looks familiar, too.} have to be +% done in vertical mode.} +% \item If footnotes are run into one paragraph, a variety of criteria +% makes sure that this formatting is only chosen when it saves +% noticeable space and delivers visually attractive results. +% \item Parameters for footnote formatting can be specified globally, +% or separately for each footnote. +% \item The material in footnotes can contain |\verb|-like material +% without problems.\footnote{We wrote \verb+|\verb|-like+ above in +% the main text.\footnoteB{Well, this is not so impressive. But we +% wrote \verb/\verb+|\verb|-like+/ in the footnote then.}} +% \item You can use color in footnotes. If a footnote gets broken +% across pages, the color at the point of the break will get resumed +% on the next page. Actually, the whole color stack will get +% reinstated. +% \end{itemize} +% As an example of how simple the usage can be, here is the +% documentation driver for this document: +% \begin{macrocode} +%<*driver> +\documentclass{ltxdoc} +\usepackage{bigfoot} +\usepackage{tabularx} +\usepackage{hyperref} +% \end{macrocode} +% After loading the packages, we declare two footnote blocks. One is +% the default footnote block, another block is called~|B| and is +% numbered with letters. The letters start new on each page. Both +% footnote blocks default to in-paragraph footnotes. Since the +% block~|B| can get entries from both the main text as well as the +% default footnote block, the entries are not necessarily generated in +% page order. So we need to use a sorted counter to fix this (feel +% free to try what happens when using an unsorted counter). +% \begin{macrocode} +\DeclareNewFootnote[para]{default} +\DeclareNewFootnote[para]{B}[alph] +\MakeSortedPerPage{footnoteB} +% \end{macrocode} +% In addition, we add an alternate footnote sequence that can be +% interspersed with the normal footnotes by use of the +% \cmd{\footnote'} command which we effectively define here. +% \begin{macrocode} +\newcounter{footalt} +\def\thefootalt{\fnsymbol{footalt}} +\MakeSortedPerPage[2]{footalt} +\WithSuffix\def\footnotedefault'{\refstepcounter{footalt}% + \Footnotedefault{\thefootalt}} +% \end{macrocode} +% Actually, that already was all. We can now start the document. The +% following makes sure that we get the full documentation only by +% compiling the separate driver file: +% \begin{macrocode} +\begin{document} +\OnlyDescription +% \AlsoImplementation +\DocInput{bigfoot.dtx} +\end{document} +% +% \end{macrocode} +% In order to be useful without additional hassle, the normal footnote +% level will be called |default|. If no such style has been defined +% at the start of the document, it will get defined and used for +% ordinary footnotes, fixing quite a few problems of \LaTeX's own +% footnote placement algorithms. +% +% Apart from that, usage is very much like that of |manyfoot|, so for +% the customization possibilities of |bigfoot| with regards to +% multiple footnote blocks and rules between them, refer to +% |manyfoot|'s documentation. +% +% |bigfoot| contains a lot of bells and whistles for defining your +% footnote formats and can use different formats for different +% footnote blocks. Those expert options are not documented separately +% yet: look through the code sections to see them explained. +% \StopEventually{} +% \section{The implementation} +% \subsection{Startup code} +% We declare the package and several compatibility options supposed to +% make |bigfoot| a drop-in replacement for |manyfoot|. +% \begin{macrocode} +%<*style> +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{bigfoot}[2015/08/30 2.1 makes footnotes work] + +\DeclareOption{para}{\PackageInfo{bigfoot}{Compatibility option `para' + has no effect:^^J% + Spacing will be guessed from `\string\@makefntext' unless^^J% + `\string\@preparefnhtext' is redefined}} + +\DeclareOption{para*}{\PackageInfo{bigfoot}{Compatibility option + `para*':^^J% + Redefining `\string\@preparefnhtext'}% + \def\@preparefnhtext{\ifx\@thefnmark\@empty + \else\@makefnmark\nobreak\fi}} + +\DeclareOption{ruled}{\PassOptionsToPackage{ruled}{manyfoot}} +% \end{macrocode} +% The normal processing makes footnote text macros allow verbatim and +% similar. We call this |robust| processing though it is not totally +% accurate. This is the default. There is also an option |fragile| +% which will not allow this, but may be required for some definitions +% of \cmd{\@makefntext}. It turns out that most document classes work +% with the `robust' option, but there might be some that fail, and +% there might be some footnote-modifying packages that also can cause +% failure. +% \begin{macrocode} +\DeclareOption{robust}{\def\FN@makefncall{\FN@makefnrobust}} +\DeclareOption{fragile}{\def\FN@makefncall{\FN@makefnfragile}} +\ExecuteOptions{robust} +% \end{macrocode} +% The |verbose| option talks about changed labels at the end of a +% run. It is for debugging instable configurations that fail to +% converge after a number of \TeX\ runs. The output is probably +% obscure. +% \begin{macrocode} +\DeclareOption{verbose}{\AtBeginDocument{% + \def\@testdef #1#2#3{% + \def\reserved@a{#3}% + \expandafter \ifx \csname #1@#2\endcsname + \reserved@a + \else \@tempswatrue + \typeout{Changed label #1/#2: + \csname #1@#2\endcsname->#3}% + \fi}}} +% \end{macrocode} +% The |trace| option is only available if you used |docstrip| while +% explicitly requesting |trace| functionality. If you set the |trace| +% option, the next option specifies a bit map of trace bits. +% +% The following bits can be set in tracing: +% \begin{tabular}{rl} +% 1&break decisions\\ +% 2&horizontal box building\\ +% 4&allocation stuff\\ +% 8&output routine stuff\\ +% 16&retained and kept boxes +% \end{tabular} +% \begin{macrocode} +%\DeclareOption{trace}{% +%\DeclareOption*{\ftflags=\CurrentOption\relax +% \DeclareOption*{\OptionNotUsed}}% +% \AtEndOfPackage{\RequirePackage{trace}\relax +% \errorcontextlines\maxdimen +% \showboxdepth4 +% \showboxbreadth100 +% \tracingonline=\@ne}% +%} +% \end{macrocode} +% The |tracepage| option is followed by another option specifying the +% page to be traced. If you use it, tracing happens only on the +% specified page. Only a single page can be specified. +% \begin{macrocode} +%\def\FN@tracepage{\c@page} +%\DeclareOption{tracepage}{% +% \DeclareOption*{\edef\FN@tracepage{\CurrentOption}% +% \DeclareOption*{\OptionNotUsed}}} +%\newcount\ftflags +%\def\foottrace#1{\ifnum\numexpr(\ftflags+(#1))/(2*#1)*(2*#1)% +% =\numexpr(\ftflags+3*#1/2)/#1*#1\relax +% f\else t\fi\ifnum\FN@tracepage=\c@page t\else n\fi} +\ProcessOptions* +% \end{macrocode} +% |hyperref|'s footnote support will just cause trouble. So if +% |hyperref| was already loaded or is going to be loaded, we turn off +% its footnote support. If you think you know what you are doing, you +% can use \cmd{\hypersetup} to turn it on again before the start of +% the document. Unfortunately, it appears like \cmd{\hypersetup} +% refuses to be called more than once, so this actually does not work +% unless you load |hyperref| last. +% \begin{macrocode} +\ifx\hypersetup\@undefined + \PassOptionsToPackage{hyperfootnotes=false}{hyperref} +\else + \hypersetup{hyperfootnotes=false} +\fi +% \end{macrocode} +% We require the |etex| package because +% \begin{enumerate} +% \item We need the facilities of the \eTeX\ engine; and where they +% are not available, the error messages from not finding the |etex| +% package or from loading it into the wrong engine make much more +% sense than what would happen otherwise. +% \item We allocate quite a few registers, and the danger of running +% out of them is smaller when the extra registers of \eTeX\ are +% taken into account. Now unfortunately the LaTeX team has decided +% in 2015 to do its own extended allocation scheme incompatible with +% the |etex| package, so we need to guard against this load in case +% the new LaTeX allocation scheme is detected. +% \end{enumerate} +% We need the |manyfoot| package to build on. The |suffix| and +% |perpage| package are needed for some small stuff. +% \begin{macrocode} +\ifx\e@alloc\@undefined +\RequirePackage{etex} +\fi +\RequirePackage{manyfoot} +\RequirePackage{suffix} +\RequirePackage{perpage} +% \end{macrocode} +% \subsection{Fixes to the \texttt{manyfoot} package} +% While those fixes have been submitted once to the author of +% |manyfoot|, they have not made it into its distribution at the +% current point of time. In the interest of stability, it would +% probably be best just to incorporate the parts from |manyfoot| that +% get used by |bigfoot|. This has not yet been done. +% +% \begin{macro}{\MFL@reinsout} +% We need the appropriate splitting parameters set for the footnote +% again. \cmd{\MFL@realinsert} does that, but it has the disadvantage +% that it uses \cmd{\strutbox}, and that may be set to arbitrary +% values at the time the output routine is invoked. |manyfoot| +% already has this problem with minipages: the split sizes will be +% those of the font at the end of the minipage instead of those at the +% time the footnote body was set up. So we do this here, and see +% later for more info about how to do this right: +% \begin{macrocode} +\def\MFL@reinsout#1#2{\ifvoid#2\else + \ifnum\count\@currbox>\z@ + \advance\@pageht \ht#2% + \advance\@pageht \skip#2% + \advance\@pageht \dp#2% + \fi + \MFL@realinsert{#2}{\unvbox#2}% + \fi +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\MFL@reins} +% Actually, I don't get the purpose of the following line in the +% first place. But if we do need it for some reason, it is rather +% certain that we don't want this empty insert to float. Use +% \cmd{\MFL@realinsert}, or set the floatingpenalty the hard way. +% \begin{macrocode} +\def\MFL@reins#1#2{\ifvoid#2\else\insert#2{\floatingpenalty\@MM}\fi} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\MFL@mpinsert} +% \begin{macro}{\MFL@minipage} +% The structure of the \cmd{\MFL@mpinsert} box is overly +% complicated, and it is a bad idea to unpack the boxes put into it +% too early: the \cmd{\lastbox} command is pretty inefficient when +% the list before it is long due to unpacking. So we just leave +% everything packed in its own boxes, and unpack only at the moment +% when we are reinserting. +% \begin{macrocode} +\long\def\MFL@mpinsert#1#2{% + \global\setbox#1\vbox{% + \unvbox#1% + \nointerlineskip + \vbox{#2}% + }% +} + +\def\FN@divert{% + \let\MFL@mpinsertsave\MFL@insert + \MFL@reinsert \let\MFL@insert\MFL@mpinsert} +\def\FN@enddivert{{\let\@elt\MFL@mpreinsert \MFL@list}} + +\def\MFL@minipage{\ifinner\else \FN@divert\fi} +\def\MFL@endminipage{\ifinner\else \FN@enddivert\fi} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \begin{macro}{\MFL@mpreinsert} +% When reinserting, we put all but the last insertion into one +% humongous blob. This is so that the last insertion can be split +% by \TeX's paragraph splitting routines. The footnote types that +% |bigfoot| supports will never get split by \TeX, anyhow, but it is +% conceivable that other extension packages for manyfoot work +% differently. There is one difference, though: we let a slave mark +% escape into the main vertical list. +% \begin{macrocode} +\def\MFL@mpreinsert#1#2{% + \ifvoid#2\else + \setbox\@tempboxa\vbox\bgroup\unvbox#2% + \global\setbox#2\lastbox + \setbox\z@\lastbox + \ifvoid\z@ + \egroup + \setbox\z@\box#2% + \else + \MFL@removevboxes \unvbox\z@ + \egroup + \setbox\z@\box#2% + \MFL@mpinsertsave#2{\unvbox\@tempboxa}% + \fi + \ifvoid\z@\else + \MFL@mpinsertsave#2{\unvbox\z@}% + \fi + \marks\FN@slave{\number\FN@id}% + \fi} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\MFL@removevboxes} +% This trick works like \cmd{\removehboxes} in the \TeX book's +% appendix~D. +% \begin{macrocode} +\def\MFL@removevboxes{{\setbox\z@\lastbox + \ifvbox\z@ \MFL@removevboxes \unvbox\z@\fi}} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\NCC@makefnmark} +% This provides the command in case it is not present (some versions +% did not have it). +% \begin{macrocode} +\ifx\NCC@makemark\@undefined + \ifx\NCC@makefnmark\@undefined \else + \def\NCC@makemark{\NCC@makefnmark} + \fi +\fi +% \end{macrocode} +% \end{macro} +% +% While the above operations actually were fixes to |manyfoot|, now we +% actually patch it for our own purposes. When allocating a new +% footnote, we set its maximum dimension to \cmd{\maxdimen} (since no +% hard limit makes sense, given that we recalculate all respective +% sizes at output time) and allocate a cache box to go with it. We +% also add the insertion to the list of insertions in +% \cmd{\FN@nestlist}. +% \begin{macro}{\MFL@startplain} +% \begin{macro}{\MFL@startpara} +% \begin{macrocode} +\def\MFL@startplain#1{\global\dimen#1\maxdimen + \@cons\FN@nestlist{{}#1}% + \expandafter\expandafter\expandafter\newbox\FN@cache#1} + +\let\MFL@startpara\MFL@startplain +% \end{macrocode} +% \end{macro} +% \end{macro} +% \begin{macro}{\RestyleFootnote} +% This macro gets two arguments: a footnote \meta{type}, and the +% style to be used for it. It works by redefining the corresponding +% |Footnotetext|\meta{type} macro. +% \begin{macrocode} +\def\RestyleFootnote#1#2{\expandafter\xdef + \csname Footnotetext#1\endcsname{\expandafter + \noexpand\csname MFL@fnote#2\endcsname{\csname footins#1\endcsname}}} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@stripfootins} +% \begin{macro}{\FN@restylefootnote} +% We need the same kind of functionality for a footnote specified by +% its footnote insertion. So we strip the footnote \meta{type} from +% the insertion macro name. Kind of ugly. +% \begin{macrocode} +\expandafter\def\expandafter\FN@stripfootins\string\footins{} + +\def\FN@restylefootnote#1#2{{\edef\next{% + \noexpand\RestyleFootnote{\expandafter\FN@stripfootins + \string#1}{#2}}\next}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Dealing with footnote-specific code} +% The formatting of footnotes is determined by macros such as +% \cmd{\@makefntext}. For several blocks of footnotes, we might want +% to have several different ways for formatting them. Whenever this +% is the case, we call them with +% \begin{quote} +% |\FN@specific|\marg{insert\#}\marg{macroname} +% \end{quote} +% This will use the default \meta{macroname} unless a special macro has +% been defined with something like +% \begin{quote} +% |\FootnoteSpecific\marg{type}|\def|\meta{macroname}\dots +% \end{quote} +% A number of other defining commands and constructs are available: +% those are pretty much like the ones for the \cmd{\WithSuffix} command +% implemented by the |suffix| package. +% \begin{macro}{\FN@specific} +% We use |\romannumeral| here just for the purpose of sustaining +% expansion. It expands to nothing when followed by |\z@| +% eventually. Thus expanding the expansion of \cmd{\FN@specific} +% again delivers the (unexpanded) final token to use. +% \begin{macrocode} +\def\FN@specific#1#2{\romannumeral + \ifcsname FN\string#2\number#1\endcsname + \expandafter + \z@\csname FN\string#2\number#1\expandafter\endcsname + \else\expandafter\z@ + \expandafter#2\fi} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FootnoteSpecific} +% \begin{macro}{\FN@specific@ii} +% This is all a bit muddy, but quite similar to what the |suffix| +% package does, so you might want to look there for the explanation. +% \begin{macrocode} +\def\FootnoteSpecific#1{\count@\csname footins#1\endcsname\toks@{}% + \FN@specific@ii} + +\long\def\FN@specific@ii#1#2{\toks@\expandafter{\the\toks@#1}% + \the\expandafter\toks@ + \csname FN\string#2\number\count@\endcsname} + +\WithSuffix\def\FN@specific@ii\long{\toks@\expandafter + {\the\toks@\long}\FN@specific@ii} + +\WithSuffix\def\FN@specific@ii\global{\toks@\expandafter + {\the\toks@\global}\FN@specific@ii} + +\WithSuffix\def\FN@specific@ii\expandafter{\expandafter + \FN@specific@ii\expandafter} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Putting footnotes into insertions} +% \subsubsection{Dealing with Ids} +% Since we have to store additional information for each footnote as +% long as it is not yet typeset, we allocate and deallocate numeric +% `id's on an as-needed base, since we do not want to store this +% sort of information indefinitely, with a large toll on hash space. +% So we work with indirect ids, where the unique ids are just +% referenced indirectly. We do this with `slots'. +% \begin{macro}{\FN@slotxdef} +% \begin{macro}{\FN@slotget} +% New slots are assigned values with \cmd{\FN@slotxdef}, which can +% be retrieved again with \cmd{\FN@slotget}. +% \begin{macrocode} +\def\FN@slotxdef#1{% + \global\expandafter\xdef\csname FN@slot#1\endcsname} + +\def\FN@slotget#1{\csname FN@slot#1\endcsname} +%\def\FN@slotget#1{% +% \expandafter\FN@slotgetii\expandafter +% \FN@slotfreelist\expandafter +% {\number\number#1}} +%\def\FN@slotgetii#1#2{% +% \ifx#1\@empty \csname FN@slot#2\endcsname\else +% \ifnum#1=#2 \errmessage{Use after freed: #1}\else +% \expandafter\FN@slotgetii +% \csname FN@slot#1\endcsname{#2}\fi\fi} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \begin{macro}{\FN@slotfreelist} +% \begin{macro}{\FN@nextslot} +% \cmd{\FN@slotfreelist} point to the first already allocated +% available id to be reused. If it is empty, none exist. In that +% case, \cmd{FN@nextslot} contains the next slot number to use. +% \begin{macrocode} +\def\FN@slotfreelist{} +\def\FN@nextslot{1} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \begin{macro}{\FN@newslot} +% This allocates a new slot by setting the given macro to a +% currently unused slot number in decimal form. If there is +% something left in the freelist, it is assigned, otherwise a new +% slot gets allocated. +% \begin{macrocode} +\def\FN@newslot#1{% + \ifx\FN@slotfreelist\@empty + \edef#1{\FN@nextslot}% + \xdef\FN@nextslot{\number\numexpr \FN@nextslot+\@ne}% + \else + \let#1\FN@slotfreelist + \xdef\FN@slotfreelist{\csname FN@slot\FN@slotfreelist\endcsname}% + \fi +% \if\foottrace4\message{^^JAllocated #1^^J}\fi +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@freeslot} +% This frees a given slot (by number) again by adding it to the +% freelist. +% \begin{macrocode} +\def\FN@freeslot#1{% +% \if\foottrace4\message{^^JFreeing #1^^J}\fi + \global\expandafter\let\csname FN@slot#1\endcsname=\FN@slotfreelist + \xdef\FN@slotfreelist{#1}} +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Dealing with footnote stacks} +% Footnote stacks are used for paired footnotes that refer to a text +% range instead of a single text point. For example, you can use +% something like +% \begin{verbatim} +% Text \var<{was there}is here\var> +% \end{verbatim} +% To have a text variant ``was there'' for the original passage ``is +% here'', and mark it, say, as ``\textsuperscript{a}is +% here\textsuperscript{\textsl{a}}'' by employing the |suffix| package +% suitably. This would anchor the footnote at the start of the +% passage. It would also be imaginable to implement the syntax +% \begin{verbatim} +% Text \var{was there} +% \end{verbatim} +% for anchoring it at the end of the given passage. +% \begin{macrocode} +\global\let\FN@stacklist\@empty +% \end{macrocode} +% \begin{macro}{\DefineFootnoteStack} +% This command is used for defining a footnote stack. It gets a +% single argument which is the name of the stack and should consist +% just of ordinary character tokens. +% \begin{macrocode} +\def\DefineFootnoteStack#1{% + \global\expandafter\let\csname FN@stack@#1\endcsname\@empty + \@cons\FN@stacklist{{#1}}% +} +% \end{macrocode} +% \end{macro} +% At the end of the document, all stacks are checked to make sure they +% have been used up completely. +% \begin{macrocode} +\AtEndDocument{\FN@checkstacklist} + +\def\FN@checkstacklist{{\let\@elt\FN@checkstack + \FN@stacklist}} + +\def\FN@checkstack#1{{\let\@elt\FN@checkstackentry + \csname FN@stack#1@\endcsname}} + +\def\FN@checkstackentry#1#2#3{% + \PackageError{bigfoot}{Unfinished #1 #2 from line #3}% + {The specified footnote range is uncomplete}} +% \end{macrocode} +% \begin{macro}{\PushFootnoteMark} +% This gets one argument, the name of the footnote stack. It pushes +% the current footnote mark name stored in \cmd{\@thefnmark} onto +% the footnote stack. +% \begin{macrocode} +\def\PushFootnoteMark#1{{\let\@elt\relax + \expandafter\unrestored@protected@xdef \csname FN@stack@#1\endcsname + {\@elt{#1}{\@thefnmark}{\number\inputlineno}\csname + FN@stack@#1\endcsname}}} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\PopFootnoteMark} +% This gets one argument, the name of the footnote stack. It pops +% the value of \cmd{\@thefnmark} from the named footnote stack. +% \begin{macrocode} +\def\PopFootnoteMark#1{\expandafter + \ifx\csname FN@stack@#1\endcsname\@empty + \PackageError{bigfoot}{Empty footnote stack #1}% + {The specified footnote type has no uncompleted range}% + \else + {\let\@elt\FN@firstpop + \iffalse{\fi\csname FN@stack@#1\endcsname}}\fi} +% \end{macrocode} +% \end{macro} +% \begin{macrocode} +\def\FN@firstpop#1#2#3{\protected@xdef\@thefnmark{#2}% + \let\@elt\relax + \expandafter\protected@xdef\csname FN@stack@#1\endcsname{% + \iffalse}\fi} +% \end{macrocode} +% +% \subsubsection{Continuation marks} +% +% We add a possibility of adding continuation marks. While the box is +% assembled, immediately before the break, \cmd{\FN@beforebreak} gets +% called, and \cmd{\FN@afterbreak} is called at the top of the +% continuing box. +% \begin{macrocode} +\ifx\FN@beforebreak\@undefined + \let\FN@beforebreak\@empty +\fi +\ifx\FN@afterbreak\@undefined + \let\FN@afterbreak\@empty +\fi +% \end{macrocode} +% +% +%\subsubsection{The works} +% +% \begin{macro}{\FN@cache} +% Cacheboxes cache the typeset forms of the insertion boxes for a +% certain configuration of footnotes. +% \begin{macrocode} +\def\FN@cache#1{\csname FN@cache\number#1\endcsname} +% \end{macrocode} +% \end{macro} +% \cmd{\FN@sortlist} takes the current vertical list and sorts the +% contained boxes according to their width (which is supposed to +% contain the sort key). +% +% The algorithm is a pretty straightforward insertion sort with +% $O(n^2)$~steps. This is the best one can hope for without +% comparisons across non-adjacent list elements. For presorted lists, +% the performance will be $O(n)$, and that's what we expect to see for +% simple cases (and when there are no sortkeys yet). Any negative +% width will certainly hang the algorithm. +% +% It also happens that \TeX\ has a hardwired limit for grouping levels +% that hits at 255. Oops. We better not have a few hundred footnotes +% in a single block on one page\dots +% \begin{macrocode} +\def\FN@sortlist{{% + \setbox\z@\lastbox + \ifvoid\z@ \else \FN@sortlist\FN@sortlistii \fi}} + +\def\FN@sortlistii{% + \setbox\tw@\lastbox + \ifvoid\tw@\else + \ifdim\wd\tw@<\wd\z@ {\FN@sortlistii}% + \fi\nointerlineskip\box\tw@\fi\nointerlineskip\box\z@} +% \end{macrocode} +% \begin{macro}{\FN@sortinsert} +% This function is an \cmd{\@elt} function that will sort the given +% insertion if it is non-empty and if there is no cache box present +% (which would imply that the insertion had already been sorted +% previously). +% \begin{macrocode} +\def\FN@sortinsert#1#2{\ifvoid\FN@cache#2% + \ifvoid#2\else\global\setbox#2\vbox{\unvbox#2% + \FN@sortlist}\fi\fi} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@maybeinvalidatecache} +% This is called after pulling in additional material from the +% page. If the material added an insertion, the cache is junk and +% must be regenerated. +% \begin{macrocode} +\def\FN@maybeinvalidatecache#1#2{% + \ifvoid#2\else\global\setbox\FN@cache#2=\box\voidb@x\fi} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@regeneratecache} +% This unconditionally regenerates one cache box. The structure of +% a cache box is basically a list of vertical boxes. All but the +% last such box are packed into a single vertical box which is then +% followed by the last vertical box. +% \begin{macrocode} +\def\FN@regeneratecache#1#2{% + \global\setbox\FN@cache#2=% + \ifvoid#2% + \box\voidb@x + \else + \vbox{\vbox{\unvcopy#2% + \setbox\z@\lastbox + \def\FN@masterinsert{#2}% + \FN@assembleboxes + \global\setbox\FN@cache#2\box\z@}% + \nointerlineskip \box\FN@cache#2}% + \fi} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@mayberegeneratecache} +% This regenerates the cache in case the cache box has been voided +% in order to mark it as invalid. +% \begin{macrocode} +\def\FN@mayberegeneratecache#1#2{% + \ifvoid\FN@cache#2% + \FN@regeneratecache{}#2% + \fi} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@cachesize} +% This calculates the size impact of a cache box on the current page +% as a term to be added into a \cmd{\glueexpr}-type of expression. +% \begin{macrocode} +\def\FN@cachesize#1#2{% + \ifvoid\FN@cache#2% + \else + +\skip#2+(\ht\FN@cache#2+\dp\FN@cache#2)*\count#2/\@m + \fi} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@clearcache} +% This just completely voids a cache register. +% \begin{macrocode} +\def\FN@clearcache#1#2{% + \global\setbox\FN@cache#2=\box\voidb@x} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@makefnvtext} +% Ok, this is one of the parts putting together footnotes in para +% mode. The footnotes themselves have already been formatted into +% hboxes (placed there with \cmd{\@preparefnhtext} in order to cater +% for proper indentation). \cmd{\@makefnvtext} then formats a +% single footnote block from horizontal mode pieces (vertical mode +% pieces are kept as-is). +% This takes text and typesets it in a single block. To get correct +% indentation, it breaks before the first footnote and adjusts the +% clubpenalties to move them to one line lower effectively. +% \cmd{\@makefnvtext} is called in vertical mode, and its argument +% is typeset in horizontal mode right after a break, inside of +% \cmd{\@makefntext}. +% \begin{macrocode} +\def\@makefnvtext#1{% + \FN@specific\FN@masterinsert\@makefntext{% + \clubpenalties\thr@@\@MM\clubpenalty\z@ + \vadjust{\nobreak\vskip-\baselineskip}\nobreak\hfill\break#1}} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\@preparefnhtext} +% This creates appropriate skips to be put before the horizontal +% material to make the indentation correct with a breakpoint before +% the footnote as well as when in run-in text. This is run once at +% the start of each horizontal mode footnote when it is first being +% typeset, in horizontal mode. +% \begin{macrocode} +\ifx\@preparefnhtext\@undefined +\def\@preparefnhtext{{% + \setbox\z@\vbox{\FN@specific\FN@masterinsert\@makefntext{% + \unskip\unpenalty\setbox\z@\lastbox + \dimen@ + \ifnum\parshape>\z@ + \dimexpr\parshapeindent\tw@-\parshapeindent\@ne\relax + \else \ifnum\hangafter=\@ne\hangindent \else + \ifnum\hangafter=\m@ne -\hangindent + \else \z@ \fi\fi\fi + \dimen@ii\dimen@ + \ifhbox\z@ \advance\dimen@-\wd\z@ + \setbox\z@\hbox{\unhbox\z@}% + \advance\dimen@\wd\z@ + \fi + \xdef\FN@tempinfo{\hskip\the\dimen@ + \vadjust{}\nobreak\hskip-\the\dimen@ii\relax}}}}% + \FN@tempinfo} +\fi +% \end{macrocode} +% Now we have in |\FN@tempinfo| the excess width of the label we don't +% want to preserve when doing in-paragraph footnote setting. A +% sequence of glue before a label now has to consist of stuff that +% vanishes at a breakpoint, followed by stuff that remains. We have +% to have two behaviors for the contents: behavior one is +% justification at the start of a line, behavior two is justification +% in the line. When we are at the start of the line, preceding +% interword space disappears swallowed and so the natural criterion +% for distinguishing those cases is this initial line break. This +% means that we can't avoid articifially adding a line break at the +% start of such a box. We will back up its height again. Some +% packages specify a |\hangindent| (I~know of no examples where they +% would actually set |\hangafter| to a value different from its +% default of~1, or set |\hangindent| to a negative value which would +% affect the right margin): due to our artifical line at the top, the +% indent will actually be active for the first line already. We back +% it out of the actual labels happening at the start of the line. +% Two-line parshapes have the same effect: the first line is not +% actually used, and we put the relevant info for the first line into +% the label. Different right indentation for the first line is +% something we can't simulate, but again, it should occur rarely. +% When |\parshape| is active, |\hangindent| is ignored. +% \end{macro} +% \begin{macrocode} +\def\@makefnstartbox{% + \ifdefined\setspace@singlespace + \def\baselinestretch{\setspace@singlespace}% + \fi + \reset@font\footnotesize + \hsize\MFL@columnwidth \@parboxrestore + \interlinepenalty\FN@specific\FN@masterinsert\interfootnotelinepenalty + \widowpenalty\FN@specific\FN@masterinsert\footnotewidowpenalty + \clubpenalty\FN@specific\FN@masterinsert\footnoteclubpenalty + \advance\linepenalty500\relax} + +\def\@makefnendbox{% + \widowpenalty\FN@specific\FN@masterinsert\finalfootnotewidowpenalty} + +\newcount\footnotewidowpenalty +\footnotewidowpenalty=250 +\newcount\footnoteclubpenalty +\footnoteclubpenalty=250 +\newcount\finalfootnotewidowpenalty +\finalfootnotewidowpenalty=4000 +% \end{macrocode} +% \begin{macro}{\@makefnvbox} +% This is the formatting code for a vertical mode footnote box from +% already set horizontal material. It uses \cmd{\@makefnstartbox} +% for setting up the initial widow/club penalties, and +% \cmd{\@makefnendbox} for preparing the final end. It results in a +% vbox. +% \begin{macrocode} +\ifx\@makefnvbox\@undefined + \def\@makefnvbox#1{\vbox{% + \@makefnstartbox + \clubpenalties\thr@@\@MM\clubpenalty\z@ + \let\@thefnmark\@empty + \FN@specific\FN@masterinsert\@makefntext{\rule\z@\footnotesep + \nobreak + #1\@finalstrut\strutbox + \@makefnendbox}}} +\fi +% \end{macrocode} +% \end{macro} +% \begin{macro}{\hfootfraction} +% \begin{macro}{\vtypefraction} +% Those parameters govern when a footnote block is going to be set +% completely in vertical mode. If a footnote block does not shrink +% to less than \cmd{\hfootfraction} its size when using in-paragraph +% notes or has at least \cmd{\vtypefraction} of forcedly vertical +% footnotes (specified as purely vertical, or vertical because of +% being large), it is set entirely in vertical mode. +% \begin{macrocode} +\def\hfootfraction{0.9} +\def\vtypefraction{0.7} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \begin{macro}{\FN@assembleboxes} +% This will produce the finished product, by generating all boxes +% and concatenating them except for the last vbox. It is assumed +% that have already set |\box\z@| to |\lastbox| before calling this +% routine (or, more likely, have already assembled and split the +% last box). The last, not yet unpacked |\vbox| is left in +% |\box\z@| on return. The original id of the last box of a block +% is properly transferred to it. +% +% The last box might have come about by joining several horizontal +% boxes, so splitting it might separate footnotes. We deal with +% that problem at a different point of time by checking the +% respective Ids when breaking a vbox into pieces: if the split +% piece does not contain the last footnote beginning, we switch to a +% slow motion decomposal. \cmd{\FN@assembleboxes} is supposed to be +% entered and exited in vertical mode. +% \begin{macrocode} +\def\FN@assembleboxes{% +% \ifhmode \PackageError{bigfoot}{Unexpected hmode}{}\fi + \ifhbox\z@ + \dimen@\dp\z@ +% \MFL@checksinglebox\z@\z@{}{}% + \dimen@ii\z@ + \setbox\tw@\box\voidb@x + \loop \advance\dimen@ii\dimexpr\ht\z@+\dp\z@\relax + \setbox\tw@\hbox{\box\z@\unhbox\tw@}% + \setbox\z@\lastbox + \ifhbox\z@ + \repeat + {\FN@assembleboxes\nointerlineskip\unvbox\z@}% +% \end{macrocode} +% At this point of time, |\box\tw@| contains a plain hbox with nothing +% but the unadorned hboxes in horizontal mode to be joined into one +% footnote block. All preceding footnote blocks have been emptied +% into the current vertical list. We put the |\unvbox| operations in +% a group so that the paragraph shapes will not get reset over the +% break. +% \begin{macrocode} + \global\setbox\FN@tempbox\copy\tw@ + \setbox\z@\@makefnvbox{% + {\unhbox\FN@tempbox}% + \setbox\z@\lastbox\FN@joinhboxes}% + \ifcase + \ifdim\FN@vfound>\dimexpr\vtypefraction\p@*\FN@found\relax \@ne\fi + \ifdim\dimexpr \ht\z@+\dp\z@>\hfootfraction\dimen@ii \@ne\fi \z@ + \or + \global\setbox\FN@tempbox\box\tw@ + \setbox\z@\@makefnvbox{\let\@makefnbreak\FN@pseudofillbreak + {\unhbox\FN@tempbox}\setbox\z@\lastbox\FN@joinhboxes}% + \fi + \setbox\tw@\box\voidb@x + \ht\z@\dimexpr \ht\z@+\dp\z@-\dimen@\relax + \dp\z@\dimen@ +% \MFL@checksinglebox\z@\z@{}{}% + \else + \ifvbox\z@ +% \MFL@checksinglebox\z@\z@{}{}% + {\setbox\z@\lastbox + \FN@assembleboxes\nointerlineskip\unvbox\z@}% + \fi + \fi} +% \end{macrocode} +% \end{macro} +% Ok, now follow a lot of fuzzy calculation routines. When we are +% considering truth values, |\p@| (1pt) corresponds to a value of +% ``true'', and |\z@| corresponds to ``false''. +% \begin{macro}{\FN@fuzzyeval} +% This calculates a ratio, something with which you multiply. The +% first two arguments of the function define an interval, and the +% third argument is a value in that interval. If |#3| is equal to +% |#1|, the resulting ratio is~0, if the |#3| is equal to |#2|, the +% resulting ratio is~1. Values in between are linearly +% interpolated. Values outside of the interval are mapped to 0 +% and~1. If all three values are equal (hardly useful), 1 is +% returned. +% \begin{macrocode} +\def\FN@fuzzyeval#1#2#3{% + \ifdim\dimexpr(#3)<\dimexpr(#2)\relax + \ifdim\dimexpr(#3)>\dimexpr(#1)\relax + *(\dimexpr(#3)-(#1))% + /(\dimexpr(#2)-(#1))% + \else *\z@ + \fi + \fi} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@fuzzyor} +% This returns probabilistic \textsc{or}: +% \[(|#1|+|#2|-|#1|\cdot|#2|)\] +% \begin{macrocode} +\def\FN@fuzzyor#1#2{(\p@-(\p@-(#1))*(\dimexpr\p@-(#2))/\p@)} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@magicclue} +% Ok, so here is the magic glue calculator. |#1| and~|#2| give the +% range over which the preceding line changes from `short' to `long'. +% |#3| and |#4| give the range over which the current line changes +% from `short' to `long'. Both are combined with a probabilistic or +% function, and then a penalty is chosen which ranges from |#5| +% to~|#6| for short to long. +% \begin{macrocode} +\def\FN@magicglue#1#2#3#4#5#6{% +% \if\foottrace2\traceon\fi + \dimen@\dimexpr\p@\FN@fuzzyeval{#1}{#2}\FN@lasthsize\relax + \dimen@ii\dimexpr\p@\FN@fuzzyeval{#3}{#4}{\ht\z@+\dp\z@}\relax + \dimen@\dimexpr\FN@fuzzyor\dimen@\dimen@ii + \count@\numexpr((#6)-(#5))*\dimen@/\p@+(#5)\relax + \xdef\FN@vfound{\the\dimexpr\FN@vfound+\dimen@}% + \ifnum\count@>-\@M + \penalty\count@ + \hskip\glueexpr -\parfillskip+1em minus 0.5em\relax + \else + \FN@pseudobreak + \fi + \xdef\FN@found{\number\numexpr\FN@found+\@ne}% +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@pseudobreak} +% This ends a line, but without introducing parskip and similar. It +% also `breaks in' the next line to get proper indentation. The +% main difference with regard to \cmd{\break} is that this restarts +% the reckoning of line numbers for the sake of \cmd{\clubpenalty} +% calculation. +% \begin{macrocode} +\def\FN@pseudobreak{% + {\parskip\z@skip\parfillskip\z@skip\parindent\z@\vadjust{}\par\noindent + \vadjust{\nobreak\vskip-\baselineskip}\nobreak\hfill\break}} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@pseudofillbreak} +% This is basically just for separating paragraphs by force. +% \begin{macrocode} +\def\FN@pseudofillbreak{\nobreak\hskip\parfillskip\FN@pseudobreak} +% \end{macrocode} +% +% \end{macro} +% \begin{macro}{\@makefnbreak} +% This calculates the glue for the standard horizontal footnotes. +% \begin{macrocode} +\def\@makefnbreak{\FN@magicglue {\footnotesep+\dp\strutbox}% + {\footnotesep+\dp\strutbox+\baselineskip}% + {\footnotesep+\dp\strutbox+0.5\baselineskip}% + {\footnotesep+\dp\strutbox+2\baselineskip}{-200}{-12000}} +% \end{macrocode} +% \end{macro} +% \cmd{\FN@joinhboxes} is called with box~0 set to the next box to be +% appended to the current list (all preceding hboxes on the current +% vertical list will have to go in front). \cmd{\FN@joinhboxes} is +% entered in vertical mode, and will be exited in horizontal mode. +% \begin{macrocode} +\def\FN@joinhboxes{% +% \ifvmode \errmessage{Unexpected vertical mode.}\fi + \begingroup\setbox\z@\lastbox + \ifhbox\z@ \FN@joinhboxes +% \ifvmode \errmessage{Unexpected vertical mode.}\fi + \endgroup + \nobreak\hskip\parfillskip + \@makefnbreak + \else +% \ifvbox\z@ \errmessage{Unexpected vbox.}\fi + \endgroup + \vadjust{\nobreak\vskip-\baselineskip}\nobreak\hfill\break + \xdef\FN@vfound{\z@}% + \xdef\FN@found{\z@}% + \fi + \xdef\FN@lasthsize{\the\dimexpr \ht\z@ +\dp\z@}% + \unhbox\z@} +% \end{macrocode} +% \begin{macro}{\FN@par} +% \begin{macro}{\FN@noindent} +% \begin{macro}{\FN@indent} +% In-paragraph footnotes are collected in horizontal mode. So +% |\par|, \cmd{\noindent} and \cmd{\indent} simply don't work. We +% replace them with something having the same effect when the boxes +% get unhboxed. Note that this does not admit the tracking of +% club/widow penalties: in a later version, it should get replaced +% by something that actually allows for separate paragraphs. One +% possibility would be to replace the current single hbox for an +% in-paragraph footnote by an hbox of hboxes and unbox all of them +% in separate paragraphs. But that glosses over the fact that a +% multi-paragraph footnote does not make sense in anything but +% vertical mode. So a saner way would probably be to close off the +% hbox altogether and reinsert it into a vbox, restarting the whole +% footnote in vertical mode. Both of those approaches would require +% that no groups have been opened since the start of the footnote by +% the time |\par| gets called. The below pseudosolution at least +% has the advantage of not depending on the grouping structure at +% all. +% \begin{macrocode} +\def\FN@par{\unskip\nobreak\hskip\parfillskip + \vadjust{\vskip\parskip}\break\null\kern\parindent\ignorespaces} +\def\FN@noindent{\unkern} +\def\FN@indent{\unkern{\setbox\z@\null\wd\z@\parindent\box\z@}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \begin{macro}{\MFL@fnoteplain} +% \begin{macro}{\MFL@fnotepara} +% We redefine |manyfoot|'s basic footnote calls to use our own, +% versatile variant. +% \begin{macrocode} +\def\MFL@fnoteplain{\FN@fnotenested{plain}} +\def\MFL@fnotepara{\FN@fnotenested{para}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \begin{macro}{\FN@fnotenested} +% This is somewhat contorted: we want |\footnote+| to be in |plain| +% style and |\footnote-| in |para| style regardless of the current +% footnote style. Adding a second |+| or |-| after the first will +% actually restyle all footnotes coming afterwards appropriately. +% This should work for all footnote commands getting footnote text. +% \begin{macrocode} +\def\FN@fnotenested#1#2#3{% + \edef\reserved@d{#1}% + \FN@checkvariant{\edef\reserved@d}{% + \FN@checkvariant{\FN@restylefootnote{#2}}% + {\csname FN@fnote\reserved@d\endcsname{#2}{#3}}}} + +\def\FN@checkvariant#1#2{\def\reserved@a{#1}% + \def\reserved@b{#2}% + \futurelet\reserved@c\FN@checkvariantii} + +\def\FN@checkvariantii{% + \ifx\reserved@c+% + \reserved@a{plain}\expandafter\@firstoftwo + \else\ifx\reserved@c-% + \reserved@a{para}\expandafter\expandafter\expandafter + \@firstoftwo + \fi\fi + \reserved@b} +% \end{macrocode} +% \end{macro} +% In order to be able to sort footnotes according to the order of +% their reference points, we use a sorted counter. +% \begin{macrocode} +\newcounter{FN@totalid} +\MakeSorted{FN@totalid} +% \end{macrocode} +% \begin{macro}{\FN@fnoteplain} +% \begin{macro}{\FN@fnotepara} +% The actual commands are easy enough: +% \begin{macrocode} +\def\FN@fnoteplain{\FN@fnotecommon\vbox} +\def\FN@fnotepara{\FN@fnotecommon\hbox} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \begin{macro}{\FN@masterinsert} +% This contains the insert number of the insert where the footnote +% mark appears. If it appears in the main text, 255~will be used. +% \begin{macrocode} +\def\FN@masterinsert{\@cclv} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@id} +% \begin{macro}{\FN@master} +% \begin{macro}{\FN@slave} +% Here is the deal with master and slave ids: each footnote has a +% unique master id. This master id is larger by one than the last +% id of its subordinate footnotes. It is recorded in the mark +% \cmd{\FN@master} in the footnote box at the start itself, although +% with an indirection through the \cmd{\FN@newslot} mechanism since +% the actual id can only become known after all subfootnotes have +% been typeset. The same id is recorded in \cmd{\FN@slave} at the +% ultimate end of the footnote. +% +% At the point where a \cmd{\FN@master} mark is placed, a default +% \cmd{\FN@slave} mark is placed also with an id that is one less +% than the smallest id generated from a footnote that is a +% `descendent' of the current one. This makes it possible to +% distinguish any split off subordinate footnotes. It must be noted +% that this sentinel slave id will be the valid id of a completely +% unrelated footnote! Since the value is only used for determining +% one end of an \emph{open} interval of excluded ids, this is no +% problem. All subordinate footnotes are numbered sequentially in +% the order of \emph{completion}, so that any subordinate footnotes +% have lower ids than their master. +% \begin{macrocode} +\newcount\FN@id +\FN@id\@ne +\newmarks\FN@master +\newmarks\FN@slave +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \begin{macro}{\FN@errorstack} +% This records the history of nested footnotes in order to deliver +% more useful error messages. +% \begin{macrocode} +\let\FN@errorstack\@empty +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@fnotecommon} +% Well, this is the work horse if the footnote macro. Really bad +% thing. We start off by stepping our absolute counter and making a +% mark. \cmd{\leavevmode} is required so that the action of +% |perpage.sty| is done smoothly. +% \begin{macrocode} +\def\FN@fnotecommon#1#2#3{% + \leavevmode + \stepcounter{FN@totalid}% + \NCC@makemark{#3}% +% \end{macrocode} +% It is an error if the footnote insert number of the current +% footnote does not correspond to a block below the current +% insertion level. +% \begin{macrocode} + \ifnum#2<\FN@masterinsert + \FN@colorstackbgroup\FN@divert + \FN@newslot\FN@masterslot + \count@\FN@id +% \end{macrocode} +% \cmd{\dimen@} is here set to a sorting criterion. This is +% designed to make the conversion of footnote blocks as reliable as +% possible. If we could guarantee convergence, just using +% \cmd{\c@FN@totalid} would be sufficient for sorting. It turns out +% that this is too sensitive to footnotes of different blocks +% changing pages, so the number of the superior footnote block is +% allowed to take precedence by multiplying it with 4194304 which is +% unlikely to get exceeded by \cmd{\c@FN@totalid}. +% \begin{macrocode} + \dimen@=\dimexpr64\p@*\FN@masterinsert-\c@FN@totalid sp\relax + \def\FN@masterinsert{#2}% + \edef\FN@errorstack{\FN@errorstack^^J% +\FN@masterinsert\space entered in line \number\inputlineno}% + \let\FN@boxtype=#1% + \setbox\z@#1\bgroup +% \end{macrocode} +% The following is for the likes of PDF\TeX\ which has its own idea +% about how to restore a color stack. +% \begin{macrocode} + \let\current@color\default@color + \FN@@color@begingroup + \let\MFL@minipage\relax + \let\MFL@endminipage\relax + \@makefnstartbox +% \end{macrocode} +% We reset the list parameters in footnotes. Strictly speaking, +% this is interfering with \LaTeX's standard operation, but the +% standard operation does not make sense. +% \begin{macrocode} + \let\@listdepth\@mplistdepth \@mplistdepth\z@ + \@itemdepth\z@ \@enumdepth\z@ + \protected@edef\@currentlabel{\csname p@footnote% + \expandafter\FN@stripfootins\string#2\endcsname\@thefnmark}% + \ifx\FN@boxtype\vbox \normalcolor\nobreak + \else \FN@specific{#2}\@preparefnhtext \normalcolor + \fi +% \end{macrocode} +% Ok, now we do the call to \cmd{\@makefntext} which may occur in +% one of several ways, depending on whether the `robust' or the +% `fragile' package option got used. +% \begin{macrocode} + \expandafter \FN@makefncall + \else +% \end{macrocode} +% We still needed to cater for the error of badly anchored footnotes: +% \begin{macrocode} + \PackageError{bigfoot}{#2 forbidden in \FN@masterinsert.}% + {Higher-placed footnotes can't be anchored in inferior ones.^^J% + I am not putting this text in a footnote. History:% +\FN@errorstack}% + \rule{1em}{\ht\strutbox}% +\fi} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@makefnstart} +% This is called in the start of \cmd{\@makefntext}. +% \begin{macrocode} +\providecommand{\FN@seitenobreak}{\nobreak} +\def\FN@makefnstart{% +% \end{macrocode} +% Record the footnote specific dimensions. It is assumed that they +% don't change in the document, at least not before the footnote +% gets actually placed. +% \begin{macrocode} + \expandafter\xdef\csname FN@ht\number\FN@masterinsert\endcsname + {\the\footnotesep}% + \expandafter\xdef\csname FN@dp\number\FN@masterinsert\endcsname + {\the\dp\strutbox}% + \expandafter\xdef\csname FN@wd\number\FN@masterinsert\endcsname + {\the\hsize}% +% \end{macrocode} +% The footnote gets markers for identifying it and its starting block. +% \begin{macrocode} + \marks\FN@master{\FN@masterslot}% + \marks\FN@slave{\number\FN@id}% + \nobreak +% \end{macrocode} +% \cmd{\FN@commonending} will intervene before any tokens that are +% shifted in due to switching back the color stack. Those will only +% be executed once we completely relinquish control. +% \begin{macrocode} + \ifx\FN@boxtype\vbox + \rule\z@\footnotesep + \else + \ifx\FN@par\par\else + \let\FN@@par\par + \let\FN@@noindent\noindent + \let\FN@@indent\indent + \fi + \everyvbox\expandafter{\expandafter\everyvbox + \expandafter{\the\everyvbox}% + \let\par\FN@@par + \let\noindent\FN@@noindent + \let\indent\FN@@indent + \the\everyvbox}% + \let\par\FN@par + \let\noindent\FN@noindent + \let\indent\FN@indent + \fi + \FN@seitenobreak + \afterassignment\ignorespaces} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@makefnrobust} +% After preparation, we now do the big bad trick for making +% footnotes cooperate with \cmd{\verb} and other catcode changing +% things: we call \cmd{\@makefntext} with an argument of +% |\iffalse|. This kills off its expansion right at the point +% where it would choose to place its argument. +% +% Furthermore, this swallows the opening brace of the footnote text +% and then lets the footnote text progress. The closing group will +% then trigger the processing via \cmd{\aftergroup}. +% \begin{macrocode} +\def\FN@makefnrobust#{% + \FN@specific\FN@masterinsert\@makefntext + \iffalse\fi + \bgroup + \aftergroup\FN@robustending + \FN@makefnstart + \let\next} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@robustending} +% Here we put in the missing part of \cmd{\@makefntext}. +% \begin{macrocode} +\def\FN@robustending{% + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter + \iffalse \FN@specific\FN@masterinsert\@makefntext\fi + \FN@commonending} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@makefnfragile} +% This is the escape route when the robust variant does not work. +% In that case, |\verb| and similar won't work in footnotes. +% \begin{macrocode} +\long\def\FN@makefnfragile#1{% + \FN@specific\FN@masterinsert\@makefntext + {\FN@makefnstart#1\FN@commonending}} +% \end{macrocode} +% +% \end{macro} +% +% Ok, color handling is a nuisance, to say the least. Split +% footnotes need to close their color stack on the old page, and reopen +% it on the new one. So we record the color stack state at each time +% it changes in a marks register. +% \begin{macrocode} +\newmarks\FN@color +\def\FN@colorstackbgroup{\let\FN@savecolorstack\FN@colorstack + \global\let\FN@colorstack\@empty + \bgroup + \ifdefined\FN@savecolorstack\else + \let\FN@@set@color\set@color + \let\FN@@reset@color\reset@color + \let\FN@@color@begingroup\color@begingroup + \fi + \let\set@color\FN@set@color + \let\reset@color\FN@reset@color + \let\color@begingroup\FN@color@begingroup} + +\def\FN@colorstackegroup{\egroup + \global\let\FN@colorstack\FN@savecolorstack} + +\def\FN@colorstackfinish{\def\@elt##1##2{\FN@@reset@color##2}% + \FN@colorstack + \def\@elt##1##2{\noexpand\@elt{}{##2}}% + \xdef\FN@colorstack{\FN@colorstack}% + \let\@elt\relax + \marks\FN@color{}} + +\def\FN@reset@color{% + \bgroup\def\@elt##1##2{\def\FN@next{##1}{\gdef\FN@colorstack{##2}}}% + \let\FN@next\@empty + \FN@colorstack + \ifx\FN@next\@empty + \FN@colorstackegroup + \else \egroup + \FN@@reset@color + \marks\FN@color{\FN@colorstack}% + \fi} + +\def\FN@color@begingroup{% + \let\reset@color\FN@@reset@color + \let\color@begingroup\FN@@color@begingroup + \let\set@color\FN@@set@color + \color@begingroup} + +\def\FN@set@color{\FN@@set@color + \xdef\FN@colorstack{\@elt{\current@color}{\FN@colorstack}}% + \marks\FN@color{\FN@colorstack}} + +\def\FN@coloraftersplit#1{% + \def\@elt##1##2{##2\def\current@color{##1}\set@color}% + #1% + \let\@elt\relax} +% \end{macrocode} +% \begin{macro}{\FN@commonending} +% We'll eventually arrive here at the end of the footnote. Now we +% again call \cmd{\@makefntext}, but this time pass it |\fi| as +% its argument, and place |\iffalse| before its expansion. This +% cuts away the start of the macro. If this start changes the tail +% of the macro when executed, the whole trickery will not work. It +% turns out that a large sampling of document classes (including the +% standard ones) happens to work. +% \begin{macrocode} +\def\FN@commonending{% + \@makefnendbox + \ifx\FN@boxtype\vbox\@finalstrut\strutbox \else \unskip \fi + \FN@colorstackfinish + \color@endgroup + \egroup + \global\advance\FN@id\@ne + \FN@slotxdef\FN@masterslot{\number\FN@id}% +% \end{macrocode} +% Now we want to get an upper estimate of the size. In case of a +% horizontal box, we do this by creating a vertical box of it all +% alone, and measuring that. Measuring the hbox itself is plain +% out: \TeX's maximal dimension of something like 5\,m is already +% busted with about two pages of material. We put the master slot +% identification into the depth of the box, and arrange for the +% total of depth and height of the box to still give the total depth +% and height of its size on the page. +% \begin{macrocode} + \ifhbox\z@ + \global\setbox\FN@tempbox\copy\z@ + \setbox\tw@\@makefnvbox{\unhbox\FN@tempbox}% + \ht\z@\dimexpr\ht\tw@+\dp\tw@-\FN@masterslot sp\relax + \else + \ht\z@\dimexpr\ht\z@+\dp\z@-\FN@masterslot sp\relax + \fi +% \end{macrocode} +% Now we put the sorting criterion into the width of the box, and +% then put the masterslot id into the depth. +% \begin{macrocode} + \wd\z@\dimen@ + \dp\z@\FN@masterslot sp\relax +% \ifnum\z@<0\FN@slotget{\FN@masterslot} % +% \else \errmessage{Inconsistent +% \string\FN@masterslot=\FN@masterslot}\fi +% \end{macrocode} +% Now we just need to place the stuff into an insertion and record +% the possibly changed slave id in order to know what subordinate +% footnotes belong to this one. +% \begin{macrocode} + \MFL@insert\FN@masterinsert{\nointerlineskip\box\z@}% + \ifdim\lastkern=\z@ \let\FN@next\@empty\else + \edef\FN@next{\kern\the\lastkern\relax}\unkern + \fi + \marks\FN@slave{\number\FN@id}% + \expandafter\FN@enddivert\expandafter\FN@colorstackegroup + \FN@next +} +% \end{macrocode} +% \end{macro} +% A lot of stuff follows. This should really be cleaned up and +% documented. +% \begin{macrocode} +\dimen\footins\maxdimen +\gdef\FN@nestlist{} + +\newdimen\FN@outervsize +\newskip\FN@vsize + +\newbox\FN@insertions + +%\def\MFL@showone#1#2{\message{Box #2:}\showbox#2% +% \MFL@checkconsistency{#2}% +% \message{Cachebox #2:}\showbox\FN@cache#2} +% +%\def\MFL@checkconsistency#1{{% +% \setbox\z@\vbox{\unvcopy#1% +% \MFL@checkconsistencyi{#1}}}} +% \end{macrocode} +% \begin{macro}{\MFL@checksinglebox} +% Check box~|#1| for consistency. If it is bad, output box~|#2|. +% Execute |#3| if it was good, |#4| if it was bad. +% \begin{macrocode} +%\def\MFL@checksinglebox#1#2#3#4{% +% \ifvoid#1\else +% \ifnum\z@<0\FN@slotget{\number\dp#1} % +% #3% +% \else \errmessage{Inconsistent box #2}% +% \showboxdepth4\showboxbreadth100 +% \showbox#2\relax +% #4% +% \fi\fi} +% \end{macrocode} +% \end{macro} +% \begin{macrocode} +%\def\MFL@checkconsistencyi#1{% +% \unpenalty\unskip\unkern +% \setbox\z@\lastbox +% \MFL@checksinglebox\z@{#1}{{\MFL@checkconsistencyi{#1}}}{}} +% +%\def\MFL@showall{{% +% \showboxbreadth=\maxdimen +% \showboxdepth=4 +% \tracingonline=\@ne +% \FN@nest@iterate\MFL@showone}} +% \end{macrocode} +% \begin{macro}{\FN@retaindelayed} +% This is a complex macro that removes all boxes from the current +% list that are not to be kept for the next page. It works on the +% material from the original insertions, not the cache boxes. +% The slot specified by \cmd{\count@} is not freed when encountered, +% all others are freed upon removing the box. The last box is +% returned in box~0 if any is retained. The vertical list might +% have an unchecked part locked off in front by placing a +% \cmd{\nobreak} penalty there. This penalty is removed, and the +% list before it not touched. +% \begin{macrocode} +\def\FN@retaindelayed{% + \setbox\z@\lastbox + \ifcase + \ifvoid\z@\m@ne\fi \FN@config\z@ +% \if\foottrace8\message{^^J\string\FN@retaindelayed: +% dropping Id \FN@slotget{\number\dp\z@}}\fi +% \if\foottrace{16}{\showboxdepth4 \showboxbreadth400 +% \tracingonline=\@ne\showbox\z@}\fi + \ifnum\dp\z@=\count@\else \FN@freeslot{\number\dp\z@}\fi +% \ifnum\dp\z@<\@ne \errmessage{Unidentified box}\fi + \expandafter\FN@retaindelayed + \or +% \if\foottrace8\message{^^J\string\FN@retaindelayed: +% retaining Id \FN@slotget{\number\dp\z@}}\fi +% \if\foottrace{16}{\showboxdepth4 \showboxbreadth400 +% \tracingonline=\@ne\showbox\z@}\fi + {\FN@retaindelayed \nointerlineskip \box\z@}% + \else \unpenalty \setbox\z@\lastbox +% \ifnum\lastnodetype>\m@ne +% \errmessage{Unexpected node \number\lastnodetype}\fi +% \ifvoid\z@ \else +% \if\foottrace8\message{^^J\string\FN@retaindelayed: +% carrying split box \FN@slotget{\number\dp\z@}}\fi +% \if\foottrace{16}{\showboxdepth4 \showboxbreadth400 +% \tracingonline=\@ne\showbox\z@}\fi\fi + \fi} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\MFL@processplain} +% This gets called for actually inserting the processed material +% into the footnote box. The current state of affairs is that +% \cmd{\FN@config} contains all footnotes that should get +% transferred to the next page completely. The cache boxes contain +% the collected and typeset footnotes for typesetting on the current +% page. +% +% The structure of a cachebox is currently as follows: it is filled +% with vboxes containing the arranged material, optionally followed +% by another box to be carried over to the next page flagged with a +% \cmd{\nobreak} penalty. +% \begin{macrocode} +\def\MFL@processplain#1{% +% \MFL@checkconsistency#1% + \ifvoid\FN@cache#1% +% \end{macrocode} +% Now if the cache box is void, nothing gets typeset on the current +% page. What we do, however, is to collect all boxes from the +% original insertion that did not make it on this page and reinsert +% them. \cmd{\count@} is cleared to zero to retain nothing special. +% \begin{macrocode} + \global\setbox\FN@tempbox\vbox\bgroup + \unvbox#1% + \count@\z@ + \let\@elt\FN@removecheck \FN@retaindelayed + \ifvoid\z@ \egroup + \else \nointerlineskip \box\z@ \egroup + \MFL@realinsert{#1}{\unvbox\FN@tempbox}% + \fi +% \end{macrocode} +% The following stops in the insertion process within the |manyfoot| +% package. +% \begin{macrocode} + \expandafter\expandafter + \fi\iffalse\fi +% \end{macrocode} +% Ok, this is the case when we have a nonvoid cache box. +% \begin{macrocode} + \global\setbox#1\vbox\bgroup% + \unvbox\FN@cache#1% + \ifnum\lastpenalty>\z@ + \unpenalty + \setbox\z@\lastbox + \else + \setbox\z@\box\voidb@x + \fi +% \end{macrocode} +% Ok, now box zero contains carryover material (if any). We +% initialize \cmd{\count@} to this so that we will keep this carryover +% material just once. +% \begin{macrocode} + \count@\dp\z@ + \global\setbox\FN@tempbox\vbox\bgroup + \box\z@ + \nobreak + \unvbox#1% + \let\@elt\FN@removecheck \FN@retaindelayed + \ifvoid\z@ \egroup \MFL@removevboxes\egroup + \else \nointerlineskip \box\z@ \egroup + \MFL@removevboxes \egroup + \MFL@realinsert{#1}{\unvbox\FN@tempbox}% + \fi} + +\let\MFL@processpara\MFL@processplain +% \end{macrocode} +% \end{macro} +% Ok, here is the bit about the caches: whenever we encounter a new +% configuration, we have to first update the caches since we don't +% know the sizes we are dealing with regarding the new configuration +% until we do so. The caches are kept up to date globally. When we +% are working at several levels in the recursion, we have a bottom +% active level where we may are looking for a way to find a best break +% and configuration. We will return at most one configuration once we +% are finished. While we are working with a returned configuration, +% adding more material on the current list will not require another +% recursion as long as the totals stay underfull: the penalty +% difference between underfull configurations becomes smaller while +% the underfullness decreases, which means that smaller breaks that +% have not been chosen before might become eligible if the penalties +% allow for that. Only when the badness of underfullness remains +% infinite can't we have any improvement. +% +% Ok, after we recurse for removing an underfull condition, the +% resulting configuration can't actually be used further for breaks +% with less remaining space. It is, however, clear that if less space +% remains, there is no better break with the same configuration +% leaving \emph{more} space: if there were, it would already have been +% taken. That means that our goal height for the next break will be +% chosen in order to reach the exact size met on the last recursion. +% No break before that can be chosen on the next try, but a break +% after it might then be taken. +% +% available, or an overfull one. If a deeper level at any point of +% time returns an overfull configuration, we are finished. The best +% configuration to be returned is the least underfull. If there is +% none, the least overfull. The case of no underfull at all can only +% happen if even splitting this and every subordinate level to minimal +% height and recursing does not yield an underfull. At every level, +% we need to maintain just a current split, and the previous best +% split at most. +% +% When we change a configuration on recursing, we have to remember the +% configurations for the previous best split. We can manage that by +% sweeping the current cache values into a local box register +% before recursing with a different configuration: we have to rebuild +% the box registers for a different configuration, anyway. We don't +% save the configuration from an overfull setting: when we rework the +% list in slow motion mode, we can't help stopping the recursion by +% reaching an overfull setting that is at least as good as the +% initial one. +% +% When we return to a caller, we leave the cache in the configuration +% of the best choice up to now: either we are returning an overfull +% configuration and if it is not the best so far, the caller can +% restore his better choice from his copy, or we are returning an +% underfull configuration in which case the caller might still want to +% improve upon it before returning to its caller in turn. New: If we +% return an underfull configuration, we also return an ``optimal +% penalty estimate'' that gives the best break point penalty under the +% assumption that additional stretchability is present on the page. +% +% The purpose of this is to offer the possibility of avoiding widows +% and similar by moving more material in some footnotes to the next +% page in exchange for other material. +% +% At the current grouping level we empty out our current cache and +% keep it for working purposes on the vertical list until we return +% (nobody references it while we are working on it). We always enter +% with an overfull configuration, meaning that \cmd{\FN@vsize} is +% negative. It is calculated with the current cache\slash config +% setting. +% +% There is a danger of overflow involved with that: if we keep a swept +% complete configuration at each level of recursion, we need $O(n^2)$ +% of space here. The alternative would be to keep the history of how +% the configuration came about. Since that might involve some +% slow-motion splitting, this is also a speed issue. Since deep +% recursion with pending best data at each level is not really +% likely, and since we are not going to have that many footnote +% levels to go around, anyway, we just rely on \LaTeX\ having been +% started with sufficient memory. +% +% A workable compromise would be to just store the split boxes +% from a configuration together with the configuration data for +% reconstructing the rest. After all, we don't need to reconsider +% such a configuration before actually typesetting anything. And +% whenever we find an acceptable fit (neither underfull\slash +% overfull), we could cut through all the hierarchy without having to +% restore anything. This has not been implemented yet: at the moment +% we go for the less complicated variation. +% +% +% The algorithm we use here is a bit complicated. Whenever we +% recurse, we have one of the following situations: +% \begin{enumerate} +% \item An overfull/underfull dilemma: including a minimal amount of +% material at the current level will cause the page to become +% overfull. This can be the case in connection with zero (in +% case of interline penalties for larger blocks), one or more +% subordinate footnotes and related footnotes. +% \item A pure overfull dilemma: the page was overfull to start with, +% we need to reduce it. +% \item an underfull dilemma: some operation in the next level made +% the page become underfull, only too much so. We can't make it +% fuller on the current level, but we can make it even emptier, +% and let the next level fill it up again. +% \end{enumerate} +% +% In the current implementation, we just ignore the slight probability +% that the optimum choice might lie with case~3. We don't +% recurse for making the page fuller again. If we have an +% overfull/underfull dilemma, the recursion will either give us a +% less awful overfull box, or an underfull one. An overfull box that +% occurs at the highest level of recursion can't be improved on any +% lower level. So we never need to locally return an overfull box: we +% can compare it to the best overfull box seen before, and if we turn +% out better than that, we overwrite the global best overfull value +% and return the best local underfull if there is such a one. The +% best local underfull will then be refilled as much as possible on +% the next level without changing the configuration. Actually, if we +% need to change the configuration, this would also be fine as long as +% we arrive at a better underfull eventually. But since a change of +% configuration renders our previous split completely useless, as the +% broken paragraph could look disastrously different under a changed +% configuration, we would need to recurse again. We repeat this +% recursing operation until we don't get an underfull solution +% returned anymore. We then return the best underfull, if any. The +% best overfull is stored globally, as mention before. +% +% Does this sound complicated? Unfortunately, it does. It also +% sounds somewhat slow. For that reason, we do a few assumptions that +% will facilitate a good average-case behavior. The first assumption +% is that we will usually do fine by just splitting in the current +% level (if at all) and not at all in subordinate levels. +% +% We do this assumption on the first pass used for gathering the size +% information and collect the corresponding boxes in nested lists. +% When the recursion tops out, it does so either with an overfull +% page, or an underfull page. If it does with an underfull page, we +% cache the current configuration for the next pass through the output +% routine, so that we won't need to retypeset and measure assembled +% boxes that have not gathered any new material. If we top out with an +% overfull page, the previous underfull configuration is still worth +% keeping as well, as it might become the material actually chosen to +% be typeset. +% +% Ok, the current best configuration of the next recursion level is +% gathered on the current vertical list, in a separate box. We use +% box~2 for this purpose. A saved configuration consists of the +% complete contents for the current cache box without the trailing +% penalty indicating material from a single split box carried over to +% the next page (boxes that are carried over completely to the next +% page are not maintained here but rather reinserted by +% \cmd{\MFL@processnested}). This penalty is added in case the box +% is actually disassembled and returned: there is no possibility for +% confusion since we only save such a configuration if indeed there is +% a split present. +% \begin{macrocode} +\newtoks\FN@output +\FN@output\output + +\newbox\FN@tempbox +\newinsert\FN@savebox +\count\FN@savebox\@m +\dimen\FN@savebox\maxdimen +\skip\FN@savebox\z@skip +\global\setbox\FN@savebox\box\voidb@x + +\expandafter\expandafter\expandafter\let\FN@cache\FN@savebox=\@cclv + +\expandafter\def\csname FN@ht\number\FN@savebox\endcsname{\z@skip}% +\expandafter\def\csname FN@dp\number\FN@savebox\endcsname{\maxdepth} +\expandafter\def\csname FN@wd\number\FN@savebox\endcsname{\columnwidth} + +\def\FN@list{\MFL@list\@elt{}\footins} + +\def\FN@sweepbox#1#2{\ifvoid#2\else + \nointerlineskip\box#2\penalty#2\fi} + +\def\FN@sweepcachebox#1#2{\nointerlineskip + \box\FN@cache#2% + \penalty\FN@cache#2} + +\def\FN@copycachebox#1#2{\nointerlineskip + \copy\FN@cache#2% + \penalty\FN@cache#2} + +\def\FN@restoreboxes{\count@\lastpenalty \unpenalty + \ifnum\count@>\z@ + \global\setbox\count@\lastbox + \expandafter\FN@restoreboxes + \fi} +% \end{macrocode} +% \begin{macro}{\FN@removecheck} +% This returns |\@ne| if and only if the current slot master is strictly +% inside of the specified open interval. In this case it is not to +% appear on the current page. +% \begin{macrocode} +\def\FN@removecheck#1#2{% + \ifnum#1<\FN@slotget{\number\dp\z@} % + \ifnum#2>\FN@slotget{\number\dp\z@} % + \@ne\fi\fi} +% \end{macrocode} +% \end{macro} +% Parameter recording merely records the relevant value of the +% skip register and sets it to zero. The purpose is to avoid changes +% of the reserved page space when we collect additional material from +% a page where an insertion of the appropriate kind had already been +% encountered. This is used for filling up underfull pages. +% \begin{macrocode} +\def\FN@recordinsertparam#1#2{\ifvoid#2\else + \global\skip\number#2=\the\skip#2\relax\fi} + +\def\FN@clearinsertparam#1#2{\ifvoid#2\else + \global\skip#2=\z@skip\fi} +% \end{macrocode} +% \cmd{\FN@insertouterspace} will sum the size of the inserts manually. +% \begin{macrocode} +\def\FN@insertouterspace#1#2{\ifvoid#2\else + +\skip#2+(\ht#2+\dp#2)*\count#2/\@m\fi} + +\def\FN@list@iterate#1{\let\FN@eltsave\@elt + \let\@elt#1% + \FN@list + \let\@elt\FN@eltsave} + +\def\FN@nest@iterate#1{\let\FN@eltsave\@elt + \let\@elt#1% + \FN@nestlist + \let\@elt\FN@eltsave} +% \end{macrocode} +% +% \subsection{The output routine stuff} +% +% \paragraph{Marks} +% This is used for sweeping all marks up for reinsertion. +% \begin{macro}{\FN@allmarks} +% \begin{macrocode} +\def\FN@allmarks#1{\@elt{#1}% + \ifnum#1<\count266 + \expandafter\FN@allmarks\expandafter{\number\numexpr#1+\@ne}% + \fi} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@sweeptopmarks} +% \begin{macro}{\FN@topmarkbox} +% This sweeps the current topmarks and places them into the global box +% \cmd{\FN@topmarkbox}. +% \begin{macrocode} +\def\FN@sweeptopmarks{\global\setbox\FN@topmarkbox\vbox{% + \def\@elt##1{\marks##1{\unexpanded\expandafter{\topmarks##1}}}% + \FN@allmarks0}} +\newbox\FN@topmarkbox +% \end{macrocode} +% \end{macro} +% \end{macro} +% \begin{macro}{\FN@establishmarks} +% This sets marks from a marks sweep. The first argument is the +% mark number, the second is from the first mark on the first scan, +% the third argument from the bottom mark on the first scan, and the +% fourth argument from the bottom mark on the second scan (with +% additional mark entries). If second and third arguments don't +% match, no mark gets placed. +% \begin{macrocode} +\long\def\FN@establishmarks#1#2{\edef\reserved@a{\unexpanded{#2}}% + \edef\reserved@b{\unexpanded\expandafter{\splitbotmarks#1}}% + \ifx\reserved@a\reserved@b + \marks#1{\unexpanded\expandafter{\splitfirstmarks#1}}% + \marks#1{\unexpanded\expandafter{\reserved@b}}% + \fi} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@markspassone} +% This constitutes the first pass for mark collection. We do this +% just to check whether there are any marks in the list. +% \begin{macrocode} +\def\FN@markspassone#1{\noexpand\FN@establishmarks{#1}% + {\unexpanded\expandafter{\splitbotmarks#1}}} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@insertmarks} +% This routine transfers first and bottom marks from the current +% |\box255| to the vertical list in order to get the marks right. +% This is quite a bother, since we must detect the special case +% where there are no marks at all in the list, and since we might +% require the use of several \cmd{\vsplit} commands in a row, since +% infinite stretch might make the optimal breakpoint lie before the +% end of the box in spite of its large size. +% +% So we need to do the splitting in a loop, and do it twice, once +% with artificial marks at the start. If those artificial marks +% make it to \cmd{\splitbotmarks}, we don't place any actual marks. +% \begin{macrocode} +\def\FN@pseudomarks#1{\marks#1{X}} +\def\FN@insertmarks{% + {\setbox\z@\copy\@cclv + \splittopskip-\maxdimen\relax + \vbadness=\@M + \vfuzz=\maxdimen + \loop + \ifvoid\z@\else + {\let\@elt\FN@pseudomarks + \setbox\z@\vbox{\FN@allmarks0\nobreak\unvcopy\z@}% + \setbox\z@\vsplit\z@ to\maxdimen}% + \let\@elt\FN@markspassone + \edef\next{\FN@allmarks0}% + \setbox\z@\vbox{\nobreak\unvbox\z@}% + {\setbox\z@\vsplit\z@ to\maxdimen}% + \next + \repeat}} +% \end{macrocode} +% \end{macro} +% \paragraph{Some stuff} +% +% \begin{macro}{\FootnoteMainMinimum} +% This specifies the minimum amount of main text. You can make this +% a complicated expression if you want to, for example by checking +% the presence of particular footnotes. +% \begin{macrocode} +\def\FootnoteMinimum{1sp} +\def\FootnoteMainMinimum{0pt} +\expandafter\def\csname\string\FootnoteMinimum\number\FN@savebox +\endcsname{\FootnoteMainMinimum} +% \end{macrocode} +% \end{macro} +% +%\paragraph{The output routine itself} +% +% This is our own output routine that does all the balancing stuff. +% If we receive a forced penalty here, we must not do any of our +% output processing on our own unless this is the choice of the +% underlying output routine. We do want to have the `real' output +% routine to have a correct idea about the size that the insertions +% will take up. So the steps that we \emph{will} actually perform in +% any case are sorting the insertions and calculating their real +% size. If we have not had a forced penalty, we are free to exit the +% output routine for gathering further material as there are no +% expections of the underlying output routine when it should get +% called. If we encountered a forced penalty, things are getting more +% complicated. If the current page happens to be overfull after +% adding the current material, we first need to ship out the material +% for a regular page (after splitting off the necessary material for +% the next page). We then reinsert the remaining split insertions, +% any possibly split off page material and the penalty. +% +% \TeX\ is rather monotonous in its page break processing. Increase +% the available page size, and the available page material will also +% increase. There is a singular exception to that rule, and that are +% split and floating insertions. However, we notice their presence by +% a non-zero setting of \cmd{\insertpenalties}, and we can just +% measure the material that they have taken up in a forced pass of the +% output routine, adding that much to our request size. However, this +% operation will change the penalties associated with the page breaks. +% +% Unfortunately, this is not sufficient: the penalty might have been +% inserted with a box immediately preceding it. In that case the +% penalty would have been guaranteed to eventually turn up in the +% output routine. If we now reinsert merely all of the above stuff, +% the penalty will just disappear. If we protect the penalty by +% placing an empty box before it when none of it had been before it +% before, we will get an empty page. Since we don't know whether the +% penalty was supposed to disappear at the start of an empty page or +% not, we will do the following: if the rest of |\box255| is nonvoid, +% we just reinsert the split insertions followed by the rest of +% \box255 and the penalty and return. If it is void, we call the +% regular output routine, capturing its output in a |\vbox| of its +% own. If the regular output routine failed to ship out the prepared +% insertions, we just keep the original data either in their boxes or +% in a reinserted insertion. +% +% It hides the relevant information from the `real' output routine +% until such a time that we have enough material gathered to produce a +% full page. The exception to this is when we have a special penalty +% that gets passed through to the regular output routine. +% +% If we are on a material collecting spree, \cmd{\FN@savebox} contains +% all boxes from the last output call time. At the point where we +% enter the output routine, \cmd{\FN@vsize} contains the amount of +% space available for mounting footnotes, after subtracting all +% insertions of footnote variety. At most times in our output +% routine, the variable will contain the amount of space left after +% everything is put to the page including footnotes. +% \begin{macrocode} +\savingvdiscards=\@ne +% \end{macrocode} +% We have the following situations that can cause us to enter the +% output routine: +% \begin{enumerate} +% \item The page has just filled up. +% \item A magic output penalty has been encountered. +% \item We are filling up a previously underfull page. +% \item We are looking for missing insertions that may have floated. +% \end{enumerate} +% +% We are trying to do bookkeeping on the effects of page size for +% insertions that fall into the footnote class. While we do basic +% bookkeeping for other insertions as well, this can only be +% incomplete since we don't reinsert material. In consequence, +% multiple material ending up in the same insertion might cause the +% corresponding skip register to be accounted for several times. +% \LaTeX\ does not really reuse insertions in that manner except for +% footnotes, so we are mostly ok here. +% +% |bigfoot| usually does some lookahead in the main list in order to +% obtain optimal breakpoints. It explicitly undoes the effect this +% has on marks, but insertions are a different matter here. So floats +% may appear on an earlier page than expected. +% +% If the output routine is invoked with a penalty of $-13750$, then +% the page content is merely used for setting the \cmd{\topmarks} +% array. In that case, we just clear out the output box and resume. +% We don't fiddle with \cmd{\deadcycles} in order to catch foulups. +% +% Also we don't touch insertion boxes. There is a particular +% situation where there \emph{are} insertions, namely if we are +% collecting insertions after the last output routine has ended up +% with a non-zero value of \cmd{\insertpenalties}. In this case, all +% insertions we \emph{do} get are floating insertions, meaning that +% they had a preceding insertion of the same class already on the last +% page, and thus we have zeroed its skip register already. We are +% assuming that a single pass with such a large \cmd{\vsize} is +% sufficient for pulling all insertions. If that happens to be +% incorrect, insertions need to get pulled in piecewise, but then we +% are probably in big dodo with regard to page size accounting, +% anyway. +% \begin{macrocode} +\newcount\FN@outputflag +\FN@outputflag=3158345 +\output{% + \let\@elt\relax + \ifvoid\@cclv \PackageError{bigfoot}{Empty box 255 in \output}\fi +% \if\foottrace8% +% \message{entering output with +% \outputpenalty=\the\outputpenalty:}% +% {\showboxdepth4\showboxbreadth\maxdimen\showbox\@cclv}\fi + \ifnum\outputpenalty=-13750 +% \if\foottrace8% +% \message{Discarding box 255.}% +% \fi + \ifnum\insertpenalties>\z@ + \PackageError{bigfoot}{Too much insertion material}{% + This error means that the output routine was not able to^^J% + gather all floating insertions in a single pass.^^J% + Complain to the author if you consider this a bug}% + \fi + \global\advance\FN@outervsize\dimexpr\ht\@cclv-\vsize + \global\setbox\@cclv\box\voidb@x + \else +% \end{macrocode} +% Note that a potential \cmd{\FN@vsadjustlist} will restore the +% previous value of \cmd{\outputpenalty}. So we need to save it. +% \begin{macrocode} + \edef\FN@outputpenalty{\number\outputpenalty}% + \ifvoid\FN@savebox + \ifvoid\@holdpg + \FN@sweeptopmarks + \fi + \FN@nest@iterate{\FN@insertouterspace\global\FN@outervsize + \dimexpr\z@}% + \global\advance\FN@outervsize\ht\@cclv + \global\setbox\@cclv\vbox{\unvbox\@cclv\boxmaxdepth\maxdepth}% + \global\let\FN@vsadjustlist\@empty +% \end{macrocode} +% \cmd{\FN@outervsize} now contains the value of \cmd{\pagegoal} at +% the time of output. It should be \cmd{\vsize} adjusted by the +% natural size of insertions. Note that \cmd{\FN@normaloutput} is not +% required to return with a sensible value of \cmd{\outputpenalty}. +% \begin{macrocode} + \FN@normaloutput + \else +% \end{macrocode} +% We now are in the situation that we already have collected material +% previously. We can't be sure that adding a special penalty does not +% take more than one output routine call before delivery. For that +% reason, we don't rely on special outputs being special and always +% subtract any additionally demanded \cmd{\vspace} from +% \cmd{\FN@outervsize} before calling a special output, so that we can +% afterwards compensate for it. +% \begin{macrocode} + \FN@nest@iterate{\FN@insertouterspace\global\advance\FN@outervsize + \dimexpr\ht\@cclv}% + \global\setbox\@cclv\vbox{\unvbox\@cclv\boxmaxdepth\maxdepth}% +% \end{macrocode} +% Now we invalidate the cache boxes for all insertions that had +% changed due to the recent additions to the page (this does +% \emph{not} affect \cmd{\FN@vsize}). +% \begin{macrocode} + \FN@nest@iterate\FN@maybeinvalidatecache +% \end{macrocode} +% We now update all boxes by inserting the previously collected +% material in front of the boxes. +% \begin{macrocode} + \vskip\z@skip + \unvbox\FN@savebox + \loop + \count@\lastpenalty + \ifnum\count@>\z@ + \unpenalty + \setbox\z@\lastbox + \global\setbox\count@\vbox{\unvbox\z@\unvbox\count@}% + \repeat + \ifcase + \ifnum\FN@outputpenalty=-13749 \@ne\fi + \ifnum\FN@outputpenalty=-13751 \@ne\fi \tw@ + \or +% \end{macrocode} +% \cmd{\outputpenalty} is restored to the original value before the +% total page is glued together. +% \begin{macrocode} + \FN@vsadjustlist +% \if\foottrace8\message{receiving special penalty +% \FN@outputpenalty, dissing box 255:}% +% {\showboxdepth4 \showboxbreadth400 +% \tracingonline=\@ne\showbox\@cclv}\fi +% \end{macrocode} +% This special penalty means that we have been collecting floated +% insertions right now. So |\box255| is actually empty except for +% filler material. We restore the old box into it. +% \begin{macrocode} + \global\setbox\@cclv\lastbox + \unskip +% \ifnum\lastnodetype>\m@ne +% \errmessage{Unexpected node \number\lastnodetype}\fi + \ifnum\FN@outputpenalty=-13749 + \FN@normaloutput + \else + \the\FN@output + \@pageht-\vsize + \let\@currbox\footins + \@reinserts + \global\vsize-\@pageht + \fi + \else + \dimen@\topskip + \FN@vsadjustlist + \setbox\z@\lastbox + \unskip +% \ifnum\lastnodetype>\m@ne +% \errmessage{Unexpected node \number\lastnodetype}\fi +% \end{macrocode} +% Ok, now we reconstruct the box from its parts. We add the material +% together, taking the previous output penalty and the current page +% discards (if it belongs between those boxes, otherwise we leave it +% on the list) for glueing the stuff together. The previous output +% penalty then is irrelevant for further purposes and we replace it +% again. \cmd{\FN@outervsize} has been +% adjusted by the accumulated contributions of insertions to the page +% size. Fiddling with it would not appear necessary or even prudent. +% \begin{macrocode} +%\if\foottrace8 +% \message{Box 255 before reglue +% (outputpenalty=\the\outputpenalty):}% +% {\showboxdepth4\showboxbreadth100\showbox\@cclv}\fi + \global\setbox\@cclv\vbox{% +% \end{macrocode} +% Now we might have had a \cmd{\topskip} value designed for requesting +% a given number of lines. We need to remove anything of that kind. +% Splitting again achieves that. If the current page was empty except +% for insertions, this means that we gain a new breakpoint. But +% insertions with discardable material before them would be unusual. +% +% The only exception to this may happen if the current page contained +% only insertions: in this case \TeX\ has made a page break before the +% actually inserted \cmd{\topskip} glue (which will then arrive one +% page later). +% +% Note that the pagediscards contain material corresponding to the +% last breakpoint chosen, so they will either start with a penalty +% of~10000 (which is what an actual outputpenalty gets replaced with) +% or will start with discardable material. We clean it for that +% reason. +% \begin{macrocode} + \unvbox\z@ + \global\setbox\@cclv\vbox{\break\unvbox\@cclv}% + {\splittopskip-\maxdimen \setbox\z@\vsplit\@cclv to\z@}% + \ifnum\outputpenalty=\@M + \setbox\z@\vbox{\pagediscards + \FN@cleanpagepenalty}% + \unvbox\z@ + \else + \penalty\outputpenalty + \pagediscards + \fi + \unvbox\@cclv + \boxmaxdepth\maxdepth}% +%\if\foottrace8 +% \message{Box 255 reglued (outputpenalty=\FN@outputpenalty):}% +% {\showboxdepth4\showboxbreadth100\showbox\@cclv}\fi + \global\outputpenalty\FN@outputpenalty\relax +% \end{macrocode} +% Ok, now if \cmd{\topskip} is actually \emph{positive}, we have been +% collecting material tentatively without having proper marks. We +% then need to fill in the marks into the list and try again. Note +% that we are not reinserting anything in order to compensate for +% \cmd{\outputpenalty} being replaced by a nobreak: this is the job of +% \cmd{\FN@normaloutput} when it decides to place material back on the +% page. That is: when code is written that will make use of +% pagediscards, it has to cater for their proper structure. +% \begin{macrocode} + \ifdim\dimen@>\z@ +% \if\foottrace8 +% \message{recycling special penalty} +% \fi + \hrule\@height\z@\@depth\z@ + \unvcopy\FN@topmarkbox + \penalty-13750 + \penalty\FN@outputflag + \hrule\@height\z@\@depth\z@ + \FN@insertmarks + \penalty-13749 + \penalty\FN@outputflag + \FN@prepareoutput + \global\topskip-\maxdimen + \global\vsize0.5\maxdimen + \global\advance\FN@outervsize-\vsize + \else + \FN@normaloutput + \fi + \fi + \fi + \fi} +% \end{macrocode} +% \begin{macro}{\FN@normaloutput} +% This is the normal output routine we use. +% Now we have recovered a sensible state and glued everything together +% that has been necessary. All insertion parameters are at their +% standard values, and any insertions have been collected in the +% respective boxes. +% \begin{macrocode} +\def\FN@normaloutput{% +% \if\foottrace8\message{^^JEntering \string\FN@normaloutput:^^J}\fi +% \end{macrocode} +% \cmd{\FN@vsize} is now being set to the vertical size taken up by +% the insertions, according to \TeX. Note that this does not include +% flexibility. This much amount of space gets available on the +% current page if we remove all insertions. This figures into +% \cmd{\FN@vsize} as a \emph{positive} quantity since the insertion +% size was taken from \cmd{\pagegoal}, and we reconstitute it in this +% manner. +% \begin{macrocode} + \global\FN@vsize\FN@outervsize + \global\advance\FN@vsize-\ht\@cclv\relax\relax +% \end{macrocode} +% Now we sort the inserts and regenerate the cache. +% \begin{macrocode} + \FN@nest@iterate\FN@sortinsert + \FN@nest@iterate\FN@clearcache + \xdef\FN@config{\@elt{\number0\botmarks\FN@slave}% + {\number\maxdimen}}% +% \if\foottrace8% +% \message{\noexpand\FN@normaloutput start config: \FN@config^^J}% +% \fi + \FN@nest@iterate\FN@reconfig +% \end{macrocode} +% Note that \cmd{\FN@reconfig} subtracts the \emph{actual} size of all +% insertions (after paragraphs have been combined and too early +% insertions moved to the next page) and also subtracts the flexible +% glues associated with the insertions' skip registers, so this +% flexibility is typically negative. Since the cache registers have +% been explicitly cleared, \cmd{\FN@reconfig} starts from the state +% where indeed no insertions are present. +% \begin{macrocode} + \ifcase + \ifnum\insertpenalties>\z@ \@ne\fi +% \end{macrocode} +% If we have floating insertions, we need to catch up with them. This +% is done in case~1 which just places an immediate penalty and +% recurses. +% +% Now here are a few cases that are only checked when we don't have a +% special penalty: +% \begin{macrocode} + \ifnum\outputpenalty>-\@M +% \end{macrocode} +% The first case is if the page is underfull. We need more material then. +% \begin{macrocode} + \ifdim\FN@vsize>-\gluestretch\FN@vsize \tw@ \fi +% \end{macrocode} +% Second case is when there is not enough vertical minimum material. +% \begin{macrocode} + \ifdim\FootnoteMainMinimum>\ht\@cclv \tw@ \fi + \fi +% \end{macrocode} +% Case 3 means page is overfull. If there are no missing insertions, +% try to split. +% \begin{macrocode} + \ifdim\FN@vsize<\glueshrink\FN@vsize \thr@@ \fi +% \end{macrocode} +% page has appropriate size or we have special penalty. If we have +% come here not the first time, we might have arrived at a non-optimal +% break. So we attempt a split. +% \begin{macrocode} + \ifx\FN@vsadjustlist\@empty \else \thr@@\fi\z@ +% \end{macrocode} +% Ok, now we get the default case in our big routine: case~0. We just +% pass the result onto the output routine. +% \begin{macrocode} + {\vbadness\@M + \vfuzz\maxdimen + \global\setbox\@cclv\vbox + spread\FN@vsize{\unvbox\@cclv\boxmaxdepth\maxdepth}}% + \the\FN@output + \let\@currbox\footins + \@pageht-\vsize + \@reinserts + \global\vsize-\@pageht + \FN@nest@iterate\FN@clearcache + \or +% \end{macrocode} +% Case 1: We just pull in remaining insertions and are done. Note +% that the special penalty here will get turned into an explicit +% nobreak. So if we have no record of an actual outputpenalty, we +% need to insert an artificial penalty of 0 here. +% \begin{macrocode} + \FN@restartoutput + \penalty -13749 + \penalty \FN@outputflag + \or +% \end{macrocode} +% Case 2: Now we want to gather additional material. This is somewhat +% weird. We first gather our material with a `normal' setting of +% topskip, and then we'll have another go at the material using proper +% marks. We can't actually insert anything right now in order not to +% introduce a premature breakpoint. +% \begin{macrocode} + \dimen@=\dimexpr\FN@vsize-\glueshrink\FN@vsize\relax + \FN@prepareoutput + \global\topskip \normalbaselineskip + \global\vsize \dimen@ + \global\advance\FN@outervsize-\vsize + \global\deadcycles\z@ + \else +% \end{macrocode} +% This is case 3: Fake our output box into something looking like a +% cache box and do the optimal split routine. The output cache box +% has a few deficiencies: its inner box is \emph{not} depth-extended +% to some default measurement. That means that where page size +% calculations are involved, one needs to \emph{disregard} its actual +% depth and instead use \cmd{\maxdepth}. This is somewhat awkward and +% prone to problems. One alternative might be to mark the box as +% split, extend its depth in the split part and let it be followed by +% nothing as lower part of the split. But we still would need to +% account for the missing depth at the end. +% \begin{macrocode} + \edef\FN@masterid{\number\maxdimen}% + \def\FN@masterslot{-1}% + \global\setbox\@cclv\vbox{\box\@cclv}% + \xdef\FN@config{\noexpand\@elt{\number0\botmarks\FN@slave}% + {\number\maxdimen}}% +% \ifvoid\FN@savebox \else \PackageError{bigfoot}{\FN@savebox +% \space should be void!}{}\fi + \global\setbox\FN@savebox\vbox{}% + \gdef\FN@penalties{0}% + \edef\FN@defaultpenalty{\ifnum\outputpenalty<\@M + \number\outputpenalty + \else + 0\fi}% + \let\@elt\FN@newlevel + \@elt{}\FN@savebox\FN@nestlist\FN@mainsplitreturn + \let\@elt\relax +% \if\foottrace8{\showboxdepth4\showboxbreadth100\showbox\@cclv}\fi + \global\setbox\FN@savebox\box\voidb@x + {% + \vbadness\@M + \vfuzz\maxdimen + \global\setbox\@cclv\vbox spread\FN@vsize{% + \unvbox\@cclv + \ifnum\lastpenalty>\z@ + \unpenalty + \global\setbox\FN@tempbox\lastbox + \else + \global\setbox\FN@tempbox\box\voidb@x + \fi + \setbox\z@\lastbox +% \end{macrocode} +% Now if a split has been done, |\box\FN@tempbox| contains the lower +% part of the split. In either case, |\box\z@| contains the upper +% part of the split (in a prepared form with the splitdiscards in a +% box of their own). This may be void if there is no main text but +% only footnotes. If we have carryover material, we add the current +% outputpenalty there and set outputpenalty to a value indicating that +% we have no outputpenalty to add at the end of the current list. +% \begin{macrocode} + \ifvoid\z@ + \ifvbox\FN@tempbox + \ifnum\outputpenalty<\@M +% The output penalty originally from below the split box gets appended +% to the end of the split box. + \global\setbox\FN@tempbox{\unvbox\FN@tempbox + \penalty\outputpenalty}% + \fi + \global\outputpenalty=\@M + \fi + \else +% \end{macrocode} +% Ok, we have material to go to the next page. We unpack it and fish +% out the break penalty from the last box. After checking it, put it in +% box~0. A prospective current break penalty gets appended to the +% carryover material. The fished-out break penalty becomes the new +% value of outputpenalty. +% \begin{macrocode} + \MFL@removevboxes + \unvbox\z@ + \edef\FN@defaultpenalty{\number\@M}% + \FN@getbreakpenalty + \setbox\z@\lastbox + \global\setbox\FN@tempbox\vbox\bgroup\unvbox\z@ + \unvbox\FN@tempbox + \ifnum\lastnodetype<\z@ + \egroup\global\setbox\FN@tempbox\box\voidb@x + \else + \ifnum\outputpenalty<\@M + \penalty\outputpenalty + \fi + \egroup + \global\outputpenalty\FN@breakpenalty + \fi + \fi + \boxmaxdepth\maxdepth}% + }% + \setbox\z@\box\FN@tempbox + \let\@elt\relax +% \end{macrocode} +% Ok, now we have in box~255 the split off stuff for the current +% output routine, and in box~0 stuff that is going to follow +% afterwards. If box~0 is not void, we were not able to make use of +% all of box~255. There is a slight probability that by taking even +% \emph{more} material from the main list, we might get a better +% result (by being able to move footnote material to the next page +% instead), but we don't make use of this possibility here. In +% general, we assume that if box~0 is nonvoid, we take the resulting +% split. Otherwise, if the page appears underfull, we pull in more +% material. If the page is not underfull, we can pass it to the +% output routine. If box~0 is void, the break was chosen at the +% ultimate end of the vertical list. If it was not a forced break, +% and if it is not an overfull case already, we pull in more material +% in order to avoid widows in the main text. +% \begin{macrocode} + \dimen@=\dimexpr\FN@vsize-\glueshrink\FN@vsize\relax + \ifcase + \ifvoid\z@ \ifnum\outputpenalty>-\@M + \ifdim\dimen@<\z@ \else \@ne \fi + \fi + \else \thr@@ + \fi + \ifdim\ht\@cclv<\normalbaselineskip \@ne\fi + \ifdim\dimen@<\normalbaselineskip \tw@\fi \@ne + \or + \FN@prepareoutput + \global\topskip \normalbaselineskip + \ifdim\dimen@<\normalbaselineskip \dimen@=2\baselineskip\fi + \global\vsize \dimen@ + \global\advance\FN@outervsize-\vsize + \global\deadcycles\z@ + \or +% \if\foottrace8% +% \message{^^JOutput: config is \FN@config...}\fi + \setbox\tw@\vbox{% + \the\FN@output +% \if\foottrace8% +% \ifnum\lastnodetype=\m@ne +% \message{^^JOutput: end without carryover^^J}% +% \else +% \message{^^JOutput: end with carryover}}% +% {\showboxdepth5 \showboxbreadth400 +% \tracingonline=\@ne\showbox\tw@ +% \fi +% \fi + }% + \unvbox\tw@ + \unvbox\z@ + \let\@currbox\footins + \@pageht-\vsize + \@reinserts + \global\vsize-\@pageht + \FN@nest@iterate\FN@clearcache + \or + \FN@restartoutput + \penalty -13751 + \penalty\FN@outputflag + \unvbox\z@ + \ifnum\outputpenalty>\@M + \else \penalty + \ifnum\outputpenalty=\@M \z@ \else\outputpenalty\fi + \fi + \fi + \fi +% \if\foottrace8\message{^^JExiting \string\FN@normaloutput^^J}\fi +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@prepareoutput} +% This is a preparation for gathering more material. First sweep up +% all the information about \cmd{\vsize}, \cmd{\topskip} and +% \cmd{\outputpenalty}. After that, record the insertion skip +% parameter of all insertions that have already been started, and +% reset them to zero so that no additional space gets reserved for +% them in case more material accumulates. We don't reset +% \cmd{\topskip} here since the amount of newly requested material +% will typically be in total lines, and \cmd{\topskip} might be the +% only way to figure out the proper request size. If the current +% depth and following height would make for a non-standard line +% distance, we might have a problem here. There is no obvious way +% to avoid it, though. +% \begin{macrocode} +\def\FN@prepareoutput{% + {\let\@elt\FN@recordinsertparam + \xdef\FN@vsadjustlist{% + \global\vsize=\the\vsize + \global\topskip=\the\topskip + \global\outputpenalty=\the\outputpenalty\relax + \FN@list}% + \let\@elt\FN@clearinsertparam + \FN@list}% +% \end{macrocode} +% Now we collect all boxes in the save box. +% \begin{macrocode} +% \ifvoid\FN@savebox \else \PackageError{bigfoot}{\FN@savebox +% \space should be void in \string\FN@prepareoutput}{}\fi + \global\setbox\FN@savebox\vbox{% + \box\@cclv + \FN@list@iterate\FN@sweepbox}} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@restartoutput} +% This is for the case where we are requesting additional material +% and have to cater for sizes. +% \begin{macrocode} +\def\FN@restartoutput{% +% \end{macrocode} +% Calculate the remaining size on this page: +% \begin{macrocode} + \dimen@=\dimexpr\FN@vsize-\glueshrink\FN@vsize\relax +% \end{macrocode} +% We just pull in remaining insertions and are done. +% \begin{macrocode} +% \if\foottrace8\message{sending special penalty}\fi + \hrule\@height\z@\@depth\z@ + \unvcopy\FN@topmarkbox + \penalty -13750 + \penalty\FN@outputflag + \hrule\@height\z@\@depth\z@ + \FN@insertmarks + \FN@prepareoutput + \global\topskip-\maxdimen\relax + \global\vsize 0.5\maxdimen + \global\advance\FN@outervsize-\vsize + \global\deadcycles\z@ +} +% \end{macrocode} +% \end{macro} +% +% Ok, here is the deal. If the \cmd\FN@truevsize is negative, we have +% an overfull vbox at our hand. We then start the splitting action. +% We take the first non-split lowest footnote block and split it to +% size, removing subordinate footnotes that we would not be able to +% maintain. We do this recursively starting by the top footnote +% block. It must be noted that it would be even better to start with +% the highest-numbered footnote (which corresponds to the latest +% finished footnote in \emph{logical} order, that in the source code), +% but then we get the problem that we might have to remove boxes from +% a footnote block that has already been split, and that is +% troublesome (to put it mildly) in case where the footnote block is +% set in paragraph mode. It's bad enough backtracking in a fixed +% order across footnote blocks, going back and forward would be pretty +% tough. +% +% So our recursion just walks the footnote blocks once top to bottom, +% splitting and removing boxes that are not needed. When we recurse, +% we have a dichotomy between current overfull and underfull boxes. +% At each recursion level, we enter with an overfull configuration +% that establishes the breakable section for the footnote block in +% question. +% +% Suppose that we have already established a previous best +% configuration. When we are recursing, we can only increase the +% badness (a non-broken insertion box contributes nothing to the +% overall badness or penalties, breaking the box causes a badness of +% 10000, minus the break penalty, plus the break badness). So there +% is no point in recursing if entry badness and break penalty are as +% large as the previous best break penalty or more. +% +% Ok, so we construct the footnote block and try splitting it +% to size. If this +% gives us a \emph{good} underfull version, we return that (and break +% out of recursion altogether). Otherwise we remember the underfull +% version before the break and recurse on the overfull version. If +% this returns an overfull version again, we return the underfull +% version before the break. If it returns an underfull version, we +% fill up the underfull version as much as possible without a change +% of configuration, then select the best of the last underfull and +% this as new local underfull. We then take the first overfull +% combination (even allowing a change of configuration), throw away +% the previous split in the next recursion level and recurse on the +% now thoroughly overfull combination again. +% +% When recursion tops out, we compare the current overfull with the +% previous one and record the best. We prefer keeping an older +% overfull, all other things being equal. +% +% Ok, so what are the data structures we maintain when going through +% all this folderol? +% +% We let the insertion boxes themselves remain untouched: that makes +% it only a bit more complicated to maintain and access the relevant +% boxes, but it might come handy at one time when somebody wants to +% implement recursion that is not strictly top-to-bottom. +% +% Instead we return the relevant information in the cache boxes. The +% total size of the cache boxes may not correspond to their actual +% contents: in case a split box intended for the next page is stored +% within them, its height is deducted from the total height of the +% cache box (and, consequentially, from \cmd{\FN@vsize}). +% +% \cmd{\FN@vsize}, the amount of free space on the current page, is +% only updated when changing levels of recursion. Instead we maintain +% score of the accumulated size in the current insertion in +% \cmd{\FN@myvsize}. +% +% What about the penalties and badness we collect? An unsplit +% footnote block carries a penalty of~0 (so we need not take into +% account unsplit footnote blocks at all during our bookkeeping, as +% they are neutral), a split footnote block is prepenalized with a +% penalty of~10000, plus the badness of the split, plus any penalties +% associated with the split (limited to the $[-10000\ldots10000]$ +% range). This means that no operation on other footnote blocks can +% lower an already accumulated score. This in turn means that we can +% prune any operations leading to a worse score than the preceding +% best score without having to actually recurse. +% +% This strategy will usually buy us a minimum number of split +% footnotes (since the penalty of~10000 is not easy to compensate) +% and corresponds rather closely to \TeX's own idea of footnote +% splitting. +% +% The following routine will analyze the last box where the results +% from \cmd{\splitdiscards} are stored and return the penalty +% associated with the breakpoint in the macro +% \cmd{\FN@breakpenalty}. +% \begin{macro}{\FN@getbreakpenalty} +% \begin{macrocode} +\def\FN@getbreakpenalty{{\setbox\z@\lastbox + \nointerlineskip\copy\z@ + \setbox\z@ + \vbox{\unvbox\z@ + \count@\@M + \FN@getbreakpenaltyii + \xdef\FN@tempinfo{\edef\noexpand\FN@breakpenalty{% + \number\ifnum\count@=\@M \FN@defaultpenalty \else \count@\fi + }}}}% + \FN@tempinfo} + +\def\FN@getbreakpenaltyii{% + \ifcase + \ifnum\lastnodetype<\z@ \m@ne\fi + \ifnum\lastnodetype<11 \@ne\fi + \ifnum\lastnodetype>13 \@ne\fi + \numexpr\lastnodetype-9\relax + \or + \PackageError{bigfoot}{Illegal node type}{This can't happen}% + \or + \count@\z@ \unskip \expandafter\FN@getbreakpenaltyii + \or + \count@\z@ \unkern \expandafter\FN@getbreakpenaltyii + \or + \count@\lastpenalty + \unpenalty \expandafter\FN@getbreakpenaltyii + \fi} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@cleanpagepenalty} +% This is used for removing initial infinite penalties from the +% pagediscards: those are artifacts of the page break routine. +% \begin{macrocode} +\def\FN@cleanpagepenalty{% + \ifcase + \ifnum\lastnodetype<\z@ \m@ne\fi + \ifnum\lastnodetype<11 \@ne\fi + \ifnum\lastnodetype>13 \@ne\fi + \numexpr\lastnodetype-9\relax + \or + \PackageError{bigfoot}{Illegal node type}{This can't happen}% + \or + \skip@=\lastskip \unskip + \expandafter \FN@cleanpagepenalty \expandafter\vskip\the + \expandafter\skip@ + \or + \dimen@=\lastkern \unkern + \expandafter \FN@cleanpagepenalty \expandafter\kern\the + \expandafter\dimen@ + \or + \count@\lastpenalty \unpenalty + \ifnum\count@=\FN@outputflag + \unpenalty\expandafter\expandafter\expandafter\FN@cleanpagepenalty + \else + \expandafter\FN@cleanpagepenalty\expandafter + \penalty\the\expandafter\expandafter\expandafter\count@ + \fi + \fi + \relax} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@mainsplitreturn} +% This is merely an argument delimiting control sequence to make it +% possible to figure out which recursion levels still need visiting. +% \begin{macrocode} +\def\FN@mainsplitreturn{} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@myvsize} +% This is the size currently taken by this insertion. +% \begin{macrocode} +\newdimen\FN@myvsize +% \end{macrocode} +% \end{macro} +% \begin{macro}{\bigfoottolerance} +% This specifies what footnote arrangement penalty will be accepted +% without looking for a better solution. +% \begin{macrocode} +\newcount\bigfoottolerance +\bigfoottolerance=100 +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@getbadness} +% This takes a skip value of remaining space and negative +% stretchability and shrinkability, and then calculates +% \cmd{\badness} depending on how good the stretching accommodates +% the remaining space. +% \begin{macrocode} +\def\FN@getbadness#1{% + {\hfuzz\maxdimen\hbadness\@M\setbox\z@\hbox to\z@{\hskip-#1}}} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@newlevel} +% This is the main workhorse of |bigfoot|. It splits a particular +% footnote level, recursing if necessary. The level list is +% delimited with \cmd{\FN@mainsplitreturn}. The whole thing is +% looped through while the splits are being optimized. While +% recursing, \cmd{\FN@penalties} contains the accumulated penalities +% of the current split configuration: a penalty of $10000$ for any +% split (except the main list), plus the penalty at the split points +% plus a `hangover' badness for the percentage of material carried +% over to the following pages. If nothing is carried over, this +% is~0, if more is carried over, we get a penalty according to the +% proportion of carryover material, raised to the third power. +% \begin{macro}{\footnotecarryratio} +% The fractional variable \cmd{\footnotecarryratio} is used for +% scaling the leftover material dimensions. After scaling with +% \cmd{\footnotecarryratio}, the carried material is treated like +% missing material in a glue calculation, while the stretchability +% for this calculation is given by the total size of material before +% breaking. So with a setting of~1, there should always be enough +% stretchability, causing at most a penalty of~100. That's not very +% effective, so we scale this up. +% +% The default value of~2 seems to provide a reasonable penalty for +% leftover material. The actual purpose for this component of the +% scoring is to penalize footnote blocks that seem to carry over +% disproportionally much material to later pages. +% \begin{macrocode} +\providecommand\footnotecarryratio{2} +% \end{macrocode} +% \end{macro} +% \cmd{\FN@ebadness} is an augmented value, but also counting in the +% stretch badness for one particular configuration. Ebadness does +% not make sense to evaluate more than temporarily: it is not passed +% through the levels. Since \cmd{\FN@penalties} is globally +% tampered with, its value at entry is saved in +% \cmd{\FN@entrypenalties}. Whenever we recurse or return, +% \cmd{\FN@vsize} contains the full information about the available +% space on the page, even though locally we use \cmd{\FN@myvsize}, a +% local value, to keep track of the locally reserved space. The +% only time when we need to save \cmd{\FN@myvsize} should be when we +% temporarily leave boxes in order to save the current +% configuration. +% \begin{macrocode} +\def\FN@newlevel#1#2#3\FN@mainsplitreturn{% + \count@\FN@cache#2% + \ifvoid\count@ +% \if\foottrace1\message{Page=\thepage #2 is empty, recursing with +% \the\FN@vsize^^J}% +% \message{Config=\unexpanded\expandafter{\FN@config}^^J}\fi + #3\FN@mainsplitreturn +% \if\foottrace1% +% \message{Page=\thepage #2 was empty, +% returning with \the\FN@vsize^^J}% +% \message{Config=\unexpanded\expandafter{\FN@config}^^J}\fi + \else +% \if\foottrace1\message{Entering #2 with \FN@penalties, +% \FN@vsize=\the\FN@vsize,^^J% +% Config=\unexpanded\expandafter{\FN@config}^^J}\fi + {\def\FN@currentinsertion{#2}% + \def\FN@currentrecursion{#3}% + \let\FN@entryconfig\FN@config + \let\FN@entrypenalties\FN@penalties + \splittopskip\csname FN@ht\number#2\endcsname\relax + \splitmaxdepth\csname FN@dp\number#2\endcsname\relax + \hsize\csname FN@wd\number#2\endcsname\relax + \vbadness=\@M + \vfuzz\maxdimen + \let\@elt\relax + \expandafter\FN@newleveli\expandafter}% +% \if\foottrace1\message{Exiting #2 with \FN@penalties, +% \FN@vsize=\the\FN@vsize,^^J% +% Config=\unexpanded\expandafter{\FN@config}^^J}\fi + \fi} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@newleveli} +% \begin{macrocode} +\def\FN@newleveli{% +% \end{macrocode} +% \cmd{\FN@vsize} already includes the size of the complete unsplit +% insertion. When we recurse, it has to reflect the correct size at +% the time of recursion. Rounding error problems don't permit us to +% accumulate any sizes in \cmd{\FN@vsize} from processing our current +% insertion, so we just subtract the whole insertion-related +% content. We'll add stuff into it when recursing. +% \begin{macrocode} + \dimen@\dimexpr\ht\count@ + \ifnum\FN@currentinsertion=\FN@savebox + +\maxdepth + \else + +\dp\count@ + \fi\relax + \global\advance\FN@vsize\dimexpr \dimen@ + *\count\FN@currentinsertion/\@m\relax\relax +% \end{macrocode} +% Ok, now we are typesetting and collecting the best box. Notice +% that we \emph{don't} exit this \cmd{\setbox} command until we have +% found the best possible split. What we \cmd{\unvbox} here, stays +% dormant except for the last box. When we collect configurations +% from cache boxes, we don't collect anything from our current box +% that is being assembled. So the whole action is confined within the +% current list that will replace the cache box after splitting. The +% meaning of boxes on the various levels are:\par\noindent +% \begin{tabularx}{\linewidth}{ll@{:\hskip\tabcolsep}X} +% 0&box0&where stuff gets collected as tentative material to be +% unboxed with \cmd{\FN@removevboxes} once the insertion gets readied +% for shipout\\ +% 0&box2&the previous best split that was found\\\hline +% 1&box0&the material that gets worked off, the tail of the split\\ +% 1&box2&where the current split is assigned +% \end{tabularx} +% The structure of 0/box2 is the head of the split, followed by +% |\break| penalty, followed by the tail of the split, followed by +% |\penalty\FN@tempbox|, followed by pairs of cache boxes and +% penalties indicating their box number. That way, the tail can get +% restored immediately into |\FN@tempbox| when using +% |\FN@restoreboxes|. +% \begin{macrocode} + \global\setbox\count@\vbox\bgroup\unvbox\count@ +% \end{macrocode} +% We calculate \cmd{\FN@myvsize} as the total space taken up by this +% insertion. The size of the last box is excluded since it will be +% split now. +% \begin{macrocode} + \ifnum\lastpenalty=\z@ + \setbox\tw@\box\voidb@x + \setbox\z@\lastbox + \FN@myvsize=\ifnum\lastnodetype<\z@ + \z@ + \else + \dimexpr\dimen@-\ht\z@-\dp\z@\relax + \fi + \else +% \end{macrocode} +% Now if the box has been split previously, we glue it back together +% again. Since the lower part of the split has been \emph{subtracted} +% from the total in \cmd{\dimen@}, we need to put it back into the +% equation here. \cmd{\dimen@} contains the size of the box after +% padding split material has been added. +% \begin{macrocode} +% \if\foottrace1\message{Regluing box 2}\fi + \unpenalty + \setbox\tw@\lastbox + \setbox\z@\lastbox + \FN@myvsize=\dimexpr\dimen@-\ht\z@-\dp\z@\relax + \dimen@\dp\z@ + \setbox\z@{\unvbox\z@ + \setbox\z@\lastbox + \unvbox\z@ + \unvbox\tw@}% + \ht\z@=\dimexpr\ht\z@+\dp\z@-\dimen@\relax + \dp\z@\dimen@ + \fi +% \end{macrocode} +% Ok, size is all accounted for. Go on with optimization. Note that +% these definitions here are made in \emph{inner} level, so they can't +% make it outside as the result of the optimization. If we drop out +% of here without superceding them, something's completely rotten. +% ^^A Fixme: Alpha pruning could be implemented by calling with +% ^^A \FN@bestcost already set at entry to the best badness at +% ^^A the respective level. +% \begin{macrocode} + \edef\FN@bestcost{\number\maxdimen}% + \let\FN@bestbadness\FN@bestcost + \let\FN@bestconfig\@undefined + \def\FN@bestvsize{-\maxdimen}% + \let\FN@splitcolors\@empty +% \end{macrocode} +% Ok, first attempt. One interesting feature is that we will never +% have to rewind the boxes from a split: we can always just glue the +% box together again. And apart from tentative splits which we might +% revert if they cause a configuration change, we will not have to +% bother about contributing too much. What we put in the box here +% can stay. +% +% First we split to the remaining size. Since we still have all +% subordinate footnotes considered fully, we need at least this split +% size (in case of a configuration change, we will need more). After +% having done the initial split, we continue splitting until we get +% the necessary mark of the last footnote into our grasp: we can't +% split before that. +% \begin{macrocode} + \ifnum\FN@currentinsertion=\FN@savebox + \else + \edef\FN@defaultpenalty{\number-\@M}% + \edef\FN@masterslot{\number\dp\z@}% + \edef\FN@masterid{\FN@slotget\FN@masterslot}% + \fi +% \end{macrocode} +% Now we are building one tentative candidate for returning in +% |\box\z@|. It will get discarded in case that a better candidate +% was already found before this box completes. +% \begin{macrocode} + \setbox\z@ + \vbox\bgroup +% \end{macrocode} +% Ok, now stuff gets complicated: for the first, tentatively `optimal' +% split, we want to have all available page stretchability properly +% taken into account. So we take the box, and add the available page +% stretchability at the top. Note that the stretchability is +% registered negatively. If we are on the main vertical list, an +% empty page can be an acceptable option, so we add a penalty of zero +% to account for that. Note that any prospective true penalties will +% already have disappeared into the page break. +% \begin{macrocode} + \let\FN@splitcolors\@empty + \setbox\z@\vbox{\vskip-\glueexpr(\FN@vsize-\dimexpr\FN@vsize + \relax\@minus\glueshrink\FN@vsize)% + *\@m/\count\FN@currentinsertion + \penalty\z@ + \unvbox\z@ + \ifnum\FN@defaultpenalty>-\@M + \penalty\FN@defaultpenalty\relax\nointerlineskip + \vbox to\maxdimen{}% + \fi}% +% \end{macrocode} +% Ok, now we have pushed the additional available stretch onto the top +% of box~0. Now we do the actual split to minimal size. That means +% that we don't consider any of the shrinkability available on the +% page: it might still be better employed in some recursive level. +% \begin{macrocode} + \setbox\tw@\vsplit\z@ to% + \dimexpr\FN@vsize*\@m/\count\FN@currentinsertion + -\FN@myvsize-\splitmaxdepth + \relax + \ifnum\FN@defaultpenalty>-\@M + \setbox\z@\vbox\bgroup\unvbox\z@\setbox\z@\lastbox + \unskip + \unpenalty + \ifnum\lastnodetype<\z@ + \egroup \setbox\z@\box\voidb@x + \else + \egroup + \fi + \fi +% \end{macrocode} +% Ok, now the top of box~2 contains unwanted additional +% stretchability. The easiest way to get rid of it is by adding its +% negation. +% \begin{macrocode} + \setbox\tw@\vbox{% + \vskip\glueexpr(\FN@vsize-\dimexpr\FN@vsize + \relax\@minus\glueshrink\FN@vsize)% + *\@m/\count\FN@currentinsertion + \unvbox\tw@\boxmaxdepth\splitmaxdepth}% +% \end{macrocode} +% Ok, now rinse and repeat if we haven't reached the last footnote +% in the block. +% \begin{macrocode} + \ifnum\FN@currentinsertion=\FN@savebox + \edef\FN@slaveid{\splitbotmarks\FN@slave}% + \FN@contribute@tw@ + \else + \ifnum0\splitbotmarks\FN@master=\FN@masterslot \else + \loop + \FN@contribute@tw@ + \setbox\tw@\vsplit\z@ to\z@ + \ifnum0\splitbotmarks\FN@master=\FN@masterslot + \else + \repeat + \fi + \let\FN@splitcolors\@empty + \edef\FN@slaveid{\splitbotmarks\FN@slave}% + \FN@contribute@tw@ + \fi +% \end{macrocode} +% All of the above was necessary to ensure that we actually have the +% beginning of the relevant footnote in our material. From now on, +% we are dealing with legal splits. +% Ok, now we have to check whether the subordinate configuration has +% changed. +% \begin{macrocode} + \ifx\FN@slaveid\@empty +% \ifnum\FN@currentinsertion=\FN@savebox\else +% \errmessage{Missing slaveid in \FN@currentinsertion}\fi + \edef\FN@slaveid{\number0\topmarks\FN@slave}% + \fi + \ifnum\numexpr\FN@slaveid+\@ne<\FN@masterid + \let\FN@next\FN@slaveid + \else + \let\FN@next\@empty + \fi +% \end{macrocode} +% At this point of time, we have \cmd{\FN@masterid} set properly for +% our purposes. It is to be used for returning any \emph{tail} part +% of a box. \cmd{\FN@slaveid} is by necessity not empty. If any +% footnote +% has had its mark broken off, its id must be in the open range +% between \cmd{\FN@slaveid} and \cmd{\FN@masterid}. So a nonempty +% value of \cmd{\FN@next} at this point of time indicates that we have +% to cater for a different configuration rather than the currently +% cached one. +% \begin{macrocode} + \FN@splitfurther} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@vsizerecurse} +% This fixes the vertical size up and recurses once. +% \begin{macrocode} +\def\FN@vsizerecurse{% + \global\advance\FN@vsize + -\dimexpr\FN@myvsize*\count\FN@currentinsertion/\@m \relax\relax + \let\@elt\FN@newlevel + \FN@currentrecursion\FN@mainsplitreturn + \let\@elt\relax + \global\advance\FN@vsize + \dimexpr\FN@myvsize*\count\FN@currentinsertion/\@m \relax\relax} +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Main label for reconsideration} +% When we are here, then there is not yet a split in the next footnote +% blocks scheduled. We might have to restitch stuff together here, +% though. +% \begin{macro}{\FN@splitfurther} +% \begin{macrocode} +\def\FN@splitfurther{% + \ifx\FN@next\@empty \else \let \FN@slaveid\FN@next \fi +% \end{macrocode} +% Ok, if our configuration now differs from the last one for which we +% have cache boxes set up, we have to reconfigure. It it doesn't, we +% just stitch the boxes together again in order to have correct size +% info. +% \begin{macrocode} + \let\FN@next\FN@config + \xdef\FN@config{% + \@elt{\FN@slaveid}% + {\FN@masterid}% + \FN@entryconfig}% + \ifx\FN@next\FN@config + \let\@elt\FN@rejoin + \else + \let\@elt\FN@reconfig + \fi + \FN@currentrecursion + \let\@elt\relax +% \end{macrocode} +% Ok, now we check whether the current configuration is a match for +% the best previous one. Also we calculate the badness of the current +% situation. +% \begin{macrocode} + \xdef\FN@penalties{\number\FN@entrypenalties}% + \FN@checkcurrent +% \end{macrocode} +% No point in recursing if we can't beat the current best one. +% However, if we find a forced break, this is considered perfect as +% long as we are not overfull. Note that recursion can only increase +% the badness if we are still underfull here, so there is no point in +% using \cmd{\FN@penalties} as the deciding factor of whether there may +% be a point in recursing: the current ebadness (which is never less +% than the badness) already is minimal. +% \begin{macrocode} + \ifnum + \ifdim\skip@>\z@ \FN@ebadness \else \FN@penalties \fi + >\FN@bestcost\relax +% \if\foottrace1% +% \message{no recursion: \skip@=\the\skip@, +% \noexpand\FN@bestvsize=\FN@bestvsize, +% \noexpand\FN@ebadness=\FN@ebadness, +% \noexpand\FN@penalties=\FN@penalties, +% \noexpand\FN@bestcost=\FN@bestcost.}\fi + \else +% \if\foottrace1% +% \message{before recursion: \skip@=\the\skip@, +% \noexpand\FN@bestvsize=\FN@bestvsize, +% \noexpand\FN@ebadness=\FN@ebadness, +% \noexpand\FN@penalties=\FN@penalties, +% \noexpand\FN@bestcost=\FN@bestcost.^^J +% recurse with \noexpand\FN@penalties=\number\FN@entrypenalties.}\fi + \xdef\FN@penalties{\number\FN@entrypenalties}% + \FN@vsizerecurse + \FN@checkcurrent +% \if\foottrace1% +% \message{after recursion: \skip@=\the\skip@, +% \noexpand\FN@bestvsize=\FN@bestvsize, +% \noexpand\FN@ebadness=\FN@ebadness, +% \noexpand\FN@penalties=\FN@penalties, +% \noexpand\FN@bestcost=\FN@bestcost.}\fi + \fi +% \end{macrocode} +% Don't look further if we had a forced break or are overfull or are +% at the end of the list. +% \begin{macrocode} + \ifcase + \ifnum\FN@breakpenalty>-\@M \else \@ne \fi + \ifvoid\z@ \@ne \fi + \ifnum\badness<\@MM \else \@ne \fi + \tw@ + \or + \expandafter \FN@returnbest + \else + \FN@mayberecordbest + \setbox\tw@\vsplit\z@ to\z@ + \edef\FN@next{\splitbotmarks\FN@slave}% + \FN@contribute@tw@ + \expandafter \FN@splitfurther + \fi} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@checkcurrent} +% Check out the badness of the current configuration. The last box +% on the list is the material constituting the discardable material +% after a split. +% \begin{macrocode} +\def\FN@checkcurrent{% + \FN@getbreakpenalty + \ifnum\FN@breakpenalty<-\@M + \edef\FN@breakpenalty{\number-\@M}% + \fi + \ifnum\FN@currentinsertion=\FN@savebox + \else + \ifdim\FN@specific\FN@currentinsertion\footnotecarryratio\p@>\z@ + \skip@ + \ifdim\FN@specific\FN@currentinsertion\footnotecarryratio\p@>\p@ + \dimexpr\ht\z@+\dp\z@\relax + \@plus-\dimexpr((\FN@myvsize+\ht\z@+\dp\z@) + *\p@/\dimexpr + \FN@specific\FN@currentinsertion + \footnotecarryratio\p@)\relax + \else + \FN@specific\FN@currentinsertion + \footnotecarryratio + \dimexpr\ht\z@+\dp\z@\relax + \@plus-\dimexpr\FN@myvsize+\ht\z@+\dp\z@\relax + \fi + \relax + \FN@getbadness\skip@ + \xdef\FN@penalties{\number\numexpr\FN@penalties+\badness}% + \fi + \fi + \skip@\glueexpr\FN@vsize-\FN@myvsize + *\count\FN@currentinsertion/\@m\relax + \FN@getbadness\skip@ + \xdef\FN@penalties{\number\numexpr\FN@penalties+% + \FN@breakpenalty+\@M}% + \ifnum\badness>\@M + \edef\FN@ebadness{\number\numexpr\maxdimen-\@ne}% + \else + \ifnum\badness=\@M + \ifdim\skip@<\vsize + \edef\FN@ebadness{\number\numexpr\maxdimen-\tw@}% + \else + \edef\FN@ebadness{\number\numexpr\maxdimen}% + \fi + \else + \edef\FN@ebadness{\number\numexpr + \FN@penalties+\badness + \ifdim\FN@specific\FN@currentinsertion\FootnoteMinimum>\FN@myvsize + 1000000 + \fi + }% + \fi + \fi + \dimen@\glueexpr\FN@bestvsize\relax +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@checkforbest} +% This generates 2 if the old stored best is better, 1~if the +% current variation is better. +% \begin{macrocode} +\def\FN@checkforbest{% + \ifnum\FN@breakpenalty>-\@M \else + \ifnum\badness>\@M \else + \@ne + \fi + \fi +% \end{macrocode} +% Ok, so the split was not as good as to cause us to return +% immediately, and it also was not the last opportunity for a split +% (which again would make us return immediately). +% So we check if it is at least better than the last one, in which +% case we need to replace the previous best. +% \begin{macrocode} + \ifnum\FN@bestcost>\FN@ebadness \@ne\fi + \ifnum\FN@bestcost<\FN@ebadness \tw@\fi + \ifdim\skip@<\z@ + \ifdim\dimen@<\skip@ \@ne \fi \tw@ + \fi + \ifdim\dimen@>\skip@ \@ne\fi \tw@} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@mayberecordbest} +% This checks whether the current configuration is better than a +% previously saved one. If it is, the previous configuration gets +% replaced. The cache boxes itself are copied, not voided in the +% process for efficiency reasons. +% \begin{macrocode} +\def\FN@mayberecordbest{% +% \end{macrocode} +% If the current break is forced and the page is not overfull, we take +% the break. +% \begin{macrocode} + \ifcase + \FN@checkforbest + \or + \xdef\FN@tempinfo{\def\noexpand\FN@bestvsize{\the\skip@}% + \def\noexpand\FN@bestcost{\FN@ebadness}% + \def\noexpand\FN@bestbadness{\number\FN@penalties}% + \def\noexpand\FN@bestconfig{\FN@config}% + \def\noexpand\FN@bestslaveid{\FN@slaveid}% + \def\noexpand\FN@bestsplitcolors{\FN@splitcolors}% + \def\noexpand\FN@breakpenalty{\FN@breakpenalty}% + \FN@myvsize=\the\FN@myvsize\relax}% + \global\setbox\FN@tempbox\box\z@ + \egroup + \FN@tempinfo + \let\FN@splitcolors\FN@bestsplitcolors + \let\FN@slaveid\FN@bestslaveid +% \end{macrocode} +% Now all relevant info has been retrieved, and we collect the best +% box info in |\box\tw@|. The structure of the information is as +% follows: it starts with the current box in split form, first the +% tail, then the start of the current split box. +% This is then followed by a zero kern, and then by pairs of boxes and +% penalties indicating the swept box. +% \begin{macrocode} + \setbox\tw@\vbox{% +% \end{macrocode} +% We don't need to place master/slave marks here: the necessary +% information is available outside in the \cmd{\FN@masterslot} and +% \cmd{\FN@slaveid} info and gets attached afterwards. +% \begin{macrocode} + \copy\z@\break\nointerlineskip + \copy\FN@tempbox\penalty\FN@tempbox + \let\@elt\FN@copycachebox + \FN@currentrecursion}% + \setbox\z@ + \vbox\bgroup + \unvbox\z@ + \setbox\z@\box\FN@tempbox + \fi} +% \end{macrocode} +% \end{macro} + +% \begin{macro}{\FN@returnbest} +% \begin{macrocode} +\def\FN@returnbest{% + \ifcase\FN@checkforbest + \or + \xdef\FN@tempinfo{\def\noexpand\FN@bestvsize{\the\skip@}% + \def\noexpand\FN@bestcost{\FN@ebadness}% + \def\noexpand\FN@bestbadness{\number\FN@penalties}% + \def\noexpand\FN@bestconfig{\FN@config}% + \def\noexpand\FN@bestslaveid{\FN@slaveid}% + \def\noexpand\FN@bestsplitcolors{\FN@splitcolors}% + \def\noexpand\FN@breakpenalty{\FN@breakpenalty}% + \FN@myvsize=\the\FN@myvsize\relax}% + \global\setbox\FN@tempbox\box\z@ + \egroup + \FN@tempinfo + \let\FN@splitcolors\FN@bestsplitcolors + \let\FN@slaveid\FN@bestslaveid + \global\FN@vsize\FN@bestvsize\relax +% \end{macrocode} +% Now all relevant info has been retrieved, and we collect the best +% box info in |\box\tw@|. The structure of the information is as +% follows: it starts with the current box in split form, first the +% tail, then the start of the current split box. +% This is then followed by a zero kern, and then by pairs of boxes and +% penalties indicating the swept box. +% \begin{macrocode} + \or + \global\let\FN@config\FN@bestconfig + \global\FN@vsize\FN@bestvsize + \global\let\FN@penalties\FN@bestbadness + \egroup +% \end{macrocode} +% Restore the saved configuration. +% \begin{macrocode} + \setbox\z@\vbox{\unvbox\tw@ \FN@restoreboxes}% + \let\FN@splitcolors\FN@bestsplitcolors + \let\FN@slaveid\FN@bestslaveid + \unvbox\z@ + \setbox\z@\lastbox + \fi +% \end{macrocode} +% \begin{macrocode} + \ifnum\FN@currentinsertion=\FN@savebox + \else + \setbox\z@\vbox{% + \prevdepth\dp\z@ + \unvbox\z@ + \ifvoid\FN@tempbox + \else + \global\setbox\FN@tempbox\vbox{% + \marks\FN@master{\FN@masterslot}% + \marks\FN@slave{\FN@slaveid}% + \FN@coloraftersplit\FN@splitcolors + \FN@specific\FN@currentinsertion\FN@afterbreak + \nobreak + \unvbox\FN@tempbox}% + \FN@specific\FN@currentinsertion\FN@beforebreak + \ht\FN@tempbox + \dimexpr\ht\FN@tempbox+\dp\FN@tempbox-\FN@masterslot sp\relax + \dp\FN@tempbox\FN@masterslot sp\relax + \wd\FN@tempbox\maxdimen + \fi + \ifdim\prevdepth<\splitmaxdepth + \hrule\@height-\prevdepth \@width\z@ + \@depth \splitmaxdepth \relax \fi}% + \ht\z@=\dimexpr\ht\z@+\dp\z@-\FN@masterslot sp\relax + \dp\z@=\FN@masterslot sp + \fi + \nointerlineskip \box\z@ +% \end{macrocode} +% If nothing is to be carried over, we just finish our assignment to +% the cache box and return. +% \begin{macrocode} + \ifvoid\FN@tempbox \egroup +% \end{macrocode} +% If not, we add the carried-over box to the list, flag it with a +% \cmd{\nobreak}, and subtract its size from the finished box. Please +% note that the \cmd{\expandafter} chain will expand just +% |\cmd\dimen@|, but everything following it will be evaluated only +% after \cmd{\egroup}, thus using the new height of the box. +% \begin{macrocode} + \else + \dimen@-\dimexpr\ht\FN@tempbox+\dp\FN@tempbox\relax + \nointerlineskip\box\FN@tempbox + \nobreak + \expandafter\egroup + \expandafter\ht\expandafter\count@\expandafter\dimexpr + \the\dimen@+\ht\count@\relax + \fi +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\FN@contribute@tw@} +% This will go from the state where we have the previous +% \cmd{\splitdiscards} struttified on the current list some material +% split off from box~0 in box~2 to a state where box~2 is +% contributed to the current list. +% \begin{macrocode} +\def\FN@contribute@tw@{% +% \end{macrocode} +% First we change the current colors if we have any in our group. Not +% sure if this is entirely correct. +% \begin{macrocode} + \begingroup\edef\FN@next{\splitbotmarks\FN@color}% + \ifx\FN@next\@empty \endgroup\else \endgroup + \edef\FN@splitcolors{\splitbotmarks\FN@color}\fi +% \end{macrocode} +% If the last box is void, there is no previous split to reconstitute. +% \begin{macrocode} + \setbox4\lastbox + \ifvoid4 \setbox4\vbox{\splitdiscards}% + \setbox\tw@\vbox{\unvbox\tw@\boxmaxdepth\splitmaxdepth}% + \else +% \end{macrocode} +% Now the last box is a strut. We remove its outer dimensions from +% the total account, and then add back its natural dimensions after +% which we pour it back into the current list. +% \begin{macrocode} + \advance\FN@myvsize-\dimexpr\ht4+\dp4\relax + \setbox4\vbox{\unvbox4}% + \advance\FN@myvsize\dimexpr\ht4+\dp4\relax + \unvbox4 +% \end{macrocode} +% We want to contribute box~2 back without any topskip glue, so we +% manually remove any such glue by splitting an empty box off. +% \begin{macrocode} + \setbox4\vbox{\splitdiscards}% + \setbox\tw@\vbox{\break\unvbox\tw@}% + {\splittopskip-\maxdimen \setbox\tw@\vsplit\tw@ to\z@}% +% \end{macrocode} +% Notice the effect of \TeX's special box scope rules: box~2 assigned +% just right now will be affected by the split. The result of the +% split will be an empty box that will temporarily overwrite box~2 +% within the group, but will be restored back to the split result on +% exit. In this manner, any topskip glue will have disappeared. +% After the split, box~2 is set to the natural depth and height of +% its contents. +% +% We now add a sort of strut by putting all the discarded material +% inside of a box that creates the proper size. +% If this split is taken, the box is adjusted to have a full depth of +% \cmd{\splitmaxdepth}, and we take this into account. +% \begin{macrocode} + \fi + \ht4-\dp\tw@ + \dp4\ifdim\dp\tw@<\splitmaxdepth \splitmaxdepth \else \dp\tw@ \fi + \advance\FN@myvsize\dimexpr \ht\tw@+\dp4\relax + \unvbox\tw@ + \nointerlineskip + \box4 } +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@uncontribute@tw@} +% This is just the opposite: after a split, we revert its effects again. +% \begin{macrocode} +\def\FN@uncontribute@tw@{% + \ifvoid\tw@ \else + \setbox\tw@\vbox{\unvbox\tw@\splitdiscards}% + \setbox\z@\vbox{\break\unvbox\z@}% + {\splittopskip-\maxdimen \setbox\z@\vsplit\z@ to\z@}% + \setbox\z@\vbox{\unvbox\tw@\unvbox\z@}\fi} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@reconfig} +% This reconfigures the insertion cache to contain only the boxes +% that belong to this page. If the insertion box is empty, we can +% skip all the folderol. If it isn't, we empty the cache box (the +% number of which we place in \cmd{\count@}) and add its size back +% to \cmd{\FN@vsize}. +% \begin{macrocode} +\def\FN@reconfig#1#2{\ifvoid#2% +% \ifvoid\FN@cache#2\else +% \errmessage{\FN@cache#2 should be void}\fi + \else + \count@\FN@cache#2% + \ifvoid\count@\else + \global\advance\FN@vsize + \glueexpr(\ht\count@+\dp\count@)*\count#2/\@m+\skip#2\relax + \global\setbox\count@ \box\voidb@x + \fi +% \end{macrocode} +% Ok, now we have emptied the cache and readjusted the size. We now +% fill the cache by first copying the insertion into it. +% \begin{macrocode} + \global\setbox\count@\vbox\bgroup\vbox\bgroup\unvcopy#2% + \let\@elt\FN@removecheck + \FN@retainkept +% \end{macrocode} +% Now if nothing was retained, we void the cachebox. +% \begin{macrocode} + \ifvoid\z@ \egroup\egroup \global\setbox\count@ \box\voidb@x +% \end{macrocode} +% Otherwise, we combine all the boxes that remain on the page. +% \begin{macrocode} + \else \def\FN@masterinsert{#2}% + \FN@assembleboxes\global\setbox\count@\box\z@\egroup + \nointerlineskip\box\count@\egroup +% \end{macrocode} +% Note that now all footnote boxes are collected into a single vbox, +% followed by the last footnote box as another vbox. +% Now we just need to reduce the available size on the page by the +% height of the assembled material: +% \begin{macrocode} + \global\advance\FN@vsize + -\glueexpr(\ht\count@+\dp\count@)*\count#2/\@m+\skip#2\relax + \fi\fi} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\FN@rejoin} +% This glues together cache boxes that have been split, without +% regenerating them. This saves a lot of time as compared to +% \cmd{\FN@reconfig}. +% \begin{macrocode} +\def\FN@rejoin#1#2{{% +% \if\foottrace1\message{^^JRejoining #2}\fi + \count@\FN@cache#2% + \ifvoid\count@\else + \global\advance\FN@vsize\dimexpr + (\ht\count@+\dp\count@)*\count#2/\@m\relax + \global\setbox\count@\vbox{% + \unvbox\count@ + \ifnum\lastpenalty>\z@ + \unpenalty + \setbox\tw@\lastbox + \setbox\z@\lastbox + \dimen@\dp\z@ + \setbox\z@\vbox{% + \unvbox\z@ + \setbox\z@\lastbox + \unvbox\z@ + \unvbox\tw@}% + \ht\z@=\dimexpr\ht\z@+\dp\z@-\dimen@\relax + \dp\z@=\dimen@ + \nointerlineskip + \box\z@ + \fi}% + \global\advance\FN@vsize-\dimexpr + (\ht\count@+\dp\count@)*\count#2/\@m\relax + \fi}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\FN@retainkept} +% This relies on \cmd{\@elt} being set to \cmd{\FN@removecheck} which +% expands to \cmd{\@ne} if |\box0| is strictly between the two values +% from an entry of \cmd{\FN@config}, which means that it is material +% that should get moved to the next page. In that case, we recurse +% while dropping the box in question. Otherwise we keep it. +% Recursion bottoms out when there are no boxes left. The function +% leaves the last retained box in box~0; if there are no boxes to be +% retained, this will be void. +% \begin{macrocode} +\def\FN@retainkept{% + \setbox\z@\lastbox + \ifcase + \ifvoid\z@\m@ne\fi \FN@config\z@ +% \if\foottrace8\message{^^J\string\FN@retainkept: +% retaining Id \FN@slotget{\number\dp\z@}}\fi +% \if\foottrace{16}{\showboxdepth4 \showboxbreadth400 +% \tracingonline=\@ne\showbox\z@}\fi + {\FN@retainkept \nointerlineskip \box\z@}% + \or +% \if\foottrace8\message{^^J\string\FN@retainkept: +% dropping Id \FN@slotget{\number\dp\z@}}\fi +% \if\foottrace{16}{\showboxdepth4 \showboxbreadth400 +% \tracingonline=\@ne\showbox\z@}\fi + \FN@retainkept +% \else +% \ifnum\lastnodetype>\m@ne +% \errmessage{Unexpected node \number\lastnodetype}\fi + \fi} +% \end{macrocode} +% \end{macro} +% Well, as the last measure, we change the output routine to our new +% routine. +% \begin{macrocode} +\let\output\FN@output +% \end{macrocode} +% Ok, here is debugging code intercepting all calls of the regular +% output routine and reporting its entry and exit states. +% \begin{macrocode} +% \newtoks\FN@tr@output +% \FN@tr@output\output +% \output{\if\foottrace8{% +% \setbox\z@\vbox{% +% \message{Calling regular output with +% \outputpenalty=\the\outputpenalty, box255 as}% +% \showbox\@cclv +% \the\FN@tr@output +% \message{Returning from regular output with +% \ifnum\lastnodetype<\z@ +% empty vertical list.\else vlist:}}% +% \showbox\z@ +% \unvbox\z@{{\fi}}}\else\the\FN@tr@output\fi} +% \let\output\FN@tr@output +% \end{macrocode} +% If the footnote type ``default'' has not been declared by the time +% the document starts, we do so at the start of the document. +% Unfortunately, by this time the initialization code in |manyfoot|'s +% own \cmd{\AtBeginDocument} hook has already run, so we manually run +% the initialization hook just for the command we inserted ourselves. +% \begin{macrocode} +\def\FN@maybestart#1#2#3{\ifx#3\relax + \csname MFL@start#1\endcsname{#2}\fi#3} +\@onlypreamble\FN@maybestart +\AtBeginDocument{\@ifundefined{footinsdefault}% + {\newfootnote[plain]{default}% + {\let\@elt\FN@maybestart + \MFL@list\relax}% + }{}% +% \end{macrocode} +% And since LaTeX's macros are inferior to our own (and would probably +% not match too well), we reroot them to the default footnote style. +% \begin{macrocode} + \def\@footnotetext{\Footnotetextdefault{}}% + \def\p@footnotedefault{\p@footnote}% +} +% +% \end{macrocode} +% +% \section{Various driver files} +% The installer, in case it is missing. If it is to be used via +% |make|, we don't specify an installation path, since +% \begin{quote} +% |make install| +% \end{quote} +% is supposed to cater for the installation itself. +% \begin{macrocode} +% \input docstrip +% \askforoverwritefalse \nopreamble +% \generate{ +% \file{bigfoot.drv}{\from{bigfoot.dtx}{driver}} +% \file{perpage.drv}{\from{perpage.dtx}{driver}} +% \file{suffix.drv}{\from{suffix.dtx}{driver}} +% \usedir{tex/latex/bigfoot} +% \file{bigfoot.sty}{\from{bigfoot.dtx}{style}} +% \file{perpage.sty}{\from{perpage.dtx}{style}} +% \file{suffix.sty}{\from{suffix.dtx}{style}} +% } +% \endbatchfile +% \end{macrocode} +% \Finale +% \endinput +% Local Variables: +% mode: doctex +% TeX-master: "bigfoot.drv" +% End: diff --git a/macros/latex/contrib/bigfoot/bigfoot.ins b/macros/latex/contrib/bigfoot/bigfoot.ins new file mode 100644 index 0000000000..dceb20a061 --- /dev/null +++ b/macros/latex/contrib/bigfoot/bigfoot.ins @@ -0,0 +1,21 @@ +%% +%% bigfoot is part of the bigfoot bundle for critical typesetting +%% Copyright 2004--2015 David Kastrup +%% +%% The license notice and corresponding source code for this file are +%% contained in bigfoot.dtx. +%% + \input docstrip + \generate{ + \file{bigfoot.drv}{\from{bigfoot.dtx}{driver}} + \file{perpage.drv}{\from{perpage.dtx}{driver}} + \file{suffix.drv}{\from{suffix.dtx}{driver}} + \usedir{tex/latex/bigfoot} + \file{bigfoot.sty}{\from{bigfoot.dtx}{style}} + \file{perpage.sty}{\from{perpage.dtx}{style}} + \file{suffix.sty}{\from{suffix.dtx}{style}} + } + \endbatchfile +\endinput +%% +%% End of file `bigfoot.ins'. diff --git a/macros/latex/contrib/bigfoot/bigfoot.pdf b/macros/latex/contrib/bigfoot/bigfoot.pdf new file mode 100644 index 0000000000..3c5eac0f92 Binary files /dev/null and b/macros/latex/contrib/bigfoot/bigfoot.pdf differ diff --git a/macros/latex/contrib/bigfoot/perpage.dtx b/macros/latex/contrib/bigfoot/perpage.dtx new file mode 100644 index 0000000000..ad4be3ad78 --- /dev/null +++ b/macros/latex/contrib/bigfoot/perpage.dtx @@ -0,0 +1,547 @@ +% \iffalse +%% +%% perpage is part of the bigfoot bundle for critical typesetting +%% Copyright 2002--2014 David Kastrup +%% +%% The license notice and corresponding source code for this file are +%% contained in perpage.dtx. +%% +% 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{396} +% \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 \cmd{\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. +% \begin{macrocode} +%<*style> +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{perpage}[2014/10/25 2.0 Reset/sort counters per page] +% \end{macrocode} +% \begin{macro}{\pp@cl@begin} +% \begin{macro}{\pp@cl@end} +% These macros are considerable tricky. They are called as +% artificial `dependent' counters when the counter they are hooked +% into is advanced. The way in which those counters are called are +% one of the following: +% \begin{quote} +% \begin{verbatim} +% \def\@stpelt#1{\global\csname c@#1\endcsname \z@} +% \end{verbatim} +% \end{quote} +% which is the default way of resetting a subordinate counter used +% in \LaTeX, or +% \begin{quote} +% \begin{verbatim} +% \def\@stpelt#1{\global\csname c@#1\endcsname \m@ne\stepcounter{#1}} +% \end{verbatim} +% \end{quote} +% which is a little present from |fixltx2e.sty| as of 2014/05/01, +% quite complicating this feat. +% +% The startup code swallows either |\global \advance| or |\global|. +% \begin{macrocode} +\def\pp@cl@begin{\z@\z@ \begingroup} +% \end{macrocode} +% The command used for ending our fake counters checks for the +% |\m@ne| condition. We don't want to bump our auxiliary counters +% twice, so we remove the following |\stepcounter| command. Things +% will go haywire if there is none, of course. +% \begin{macrocode} +\def\pp@cl@end{\afterassignment\pp@cl@end@ii \count@} +\def\pp@cl@end@ii{% + \relax + \expandafter\endgroup + \ifnum\count@<\z@ + \expandafter\pp@cl@end@iii + \fi} +\def\pp@cl@end@iii\stepcounter#1{} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \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 +% whenever the unprefixed counter gets advanced. +% \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}{\pp@cl@begin + \stepcounter{abs#1}% + \pp@cl@end}% + \@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 + {}{}} + +\global\let\theperpage\@empty + +\def\pp@fetchctrii#1#2#3{\def\pp@label{#1}% + \def\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{\pp@cl@begin +% \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. We try to replicate any sentinel kerns or penalties. +% \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 + \count@=\lastpenalty + \protected@write\@auxout{}{\next}% + \ifdim\dimen@=\z@ + \penalty \ifnum\count@<\@M \@M \else \count@ \fi + \else \kern\dimen@\fi + \pp@cl@end} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\pp@labeldef} +% This is a helper macro. +% \begin{macrocode} +\def\pp@labeldef#1#2#3#4#5{\@newl@bel{pp@r@#2}{#3}{{#1}{#4}{#5}}} +% \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 + \expandafter\pp@labeldef\expandafter + {\number\value{pp@a@#1}}{#1}{#2}{#3}{#4}}} +% \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{\pp@cl@begin + \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@}% + \expandafter\pp@labeldef\expandafter + {\number\count@}{#1}{#2}{#3}{#4}}} +% \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{\pp@cl@begin + \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 + \expandafter\pp@labeldef\expandafter + {\number\value{pp@a@#1}}{#1}{#2}{#3}{#4}}} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\@testdef} +% \LaTeX's current (2007) definition of this macro causes save stack +% overflow. We fix this by an additional grouping. Delay to the +% beginning of document to keep Babel happy. +% \begin{macrocode} +\AtBeginDocument{% + \begingroup + \@testdef{}{undefined}{}% + \expandafter + \endgroup + \ifx\@undefined\relax + \let\pp@@testdef\@testdef + \def\@testdef#1#2#3{{\pp@@testdef{#1}{#2}{#3}% + \if@tempswa\aftergroup\@tempswatrue\fi}}% + \fi} +% +% \end{macrocode} +% \end{macro} +% +% \Finale +% \endinput +% Local Variables: +% mode: doctex +% TeX-master: "perpage.drv" +% End: diff --git a/macros/latex/contrib/bigfoot/perpage.pdf b/macros/latex/contrib/bigfoot/perpage.pdf new file mode 100644 index 0000000000..b5d53e0804 Binary files /dev/null and b/macros/latex/contrib/bigfoot/perpage.pdf differ diff --git a/macros/latex/contrib/bigfoot/suffix.dtx b/macros/latex/contrib/bigfoot/suffix.dtx new file mode 100644 index 0000000000..9a6478e73a --- /dev/null +++ b/macros/latex/contrib/bigfoot/suffix.dtx @@ -0,0 +1,236 @@ +% \iffalse +%% +%% suffix is part of the bigfoot bundle for critical typesetting +%% Copyright 2002--2006 David Kastrup +%% +%% The license notice and corresponding source code for this file are +%% contained in suffix.dtx. +%% +% 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{198} +% \GetFileInfo{suffix.sty} +% \author{David Kastrup\thanks{\href{mailto:dak@gnu.org} +% {Email: \texttt{dak@gnu.org}}}} +% \title{The \texttt{suffix} Package\\Version \fileversion} +% \date{\filedate} +% \maketitle +% \section{Basics} +% The \texttt{suffix} package has the purpose of making it easy to +% define and maintain command variants like |\macro*| and even +% |\macro\/| or similar. It requires e\TeX\ version~2 for its work. +% The suffixes are fetched with |\futurelet|, so things like |\bgroup| +% and |{| ^^A} +% can't be distinguished. In addition, the efficiency depends on the +% complexity of the suffix' definition, so you should preferably use +% characters or short commands as a suffix. A suffixed command itself +% counts as short for this purpose. How does a suffix definition look +% like? +% +% \DescribeMacro{\WithSuffix} The general form is +% \begin{quote} +% |\WithSuffix|\meta{prefixed definition}\meta{macro}\meta{suffix}\dots +% \end{quote} +% where \meta{prefixed definition} is something like |\xdef|, +% |\global\let| or similar. Recognised prefixes are |\global|, +% |\long|, |\protected| (the latter is rarely useful, as the original +% definition already is robust), and |\expandafter| (with its +% `natural' meaning), specially recognized commands are |\gdef| and +% |\xdef|. Other commands can be used as long as they are suitable as +% an undelimited macro argument. This means they must either be a +% single token like |\newcommand| or brace-enclosed like +% |{\newcommand*}|. \meta{macro} can be a macro or an active +% character. It should be a single token suitable for assignment with +% |\let|. \meta{suffix} can be something like a single letter such as +% |*| or |[|. +% +% For example, assume that a command |\snarf| already exists and we +% want to define a variant |\snarf|\oarg{optarg}. Then we can do this +% with +% \begin{quote} +% \cmd\WithSuffix|\long\def\snarf[#1]{|\meta{Definition using +% \texttt{\#1}}|}| +% \end{quote} +% That's pretty much it. Oh, only when a command is recognised as +% having a prefix |\global| or being |\xdef| or |gdef| will the +% corresponding redefinitions be done globally. This is rarely a +% concern. +% +% \DescribeMacro{\SuffixName} In case you need to refer to the control +% sequence name used to refer to the suffixed macro, you can access it +% as +% \begin{quote} +% |\csname|\cmd{\SuffixName}\meta{macro}\meta{suffix}|\endcsname| +% \end{quote} +% \DescribeMacro{\NoSuffixName} and if you need to refer to the +% original unsuffixed macro, you can access it as +% \begin{quote} +% |\csname|\cmd{\NoSuffixName}\meta{macro}|\endcsname| +% \end{quote} +% \StopEventually{} +% \section{The driver file for the documentation} +% Installation is done by |bigfoot.ins|, so look there for more +% information for that. Here comes the documentation driver. +% \begin{macrocode} +%<*driver> +\documentclass{ltxdoc} +\usepackage{hyperref} +\usepackage{suffix} +\begin{document} +\OnlyDescription +% \AlsoImplementation +\DocInput{suffix.dtx} +\end{document} +% +% \end{macrocode} +% \section{Implementation} +% First we announce the package and check for e\TeX~2. +% \begin{macrocode} +%<*style> +\ProvidesPackage{suffix}[2006/07/15 1.5a Variant command support] +\ifcase\ifx\eTeXversion\@undefined \@ne\fi + \ifnum\eTeXversion<\tw@ \@ne\fi\z@ +\else + \PackageError{suffix}{This package requires eTeX version 2}% + {You might try to use the `elatex' command.}% +\fi +% \end{macrocode} +% \begin{macro}{\WithSuffix} +% Then we define the \cmd{\WithSuffix} command. We use +% \cmd{\@temptokena} to collect prefixes and let \cmd{\WSF@global} +% to |\global| for global definitions. +% +% \begin{macrocode} +\def\WithSuffix{\@temptokena{}\let\WSF@global\relax + \WSF@sfx} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\WSF@sfx} +% \begin{macro}{\WSF@append} +% \begin{macro}{\WSF@gobblenext} +% After checking all prefixes and stuff (we'll fill in this missing +% link later), we add the defining command itself to the token list, +% place \meta{macro} into \cmd{\reserved@a} and fetch \meta{suffix} +% into \cmd{\reserved@b}. +% \begin{macrocode} +\long\def\WSF@sfx#1#2{\WSF@append{#1}\def\reserved@a{#2}% + \afterassignment\WSF@decsuff \WSF@gobblenext} + +\def\WSF@append#1{\@temptokena\expandafter{\the\@temptokena#1}} + +\def\WSF@gobblenext{\let\reserved@b= } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \begin{macro}{\SuffixName} +% \begin{macro}{\NoSuffixName} +% While we are at it, let us define the macro names to use for +% suffixed and unsuffixed \meta{macro}. +% \begin{macrocode} +\long\def\SuffixName#1{WSF:\string#1 \meaning} +\def\NoSuffixName{WSF:\string} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \begin{macro}{\WSF@decsuff} +% We first check whether the macro has already been suffixed. If it +% hasn't, we save a copy of it and redefine it in terms of +% \cmd{\WSF@suffixcheck}. +% \begin{macrocode} +\def\WSF@decsuff{\ifcsname + \expandafter\NoSuffixName\reserved@a\endcsname + \else + \WSF@global\expandafter\let\csname + \expandafter\NoSuffixName\reserved@a + \expandafter\endcsname \reserved@a + \long\def\reserved@c##1{\WSF@global\protected\def + ##1{\WSF@suffixcheck##1}}% + \expandafter\reserved@c\reserved@a + \fi +% \end{macrocode} +% Once we have done that, we are ready for calling the definition +% command on the suffixed \meta{macro}. +% \begin{macrocode} + \WSF@global + \the\expandafter\@temptokena\csname + \expandafter \SuffixName + \reserved@a\reserved@b\endcsname} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\WSF@suffixcheck} +% We now do the runtime code. This is +% executed in a group of its own in order not to interfere with any +% other macros. +% \begin{macrocode} +\def\WSF@suffixcheck#1{\begingroup\def\reserved@a{#1}% + \futurelet\reserved@b\WSF@suffixcheckii} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\WSF@suffixcheckii} +% After assigning the \meta{suffix} to \cmd{\reserved@b}, we split +% into the case of known and unknown suffix. We don't code this +% inline, since \cmd{\reserved@} in a false conditional might +% confuse \TeX\ if it happens to be something like |\iffalse| +% itself. +% \begin{macrocode} +\def\WSF@suffixcheckii{\ifcsname \expandafter\SuffixName + \reserved@a\reserved@b\endcsname + \expandafter + \WSF@suffixcheckiii + \else + \expandafter + \WSF@suffixcheckiv + \fi} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\WSF@suffixcheckiii} +% \begin{macro}{\WSF@suffixcheckiv} +% Calling the macros is reasonably straightforward, we just have to +% take care not to close the group at the wrong time. +% \begin{macrocode} +\def\WSF@suffixcheckiii{% + \afterassignment\endgroup + \expandafter\aftergroup + \csname \expandafter \SuffixName\reserved@a\reserved@b\endcsname + \WSF@gobblenext} + +\def\WSF@suffixcheckiv{% + \expandafter\endgroup + \csname \expandafter\NoSuffixName\reserved@a\endcsname} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \begin{macro}{\WSF@sfx} +% Now we just augment \cmd{WSF@sfx} to recognize all prefixes and +% global commands: +% \begin{macrocode} +\WithSuffix\def\WSF@sfx\long{\WSF@append\long\WSF@sfx} +\WithSuffix\def\WSF@sfx\global{\let\WSF@global\global\WSF@sfx} +\WithSuffix\def\WSF@sfx\protected{\WSF@append\protected\WSF@sfx} +\WithSuffix\def\WSF@sfx\expandafter{\expandafter\WSF@sfx\expandafter} +\WithSuffix\edef\WSF@sfx\gdef{\let\WSF@global\global + \expandafter\noexpand\csname\NoSuffixName\WSF@sfx\endcsname\def} +\WithSuffix\edef\WSF@sfx\xdef{\let\WSF@global\global + \expandafter\noexpand\csname\NoSuffixName\WSF@sfx\endcsname\edef} +% +% \end{macrocode} +%\end{macro} +% \Finale +% \endinput +% Local Variables: +% mode: doctex +% TeX-master: "suffix.drv" +% End: diff --git a/macros/latex/contrib/bigfoot/suffix.pdf b/macros/latex/contrib/bigfoot/suffix.pdf new file mode 100644 index 0000000000..faae714a5b Binary files /dev/null and b/macros/latex/contrib/bigfoot/suffix.pdf differ -- cgit v1.2.3