% $Id: xeplain.tex 60 2022-10-05 22:42:54Z karl $ % xeplain.tex: macros for nonformatting. Written 1989--94 by (mostly) % Karl Berry. Some additions/changes 1997--98 by Adam Lewenberg, % with subsequent contributions from many people. % These macros are in the public domain. % % This is the ``extended plain'' TeX format that's described in % `eplain.texi', which you should have received with this file. % It assumes that 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 = "tex-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. The original sources %% can be found in Eplain sources in your TeX %% distribution, on CTAN or on Eplain's home page at %% https://tug.org/eplain. 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 iftex.sty file included below was mainly written by Heiko Oberdiek % and is now maintained by the LaTeX Project. %% [[[include iftex.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}% % % True if #1 is an integer. From the UK List of TeX Frequently Asked % Questions, https://texfaq.org.\def\@gobbleminus#1{\ifx-#1\else#1\fi}% \def\ifinteger#1{\ifcat_\ifnum9<1\@gobbleminus#1 _\else A\fi}% % This is a convenience to be used in places where TeX might be % skipping tokens, e.g., in conditionals. Usage: % \if\isinteger{}% % % % \else % % % \fi \def\isinteger{TT\fi\ifinteger}% % % 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{}. % \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}% }% % % btxmac.tex defines a \@for loop. We provide an alternative \For % loop, extended to strip an optional leading space off list items. \def\@Nnil{\@Nil}% \def\@Fornoop#1\@@#2#3{}% % \def\For#1:=#2\do#3{% \edef\@Fortmp{#2}% \ifx\@Fortmp\empty \else \expandafter\@Forloop#2,\@Nil,\@Nil\@@#1{#3}% \fi }% % \def\@Forloop#1,#2,#3\@@#4#5{\@Fordef#1\@@#4\ifx #4\@Nnil \else #5\@Fordef#2\@@#4\ifx #4\@Nnil \else#5\@iForloop #3\@@#4{#5}\fi\fi }% % \def\@iForloop#1,#2\@@#3#4{\@Fordef#1\@@#3\ifx #3\@Nnil \let\@Nextwhile=\@Fornoop \else #4\relax\let\@Nextwhile=\@iForloop\fi\@Nextwhile#2\@@#3{#4}% }% % \@Fordef\@@ defines COMMAND to the TEXT trimmed off % optional space tokens at the beginning. Assume spaces are of % category 10 (won't work when \obeyspaces is in effect). \def\@Forspc{ }% % \def\@Fordef{\futurelet\@Fortmp\@@Fordef}% Peep at the next token. % \def\@@Fordef{% \expandafter\ifx\@Forspc\@Fortmp % Next token is a space. \expandafter\@Fortrim \else \expandafter\@@@Fordef \fi }% % \expandafter\def\expandafter\@Fortrim\@Forspc#1\@@{\@Fordef#1\@@}% % \def\@@@Fordef#1\@@#2{\def#2{#1}}% % % From texinfo.tex. Emulate eTeX's \scantokens with a temporary file % in ordinary TeX. \def\tmpfileextension{.tmp}% \let\tmpfilebasename = \jobname \ifx\eTeXversion\undefined \innernewwrite\eplain@tmpfile \def\scantokens#1{% \toks@={#1}% \immediate\openout\eplain@tmpfile=\tmpfilebasename\tmpfileextension \immediate\write\eplain@tmpfile{\the\toks@}% \immediate\closeout\eplain@tmpfile \input \tmpfilebasename\tmpfileextension\relax }% \fi % % % % 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{\unhcopy0}% Preserve \box0 so we can put it back. \ifdim\wd2=0pt % Don't put it back: it was an indentation box. % This \ignorespaces ignores spaces after the group. \ignorespaces \else \box0 % 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]]] % % % More TeX logos. % % Adapted from tugboat.dtx. \ifx\eTeX\undefined \def\eTeX{\hbox{\mathsurround=0pt $\varepsilon$-\kern-.125em\TeX}}% \fi % \ifx\ExTeX\undefined \def\ExTeX{\hbox{\mathsurround=0pt $\textstyle\varepsilon_{\kern-0.15em\cal{X}}$\kern-.2em\TeX}}% \fi % % XeTeX require the graphics package for reflecting/rotating. From % tugboat.dtx: "Also, at Barbara's suggestion, if the current font is % slanted, we rotate by 180 instead of reflecting so there is at least % a chance to look ok. (The magic values here seem more or less ok % for \texttt{cmsl} and \texttt{cmti}.)". \def\eplain@Xe@reflect#1{% \ifx\reflectbox\undefined \errmessage{A graphics package must be loaded for \string\XeTeX}% \else \ifdim \fontdimen1\font>0pt \raise 1.75ex \hbox{\kern.1em\rotatebox{180}{#1}}\kern-.1em \else \reflectbox{#1}% \fi \fi }% \def\eplain@Xe#1{\leavevmode \smash{\hbox{X% \setbox0=\hbox{\TeX}\setbox2=\hbox{E}% \lower\dp0\hbox{\raise\dp2\hbox{\kern-.125em\eplain@Xe@reflect{E}}}% \kern-.1667em #1}}}% \ifx\XeTeX\undefined \def\XeTeX{\eplain@Xe\TeX}% \fi \ifx\XeLaTeX\undefined \def\XeLaTeX{\eplain@Xe{\thinspace\LaTeX}}% \fi % % % 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 $$\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{&}% \def\leqno{&}% \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{&}% \def\leqno{&}% \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 , we would end up with double indentation, anyway: one % because we're indenting the whole display, and one at the start of the % . (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. To omit last % (empty) line of input, say \let\setuplistinghook = \nolastlinelisting. % (This works with line numbers, too, but only if \printlistinglineno % consists of boxes only.) \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}}% % Remove the last line by removing all boxes (indentation \hbox and/or % line number from \everypar). \def\nolastlinelisting{\aftergroup\@removeboxes}% % Remove boxes until we remove all of them, or until we % encounter something other than a box. \def\@removeboxes{% \setbox0 = \lastbox \ifvoid0 \ignorespaces % Ignore spaces after the \obeywhitespace's group. \else \expandafter\@removeboxes \fi }% % % % % \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\def{writenumbered#1line}{\writenumberedcontentsline{#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. % % One special case is for #1 to be an integer (once fully expanded). % If it is, we produce a line in the .toc file that looks like: % \tocentry{#1}{#2}{page number} % This might be useful if you want to write one generic \tocentry % macro to format all TOC entries on the basis of their depth (#1). % % 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 % Set \toks0 to the initial part (command name and possible PART argument). \writenumberedcontents@cmdname{#1}{#2}% % \def\temp{#3}% the text % % 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 }% % This is very similar to \writenumberedcontentsentry, differing only % in the order of parameters it takes and writes for the % \toc...entry control sequence. #3 is the chapter (section, etc.) % number, and #4 is the text. \def\writenumberedcontentsline#1#2#3#4{% \csname ifrewrite#1file\endcsname % Set \toks0 to the initial part (command name and possible PART argument). \writenumberedcontents@cmdname{#1}{#2}% % \def\temp{#4}% the text % % Usually #3 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{#3}% \edef\cs{\the\toks2}% \edef\@wr{% \write\csname #1file\endcsname{% \the\toks0 % the \toc...entry control sequence \ifx\empty\cs\else {\sanitize\cs}\fi % a secondary number, or nothing {\sanitize\temp}% the text {\noexpand\folio}% the page number }% }% \@wr \fi \ignorespaces }% % This is the common part of \writenumberedcontentsentry and % \writenumberedcontentsline. It takes `toc' and PART arguments, % opens toc file and sets \toks0 to `\tocentry{PART}' (if PART is an % integer) or `\tocPARTentry' (otherwise). \def\writenumberedcontents@cmdname#1#2{% \csname open#1file\endcsname \edef\temp{#2}% Expand PART fully and see if this produced an integer. \expandafter\if\expandafter\isinteger\expandafter{\temp}% \toks0 = {\expandafter\noexpand \csname #1entry\endcsname}% \edef\temp{\the\toks0{\temp}}% \toks0 = \expandafter{\temp}% \else \toks0 = {\expandafter\noexpand \csname #1#2entry\endcsname}% \fi }% % % 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}}% \def\tocentry#1#2#3{\line{\rm\hskip#1em #2 \dotfill\ #3}}% % % % % 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 ''. \xrefn{foo} produces % ``''. \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. % % We check for multiply defined labels during the reading of the aux % file, not at the time a cross-reference macro is called by the user. % (From Tomas Penicka .) % % % \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 \ignorespaces }% % % \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 and #3 will be read later. % The following group will keep the save stack from overflowing: % We are reading the .aux file inside a group. For undefined % commands, \csname...\endcsname makes them equivalent to \relax % locally in that group; when we globally redefine them, TeX enters % the definitions on the save stack, once for each label. When done % in the topmost group, this can overflow stack of any size, given % sufficient number of label definitions. So, we put these % \csname...\endcsname's inside another group, to pop the stack for % every label. \begingroup % Will be ended in \@definelabel@nocheck. % Warn if we see that another label with the same name has been % defined. Remember, we are called when the aux file is being read, % which means that no labels have been defined yet except the ones % which come earlier in this aux file. \expandafter\ifx\csname\xrlabel{#1}\endcsname \relax \expandafter\@definelabel@nocheck \else \expandafter\@definelabel@warn \fi % Define the control sequences or warn. {#1}% }% % Define a label without checking for redefinitions. \def\@definelabel@nocheck#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}% \endgroup % From \@definelabel. }% % Warn and then redefine a label. \def\@definelabel@warn#1#2#3{% \message{^^J\linenumber Label `#1' multiply defined, value `#2' of class `#3' overwriting value `\csname\xrlabel{#1}\endcsname' of class `\getproperty{\xrlabel{#1}}{class}'.}% \@definelabel@nocheck{#1}{#2}{#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\@generalref@class{\getproperty{\xrlabel{#3}}{class}}% % If the word for this class is not defined, don't complain. \expandafter\ifx\csname \@generalref@class 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 \@generalref@class 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 ``()''. % \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. This however needs special % treatment with respect to hyperlink labels which should not be % duplicated. For each \eqdef{}, we define a destination with a % unique hyperlink label. These labels can be customized with: \newcount\phantomeqnumber \def\phantomeqlabel{PHEQ\the\phantomeqnumber}% % \def\@eqdefn#1#2{% % Write out xref into the aux file to allow forward references, but % only if the label is not empty. Otherwise numerous redefinitions % of the empty label might be reported. \ifempty{#1}% % LABEL is empty, so generate a `phantom' label. \global\advance\phantomeqnumber by 1 \edef\hl@eqlabel{\phantomeqlabel}% % Do not write to the aux file but read it anyway, so that % \@definelabel's get a chance to do the checks for multiple % definitions before we define any cross-references. \readauxfile \else % LABEL is not empty, so use it for hyperlinks. \def\hl@eqlabel{#1}% % Write the definition to the aux file, but do not create % hyperlink destination (we'll create it ourselves below). % This also reads the aux file. {\@@hldestoff \definexref{#1}{#2}{eq}}% \fi % Define hyperlink destination. \hldest@impl{eq}{\hl@eqlabel}% % Define the LABEL omitting redefinition check. \begingroup % \@definelabel@nocheck will end this group. \@definelabel@nocheck{#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{% \@maybedisableeqno \eqnum #1{#2}% Define the label and hyperlink destination. \let\@optionalarg\empty % \@fineqref will examine \@optionalarg. {\@@hloff\@fineqref{#2}}% Print the text without a hyperlink. \@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\leqno = \relax \global\let\@mayberestoreeqno = \@restoreeqno \fi }% % % This makes `\eqno' mean \eqno again. % \let\@primitiveeqno = \eqno \let\@primitiveleqno = \leqno \def\@restoreeqno{% \global\let\eqno = \@primitiveeqno \global\let\leqno = \@primitiveleqno \global\let\@mayberestoreeqno = \empty }% % % % \righteqnumbers/\lefteqnumbers configure \eqnum, \eqdef % and \eqalignnum to place the equation number against right/left % margin respectively. % \def\righteqnumbers{% \def\eqnum{\eqno}% \def\eqalignnum{\eqalignno}% }% % \def\lefteqnumbers{% \def\eqnum{\leqno}% \def\eqalignnum{\leqalignno}% }% % \righteqnumbers % % % \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@impl{eq}% }% % % \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 % \def\defineindex#1{% \def\@idxprefix{#1}% % % Define a switch to control opening and writing of the index file % for this prefix. \expandafter\innernewif\csname if\@idxprefix dx\endcsname \csname \@idxprefix dxtrue\endcsname % % 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. We % only write out the index term if this has not been disabled with % \csname\@idxprefix dxfalse\endcsname. % \let\indexfilebasename = \jobname % \def\@idxwrite#1#2{% \csname if\@idxprefix dx\endcsname % Be sure the file is opened. \@openidxfile % % 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 \else % Produce a whatsit anyway, to ensure consistent page-breaking. \write-1{}% \fi % % Marginalize the index term, if desired. We \sanitize the term to % avoid expansion of any (user-defined) active characters that made % it through (e.g., because they had not been added to \dospecials % and hence were not read verbatim by the indexing commands). \ifindexproofing \def\temp{#1}% \edef\temp{% \insert\@indexproof{\noexpand\indexproofterm{\sanitize\temp}}% }% \temp % Allow `infinitesimal' in \sidx{Infinitesimal}infinitesimal to be % hyphenated. \ifhmode\allowhyphens\fi \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 }% % \def\@openidxfile{% \csname if@\@idxprefix indexfileopened\endcsname \else \expandafter\immediate\openout\csname @\@idxprefix indexfile\endcsname = \indexfilebasename.\@idxprefix dx \expandafter\global\csname @\@idxprefix indexfileopenedtrue\endcsname \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 `page anchor' is defined. \expandafter\ifx\csname\idxpageanchor{\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% % Since \@getoptionalarg scans ahead, it might scan the \idxargopen % character of the following non-optional argument if the optional % argument is missing. To make sure that \idxargopen gets the right % catcode, we need to set it up before calling \@getoptionalarg. \begingroup \catcode\idxargopen=1 \@getoptionalarg\@finidxgetopt }% \def\@finidxgetopt{% \global\let\@idxgetrange@arg\@optionalarg \endgroup % \@hlidxencaptrue % \for\@idxarg:=\@idxgetrange@arg\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 % `page anchor' will tell \makeheadline on which pages to % generate an \hldest. \definepageanchor{\noexpand\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}% % % \idxpageanchor{PAGE} expands to index page anchor internal name. % This page anchor is used when index entries point to pages. Like in % \xrlabel, we append an _ character to NAME, to help avoid conflicts. % And we append a `p' 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\idxpageanchor#1{#1_p}% \endgroup % \definepageanchor{PAGE} defines a page anchor for the page PAGE. % \makeheadline will then define a hyperlink destination on top of % each page for which an anchor is defined. 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\definepageanchor#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\@definepageanchor{#1}}}% \@wr \ignorespaces }% % \@definepageanchor{PAGE} actually defines page anchor for the PAGE. \def\@definepageanchor#1{% \expandafter\gdef\csname\idxpageanchor{#1}\endcsname{}% }% % % 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{% \ifempty{#2}% \let\@idxpageencap\relax \else \expandafter\let\expandafter\@idxpageencap\csname #2\endcsname \fi \hlstart@impl{idx}{#1}% \@idxpageencap{#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. \ifempty{#1}% \let\@idxpageencap\relax \else \expandafter\let\expandafter\@idxpageencap\csname #1\endcsname \fi % 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\idx@getverbatimarg {\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 }% % % % Macros for reading verbatim the TERM, SUBTERM, SEE and SEEALSO % arguments of indexing commands. % % These can be customized by the user to different beginning and % end of group characters, so that `{' and `}' can be used inside % index terms. \def\idxargopen{`\{}% \def\idxargclose{`\}}% % \idx@getverbatimarg#1{ARG} reads ARG verbatim and then calls #1 with % that argument. We use it to read all TERM, (non-optional) SUBTERM, % SEE and SEEALSO arguments. \def\idx@getverbatimarg#1{% \def\idx@getverbatimarg@cmd{#1}% Save the command, allowing it to be % more than just a command sequence. \begingroup \uncatcodespecials \catcode\idxargopen=1 \catcode\idxargclose=2 \catcode`\ =10 % Swallow multiple consequent spaces. \catcode`\^^I=10 % Just in case, to avoid dependence on \catcode`\^^M=5 % current meanings of tabs and newlines. \idx@fingetverbatimarg }% \def\idx@fingetverbatimarg#1{\endgroup\idx@getverbatimarg@cmd{#1}}% % \idx@getverboptarg#1[ARG] reads ARG verbatim and then calls #1 with % that argument. We use it to read all optional SUBTERM arguments. % This is adopted from btxmac.tex's \@getoptionalarg. \def\idx@getverboptarg#1{% \def\idx@optionaltemp{#1}% Save the command, allowing it to be more % than just a command sequence (unlike \@getoptionalarg). \let\idx@optionalnext = \relax % If this is a SEE or SEEALSO entry, we know that another % non-optional arg follows, delimited by the \idxargopen and % \idxargclose characters. Since \@futurenonspacelet scans ahead, % it might scan \idxargopen if the optional argument is missing. To % make sure that \idxargopen gets the right catcode, we need to set % it up before calling \@futurenonspacelet. \begingroup \if@idxsee \catcode\idxargopen=1 \fi \@futurenonspacelet\idx@optionalnext\idx@bracketcheck }% % The \expandafter's in this macro let us avoid the use of \aftergroup, % which is somewhat more expensive. \def\idx@bracketcheck{% \ifx [\idx@optionalnext \endgroup % Cancel \catcode\idxargopen=1. \expandafter\idx@finbracketcheck \else \endgroup % Cancel \catcode\idxargopen=1. \let\@optionalarg = \empty % We can't do the \temp after the \fi, because then the \temp gets % in the way of reading the optional argument from the input, if % we do have one. \expandafter\idx@optionaltemp \fi }% % \def\idx@finbracketcheck{% \begingroup \uncatcodespecials % `[' should already be \other since \idx@bracketcheck succeeded; % we assume that the user also didn't give `]' a funky catcode % (otherwise it should have been added to \dospecials, anyway). %\catcode`\[=\other %\catcode`\]=\other \catcode`\ =10 % Swallow multiple consequent spaces. \catcode`\^^I=10 % Just in case, to avoid dependence on \catcode`\^^M=5 % current meanings of tabs and newlines. \idx@@getoptionalarg }% % \def\idx@@getoptionalarg[#1]{% \endgroup \def\@optionalarg{#1}% \idx@optionaltemp }% % % Produce term (which has been scanned verbatim) as output, rescanning % with `real' catcodes. \endinput ensures TeX does not see the ending % newline. Stepan Kasal verified that it is necessary both for e-TeX % and for ordinary TeX (see texinfo.tex). We reset catcode of newline % because \scantokens (both the e-TeX primitive and the Eplain's % emulation) generate a trailing newline when newline is catcode 13 % (putting \scantokens in an \hbox also fixes that newline--strange). % We don't write `\endinput' directly because the merge script strips % any lines with an \endinput. {\catcode`\&=0 \gdef\idx@scanterm#1{% \edef\idx@scanterm@nl@catcode{\the\catcode`\^^M\relax}% \catcode`\^^M=5 \scantokens{#1&endinput}% \catcode`\^^M=\idx@scanterm@nl@catcode }}% % % % 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{\idx@getverbatimarg\@finidx}% \def\@finidx#1{% \idx@scanterm{#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{\idx@getverbatimarg\@finsidx}% \def\@finsidx#1{\@idxmaintoks = {#1}\idx@getverboptarg\@finfinsidx}% \def\@finfinsidx{% \@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 makes an index entry % sorted by TERM but producing \CS{TERM}. % \def\@idxmarked#1{\idx@getverbatimarg{\@finidxmarked{#1}}}% \def\@finidxmarked#1#2{% \idx@scanterm{#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{\idx@getverbatimarg{\@finsidxmarked{#1}}}% \def\@finsidxmarked#1#2{% \@idxconstructmarked\toks@{#1}{#2}% \edef\temp{{\the\toks@}}% \expandafter\@finsidx\temp }% % % % \@idxsubmarked{TERM}\CS{SUBTERM} is like \@idxmarked, except that it's % SUBTERM that's marked instead of TERM. % \def\@idxsubmarked{% \let\sidxsubmarked@print\idxsubmarked@print \idx@getverbatimarg\@finsidxsubmarked }% \def\idxsubmarked@print{\expandafter\idx@scanterm\expandafter}% % % \@sidxsubmarked{TERM}\CS{SUBTERM} is to \@sidxmarked as \@idxsubmarked % is to \@idxmarked. % \def\@sidxsubmarked{% \let\sidxsubmarked@print\gobble \idx@getverbatimarg\@finsidxsubmarked }% \def\@finsidxsubmarked#1{\@idxmaintoks = {#1}\@@finsidxsubmarked}% Reads TERM. \def\@@finsidxsubmarked#1{\idx@getverbatimarg{\@@@finsidxsubmarked{#1}}}% Reads \CS. \def\@@@finsidxsubmarked#1#2{% Reads {\CS}{SUBTERM}. \sidxsubmarked@print % Prints for \@idxsubmarked, gobbles for \@sidxsubmarked. {\the\@idxmaintoks\space #1{#2}}% Maybe produce `TERM \CS{SUBTERM}' as output. \@idxconstructmarked\@idxsubtoks{#1}{#2}% \@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@ = \expandafter{\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{\idx@getverbatimarg\@finidxname}% \def\@finidxname#1{\idx@getverbatimarg{\@finfinidxname{#1}}}% \def\@finfinidxname#1#2{% \idx@scanterm{#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{\idx@getverbatimarg\@finsidxname}% \def\@finsidxname#1{\idx@getverbatimarg{\@finfinsidxname{#1}}}% \def\@finfinsidxname#1#2{% \@idxcollectname{#1}{#2}% \expandafter\@finsidx\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{\idx@getverbatimarg\@finindexsee}% \def\@finindexsee#1#2{{\seevariant \indexseeword\/ }\idx@scanterm{#1}}% % % \indexseealso{TERM}{PAGENO} is similar. \def\indexseealsowords{see also}% \def\indexseealso{\idx@getverbatimarg\@finindexseealso}% \def\@finindexseealso#1#2{{\seevariant \indexseealsowords\/ }\idx@scanterm{#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 % % } % % 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 }% % \ifx\@undefined\raggedleft % like plain's \raggedright except for \parfillskip. \innernewskip\raggedleftskip \raggedleftskip=0pt plus2em \def\raggedleft{\leftskip\raggedleftskip \parindent=0pt \spaceskip.3333em \xspaceskip.5em \parfillskip0pt \relax} \fi % \raggedleft undefined % % % 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. % % A fundamental bug is that marks are not always preserved. See: % https://tug.org/pipermail/tex-eplain/2021/001001.html % https://tug.org/pipermail/tex-eplain/2022/001049.html % % 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 its macros) has to be fixed. % % Gather this many baselines \chardef\@col@extralines = 3 % of additional material per each column than the combined height of the % columns, before attempting to break the columns. This sometimes % considerably improves the last column, when it would become too spaced % out because TeX had to squeeze some lines into the previous columns % due to unfortunate column breaks. % % The larger \@col@extralines, the better, but we don't want to make % it too large. If there are less than \@col@extralines * num_columns % lines left before we start gathering these extra lines, we'll hit % \@endcolumns while gathering material for this page. If the extra % lines will not actually fit in the columns, we'll have to move them % to the next page. But we won't move them if there are any % insertions on this page (see \@balancecolumns), so in such case % we'll stuff everything on the current page, producing an overfull % box, even though these extra lines could successfully be moved to % the next page. % \newdimen\@col@extraheight % % 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 % % Gather some extra material, to improve the last column. \@col@extraheight=\@col@extralines\baselineskip \multiply\@col@extraheight by \@numcolumns \global\advance\vsize by \@col@extraheight }% % % 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}}% % \def\@columnsplit{% \splittopskip = \topskip \splitmaxdepth = \baselineskip % % \dimen@ should be the height that columns 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 in \@columns and \@endcolumns. % % Unfortunately, we lose on flexible glue because we must % \vsplit to a . % % 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. %d\message{^^J starting columnsplit, splitting to \the\dimen@}% %d\showbox255 \global\setbox1 = \vsplit255 to \dimen@ \global\wd1 = \hsize %d\message{^^J split off to this box1:}% %d\showbox1 % % 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 % % 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{% %d\message{^^J starting columnoutput, ht255: \the\ht255}% \dimen@ = \ht255 \advance\dimen@ by -\@col@extraheight %d\message{^^J minus col@extraheight: \the\@col@extraheight}% \divide\dimen@ by \@numcolumns \@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, plus the ``extra height''. \global\vsize = \@numcolumns\@normalvsize \global\advance\vsize by \@col@extraheight }% % % Go back to single-column typesetting. Assume \doublecolumns has % been called. % \def\singlecolumn{% \@ndcolumns \chardef\@numcolumns = 1 \vskip\belowcolumnskip \nointerlineskip }% % \newbox\@singlecolumnbox \newdimen\column@pagegoal \newdimen\column@vsize % \def\@endcolumns{% \global\let\@ndcolumns = \relax \par % Shouldn't start in horizontal mode. % Save the combined height of the columns and the page goal. We % have to be careful -- the last line of the multi-column material % might have taken \pagetotal just over \pagegoal, in which case we % have to use \pagegoal for the height, otherwise the box produced % when splitting the columns will not fit on the page. \column@pagegoal = \pagegoal \advance\column@pagegoal by-\@col@extraheight \ifdim \pagetotal > \column@pagegoal \column@vsize = \column@pagegoal \else \column@vsize = \pagetotal \fi % Grab whatever is left of the multi-column material. \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. % We won't need \columnoutput anymore. \global\output = \expandafter{\the\previousoutput}% % Save single column material (in case the multi-column material % ends on the same page where it starts; otherwise \@partialpage % will be void). This also voids \@partialpage. \setbox\@singlecolumnbox = \box\@partialpage % Try to fit what's left into the columns. \@balancecolumns }% % % There are many caveats when balancing columns at the end of % multi-column material. The core of all problems is the following. % Eplain collects multi-column material in one long scroll until the % scroll's length is at least \vsize * \@numcolumns. But when we try % to split that scroll into columns, there is no guarantee that all % the collected material will fit (for example, because a column break % occured inside a large unbreakable block, so we had to carry it over % to the next column and stretch out the previous column). So every % time we call \@columnsplit, we should expect it to leave something % for us in \@partialpage. % % Now, what should we do with these left-overs? We increase column % height a bit and try to split the scroll again, and so on until % everything fits. % % However, while doing this, we might increase column height so much % that the columns no longer fit on a page. What we do then is output % the highest fitting columns, break the page and then restart the % whole process on what's left. % % However, there's another catch -- if a page contains insertions, % there's a slight chance that the footnotes or top insertions were % inserted by the multi-column material we are going to carry over to % the next page, so those footnotes or top insertions will appear one % page ahead of their references. The worst thing is that the user % will get no warning of this. Therefore, when we have left-overs on % a page with insertions, we just stuff them into columns to produce % an overfull box warning. % \def\@balancecolumns{% % Split the scroll to the new column height. \global\setbox255 = \copy2 % Retrieve what the fake \output set. \dimen@ = \column@vsize \divide\dimen@ by \@numcolumns \@columnsplit % \ifvoid\@partialpage % Everything fits -- we're done. \global\vsize = \@normalvsize \global\hsize = \@normalhsize \dump@balanced@columns \let\next\relax \else % There is some left-over. Increase column height. \advance \column@vsize by \@numcolumns pt % Check what we should do with the left-over. \test@spill@columns \ifspill@columns % We are to break the page here. Make up a page from the % single-column material followed by the columns that we've % already split off into \box255. \begingroup \vsize = \@normalvsize \hsize = \@normalhsize \dump@balanced@columns \break \@recoverclubpenalty \endgroup % Now put back what didn't fit and process it recursively. \unvbox\@partialpage \let\next\@endcolumns \else % We should continue incrementing column height. \setbox0=\box\@partialpage % Merely to void \@partialpage. \let\next\@balancecolumns \fi \fi \next }% % \def\dump@balanced@columns{% \ifvoid\topins\else\topinsert\unvbox\topins\endinsert\fi \unvbox\@singlecolumnbox % Avoid interline glue here -- we didn't (couldn't) account for it % when assessing \vsize for the columns in \@columns, which means % the columns may not fit if we also add the interline glue. \nointerlineskip \box255 }% % % If we hit page bottom while balancing columns and there are no % insertions on the page, we can let the left-over spill to the next % page. If there are insertions on the page, we shouldn't let % \@partialpage to the next page, to avoid separating a possible % reference from an insertion. The following flag and test are to % check these conditions. \newif\ifspill@columns \def\test@spill@columns{% \spill@columnsfalse \ifdim \column@vsize > \column@pagegoal \ifvoid\footins \ifvoid\topins \spill@columnstrue \fi \fi \fi }% % % [\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 with some % modifications by A. Lewenberg . % % 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 so far. %d\message{^^J pagetotal start (dimen@): \the\dimen@}% % \temp@dimen = \vsize % = \@numcolumns * columnheight %d\message{^^J temp@dimen (total height): \the\temp@dimen}% % \advance\temp@dimen by -\@col@extraheight %d\message{^^J reducing temp@dimen \the\temp@dimen (-@col@extraheight)}% % \divide\temp@dimen by \@numcolumns % Compute column height %d\message{^^J col height (tempdimen@): \the\temp@dimen}% % \loop %d\message{^^J looping}% \ifdim \dimen@ > \temp@dimen % more material than a column? \advance \dimen@ by -\temp@dimen \advance \dimen@ by \topskip % fudge factor %d\message{^^J reducing dimen@ to \the\dimen@ (tempdimen@ + \the\topskip)}% \repeat \advance \temp@dimen by -\dimen@ %d\message{^^J reducing temp@dimen to \the\temp@dimen (-dimen@)}% % \advance \temp@dimen by -\prevdepth %d\message{ reducing temp@dimen to \the\temp@dimen (-prevdepth)}% % \@saveclubpenalty \clubpenalty=10000\relax \hrule height\temp@dimen width0pt depth0pt\relax % fill space with rule \nointerlineskip \par \nointerlineskip \allowbreak \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{% We'll read #3 (LABEL) later. % 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 hyperlink 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 }% % Now read the third argument, LABEL. Do so inside a group with % \uncatcodespecials, to allow `#' and `~' in it (LABEL can be a URL % for some link types). \bgroup \uncatcodespecials \catcode`\{=1 \catcode`\}=2 \@hl@getparam }% % \def\@hl@getparam#1{% \egroup % Save LABEL in \@hllabel. \edef\@hllabel{#1}% % 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 hyperlink 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,hrefint,hrefext}% % \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 (except 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. % This will become \hl@setparam in \enablehyperlinks. \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 `\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. Even if we simply need to override the old option list, % we still call \hl@update@opts@with@list to go through the % options and trim possible leading space token in option keys. \if@params@override \expandafter\let\csname\hl@prefix @\hl@param @\hl@group\endcsname\empty \fi \hl@update@opts@with@list{#1}% #1 will be used in the \for % loop, so it will be expanded once. \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 hyperlink 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@opts@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). Changing them here has no % effect, modify \enablehyperlinks to set defaults. \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). Changing them here has no % effect, modify \enablehyperlinks to set defaults. \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 \def\hl@on@hrefint{0}% \href with internal #labels \def\hl@on@hrefext{0}% \href with external labels (URLs) % 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) \let\hl@type@hrefint\empty % \href with internal #labels \let\hl@type@hrefext\empty % \href with external labels (URLs) (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 \let\hl@opts@hrefint\empty % \href with internal #labels \let\hl@opts@hrefext\empty % \href with external labels (URLs) % % \@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 % Force the hyperlink driver % % If is omitted, appropriate driver will be detected, if % possible; if not, we fall back on `hypertex'. \def\hl@idxexact@word{idxexact}% \def\hl@idxpage@word{idxpage}% \def\hl@idxnone@word{idxnone}% \def\hl@raw@word{raw}% % \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{^^JEplain: using `pdftex' hyperlink driver.}% \else \def\hl@selecteddriver{hypertex}% \message{^^JEplain: using `hypertex' 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 % Enable \hltype, \hlopts, \hldest and \hldestopts now (the driver's % initialization routine may change this). \let\hl@setparam\@hl@setparam % 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@hypertex\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 % By default turn everything on except the footnotes. \hlon[*,]\hloff[foot,footback]% \hldeston[*,]\hldestoff[foot,footback]% }% % % 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. % % Additionally, `nolinks' driver defines the \hldesttype, \hldestopts, % \hltype, \hlopts macros to gobble their parameters, to avoid error % messages about "unknown" options and types under the `nolinks' % driver. \def\hldriver@nolinks{% \def\@hldest##1##2##3{% \edef\temp{\write-1{hldest: ##3}}% \ifvmode \temp \else \allowhyphens \expandafter\smash\expandafter{\temp}% \allowhyphens \fi \ignorespaces }% \def\@hlstart##1##2##3{% \leavevmode \begingroup % Start the color group. \edef\temp{\write-1{hlstart: ##3}}% \temp \ignorespaces }% \def\@hlend{% \edef\temp{\write-1{hlend}}% \temp \endgroup % End the color group from \@hlstart. }% % Make \hltype, \hlopts, \hldesttype and \hldestopts ignore their % parameters. \let\hl@setparam\gobble }% % % Driver `hypertex'. % {\catcode`\#=\other \gdef\hlhash{#}}% % \def\hldriver@hypertex{% % % Hyperlink destinations. % % Default type. \def\hldest@type{xyz}% % Set defaults for the options (this also tells \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@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 \special{html:}\special{html:}% \fi }% % Define handlers for each supported destination type (this also % tells \hl@getparam what types we support). \let\hldest@typeh@raw \empty \let\hldest@typeh@xyz \empty % % Hyperlinks. % % Default type. \def\hl@type{name}% % We support `url' hyperlinks, so set some group types. \ifx\hl@type@url\empty \def\hl@type@url{url}% \fi \ifx\hl@type@hrefext\empty \def\hl@type@hrefext{url}% \fi % Set defaults for the options (this also tells \hl@set@opt what % options we support). \let\hl@opt@cmd \empty \let\hl@opt@ext \empty \let\hl@opt@file \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 % Construct common preamble of a link. \def\hlstart@preamble{html:}}% \def\hl@typeh@filename{% \special{% \hlstart@preamble file:\hl@opt@file\hl@opt@ext \ifempty\@hllabel \else \hlhash\@hllabel\fi ">% }% }% \def\hl@typeh@url{% \special{% \hlstart@preamble \@hllabel ">% }% }% % \def\@hlend{\special{html:}\endgroup}% End the group from \@hlstart. }% % % Driver `pdftex'. % \def\hldriver@pdftex{% \ifpdf % PDF output is enabled. % % Hyperlink destinations. % % Default type. \def\hldest@type{xyz}% % Set defaults for the options (this also tells \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 (this also % tells \hl@getparam what types we support). \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 some group types. \ifx\hl@type@url\empty \def\hl@type@url{url}% \fi \ifx\hl@type@hrefext\empty \def\hl@type@hrefext{url}% \fi % Set defaults for the options (this also tells \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 }% % Define handlers for each supported link type (this also tells % \hl@getparam what types we support). \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{Eplain warning: `pdftex' hyperlink driver: PDF output is^^J \space not enabled, falling back on `nolinks' driver.}% \hldriver@nolinks \fi }% % % Driver `dvipdfm'. % \def\hldriver@dvipdfm{% % % Hyperlink destinations. % % Default type. \def\hldest@type{xyz}% % Set defaults for the options (this also tells \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 (this also % tells \hl@getparam what types we support). \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 some group types. \ifx\hl@type@url\empty \def\hl@type@url{url}% \fi \ifx\hl@type@hrefext\empty \def\hl@type@hrefext{url}% \fi % Set defaults for the options (this also tells \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 }% % Define handlers for each supported link type (this also tells % \hl@getparam what types we support). \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. }% % % Miscellaneous hyperlink macros. % % % \href{URL}{TEXT} typesets TEXT as a link to the URL. If URL starts % with a #, the rest of the URL is assumed to be this document's local % anchor. Special chars (like # and ~) in URL don't need to be % escaped in any way. \def\href{% % Read #1 (URL) inside a group with \uncatcodespecials, to get the # % and ~ right. \bgroup \uncatcodespecials \catcode`\{=1 \catcode`\}=2 \@href }% % \def\@href#1{% We'll read #2 (TEXT) later. \egroup \edef\@hreftmp{\ifempty{#1}{}\fi}% Parameter stuffing for \@@href. \expandafter\@@href\@hreftmp#1\@@ }% % \def\href@end@int{\hlend@impl{hrefint}}% \def\href@end@ext{\hlend@impl{hrefext}}% % Split out the first token and check if it is a #. \def\@@href#1#2\@@{% \def\@hreftmp{#1}% \ifx\@hreftmp\hlhash \let\href@end\href@end@int \hlstart@impl{hrefint}{#2}% \else \let\href@end\href@end@ext \hlstart@impl{hrefext}{#1#2}% \fi \@@@href }% % Now some tricks to avoid reading the TEXT as an argument (from the % \footnote definition in plain TeX). \def\@@@href{% \futurelet\@hreftmp\href@ }% % \def\href@{% \ifcat\bgroup\noexpand\@hreftmp \let\@hreftmp\href@@ \else \let\@hreftmp\href@@@ \fi \@hreftmp }% % \def\href@@{\bgroup\aftergroup\href@end \let\@hreftmp}% % \def\href@@@#1{#1\href@end}% % % Make all user-visible \hl* macros to give errors until hyperlinks % are explicitly enabled with \enablehyperlinks. \def\hldeston{\errmessage{Please enable hyperlinks with \string\enablehyperlinks\space before using hyperlink commands (consider selecting the `nolinks' driver to ignore all hyperlink commands in your document)}}% \let\hldestoff\hldeston \let\hlon\hldeston \let\hloff\hldeston \let\hlstart\hldeston \let\hlend\hldeston \let\hldest\hldeston % This catches \hltype, \hlopts, \hldesttype, \hldestopts. \let\hl@setparam\hldeston % Turn off all groups to make sure \hlstart@impl, \hlend@impl and % \hldest@impl do not call \hlstart, \hlend and \hldest until % hyperlinks are enabled. \@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. % % At the end of the \beginpackages...\endpackages block, we restore % the \input command to whatever it was defined before the % package(s), because miniltx.tex and some packages make (sometimes % incompatible) redefinitions of \input, and under plain TeX % non-primitive \input is probably not what the user expects. But in % case the redefined \input is actually needed, we save it as % \packageinput. % % Define \DoNotLoadEpstopdf so that graphics.cfg does not try to load % epstopdf.sty, which is a complication surely not wanted by default. % \long\def\beginpackages#1\endpackages{% \let\usepackage\real@usepackage \let\DoNotLoadEpstopdf=t \let\eplaininput=\input #1% \usepkg@at@begin@document \global\let\usepkg@at@begin@document\empty \global\let\usepackage\fake@usepackage \let\packageinput=\input \let\input=\eplaininput % should always be defined (from miniltx), but just in case: \ifx\resetatcatcode\@undefined \else\resetatcatcode \fi }% % % \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 \gdef\ProcessOptions{\@ifstar\eplain@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 superset 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}% \expandafter\@finusepkg@load@pkg \else \immediate\write-1{^^J\linenumber Eplain: package `\usepkg@pkg' already loaded, skipping reloading}% \fi }% \def\@finusepkg@load@pkg{% \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 }% % From base/latex.ltx. Support both date formats % \ProvidePackage{pkg}[2020-01-02 ...] % \ProvidePackage{pkg}[2020/01/02 ...] % \def\@parse@version#1/#2/#3#4#5\@nil{% \@parse@version@dash#1-#2-#3#4\@nil }% \def\@parse@version@dash#1-#2-#3#4#5\@nil{% \if\relax#2\relax\else#1\fi#2#3#4 }% % % For the `draft' option to graphic{s,x}.sty. \let\ttfamily\tt \def\strip@prefix#1>{}% % Definitions for epstopdf.sty. \def\@ifpackageloaded#1{% \expandafter\ifx\csname ver@#1.sty\endcsname\relax \expandafter\@secondoftwo \else \expandafter\@firstoftwo \fi }% \long\def\g@addto@macro#1#2{% \begingroup \toks@\expandafter{#1#2}% \xdef#1{\the\toks@}% \endgroup }% % These are for the warnings from epstopdf.sty when graphics.sty is % not loaded. From pdftex.def. \def\PackageWarning#1#2{% \begingroup \newlinechar=10 % \def\MessageBreak{% ^^J(#1)\@spaces\@spaces\@spaces\@spaces }% \immediate\write16{^^JPackage #1 Warning: #2\on@line.^^J}% \endgroup }% \def\PackageWarningNoLine#1#2{% \PackageWarning{#1}{#2\@gobble}% }% \def\on@line{ on input line \the\inputlineno}% % 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\protected@edef\edef % % % \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: