% \begin{meta-comment}
%
% $Id$
%
% Save footnotes around boxing environments and things
%
% (c) 1996 Mark Wooding
%
%----- Revision history -----------------------------------------------------
%
% $Log$
% Revision 1.1  2000-07-13 09:10:20  michael
% + Initial import
%
% Revision 1.1  1998/09/21 10:19:01  michael
% Initial implementation
%
% Revision 1.13  1997/01/28 19:45:16  mdw
% Fixed stupid bug in AMS environment handling which stops the thing from
% working properly if you haven't included amsmath.  Doh.
%
% Revision 1.12  1997/01/18 00:45:37  mdw
% Fix problems with duplicated footnotes in broken AMS environments which
% typeset things multiple times.  This is a nasty kludge.
%
% Revision 1.11  1996/11/19 20:50:05  mdw
% Entered into RCS
%
%
% \end{meta-comment}
%
% \begin{meta-comment} <general public licence>
%%
%% footnote package -- Save footnotes around boxing environments
%% Copyright (c) 1996 Mark Wooding
%<*package>
%%
%% 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., 675 Mass Ave, Cambridge, MA 02139, USA.
%</package>
%%
% \end{meta-comment}
%
% \begin{meta-comment} <Package preamble>
%<+package>\NeedsTeXFormat{LaTeX2e}
%<+package>\ProvidesPackage{footnote}
%<+package>                [1997/01/28 1.13 Save footnotes around boxes]
% \end{meta-comment}
%
% \CheckSum{327}
%\iffalse
%<*package>
%\fi
%% \CharacterTable
%%  {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
%%   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
%%   Digits        \0\1\2\3\4\5\6\7\8\9
%%   Exclamation   \!     Double quote  \"     Hash (number) \#
%%   Dollar        \$     Percent       \%     Ampersand     \&
%%   Acute accent  \'     Left paren    \(     Right paren   \)
%%   Asterisk      \*     Plus          \+     Comma         \,
%%   Minus         \-     Point         \.     Solidus       \/
%%   Colon         \:     Semicolon     \;     Less than     \<
%%   Equals        \=     Greater than  \>     Question mark \?
%%   Commercial at \@     Left bracket  \[     Backslash     \\
%%   Right bracket \]     Circumflex    \^     Underscore    \_
%%   Grave accent  \`     Left brace    \{     Vertical bar  \|
%%   Right brace   \}     Tilde         \~}
%%
%\iffalse
%</package>
%\fi
%
% \begin{meta-comment} <driver>
%
%<*driver>
\input{mdwtools}
\describespackage{footnote}
\mdwdoc
%</driver>
%
% \end{meta-comment}
%
% \section{User guide}
%
% This package provides some commands for handling footnotes slightly
% better than \LaTeX\ usually does; there are several commands and
% environments (notably |\parbox|, \env{minipage} and \env{tabular}
% \begin{footnote}
%   The \package{mdwtab} package, provided in this distribution, handles
%   footnotes correctly anyway; it uses an internal version of this package
%   to do so.
% \end{footnote})
% which `trap' footnotes so that they can't escape and appear at the bottom
% of the page.
%
% \DescribeEnv{savenotes}
% The \env{savenotes} environment saves up any footnotes encountered within
% it, and performs them all at the end.
%
% \DescribeMacro{\savenotes}
% \DescribeMacro{\spewnotes}
% If you're defining a command or environment, you can use the |\savenotes|
% command to start saving up footnotes, and the |\spewnotes| command to
% execute them all at the end.  Note that |\savenotes| and |\spewnotes|
% enclose a group, so watch out.  You can safely nest the commands and
% environments -- they work out if they're already working and behave
% appropriately.
%
% \DescribeEnv{minipage*}
% To help things along a bit, the package provides a $*$-version of the
% \env{minipage} environment, which doesn't trap footnotes for itself (and
% in fact sends any footnotes it contains to the bottom of the page, where
% they belong).
%
% \DescribeMacro{\makesavenoteenv}
% The new \env{minipage$*$} environment was created with a magic command
% called |\makesavenoteenv|.  It has a fairly simple syntax:
%
% \begin{grammar}
% <make-save-note-env-cmd> ::= \[[
%   "\\makesavenoteenv"
%   \begin{stack} \\ "[" <new-env-name> "]" \end{stack}
%   "{" <env-name> "}"
% \]]
% \end{grammar}
%
% Without the optional argument, it redefines the named environment so that
% it handles footnotes correctly.  With the optional argument, it makes
% the new environment named by \<new-env-name> into a footnote-friendly
% version of the \<env-name> environment.
%
% \DescribeMacro{\parbox}
% The package also redefines the |\parbox| command so that it works properly
% with footnotes.
%
% \DescribeEnv{footnote}
% The other problem which people tend to experience with footnotes is that
% you can't put verbatim text (with the |\verb| comamnd or the \env{verbatim}
% environment) into the |\footnote| command's argument.  This package
% provides a \env{footnote} \emph{environment}, which \emph{does} allow
% verbatim things.  You use the environment just like you do the command.
% It's really easy.  It even has an optional argument, which works the same
% way.
%
% \DescribeEnv{footnotetext}
% To go with the \env{footnote} environment, there's a \env{footnotetext}
% environment, which just puts the text in the bottom of the page, like
% |\footnotetext| does.
%
% There's a snag with these environments, though.  Some other nonstandard
% environments, like \env{tabularx}, try to handle footnotes their own
% way, because they won't work otherwise.  The way they do this is not
% compatible with the way that the \env{footnote} and \env{footnotetext}
% environments work, and you will get strange results if you try (there'll
% be odd vertical spacing, and the footnote text may well be incorrect).
% \begin{footnote}
%   The solution to this problem is to send mail to David Carlisle persuading
%   him to use this package to handle footnotes, rather than doing it his
%   way.
% \end{footnote}
%
% \implementation
%
% \section{Implementation}
%
% Most implementations of footnote-saving (in particular, that used in
% the \package{tabularx} and \package{longtable} packages) use a token
% list register to store the footnote text, and then expand it when whatever
% was preventing footnotes (usually a vbox) stops.  This is no good at all
% if the footnotes contain things which might not be there by the time the
% expansion occurs.  For example, references to things in temporary boxes
% won't work.
%
% This implementation therefore stores the footnotes up in a box register.
% This must be just as valid as using tokens, because all I'm going to do
% at the end is unbox the box).
%
%    \begin{macrocode}
%<*macro|package>
\ifx\fn@notes\@@undefined%
  \newbox\fn@notes%
\fi
%    \end{macrocode}
%
% I'll need a length to tell me how wide the footnotes should be at the
% moment.
%
%    \begin{macrocode}
\newdimen\fn@width
%    \end{macrocode}
%
% Of course, I can't set this up until I actually start saving footnotes.
% Until then I'll use |\columnwidth| (which works in \package{multicol}
% even though it doesn't have any right to).
%
%    \begin{macrocode}
\let\fn@colwidth\columnwidth
%    \end{macrocode}
%
% And now a switch to remember if we're already handling footnotes,
%
%    \begin{macrocode}
\newif\if@savingnotes
%    \end{macrocode}
%
%
% \subsection{Building footnote text}
%
% I need to emulate \LaTeX's footnote handling when I'm putting the notes
% into my box; this is also useful in the verbatim-in-footnotes stuff.
%
% \begin{macro}{\fn@startnote}
%
% Here's how a footnote gets started.  Most of the code here is stolen
% from |\@footnotetext|.
%
%    \begin{macrocode}
\def\fn@startnote{%
  \hsize\fn@colwidth%
  \interlinepenalty\interfootnotelinepenalty%
  \reset@font\footnotesize%
  \floatingpenalty\@MM% Is this right???
  \@parboxrestore%
  \protected@edef\@currentlabel{\csname p@\@mpfn\endcsname\@thefnmark}%
  \color@begingroup%
}
%    \end{macrocode}
%
% \end{macro}
%
% \begin{macro}{\fn@endnote}
%
% Footnotes are finished off by this macro.  This is the easy bit.
%
%    \begin{macrocode}
\let\fn@endnote\color@endgroup
%    \end{macrocode}
%
% \end{macro}
%
%
% \subsection{Footnote saving}
%
% \begin{macro}{\fn@fntext}
%
% Now to define how to actually do footnotes.  I'll just add the notes to
% the bottom of the footnote box I'm building.
%
% There's some hacking added here to handle the case that a footnote is
% in an |\intertext| command within a broken \package{amsmath} alignment
% environment -- otherwise the footnotes get duplicated due to the way that
% that package measures equations.
% \begin{footnote}
%   The correct solution of course is to
%   implement aligning environments in a sensible way, by building the table
%   and leaving penalties describing the intended format, and then pick that
%   apart in a postprocessing phase.  If I get the time, I'll start working
%   on this again.  I have a design worked out and the beginnings of an
%   implementation, but it's going to be a long time coming.
% \end{footnote}
%
%    \begin{macrocode}
\def\fn@fntext#1{%
  \ifx\ifmeasuring@\@@undefined%
    \expandafter\@secondoftwo\else\expandafter\@iden%
  \fi%
  {\ifmeasuring@\expandafter\@gobble\else\expandafter\@iden\fi}%
  {%
    \global\setbox\fn@notes\vbox{%
      \unvbox\fn@notes%
      \fn@startnote%
      \@makefntext{%
        \rule\z@\footnotesep%
        \ignorespaces%
        #1%
        \@finalstrut\strutbox%
      }%
      \fn@endnote%
    }%
  }%
}
%    \end{macrocode}
%
% \end{macro}
%
% \begin{macro}{\savenotes}
%
% The |\savenotes| declaration starts saving footnotes, to be spewed at a
% later date.  We'll also remember which counter we're meant to use, and
% redefine the footnotes used by minipages.
%
% The idea here is that we'll gather up footnotes within the environment,
% and output them in whatever format they were being typeset outside the
% environment.
%
% I'll take this a bit at a time.  The start is easy: we need a group in
% which to keep our local definitions.
%
%    \begin{macrocode}
\def\savenotes{%
  \begingroup%
%    \end{macrocode}
%
% Now, if I'm already saving footnotes away, I won't bother doing anything
% here.  Otherwise I need to start hacking, and set the switch.
%
%    \begin{macrocode}
  \if@savingnotes\else%
    \@savingnotestrue%
%    \end{macrocode}
%
% I redefine the |\@footnotetext| command, which is responsible for adding
% a footnote to the appropriate insert.  I'll redefine both the current
% version, and \env{minipage}'s specific version, in case there's a nested
% minipage.
%
%    \begin{macrocode}
    \let\@footnotetext\fn@fntext%
    \let\@mpfootnotetext\fn@fntext%
%    \end{macrocode}
%
% I'd better make sure my box is empty before I start, and I must set up
% the column width so that later changes (e.g., in \env{minipage}) don't
% upset things too much.
%
%    \begin{macrocode}
    \fn@width\columnwidth%
    \let\fn@colwidth\fn@width%
    \global\setbox\fn@notes\box\voidb@x%
%    \end{macrocode}
%
% Now for some yuckiness.  I want to ensure that \env{minipage} doesn't
% change how footnotes are handled once I've taken charge.  I'll store the
% current values of |\thempfn| (which typesets a footnote marker) and
% |\@mpfn| (which contains the name of the current footnote counter).
%
%    \begin{macrocode}
    \let\fn@thempfn\thempfn%
    \let\fn@mpfn\@mpfn%
%    \end{macrocode}
%
% The \env{minipage} environment provides a hook, called |\@minipagerestore|.
% Initially it's set to |\relax|, which is unfortunately unexpandable, so if
% I want to add code to it, I must check this possibility.  I'll make it
% |\@empty| (which expands to nothing) if it's still |\relax|.  Then I'll
% add my code to the hook, to override |\thempfn| and |\@mpfn| set up by
% \env{minipage}.
%
% Note that I can't just force the |mpfootnote| counter to be equal to
% the |footnote| one, because \env{minipage} clears |\c@mpfootnote| to zero
% when it starts.  This method will ensure that even so, the current counter
% works OK.
%
%    \begin{macrocode}
    \ifx\@minipagerestore\relax\let\@minipagerestore\@empty\fi%
    \expandafter\def\expandafter\@minipagerestore\expandafter{%
      \@minipagerestore%
      \let\thempfn\fn@thempfn%
      \let\@mpfn\fn@mpfn%
    }%
  \fi%
}
%    \end{macrocode}
%
% \end{macro}
%
% \begin{macro}{\spewnotes}
%
% Now I can spew out the notes we saved.  This is a bit messy, actually.
% Since the standard |\@footnotetext| implementation tries to insert funny
% struts and things, I must be a bit careful.  I'll disable all this bits
% which start paragraphs prematurely.
%
%    \begin{macrocode}
\def\spewnotes{%
  \endgroup%
  \if@savingnotes\else\ifvoid\fn@notes\else\begingroup%
    \let\@makefntext\@empty%
    \let\@finalstrut\@gobble%
    \let\rule\@gobbletwo%
    \@footnotetext{\unvbox\fn@notes}%
  \endgroup\fi\fi%
}
%    \end{macrocode}
%
% \end{macro}
%
% Now make an environment, for users.
%
%    \begin{macrocode}
\let\endsavenotes\spewnotes
%    \end{macrocode}
%
% That's all that needs to be in the shared code section.
%
%    \begin{macrocode}
%</macro|package>
%<*package>
%    \end{macrocode}
%
%
% \subsection{The \env{footnote} environment}
%
% Since |\footnote| is a command with an argument, things like \env{verbatim}
% are unwelcome in it.  Every so often someone on |comp.text.tex| moans
% about it and I post a nasty hack to make it work.  However, as a more
% permanent and `official' solution, here's an environment which does the
% job rather better.  Lots of this is based on code from my latest attempt
% on the newsgroup.
%
% I'll work on this in a funny order, although I think it's easier to
% understand.  First, I'll do some macros for reading the optional argument
% of footnote-related commands.
%
% \begin{macro}{\fn@getmark}
%
% Saying \syntax{"\\fn@getmark{"<default-code>"}{"<cont-code>"}"} will read
% an optional argument giving a value for the footnote counter; if the
% argument isn't there, the \<default-code> is executed, and it's expected
% to set up the appropriate counter to the current value.  The footnote
% marker text is stored in the macro |\@thefnmark|, as is conventional for
% \LaTeX's footnote handling macros.  Once this is done properly, the
% \<cont-code> is called to continue handling things.
%
% Since the handling of the optional argument plays with the footnote
% counter locally, I'll start a group right now to save some code.  Then I'll
% decide what to do based on the presence of the argument.
%
%    \begin{macrocode}
\def\fn@getmark#1#2{%
  \begingroup%
  \@ifnextchar[%
    {\fn@getmark@i{#1}}%
    {#1\fn@getmark@ii{#2}}%
}
%    \end{macrocode}
%
% There's an optional argument, so I need to read it and assign it to the
% footnote counter.
%
%    \begin{macrocode}
\def\fn@getmark@i#1[#2]{%
  \csname c@\@mpfn\endcsname#2%
  \fn@getmark@ii%
}
%    \end{macrocode}
%
% Finally, set up the macro properly, and end the group.
%
%    \begin{macrocode}
\def\fn@getmark@ii#1{%
  \unrestored@protected@xdef\@thefnmark{\thempfn}%
  \endgroup%
  #1%
}
%    \end{macrocode}
%
% \end{macro}
%
% From argument reading, I'll move on to footnote typesetting.
%
% \begin{macro}{\fn@startfntext}
%
% The |\fn@startfntext| macro sets everything up for building the footnote
% in a box register, ready for unboxing into the footnotes insert.  The
% |\fn@prefntext| macro is a style hook I'll set up later.
%
%    \begin{macrocode}
\def\fn@startfntext{%
  \setbox\z@\vbox\bgroup%
    \fn@startnote%
    \fn@prefntext%
    \rule\z@\footnotesep%
    \ignorespaces%
}
%    \end{macrocode}
%
% \end{macro}
%
% \begin{macro}{\fn@endfntext}
%
% Now I'll end the vbox, and add it to the footnote insertion.  Again, I
% must be careful to prevent |\@footnotetext| from adding horizontal mode
% things in bad places.
%
%    \begin{macrocode}
\def\fn@endfntext{%
    \@finalstrut\strutbox%
    \fn@postfntext%
  \egroup%
  \begingroup%
    \let\@makefntext\@empty%
    \let\@finalstrut\@gobble%
    \let\rule\@gobbletwo%
    \@footnotetext{\unvbox\z@}%
  \endgroup%
}
%    \end{macrocode}
%
% \end{macro}
%
% \begin{environment}{footnote}
%
% I can now start on the environment proper.  First I'll look for an
% optional argument.
%
%    \begin{listing}
%\def\footnote{%
%    \end{listing}
%
% Oh.  I've already come up against the first problem: that name's already
% used.  I'd better save the original version.
%
%    \begin{macrocode}
\let\fn@latex@@footnote\footnote
%    \end{macrocode}
%
% The best way I can think of for seeing if I'm in an environment is to
% look at |\@currenvir|.  I'll need something to compare with, then.
%
%    \begin{macrocode}
\def\fn@footnote{footnote}
%    \end{macrocode}
%
% Now to start properly.  |;-)|
%
%    \begin{macrocode}
\def\footnote{%
  \ifx\@currenvir\fn@footnote%
    \expandafter\@firstoftwo%
  \else%
    \expandafter\@secondoftwo%
  \fi%
  {\fn@getmark{\stepcounter\@mpfn}%
              {\leavevmode\unskip\@footnotemark\fn@startfntext}}%
  {\fn@latex@@footnote}%
}
%    \end{macrocode}
%
% Ending the environment is simple.
%
%    \begin{macrocode}
\let\endfootnote\fn@endfntext
%    \end{macrocode}
%
% \end{environment}
%
% \begin{environment}{footnotetext}
%
% I'll do the same magic as before for |\footnotetext|.
%
%    \begin{macrocode}
\def\fn@footnotetext{footnotetext}
\let\fn@latex@@footnotetext\footnotetext
\def\footnotetext{%
  \ifx\@currenvir\fn@footnotetext%
    \expandafter\@firstoftwo%
  \else%
    \expandafter\@secondoftwo%
  \fi%
  {\fn@getmark{}\fn@startfntext}%
  {\fn@latex@@footnotetext}%
}
\let\endfootnotetext\endfootnote
%    \end{macrocode}
%
% \end{environment}
%
% \begin{macro}{\fn@prefntext}
% \begin{macro}{\fn@postfntext}
%
% Now for one final problem.  The style hook for footnotes is the command
% |\@makefntext|, which takes the footnote text as its argument.  Clearly
% this is utterly unsuitable, so I need to split it into two bits, where
% the argument is.  This is very tricky, and doesn't deserve to work,
% although it appears to be a good deal more effective than it has any right
% to be.
%
%    \begin{macrocode}
\long\def\@tempa#1\@@#2\@@@{\def\fn@prefntext{#1}\def\fn@postfntext{#2}}
\expandafter\@tempa\@makefntext\@@\@@@
%    \end{macrocode}
%
% \end{macro}
% \end{macro}
%
%
% \subsection{Hacking existing environments}
%
% Some existing \LaTeX\ environments ought to have footnote handling but
% don't.  Now's our chance.
%
% \begin{macro}{\makesavenoteenv}
%
% The |\makesavenoteenv| command makes an environment save footnotes around
% itself.
%
% It would also be nice to make |\parbox| work with footnotes.  I'll do this
% later.
%
%    \begin{macrocode}
\def\makesavenoteenv{\@ifnextchar[\fn@msne@ii\fn@msne@i}
%    \end{macrocode}
%
% We're meant to redefine the environment.  We'll copy it (using |\let|) to
% a magic name, and then pass it on to stage~2.
%
%    \begin{macrocode}
\def\fn@msne@i#1{%
  \expandafter\let\csname msne$#1\expandafter\endcsname%
                  \csname #1\endcsname%
  \expandafter\let\csname endmsne$#1\expandafter\endcsname%
                  \csname end#1\endcsname%
  \fn@msne@ii[#1]{msne$#1}%
}
%    \end{macrocode}
%
% Now we'll define the new environment.  The start is really easy, since we
% just need to insert a |\savenotes|.  The end is more complex, since we
% need to preserve the |\if@endpe| flag so that |\end| can pick it up.  I
% reckon that proper hooks should be added to |\begin| and |\end| so that
% environments can define things to be done outside the main group as
% well as within it; still, we can't all have what we want, can we?
%
%    \begin{macrocode}
\def\fn@msne@ii[#1]#2{%
  \expandafter\edef\csname#1\endcsname{%
    \noexpand\savenotes%
    \expandafter\noexpand\csname#2\endcsname%
  }%
  \expandafter\edef\csname end#1\endcsname{%
    \expandafter\noexpand\csname end#2\endcsname%
    \noexpand\expandafter%
    \noexpand\spewnotes%
    \noexpand\if@endpe\noexpand\@endpetrue\noexpand\fi%
  }%
}
%    \end{macrocode}
%
% \end{macro}
%
% \begin{environment}{minipage*}
%
% Let's define a \env{minipage$*$} environment which handles footnotes
% nicely.  Really easy:
%
%    \begin{macrocode}
\makesavenoteenv[minipage*]{minipage}
%    \end{macrocode}
%
% \end{environment}
%
% \begin{macro}{\parbox}
%
% Now to alter |\parbox| slightly, so that it handles footnotes properly.
% I'm going to do this fairly inefficiently, because I'm going to try and
% change it as little as possible.
%
% First, I'll save the old |\parbox| command.  If I don't find a \lit{*},
% I'll just call this command.
%
%    \begin{macrocode}
\let\fn@parbox\parbox
%    \end{macrocode}
%
% This is the clever bit: I don't know how many optional arguments
% Mr~Mittelbach and his chums will add to |\parbox|, so I'll handle any
% number.  I'll store them all up in my first argument and call myself
% every time I find a new one.  If I run out of optional arguments,
% I'll call the original |\parbox| command, surrounding it with |\savenotes|
% and |\spewnotes|.
%
%    \begin{macrocode}
\def\parbox{\@ifnextchar[{\fn@parbox@i{}}{\fn@parbox@ii{}}}
\def\fn@parbox@i#1[#2]{%
  \@ifnextchar[{\fn@parbox@i{#1[#2]}}{\fn@parbox@ii{#1[#2]}}%
}
\long\def\fn@parbox@ii#1#2#3{\savenotes\fn@parbox#1{#2}{#3}\spewnotes}
%    \end{macrocode}
%
% \end{macro}
%
% Done!
%
%    \begin{macrocode}
%</package>
%    \end{macrocode}
%
% \hfill Mark Wooding, \today
%
% \Finale
%
\endinput
