              footnote —

a portmanteau package for customising footnotes in L^{A}TEX 2ε^{∗}

Robin Fairbairns^{†}

October 10, 1996

1 User interface

The footnote package provides four different customisations of the way foonotes are represented in L^{A}TEX 2ε documents (the sources of the code in this package are various, but all of it has been massaged by the author; where the code comes from elsewhere, there are attributions given below, somewhere or other).

The interface to the package’s options is very simple — each one is presented as an option in the \usepackage command. For example, to use a useful and consistent set, the author invokes the package with the command

\usepackage[perpage,para,symbol]{footnote}.

1.1 Option perpage

This option resets footnote numbering for each page of the document. It is derived from pagefoots.sty by Brian T. Schellenberger (bts@unx.sas.com), but I’ve done quite a lot of L^{A}TEX(2ε)-isation of the code. It needs two passes to do this correctly (though it comes as close as possible on the first pass). You generally have to make two passes with L^{A}TEX anyway, to get the cross-references right, so an additional pass for this purpose shouldn’t cause any additional problem. The option includes code to report that ‘Label(s) may have changed’, which will help the poor user to realise that another run is in order…

1.2 Option para

This option (derived from code by Dominik Wujastyk and Chris Rowley) causes footnotes to be typeset as a single paragraph at the bottom of the page on which they occur. In the case that there is only one footnote on the page, no effect will be observed. However, if there are several footnotes on the page, they will be run together in the page foot, each introduced by its footnote mark. This arrangement can save considerable space, but one should bear in mind Jill Knuth’s admonition on page 125 of the TEXbook: Don’t use footnotes in your books, Don. The original demand for the option came from the needs of those preparing critical editions; such documents typically have large numbers of small footnotes, which look ridiculous if each is typeset in a paragraph of its own. One imagines that even Jill Knuth would accept such usage…

∗This file has version number ?, last revised ?

†University of Cambridge Computer Laboratory, Pembroke St., Cambridge, CB2 3QG, UK (rf@cl.cam.ac.uk)

1.3 Option symbol

This option causes footnotes within the document to be ‘numbered’ with symbols rather than numbers; since the symbol set (derived from command \fnsymbol) is somewhat restricted (it contains only 9 distinct symbols, and does not wrap round), this option only makes sense in documents which have very few footnotes in total, or which invoke option perpage.

1.4 Option bottom

This option forces footnotes to the bottom of the page; this is only noticeably useful in case that \raggedbottom is in effect, when L^{A}TEX would normally set the footnotes a mere \skip\footins distant from the bottom of the text.

1.5 Option marginal

This option adjusts the position of footnote mark relative to the start of the line in which they appear (the the option is incompatible with option para, for obvious reasons).

When this option is in effect, the footnote is set \footnotemargin relative to the left margin of the page; the default setting for \footnotemargin is -0.8em, which means that the footnote mark will be set jutting 0.8em into the margin. If \footnotemargin is a positive length, the footnote mark will be set with its right edge \footnotemargin from the margin. (In the absence of the option,

\footnotemargin is set to 1.8em.)
1.6 Option flushmargin

This option is as option marginal, but sets the footnote marker flush with, but just inside the margin from, the text of the footnote.

1.7 Option norule

This option suppresses the ‘normal’ footnote rule, and advances \skip\footins a bit to compensate

2 Code: Preliminaries

Well — here we go: let’s make the package file:

1 ⟨∗package⟩

Now declare what environment we need:

 2 \NeedsTeXFormat{LaTeX2e}

Sometimes, we need a little verbosity for debugging. This can be achieved by un-commenting this line:

 3 %\setcounter{errorcontextlines}{999}

3 The package’s ‘initial code’

This conditional used to be declared inside pagefoots.sty (I don’t much like it, but…); I’ve renamed it from \ifisdigit and moved it ‘outer’ (damn that mechanism).

 4 %\newif\if@@digit

This command is defined differently in Matt Swift’s newclude package (yet to hit the streets), and we also define it here in a compatible way

 5 \providecommand\protected@writeaux{%
 6 \protected@write\@auxout
 7 }

The counter here is used to detect whether any hacking needs doing to L^{A}TEX’s output routine. After processing options, the value of the counter is < 0 if the bottom option has been exercised, and odd if para option has been exercised.

 8 \def\FN@outputflag{0}

The same job for whether we are to patch \footnote is done with this counter. Its value is 9 if the perpage option has been exercised (the curious value being chosen such that if either of \FN@outputflag or \PP@footflag has been touched, their sum is non-zero.

 9 \def\PP@footflag{0}

Now we define a jollly little macro to advance a macro count (#1) by a given amount (#2).

10 \def\@advance@macro#1#2{\expandafter\@tempcnta#1\relax
11  \advance\@tempcnta#2\relax
12  \edef#1{\the\@tempcnta}}

Finally, we define the length used by the marginal option, and initialise it as if we’ve not had the option.

13 \newdimen\footnotemargin
14 \footnotemargin1.8em\relax

4 The symbol option

This is a declaration that appears in the original L^{A}TEX book. Since it appeared in the old pagefoots.sty (presumably since it goes so naturally with the perpage option), I’ve added this trivial piece of customisation to the package.

15 \DeclareOption{symbol}{\renewcommand\thefootnote{\fnsymbol{footnote}}}

5 The para option

The basis of the code for this option comes from TEXbook, p.398 ff. (“Dirty Tricks”), though it does (of course) avoid redefining \\ which has some other (somewhat significant) uses in L^{A}TEX! The user should be aware of Knuth’s note on the limitations of this method of doing the job: the TEX stack is used four times per footnote, and the stack is limited (see the TEXbook, p.300 ff.). If you have very large numbers of footnotes (in the hundreds), and encounter the error

“! TeX capacity exceeded, sorry (... save size ...)”, you may need to

break your text into smaller sections and compile the separately. Fortunately (say the comments on the original fnpara.sty) this is very easy to do with L^{A}TEX, provided that you reset the footnote counter to make the joins seamless.

First we define a means of hiding \par in a case where we need it within the declaration of the para option

16 \def\FN@unhbox@par#1{\unhbox#1\par}

We need some temporary boxes

17 \let\FN@tempboxa\@tempboxa
18 \newbox\FN@tempboxb
19 \newbox\FN@tempboxc

Define the para option

20 %\typeout{Declaring para}
21 \DeclareOption{para}{%

We will patch the source of L^{A}TEX for this; we don’t do the job here — we simply set a flag for the postamble to do it using patch.tex

Another direct crib from the TEXbook:

22 \newskip\footglue \footglue=1em plus.3em minus.3em

The standard classes set the footnote mark flush with the text of the footnote, but that’s not appropriate for paragraph footnotes, we find.

There’s not much point in patching this code from the original, since the only things it has in common with the original are the footnote mark and the footnote text (which last is the argument).

23 \long\def\@makefntext#1{\@makefnmark\nobreak\hskip.5em\relax#1}

We also need to patch the output routine’s handling of footnotes. Since this isn’t the only instance of this requirement in this package, we simply set a flag for it to be done later.

24 \@advance@macro\FN@outputflag1

We need to record a value for the baseline skip when in footnotes:

25 {\footnotesize \newdimen\footnotebaselineskip
26 \global
27 \footnotebaselineskip=\normalbaselineskip}

Now we derive a fudge factor from the baselineskip we’ve just established^{1}:

28 \@tempdima=\footnotebaselineskip \multiply\@tempdima by 1024
29 \divide \@tempdima by \columnwidth \multiply\@tempdima by 64
30 \xdef\fudgefactor{\strip@pt\@tempdima }
31 %\typeout{Done that - \string\fudgefactor is \fudgefactor}
32 \def\makefootnoteparagraph{\unvbox\footins \makehboxofhboxes
33 \setbox\FN@tempboxa=\hbox{\unhbox\FN@tempboxa \removehboxes}

1We use \strip@pt which is defined for use in the L^{A}TEX 2ε kernel, but not documented: this is a potential problem, but I don’t imagine it will be, since the definition is obviously right

CCCC —now we are ready to set the paragraph:

34  \hsize\columnwidth
35  \@parboxrestore
36  \baselineskip=\footnotebaselineskip
37  \noindent

CCCC —this is where the strut is needed:

38 \rule{\z@}{\footnotesep}%
39 \FN@unhbox@par{\FN@tempboxa}

40 }

41 \def\makehboxofhboxes{\setbox\FN@tempboxa=\hbox{}
42 \loop\setbox\FN@tempboxb=\lastbox \ifhbox\FN@tempboxb
43 \setbox\FN@tempboxa=\hbox{\box\FN@tempboxb\unhbox\FN@tempboxa}\repeat}
44 \def\removehboxes{\setbox\FN@tempboxa=\lastbox
45 \ifhbox\FN@tempboxa{\removehboxes}\unhbox\FN@tempboxa \fi}

46 % 47 }

6 The perpage option

A footnote-numbering modification from Brian T. Schellenberger. Brian’s code is “redistributable by anybody to anybody for any price”, subject to crediting his contribution (which I do herewith: a nice piece of stuff, Brian), and subject to reasonable conditions about distributing modified versions (which include sending a copy back to him).

48 %\typeout{Declaring perpage}
49 \DeclareOption{perpage}{%

The footnote code itself.

\PP@footnote: stuff for handling footnotes numbered per page.

50 \def \PP@footnote
51 {%

Are we in a minipage? If so, there’s no issue, since they’re all done and finished in themselves, and footnotes can’t defer to a new page…

52 \if@minipage\else

Make a \newfoot@mark for the next time

53  \if@filesw
54  \edef \@tempa
55  {%
56  \noexpand\protected@writeaux\relax
57  {%
58  \string\newfoot@mark{\thepage}%
59  {\the\c@footnote}{\noexpand\thepage}%
60  }%
61  }%
62  \@tempa
63  \fi

Now we look at the name that might have been created by a \newfoot@mark when the .aux file was scanned at begin document.

64  \edef \@tempa {ft@\thepage-\the\c@footnote}%
65  \expandafter\ifx\csname\@tempa\endcsname \relax
66  \else

The name is defined: we need to replace the footnote number with what (should have) happened last time

67  \begingroup
68  \global\expandafter\c@footnote
69  \csname\@tempa\endcsname\relax
70  \xdef \@thefnmark {\thefootnote}%
71  \endgroup
72  \fi

Close the conditional (minipage) around the whole thing

73 \fi

74 }

Macros for use while reading the .aux file at \begin{document}: \ft@page is what page we might appear to be on; \ft@foot is the footnote

number last used.

75 \def\ft@page{0}
76 \def\ft@foot{0}

\newfoot@marks appear in the .aux file (unless this is the first time around); each one contains:

• nominal page where the typesetting seemed to be happening at the time the \footnote was typeset, as by \thepage, \immediate at the time the footnote was encountered.

• nominal footnote number on that page.

• actual page it occurs on, as by \thepage deferred to \shipout time.

77 \def \newfoot@mark #1#2#3{%

We don’t even try to play funny games if the actual page isn’t a number:

78 \@ifdigit{#3}{%

Well, it is a number: is it different from the page number we might expect? If \ft@page has got ahead of itself, reset it to zero; if the actual page has gone ahead of \ft@page, we set \ft@page from it and reset \ft@foot

79  \expandafter\ifnum \ft@page > #3\relax
80  \def\ft@page{0}%
81  \else
82  \expandafter\ifnum \ft@page < #3\relax
83  \def\ft@page{#3}
84  \def\ft@foot{0}%
85  \fi\fi}%

if the ‘actual page’ wasn’t numeric, we simply reset \ft@page

86 {\def\ft@page{0}}%

Now advance our ‘expected’ footnote number; if it’s different from what would be typeset without our intervention, create a macro \ft@⟨apparent-page⟩-⟨natural-footnote⟩ that contains the number that in fact needs to be typeset.

87 \@advance@macro\ft@foot1
88 \def\@tempa{#2}%
89 \ifx \@tempa\ft@foot \else
90  \expandafter \xdef \csname ft@#1-#2\endcsname {\ft@foot}%
91 \fi

92 }

Don’t need that definition in the body of the code (though something similar is resurrected at end document).

93 \@onlypreamble\newfoot@mark

A simple bit of code to detect whether the argument it’s offered is a number (at least to the extent of starting with a digit).

Apparent external interface is: \@ifdigit{⟨poss digits⟩}{⟨digit text⟩}{⟨non-digit text⟩}

94 \def\@ifdigit#1{\expandafter\@digithelp\string#1\@digithelp}%

Behold, a piece of horrible code, slowly reducing in number of tokens as I find ways to improve it, which does the guts of \@ifdigit. (The original was a sequence of \ifs comparing to each digit in turn; this one at least is more fun…)

95 \def\@digithelp#1#2\@digithelp{%
96 \ifnum `#1<`0
97  \@triple@expandafter\@secondoftwo
98 \else
99  \ifnum `#1>`9
100  \@triple@expandafter\@secondoftwo
101  \else
102  \@triple@expandafter\@firstoftwo
103  \fi
104 \fi}

Since we use \@triple@expandafter, we had better define it. (I think the kernel could do with it, in fact…)

105 \providecommand\@triple@expandafter{\expandafter
106 \expandafter\expandafter}

\enddoc@newfoot@mark is used to detect channges at the end of the run, when the new .aux file is scanned. It’s mostly the same as \newfoot@mark, except at its last gasp…

107 \def \enddoc@newfoot@mark #1#2#3{%
108 \@ifdigit{#3}{%
109  \expandafter\ifnum \ft@page > #3\relax
110  \def\ft@page{0}%
111  \else
112  \expandafter\ifnum \ft@page < #3\relax
113  \def\ft@page{#3}
114  \def\ft@foot{0}%
115  \fi\fi}%
116 {\def\ft@page{0}}%

If our ‘expected’ footnote number is different from what would be typeset without our intervention, check there was a macro \ft@⟨apparent-page⟩-⟨natural-footnote⟩ containing the number that in fact needs to be typeset.

117 \@advance@macro\ft@foot1
118 \def\@tempa{#2}%
119 \ifx \@tempa\ft@foot \else
120  \expandafter \ifx \csname ft@#1-#2\endcsname \ft@foot
121  \else\@tempswatrue
122  \fi
123 \fi

124 }

At the end of the document, redefine \newfoot@mark to perform a check for footnote labels misbehaving when the .aux file is scanned:

125 \AtEndDocument{%
126 \def\ft@page{0}
127 \def\ft@foot{0}
128 \let\newfoot@mark\enddoc@newfoot@mark

129 }

Mark we’ve patching to do, and arrange that the reset list (of \c@page takes most of the strain…

130 \@advance@macro\PP@footflag9
131 \@addtoreset{footnote}{page}%

132 }

7 The bottom option

All this needs to do is to reset the value of \FN@outputflag to be negative. This is simply by subtracting two from it (which doesn’t affect its oddness … or should that be oddity?)

133 \DeclareOption{bottom}{%
134 \@advance@macro\FN@outputflag{-2}

135 }

8 The marginal option

Again, the processing of the option is pretty trivial:

136 \DeclareOption{marginal}{%
137 \footnotemargin-0.8em\relax

138 }

9 The flushmargin option

Again, the processing of the option is pretty trivial:

139 \DeclareOption{flushmargin}{%
140 \footnotemargin0pt\relax

141 }

10 The norule option

Pretty simple too…

142 \DeclareOption{norule}{%
143 \renewcommand\footnoterule{}%
144 \advance\skip\footins 4\p@\@plus2\p@\relax

145 }

11 The start of the endgame

Exercise the options that the user has requested…

146 \ProcessOptions

12 The output routine hacks

Now; do we need to mess about with the output routine? If either fnpara or bottom has been invoked, we do. In order to do this job, we use David Kastrup’s

 patch.tex:
147 \expandafter\@tempcntb\PP@footflag\relax
148 \@advance@macro\FN@outputflag\@tempcntb\relax
149 % We rely on \@advance@macro to set \@tempcnta for us
150 \ifnum\@tempcnta=0
151 \else
152 \advance\@tempcnta-\@tempcntb\relax

… so we’ve patching to do.

Since patch won’t let us compare braces (for obvious reasons), but more significantly won’t allow us use of \bgroup or \egroup, we need private copies of the brace characters for one of our patches:

153 \let\FN@obrace{
154 \let\FN@cbrace} % this has the merit (at least) of satisfying emacs...

Now we get the patcher:

155 \input{patch}

Now we need to do our patches and then to get out of the way.

156 \ifnum\FN@outputflag<0

Option bottom was requested.

In this case, we’ve to fix the size of \vbox that \@makecol uses if there’s a footnote present on the page, and then stick a \vfill in it:

157 \gpatch\@makecol{}{\vbox\FN@obrace\boxmaxdepth\@maxdepth
158  \unvbox\@cclv\vskip\skip\footins
159  {\vbox to\@colht\FN@obrace\boxmaxdepth\@maxdepth
160  \unvbox\@cclv\vfill\relax\vskip\skip\footins}}

That completes bottom

161 \fi

Similarly, if we’re doing paragraph footnotes, the actual grubby end of the work is done in the output routine; the need for this is signalled by the flag being odd.

162 \ifodd\@tempcnta

The output routine part of it simply makes a box out of the paragraph of footnotes, and then stuffing the contents of the box into that which is going to be

 \shipped out.
163 \gpatch\@makecol{}{\normalcolor\footnoterule\unvbox\footins
164  {\normalcolor\footnoterule
165  \global\setbox\FN@tempboxc\vbox
166  {\makefootnoteparagraph}%
167  \unvbox\FN@tempboxc}}

Paragraph footnotes also require that we patch \@footnotetext, so we do this here, too:

168 \gpatch\@footnotetext#1{{#1}}{\@makefntext\FN@obrace
169  \rule\z@\footnotesep
170  \ignorespaces#1%
171  \@finalstrut\strutbox\FN@cbrace

172 {%

We set the paragraph in an \hbox and apply the fudge factor here:

173  \setbox\FN@tempboxa=\hbox\FN@obrace

This needs a parameter; the rule should be moved to the beginning of the footnote paragraph, but the \ignorespaces should be left here.

174  \@makefntext\FN@obrace
175  \ignorespaces#1\strut

We insert a penalty^{2} here to help line breaking in the footnote paragraph; the value is taken from the TEXbook.

176  \penalty-10\relax
177  \hskip\footglue
178  \FN@cbrace% end of \@makefntext parameter
179  \FN@cbrace% end of \hbox
180  \dp\FN@tempboxa=0pt\ht\FN@tempboxa=\fudgefactor\wd\FN@tempboxa
181  \box\FN@tempboxa

182 }}

183 \fi

Finally, do we need to patch \footnote? This is signalled by setting \PP@footflag to a non-zero value, and we set \@tempcntb to that before the last patching session:

184 \ifnum\@tempcntb=0
185 \else
186 \gpatch\footnote{}% Note that \footnote doesn't have arguments,
187  % whatever it says in the book...
188  {\@footnotemark{\PP@footnote\@footnotemark}}
189 \gpatch\footnotemark{}{\@footnotemark{\PP@footnote\@footnotemark}}
190 \fi

2Well, a negative penalty — perhaps, more of an encouragement…

And lo!, we are done with patching

191 \endpatch

All of this occurred conditionally on the values of \FN@outputflag and \PP@footflag, so we now close that conditional.

192 \fi

Finally, if we’re not doing paragraph footnotes, we redefine \@makefntext to take account of the value of \footnotemargin; the actual test is that the value of \@tempcnta should be even.

193 \ifodd\@tempcnta\else
194 \def\@makefntext#1{%
195  \parindent1em
196  \noindent
197  \ifdim\footnotemargin>0pt
198  \hbox to 1.8em{\hss\@makefnmark}%
199  \else
200  \ifdim\footnotemargin=0pt
201  \llap{$^{\@thefnmark}$}%
202  \else
203  \llap{\hbox to-\footnotemargin{$^{\@thefnmark}$\hss}}%
204  \fi
205  \fi
206  #1}
207 \fi

208 ⟨/package⟩