% \begin{meta-comment} <general public licence>
%%
%% mdwtab package -- another rewrite of the tabular environment, etc.
%% Copyright (c) 1996, 2002, 2003, 2007, 2016, 2020 Mark Wooding
%%
%% This file is part of the `mdwtools' LaTeX package collection.
%%
%% `mdwtools' 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.
%%
%% `mdwtools' 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 `mdwtools'.  If not, write to the Free Software Foundation,
%% Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
%%
% \end{meta-comment}
%
% \begin{meta-comment} <Package preambles>
%<+mdwtab>\NeedsTeXFormat{LaTeX2e}
%<+mdwtab>\ProvidesPackage{mdwtab}
%<+mdwtab>                [2020/09/06 1.14.0 Table typesetting with style]
%<+mathenv>\NeedsTeXFormat{LaTeX2e}
%<+mathenv>\ProvidesPackage{mathenv}
%<+mathenv>                [2020/09/06 1.14.0 Various maths environments]
%<+colour>\NeedsTeXFormat{LaTeX2e}
%<+colour>\ProvidesPackage{mtcolour}
%<+colour>                [2020/09/06 1.14.0 Colour support for mdwtab]
%<+color>\NeedsTeXFormat{LaTeX2e}
%<+color>\ProvidesPackage{mtcolor}
%<+color>                [2020/09/06 1.14.0 Fix for people who can't spell]
% \end{meta-comment}
%
% \CheckSum{3426}
%% \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{mtcolour}
\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).
%
% \item David Carlisle's \package{colortbl} package entirely fails to work
%       with \package{mdwtab}.  However, we now have colour support of our
%       own which is at times similar in style.
%
% \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{.}
% "$*["<params>"]" & Inserts a vertical rule of given
%                 width between columns; "*" selects
%                 "\arraythickrulewidth".*              \\ \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{.}
% "?>{"<text>"}" & Inserts \<text> before the column
%                 entry \emph{and} the rules list.*     \\ \hlx{.}
% "?<{"<text>"}" & Inserts \<text> after the column
%                 entry \emph{and} the rules list.*     \\ \hlx{.}
% "'{"<text>"}" & Inserts \<text> into the rules list
%                 only.*                                \\ \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 describes
% parameters for the line.  See section~\ref{sec:ruleparams}.
%
% { \let\tabstyle=\relax
% \begin{demo}{An example of \cmd\vline}
%\large
%\begin{tabular}
%  {| c !{\vline[5pt]} c | c |}
%  \hlx{hv}
%  \bf A & \it B & \sf C \\
%  \hlx[2pt]{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}.} ^^A
% being implemented by totally unsuitable commands.  Someone may find it
% handy.
%
%
% \subsection{An updated \cs{cline} command}
%
% \DescribeMacro{\cline}
% \DescribeMacro{\hline}
% 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"
%   \[ "*" \] \\ \[ "[" <rule-params> "]" \]
%   "{" \< <number> \[ "-" <number> \] \\ "," \> "}"
% \]]
% \end{grammar}
%
% The rules printed by |\cline| and |\hline| can be modified by rule
% parameters: see section~\ref{sec:ruleparams}.
%
% Note that |\cline| rules are rather bodgy.  Other rules now have
% \emph{thickness}, but |\cline|s don't.  Instead, they backspace over
% previous stuff.  If you don't like that, insert an appropriate gap, using
% |\vgap|.  The \lit{z} rune in |\hlx| is perfect for this kind of thing --
% precede your \lit{c} lines by \lit{z} lines for best results.
%
% {\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{Other stuff}
%
% \DescribeMacro\nextrow
% The \env{tabular} and \env{array} environments maintain a counter
% \textsf{tabrow}.  The counter is reset to zero at the start of each table.
% It is stepped by one by default; you can provide an optional argument which
% is the amount to add.
%
%
% \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"
%   \[ "*" \] \[ "[" <rule-params> "]" \]
%   "{"
%   \begin{rep}
%     \begin{stack}
%       "h" \\
%       \tok{"v["<which-cols>"]["<length>"]"} \\
%       \tok{"z["<which-cols>"]["<length>"]"} \\
%       \tok{"s["<length>"]"} \\
%       \tok{"c{"<which-cols>"}"} \\
%       "b" \\
%       \tok{"/["<number>"]"} \\
%       \tok{"!{"<rule-params>"}"} \\
%       \tok{"?{"<stuff>"}"} \\
%       \tok{"+["<step>"]"} \\
%       "."
%     \end{stack}
%   \end{rep}
%   "}"
% \]]
%
% \end{grammar}
% The |*| or optional \<rule-params> give rule-drawing parameters for the |h|
% and |c| subcommands.  (Note that you can't pass a |*| or an optional
% parameters argument to the |h| or |c| subcommands directly.)  See
% section~\ref{sec:ruleparams}.
%
% 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*{z[}\<which-cols>\lit*{][}\<length>\lit*{]}]  Like \lit{v},
%       except that the default gap is the current rule width (set by the
%       \<rule-params>) rather than |\doublerulesep|.  This is a good thing
%       to insert before a |\cline| row.
%
% \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*{!\char`\{}\<rule-params>\lit*{\char`\}}]  Change the rule
%       parameters to be used for subsequent subcommands.
%
% \item [\lit*{?\char`\{}\<stuff>\lit*{\char`\}}]  Do \<stuff>, which can be
%       any commands which \emph{don't} typeset anything.
%
% \item [\lit*{+[\<step>]}]  Add \<step> (default is 1) to the value of the
%       \textsf{tabrow} counter.
%
% \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{Rule parameters}
% \label{sec:ruleparams}
%
% The rule-drawing commands |\hline|, |\vline|, |\cline| and |\hlx|, and the
% |$| column type (which is otherwise a synonym for "|") accept \emph{rule
% parameters}.  If the command is followed by a |*|, then the rules are a bit
% thicker than usual -- they use |\arraythickrulewidth| rather than
% |\arrayrulewidth|.  However, there's an optional argument which can contain
% one of:
%
% \begin{description} \setdescriptionlabel{\ttfamily#1}
% \item[thin] Use |\arrayrulewidth| as the line width.  This is the default.
% \item[thick] Use |\arraythickrulewidth| as the line width.  This is the
%   same as giving a |*| after the command.
% \item[width=\<length>] Make the rules exactly \<length> wide.
% \item[\<length>] The same as \texttt{width=\<length>}, for compatibility.
% \end{description}
%
% More of these keywords will be added later if past experience is anything
% to go by.  Note that the individual |\hlx| subcommands \emph{don't} take
% rule parameters, but see the |!| subcommand for updating the current
% parameters.
%
% \DescribeMacro\tabsetruleparams
% If you say \syntax{"\\tabsetruleparams{"<rule-params>"}"} then the
% \<rule-params> will be prepended to any parameters provided to specific
% rule-drawing commands (including the \lit{\char`\|} preamble command).  For
% example, |\tabsetruleparams{thick}| makes all rules thick.  This is a local
% declaration.
%
%
% \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.                      \\
% |\arraythickrulewidth|& The width of starred 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 definitions 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 initialise 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{Colour support}
%
% I've now added colour support to \package{mdwtab}.  That is, you can play
% with the colours of table cell backgrounds, rules and text.  The support
% isn't there by default: you have to either give the \textsf{colour} option
% when you load \package{mdwtab}, or include the \package{mtcolour} package
% yourself.  It's very new, and might break.  It's probably not as good as
% \package{colortbl}.  I prefer English spellings for the commands and
% declarations: to reduce confusion, I've provided synonyms with fewer `u's.
% If only American package authors were so thoughtful.  The examples in this
% part of the documentation may not display correctly in some DVI viewers:
% for best results, run |dvips| and view the PostScript using (say)
% GhostScript.
%
% \subsubsection{New commands and features}
%
% \DescribeMacro\cellcolour
% The |\cellcolour| command changes the background colour for the current
% cell.  You can use it directly in a table cell, or in the table preamble.
% It doesn't matter whereabouts in the table cell it goes.  Note that
% unlike the \package{colortbl}, the |\cellcolour| command works on the
% \emph{entire} contents of the cell, including the |\tabcolsep| space and
% the rules, if any.  That means that it's robust even if there are |@{...}|
% preamble commands present.
%
% The actual syntax is like this:
%
% \begin{grammar}
% <cell-colour-cmd> ::= \[[
%   \( "\\cellcolour" \\ "\\cellcolor" \)
%   \[ "*" \]
%   \[ "[" <colour-model> "]" \]
%   "{" <colour> "}"
%   \[ "[" <left-overhang> "]"
%      \[ "[" <right-overhang> "]" \] \]
% \]]
% \end{grammar}
%
% The \lit{*} makes |\cellcolour| override an extant |\rowcolour| command
% (see below).  The \<colour-model> and \<colour> are as for the |\color|
% command.  The \<left-overhang> is how much the colour band should stick out
% to the left of the cell; and similarly for the \<right-overhang>.  If you
% don't give a \<right-overhang> then the same value is used for both; if you
% give neither then there's no overhang.  The reason you might want overhang
% is to deal with |\extracolsep| glue.  I shouldn't worry about it if I were
% you.
%
% It's very useful to use |\cellcolour| in a preamble, in particular, in the
% |?>| preamble command (which was added specifically).  (If you use only |>|
% then |\vgap| leaves very odd-looking gaps in the table.)
%
% { \let\tabstyle=\relax
% \begin{demo}{A coloured table}
%\newcolumntype{\c}[2]{%
%  >{\color{#1}}%
%  ?>{\cellcolour{#2}}%
%}
%\begin{tabular}
%   {|\c{cyan}{red}c|
%     \c{magenta}{green}c|
%     \c{yellow}{blue}c|}
%                       \hlx{hv}
%  One  &Two  &Three \\ \hlx{vhv}
%  Four &Five &Six   \\ \hlx{vhv}
%  Seven&Eight&Nine  \\ \hlx{vh}
%\end{tabular}
% \end{demo}
% }
%
% Obviously, judicious use of |\newcolumntype| would abbreviate the above
% considerably.
%
% \DescribeMacro\rowcolour
% \DescribeMacro\rowcolouroff
% The |\rowcolour| command changes the background colour in the same way as
% |\cellcolour|; however, its effect takes precedence over |\cellcolour| (but
% not |\cellcolour*|) if both are active, and isn't automatically turned off
% at the start of the next cell.  To actually turn it off again, say
% |\rowcolouroff|.
%
% \begin{grammar}
% <row-colour-cmd> ::= \[[
%   \( "\\rowcolour" \\ "\\rowcolor" \)
%   \[ "[" <colour-model> "]" \]
%   "{" <colour> "}"
% \]]
% \end{grammar}
%
% Note that you don't get to specify overhang parameters here.  The ones from
% the |\cellcolour| declaration are used, unless there isn't one in which
% case there aren't any.
%
% \DescribeMacro\ifmod
% A common thing to do is colour alternate rows of the table differently.
% This is a bit tricker for \package{mdwtab} than it would be for, say,
% \package{array}, since it's hard to spot where the `rows' actually change.
% The solution is to use the \textsf{tabrow} counter, and |\ifmod|.  Saying
% say \syntax{"\\ifmod{"$x$"}{"$m$"}{"$y$"}{"<yes>"}{"<no>"}"} is the same as
% saying \<yes> if $x \bmod m = y$, and \<no> otherwise.  This is typically
% used as follows.
%
% % { \let\tabstyle=\relax
% \begin{demo}{Alternating row colours}
%\begin{tabular}
%  {|?>{\ifmod
%    {\value{tabrow}}{2}{1}
%    {\rowcolour{white}}
%    {\rowcolour[gray]{0.9}}}
%     c|c|}
%  \hlx{h+v}
%  One   & Two   \\ \hlx{vh+v}
%  Three & Four  \\ \hlx{vh+v}
%  Five  & Six   \\ \hlx{vh+v}
%  Seven & Eight \\ \hlx{vh+v}
%  Nine  & Ten   \\ \hlx{vh+}
%\end{tabular}
% \end{demo}
% }
%
% There are new rule parameters for colours.  You get a colourful rule if you
% say \syntax{"colour" "=" <colour>}.  You can also say \syntax{"colourmodel"
% "=" <colour-model>} to choose unnamed colours.
%
% When I've thought of what other things need doing, I'll do some of them.
% The kit I've provided \emph{can} do most interesting things, but it might
% require a certain level of hacking.  Ask me if you want something and it's
% not obvious how to do it.
%
% \subsubsection{Dirty tricks}
%
% The colour support interacts with |\vgap| very badly.  The preamble rune
% |?>{\cellcolour{...}}| works well if you want to colour a column, and
% |\rowcolour| works either in the preamble or as
% |\hlx{?{\rowcolour{...}}}|.  But what if you want to just colour one table
% cell?  You can, as suggested above, just say |\cellcolour{...}| in the
% table text, but that leaves really nasty-looking gaps above and below if
% there are adjacent |\vgap| rows.
%
% This is what |\hlx{?{...}}| was invented for.  Here's a demo.
%
% \begin{demo}[w]{Colouring just one cell}
%\let\hack=\relax
%\begin{tabular}[C]{|c|?>{\hack}c|}          \hlx{hv}
%Uncoloured & cells here                  \\ \hlx{vhv}
%And some & more                          \\
%        \hlx{vh?{\gdef\hack{\cellcolour{red}}}v}
%Yet more & This one's red!               \\
%        \hlx{vh?{\global\let\hack=\relax}v}
%And more & uncoloured cells              \\ \hlx{vh}
%\end{tabular}
% \end{demo}
%
%
% \subsection{The \package{mathenv} package alignment environments}
%
% The \package{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$*$} instead.
%
% \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.
% \item [\textsf{tabrow}] contains the row number in the table.  It's a
%       proper \LaTeX\ counter.
% \end{description}
%
%    \begin{macrocode}
\newcount\tab@state
\newcount\tab@columns
\newcounter{tabrow}
%    \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
\newdimen\arraythickrulewidth
\newdimen\tab@rulewidth
%    \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
\newif\iftab@colour
%    \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@
\arraythickrulewidth\p@
%    \end{macrocode}
%
% Set some things up for alien table environments.
%
%    \begin{macrocode}
\let\tab@extrasep\tabextrasep
\let\tab@penalty\relax
%    \end{macrocode}
%
%
% \subsection{Options processing}
%
% Notice options, load package.
%
%    \begin{macrocode}
\DeclareOption{colour}{\tab@colourtrue}
\DeclareOption{color}{\tab@colourtrue}
\ProcessOptions
\RequirePackage{mdwkey}
%    \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 rapidly 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, extracting 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 dump in the |\tab@lefttext| material.
%
%    \begin{macrocode}
  \expandafter\tab@append\expandafter\tab@preamble%
    \expandafter{\tab@lefttext}%
%    \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\expandafter\tab@posttext%
    \tab@righttext%
  }%
%    \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%
      \expandafter\tab@append\expandafter\tab@shortline%
        \expandafter{\tab@rightruletext}%
      \tab@append\tab@shortline{&\omit}%
      \expandafter\tab@append\expandafter\tab@shortline%
        \expandafter{\tab@leftruletext}%
    \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{\edef#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.  This
% version just sets the major hooks, and then does a subread.  The midtext
% macro contains what to put in the very middle of each template --
% |\multicolumn| will insert its argument here.
%
%    \begin{macrocode}
\def\tab@initread{%
  \def\tab@lefttext{}%
  \def\tab@leftruletext{}%
  \def\tab@righttext{}%
  \def\tab@rightruletext{}%
  \def\tab@tabtext{&}%
  \def\tab@midtext{\ignorespaces####\@maybe@unskip}%
  \tab@initsubread%
}
%    \end{macrocode}
%
% \end{macro}
%
% \begin{macro}{\tab@initsubread}
%
% This is where most of the activity is.  We don't replace the left and right
% texts, so that we effectively inherit them rfrom the enclosing
% environment.
%
%    \begin{macrocode}
\def\tab@initsubread{%
%    \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.
%
%    \begin{macrocode}
  \tab@preamble{}%
  \tab@shortline{}%
  \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{%
  \expandafter\tab@append\expandafter\tab@shortline%
    \expandafter{\tab@leftruletext}%
  \tab@doreadpream{#1}%
  \iftab@initrule\global\tab@state\tab@prespcstate\fi%
  \tab@setstate\tab@rulestate%
  \expandafter\tab@append\expandafter\tab@shortline%
    \expandafter{\tab@rightruletext}%
  \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{\@testopt\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{\@testopt\collet@i\tab@colset}
\def\collet@i[#1]#2{%
  \@ifnextchar=%
    {\collet@ii[#1]{#2}}%
    {\collet@ii[#1]{#2}=}%
}
\def\collet@ii[#1]#2={\@testopt{\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 compatibility with the obscure way
% that \package{array} works.
%
%    \begin{macrocode}
\def\newcolumntype#1{\@testopt{\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.
% For colour support, we ensure that the total stretch in a table cell is
% 1\,fil.
%
%    \begin{macrocode}
\def\tab@halfhfil{\hskip\z@\@plus.5fil\relax}
%    \end{macrocode}
%
% And now on with the show.
%
%    \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{\tab@halfhfil\tab@bgroup}{\tab@egroup\tab@halfhfil}}
\coldef r{\tabcoltype{\hfil\tab@bgroup}{\tab@egroup}}
%    \end{macrocode}
%
% Some extensions now.  These are explicitly textual 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{\tab@halfhfil#2}{#3\tab@halfhfil}\fi%
  \if#1r\tabcoltype{\hfil#2}{#3}\fi%
}
%    \end{macrocode}
%
% Now for the default rules.
%
%    \begin{macrocode}
\coldef ${\@firstoftwo{\tab@withrp\tab@vrule}}
\coldef |{\@firstoftwo{\tab@withrp\tab@vrule[]}}
\def\tab@vrule#1{\tabruletype{#1\vrule\@width\dimen@}\tab@mkpreamble}
\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}}
\coldef ?#1#2{%
  \ifx>#1\expandafter\tabuserpretype%
  \else\expandafter\tabuserposttype\fi%
  {#2}%
  \tab@append\tab@shortline{#2}%
}
\coldef '#1{%
  \tab@append\tab@shortline{#1}%
}
%    \end{macrocode}
%
% The strange column type.
%
%    \begin{macrocode}
\coldef ##1#2{\tabcoltype{#1}{#2}}
%    \end{macrocode}
%
% And \lit{*}, which repeats a preamble spec.  The tricky part is ensuring
% that nested \lit{*} specs work correctly: we must save the loop counter, in
% |\count 0|, obviously, but \emph{also} the |\iterate| macro built which
% |\loop| modifies internally.  Usually you'd use grouping to fix this, but
% if we introduce a group level then we won't update the preamble registers
% correctly.  Instead, queue up tokens to restore the values in \TeX's input
% list.
%
%    \begin{macrocode}
\coldef *#1#2{%
  \toks\tw@\expandafter{\iterate}%
  \toks@{%
    \count@#1%
    \loop\ifnum\count@>0\relax%
      \tab@doreadpream{#2}%
      \advance\count@\m@ne%
    \repeat%
  }%
  \edef\@tempa{%
    \the\toks@%
    \def\noexpand\iterate{\the\toks\tw@}%
    \count@\the\count@%
  }%
  \@tempa%
}
%    \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%
  \setlength\hsize{#1}%
  \@arrayparboxrestore%
  \setbox\z@\vtop\bgroup%
  \global\@minipagetrue%
  \global\@noskipsecfalse%
  \everypar\expandafter{\the\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 McDonnell
% 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}%
  \let\tab@lefttext\tab@lefttexthook%
  \let\tab@righttext\tab@righttexthook%
  \let\tab@leftruletext\tab@leftruletexthook%
  \let\tab@rightruletext\tab@rightruletexthook%
  \def\tab@midtext{\tab@setcr\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{\color@begingroup$}
\def\tab@etext{\endgroup}
\def\tab@emaths{\m@th$\color@endgroup}
%    \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%
  \endgroup%
  \tab@restorehlstate%
  \global\c@tabrow\count@%
  \def\@currentlabel{\p@tabrow\thetabrow}%
  \tab@endhook%
}
%    \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{\color@begingroup$\scriptstyle}%
  \def\tab@btext{\begingroup\scriptsize}%
  \setbox\z@\hbox{\scriptsize\strut}%
  \dimen@\ht\z@\dimen@ii\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%
  \setlength\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@ii|, 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@ii%
      \@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
\let\tab@beginhook\@empty
\let\tab@lefttexthook\@empty
\let\tab@righttexthook\@empty
\let\tab@leftruletexthook\@empty
\let\tab@rightruletexthook\@empty
\let\tab@endhook\@empty
%    \end{macrocode}
%
% For setting these hooks, we provide some handy commands.
%
%    \begin{macrocode}
\def\tab@addhookbefore#1#2{%
  \toks@{#2}\toks@\expandafter{\the\expandafter\toks@#1}%
  \edef#1{\the\toks@}%
}
\def\tab@addhookafter#1#2{%
  \toks@\expandafter{#1#2}%
  \edef#1{\the\toks@}%
}
%    \end{macrocode}
%
% And now we get on with the real thing.
%
%    \begin{macrocode}
\def\@tabarray{%
  \let\@arrayleft\relax%
  \let\@arrayright\relax%
  \@testopt\@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}
  \tab@beginhook%
  \count@\c@tabrow%
  \global\c@tabrow\z@%
  \edef\tab@restorehlstate{%
    \global\tab@endheight\the\tab@endheight%
    \gdef\noexpand\tab@hlstate{\tab@hlstate}%
  }%
  \begingroup%
  \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%
  \let\tab@lefttext\tab@lefttexthook%
  \let\tab@righttext\tab@righttexthook%
  \let\tab@leftruletext\tab@leftruletexthook%
  \let\tab@rightruletext\tab@rightruletexthook%
  \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 possibilities:
%
% \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 selectively include lots of stuff from
% |\arrayparboxrestore|.
%
% 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%
  \let\if@nobreak\iffalse
  \let\if@noskipsec\iffalse
  \let\par\@@par
  \let\-\@dischyph
  \let\'\@acci\let\`\@accii\let\=\@acciii
  \everypar{}%
  \lineskip\normallineskip%
  \let\\\@normalcr%
  \color@begingroup%
  \tab@startpause%
  \vskip-\parskip%
  \parshape\@ne\@totalleftmargin\linewidth%
  \noindent%
  \doafter\tabpause@i%
}
\def\tabpause@i{%
  \nobreak%
  \tab@endpause%
  \color@endgroup%
  \ifnum0=`{\fi}%
}
%    \end{macrocode}
%
% \end{macro}
%
%
% \subsection{The wonderful world of \cmd\multicolumn}
%
% \begin{macro}{\multicolumn}
%
% This is actually fantastically 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.)
%
% Again, we have a sneaky |\kern| to prevent the final |\tabcolsep| glue from
% being eaten by a later |\unskip|.
%
%    \begin{macrocode}
\long\def\multicolumn#1#2#3{%
  \multispan{#1}%
  \begingroup%
    \tab@multicol%
    \tab@initsubread%
    \long\def\tab@midtext{#3}%
    \let\tab@looped\tab@err@multi%
    \tab@readpreamble{#2}%
    \the\tab@preamble%
    \kern\z@%
  \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{Common parsing for rule parameters twiddling}
%
% \begin{macro}{\tab@ruleparams}
%
% Given a macro name, make a (global) macro |\tab@ruledecls|, which sets
% |\dimen0| to be the chosen rule thickness, and sets up colours and whatnot,
% and then and calls the macro.  We parse a `|*|' to mean
% |\arraythickrulewidth|, an optional argument which should be something
% |\setlength| can understand, or nothing, which gives the default
% |\arrayrulewidth|.
%
% To make this properly hookable, we need to make a list of properties and
% gather them together.
%
%    \begin{macrocode}
\let\tab@rp@inithook\@empty
\let\tab@rp@sethook\@empty
\let\tab@rp@donehook\@empty
\let\tab@rp@default\@empty
\def\tab@ruleparams#1{%
  {\ifnum0=`}\fi%
  \tab@rp@inithook%
  \def\tab@rp@next{\ifnum0=`{\fi}#1}%
  \expandafter\tab@rp@keys\expandafter{\tab@rp@default}%
  \@ifstar\tab@rp@star\tab@rp@what%
}
\def\tab@rp@star{\dimen@\arraythickrulewidth\tab@rp@what}
\def\tab@rp@what{\@ifnextchar[\tab@rp@opt\tab@rp@done}
\def\tab@rp@opt[#1]{\tab@rp@keys{#1}\tab@rp@done}
\def\tab@rp@keys{\mkparse{mdwtab:rule}}
\def\tab@rp@done{%
  \protected@xdef\tab@rp@{\tab@rp@sethook}%
  \tab@rp@donehook%
  \tab@rp@next%
}
\def\tab@withrp#1{\tab@ruleparams{\tab@withrp@i{#1}}}
\def\tab@withrp@i#1{%
  \toks@{#1}%
  \toks@\expandafter{\the\expandafter\toks@\expandafter{\tab@rp@}}%
  \the\toks@%
}
%    \end{macrocode}
%
% And now to define the width parameters.
%
%    \begin{macrocode}
\tab@addhookafter\tab@rp@inithook{\dimen@\arrayrulewidth}
\tab@addhookafter\tab@rp@sethook{\dimen@\the\dimen@}
\tab@addhookafter\tab@rp@donehook{\global\tab@rulewidth\dimen@}
\mkdef{mdwtab:rule}{width}{\setlength\dimen@{#1}}
\mkdef{mdwtab:rule}{thin}*{\dimen@\arrayrulewidth}
\mkdef{mdwtab:rule}{thick}*{\dimen@\arraythickrulewidth}
\mkdef*{mdwtab:rule}*{\setlength\dimen@{#1}}
%    \end{macrocode}
%
% \end{macro}
%
% \begin{macro}{\tabsetruleparams}
%
% And the user default-parameter list.
%
%    \begin{macrocode}
\def\tabsetruleparams{\def\tab@rp@default}
%    \end{macrocode}
%
% \end{macro}
%
% \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{\noalign\tab@ruleparams\hline@prep}
\def\hline@prep{%
  \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{%
  \@tempswafalse%
  \ifx\@let@token\hline\@tempswatrue\fi%
  \ifx\@let@token\hline@prep\@tempswatrue\fi%
  \if@tempswa%
    \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%
  \color@begingroup%
  \tab@rp@\leaders\hrule\@height\dimen@\hfil%
  \tab@addruleheight\dimen@%
  \color@endgroup%
  \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}
%
% Now uses the general |\tab@ruleparams| parser.  We save and restore the
% global |\tab@rulewidth| parameter here.
%
%    \begin{macrocode}
\def\vline{%
  \begingroup%
  \@tempdima\tab@rulewidth\let\safe@\tab@rp@%
  \tab@ruleparams\tab@vline%
}
\def\tab@vline{%
  \tab@rp@\vrule\@width\dimen@%
  \global\tab@rulewidth\@tempdima\global\let\tab@rp@\safe@%
  \endgroup%
}
%    \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.  Worse, if the lines have real thickness then we leave gaps
% in the vertical rules which aren't covered by our line.  But if we
% backspace over the line, then we overwrite it with coloured blobs.
%
% We give up on doing the job properly -- that's just doomed.  Backspace over
% the previous row, and provide a hack for doing the spacing right elsewhere.
%
% 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{\noalign\tab@ruleparams\cline@do}
%    \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.  This is hardly perfect, but gets the job
% done in many cases.  Correct |\vgap| insertion fixes the remaining bugs.
%
%    \begin{macrocode}
\def\cline@do#1{%
  \noalign{\kern-\tab@rulewidth}%
  \omit%
  \global\tab@state\@ne%
  \ranges\cline@do@i{#1}\cr%
}
\def\cline@do@i#1#2{%
  \ifnum#1<\tab@state\relax%
    \tab@@cr%
    \noalign{\kern-\tab@rulewidth\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}
  \color@begingroup%
  \tab@rp@%
  \leaders\hrule\@height\tab@rulewidth\hfill%
  \color@endgroup%
}
%    \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, we just 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{\noalign\tab@ruleparams\hlx@prep}
\def\hlx@prep#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@prep\hline@prep\hlx@loop}%
    \else\def\@tempa{\hline@prep\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\@testopt\hlx@cmd@break@i0}
\def\hlx@cmd@break@i[#1]{\ifnum0=`{\fi}\pagebreak[#1]\hlx@loop}
%    \end{macrocode}
%
% \end{macro}
%
% \begin{macro}{\hlx v}
% \begin{macro}{\hlx z}
%
% Handle a \lit{v} or \lit{z} character.  This is rather like the |\vgap|
% code above, although there are syntactic differences.
%
%    \begin{macrocode}
\hlxdef v{\hlx@vgap\doublerulesep}
\hlxdef z{\hlx@vgap\tab@rulewidth}
\def\hlx@vgap#1{%
  \noalign{\nobreak}%
  \omit%
  \iffalse{\fi\ifnum0=`}\fi%
  \global\let\vgap@after\hlx@loop%
  \@ifnextchar[{\hlx@vgap@i{#1}}{\hlx@vgap@ii\vgap@simple{#1}}%
}
\def\hlx@vgap@i#1[#2]{%
  \ifx!#2!\def\@tempa{\hlx@vgap@ii\vgap@simple{#1}}%
  \else\def\@tempa{\hlx@vgap@ii{\vgap@spec{#2}}{#1}}\fi%
  \@tempa%
}
\def\hlx@vgap@ii#1#2{\@testopt{\hlx@vgap@iii{#1}}{#2}}
\def\hlx@vgap@iii#1[#2]{#1{#2}}
%    \end{macrocode}
%
% \end{macro}
% \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%
  \@testopt\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|.  The fix to
% |\cline| permeates here.
%
%    \begin{macrocode}
\hlxdef c#1{\cline@do{#1}\hlx@loop}
%    \end{macrocode}
%
% \end{macro}
%
% \begin{macro}{\hlx ?}
%
% Do some arbitrary stuff which won't typeset.  Put the stuff in a box which
% is discarded, just in case.
%
%    \begin{macrocode}
\hlxdef ?#1{%
  \noalign{\setbox\z@\hbox{\color@begingroup#1\color@endgroup}}\hlx@loop%
}
%    \end{macrocode}
%
% \end{macro}
%
% \begin{macro}{\hlx !}
%
% Change parameters in mid-flow.
%
%    \begin{macrocode}
\hlxdef !#1{\noalign\tab@ruleparams\hlx@loop[{#1}]}
%    \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}
%
% \begin{macro}{\hlx +}
% \begin{macro}{\nextrow}
%
% The \lit{+} subcommand just steps the table-row counter.
%
%    \begin{macrocode}
\hlxdef +{\nextrow\hlx@loop}
\def\nextrow{\noalign{\ifnum0=`}\fi\@testopt\nextrow@i\@ne}
\def\nextrow@i[#1]{\global\advance\c@tabrow#1\ifnum0=`{\fi}}
%    \end{macrocode}
%
% \end{macro}
% \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}
  \setlength\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{\@testopt{\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}
%
%
% \subsection{Loading the colour package}
%
% If requested, we load the \package{mtcolour} package here.  This ensures
% that it can patch this code if it needs to.
%
%    \begin{macrocode}
\iftab@colour
  \RequirePackage{mtcolour}
\fi
%    \end{macrocode}
%
% That's it.  No more.  Move along please.
%
%    \begin{macrocode}
%</mdwtab>
%    \end{macrocode}
%
%
%^^A-------------------------------------------------------------------------
% \section{Implementation of \package{mtcolour}}
%
%
% This is in a separate package to avoid dragging in the \package{color}
% package if it's unwanted.
%
% I prefer English spellings.  Here's a trivial redirection for Americans.
%
%    \begin{macrocode}
%<*color>
\DeclareOption*{\PassOptionsToPackage{\CurrentOption}{mtcolour}}
\ProcessOptions
\RequirePackage{mtcolour}
%</color>
%    \end{macrocode}
%
% And now we can start the thing properly.
%
%    \begin{macrocode}
%<*colour>
\RequirePackage{color}
%    \end{macrocode}
%
%
% \subsection{Cell background colours}
%
% First, some simple preliminaries.  The |\iftab@colour| switch is set if the
% current cell is meant to have a colour.
%
%    \begin{macrocode}
\newif\iftab@colour
\tab@colourfalse
%    \end{macrocode}
%
% We shall store the cell colour information in |\tab@cellcolour|, and the
% row colour information as |\tab@rowcolour|.  Because of the structure of
% tables, we need to make global assignments; so we must copy the current
% value away at the start of a table and put the value back at the end.  In
% order to transfer the overhang information reliably, we use a separate
% control sequence |\tab@colouroverhangs| for that -- otherwise |\color| can
% corrupt it.
%
%    \begin{macrocode}
\tab@addhookbefore\tab@beginhook{%
  \let\tab@saverowcolour\tab@rowcolour%
  \let\tab@savecolouroverhangs\tab@colouroverhangs%
  \let\tab@savecellcolour\tab@cellcolour%
}
\tab@addhookafter\tab@endhook{%
  \global\let\tab@rowcolour\tab@saverowcolour%
  \global\let\tab@colouroverhangs\tab@savecolouroverhangs%
  \global\let\tab@cellcolour\tab@savecellcolour%
}
%    \end{macrocode}
%
% Initially, there are no colours.
%
%    \begin{macrocode}
\let\tab@rowcolour\@empty%
\let\tab@cellcolour\@empty%
\let\tab@colouroverhangs\@empty%
%    \end{macrocode}
%
% \begin{macro}{\@snarfcolour}
%
% Reading a colour specification is something we'll need to do a few times,
% so an abstraction is useful.  Its single argument is a continuation to
% which we pass a colour-spec acceptable to the |\color| command.  (This is
% the same code as found in the \package{sverb} package.  Remember to keep
% them in step.)
%
%    \begin{macrocode}
\def\@snarfcolour#1{%
  \@ifnextchar[{\@snarfcolour@i{#1}}{\@snarfcolour@ii{#1}{}}%
}
\def\@snarfcolour@i#1[#2]{\@snarfcolour@ii{#1}{[#2]}}
\def\@snarfcolour@ii#1#2#3{#1{#2{#3}}}
%    \end{macrocode}
%
% \end{macro}
%
% \begin{macro}{\cellcolour}
%
% Setting a cell colour is a matter of stashing the right declarations in
% |\tab@cellcolour| and |\tab@colouroverhangs|.  Note that the overhangs end
% up in |\dimen0| and |\dimen2|.
%
%    \begin{macrocode}
\def\cellcolour{%
  \@ifstar{\tab@ccol@i{\let\tab@rowcolour\@empty}}{\tab@ccol@i{}}%
}
\def\tab@ccol@i#1{\@snarfcolour{\tab@ccol@ii{#1}}}
\def\tab@ccol@ii#1#2{\@testopt{\tab@ccol@iii{#2#1}}\z@}
\def\tab@ccol@iii#1[#2]{\@testopt{\tab@ccol@iv{#1}{#2}}{#2}}
\def\tab@ccol@iv#1#2[#3]{%
  \gdef\tab@cellcolour{\color#1\tab@colourtrue}%
  \gdef\tab@colouroverhangs{%
    \setlength\dimen@{#2}%
    \setlength{\dimen\tw@}{#3}%
  }%
}
%    \end{macrocode}
%
% \end{macro}
%
% \begin{macro}{\rowcolour}
%
% Setting the global row colour is simpler, because we don't mess with
% overhangs.
%
%    \begin{macrocode}
\def\rowcolour{\@snarfcolour\tab@setrowcolour}
\let\rowcolor\rowcolour
\def\tab@setrowcolour#1{%
  \gdef\tab@rowcolour{\color#1\tab@colourtrue}%
}
%    \end{macrocode}
%
% \end{macro}
%
% \begin{macro}{\rowcolouroff}
%
% And turning the global colouring off is easy.
%
%    \begin{macrocode}
\def\rowcolouroff{\global\let\tab@rowcolour\@empty}
\let\rowcoloroff\rowcolouroff
%    \end{macrocode}
%
% \end{macro}
%
% \begin{macro}{\tab@colourleft}
%
% Now we start on the table-cell hooks.  The left hook starts a box which
% will capture the cell's text and natural width.  We add the hook to the
% rule list as well, so that we can colour the bits in |\vgap|s correctly.
%
%    \begin{macrocode}
\tab@addhookbefore\tab@lefttexthook\tab@colourleft
\tab@addhookbefore\tab@leftruletexthook\tab@colourleft
\def\tab@colourleft{%
  \global\let\tab@cellcolour\@empty%
  \global\let\tab@colouroverhangs\@empty%
  \setbox\z@\hbox\bgroup\color@begingroup%
}
%    \end{macrocode}
%
% \end{macro}
%
% \begin{macro}{\tab@colourright}
%
% The right hook will insert an appropriate rule behind the cell and
% retypeset the cell contents over the top.  Note that the stretch in a table
% cell is exactly 1\,fil.  Because we add (leaders) and subtract (negative
% |\hskip|) 1\,fil, we retain this stretch exactly.  Don't bother unless
% there's actually some colouring.
%
%    \begin{macrocode}
\tab@addhookafter\tab@righttexthook\tab@colourright
\tab@addhookafter\tab@rightruletexthook\tab@colourright
\def\tab@colourright{%
  \color@endgroup\egroup%
  \color@begingroup%
  \global\tab@colourfalse%
  \tab@cellcolour\tab@rowcolour%
  \dimen@\z@\dimen\tw@\z@\tab@colouroverhangs%
  \iftab@colour%
    \skip@\wd\z@\advance\skip@\z@\@plus1fil%
    \skip\tw@\skip@%
    \kern-\dimen@%
    \advance\skip\tw@\dimen@%
    \advance\skip\tw@\dimen\tw@%
    \leaders\vrule\hskip\skip\tw@%
    \kern-\dimen\tw@%
    \hskip-\skip@%
  \fi%
  \color@endgroup%
  \unhbox\z@%
}
%    \end{macrocode}
%
% \end{macro}
%
%
% \subsection{Coloured rules}
%
% We hook ourselves onto the rule-parameters edifice.  This is rather
% straightforward.
%
%    \begin{macrocode}
\tab@addhookafter\tab@rp@inithook{%
  \let\tab@rulecolour\@empty%
  \let\tab@rulecolourmodel\@empty%
}
\mkdef{mdwtab:rule}{colour}{\tab@setrulecolour{#1}}
\mkdef{mdwtab:rule}{colourmodel}{\tab@setrulecolourmodel{#1}}
\mkdef{mdwtab:rule}{color}{\tab@setrulecolour{#1}}
\mkdef{mdwtab:rule}{colormodel}{\tab@setrulecolourmodel{#1}}
\mkdef{mdwtab:rule}{nocolour}*{\let\tab@rulecolour\@empty}
\mkdef{mdwtab:rule}{nocolor}*{\let\tab@rulecolour\@empty}
\mkdef{mdwtab:rule}{nocolourmodel}*{\let\tab@rulecolourmodel\@empty}
\mkdef{mdwtab:rule}{nocolormodel}*{\let\tab@rulecolourmodel\@empty}
\def\tab@setrulecolour#1{%
  \def\tab@rulecolour{\color\tab@rulecolourmodel{#1}}%
}
\def\tab@setrulecolourmodel#1{\def\tab@rulecolourmodel{[#1]}}
\tab@addhookafter\tab@rp@sethook{\tab@rulecolour}
%    \end{macrocode}
%
%
% \subsection{Other stuff}
%
% \begin{macro}{\ifmod}
%
% \syntax{"\\ifmod{"$x$"}{"$m$"}{"$y$"}{"<yes>"}{"<no>"}"} -- if $x \bmod m =
% y$ then do \<yes>; otherwise do \<no>.
%
%    \begin{macrocode}
\def\ifmod#1#2#3{%
  \begingroup%
  \@tempcnta#1%
  \@tempcntb#2%
  \count@\@tempcnta%
  \divide\count@\@tempcntb%
  \multiply\count@\@tempcntb%
  \advance\@tempcnta-\count@%
  \count@#3\relax%
  \ifnum\@tempcnta=\count@\endgroup\expandafter\@firstoftwo%
  \else\endgroup\expandafter\@secondoftwo\fi%
}
%    \end{macrocode}
%
% \end{macro}
%
% Done.
%
%    \begin{macrocode}
%</colour>
%    \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{\@testopt{\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 ones.  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}
\def\eqa@eqpos#1{%
  \if@leqno%
    \hb@xt@.01\p@{}\rlap{\normalfont\normalcolor\hskip-\displaywidth#1}%
  \else%
    \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{\@testopt\eqnalign@i{rcl}}
\def\eqnalign@i[#1]{\@testopt{\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.  There'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%
  \global\@ignoretrue%
}
\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 extremities of the environment.
%
%    \begin{macrocode}
\def\subsplit{\@ifnextchar[\subsplit@i{\subsplit@i[c]}}
\def\subsplit@i[#1]{%
  \let\@tempa\vcenter%
  \if#1t\let\@tempa\vtop\fi%
  \if#1b\let\@tempa\vbox\fi%
  \let\\\seq@cr%
  \@tempa\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}
  \@testopt\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\ primitives, 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%
  \@testopt\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}}
\collet > [tabular]>
\collet < [tabular]<
\collet * [tabular]*
\collet @ [tabular]@
%    \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
