You are on page 1of 36

An environment for multicolumn output

Frank Mittelbach
Email: see top of the source file
Printed April 15, 2017

This file is maintained by the LATEX Project team.


Bug reports can be opened (category tools) at
http://latex-project.org/bugs.html.

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. LATEXs
float mechanism, however, is partly disabled in this 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.8


The 1.8 release improves on the enlarge pages by more than one to execute if we are in the last
balancing approach. If due line you may have to increase the column. Thus
to a limited number of break collectmore counter value to en-
points (e.g., due to large ob- sure that enough material is be- \docolaction{first}
jects) the balanced columns ex- ing picked up. {middle}{last}
ceed the available vertical space, This command was used on the
then balancing is canceled and second page of this manual to would typeset a different word
a normal page is produced shorten it by one line, in order depending the type of column
first. Some overflow is allowed to get rid of a number of widow this code is executed. Using it
(controlled by the parameter lines on the following pages. like this is probably pointless, but
\maxbalancingoverflow which Finally, version 1.8 adds the you can imagine applications like
defaults to 12pt). This ensures command \docolaction to help writing something into the near-
that we only cut a normal page with more complicated actions est margin, etc.
if we get enough material carried that depend on the current col- As this feature needs at least
over to next page. umn. This command expects 3 two LATEX runs to produce cor-
Also added was support for arguments: code that is executed rect results and as it adds to the
\enlargethispage. This means if we are in the first column, processing complexity it is only
it is now possible to request a code to execute if we end up in made available if one add the op-
page to be artificially enlarged any middle column (if there are tion colaction when loading the
or shortened. Note that if you more than two) and finally code package.

This file has version number v1.8q, last revised 2017/04/11.


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
Preface to version 1.7 (right to left support)
The 1.7 release adds support for something that wasnt supported so read the rightmost column
languages that are typeset right- before. The next paragraph first). The change is initialized
to-left. For those languages the demonstrates the result (as it via \RLmulticolcolumns and re-
order of the columns on the is typeset as if we are writ- turning to left-right (default) is
page also need to be reversed ing in a left-to-right language done via \LRmulticolcolumns.

For example: directions within the columns. Right-to-left typesetting will


As footnotes are typeset in full only reverse the column orders.
\renewcommand \footnoterule{%
measure the footnote rule needs Any other support needed will
\kern-3pt\hbox to\textwidth
to be redefined as if they are be- have to be provided by other
{\hskip .6\textwidth
\hrulefill }% low a single column, i.e., using means, e.g., using appropriate
\kern2.6pt} \textwidth not \columnwidth. fonts and reversing the writing

Preface to version 1.5 + 1.6


The 1.5 release contains two tine now checks the badness of Later changes to 1.5 include
major changes: multicols will the resulting columns and rejects \columnbreak and multicols*.
now support up to 10 columns solutions that are larger than a For version 1.6 micro-spacing
and two more tuning possibilities certain threshold. At the same around the boxes produced by
have been added to the balanc- time multicols has been upgraded multicols has been improved to al-
ing routine. The balancing rou- to run under LATEX 2 . low for baseline-grid typesetting.

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

2 The User Interface


To use the environment one sim- where hnumber i is the required mentation2 .
ply says number of columns and hmulti-
column texti may contain arbi-
\begin{multicols}{hnumber i}
trary LATEX commands, except As its first action, the multicols
hmulticolumn texti
that floats and marginpars are environment measures the cur-
\end{multicols}
not allowed in the current imple- rent page to determine whether
there is enough room for some
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
(This remark was made in the documentation of the initial release, since then several hundreds more hours went into improving
the original code.)
2 This is dictated by lack of time. To implement floats one has to reimplement the whole LAT X output routine.
E

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

3
might be set on the next one.5 only applies to one multicols en- really ugly looking columns.
Therefore the multicols environ- vironment. In the new release this stretch-
ment gives a warning message6 The two methods may be com- ing is only done if the badness
whenever it is unable to use all bined but I suggest using these of the final column is not larger
the material considered so far. features only when fine tuning than the value of the counter fi-
If you dont use footnotes too important publications. nalcolumnbadness. The default
often the chances of something Two more general tuning pos- setting is 9999, thus preventing
actually going wrong are very sibilities were added with ver- the stretching for all columns
slim, but if this happens you can sion 1.5. TEX allows to mea- that TEX would consider in-
help TEX by using a \pagebreak sure the badness of a column in finitely bad. In that case the fi-
command in the final document. terms of an integer value, where nal column is allowed to run short
Another way to influence the be- 0 means optimal and any higher which gives a much better result.
havior of TEX in this respect value means a certain amount And there are two more
is given by the counter variable of extra white space. 10000 is parameters of some exper-
collectmore. If you use the considered to be infinitely bad imental nature, one called
\setcounter declaration to set (TEX does not distinguish any \multicolovershoot the other
this counter to hnumber i, TEX further). In addition the special \multicolundershoot. They
will consider hnumber i more (or value 100000 means overfull (i.e., control the amount of space a col-
less) lines before making its fi- the column contains more text umn within the multicols environ-
nal decision. So a value of 1 than could possibly fit into it). ment is allowed to be too full
may solve all your problems at The new release now measures or too short without affecting
the cost of slightly less optimal every generated column and ig- the column badness. They are
columns. nores solutions where at least set to 0pt and 2pt, respectively.
In the second step (balanc- one column has a badness be- Finally, when doing the bal-
ing columns) we have other bells ing larger than the value of the ancing at the end, columns
and whistles. First of all you counter columnbadness. The de- may become higher than the
can say \raggedcolumns if you fault value for this counter is remaining available space. In
dont want the bottom lines to 10000, thus TEX will accept all that case the algorithm aborts
be aligned. The default is solutions except those being over- and instead generates a normal
\flushcolumns, so TEX will nor- full. By setting the counter to a page. However, if the amount
mally try to make both the smaller value you can force the is not too large, e.g., a line or
top and bottom baselines of all algorithm to search for solutions so, then it might be better to
columns align. that do not have columns with a keep everything on the same
Additionally you can set lot of white space. page instead of starting a new
another counter, the unbal- However, if the setting is too page with just one line after
ance counter, to some positive low, the algorithm may not find balancing. So the parameter
hnumber i. This will make all but any acceptable solution at all and \maxbalancingoverflow gov-
the right-most column hnumber i will then finally choose the ex- erns this process: only when the
of lines longer than they would treme solution of placing all text excess gets larger than its value
normally have been. Lines in into the first column. balancing is aborted.
this context refer to normal text Often, when columns are bal-
lines (i.e. one \baselineskip anced, it is impossible to find a 2.2 Not balancing the
apart); thus, if your columns solution that distributes the text
contain displays, for example,
columns
evenly over all columns. If that
you may need a higher hnumber i is the case the last column usu- Although this package was writ-
to shift something from one col- ally has less text than the oth- ten to solve the problem of bal-
umn into another. ers. In the earlier releases this ancing columns, I got repeated
Unlike collectmore, the unbal- text was stretched to produce a requests to provide a version
ance counter is reset to zero at column with the same height as where all white space is auto-
the end of the environment so it all others, sometimes resulting in matically placed in the last col-
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 dont 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.

4
umn or columns. Since version in their optional argument, but LaTeX Warning: I moved
v1.5q this now exists: if you h doesnt work because the first some lines to the next
use multicols* instead of the possible place is the top of the page
usual environment the columns next page. One should also note, As mentioned above, multicols
on the last page are not balanced. that this means that their place- sometimes screws up the foot-
Of course, this environment only ment behavior is determined by note numbering. As a precau-
works on top-level, e.g., inside a the values of \topfraction, etc. tion, whenever there is a foot-
box one has to balance to deter- rather than by \dbl.... note on a page where multicols
mine a column height in absence had to leave a remainder for the
of a fixed value. following page this warning ap-
2.5 Support for right-
pears. Check the footnote num-
to-left typesetting
2.3 Manually breaking bering on this page. If it turns
columns In right-to-left typesetting the or- out that it is wrong, you have to
der of the columns on the page manually break the page using
Another request often voiced also need to be reversed, i.e., the \newpage or \pagebreak[..].
was: How do I tell LATEX that first column has to appear on
it should break the first column Floats and marginpars not
the far right and the last col-
after this particular line?. The allowed inside multicols
umn on the left. This is sup-
\pagebreak command (which environment!
ported through the commands
works with the two-column op- \RLmulticolcolumns (switching This message appears if you try
tion of LATEX) is of no use here to right-to-left typesetting) and to use the \marginpar com-
since it would end the collection \LRmulticolcolumns (switching mand or an unstarred version of
phase of multicols and thus all to left-to-right typesetting) the the figure or table environment.
columns on that page. So with latter being the default. Such floats will disappear!
version 1.5u the \columnbreak
Very deep columns! Grid
command was added. If used
2.6 Warnings alignment might be broken
within a paragraph it marks the
end of the current line as the de- This message can only appear if
Under certain circumstances the the option grid was chosen. In
sired breakpoint. You can ob-
use of the multicols environment that case it will show up if a col-
serve its effect on the previous
may result in some warnings from umn has a very large depth so
page where three lines of text
TEX or LATEX. Here is a list of the that multicols is unable to back
have been artificially forced into
important ones and the possible up to its baseline. This is only
the second column (resulting in
cause: relevant if one tries to produce
some white space between para-
graphs in the first column). a document where all text lines
Underfull \hbox (badness
are aligned at an invisible grid,
...)
something that requires careful
2.4 Floats inside a mul- As the columns are often very adjustment of many parameters
ticols environment narrow TEX wasnt able to find and macros, e.g., heading defini-
Within the multicols environment a good way to break the para- tions.
the usual star float commands graph. Underfull denotes a loose
are available but their function is line but as long as the badness 2.7 Tracing the output
somewhat different as in the two- value is below 10000 the result
is probably acceptable. To understand the reasoning be-
column mode of standard LATEX.
hind the decisions TEX makes
Stared floats, e.g., figure*, de-
Underfull \vbox ... while when processing a multicols envi-
note page wide floats that are
\output is active ronment, a tracing mechanism is
handled in a similar fashion as
provided. If you set the counter
normal floats outside the multi- If a column contains a character
tracingmulticols to a positive
cols environment. However, they with an unusual depth, for ex-
hnumber i you then will get some
will never show up on the page ample a (, in the bottom line
tracing information on the termi-
where they are encountered. In then this message may show up.
nal and in the transcript file:
other words, one can influence It usually has no significance as
their placement by specifying a long as the value is not more hnumber i = 1. TEX will now
combination of t, b, and/or p than a few points. tell you, whenever it enters

5
or leaves a multicols environ- in force and the value of the hnumber i 4. Setting
ment, the number of columns it unbalance counter if positive. hnumber i to such a high value
is working on and its decision will additionally place an
hnumber i = 3. Setting
about starting a new page be- \hrule into your output, sep-
hnumber i to this value will ad-
fore or after the environment. arating the part of text which
ditionally trace the mark han-
had already been considered
hnumber i = 2. In this case dling algorithm. It will show
on the previous page from the
you also get information from what marks are found, what
rest. Clearly this setting should
the balancing routine: the marks are considered, etc. To
not be used for the final out-
heights tried for the left and fully understand this informa-
put. It will also activate even
right-most columns, informa- tion you will probably have to
more debugging code for mark
tion about shrinking if the read carefully trough the imple-
handling.
\raggedcolumns declaration is mentation.

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 TEXs internal rithm of multicols: The balanc- the copyright notice and dont
vertical mode) is that such vari- ing routine is now placed into change multicol.dtx directly!

3.2 Preface to version 1.2


After the article about the mul- But actually resetting such pa- sults in the fewest demerits will
ticols environment was published rameters to zero or even worse to be chosen. This means that a
in TUGboat 10#3, I got numer- a negative value wont give bet- value of 1000 for \adjdemerits
ous requests for these macros. ter line breaks inside the multicols instructs TEX to prefer visibly in-
However, I also got a changed environment. TEXs line break- compatible lines instead of pro-
version of my style file, together ing algorithm will only look at ducing better line breaks.
with a letter asking me if I would those possible line breaks which
include the changes to get better can be reached without a badness However, with TEX 3.0 it is
paragraphing results in the case higher than the current value of possible to get decent line breaks
of narrow lines. The main dif- \tolerance (or \pretolerance even in small columns by setting
ferences to my original style op- in the first pass). If this isnt pos- \emergencystretch to an appro-
tion were additional parameters sible, then, as a last resort, TEX priate value. I implemented a
(like \multicoladjdemerits to will produce overfull boxes. All version which is capable of run-
be used for \adjdemerits, etc.) those (and only those) possible ning both in the old and the
which would influence the line break points will be considered new TEX (actually it will sim-
breaking algorithm. and finally the sequence which re- ply ignore the new feature if it
is not available). The calculation

6
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 the two 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

of \emergencystretch is proba- Rowley for pointing this out.) I It has a few features which will
bly incorrect. I made a few tests removed this misbehaviour and make life much easier in multi-
but of course one has to have at the same time decided to al- column surroundings. Neverthe-
much more experience with the low at least floats spanning all less we are working here at the
new possibilities to achieve the columns, e.g., generated by the edge of TEXs capabilities, really
maximum quality. figure* environment. You can perfect solutions would need a
Version 1.1a had a nice fea- see the new functionality in ta- different approach than it was
ture: the penalty for using ble 2 which was inserted at this done in TEXs page builder.
the forbidden floats was their very point. However single col- The text below is nearly un-
ultimate removal from LATEXs umn floats are still forbidden and changed, I only added documen-
\@freelist so that after a few I dont think I will have time to tation at places where new code
\marginpars inside the multi- tackle this problem in the near fu- was added.
cols environment floats where dis- ture. As an advice for all who
abled forever. (Thanks to Chris want to try: wait for TEX 3.0.

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

7
\setemergencystretch: This is a hook for people 4pt #1, i.e. the \hsize isnt 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.

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

4.2 Identification and option processing


We start by identifying the package. Since it makes 45 \DeclareOption{errorshow}
use of features only available in LATEX 2 we ensure 46 {\c@tracingmulticols\z@}
that this format is available. (Now this is done ear- 47 \DeclareOption{infoshow}

lier in the file.) 48 {\c@tracingmulticols\@ne}


49 \DeclareOption{balancingshow}
37 h*packagei 50 {\c@tracingmulticols\tw@}
38 % \NeedsTeXFormat{LaTeX2e} 51 \DeclareOption{markshow}
39 % \ProvidesPackage{multicol}[..../../..
52 {\c@tracingmulticols\thr@@}
40 % v... multicolumn formatting] 53 \DeclareOption{debugshow}
Next we declare options supported by multicols. 54 {\c@tracingmulticols5\relax}
Two-column mode and multicols do not work to- The next option is intended for typesetting on a
gether so we warn about possible problems. How- \baselineskip grid. Right now it doesnt do any-
ever, since you can revert to \onecolumn in which thing other than warning if it thinks that the grid
case multicols does work, we dont make this an er- got lost.
ror.
55 \let\mc@gridwarn\maxdimen
41 \DeclareOption{twocolumn} 56 \DeclareOption{grid}{\def\mc@gridwarn{\maxdepth}}
42 {\PackageWarning{multicol}{May not work
Next option enables the \docolaction command.
43 with the twocolumn option}}
As this changes the .aux file content this is not au-
Tracing is done using a counter. However it is also tomatically enabled.
possible to invoke the tracing using the options de-
57 \DeclareOption{colaction}{%
clared below. 58 \def\mc@col@status@write{%
44 \newcount\c@tracingmulticols 59 \protected@write\@auxout{}%

8
60 {\string\mc@col@status 65 {\string\mc@col@status{3}}}%
61 {\ifmc@firstcol 1\else 2\fi}}% 66 }
62 \mc@firstcolfalse}% 67 \let\mc@col@status@write\relax
63 \def\mc@lastcol@status@write{% 68 \let\mc@lastcol@status@write\relax
64 \protected@write\@auxout{}%
69 \ProcessOptions

4.3 Starting and Ending the multicols Environment


As mentioned before, the multicols environment has 85 \ifx\@footnotetext\mult@footnotetext\else
one mandatory argument (the number of columns) 86 \let\orig@footnotetext\@footnotetext
and up to two optional ones. We start by reading 87 \let\@footnotetext\mult@footnotetext
the number of columns into the \col@number regis- 88 \fi
ter. Now we can safely look for the optional arguments.
70 \def\multicols#1{\col@number#1\relax 89 \@ifnextchar[\mult@cols{\mult@cols[]}}
If the user forgot the argument, TEX will complain
about a missing number at this point. The error
recovery mechanism will then use zero, which isnt 90 \long\def\mult@footnotetext#1{\begingroup
91 \columnwidth\textwidth
a good choice in this case. So we should now test
92 \orig@footnotetext{#1}\endgroup}
whether everything is okay. The minimum is two
columns at the moment. The \mult@cols macro grabs the first optional ar-
71 \ifnum\col@number<\tw@ gument (if any) and looks for the second one.
72 \PackageWarning{multicol}% 93 \def\mult@cols[#1]{\@ifnextchar[%
73 {Using \number\col@number
74 columns doesnt seem a good idea.^^J This argument should be a hdimeni denoting the
75 I therefore use two columns instead}% minimum free space needed on the current page to
76 \col@number\tw@ \fi start the environment. If the user didnt supply one,
We have only enough box registers for ten columns, we use \premulticols as a default.
so we need to check that the user hasnt asked for 94 {\mult@@cols{#1}}%
more. 95 {\mult@@cols{#1}[\premulticols]}}
77 \ifnum\col@number>10 After removing all arguments from the input we are
78 \PackageError{multicol}% able to start with \mult@@cols.
79 {Too many columns}%
80 {Current implementation doesnt 96 \def\mult@@cols#1[#2]{%
81 support more than 10 columns.% First thing we do is to decide whether or not this is
82 \MessageBreak an unbounded multicols environment, i.e. one that
83 I therefore use 10 columns instead}% may split across pages, or one that has to be typeset
84 \col@number10 \fi into a box. If we are in TEXs inner mode (e.g.,
Within the environment we need a special version inside a box already) then we have a boxed version
of the kernel \@footnotetext command since the of multicols therefore we set the @boxedmulticols
original sets the the \hsize to \columnwidth which switch to true. The multicols should start in vertical
is not correct in the multicol environment. Here mode. If we are not already there we now force it
\columnwidth refers to the width of the individual with \par since otherwise the test for inner mode
column and the footnote should be in \textwidth. wouldnt show if we are in a box.
Since \@footnotetext has a different definition in- 97 \par
side a minipage environment we do not redefine it 98 \ifinner \@boxedmulticolstrue
directly. Instead we locally set \columnwidth to Otherwise we check \doublecol@number. This
\textwidth and call the original (current) definition counter is zero outside a multicols environment but
stored in \orig@footnotetext. If the multicols positive inside (this happens a little later on). In
environment is nested inside another multicols envi- the second case we need to process the current mul-
ronment then the redefinition has already happened. ticols also in boxed mode and so change the switch
So be better test for this situation. Otherwise, we accordingly.
will get a TEX stack overflow as this would generate
99 \else
a self-referencing definition. .
100 \ifnum \doublecol@number>\z@

9
101 \@boxedmulticolstrue 114 \@tempcnta\prevdepth
102 \fi 115 \@tempcntb\baselineskip
103 \fi 116 \divide\@tempcnta\@tempcntb
Then we look to see if statistics are requested: 117 \advance\@tempcnta\@ne
118 \dimen@\prevdepth
104 \mult@info\z@ 119 \advance\dimen@ -\@tempcnta\baselineskip
105 {Starting environment with 120 \advance\dimen@ \topskip
106 \the\col@number\space columns% 121 \kern-\dimen@
In boxed mode we add some more info. 122 \fi
107 \if@boxedmulticols\MessageBreak We start a new grouping level to hide all subsequent
108 (boxed mode)\fi changes (done in \prepare@multicols for exam-
109 }% ple).
Then we measure the current page to see whether a 123 \begingroup
useful portion of the multicolumn environment can 124 \prepare@multicols
be typeset. This routine might start a new page. If we are in boxed mode we now open a box to type-
110 \enough@room{#2}% set all material from the multicols body into it, oth-
Now we output the first argument and produce ver- erwise we simply go ahead.
tical space above the columns. (Note that this ar- 125 \if@boxedmulticols
gument corresponds to the first optional argument 126 \setbox\mult@box\vbox\bgroup
of the multicols environment.) For many releases
127 \color@setgroup
this argument was typeset in a group to get a sim-
ilar effect as \twocolumn[..] where the argument We may have to reset some parameters at this point,
is also implicitly surrounded by braces. However, perhaps \@parboxrestore would be the right action
this conflicts with local changes done by things like but I leave it for the moment.
sectioning commands (which account for the major- 128 \fi
ity of commands used in that argument) messing up We finish by suppressing initial spaces.
vertical spacing etc. later in the document so that
129 \ignorespaces}
from version v1.5q on this argument is again typeset
at the outer level. Here is the switch and the box for boxed multicols
111 #1\par\addvspace\multicolsep code.
When the last line of a paragraph had a posi- 130 \newif\if@boxedmulticols
tive depth then this depth normally taken into ac- 131 \@boxedmulticolsfalse
count by the baselineskip calculation for the next 132 \newbox\mult@box

line. However, the columns produced by a following The \enough@room macro used above isnt perfect
multicol are rigid and thus the distance from the but works reasonably well in this context. We mea-
baseline of a previous text line to the first line in sure the free space on the current page by subtract-
a multicol would differ depending on the depth of ing \pagetotal from \pagegoal. This isnt en-
the previous line. To account for this we add a nega- tirely correct since it doesnt take the shrinking
tive space unless the depth is -1000pt which signals (i.e. \pageshrink) into account. The recent con-
something special to TEXand is not supposed to be tribution list might be nonempty so we start with
a real depth. \par and an explicit \penalty.7 Actually, we use
112 \ifdim \prevdepth = -\@m\p@ \addpenalty to ensure that a following \addvspace
113 \else will see the vertical space that might be present.
The actual generation of this corrective space is a The use of \addpenalty will have the effect that all
little bit more complicated as it doesnt make sense items from the recent contributions will be moved
to always back up to the previous baseline (in case to the main vertical list and the \pagetotal value
an object with a very large depth was placed there, will be updated correctly. However, the penalty will
e.g., a centered tabular). So we only back up to the be placed in front of any dangling glue item with
extend that we are within the \baselineskip grid. the result that the main vertical list may already
We know that the box produced by multicols has be overfull even if TEX is not invoking the output
\topskip at its top so that also needs to be taken routine.
into account. 133 \def\enough@room#1{%
7 See the documentation of \endmulticols for further details.

10
Measuring makes only sense when we are not in We also set the register \doublecol@number for
boxed mode so the routine does nothing if the later use. This register should contain 2
switch is true. \col@number. This is also an indicator that we are
134 \if@boxedmulticols\else within a multicols environment as mentioned above.
135 \par
To empty the contribution list the first release con- 154 \doublecol@number\col@number
tained a penalty zero but this had the result that 155 \multiply\doublecol@number\tw@
\addvspace couldnt detect preceding glue. So this 156 \advance\doublecol@number\mult@rightbox
was changed to \addpenalty. But this turned out 157 \if@boxedmulticols
to be not enough as \addpenalty will not add a 158 \let\l@kept@firstmark\kept@firstmark
penalty when @nobreak is true. Therefore we force 159 \let\l@kept@botmark\kept@botmark
this switch locally to false. As a result there may 160 \global\let\kept@firstmark\@empty
be a break between preceding text and the start of 161 \global\let\kept@botmark\@empty
a multicols environment, but this seems acceptable 162 \else
since there is the optional argument for exactly this We add an empty box to the main vertical list to
reason. ensure that we catch any insertions (held over or in-
136 \bgroup\@nobreakfalse\addpenalty\z@\egroup serted at the top of the page). Otherwise it might
137 \page@free \pagegoal happen that the \eject is discarded without calling
138 \advance \page@free -\pagetotal the output routine. Inside the output routine we re-
To be able to output the value we need to assign it move this box again. Again this code applies only
to a register first since it might be a register (de- if we are on the main vertical list and not within
fault) in which case we need to use \the or it might a box. However, it is not enough to turn off inter-
be a plain value in which case \the would be wrong. line spacing, we also have to clear \topskip before
adding this box, since \topskip is always inserted
139 \@tempskipa#1\relax before the first box on a page which would leave us
Now we test whether tracing information is required: with an extra space of \topskip if multicols start on
140 \mult@info\z@
a fresh sheet.
141 {Current page:\MessageBreak 163 \nointerlineskip {\topskip\z@\null}%
142 height=% 164 \output{%
143 \the\pagegoal: used \the\pagetotal 165 \global\setbox\partial@page\vbox
144 \space -> free=\the\page@free 166 {%
145 \MessageBreak Now we have to make sure that we catch one spe-
146 needed \the\@tempskipa cial situation which may result in loss of text! If
147 \space(for #1)}% the user has a huge amount of vertical material
Our last action is to force a page break if there isnt within the first optional argument that is larger then
enough room left. \premulticols and we are near the bottom of the
148 \ifdim \page@free <#1\newpage \fi page then it can happen that not the \eject is
149 \fi} triggering this special output routine but rather the
overfull main vertical list. In that case we get an-
When preparing for multicolumn output several
other breakpoint through the \eject penalty. As
things must be done.
a result this special output routine would be called
150 \def\prepare@multicols{%
twice and the contents of \partial@page, i.e. the
We start saving the current \@totalleftmargin material before the multicols environment gets lost.
and then resetting the \parshape in case we are There are several solutions to avoid this problem,
inside some list environment. The correct inden- but for now we will simply detect this and inform the
tation for the multicols environment in such a case user that he/she has to enlarge the \premulticols
will be produced by moving the result to the right by using a suitable value for the second argument.
by \multicol@leftmargin later on. If we would
167 h*checki
use the value of of \@totalleftmargin directly then 168 \ifvoid\partial@page\else
lists inside the multicols environment could cause a 169 \PackageError{multicol}%
shift of the output. 170 {Error saving partial page}%
151 \multicol@leftmargin\@totalleftmargin 171 {The part of the page before
152 \@totalleftmargin\z@ 172 the multicols environment was
153 \parshape\z@ 173 nearly full with^^Jthe result

11
174 that starting the environment Now we switch to a new \output routine which will
175 will produce an overfull be used to put the gathered column material to-
176 page. Some^^Jtext may be lost! gether.
177 Please increase \premulticols
195 \output{\multi@column@out}%
178 either generally or for this%
179 ^^Jenvironment by specifying a Finally we handle the footnote insertions. We have
180 suitable value in the second to multiply the magnification factor and the extra
181 optional argument to^^Jthe skip by the number of columns since each footnote
182 multicols environment.} reduces the space for every column (remember that
183 \unvbox\partial@page we have pagewide footnotes). If, on the other hand,
184 \box\last@line footnotes are typeset at the very end of the docu-
185 \fi
ment, our scheme still works since \count\footins
186 h/checki
187 \unvbox\@cclv
is zero then, so it will not change. To allow even
188 \global\setbox\last@line\lastbox further customization the setting of the \footins
189 }% parameters is done in a separate macro.
Finally we need to record the marks that are present 196 \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 isnt changed. Having done this,
190 \prep@keptmarks we must reinsert all the footnotes which are already
present (i.e. those encountered when the material
Finally we have to initialize \kept@topmark which saved in \partial@page was first processed). This
should ideally be initialized with the mark that is will reduce the free space (i.e. \pagetotal) by the
current on top of this page. Unfortunately we appropriate amount since we have changed the mag-
cant use \topmark because this register will not al- nification factor, etc. above.
ways contain what its name promises because LATEX
197 \reinsert@footnotes
sometimes calls the output routine for float manage-
ment.8 Therefore we use the second best solution by Inside multicols a \clearpage is fairly useless as
initializing it with \firstmark. In fact, for our pur- we arent supporting floats. In fact, it can cause
pose this doesnt matter as we use \kept@topmark harm as it doesnt know about the \partial@page
only to initialize \firstmark and \botmark of a fol- and may therefore result in making columns too
lowing page if we dont find any marks on the current long. So we change that to bahve like \newpage
one. but also check if there are any deferred floats. If
191 \global\let\kept@topmark\firstmark so, perhaps the user tried to place them through
192 }\eject that \clearpage (but that needs to be done before
starting the multicols environment.
The next thing to do is to assign a new value to
\vsize. LATEX maintains the free room on the page 198 \def\clearpage{%
199 \ifx\@deferlist\@empty\else
(i.e. the page height without the space for already
200 \PackageError{multicol}%
contributed floats) in the register \@colroom. We 201 {Deferred floats not cleared}%
must subtract the height of \partial@page to put 202 {A \string\clearpage\space inside multicols ac
the actual free room into this variable. 203 \string\newpage\space and doesnt clear float
193 \advance\@colroom-\ht\partial@page 204 Move it before the multicols environment if y
205 \fi
Then we have to calculate the \vsize value to use
206 \newpage}%
during column assembly. \set@mult@vsize takes
an argument which allows to make the setting local All the code above was only necessary for the un-
(\relax) or global (\global). The latter variant is restricted multicols version, i.e. the one that allows
used inside the output routine below. At this point page breaks. If we are within a box there is no point
here we have to make a local change to \vsize be- in setting up special output routines or \vsize, etc.
cause we want to get the original value for \vsize 207 \fi
restored in case this multicols environment ends on But now we are coming to code that is necessary
the same page where it has started. in all cases. We assign new values to \vbadness,
194 \set@mult@vsize\relax \hbadness and \tolerance since its rather hard
8 During such a call the \botmark gets globally copied to \topmark by the TEX program.

12
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
208 \vbadness\@Mi \hbadness5000 macros. However, some applications referred to
209 \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
\full@width. This value is used later on when we
210 \pretolerance\multicolpretolerance
package all columns together.
For use with the new TEX we set
217 \full@width\linewidth
\emergencystretch to \col@number 4pt. How- 218 \linewidth\hsize
ever this is only a guess so at the moment this is 219 \columnwidth\hsize
done in a macro \setemergencystretch which gets 220 }
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
211 \setemergencystretch\col@number\hsize applications that require different amount of spaces
Another hook to allow people adding their own when typesetting footnotes.
extensions without making a new package is 221 \def\init@mult@footins{%
\set@floatcmds which handles any redefinitions of 222 \multiply\count\footins\col@number
LATEXs internal float commands to work with the 223 \multiply\skip \footins\col@number
224 }
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
212 \set@floatcmds page, each with a height of \@colroom, we have to
Additionally, we advance \baselineskip by assign \vsize = \col@number \@colroom in or-
\multicolbaselineskip to allow corrections for der to collect enough material before entering the
narrow columns. \output routine again. In fact we have to add
213 \advance\baselineskip\multicolbaselineskip another (\col@number 1) (\baselineskip
The \hsize of the columns is given by the formula: \topskip) if you think about it.
225 \def\set@mult@vsize#1{%
\linewidth (\col@number 1) \columnsep 226 \vsize\@colroom
\col@number 227 \@tempdima\baselineskip
228 \advance\@tempdima-\topskip
The formula above has changed from release to 229 \advance\vsize\@tempdima
release. We now start with the current value of 230 \vsize\col@number\vsize
\linewidth so that the column width is properly 231 \advance\vsize-\@tempdima
calculated when we are inside a minipage or a list But this might not be enough since we use \vsplit
or some other environment. This will be achieved later to extract the columns from the gathered ma-
with: terial. Therefore we add some extra lines, one for
214 \hsize\linewidth \advance\hsize\columnsep each column plus a corrective action depending on
215 \advance\hsize-\col@number\columnsep the value of the collectmore counter. The final
216 \divide\hsize\col@number value is assigned globally if #1 is \global because
We also set \linewidth and \columnwidth to we want to use this macro later inside the output
\hsize In the past \columnwidth was left un- routine too.
changed. This is inconsistent, but \columnwidth is 232 \advance\vsize\col@number\baselineskip
used only by floats (which arent allowed in their 233 #1\advance\vsize
current implementation) and by the \footnote 234 \c@collectmore\baselineskip}
9 Im 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 its 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.

13
Here is the dimen register we need for saving away \colbreak@box contains text and if so return that
the outer value of \@totalleftmargin. to the galley. If the galley is non-empty any mate-
235 \newdimen\multicol@leftmargin rial in \colbreak@box is added in the output routine
since it needs to be put in front.
When the end of the multicols environment is sensed 257 \ifdim\pagegoal=\maxdimen
we have to balance the gathered material. Depend- 258 \ifvoid\colbreak@box\else
ing on whether or not we are inside a boxed multicol 259 \mult@info\@ne{Re-adding forced
different things must happen. But first we end the 260 break(s) for splitting}%
current paragraph with a \par command. 261 \unvbox\colbreak@box\fi
236 \def\endmulticols{\par 262 \fi
237 \if@boxedmulticols If we are in an unrestricted multicols environment
In boxed mode we have to close the box in which we we end the current paragraph above with \par but
have gathered all material for the columns. But be- this isnt sufficient since TEXs page builder will not
fore we do this we need to remove any space at the totally empty the contribution list.10 Therefore we
must also add an explicit \penalty. Now the con-
end of the box as we dont want to use this in balanc-
ing. Because of the \color@endgroup this cant be tribution list will be emptied and, if its material
done later in \balance@columns as the color com- doesnt all fit onto the current page then the output
mand will hide it. routine will be called before we change it. At this
238
point we need to use \penalty not \addpenalty to
\remove@discardable@items\color@endgroup\egroup
ensure that a) the recent contributions are emptied
Now we call \balance@columns the routine that and b) that the very last item on the main vertical
balances material stored in the box \mult@box. list is a valid break point so that TEX breaks the
239 \balance@columns page in case it is overfull.
After balancing the result has to be returned by the 263 \penalty\z@
command \page@sofar. But before we do this we Now its safe to change the output routine in order
reinsert any marks found in box \mult@box. to balance the columns.
240 \return@nonemptymark{first}%
264 \output{\balance@columns@out}%
241 \kept@firstmark
265 \eject
242 \return@nonemptymark{bot}%
243 \kept@botmark If the multicols environment body was completely
244 \page@sofar empty or if a multi-page multicols just ends at a
245 \global\let\kept@firstmark
page boundary we have the unusual case that the
246 \l@kept@firstmark \eject will have no effect (since the main vertical
247 \global\let\kept@botmark list is empty)thus no output routine is called at
248 \l@kept@botmark all. As a result the material preceding the multicols
249 h*marktracei (stored in \partial@page will get lost if we dont
250 \mult@info\tw@ put this back by hand.
251 {Restore kept marks to\MessageBreak 266 \ifvbox\partial@page
252 first: \meaning\kept@firstmark 267 \unvbox\partial@page\fi
253 \MessageBreak bot\space\space:
254 \meaning\kept@botmark }% After the output routine has acted we restore the
255 h/marktracei kept marks to their initial value.
This finishes the code for the boxed case. 268 \global\let\kept@firstmark\@empty
269 \global\let\kept@botmark\@empty
256 \else 270 h*marktracei
If there was a \columnbreak on the very last 271 \mult@info\tw@
line all material will have been moved to the 272 {Make kept marks empty}%
\colbreak@box. Thus the the galley will be empty 273 h/marktracei

and no output routine gets called so that the text 274 \fi
is lost. To avoid this problem (though unlikely) The output routine above will take care of the
we check if the current galley is empty and the \vsize and reinsert the balanced columns, etc. But
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 didnt fit onto the current page. It was then reconsidered after
the output routine had ended, causing a second break after one line.

14
it cant reinsert the \footnotes because we first \prevdepth that was current before the OR once
have to restore the \footins parameter since we the OR has finished. In short \prevdepth is some-
are returning to one column mode. This will be thing you cant set globally it is alway local to the
done in the next line of code; we simply close the current list being built. Thus we need to set it back
group started in \multicols. to zero here to avoid incorrect spacing.
To fix an obscure bug which is the result of the 287 \prevdepth\z@
current definition of the \begin . . . \end macros,
If statistics are required we finally report that we
we check that we are still (logically speaking) in the
have finished everything.
multicols environment. If, for example, we forget to
close some environment inside the multicols environ- 288 \mult@info\z@
ment, the following \endgroup would be incorrectly 289 {Ending environment
290 \if@boxedmulticols
considered to be the closing of this environment.
291 \space(boxed mode)\fi
275 \@checkend{multicols}% 292 }}
276 \endgroup
We also set the unbalance counter to its default. Let us end this section by allocating all the registers
This is done globally since LATEX counters are al- used so far.
ways changed this way.11 293 \newcount\c@unbalance
277 \global\c@unbalance\z@ 294 \newcount\c@collectmore
Now its time to return any footnotes if we are in In the new LATEX release \col@number is already al-
unrestricted mode: located by the kernel, so we dont allocate it again.
278 \if@boxedmulticols\else 295 %\newcount\col@number
279 \reinsert@footnotes 296 \newcount\doublecol@number
We also take a look at the amount of free space on 297 \newcount\multicoltolerance
the current page to see if its time for a page break. 298 \newcount\multicolpretolerance
The vertical space added thereafter will vanish if 299 \newdimen\full@width
\enough@room starts a new page. 300 \newdimen\page@free

But there is one catch. If the \end{multicols} 301 \newdimen\premulticols


302 \newdimen\postmulticols
is at the top of which can happen if there is a break
303 \newskip\multicolsep
point just before it (such as end ending environment)
304 \newskip\multicolbaselineskip
which was chosen. In that case we would do the next 305 \newbox\partial@page
page using the internal \vsize for multicol collec- 306 \newbox\last@line
tion which is a disaster. So we better catch this
case. Fortunately we can detect it by looking at And here are their default values:
\pagegoal. 307 \c@unbalance = 0
280 \ifdim \pagegoal=\maxdimen 308 \c@collectmore = 0
281 \global\vsize\@colroom To allow checking whether some macro is used
282 \else within the multicols environment the counter
283 \enough@room\postmulticols \col@number gets a default of 1 outside the the en-
284 \fi vironment.
285 \fi
286 \addvspace\multicolsep 309 %\col@number = 1
310 \multicoltolerance = 9999
There is one more thing to do: the balanced result of 311 \multicolpretolerance = -1
the environment is supposed to have a \prevdepth 312 \premulticols = 50pt
of zero as we backed up by its real prevdepth 313 \postmulticols= 20pt
within \page@sofar. However if the balancing hap- 314 \multicolsep = 12pt plus 4pt minus 3pt
pened in the output routine then TEX reverts to the 315 \multicolbaselineskip=0pt

4.4 The output routines


We first start with some simple macros. When type- ally). This is Plain TEX policy to avoid an overflow
setting the page we save the columns either in the of the save stack.
box registers 0, 2, 4,. . . (locally) or 1, 3, 5,. . . (glob-
11 Actually, we are still in a group started by the \begin macro, so \global must be used anyway.

15
Therefore we define a \process@cols macro to help 337 + \the\col@number\space
us in using these registers in the output routines 338 x \the\hsize\space
below. It has two arguments: the first one is a 339 + \the\count@\space
number; the second one is the processing informa- 340 x \the\columnsep
tion. It loops starting with \count@=#1 (\count@ is 341 }%
a scratch register defined in Plain TEX), processes At this point we should always be in vertical mode.
argument #2, adds two to \count@, processes ar- 342 \ifvmode\else\errmessage{Multicol Error}\fi
gument #2 again, etc. until \count@ is higher than
Now we put all columns together in an
\doublecol@number. It might be easier to under-
\hbox of width \full@width (shifting it by
stand it through an example, so we define it now
\multicol@leftmargin to the right so that it will
and explain its usage afterwards.
be placed correctly if we are within a list environ-
316 \def\process@cols#1#2{\count@#1\relax ment) and separating the columns with a rule if
317 \loop
desired.
318 h*debugi
319 \typeout{Looking at box \the\count@}
The box containing the columns has a large height
320 h/debugi
and thus will always result in using \lineskip if the
321 #2% normal \baselineskip calculations are used. We
322 \advance\count@\tw@ therefore better cancel that process.
323 \ifnum\count@<\doublecol@number 343 \nointerlineskip
324 \repeat}
As mentioned earlier we want to have the reference
We now define \page@sofar to give an example point of the box we put on the page being at the
of the \process@cols macro. \page@sofar should baseline of the last line of the columns but we also
output everything prepared by the balancing routine want to ensure that the box has no depth so that any
\balance@columns. following skip is automatically starting from that
325 \def\page@sofar{%
baseline. We achieve this by recording the depths
of all columns and then finally backing up by the
\balance@columns prepares its output in the even maximum. (perhaps a simpler method would be to
numbered scratch box registers. Now we output assemble the box in a register and set the depth of
the columns gathered assuming that they are saved that box to zero (not checked).
in the box registers 2 (left column), 4 (second col- We need a global scratch register for this; using
umn), . . . However, the last column (i.e. the right- standard TEX conventions we choose \dimen2 and
most) should be saved in box register 0.12 First initialize it with the depth of the character p since
we ensure that the columns have equal width. We that is one of the depths that compete for the max-
use \process@cols for this purpose, starting with imum.
\count@ = \mult@rightbox. Therefore \count@
344 \setbox\z@\hbox{p}\global\dimen\tw@\dp\z@
loops through \mult@rightbox, \mult@rightbox +
345 \moveright\multicol@leftmargin
2,. . . (to \doublecol@number). 346 \hbox to\full@width{%
326 \process@cols\mult@rightbox
If the document is written in a language that is type-
We have to check if the box in question is void, be- set right-to-left then, of course, the multicol columns
cause the operation \wdhnumber i on a void box will should be also typeset right-to-left. To support this
not change its dimension (sigh). we call \mc@align@columns which with execute dif-
327 {\ifvoid\count@ ferent code depending on the typesetting direction.
328 \setbox\count@\hbox to\hsize{}%
329 \else
347 \mc@align@columns
330 \wd\count@\hsize
331 \fi}% The depths of the columns depend on their last lines.
Now we give some tracing information. To ensure that we will always get a similar look as
far as the rules are concerned we force the depth to
332 \count@\col@number \advance\count@\m@ne
333 \mult@info\z@
be at least the depth of a letter p (which is what
334 {Column spec: \the\full@width\space = indentwe set \dimen2 to above).
335 + columns + sep =\MessageBreak 348 \rlap{\phantom p}%
336 \the\multicol@leftmargin\space 349 }%
12 You will see the reason for this numbering when we look at the output routines \multi@column@out and

\balance@columns@out.

16
The processed material might consist of a last line \vfill in that case but this is actually wrong for
with a descender in which case the \prevdepth will columns that are more or less full: by adding a glue
be non-zero. However, this material is getting refor- at the bottom such a column doesnt have any depth
matted now so that this value is likely to be wrong. any more but without it the material would be al-
We therefore normalize the situation by pretending lowed a depth of \maxdepth. So we allow shrinking
that the depth is zero. However, if \page@sofar is by that amount. This only makes a difference if the
being called inside the OR then setting \prevdepth box would otherwise become overfull and shrinking
here has no longlasting effect, we therefore have to never exceeds the specified value, so we should be
repeat this once we return to the main vertical list. fine.
Here we set it only for those cases where the com- 361 \def\vfilmaxdepth{\vskip \z@ \@plus .0001fil
mand is used within a list and then followed by 362 \@minus \maxdepth}
something else.
350 \prevdepth\z@ Now we cant postpone the difficulties any longer.
The \multi@column@out routine will be called in
Now after typesetting the box we back up to its base-
two situations. Either the page is full (i.e., we
line by using the value stored in \dimen2 (which will
have collected enough material to generate all the
hold the largest depth found on any column).
required columns) or a float or marginpar or a
351 \kern-\dimen\tw@
\clearpage is sensed. In the latter case the
However, in case one of the columns was unusually \outputpenalty is less than 10000, otherwise the
deep TEX may have tried some corrective actions in penalty which triggered the output routine is higher.
which case backing up by the saved value will not Therefore its easy to distinguish both cases: we sim-
bring us back to the baseline. A good indication for ply test this register.
this is a depth of \maxdepth though it is not an abso- 363 \def\multi@column@out{%
lute proof. If the option grid is used \mc@gridwarn 364 \ifnum\outputpenalty <-\@M
will expand to this, otherwise to \maxdimen in which
case this warning will not show up. If this was a \clearpage, a float or a marginpar we
call \speci@ls
352 \ifdim\dimen\tw@ > \mc@gridwarn
353 \PackageWarning{multicol}% 365 \speci@ls \else
354 {Very deep columns!\MessageBreak otherwise we construct the final page. For the next
355 Grid alignment might be broken}% block of code see comments in section 7.2.
356 \fi
366 \ifvoid\colbreak@box\else
357 }
367 \mult@info\@ne{Re-adding forced
By default the vertical rule between columns will be 368 break(s) for splitting}%
369 \setbox\@cclv\vbox{%
in \normalcolor.
370 \unvbox\colbreak@box
358 \def\columnseprulecolor{\normalcolor} 371 \penalty-\@Mv
372 \unvbox\@cclv}%
Before we tackle the bigger output routines we 373 \fi
define just one more macro which will help us
to find our way through the mysteries later. Let us now consider the normal case. We have to
\reinsert@footnotes will do what its name in- \vsplit the columns from the accumulated mate-
dicates: it reinserts the footnotes present in rial in box 255. Therefore we first assign appropriate
\footinbox so that they will be reprocessed by values to \splittopskip and \splitmaxdepth.
TEXs page builder. 374 \splittopskip\topskip
Instead of actually reinserting the footnotes we 375 \splitmaxdepth\maxdepth
insert an empty footnote. This will trigger insertion We also need to restrict \boxmaxdepth so that re-
mechanism as well and since the old footnotes are boxing is not generating boxes with arbitrary depth.
still in their box and we are on a fresh page \skip
footins should be correctly taken into account. 376 \boxmaxdepth\maxdepth
359 \def\reinsert@footnotes{\ifvoid\footins\else
Then we calculate the current column height (in
360 \insert\footins{}\fi}
\dimen@). Note that the height of \partial@page
This curious definition is used as the space is already subtracted from \@colroom so we can use
at the bottom of a column if we implement its value as a starter.
\raggedcolumns. Normlly one only appends 377 \dimen@\@colroom

17
But we must also subtract the space occupied by 401 \setbox\mult@rightbox\vbox to\dimen@
footnotes on the current page. Note that we first 402 {\unvbox\mult@rightbox
have to reset the skip register to its normal value. 403 \ifshr@nking\vfilmaxdepth\fi}%
Again, the actual action is carried out in a utility Now that we are done with the boxes, we restored
macro, so that other applications can modify it. the current setting for shrinking in case it got
378 \divide\skip\footins\col@number changed:
379 \ifvoid\footins \else 404 \let\ifshr@king\ifshr@kingsaved
380 \leave@mult@footins
381 \fi
Having done this we hope that box 255 is emptied.
If not, we reinsert its contents.
And there is one more adjustment that we have to
405 \ifvoid\@cclv \else
make: if the user has issue a \enlargethispage
406 \unvbox\@cclv
command then the height the \@kludgeins box will 407 \ifnum\outputpenalty=\@M
be the negation of the size by which the page should 408 \else
be enlarged. If the star form of this command has 409 \penalty\outputpenalty
been used then we also need to shrink the resulting 410 \fi
column. As we dont know whether or not shrinking In this case a footnote that happens to fall into
is already generally requested with save the current the leftover bit will be typeset on the wrong page.
value of \ifshr@king and restore it afterwards. Therefore we warn the user if the current page con-
382 \let\ifshr@kingsaved\ifshr@king tains footnotes. The older versions of multicols pro-
383 \ifvbox \@kludgeins duced this warning regardless of whether or not foot-
384 \advance \dimen@ -\ht\@kludgeins
notes were present, resulting in many unnecessary
The star form of \enlargethispage makes the warnings.
width of the box greater than zero (sneaky isnt it?). 411 \ifvoid\footins\else
385 \ifdim \wd\@kludgeins>\z@ 412 \PackageWarning{multicol}%
386 \shr@nkingtrue 413 {I moved some lines to
387 \fi 414 the next page.\MessageBreak
388 \fi 415 Footnotes on page
Now we are able to \vsplit off all but the last col- 416 \thepage\space might be wrong}%
umn. Recall that these columns should be saved in 417 \fi
the box registers 2, 4,. . . (plus offset). If the tracingmulticols counter is 4 or higher we also
389 \process@cols\mult@gfirstbox{% add a rule.
390 \setbox\count@ 418 \ifnum \c@tracingmulticols>\thr@@
391 \vsplit\@cclv to\dimen@ 419 \hrule\allowbreak \fi
After splitting we update the kept marks. 420 \fi
392 \set@keptmarks To get a correct marks for the current page
If \raggedcolumns is in force we add a vfill at the we have to (locally) redefine \firstmark and
bottom by unboxing the split box. But we need to \botmark. If \kept@firstmark is non-empty then
unbox anyway to ensure that at the end of the box \kept@botmark must be non-empty too so we can
we do not have unwanted space. This can sneak in use their values. Otherwise we use the value of
in certain situations, for example, if two lists follow \kept@topmark which was first initialized when we
each other and we break between them. While sich gathered the \partical@page and later on was up-
space is usually zero it still has an effect because it dated to the \botmark for the preceding page.
hides depth of the last line in the column and that 421 \ifx\@empty\kept@firstmark
will result in incorrect placement. 422 \let\firstmark\kept@topmark
393 \setbox\count@ 423 \let\botmark\kept@topmark
394 \vbox to\dimen@ 424 \else
395 {\unvbox\count@ 425 \let\firstmark\kept@firstmark
396 \ifshr@nking\vfilmaxdepth\fi}%426 \let\botmark\kept@botmark
397 }% 427 \fi

Then the last column follows. We also initalize \topmark with \kept@topmark.
398 \setbox\mult@rightbox This will make this mark okay for all middle pages
399 \vsplit\@cclv to\dimen@ of the multicols environment.
400 \set@keptmarks 428 \let\topmark\kept@topmark

18
429 h*marktracei 459 h/marktracei
430 \mult@info\tw@ Now we reset \@colroom to \@colht which is
431 {Use kept top mark:\MessageBreak LATEXs saved value of \textheight. We also have
432 \meaning\kept@topmark
to reset the recorded position of the last \marginpar
433 \MessageBreak
434 Use kept first mark:\MessageBreak
as well as the recorded size of intext floats as we are
435 \meaning\kept@firstmark now on a new page.
436 \MessageBreak 460 \global\@colroom\@colht
437 Use kept bot mark:\MessageBreak 461 \global \@mparbottom \z@
438 \meaning\kept@botmark 462 \global \@textfloatsheight \z@
439 \MessageBreak Then we process deferred floats waiting for their
440 Produce first mark:\MessageBreak chance to be placed on the next page.
441 \meaning\firstmark
463 \process@deferreds
442 \MessageBreak
464 \@whilesw\if@fcolmade\fi{\@outputpage
443 Produce bot mark:\MessageBreak
465 \global\@colroom\@colht
444 \meaning\botmark
466 \process@deferreds}%
445 \@gobbletwo}%
446 h/marktracei If the user is interested in statistics we inform him
about the amount of space reserved for floats.
With a little more effort we could have done bet-
ter. If we had, for example, recorded the shrinkage 467 \mult@info\@ne
468 {Colroom:\MessageBreak
of the material in \partial@page it would be now
469 \the\@colht\space
possible to try higher values for \dimen@ (i.e. the
470 after float space removed
column height) to overcome the problem with the 471 = \the\@colroom \@gobble}%
nonempty box 255. But this would make the code
Having done all this we must prepare to tackle the
even more complex so I skipped it in the current
next page. Therefore we assign a new value to
implementation.
\vsize. New, because \partial@page is now empty
Now we use LATEXs standard output mecha-
and \@colroom might be reduced by the space re-
nism.13 Admittedly this is a funny way to do it.
served for floats.
Within the OR \boxmaxdepth needs to be unre-
stricted so we set it back now as it was changed 472 \set@mult@vsize \global
above. The \footins skip register will be adjusted when
447 \boxmaxdepth\maxdimen the output group is closed.
448 \setbox\@cclv\vbox{\unvbox\partial@page 473 \fi}
449 \page@sofar}%
This macro is used to subtract the amount of space
The macro \@makecol adds all floats assigned for occupied by footnotes for the current space from the
the current page to this page. \@outputpage ships space available for the current column. The space
out the resulting box. Note that it is just possible current column is stored in \dimen@. See above for
that such floats are present even if we do not allow the description of the default action.
any inside a multicols environment.
474 \def\leave@mult@footins{%
450 \@makecol\@outputpage 475 \advance\dimen@-\skip\footins
After the page is shipped out we have to pre- 476 \advance\dimen@-\ht\footins
pare the kept marks for the following page. 477 }

\kept@firstmark and \kept@botmark reinitialized We left out two macros: \process@deferreds and
by setting them to \@empty. The value of \botmark \speci@ls.
is then assigned to \kept@topmark.
478 \def\speci@ls{%
451 \global\let\kept@topmark\botmark 479 \ifnum\outputpenalty <-\@Mi
452 \global\let\kept@firstmark\@empty
453 \global\let\kept@botmark\@empty
If the document ends in the middle of a mul-
454 h*marktracei
ticols environment, e.g., if the user forgot the
455 \mult@info\tw@ \end{multicols}, TEX adds a very negative
456 {(Re)Init top mark:\MessageBreak penalty to the end of the galley which is intended
457 \meaning\kept@topmark to signal the output routine that it is time to pre-
458 \@gobbletwo}% pare for shipping out everything remaining. Since
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.

19
inside multicols the output routine of LATEX is dis- 509 environment!}%
abled sometimes we better check for this case: if 510 \unvbox\@cclv\reinsert@footnotes
we find a very negative penalty we produce an error Additionally we empty the \@currlist to avoid
message and run the default output routine for this later error messages when the LATEX output routine
case. is again in force. But first we have to place the
480 \ifnum \outputpenalty<-\@MM boxes back onto the \@freelist. (\@elts default is
481 \PackageError{multicol}{Document end \relax so this is possible with \xdef.)
482 inside multicols environment}\@ehd 511 \xdef\@freelist{\@freelist\@currlist}%
483 \@specialoutput 512 \gdef\@currlist{}%
484 \else 513 \fi
For the next block of code see comments in sec- 514 \fi
tion 7.2. If the penalty is 10001 it will come from a
485 \ifnum\outputpenalty = -\@Mv \clearpage and we will execute \@doclearpage to
486 \mult@info\@ne{Forced column get rid of any deferred floats.
487 break seen}%
515 \else \@doclearpage \fi
488 \global\advance\vsize-\pagetotal
516 }
489 \global\setbox\colbreak@box
490 \vbox{% \process@deferreds is a simplified version of
491 \ifvoid\colbreak@box
LATEXs \@startpage. We first call the macro
492 \else
493 \unvbox\colbreak@box
\@floatplacement to save the current user parame-
494 \penalty-\@Mv ters in internal registers. Then we start a new group
495 \fi and save the \@deferlist temporarily in the macro
\@tempb.
As this is the place of a forced break we now remove
vertical white space just in front of it (or some of 517 \def\process@deferreds{%
518 \@floatplacement
it at least) as it is quite likely that the break is not
519 \@tryfcolumn\@deferlist
exactly in the right place, e.g., after a display envi-
520 \if@fcolmade\else
ronment (if LaTeX would break here by its own it 521 \begingroup
would break before the space following the display). 522 \let\@tempb\@deferlist
Thus we rebox box 255 once (using \maxdepth
Our next action is to (globally) empty \@deferlist
and calling \remove@discardable@items inside).
and assign a new meaning to \@elt. Here
The depth of 255 will then give us the depth the
\@scolelt is a macro that looks at the boxes in
box would have had if it would have been a nat-
a list to decide whether they should be placed on
ural break. We then unbox 255 to get it into the
the next page (i.e. on \@toplist or \@botlist) or
\colbreak@box and then back up by this depth.
should wait for further processing.
This will position the bottom of the box at its nat-
ural baseline which is useful for balancing later on. 523 \gdef\@deferlist{}%
524 \let\@elt\@scolelt

496 \boxmaxdepth\maxdepth Now we call \@tempb which has the form


497 \setbox\@cclv\vbox{% \@elthbox register i\@elthbox register i. . .
498 \unvbox\@cclv
499 \remove@discardable@items}% So \@elt (i.e. \@scolelt) will distribute the boxes
500 \dimen@\dp\@cclv to the three lists.
501 \unvbox\@cclv
525 \@tempb \endgroup
502 \kern-\dimen@
526 \fi}
503 }%
504 \reinsert@footnotes The \raggedcolumns and \flushcolumns declara-
505 \else
tions are defined with the help of a new \if...
If we encounter a float or a marginpar in the cur- macro.
rent implementation we simply warn the user that 527 \newif\ifshr@nking
this is not allowed. Then we reinsert the page and
The actual definitions are simple: we just switch to
its footnotes.
true or false depending on the desired action. To
506 \PackageWarningNoLine{multicol}%
avoid extra spaces in the output we enclose these
507 {Floats and marginpars not
changes in \@bsphack. . . \@esphack.
508 allowed inside multicols

20
528 \def\raggedcolumns{% \enlargethispage present it will apply to this page
529 \@bsphack\shr@nkingtrue\@esphack} as \multi@column@out will look at the status of
530 \def\flushcolumns{% \@kludgeins.
531 \@bsphack\shr@nkingfalse\@esphack}
552 \multi@column@out
Now for the last part of the show: the column bal- Because balancing made the columns too long
ancing output routine. Since this code is called with we are sure that there will be some material re-
an explicit penalty (\eject) there is no need to maining which was put back onto the main ver-
check for something special (eg floats). We start tical list by \multi@column@out. This will also
by balancing the material gathered. put the explicit \eject penalty back so the cur-
532 \def\balance@columns@out{% rent \balance@columns@out output routine will be
For this we need to put the contents of box 255 called again (so we better do not add another
into \mult@box. For the next block of code see penalty or else the OR will be called twice and we
also comments in section 7.2. All forced breaks ex- may get scrambled results).
cept the last are inside \colbreak@box so all we 553 \else
have to do is to concatenate this box with box If the balancing went ok, we are in the position to
\@cclv and put a penalty inbetween. Here we test apply \page@sofar. But first we have to set \vsize
if \colbreak@box is void so that the message is only to a value suitable for one column output.
generated if we really add forced breaks and the 554 \global\vsize\@colroom
penalty. 555 \global\advance\vsize\ht\partial@page
533 \setbox\mult@box\vbox{% We also have to look at \@kludgeins and generate
534 \ifvoid\colbreak@box\else
a new \insert in case there was one present due to
535 \unvbox\colbreak@box
536 \penalty-\@Mv
an \enlargethispage command.
537 \mult@info\@ne{Re-adding 556 \ifvbox\@kludgeins\insert\@kludgeins
538 forced break(s) in balancing}% 557 {\unvbox\@kludgeins}\fi
539 \fi Then we \unvbox the \partial@page (which may
540 \unvbox\@cclv be void if we are not processing the first page of this
The last column again is a forced break, so here we multicols environment.
discard white space as well as that is normally un- 558 \unvbox\partial@page
wanted.
Then we return the first and bottom mark and the
541 \remove@discardable@items
gathered material to the main vertical list.
542 }%
543 \balance@columns 559 \return@nonemptymark{first}\kept@firstmark
560 \return@nonemptymark{bot}\kept@botmark
If during balancing the columns got too long the flag 561 \page@sofar
\iftoo@bad is set to true.
We need to add a penalty at this point which allows
544 \iftoo@bad
545 \mult@info\@ne
to break at this point since calling the output rou-
546 {Balancing failed ... tine may have removed the only permissible break
547 cut a normal page}% point thereby glueing any following skip to the
balanced box. In case there are any weird settings
In that case we put the material back in box 255
for \multicolsep etc. this could produce funny re-
so that we can cut a normal page. The curious set
sults.
of \vskips we add is necessary to cancel out the
\splittopskip that got added for balancing. 562 \penalty\z@
563 \fi
548 \setbox\@cclv\vbox
564 }
549 {\vskip\topskip
550 \vskip-\splittopskip As we already know, reinserting of footnotes will be
551 \unvbox\mult@box}% done in the macro \endmulticols.
We then call the standard multicol output routine
This macro now does the actual balancing.
which will produce a normal page for us (remem-
ber we are still within the OR so some part of 565 \def\balance@columns{%
the code in \multi@column@out is actually not do- We start by setting the kept marks by updating
ing anythingperhaps this should be cleaned up at them with any marks from this box. This has to
some point). This also means that if there was an be done before we add a penalty of 10000 to the

21
top of the box, otherwise only an empty box will be \baselineskip. The coding is slightly tricky in TEX
considered. and there are perhaps better ways . . .
566 \get@keptmarks\mult@box 578 \@tempdima\ht\mult@box
579 \advance\@tempdima\dp\mult@box
We then continue by resetting trying to remove any 580 \divide\@tempdima\col@number
discardable stuff at the end of \mult@box. This is
The code above sets \@tempdima to the length of
rather experimental. We also add a forced break
a column if we simply divide the whole box into
point at the very beginning, so that we can split the
equal pieces. To get to the next lower multiple of
box to height zero later on, thereby adding a known
\baselineskip we convert this dimen to a num-
\splittopskip glue at the beginning.
ber (the number of scaled points) then divide this
567 \setbox\mult@box\vbox{% by \baselineskip (also in scaled points) and then
568 \penalty-\@M
multiply this result with \baselineskip assigning
569 \unvbox\mult@box
the result to \dimen@. This makes \dimen@ to
570 }%
\@tempdimena.
Then follow values assignments to get the 581 \count@\@tempdima
\vsplitting right. We use the natural part of 582 \divide\count@\baselineskip
\topskip as the natural part for \splittopskip 583 \dimen@\count@\baselineskip
and allow for a bit of undershoot and overshoot by Next step is to correct our result by taking
adding some stretch and shrink. into account the difference between \topskip and
571 \@tempdima\topskip \baselineskip. We start by adding \topskip; if
572 \splittopskip\@tempdima this makes the result too large then we have to sub-
573 \@plus\multicolundershoot tract one \baselineskip.
574 \@minus\multicolovershoot
584 \advance\dimen@\topskip
575 \splitmaxdepth\maxdepth
585 \ifdim \dimen@ >\@tempdima
We also have to set \boxmaxdepth which normally 586 \advance\dimen@-\baselineskip
allows to build boxes with arbitrary depth, but as 587 \fi
we are building text columns we really want to re- At the users request we start with a higher value (or
strict the depth. This is necessary as we sometimes lower, but this usually only increases the number of
rebox the boxes generated by \vsplit and then the tries).
restriction posed by \splitmaxdepth gets lost. 588 \advance\dimen@\c@unbalance\baselineskip
576 \boxmaxdepth\maxdepth We type out statistics if we were asked to do so.
The next step is a bit tricky: when TEX assem- 589 \mult@info\@ne
bles material in a box, the first line isnt preceded 590 {Balance columns\on@line:
by interline glue, i.e. there is no parameter like 591 \ifnum\c@unbalance=\z@\else
\boxtopskip in TEX. This means that the baseline 592 (off balance=\number\c@unbalance)\fi
593 \@gobbletwo}%
of the first line in our box is at some unpredictable
point depending on the height of the largest charac- But we dont allow nonsense values for a start.
ter in this line. But of course we want all columns 594 \ifnum\dimen@<\topskip
to align properly at the baselines of their first lines. 595 \mult@info\@ne
For this reason we have opened \mult@box with a 596 {Start value
597 \the\dimen@ \space ->
\penalty -10000. This will now allow us to split
598 \the\topskip \space (corrected)}%
off from \mult@box a tiny bit (in fact nothing since 599 \dimen@\topskip
the first possible break-point is the first item in the 600 \fi
box). The result is that \splittopskip is inserted
Now we try to find the final column height. We start
at the top of \mult@box which is exactly what we
by setting \vbadness to infinity (i.e. 10000) to sup-
like to achieve.
press underfull box reports while we are trying to
577 \setbox\@tempboxa\vsplit\mult@box to\z@ find an acceptable solution. We do not need to do
Next we try to find a suitable starting point for it in a group since at the end of the output routine
the calculation of the column height. It should be everything will be restored. The setting of the final
less than the height finally chosen, but large enough columns will nearly always produce underfull boxes
to reach this final value in only a few iterations. with badness 10000 so there is no point in warning
The formula which is now implemented will try to the user about it.
start with the nearest value which is a multiple of 601 \vbadness\@M

22
We also allow for overfull boxes while we trying to 621 \ifnum\c@tracingmulticols>\@ne
split the columns. They can easily happen if we have 622 \@tempcnta\count@
objects with unusual depth. 623 \advance\@tempcnta-\mult@grightbox
624 \divide\@tempcnta \tw@
602 \vfuzz \maxdimen
625 \message{^^JColumn
The variable \last@try will hold the dimension 626 \number\@tempcnta\space
used in the previous trial splitting. We initialize 627 badness: \the\badness\space}%
it with a negative value. 628 \fi
603 \last@try-\p@ If this badness is larger than the allowed column
604 \loop badness we reject this solution by setting too@bad
In order not to clutter up TEXs valuable main to true.
memory with things that are no longer needed, we 629 \ifnum\badness>\c@columnbadness
empty all globally used box registers. This is neces- 630 \ifnum\c@tracingmulticols>\@ne
sary if we return to this point after an unsuccessful 631 \message{too bad
trial. We use \process@cols for this purpose, start- 632 (>\the\c@columnbadness)}%
ing with \mult@grightbox. Note the extra braces 633 \fi
634 \too@badtrue
around this macro call. They are needed since
635 \fi
Plain TEXs \loop. . . \repeat mechanism cannot 636 h/badnessi
be nested on the same level of grouping. 637 }}%
605 {\process@cols\mult@grightbox There is one subtle point here: while all other con-
606 {\global\setbox\count@
structed boxes have a depth that is determined
607 \box\voidb@x}}%
by \splitmaxdepth and/or \boxmaxdepth the last
The contents of box \mult@box are now copied glob- box will get a natural depth disregarding the orig-
ally to box \mult@grightbox. (This will be the inal setting and the value of \splitmaxdepth or
right-most column, as we shall see later.) \boxmaxdepth. This means that we may end up
608 \global\setbox\mult@grightbox with a very large depth in box \mult@grightbox
609 \copy\mult@box which would make the result of the testing incor-
We start with the assumption that the trial will be rect. So we change the value by unboxing the box
successful. If we end up with a solution that is too into itself.
bad we set too@bad to true. We also assume that 638 \global\setbox\mult@grightbox
all forced breaks (if any) will be used during bal- 639 \vbox{\unvbox\mult@grightbox}%
ancing. If this is not the case we record this in We also save a copy \mult@firstbox at its natu-
forcedbreak@leftover. ral size for later use.
610 h*badnessi 640 \setbox\mult@nat@firstbox
611 \too@badfalse 641 \vbox{\unvcopy\mult@firstbox}%
612 \forcedbreak@leftoverfalse After \process@cols has done its job we have the
613 h/badnessi
following situation:
Using \vsplit we extract the other columns from
box register \mult@grightbox. This leaves box reg- box \mult@rightbox all material
ister \mult@box untouched so that we can start over box \mult@gfirstbox first column
again if this trial was unsuccessful. box \mult@gfirstbox + 2 second column
.. ..
614 {\process@cols\mult@firstbox{% . .
615 \global\setbox\count@ box \mult@grightbox last column
616 \vsplit\mult@grightbox to\dimen@
We report the height of the first column, in brackets
After splitting we need to ensure that there isnt any the natural size is given.
space at the bottom, so we rebox once more.
642 \ifnum\c@tracingmulticols>\@ne
617 \global\setbox\count@ 643 \message{^^JFirst column
618 \vbox to\dimen@ 644 = \the\dimen@\space
619 {\unvbox\count@}% 645 (\the\ht\mult@nat@firstbox)}\fi
After every split we check the badness of the result- If \raggedcolumns is in force older releases of this
ing column, normally the amount of extra white in file also shrank the first column to its natural height
the column. at this point. This was done so that the first col-
620 h*badnessi umn doesnt run short compared to later columns

23
but it is actually producing incorrect results (over- 672 \copy\mult@grightbox
printing of text) in boundary cases, so since version 673 \setbox\z@\vsplit\@tempboxa to\maxdimen
v1.5q \raggedcolumns means allows for all columns 674 \ifvoid\@tempboxa
to run slightly short. Thus if \@tempboxa is void we have a valid solution.
646 % \ifshr@nking In this case we take a closer look at the last column
647 % \global\setbox\mult@firstbox to decide if this column should be made as long as
648 % \copy\mult@nat@firstbox all other columns or if it should be allowed to be
649 % \fi shorter. For this we first have to rebox the column
Then we give information about the last column.14 into a box of the appropriate height. If tracing is
650 \ifnum\c@tracingmulticols>\@ne enabled we then display the badness for this box.
651 \message{<> last column = 675 \global\setbox\mult@grightbox
652 \the\ht\mult@grightbox^^J}% 676 \vbox to\dimen@
677 {\unvbox\mult@grightbox}%
Some tracing code that we dont compile into the
678 \ifnum\c@tracingmulticols>\@ne
production version unless asked for. It will produce 679 \message{Final badness:
huge listings of the boxes involved in balancing in 680 \the\badness}%
the transcript file. 681 \fi
653 h*debugi We then compare this badness with the allowed bad-
654 \ifnum\c@tracingmulticols>4 ness for the final column. If it does not exceed this
655 {\showoutput
value we use the box, otherwise we rebox it once
656 \batchmode
657 \process@cols\mult@grightbox
more and add some glue at the bottom.
658 {\showbox\count@}}% 682 \ifnum\badness>\c@finalcolumnbadness
659 \errorstopmode 683 \global\setbox\mult@grightbox
660 \fi 684 \vbox to\dimen@
661 h/debugi 685 {\unvbox\mult@grightbox\vfil}%
662 \fi 686 \ifnum\c@tracingmulticols>\@ne
687 \message{ setting natural
We check whether our trial was successful. The test
688 (> \the\c@finalcolumnbadness)}%
used is very simple: we merely compare the first and 689 \fi
the last column. Thus the intermediate columns 690 \fi
may be longer than the first if \raggedcolumns
If \@tempboxa above was not void our trial was un-
is used. If the right-most column is longer than
successful and we report this fact and try again.
the first then we start over with a larger value for
\dimen@. 691 \else
663 \ifdim\ht\mult@grightbox >\dimen@ If we have unprocessed forced breaks we normally
reiterate with a larger column size to fit them in
If the height of the last box is too large we mark this
eventually. However, if there are simply too many
trial as unsuccessful.
of them (e.g., 3 forced breaks but only 2 columns
664 h*badnessi to balance) then this will never succeed and and
665 \too@badtrue
we would continue growing the columns until we
666 \ifnum\c@tracingmulticols>\@ne
hit the largest possible column size. So in ad-
667 \typeout{Rejected: last
668 column too large!}% dition we check how big the column size is com-
669 \fi pared to available room and if we exceed this by
670 \else \maxbalancingoverflow we give up and instead of
balancing cut another normal page. To be indicate
To ensure that there isnt a forced break in the last
this case we set forcedbreak@leftover to true.
column we try to split off a box of size \maxdimen
from \mult@grightbox (or rather from a copy of it). 692 \@tempdima\@colroom
This should result in a void box after the split, un- 693 \advance\@tempdima \maxbalancingoverflow
694 \ifdim \dimen@ < \@tempdima
less there was a forced break somewhere within the
695 \too@badtrue
column in which case the material after the break 696 \ifnum\c@tracingmulticols>\@ne
would have stayed in the box. 697 \typeout{Rejected: unprocessed
671 \setbox\@tempboxa 698 forced break(s) in last column!}%
14 With TEX version 3.141 it is now possible to use LATEXs \newlinechar in the \message command, but people with older
TEX versions will now get ^^J instead of a new line on the screen.

24
699 \fi shrinkability to allow this.16 However, this squeez-
700 \else ing should only be done if we are balancing columns
701 \forcedbreak@leftovertrue on the main galley and not if we are building a boxed
702 \ifnum\c@tracingmulticols>\@ne multicol (in the latter case the current \@colroom is
703 \typeout{Failed: columns too large irrelevant since the produced box might be moved
704 with unprocessed forced break(s)!}%
anywhere at a later stage).
705 \fi
706 \fi 728 \if@boxedmulticols\else
707 \fi 729 \ifdim\dimen@>\@colroom
708 \fi 730 \dimen@\@colroom
731 \fi
If the natural height of the first box is smaller than 732 \fi
the current trial size but is larger than the previous
Then we move the contents of the odd-numbered
trial size it is likely that we have missed a poten-
box registers to the even-numbered ones, shrinking
tially better solution. (This could have happened if
them if requested. We have to use \vbox not \vtop
for some reason our first trial size was too high.) In
(as it was done in the first versions) since otherwise
that case we dismiss this trial and restart using the
the resulting boxes will have no height (TEXbook
natural height for the next trial.
page 81). This would mean that extra \topskip
709 \ifdim\ht\mult@nat@firstbox<\dimen@ is added when the boxes are returned to the page-
710 \ifdim\ht\mult@nat@firstbox>\last@try builder via \page@sofar.
711 \too@badtrue
712 \ifnum\c@tracingmulticols>\@ne 733 \process@cols\mult@rightbox
713 \typeout{Retry: using natural 734 {\@tempcnta\count@
714 height of first column!}% 735 \advance\@tempcnta\@ne
715 \fi when putting the final column together we want
716 \dimen@\ht\mult@nat@firstbox overfull information:
717 \last@try\dimen@
736 \vfuzz\z@
718 \advance\dimen@-\p@
737 \setbox\count@\vbox to\dimen@
719 \fi
738 {%
720 \fi
Finally the switch too@bad is tested. If it was made 739 \vskip \z@
true either earlier on or due to a rightmost column 740 \@plus-\multicolundershoot
741 \@minus-\multicolovershoot
being too large we try again with a slightly larger
742 \unvbox\@tempcnta
value for \dimen@. 743 \ifshr@nking\vfilmaxdepth\fi
721 \iftoo@bad 744 }%
722 h/badnessi
723 \advance\dimen@\p@ If the resulting box is overfull there was too much
724 \repeat material to fit into the available space. The ques-
tion though is how much? If it wasnt more than
If we come out of the loop with the switch \maxbalancingoverflow we accept it still to avoid
forcedbreak@leftover set to true then balancing getting very little material for the next page (which
has failed and we should cut a normal page. We we would then have difficulties to balance).
indicate this below with \too@badtrue when any of
745 \ifnum\badness>\@M
the columns get too high, so we set this flag here too
746 \vfuzz\maxdimen % no overfull warning
in order to get the same processing logic.15 747 \setbox\@tempboxa \vbox to\dimen@
725 \ifforcedbreak@leftover 748 {\vskip-\maxbalancingoverflow
726 \too@badtrue 749 \unvcopy\count@}%
727 \else 750 \ifnum\badness>\@M
751 \mult@info\@ne
At that point \dimen@ holds the height that was de-
752 {Balanced column more than
termined by the balancing loop. If that height for 753 \the\maxbalancingoverflow\space
the columns turns out to be larger than the available 754 too large}%
space (which is \@colroom) we squeeze the columns
Fail the balancing attempt:
into the space assuming that they will have enough
15 Shouldget cleaned up as we now have two different routes to reach this part of the processing.
16 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.

25
755 \too@badtrue Finally end the \ifforcedbreak@leftover condi-
756 \else tional.
Otherwise report that there is a problem but within 764 \fi
the accepted boundary. 765 }
757 \mult@info\@ne
758 {Balanced column Amount that balancing is allowed to overflow the
759 too large, but less than
available column space. We default to 12pt which
760 \the\maxbalancingoverflow}%
means about one line in most layouts.
761 \fi
762 \fi 766 \newdimen\maxbalancingoverflow
763 }% 767 \maxbalancingoverflow=12pt

4.5 The box allocations

Early releases of these macros used the first box 771 \newbox\mult@firstbox
registers 0, 2, 4,. . . for global boxes and 1, 3, 5,. . . 772 \newbox\@tempa\newbox\@tempa
for the corresponding local boxes. (You might still 773 \newbox\@tempa\newbox\@tempa
find some traces of this setup in the documentation, 774 \newbox\@tempa\newbox\@tempa
775 \newbox\@tempa\newbox\@tempa
sigh.) This produced a problem at the moment we
776 \newbox\@tempa\newbox\@tempa
had more than 5 columns because then officially allo-
777 \newbox\@tempa\newbox\@tempa
cated boxes were overwritten by the algorithm. The 778 \newbox\@tempa\newbox\@tempa
new release now uses private box registers 779 \newbox\@tempa\newbox\@tempa
768 \newbox\mult@rightbox 780 \newbox\@tempa
769 \newbox\mult@grightbox 781 \let\@tempa\relax
770 \newbox\mult@gfirstbox

5 New macros and hacks for version 1.2


If we dont use TEX 3.0 \emergencystretch is un- 790 \@largefloatcheck
defined so in this case we simply add it as an unused 791 \outer@nobreak
hdimeni register. This is cheap (deferring the floats until after the cur-
782 \@ifundefined{emergencystretch} rent page) but any other solution would go deep into
783 {\newdimen\emergencystretch}{} LATEXs output routine and I dont like to work on it
My tests showed that the following for- until I know which parts of the output routine have
mula worked pretty well. Nevertheless the to be reimplemented anyway for LATEX3.
\setemergencystretch macro also gets \hsize as 792 \ifnum\@floatpenalty<\z@
second argument to enable the user to try different We have to add the float to the \@deferlist be-
formulae. cause we assume that outside the multicols environ-
784 \def\setemergencystretch#1#2{% ment we are in one column mode. This is not en-
785 \emergencystretch 4pt tirely correct, I already used the multicols environ-
786 \multiply\emergencystretch#1} ment inside of LATEXs \twocolumn declaration but
it will do for most applications.
Even if this should be used as a hook we use a @ in 793 \@cons\@deferlist\@currbox
the name since it is more for experts. 794 \fi
787\def\set@floatcmds{% 795 \ifnum\@floatpenalty=-\@Mii
788 \let\@dblfloat\@dbflt 796 \@Esphack
789 \def\end@dblfloat{\@endfloatbox 797 \fi}}

5.1 Maintaining the mark registers

This section contains the routines that set the marks been introduced with version 1.4.
so that they will be handled correctly. They have
First thing we do is to reserve three macro names

26
to hold the replacement text for TEXs primitives takes one argument: the box register number or its
\firstmark, \botmark and \topmark. We initial- nick name defined by \newbox.
ize the first two to be empty and \kept@topmark to 815 \def\get@keptmarks#1{%
contain two empty pair of braces. This is necessary For debugging purposes we take a look at the cur-
since \kept@topmark is supposed to contain the last rent dimensions of the box since in earlier versions
mark from a preceding page and in LATEX any real of the code I made some mistakes in this area.
mark must contain two parts representing left and
816 h*debugi
right mark information. 817 \typeout{Mark box #1 before:
798 \def\kept@topmark{{}{}} 818 ht \the\ht#1, dp \the\dp#1}%
799 \let\kept@firstmark\@empty 819 h/debugi
800 \let\kept@botmark\@empty
Now we open a new group an locally copy the box to
itself. As a result any operation, i.e. \vsplit, will
Sometimes we want to return the value of a
only have a local effect. Without this trick the box
kept mark into a \mark node on the main
content would get lost up to the level where the last
vertical list. This is done by the function
assignment to the box register was done.
\return@nonemptymark. As the name suggests it
820 \begingroup
only acts if the replacement text of the kept mark is
821 \vbadness\@M
non-empty. This is done to avoid adding an empty 822 \setbox#1\copy#1%
mark when no mark was actually present. If we
would nevertheless add such a mark it would be re- Now we split the box to the maximal possible di-
garded as a valid \firstmark later on. mension. This should split off the full contents of
the box so that effectively everything is split off. As
801 \def\return@nonemptymark#1#2{% a result \splitfirstmark and \splitbotmark will
802 \ifx#2\@empty
contain the first and last mark in the box respec-
803 \else
tively.
For debugging purposes we take a look at the value 823 \setbox#1\vsplit#1to\maxdimen
of the kept mark that we are about to return. This
Therefore we can now set the kept marks which is
code will get stripped out for production.
a global operation and afterwards close the group.
804 h*marktracei This will restore the original box contents.
805 \mult@info\tw@
824 \set@keptmarks
806 {Returned #1 mark:\MessageBreak
825 \endgroup
807 \meaning#2}%
808 % \nobreak For debugging we take again a look at the box di-
809 % \fi mension which shouldnt have changed.
810 h/marktracei 826 h*debugi
Since the contents of the mark may be arbitrary 827 \typeout{Mark box #1 \space after:
LATEX code we better make sure that it doesnt get 828 ht \the\ht#1, dp \the\dp#1}%
829 h/debugi
expanded any further. (Some expansion have been
830 }
done already during the execution of \markright or
\markboth.) We therefore use the usual mechanism The macro \set@keptmarks is responsible for set-
of a toks register to prohibit expansion.17 ting \kept@firstmark and \kept@botmark, by
811 \toks@\expandafter{#2}% checking the current values for \splitfirstmark
812 \mark{\the\toks@}% and \splitbotmark.
We dont want any breakpoint between such a re- 831 \def\set@keptmarks{%
turned mark and the following material (which is If \kept@firstmark is empty we assume that it
usually just the box where the mark came from). isnt set. This is strictly speaking not correct as
813 \nobreak we loose the ability to have marks that are explic-
814 \fi} itly empty, but for standard LATEX application it is
sufficient. If it is non-empty we dont change the
If we have some material in a box register we may valuewithin the output routines it will then be re-
want to get the first and the last mark out of this stored to \@empty.
box. This can be done with \get@keptmarks which 832 \ifx\kept@firstmark\@empty
17 Due to the current definition of \markright etc. it wouldnt help to define the \protect command to prohibit expansion
as any \protect has already vanished due to earlier expansions.

27
We now put the contents of \splitfirstmark into list we assume that this is a desired space. We
\kept@firstmark. In the case that there wasnt therefore stop the recursion and reinsert the spaces.
any mark at all \kept@firstmark will not change As the multicol code sometimes add an explicit
by that operation. penalty at the end of a column we first attempt to
833 \expandafter\gdef\expandafter remove it in case it is there.
834 \kept@firstmark 860 \skip0=0pt
835 \expandafter{\splitfirstmark}% 861 \edef\the@zero@skip{\the\skip0}
862 \def\remove@discardable@items{%
When debugging we show the assignment but only
863 \unpenalty
when something actually happened.
Save a previous skip (if there) and then remove it,
836 h*marktracei
we cant really tell the difference between no skip an
837 \ifx\kept@firstmark\@empty\else
838 \mult@info\tw@ a skip of zero but thats life.
839 {Set kept first mark:\MessageBreak 864 \edef\@tempa{\the\lastskip}%
840 \meaning\kept@firstmark% 865 %\typeout{s1=\@tempa}%
841 \@gobbletwo}% 866 \unskip
842 \fi If it was a zero skip (or none) we save the next pre-
843 h/marktracei vious skip (if any).
844 \fi 867 \ifx\@tempa\the@zero@skip
We always try to set the bottom mark to the 868 \edef\@tempb{\the\lastskip}%
\splitbotmark but of course only when there has 869 %\typeout{s2=\@tempb}%
been a \splitbotmark at all. Again, we assume If this one again was zero (or more likely not there
that an empty \splitbotmark means that the split in the first place) we stop.
off box part didnt contain any marks at all. 870 \ifx\@tempb\the@zero@skip
845 \expandafter\def\expandafter\@tempa 871 \else
846 \expandafter{\splitbotmark}% Otherwise we remove this real skip. Then we look
847 \ifx\@tempa\@empty\else if it was preceeded by a penalty of 10000 (i.e., a
848 \global\let\kept@botmark\@tempa \nobreak)
849 h*marktracei
872 \unskip
850 \mult@info\tw@
873 %\typeout{p=\lastpenalty}%
851 {Set kept bot mark:\MessageBreak
874 \ifnum \lastpenalty=\@M
852 \meaning\kept@botmark%
853 \@gobbletwo}% If so this was a \vspace* or something equivalent
854 h/marktracei to it. Therefore we reintroduce the skips and stop.
855 \fi}% Otherwise we recurse.
875 \vskip\@tempb\vskip\@tempa\relax
The \prep@keptmarks function is used to initialize 876 \else
the kept marks from the contents of \partial@page, 877 \remove@discardable@items
i.e. the box that holds everything from the top of the 878 \fi
current page prior to starting the multicols environ- 879 \fi
ment. However, such a box is only available if we 880 \else
are not producing a boxed multicols. If the first skip was a non-zero skip we recurse as
856 \def\prep@keptmarks{% well.
857 \if@boxedmulticols \else 881 \remove@discardable@items
858 \get@keptmarks\partial@page 882 \fi
859 \fi} 883 }
884 h*badnessi
There are situations when we may have some space 885 \newif\iftoo@bad
at the end of a column and this macro here will at- 886 \def\too@badtrue{\global\let\iftoo@bad\iftrue}
tempt to get rid of it. The typical LATEX sequence is 887 \def\too@badfalse{\global\let\iftoo@bad\iffalse}
a series of selfcanceling glues so if we remove them
888 \newif\ifforcedbreak@leftover
recursively we are usually fine.
Special care is needed with handling
\vspace* as that corresponds to \penalty10000, 889 \newcount\c@columnbadness
\vskip <skip>, followed by \vskip 0pt. If we see 890 \c@columnbadness=10000
this sequence going backwards in the the vertical 891 \newcount\c@finalcolumnbadness

28
892 \c@finalcolumnbadness=9999 901 h/badnessi
893
894 \newdimen\last@try A helper for producing info messages
895 902 \def\mult@info#1#2{%
903 \ifnum\c@tracingmulticols>#1%
896 \newdimen\multicolovershoot 904 \GenericWarning
897 \newdimen\multicolundershoot 905 {(multicol)\@spaces\@spaces}%
898 \multicolovershoot=0pt 906 {Package multicol: #2}%
899 \multicolundershoot=2pt 907 \fi
900 \newbox\mult@nat@firstbox 908 }

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 than 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, except 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 921 }
to this package over time. Not all of them may be
When ending the environment we simply end the in-
active, some might sit dormant and wait for being
ner multicols environment, except that we better
activated in some later release.
also stick in some stretchable vertical glue so that
the last column still containing text is not vertically
7.1 Not balancing the columns stretched out.
This is fairly trivial to implement. we just have to We do this as follows: first we ensure that we
disable the balancing output routine and replace it are back in vertical mode and then we cancel out
by the one that ships out the other pages. \lastskip if it was positive (in case of a negative
glue we assume that it was deliberate, for a delib-
The code for this environment was suggested by erate positive glue one needs to use \vspace*). We
Matthias Clasen. cant simply use \remove@discardable@items here
909 h*nobalancei as this only works inside boxes but we are here on
910 \@namedef{multicols*}{% the main vertical list.
If we are not on the main galley, i.e., inside a box Then we back up by \prevdepth but not more
of some sort, that approach will not work since we than \boxmaxdepth so that a baseline of the last
dont have a vertical size for the box so we better box is now at the bottom. This way the material
warn that we balance anyway. will align properly in case something like \vfill
spreads it out after all. Finally we append \vfil
911 \ifinner
912 \PackageWarning{multicol}% to put white space at the bottom of the column,
913 {multicols* inside a box does but we only do this if we arent anyway doing
914 not make sense.\MessageBreak \raggedcolumns.
915 Going to balance anyway}% 922 \@namedef{endmulticols*}{%
916 \else 923 \par
917 \let\balance@columns@out 924 \ifdim\lastskip>\z@ \vskip-\lastskip \fi
918 \multi@column@out 925 \ifdim \prevdepth>\z@
919 \fi 926 \vskip-\ifdim\prevdepth>\boxmaxdepth
920 \begin{multicols} 927 \boxmaxdepth

29
928 \else \prevdepth \fi 944 \penalty -\@Mv\relax
929 \fi 945 \else
930 \ifshr@nking\else 946 \@bsphack
931 \vfil 947 \vadjust{\penalty -\@Mv\relax}%
932 \fi 948 \@esphack
933 \end{multicols}} 949 \fi
934 h/nobalancei 950 \fi}

Need a box to collect the galley up to the column


7.2 Manual column breaking break.
The problem with manual page breaks within multi- 951 \newbox\colbreak@box
cols is the fact that during collection of material for 952 h/packagei
all columns a page-forcing penalty (i.e. -10000 or
higher) would stop the collecting pass which is not 7.3 Supporting right-to-left lan-
quite what is desired. On the other hand, using a
penalty like -9999 would mean that there would be
guages
occasions where the \vspliting operations within \LR@column@boxes is called when we are assembling
multicols would ignore that penalty and still choose the columns for left to right typesetting. When we
a different break point. start we are inside an \hbox of full width. Left to
For this reason the current implementation uses right typesetting is fairly easy, we basically output
a completely different approach. In a nutshell it each column box intermixed with vertical rules and
extends the LATEX output routine handling by in- proper spacing. As this happens inside a box of a
troducing an additional penalty flag (i.e., a penalty defined width the rules and the columns automati-
which is forcing but higher than -10000 so that the cally get into the right positions.
output routine can look at this value and thus knows 953 \def\LR@column@boxes{%
why it has been called).
We loop through the columns with \process@cols
Inside the output routine we test for this value
and if it appears we do two things: save the galley 954 \process@cols\mult@gfirstbox{%
up to this point in a special box for later use and re- If the depth of the current box is larger than the
duce the \vsize by the height of the material seen. maximum found so far in \dimen2 we update that
This way the forcing penalty is now hidden in that register for later use.
box and we can restart the collection process for 955 \ifdim\dp\count@>\dimen\tw@
the remaining columns. (This is done in \speci@ls 956 \global\dimen\tw@\dp\count@ \fi
above.) If the colaction option is given we write out sta-
In the output routines that do the \vsplitting tus information about the current column, otherwise
either for balancing or for a full page we simply com- the next command does nothing.
bine box 255 with the saved box thus getting a single
957 \mc@col@status@write
box for splitting which now contains forcing breaks
in the right positions. The typeset box followed by the column rule mate-
rial
\columnbreak is modelled after \pagebreak except 958 \box\count@
that we generate a penalty -10005. 959 \hss{\columnseprulecolor\vrule
935 \mathchardef\@Mv=10005 960 \@width\columnseprule}\hss}%
936 \def\columnbreak{% As you will have noticed, we started with box
We have to ensure that it is only used within a mul- register \mult@gfirstbox (i.e. the left column).
ticols environment since if that penalty would be So this time \count@ looped through 2, 4,. . .
seen by the unmodified LATEX output routine strange (plus the appropriate offset). Finally we add box
things would happen. \mult@rightbox and we are done. Again we may
937 \ifnum\col@number<\tw@ have to update \dimen\tw@.
938 \PackageError{multicol}% 961 \ifdim\dp\mult@rightbox>\dimen\tw@
939 {\noexpand\columnbreak outside multicols}% 962 \global\dimen\tw@\dp\mult@rightbox \fi
940 {This command can only be used within If the colaction option is given we write out status
941 a multicols or multicols* environment.}%
information about the last column, otherwise the
942 \else
next command does nothing.
943 \ifvmode

30
963 \mc@lastcol@status@write 985 \mc@lastcol@status@write
964 \box\mult@rightbox 986 \box\mult@rightbox
965 } 987 \hskip-\hsize

Assembling the boxes for right to left typesetting is However we do have to move the reference point to
far more complicated. When I first tried to build a its right place: to make the rules appear at the ex-
solution for this my thinking was that all that is nec- pected places, we should get the typesetting position
essary to do is to reverse the order of the columns. to the far right again. As we at the moment at the
But such an approach produces a subtle bug: If we far left we skip to the far right like this:
work this way then the first column put on the page 988 \hskip\full@width
will be the last column of the text to read. and this 989 }
means that the order in which TEX executes write Macros to switch between left-right and right-
statements or assembles mark material will not hap- left typesetting. In LR typesetting the
pen in the order of the textual flow. So if, for exam- \LR@column@boxes is used to combine the
ple each column contains a section command then columns. When typesetting right to left the
these sections will appear in reverse order in the ta- \RL@column@boxes is used instead.
ble of content.
990 \newcommand\RLmulticolcolumns
For this reason some amount of gymnastics is 991 {\let\mc@align@columns
needed to add the columns in their natural flow. 992 \RL@column@boxes}
966 \def\RL@column@boxes{% 993 \newcommand\LRmulticolcolumns
First step is to put all rules in the right place (with- 994 {\let\mc@align@columns
out adding the comes which are instead represented 995 \LR@column@boxes}
by a space of \hsize. The default is left-to-right:
967 \process@cols\mult@gfirstbox{% 996 \LRmulticolcolumns
968 \hskip\hsize
969 \hss{\columnseprulecolor\vrule 7.4 Supporting \docolaction
970 \@width\columnseprule}\hss
971 }% Whenever we want to do something that depends on
972 \hskip\hsize the current column we execute \docolaction. This
At this point in the code our typesetting reference command takes one optional and three mandatory
point is at the right end of the rightmost column (or arguments. The mandatory ones denote what to do
rather where that column should appear). if this is a left, middle, or right column and
We are now typesetting all columns by first back- the optional one is simply there to say what to do if
ing up by their width (which is \hsize) then type- we dont know (default is to use the left column
setting the box and then backing up again, but this action in that case).
time further, i.e., also across the column separation.
We use one counter \mc@col@check@num to gener-
That will then enable us to typeset the next column
ate us unique label names. Each time we execute
using the same approach until we are done with all
\docolaction we increment this counter to get a
but the final column.
new name.
973 \process@cols\mult@gfirstbox{%
997 \newcount\mc@col@check@num
974 \ifdim\dp\count@>\dimen\tw@
975 \global\dimen\tw@\dp\count@ \fi The generated labels are named
976 \hskip-\hsize
\mc@col-\the\mc@col@check@num
977 \mc@col@status@write
978 \box\count@ and they hold as values the numbers 1, 2, or 3 de-
979 \hskip-\hsize noting the current column type.
980 \hskip-\columnsep
981 }%
998 \newcommand\docolaction[4][1]{%
The approach for the final column is similar only 999 \ifx\mc@col@status@write\relax
that we do not have to back up over any column 1000 \PackageError{multicol}%
gap. 1001 {Option colaction not selected}%
982 \ifdim\dp\mult@rightbox>\dimen\tw@ 1002 {\string\docolaction\space
983 \global\dimen\tw@\dp\mult@rightbox \fi 1003 requires the use of the colaction
984 \hskip-\hsize 1004 option on the package}%

31
1005 \fi page. The\mc@set@col@status lines have been
1006 \global\advance\mc@col@check@num\@ne written out as part of shipping the column
1007 \edef\mc@col@type{\expandafter\ifx boxes out, e.g., \mc@set@col@status{lcol-1}{0}
1008 \csname mc@col-\the\mc@col@check@num was therefore somewhere within the first column
1009 \endcsname\relax as it appears between \mc@col@status{1} and
1010 0\else
\mc@col@status{2} The second argument in that
1011 \csname mc@col-\the\mc@col@check@num
line is the value used in the previous run (or zero
1012 \endcsname
1013 \fi}% if there was no previous run. We can use this to
determine if a rerun is necessary.
We prefix with 0 so that an unknown label (that Thus with this knowledge we can set things up to
returns \relax) will result in case 0 get the labels working.
1014 \ifcase \mc@col@type\relax
If column is unknown we use the default action or When the aux file is read in \mc@col@status is used
the action denoted by the optional argument (so to set \mc@curr@col@status:
that arg can take the value 1, 2, 3). 1031 \def\mc@col@status#1{%
1015 \ifcase #1\or #2\or#3\or#4\fi 1032 \gdef\mc@curr@col@status{#1}}
1016 \or
And when \mc@set@col@status is executed we can
Otherwise we know (or think we know) that this is simply set up the label by associating it with the
a first, middle, or last column: \mc@curr@col@status and ignore the second argu-
1017 #2% % 1 First col ment:
1018 \or 1033 \def\mc@set@col@status#1#2{%
1019 #3% % 2 any middle col 1034 \global\expandafter\let\csname #1\endcsname
1020 \or 1035 \mc@curr@col@status}
1021 #4% % 3 last col
1022 \else The above definition is being used when the .aux file
1023 \ERROR is read in at the beginning. At the end we need a
1024 \fi different definition to test if another typesetting run
But how does the column number get associated is needed. There we compare the value used in the
with our label? We do do this by writing another current run (stored in the second argument) with
line into the aux file at this point: the value used on the next run. If those two values
differ we set @tempswa to false which will trigger the
1025 \edef\next{\write\@auxout
Label(s) may have changed warning.
1026 {\string\mc@set@col@status
1027 {mc@col-\the\mc@col@check@num}% 1036 \AtEndDocument{\def\mc@set@col@status#1#2{%
1028 {\mc@col@type}}}% 1037 \ifnum #2=\mc@curr@col@status\else
1029 \next 1038 \@tempswatrue
1030 } 1039 \fi}%
1040 }
Because of extra data writing to the aux file the
aux file will now contain something like the following Finally, as part of determining in which column we
after the document is processed the first time: are, we used a switch inside \mc@col@status@write
to determine if we are in the first column or not.
\relax 1041 \newif\ifmc@firstcol
\mc@col@status{1} 1042 \mc@firstcoltrue
\mc@set@col@status{lcol-1}{0}
\mc@col@status{2}
\mc@set@col@status{lcol-2}{0}
\mc@col@status{3}
\mc@set@col@status{lcol-3}{0}
\mc@col@status{1}
\mc@col@status{2}
\mc@col@status{3}
\mc@set@col@status{lcol-4}{0}

The \mc@col@status line denotes the column


type and has been written out just before cor-
responding the column box was placed onto the

32
Index
Numbers written in italic refer to the page where the corresponding entry is described; numbers underlined
refer to the code line of the definition; numbers in roman refer to the code lines where the entry is used.

Symbols \endmulticols* . . 922 \mc@col@status . 1031 \partial@page . . . 292


\@footnotetext . . 909 \enough@room . . . . 133 \mc@firstcol . . . 1041 \postmulticols 3, 292
\mc@set@col@status \premulticols . 2, 292
B F . . . . . . . . . 1033 \prep@keptmarks . 856
\balance@columns 565 \flushcolumns . . . 527 \mult@@cols . . . . . . 96 \prepare@multicols 150
\balance@columns@out \mult@cols . . . . . . 93 \process@cols . . . 316
. . . . . . . . . . 532 G \mult@firstbox . . 768 \process@deferreds 517
\get@keptmarks . . 815 \mult@footnotetext
C . . . . . . . 90, 909 R
I
\c@collectmore . . 292 \mult@gfirstbox . 768 \raggedcolumns . . 527
\if@boxedmulticols 130
\c@columnbadness 889 \mult@grightbox . 768 \reinsert@footnotes
\ifshr@nking . . . . 527
\c@finalcolumnbadness \mult@info . . . . . 902 . . . . . . . . . . 359
\init@mult@footins 221
. . . . . . . . . . 889 \mult@rightbox . . 768 \remove@discardable@items
\c@unbalance . . . . 293 K \multi@column@out 363 . . . . . . . . . . 860
\col@number . . . . . 292 \kept@botmark . . . 798 \multicol@leftmargin \return@nonemptymark
\colbreak@box . . . 951 \kept@firstmark . 798 . . . . . . . . . . 235 . . . . . . . . . . 801
\columnbreak . . . . 935 \kept@topmark . . . 798 \multicolbaselineskip \RL@column@boxes 966
\columnsep . . . . . . . 3 . . . . . . . . 3, 292 \RLmulticolcolumns 990
\columnseprule . . . . 3 L \multicolpretolerance
\columnseprulecolor \leave@mult@footins . . . . . . . . 3, 292 S
. . . . . . . . 3, 358 . . . . . . . . . . 474 \multicols . . . . . . 70 \set@floatcmds . . 787
\LR@column@boxes 953 \multicols* . . . . . 909 \set@keptmarks . . 831
D \LRmulticolcolumns 990 \multicolsep . . 3, 292 \set@mult@vsize . 225
\docolaction . . . . 998 \multicoltolerance \setemergencystretch
\doublecol@number 292 M . . . . . . . . 3, 292 . . . . . . . . . . 782
\maxbalancingoverflow \speci@ls . . . . . . 478
E . . . . . . . . . . 766 P
\emergencystretch 782 \mc@align@columns 990 \page@free . . . . . 292 V
\endmulticols . . . 236 \mc@col@check@num 997 \page@sofar . . . . . 325 \vfilmaxdepth . . . 361

Change History

v1.0c v1.1a
\enough@room: Penalty 0 added to empty the \flushcolumns: \flushedcolumns renamed to
contribution list. . . . . . . . . . . . . . . . . . . . 10 \flushcolumns. . . . . . . . . . . . . . . . . . . . 20
v1.0d General: \multicolssep changed to
General: All lines shortened to 72 or less. . . . . . 1 \multicolsep. . . . . . . . . . . . . . . . . . . . . . 1
v1.2a
v1.0e
\balance@columns: Group around main loop
\prepare@multicols: \textwidth changed to
removed. . . . . . . . . . . . . . . . . . . . . . . . . 22
\linewidth. . . . . . . . . . . . . . . . . . . . . . . 13
\prepare@multicols: \pretolerance -1
Setting of \columnwidth removed. . . . . . . . 13 because it nearly never succeeds. . . . . . . . 13
So this file will work with the twocolumn \set@floatcmds added. . . . . . . . . . . . . . . . 13
command. . . . . . . . . . . . . . . . . . . . . . . . 13 \setemergencystretch added. . . . . . . . . . . 13
General: Redefinition of description env. to use \vbadness 10001 now. . . . . . . . . . . . . . . . . 13
\descriptionmargin=5pt in \set@floatcmds: Macro added. . . . . . . . . . . . 26
documentation. . . . . . . . . . . . . . . . . . . . . . 1 \setemergencystretch: Macro added. . . . . . . 26
v1.0f \speci@ls: Float boxes freed. . . . . . . . . . . . . . 20
General: Changed \z@ to 0pt in redefinition of v1.3a
description. . . . . . . . . . . . . . . . . . . . . . . . . 1 \balance@columns: Changed \vtop to \vbox. . 25

33
v1.3b v1.4j
\endmulticols: Do \penalty with \addpenalty 14 \setemergencystretch: Setting of
\enough@room: Do \penalty with \addpenalty 10 \emergencystretch on top removed. . . . . 26
\multicols: Minimum of two columns . . . . . . . 9 v1.4k
v1.3c \multicols: Maximum of 5 columns (temp) . . . 9
\balance@columns: \global\advance left over v1.4l
from older code . . . . . . . . . . . . . . . . . . . . 24 \mult@@cols: \@totalleftmargin now in
Limit column height to \@colroom . . . . . . . 25 \prepare@multicols . . . . . . . . . . . . . . . . 10
\endmulticols: Check closing env. . . . . . . . . . 15 \page@sofar: use \multicol@leftmargin
\multi@column@out: \unboxing avoided. . . . . . 18 instead of \@totalleftmargin . . . . . . . . . 16
Check if footnotes are actually present before \prepare@multicols: saved
issuing a warning. . . . . . . . . . . . . . . . . . . 18 \@totalleftmargin . . . . . . . . . . . . . . . . 11
Unnecessary code removed . . . . . . . . . . . . . 19 v1.4m
\prepare@multicols: \null inserted and \endmulticols: Check \partial@page being
removed in output . . . . . . . . . . . . . . . . . 11 emptied . . . . . . . . . . . . . . . . . . . . . . . . . 14
\reinsert@footnotes: \unboxing avoided. . . . 17 v1.4n
v1.3d \return@nonemptymark: Make marks robust . . 27
\c@unbalance: \col@number set to one . . . . . . 15 v1.4o
v1.4a \prepare@multicols: \topskip locally zeroed. 11
\balance@columns: Changed to proper v1.4p
\endlinechar in\message . . . . . . . . . . . . 24 \multi@column@out: Use different \vsize
\mult@@cols: Forgotten braces added . . . . . . . 10 setting . . . . . . . . . . . . . . . . . . . . . . . . . . 19
\multi@column@out: \botmark set to \prepare@multicols: Code moved to
\splitbotmark . . . . . . . . . . . . . . . . . . . . 18 \set@mult@vsize . . . . . . . . . . . . . . . . . . 12
\prepare@multicols: Checking for text losses. 11 Use different \vsize setting . . . . . . . . . . . . 12
Conditional code for boxed mode added. . . . 11 \set@mult@vsize: Macro added. . . . . . . . . . . 13
kept marks initiated . . . . . . . . . . . . . . . . . . 12 v1.5?
General: Added support for multicol in inner \balance@columns: Allow columns to come out
mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 a bit long or short . . . . . . . . . . . . . . . . . . 22
v1.4d Do splitting to zero here . . . . . . . . . . . . . . . 22
\balance@columns: New algorithm for start Initialize \last@try . . . . . . . . . . . . . . . . . . 23
height . . . . . . . . . . . . . . . . . . . . . . . . . . 22 Show natural size . . . . . . . . . . . . . . . . . . . . 23
v1.4e \endmulticols: Splitting off zero box moved to
\endmulticols: But ignore \@nobreak in \balance@columns . . . . . . . . . . . . . . . . . 14
\addpenalty . . . . . . . . . . . . . . . . . . . . . . 14 \leave@mult@footins: Macro added . . . . . . . . 19
\enough@room: But ignore \@nobreak in \mult@@cols: Penalty moved to later point . . . 10
\addpenalty . . . . . . . . . . . . . . . . . . . . . . 10 \multi@column@out: Use \leave@mult@footins 18
\mult@@cols: Typeset optional arg inside group 10 \prepare@multicols: Use \init@mult@footins 12
\prepare@multicols: Using . . . . . . . . . . . . . . 13 v1.5a
v1.4f \LR@column@boxes: New box mechanism . . . . . 30
\balance@columns: \on@line added to tracing \balance@columns: New box mechanism . . . . . 23
info . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 \multi@column@out: New box mechanism . . . . 18
\mult@@cols: \on@line added to tracing info . 10 \multicols: Allow 10 columns again . . . . . . . . 9
\par added to allow for correct inner test . . . 9 \page@sofar: New box mechanism . . . . . . . . . 16
v1.4g \prepare@multicols: Add offset to
\mult@@cols: \global was probably wrong but \doublecolnumber . . . . . . . . . . . . . . . . . 11
at least unnecessary . . . . . . . . . . . . . . . . 10 v1.5b
\multi@column@out: Only change \balance@columns: New badness mechanism . . 23
\kept@topmark if \kept@botmark v1.5c
non-empty . . . . . . . . . . . . . . . . . . . . . . . 19 \balance@columns@out: added penalty at
v1.4h output routine exit . . . . . . . . . . . . . . . . . 21
\kept@topmark: Init to double brace pair . . . . 26 \endmulticols: Again use \penalty . . . . . . . . 14
General: Added mark tracing with \multi@column@out: Support \clearpage . . . . 17
tracingmulticols 2 . . . . . . . . . . . . . . . . . . 1 \speci@ls: Support \clearpage . . . . . . . . . . . 19
v1.4i v1.5d
\multi@column@out: Set \kept@topmark to \multi@column@out: reinit \topmark . . . . . . . 18
\botmark . . . . . . . . . . . . . . . . . . . . . . . . 19 v1.5e
\prepare@multicols: \kept@topmark \enough@room: Assign arg to skip register to be
initialized. . . . . . . . . . . . . . . . . . . . . . . . 12 able to output value . . . . . . . . . . . . . . . . 11

34
v1.5g \balance@columns@out: Added debug
\set@floatcmds: Updated since floats have statements for column break support . . . . 21
changed . . . . . . . . . . . . . . . . . . . . . . . . . 26 \multi@column@out: Added debug statements
v1.5h for column break support . . . . . . . . . . . . 17
\balance@columns: Get kept marks first . . . . . 22 \speci@ls: Added debug statements for column
\page@sofar: Check for void boxes . . . . . . . . . 16 break support . . . . . . . . . . . . . . . . . . . . . 20
v1.5i v1.5w
\page@sofar: But dont remove original code. . 16 \multicols: Make \@footnotetext long to
v1.5j allow multi-paragraph footnotes. . . . . . . . . 9
\set@floatcmds: Updated since floats have v1.5x
changed again . . . . . . . . . . . . . . . . . . . . . 26 \endmulticols: Detect and fix problem if a
v1.5l multicols ends at the top of a page . . . . . . 15
\set@floatcmds: Added \@largefloatcheck . . 26 v1.5y
General: Try hard to explain unresolved \balance@columns: Limit column height only in
reference that happens if \OnlyDescription unrestricted mode (pr/3212) . . . . . . . . . . 25
is used . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 v1.5z
v1.5n \page@sofar: Ensure that column rule has
General: Applied improvement of always \normalcolor . . . . . . . . . . . . . . . 16
documentation, kindly done by Robin v1.5z1
Fairbairns. . . . . . . . . . . . . . . . . . . . . . . . . 1 \c@finalcolumnbadness: Change wrong default
v1.5o for \multicolovershoot to zero (pr/3465). 29
\@footnotetext: Redefinition added pr/2664. . 29 \mult@@cols: Add a kern to cancel potential
\prepare@multicols: Setting of \columnwidth depth of previous line . . . . . . . . . . . . . . . 10
added again pr/2664. . . . . . . . . . . . . . . . 13 \page@sofar: Suppress interline glue at this
v1.5p point . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
\multicols: Redefinition of \@footnotetext v1.6a
only within env pr/2689. . . . . . . . . . . . . . . 9 \LR@column@boxes: Preparing for adjusting
v1.5q \prevdepth . . . . . . . . . . . . . . . . . . . . . . 30
\balance@columns: Do not reset \mult@@cols: Adjust spacing . . . . . . . . . . . . . 10
\mult@firstbox (pr2739) . . . . . . . . . . . . 24 \page@sofar: Preparing for adjusting
Removed setting \dimen@ (pr2739) . . . . . . . 25 \prevdepth . . . . . . . . . . . . . . . . . . . . . . 16
\endmulticols*: Macro added . . . . . . . . . . . . 29 General: New option grid . . . . . . . . . . . . . . . . . 8
\mult@@cols: And removed the group again six v1.6b
years later . . . . . . . . . . . . . . . . . . . . . . . 10 \page@sofar: Different info display . . . . . . . . . 16
\multicols*: Macro added . . . . . . . . . . . . . . 29 v1.6c
v1.5r \set@mult@vsize: Collect one line per column
\@footnotetext: Use \@footnotetext but with more . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
local change to \columnwidth. . . . . . . . . . 29 v1.6d
\mult@footnotetext: Macro removed again. . . 29 \endmulticols: Catch problem with
\multicols: Use \@footnotetext but with \columnbreak in last line . . . . . . . . . . . . 14
local change to \columnwidth. . . . . . . . . . . 9 v1.6e
v1.5s \multicols: Avoid self-referencing definition of
\speci@ls: check for \stop penalty pr/2873 . . 20 \@footnotetext (pr/3618) . . . . . . . . . . . . 9
v1.5t v1.6f
\return@nonemptymark: re-add \mark command \balance@columns: /colbreak guard in the
which was commented out by mistake at wrong position . . . . . . . . . . . . . . . . . . . . 24
some point in 1998 (pr/2978) . . . . . . . . . . 27 need to use \mult@grightbox in the loop . . 24
v1.5u \columnseprulecolor: Make the color of the
\balance@columns@out: Support \columnbreak 21 rule a hook . . . . . . . . . . . . . . . . . . . . . . . 17
\colbreak@box: Macro added . . . . . . . . . . . . . 30 \page@sofar: Make the color of the rule a hook 16
\columnbreak: Macro added . . . . . . . . . . . . . . 30 v1.6g
\multi@column@out: Support \columnbreak . . 17 \set@floatcmds: Added \@minipagefalse . . . 26
\speci@ls: Support \columnbreak . . . . . . . . . 20 v1.6h
v1.5v \set@floatcmds: Use \@endfloatbox to better
\balance@columns: Added tracing statements support the modifications done by the float
for trial unsuccessful . . . . . . . . . . . . . . . . 24 package . . . . . . . . . . . . . . . . . . . . . . . . . 26
Check last column if it contains forced break v1.7a
and reject trial if that is the case . . . . . . . 24 General: RL language support added . . . . . . . 30

35
v1.7b v1.8i
\page@sofar: RL language support fixed . . . . 16 \endmulticols*: Add \null to hide the final
General: RL language support fixed . . . . . . . . 30 fill and only add vertical space if not doing
v1.8a \raggedcolumns . . . . . . . . . . . . . . . . . . . 29
\balance@columns: Balancing concept improved 25 v1.8j
\balance@columns: Use \vfil in this case . . . 24
\balance@columns@out: Balancing concept
\endmulticols*: Redesign the whole approach. 29
improved . . . . . . . . . . . . . . . . . . . . . . . . 21
\multi@column@out: Set \boxmaxdepth . . . . . . 17
Support for \enlargethispage . . . . . . . . . . 21
\vfilmaxdepth: Use only 0.0001fil for
\maxbalancingoverflow:
stretching . . . . . . . . . . . . . . . . . . . . . . . . 17
\maxbalancingoverflow parameter added 26
v1.8k
\multi@column@out: Only re-add output \balance@columns: . . . . . . . . . . . . . . . . . . . . 25
penalty if it was explicitly set . . . . . . . . . 18 \remove@discardable@items removed . . . . . 22
Support for \enlargethispage . . . . . . . . . . 18 Do not use \remove@discardable@items here 23
v1.8b Finish the new conditional . . . . . . . . . . . . . 26
\balance@columns: Remove discardable items Init \ifforcedbreak@leftover . . . . . . . . . . 23
at the end of split boxes . . . . . . . . . . . . . 23 Watch out for columns growing too far in
\multi@column@out: And 20odd years later case of forced breaks . . . . . . . . . . . . . . . . 24
conclude that this was wrong and unboxing \balance@columns@out: Add
is always needed. . . . . . . . . . . . . . . . . . . 18 \remove@discardable@items at the end of
Remove discardable items at the end of split the last column when balancing. . . . . . . . 21
boxes . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 No additional penalty here . . . . . . . . . . . . . 21
v1.8c Use \@Mv and not \break in case this forced
\endmulticols: Add \color@endgroup to break is not used on this page . . . . . . . . . 21
prevent color leak . . . . . . . . . . . . . . . . . . 14 \endmulticols*: And a bit more redesign
\mult@@cols: Add \color@setgroup to prevent because of the change in
color leak . . . . . . . . . . . . . . . . . . . . . . . . 10 \remove@discardable@items . . . . . . . . . . 29
\multi@column@out:
v1.8d
\remove@discardable@items removed . . . 18
\multi@column@out: Reset \@mparbottom after
\speci@ls: Remove discarable items just before
page finishes . . . . . . . . . . . . . . . . . . . . . . 19
a forced break . . . . . . . . . . . . . . . . . . . . . 20
v1.8e
General: The new switch . . . . . . . . . . . . . . . . 28
\LR@column@boxes: Support \docolaction . . . 30 v1.8l
\RL@column@boxes: Support \docolaction . . . 31 \balance@columns: Added additional tracing if
General: Support \docolaction . . . . . . . . . 8, 31 column overflows . . . . . . . . . . . . . . . . . . . 24
v1.8f v1.8m
\endmulticols: Discard spaces before adding \remove@discardable@items: Another rewrite
\color@endgroup . . . . . . . . . . . . . . . . . . 14 of \remove@discardable@items hopefully
v1.8g okay now . . . . . . . . . . . . . . . . . . . . . . . . 28
\page@sofar: Now adjusting \prevdepth . . . . 17 v1.8n
Resetting \prevdepth in the right place . . . 17 \multi@column@out: Reset
Warn if value is exceeded not when equal . . 17 \@textfloatsheight after page finishes . . 19
v1.8o
v1.8h
\c@unbalance: \col@number already initialized
\balance@columns: All column boxes should
in the kernel, so not initializing it in the
obey \maxdepth (pr/4395) . . . . . . . . . . . . 22
package in case the document is in
Do not report overfull . . . . . . . . . . . . . . . . 23
two-column (pr/4435) . . . . . . . . . . . . . . . 15
Use \vfilmaxdepth . . . . . . . . . . . . . . . 24, 25 \endmulticols*: Ensure we are back in vmode
\endmulticols: Set \prevdepdth for current before using \prevdepth (pr/4448) . . . . . 29
vlist when returning from multicols v1.8p
environment . . . . . . . . . . . . . . . . . . . . . . 15 \multi@column@out: Reset \boxmaxdepth . . . . 19
\endmulticols*: Use \vfilmaxdepth . . . . . . . 29 v1.8q
\multi@column@out: Use \vfilmaxdepth . . . . 18 \prepare@multicols: Make \clearpage behave
\vfilmaxdepth: Macro added (pr/4395) . . . . . 17 like \newpage (pr/4511) . . . . . . . . . . . . . 12

36

You might also like