summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/mdwtools/mdwtab.dtx
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/contrib/mdwtools/mdwtab.dtx
Initial commit
Diffstat (limited to 'macros/latex/contrib/mdwtools/mdwtab.dtx')
-rw-r--r--macros/latex/contrib/mdwtools/mdwtab.dtx5441
1 files changed, 5441 insertions, 0 deletions
diff --git a/macros/latex/contrib/mdwtools/mdwtab.dtx b/macros/latex/contrib/mdwtools/mdwtab.dtx
new file mode 100644
index 0000000000..84d67f0724
--- /dev/null
+++ b/macros/latex/contrib/mdwtools/mdwtab.dtx
@@ -0,0 +1,5441 @@
+% \begin{meta-comment}
+%
+% $Id: mdwtab.dtx,v 1.8 1996/12/09 23:20:42 mdw Exp $
+%
+% Another rewrite of the tabular environment, and maths alignments
+%
+% (c) 1996 Mark Wooding
+%
+%----- Revision history -----------------------------------------------------
+%
+% $Log: mdwtab.dtx,v $
+% Revision 1.8 1996/12/09 23:20:42 mdw
+% (\tab@setstrut): Fixed so that it uses \dimen\tw@ for the strut depth,
+% as advertised.
+%
+% Revision 1.7 1996/11/29 21:59:16 mdw
+% Fixed a little formatting mistake in a syntax diagram, and switched over
+% to the new syntax diagram commands on the grounds that they're slightly
+% less messy. Maybe.
+%
+% Revision 1.6 1996/11/19 20:54:33 mdw
+% Entered into RCS
+%
+%
+% \end{meta-comment}
+%
+% \begin{meta-comment} <general public licence>
+%%
+%% mdwtab package -- another rewrite of the tabular environment, etc.
+%% Copyright (c) 1996 Mark Wooding
+%%
+%% This program is free software; you can redistribute it and/or modify
+%% it under the terms of the GNU General Public License as published by
+%% the Free Software Foundation; either version 2 of the License, or
+%% (at your option) any later version.
+%%
+%% This program is distributed in the hope that it will be useful,
+%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+%% GNU General Public License for more details.
+%%
+%% You should have received a copy of the GNU General Public License
+%% along with this program; if not, write to the Free Software
+%% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+%%
+% \end{meta-comment}
+%
+% \begin{meta-comment} <Package preambles>
+%<+mdwtab>\NeedsTeXFormat{LaTeX2e}
+%<+mdwtab>\ProvidesPackage{mdwtab}
+%<+mdwtab> [1998/04/28 1.9 Table typesetting with style]
+%<+mathenv>\NeedsTeXFormat{LaTeX2e}
+%<+mathenv>\ProvidesPackage{mathenv}
+%<+mathenv> [1998/04/28 1.9 Various maths environments]
+% \end{meta-comment}
+%
+% \CheckSum{2758}
+%% \CharacterTable
+%% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
+%% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
+%% Digits \0\1\2\3\4\5\6\7\8\9
+%% Exclamation \! Double quote \" Hash (number) \#
+%% Dollar \$ Percent \% Ampersand \&
+%% Acute accent \' Left paren \( Right paren \)
+%% Asterisk \* Plus \+ Comma \,
+%% Minus \- Point \. Solidus \/
+%% Colon \: Semicolon \; Less than \<
+%% Equals \= Greater than \> Question mark \?
+%% Commercial at \@ Left bracket \[ Backslash \\
+%% Right bracket \] Circumflex \^ Underscore \_
+%% Grave accent \` Left brace \{ Vertical bar \|
+%% Right brace \} Tilde \~}
+%%
+%
+% \begin{meta-comment}
+%
+%<*driver>
+\input{mdwtools}
+\describespackage{mdwtab}
+\describespackage{mathenv}
+\addcontents{lot}{\listoftables}
+\mdwdoc
+%</driver>
+%
+% \end{meta-comment}
+%
+%^^A-------------------------------------------------------------------------
+% \renewcommand{\tabstyle}{\small}
+%
+% \section{User guide}
+%
+%
+% The \package{mdwtab} package contains a reimplementation of the standard
+% \LaTeX\ \env{tabular} and \env{array} environments. This is not just an
+% upgraded version: it's a complete rewrite. It has several advantages over
+% the official \package{array} package (not raw \LaTeX's, which is even less
+% nice), and it's more-or-less compatible. Most of these are rather
+% technical, I'll admit.
+%
+% \begin{itemize}
+%
+% \item The newcolumn system is properly and perfectly integrated into the
+% system. There are now \emph{no} `primitive' column types -- all the
+% standard types are created as user-defined columns.
+%
+% \item You can define entirely different table-like environments using the
+% equipment here. It's still hard work, although less so than before.
+% I'll do an example of this some time.
+%
+% \item Construction of the preamble is generally much tidier. I've used
+% token registers rather than |\edef|, and it's all done very nicely.
+%
+% \item Fine spacing before and after rules (described by DEK as `a mark of
+% quality') is now utterly trivial, since the preamble-generator will
+% store the appropriate information.
+%
+% \item You can use \env{array} in LR and paragraph modes without having
+% to surround it with `|$|' signs.
+%
+% \item Usually you don't want tables in the middle of paragraphs. For these
+% cases, I've provided a simpler way to position the table
+% horizontally.
+%
+% \item Footnotes work properly inside \env{tabular} environments (hoorah!).
+% You can `catch' footnotes using the \env{minipage} environment if
+% you like. (It uses an internal version of the \package{footnote}
+% package to handle footnotes, which doesn't provide extra goodies like
+% the \env{footnote} environment; you'll need to load the full package
+% explicitly to get them.)
+%
+% \item Standard \LaTeX\ tabular environments have a problem with lining up
+% ruled tables. The |\firsthline| command given in the \textit{\LaTeX\
+% Companion} helps a bit, but it's not really good enough, and besides,
+% it doesn't \emph{actually} line the text up right after all. The
+% \package{mdwtab} package does the job properly to begin with, so you
+% don't need to worry.
+%
+% \end{itemize}
+%
+% I've tested the following packages with \package{mdwtab}, and they all
+% work. Some of the contortions required to make them work weren't pleasant,
+% but you don't need to know about them. By a strange coincidence, all the
+% packages were written by David Carlisle. Anyway, here's the list:
+% \begin{itemize}
+% \item The quite nice \package{dcolumn} package.
+% \item The more useful \package{delarray} package.
+% \item The rather spiffy \package{hhline} package.
+% \item The truly wonderful \package{tabularx} package.
+% \item The utterly magnificent \package{longtable} package.
+% \end{itemize}
+%
+% Note that I've looked at \package{supertabular} as well: it won't work, so
+% use \package{longtable} instead, 'cos it's much better.
+%
+%
+% \subsection{The downside}
+%
+% There's no such thing as a free lunch. The \package{mdwtab} environment
+% is not 100\% compatible with the \env{tabular} environment found in
+% \LaTeXe\ or the \package{array} package.
+%
+% The differences between \package{mdwtab} and \LaTeXe's \env{tabular}
+% environment are as follows:
+%
+% \begin{itemize} \synshorts \let\`=\lq
+%
+% \item The vertical spacing in \env{array} environments is different to
+% that in \env{tabular} environments. This produces more attractive
+% results in most mathematical uses of \env{array}s, in the author's
+% opinion. The spacing can be modified by playing with length
+% parameters.
+%
+% \item The presence of horizontal and vertical rules will alter the spacing
+% of the table (so a pair of columns separated by a `|' is wider than
+% a pair with no separation by "\\arrayrulewidth". This does mean that
+% horizontal and vertical rules match up properly -- the usual \LaTeX\
+% environment makes the horizontal rules stop just short of the edge
+% of the table, making an ugly mess (check out the \textit{\LaTeX\
+% book} if you don't believe me -- page~62 provides a good example).
+% The \package{array} package handles rules in the same way as
+% \package{mdwtab}.
+%
+% \setbox0=\hbox{\footnotesize`\\def\\xcs{\\tabskip=\\fill}'}
+% \setbox2=\hbox{\footnotesize`...@{\\span\\xcs}...'}
+% \item In common with the \package{array} package, there are some
+% restrictions on the use of the "\\extracolsep" command in preambles:
+% you may use at most one "\\extracolsep" command in each `@' or `!'
+% expression. Also, you can't say
+% \begin{listing}
+%\newcommand{\xcs}{\extracolsep{\fill}}
+% \end{listing}
+% and then expect something like `...@{\\xcs}...' to actually work --
+% the "\\extracolsep" mustn't be hidden inside any other
+% commands. Because things like `@' expressions aren't expanded at
+% the time, "\\extracolsep" has to be searched and processed
+% \`by hand'.\footnote{^^A
+% All \cs{extracolsep} does is modify the \cs{tabskip} glue, so
+% if you were an evil \TeX\ hacker like me, you could just say
+% \unhbox0\ and put \unhbox2\ in your preamble. That'd work nicely.
+% It also works with the \package{array} package.}
+%
+% \item Control sequences (commands) in a table's preamble aren't expanded
+% before the preamble is read. In fact, commands in the preamble are
+% considered to be column types, and their names are entirely
+% independent of normal \LaTeX\ commands. No column types of this
+% nature have yet been defined\footnote{^^A
+% There used to be an internal \cs{@magic} type used by
+% \env{eqnarray}, but you're not supposed to know about that.
+% Besides, it's not there any more.}
+% but the possibility's always there. Use the "\\newcolumntype" or
+% "\\coldef" commands to define new column types.
+%
+% \item The preamble parsing works in a completely different way. There is
+% a certain amount of compatibility provided, although it's heavily
+% geared towards keeping \package{longtable} happy and probably won't
+% work with other packages.
+%
+% \item Obscure constructs which were allowed by the old preamble parser but
+% violate the syntax shown in the next section (e.g., `|@{}|' to
+% suppress the "\\doublerulesep" space between two vertical rules,
+% described in \textit{The \LaTeX\ Companion} as \`a misuse of the
+% `@{...}' qualifier') are now properly outlawed. You will be given
+% an error message if you attempt to use such a construction.
+%
+% \item The `*' forms (which repeat column types) are now expanded at a
+% different time. Previously, preambles like `c@*{4}{{:}@}{--}c'
+% were considered valid (the example would expand to
+% `c@{:}@{:}@{:}@{:}@{--}c'), because `*'s were expanded before the
+% preamble was actually parsed. In the new system, `*' is treated
+% just like any other preamble character (it just has a rather odd
+% action), and preambles like this will result in an error (and
+% probably a rather confusing one).
+%
+% \end{itemize}
+%
+% There are also several incompatibilities between \package{mdwtab} and
+% \package{array}:
+%
+% \begin{itemize} \synshorts \let\`=\lq
+%
+% \item Because of the way "\\newcolumntype" works in the \package{array}
+% package, a horrid construction like
+% \begin{listing}
+%\newcolumntype{x}{{:}}
+%\begin{tabular}{|c!xc|}
+% \end{listing}
+% is considered to be valid, and is interpreted as `|c!{:}c|'. My
+% reading of pages~54 and~55 of the \textit{\LaTeX\ book} tells me
+% that this sort of thing is forbidden in normal \LaTeX\ commands.
+% The \package{mdwtab} preamble parser now treats column type letters
+% much more like commands with the result that the hacking above won't
+% work any more. The construction above would actually be interpreted
+% as `|c!{x}c|' (i.e., the `x' column type wouldn't be expanded to
+% `{:}' because the parser noticed that it was the argument to the
+% `!' modifier\footnote{^^A
+% This is a direct result of the way \TeX\ treats undelimited
+% arguments. See chapters~5 and~20 of \textit{The \TeX book} for
+% more information about how grouping affects argument reading.}).
+%
+% \item Most of the points above, particularly those relating to the
+% handling of the preamble, also apply to the \package{array} package.
+% it's not such an advance over the \LaTeXe\ version as everyone said
+% it was.
+%
+% \end{itemize}
+%
+%
+% \subsection{Syntax}
+%
+% \DescribeEnv{tabular}
+% \DescribeEnv{tabular*}
+% \DescribeEnv{array}
+% So that everyone knows where I stand, here's a complete syntax for my
+% version of the \env{tabular} environment, and friends
+%
+% \begin{grammar}
+%
+% <tabular-env> ::= \[[
+% "\\begin"
+% \begin{stack}
+% "{tabular}" \\ "{tabular*}" "{" <length> "}" \\
+% "{array}" \\ "{smarray}"
+% \end{stack}
+% \[ "[" <position-arg> "]" \]
+% "{" <preamble> "}" <text>
+% "\\end"
+% \( "{tabular}" \\ "{tabular*}" \\ "{array}" \\ "{smarray}" \)
+% \]]
+%
+% <position-arg> ::= (see below)
+%
+% <preamble> ::= \[[
+% <first-column>
+% \[ \< <column> \> \]
+% \]]
+%
+% <first-column> ::= \[[ \[ <rule> \] <column> \]]
+%
+% <column> ::= \[[
+% \[ <spacing> \] \[ \< <user-pre-text> \> \] <column-type>
+% \[ \< <user-post-text> \> \] \[ <spacing> \] \[ <rule> \]
+% \]]
+%
+% <spacing> ::= \[[ "@" "{" <text> "}" \]]
+%
+% <user-pre-text> ::= \[[ ">" "{" <text> "}" \]]
+%
+% <column-type> ::= \[[
+% \begin{stack}
+% \[ "T" \\ "M" \] \( "l" \\ "c" \\ "r" \) \\
+% \( "p" \\ "m" \\ "b" \) "{" <length> "}" \\
+% "#" "{" <raw-pre-text> "}" "{" <raw-post-text> "}"
+% \end{stack}
+% \]]
+%
+% <user-post-text> ::= \[[ "<" "{" <text> "}" \]]
+%
+% <rule> ::= \[[ \( "|" \\ "!" "{" <text> "}" \) \]]
+%
+% \end{grammar}
+%
+% If you examine the above very carefully, you'll notice a slight deviation
+% from the original -- an |@|-expression \emph{following} a rule is
+% considered to be part of the \emph{next} column, not the current one. This
+% is, I think, an almost insignificant change, and essential for some of the
+% new features. You'll also notice the new |#| column type form, which
+% allows you to define new real column types instead of just modifying
+% existing ones. It's not intended for direct use in preambles -- it's
+% there mainly for the benefit of people who know what they're doing and
+% insist on using |\newcolumntype| anyway.
+%%
+% The actual column types are shown in table~\ref{tbl:columns}.
+%
+% \begin{table}
+% \begin{tabular}[C]{| >{\synshorts} c | m{3in} |} \hlx{hv[1]}
+%
+% \multicolumn{2}{|c|}{\bf Column types} \\ \hlx{v[1]hv}
+% \bf Name & \bf Meaning \\ \hlx{vhv.}
+% "l" & Left aligned text (\env{tabular}) or
+% equation (\env{array}). \\ \hlx{.}
+% "c" & Centred text (\env{tabular}) or
+% equation (\env{array}). \\ \hlx{.}
+% "r" & Right aligned text (\env{tabular}) or
+% equation (\env{array}). \\ \hlx{vhv.}
+% "Ml", "Mc" and "Mr" & Left, centre and right aligned
+% equations.* \\ \hlx{.}
+% "Tl", "Tc" and "Tr" & Left, centre and right aligned
+% text.* \\ \hlx{vhv.}
+% "p{"<width>"}" & Top aligned paragraph with the given
+% width. \\ \hlx{.}
+% "m{"<width>"}" & Vertically centred paragraph with
+% the given width. \\ \hlx{.}
+% "b{"<width>"}" & Bottom aligned paragraph with the
+% given width. \\ \hlx{vhv.}
+% "#{"<pre>"}{"<post>"}" & User defined column type:
+% \<pre> is inserted before the
+% cell entry, \<post> is inserted
+% afterwards.* \\ \hlx{vhhv[1]}
+%
+% \multicolumn{2}{|c|}{\bf Other modifier characters} \\ \hlx{v[1]hv}
+% \bf Name & \bf Meaning \\ \hlx{vhv.}
+% "|" & Inserts a vertical rule between
+% columns. \\ \hlx{.}
+% "!{"<text>"}" & Inserts \<text> between columns,
+% treating it as a vertical rule. \\ \hlx{vhv.}
+% "@{"<text>"}" & Inserts \<text> instead of the
+% usual intercolumn space. \\ \hlx{vhv.}
+% ">{"<text>"}" & Inserts \<text> just before the
+% actual column entry. \\ \hlx{.}
+% "<{"<text>"}" & Inserts \<text> just after the
+% actual column entry. \\ \hlx{vhv.}
+% "*{"<count>"}{"<chars>"}" & Inserts \<count>
+% copies of the \<chars> into the
+% preamble. \\ \hlx{vhs}
+%
+% \multicolumn{2}{@{}l}{* This column type is a new feature}
+% \end{tabular}
+%
+% \caption{\package{array} and \package{tabular} column types and modifiers}
+% \label{tbl:columns}
+% \end{table}
+%
+% Now that's sorted everything out, there shouldn't be any arguments at all
+% about what a column means.
+%
+% The lowercase \<position-arg>s \lit{t}, \lit{c} and \lit{b} do exactly
+% what they did before: control the vertical positioning of the table. The
+% uppercase ones control the \emph{horizontal} positioning -- this is how you
+% create \emph{unboxed} tables. You can only create unboxed tables in
+% paragraph mode.
+%
+% Note that unboxed tables still can't be broken across pages. Use
+% the \package{longtable} package for this, because it already does an
+% excellent job.
+%
+% \DescribeMacro{\tabpause}
+% One thing you can to with unboxed tables, however, is to `interrupt' them,
+% do some normal typesetting, and then continue. This is achieved by the
+% |\tabpause| command: its argument is written out in paragraph mode, and
+% the table is continued after the argument finishes.
+% Note that it isn't a real argument as far as commands like |\verb| are
+% concerned -- they'll work inside |\tabpause| without any problems.
+%
+% \DescribeMacro{\vline}
+% The |\vline| command draws a vertical rule the height of the current table
+% cell (unless the current cell is being typeset in paragraph mode -- it
+% only works in the simple LR-mode table cells, or in \lit{@} or \lit{!}
+% modifiers). It's now been given an optional argument which gives the
+% width of the rule to draw:
+%
+% { \let\tabstyle=\relax
+% \begin{demo}{An example of \cmd\vline}
+%\large
+%\begin{tabular}
+% {| c !{\vline[2pt]} c | c |}
+% \hlx{hv}
+% \bf A & \it B & \sf C \\
+% \hlx{vhv}
+% \bf D & \it E & \sf F \\
+% \hlx{vh}
+%\end{tabular}
+% \end{demo}
+% }
+%
+% \DescribeMacro{smarray}
+% You've probably noticed that there's an unfamiliar environment mentioned
+% in the syntax shown above. The \env{smarray} environment produces a
+% `small' array, with script size cells rather than the normal full text
+% size cells. I've seen examples of this sort of construction\footnote{^^A
+% There's a nasty use of \env{smallmatrix} in the |testmath.tex| file which
+% comes with the \package{amslatex} distribution. It's actually there to
+% simulate a `smallcases' environment, which the \package{mathenv} package
+% includes, based around \env{smarray}.}
+% being implemented by totally unsuitable commands. Someone may find it
+% handy.
+%
+%
+% \subsection{An updated \cs{cline} command}
+%
+% \DescribeMacro{\cline}
+% The standard \LaTeX\ |\cline| command has been updated. As well as just
+% passing a range of columns to draw lines through, you can now pass a comma
+% separated list of column numbers and ranges:
+%
+% \begin{grammar}
+% <cline-cmd> ::= \[[
+% "\\cline" "{" \< <number> \[ "-" <number> \] \\ "," \> "}"
+% \]]
+% \end{grammar}
+%
+% The positioning of the horizontal lines has also been improved a bit, so
+% that they meet up with the vertical lines properly. Displays like the one
+% in the example below don't look good unless this has been done properly.
+%
+% {\let\tabstyle\relax
+% \begin{demo}[w]{A \cs{cline} example}
+%\newcommand{\mc}{\multicolumn{1}}
+%\begin{tabular}[C]{|c|c|c|c|} \cline{2,4}
+% \mc{c|}{one} & two & three & four \\ \hline
+% five & six & seven & \mc{c}{eight} \\ \cline{1,3}
+%\end{tabular}
+% \end{demo}
+% }
+%
+% \subsection{Spacing control}
+%
+% One of the most irritating things about \LaTeX's tables is that there isn't
+% enough space around horizontal rules. Donald Knuth, in \textit{The
+% \TeX book}, describes addition of some extra vertical space here as `a mark
+% of quality', and since \TeX\ was designed to produce `beautiful documents'
+% it seems a shame that \LaTeX\ doesn't allow this to be done nicely. Well,
+% it does now.
+%
+% \DescribeMacro{\vgap}
+% The extra vertical space is added using a command |\vgap|, with the
+% following syntax:
+%
+% \begin{grammar}
+%
+% <vgap-cmd> ::= \[[
+% "\\vgap" \[ "[" <which-cols> "]" \] "{" <length> "}"
+% \]]
+%
+% <which-cols> ::= \[[ \< <number> \[ "-" <number> \] \\ "," \> \]]
+%
+% \end{grammar}
+%
+% This command must appear either immediately after the beginning of the
+% table or immediately after the |\\| which ends a row. (Actually, there are
+% other commands which also have this requirement -- you can specify a
+% collection of them wherever you're allowed to give any one.) It adds some
+% vertical space (the amount is given by the \<length>) to the table,
+% making sure that the vertical rules of the table are extended correctly.
+%
+% The |\vgap| command relies on information stored while your table preamble
+% is being examined. However, it's possible that you might not want some
+% of the rules drawn (e.g., if you've used |\multicolumn|). The optional
+% \<which-cols> argument allows you to specify which rules are \emph{not}
+% to be drawn. You can specify either single column numbers or ranges. The
+% rule at the very left hand side is given the number~0; the rules at the
+% end of column~$n$ are numbered~$n$. It's easy really.
+%
+% \DescribeMacro{\hlx}
+% Using |\vgap| is all very well, but it's a bit cumbersome, and takes up a
+% lot of typing, especially when combined with |\hline| commands. The |\hlx|
+% command tries to tidy things.
+%
+% The syntax is simple:
+% \begin{grammar}
+%
+% <hlx-cmd> ::= \[[
+% "\\hlx" "{"
+% \begin{rep}
+% \begin{stack}
+% "h" \\
+% \tok{"v["<which-cols>"]["<length>"]"} \\
+% \tok{"s["<length>"]"} \\
+% \tok{"c{"<which-cols>"}"} \\
+% "b" \\
+% \tok{"/["<number>"]"} \\
+% "."
+% \end{stack}
+% \end{rep}
+% "}"
+% \]]
+%
+% \end{grammar}
+% The argument works a bit like a table preamble, really. Each letter is a
+% command. The following are supported:
+%
+% \begin{description}
+%
+% \item [\lit*{h}] Works just like |\hline|. If you put two adjacent to each
+% other, a gap will be put between them.
+%
+% \item [\lit*{v[}\<which-cols>\lit*{][}\<length>\lit*{]}] Works
+% like \syntax{"\\vgap["<which-cols>"]{"<length>"}"}. If the
+% \<length> is omitted, the value of |\doublerulesep| is used.
+% This usually looks right.
+%
+% \item [\lit*{s[}\<length>\lit*{]}] Leaves a vertical gap with the
+% given size. If you omit the \<length> then |\doublerulesep| is
+% used. This is usually right.
+%
+% \item [\lit*{c\char`\{}\<which-cols>\lit*{\char`\}}] Works just like
+% |\cline|.
+%
+% \item [\lit*{b}] Inserts a backspace the width of a rule. This is useful
+% when doing \package{longtable}s.
+%
+% \item [\lit*{/[}\<number>\lit*{]}] Allows a page break in a table. Don't
+% use this except in a \env{longtable} environment. The \<number>
+% works exactly the same as it does in the |\pagebreak| command,
+% except that the default is 0, which just permits a break without
+% forcing it.
+%
+% \item [\lit*{.}] (That's a dot) Starts the next row of the table. No
+% more characters may follow the dot, and no |\hline|, |\hlx|, |\vgap|
+% or |\multicolumn| commands may be used after it. You don't have to
+% include it, and most of the time it's totally useless. It can be
+% handy for some macros, though. I used it in (and in fact added it
+% especially for) the table of column types.
+%
+% \end{description}
+%
+% An example of the use of |\hlx| is given, so you can see what's going on.
+%
+% \begin{figure}
+% \let\tabstyle\relax
+% \begin{demo}[w]{Beautiful table example}
+%\newcommand{\zerowidth}[1]{\hbox to 0pt{\hss#1\hss}}
+%\setlength{\tabcolsep}{1.5em}
+%\begin{tabular}[C]{| r | c | r |} \hlx{hv[1,2]}
+% \multicolumn{3}{|c|}{\bf AT\&T Common Stock} \\ \hlx{v[1,2]hv}
+% \multicolumn{1}{|c|}{\zerowidth{\bf Year}} &
+% \multicolumn{1}{c|}{\zerowidth{\bf Price}} &
+% \multicolumn{1}{c|}{\zerowidth{\bf Dividend}} \\ \hlx{vhv}
+% 1971 & 41--54 & \$2.60 \\
+% 2 & 41--54 & 2.70 \\
+% 3 & 46--55 & 2.87 \\
+% 4 & 40--53 & 3.24 \\
+% 5 & 45--52 & 3.40 \\
+% 6 & 51--59 & .95\rlap{*} \\ \hlx{vhs}
+% \multicolumn{3}{@{}l}{* (first quarter only)}
+%\end{tabular}
+% \end{demo}
+% \end{figure}
+%
+%
+% \subsection{Creating beautiful long tables}
+%
+% You can use the |\vgap| and |\hlx| commands with David Carlisle's
+% stunning \package{longtable} package. However, there are some things you
+% should be away of to ensure that your tables always come out looking
+% lovely.
+%
+% The \package{longtable} package will break a table at an |\hline| command,
+% leaving a rule at the bottom of the page and another at the top of the
+% next page. This means that a constructions like |\hlx{vhv}| will be
+% broken into something like |\hlx{vh}| at the bottom of the page and
+% |\hlx{hv}| at the top of the next. You need to design the table headers
+% and footers with this in mind.
+%
+% However, there appears to be a slight problem:\footnote
+% {You might very well call it a bug. I couldn't possibly comment.}
+% if the footer starts with an |\hline|, and a page is broken at an |\hline|,
+% then you get an extra thick rule at the bottom of the page. This is a bit
+% of a problem, because if the rule isn't there in the footer and you get
+% a break between two rows \emph{without} a rule between them, then the page
+% looks very odd.
+%
+% If you want to do ruled longtables, I'd recommend that you proceed as
+% follows:
+% \begin{itemize}
+% \item End header sections with an |\hlx{vh}|.
+% \item Begin footer sections with an |\hlx{bh}|.
+% \item Begin the main table with |\hlx{v}|.
+% \item Insert |\hlx{vhv}| commands in the main table body as usual.
+% \end{itemize}
+% If \package{longtable} gets modified appropriately, the use of the \lit{b}
+% command won't be necessary.
+%
+% Here's an example of the sort of thing you'd type.
+%
+% \begin{listinglist} \listingsize
+% \verb"\begin{longtable}[c]{|c|l|} \hlx{hv}" \\
+% \verb"\bf Heading & \bf Also heading \\ \hlx{vh}" \\
+% \verb"\endhead" \\
+% \verb"\hlx{bh}" \\
+% \verb"\endfoot" \\
+% \verb"\hlx{v}" \\
+% \verb"First main & table line \\ \hlx{vhv}" \\
+% \verb"Lots of text & like this \\ \hlx{vhv}" \\
+% \null\quad\vdots \\
+% \verb"Lots of text & like this \\ \hlx{vhv}" \\
+% \verb"Last main & table line \\ \hlx{vh}" \\
+% \verb"\end{longtable}"
+% \end{listinglist}
+%
+%
+% \subsection{Rules and vertical positioning}
+%
+% In the \LaTeXe\ and \package{array.sty} versions of \env{tabular}, you run
+% into problems if you try to use ruled tables together with the \lit{[t]} or
+% \lit{[b]} position specifiers -- the top or bottom rule ends up being
+% nicely lined up with the text baseline, giving you an effect which is
+% nothing like the one you expected. The \textit{\LaTeX\ Companion} gives
+% two commands |\firsthline| and |\lasthline| which are supposed to help with
+% this problem. (These commands have since migrated into the \package{array}
+% package.) Unfortunately, |\firsthline| doesn't do its job properly --
+% it gets the text position wrong by exactly the width of the table rules.
+%
+% The \package{mdwtab} package makes all of this automatic. It gets the
+% baseline positions exactly right, whether or not you use rules. Earlier
+% versions of this package required that you play with a length parameter
+% called |\rulefudge|; this is no longer necessary (or even possible -- the
+% length parameter no longer exists). The package now correctly compensates
+% for all sorts of rules and |\vgap|s at the top and bottom of a table and
+% it gets the positioning right all by itself. You've never had it so good.
+%
+%
+% \subsection{User serviceable parts}
+%
+% There are a lot of parameters which you can modify in order to make arrays
+% and tables look nicer. They are all listed in table~\ref{tbl:config}.
+%
+% \begin{table}
+% \begin{tabular}[C]{| l | m{3in} |} \hlx{hv}
+% \bf Parameter & \bf Meaning \\ \hlx{vhv}
+% |\tabstyle| & A command executed at the beginning of
+% a \env{tabular} or \env{tabular$*$}
+% environment. By default does nothing.
+% Change using |\renewcommand|. \\ \hlx{vhv}
+% |\extrarowheight| & A length added to the height of every
+% row, used to stop table rules
+% overprinting ascenders. Default 0\,pt.
+% Usage is deprecated now: use |\hlx|
+% instead. \\ \hlx{vhv}
+% |\tabextrasep| & Extra space added between rows in a
+% \env{tabular} or \env{tabular$*$}
+% environment (added \emph{before} any
+% following |\hline|). Default 0\,pt. \\
+% |\arrayextrasep| & Analogous to |\tabextrasep|, but for
+% \env{array} environments. Default
+% 1\,jot (3\,pt). \\
+% |\smarrayextrasep| & Analogous to |\tabextrasep|, but for
+% \env{smarray} environments. Default
+% 1\,pt. \\ \hlx{vhv}
+% |\tabcolsep| & Space added by default on each side of
+% a table cell (unless suppressed by an
+% \lit{@}-expression) in \env{tabular}
+% environments. Default is defined by
+% your document class. \\
+% |\arraycolsep| & Analogous to |\tabcolsep|, but for
+% \env{array} environments. Default is
+% defined by your document class. \\
+% |\smarraycolsep| & Analogous to |\tabcolsep|, but for
+% \env{smarray} environments. Default
+% is 3\,pt. \\ \hlx{vhv}
+% |\arrayrulewidth| & The width of horizontal and vertical
+% rules in tables. \\
+% |\doublerulesep| & Space added between two adjacent
+% vertical or horizontal rules. Also
+% used by |\hlx{v}|. \\ \hlx{vhv}
+% |\arraystretch| & Command containing a factor to
+% multiply the default row height.
+% Default is defined by your document
+% class (usually 1). \\ \hlx{vh}
+% \end{tabular}
+%
+% \caption{Parameters for configuring table environments}
+% \label{tbl:config}
+%
+% \end{table}
+%
+%
+% \subsection{Defining column types}
+%
+% \DescribeMacro{\newcolumntype}
+% The easy way to define new column types is using |\newcolumntype|. It
+% works in more or less the same way as |\newcommand|:
+%
+% \begin{grammar}
+%
+% <new-col-type-cmd> ::= \[[
+% "\\newcolumntype"
+% "{" <column-name> "}"
+% \[ "[" <num-args> "]" \]
+% \[ "[" <default-arg> "]" \]
+% "{" <first-column> \[ \< <column> \> \] "}"
+% \]]
+%
+% \end{grammar}
+%
+% (The \env{array.sty} implementation doesn't accept the \<default-arg>
+% argument. I've no idea why not, 'cos it was very easy to implement.)
+%
+% \DescribeMacro{\colset}
+% This implementation allows you to define lots of different sets of columns.
+% You can change the current set using the |\colset| declaration:
+% \begin{grammar}
+% <colset-cmd> ::= \[[ "\\colset" "{" <set-name> "}" \]]
+% \end{grammar}
+% This leaves a problem, though: at any particular moment, the current
+% column set could be anything, since other macros and packages can change
+% it.
+%
+% \DescribeMacro{\colpush}
+% \DescribeMacro{\colpop}
+% What actually happens is that a stack of column sets is maintained. The
+% |\colset| command just replaces the item at the top of the stack. The
+% command |\colpush| pushes its argument onto the top of the stack, making
+% it the new current set. The corresponding |\colpop| macro (which doesn't
+% take any arguments) removes the top item from the stack, reinstating the
+% previous current column set.
+%
+% \begin{grammar}
+% <colpush-cmd> ::= \[[ "\\colpush" "{" <set-name> "}" \]]
+% <colpop-cmd> ::= \[[ "\\colpop" \]]
+% \end{grammar}
+%
+% The macros which manipulate the column set stack work \emph{locally}.
+% The contents of the stack are saved when you open a new group.
+%
+% To make sure everyone behaves themselves properly, these are the rules for
+% using the column set stack:
+%
+% \begin{itemize}
+%
+% \item Packages defining column types must ensure that they preserve the
+% current column set. Either they must push their own column type
+% and pop it off when they're finished defining columns, or they must
+% avoid changing the stack at all, and use the optional arguments to
+% |\coldef| and |\collet|.
+%
+% \item Packages must not assume that any particular column set is current
+% unless they have made sure of it themselves.
+%
+% \item Packages must ensure that they pop exactly as much as they push.
+% There isn't much policing of this (perhaps there should be more),
+% so authors are encouraged to behave responsibly.
+%
+% \item Packages must change the current column set (using |\colset|) when
+% they start up their table environment. This will be restored when
+% the environment closes.
+%
+% \end{itemize}
+%
+% \DescribeMacro{\coldef}
+% |\newcolumntype| is probably enough for most purposes. However, Real
+% \TeX nicians, and people writing new table-generating environments, require
+% something lower-level.
+%
+% \begin{grammar}
+% <coldef-cmd> ::= \[[
+% "\\coldef"
+% \[ "[" <set-name> "]" \]
+% <col-name> <arg-template> "{" <replacement-text> "}"
+% \]]
+% \end{grammar}
+%
+% Note that this defines a column type in the current colset. It works
+% almost exactly the same way as \TeX's primitive |\def|. There is a
+% potential gotcha here: a |\tab@mkpream| token is inserted at the end of
+% your replacement text. If you need to read an optional argument or
+% something, you'll need to gobble this token before you carry on. The
+% |\@firstoftwo| macro could be handy here:
+% \begin{listing}
+%\coldef x{\@firstoftwo{\@ifnextchar[\@xcolumn@i\@xcolumn@ii}}}
+% \end{listing}
+% This isn't a terribly pretty state of affairs, and I ought to do something
+% about it. I've not seen any use for an optional argument yet, though.
+% Note that if you do gobble the |\tab@mkpream|, it's your responsibility to
+% insert another one at the very end of your macro's expansion (so that
+% further preamble characters can be read).
+%
+% The replacement text is inserted directly. It's normal to insert preamble
+% elements here. There are several to choose from:
+%
+% \begin{description}
+%
+% \item [Column items] provide the main `meat' of a column. You insert a
+% column element by saying
+% \syntax{"\\tabcoltype{"<pre-text>"}{"<post-text>"}"}.
+% The user's text gets inserted between these two. (So do user pre-
+% and post-texts. Bear this in mind.)
+%
+% \item [User pre-text items] work like the \lit{>} preamble command. You
+% use the \syntax{"\\tabuserpretype{"<text>"}"} command to insert it.
+% User pre-texts are written in \emph{reverse} order between the
+% pre-text of the column item and the text from the table cell.
+%
+% \item [User post-text items] work like the \lit{<} preamble command. You
+% use the \syntax{"\\tabuserposttype{"<text>"}"} command to insert it.
+% Like user pre-texts, user post-texts are written in reverse order,
+% between the table cell text and the column item post-text.
+%
+% \item [Space items] work like the \lit{@} preamble command. They're
+% inserted with the \syntax{"\\tabspctype{"<text>"}"} command.
+%
+% \item [Rule items] work like the `\verb"|"' and \lit{!} commands. You
+% insert them with the \syntax{"\\tabruletype{"<text>"}"} command.
+% Note that the text is inserted by |\vgap| too, so it should contain
+% things which adjust their vertical size nicely. If you really need
+% to, you can test |\iftab@vgap| to see if you're in a |\vgap|.
+%
+% \end{description}
+%
+% \DescribeMacro{\collet}
+% As well as defining columns, you can copy definitions (rather like |\let|
+% allows you to copy macros). The syntax is like this:
+%
+% \begin{grammar}
+%
+% <collet-cmd> ::= \[[
+% \[ "[" <set-name> "]" \] <col-name> \[ "=" \] \[ "[" <set-name> "]" \]
+% <col-name>
+% \]]
+%
+% \end{grammar}
+%
+% (In other words, you can copy defintions from other column sets.)
+%
+%
+% \subsection{Defining new table-generating environments}
+%
+% Quite a few routines are provided specifically to help you to define new
+% environments which do alignment in a nice way.
+%
+% \subsubsection{Reading preambles}
+%
+% The main tricky bit in doing table-like environments is parsing preambles.
+% No longer.
+%
+% \DescribeMacro{\tab@readpreamble}
+% \DescribeMacro{\tab@doreadpream}
+% The main parser routine is called |\tab@doreadpream|. Given a user
+% preamble string as an argument, it will build an |\halign| preamble to
+% return to you. However, the preamble produced won't be complete. This is
+% because you can actually make multiple calls to |\tab@doreadpream| with
+% bits of user preambles. The |\newcolumntype| system uses this mechanism,
+% as does the \lit{*} (repeating) modifier. When there really is no more
+% preamble to read, you need to \emph{commit} the heldover tokens to the
+% output. The |\tab@readpreamble| routine will do this for you -- given a
+% user preamble, it builds a complete output from it.
+%
+% A token register |\tab@preamble| is used to store the generated preamble.
+% Before starting, you must iniitialise this token list to whatever you want.
+% There's another token register, |\tab@shortline|, which is used to store
+% tokens used by |\vgap|. For each column in the table, the list contains
+% an |\omit| (to override the standard preamble) and an |\hfil| space taking
+% up most of the column. Finally, for each rule item in the user preamble,
+% the shortline list contains an entry of the form:
+% \begin{quote} \synshorts
+% "\\tab@ckr{"<column-number>"}{"<rule-text>"}"
+% \end{quote}
+% This is used to decide whether to print the rule or an empty thing of the
+% same width. You probably ought to know that the very first column does
+% \emph{not} have a leading |\omit| -- this is supplied by |\vgap| so that
+% it can then look for optional arguments.
+%
+% \DescribeMacro{\tab@initread}
+% As well as initialising |\tab@preamble| and emptying |\tab@shortline|,
+% there are several other operations required to initialise a preamble read.
+% These are all performed by the |\tab@initread| macro, although you may want
+% to change some of the values for your specific application. For reference,
+% the actions performed are:
+% \begin{itemize}
+% \item initialising the parser state by setting $|\tab@state| =
+% |\tab@startstate|$;
+% \item clearing the token lists |\tab@preamble| and |\tab@shortlist|;
+% \item initialising the macros |\tab@tabtext|, |\tab@midtext|, and
+% |\tab@multicol| to their default values of `|&|',
+% `|\ignorespaces#\unskip|' and the empty token list respectively.^^A
+% \footnote{^^A
+% These are macros rather than token lists to avoid hogging all
+% the token list registers. Actually, the package only allocates
+% two, although it does use almost all of the temporary registers as
+% well. Also, there's a lie: \cs{unskip} is too hamfisted to remove
+% trailing spaces properly; I really use a macro called
+% \cs{@maybe@unskip}}
+% \item clearing the internal token list registers |\tab@pretext|,
+% |tab@userpretext| and |\tab@posttext|;
+% \item clearing the column counter |\tab@columns| to zero;
+% \item clearing the action performed when a new column is started (by making
+% the |\tab@looped| macro equal to |\relax|; this is used to make
+% |\multicolumn| macro raise an error if you try to do more than one
+% column); and
+% \item setting up some other switches used by the parser (|\iftab@rule|,
+% |\iftab@initrule| and |\iftab@firstcol|, all of which are set to be
+% |true|).
+% \end{itemize}
+%
+% The macro |\tab@multicol| is used by the |\multicolumn| command to insert
+% any necessary items (e.g., struts) before the actual column text. If you
+% set this to something non-empty, you should probably consider adding a
+% call to the macro to the beginning of |\tab@preamble|.
+%
+% When parsing is finally done, the count register |\tab@columns| contains
+% the number of columns in the alignment. Don't corrupt this value, because
+% it's used for handling |\hline| commands.
+%
+% \subsubsection{Starting new lines}
+%
+% The other messy bit required by table environments is the newline command
+% |\\|. There are nasty complications involved with starting new lines, some
+% of which can be handled by this package, and some on which I can only give
+% advice.
+%
+% \DescribeMacro{\tab@cr}
+% The optional arguments and star-forms etc. can be read fairly painlessly
+% using the |\tab@cr| command:
+%
+% \begin{grammar}
+% <tabcr-cmd> ::= \[[
+% "\\tab@cr" <command> "{" <non-star-text> "}" "{" <star-text> "}"
+% \]]
+% \end{grammar}
+%
+% This will call your \<command> with two arguments. The first is the
+% contents of the optional argument, or `|\z@|' if there wasn't one. The
+% second is either \<star-text> or \<non-star-text> depending on
+% whether the user wrote the $*$-form or not.
+%
+% Somewhere in your \<command>, you'll have to use the |\cr| primitive to
+% end the table row. After you've done this, you \emph{must} ensure that you
+% don't do anything that gets past \TeX's mouth without protecting it --
+% otherwise |\hline| and co.\ won't work. I usually wrap things up in a
+% |\noalign| to protect them, although there are other methods. Maybe.
+%
+% You might like to have a look at the \env{eqnarray} implementation provided
+% to see how all this gets put into practice.
+%
+%
+% \subsection{The \env{mathenv} package alignment environments}
+%
+% The \env{mathenv} package provides several environments for aligning
+% equations in various ways. They're mainly provided as a demonstration of
+% the table handling macros in \package{mdwtab}, so don't expect great
+% things. If you want truly beautiful mathematics, use
+% \package{amsmath}.\footnote{^^A
+% Particularly since nice commands like \cmd\over\ are being reactivated
+% in a later release of \package{amsmath}.}
+% However, the various environments do nest in an approximately useful way.
+% I also think that the \env{matrix} and \env{script} environments provided
+% here give better results than their \package{amsmath} equivalents, and
+% they are certainly more versatile.
+%
+% \subsubsection{The new \env{eqnarray} environment}
+%
+% \DescribeEnv{eqnarray}
+% \DescribeEnv{eqnarray*}
+% As an example of the new column defining features, and because the original
+% isn't terribly good, I've included a rewritten version of the
+% \env{eqnarray} environment. The new implementation closes the gap between
+% \env{eqnarray} and \AmSTeX\ alignment features. It's in a separate,
+% package called \package{mathenv}, to avoid wasting your memory.
+%
+% \begin{grammar}
+%
+% <eqnarray-env> ::= \[[
+% <begin-eqnarray> \< <row> \\ "\\\\" \> <end-eqnarray>
+% \]]
+%
+% <begin-eqnarray> ::= \[[
+% "\\begin" \( "{eqnarray}" \\ "{eqnarray*}" \)
+% \[ "[" \< <eqa-column> \> "]" \]
+% \]]
+%
+% <eqa-column> ::= \[[
+% \[ "q" \\ ":" \]
+% \[ \< ">" "{" <pre-text> "}" \> \]
+% \begin{stack}
+% \[ "T" \] \( "r" \\ "c" \\ "l" \) \\
+% "L" \\
+% "x"
+% \end{stack}
+% \[ \< "<" "{" <post-text> "}" \> \]
+% \]]
+%
+% <end-eqnarray> ::= \[[
+% "\\end" \begin{stack} "{eqnarray}" \\ "{eqnarray*}" \end{stack}
+% \]]
+%
+% \end{grammar}
+%
+% Descriptions of the various column types are given in
+% table~\ref{tbl:eqnarray}.
+%
+% \begin{table}
+% \begin{tabular}[C]{| >{\synshorts} c | m{3in} |} \hlx{hv[1]}
+%
+% \multicolumn{2}{|c|}{\bf Column types} \\ \hlx{v[1]hv}
+% \bf Name & \bf Meaning \\ \hlx{vhv.}
+% "l" & Left aligned piece of equation. \\ \hlx{.}
+% "c" & Centred piece of equation. \\ \hlx{.}
+% "x" & Centred or flush-left whole equation
+% (depending on \textsf{fleqn} option). \\ \hlx{.}
+% "r" & Right aligned piece of equation. \\ \hlx{vhv.}
+% "L" & Left aligned piece of equation whose
+% width is considered to be 2\,em. \\ \hlx{vhv.}
+% "Tl", "Tc" and "Tr" & Left, centre and right aligned
+% text. \\ \hlx{vhhv[1]}
+%
+% \multicolumn{2}{|c|}{\bf Other modifier characters} \\ \hlx{v[1]hv}
+% \bf Name & \bf Meaning \\ \hlx{vhv.}
+% ":" & Leaves a big gap between equations.
+% By default, the `chunks' separated by
+% \lit{:}s are equally spaced on the
+% line. \\ \hlx{.}
+% "q" & Inserts 1\,em of space \\ \hlx{vhv.}
+% ">{"<text>"}" & Inserts \<text> just before the
+% actual column entry. \\ \hlx{.}
+% "<{"<text>"}" & Inserts \<text> just after the
+% actual column entry. \\ \hlx{vhv.}
+% "*{"<count>"}{"<chars>"}" & Inserts \<count>
+% copies of the \<chars> into the
+% preamble. \\ \hlx{vh}
+% \end{tabular}
+%
+% \caption{\package{eqnarray} column types and modifiers}
+% \label{tbl:eqnarray}
+% \end{table}
+%
+% The default preamble, if you don't supply one of your own, is \lit{rcl}.
+% Most of the time, \lit{rl} is sufficient, although compatibility is more
+% important to me.
+%
+% By default, there is no space between columns, which makes formul\ae\ in an
+% \env{eqnarray} environment look just like formul\ae\ typeset on their own,
+% except that things get aligned in columns. This is where the default
+% \env{eqnarray} falls down: it leaves |\arraycolsep| space between each
+% column making the thing look horrible.
+%
+% An example would be good here, I think. This one's from exercise 22.9 of
+% the \textit{\TeX book}.
+%
+% \begin{demo}[w]{Simultaneous equations}
+%\begin{eqnarray}[*3{rc}rl]
+% 10w & + & 3x & + & 3y & + & 18z & = 1 \\
+% 6w & - & 17x & & & - & 5z & = 2
+%\end{eqnarray}
+% \end{demo}
+%
+% Choosing a more up-to-date example, here's some examples from the
+% \textit{\LaTeX\ Companion}.
+%
+% \begin{demo}[w]{Lots of equations}
+%\begin{eqnarray}[rl:rl:lq]
+% V_i &= v_i - q_i v_j, & X_i &= x_i - q_i x_j, &
+% U_i = u_i, \qquad \mbox{for $i \ne j$} \\
+% V_j &= v_j, & X_j &= x_j &
+% U_j u_j + \sum_{i \ne j} q_i u_i. \label{eq:A}
+%\end{eqnarray}
+% \end{demo}
+%
+% \begin{figure}
+% \begin{demo}[w]{Plain text column and \cs{tabpause}}
+%\begin{eqnarray}[rlqqTl]
+% x &= y & by (\ref{eq:A}) \\
+% x' &= y' & by definition \\
+%\tabpause{and}
+% x + x' &= y + y' & by Axiom~1
+%\end{eqnarray}
+% \end{demo}
+% \end{figure}
+%
+% The new features also mean that you don't need to mess about with
+% |\lefteqn| any more. This is handled by the \lit{L} column type:
+%
+% \begin{demo}{Splitting example}
+%\begin{eqnarray*}[Ll]
+% w+x+y+z = \\
+% & a+b+c+d+e+ \\
+% & f+g+h+i+j
+%\end{eqnarray*}
+% \end{demo}
+%
+% Finally, just to prove that the spacing's right at last, here's another one
+% from the \textit{Companion}.
+%
+% \begin{demo}{Spacing demonstration}
+%\begin{equation}
+% x^2 + y^2 = z^2
+%\end{equation}
+%\begin{eqnarray}[rl]
+% x^2 + y^2 &= z^2 \\
+% y^2 &< z^2
+%\end{eqnarray}
+% \end{demo}
+%
+% Well, that was easy enough. Now on to numbering. As you've noticed, the
+% equations above are numbered. You can use the \env{eqnarray$*$}
+% environment to turn off the numbering in the whole environment, or say
+% |\nonumber| on a line to suppress numbering of that one in particular.
+%
+% \DescribeMacro{\eqnumber}
+% More excitingly, you can say |\eqnumber| to enable numbering for a
+% particular equation, or \syntax{"\\eqnumber["<text>"]"} to choose what to
+% show instead of the line number. This works for both starred and unstarred
+% versions of the environment. Now |\nonumber| becomes merely a synonym for
+% `|\eqnumber[]|'.
+%
+% A note for cheats: you can use the sparkly new \env{eqnarray} for simple
+% equations by specifying \lit{x} as the column description. Who needs
+% \AmSTeX?\ |;-)|
+%
+% \DescribeEnv{eqlines}
+% \DescribeEnv{eqlines*}
+% In fact, there's a separate environment \env{eqlines}, which is equivalent
+% to \env{eqnarray} with a single \lit{x} column; the result is that you can
+% insert a collection of displayed equations separated by |\\| commands. If
+% you don't like numbering, use \env{eqlines$*$} insead.
+%
+% \subsubsection{The \env{eqnalign} environment}
+%
+% \DescribeEnv{eqnalign}
+% There's a new environment, \env{eqnalign}, which does almost the same
+% thing as \env{eqnarray} but not quite. It doesn't do equation numbers,
+% and it wraps its contents up in a box. The result of this is that:
+%
+% \begin{itemize}
+%
+% \item You can use \env{eqnalign} for just a part of a formula.
+% The \env{eqnarray} environment must take up the whole display.
+%
+% \item You can use \env{eqnalign} within \env{eqnarray} for extra fine
+% alignment of subsidiary bits.
+%
+% \item You can break off from doing an \env{eqnarray} using the |\tabpause|
+% command. You can't use |\tabpause| inside
+% \env{eqnalign}.\footnote{^^A
+% Well, technically speaking there's nothing to stop you. However,
+% the results won't be pretty.}
+%
+% \end{itemize}
+%
+% The \env{eqnalign} environment works like this:
+%
+% \begin{grammar}
+%
+% <eqnalign-env> ::= \[[
+% <begin-eqnalign> <contents> <end-eqnalign>
+% \]]
+%
+% <begin-eqnalign> ::= \[[
+% "\\begin" "{eqnalign}"
+% \[ "[" \< <eqa-column> \> "]" \]
+% \[ "[" \( "t" \\ "c" \\ "b" \) "]" \]
+% \]]
+%
+% <end-eqnalign> ::= \[[ "\\end" "{eqnalign}" \]]
+%
+% \end{grammar}
+%
+% As the syntax suggests, the preamble for the \env{eqnalign} environment
+% works exactly the same way as for \env{eqnarray}. Example time: another
+% one from the \textit{\TeX book}.
+%
+% \begin{figure}
+% \begin{demo}[w]{Example of \env{eqnalign}}
+%\[
+% \left\{ \begin{eqnalign}[rl]
+% \alpha &= f(z) \\ \beta &= f(z^2) \\
+% \gamma &= f(z^3)
+% \end{eqnalign} \right\}
+% \qquad
+% \left\{ \begin{eqnalign}[rl]
+% x &= \alpha^2 - \beta \\ y &= 2\gamma
+% \end{eqnalign} \right\}.
+%\]
+% \end{demo}
+% \end{figure}
+%
+% \DescribeMacro{\multicolumn}
+% The |\multicolumn| command works correctly in both the \env{eqnarray} and
+% \env{eqnalign} environments, although you should bear in mind that you
+% should give \env{eqnarray} column types, not \env{array} ones.
+%
+% \subsubsection{A note on spacing in alignment environments}
+%
+% Most of the time, equations in \env{eqnarray} and \env{eqnalign}
+% environments will be beautiful. However, there are some things you should
+% bear in mind when you produce beautiful equations.
+%
+% The main problem with spacing is making sure that binary relations and
+% binary operators have the correct amount of space on each side of them.
+% The alignment environments insert `hidden' objects at the ends of table
+% cells to assist with the spacing: \lit{l} column types have a hidden object
+% on the left, \lit{r} types have a hidden object on the right, and \lit{c}
+% types have a hidden object on \emph{both} ends. These hidden objects add
+% the correct space when there's a binary operator or relation next to them.
+% If some other sort of object is lurking there, no space is added. So far,
+% so good.
+%
+% The only problem comes when you have something like this:
+%
+% \begin{demo}{How not to do an \env{eqnarray}}
+%\begin{eqnarray*}[rcl]
+% x + y & = & 12 \\
+% 2x - 5y & = & -6
+%\end{eqnarray*}
+% \end{demo}
+%
+% The `$-$' sign in the second equation has been treated as a binary operator
+% when really it should be a unary prefix operator, but \TeX\ isn't clever
+% enough to know the difference. (Can you see the difference in the spacing
+% between $-6$~and~${}-6$?) There are two possible solutions to the
+% problem. You could wrap the `|-6|' up in a group (`|{-6}|'), or just the
+% $-$ sign (`|{-}6|'). A better plan, though, is to get rid of the middle
+% column altogether:
+%
+% \begin{demo}{How to do an \env{eqnarray}}
+%\begin{eqnarray*}[rl]
+% x + y & = 12 \\
+% 2x - 5y & = -6
+%\end{eqnarray*}
+% \end{demo}
+%
+% Since the things in the middle column were the same width, it's not
+% actually doing any good. Also, now that \TeX\ can see that the thing on
+% the left of the `$-$' sign is a relation (the `$=$' sign), it will space
+% the formula correctly.
+%
+% In this case, it might be even better to add some extra columns, and line
+% up the $x$ and $y$ terms in the left hand side:
+%
+% \begin{demo}{Extra beautiful \env{eqnarray}}
+%\begin{eqnarray*}[rrl]
+% x + & y & = 12 \\
+% 2x - & 5y & = -6
+%\end{eqnarray*}
+% \end{demo}
+%
+% ^^A Some hacking now to display box sizes.
+%
+% {
+% \catcode`p=12 \catcode`t=12
+% \gdef\magni#1pt{#1}
+% }
+%
+% \newcommand{\widthof}[1]{^^A
+% \settowidth{\dimen0 }{#1}^^A
+% \expandafter\magni\the\dimen0\,pt^^A
+% }
+%
+% ^^A The text below makes an assumption which looks correct to me (I asked
+% ^^A TeX, and it agreed with me), although in case anything changes, I want
+% ^^A to be informed.
+%
+% \sbox0{$+$} \sbox2{$-$} \ifdim\wd0=\wd2\else%
+% \errmessage{Assertion failed: `+' and `-' are different widths!}
+% \fi
+%
+% There's no need to put the `$+$' and `$-$' operators in their own column
+% here, because they're both \widthof{$+$} wide, even though they don't
+% look it.
+%
+% \subsubsection{Configuring the alignment environments}
+%
+% There are a collection of parameters you can use to make the equation
+% alignment environments (\env{eqnarray} and \env{eqnalign}) look the way
+% you like them. These are all shown in table~\ref{tbl:eqnparms}.
+%
+% \begin{table}
+% \begin{tabular}[C]{| l | p{3in} |} \hlx{hv}
+% \bf Parameter & \bf Use \\ \hlx{vhv}
+% |\eqaopenskip| & Length put on the left of an
+% \env{eqnarray} environment. By
+% default, this is |\@centering| (to
+% centre the alignment) or |\mathindent|
+% (to left align) depending on whether
+% you're using the \textsf{fleqn}
+% document class option. \\
+% |\eqacloseskip| & Length put on the right of an
+% \env{eqnarray} environment. By
+% default, this is |\@centering|, to
+% align the environment correctly. \\ \hlx{vhv}
+% |\eqacolskip| & Space added by the \lit{:} column
+% modifier. This should be a rubber
+% length, although it only stretches in
+% \env{eqnarray}, not in \env{eqnalign}.
+% The default value is 1\smallf1/2\,em
+% with 1000\,pt of stretch. \\
+% |\eqainskip| & Space added at each side of a normal
+% column. By default this is 0\,pt. \\ \hlx{vhv}
+% |\eqastyle| & The maths style used in the alignment.
+% By default, this is |\textstyle|,
+% and you probably won't want to change
+% it. \\ \hlx{vh}
+% \end{tabular}
+%
+% \caption{Parameters for the \env{eqnarray} and \env{eqnalign} environments}
+% \label{tbl:eqnparms}
+% \end{table}
+%
+%
+% \subsection{Other multiline equations}
+%
+% Sometimes there's no sensible alignment point for splitting equations. The
+% normal thing to do under these circumstances is to put the first line way
+% over to the left of the page, and the last line over to the right. (If
+% there are more lines, I imagine we put them in the middle.)
+%
+% \DescribeEnv{spliteqn}
+% \DescribeEnv{spliteqn*}
+% The \env{spliteqn} environment allows you to do such splitting of
+% equations. Rather than tediously describe it, I'll just give an example,
+% because it's really easy. The $*$-version works the same, except it
+% doesn't put an equation number in.
+%
+% \begin{figure}
+% \begin{demo}[w]{A split equation}
+%\begin{spliteqn}
+% \sum_{1\le j\le n}
+% \frac {1} { (x_j - x_1) \ldots (x_j - x_{j-1})
+% (x - x_j) (x_j - x_{j+1}) \ldots (x_j - x_n) }
+% \\
+% = \frac {1} { (x - x_1) \ldots (x - x_n) }.
+%\end{spliteqn}
+% \end{demo}
+% \end{figure}
+%
+% \DescribeEnv{subsplit}
+% If you have a very badly behaved equation, you might want to split a part
+% of it (say, a bit of a fraction), particularly if you're doing things in
+% narrow columns.
+%
+% \begin{figure}
+% \begin{demo}[w]{A \env{subsplit} environment}
+%\begin{equation}
+% \frac{
+% \begin{subsplit}
+% q^{\frac{1}{2} n(n+1)}(ea; q^2)_\infty (eq/a; q^2)_\infty \\
+% (caq/e; q^2)_\infty (cq^2/ae; q^2)_\infty
+% \end{subsplit}
+% }{
+% (e; q)_\infty (cq/e; q)_\infty
+% }
+%\end{equation}
+% \end{demo}
+% \end{figure}
+%
+% \subsection{Matrices}
+%
+% Also included in the \package{mathenv} package is a collection of things
+% for typesetting matrices. The standard \env{array} doesn't (in my opinion)
+% provide the right sort of spacing for matrices. \PlainTeX\ provides some
+% quite nice matrix handling macros, but they don't work in the appropriate
+% \LaTeX\ way.
+%
+% \textbf{Warning:} These definitions will make old versions of
+% \package{plain.sty} unhappy; newer versions correctly restore the
+% Plain~\TeX\ macros |\matrix| and |\pmatrix|.
+%
+% \DescribeEnv{matrix}
+% The simple way to do matrices is with the \env{matrix} environment.
+%
+% \begin{grammar}
+%
+% <matrix-env> ::= \[[ <begin-matrix> <contents> <end-matrix> \]]
+%
+% <begin-matrix> ::= \[[ "\\begin{matrix}" \[ "[" <matrix-cols> "]" \] \]]
+%
+% <matrix-cols> ::= \[[
+% \< \[ "[" \] \[ "T" \] \( "l" \\ "c" \\ "r" \) \>
+% \]]
+%
+% <end-matrix> ::= \[[ "\\end{stack}" \]]
+%
+% \end{grammar}
+%
+% The \lit{l}, \lit{c} and \lit{r} columns are fairly obvious -- they align
+% their contents in the appropriate way. The \lit{[} character is more
+% complicated. It means `repeat the remaining column types forever', so a
+% preamble of \lit{cc[lr} means `two centred columns, then alternating left-
+% and right-aligned columns for as often as needed'. The default preamble,
+% if you don't specify one, is \lit{[c} -- `any number of centred columns'.
+%
+% \DescribeMacro{\multicolumn}
+% The |\multicolumn| command works correctly in matrices, although you should
+% bear in mind that you should give \env{matrix} column types, not
+% \env{array} ones.
+%
+% \DescribeEnv{pmatrix}
+% The standard \env{matrix} environment doesn't put any delimiters around the
+% matrix. You can use the standard |\left| and |\right| commands, although
+% this is a bit nasty. The \env{pmatrix} environment will put parentheses
+% around the matrix it creates; it's otherwise exactly the same as
+% \env{matrix}.
+%
+% \DescribeEnv{dmatrix}
+% A \env{dmatrix} environment is also provided. It takes two extra
+% arguments: the left and right delimiter characters (without |\left| or
+% |\right|).
+%
+% \begin{figure}
+% \begin{demo}[w]{Various \env{matrix} environments}
+%\[ \begin{matrix} 1 & 0 \\ 0 & -1 \end{matrix} \quad
+% \begin{pmatrix}
+% \cos\theta & \sin\theta \\
+% -\sin\theta & \cos\theta
+% \end{pmatrix} \quad
+% \begin{dmatrix}[] 0 & -i \\ i & 0 \end{dmatrix}
+%\]
+% \end{demo}
+% \end{figure}
+%
+% \DescribeEnv{smatrix}
+% Normal matrices always come out the same size; they don't change size
+% according to the surrounding context (unfortunately). However, it can be
+% occasionally useful to put matrices in running text, so you can talk about
+% $A$ being $\bigl( \begin{smatrix} a & b \\ b & c \end{smatrix} \bigr)$
+% being its own transpose (i.e., $A = A^T$). This is accomplished using the
+% \env{smatrix} (the `s' stands for `small' -- I thought that `smallmatrix'
+% was too big to type inline). As well as inline text, the \env{smatrix}
+% can be useful in displays, if the matrix is deep in a subformula. I can't
+% think of any examples offhand, though.
+%
+% \DescribeEnv{spmatrix}
+% \DescribeEnv{sdmatrix}
+% The \env{smatrix} environment doesn't supply any delimiters, like
+% \env{matrix}. There are \env{spmatrix} and \env{sdmatrix} environments
+% which do, though. Note that delimiters have a tendency to get too big and
+% mess up the line spacing -- I had to use explicitly |\big| delimiters
+% in the above example.
+%
+% \DescribeEnv{pmatrix*}
+% \DescribeEnv{spmatrix*}
+% \DescribeEnv{sdmatrix*}
+% All the small matrix environments have starred versions, which are more
+% suitable for use in displays, since they have more space between the rows.
+% They're intended for typesetting really big matrices in displays.
+%
+% \DescribeMacro{\ddots}
+% \DescribeMacro{\vdots}
+% The standard |\vdots| and |\ddots| commands don't produce anything at all
+% nice in small matrices, so this package redefines them so that they scale
+% properly to smaller sizes.
+%
+% \DescribeEnv{genmatrix}
+% Actually, all these environments are special cases of one: \env{genmatrix}.
+% This takes oodles of arguments:
+% \begin{quote} \synshorts
+% "\\begin{genmatrix}{"<matrix-style>"}{"<outer-style>"}" \\
+% \null \qquad "{"<spacing>"}{"<left-delim>"}{"<right-delim>"}" \\
+% \null \quad\vdots \\
+% "\\end{genmatrix}"
+% \end{quote}
+% The two `style' arguments should be things like |\textstyle| or
+% |\scriptstyle|; the first, \<matrix-style>, is the style to use for the
+% matrix elements, and the second, \<outer-style>, is the style to assume
+% for the surrounding text (this affects the spacing within the matrix; it
+% should usually be the same as \<matrix-style>). The \<spacing> is inserted
+% between the matrix and the delimiters, on each side of the matrix. It's
+% usually `|\,|' in full-size matrices, and blank for small ones. The
+% delimiters are inserted around the matrices, and sized appropriately.
+%
+% \DescribeEnv{newmatrix}
+% You can create your own matrix environments if you like, using the
+% |\newmatrix| command. It takes two arguments, although they're a bit
+% odd. The first is the name of the environment, and the second contains
+% the arguments to pass to \env{genmatrix}. For example, the \env{pmatrix}
+% environment was defined by saying
+%
+% \begin{listing}
+%\newmatrix{pmatrix}{{\textstyle}{\textstyle}{\,}{(}{)}}
+% \end{listing}
+%
+% If you don't pass all three arguments, then you end up requiring the
+% user to specify the remaining ones. This is how \env{dmatrix} works.
+%
+% \DescribeEnv{script}
+% Finally, although it's not really a matrix, stacked super- and subscripts
+% follow much the same sorts of spacing rules. The \env{script} environment
+% allows you to do this sort of thing very easily. It essentially provides
+% a `matrix' with the right sort of spacing. The default preamble string is
+% \lit{c}, giving you centred scripts, although you can say
+% |\begin{script}[l]| for left-aligned scripts, which is better if the
+% script is being placed to the right of its operator. If you're really
+% odd, you can have more than one column.
+%
+% \begin{demo}{Example of \env{script}}
+%\[ \mathop{{\sum}'}_{x \in A}
+% f(x)
+% \stackrel{\mathrm{def}}{=}
+% \sum_{\begin{script}
+% x \in A \\ x \ne 0
+% \end{script}} f(x)
+%\]
+% \end{demo}
+%
+%
+% \subsection{Other \package{mathenv} environments}
+%
+% The \package{mathenv} package contains some other environments which may
+% be useful, based on the enhanced \env{tabular} and \env{array}
+% environments.
+%
+% \DescribeEnv{cases}
+% The \env{cases} environment lets you say things like the following:
+%
+% \begin{demo}[w]{Example of \env{cases}}
+%\[ P_{r-j} = \begin{cases}
+% 0 & if $r-j$ is odd \\
+% r!\,(-1)^{(r-j)/2} & if $r-j$ is even
+% \end{cases}
+%\]
+% \end{demo}
+%
+% The spacing required for this is a bit messy, so providing an environment
+% for it is quite handy.
+%
+% \DescribeEnv{smcases}
+% The \env{smcases} environment works the same way as \env{cases}, but with
+% scriptsize lettering.
+%
+% \implementation
+%
+%
+%^^A-------------------------------------------------------------------------
+% \section{Implementation of table handling}
+%
+%
+% Here we go. It starts horrid and gets worse. However, it does stay nicer
+% than the original, IMHO.
+%
+% \begin{macrocode}
+%<*mdwtab>
+% \end{macrocode}
+%
+%
+% \subsection{Registers, switches and things}
+%
+% We need lots of these. It's great fun.
+%
+% The two count registers are simple enough:
+%
+% \begin{description}
+% \item [\cs{tab@state}] contains the current parser state. Since we
+% probably won't be parsing preambles recursively, this is a global
+% variable.
+% \item [\cs{tab@columns}] contains the number of the current column.
+% \item [\cs{tab@hlstate}] contains the state required for hline management.
+% \end{description}
+%
+% \begin{macrocode}
+\newcount\tab@state
+\newcount\tab@columns
+% \end{macrocode}
+%
+% We need \emph{lots} of token registers. Fortunately, most of them are only
+% used during parsing. We'll use \PlainTeX's scratch tokens for this. Note
+% that |\toks\tw@| isn't used here. It, and |\toks@|, are free for use by
+% column commands.
+%
+% \begin{macrocode}
+\newtoks\tab@preamble
+\newtoks\tab@shortline
+\toksdef\tab@pretext 4
+\toksdef\tab@posttext 6
+\toksdef\tab@userpretext 8
+% \end{macrocode}
+%
+% The dimens are fairly straightforward. The inclusion of |\col@sep| is a
+% sacrifice to compatibility -- judicious use of |\let| in \package{array}
+% would have saved a register.
+%
+% \begin{macrocode}
+\newdimen\extrarowheight
+\newdimen\tabextrasep
+\newdimen\arrayextrasep
+\newdimen\smarraycolsep
+\newdimen\smarrayextrasep
+\newdimen\tab@width
+\newdimen\col@sep
+\newdimen\tab@endheight
+% \end{macrocode}
+%
+% Some skip registers too. Phew.
+%
+% \begin{macrocode}
+\newskip\tab@leftskip
+\newskip\tab@rightskip
+% \end{macrocode}
+%
+% And some switches. The first three are for the parser.
+%
+% \begin{macrocode}
+\newif\iftab@firstcol
+\newif\iftab@initrule
+\newif\iftab@rule
+\newif\iftab@vgap
+% \end{macrocode}
+%
+% Now assign some default values to new dimen parameters. These definitions
+% are essentially the equivalent of an |\openup 1\jot| in \env{array}, but
+% not in \env{tabular}. This looks nice, I think.
+%
+% \begin{macrocode}
+\tabextrasep\z@
+\arrayextrasep\jot
+\smarraycolsep\thr@@\p@
+\smarrayextrasep\z@
+% \end{macrocode}
+%
+% Set some things up for alien table environments.
+%
+% \begin{macrocode}
+\let\tab@extrasep\tabextrasep
+\let\tab@penalty\relax
+% \end{macrocode}
+%
+%
+% \subsection{Some little details}
+%
+% \begin{macro}{\@maybe@unskip}
+%
+% This macro solves a little problem. In an alignment (and in other places)
+% it's desirable to suppress trailing space. The usual method, to say
+% |\unskip|, is a little hamfisted, because it removes perfectly reasonable
+% aligning spaces like |\hfil|s. While as a package writer I can deal with
+% this sort of thing by saying |\kern\z@| in appropriate places, it can
+% annoy users who are trying to use |\hfill| to override alignment in funny
+% places.
+%
+% My current solution seems to be acceptable. I'll remove the natural width
+% of the last glue item, so that it can still stretch and shrink if
+% necessary. The implementation makes use of the fact that multiplying
+% a \<skip> by a \<number> kills off the stretch. (Bug fix: don't do this
+% when we're in vertical mode.)
+%
+% \begin{macrocode}
+\def\@maybe@unskip{\ifhmode\hskip\m@ne\lastskip\relax\fi}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\q@delim}
+%
+% Finally, for the sake of niceness, here's a delimiter token I can use
+% for various things. It's a `quark', for what it's worth (i.e., it expands
+% to itself) although I'm not really sure why this is a good thing. As far
+% as I'm concerned, it's important that it has a unique meaning (i.e., that
+% it won't be |\ifx|-equal to other things, or something undefined) and that
+% it won't be used where I don't expect it to be used. \TeX\ will loop
+% horridly if it tries to expand this, so I don't think that quarks are
+% wonderfully clever thing to use. (Maybe it should really expand to
+% something like `\syntax{<quark>"."}', which will rapdly fill \TeX's memory
+% if it gets accidentally expanded. Still, I'll leave it as it is until
+% such time as I understand the idea more.)
+%
+% \begin{macrocode}
+\def\q@delim{\q@delim}
+% \end{macrocode}
+%
+% \end{macro}
+%
+%
+% \subsection{Parser states}
+%
+% Now we start on the parser. It's really simple, deep down. We progress
+% from state to state, extracing tokens from the preamble and building
+% command names from them. Each command calls one of the element-building
+% routines, which works out which state it should be in. We go through each
+% of the states in between (see later) doing default things for the ones we
+% missed out.
+%
+% Anyway, here's some symbolic names for the states. It makes my life
+% easier.
+%
+% \begin{macrocode}
+\chardef\tab@startstate 0
+\chardef\tab@loopstate 1
+\chardef\tab@rulestate 1
+\chardef\tab@prespcstate 2
+\chardef\tab@prestate 3
+\chardef\tab@colstate 4
+\chardef\tab@poststate 5
+\chardef\tab@postspcstate 6
+\chardef\tab@limitstate 7
+% \end{macrocode}
+%
+%
+% \subsection{Adding things to token lists}
+%
+% Define some macros for adding stuff to the beginning and end of token
+% lists. This is really easy, actually. Here we go.
+%
+% \begin{macrocode}
+\def\tab@append#1#2{#1\expandafter{\the#1#2}}
+\def\tab@prepend#1#2{%
+ \toks@{#2}#1\expandafter{\the\expandafter\toks@\the#1}%
+}
+% \end{macrocode}%
+%
+%
+% \subsection{Committing a column to the preamble}
+%
+% Each time we pass the `rule' state, we `commit' the tokens we've gathered
+% so far to the main preamble token list. This is how we do it. Note the
+% icky use of |\expandafter|.
+%
+% \begin{macrocode}
+\def\tab@commit{%
+% \end{macrocode}
+%
+% If this isn't the first column, then we need to put in a column separator.
+%
+% \begin{macrocode}
+ \iftab@firstcol\else%
+ \expandafter\tab@append\expandafter\tab@preamble%
+ \expandafter{\tab@tabtext}%
+ \fi%
+% \end{macrocode}
+%
+% Now we spill the token registers into the main list in a funny order (which
+% is why we're doing it in this strange way in the first place.
+%
+% \begin{macrocode}
+ \toks@\expandafter{\tab@midtext}%
+ \tab@preamble\expandafter{%
+ \the\expandafter\tab@preamble%
+ \the\expandafter\tab@pretext%
+ \the\expandafter\tab@userpretext%
+ \the\expandafter\toks@%
+ \the\tab@posttext%
+ }%
+% \end{macrocode}
+%
+% Now reset token lists and things for the next go round.
+%
+% \begin{macrocode}
+ \tab@firstcolfalse%
+ \tab@pretext{}%
+ \tab@userpretext{}%
+ \tab@posttext{}%
+}
+% \end{macrocode}
+%
+%
+% \subsection{Playing with parser states}
+%
+% \begin{macro}{\tab@setstate}
+%
+% This is how we set new states. The algorithm is fairly simple, really.
+%
+% ^^A Let's see how good my TeX really is... ;-)
+% ^^A Actually, it doesn't seem to have worked out too badly. Maybe I should
+% ^^A write a package to do this automatically. It's rather tricky, though.
+%
+% \def\qq{\mbox{\quad}}
+% \sbox{0}{\itshape\textunderscore}\def\_{\usebox{0}}
+%
+% \begin{quote}
+% {\bf while} $\it tab\_state \ne s$ {\bf do} \\
+% \qq $\mathit{tab\_state = tab\_state}+1$; \\
+% \qq {\bf if} $\it tab\_state = tab\_limitState$ {\bf then}
+% $\it tab\_state=tab\_loopState$; \\
+% \qq {\bf if} $\it tab\_state = tab\_preSpcState$ {\bf then} \\
+% \qq \qq {\bf if} $\it tab\_initRule$ {\bf then} \\
+% \qq \qq \qq $\it tab\_initRule = {\bf false}$; \\
+% \qq \qq {\bf else} \\
+% \qq \qq \qq {\bf if} $\it tab\_inMultiCol$ {\bf then moan}; \\
+% \qq \qq \qq $\it commit$; \\
+% \qq \qq \qq $\it append(tab\_shortLine,\hbox{`|&\omit|')}$; \\
+% \qq \qq {\bf end\,if}; \\
+% \qq {\bf end\,if}; \\
+% \qq {\bf if} $\it tab\_state \ne s$ {\bf then}
+% $\it do\_default(tab\_state)$; \\
+% {\bf end\,while};
+% \end{quote}
+%
+% First we decide if there's anything to do. If so, we call another macro to
+% do it for us.
+%
+% \begin{macrocode}
+\def\tab@setstate#1{%
+ \ifnum#1=\tab@state\else%
+ \def\@tempa{\tab@setstate@i{#1}}%
+ \@tempa%
+ \fi%
+}
+% \end{macrocode}
+%
+% This is where the fun is. First we bump the state by one, and loop back
+% if we fall off the end.
+%
+% \begin{macrocode}
+\def\tab@setstate@i#1{%
+ \global\advance\tab@state\@ne%
+ \ifnum\tab@state>\tab@limitstate%
+ \global\tab@state\tab@loopstate%
+ \fi%
+% \end{macrocode}
+%
+% Now, if we've just passed the ruleoff state, we commit the current text
+% \emph{unless} this was the strange initial rule at the very beginning. We
+% provide a little hook here so that |\multicolumn| can moan if you try and
+% give more than one column there. We also add another tab/omit pair to the
+% list we use for |\vgap|.
+%
+% \begin{macrocode}
+ \ifnum\tab@state=\tab@prespcstate%
+ \iftab@initrule%
+ \tab@initrulefalse%
+ \else%
+ \tab@looped%
+ \tab@commit%
+ \tab@append\tab@shortline{&\omit}%
+ \fi%
+ \fi%
+% \end{macrocode}
+%
+% Now we decide whether to go round again. If not, we do the default thing
+% for this state. This is mainly here so that we can put the |\tabcolsep| or
+% whatever in if the user didn't give an \lit{@} expression.
+%
+% \begin{macrocode}
+ \ifnum#1=\tab@state%
+ \let\@tempa\relax%
+ \else%
+ \csname tab@default@\number\tab@state\endcsname%
+ \fi%
+ \@tempa%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% Now we set up the default actions for the various states.
+%
+% In state~2 (pre-space) we add in the default gap if either we didn't have
+% an \lit{@} expression in the post-space state or there was an explicit
+% intervening rule.
+%
+% \begin{macrocode}
+\@namedef{tab@default@2}{%
+ \iftab@rule%
+ \tab@append\tab@pretext{\hskip\col@sep}%
+ \fi%
+}
+% \end{macrocode}
+%
+% If the user omits the column type, we insert an `l'-type column and moan
+% a lot.
+%
+% \begin{macrocode}
+\@namedef{tab@default@4}{%
+ \tab@err@misscol%
+ \tab@append\tab@pretext{\tab@bgroup\relax}%
+ \tab@append\tab@posttext{\relax\tab@egroup\hfil}%
+ \tab@append\tab@shortline{\hfil}%
+ \advance\tab@columns\@ne%
+}
+% \end{macrocode}
+%
+% Finally we deal with the post-space state. We set a marker so that we
+% put in the default space in the pre-space state later too.
+%
+% \begin{macrocode}
+\@namedef{tab@default@6}{%
+ \tab@append\tab@posttext{\hskip\col@sep}%
+ \tab@ruletrue%
+}
+% \end{macrocode}
+%
+%
+% \subsection{Declaring token types}
+%
+% \begin{macro}{\tab@extracol}
+%
+% Before we start, we need to handle |\extracolsep|. This is a right pain,
+% because the original version of \env{tabular} worked on total expansion,
+% which is a Bad Thing. On the other hand, turning |\extracolsep| into a
+% |\tabskip| is also a major pain.
+%
+% \begin{macrocode}
+\def\tab@extracol#1#2{\tab@extracol@i#1#2\extracolsep{}\extracolsep\end}
+\def\tab@extracol@i#1#2\extracolsep#3#4\extracolsep#5\end{%
+ \ifx @#3@%
+ \def\@tempa{#1{#2}}%
+ \else%
+ \def\@tempa{#1{#2\tabskip#3\relax#4}}%
+ \fi%
+ \@tempa%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% This is where we do the work for inserting preamble elements.
+%
+% \begin{macro}{\tabruletype}
+%
+% Inserting rules is interesting, because we have to decide where to put
+% them. If this is the funny initial rule, it goes in the pre-text list,
+% otherwise it goes in the post-text list. We work out what to do first
+% thing:
+%
+% \begin{macrocode}
+\def\tabruletype#1{\tab@extracol\tabruletype@i{#1}}%
+\def\tabruletype@i#1{%
+ \iftab@initrule%
+ \let\tab@tok\tab@pretext%
+ \else%
+ \let\tab@tok\tab@posttext%
+ \fi%
+% \end{macrocode}
+%
+% Now if we're already in the rule state, we must have just done a rule.
+% This means we must put in the |\doublerulesep| space, both here and in the
+% shortline list. Otherwise we just stick the rule in.
+%
+% This is complicated, because |\vgap| needs to be able to remove some bits
+% of rule. We pass each one to a macro |\tab@ckr|, together with the column
+% number, which is carefully bumped at the right times, and this macro will
+% vet the rules and output the appropriate ones. There's lots of extreme
+% |\expandafter| nastiness as a result. Amazingly, this actually works.
+%
+% \begin{macrocode}
+ \ifnum\tab@state=\tab@rulestate%
+ \tab@append\tab@tok{\hskip\doublerulesep\begingroup#1\endgroup}%
+ \expandafter\tab@append\expandafter\tab@shortline\expandafter{%
+ \expandafter\hskip\expandafter\doublerulesep%
+ \expandafter\tab@ckr\expandafter{\the\tab@columns}%
+ {\begingroup#1\endgroup}%
+ }%
+ \else%
+ \tab@setstate\tab@rulestate%
+ \tab@append\tab@tok{\begingroup#1\endgroup}%
+ \expandafter\tab@append\expandafter\tab@shortline\expandafter{%
+ \expandafter\tab@ckr\expandafter{\the\tab@columns}%
+ {\begingroup#1\endgroup}%
+ }%
+ \fi%
+% \end{macrocode}
+%
+% Finally, we say there was a rule here, so that default space gets put in
+% after this. Otherwise we lose lots of generality.
+%
+% \begin{macrocode}
+ \tab@ruletrue%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\tabspctype}
+%
+% We need to work out which space-state we should be in. Then we just put
+% the text in. Easy, really.
+%
+% \begin{macrocode}
+\def\tabspctype#1{\tab@extracol\tabspctype@i{#1}}%
+\def\tabspctype@i#1{%
+ \tab@rulefalse%
+ \ifnum\tab@state>\tab@prespcstate%
+ \tab@setstate\tab@postspcstate%
+ \let\tab@tok\tab@posttext%
+ \else%
+ \tab@setstate\tab@prespcstate%
+ \let\tab@tok\tab@pretext%
+ \fi%
+ \tab@append\tab@tok{\begingroup#1\endgroup}%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\tabcoltype}
+%
+% If we're already in the column state, we bump the state and loop round
+% again, to get all the appropriate default behaviour. We bump the column
+% counter, and add the bits of text we were given to appropriate token lists.
+% We also add the |\hfil| glue to the shortline list, to space out the rules
+% properly.
+%
+% \begin{macrocode}
+\def\tabcoltype#1#2{%
+ \ifnum\tab@state=\tab@colstate%
+ \global\advance\tab@state\@ne%
+ \fi%
+ \advance\tab@columns\@ne%
+ \tab@setstate\tab@colstate%
+ \tab@append\tab@pretext{#1}%
+ \tab@append\tab@posttext{#2}%
+ \tab@append\tab@shortline{\hfil}%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\tabuserpretype}
+% \begin{macro}{\tabuserposttype}
+%
+% These are both utterly trivial.
+%
+% \begin{macrocode}
+\def\tabuserpretype#1{%
+ \tab@setstate\tab@prestate%
+ \tab@prepend\tab@userpretext{#1}%
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\def\tabuserposttype#1{%
+ \tab@setstate\tab@poststate%
+ \tab@prepend\tab@posttext{#1}%
+}
+% \end{macrocode}
+%
+% \end{macro}
+% \end{macro}
+%
+%
+% \subsection{The colset stack}
+%
+% Let's start with something fairly easy. We'll keep a stack of column sets
+% so that users don't get confused by package authors changing the current
+% column set. This is fairly easy, really.
+%
+% \begin{macro}{\tab@push}
+% \begin{macro}{\tab@pop}
+% \begin{macro}{\tab@head}
+%
+% These are the stack management routines. The only important thing to note
+% is that |\tab@head| must take place \emph{only} in \TeX's mouth, so we can
+% use it in |\csname|\dots|\endcsname| constructions.
+%
+% \begin{macrocode}
+\def\tab@push#1#2{%
+ \toks@{{#2}}%
+ \expandafter\def\expandafter#1\expandafter{\the\expandafter\toks@#1}%
+}
+\def\tab@pop#1{\expandafter\def\expandafter#1\expandafter{\@gobble#1}}
+\def\tab@head#1{\expandafter\tab@head@i#1\relax}
+\def\tab@head@i#1#2\relax{#1}
+% \end{macrocode}
+%
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\colset}
+% \begin{macro}{\colpush}
+% \begin{macro}{\colpop}
+%
+% Now we can define the user macros.
+%
+% \begin{macrocode}
+\def\tab@colstack{{tabular}}
+\def\colset{\colpop\colpush}
+\def\colpush{\tab@push\tab@colstack}
+\def\colpop{\tab@pop\tab@colstack}
+% \end{macrocode}
+%
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\tab@colset}
+%
+% Now we define a shortcut for reading the top item off the stack.
+%
+% \begin{macrocode}
+\def\tab@colset{\tab@head\tab@colstack}
+% \end{macrocode}
+%
+% \end{macro}
+%
+%
+% \subsection{The main parser routine}
+%
+% \begin{macro}{\tab@initread}
+%
+% This macro sets up lots of variables to their normal states prior to
+% parsing a preamble. Some things may need changing, but not many.
+%
+% \begin{macrocode}
+\def\tab@initread{%
+% \end{macrocode}
+%
+% First, reset the parser state to the start state.
+%
+% \begin{macrocode}
+ \global\tab@state\tab@startstate%
+% \end{macrocode}
+%
+% We clear the token lists to sensible values, mostly. The midtext macro
+% contains what to put in the very middle of each template -- |\multicolumn|
+% will insert its argument here.
+%
+% \begin{macrocode}
+ \tab@preamble{}%
+ \tab@shortline{}%
+ \def\tab@tabtext{&}%
+ \def\tab@midtext{\ignorespaces####\@maybe@unskip}%
+ \tab@pretext{}%
+ \tab@userpretext{}%
+ \tab@posttext{}%
+ \let\tab@multicol\@empty%
+ \def\tab@startpause{\penalty\postdisplaypenalty\medskip}%
+ \def\tab@endpause{\penalty\predisplaypenalty\medskip}%
+% \end{macrocode}
+%
+% Finally, reset the column counter, don't raise errors when we loop, and set
+% some parser flags to their appropriate values.
+%
+% \begin{macrocode}
+ \tab@columns\z@%
+ \let\tab@looped\relax%
+ \tab@ruletrue%
+ \tab@initruletrue%
+ \tab@firstcoltrue%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\tab@readpreamble}
+%
+% This is the main macro for preamble handling. Actually, all it does is
+% gobble its argument's leading brace and call another macro, but it does it
+% with style.
+%
+% \begin{macrocode}
+\def\tab@readpreamble#1{%
+ \tab@doreadpream{#1}%
+ \iftab@initrule\global\tab@state\tab@prespcstate\fi%
+ \tab@setstate\tab@rulestate%
+ \tab@commit%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\tab@doreadpream}
+%
+% The preamble is in an argument. Previous versions used a nasty trick using
+% |\let| and |\afterassignment|. Now we use an explicit end token, to allow
+% dodgy column type handlers to scoop up the remaining preamble tokens
+% and process them. Not that anyone would want to do that, oh no (see
+% the \lit{[} type in the \env{eqnarray} environment |;-)|).
+%
+% \begin{macrocode}
+\def\tab@doreadpream#1{\tab@mkpreamble#1\q@delim}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\tab@mkpreamble}
+%
+% This is the main parser routine. It takes each token in turn, scrutinises
+% it carefully, and does the appropriate thing with it.
+%
+% The preamble was given as an argument to |\tab@doreadpream|, and that has
+% helpfully stripped off the initial |{| character. We need to pick off the
+% next token (whatever it is) so we can examine it. We'll use |\futurelet|
+% so we can detect groups and things in funny places.
+%
+% \begin{macrocode}
+\def\tab@mkpreamble{\futurelet\@let@token\tab@mkpreamble@i}
+% \end{macrocode}
+%
+% If we find a space token, we'll go off and do something a bit special,
+% since spaces are sort of hard to handle. Otherwise we'll do it in the old
+% fashioned way.
+%
+% \begin{macrocode}
+\def\tab@mkpreamble@i{%
+ \ifx\@let@token\@sptoken%
+ \expandafter\tab@mkpreamble@spc%
+ \else%
+ \expandafter\tab@mkpreamble@ii%
+ \fi%
+}
+% \end{macrocode}
+%
+% If we find a |\@@endpreamble| token, that's it and we're finished. We just
+% gobble it and return. Otherwise, if it's an open group character, we'll
+% complain because someone's probably tried to put an argument in the wrong
+% place. Finally, if none of the other things apply, we'll deal with the
+% character below.
+%
+% \begin{macrocode}
+\def\tab@mkpreamble@ii{%
+ \ifx\@let@token\q@delim%
+ \def\@tempa{\let\@let@token}%
+ \else%
+ \ifcat\bgroup\noexpand\@let@token%
+ \tab@err@oddgroup%
+ \def\@tempa##1{\tab@mkpreamble}%
+ \else%
+ \let\@tempa\tab@mkpreamble@iii%
+ \fi%
+ \fi%
+ \@tempa%
+}
+% \end{macrocode}
+%
+% Handle a character. This involves checking to see if it's actually
+% defined, and then doing it. Doing things this way means we won't get
+% stranded in mid-preamble unless a package author has blown it.
+%
+% \begin{macrocode}
+\def\tab@mkpreamble@iii#1{%
+ \@ifundefined{\tab@colset!col.\string#1}{%
+ \tab@err@undef{#1}\tab@mkpreamble%
+ }{%
+ \@nameuse{\tab@colset!col.\string#1}%
+ }%
+}
+% \end{macrocode}
+%
+% If we get given a space character, we'll look up the command name as
+% before. If no-one's defined the column type we'll just skip it silently,
+% which lets users do pretty formatting if they like.
+%
+% \begin{macrocode}
+\@namedef{tab@mkpreamble@spc} {%
+ \@ifundefined{\tab@colset!col. }{%
+ \tab@mkpreamble%
+ }{%
+ \@nameuse{\tab@colset!col. }%
+ }%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\coldef}
+%
+% Here's how to define column types the nice way. Some dexterity is required
+% to make everything work right, but it's simple really.
+%
+% \begin{macrocode}
+\def\coldef{\@ifnextchar[\coldef@i{\coldef@i[\tab@colset]}}
+\def\coldef@i[#1]#2#3#{\coldef@ii[#1]{#2}{#3}}
+\def\coldef@ii[#1]#2#3#4{%
+ \expandafter\def\csname#1!col.\string#2\endcsname#3{%
+ #4\tab@mkpreamble%
+ }%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\collet}
+%
+% We'd like to let people copy column types from other places. This is how
+% to do it.
+%
+% \begin{macrocode}
+\def\collet{\@ifnextchar[\collet@i{\collet@i[\tab@colset]}}
+\def\collet@i[#1]#2{%
+ \@ifnextchar=%
+ {\collet@ii[#1]{#2}}%
+ {\collet@ii[#1]{#2}=}%
+}
+\def\collet@ii[#1]#2={%
+ \@ifnextchar[%
+ {\collet@iii[#1]{#2}}%
+ {\collet@iii[#1]{#2}[\tab@colset]}%
+}
+\def\collet@iii[#1]#2[#3]#4{%
+ \expandafter\let\csname#1!col.\string#2\expandafter\endcsname%
+ \csname#3!col.\string#4\endcsname%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\newcolumntype}
+%
+% We just bundle the text off to |\newcommand| and expect it to cope. It
+% ought to. The column type code inserts the user's tokens directly, rather
+% than calling |\tab@doreadpream| recursively. The magic control sequence
+% is the one looked up by the parser.
+%
+% There's some additional magic here for compatiblity with the obscure way
+% that \package{array} works.
+%
+% \begin{macrocode}
+\def\newcolumntype#1{\@ifnextchar[{\nct@i{#1}}{\nct@i#1[0]}}
+\def\nct@i#1[#2]{\@ifnextchar[{\nct@ii{#1}[#2]}{\nct@iii{#1}{[#2]}}}
+\def\nct@ii#1[#2][#3]{\nct@iii{#1}{[#2][#3]}}
+\def\nct@iii#1#2#3{%
+ \expandafter\let\csname\tab@colset!col.\string#1\endcsname\relax%
+ \expandafter\newcommand\csname\tab@colset!col.\string#1\endcsname#2{%
+ \tab@deepmagic{#1}%
+ \tab@mkpreamble%
+ #3%
+ }%
+}
+% \end{macrocode}
+%
+% Now for some hacking for compatibility with \package{tabularx}.
+%
+% \begin{macrocode}
+\def\newcol@#1[#2]{\nct@iii{#1}{[#2]}}
+% \end{macrocode}
+%
+% And now some more. This is seriously deep magic. Hence the name.
+%
+% \begin{macrocode}
+\def\tab@deepmagic#1{%
+ \csname NC@rewrite@\string#1\endcsname\NC@find\tab@@magic@@%
+}
+\def\NC@find#1\tab@@magic@@{}
+% \end{macrocode}
+%
+% \end{macro}
+%
+%
+% \subsection{Standard column types}
+%
+% First, make sure we're setting up the right columns. This also sets the
+% default for the user. Other packages must not use the |\colset| command
+% for defining columns -- they should use the stack operations defined above.
+%
+% \begin{macrocode}
+\colset{tabular}
+% \end{macrocode}
+%
+% Now do the simple alignment types. These are fairly simple. The
+% mysterious kern in the \lit{l} type is to stop the |\col@sep| glue from
+% vanishing due to the |\unskip| inserted by the standard |\tab@midtext| if
+% the column contains no text. (Thanks for spotting this bug go to that
+% nice Mr~Carlisle.)
+%
+% \begin{macrocode}
+\coldef l{\tabcoltype{\kern\z@\tab@bgroup}{\tab@egroup\hfil}}
+\coldef c{\tabcoltype{\hfil\tab@bgroup}{\tab@egroup\hfil}}
+\coldef r{\tabcoltype{\hfil\tab@bgroup}{\tab@egroup}}
+% \end{macrocode}
+%
+% Some extensions now. These are explicitly teextual or mathematical
+% columns. Can be useful if you're providing column types for other people.
+% I've inserted a kern here for exactly the same reason as for the \lit{l}
+% column type above.
+%
+% \begin{macrocode}
+\coldef T#1{\tab@aligncol{#1}{\tab@btext}{\tab@etext}}
+\coldef M#1{\tab@aligncol{#1}{\tab@bmaths}{\tab@emaths}}
+\def\tab@aligncol#1#2#3{%
+ \if#1l\tabcoltype{\kern\z@#2}{#3\hfil}\fi%
+ \if#1c\tabcoltype{\hfil#2}{#3\hfil}\fi%
+ \if#1r\tabcoltype{\hfil#2}{#3}\fi%
+}
+% \end{macrocode}
+%
+% Now for the default rules.
+%
+% \begin{macrocode}
+\coldef |{\tabruletype{\vrule\@width\arrayrulewidth}}
+\coldef !#1{\tabruletype{#1}}
+% \end{macrocode}
+%
+% Deal with \lit{@} expressions.
+%
+% \begin{macrocode}
+\coldef @#1{\tabspctype{#1}}
+% \end{macrocode}
+%
+% And the paragraph types. I've added things to handle footnotes here.
+%
+% \begin{macrocode}
+\coldef p#1{\tabcoltype%
+ {\savenotes\vtop\tab@bpar{#1}}%
+ {\tab@epar\spewnotes\hfil}}
+\coldef m#1{\tabcoltype%
+ {\savenotes$\vcenter\tab@bpar{#1}}%
+ {\tab@epar$\spewnotes\hfil}}
+\coldef b#1{\tabcoltype%
+ {\savenotes\vbox\tab@bpar{#1}}%
+ {\tab@epar\spewnotes\hfil}}
+% \end{macrocode}
+%
+% Phew. Only a few more left now. The user text ones.
+%
+% \begin{macrocode}
+\coldef >#1{\tabuserpretype{#1}}
+\coldef <#1{\tabuserposttype{#1}}
+% \end{macrocode}
+%
+% The strange column type.
+%
+% \begin{macrocode}
+\coldef ##1#2{\tabcoltype{#1}{#2}}
+% \end{macrocode}
+%
+% And \lit{*}, which repeats a preamble spec. This is really easy, and not
+% at all like the original one.
+%
+% \begin{macrocode}
+\coldef *#1#2{%
+ \count@#1%
+ \loop\ifnum\count@>0\relax%
+ \tab@doreadpream{#2}%
+ \advance\count@\m@ne%
+ \repeat%
+}
+% \end{macrocode}
+%
+%
+% \subsection{Paragraph handling}
+%
+% First of all, starting new paragraphs: the vbox token is already there, and
+% we have the width as an argument.
+%
+% \begin{macro}{\tab@bpar}
+%
+% There are some gymnastics to do here to support lists which form the
+% complete text of the parbox. One of the odd things I'll do here is to
+% not insert a strut on the first line: instead, I'll put the text into a
+% box register so that I can inspect it later. So that I have access to
+% the height of the first line, I'll use a |\vtop| -- I can get at the
+% final depth by using |\prevdepth|, so this seems to be the most general
+% solution.
+%
+% \begin{macrocode}
+\def\tab@bpar#1{%
+ \bgroup%
+ \hsize#1\relax%
+ \@arrayparboxrestore%
+ \setbox\z@\vtop\bgroup
+ \global\@minipagetrue%
+ \everypar{%
+ \global\@minipagefalse%
+ \everypar{}%
+ }%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\tab@epar}
+%
+% To end the paragraph, close the box. That sounds easy, doesn't it?
+% I need to space out the top and bottom of the box so that it looks as if
+% struts have been applied.
+%
+% \begin{macrocode}
+\def\tab@epar{%
+% \end{macrocode}
+%
+% Anyway, I should end the current paragraph if I'm still in horizontal
+% mode. A simple |\par| will do this nicely. I'll also remove any trailing
+% vertical glue (which may be left there by a list environment), because
+% things will look very strange otherwise.
+%
+% \begin{macrocode}
+ \ifhmode\@maybe@unskip\par\fi%
+ \unskip%
+% \end{macrocode}
+%
+% Now I'll look at the depth of the last box: if it's less deep than my
+% special strut, I'll cunningly backpedal by a bit, and add a box with the
+% appropriate depth. Since this will lie on the previous baseline, it won't
+% alter the effective height of the box. There's a snag here. |\prevdepth|
+% may be wrong for example if the last thing inserted was a rule, or the
+% box is just empty. Check for this specially. (Thanks to Rowland for
+% spotting this.)
+%
+% \begin{macrocode}
+ \ifdim\prevdepth>-\@m\p@\ifdim\prevdepth<\dp\@arstrutbox%
+ \kern-\prevdepth%
+ \nointerlineskip%
+ \vtop to\dp\@arstrutbox{}%
+ \fi\fi%
+% \end{macrocode}
+%
+% I've finished the bottom of the box now: I'll close it, and start work on
+% the top again.
+%
+% \begin{macrocode}
+ \egroup%
+% \end{macrocode}
+%
+% For top-alignment to work, the first item in the box must be another box.
+% (This is why I couldn't just set |\prevdepth| at the beginning.) If the
+% box isn't high enough, I'll add a box of the right height and then kern
+% backwards so that the `real' first box ends up in the right place.
+%
+% \begin{macrocode}
+ \ifdim\ht\z@<\ht\@arstrutbox%
+ \vbox to\ht\@arstrutbox{}%
+ \kern-\ht\z@%
+ \fi%
+ \unvbox\z@%
+ \egroup%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+%
+% \subsection{Gentle persuasion}
+%
+% To persuade \package{longtable} to work, we emulate some features of
+% the \package{array} way of doing things. It's a shame, but we have to do
+% it, because \package{longtable} came first.
+%
+% Note the horribleness with the grouping here. In order to get everything
+% expanded at the right time, |\@preamble| just replaces itself with the (not
+% expanded!) preamble string, using |\the|. This means that the preamble
+% string must be visible in the group just above us. Now,
+% \package{longtable} (and \package{array} for that matter) does
+% |\@mkpreamble| immediately after opening a new group. So all we need to do
+% is close that group, do our stuff, and reopen the group again. (Evil
+% laughter\dots)
+%
+% \begin{macrocode}
+\def\@mkpream#1{%
+ \endgroup%
+ \colset{tabular}%
+ \tab@initread%
+ \def\tab@multicol{\@arstrut}%
+ \tab@preamble{\tab@multicol}%
+ \def\tab@midtext{\ignorespaces\@sharp\@sharp\@maybe@unskip}%
+ \tab@readpreamble{#1}%
+ \gdef\@preamble{\the\tab@preamble}%
+ \let\tab@bgroup\begingroup%
+ \let\tab@egroup\endgroup%
+ \begingroup%
+}
+% \end{macrocode}
+%
+%
+% \subsection{Debugging}
+%
+% This macro just parses a preamble and displays it on the terminal. It
+% means I can see whether the thing's working.
+%
+% \begin{macrocode}
+\def\showpream#1{%
+ \tab@initread%
+ \tab@readpreamble{#1}%
+ \showthe\tab@preamble%
+ \showthe\tab@shortline%
+}
+% \end{macrocode}
+%
+% A quick macro for showing column types.
+%
+% \begin{macrocode}
+\def\showcol#1{%
+ \expandafter\show\csname\tab@colset!col.\string#1\endcsname%
+}
+% \end{macrocode}
+%
+%
+% \subsection{The \env{tabular} and \env{array} environments}
+%
+% This is where we define the actual environments which users play with.
+%
+% \subsubsection{The environment routines}
+%
+% The real work is done in the |\@array| macro later. We just set up lots
+% (and I mean \emph{lots}) of parameters first, and then call |\@array|.
+%
+% \begin{macro}{\tab@array}
+%
+% The |\tab@array| macro does most of the common array things.
+%
+% \begin{macrocode}
+\def\tab@array{%
+ \tab@width\z@%
+ \let\tab@bgroup\tab@bmaths%
+ \let\tab@egroup\tab@emaths%
+ \@tabarray%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\tab@btext}
+% \begin{macro}{\tab@bmaths}
+% \begin{macro}{\tab@etext}
+% \begin{macro}{\tab@emaths}
+%
+% These macros contain appropriate things to use when typesetting
+% text or maths macros. They're all trivial. They're here only for
+% later modification by funny things like the \env{smarray} environment.
+%
+% \begin{macrocode}
+\def\tab@btext{\begingroup}
+\def\tab@bmaths{$}
+\def\tab@etext{\endgroup}
+\def\tab@emaths{\m@th$}
+% \end{macrocode}
+%
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{environment}{array}
+%
+% Now for the \env{array} environment. The `|$|' signs act as a group, so we
+% don't need to do extra grouping this time. Closing the environment is
+% easy.
+%
+% \begin{macrocode}
+\def\array{%
+ \col@sep\arraycolsep%
+ \let\tab@extrasep\arrayextrasep%
+ \tab@normalstrut%
+ \tab@array%
+}
+\def\endarray{%
+ \crcr%
+ \egroup%
+ \tab@right%
+ \tab@restorehlstate%
+}
+% \end{macrocode}
+%
+% \end{environment}
+%
+% \begin{environment}{smarray}
+%
+% Now for something a little different. The \env{smarray} environment
+% gives you an array with lots of small text.
+%
+% \begin{macrocode}
+\def\smarray{%
+ \extrarowheight\z@%
+ \col@sep\smarraycolsep%
+ \let\tab@extrasep\smarrayextrasep%
+ \def\tab@bmaths{$\scriptstyle}%
+ \def\tab@btext{\begingroup\scriptsize}%
+ \setbox\z@\hbox{\scriptsize\strut}%
+ \dimen@\ht\z@\dimen\tw@\dp\z@\tab@setstrut%
+ \tab@array%
+}
+\let\endsmarray\endarray
+% \end{macrocode}
+%
+% \end{environment}
+%
+% \begin{macro}{\tabstyle}
+%
+% This is a little hook that document designers can use to modify the
+% appearance of tables throughout a document. For example, I've set it to
+% make the text size |\small| in all tables in this document. Macro writers
+% shouldn't try to use it as a hook for their own evilness, though. I've
+% used |\providecommand| to avoid nobbling an existing definition.
+%
+% \begin{macrocode}
+\providecommand\tabstyle{}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\@tabular}
+%
+% The two \env{tabular} environments share lots of common code, so we
+% separate that out. (This needs to be done better.) All we really do here
+% is set up the |\tab@bgroup| and |\tab@egroup| to localise things properly,
+% and then go.
+%
+% \begin{macrocode}
+\def\@tabular#1{%
+ \tabstyle%
+ \tab@width#1%
+ \let\tab@bgroup\tab@btext%
+ \let\tab@egroup\tab@etext%
+ \col@sep\tabcolsep%
+ \let\tab@extrasep\tabextrasep%
+ \tab@normalstrut%
+ \@tabarray%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{environment}{tabular}
+% \begin{environment}{tabular*}
+%
+% These environments just call a macro which does all the common stuff.
+%
+% \begin{macrocode}
+\def\tabular{\@tabular\z@}
+\expandafter\let\csname tabular*\endcsname\@tabular
+\let\endtabular\endarray
+\expandafter\let\csname endtabular*\endcsname\endarray
+% \end{macrocode}
+%
+% \end{environment}
+% \end{environment}
+%
+% \subsubsection{Setting the strut height}
+%
+% \begin{macro}{\tab@setstrut}
+%
+% We use a magical strut, called |\@arstrut|, which keeps the table from
+% collapsing around our heads. This is where we set it up.
+%
+% It bases the array strut size on the given values of |\dimen@| and
+% |\dimen\tw@|, amended by various appropriate fiddle values added in by
+% various people.
+%
+% \begin{macrocode}
+\def\tab@setstrut{%
+ \setbox\@arstrutbox\hbox{%
+ \vrule%
+ \@height\arraystretch\dimen@%
+ \@depth\arraystretch\dimen\tw@%
+ \@width\z@%
+ }%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\tab@normalstrut}
+%
+% This sets the strut the normal way, from the size of |\strutbox|.
+%
+% \begin{macrocode}
+\def\tab@normalstrut{%
+ \dimen@\ht\strutbox\advance\dimen@\extrarowheight%
+ \dimen\tw@\dp\strutbox%
+ \tab@setstrut%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \subsubsection{Setting up the alignment}
+%
+% The following bits are mainly for other packages to hook themselves onto.
+%
+% \begin{macrocode}
+\let\@arrayleft\relax%
+\let\@arrayright\relax%
+% \end{macrocode}
+%
+% \begin{macrocode}
+\def\@tabarray{%
+ \let\@arrayleft\relax%
+ \let\@arrayright\relax%
+ \@ifnextchar[\@array{\@array[c]}%
+}
+% \end{macrocode}
+%
+% \begin{macro}{\@array}
+%
+% The |\@array| macro does most of the real work for the environments. The
+% first job is to set up the row strut, which keeps the table rows at the
+% right height. We just take the normal strut box, and extend its height by
+% the |\extrarowheight| length parameter.
+%
+% \begin{macrocode}
+\def\@array[#1]#2{%
+% \end{macrocode}
+%
+% Sort out the hline state variable. We'll store the old value in a
+% control sequence to avoid wasting any more count registers.
+%
+% \begin{macrocode}
+ \edef\tab@restorehlstate{%
+ \global\tab@endheight\the\tab@endheight%
+ \gdef\noexpand\tab@hlstate{\tab@hlstate}%
+ }%
+ \def\tab@hlstate{n}%
+% \end{macrocode}
+%
+% Now we read the preamble. All the clever things we've already done are
+% terribly useful here.
+%
+% The |\tab@setcr| sets up |\\| to be a newline even if users have changed it
+% using something like |\raggedright|.
+%
+% \begin{macrocode}
+ \colset{tabular}%
+ \tab@initread%
+ \def\tab@midtext{\tab@setcr\ignorespaces####\@maybe@unskip}%
+ \def\tab@multicol{\@arstrut\tab@startrow}%
+ \tab@preamble{\tab@multicol\tabskip\z@skip}%
+ \tab@readpreamble{#2}%
+% \end{macrocode}
+%
+% Set up the default tabskip glue. This is easy: there isn't any.
+%
+% \begin{macrocode}
+ \tab@leftskip\z@skip%
+ \tab@rightskip\z@skip%
+% \end{macrocode}
+%
+% Now set up the positioning of the table. This is put into a separate macro
+% because it's rather complicated.
+%
+% \begin{macrocode}
+ \tab@setposn{#1}%
+% \end{macrocode}
+%
+% Now work out how to start the alignment.
+%
+% \begin{macrocode}
+ \ifdim\tab@width=\z@%
+ \def\tab@halign{}%
+ \else%
+ \def\tab@halign{to\tab@width}%
+ \fi%
+% \end{macrocode}
+%
+% Finally, do all the normal things we need to do before an alignment. Note
+% that we define |\tabularnewline| first, then set |\\| from that (using
+% |\tab@setcr|). Since |\\| is reset in the |\tab@midtext| of every table
+% cell, it becomes secondary to |\tabularnewline|. Doing things this way
+% avoids the problems with declarations like |\raggedright| which redefine
+% |\\| in their own (usually rather strange) way, so you don't need to mess
+% about with things like the |\PreserveBackslash| command given in the
+% \textit{\LaTeX\ Companion}.
+%
+% \begin{macrocode}
+ \lineskip\z@\baselineskip\z@%
+ \m@th%
+ \def\tabularnewline{\tab@arraycr\tab@penalty}%
+ \tab@setcr%
+ \let\par\@empty%
+ \everycr{}\tabskip\tab@leftskip%
+ \tab@left\halign\tab@halign\expandafter\bgroup%
+ \the\tab@preamble\tabskip\tab@rightskip\cr%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% You've no doubt noticed the |\tab@left| and |\tab@right| macros above.
+% These are set up here and elsewhere to allow other things to gain control
+% at various points of the table (they include and take the place of the
+% |\@arrayleft| and |\@arrayright| hooks in \package{array}, put in for
+% \package{delarray}'s use.
+%
+% \subsubsection{Positioning the table}
+%
+% \begin{macro}{\tab@setposn}
+%
+% This macro sets everything up for the table's positioning. It's rather
+% long, but not all that complicated. Honest.
+%
+% First, we set up some defaults (for centring). If anything goes wrong, we
+% just do the centring things.
+%
+% \begin{macrocode}
+\def\tab@setposn#1{%
+ \def\tab@left{%
+ \savenotes%
+ \leavevmode\hbox\bgroup$\@arrayleft\vcenter\bgroup%
+ }%
+ \def\tab@right{%
+ \egroup%
+ \m@th\@arrayright$\egroup%
+ \spewnotes%
+ }%
+ \global\tab@endheight\z@%
+% \end{macrocode}
+%
+% For the standard positioning things, we just do appropriate boxing things.
+% Note that the dollar signs are important, since \package{delarray} might
+% want to put its delimiters in here.
+%
+% The |\if@tempswa| switch it used to decide if we're doing an unboxed
+% tabular. We'll set it if we find an unbox-type position code, and then
+% check that everything's OK for this.
+%
+% \begin{macrocode}
+ \@tempswafalse%
+ \let\tab@penalty\relax%
+ \if#1t%
+ \def\tab@left{%
+ \savenotes%
+ \leavevmode\setbox\z@\hbox\bgroup$\@arrayleft\vtop\bgroup%
+ }%
+ \def\tab@right{%
+ \egroup%
+ \m@th\@arrayright$\egroup%
+ \tab@raisebase%
+ \spewnotes%
+ }%
+ \gdef\tab@hlstate{t}%
+ \global\tab@endheight\ht\@arstrutbox%
+ \else\if#1b%
+ \def\tab@left{%
+ \savenotes%
+ \leavevmode\setbox\z@\hbox\bgroup$\@arrayleft\vbox\bgroup%
+ }%
+ \def\tab@right{%
+ \egroup%
+ \m@th\@arrayright$\egroup%
+ \tab@lowerbase%
+ \spewnotes%
+ }%
+ \gdef\tab@hlstate{b}%
+ \else%
+ \if#1L\@tempswatrue\fi%
+ \if#1C\@tempswatrue\fi%
+ \if#1R\@tempswatrue\fi%
+ \fi\fi%
+% \end{macrocode}
+%
+% Now for some tests to make sure we're allowed to do the unboxing. We text
+% for |\@arrayleft| being defined, because people trying to hook us won't
+% understand unboxed tabulars.
+%
+% \begin{macrocode}
+ \if@tempswa\ifhmode%
+ \ifinner\tab@err@unbrh\@tempswafalse\else\par\fi%
+ \fi\fi%
+ \if@tempswa\ifmmode\tab@err@unbmm\@tempswafalse\fi\fi%
+ \if@tempswa\ifx\@arrayleft\relax\else%
+ \tab@err@unbext\@tempswafalse%
+ \fi\fi%
+% \end{macrocode}
+%
+% Finally, if we're still doing an unboxed alignment, we need to sort out the
+% spacing. We know that no-one's tried to hook on to the environment, so we
+% clear |\tab@left| and |\tab@right|.
+%
+% \begin{macrocode}
+ \if@tempswa%
+ \def\tab@left{\vskip\parskip\medskip}%
+ \def\tab@right{\par\@endpetrue\global\@ignoretrue}%
+% \end{macrocode}
+%
+% Now we need to sort out the alignment. The only way we can do this is by
+% playing with tabskip glue. There are two possiblities:
+%
+% \begin{itemize}
+%
+% \item If this is a straight \env{tabular} or an \env{array}, we just use
+% infinite glue. This is reasonable, I think.
+%
+% \item If we have a width for the table, we calculate the fixed values of
+% glue on either side. This is fairly easy, and forces the table to
+% the required width.
+%
+% \end{itemize}
+%
+% First, set up the left and right glues to represent the prevailing
+% margins set up by \env{list} environments. I think this is the right
+% thing to do.
+%
+% \begin{macrocode}
+ \tab@leftskip\@totalleftmargin%
+ \tab@rightskip\hsize%
+ \advance\tab@rightskip-\linewidth%
+ \advance\tab@rightskip-\@totalleftmargin%
+% \end{macrocode}
+%
+% First of all, deal with the simple case. I'm using 10000\,fill glue here,
+% in an attempt to suppress |\extracolsep| glue from making the table the
+% wrong width. It can always use filll glue if it really needs to, though.
+%
+% \begin{macrocode}
+ \ifdim\tab@width=\z@%
+ \if#1L\else\advance\tab@leftskip\z@\@plus10000fill\fi%
+ \if#1R\else\advance\tab@rightskip\z@\@plus10000fill\fi%
+% \end{macrocode}
+%
+% Now for the fun bit. This isn't too hard really. The extra space I must
+% add around the table adds up to $|\linewidth| - |\tab@width|$. I just
+% need to add this onto the appropriate sides of the table.
+%
+% \begin{macrocode}
+ \else%
+ \dimen@\linewidth%
+ \advance\dimen@-\tab@width%
+ \if#1L\advance\tab@rightskip\dimen@\fi%
+ \if#1R\advance\tab@leftskip\dimen@\fi%
+ \if#1C%
+ \advance\tab@leftskip.5\dimen@%
+ \advance\tab@rightskip.5\dimen@%
+ \fi%
+ \fi%
+% \end{macrocode}
+%
+% Don't allow page breaks. David Carlisle's wonderful \env{longtable}
+% package does page breaks far better than I could possibly do here, and
+% we're compatible with it (wahey!).
+%
+% \begin{macrocode}
+ \def\tab@penalty{\penalty\@M}%
+% \end{macrocode}
+%
+% Finally, set the new width of the table, and leave.
+%
+% \begin{macrocode}
+ \tab@width\hsize%
+ \fi%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \subsubsection{Handling tops and bottoms}
+%
+% This is how the tops and bottoms of tables are made to line up with the
+% text on the same line, in the presence of arbitrary rules and space. The
+% old method, based on the way the \package{array} package worked, wasn't
+% terribly good. This new version copes much better with almost anything
+% that gets thrown at it.
+%
+% I'll keep a state in a macro (|\tab@hlstate|), which tells me what I'm
+% meant to be doing. The possible values are \lit{n}, which means I don't
+% have to do anything, \lit{t}, which means that I'm meant to be handling
+% top-aligned tables, and \lit{b}, which means that I'm meant to be lining
+% up the bottom. There are several other `substates' which have various
+% magic meanings.
+%
+% \begin{macrocode}
+\def\tab@hlstate{n}
+% \end{macrocode}
+%
+% When all's said and done, I extract the box containing the table, and
+% play with the height and depth to try and make it correct.
+%
+% \begin{macro}{\tab@addruleheight}
+%
+% This macro is called by `inter-row' things to add their height to our
+% dimen register.
+%
+% Only do this if the state indicates that it's sensible.
+%
+% \begin{macrocode}
+\def\tab@addruleheight#1{%
+ \if\tab@hlstate n\else%
+ \global\advance\tab@endheight#1\relax%
+ \fi%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\tab@startrow}
+%
+% This is called at the start of a row, from within the array preamble.
+% Currently, this assumes that the rows aren't bigger than their struts:
+% this is reasonable, although slightly limiting, and it could be done better
+% if I was willing to rip the alignment apart and put it back together
+% again.
+%
+% \begin{macrocode}
+\def\tab@startrow{%
+ \if\tab@hlstate t%
+ \gdef\tab@hlstate{n}%
+ \else\if\tab@hlstate b%
+ \global\tab@endheight\dp\@arstrutbox%
+ \fi\fi%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\tab@raisebase}
+%
+% This macro is called at the end of it all, to set the height and depth
+% of the box correctly. It sets the height to |\tab@endheight|, and the
+% depth to everything else. The box is in |\box|~0 currently.
+%
+% \begin{macrocode}
+\def\tab@raisebase{%
+ \global\advance\tab@endheight-\ht\z@%
+ \raise\tab@endheight\box\z@%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\tab@lowerbase}
+%
+% And, for symmetry's sake, here's how to set the bottom properly instead.
+%
+% \begin{macrocode}
+\def\tab@lowerbase{%
+ \global\advance\tab@endheight-\dp\z@%
+ \lower\tab@endheight\box\z@%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+%
+% \subsection{Breaking tables into bits}
+%
+% Unboxed tables have a wonderful advantage over boxed ones: you can stop
+% halfway through and do something else for a bit. Here's how:
+%
+% \begin{macro}{\tabpause}
+%
+% I'd like to avoid forbidding catcode changes here. I'll use |\doafter|
+% now I've got it, to ensure that colour handling and things occur
+% \emph{inside} the |\noalign| (otherwise they'll mess up the alignment
+% very seriously).
+%
+% We have to be careful here to ensure that everything works correctly within
+% lists. (The \package{amsmath} package had this problem in its
+% |\intertext| macro, so I'm not alone here.)
+%
+% \begin{macrocode}
+\def\tabpause#{%
+ \noalign{\ifnum0=`}\fi%
+ \@parboxrestore%
+ \tab@startpause%
+ \vskip-\parskip%
+ \parshape\@ne\@totalleftmargin\linewidth%
+ \noindent%
+ \doafter\tabpause@i%
+}
+\def\tabpause@i{%
+ \nobreak%
+ \tab@endpause%
+ \ifnum0=`{\fi}%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+%
+% \subsection{The wonderful world of \cmd\multicolumn}
+%
+% \begin{macro}{\multicolumn}
+%
+% This is actually fantasitcally easy. Watch and learn. Make sure you
+% notice the |\long|s here: remember that some table cells can contain
+% paragraphs, so it seems sensible to allow |\par| into the argument.
+% (As far as I know, most other |\multicolumn| commands don't do this,
+% which seems a little silly. Then again, I forgot to do it the first
+% time around.)
+%
+% \begin{macrocode}
+\long\def\multicolumn#1#2#3{%
+ \multispan{#1}%
+ \begingroup%
+ \tab@multicol%
+ \tab@initread%
+ \tab@preamble{}%
+ \long\def\tab@midtext{#3}%
+ \let\tab@looped\tab@err@multi%
+ \tab@readpreamble{#2}%
+ \the\tab@preamble%
+ \endgroup%
+ \ignorespaces%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+%
+% \subsection{Interlude: range lists}
+%
+% For processing arguments to |\vgap| and |\cline|, we need to be able to
+% do things with lists of column ranges. To save space, and to make my
+% fingers do less typing, here's some routines which do range handling.
+%
+% \begin{macro}{\ranges}
+%
+% Given a macro name and a comma separated list of ranges and simple numbers,
+% this macro will call the macro giving it each range in the list in turn.
+% Single numbers~$n$ will be turned into ranges $n$--$n$.
+%
+% The first job is to read the macro to do (which may already have some
+% arguments attached to it). We'll also start a group to make sure that
+% our changes to temp registers don't affect anyone else.
+%
+% There's a space before the delimiting |\q@delim| to stop numbers being
+% parsed to far and expanding our quark (which will stop \TeX\ dead in its
+% tracks). Since we use |\@ifnextchar| to look ahead, spaces in range lists
+% are perfectly all right.
+%
+% \begin{macrocode}
+\def\ranges#1#2{%
+ \gdef\ranges@temp{#1}%
+ \begingroup%
+ \ranges@i#2 \q@delim%
+}
+% \end{macrocode}
+%
+%
+% We're at the beginning of the list. We expect either the closing marker
+% (if this is an empty list) or a number, which we can scoop up into a
+% scratch register.
+%
+% \begin{macrocode}
+\def\ranges@i{%
+ \@ifnextchar\q@delim\ranges@done{\afterassignment\ranges@ii\count@}%
+}
+% \end{macrocode}
+%
+% We've read the first number in the range. If there's another number, we'll
+% expect a `|-|' sign to be next. If there is no `|-|', call the user's code
+% with the number duplicated and then do the rest of the list.
+%
+% \begin{macrocode}
+\def\ranges@ii{%
+ \@ifnextchar-\ranges@iii{\ranges@do\count@\count@\ranges@v}%
+}
+% \end{macrocode}
+%
+% Now we strip the `|-|' off and read the other number into a temporary
+% register.
+%
+% \begin{macrocode}
+\def\ranges@iii-{\afterassignment\ranges@iv\@tempcnta}
+% \end{macrocode}
+%
+% We have both ends of the range now, so call the user's code, passing it
+% both ends of the range.
+%
+% \begin{macrocode}
+\def\ranges@iv{\ranges@do\count@\@tempcnta\ranges@v}
+% \end{macrocode}
+%
+% We've finished doing an item now. If we have a `|,|' next, then start
+% over with the next item. Otherwise, if we're at the end of the list,
+% we can end happily. Finally, if we're totally confused, raise an
+% error.
+%
+% \begin{macrocode}
+\def\ranges@v{%
+ \@ifnextchar,%
+ \ranges@vi%
+ {%
+ \@ifnextchar\q@delim%
+ \ranges@done%
+ {\tab@err@range\ranges@vi,}%
+ }%
+}
+% \end{macrocode}
+%
+% We had a comma, so gobble it, read the next number, and go round again.
+%
+% \begin{macrocode}
+\def\ranges@vi,{\afterassignment\ranges@ii\count@}
+% \end{macrocode}
+%
+% Here's how we call the user's code, now. We close the group, so that the
+% user's code doesn't have to do global things to remember its results, and
+% we expand the two range ends from their count registers. We also ensure
+% that the range is the right way round.
+%
+% \begin{macrocode}
+\def\ranges@do#1#2{%
+ \ifnum#1>#2\else%
+ \expandafter\endgroup%
+ \expandafter\ranges@temp%
+ \expandafter{%
+ \the\expandafter#1%
+ \expandafter}%
+ \expandafter{%
+ \the#2%
+ }%
+ \begingroup%
+ \fi%
+}
+% \end{macrocode}
+%
+% And finishing the scan is really easy. We close the group after gobbling
+% the close token.
+%
+% \begin{macrocode}
+\def\ranges@done\q@delim{\endgroup}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\ifinrange}
+%
+% Something a little more useful, now. |\ifinrange| takes four arguments:
+% a number, a range list (as above), and two token lists which I'll call
+% \emph{then} and \emph{else}. If the number is in the list, I'll do
+% \emph{then}, otherwise I'll do \emph{else}.
+%
+% \begin{macrocode}
+\def\ifinrange#1#2{%
+ \@tempswafalse%
+ \count@#1%
+ \ranges\ifinrange@i{#2}%
+ \if@tempswa%
+ \expandafter\@firstoftwo%
+ \else%
+ \expandafter\@secondoftwo%
+ \fi%
+}
+\def\ifinrange@i#1#2{%
+ \ifnum\count@<#1 \else\ifnum\count@>#2 \else\@tempswatrue\fi\fi%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+%
+% \subsection{Horizontal rules OK}
+%
+% This is where all the gubbins for |\vgap| and friends is kept, lest it
+% contaminate fairly clean bits of code found elsewhere.
+%
+% \subsubsection{Drawing horizontal rules}
+%
+% \begin{macro}{\hline}
+%
+% Note the funny use of |\noalign| to allow \TeX\ stomach ops like
+% |\futurelet| without starting a new table row. This lets us see if there's
+% another |\hline| coming up, so we can see if we need to insert extra
+% vertical space.
+%
+% \begin{macrocode}
+\def\hline{%
+ \tab@dohline%
+ \noalign{\ifnum0=`}\fi%
+ \tab@penalty%
+ \futurelet\@let@token\hline@i%
+}
+% \end{macrocode}
+%
+% We check here for another |\hline| command, and insert glue if there is.
+% This looks terrible, though, and |\hlx{hvh}| is much nicer. Still\dots
+%
+% \begin{macrocode}
+\def\hline@i{%
+ \ifx\@let@token\hline%
+ \vskip\doublerulesep%
+ \tab@addruleheight\doublerulesep%
+ \fi%
+ \ifnum0=`{\fi}%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\tab@dohline}
+%
+% This is where hlines actually get drawn.
+% Drawing lines is more awkward than it used to be, particularly in unboxed
+% tables. It used to be a case simply of saying |\noalign{\hrule}|.
+% However, since unboxed tables are actually much wider than they look, this
+% would make the rules stretch right across the page and look generally
+% horrible.
+%
+% The solution is simple: we basically do a dirty big |\cline|.
+%
+% \begin{macrocode}
+\def\tab@dohline{%
+ \multispan{\tab@columns}%
+ \leaders\hrule\@height\arrayrulewidth\hfil%
+ \tab@addruleheight\arrayrulewidth%
+ \cr%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \subsubsection{Vertical rules}
+%
+% I couldn't fit these in anywhere else, so they'll have to go here. I'll
+% provide a new optional argument which specifies the width of the rule; this
+% gets rid of the problem described in the \emph{Companion}, where to get
+% an unusually wide vertical rule, you have to play with things like
+% \syntax{"\\vrule width" <dimen>} which really isn't too nice.
+%
+% \begin{macro}{\vline}
+%
+% The new |\vline| has an optional argument which gives the width of the
+% rule. The |\relax| stops \TeX\ trying to parse a \<rule-specification> for
+% too long, in case someone says something like `|\vline depthcharges|' or
+% something equally unlikely.
+%
+% \begin{macrocode}
+\renewcommand\vline[1][\arrayrulewidth]{\vrule\@width#1\relax}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \subsubsection{Drawing bits of lines}
+%
+% Just for a bit of fun, here's an extended version of |\cline| which takes
+% a list of columns to draw lines under, rather than just a single range.
+%
+% \begin{macro}{\cline}
+%
+% Not a single line of code written yet, and we already have a dilemma on
+% our hands. Multiple consecutive |\cline| commands are meant to draw
+% on the same vertical bit of table. But horizontal lines are meant to have
+% thickness now. Oh, well [sigh], we'll skip back on it after all.
+%
+% Now the problem remains how best to do the job. The way I see it, there
+% are three possibilities:
+%
+% \begin{itemize}
+%
+% \item We can start a table row, and then for each column of the table
+% (as recorded in |\tab@columns|) we look to see if that column is
+% listed in the range list and if so draw the rule. This requires
+% lots of scanning of the range list.
+%
+% \item We can take each range in the list, and draw rules appropriately,
+% just like the old |\cline| used to do, and starting a new table row
+% for each.
+%
+% \item We can start a table row, and then for each range remember where we
+% stopped drawing the last row, move to the start of the new one, and
+% draw it. If we start moving backwards, we close the current row
+% and open a new one.
+%
+% \end{itemize}
+%
+% The last option looks the most efficient, and the most difficult. This
+% is therefore what I shall do |;-)|.
+%
+% The first thing to do is to add in a little negative space, and start a
+% table row (omitting the first item). Then scan the range list, and finally
+% close the table row and add some negative space again.
+%
+% We need a global count register to keep track of where we are. Mixing
+% local and global assignments causes all sorts of tragedy, so I shall hijack
+% |\tab@state|.
+%
+% \begin{macrocode}
+\def\cline#1{%
+ \noalign{\kern-.5\arrayrulewidth\tab@penalty}%
+ \omit%
+ \global\tab@state\@ne%
+ \ranges\cline@i{#1}%
+ \cr%
+ \noalign{\kern-.5\arrayrulewidth\tab@penalty}%
+}
+% \end{macrocode}
+%
+% Now for the tricky bit. When we're given a range, we look to see if the
+% first number is less than |\tab@state|. If so, we quickly close the
+% current row, kern backwards and start again with an |\omit| and reset
+% |\tab@state| to 1, and try again.
+%
+% \begin{macrocode}
+\def\cline@i#1#2{%
+ \ifnum#1<\tab@state\relax%
+ \tab@@cr%
+ \noalign{\kern-\arrayrulewidth\tab@penalty}%
+ \omit%
+ \global\tab@state\@ne%
+ \fi%
+% \end{macrocode}
+%
+% We are now either at or in front of the column position required. If
+% we're too far back, we must |\hfil&\omit| our way over to the correct%
+% column.
+%
+% \begin{macrocode}
+ \@whilenum\tab@state<#1\do{%
+ \hfil\tab@@tab@omit%
+ \global\advance\tab@state\@ne%
+ }%
+% \end{macrocode}
+%
+% We've found the start correctly. We must deal with a tiny problem now:
+% if this is not the first table cell, the left hand vertical rule is in the
+% column to the left, so our horizontal rule won't match up properly. So
+% we skip back by a bit to compensate. If there isn't actually a vertical
+% rule to line up with, no-one will notice, because the rules are so thin.
+% This adds a little touch of quality to the whole thing, which is after all
+% the point of this whole exercise.
+%
+% \begin{macrocode}
+ \ifnum\tab@state>\@ne%
+ \kern-\arrayrulewidth%
+ \fi%
+% \end{macrocode}
+%
+% Now we must stretch this table cell to the correct width.
+%
+% \begin{macrocode}
+ \@whilenum\tab@state<#2\do{%
+ \tab@@span@omit%
+ \global\advance\tab@state\@ne%
+ }%
+% \end{macrocode}
+%
+% We're ready. Draw the rule. Note that this is |\hfill| glue, just in case
+% we start putting in |\hfil| glue when we step onto the next cell.
+%
+% \begin{macrocode}
+ \leaders\hrule\@height\arrayrulewidth\hfill%
+}
+% \end{macrocode}
+%
+% Some alignment primitives are hidden inside macros so they don't get seen
+% at the wrong time. This is what they look like:
+%
+% \begin{macrocode}
+\def\tab@@cr{\cr}
+\def\tab@@tab@omit{&\omit}
+\def\tab@@span@omit{\span\omit}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \subsubsection{Drawing short table rows}
+%
+% Before I start on a description of more code, I think I'll briefly discuss
+% my reasons for leaving the |\vgap| command in its current state. There's a
+% reasonable case for introducing an interface between |\vgap| and
+% |\multicolumn|, to avoid all the tedious messing about with column
+% ranges. There are good reasons why I'm not going to do this:
+%
+% \begin{itemize}
+%
+% \item It's very difficult to do: it requires either postprocessing of
+% the table or delaying processing of each row until I know exactly
+% what's in it; a |\multicolumn| in a row should be able to affect
+% a |\vgap| before the row, which gets very nasty. This package is
+% probably far too large already, and adding more complexity and
+% running the risk of exhausting \TeX's frustratingly finite capacity
+% for the sake of relieving the user of a fairly trivial job doesn't
+% seem worthwhile.
+%
+% \item Perhaps more importantly, there are perfectly valid occasions when
+% it's useful to have the current vgap behaviour. For example, the
+% \texttt{MIX} word layout diagrams found in \emph{The Art of
+% Computer Programming} use the little `stub lines' to show where
+% data items cross byte boundaries:
+%
+% ^^A This actually looks terrifyingly similar to the original.
+% ^^A The leading @{} is there to stop the table looking off-centre,
+% ^^A because there's no left hand rule telling you where the table
+% ^^A starts, like there is on the right, just the \tabcolsep glue.
+%
+% \begingroup
+% \newcommand{\wide}[2]{\multicolumn{#1}{c|}{\ttfamily #2}}
+% \begin{tabular}[C]{@{} r @{\qquad} | Mc | *{5}{c|}} \hlx{c{2-7} v}
+% empty & - & 1 & 0 & 0 & 0 & 0 \\ \hlx{v c{2-7} v}
+% occupied & + & \wide{2}{LINK} & \wide{3}{KEY} \\ \hlx{v c{2-7}}
+% \end{tabular}
+% \endgroup
+%
+% \end{itemize}
+%
+% That's my excuses out of the way; now I'll press on with the actual
+% programming.
+%
+% \begin{macro}{\tab@checkrule}
+%
+% We have a range list in |\tab@xcols| and a number as an argument. If we
+% find the number in the list, wejust space out the following group,
+% otherwise we let it be.
+%
+% \begin{macrocode}
+\def\tab@checkrule#1{%
+ \count@#1\relax%
+ \expandafter\ifinrange%
+ \expandafter\count@%
+ \expandafter{\tab@xcols}%
+ {\tab@checkrule@i}%
+ {}%
+}
+\def\tab@checkrule@i#1{\setbox\z@\hbox{#1}\hb@xt@\wd\z@{}}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\vgap}
+%
+% We must tread carefully here. A single misplaced stomach operation can
+% cause error messages. We therefore start with an |\omit| so we can search
+% for optional arguments.
+%
+% So that |\hlx| can get control after |\vgap| has finished, we provide a
+% hook called |\vgap@after| which is expanded after |\vgap| has finished.
+% Here we make it work like |\@empty|, which expands to nothing. (Note that
+% |\relax| will start a new table row, so we can't use that.) There are
+% some penalty items here to stick the |\vgap| row to the text row and
+% |\hline| that are adjacent to it. The \package{longtable} package will
+% split an |\hline| in half, so this is the correct thing to do.
+%
+% \begin{macrocode}
+\def\vgap{%
+ \noalign{\nobreak}%
+ \omit%
+ \global\let\vgap@after\@empty%
+ \iffalse{\fi\ifnum0=`}\fi%
+ \@ifnextchar[\vgap@i\vgap@simple%
+}
+% \end{macrocode}
+%
+% We set up two different sorts of |\vgap| -- a simple one which allows all
+% rules to be passed through, and a specific one which carefully vets each
+% one (and is therefore slower). We decide which to so based on the presence
+% of an optional argument.
+%
+% The optional argument handler just passes its argument to an interface
+% routine which is used by |\hlx|.
+%
+% \begin{macrocode}
+\def\vgap@i[#1]{\vgap@spec{#1}}
+% \end{macrocode}
+%
+% Now we handle specified columns. Since we're in an omitted table cell, we
+% must set things up globally. Assign the column spec to a macro, and set up
+% vetting by the routine above. Then just go and do the job.
+%
+% \begin{macrocode}
+\def\vgap@spec#1#2{%
+ \gdef\tab@xcols{#1}%
+ \global\let\tab@ckr\tab@checkrule%
+ \vgap@do{#2}%
+}
+% \end{macrocode}
+%
+% Handle all columns. Just gobble the column number for each rule, and let
+% the drawing pass unharmed. Easy.
+%
+% \begin{macrocode}
+\def\vgap@simple#1{%
+ \global\let\tab@ckr\@gobble%
+ \vgap@do{#1}%
+}
+% \end{macrocode}
+%
+% This is where stuff actually gets done. We set the |\vgap| flag on while
+% we do the short row. Then just expand the token list we built while
+% scanning the preamble.
+%
+% Note that the flag is cleared at the end of the last column, to allow other
+% funny things like |\noalign| and |\omit| before a new row is started.
+%
+% \begin{macrocode}
+\def\vgap@do#1{%
+ \ifnum0=`{}\fi%
+ \global\tab@vgaptrue%
+ \the\tab@shortline%
+ \vrule\@height#1\@width\z@%
+ \global\tab@vgapfalse
+ \tab@addruleheight{#1}%
+ \cr%
+ \noalign{\nobreak}%
+ \vgap@after%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \subsubsection{Prettifying syntax}
+%
+% \begin{macro}{\hlx}
+%
+% This is like a poor cousin to the preamble parser. The whole loop is
+% carefully written to take place \emph{only} in \TeX's mouth, so the
+% alignment handling bits half way down the gullet don't see any of this.
+%
+% First, pass the string to another routine.
+%
+% \begin{macrocode}
+\def\hlx#1{\hlx@loop#1\q@delim}
+% \end{macrocode}
+%
+% Now peel off a token, and dispatch using |\csname|. We handle
+% undefinedness of the command in a fairly messy way, although it probably
+% works. Maybe.
+%
+% \begin{macrocode}
+\def\hlx@loop#1{%
+ \ifx#1\q@delim\else%
+ \@ifundefined{hlx@cmd@\string#1}{%
+ \expandafter\hlx@loop%
+ }{%
+ \csname hlx@cmd@\string#1\expandafter\endcsname%
+ }%
+ \fi%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\hlxdef}
+%
+% New |\hlx| commands can be defined using |\hlxdef|. This is a simple
+% abbreviation.
+%
+% \begin{macrocode}
+\def\hlxdef#1{\@namedef{hlx@cmd@#1}}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\hlx h}
+%
+% Handle an \lit{h} character. Just do an |\hline| and return to the loop.
+% We look ahead to see if there's another \lit{h} coming up, and if so
+% insert two |\hline| commands. This strange (and inefficient) behaviour
+% keeps packages which redefine |\hline| happy.
+%
+% \begin{macrocode}
+\hlxdef h#1{%
+ \noalign{%
+ \ifx#1h%
+ \def\@tempa{\hline\hline\hlx@loop}%
+ \else%
+ \def\@tempa{\hline\hlx@loop#1}%
+ \fi%
+ \expandafter
+ }%
+ \@tempa%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\hlx b}
+%
+% The \lit{b} character does a nifty backspace, for \package{longtable}'s
+% benefit.
+%
+% \begin{macrocode}
+\hlxdef b{\noalign{\kern-\arrayrulewidth}\hlx@loop}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\hlx /}
+%
+% The `"/"' character allows a page break at the current position.
+%
+% \begin{macrocode}
+\hlxdef /{%
+ \noalign{\ifnum0=`}\fi%
+ \@ifnextchar[\hlx@cmd@break@i{\hlx@cmd@break@i[0]}%
+}
+\def\hlx@cmd@break@i[#1]{\ifnum0=`{\fi}\pagebreak[0]\hlx@loop}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\hlx v}
+%
+% Handle a \lit{v} character. This is rather like the |\vgap| code above,
+% although there are syntactic differences.
+%
+% \begin{macrocode}
+\hlxdef v{%
+ \noalign{\nobreak}%
+ \omit%
+ \iffalse{\fi\ifnum0=`}\fi%
+ \global\let\vgap@after\hlx@loop%
+ \@ifnextchar[\hlx@vgap@i{\hlx@vgap@ii\vgap@simple}%
+}
+\def\hlx@vgap@i[#1]{%
+ \ifx!#1!%
+ \def\@tempa{\hlx@vgap@ii\vgap@simple}%
+ \else%
+ \def\@tempa{\hlx@vgap@ii{\vgap@spec{#1}}}%
+ \fi%
+ \@tempa%
+}
+\def\hlx@vgap@ii#1{%
+ \@ifnextchar[{\hlx@vgap@iii{#1}}{\hlx@vgap@iii{#1}[\doublerulesep]}%
+}
+\def\hlx@vgap@iii#1[#2]{#1{#2}}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\hlx s}
+%
+% Allow the user to leave a small gap using the \lit{s} command.
+%
+% \begin{macrocode}
+\hlxdef s{%
+ \noalign{\ifnum0=`}\fi%
+ \nobreak%
+ \@ifnextchar[\hlx@space@i{\hlx@space@i[\doublerulesep]}%
+}
+\def\hlx@space@i[#1]{%
+ \vskip#1%
+ \tab@addruleheight{#1}%
+ \ifnum0=`{\fi}%
+ \hlx@loop%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\hlx c}
+%
+% We might as well allow a \lit{c} command to do a |\cline|.
+%
+% \begin{macrocode}
+\hlxdef c#1{\cline{#1}\hlx@loop}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\hlx .}
+%
+% The \lit{.} character forces a start of the new column. There's a little
+% problem here. Since the \lit{.} character starts the next column, we need
+% to gobble any spaces following the |\hlx| command before the cell contents
+% actually starts. Unfortunately, |\ignorespaces| will start the column for
+% us, so we can't put it in always. We'll handle it here, then. We'll take
+% the rest of the `preamble' string, and warn if it's not empty. Then we'll
+% |\ignorespaces| -- this will start the column for us, so we don't need to
+% |\relax| any more.
+%
+% \begin{macrocode}
+\hlxdef .#1\q@delim{%
+ \ifx @#1@\else%
+ \PackageWarning{mdwtab}{%
+ Ignoring \protect\hlx\space command characters following a
+ `.'\MessageBreak command%
+ }%
+ \fi%
+ \ignorespaces%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+%
+% \subsection{Starting new table rows}
+%
+% We take a break from careful mouthery at last, and start playing with
+% newlines. The standard one allows pagebreaks in unboxed tables, which
+% isn't really too desirable.
+%
+% Anyway, we'll try to make this macro rather more reusable than the standard
+% one. Here goes.
+%
+% \begin{macro}{\@arraycr}
+%
+% We pass lots of information to a main parser macro, and expect it to cope.
+%
+% \begin{macrocode}
+\def\@arraycr{\tab@arraycr{}}
+\def\tab@arraycr#1{\tab@cr{\tab@tabcr{#1}}{}{}}
+% \end{macrocode}
+%
+% Now to actually do the work. |\tab@cr| passes us the skip size, and the
+% appropriate one of the two arguments given above (both of which are empty)
+% depending on the presence of the $*$.
+%
+% \begin{macrocode}
+\def\tab@tabcr#1#2{%
+% \end{macrocode}
+%
+% If the total height I need to add between rows (from the optional argument
+% and the `extrasep' parameter) is greater than zero, I'll handle this by
+% extending the strut slightly. I'm not actually sure whether this is the
+% right thing to do, to be honest, although it's easier than trying to
+% to an automatic |\vgap|, because I need to know which columns to skip.
+% If the space is less than zero, I'll just insert the vertical space with
+% in a |\noalign|.
+%
+% First, to calculate how much space needs adding.
+%
+% \begin{macrocode}
+ \dimen@#2%
+ \advance\dimen@\tab@extrasep%
+% \end{macrocode}
+%
+% If the height is greater than zero, I need to play with the strut. I must
+% bear in mind that the current table cell (which I'm still in, remember)
+% may be in vertical mode, and I may or may not be in a paragraph.
+%
+% If I am in vertical mode, I'll backpedal to the previous box and put the
+% strut in an hbox superimposed on the previous baseline. Otherwise, I can
+% just put the strut at the end of the text. (This works in either LR
+% or paragraph mode as long as I'm not between paragraphs.) Again, Rowland's
+% empty cell bug strikes. (See |\tab@epar| for details.)
+%
+% \begin{macrocode}
+ \ifdim\dimen@>\z@%
+ \ifvmode%
+ \unskip\ifdim\prevdepth>-\@m\p@\kern-\prevdepth\fi%
+ \nointerlineskip\expandafter\hbox%
+ \else%
+ \@maybe@unskip\expandafter\@firstofone%
+ \fi%
+ {\advance\dimen@\dp\@arstrutbox\vrule\@depth\dimen@\@width\z@}%
+ \fi%
+% \end{macrocode}
+%
+% This table cell works as a group (which is annoying here). I'll copy the
+% interrow gap into a global register so that I can use it in the |\noalign|.
+%
+% \begin{macrocode}
+ \global\dimen\@ne\dimen@%
+ \cr%
+ \noalign{%
+ #1%
+ \ifdim\dimen\@ne<\z@\vskip\dimen\@ne\relax\fi%
+ }%
+ \@gobble%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\tab@setcr}
+%
+% To set the |\\| command correctly in each table cell, we make it a part of
+% the preamble (in |\tab@midtext|) to call this routine. It's easy -- just
+% saves the preamble from being huge.
+%
+% \begin{macrocode}
+\def\tab@setcr{\let\\\tabularnewline}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\tab@cr}
+%
+% Now we do the parsing work. This is fun. Note the revenge of the funny
+% braces here. Nothing to worry about, honest. The tricky bit is to keep
+% track of which arguments are which. (Thanks to David Carlisle for pointing
+% out that I'd missed out the |\relax| here.)
+%
+% \begin{macrocode}
+\def\tab@cr#1#2#3{%
+ \relax%
+ \iffalse{\fi\ifnum0=`}\fi%
+ \@ifstar{\tab@cr@i{#1}{#3}}{\tab@cr@i{#1}{#2}}%
+}
+\def\tab@cr@i#1#2{%
+ \@ifnextchar[{\tab@cr@ii{#1}{#2}}{\tab@cr@ii{#1}{#2}[\z@]}%
+}
+\def\tab@cr@ii#1#2[#3]{%
+ \ifnum0=`{}\fi%
+ #1{#3}{#2}%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+%
+% \subsection{Gratuitous grotesquery}
+%
+% So far we've had an easy-ish ride (or should that be \emph{queasy}?). Now
+% for something unexplainably evil. We convince \LaTeX\ that it's loaded the
+% \package{array} package, so that packages which need it think they've got
+% it.
+%
+% The bogus date is the same as the date for the \package{array} package I've
+% got here -- this will raise a warning if Frank updates his package which
+% should filter back to me telling me that there's something I need to
+% know about.
+%
+% The messing with |\xdef| and the funny parsing ought to insert the current
+% \package{mdwtab} version and date into the fake \package{array} version
+% string, giving a visible clue to the user that this isn't the real
+% \package{array} package.
+%
+% \begin{macrocode}
+\begingroup
+\catcode`.=11
+\def\@tempa#1 #2 #3\@@{#1 #2}
+\xdef\ver@array.sty
+ {1995/11/19 [mdwtab.sty \expandafter\@tempa\ver@mdwtab.sty\@@]}
+\endgroup
+% \end{macrocode}
+%
+%
+% \subsection{Error messages}
+%
+% I've put all the error messages together, where I can find them, translate
+% them or whatever.
+%
+% First, some token-space saving (which also saves my fingers):
+%
+% \begin{macrocode}
+\def\tab@error{\PackageError{mdwtab}}
+% \end{macrocode}
+%
+% Now do the error messages.
+%
+% \begin{macrocode}
+\def\tab@err@misscol{%
+ \tab@error{Missing column type}{%
+ I'm lost. I was expecting something describing^^J%
+ the type of the current column, but you seem to^^J%
+ have missed it out. I've inserted a type `l'^^J%
+ column here in the hope that this makes sense.%
+ }%
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\def\tab@err@oddgroup{%
+ \tab@error{Misplaced group in table preamble}{%
+ I've found an open brace character in your preamble^^J%
+ when I was expecting a specifier character. I'm^^J%
+ going to gobble the whole group and carry on as if^^J%
+ I'd never seen it.%
+ }%
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\def\tab@err@undef#1{%
+ \tab@error{Unknown `\tab@colset' preamble character `\string#1'}{%
+ I don't understand what you meant by typing this^^J%
+ character. Anyway, I'll ignore it this time around.^^J%
+ Just don't you do it again.%
+ }%
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\def\tab@err@unbrh{%
+ \tab@error{Can't use unboxed tabular in LR mode}{%
+ You've asked for a tabular or array environment with^^J%
+ `L', `C' or `R' as the position specifier, but you're^^J%
+ in LR (restricted horizontal) mode, so it won't work.^^J%
+ I'll assume you really meant `c' and soldier on.%
+ }%
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\def\tab@err@unbmm{%
+ \tab@error{Can't use unboxed tabular in maths mode}{%
+ You've asked for a tabular or array environment with^^J%
+ `L', `C' or `R' as the position specifier, but you're^^J%
+ in maths mode, so it won't work. I'll pretend that^^J%
+ you really typed `c', and that this is all a bad dream.%
+ }%
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\def\tab@err@unbext{%
+ \tab@error{Can't extend unboxed tabulars}{%
+ You're trying to use kludgy extensions (e.g.,^^J%
+ `delarray') on an array or tabular with `L', `C'^^J%
+ or `R' as the position specifier. I'll assume you^^J%
+ subconsciously wanted a `c' type all along.%
+ }%
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\def\tab@err@multi{%
+ \tab@error{More than one column in a \protect\multicolumn}{%
+ You've put more than one column into a \string\multicolumn^^J%
+ descriptor. It won't work. I have no idea what^^J%
+ will happen, although it won't be pleasant. Hold^^J%
+ on tight now...%
+ }%
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\def\tab@err@range{%
+ \tab@error{Expected `,' or `<end>' in range list}{%
+ I was expecting either the end of the range list,^^J%
+ or a comma, followed by another range. I've^^J%
+ inserted a comma to try and get me back on track.^^J%
+ Good luck.%
+ }%
+}
+% \end{macrocode}
+%
+% That's it. No more. Move along please.
+%
+% \begin{macrocode}
+%</mdwtab>
+% \end{macrocode}
+%
+%
+%^^A-------------------------------------------------------------------------
+% \section{Implementation of \package{mathenv}}
+%
+%
+% This is in a separate package, mainly to avoid wasting people's memory.
+%
+% \begin{macrocode}
+%<*mathenv>
+% \end{macrocode}
+%
+%
+% \subsection{Options handling}
+%
+% We need to be able to cope with \textsf{fleqn} and \textsf{leqno} options.
+% This will adjust our magic modified \env{eqnarray} environment
+% appropriately.
+%
+% \begin{macrocode}
+\newif\if@fleqn
+\newif\if@leqno
+\DeclareOption{fleqn}{\@fleqntrue}
+\DeclareOption{leqno}{\@leqnotrue}
+\ProcessOptions
+% \end{macrocode}
+%
+% We use the \package{mdwtab} package for all its nice table handling things.
+% (Oh, and to inflict it on users who want to do nice equations and don't
+% care about our tables.)
+%
+% \begin{macrocode}
+\RequirePackage{mdwtab}
+% \end{macrocode}
+%
+%
+% \subsection{Some useful registers}
+%
+% The old \LaTeX\ version puts the equation numbers in by keeping a count of
+% where it is in the alignment. Since I don't know how may columns there are
+% going to be, I'll just use a switch in the preamble to tell me to stop
+% tabbing.
+%
+% \begin{macrocode}
+\newif\if@eqalast
+% \end{macrocode}
+%
+% Now define some useful length parameters. First allocate them:
+%
+% \begin{macrocode}
+\newskip\eqaopenskip
+\newskip\eqacloseskip
+\newskip\eqacolskip
+\newskip\eqainskip
+\newskip\splitleft
+\newskip\splitright
+% \end{macrocode}
+%
+% Now assign some default values. Users can play with these if they really
+% want although I can't see the point myself.
+%
+% \begin{macrocode}
+\AtBeginDocument{%
+ \eqacloseskip\@centering%
+ \eqacolskip1.5em\@plus\@m\p@
+ \eqainskip\z@%
+ \if@fleqn%
+ \eqaopenskip\mathindent%
+ \splitleft\mathindent\relax%
+ \splitright\mathindent\@minus\mathindent\relax%
+ \else%
+ \eqaopenskip\@centering%
+ \splitleft2.5em\@minus2.5em%
+ \splitright\splitleft%
+ \fi%
+ \relax%
+}
+% \end{macrocode}
+%
+%
+% \subsection{A little display handling}
+%
+% I'm probably going a little far here, and invading territory already
+% claimed by the \package{amsmath} stuff (and done a good deal better than
+% I can be bothered to do), but just for completeness, this is how we handle
+% attempts to put displays inside other displays without screwing up the
+% spacing.
+%
+% \begin{macro}{\dsp@startouter}
+%
+% This is how we start an outermost display. It's fairly easy really. We
+% make |\dsp@start| start an inner display, and make |\dsp@end| close the
+% outer display.
+%
+% \begin{macrocode}
+\def\dsp@startouter{%
+ \let\dsp@end\dsp@endouter%
+ $$%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\dsp@endouter}
+%
+% Ending the outer display is utterly trivial.
+%
+% \begin{macrocode}
+\def\dsp@endouter{$$}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\dsp@startinner}
+%
+% Starting inner displays is done in a vbox (actually I choose |\vbox| or
+% |\vtop| depending on the setting of \textsf{leqno} to put the equation
+% number the right way round).
+%
+% \begin{macrocode}
+\def\dsp@startinner{%
+ \let\dsp@end\dsp@endinner%
+ \if@fleqn\kern-\mathindent\fi%
+ \if@leqno\vtop\else\vtop\fi\bgroup%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\dsp@endinner}
+%
+% Ending an inner display is also really easy.
+%
+% \begin{macrocode}
+\def\dsp@endinner{\egroup}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\dsp@start}
+%
+% This is what other bits of code uses to start displays. It's one of the
+% start macros up above, and outer by default.
+%
+% \begin{macrocode}
+\def\dsp@start{%
+ \ifmmode%
+ \ifinner\mth@err@mdsp\fi%
+ \expandafter\dsp@startinner%
+ \else%
+ \ifhmode\ifinner\mth@err@hdsp\fi\fi%
+ \expandafter\dsp@startouter%
+ \fi%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\dsp@tabpause}
+%
+% This sets up the correct pre- and postambles for the |\tabpause| macro in
+% maths displays. This is fairly simple stuff.
+%
+% \begin{macrocode}
+\def\dsp@tabpause{%
+ \def\tab@startpause%
+ {\penalty\postdisplaypenalty\vskip\belowdisplayskip}%
+ \def\tab@endpause%
+ {\penalty\predisplaypenalty\vskip\abovedisplayskip}%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+%
+% \subsection{The \env{eqnarray} environment}
+%
+% We allow the user to play with the style if this is really wanted. I dunno
+% why, really. Maybe someone wants very small alignments.
+%
+% \begin{macrocode}
+\let\eqastyle\displaystyle
+% \end{macrocode}
+%
+% \subsubsection{The main environments}
+%
+% \begin{environment}{eqnarray}
+% \begin{environment}{eqnarray*}
+%
+% We define the toplevel commands here. They just add in default arguments
+% and then call |\@eqnarray| with a preamble string. We handle equation
+% numbers by setting up a default (|\eqa@defnumber|) which is put into
+% the final column. At the beginning of each row, we globally |\let|
+% |\eqa@number| equal to |\eqa@defnumber|. The |\eqnumber| macro just
+% changes |\eqa@number| as required. Since |\eqa@number| is changed globally
+% we must save it in this environment.
+%
+% First, we must sort out the optional arguments and things. This is really
+% easy. The only difference between the starred and non-starred environments
+% is the default definition of |\eqa@defnumber|.
+%
+% \begin{macrocode}
+\def\eqnarray{%
+ \eqnarray@i\eqa@eqcount%
+}
+\@namedef{eqnarray*}{\eqnarray@i{}}
+\def\eqnarray@i#1{\@ifnextchar[{\eqnarray@ii{#1}}{\eqnarray@ii{#1}[rcl]}}
+% \end{macrocode}
+%
+% Right. Now for the real work. The first argument is the default numbering
+% tokens; the second is the preamble string.
+%
+% \begin{macrocode}
+\def\eqnarray@ii#1[#2]{%
+% \end{macrocode}
+%
+% Set up the equation counter and labels correctly.
+%
+% \medskip\par\noindent|\begin{rant}|\par
+% The hacking with |\@currentlabel| is here because (in the author's opinion)
+% \LaTeX's |\refstepcounter| macro is broken. It's currently defined as
+% \begin{listing}
+%\def\refstepcounter#1{%
+% \stepcounter{#1}%
+% \protected@edef\@currentlabel%
+% {\csname p@#1\endcsname\csname the#1\endcsname}%
+%}
+% \end{listing}
+% which means that the current label gets `frozen' as soon as you do the
+% counter step. By redefining the macro as
+% \begin{listing}
+%\def\refstepcounter#1{%
+% \stepcounter{#1}%
+% \edef\@currentlabel{%
+% \expandafter\noexpand\csname p@#1\endcsname%
+% \expandafter\noexpand\csname the#1\endcsname%
+% }%
+%}
+% \end{listing}
+% these sorts of problems would be avoided, without any loss of functionality
+% or compatibility that I can see.
+% \par\noindent|\end{rant}|\par
+%
+% \begin{macrocode}
+ \stepcounter{equation}%
+ \def\@currentlabel{\p@equation\theequation}%
+% \end{macrocode}
+%
+% The next step is to set up the numbering. I must save the old numbering
+% so I can restore it later (once in the alignment, I must assign these
+% things globally).
+%
+% \begin{macrocode}
+ \let\eqa@oldnumber\eqa@number%
+ \def\eqa@defnumber{#1}%
+ \global\let\eqa@number\eqa@defnumber%
+% \end{macrocode}
+%
+% The |\if@eqalastfalse| switch is false everywhere except when we're in the
+% final column.
+%
+% \begin{macrocode}
+ \@eqalastfalse%
+% \end{macrocode}
+%
+% Remove the |\mathsurround| kerning, since it will look very odd inside
+% the display. We have our own spacing parameters for configuring these
+% things, so |\mathsurround| is unnecessary.
+%
+% \begin{macrocode}
+ \m@th%
+% \end{macrocode}
+%
+% Time to parse the preamble string now. I must choose the correct column
+% set, initialise the preamble parser and set up the various macros. The%
+% extra `|@{\tabskip\eqacloseskip}|' item sets up the tabskip glue to centre
+% the alignment properly.
+%
+% \begin{macrocode}
+ \colset{eqnarray}%
+ \tab@initread%
+ \def\tab@tabtext{&\tabskip\z@skip}%
+ \tab@preamble{\tabskip\z@skip}%
+ \tab@readpreamble{#2@{\tabskip\eqacloseskip}}%
+ \dsp@tabpause%
+% \end{macrocode}
+%
+% Now for some final setting up. The column separation is set from the
+% user's parameter, the |\everycr| tokens are cleared, and I set up the
+% newline command appropriately.
+%
+% \begin{macrocode}
+ \col@sep.5\eqainskip%
+ \everycr{}%
+ \let\\\@eqncr%
+% \end{macrocode}
+%
+% Now start a maths display and do the alignment. Set up the left hand
+% tabskip glue to centre the alignment, and do the actual alignment.
+% The preamble used is mainly that generated from the user's string, although
+% the stuff at the end is how we set up the equation number -- it repeats
+% appropriately so we can always find it.
+%
+% \begin{macrocode}
+ \dsp@start%
+ \tabskip\eqaopenskip%
+ \halign to\displaywidth\expandafter\bgroup%
+ \the\tab@preamble%
+ &&\eqa@lastcol\hb@xt@\z@{\hss##}\tabskip\z@\cr%
+}
+% \end{macrocode}
+%
+% Now for the end of the environment. This is really easy. Set the final
+% equation number, close the |\halign|, tidy up the equation counter (it's
+% been stepped once too many times) and close the display.
+%
+% \begin{macrocode}
+\def\endeqnarray{%
+ \eqa@eqnum%
+ \egroup%
+ \dsp@end%
+ \global\let\eqa@number\eqa@oldnumber%
+ \global\@ignoretrue%
+ \global\advance\c@equation\m@ne%
+}
+\expandafter\let\csname endeqnarray*\endcsname\endeqnarray
+% \end{macrocode}
+%
+% \end{environment}
+% \end{environment}
+%
+% Now we can define the column types.
+%
+% \begin{macrocode}
+\colpush{eqnarray}
+% \end{macrocode}
+%
+% Note the positioning of ord atoms in the stuff below. This will space out
+% relations and binops correctly when they occur at the edges of columns, and
+% won't affect ord atoms at the edges, because ords pack closely.
+%
+% First the easy onces. Just stick |\hfil| in the right places and
+% everything will be all right.
+%
+% \begin{macrocode}
+\coldef r{\tabcoltype{\hfil$\eqastyle}{{}$}}
+\coldef c{\tabcoltype{\hfil$\eqastyle{}}{{}$\hfil}}
+\coldef l{\tabcoltype{$\eqastyle{}}{$\hfil}}
+\coldef x{\tabcoltype{\if@fleqn\else\hfil\fi$\eqastyle}{$\hfil}}
+% \end{macrocode}
+%
+% Now for the textual ones. This is also fairly easy.
+%
+% \begin{macrocode}
+\collet T [tabular]T
+% \end{macrocode}
+%
+% Sort of split types of equations. I mustn't use |\rlap| here, or
+% everything goes wrong -- |\\| doesn't get noticed by \TeX\ in the same way
+% as |\cr| does.
+%
+% \begin{macrocode}
+\coldef L{\tabcoltype{\hb@xt@2em\bgroup$\eqastyle}{$\hss\egroup}}
+% \end{macrocode}
+%
+% The \lit{:} column type is fairly simple.
+%
+% \begin{macrocode}
+\coldef :{\tabspctype{\tabskip\eqacolskip}}
+\coldef q{\tabspctype{\quad}}
+% \end{macrocode}
+%
+% The other column types just insert given text in an appropriate way.
+%
+% \begin{macrocode}
+\collet > [tabular]>
+\collet < [tabular]<
+\collet * [tabular]*
+\collet @ [tabular]@
+% \end{macrocode}
+%
+% Finally, the magical `|\magic|' column type, which sets the equation
+% number. We set up the |\tabskip| glue properly, tab on, and set the flag
+% which marks the final column. The |\eqa@lastcol| command is there to
+% raise an error if the user tabs over to this column. I'll temporarily
+% redefine it to |\@eqalasttrue| when I enter this column legitimately.
+% The extra magical bits here will make the final column repeat, so that we
+% can find it if necessary. Well is this column type named.
+%
+% That's it. We can return to normal now.
+%
+% \begin{macrocode}
+\colpop
+% \end{macrocode}
+%
+% \subsubsection{Newline codes}
+%
+% Newline sequences (|\\|) get turned into calls of |\@eqncr|. The job is
+% fairly simple, really.
+%
+% \begin{macrocode}
+\def\@eqncr{\tab@cr\eqacr@i\interdisplaylinepenalty\@M}%
+\def\eqacr@i#1#2{%
+ \eqa@eqnum%
+ \noalign{\penalty#2\vskip\jot\vskip#1}%
+}
+% \end{macrocode}
+%
+% \subsubsection{Setting equation numbers}
+%
+% \begin{macro}{\eqa@eqpos}
+%
+% Before we start, we need to generalise the flush-left number handling bits.
+% The macro |\eqa@eqpos| will put its argument in the right place.
+%
+% \begin{macrocode}
+\if@leqno
+ \def\eqa@eqpos#1{%
+ \hb@xt@.01\p@{}\rlap{\normalfont\normalcolor\hskip-\displaywidth#1}%
+ }
+\else
+ \def\eqa@eqpos#1{\normalfont\normalcolor#1}
+\fi
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\eqa@eqnum}
+%
+% Here we typeset an equation number in roughly the right place. First I'll
+% redefine |\eqa@lastcol| so that it tells me I'm in the right place, and
+% start a loop to find that place.
+%
+% \begin{macrocode}
+\def\eqa@eqnum{%
+ \global\let\eqa@lastcol\@eqalasttrue%
+ \eqa@eqnum@i%
+}
+% \end{macrocode}
+%
+% Now for the loop. The |\relax| here is absolutely vital -- it starts the
+% table column, inserting useful tokens like `|\eqa@lastcol|' which tell
+% me where I am in the alignment. Then, if I've reached the end, I can
+% typeset the equation number; otherwise I go off into another macro and
+% step on to the next column.
+%
+% \begin{macrocode}
+\def\eqa@eqnum@i{%
+ \relax%
+ \if@eqalast%
+ \expandafter\eqa@eqnum@ii%
+ \else%
+ \expandafter\eqa@eqnum@iii%
+ \fi%
+}
+\def\eqa@eqnum@ii{%
+ \eqa@eqpos\eqa@number%
+ \global\let\eqa@number\eqa@defnumber%
+ \global\let\eqa@lastcol\eqa@@lastcol%
+ \cr%
+}
+\def\eqa@eqnum@iii{&\eqa@eqnum@i}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\eqa@lastcol}
+%
+% This is used as a marker for the final column in an \env{eqnarray}
+% environment. By default it informs the user that they've been very
+% silly and swallows the contents of the column. I'll redefine it to
+% something more useful at appropriate times, and then turn it back again.
+%
+% \begin{macrocode}
+\def\eqa@@lastcol{\mth@err@number\setbox\z@}
+\let\eqa@lastcol\eqa@@lastcol
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \subsubsection{Numbering control}
+%
+% \begin{macro}{\eqnumber}
+%
+% The |\eqnumber| command sets the equation number on the current equation.
+% This is really easy, actually.
+%
+% \begin{macrocode}
+\newcommand\eqnumber[1][\eqa@eqcount]{\gdef\eqa@number{#1}}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\eqa@eqcount}
+%
+% This is how a standard equation number is set, stepping the counter and
+% all. It's really easy and obvious.
+%
+% \begin{macrocode}
+\def\eqa@eqcount{(\theequation)\global\advance\c@equation\@ne}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\nonumber}
+%
+% The \LaTeX\ |\nonumber| command could be defined by saying
+% \begin{listing}
+%\renewcommand{\nonumber}{\eqnumber[]}
+% \end{listing}
+% but I'll be slightly more efficient and redefine |\eqa@number| directly.
+%
+% \begin{macrocode}
+\def\nonumber{\global\let\eqa@number\@empty}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \subsubsection{The \env{eqnalign} environment}
+%
+% As a sort of companion to \env{eqnarray}, here's an environment which does
+% similar things inside a box, rather than taking up the whole display width.
+% It uses the same column types that we've already created, so there should
+% be no problems.
+%
+% \begin{environment}{eqnalign}
+%
+% First, sort out some simple things like optional arguments.
+%
+% \begin{macrocode}
+\def\eqnalign{\@ifnextchar[\eqnalign@i{\eqnalign@i[rcl]}}
+\def\eqnalign@i[#1]{%
+ \@ifnextchar[{\eqnalign@ii{#1}}{\eqnalign@ii{#1}[c]}%
+}
+% \end{macrocode}
+%
+% Now we actually do the environment. This is fairly easy, actually.
+%
+% \begin{macrocode}
+\def\eqnalign@ii#1[#2]{%
+ \let\\\eqn@cr%
+ \colset{eqnarray}%
+ \tab@initread%
+ \def\tab@tabtext{&\tabskip\z@skip}%
+ \tabskip\z@skip%
+ \col@sep.5\eqainskip%
+ \tab@readpreamble{#1}%
+ \everycr{}%
+ \if#2t\vtop\else%
+ \if#2b\vbox\else%
+ \vcenter%
+ \fi%
+ \fi%
+ \bgroup%
+ \halign\expandafter\bgroup\the\tab@preamble\cr%
+}
+% \end{macrocode}
+%
+% Finishing the environment is even simpler.
+%
+% \begin{macrocode}
+\def\endeqnalign{%
+ \crcr%
+ \egroup%
+ \egroup%
+}
+% \end{macrocode}
+%
+% \end{environment}
+%
+% \begin{macro}{\eqn@cr}
+%
+% Newlines are really easy here.
+%
+% \begin{macrocode}
+\def\eqn@cr{\tab@cr\eqn@cr@i{}{}}
+\def\eqn@cr@i#1{\cr\noalign{\vskip\jot\vskip#1}\@gobble}
+% \end{macrocode}
+%
+% \end{macro}
+%
+%
+% \subsection{Simple multiline equations}
+%
+% As a sort of example and abbreviation, here's a multiline display
+% environment which just centres everything.
+%
+% \begin{environment}{eqlines}
+%
+% We just get |\eqnarray| to do everything for us. This is really easy.
+%
+% \begin{macrocode}
+\def\eqlines{\eqnarray[x]}
+\let\endeqlines\endeqnarray
+% \end{macrocode}
+%
+% \end{environment}
+%
+% \begin{environment}{eqlines*}
+%
+% There's a $*$ version which omits numbers. This is easy too. Lots of
+% hacking with expansion here to try and reduce the number of tokens being
+% used. Is it worth it?
+%
+% \begin{macrocode}
+\expandafter\edef\csname eqlines*\endcsname{%
+ \expandafter\noexpand\csname eqnarray*\endcsname[x]%
+}
+\expandafter\let\csname endeqlines*\expandafter\endcsname
+ \csname endeqnarray*\endcsname
+% \end{macrocode}
+%
+% \end{environment}
+%
+%
+% \subsection{Split equations}
+%
+% Based on an idea from \textit{The \TeX book}, we provide some simple
+% environments for doing split equations. These's plenty of scope for
+% improvement here, though.
+%
+% \begin{environment}{spliteqn}
+% \begin{environment}{spliteqn*}
+%
+% The only difference between these two is that the $*$-version doesn't put
+% in an equation number by default (although this behaviour can be
+% changed by |\eqnumber|).
+%
+% The fun here mainly concerns putting in the equation number at the right
+% place -- for |leqno| users, we need to put the number on the first line;
+% otherwise we put it on the last line.
+%
+% The way we handle this is to have two macros, |\\| (which clearly does
+% all the user line breaks) and |\seq@lastcr| which is used at the end of
+% the environment to wrap everything up. The |\seq@eqnocr| macro puts an
+% equation number on the current line and then does a normal |\\|. It also
+% resets |\\| and |\seq@lastcr| so that they don't try to put another
+% equation number in. This must be done globally, although anyone who tries
+% to nest maths displays will get what they deserve.
+%
+% For the non-$*$ environment, then, we need to step the equation counter,
+% and set |\\| to |\seq@cr| or |\seq@eqnocr| as appropriate for the setting
+% of the |leqno| flag -- |\seq@lastcr| always gets set to put an equation
+% number in (because it will be reset if the number actually gets done
+% earlier -- this catches stupid users trying to put a single row into
+% a split environment).
+%
+% \begin{macrocode}
+\def\spliteqn{%
+ \let\eqa@oldnumber\eqa@number%
+ \global\let\eqa@number\eqa@eqcount%
+ \spliteqn@i%
+}
+% \end{macrocode}
+%
+% For the $*$ variant, we don't need to bother with equation numbering, so
+% this is really easy.
+%
+% \begin{macrocode}
+\@namedef{spliteqn*}{%
+ \let\eqa@oldnumber\eqa@number%
+ \gdef\eqa@number{}%
+ \spliteqn@i%
+}
+% \end{macrocode}
+%
+% Ending the environments is easy. Most of the stuff here will be described
+% later.
+%
+% \begin{macrocode}
+\def\endspliteqn{%
+ \hfilneg\seq@lastcr%
+ \egroup%
+ \dsp@end%
+ \global\let\eqa@number\eqa@oldnumber%
+ \global\advance\c@equation\m@ne%
+}
+\expandafter\let\csname endspliteqn*\endcsname\endspliteqn
+% \end{macrocode}
+%
+% \end{environment}
+% \end{environment}
+%
+% \begin{macro}{\spliteqn@i}
+%
+% Here we handle the full display splits. Start a maths display, and make
+% each row of the alignment take up the full display width.
+%
+% The macro |\seq@dosplit| does most of the real work for us -- setting up
+% the alignment and so forth. The template column is interesting. There
+% are two items glue on both sides of the actual text:
+%
+% \begin{itemize}
+%
+% \item Some glue which can shrink. This keeps the display from the edges
+% of the page unless we get a really wide item.
+%
+% \item An |\hfil| to do the alignment. By default, this centres the
+% equations. On the first line, however, we put a leading |\hfilneg|
+% which cancels the first |\hfil|, making the first row left aligned.
+% Similarly, at the end, we put an |\hfilneg| after the last equation
+% to right align the last line.
+%
+% \end{itemize}
+%
+% We pass this information on as an argument. It's easy really.
+%
+% \begin{macrocode}
+\def\spliteqn@i{%
+% \end{macrocode}
+%
+% First, set up equation numbering properly. See my rant about
+% |\refstepcounter| above.
+%
+% \begin{macrocode}
+ \stepcounter{equation}%
+ \def\@currentlabel{\p@equation\theequation}%
+% \end{macrocode}
+%
+% Right; now to sort out the numbering and newline handling. If the number's
+% meant to be on the first line (for \textsf{leqno} users), then it gets
+% typeset on the first like; otherwise we just do a normal newline on
+% all lines except the first. Once |\seq@eqnocr| has done its stuff, it
+% redefines all the newline handling not to insert another number.
+%
+% \begin{macrocode}
+ \if@leqno%
+ \global\let\seq@docr\seq@eqnocr%
+ \else%
+ \global\let\seq@docr\seq@cr%
+ \fi%
+ \global\let\seq@lastcr\seq@eqnocr%
+% \end{macrocode}
+%
+% For my next trick, I'll do some display handling -- start a (possibly
+% nested) maths display, set up the |\tabpause| macro appropriately, and
+% set the newline command to do the right thing.
+%
+% \begin{macrocode}
+ \dsp@start%
+ \dsp@tabpause%
+ \def\\{\seq@docr}%
+% \end{macrocode}
+%
+% Finally, call another macro to do the remaining bits of setting up.
+%
+% \begin{macrocode}
+ \seq@dosplit%
+ {\hb@xt@\displaywidth{%
+ \hskip\splitleft\hfil$\displaystyle##$%
+ \hfil\hskip\splitright}}%
+ {\hfilneg}%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{environment}{subsplit}
+%
+% For doing splits in the middle of equations, we provide a similar
+% environment. Here, we make |\\| just start a new line. We also use
+% a |\vcenter| rather than a full maths display. The glue items are also
+% a bit different: we use plain double-quads on each side of the item, and
+% we need to remove them by hand at the extremeties of the environment.
+%
+% \begin{macrocode}
+\def\subsplit{%
+ \let\\\seq@cr%
+ \vcenter\bgroup%
+ \seq@dosplit{\hfil\qquad$##$\qquad\hfil}{\hfilneg\hskip-2em}%
+}
+% \end{macrocode}
+%
+% Ending the environment is fairly easy. We remove the final glue item,
+% and close the alignment and the vbox.
+%
+% \begin{macrocode}
+\def\endsubsplit{%
+ \hfilneg\hskip-2em\cr%
+ \egroup\egroup%
+}
+% \end{macrocode}
+%
+% \end{environment}
+%
+% \begin{macro}{\seq@dosplit}
+%
+% Here we do most of the real work. Actually, since the preamble is passed
+% in as an argument, most of the work is already done. The only thing to
+% really note is the template for subsequent columns. To stop users putting
+% in extra columns (which is where we put the equation number) we raise an
+% error and discard the input in a scratch box register. This template is
+% repeated infinitely so as to allow us to put the equation number in nicely.
+% However, the final negative glue item won't work properly, so the equation
+% will look awful.
+%
+% \begin{macrocode}
+\def\seq@dosplit#1#2{%
+ \halign\bgroup%
+ #1&&\mth@err@number\setbox\z@\hbox{##}\cr%
+ #2\relax%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\seq@eqnocr}
+%
+% Here's how we set equation numbers. Since the column provided raises
+% errors as soon as a token finds its way into it, we start with a |&\omit|.
+% Then we just put the equation number in a zero-width box. Finally, we
+% reset the newline commands to avoid putting in more than one equation
+% number, and do normal newline things.
+%
+% \begin{macrocode}
+\def\seq@eqnocr{%
+ &\omit%
+ \hb@xt@\z@{\hss\eqa@eqpos\eqa@number}%
+ \global\let\seq@docr\seq@cr%
+ \global\let\seq@lastcr\seq@cr%
+ \seq@cr%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\seq@cr}
+%
+% Newlines are very easy. We add a |\jot| of extra space, since this is
+% a nice thing to do.
+%
+% \begin{macrocode}
+\def\seq@cr{\tab@cr\seq@cr@i\interdisplaylinepenalty\@M}
+\def\seq@cr@i#1#2{\cr\noalign{\penalty#2\vskip\jot\vskip#1}}
+% \end{macrocode}
+%
+% \end{macro}
+%
+%
+% \subsection{Matrix handling}
+%
+% There's been a complete and total overhaul of the spacing calculations
+% for matrices here. The vertical spacing now bears an uncanny similarity
+% to the rules \TeX\ uses to space out |\atop|-like fractions, the difference
+% being that you can have more than one column in a matrix. This has the
+% interesting side-effect that we get an \package{amsmath}-style
+% sub/superscript environment almost free of charge with the matrix handling
+% (it just ends up being a script-size single-column matrix).
+%
+% What is rather gratifying is that our \env{matrix} environment looks
+% rather nicer than \package{amsmath}'s (which is based directly on
+% \env{array}, giving it nasty restrictions on the numbers of columns and
+% so on); in particular, the version here gives the `correct' result for
+% Knuth's exercise~18.42 (which states categorically that a |\smallskip|
+% should be placed between the rows of the big matrix).
+%
+% The reason the interrow space doesn't come out in the AMS version is
+% that \env{array} inserts extra vertical space by extending the depth of
+% the final row using a strut: the big matrix already extends deeper than
+% this, so the strut doesn't make any difference. If the space was added
+% by |\hlx{s[\smallskipamount]}| instead of the |\\| command, things would
+% be different.
+%
+% \begin{figure}
+%
+% ^^A This is essentially what amsmath (version 1.2b) does. The real
+% ^^A implementation requires a counter MaxMatrixCols, and has fewer braces:
+% ^^A that's all the difference. Oh, and I turn off \arrayextrasep here,
+% ^^A since amsmath doesn't expect it to be there (accurate emulation, see?)
+% ^^A and I've used \hspace instead of \hskip since everything else is
+% ^^A `proper' LaTeX stuff.
+%
+% \newenvironment{ams-pmatrix}{^^A
+% \setlength{\arrayextrasep}{0pt}^^A
+% \left(^^A
+% \hspace{-\arraycolsep}^^A
+% \begin{array}{*{10}{c}}^^A
+% }{^^A
+% \end{array}^^A
+% \hspace{-\arraycolsep}^^A
+% \right)^^A
+% }
+%
+% \begin{demo}{Exercise 18.42 from \emph{The \TeX book}}
+%\newcommand{\domatrix}[1]{
+% \def\mat##1
+% {\begin{#1}##1\end{#1}}
+% \[ \begin{#1}
+% \mat{a & b \\ c & d} &
+% \mat{e & f \\ g & h}
+% \\[\smallskipamount]
+% 0 &
+% \mat{i & j \\ k & l}
+% \end{#1}
+% \]
+%}
+%\domatrix{pmatrix}
+%\domatrix{ams-pmatrix}
+% \end{demo}
+%
+% \end{figure}
+%
+% \begin{environment}{genmatrix}
+%
+% The first job is to store my maths style and font away, because I'll be
+% needing it lots later.
+%
+% \begin{macrocode}
+\def\genmatrix#1#2#3#4#5{%
+ \let\mat@style#1%
+ \ifx#2\scriptstyle%
+ \let\mat@font\scriptfont%
+ \else\ifx#2\scriptscriptstyle%
+ \let\mat@font\scriptscriptfont%
+ \else%
+ \let\mat@font\textfont%
+ \fi\fi%
+% \end{macrocode}
+%
+% Now to cope with inserted text. This is easy.
+%
+% \begin{macrocode}
+ \ifx\mat@style\scriptstyle%
+ \let\mat@textsize\scriptsize%
+ \else\ifx\mat@style\scriptscriptstyle%
+ \let\mat@textsize\scriptscriptsize%
+ \else%
+ \let\mat@textsize\relax%
+ \fi\fi%
+% \end{macrocode}
+%
+% Now for some fun. I'll remember how to start and end the matrix in a
+% couple of macros |\mat@left| and |\mat@right|. I haven't yet worked out
+% exactly what needs to be in |\mat@right| yet, though, so I'll build that
+% up in a scratch token list while I'm making my mind up.
+%
+% Initially, I want to open a group (to trap the style changes), set the
+% maths style (to get the right spacing), insert the left delimiter, insert
+% some spacing around the matrix, and start a centred box. The ending just
+% closes all the groups and delimiters I opened.
+%
+% \begin{macrocode}
+ \def\mat@left{\bgroup\mat@style\left#4#3\vcenter\bgroup}%
+ \toks@{\egroup#3\right#5\egroup}%
+% \end{macrocode}
+%
+% Now comes a slightly trickier bit. If the maths style is script or
+% scriptscript, then I need to raise the box by a little bit to make it look
+% really good. The right amount is somewhere around \smallf 3/4\,pt, I
+% think, so that's what I'll use.
+%
+% \begin{macrocode}
+ \@tempswatrue%
+ \ifx\mat@style\displaystyle\else\ifx\mat@style\textstyle\else%
+ \@tempswafalse%
+ \setbox\z@\hbox\bgroup$%
+ \toks@\expandafter{\the\toks@$\m@th\egroup\raise.75\p@\box\z@}%
+ \fi\fi%
+% \end{macrocode}
+%
+% If I'm not in maths mode right now, then I should enter maths mode, and
+% remember to leave it later.
+%
+% \begin{macrocode}
+ \if@tempswa\ifmmode\else%
+ $\m@th%
+ \toks@\expandafter{\the\toks@$}%
+ \fi\fi%
+% \end{macrocode}
+%
+% Now I've sorted out how to end the environment properly, so I can set up
+% the macro, using |\edef|.
+%
+% \begin{macrocode}
+ \edef\mat@right{\the\toks@}%
+% \end{macrocode}
+%
+% Now see if there's an optional argument. If not, create lots of centred
+% columns.
+%
+% \begin{macrocode}
+ \@ifnextchar[\genmatrix@i{\genmatrix@i[[c]}%
+}
+% \end{macrocode}
+%
+% Now to sort out everything else.
+%
+% \begin{macrocode}
+\def\genmatrix@i[#1]{%
+% \end{macrocode}
+%
+% Some initial setting up: choose the correct column set, and set up some
+% variables for reading the preamble.
+%
+% \begin{macrocode}
+ \colset{matrix}%
+ \tab@initread%
+% \end{macrocode}
+%
+% Now comes some of the tricky stuff. The space between columns should be
+% 12\,mu (by trial and error). We put the space in a box so we can measure
+% it in the correct mathstyle.
+%
+% \begin{macrocode}
+ \setbox\z@\hbox{$\mat@style\mskip12mu$}%
+ \edef\tab@tabtext{&\kern\the\wd\z@}%
+ \tab@readpreamble{#1}%
+% \end{macrocode}
+%
+% Now we need to decide how to space out the rows. The code here is based
+% on the information in appendix~G of \emph{The \TeX book}: I think it'd be
+% nice if my matrices were spaced out in the same way as normal fractions
+% (particularly |\choose|y things). The standard |\baselineskip| and
+% |\lineskip| parameters come in really handy here.
+%
+% The parameters vary according to the size of the text, so I need to see
+% if we have scriptsize or less, or not. The tricky |\if| sorts this out.
+%
+% \begin{macrocode}
+ \if1\ifx\mat@style\scriptstyle1\else%
+ \ifx\mat@style\scriptscriptstyle1\else0\fi\fi%
+ \baselineskip\fontdimen10\mat@font\tw@%
+ \advance\baselineskip\fontdimen12\mat@font\tw@%
+ \lineskip\thr@@\fontdimen8\mat@font\thr@@%
+ \else%
+ \baselineskip\fontdimen8\mat@font\tw@%
+ \advance\baselineskip\fontdimen11\mat@font\tw@%
+ \lineskip7\fontdimen8\mat@font\thr@@%
+ \fi%
+ \lineskiplimit\lineskip%
+% \end{macrocode}
+%
+% Now actually set up for the alignment. Assign |\\| to the correct value.
+% Set up the |\tabskip|. Do the appropriate |\mat@left| thing set up above.
+% And then start the alignment.
+%
+% \begin{macrocode}
+ \let\\\mat@cr%
+ \tabskip\z@skip%
+ \col@sep\z@%
+ \mat@left%
+ \halign\expandafter\bgroup\the\tab@preamble\tabskip\z@skip\cr%
+% \end{macrocode}
+%
+% Now for a little hack to make the spacing consistent between matrices of
+% the same height. This comes directly from \PlainTeX. This appears to
+% make the spacing \emph{exactly} the same as the \TeX\ primites, oddly
+% enough.
+%
+% \begin{macrocode}
+ \ifx\mat@font\textfont%
+ \omit$\mat@style\mathstrut$\cr\noalign{\kern-\baselineskip}%
+ \fi%
+}
+% \end{macrocode}
+%
+% Finishing the environment is really easy. We do the spacing hack again
+% at the bottom, close the alignment and then tidy whatever we started in
+% |\mat@left|.
+%
+% \begin{macrocode}
+\def\endgenmatrix{%
+ \crcr%
+ \ifx\mat@font\textfont%
+ \omit$\mat@style\mathstrut$\cr\noalign{\kern-\baselineskip}%
+ \fi%
+ \egroup%
+ \mat@right%
+}
+% \end{macrocode}
+%
+% \end{environment}
+%
+% \begin{macro}{\mat@cr}
+%
+% Newlines are really easy. The $*$-form means nothing here, so we ignore
+% it.
+%
+% \begin{macrocode}
+\def\mat@cr{\tab@cr\mat@cr@i{}{}}
+\def\mat@cr@i#1{\cr\noalign{\vskip#1}\@gobble}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\newmatrix}
+%
+% This is how we define new matrix environments. It's simple fun with
+% |\csname| and |\expandafter|.
+%
+% \begin{macrocode}
+\def\newmatrix#1#2{%
+ \@namedef{#1}{\genmatrix#2}%
+ \expandafter\let\csname end#1\endcsname\endgenmatrix%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{environment}{matrix}
+% \begin{environment}{pmatrix}
+% \begin{environment}{dmatrix}
+% \begin{environment}{smatrix}
+% \begin{environment}{spmatrix}
+% \begin{environment}{sdmatrix}
+% \begin{environment}{smatrix*}
+% \begin{environment}{spmatrix*}
+% \begin{environment}{sdmatrix*}
+%
+% Now we define all the other environments we promised. This is easy.
+%
+% \begin{macrocode}
+\newmatrix{matrix}{{\textstyle}{\textstyle}{\,}{.}{.}}
+\newmatrix{pmatrix}{{\textstyle}{\textstyle}{\,}{(}{)}}
+\newmatrix{dmatrix}{{\textstyle}{\textstyle}{\,}}
+\newmatrix{smatrix}{{\scriptstyle}{\scriptstyle}{}{.}{.}}
+\newmatrix{spmatrix}{{\scriptstyle}{\scriptstyle}{}{(}{)}}
+\newmatrix{sdmatrix}{{\scriptstyle}{\scriptstyle}{}}
+\newmatrix{smatrix*}{{\scriptstyle}{\textstyle}{}{.}{.}}
+\newmatrix{spmatrix*}{{\scriptstyle}{\textstyle}{}{(}{)}}
+\newmatrix{sdmatrix*}{{\scriptstyle}{\textstyle}{}}
+% \end{macrocode}
+%
+% \end{environment}
+% \end{environment}
+% \end{environment}
+% \end{environment}
+% \end{environment}
+% \end{environment}
+% \end{environment}
+% \end{environment}
+% \end{environment}
+%
+% \begin{environment}{script}
+%
+% Now for superscripts and subscripts. This is fairly easy, because I
+% took so much care over the matrix handling.
+%
+% \begin{macrocode}
+\def\script{%
+ \let\mat@style\scriptstyle%
+ \def\mat@left{\vcenter\bgroup}%
+ \def\mat@right{\egroup}%
+ \let\mat@font\scriptfont%
+ \let\mat@textsize\scriptsize%
+ \@ifnextchar[\genmatrix@i{\genmatrix@i[c]}%
+}
+\let\endscript\endgenmatrix
+% \end{macrocode}
+%
+% \end{environment}
+%
+% Now define the column types.
+%
+% \begin{macrocode}
+\colpush{matrix}
+\coldef l{\tabcoltype{\kern\z@$\mat@style}{\m@th$\hfil}}
+\coldef c{\tabcoltype{\hfil$\mat@style}{\m@th$\hfil}}
+\coldef r{\tabcoltype{\hfil$\mat@style}{\m@th$}}
+\coldef T#1{\tab@aligncol{#1}{\begingroup\mat@textsize}{\endgroup}}
+% \end{macrocode}
+%
+% The repeating type is more awkward. Things will go wrong if this is
+% given before the first column, so we must do a whole repeat by hand. We
+% can tell if we haven't contributed a column yet, since |\tab@column| will
+% be zero. Otherwise, we fiddle the parser state to start a new column, and
+% insert the |&| character to make \TeX\ repeat the preamble.
+%
+% \begin{macrocode}
+\coldef {[}{%
+ \@firstoftwo{%
+ \ifnum\tab@columns=\z@%
+ \def\@tempa##1\q@delim{%
+ \tab@mkpreamble##1[##1\q@delim%
+ }%
+ \expandafter\@tempa%
+ \else%
+ \tab@setstate\tab@prestate%
+ \tab@append\tab@preamble{&}%
+ \expandafter\tab@mkpreamble%
+ \fi%
+ }%
+}
+% \end{macrocode}
+%
+% We're done defining columns now.
+%
+% \begin{macrocode}
+\colpop
+% \end{macrocode}
+%
+%
+% \subsection{Dots\dots}
+%
+% Nothing whatsoever to do with alignments, although vertical and diagonal
+% dots in small matrices look really silly. The following hacky definitions
+% work rather better.
+%
+% \begin{macro}{\mdw@dots}
+%
+% First of all, here's some definitions common to both of the dots macros.
+% The macro takes as an argument the actual code to draw the dots, passing
+% it the scaled size of a point in the scratch register |\dimen@|; the
+% register |\box 0| is set to contain a dot of the appropriate size.
+%
+% \begin{macrocode}
+\def\mdw@dots#1{\ensuremath{\mathpalette\mdw@dots@i{#1}}}
+\def\mdw@dots@i#1#2{%
+ \setbox\z@\hbox{$#1\mskip1.8mu$}%
+ \dimen@\wd\z@%
+ \setbox\z@\hbox{$#1.$}%
+ #2%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\vdots}
+%
+% I'll start with the easy one. This is a simple translation of the original
+% implementation.
+%
+% \begin{macrocode}
+\def\vdots{%
+ \mdw@dots{\vbox{%
+ \baselineskip4\dimen@%
+ \lineskiplimit\z@%
+ \kern6\dimen@%
+ \copy\z@\copy\z@\box\z@%
+ }}%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\ddots}
+%
+% And I'll end with the other easy one\dots
+%
+% \begin{macrocode}
+\def\ddots{%
+ \mdw@dots{\mathinner{%
+ \mkern1mu%
+ \raise7\dimen@\vbox{\kern7\dimen@\copy\z@}%
+ \mkern2mu%
+ \raise4\dimen@\copy\z@%
+ \mkern2mu%
+ \raise\dimen@\box\z@%
+ \mkern1mu%
+ }}%
+}
+% \end{macrocode}
+%
+% \end{macro}
+%
+%
+% \subsection{Lucky dip}
+%
+% Time to round off with some trivial environments, just to show how easy
+% this stuff is.
+%
+% \begin{environment}{cases}
+% \begin{environment}{smcases}
+%
+% These are totally and utterly trivial.
+%
+% \begin{macrocode}
+\def\cases{\left\{\,\array{@{}lTl@{}}}
+\def\endcases{\endarray\,\right.}
+\def\smcases{\left\{\smarray{@{}lTl@{}}}
+\def\endsmcases{\endsmarray\,\right.}
+% \end{macrocode}
+%
+% \end{environment}
+% \end{environment}
+%
+% \subsection{Error messages}
+%
+% Some token saving:
+%
+% \begin{macrocode}
+\def\mth@error{\PackageError{mathenv}}
+% \end{macrocode}
+%
+% Now for the error messages.
+%
+% \begin{macrocode}
+\def\mth@err@number{%
+ \mth@error{Too many `&' characters found}{%
+ You've put too many `&' characters in an alignment^^J%
+ environment (like `eqnarray' or `spliteqn') and wandered^^J%
+ into trouble. I've gobbled the contents of that column^^J%
+ and hopefully I can recover fairly easily.%
+ }%
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\def\mth@err@mdsp{%
+ \mth@error{Can't do displays in nondisplay maths mode}{%
+ You're trying to start a display environment, but you're^^J%
+ in nondisplay maths mode. The display will appear but^^J%
+ don't blame me when it looks horrible.%
+ }%
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\def\mth@err@hdsp{%
+ \mth@error{Can't do displays in LR mode}{%
+ You're trying to start a display environment, but you're^^J%
+ in LR (restricted horizontal) mode. Everything will go^^J%
+ totally wrong, so your best bet is to type `X', fix the^^J%
+ mistake and start again.%
+ }%
+}
+% \end{macrocode}
+%
+% \vskip\parskip\vbox{ ^^A The best way I could find of keeping this lot
+% ^^A together, I'm afraid.
+% That's all there is. Byebye.
+%
+% \begin{macrocode}
+%</mathenv>
+% \end{macrocode}
+% \nopagebreak
+%
+% \hfill Mark Wooding, \today
+% }
+%
+% \Finale
+%
+\endinput