diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /info/impatient/usermacs.tex |
Initial commit
Diffstat (limited to 'info/impatient/usermacs.tex')
-rw-r--r-- | info/impatient/usermacs.tex | 1169 |
1 files changed, 1169 insertions, 0 deletions
diff --git a/info/impatient/usermacs.tex b/info/impatient/usermacs.tex new file mode 100644 index 0000000000..dbf78ddb83 --- /dev/null +++ b/info/impatient/usermacs.tex @@ -0,0 +1,1169 @@ +% This is part of the book TeX for the Impatient. +% Copyright (C) 2003, 2014 Paul W. Abrahams, Kathryn A. Hargreaves, Karl Berry. +% See file fdl.tex for copying conditions. + +\input macros +\chapter{A compendium \linebreak of useful macros} + +\chapterdef{eplain} + +This section describes |eplain.tex|, a collection of macros and other +definitions that extend plain \TeX. +\bix^^|eplain.tex| +The descriptions of the various macros explain their purposes, +but usually do not explain how they +work or provide explicit details on +how to use them. That information is contained in the source files for +|eplain.tex| and in the documentation that comes with it. +See \headcit{Resources}{resources} for how to obtain |eplain.tex|. + + +\section{Preliminaries} + +We start with some macros for changing category codes and convenient +definitions for two of the commonly used ones. +^^{category codes//useful definitions for} + +\pix^^|\makeactive| +\pix^^|\letter| +\pix^^|\other| +\pix^^|\uncatcodespecials| + +\csdisplay +\def\makeactive#1{\catcode`#1 = \active \ignorespaces}% +\chardef\letter = 11 \chardef\other = 12 +\def\uncatcodespecials{% + \def\do##1{\catcode`##1 = \other}% + \dospecials}% Defined in plain. +| + +In order to define `|^^M|' as an active character, you need to encase +the definition in a group and invoke some extra machinery. +\ttidxref{^^M} +The \pix^|\letreturn| macro lets you define `|^^M|' without that +extra machinery (which you can see in the definition below). + +\csdisplay +{\makeactive\^^M \long\gdef\letreturn#1{\let^^M = #1}}% +| + +These macros consume one, two, or three arguments. + +\pix^^|\gobble| +\pix^^|\gobbletwo| +\pix^^|\gobblethree| +\csdisplay +\def\gobble#1{}\def\gobbletwo#1#2{}% +\def\gobblethree#1#2#3{}% +| + +Now we establish some conventions for reading the rest of the file. +Within the file we allow ``private'' control sequences that contain +`|@|' in their names. +These control sequences aren't accessible outside of this file (unless +you change the category code of `|@|' again). +\xrdef{eplainconv} + +\csdisplay +\catcode`@ = \letter % Allow control sequences with @. +\let\@plainwlog = \wlog % Don't log register allocations. +\let\wlog = \gobble +\newlinechar = `^^J +| + +The next two macros provide convenient forms of diagnostic output. +\pix^|\loggingall| turns on all tracing, but causes the trace +output to appear only in the log file and not at your terminal. +\pix^|\tracingboxes| causes boxes to be displayed completely when +they're traced. (\TeX\ normally shows only three levels of boxing +and five items within each box.) + + +\csdisplay +\def\loggingall{\tracingcommands\tw@\tracingstats\tw@ + \tracingpages\@ne\tracingoutput\@ne + \tracinglostchars\@ne\tracingmacros\tw@ + \tracingparagraphs\@ne\tracingrestores\@ne + \showboxbreadth\maxdimen\showboxdepth\maxdimen}% +\def\tracingboxes{\showboxbreadth = \maxdimen + \showboxdepth = \maxdimen}% +| + + +The default thickness of rules is $0.4$\pt. +You can produce rules of any default thickness you choose by redefining +|\vruledefaultwidth|, |\hruledefaultheight|, and |\hruledefaultdepth| +and then using +\pix^^|\ehrule| +|\eh!-rule| +and \pix^|\evrule| +instead of |\hrule| and |\vrule|. (The `e' stands for +``eplain''.) +^^{rules//thickness of} +If you give an explicit +dimension (e.g., |\ehrule height 16pt|), \TeX\ will use it. + +\csdisplay +\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 |\%| convention for writing a `|%|' character doesn't work when you +want to include that character in the token list of |\write|. +^^|\write//writing \b\tt\%\e\ with| +^^|%//writing out| +You can use ^|\percentchar| to achieve this. +We also redefine ^|^^L| to be nonouter so that you can use it in a +macro definition or argument. + +\csdisplay +{\catcode`\% = \other \gdef\percentchar{%}}% + \def^^L{\par +}% +| + +\pix^|\tokstostring| converts its argument into a list of ^{character +tokens}. +It uses only expansions that are handled in \TeX's gullet. +This property is necessary +for it to work with |\edef|. It is used by the cross-referencing +macros (\xref{xrefs}). + +In order to split the argument up at spaces, we have to use two +subsidiary macros. |\@ttsA| finds the spaces, and |\@ttsB| handles a +token sequence without any spaces. Each space is replaced by the +expansion of \pix^|\spacesub|. + +\csdisplay +\def\tokstostring#1{\@ttsA#1 \ttsmarkA}% +\def\@ttsA#1 #2\ttsmarkA{\ifempty{#1}\else + \@ttsB #1\@ttsmarkB + \ifempty{#2}\else + \spacesub\@ttsA#2\ttsmarkA\fi\fi}% +\def\@ttsB#1{\ifx #1\@ttsmarkB\else + \string #1% + \expandafter\@ttsB\fi}% +\def\@ttsmarkB{\@ttsmarkB}% should never be expanded +\def\spacesub{+}% +| + +\noindent +\pix^|\ifempty| tests if its argument is empty. + +\csdisplay +\def\ifempty#1{\@ifempty #1\@emptymarkA\@emptymarkB}% +\def\@ifempty#1#2\@emptymarkB{\ifx #1\@emptymarkA}% +\def\@emptymarkA{\@emptymarkA}% +| + +The ^|\for| macro implements a \TeX\ version of the ^{for loop} in +traditional programming languages. These macros come directly from +\LaTeX. + +\csdisplay +\def\for#1:=#2\do#3{\edef\@fortmp{#2}% + \ifx\@fortmp\empty \else + \expandafter\@forloop#2,\@nil,\@nil\@@#1{#3}\fi}% +\def\@nnil{\@nil}% +\def\@fornoop#1\@@#2#3{}% +\def\@forloop#1,#2,#3\@@#4#5{\def#4{#1}\ifx #4\@nnil + \else #5\def#4{#2} ifx #4\@nnil \else + #5\@iforloop #3\@@#4{#5}\fi\fi}% +\def\@iforloop#1,#2\@@#3#4{\def#3{#1}\ifx #3\@nnil + \let\@nextwhile=\@fornoop \else #4\relax + \let\@nextwhile=\@iforloop\fi + \@nextwhile#2\@@#3{#4}}% +| + +\pix^|\obeywhitespace| is useful for reproducing line breaks, blank lines, +and spaces in your input. It combines the effects of |\obey!-lines| and +|\obey!-spaces|, +^^|\obeylines| ^^|\obeyspaces| +and also causes spaces at the start of a line to +be printed. Tab characters are not affected by this; they still produce +normal glue. +\xrdef{ewhitesp} +^^{space characters} +^^|\fontdimen| +^^|\font| +^^|\letreturn| + +\csdisplay +\def\alwaysspace{\hglue\fontdimen2\the\font \relax}% +{\makeactive\^^M \makeactive\ % +\gdef\obeywhitespace{% +\makeactive\^^M\def^^M{\par\indent}% +\aftergroup\@removebox% Kill extra paragraph at end. +\makeactive\ \let =\alwaysspace}}% +\def\@removebox{\setbox0=\lastbox} +| + +\pix^|\frac| is a good way to print fractions in text when you don't +want to use |\over| and +``1/2'' just doesn't look right. This macro is the answer to +\knuth{Exercise~11.6}.^^{fractions//slashed form} + +\csdisplay +\def\frac#1/#2{\leavevmode + \kern.1em \raise .5ex \hbox{\the\scriptfont0 #1}% + \kern-.1em $/$% + \kern-.15em \lower .25ex \hbox{\the\scriptfont0 #2}}% +| + +The following macros produce logos that are useful in the \TeX\ world. +The \AMSTeX\ logo is from \knuth{page~420}. The \LaTeX\ logo is +slightly modified from the one in |latex.tex| (we use a different font +for the `A'); similarly, the \BibTeX\ logo uses |\sevenrm| instead of a +true caps-and-small-caps font. The |.mf| source file for the \MF\ logo +is given in the \MF\ manual: +\smallskip +{\narrower\noindent +^{Knuth, Donald E.},{\sl The {\logosl METAFONT}book}. + Reading, Mass.: Addison-Wesley, 1986.\par} +\smallskip +\pix^^|\LaTeX| +\pix^^|\AMSTeX| +\pix^^|\BibTeX| +\pix^^|\MF| + +\csdisplay +\def\LaTeX{L\kern-.26em \raise.6ex\hbox{\fiverm A}% + \kern-.15em TeX}% +\def\AMSTeX{$\cal A\kern-.1667em \lower.5ex\hbox{$\cal M$}% + \kern-.125em S$-\TeX}% +\def\BibTeX{{\rm B\kern-.05em {\sevenrm I\kern-.025em B}% + \kern-.08em T\kern-.1667em \lower.7ex\hbox{E}% + \kern-.125emX}}% +\font\mflogo = logo10 +\def\MF{{\mflogo META}{\tenrm \-}{\mflogo FONT}}% +| + +The next two macros produce boxes. \pix^|\blackbox| produces a ``square +bullet'', used in the list macros (\xref{listmacs}). +\pix^|\makeblankbox| (from \knuth{page~311}) produces an unfilled +rectangle, with the thickness of the border rules given by the +arguments. + +\csdisplay +\def\blackbox{\vrule height .8ex width .6ex depth -.2ex}% +\def\makeblankbox#1#2{% + \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}}}}% +\def\hidehrule#1#2{\kern-#1\hrule height#1 depth#2 + \kern-#2}% +\def\hidevrule#1#2{\kern-#1{\dimen0 = #1 + \advance\dimen0 by #2 \vrule width\dimen0}\kern-#2}% +| + +\pix^|\numbername| produces the written-out form of a number. (If the +number is greater than ten, the macro just reproduces the numerals +of its argument.) + +\csdisplay +\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}% +| + +\pix^|\testfileexistence| determines whether a file |\jobname.#1| is +non\-empty and sets |\if!-fileexists| appropriately. +^^{files//testing for existence of} +The file name in the argument need not end in a space token since +the macro provides the space token. + +\csdisplay +\newif\iffileexists +\def\testfileexistence#1{\begingroup + \immediate\openin0 = \jobname.#1\space + \ifeof 0\global\fileexistsfalse + \else \global\fileexiststrue\fi + \immediate\closein0 + \endgroup}% +| + + +\section Displays + +By default, \TeX\ centers displayed material (the material between +|$$|'s). ^^{displays, formatting} \pix^|\leftdisplays| causes displays +to be left-justified by default. You can return to centered displays +with \pix^|\centereddisplays|. + +The macros here are more general than they need to be just for doing +left-justified displays. For every display, +\pix^|\ifeqno| will be true if an |\eqno| occurred in the display. +\pix^|\ifleqno| will be true if an |\leqno| occurred. If either +kind of equation number occurred, \pix^|\eqn| produces the text of the +equation number. \pix^|\eq| always produces the text of the +equation itself. + +These macros are based on the code on \knuth{page~376}. + +\csdisplay +\newif\ifeqno \newif\ifleqno +\newtoks\@eqtoks \newtoks\@eqnotoks +\def\eq{\the\@eqtoks}\def\eqn{\the\@eqnotoks}% +\def\displaysetup#1$${% + \@displaytest#1\eqno\eqno\@displaytest}% +\def\@displaytest#1\eqno#2\eqno#3\@displaytest{% + \if !#3!% No \eqno, check for \leqno: + \@ldisplaytest#1\leqno\leqno\@ldisplaytest + \else + \eqnotrue \leqnofalse % Have \eqno, not \leqno. + \@eqnotoks = {#2}\@eqtoks = {#1}% + \fi + \generaldisplay$$}% +\def\@ldisplaytest#1\leqno#2\leqno#3\@ldisplaytest{% + \@eqtoks = {#1}% + \if !#3!% + \eqnofalse % No \leqno; we're done. + \else + \eqnotrue \leqnotrue % Have \leqno. + \@eqnotoks = {#2}% + \fi}% +| + +You can format displays differently by defining your own macro, +analogous to \pix^|\leftdisplays|. +The macro definition must +place a call on |\display!-setup| in |\every!-display| ^^|\everydisplay| +so as to ensure +that |\dis!-play!-setup| ^^|\displaysetup| is called at the start of +every display. The macro definition must also include a definition of +^|\generaldisplay|. + +\csdisplay +\newtoks\previouseverydisplay +\def\leftdisplays{% + \previouseverydisplay = \everydisplay + \everydisplay = + {\the\previouseverydisplay \displaysetup}% + \def\generaldisplay{% + \leftline{% + \strut \indent \hskip\leftskip + \dimen0 = \parindent + \advance\dimen0 by \leftskip + \advance\displaywidth by -\dimen0 + \@redefinealignmentdisplays + \ifeqno \ifleqno + \kern-\dimen0 + \rlap{$\displaystyle\eqn$}% + \kern\dimen0 + \fi\fi + $\displaystyle{\eq}$% + \ifeqno \ifleqno\else + \hfill $\displaystyle{\eqn}$% + \fi\fi}}}% +\def\centereddisplays{\let\displaysetup = \relax}% +| + +\filbreak +\pix^|\leftdisplays| must go to some pains to make sure that +|\dis!-play!-lines|, ^^|\displaylines| +^|\eqalignno|, and ^|\leqalignno| still work properly. +|\eq| is typeset in math mode, +and |\halign| is illegal in math mode. +^^|\halign//illegal in math mode| +We use ^|\vcenter| to change the context so that |\halign| becomes +legal again. We also remove the |\hfil| commands at the left of the template +to obtain the flush left formatting. Other than those changes, the macros +are the same as in |plain.tex|. + +\csdisplay +\def\@redefinealignmentdisplays{% + \def\displaylines##1{\displ@y + \vcenter{\halign{\hbox to\displaywidth{$\@lign + \displaystyle####\hfil$}\crcr##1\crcr}}}% + \def\eqalignno##1{\displ@y + \vcenter{\halign to\displaywidth{% + $\@lign\displaystyle{####}$\tabskip\z@skip + &$\@lign\displaystyle{{}####}$ + \hfil\tabskip\centering + &\llap{$\@lign####$}\tabskip\z@skip\crcr + ##1\crcr}}}% + \def\leqalignno##1{\displ@y + \vcenter{\halign to\displaywidth{% + $\@lign\displaystyle{####}$\tabskip\z@skip + &$\@lign\displaystyle{{}####} + $\hfil\tabskip\centering + &\kern-\displaywidth + \rlap{\kern-\parindent\kern-\leftskip$ + \@lign####$}% + \tabskip\displaywidth\crcr + ##1\crcr}}}}% +| + + +\section Time of day + +When \TeX\ starts up, it sets the values of the +^|\time|, ^|\day|, ^|\month|, and ^|\year| parameters. +^^{time of day}^^{date} +\pix^|\monthname| +produces the name of the month, abbreviated to three letters. +\pix^|\timestring| produces the current time, as in ``1:14\thinspace +p.m.''. \pix^|\timestamp| produces the text of the complete date, as +in ``23 Apr 1964\quad 1:14\thinspace p.m.''. + +\csdisplay +\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}% +\def\timestring{\begingroup + \count0 = \time \divide\count0 by 60 + \count2 = \count0 % The hour. + \count4 = \time \multiply\count0 by 60 + \advance\count4 by -\count0 % The minute. + \ifnum\count4<10 \toks1 = {0}% Get a leading zero. + \else \toks1 = {}% + \fi + \ifnum\count2<12 \toks0 = {a.m.}% + \else \toks0 = {p.m.}% + \advance\count2 by -12 + \fi + \ifnum\count2=0 \count2 = 12 \fi % Make midnight `12'. + \number\count2:\the\toks1 \number\count4 + \thinspace \the\toks0 +\endgroup}% +\def\timestamp{\number\day\space\monthname\space + \number\year\quad\timestring}% +| + + +\section Lists + +\null +\xrdef{listmacs} +\bix^^{itemized lists} +\bix^^{enumerations} +\pix^|\numberedlist| produces numbered lists; |\endnumberedlist| ends +them. +\pix^|\unorderedlist| is analogous. +For either of these, items inside the lists begin +with \pix^|\li| (``list item''). You can put \pix^|\listcompact| +at the beginning of a list if +you don't want any additional space between the items of that list. +Lists can be nested arbitrarily. + +You can control the spacing between the items more generally by +assigning values to the registers listed below. If the items in +your lists tend to be long, you might want to make |\interitemskip| +nonzero. +The left indentation of each list item is given by |\par!-indent| plus +|\list!-left!-indent|; the right indentation of each list item +is given by |\list!-right!-indent|. + +\csdisplay +\newskip\abovelistskip \abovelistskip = .5\baselineskip +\newskip\interitemskip \interitemskip = 0pt +\newskip\belowlistskip \belowlistskip = .5\baselineskip +\newdimen\listleftindent \listleftindent = \parindent +\newdimen\listrightindent \listrightindent = 0pt +\def\listcompact{\interitemskip = 0pt \relax}% +| + +Both numbered and unnumbered lists use the macros that follow. +We don't change |\parindent|, since many existing macros, e.g., +|\footnote|, depend on |\parindent|. +We must account for the +possibility that items are more than one paragraph long. In this case, all +paragraphs after the first will be indented. +We use +|\leftskip| and |\rightskip| to indent the list items. +Indentation of displays is accounted for by changes to |\every!-dis!-play|. +^^|\everydisplay| + +\csdisplay +\newdimen\@listindent +\def\beginlist{% + \@listindent = \parindent + \advance\@listindent by \listleftindent + \everydisplay = \expandafter{\the\everydisplay + % Don't lose user's \everydisplay: + \advance\displayindent by \@listindent + \advance\displaywidth by -\@listindent + \advance\displaywidth by -\listrightindent}% + \nobreak\vskip\abovelistskip + \parskip = 0pt + % \leftskip shifts nested lists to the right on the page. + \advance\leftskip by \@listindent + \advance\rightskip by \listrightindent}% +\def\printitem{\par\noindent + \llap{\hskip-\listleftindent \marker \enspace}}% +\def\endlist{\vskip\belowlistskip}% +| + +\noindent +You can change the way the item labels are typeset by +redefining the |\numbered!-marker| macro. +\pix^^|\numberedmarker| + +\csdisplay +\newcount\numberedlistdepth \newcount\itemnumber +\newcount\itemletter +\def\numberedmarker{% + \ifcase\numberedlistdepth + (impossible)% + \or \itemnumberout)% + \or \itemletterout)% + \else *% + \fi}% +| + +\noindent Here are the definitions of |\numberedlist| and +|\unorderedlist|. +Both definitions have the same structure. + +\csdisplay +\def\numberedlist{\environment{@numbered-list}% + \advance\numberedlistdepth by 1 + \itemnumber = 1 \itemletter = `a + \beginlist \let\marker = \numberedmarker + \def\li{% + \ifnum\itemnumber=1\else \vskip\interitemskip \fi + \printitem + \advance\itemnumber by 1 \advance\itemletter by 1 + }}% +\def\itemnumberout{\number\itemnumber}% +\def\itemletterout{\char\itemletter}% +\def\endnumberedlist{\par + \endenvironment{@numbered-list}\endlist}% +!bigskip +\newcount\unorderedlistdepth +\def\unorderedmarker{% + \ifcase\unorderedlistdepth + (impossible)% + \or \blackbox + \or ---% + \else *% + \fi}% +\def\unorderedlist{\environment{@unordered-list}% + \advance\unorderedlistdepth by 1 + \beginlist \itemnumber = 1 + \let\marker = \unorderedmarker + \def\li{% + \ifnum\itemnumber=1\else \vskip\interitemskip \fi + \printitem \advance\itemnumber by 1 + }}% +\def\endunorderedlist{\par + \endenvironment{@unordered-list}\endlist}% +| + +\eix^^{itemized lists} +\eix^^{enumerations} + + +\section Verbatim listing + +The \pix^|\listing| macro produces a verbatim listing of a specified +file in the |\tt| font. +It is based on the code on \knuth{page~380}. +Tabs produce a fixed amount of space, and form +feeds produce a page break. Other control characters produce whatever +happens to be at that font position, which is generally not very useful. +By redefining |\setup!-listing!-hook|, +\pix^^|\setuplistinghook| +you can take additional actions that are appropriate for your particular +fonts and\slash or environment before the file is read in. + +\csdisplay +\def\listing#1{% + \par \begingroup \@setuplisting \setuplistinghook + \input #1 \endgroup}% +\let\setuplistinghook = \empty +\def\@setuplisting{% + \uncatcodespecials + \obeywhitespace \makeactive\` \makeactive\^^I + \def^^L{\vfill\eject}\tt}% +{\makeactive\` \gdef`{\relax\lq}}% Defeat ligatures. +{\makeactive\^^I\gdef^^I{\hskip8\fontdimen2\tt \relax}}% +| + + +\section Tables of contents + +\null ^^{table of contents} +The macro \pix^|\writetocentry| writes a macro call to the file +|\jobname.toc|. The first argument of |\writetocentry|, e.g., +``chapter'', is used to compose the name of the called macro. The second +argument is the text to appear in the table of contents entry. +|\writetocentry| appends the page number to the macro call. For +example: +\csdisplay +\writetocentry{chapter}{Introduction} +| +\noindent +will produce the line: +\csdisplay +\tocchapterentry{Introduction}{2} +| +\noindent in the |.toc| file, indicating +that `Introduction' started on page 2. + +You can use |\writenumberedtocentry| to provide a third parameter, such +as a chapter number. For example: +\csdisplay +\writenumberedtocentry{chapter}{The second chapter}{2} +| +\noindent will write a line: +\csdisplay +\tocchapterentry{The second chapter}{2}{14} +| +\noindent +You can also |\write| to |\tocfile| yourself. + +\csdisplay +\newwrite\tocfile \newif\iftocfileopened +\def\opentocfile{\iftocfileopened\else + \tocfileopenedtrue + \immediate\openout\tocfile = \jobname.toc +\fi}% +\def\writetocentry#1#2{\ifrewritetocfile + \opentocfile + \write\tocfile{% + \expandafter\noexpand \csname toc#1entry\endcsname + {#2}{\folio}}% +\fi\ignorespaces}% +% +\def\writenumberedtocentry#1#2#3{\ifrewritetocfile + \opentocfile + \write\tocfile{% + \expandafter\noexpand \csname toc#1entry\endcsname + {#2}{#3}{\folio}}% +\fi\ignorespaces}% +| + +To produce a table of contents, read the |.toc| file with +\pix^|\readtocfile|. You should call |\read!-tocfile| before the first +|\write!-toc!-entry|. When you're processing the table of contents +without regenerating it, you should not rewrite +the |.toc| file---if you do, its contents will be lost. +The command +|\rewrite!-tocfile!-false| will prevent the rewrite. + +\csdisplay +\newif\ifrewritetocfile \rewritetocfiletrue +\def\readtocfile{\testfileexistence{toc}% + \iffileexists + \input \jobname.toc + \ifrewritetocfile \opentocfile \fi + \fi}% +| + +Here are some definitions of possible |\toc|\dots|entry| macros. These +definitions are meant only as examples---running leaders across the line +is usually not the best way to typeset a table of contents. + +\csdisplay +\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}}% +| + + +\section Cross-references + +\null ^^{cross-references} +\xrdef{xrefs} +The macros that follow provide symbolic +cross-referencing, so that you can refer to something in another part of +a document by name instead of by its actual page number. +\pix^|\xrdef||{foo}| defines a label |foo| to be the current page +number, and \pix^|\xrefn||{foo}| produces that page number, e.g., $77$. +More often you'll want to say something like ``see p.\thinspace77'', so +\pix^|\xref||{foo}| produces ``p.\thinspace 77''. If |foo| is not +defined, a warning message will be given. |\xrefwarningfalse| +suppresses the warning. + +These macros provide no protection against duplicate definitions. You can +check for duplicate definitions by sorting the cross-reference file and +checking, either mechanically or by eye, for adjacent definitions of +the same symbol. + +\csdisplay +\newif\ifxrefwarning \xrefwarningtrue +\def\xrdef#1{\begingroup + \xrlabel{#1}% + \edef\@wr{\@writexrdef{\the\@xrlabeltoks}}% + \@wr + \endgroup \ignorespaces}% +\def\@writexrdef#1{\write\reffile{% + \string\gdef + \expandafter\string\csname#1\endcsname + {\noexpand\folio}\percentchar}}% +\def\xrefnumber#1{% + \xrlabel{#1}% + % \@xrlabeltoks now has the control sequence name. + \toks0 = + \expandafter{\csname\the\@xrlabeltoks\endcsname}% + \expandafter \ifx\the\toks0\relax + \ifxrefwarning \message{Undefined label + `\tokstostring{#1}'.}\fi + {\let\spacesub = \space + \expandafter\xdef\the\toks0 + {`{\tt \tokstostring{#1}}'}}\fi + \the\toks0}% +\def\xref#1{p.\thinspace\xrefnumber{#1}}% +\def\xrefn#1{\xrefnumber{#1}}% +| + +This macro turns a label into a list of character tokens in the token +register |\labeltoks|. A label can include blanks and control sequences in +it as well as normal characters, but it can't include braces. + +\csdisplay +\newtoks\@xrlabeltoks +\def\xrlabel#1{\begingroup + \escapechar = `\_ \edef\tts{\tokstostring{#1_}}% + \global\@xrlabeltoks = \expandafter{\tts}% + \endgroup}% +| + +It takes two passes to get the cross-references right, since the +definitions are written out to the auxiliary file |\jobname.aux|. +\pix^|\readreffile| reads them back in. If you don't issue this command +before the first definition, you'll lose all the definitions from the +previous run. + +\csdisplay +\newwrite\reffile \newif\ifreffileopened +\def\openreffile{\ifreffileopened\else + \reffileopenedtrue + \immediate\openout\reffile = \jobname.aux + \fi}% +\def\readreffile{% + \testfileexistence{aux}% + \iffileexists + \begingroup + \@setletters + \input \jobname.aux + \endgroup + \else + \message{No cross-reference file; I won't give you + warnings about undefined labels.}% + \xrefwarningfalse + \fi + \openreffile}% +\def\@setletters{% + \catcode`_ = \letter \catcode`+ = \letter + \catcode`- = \letter \catcode`@ = \letter + \catcode`0 = \letter \catcode`1 = \letter + \catcode`2 = \letter \catcode`3 = \letter + \catcode`4 = \letter \catcode`5 = \letter + \catcode`6 = \letter \catcode`7 = \letter + \catcode`8 = \letter \catcode`9 = \letter + \catcode`( = \letter \catcode`) = \letter}% +| + +^^{equations, labelling} +You can give symbolic names to equations in a similar way, using +\pix^|\eqdef| and \pix^|\eqref|. |\eqdef| inserts its own |\eqno| +command, so it must be invoked in a place where |\eqno| is legal. + +\csdisplay +\newcount\eqnumber +\def\eqdef#1{\global\advance\eqnumber by 1 + \expandafter\xdef + \csname#1eqref\endcsname{\the\eqnumber}% + \immediate\write\reffile{\string\def + \expandafter\string\csname#1eqref\endcsname + {\the\eqnumber}}% + \eqno + \eqprint{\the\eqnumber}}% +| + +|\eqref| produces ``(equation number)''. You can handle fancier +formatting by redefining \pix^|\eqprint|. For example, you could redefine +it so that the equation numbers include +the chapter number. + +\csdisplay +\def\eqref#1{% + \expandafter \ifx \csname#1eqref\endcsname \relax + \ifxrefwarning \message{Undefined equation label + `#1'.}\fi + \expandafter\def\csname#1eqref\endcsname{00}% + \else \eqprint{\csname#1eqref\endcsname}% + \fi}% +\def\eqprint#1{(#1)}% +| + + +\section Environments + +\null ^^{environments} These macros let you define your own named groups +(environments) for parts of your manuscript. Like \TeX\ groups, these +groups can be nested, and in fact their nesting can be intertwined with +the nesting of \TeX\ groups. If the names at the beginning and end of +an environment don't match, you'll get an error message. The macros are +designed so that the message you get when such an error occurs will give +you a good chance of localizing the cause of the error easily. + +You begin an environment with +\pix^^|\environment| +|\envi!-ron!-ment| |{foo}| and end it with |\endenvironment{foo}|, where +|foo| is the name of the environment. Our macros slightly improve on +the answer to Exercise~5.7 of \texbook, by doing some checks on +|\begingroup| and |\endgroup| pairs, as well as making sure +|\environment| and |\endenvironment| pairs match. + +\csdisplay +\def\environment#1{\ifx\@groupname\undefined\else + \errhelp = \@unnamedendgrouphelp + \errmessage{`\@groupname' was not closed by + \string\endenvironment}\fi + \def\@groupname{#1}% + \begingroup + \let\@groupname = \undefined \ignorespaces}% +\def\endenvironment#1{\endgroup + \def\@thearg{#1}% + \ifx\@groupname\@thearg + \else + \ifx\@groupname\undefined + \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 \ignorespaces}% +| + +We also define help messages for each of the errors above. +^^|\newhelp| + +\csdisplay +\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\space 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 X, but^^J% + you ended it with Y. Maybe you made a typo + in one or the other^^J% + of the names.}% +| + +Some environments should not be allowed to occur within +another environment. Let's call these environments +``outer environments''. |\check!-env| checks that no outer environment +is currently in effect and complains if one is. To use |\check!-env|, you +must issue the command |\environment!-true| at the beginning of every +outer environment. + +\csdisplay +\newif\ifenvironment +\def\checkenv{% + \ifenvironment + \errhelp = \@interwovenenvhelp + \errmessage{Interwoven environments}% + \endgroup + \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.}% +| + + +\section Justification + +\bix^^{flush left} +\bix^^{flush right} +\bix^^{centered text} +The three macros \pix^|\flushleft|, \pix^|\flushright|, and +\xrdef{eplaincenter} +\pix^|\center| justify the text on the following lines in the indicated way. +The command should appear on a line by itself. +Both the command and the text should be enclosed in a group---% +the end of the group indicates the end of the text. +The entire group is set as a single paragraph, with lines filled out +on one side or another as appropriate. Blank lines are reproduced. + +\csdisplay +\begingroup + \catcode `\^^M = \active + \globaldefs = 1 % + \def\flushleft{\beforejustify % + \aftergroup\@endflushleft % + \def^^M{\null\hfil\break}% + \def\@eateol^^M{}\@eateol}% + \def\flushright{\beforejustify % + \aftergroup\@endflushright % + \def^^M{\break\null\hfil}% + \def\@eateol^^M{\hfil\null}\@eateol}% + \def\center {\beforejustify % + \aftergroup\@endcenter % + \def^^M{\hfil\break\null\hfil}% + \def\@eateol^^M{\hfil\null}\@eateol}% +\endgroup +| + +The following commands are called as a result of the |\after!-group| +^^|\aftergroup| +in the definitions of |\flush!-left|, |\flush!-right|, and |\center|. +They perform the necessary cleanup operations. + +\csdisplay +\def\@endflushleft{\unpenalty + {\parfillskip = 0pt plus 1 fil\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 plus 1fil \par}\ignorespaces}% +\def\beforejustify{% + \par\noindent + \catcode`\^^M = \active + \checkenv \environmenttrue}% +| + +\eix^^{flush left} +\eix^^{flush right} +\eix^^{centered text} + + +\section Tables + +The \pix^|\makecolumns| macro enables you to give all the entries in a +table without having to worry about where the columns break. For +example, if you're typing a long alphabetical list that will be +formatted in several columns, you usually won't know in advance where +one column ends and the next begins. Moreover, if another item gets +added, the column breaks will change. + +|\makecolumns| takes two (delimited) arguments: the total number of +entries in the table and the number of columns in the table. For +example, `|\makecolumns 37/3:|' specifies a three-column table whose +entries are the next $37$ lines. You can adjust the positioning of the +table on the page by changing |\parindent|, which determines the space +to the left, and |\hsize|, which determines the space from the left +margin of the page to the right of the block. You can allow a page +break above the |\valign| +^^|\valign//used in {\tt\\makecolumns}| +by changing +\pix^|\abovecolumnspenalty|. + +\csdisplay +\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}% +\def\makecolumns#1/#2: {\par \begingroup + \@columndepth = #1 \advance\@columndepth by #2 + \advance\@columndepth by -1 + \divide \@columndepth by #2 + \@linestogoincolumn = \@columndepth \@linestogo = #1 + \def\@endcolumnactions{% + \ifnum \@linestogo<2 + \the\crtok \egroup \endgroup \par + % End \valign and \makecolumns. + \else + \global\advance\@linestogo by -1 + \ifnum\@linestogoincolumn<2 + \global\@linestogoincolumn = \@columndepth + \the\crtok + \else &\global\advance\@linestogoincolumn by -1 + \fi + \fi}% + \makeactive\^^M\letreturn\@endcolumnactions + \@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 ##\hfil}\cr +}% The next end-of-line starts everything going. +| + + +\section Footnotes + +\null ^^{footnotes} +Footnotes are most commonly typeset by using a raised number as the +reference mark. We define the \pix^|\numberedfootnote| macro to do +this. It also redefines ^|\vfootnote| to allow slightly more general +formatting of footnotes than \plainTeX\ does. The dimension register +\pix^^|\footnotemarkseparation| |\foot!-note!-mark!-sepa!-ra!-tion| +controls the space between the footnote mark (e.g., the number) and the +beginning of the text. The \pix^|\everyfootnote| tokens are inserted +before producing the footnote. + +The \plainTeX\ definitions of |\footnote| and |\vfootnote| are +preserved in |\@plain!-footnote| and |\@plain!-vfootnote| in case you should +need them. +\csdisplay +\newcount\footnotenumber \newtoks\everyfootnote +\newdimen\footnotemarkseparation +\footnotemarkseparation = .5em +\let\@plainfootnote = \footnote +\let\@plainvfootnote = \vfootnote +\def\vfootnote#1{\insert\footins\bgroup + \interlinepenalty\interfootnotelinepenalty + \splittopskip\ht\strutbox \splitmaxdepth\dp\strutbox + \floatingpenalty\@MM + \leftskip\z@skip \rightskip\z@skip \spaceskip\z@skip + \xspaceskip\z@skip + \everypar = {}% + \the\everyfootnote + \indent\llap{#1\kern\footnotemarkseparation}\footstrut + \futurelet\next\fo@t}% +\def\numberedfootnote{\global\advance\footnotenumber by 1 + \@plainfootnote{$^{\number\footnotenumber}$}}% +| + + +\section Double columns + +\null ^^{double columns} The |\doublecolumns| command begins +double-column output, while the |\single!-column| +\pix^^|\singlecolumn| +command restores +single-column output. You can switch back and forth between them +on a single page. +The glue specified by |\above!-double!-column!-skip| and +|\below!-double!-column!-skip| is inserted before and after the +double-column material. + +The approach is derived from \knuth{page~417}. + +\csdisplay +\newskip\abovedoublecolumnskip +\newskip\belowdoublecolumnskip +\abovedoublecolumnskip = \bigskipamount +\belowdoublecolumnskip = \bigskipamount +\newdimen\gutter \gutter = 2pc +\newdimen\doublecolumnhsize \doublecolumnhsize = \hsize +\newbox\@partialpage \newdimen\singlecolumnhsize +\newdimen\singlecolumnvsize \newtoks\previousoutput +\def\doublecolumns{\par % Don't start in horizontal mode. + \previousoutput = \expandafter{\the\output} + \advance\doublecolumnhsize by -\gutter + \divide\doublecolumnhsize by 2 + \output = {\global\setbox\@partialpage = + \vbox{\unvbox255\vskip\abovedoublecolumnskip}}% + \pagegoal = \pagetotal \break % Expands \output above. + \output = {\doublecolumnoutput}% + \singlecolumnhsize = \hsize + \singlecolumnvsize = \vsize + \hsize = \doublecolumnhsize \vsize = 2\vsize}% +| + +The |\@double!-column!-split| macro does the actual splitting. +Insertions are assumed to be single-column material. If you don't want +this to be the case, you'll have to modify the output routine. After +|\@double!-column!-split| has done its work, |\box255| will have the +double-column material. The double-column material will be preceded by +any single-column material that was typeset before |\doublecolumns| was +invoked. |\box4| will have the material that didn't fit on the page. + +\csdisplay +\def\@doublecolumnsplit{% + \splittopskip = \topskip \splitmaxdepth = \maxdepth + \dimen0 = \singlecolumnvsize + \advance\dimen0 by -\ht\@partialpage + \advance\dimen0 by -\ht\footins + \advance\dimen0 by -\skip\footins + \advance\dimen0 by -\ht\topins + \begingroup + \vbadness = 10000 + \global\setbox1=\vsplit255 to \dimen0 \wd1=\hsize + \global\setbox3=\vsplit255 to \dimen0 \wd3=\hsize + \endgroup + \global\setbox4=\vbox{\unvbox255 + \penalty\outputpenalty}% + \global\setbox255=\vbox{\unvbox\@partialpage + \hbox to \singlecolumnhsize{\box1\hfil\box3}% + \vfill}}% +| +\needspace{.5in} +|\double!-column!-out!-put| is the real output routine. We call the old +|\output| to do the work of actually shipping out the box. + +\csdisplay +\def\doublecolumnoutput{\@doublecolumnsplit + \hsize = \singlecolumnhsize \vsize = \singlecolumnvsize + \previousoutput \unvbox4}% +| + +|\singlecolumn| resumes typesetting in one column. It assumes that +|\doublecolumns| has been called. + +\csdisplay +\def\singlecolumn{\par % Don't start in horizontal mode. + \output = {\global\setbox1 = + \vbox{\unvbox255\vskip\abovedoublecolumnskip}}% + \pagegoal = \pagetotal \break \setbox255 = \box1 + {\singlecolumnvsize = \ht255 + \divide\singlecolumnvsize by 2 + \advance\singlecolumnvsize by +\ht\@partialpage + \advance\singlecolumnvsize by +\ht\footins + \advance\singlecolumnvsize by +\skip\footins + \advance\singlecolumnvsize by +\ht\topins + \@doublecolumnsplit}% + \hsize = \singlecolumnhsize + \vsize = \singlecolumnvsize + \output = \expandafter{\the\previousoutput}% + \unvbox255}% +| + +\margin{`Sensible paragraph skips' section deleted} + + +\section Finishing up + +We now must undo the changes that we made when we started (see +\xref{eplainconv}). We also give a version identification, which is +subsequently available in |\fmt!-name| and |\fmt!-version|. + +\csdisplay +\let\wlog = \@plainwlog \catcode`@ = \other +\def\fmtname{eplain}% +{\edef\plainversion{\fmtversion}% + \xdef\fmtversion{1.0: 15 May 1990 + (and plain \plainversion)}% +}% +| + +\eix^^|eplain.tex| + +\endchapter +\byebye |