You are on page 1of 26

An environment for multicolumn output∗†

Frank Mittelbach
Email: see top of the source file
Printed January 24, 2000

Abstract
This article describes the use and the implementation of the multicols environment. This environment
allows switching between one and multicolumn format on the same page. Footnotes are handled correctly
(for the most part), but will be placed at the bottom of the page and not under each column. LATEX’s float
mechanism, however, is partly disabled in the current implementation. At the moment only page-wide
floats (i.e., star-forms) can be used within the scope of the environment.

Preface to version 1.5


This new release contains two the resulting columns and rejects code documentation but the work
major changes: multicols will solutions that are larger than a on LATEX 2ε kept me too busy to
now support up to 10 columns certain treshold. do a proper job. This will hope-
and two more tuning possibilities At the same time multicols fully be corrected in the near fu-
have been added to the balanc- has been upgraded to run under ture.
ing routine. The balancing rou- LATEX 2ε .
tine now checks the badness of I apologise for the state of the

1 Introduction
Switching between two column 10 #2, pp. 245–273) I thought ment which takes care of foot-
and one column layout is pos- that it would be nice to place notes, floats etc., was a harder
sible in LATEX, but every use the index on the same page as task. It took me a whole week-
of \twocolumn or \onecolumn the bibliography. And balanc- end1 to get together the few lines
starts a new page. More- ing the last page would not only of code below and there is still a
over, the last page of two look better, it also would save good chance that I missed some-
column output isn’t balanced space; provided of course that thing after all.
and this often results in an it is also possible to start the Try it and, hopefully, enjoy it;
empty, or nearly empty, right col- next article on the same page. and please direct bug reports and
umn. When I started to write Rewriting the index environment suggestions back to Mainz.
macros for doc.sty (see “The was comparatively easy, but the
doc–Option”, TUGboat volume next goal, designing an environ-

∗ This file has version number v1.5w, last revised 1999/10/21.


† Note: This package is released under terms which affect its use in commercial applications. Please see the details at the
top of the source file.
1 I started with the algorithm given in the T Xbook on page 417. Without this help a weekend would not have been enough.
E

1
2 The User Interface
To use the environment one sim- long (or short) the value of 2.1 Balancing columns
ply says \premulticols might need ad-
Besides the previously mentioned
justing to prevent a bad page
\begin{multicols}{hnumber i} parameters, some others are pro-
break. We therefore provide a
hmulticolumn texti vided to influence the layout of
third argument which can be
\end{multicols} the columns generated.
used to overwrite the default
where hnumber i is the required value of \premulticols just for Paragraphing in TEX is con-
number of columns and hmulti- this occasion. So if you want trolled by several parameters.
column texti may contain arbi- to combine some longer single One of the most important is
trary LATEX commands, except column text with a multicols en- called \tolerance: this controls
that floats and marginpars are vironment you could write the allowed ‘looseness’ (i.e. the
not allowed in the current imple- amount of blank space between
mentation2 . words). Its default value is 200
As its first action, the multicols (the LATEX \fussy) which is too
\begin{multicols}{3} small for narrow columns. On the
environment measures the cur- [\section{Index}
rent page to determine whether other hand the \sloppy declara-
This index contains ...]
there is enough room for some [6cm]
tion (which sets \tolerance to
portion of multicolumn out- ... 10000 = ∞) is too large, allow-
put. This is controlled by the ing really bad spacing.4
hdimeni variable \premulticols We therefore use a
which can be changed by the The space between columns is \multicoltolerance parameter
user with ordinary LATEX com- controlled by the length param- for the \tolerance value inside
mands. If the space is less than eter \columnsep. The width the multicols environment. Its
\premulticols, a new page is for the individual columns is default value is 9999 which
started. Otherwise, a \vskip of automatically calculated from is less than infinity but ‘bad’
\multicolsep is added.3 this parameter and the current enough for most paragraphs
When the end of the mul- \linewidth. In this article a in a multicolumn environment.
ticols environment is encoun- value of 18.0pt was used. Changing its value should be
tered, an analogous mechanism done outside the multicols envi-
Separation of columns with ronment. Since \tolerance is
is employed, but now we test vertical rules is achieved
whether there is a space larger set to \multicoltolerance at
by setting the parameter the beginning of every multicols
than \postmulticols available. \columnseprule to some posi-
Again we add \multicolsep or environment one can locally
tive value. In this article a value overwrite this default by as-
start a new page. of .4pt was used.
It is often convenient to spread signing \tolerance = hdesired
some text over all columns, just Since narrow columns tend valuei. There also exists a
before the multicolumn output, to need adjustments in in- \multicolpretolerance pa-
without any page break in be- terline spacing we also pro- rameter holding the value
tween. To achieve this the multi- vide a hskipi parameter called for \pretolerance within a
cols environment has an optional \multicolbaselineskip which multicols environment. Both
second argument which can be is added to the \baselineskip parameters are usually used only
used for this purpose. For exam- parameter inside the multicols en- by package designers.
ple, the text you are now reading vironment. Please use this pa- Generation of multicolumn
was started with rameter with care or leave it output can be divided into two
alone; it is intended only for parts. In the first part we are
\begin{multicols}{3} package file designers since even collecting material for a page,
[\section{The User
small changes might produce to- shipping it out, collecting mate-
Interface}] ...
tally unexpected changes to your rial for the next page, and so on.
If such text is unusually document. As a second step, balancing will
2 This
is dictated by lack of time. To implement floats one has to reimplement the whole LATEX output routine.
3 Actually
the added space may be less because we use \addvspace (see the LATEX manual for further information about this
command).
4 Look at the next paragraph, it was set with the \sloppy declaration.

2
be done when the end of the mul- Additionally you can set lot of white space.
ticols environment is reached. In another counter, the ‘unbal- However, if the setting is too
the first step TEX might consider ance’ counter, to some positive low, the algorithm may not find
more material whilst finding the hnumber i. This will make all but any acceptable solution at all and
final columns than it actually the right-most column hnumber i will then finally choose the ex-
use when shipping out the page. of lines longer than they would treme solution of placing all text
This might cause a problem if normally have been. ‘Lines’ in into the first column.
a footnote is encountered in the this context refer to normal text Often, when colunms are bal-
part of the input considered, but lines (i.e. one \baselineskip anced, it is impossible to find a
not used, on the current page. In apart); thus, if your columns solution that distributes the text
this case the footnote might show contain displays, for example, evenly over all columns. If that
up on the current page, while the you may need a higher hnumber i is the case the last column usu-
footnotemark corresponding to to shift something from one col- ally has less text than the oth-
this footnote might be set on the umn into another. ers. In the earlier releases this
next one.5 Therefore the multi- Unlike ‘collectmore,’ the ‘unbal- text was stretched to produce a
cols environment gives a warning ance’ counter is reset to zero at column with the same height as
message6 whenever it is unable the end of the environment so it all others, sometimes resulting in
to use all the material considered only applies to one multicols en- really ugly looking columns.
so far. vironment. In the new release this stretch-
The two methods may be com- ing is only done if the badness
bined but I suggest using these of the final column is not larger
If you don’t use footnotes too than the value of the counter fi-
features only when fine tuning
often the chances of something nalcolumnbadness. The default
important publications.
actually going wrong are very setting is 9999, thus preventing
slim, but if this happens you can Two more general tuning pos-
sibilities were added with ver- the stretching for all columns
help TEX by using a \pagebreak that TEX would consider in-
command in the final document. sion 1.5. TEX allows to mea-
sure the badness of a column in finitely bad. In that case the fi-
Another way to influence the be- nal column is allowed to run short
havior of TEX in this respect terms of an integer value, where
0 means optimal and any higher which gives a much better result.
is given by the counter variable And there are two more
‘collectmore’. If you use the value means a certain amount
of extra white space. 10000 is parameters of some exper-
\setcounter declaration to set imental nature, one called
this counter to hnumber i, TEX considered to be infinitely bad
(TEX does not distinguish any \multicolovershoot the other
will consider hnumber i more (or \multicolundershoot. They
less) lines before making its fi- further). In addition the special
value 100000 means overfull (i.e., control the amount of space a
nal decision. So a value of −1 column is allowed to be “too full”
may solve all your problems at the column contains more text
than could possibly fit into it). or “too short” without affecting
the cost of slightly less optimal the column badness. They are
columns. The new release now measures
every generated column and ig- set to 2pt by default.
nores solutions where at least
In the second step (balanc- one column has a badness be- 2.2 Not balancing the
ing columns) we have other bells ing larger than the value of the columns
and whistles. First of all you counter columnbadness. The de-
can say \raggedcolumns if you fault value for this counter is Although this package was writ-
don’t want the bottom lines to 10000, thus TEX will accept all ten to solve the problem of bal-
be aligned. The default is solutions except those being over- ancing columns, I got repeated
\flushcolumns, so TEX will nor- full. By setting the counter to a requests to provide a version
mally try to make both the smaller value you can force the where all white space is auto-
top and bottom baselines of all algorithm to search for solutions matically placed in the last col-
columns align. that do not have columns with a umn or columns. Since version
5 The reason behind this behavior is the asynchronous character of the T X page builder. However, this could be avoided
E
by defining very complicated output routines which don’t use TEX primitives like \insert but do everything by hand. This is
clearly beyond the scope of a weekend problem.
6 This message will be generated even if there are no footnotes in this part of the text.

3
v1.5q this now exists: if you h doesn’t work because the first Floats and marginpars not
use multicols* instead of the possible place is the top of the allowed inside ‘multicols’
usual environment the columns next page. One should also note, environment!
on the last page are not balanced. that this means that their place-
Of course, this environment only ment behavior is determined by This message appears if you try
works on top-level, e.g., inside a the values of \topfraction, etc. to use the \marginpar com-
box one has to balance to deter- rather then by \dbl.... mand or an unstared version of
mine a column height in absense the figure or table environment.
of a fixed value. Such floats will disappear!
2.5 Warnings
2.3 Manually breaking Under certain circumstances the 2.6 Tracing the output
columns use of the multicols environment
may result in some warnings from To understand the reasoning be-
Another request often voiced TEX or LATEX. Here is a list of the hind the decisions TEX makes
was: “How to I tell LATEX that important ones and the possible when processing a multicols envi-
it should break the first column cause: ronment, a tracing mechanism is
after this particular line?”. The provided. If you set the counter
\pagebreak command (which Underfull \hbox (badness ‘multicols’ to a positive hnumber i
works with the two-column op- ...) you then will get some tracing in-
tion of LATEX) is of no use here formation on the terminal and in
As the columns are often very
since it would end the collection the transcript file:
narrow TEX wasn’t able to find
phase of multicols and thus all
a good way to break the para-
columns on that page. So with
graph. Underfull denotes a loose hnumber i = 1. TEX will now
version 1.5u the \columnbreak
line but as long the badness val- tell you, whenever it enters
command was added. If used
ues is below 10000 the result is or leaves a multicols environ-
within a paragraph it marks the
probably acceptable. ment, the number of columns it
end of the current line as the de-
is working on and its decision
sired breakpoint. You can ob- Underfull \vbox ... while about starting a new page be-
serve its effect on the previous \output is active fore or after the environment.
page where three lines of text
have been artifically forced into If a column contains an charac-
the second column (resulting in ter with an unusual depth, for hnumber i = 2. In this case
some white space between para- example a ‘(’, in the bottom line you also get information from
graphs in the first column). then this message may show up. the balancing routine: the
It usually has no significance as heights tried for the left and
long as the value is not more right-most columns, informa-
2.4 Floats inside a mul- than a few points. tion about shrinking if the
ticols environment \raggedcolumns declaration is
LaTeX Warning: I moved in force and the value of the
Within the multicols environment
some lines to the next ‘unbalance’ counter if positive.
the usual star float commands
page
are available but their function is
somewhat different as in the two- As mentioned above, multicols hnumber i = 3. Setting
column mode of standard LATEX. sometimes screws up the foot- hnumber i to this value will ad-
Stared floats, e.g., figure*, de- note numbering. As a pre- ditionally trace the mark han-
note page wide floats that are caution, whenever there is a dling algorithm. It will show
handled in a similar fashion as footnote on a page that where what marks are found, what
normal floats outside the multi- multicols had to leave a re- marks are considered, etc. To
cols environment. However, they mainder for the following page fully understand this informa-
will never show up on the page this warning appears. Check tion you will probably have to
where they are encountered. In the footnote numbering on this read carefully trough the imple-
other words, one can influence page. If it turns out that it mentation.
their placement by specifying a is wrong you have to manually
combination of t, b, and/or p break the page using \newpage hnumber i ≥ 4. Setting
in their optional argument, but or \pagebreak[..]. hnumber i to such a high value

4
will additionally place an on the previous page from the more debugging code for mark
\hrule into your output, sep- rest. Clearly this setting should handling.
arating the part of text which not be used for the final out-
had already been considered put. It will also activate even

3 Prefaces to older versions


3.1 Preface to version 1.4
Beside fixing some bugs as men- ants will produce a box with the a single macro which is called
tioned in the multicol.bug file this balanced material in it, so that \balance@columns. This means
new release enhances the multi- they can not be broken across that one can easily try different
cols environment by allowing for pages or columns. balancing routines by rewriting
balancing in arbitrary contexts. Additionally I rewrote the al- this macro. The interface for it
It is now, for example, possible gorithm for balancing so that it is explained in table 1. There
to balance text within a multicols will now produce slightly better are several improvements possi-
or a minipage as shown in 2 where results. ble, one can think of integrating
a multicols environment within a I updated the source documen- the \badness function of TEX3,
quote environment was used. It tation but like to apologize in ad- define a faster algorithm for find-
is now even possible to nest mul- vance for some ‘left over’ parts ing the right column height, etc.
ticols environments. that slipped through the revision. If somebody thinks he/she has an
The only restriction to such A note to people who like enhancement I would be pleased
inner multicols environments to improve the balancing algo- to learn about it. But please obey
(nested, or within TEX’s internal rithm of multicols: The balanc- the copyright notice and don’t
vertical mode) is that such vari- ing routine in now placed into change multicol.dtx directly!

3.2 Preface to version 1.2


After the article about the mul- \tolerance (or \pretolerance of course one has have much more
ticols environment was published in the first pass). If this isn’t pos- experience with the new possi-
in TUGboat 10#3, I got numer- sible, then, as a last resort, TEX bilities to achieve the maximum
ous requests for these macros. will produce overfull boxes. All quality.
However, I also got a changed those (and only those) possible
Version 1.1a had a nice ‘fea-
version of my style file, together break points will be considered
ture’: the penalty for using
with a letter asking me if I would and finally the sequence which re-
the forbidden floats was their
include the changes to get better sults in the fewest demerits will
ultimate removal from LATEXs
paragraphing results in the case be chosen. This means that a
\@freelist so that after a few
of narrow lines. The main dif- value of −1000 for \adjdemerits
\marginpars inside the multi-
ferences to my original style op- instructs TEX to prefer visibly in-
cols environment floats where dis-
tion were additional parameters compatible lines instead of pro-
abled forever. (Thanks to Chris
(like \multicoladjdemerits to ducing better line breaks.
Rowley for pointing this out.) I
be used for \adjdemerits, etc.)
However, with TEX 3.0 it is removed this misbehaviour and
which would influence the line
possible to get decent line breaks at the same time decided to al-
breaking algorithm.
even in small columns by setting low at least floats spanning all
But actually resetting such pa- \emergencystretch to an appro- columns, e.g., generated by the
rameters to zero or even worse to priate value. I implemented a figure* environment. You can
a negative value won’t give bet- version which is capable of run- see the new functionality in ta-
ter line breaks inside the multicols ning both in the old and the new ble 2 which was inserted at this
environment. TEXs line break- TEX (actually it will simply ig- very point. However single col-
ing algorithm will only look at nore the new feature if it is not umn floats are still forbidden and
those possible line breaks which available). The calculation of I don’t think I will have time to
can be reached without a badness \emergencystretch is probably tackle this problem in the near fu-
higher than the current value of incorrect. I made a few tests but ture. As an advice for all who

5
The macro \balance@columns that contains ister \mult@gfirstbox, the next in register
the code for balancing gathered material is a \mult@firstbox + 2, . . . , only the last one
macro without parameters. It assumes that as an exception in register \mult@grightbox.
the material for balancing is stored in the box Furthermore it has to set up two the macros
\mult@box which is a \vbox. It also “knows” \kept@firstmark and \kept@botmark to hold
about all parameters set up by the multicols the values for the first and bottom mark as
environment, like \col@number, etc. It can found in the individual columns. There are
also assume that \@colroom is the still avail- some helper functions defined in section 5.1
able space on the current page. which may be used for this. Getting the marks
When it finishes it must return the individ- right “by hand” is non-trivial and it may pay
ual columns in boxes suitable for further pro- off to first take a look at the documentation
cessing with \page@sofar. This means that and implementation of \balance@columns be-
the left column should be stored in box reg- low before trying anew.

Table 1: Interface description for \balance@columns

\setemergencystretch: This is a hook for people 4pt × #1, i.e. the \hsize isn’t used at all. But
who like to play around. It is supposed to set the maybe there are better formulae.
\emergencystretch hdimeni register provided in \set@floatcmds: This is the hook for the experts
the new TEX 3.0. The first argument is the num- who like to implement a full float mechanism for
ber of columns and the second one is the current the multicols environment. The @ in the name
\hsize. At the moment the default definition is should signal that this might not be easy.

Table 2: The new commands of multicol.sty version 1.2. Both commands might be removed if good solutions
to these open problems are found. I hope that these commands will prevent that nearly identical style files
derived from this one are floating around.

want to try: wait for TEX 3.0. edge of TEXs capabilities, really changed, I only added documen-
It has a few features which will perfect solutions would need a tation at places where new code
make life much easier in multi- different approach than it was was added.
column surroundings. Neverthe- done in TEXs page builder.
less we are working here at the The text below is nearly un-

4 The Implementation
We are now switching to two-column output to show the abilities of this environment (and bad layout
decisions).

4.1 The documentation driver file


The next bit of code contains the documentation be done before the doc package is loaded, since doc
driver file for TEX, i.e., the file that will produce the otherwise requires multicols without any options.
documentation you are currently reading. It will be 3 \usepackage{multicol}[1999/05/25]
extracted from this file by the docstrip program. 4 \usepackage{doc}
Since this is the first code in this file one can produce
the documentation simply by running LATEX on the First we set up the page layout suitable for this ar-
.dtx file. ticle.
1 h∗driveri 5 \setlength{\textwidth}{39pc}
2 \documentclass{ltxdoc} 6 \setlength{\textheight}{54pc}
7 \setlength{\parindent}{1em}
We use the balancingshow option when loading 8 \setlength{\parskip}{0pt plus 1pt}
multicols so that full tracing is produced. This has to 9 \setlength{\oddsidemargin}{0pc}

6
10 \setlength{\marginparwidth}{0pc} 19 \let\DescribeMacro\SpecialUsageIndex
11 \setlength{\topmargin}{-2.5pc} 20 \let\DescribeEnv\SpecialEnvIndex
12 \setlength{\headsep}{20pt} 21 \renewcommand\PrintMacroName[1]{}
13 \setlength{\columnsep}{1.5pc} 22 \CodelineIndex
23 %\DisableCrossrefs % Partial index
We want a rule between columns.
24 \RecordChanges % Change log
14 \setlength\columnseprule{.4pt}
We also want to ensure that a new multicols envi- Line numbers are very small for this article.
ronment finds enough space at the bottom of the
page. 25 \renewcommand{\theCodelineNo}
26 {\scriptsize\rm\arabic{CodelineNo}}
15 \setlength\premulticols{6\baselineskip} 27 \settowidth\MacroIndent{\scriptsize\rm 00\ }
When balancing columns we disregard solutions that 28
are too bad. Also, if the last column is too bad we 29 \begin{document}
typeset it without stretch. 30 \typeout
16 \setcounter{columnbadness}{7000} 31 {****************************************
32 ^^J* Expect some Under- and overfull boxes.
17 \setcounter{finalcolumnbadness}{7000}
33 ^^J****************************************}
The index is supposed to come out in four columns. 34 \DocInput{multicol.dtx}
And we don’t show macro names in the margin. 35 \end{document}
18 \setcounter{IndexColumns}{4} 36 h/driveri

4.2 Identification and option processing

We start by identifying the package. Since it makes 43 with the twocolumn option}}
use of features only available in LATEX 2ε we ensure
Tracing is done using a counter. However it is also
that this format is available. (Now this is done ear-
possible to invoke the tracing using the options de-
lier in the file.)
clared below.
37 h∗packagei
38 % \NeedsTeXFormat{LaTeX2e} 44 \newcount\c@tracingmulticols
39 % \ProvidesPackage{multicol}[..../../.. 45 \DeclareOption{errorshow}
40 % v... multicolum formatting] 46 {\c@tracingmulticols\z@}
47 \DeclareOption{infoshow}
Next we declare options supported by multicols.
48 {\c@tracingmulticols\@ne}
Twocolumn mode and multicols do not work to-
49 \DeclareOption{balancingshow}
gether so we warn about possible problems. How-
50 {\c@tracingmulticols\tw@}
ever, since you can revert to \onecolumn in which 51 \DeclareOption{markshow}
case multicols does work, we don’t make this an er- 52 {\c@tracingmulticols\thr@@}
ror. 53 \DeclareOption{debugshow}
41 \DeclareOption{twocolumn} 54 {\c@tracingmulticols5\relax}
42 {\PackageWarning{multicol}{May not work 55 \ProcessOptions

4.3 Starting and Ending the multicols Environment

As mentioned before, the multicols environment has columns at the moment.


one mandatory argument (the number of columns) 57 \ifnum\col@number<\tw@
and up to two optional ones. We start by reading 58 \PackageWarning{multicol}%
the number of columns into the \col@number regis- 59 {Using ‘\number\col@number’
ter. 60 columns doesn’t seem a good idea.^^J
61 I therefore use two columns instead}%
56 \def\multicols#1{\col@number#1\relax 62 \col@number\tw@ \fi

If the user forgot the argument, TEX will complain We have only enough box registers for ten columns,
about a missing number at this point. The error so we need to check that the user hasn’t asked for
recovery mechanism will then use zero, which isn’t more.
a good choice in this case. So we should now test 63 \ifnum\col@number>10
whether everything is okay. The minimum is two 64 \PackageError{multicol}%

7
65 {Too many columns}% the second case we need to process the current mul-
66 {Current implementation doesn’t ticols also in “boxed mode” and so change the switch
67 support more than 10 columns.% accordingly.
68 \MessageBreak
82 \else
69 I therefore use 10 columns instead}%
83 \ifnum \doublecol@number>\z@
70 \col@number10 \fi
84 \@boxedmulticolstrue
Within the environment we need a special version 85 \fi
of the kernel \@footnotetext command since the 86 \fi
original sets the the \hsize to \columnwidth which Then we look to see if statistics are requested:
is not correct in the multicol environment. Here
87 \mult@info\z@
\columnwidth refers to the width of the individual
88 {Starting environment with
column and the footnote should be in \textwidth. 89 \the\col@number\space columns%
Since \@footnotetext has a different definition in-
side a minipage environment we do not redefine it In boxed mode we add some more info.
directly. Instead we locally set \columnwidth to 90 \if@boxedmulticols\MessageBreak
\textwidth and call the original (current) defini- 91 (boxed mode)\fi
tion stored in \orig@footnotetext. 92 }%
71 \let\orig@footnotetext\@footnotetext Then we measure the current page to see whether a
72 \long\def\@footnotetext##1{\begingroup useful portion of the multicolumn environment can
73 \columnwidth\textwidth be typeset. This routine might start a new page.
74 \orig@footnotetext{##1}\endgroup}%
93 \enough@room{#2}%
Now we can safely look for the optional arguments. Now we output the first argument and produce ver-
75 \@ifnextchar[\mult@cols{\mult@cols[]}} tical space above the columns. (Note that this ar-
gument corresponds to the first optional argument
The \mult@cols macro grabs the first optional ar- of the multicols environment.) For many releases
gument (if any) and looks for the second one. this argument was typeset in a group to get a sim-
76 \def\mult@cols[#1]{\@ifnextchar[% ilar effect as \twocolumn[..] where the argument
This argument should be a hdimeni denoting the is also implicitly surrounded by braces. However,
minimum free space needed on the current page to this conflicts with local changes done by things like
start the environment. If the user didn’t supply one, sectioning commands (which account for the major-
we use \premulticols as a default. ity of commands used in that argument) messing up
vertical spacing etc. later in the document so that
77 {\mult@@cols{#1}}%
from version v1.5q on this argument is again typeset
78 {\mult@@cols{#1}[\premulticols]}}
at the outer level.
After removing all arguments from the input we are 94 #1\par\addvspace\multicolsep
able to start with \mult@@cols. We start a new grouping level to hide all subsequent
79 \def\mult@@cols#1[#2]{% changes (done in \prepare@multicols for exam-
ple).
First thing we do is to decide whether or not this is
an unbounded multicols environment, i.e. one that 95 \begingroup
may split across pages, or one that has to be typeset 96 \prepare@multicols
into a box. If we are in TEX’s “inner” mode (e.g., If we are in boxed mode we now open a box to type-
inside a box already) then we have a boxed version set all material from the multicols body into it, oth-
of multicols therefore we set the @boxedmulticols erwise we simply go ahead.
switch to true. The multicols should start in vertical 97 \if@boxedmulticols
mode. If we are not already there we now force it 98 \setbox\mult@box\vbox\bgroup
with \par since otherwise the test for “inner” mode
We may have to reset some parameters at this point,
wouldn’t show if we are in a box.
perhaps \@parboxrestore would be the right action
80 \par but I leave it for the moment.
81 \ifinner \@boxedmulticolstrue
99 \fi
Otherwise we check \doublecol@number. This
counter is zero outside a multicols environment but We finish by suppressing initial spaces.
positive inside (this happens a little later on). In 100 \ignorespaces}

8
Here is the switch and the box for “boxed” multicols 111 \mult@info\z@
code. 112 {Current page:\MessageBreak
101 \newif\if@boxedmulticols 113 height=%
102 \@boxedmulticolsfalse
114 \the\pagegoal: used \the\pagetotal
103 \newbox\mult@box
115 \space -> free=\the\page@free
116 \MessageBreak
The \enough@room macro used above isn’t perfect 117 needed \the\@tempskipa
118 \space(for #1)}%
but works reasonably well in this context. We mea-
sure the free space on the current page by subtract- Our last action is to force a page break if there isn’t
ing \pagetotal from \pagegoal. This isn’t en- enough room left.
tirely correct since it doesn’t take the ‘shrinking’ 119 \ifdim \page@free <#1\newpage \fi
(i.e. \pageshrink) into account. The ‘recent con- 120 \fi}
tribution list’ might be nonempty so we start with
\par and an explicit \penalty.7 Actually, we use When preparing for multicolumn output several
\addpenalty to ensure that a following \addvspace things must be done.
will ‘see’ the vertical space that might be present. 121 \def\prepare@multicols{%
The use of \addpenalty will have the effect that all We start saving the current \@totalleftmargin
items from the recent contributions will be moved and then resetting the \parshape in case we are
to the main vertical list and the \pagetotal value inside some list environment. The correct inden-
will be updated correctly. However, the penalty will tation for the multicols environment in such a case
be placed in front of any dangling glue item with will be produced by moving the result to the right
the result that the main vertical list may already by \multicol@leftmargin later on. If we would
be overfull even if TEX is not invoking the output use the value of of \@totalleftmargin directly then
routine. lists inside the multicols environment could cause a
104 \def\enough@room#1{% shift of the output.
Measuring makes only sense when we are not in 122 \multicol@leftmargin\@totalleftmargin
“boxed mode” so the routine does nothing if the 123 \@totalleftmargin\z@
switch is true. 124 \parshape\z@
105 \if@boxedmulticols\else We also set the register \doublecol@number for
106 \par later use. This register should contain 2 ×
To empty the contribution list the first release con- \col@number. This is also an indicator that we are
tained a penalty zero but this had the result that within a multicols environment as mentioned above.
\addvspace couldn’t detect preceding glue. So this
was changed to \addpenalty. But this turned out 125 \doublecol@number\col@number
to be not enough as \addpenalty will not add a 126 \multiply\doublecol@number\tw@
penalty when @nobreak is true. Therefore we force 127 \advance\doublecol@number\mult@rightbox
this switch locally to false. As a result there may 128 \if@boxedmulticols
be a break between preceding text and the start of 129 \let\l@kept@firstmark\kept@firstmark
a multicols environment, but this seems acceptable 130 \let\l@kept@botmark\kept@botmark
since there is the optional argument for exactly this 131 \global\let\kept@firstmark\@empty
reason. 132 \global\let\kept@botmark\@empty
133 \else
107 \bgroup\@nobreakfalse\addpenalty\z@\egroup
108 \page@free \pagegoal We add an empty box to the main vertical list to
109 \advance \page@free -\pagetotal ensure that we catch any insertions (held over or in-
To be able to output the value we need to assign it serted at the top of the page). Otherwise it might
to a register first since it might be a register (de- happen that the \eject is discarded without calling
fault) in which case we need to use \the or it might the output routine. Inside the output routine we re-
be a plain value in which case \the would be wrong. move this box again. Again this code applies only
if we are on the main vertical list and not within
110 \@tempskipa#1\relax a box. However, it is not enough to turn off inter-
line spacing, we also have to clear \topskip before
Now we test whether tracing information is required:
adding this box, since \topskip is always inserted
7 See the documentation of \endmulticols for further details.

9
before the first box on a page which would leave us can’t use \topmark because this register will not al-
with an extra space of \topskip if multicols start on ways contain what its name promises because LATEX
a fresh sheet. sometimes calls the output routine for float manage-
134 \nointerlineskip {\topskip\z@\null}% ment.8 Therefore we use the second best solution by
135 \output{% initializing it with \firstmark. In fact, for our pur-
136 \global\setbox\partial@page\vbox pose this doesn’t matter as we use \kept@topmark
137 {% only to initialize \firstmark and \botmark of a fol-
Now we have to make sure that we catch one spe- lowing page if we don’t find any marks on the current
cial situation which may result in loss of text! If one.
the user has a huge amount of vertical material 162 \global\let\kept@topmark\firstmark
within the first optional argument that is larger then 163 }\eject
\premulticols and we are near the bottom of the
The next thing to do is to assign a new value to
page then it can happen that not the \eject is
\vsize. LATEX maintains the free room on the page
triggering this special output routine but rather the
(i.e. the page height without the space for already
overfull main vertical list. In that case we get an-
contributed floats) in the register \@colroom. We
other breakpoint through the \eject penalty. As
must subtract the height of \partial@page to put
a result this special output routine would be called
the actual free room into this variable.
twice and the contents of \partial@page, i.e. the
material before the multicols environment gets lost. 164 \advance\@colroom-\ht\partial@page
There are several solutions to avoid this problem, Then we have to calulate the \vsize value to use
but for now we will simply detect this and inform the during column assembly. \set@mult@vsize takes
user that he/she has to enlarge the \premulticols an argument which allows to make the setting local
by using a suitable value for the second argument. (\relax) or global (\global). The latter variant is
138 h∗checki used inside the output routine below. At this point
139 \ifvoid\partial@page\else here we have to make a local change to \vsize be-
140 \PackageError{multicol}% cause we want to get the original value for \vsize
141 {Error saving partial page}% restored in case this multicols environment ends on
142 {The part of the page before the same page where it has started.
143 the multicols environment was
144 nearly full with^^Jthe result 165 \set@mult@vsize\relax
145 that starting the environment Now we switch to a new \output routine which will
146 will produce an overfull be used to put the gathered column material to-
147 page. Some^^Jtext may be lost! gether.
148 Please increase \premulticols
149 either generally or for this% 166 \output{\multi@column@out}%
150 ^^Jenvironment by specifying a Finally we handle the footnote insertions. We have
151 suitable value in the second to multiply the magnification factor and the extra
152 optional argument to^^Jthe skip by the number of columns since each footnote
153 multicols environment.} reduces the space for every column (remember that
154 \unvbox\partial@page
we have pagewide footnotes). If, on the other hand,
155 \box\last@line
156 \fi
footnotes are typeset at the very end of the docu-
157 h/checki ment, our scheme still works since \count\footins
158 \unvbox\@cclv is zero then, so it will not change. To allow even
159 \global\setbox\last@line\lastbox further customization the setting of the \footins
160 }% parameters is done in a separate macro.
Finally we need to record the marks that are present 167 \init@mult@footins
within the \partial@page so that we can construct For the same reason (pagewide footnotes), the
correct first and bottom marks later on. This is done hdimeni register controlling the maximum space
by the following code. used for footnotes isn’t changed. Having done this,
161 \prep@keptmarks we must reinsert all the footnotes which are already
Finally we have to initialize \kept@topmark which present (i.e. those encountered when the material
should ideally be initialized with the mark that is saved in \partial@page was first processed). This
current on “top” of this page. Unfortunately we will reduce the free space (i.e. \pagetotal) by the
8 During such a call the \botmark gets globally copied to \topmark by the TEX program.

10
appropriate amount since we have changed the mag- \linewidth so that the column width is properly
nification factor, etc. above. calculated when we are inside a minipage or a list
168 \reinsert@footnotes or some other environment. This will be achieved
with:
All the code above was only necessary for the un-
restricted multicols version, i.e. the one that allows 176 \hsize\linewidth \advance\hsize\columnsep
177 \advance\hsize-\col@number\columnsep
page breaks. If we are within a box there is no point
178 \divide\hsize\col@number
in setting up special output routines or \vsize, etc.
We also set \linewidth and \columnwidth to
169 \fi
\hsize In the past \columnwidth was left un-
But now we are coming to code that is necessary changed. This is inconsistent, but \columnwidth is
in all cases. We assign new values to \vbadness, used only by floats (which aren’t allowed in their
\hbadness and \tolerance since it’s rather hard current implementation) and by the \footnote
for TEX to produce ‘good’ paragraphs within nar- macro. Since we want pagewide footnotes9 this sim-
row columns. ple trick saved us from rewriting the \footnote
170 \vbadness\@Mi \hbadness5000 macros. However, some applications refered to
171 \tolerance\multicoltolerance \columnwidth as the “width of the current column”
Since nearly always the first pass will fail we ignore to typeset displays (the amsmath package, for exam-
it completely telling TEX to hyphenate directly. In ple) and to allow the use of such applications to-
fact, we now use another register to keep the value gether with multicol this is now changed.
for the multicol pre-tolerance, so that a designer may Before we change \linewidth to the new value
allow to use \pretolerance. we record its old value in some register called
172 \pretolerance\multicolpretolerance
\full@width. This value is used later on when we
package all columns together.
For use with the new TEX we set
179 \full@width\linewidth
\emergencystretch to \col@number × 4pt. How- 180 \linewidth\hsize
ever this is only a guess so at the moment this is 181 \columnwidth\hsize
done in a macro \setemergencystretch which gets 182 }
the current \hsize and the number of columns as
arguments. Therefore users are able to figure out This macro is used to set up the parameters asso-
their own formula. ciated with footnote floats. It can be redefined by
173 \setemergencystretch\col@number\hsize
applications that require different amount of spaces
when typesetting footnotes.
Another hook to allow people adding their own
183 \def\init@mult@footins{%
extensions without making a new package is 184 \multiply\count\footins\col@number
\set@floatcmds which handles any redefinitions of 185 \multiply\skip \footins\col@number
LATEXs internal float commands to work with the 186 }
multicols environment. At the moment it is only
used to redefine \@dblfloat and \end@dblfloat. Since we have to set \col@umber columns on one
174 \set@floatcmds
page, each with a height of \@colroom, we have to
assign \vsize = \col@number × \@colroom in or-
Additionally, we advance \baselineskip by der to collect enough material before entering the
\multicolbaselineskip to allow corrections for \output routine again. In fact we have to add
narrow columns. another (\col@number − 1) × (\baselineskip −
175 \advance\baselineskip\multicolbaselineskip \topskip) if you think about it.
The \hsize of the columns is given by the formula: 187 \def\set@mult@vsize#1{%
188 \vsize\@colroom
\linewidth − (\col@number − 1) × \columnsep 189 \@tempdima\baselineskip
\col@number 190 \advance\@tempdima-\topskip
191 \advance\vsize\@tempdima
The formula above has changed from release to 192 \vsize\col@number\vsize
release. We now start with the current value of 193 \advance\vsize-\@tempdima
9 I’m
not sure that I really want pagewide footnotes. But balancing of the last page can only be achieved with this approach
or with a multi-path algorithm which is complicated and slow. But it’s a challenge to everybody to prove me wrong! Another
possibility is to reimplement a small part of the fire up procedure in TEX (the program). I think that this is the best solution
if you are interested in complex page makeup, but it has the disadvantage that the resulting program cannot be called TEX
thereafter.

11
But this might not be enough since we use \vsplit If we are in an unrestricted multicols environment
later to extract the columns from the gathered ma- we end the current paragraph with \par but this
terial. Therefore we add some ‘extra lines,’ the num- isn’t sufficient since TEXs page builder will not to-
ber depending on the value of the ‘multicols’ counter. tally empty the contribution list.10 Therefore we
The final value is assigned globally if #1 is \global must also add an explicit \penalty. Now the con-
because we want to use this macro later inside the tribution list will be emptied and, if its material
output routine too. doesn’t all fit onto the current page then the output
194 #1\advance\vsize routine will be called before we change it. At this
195 \c@collectmore\baselineskip} point we need to use \penalty not \addpenalty to
ensure that a) the recent contributions are emptied
Here is the dimen register we need for saving away and b) that the very last item on the main vertical
the outer value of \@totalleftmargin. list is a valid break point so that TEX breaks the
196 \newdimen\multicol@leftmargin
page in case it is overfull.
218 \penalty\z@
When the end of the multicols environment is sensed Now it’s safe to change the output routine in order
we have to balance the gathered material. Depend- to balance the columns.
ing on whether or not we are inside a boxed multicol 219 \output{\balance@columns@out}\eject
different things must happen. But first we end the
current paragraph with a \par command. If the multicols environment body was completely
empty or if a multi-page multicols just ends at a
197 \def\endmulticols{\par
page boundary we have the unusual case that the
198 \if@boxedmulticols
\eject will have no effect (since the main vertical
In boxed mode we have to close the box in which we list is empty)—thus no output routine is called at
have gathered all material for the columns. all. As a result the material preceding the multicols
199 \egroup (stored in \partial@page will get lost if we don’t
take of this by hand.
Now we call \balance@columns the routine that
balances material stored in the box \mult@box. 220 \ifvbox\partial@page
221 \unvbox\partial@page\fi
200 \balance@columns
After the output routine has acted we restore the
After balancing the result has to be returned by the kept marks to their initial value.
command \page@sofar. But before we do this we
222 \global\let\kept@firstmark\@empty
reinsert any marks found in box \mult@box.
223 \global\let\kept@botmark\@empty
201 \return@nonemptymark{first}% 224 h∗marktracei
202 \kept@firstmark 225 \mult@info\tw@
203 \return@nonemptymark{bot}% 226 {Make kept marks empty}%
204 \kept@botmark 227 h/marktracei
205 \page@sofar 228 \fi
206 \global\let\kept@firstmark The output routine above will take care of the
207 \l@kept@firstmark \vsize and reinsert the balanced columns, etc. But
208 \global\let\kept@botmark it can’t reinsert the \footnotes because we first
209 \l@kept@botmark have to restore the \footins parameter since we
210 h∗marktracei
are returning to one column mode. This will be
211 \mult@info\tw@
done in the next line of code; we simply close the
212 {Restore kept marks to\MessageBreak
group started in \multicols.
213 first: \meaning\kept@firstmark
214 \MessageBreak bot\space\space: To fix an obscure bug which is the result of the
215 \meaning\kept@botmark }% current definition of the \begin . . . \end macros,
216 h/marktracei we check that we are still (logically speaking) in the
multicols environment. If, for example, we forget to
This finishes the code for the “boxed” case. close some environment inside the multicols environ-
217 \else ment, the following \endgroup would be incorrectly
10 This once caused a puzzling bug where some of the material was balanced twice, resulting in some overprints. The reason

was the \eject which was placed at the end of the contribution list. Then the page builder was called (an explicit \penalty
will empty the contribution list), but the line with the \eject didn’t fit onto the current page. It was then reconsidered after
the output routine had ended, causing a second break after one line.

12
considered to be the closing of this environment. 243 \newcount\c@collectmore
229 \@checkend{multicols}% In the new LATEX release \col@number is already al-
230 \endgroup located by the kernel, so we don’t allocate it again.
Now it’s time to return any footnotes if we are in %\newcount\col@number
244
unrestricted mode: \newcount\doublecol@number
245
231 \if@boxedmulticols\else 246 \newcount\multicoltolerance
232 \reinsert@footnotes 247 \newcount\multicolpretolerance
233 \fi 248 \newdimen\full@width
We also set the ‘unbalance’ counter to its default. 249 \newdimen\page@free

This is done globally since LATEX counters are al- 250 \newdimen\premulticols
251 \newdimen\postmulticols
ways changed this way.11
252 \newskip\multicolsep
234 \global\c@unbalance\z@ 253 \newskip\multicolbaselineskip
We also take a look at the amount of free space on 254 \newbox\partial@page
the current page to see if it’s time for a page break. 255 \newbox\last@line
The vertical space added thereafter will vanish if And here are their default values:
\enough@room starts a new page.
256 \c@unbalance = 0
235 \enough@room\postmulticols
257 \c@collectmore = 0
236 \addvspace\multicolsep
If statistics are required we finally report that we To allow checking whether some macro is used
have finished everything. within the multicols environment the counter
\col@number gets a default of 1 outside the the en-
237 \mult@info\z@
238 {Ending environment
vironment.
239 \if@boxedmulticols 258 \col@number = 1
240 \space(boxed mode)\fi 259 \multicoltolerance = 9999
241 }} 260 \multicolpretolerance = -1
261 \premulticols = 50pt
Let us end this section by allocating all the registers 262 \postmulticols= 20pt
used so far. 263 \multicolsep = 12pt plus 4pt minus 3pt
242 \newcount\c@unbalance 264 \multicolbaselineskip=0pt

4.4 The output routines

We first start with some simple macros. When type- 268 \typeout{Looking at box \the\count@}
setting the page we save the columns either in the 269 h/debugi
box registers 0, 2, 4,. . . (locally) or 1, 3, 5,. . . (glob- 270 #2%
ally). This is Plain TEX policy to avoid an overflow 271 \advance\count@\tw@
of the save stack. 272 \ifnum\count@<\doublecol@number
273 \repeat}
Therefore we define a \process@cols macro to help
us in using these registers in the output routines
below. It has two arguments: the first one is a We now define \page@sofar to give an example
number; the second one is the processing informa- of the \process@cols macro. \page@sofar should
tion. It loops starting with \count@=#1 (\count@ is output everything prepared by the balancing routine
a scratch register defined in Plain TEX), processes \balance@columns.
argument #2, adds two to \count@, processes ar-
gument #2 again, etc. until \count@ is higher than 274 \def\page@sofar{%
\doublecol@number. It might be easier to under-
stand it through an example, so we define it now \balance@columns prepares its output in the even
and explain its usage afterwards. numbered scratch box registers. Now we output
265 \def\process@cols#1#2{\count@#1\relax the columns gathered assuming that they are saved
266 \loop in the box registers 2 (left column), 4 (second col-
267 h∗debugi umn), . . . However, the last column (i.e. the right-
11 Actually, we are still in a group started by the \begin macro, so \global must be used anyway.

13
most) should be saved in box register 0.12 First Before we tackle the bigger output routines we
we ensure that the columns have equal width. We define just one more macro which will help us
use \process@cols for this purpose, starting with to find our way through the mysteries later.
\count@ = \mult@rightbox. Therefore \count@ \reinsert@footnotes will do what its name in-
loops through \mult@rightbox, \mult@rightbox + dicates: it reinserts the footnotes present in
2,. . . (to \doublecol@number). \footinbox so that they will be reprocessed by
275 \process@cols\mult@rightbox TEX’s page builder.
Instead of actually reinserting the footnotes we
We have to check if the box in question is void, be- insert an empty footnote. This will trigger insertion
cause the operation \wdhnumber i on a void box will mechanism as well and since the old footnotes are
not change its dimension (sigh). still in their box and we are on a fresh page \skip
276 {\ifvoid\count@ footins should be correctly taken into account.
277 \setbox\count@\hbox to\hsize{}% 297 \def\reinsert@footnotes{\ifvoid\footins\else
278 \else 298 \insert\footins{}\fi}
279 \wd\count@\hsize
280 \fi}% Now we can’t postpone the difficulties any longer.
The \multi@column@out routine will be called in
Now we give some tracing information.
two situations. Either the page is full (i.e. we
281 \mult@info\z@ have collected enough material to generate all the
282 {Column spec:\MessageBreak required columns) or a float or marginpar (or a
283 (\the\multicol@leftmargin\space -->
\clearpage is sensed. In the latter case the
284 \the\full@width\space = \the\hsize
\outputpenalty is less than −10000, otherwise the
285 \space x \the\col@number)%
286 }% penalty which triggered the output routine is higher.
Therefore it’s easy to distinguish both cases: we sim-
At this point we should always be in vertical mode. ply test this register.
287 \ifvmode\else\errmessage{Multicol Error}\fi 299 \def\multi@column@out{%
300 \ifnum\outputpenalty <-\@M
Now we put all columns together in an
\hbox of width \full@width (shifting it by If this was a \clearpage, a float or a marginpar we
\multicol@leftmargin to the right so that it will call \speci@ls
be placed correctly if we are within a list environ- 301 \speci@ls \else
ment) otherwise we construct the final page. For the next
288 \moveright\multicol@leftmargin block of code see comments in section 7.2.
289 \hbox to\full@width{% 302h∗colbreaki
303 \ifvoid\colbreak@box\else
and separating the columns with a rule if desired. 304 \mult@info\@ne{Re-adding forced
290 \process@cols\mult@gfirstbox{\box\count@ 305 break(s) for splitting}%
291 \hss\vrule\@width\columnseprule\hss}% 306 \setbox\@cclv\vbox{%
307 \unvbox\colbreak@box
As you will have noticed, we started with box regis-
308 \penalty-\@Mv\unvbox\@cclv}%
ter \mult@gfirstbox (i.e. the left column). So this 309 \fi
time \count@ looped through 2, 4,. . . (plus the ap- 310 h/colbreaki
propriate offset). Finally we add box 0 and close the
Let us now consider the normal case. We have to
\hbox.
\vsplit the columns from the accumulated mate-
292 \box\mult@rightbox rial in box 255. Therefore we first assign appropriate
The depths of the columns depend on their last lines. values to \splittopskip and \splitmaxdepth.
To ensure that we will always get a similar look as 311 \splittopskip\topskip
far as the rules are concerned we force the depth at 312 \splitmaxdepth\maxdepth
least the depth of a letter ‘p’. Then we calculate the current column height (in
293 % \strut \dimen@). Note that the height of \partial@page
294 \rlap{\phantom p}% is already subtracted from \@colroom so we can use
295 }% its value as a starter.
296 } 313 \dimen@\@colroom
12 You will see the reason for this numbering when we look at the output routines \multi@column@out and
\balance@columns@out.

14
But we must also subtract the space occupied by If the ‘tracingmulticols’ counter is 4 or higher we also
footnotes on the current page. Note that we first add a rule.
have to reset the skip register to its normal value. 345 \ifnum \c@tracingmulticols>\thr@@
Again, the actual action is carried out in a utility 346 \hrule\allowbreak \fi
macro, so that other applications can modify it. 347 \fi
314 \divide\skip\footins\col@number To get a correct marks for the current page
315 \ifvoid\footins \else we have to (locally redefine \firstmark and
316 \leave@mult@footins \botmark. If \kept@firstmark is non-empty then
317 \fi
\kept@botmark must be non-empty too so we can
Now we are able to \vsplit off all but the last col- use their values. Otherwise we use the value of
umn. Recall that these columns should be saved in \kept@topmark which was first initialized when we
the box registers 2, 4,. . . (plus offset). gathered the \partical@page and later on was up-
318 \process@cols\mult@gfirstbox{% dated to the \botmark for the preceding page
319 \setbox\count@
348 \ifx\@empty\kept@firstmark
320 \vsplit\@cclv to\dimen@
349 \let\firstmark\kept@topmark
After splitting we update the kept marks. 350 \let\botmark\kept@topmark
321 \set@keptmarks 351 \else
If \raggedcolumns is in force we add a vfill at the 352 \let\firstmark\kept@firstmark
bottom by unboxing the split box. 353 \let\botmark\kept@botmark
354 \fi
322 \ifshr@nking
323 \setbox\count@ We also initalize \topmark with \kept@topmark.
324 \vbox to\dimen@ This will make this mark okay for all middle pages
325 {\unvbox\count@\vfill}% of the multicols environment.
326 \fi 355 \let\topmark\kept@topmark
327 }% h∗marktracei
356
Then the last column follows. 357 \mult@info\tw@
328 \setbox\mult@rightbox 358 {Use kept top mark:\MessageBreak
329 \vsplit\@cclv to\dimen@ 359 \meaning\kept@topmark
330 \set@keptmarks 360 \MessageBreak
331 \ifshr@nking 361 Use kept first mark:\MessageBreak
332 \setbox\mult@rightbox\vbox to\dimen@ 362 \meaning\kept@firstmark
333 {\unvbox\mult@rightbox\vfill}% 363 \MessageBreak
334 \fi 364 Use kept bot mark:\MessageBreak
365 \meaning\kept@botmark
Having done this we hope that box 255 is emptied.
366 \MessageBreak
If not, we reinsert its contents.
367 Produce first mark:\MessageBreak
335 \ifvoid\@cclv \else 368 \meaning\firstmark
336 \unvbox\@cclv 369 \MessageBreak
337 \penalty\outputpenalty 370 Produce bot mark:\MessageBreak
In this case a footnote that happens to fall into 371 \meaning\botmark
the leftover bit will be typeset on the wrong page. 372 \@gobbletwo}%
Therefore we warn the user if the current page con- 373 h/marktracei

tains footnotes. The older versions of multicols pro- With a little more effort we could have done bet-
duced this warning regardless of whether or not foot- ter. If we had, for example, recorded the shrinkage
notes were present, resulting in many unnecessary of the material in \partial@page it would be now
warnings. possible to try higher values for \dimen@ (i.e. the
338 \ifvoid\footins\else column height) to overcome the problem with the
339 \PackageWarning{multicol}% nonempty box 255. But this would make the code
340 {I moved some lines to even more complex so I skipped it in the current
341 the next page.\MessageBreak implementation.
342 Footnotes on page Now we use LATEX’s standard output mecha-
343 \thepage\space might be wrong}% nism.13 Admittedly this is a funny way to do it.
344 \fi
13 This will produce a lot of overhead since both output routines are held in memory. The correct solution would be to

redesign the whole output routine used in LATEX.

15
374 \setbox\@cclv\vbox{\unvbox\partial@page 398 \def\leave@mult@footins{%
375 \page@sofar}% 399 \advance\dimen@-\skip\footins
400 \advance\dimen@-\ht\footins
The macro \@makecol adds all floats assigned for
401 }
the current page to this page. \@outputpage ships
out the resulting box. Note that it is just possible
that such floats are present even if we do not allow We left out two macros: \process@deferreds and
any inside a multicols environment. \speci@ls.
376 \@makecol\@outputpage 402 \def\speci@ls{%
After the page is shipped out we have to pre- 403 \ifnum\outputpenalty <-\@Mi
pare the kept marks for the following page.
\kept@firstmark and \kept@botmark reinitilized If the document ends in the middle of a mul-
by setting them to \@empty. The value of \botmark ticols environment, e.g., if the user forgot the
is then assigned to \kept@topmark. \end{multicols}, TEX adds a very negative
penalty to the end of the galley which is intended
377 \global\let\kept@topmark\botmark
378 \global\let\kept@firstmark\@empty
to signal the output routine that it is time to pre-
379 \global\let\kept@botmark\@empty pare for shipping out everything remaining. Since
380 h∗marktracei inside multicols the output routine of LATEX is dis-
381 \mult@info\tw@ abled sometimes we better check for this case: if
382 {(Re)Init top mark:\MessageBreak we find a very negative penalty we produce an error
383 \meaning\kept@topmark message and run the default output routine for this
384 \@gobbletwo}% case.
385 h/marktracei
404 \ifnum \outputpenalty<-\@MM
Now we reset \@colroom to \@colht which is
405 \PackageError{multicol}{Document end
LATEX’s saved value of \textheight. 406 inside multicols environment}\@ehd
386 \global\@colroom\@colht 407 \@specialoutput
Then we process deferred floats waiting for their 408 \else
chance to be placed on the next page.
For the next block of code see comments in sec-
387 \process@deferreds tion 7.2.
388 \@whilesw\if@fcolmade\fi{\@outputpage
389 \global\@colroom\@colht 409 h∗colbreaki
390 \process@deferreds}% 410 \ifnum\outputpenalty = -\@Mv
If the user is interested in statistics we inform him 411 \mult@info\@ne{Forced column
about the amount of space reserved for floats. 412 break seen}%
413 \global\advance\vsize-\pagetotal
391 \mult@info\@ne 414 \global\setbox\colbreak@box
392 {Colroom:\MessageBreak 415 \vbox{\ifvoid\colbreak@box
393 \the\@colht\space 416 \else
394 after float space removed 417 \unvbox\colbreak@box
395 = \the\@colroom \@gobble}% 418 \penalty-\@Mv
Having done all this we must prepare to tackle the 419 \fi
next page. Therefore we assign a new value to 420 \unvbox\@cclv}
\vsize. New, because \partial@page is now empty 421 \reinsert@footnotes
and \@colroom might be reduced by the space re- 422 \else
served for floats. 423 h/colbreaki

396 \set@mult@vsize \global If we encounter a float or a marginpar in the cur-


The \footins skip register will be adjusted when rent implementation we simply warn the user that
the output group is closed. this is not allowed. Then we reinsert the page and
397 \fi} its footnotes.

This macro is used to subtract the amount of space 424 \PackageWarning{multicol}%


occupied by footnotes for the current space from the 425 {Floats and marginpars not
space available for the current column. The space 426 allowed inside ‘multicols’
427 environment!
current column is stored in \dimen@. See above for
428 \@gobble}%
the description of the default action. 429 \unvbox\@cclv\reinsert@footnotes

16
Additionally we empty the \@currlist to avoid 449 \def\raggedcolumns{%
later error messages when the LATEX output routine 450 \@bsphack\shr@nkingtrue\@esphack}
is again in force. But first we have to place the 451 \def\flushcolumns{%

boxes back onto the \@freelist. (\@elts default is 452 \@bsphack\shr@nkingfalse\@esphack}


\relax so this is possible with \xdef.)
Now for the last part of the show: the column bal-
430 \xdef\@freelist{\@freelist\@currlist}%
ancing output routine. Since this code is called with
431 \gdef\@currlist{}%
432 h∗colbreaki
an explicit penalty (\eject) there is no need to
433 \fi check for something special (eg floats). We start
434 h/colbreaki by balancing the material gathered.
435 \fi 453 \def\balance@columns@out{%
If the penalty is −10001 it will come from a For this we need to put the contents of box 255 into
\clearpage and we will execute \@doclearpage to \mult@box.
get rid of any deferred floats. 454 h−colbreaki \setbox\mult@box
436 \else \@doclearpage \fi 455 h−colbreaki \vbox{\unvbox\@cclv}%
437 }
For the next block of code see comments in sec-
\process@deferreds is a simplified version of tion 7.2.
LATEX’s \@startpage. We first call the macro 456 h∗colbreaki
\@floatplacement to save the current user parame- 457 \setbox\mult@box\vbox{%
ters in internal registers. Then we start a new group 458 \ifvoid\colbreak@box\else
and save the \@deferlist temporarily in the macro 459 \unvbox\colbreak@box\break
460 \mult@info\@ne{Re-adding
\@tempb.
461 forced break(s) in balancing}%
438 \def\process@deferreds{% 462 \fi
439 \@floatplacement 463 \unvbox\@cclv}%
440 \@tryfcolumn\@deferlist 464 h/colbreaki
441 \if@fcolmade\else 465 \balance@columns
442 \begingroup
443 \let\@tempb\@deferlist This will bring us into the position to apply
\page@sofar. But first we have to set \vsize to
Our next action is to (globally) empty \@deferlist
a value suitable for one column output.
and assign a new meaning to \@elt. Here
\@scolelt is a macro that looks at the boxes in 466 \global\vsize\@colroom
467 \global\advance\vsize\ht\partial@page
a list to decide whether they should be placed on
the next page (i.e. on \@toplist or \@botlist) or Then we \unvbox the \partial@page (which may
should wait for further processing. be void if we are not prcessing the first page of this
444 \gdef\@deferlist{}% multicols environment.
445 \let\@elt\@scolelt 468 \unvbox\partial@page
Now we call \@tempb which has the form Then we return the first and bottom mark and the
gathered material to the main vertical list.
\@elthbox register i\@elthbox register i. . .
469 \return@nonemptymark{first}\kept@firstmark
So \@elt (i.e. \@scolelt) will distribute the boxes 470 \return@nonemptymark{bot}\kept@botmark
to the three lists. 471 \page@sofar
446 \@tempb \endgroup We need to add a penalty at this point which allows
447 \fi} to break at this point since calling the output rou-
tine may have removed the only permissible break
The \raggedcolumns and \flushcolumns declara- point thereby “glueing” any following skip to the
tions are defined with the help of a new \if... balanced box. In case there are any weird settings
macro. for \multicolsep etc. this could produce funny re-
448 \newif\ifshr@nking sults.
The actual definitions are simple: we just switch to 472 \penalty\z@
true or false depending on the desired action. To 473 }
avoid extra spaces in the output we enclose these As we already know, reinserting of footnotes will be
changes in \@bsphack. . . \@esphack. done in the macro \endmulticols.

17
This macro now does the actual balancing. 487 \@tempdima\ht\mult@box
474 \def\balance@columns{% 488 \advance\@tempdima\dp\mult@box
489 \divide\@tempdima\col@number
We start by setting the kept marks by updating
them with any marks from this box. This has to The code above sets \@tempdima to the length of
be done before we add a penalty of −10000 to the a column if we simply divide the whole box into
top of the box, otherwise only an empty box will be equal pieces. To get to the next lower multiple of
considered. \baselineskip we convert this dimen to a num-
475 \get@keptmarks\mult@box ber (the number of scaled points) then divide this
by \baselineskip (also in scaled points) and then
We then contine by resetting trying to remove any
multiply this result with \baselineskip assigning
discardable stuff at the end of \mult@box. This is
the result to \dimen@. This makes \dimen@ ≤ to
rather experimental. We also add a forced break
\@tempdimena.
point at the very beginning, so that we can split the
box to height zero later on, thereby adding a known 490 \count@\@tempdima
\splittopskip glue at the beginning. 491 \divide\count@\baselineskip
492 \dimen@\count@\baselineskip
476 \setbox\mult@box\vbox{%
477 \penalty-\@M Next step is to correct our result by taking
478 \unvbox\mult@box into account the difference between \topskip and
479 \remove@discardable@items \baselineskip. We start by adding \topskip; if
480 }% this makes the result too large then we have to sub-
Then follow values assignments to get the tract one \baselineskip.
\vsplitting right. We use the natural part of 493 \advance\dimen@\topskip
\topskip as the natural part for \splittopskip 494 \ifdim \dimen@ >\@tempdima
and allow for a bit of undershoot and overshoot by 495 \advance\dimen@-\baselineskip
adding some stretch and shrink. 496 \fi
481 \@tempdima\topskip At the user’s request we start with a higher value (or
482 \splittopskip\@tempdima lower, but this usually only increases the number of
483 \@plus\multicolundershoot
tries).
484 \@minus\multicolovershoot
485 \splitmaxdepth\maxdepth 497 \advance\dimen@\c@unbalance\baselineskip
The next step is a bit tricky: when TEX assem- We type out statistics if we were asked to do so.
bles material in a box, the first line isn’t preceded 498 \mult@info\@ne
by interline glue, i.e. there is no parameter like 499 {Balance columns\on@line:
\boxtopskip in TEX. This means that the baseline 500 \ifnum\c@unbalance=\z@\else
of the first line in our box is at some unpredictable 501 (off balance=\number\c@unbalance)\fi
point depending on the height of the largest charac- 502 \@gobbletwo}%
ter in this line. But of course we want all columns But we don’t allow nonsense values for a start.
to align properly at the baselines of their first lines.
503 \ifnum\dimen@<\topskip
For this reason we have opened \mult@box with a
504 \mult@info\@ne
\penalty -10000. This will now allow us to split 505 {Start value
off from \mult@box a tiny bit (in fact nothing since 506 \the\dimen@ \space ->
the first possible break-point is the first item in the 507 \the\topskip \space (corrected)}%
box). The result is that \splittopskip is inserted 508 \dimen@\topskip
at the top of \mult@box which is exactly what we 509 \fi
like to achieve. Now we try to find the final column height. We start
486 \setbox\@tempboxa\vsplit\mult@box to\z@ by setting \vbadness to infinity (i.e. 10000) to sup-
Next we try to find a suitable starting point for press underfull box reports while we are trying to
the calculation of the column height. It should be find an acceptable solution. We do not need to do
less than the height finally chosen, but large enough it in a group since at the end of the output routine
to reach this final value in only a few iterations. everything will be restored. The setting of the final
The formula which is now implemented will try to columns will nearly always produce underfull boxes
start with the nearest value which is a multiple of with badness 10000 so there is no point in warning
\baselineskip. The coding is slightly tricky in TEX the user about it.
and there are perhaps better ways . . . 510 \vbadness\@M

18
We also allow for overfull boxes while we trying to 534 \ifnum\badness>\c@columnbadness
split the columns. 535 \ifnum\c@tracingmulticols>\@ne
511 \vfuzz \col@number\baselineskip 536 \message{too bad
537 (>\the\c@columnbadness)}%
The variable \last@try will hold the dimension 538 \fi
used in the previous trial splitting. We initialize 539 \global\too@badtrue
it with a negative value. 540 \fi
512 \last@try-\p@ 541 h/badnessi
513 \loop 542 }}%
In order not to clutter up TEX’s valuable main There is one subtle point here: while all other con-
memory with things that are no longer needed, we structed boxes have a depth that is determined by
empty all globally used box registers. This is neces- \splitmaxdepth the last box will get a natural
sary if we return to this point after an unsuccessful depth disregarding the original setting and the value
trial. We use \process@cols for this purpose, start- of \splitmaxdepth or \boxmaxdepth. This means
ing with \mult@grightbox. Note the extra braces that we may end up with a very large depth in box
around this macro call. They are needed since \mult@grightbox which would make the result of
Plain TEX’s \loop. . . \repeat mechanism cannot the testing incorrect. So we change the value by
be nested on the same level of grouping. unboxing the box into itself.
514 {\process@cols\mult@grightbox
543 \boxmaxdepth\maxdepth
515 {\global\setbox\count@
544 \global\setbox\mult@grightbox
516 \box\voidb@x}}%
545 \vbox{\unvbox\mult@grightbox}%
The contents of box \mult@box are now copied glob-
ally to box \mult@grightbox. (This will be the We also save a copy \mult@firstbox at its “natu-
right-most column, as we shall see later.) ral” size for later use.
517 \global\setbox\mult@grightbox 546 \setbox\mult@nat@firstbox
518 \copy\mult@box 547 \vbox{\unvcopy\mult@firstbox}%
We start with the assumption that the trial will be After \process@cols has done its job we have the
successful. If we end up with a solution that is too following situation:
bad we set too@bad to true.
519 h∗badnessi box \mult@rightbox ←− all material
520 \global\too@badfalse box \mult@gfirstbox ←− first column
521 h/badnessi box \mult@gfirstbox + 2 ←− second column
Using \vsplit we extract the other columns from .. ..
. .
box register \mult@grightbox. This leaves box reg-
box \mult@grightbox ←− last column
ister \mult@box untouched so that we can start over
again if this trial was unsuccessful. We report the height of the first column, in brackets
522 {\process@cols\mult@firstbox{% the natural size is given.
523 \global\setbox\count@
524 \vsplit\mult@grightbox to\dimen@ 548 \ifnum\c@tracingmulticols>\@ne
549 \message{^^JFirst column
After every split we check the badness of the result- 550 = \the\dimen@\space
ing column, normally the amount of extra white in 551 (\the\ht\mult@nat@firstbox)}\fi
the column.
525 h∗badnessi If \raggedcolumns is in force older releases of this
526 \ifnum\c@tracingmulticols>\@ne file also shrank the first column to its natural height
527 \@tempcnta\count@ at this point. This was done so that the first col-
528 \advance\@tempcnta-\mult@grightbox umn doesn’t run short compared to later columns
529 \divide\@tempcnta \tw@ but it is actually producing incorrect results (over-
530 \message{^^JColumn printing of text) in boundary cases, so since version
531 \number\@tempcnta\space v1.5q \raggedcolumns means allows for all columns
532 badness: \the\badness\space}% to run slightly short.
533 \fi
552 % \ifshr@nking
If this badness is larger than the allowed column 553 % \global\setbox\mult@firstbox
badness we reject this solution by setting too@bad 554 % \copy\mult@nat@firstbox
to true. 555 % \fi

19
Then we give information about the last column.14 shorter. For this we first have to rebox the column
556 \ifnum\c@tracingmulticols>\@ne into a box of the appropriate height. If tracing is
557 \message{<> last column = enabled we then display the badness for this box.
558 \the\ht\mult@grightbox^^J}% 583 \global\setbox\mult@grightbox
Some tracing code that we don’t compile into the 584 \vbox to\dimen@
production version unless asked for. It will produce 585 {\unvbox\mult@grightbox}%
huge listings of the boxes involved in balancing in 586 \ifnum\c@tracingmulticols>\@ne
587 \message{Final badness:
the transcript file.
588 \the\badness}%
559 h∗debugi 589 \fi
560 \ifnum\c@tracingmulticols>4
We then compare this badness with the allowed bad-
561 {\showoutput
562 \batchmode ness for the final column. If it does not exceed this
563 \process@cols\@ne value we use the box, otherwise we rebox it once
564 {\showbox\count@}}% more and add some glue at the bottom.
565 \errorstopmode 590 \ifnum\badness>\c@finalcolumnbadness
566 \fi 591 \global\setbox\mult@grightbox
567 h/debugi 592 \vbox to\dimen@
568 \fi 593 {\unvbox\mult@grightbox\vfill}%
We check whether our trial was successful. The test 594 \ifnum\c@tracingmulticols>\@ne
595 \message{ setting natural
used is very simple: we merely compare the first and
596 (> \the\c@finalcolumnbadness)}%
the last column. Thus the intermediate columns
597 \fi
may be longer than the first if \raggedcolumns 598 \fi
is used. If the right-most column is longer than
If \@tempboxa above was not void our trial was un-
the first then we start over with a larger value for
successful and we report this fact and try again.
\dimen@.
599 h∗colbreaki
569 \ifdim\ht\mult@grightbox >\dimen@
600 \else
If the height of the last box is too large we mark this 601 \too@badtrue
trial as unsuccessful. 602 \ifnum\c@tracingmulticols>\@ne
570 h∗badnessi 603 \typeout{Rejected: unprocessed
571 \too@badtrue 604 forced break(s) in last column!}%
572 \ifnum\c@tracingmulticols>\@ne 605 \fi
573 \typeout{Rejected: last 606 \fi
574 column too large!}% 607 \fi
575 \fi 608 h/colbreaki
576 \else If the natural height of the first box is smaller than
To ensure that there isn’t a forced break in the last the current trial size but is larger than the previous
column we try to split off a box of size \maxdimen trial size it is likely that we have missed a potien-
from \mult@grightbox (or rather from a copy of it). tially better solution. (This could have happened if
This should result in a void box after the split, un- for some reason our first trial size was too high.) In
less there was a forced break somewhere within the that case we dismiss this trial and restart using the
column in which case the material after the break natural height for the next trial.
would have stayed in the box. 609 \ifdim\ht\mult@nat@firstbox<\dimen@
577 h∗colbreaki 610 \ifdim\ht\mult@nat@firstbox>\last@try
578 \setbox\@tempboxa 611 \too@badtrue
579 \copy\mult@grightbox 612 \ifnum\c@tracingmulticols>\@ne
580 \setbox\z@\vsplit\@tempboxa to\maxdimen 613 \typeout{Retry: using natural
581 \ifvoid\@tempboxa 614 height of first column!}%
582 h/colbreaki
615 \fi
616 \dimen@\ht\mult@nat@firstbox
Thus if \@tempboxa is void we have a valid solution. 617 \last@try\dimen@
In this case we take a closer look at the last column 618 \advance\dimen@-\p@
to decide if this column should be made as long as 619 \fi
all other columns or if it should be allowed to be 620 \fi
14 With TEX version 3.141 it is now possible to use LATEX’s \newlinechar in the \message command, but people with older
TEX versions will now get ^^J instead of a new line on the screen.

20
Finally the switch too@bad is tested. If it was made box registers to the even-numbered ones, shrinking
true either earlier on or due to a rightmost column them if requested. We have to use \vbox not \vtop
being too large we try again with a slightly larger (as it was done in the first versions) since otherwise
value for \dimen@. the resulting boxes will have no height (TEXbook
621 \iftoo@bad page 81). This would mean that extra \topskip
622 h/badnessi is added when the boxes are returned to the page-
623 \advance\dimen@\p@ builder via \page@sofar.
624 \repeat
628 \process@cols\mult@rightbox
At that point \dimen@ holds the height that was de- 629 {\@tempcnta\count@
termined by the balancing loop. If that height for 630 \advance\@tempcnta\@ne
the columns turns out to be larger than the available 631 \setbox\count@\vbox to\dimen@
space (which is \@colroom) we sqeeze the columns 632 {%
into the space assuming that they will have enough
633 \vskip \z@
shrinkability to allow this.15 634 \@plus-\multicolundershoot
625 \ifdim\dimen@>\@colroom 635 \@minus-\multicolovershoot
626 \dimen@\@colroom 636 \unvbox\@tempcnta
627 \fi 637 \ifshr@nking\vfill\fi}}%
Then we move the contents of the odd-numbered 638 }

4.5 The box allocations


Early releases of these macros used the first box \newbox\mult@firstbox
642
registers 0, 2, 4,. . . for global boxes and 1, 3, 5,. . . \newbox\@tempa\newbox\@tempa
643
for the corresponding local boxes. (You might still 644 \newbox\@tempa\newbox\@tempa

find some traces of this setup in the documentation, 645 \newbox\@tempa\newbox\@tempa


646 \newbox\@tempa\newbox\@tempa
sigh.) This produced a problem at the moment we
647 \newbox\@tempa\newbox\@tempa
had more than 5 columns because then officially allo-
648 \newbox\@tempa\newbox\@tempa
cated boxes were overwritten by the algorithm. The
649 \newbox\@tempa\newbox\@tempa
new release now uses private box registers 650 \newbox\@tempa\newbox\@tempa
639 \newbox\mult@rightbox 651 \newbox\@tempa
640 \newbox\mult@grightbox 652 \let\@tempa\relax
641 \newbox\mult@gfirstbox

5 New macros and hacks for version 1.2


If we don’t use TEX 3.0 \emergencystretch is un- 658 \def\set@floatcmds{%
defined so in this case we simply add it as an unused 659 \let\@dblfloat\@dbflt
hdimeni register. 660 \def\end@dblfloat{\par
661 \vskip\z@
653 \@ifundefined{emergencystretch}
662 \egroup
654 {\newdimen\emergencystretch}{}
663 \color@endbox
My tests showed that the following for- 664 \@largefloatcheck
mula worked pretty well. Nevertheless the 665 \outer@nobreak
\setemergencystretch macro also gets \hsize as
second argument to enable the user to try different
formulae. This is cheap (defering the floats until after the cur-
rent page) but any other solution would go deep into
655 \def\setemergencystretch#1#2{%
LATEX’s output routine and I don’t like to work on it
656 \emergencystretch 4pt
657 \multiply\emergencystretch#1} until I know which parts of the output routine have
to be reimplemented anyway for LATEX3.
Even if this should be used as a hook we use a @ in
the name since it is more for experts. 666 \ifnum\@floatpenalty<\z@
15 This might be wrong, since the shrinkability that accounts for the amount of material might be present only in some
columns. But it is better to try then to give up directly.

21
We have to add the float to the \@deferlist be- 667 \@cons\@deferlist\@currbox
cause we assume that outside the multicols environ- 668 \fi
ment we are in one column mode. This is not en- 669 \ifnum\@floatpenalty=-\@Mii
tirely correct, I already used the multicols environ- 670 \@Esphack
ment inside of LATEXs \twocolumn declaration but 671 \fi}}
it will do for most applications.

5.1 Maintaining the mark registers

This section contains the routines that set the marks \markboth.) We therefore use the usual mechanism
so that they will be handled correctly. They have of a toks register to prohibit expansion.16
been introduced with version 1.4.
685 \toks@\expandafter{#2}%
First thing we do is to reserve three macro names 686 \mark{\the\toks@}%
to hold the replacement text for TEX’s primitives We don’t want any breakpoint between such a re-
\firstmark, \botmark and \topmark. We initial- turned mark and the following material (which is
ize the first two to be empty and \kept@topmark to usually just the box where the mark came from).
contain two empty pair of braces. This is necessary
since \kept@topmark is supposed to contain the last 687 \nobreak
688 \fi}
mark from a preceding page and in LATEX any “real”
mark must contain two parts representing left and
right mark information. If we have some material in a box register we may
672 \def\kept@topmark{{}{}} want to get the first and the last mark out of this
673 \let\kept@firstmark\@empty box. This can be done with \get@keptmarks which
674 \let\kept@botmark\@empty takes one argument: the box register number or its
nick name defined by \newbox.
Sometimes we want to return the value of a
689 \def\get@keptmarks#1{%
“kept” mark into a \mark node on the main
vertical list. This is done by the function For debugging purposes we take a look at the cur-
\return@nonemptymark. As the name suggests it rent dimensions of the box since in earlier versions
only acts if the replacement text of the kept mark is of the code I made some mistakes in this area.
non-empty. This is done to avoid adding an empty
690 h∗debugi
mark when no mark was actually present. If we
691 \typeout{Mark box #1 before:
would nevertheless add such a mark it would be re- 692 ht \the\ht#1, dp \the\dp#1}%
garded as a valid \firstmark later on. 693 h/debugi
675 \def\return@nonemptymark#1#2{%
676 \ifx#2\@empty Now we open a new group an locally copy the box to
677 \else itself. As a result any operation, i.e. \vsplit, will
For debugging purposes we take a look at the value only have a local effect. Without this trick the box
of the kept mark that we are about to return. This content would get lost up to the level where the last
code will get stripped out for production. assignment to the box register was done.
678 h∗marktracei 694 \begingroup
679 \mult@info\tw@ 695 \vbadness\@M
680 {Returned #1 mark:\MessageBreak 696 \setbox#1\copy#1%
681 \meaning#2}%
682 % \nobreak
Now we split the box to the maximal possible di-
683 % \fi mension. This should split off the full contents of
684 h/marktracei the box so that effectively everything is split off. As
a result \splitfirstmark and \splitbotmark will
Since the contents of the mark may be arbitrary
contain the first and last mark in the box respec-
LATEX code we better make sure that it doesn’t get
tively.
expanded any further. (Some expansion have been
done already during the execution of \markright or 697 \setbox#1\vsplit#1to\maxdimen
16 Due to the current definition of \markright etc. it wouldn’t help to define the \protect command to prohibit expansion
as any \protect has already vanished due to earlier expansions.

22
Therefore we can now set the kept marks which is 723 h∗marktracei
a global operation and afterwards close the group. 724 \mult@info\tw@
This will restore the original box contents. 725 {Set kept bot mark:\MessageBreak
726 \meaning\kept@botmark%
698 \set@keptmarks
727 \@gobbletwo}%
699 \endgroup
728 h/marktracei
For debugging we take again a look at the box di- 729 \fi}%
mension which shouldn’t have changed.
The \prep@keptmarks function is used to initialize
700 h∗debugi
the kept marks from the contents of \partial@page,
701 \typeout{Mark box #1 \space after:
702 ht \the\ht#1, dp \the\dp#1}% i.e. the box that holds everything from the top of the
703 h/debugi current page prior to starting the multicols environ-
704 } ment. However, such a box is only available if we
are not producing a boxed multicols.
The macro \set@keptmarks is responsible for set- 730 \def\prep@keptmarks{%
ting \kept@firstmark and \kept@botmark, by 731 \if@boxedmulticols \else
checking the current values for \splitfirstmark 732 \get@keptmarks\partial@page
and \splitbotmark. 733 \fi}
705 \def\set@keptmarks{%
If \kept@firstmark is empty we assume that it 734 \def\remove@discardable@items{%
isn’t set. This is strictly speaking not correct as 735 h∗debugi
we loose the ability to have marks that are explic- 736 \edef\@tempa{s=\the\lastskip,
itly empty, but for standard LATEX application it is 737 p=\the\lastpenalty,
sufficient. If it is non-empty we don’t change the 738 k=\the\lastkern}%
value—within the output routines it will then be re- 739 \typeout\@tempa
740 h/debugi
stored to \@empty.
741 \unskip\unpenalty\unkern
706 \ifx\kept@firstmark\@empty 742 h∗debugi
We now put the contents of \splitfirstmark into 743 \edef\@tempa{s=\the\lastskip,
\kept@firstmark. In the case that there wasn’t 744 p=\the\lastpenalty,
any mark at all \kept@firstmark will not change 745 k=\the\lastkern}%
746 \typeout\@tempa
by that operation.
747 h/debugi
707 \expandafter\gdef\expandafter 748 \unskip\unpenalty\unkern
708 \kept@firstmark 749 h∗debugi
709 \expandafter{\splitfirstmark}% 750 \edef\@tempa{s=\the\lastskip,
When debugging we show the assignment but only 751 p=\the\lastpenalty,
when something actually happened. 752 k=\the\lastkern}%
753 \typeout\@tempa
710 h∗marktracei
754 h/debugi
711 \ifx\kept@firstmark\@empty\else
755 \unskip\unpenalty\unkern
712 \mult@info\tw@
756 h∗debugi
713 {Set kept first mark:\MessageBreak
757 \edef\@tempa{s=\the\lastskip,
714 \meaning\kept@firstmark%
758 p=\the\lastpenalty,
715 \@gobbletwo}%
759 k=\the\lastkern}%
716 \fi
760 \typeout\@tempa
717 h/marktracei
761 h/debugi
718 \fi
762 \unskip\unpenalty\unkern
We always try to set the bottom mark to the 763 }
\splitbotmark but of course only when there has
764 h∗badnessi
been a \splitbotmark at all. Again, we assume
765 \newif\iftoo@bad
that an empty \splitbotmark means that the split
off box part didn’t contain any marks at all.
719 \expandafter\def\expandafter\@tempa 766 \newcount\c@columnbadness
720 \expandafter{\splitbotmark}% 767 \c@columnbadness=10000
721 \ifx\@tempa\@empty\else 768 \newcount\c@finalcolumnbadness
722 \global\let\kept@botmark\@tempa 769 \c@finalcolumnbadness=9999

23
770 A helper for producing info messages
771 \newdimen\last@try
772 779 \def\mult@info#1#2{%
773 \newdimen\multicolovershoot 780 \ifnum\c@tracingmulticols>#1%
774 \multicolovershoot=2pt 781 \GenericWarning
775 \newdimen\multicolundershoot 782 {(multicol)\@spaces\@spaces}%
776 \multicolundershoot=2pt 783 {Package multicol: #2}%
777 \newbox\mult@nat@firstbox 784 \fi
778 h/badnessi 785 }

6 Fixing the \columnwidth


If we store the current column width in \@footnotetext done by a class will correctly
\columnwidth we have to redefine the internal survive and second if multicols is used inside
\@footnotetext macro to use \textwidth for the a minipage environment the special definition of
width of the footnotes rather then using the original \@footnotetext in that environment will be picked
definition. up and not the one for the main galley (the lat-
Starting with version v1.5r this is now done in a ter would result in all footnotes getting lost in that
way that the original definition is still used, execpt case).
that locally \columnwidth is set to \textwidth. See the definition of the \multicols command
This solves two problems: first redefinitions of further up for the exact code.

7 Further extensions
This section does contain code for extensions added When ending the environment we simply end the in-
to this package over time. Not all of them may be ner multicols environment, except that we better
active, some might sit dormant and wait for being also stick in some stretchable vertical glue so that
activated in some later release. the last column still containing text is not vertically
stretched out.
7.1 Not balancing the columns 799 \@namedef{endmulticols*}{\vfill
800 \end{multicols}}
This is fairly trivial to implement. we just have to 801 h/nobalancei
disable the balancing output routine and replace it
by the one that ships out the other pages.
7.2 Manual column breaking
The code for this environment was suggested by
Matthias Clasen. The problem with manual page breaks within multi-
cols is the fact that during collection of material for
786 h∗nobalancei
all columns a page-forcing penalty (i.e. -10000 or
787 \@namedef{multicols*}{%
higher) would stop the collecting pass which is not
If we are not on the main galley, i.e., inside a box quite what is desired. On the other hand, using a
of some sort, that approach will not work since we penalty like -9999 would mean that there would be
don’t have a vertical size for the box so we better occasions where the \vspliting operations within
warn that we balance anyway. multicols would ignore that penalty and still choose
788 \ifinner a different break point.
789 \PackageWarning{multicol}% For this reason the current implementation uses
790 {multicols* inside a box does a completely different approach. In a nutshell it
791 not make sense.\MessageBreak
extends the LATEX output routine handling by in-
792 Going to balance anyway}%
793 \else
troducing an additional penalty flag (i.e., a penalty
794 \let\balance@columns@out which is forcing but higher than -10000 so that the
795 \multi@column@out output routine can look at this value and thus knows
796 \fi why it has been called).
797 \begin{multicols} Inside the output routine we test for this value
798 } and if it appears we do two things: save the galley

24
up to this point in a special box for later use and re-
duce the \vsize by the height of the material seen.
This way the forcing penalty is now hidden in that
box and we can restart the collection process for
the remaining columns. (This is done in \speci@ls
above.)
In the output routines that do the \vsplitting
either for balancing or for a full page we simply com-
bine box 255 with the saved box thus getting a single
box for splitting which now contains forcing breaks
in the right positions.

\columnbreak is modelled after \pagebreak except


that we generate a penalty -10005.
802 h∗colbreaki
803 \mathchardef\@Mv=10005
804 \def\columnbreak{%

We have to ensure that it is only used within a mul-


ticols environment since if that penalty would be
seen by the unmodified LATEX output routine strange
things would happen.
805 \ifnum\col@number<\tw@
806 \PackageError{multicol}%
807 {\noexpand\columnbreak outside multicols}%
808 {This command can only be used within
809 a multicols or multicols* environment.}%
810 \else
811 \ifvmode
812 \penalty -\@Mv\relax
813 \else
814 \@bsphack
815 \vadjust{\penalty -\@Mv\relax}%
816 \@esphack
817 \fi
818 \fi}

Need a box to collect the galley up to the column


break.
819 \newbox\colbreak@box
820 h/colbreaki
821 h/packagei

25
Index
Numbers written in italic refer to the page where the corresponding entry is described, the ones underlined
to the code line of the definition, the rest to the code lines where the entry is used.

Symbols \endmulticols . . . 197 \mult@cols . . . . . . 76 \postmulticols 2, 241


\@footnotetext . . 786 \endmulticols* . . 799 \mult@firstbox . . 639 \premulticols . 2, 241
\enough@room . . . . 104 \mult@footnotetext 786 \prep@keptmarks . 730
B \mult@gfirstbox . 639 \prepare@multicols 121
\balance@columns 474 F \mult@grightbox . 639 \process@cols . . . 265
\balance@columns@out \flushcolumns . . . 448 \mult@info . . . . . 779 \process@deferreds 438
. . . . . . . . . . 453 \mult@rightbox . . 639
G
\get@keptmarks . . 689 \multi@column@out 299 R
C
\multicol@leftmargin
\c@collectmore . . 241 \raggedcolumns . . 448
I . . . . . . . . . . 196
\c@columnbadness 766 \reinsert@footnotes
\if@boxedmulticols 101 \multicolbaselineskip
\c@finalcolumnbadness . . . . . . . . . . 297
\ifshr@nking . . . . 448 . . . . . . . . 2, 241
. . . . . . . . . . 766 \remove@discardable@items
\init@mult@footins 183 \multicolpretolerance
\c@unbalance . . . . 242 . . . . . . . . . . 734
. . . . . . . . 2, 241
\col@number . . . . . 241 K \return@nonemptymark
\multicols . . . . . . 56
\colbreak@box . . . 819 \kept@botmark . . . 672 . . . . . . . . . . 675
\multicols* . . . . . 786
\columnbreak . . . . 802 \kept@firstmark . 672
\columnsep . . . . . . . 2 \multicolsep . . 2, 241
\kept@topmark . . . 672 \multicoltolerance S
\columnseprule . . . . 2 \set@floatcmds . . 658
L . . . . . . . . 2, 241
D \set@keptmarks . . 705
\leave@mult@footins
\doublecol@number 241 P \set@mult@vsize . 187
. . . . . . . . . . 398
\page@free . . . . . 241 \setemergencystretch
E M \page@sofar . . . . . 274 . . . . . . . . . . 653
\emergencystretch 653 \mult@@cols . . . . . . 79 \partial@page . . . 241 \speci@ls . . . . . . 402

26

You might also like