summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/mparhack/mparhack.dtx
blob: 11ea9965b9de5bb9a25171c10f45eb6d9da4c36f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
% \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{418}
%
% \MakeShortVerb\|
%
% \iffalse
%    \begin{macrocode}
%<*driver>
\documentclass{ltxdoc}
\RequirePackage{url}%
\IfFileExists{hyperref.sty}{\RequirePackage{hyperref}}{%
%%% alternative definitions if hyperref is not available
    \newcommand\href[2]{#2}%
    \newcommand\url{\texttt}%
}
\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}
%</driver>
%    \end{macrocode}
% ^^A See CTAN:tools/filehdr/filehdr.dvi for an explanation for the following stuff
%
% ===================================================================
%  @LaTeX-package-file{
%     version         = "1.4",
%     date            = "2005/04/17",
%     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.4 2005/04/17\\[1ex] {\footnotesize CTAN:
% \href{http://www.ucc.ie/cgi-bin/ctan?server=ftp.dante.de%2Ftex-archive&term=mparhack}
%      {\texttt{macros/latex/contrib/supported/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{1.0}{1999/03/02}{Created}
% \changes{1.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{1.2a}{2000/03/14}{Fixed the \Com{NeedsTeXFormat} to use 1997/04/14}
% \changes{1.2c}{2001/02/07}{Small documentation changes}
% \changes{1.3}{2001/02/07}{Use \Com{mph@tempa} instead of \Com{@tempa} to avoid
%               possible clashes with other classes (e.g. scrpage2)}
% \changes{1.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{http://www.latex-project.org/cgi-bin/ltxbugs2html}:
%       \href{http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/2361}{latex/2361},
%       \href{http://www.latex-project.org/cgi-bin/ltxbugs2html?pr=latex/2484}{latex/2484},
%       \href{http://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).
%
% ^^A --------------------------------------------------
% ^^A Place to stop if implementation shouldn't be printed
% ^^A --------------------------------------------------
%
%    \typein[\answer]%
%        {^^JPrint an annotated listing of the macro definitions (y/n)? [n]}
%    \def\next{y}^^A
%    \ifx\answer\next
%    \AfterElseFi\AlsoImplementation
%    \else
%        \typeout{(not printing macro definitions.)}^^A
%        \expandafter\endinput
%    \fi
%    \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}
      [2005/04/17 v1.4  (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{http://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%
        <stefanulrich@users.sourceforge.net>, 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.
%
%    \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%
                    }%
                }%
            }%
        \else
            \def\mph@tempa{}%
        \fi
        \mph@orig@hb@xt@##1{##2\mph@tempa}%
    }%
    \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}
%</sty>
%    \end{macrocode}
% ^^A\typeout{End of package documentation.}
% \typein[\answer]%
%   {^^JPrint an index of command names (y/n)? [n]^^J^^A
%       -- Note: this requires a previous run of:^^J^^A
%       \space\space\space makeindex -s gind.ist \PackageNameNoExt^^J}
%    \def\next{y}^^A
%    \ifx\answer\next
%    \AfterElseFi\PrintIndex
%    \else
%        \typeout{(not printing index.)}^^A
%    \fi
% \typein[\answer]%
%   {^^JPrint a history of changes (y/n)? [n]^^J^^A
%       -- Note: this requires a previous run of:^^J^^A
%       \space\space\space makeindex -s gglo.ist -o \PackageNameNoExt.gls \PackageNameNoExt.glo^^J}
%    \def\next{y}^^A
%    \ifx\answer\next
%    \AfterElseFi\PrintChanges
%    \else
%        \typeout{(not printing history of changes.)}^^A
%    \fi
% \Finale