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