latex - multicol package

29
An environment for multicolumn output ∗† Frank Mittelbach Email: see top of the source file Printed October 5, 2011 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. L A T E X’s float mechanism, however, is partly disabled in the current implementation. At the moment only page-wide floats (i.e., star-forms) can be used within the scope of the environment. Preface to version 1.7 as if we are writing in a left-to- right language—so restart read- ing the rightmost column first if you started with this column). page also need to be reversed— something that wasn’t supported before. This paragraph demon- strates the result (as it is typeset The 1.7 release adds support for languages that are typeset right- to-left. For those languages the order of the columns on the Preface to version 1.5 + 1.6 The 1.5 release contains two major changes: multicols will now support up to 10 columns and two more tuning possibilities have been added to the balancing routine. The balancing routine now checks the badness of the re- sulting columns and rejects solu- tions that are larger than a cer- tain treshold. At the same time multicols has been upgraded to run under L A T E X2 . Later changes to 1.5 include \columnbreak and multicols*. For version 1.6 micro-spacing around the boxes produced by multicols has been improved to al- low for baseline-grid typesetting. 1 Introduction Switching between two-column and one-column layout is pos- sible in L A T E X, but every use of \twocolumn or \onecolumn starts a new page. More- over, the last page of two- column output isn’t balanced and this often results in an empty, or nearly empty, right col- umn. When I started to write macros for doc.sty (see “The doc–Option”, TUGboat volume 10 #2, pp. 245–273) I thought that it would be nice to place the index on the same page as the bibliography. And balancing the last page would not only look better, it also would save space; provided of course that it is also possible to start the next article on the same page. Rewriting the index environment was compar- atively easy, but the next goal, designing an environment which takes care of footnotes, floats, etc., was a harder task. It took me a whole weekend 1 to get to- gether the few lines of code below and there is still a good chance that I missed something after all. Try it and, hopefully, enjoy it; and please direct bug reports and suggestions back to Mainz. * This file has version number v1.7a, last revised 2011/06/27. Note: This package is released under terms which affect its use in commercial applications. Please see the details at the top of the source file. 1 I started with the algorithm given in the T E Xbook on page 417. Without this help a weekend would not have been enough. (This remark was made in the documentation of the initial release, since then several hundreds more hours went into improving the original code.) 1

Upload: tayitooo

Post on 31-Dec-2015

56 views

Category:

Documents


0 download

DESCRIPTION

User manual for multicol package

TRANSCRIPT

Page 1: LaTeX - MultiCol Package

An environment for multicolumn output∗†

Frank MittelbachEmail: see top of the source file

Printed October 5, 2011

Abstract

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

Preface to version 1.7as if we are writing in a left-to-right language—so restart read-ing the rightmost column first ifyou started with this column).

page also need to be reversed—something that wasn’t supportedbefore. This paragraph demon-strates the result (as it is typeset

The 1.7 release adds support forlanguages that are typeset right-to-left. For those languages theorder of the columns on the

Preface to version 1.5 + 1.6The 1.5 release contains twomajor changes: multicols willnow support up to 10 columnsand two more tuning possibilitieshave been added to the balancingroutine. The balancing routine

now checks the badness of the re-sulting columns and rejects solu-tions that are larger than a cer-tain treshold. At the same timemulticols has been upgraded torun under LATEX 2𝜀.

Later changes to 1.5 include\columnbreak and multicols*.

For version 1.6 micro-spacingaround the boxes produced bymulticols has been improved to al-low for baseline-grid typesetting.

1 IntroductionSwitching between two-columnand one-column layout is pos-sible in LATEX, but every useof \twocolumn or \onecolumnstarts a new page. More-over, the last page of two-column output isn’t balancedand this often results in anempty, or nearly empty, right col-umn. When I started to writemacros for doc.sty (see “The

doc–Option”, TUGboat volume10 #2, pp. 245–273) I thoughtthat it would be nice to placethe index on the same page asthe bibliography. And balancingthe last page would not only lookbetter, it also would save space;provided of course that it is alsopossible to start the next articleon the same page. Rewriting theindex environment was compar-

atively easy, but the next goal,designing an environment whichtakes care of footnotes, floats,etc., was a harder task. It tookme a whole weekend1 to get to-gether the few lines of code belowand there is still a good chancethat I missed something after all.

Try it and, hopefully, enjoy it;and please direct bug reports andsuggestions back to Mainz.

*This file has version number v1.7a, last revised 2011/06/27.†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.1I started with the algorithm given in the TEXbook on page 417. Without this help a weekend would not have been enough.

(This remark was made in the documentation of the initial release, since then several hundreds more hours went into improvingthe original code.)

1

Page 2: LaTeX - MultiCol Package

2 The User InterfaceTo use the environment one sim-ply says

\begin{multicols}{⟨number⟩}⟨multicolumn text⟩

\end{multicols}

where ⟨number⟩ is the requirednumber of columns and ⟨multi-column text⟩ may contain arbi-trary LATEX commands, exceptthat floats and marginpars arenot allowed in the current imple-mentation2.

As its first action, the multicolsenvironment measures the cur-rent page to determine whetherthere is enough room for someportion of multicolumn out-put. This is controlled by the⟨dimen⟩ variable \premulticolswhich can be changed by theuser with ordinary LATEX com-mands. If the space is less than\premulticols, a new page isstarted. Otherwise, a \vskip of\multicolsep is added.3

When the end of the mul-ticols environment is encoun-tered, an analogous mechanismis employed, but now we testwhether there is a space largerthan \postmulticols available.Again we add \multicolsep orstart a new page.

It is often convenient to spreadsome text over all columns, justbefore the multicolumn output,without any page break in be-tween. To achieve this the multi-cols environment has an optionalsecond argument which can beused for this purpose. For exam-ple, the text you are now readingwas started with

\begin{multicols}{3}[\section{The User

Interface}] ...

If such text is unusually

long (or short) the value of\premulticols might need ad-justing to prevent a bad pagebreak. We therefore provide athird argument which can beused to overwrite the defaultvalue of \premulticols just forthis occasion. So if you wantto combine some longer singlecolumn text with a multicols en-vironment you could write

\begin{multicols}{3}[\section{Index}This index contains ...][6cm]

...

The space between columns iscontrolled by the length param-eter \columnsep. The widthfor the individual columns isautomatically calculated fromthis parameter and the current\linewidth. In this article avalue of 18.0pt was used.

Separation of columns withvertical rules is achievedby setting the parameter\columnseprule to some posi-tive value. In this article a valueof .4pt was used.

The color of the rulesseparating the columnscan be specified through\columnseprulecolor. The de-fault value is \normalcolor.

Since narrow columns tendto need adjustments in in-terline spacing we also pro-vide a ⟨skip⟩ parameter called\multicolbaselineskip whichis added to the \baselineskipparameter inside the multicols en-vironment. Please use this pa-rameter with care or leave italone; it is intended only forpackage file designers since even

small changes might produce to-tally unexpected changes to yourdocument.

2.1 Balancing columnsBesides the previously mentionedparameters, some others are pro-vided to influence the layout ofthe columns generated.

Paragraphing in TEX is con-trolled by several parameters.One of the most important iscalled \tolerance: this controlsthe allowed ‘looseness’ (i.e. theamount of blank space betweenwords). Its default value is 200(the LATEX \fussy) which is toosmall for narrow columns. On theother hand the \sloppy declara-tion (which sets \tolerance to10000 = ∞) is too large, allow-ing really bad spacing.4

We therefore use a\multicoltolerance parameterfor the \tolerance value insidethe multicols environment. Itsdefault value is 9999 whichis less than infinity but ‘bad’enough for most paragraphsin a multicolumn environment.Changing its value should bedone outside the multicols envi-ronment. Since \tolerance isset to \multicoltolerance atthe beginning of every multicolsenvironment one can locallyoverwrite this default by as-signing \tolerance␣=␣⟨desiredvalue⟩. There also exists a\multicolpretolerance pa-rameter holding the valuefor \pretolerance within amulticols environment. Bothparameters are usually used onlyby package designers.

Generation of multicolumnoutput can be divided into twoparts. In the first part we are

2This is dictated by lack of time. To implement floats one has to reimplement the whole LATEX output routine.3Actually the added space may be less because we use \addvspace (see the LATEX manual for further information about this

command).4Look at the next paragraph, it was set with the \sloppy declaration.

2

Page 3: LaTeX - MultiCol Package

collecting material for a page,shipping it out, collecting mate-rial for the next page, and so on.As a second step, balancing willbe done when the end of the mul-ticols environment is reached. Inthe first step TEX might considermore material whilst finding thefinal column content than it ac-tually uses when shipping out thepage. This might cause a prob-lem if a footnote is encounteredin the part of the input consid-ered, but not used, on the currentpage. In this case the footnotemight show up on the currentpage, while the footnotemarkcorresponding to this footnotemight be set on the next one.5Therefore the multicols environ-ment gives a warning message6

whenever it is unable to use allthe material considered so far.

If you don’t use footnotes toooften the chances of somethingactually going wrong are veryslim, but if this happens you canhelp TEX by using a \pagebreakcommand in the final document.Another way to influence the be-havior of TEX in this respectis given by the counter variable‘collectmore’. If you use the\setcounter declaration to setthis counter to ⟨number⟩, TEXwill consider ⟨number⟩ more (orless) lines before making its fi-nal decision. So a value of −1may solve all your problems atthe cost of slightly less optimalcolumns.

In the second step (balanc-ing columns) we have other bellsand whistles. First of all youcan say \raggedcolumns if youdon’t want the bottom lines tobe aligned. The default is\flushcolumns, so TEX will nor-mally try to make both the

top and bottom baselines of allcolumns align.

Additionally you can setanother counter, the ‘unbal-ance’ counter, to some positive⟨number⟩. This will make all butthe right-most column ⟨number⟩of lines longer than they wouldnormally have been. ‘Lines’ inthis context refer to normal textlines (i.e. one \baselineskipapart); thus, if your columnscontain displays, for example,you may need a higher ⟨number⟩to shift something from one col-umn into another.

Unlike ‘collectmore,’ the ‘unbal-ance’ counter is reset to zero atthe end of the environment so itonly applies to one multicols en-vironment.

The two methods may be com-bined but I suggest using thesefeatures only when fine tuningimportant publications.

Two more general tuning pos-sibilities were added with ver-sion 1.5. TEX allows to mea-sure the badness of a column interms of an integer value, where0 means optimal and any highervalue means a certain amountof extra white space. 10000 isconsidered to be infinitely bad(TEX does not distinguish anyfurther). In addition the specialvalue 100000 means overfull (i.e.,the column contains more textthan could possibly fit into it).

The new release now measuresevery generated column and ig-nores solutions where at leastone column has a badness be-ing larger than the value of thecounter columnbadness. The de-fault value for this counter is10000, thus TEX will accept allsolutions except those being over-full. By setting the counter to asmaller value you can force thealgorithm to search for solutionsthat do not have columns with alot of white space.

However, if the setting is toolow, the algorithm may not findany acceptable solution at all andwill then finally choose the ex-treme solution of placing all textinto the first column.

Often, when columns are bal-anced, it is impossible to find asolution that distributes the textevenly over all columns. If thatis the case the last column usu-ally has less text than the oth-ers. In the earlier releases thistext was stretched to produce acolumn with the same height asall others, sometimes resulting inreally ugly looking columns.

In the new release this stretch-ing is only done if the badnessof the final column is not largerthan the value of the counter fi-nalcolumnbadness. The defaultsetting is 9999, thus preventingthe stretching for all columnsthat TEX would consider in-finitely bad. In that case the fi-nal column is allowed to run shortwhich gives a much better result.

And there are two moreparameters of some exper-imental nature, one called\multicolovershoot the other\multicolundershoot. Theycontrol the amount of space acolumn is allowed to be “too full”or “too short” without affectingthe column badness. They areset to 0pt and 2pt, respectively.

2.2 Not balancing thecolumns

Although this package was writ-ten to solve the problem of bal-ancing columns, I got repeatedrequests to provide a versionwhere all white space is auto-matically placed in the last col-umn or columns. Since versionv1.5q this now exists: if youuse multicols* instead of theusual environment the columnson the last page are not balanced.

5The reason behind this behavior is the asynchronous character of the TEX page_builder. However, this could be avoidedby defining very complicated output routines which don’t use TEX primitives like \insert but do everything by hand. This isclearly beyond the scope of a weekend problem.

6This message will be generated even if there are no footnotes in this part of the text.

3

Page 4: LaTeX - MultiCol Package

Of course, this environment onlyworks on top-level, e.g., inside abox one has to balance to deter-mine a column height in absenceof a fixed value.

2.3 Manually breakingcolumns

Another request often voicedwas: “How do I tell LATEX thatit should break the first columnafter this particular line?”. The\pagebreak command (whichworks with the two-column op-tion of LATEX) is of no use heresince it would end the collectionphase of multicols and thus allcolumns on that page. So withversion 1.5u the \columnbreakcommand was added. If usedwithin a paragraph it marks theend of the current line as the de-sired breakpoint. You can ob-serve its effect on the previouspage where three lines of texthave been artificially forced intothe second column (resulting insome white space between para-graphs in the first column).

2.4 Floats inside a mul-ticols environment

Within the multicols environmentthe usual star float commandsare available but their function issomewhat different as in the two-column mode of standard LATEX.Stared floats, e.g., figure*, de-note page wide floats that arehandled in a similar fashion asnormal floats outside the multi-cols environment. However, theywill never show up on the pagewhere they are encountered. Inother words, one can influencetheir placement by specifying acombination of t, b, and/or pin their optional argument, buth doesn’t work because the firstpossible place is the top of thenext page. One should also note,that this means that their place-ment behavior is determined bythe values of \topfraction, etc.

rather than by \dbl....

2.5 Support for right-to-left typesetting

In right-to-left typesetting the or-der of the columns on the pagealso need to be reversed, i.e., thefirst column has to appear onthe far right and the last col-umn on the left. This is sup-ported through the commands\RLmulticolcolumns (switchingto right-to-left typesetting) and\LRmulticolcolumns (switchingto left-to-right typesetting) thelatter being the default.

2.6 WarningsUnder certain circumstances theuse of the multicols environmentmay result in some warnings fromTEX or LATEX. Here is a list of theimportant ones and the possiblecause:

Underfull \hbox (badness...)

As the columns are often verynarrow TEX wasn’t able to finda good way to break the para-graph. Underfull denotes a looseline but as long as the badnessvalue is below 10000 the resultis probably acceptable.

Underfull \vbox ... while\output is active

If a column contains a characterwith an unusual depth, for ex-ample a ‘(’, in the bottom linethen this message may show up.It usually has no significance aslong as the value is not morethan a few points.

LaTeX Warning: I moved somelines to the next page

As mentioned above, multicolssometimes screws up the foot-note numbering. As a precau-tion, whenever there is a foot-note on a page where multicolshad to leave a remainder for the

following page this warning ap-pears. Check the footnote num-bering on this page. If it turnsout that it is wrong, you have tomanually break the page using\newpage or \pagebreak[..].

Floats and marginpars notallowed inside `multicols'environment!

This message appears if you tryto use the \marginpar com-mand or an unstared version ofthe figure or table environment.Such floats will disappear!

Very deep columns! Gridalignment might be broken

This message can only appear ifthe option grid was chosen. Inthat case it will show up if a col-umn has a very large depth sothat multicols is unable to backup to its baseline. This is onlyrelevant if one tries to producea document where all text linesare aligned at an invisible grid,something that requires carefuladjustment of many parametersand macros, e.g., heading defini-tions.

2.7 Tracing the outputTo understand the reasoning be-hind the decisions TEX makeswhen processing a multicols envi-ronment, a tracing mechanism isprovided. If you set the counter‘tracingmulticols’ to a positive⟨number⟩ you then will get sometracing information on the termi-nal and in the transcript file:

⟨number⟩ = 1. TEX will now tellyou, whenever it enters or leavesa multicols environment, thenumber of columns it is workingon and its decision about start-ing a new page before or afterthe environment.

⟨number⟩ = 2. In this caseyou also get information fromthe balancing routine: theheights tried for the left andright-most columns, informa-tion about shrinking if the

4

Page 5: LaTeX - MultiCol Package

\raggedcolumns declaration isin force and the value of the‘unbalance’ counter if positive.

⟨number⟩ = 3. Setting⟨number⟩ to this value will ad-ditionally trace the mark han-dling algorithm. It will showwhat marks are found, what

marks are considered, etc. Tofully understand this informa-tion you will probably have toread carefully trough the imple-mentation.

⟨number⟩ ≥ 4. Setting⟨number⟩ to such a high valuewill additionally place an

\hrule into your output, sep-arating the part of text whichhad already been consideredon the previous page from therest. Clearly this setting shouldnot be used for the final out-put. It will also activate evenmore debugging code for markhandling.

3 Prefaces to older versions3.1 Preface to version 1.4

Beside fixing some bugs as men-tioned in the multicol.bug file thisnew release enhances the multi-cols environment by allowing forbalancing in arbitrary contexts.It is now, for example, possibleto balance text within a multicolsor a minipage as shown in 2 wherea multicols environment within aquote environment was used. Itis now even possible to nest mul-ticols environments.

The only restriction to suchinner multicols environments(nested, or within TEX’s internalvertical mode) is that such vari-

ants will produce a box with thebalanced material in it, so thatthey can not be broken acrosspages or columns.

Additionally I rewrote the al-gorithm for balancing so that itwill now produce slightly betterresults.

I updated the source documen-tation but like to apologize in ad-vance for some ‘left over’ partsthat slipped through the revision.

A note to people who liketo improve the balancing algo-rithm of multicols: The balanc-ing routine is now placed into

a single macro which is called\balance@columns. This meansthat one can easily try differentbalancing routines by rewritingthis macro. The interface for itis explained in table 1. Thereare several improvements possi-ble, one can think of integratingthe \badness function of TEX3,define a faster algorithm for find-ing the right column height, etc.If somebody thinks he/she has anenhancement I would be pleasedto learn about it. But please obeythe copyright notice and don’tchange multicol.dtx directly!

3.2 Preface to version 1.2

After the article about the mul-ticols environment was publishedin TUGboat 10#3, I got numer-ous requests for these macros.However, I also got a changedversion of my style file, togetherwith a letter asking me if I wouldinclude the changes to get betterparagraphing results in the caseof narrow lines. The main differ-ences to my original style op-tion were additional parameters(like \multicoladjdemerits tobe used for \adjdemerits, etc.)which would influence the linebreaking algorithm.

But actually resetting such pa-rameters to zero or even worse toa negative value won’t give bet-ter line breaks inside the multicolsenvironment. TEXs line break-ing algorithm will only look at

those possible line breaks whichcan be reached without a badnesshigher than the current value of\tolerance (or \pretolerancein the first pass). If this isn’t pos-sible, then, as a last resort, TEXwill produce overfull boxes. Allthose (and only those) possiblebreak points will be consideredand finally the sequence which re-sults in the fewest demerits willbe chosen. This means that avalue of −1000 for \adjdemeritsinstructs TEX to prefer visibly in-compatible lines instead of pro-ducing better line breaks.

However, with TEX 3.0 it ispossible to get decent line breakseven in small columns by setting\emergencystretch to an appro-priate value. I implemented aversion which is capable of run-

ning both in the old and thenew TEX (actually it will sim-ply ignore the new feature if itis not available). The calculationof \emergencystretch is proba-bly incorrect. I made a few testsbut of course one has to havemuch more experience with thenew possibilities to achieve themaximum quality.

Version 1.1a had a nice ‘fea-ture’: the penalty for usingthe forbidden floats was theirultimate removal from LATEXs\@freelist so that after a few\marginpars inside the multi-cols environment floats where dis-abled forever. (Thanks to ChrisRowley for pointing this out.) Iremoved this misbehaviour andat the same time decided to al-low at least floats spanning all

5

Page 6: LaTeX - MultiCol Package

The macro \balance@columns that containsthe code for balancing gathered material is amacro without parameters. It assumes thatthe material for balancing is stored in the box\mult@box which is a \vbox. It also “knows”about all parameters set up by the multicolsenvironment, like \col@number, etc. It canalso assume that \@colroom is the still avail-able space on the current page.When it finishes it must return the individ-ual columns in boxes suitable for further pro-cessing with \page@sofar. This means thatthe left column should be stored in box reg-

ister \mult@gfirstbox, the next in register\mult@firstbox + 2, …, only the last oneas an exception in register \[email protected] it has to set up the two macros\kept@firstmark and \kept@botmark to holdthe values for the first and bottom mark asfound in the individual columns. There aresome helper functions defined in section 5.1which may be used for this. Getting the marksright “by hand” is non-trivial and it may payoff to first take a look at the documentationand implementation of \balance@columns be-low before trying anew.

Table 1: Interface description for \balance@columns

\setemergencystretch: This is a hook for peoplewho like to play around. It is supposed to set the\emergencystretch ⟨dimen⟩ register provided inthe new TEX 3.0. The first argument is the num-ber of columns and the second one is the current\hsize. At the moment the default definition is

4pt × #1, i.e. the \hsize isn’t used at all. Butmaybe there are better formulae.\set@floatcmds: This is the hook for the expertswho like to implement a full float mechanism forthe multicols environment. The @ in the nameshould 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 solutionsto these open problems are found. I hope that these commands will prevent that nearly identical style filesderived from this one are floating around.

columns, e.g., generated by thefigure* environment. You cansee the new functionality in ta-ble 2 which was inserted at thisvery point. However single col-umn floats are still forbidden andI don’t think I will have time totackle this problem in the near fu-

ture. As an advice for all whowant to try: wait for TEX 3.0.It has a few features which willmake life much easier in multi-column surroundings. Neverthe-less we are working here at theedge of TEXs capabilities, reallyperfect solutions would need a

different approach than it wasdone in TEXs page builder.

The text below is nearly un-changed, I only added documen-tation at places where new codewas added.

4 The ImplementationWe are now switching to two-column output to show the abilities of this environment (and bad layoutdecisions).

4.1 The documentation driver file

The next bit of code contains the documentationdriver file for TEX, i.e., the file that will produce thedocumentation you are currently reading. It will beextracted from this file by the docstrip program.Since this is the first code in this file one can producethe documentation simply by running LATEX on the.dtx file.

1 ⟨*𭖽𭗋𭗂𭗏𭖾𭗋⟩2 \documentclass{ltxdoc}

We use the balancingshow option when loadingmulticols so that full tracing is produced. This has to

be done before the doc package is loaded, since docotherwise requires multicols without any options.

3 \usepackage{multicol}[1999/05/25]4 \usepackage{doc}

First we set up the page layout suitable for this ar-ticle.

5 \setlength{\textwidth}{39pc}6 \setlength{\textheight}{54pc}7 \setlength{\parindent}{1em}8 \setlength{\parskip}{0pt plus 1pt}9 \setlength{\oddsidemargin}{0pc}

6

Page 7: LaTeX - MultiCol Package

10 \setlength{\marginparwidth}{0pc}11 \setlength{\topmargin}{-2.5pc}12 \setlength{\headsep}{20pt}13 \setlength{\columnsep}{1.5pc}

We want a rule between columns.14 \setlength\columnseprule{.4pt}

We also want to ensure that a new multicols envi-ronment finds enough space at the bottom of thepage.

15 \setlength\premulticols{6\baselineskip}

When balancing columns we disregard solutions thatare too bad. Also, if the last column is too bad wetypeset it without stretch.

16 \setcounter{columnbadness}{7000}17 \setcounter{finalcolumnbadness}{7000}

The index is supposed to come out in four columns.And we don’t show macro names in the margin.

18 \setcounter{IndexColumns}{4}19 \let\DescribeMacro\SpecialUsageIndex20 \let\DescribeEnv\SpecialEnvIndex21 \renewcommand\PrintMacroName[1]{}22 \CodelineIndex23 %\DisableCrossrefs % Partial index24 \RecordChanges % Change log

Line numbers are very small for this article.25 \renewcommand{\theCodelineNo}26 {\scriptsize\rm\arabic{CodelineNo}}27 \settowidth\MacroIndent{\scriptsize\rm 00\ }2829 \begin{document}30 \typeout31 {****************************************32 ^^J* Expect some Under- and overfull boxes.33 ^^J****************************************}34 \DocInput{multicol.dtx}35 \end{document}36 ⟨/𭖽𭗋𭗂𭗏𭖾𭗋⟩

4.2 Identification and option processing

We start by identifying the package. Since it makesuse of features only available in LATEX 2𝜀 we ensurethat this format is available. (Now this is done ear-lier in the file.)

37 ⟨*𭗉𭖺𭖼𭗄𭖺𭗀𭖾⟩38 % \NeedsTeXFormat{LaTeX2e}39 % \ProvidesPackage{multicol}[..../../..40 % v... multicolum formatting]

Next we declare options supported by multicols.Two-column mode and multicols do not work to-gether so we warn about possible problems. How-ever, since you can revert to \onecolumn in whichcase multicols does work, we don’t make this an er-ror.

41 \DeclareOption{twocolumn}42 {\PackageWarning{multicol}{May not work43 with the twocolumn option}}

Tracing is done using a counter. However it is alsopossible to invoke the tracing using the options de-

clared below.44 \newcount\c@tracingmulticols45 \DeclareOption{errorshow}46 {\c@tracingmulticols\z@}47 \DeclareOption{infoshow}48 {\c@tracingmulticols\@ne}49 \DeclareOption{balancingshow}50 {\c@tracingmulticols\tw@}51 \DeclareOption{markshow}52 {\c@tracingmulticols\thr@@}53 \DeclareOption{debugshow}54 {\c@tracingmulticols5\relax}

The next option is intended for typesetting on a\baselineskip grid. Right now it doesn’t do any-thing other than warning if it thinks that the gridgot lost.

55 \let\mc@gridwarn\maxdimen56 \DeclareOption{grid}{\def\mc@gridwarn{\maxdepth}}57 \ProcessOptions

4.3 Starting and Ending the multicols Environment

As mentioned before, the multicols environment hasone mandatory argument (the number of columns)and up to two optional ones. We start by readingthe number of columns into the \col@number regis-ter.

58 \def\multicols#1{\col@number#1\relax

If the user forgot the argument, TEX will complainabout a missing number at this point. The errorrecovery mechanism will then use zero, which isn’ta good choice in this case. So we should now testwhether everything is okay. The minimum is two

columns at the moment.59 \ifnum\col@number<\tw@60 \PackageWarning{multicol}%61 {Using `\number\col@number'62 columns doesn't seem a good idea.^^J63 I therefore use two columns instead}%64 \col@number\tw@ \fi

We have only enough box registers for ten columns,so we need to check that the user hasn’t asked formore.

65 \ifnum\col@number>1066 \PackageError{multicol}%

7

Page 8: LaTeX - MultiCol Package

67 {Too many columns}%68 {Current implementation doesn't69 support more than 10 columns.%70 \MessageBreak71 I therefore use 10 columns instead}%72 \col@number10 \fi

Within the environment we need a special versionof the kernel \@footnotetext command since theoriginal sets the the \hsize to \columnwidth whichis not correct in the multicol environment. Here\columnwidth refers to the width of the individualcolumn and the footnote should be in \textwidth.Since \@footnotetext has a different definition in-side a minipage environment we do not redefine itdirectly. Instead we locally set \columnwidth to\textwidth and call the original (current) defini-tion stored in \orig@footnotetext. If the multi-cols environment is nested inside another multicolsenvironment then the redefinition has already hap-pened. So be better test for this situation. Other-wise, we will get a TEX stack overflow as this wouldgenerate a self-referencing definition. .

73 \ifx\@footnotetext\mult@footnotetext\else74 \let\orig@footnotetext\@footnotetext75 \let\@footnotetext\mult@footnotetext76 \fi

Now we can safely look for the optional arguments.77 \@ifnextchar[\mult@cols{\mult@cols[]}}

78 \long\def\mult@footnotetext#1{\begingroup79 \columnwidth\textwidth80 \orig@footnotetext{#1}\endgroup}

The \mult@cols macro grabs the first optional ar-gument (if any) and looks for the second one.

81 \def\mult@cols[#1]{\@ifnextchar[%

This argument should be a ⟨dimen⟩ denoting theminimum free space needed on the current page tostart the environment. If the user didn’t supply one,we use \premulticols as a default.

82 {\mult@@cols{#1}}%83 {\mult@@cols{#1}[\premulticols]}}

After removing all arguments from the input we areable to start with \mult@@cols.

84 \def\mult@@cols#1[#2]{%

First thing we do is to decide whether or not this isan unbounded multicols environment, i.e. one thatmay split across pages, or one that has to be typesetinto a box. If we are in TEX’s “inner” mode (e.g.,inside a box already) then we have a boxed versionof multicols therefore we set the @boxedmulticolsswitch to true. The multicols should start in verticalmode. If we are not already there we now force itwith \par since otherwise the test for “inner” modewouldn’t show if we are in a box.

85 \par86 \ifinner \@boxedmulticolstrue

Otherwise we check \doublecol@number. Thiscounter is zero outside a multicols environment butpositive inside (this happens a little later on). Inthe second case we need to process the current mul-ticols also in “boxed mode” and so change the switchaccordingly.

87 \else88 \ifnum \doublecol@number>\z@89 \@boxedmulticolstrue90 \fi91 \fi

Then we look to see if statistics are requested:92 \mult@info\z@93 {Starting environment with94 \the\col@number\space columns%

In boxed mode we add some more info.95 \if@boxedmulticols\MessageBreak96 (boxed mode)\fi97 }%

Then we measure the current page to see whether auseful portion of the multicolumn environment canbe typeset. This routine might start a new page.

98 \enough@room{#2}%

Now we output the first argument and produce ver-tical space above the columns. (Note that this ar-gument corresponds to the first optional argumentof the multicols environment.) For many releasesthis argument was typeset in a group to get a sim-ilar effect as \twocolumn[..] where the argumentis also implicitly surrounded by braces. However,this conflicts with local changes done by things likesectioning commands (which account for the major-ity of commands used in that argument) messing upvertical spacing etc. later in the document so thatfrom version v1.5q on this argument is again typesetat the outer level.

99 #1\par\addvspace\multicolsep

When the last line of a paragraph had a posi-tive depth then this depth normally taken into ac-count by the baselineskip calculation for the nextline. However, the columns produced by a followingmulticol are rigid and thus the distance from thebaseline of a previous text line to the first line ina multicol would differ depending on the depth ofthe previous line. To account for this we add a nega-tive space unless the depth is -1000pt which signalssomething special to TEXand is not supposed to bea real depth.100 \ifdim \prevdepth = -\@m\p@101 \else

The actual generation of this corrective space is alittle bit more complicated as it doesn’t make senseto always back up to the previous baseline (in casean object with a very large depth was placed there,

8

Page 9: LaTeX - MultiCol Package

e.g., a centered tabular). So we only back up to theextend that we are within the \baselineskip grid.We know that the box produced by multicols has\topskip at its top so that also needs to be takeninto account.102 \@tempcnta\prevdepth103 \@tempcntb\baselineskip104 \divide\@tempcnta\@tempcntb105 \advance\@tempcnta\@ne106 \dimen@\prevdepth107 \advance\dimen@ -\@tempcnta\baselineskip108 \advance\dimen@ \topskip109 \kern-\dimen@110 \fi

We start a new grouping level to hide all subsequentchanges (done in \prepare@multicols for exam-ple).111 \begingroup112 \prepare@multicols

If we are in boxed mode we now open a box to type-set all material from the multicols body into it, oth-erwise we simply go ahead.113 \if@boxedmulticols114 \setbox\mult@box\vbox\bgroup

We may have to reset some parameters at this point,perhaps \@parboxrestore would be the right actionbut I leave it for the moment.115 \fi

We finish by suppressing initial spaces.116 \ignorespaces}

Here is the switch and the box for “boxed” multicolscode.117 \newif\if@boxedmulticols118 \@boxedmulticolsfalse119 \newbox\mult@box

The \enough@room macro used above isn’t perfectbut works reasonably well in this context. We mea-sure the free space on the current page by subtract-ing \pagetotal from \pagegoal. This isn’t en-tirely correct since it doesn’t take the ‘shrinking’(i.e. \pageshrink) into account. The ‘recent con-tribution list’ might be nonempty so we start with\par and an explicit \penalty.7 Actually, we use\addpenalty to ensure that a following \addvspacewill ‘see’ the vertical space that might be present.The use of \addpenalty will have the effect that allitems from the recent contributions will be movedto the main vertical list and the \pagetotal valuewill be updated correctly. However, the penalty willbe placed in front of any dangling glue item withthe result that the main vertical list may alreadybe overfull even if TEX is not invoking the outputroutine.

120 \def\enough@room#1{%

Measuring makes only sense when we are not in“boxed mode” so the routine does nothing if theswitch is true.121 \if@boxedmulticols\else122 \par

To empty the contribution list the first release con-tained a penalty zero but this had the result that\addvspace couldn’t detect preceding glue. So thiswas changed to \addpenalty. But this turned outto be not enough as \addpenalty will not add apenalty when @nobreak is true. Therefore we forcethis switch locally to false. As a result there maybe a break between preceding text and the start ofa multicols environment, but this seems acceptablesince there is the optional argument for exactly thisreason.123 \bgroup\@nobreakfalse\addpenalty\z@\egroup124 \page@free \pagegoal125 \advance \page@free -\pagetotal

To be able to output the value we need to assign itto a register first since it might be a register (de-fault) in which case we need to use \the or it mightbe a plain value in which case \the would be wrong.

126 \@tempskipa#1\relax

Now we test whether tracing information is required:127 \mult@info\z@128 {Current page:\MessageBreak129 height=%130 \the\pagegoal: used \the\pagetotal131 \space -> free=\the\page@free132 \MessageBreak133 needed \the\@tempskipa134 \space(for #1)}%

Our last action is to force a page break if there isn’tenough room left.135 \ifdim \page@free <#1\newpage \fi136 \fi}

When preparing for multicolumn output severalthings must be done.137 \def\prepare@multicols{%

We start saving the current \@totalleftmarginand then resetting the \parshape in case we areinside some list environment. The correct inden-tation for the multicols environment in such a casewill be produced by moving the result to the rightby \multicol@leftmargin later on. If we woulduse the value of of \@totalleftmargin directly thenlists inside the multicols environment could cause ashift of the output.138 \multicol@leftmargin\@totalleftmargin139 \@totalleftmargin\z@140 \parshape\z@

7See the documentation of \endmulticols for further details.

9

Page 10: LaTeX - MultiCol Package

We also set the register \doublecol@number forlater use. This register should contain 2 ×\col@number. This is also an indicator that we arewithin a multicols environment as mentioned above.

141 \doublecol@number\col@number142 \multiply\doublecol@number\tw@143 \advance\doublecol@number\mult@rightbox

144 \if@boxedmulticols145 \let\l@kept@firstmark\kept@firstmark146 \let\l@kept@botmark\kept@botmark147 \global\let\kept@firstmark\@empty148 \global\let\kept@botmark\@empty149 \else

We add an empty box to the main vertical list toensure that we catch any insertions (held over or in-serted at the top of the page). Otherwise it mighthappen that the \eject is discarded without callingthe output routine. Inside the output routine we re-move this box again. Again this code applies onlyif we are on the main vertical list and not withina box. However, it is not enough to turn off inter-line spacing, we also have to clear \topskip beforeadding this box, since \topskip is always insertedbefore the first box on a page which would leave uswith an extra space of \topskip if multicols start ona fresh sheet.150 \nointerlineskip {\topskip\z@\null}%151 \output{%152 \global\setbox\partial@page\vbox153 {%

Now we have to make sure that we catch one spe-cial situation which may result in loss of text! Ifthe user has a huge amount of vertical materialwithin the first optional argument that is larger then\premulticols and we are near the bottom of thepage then it can happen that not the \eject istriggering this special output routine but rather theoverfull main vertical list. In that case we get an-other breakpoint through the \eject penalty. Asa result this special output routine would be calledtwice and the contents of \partial@page, i.e. thematerial before the multicols environment gets lost.There are several solutions to avoid this problem,but for now we will simply detect this and inform theuser that he/she has to enlarge the \premulticolsby using a suitable value for the second argument.154 ⟨*𭖼𭗁𭖾𭖼𭗄⟩155 \ifvoid\partial@page\else156 \PackageError{multicol}%157 {Error saving partial page}%158 {The part of the page before159 the multicols environment was160 nearly full with^^Jthe result161 that starting the environment

162 will produce an overfull163 page. Some^^Jtext may be lost!164 Please increase \premulticols165 either generally or for this%166 ^^Jenvironment by specifying a167 suitable value in the second168 optional argument to^^Jthe169 multicols environment.}170 \unvbox\partial@page171 \box\last@line172 \fi173 ⟨/𭖼𭗁𭖾𭖼𭗄⟩174 \unvbox\@cclv175 \global\setbox\last@line\lastbox176 }%

Finally we need to record the marks that are presentwithin the \partial@page so that we can constructcorrect first and bottom marks later on. This is doneby the following code.177 \prep@keptmarks

Finally we have to initialize \kept@topmark whichshould ideally be initialized with the mark that iscurrent on “top” of this page. Unfortunately wecan’t use \topmark because this register will not al-ways contain what its name promises because LATEXsometimes calls the output routine for float manage-ment.8 Therefore we use the second best solution byinitializing it with \firstmark. In fact, for our pur-pose this doesn’t matter as we use \kept@topmarkonly to initialize \firstmark and \botmark of a fol-lowing page if we don’t find any marks on the currentone.178 \global\let\kept@topmark\firstmark179 }\eject

The next thing to do is to assign a new value to\vsize. LATEX maintains the free room on the page(i.e. the page height without the space for alreadycontributed floats) in the register \@colroom. Wemust subtract the height of \partial@page to putthe actual free room into this variable.180 \advance\@colroom-\ht\partial@page

Then we have to calulate the \vsize value to useduring column assembly. \set@mult@vsize takesan argument which allows to make the setting local(\relax) or global (\global). The latter variant isused inside the output routine below. At this pointhere we have to make a local change to \vsize be-cause we want to get the original value for \vsizerestored in case this multicols environment ends onthe same page where it has started.181 \set@mult@vsize\relax

Now we switch to a new \output routine which willbe used to put the gathered column material to-gether.182 \output{\multi@column@out}%

8During such a call the \botmark gets globally copied to \topmark by the TEX program.

10

Page 11: LaTeX - MultiCol Package

Finally we handle the footnote insertions. We haveto multiply the magnification factor and the extraskip by the number of columns since each footnotereduces the space for every column (remember thatwe have pagewide footnotes). If, on the other hand,footnotes are typeset at the very end of the docu-ment, our scheme still works since \count\footinsis zero then, so it will not change. To allow evenfurther customization the setting of the \footinsparameters is done in a separate macro.183 \init@mult@footins

For the same reason (pagewide footnotes), the⟨dimen⟩ register controlling the maximum spaceused for footnotes isn’t changed. Having done this,we must reinsert all the footnotes which are alreadypresent (i.e. those encountered when the materialsaved in \partial@page was first processed). Thiswill reduce the free space (i.e. \pagetotal) by theappropriate amount since we have changed the mag-nification factor, etc. above.184 \reinsert@footnotes

All the code above was only necessary for the un-restricted multicols version, i.e. the one that allowspage breaks. If we are within a box there is no pointin setting up special output routines or \vsize, etc.185 \fi

But now we are coming to code that is necessaryin all cases. We assign new values to \vbadness,\hbadness and \tolerance since it’s rather hardfor TEX to produce ‘good’ paragraphs within nar-row columns.186 \vbadness\@Mi \hbadness5000187 \tolerance\multicoltolerance

Since nearly always the first pass will fail we ignoreit completely telling TEX to hyphenate directly. Infact, we now use another register to keep the valuefor the multicol pre-tolerance, so that a designer mayallow to use \pretolerance.188 \pretolerance\multicolpretolerance

For use with the new TEX we set\emergencystretch to \col@number × 4𝑝𝑡. How-ever this is only a guess so at the moment this isdone in a macro \setemergencystretch which getsthe current \hsize and the number of columns asarguments. Therefore users are able to figure outtheir own formula.189 \setemergencystretch\col@number\hsize

Another hook to allow people adding their ownextensions without making a new package is\set@floatcmds which handles any redefinitions of

LATEXs internal float commands to work with themulticols environment. At the moment it is onlyused to redefine \@dblfloat and \[email protected] \set@floatcmds

Additionally, we advance \baselineskip by\multicolbaselineskip to allow corrections fornarrow columns.191 \advance\baselineskip\multicolbaselineskip

The \hsize of the columns is given by the formula:

\linewidth − (\col@number − 1) × \columnsep\col@number

The formula above has changed from release torelease. We now start with the current value of\linewidth so that the column width is properlycalculated when we are inside a minipage or a listor some other environment. This will be achievedwith:192 \hsize\linewidth \advance\hsize\columnsep193 \advance\hsize-\col@number\columnsep194 \divide\hsize\col@number

We also set \linewidth and \columnwidth to\hsize In the past \columnwidth was left un-changed. This is inconsistent, but \columnwidth isused only by floats (which aren’t allowed in theircurrent implementation) and by the \footnotemacro. Since we want pagewide footnotes9 this sim-ple trick saved us from rewriting the \footnotemacros. However, some applications refered to\columnwidth as the “width of the current column”to typeset displays (the amsmath package, for exam-ple) and to allow the use of such applications to-gether with multicol this is now changed.

Before we change \linewidth to the new valuewe record its old value in some register called\full@width. This value is used later on when wepackage all columns together.195 \full@width\linewidth196 \linewidth\hsize197 \columnwidth\hsize198 }

This macro is used to set up the parameters asso-ciated with footnote floats. It can be redefined byapplications that require different amount of spaceswhen typesetting footnotes.199 \def\init@mult@footins{%200 \multiply\count\footins\col@number201 \multiply\skip \footins\col@number202 }

9I’m not sure that I really want pagewide footnotes. But balancing of the last page can only be achieved with this approachor with a multi-path algorithm which is complicated and slow. But it’s a challenge to everybody to prove me wrong! Anotherpossibility is to reimplement a small part of the fire_up procedure in TEX (the program). I think that this is the best solutionif you are interested in complex page makeup, but it has the disadvantage that the resulting program cannot be called TEXthereafter.

11

Page 12: LaTeX - MultiCol Package

Since we have to set \col@umber columns on onepage, each with a height of \@colroom, we have toassign \vsize = \col@number × \@colroom in or-der to collect enough material before entering the\output routine again. In fact we have to addanother (\col@number − 1) × (\baselineskip −\topskip) if you think about it.203 \def\set@mult@vsize#1{%204 \vsize\@colroom205 \@tempdima\baselineskip206 \advance\@tempdima-\topskip207 \advance\vsize\@tempdima208 \vsize\col@number\vsize209 \advance\vsize-\@tempdima

But this might not be enough since we use \vsplitlater to extract the columns from the gathered ma-terial. Therefore we add some ‘extra lines,’ one foreach column plus a corrective action depending onthe value of the ‘collectmore’ counter. The finalvalue is assigned globally if #1 is \global becausewe want to use this macro later inside the outputroutine too.210 \advance\vsize\col@number\baselineskip211 #1\advance\vsize212 \c@collectmore\baselineskip}

Here is the dimen register we need for saving awaythe outer value of \@totalleftmargin.213 \newdimen\multicol@leftmargin

When the end of the multicols environment is sensedwe have to balance the gathered material. Depend-ing on whether or not we are inside a boxed multicoldifferent things must happen. But first we end thecurrent paragraph with a \par command.214 \def\endmulticols{\par215 \if@boxedmulticols

In boxed mode we have to close the box in which wehave gathered all material for the columns.216 \egroup

Now we call \balance@columns the routine thatbalances material stored in the box \[email protected] \balance@columns

After balancing the result has to be returned by thecommand \page@sofar. But before we do this wereinsert any marks found in box \[email protected] \return@nonemptymark{first}%219 \kept@firstmark220 \return@nonemptymark{bot}%221 \kept@botmark222 \page@sofar

223 \global\let\kept@firstmark224 \l@kept@firstmark225 \global\let\kept@botmark226 \l@kept@botmark227 ⟨*𭗆𭖺𭗋𭗄𭗍𭗋𭖺𭖼𭖾⟩228 \mult@info\tw@229 {Restore kept marks to\MessageBreak230 first: \meaning\kept@firstmark231 \MessageBreak bot\space\space:232 \meaning\kept@botmark }%233 ⟨/𭗆𭖺𭗋𭗄𭗍𭗋𭖺𭖼𭖾⟩

This finishes the code for the “boxed” case.234 \else

If there was a \columnbreak on the very lastline all material will have been moved to the\colbreak@box. Thus the the galley will be amptyand no output routine gets called so that the textis lost. To avoid this problem (though unlikely)we check if the current galley is empty and the\colbreak@box contains text and if so return thatto the galley. If the galley is non-empty any mate-rial in \colbreak@box is added in the output routinesince it needs to be put in front.235 ⟨*𭖼𭗈𭗅𭖻𭗋𭖾𭖺𭗄⟩236 \ifdim\pagegoal=\maxdimen237 \ifvoid\colbreak@box\else238 \mult@info\@ne{Re-adding forced239 break(s) for splitting}%240 \unvbox\colbreak@box\fi241 \fi242 ⟨/𭖼𭗈𭗅𭖻𭗋𭖾𭖺𭗄⟩

If we are in an unrestricted multicols environmentwe end the current paragraph above with \par butthis isn’t sufficient since TEXs page_builder will nottotally empty the contribution list.10 Therefore wemust also add an explicit \penalty. Now the con-tribution list will be emptied and, if its materialdoesn’t all fit onto the current page then the outputroutine will be called before we change it. At thispoint we need to use \penalty not \addpenalty toensure that a) the recent contributions are emptiedand b) that the very last item on the main verticallist is a valid break point so that TEX breaks thepage in case it is overfull.243 \penalty\z@

The processed material might consist of a last linewith a decender in which case the \prevdepth willbe non-zero. However, this material is getting refor-matted now so that this value is likely to be wrong.We therefore normalize the situation by pretendingthat the depth is zero and arrange later that thebox containing the assembled columns has in factthis property.

10This once caused a puzzling bug where some of the material was balanced twice, resulting in some overprints. The reasonwas the \eject which was placed at the end of the contribution list. Then the page_builder was called (an explicit \penaltywill empty the contribution list), but the line with the \eject didn’t fit onto the current page. It was then reconsidered afterthe output routine had ended, causing a second break after one line.

12

Page 13: LaTeX - MultiCol Package

244 \prevdepth\z@

Now it’s safe to change the output routine in orderto balance the columns.245 \output{\balance@columns@out}\eject

If the multicols environment body was completelyempty or if a multi-page multicols just ends at apage boundary we have the unusual case that the\eject will have no effect (since the main verticallist is empty)—thus no output routine is called atall. As a result the material preceding the multicols(stored in \partial@page will get lost if we don’ttake of this by hand.246 \ifvbox\partial@page247 \unvbox\partial@page\fi

After the output routine has acted we restore thekept marks to their initial value.248 \global\let\kept@firstmark\@empty249 \global\let\kept@botmark\@empty250 ⟨*𭗆𭖺𭗋𭗄𭗍𭗋𭖺𭖼𭖾⟩251 \mult@info\tw@252 {Make kept marks empty}%253 ⟨/𭗆𭖺𭗋𭗄𭗍𭗋𭖺𭖼𭖾⟩254 \fi

The output routine above will take care of the\vsize and reinsert the balanced columns, etc. Butit can’t reinsert the \footnotes because we firsthave to restore the \footins parameter since weare returning to one column mode. This will bedone in the next line of code; we simply close thegroup started in \multicols.

To fix an obscure bug which is the result of thecurrent definition of the \begin … \end macros, wecheck that we are still (logically speaking) in themulticols environment. If, for example, we forget toclose some environment inside the multicols environ-ment, the following \endgroup would be incorrectlyconsidered to be the closing of this environment.255 \@checkend{multicols}%256 \endgroup

We also set the ‘unbalance’ counter to its default.This is done globally since LATEX counters are al-ways changed this way.11

257 \global\c@unbalance\z@

Now it’s time to return any footnotes if we are inunrestricted mode:258 \if@boxedmulticols\else259 \reinsert@footnotes

We also take a look at the amount of free space onthe current page to see if it’s time for a page break.The vertical space added thereafter will vanish if\enough@room starts a new page.

But there is one catch. If the \end{multicols}is at the top of which can happen if there is a break

point just before it (such as end ending environ-ment) which was chosen. In that case we would dothe next page using the internal \vsize for multicolcollection which is a desaster. So we better catchthis case. Fortunately we can detect it by lookingat \pagegoal.260 \ifdim \pagegoal=\maxdimen261 \global\vsize\@colroom262 \else263 \enough@room\postmulticols264 \fi265 \fi266 \addvspace\multicolsep

If statistics are required we finally report that wehave finished everything.267 \mult@info\z@268 {Ending environment269 \if@boxedmulticols270 \space(boxed mode)\fi271 }}

Let us end this section by allocating all the registersused so far.272 \newcount\c@unbalance273 \newcount\c@collectmore

In the new LATEX release \col@number is already al-located by the kernel, so we don’t allocate it again.274 %\newcount\col@number275 \newcount\doublecol@number276 \newcount\multicoltolerance277 \newcount\multicolpretolerance278 \newdimen\full@width279 \newdimen\page@free280 \newdimen\premulticols281 \newdimen\postmulticols282 \newskip\multicolsep283 \newskip\multicolbaselineskip284 \newbox\partial@page285 \newbox\last@line

And here are their default values:286 \c@unbalance = 0287 \c@collectmore = 0

To allow checking whether some macro is usedwithin the multicols environment the counter\col@number gets a default of 1 outside the the en-vironment.288 \col@number = 1289 \multicoltolerance = 9999290 \multicolpretolerance = -1291 \premulticols = 50pt292 \postmulticols= 20pt293 \multicolsep = 12pt plus 4pt minus 3pt294 \multicolbaselineskip=0pt

11Actually, we are still in a group started by the \begin macro, so \global must be used anyway.

13

Page 14: LaTeX - MultiCol Package

4.4 The output routines

We first start with some simple macros. When type-setting the page we save the columns either in thebox registers 0, 2, 4,… (locally) or 1, 3, 5,… (globally).This is Plain TEX policy to avoid an overflow of thesave stack.

Therefore we define a \process@cols macro to helpus in using these registers in the output routinesbelow. It has two arguments: the first one is anumber; the second one is the processing informa-tion. It loops starting with \count@=#1 (\count@ isa scratch register defined in Plain TEX), processesargument #2, adds two to \count@, processes ar-gument #2 again, etc. until \count@ is higher than\doublecol@number. It might be easier to under-stand it through an example, so we define it nowand explain its usage afterwards.295 \def\process@cols#1#2{\count@#1\relax296 \loop297 ⟨*𭖽𭖾𭖻𭗎𭗀⟩298 \typeout{Looking at box \the\count@}299 ⟨/𭖽𭖾𭖻𭗎𭗀⟩300 #2%301 \advance\count@\tw@302 \ifnum\count@<\doublecol@number303 \repeat}

We now define \page@sofar to give an example ofthe \process@cols macro. \page@sofar shouldoutput everything prepared by the balancing rou-tine \[email protected] \def\page@sofar{%

\balance@columns prepares its output in the evennumbered scratch box registers. Now we outputthe columns gathered assuming that they are savedin the box registers 2 (left column), 4 (second col-umn), … However, the last column (i.e. the right-most) should be saved in box register 0.12 Firstwe ensure that the columns have equal width. Weuse \process@cols for this purpose, starting with\count@ = \mult@rightbox. Therefore \count@loops through \mult@rightbox, \mult@rightbox+2,…(to \doublecol@number).305 \process@cols\mult@rightbox

We have to check if the box in question is void, be-cause the operation \wd⟨number⟩ on a void box willnot change its dimension (sigh).306 {\ifvoid\count@307 \setbox\count@\hbox to\hsize{}%308 \else309 \wd\count@\hsize310 \fi}%

Now we give some tracing information.311 \count@\col@number \advance\count@\m@ne312 \mult@info\z@313 {Column spec: \the\full@width\space = indent314 + columns + sep =\MessageBreak315 \the\multicol@leftmargin\space316 + \the\col@number\space317 x \the\hsize\space318 + \the\count@\space319 x \the\columnsep320 }%

At this point we should always be in vertical mode.321 \ifvmode\else\errmessage{Multicol Error}\fi

Now we put all columns together in an\hbox of width \full@width (shifting it by\multicol@leftmargin to the right so that it willbe placed correctly if we are within a list environ-ment) and separating the columns with a rule ifdesired.

The box containing the columns has a large heightand thus will always result in using \lineskip if thenormal \baselineskip calculations are used. Wetherefore better cancel that process.322 \nointerlineskip

As mentioned earlier we want to have the referencepoint of the box we put on the page being at thebaseline of the last line of the columns but we alsowant to ensure that the box has no depth so that anyfollowing skip is automatically starting from thatbaseline. We achieve this by recording the depthsof all columns and then finally backing up by themaximum. (perhaps a simpler method would be toassemble the box in a register and set the depth ofthat box to zero (not checked).

We need a global scratch register for this; usingstandard TEX conventions we choose \dimen2 andinitialize it with the depth of the character “p” sincethat is one of the depths that compete for the max-imum.323 \setbox\z@\hbox{p}\global\dimen\tw@\dp\z@

If the document is written in a language that is type-set right-to-left then, of course, the multicol columnsshould be also typeset right-to-left. To support thiswe call \maybe@reverse@columns which either doesnothin (in the LR case) or re-sorts the columns sothat they come out in reverse order (for the RLcase).324 \maybe@reverse@columns

After that we can output all columns regardless oftypesetting direction in the same way.325 \moveright\multicol@leftmargin

12You will see the reason for this numbering when we look at the output routines \multi@column@out and\balance@columns@out.

14

Page 15: LaTeX - MultiCol Package

326 \hbox to\full@width{%327 \process@cols\mult@gfirstbox{%

If the depth of the current box is larger than themaximum found so far in \dimen2 we update thatregister.328 \ifdim\dp\count@>\dimen\tw@329 \global\dimen\tw@\dp\count@ \fi330 \box\count@331 \hss{\columnseprulecolor\vrule332 \@width\columnseprule}\hss}%

As you will have noticed, we started with box regis-ter \mult@gfirstbox (i.e. the left column). So thistime \count@ looped through 2, 4,… (plus the appro-priate offset). Finally we add box 0 and close the\hbox. Again we may have to update \dimen\[email protected] \ifdim\dp\mult@rightbox>\dimen\tw@334 \global\dimen\tw@\dp\mult@rightbox \fi335 \box\mult@rightbox

The depths of the columns depend on their last lines.To ensure that we will always get a similar look asfar as the rules are concerned we force the depth atleast the depth of a letter ‘p’.336 \rlap{\phantom p}%337 }%

Now after typesetting the box we back up to itsbaseline by using the value stored in \dimen2.338 \kern-\dimen\tw@

However, in case one of the columns was unusuallydeep TEX may have tried some corrective actions inwhich case backing up by the saved value will notbring us back to the baseline. A good indication forthis is a depth of \maxdepth though it is not an abso-lute proof. If the option grid is used \mc@gridwarnwill expand to this, otherwise to \maxdimen in whichcase this warning will not show up.339 \ifdim\dimen\tw@ = \mc@gridwarn340 \PackageWarning{multicol}%341 {Very deep columns!\MessageBreak342 Grid alignment might be broken}%343 \fi344 }

By default the vertical rule between columns will bein \normalcolor.345 \def\columnseprulecolor{\normalcolor}

Before we tackle the bigger output routines wedefine just one more macro which will help usto find our way through the mysteries later.\reinsert@footnotes will do what its name in-dicates: it reinserts the footnotes present in\footinbox so that they will be reprocessed byTEX’s page_builder.

Instead of actually reinserting the footnotes weinsert an empty footnote. This will trigger insertionmechanism as well and since the old footnotes are

still in their box and we are on a fresh page \skipfootins should be correctly taken into account.346 \def\reinsert@footnotes{\ifvoid\footins\else347 \insert\footins{}\fi}

Now we can’t postpone the difficulties any longer.The \multi@column@out routine will be called intwo situations. Either the page is full (i.e., wehave collected enough material to generate all therequired columns) or a float or marginpar or a\clearpage is sensed. In the latter case the\outputpenalty is less than −10000, otherwise thepenalty which triggered the output routine is higher.Therefore it’s easy to distinguish both cases: we sim-ply test this register.348 \def\multi@column@out{%349 \ifnum\outputpenalty <-\@M

If this was a \clearpage, a float or a marginpar wecall \speci@ls350 \speci@ls \else

otherwise we construct the final page. For the nextblock of code see comments in section 7.2.351 ⟨*𭖼𭗈𭗅𭖻𭗋𭖾𭖺𭗄⟩352 \ifvoid\colbreak@box\else353 \mult@info\@ne{Re-adding forced354 break(s) for splitting}%355 \setbox\@cclv\vbox{%356 \unvbox\colbreak@box357 \penalty-\@Mv\unvbox\@cclv}%358 \fi359 ⟨/𭖼𭗈𭗅𭖻𭗋𭖾𭖺𭗄⟩Let us now consider the normal case. We have to\vsplit the columns from the accumulated mate-rial in box 255. Therefore we first assign appropriatevalues to \splittopskip and \splitmaxdepth.360 \splittopskip\topskip361 \splitmaxdepth\maxdepth

Then we calculate the current column height (in\dimen@). Note that the height of \partial@pageis already subtracted from \@colroom so we can useits value as a starter.362 \dimen@\@colroom

But we must also subtract the space occupied byfootnotes on the current page. Note that we firsthave to reset the skip register to its normal value.Again, the actual action is carried out in a utilitymacro, so that other applications can modify it.363 \divide\skip\footins\col@number364 \ifvoid\footins \else365 \leave@mult@footins366 \fi

Now we are able to \vsplit off all but the last col-umn. Recall that these columns should be saved inthe box registers 2, 4,… (plus offset).367 \process@cols\mult@gfirstbox{%368 \setbox\count@369 \vsplit\@cclv to\dimen@

15

Page 16: LaTeX - MultiCol Package

After splitting we update the kept marks.370 \set@keptmarks

If \raggedcolumns is in force we add a vfill at thebottom by unboxing the split box.371 \ifshr@nking372 \setbox\count@373 \vbox to\dimen@374 {\unvbox\count@\vfill}%375 \fi376 }%

Then the last column follows.377 \setbox\mult@rightbox378 \vsplit\@cclv to\dimen@379 \set@keptmarks380 \ifshr@nking381 \setbox\mult@rightbox\vbox to\dimen@382 {\unvbox\mult@rightbox\vfill}%383 \fi

Having done this we hope that box 255 is emptied.If not, we reinsert its contents.384 \ifvoid\@cclv \else385 \unvbox\@cclv386 \penalty\outputpenalty

In this case a footnote that happens to fall intothe leftover bit will be typeset on the wrong page.Therefore we warn the user if the current page con-tains footnotes. The older versions of multicols pro-duced this warning regardless of whether or not foot-notes were present, resulting in many unnecessarywarnings.387 \ifvoid\footins\else388 \PackageWarning{multicol}%389 {I moved some lines to390 the next page.\MessageBreak391 Footnotes on page392 \thepage\space might be wrong}%393 \fi

If the ‘tracingmulticols’ counter is 4 or higher we alsoadd a rule.394 \ifnum \c@tracingmulticols>\thr@@395 \hrule\allowbreak \fi396 \fi

To get a correct marks for the current pagewe have to (locally) redefine \firstmark and\botmark. If \kept@firstmark is non-empty then\kept@botmark must be non-empty too so we canuse their values. Otherwise we use the value of\kept@topmark which was first initialized when wegathered the \partical@page and later on was up-dated to the \botmark for the preceding page.397 \ifx\@empty\kept@firstmark398 \let\firstmark\kept@topmark399 \let\botmark\kept@topmark400 \else

401 \let\firstmark\kept@firstmark402 \let\botmark\kept@botmark403 \fi

We also initalize \topmark with \[email protected] will make this mark okay for all middle pagesof the multicols environment.404 \let\topmark\kept@topmark405 ⟨*𭗆𭖺𭗋𭗄𭗍𭗋𭖺𭖼𭖾⟩406 \mult@info\tw@407 {Use kept top mark:\MessageBreak408 \meaning\kept@topmark409 \MessageBreak410 Use kept first mark:\MessageBreak411 \meaning\kept@firstmark412 \MessageBreak413 Use kept bot mark:\MessageBreak414 \meaning\kept@botmark415 \MessageBreak416 Produce first mark:\MessageBreak417 \meaning\firstmark418 \MessageBreak419 Produce bot mark:\MessageBreak420 \meaning\botmark421 \@gobbletwo}%422 ⟨/𭗆𭖺𭗋𭗄𭗍𭗋𭖺𭖼𭖾⟩With a little more effort we could have done bet-ter. If we had, for example, recorded the shrinkageof the material in \partial@page it would be nowpossible to try higher values for \dimen@ (i.e. thecolumn height) to overcome the problem with thenonempty box 255. But this would make the codeeven more complex so I skipped it in the currentimplementation.

Now we use LATEX’s standard output mecha-nism.13 Admittedly this is a funny way to do it.423 \setbox\@cclv\vbox{\unvbox\partial@page424 \page@sofar}%

The macro \@makecol adds all floats assigned forthe current page to this page. \@outputpage shipsout the resulting box. Note that it is just possiblethat such floats are present even if we do not allowany inside a multicols environment.425 \@makecol\@outputpage

After the page is shipped out we have to pre-pare the kept marks for the following page.\kept@firstmark and \kept@botmark reinitilizedby setting them to \@empty. The value of \botmarkis then assigned to \[email protected] \global\let\kept@topmark\botmark427 \global\let\kept@firstmark\@empty428 \global\let\kept@botmark\@empty429 ⟨*𭗆𭖺𭗋𭗄𭗍𭗋𭖺𭖼𭖾⟩430 \mult@info\tw@431 {(Re)Init top mark:\MessageBreak432 \meaning\kept@topmark

13This will produce a lot of overhead since both output routines are held in memory. The correct solution would be toredesign the whole output routine used in LATEX.

16

Page 17: LaTeX - MultiCol Package

433 \@gobbletwo}%434 ⟨/𭗆𭖺𭗋𭗄𭗍𭗋𭖺𭖼𭖾⟩Now we reset \@colroom to \@colht which isLATEX’s saved value of \textheight.435 \global\@colroom\@colht

Then we process deferred floats waiting for theirchance to be placed on the next page.436 \process@deferreds437 \@whilesw\if@fcolmade\fi{\@outputpage438 \global\@colroom\@colht439 \process@deferreds}%

If the user is interested in statistics we inform himabout the amount of space reserved for floats.440 \mult@info\@ne441 {Colroom:\MessageBreak442 \the\@colht\space443 after float space removed444 = \the\@colroom \@gobble}%

Having done all this we must prepare to tackle thenext page. Therefore we assign a new value to\vsize. New, because \partial@page is now emptyand \@colroom might be reduced by the space re-served for floats.445 \set@mult@vsize \global

The \footins skip register will be adjusted whenthe output group is closed.446 \fi}

This macro is used to subtract the amount of spaceoccupied by footnotes for the current space from thespace available for the current column. The spacecurrent column is stored in \dimen@. See above forthe description of the default action.447 \def\leave@mult@footins{%448 \advance\dimen@-\skip\footins449 \advance\dimen@-\ht\footins450 }

We left out two macros: \process@deferreds and\[email protected] \def\speci@ls{%452 \ifnum\outputpenalty <-\@Mi

If the document ends in the middle of a mul-ticols environment, e.g., if the user forgot the\end{multicols}, TEX adds a very negativepenalty to the end of the galley which is intendedto signal the output routine that it is time to pre-pare for shipping out everything remaining. Sinceinside multicols the output routine of LATEX is dis-abled sometimes we better check for this case: ifwe find a very negative penalty we produce an errormessage and run the default output routine for thiscase.453 \ifnum \outputpenalty<-\@MM454 \PackageError{multicol}{Document end455 inside multicols environment}\@ehd

456 \@specialoutput457 \else

For the next block of code see comments in sec-tion 7.2.458 ⟨*𭖼𭗈𭗅𭖻𭗋𭖾𭖺𭗄⟩459 \ifnum\outputpenalty = -\@Mv460 \mult@info\@ne{Forced column461 break seen}%462 \global\advance\vsize-\pagetotal463 \global\setbox\colbreak@box464 \vbox{\ifvoid\colbreak@box465 \else466 \unvbox\colbreak@box467 \penalty-\@Mv468 \fi469 \unvbox\@cclv}470 \reinsert@footnotes471 \else472 ⟨/𭖼𭗈𭗅𭖻𭗋𭖾𭖺𭗄⟩

If we encounter a float or a marginpar in the currentimplementation we simply warn the user that thisis not allowed. Then we reinsert the page and itsfootnotes.473 \PackageWarningNoLine{multicol}%474 {Floats and marginpars not475 allowed inside `multicols'476 environment!}477 \unvbox\@cclv\reinsert@footnotes

Additionally we empty the \@currlist to avoidlater error messages when the LATEX output routineis again in force. But first we have to place theboxes back onto the \@freelist. (\@elts default is\relax so this is possible with \xdef.)478 \xdef\@freelist{\@freelist\@currlist}%479 \gdef\@currlist{}%480 ⟨*𭖼𭗈𭗅𭖻𭗋𭖾𭖺𭗄⟩481 \fi482 ⟨/𭖼𭗈𭗅𭖻𭗋𭖾𭖺𭗄⟩483 \fi

If the penalty is −10001 it will come from a\clearpage and we will execute \@doclearpage toget rid of any deferred floats.484 \else \@doclearpage \fi485 }

\process@deferreds is a simplified version ofLATEX’s \@startpage. We first call the macro\@floatplacement to save the current user parame-ters in internal registers. Then we start a new groupand save the \@deferlist temporarily in the macro\@tempb.486 \def\process@deferreds{%487 \@floatplacement488 \@tryfcolumn\@deferlist489 \if@fcolmade\else490 \begingroup491 \let\@tempb\@deferlist

17

Page 18: LaTeX - MultiCol Package

Our next action is to (globally) empty \@deferlistand assign a new meaning to \@elt. Here\@scolelt is a macro that looks at the boxes ina list to decide whether they should be placed onthe next page (i.e. on \@toplist or \@botlist) orshould wait for further processing.492 \gdef\@deferlist{}%493 \let\@elt\@scolelt

Now we call \@tempb which has the form

\@elt⟨box register⟩\@elt⟨box register⟩…

So \@elt (i.e. \@scolelt) will distribute the boxesto the three lists.494 \@tempb \endgroup495 \fi}

The \raggedcolumns and \flushcolumns declara-tions are defined with the help of a new \if...macro.496 \newif\ifshr@nking

The actual definitions are simple: we just switch totrue or false depending on the desired action. Toavoid extra spaces in the output we enclose thesechanges in \@bsphack…\@esphack.497 \def\raggedcolumns{%498 \@bsphack\shr@nkingtrue\@esphack}499 \def\flushcolumns{%500 \@bsphack\shr@nkingfalse\@esphack}

Now for the last part of the show: the column bal-ancing output routine. Since this code is called withan explicit penalty (\eject) there is no need tocheck for something special (eg floats). We startby balancing the material gathered.501 \def\balance@columns@out{%

For this we need to put the contents of box 255 into\[email protected] ⟨-𭖼𭗈𭗅𭖻𭗋𭖾𭖺𭗄⟩ \setbox\mult@box503 ⟨-𭖼𭗈𭗅𭖻𭗋𭖾𭖺𭗄⟩ \vbox{\unvbox\@cclv}%

For the next block of code see comments in sec-tion 7.2.504 ⟨*𭖼𭗈𭗅𭖻𭗋𭖾𭖺𭗄⟩505 \setbox\mult@box\vbox{%506 \ifvoid\colbreak@box\else507 \unvbox\colbreak@box\break508 \mult@info\@ne{Re-adding509 forced break(s) in balancing}%510 \fi511 \unvbox\@cclv}%512 ⟨/𭖼𭗈𭗅𭖻𭗋𭖾𭖺𭗄⟩513 \balance@columns

This will bring us into the position to apply\page@sofar. But first we have to set \vsize toa value suitable for one column output.514 \global\vsize\@colroom515 \global\advance\vsize\ht\partial@page

Then we \unvbox the \partial@page (which maybe void if we are not prcessing the first page of thismulticols environment.516 \unvbox\partial@page

Then we return the first and bottom mark and thegathered material to the main vertical list.517 \return@nonemptymark{first}\kept@firstmark518 \return@nonemptymark{bot}\kept@botmark519 \page@sofar

We need to add a penalty at this point which allowsto break at this point since calling the output rou-tine may have removed the only permissible breakpoint thereby “glueing” any following skip to thebalanced box. In case there are any weird settingsfor \multicolsep etc. this could produce funny re-sults.520 \penalty\z@521 }

As we already know, reinserting of footnotes will bedone in the macro \endmulticols.

This macro now does the actual balancing.522 \def\balance@columns{%

We start by setting the kept marks by updatingthem with any marks from this box. This has tobe done before we add a penalty of −10000 to thetop of the box, otherwise only an empty box will beconsidered.523 \get@keptmarks\mult@box

We then contine by resetting trying to remove anydiscardable stuff at the end of \mult@box. This israther experimental. We also add a forced breakpoint at the very beginning, so that we can split thebox to height zero later on, thereby adding a known\splittopskip glue at the beginning.524 \setbox\mult@box\vbox{%525 \penalty-\@M526 \unvbox\mult@box527 \remove@discardable@items528 }%

Then follow values assignments to get the\vsplitting right. We use the natural part of\topskip as the natural part for \splittopskipand allow for a bit of undershoot and overshoot byadding some stretch and shrink.529 \@tempdima\topskip530 \splittopskip\@tempdima531 \@plus\multicolundershoot532 \@minus\multicolovershoot533 \splitmaxdepth\maxdepth

The next step is a bit tricky: when TEX assem-bles material in a box, the first line isn’t precededby interline glue, i.e. there is no parameter like\boxtopskip in TEX. This means that the baselineof the first line in our box is at some unpredictable

18

Page 19: LaTeX - MultiCol Package

point depending on the height of the largest charac-ter in this line. But of course we want all columnsto align properly at the baselines of their first lines.For this reason we have opened \mult@box with a\penalty -10000. This will now allow us to splitoff from \mult@box a tiny bit (in fact nothing sincethe first possible break-point is the first item in thebox). The result is that \splittopskip is insertedat the top of \mult@box which is exactly what welike to achieve.534 \setbox\@tempboxa\vsplit\mult@box to\z@

Next we try to find a suitable starting point forthe calculation of the column height. It should beless than the height finally chosen, but large enoughto reach this final value in only a few iterations.The formula which is now implemented will try tostart with the nearest value which is a multiple of\baselineskip. The coding is slightly tricky in TEXand there are perhaps better ways …535 \@tempdima\ht\mult@box536 \advance\@tempdima\dp\mult@box537 \divide\@tempdima\col@number

The code above sets \@tempdima to the length ofa column if we simply divide the whole box intoequal pieces. To get to the next lower multiple of\baselineskip we convert this dimen to a num-ber (the number of scaled points) then divide thisby \baselineskip (also in scaled points) and thenmultiply this result with \baselineskip assigningthe result to \dimen@. This makes \dimen@ ≤ to\@tempdimena.538 \count@\@tempdima539 \divide\count@\baselineskip540 \dimen@\count@\baselineskip

Next step is to correct our result by takinginto account the difference between \topskip and\baselineskip. We start by adding \topskip; ifthis makes the result too large then we have to sub-tract one \baselineskip.541 \advance\dimen@\topskip542 \ifdim \dimen@ >\@tempdima543 \advance\dimen@-\baselineskip544 \fi

At the user’s request we start with a higher value (orlower, but this usually only increases the number oftries).545 \advance\dimen@\c@unbalance\baselineskip

We type out statistics if we were asked to do so.546 \mult@info\@ne547 {Balance columns\on@line:548 \ifnum\c@unbalance=\z@\else549 (off balance=\number\c@unbalance)\fi550 \@gobbletwo}%

But we don’t allow nonsense values for a start.551 \ifnum\dimen@<\topskip

552 \mult@info\@ne553 {Start value554 \the\dimen@ \space ->555 \the\topskip \space (corrected)}%556 \dimen@\topskip557 \fi

Now we try to find the final column height. We startby setting \vbadness to infinity (i.e. 10000) to sup-press underfull box reports while we are trying tofind an acceptable solution. We do not need to doit in a group since at the end of the output routineeverything will be restored. The setting of the finalcolumns will nearly always produce underfull boxeswith badness 10000 so there is no point in warningthe user about it.558 \vbadness\@M

We also allow for overfull boxes while we trying tosplit the columns.559 \vfuzz \col@number\baselineskip

The variable \last@try will hold the dimensionused in the previous trial splitting. We initializeit with a negative value.560 \last@try-\p@561 \loop

In order not to clutter up TEX’s valuable mainmemory with things that are no longer needed, weempty all globally used box registers. This is nec-essary if we return to this point after an unsuc-cessful trial. We use \process@cols for this pur-pose, starting with \mult@grightbox. Note the ex-tra braces around this macro call. They are neededsince Plain TEX’s \loop…\repeat mechanism can-not be nested on the same level of grouping.562 {\process@cols\mult@grightbox563 {\global\setbox\count@564 \box\voidb@x}}%

The contents of box \mult@box are now copied glob-ally to box \mult@grightbox. (This will be theright-most column, as we shall see later.)565 \global\setbox\mult@grightbox566 \copy\mult@box

We start with the assumption that the trial will besuccessful. If we end up with a solution that is toobad we set too@bad to true.567 ⟨*𭖻𭖺𭖽𭗇𭖾𭗌𭗌⟩568 \global\too@badfalse569 ⟨/𭖻𭖺𭖽𭗇𭖾𭗌𭗌⟩

Using \vsplit we extract the other columns frombox register \mult@grightbox. This leaves box reg-ister \mult@box untouched so that we can start overagain if this trial was unsuccessful.570 {\process@cols\mult@firstbox{%571 \global\setbox\count@572 \vsplit\mult@grightbox to\dimen@

19

Page 20: LaTeX - MultiCol Package

After every split we check the badness of the result-ing column, normally the amount of extra white inthe column.573 ⟨*𭖻𭖺𭖽𭗇𭖾𭗌𭗌⟩574 \ifnum\c@tracingmulticols>\@ne575 \@tempcnta\count@576 \advance\@tempcnta-\mult@grightbox577 \divide\@tempcnta \tw@578 \message{^^JColumn579 \number\@tempcnta\space580 badness: \the\badness\space}%581 \fi

If this badness is larger than the allowed columnbadness we reject this solution by setting too@badto true.582 \ifnum\badness>\c@columnbadness583 \ifnum\c@tracingmulticols>\@ne584 \message{too bad585 (>\the\c@columnbadness)}%586 \fi587 \global\too@badtrue588 \fi589 ⟨/𭖻𭖺𭖽𭗇𭖾𭗌𭗌⟩590 }}%

There is one subtle point here: while all other con-structed boxes have a depth that is determined by\splitmaxdepth the last box will get a naturaldepth disregarding the original setting and the valueof \splitmaxdepth or \boxmaxdepth. This meansthat we may end up with a very large depth in box\mult@grightbox which would make the result ofthe testing incorrect. So we change the value byunboxing the box into itself.591 \boxmaxdepth\maxdepth592 \global\setbox\mult@grightbox593 \vbox{\unvbox\mult@grightbox}%

We also save a copy \mult@firstbox at its “natu-ral” size for later use.594 \setbox\mult@nat@firstbox595 \vbox{\unvcopy\mult@firstbox}%

After \process@cols has done its job we have thefollowing situation:

box \mult@rightbox all materialbox \mult@gfirstbox first column

box \mult@gfirstbox + 2 second column⋮ ⋮

box \mult@grightbox last column

We report the height of the first column, in bracketsthe natural size is given.596 \ifnum\c@tracingmulticols>\@ne597 \message{^^JFirst column598 = \the\dimen@\space599 (\the\ht\mult@nat@firstbox)}\fi

If \raggedcolumns is in force older releases of thisfile also shrank the first column to its natural heightat this point. This was done so that the first col-umn doesn’t run short compared to later columnsbut it is actually producing incorrect results (over-printing of text) in boundary cases, so since versionv1.5q \raggedcolumns means allows for all columnsto run slightly short.600 % \ifshr@nking601 % \global\setbox\mult@firstbox602 % \copy\mult@nat@firstbox603 % \fi

Then we give information about the last column.14

604 \ifnum\c@tracingmulticols>\@ne605 \message{<> last column =606 \the\ht\mult@grightbox^^J}%

Some tracing code that we don’t compile into theproduction version unless asked for. It will producehuge listings of the boxes involved in balancing inthe transcript file.607 ⟨*𭖽𭖾𭖻𭗎𭗀⟩608 \ifnum\c@tracingmulticols>4609 {\showoutput610 \batchmode611 \process@cols\mult@grightbox612 {\showbox\count@}}%613 \errorstopmode614 \fi615 ⟨/𭖽𭖾𭖻𭗎𭗀⟩616 \fi

We check whether our trial was successful. The testused is very simple: we merely compare the first andthe last column. Thus the intermediate columnsmay be longer than the first if \raggedcolumnsis used. If the right-most column is longer thanthe first then we start over with a larger value for\[email protected] \ifdim\ht\mult@grightbox >\dimen@

If the height of the last box is too large we mark thistrial as unsuccessful.618 ⟨*𭖻𭖺𭖽𭗇𭖾𭗌𭗌⟩619 \too@badtrue620 \ifnum\c@tracingmulticols>\@ne621 \typeout{Rejected: last622 column too large!}%623 \fi624 \else

To ensure that there isn’t a forced break in the lastcolumn we try to split off a box of size \maxdimenfrom \mult@grightbox (or rather from a copy of it).This should result in a void box after the split, un-less there was a forced break somewhere within thecolumn in which case the material after the breakwould have stayed in the box.

14With TEX version 3.141 it is now possible to use LATEX’s \newlinechar in the \message command, but people with olderTEX versions will now get ^^J instead of a new line on the screen.

20

Page 21: LaTeX - MultiCol Package

625 ⟨*𭖼𭗈𭗅𭖻𭗋𭖾𭖺𭗄⟩626 \setbox\@tempboxa627 \copy\mult@grightbox628 \setbox\z@\vsplit\@tempboxa to\maxdimen629 \ifvoid\@tempboxa630 ⟨/𭖼𭗈𭗅𭖻𭗋𭖾𭖺𭗄⟩Thus if \@tempboxa is void we have a valid solution.In this case we take a closer look at the last columnto decide if this column should be made as long asall other columns or if it should be allowed to beshorter. For this we first have to rebox the columninto a box of the appropriate height. If tracing isenabled we then display the badness for this box.631 \global\setbox\mult@grightbox632 \vbox to\dimen@633 {\unvbox\mult@grightbox}%634 \ifnum\c@tracingmulticols>\@ne635 \message{Final badness:636 \the\badness}%637 \fi

We then compare this badness with the allowed bad-ness for the final column. If it does not exceed thisvalue we use the box, otherwise we rebox it oncemore and add some glue at the bottom.638 \ifnum\badness>\c@finalcolumnbadness639 \global\setbox\mult@grightbox640 \vbox to\dimen@641 {\unvbox\mult@grightbox\vfill}%642 \ifnum\c@tracingmulticols>\@ne643 \message{ setting natural644 (> \the\c@finalcolumnbadness)}%645 \fi646 \fi

If \@tempboxa above was not void our trial was un-successful and we report this fact and try again.647 ⟨*𭖼𭗈𭗅𭖻𭗋𭖾𭖺𭗄⟩648 \else649 \too@badtrue650 \ifnum\c@tracingmulticols>\@ne651 \typeout{Rejected: unprocessed652 forced break(s) in last column!}%653 \fi654 \fi655 ⟨/𭖼𭗈𭗅𭖻𭗋𭖾𭖺𭗄⟩656 \fi

If the natural height of the first box is smaller thanthe current trial size but is larger than the previoustrial size it is likely that we have missed a potien-tially better solution. (This could have happened iffor some reason our first trial size was too high.) Inthat case we dismiss this trial and restart using thenatural height for the next trial.657 \ifdim\ht\mult@nat@firstbox<\dimen@658 \ifdim\ht\mult@nat@firstbox>\last@try

659 \too@badtrue660 \ifnum\c@tracingmulticols>\@ne661 \typeout{Retry: using natural662 height of first column!}%663 \fi664 \dimen@\ht\mult@nat@firstbox665 \last@try\dimen@666 \advance\dimen@-\p@667 \fi668 \fi

Finally the switch too@bad is tested. If it was madetrue either earlier on or due to a rightmost columnbeing too large we try again with a slightly largervalue for \[email protected] \iftoo@bad670 ⟨/𭖻𭖺𭖽𭗇𭖾𭗌𭗌⟩671 \advance\dimen@\p@672 \repeat

At that point \dimen@ holds the height that was de-termined by the balancing loop. If that height forthe columns turns out to be larger than the availablespace (which is \@colroom) we sqeeze the columnsinto the space assuming that they will have enoughshrinkability to allow this.15 However, this squeez-ing should only be done if we are balancing columnson the main galley and not if we are building a boxedmulticol (in the latter case the current \@colroom isirrelevant since the produced box might be movedanywhere at a later stage).673 \if@boxedmulticols\else674 \ifdim\dimen@>\@colroom675 \dimen@\@colroom676 \fi677 \fi

Then we move the contents of the odd-numberedbox registers to the even-numbered ones, shrinkingthem if requested. We have to use \vbox not \vtop(as it was done in the first versions) since otherwisethe resulting boxes will have no height (TEXbookpage 81). This would mean that extra \topskipis added when the boxes are returned to the page-builder via \[email protected] \process@cols\mult@rightbox679 {\@tempcnta\count@680 \advance\@tempcnta\@ne681 \setbox\count@\vbox to\dimen@682 {%

683 \vskip \z@684 \@plus-\multicolundershoot685 \@minus-\multicolovershoot686 \unvbox\@tempcnta687 \ifshr@nking\vfill\fi}}%688 }

15This might be wrong, since the shrinkability that accounts for the amount of material might be present only in somecolumns. But it is better to try then to give up directly.

21

Page 22: LaTeX - MultiCol Package

4.5 The box allocations

Early releases of these macros used the first boxregisters 0, 2, 4,… for global boxes and 1, 3, 5,…for the corresponding local boxes. (You might stillfind some traces of this setup in the documentation,sigh.) This produced a problem at the moment wehad more than 5 columns because then officially allo-cated boxes were overwritten by the algorithm. Thenew release now uses private box registers689 \newbox\mult@rightbox690 \newbox\mult@grightbox691 \newbox\mult@gfirstbox

692 \newbox\mult@firstbox693 \newbox\@tempa\newbox\@tempa694 \newbox\@tempa\newbox\@tempa695 \newbox\@tempa\newbox\@tempa696 \newbox\@tempa\newbox\@tempa697 \newbox\@tempa\newbox\@tempa698 \newbox\@tempa\newbox\@tempa699 \newbox\@tempa\newbox\@tempa700 \newbox\@tempa\newbox\@tempa701 \newbox\@tempa702 \let\@tempa\relax

5 New macros and hacks for version 1.2If we don’t use TEX 3.0 \emergencystretch is un-defined so in this case we simply add it as an unused⟨dimen⟩ register.703 \@ifundefined{emergencystretch}704 {\newdimen\emergencystretch}{}

My tests showed that the following for-mula worked pretty well. Nevertheless the\setemergencystretch macro also gets \hsize assecond argument to enable the user to try differentformulae.705 \def\setemergencystretch#1#2{%706 \emergencystretch 4pt707 \multiply\emergencystretch#1}

Even if this should be used as a hook we use a @ inthe name since it is more for experts.708 \def\set@floatcmds{%709 \let\@dblfloat\@dbflt710 \def\end@dblfloat{\@endfloatbox

711 \@largefloatcheck712 \outer@nobreak

This is cheap (defering the floats until after the cur-rent page) but any other solution would go deep intoLATEX’s output routine and I don’t like to work on ituntil I know which parts of the output routine haveto be reimplemented anyway for LATEX3.713 \ifnum\@floatpenalty<\z@

We have to add the float to the \@deferlist be-cause we assume that outside the multicols environ-ment we are in one column mode. This is not en-tirely correct, I already used the multicols environ-ment inside of LATEXs \twocolumn declaration butit will do for most applications.714 \@cons\@deferlist\@currbox715 \fi716 \ifnum\@floatpenalty=-\@Mii717 \@Esphack718 \fi}}

5.1 Maintaining the mark registers

This section contains the routines that set the marksso that they will be handled correctly. They havebeen introduced with version 1.4.

First thing we do is to reserve three macro namesto hold the replacement text for TEX’s primitives\firstmark, \botmark and \topmark. We initial-ize the first two to be empty and \kept@topmark tocontain two empty pair of braces. This is necessarysince \kept@topmark is supposed to contain the lastmark from a preceding page and in LATEX any “real”mark must contain two parts representing left andright mark information.719 \def\kept@topmark{{}{}}720 \let\kept@firstmark\@empty721 \let\kept@botmark\@empty

Sometimes we want to return the value of a

“kept” mark into a \mark node on the mainvertical list. This is done by the function\return@nonemptymark. As the name suggests itonly acts if the replacement text of the kept mark isnon-empty. This is done to avoid adding an emptymark when no mark was actually present. If wewould nevertheless add such a mark it would be re-garded as a valid \firstmark later on.722 \def\return@nonemptymark#1#2{%723 \ifx#2\@empty724 \else

For debugging purposes we take a look at the valueof the kept mark that we are about to return. Thiscode will get stripped out for production.725 ⟨*𭗆𭖺𭗋𭗄𭗍𭗋𭖺𭖼𭖾⟩726 \mult@info\tw@727 {Returned #1 mark:\MessageBreak

22

Page 23: LaTeX - MultiCol Package

728 \meaning#2}%729 % \nobreak730 % \fi731 ⟨/𭗆𭖺𭗋𭗄𭗍𭗋𭖺𭖼𭖾⟩Since the contents of the mark may be arbitraryLATEX code we better make sure that it doesn’t getexpanded any further. (Some expansion have beendone already during the execution of \markright or\markboth.) We therefore use the usual mechanismof a toks register to prohibit expansion.16

732 \toks@\expandafter{#2}%733 \mark{\the\toks@}%

We don’t want any breakpoint between such a re-turned mark and the following material (which isusually just the box where the mark came from).734 \nobreak735 \fi}

If we have some material in a box register we maywant to get the first and the last mark out of thisbox. This can be done with \get@keptmarks whichtakes one argument: the box register number or itsnick name defined by \newbox.736 \def\get@keptmarks#1{%

For debugging purposes we take a look at the cur-rent dimensions of the box since in earlier versionsof the code I made some mistakes in this area.737 ⟨*𭖽𭖾𭖻𭗎𭗀⟩738 \typeout{Mark box #1 before:739 ht \the\ht#1, dp \the\dp#1}%740 ⟨/𭖽𭖾𭖻𭗎𭗀⟩Now we open a new group an locally copy the box toitself. As a result any operation, i.e. \vsplit, willonly have a local effect. Without this trick the boxcontent would get lost up to the level where the lastassignment to the box register was done.741 \begingroup742 \vbadness\@M743 \setbox#1\copy#1%

Now we split the box to the maximal possible di-mension. This should split off the full contents ofthe box so that effectively everything is split off. Asa result \splitfirstmark and \splitbotmark willcontain the first and last mark in the box respec-tively.744 \setbox#1\vsplit#1to\maxdimen

Therefore we can now set the kept marks which isa global operation and afterwards close the group.This will restore the original box contents.745 \set@keptmarks746 \endgroup

For debugging we take again a look at the box di-mension which shouldn’t have changed.

747 ⟨*𭖽𭖾𭖻𭗎𭗀⟩748 \typeout{Mark box #1 \space after:749 ht \the\ht#1, dp \the\dp#1}%750 ⟨/𭖽𭖾𭖻𭗎𭗀⟩751 }

The macro \set@keptmarks is responsible for set-ting \kept@firstmark and \kept@botmark, bychecking the current values for \splitfirstmarkand \splitbotmark.752 \def\set@keptmarks{%

If \kept@firstmark is empty we assume that itisn’t set. This is strictly speaking not correct aswe loose the ability to have marks that are explic-itly empty, but for standard LATEX application it issufficient. If it is non-empty we don’t change thevalue—within the output routines it will then be re-stored to \@empty.753 \ifx\kept@firstmark\@empty

We now put the contents of \splitfirstmark into\kept@firstmark. In the case that there wasn’tany mark at all \kept@firstmark will not changeby that operation.754 \expandafter\gdef\expandafter755 \kept@firstmark756 \expandafter{\splitfirstmark}%

When debugging we show the assignment but onlywhen something actually happened.757 ⟨*𭗆𭖺𭗋𭗄𭗍𭗋𭖺𭖼𭖾⟩758 \ifx\kept@firstmark\@empty\else759 \mult@info\tw@760 {Set kept first mark:\MessageBreak761 \meaning\kept@firstmark%762 \@gobbletwo}%763 \fi764 ⟨/𭗆𭖺𭗋𭗄𭗍𭗋𭖺𭖼𭖾⟩765 \fi

We always try to set the bottom mark to the\splitbotmark but of course only when there hasbeen a \splitbotmark at all. Again, we assumethat an empty \splitbotmark means that the splitoff box part didn’t contain any marks at all.766 \expandafter\def\expandafter\@tempa767 \expandafter{\splitbotmark}%768 \ifx\@tempa\@empty\else769 \global\let\kept@botmark\@tempa770 ⟨*𭗆𭖺𭗋𭗄𭗍𭗋𭖺𭖼𭖾⟩771 \mult@info\tw@772 {Set kept bot mark:\MessageBreak773 \meaning\kept@botmark%774 \@gobbletwo}%775 ⟨/𭗆𭖺𭗋𭗄𭗍𭗋𭖺𭖼𭖾⟩776 \fi}%

16Due to the current definition of \markright etc. it wouldn’t help to define the \protect command to prohibit expansionas any \protect has already vanished due to earlier expansions.

23

Page 24: LaTeX - MultiCol Package

The \prep@keptmarks function is used to initializethe kept marks from the contents of \partial@page,i.e. the box that holds everything from the top of thecurrent page prior to starting the multicols environ-ment. However, such a box is only available if weare not producing a boxed multicols.777 \def\prep@keptmarks{%778 \if@boxedmulticols \else779 \get@keptmarks\partial@page780 \fi}

781 \def\remove@discardable@items{%782 ⟨*𭖽𭖾𭖻𭗎𭗀⟩783 \edef\@tempa{s=\the\lastskip,784 p=\the\lastpenalty,785 k=\the\lastkern}%786 \typeout\@tempa787 ⟨/𭖽𭖾𭖻𭗎𭗀⟩788 \unskip\unpenalty\unkern789 ⟨*𭖽𭖾𭖻𭗎𭗀⟩790 \edef\@tempa{s=\the\lastskip,791 p=\the\lastpenalty,792 k=\the\lastkern}%793 \typeout\@tempa794 ⟨/𭖽𭖾𭖻𭗎𭗀⟩795 \unskip\unpenalty\unkern796 ⟨*𭖽𭖾𭖻𭗎𭗀⟩797 \edef\@tempa{s=\the\lastskip,798 p=\the\lastpenalty,799 k=\the\lastkern}%800 \typeout\@tempa801 ⟨/𭖽𭖾𭖻𭗎𭗀⟩802 \unskip\unpenalty\unkern803 ⟨*𭖽𭖾𭖻𭗎𭗀⟩

804 \edef\@tempa{s=\the\lastskip,805 p=\the\lastpenalty,806 k=\the\lastkern}%807 \typeout\@tempa808 ⟨/𭖽𭖾𭖻𭗎𭗀⟩809 \unskip\unpenalty\unkern810 }

811 ⟨*𭖻𭖺𭖽𭗇𭖾𭗌𭗌⟩812 \newif\iftoo@bad

813 \newcount\c@columnbadness814 \c@columnbadness=10000815 \newcount\c@finalcolumnbadness816 \c@finalcolumnbadness=9999817818 \newdimen\last@try819

820 \newdimen\multicolovershoot821 \newdimen\multicolundershoot822 \multicolovershoot=0pt823 \multicolundershoot=2pt824 \newbox\mult@nat@firstbox825 ⟨/𭖻𭖺𭖽𭗇𭖾𭗌𭗌⟩

A helper for producing info messages826 \def\mult@info#1#2{%827 \ifnum\c@tracingmulticols>#1%828 \GenericWarning829 {(multicol)\@spaces\@spaces}%830 {Package multicol: #2}%831 \fi832 }

6 Fixing the \columnwidth

If we store the current column width in\columnwidth we have to redefine the internal\@footnotetext macro to use \textwidth for thewidth of the footnotes rather than using the originaldefinition.

Starting with version v1.5r this is now done in away that the original definition is still used, execptthat locally \columnwidth is set to \textwidth.

This solves two problems: first redefinitions of

\@footnotetext done by a class will correctlysurvive and second if multicols is used insidea minipage environment the special definition of\@footnotetext in that environment will be pickedup and not the one for the main galley (the lat-ter would result in all footnotes getting lost in thatcase).

See the definition of the \multicols commandfurther up for the exact code.

7 Further extensionsThis section does contain code for extensions addedto this package over time. Not all of them may beactive, some might sit dormant and wait for beingactivated in some later release.

7.1 Not balancing the columnsThis is fairly trivial to implement. we just have todisable the balancing output routine and replace itby the one that ships out the other pages.

The code for this environment was suggested byMatthias Clasen.

24

Page 25: LaTeX - MultiCol Package

833 ⟨*𭗇𭗈𭖻𭖺𭗅𭖺𭗇𭖼𭖾⟩834 \@namedef{multicols*}{%

If we are not on the main galley, i.e., inside a boxof some sort, that approach will not work since wedon’t have a vertical size for the box so we betterwarn that we balance anyway.835 \ifinner836 \PackageWarning{multicol}%837 {multicols* inside a box does838 not make sense.\MessageBreak839 Going to balance anyway}%840 \else841 \let\balance@columns@out842 \multi@column@out843 \fi844 \begin{multicols}845 }

When ending the environment we simply end the in-ner multicols environment, except that we betteralso stick in some stretchable vertical glue so thatthe last column still containing text is not verticallystretched out.846 \@namedef{endmulticols*}{\vfill847 \end{multicols}}848 ⟨/𭗇𭗈𭖻𭖺𭗅𭖺𭗇𭖼𭖾⟩

7.2 Manual column breakingThe problem with manual page breaks within multi-cols is the fact that during collection of material forall columns a page-forcing penalty (i.e. -10000 orhigher) would stop the collecting pass which is notquite what is desired. On the other hand, using apenalty like -9999 would mean that there would beoccasions where the \vspliting operations withinmulticols would ignore that penalty and still choosea different break point.

For this reason the current implementation usesa completely different approach. In a nutshell itextends the LATEX output routine handling by in-troducing an additional penalty flag (i.e., a penaltywhich is forcing but higher than -10000 so that theoutput routine can look at this value and thus knowswhy it has been called).

Inside the output routine we test for this valueand if it appears we do two things: save the galleyup to this point in a special box for later use and re-duce the \vsize by the height of the material seen.This way the forcing penalty is now hidden in thatbox and we can restart the collection process forthe remaining columns. (This is done in \speci@lsabove.)

In the output routines that do the \vsplittingeither for balancing or for a full page we simply com-bine box 255 with the saved box thus getting a singlebox for splitting which now contains forcing breaksin the right positions.

\columnbreak is modelled after \pagebreak exceptthat we generate a penalty -10005.849 ⟨*𭖼𭗈𭗅𭖻𭗋𭖾𭖺𭗄⟩850 \mathchardef\@Mv=10005851 \def\columnbreak{%

We have to ensure that it is only used within amulticols environment since if that penalty wouldbe seen by the unmodified LATEX output routinestrange things would happen.852 \ifnum\col@number<\tw@853 \PackageError{multicol}%854 {\noexpand\columnbreak outside multicols}%855 {This command can only be used within856 a multicols or multicols* environment.}%857 \else858 \ifvmode859 \penalty -\@Mv\relax860 \else861 \@bsphack862 \vadjust{\penalty -\@Mv\relax}%863 \@esphack864 \fi865 \fi}

Need a box to collect the galley up to the columnbreak.866 \newbox\colbreak@box867 ⟨/𭖼𭗈𭗅𭖻𭗋𭖾𭖺𭗄⟩868 ⟨/𭗉𭖺𭖼𭗄𭖺𭗀𭖾⟩

7.3 Supporting right-to-left lan-guages

Macros to switch between left-right and right-left typesetting. In RL typesetting the\reverse@column@boxes is executed prior to type-setting the columns. In LR typesetting this resort-ing is omitted as the boxes are already in the rightorder.869 \newcommand\RLmulticolcolumns870 {\let\maybe@reverse@columns871 \reverse@column@boxes}872 \newcommand\LRmulticolcolumns873 {\let\maybe@reverse@columns\relax}

The default is left-to-right:874 \LRmulticolcolumns

We need a counter to resort the column boxes if weare typesetting right-to-left.875 \newcount\multicol@sort@counter

This macro is called to re-sort the assembled columnboxes when we are typesetting right-to-left. Thefirst step is to reverse the columns.876 \def\reverse@column@boxes {%877 \ifnum\c@tracingmulticols>\thr@@878 \typeout{reversing columns ...}879 \fi

25

Page 26: LaTeX - MultiCol Package

The columns are at this point in theboxes with register numbers \mult@gfirstbox,\mult@gfirstbox + 2, … but the last col-umn is in \mult@rightbox which is equal to\mult@gfirstbox − 2.

So to re-sort we use \process@cols with \count@starting at \mult@gfirstbox and incrementing by 2and \multicol@sort@counter starting at the highend of the now unused intermediate boxes and decre-menting by 2.880 \multicol@sort@counter\doublecol@number881 \advance\multicol@sort@counter\m@ne882 \process@cols\mult@gfirstbox{%883 \setbox\multicol@sort@counter884 \box\count@885 \ifnum\c@tracingmulticols>\thr@@886 \typeout{Setting887 \the\multicol@sort@counter\space888 <- \the\count@}%889 \fi890 \advance \multicol@sort@counter -\tw@891 }%

For example with 4 columns we would see somethinglike this: What remains to do is to move the last boxout of the way:892 %893 \ifnum\c@tracingmulticols>\thr@@894 \typeout{Setting last:895 \the\mult@grightbox\space896 <- \the\mult@rightbox}%897 \fi898 \setbox \mult@grightbox \box\mult@rightbox

Now the boxes are more or less resorted butthe register numbers are off by one, so we shiftthe boxes again using \process@cols. Thistime \multicol@sort@counter trails one behind\[email protected] \ifnum\c@tracingmulticols>\thr@@900 \typeout{shifting ...}901 \fi902 \multicol@sort@counter\mult@gfirstbox903 \advance\multicol@sort@counter \m@ne904 \process@cols\mult@gfirstbox{%905 \global\setbox\count@906 \box\multicol@sort@counter907 \ifnum\c@tracingmulticols>\thr@@908 \typeout{Setting \the\count@\space909 <- \the\multicol@sort@counter}%910 \fi911 \advance \multicol@sort@counter \tw@912 }%

With 4 columns this would do the following registermoves:

Setting 31 <- 30Setting 33 <- 32Setting 35 <- 34

Now all columns except the last one are in the rightplace. That one is now in highest register we usedwhich corresponds to \doublecol@number−1 if youlook back to the first loop. And it has to moveto \mult@rightbox which happens in the followingcode.913 \multicol@sort@counter\doublecol@number914 \advance\multicol@sort@counter\m@ne915 \ifnum\c@tracingmulticols>\thr@@916 \typeout{Setting last:917 \the\mult@rightbox\space918 <- \the\multicol@sort@counter}%919 \fi920 \global\setbox \mult@rightbox921 \box\multicol@sort@counter

After that the columns are in the same boxes as be-fore but sorted the other way around and thus can beprocessed without further adjustments by the nor-mal multicol code.922 }

26

Page 27: LaTeX - MultiCol Package

IndexNumbers written in italic refer to the page where the corresponding entry is described; numbers underlinedrefer to the code line of the definition; numbers in roman refer to the code lines where the entry is used.

Symbols\@footnotetext . . . 833

B\balance@columns . 522\balance@columns@out

. . . . . . . . . . 501

C\c@collectmore . . . 271\c@columnbadness . 813\c@finalcolumnbadness

. . . . . . . . . . 813\c@unbalance . . . . 272\col@number . . . . . 271\colbreak@box . . . . 866\columnbreak . . . . 849\columnsep . . . . . . . 2\columnseprule . . . . 2\columnseprulecolor

. . . . . . . . 2, 345

D\doublecol@number 271

E\emergencystretch 703

\endmulticols . . . . 214\endmulticols* . . . 846\enough@room . . . . 120

F\flushcolumns . . . . 496

G\get@keptmarks . . . 736

I\if@boxedmulticols 117\ifshr@nking . . . . 496\init@mult@footins 199

K\kept@botmark . . . . 719\kept@firstmark . . 719\kept@topmark . . . . 719

L\leave@mult@footins

. . . . . . . . . . 447\LRmulticolcolumns 869

M\maybe@reverse@columns

. . . . . . . . . . 869

\mult@@cols . . . . . 84\mult@cols . . . . . . 81\mult@firstbox . . . 689\mult@footnotetext

. . . . . . . 78, 833\mult@gfirstbox . . 689\mult@grightbox . . 689\mult@info . . . . . . 826\mult@rightbox . . . 689\multi@column@out 348\multicol@leftmargin

. . . . . . . . . . 213\multicol@sort@counter

. . . . . . . . . . 875\multicolbaselineskip

. . . . . . . . 2, 271\multicolpretolerance

. . . . . . . . 2, 271\multicols . . . . . . 58\multicols* . . . . . 833\multicolsep . . 2, 271\multicoltolerance

. . . . . . . . 2, 271

P\page@free . . . . . . 271\page@sofar . . . . . 304

\partial@page . . . . 271\postmulticols . 2, 271\premulticols . . 2, 271\prep@keptmarks . . 777\prepare@multicols 137\process@cols . . . . 295\process@deferreds 486

R\raggedcolumns . . . 496\reinsert@footnotes

. . . . . . . . . . 346\remove@discardable@items

. . . . . . . . . . 781\return@nonemptymark

. . . . . . . . . . 722\reverse@column@boxes

. . . . . . . . . . 876\RLmulticolcolumns 869

S\set@floatcmds . . . 708\set@keptmarks . . . 752\set@mult@vsize . . 203\setemergencystretch

. . . . . . . . . . 703\speci@ls . . . . . . . 451

Change History

v1.0c\enough@room: Penalty 0 added to empty the

contribution list. . . . . . . . . . . . . . . . . . . . . 9v1.0d

General: All lines shortened to 72 or less. . . . . . 1v1.0e

General: Redefinition of description env. touse \descriptionmargin=5pt in documenta-tion. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

\prepare@multicols: \textwidth changed to\linewidth. . . . . . . . . . . . . . . . . . . . . . . . 11

Setting of \columnwidth removed. . . . . . . . . 11So this file will work with the ‘twocolumn’command. . . . . . . . . . . . . . . . . . . . . . . . . 11

v1.0fGeneral: Changed \z@ to 0pt in redefinition of

description. . . . . . . . . . . . . . . . . . . . . . . . . 1v1.1a

General: \multicolssep changed to\multicolsep. . . . . . . . . . . . . . . . . . . . . . . 1

\flushcolumns: \flushedcolumns renamed to\flushcolumns. . . . . . . . . . . . . . . . . . . . . 18

v1.2a\balance@columns: Group around main loop re-

moved. . . . . . . . . . . . . . . . . . . . . . . . . . . . 19\prepare@multicols: \pretolerance -1 because

it nearly never succeeds. . . . . . . . . . . . . . . 11\set@floatcmds added. . . . . . . . . . . . . . . . . 11\setemergencystretch added. . . . . . . . . . . 11\vbadness 10001 now. . . . . . . . . . . . . . . . . . 11

\set@floatcmds: Macro added. . . . . . . . . . . . . 22\setemergencystretch: Macro added. . . . . . . 22\speci@ls: Float boxes freed. . . . . . . . . . . . . . 17

v1.3a\balance@columns: Changed \vtop to \vbox. . 21

v1.3b\endmulticols: Do \penalty with \addpenalty 12\enough@room: Do \penalty with \addpenalty . 9\multicols: Minimum of two columns . . . . . . . 7

v1.3c\balance@columns: \global\advance left over

from older code . . . . . . . . . . . . . . . . . . . . 20Limit column height to \@colroom . . . . . . . 21

\endmulticols: Check closing env. . . . . . . . . . 13\multi@column@out: \unboxing avoided. . . . . . 16

27

Page 28: LaTeX - MultiCol Package

Check if footnotes are actually present beforeissuing a warning. . . . . . . . . . . . . . . . . . . 16

Unnecessary code removed . . . . . . . . . . . . . 17\prepare@multicols: \null inserted and re-

moved in output . . . . . . . . . . . . . . . . . . . . 10\reinsert@footnotes: \unboxing avoided. . . . 15

v1.3d\c@unbalance: \col@number set to one . . . . . . 13

v1.4aGeneral: Added support for multicol in inner

mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1\balance@columns: Changed to proper

\endlinechar in\message . . . . . . . . . . . . 20\mult@@cols: Forgotten braces added . . . . . . . . 8\multi@column@out: \botmark set to

\splitbotmark . . . . . . . . . . . . . . . . . . . . . 16\prepare@multicols: Checking for text losses. 10

Conditional code for boxed mode added. . . . 10kept marks initiated . . . . . . . . . . . . . . . . . . 10

v1.4d\balance@columns: New algorithm for start

height . . . . . . . . . . . . . . . . . . . . . . . . . . . 19v1.4e

\endmulticols: But ignore \@nobreak in\addpenalty . . . . . . . . . . . . . . . . . . . . . . 12

\enough@room: But ignore \@nobreak in\addpenalty . . . . . . . . . . . . . . . . . . . . . . . 9

\mult@@cols: Typeset optional arg inside group 8\prepare@multicols: Using . . . . . . . . . . . . . . 11

v1.4f\balance@columns: \on@line added to tracing

info . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19\mult@@cols: \on@line added to tracing info . . 8

\par added to allow for correct inner test . . . 8v1.4g

\mult@@cols: \global was probably wrong butat least unnecessary . . . . . . . . . . . . . . . . . . 9

\multi@column@out: Only change \kept@topmarkif \kept@botmark non-empty . . . . . . . . . . 16

v1.4hGeneral: Added mark tracing with

tracingmulticols≥ 2 . . . . . . . . . . . . . . . . . . 1\kept@topmark: Init to double brace pair . . . . 22

v1.4i\multi@column@out: Set \kept@topmark to

\botmark . . . . . . . . . . . . . . . . . . . . . . . . . 16\prepare@multicols: \kept@topmark initial-

ized. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10v1.4j

\setemergencystretch: Setting of \emergencystretchon top removed. . . . . . . . . . . . . . . . . . . . . 22

v1.4k\multicols: Maximum of 5 columns (temp) . . . 7

v1.4l\mult@@cols: \@totalleftmargin now in

\prepare@multicols . . . . . . . . . . . . . . . . . 9\page@sofar: use \multicol@leftmargin in-

stead of \@totalleftmargin . . . . . . . . . . . 14\prepare@multicols: saved \@totalleftmargin

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

v1.4m\endmulticols: Check \partial@page being

emptied . . . . . . . . . . . . . . . . . . . . . . . . . . 13v1.4n

\return@nonemptymark: Make marks robust . . 23v1.4o

\prepare@multicols: \topskip locally zeroed. 10v1.4p

\multi@column@out: Use different \vsize set-ting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

\prepare@multicols: Code moved to\set@mult@vsize . . . . . . . . . . . . . . . . . . . 10

Use different \vsize setting . . . . . . . . . . . . 10\set@mult@vsize: Macro added. . . . . . . . . . . . 12

v1.5?\balance@columns: Allow columns to come out

a bit long or short . . . . . . . . . . . . . . . . . . 18Do splitting to zero here . . . . . . . . . . . . . . . 19Initialize \last@try . . . . . . . . . . . . . . . . . . 19Show natural size . . . . . . . . . . . . . . . . . . . . 20

\endmulticols: Splitting off zero box moved to\balance@columns . . . . . . . . . . . . . . . . . . 12

\leave@mult@footins: Macro added . . . . . . . . 17\mult@@cols: Penalty moved to later point . . . . 9\multi@column@out: Use \leave@mult@footins 15\prepare@multicols: Use \init@mult@footins 11

v1.5a\balance@columns: New box mechanism . . . . . 19\multi@column@out: New box mechanism . 15, 16\multicols: Allow 10 columns again . . . . . . . . . 7\page@sofar: New box mechanism . . . . . . 14, 15\prepare@multicols: Add offset to

\doublecolnumber . . . . . . . . . . . . . . . . . . 10v1.5b

\balance@columns: New badness mechanism . . 19v1.5c

\balance@columns@out: added penalty at out-put routine exit . . . . . . . . . . . . . . . . . . . . 18

\endmulticols: Again use \penalty . . . . . . . . 12\multi@column@out: Support \clearpage . . . . 15\speci@ls: Support \clearpage . . . . . . . . . . . 17

v1.5d\multi@column@out: reinit \topmark . . . . . . . . 16

v1.5e\enough@room: Assign arg to skip register to be

able to output value . . . . . . . . . . . . . . . . . . 9v1.5g

\set@floatcmds: Updated since floats havechanged . . . . . . . . . . . . . . . . . . . . . . . . . . 22

v1.5h\balance@columns: Get kept marks first . . . . . 18\page@sofar: Check for void boxes . . . . . . . . . 14

v1.5i\page@sofar: But don’t remove original code. . 14

v1.5j\set@floatcmds: Updated since floats have

changed again . . . . . . . . . . . . . . . . . . . . . 22v1.5l

General: Try hard to explain unresolved refer-ence that happens if \OnlyDescription isused . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

28

Page 29: LaTeX - MultiCol Package

\set@floatcmds: Added \@largefloatcheck . . 22v1.5n

General: Applied improvement of documenta-tion, kindly done by Robin Fairbairns. . . . . 1

v1.5o\@footnotetext: Redefinition added pr/2664. . 24\prepare@multicols: Setting of \columnwidth

added again pr/2664. . . . . . . . . . . . . . . . . 11v1.5p

\multicols: Redefinition of \@footnotetextonly within env pr/2689. . . . . . . . . . . . . . . 8

v1.5q\balance@columns: Do not reset \mult@firstbox

(pr2739) . . . . . . . . . . . . . . . . . . . . . . . . . . 20Removed setting \dimen@ (pr2739) . . . . . . . 21

\endmulticols*: Macro added . . . . . . . . . . . . 25\mult@@cols: And removed the group again six

years later . . . . . . . . . . . . . . . . . . . . . . . . . 8\multicols*: Macro added . . . . . . . . . . . . . . . 24

v1.5r\@footnotetext: Use \@footnotetext but with

local change to \columnwidth. . . . . . . . . . 24\mult@footnotetext: Macro removed again. . . 24\multicols: Use \@footnotetext but with local

change to \columnwidth. . . . . . . . . . . . . . . 8v1.5s

\speci@ls: check for \stop penalty pr/2873 . . 17v1.5t

\return@nonemptymark: re-add \mark commandwhich was commented out by mistake atsome point in 1998 (pr/2978) . . . . . . . . . . 23

v1.5u\balance@columns@out: Support \columnbreak 18\colbreak@box: Macro added . . . . . . . . . . . . . 25\columnbreak: Macro added . . . . . . . . . . . . . . 25\multi@column@out: Support \columnbreak . . 15\speci@ls: Support \columnbreak . . . . . . . . . 17

v1.5v\balance@columns: Added tracing statements

for trial unsuccesful . . . . . . . . . . . . . . . . . 20Check last column if it contains forced breakand reject trial if that is the case . . . . . . . 20

\balance@columns@out: Added debug state-ments for column break support . . . . . . . . 18

\multi@column@out: Added debug statementsfor column break support . . . . . . . . . . . . . 15

\speci@ls: Added debug statements for columnbreak support . . . . . . . . . . . . . . . . . . . . . 17

v1.5w\multicols: Make \@footnotetext long to allow

multi-paragraph footnotes. . . . . . . . . . . . . . 8

v1.5x\endmulticols: Detect and fix problem if a mul-

ticols ends at the top of a page . . . . . . . . . 13v1.5y

\balance@columns: Limit column height only inunrestricted mode (pr/3212) . . . . . . . . . . . 21

v1.5z\page@sofar: Ensure that column rule has al-

ways \normalcolor . . . . . . . . . . . . . . . . . 14v1.5z1

\c@finalcolumnbadness: Change wrong defaultfor \multicolovershoot to zero (pr/3465). 24

\mult@@cols: Add a kern to cancel potentialdepth of previous line . . . . . . . . . . . . . . . . . 8

\page@sofar: Suppress interline glue at thispoint . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

v1.6aGeneral: New option grid . . . . . . . . . . . . . . . . . 7\endmulticols: Adjusting \prevdepth . . . . . . 12\mult@@cols: Adjust spacing . . . . . . . . . . . . . . 9\page@sofar: Now adjusting \prevdepth . . . . 15

Preparing for adjusting \prevdepth . . . . 14, 15v1.6b

\page@sofar: Different info display . . . . . . . . . 14v1.6c

\set@mult@vsize: Collect one line per columnmore . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

v1.6d\endmulticols: Catch problem with

\columnbreak in last line . . . . . . . . . . . . . 12v1.6e

\multicols: Avoid self-referencing definition of\@footnotetext (pr/3618) . . . . . . . . . . . . . 8

v1.6f\balance@columns: /colbreak guard in the

wrong position . . . . . . . . . . . . . . . . . . . . . 21need to use \mult@grightbox in the loop . . 20

\columnseprulecolor: Make the color of the rulea hook . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

\page@sofar: Make the color of the rule a hook 14v1.6g

\set@floatcmds: Added \@minipagefalse . . . 22v1.6h

\set@floatcmds: Use \@endfloatbox to bettersupport the modifications done by the floatpackage . . . . . . . . . . . . . . . . . . . . . . . . . . 22

v1.7aGeneral: RL language support added . . . . . . . 25\page@sofar: . . . . . . . . . . . . . . . . . . . . . . . . . 14

29