summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/eplain/base/xeplain.tex
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/eplain/base/xeplain.tex')
-rw-r--r--Master/texmf-dist/source/eplain/base/xeplain.tex4783
1 files changed, 4783 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/eplain/base/xeplain.tex b/Master/texmf-dist/source/eplain/base/xeplain.tex
new file mode 100644
index 00000000000..5464d27a82e
--- /dev/null
+++ b/Master/texmf-dist/source/eplain/base/xeplain.tex
@@ -0,0 +1,4783 @@
+% xeplain.tex: macros for nonformatting. Written 1989--94 by (mostly)
+% Karl Berry. Some additions/changes 1997--98 by Adam Lewenberg.
+% These macros are in the public domain.
+%
+% This is the ``extended plain'' TeX format that's described in
+% `eplain.texinfo', which you should have received with this file. We
+% assume plain has been loaded.
+%
+% N.B.: A version number is defined at the beginning and end of this file;
+% please change those numbers whenever the file is modified!
+% And it's best to rename the file if you're going to distribute a
+% modified version.
+%
+% Some macros were written and/or suggested by Paul Abrahams.
+% Other sources (e.g., The TeXbook) are cited at the appropriate places.
+%
+%% @texfile{
+%% author = "Karl Berry, Steven Smith, Oleg Katsitadze, and others",
+%% version = "REPLACE-WITH-VERSION",
+%% date = "REPLACE-WITH-DATE",
+%% filename = "xeplain.tex",
+%% email = "bug-eplain@tug.org",
+%% checksum = "REPLACE-WITH-CHECKSUM",
+%% codetable = "ASCII",
+%% supported = "yes",
+%% docstring = "This file defines macros that extend and expand on
+%% plain TeX. eplain.tex is xeplain.tex and the other
+%% source files with comments stripped; see the original
+%% files for author credits, etc. And please base diffs
+%% or other contributions on xeplain.tex, not the
+%% stripped-down eplain.tex.",
+%% }
+%
+%
+% Load eplain.tex only once (to avoid using up \new's).
+% \eplain is defined at the end of this file, so we can test \eplain to
+% detect whether eplain.tex has been loaded already or not.
+%
+% We use \expandafter because the merge script strips any lines
+% with an \endinput.
+%
+\ifx\eplain\undefined
+ \let\next\relax
+\else
+ \expandafter\let\expandafter\next\csname endinput\endcsname
+\fi
+\next
+% The ifpdf.sty file included below was written by Heiko Oberdiek.
+% See the complete source file (e.g., in this distribution) for
+% comments.
+%% [[[include ifpdf.sty]]]
+%
+%
+% Category codes, etc.
+%
+\def\makeactive#1{\catcode`#1 = \active \ignorespaces}%
+\chardef\letter = 11
+\chardef\other = 12
+% The following two macros were adopted from miniltx.tex of graphics.
+\def\makeatletter{%
+ \edef\resetatcatcode{\catcode`\noexpand\@\the\catcode`\@\relax}%
+ \catcode`\@11\relax
+}%
+\def\makeatother{%
+ \edef\resetatcatcode{\catcode`\noexpand\@\the\catcode`\@\relax}%
+ \catcode`\@12\relax
+}%
+%
+%
+% So we can have user-inaccessible control sequences.
+%
+\edef\leftdisplays{\the\catcode`@}%
+\catcode`@ = \letter
+\let\@eplainoldatcode = \leftdisplays
+%
+% Save miniscule amounts of memory and time by writing \toks@ii instead
+% of \toks2.
+\toksdef\toks@ii = 2
+%
+%
+% This macro is defined in The TeXbook, but it never made it
+% into plain TeX. \dospecials is defined there, though.
+%
+\def\uncatcodespecials{%
+ \def\do##1{\catcode`##1 = \other}%
+ \dospecials
+}%
+%
+%
+% Here is a way to do \let^^M = \cs, where the \let need not be global.
+{%
+ \makeactive\^^M %
+ \long\gdef\letreturn#1{\let^^M = #1}%
+}%
+%
+%
+% Swallow parameters, etc.
+%
+\let\@eattoken = \relax % Define this, so \eattoken can be used in \edef.
+\def\eattoken{\let\@eattoken = }%
+\def\gobble#1{}%
+\def\gobbletwo#1#2{}%
+\def\gobblethree#1#2#3{}%
+%
+% We can't just use \empty as the identity function, since then outer
+% braces which would supposedly delimit the argument would define a group.
+\def\identity#1{#1}%
+%
+% True if #1 is the empty string, i.e., called like `\ifempty{}'.
+% Use notes:
+% So far, \ifempty works in the following cases:
+% 1. \ifempty{}\message{empty}\else\message{not empty}\fi --> empty
+% 2. \ifempty\undefined\message{empty}\else\message{not empty}\fi --> not empty
+% But does NOT work in the case
+% 3. \def\empty{}
+% \ifempty\empty\message{empty}\else\message{not empty}\fi --> not empty
+% Question: When should \ifempty be true?
+\def\@emptymarkA{\@emptymarkB}
+% The above line suggested by Stanislav Brabec.
+\def\ifempty#1{\@@ifempty #1\@emptymarkA\@emptymarkB}%
+\def\@@ifempty#1#2\@emptymarkB{\ifx #1\@emptymarkA}%
+%
+% Turn a definition into the characters that compose it. See
+% ``Sanitizing control sequences under \write'', by Ron Whitney, TUGboat
+% 11(4), p.620.
+\def\@gobblemeaning#1:->{}%
+\def\sanitize{\expandafter\@gobblemeaning\meaning}%
+%
+%
+% From p.308 of the TeXbook. This cannot be used in places where TeX
+% might be skipping tokens, e.g., in conditionals.
+%
+\def\ifundefined#1{\expandafter\ifx\csname#1\endcsname\relax}%
+%
+%
+% \csname constructions come up an awful lot, so we save typing with the
+% following. (But the extra macro expansion does take time, so we don't
+% use these in frequently-executed code.)
+%
+\def\csn#1{\csname#1\endcsname}%
+\def\ece#1#2{\expandafter#1\csname#2\endcsname}%
+%
+%
+% \expandonce{TOKEN} abbreviates \expandafter\noexpand TOKEN.
+%
+\def\expandonce{\expandafter\noexpand}%
+%
+%
+% Don't show our register allocations in the log.
+%
+\let\@plainwlog = \wlog
+\let\wlog = \gobble
+%
+%
+% Make it convenient to put newlines in error messages.
+%
+\newlinechar = `^^J
+%
+%
+% Sometimes it is convenient to have everything in the transcript file
+% and nothing on the terminal. We don't just call \tracingall here,
+% since that produces some useless output on the terminal.
+%
+\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}%
+\def\loggingall{\tracingcommands\tw@\tracingstats\tw@
+ \tracingpages\@ne\tracingoutput\@ne\tracinglostchars\@ne
+ \tracingmacros\tw@\tracingparagraphs\@ne\tracingrestores\@ne
+ \showboxbreadth\maxdimen\showboxdepth\maxdimen
+}%
+% Show the complete contents of boxes.
+%
+\def\tracingboxes{\showboxbreadth = \maxdimen \showboxdepth = \maxdimen}%
+%
+% Don't trace anything, except restore \showbox... to plain's values.
+%
+\def\gtracingoff{\begingroup \globaldefs = 1 \tracingoff \endgroup}%
+\def\tracingoff{\tracingonline\z@\tracingcommands\z@\tracingstats\z@
+ \tracingpages\z@\tracingoutput\z@\tracinglostchars\z@
+ \tracingmacros\z@\tracingparagraphs\z@\tracingrestores\z@
+ \showboxbreadth5 \showboxdepth3
+}%
+%
+%
+% Definitions to produce actual `{' (et al.) characters in an output
+% file via \write. We omit the line break after the first }, since we
+% have no comment character at that point.
+%
+\begingroup
+ \catcode`\{ = 12 \catcode`\} = 12
+ \catcode`\[ = 1 \catcode`\] = 2
+ \gdef\lbracechar[{]%
+ \gdef\rbracechar[}]%
+ \catcode`\% = \other
+ \gdef\percentchar[%]\endgroup
+%
+%
+% Leave horizontal mode (if we're in it), then insert a penalty.
+% And conversely.
+%
+\def\vpenalty{\ifhmode\par\fi \penalty}%
+\def\hpenalty{\ifvmode\leavevmode\fi \penalty}%
+%
+%
+% Make \else usable in \loop. From Victor Eijkhout's TeX by Topic (page
+% 104). See also Alois Kabelschacht, TUGboat 8(2), page 184.
+%
+\def\iterate{%
+ \let\loop@next\relax
+ \body
+ \let\loop@next\iterate
+ \fi
+ \loop@next
+}%
+%
+%
+% Add #2 (which is expanded in an \edef) to the end of the definition of
+% #1 (which must be a previously-defined control sequence). This is a
+% way to construct simple lists.
+%
+\def\edefappend#1#2{%
+ \toks@ = \expandafter{#1}%
+ \edef#1{\the\toks@ #2}%
+}%
+%
+%
+% \allowhyphens, from TeXbook, p. 395. Allows following & preceding word
+% to be hyphenated.
+%
+\def\allowhyphens{\nobreak\hskip\z@skip}%
+%
+%
+%
+% Hooks.
+%
+% \hookaction{HOOK}{TOKENS} adds TOKENS to the list of actions for
+% HOOK. We avoid defining a \toks register for each hook, although
+% maybe that isn't so important.
+%
+% \hookappend and \hookprepend add TOKENS specificially to the end or
+% the beginning. When the argument is used, \toks@ will be the previous
+% value of the hook, and \toks@ii the new tokens.
+%
+\long\def\hookprepend{\@hookassign{\the\toks@ii \the\toks@}}%
+\long\def\hookappend{\@hookassign{\the\toks@ \the\toks@ii}}%
+\let\hookaction = \hookappend % either one should be ok
+%
+%
+% \@hookassign{LAST-DEF}{HOOK}{TOKENS} makes \toks@ the previous value
+% of HOOK, and \toks@ii TOKENS, and then assigns the new value using
+% LASTDEF. We store the hook in a control sequence \@HOOKhook.
+%
+\long\def\@hookassign#1#2#3{%
+ % Make \toks@ be the expansion (to one level) of \@HOOKhook, or empty.
+ \expandafter\ifx\csname @#2hook\endcsname \relax
+ % If \@HOOKhook was undefined, let it be empty.
+ \toks@ = {}%
+ \else
+ % Otherwise, expand it to one level. We can't just assign from
+ % \expandafter{\csname ...} since then the \toks register would
+ % contain the control sequence, not its definition.
+ \expandafter\let\expandafter\temp \csname @#2hook\endcsname
+ \toks@ = \expandafter{\temp}%
+ \fi
+ \toks2 = {#3}% Don't expand the argument all the way.
+ \ece\edef{@#2hook}{#1}%
+}%
+%
+%
+% \hookactiononce{HOOK}\CS adds `\global\let\CS=\relax' to the
+% definition of \CS, then adds to HOOK. Thus, \CS is expanded the next
+% time HOOK is called, but then it goes away. This only works if \CS is
+% expandable, though.
+%
+\long\def\hookactiononce#1#2{%
+ \edefappend#2{\global\let\noexpand#2\relax}
+ \hookaction{#1}#2%
+}%
+%
+%
+% \hookrun{HOOKNAME} runs whatever actions have been defined for HOOK.
+%
+\def\hookrun#1{%
+ \expandafter\ifx\csname @#1hook\endcsname \relax \else
+ % Isn't this fun? We want to get rid of the \fi before expanding
+ % the actions, so that they can read what's coming up next.
+ \def\temp{\csname @#1hook\endcsname}%
+ \expandafter\temp
+ \fi
+}%
+%
+%
+%
+% Properties a la Lisp.
+%
+% \setproperty{ATOM}{PROPNAME}{VALUE} defines the property PROPNAME on the
+% ``atom'' ATOM to have VALUE.
+%
+\def\setproperty#1#2#3{\ece\edef{#1@p#2}{#3}}%
+\def\setpropertyglobal#1#2#3{\ece\xdef{#1@p#2}{#3}}%
+%
+%
+% \getproperty{ATOM}{PROPNAME} expands to the value of the property
+% PROPNAME on ATOM, or to nothing (i.e., \empty), if the property isn't
+% present.
+%
+\def\getproperty#1#2{%
+ \expandafter\ifx\csname#1@p#2\endcsname\relax
+ % then \empty
+ \else \csname#1@p#2\endcsname
+ \fi
+}%
+%
+%
+%
+% Macros to support BibTeX are in a separate file, btxmac.tex.
+%
+% (They are maintained separately, too, by Oren Patashnik,
+% opbibtex@cs.stanford.edu.) btxmac.tex also defines other macros we
+% want to use and make available.
+%
+% But not all people want to read the BibTeX macros, because of either
+% space or time considerations. Therefore, we look for \nobibtex,
+% which, if defined, causes btxmac.tex not to be read. But we still
+% have to get \tokstostring et al. defined---so eplain.tex contains
+% those definitions, automatically edited in from btxmac.tex. All the
+% documentation has been removed, so you must read btxmac.tex if you
+% want the comments.
+%
+%
+% We want to give a slightly different message than btxmac if no .aux
+% file exists (unless the person using us has already define some
+% message, possibly empty.)
+%
+\ifx\@undefinedmessage\@undefined
+ \def\@undefinedmessage
+ {No .aux file; I won't warn you about undefined labels.}%
+\fi
+%
+%
+% We use a token register to define all the BibTeX definitions, to avoid
+% problems with the \if... constructions when they are conditionally
+% read.
+%
+%% [[[here is the first set of common definitions from btxmac]]]
+\toks0 = {%
+ %% [[[here are the BibTeX-specific definitions from btxmac]]]
+}%
+\ifx\nobibtex\@undefined \the\toks0 \fi
+%% [[[here is the second set of common definitions from btxmac]]]
+%
+% Here are the control sequences that btxmac.tex defines using an @,
+% because btxmac.tex wants to absolutely minimize the chance of
+% conflicts. But these control sequence implement documented features
+% of eplain, so we want to allow people to use them without the @.
+%
+\let\auxfile = \@auxfile
+\let\for = \@for
+\let\futurenonspacelet = \@futurenonspacelet
+\def\iffileexists{\if@fileexists}%
+\let\innerdef = \@innerdef
+\let\innernewcount = \@innernewcount
+\let\innernewdimen = \@innernewdimen
+\let\innernewif = \@innernewif
+\let\innernewwrite = \@innernewwrite
+\let\linenumber = \@linenumber
+\let\readauxfile = \@readauxfile
+\let\spacesub = \@spacesub
+\let\testfileexistence = \@testfileexistence
+\let\writeaux = \@writeaux
+%
+%
+% btxmac.tex defines \innerdef. Let's use it to make an abbreviation
+% for \innerdef\inner<name>{<name>}.
+%
+\def\innerinnerdef#1{\expandafter\innerdef\csname inner#1\endcsname{#1}}%
+%
+% Use that in turn to make non-outer versions of the rest of plain TeX's
+% allocation macros. (btxmac.tex already did a few of them.)
+%
+\innerinnerdef{newbox}%
+\innerinnerdef{newfam}%
+\innerinnerdef{newhelp}%
+\innerinnerdef{newinsert}%
+\innerinnerdef{newlanguage}%
+\innerinnerdef{newmuskip}%
+\innerinnerdef{newread}%
+\innerinnerdef{newskip}%
+\innerinnerdef{newtoks}%
+%
+%
+% Besides doing a \write to the aux file, we also need to do an
+% \immediate\write.
+%
+\def\immediatewriteaux#1{%
+ \ifx\noauxfile\@undefined
+ \immediate\write\@auxfile{#1}%
+ \fi
+}%
+%
+%
+% We want \biblabelprint to define hyperlink destination. For that,
+% we save the label for the current bibliography entry from within
+% \bblitemhook.
+\def\bblitemhook#1{\gdef\@hlbblitemlabel{#1}}%
+%
+\def\biblabelprint#1{%
+ \noindent
+ \hbox to \biblabelwidth{%
+ \hldest@impl{bib}{\@hlbblitemlabel}%
+ \biblabelprecontents
+ \biblabelcontents{#1}%
+ \biblabelpostcontents
+ }%
+ \kern\biblabelextraspace
+}%
+% We want each citation item to be hyperlink to bibliography entry.
+% To avoid unnecessary warnings about undefined destinations (e.g.,
+% from pdfTeX), produce the link only when .bbl file (which does the
+% \hldest's) is present.
+\def\eplainprintcitepreitem#1{\hlstart@impl{cite}{#1}}%
+\def\eplainprintcitepostitem{\hlend@impl{cite}}%
+%
+%
+\def\printcitepreitem#1{%
+ \testfileexistence[\bblfilebasename]{bbl}%
+ \iffileexists
+ \global\let\printcitepreitem\eplainprintcitepreitem
+ \global\let\printcitepostitem\eplainprintcitepostitem
+ \else
+ \global\let\printcitepreitem\gobble
+ \global\let\printcitepostitem\relax
+ \fi
+ \printcitepreitem{#1}%
+}%
+%
+%
+%
+% Macros that produce output.
+%
+% \obeywhitespace makes both end-of-lines and spaces in the input be
+% respected in the output. Even spaces at the beginning of lines turn
+% into blank space the size of the natural space of the current font.
+% The reason why plain TeX's \obeyspaces does not do this last is that
+% it produces actual space characters, i.e., glue, and glue is discarded
+% at a(n output) line break, and so if line breaks in the input are
+% line breaks in the output...
+%
+% Tabs are not affected; they will still produce glue (a single space).
+%
+\begingroup
+ \makeactive\^^M \makeactive\ % No spaces or ^^M's from here on.
+\gdef\obeywhitespace{%
+\makeactive\^^M\def^^M{\par\futurelet\next\@finishobeyedreturn}%
+\makeactive\ \let =\ %
+%
+% The group we use here is the one \obeywhitespace must be enclosed in.
+% If we don't do this, then if the obeyed stuff ends in a newline, the
+% indent produced by the definition of ^^M will make that line indented,
+% even if it isn't the end of the paragraph.
+\aftergroup\@removebox%
+\futurelet\next\@finishobeywhitespace%
+}%
+%
+% \@finishobeywhitespace eats any spaces and/or the end-of-line after
+% the \obeywhitespace command itself. The group here is the one that it
+% itself creates.
+%
+\gdef\@finishobeywhitespace{{%
+\ifx\next %
+\aftergroup\@obeywhitespaceloop%
+\else\ifx\next^^M%
+\aftergroup\gobble%
+\fi\fi}}%
+%
+% \@finishobeyedreturn is invoked at the end of every input line. We
+% check if the next thing is also a return, and, if so, insert extra
+% space. Then we start the next line.
+%
+\gdef\@finishobeyedreturn{%
+\ifx\next^^M\vskip\blanklineskipamount\fi%
+\indent%
+}%
+\endgroup
+%
+% The argument here is the space that we are supposed to eat after the
+% \obeywhitespace command.
+%
+\def\@obeywhitespaceloop#1{\futurelet\next\@finishobeywhitespace}%
+%
+%
+% This removes the last box, if it was a empty box of width \parindent.
+% We might have been called inside a \vbox, so we have to test if we are
+% in horizontal mode before using \lastbox.
+%
+\def\@removebox{%
+ \ifhmode
+ \setbox0 = \lastbox
+ \ifdim\wd0=\parindent
+ \setbox2 = \hbox{\unhbox0}%
+ \ifdim\wd2=0pt
+ % Don't put it back: it was an indentation box.
+ % This \ignorespaces ignores spaces after the group.
+ \ignorespaces
+ \else
+ \box2 % Put it back: it wasn't empty.
+ \fi
+ \else
+ \box0 % Put it back: it wasn't the right width.
+ \fi
+ \fi
+}%
+%
+% We allow for extra (possibly negative) space when we hit blank lines.
+%
+\newskip\blanklineskipamount
+\blanklineskipamount = 0pt
+%
+%
+% A good way to print fractions in text when you don't want
+% to use \over (which should be most of the time), and yet
+% just `1/2' doesn't look right. (From the TeXbook,
+% the answer to exercise 11.6, p.311.)
+%
+\def\frac#1/#2{\leavevmode
+ \kern.1em \raise .5ex \hbox{\the\scriptfont0 #1}%
+ \kern-.1em $/$%
+ \kern-.15em \lower .25ex \hbox{\the\scriptfont0 #2}%
+}%
+%
+%
+% The `e' just means `Eplain', as in `Eplain's hrule'. The advantage
+% to using these is that you can change the default thickness.
+%
+\newdimen\hruledefaultheight \hruledefaultheight = 0.4pt
+\newdimen\hruledefaultdepth \hruledefaultdepth = 0.0pt
+\newdimen\vruledefaultwidth \vruledefaultwidth = 0.4pt
+%
+\def\ehrule{\hrule height\hruledefaultheight depth\hruledefaultdepth}%
+\def\evrule{\vrule width\vruledefaultwidth}%
+%
+%
+% The texnames.sty and path.sty files included below were originally
+% written by Nelson Beebe and Philip Taylor, respectively. See the
+% complete source files (e.g., in this distribution) for comments.
+%% [[[include texnames.sty]]]
+%% [[[include path.sty]]]
+%
+%
+% A square box, suitable for being a marker in lists.
+%
+\def\blackbox{\vrule height .8ex width .6ex depth -.2ex \relax}% square bullet
+%
+%
+% From p.311 of the TeXbook.
+%
+% Make an unfilled rectangle with the dimensions of \box0. #1 is the
+% height of the rules, #2 the depth (i.e., the thicknesses).
+%
+\def\makeblankbox#1#2{%
+ \ifvoid0
+ \errhelp = \@makeblankboxhelp
+ \errmessage{Box 0 is void}%
+ \fi
+ \hbox{\lower\dp0
+ \vbox{\hidehrule{#1}{#2}%
+ \kern -#1% overlap rules
+ \hbox to \wd0{\hidevrule{#1}{#2}%
+ \raise\ht0\vbox to #1{}% vrule height
+ \lower\dp0\vtop to #1{}% vrule depth
+ \hfil\hidevrule{#2}{#1}%
+ }%
+ \kern-#1\hidehrule{#2}{#1}%
+ }%
+ }%
+}%
+%
+\newhelp\@makeblankboxhelp{Assigning to the dimensions of a void^^J%
+ box has no effect. Do `\string\setbox0=\string\null' before you^^J%
+ define its dimensions.}%
+%
+%
+% Produce an hrule with height #1 and depth #2, and insert kerning so it
+% doesn't change the current position.
+%
+\def\hidehrule#1#2{\kern-#1\hrule height#1 depth#2 \kern-#2}%
+%
+% Produce a vrule with width #1+#2, kerning so as not to change the
+% current position.
+%
+\def\hidevrule#1#2{%
+ \kern-#1%
+ \dimen@=#1\advance\dimen@ by #2%
+ \vrule width\dimen@
+ \kern-#2%
+}%
+%
+%
+% The \boxit macro from the TeXbook, trivially generalized to allow
+% something other than 3pt around the TeX box being boxed.
+%
+\newdimen\boxitspace \boxitspace = 3pt
+%
+\long\def\boxit#1{%
+ \vbox{%
+ \ehrule
+ \hbox{%
+ \evrule
+ \kern\boxitspace
+ \vbox{\kern\boxitspace \parindent = 0pt #1\kern\boxitspace}%
+ \kern\boxitspace
+ \evrule
+ }%
+ \ehrule
+ }%
+}%
+%
+%
+% Produce the written-out form of a number.
+%
+\def\numbername#1{\ifcase#1%
+ zero%
+ \or one%
+ \or two%
+ \or three%
+ \or four%
+ \or five%
+ \or six%
+ \or seven%
+ \or eight%
+ \or nine%
+ \or ten%
+ \or #1%
+ \fi
+}%
+%
+% The following arrow macros were written by Steven Smith. See arrow.tex.
+\let\@plainnewif = \newif
+\let\@plainnewdimen = \newdimen
+\let\newif = \innernewif
+\let\newdimen = \innernewdimen
+\edef\@eplainoldandcode{\the\catcode`& }%
+\catcode`& = 11
+\toks0 = {%
+ %% [[[include arrow1]]]
+}%
+\catcode`& = 4
+\toks2 = {%
+ %% [[[include arrow2]]]
+}%
+\let\newif = \@plainnewif
+\let\newdimen = \@plainnewdimen
+\ifx\noarrow\@undefined \the\toks0 \the\toks2 \fi
+\catcode`& = \@eplainoldandcode
+%
+%
+%
+% Environments.
+%
+% Define an ``environment'': arbitrary text, enclosed by \begingroup and
+% \endgroup. But you get to label the group, so that if you forget an
+% \environment or an \endenvironment, you will probably get an error
+% message about it.
+%
+% Since the environment names appear in \errmessage arguments, it's best
+% to keep them to `letter' and `other' characters. I suppose we could
+% call \tokstostring to allow more general labels.
+%
+% These macros improve slightly on the answer to exercise 5.7 in
+% The TeXbook, by making some checks on \begingroup and \endgroup, as
+% well as just making sure \environment and \endenvironment's match.
+%
+%
+\def\environment#1{%
+ \ifx\@groupname\@undefined\else
+ % This gets invoked if we have two \environments (and no matching
+ % \endenvironment to the first) with an \endgroup in between.
+ \errhelp = \@unnamedendgrouphelp
+ \errmessage{`\@groupname' was not closed by \string\endenvironment}%
+ \fi
+ % Use \edef in case we are passed a macro that contains the name,
+ % instead of the name.
+ \edef\@groupname{#1}%
+ \begingroup
+ \let\@groupname = \@undefined
+}%
+%
+\def\endenvironment#1{%
+ \endgroup
+ \edef\@thearg{#1}%
+ \ifx\@groupname\@thearg
+ \else
+ \ifx\@groupname\@undefined
+ % Unfortunately, one gets an `extra \endgroup' message before
+ % seeing this. But we have to restore \@groupname, so I see no
+ % alternative.
+ \errhelp = \@isolatedendenvironmenthelp
+ \errmessage{Isolated \string\endenvironment\space for `#1'}%
+ \else
+ \errhelp = \@mismatchedenvironmenthelp
+ \errmessage{Environment `#1' ended, but `\@groupname' started}%
+ \endgroup % Probably a typo in the names.
+ \fi
+ \fi
+ \let\@groupname = \@undefined
+}%
+%
+\newhelp\@unnamedendgrouphelp{Most likely, you just forgot an^^J%
+ \string\endenvironment. Maybe you should try inserting another^^J%
+ \string\endgroup to recover.}%
+%
+\newhelp\@isolatedendenvironmenthelp{You ended an environment X, but^^J%
+ no \string\environment{X} to start it is anywhere in sight.^^J%
+ You might also be at an \string\endenvironment\space that would match^^J%
+ a \string\begingroup, i.e., you forgot an \string\endgroup.}%
+%
+\newhelp\@mismatchedenvironmenthelp{You started an environment named X, but^^J%
+ you ended one named Y. Maybe you made a typo in one^^J%
+ or the other of the names?}%
+%
+%
+% The above sort of environment allows nesting. But environments
+% shouldn't always be allowed to nest (like the \flushright,
+% \flushleft, and \center ones defined below). Here are some macros to
+% help deal with that.
+%
+% \checkenv goes at the beginning of a macro that is
+% going to define the environment.
+%
+\newif\ifenvironment
+\def\checkenv{\ifenvironment \errhelp = \@interwovenenvhelp
+ \errmessage{Interwoven environments}%
+ \egroup \fi
+}%
+%
+\newhelp\@interwovenenvhelp{Perhaps you forgot to end the previous^^J%
+ environment? I'm finishing off the current group,^^J%
+ hoping that will fix it.}%
+%
+%
+%
+% Mathematics displays.
+%
+% By default, TeX centers displayed material. To get left-justified
+% displays, say \leftdisplays. To go back to centered displays, say
+% \centereddisplays.
+%
+% This is based on an approach developed by Donald Arseneau,
+% asnd@triumfrg.bitnet.
+%
+\newtoks\previouseverydisplay
+% Here we want to make ordinary math displays flush left,
+% indented by the dimen \leftdisplayindent, which defaults
+% to \parindent.
+%
+% How do you want the first column aligned?
+\let\@leftleftfill\relax % as it was
+%\let\@leftleftfill\hfill % makes more sense, but could be too ugly
+%
+% Surely it makes more sense to not sum \leftdisplayindent+\parindent
+\newdimen\leftdisplayindent \leftdisplayindent=\parindent
+\newif\if@leftdisplays
+%
+\def\leftdisplays{%
+ \if@leftdisplays\else
+ \previouseverydisplay = \everydisplay
+ \everydisplay = {\the\previouseverydisplay \leftdisplaysetup}%
+ \let\@save@maybedisableeqno = \@maybedisableeqno
+ \let\@saveeqno = \eqno
+ \let\@saveleqno = \leqno
+ \let\@saveeqalignno = \eqalignno
+ \let\@saveleqalignno = \leqalignno
+ \let\@maybedisableeqno = \relax
+ \def\eqno{\hfill\textstyle\enspace}%
+ \def\leqno{%
+ \hfill
+ \hbox to0pt\bgroup
+ \kern-\displaywidth
+ % was: \kern-\displayindent % really \displayindent?
+ \kern-\leftdisplayindent % I'll use just \leftdisplayindent
+ $\aftergroup\@leftleqnoend % inserted after ending $
+ }%
+ \@redefinealignmentdisplays
+ \@leftdisplaystrue
+ \fi
+}%
+\newbox\@lignbox
+\newdimen\disprevdepth
+
+% In order to use $$ for left-aligned equation we have to
+% put something like \leftline{$\displaystyle ...$} in the
+% display. Then \eqno works basically like \hfill.
+% In order to make $$<assignments>\eqalignno{...}$$ work as
+% expected, including page breaks, we have to get rid of the
+% horizontal box, and un-vbox the alignment. Sadly, \unvbox
+% does not perform baselineskip handing, so we need to get
+% the \prevdepth ourselves...in order to get the prevdepth,
+% the outermost display must be an alignment display.
+% Therefore, an ordinary $$ a=b $$ becomes:
+% $$\halign{#\cr\noalign{\disprevdepth = \prevdepth
+% \leftline{$\displaystyle a=b$}
+% }}$$
+%
+\def\centereddisplays{%
+ % If \leftdisplays hasn't been called, don't try to restore all the
+ % stuff it changes.
+ %
+ \if@leftdisplays
+ \everydisplay = \previouseverydisplay
+ \let\@maybedisableeqno = \@save@maybedisableeqno
+ \let\eqno = \@saveeqno
+ \let\leqno = \@saveleqno
+ \let\eqalignno = \@saveeqalignno
+ \let\leqalignno = \@saveleqalignno
+ \@leftdisplaysfalse
+ \fi
+}%
+%
+\def\leftdisplaysetup{%
+% surely not this *and* \leftdisplayindent? : \dimen@ = \parindent
+ \dimen@ = \leftdisplayindent
+ \advance\dimen@ by \leftskip
+ \advance\displayindent by \dimen@
+ \advance\displaywidth by -\dimen@
+% this outermost alignment doesn't align anything.
+ \halign\bgroup##\cr \noalign\bgroup
+ \disprevdepth = \prevdepth
+ \setbox\z@ = \hbox to\displaywidth\bgroup
+ % Why strut?? \strut
+ % Why this?? \advance\hsize by -\displayindent
+ $\displaystyle
+ \aftergroup\@lefteqend % inserted after ending $
+}
+%
+\def\@lefteqend{% gets inserted between the ending $$
+ \hfil\egroup% end box 0
+ \@putdisplay}
+% gets inserted between trailing $$.
+\def\@leftleqnoend{\hss \egroup $}% end the \hbox to 0pt for \leqno, restore $
+%
+\def\@putdisplay{%
+ \ifvoid\@lignbox % Ordinary display; use it.
+ \moveright\displayindent\box\z@
+ \else % alignment display; unwrap alignment
+ \prevdepth = \dp\@lignbox % affects the skip *below*
+ \unvbox\@lignbox
+ \fi
+ \egroup\egroup % end \noalign, end outer \halign
+ $% restore first $ of trailing $$
+}
+%
+\def\@redefinealignmentdisplays{%
+ \def\displaylines##1{
+ \global\setbox\@lignbox\vbox{%
+ \prevdepth = \disprevdepth
+ \displ@y
+ \tabskip\displayindent
+ \halign{\hbox to\displaywidth
+ {$\@lign\displaystyle####\hfil$\hfil}\crcr
+ ##1\crcr}}}%
+ \def\eqalignno##1{%
+ \def\eqno{&}%
+ \global\setbox\@lignbox\vbox{%
+ \prevdepth = \disprevdepth
+ \displ@y
+ \advance\displaywidth by \displayindent
+ \tabskip\displayindent
+ \halign to\displaywidth{%
+ \hfil $\@lign\displaystyle{####}$\@leftleftfill\tabskip\z@skip
+ &$\@lign\displaystyle{{}####}$\hfil\tabskip\centering
+ &\llap{$\@lign####$}\tabskip\z@skip\crcr
+ ##1\crcr}}}%
+ \def\leqalignno##1{%
+ \def\eqno{&}%
+ \global\setbox\@lignbox\vbox{%
+ \prevdepth = \disprevdepth
+ \displ@y
+ \advance\displaywidth by \displayindent
+ \tabskip\displayindent
+ \halign to\displaywidth{%
+ \hfil $\@lign\displaystyle{####}$\@leftleftfill\tabskip\z@skip
+ &$\@lign\displaystyle{{}####}$\hfil\tabskip\centering
+ &\kern-\displaywidth
+% \showthe\displayindent \showthe\leftdisplayindent
+ \rlap{\kern\displayindent \kern-\leftdisplayindent$\@lign####$}%
+ \tabskip\displaywidth\crcr
+ ##1\crcr}}}%
+}%
+%
+% \noalign is typically used to insert a few words (`and', for example)
+% between two aligned equations. So I don't think the \noaligned
+% material should be indented. Since \noalign takes <vertical mode
+% material>, we would end up with double indentation, anyway: one
+% because we're indenting the whole display, and one at the start of the
+% <v.m.m.>. (If you want to change any of this, you can put something in
+% \@everynoalign.) So, we use this definition for \noalign in a
+% left-justified \eqalignno:
+%
+\let\@primitivenoalign = \noalign
+\newtoks\@everynoalign
+\def\@lefteqalignonoalign#1{%
+ \@primitivenoalign{%
+ % Is it right to set \leftskip=0pt first, thus perhaps making this
+ % work in lists and so forth? We just compensate for the other ways
+ % the display is indented here.
+ \advance\leftskip by -\parindent
+ \advance\leftskip by -\leftdisplayindent
+ \parskip = 0pt
+ %
+ % We use \parindent=0pt instead of \noindent because the latter
+ % starts unrestricted horizontal mode, which means the alignment
+ % we're inside will wind up being as wide as the page. When the arg
+ % is just vertical material, this is wrong. For example, using
+ % \matrix inside \eqalignno fails if \noindent is used.
+ \parindent = 0pt
+ \the\@everynoalign
+ #1%
+ }%
+}%
+%
+%
+%
+% Time macros.
+%
+% TeX sets \time, \day, \month, and \year when it begins. (And does not
+% update them as it runs!)
+%
+%
+% \monthname produces the name of the month, abbreviated to three
+% letters. The primitive \month should never be zero.
+%
+\def\monthname{%
+ \ifcase\month
+ \or Jan\or Feb\or Mar\or Apr\or May\or Jun%
+ \or Jul\or Aug\or Sep\or Oct\or Nov\or Dec%
+ \fi
+}%
+%
+% \fullmonthname is like \monthname, except it doesn't abbreviate.
+%
+\def\fullmonthname{%
+ \ifcase\month
+ \or January\or February\or March\or April\or May\or June%
+ \or July\or August\or September\or October\or November\or December%
+ \fi
+}%
+%
+% \timestring produces the current time, in a format like `1:14 p.m.'.
+%
+\def\timestring{\begingroup
+ \count0 = \time
+ \divide\count0 by 60
+ \count2 = \count0 % The hour, from zero to 23.
+ %
+ \count4 = \time
+ \multiply\count0 by 60
+ \advance\count4 by -\count0 % The minute, from zero to 59.
+ % But we need the minutes with a leading zero, if necessary.
+ \ifnum\count4<10
+ \toks1 = {0}%
+ \else
+ \toks1 = {}%
+ \fi
+ %
+ % Convert the hour into `a.m.' or `p.m.', and make it mod 12.
+ \ifnum\count2<12
+ \toks0 = {a.m.}%
+ \else
+ \toks0 = {p.m.}%
+ \advance\count2 by -12
+ \fi
+ %
+ % If it's midnight, call it `12', not `0'.
+ \ifnum\count2=0
+ \count2 = 12
+ \fi
+ %
+ % Produce the output.
+ \number\count2:\the\toks1 \number\count4 \thinspace \the\toks0
+\endgroup}%
+%
+%
+% \timestamp produces a text string for the whole thing like
+% `23 Apr 1964 1:14 p.m.'.
+%
+\def\timestamp{\number\day\space\monthname\space\number\year\quad\timestring}%
+%
+%
+% \today produces the current date, as in `23 April 1964'.
+%
+\def\today{\the\day\ \fullmonthname\ \the\year}%
+%
+%
+%
+% (Typographical) lists.
+%
+% These macros can produce numbered or unnumbered lists.
+%
+% You can change the spacing by assigning new values to these registers.
+% They are used by both kinds of lists. \listleftindent is relative to
+% the current paragraph indentation, while \listrightindent is an
+% absolute value. I do this for two reasons: (1) it is more useful, if not
+% more ``logical'', to make list indentation depend on the paragraph
+% indentation; (2) footnotes do not work if \parindent is zero, and
+% having a footnote in a list item is perfectly reasonable.
+%
+% If you change \baselineskip and want \abovelistskip and \belowlistskip
+% to retain their meanings here, you will have to reassign to them. The
+% \baselineskip here is the value at the time eplain.tex is read, i.e.,
+% 12pt (most likely).
+%
+% If the items in your lists are very long, you might want to
+% make \interitemskipamount nonzero.
+%
+\newskip\abovelistskipamount \abovelistskipamount = .5\baselineskip
+ \newcount\abovelistpenalty \abovelistpenalty = 10000
+ \def\abovelistskip{\vpenalty\abovelistpenalty \vskip\abovelistskipamount}%
+\newskip\interitemskipamount \interitemskipamount = 0pt
+ \newcount\belowlistpenalty \belowlistpenalty = -50
+ \def\belowlistskip{\vpenalty\belowlistpenalty \vskip\belowlistskipamount}%
+\newskip\belowlistskipamount \belowlistskipamount = .5\baselineskip
+ \newcount\interitempenalty \interitempenalty = 0
+ \def\interitemskip{\vpenalty\interitempenalty \vskip\interitemskipamount}%
+\newdimen\listleftindent \listleftindent = 0pt
+\newdimen\listrightindent \listrightindent = 0pt
+\let\listmarkerspace = \enspace
+%
+% To do arbitrary things at the start of each list:
+\newtoks\everylist
+%
+% If you want no space between items for a particular list
+% (perhaps because the items in it are short), you can say,
+% e.g., \numberedlist\listcompact.
+%
+\def\listcompact{\interitemskipamount = 0pt \relax}%
+%
+% This is called to set up the parameters by both sorts of lists.
+% Because we set \rightskip, we finish off the current paragraph.
+%
+\newdimen\@listindent
+%
+\def\beginlist{%
+ % Insert the space above this list, before we change \leftskip
+ % (because the \vskip in here might be what ends the paragraph).
+ \abovelistskip
+ %
+ \@listindent = \parindent
+ \advance\@listindent by \listleftindent
+ %
+ % \leftskip shifts nested lists to the right on the page.
+ \advance\leftskip by \@listindent
+ \advance\rightskip by \listrightindent
+ %
+ % We always need \itemnumber, so we can know whether an item is the
+ % first one or not.
+ \itemnumber = 1
+ %
+ \the\everylist
+}%
+%
+% A list item, for both kinds of lists.
+%
+\def\li{\@getoptionalarg\@finli}%
+\def\@finli{%
+ % Save \@optionalarg in case \interitemskip garble it.
+ \let\@lioptarg\@optionalarg
+ % Write xref definition but do not define hyperlink destination
+ % (\printitem will do it).
+ \ifx\@lioptarg\empty \else
+ \begingroup
+ \@@hldestoff
+ \expandafter\writeitemxref\expandafter{\@lioptarg}%
+ \endgroup
+ \fi
+ \ifnum\itemnumber=1 \else \interitemskip \fi
+ % Add hyperlink destination in front of \marker before doing \printitem.
+ \begingroup
+ \ifx\@lioptarg\empty \else
+ \toks@ = \expandafter{\@lioptarg}%
+ \let\li@nohldest@marker\marker
+ \edef\marker{\noexpand\hldest@impl{li}{\the\toks@}\noexpand\li@nohldest@marker}%
+ \fi
+ \printitem
+ \endgroup
+ \advance\itemnumber by 1
+ \advance\itemletter by 1
+ \advance\itemromannumeral by 1
+ %
+ % Just in case somebody creeps in with an argument or something.
+ \ignorespaces
+}%
+%
+% \writeitemxref{LABEL} writes out a definition for LABEL to be \marker
+% for the aux file.
+%
+\def\writeitemxref#1{\definexref{#1}\marker{item}}%
+%
+% \printitem is used to print items by both sorts of lists. A \par gets
+% produced before every item -- even the first one. We also want to
+% make paragraphs after the first appear to be indented -- i.e., they
+% will have double indentation. It is usually bad exposition to have
+% lists with multiparagraph items, but sometimes it is unavoidable.
+%
+\def\printitem{%
+ \par
+ \nobreak
+ \vskip-\parskip
+ \noindent
+ \printmarker\marker
+}%
+%
+% Output the list marker.
+%
+\def\printmarker#1{\llap{\marker \enspace}}%
+%
+% Common ending.
+%
+\def\endlist{\belowlistskip}%
+%
+%
+% \numberedlist produces items which are numbered sequentially, starting
+% from one. You start items with \li (`list item'). End the list with
+% \endnumberedlist.
+%
+% A nested \numberedlist produces items labelled `(a)', `(b)', etc. A
+% doubly (and deeper) nested \numberedlist labels items with `*'.
+%
+% These registers keep track of where we are.
+%
+\newcount\numberedlistdepth
+\newcount\itemnumber
+\newcount\itemletter
+\newcount\itemromannumeral
+%
+\def\numberedmarker{%
+ \ifcase\numberedlistdepth
+ (impossible)%
+ \or \printitemnumber
+ \or \printitemletter
+ \or \printitemromannumeral
+ \else *%
+ \fi
+}%
+%
+% These produce the text of the labels. We use \the\itemletter so that
+% the value will expand.
+%
+\def\printitemnumber{\number\itemnumber}%
+\def\printitemletter{\char\the\itemletter}%
+\def\printitemromannumeral{\romannumeral\itemromannumeral}%
+\def\numberedprintmarker#1{\llap{#1) \listmarkerspace}}%
+%
+\def\numberedlist{\environment{@numbered-list}%
+ % This is set back to zero by getting to the end of the group.
+ \advance\numberedlistdepth by 1
+ \itemletter = `a
+ \itemromannumeral = 1
+ \beginlist
+ \let\marker = \numberedmarker
+ \let\printmarker = \numberedprintmarker
+}%
+%
+\def\endnumberedlist{%
+ \par
+ \endenvironment{@numbered-list}%
+ \endlist
+}%
+%
+% Allow synonyms for \numberedlist.
+\let\orderedlist = \numberedlist
+\let\endorderedlist = \endnumberedlist
+%
+%
+%
+% \unorderedlist produces items which are labelled with bullets. You
+% start an item with \li, just as with numbered lists. You end the list
+% with \endunorderedlist.
+%
+% A nested \unorderedlist produces items labelled with em-dashes. A
+% doubly (and deeper) nested \unorderedlist uses `*'.
+%
+\newcount\unorderedlistdepth
+%
+\def\unorderedmarker{%
+ \ifcase\unorderedlistdepth
+ (impossible)%
+ \or \blackbox
+ \or ---%
+ \else *%
+ \fi
+}%
+\def\unorderedprintmarker#1{\llap{#1\listmarkerspace}}%
+%
+\def\unorderedlist{\environment{@unordered-list}%
+ \advance\unorderedlistdepth by 1
+ \beginlist
+ \let\marker = \unorderedmarker
+ \let\printmarker = \unorderedprintmarker
+}%
+%
+\def\endunorderedlist{%
+ \par
+ \endenvironment{@unordered-list}%
+ \endlist
+}%
+%
+%
+%
+% Verbatim listing.
+%
+% ... well, almost verbatim. We assume the font \tt has all the
+% characters that will appear. Control characters, except for tabs and
+% form feeds (and returns) won't produce anything useful. Tabs produce
+% a fixed amount of space, and form feeds produce a page break.
+%
+% This is based on Knuth's ideas in Appendix D of the TeXbook, p. 380.
+% The argument should be a filename.
+%
+% if you need to do something more for your particular fonts and/or
+% environment before the file is input, give a definition to
+% \setuplistinghook. If you want line numbers on the output, you can
+% say \let\setuplistinghook = \linenumberedlisting.
+%
+\def\listing#1{%
+ \par \begingroup
+ \@setuplisting
+ \setuplistinghook
+ \input #1
+ \endgroup
+}%
+%
+\let\setuplistinghook = \relax
+%
+\def\linenumberedlisting{%
+ \ifx\lineno\undefined \innernewcount\lineno \fi
+ \lineno = 0
+ \everypar = {\advance\lineno by 1 \printlistinglineno}%
+}%
+\def\printlistinglineno{\llap{[\the\lineno]\quad}}%
+%
+%
+% \uncatcodespecials must come before \obeywhitespace, lest a space
+% character in the input produce character 32 from the \tt font.
+% Ensure ^^L is active and non-outer.
+%
+{%
+ \makeactive\^^L
+ \let^^L = \relax
+ \gdef\@setuplisting{%
+ \uncatcodespecials
+ \obeywhitespace
+ \makeactive\`
+ \makeactive\^^I
+ \makeactive\^^L
+ \def^^L{\vfill\break}%
+ \parskip = 0pt
+ \listingfont
+ }%
+}%
+\def\listingfont{\tt}%
+%
+% Give definitions to the characters we want to be special.
+%
+% Do ` separately, so can use ` in the \catcode commands elsewhere.
+%
+{%
+ \makeactive\`
+ \gdef`{\relax\lq}% Defeat ligatures.
+}%
+{%
+ \makeactive\^^I
+ \gdef^^I{\hskip8\fontdimen2\font \relax}%
+}%
+%
+%
+% \verbatim ... |endverbatim typesets the ... in typewriter. To produce a |
+% in the ..., use ||. This macro was contributed by beebe@math.utah.edu.
+% Generalized to characters other than | by dorai@cs.rice.edu.
+%
+\def\verbatimescapechar#1{%
+ \gdef\@makeverbatimescapechar{%
+ \@makeverbatimdoubleescape #1%
+ \catcode`#1 = 0
+ }%
+}%
+\def\@makeverbatimdoubleescape#1{%
+ \catcode`#1 = \other
+ \begingroup
+ \lccode`\* = `#1%
+ \lowercase{\endgroup \ece\def*{*}}%
+}%
+\verbatimescapechar\| % initially escapechar is |
+%
+\def\verbatim{\begingroup
+ \uncatcodespecials
+ \makeactive\` % make space character a single space, not stretchable
+ \@makeverbatimescapechar
+ \tt\obeywhitespace}
+\let\endverbatim = \endgroup
+%
+%
+%
+% Table of contents, list of figures, etc.
+%
+% Entries for the table of contents are recorded in \jobname.toc, which
+% we open for writing at the first \writetocentry. Actually, we use
+% \tocfilebasename for the root of the filename to read; \jobname is
+% the default.
+%
+\def\definecontentsfile#1{%
+ \ece\innernewwrite{#1file}%
+ \ece\innernewif{if@#1fileopened}%
+ \ece\let{#1filebasename} = \jobname
+ \ece\def{open#1file}{\opencontentsfile{#1}}%
+ \ece\def{write#1entry}{\writecontentsentry{#1}}%
+ \ece\def{writenumbered#1entry}{\writenumberedcontentsentry{#1}}%
+ \ece\innernewif{ifrewrite#1file} \csname rewrite#1filetrue\endcsname
+ \ece\def{read#1file}{\readcontentsfile{#1}}%
+}%
+%
+% We provide \opentocfile, \readtocfile, etc., by default.
+\definecontentsfile{toc}%
+%
+% And `toc' is just the argument to this macro.
+\def\opencontentsfile#1{%
+ \csname if@#1fileopened\endcsname \else
+ \ece{\immediate\openout}{#1file} = \csname #1filebasename\endcsname.#1
+ \ece\global{@#1fileopenedtrue}%
+ \fi
+}%
+%
+% \writetocentry#1#2 produces a line in the .toc file that
+% looks like:
+% \toc#1entry{#2}{page number}
+% e.g.,
+% \tocchapterentry{Introduction}{2}
+% would be written by
+% \writetocentry{chapter}{Introduction}
+% if the chapter started on page two.
+%
+% Thus, #1 is intended to be something like `chapter' or `section', #2
+% to be the text of the title.
+%
+% Of course, if you want, you can \write\tocfile yourself with whatever
+% you like. In that case, you must also call \opentocfile.
+%
+% By the way, it would be wrong to put a \percentchar at the end of the
+% output line. Then, when the .toc file is read, if each line is turned
+% into a \leftline, say, there would be no legal breakpoint between the
+% boxes, and one extremely long line would result.
+%
+% `toc' is the first argument to this; \writetocentry is defined by
+% \definecontentsfile.
+\def\writecontentsentry#1#2#3{\writenumberedcontentsentry{#1}{#2}{#3}{}}%
+%
+% Sometimes you want the control sequence to take another number (e.g.,
+% a chapter number) as a parameter. (Although you can pass anything you
+% want as the third parameter, naturally.) The third parameter is
+% expanded at the point of the \writenumberedtocentry, not when the
+% \write actually happens. This makes the usual case---the third
+% parameter being \the\someregister---work.
+%
+% For example:
+% \writenumberedtocentry{chapter}{The second chapter}{2}
+% would produce:
+% \tocchapterentry{The second chapter}{2}{14}
+%
+% if the second chapter started on page 14.
+%
+% `toc' is the first argument, as above.
+\def\writenumberedcontentsentry#1#2#3#4{%
+ \csname ifrewrite#1file\endcsname
+ \csname open#1file\endcsname
+ \toks0 = {\expandafter\noexpand \csname #1#2entry\endcsname}%
+ \def\temp{#3}%
+ %
+ % Usually #4 is just `\the\register', which we want to expand. But
+ % if it's not a number at all -- e.g., if it's an author's name, we
+ % don't want to expand control sequences for accents and the like.
+ % So we play some games here.
+ \toks2 = \expandafter{#4}%
+ \edef\cs{\the\toks2}%
+ \edef\@wr{%
+ \write\csname #1file\endcsname{%
+ \the\toks0 % the \toc...entry control sequence
+ {\sanitize\temp}% the text
+ \ifx\empty\cs\else {\sanitize\cs}\fi % A secondary number, or nothing:
+ {\noexpand\folio}% the page number
+ }%
+ }%
+ \@wr
+ \fi
+ \ignorespaces
+}%
+%
+% The entries are read in when the user invokes \readtocfile (which
+% should be before the first \writetocentry). We do not open the .toc
+% file to allow reading it in twice to make a short contents or some
+% such. This should not cause any problems because each of
+% \writecontentsentry and \writenumberedcontentsentry open the .toc
+% file for writing (i.e., empty it) before trying to write to it.
+\def\readcontentsfile#1{%
+ \edef\temp{%
+ \noexpand\testfileexistence[\csname #1filebasename\endcsname]{#1}%
+ }\temp
+ \if@fileexists
+ \input \csname #1filebasename\endcsname.#1\relax
+ \fi
+}%
+%
+% Here are some sample definitions of the \toc...entry macros. Perhaps
+% you or your book designer can come up with a better way of handling
+% contents than leaders. These definitions are just examples, not
+% something you might want to actually use to print a document.
+\def\tocchapterentry#1#2{\line{\bf #1 \dotfill\ #2}}%
+\def\tocsectionentry#1#2{\line{\quad\sl #1 \dotfill\ \rm #2}}%
+\def\tocsubsectionentry#1#2{\line{\qquad\rm #1 \dotfill\ #2}}%
+%
+%
+%
+% Cross-references.
+%
+% Definitions of references are recorded in \jobname.aux, called
+% \auxfile in the macros, which btxmac.tex has opened.
+%
+% When a label isn't defined, we only want to complain if
+% \xrefwarningtrue; btxmac uses \if@citewarning for this, so we have to
+% reuse that name. We can't just say \let\ifxrefwarning =
+% \if@citewarning, since then changes to the latter won't be reflected
+% in the former. On the other hand, we have to have a true \if...
+% command, so \if's and \fi's match properly. What a mess.
+%
+\let\ifxrefwarning = \iftrue
+\def\xrefwarningtrue{\@citewarningtrue \let\ifxrefwarning = \iftrue}%
+\def\xrefwarningfalse{\@citewarningfalse \let\ifxrefwarning = \iffalse}%
+%
+%
+% \xref{foo} produces ``p.\thinspace <page#>''. \xrefn{foo} produces
+% ``<page#>''. \xrdef{foo} produces nothing, but defines the label
+% `foo' to be on the current page.
+%
+% As usual, it takes two passes to get the cross-references right. I
+% would like to check for labels being defined twice, but I don't know
+% how to do that. If the cross-reference file has been read in, many
+% cross-references will be defined that I don't want to complain about.
+% It is only if two \xrdef commands are given to the same string that I
+% want to complain. I could define a new control sequence for each
+% cross-reference, and check that, but that seems like too high of a
+% price to pay.
+%
+%
+% \xrlabel{LABEL} expands to a cross-reference internal name. We append
+% an _ character to NAME, to help avoid conflicts. And we append an `x'
+% so that we don't redefine \_ on an empty label.
+%
+\begingroup
+ % Mike Spivak's MathTime macros for Times Roman fonts changes the
+ % catcode of _ to be active. Undo that. (From adam@symcom.math.uiuc.edu.)
+ \catcode`\_ = 8
+ \gdef\xrlabel#1{#1_x}%
+\endgroup
+%
+%
+% \xrdef{LABEL} defines LABEL to be the current page number. But we
+% don't define the label here, because the page number might be off: if
+% this is not the first time through, the label would already be
+% defined, and we would redefine it with the wrong information.
+%
+\def\xrdef#1{%
+ \begingroup
+ % Define hyperlink destination.
+ \hldest@impl{xrdef}{#1}%
+ % Define cross-reference but not hyperlink destination.
+ \begingroup
+ \@@hldestoff
+ \definexref{#1}{\noexpand\folio}{page}%
+ \endgroup
+ \endgroup
+}%
+%
+% \definexref{LABEL}{DEFINITION}{CLASS} defines a cross-reference named
+% LABEL of label class CLASS to be DEFINITION. (Or LABEL can be a
+% control sequence; it's expanded to get the label text.) To get a
+% possible page number right, we have to write the definition out to the
+% auxiliary file, instead of only defining it directly.
+%
+\def\definexref#1#2#3{%
+ % Define a hyperlink destination LABEL.
+ \hldest@impl{definexref}{#1}%
+ % Remember what we're given; it might be `\@optionalarg', which
+ % \readauxfile trashes. (No loss of generality here, since \csname
+ % will fully expand the label anyway.)
+ \edef\temp{#1}%
+ %
+ % Be sure we've read the aux file before we zap it:
+ \readauxfile
+ %
+ % When we read in the aux file next time, define the label:
+ \edef\@wr{\noexpand\writeaux{\string\@definelabel{\temp}{#2}{#3}}}%
+ \@wr
+ \ignorespaces
+}%
+%
+% \@definelabel{LABEL}{DEFINITION}{CLASS} actually defines LABEL of
+% label class CLASS to be DEFINITION.
+%
+\def\@definelabel#1#2#3{%
+ % Define the control sequence.
+ \expandafter\gdef\csname\xrlabel{#1}\endcsname{#2}%
+ %
+ % Remember what kind of label this is, so \ref will know what to do.
+% \global\setproperty{\xrlabel{#1}}{class}{#3}%
+ \setpropertyglobal{\xrlabel{#1}}{class}{#3}%
+}%
+%
+% \reftie is used by several cross-referencing macros to separate
+% optional text from label reference. \refspace is used by \ref to
+% separate optional text from \CLASSword and by \xref to separate
+% optional text from `p. '.
+%
+\def\reftie{\penalty\@M \ }% Do not rely on `~' being defined as a tie.
+\let\refspace\
+%
+% Typeset a reference to the label #1. If optional argument is
+% present it will be tied with \reftie to the reference and become
+% part of the hyperlink.
+%
+\def\xrefn{\@getoptionalarg\@finxrefn}%
+\def\@finxrefn#1{%
+ % Hyperlink and optional TEXT.
+ \hlstart@impl{ref}{#1}%
+ \ifx\@optionalarg\empty \else
+ % Save \@optionalarg before it is trashed by \readauxfile.
+ \let\@xrefnoptarg\@optionalarg
+ % Read .aux file -- \@optionalarg may contain cross-references.
+ \readauxfile
+ % Typeset the \@optionalarg
+ {\@@hloff\@xrefnoptarg}\reftie
+ \fi
+ % Typeset the reference.
+ \plain@xrefn{#1}%
+ \hlend@impl{ref}%
+}%
+% This is equivalent to \xrefn but without the hyperlink stuff and the
+% optional parameter so that its expansion does not contain the many
+% \let's, \def's and such which the expansion of \xrefn contains. It
+% is needed by \eqdefn and \eqsubdefn to be able to `cleanly' write
+% texts of equation labels to .aux file. It is also used when
+% functionality of \xrefn is needed without the hyperlink and the
+% optional parameter.
+\def\plain@xrefn#1{%
+ \readauxfile
+ %
+ \expandafter \ifx\csname\xrlabel{#1}\endcsname\relax
+ \if@citewarning
+ \message{\linenumber Undefined label `#1'.}%
+ \fi
+ %
+ % Give it a dummy definition, though, to stop multiple error messages.
+ \expandafter\def\csname\xrlabel{#1}\endcsname{%
+ `{\tt
+ \escapechar = -1
+ \expandafter\string\csname#1\endcsname
+ }'%
+ }%
+ \fi
+ \csname\xrlabel{#1}\endcsname % Always produce something.
+}%
+%
+% \refn is just a synonym.
+%
+\let\refn = \xrefn
+%
+% One common case: print `p. ' before the page number.
+%
+\def\xrefpageword{p.\thinspace}%
+%
+\def\xref{\@getoptionalarg\@finxref}%
+\def\@finxref#1{%
+ % Hyperlink and optional TEXT.
+ \hlstart@impl{xref}{#1}%
+ \ifx\@optionalarg\empty \else
+ {\@@hloff\@optionalarg}\refspace
+ \fi
+ % Typeset page reference but omit hyperlink.
+ \xrefpageword\plain@xrefn{#1}%
+ \hlend@impl{xref}%
+}%
+%
+% \ref[TEXT]{LABEL} typesets TEXT, \CLASSword for LABEL's class (if it's defined)
+% and then does \refn on LABEL. But amstex also has a \ref, so tell the
+% user if they try to use \ref and have loaded amsppt.sty.
+%
+% \refs{LABEL} is similar, but puts the letter `s' after the \...word, thus
+% producing (for example) `Figures 1.2' (presumably to be followed by
+% `and~\refn{fig-1.3}').
+%
+% Note that \ref takes an optional TEXT, while \refs does not. This
+% text (together with \CLASSword) will become part of the hyperlink
+% generated by \ref. \refs does not include \CLASSword in the
+% hyperlink.
+%
+\def\@maybewarnref{%
+ \ifundefined{amsppt.sty}%
+ % No amsppt.sty, so just use ours.
+ \else
+ \message{Warning: amsppt.sty and Eplain both define \string\ref. See
+ the Eplain manual.}%
+ % Remember their definition.
+ \let\amsref = \ref
+ \fi
+ \let\ref = \eplainref
+ \ref
+}
+\let\ref = \@maybewarnref
+%
+\def\eplainref{\@getoptionalarg\@fineplainref}%
+\def\@fineplainref{\@generalref{1}{}}%
+\def\refs{\let\@optionalarg\empty \@generalref{0}s}%
+%
+% #1 is an integer flag which tells whether hyperlink should include
+% \@optionalarg and class word (non-0) or not (0). #2 is the text to
+% follow the \...word. Both #1 and #2 are supplied by the macros
+% above. #3 comes from the document, and is the LABEL.
+%
+% \reftie separates \@optionalarg or \..word from \refn; \refspace
+% separates \@optionalarg from \..word.
+%
+\def\@generalref#1#2#3{%
+ % Save \@optionalarg before it is trashed by \readauxfile.
+ \let\@generalrefoptarg\@optionalarg
+ \readauxfile
+ % Maybe start hyperlink here.
+ \ifcase#1 \else \hlstart@impl{ref}{#3}\fi
+ % Get the class of the label.
+ \edef\temp{\getproperty{\xrlabel{#3}}{class}}%
+ % If the word for this class is not defined, don't complain.
+ \expandafter\ifx\csname \temp word\endcsname\relax
+ % Produce \@optionalarg followed by a \reftie, if \@optionalarg is
+ % not empty.
+ \ifx\@generalrefoptarg\empty \else {\@@hloff\@generalrefoptarg\reftie}\fi
+ \else
+ \begingroup
+ \@@hloff
+ % Produce \@optionalarg, if not empty, followed by a \refspace.
+ \ifx\@generalrefoptarg\empty \else \@generalrefoptarg \refspace \fi
+ % Produce the word.
+ \csname \temp word\endcsname
+ % Add the suffix and then put in a \reftie before the \refn.
+ #2\reftie
+ \endgroup
+ \fi
+ % Maybe start hyperlink here.
+ \ifcase#1 \hlstart@impl{ref}{#3}\fi
+ % Typeset the reference omitting hyperlinks.
+ \plain@xrefn{#3}%
+ \hlend@impl{ref}%
+}%
+%
+%
+% References to equations are similar.
+%
+% \eqref{foo} produces ``(<text for equation label foo>)''.
+% \eqdefn{foo} advances \eqnumber, resets \eqsubnumber, and defines
+% `foo' to be the new number.
+% \eqsubdefn{foo} advances \eqsubnumber and defines `foo'. \eqref works
+% for both equations and subequations,
+% \eqdef{foo} does \eqdefn, then inserts an \eqno and \eqref.
+% \eqsubdef{foo} does \eqsubdefn, then what \eqdef does.
+%
+% The non-``sub'' macros also take an optional argument; if it's
+% present, we use it as the text for the equation label, instead of the
+% various counters.
+%
+% Because there are no page break issues with equations, we can
+% immediately define the control sequence. But we also need to write
+% the definition out, in case the user wants to forward reference an
+% equation (bad style as that may be).
+%
+% The current equation number is in \eqnumber; we just advance it by one
+% for each \eqdef. You can handle fancier equation numbers (e.g., ones
+% that include a chapter number) by redefining \eqprint, below, and
+% using your own counters. We do provide for one level of substructure,
+% since that's more painful to implement than superstructures.
+%
+\newcount\eqnumber
+\newcount\subeqnumber
+%
+%
+% \eqdefn[TEXT]{LABEL} defines LABEL to be TEXT (if it's present),
+% otherwise it advances \eqnumber and defines LABEL to be that. It
+% doesn't produce anything.
+%
+\def\eqdefn{\@getoptionalarg\@fineqdefn}%
+\def\@fineqdefn#1{%
+ \ifx\@optionalarg\empty
+ \global\advance\eqnumber by 1
+ % We call \eqconstruct here instead of in \@eqdefn because we don't
+ % want to expand it for \eqsubdefn -- \eqsubdefn already includes an
+ % \eqrefn which includes the text of the label which was \eqconstructed.
+ \def\temp{\eqconstruct{\number\eqnumber}}%
+ \else
+ % In the next \def there is (I believe) a spurious \noexpand.
+ % I leave in the old definition, albeit commented out, in case the
+ % \noexpand really _is_ necessary. But I don't thikn so. Adam Lewenberg
+% \def\temp{\noexpand\@optionalarg}%
+ \def\temp{\@optionalarg}%
+ \fi
+ %
+ % Always reset the current subequation number:
+ \global\subeqnumber = 0
+ %
+ % Remember this label, so that we can define subequations:
+ \gdef\@currenteqlabel{#1}%
+ \toks0 = \expandafter{\@currenteqlabel}%
+ %
+ % Actually do the definition, replacing \xrefn and \eqrefn with
+ % \plain@xrefn and taking precautions not to expand \plain@xrefn
+ % in what we output to the aux file. \plain@xrefn expands to many things,
+ % including \count@'s and \edef's and the expansion of \xrlabel, and
+ % it's just a real mess.
+ \begingroup
+ \def\eqrefn{\noexpand\plain@xrefn}%
+ \def\xrefn{\noexpand\plain@xrefn}%
+ \edef\temp{\noexpand\@eqdefn{\the\toks0}{\temp}}%
+ \temp
+ \endgroup
+}%
+%
+%
+% \eqsubdefn defines its argument as a ``subequation'' of the last \eqdef.
+%
+\def\eqsubdefn#1{%
+ \global\advance\subeqnumber by 1
+ \toks0 = {#1}%
+ %
+ % Get the text of the label;
+ \toks2 = \expandafter{\@currenteqlabel}%
+ %
+ % We must expand \@currenteqlabel. We have to not expand
+ % \eqsubreftext here, as well as \plain@xrefn (which we substitute
+ % for \eqrefn and \xrefn), since the first arg to \eqsubreftext
+ % could also include lots of complicated things.
+ \begingroup
+ \def\eqrefn{\noexpand\plain@xrefn}%
+ \def\xrefn{\noexpand\plain@xrefn}%
+ \def\eqsubreftext{\noexpand\eqsubreftext}%
+ \edef\temp{%
+ \noexpand\@eqdefn
+ {\the\toks0}%
+ {\eqsubreftext{\eqrefn{\the\toks2}}{\the\subeqnumber}}%
+ }%
+ \temp
+ \endgroup
+}%
+%
+% \@eqdefn{LABEL}{REF-TEXT} actually handles the equation number
+% definitions and writing to the aux file.
+%
+% In contrast to \xrdef, we define LABEL right away (as REF-TEXT). We
+% can do this since we know right now what the right equation number is.
+% This eliminates some unnecessary warning. It also lets the user put
+% \eqdef{} on all equations and have it work, since then \eqref
+% refers to the just-defined new value.
+%
+\def\@eqdefn#1#2{%
+ % Define hyperlink destination taking care of empty LABEL.
+ \hl@define@eqlabel{#1}%
+ \hldest@impl{eq}{\hl@eqlabel}%
+ % Define cross-reference but not hyperlink destination.
+ \begingroup
+ \@@hldestoff
+ \definexref{#1}{#2}{eq}%
+ \endgroup
+ % Define the LABEL.
+ \@definelabel{#1}{#2}{eq}%
+}%
+%
+% \eqdef{LABEL} defines LABEL, with \eqdefn, then prints it. We allow
+% an optional argument to explicitly specify the text which we define
+% the label as.
+%
+\def\eqdef{\@getoptionalarg\@fineqdef}%
+\def\@fineqdef{%
+ \toks0 = \expandafter{\@optionalarg}%
+ \edef\temp{\noexpand\@eqdef{\noexpand\eqdefn[\the\toks0]}}%
+ \temp
+}%
+%
+% \eqsubdef is to \eqdef as \eqsubdefn is to \eqdefn. No optional
+% argument allowed here.
+%
+\def\eqsubdef{\@eqdef\eqsubdefn}%
+%
+% \@eqdef{DEFN-CMD}{LABEL} defines LABEL, using DEFN-CMD. Then it
+% inserts an \eqno (unless it's called when an \eqno would be invalid).
+% Then it prints the newly-defined value using \eqprint.
+%
+\def\@eqdef#1#2{%
+ % Define the label but not hyperlink destination (we want to define
+ % the destination after \eqno). Note that \@eqdefn will call
+ % \hl@define@eqlabel{#2}, so we won't call it again (definintions in
+ % \hl@define@eqlabel must be global to survive past the group).
+ \begingroup
+ \@@hldestoff
+ #1{#2}%
+ \endgroup
+ % Define hyperlink destination and print the text.
+ \@maybedisableeqno
+ \eqno % \hl@define@eqlabel already called in \@eqdefn.
+ \hldest@impl{eq}{\hl@eqlabel}%
+ \let\@optionalarg\empty % \@fineqref will examine \@optionalarg.
+ {\@@hloff\@fineqref{#2}}% No hyperlink here.
+ \@mayberestoreeqno
+ \ignorespaces
+}%
+%
+%
+% If we are in an alignment or some other inner place, \eqno won't work.
+%
+\let\@mayberestoreeqno = \relax
+%
+\def\@maybedisableeqno{%
+ \ifinner
+ \global\let\eqno = \relax
+ \global\let\@mayberestoreeqno = \@restoreeqno
+ \fi
+}%
+%
+% This makes `\eqno' mean \eqno again.
+%
+\let\@primitiveeqno = \eqno
+\def\@restoreeqno{%
+ \global\let\eqno = \@primitiveeqno
+ \global\let\@mayberestoreeqno = \empty
+}%
+%
+%
+% \eqrefn[TEXT]{LABEL} produces the text for the equation label LABEL, or
+% something suitable if LABEL is undefined. (It possibly issues a
+% warning in the latter case as well.) TEXT followed by a \reftie is
+% prepended to the equation text as part of the hyperlink.
+%
+\def\eqrefn{\@getoptionalarg\@fineqrefn}%
+\def\@fineqrefn#1{%
+ \eqref@start{#1}%
+ % Typeset the equation reference but do not produce hyperlink.
+ \plain@xrefn{#1}%
+ \hlend
+}%
+%
+% \eqref[TEXT]{LABEL} is the usual way to refer to equation labels; it
+% calls \eqprint on the text of LABEL, prepending it with TEXT and a
+% \reftie as part of the hyperlink.
+%
+\def\eqref{\@getoptionalarg\@fineqref}%
+\def\@fineqref#1{%
+ \eqref@start{#1}%
+ % Typeset the equation reference but do not produce hyperlink.
+ \eqprint{\plain@xrefn{#1}}%
+ \hlend@impl{eq}%
+}%
+% Common code executed at the start of \@fineqrefn and \@fineqref.
+\def\eqref@start#1{%
+ % Save \@optionalarg in case \phantomeqlabel is redefined by the
+ % user to something that trashes it.
+ \let\@eqrefoptarg\@optionalarg
+ % Hyperlink (fetch last `phantom' equation label if LABEL is empty).
+ \ifempty{#1}%
+ \hlstart@impl{eq}{\phantomeqlabel}%
+ \else
+ \hlstart@impl{eq}{#1}%
+ \fi
+ % Optional TEXT followed by a \reftie.
+ \ifx\@eqrefoptarg\empty \else
+ {\@@hloff\@eqrefoptarg\reftie}%
+ \fi
+}%
+%
+%
+% \eqconstruct{EQ-TEXT} constructs an equation number, i.e., the text to
+% be defined as the value of a label.
+%
+\let\eqconstruct = \identity
+%
+% \eqprint{EQ-TEXT} produces the typeset equation number EQ-TEXT.
+%
+\def\eqprint#1{(#1)}%
+%
+% \eqsubreftext{EQ-TEXT}{SUBEQ-TEXT} produces the text of a subequation
+% reference. (\eqprint is later called on the result of this to produce
+% output for subequations; I didn't define any \subeqprint.)
+%
+\def\eqsubreftext#1#2{#1.#2}%
+%
+%
+%
+% Indexing.
+%
+% \defineindex{PREFIX} defines an index with ``prefix'' PREFIX. The
+% prefix is used to construct the output filename and the various
+% commands. We just define all the index commands for this index to
+% call the general commands with PREFIX.
+%
+\let\extraidxcmdsuffixes = \empty
+%
+\outer\def\defineindex#1{%
+ \def\@idxprefix{#1}%
+ %
+ % Define the indexing commands for this prefix.
+ \for\@idxcmd:=,marked,submarked,name%
+ \extraidxcmdsuffixes\do
+ {%
+ \@defineindexcmd\@idxcmd
+ }%
+ %
+ % Allocate a stream for the output.
+ \ece\innernewwrite{@#1indexfile}%
+ %
+ % And a conditional to test whether we've opened the file.
+ \ece\innernewif{if@#1indexfileopened}%
+}%
+%
+%
+% \@defineindexcmd{SUFFIX} defines both silent and non-silent index
+% command for prefix \@idxprefix with suffix SUFFIX. That is, we define
+% both `\@idxprefix dxSUFFIX' and `\s\@idxprefix dxSUFFIX' to call the
+% corresponding generic command with \@idxprefix. \silentindexentry is
+% used to decide whether we should ignore following spaces.
+%
+\newif\ifsilentindexentry
+%
+\def\@defineindexcmd#1{%
+ \@defineoneindexcmd{s}{#1}\silentindexentrytrue
+ \@defineoneindexcmd{}{#1}\silentindexentryfalse
+}%
+%
+%
+% \@defineoneindexcmd{PREFIX}{SUFFIX}{PRECALL} does just one silent or
+% non-silent commands. We define the command `\@@PREFIXidxSUFFIX' to do
+% PRECALL, then define \@idxprefix, then call \@idxgetrange with an
+% argument of `\@@{,s}idxSUFFIX'. (So far every indexing command
+% should allow a range. If not, you could redefine `\@@{,s}idxSUFFIX'
+% after this macro is called.)
+%
+\def\@defineoneindexcmd#1#2#3{%
+ \toks@ = {#3}%
+ \edef\temp{%
+ \def
+ % We have to restrict expansion because the generic (\@@...)
+ % commands will be defined after the first call to \defineindex.
+ % Not expanding the user (\idx...) commands is unnecessary unless
+ % the user has defined some new commands, but may as well be cautious.
+ \expandonce\csname#1\@idxprefix dx#2\endcsname % e.g., \idx or \sidxname.
+ {\def\noexpand\@idxprefix{\@idxprefix}% define \@idxprefix
+ % call, e.g., \@@idx or \@@sidxname:
+ \expandonce\csname @@#1idx#2\endcsname
+ }%
+ \def
+ \expandonce\csname @@#1idx#2\endcsname{% e.g., \@@idx
+ % First do PRECALL.
+ \the\toks@
+ % Then call \@idxgetrange with, e.g., \@idx or \@sidxname as its arg.
+ \noexpand\@idxgetrange\expandonce\csname @#1idx#2\endcsname
+ }%
+ }%
+ \temp
+}%
+%
+%
+% \@idxwrite{TERM}{PAGENO} writes a general index entry for TERM on page
+% PAGENO to the index file `\@idxprefix indexfile'. We open the stream
+% as `\indexfilebasename.\@idxprefix dx' if it isn't already open.
+%
+\let\indexfilebasename = \jobname
+%
+\def\@idxwrite#1#2{%
+ % Be sure the file is opened.
+ \csname if@\@idxprefix indexfileopened\endcsname \else
+ \expandafter\immediate\openout\csname @\@idxprefix indexfile\endcsname =
+ \indexfilebasename.\@idxprefix dx
+ \expandafter\global\csname @\@idxprefix indexfileopenedtrue\endcsname
+ \fi
+ %
+ % Save the index term.
+ \def\temp{#1}%
+ %
+ % Write the index term and page number.
+ \edef\@wr{%
+ \expandafter\write\csname @\@idxprefix indexfile\endcsname{%
+ \string\indexentry
+ {\sanitize\temp}%
+ {\noexpand#2}%
+ }%
+ }%
+ \@wr
+ %
+ % Marginalize the index term, if desired.
+ % (the \allowhyphens allows `infinitesimal' in \sidx{Infinitesimal}infinitesimal
+ % to be hyphenated.
+ \ifindexproofing \insert\@indexproof{\indexproofterm{#1}}\allowhyphens\fi
+ %
+ % We just appended at least one non-discardable item (namely, the
+ % whatsit from the \write) to the current list. So in case glue comes
+ % next (not unlikely), be sure we don't inadvertently make that glue a
+ % valid breakpoint, if it wouldn't have been without us.
+ \hookrun{afterindexterm}%
+ %
+ % This is the end of the index entry processing. If this was a silent
+ % entry, ignore following spaces.
+ \ifsilentindexentry \expandafter\ignorespaces\fi
+}%
+%
+%
+% If this conditional is true, we output the index terms on the page
+% where they occur.
+\newif\ifindexproofing
+%
+% We need a new insertion class to collect the proofed terms.
+\newinsert\@indexproof
+\dimen\@indexproof = \maxdimen % No limit on number of terms.
+\count\@indexproof = 0 \skip\@indexproof = 0pt % They take up no space.
+%
+% This actually typesets the proofed term. We don't go to any lengths
+% to provide nice-looking output; since the term might have all kinds of
+% weird characters in it, we just dump it in the smallest standard
+% Computer Modern typewriter font.
+%
+% We put the term in an \hbox, even though that might make the output
+% run off the page, since we don't really need to see all of it, and
+% I think it's better to opt for simplicity -- one term per line.
+\font\indexprooffont = cmtt8
+\def\indexproofterm#1{\hbox{\strut \indexprooffont #1}}%
+%
+%
+% If \output doesn't use \makeheadline, or redefines it, it's up to the
+% new \output to define index hyperlink destination and to call
+% \indexproofunbox.
+\let\@plainmakeheadline = \makeheadline
+\def\makeheadline{%
+ % Define index page destination only when this `cross-reference' is defined.
+ \expandafter\ifx\csname\xrlabel{\idxpagexref{\folio}}\endcsname\relax \else
+ % Say \@@hldeston in case a page break happened at an unfortunate
+ % time when user said \hldestoff.
+ {\@@hldeston \hldest@impl{idx}{\hlidxpagelabel{\folio}}}%
+ \fi
+ \indexproofunbox
+ \@plainmakeheadline
+}%
+%
+% We want to put the proof index terms in the margin, outside the
+% printed area. So if \outsidemargin (for odd pages) and \insidemargin
+% (for even pages) are undefined, we define them (both) to be the default
+% TeX margin -- one inch + \hoffset.
+\def\indexsetmargins{%
+ \ifx\undefined\outsidemargin
+ \dimen@ = 1truein
+ \advance\dimen@ by \hoffset
+ \edef\outsidemargin{\the\dimen@}%
+ \let\insidemargin = \outsidemargin
+ \fi
+}%
+%
+% We always put the terms in the right-hand margin, so long terms run
+% off the page, instead of into the text.
+\def\indexproofunbox{%
+ \ifvoid\@indexproof\else
+ \indexsetmargins
+ \rlap{%
+ \kern\hsize
+ \ifodd\pageno \kern\outsidemargin \else \kern\insidemargin \fi
+ \vbox to 0pt{\unvbox\@indexproof\vss}%
+ }\nointerlineskip
+ \fi
+}%
+%
+%
+% \@idxgetrange\CS parses an optional argument which, if present, should
+% be either `begin' or `end', marking the beginning or ending of a range
+% for the index entry. If we find this, we set the appropriate one of
+% \@idxrangestr. Then we call \CS.
+%
+% If the optional argument is `see' or `seealso' we read another
+% argument, namely, the entry to see.
+%
+\def\idxrangebeginword{begin}%
+\def\idxbeginrangemark{(}% the corresponding magic char to go in the idx file
+%
+\def\idxrangeendword{end}%
+\def\idxendrangemark{)}%
+%
+\def\idxseecmdword{see}%
+\def\idxseealsocmdword{seealso}%
+\newif\if@idxsee
+\newif\if@hlidxencap
+\let\@idxseenterm = \relax
+%
+\def\idxpagemarkupcmdword{pagemarkup}%
+\let\@idxpagemarkup = \relax
+%
+\def\@idxgetrange#1{%
+ \let\@idxrangestr = \empty
+ \let\@afteridxgetrange = #1%
+ \@getoptionalarg\@finidxgetopt
+}%
+\def\@finidxgetopt{%
+ \@hlidxencaptrue
+ %
+ \for\@idxarg:=\@optionalarg\do{%
+ % These are ordered by my guess at frequency of use.
+ \expandafter\@idxcheckpagemarkup\@idxarg=,%
+ %
+ \ifx\@idxarg\idxrangebeginword
+ \def\@idxrangestr{\idxencapoperator\idxbeginrangemark}%
+ \else
+ \ifx\@idxarg\idxrangeendword
+ \def\@idxrangestr{\idxencapoperator\idxendrangemark}%
+ \@hlidxencapfalse
+ \else
+ \ifx\@idxarg\idxseecmdword
+ \def\@idxpagemarkup{indexsee}%
+ \@idxseetrue
+ \@hlidxencapfalse
+ \else
+ \ifx\@idxarg\idxseealsocmdword
+ \def\@idxpagemarkup{indexseealso}%
+ \@idxseetrue
+ \@hlidxencapfalse
+ \else
+ \ifx\@idxpagemarkup\relax
+ \errmessage{Unrecognized index option `\@idxarg'}%
+ \fi
+ \fi
+ \fi
+ \fi
+ \fi
+ }%
+ % Stick hyperlink encapsulator into \@idxpagemarkup.
+ \ifnum\hldest@place@idx < 0 \else
+ \if@hlidxencap
+ \ifx\@idxpagemarkup\relax
+ % Even when user gives no pagemarkup command, we still do
+ % insert our hyperlink encapsulator.
+ \let\@idxpagemarkup\empty
+ \fi
+ \ifcase\hldest@place@idx \relax
+ % \hldest@place@idx = 0, dests point to a page with a term.
+ \edef\@idxpagemarkup{hlidxpage{\@idxpagemarkup}}%
+ % We want to define index \hldest's only on those
+ % pages which contain at least one index term, so this
+ % `cross-reference' will tell \makeheadline on which pages to
+ % generate an \hldest.
+ {\@@hldestoff \definexref{\idxpagexref{\folio}}{}{}}%
+ \else
+ % \hldest@place@idx = 1, dests point to exact location of a term.
+ \global\advance\hlidxlabelnumber by 1
+ \edef\@idxpagemarkup{hlidx{\hlidxlabel}{\@idxpagemarkup}}%
+ \hldest@impl{idx}{\hlidxlabel}%
+ \fi
+ \fi
+ \fi
+ %
+ \@afteridxgetrange
+}%
+%
+%
+% Check for a command of the form `pagemarkup=\cmd', and if found, set
+% \@idxpagemarkup to `cmd'.
+%
+\def\@idxcheckpagemarkup#1=#2,{%
+ \def\temp{#1}%
+ \ifx\temp\idxpagemarkupcmdword
+ \if ,#2, % If #2 is empty, complain.
+ \errmessage{Missing markup command to `pagemarkup'}%
+ \else
+ % Remove a trailing =.
+ \def\temp##1={##1}%
+ \edef\@idxpagemarkup{\temp\string#2}%
+ \fi
+ \fi
+}%
+%
+%
+% \hlidxpage and \hlidx are hyperlink encapsulators for the two types
+% of hyperlink destinations for index terms.
+%
+% \hldest@place@idx defines which type is selected. When defined to 0,
+% we generate destinations pointing to the page on which the indexed
+% term is located. When defined to 1, we generate destinations
+% pointing to exact location of the indexed term. When negative, we
+% generate no hyperlinks / destinations.
+\def\hldest@place@idx{-1}%
+% Name for a `cross-reference' which \makeheadline uses do decide on
+% which pages to generate \hldest.
+\def\idxpagexref#1{@@IDXPG@@#1}%
+% Hyperlink labels for both types of destinations.
+\newcount\hlidxlabelnumber
+\def\hlidxlabel{IDX\the\hlidxlabelnumber}%
+\def\hlidxpagelabel#1{IDXPG#1}%
+%
+% \hlidx{HYPERLINK-LABEL}{PAGEENCAP}{PAGESPEC}
+\def\hlidx#1#2#3{%
+ \hlstart@impl{idx}{#1}%
+ \csname #2\endcsname{#3}%
+ \hlend@impl{idx}%
+}%
+%
+% \hlidxpage{PAGEENCAP}{PAGESPEC}
+%
+% We expect PAGESPEC to be one of the following:
+% 14 (single page number)
+% 14, 15 (list of two consecutive page numbers)
+% 14--15 (page range)
+%
+% If you configure MakeIndex to use different page list separator
+% (delim_n parameter in .mst file) / different page range separator
+% (delim_r parameter), you should call \setidxpagelistdelimiter /
+% \setidxpagerangedelimiter to setup the new separators.
+%
+% In case of a single page number, we call \PAGEENCAP on the page
+% number and turn the result into a hyperlink.
+%
+% In case of a two-page list, we break the list, call \PAGEENCAP on
+% each of the page numbers separately, and turn each result into a
+% hyperlink, producing page list separator between the page numbers.
+%
+% In case of a page range, we do not break the range, call \PAGEENCAP
+% on the entire range and turn what results into a hyperlink for the
+% first of the page numbers.
+\def\hlidxpage#1#2{%
+ % Set \@idxpagei[i][ref] and \@idxpagesep
+ \@hlidxgetpages{#2}%
+ % Alias for \PAGEENCAP.
+ \expandafter\let\expandafter\@idxpageencap\csname #1\endcsname
+ % Now comes the first part, to be done in any of the three cases.
+ \hlstart@impl{idx}{\hlidxpagelabel{\@idxpageiref}}%
+ \expandafter\@idxpageencap\expandafter{\@idxpagei}%
+ \hlend@impl{idx}%
+ % The second part, to be done only if there is a second page number.
+ \ifx\@idxpageii\empty \else
+ \@idxpagesep
+ \hlstart@impl{idx}{\hlidxpagelabel{\@idxpageiiref}}%
+ \expandafter\@idxpageencap\expandafter{\@idxpageii}%
+ \hlend@impl{idx}%
+ \fi
+}%
+%
+% This macro parses PAGESPEC parameter to \hlidxpage. It sets
+% \@idxpagei to the first page number, \@idxpageii to the second (if
+% present; if not, \@idxpageii will be set to \empty). For the first
+% page number, use \@idxpageiref to construct hyperlink label; for
+% the second page number, use \@idxpageiiref. Use \@idxpagesep to
+% separate the two page numbers.
+%
+% NOTE: we use \@idxpagei[i], not \idxpagei[i], because the user may
+% use \idxparselist / \idxparserange in his \PAGEENCAP, in which case
+% our \idxpagei[i]'s will get garbled.
+\def\@hlidxgetpages#1{%
+ % Try to parse a two-page list.
+ \idxparselist{#1}%
+ \ifx\idxpagei\empty
+ % It is not a two-page list, try page range.
+ \idxparserange{#1}%
+ \ifx\idxpagei\empty
+ % It is neither a two-page list nor a page range, so we assume
+ % it is a single page number.
+ \def\@idxpageiref{#1}% Label for \hlstart.
+ \else
+ % It is a page range.
+ \let\@idxpageiref\idxpagei % Label for \hlstart.
+ \fi
+ \def\@idxpagei{#1}%
+ \let\@idxpageii\empty
+ \else
+ % It is a two-page list.
+ \let\@idxpagei\idxpagei
+ \let\@idxpageii\idxpageii
+ \let\@idxpageiref\idxpagei % Label for \hlstart.
+ \let\@idxpageiiref\idxpageii % Label for \hlstart.
+ \let\@idxpagesep\idxpagelistdelimiter
+ \fi
+}%
+%
+% Set up a macro \@idxparselist and user-accessible \idxparselist for
+% parsing two-page list. Takes list separator (which is saved in
+% \idxpagelistdelimiter). If the list is found, \@idxparselist will
+% set \idxpagei to the first page number, \idxpageii to the second;
+% if not found, it will set \idxpagei to \empty (this implies that
+% the list's first page number should never be empty).
+\def\setidxpagelistdelimiter#1{%
+ \gdef\idxpagelistdelimiter{#1}%
+ \gdef\@removepagelistdelimiter##1#1{##1}%
+ \gdef\@idxparselist##1#1##2\@@{%
+ \ifempty{##2}%
+ \let\idxpagei\empty
+ \else
+ \def\idxpagei{##1}%
+ \edef\idxpageii{\@removepagelistdelimiter##2}%
+ \fi
+ }%
+ \gdef\idxparselist##1{\@idxparselist##1#1\@@}%
+}%
+%
+% Same as previous, but \@idxparserange and \idxparserange will parse
+% page range, range separator is saved in \idxpagerangedelimiter.
+\def\setidxpagerangedelimiter#1{%
+ \gdef\idxpagerangedelimiter{#1}%
+ \gdef\@removepagerangedelimiter##1#1{##1}%
+ \gdef\@idxparserange##1#1##2\@@{%
+ \ifempty{##2}%
+ \let\idxpagei\empty
+ \else
+ \def\idxpagei{##1}%
+ \edef\idxpageii{\@removepagerangedelimiter##2}%
+ \fi
+ }%
+ \gdef\idxparserange##1{\@idxparserange##1#1\@@}%
+}%
+%
+% Set up the default delimiters.
+\setidxpagelistdelimiter{, }%
+\setidxpagerangedelimiter{--}%
+%
+%
+% \@idxtokscollect uses \@idxmaintoks as the token list for the main
+% part of an index entry and \@idxsubtoks for the subpart. Then it
+% calls \@idxwrite.
+%
+\def\idxsubentryseparator{!}%
+\def\idxencapoperator{|}%
+\def\idxmaxpagenum{99999}%
+%
+\newtoks\@idxmaintoks
+\newtoks\@idxsubtoks
+%
+\def\@idxtokscollect{%
+ % Remember the subentry.
+ \edef\temp{\the\@idxsubtoks}%
+ %
+ % We want to expand the conditions, but not the terms. The index
+ % entry starts simply with \@idxmaintoks and \@idxsubtoks.
+ \edef\@indexentry{%
+ \the\@idxmaintoks
+ \ifx\temp\empty\else \idxsubentryseparator\the\@idxsubtoks \fi
+ \@idxrangestr
+ }%
+ %
+ % If this is a `see' or `see also' entry, we need to read one more
+ % arg. We use a giant page number so the entry will be last (for the
+ % benefit of `see also's). MakeIndex rejects page numbers >=1000.
+ %
+ \if@idxsee
+ \@idxseefalse % Reset so the next term won't be a `see'.
+ \edef\temp{\noexpand\@finidxtokscollect{\idxmaxpagenum}}%
+ \else
+ \def\temp{\@finfinidxtokscollect\folio}%
+ \fi
+ \temp
+}%
+%
+%
+% \@finidxtokscollect{PAGENO}{REAL-TERM} reads the final term for
+% see/see also entries. We do not check if the person has put both a
+% range and a see in the same index term (which will confuse makeindex).
+%
+\def\@finidxtokscollect#1#2{%
+ \def\@idxseenterm{#2}%
+ \@finfinidxtokscollect{#1}%
+}%
+%
+% \@finfinidxtokscollect{PAGENO} writes \@indexentry for page PAGENO.
+% Besides \@indexentry, if \@idxpagemarkup is not \relax we output an
+% index entry \@indexentry|\@idxpagemarkup{PAGENO} (but omitting | if
+% this is a range term, because in that case | will have been added
+% together with \@idxrangestr in \@idxtokscollect). And if
+% \@idxseenterm is not \relax we output {\@idxseenterm} after the
+% \@idxpagemarkup. (This will become an argument to the ``markup''
+% command, which will be \indexsee or \indexseealso.)
+%
+\def\@finfinidxtokscollect#1{%
+ % If we've got a page markup command, append it.
+ \ifx\@idxpagemarkup\relax \else
+ \toks@ = \expandafter{\@indexentry}%
+ \edef\@indexentry{%
+ \the\toks@
+ % Add | only if this is not a range term, otherwise | has
+ % already been added with \@idxrangestr by \@idxtokscollect.
+ \ifx\@idxrangestr\empty \idxencapoperator \fi
+ \@idxpagemarkup
+ }%
+ \let\@idxpagemarkup = \relax
+ \fi
+ %
+ % If we've got an argument to the ``page markup'' command, append it.
+ \ifx\@idxseenterm\relax \else
+ \toks@ = \expandafter{\@indexentry}%
+ \edef\@indexentry{\the\toks@{\sanitize\@idxseenterm}}%
+ \let\@idxseenterm = \relax
+ \fi
+ %
+ % Finally, write what we've constructed.
+ \expandafter\@idxwrite\expandafter{\@indexentry}{#1}%
+}%
+%
+%
+% \@idxcollect{MAIN}{SUB} sets up the token registers
+% \@idx{main,sub}toks, then calls \@idxtokscollect. This is convenient
+% for some of the macros below.
+%
+\def\@idxcollect#1#2{%
+ \@idxmaintoks = {#1}%
+ \@idxsubtoks = {#2}%
+ \@idxtokscollect
+}%
+%
+%
+% Following are the TeX macros that correspond to the commands
+% that actually appear in the document.
+%
+% \@idx{TERM} produces TERM in the output and then makes the index entry
+% for TERM as usual. We don't allow a [SUBTERM] here since then we
+% would lose spaces after the command, which would be very inconvenient.
+%
+% As with all our index commands, we've already defined \@idxprefix (in
+% \idx or whatever), to save passing it around, and we've looked for a
+% range argument before TERM.
+%
+\def\@idx#1{%
+ #1% Produce TERM as output.
+ \@idxcollect{#1}{}%
+}%
+%
+% \@sidx{TERM}[SUBTERM] produces an index entry TERM and no output. If
+% SUBTERM is present, this is a subentry. (At the moment, I don't
+% provide for subsubentries, since I've never needed that.)
+%
+\def\@sidx#1{\@idxmaintoks = {#1}\@getoptionalarg\@finsidx}%
+\def\@finsidx{%
+ \@idxsubtoks = \expandafter{\@optionalarg}%
+ \@idxtokscollect
+}%
+%
+%
+% \@idxconstructmarked{TOKS-REG}\CS{TERM}
+%
+\def\idxsortkeysep{@}% This `@' is catcode 11, but it doesn't matter.
+%
+\def\@idxconstructmarked#1#2#3{%
+ \toks@ = {#2}% The control sequence.
+ \toks2 = {#3}% The term.
+ %
+ % Construct TERM@\CS{TERM} as the string to write.
+ \edef\temp{\the\toks2 \idxsortkeysep \the\toks@{\the\toks2}}%
+ %
+ % Save it in TOKS-REG.
+ #1 = \expandafter{\temp}%
+}%
+%
+%
+% \@idxmarked\CS{TERM} outputs \CS{TERM} and then calls the main part of
+% \@sidxmarked.
+%
+\def\@idxmarked#1#2{%
+ #1{#2}% Produce \CS{TERM} as output.
+ \@idxconstructmarked\@idxmaintoks{#1}{#2}%
+ \@idxsubtoks = {}%
+ \@idxtokscollect
+}%
+%
+% \@sidxmarked\CS{TERM}[SUBTERM] outputs an index entry sorted by TERM
+% but producing \CS{TERM}.
+%
+\def\@sidxmarked#1#2{%
+ \@idxconstructmarked\toks@{#1}{#2}%
+ \edef\temp{{\the\toks@}}%
+ \expandafter\@sidx\temp
+}%
+%
+%
+% \@idxsubmarked{TERM}\CS{SUBTERM} is like \@idxmarked, except that it's
+% SUBTERM that's marked instead of TERM.
+%
+\def\@idxsubmarked#1#2#3{%
+ #1 #2{#3}% produce `TERM \CS{SUBTERM} as output.
+ \@sidxsubmarked{#1}{#2}{#3}%
+}%
+%
+% \@sidxsubmarked{TERM}\CS{SUBTERM} is to \@sidxmarked as \@idxsubmarked
+% is to \@idxmarked.
+%
+\def\@sidxsubmarked#1#2#3{%
+ \@idxmaintoks = {#1}%
+ \@idxconstructmarked\@idxsubtoks{#2}{#3}%
+ \@idxtokscollect
+}%
+%
+%
+% \@idxcollectname{FIRST}{LAST} puts `LAST, FIRST' into \temp. (Well,
+% we use \idxnameseparator instead of hardwiring `, '.) If FIRST is
+% empty, don't include the separator.
+%
+\def\idxnameseparator{, }% as in `Tachikawa, Elizabeth'
+%
+\def\@idxcollectname#1#2{%
+ \def\temp{#1}%
+ \ifx\temp\empty
+ \toks@ = {}%
+ \else
+ \toks@ = {\idxnameseparator #1}%
+ \fi
+ \toks2 = {#2}%
+ %
+ \edef\temp{\the\toks2 \the\toks@}%
+}%
+%
+%
+% \@idxname{FIRST}{LAST} also produces `FIRST LAST' in the output and an
+% index entry for `LAST, FIRST'.
+%
+\def\@idxname#1#2{%
+ #1 #2% Separate the names by a space in the output.
+ \@idxcollectname{#1}{#2}%
+ \expandafter\@idxcollect\expandafter{\temp}{}%
+}%
+%
+% \@sidxname{FIRST}{LAST}[SUBTERM] is to \@sidx as \@idxname is to
+% \@idx.
+%
+\def\@sidxname#1#2{%
+ \@idxcollectname{#1}{#2}%
+ \expandafter\@sidx\expandafter{\temp}%
+}%
+%
+%
+% Now we come to actually producing the index, i.e., implementing the
+% formatting commands that MakeIndex outputs.
+%
+% \readindexfile is responsible for formatting and printing the index.
+% It reads \indexfilebasename.ind. We implement the same commands that
+% LaTeX does. I suppose we could allow for different indices having
+% different basenames, but I can't imagine when that would be useful.
+%
+\let\indexfonts = \relax
+%
+\def\readindexfile#1{%
+ \edef\@idxprefix{#1}%
+ %
+ % Does the output file exist?
+ \testfileexistence[\indexfilebasename]{\@idxprefix nd}%
+ \iffileexists \begingroup
+ % If no \begin or \end, define them. The argument will be `{theindex}'.
+ \ifx\begin\undefined
+ \def\begin##1{\@beginindex}%
+ \let\end = \@gobble
+ \fi
+ %
+ % Read the file:
+ \input \indexfilebasename.\@idxprefix nd
+ %
+ % \doublecolumns isn't affected by groups.
+ \singlecolumn
+ \endgroup
+ \else
+ \message{No index file \indexfilebasename.\@idxprefix nd.}%
+ \fi
+}%
+%
+% Here's the default for `\begin{theindex}', if \begin isn't defined.
+\def\@beginindex{%
+ % Define the commands MakeIndex outputs.
+ \let\item = \@indexitem
+ \let\subitem = \@indexsubitem
+ \let\subsubitem = \@indexsubsubitem
+ %
+ % Set up the default formatting:
+ \indexfonts
+ \doublecolumns
+ \parindent = 0pt
+ %
+ % Let the user override the defaults.
+ \hookrun{beginindex}%
+}%
+%
+% MakeIndex puts \indexspace between groups in the ind file.
+\let\indexspace = \bigbreak
+%
+% You can make \afterindexterm appear after the term and before the
+% first page with the following in the ist file:
+% delim_0 "\\afterindexterm "
+% delim_1 "\\afterindexterm "
+% delim_2 "\\afterindexterm "
+\let\afterindexterm = \quad
+%
+%
+% Top-level index entries start with \item.
+\newskip\aboveindexitemskipamount \aboveindexitemskipamount = 0pt plus2pt
+\def\aboveindexitemskip{\vskip\aboveindexitemskipamount}%
+%
+\def\@indexitem{\begingroup
+ \@indexitemsetup
+ \leftskip = 0pt
+ \aboveindexitemskip
+ \penalty-100 % Encourage page breaks before items.
+ %
+ % But forbid page breaks after items, in case a subitem follows.
+ \def\par{\endgraf\endgroup\nobreak}%
+}%
+%
+% Secondary index entries.
+\def\@indexsubitem{%
+ \@indexitemsetup
+ \leftskip = 1em
+}%
+%
+% And tertiary entries.
+\def\@indexsubsubitem{%
+ \@indexitemsetup
+ \leftskip = 2em
+}%
+%
+% Common setup for the formatting.
+\def\@indexitemsetup{%
+ \par
+ \hangindent = 1em
+ \raggedright
+ \hyphenpenalty = 10000
+ \hookrun{indexitem}%
+}%
+%
+%
+% \indexsee{TERM}{PAGENO} ignores PAGENO, and says `see TERM'.
+\def\seevariant{\it}%
+\def\indexseeword{see}%
+\def\indexsee#1#2{{\seevariant \indexseeword\/ }#1}%
+%
+% \indexseealso{TERM}{PAGENO} is similar.
+\def\indexseealsowords{see also}%
+\def\indexseealso#1#2{{\seevariant \indexseealsowords\/ }#1}%
+%
+%
+% We provide one index by default; commands are \idx, \sidx, etc.
+\defineindex{i}%
+%
+%
+%
+% Justification of multiple input lines.
+%
+% You use these by saying
+% {\flushright
+% <flush right text>
+% }
+%
+% and similarly for \flushleft and \center. The command must be
+% embedded in a group. The lines are set in paragraphs as usual, i.e.,
+% blank lines start a new paragraph (by virtue of the
+% \blanklineskipamount vertical glue being inserted).
+%
+% \environment ... \endenvironment isn't appropriate in this case, since
+% these ``environments'' can't be nested.
+%
+\begingroup
+ \catcode `\^^M = \active %
+ \gdef\flushleft{%
+ \def\@endjustifycmd{\@endflushleft}%
+ \def\@eoljustifyaction{\null\hfil\break}%
+ \let\@firstlinejustifyaction = \relax
+ \@startjustify %
+ }%
+ \gdef\flushright{%
+ \def\@endjustifycmd{\@endflushright}%
+ \def\@eoljustifyaction{\break\null\hfil}%
+ \def\@firstlinejustifyaction{\hfil\null}%
+ \@startjustify %
+ }%
+ \gdef\center{%
+ \def\@endjustifycmd{\@endcenter}%
+ \def\@eoljustifyaction{\hfil\break\null\hfil}%
+ \def\@firstlinejustifyaction{\hfil\null}%
+ \@startjustify %
+ }%
+ %
+ % We do this before starting any of the justification commands.
+ \gdef\@startjustify{%
+ \parskip = 0pt
+ \catcode`\^^M = \active %
+ \def^^M{\futurelet\next\@finjustifyreturn}%
+ %
+ % \@eateol is called at the beginning of each justified paragraph.
+ \def\@eateol##1^^M{%
+ \def\temp{##1}%
+ \@firstlinejustifyaction %
+ \ifx\temp\empty\else \temp^^M\fi %
+ }%
+ \expandafter\aftergroup\@endjustifycmd %
+ \checkenv \environmenttrue %
+ \par\noindent %
+ \@eateol %
+ }%
+ %
+ % If the next thing is a ^^M, insert \blanklineskipamount glue. Then
+ % do \@eoljustifyaction (which each justification command defines).
+ \gdef\@finjustifyreturn{%
+ \@eoljustifyaction %
+ \ifx\next^^M%
+ % Insert extra glue when the \@end... command does the \par.
+ \def\par{\endgraf\vskip\blanklineskipamount \global\let\par = \endgraf}%
+ \@endjustifycmd %
+ % Get back into horizontal mode for the next line.
+ \noindent %
+ \@firstlinejustifyaction %
+ \fi %
+ }%
+\endgroup
+%
+\def\@endflushleft{\unpenalty{\parfillskip = 0pt plus1fil\par}\ignorespaces}%
+\def\@endflushright{% Remove the \hfil\null\break we just put on.
+ \unskip \setbox0=\lastbox \unpenalty
+ % We have fil glue at the left of the line; \parfillskip shouldn't
+ % affect that.
+ {\parfillskip = 0pt \par}\ignorespaces
+}%
+\def\@endcenter{% Remove the \hfil\null\break we just put on.
+ \unskip \setbox0=\lastbox \unpenalty
+ % We have fil glue at the left of the line; \parfillskip must balance it.
+ {\parfillskip = 0pt plus1fil \par}\ignorespaces
+}%
+%
+%
+%
+% Automatically-columnated tables.
+%
+% \makecolumns N/K: organizes the entries on the following N lines into
+% K columns. If N is too small, some text beyond the end of the table
+% will be incorporated into the table, probably producing an error
+% message. If N is too large, some of the entries will appear after the
+% table, probably looking very out of place.
+%
+% You can adjust the position of the table on the page by changing
+% \parindent (space to the left of the block) and \hsize (distance from
+% the left margin to the right of the block). (No doubt inside a
+% group.) And you can allow a page break above the valign by changing
+% \abovecolumnspenalty.
+%
+\newcount\abovecolumnspenalty \abovecolumnspenalty = 10000
+\newcount\@linestogo % Lines remaining to process.
+\newcount\@linestogoincolumn % Lines remaining in column.
+\newcount\@columndepth % Number of lines in a column.
+\newdimen\@columnwidth % Width of each column.
+\newtoks\crtok \crtok = {\cr}%
+\newcount\currentcolumn
+%
+% The space matches an end-of-line that will probably be there.
+%
+\def\makecolumns#1/#2: {\par \begingroup
+ % Set \@columndepth to the number of items we will put in a column:
+ % ceiling(N/K), i.e. (N - 1) / K + 1.
+ \@columndepth = #1
+ \advance\@columndepth by -1
+ \divide \@columndepth by #2
+ \advance\@columndepth by 1
+ \@linestogoincolumn = \@columndepth
+ \@linestogo = #1
+ %
+ % We start in the first column.
+ \currentcolumn = 1
+ %
+ \def\@endcolumnactions{%
+ \ifnum \@linestogo<2
+ \the\crtok \egroup \endgroup \par % End \valign and \makecolumns.
+ \else
+ % We've done one more line out of the total.
+ \global\advance\@linestogo by -1
+ %
+ % How many left in the column?
+ %
+ \ifnum\@linestogoincolumn<2
+ % End this column, that was the last line.
+ \global\advance\currentcolumn by 1
+ \global\@linestogoincolumn = \@columndepth
+ \the\crtok
+ \else
+ % Still got more lines to go.
+ &\global\advance\@linestogoincolumn by -1
+ \fi
+ \fi
+ }%
+ %
+ % Set up to read the table.
+ %
+ \makeactive\^^M
+ \letreturn \@endcolumnactions
+ %
+ % Figure out how wide our columns are going to be; each column has
+ % exactly the same template, so we can use the feature described on
+ % p.241 of the TeXbook for repeating preambles.
+ %
+ \@columnwidth = \hsize
+ \advance\@columnwidth by -\parindent
+ \divide\@columnwidth by #2
+ \penalty\abovecolumnspenalty
+ \noindent % It's not a paragraph (usually).
+ \valign\bgroup
+ &\hbox to \@columnwidth{\strut \hsize = \@columnwidth ##\hfil}\cr
+ %
+ % The next end-of-line starts everything going.
+}%
+%
+%
+%
+% \numberedfootnote is like plain TeX's \footnote, but automatically
+% numbered. When you want to reset the footnote number, say
+% \footnotenumber = 0.
+%
+% We also provide for more general formatting than \footnote:
+% \footnotemarkseparation is the space between the reference mark and
+% the footnote text;
+% \interfootnoteskip is the space between footnotes;
+% \everyfootnote is expanded just before we typeset the footnote.
+%
+% The dimensions of the footnote rule are controlled by
+% \footnoterulewidth and \footnoteruleheight (the depth is always zero);
+% the space after the rule is \belowfootnoterulespace.
+%
+\newcount\footnotenumber
+\newcount\hlfootlabelnumber
+\newdimen\footnotemarkseparation \footnotemarkseparation = .5em
+\newskip\interfootnoteskip \interfootnoteskip = 0pt
+\newtoks\everyfootnote
+\newdimen\footnoterulewidth \footnoterulewidth = 2in
+\newdimen\footnoteruleheight \footnoteruleheight = 0.4pt
+\newdimen\belowfootnoterulespace \belowfootnoterulespace = 2.6pt
+%
+\let\@plainfootnote = \footnote
+\let\@plainvfootnote = \vfootnote
+% Hyperlink labels for forward and back references.
+\def\hlfootlabel{FOOT\the\hlfootlabelnumber}%
+\def\hlfootbacklabel{FOOTB\the\hlfootlabelnumber}%
+%
+\def\@eplainfootnote#1{\let\@sf\empty % parameter #2 (the text) is read later
+ \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi
+ \global\advance\hlfootlabelnumber by 1
+ \hlstart@impl{foot}{\hlfootlabel}%
+ \hldest@impl{footback}{\hlfootbacklabel}%
+ #1%
+ \hlend@impl{foot}%
+ \@sf\vfootnote{#1}%
+}%
+%
+\let\footnote\@eplainfootnote
+%
+\def\vfootnote#1{\insert\footins\bgroup
+ \interlinepenalty\interfootnotelinepenalty
+ \splittopskip\ht\strutbox % top baseline for broken footnotes
+ \advance\splittopskip by \interfootnoteskip
+ \splitmaxdepth\dp\strutbox
+ \floatingpenalty\@MM
+ \leftskip\z@skip \rightskip\z@skip \spaceskip\z@skip \xspaceskip\z@skip
+ \everypar = {}%
+ \parskip = 0pt % because of the vskip
+ % Even if typesetting in multicolumns, do footnotes in normal page width.
+ % (We don't have any provision in the output routine for having
+ % footnotes per column, anyway.)
+ \ifnum\@numcolumns > 1 \hsize = \@normalhsize \fi
+ \the\everyfootnote
+ \vskip\interfootnoteskip
+ \indent\llap{%
+ \hlstart@impl{footback}{\hlfootbacklabel}%
+ \hldest@impl{foot}{\hlfootlabel}%
+ #1%
+ \hlend@impl{footback}%
+ \kern\footnotemarkseparation
+ }%
+ \footstrut\futurelet\next\fo@t
+}%
+%
+\def\footnoterule{\dimen@ = \footnoteruleheight
+ \advance\dimen@ by \belowfootnoterulespace
+ \kern-\dimen@
+ \hrule width\footnoterulewidth height\footnoteruleheight depth0pt
+ \kern\belowfootnoterulespace
+ \vskip-\interfootnoteskip
+}%
+%
+\def\numberedfootnote{%
+ \global\advance\footnotenumber by 1
+ \@eplainfootnote{$^{\number\footnotenumber}$}%
+}%
+%
+%
+%
+% Margins.
+%
+% TeX's primitives determine the type area. But some users prefer to
+% think in terms of margins. These definitions allow one to say, for
+% example, `\topmargin = 2in', instead of `\voffset=1in\advance\vsize by
+% -1in'. Constructions like `\advance\topmargin by 1in' give an error
+% message, though, since \topmargin is not a parameter. Instead, the
+% macro \advancetopmargin has to be used.
+%
+\newdimen\paperheight
+\ifnum\mag=1000
+ \paperheight = 11in % No magnification (yet).
+\else
+ \paperheight = 11truein % We already have a magnification.
+\fi
+%
+\def\topmargin{\afterassignment\@finishtopmargin \dimen@}%
+\def\@finishtopmargin{%
+ \dimen2 = \voffset % Remember the old \voffset.
+ \voffset = \dimen@ \advance\voffset by -1truein
+ \advance\dimen2 by -\voffset % Compute the change in \voffset.
+ \advance\vsize by \dimen2 % Change type area accordingly.
+}%
+\def\advancetopmargin{%
+ \dimen@ = 0pt \afterassignment\@finishadvancetopmargin \advance\dimen@
+}%
+\def\@finishadvancetopmargin{%
+ \advance\voffset by \dimen@
+ \advance\vsize by -\dimen@
+}%
+%
+%
+\def\bottommargin{\afterassignment\@finishbottommargin \dimen@}%
+\def\@finishbottommargin{%
+ \@computebottommargin % Result in \dimen2.
+ \advance\dimen2 by -\dimen@ % Compute the change in the bottom margin.
+ \advance\vsize by \dimen2 % Change the type area.
+}%
+\def\advancebottommargin{%
+ \dimen@ = 0pt \afterassignment\@finishadvancebottommargin \advance\dimen@
+}%
+\def\@finishadvancebottommargin{%
+ \advance\vsize by -\dimen@
+}%
+%
+% Find the current bottom margin, putting the result in \dimen2.
+%
+\def\@computebottommargin{%
+ \dimen2 = \paperheight % The total paper size.
+ \advance\dimen2 by -\vsize % Less the text size.
+ \advance\dimen2 by -\voffset % Less the offset at the top.
+ \advance\dimen2 by -1truein % Less the default offset.
+}%
+%
+%
+\newdimen\paperwidth
+\ifnum\mag=1000
+ \paperwidth = 8.5in % No magnification (yet).
+\else
+ \paperwidth = 8.5truein % We already have a magnification.
+\fi
+%
+\def\leftmargin{\afterassignment\@finishleftmargin \dimen@}%
+\def\@finishleftmargin{%
+ \dimen2 = \hoffset % Remember the old \hoffset.
+ \hoffset = \dimen@ \advance\hoffset by -1truein
+ \advance\dimen2 by -\hoffset % Compute the change in \hoffset.
+ \advance\hsize by \dimen2 % Change type area accordingly.
+}%
+\def\advanceleftmargin{%
+ \dimen@ = 0pt \afterassignment\@finishadvanceleftmargin \advance\dimen@
+}%
+\def\@finishadvanceleftmargin{%
+ \advance\hoffset by \dimen@
+ \advance\hsize by -\dimen@
+}%
+%
+%
+\def\rightmargin{\afterassignment\@finishrightmargin \dimen@}%
+\def\@finishrightmargin{%
+ \@computerightmargin % Result in \dimen2.
+ \advance\dimen2 by -\dimen@ % Compute the change in the right margin.
+ \advance\hsize by \dimen2 % Change the type area.
+}%
+\def\advancerightmargin{%
+ \dimen@ = 0pt \afterassignment\@finishadvancerightmargin \advance\dimen@
+}%
+\def\@finishadvancerightmargin{%
+ \advance\hsize by -\dimen@
+}%
+%
+% Find the current right margin, putting the result in \dimen2.
+%
+\def\@computerightmargin{%
+ \dimen2 = \paperwidth % The total paper size.
+ \advance\dimen2 by -\hsize % Less the text size.
+ \advance\dimen2 by -\hoffset % Less the offset at the left.
+ \advance\dimen2 by -1truein % Less the default offset.
+}%
+%
+% There is a potential problem when using the margin macros at a true
+% dimension and then calling \magnification. So we redefine
+% \magnification to address this.
+%
+\let\@plainm@g = \m@g
+\def\m@g{\@plainm@g \paperwidth = 8.5 true in \paperheight = 11 true in}%
+%
+%
+%
+% Double column output.
+%
+% \doublecolumns begins double column output. It can be called
+% in the midst of a page. \singlecolumn restores single column
+% output. (It would be wrong to require \enddoublecolumns, because
+% often one wants double column mode to continue to the end of
+% the document.)
+%
+% The basic approach is that of Appendix E of the TeXbook, p.417.
+% David Guichard made significant improvements to my original implementation.
+%
+% The glue here (the default is intended to be one linespace) is inserted
+% before double columns start, and after they end.
+%
+\newskip\abovecolumnskip \abovecolumnskip = \bigskipamount
+\newskip\belowcolumnskip \belowcolumnskip = \bigskipamount
+%
+% Space between the columns. It can be changed as desired.
+\newdimen\gutter \gutter = 2pc
+%
+% These registers are needed for dealing with switching back and forth.
+\newbox\@partialpage
+\newdimen\@normalhsize
+\newdimen\@normalvsize % The original (before multi-columns) \vsize.
+\newtoks\previousoutput
+%
+% Some synonymous ways to refer to multiple column modes.
+\def\quadcolumns{\@columns4}%
+\def\triplecolumns{\@columns3}%
+\def\doublecolumns{\@columns2}%
+\def\begincolumns#1{\ifcase#1\relax \or \singlecolumn \or \@columns2 \or
+ \@columns3 \or \@columns4 \else \relax \fi}%
+\def\endcolumns{\singlecolumn}%
+\let\@ndcolumns = \relax
+%
+% Set this by default so \vfootnote can unconditionally inspect it.
+\chardef\@numcolumns = 1
+%
+\mathchardef\@ejectpartialpenalty = 10141
+%
+%
+% \@columns: Start typesetting with #1 columns.
+%
+% Before we actually start, we have to make sure that there are at least
+\chardef\@col@minlines = 3
+% free lines.
+% (It could be 2, or even 1, but it might give ugly results; at least one
+% line is absolutely necessary, or the output routine might get confused.)
+% We have to be careful, so that eg.
+% \hbox{TITLE}
+% \nobreak
+% \doublecolumns
+% won't break between the title and the start of the columned output.
+%
+% To achieve this, we add vskip of fixed size equal to
+% @col@minlines * baselineskip
+% and then eject the page.
+% The output routine then catches the pages ejected:
+% 1) if it's a normal page, it is processed by previous output routine;
+% 2) if it's the last one, it is saved and the added skip is removed.
+%
+% When the box is processed according to 1), an underfull vbox can appear,
+% but it's not our problem, the manuscript (or it's macros) has to be fixed.
+%
+% Another note: all assignments are global; it is not possible to call
+% \doublecolumns in a group.
+%
+\def\@columns#1{%
+ \@ndcolumns
+ %
+ \global\let\@ndcolumns = \@endcolumns
+ \global\chardef\@numcolumns = #1
+ \global\previousoutput = \expandafter{\the\output}%
+ %
+ % Grab the page so far (i.e., the material BEFORE \@columns was called)
+ % and save it in \@partialpage.
+ \global\output = {%
+ \ifnum\outputpenalty = -\@ejectpartialpenalty
+ \dimen@ = \vsize
+ \advance\dimen@ by \@col@minlines\baselineskip
+ \global\setbox\@partialpage =
+ \vbox \ifdim \pagetotal > \vsize to \dimen@ \fi {%
+ \unvbox255 \unskip
+ }%
+ \else
+ \the\previousoutput
+ \fi
+ }%
+ %
+ \vskip \abovecolumnskip
+ \vskip \@col@minlines\baselineskip
+ % now execute the output routine:
+ \penalty -\@ejectpartialpenalty
+ %
+ % Reset \output to prepare for the first real page break.
+ \global\output = {\@columnoutput}%
+ %
+ \global\@normalhsize = \hsize
+ \global\@normalvsize = \vsize
+ %
+ % Figure out how wide the columns should be -- for n columns,
+ % decrement by n - 1 gutters.
+ \count@ = \@numcolumns
+ \advance\count@ by -1
+ \global\advance\hsize by -\count@\gutter
+ \global\divide\hsize by \@numcolumns
+ %
+ % Compute \vsize based on what's already on the page
+ % and the number of columns. Also change the mag factor for insertions.
+ %
+ \advance\vsize by -\ht\@partialpage
+ %
+ \advance\vsize by -\ht\footins
+ \ifvoid\footins\else \advance\vsize by -\skip\footins \fi
+ \multiply\count\footins by \@numcolumns
+ %
+ \advance\vsize by -\ht\topins
+ \ifvoid\topins\else \advance\vsize by -\skip\topins \fi
+ \multiply\count\topins by \@numcolumns
+ %
+ \global\vsize = \@numcolumns\vsize
+}%
+%
+% When this is invoked box 255 contains just the right amount of
+% material, whether triggered by an output routine or a change in the
+% number of columns. Because columns have to contain an integral number
+% of lines of type, we take a bit of care with balancing the heights of
+% the columns to prevent either losing material or having a very short
+% last column.
+%
+% When a page ends due to \bye or \eject, box 255 will contain lots of
+% white space, so the columns will not look balanced. To fix this use
+% \singlecolumn before ending the page.
+%
+% [gutterbox material added by AHL on 5 November 1997.]
+% \gutterbox is a hook to enable the placement of arbitrary vertical
+% material in the gutter between columns. For example, to put a
+% vertical line between the columns you could say
+%
+% \def\gutterbox{\vbox to \dimen0{\vfil\hbox{\vrule height\dimen0}\vfil}}%
+%
+% The dimension counter \dimen0 contains the height of the column.
+%
+% By default, we define \gutterbox to be "empty":
+\def\gutterbox{\vbox to \dimen0{\vfil\hbox{\hfil}\vfil}}%
+%
+% [This next paragraph added by AHL on 22 Sep 1996.]
+% There is a special case we have to worry about, namely when we
+% switch from multiple columns to single columns. In this case, we may
+% have a bit of text left over that doesn't fit evenly into the
+% multiple columns. In that case, we will have un-even columns. Not a
+% pretty solution, but I don't have a better one at the moment. The
+% conditional \if@forceextraline tests whether we are in this case.
+%
+\newif\if@forceextraline\@forceextralinefalse
+\def\@columnsplit{%
+ \splittopskip = \topskip
+ \splitmaxdepth = \baselineskip
+ %
+ % \dimen@ will be the height that the double-column material on this
+ % page should have, i.e., the height of the page (\singlecolumvsize)
+ % minus single-column material, which includes insertions. (If you
+ % want your insertions to respect the columns, you will have to
+ % change the output routine.) If you add more insertions, they
+ % should be taken into account both here and in \singlecolumn.
+ %
+ % Unfortunately, we lose on flexible glue because we must
+ % \vsplit to a <dimen>.
+ \dimen@ = \ht255
+ \divide\dimen@ by \@numcolumns
+ %
+ % If we are in an end-column mode and we need extra vertical space
+ % in the last column, advance \dimen@.
+ \if@forceextraline
+ \advance\dimen@ by \baselineskip
+ \fi
+ %
+ % Split the long scroll into columns.
+ \begingroup
+ % We do not want to see underfull \vbox messages unless the final
+ % page is underfull.
+ \vbadness = 10000
+ %
+ % The first (leftmost) column.
+ \global\setbox1 = \vsplit255 to \dimen@ \global\wd1 = \hsize
+ %
+ % The second column.
+ \global\setbox3 = \vsplit255 to \dimen@ \global\wd3 = \hsize
+ %
+ \ifnum\@numcolumns > 2
+ % The third column, if requested.
+ \global\setbox5 = \vsplit255 to \dimen@ \global\wd5 = \hsize
+ \fi
+ \ifnum\@numcolumns > 3
+ % The fourth column, likewise if requested.
+ \global\setbox7 = \vsplit255 to \dimen@ \global\wd7 = \hsize
+ \fi
+ \endgroup
+ \if@forceextraline % If this is the first time
+ \else % through, save the single
+ \setbox\@forcelinebox=\copy\@partialpage % column material.
+ \fi
+ %
+ % Set up \box255 with the real output page, as the previous output
+ % routine expects.
+ \setbox0 = \box255
+ \global\setbox255 = \vbox{%
+ \unvbox\@partialpage
+ \ifcase\@numcolumns \relax\or\relax
+ \or \hbox to \@normalhsize{\box1\hfil\gutterbox\hfil\box3}%
+ \or \hbox to \@normalhsize{\box1\hfil\gutterbox\hfil\box3%
+ \hfil\gutterbox\hfil\box5}%
+ \or \hbox to \@normalhsize{\box1\hfil\gutterbox\hfil\box3%
+ \hfil\gutterbox\hfil\box5%
+ \hfil\gutterbox\hfil\box7}%
+ \fi
+ }%
+ %
+ % Save what's left over in a private register before calling their
+ % output routine.
+ \setbox\@partialpage = \box0
+}%
+%
+% Our output routine splits the columns and then calls the previous one.
+%
+\def\@columnoutput{%
+ \@columnsplit
+ \@recoverclubpenalty
+ \hsize = \@normalhsize % Local to \output's group.
+ \vsize = \@normalvsize
+ \the\previousoutput
+ %
+ % Put back what didn't fit.
+ \unvbox\@partialpage
+ \penalty\outputpenalty
+ %
+ % The correct vsize is the original vsize times the
+ % number of columns.
+ \global\vsize = \@numcolumns\@normalvsize
+}%
+%
+% Go back to single-column typesetting. Assume \doublecolumns has
+% been called.
+%
+\def\singlecolumn{%
+ \@ndcolumns
+ \chardef\@numcolumns = 1
+ \vskip\belowcolumnskip
+ \nointerlineskip
+}%
+%
+\newbox\@forcelinebox
+\def\@endcolumns{%
+ \global\let\@ndcolumns = \relax
+ \par % Shouldn't start in horizontal mode.
+ %
+ \global\output = {\global\setbox1 = \box255}%
+ \pagegoal = \pagetotal
+ \break % Exercise the page builder, i.e., \output.
+ \setbox2 = \box1 % Save material in box2 in case of overflow.
+ \global\setbox255 = \copy2 % Retrieve what the fake \output set.
+ %
+ % \box255 now has the double-column material. On the page where we
+ % switch back to one column, the double-column material might not
+ % fill up the page. We want to split whatever is there.
+ \@columnsplit
+ %
+ % Check that \@columnsplit did not leave any lines in
+ % \@partialpage. If it did, do it again, but this time with longer
+ % columns.
+ \ifvoid\@partialpage
+ \else % There is some left-over.
+ \setbox0=\box\@partialpage % Merely to void \@partialpage
+ \global\setbox255 = \box2 % Retrieve what the fake \output set.
+ \@forceextralinetrue % Add \forcelinebox to \box255 to save single
+ \@columnsplit % column material.
+ \global\setbox255 = \vbox{\box\@forcelinebox\box255}%
+ \fi
+
+ \global\vsize = \@normalvsize
+ \global\hsize = \@normalhsize
+ \global\output = \expandafter{\the\previousoutput}%
+ %
+ \ifvoid\topins\else\topinsert\unvbox\topins\endinsert\fi
+ \unvbox255
+}%
+% [\columnfill]
+% We don't have any way to force a column eject, since the \output
+% routine is only prepared to split up a full page of material. Instead,
+% we provide the following as a guess at enough space to fill up the
+% current column.
+%
+% [April 30, 1998] This definition is from
+% Helmut Jarausch <jarausch@IGPM.Rwth-Aachen.DE> with some
+% modifications by A. Lewenberg <ahl@uakron.edu>.
+%
+% Here is the main difficulty: when \vsplitting the long page into the
+% component columns, \vsplit prepends to the top of each column glue
+% in the amount \topskip - (height of top box). But this happens
+% in the output routine _after_ the \columnfill does its
+% calculations. The result of this is that if we are not careful
+% \columnfill will insert too much space attempting to ``eject'' the
+% current column. There is no simple way around this, so what I have
+% done is have is make \columnfill insert less space than needed, and
+% then not allow any \club lines by setting \clubpenalty to its
+% maximum value. Not a pretty solution, but until something better
+% comes along, it will have to do.
+%
+\def\@saveclubpenalty{% save the current value of \clubpenalty
+ \edef\@recoverclubpenalty{%
+ \global\clubpenalty=\the\clubpenalty\relax%
+ \global\let\noexpand\@recoverclubpenalty\relax
+ }% the \noexpand handles infinite self-reference
+}%
+\let\@recoverclubpenalty\relax
+\newdimen\temp@dimen
+\def\columnfill{%
+ \par
+ \dimen@=\pagetotal % The height of the text set so far.
+ \temp@dimen = \vsize % = \@numcolumns * columnheight
+ \divide\temp@dimen by \@numcolumns % find out column height
+ \loop
+ \ifdim \dimen@ > \temp@dimen
+ \advance \dimen@ by -\temp@dimen
+ \advance \dimen@ by \topskip % fudge factor
+ \repeat
+ \advance \temp@dimen by -\dimen@
+ \advance \temp@dimen by -\prevdepth
+ \@saveclubpenalty
+ \clubpenalty=10000\relax
+ \hrule height\temp@dimen width0pt depth0pt\relax
+ \nointerlineskip
+ \par
+ \nointerlineskip
+ \penalty0\vfil % To allow a page break here.
+ \relax
+}%
+%
+%
+%
+% Hypertext links support.
+%
+% Hyperlink destinations (driver-independent code).
+%
+% \hldest{TYPE}{OPTIONS}{LABEL} defines a hyperlink destination
+% LABEL. OPTIONS is a comma-separated list of option assignments of
+% the form `opt=value'; permitted values for TYPE and OPTIONS depend
+% on selected hyperlink driver.
+%
+% \hldest will be \let to \@hldest by \enablehyperlinks. TYPE,
+% OPTIONS and LABEL will be read by \hl@getparam.
+\def\@hldest{%
+ \def\hl@prefix{hldest}%
+ \let\after@hl@getparam\hldest@aftergetparam
+ % Start the group which will isolate option settings. It will be
+ % ended in \hldest@aftergetparam
+ \begingroup
+ \hl@getparam
+}%
+% This actually produces hyperlink destination. It will be called at
+% the end of \hl@getparam, after the parameters are parsed.
+\def\hldest@aftergetparam{%
+ \ifvmode
+ % In vertical mode we don't raise the destination, so it can go
+ % directly into the vertical list.
+ \hldest@driver
+ \else
+ % In horizontal mode, the destination is raised \hldest@opt@raise
+ % above the baseline and placed inside a zero-width/height/depth
+ % box; the box is surrounded by \allowhyphens in case it is
+ % placed next to a word, to allow hyphenation of that word.
+ \allowhyphens
+ \smash{\ifx\hldest@opt@raise\empty \else \raise\hldest@opt@raise\fi
+ \hbox{\hldest@driver}}%
+ \allowhyphens
+ \fi
+ % End the group which was isolating option settings (it was started
+ % in \@hldest).
+ \endgroup
+}%
+%
+% Hyperlinks (driver-independent code).
+%
+% \hlstart{TYPE}{OPTIONS}{LABEL} starts a hyperlink to destination
+% LABEL. OPTIONS is a comma-separated list of option assignments of
+% the form `opt=value'; permitted values of TYPE and OPTIONS depend on
+% selected hyperlink driver. End the link with \hlend.
+%
+% \hlstart will be \let to \@hlstart by \enablehyperlinks. TYPE,
+% OPTIONS and LABEL will be read by \hl@getparam.
+\def\@hlstart{%
+ \leavevmode
+ \def\hl@prefix{hl}%
+ \let\after@hl@getparam\hlstart@aftergetparam
+ % Start the group which will isolate option settings and color
+ % changes. It will be ended in \@hlend
+ \begingroup
+ \hl@getparam
+}%
+%
+\def\hlstart@aftergetparam{%
+ % Set the color for the link.
+ \ifx\color\undefined \else
+ \ifx\hl@opt@color\empty \else
+ \ifx\hl@opt@colormodel\empty
+ \edef\temp{\noexpand\color{\hl@opt@color}}%
+ \else
+ \edef\temp{\noexpand\color[\hl@opt@colormodel]{\hl@opt@color}}%
+ \fi
+ \temp
+ \fi
+ \fi
+ % Call the driver.
+ \hl@driver
+}%
+% \hlend will be \let to \@hlend by \enablehyperlinks. \@hlend will
+% be defined by a driver.
+%
+% Macros which are used commonly by \hldest and \hlstart to parse and
+% save parameters. \hl@prefix must be set to `hldest' by \hldest and
+% to `hl' by \hlstart.
+%
+% \hl@getparam{TYPE}{OPTIONS}{LABEL} reads, parses and saves the
+% parameters for \hldest or \hlstart into \@hltype, \hl[dest]@opt@...
+% and \@hllabel. After doing that it calls \after@hl@getparam which
+% should be defined by \@hldest and \@hlstart to produce destination /
+% link using the saved parameters.
+\def\hl@getparam#1#2#3{%
+ % Save TYPE in \@hltype (use default if empty).
+ \edef\@hltype{#1}%
+ \ifx\@hltype\empty
+ \expandafter\let\expandafter\@hltype
+ \csname \hl@prefix @type\endcsname
+ \fi
+ % For each supported destination / link type TYPE, a driver should
+ % define \hl[dest]@typeh@TYPE handler.
+ \expandafter\ifx\csname \hl@prefix @typeh@\@hltype\endcsname \relax
+ \errmessage{Invalid type `\@hltype'}%
+ \fi
+ % \for will expand #2 once so user can pass a shortcut macro. We
+ % also ignore empty \hl@arg, so that the following
+ % \hldest{TYPE}{\myopt,height=200pt}{LABEL}
+ % would be legal even when \myopt happens to be empty.
+ \for\hl@arg:=#2\do{%
+ \ifx\hl@arg\empty \else
+ \expandafter\hl@set@opt\hl@arg=,%
+ \fi
+ }%
+ % Save LABEL in \@hllabel.
+ \edef\@hllabel{#3}%
+ % Execute the commands specific to destination / link
+ \after@hl@getparam
+ % Ignore spaces after \hlstart and \hldest.
+ \ignorespaces
+}%
+% Parse and set a (default, not a group) option.
+\def\hl@set@opt#1=#2,{%
+ % For each supported option OPTION, a driver should define
+ % \hl[dest]@opt@OPTION.
+ \expandafter\ifx\csname \hl@prefix @opt@#1\endcsname \relax
+ \errmessage{Invalid option `#1'}%
+ \fi
+ % Save the value of the option.
+ \if ,#2, % if #2 is empty, complain.
+ \errmessage{Missing value for option `#1'}%
+ \else
+ % Remove a trailing =.
+ \def\temp##1={##1}%
+ \expandafter\edef\csname \hl@prefix @opt@#1\endcsname{\temp#2}%
+ \fi
+}%
+% \hl{dest,start,end}@impl{GROUP}{LABEL} will generate `implicit' destination /
+% hyperlink, if the user has not turned off this kind of implicit
+% destinations / hyperlinks. This is used by Eplain's cross-reference
+% macros.
+\def\hldest@impl#1{%
+ \expandafter\ifcase\csname hldest@on@#1\endcsname
+ \relax\expandafter\gobble
+ \else
+ \toks@=\expandafter{\csname hldest@type@#1\endcsname}%
+ \toks@ii=\expandafter{\csname hldest@opts@#1\endcsname}%
+ \edef\temp{\noexpand\hldest{\the\toks@}{\the\toks@ii}}%
+ \expandafter\temp
+ \fi
+}%
+\def\hlstart@impl#1{%
+ \expandafter\ifcase\csname hl@on@#1\endcsname
+ % Still produce \leavevmode, to be consistent with \hloff.
+ \leavevmode\expandafter\gobble
+ \else
+ \toks@=\expandafter{\csname hl@type@#1\endcsname}%
+ \toks@ii=\expandafter{\csname hl@opts@#1\endcsname}%
+ \edef\temp{\noexpand\hlstart{\the\toks@}{\the\toks@ii}}%
+ \expandafter\temp
+ \fi
+}%
+\def\hlend@impl#1{%
+ \expandafter\ifcase\csname hl@on@#1\endcsname
+ \else
+ \hlend
+ \fi
+}%
+%
+% Setting options and types.
+%
+\def\hl@asterisk@word{*}%
+\def\hl@opts@word{opts}%
+\newif\if@params@override
+% We define hyperlink / destination groups. A group is a macro or a
+% group of macros which implicitly generate hyperlink / destination.
+% The user can set parameters for each group individually, as well as
+% the default parameters, with the macros defined below. Group
+% settings will override the default hyperlink / destination
+% parameters.
+\def\hldest@groups{definexref,xrdef,li,eq,bib,foot,footback,idx}%
+\def\hl@groups{ref,xref,eq,cite,foot,footback,idx,url}%
+% \hldesttype [GROUPS]{VALUE}
+% \hldestopts [GROUPS]{VALUE}
+% \hltype [GROUPS]{VALUE}
+% \hlopts [GROUPS]{VALUE}
+%
+% Set hyperlink or destination parameter (type / opts) to VALUE for
+% each group in GROUPS. An empty `group' will set default value for
+% the parameter. A star (*) `group' stands for all groups (exept the
+% empty `group'). If the macro is followed by an exclamation mark
+% (like \hlopts!...), the parameters will be overridden; otherwise,
+% they will be updated (this has effect only on group option list).
+\def\hldesttype{%
+ \def\hl@prefix{hldest}%
+ \def\hl@param{type}%
+ \let\hl@all@groups\hldest@groups
+ \futurelet\hl@excl\hl@param@read@excl
+}%
+\def\hldestopts{%
+ \def\hl@prefix{hldest}%
+ \def\hl@param{opts}%
+ \let\hl@all@groups\hldest@groups
+ \futurelet\hl@excl\hl@param@read@excl
+}%
+\def\hltype{%
+ \def\hl@prefix{hl}%
+ \def\hl@param{type}%
+ \let\hl@all@groups\hl@groups
+ \futurelet\hl@excl\hl@param@read@excl
+}%
+\def\hlopts{%
+ \def\hl@prefix{hl}%
+ \def\hl@param{opts}%
+ \let\hl@all@groups\hl@groups
+ \futurelet\hl@excl\hl@param@read@excl
+}%
+\def\hl@param@read@excl{%
+ \ifx!\hl@excl
+ \let\next\hl@param@read@opt@arg
+ \@params@overridetrue
+ \else
+ \def\next{\hl@param@read@opt@arg{!}}%
+ \@params@overridefalse
+ \fi
+ \next
+}%
+\def\hl@param@read@opt@arg#1{% #1 is the `!', ignore it.
+ \@getoptionalarg\hl@setparam
+}%
+% Set the parameter \hl@param to #1 for each group in \@optionalarg.
+\def\hl@setparam#1{%
+ \ifx\@optionalarg\empty
+ \hl@setparam@default{#1}% Set default.
+ \else
+ % If we find an asterisk in the list, we have no choice but to
+ % finish the list and then call \hl@setparam again, now with
+ % \hl@all@groups for the list of groups.
+ \let\hl@do@all@groups\gobble
+%
+ \for\hl@group:=\@optionalarg\do{%
+ \ifx\hl@group\hl@asterisk@word
+ \def\hl@do@all@groups{\let\@optionalarg\hl@all@groups \hl@setparam}%
+ \else
+ \hl@setparam@group{#1}%
+ \fi
+ }%
+%
+ \hl@do@all@groups{#1}%
+ \fi
+}%
+% Set a parameter (\hl@param) for one group (\hl@group) to the value
+% (#1). The group may be empty, in which case we call
+% \hl@setparam@default
+\def\hl@setparam@group#1{%
+ \ifx\hl@group\empty
+ \hl@setparam@default{#1}%
+ \else
+ \expandafter\ifx\csname\hl@prefix @\hl@param @\hl@group\endcsname\relax
+ \errmessage{Hyperlink group parameter `\hl@prefix:\hl@param:\hl@group' is not defined}%
+ \fi
+ \ifx\hl@param\hl@opts@word
+ % For the `opts' parameter, we want to expand the first token of
+ % #1 once, in case the user passed a macro containing the option
+ % list. We may need to either simply override the old option
+ % list, or to update it with the new option settings.
+ \if@params@override
+ \toks@=\expandafter{#1}%
+ \ece\edef{\hl@prefix @\hl@param @\hl@group}{\the\toks@}%
+ \else
+ \hl@update@opts@with@list{#1}% #1 will be used in the \for
+ % loop, so it will be expanded once.
+ \fi
+ \else
+ % Do not use \edef here to define the parameter, so the user can
+ % define it to, e.g., \normalbaselineskip, and make the parameter
+ % adjustable to a situation.
+ \ece\def{\hl@prefix @\hl@param @\hl@group}{#1}%
+ \fi
+ \fi
+}%
+% Set default parameter values. We have to treat `opts' (list of
+% options) specially, because for option defaults we don't store a
+% list of options (like we do for the group options) but set each
+% option individually.
+\def\hl@setparam@default#1{%
+ \ifx\hl@param\hl@opts@word
+ % `opts'.
+ \for\hl@opt:=#1\do{%
+ \ifx\hl@opt\empty \else
+ \expandafter\hl@set@opt\hl@opt=,%
+ \fi
+ }%
+ \else
+ % Everything except `opts'.
+ \expandafter\ifx\csname\hl@prefix @\hl@param\endcsname\relax
+ \message{Default parameter `\hl@prefix:\hl@param' is not defined}%
+ \fi
+ % Should not use \edef, so the user could define this to, e.g.,
+ % \normalbaselineskip, to make the parameter adjustable to a
+ % situation.
+ \ece\def{\hl@prefix @\hl@param}{#1}%
+ \fi
+}%
+% For each option in the list (#1), call \hl@update@with@opt to update
+% the group's option list (\csname\hl@prefix @opts@ \hl@group\endcsname)
+% with this new option.
+\def\hl@update@opts@with@list#1{%
+ % Start with the current list of the group.
+ \global\expandafter\let\expandafter\hl@update@new@list
+ \csname \hl@prefix @opts@\hl@group\endcsname
+ % We have to isolate the \for loop inside a (TeX) group, to avoid
+ % clashes with the loop in \hl@setparam
+ \begingroup
+ \for\hl@opt:=#1\do{%
+ \hl@update@opts@with@opt
+ }%
+ \endgroup
+ % Save the final list back in the option list for the group.
+ \ece\let{\hl@prefix @opts@\hl@group}\hl@update@new@list
+}%
+% Go through the option list (\hl@update@new@list) and construct the
+% new list (in \hl@update@new@list), replacing the old definition of
+% the option with the new one (\hl@opt).
+\def\hl@update@opts@with@opt{%
+ % Save the old list and the new option.
+ \global\let\hl@update@old@list\hl@update@new@list
+ \global\let\hl@update@new@list\empty
+ \global\let\hl@update@new@opt\hl@opt
+ % Get the key of the new option and save it.
+ \expandafter\hl@parse@opt@key\hl@opt=,%
+ \let\hl@update@new@key\hl@update@key
+ % We will set this to real comma after the first entry.
+ \global\let\hl@update@comma\empty
+ % We have to isolate the \for loop inside a (TeX) group, to avoid
+ % clashes with the loop in \hl@update@opts@with@list
+ \begingroup
+ \for\hl@opt:=\hl@update@old@list\do{%
+ \ifx\hl@opt\empty \else % Skip empty `options'.
+ % Get the key of this option.
+ \expandafter\hl@parse@opt@key\hl@opt=,%
+ % If the key matches, replace the option definition with the
+ % new definition, otherwise, repeat the old definition.
+ \toks@=\expandafter{\hl@update@new@list}%
+ \ifx\hl@update@key\hl@update@new@key
+ \ifx\hl@update@new@opt\empty \else % Skip multiple options.
+ \toks@ii=\expandafter{\hl@update@new@opt}%
+ \xdef\hl@update@new@list{\the\toks@\hl@update@comma\the\toks@ii}%
+ \global\let\hl@update@new@opt\empty
+ \global\def\hl@update@comma{,}%
+ \fi
+ \else
+ \toks@ii=\expandafter{\hl@opt}%
+ \xdef\hl@update@new@list{\the\toks@\hl@update@comma\the\toks@ii}%
+ \global\def\hl@update@comma{,}%
+ \fi
+ \fi
+ }%
+ \endgroup
+ % If nothing was replaced, add the new option to the end of the new list.
+ \ifx\hl@update@new@opt\empty \else
+ \toks@=\expandafter{\hl@update@new@list}%
+ \toks@ii=\expandafter{\hl@update@new@opt}%
+ \xdef\hl@update@new@list{\the\toks@\hl@update@comma\the\toks@ii}%
+ \fi
+}%
+% Parse the key of the option and save it in \hl@update@key
+\def\hl@parse@opt@key#1=#2,{\def\hl@update@key{#1}}%
+%
+% Default and group parameters (options and types).
+%
+% Option `raise' will determine how much to raise hyperlink
+% destinations above the baseline. It will be supported by all
+% drivers, since it is handled outside the drivers, in
+% \hldest@aftergetparam.
+\def\hldest@opt@raise{\normalbaselineskip}%
+% Options `colormodel' and `color' will also be handled outside the
+% drivers, in \hlstart@aftergetparam.
+\def\hl@opt@colormodel{cmyk}%
+\def\hl@opt@color{0.28,1,1,0.35}%
+%
+% Parameters for destinations and links produced implicitly by
+% cross-reference macros. Note that each driver will additionally
+% define \hldest@type and \hl@type parameters which will be used when
+% one of the below is empty, and default values for destination and
+% link options (which are driver-specific).
+%
+% Destination on/off flags (0=off, 1=on).
+\def\hldest@on@definexref{0}%
+\def\hldest@on@xrdef{0}%
+\def\hldest@on@li{0}%
+\def\hldest@on@eq{0}% \eqdef and friends
+\def\hldest@on@bib{0}% \biblabelprint (BibTeX)
+\def\hldest@on@foot{0}% \footnote / \numberedfootnote
+\def\hldest@on@footback{0}% back-ref for \footnote / \numberedfootnote
+\def\hldest@on@idx{0}% both `page' dests and `exact' dests
+% Types of destinations.
+\let\hldest@type@definexref\empty
+\let\hldest@type@xrdef\empty
+\let\hldest@type@li\empty
+\let\hldest@type@eq\empty % \eqdef and friends
+\let\hldest@type@bib\empty % \biblabelprint (BibTeX)
+\let\hldest@type@foot\empty % \footnote / \numberedfootnote
+\let\hldest@type@footback\empty % back-ref for \footnote / \numberedfootnote
+\let\hldest@type@idx\empty % both `page' dests and `exact' dests
+% Options for destinations.
+\let\hldest@opts@definexref\empty
+\let\hldest@opts@xrdef\empty
+\let\hldest@opts@li\empty
+\def\hldest@opts@eq{raise=1.7\normalbaselineskip}% \eqdef and friends
+\let\hldest@opts@bib\empty % \biblabelprint (BibTeX)
+\let\hldest@opts@foot\empty % \footnote / \numberedfootnote
+\let\hldest@opts@footback\empty % back-ref for \footnote / \numberedfootnote
+\let\hldest@opts@idx\empty % both `page' dests and `exact' dests
+%
+% Hyperlink on/off flags (0=off, 1=on).
+\def\hl@on@ref{0}% \refn and \xrefn, \ref, \refs
+\def\hl@on@xref{0}%
+\def\hl@on@eq{0}% \eqref and \eqrefn
+\def\hl@on@cite{0}% \cite (BibTeX)
+\def\hl@on@foot{0}% \footnote / \numberedfootnote
+\def\hl@on@footback{0}% back-reference for \footnote / \numberedfootnote
+\def\hl@on@idx{0}%
+\def\hl@on@url{0}% \url from url.sty
+% Types of links.
+\let\hl@type@ref\empty % \refn and \xrefn, \ref, \refs
+\let\hl@type@xref\empty
+\let\hl@type@eq\empty % \eqref and \eqrefn
+\let\hl@type@cite\empty % \cite (BibTeX)
+\let\hl@type@foot\empty % \footnote / \numberedfootnote
+\let\hl@type@footback\empty % back-reference for \footnote / \numberedfootnote
+\let\hl@type@idx\empty
+\let\hl@type@url\empty % \url from url.sty (this will be set to `url' by
+ % drivers which support the `url' type)
+% Options for links.
+\let\hl@opts@ref\empty % \refn and \xrefn, \ref, \refs
+\let\hl@opts@xref\empty
+\let\hl@opts@eq\empty % \eqref and \eqrefn
+\let\hl@opts@cite\empty % \cite (BibTeX)
+\let\hl@opts@foot\empty % \footnote / \numberedfootnote
+\let\hl@opts@footback\empty % back-reference for \footnote / \numberedfootnote
+\let\hl@opts@idx\empty
+\let\hl@opts@url\empty % \url from url.sty
+%
+% \@hlon[GROUPS]
+% \@hloff[GROUPS]
+% \@hldeston[GROUPS]
+% \@hldestoff[GROUPS]
+% \@@hlon
+% \@@hloff
+% \@@hldeston
+% \@@hldestoff
+%
+% Macros to switch hyperlinks / destinations on/off.
+%
+% The optional arg is the list of groups. It can contain a star (*)
+% which will make the macros affect all groups (but not the low-level
+% macros \hlstart, \hlend and \hldest).
+%
+% \@hlon, \@hldeston, \@hloff and \@hldestoff will turn low-level
+% macros on/off only when they are used either without the optional
+% arg or with an empty `group' in the optional arg, otherwise only the
+% specified groups are affected.
+%
+% The single-`@' variants (\@hl...) are for the user. In your macros,
+% if you want to (temporarily) turn low-level macros on/off, it's
+% better to use the double-`@' variants (\@@hl...), because they are
+% much faster and won't clobber \@optionalarg or anything else.
+%
+\def\@hlon{\@hlonoff@value@stub{hl}\@@hlon1 }%
+\def\@hloff{\@hlonoff@value@stub{hl}\@@hloff0 }%
+\def\@hldeston{\@hlonoff@value@stub{hldest}\@@hldeston1 }%
+\def\@hldestoff{\@hlonoff@value@stub{hldest}\@@hldestoff0 }%
+%
+\def\@hlonoff@value@stub#1#2#3{%
+ \def\hl@prefix{#1}%
+ \let\hl@on@empty#2%
+ \def\hl@value{#3}%
+ \expandafter\let\expandafter\hl@all@groups
+ \csname \hl@prefix @groups\endcsname
+ \@getoptionalarg\@finhlswitch
+}%
+%
+\def\@finhlswitch{%
+ \ifx\@optionalarg\empty
+ \hl@on@empty
+ \fi
+ % If we find an asterisk in the list, we have no choice but to
+ % finish the list and then call \@finhlswitch again, now with
+ % \hl@all@groups for the list of groups.
+ \let\hl@do@all@groups\relax
+%
+ \for\hl@group:=\@optionalarg\do{%
+ \ifx\hl@group\hl@asterisk@word
+ \let\@optionalarg\hl@all@groups
+ \let\hl@do@all@groups\@finhlswitch
+ \else
+ \ifx\hl@group\empty
+ \hl@on@empty
+ \else
+ \expandafter\ifx\csname\hl@prefix @on@\hl@group\endcsname \relax
+ \errmessage{Hyperlink group `\hl@prefix:on:\hl@group'
+ is not defined}%
+ \fi
+ \ece\edef{\hl@prefix @on@\hl@group}{\hl@value}%
+ \fi
+ \fi
+ }%
+%
+ \hl@do@all@groups
+}%
+% Turn low-level macros on/off.
+\def\@@hlon{%
+ \let\hlstart\@hlstart
+ \let\hlend\@hlend
+}%
+\def\@@hloff{%
+ \def\hlstart##1##2##3{\leavevmode\ignorespaces}%
+ \let\hlend\relax
+}%
+\def\@@hldeston{%
+ \let\hldest\@hldest
+}%
+\def\@@hldestoff{%
+ \def\hldest##1##2##3{\ignorespaces}%
+}%
+%
+% Hyperlink drivers.
+%
+% \enablehyperlinks[OPTIONS] will enable hyperlinks. OPTIONS is a
+% list of comma-separated options. An option is one of the following:
+%
+% idxexact Point index links to exact locations of the term
+% idxpage Point index links to pages with the term (default)
+% idxnone No links for index entries
+% <driver-name> Force the hyperlink driver
+%
+% If <driver-name> is omitted, appropriate driver will be detected, if
+% possible; if not, we fall back on `dvipdfm' (currently this means
+% `pdftex' when \ifpdf, and `dvipdfm' otherwise).
+\def\hl@idxexact@word{idxexact}%
+\def\hl@idxpage@word{idxpage}%
+\def\hl@idxnone@word{idxnone}%
+%
+\def\enablehyperlinks{\@getoptionalarg\@finenablehyperlinks}%
+\def\@finenablehyperlinks{%
+ \let\hl@selecteddriver\empty
+ % By default we generate `idxpage' index hyperlinks.
+ \def\hldest@place@idx{0}%
+ % Go through the option list.
+ \for\hl@arg:=\@optionalarg\do{%
+ \ifx\hl@arg\hl@idxexact@word
+ \def\hldest@place@idx{1}%
+ \else
+ \ifx\hl@arg\hl@idxnone@word
+ \def\hldest@place@idx{-1}%
+ \else
+ \ifx\hl@arg\hl@idxpage@word
+ \def\hldest@place@idx{0}%
+ \else
+ \let\hl@selecteddriver\hl@arg
+ \fi
+ \fi
+ \fi
+ }%
+ % Check the driver name.
+ \ifx\hl@selecteddriver\empty
+ % The user did not specify a driver, detect.
+ \ifpdf
+ \def\hl@selecteddriver{pdftex}%
+ \message{^^JUsing `pdftex' hyperlink driver.}%
+ \else
+ \def\hl@selecteddriver{dvipdfm}%
+ \message{^^JUsing `dvipdfm' hyperlink driver.}%
+ \fi
+ \else
+ % Check that the requested driver's initialization routine is
+ % available.
+ \expandafter\ifx\csname hldriver@\hl@selecteddriver\endcsname \relax
+ \errmessage{No hyperlink driver `\hl@selecteddriver' available}%
+ \fi
+ \fi
+ % Call the driver's initialization routine.
+ \csname hldriver@\hl@selecteddriver\endcsname
+ % Driver should not be changed later.
+ \def\@finenablehyperlinks{\errmessage{Hyperlink driver `\hl@selecteddriver'
+ already selected}}%
+ % Free memory taken up by the drivers.
+ \let\hldriver@nolinks\undefined
+ \let\hldriver@pdftex \undefined
+ \let\hldriver@dvipdfm\undefined
+ % The user can use these to turn the links / destinations on/off
+ % (see comments to the driver `nolinks').
+ \let\hloff\@hloff
+ \let\hlon\@hlon
+ \let\hldestoff\@hldestoff
+ \let\hldeston\@hldeston
+ % Turn everything on by default.
+ \hlon[*,]%
+ \hldeston[*,]%
+}%
+%
+% Driver `nolinks'.
+%
+% Select this driver to suppress any hyperlinks / destinations in your
+% document.
+%
+% NOTE: selecting this driver is quite different from not selecting
+% any driver at all, or from selecting some driver and then turning
+% off links and destinations for the entire document with \hloff and
+% \hldestoff.
+%
+% The purpose of \hldestoff and \hloff is to mark (parts) of document
+% where links should never appear. (Imagine you want to prevent a
+% cross-referencing macro from generating a link at a certain spot in
+% your document.)
+%
+% If instead you have prepared a document with links and just want to
+% compile a version without the links, it is better to select the
+% driver `nolinks'. This will ensure that spacing and pagebreaking
+% will be the same as what you were getting with hyperlinks enabled.
+%
+% The reason for this is that hyperlinks are produced by \special
+% commands. Each \special is placed inside a whatsit which may
+% introduce a legitimate breakpoint at places where none would exist
+% without the whatsit. The macros \hldestoff and \hloff disable
+% hyperlink macros so drastically that no whatsits are produced.
+%
+% On the other hand, `nolinks' driver does not completely disable
+% hyperlink macros. Instead, it defines them to write to the log
+% file (what gets written is not really important). This will produce
+% the whatsits imitating the whatsits from the \special's. (This
+% trick was borrowed from graphics bundle.)
+%
+% Another reason for using `nolinks' is that in horizontal mode
+% \hldest places destinations inside zero-width/height/depth boxes.
+% When you say \hldestoff, \hldest will omit both destination specs
+% and these boxes. The missing boxes can cause typesetting to be
+% inconsistent with what you were getting with destinations enabled.
+% Again, `nolinks' driver helps here by defining \hldest to still
+% produce the empty boxes.
+%
+\def\hldriver@nolinks{%
+ \def\@hldest##1##2##3{%
+ \ifvmode
+ \write-1{\string\hldest: ##3}%
+ \else
+ \allowhyphens
+ \smash{\write-1{\string\hldest: ##3}}%
+ \allowhyphens
+ \fi
+ \ignorespaces
+ }%
+ \def\@hlstart##1##2##3{%
+ \leavevmode
+ \begingroup % Start the color group.
+ \write-1{\string\hlstart: ##3}%
+ \ignorespaces
+ }%
+ \def\@hlend{\write-1{\string\hlend}\endgroup}% End the group from \@hlstart.
+}%
+%
+% Driver `pdftex'.
+%
+\def\hldriver@pdftex{%
+\ifpdf % PDF output is enabled.
+ \def\hl@raw@word{raw}%
+ %
+ % Hyperlink destinations.
+ %
+ % Default type.
+ \def\hldest@type{xyz}%
+ % Set defaults for the options and tell \hl@set@opt what options we
+ % support. (We do not define \hldest@opt@raise, \hl@opt@colormodel
+ % and \hl@opt@color, they are defined and used outside the drivers.)
+ \let\hldest@opt@width \empty
+ \let\hldest@opt@height \empty
+ \let\hldest@opt@depth \empty
+ \let\hldest@opt@zoom \empty
+ \let\hldest@opt@cmd \empty
+ % Multiplexer for all supported destination types.
+ \def\hldest@driver{%
+ % Special case for `raw' destinations.
+ \ifx\@hltype\hl@raw@word
+ \csname \hldest@opt@cmd \endcsname
+ \else
+ \pdfdest name{\@hllabel}\@hltype
+ \csname hldest@typeh@\@hltype\endcsname
+ \fi
+ }%
+ % Define handlers for each supported destination type.
+ \let\hldest@typeh@raw \empty
+ \let\hldest@typeh@fit \empty
+ \let\hldest@typeh@fith \empty
+ \let\hldest@typeh@fitv \empty
+ \let\hldest@typeh@fitb \empty
+ \let\hldest@typeh@fitbh \empty
+ \let\hldest@typeh@fitbv \empty
+ \def\hldest@typeh@fitr{%
+ \ifx\hldest@opt@width \empty \else width \hldest@opt@width \fi
+ \ifx\hldest@opt@height \empty \else height \hldest@opt@height \fi
+ \ifx\hldest@opt@depth \empty \else depth \hldest@opt@depth \fi
+ }%
+ \def\hldest@typeh@xyz{%
+ \ifx\hldest@opt@zoom\empty \else zoom \hldest@opt@zoom \fi
+ }%
+ %
+ % Hyperlinks.
+ %
+ % Default type.
+ \def\hl@type{name}%
+ % We support `url' hyperlinks, so set the `url' group type.
+ \ifx\hl@type@url\empty
+ \def\hl@type@url{url}%
+ \fi
+ % Set defaults for the options and tell \hl@set@opt what options we
+ % support.
+ \let\hl@opt@width \empty
+ \let\hl@opt@height \empty
+ \let\hl@opt@depth \empty
+ \def\hl@opt@bstyle {S}%
+ \def\hl@opt@bwidth {1}%
+ \let\hl@opt@bcolor \empty
+ \let\hl@opt@hlight \empty
+ \let\hl@opt@bdash \empty
+ \let\hl@opt@pagefit \empty
+ \let\hl@opt@cmd \empty
+ \let\hl@opt@file \empty
+ \let\hl@opt@newwin \empty
+ % Multiplexer for all supported link types.
+ \def\hl@driver{%
+ % Special case for `raw' links.
+ \ifx\@hltype\hl@raw@word
+ \csname \hl@opt@cmd \endcsname
+ \else
+ % See if we will construct a /BS spec. We want to bother only
+ % if any of \hl@opt@bstyle, \hl@opt@bwidth and \hl@opt@bdash is
+ % not empty.
+ \let\hl@BSspec\relax % construct
+ \ifx\hl@opt@bstyle \empty
+ \ifx\hl@opt@bwidth \empty
+ \ifx\hl@opt@bdash \empty
+ \let\hl@BSspec\empty % don't construct
+ \fi
+ \fi
+ \fi
+ % Construct common preamble of a link.
+ \def\hlstart@preamble{%
+ \pdfstartlink
+ \ifx\hl@opt@width \empty \else width \hl@opt@width \fi
+ \ifx\hl@opt@height \empty \else height \hl@opt@height \fi
+ \ifx\hl@opt@depth \empty \else depth \hl@opt@depth \fi
+ attr{%
+ \ifx\hl@opt@bcolor\empty\else /C[\hl@opt@bcolor]\fi
+ \ifx\hl@opt@hlight\empty\else /H/\hl@opt@hlight\fi
+ \ifx\hl@BSspec\relax
+ /BS<<%
+ /Type/Border%
+ \ifx\hl@opt@bstyle\empty\else /S/\hl@opt@bstyle\fi
+ \ifx\hl@opt@bwidth\empty\else /W \hl@opt@bwidth\fi
+ \ifx\hl@opt@bdash\empty \else /D[\hl@opt@bdash]\fi
+ >>%
+ \fi
+ }%
+ }%
+ % Call the handler.
+ \csname hl@typeh@\@hltype\endcsname
+ \fi
+ }%
+ % Link type handlers
+ \let\hl@typeh@raw\empty
+ \def\hl@typeh@name{\hlstart@preamble goto name{\@hllabel}}%
+ \def\hl@typeh@num{\hlstart@preamble goto num \@hllabel}%
+ \def\hl@typeh@page{%
+ % PDF requires pages to start from 0, so adjust page number.
+ \count@=\@hllabel
+ \advance\count@ by-1
+ %
+ \hlstart@preamble
+ user{%
+ /Subtype/Link%
+ /Dest%
+ [\the\count@
+ \ifx\hl@opt@pagefit\empty/Fit\else\hl@opt@pagefit\fi]%
+ }%
+ }%
+ \def\hl@typeh@filename{\hl@file{(\@hllabel)}}%
+ \def\hl@typeh@filepage{%
+ % PDF requires pages to start from 0, so adjust page number.
+ \count@=\@hllabel
+ \advance\count@ by-1
+ %
+ \hl@file{%
+ [\the\count@ \ifx\hl@opt@pagefit\empty/Fit\else\hl@opt@pagefit\fi]%
+ }%
+ }%
+ \def\hl@file##1{%
+ \hlstart@preamble
+ user{%
+ /Subtype/Link%
+ /A<<%
+ /Type/Action%
+ /S/GoToR%
+ /D##1%
+ /F(\hl@opt@file)%
+ \ifx\hl@opt@newwin\empty \else
+ /NewWindow \ifcase\hl@opt@newwin false\else true\fi
+ \fi
+ >>%
+ }%
+ }%
+ \def\hl@typeh@url{%
+ \hlstart@preamble
+ user{%
+ /Subtype/Link%
+ /A<<%
+ /Type/Action
+ /S/URI%
+ /URI(\@hllabel)%
+ >>%
+ }%
+ }%
+ %
+ \def\@hlend{\pdfendlink\endgroup}% End the group from the \@hlstart.
+%
+\else % PDF output is not enabled.
+ \message{Warning: `pdftex' hyperlink driver: PDF output is
+ not enabled, falling back on `nolinks' driver.}%
+ \hldriver@nolinks
+\fi
+}%
+%
+% Driver `dvipdfm'.
+%
+\def\hldriver@dvipdfm{%
+ \def\hl@raw@word{raw}%
+ %
+ % Hyperlink destinations.
+ %
+ % Default type.
+ \def\hldest@type{xyz}%
+ % Set defaults for the options and tell \hl@set@opt what options we
+ % support. (We do not define \hldest@opt@raise, \hl@opt@colormodel
+ % and \hl@opt@color, they are defined and used outside the drivers.)
+ \let\hldest@opt@left \empty
+ \let\hldest@opt@top \empty
+ \let\hldest@opt@right \empty
+ \let\hldest@opt@bottom \empty
+ \let\hldest@opt@zoom \empty
+ \let\hldest@opt@cmd \empty
+ % Multiplexer for all supported destination types.
+ \def\hldest@driver{%
+ % Special case for `raw' destinations.
+ \ifx\@hltype\hl@raw@word
+ \csname \hldest@opt@cmd \endcsname
+ \else
+ % Construct common preamble of a destination.
+ \def\hldest@preamble{%
+ pdf: dest (\@hllabel) [@thispage
+ }%
+ % Call the handler.
+ \csname hldest@typeh@\@hltype\endcsname
+ \fi
+ }%
+ % Define handlers for each supported destination type.
+ \let\hldest@typeh@raw\empty
+ \def\hldest@typeh@fit{%
+ \special{\hldest@preamble /Fit]}%
+ }%
+ \def\hldest@typeh@fith{%
+ \special{\hldest@preamble /FitH
+ \ifx\hldest@opt@top\empty @ypos \else \hldest@opt@top \fi]}%
+ }%
+ \def\hldest@typeh@fitv{%
+ \special{\hldest@preamble /FitV
+ \ifx\hldest@opt@left\empty @xpos \else \hldest@opt@left \fi]}%
+ }%
+ \def\hldest@typeh@fitb{%
+ \special{\hldest@preamble /FitB]}%
+ }%
+ \def\hldest@typeh@fitbh{%
+ \special{\hldest@preamble /FitBH
+ \ifx\hldest@opt@top\empty @ypos \else \hldest@opt@top \fi]}%
+ }%
+ \def\hldest@typeh@fitbv{%
+ \special{\hldest@preamble /FitBV
+ \ifx\hldest@opt@left\empty @xpos \else \hldest@opt@left \fi]}%
+ }%
+ \def\hldest@typeh@fitr{%
+ \special{\hldest@preamble /FitR
+ \ifx\hldest@opt@left\empty @xpos\else\hldest@opt@left\fi\space
+ \ifx\hldest@opt@bottom\empty @ypos\else\hldest@opt@bottom\fi\space
+ \ifx\hldest@opt@right\empty @xpos\else\hldest@opt@right\fi\space
+ \ifx\hldest@opt@top\empty @ypos\else\hldest@opt@top \fi]}%
+ }%
+ \def\hldest@typeh@xyz{%
+ \begingroup
+ % Convert zoom factor: 12345 -> 12.345
+ \ifx\hldest@opt@zoom\empty
+ \count1=\z@ \count2=\z@
+ \else
+ \count2=\hldest@opt@zoom
+ \count1=\count2 \divide\count1 by 1000
+ \count3=\count1 \multiply\count3 by 1000
+ \advance\count2 by -\count3
+ \fi
+ \special{\hldest@preamble /XYZ
+ \ifx\hldest@opt@left\empty @xpos\else\hldest@opt@left\fi\space
+ \ifx\hldest@opt@top\empty @ypos\else\hldest@opt@top\fi\space
+ \the\count1.\the\count2]}%
+ \endgroup
+ }%
+ %
+ % Hyperlinks.
+ %
+ % Default type.
+ \def\hl@type{name}%
+ % We support `url' hyperlinks, so set `url' group type.
+ \ifx\hl@type@url\empty
+ \def\hl@type@url{url}%
+ \fi
+ % Set defaults for the options and tell \hl@set@opt what options we
+ % support.
+ \def\hl@opt@bstyle {S}%
+ \def\hl@opt@bwidth {1}%
+ \let\hl@opt@bcolor \empty
+ \let\hl@opt@hlight \empty
+ \let\hl@opt@bdash \empty
+ \let\hl@opt@pagefit \empty
+ \let\hl@opt@cmd \empty
+ \let\hl@opt@file \empty
+ \let\hl@opt@newwin \empty
+ % Multiplexer for all supported link types.
+ \def\hl@driver{%
+ % Special case for `raw' links.
+ \ifx\@hltype\hl@raw@word
+ \csname \hl@opt@cmd \endcsname
+ \else
+ % See if we will construct a /BS spec. We want to bother only
+ % if any of \hl@opt@bstyle, \hl@opt@bwidth and \hl@opt@bdash is
+ % not empty.
+ \let\hl@BSspec\relax % construct
+ \ifx\hl@opt@bstyle \empty
+ \ifx\hl@opt@bwidth \empty
+ \ifx\hl@opt@bdash \empty
+ \let\hl@BSspec\empty % don't construct
+ \fi
+ \fi
+ \fi
+ % Construct common preamble of a link.
+ \def\hlstart@preamble{%
+ pdf: beginann
+ <<%
+ /Type/Annot%
+ /Subtype/Link%
+ \ifx\hl@opt@bcolor\empty\else /C[\hl@opt@bcolor]\fi
+ \ifx\hl@opt@hlight\empty\else /H/\hl@opt@hlight\fi
+ \ifx\hl@BSspec\relax
+ /BS<<%
+ /Type/Border%
+ \ifx\hl@opt@bstyle\empty\else /S/\hl@opt@bstyle\fi
+ \ifx\hl@opt@bwidth\empty\else /W \hl@opt@bwidth\fi
+ \ifx\hl@opt@bdash\empty \else /D[\hl@opt@bdash]\fi
+ >>%
+ \fi
+ }%
+ % Call the handler.
+ \csname hl@typeh@\@hltype\endcsname
+ \fi
+ }%
+ % Link type handlers.
+ \let\hl@typeh@raw\empty
+ \def\hl@typeh@name{\special{\hlstart@preamble /Dest(\@hllabel)>>}}%
+ \def\hl@typeh@page{%
+ % PDF requires pages to start from 0, so adjust page number.
+ \count@=\@hllabel
+ \advance\count@ by-1
+ %
+ \special{%
+ \hlstart@preamble
+ /Dest[\the\count@
+ \ifx\hl@opt@pagefit\empty/Fit\else\hl@opt@pagefit\fi]%
+ >>%
+ }%
+ }%
+ \def\hl@typeh@filename{\hl@file{(\@hllabel)}}%
+ \def\hl@typeh@filepage{%
+ % PDF requires pages to start from 0, so adjust page number.
+ \count@=\@hllabel
+ \advance\count@ by-1
+ %
+ \hl@file{%
+ [\the\count@ \ifx\hl@opt@pagefit\empty/Fit\else\hl@opt@pagefit\fi]%
+ }%
+ }%
+ \def\hl@file##1{%
+ \special{%
+ \hlstart@preamble
+ /A<<%
+ /Type/Action%
+ /S/GoToR%
+ /D##1%
+ /F(\hl@opt@file)%
+ \ifx\hl@opt@newwin\empty \else
+ /NewWindow \ifcase\hl@opt@newwin false\else true\fi
+ \fi
+ >>%
+ >>%
+ }%
+ }%
+ \def\hl@typeh@url{%
+ \special{%
+ \hlstart@preamble
+ /A<<%
+ /Type/Action
+ /S/URI%
+ /URI(\@hllabel)%
+ >>%
+ >>%
+ }%
+ }%
+ %
+ \def\@hlend{\special{pdf: endann}\endgroup}% End the group from \@hlstart.
+}%
+%
+% Internal hyperlink macros.
+%
+% \hl@define@eqlabel{LABEL} will define \hl@eqlabel to a non-empty
+% hyperlink label for an equation. The idea is to generate
+% (hopefully) unique label in cases when LABEL is empty (e.g., when
+% user says `\eqdef{}'). To customize the autogenerated labels
+% redefine \phantomeqlabel.
+%
+\newcount\phantomeqnumber
+\def\phantomeqlabel{PHEQ\the\phantomeqnumber}%
+%
+\def\hl@define@eqlabel#1{%
+ % Make all definitions global so they are not shadowed by groups
+ % (\@eqdef depends on this).
+ \ifempty{#1}%
+ \global\advance\phantomeqnumber by1
+ \xdef\hl@eqlabel{\phantomeqlabel}%
+ \else
+ \gdef\hl@eqlabel{#1}%
+ \fi
+}%
+%
+% Cross-reference macros call hyperlink macros, so define them to
+% produce nothing by default. However, we still want \hldest and
+% \hlstart to produce \leavevmode and/or \ignorespaces, to make
+% cross-reference macros consistent. Note that this, strictly
+% speaking, makes cross-reference macros incompatible with
+% pre-hyperlink releases of eplain, in cases where paragraph is
+% started by a cross-reference macro. It is quite unlikely though
+% that any problem will arise.
+\let\hldeston\relax \let\hldestoff\relax
+\let\hlon\relax \let\hloff\relax
+\@@hloff
+\@@hldestoff
+%
+%
+%
+% Support for LaTeX packages under plain TeX.
+%
+% We use miniltx.tex from the LaTeX graphics collection and build on
+% it to provide package options support, package version check,
+% recursive package loading with \RequirePackage, proper handling of
+% \AtBeginDocument and \AtEndOfPackage.
+%
+% Much of the following was borrowed from LaTeX.
+%
+% The internal variables are quite a mess, so here is a hint:
+%
+% - \usepkg@pkg, \usepkg@options, \usepkg@date are used by
+% \usepackage to save its parameters.
+%
+% - When \RequirePackage is called within a package, the above
+% variables are saved in \usepkg@save@VAR@RECURSIONLEVEL, where
+% VAR={pkg,options,date}, and RECURSIONLEVEL is incremented for
+% each nested package inclusion. This way the variables can be
+% restored after the (nested) package will have been loaded.
+%
+% - Options for package PACKAGE (no .sty extension) are accumulated
+% in \usepkg@options@PACKAGE.
+%
+% - For each declared option OPTION in package PACKAGE, we save the
+% code which enables OPTION in \usepkg@option@PACKAGE@OPTION.
+% There may be a star (`*') option declaration, the code from which
+% will be used to process options not declared by the package
+% (without it, an undeclared option will cause an error).
+%
+% - For each loaded PACKAGE / FILE.EXT we declare \ver@PACKAGE.sty /
+% \ver@FILE.EXT. We use \ver@PACKAGE.sty to detect reloading
+% of packages. Some packages also use these macros.
+%
+% - Calls to \AtBeginDocument accumulate the code in
+% \usepkg@at@begin@document. We will expand it at the end of the
+% \beginpackages...\endpackages `environment'.
+%
+% - Calls to \AtEndOfPackage accumulate the code in
+% \usepkg@at@end@of@package. We will expand it after the package
+% is loaded. To allow recursive package loading, \RequirePackage
+% saves \usepkg@at@end@of@package analogous to \usepkg@pkg.
+%
+\newif\ifusepkg@miniltx@loaded
+\newcount\usepkg@recursion@level
+\def\usepkg@rcrs{\the\usepkg@recursion@level}%
+\let\usepkg@at@begin@document\empty
+\let\usepkg@at@end@of@package\empty
+\def\usepkg@word@autopict{autopict}%
+\def\usepkg@word@psfrag{psfrag}%
+% \beginpackages...\endpackages
+%
+% All packages must be loaded within this `environment' (a kind of
+% LaTeX's preamble). This is so to give us a chance to expand the
+% accumulated \AtBeginDocument commands. Usually, you will want to
+% restrict all \usepackage's to a single \beginpackages...\endpackages,
+% just like in LaTeX, where you load all packages within a (single)
+% preamble.
+\long\def\beginpackages#1\endpackages{%
+ \let\usepackage\real@usepackage
+ #1%
+ \usepkg@at@begin@document
+ \global\let\usepkg@at@begin@document\empty
+ \global\let\usepackage\fake@usepackage
+}%
+% \fake@usepackage
+%
+% This is what \usepackage is defined to outside of
+% \beginpackages...\endpackages `environment'.
+\def\fake@usepackage{\errmessage{You should not use \string\usepackage\space outside of^^J
+ \@spaces\string\beginpackages...\string\endpackages\space environment}%
+}%
+% \RequirePackage[OPTIONS]{PACKAGES}[YYYY/MM/DD]
+%
+% Save parameters for the package being loaded and call \usepackage to
+% load PACKAGES. We depend on \usepackage to restore the saved
+% parameters. We allow for nested calls to \RequirePackage.
+\def\eplain@RequirePackage{%
+ \global\ece\let{usepkg@save@pkg\usepkg@rcrs}\usepkg@pkg
+ \global\ece\let{usepkg@save@options\usepkg@rcrs}\usepkg@options
+ \global\ece\let{usepkg@save@date\usepkg@rcrs}\usepkg@date
+ \global\ece\let{usepkg@at@end@of@package\usepkg@rcrs}\usepkg@at@end@of@package
+ \global\advance\usepkg@recursion@level by\@ne
+ \real@usepackage
+}%
+% \usepackage[OPTIONS]{PACKAGES}[YYYY/MM/DD]
+%
+% Load each of the PACKAGES with OPTIONS, checking that the package
+% date is at least YYYY/MM/DD; if it is not, issue a warning.
+\let\usepackage\fake@usepackage
+\def\real@usepackage{\@getoptionalarg\@finusepackage}%
+\def\@finusepackage#1{%
+ \let\usepkg@options\@optionalarg
+ \ifempty{#1}%
+ \errmessage{No packages specified}%
+ \fi
+ % Load miniltx.tex, if it is not loaded.
+ \ifusepkg@miniltx@loaded \else
+ \testfileexistence[miniltx]{tex}%
+ \if@fileexists
+ \input miniltx.tex
+ \global\usepkg@miniltx@loadedtrue
+ % Redefine some macros from miniltx.tex
+ \global\let\RequirePackage\eplain@RequirePackage
+ \global\let\DeclareOption\eplain@DeclareOption
+ \global\let\PassOptionsToPackage\eplain@PassOptionsToPackage
+ \global\let\ExecuteOptions\eplain@ExecuteOptions
+ \global\let\ProcessOptions\eplain@ProcessOptions
+ \global\let\AtBeginDocument\eplain@AtBeginDocument
+ \global\let\AtEndOfPackage\eplain@AtEndOfPackage
+ \global\let\ProvidesFile\eplain@ProvidesFile
+ \global\let\ProvidesPackage\eplain@ProvidesPackage
+ \else
+ \errmessage{miniltx.tex not found, cannot load LaTeX packages}%
+ \fi
+ \fi
+ % Read the trailing optional arg (YYYY/MM/DD).
+ \@ifnextchar[%]
+ {\@finfinusepackage{#1}}%
+ {\@finfinusepackage{#1}[]}%
+}%
+%
+\def\@finfinusepackage#1[#2]{%
+ \edef\usepkg@date{#2}%
+ % Load each package from the list. Do it outside the \for loop to
+ % avoid clashes with any \for loops executed by the package.
+ \let\usepkg@load@list\empty
+ \for\usepkg@pkg:=#1\do{%
+ \toks@=\expandafter{\usepkg@load@list}%
+ \edef\usepkg@load@list{%
+ \the\toks@
+ \noexpand\usepkg@load@pkg{\usepkg@pkg}%
+ }%
+ }%
+ \usepkg@load@list
+ % Restore parameters in case we were called from \RequirePackage.
+ \ifnum\usepkg@recursion@level>0
+ \global\advance\usepkg@recursion@level by\m@ne
+ \expandafter\let\expandafter\usepkg@pkg\csname usepkg@save@pkg\usepkg@rcrs\endcsname
+ \expandafter\let\expandafter\usepkg@options\csname usepkg@save@options\usepkg@rcrs\endcsname
+ \expandafter\let\expandafter\usepkg@date\csname usepkg@save@date\usepkg@rcrs\endcsname
+ \expandafter\let\expandafter\usepkg@at@end@of@package\csname usepkg@at@end@of@package\usepkg@rcrs\endcsname
+ % Free the memory.
+ \global\ece\let{usepkg@save@pkg\usepkg@rcrs}\undefined
+ \global\ece\let{usepkg@save@options\usepkg@rcrs}\undefined
+ \global\ece\let{usepkg@save@date\usepkg@rcrs}\undefined
+ \global\ece\let{usepkg@at@end@of@package\usepkg@rcrs}\undefined
+ \fi
+}%
+% Load one package. We assume packages have `sty' extension.
+\def\usepkg@load@pkg#1{%
+ % Special cases for `autopict' and `psfrag' packages:
+ % - `psfrag' is loaded by psfrag.tex.
+ % - `autopict' is loaded by picture.tex, but the package file is
+ % autopict.sty.
+ \def\usepkg@pkg{#1}%
+ \ifx\usepkg@pkg\usepkg@word@autopict
+ \testfileexistence[picture]{tex}%
+ \if@fileexists \else
+ \errmessage{Loader `picture.tex' for package `\usepkg@pkg' not found}%
+ \fi
+ \else
+ \ifx\usepkg@pkg\usepkg@word@psfrag
+ \testfileexistence[psfrag]{tex}%
+ \if@fileexists \else
+ \errmessage{Loader `psfrag.tex' for package `\usepkg@pkg' not found}%
+ \fi
+ \fi
+ \fi
+ % See if the package was loaded. If it was, we just bail out.
+ % (Maybe we should skip reloading it/warn? We don't want to go into
+ % checking that the package was first loaded with a subset of
+ % options which are requested now.) \ProvidePackage and
+ % \ProvideFile define the macro \ver@PACKAGE.sty (see
+ % \eplain@pr@videpackage below).
+ \ifundefined{ver@\usepkg@pkg.sty}\else
+ \errmessage{Package `\usepkg@pkg' already loaded}%
+ \fi
+ \testfileexistence[\usepkg@pkg]{sty}%
+ \if@fileexists \else
+ \errmessage{Package `\usepkg@pkg' not found}%
+ \fi
+ % Construct option list for the package. Include any options
+ % passed to us by \PassOptionsToPackage and \RequirePackage.
+ \expandafter\let\expandafter\temp\csname usepkg@options@\usepkg@pkg\endcsname
+ \ifx\temp\relax
+ \let\temp\empty
+ \fi
+ \ifx\temp\empty
+ \let\temp\usepkg@options
+ \else
+ \ifx\usepkg@options\empty \else
+ \edef\temp{\temp,\usepkg@options}%
+ \fi
+ \fi
+ \global\ece\let{usepkg@options@\usepkg@pkg}\temp
+ % For the duration of the package, we want any calls to \usepackage
+ % to be mapped to \RequirePackage, to allow nested package loads
+ % without clobbering up anything. (Maybe packages never use
+ % \usepackage instead of \RequirePackage, but this won't hurt.)
+ \let\usepackage\eplain@RequirePackage
+ % Clear \AtEndOfPackage commands (can be non-empty during recursive
+ % package loading).
+ \global\let\usepkg@at@end@of@package\empty
+ % Load the package. If the package asks to load other package,
+ % \RequirePackage will save our \usepkg@{pkg,options,date} and
+ % \AtEndOfPackage commands, and \usepackage will restore them after
+ % recursively loading that package, so we don't worry about our
+ % setup being clobbered.
+ \ifx\usepkg@pkg\usepkg@word@autopict
+ \input picture.tex
+ \else
+ \ifx\usepkg@pkg\usepkg@word@psfrag
+ \input \usepkg@pkg.tex
+ \else
+ \input \usepkg@pkg.sty
+ \fi
+ \fi
+ % Execute the accumulated \AtEndOfPackage commands, and reset them
+ % to free the memory.
+ \usepkg@at@end@of@package
+ \global\let\usepkg@at@end@of@package\empty
+ % Restore the `real' \usepackage definition.
+ \let\usepackage\real@usepackage
+ % Clear the option list for the loaded package (we won't load a
+ % second copy anyway).
+ \global\ece\let{usepkg@options@\usepkg@pkg}\undefined
+ % Set \Url@HyperHook for url.sty
+ \def\Url@HyperHook##1{\hlstart@impl{url}{\Url@String}##1\hlend@impl{url}}%
+ % We check package version in \ProvidePackage, before reading the
+ % rest of the package, so that in case of errors (which can be
+ % numerous) the warning hopefully comes before the errors.
+% \@ifl@ter{sty}\usepkg@pkg\usepkg@date{}%
+% {\message{Warning: you have requested package `\usepkg@pkg', version \usepkg@date,^^J
+% \@spaces but only version `\csname ver@\usepkg@pkg.sty\endcsname' is available.}}%
+}%
+% \DeclareOption{OPTION}{CODE}
+%
+% Save CODE in `usepkg@option@PACKAGE@OPTION'. Starred version is not
+% treated any different here, but when defined it will be used by
+% \ProcessOptions and \ExecuteOptions to process undeclared options.
+\def\eplain@DeclareOption#1#2{%
+ \toks@{#2}%
+ \expandafter\xdef\csname usepkg@option@\usepkg@pkg @#1\endcsname{\the\toks@}%
+}%
+% \PassOptionsToPackage{OPTIONS}{PACKAGES}
+%
+% Add OPTIONS to the option list for each of the PACKAGES.
+\def\eplain@PassOptionsToPackage#1#2{%
+ \ifempty{#1}\else
+ \for\usepkg@temp:=#2\do{%
+ \expandafter\let\expandafter\temp\csname usepkg@options@\usepkg@temp\endcsname
+ \ifx\temp\relax
+ \let\temp\empty
+ \fi
+ \ifx\temp\empty
+ \edef\temp{#1}%
+ \else
+ \edef\temp{\temp,#1}%
+ \fi
+ \global\ece\let{usepkg@options@\usepkg@temp}\temp
+ }%
+ \fi
+}%
+% \ExecuteOptions{OPTIONS}
+% \ProcessOptions
+%
+% \ExecuteOptions executes each option from OPTIONS, \ProcessOptions
+% executes each option from the option list for the current package.
+% If the star (`*') option is declared, it will be used to process
+% undeclared options; otherwise, undeclared option will cause an
+% error.
+\def\usepkg@exec@options#1{%
+ % The iterator \CurrentOption below was used purposely. Some
+ % packages use it in the argument to \DeclareOption.
+ \for\CurrentOption:=#1\do{%
+ \expandafter\let\expandafter\usepkg@temp
+ \csname usepkg@option@\usepkg@pkg @\CurrentOption\endcsname
+%
+ \ifx\usepkg@temp\relax
+ % Option is not declared. If a `default' option handler is
+ % declared, use it.
+ \expandafter\let\expandafter\temp\csname usepkg@option@\usepkg@pkg @*\endcsname
+ \ifx\temp\relax
+ \errmessage{Unknown option `\CurrentOption' to package `\usepkg@pkg'}%
+ \else
+ \temp
+ \fi
+ \else
+ % Option is declared.
+ \usepkg@temp
+ \fi
+ }%
+}%
+%
+\let\eplain@ExecuteOptions\usepkg@exec@options
+\def\eplain@ProcessOptions{%
+ \expandafter\usepkg@exec@options\csname usepkg@options@\usepkg@pkg\endcsname
+}%
+% \AtBeginDocument{CODE}
+% \AtEndOfPackage{CODE}
+%
+% miniltx.tex defines \AtBeginDocument to execute its parameter right
+% away, but some packages depend on \AtBeginDocument to be executed
+% after packages are processed. So we redefine \AtBeginDocument to
+% accumulate its argument, to be executed by us at the end of
+% \beginpackages...\endpackages. \AtEndOfPackage is not defined by
+% miniltx.tex at all; we define it similar to \AtBeginDocument.
+\def\usepkg@accumulate@cmds#1#2{%
+ \toks@=\expandafter{#1}%
+ \toks@ii={#2}%
+ \xdef#1{\the\toks@\the\toks@ii}%
+}%
+\def\eplain@AtBeginDocument{\usepkg@accumulate@cmds\usepkg@at@begin@document}%
+\def\eplain@AtEndOfPackage{\usepkg@accumulate@cmds\usepkg@at@end@of@package}%
+% \ProvidesFile{FILENAME.EXT}[VERSION]
+% \ProvidesPackage{PACKAGENAME}[VERSION]
+%
+% miniltx.tex defines \ProvidesFile and \ProvidesPackage to only log a
+% message. We want to define \ver@PACKAGE.sty / \ver@FILENAME.EXT, as
+% we depend on these to know when a package/file has been loaded, and
+% some packages depend on them, too.
+\def\eplain@ProvidesPackage#1{%
+ \@ifnextchar[%]
+ {\eplain@pr@videpackage{#1.sty}}{\eplain@pr@videpackage#1[]}%
+}%
+\def\eplain@pr@videpackage#1[#2]{%
+ \wlog{#1: #2}%
+ % This will flag the package as loaded.
+ \expandafter\xdef\csname ver@#1\endcsname{#2}%
+% \expandafter\edef\expandafter\temp{\csname usepkg@options@\usepkg@pkg\endcsname}%
+% \message{^^JPackage:\usepkg@pkg^^JOptions:\usepkg@options^^J+ passed options:\temp^^J}%
+ % Check package version.
+ \@ifl@t@r{#2}\usepkg@date{}%
+ {\message{Warning: you have requested package `\usepkg@pkg', version \usepkg@date,^^J
+ \@spaces but only version `\csname ver@#1\endcsname' is available.}}%
+}%
+%
+\def\eplain@ProvidesFile#1{%
+ \@ifnextchar[%]
+ {\eplain@pr@videfile{#1}}{\eplain@pr@videfile#1[]}%
+}%
+\def\eplain@pr@videfile#1[#2]{%
+ \wlog{#1: #2}%
+ % This will flag the file as loaded.
+ \expandafter\xdef\csname ver@#1\endcsname{#2}%
+ % We don't check file version. graphics calls \ProvideFile to
+ % \includegraphics, and it does not give any date at the beginning
+ % of #2, so checking the date will cause an error.
+}%
+% Check package version. From LaTeX.
+\def\@ifl@ter#1#2{%
+ \expandafter\@ifl@t@r
+ \csname ver@#2.#1\endcsname
+}%
+\def\@ifl@t@r#1#2{%
+ \ifnum\expandafter\@parse@version#1//00\@nil<%
+ \expandafter\@parse@version#2//00\@nil
+ \expandafter\@secondoftwo
+ \else
+ \expandafter\@firstoftwo
+ \fi
+}%
+\def\@parse@version#1/#2/#3#4#5\@nil{#1#2#3#4 }%
+% Needed by some packages.
+\def\@spaces{\space\space\space\space}%
+\def\@inmatherr#1{%
+ \relax
+ \ifmmode
+ \errmessage{The command is invalid in math mode}%
+ \fi
+}%
+%
+%
+%
+\let\wlog = \@plainwlog
+\catcode`@ = \@eplainoldatcode
+%
+\def\fmtname{eplain}%
+\def\eplain{t}%
+{\edef\plainversion{\fmtversion}%
+ \xdef\fmtversion{REPLACE-WITH-VERSION: REPLACE-WITH-DAY-MONTH-YEAR (and plain \plainversion)}%
+}%
+%
+%
+%
+%
+% Local variables:
+% page-delimiter: "^% \f"
+% End: