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