Replace general GPL rubrics with project-specific ones.
[mdwtools] / footnote.dtx
CommitLineData
86f6a31e 1% \begin{meta-comment} <general public licence>
2%%
3%% footnote package -- Save footnotes around boxing environments
8bc5bdd2 4%% Copyright (c) 1996, 1997, 2002, 2020 Mark Wooding
86f6a31e 5%<*package>
6%%
3d509049 7%% This file is part of the `mdwtools' LaTeX package collection.
86f6a31e 8%%
3d509049
MW
9%% `mdwtools' is free software: you can redistribute it and/or modify it
10%% under the terms of the GNU General Public License as published by the
11%% Free Software Foundation; either version 2 of the License, or (at your
12%% option) any later version.
13%%
14%% `mdwtools' is distributed in the hope that it will be useful, but
15%% WITHOUT ANY WARRANTY; without even the implied warranty of
16%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17%% General Public License for more details.
86f6a31e 18%%
19%% You should have received a copy of the GNU General Public License
3d509049
MW
20%% along with `mdwtools'. If not, write to the Free Software Foundation,
21%% Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
86f6a31e 22%</package>
23%%
24% \end{meta-comment}
25%
26% \begin{meta-comment} <Package preamble>
27%<+package>\NeedsTeXFormat{LaTeX2e}
28%<+package>\ProvidesPackage{footnote}
af8af7eb 29%<+package> [2020/09/06 1.14.0 Save footnotes around boxes]
86f6a31e 30% \end{meta-comment}
31%
3e2c5da8 32% \CheckSum{329}
86f6a31e 33%\iffalse
34%<*package>
35%\fi
36%% \CharacterTable
37%% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
38%% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
39%% Digits \0\1\2\3\4\5\6\7\8\9
40%% Exclamation \! Double quote \" Hash (number) \#
41%% Dollar \$ Percent \% Ampersand \&
42%% Acute accent \' Left paren \( Right paren \)
43%% Asterisk \* Plus \+ Comma \,
44%% Minus \- Point \. Solidus \/
45%% Colon \: Semicolon \; Less than \<
46%% Equals \= Greater than \> Question mark \?
47%% Commercial at \@ Left bracket \[ Backslash \\
48%% Right bracket \] Circumflex \^ Underscore \_
49%% Grave accent \` Left brace \{ Vertical bar \|
50%% Right brace \} Tilde \~}
51%%
52%\iffalse
53%</package>
54%\fi
55%
56% \begin{meta-comment} <driver>
57%
58%<*driver>
59\input{mdwtools}
60\describespackage{footnote}
61\mdwdoc
62%</driver>
63%
64% \end{meta-comment}
65%
66% \section{User guide}
67%
68% This package provides some commands for handling footnotes slightly
69% better than \LaTeX\ usually does; there are several commands and
70% environments (notably |\parbox|, \env{minipage} and \env{tabular}
71% \begin{footnote}
72% The \package{mdwtab} package, provided in this distribution, handles
73% footnotes correctly anyway; it uses an internal version of this package
74% to do so.
75% \end{footnote})
76% which `trap' footnotes so that they can't escape and appear at the bottom
77% of the page.
78%
79% \DescribeEnv{savenotes}
80% The \env{savenotes} environment saves up any footnotes encountered within
81% it, and performs them all at the end.
82%
83% \DescribeMacro{\savenotes}
84% \DescribeMacro{\spewnotes}
85% If you're defining a command or environment, you can use the |\savenotes|
86% command to start saving up footnotes, and the |\spewnotes| command to
87% execute them all at the end. Note that |\savenotes| and |\spewnotes|
88% enclose a group, so watch out. You can safely nest the commands and
89% environments -- they work out if they're already working and behave
90% appropriately.
91%
92% \DescribeEnv{minipage*}
93% To help things along a bit, the package provides a $*$-version of the
94% \env{minipage} environment, which doesn't trap footnotes for itself (and
95% in fact sends any footnotes it contains to the bottom of the page, where
96% they belong).
97%
98% \DescribeMacro{\makesavenoteenv}
99% The new \env{minipage$*$} environment was created with a magic command
100% called |\makesavenoteenv|. It has a fairly simple syntax:
101%
102% \begin{grammar}
103% <make-save-note-env-cmd> ::= \[[
104% "\\makesavenoteenv"
105% \begin{stack} \\ "[" <new-env-name> "]" \end{stack}
106% "{" <env-name> "}"
107% \]]
108% \end{grammar}
109%
110% Without the optional argument, it redefines the named environment so that
111% it handles footnotes correctly. With the optional argument, it makes
112% the new environment named by \<new-env-name> into a footnote-friendly
113% version of the \<env-name> environment.
114%
115% \DescribeMacro{\parbox}
116% The package also redefines the |\parbox| command so that it works properly
117% with footnotes.
118%
119% \DescribeEnv{footnote}
120% The other problem which people tend to experience with footnotes is that
121% you can't put verbatim text (with the |\verb| comamnd or the \env{verbatim}
122% environment) into the |\footnote| command's argument. This package
123% provides a \env{footnote} \emph{environment}, which \emph{does} allow
124% verbatim things. You use the environment just like you do the command.
125% It's really easy. It even has an optional argument, which works the same
126% way.
127%
128% \DescribeEnv{footnotetext}
129% To go with the \env{footnote} environment, there's a \env{footnotetext}
130% environment, which just puts the text in the bottom of the page, like
131% |\footnotetext| does.
132%
133% There's a snag with these environments, though. Some other nonstandard
134% environments, like \env{tabularx}, try to handle footnotes their own
135% way, because they won't work otherwise. The way they do this is not
136% compatible with the way that the \env{footnote} and \env{footnotetext}
137% environments work, and you will get strange results if you try (there'll
138% be odd vertical spacing, and the footnote text may well be incorrect).
139% \begin{footnote}
140% The solution to this problem is to send mail to David Carlisle persuading
141% him to use this package to handle footnotes, rather than doing it his
142% way.
143% \end{footnote}
144%
145% \implementation
146%
147% \section{Implementation}
148%
149% Most implementations of footnote-saving (in particular, that used in
150% the \package{tabularx} and \package{longtable} packages) use a token
151% list register to store the footnote text, and then expand it when whatever
152% was preventing footnotes (usually a vbox) stops. This is no good at all
153% if the footnotes contain things which might not be there by the time the
154% expansion occurs. For example, references to things in temporary boxes
155% won't work.
156%
157% This implementation therefore stores the footnotes up in a box register.
158% This must be just as valid as using tokens, because all I'm going to do
159% at the end is unbox the box).
160%
161% \begin{macrocode}
162%<*macro|package>
163\ifx\fn@notes\@@undefined%
164 \newbox\fn@notes%
165\fi
166% \end{macrocode}
167%
168% I'll need a length to tell me how wide the footnotes should be at the
169% moment.
170%
171% \begin{macrocode}
172\newdimen\fn@width
173% \end{macrocode}
174%
175% Of course, I can't set this up until I actually start saving footnotes.
176% Until then I'll use |\columnwidth| (which works in \package{multicol}
177% even though it doesn't have any right to).
178%
179% \begin{macrocode}
180\let\fn@colwidth\columnwidth
181% \end{macrocode}
182%
183% And now a switch to remember if we're already handling footnotes,
184%
185% \begin{macrocode}
186\newif\if@savingnotes
187% \end{macrocode}
188%
189%
190% \subsection{Building footnote text}
191%
192% I need to emulate \LaTeX's footnote handling when I'm putting the notes
193% into my box; this is also useful in the verbatim-in-footnotes stuff.
194%
195% \begin{macro}{\fn@startnote}
196%
197% Here's how a footnote gets started. Most of the code here is stolen
198% from |\@footnotetext|.
199%
200% \begin{macrocode}
201\def\fn@startnote{%
202 \hsize\fn@colwidth%
203 \interlinepenalty\interfootnotelinepenalty%
204 \reset@font\footnotesize%
205 \floatingpenalty\@MM% Is this right???
206 \@parboxrestore%
207 \protected@edef\@currentlabel{\csname p@\@mpfn\endcsname\@thefnmark}%
208 \color@begingroup%
209}
210% \end{macrocode}
211%
212% \end{macro}
213%
214% \begin{macro}{\fn@endnote}
215%
216% Footnotes are finished off by this macro. This is the easy bit.
217%
218% \begin{macrocode}
5ca7df6a 219\def\fn@endnote{\color@endgroup}
86f6a31e 220% \end{macrocode}
221%
222% \end{macro}
223%
224%
225% \subsection{Footnote saving}
226%
227% \begin{macro}{\fn@fntext}
228%
229% Now to define how to actually do footnotes. I'll just add the notes to
230% the bottom of the footnote box I'm building.
231%
232% There's some hacking added here to handle the case that a footnote is
233% in an |\intertext| command within a broken \package{amsmath} alignment
234% environment -- otherwise the footnotes get duplicated due to the way that
235% that package measures equations.
236% \begin{footnote}
237% The correct solution of course is to
238% implement aligning environments in a sensible way, by building the table
239% and leaving penalties describing the intended format, and then pick that
240% apart in a postprocessing phase. If I get the time, I'll start working
241% on this again. I have a design worked out and the beginnings of an
242% implementation, but it's going to be a long time coming.
243% \end{footnote}
244%
245% \begin{macrocode}
9369e223 246\long\def\fn@fntext#1{%
86f6a31e 247 \ifx\ifmeasuring@\@@undefined%
248 \expandafter\@secondoftwo\else\expandafter\@iden%
249 \fi%
250 {\ifmeasuring@\expandafter\@gobble\else\expandafter\@iden\fi}%
251 {%
252 \global\setbox\fn@notes\vbox{%
253 \unvbox\fn@notes%
254 \fn@startnote%
255 \@makefntext{%
256 \rule\z@\footnotesep%
257 \ignorespaces%
258 #1%
259 \@finalstrut\strutbox%
260 }%
261 \fn@endnote%
262 }%
263 }%
264}
265% \end{macrocode}
266%
267% \end{macro}
268%
269% \begin{macro}{\savenotes}
270%
271% The |\savenotes| declaration starts saving footnotes, to be spewed at a
272% later date. We'll also remember which counter we're meant to use, and
273% redefine the footnotes used by minipages.
274%
275% The idea here is that we'll gather up footnotes within the environment,
276% and output them in whatever format they were being typeset outside the
277% environment.
278%
279% I'll take this a bit at a time. The start is easy: we need a group in
280% which to keep our local definitions.
281%
282% \begin{macrocode}
283\def\savenotes{%
284 \begingroup%
285% \end{macrocode}
286%
287% Now, if I'm already saving footnotes away, I won't bother doing anything
288% here. Otherwise I need to start hacking, and set the switch.
289%
290% \begin{macrocode}
291 \if@savingnotes\else%
292 \@savingnotestrue%
293% \end{macrocode}
294%
295% I redefine the |\@footnotetext| command, which is responsible for adding
296% a footnote to the appropriate insert. I'll redefine both the current
297% version, and \env{minipage}'s specific version, in case there's a nested
298% minipage.
299%
300% \begin{macrocode}
301 \let\@footnotetext\fn@fntext%
302 \let\@mpfootnotetext\fn@fntext%
303% \end{macrocode}
304%
305% I'd better make sure my box is empty before I start, and I must set up
306% the column width so that later changes (e.g., in \env{minipage}) don't
307% upset things too much.
308%
309% \begin{macrocode}
310 \fn@width\columnwidth%
311 \let\fn@colwidth\fn@width%
312 \global\setbox\fn@notes\box\voidb@x%
313% \end{macrocode}
314%
315% Now for some yuckiness. I want to ensure that \env{minipage} doesn't
316% change how footnotes are handled once I've taken charge. I'll store the
317% current values of |\thempfn| (which typesets a footnote marker) and
318% |\@mpfn| (which contains the name of the current footnote counter).
319%
320% \begin{macrocode}
321 \let\fn@thempfn\thempfn%
322 \let\fn@mpfn\@mpfn%
323% \end{macrocode}
324%
325% The \env{minipage} environment provides a hook, called |\@minipagerestore|.
326% Initially it's set to |\relax|, which is unfortunately unexpandable, so if
327% I want to add code to it, I must check this possibility. I'll make it
328% |\@empty| (which expands to nothing) if it's still |\relax|. Then I'll
329% add my code to the hook, to override |\thempfn| and |\@mpfn| set up by
330% \env{minipage}.
331%
332% Note that I can't just force the |mpfootnote| counter to be equal to
333% the |footnote| one, because \env{minipage} clears |\c@mpfootnote| to zero
334% when it starts. This method will ensure that even so, the current counter
335% works OK.
336%
337% \begin{macrocode}
338 \ifx\@minipagerestore\relax\let\@minipagerestore\@empty\fi%
339 \expandafter\def\expandafter\@minipagerestore\expandafter{%
340 \@minipagerestore%
341 \let\thempfn\fn@thempfn%
342 \let\@mpfn\fn@mpfn%
343 }%
344 \fi%
345}
346% \end{macrocode}
347%
348% \end{macro}
349%
350% \begin{macro}{\spewnotes}
351%
352% Now I can spew out the notes we saved. This is a bit messy, actually.
353% Since the standard |\@footnotetext| implementation tries to insert funny
354% struts and things, I must be a bit careful. I'll disable all this bits
355% which start paragraphs prematurely.
356%
357% \begin{macrocode}
358\def\spewnotes{%
359 \endgroup%
360 \if@savingnotes\else\ifvoid\fn@notes\else\begingroup%
361 \let\@makefntext\@empty%
362 \let\@finalstrut\@gobble%
363 \let\rule\@gobbletwo%
364 \@footnotetext{\unvbox\fn@notes}%
365 \endgroup\fi\fi%
366}
367% \end{macrocode}
368%
369% \end{macro}
370%
371% Now make an environment, for users.
372%
373% \begin{macrocode}
374\let\endsavenotes\spewnotes
375% \end{macrocode}
376%
377% That's all that needs to be in the shared code section.
378%
379% \begin{macrocode}
380%</macro|package>
381%<*package>
382% \end{macrocode}
383%
384%
385% \subsection{The \env{footnote} environment}
386%
387% Since |\footnote| is a command with an argument, things like \env{verbatim}
388% are unwelcome in it. Every so often someone on |comp.text.tex| moans
389% about it and I post a nasty hack to make it work. However, as a more
390% permanent and `official' solution, here's an environment which does the
391% job rather better. Lots of this is based on code from my latest attempt
392% on the newsgroup.
393%
394% I'll work on this in a funny order, although I think it's easier to
395% understand. First, I'll do some macros for reading the optional argument
396% of footnote-related commands.
397%
398% \begin{macro}{\fn@getmark}
399%
400% Saying \syntax{"\\fn@getmark{"<default-code>"}{"<cont-code>"}"} will read
401% an optional argument giving a value for the footnote counter; if the
402% argument isn't there, the \<default-code> is executed, and it's expected
403% to set up the appropriate counter to the current value. The footnote
404% marker text is stored in the macro |\@thefnmark|, as is conventional for
405% \LaTeX's footnote handling macros. Once this is done properly, the
406% \<cont-code> is called to continue handling things.
407%
408% Since the handling of the optional argument plays with the footnote
409% counter locally, I'll start a group right now to save some code. Then I'll
410% decide what to do based on the presence of the argument.
411%
412% \begin{macrocode}
413\def\fn@getmark#1#2{%
414 \begingroup%
415 \@ifnextchar[%
416 {\fn@getmark@i{#1}}%
417 {#1\fn@getmark@ii{#2}}%
418}
419% \end{macrocode}
420%
421% There's an optional argument, so I need to read it and assign it to the
422% footnote counter.
423%
424% \begin{macrocode}
425\def\fn@getmark@i#1[#2]{%
426 \csname c@\@mpfn\endcsname#2%
427 \fn@getmark@ii%
428}
429% \end{macrocode}
430%
431% Finally, set up the macro properly, and end the group.
432%
433% \begin{macrocode}
434\def\fn@getmark@ii#1{%
435 \unrestored@protected@xdef\@thefnmark{\thempfn}%
436 \endgroup%
437 #1%
438}
439% \end{macrocode}
440%
441% \end{macro}
442%
443% From argument reading, I'll move on to footnote typesetting.
444%
445% \begin{macro}{\fn@startfntext}
446%
447% The |\fn@startfntext| macro sets everything up for building the footnote
448% in a box register, ready for unboxing into the footnotes insert. The
449% |\fn@prefntext| macro is a style hook I'll set up later.
450%
451% \begin{macrocode}
452\def\fn@startfntext{%
453 \setbox\z@\vbox\bgroup%
454 \fn@startnote%
455 \fn@prefntext%
456 \rule\z@\footnotesep%
457 \ignorespaces%
458}
459% \end{macrocode}
460%
461% \end{macro}
462%
463% \begin{macro}{\fn@endfntext}
464%
465% Now I'll end the vbox, and add it to the footnote insertion. Again, I
466% must be careful to prevent |\@footnotetext| from adding horizontal mode
467% things in bad places.
468%
469% \begin{macrocode}
470\def\fn@endfntext{%
471 \@finalstrut\strutbox%
472 \fn@postfntext%
3e2c5da8 473 \fn@endnote%
86f6a31e 474 \egroup%
475 \begingroup%
476 \let\@makefntext\@empty%
477 \let\@finalstrut\@gobble%
478 \let\rule\@gobbletwo%
479 \@footnotetext{\unvbox\z@}%
480 \endgroup%
481}
482% \end{macrocode}
483%
484% \end{macro}
485%
486% \begin{environment}{footnote}
487%
488% I can now start on the environment proper. First I'll look for an
489% optional argument.
490%
491% \begin{listing}
492%\def\footnote{%
493% \end{listing}
494%
495% Oh. I've already come up against the first problem: that name's already
496% used. I'd better save the original version.
497%
498% \begin{macrocode}
499\let\fn@latex@@footnote\footnote
500% \end{macrocode}
501%
502% The best way I can think of for seeing if I'm in an environment is to
503% look at |\@currenvir|. I'll need something to compare with, then.
504%
505% \begin{macrocode}
506\def\fn@footnote{footnote}
507% \end{macrocode}
508%
509% Now to start properly. |;-)|
510%
511% \begin{macrocode}
512\def\footnote{%
513 \ifx\@currenvir\fn@footnote%
514 \expandafter\@firstoftwo%
515 \else%
516 \expandafter\@secondoftwo%
517 \fi%
518 {\fn@getmark{\stepcounter\@mpfn}%
519 {\leavevmode\unskip\@footnotemark\fn@startfntext}}%
520 {\fn@latex@@footnote}%
521}
522% \end{macrocode}
523%
524% Ending the environment is simple.
525%
526% \begin{macrocode}
527\let\endfootnote\fn@endfntext
528% \end{macrocode}
529%
530% \end{environment}
531%
532% \begin{environment}{footnotetext}
533%
534% I'll do the same magic as before for |\footnotetext|.
535%
536% \begin{macrocode}
537\def\fn@footnotetext{footnotetext}
538\let\fn@latex@@footnotetext\footnotetext
539\def\footnotetext{%
540 \ifx\@currenvir\fn@footnotetext%
541 \expandafter\@firstoftwo%
542 \else%
543 \expandafter\@secondoftwo%
544 \fi%
545 {\fn@getmark{}\fn@startfntext}%
546 {\fn@latex@@footnotetext}%
547}
548\let\endfootnotetext\endfootnote
549% \end{macrocode}
550%
551% \end{environment}
552%
553% \begin{macro}{\fn@prefntext}
554% \begin{macro}{\fn@postfntext}
555%
556% Now for one final problem. The style hook for footnotes is the command
557% |\@makefntext|, which takes the footnote text as its argument. Clearly
558% this is utterly unsuitable, so I need to split it into two bits, where
559% the argument is. This is very tricky, and doesn't deserve to work,
560% although it appears to be a good deal more effective than it has any right
561% to be.
562%
563% \begin{macrocode}
564\long\def\@tempa#1\@@#2\@@@{\def\fn@prefntext{#1}\def\fn@postfntext{#2}}
565\expandafter\@tempa\@makefntext\@@\@@@
566% \end{macrocode}
567%
568% \end{macro}
569% \end{macro}
570%
571%
572% \subsection{Hacking existing environments}
573%
574% Some existing \LaTeX\ environments ought to have footnote handling but
575% don't. Now's our chance.
576%
577% \begin{macro}{\makesavenoteenv}
578%
579% The |\makesavenoteenv| command makes an environment save footnotes around
580% itself.
581%
582% It would also be nice to make |\parbox| work with footnotes. I'll do this
583% later.
584%
585% \begin{macrocode}
586\def\makesavenoteenv{\@ifnextchar[\fn@msne@ii\fn@msne@i}
587% \end{macrocode}
588%
589% We're meant to redefine the environment. We'll copy it (using |\let|) to
590% a magic name, and then pass it on to stage~2.
591%
592% \begin{macrocode}
593\def\fn@msne@i#1{%
594 \expandafter\let\csname msne$#1\expandafter\endcsname%
595 \csname #1\endcsname%
596 \expandafter\let\csname endmsne$#1\expandafter\endcsname%
597 \csname end#1\endcsname%
598 \fn@msne@ii[#1]{msne$#1}%
599}
600% \end{macrocode}
601%
602% Now we'll define the new environment. The start is really easy, since we
603% just need to insert a |\savenotes|. The end is more complex, since we
604% need to preserve the |\if@endpe| flag so that |\end| can pick it up. I
605% reckon that proper hooks should be added to |\begin| and |\end| so that
606% environments can define things to be done outside the main group as
607% well as within it; still, we can't all have what we want, can we?
608%
609% \begin{macrocode}
610\def\fn@msne@ii[#1]#2{%
611 \expandafter\edef\csname#1\endcsname{%
612 \noexpand\savenotes%
613 \expandafter\noexpand\csname#2\endcsname%
614 }%
615 \expandafter\edef\csname end#1\endcsname{%
616 \expandafter\noexpand\csname end#2\endcsname%
617 \noexpand\expandafter%
618 \noexpand\spewnotes%
619 \noexpand\if@endpe\noexpand\@endpetrue\noexpand\fi%
620 }%
621}
622% \end{macrocode}
623%
624% \end{macro}
625%
626% \begin{environment}{minipage*}
627%
628% Let's define a \env{minipage$*$} environment which handles footnotes
629% nicely. Really easy:
630%
631% \begin{macrocode}
632\makesavenoteenv[minipage*]{minipage}
633% \end{macrocode}
634%
635% \end{environment}
636%
637% \begin{macro}{\parbox}
638%
639% Now to alter |\parbox| slightly, so that it handles footnotes properly.
640% I'm going to do this fairly inefficiently, because I'm going to try and
641% change it as little as possible.
642%
643% First, I'll save the old |\parbox| command. If I don't find a \lit{*},
644% I'll just call this command.
645%
646% \begin{macrocode}
647\let\fn@parbox\parbox
648% \end{macrocode}
649%
650% This is the clever bit: I don't know how many optional arguments
651% Mr~Mittelbach and his chums will add to |\parbox|, so I'll handle any
652% number. I'll store them all up in my first argument and call myself
653% every time I find a new one. If I run out of optional arguments,
654% I'll call the original |\parbox| command, surrounding it with |\savenotes|
655% and |\spewnotes|.
656%
657% \begin{macrocode}
658\def\parbox{\@ifnextchar[{\fn@parbox@i{}}{\fn@parbox@ii{}}}
659\def\fn@parbox@i#1[#2]{%
660 \@ifnextchar[{\fn@parbox@i{#1[#2]}}{\fn@parbox@ii{#1[#2]}}%
661}
662\long\def\fn@parbox@ii#1#2#3{\savenotes\fn@parbox#1{#2}{#3}\spewnotes}
663% \end{macrocode}
664%
665% \end{macro}
666%
667% Done!
668%
669% \begin{macrocode}
670%</package>
671% \end{macrocode}
672%
673% \hfill Mark Wooding, \today
674%
675% \Finale
676%
677\endinput