% \iffalse meta-comment % % This program is free software; you can redistribute it and/or % modify it under the terms of the GNU General Public License % as published by the Free Software Foundation; either version 2 % of the License, or (at your option) any later version. % % This program is distributed in the hope that it will be useful, % but WITHOUT ANY WARRANTY; without even the implied warranty of % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the % GNU General Public License for more details. % % You should have received a copy of the GNU General Public License % along with this program; if not, write to the Free Software % Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. % % \fi % % \DoNotIndex{\#,\$,\%,\&,\@,\\,\{,\},\^,\_,\~,\ } % \DoNotIndex{\def,\long,\edef,\xdef,\gdef,\let,\global} % \DoNotIndex{\if,\ifnum,\ifdim,\ifcat,\ifmmode,\ifvmode,\ifhmode,% % \iftrue,\iffalse,\ifvoid,\ifx,\ifeof,\ifcase,\else,\or,\fi,\loop,\do} % \DoNotIndex{\box,\copy,\setbox,\unvbox,\unhbox,\hbox,% % \vbox,\vtop,\vcenter} % \DoNotIndex{\@empty,\immediate,\write} % \DoNotIndex{\egroup,\bgroup,\expandafter,\begingroup,\endgroup} % \DoNotIndex{\divide,\advance,\multiply,\count,\dimen} % \DoNotIndex{\relax,\space,\string} % \DoNotIndex{\csname,\endcsname,\@spaces,\openin,\openout,% % \closein,\closeout} % \DoNotIndex{\catcode,\endinput} % \DoNotIndex{\jobname,\message,\read,\the,\noexpand} % \DoNotIndex{\hsize,\vsize,\hskip,\vskip,\kern,\hfil,\hfill,\hss} % \DoNotIndex{\m@ne,\z@,\@m,\z@skip,\@ne,\tw@,\p@} % \DoNotIndex{\DeclareRobustCommand,\DeclareOption,\newcommand,\newcommand*} % \DoNotIndex{\newcount,\newif,\newlinechar,\newread,\newtoks,\newwrite} % \DoNotIndex{\dp,\wd,\ht,\vss,\unskip} % % \CheckSum{417} % % \MakeShortVerb\| % % \iffalse % \begin{macrocode} %<*driver> \documentclass{ltxdoc} \RequirePackage{hyperref} \EnableCrossrefs %\DisableCrossrefs % Say \DisableCrossrefs if index is ready \CodelineIndex \RecordChanges \setcounter{IndexColumns}{2} % make a twocolumn index \setlength{\columnseprule}{0pt} % no rules between columns ... \setlength{\columnsep}{2em} % ... but more spacing instead. \setcounter{unbalance}{4} \setlength{\IndexMin}{100pt} \OnlyDescription \setlength\hfuzz{3pt} %\hbadness=7000 \frenchspacing \begin{document} \DocInput{mparhack.dtx} \raggedright \end{document} % % \end{macrocode} % ^^A See CTAN:tools/filehdr/filehdr.dvi for an explanation for the following stuff % % =================================================================== % @LaTeX-package-file{ % version = "1.5", % date = "2021-05-02", % filename = "mparhack.sty", % author-1 = "Tom Sgouros", % email-1 = "tomfool@top.gso.uri.edu", % author-2 = "Stefan Ulrich", % email-2 = "stefanulrich@users.sourceforge.net", % codetable = "ISO/ASCII", % keywords = "marginpar, marginpars, marginal notes, wrong margin" % supported = "yes", % docstring = "User manual and documented source code and for the % LaTeX package mparhack.sty" % } % =================================================================== % \fi % \newcommand*\Com[1]{\texttt{\char`\\#1}} % \newcommand*\File[1]{\texttt{#1}} % \newcommand*\Explanation[1]{\noindent % \rule[.5ex]{.4\linewidth}{.6pt}\kern1em % ^^A$\bullet\bullet\bullet$ % {\itshape\small #1}^^A % }^^A\kern1em\rule[.5ex]{6em}{.6pt}} % \newenvironment{Addition}{\par\noindent\Explanation{begin addition}\par\noindent\ignorespaces}^^A % {\Explanation{end addition}} % \newenvironment{Replacement}{\par\noindent\Explanation{begin replacement:}\par\noindent\ignorespaces}^^A % {\Explanation{end replacement}} % \newcommand*\ReplacedBy{\par\noindent\Explanation{by:}\par\noindent\ignorespaces} % \newcommand*\PackageNameNoExt{mparhack} % \newcommand*\PackageName{\texttt{\PackageNameNoExt.sty}} % \def\AfterElseFi#1\else#2\fi{\else#2\fi#1} % \GetFileInfo{mparhack.sty} % \title{\PackageName} % \author{Tom Sgouros\\ {\small\texttt{tomfool@top.gso.uri.edu}} \and % Stefan Ulrich\\ {\small\href{mailto:stefanulrich@users.sourceforge.net}{\texttt{stefanulrich@users.sourceforge.net}}}} % \date{v1.5 2021-05-02\\[1ex] {\footnotesize CTAN: % \href{https://ctan.org/pkg/mparhack} % {\texttt{https://ctan.org/pkg/mparhack}}} % \\[1ex] % {\footnotesize Github: % \href{https://github.com/u-fischer/mparhack} % {\texttt{https://github.com/u-fischer/mparhack}}} % } % \maketitle % % \begin{abstract} % This package implements a workaround for the \LaTeX\ bug % that marginpars sometimes show up on the wrong margin. % \end{abstract} % % \changes{v1.0}{1999/03/02}{Created} % \changes{v1.1}{1999/09/23}{Rewrite to use only one label per page, and to implement % `twocolumn' document option.} % \changes{v1.2}{2000/02/29}{Small documentation changes} % \changes{v1.2a}{2000/03/14}{Fixed the \Com{NeedsTeXFormat} to use 1997/04/14} % \changes{v1.2c}{2001/02/07}{Small documentation changes} % \changes{v1.3}{2001/02/07}{Use \Com{mph@tempa} instead of \Com{@tempa} to avoid % possible clashes with other classes (e.g. scrpage2)} % \changes{v1.4}{2005/04/17}{Fix a bug with eso-pic.sty (latex/3775)} % % % {\parskip 0pt \tableofcontents } % % ^^A -------------------------------------------------- % \section{Introduction} % ^^A -------------------------------------------------- % % A persistent problem with the |\marginpar| command is that the % marginalia produced often show up on the wrong margin. This has % been noted in the \LaTeX\ bugs database.^^A % \footnote{See \url{https://www.latex-project.org/cgi-bin/ltxbugs2html}: % \href{https://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/2361}{latex/2361}, % \href{https://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/2484}{latex/2484}, % \href{https://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/2617}{latex/2617}.} % % % The problem occurs most likely when a marginpar appears near % the top of a page. The problem is exacerbated when % the page break penalties are adjusted so that the page look is % quite ragged. In cases like this, if there is a deal of white % space on a page, the marginpars on the next page will be on the % wrong side for the same length of the page. % The reason for this is that the \LaTeX\ output routine is not % in complete synchronization with the \TeX\ page breaker, so that % sometimes % material might still move to a later page \emph{after} \LaTeX's % marginpar algorithm has determined a page number for the marginpar. % % The fix suggested in the bugs database is to insert |\pagebreak| % commands at the places where the page breaks naturally fall; % then the marginpars will appear on the correct side. However, this is % awkward and unpleasant work for a document that changes % regularly, and seems to fly against the spirit of \LaTeX. % % A different approach was suggested by D. E. Knuth in his % \emph{Macros for Jill}\footnote{Originally published in TUGboat % \textbf{8}, pp.~309--314, reprinted in his \emph{Digital % Typography} pp.~185--193.}: make two |.dvi| files, one with all % notes in the left margin, the other one with all notes in the % right margin. Then print the odd pages from one file, and the % even pages from the other file; merge them by hand. % % However, Knuth also mentions the possibility to use an auxiliar % file to save the page information for each marginpar and use this % information to position it correctly in a second \TeX\ run; and % this is the strategy adopted by \PackageName. % Each marginpar is assigned a unique number; the output routine % writes the number of the last marginpar of each page\slash column % to the |.aux| file, and this information is used in % |\@addmarginpar| to position the current marginpar on the correct % margin. % % % ^^A -------------------------------------------------- % \section{Usage} % ^^A -------------------------------------------------- % Just insert |\usepackage{mparhack}| into your document preamble. % After the first run, you'll probably get the warning message % `\texttt{Marginpars may have changed. Rerun to get them right}'. % This is similar to \LaTeX's warning `\texttt{Label(s) may have % changed}'; it indicates that the |.aux| file doesn't contain the % information needed to position the marginpars correctly, due to % some changes in the document since the last run. The warning % should go away after running \LaTeX\ again (eventually several % times if there's also a table of contents etc.). % % \DescribeMacro{debug}^^A % If you think something is going wrong, the package also has a % \texttt{debug} option; this will output a lot of tracing % information and will add numbers to the marginpars in the |.dvi| % file for reference. % % % ^^A -------------------------------------------------- % \section{Bugs\slash Restrictions} % ^^A -------------------------------------------------- % \begin{itemize} % \item % The package works with the |twocolumn| document option, but not % with the |multicol| package (you can't use marginpars inside % the |multicols| environment). % \item % The package uses one command sequence per page, and the total number % of command sequences available is limited on most \TeX\ systems. % Note however that most current \TeX\ implementations % can allocate more than several thousand command names, and some can % be configured to allocate more than the default during run-time, % so this shouldn't be a problem for moderately sized documents. % \item % The package has to hook into three commands of the \LaTeX2e\ output % routine (by redefining some command), so it requires at least % \LaTeX\ version 1997/04/14 and might break with future \LaTeX\ % versions that change these commands. % We try to detect this by requiring a version newer than 1997/04/14 % and using some heuristics to check if the redefinitions have worked. % You should watch out for this warning message:\par % {\ttfamily\footnotesize\begin{tabular}{@{}l@{}l@{}} %LaTeX Warning:&\ You have requested release `1997/04/14' of LaTeX,\\ % &\ but only release `...' is available. % \end{tabular}}\par\noindent % It might be that the package also works with older versions of \LaTeX, % but this hasn't been tested. If one of the heuristics detects an incompatible % change, it will raise an error:\par % {\ttfamily\footnotesize\begin{tabular}{@{}l@{}} %Package mparhack Error: Couldn't hook into command `xyz'. % \end{tabular}}\par\noindent % \vskip-\lastskip\noindent % It might also happen that the heuristics don't detect a change % properly. If the package simply seems to fail, this could be a reason. % In both cases, please send a bug report to % \href{mailto:stefanulrich@users.sourceforge.net}{\texttt{stefanulrich@users.sourceforge.net}} % (if neccessary including the % |.log| file of your \LaTeX\ run with the \texttt{debug} % package option enabled). Suggestions/improvements are also welcome, % of course. % \end{itemize} % % ^^A -------------------------------------------------- % \section{Acknowledgements} % ^^A -------------------------------------------------- % Thanks to Donald Arseneau and Robin Fairbairns for providing % detailed hints\footnote{in \texttt{<23AUG199920123097@erich.triumf.ca>} and % \texttt{<7prb8s\$dpr\$1@pegasus.csx.cam.ac.uk>}, respectively.} % on how to implement the page referencing mechanism using only one % label per page (instead of one label each marginpar, as in a % previous version). % % \AlsoImplementation % \StopEventually{\relax} % ^^A -------------------------------------------------- % \section{Implementation} % ^^A -------------------------------------------------- % % ^^A -------------------------------------------------- % \subsection{Overview}\label{implementation} % ^^A -------------------------------------------------- % Here's the algorithm for recording the positioning information for % marginpars in more detail: Every marginpar has a unique number $n$ and % writes to the |.aux| file a string like\par\medskip % ^^A % \begin{tabular}{@{}l} % |\def\mph@nr{|$n$|}|. % \end{tabular}\par\medskip % % The commands shipping out the columns and pages write to the % |.aux| file strings like:\par\medskip % ^^A % \begin{tabular}{@{}l} % |\mph@setcol{|$x{\texttt{:}}$|\thepage}{\mph@nr}|, % \end{tabular}\par\medskip\noindent % ^^A % with $x = \mbox{i}$ for the first column and $x = \mbox{ii}$ % otherwise. Then when reading the |.aux| % file at the begin of the \LaTeX\ run, |\mph@nr| will be substitued % by the number of the last marginpar (the value of the |\mph@nr| command % read before that), % and |\mph@setcol| will assign that number to the command sequence |\csname| % |mph@last@|$x{\texttt{:}}$|\thepage\endcsname|; so this will contain % the number of the last marginpar on column\slash page $x{\texttt{:}}$|\thepage|. % % Later on, in the document itself, |\@addmarginpar| will be able to check the value of % |\csname| |mph@last@|$x{\texttt{:}}$\Com{thepage}\Com{end\-csname}, % using the current values for $x$ and |\thepage|. Then there are two % cases: % % (a) |\csname| |mph@last@|$x{\texttt{:}}$|\thepage\endcsname| is % undefined, which means that there has been no |.aux| file % previously, or that there are more pages\slash marginpars than in % the previous run; in this case, |\@addmarginpar| will fall back to using % the value of |\c@page| to determine the current page number (yielding the % same result as without this package), or % % (b) |\csname| |mph@last@|$x{\texttt{:}}$|\thepage\endcsname| is defined as % an integer $z$, the number of the last marginpar on |\thepage|. % Then $z \leq n$, the number of the current marginpar.^^A % \footnote{$z$ cannot be greater than $n$: this would % mean that \TeX\ had shifted some material (including a marginpar) % from later pages to earlier pages, which AFAIK cannot happen.} % While $z < n$, the page counter will be incremented (inside a group) % until |\csname| |mph@last@|$x{\texttt{:}}$|\thepage\endcsname| for % that new page is $\geq n$, or until % we end up in case (a). The incremented value for the page counter % now represents the actual page number of the current marginpar, % and it will be used instead of the original page counter in the % check for even-\slash oddness. % % ^^A -------------------------------------------------- % \subsection{Code} % ^^A -------------------------------------------------- % % We need at least \LaTeX\ version 1997/04/14 which introduced % |\normalsfcodes| into |\@outputdblcol|. % \begin{macrocode} %<*sty> \NeedsTeXFormat{LaTeX2e}[1997/04/14] \ProvidesPackage{mparhack} [2021-05-02 v1.5 (T. Sgouros and S. Ulrich)] % \end{macrocode} % ^^A -------------------------------------------------- % \subsubsection{Booleans, Options, etc.} % ^^A -------------------------------------------------- % Some boolean switches which we will be using: % |\if@mph@firstcol@| indicates that the current column is the % first column, |\if@mph@warning@| toggles the warning message % about changed marginpars, and |\if@debug@| toggles printing (lots % of) debugging messages. % \begin{macrocode} \newif\if@mph@firstcol@ \newif\if@mph@warning@ \newif\if@debug@ % \end{macrocode} % \begin{macro}{\mph@debug} % This command will print the debugging messages if |@debug@| is |true|: % \begin{macrocode} \newcommand*\mph@debug[2][]{% \if@debug@ \typeout{DBG: #2}% \else \ifx#1\@empty\else \typeout{DBG (#1): #2}% \fi \fi } % \end{macrocode} % \end{macro} % The |debug| package option sets |@debug@| to true and adds % numbers to each marginpar by redefining \Com{@xmpar} and % \Com{@ympar}. The numbers are put into boxes of dimension % zero so that they don't alter the spacing. % \begin{macrocode} \DeclareOption{debug}{% \newcommand\mph@info{% \@tempcnta=\mph@cnt \advance\@tempcnta1 \raisebox{0pt}[0pt][0pt]{\makebox[0pt][r]{\tiny\the\@tempcnta}}% }% \long\def\@xmpar[#1]#2{% \@savemarbox\@marbox{\mph@info#1}% \@savemarbox\@currbox{\mph@info#2}% \@xympar }% \long\def\@ympar#1{% \@savemarbox\@marbox{\mph@info#1}% \global\setbox\@currbox\copy\@marbox \@xympar }% \global\@debug@true }% \ProcessOptions* % \end{macrocode} % ^^A -------------------------------------------------- % \subsubsection{Commands} % ^^A -------------------------------------------------- % \begin{macro}{\mph@nr} % A command sequence containing the current marginpar number (which % will be written to the |.aux| file). % \begin{macrocode} \newcommand*\mph@nr{0} % \end{macrocode} % \end{macro} % \begin{macro}{\mph@pg@new} % A command sequence for saving the newly determined value of |\thepage| for later use. % \begin{macrocode} \newcommand*\mph@pg@new{0} \newcommand*\mph@lastpage{0} % \end{macrocode} % \end{macro} % % \begin{macro}{\mph@cnt} % Emulate a counter with a command name to save one count % register. Oh well~\dots \texttt{;-)} % \begin{macrocode} \newcommand*\mph@cnt{0} % \end{macrocode} % \end{macro} % \begin{macro}{\mph@step@cnt} % Use this instead of |\stepcounter| to increment the `counter' % passed as the argument. % \begin{macrocode} \newcommand*\mph@step@cnt[1]{% \begingroup \@tempcnta#1 \advance\@tempcnta\@ne \protected@xdef#1{\the\@tempcnta}% \endgroup } % \end{macrocode} % \end{macro} % \begin{macro}{\mph@setcol} % The command sequence written to the |.aux| file that will save % the column number\slash page number of the last marginpar on the % column\slash page.^^A The additional |ignore@warn#1| macro is used % ^^A in the |\mph@check| macro. % \begin{macrocode} \newcommand*\mph@setcol[2]{% % \@ifundefined{mph@last@#1}{% % \relax % }{% % \expandafter\xdef\csname ignore@warn#1\endcsname{x}% % }% \expandafter\xdef\csname mph@last@#1\endcsname{#2}% } % \end{macrocode} % \end{macro} % \begin{macro}{\mph@check} % Similar to \LaTeX's |\@testdef| for labels, this will be called % at the end of the \LaTeX\ run to check if the meaning of |#2| is % still equal to |mph@last@#1| or if it has changed since the last % run. % \begin{macrocode} \newcommand*\mph@tempa{} \newcommand*\mph@check[2]{% \protected@edef\mph@tempa{#2}% \expandafter\ifx\csname mph@last@#1\endcsname\mph@tempa \mph@debug{\csname mph@last@#1\endcsname\space == \mph@tempa}% \else \mph@debug{\csname mph@last@#1\endcsname\space != \mph@tempa!}% \global\@mph@warning@true \fi } \newcommand*\mph@do@warn{% \if@mph@warning@ \PackageWarningNoLine{mparhack}{Marginpars may have changed.\MessageBreak Rerun to get them right% }% \fi } % \end{macrocode} % \end{macro} % To avoid warnings about undefined commands when someone stops using % this package, we |\providecommand| the |\mph@setcol| command that % we're going to write to the |.aux| file. % \begin{macrocode} \AtBeginDocument{% \protected@write\@auxout{}{% \string\providecommand\string\mph@setcol[2]{}% }% % \end{macrocode} % Fix for latex/3775\footnote{^^A % \url{https://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/3775}^^A % }: eso-pic uses \Com{@picture} inside the output routine, % which causes problems with our redefinition of \Com{hb@xt@} in \Com{@outputdblcol}. % So, as suggested by M. H\o gholm in his reply to the above bug report, we patch % \Com{@picture} to revert to the original definition of \Com{hb@xt@}. % \begin{macrocode} \@ifpackageloaded{eso-pic}{% \let\mph@orig@picture\@picture \renewcommand\@picture{\let\hb@xt@\mph@orig@hb@xt@\mph@orig@picture}% }{% \relax }% } % \end{macrocode} % Add the needed checks to |\@enddocumenthook|. Again, use % |\csname| ... |\endcsname| to avoid warnings about undefined % commands. % \changes{v1.2}{2000/02/29}{% % Use \Com{csname...} when writing commands to \texttt{.aux} file % }% % \begin{macrocode} \AtEndDocument{% \let\mph@setcol\mph@check \clearpage \immediate\write\@auxout{% \string\gdef\string\mph@lastpage{\the\c@page}^^J% \string\csname\space mph@do@warn\string\endcsname }% } % \end{macrocode} % % \begin{macro}{\mph@ifundef@or@smaller} % A helper macro that checks if the command sequence in |#1| is % undefined or if its value is smaller than |\mph@cnt| (it assumes % that |#1| is never empty). If one of these conditions is true, % the second argument is evaluated, else the third argument is % evaluated (similar to \LaTeX's |\@ifundefined|). This macro % will be used to shorten the body of the next macro definition. % \changes{v1.2}{2000/02/29}{% % Renamed this command, and updated the documentation % }% % \begin{macrocode} \newcommand*\mph@ifundef@or@smaller[1]{% \expandafter\ifx#1\relax \let\mph@tempa\@firstoftwo \else \ifnum#1<\mph@cnt\relax \let\mph@tempa\@firstoftwo \else \let\mph@tempa\@secondoftwo \fi \fi \mph@tempa } % \end{macrocode} % \end{macro} % % \begin{macro}{\mph@pg@orig} % \changes{v1.2}{2000/02/29}{% % Added the \Com{mph@pg@orig} macro % }% % The macro |\mph@pg@orig| is used to % save the original value of |\c@page| which is used in case the |.aux| % file information is not up-to date and we can't determine the % correct value; this should give the same results as if \PackageName\ % hadn't been used. % \begin{macrocode} \newcommand*\mph@pg@orig{} % \end{macrocode} % \end{macro} % % \begin{macro}{\mph@get@margin} % This macro does most of the work described in % section~\ref{implementation}. % \changes{v1.2}{2000/02/29}{% % Use \Com{c@page} instead of \Com{thepage} as value in \Com{mph@pg@new} % }% % \begin{macrocode} \newcommand*\mph@get@margin{% \begingroup \edef\mph@pg@orig{\the\c@page} \loop % \end{macrocode} % This loop will be controlled by |\@tempswa|; all changes to that % and to |\thepage| will be local to the current group. % \begin{macrocode} \@tempswafalse \mph@debug{--- checking marginpar \mph@cnt}% \if@twocolumn % \end{macrocode} % When we are in twocolumn mode, first check if the current % marginpar number is greater than the last marginpar in the first % column. If it isn't, we're in the first column. If it is, do the % check for the last marginpar of the entire page. If this returns % false, we're in the second column. Else, advance the page number % and try again. % \begin{macrocode} \mph@debug{last on page \thepage: \csname mph@last@i:\thepage\endcsname(i) \csname mph@last@ii:\thepage\endcsname(ii), }% \mph@ifundef@or@smaller{% \csname mph@last@i:\thepage\endcsname }{% \mph@ifundef@or@smaller{% \csname mph@last@ii:\thepage\endcsname }{% \global\@mph@firstcol@true \@tempswatrue \advance\c@page by 1 \mph@debug{\mph@cnt\space > \csname mph@last@ii:\thepage\endcsname, incrementing \thepage, set col to i }% }{% \global\@mph@firstcol@false \@tempswafalse \mph@debug{\mph@cnt\space <= \csname mph@last@ii:\thepage\endcsname, exiting loop }% }% }{% \@tempswafalse \global\@mph@firstcol@true \mph@debug{exiting loop}% }% \else % \end{macrocode} % Not in twocolumn mode, we need only check for |mph@last@ii|: % \begin{macrocode} \mph@debug{last on page \thepage\space is \csname mph@last@ii:\thepage\endcsname }% \mph@ifundef@or@smaller{% \csname mph@last@ii:\thepage\endcsname }{% \@tempswatrue \advance\c@page by 1 \mph@debug{\mph@cnt\space > \csname mph@last@ii:\thepage\endcsname, incrementing page number }% }{% \@tempswafalse \mph@debug{\mph@cnt\space <= \csname mph@last@ii:\thepage\endcsname, exiting loop }% }% \fi % \end{macrocode} % Now we have either found the correct page, or reached the end of the document % without finding the appropriate page (e.\,g., if the |.aux| file hasn't existed % before, or if the document has grown a lot since the last run). % In this case we reset |\c@page| and |\if@mph@firstcol@| to their original values % and jump out of the loop. % \changes{v1.2}{2000/02/29}{% % Use original values for page and column number by default% % }% % \begin{macrocode} \ifnum\mph@lastpage>\c@page \else \@tempswafalse \mph@debug{\c@page >= \mph@lastpage!}% \c@page=\mph@pg@orig \if@firstcolumn \global\@mph@firstcol@true \else \global\@mph@firstcol@false \fi \mph@debug{using original value: \c@page for \string\c@page and exiting loop. }% \fi \if@tempswa \mph@debug{iterating ...}% \repeat % \end{macrocode} % After having finished the loop, we save the current (eventually modified) % value of |\c@page| to |\mph@pg@new|: % \begin{macrocode} \mph@debug{=== marginpar \mph@cnt\space is on page \thepage% \if@twocolumn, col \if@mph@firstcol@ 1 \else 2 \fi\fi }% \protected@xdef\mph@pg@new{\the\c@page}% \endgroup } % \end{macrocode} % \end{macro} % % ^^A -------------------------------------------------- % \subsubsection{Patching the output routine} % ^^A -------------------------------------------------- % We have to hook into 3 commands that are part of \LaTeX's output routine: % |\@addmarginpar|, |\@outputdblcol| and |\@outputpage|. For the latter, we can use the default % \LaTeX\ mechanism |\g@addto@macro|. For the others, this is more difficult, % since the changes need to go somewhere `in between'. % % One could use hard redefinitions (plus % \Com{CheckCommand*} to verify that the correct version of % the command was being defined); but this soon gets too bothersome % with new \LaTeX2e\ versions introducing minor changes that don't % affect the stuff which we are concerned, but that nevertheless % would require multiplying the redefinitions for the various versions. % % So instead, we locally redefine some % commands to hook into the existing definitions. As a heuristic of % detecting whether we change the appropriate commands, we check % the values of some special counters \Com{mph@chk@xyz} that get % incremented by some of the `hooks'. % % \changes{v1.3a}{2003/05/22}{% % Use \Com{g@addto@macro} for \Com{@outputpage} to % improve compatibility with e.g. the memoir class % }% % \changes{v1.2}{2000/02/29}{% % Added \Com{CheckCommand*} for \Com{@addmarginpar}, \Com{@outputpage} % and \Com{@outputdblcol} % }% % \changes{v1.2b}{2000/09/01}{% % Replaced \Com{CheckCommand*} and the full redefinitions of % \Com{@addmarginpar}, \Com{@outputpage} and \Com{@outputdblcol} % by hooking into certain commands inside them % }% % % \begin{macro}{\mph@error} % Error message if something suspicious happened with the redefintions: % \begin{macrocode} \newcommand\mph@error[1]{% \PackageError{mparhack}{% Couldn't hook into command `#1' }{% This means that a LaTeX version incompatible with mparhack.sty^^J% has been used. See also the section on `Bugs/Restrictions'^^J% in mparhack.dvi. Please send an email about this bug to^^J% , along with the file `\jobname.log'. }% } % \end{macrocode} % \end{macro} % % \begin{macro}{\@addmarginpar} % This command adds the marginpar box to the current page. % We change the \Com{c@page} counter and the \Com{if@firstcolumn} switch % to the values that have been set correctly by the \Com{mph@get@margin} % command. There's no further error checking done here. % % \begin{macrocode} \newcommand\mph@orig@c@page{} \newcommand\mph@orig@addmarginpar{} \let\mph@orig@addmarginpar\@addmarginpar \renewcommand\@addmarginpar{% \mph@step@cnt\mph@cnt \protected@write\@auxout{}% {\string\def\string\mph@nr{\mph@cnt}}% \mph@get@margin \def\mph@orig@c@page{\c@page} \c@page=\mph@pg@new \if@mph@firstcol@ \@firstcolumntrue \else \@firstcolumnfalse \fi \mph@orig@addmarginpar \c@page=\mph@orig@c@page } % \end{macrocode} % \end{macro} % % \begin{macro}{\@outputpage} % Add the |\mph@outputpage@hook| hook to |\@outputpage|. % We need to decrement |\c@page|, since |\@outputpage| will % have incremented it after dumping the page contents. % The group in |\mph@outputpage@hook| is to keep this change local. % \begin{macrocode} \newcommand*\mph@outputpage@hook{% \bgroup \advance\c@page\m@ne \immediate\write\@auxout{% \string\mph@setcol{ii:\thepage}{\string\mph@nr}% }% \egroup } \g@addto@macro{\@outputpage}{\mph@outputpage@hook} % \end{macrocode} % \end{macro} % % \begin{macro}{\@outputdblcol} % In case an entire twocolumn page is finished, this command calls % \Com{hb@xt@} with the boxes for the two columns inside, and each % one needs to set a marker with the current column number. So % we hook into \Com{hb@xt@} and check if its first argument equals % \Com{columnwidth} (\Com{hb@xt@} is also called for the entire page, % but in this case the first argument is \Com{textwidth}). % % The current column number is represented by \Com{mph@chk@dcl}, and at % the end we check if this number equals 0 (in which case the % page hadn't been fininshed yet, and we didn't need to do anything) % or 2 (the `interesting' case); else we signal an error. % \changes{v1.5}{2021-04-02}{% % Changed definition of \Com{@outputdblcol} to allow % \Com{hb@xt@} to correctly expands in shipout hooks. See % \url{https://tex.stackexchange.com/q/595272/2388} % }% % \begin{macrocode} \newcommand\mph@orig@hb@xt@{} \newcommand\mph@orig@outputdblcol{} \newcommand\mph@chk@dcl{0}% \let\mph@orig@hb@xt@\hb@xt@ \let\mph@orig@outputdblcol\@outputdblcol \renewcommand\@outputdblcol{% \def\mph@chk@dcl{0}% \def\hb@xt@##1##2{% \ifx##1\columnwidth \mph@step@cnt\mph@chk@dcl \protected@edef\mph@tempa{% \noexpand\write\noexpand\@auxout{% \noexpand\string\noexpand\mph@setcol{% \romannumeral\mph@chk@dcl:\noexpand\thepage% }{% \noexpand\string\noexpand\mph@nr% }% }% }% \mph@orig@hb@xt@##1{##2\mph@tempa}% \else \mph@orig@hb@xt@##1{##2}% \fi }% \mph@orig@outputdblcol \def\hb@xt@{\mph@orig@hb@xt@}% \ifnum\mph@chk@dcl=0\relax \else \ifnum\mph@chk@dcl=2\relax \else \mph@error{\string\@outputdblcol}% \fi \fi } % \end{macrocode} % \end{macro} % % \begin{macro}{\mph@orig@picture} % \begin{macrocode} \newcommand\mph@orig@picture{} % \end{macrocode} % \end{macro} % % \begin{macrocode} % % \end{macrocode} % ^^A\typeout{End of package documentation.} % ^^A makeindex -s gind.ist \PackageNameNoExt^^J} % \PrintIndex % \PrintChanges % \Finale