Browse Source

Initial implementation

michael 27 years ago
parent
commit
cfa519dbe9

+ 4163 - 0
docs/packages/listings/listings.dtx

@@ -0,0 +1,4163 @@
+% \iffalse
+%<*driver>
+\documentclass{ltxdoc}
+
+\usepackage{listings}[1997/09/29]
+\selectlisting{cpp}
+\selectlisting{fortran}
+\selectlisting{pascal}
+
+\EnableCrossrefs         
+\CodelineIndex
+\OldMakeindex     % used for MakeIndex pre v2.9
+
+\begin{document}
+    \DocInput{listings.dtx}
+\end{document}
+%</driver>
+%
+% listings package for LaTeX2e
+% (w)(c) 1996-1997 Carsten Heinz, all rights reserved.
+% 
+%<+package>\NeedsTeXFormat{LaTeX2e}
+%<+package>\ProvidesPackage{listings}[1997/09/29 v0.17 by Carsten Heinz]
+% \fi
+%
+% \CheckSum{2784}
+% \DoNotIndex{\@ifundefined,\@tempa,\ ,\@dottedtocline,\@empty,\@ne}
+% \DoNotIndex{\if@twocolumn,\if@restonecol,\@mkboth,\@restonecoltrue}
+% \DoNotIndex{\@restonecolfalse,\@starttoc,\z@}
+% \DoNotIndex{\[,\{,\},\],\1,\2,\3,\4,\5,\6,\7,\8,\9,\0}
+% \DoNotIndex{\`,\,,\!,\#,\$,\&,\',\(,\),\+,\.,\:,\;,\<,\=,\>,\?,\_}
+% \DoNotIndex{\active,\addtocontents,\advance,\begin,\backslash}
+% \DoNotIndex{\baselineskip,\begingroup,\bfseries,\bgroup,\catcode}
+% \DoNotIndex{\chapter,\chardef,\closein,\csname,\def,\divide,\do}
+% \DoNotIndex{\edef,\egroup,\else,\@empty,\end,\endcsname,\endgroup}
+% \DoNotIndex{\expandafter,\fi,\gdef,\global,\hbox,\hskip,\hss,\if}
+% \DoNotIndex{\ifcat,\ifdim,\ifeof,\iffalse,\ifnum,\iftrue,\ifx}
+% \DoNotIndex{\ignorespaces,\input,\itshape,\lccode,\let,\llap,\long}
+% \DoNotIndex{\loop,\lst@,\makeatletter,\makeatother,\MakeUppercase}
+% \DoNotIndex{\message,\multiply,\newcommand,\newenvironment,\newcount}
+% \DoNotIndex{\newdimen,\newif,\newread,\next,\noindent,\onecolumn}
+% \DoNotIndex{\openin,\par,\parshape,\parskip,\protect,\read,\relax}
+% \DoNotIndex{\removelastskip,\repeat,\section,\setbox,\space}
+% \DoNotIndex{\smallbreak,\string,\textwidth,\the,\thepage,\ttfamily}
+% \DoNotIndex{\twocolumn,\undefined,\vskip,\vspace}
+%
+%
+% \title{{LISTINGS.DTX} Version {0.17}}
+% \author{{\copyright} 1996--1997 by Carsten Heinz}
+% \date{}
+%
+% \makeatletter\@twocolumntrue\makeatother
+% \maketitle
+% \tableofcontents
+% \vfill
+% \noindent \textbf{\uppercase{incompatible changes}}
+% have been made from version 0.16 to version 0.17. The commands
+% \cs{blanklisting}, \cs{clisting}, {\ldots} have been removed.
+% Languages are selected with the command \cs{selectlisting}.
+% The command \cs{labelstyle} has a new syntax and semantics.
+% These features are described on page \pageref{ssSelecting} and
+% \pageref{newlabelstyle}, respectively.
+% Sorry, but now it's possible to add languages without changing
+% the kernel \texttt{listings.sty}.
+% \onecolumn
+%
+%
+% \section{User's guide}
+%
+%
+% \subsection{Introduction}
+%
+% You have a problem? You wanna typeset source code of a programming
+% language within \LaTeXe{} like
+%     \selectlisting{cpp}
+% \iffalse
+%<*sample>
+% \fi
+% \begin{listing}
+	switch (direction)
+	{// choose direction
+		case backward     : { ... break; }
+		case backwarddown : { ... break; }
+		case up           : { ... break; }
+	}
+
+	for (int i=0; i<1000; i++)
+	{// do something
+		if (i == i) { i += 1; i--; }
+	}
+% \end{listing}
+% \iffalse
+%</sample>
+% \fi
+% \noindent or
+%     \labelstyle{\small\ttfamily}
+%     \selectlisting{pascal}
+% \iffalse
+%<*sample>
+% \fi
+% \begin{listing}
+	for i:=maxint downto 0 do
+	begin
+		{ do nothing }
+	end;
+
+	WriteLn('Pascal keywords are');
+	writeln('not case sensitive.');
+% \end{listing}
+% \iffalse
+%</sample>
+% \fi
+% Obviously the verbatim environment doesn't fit. You might use the
+% tabbing environment or something like that. But you have to mark all
+% keywords yourself and doing the indention is also a heavy work. But
+% the most striking disadvantage is that you can't run your \LaTeXe-file
+% through your C++, Pascal or whatever else compiler.
+%
+% Fortunately there is another possibility. You might use a cross
+% compiler, e.g.\ you run a special compiler on your Pascal source
+% code to get a \TeX-file with marked keywords, etc. Then \TeX{}
+% produces a pretty output (usage of a well-designed cross compiler
+% granted). If your sources change, you would have to rerun the cross
+% compiler to get your \TeX-file right and have to compile this to get
+% your document. Again and again.
+%
+% By now these days have gone. The listings package goes around this by
+% reading the source code directly. Comments, strings and keywords can
+% be typeset in different styles as shown in the examples above. The
+% indention is taken from the sources. Hence, the programmer is
+% responsible for writing 'readable' code. The package only helps to
+% present it.
+%
+% This package is surely not the final utility for typesetting
+% listings. May be it's a matter of pureness whether to use a cross
+% compiler or the listings package. Hope you join it and help to get
+% this tool more powerful. Please report all errors and offer
+% improvements!
+% 
+%
+% \subsection{Installation}
+%
+% The main files of this package are \texttt{listings.dtx} and
+% \texttt{listings.ins}. Run the latter file through \TeX{}. This
+% will create \texttt{listings.sty} and a couple of driver files
+% with the prefix \texttt{lst}, e.g.\ \texttt{lstfortran.sty},
+% but the exact name is system dependent.
+% Copy all created \texttt{.sty}-files to a directory searched by
+% \TeX{}. This completes the installation. Run \texttt{listings.dtx}
+% through \TeX{} to get the documentation \texttt{listings.dvi}.
+%
+% \textbf{Important note:} All files of the listings package are
+% distributed freely. You are not allowed to take money for the
+% distribution or use of these files, except for a nomial charge for
+% copying etc.
+% The files are distributed without any warranty; without even the
+% implied warranty of merchantability or fitness for a particular
+% purpose.
+% You are not allowed to change one of the files, except using a
+% clearly different filename.
+%
+% \textbf{Trademarks} appear throughout this documentation without any
+% trademark symbol. So you can't assume that a name is not trademarked.
+% There is no intention of infringement. The usage is to the benefit
+% of the trademark owner.
+%
+%
+% \subsection{Selecting a language}
+% \label{ssSelecting}\DescribeMacro\selectlisting
+% You choose a language with \cs{selectlisting}. The argument is (nearly)
+% one of the language names listed below. The driver files are loaded on
+% demand. The command also has an optional argument to select different
+% kinds of the same language, e.g.\ 
+% \begin{verbatim}
+%    \selectlisting[1974]{cobol}\end{verbatim}
+% selects COBOL ANS-1974, whereas the default would be ANS-1985. All
+% languages currently supported are listed together with the available
+% options, where always the first option is default, i.e.\ selected
+% if none is given.
+% I also mention what the listings package is not capable of.
+% '\texttt{???}' in driver files indicate things I don't know.
+% \textbf{To help me}:
+% \emph{Please send me an e-mail with the languages and options you
+% use (i.e.\ are tested in a way), languages and options you want
+% to be corrected or want additionally.}
+% See section \ref{ssItsNotAllFine}.
+% Note: Language selection is local now.
+%
+% \begin{description}
+% \item[Blank] \verb!\selectlisting{blank}!.
+%
+%	This is the default language: no keywords and no comments are
+%	detected (unless additional specified, see section
+%	\ref{sOtherLanguages}).
+% \item[Ada] \verb!\selectlisting{ada}!.
+%
+%	This package can't handle strings where the usual quotation marks
+%	(double quotes) are replaced by percent characters.
+% \item[Algol] \verb!\selectlisting{algol}!,
+%	options: \texttt{68}, \texttt{60}.
+%
+%	Algol 60 seems to be ok. But there are problems concerning the
+%	comments of Algol 68. First, comments enclosed by \rlap{/}c
+%	are not	supported. Second, if you use a sharp $\#$ within
+%	\verb!co!...\verb!co! (and dito within \verb!comment!), there
+%	\emph{must} be a matching second $\#$, or the output is not all
+%	right.\footnote{The problem is the following: The sharp is a special
+%	character, whereas \texttt{co} is a predefined word and consists
+%	of letters. Comments enclosed by special characters are handled
+%	easily, and even comments starting or ending with keywords are
+%	possible (Algol 60). But a mixture of both (without matching sharp)
+%	can only be handled by changing the kernel \texttt{listings.sty}.
+%	Since that would slow down all other languages, I decided to do
+%	it this way (matching sharp). I even don't know, if this way is
+%	standard Algol 68 --- the books are not very detailed, or I haven't
+%	found it.} The other way round, i.e.\ a lonely \texttt{comment}
+%	within $\#$...$\#$ is harmless.
+% \item[C] \verb!\selectlisting{c}!.
+% \item[C++] \verb!\selectlisting{cpp}!,
+%	options: \texttt{ansi}, \texttt{vc} (Visual C++).
+% \item[Cobol] \verb!\selectlisting{cobol}!,
+%	options: \texttt{1985}, \texttt{1974}, \texttt{ibm}.
+%
+%	Keywords are not marked, if their names are broken in two parts,
+%	i.e.\ continued in the following line.
+%	Sometimes portions of a string are not printed as a string.
+%	This happens, if the double quote is not doubled to insert a quote,
+%	e.g.\ \verb!""bad" cobol"! won't be printed correctly.
+% \item[Comal 80] \verb!\selectlisting{comal}!.
+% \item[Eiffel] \verb!\selectlisting{eiffel}!.
+% \item[Elan] \verb!\selectlisting{elan}!.
+% \item[Fortran] \verb!\selectlisting{fortran}!,
+%	options: \texttt{90}, \texttt{77}.
+%
+%	The keywords are assumed to be \emph{not} case sensitive.
+% \item[Java] \verb!\selectlisting{java}!.
+% \item[Lisp] \verb!\selectlisting{lisp}! (Common Lisp).
+% \item[Logo] \verb!\selectlisting{logo}!.
+% \item[Matlab] \verb!\selectlisting{matlab}!.
+%
+%	Matlab uses the quote with two meanings. This package always assumes
+%	the beginning or ending of a string, even if you use the quote as
+%	transpose-conjugate operator.
+% \item[Modula-2] \verb!\selectlisting{modula}!.
+% \item[Oberon-2] \verb!\selectlisting{oberon}!.
+% \item[Pascal] \verb!\selectlisting{pascal}!.
+% \item[Pascal XSC] \verb!\selectlisting{pxsc}!.
+%
+%	Tell me, if you want more words to be keywords.
+% \item[Turbo Pascal] \verb!\selectlisting{tp}!.
+%
+%	Keywords are from version 6.0. Possibly too many keywords present.
+% \item[Perl] \verb!\selectlisting{perl}!.
+% \item[PL/I] \verb!\selectlisting{pli}!.
+% \item[Simula 67] \verb!\selectlisting{simula}!,
+%	options: \texttt{67}, \texttt{cii}, \texttt{dec}, \texttt{ibm}.
+% \item[SQL-92] \verb!\selectlisting{sql}!.
+% \item[\TeX] \verb!\selectlisting{tex}!,
+%	options: \texttt{plain}, \texttt{primitive}, \texttt{latex},
+%		\texttt{allatex}.
+% \end{description}
+%
+%
+% \subsection{Typesetting a listing}
+%
+% \DescribeMacro\inputlisting
+% The main command for this purpose is \cs{inputlisting}. The syntax
+% is
+% \begin{verbatim}
+%    \inputlisting[FIRST,LAST]{WHOLE FILENAME}\end{verbatim}
+% where \verb![FIRST,LAST]! is optional and determines the range of lines
+% to typeset. The default range is $[1,999999]$. If you specify negative
+% lines or an empty range, for example, you won't get any warning.
+% There is no default extension, so you must specify the whole filename.
+% The example
+% \begin{verbatim}
+%    \inputlisting[3,10]{testfile.pas}\end{verbatim}
+% would print lines 3,4,\ldots,10 of \verb!testfile.pas!, if file and
+% lines are present.
+%
+% \DescribeEnv{listing}
+% There is also a listing environment. It typesets the source code
+% enclosed within \verb!\begin{listing}! and \verb!\end{listing}!.
+% If the source code starts right after \verb!\begin{listing}!, it is
+% dropped upto the end of line. Dito the source preceding and following
+% \verb!\end{listing}! directly, i.e.\ in the same line. You may don't
+% like this, but the lines
+% \begin{verbatim}
+%       \selectlisting{fortran}
+%       \begin{listing}DROPPED
+%* This is a test for the listing environment
+%C and not considered to be an example for
+%   ! Fortran!
+%      Program example
+%      ...
+%DROPPED\end{listing}DROPPED\end{verbatim}
+% result in
+%    \normallisting
+%    \selectlisting{fortran}
+% \iffalse
+%<*sample>
+% \fi
+%    \begin{listing}DROPPED
+* This is a test for the listing environment
+C and not considered to be an example for
+   ! Fortran!
+      Program example
+      ...
+%DROPPED\end{listing}DROPPED
+% \iffalse
+%</sample>
+% \fi
+%
+% \DescribeMacro\listingfalse
+% Since typesetting listings with this package is possibly slow,
+% you can suppress the output with \cs{listingfalse}. Afterwards this
+% \DescribeMacro\listingtrue
+% package only prints the name of the source like
+%     \selectlisting{pascal}\listingfalse
+%     \inputlisting{testfile.pas}\listingtrue
+% \cs{listingtrue} reverses the effect.
+% 
+% \DescribeMacro\tablength
+% If you use tabulators in your source codes, you have to tell this
+% package the number of characters between two tabulator stops.
+% Default value is 4. Changes are made by, e.g.,\ 
+% \begin{verbatim}
+%    \tablength{8}\end{verbatim}
+% i.e. tabulator stops are set at the columns 1, 9, 17, 25 {\ldots}
+% Negative values are prohibited. They won't confuse this package,
+% since it gives an error message and proceeds with the old value of
+% tablength.
+%
+% \DescribeMacro\listoflistings
+% Two more commands should be mentioned here. Use \cs{listoflistings}
+% as you do \cs{listoftables} and \cs{listoffigures} and renew
+% \DescribeMacro\listlistingsname\cs{listlistingsname} to change the
+% default header 'Listings'. The list shows either the filename or
+% the optional argument of the listing environment, e.g.\ 
+% \begin{verbatim}
+%    \inputlisting{Quicksort.pas}
+%    \begin{listing}[Heapsort]
+%    ...
+%    \end{listing}\end{verbatim}
+% will show the names 'Quicksort.pas' and 'Heapsort'.
+%
+%
+% \subsection{Figure out the appearance}\label{ssFigureOutTheAppearance}
+% You have some possibilities to change how the output looks like.
+%
+% \DescribeMacro\keywordstyle
+% By default keywords\footnote{Let's talk about keywords: I tried to get
+% all keywords of the languages, but there are so many books with no
+% list of keywords. So I looked at the index, but some books print
+% keywords bold and predefined functions in italics, other books print
+% both in bold. So I had to guess, which words are keywords. Moreover
+% it's a great deal to find out whether the keywords are case sensitive
+% or not. Of course, there are really fine books (e.g.\ \cite{Ada}).
+% And I know that some languages don't have keywords, and so there
+% can't be a list of them. But even these languages have predefined
+% words --- which are not listed. Hence, for our purpose \emph{keywords}
+% are predefined words, fixed words, reserved words, real keywords and
+% all words you or I want to name so.} are typeset bold, comments in
+% italic shape and strings using no special style.
+% \DescribeMacro\commentstyle
+% You can change this with the commands \cs{keywordstyle},
+% \DescribeMacro\stringstyle
+% \cs{commentstyle} and \cs{stringstyle}, e.g.
+% \begin{verbatim}
+%    \keywordstyle{\bfseries\itshape} % bold and italic
+%    \commentstyle{\tt\small}         % LaTeX 2.09 typewriter, small
+%    \stringstyle{\ttfamily}          % typewriter\end{verbatim}
+% will typeset the second example of the introduction as follows
+%     \keywordstyle{\bfseries\itshape} \commentstyle{\tt\small}
+%     \stringstyle{\ttfamily}
+%     \selectlisting{pascal}
+% \iffalse
+%<*sample>
+% \fi
+% \begin{listing}
+	for i:=maxint downto 0 do
+	begin
+		{ do nothing }
+	end;
+
+	WriteLn('Pascal keywords are');
+	writeln('not case sensitive.');
+% \end{listing}
+% \iffalse
+%</sample>
+% \fi
+%    \normallisting
+%
+% \DescribeMacro\blankstringtrue
+% Once again blank spaces of a string have been printed \textvisiblespace.
+% Suppress this by using \cs{blankstringtrue} and switch to default
+% \DescribeMacro\blankstringfalse
+% with \cs{blankstringfalse}.
+%
+% \DescribeMacro\labelstyle\label{newlabelstyle}
+% By default no line numbers are printed. You can change this with the
+% \cs{labelstyle} command. The syntax is
+% \begin{verbatim}
+%    \labelstyle[step]{the style}\end{verbatim}
+% The style determines how the line numbers look like (\cs{ttfamily},
+% \cs{small}, and so on). Line numbers are printed all 'step' lines.
+% More precisely all line numbers are printed, which are divisible by
+% step. If step is zero, no line numbers will be typeset.
+% The step is an optional argument. If no step is specified, it is
+% assumed to be 1. Here some (exotic) examples:
+% \begin{verbatim}
+%   \labelstyle[3]{\ttfamily\small} % line 3,6,9,..., small typewriter
+%   \labelstyle{\small\oldstylenums}% small oldstyle numbers
+%   \makeatletter
+%   \labelstyle{\@roman} % roman numbers(!) each line
+%   \labelstyle{\@Roman} % upper case roman numbers
+%   \makeatother\end{verbatim}
+%
+% The C++ source line
+%     \selectlisting{cpp}
+% \iffalse
+%<*sample>
+% \fi
+% \begin{listing}
+    if (ThereIsALongLine) { ItExceedsASingleLineInTheListing(); }
+% \end{listing}
+% \iffalse
+%</sample>
+% \fi
+% \noindent\DescribeMacro\spreadlisting
+% gives rise to an overfull \verb!\hbox!. To avoid things like that
+% you can first spread the width taken by a listing, and second
+% \DescribeMacro\prelisting
+% change the fontsize. The commands \cs{spreadlisting}, \cs{prelisting}
+% \DescribeMacro\postlisting
+% and \cs{postlisting} have one argument each. For the example above
+% you should use
+% \begin{verbatim}
+%    \spreadlisting{1in} % spread the width by 1in, 0.5in left and right
+%    \prelisting{\small} % select new fontsize
+%    \postlisting{}      % nothing to do (default)\end{verbatim}
+% or something similar and get
+%     \spreadlisting{1in}
+%     \prelisting{\small}
+% \iffalse
+%<*sample>
+% \fi
+% \begin{listing}
+    if (ThereIsALongLine) { ItExceedsASingleLineInTheListing(); }
+% \end{listing}
+% \iffalse
+%</sample>
+% \fi
+%     \normallisting
+% You can use the pre-post-mechanism to add something right before a
+% listing starts or after it ends, e.g.\ \verb!\prelisting{\bigbreak}!
+% will lead to an empty line between a listing and the preceding text
+% (if on the same page).
+%
+% \DescribeMacro\normallisting
+% Changes made by the commands above are reset by \cs{normallisting}
+% (there are no arguments): Keywords are typeset bold, comments in
+% italic shape, stringstyle, labelstyle and pre- and postlisting are
+% empty, blank spaces in strings are printed \textvisiblespace, and
+% spreadlisting is set to 0pt. Nothing other is affected.
+%
+% \DescribeMacro\lstlineskip
+% The one and only argument of this command is a skip. It's the
+% \emph{additional} space between two lines in the output of a listing.
+% The default is 0pt.
+%
+% \DescribeMacro\lstbaseem
+% Here is one more command, which should be used in driver files only,
+% since the one and only parameter is language specific. But you can
+% use it for adjustment in your document. The parameter gives the witdh
+% one character takes in the output in units of 1em. The parameter is a
+% floating number and not a \TeX{} dimension, i.e.\ the unit em is
+% added by the listings package. If you specify \verb!\lstbaseem{1}!,
+% i.e.\ 1em, characters will never overlap. And the output produced
+% after \verb!\lstbaseem{0}! looks quite funny. Better try values near
+% $0.6$.
+%
+%
+% \subsection{Other languages}\label{sOtherLanguages}
+%
+% You have some possibilities to adapt this package to other languages.
+% For our purpose here the main characteristics of a language are
+% keywords, comments and strings.
+%
+% Let's say, we want to produce following output:
+% \selectlisting{blank}
+% \keywords{function,integer,begin,end,if,then,else,return,print}
+% \DeclareCommentLine//\relax
+% \begingroup\catcode`\"=12\stringizer{"}\endgroup
+% \stringstyle{\ttfamily}\blankstringfalse
+% \iffalse
+%<*sample>
+% \fi
+% \begin{listing}
+function Fib(integer n):integer;
+// Function returns the n-th Fibonacci.
+begin
+   if (n<2) then return 1;
+			else return Fib(n-1)+Fib(n-2);
+end;
+
+// Main program.
+begin
+   print("Fib(10) = ",Fib(10), "\n");
+end.
+% \end{listing}
+% \iffalse
+%</sample>
+% \fi
+% You already know about \cs{stringstyle} and \cs{blankstringfalse}.
+% We assume \verb!\selectlisting{blank}!. And now comes all the rest
+% to print such a language mixture.
+% \DescribeMacro\keywords
+% To set the keywords use the \cs{keywords} command. After
+% \begin{verbatim}
+%    \keywords{one,two,three,four,five,six,seven,eight,nine,ten,
+%        eleven,twelve}\end{verbatim}
+% exactly these twelve keywords are present. As you see, each two
+% keywords are separated by a comma.
+% \DescribeMacro\morekeywords
+% If you want to add keywords only use \cs{morekeywords} like
+% \begin{verbatim}
+%    \morekeywords{maxreal,minreal} % add these keywords
+%    \morekeywords{zero,MAXINT}     % add also\end{verbatim}
+%
+% \DescribeMacro\sensitivetrue
+% Some languages are case sensitive, others are not. You can select
+% this with \cs{sensitivetrue} and \cs{sensitivefalse}, respectively.
+% \DescribeMacro\sensitivefalse
+% This package will then use the right keyword test.
+%
+% \DescribeMacro\stringizer
+% The command \cs{stringizer} changes the character, which begins and
+% ends a string. If your parameter consists of several characters,
+% each character can start a string. But the string must be terminated
+% with the same character. Using a letter, a digit or the underbar as
+% stringizer will not work. The Modula-2 option defines the stringizer
+% by
+% \begin{verbatim}
+%    \catcode`\"=12
+%    \stringizer{'"}\end{verbatim}
+% The catcode is changed (locally) for compatibility with
+% \verb!german.sty!. The double quote is defined active there, but
+% when we input a listing the double quote will have catcode 12
+% (=other). The stringizer command has an optional argument to select
+% whether the stringizer is doubled (default, e.g.\ Pascal) or preceded
+% by a backslash (e.g.\ C) to insert the stringizer itself at the current
+% position. The arguments are \verb!d! and \verb!b!, respectively, e.g.\ 
+% \begin{verbatim}
+%    \stringizer[d]{'} % doubled stringizer inserts stringizer
+%    \stringizer[b]{"} % backslashed stringizer inserts\end{verbatim}
+%
+% Let's come to comments. For our purpose a 'comment line' is a comment,
+% which starts with a character sequence and goes upto the end of a
+% line. 'Comments' start and end with given character sequences.
+% Comment lines need not to begin at the first column and comments
+% can start and end wherever you want.
+%
+% \DescribeMacro\DeclareCommentLine
+% \cs{DeclareCommentLine} has one parameter, which is terminated by
+% \cs{relax}, i.e.\ 
+% \begin{verbatim}
+%    \DeclareCommentLine //\relax\end{verbatim}
+% is legal. The parameter is a (nearly) arbitrary character sequence,
+% which separates a comment line. Using a letter, a digit or the
+% underbar will not work. And: When we input a listing, the characters
+% must have the same category codes. Refer section
+% \ref{SpecialCharacters} and \ref{ssSpecialCharacters}.
+% If you don't want any comment lines, let the parameter empty, but
+% don't forget the \cs{relax}!
+%
+% \DescribeMacro\DeclareSingleComment
+% Four types of comments are supported: \textbf{single} for languages
+% with one kind of comment, e.g.\ C or C++; \textbf{double} for
+% \DescribeMacro\DeclareDoubleComment
+% languages with two kinds of comments, e.g.\ Pascal comments enclosed
+% \DescribeMacro\DeclareNestedComment
+% within \verb!(*! and \verb!*)! and within \verb!{! and \verb!}!;
+% \textbf{nested} for languages with one kind of comment, which can be
+% \DescribeMacro\DeclarePairedComment
+% nested, e.g.\ Modula-2. A \textbf{paired} comment is a single comment,
+% but the two comment delimiters are the same and therefore occur paired.
+% The declaration of such comments is similar to comment lines.
+% The character sequences are separated by one blank space, e.g.\ 
+% \begin{verbatim}
+%    \DeclareSingleComment /* */\relax
+%    \DeclareDoubleComment (* *) { }\relax
+%    \DeclareNestedComment (* *)\relax
+%    \DeclarePairedComment #\relax\end{verbatim}
+% But hold on: When we input a listing, the characters must have the
+% same category codes. So the examples won't work without changing
+% them. See section \ref{ssSpecialCharacters}. If you don't want
+% comments, let the second parameter of \cs{DeclareSingleComment}
+% empty, i.e.\ type something like
+% \begin{verbatim*}
+%    \DeclareSingleComment stuff \relax\end{verbatim*}
+% If a supported language already uses your favourite keywords,
+% stringizer and/or comments, you are free to select that language
+% and adjust only the wrong data.
+%
+%
+% \subsection{Troubleshooting}
+% After receiving an e-mail from Andreas Bartelt\footnote{
+% [email protected]} the idea comes up
+% to write this section. It is intend to help you handling unusual
+% situations.
+% \begin{itemize}
+% \item	If you have problems using \cs{inputlisting} within \LaTeX{}
+%		environments or commands, put the listing in a \cs{vbox}.
+% \item	A source line might exceeds the textwidth, as shown in section
+%		\ref{ssFigureOutTheAppearance}. Put the listing in a \cs{hbox}
+%		to decrease the logical width like
+% \begin{verbatim}
+%    \hbox to 3.5in{
+%        \vbox{\inputlisting{testfile.pas}}
+%        \hss}\end{verbatim}
+%		The \cs{hss} avoids an overfull \cs{hbox}. You can use that
+%		construction together with \cs{fbox} to get something like
+% \iffalse
+%<*sample>
+% \fi
+% \setbox0=\vbox{\begin{listing}
+function Fib(integer n):integer;
+// Function returns the n-th Fibonacci.
+begin
+   if (n<2) then return 1;
+			else return Fib(n-1)+Fib(n-2);
+end;
+% \end{listing}
+% }
+% \iffalse
+%</sample>
+% \fi
+%		$$\fbox{\hbox to 3.5in{\box0\hss}}$$
+% \item	The example just presented uses \cs{inputlisting} within an
+%		argument of a command like \cs{fbox}. It's not possible with the
+%		listing environment! To go around this type
+% \begin{verbatim}
+%    \setbox0=\vbox{
+%    \begin{listing}
+%function Fib(integer n):integer;
+%...
+%    \end{listing}
+%    }% not on the same line as \end{listing}!\end{verbatim}
+%		and then \verb!$$\fbox{\hbox to 3.5in{\box0\hss}}$$! to get
+%		the example.
+% \end{itemize}
+%
+%
+% \subsection{It's not all fine}\label{ssItsNotAllFine}
+%
+% Please be patient of my English.
+%
+% Not all languages have been tested fully, since I don't know all
+% languages well. Hope I haven't forgotten any important feature.
+% Tell me, if you want additional languages or more options for a
+% language already present. What's about Delphi, Prolog or Reduce?
+% \begin{itemize}
+% \item	If you use italic cmr fonts (comments), the dollar \${} comes
+%		out as \pounds. Change italic to slanted (\cs{slshape})
+%		or don't use cmr fonts.
+% \item	If you use \cs{DeclarePairedComment}, the first comment delimiter
+%		appears not in commentstyle, e.g.\ \#\textit{ comment \#}.
+% \end{itemize}
+% You're not lucky about the listings package? You found errors?
+% Damn and blast it or contact me:
+% \begin{verbatim}
+%    [email protected]\end{verbatim}
+%
+%
+% \StopEventually{}
+%
+%
+% \section{How the package works}
+%
+% What happens when a user calls \cs{inputlisting}? First we set up a
+% bit (execute prelisting, open input file, do other initialization)
+% and at the end we have to close the input file for example.
+%
+%
+% \subsection{The main idea}\label{TheMainIdea}
+% The interesting part is the loop between: The source file is read,
+% processed and typeset line by line. Before looking closer we have to
+% deal with the alignment of columns, since this influences processing
+% and typesetting. The problem: I don't like listings, which are
+% printed with typewriter fonts. But only in these fonts all characters
+% have the same width. So we have to handle different widths.
+% The Pascal source lines
+% \begin{verbatim}
+%    if x=y then write('alignment')
+%           else print('alignment');\end{verbatim}
+% shouldn't come out as
+% \begin{center}\hfill
+% \begin{tabular}{l}
+%	if\ x=y\ then\ write('alignment')\\
+%	\ \ \ \ \ \ \ else\ print('alignment');
+% \end{tabular}
+% \hfill or \hfill
+% \begin{tabular}{l@{\space}l@{\space}l}
+%    \textbf{if} x=y&\textbf{then}&\textbf{write}('alignment')\\
+%                   &\textbf{else}&print('alignment');
+% \end{tabular}\hfill
+% \end{center}
+% only because blank spaces are not wide enough or because a bold
+% letter is wider than a normal one.
+% There is a simple trick to avoid things like that. We make boxes of
+% the same width and put one character in each box:
+% \begin{center}
+%     \vbox{\def\makeboxes#1{\fbox{\hbox to 1em{\hss\vphantom{fy}#1\ignorespaces%
+%         \hss}}\ifx#1\relax\else\expandafter\makeboxes\fi}
+%     \makeboxes if\ x=y\ then\ write\relax\space\ldots\\
+%     \makeboxes \ \ \ \ \ \ \ else \ print\relax\space\ldots}
+% \end{center}
+% Going this way the alignment of columns can't be disturbed. But if
+% the boxes are not wide enaugh, we get
+% \begin{center}
+%     \def\makeboxes#1{\hbox{\hbox to 0.45em{\hss\vphantom{fy}#1\ignorespaces%
+%         \hss}}\ifx#1\relax\else\expandafter\makeboxes\fi}
+%     \begin{tabular}{l}
+%     \makeboxes if\ x=y\ then\ write\relax\space\ldots
+%     \end{tabular}
+% \end{center}
+% And choosing the width so that the widest character fits in, leads to
+% \begin{center}
+%     \def\makeboxes#1{\hbox to 1em{\hss\vphantom{fy}#1\hss}\ignorespaces%
+%         \ifx#1\relax\else\expandafter\makeboxes\fi}
+%     \begin{tabular}{l}
+%     \makeboxes if\ x=y\ then\ write\relax\space\ldots
+%     \end{tabular}
+% \end{center}
+% Both are not acceptable. So there is more to do. Each input line
+% will be cut up in units. Since we want to scan for keywords, this
+% is no extra work. In the example the units are
+% \begin{center}\begin{tabular}{ccccccc}
+%     if, & x, & =, & y, & then, & write, & \ldots
+% \end{tabular}\end{center}
+% and the blank spaces between. We put each unit in a box, which width
+% is multiplied by the number of characters we put in, of course. The
+% result is
+% \begin{center}
+%     \def\makeboxes#1#2{\fbox{\hbox to #1em{\hss\vphantom{fy}#2\hss}\ignorespaces%
+%         }\ifx#2\relax\else\expandafter\makeboxes\fi}
+%     \begin{tabular}{l}
+%     \makeboxes2{i\hss f}1{\ }1{x}1{=}1{y}1{\ }4{t\hss h\hss e\hss n}%
+%         1{\ }5{w\hss r\hss i\hss t\hss e}1\relax\space\ldots
+%     \end{tabular}
+% \end{center}
+% Now we are ready to choose the base width of a box --- that's
+% \cs{lstbaseem}. Consider the 'write'. The 'w' needs more space than
+% base width, but the 'i' needs less. This will compensate each other,
+% because we put them in the same box. In general: Since wide characters
+% use space actually reserved for thin characters, the base width need
+% not to be the width of the widest character. This would be 1em
+% (a \cs{quad}). At the moment most languages use the empirical value
+% 0.6em. It's a compromise between overlapping characters and the
+% number of boxes exceeding not the textwidth, i.e.\ how many
+% characters fit a line without getting an overfull \verb!\hbox!.
+%
+% 
+% \subsection{Line processing}
+% Let's discuss the line processing. The job is to classify comments,
+% strings and other source code, where we search for keywords. We do
+% that in several steps.
+% \begin{itemize}
+% \item First we pay attention on comments, which started in preceding
+%	lines, e.g.\ 
+%	\begin{verbatim}
+%    comment } for i:=1 to maxint do ...\end{verbatim}
+%	In that case we look for the end of comment and output the comment.
+%	If there is other source code left, we run the line processing on
+%	that code.
+% \item If no comment is in work, we look for one and split the input
+%	into comment and other source code. Since the other code comes
+%	first, we give it to a routine, which cuts it into the units
+%	described above (tokenizing). The output takes place there.
+% \item Afterwards we have to output the comment. But when we look for
+%	a comment, we don't take notice of other things. Consider
+%	\begin{verbatim}
+%    writeln('This is a string { and not a comment }');\end{verbatim}
+%	We cut this line at the left brace into other code and comment.
+%	After typesetting the other code we notice, that a string started,
+%	but hasn't been finished. Our first classification was wrong.
+%	We use the comment as new input and simply run the line processing
+%	again to continue the string.
+% \item If all strings are finished, we can output the comment, since
+%	it's really a comment.
+% \end{itemize}
+% This is a sketch of line processing. For more detailed information
+% see section \ref{ssLineProcessing}, where the implementation is
+% described.
+%
+% One question about the third item is left: Why do we cut off a
+% comment, even if we don't know that it is a comment? It's a matter
+% of modularity and extension. Consider the alternative: The tokenize
+% routine below (where we cut the classified input into the smallest
+% units) would have to look for the start and end of comment.
+% To support different languages we have to write either more than one
+% tokenize routine or one, which handles comments of all languages.
+% Adding another language means extending tokenizing or writing a new
+% routine, which looks only for the particular comment. But finding a
+% comment has nearly nothing to do with looking for delimiters (blank
+% space, comma, plus, bracket, etc.). So we write exactly one tokenize
+% macro and separate this from finding a comment.
+%
+%
+% \subsection{Tokenizing}
+% The next step is breaking up the parts produced by line processing
+% into the units mentioned above. We gather all characters, until
+% reaching a nonletter. Then we output the collected characters using
+% a routine, which selects the right style (comment, keyword, string).
+% Afterwards we handle the nonletter:
+%
+% If it is a stringizer, we switch a string boolean to indicate whether
+% we are in string mode or not. This boolean is also used by the line
+% processing.
+%
+% If we found a tabulator, we go to the next tabulator stop. The output
+% routines are responsible for knowing the number of blanks we need.
+%
+% If it's any other nonletter, we gather all coming nonletter (upto the
+% next letter, of course) and output these nonletter. Then we start
+% with a letter again, \ldots
+%
+%
+% \subsection{Special characters}\label{SpecialCharacters}
+% As you know some characters have a special meaning to \TeX, e.g.\ the
+% subscript \verb!_! or the backslash \verb!\!. \TeX{} realizes this
+% using so called category codes (catcodes). \TeX{} knows sixteen
+% different ones:
+% \begin{center}\begin{tabular}{rll}
+%	 0 & escape delimiter (backslash)& \verb!\catcode`\\=0!\\
+%	 1 & beginning of a group ($\{$)& \verb!\catcode`\{=1!\\
+%	 2 & ending of a group ($\}$)	& \verb!\catcode`\}=2!\\
+%	 3 & mathematics shift ($\$$)	& \verb!\catcode`\$=3!\\
+%	 4 & tabulator ($\&$)		& \verb!\catcode`\&=4!\\
+%	 5 & end of line (carriage return)& \verb!\catcode`\^^M=5!\\
+%	 6 & macro parameter (\verb!#!) & \verb!\catcode`\#=6!\\
+%	 7 & superscript (\verb!^!)	& \verb!\catcode`\^=7!\\
+%	 8 & subscript (\verb!_!)	& \verb!\catcode`\_=8!\\
+%	 9 & ignore			& \verb!\catcode`\^^@=9!\\
+%	10 & blank space		& \verb!\catcode`\ =10!\\
+%	11 & letter			& A..Z,a..z\\
+%	12 & other			& \\
+%	13 & active (e.g.\ \verb!~!)	& \\
+%	14 & comment			& \verb!\catcode`\%=14!\\
+%	15 & invalid characters		&
+% \end{tabular}\end{center}
+% When \TeX{} reads a character, it looks up the associated catcode and
+% treats the character accordingly, e.g.\ an active character stands
+% for a command without a leading backslash (like \verb!~! or the
+% double quote in \verb!german.sty!).
+%
+% We can't change catcodes of characters, which \TeX{} has already
+% read. But we are able to change them before. After
+% \verb!\catcode`\A=10! an upper 'A' has the same effect as a blank
+% space! Consider the \TeX source
+% \begin{verbatim}
+%    \def\uppera{A} % saving upper 'A'; we shouldn't use \upperA. Why?
+%    \catcode`\A=10 % 'A' becomes blank space. That's the reason!
+%    MayAbeAaAcuriousAexample. \upperaAnd it work's.\end{verbatim}
+% The output is
+% \begin{verbatim}
+%    May be a curious example. And it work's.\end{verbatim}
+% First we save the 'A'. Changing the catcode has no effect on the
+% definition in the first line, since \TeX{} has read it before. All
+% coming 'A' are blank spaces.
+%
+% We want to input and typeset characters 'as they are'. But the
+% subscript or the macro parameter character are not printable. So it
+% is necessary to change catcodes. We make these characters active.
+% We also change catcodes of printable characters, e.g.\ a digit
+% (normally other) will be treated as a letter, since indentifiers like
+% \verb!x1!, \verb!y2! are legal. Then it is possible to gather all
+% characters upto a nonletter to cut up a unit!
+%
+% We change catcodes for input and output. That's clear. But we also
+% do it to define some commands. One example: In Pascal we have to look
+% for \verb!{!. Let's say, we compare it with a left brace from a
+% source file. This only works, if both have the same meaning.
+% And when we declare the comment, \TeX{} must know the associated
+% catcode, since it can't be changed later.
+% Hence, we have to change it also at the time of defining the macros.
+%
+% There is at least one more thing to say: Catcodes aren't easy to
+% work with.
+%
+%
+% \section{General \TeX{}niques}
+%
+% \subsection{Macro parameter parsing}
+% A macro has at most nine parameters. They are numbered consecutively
+% and are referenced by $\#1,\ldots,\#9$. In the definition they appear
+% after the macro name, e.g.\ 
+% \begin{verbatim}
+%    \def\macro#1#2#3{\textbf{#1}\texttt{#2}\textit{#3}}\end{verbatim}
+% has three parameters. \verb!\macro the! and \verb!\macro{t}{h}{e}!
+% both lead to the output '\textbf{t}\texttt{h}\textit{e}'.
+% Parameters with more than one character must be enclosed in braces.
+% If you call the macro with less than three parameters, you will get
+% an error message (hopefully most times), since the three parameters
+% are the calling syntax of the macro. That's all well known.
+%
+% But \TeX's macro processor is more powerful. Nearly any character
+% sequence and parameter mixture can be used for the calling syntax,
+% e.g.\ 
+% \begin{verbatim}
+%    \def\macro z=(#1,#2){ ... }\end{verbatim}
+% The call \verb!\macro{10}{0}! is illegal, but \verb!\macro z=(10,0)!
+% is ok. The parameters are '10' and '0', respectively.
+%
+% This mechanism can be used to check whether a character sequence
+% is a substring of another sequence --- which will be used to
+% extract comments and keywords, but this comes later. Consider
+% \begin{verbatim}
+%    \def\macro #1substring#2\relax{ ... }\end{verbatim}
+% If we call this macro, we should always add \verb!substring\relax!
+% at the end, since the sequence belongs to the syntax of the macro:
+% \begin{verbatim}
+%    \macro This is our first call.substring\relax\end{verbatim}
+% Here the second parameter of the macro will be empty, but using
+% \begin{verbatim}
+%    \macro This is a substring example.substring\relax\end{verbatim}
+% the second parameter is not empty, since the first 'substring'
+% terminates the first parameter and lets the second begin after
+% (upto the closing \cs{relax}). The character sequence 'substring'
+% is a substring of the preceding character sequence, if and only if
+% the second parameter is not empty.
+%
+% Later we let the preceding character sequence be a list of keywords
+% to test whether a character sequence is a keyword or not.
+% Or we let the preceding character sequence be the current soure line
+% and replace 'substring' by  '//' to look for a C++ comment line.
+%
+%
+% \subsection{Quick 'if parameter empty'}
+% There are many situations where you have to look whether a macro
+% parameter is empty or not. Let's say, we want to test the first
+% parameter, which is refered by $\#1$. The \emph{natural} way would
+% be something like
+% \begin{verbatim}
+%    \def\test{#1}%
+%    \ifx \test\empty %
+%            % #1 is empty
+%    \else %
+%            % #1 is not empty
+%    \fi %\end{verbatim}
+% where \cs{empty} is defined by \verb!\def\empty{}!, of course.
+% And now the \emph{mad} way:
+% \begin{verbatim}
+%    \ifx \empty#1\empty %
+%            % #1 is empty
+%    \else %
+%            % #1 is not empty
+%    \fi %\end{verbatim}
+% Having an empty parameter the \cs{empty} left from $\#1$ is compared
+% with the \cs{empty} on the right. Since they are the same, it's all ok.
+% If the parameter is not empty, the \cs{empty} on the left is compared
+% with the first token of the parameter. Assuming this token is not
+% equivalent to \cs{empty} the \cs{else} section is executed as desired.
+% The paramater must not be the macro \cs{empty}, e.g.
+%
+% The mad way works, if and only if the first token of the parameter is
+% not equivalent to \cs{empty}. You must check, if this meets your
+% purpose. The two \cs{empty}s might be replaced by any other macro,
+% which is not equivalent to the first token of the parameter.
+% But the definition of that macro shouldn't be too complex, since
+% this slows down the \cs{ifx}. Consider
+% \begin{verbatim}
+%    \def\test{#1}\ifx \test\empty \else \fi % natural\end{verbatim}
+% and
+% \begin{verbatim}
+%    \ifx \empty#1\empty \else \fi % mad\end{verbatim}
+% The mad version needs about $45\%$ of the natural's time.
+%
+%
+% \section{Implementation}
+%
+% Before considering the implementation, here some conventions I used:
+% \begin{itemize}
+% \item The names of all public macros (the user commands) have lower
+%	case letters. (That's not true: \cs{DeclareCommentLine}, \ldots,
+%	but consistent with the third item.)
+% \item The name of all private macros and variables have prefixes:
+%	\verb!lst@! for a general macro or variable, \verb!lstdrv@! when
+%	it is defined in a driver file, and \verb!lstenv@! if it is
+%	defined for the listing environment.
+% \item To distinguish procedure-like macros from macros holding data,
+%	the name of procedure macros use upper case letters with each
+%	beginning word, e.g.\ \verb!\lst@ProcessLine!. (The only exception
+%	is the 'procedure-macro' \verb!\lst@ifoneof!.)
+% \end{itemize}
+%
+%
+% \subsection{Registers and variables}\label{ssRegisters}
+% The current version needs 1 read register, 5 counters, 2 dimensions
+% and 1 token register. The counter \verb!\@tempcnta! and the dimension
+% \verb!\@tempdima! are also used, see the index.
+%
+% \begin{macro}{\lst@inputfile}
+% \begin{macro}{\lst@ifendinput}
+% \begin{macro}{\iflisting}
+% \verb!\iflisting! is described in the user's guide. The input file
+% is \verb!\lst@inputfile!. The output of the file terminates, if and
+% only if the boolean \verb!\lst@ifendinput! is true.
+%    \begin{macrocode}
+%<*package>
+\newif\iflisting
+\newread\lst@inputfile
+\def\lst@endinputtrue{\let\lst@ifendinput\iftrue}
+\def\lst@endinputfalse{\let\lst@ifendinput\iffalse}
+%    \end{macrocode}
+% \end{macro}\end{macro}\end{macro}
+%
+% \begin{macro}{\lst@lastno}
+% \begin{macro}{\lst@lineno}
+% The user specified last line and the current input line are kept
+% in two counters:
+%    \begin{macrocode}
+\newcount\lst@lastno \newcount\lst@lineno
+%    \end{macrocode}
+% \end{macro}\end{macro}
+%
+% \begin{macro}{\lst@ifcomment}
+% \begin{macro}{\lst@ifstring}
+% \begin{macro}{\lst@commentdepth}
+% Comments (not whole comment lines) and strings are indicated by
+% following booleans. The current comment depth uses a counter.
+%    \begin{macrocode}
+\newcount\lst@commentdepth
+\def\lst@commenttrue{\let\lst@ifcomment\iftrue}
+\def\lst@commentfalse{\let\lst@ifcomment\iffalse}
+\def\lst@stringtrue{\let\lst@ifstring\iftrue}
+\def\lst@stringfalse{\let\lst@ifstring\iffalse}
+%    \end{macrocode}
+% \end{macro}\end{macro}\end{macro}
+%
+% \begin{macro}{\lst@width}
+% \begin{macro}{\lst@length}
+% \begin{macro}{\lst@pos}
+% The dimension \verb!\lst@width! holds the width of a single character
+% box and is set to \verb!\lst@baseem em!, when we output a listing.
+% The counter \verb!\lst@length! holds the length of the current
+% character string we want to output.
+% \verb!\lst@pos! holds the current column number to handle tabulators.
+%    \begin{macrocode}
+\newdimen\lst@width \newcount\lst@length \newcount\lst@pos
+%    \end{macrocode}
+% \end{macro}\end{macro}\end{macro}
+%
+% \begin{macro}{\lst@halfspread}
+% That's the half of spreadlisting's argument.
+%    \begin{macrocode}
+\newdimen\lst@halfspread
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lst@line} \begin{macro}{\lst@comment}
+% \begin{macro}{\lst@commentline}
+% Some variables need no allocation here, since they are macros, e.g.\ 
+% most user commands save their parameter within a macro. The most
+% important 'data' macros are \verb!\lst@line!, \verb!\lst@comment!
+% and \verb!\lst@commentline!. They hold the current line, comment and
+% comment line for line processing.
+% \end{macro}\end{macro}\end{macro}
+%
+% \begin{macro}{\lst@other}
+% This version gather non-alphanumeric characters before their output.
+% Since these characters might expand, we need a token register to
+% gather them, where they surely do not expand.
+%    \begin{macrocode}
+\newtoks\lst@other
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Comments}\label{ssComments}
+%
+% First we discuss comment lines (CL). Let's say, we have a C++ source
+% line with a comment, which is separated by '//'. To cut the line into
+% code and comment we use a macro like this:
+% \DescribeMacro\lst@CutCL
+% \begin{verbatim}
+%    \def\lst@CutCL#1//#2\relax{%
+%        \def\lst@line{#1}\def\lst@commentline{//#2}}\end{verbatim}
+% The parameter definition ensures that the first parameter holds the
+% code and our second paramater the comment upto a \cs{relax}, which
+% marks the end of the source. We (re)define the input and comment line,
+% where we must add the separator '//' again. That's easy.
+% \DescribeMacro\lst@CommentLine
+% But if we call this macro using a line without any '//', \TeX{}
+% detects a syntax error, since the line doesn't meet the definition.
+% Hence, we can't use the cut macro to look for a comment line,
+% but this:
+% \begin{verbatim}
+%    \def\lst@CommentLine{%
+%        \expandafter\lst@TestCL\lst@line//\relax}\end{verbatim}
+% Additional '//' and '\cs{relax}' hold up the syntax of the cut macro.
+% That's the point. We use an \cs{expandafter}, because we need the
+% \emph{content} of \verb!\lst@line! and not the macro token itself as
+% parameter. So the test macro is called (or expanded) after the
+% content is written behind.
+%
+% \DescribeMacro\lst@TestCL
+% Why we don't use the cut macro here? Our additional '//' would be
+% added to the comment! Therefore:
+% \begin{verbatim}
+%    \def\lst@TestCL#1//#2\relax{%
+%        \ifx\empty#2\empty %
+%            \let\lst@commentline\empty %
+%        \else %
+%            \expandafter\lst@CutCL\lst@line\relax %
+%        \fi}\end{verbatim}
+% If you compare the definition of \verb!\lst@TestCL! here and the
+% call above, you will see: The second parameter is empty, if and only
+% if there is no comment (no double slash). So we are able to call
+% the cut macro without additional '//' if we've found a comment.
+%
+% \begin{macro}{\DeclareCommentLine}
+% \begin{macro}{\lst@CommentLine}
+% \begin{macro}{\lst@TestCL}
+% \begin{macro}{\lst@CutCL}
+% Now comes the real implementation. It's different from the C++
+% example, but it only seems to. The one and only parameter of
+% \cs{DeclareCommentLine} is the comment line separator.
+% First we test, if comment lines are desired. If not we let the main
+% macro be empty. Otherwise we define three macros similar to the
+% example. But: To distinguish their parameters from the comment line
+% separator $\#1$, we have to double the '$\#$': The $n$th parameter
+% of a macro within a macro is $\#\#n$. If you know this, following
+% is clear: It's the same as the simplified example.
+%    \begin{macrocode}
+\def\DeclareCommentLine#1\relax{%
+  \ifx\@empty#1\@empty \let\lst@CommentLine\@empty %
+  \else
+      \def\lst@CommentLine{\expandafter\lst@TestCL\lst@line#1\relax}%
+      \def\lst@TestCL##1#1##2\relax{%
+          \ifx\@empty##2\@empty \let\lst@commentline\@empty %
+          \else \expandafter\lst@CutCL\lst@line\relax %
+          \fi}%
+      \def\lst@CutCL##1#1##2\relax{%
+          \def\lst@line{##1}\def\lst@commentline{#1##2}}%
+  \fi}
+%    \end{macrocode}
+% \end{macro}\end{macro}\end{macro}\end{macro}
+%
+% \begin{macro}{\lst@DefineSingleComment}
+% \begin{macro}{\lst@SOC}
+% \begin{macro}{\lst@EOC}
+% For single comments we use the same cut mechanism as above, except
+% that we use it for the start of comment (SOC) and for the end of
+% comment (EOC): We define six macros here. Additional the comment
+% boolean is switched by the cut macros. The last two parameters of
+% \verb!lst@DefineSingleComment! are the character sequences for the
+% beginning and ending of a single comment, of course. The first
+% parameter is used as suffix for the macro names.
+%    \begin{macrocode}
+\def\lst@DefineSingleComment[#1]#2 #3\relax{%
+  \ifx\@empty#3\@empty %
+    \expandafter\let\csname lst@SOC#1\endcsname\relax %
+    \expandafter\let\csname lst@EOC#1\endcsname\relax %
+  \else %
+    \expandafter\def\csname lst@SOC#1\endcsname{\expandafter %
+        \expandafter\csname lst@TestSOC#1\endcsname \lst@line#2\relax}%
+    \expandafter\def\csname lst@TestSOC#1\endcsname##1#2##2\relax{%
+        \ifx\@empty##2\@empty\else \expandafter %
+            \expandafter\csname lst@CutSOC#1\endcsname \lst@line\relax %
+        \fi}%
+    \expandafter\def\csname lst@CutSOC#1\endcsname##1#2##2\relax{%
+        \lst@commenttrue \def\lst@line{##1}\def\lst@comment{#2##2}}%
+    \expandafter\def\csname lst@EOC#1\endcsname{\expandafter %
+        \expandafter\csname lst@TestEOC#1\endcsname \lst@line#3\relax}%
+%    \end{macrocode}
+%    \begin{macrocode}
+    \expandafter\def\csname lst@TestEOC#1\endcsname ##1#3##2\relax{%
+          \ifx\@empty##2\@empty %
+%    \end{macrocode}
+% Here we are in the situation that we look for the end of comment but
+% haven't found one. Since we are in comment mode, the whole line is
+% the comment and the line gets empty.
+%    \begin{macrocode}
+              \let\lst@comment\lst@line \let\lst@line\@empty %
+          \else \expandafter %
+              \expandafter\csname lst@CutEOC#1\endcsname\lst@line\relax%
+          \fi}%
+    \expandafter\def\csname lst@CutEOC#1\endcsname##1#3##2\relax{%
+        \lst@commentfalse \def\lst@line{##2}\def\lst@comment{##1#3}}%
+  \fi}
+%    \end{macrocode}
+% \end{macro}\end{macro}\end{macro}
+%
+% \begin{macro}{\DeclareSingleComment}
+% That's an abbreviation of the macro just defined, but where the
+% suffix-parameter is empty.
+%    \begin{macrocode}
+\def\DeclareSingleComment{\lst@DefineSingleComment[]}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\DeclarePairedComment}
+% First we define a single comment. Then we adjust one cut macro:
+% The SOC delimiter is defined to belong to the line and not to the
+% comment.
+%    \begin{macrocode}
+\def\DeclarePairedComment#1\relax{%
+    \lst@DefineSingleComment[]#1 #1\relax %
+    \def\lst@CutSOC##1#1##2\relax{%
+        \lst@commenttrue \def\lst@line{##1#1}\def\lst@comment{##2}}}%
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\DeclareDoubleComment}
+% We define a single comment and another one with slightly different
+% names (additional \verb!@!). Then we compose the two single comments.
+%    \begin{macrocode}
+\def\DeclareDoubleComment#1 #2 #3 #4\relax{%
+    \lst@DefineSingleComment[]#1 #2\relax %
+    \lst@DefineSingleComment[@]#3 #4\relax %
+    \lst@HookComment#1 #3 \lst@TestSOC@\lst@EOC@\lst@SavedEOC}%
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lst@HookComment}
+% The purpose of this macro is to compose a SOC/EOC pair already
+% defined with another SOC/EOC pair, which need not to be defined yet.
+% The job is to coincide start and end of comment: We have to look
+% whether the first, the second or none comment starts, and must
+% select the right macro to find the corresponding end of comment.
+% The first and second parameter are the SOC delimiters of the first
+% (defined) and second SOC/EOC pair, respectively. Therefor they are
+% separated by blank spaces. The third and fourth parameters are the
+% \verb!TestSOC! and \verb!EOC! macros of the second SOC/EOC pair.
+% Parameter five is a macro name used to save a EOC macro. That's done
+% in the second line:
+%    \begin{macrocode}
+\def\lst@HookComment#1 #2 #3#4#5{%
+    \let#5\lst@EOC %
+    \def\lst@TestSOC##1#1##2\relax{%
+%    \end{macrocode}
+% Now $\#\#1$ holds the code of the line and $\#\#2$ (possibly) the
+% comment. But we have to look whether the other comment type starts
+% before this here or not. So we call the test macro of the other
+% comment first. If we've found one, we let \verb!\lst@EOC! be the
+% macro, which looks for the end of that comment.
+%    \begin{macrocode}
+        #3##1#2\relax %
+        \lst@ifcomment \let\lst@EOC#4%
+%    \end{macrocode}
+% Otherwise we do the test for this comment. If there is a comment,
+% we cut up the line and let \verb!\lst@EOC! be the macro, which
+% looks for the end of this comment.
+%    \begin{macrocode}
+        \else %
+            \ifx\@empty##2\@empty \else %
+                \expandafter\lst@CutSOC\lst@line\relax %
+                \let\lst@EOC#5%
+            \fi %
+        \fi}}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\DeclareNestedComment}
+% For nested comments we do it the same way: We declare a single
+% comment and adjust some macros. Testing for an end of comment is
+% nearly the same as for single comments.
+%    \begin{macrocode}
+\def\DeclareNestedComment#1 #2\relax{%
+    \lst@DefineSingleComment[]#1 #2\relax %
+    \def\lst@TestEOC##1#2##2\relax{%
+%    \end{macrocode}
+% The only difference is that we have to count how many (new) comments
+% start in the comment. And this is done here, the rest is the same as
+% above.
+%    \begin{macrocode}
+        \lst@CountSOC##1#1\relax %
+        \ifx\@empty##2\@empty %
+            \let\lst@comment\lst@line \let\lst@line\@empty %
+        \else %
+            \expandafter\lst@CutEOC\lst@line\relax %
+        \fi}%
+%    \end{macrocode}
+% An end of comment lets the comment depth decrease. If we reach 0,
+% we set the comment boolean false. That's not new, since this happens
+% always with not nested comments.
+%    \begin{macrocode}
+    \def\lst@CutEOC##1#2##2\relax{%
+        \advance\lst@commentdepth by -1\relax %
+        \ifnum 0=\lst@commentdepth \lst@commentfalse\fi %
+        \def\lst@line{##2}\def\lst@comment{##1#2}}%
+%    \end{macrocode}
+% Now we have to do something for increasing the comment depth. We
+% count how many new comments start within a comment. To move through
+% a comment we use the same separation mechanism as all the time. The
+% second parameter is empty, if and only if there is no (more) start
+% of comment. While it is not empty we increase the comment depth and
+% call this macro again with the current rest of the comment.
+%    \begin{macrocode}
+    \def\lst@CountSOC##1#1##2\relax{%
+        \ifx\@empty##2\@empty\else %
+            \advance\lst@commentdepth by 1%
+            \def\@tempa{\lst@CountSOC##2\relax}%
+%    \end{macrocode}
+% Note: \verb!\@tempa! is executed after the closing \verb!\fi! to call
+% the macro again.
+%    \begin{macrocode}
+            \expandafter\@tempa %
+        \fi}}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\DeclareCLPercent}
+% This command is equivalent to \verb!\DeclareCommentLine %\relax!,
+% where the percent has the catcode we need when we input a listing.
+%    \begin{macrocode}
+{\catcode`\%=12 \gdef\DeclareCLPercent{\DeclareCommentLine %\relax}}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\DeclareDoubleCommentPascal}
+% Dito for Pascal comments.
+%    \begin{macrocode}
+\begingroup \catcode`\[=1 \catcode`\]=2
+\catcode`\{=\active \catcode`\}=\active \catcode`\*=\active
+\gdef\DeclareDoubleCommentPascal[\DeclareDoubleComment (* *) { }\relax]
+\endgroup
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Keywords}\label{ssKeywords}
+%
+% \begin{macro}{\lst@CaseSensitiveKeywords}
+% We have to decide whether a given character sequence is a reserved
+% word or not. Doing this test is very familiar with the cut mechanism
+% for comments. To test, if \verb!key! is a keyword, we define a macro
+% \begin{verbatim}
+%    \def\lst@test#1,key,#2\relax{...}\end{verbatim}
+% Afterwards we call the macro with the parameters
+% \begin{center}\begin{tabular}{l@{}l}
+%    all current keywords&\verb!,key,\relax!
+% \end{tabular}\end{center}
+% When \TeX{} passes the arguments, the second parameter is empty,
+% if and only if \verb!key! is not a current keyword. So we are able to
+% decide whether to make a normal box, or a box with keywordstyle.
+%    \begin{macrocode}
+\def\lst@CaseSensitiveKeywords#1\relax{%
+    \def\lst@test##1,#1,##2\relax{%
+        \ifx \@empty##2\@empty \lst@MakeBox{}%
+        \else \lst@MakeBox{\lst@keywordstyle}%
+        \fi}%
+%    \end{macrocode}
+% We only need to call the macro defined right before. \verb!,#1,\relax!
+% holds up the syntax of the macro.
+%    \begin{macrocode}
+    \expandafter\lst@test\lst@keywords,#1,\relax}%
+%    \end{macrocode}
+% Since \TeX{} always passes two arguments to the test macro, \TeX{}
+% splits the whole 'input' \verb!\lst@keywords,#1,\relax! in two parts.
+% So there is no need to sort the keywords by probability.\footnote{If
+% you sort the keywords by probability and make a loop for the keyword
+% tests, which terminates right after finding a keyword, you might think
+% that's faster than the \TeX{}nique used here. Well, if your source
+% code uses the three or four most common keywords only, you are right.
+% Most cases it will be slow. In fact the versions 0.1 and 0.11 have
+% used something like loops, even something faster, but which is much
+% slower than this here.}
+% \end{macro}
+%
+% \begin{macro}{\lst@NonCaseSensitiveKeywords}
+% Now we implement the test for keywords, which are not case sensitive.
+% We use two \cs{uppercase} to normalize the test string and the keywords.
+% For the keywords we need some expandafters, so that the keywords are
+% expanded before making the characters upper case.
+%    \begin{macrocode}
+\def\lst@NonCaseSensitiveKeywords#1\relax{%
+    \uppercase{\def\lst@test##1,#1,##2\relax{%
+        \ifx \@empty##2\@empty \lst@MakeBox{}%
+        \else \lst@MakeBox{\lst@keywordstyle}%
+        \fi}}%
+    \expandafter\uppercase\expandafter{%
+        \expandafter\lst@test\lst@keywords,#1,\relax}}%
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lst@IfOneOf}
+% \begin{macro}{\lst@ifoneof}
+% We define two macros, which are very familiar with the keyword tests.
+% The first macro is a case sensitive version of the second one. The
+% first parameter is terminated by \cs{relax}, the other three are not.
+% If the first parameter is found in the second parameter (a keyword
+% list) the third parameter is executed. Otherwise we perform the forth.
+% The implementation is clear.
+%    \begin{macrocode}
+\def\lst@IfOneOf#1\relax#2{%
+    \def\lst@test##1,#1,##2\relax{%
+        \ifx \@empty##2\@empty \expandafter\@secondoftwo %
+        \else \expandafter\@firstoftwo %
+        \fi}%
+    \lst@test,#2,#1,\relax}%
+\def\lst@ifoneof#1\relax#2{%
+    \uppercase{\def\lst@test##1,#1,##2\relax{%
+        \ifx \@empty##2\@empty \expandafter\@secondoftwo %
+        \else \expandafter\@firstoftwo %
+        \fi}}%
+    \uppercase{\lst@test,#2,#1,\relax}}%
+%    \end{macrocode}
+% \end{macro}\end{macro}
+%
+%
+% \subsection{Commands}\label{ssCommands}
+% \begin{macro}{\selectlisting}
+% This command loads the specified driver file and selects the language.
+% We give an error message, if the driver file doesn't support the
+% necessary macro.
+%    \begin{macrocode}
+\newcommand\selectlisting[2][]{%
+    \@ifundefined{lstdrv@#2@}{\input{lst#2.sty}}{}%
+    \@ifundefined{lstdrv@#2@}{%
+        \PackageError{Listings}{Driver file for `#2' corrupt}{%
+        The driver file doesn't define \string\lstdrv@#2@.}}{%
+    \@ifundefined{lstdrv@#2@#1}{%
+        \PackageError{Listings}{Option `#1' not supported}{%
+        The driver file doesn't define \string\lstdrv@#2@#1.}}{%
+    \csname lstdrv@#2@#1\endcsname \def\lst@curr{#2}\def\lst@opt{#1}}}}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lst@ifselect}
+% \begin{macro}{\lst@ifoption}
+% These two private macros are similar to \LaTeXe{}'s \verb!\@ifundefined!,
+% except that the selected language and option are tested, of course.
+%    \begin{macrocode}
+\def\lst@ifselect#1{\def\lst@test{#1}%
+    \ifx\lst@curr\lst@test \expandafter\@firstoftwo %
+    \else \expandafter\@secondoftwo \fi}
+\def\lst@ifoption#1{\def\lst@test{#1}%
+    \ifx\lst@opt\lst@test \expandafter\@firstoftwo %
+    \else \expandafter\@secondoftwo \fi}
+%    \end{macrocode}
+% \end{macro}\end{macro}
+%
+% \begin{macro}{\keywordstyle}
+% \begin{macro}{\commentstyle}
+% \begin{macro}{\stringstyle}
+% \begin{macro}{\labelstyle}
+% The following user commands save the parameter in (private) macros.
+% The labelstyle command checks for a legal step count for labels.
+%    \begin{macrocode}
+\newcommand\keywordstyle[1]{\def\lst@keywordstyle{#1}}
+\newcommand\commentstyle[1]{\def\lst@commentstyle{#1}}
+\newcommand\stringstyle[1]{\def\lst@stringstyle{#1}}
+\newcommand\labelstyle[2][1]{\def\lst@labelstyle{#2}%
+    \ifnum #1>-1 \def\lst@labelstep{#1}\else %
+    \PackageError{Listings}{Nonnegative integer expected}{%
+    You can't use `#1' as step count for labels.^^J%
+    I'll forget it and proceed.}\fi}
+%    \end{macrocode}
+% \end{macro}\end{macro}\end{macro}\end{macro}
+%
+% \begin{macro}{\tablength}
+% \begin{macro}{\lstbaseem}
+% \begin{macro}{\lstlineskip}
+% \cs{tablength} and \cs{lstbaseem} also look, if the arguments are
+% legal.
+%    \begin{macrocode}
+\newcommand\tablength[1]{\ifnum#1>0 \def\lst@tablength{#1}\else %
+    \PackageError{Listings}{Strict positive integer expected}{%
+    You can't use `#1' as tablength.^^J I'll forget it and proceed.}\fi}
+\newcommand\lstbaseem[1]{\ifdim #1em>0pt \def\lst@baseem{#1}\else %
+    \PackageError{Listings}{Strict positive number expected}{%
+    You can't use `#1' as baseem.^^J I'll forget it and proceed.}\fi}
+\newcommand\lstlineskip[1]{\def\lst@lineskip{#1}}
+%    \end{macrocode}
+% \end{macro}\end{macro}\end{macro}
+%
+% \begin{macro}{\prelisting}
+% \begin{macro}{\postlisting}
+% \begin{macro}{\spreadlisting}
+% \begin{macro}{\keywords}
+% \begin{macro}{\morekeywords}
+% \begin{macro}{\stringizer}
+% More 'parameter-saving' commands:
+%    \begin{macrocode}
+\newcommand\prelisting[1]{\def\lst@prelisting{#1}}
+\newcommand\postlisting[1]{\def\lst@postlisting{#1}}
+\newcommand\spreadlisting[1]{\lst@halfspread#1\relax %
+    \lst@halfspread 0.5\lst@halfspread\relax}
+\newcommand\keywords[1]{%
+    \edef\lst@keywords{,\zap@space#1 \@empty}}
+\newcommand\morekeywords[1]{%
+    \edef\lst@keywords{\lst@keywords,\zap@space#1 \@empty}}
+\newcommand\stringizer[2][d]{%
+    \@ifundefined{lst@#1TestStringizer}{%
+        \PackageError{Listings}{Illegal stringizer option `#1'}{%
+        Available options are 'b' and 'd'.}}{%
+    \expandafter\let\expandafter\lst@TestStringizer %
+    \csname lst@#1TestStringizer\endcsname \def\lst@stringizer{#2}}}
+%    \end{macrocode}
+% \end{macro}\end{macro}\end{macro}\end{macro}
+% \end{macro}\end{macro}
+%
+% \begin{macro}{\blankstringtrue}
+% \begin{macro}{\blankstringfalse}
+% \begin{macro}{\sensitivetrue}
+% \begin{macro}{\sensitivefalse}
+% The user switches assign the right macros.
+%    \begin{macrocode}
+\newcommand\blankstringtrue{%
+    \let\lst@MakeStringBox\lst@MakeBox}
+\newcommand\blankstringfalse{%
+    \let\lst@MakeStringBox\lst@MakeSpecialStringBox}
+\newcommand\sensitivetrue{%
+    \let\lst@KeywordOrNot\lst@CaseSensitiveKeywords}
+\newcommand\sensitivefalse{%
+    \let\lst@KeywordOrNot\lst@NonCaseSensitiveKeywords}
+%    \end{macrocode}
+% \end{macro}\end{macro}\end{macro}\end{macro}
+%
+% \begin{macro}{\normallisting}
+% The default style is set using the previous commands:
+%    \begin{macrocode}
+\newcommand\normallisting{%
+    \keywordstyle{\bfseries}\commentstyle{\itshape}%
+    \stringstyle{}\labelstyle[0]{}%
+    \prelisting{}\postlisting{}%
+    \spreadlisting{0pt}\blankstringfalse}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\listoflistings}
+% At the end of this section we define commands for the list of
+% listings. It's a derivation of \cs{listoffigures}.
+%    \begin{macrocode}
+\newcommand\listoflistings{%
+    \ifx\chapter\undefined %
+        \expandafter\section \else \expandafter\chapter %
+    \fi *{\listlistingsname %
+      \@mkboth{\MakeUppercase\listlistingsname}%
+              {\MakeUppercase\listlistingsname}}%
+    \@starttoc{lol}}
+\newcommand\listlistingsname{Listings}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lst@ListOfListingsEntry}
+% And at the very end a command to add an entry to the list. The first
+% parameter is the name of the listing, and the second is reserved for
+% the line range, I think, but not used so far.
+%    \begin{macrocode}
+\newcommand\lst@ListOfListingsEntry[2]{%
+    \ifx \@empty#1\@empty \else %
+        \addtocontents{lol}{\protect\ListOfListingsLine{#1}{#2}%
+            {\lst@curr}{\thepage}}%
+    \fi}
+\newcommand\ListOfListingsLine[4]{%
+    \@dottedtocline{1}{1.5em}{2.3em}{#1}{#4}}
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Typesetting a listing}
+% \begin{macro}{\inputlisting}
+% Now we define the main command. The first parameter is optional and
+% set to $[1,999999]$, if none is given. The second parameter is the
+% filename. If the file doesn't exist, we give an error message.
+% Otherwise we process the listing. But all this only happens,
+% if listings are desired.
+%    \begin{macrocode}
+\newcommand\inputlisting[2][1,999999]{%
+    \lst@ListOfListingsEntry{#2}{}%
+    \iflisting %
+        \batchmode \openin\lst@inputfile#2 \errorstopmode %
+        \ifeof\lst@inputfile %
+            \PackageError{Listings}{File `#2' not found}{%
+            You must tell me the right name or I can't do the job.}%
+        \else %
+            \message{(#2}\lst@ProcessListing[#1]\message{)}%
+        \fi \closein\lst@inputfile %
+    \else %
+        \begin{center}%
+        --- Listing of #2 has been skipped. ---
+        \end{center}%
+    \fi}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lst@ProcessListing}
+% The two parameters of this command are the first and last output
+% line, respectively. First we set up a bit and skip the lines of the
+% listing upto the first printing line.
+%    \begin{macrocode}
+\def\lst@ProcessListing[#1,#2]{%
+    \lst@Begin{#1}%
+    \lst@lastno #2%
+    \@whilenum #1>\lst@lineno \do %
+        {\read\lst@inputfile to\lst@line %
+         \advance\lst@lineno\@ne}%
+%    \end{macrocode}
+% The following loop terminates, if the end of file or the specified
+% last line is reached. In the loop we read and process the listing
+% line by line.
+%    \begin{macrocode}
+    \lst@endinputfalse %
+    \loop %
+        \read\lst@inputfile to\lst@line %
+        \ifeof\lst@inputfile \lst@endinputtrue \fi %
+        \ifnum\lst@lastno<\lst@lineno\lst@endinputtrue\fi %
+    \lst@ifendinput\else %
+        \expandafter\lst@RemovePar\lst@line\par\relax %
+        \lst@AllLineProcessing %
+    \repeat %
+    \lst@End}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lst@RemovePar}
+% The next macro removes (together with the special call above) a
+% \cs{par} from the input line. So we need only one \cs{long}
+% definition, namely this here.
+%    \begin{macrocode}
+\long\def\lst@RemovePar#1\par#2\relax{\def\lst@line{#1}}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\listing}
+% Now we define the environment for typesetting listings. To read the
+% \TeX-file line by line we have to make the end of line character
+% \verb!^^M! active. If no output is desired, we typeset a message and
+% read the listing without doing any output.
+% Ending the environment is very easy.
+%    \begin{macrocode}
+\newenvironment{listing}{%
+    \iflisting\else
+        \begin{center}%
+        --- Listing has been skipped. ---
+        \end{center}%
+    \fi %
+    \lst@Begin{1}\catcode`\^^M=\active %
+    \lstenv@SkipLineAndProcess}{}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lstenv@SkipLineAndProcess}
+% We will use a mechanism used in the new implementation of \LaTeX's
+% \verb!verbatim! environments. I don't explain it here. It is
+% described in section 3.4 of \cite{verbatim}.
+%    \begin{macrocode}
+\begingroup
+\catcode`\!=\active \catcode`\(=\active \catcode`\)=\active
+\lccode`\!=`\\ \lccode`\(=`\{ \lccode`\)=`\}
+\catcode`\~=\active \lccode`\~=`\^^M
+\lowercase{
+%    \end{macrocode}
+% The effect of \cs{lowercase} is that all \verb+!+, \verb!(!, \verb!)!
+% and \verb!~! of the argument are converted to \verb!\!, \verb!{!,
+% \verb!}! and \verb!^^M!.
+% The macro \verb!\lstenv@SkipLineAndProcess! skips the rest of the
+% line, tests the optional argument and begins the loop of processing.
+%    \begin{macrocode}
+\gdef\lstenv@SkipLineAndProcess#1~{%
+    \lstenv@TestOptional#1[]~\lstenv@ReadAndProcess}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lstenv@TestOptional}
+% The second parameter is empty, if and only if there is no optional
+% argument.
+%    \begin{macrocode}
+\gdef\lstenv@TestOptional#1[#2]#3~{%
+    \ifx\@empty#2\@empty\else \lst@ListOfListingsEntry{#2}{}\fi}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lstenv@ReadAndProcess}
+% The macro \verb!\lstenv@ReadAndProcess! gets the input upto the next
+% end of line character. We append \verb!\end{listing}\relax!
+% to hold up the syntax of \verb!\lstenv@Process!.
+%    \begin{macrocode}
+\gdef\lstenv@ReadAndProcess#1~{\lstenv@Process#1!end(listing)\relax}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lstenv@Process}
+% The second parameter of this macro is empty, if and only if the end
+% of the environment is not reached. If the listing goes on, we define
+% the current line, do the line processing and define the next macro.
+% If the listing is over, we define the right macro to be done next.
+%    \begin{macrocode}
+\gdef\lstenv@Process#1!end(listing)#2\relax{%
+    \ifx \@empty#2\@empty %
+        \iflisting \def\lst@line{#1}\lst@AllLineProcessing \fi %
+        \let\lst@next\lstenv@ReadAndProcess %
+    \else %
+        \def\lst@next{\lst@End\end{listing}}%
+    \fi \lst@next}
+}\endgroup
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lst@Begin}
+% \begin{macro}{\lst@End}
+% Let's look what's to do to begin and end a listing, respectively.
+% We insert a small skip, the user defined \verb!\lst@prelisting!
+% and \verb!\lst@postlisting! and initialize some variables.
+% Of course, we use a new group level, so that outer blocks are not
+% affected by the changes made here.
+%    \begin{macrocode}
+\newcommand\lst@Begin[1]{%
+    \smallbreak\bgroup\lst@prelisting %
+    \parskip\lst@lineskip %
+    \lst@stringfalse \lst@commentdepth0 \lst@commentfalse %
+    \let\lst@comment\@empty \let\lst@commentline\@empty %
+    \lst@lineno\@ne %
+%    \end{macrocode}
+% The following two lines ensure, that \TeX{} doesn't read font
+% information from other files when catcodes are changed.
+%    \begin{macrocode}
+    \setbox0\hbox{{\lst@keywordstyle}{\lst@commentstyle}%
+        {\lst@stringstyle}{{\lst@labelstyle0}}}%
+%    \end{macrocode}
+% The textwidth for a listing is spread using a parshape command
+% every paragraph. If \verb!\lst@labelstep! is zero, no labels (=line
+% numbers) are printed.
+%    \begin{macrocode}
+    \@tempdima\textwidth \advance\@tempdima by 2\lst@halfspread %
+    \expandafter\ifnum \lst@labelstep=0 %
+        \everypar{\parshape 1 -\lst@halfspread \@tempdima}%
+    \else %
+%    \end{macrocode}
+% The parameter is the number of the first printing line. We calculate
+% how many lines it will take to set the first label (a line number)
+% and assign it to \verb!\@tempcnta!.
+%    \begin{macrocode}
+        \@tempcnta#1\divide\@tempcnta\lst@labelstep %
+        \multiply\@tempcnta-\lst@labelstep \advance\@tempcnta#1\relax %
+        \ifnum\@tempcnta>0 \advance\@tempcnta-\lst@labelstep \fi %
+%    \end{macrocode}
+% Defining \cs{everypar} is easy now and some other things also.
+%    \begin{macrocode}
+        \everypar{\parshape 1 -\lst@halfspread \@tempdima %
+            \ifnum \@tempcnta=0 %
+                \advance\@tempcnta-\lst@labelstep \llap{%
+                \bgroup\lst@labelstyle\the\lst@lineno\relax\egroup\ }%
+            \fi %
+            \advance\@tempcnta\@ne}%
+    \fi %
+    \expandafter\lst@width\lst@baseem em %
+    \lst@ChangeCatcodes %
+%    \end{macrocode}
+% Finally we call the language's own prepare macro.
+%    \begin{macrocode}
+    \edef\next{lstdrv@\lst@curr @PrepareListing}%
+    \expandafter\csname\next\endcsname}
+%    \end{macrocode}
+% The ending of a listing is not very exciting.
+%    \begin{macrocode}
+\def\lst@End{\lst@postlisting\catcode`\%=\lst@ccPercent %
+    \par\removelastskip\egroup \smallbreak\ignorespaces}
+%    \end{macrocode}
+% \end{macro}\end{macro}
+%
+%
+% \subsection{Line processing}\label{ssLineProcessing}
+%
+% \begin{macro}{\lst@AllLineProcessing}
+% Here comes the single line processing. First we collect the line
+% processing in one macro: Some initialization, pre-processing,
+% processing and post-processing, but only if the line is not empty.
+% We increase the current line number also.
+%    \begin{macrocode}
+\def\lst@AllLineProcessing{%
+    \ifx \lst@line\@empty \par\noindent\hbox{}\else
+        \let\lst@text\@empty \lst@length0 \global\lst@pos0 %
+        \let\lst@lastother\@empty %
+        \par\noindent \lst@PrePL \lst@ProcessLine \lst@PostPL %
+    \fi \advance\lst@lineno\@ne}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lst@PrePLDefault}
+% \begin{macro}{\lst@PostPLDefault}
+% Before considering the main macro we define the defaults for
+% \verb!\lst@PrePL! and \verb!\lst@PostPL!. The latter gives a
+% warning, if a string exceeds a line.
+%    \begin{macrocode}
+\let\lst@PrePLDefault\relax
+\def\lst@PostPLDefault{%
+    \lst@ifstring %
+        \PackageWarning{Listings}{string constant exceeds line}%
+        \lst@stringfalse %
+    \fi}
+%    \end{macrocode}
+% \end{macro}\end{macro}
+%
+% \begin{macro}{\lst@ProcessLine}
+% Now the main macro for line processing. There is no parameter,
+% because the data is given by \verb!\lst@line!. We construct a loop
+% by defining the macro \cs{next} to call this macro again. But this
+% definition might changes soon to terminate line processing.
+%    \begin{macrocode}
+\def\lst@ProcessLine{\let\next\lst@ProcessLine %
+%    \end{macrocode}
+% Since a comment might exceeds a line, we have to handle this case
+% first. We try to find the end of comment, which saves the comment
+% in \verb!\lst@comment! and might changes the boolean
+% \verb!\lst@ifcomment!.
+%    \begin{macrocode}
+    \lst@ifcomment \lst@EOC %
+%    \end{macrocode}
+% To output the comment we use a little trick (concerning the naming
+% of a macro). The tokenize macro below not only cuts up the input for
+% scanning keywords. In comment mode it will cut the input in the same
+% way, but always uses commentstyle for the output. Therefore we
+% switch to comment mode locally and call the macro.
+%    \begin{macrocode}
+        {\lst@commenttrue \expandafter\lst@Tokenize\lst@comment\relax}%
+%    \end{macrocode}
+% We empty the comment just output. If the comment goes on, i.e.\ the
+% comment was the whole line, line processing is over, i.e.\ there is
+% nothing to do next: We redefine the macro \cs{next}.
+%    \begin{macrocode}
+        \let\lst@comment\@empty \lst@ifcomment \let\next\relax \fi %
+    \else %
+%    \end{macrocode}
+% If no comment is in progress, the macro tries to find one and cuts
+% off a comment line, if possible (or a part of the line as a comment
+% line).
+%    \begin{macrocode}
+        \lst@SOC \lst@CommentLine %
+%    \end{macrocode}
+% Now \verb!\lst@line! has been cut to the noncomment rest.
+% We have to find the keywords. \cs{relax} is used as a brake:
+% It marks the end and will terminate tokenizing.
+%    \begin{macrocode}
+        {\lst@commentfalse \expandafter\lst@Tokenize\lst@line\relax}%
+%    \end{macrocode}
+% If a string has begun in \verb!\lst@Tokenize!, but not finished,
+% the potential comment above belongs to the string. What's to do? The
+% input line gets the comment and the next character is typeset. Then
+% we call this macro without being in danger classifing the comment as
+% a comment again, because the first character is missing now. But
+% hold on: The comment might be empty and so the input line. To handle
+% this we use two \cs{relax} as brake and might redefine \cs{next}.
+% \verb!\lst@PostPL! might gives a warning to the user.
+%    \begin{macrocode}
+        \lst@ifstring %
+            \lst@commentfalse %
+            \expandafter\expandafter\expandafter\lst@TypesetChar %
+                \expandafter\lst@commentline\lst@comment\relax\relax %
+                \let\lst@comment\@empty \let\lst@commentline\@empty %
+            \ifx \lst@line\@empty \let\next\relax \fi %
+        \else %
+%    \end{macrocode}
+% If no string is in work, it's all fine. We output the comment line,
+% if present. In that case there is no other comment.
+%    \begin{macrocode}
+            \ifx\lst@commentline\@empty \else %
+                \lst@commenttrue %
+                \expandafter\expandafter\expandafter\lst@Tokenize %
+                    \expandafter\lst@commentline\lst@comment\relax %
+                \lst@commentfalse %
+            \fi %
+%    \end{macrocode}
+% For comments this macro calls itself to find the end of comment.
+% As this is the default, we only have to assign the comment to
+% \verb!\lst@line! --- the implizit parameter of this macro.
+% If there is no comment, we redefine \cs{next}.
+%    \begin{macrocode}
+            \lst@ifcomment \let\lst@line\lst@comment %
+            \else \let\next\relax %
+            \fi %
+%    \end{macrocode}
+% We have to close some ifs and do the next thing.
+%    \begin{macrocode}
+        \fi %
+    \fi\next}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lst@TypesetChar}
+% The following macro has been used in the last macro. It typesets the
+% next character and removes it from the input line.
+%    \begin{macrocode}
+\def\lst@TypesetChar#1#2\relax{\def\lst@line{#2}\lst@OutputChar#1}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lst@ProcessWhitespaces}
+% This macro processes all whitespaces (blank spaces and tabulators here)
+% from the beginning of \verb!\lst@line! upto the first non-whitespace.
+% The macro assumes that \verb!\lst@text! is already output.
+%    \begin{macrocode}
+\def\lst@ProcessWhitespaces{%
+    \expandafter\lst@TestWhitespace\lst@line\relax}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lst@EndTestWhitespace}
+% To end the whitespace test we get the line upto the closing \cs{relax}
+% and assign it to \verb!\lst@line!.
+%    \begin{macrocode}
+\def\lst@EndTestWhitespace#1\relax{\def\lst@line{#1}}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lst@TestWhitespace}
+% The real work is done here. We test for a whitespace, do the output
+% and decide what's to be done next.
+%    \begin{macrocode}
+\def\lst@TestWhitespace#1{\let\next\lst@TestWhitespace %
+    \ifcat #1&\lst@GotoNextTabStop %
+    \else \if #1\lst@outputblank \lst@OutputChar#1%
+    \else
+        \ifx#1\relax \let\lst@line\@empty \let\next\relax %
+        \else \def\next{\lst@EndTestWhitespace#1}%
+        \fi %
+    \fi \fi \next}
+%    \end{macrocode}
+% \end{macro}
+% The line processing is complete. Now we will try to scan keywords.
+%
+%
+% \subsection{Tokenizing}\label{ssTokenizing}
+% We define two tokenize macros. The first determines potential
+% keywords by collecting characters upto a nonletter. After outputting
+% the potential keyword the second macro is called to gather all
+% characters upto the next letter. Then these characters are output
+% and the first macro is called again. That's how the two macros work
+% together.
+%
+% \begin{macro}{\lst@Tokenize}
+% The tokenize macro gets code upto \cs{relax} and scans for keywords
+% and strings. In fact it only cuts up potential keywords, which are
+% tested right before their output. We define the next operation first:
+%    \begin{macrocode}
+\def\lst@Tokenize#1{\let\lst@next\lst@Tokenize%
+%    \end{macrocode}
+% An incoming letter is gathered. If we found a nonletter, we output
+% the preceding text. The keyword test takes place there.
+%    \begin{macrocode}
+    \ifcat #1a%
+        \edef\lst@text{\lst@text#1}\advance\lst@length\@ne %
+    \else %
+        \lst@Output %
+%    \end{macrocode}
+% If the other character is a tabulator, we go to the next tab stop.
+%    \begin{macrocode}
+        \ifcat #1&\lst@GotoNextTabStop %
+    \else %
+%    \end{macrocode}
+% Getting to the terminator \cs{relax} ends tokenizing by defining
+% next operation empty, here \cs{relax}. Otherwise our next operation
+% is 'tokenizing' nonletter characters.
+%    \begin{macrocode}
+        \ifx#1\relax \let\lst@next\relax %
+        \else \let\lst@next\lst@TokenizeOther %
+%    \end{macrocode}
+% If we are in comment mode, we have not to look for strings and gather
+% the nonletter character. Otherwise we look for stringizer. Then come
+% some closing \cs{fi}s and the next operation.
+%    \begin{macrocode}
+            \lst@ifcomment \lst@length\z@ \lst@AppendOther#1%
+            \else \lst@TestStringizer#1\fi %
+        \fi %
+    \fi \fi \lst@next}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lst@TokenizeOther}
+% This macro looks like \verb!lst@Tokenize! except that we have to
+% insert some \verb!\lst@OutputOther!.
+%    \begin{macrocode}
+\def\lst@TokenizeOther#1{%
+    \let\lst@next\lst@TokenizeOther %
+    \ifcat #1a%
+        \lst@OutputOther \let\lst@lastother\@empty %
+        \def\lst@text{#1}\lst@length\@ne %
+        \let\lst@next\lst@Tokenize %
+    \else \ifcat #1&%
+        \lst@OutputOther \lst@GotoNextTabStop %
+    \else %
+        \ifx#1\relax \lst@OutputOther \let\lst@next\relax %
+%    \end{macrocode}
+% Now comes something new. If we find two successive blank spaces, we
+% output all preceding other characters first. This avoid alignment
+% problems when too many blanks follow each other.
+% The rest is unchanged.
+%    \begin{macrocode}
+        \else \ifx\lst@lastother\lst@inputblank\if#1\lst@inputblank %
+            \lst@OutputOther \fi\fi %
+        \lst@ifcomment \lst@AppendOther#1%
+        \else \lst@TestStringizer#1%
+        \fi \fi %
+    \fi \fi \lst@next}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lst@AppendOther}
+% This macro simply appends a character to the token register
+% \verb!\lst@other!.
+%    \begin{macrocode}
+\def\lst@AppendOther#1{\advance\lst@length\@ne %
+    \expandafter\lst@other\expandafter{\the\lst@other#1}}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lst@bTestStringizer}
+% Here we do the stringizer tests. If a string already started, we
+% gather the current character and look for the closing stringizer.
+% If we've found it, we output \verb!\lst@other! and switch the
+% string boolean, but only if the preceding other character is not
+% a backslash (which inserts a stringizer at the current position
+% of the string).
+%    \begin{macrocode}
+\def\lst@bTestStringizer#1{%
+    \lst@ifstring \lst@AppendOther#1%
+        \expandafter\ifx\lst@closing@stringizer#1%
+            \ifx\lst@lastother\lst@inputbackslash \else %
+            \lst@OutputOther \global\lst@stringfalse %
+        \fi \fi %
+        \def\lst@lastother{#1}%
+%    \end{macrocode}
+% If we are not in string mode, we compare the current character with
+% all given stringizers and gather the character afterwards, since
+% the string boolean might changes and we might output the preceding
+% characters with a different style.
+%    \begin{macrocode}
+    \else %
+        \def\lst@lastother{#1}%
+        \expandafter\lst@DoStringizerTest\lst@stringizer\relax %
+        \lst@AppendOther#1%
+    \fi}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lst@dTestStringizer}
+% Nearly the same:
+%    \begin{macrocode}
+\def\lst@dTestStringizer#1{\def\lst@lastother{#1}%
+    \lst@ifstring \lst@AppendOther#1%
+        \ifx\lst@closing@stringizer\lst@lastother %
+            \lst@OutputOther \global\lst@stringfalse %
+        \fi %
+    \else %
+        \expandafter\lst@DoStringizerTest\lst@stringizer\relax %
+        \lst@AppendOther#1%
+    \fi}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lst@DoStringizerTest}
+% Now we consider a stringizer test. Reaching \cs{relax} results in
+% doing nothing and so terminating the tests.
+%    \begin{macrocode}
+\def\lst@DoStringizerTest#1{%
+    \ifx#1\relax \else %
+%    \end{macrocode}
+% Otherwise we compare the current character and the current stringizer.
+% If they are equal, we output the preceding characters, switch the
+% string boolean and save the stringizer as closing stringizer.
+%    \begin{macrocode}
+        \expandafter\ifx\lst@lastother#1\relax %
+            \lst@OutputOther \global\lst@stringtrue %
+            \gdef\lst@closing@stringizer{#1}%
+        \fi %
+%    \end{macrocode}
+% At the end we call this macro again. The macro terminates reaching
+% the \cs{relax}!
+%    \begin{macrocode}
+        \expandafter\lst@DoStringizerTest %
+    \fi}%
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Output}\label{ssOutput}
+% \begin{macro}{\lst@Output}
+% It's time to do text output. First we look, if there is anything to
+% output.
+%    \begin{macrocode}
+\def\lst@Output{%
+    \ifx\lst@text\@empty\else %
+%    \end{macrocode}
+% Then we decide, whether to make a stringbox (using stringstyle) or
+% a box for a comment (using commentstyle as explicit parameter).
+%    \begin{macrocode}
+        \lst@ifstring \lst@MakeStringBox{\lst@stringstyle}\else %
+        \lst@ifcomment\lst@MakeBox{\lst@commentstyle}\else %
+%    \end{macrocode}
+% If we output neither a string nor a comment, we look for a keyword.
+% The output takes place in the macro \verb!\lst@KeywordsOrNot!
+% (see section \ref{sLanguageDriverFiles}). \cs{relax} terminates the
+% text parameter.
+%    \begin{macrocode}
+        \expandafter\lst@KeywordOrNot\lst@text\relax %
+        \fi \fi %
+%    \end{macrocode}
+% Finally we hold up the current column, empty the text and close the
+% starting 'if text not empty'.
+%    \begin{macrocode}
+        \global\advance\lst@pos by -\lst@length %
+        \let\lst@text\@empty \lst@length0 %
+    \fi}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lst@OutputOther}
+% To output the characters from the token register \verb!\lst@other!,
+% we assign these characters to a macro. The rest is the same as in
+% \verb!\lst@Output!, except that we need no keyword tests and make
+% a normal box instead.
+%    \begin{macrocode}
+\def\lst@OutputOther{%
+    \expandafter\def\expandafter\lst@text\expandafter{\the\lst@other}%
+    \ifx\lst@text\@empty\else %
+        \lst@ifstring \lst@MakeStringBox{\lst@stringstyle}\else %
+        \lst@ifcomment\lst@MakeBox{\lst@commentstyle}\else %
+            \lst@MakeBox{}%
+        \fi \fi %
+        \global\advance\lst@pos by -\lst@length %
+        \lst@other{}\let\lst@text\@empty \lst@length0 %
+    \fi}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lst@MakeBox}
+% Consider the different boxes now. A box must take \verb!\lst@length!
+% characters: the width is \verb!\lst@length!$\cdot$\verb!\lst@width!.
+% The macro parameter possibly selects another style. We insert dynamic
+% space at the beginning (and at the ending) to center the text and we
+% fill the box. Again \cs{relax} is a brake.
+%    \begin{macrocode}
+\def\lst@MakeBox#1{%
+    \hbox to \lst@length\lst@width{#1\hss %
+        \expandafter\lst@FillBox\lst@text\relax \hss}}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lst@FillBox}
+% Filling up a box is easy. If we found the end of the text, we do
+% nothing. Otherwise we output the character and insert dynamic space.
+% Since the underbar is not a printable character in \TeX{}, we have
+% to treat it special. By the way: We make the underbar having the
+% letter catcode here; we don't want subscripts. After all this is
+% done, we call the fillbox macro again.
+% Note: The macro is called after the closing \cs{fi}!
+%    \begin{macrocode}
+\begingroup
+\catcode`\_=11
+\gdef\lst@FillBox#1{%
+    \ifx\relax#1\else %
+        \ifx#1_\textunderscore \else #1\fi \hss %
+        \expandafter\lst@FillBox %
+    \fi}
+\endgroup
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lst@MakeSpecialStringBox}
+% A stringbox is nearly the same: We only let the 'normal blank' be
+% '\textvisiblespace'.
+%    \begin{macrocode}
+\def\lst@MakeSpecialStringBox#1{%
+    \hbox to\lst@length\lst@width{\let\lst@outputblank\textvisiblespace%
+        #1\hss \expandafter\lst@FillBox\lst@text\relax \hss}}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lst@OutputChar}
+% We define one more macro to save time. It outputs a single character.
+% The implementation should be clear.
+%    \begin{macrocode}
+\def\lst@OutputChar#1{\global\advance\lst@pos by -1%
+    \hbox to \lst@width{\hss %
+        \lst@ifstring \def\lst@text{#1}\lst@length\@ne %
+            \lst@MakeStringBox{\lst@stringstyle}%
+        \else \lst@ifcomment \lst@commentstyle#1\hss %
+        \else #1\hss %
+        \fi \fi}}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lst@GotoNextTabStop}
+% At the end of this section we consider tabulators. As seen, each
+% typeset character decrements the counter \verb!\lst@pos!. To go to
+% the next tabulator stop, we must first determine how many blanks are
+% needed. We simply add \verb!\lst@tablength! until \verb!\lst@pos!
+% is strict positive.
+%    \begin{macrocode}
+\def\lst@GotoNextTabStop{%
+    \@whilenum \lst@pos<1 \do %
+        {\global\advance\lst@pos\lst@tablength}%
+%    \end{macrocode}
+% Now we make a box having the width of \verb!\lst@pos! characters and
+% set \verb!\lst@pos! to zero.
+%    \begin{macrocode}
+    \hbox to \lst@pos\lst@width{\hss}\lst@pos0}%
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Special characters}\label{ssSpecialCharacters}
+% Some definitions of special characters:
+%    \begin{macrocode}
+\def\lst@leftbrace{$\{$}
+\def\lst@rightbrace{$\}$}
+\def\lst@less{$<$}
+\def\lst@greater{$>$}
+\def\lst@verticalbar{$|$}
+\def\lst@minus{$-$}
+\def\lst@multiply{$*$}
+%    \end{macrocode}
+%
+% \begin{macro}{\lst@MakeDigitsLetter}
+% This macro is similar to \cs{makeatletter}.
+%    \begin{macrocode}
+\def\lst@MakeDigitsLetter{\catcode`\0=11\catcode`\1=11%
+    \catcode`\2=11\catcode`\3=11\catcode`\4=11\catcode`\5=11%
+    \catcode`\6=11\catcode`\7=11\catcode`\8=11\catcode`\9=11}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lst@DefineCatcodes}
+% At the moment only the catcode of $-$ is language specific.
+% This macro stores such values.
+%    \begin{macrocode}
+\def\lst@DefineCatcodes#1{%
+    \def\lst@ChangeMoreCatcodes{\catcode`\-=#1}}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lst@ChangeCatcodes}
+% Now begins the horrible part: It is necessary to change many
+% catcodes. Since we need backslash and braces with other meanings,
+% we replace them by the slash $/$, $($ and $)$. Other characters like
+% \$ and \& need not to be replaced, because we don't need them for
+% defining macros, but $\backslash$, $\{$ and $\}$ are essential for
+% doing that.
+%    \begin{macrocode}
+\begingroup
+\catcode `/=0       \catcode `(= 1      \catcode `)=2 % new \, { and }
+\catcode`\<=\active \catcode`\>=\active \catcode`\|=\active
+\catcode`\-=\active \catcode`\*=\active
+\catcode`\{=\active \catcode`\}=\active \catcode`\\=\active
+%    \end{macrocode}
+% From now on we must use the slash and $()$ instead of backslash and
+% braces. Since the blank space will also be an active character, we
+% must terminate each line with a comment character. Otherwise \TeX{}
+% would think, we want to typeset something before beginning the
+% document.
+% \SpecialEscapechar/
+%    \begin{macrocode}
+/gdef/lst@inputbackslash(\)%
+/catcode`/ =/active%
+/gdef/lst@inputblank( )%
+/gdef/lst@outputblank(/ )%
+%    \end{macrocode}
+% The following macro changes catcodes and the definition of active
+% characters at the time we input a listing.
+% \SpecialEscapechar/
+%    \begin{macrocode}
+/gdef/lst@ChangeCatcodes(%
+/catcode`/ =/active/def (/lst@outputblank)%
+/catcode`/\=/active/def\($/backslash$)%
+/catcode`/{=/active/def{(/lst@leftbrace)%
+/catcode`/}=/active/def}(/lst@rightbrace)%
+/catcode`/<=/active/def<(/lst@less)%
+/catcode`/>=/active/def>(/lst@greater)%
+/catcode`/|=/active/def|(/lst@verticalbar)%
+/catcode`/-=/active/def-(/lst@minus)%
+/catcode`/*=/active/def*(/lst@multiply)%
+/chardef~="7E%
+%    \end{macrocode}
+% A tabulator (ASCII code 9=ord(I)$-$64) gets the catcode of a
+% \TeX{}-tabulator.
+% \SpecialEscapechar/
+%    \begin{macrocode}
+/catcode`/^^I=4%
+%    \end{macrocode}
+% Some characters are treated as other characters (12) or as letters
+% (11).
+% \SpecialEscapechar/
+%    \begin{macrocode}
+/catcode`/$=11/catcode`/_=11/lst@MakeDigitsLetter%
+/catcode`/&=12/catcode`/^=12/catcode`/"=12/catcode`/#=12%
+/chardef/lst@ccPercent=/catcode`/%/catcode`/%=12% save catcode
+/lst@ChangeMoreCatcodes/makeatletter)%
+/endgroup
+%    \end{macrocode}
+% All changed catcodes (time of definition) are restored by ending the
+% group.
+% \end{macro}
+%
+%
+% \subsection{Initialization}\label{ssInitialization}
+% Defaults are selected and the options are processed.
+%    \begin{macrocode}
+\normallisting
+\listingtrue
+\tablength{4}
+\lstlineskip{0pt}
+\selectlisting{blank}
+\ProcessOptions
+%</package>
+%    \end{macrocode}
+%
+%
+% \section{Language driver files}\label{sLanguageDriverFiles}
+% Each driver file contains language specific data:
+% \begin{itemize}
+% \item keywords,
+% \item whether the language is case sensitive or not,
+% \item information about comment lines and other comments,
+% \item the stringizer,
+% \item baseem --- the width of a single character box,
+% \item the catcode of the minus $-$,
+% \item \verb!\lst@PrePL! and \verb!\lst@PostPL! are executed before and
+%	after the real line processing takes place: \verb!\lst@PrePL! is
+%	intend to manipulate the input, e.g.\ Fortran uses it to detect
+%	comment lines beginning with '$*$' or 'C' and Eiffel's string
+%	concatenate mechanism is done there, and e.g.\ \verb!\lst@PostPL!
+%	might gives a warning, if a string exceeds a line.
+% \end{itemize}
+% The package selects a language by calling \verb!\lstdrv@#1@!, where
+% \verb!#1! is replaced by the language. Additionally the language option
+% (empty or not) is used as suffix, e.g.\ \verb!\lstdrv@cobol@1974!.
+% That macro must support the described things.
+%
+% Some driver files use own data. To setup things like that the macro
+% \verb!\lstdrv@#1@PrepareListing! is called \emph{after} all init
+% of the kernel is done (changing catcodes, e.g.). Here \verb!#1!
+% is replaced by the language again. If no special setup is needed,
+% a driver file need not to define that macro.
+%
+% The implemented languages follow as examples.
+% '\texttt{???}' in driver files indicate things I don't know.
+%
+%
+% \subsection{Blank listing}
+% \begin{macro}{\lstdrv@blank@}
+% For a blank listing we let all empty. \cs{makeatletter} lets \verb!@!
+% be a letter here. Otherwise we can't access \verb!\lstdrv@blank@!.
+%    \begin{macrocode}
+%<*blank>
+\begingroup \makeatletter %
+\gdef\lstdrv@blank@{%
+    \keywords{}%
+    \sensitivetrue %
+    \DeclareCommentLine\relax %
+    \DeclareSingleComment stuff \relax %
+    \stringizer{}\lstbaseem{0.6}%
+    \lst@DefineCatcodes{\active}%
+    \let\lst@PrePL \lst@PrePLDefault %
+    \let\lst@PostPL\lst@PostPLDefault}%
+\endgroup %
+%</blank>
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Ada}
+% \begin{macro}{\lstdrv@ada@}
+% Keywords, comments, \ldots{}
+% The catcode of the double quote is changed for compatibility with
+% \texttt{german.sty}.
+%    \begin{macrocode}
+%<*ada>
+\begingroup \makeatletter %
+\catcode`\"=12 \catcode`\-=\active %
+\gdef\lstdrv@ada@{%
+    \keywords{abort,abs,accept,access,all,and,array,at,begin,body,%
+        case,constant,declare,delay,delta,digits,do,else,elsif,end,%
+        entry,exception,exit,for,function,generic,goto,if,in,is,%
+        limited,loop,mod,new,not,null,of,or,others,out,package,pragma,%
+        private,procedure,raise,range,record,rem,renames,return,%
+        reverse,select,separate,subtype,task,terminate,then,type,%
+        use,when,while,with,xor}%
+    \sensitivefalse %
+    \DeclareCommentLine --\relax %
+    \DeclareSingleComment stuff \relax %
+    \stringizer[d]{"'}\lstbaseem{0.6}% ??? stringizer doubled
+    \lst@DefineCatcodes{\active}%
+    \let\lst@PrePL \lst@PrePLDefault %
+    \let\lst@PostPL\lst@PostPLDefault}%
+\endgroup %
+%</ada>
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Algol}
+% \begin{macro}{\lstdrv@algol@}
+% The main driver macro.
+%    \begin{macrocode}
+%<*algol>
+\begingroup \makeatletter %
+\catcode`\#=12 %
+\gdef\lstdrv@algol@{% ??? should 'i' be a keyword
+    \keywords{abs,and,arg,begin,bin,bits,bool,by,bytes,case,channel,%
+        char,co,comment,compl,conj,divab,do,down,elem,elif,else,empty,%
+        end,entier,eq,esac,exit,false,fi,file,flex,for,format,from,%
+        ge,goto,gt,heap,if,im,in,int,is,isnt,le,leng,level,loc,long,%
+        lt,lwb,minusab,mod,modab,mode,ne,nil,not,od,odd,of,op,or,ouse,%
+        out,over,overab,par,plusab,plusto,pr,pragmat,prio,proc,re,real,%
+        ref,repr,round,sema,shl,short,shorten,shr,sign,skip,string,%
+        structthen,timesab,to,true,union,up,upb,void,while}%
+    \sensitivefalse % ???
+    \DeclareCommentLine\relax %
+    \DeclarePairedComment #\relax %
+    \stringizer{}\lstbaseem{0.6}%
+    \lst@DefineCatcodes{\active}%
+    \let\lst@PrePL \lst@PrePLDefault %
+    \let\lst@PostPL\lst@PostPLDefault}%
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lstdrv@algol@68}
+% \begin{macro}{\lstdrv@algol@60}
+% Macros for the optional argument:
+%    \begin{macrocode}
+\global\@namedef{lstdrv@algol@68}{\lstdrv@algol@}%
+\global\@namedef{lstdrv@algol@60}{\lstdrv@algol@ %
+    \keywords{array,begin,Boolean,code,comment,div,do,else,end,false,%
+        for,goto,if,integer,label,own,power,procedure,real,step,string,%
+        switch,then,true,until,value,while}%
+    \DeclareSingleComment stuff \relax}%
+\endgroup %
+%    \end{macrocode}
+% \end{macro}\end{macro}
+%
+% \begin{macro}{\lstdrv@algol@PrepareListing}
+% To implement comments beginning with \verb!comment! or \verb!co!
+% we must go deep inside this package again. We need an additional
+% 'ifcomment' and define Algol's Prepare\-Listing to override the
+% default output macros.
+%    \begin{macrocode}
+\begingroup \makeatletter %
+\gdef\lstdrv@algol@commenttrue{%
+    \global\let\lstdrv@algol@ifcomment\iftrue}%
+\gdef\lstdrv@algol@commentfalse{%
+    \global\let\lstdrv@algol@ifcomment\iffalse %
+    \global\let\lstdrv@algol@closingcomment\@empty}%
+\gdef\lstdrv@algol@PrepareListing{%
+    \lstdrv@algol@commentfalse %
+    \let\lst@OutputOther\lstdrv@algol@OutputOther %
+    \lst@ifoption{60}{\let\lst@Output\lstdrv@algol@Output@ %
+                      \let\lst@AppendOther\lstdrv@algol@AppendOther}%
+                     {\let\lst@Output\lstdrv@algol@Output}}%
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lstdrv@algol@OutputOther}
+% This macro is a simple derivation of \verb!\lst@OutputOther!. The only
+% difference is that we test Algol's additional 'ifcomment' (4th line).
+%    \begin{macrocode}
+\gdef\lstdrv@algol@OutputOther{%
+    \expandafter\def\expandafter\lst@text\expandafter{\the\lst@other}%
+    \ifx\lst@text\@empty\else %
+        \lstdrv@algol@ifcomment\lst@MakeBox{\lst@commentstyle}\else %
+        \lst@ifstring \lst@MakeStringBox{\lst@stringstyle}\else %
+        \lst@ifcomment\lst@MakeBox{\lst@commentstyle}\else %
+            \lst@MakeBox{}%
+        \fi \fi \fi %
+        \global\advance\lst@pos by -\lst@length %
+        \lst@other{}\let\lst@text\@empty \lst@length0 %
+    \fi}%
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lstdrv@algol@Output}
+% Here we also install an additional 'ifcomment'. If we are in comment
+% mode, we look whether the comment is over or not.
+%    \begin{macrocode}
+\gdef\lstdrv@algol@Output{%
+    \ifx\lst@text\@empty\else %
+        \lstdrv@algol@ifcomment %
+            \ifx\lst@text\lstdrv@algol@closingcomment %
+                \lstdrv@algol@commentfalse %
+                \lst@MakeBox{\lst@keywordstyle}%
+            \else \lst@MakeBox{\lst@commentstyle}%
+            \fi \else %
+%    \end{macrocode}
+% The next three lines are unchanged.
+%    \begin{macrocode}
+        \lst@ifstring \lst@MakeStringBox{\lst@stringstyle}\else %
+        \lst@ifcomment\lst@MakeBox{\lst@commentstyle}\else %
+        \expandafter\lst@KeywordOrNot\lst@text\relax %
+%    \end{macrocode}
+% After the keyword (or non-keyword) is output, we look if a comment
+% starts: If the current text equals \verb!co! or \verb!comment!, we
+% enter comment mode and set the closing comment delimiter.
+%    \begin{macrocode}
+        \expandafter\lst@ifoneof\lst@text\relax{comment,co}%
+            {\global\let\lstdrv@algol@closingcomment\lst@text}{}%
+%    \end{macrocode}
+% The rest is unchanged.
+%    \begin{macrocode}
+        \fi \fi \fi %
+        \global\advance\lst@pos by -\lst@length %
+        \let\lst@text\@empty \lst@length0 %
+    \fi}%
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lstdrv@algol@Output@}
+% Now we come to Algol 60. First comes the same as above. But:
+% An empty 'closingcomment' indicates that no \verb!end! and no
+% \verb!else! closes a comment, i.e.\ we look first whether 'end
+% of comment' tests are legal or not.
+%    \begin{macrocode}
+\gdef\lstdrv@algol@Output@{%
+    \ifx\lst@text\@empty\else %
+        \lstdrv@algol@ifcomment %
+            \ifx\@empty\lstdrv@algol@closingcomment %
+                \lst@MakeBox{\lst@commentstyle}%
+            \else %
+                \expandafter\lst@ifoneof\lst@text\relax{else,end}%
+                    {\lstdrv@algol@commentfalse %
+                     \lst@MakeBox{\lst@keywordstyle}}%
+                    {\lst@MakeBox{\lst@commentstyle}}%
+            \fi \else %
+%    \end{macrocode}
+% The next three lines are unchanged.
+%    \begin{macrocode}
+        \lst@ifstring \lst@MakeStringBox{\lst@stringstyle}\else %
+        \lst@ifcomment\lst@MakeBox{\lst@commentstyle}\else %
+        \expandafter\lst@KeywordOrNot\lst@text\relax %
+%    \end{macrocode}
+% After the keyword (or non-keyword) is output, we look if a comment
+% starts: If the current text equals \verb!comment!, we enter the
+% comment mode and let \verb!\lstdrv@algol@closingcomment! empty;
+% if the text equals \verb!end!, we let 'closingcomment' not empty,
+% i.e.\ the comment may closes with \verb!else! or \verb!end!
+% (see above).
+%    \begin{macrocode}
+        \expandafter\lst@ifoneof\lst@text\relax{comment,end}%
+            {\lstdrv@simula@commenttrue %
+             \expandafter\lst@ifoneof\lst@text\relax{end}%
+                 {\gdef\lstdrv@simula@closingcomment{a}}{}}%
+            {}% empty else from 'ifoneof'
+%    \end{macrocode}
+% The rest is unchanged.
+%    \begin{macrocode}
+        \fi \fi \fi %
+        \global\advance\lst@pos by -\lst@length %
+        \let\lst@text\@empty \lst@length0 %
+    \fi}%
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lstdrv@algol@AppendOther@}
+% A semicolon also ends a comment. Hence:
+%    \begin{macrocode}
+\gdef\lstdrv@algol@AppendOther#1{%
+    \lstdrv@algol@ifcomment \if;#1%
+        \lst@OutputOther \lstdrv@algol@commentfalse %
+    \fi \fi %
+    \advance\lst@length\@ne %
+    \expandafter\lst@other\expandafter{\the\lst@other#1}}%
+\endgroup %
+%</algol>
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{C}
+% \begin{macro}{\lstdrv@c@}
+% Since $*$ will be an active character when we input a listing, we
+% have to change the catcode here.
+%    \begin{macrocode}
+%<*c>
+\begingroup \makeatletter %
+\catcode`\"=12 \catcode`\*=\active %
+\gdef\lstdrv@c@{%
+    \keywords{auto,break,case,char,const,continue,default,do,double,%
+        else,enum,extern,float,for,goto,if,int,long,register,return,%
+        short,signed,sizeof,static,struct,switch,typedef,union,%
+        unsigned,void,volatile,while}%
+    \sensitivetrue %
+    \DeclareCommentLine\relax %
+    \DeclareSingleComment /* */\relax %
+    \stringizer[b]{"}\lstbaseem{0.6}%
+    \lst@DefineCatcodes{\active}%
+    \let\lst@PrePL \lstdrv@c@PrePL %
+    \let\lst@PostPL\lst@PostPLDefault}%
+\endgroup %
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lstdrv@c@PrePL}
+% \begin{macro}{\lstdrv@c@directives}
+% We only test for C compiler directives.
+%    \begin{macrocode}
+\begingroup \makeatletter %
+\gdef\lstdrv@c@PrePL{%
+    \expandafter\lstdrv@c@TestSharp\lst@line\relax\relax}%
+\gdef\lstdrv@c@directives{,define,elif,else,endif,error,if,ifdef,%
+    ifndef,line,include,pragma,undef}%
+%    \end{macrocode}
+% \end{macro}\end{macro}
+%
+% \begin{macro}{\lstdrv@c@TestSharp}
+% To implement C (and C++) directives the catcode of $\#$ must be
+% changed from 'parameter symbol for macros' to 'letter'.
+%    \begin{macrocode}
+\catcode`\&=6 \catcode`\#=12 %
+\gdef\lstdrv@c@TestSharp&1&2\relax{%
+    \if#&1\def\lst@line{&2}%
+%    \end{macrocode}
+% If the first character of a line is a sharp, we first output that
+% sharp using the keywordstyle. All compiler directives become the
+% current keywords and we output the line, which gets empty afterwards.
+%    \begin{macrocode}
+        {\lst@keywordstyle\lst@OutputChar#}%
+        {\let\lst@keywords\lstdrv@c@directives \lst@ProcessLine}%
+        \let\lst@line\@empty %
+    \fi}%
+\endgroup %
+%</c>
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{C++}
+% \begin{macro}{\lstdrv@cpp@}
+% Since C++ is an extension of C (from the point of view here), we load
+% the C driver file and use the definition there.
+%    \begin{macrocode}
+%<*cpp>
+\selectlisting{c}%
+\begingroup \makeatletter %
+\catcode`\_=11 %
+\gdef\lstdrv@cpp@{\lstdrv@c@ %
+    \morekeywords{asm,bad_cast,bad_typeid,bool,catch,class,const_cast,%
+        delete,dynamic_cast,false,friend,inline,namespace,new,operator,%
+        private,protected,public,reinterpret_cast,static_cast,template,%
+        this,throw,true,try,type_info,typeid,using,virtual,xalloc,%
+        __multiple_inheritance,__single_inheritance,%
+        __virtual_inheritance}%
+    \DeclareCommentLine //\relax}%
+\global\let\lstdrv@cpp@ansi \lstdrv@cpp %
+\gdef\lstdrv@cpp@vc{\lstdrv@cpp %
+    \morekeywords{__asm,__based,__cdecl,__declspec,dllexport,dllimport,%
+        __except,__fastcall,__finally,__inline,__int8,__int16,__int32,%
+        __int64,naked,__stdcall,thread,__try,__leave}}%
+\endgroup %
+%</cpp>
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Cobol}
+% \begin{macro}{\lstdrv@cobol@keys}
+% \begin{macro}{\lstdrv@cobol@keys@eightyfive}
+% \begin{macro}{\lstdrv@cobol@keys@ibm}
+% The keywords first:
+%    \begin{macrocode}
+%<*cobol>
+\begingroup \makeatletter %
+\catcode`\-=11 \lst@MakeDigitsLetter %
+\gdef\lstdrv@cobol@keys{ACCEPT,ACCESS,ADD,ADVANCING,AFTER,ALL,%
+    ALPHABETIC,ALSO,ALTER,ALTERNATE,AND,ARE,AREA,AREAS,ASCENDING,%
+    ASSIGN,AT,AUTHOR,BEFORE,BINARY,BLANK,BLOCK,BOTTOM,BY,CALL,CANCEL,%
+    CD,CF,CH,CHARACTER,CHARACTERS,CLOCK-UNITS,CLOSE,COBOL,CODE,%
+    CODE-SET,COLLATING,COLUMN,COMMA,COMMUNICATION,COMP,COMPUTE,%
+    CONFIGURATION,CONTAINS,CONTROL,CONTROLS,CONVERTING,COPY,CORR,%
+    CORRESPONDING,COUNT,CURRENCY,DATA,DATE,DATE-COMPILED,DATE-WRITTEN,%
+    DAY,DE,DEBUG-CONTENTS,DEGUB-ITEM,DEBUG-LINE,DEBUG-NAME,DEBUG-SUB1,%
+    DEBUG-SUB2,DEBUG-SUB3,DEBUGGING,DECIMAL-POINT,DECLARATIVES,DELETE,%
+    DELIMITED,DELIMITER,DEPENDING,DESCENDING,DESTINATION,DETAIL,%
+    DISABLE,DISPLAY,DIVIDE,DIVISION,DOWN,DUPLICATES,DYNAMIC,EGI,ELSE,%
+    EMI,ENABLE,END,END-OF-PAGE,ENTER,ENVIRONMENT,EOP,EQUAL,ERROR,ESI,%
+    EVERY,EXCEPTION,EXIT,EXTEND,FD,FILE,FILE-CONTROL,FILLER,FINAL,%
+    FIRST,FOOTING,FOR,FROM,GENERATE,GIVING,GO,GREATER,GROUP,HEADING,%
+    HIGH-VALUE,HIGH-VALUES,I-O,I-O-CONTROL,IDENTIFICATION,IF,IN,INDEX,%
+    INDEXED,INDICATE,INITIAL,INITIATE,INPUT,INPUT-OUTPUT,INSPECT,%
+    INSTALLATION,INTO,INVALID,IS,JUST,JUSTIFIED,KEY,LABEL,LAST,LEADING,%
+    LEFT,LENGTH,LESS,LIMIT,LIMITS,LINAGE,LINAGE-COUNTER,LINE,%
+    LINE-COUNTER,LINES,LINKAGE,LOCK,LOW-VALUE,LOW-VALUES,MEMORY,MERGE,%
+    MESSAGE,MODE,MODULES,MOVE,MULTIPLE,MULTIPLY,NATIVE,NEGATIVE,NEXT,%
+    NO,NOT,NUMBER,NUMERIC,OBJECT-COMPUTER,OCCURS,OF,OFF,OMITTED,ON,%
+    OPEN,OPTIONAL,OR,ORGANIZATION,OUTPUT,OVERFLOW,PAGE,PAGE-COUNTER,%
+    PERFORM,PF,PH,PIC,PICTURE,PLUS,POINTER,POSITION,PRINTING,POSITIVE,%
+    PRINTING,PROCEDURE,PROCEDURES,PROCEED,PROGRAM,PROGRAM-ID,QUEUE,%
+    QUOTE,QUOTES,RANDOM,RD,READ,RECEIVE,RECORD,RECORDING,RECORDS,%
+    REDEFINES,REEL,REFERENCES,RELATIVE,RELEASE,REMAINDER,REMOVAL,%
+    RENAMES,REPLACING,REPORT,REPORTING,REPORTS,RERUN,RESERVE,RESET,%
+    RETURN,REVERSED,REWIND,REWRITE,RF,RH,RIGHT,ROUNDED,RUN,SAME,SD,%
+    SEARCH,SECTION,SECURITY,SEGMENT,SEGMENT-LIMIT,SELECT,SEND,SENTENCE,%
+    SEPARATE,SEQUENCE,SEQUENTIAL,SET,SIGN,SIZE,SORT,SORT-MERGE,SOURCE,%
+    SOURCE-COMPUTER,SPACE,SPACES,SPECIAL-NAMES,STANDARD,START,STATUS,%
+    STOP,STRING,SUB-QUEUE-1,SUB-QUEUE-2,SUB-QUEUE-3,SUBTRACT,SUM,%
+    SYMBOLIC,SYNC,SYNCHRONIZED,TABLE,TALLYING,TAPE,TERMINAL,TERMINATE,%
+    TEXT,THAN,THROUGH,THRU,TIME,TIMES,TO,TOP,TRAILING,TYPE,UNIT,%
+    UNSTRING,UNTIL,UP,UPON,USAGE,USE,USING,VALUE,VALUES,VARYING,WHEN,%
+    WITH,WORDS,WORKING-STORAGE,WRITE,ZERO,ZEROES,ZEROS}%
+\gdef\lstdrv@cobol@keys@eightyfive{ALPHABET,ALPHABETIC-LOWER,%
+    ALPHABETIC-UPPER,ALPHANUMERIC,ALPHANUMERIC-EDITED,ANY,CLASS,COMMON,%
+    CONTENT,CONTINUE,DAY-OF-WEEK,END-ADD,END-CALL,END-COMPUTE,%
+    END-DELETE,END-DIVIDE,END-EVALUATE,END-IF,END-MULTIPLY,END-PERFORM,%
+    END-READ,END-RECEIVE,END-RETURN,END-REWRITE,END-SEARCH,END-START,%
+    END-STRING,END-SUBTRACT,END-UNSTRING,END-WRITE,EVALUATE,EXTERNAL,%
+    FALSE,GLOBAL,INITIALIZE,NUMERIC-EDITED,ORDER,OTHER,PACKED-DECIMAL,%
+    PADDING,PURGE,REFERENCE,RELOAD,REPLACE,STANDARD-1,STANDARD-2,TEST,%
+    THEN,TRUE}%
+\gdef\lstdrv@cobol@keys@ibm{ADDRESS,BEGINNING,COMP-3,COMP-4,%
+    COMPUTATIONAL,COMPUTATIONAL-3,COMPUTATIONAL-4,DISPLAY-1,EGCS,EJECT,%
+    ENDING,ENTRY,GOBACK,ID,MORE-LABELS,NULL,NULLS,PASSWORD,RECORDING,%
+    RETURN-CODE,SERVICE,SKIP1,SKIP2,SKIP3,SORT-CONTROL,SORT-RETURN,%
+    SUPPRESS,TITLE,WHEN-COMPILED}%
+\endgroup %
+%    \end{macrocode}
+% \end{macro}\end{macro}\end{macro}
+%
+% \begin{macro}{\lstdrv@cobol@}
+% Now the main driver macro:
+%    \begin{macrocode}
+\begingroup \makeatletter %
+\catcode`\"=12%
+\gdef\lstdrv@cobol@{%
+    \keywords{\lstdrv@cobol@keys,\lstdrv@cobol@keys@eightyfive}%
+    \sensitivefalse % ???
+    \DeclareCommentLine\relax %
+    \DeclareSingleComment stuff \relax %
+    \stringizer[d]{"}\lstbaseem{0.65}%
+    \lst@DefineCatcodes{11}%
+    \let\lst@PrePL\lstdrv@cobol@PrePL %
+    \let\lst@PostPL\relax}%
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lstdrv@cobol@1985}
+% \begin{macro}{\lstdrv@cobol@1974}
+% \begin{macro}{\lstdrv@cobol@ibm}
+% And macros for the optional argument:
+%    \begin{macrocode}
+\global\@namedef{lstdrv@cobol@1985}{\lstdrv@cobol@}%
+\global\@namedef{lstdrv@cobol@1974}{\lstdrv@cobol@ %
+    \keywords{\lstdrv@cobol@keys}}%
+\gdef\lstdrv@cobol@ibm{\lstdrv@cobol@ %
+    \morekeywords{\lstdrv@cobol@keys@ibm}}%
+\endgroup %
+%    \end{macrocode}
+% \end{macro}\end{macro}\end{macro}
+%
+% \begin{macro}{\lstdrv@cobol@PrePL}
+% \begin{macro}{\lstdrv@cobol@TestComment}
+% Comments are handled with the \verb!\lst@PrePL! mechanism. We simply
+% look, if the seventh character is an asterix (and output the comment
+% if necessary).
+%    \begin{macrocode}
+\begingroup \makeatletter %
+\gdef\lstdrv@cobol@PrePL{\expandafter\lstdrv@cobol@TestComment %
+    \lst@line\relax\relax\relax\relax\relax\relax\relax\relax}%
+\catcode`\*=\active %
+\gdef\lstdrv@cobol@TestComment#1#2#3#4#5#6#7#8\relax{%
+    \ifx #7*%
+        \lst@commenttrue \expandafter\lst@Tokenize\lst@line\relax %
+        \let\lst@line\@empty \lst@commentfalse %
+    \fi}%
+\endgroup %
+%</cobol>
+%    \end{macrocode}
+% \end{macro}\end{macro}
+%
+%
+% \subsection{Comal 80}
+% \begin{macro}{\lstdrv@comal@}
+% Only the lonely driver macro.
+%    \begin{macrocode}
+%<*comal>
+\begingroup \makeatletter %
+\catcode`\"=12 %
+\gdef\lstdrv@comal@{%
+    \keywords{AND,AUTO,CASE,DATA,DEL,DIM,DIV,DO,ELSE,ENDCASE,ENDIF,%
+        ENDPROC,ENDWHILE,EOD,EXEC,FALSE,FOR,GOTO,IF,INPUT,INT,LIST,%
+        LOAD,MOD,NEW,NEXT,NOT,OF,OR,PRINT,PROC,RANDOM,RENUM,REPEAT,%
+        RND,RUN,SAVE,SELECT,STOP,TAB,THEN,TRUE,UNTIL,WHILE,ZONE}%
+    \sensitivefalse % ???
+    \DeclareCommentLine //\relax %
+    \DeclareSingleComment stuff \relax %
+    \stringizer{"}\lstbaseem{0.65}%
+    \lst@DefineCatcodes{\active}%
+    \let\lst@PrePL \lst@PrePLDefault %
+    \let\lst@PostPL\lst@PostPLDefault}%
+\endgroup %
+%</comal>
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Eiffel}
+% \begin{macro}{\lstdrv@eiffel@}
+% The same procedure \ldots
+%    \begin{macrocode}
+%<*eiffel>
+\begingroup \makeatletter %
+\catcode`\"=12 \catcode`\-=\active %
+\gdef\lstdrv@eiffel@{%
+    \keywords{alias,all,and,as,BIT,BOOLEAN,CHARACTER,check,class,%
+        creation,Current,debug,deferred,do,DOUBLE,else,elseif,end,%
+        ensure,expanded,export,external,false,feature,from,frozen,if,%
+        implies,indexing,infix,inherit,inspect,INTEGER,invariant,is,%
+        like,local,loop,NONE,not,obsolete,old,once,or,POINTER,prefix,%
+        REAL,redefine,rename,require,rescue,Result,retry,select,%
+        separate,STRING,strip,then,true,undefine,unique,until,variant,%
+        when,xor}%
+    \sensitivetrue %
+    \DeclareCommentLine --\relax %
+    \DeclareSingleComment stuff \relax %
+    \stringizer{"}\lstbaseem{0.6}%
+    \lst@DefineCatcodes{\active}%
+    \let\lst@PrePL \lstdrv@eiffel@PrePL %
+    \let\lst@PostPL\relax}%
+\endgroup %
+%    \end{macrocode}
+% \end{macro}
+%
+% Not the same procedure: Since '$\%$' continues a string, we need a
+% different comment character and let the percent be other (catcode)
+% to look for it.
+%    \begin{macrocode}
+\begingroup \makeatletter %
+\catcode`\&=14 \catcode`\%=12 &
+%    \end{macrocode}
+% \begin{macro}{\lstdrv@eiffel@PrePL}
+% \begin{macro}{\lstdrv@eiffel@TestPercent}
+% If a string started on a preceding line, we test for the percent.
+% Refer how we cut a line into a comment and other source code.
+%    \begin{macrocode}
+\gdef\lstdrv@eiffel@PrePL{&
+  \lst@ifstring &
+      \expandafter\lstdrv@eiffel@TestPercent\lst@line%\relax &
+  \fi}&
+\gdef\lstdrv@eiffel@TestPercent#1%#2\relax{&
+    \ifx\@empty#2\@empty \lst@PostPLDefault &
+        \else \expandafter\lstdrv@eiffel@CutPercent\lst@line\relax&
+    \fi}&
+%    \end{macrocode}
+% \end{macro}\end{macro}
+%
+% \begin{macro}{\lstdrv@eiffel@CutPercent}
+% To output the characters in front of the percent we temporary switch
+% the string boolean. Atferwards we redefine the input line, so that
+% the normal line processing continues the string.
+%    \begin{macrocode}
+\gdef\lstdrv@eiffel@CutPercent#1%#2\relax{&
+    \lst@stringfalse \lst@Tokenize#1\relax &
+    \lst@stringtrue \def\lst@line{%#2}}&
+\endgroup %
+%</eiffel>
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Elan}
+% \begin{macro}{\lstdrv@elan@keys}
+% Since we need digits as letters, the keywords first:
+%    \begin{macrocode}
+%<*elan>
+\begingroup \makeatletter %
+\lst@MakeDigitsLetter %
+\gdef\lstdrv@elan@keys{ABS,AND,BOOL,CAND,CASE,CAT,COLUMNS,CONCR,CONJ,%
+    CONST,COR,DECR,DEFINES,DET,DIV,DOWNTO,ELIF,ELSE,END,ENDIF,ENDOP,%
+    ENDPACKET,ENDPROC,ENDREP,ENDSELECT,FALSE,FI,FILE,FOR,FROM,IF,INCR,%
+    INT,INV,LEAVE,LENGTH,LET,MOD,NOT,OF,OP,OR,OTHERWISE,PACKET,PROC,%
+    REAL,REP,REPEAT,ROW,ROWS,SELECT,SIGN,STRUCT,SUB,TEXT,THEN,TRANSP,%
+    TRUE,TYPE,UNTIL,UPTO,VAR,WHILE,WITH,XOR,%
+    maxint,sign,abs,min,max,random,initializerandom,subtext,code,%
+    replace,text,laenge,pos,compress,change,maxreal,smallreal,floor,pi,%
+    e,ln,log2,log10,sqrt,exp,tan,tand,sin,sind,cos,cosd,arctan,arctand,%
+    int,real,lastconversionok,put,putline,line,page,get,getline,input,%
+    output,sequentialfile,maxlinelaenge,reset,eof,close,complexzero,%
+    complexone,complexi,complex,realpart,imagpart,dphi,phi,vector,norm,%
+    replace,matrix,idn,row,column,sub,replacerow,replacecolumn,%
+    replaceelement,transp,errorsstop,stop}%
+\endgroup %
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lstdrv@elan@}
+% Now we define the main driver macro:
+%    \begin{macrocode}
+\begingroup \makeatletter %
+\catcode`\"=12 %
+\gdef\lstdrv@elan@{%
+    \keywords{\lstdrv@elan@keys}%
+    \sensitivetrue %
+    \DeclareCommentLine\relax %
+    \DeclareSingleComment stuff \relax %
+    \stringizer[d]{"}\lstbaseem{0.65}%
+    \lst@DefineCatcodes{\active}%
+    \let\lst@PrePL \lst@PrePLDefault %
+    \let\lst@PostPL\lst@PostPLDefault}%
+\endgroup %
+%</elan>
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Fortran}
+% \begin{macro}{\lstdrv@fortran@keys}
+% Common 'keywords' of Fortran 90 and Fortran 77:
+%    \begin{macrocode}
+%<*fortran>
+\begingroup \makeatletter %
+\gdef\lstdrv@fortan@keys{ACCESS,ASSIGN,BACKSPACE,BLANK,BLOCK,CALL,%
+    CHARACTER,CLOSE,COMMON,COMPLEX,CONTINUE,DATA,DIMENSION,DIRECT,DO,%
+    DOUBLE,ELSE,END,ENTRY,EOF,EQUIVALENCE,ERR,EXIST,EXTERNAL,FILE,%
+    FMT,FORM,FORMAT,FORMATTED,FUNCTION,GO,TO,IF,IMPLICIT,INQUIRE,%
+    INTEGER,INTRINSIC,IOSTAT,LOGICAL,NAMED,NEXTREC,NUMBER,OPEN,OPENED,%
+    PARAMETER,PAUSE,PRECISION,PRINT,PROGRAM,READ,REAL,REC,RECL,%
+    RETURN,REWIND,SEQUENTIAL,STATUS,STOP,SUBROUTINE,THEN,TYPE,%
+    UNFORMATTED,UNIT,WRITE}%
+\endgroup %
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lstdrv@fortran@}
+% The driver macro:
+%    \begin{macrocode}
+\begingroup \makeatletter %
+\catcode`\"=12 %
+\gdef\lstdrv@fortran@{%
+    \keywords{\lstdrv@fortan@keys,ACTION,ADVANCE,ALLOCATE,ALLOCATABLE,%
+        ASSIGNMENT,CASE,CONTAINS,CYCLE,DEALLOCATE,DEFAULT,DELIM,EXIT,%
+        IN,NONE,IN,OUT,INTENT,INTERFACE,IOLENGTH,KIND,LEN,MODULE,NAME,%
+        NAMELIST,NMT,NULLIFY,ONLY,OPERATOR,OPTIONAL,OUT,PAD,POINTER,%
+        POSITION,PRIVATE,PUBLIC,READWRITE,RECURSIVE,RESULT,SELECT,%
+        SEQUENCE,SIZE,STAT,TARGET,USE,WHERE,WHILE,%
+        BLOCKDATA,DOUBLEPRECISION,ELSEIF,ENDBLOCKDATA,ENDDO,ENDFILE,%
+        ENDFUNCTION,ENDIF,ENDINTERFACE,ENDMODULE,ENDPROGRAM,ENDSELECT,%
+        ENDSUBROUTINE,ENDTYPE,ENDWHERE,GOTO,INOUT,SELECTCASE}%
+    \sensitivefalse %% not Fortran standard %%
+    \DeclareCommentLine !\relax %
+    \DeclareSingleComment stuff \relax %
+    \stringizer{"}\lstbaseem{0.6}%
+    \lst@DefineCatcodes{\active}%
+    \let\lst@PrePL \lstdrv@fortran@PrePL %
+    \let\lst@PostPL\lst@PostPLDefault}%
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lstdrv@fortran@90}
+% \begin{macro}{\lstdrv@fortran@77}
+% Macros for the optional argument:
+%    \begin{macrocode}
+\global\@namedef{lstdrv@fortran@90}{\lstdrv@fortran@}%
+\global\@namedef{lstdrv@fortran@77}{\lstdrv@fortran@ %
+    \keywords{\lstdrv@fortan@keys,SAVE}%
+    \DeclareCommentLine\relax}%
+\endgroup %
+%    \end{macrocode}
+% \end{macro}\end{macro}
+%
+% \begin{macro}{\lstdrv@fortran@PrePL}
+% \begin{macro}{\lstdrv@fortran@TestComment}
+% Again something different: We use the \verb!\lst@PrePL! mechanism to
+% handle '$*$' and 'C' comments. The defined test macro tests, if the
+% first character of the input line is a star or an upper or lower case
+% c. We output the line as comment and empty the input,
+% if necessary. That's all.
+%    \begin{macrocode}
+\begingroup \makeatletter %
+\gdef\lstdrv@fortran@PrePL{%
+    \expandafter\lstdrv@fortran@TestComment\lst@line\relax}%
+\catcode`\*=\active %
+\gdef\lstdrv@fortran@TestComment#1#2\relax{\lst@commentfalse %
+    \ifx #1*\lst@commenttrue %
+    \else\if #1c\lst@commenttrue %% not Fortran standard %%
+    \else\if #1C\lst@commenttrue %
+    \fi \fi \fi %
+    \lst@ifcomment %
+        \expandafter\lst@Tokenize\lst@line\relax %
+        \let\lst@line\@empty \lst@commentfalse %
+    \fi}%
+\endgroup %
+%</fortran>
+%    \end{macrocode}
+% \end{macro}\end{macro}
+%
+%
+% \subsection{Java}
+% \begin{macro}{\lstdrv@java@}
+% Nothing new.
+%    \begin{macrocode}
+%<*java>
+\begingroup \makeatletter %
+\catcode`\"=12 \catcode`\*=\active %
+\gdef\lstdrv@java@{%
+    \keywords{abstract,boolean,break,byte,case,catch,char,class,const,%
+        continue,default,do,double,else,extends,final,finally,float,%
+        for,goto,if,implements,import,instanceof,int,interface,long,%
+        native,new,null,package,private,protected,public,return,short,%
+        static,super,switch,synchronized,this,throw,throws,transient,%
+        try,void,volatile,while,true,false}%
+    \sensitivetrue %
+    \DeclareCommentLine //\relax %
+    \DeclareSingleComment /* */\relax %
+    \stringizer{"}\lstbaseem{0.6}%
+    \lst@DefineCatcodes{\active}%
+    \let\lst@PrePL \lst@PrePLDefault %
+    \let\lst@PostPL\lst@PostPLDefault}%
+\endgroup %
+%</java>
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Lisp}
+% \begin{macro}{\lstdrv@lisp@}
+% The keywords are the 'one-word' functions and macros of Common Lisp,
+% i.e.\ words not containing a minus. And I left out the \texttt{caaaar},
+% \ldots{} functions.
+%    \begin{macrocode}
+%<*lisp>
+\begingroup \makeatletter %
+\catcode`\"=12 \catcode`\-=11 %
+\gdef\lstdrv@lisp@{%
+    \keywords{abort,abs,acons,acos,acosh,adjoin,alphanumericp,alter,%
+        append,apply,apropos,aref,arrayp,ash,asin,asinh,assoc,atan,%
+        atanh,atom,bit,boole,boundp,break,butlast,byte,catenate,%
+        ceiling,cerror,char,character,characterp,choose,chunk,cis,%
+        close,clrhash,coerce,collect,commonp,compile,complement,%
+        complex,complexp,concatenate,conjugate,cons,consp,constantp,%
+        continue,cos,cosh,cotruncate,count,delete,denominator,%
+        describe,directory,disassemble,documentation,dpb,dribble,%
+        ed,eighth,elt,enclose,endp,eq,eql,equal,equalp,error,eval,%
+        evalhook,evenp,every,exp,expand,export,expt,fboundp,fceiling,%
+        fdefinition,ffloor,fifth,fill,find,first,float,floatp,floor,%
+        fmakunbound,format,fourth,fround,ftruncate,funcall,functionp,%
+        gatherer,gcd,generator,gensym,gentemp,get,getf,gethash,%
+        identity,imagpart,import,inspect,integerp,intern,intersection,%
+        tively,isqrt,keywordp,last,latch,lcm,ldb,ldiff,length,list,%
+        listen,listp,load,log,logand,logbitp,logcount,logeqv,logior,%
+        lognand,lognor,lognot,logtest,logxor,macroexpand,makunbound,%
+        map,mapc,mapcan,mapcar,mapcon,maphash,mapl,maplist,mask,max,%
+        member,merge,min,mingle,minusp,mismatch,mod,namestring,%
+        nbutlast,nconc,nintersection,ninth,not,notany,notevery,%
+        nreconc,nreverse,nsublis,nsubst,nth,nthcdr,null,numberp,%
+        numerator,nunion,oddp,open,packagep,pairlis,pathname,pathnamep,%
+        phase,plusp,position,positions,pprint,previous,princ,print,%
+        proclaim,provide,random,rassoc,rational,rationalize,rationalp,%
+        read,readtablep,realp,realpart,reduce,rem,remhash,remove,%
+        remprop,replace,require,rest,revappend,reverse,room,round,%
+        rplaca,rplacd,sbit,scan,schar,search,second,series,set,seventh,%
+        shadow,signal,signum,sin,sinh,sixth,sleep,some,sort,split,%
+        sqrt,streamp,string,stringp,sublis,subseq,subseries,subsetp,%
+        subst,substitute,subtypep,svref,sxhash,symbolp,tailp,tan,tanh,%
+        tenth,terpri,third,truename,truncate,typep,unexport,unintern,%
+        union,until,values,vector,vectorp,warn,write,zerop,%
+        and,assert,case,ccase,cond,ctypecase,decf,declaim,defclass,%
+        defconstant,defgeneric,defmacro,defmethod,defpackage,%
+        defparameter,defsetf,defstruct,deftype,defun,defvar,do,dolist,%
+        dotimes,ecase,encapsulated,etypecase,flet,formatter,gathering,%
+        incf,iterate,labels,let,locally,loop,macrolet,mapping,or,pop,%
+        producing,prog,psetf,psetq,push,pushnew,remf,return,rotatef,%
+        setf,shiftf,step,time,trace,typecase,unless,untrace,when}%
+    \sensitivetrue % ???
+    \DeclareCommentLine;\relax %
+    \DeclareSingleComment stuff \relax %
+    \stringizer[b]{"}\lstbaseem{0.6}%
+    \lst@DefineCatcodes{11}%
+    \let\lst@PrePL \lst@PrePLDefault %
+    \let\lst@PostPL\lst@PostPLDefault}%
+\endgroup %
+%</lisp>
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Logo}
+% \begin{macro}{\lstdrv@logo@}
+% I don't know where I have the keywords from and what kind of Logo
+% it is. Help me!
+%    \begin{macrocode}
+%<*logo>
+\begingroup \makeatletter %
+\gdef\lstdrv@logo@{% ??? end,unix
+    \keywords{and,atan,arctan,both,break,bf,bl,butfirst,butlast,cbreak,%
+        close,co,continue,cos,count,clearscreen,cs,debquit,describe,%
+        diff,difference,ed,edit,either,emptyp,equalp,er,erase,errpause,%
+        errquit,fifp,filefprint,fifty,fileftype,fip,fileprint,fird,%
+        fileread,fity,filetype,fiwd,fileword,f,first,or,fp,fprint,fput,%
+        fty,ftype,full,fullscreen,go,bye,goodbye,gprop,greaterp,help,%
+        if,iff,iffalse,ift,iftrue,nth,item,keyp,llast,lessp,list,local,%
+        lput,make,max,maximum,memberp,memtrace,min,minimum,namep,not,%
+        numberp,oflush,openr,openread,openw,openwrite,op,output,pause,%
+        plist,pots,pow,pprop,pps,pr,print,product,quotient,random,rc,%
+        readchar,rl,readlist,remprop,repcount,repeat,request,rnd,run,%
+        se,sentence,sentencep,setc,setcolor,setipause,setqpause,po,%
+        show,sin,split,splitscreen,sqrt,stop,sum,test,text,textscreen,%
+        thing,to,tone,top,toplevel,type,untrace,wait,word,wordp,%
+        yaccdebug,is,mod,remainder,trace,zerop,%
+        back,bk,bto,btouch,fd,forward,fto,ftouch,getpen,heading,hit,%
+        hitoot,ht,hideturtle,loff,lampoff,lon,lampon,lt,left,lot,%
+        lotoot,lto,ltouch,penc,pencolor,pd,pendown,pe,penerase,penmode,%
+        pu,penup,px,penreverse,rt,right,rto,rtouch,scrunch,seth,%
+        setheading,setscrun,setscrunch,setxy,shownp,st,showturtle,%
+        towardsxy,clean,wipeclean,xcor,ycor,tur,turtle,display,dpy}%
+    \sensitivefalse % ???
+    \DeclareCommentLine\relax %
+    \DeclareSingleComment stuff \relax %
+    \stringizer{}\lstbaseem{0.6}%
+    \lst@DefineCatcodes{\active}%
+    \let\lst@PrePL \lst@PrePLDefault %
+    \let\lst@PostPL\lst@PostPLDefault}%
+\endgroup %
+%</logo>
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Matlab}
+% \begin{macro}{\lstdrv@matlab@keys}
+% \begin{macro}{\lstdrv@matlab@}
+% Once more \ldots
+%    \begin{macrocode}
+%<*matlab>
+\begingroup \makeatletter %
+\lst@MakeDigitsLetter %
+\gdef\lstdrv@matlab@keys{gt,lt,gt,lt,amp,%
+    abs,acos,acosh,acot,acoth,acsc,acsch,all,angle,ans,any,asec,asech,%
+    asin,asinh,atan,atan2,atanh,auread,auwrite,axes,axis,balance,bar,%
+    bessel,besselk,bessely,beta,betainc,betaln,blanks,bone,break,%
+    brighten,capture,cart2pol,cart2sph,caxis,cd,cdf2rdf,cedit,ceil,%
+    chol,cla,clabel,clc,clear,clf,clock,close,colmmd,Colon,colorbar,%
+    colormap,ColorSpec,colperm,comet,comet3,compan,compass,computer,%
+    cond,condest,conj,contour,contour3,contourc,contrast,conv,conv2,%
+    cool,copper,corrcoef,cos,cosh,cot,coth,cov,cplxpair,cputime,cross,%
+    csc,csch,csvread,csvwrite,cumprod,cumsum,cylinder,date,dbclear,%
+    dbcont,dbdown,dbquit,dbstack,dbstatus,dbstep,dbstop,dbtype,dbup,%
+    ddeadv,ddeexec,ddeinit,ddepoke,ddereq,ddeterm,ddeunadv,deblank,%
+    dec2hex,deconv,del2,delete,demo,det,diag,diary,diff,diffuse,dir,%
+    disp,dlmread,dlmwrite,dmperm,dot,drawnow,echo,eig,ellipj,ellipke,%
+    else,elseif,end,engClose,engEvalString,engGetFull,engGetMatrix,%
+    engOpen,engOutputBuffer,engPutFull,engPutMatrix,engSetEvalCallback,%
+    engSetEvalTimeout,engWinInit,eps,erf,erfc,erfcx,erfinv,error,%
+    errorbar,etime,etree,eval,exist,exp,expint,expm,expo,eye,fclose,%
+    feather,feof,ferror,feval,fft,fft2,fftshift,fgetl,fgets,figure,%
+    fill,fill3,filter,filter2,find,findstr,finite,fix,flag,fliplr,%
+    flipud,floor,flops,fmin,fmins,fopen,for,format,fplot,fprintf,fread,%
+    frewind,fscanf,fseek,ftell,full,function,funm,fwrite,fzero,gallery,%
+    gamma,gammainc,gammaln,gca,gcd,gcf,gco,get,getenv,getframe,ginput,%
+    global,gplot,gradient,gray,graymon,grid,griddata,gtext,hadamard,%
+    hankel,help,hess,hex2dec,hex2num,hidden,hilb,hist,hold,home,hostid,%
+    hot,hsv,hsv2rgb,i,if,ifft,ifft2,imag,image,imagesc,Inf,info,input,%
+    int2str,interp1,interp2,interpft,inv,invhilb,isempty,isglobal,%
+    ishold,isieee,isinf,isletter,isnan,isreal,isspace,issparse,isstr,j,%
+    jet,keyboard,kron,lasterr,lcm,legend,legendre,length,lin2mu,line,%
+    linspace,load,log,log10,log2,loglog,logm,logspace,lookfor,lower,ls,%
+    lscov,lu,magic,matClose,matDeleteMatrix,matGetDir,matGetFp,%
+    matGetFull,matGetMatrix,matGetNextMatrix,matGetString,matlabrc,%
+    matlabroot,matOpen,matPutFull,matPutMatrix,matPutString,max,mean,%
+    median,menu,mesh,meshc,meshgrid,meshz,mexAtExit,mexCallMATLAB,%
+    mexdebug,mexErrMsgTxt,mexEvalString,mexFunction,mexGetFull,%
+    mexGetMatrix,mexGetMatrixPtr,mexPrintf,mexPutFull,mexPutMatrix,%
+    mexSetTrapFlag,min,more,movie,moviein,mu2lin,mxCalloc,%
+    mxCopyCharacterToPtr,mxCopyComplex16ToPtr,mxCopyInteger4ToPtr,%
+    mxCopyPtrToCharacter,mxCopyPtrToComplex16,mxCopyPtrToInteger4,%
+    mxCopyPtrToReal8,mxCopyReal8ToPtr,mxCreateFull,mxCreateSparse,%
+    mxCreateString,mxFree,mxFreeMatrix,mxGetIr,mxGetJc,mxGetM,mxGetN,%
+    mxGetName,mxGetNzmax,mxGetPi,mxGetPr,mxGetScalar,mxGetString,%
+    mxIsComplex,mxIsFull,mxIsNumeric,mxIsSparse,mxIsString,%
+    mxIsTypeDouble,mxSetIr,mxSetJc,mxSetM,mxSetN,mxSetName,mxSetNzmax,%
+    mxSetPi,mxSetPr,NaN,nargchk,nargin,nargout,newplot,nextpow2,nnls,%
+    nnz,nonzeros,norm,normest,null,num2str,nzmax,ode23,ode45,orient,%
+    orth,pack,pascal,patch,path,pause,pcolor,pi,pink,pinv,plot,plot3,%
+    pol2cart,polar,poly,polyder,polyeig,polyfit,polyval,polyvalm,pow2,%
+    print,printopt,prism,prod,pwd,qr,qrdelete,qrinsert,quad,quad8,quit,%
+    quiver,qz,rand,randn,randperm,rank,rat,rats,rbbox,rcond,real,%
+    realmax,realmin,refresh,rem,reset,reshape,residue,return,rgb2hsv,%
+    rgbplot,rootobject,roots,rose,rosser,rot90,rotate,round,rref,%
+    rrefmovie,rsf2csf,save,saxis,schur,sec,sech,semilogx,semilogy,set,%
+    setstr,shading,sign,sin,sinh,size,slice,sort,sound,spalloc,sparse,%
+    spaugment,spconvert,spdiags,specular,speye,spfun,sph2cart,sphere,%
+    spinmap,spline,spones,spparms,sprandn,sprandsym,sprank,sprintf,spy,%
+    sqrt,sqrtm,sscanf,stairs,startup,std,stem,str2mat,str2num,strcmp,%
+    strings,strrep,strtok,subplot,subscribe,subspace,sum,surf,surface,%
+    surfc,surfl,surfnorm,svd,symbfact,symmmd,symrcm,tan,tanh,tempdir,%
+    tempname,terminal,text,tic,title,tmp,toc,toeplitz,trace,trapz,tril,%
+    triu,type,uicontrol,uigetfile,uimenu,uiputfile,unix,unwrap,upper,%
+    vander,ver,version,view,viewmtx,waitforbuttonpress,waterfall,%
+    wavread,wavwrite,what,whatsnew,which,while,white,whitebg,who,whos,%
+    wilkinson,wk1read,wk1write,xlabel,xor,ylabel,zeros,zlabel,zoom}%
+\endgroup %
+%    \end{macrocode}
+%    \begin{macrocode}
+\begingroup \makeatletter %
+\catcode`\"=12 %
+\gdef\lstdrv@matlab@{%
+    \keywords{\lstdrv@matlab@keys}%
+    \sensitivetrue %
+    \DeclareCLPercent %
+    \DeclareSingleComment stuff \relax %
+    \stringizer{'}\lstbaseem{0.6}%
+    \lst@DefineCatcodes{\active}%
+    \let\lst@PrePL \lst@PrePLDefault %
+    \let\lst@PostPL\lst@PostPLDefault}%
+\endgroup %
+%</matlab>
+%    \end{macrocode}
+% \end{macro}\end{macro}
+%
+%
+% \subsection{Modula-2}
+% \begin{macro}{\lstdrv@modula@}
+% And once again \ldots
+%    \begin{macrocode}
+%<*modula>
+\begingroup \makeatletter %
+\catcode`\"=12 \catcode`\*=\active %
+\gdef\lstdrv@modula@{%
+    \keywords{AND,ARRAY,BEGIN,BY,CASE,CONST,DIV,DO,ELSE,ELSIF,END,EXIT,%
+        EXPORT,FOR,FROM,IF,IMPLEMENTATION,IMPORT,IN,MOD,MODULE,NOT,OF,%
+        OR,POINTER,PROCEDURE,QUALIFIED,RECORD,REPEAT,RETURN,SET,THEN,%
+        TYPE,UNTIL,VAR,WHILE,WITH,ABS,BITSET,BOOLEAN,CAP,CARDINAL,CHAR,%
+        CHR,DEC,EXCL,FALSE,FLOAT,HALT,HIGH,INC,INCL,INTEGER,LONGCARD,%
+        LONGINT,LONGREAL,MAX,MIN,NIL,ODD,ORD,PROC,REAL,SIZE,TRUE,TRUNC,%
+        VAL}%
+    \sensitivetrue %
+    \DeclareCommentLine\relax %
+    \DeclareNestedComment (* *)\relax %
+    \stringizer[d]{'"}\lstbaseem{0.65}%
+    \lst@DefineCatcodes{\active}%
+    \let\lst@PrePL \lst@PrePLDefault %
+    \let\lst@PostPL\lst@PostPLDefault}%
+\endgroup %
+%</modula>
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Oberon-2}
+% \begin{macro}{\lstdrv@oberon@}
+% 'Nearly' Modula-2:
+%    \begin{macrocode}
+%<*oberon>
+\begingroup \makeatletter %
+\catcode`\"=12 \catcode`\*=\active %
+\gdef\lstdrv@oberon@{%
+    \keywords{ARRAY,BEGIN,BOOLEAN,BY,CASE,CHAR,CONST,DIV,DO,ELSE,ELSIF,%
+        END,EXIT,FALSE,FOR,IF,IMPORT,IN,INTEGER,IS,LONGINT,LONGREAL,%
+        LOOP,MOD,MODULE,NIL,OF,OR,POINTER,PROCEDURE,REAL,RECORD,REPEAT,%
+        RETURN,SET,SHORTINT,THEN,TO,TRUE,TYPE,UNTIL,VAR,WHILE,WITH,%
+        ABS,ASH,CAP,CHR,COPY,DEC,ENTIER,EXCL,HALT,INC,INCL,LEN,LONG,%
+        MAX,MIN,NEW,ODD,ORD,SHORT,SIZE}
+    \sensitivetrue %
+    \DeclareCommentLine\relax %
+    \DeclareNestedComment (* *)\relax %
+    \stringizer[d]{'"}\lstbaseem{0.65}%
+    \lst@DefineCatcodes{\active}%
+    \let\lst@PrePL \lst@PrePLDefault %
+    \let\lst@PostPL\lst@PostPLDefault}%
+\endgroup %
+%</oberon>
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Pascal}
+% \begin{macro}{\lstdrv@pascal@}
+% Since we already defined pascal comments in section \ref{ssComments},
+% no catcodes must be changed here.
+%    \begin{macrocode}
+%<*pascal>
+\begingroup \makeatletter %
+\gdef\lstdrv@pascal@{%
+    \keywords{alfa,and,array,begin,boolean,byte,case,char,const,div,do,%
+        downto,else,end,false,file,for,function,get,goto,if,in,integer,%
+        label,maxint,mod,new,not,of,or,pack,packed,page,program,%
+        procedure,put,read,readln,real,record,repeat,reset,rewrite,set,%
+        text,then,to,true,type,unpack,until,var,while,with,write,%
+        writeln}%
+    \sensitivefalse %
+    \DeclareCommentLine\relax %
+    \DeclareDoubleCommentPascal %
+    \stringizer[d]{'}\lstbaseem{0.6}%
+    \lst@DefineCatcodes{\active}%
+    \let\lst@PrePL \lst@PrePLDefault %
+    \let\lst@PostPL\lst@PostPLDefault}%
+\endgroup %
+%</pascal>
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Pascal XSC}
+% \begin{macro}{\lstdrv@pxsc@}
+% Tell me, if you want more words to be keywords.
+%    \begin{macrocode}
+%<*pxsc>
+\selectlisting{pascal}%
+\begingroup \makeatletter %
+\gdef\lstdrv@pxsc@{\lstdrv@pascal@ %
+    \morekeywords{dynamic,external,forward,global,module,nil,operator,%
+        priority,sum,type,use,dispose,mark,page,release,cimatrix,%
+        cinterval,civector,cmatrix,complex,cvector,dotprecision,%
+        imatrix,interval,ivector,rmatrix,rvector,string,im,inf,re,sup,%
+        chr,comp,eof,eoln,expo,image,ival,lb,lbound,length,loc,mant,%
+        maxlength,odd,ord,pos,pred,round,rval,sign,substring,succ,%
+        trunc,ub,ubound}}%
+\endgroup %
+%</pxsc>
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Turbo Pascal}
+% \begin{macro}{\lstdrv@tp@}
+% The keywords are the reserved words and predefined functions and
+% procedures of Turbo Pascal 6.0, I think. It's a long list \ldots
+%    \begin{macrocode}
+%<*tp>
+\selectlisting{pascal}%
+\begingroup \makeatletter %
+\gdef\lstdrv@tp@{\lstdrv@pascal@ %
+    \morekeywords{asm,constructor,destructor,implementation,inline,%
+        interface,nil,object,shl,shr,string,unit,uses,xor,%
+        Abs,Addr,ArcTan,Chr,Concat,Copy,Cos,CSeg,DiskFree,DiskSize,%
+        DosExitCode,DosVersion,DSeg,EnvCount,EnvStr,Eof,Eoln,Exp,%
+        FExpand,FilePos,FileSize,Frac,FSearch,GetBkColor,GetColor,%
+        GetDefaultPalette,GetDriverName,GetEnv,GetGraphMode,GetMaxMode,%
+        GetMaxX,GetMaxY,GetModeName,GetPaletteSize,GetPixel,GetX,GetY,%
+        GraphErrorMsg,GraphResult,Hi,ImageSize,InstallUserDriver,%
+        InstallUserFont,Int,IOResult,KeyPressed,Length,Lo,MaxAvail,%
+        MemAvail,MsDos,Odd,Ofs,Ord,OvrGetBuf,OvrGetRetry,ParamCount,%
+        ParamStr,Pi,Pos,Pred,Ptr,Random,ReadKey,Round,SeekEof,SeekEoln,%
+        Seg,SetAspectRatio,Sin,SizeOf,Sound,SPtr,Sqr,Sqrt,SSeg,Succ,%
+        Swap,TextHeight,TextWidth,Trunc,TypeOf,UpCase,WhereX,WhereY,%
+        Append,Arc,Assign,AssignCrt,Bar,Bar3D,BlockRead,BlockWrite,%
+        ChDir,Circle,ClearDevice,ClearViewPort,Close,CloseGraph,ClrEol,%
+        ClrScr,Dec,Delay,Delete,DelLine,DetectGraph,Dispose,DrawPoly,%
+        Ellipse,Erase,Exec,Exit,FillChar,FillEllipse,FillPoly,%
+        FindFirst,FindNext,FloodFill,Flush,FreeMem,FSplit,GetArcCoords,%
+        GetAspectRatio,GetDate,GetDefaultPalette,GetDir,GetCBreak,%
+        GetFAttr,GetFillSettings,GetFTime,GetImage,GetIntVec,%
+        GetLineSettings,GetMem,GetPalette,GetTextSettings,GetTime,%
+        GetVerify,GetViewSettings,GoToXY,Halt,HighVideo,Inc,InitGraph,%
+        Insert,InsLine,Intr,Keep,Line,LineRel,LineTo,LowVideo,Mark,%
+        MkDir,Move,MoveRel,MoveTo,MsDos,New,NormVideo,NoSound,OutText,%
+        OutTextXY,OvrClearBuf,OvrInit,OvrInitEMS,OvrSetBuf,PackTime,%
+        PieSlice,PutImage,PutPixel,Randomize,Rectangle,Release,Rename,%
+        RestoreCrtMode,RmDir,RunError,Sector,Seek,SetActivePage,%
+        SetAllPalette,SetBkColor,SetCBreak,SetColor,SetDate,SetFAttr,%
+        SetFillPattern,SetFillStyle,SetFTime,SetGraphBufSize,%
+        SetGraphMode,SetIntVec,SetLineStyle,SetPalette,SetRGBPalette,%
+        SetTextBuf,SetTextJustify,SetTextStyle,SetTime,SetUserCharSize,%
+        SetVerify,SetViewPort,SetVisualPage,SetWriteMode,Sound,Str,%
+        SwapVectors,TextBackground,TextColor,TextMode,Truncate,%
+        UnpackTime,Val,Window}}%
+\endgroup %
+%</tp>
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Perl}
+% \begin{macro}{\lstdrv@perl@keys}
+% First the keywords, \ldots
+%    \begin{macrocode}
+%<*perl>
+\begingroup \makeatletter %
+\lst@MakeDigitsLetter %
+\gdef\lstdrv@perl@keys{abs,accept,alarm,atan2,bind,binmode,bless,%
+    caller,chdir,chmod,chomp,chop,chown,chr,chroot,close,closedir,%
+    connect,continue,cos,crypt,dbmclose,dbmopen,defined,delete,die,do,%
+    dump,each,else,elsif,endgrent,endhostent,endnetent,endprotoent,%
+    endpwent,endservent,eof,eval,exec,exists,exit,exp,fcntl,fileno,%
+    flock,for,foreach,fork,format,formline,getc,getgrent,getgrgid,%
+    getgrnam,gethostbyaddr,gethostbyname,gethostent,getlogin,%
+    getnetbyaddr,getnetbyname,getnetent,getpeername,getpgrp,getppid,%
+    getpriority,getprotobyname,getprotobynumber,getprotoent,getpwent,%
+    getpwnam,getpwuid,getservbyname,getservbyport,getservent,%
+    getsockname,getsockopt,glob,gmtime,goto,grep,hex,if,import,index,%
+    int,ioctl,join,keys,kill,last,lc,lcfirst,length,link,listen,local,%
+    localtime,log,lstat,m,map,mkdir,msgctl,msgget,msgrcv,msgsnd,my,%
+    next,no,oct,open,opendir,ord,pack,package,pipe,pop,pos,print,%
+    printf,prototype,push,q,qq,quotemeta,qw,qx,rand,read,readdir,%
+    readlink,recv,redo,ref,rename,require,reset,return,reverse,%
+    rewinddir,rindex,rmdir,s,scalar,seek,seekdir,select,semctl,semget,%
+    semop,send,setgrent,sethostent,setnetent,setpgrp,setpriority,%
+    setprotoent,setpwent,setservent,setsockopt,shift,shmctl,shmget,%
+    shmread,shmwrite,shutdown,sin,sleep,socket,socketpair,sort,splice,%
+    split,sprintf,sqrt,srand,stat,study,sub,substr,symlink,syscall,%
+    sysopen,sysread,system,syswrite,tell,telldir,tie,tied,time,times,%
+    tr,truncate,uc,ucfirst,umask,undef,unless,unlink,unpack,unshift,%
+    untie,until,use,utime,values,vec,wait,waitpid,wantarray,warn,while,%
+    write,y}%
+\endgroup %
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lstdrv@perl@}
+% {\ldots} and now the main driver file macro.
+%    \begin{macrocode}
+\begingroup \makeatletter %
+\catcode`\"=12 \catcode`\#=12 %
+\gdef\lstdrv@perl@{%
+    \keywords{\lstdrv@perl@keys}%
+    \sensitivetrue %
+    \DeclareCommentLine#\relax %
+    \DeclareSingleComment stuff \relax %
+    \stringizer[b]{"'}\lstbaseem{0.6}%
+    \lst@DefineCatcodes{\active}%
+    \let\lst@PrePL \lstdrv@perl@PrePL %
+    \let\lst@PostPL\relax}%
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lstdrv@perl@ifPOD}
+% \begin{macro}{\lstdrv@perl@PrepareListing}
+% We use a switch to indicate PODs. Every (Perl) listing
+% \verb!\lst@Begin! calls the macro \verb!\lstdrv@perl@PrepareListing!
+% to reset the switch.
+%    \begin{macrocode}
+\gdef\lstdrv@perl@PODtrue{\let\lstdrv@perl@ifPOD\iftrue}%
+\gdef\lstdrv@perl@PODfalse{\let\lstdrv@perl@ifPOD\iffalse}%
+\gdef\lstdrv@perl@PrepareListing{\lstdrv@perl@PODfalse}%
+%    \end{macrocode}
+% \end{macro}\end{macro}
+%
+% \begin{macro}{\lstdrv@perl@PrePL}
+% \begin{macro}{\lstdrv@perl@TestComment}
+% \begin{macro}{\lstdrv@perl@TestCommentCut}
+% \begin{macro}{\lstdrv@perl@TestSharp}
+% Nothing else is really new now.
+%    \begin{macrocode}
+\gdef\lstdrv@perl@PrePL{%
+    \lst@ifstring %
+        \lst@stringfalse \lst@ProcessWhitespaces \lst@stringtrue %
+    \else\lstdrv@perl@ifPOD %
+        \expandafter\lstdrv@perl@TestCommentCut\lst@line=cut\relax %
+    \else \expandafter\lstdrv@perl@TestComment\lst@line\relax\relax %
+    \fi \fi}%
+\gdef\lstdrv@perl@TestCommentCut#1=cut#2\relax{%
+    \lst@commenttrue \expandafter\lst@Tokenize\lst@line\relax %
+    \let\lst@line\@empty \lst@commentfalse %
+    \ifx\@empty#2\@empty\else \lstdrv@perl@PODfalse \fi}%
+%    \end{macrocode}
+% We have to change some catcodes, to look for the sharp. In particular
+% we need a new 'macro parameter symbol' ($\&$).
+%    \begin{macrocode}
+\catcode`\$=11 \catcode`\&=6 \catcode`\#=12 %
+\gdef\lstdrv@perl@TestComment&1&2\relax{%
+    \ifx &1=%
+        \lstdrv@perl@PODtrue \lst@commenttrue %
+        \expandafter\lst@Tokenize\lst@line\relax %
+        \let\lst@line\@empty \lst@commentfalse %
+    \else %
+        \expandafter\lstdrv@perl@TestSharp\lst@line $#\relax %
+    \fi}%
+%    \end{macrocode}
+% The \cs{lowercase} mechanism mentioned some time before to replace
+% each \verb!$#! with \verb!$#!, where the latter \verb!#! has letter
+% catcode. This avoids wrong comment detection.
+%    \begin{macrocode}
+\catcode`\~=11 \lccode`\~=`\#%
+\lowercase{%
+\gdef\lstdrv@perl@TestSharp&1$#&2\relax{%
+    \ifx \@empty&2\@empty \else %
+        \expandafter\lstdrv@perl@ReplaceSharp\lst@line\relax %
+        \expandafter\lstdrv@perl@TestSharp\lst@line $#\relax %
+    \fi}%
+\gdef\lstdrv@perl@ReplaceSharp&1$#&2\relax{\def\lst@line{&1$~&2}}%
+}\endgroup %
+%</perl>
+%    \end{macrocode}
+% \end{macro}\end{macro}\end{macro}\end{macro}
+%
+%
+% \subsection{PL/I}
+% \begin{macro}{\lstdrv@pli@keys}
+% \begin{macro}{\lstdrv@pli@}
+% Same procedure \ldots
+%    \begin{macrocode}
+%<*pli>
+\begingroup \makeatletter %
+\lst@MakeDigitsLetter %
+\gdef\lstdrv@pli@keys{ABS,ATAN,AUTOMATIC,AUTO,ATAND,BEGIN,BINARY,BIN,%
+    BIT,BUILTIN,BY,CALL,CHARACTER,CHAR,CHECK,COLUMN,COL,COMPLEX,CPLX,%
+    COPY,COS,COSD,COSH,DATA,DATE,DECIMAL,DEC,DECLARE,DCL,DO,EDIT,ELSE,%
+    END,ENDFILE,ENDPAGE,ENTRY,EXP,EXTERNAL,EXT,FINISH,FIXED,%
+    FIXEDOVERFLOW,FOFL,FLOAT,FORMAT,GET,GO,GOTO,IF,IMAG,INDEX,INITIAL,%
+    INIT,INTERNAL,INT,LABEL,LENGTH,LIKE,LINE,LIST,LOG,LOG2,LOG10,MAIN,%
+    MAX,MIN,MOD,NOCHECK,NOFIXEDOVERFLOW,NOFOFL,NOOVERFLOW,NOOFL,NOSIZE,%
+    NOUNDERFLOW,NOUFL,NOZERODIVIDE,NOZDIV,ON,OPTIONS,OVERFLOW,OFL,PAGE,%
+    PICTURE,PROCEDURE,PROC,PUT,READ,REPEAT,RETURN,RETURNS,ROUND,SIN,%
+    SIND,SINH,SIZE,SKIP,SQRT,STATIC,STOP,STRING,SUBSTR,SUM,SYSIN,%
+    SYSPRINT,TAN,TAND,TANH,THEN,TO,UNDERFLOW,UFL,VARYING,WHILE,WRITE,%
+    ZERODIVIDE,ZDIV}%
+\endgroup %
+\begingroup \makeatletter %
+\catcode`\*=\active %
+\gdef\lstdrv@pli@{%
+    \keywords{\lstdrv@pli@keys}%
+    \sensitivefalse %
+    \DeclareCommentLine\relax %
+    \DeclareSingleComment /* */\relax %
+    \stringizer{'}\lstbaseem{0.6}%
+    \lst@DefineCatcodes{\active}%
+    \let\lst@PrePL \lst@PrePLDefault %
+    \let\lst@PostPL\lst@PostPLDefault}%
+\endgroup %
+%</pli>
+%    \end{macrocode}
+% \end{macro}\end{macro}
+%
+%
+% \subsection{Simula}
+% \begin{macro}{\lstdrv@simula@}
+% Same as all the time.
+%    \begin{macrocode}
+%<*simula>
+\begingroup \makeatletter %
+\catcode`\"=12 %
+\gdef\lstdrv@simula@{%
+    \keywords{activate,after,array,at,before,begin,boolean,character,%
+        class,comment,delay,detach,do,else,end,external,false,for,go,%
+        goto,if,in,inner,inspect,integer,is,label,name,new,none,notext,%
+        otherwise,prior,procedure,qua,reactivate,real,ref,resume,%
+        simset,simulation,step,switch,text,then,this,to,true,until,%
+        value,virtual,when,while}%
+    \sensitivefalse %
+    \DeclareCommentLine\relax %
+    \DeclareSingleComment stuff \relax %
+    \stringizer{"'}\lstbaseem{0.65}%
+    \lst@DefineCatcodes{\active}%
+    \let\lst@PrePL \lst@PrePLDefault %
+    \let\lst@PostPL\lst@PostPLDefault}%
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lstdrv@simula@67}
+% \begin{macro}{\lstdrv@simula@cii}
+% \begin{macro}{\lstdrv@simula@dec}
+% \begin{macro}{\lstdrv@simula@ibm}
+% Macros for the options:
+%    \begin{macrocode}
+\global\@namedef{lstdrv@simula@67}{\lstdrv@simula@}%
+\global\@namedef{lstdrv@simula@cii}{\lstdrv@simula@%
+    \morekeywords{and,equiv,exit,impl,not,or,stop}}%
+\global\@namedef{lstdrv@simula@dec}{\lstdrv@simula@%
+    \morekeywords{and,eq,eqv,ge,gt,hidden,imp,le,long,lt,ne,not,%
+        options,or,protected,short}}%
+\global\@namedef{lstdrv@simula@ibm}{\lstdrv@simula@dec}%
+\endgroup %
+%    \end{macrocode}
+% \end{macro}\end{macro}\end{macro}\end{macro}
+%
+% \begin{macro}{\lstdrv@simula@PrepareListing}
+% \begin{macro}{\lstdrv@simula@OutputOther}
+% \begin{macro}{\lstdrv@simula@Output@}
+% \begin{macro}{\lstdrv@simula@AppendOther@}
+% Refer the section about Algol how comments are implemented.
+%    \begin{macrocode}
+\begingroup \makeatletter %
+\gdef\lstdrv@simula@commenttrue{%
+    \global\let\lstdrv@simula@ifcomment\iftrue}%
+\gdef\lstdrv@simula@commentfalse{%
+    \global\let\lstdrv@simula@ifcomment\iffalse %
+    \global\let\lstdrv@simula@closingcomment\@empty}%
+\gdef\lstdrv@simula@PrepareListing{%
+    \lstdrv@simula@commentfalse %
+    \let\lst@OutputOther\lstdrv@simula@OutputOther %
+    \let\lst@Output\lstdrv@simula@Output@ %
+    \let\lst@AppendOther\lstdrv@simula@AppendOther}%
+%    \end{macrocode}
+%    \begin{macrocode}
+\gdef\lstdrv@simula@OutputOther{%
+    \expandafter\def\expandafter\lst@text\expandafter{\the\lst@other}%
+    \ifx\lst@text\@empty\else %
+        \lstdrv@simula@ifcomment\lst@MakeBox{\lst@commentstyle}\else %
+        \lst@ifstring \lst@MakeStringBox{\lst@stringstyle}\else %
+        \lst@ifcomment\lst@MakeBox{\lst@commentstyle}\else %
+            \lst@MakeBox{}%
+        \fi \fi \fi %
+        \global\advance\lst@pos by -\lst@length %
+        \lst@other{}\let\lst@text\@empty \lst@length0 %
+    \fi}%
+%    \end{macrocode}
+%    \begin{macrocode}
+\gdef\lstdrv@simula@Output@{%
+    \ifx\lst@text\@empty\else %
+        \lstdrv@simula@ifcomment %
+            \ifx\@empty\lstdrv@simula@closingcomment %
+                \lst@MakeBox{\lst@commentstyle}%
+            \else %
+                \expandafter\lst@ifoneof\lst@text\relax %
+                {else,end,otherwise,when}%
+                    {\lstdrv@simula@commentfalse %
+                     \lst@MakeBox{\lst@keywordstyle}}%
+                    {\lst@MakeBox{\lst@commentstyle}}%
+            \fi \else %
+        \lst@ifstring \lst@MakeStringBox{\lst@stringstyle}\else %
+        \lst@ifcomment\lst@MakeBox{\lst@commentstyle}\else %
+        \expandafter\lst@KeywordOrNot\lst@text\relax %
+        \expandafter\lst@ifoneof\lst@text\relax{comment,end}%
+            {\lstdrv@simula@commenttrue %
+             \expandafter\lst@ifoneof\lst@text\relax{end}%
+                 {\gdef\lstdrv@simula@closingcomment{a}}{}}%
+            {}% empty else from 'ifoneof'
+        \fi \fi \fi %
+        \global\advance\lst@pos by -\lst@length %
+        \let\lst@text\@empty \lst@length0 %
+    \fi}%
+%    \end{macrocode}
+%    \begin{macrocode}
+\gdef\lstdrv@simula@AppendOther#1{%
+    \lstdrv@simula@ifcomment \if;#1%
+        \lst@OutputOther \lstdrv@simula@commentfalse %
+    \fi \fi %
+    \advance\lst@length\@ne %
+    \expandafter\lst@other\expandafter{\the\lst@other#1}}%
+\endgroup %
+%</simula>
+%    \end{macrocode}
+% \end{macro}\end{macro}\end{macro}\end{macro}
+%
+%
+% \subsection{SQL}
+% \begin{macro}{\lstdrv@sql@}
+% Do you have corrections? Do you want more data base languages?
+%    \begin{macrocode}
+%<*sql>
+\begingroup \makeatletter %
+\catcode`\"=12 \catcode`\*=\active \catcode`\_=11 %
+\gdef\lstdrv@sql@{%
+    \keywords{absolute,action,add,allocate,alter,are,assertion,at,%
+        between,bit,bit_length,both,cascade,cascaded,case,cast,catalog,%
+        char_length,character_length,coalesce,collate,collation,column,%
+        connect,connection,constraint,constraints,convert,%
+        corresponding,cross,current_date,current_time,%
+        current_timestamp,current_user,date,day,deallocate,deferrable,%
+        defered,describe,descriptor,diagnostics,disconnect,domain,drop,%
+        else,end,exec,except,exception,execute,external,extract,false,%
+        first,full,get,global,hour,identity,immediate,initially,inner,%
+        input,insensitive,intersect,interval,isolation,join,last,%
+        leading,left,level,local,lower,match,minute,month,names,%
+        national,natural,nchar,next,no,nullif,octet_length,only,outer,%
+        output,overlaps,pad,partial,position,prepare,preserve,prior,%
+        read,relative,restrict,revoke,right,rows,scroll,second,session,%
+        session_user,size,space,sqlstate,substring,system_user,%
+        temporary,then,time,timestamp,timezone_hour,timezone_minute,%
+        trailing,transaction,translate,translation,trim,true,unknown,%
+        upper,usage,using,value,varchar,varying,when,write,year,zone}%
+    \sensitivefalse %
+    \DeclareCommentLine\relax %
+    \DeclareSingleComment /* */\relax %
+    \stringizer{'"}\lstbaseem{0.6}%
+    \lst@DefineCatcodes{\active}%
+    \let\lst@PrePL \lst@PrePLDefault %
+    \let\lst@PostPL\lst@PostPLDefault}%
+\endgroup %
+%</sql>
+%    \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{\TeX}
+% \begin{macro}{\lstdrv@tex@primitives}
+% \begin{macro}{\lstdrv@tex@commoncs}
+% \begin{macro}{\lstdrv@tex@latexcs}
+% We define the different classes of control sequences. The second macro
+% holds the common control sequences of plain-\TeX{} and \LaTeXe.
+%    \begin{macrocode}
+%<*tex>
+\begingroup \makeatletter %
+\gdef\lstdrv@tex@primitives{above,abovedisplayshortskip,%
+    abovedisplayskip,abovewithdelims,accent,adjdemerits,advance,%
+    afterassignment,aftergroup,atop,atopwithdelims,badness,%
+    baselineskip,batchmode,begingroup,belowdisplayshortskip,%
+    belowdisplayskip,binoppenalty,botmark,box,boxmaxdepth,%
+    brokenpenalty,catcode,char,chardef,cleaders,closein,closeout,%
+    clubpenalty,copy,count,countdef,cr,crcr,csname,day,deadcycles,def,%
+    defaulthyphenchar,defaultskewchar,delcode,delimiter,%
+    delimiterfactor,delimitershortfall,dimen,dimendef,discretionary,%
+    displayindent,displaylimits,displaystyle,displaywidowpenalty,%
+    displaywidth,divide,doublehyphendemerits,dp,else,emergencystretch,%
+    end,endcsname,endgroup,endinput,endlinechar,eqno,errhelp,%
+    errmessage,errorcontextlines,errorstopmode,escapechar,everycr,%
+    everydisplay,everyhbox,everyjob,everymath,everypar,everyvbox,%
+    exhyphenpenalty,expandafter,fam,fi,finalhypendemerits,firstmark,%
+    floatingpenalty,font,fontdimen,fontname,futurelet,gdef,global,%
+    globaldefs,halign,hangafter,hangindent,hbadness,hbox,hfil,hfill,%
+    hfilneg,hfuzz,hoffset,holdinginserts,hrule,hsize,hskip,hss,ht,%
+    hyphenation,hyphenchar,hyphenpenalty,if,ifcase,ifcat,ifdim,ifeof,%
+    iffalse,ifhbox,ifhmode,ifinner,ifmmode,ifnum,ifodd,iftrue,ifvbox,%
+    ifvmode,ifvoid,ifx,ignorespaces,immediate,indent,input,insert,%
+    insertpenalties,interlinepenalty,jobname,kern,language,lastbox,%
+    lastkern,lastpenalty,lastskip,lccode,leaders,left,lefthyphenmin,%
+    leftskip,leqno,let,limits,linepenalty,lineskip,lineskiplimits,long,%
+    looseness,lower,lowercase,mag,mark,,mathaccent,mathbin,mathchar,%
+    mathchardef,mathchoice,mathclose,mathcode,mathinner,mathop,%
+    mathopen,mathord,mathpunct,mathrel,mathsurround,maxdeadcycles,%
+    maxdepth,meaning,medmuskip,message,mkern,month,moveleft,moveright,%
+    mskip,multiply,muskip,muskipdef,newlinechar,noalign,noboundary,%
+    noexpand,noindent,nolimits,nonscript,nonstopmode,%
+    nulldelimiterspace,nullfont,number,omit,openin,openout,or,outer,%
+    output,outputpenalty,over,overfullrule,overline,overwithdelims,%
+    pagedepth,pagefilllstretch,pagefillstretch,pagefilstretch,pagegoal,%
+    pageshrink,pagestretch,pagetotal,par,parfillskip,parindent,%
+    parshape,parskip,patterns,pausing,penalty,postdisplaypenalty,%
+    predisplaypenalty,predisplaysize,pretolerance,prevdepth,prevgraf,%
+    radical,raise,read,relax,relpenalty,right,righthyphenmin,rightskip,%
+    romannumeral,scriptfont,scriptscriptfont,scriptscriptstyle,%
+    scriptspace,scriptstyle,scrollmode,setbox,setlanguage,sfcode,%
+    shipout,show,showbox,showboxbreadth,showboxdepth,showlists,showthe,%
+    skewchar,skip,skipdef,spacefactor,spaceskip,span,special,%
+    splitbotmark,splitfirstmark,splitmaxdepth,splittopskip,string,%
+    tabskip,textfont,textstyle,the,thickmuskip,thinmuskip,time,toks,%
+    toksdef,tolerance,topmark,topskip,tracingcommands,tracinglostchars,%
+    tracingmacros,tracingonline,tracingoutput,tracingpages,%
+    tracingparagraphs,tracingrestores,tracingstats,uccode,uchyph,%
+    underline,unhbox,unhcopy,unkern,unpenalty,unskip,unvbox,unvcopy,%
+    uppercase,vadjust,valign,vbadness,vbox,vcenter,vfil,vfill,vfilneg,%
+    vfuzz,voffset,vrule,vsize,vskip,vsplit,vss,vtop,wd,widowpenalty,%
+    write,xdef,xleaders,xspaceskip,year}%
+\gdef\lstdrv@tex@commoncs{active,acute,ae,AE,aleph,allocationnumber,%
+    allowbreak,alpha,amalg,angle,approx,arccos,arcsin,arctan,arg,%
+    arrowvert,Arrowvert,ast,asymp,b,backslash,bar,beta,bgroup,big,Big,%
+    bigbreak,bigcap,bigcirc,bigcup,bigg,Bigg,biggl,Biggl,biggm,Biggm,%
+    biggr,Biggr,bigl,Bigl,bigm,Bigm,bigodot,bigoplus,bigotimes,bigr,%
+    Bigr,bigskip,bigskipamount,bigsqcup,bigtriangledown,bigtriangleup,%
+    biguplus,bigvee,bigwedge,bmod,bordermatrix,bot,bowtie,brace,%
+    braceld,bracelu,bracerd,braceru,bracevert,brack,break,breve,%
+    buildrel,bullet,c,cap,cases,cdot,cdotp,cdots,centering,centerline,%
+    check,chi,choose,circ,clubsuit,colon,cong,coprod,copyright,cos,%
+    cosh,cot,coth,csc,cup,d,dag,dagger,dashv,ddag,ddagger,ddot,ddots,%
+    deg,delta,Delta,det,diamond,diamondsuit,dim,displaylines,div,do,%
+    dospecials,dot,doteq,dotfill,dots,downarrow,Downarrow,%
+    downbracefill,egroup,eject,ell,empty,emptyset,endgraf,endline,%
+    enskip,enspace,epsilon,equiv,eta,exists,exp,filbreak,flat,fmtname,%
+    fmtversion,footins,footnote,footnoterule,forall,frenchspacing,%
+    frown,gamma,Gamma,gcd,ge,geq,gets,gg,goodbreak,grave,H,hat,hbar,%
+    heartsuit,hglue,hideskip,hidewidth,hom,hookleftarrow,%
+    hookrightarrow,hphantom,hrulefill,i,ialign,iff,Im,imath,in,inf,%
+    infty,int,interdisplaylinepenalty,interfootnotelinepenalty,intop,%
+    iota,item,j,jmath,joinrel,jot,kappa,ker,l,L,lambda,Lambda,land,%
+    langle,lbrace,lbrack,lceil,ldotp,ldots,le,leavevmode,leftarrow,%
+    Leftarrow,leftarrowfill,leftharpoondown,leftharpoonup,leftline,%
+    leftrightarrow,Leftrightarrow,leq,lfloor,lg,lgroup,lhook,lim,%
+    liminf,limsup,line,ll,llap,lmoustache,ln,lnot,log,longleftarrow,%
+    Longleftarrow,longleftrightarrow,Longleftrightarrow,longmapsto,%
+    longrightarrow,Longrightarrow,loop,lor,lq,magstep,magstep,%
+    magstephalf,mapsto,mapstochar,mathhexbox,mathpalette,mathstrut,%
+    matrix,max,maxdimen,medbreak,medskip,medskipamount,mid,min,models,%
+    mp,mu,multispan,nabla,narrower,natural,ne,nearrow,neg,negthinspace,%
+    neq,newbox,newcount,newdimen,newfam,newif,newinsert,newlanguage,%
+    newmuskip,newread,newskip,newtoks,newwrite,next,ni,nobreak,%
+    nointerlineskip,nonfrenchspacing,normalbaselines,%
+    normalbaselineskip,normallineskip,normallineskiplimit,not,notin,nu,%
+    null,nwarrow,o,O,oalign,obeylines,obeyspaces,odot,oe,OE,%
+    offinterlineskip,oint,ointop,omega,Omega,ominus,ooalign,openup,%
+    oplus,oslash,otimes,overbrace,overleftarrow,overrightarrow,owns,P,%
+    parallel,partial,perp,phantom,phi,Phi,pi,Pi,pm,pmatrix,pmod,Pr,%
+    prec,preceq,prime,prod,propto,psi,Psi,qquad,quad,raggedbottom,%
+    raggedright,rangle,rbrace,rbrack,rceil,Re,relbar,Relbar,%
+    removelastskip,repeat,rfloor,rgroup,rho,rhook,rightarrow,%
+    Rightarrow,rightarrowfill,rightharpoondown,rightharpoonup,%
+    rightleftharpoons,rightline,rlap,rmoustache,root,rq,S,sb,searrow,%
+    sec,setminus,sharp,showhyphens,sigma,Sigma,sim,simeq,sin,sinh,skew,%
+    slash,smallbreak,smallint,smallskip,smallskipamount,smash,smile,sp,%
+    space,spadesuit,sqcap,sqcup,sqrt,sqsubseteq,sqsupseteq,ss,star,%
+    strut,strutbox,subset,subseteq,succ,succeq,sum,sup,supset,supseteq,%
+    surd,swarrow,t,tan,tanh,tau,TeX,theta,Theta,thinspace,tilde,times,%
+    to,top,tracingall,triangle,triangleleft,triangleright,u,underbar,%
+    underbrace,uparrow,Uparrow,upbracefill,updownarrow,Updownarrow,%
+    uplus,upsilon,Upsilon,v,varepsilon,varphi,varpi,varrho,varsigma,%
+    vartheta,vdash,vdots,vec,vee,vert,Vert,vglue,vphantom,wedge,%
+    widehat,widetilde,wlog,wp,wr,xi,Xi,zeta}%
+\gdef\lstdrv@tex@latexcs{a,AA,aa,addcontentsline,addpenalty,%
+    addtocontents,addtocounter,addtolength,addtoversion,addvspace,alph,%
+    Alph,and,arabic,array,arraycolsep,arrayrulewidth,arraystretch,%
+    author,baselinestretch,begin,bezier,bfseries,bibcite,bibdata,%
+    bibitem,bibliography,bibliographystyle,bibstyle,boldmath,%
+    botfigrule,bottomfraction,Box,caption,center,CheckCommand,circle,%
+    citation,cite,cleardoublepage,clearpage,cline,columnsep,%
+    columnseprule,columnwidth,contentsline,dashbox,date,dblfigrule,%
+    dblfloatpagefraction,dblfloatsep,dbltextfloatsep,dbltopfraction,%
+    defaultscriptratio,defaultscriptscriptratio,depth,Diamond,%
+    displaymath,document,documentclass,documentstyle,doublerulesep,em,%
+    emph,endarray,endcenter,enddisplaymath,enddocument,endenumerate,%
+    endeqnarray,endequation,endflushleft,endflushright,enditemize,%
+    endlist,endlrbox,endmath,endminipage,endpicture,endsloppypar,%
+    endtabbing,endtabular,endtrivlist,endverbatim,enlargethispage,%
+    ensuremath,enumerate,eqnarray,equation,evensidemargin,extracolsep,%
+    fbox,fboxrule,fboxsep,filecontents,fill,floatpagefraction,floatsep,%
+    flushbottom,flushleft,flushright,fnsymbol,fontencoding,fontfamily,%
+    fontseries,fontshape,fontsize,fontsubfuzz,footnotemark,footnotesep,%
+    footnotetext,footskip,frac,frame,framebox,fussy,glossary,%
+    headheight,headsep,height,hline,hspace,I,include,includeonly,index,%
+    inputlineno,intextsep,itemindent,itemize,itemsep,iterate,itshape,%
+    Join,kill,label,labelsep,labelwidth,LaTeX,LaTeXe,leadsto,lefteqn,%
+    leftmargin,leftmargini,leftmarginii,leftmarginiii,leftmarginiv,%
+    leftmarginv,leftmarginvi,leftmark,lhd,linebreak,linespread,%
+    linethickness,linewidth,list,listfiles,listfiles,listparindent,%
+    lrbox,makeatletter,makeatother,makebox,makeglossary,makeindex,%
+    makelabel,MakeLowercase,MakeUppercase,marginpar,marginparpush,%
+    marginparsep,marginparwidth,markboth,markright,math,mathbf,%
+    mathellipsis,mathgroup,mathit,mathsf,mathsterling,mathtt,%
+    mathunderscore,mathversion,mbox,mdseries,mho,minipage,multicolumn,%
+    multiput,NeedsTeXFormat,newcommand,newcounter,newenvironment,%
+    newfont,newhelp,newlabel,newlength,newline,newmathalphabet,newpage,%
+    newsavebox,newtheorem,nobreakspace,nobreakspace,nocite,nocorr,%
+    nocorrlist,nofiles,nolinebreak,nonumber,nopagebreak,normalcolor,%
+    normalfont,normalmarginpar,numberline,obeycr,oddsidemargin,%
+    oldstylenums,onecolumn,oval,pagebreak,pagenumbering,pageref,%
+    pagestyle,paperheight,paperwidth,paragraphmark,parbox,parsep,%
+    partopsep,picture,poptabs,pounds,protect,pushtabs,put,qbezier,%
+    qbeziermax,r,raggedleft,raisebox,ref,refstepcounter,renewcommand,%
+    renewenvironment,restorecr,reversemarginpar,rhd,rightmargin,%
+    rightmark,rmfamily,roman,Roman,rootbox,rule,samepage,sbox,scshape,%
+    secdef,sectionmark,selectfont,setcounter,settodepth,settoheight,%
+    settowidth,sffamily,shortstack,showoutput,showoverfull,sloppy,%
+    sloppypar,slshape,sqsubset,sqsupset,SS,stackrel,stepcounter,stop,%
+    stretch,subparagraphmark,subsectionmark,subsubsectionmark,%
+    suppressfloats,symbol,tabbing,tabbingsep,tabcolsep,tabular,%
+    tabularnewline,textasciicircum,textasciitilde,textbackslash,%
+    textbar,textbf,textbraceleft,textbraceright,textbullet,textcircled,%
+    textcompwordmark,textdagger,textdaggerdbl,textdollar,textellipsis,%
+    textemdash,textendash,textexclamdown,textfloatsep,textfraction,%
+    textgreater,textheight,textit,textless,textmd,textnormal,%
+    textparagraph,textperiodcentered,textquestiondown,textquotedblleft,%
+    textquotedblright,textquoteleft,textquoteright,textregistered,%
+    textrm,textsc,textsection,textsf,textsl,textsterling,%
+    textsuperscript,texttrademark,texttt,textunderscore,textup,%
+    textvisiblespace,textwidth,thanks,thefootnote,thempfn,thempfn,%
+    thempfootnote,thepage,thepage,thicklines,thinlines,thispagestyle,%
+    title,today,topfigrule,topfraction,topmargin,topsep,totalheight,%
+    tracingfonts,trivlist,ttfamily,twocolumn,typein,typeout,unboldmath,%
+    unitlength,unlhd,unrhd,upshape,usebox,usecounter,usefont,%
+    usepackage,value,vector,verb,verbatim,vline,vspace,width}%
+%    \end{macrocode}
+% \end{macro}\end{macro}\end{macro}
+%
+% \begin{macro}{\texcs}
+% \begin{macro}{\moretexcs}
+% The definitions are similar to \cs{keywords} and \cs{morekeywords}.
+%    \begin{macrocode}
+\gdef\texcs#1{\edef\lst@cs{,\zap@space#1 \@empty}}%
+\gdef\moretexcs#1{\edef\lst@cs{\lst@cs,\zap@space#1 \@empty}}%
+%    \end{macrocode}
+% \end{macro}\end{macro}
+%
+% \begin{macro}{\lstdrv@tex@}
+% Main driver and option macros:
+%    \begin{macrocode}
+\gdef\lstdrv@tex@{%
+    \keywords{}%
+    \texcs{\lstdrv@tex@primitives,\lstdrv@tex@commoncs,%
+        advancepageno,beginsection,bf,bffam,bye,cal,cleartabs,columns,%
+        dosupereject,endinsert,eqalign,eqalignno,fiverm,fivebf,fivei,%
+        fivesy,folio,footline,hang,headline,it,itemitem,itfam,%
+        leqalignno,magnification,makefootline,makeheadline,midinsert,%
+        mit,mscount,nopagenumbers,normalbottom,of,oldstyle,pagebody,%
+        pagecontents,pageinsert,pageno,plainoutput,preloaded,proclaim,%
+        rm,settabs,sevenbf,seveni,sevensy,sevenrm,sl,slfam,supereject,%
+        tabalign,tabs,tabsdone,tabsyet,tenbf,tenex,teni,tenit,tenrm,%
+        tensl,tensy,tentt,textindent,topglue,topins,topinsert,tt,ttfam,%
+        ttraggedright,vfootnote}%
+    \sensitivetrue %
+    \DeclareCLPercent %
+    \DeclareSingleComment stuff \relax %
+    \stringizer{}\lstbaseem{0.6}%
+    \lst@DefineCatcodes{\active}%
+    \let\lst@PrePL \relax %
+    \let\lst@PostPL\relax}%
+\gdef\lstdrv@tex@plain{\lstdrv@tex@}%
+\gdef\lstdrv@tex@primitive{\lstdrv@tex@ \texcs{\lstdrv@tex@primitives}}%
+\gdef\lstdrv@tex@latex{\lstdrv@tex@ %
+    \texcs{\lstdrv@tex@primitives,\lstdrv@tex@latexcs}}%
+\gdef\lstdrv@tex@allatex{\lstdrv@tex@ %
+    \keywords{array,center,displaymath,document,enumerate,eqnarray,%
+        equation,flushleft,flushright,itemize,list,lrbox,math,minipage,%
+        picture,sloppypar,tabbing,tabular,trivlist,verbatim}%
+    \texcs{\lstdrv@tex@primitives,\lstdrv@tex@latexcs,%
+        AtBeginDocument,AtBeginDocument,AtBeginDvi,AtEndDocument,%
+        AtEndOfClass,AtEndOfPackage,ClassError,ClassInfo,ClassWarning,%
+        ClassWarningNoLine,CurrentOption,DeclareErrorFont,%
+        DeclareFixedFont,DeclareFontEncoding,%
+        DeclareFontEncodingDefaults,DeclareFontFamily,DeclareFontShape,%
+        DeclareFontSubstitution,DeclareMathAccent,DeclareMathAlphabet,%
+        DeclareMathAlphabet,DeclareMathDelimiter,DeclareMathRadical,%
+        DeclareMathSizes,DeclareMathSymbol,DeclareMathVersion,%
+        DeclareOldFontCommand,DeclareOption,DeclarePreloadSizes,%
+        DeclareRobustCommand,DeclareSizeFunction,DeclareSymbolFont,%
+        DeclareSymbolFontAlphabet,DeclareTextAccent,%
+        DeclareTextAccentDefault,DeclareTextCommand,%
+        DeclareTextCommandDefault,DeclareTextComposite,%
+        DeclareTextCompositeCommand,DeclareTextFontCommand,%
+        DeclareTextSymbol,DeclareTextSymbolDefault,ExecuteOptions,%
+        GenericError,GenericInfo,GenericWarning,IfFileExists,%
+        InputIfFileExists,LoadClass,LoadClassWithOptions,MessageBreak,%
+        OptionNotUsed,PackageError,PackageInfo,PackageWarning,%
+        PackageWarningNoLine,PassOptionsToClass,PassOptionsToPackage,%
+        ProcessOptionsProvidesClass,ProvidesFile,ProvidesFile,%
+        ProvidesPackage,ProvideTextCommand,RequirePackage,%
+        RequirePackageWithOptions,SetMathAlphabet,SetSymbolFont,%
+        TextSymbolUnavailable,UseTextAccent,UseTextSymbol}}%
+\endgroup %
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lstdrv@tex@PrepareListing}
+% Here we assign a different \verb!\lst@Output! macro to detect control
+% sequences. We also (re-) set some catcodes.
+%    \begin{macrocode}
+\begingroup \makeatletter %
+\gdef\lstdrv@tex@PrepareListing{\let\lst@Output\lstdrv@tex@Output %
+    \catcode`\0=12 \catcode`\1=12 \catcode`\2=12 \catcode`\3=12 %
+    \catcode`\4=12 \catcode`\5=12 \catcode`\6=12 \catcode`\7=12 %
+    \catcode`\8=12 \catcode`\9=12}%
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\lstdrv@tex@Output}
+% \begin{macro}{\lstdrv@tex@CSOrNot}
+% These macros are similar to \verb!\lst@Output! and
+% \verb!\lst@CaseSensitiveKeywords!. We only do some adjustments, e.g.\ 
+% we need no 'ifstring' test, since the stringizer is empty for \TeX{}.
+%    \begin{macrocode}
+\gdef\lstdrv@tex@Output{%
+    \ifx\lst@text\@empty\else %
+        \lst@ifcomment\lst@MakeBox{\lst@commentstyle}%
+        \else\ifx\lst@lastother\lst@inputbackslash %
+            \expandafter\lstdrv@tex@CSOrNot\lst@text\relax %
+        \else\expandafter\lst@KeywordOrNot\lst@text\relax %
+        \fi \fi %
+        \global\advance\lst@pos by -\lst@length %
+        \let\lst@text\@empty \lst@length0 %
+    \fi}%
+\gdef\lstdrv@tex@CSOrNot#1\relax{%
+    \def\lst@test##1,#1,##2\relax{%
+        \ifx \@empty##2\@empty \lst@MakeBox{}%
+        \else \lst@MakeBox{\lst@keywordstyle}%
+        \fi}%
+    \expandafter\lst@test\lst@cs,#1,\relax}%
+\endgroup
+%</tex>
+%    \end{macrocode}
+% \end{macro}\end{macro}
+%
+%
+% \begingroup\small
+% \section{Extensions}\label{sExtensions}
+% Define a new driver file for an additional language.
+% Refer the previous section how this is done.
+%
+% If you want comment lines or comments, which are not supported by
+% the declaration commands of this package, you have a problem.
+% Contact me or follow these steps:
+% \begin{enumerate}
+% \item \DescribeMacro\lst@CommentLine
+%	Define the macro, which cuts up the input line into a comment
+%	line and the noncomment rest: The macro gets the input via the
+%	macro \verb!\lst@line!. After the call \verb!\lst@line! must hold
+%	the noncomment rest and \verb!\lst@commentline! the comment line.
+%	The C++ line
+% \begin{verbatim}
+%    if (comments!=appear) // comment stuff\end{verbatim}
+%	must be cut into '\verb|if (comments!=appear) |' and
+%	'\verb!// comment stuff!'.
+% \item \DescribeMacro\lst@SOC
+%	Define the macro, which finds the start of a comment:
+%	The macro gets the input via the macro \verb!\lst@line!. After
+%	the call \verb!\lst@line! must contain the source line upto the
+%	first appearance of a comment (exclusive). The comment and might
+%	the rest of the line must be in the macro \verb!\lst@comment!.
+%	If a comment is separated (not if and only if), you have to call
+%       \verb!\lst@commenttrue!. The Pascal line
+% \begin{verbatim}
+%    if { comment } appears then\end{verbatim}
+%	is cut into '\verb!if !' and '\verb!{ comment } appears then!'.
+% \item \DescribeMacro\lst@EOC
+%	Define the macro, which finds the end of a comment:
+%	The macro gets the input via the macro \verb!\lst@line!. After
+%	the call \verb!\lst@comment! must hold the comment and
+%	\verb!\lst@line! the noncomment rest of the line (which might be
+%	empty, of course). If the end of comment is found, you have to call
+%	\verb!\lst@commentfalse!. The Pascal line
+% \begin{verbatim}
+%    { comment } appears then\end{verbatim}
+%	must be cut into '\verb!{ comment }!' and '\verb! appears then!'.
+% \end{enumerate}
+% Assign these macros to \verb!\lst@CommentLine!, \verb!\lst@SOC! and
+% \verb!\lst@EOC! within your language command.
+%
+%
+% \section{History}\label{sHistory}
+% Only major changes after version 0.15 are listed here.
+% Previous changes are still present in the \texttt{.dtx}-file.
+% \renewcommand\labelitemi{--}
+% \begin{itemize}
+% \iffalse
+% \item[0.1] from 1996/03/09
+%	\item test version to look whether package is possible or not
+% \item[0.11] from 1996/08/19
+%	\item additional blank option
+%	\item	\cs{keywords}, \cs{morekeywords}, \cs{keywordstyle}
+%		and \cs{commentstyle} are new commands
+%	\item implementation guide improved and user's guide updated
+%	\item alignment improved by rewriting some macros
+% \item[0.12] from 1997/01/16
+%	\item nearly perfect alignment now
+%	\item \cs{stringizer}, \cs{stringstyle}, \cs{prelisting}
+%		and \cs{postlisting} are new
+%	\item user selection \cs{listingtrue} and \cs{listingfalse} possible
+%	\item \cs{blankstringtrue} and \cs{blankstringfalse} handle output
+%		of blanks in strings
+%	\item package supports tabulators now; new command \cs{tablength}
+% \item[0.13] from 1997/02/11
+%	\item additional languages: Eiffel, Fortran 90, Modula-2, Pascal XSC
+%	\item load on demand: language specific macros moved to driver files
+%	\item comments are declared now and not implemented for each language
+%		again (this makes the \TeX{} sources easier to read)
+%	\item 'string exceeds line' test moved to
+%		\verb!\lst@PreProcessLineDefault!
+%	\item sample files moved to .dtx-file
+% \item[0.14] from 1997/02/18
+%	\item user's guide rewritten
+%	\item implementation guide uses macro environment from the doc
+%		package
+%	\item (non) case sensitivity implemented, e.g.\ Pascal is not
+%	\item multiple stringizer implemented, i.e.\ Modula-2 handles
+%		both string types: quotes and double quotes
+%	\item comment declaration is user-accessible now
+%	\item package compatible to \verb!german.sty! now
+%	\item changed some identifiers
+% \item[0.15] from 1997/04/18
+%	\item listing environment is new
+%	\item additional languages: Java, Turbo Pascal
+%   \item \verb!\lst@width! changes from 0.65em to 0.8em for Fortran 90
+%   \item corrected some mistakes in the documentation
+%	\item package renamed from listing.dtx to listings.dtx, since there
+%		is already a listing package
+% \fi
+% \item[0.16] from 1997/06/01
+%	\item Thanks to Anders Edenbrandt\footnote{Department of Computer
+%		Science\ \ Lund University, Sweden.
+%       [email protected]} for reporting two bugs:
+%		lstmodula.sty corrected (misspelled \verb!\`"!) and
+%		call of \verb!\lst@???style!s in \verb!\lst@Begin! avoid
+%		loading of font files when catcodes are changed.
+%	\item Thanks to Rolf Niepraschk\footnote{Physikalisch--Technische
+%		Bundesanstalt\ \ Berlin, Germany.
+%       [email protected]} for reporting wrong catcode
+%		of \verb!$!. I've also changed catcode of \verb!@! and took
+%		over the proposal of using \verb!\zap@space!. The catcode of
+%       the percent \verb!%! is restored after typesetting a listing now.
+%	\item Thanks to Knut M\"uller\footnote{[email protected]} and
+%       Stefan Meister\footnote{FH--Wolfenb\"uttel, Germany.}
+%		for reporting problem with the command \cs{blankstringtrue}.
+%		The problem is gone.
+% \iffalse
+%	\item changed '$<$' to '$>$' in \verb!\lst@SkipUptoFirst!
+%   \item bug removed: \verb!\lst@Begin! must be placed before
+%       \verb!\lst@SkipUptoFirst!
+% \fi
+%   \item new commands \cs{spreadlisting}, \cs{listoflistings},
+%       \cs{labelstyle}, \cs{thelstline}, \cs{lstbaseem},
+%       \cs{listlistingsname}
+%   \item listing environment rewritten
+% \item[0.17] from 1997/09/29
+%	\item \cs{spreadlisting} works correct now (e.g.\ page numbers
+%		move not right any more), new commands \cs{selectlisting}
+%		and \cs{lstlineskip}, \cs{labelstyle} changed
+%	\item speed up things (quick 'if parameter empty', all \cs{long}
+%		except one removed, faster \verb!\lst@GotoNextTabStop!, etc.)
+%	\item alignment of wide other characters improved (e.g.\ $==$)
+%	\item many new languages: Ada, Algol, Cobol, Comal 80, Elan,
+%		Fortran 77, Lisp, Logo, Matlab, Oberon, Perl, PL/I, Simula,
+%		SQL, \TeX{}
+% \end{itemize}
+%
+%
+% \begin{thebibliography}{99}
+% \bibitem{Ada}
+%		\textsc{Barnes, John Gilbert Presslie}:
+%		\textbf{Programming in Ada plus language reference manual}\\
+%		{\copyright} 1991 Addison-Wesley Publishing Company, Inc.;
+%		ISBN 0-201-56539-0
+% \bibitem{Algol60}
+%		\textsc{Uwe Pape}:
+%		\textbf{Programmieren in ALGOL 60}\\
+%		{\copyright} 1973 Carl Hanser Verlag M\"unchen;
+%		ISBN 3-446-11605-2
+% \bibitem{Algol68}
+%		\textsc{Frank G.\ Pagan}:
+%		\textbf{A practical guide to ALGOL 68}\\
+%		{\copyright} 1976 by John Wiley $\&$ Sohn Ltd.;
+%		ISBN 0-471-65746-8 (Cloth); ISBN 0-471-65747-6 (Pbk)
+% \bibitem{Comal}
+%		\textsc{Borge R. Christensen}:
+%		\textbf{Strukturierte Programmierung mit COMAL 80} [aus dem
+%		D\"anischen \"ubertragen und bearbeitet von Margarete Kragh]\\
+%		2., verb.\ Auflage -- M\"unchen; Wien: Oldenburg, 1985;
+%		ISBN 3-486-26902-X
+% \bibitem{Eiffel}
+%       \textsc{Bertrand Meyer}: \textbf{Eiffel: the language}\\
+%       Prentice Hall International (UK) Ldt, 1992;
+%       ISBN 0-13-247925-7
+% \bibitem{Elan}
+%		\textsc{Leo~H.~Klingen, Jochen Liedtke}:
+%		\textbf{Programmieren mit ELAN}\\
+%		B.G.\ Teubner, Stuttgart 1983; ISBN 3-519-02507-8
+% \bibitem{Fortran77}
+%		\textsc{Karl Hans M\"uller}:
+%		\textbf{Fortran 77: Programmierungsanleitung}\\
+%		3., v\"ollig neu bearb.\ Aufl.\ -- Mannheim; Wien; Z\"urich:
+%		Bibliographisches Institut, 1984;
+%		ISBN 3-411-05804-8
+% \bibitem{Fortran90}
+%       \textsc{Thomas Michel}: \textbf{Fortran 90: Lehr-- und Handbuch}\\
+%       Mannheim; Leipzig; Wien; Z\"urich: BI-Wiss.-Verlag, 1994;
+%       ISBN 3-411-16861-7
+% \bibitem{Matlab} \texttt{http://www.utexas.edu/math/Matlab/Manual}
+% \bibitem{Modula}
+%       \textsc{Niklaus Wirth}: \textbf{Programmieren in Modula-2},
+%       \"Ubers.\ Guido Pfeiffer\\
+%       2.\ Auflage -- Berlin; Heidelberg; New York; London; Paris; Tokyo;
+%               Hong Kong: Springer, 1991;
+%       ISBN 3-540-51689-1
+% \bibitem{java} \texttt{http://java.sun.com}
+% \bibitem{lisp}
+%		\textsc{Guy Steele}:
+%		\textbf{Common Lisp}\\
+%		Copyright 1990 by Digital Equipment Corporation;
+%		ISBN 1-55558-042-4
+% \bibitem{perl} \texttt{http://www.perl.com}
+% \bibitem{pli}
+%		\textsc{Bernhard Fischer, Herman Fischer}:
+%		\textbf{Structured Programming in PL/I and PL/C}\\
+%		Copyright {\copyright} 1976 by Marcel Dekker, Inc.;
+%		ISBN 0-8247-6394-7
+% \bibitem{simula}
+%		\textsc{G\"unther Lamprecht}:
+%		\textbf{Introduction to SIMULA 67}\\
+%		Braunschweig; Wiesbaden: Vieweg, 1981
+% \bibitem{sql}
+%		\textsc{Jim~Melton, Alan~R.~Simon}:
+%		\textbf{Understanding the new SQL: A Complete Guide}\\
+%		{\copyright} 1993 Morgan Kaufmann Publishers, Inc.;
+%		ISBN 1-55860-245-3
+% \bibitem{verbatim}
+%       \textsc{Rainer Sch\"opf, Bernd Raichle, Chris Rowley}:
+%       \textbf{A New Implementation of \LaTeX's \texttt{verbatim}
+%           and \texttt{verbatim*} Environments.}
+% \end{thebibliography}
+% \endgroup
+%
+%
+% \setcounter{IndexColumns}{2}
+% \PrintIndex
+%
+%
+% \Finale
+%
+\endinput

+ 59 - 0
docs/packages/listings/listings.ins

@@ -0,0 +1,59 @@
+%%
+%% Installation file: Listings package for LaTeX2e
+%% (w)(c) 1996-1997 by Carsten Heinz
+%%
+\def\batchfile{listings.ins}
+\input{docstrip}
+\keepsilent
+
+\preamble
+
+(w)(c) 1996-1997 by Carsten Heinz
+
+This file is distributed freely. You are not allowed to take money
+for the distribution or use of this file, except for a nominal charge
+for copying etc.
+
+This file is distributed without any warranty; without even the implied
+warranty of merchantability or fitness for a particular purpose.
+
+You are not allowed to change this file.
+
+\endpreamble
+
+\askforoverwritefalse
+
+\generate{%
+  \file{listings.sty}{\from{listings.dtx}{package}}
+  \file{lstblank.sty}{\from{listings.dtx}{blank}}
+  \file{lstada.sty}{\from{listings.dtx}{ada}}
+  \file{lstalgol.sty}{\from{listings.dtx}{algol}}
+  \file{lstc.sty}{\from{listings.dtx}{c}}
+  \file{lstcpp.sty}{\from{listings.dtx}{cpp}}
+  \file{lstcobol.sty}{\from{listings.dtx}{cobol}}
+  \file{lstcomal.sty}{\from{listings.dtx}{comal}}
+  \file{lsteiffel.sty}{\from{listings.dtx}{eiffel}}
+  \file{lstelan.sty}{\from{listings.dtx}{elan}}
+  \file{lstfortran.sty}{\from{listings.dtx}{fortran}}
+  \file{lstjava.sty}{\from{listings.dtx}{java}}
+  \file{lstlisp.sty}{\from{listings.dtx}{lisp}}
+  \file{lstlogo.sty}{\from{listings.dtx}{logo}}
+  \file{lstmatlab.sty}{\from{listings.dtx}{matlab}}
+  \file{lstmodula.sty}{\from{listings.dtx}{modula}}}
+\generate{%
+  \file{lstoberon.sty}{\from{listings.dtx}{oberon}}
+  \file{lstpascal.sty}{\from{listings.dtx}{pascal}}
+  \file{lstpxsc.sty}{\from{listings.dtx}{pxsc}}
+  \file{lsttp.sty}{\from{listings.dtx}{tp}}
+  \file{lstperl.sty}{\from{listings.dtx}{perl}}
+  \file{lstpli.sty}{\from{listings.dtx}{pli}}
+  \file{lstsimula.sty}{\from{listings.dtx}{simula}}
+  \file{lstsql.sty}{\from{listings.dtx}{sql}}
+  \file{lsttex.sty}{\from{listings.dtx}{tex}}}
+
+
+\Msg{*}
+\Msg{* Move all `.sty' files into a directory searched by TeX.}
+\Msg{*}
+\Msg{* Run the `.dtx' file through LaTeX2e to get the documentation.}
+\Msg{*}

+ 339 - 0
docs/packages/mdwtools/COPYING

@@ -0,0 +1,339 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.

+ 499 - 0
docs/packages/mdwtools/README

@@ -0,0 +1,499 @@
+
+                            ===============
+
+                            M D W T O O L S
+
+                            ===============
+
+
+--- Licence note ---
+
+mdwtools package release note
+Copyright (c) 1996 Mark Wooding, except doafter, which is Copyright (c) 1996
+Peter Schmitt and Mark Wooding.
+
+These programs are free software; you can redistribute them and/or modify
+them 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.
+
+These programs are distributed in the hope that they 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 these programs; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+--- What it's all about ---
+
+This is a bunch of LaTeX 2e packages which have made my life as a LaTeX user
+easier, so I thought I'd share them.  I'm mainly an ARM assembler hacker
+(which explains why my TeX code looks so horrible), although I have been
+known to write documentation for programs.  This may explain the sort of
+things these packages do, and where I'm coming from.
+
+
+--- Licencing ---
+
+The packages are made available under the GNU General Public Licence (not the
+usual LaTeX agreement).  A copy of this licence is supplied in the file
+COPYING.  You should read this document if you haven't read it already, even
+if it's just for educational value.  I'm not actually sure how good a thing
+the GNU GPL actually is, so I'm sort of testing the water.  The idea that
+this is how all software should be distributed still fills me with a certain
+amount of trepidation.
+
+
+--- What's in the box ---
+
+You should have received the following files in whatever sort of archive
+thing this suite came in:
+
+  README	-- You've got this file for sure, because it's this one
+  COPYING	-- A textual version of the GNU General Public Licence
+  at.dtx	-- Documentation and code for `at.sty' package
+  cmtt.dtx	-- Documentation and code for `cmtt.sty'package and
+		   associated files
+  doafter.dtx	-- Documentation and code for `doafter.sty' package; the
+		   code is also used in `syntax.sty' and `mdwtab.sty'
+  mdwlist.dtx	-- Documentation and code for `mdwlist.sty' package
+  mdwmath.dtx	-- Documentation and code for `mdwmath.sty' package
+  mdwtab.dtx	-- Documentation and code for `mdwtab.sty' and `mathenv.sty'
+		   packages
+  footnote.dtx  -- Documentation and code for `footnote.sty' package; the
+		   code is used in `mdwtab.sty'
+  sverb.dtx	-- Documentation and code for `sverb.stx' package
+  syntax.dtx	-- Documentation and code for `syntax.dtx' package
+  mdwtools.ins	-- Installation script for all the packages
+  gpl.tex	-- LaTeX version of the GNU General Public Licence
+  mdwtools.tex	-- Definitions for typesetting the documentation
+
+If you're missing any of these files, complain at whoever gave the rest of
+them to you, and get them quickly.  However, if you're lucky, you may have
+received some other files:
+
+  at.sty	-- Unpacked `at.sty' package
+  cmtt.sty	-- Unpacked `cmtt.sty' package
+  mTTenc.def	-- Unpacked encoding definition file for `cmtt.sty'
+  mTTcmtt.fd	-- Unpacked font definition file for `cmtt.sty'
+  doafter.sty	-- Unpacked `doafter.sty' package for LaTeX
+  doafter.tex	-- Unpacked `doafter.tex' package for Plain TeX
+  mathenv.sty	-- Unpacked `mathenv.sty' package
+  mdwlist.sty	-- Unpacked `mdwlist.sty' package
+  mdwmath.sty	-- Unpacked `mdwmath.sty' package
+  mdwtab.sty	-- Unpacked `mdwtab.sty' package
+  footnote.sty  -- Unpackad `savenot.dty' package
+  sverb.sty	-- Unpacked `sverb.sty' package
+  syntax.sty	-- Unpacked `syntax.sty' package
+
+  at.dvi	-- Typeset documentation for `at.sty'
+  cmtt.dvi	-- Typeset documentation for `cmtt.sty' and co.
+  doafter.dvi	-- Typeset documentation for `doafter.sty'
+  mdwlist.dtx	-- Typeset documentation for `mdwlist.sty'
+  mdwmath.dvi	-- Typeset documentation for `mdwmath.sty'
+  mdwtab.dvi	-- Typeset documentation for `mdwtab.sty' and `mathenv.sty'
+  footnote.dvi	-- Typeset documentation for `footnote.sty'
+  sverb.dvi	-- Typeset documentation for `sverb.sty'
+  syntax.dvi	-- Typeset documentation for `syntax.sty'
+
+If you've already got these, then great, because you don't have to generate
+them.  If you haven't, it's not a big deal.  You might also have a bunch of
+files with extensions like `.log', `.aux', `.tmp', `.ilg' and so on.  These
+files are really not at all interesting, and you might as well get rid of
+them now.
+
+
+--- What the packages do ---
+
+Before we can get anywhere, you need to know what the packages do, roughly
+speaking.  Here's a quick rundown:
+
+at.sty		-- Allows you to use `@' as a sort of `command-introducing'
+		   character, a bit like `\' is already.  This gives you
+		   a lot more short command names which you can assign to
+		   common constructions.  For example, you can set up
+		   @/<text>/ as a command to put <text> in italics.
+
+cmtt.sty	-- Provides an `mTT' encoding for the Computer Modern
+		   Typewriter font, which solves lots of messy problems.
+
+doafter.sty	-- Provides a TeX programmer's utility
+		     \doafter <token> <group>
+		   which does the <token> after the group is complete,
+		   including any \aftergroup things.  The code was originally
+		   written by Peter Schmitt in answer to a `challenge' I made
+		   on comp.text.tex;I tweaked it a bit to make it work
+		   slightly better.  doafter.tex is a plain TeX version of
+		   the same macro.
+
+mathenv.sty	-- Contains a collection of mathematical environments with
+		   a theme of aligning things in columns.  There's a
+		   rewritten version of `eqnarray' which is much more
+		   powerful than the old one, and it gets the spacing right.
+		   This package requires `mdwtab.sty' in order to work.  It
+		   is extracted from `mdwtab.dtx'.  In general, the AmS
+		   things to a better job, although it seems that the mathenv
+		   matrix and script handling environments give prettier
+		   results than the AmS equivalents (at least to my eyes).
+
+mdwlist.sty	-- Various list related environments.  There's a more
+		   versatile `description' environment, and some stuff for
+		   making `compacted' lists (with no extra space between
+		   items).
+
+mdwmath.sty	-- Contains a few trivial definitions for mathematical
+		   things.  The main thing is that the \sqrt command for
+		   doing square roots has been improved -- there's a \sqrt*
+		   command which stops the line being drawn over the formula
+		   being square-rooted, and the positioning of the root
+		   index (the optional argument) has been improved.
+
+mdwtab.sty	-- A complete ground-up rewrite of LaTeX's `tabular' and
+		   `array' environments.  Has lots of advantages over
+		   the standard version, and over the version in `array.sty'.
+		   It works correctly with all the table-related packages in
+		   the Tools bundle (longtable, delarray, hhline, tabularx
+		   and dcolumn).  This package includes most of the code
+		   from `doafter.sty' and `footnote.sty' (it doesn't load
+		   the packages -- it has its own copies built-in, although
+		   you won't waste memory if you do load these packages).
+		   To generate `mdwtab.sty', you require `mdwtab.dtx',
+		   `doafter.dtx' and `footnote.dtx'; the last two provide
+		   the shared code.
+
+footnote.sty	-- Provides commands for saving executing footnotes; the
+		   author has noticed several packages which attempt to
+		   enable footnotes in tables, all of which eat an extra
+		   token list register.  This is an attempt to offer shared
+		   code to do the job, saving space and effort.  It also
+		   provides a `footnote' environment which allows verbatim
+		   text.
+
+sverb.sty	-- A bunch of macros for doing verbatim things.  Required
+		   for typesetting all the documentation for the other
+		   packages.
+
+syntax.sty	-- A load of commands for describing syntax.  There's an
+		   environment for typesetting BNF grammars.  But best of
+		   all, there's a load of commands and environments for
+		   drawing syntax diagrams.  Required for typesetting all
+		   the documentation for the other packages.  If you're
+		   extracting syntax.sty from syntax.dtx, you also need
+		   doafter.dtx.
+
+With the exception of the dependencies listed above, the packages will all
+work independently of each other.  If you want to typeset the documentation,
+you'll need `sverb.sty' and `syntax.sty'.  Typesetting the documentation
+isn't essential, although it will probably help if you can see what the
+various commands actually do.
+
+
+--- Extracting the packages ---
+
+If you don't have the various .sty files already, you'll need to extract them
+from the .dtx files.  This requires docstrip.tex, which should be part of
+your base LaTeX 2e distribution.  If you have docstrip vsersion 2.3d, which
+is available with the December 1995 release of LaTeX, things will go rather
+faster.  If your LaTeX release is much older than this, you should upgrade,
+because the packages need a fairly new LaTeX anyway.  (I could do something
+about this, but I won't, because I want to encourage everyone to upgrade.)
+
+If everything's set up correctly, all you should need to do is say
+
+  tex mdwtools.ins
+
+or
+
+  latex mdwtools.ins
+
+or whatever incantation is necessary to run TeX or LaTeX on the supplied
+`mdwtools.ins' file on your system.
+
+TeX will grind away at the files for a bit, and then say `Done' at you. (This
+could take a while, so be patient.)  You will then have a mdwtools.log file,
+which you can throw away, and a collection of sparkly new .sty files, which
+you should put somewhere where TeX can find them easily.
+
+
+--- Typesetting the documentation ---
+
+If you want to typeset the documentation for a package, you'll need the
+`mdwtools.tex' file provided, and the `syntax.sty' and `sverb.sty' packages.
+You'll also need the `.dtx' file for the package you want documentation on,
+and any packages it generated.
+
+For example, if you want documentation on `mathenv.sty', you need:
+
+  mdwtools.tex	-- Shared defintions for all the documentation files
+  syntax.sty	-- Syntax typesetting commands
+  sverb.sty	-- Verbatim text handling commands
+  mathenv.sty	-- So the documentation can use it to demonstrate its
+		   features
+  mdwtab.sty	-- Required by `mathenv.sty'
+  mdwtab.dtx	-- The documentation file from which `mathenv.sty' was
+		   extracted, and therefore the file which contains the
+		   documentation you want to read
+
+Make sure you've got all the files, and then run LaTeX on the .dtx file you
+want to read.
+
+TeX will start hammering away for a very short while, and then stop and ask
+you whether you want to build the indexing files.  Generating index files
+takes a lot longer (I'd guess that it doubled the amount of time taken to
+typeset the `.dtx' file) so I don't recommend it unless:
+
+  * you've got a very fast processor, or
+  * you're very interested in how the package works internally, or
+  * you just like everything to be complete, or
+  * you're a masochist.
+
+Even so, there's no point writing indexing information the first time you
+run LaTeX on a file, because the table of contents hasn't been created yet,
+and when you LaTeX the file the second time, all the references will change.
+
+If you want the index files anyway, type `y' when you're asked.  Otherwise,
+type 'n'.  You know you want to type `n' really...
+
+If you want to do the job properly, you need to run LaTeX a second time
+to read in the contents table.  /This/ is the correct time to turn on
+indexing, if you really want it.
+
+If you did build the index files, you should now sort the index by saying
+
+  makeindex -s gind.ist <name>.idx
+
+where <name> is the same as the name of the `.dtx' file.  The `gind.ist' file
+should have come with LaTeX.  Having done this, you should run the `.dtx'
+file though LaTeX one final time, to insert the formatted index.
+
+You can now print or preview the generated `.dvi' file using whatever tools
+you usually use for such things.
+
+
+--- What changed? ---
+
+Here's a list of what changed in the various releases.
+
+Version		Changes
+
+1.00		* First general releases of everything.
+
+
+1.01		* Fixed typos in various bits of documentation.
+
+		* (mdwtab.sty) Added enhanced \cline command.  Added
+		  hhline.sty to list of supported table-related packages.
+		  (I guess it always worked -- I just forgot about it.)
+		  Made some of the section titles a little sillier ;-)
+
+		* (mathenv.sty) Added some new random environments, mainly
+		  because I saw some more interesting examples in /The/
+		  /TeXbook/ and had an idea...  Now support nesting of
+		  various environments, albeit rather imperfectly.
+
+		* (at.sty) Made @-commands really properly robust.  Fixed
+		  some lies in the documentation.  Removed some truly insane
+		  bits of old code here too.  Made package sort of
+		  cooperate with amsmath's use of @-commands -- suggestions
+		  for improvement welcomed.
+
+		* (mdwtools.tex) Fixed /really/ stupid mistake in which made
+		  typesetting the documentation about fifty times slower
+		  than it should have been (bashes self on head several
+		  times).  Changed the structure here a bit too, to handle
+		  document classes as well as packages.  Made TeX much
+		  quieter while it's typesetting the documentation.
+
+		* (sverb.sty) Fixed duff paragraph formatting in listing
+		  environment and \verbinput command (due to the `wrong
+		  sort' of grouping).  (My excuse for missing this one is
+		  that my standard document class sets \parskip=0pt.)
+
+		* (mdwtools.ins) Fixed this in line with the documentation
+		  which hints that it should work with older docstrips.
+		  It's a bit hacky but it works.
+
+
+1.02		* (gpl.tex) Fixed some bugs which made typesetting go wrong
+		  in larger documents.  Restructured preamble so that it
+		  can be typeset on its own.  Put in eplicit item numbers
+		  in the enumerate environments, for more obvious conformance
+		  to the original.
+
+		* (mdwtab.sty) Lots of changes here, many suggested by
+		  David Carlisle (so oodles of thanks to him for taking
+		  an interest in my humble hackings).  Fixed bugs, including
+		  one which put entirely incorrect interline spacing in
+		  `p' type columns.  Redone the handling of [t] and [b]
+		  tables with top and bottom rules, and removed the
+		  `\rulefudge' parameter which is no longer necessary.
+		  Miscellaneous other changes.
+
+		* (mdwtab.dtx) Tidied up some nastinesses in the
+		  documentation, and removed the `\over' commands from the
+		  maths demos, to keep certain people happy.  Floated a few
+		  more of the demonstrations to make page breaking better.
+		  There's a danger that some of the demos are drifting too
+		  far away from their text, but it's not too bad yet.
+
+		* (syntax.sty) Used \doafter here to fix some colour handling
+		  problems.
+
+		* (syntax.sty) Tidied up the `grammar' environment quite a
+		  bit (it now uses `\item', rather than trying to emulate it
+		  internally), and fixed some vicious bugs in it and some
+		  other code.
+
+		* (doafter.sty etc.) A new addition, to make the various
+		  packages handle colour properly.  Mainly written by
+		  Peter Scmitt, actually, I just fiddled with it a little.
+		  Then Peter gave me a better version, and I've tried to
+		  upgrade this one.
+
+		* (footnote.sty) A new addition, to offer some shared things
+		  for handling footnotes.  It also enables footnotes in
+		  parboxes, which used to be difficult, and provides a
+		  `footnote' environment which allows verbatim text.
+
+		* (mdwlist.sty} A new addition, providing miscellanous
+		  list-related macros.  It's a sort of mixed bag of things
+		  I've had lying around various document preambles, combined
+		  with some ideas from the Companion.
+
+		* (at.sty) Rewritten command name parser to be much nicer.
+		  Added support for digits within @-command names (subject
+		  to being enabled by an option).  This is in response to
+		  requests in comp.text.tex for digits in command names.
+
+		* (mathenv.sty) Totally overhauled the matrix spacing rules.
+		  Added `script' environment.  Improved numbering things,
+		  with `\eqnumber'.  
+
+		* (mdwtools.tex) Some minor changes here to fix some buglets.
+		  Played with some more float parameters, to discourage
+		  float pages a bit more.  Then revamped completely, turned
+		  into a docced program (although it isn't docstripped),
+		  rewritten title generation, and made much more
+		  customisable.
+
+
+1.02a		* (mdwtab.sty) Added support for table beautification in
+		  longtable.  Documented how to do this.
+
+
+1.03		* (mdwtab.sty) Completely redone the paragraph-cell handling:
+		  list environments now work properly inside tables (without
+		  funny extra space appearing at the top and bottom).  Also
+		  fixed a bug in the newline handling, which ignored negative
+		  interrow space in the \\ command.
+
+		* (syntax.sty) Changed the underscore handling, and some
+		  other bits, to fit in rather better with LaTeX's output
+		  encoding system.  It's nastier and hackier inside, but it
+		  works better with things like the DC fonts.  Also stopped
+		  re-lowercasing of `~' from escaping and messing everything
+		  up for everyone.  Improved underscore appearance by
+		  lowering it some more.
+
+		* (syntax.sty) Replaced some `2's with `\tw@'s.  Added a
+		  comment about dvips's inaccurate positioning of rules.
+
+		* (sverb.sty) Made non-* environments build end text from
+		  the name of the current environment, rather than having it
+		  hardcoded.  Also stopped `unignore' environments being
+		  a group.
+
+		* (sverb.dtx) Removed some porkies from the documentation.
+
+		* (mdwtab.sty) Fixed some miscellaneous typos.  Removed
+		  `\rulefudge' from the table of tweakables, because it
+		  was withdrawn in release 1.02.
+
+		* (cmtt.dtx) New package, for handling the `cmtt' font
+		  better.  It introduces a special encoding for the font,
+		  and provides a command which allows you to use all the
+		  characters without the disadvantages of verbatim text.
+
+		* (other changes) Improved distribution building and
+		  testing stuff which you can't see because I'm not
+		  releasing it.
+
+
+1.04		* (syntax.sty) Provided some new commands for playing with
+		  interword spacing in `tt' fonts.
+
+		* (doafter.dtx and footnote.dtx) Added some docstrip guards
+		  around the meta-comments, so that the charactertable and
+		  the GPL header aren't put into other packages.
+		  Unfortunately the version of docstrip which understands
+		  this hasn't been released yet...
+
+		* RCSified everything, so I can find old revisions, and I'm
+		  less likely to destroy everything.
+
+		* (footnote.dtx) Added a check for AMS environments doing
+		  measuring passes, to avoid duplicated footnotes.  (Spotted
+		  by Roberto Bagnara.)
+
+
+1.05		* (mdwtab.dtx) Fixed stupid bug in paragraph cells which
+		  left 1000pt high table rows.  (Spotted by Rowland.)
+
+		* (mdwtab.dtx) Fixed horizontal spacing problems with
+		  empty paragraph cells.
+
+		* (mdwlist.dtx) Allowed compact lists and resumed lists
+		  to pass arguments on to the underlying environments.
+
+
+--- Future plans ---
+
+doafter.sty	Add Peter Schmitt's testing for implicit/explicit braces,
+		as a package or docstrip option.  (This extra testing is
+		a significant chunk of code, and I don't think it's worth
+		burdening the standard version with it.  Peter agrees with
+		me.)
+
+mathenv.sty	Do postprocessing on display maths environments to position
+		the equations and equation numbers properly, so they don't
+		overlap (like the AMS environments do, although more
+		robustly).  Once this is done, I think I'll have a reasonable
+		case for saying that this provides an alternative to the
+		AMS environments, although quite what the advantage is I
+		don't know: mdwtab.sty isn't exactly small.
+
+		Work is currently `in progress' on this one.
+
+mdwtab.sty	Consider doing postprocessing on tables (yuk) in a blkarray
+		sort of way.
+
+footnote.sty	Merge with Robin Fairbairn's package of the same name.  Allow
+		different rules for continued notes (suggested by Donald
+		Arseneau, after a news article by Jonathan Wand).
+
+New packages	I'm currently working on a little something for typesetting
+		poetry properly (centring poems horizontally based on the
+		longest line, etc.), handling footnotes properly, doing
+		line numbering etc.  If anyone has any wishes for this,
+		little things a tyro like me ought to know, or knows that
+		it's already done better than I could manage, then let me
+		know.
+
+
+--- Contacting the author ---
+
+The author can be reached by email at [email protected].  This is his
+personal dial-up account, paid for privately, so don't expect replies after
+five minutes or anything like that.
+
+If you do have any comments regarding the code, its documentation, or
+anything else to do with these packages, don't leave me guessing -- let me
+know.  While I won't guarantee to do anything about your comments, chances
+are that I'll right any wrongs and rescue any damsels in distress (oh, no,
+wrong spiel).
+
+
+-----------------------------------------------------------------------------

+ 753 - 0
docs/packages/mdwtools/at.dtx

@@ -0,0 +1,753 @@
+% \begin{meta-comment}
+%
+% $Id$
+%
+% Allow @-commands
+%
+% (c) 1995 Mark Wooding
+%
+%----- Revision history -----------------------------------------------------
+%
+% $Log$
+% Revision 1.1  1998-09-21 10:18:06  michael
+% Initial implementation
+%
+% Revision 1.3  1996/11/19 20:46:55  mdw
+% Entered into RCS
+%
+%
+% \end{meta-comment}
+%
+% \begin{meta-comment} <general public licence>
+%%
+%% at package -- support for `@' commands'
+%% Copyright (c) 1996 Mark Wooding
+%%
+%% This program is free software; you can redistribute it and/or modify
+%% it under the terms of the GNU General Public License as published by
+%% the Free Software Foundation; either version 2 of the License, or
+%% (at your option) any later version.
+%%
+%% This program is distributed in the hope that it will be useful,
+%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+%% GNU General Public License for more details.
+%%
+%% You should have received a copy of the GNU General Public License
+%% along with this program; if not, write to the Free Software
+%% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+%%
+% \end{meta-comment}
+%
+% \begin{meta-comment} <Package preamble>
+%<+package>\NeedsTeXFormat{LaTeX2e}
+%<+package>\ProvidesPackage{at}
+%<+package>                [1996/05/02 1.3 @-command support (MDW)]
+% \end{meta-comment}
+%
+% \CheckSum{355}
+%% \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>
+%
+%<*driver>
+\input{mdwtools}
+\describespackage{at}
+\aton
+\atlet p=\package
+\atdef at{\package{at}}
+\atdef={\mbox{-}}
+\atdef-{@@@=}
+\atlet.=\syntax
+\mdwdoc
+%</driver>
+%
+% \end{meta-comment}
+%
+% \section{User guide}
+%
+% The @at\ package is an attempt to remove a lot of tedious typing that
+% ends up in \LaTeX\ documents, by expanding the number of short command
+% names available.  The new command names begin with the `|@|' character,
+% rather than the conventional `|\|', so you can tell them apart.
+%
+% The package provides some general commands for defining @-commands, and
+% then uses them to define some fairly simple ones which will be useful to
+% most people.
+%
+% The rules for @-command names aren't terribly complex:
+% \begin{itemize}
+% \item If the first character of the name is a letter, then the command name
+%       consists of all characters up to, but not including, the first
+%       nonletter.  Spaces following the command name are ignored.
+% \item If the first character of the name is a backslash, then the @-command
+%       name consists of the control sequence introduced by the backslash.
+% \item Otherwise, the command name consists only of that first character.
+%       Spaces following the name are not ignored, unless that character
+%       was itself a space character.
+% \end{itemize}
+%
+% Usually, digits are not considered to be letters.  However, the
+% \package{at} package will consider digits to be letters if you give it the
+% \textsf{digits} option in the |\usepackage| command.  (Note that this
+% only affects the \package{at} package; it won't change the characters
+% allowed in normal command names.)
+%
+% \DescribeMacro{\atallowdigits}
+% \DescribeMacro{\atdisallowdigits}
+% You can enable and disable digits being considered as letters dynamically.
+% The |\atallowdigits| command allows digits to be used as letters;
+% |\atdisallowdigits| prevents this.  Both declarations follow \LaTeX's
+% usual scoping rules.  Both of these commands have corresponding
+% environments with the same names (without the leading `|\|', obviously).
+%
+% \subsection{Defining @-commands}
+%
+% \DescribeMacro{\newatcommand}
+% \DescribeMacro{\renewatcommand}
+% The |\newatcommand| command will define a new @-command using a syntax
+% similar to |\newcommand|.  For example, you could define
+% \begin{listing}
+%\newatcommand c[1]{\chapter{#1}}
+% \end{listing}
+% to make @.{"@c{"<name>"}"} equivalent to @.{"\\chapter{"<name>"}"}.
+%
+% A |\renewatcommand| is also provided to redefine existing commands, should
+% the need arise.
+%
+% \DescribeMacro{\atdef}
+% For \TeX\ hackers, the |\atdef| command defines @-commands using a syntax
+% similar to \TeX's built-in |\def|.  
+%
+% As an example, the following command makes @.{"@/"<text>"/"} write its
+% argument \<text> in italics:
+% \begin{listing}
+%\atdef/#1/{\textit{#1}}
+% \end{listing}
+% The real implementation of the |@/|\dots|/| command is a bit more
+% complex, and is given in the next section.
+%
+% You can use all of \TeX's features for defining the syntax of your
+% command.  (See chapter~20 of @/The \TeX book/ for more details.)
+%
+% \DescribeMacro{\atlet}
+% Since |\atdef| is provided to behave similarly to |\def|, @at\ provides
+% |\atlet| which works similarly to |\let|.  For example you can say
+% \begin{listing}
+%\atlet!=\index
+% \end{listing}
+% to allow the short |@!| to behave exactly like |\index|.
+%
+% Note that all commands defined using these commands are robust even if you
+% use fragile commands in their definitions.  Unless you start doing very
+% strange things, @-commands never need |\protect|ing.
+%
+% \subsection{Predefined @-commands}
+%
+% A small number of hopefully useful commands are provided by default.
+% These are described in the table below:
+%
+% \bigskip \begin{center} \begin{tabular}{lp{3in}}                    \hline
+% \bf Command        & \bf Meaning                                 \\ \hline
+% @.{"@@"}           & Typesets an `@@' character.                 \\
+% @.{"@/"<text>"/"}  & In text (LR or paragraph) mode, typesets its
+%                      argument emphasised.  In maths mode, it
+%                      always chooses italics.                     \\
+% @.{"@*"<text>"*"}  & Typesets its argument \<text> in bold.      \\
+% @.{"@i{"<text>"}"} & Equivalent to `@.{"\\index{"<text>"}"}'.    \\
+% @.{"@I{"<text>"}"} & As for |@i|, but also writes its argument
+%                      to the document.                            \\ \hline
+% \end{tabular} \end{center} \bigskip
+%
+% Package writers should not rely on any predefined @-commands -- they're
+% provided for users, and users should be able to redefine them without
+% fear of messing anything up.  (This includes the `standard' commands
+% provided by the @at\ package, by the way.  They're provided in the vague
+% hope that they might be useful, and as examples.)
+%
+% \implementation
+%
+% \section{Implementation}
+%
+%    \begin{macrocode}
+%<*package>
+%    \end{macrocode}
+%
+% \subsection{Options handling}
+%
+% We need a switch to say whether digits should be allowed.  Since this
+% is a user thing, I'll avoid |\newif| and just define the thing by hand.
+%
+%    \begin{macrocode}
+\def\atallowdigits{\let\ifat@digits\iftrue}
+\def\atdisallowdigits{\let\ifat@digits\iffalse}
+%    \end{macrocode}
+%
+% Now define the options.
+%
+%    \begin{macrocode}
+\DeclareOption{digits}{\atallowdigits}
+\DeclareOption{nodigits}{\atdisallowdigits}
+\ExecuteOptions{nodigits}
+\ProcessOptions
+%    \end{macrocode}
+%
+% \subsection{How the commands work}
+%
+% Obviously we make the `@@' character active.  It inspects the next
+% character (or argument, actually -- it can be enclosed in braces for
+% longer commands, although this is a bit futile), and builds the command
+% name from that.
+%
+% The |\at| command is equivalent to the active `@@' character always.
+%
+%
+% \subsection{Converting command names}
+%
+% We need to be able to read an @-command name, and convert it to a normal
+% \TeX\ control sequence.  First, we declare some control sequences for
+% braces, which we need later.
+%
+%    \begin{macrocode}
+\begingroup
+\catcode`\<1
+\catcode`\>2
+\catcode`\{12
+\catcode`\}12
+\gdef\at@lb<{>
+\gdef\at@rb<}>
+\gdef\at@spc< >
+\endgroup
+%    \end{macrocode}
+%
+% I'll set up some helper routines now, to help me read the command
+% names.  The way this works is that we |\futurelet| the token into
+% |\@let@token|.  These routines will then sort out what to do next.
+%
+% \begin{macro}{\at@test}
+%
+% Given an |\if|\dots\ test, does its first or second argument.
+%
+%    \begin{macrocode}
+\def\at@test#1\then{%
+  #1\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\at@ifcat}
+%
+% Checks the category code of the current character.  If it matches the
+% argument, it does its second argument, otherwise it does the third.
+%
+%    \begin{macrocode}
+\def\at@ifcat#1{\at@test\ifcat#1\noexpand\@let@token\then}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\at@ifletter}
+%
+% This routine tests the token to see if it's a letter, and if so adds
+% it to the token list and does the first argument; otherwise it does the
+% second argument.  It accepts digits as letters if the switch is turned
+% on.
+%
+% There's some fun later, so I'll describe this slowly.  First, we compare
+% the category code to a letter, and if we have a match, we know we're done;
+% we need to pick up the letter as an argument.  If the catcode is `other',
+% we must compare with numbers to see if it's in range.
+%
+%    \begin{macrocode}
+\def\at@ifletter#1#2{%
+  \at@ifcat x%
+    {\at@ifletter@ii{#1}}%
+    {\at@ifcat 0%
+      {\at@ifletter@i{#1}{#2}}%
+      {#2}%
+    }% 
+}
+%    \end{macrocode}
+%
+% Right.  It's `other' (so it's safe to handle as a macro argument) and we
+% need to know if it's a digit.  This is a little tricky: I use |\if| to
+% compare two characters.  The first character is~`1' or~`0' depending on the
+% `digit' switch; the second is~`1' or~`x' depending on whether it's actually
+% a digit.  They'll only match if everything's worked out OK.
+%
+%    \begin{macrocode}
+\def\at@ifletter@i#1#2#3{%
+  \at@test\if%
+    \ifat@digits1\else0\fi%
+    \ifnum`#3<`0x\else\ifnum`#3>`9x\else1\fi\fi%
+  \then%
+    {\at@ifletter@ii{#1}{#3}}%
+    {#2#3}%
+}
+%    \end{macrocode}
+%
+% Right; we have the character, so add it to the list and carry on.
+%
+%    \begin{macrocode}
+\def\at@ifletter@ii#1#2{\toks@\expandafter{\the\toks@#2}#1}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% Now we define the command name reading routines.  We have @/almost/ the
+% same behaviour as \TeX, although we can't support `|%|' characters for
+% reasons to do with \TeX's tokenising algorithm.
+%
+% \begin{macro}{\at@read@name}
+%
+% The routine which actually reads the command name works as follows:
+% \begin{enumerate}
+% \item Have a peek at the next character.  If it's a left or right brace,
+%       then use the appropriate character.
+% \item If the character is not a letter, just use the character (or whole
+%       control sequence.
+% \item Finally, if it's a letter, keep reading letters until we find one
+%       that wasn't.
+% \end{enumerate}
+%
+% First, we do some setting up and read the first character
+%
+%    \begin{macrocode}
+\def\at@read@name#1{%
+  \let\at@next=#1%
+  \toks@{}%
+  \futurelet\@let@token\at@rn@i%
+}
+%    \end{macrocode}
+%
+% Next, sort out what to do, based on the category code.
+%
+%    \begin{macrocode}
+\def\at@rn@i{%
+  \def\@tempa{\afterassignment\at@rn@iv\let\@let@token= }%
+  \at@ifletter%
+    {\futurelet\@let@token\at@rn@iii}%
+    {\at@ifcat\bgroup%
+      {\toks@\expandafter{\at@lb}\@tempa}%
+      {\at@ifcat\egroup%
+        {\toks@\expandafter{\at@rb}\@tempa}%
+        {\at@ifcat\at@spc%
+          {\toks@{ }\@tempa}%
+          {\at@rn@ii}%
+        }%
+      }%
+    }%
+}
+%    \end{macrocode}
+%
+% Most types of tokens can be fiddled using |\string|.
+%
+%    \begin{macrocode}
+\def\at@rn@ii#1{%
+  \toks@\expandafter{\string#1}%
+  \at@rn@iv%
+}
+%    \end{macrocode}
+%
+% We've found a letter, so we should check for another one.
+%
+%    \begin{macrocode}
+\def\at@rn@iii{%
+  \at@ifletter%
+    {\futurelet\@let@token\at@rn@iii}%
+    {\@ifnextchar.\at@rn@iv\at@rn@iv}%
+}
+%    \end{macrocode}
+%
+% Finally, we need to pass the real string, as an argument, to the
+% macro.  We make |\@let@token| relax, since it might be something which will
+% upset \TeX\ later, e.g., a |#| character.
+%
+%    \begin{macrocode}
+\def\at@rn@iv{%
+  \let\@let@token\relax%
+  \expandafter\at@next\csname at.\the\toks@\endcsname%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\at@cmdname}
+%
+% Given a control sequence, work out which @-command it came from.
+%
+%    \begin{macrocode}
+\def\at@cmdname#1{\expandafter\at@cmdname@i\string#1\@@foo}
+%    \end{macrocode}
+%
+% Now extract the trailing bits.
+%
+%    \begin{macrocode}
+\def\at@cmdname@i#1.#2\@@foo{#2}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\at@decode}
+%
+% The |\at@decode| macro takes an extracted @-command name, and tries to
+% execute the correct control sequence derived from it.
+%
+%    \begin{macrocode}
+\def\at@decode#1{%
+  \at@test\ifx#1\relax\then{%
+    \PackageError{at}{Unknown @-command `@\at@cmdname#1'}{%
+      The @-command you typed wasn't recognised, so I've ignored it.
+    }%
+  }{%
+    #1%
+  }%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\@at}
+%
+% We'd like a measure of compatibility with @p{amsmath}.  The @-commands
+% provided by @p{amsmath} work only in maths mode, so this gives us a way of
+% distinguishing.  If the control sequence |\Iat| is defined, and we're in
+% maths mode, we'll call that instead of doing our own thing.
+%
+%    \begin{macrocode}
+\def\@at{%
+  \def\@tempa{\at@read@name\at@decode}%
+  \ifmmode\ifx\Iat\not@@defined\else%
+    \let\@tempa\Iat%
+  \fi\fi%
+  \@tempa%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+%
+% \subsection{Defining new commands}
+%
+% \begin{macro}{\at@buildcmd}
+%
+% First, we define a command to build these other commands:
+%
+%    \begin{macrocode}
+\def\at@buildcmd#1#2{%
+  \expandafter\def\csname\expandafter
+    \@gobble\string#1@decode\endcsname##1{#2##1}%
+  \edef#1{%
+    \noexpand\at@read@name%
+    \expandafter\noexpand%
+      \csname\expandafter\@gobble\string#1@decode\endcsname%
+  }%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\newatcommand}
+% \begin{macro}{\renewatcommand}
+% \begin{macro}{\provideatcommand}
+% \begin{macro}{\atdef}
+% \begin{macro}{\atshow}
+%
+% Now we define the various operations on @-commands.
+%
+%    \begin{macrocode}
+\at@buildcmd\newatcommand\newcommand
+\at@buildcmd\renewatcommand\renewcommand
+\at@buildcmd\provideatcommand\providecommand
+\at@buildcmd\atdef\def
+\at@buildcmd\atshow\show
+%    \end{macrocode}
+%
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\atlet}
+%
+% |\atlet| is rather harder than the others, because we want to allow people
+% to say things like @.{"\\atlet"<name>"=@"<name>}.  The following hacking
+% does the trick.  I'm trying very hard to duplicate |\let|'s behaviour with
+% respect to space tokens here, to avoid any surprises, although there
+% probably will be some differences.  In particular, |\afterassignment|
+% won't work in any sensible way.
+%
+% First, we read the name of the @-command we're defining.  We also open
+% a group, to stop messing other people up, and make `@@' into an `other'
+% token, so that it doesn't irritatingly look like its meaning as a control
+% sequence.
+%
+%    \begin{macrocode}
+\def\atlet{%
+  \begingroup%
+  \@makeother\@%
+  \at@read@name\atlet@i%
+}
+%    \end{macrocode}
+%
+% Put the name into a scratch macro for later use.  Now see if there's an
+% equals sign up ahead.  If not, this will gobble any spaces in between the
+% @-command name and the argument.
+%
+%    \begin{macrocode}
+\def\atlet@i#1{%
+  \def\at@temp{#1}%
+  \@ifnextchar=\atlet@ii{\atlet@ii=}%
+}
+%    \end{macrocode}
+%
+% Now we gobble the equals sign (whatever catcode it is), and peek at the
+% next token up ahead using |\let| with no following space.
+%
+%    \begin{macrocode}
+\def\atlet@ii#1{\afterassignment\atlet@iii\global\let\at@gnext=}
+%    \end{macrocode}
+%
+% The control sequence |\at@gnext| is now |\let| to be whatever we want the
+% @-command to be, unless it's picked up an `@@' sign.  If it has, we've
+% eaten the |@| token, so just read the name and pass it on.  Otherwise,
+% we can |\let| the @-command directly to |\at@gnext|.  There's some
+% nastiness here to make |\the\toks@| expand before we close the group and
+% restore its previous definition.
+%
+%    \begin{macrocode}
+\def\atlet@iii{%
+  \if @\noexpand\at@gnext%
+    \expandafter\at@read@name\expandafter\atlet@iv%
+  \else%
+    \expandafter\endgroup%
+    \expandafter\let\at@temp= \at@gnext%
+  \fi%
+}
+%    \end{macrocode}
+%
+% We've read the source @-command name, so just copy the definitions over.
+%
+%    \begin{macrocode}
+\def\atlet@iv#1{%
+  \expandafter\endgroup%
+  \expandafter\let\at@temp=#1%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+%
+% \subsection{Robustness of @-commands}
+%
+% We want all @-commands to be robust.  We could leave them all being
+% fragile, although making robust @-commands would then be almost impossible.
+% There are two problems which we must face:
+%
+% \begin{itemize}
+%
+% \item The `|\@at|' command which scans the @-command name is (very)
+%       fragile.  I could have used |\DeclareRobustCommand| for it (and in
+%       fact I did in an earlier version), but that doesn't help the other
+%       problem at all.
+%
+% \item The `name' of the @-command may contain active characters or control
+%       sequences, which will be expanded at the wrong time unless we do
+%       something about it now.
+%
+% \end{itemize}
+%
+% We must also be careful not to introduce extra space characters into any
+% files written, because spaces are significant in @-commands.  Finally,
+% we have a minor problem in that most auxiliary files are read in with
+% the `@@' character set to be a letter.
+%
+% \begin{macro}{\at}
+%
+% Following the example of \LaTeX's `short' command handling, we'll define
+% |\at| to decide what to do depending on what |\protect| looks like.  If
+% we're typesetting, we just call |\@at| (above) and expect it to cope.
+% Otherwise we call |\at@protect|, which scoops up the |\fi| and the |\@at|,
+% and inserts other magic.
+%
+%    \begin{macrocode}
+\def\at{\ifx\protect\@typeset@protect\else\at@protect\fi\@at}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\at@protect}
+%
+% Since we gobbled the |\fi| from the above, we must put that back.  We then 
+% need to do things which are more complicated.  If |\protect| is behaving 
+% like |\string|, then we do one sort of protection.  Otherwise, we assume
+% that |\protect| is being like |\noexpand|.
+%
+%    \begin{macrocode}
+\def\at@protect\fi#1{%
+  \fi%
+  \ifx\protect\string%
+    \expandafter\at@protect@string%
+  \else%
+    \expandafter\at@protect@noexpand%
+  \fi%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\at@protect@string}
+%
+% When |\protect| is |\string|, we don't need to be able to recover the
+% original text particularly accurately -- it's for the user to look at.
+% Therefore, we just output a $|@|_{11}$ and use |\string| on the next
+% token.  This must be sufficient, since we only allow multi-token command
+% names if the first token is a letter (code~11).
+%
+%    \begin{macrocode}
+\def\at@protect@string{@\string}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\at@protect@noexpand}
+%
+% This is a little more complex, since we're still expecting to be executed
+% properly at some stage.  However, there's a cheeky dodge we can employ
+% since the |\at| command is thoroughly robustified (or at least it will be
+% by the time we've finished this).  All |\@unexpandable@protect| does
+% is confer repeated robustness on a fragile command.  Since our command
+% is robust, we don't need this and we can get away with just using a
+% single |\noexpand|, both for the |\@at@| command and the following token
+% (which we must robustify, because no-one else can do it for us -- if
+% anyone tries, they end up using the |@\protect| command which is rather
+% embarassing).
+%
+% I'll give the definition, and then examine how this expands in various
+% cases.
+%
+%    \begin{macrocode}
+\def\at@protect@noexpand{\noexpand\@at@ @\noexpand}
+\def\@at@#1{\at}
+%    \end{macrocode}
+%
+% A few points, before we go into the main examination of the protection.
+% I've inserted a $|@|_{11}$ token, which is gobbled by |\@at@| when the
+% thing is finally expanded fully.  This prevents following space tokens
+% in an |\input| file from being swallowed because they follow a control
+% sequence.  (I can't use the normal $|@|_{13}$ token, because when files
+% like the |.aux| file are read in, |@| is given code~11 by
+% |\makeatletter|.)
+%
+% \setbox0\hbox{|@at@|}
+% Now for a description of why this works.  When |\at| is expanded, it works
+% out that |\protect| is either |\noexpand| or |\@unexpandable@protect|, and
+% becomes |\at@protect@noexpand|.  Because of the |\noexpand| tokens, this
+% stops being expanded once it reaches $\fbox{\box0}\,|@|_{11}\,x$ (where
+% $x$ is the token immediately following the $|@|_{13}$ character).  If this
+% is expanded again, for example in another |\edef|, or in a |\write| or a
+% |\mark|, the |\@at@| wakes up, gobbles the following |@| (whatever catcode
+% it is -- there may be intervening |\write| and |\input| commands) and
+% becomes |\at|, and the whole thing can start over again.
+%
+% \end{macro}
+%
+%
+% \subsection{Enabling and disabling @-commands}
+%
+% \begin{macro}{\aton}
+%
+% We define the |\aton| command to enable all of our magic.  We store
+% the old catcode in the |\atoff| command, make `@@' active, and make it
+% do the stuff.
+%
+%    \begin{macrocode}
+\def\aton{%
+  \ifnum\catcode`\@=\active\else%
+    \edef\atoff{\catcode`\noexpand\@\the\catcode`\@}%
+    \catcode`\@\active%
+    \lccode`\~`\@%
+    \lowercase{\let~\at}%
+  \fi%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\atoff}
+%
+% The |\atoff| command makes `@@' do the stuff it's meant to.  We remember
+% the old catcode and revert to it.  This is largely unnecessary.
+%
+%    \begin{macrocode}
+\def\atoff{\catcode`\@12}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\makeatother}
+%
+% Now we make our active `@@' the default outside of package files.
+%
+%    \begin{macrocode}
+\let\makeatother\aton
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% And we must make sure that the user can use all of our nice commands.
+% Once the document starts, we allow @-commands.
+%
+%    \begin{macrocode}
+\AtBeginDocument{\aton}
+%    \end{macrocode}
+%
+% \begin{macro}{\dospecials}
+% \begin{macro}{\@sanitize}
+%
+% We must add the `@@' character to the various specials lists.
+%
+%    \begin{macrocode}
+\expandafter\def\expandafter\dospecials\expandafter{\dospecials\do\@}
+\expandafter\def\expandafter\@sanitize\expandafter{%
+  \@sanitize\@makeother\@}
+%    \end{macrocode}
+%
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Default @-commands}
+%
+% We define some trivial examples to get the user going.
+%
+%    \begin{macrocode}
+\expandafter\chardef\csname at.@\endcsname=`\@
+\atdef*#1*{\ifmmode\mathbf{#1}\else\textbf{#1}\fi}
+\atdef/#1/{\ifmmode\mathit{#1}\else\emph{#1}\fi}
+\atlet i=\index
+\atdef I#1{#1\index{#1}}
+%</package>
+%    \end{macrocode}
+%
+% \hfill Mark Wooding, \today
+%
+% \Finale
+%
+\endinput

+ 523 - 0
docs/packages/mdwtools/cmtt.dtx

@@ -0,0 +1,523 @@
+% \begin{meta-comment}
+%
+% $Id$
+%
+% Nicer handling of the Computer Modern Typewriter font
+%
+% (c) 1996 Mark Wooding
+%
+%----- Revision history -----------------------------------------------------
+%
+% $Log$
+% Revision 1.1  1998-09-21 10:19:01  michael
+% Initial implementation
+%
+% Revision 1.1  1996/11/19 20:47:55  mdw
+% Initial revision
+%
+%
+% \end{meta-comment}
+%
+% \begin{meta-comment} <general public licence>
+%%
+%% mdwlist package -- various list-related things
+%% Copyright (c) 1996 Mark Wooding
+%%
+%% This program is free software; you can redistribute it and/or modify
+%% it under the terms of the GNU General Public License as published by
+%% the Free Software Foundation; either version 2 of the License, or
+%% (at your option) any later version.
+%%
+%% This program is distributed in the hope that it will be useful,
+%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+%% GNU General Public License for more details.
+%%
+%% You should have received a copy of the GNU General Public License
+%% along with this program; if not, write to the Free Software
+%% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+%%
+% \end{meta-comment}
+%
+%
+% \begin{meta-comment} <Package preambles>
+%<+sty>\NeedsTeXFormat{LaTeX2e}
+%<+sty>\ProvidesPackage{cmtt}
+%<+fd>\ProvidesFile{mTTcmtt.fd}
+%<+def>\ProvidesFile{mTTcmtt.def}
+%<+sty|fd|def>         [1996/05/25 1.1 Handing of the cmtt font]
+% \end{meta-comment}
+%
+% ^^A \CheckSum{174}
+%% \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{cmtt}
+\mdwdoc
+%</driver>
+%
+% \end{meta-comment}
+%
+%^^A-------------------------------------------------------------------------
+% \section{Introductory note}
+%
+% \LaTeX\ has a rather cunning encoding handling system, which makes funny
+% commands like accents work properly independent of the current font's
+% actual layout.  While this works rather well most of the time, the standard
+% \mtt{tt} font has been rather left out of things.  \LaTeX\ assumes that
+% the Computer Modern Typewriter fonts have exactly the same layout as the
+% more normal Computer Modern Roman family (i.e., that both conform to the
+% \mtt{OT1} encoding).  This plainly isn't true, since the Typewriter font
+% contains a bunch of standard ASCII characters which are omitted from the
+% standard Computer Modern fonts, such as curly braces \mtt{\{} and \mtt{\}},
+% and the backslash \mtt{\\}; these are usually dug up from the maths fonts,
+% which looks fine in normal text, but looks really odd in monospace text.
+% Compare `\texttt{\textbackslash begin\{document\}}' to
+% `\mtt{\\begin\{document\}}', for example.
+%
+% There are two possibilities for dealing with this problem.  One is to use
+% the \mtt{\\verb} command, which works since all the extra characters in
+% the Typewriter font are in the correct places, or use the DC~fonts, which
+% have a proper encoding set up which contains all of these special
+% characters anyway.
+%
+% Neither of these solutions is perfect.  Using \mtt{\\verb} causes all
+% manner of little niggly problems: you can't use it in footnotes or
+% section headings, for example.  (There are of course workarounds for this
+% sort of thing: the author's \package{footnote} package provides a
+% \env{footnote} environment which will allow verbatim text, and verbatim
+% text in section headings can be achieved if one is sufficiently
+% \TeX nical.)  Using the DC~fonts is fine, although you actually lose a
+% glyph or two.  As far as the author is aware, the character \mtt{\'} (an
+% `unsexed' single quote) is not present in the \mtt{T1}-encoded version of
+% Computer Modern Typewriter, although it is hidden away in the original
+% version.  The author has found a need for this character in computer
+% listings, and was horrified to discover that it was replaced by a German
+% single quote character (\mtt{\\quotesinglbase}).
+%
+% This package defines a special encoding for the Computer Modern Typewriter
+% font, so that documents can take advantage of its ASCII characters without
+% resorting to verbatim text.  (The main advantage of the DC~fonts, that
+% words containing accents can be hyohenated, doesn't really apply to the
+% Typewriter font, since it doesn't allow hyphenation by default anyway.)
+%
+% There are several files you'll need to create:
+% \begin{description} \def\makelabel#1{\hskip\labelsep\mttfamily#1\hfil}
+%
+% \item [cmtt.sty] tells \LaTeX\ that there's a new encoding.  It also
+%       provides some options for customising some aspects of the
+%       encoding, and defines some useful commands.
+%
+% \item [mTTenc.def] describes the encoding to \LaTeX: it sets up all the
+%       appropriate text commands so that they produce beautiful results.
+%
+% \item [mTTcmtt.fd] describes the re-encoded version of the font.  This
+%       is more or less a copy of the file \mtt{OT1cmtt.fd}.
+%
+% \end{description}
+%
+% The package accepts some options which may be useful:
+% \begin{description} \def\makelabel#1{\hskip\labelsep\sffamily#1\hfil}
+%
+% \item [override] overrides the meaning of the \mtt{\\ttfamily} command
+%       (and therefore also the \mtt{\\texttt} command too), making it the
+%       same as the new \mtt{\\mttfamily} command.  This isn't the default
+%       just in case the change breaks something in an unexpected way.
+%
+% \item [t1] informs the package that you're using the \mtt{T1} encoding,
+%       and therefore can borrow some accented characters from the DC~version
+%       of Computer Modern Typewriter.  This will probably be unnecessary,
+%       since the package attempts to work out what to do all by itself.
+%
+% \item [ot1] forces the package \emph{not} to use the DC~version of the
+%       Computer Modern Typewriter font for funny accents.  Only use this
+%       option if the package thinks it should use the DC~Typewriter font
+%       when it shouldn't.
+%
+% \end{description}
+%
+% \DescribeMacro{\mttfamily}
+% The command \mtt{\\mttfamily} selects the properly-encoded Typewriter
+% font.  It's a declaration which works just like the \mtt{\\ttfamily}
+% command, except that comamnds like \mtt{\\\}} and \mtt{\\\_} use the
+% characters from the font rather than choosing odd-looking versions from
+% the maths fonts.  All of the accent commands still work properly.  In fact,
+% some accent commands which didn't work before have been fixed.  For
+% example, saying `\mtt{\\texttt\{P\\'al Erd\\H os\}}' would produce
+% something truly appalling like `\texttt{P\'al Erd\H os}', which is
+% obviously ghastly.  The new encoding handles this properly, and produces
+% `\textmtt{P\'al Erd\H os}'.\footnote{
+%   This isn't quite perfect.  The accent, which isn't actually present in
+%   the Typewriter font, is taken from the Computer Modern bold font, but
+%   it doesn't look too bad.  However, if you pass the option \textsf{t1}
+%   to the \package{cmtt} package when you load it, the accent will be taken
+%   from the DC~Typewriter font, and it will look totally wonderful.}
+%
+% \DescribeMacro{\textmtt}
+% Font changing commands are much more convenient than th declarations,
+% so a command \mtt{\\textmtt} is provided: it just typesets its argument
+% in the re-encoded Typewriter font.
+%
+% \DescribeMacro{\mtt}
+% Rather more excitingly, the \mtt{\\mtt} command allows you to generate
+% almost-verbatim text very easily, without any of the restrictions of
+% the \mtt{\\verb} command.  This command was inspired by something which
+% David Carlisle said to me in an email correspondence regarding the
+% overuse of verbatim commands.
+%
+% \mtt{\\mtt} redefines several `short' commands to typeset the obvious
+% characters.  The complete list is shown below: there are some oddities,
+% so watch out.
+%
+% ^^A This is an evil table.  See if I care.  (This is based on lots of
+% ^^A hacking I did in glyphs.tex, but a good deal less horrible.)
+%
+% \medskip
+% \hbox to \hsize\bgroup
+% \hfil\vbox\bgroup
+% \def\ex#1#2{\strut
+%   \enskip
+%   \mtt{\\\char`#2}\quad\hfil%
+%   \mtt{#2}\enskip}
+% \def\h{\noalign{\hrule}}
+% \def\v{height2pt&\omit&&\omit&&\omit&&\omit&&\omit&\cr}
+% \let~\relax
+% \offinterlineskip
+% \ialign\bgroup&\vrule#&\ex#\cr        \h\v
+% &~\\&&~\{&&~\}&&~\_&&~\^&\cr        \v\h\v
+% &~\$&&~\%&&~\&&&~\#&&~\~&\cr        \v\h\v
+% &~\"&&~\'&&~\ &&~\|&&\omit\hfil&\cr \v\h
+% \egroup\egroup
+% \hfil\egroup
+% \medskip
+%
+% As well as redefining these commands, \mtt{\\mtt} will endeavour to make
+% single special characters display themselves in a verbatim-like way.  This
+% only works on `active' characters (like \mtt{~}), and \mtt{\\mtt} makes
+% no attempt to change the category codes of any characters.
+%
+% Among other things, you'll probably noticed that several accent-making
+% commands have been redefined.  You can still use these accents through
+% the \mtt{\\a} command, by saying \mtt{\\a'}, \mtt{\\a\^} and so on,
+% as in the \env{tabbing} environment.
+%
+% There are also some oddities in the table: \mtt{\|} and \mtt{\"} can be
+% accessed easily without playing with silly commands.  Well, that's almost
+% the case: these two characters are both often used as `short' verbatim
+% commands, so they are forced back to their normal meanings so you can
+% type them.
+%
+% Finally, a word on spacing.  The \mtt{\\\ } command has been hijacked
+% to produce a funny `visible space' character.  You can still produce
+% multiple spaces by saying something like `\mtt{\ \{\}\ \{\}}\dots\mtt{\ }',
+% which is a bit contrived, but that's tough.  Also, \mtt{~} has been stolen
+% so that you can type \mtt{~} characters (e.g., in URLs), so the only
+% way you can tpye a nonbreaking space is by using the \mtt{\\nobreakspace}
+% command, which is a bit of a mouthful.  There's an abbreviation, though:
+% \mtt{\\nbsp} now means exactly the same thing.
+%
+% Was that not all supremely useful?  Oh, just a note: this document doesn't
+% use a single verbatim command or environment (except in the listings,
+% where it's unavoidable) -- it's all done with \mtt{\\mtt}.
+%
+% \implementation
+%
+% \section{Implementation}
+%
+% \subsection{The package}
+%
+%    \begin{macrocode}
+%<*sty>
+%    \end{macrocode}
+%
+% I'll start with some options handling.
+%
+%    \begin{macrocode}
+\newif\ifcmtt@override
+\newif\ifcmtt@dcfonts
+\def\@tempa{T1}\ifx\encodingdefault\@tempa
+  \cmtt@dcfontstrue
+\fi
+\DeclareOption{override}{\cmtt@overridetrue}
+\DeclareOption{t1}{\cmtt@dcfontstrue}
+\DeclareOption{ot1}{\cmtt@dcfontsfalse}
+\ProcessOptions
+%    \end{macrocode}
+%
+% This bit is really trivial.  I'll just declare the font encoding.  Oh, that
+% was easy.
+%
+%    \begin{macrocode}
+\DeclareFontEncoding{mTT}{}{}
+%    \end{macrocode}
+%
+% Wait: there's a problem.  \LaTeX\ will now complain bitterly that it can't
+% find the font \mtt{mTT/cmr/m/n}, which is readonable, since I haven't
+% declared any such font.  The following line should sort this out,
+%
+%    \begin{macrocode}
+\DeclareFontSubstitution{mTT}{cmtt}{m}{n}
+%    \end{macrocode}
+%
+% Now I'd better load all the text commands I'll need when in this funny
+% font variant.
+%
+%    \begin{macrocode}
+\input{mTTenc.def}
+%    \end{macrocode}
+%
+% \begin{macro}{\mttfamily}
+% \begin{macro}{\textmtt}
+%
+% Finally, I'll need to define a command which switches to this funny font,
+% and a \mtt{\\text}\dots\ command for it.
+%
+%    \begin{macrocode}
+\DeclareRobustCommand{\mttfamily}{%
+  \fontencoding{mTT}\fontfamily{\ttdefault}\selectfont%
+}
+\DeclareTextFontCommand{\textmtt}{\mttfamily}
+%    \end{macrocode}
+%
+% \end{macro}
+% \end{macro}
+%
+% If an override was requested, make \mtt{\\ttfamily} the same as
+% \mtt{\\mttfamily}.
+%
+%    \begin{macrocode}
+\ifcmtt@override
+  \let\ttfamily\mttfamily
+\fi
+%    \end{macrocode}
+%
+% Well, that's all that's needed for the font definition.  Here's a command
+% which will typeset its argument in the typewriter font, allowing easy
+% access to all the funny characters, and printing them properly in the
+% correct font (which \mtt{\\\{} doesn't do, for example).
+%
+% \begin{macro}{\mtt@setchar}
+%
+% This macro assigns the given meaning to the given control sequence.  Also,
+% if the character named in the control sequence is currently set active,
+% it will set the active meaning of the character to the same value.
+%
+%    \begin{macrocode}
+\def\mtt@setchar#1#2{%
+  \ifx#1#2\chardef#1`#1\else\let#1#2\fi%
+  \ifnum\catcode`#1=13%
+    \begingroup%
+      \lccode`\~=`#1%
+    \lowercase{\endgroup\let~#1}%
+  \fi%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\mtt@chars}
+%
+% This macro lists the various control sequences which should be set up,
+% so that they can be easily added to.
+%
+%    \begin{macrocode}
+\def\mtt@chars{%
+  \do\#\#%
+  \do\%\%%
+  \do\&\&% 
+  \do\^\^%
+  \do\~\~%
+  \do\'\textquotesingl%
+  \do\"\textquotedbl%
+  \do\|\textbar%
+  \do\$\textdollar%
+  \do\_\textunderscore%
+  \do\{\textbraceleft%
+  \do\}\textbraceright%
+  \do\\\textbackslash%
+  \do\ \textvisiblespace%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\mtt@do}
+%
+% This just sets up all the special characters listed above.  It's a simple
+% abbreviation, really.
+%
+%    \begin{macrocode}
+\def\mtt@do{\let\do\mtt@setchar\mtt@chars}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\mtt}
+%
+% And finally, the macro itself.  Ta-da!
+%
+%    \begin{macrocode}
+\DeclareRobustCommand\mtt[1]{\textmtt{\mtt@do#1}}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\@tabacckludge}
+%
+% The otherwise almost totally perfect \mtt{\\@tabacckludge} gets very
+% upset when its argument is an active character.  (If you're wondering,
+% this is the command which is responsible for the behaviour of the \mtt{\\a}
+% command.)  Adding a \mtt{\\string} makes everything work perfectly.
+%
+%    \begin{macrocode}
+\def\@tabacckludge#1{%
+  \expandafter\@changed@cmd\csname\string#1\endcsname\relax%
+}
+\let\a\@tabacckludge
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\nbsp}
+%
+% Make an abbreviation for \mtt{\\nobreakspace}.
+%
+%    \begin{macrocode}
+\let\nbsp\nobreakspace
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% I think that's all that I have to do for the package.  If there's any
+% more to do, I'll add it later.
+%
+%    \begin{macrocode}
+%</sty>
+%    \end{macrocode}
+%
+%
+% \subsection{The font definition file}
+%
+% This is obviously copied almost verbatim from the file \mtt{OT1cmtt.fd}.
+%
+%    \begin{macrocode}
+%<*fd>
+\DeclareFontFamily{mTT}{cmtt}{\hyphenchar\font\m@ne}
+\DeclareFontShape{mTT}{cmtt}{m}{n}{
+  <5> <6> <7> <8> cmtt8
+  <9> cmtt9
+  <10> <10.95> cmtt10
+  <12> <14.4> <17.28> <20.74> <24.88> cmtt12
+}{}
+\DeclareFontShape{mTT}{cmtt}{m}{it}{
+  <5> <6> <7> <8> <9> <10> <10.95> <12> <14.4> <17.28> <20.74> <24.88>
+  cmitt10
+}{}
+\DeclareFontShape{mTT}{cmtt}{m}{sl}{
+  <5> <6> <7> <8> <9> <10> <10.95> <12> <14.4> <17.28> <20.74> <24.88>
+  cmsltt10
+}{}
+\DeclareFontShape{mTT}{cmtt}{m}{sc}{
+  <5> <6> <7> <8> <9> <10> <10.95> <12> <14.4> <17.28> <20.74> <24.88>
+  cmtcsc10
+}{}
+\DeclareFontShape{mTT}{cmtt}{m}{ui}  {<->sub * cmtt/m/it} {}
+\DeclareFontShape{mTT}{cmtt}{bx}{n}  {<->sub * cmtt/m/n}  {}
+\DeclareFontShape{mTT}{cmtt}{bx}{it} {<->sub * cmtt/m/it} {}
+\DeclareFontShape{mTT}{cmtt}{bx}{ui} {<->sub * cmtt/m/it} {}
+%</fd>
+%    \end{macrocode}
+%
+%
+% \subsection{The encoding definitions file}
+%
+% I've saved the trickiest bit until last.  This file defines the mappings
+% from text commands to glyphs in the font.
+%
+%    \begin{macrocode}
+%<*def>
+%    \end{macrocode}
+%
+% First for some fun with accents.  The |cmtt| font doesn't contain all of
+% the accents which the other Computer Modern fonts do, because those slots
+% contain the standard ASCII characters which usually have to be `borrowed'
+% from the maths fonts.
+%
+% Anyway, there's a load which don't need any special treatment.  These are
+% chosen from the \mtt{OT1} encoding by default anyway, so I needn't
+% bother unless I'm really bothered about speed.  I'm not, so I'll save
+% the memory.
+%
+% Following the example of the \TeX book, I'll use the bold roman font
+% for accents, so that they don't look really spindly.  This is actually
+% remarkably difficult to do, because the \textsf{NFSS} keeps getting in
+% the way.  I'll look after the old font name in a macro (it's handy that
+% \textsf{NFSS} maintains this for me) and change to a known font, do the
+% accent, change font back again, do the argument to the accent, and then
+% close the group I did all of this in, so that no-one else notices what a
+% naughty chap I am, really.  This is startlingly evil.
+%
+%    \begin{macrocode}
+\def\cmtt@accent#1#2{{%
+  \let\@old@font\font@name%
+  \ifcmtt@dcfonts%
+    \fontencoding{T1}\selectfont%
+  \else%
+    \usefont{OT1}{cmr}{bx}{n}%
+  \fi%
+  #1{\@old@font#2}%
+}}
+%    \end{macrocode}
+%
+% And now for the actual offending accents.
+%
+%    \begin{macrocode}
+\DeclareTextCommand{\H}{mTT}{\cmtt@accent\H}
+\DeclareTextCommand{\.}{mTT}{\cmtt@accent\.}
+%    \end{macrocode}
+%
+% The `under' accents are all OK, so I shan't bother to define them either.
+% Similarly, lots of the text symbol commands are fine as they are by
+% default and I don't need to try and define them again.
+%
+% This, then, is the remaining commands which really need sorting out.
+% (By the way, the only reason I've redefined \mtt{\\textellipsis} is
+% because otherwise it will mess up the nice monospacing.)
+%
+%    \begin{macrocode}
+\DeclareTextSymbol{\textbackslash}{mTT}{92}
+\DeclareTextSymbol{\textbar}{mTT}{124}
+\DeclareTextSymbol{\textbraceleft}{mTT}{123}
+\DeclareTextSymbol{\textbraceright}{mTT}{125}
+\DeclareTextSymbol{\textless}{mTT}{60}
+\DeclareTextSymbol{\textgreater}{mTT}{62}
+\DeclareTextSymbol{\textunderscore}{mTT}{95}
+\DeclareTextSymbol{\textvisiblespace}{mTT}{32}
+\DeclareTextCommand{\textellipsis}{mTT}{...}
+\DeclareTextSymbol{\textquotedbl}{mTT}{34}
+\DeclareTextSymbol{\textquotesingl}{mTT}{13}
+%    \end{macrocode}
+%
+% That's all there is.  Please return to your homes.
+%
+% \Finale
+%
+\endinput

+ 519 - 0
docs/packages/mdwtools/doafter.dtx

@@ -0,0 +1,519 @@
+% \begin{meta-comment}
+%
+% $Id$
+%
+% Insert tokens to be read after a group has been processed
+%
+% (c) 1996 Peter Schmitt and Mark Wooding
+%
+%----- Revision history -----------------------------------------------------
+%
+% $Log$
+% Revision 1.1  1998-09-21 10:19:01  michael
+% Initial implementation
+%
+% Revision 1.2  1996/11/19 20:49:08  mdw
+% Entered into RCS
+%
+%
+% \end{meta-comment}
+%
+% \begin{meta-comment} <general public licence>
+%%
+%% doafter package -- insert a token really after a group
+%% Copyright (c) 1996 Peter Schmitt and Mark Wooding
+%<*package>
+%%
+%% This program is free software; you can redistribute it and/or modify
+%% it under the terms of the GNU General Public License as published by
+%% the Free Software Foundation; either version 2 of the License, or
+%% (at your option) any later version.
+%%
+%% This program is distributed in the hope that it will be useful,
+%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+%% GNU General Public License for more details.
+%%
+%% You should have received a copy of the GNU General Public License
+%% along with this program; if not, write to the Free Software
+%% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+%</package>
+%%
+% \end{meta-comment}
+%
+% \begin{meta-comment} <Package preamble>
+%<+latex2e>\NeedsTeXFormat{LaTeX2e}
+%<+latex2e>\ProvidesPackage{doafter}
+%<+latex2e>                [1996/05/08 1.2 Aftergroup hacking (PS/MDW)]
+% \end{meta-comment}
+%
+% \CheckSum{259}
+%\iffalse
+%<*package>
+%\fi
+%% \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         \~}
+%%
+%\iffalse
+%</package>
+%\fi
+%
+% \begin{meta-comment} <driver>
+%
+%<*driver>
+\input{mdwtools}
+\describespackage{doafter}
+\author{Peter Schmitt\thanks{%
+  Peter came up with the basic implementation after I posed the problem
+  in the \texttt{comp.text.tex} newsgroup.  I fixed some really piddly little
+  things, to improve it a bit, wrote the documentation, and turned the code
+  into a nice \package{doc}ced package.  Then Peter gave me an updated
+  version, and I upgraded this from memory.  Then he gave me some more tweaks
+  which I haven't incorporated.}
+  \and Mark Wooding}
+\def\author#1{}
+\mdwdoc
+%</driver>
+%
+% \end{meta-comment}
+%
+% \section{Description}
+%
+% \subsection{What it's all about}
+%
+% \DescribeMacro{\doafter}
+% It's common for the \TeX\ primitive |\aftergroup| to be used to `tidy up'
+% after a group.  For example, \LaTeX's colour handling uses this to insert
+% appropriate |\special|s when the scope of a colour change ends.  This
+% causes several problems, though; for example, extra grouping must be added
+% within boxes to ensure that the |\special|s don't `leak' out of their box
+% and appear in odd places in the document.  \LaTeX\ usually solves this
+% problem by reading the box contents as an argument, although this isn't
+% particularly desirable.  The |\doafter| macro provided here will solve the
+% problem in a different way, by allowing a macro to regain control after
+% all the |\aftergroup| things have been processed.
+%
+% The macro works like this:
+% \begin{grammar}
+% <doafter-cmd> ::= \[[
+%   "\\doafter" <token> <group>
+% \]]
+% \end{grammar}
+% The \<token> can be any token you like, except an explicit braces, since
+% it's read as an undelimited macro argument.  The \<group> is a normal
+% \TeX\ group, surrounded by either implicit or explicit braces, or by
+% |\begingroup| and |\endgroup| tokens.  Once the final closing token of the
+% \<group> is read, and any tokens saved up by |\aftergroup| have been
+% processed, the \<token> is inserted and processed.  Under normal
+% circumstances, this will be a macro.
+%
+% There are some subtle problems with the current implementation, which you
+% may need to be aware of:
+%
+% \begin{itemize}
+%
+% \item Since we're inserting things after all the |\aftergroup| tokens,
+%       those tokens might read something they're not expecting if they try
+%       to look ahead at the text after the group (e.g., with |\futurelet|).
+%       This is obviously totally unavoidable.
+%
+% \item Implicit braces (like |\bgroup| and |\egroup|) inserted using
+%       |\aftergroup| may be turned into \emph{explicit} $|{|_1$ and $|}|_2$
+%       characters within a |\doafter| group.  This can cause probems under
+%       very specialised circumstances.  The names |\bgroup| and |\egroup|
+%       are treated specially, and they will work normally (remaining as
+%       implicit braces).  This should minimise problems caused by this
+%       slight difference.  (This only applies to the last |\aftergroup|
+%       token in a group.)
+%
+% \item To handle the |\aftergroup| tokens properly, |\doafter| has to insert
+%       some |\aftergroup| tokens of its own.  It will then process the
+%       other tokens some more, and set them up to be read again.  This does
+%       mean that after the group ends, some assignments and other `stomach
+%       operations' will be performed, which may cause problems in
+%       alignments and similar places.
+%
+% \end{itemize}
+%
+%
+% \subsection{Package options}
+%
+% There are a fair few \textsf{docstrip} options provided by this packge:
+%
+% \begin{description}
+% \item [driver] extracts the documentation driver.  This isn't usually
+%       necessary.
+% \item [package] extracts the code as a standalone package, formatted for
+%       either \LaTeXe\ or Plain~\TeX.
+% \item [latex2e] inserts extra identification code for a \LaTeXe\ package.
+% \item [plain] inserts some extra code for a Plain \TeX\ package.
+% \item [macro] just extracts the raw code, for inclusion in another package.
+% \item [test] extracts some code for testing the current implementation.
+% \end{description}
+%
+%
+% \implementation
+%
+% \section{Implementation}
+%
+% \subsection{The main macro}
+%
+% We start outputting code here.  If this is a Plain~\TeX\ package, we must
+% make \lit{@} into a letter.
+%
+%    \begin{macrocode}
+%<*macro|package>
+%<+plain>\catcode`\@=11
+%    \end{macrocode}
+%
+% \begin{macro}{\doafter}
+%
+% The idea is to say \syntax{"\\doafter" <token> <group>} and expect the
+% \synt{token} to be processed after the group has finished its stuff,
+% even if it contains |\aftergroup| things.  My eternal gratitude goes to
+% Peter Schmitt, who came up with most of the solution implemented here;
+% I've just tidied up some very minor niggles and things later.
+%
+% Let's start with some preamble.  I'll save the (hopefully) primitive
+% |\aftergroup| in a different token.
+%
+%    \begin{macrocode}
+\let\@@aftergroup\aftergroup
+%    \end{macrocode}
+%
+% Now to define the `user' interface.  It takes a normal undelimited
+% argument, although this must be a single token; otherwise eveything will
+% go wrong.  It assumes that the token following is some kind of group
+% opening thing (an explicit or implicit character with catcode~1, or
+% a |\begingroup| token).  To make this work, I'll save the token,
+% together with an |\@@aftergroup| (to save an |\expandafter| later) in
+% a temporary macro which no-one will mind me using, and then look ahead at
+% the beginning-group token.
+%
+%    \begin{macrocode}
+\def\doafter#1{%
+  \def\@tempa{\@@aftergroup#1}%
+  \afterassignment\doafter@i\let\@let@token%
+}
+%    \end{macrocode}
+%
+% I now have the token in |\@let@token|, so I'll put that in.  I'll then
+% make |\aftergroup| do my thing rather than the normal thing, and queue
+% the tokens |\@prepare@after| and the |\doafter| argument for later use.
+%
+%    \begin{macrocode}
+\def\doafter@i{%
+  \@let@token%
+  \let\aftergroup\@my@aftergroup%
+  \@@aftergroup\@prepare@after\@tempa%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\@my@aftergroup}
+%
+% Now the cleverness begins.  We keep two macros (Peter's original used
+% count registers) which keep counts of the numbers of |\aftergroup|s,
+% both locally and globally.  Let's call the local counter~$n$ and the
+% global one $N$.  Every time we get a call to our |\aftergroup| hack,
+% we set~$n := n+1$ and~$N := n$, and leave the token given to us for later
+% processing.  When we actually process an |\aftergroup| token properly,
+% set~$N := N-1$ to indicate that it's been handled; when they're all done,
+% we'll have $N=n$, which is exactly what we'd have if there weren't any
+% to begin with.
+%
+%    \begin{macrocode}
+\def\ag@cnt@local{0 }
+\let\ag@cnt@global\ag@cnt@local
+%    \end{macrocode}
+%
+% Now we come to the definition of my version of |\aftergroup|.  I'll just
+% add the token |\@after@token| before every |\aftergroup| token I find.
+% This means there's two calls to |\aftergroup| for every one the user makes,
+% but these things aren't all that common, so it's OK really.  I'll also
+% bump the local counter, and synchronise them.
+%
+%    \begin{macrocode}
+\def\@my@aftergroup{%
+  \begingroup%
+    \count@\ag@cnt@local%
+    \advance\count@\@ne%
+    \xdef\ag@cnt@global{\the\count@\space}%
+  \endgroup%
+  \let\ag@cnt@local\ag@cnt@global%
+  \@@aftergroup\@after@token\@@aftergroup%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% Now what does |\@after@token| we inserted above actually do?  Well, this
+% is more exciting.  There are actually two different variants of the
+% macro, which are used at different times.
+%
+% \begin{macro}{\@after@token}
+%
+% The default |\@after@token| starts a group, which will `catch'
+% |\aftergroup| tokens which I throw at it.  I put the two counters into
+% some scratch count registers.  (There's a slight problem here: Plain \TeX\
+% only gives us one.  For the sake of evilness I'll use |\clubpenalty| as the
+% other one.  Eeeek.)  I then redefine |\@after@token| to the second
+% variant, and execute it.  The |\@start@after@group| macro starts the
+% group, because this code is shared with |\@prepare@after| below.
+%
+%    \begin{macrocode}
+\def\@after@token{%
+  \@start@after@group%
+  \@after@token%
+}
+\def\@start@after@group{%
+  \begingroup%
+  \count@\ag@cnt@global%
+  \clubpenalty\ag@cnt@local%
+  \let\@after@token\@after@token@i%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\@after@token@i}
+%
+% I have $|\count@| = N$ and $|\@tempcnta| = n$.  I'll decrement~$N$,
+% and if I have $N = n$, I know that this is the last token to do, so I
+% must insert an |\@after@all| after the token.  This will close the group,
+% and maybe insert the original |\doafter| token if appropriate.
+%
+%    \begin{macrocode}
+\def\@after@token@i{%
+  \advance\count@\m@ne%
+  \ifnum\count@=\clubpenalty%
+    \global\let\ag@cnt@global\ag@cnt@local%
+    \expandafter\@after@aftertoken\expandafter\@after@all%
+  \else%
+    \expandafter\@@aftergroup%
+  \fi%
+}
+%    \end{macrocode}
+%
+% Finally, establish a default meaning for |\@after@all|.
+%
+%    \begin{macrocode}
+\let\@after@all\endgroup
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\@prepare@after}
+%
+% If this group is handled by |\doafter|, then the first |\aftergroup| token
+% isn't |\@after@token|; it's |\@prepare@after|.
+%
+% There are some extra cases to deal with:
+% \begin{itemize}
+% \item If $N=n$ then there were no |\aftergroup| tokens, so we have an easy
+%       job.  I'll just let the token do its stuff directly.
+% \item Otherwise, $N>n$, and there are |\aftergroup| tokens.  I'll open
+%       the group, and let |\@after@token| do all the handling.
+% \end{itemize}
+%
+%    \begin{macrocode}
+\def\@prepare@after{%
+  \ifx\ag@cnt@local\ag@cnt@global\else%
+    \expandafter\@prepare@after@i%
+  \fi%
+}
+\def\@prepare@after@i#1{%
+  \@start@after@group%
+  \def\@after@all{\@@aftergroup#1\endgroup}%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\@after@aftertoken}
+%
+% This is where all the difficulty lies.  The next token in the stream is
+% an |\aftergroup| one, which could be more or less anything.  We have an
+% argument, which is some code to do \emph{after} the token has been
+% |\aftergroup|ed.
+%
+% If the token is anything other than a brace (i.e., an  explicit character
+% of category~1 or~2) then I have no problem; I can scoop up the token with
+% an undelimited macro argument.  But the only way I can decide if this token
+% is a brace (nondestructively) is with |\futurelet|, which makes the token
+% implicit, so I can't decide whether it's really dangerous.
+%
+% There is a possible way of doing this\footnote{Due to Peter Schmitt,
+% again.} which relates to nobbling the offending token with |\string| and
+% sifting through the results.  The problem here involves scooping up all the
+% tokens of a |\string|ed control sequence, which may turn out to be
+% `|\csname\endcsname|' or something equally horrid.
+%
+% The solution I've used is much simpler: I'll change |\bgroup| and |\egroup|
+% to stop them from being implicit braces before comparing.
+%
+%    \begin{macrocode}
+\def\@after@aftertoken#1{%
+  \let\bgroup\relax\let\egroup\relax%
+  \toks@{#1}%
+  \futurelet\@let@token\@after@aftertoken@i%
+}
+\def\@after@aftertoken@i{%
+  \ifcat\noexpand\@let@token{%
+    \@@aftergroup{%
+  \else\ifcat\noexpand\@let@token}%
+    \@@aftergroup}%
+  \else%
+    \def\@tempa##1{\@@aftergroup##1\the\toks@}%
+    \expandafter\expandafter\expandafter\@tempa%
+  \fi\fi%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+%
+% Phew!
+%
+%    \begin{macrocode}
+%<+plain>\catcode`\@=12
+%</macro|package>
+%    \end{macrocode}
+%
+% \subsection{Test code}
+%
+% The following code gives |\doafter| a bit of a testing.  It's based on
+% the test suite I gave to comp.text.tex, although it's been improved a
+% little since then.
+%
+% The first thing to do is define a control sequence with an \lit{@} sign
+% in its name, so we can test catcode changes.  This also hides an
+% |\aftergroup| within a macro, making life more difficult for prospective
+% implementations.
+%
+%    \begin{macrocode}
+%<*test>
+\catcode`\@=11
+\def\at@name{\aftergroup\saynine}
+\def\saynine{\say{ix}}
+\catcode`\@=12
+%    \end{macrocode}
+%
+% Now define a command to write a string to the terminal.  The name will
+% probably be familiar to REXX hackers.
+%
+%    \begin{macrocode}
+\def\say{\immediate\write16}
+%    \end{macrocode}
+%
+% Test one: This is really easy; it just tests that the thing works at all.
+% If your implementation fails this, it's time for a major rethink.
+%
+%    \begin{macrocode}
+\say{Test one... (1--2)}
+\def\saytwo{\say{ii}}
+\doafter\saytwo{\say{i}}
+%    \end{macrocode}
+%
+% Test two: Does |\aftergroup| work?
+%
+%    \begin{macrocode}
+\say{Test two... (1--4)}
+\def\saythree{\say{iii}}
+\def\sayfour{\say{iv}}
+\doafter\sayfour{\say{i}\aftergroup\saythree\say{ii}}
+%    \end{macrocode}
+%
+% Test three: Test braces and |\iffalse| working as they should.  Several
+% proposed solutions based on |\write|ing the group to a file get upset by
+% this test, although I forgot to include it in the torture test.  It also
+% tests whether literal braces can be |\aftergroup|ed properly.  (Added a new
+% test here, making sure that |\bgroup| is left as an implicit token.)
+%
+%    \begin{macrocode}
+\say{Test three... (1--4, `\string\bgroup', 5)}
+\def\sayfive{\say{v}}
+\doafter\sayfive{%
+  \say{i}%
+  \aftergroup\say%
+  \aftergroup{%
+  \aftergroup\romannumeral\aftergroup3%
+  \aftergroup}%
+  \iffalse}\fi%
+  \aftergroup\def%
+  \aftergroup\sayfouretc%
+  \aftergroup{%
+  \aftergroup\say%
+  \aftergroup{%
+  \aftergroup i%
+  \aftergroup v%
+  \aftergroup}%
+  \aftergroup\say%
+  \aftergroup{%
+  \aftergroup\string%
+  \aftergroup\bgroup%
+  \aftergroup}%
+  \aftergroup}%
+  \aftergroup\sayfouretc%
+  \say{ii}%
+}
+%    \end{macrocode}
+%
+% Test four: Make sure the implementation isn't leaking things.  This just
+% makes sure that |\aftergroup| is its normal reasonable self.
+%
+%    \begin{macrocode}
+\say{Test four... (1--3)}
+{\say{i}\aftergroup\saythree\say{ii}}
+%    \end{macrocode}
+%
+% Test five: Nesting, aftergroup, catcodes, grouping.  This is the `torture'
+% test I gave to comp.text.tex, slightly corrected (oops) and amended.  It
+% ensures that nested groups and |\doafter|s work properly (the latter is
+% actually more likely than might be imagined).
+%
+%    \begin{macrocode}
+\say{Test five... (1--14)}
+\def\sayten{\say{x}}
+\def\saythirteen{\say{xiii}}
+\def\sayfourteen{\say{xiv}}
+\doafter\sayfourteen\begingroup%
+  \say{i}%
+  {\say{ii}\aftergroup\sayfour\say{iii}}%
+  \def\saynum{\say{viii}}%
+  \doafter\sayten{%
+    \say{v}%
+    \def\saynum{\say{vii}}%
+    \catcode`\@=11%
+    \aftergroup\saynum%
+    \say{vi}%
+    \at@name%
+    \saynum%
+  }%
+  \say{xi}%
+  \aftergroup\saythirteen%
+  \say{xii}%
+\endgroup
+\end
+%</test>
+%    \end{macrocode}
+%
+% That's it.  All present and correct.
+%
+% \Finale
+%
+\endinput

+ 702 - 0
docs/packages/mdwtools/footnote.dtx

@@ -0,0 +1,702 @@
+% \begin{meta-comment}
+%
+% $Id$
+%
+% Save footnotes around boxing environments and things
+%
+% (c) 1996 Mark Wooding
+%
+%----- Revision history -----------------------------------------------------
+%
+% $Log$
+% Revision 1.1  1998-09-21 10:19:01  michael
+% Initial implementation
+%
+% Revision 1.13  1997/01/28 19:45:16  mdw
+% Fixed stupid bug in AMS environment handling which stops the thing from
+% working properly if you haven't included amsmath.  Doh.
+%
+% Revision 1.12  1997/01/18 00:45:37  mdw
+% Fix problems with duplicated footnotes in broken AMS environments which
+% typeset things multiple times.  This is a nasty kludge.
+%
+% Revision 1.11  1996/11/19 20:50:05  mdw
+% Entered into RCS
+%
+%
+% \end{meta-comment}
+%
+% \begin{meta-comment} <general public licence>
+%%
+%% footnote package -- Save footnotes around boxing environments
+%% Copyright (c) 1996 Mark Wooding
+%<*package>
+%%
+%% This program is free software; you can redistribute it and/or modify
+%% it under the terms of the GNU General Public License as published by
+%% the Free Software Foundation; either version 2 of the License, or
+%% (at your option) any later version.
+%%
+%% This program is distributed in the hope that it will be useful,
+%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+%% GNU General Public License for more details.
+%%
+%% You should have received a copy of the GNU General Public License
+%% along with this program; if not, write to the Free Software
+%% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+%</package>
+%%
+% \end{meta-comment}
+%
+% \begin{meta-comment} <Package preamble>
+%<+package>\NeedsTeXFormat{LaTeX2e}
+%<+package>\ProvidesPackage{footnote}
+%<+package>                [1997/01/28 1.13 Save footnotes around boxes]
+% \end{meta-comment}
+%
+% \CheckSum{327}
+%\iffalse
+%<*package>
+%\fi
+%% \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         \~}
+%%
+%\iffalse
+%</package>
+%\fi
+%
+% \begin{meta-comment} <driver>
+%
+%<*driver>
+\input{mdwtools}
+\describespackage{footnote}
+\mdwdoc
+%</driver>
+%
+% \end{meta-comment}
+%
+% \section{User guide}
+%
+% This package provides some commands for handling footnotes slightly
+% better than \LaTeX\ usually does; there are several commands and
+% environments (notably |\parbox|, \env{minipage} and \env{tabular}
+% \begin{footnote}
+%   The \package{mdwtab} package, provided in this distribution, handles
+%   footnotes correctly anyway; it uses an internal version of this package
+%   to do so.
+% \end{footnote})
+% which `trap' footnotes so that they can't escape and appear at the bottom
+% of the page.
+%
+% \DescribeEnv{savenotes}
+% The \env{savenotes} environment saves up any footnotes encountered within
+% it, and performs them all at the end.
+%
+% \DescribeMacro{\savenotes}
+% \DescribeMacro{\spewnotes}
+% If you're defining a command or environment, you can use the |\savenotes|
+% command to start saving up footnotes, and the |\spewnotes| command to
+% execute them all at the end.  Note that |\savenotes| and |\spewnotes|
+% enclose a group, so watch out.  You can safely nest the commands and
+% environments -- they work out if they're already working and behave
+% appropriately.
+%
+% \DescribeEnv{minipage*}
+% To help things along a bit, the package provides a $*$-version of the
+% \env{minipage} environment, which doesn't trap footnotes for itself (and
+% in fact sends any footnotes it contains to the bottom of the page, where
+% they belong).
+%
+% \DescribeMacro{\makesavenoteenv}
+% The new \env{minipage$*$} environment was created with a magic command
+% called |\makesavenoteenv|.  It has a fairly simple syntax:
+%
+% \begin{grammar}
+% <make-save-note-env-cmd> ::= \[[
+%   "\\makesavenoteenv"
+%   \begin{stack} \\ "[" <new-env-name> "]" \end{stack}
+%   "{" <env-name> "}"
+% \]]
+% \end{grammar}
+%
+% Without the optional argument, it redefines the named environment so that
+% it handles footnotes correctly.  With the optional argument, it makes
+% the new environment named by \<new-env-name> into a footnote-friendly
+% version of the \<env-name> environment.
+%
+% \DescribeMacro{\parbox}
+% The package also redefines the |\parbox| command so that it works properly
+% with footnotes.
+%
+% \DescribeEnv{footnote}
+% The other problem which people tend to experience with footnotes is that
+% you can't put verbatim text (with the |\verb| comamnd or the \env{verbatim}
+% environment) into the |\footnote| command's argument.  This package
+% provides a \env{footnote} \emph{environment}, which \emph{does} allow
+% verbatim things.  You use the environment just like you do the command.
+% It's really easy.  It even has an optional argument, which works the same
+% way.
+%
+% \DescribeEnv{footnotetext}
+% To go with the \env{footnote} environment, there's a \env{footnotetext}
+% environment, which just puts the text in the bottom of the page, like
+% |\footnotetext| does.
+%
+% There's a snag with these environments, though.  Some other nonstandard
+% environments, like \env{tabularx}, try to handle footnotes their own
+% way, because they won't work otherwise.  The way they do this is not
+% compatible with the way that the \env{footnote} and \env{footnotetext}
+% environments work, and you will get strange results if you try (there'll
+% be odd vertical spacing, and the footnote text may well be incorrect).
+% \begin{footnote}
+%   The solution to this problem is to send mail to David Carlisle persuading
+%   him to use this package to handle footnotes, rather than doing it his
+%   way.
+% \end{footnote}
+%
+% \implementation
+%
+% \section{Implementation}
+%
+% Most implementations of footnote-saving (in particular, that used in
+% the \package{tabularx} and \package{longtable} packages) use a token
+% list register to store the footnote text, and then expand it when whatever
+% was preventing footnotes (usually a vbox) stops.  This is no good at all
+% if the footnotes contain things which might not be there by the time the
+% expansion occurs.  For example, references to things in temporary boxes
+% won't work.
+%
+% This implementation therefore stores the footnotes up in a box register.
+% This must be just as valid as using tokens, because all I'm going to do
+% at the end is unbox the box).
+%
+%    \begin{macrocode}
+%<*macro|package>
+\ifx\fn@notes\@@undefined%
+  \newbox\fn@notes%
+\fi
+%    \end{macrocode}
+%
+% I'll need a length to tell me how wide the footnotes should be at the
+% moment.
+%
+%    \begin{macrocode}
+\newdimen\fn@width
+%    \end{macrocode}
+%
+% Of course, I can't set this up until I actually start saving footnotes.
+% Until then I'll use |\columnwidth| (which works in \package{multicol}
+% even though it doesn't have any right to).
+%
+%    \begin{macrocode}
+\let\fn@colwidth\columnwidth
+%    \end{macrocode}
+%
+% And now a switch to remember if we're already handling footnotes,
+%
+%    \begin{macrocode}
+\newif\if@savingnotes
+%    \end{macrocode}
+%
+%
+% \subsection{Building footnote text}
+%
+% I need to emulate \LaTeX's footnote handling when I'm putting the notes
+% into my box; this is also useful in the verbatim-in-footnotes stuff.
+%
+% \begin{macro}{\fn@startnote}
+%
+% Here's how a footnote gets started.  Most of the code here is stolen
+% from |\@footnotetext|.
+%
+%    \begin{macrocode}
+\def\fn@startnote{%
+  \hsize\fn@colwidth%
+  \interlinepenalty\interfootnotelinepenalty%
+  \reset@font\footnotesize%
+  \floatingpenalty\@MM% Is this right???
+  \@parboxrestore%
+  \protected@edef\@currentlabel{\csname p@\@mpfn\endcsname\@thefnmark}%
+  \color@begingroup%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\fn@endnote}
+%
+% Footnotes are finished off by this macro.  This is the easy bit.
+%
+%    \begin{macrocode}
+\let\fn@endnote\color@endgroup
+%    \end{macrocode}
+%
+% \end{macro}
+%
+%
+% \subsection{Footnote saving}
+%
+% \begin{macro}{\fn@fntext}
+%
+% Now to define how to actually do footnotes.  I'll just add the notes to
+% the bottom of the footnote box I'm building.
+%
+% There's some hacking added here to handle the case that a footnote is
+% in an |\intertext| command within a broken \package{amsmath} alignment
+% environment -- otherwise the footnotes get duplicated due to the way that
+% that package measures equations.
+% \begin{footnote}
+%   The correct solution of course is to
+%   implement aligning environments in a sensible way, by building the table
+%   and leaving penalties describing the intended format, and then pick that
+%   apart in a postprocessing phase.  If I get the time, I'll start working
+%   on this again.  I have a design worked out and the beginnings of an
+%   implementation, but it's going to be a long time coming.
+% \end{footnote}
+%
+%    \begin{macrocode}
+\def\fn@fntext#1{%
+  \ifx\ifmeasuring@\@@undefined%
+    \expandafter\@secondoftwo\else\expandafter\@iden%
+  \fi%
+  {\ifmeasuring@\expandafter\@gobble\else\expandafter\@iden\fi}%
+  {%
+    \global\setbox\fn@notes\vbox{%
+      \unvbox\fn@notes%
+      \fn@startnote%
+      \@makefntext{%
+        \rule\z@\footnotesep%
+        \ignorespaces%
+        #1%
+        \@finalstrut\strutbox%
+      }%
+      \fn@endnote%
+    }%
+  }%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\savenotes}
+%
+% The |\savenotes| declaration starts saving footnotes, to be spewed at a
+% later date.  We'll also remember which counter we're meant to use, and
+% redefine the footnotes used by minipages.
+%
+% The idea here is that we'll gather up footnotes within the environment,
+% and output them in whatever format they were being typeset outside the
+% environment.
+%
+% I'll take this a bit at a time.  The start is easy: we need a group in
+% which to keep our local definitions.
+%
+%    \begin{macrocode}
+\def\savenotes{%
+  \begingroup%
+%    \end{macrocode}
+%
+% Now, if I'm already saving footnotes away, I won't bother doing anything
+% here.  Otherwise I need to start hacking, and set the switch.
+%
+%    \begin{macrocode}
+  \if@savingnotes\else%
+    \@savingnotestrue%
+%    \end{macrocode}
+%
+% I redefine the |\@footnotetext| command, which is responsible for adding
+% a footnote to the appropriate insert.  I'll redefine both the current
+% version, and \env{minipage}'s specific version, in case there's a nested
+% minipage.
+%
+%    \begin{macrocode}
+    \let\@footnotetext\fn@fntext%
+    \let\@mpfootnotetext\fn@fntext%
+%    \end{macrocode}
+%
+% I'd better make sure my box is empty before I start, and I must set up
+% the column width so that later changes (e.g., in \env{minipage}) don't
+% upset things too much.
+%
+%    \begin{macrocode}
+    \fn@width\columnwidth%
+    \let\fn@colwidth\fn@width%
+    \global\setbox\fn@notes\box\voidb@x%
+%    \end{macrocode}
+%
+% Now for some yuckiness.  I want to ensure that \env{minipage} doesn't
+% change how footnotes are handled once I've taken charge.  I'll store the
+% current values of |\thempfn| (which typesets a footnote marker) and
+% |\@mpfn| (which contains the name of the current footnote counter).
+%
+%    \begin{macrocode}
+    \let\fn@thempfn\thempfn%
+    \let\fn@mpfn\@mpfn%
+%    \end{macrocode}
+%
+% The \env{minipage} environment provides a hook, called |\@minipagerestore|.
+% Initially it's set to |\relax|, which is unfortunately unexpandable, so if
+% I want to add code to it, I must check this possibility.  I'll make it
+% |\@empty| (which expands to nothing) if it's still |\relax|.  Then I'll
+% add my code to the hook, to override |\thempfn| and |\@mpfn| set up by
+% \env{minipage}.
+%
+% Note that I can't just force the |mpfootnote| counter to be equal to
+% the |footnote| one, because \env{minipage} clears |\c@mpfootnote| to zero
+% when it starts.  This method will ensure that even so, the current counter
+% works OK.
+%
+%    \begin{macrocode}
+    \ifx\@minipagerestore\relax\let\@minipagerestore\@empty\fi%
+    \expandafter\def\expandafter\@minipagerestore\expandafter{%
+      \@minipagerestore%
+      \let\thempfn\fn@thempfn%
+      \let\@mpfn\fn@mpfn%
+    }%
+  \fi%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\spewnotes}
+%
+% Now I can spew out the notes we saved.  This is a bit messy, actually.
+% Since the standard |\@footnotetext| implementation tries to insert funny
+% struts and things, I must be a bit careful.  I'll disable all this bits
+% which start paragraphs prematurely.
+%
+%    \begin{macrocode}
+\def\spewnotes{%
+  \endgroup%
+  \if@savingnotes\else\ifvoid\fn@notes\else\begingroup%
+    \let\@makefntext\@empty%
+    \let\@finalstrut\@gobble%
+    \let\rule\@gobbletwo%
+    \@footnotetext{\unvbox\fn@notes}%
+  \endgroup\fi\fi%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% Now make an environment, for users.
+%
+%    \begin{macrocode}
+\let\endsavenotes\spewnotes
+%    \end{macrocode}
+%
+% That's all that needs to be in the shared code section.
+%
+%    \begin{macrocode}
+%</macro|package>
+%<*package>
+%    \end{macrocode}
+%
+%
+% \subsection{The \env{footnote} environment}
+%
+% Since |\footnote| is a command with an argument, things like \env{verbatim}
+% are unwelcome in it.  Every so often someone on |comp.text.tex| moans
+% about it and I post a nasty hack to make it work.  However, as a more
+% permanent and `official' solution, here's an environment which does the
+% job rather better.  Lots of this is based on code from my latest attempt
+% on the newsgroup.
+%
+% I'll work on this in a funny order, although I think it's easier to
+% understand.  First, I'll do some macros for reading the optional argument
+% of footnote-related commands.
+%
+% \begin{macro}{\fn@getmark}
+%
+% Saying \syntax{"\\fn@getmark{"<default-code>"}{"<cont-code>"}"} will read
+% an optional argument giving a value for the footnote counter; if the
+% argument isn't there, the \<default-code> is executed, and it's expected
+% to set up the appropriate counter to the current value.  The footnote
+% marker text is stored in the macro |\@thefnmark|, as is conventional for
+% \LaTeX's footnote handling macros.  Once this is done properly, the
+% \<cont-code> is called to continue handling things.
+%
+% Since the handling of the optional argument plays with the footnote
+% counter locally, I'll start a group right now to save some code.  Then I'll
+% decide what to do based on the presence of the argument.
+%
+%    \begin{macrocode}
+\def\fn@getmark#1#2{%
+  \begingroup%
+  \@ifnextchar[%
+    {\fn@getmark@i{#1}}%
+    {#1\fn@getmark@ii{#2}}%
+}
+%    \end{macrocode}
+%
+% There's an optional argument, so I need to read it and assign it to the
+% footnote counter.
+%
+%    \begin{macrocode}
+\def\fn@getmark@i#1[#2]{%
+  \csname c@\@mpfn\endcsname#2%
+  \fn@getmark@ii%
+}
+%    \end{macrocode}
+%
+% Finally, set up the macro properly, and end the group.
+%
+%    \begin{macrocode}
+\def\fn@getmark@ii#1{%
+  \unrestored@protected@xdef\@thefnmark{\thempfn}%
+  \endgroup%
+  #1%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% From argument reading, I'll move on to footnote typesetting.
+%
+% \begin{macro}{\fn@startfntext}
+%
+% The |\fn@startfntext| macro sets everything up for building the footnote
+% in a box register, ready for unboxing into the footnotes insert.  The
+% |\fn@prefntext| macro is a style hook I'll set up later.
+%
+%    \begin{macrocode}
+\def\fn@startfntext{%
+  \setbox\z@\vbox\bgroup%
+    \fn@startnote%
+    \fn@prefntext%
+    \rule\z@\footnotesep%
+    \ignorespaces%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\fn@endfntext}
+%
+% Now I'll end the vbox, and add it to the footnote insertion.  Again, I
+% must be careful to prevent |\@footnotetext| from adding horizontal mode
+% things in bad places.
+%
+%    \begin{macrocode}
+\def\fn@endfntext{%
+    \@finalstrut\strutbox%
+    \fn@postfntext%
+  \egroup%
+  \begingroup%
+    \let\@makefntext\@empty%
+    \let\@finalstrut\@gobble%
+    \let\rule\@gobbletwo%
+    \@footnotetext{\unvbox\z@}%
+  \endgroup%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{environment}{footnote}
+%
+% I can now start on the environment proper.  First I'll look for an
+% optional argument.
+%
+%    \begin{listing}
+%\def\footnote{%
+%    \end{listing}
+%
+% Oh.  I've already come up against the first problem: that name's already
+% used.  I'd better save the original version.
+%
+%    \begin{macrocode}
+\let\fn@latex@@footnote\footnote
+%    \end{macrocode}
+%
+% The best way I can think of for seeing if I'm in an environment is to
+% look at |\@currenvir|.  I'll need something to compare with, then.
+%
+%    \begin{macrocode}
+\def\fn@footnote{footnote}
+%    \end{macrocode}
+%
+% Now to start properly.  |;-)|
+%
+%    \begin{macrocode}
+\def\footnote{%
+  \ifx\@currenvir\fn@footnote%
+    \expandafter\@firstoftwo%
+  \else%
+    \expandafter\@secondoftwo%
+  \fi%
+  {\fn@getmark{\stepcounter\@mpfn}%
+              {\leavevmode\unskip\@footnotemark\fn@startfntext}}%
+  {\fn@latex@@footnote}%
+}
+%    \end{macrocode}
+%
+% Ending the environment is simple.
+%
+%    \begin{macrocode}
+\let\endfootnote\fn@endfntext
+%    \end{macrocode}
+%
+% \end{environment}
+%
+% \begin{environment}{footnotetext}
+%
+% I'll do the same magic as before for |\footnotetext|.
+%
+%    \begin{macrocode}
+\def\fn@footnotetext{footnotetext}
+\let\fn@latex@@footnotetext\footnotetext
+\def\footnotetext{%
+  \ifx\@currenvir\fn@footnotetext%
+    \expandafter\@firstoftwo%
+  \else%
+    \expandafter\@secondoftwo%
+  \fi%
+  {\fn@getmark{}\fn@startfntext}%
+  {\fn@latex@@footnotetext}%
+}
+\let\endfootnotetext\endfootnote
+%    \end{macrocode}
+%
+% \end{environment}
+%
+% \begin{macro}{\fn@prefntext}
+% \begin{macro}{\fn@postfntext}
+%
+% Now for one final problem.  The style hook for footnotes is the command
+% |\@makefntext|, which takes the footnote text as its argument.  Clearly
+% this is utterly unsuitable, so I need to split it into two bits, where
+% the argument is.  This is very tricky, and doesn't deserve to work,
+% although it appears to be a good deal more effective than it has any right
+% to be.
+%
+%    \begin{macrocode}
+\long\def\@tempa#1\@@#2\@@@{\def\fn@prefntext{#1}\def\fn@postfntext{#2}}
+\expandafter\@tempa\@makefntext\@@\@@@
+%    \end{macrocode}
+%
+% \end{macro}
+% \end{macro}
+%
+%
+% \subsection{Hacking existing environments}
+%
+% Some existing \LaTeX\ environments ought to have footnote handling but
+% don't.  Now's our chance.
+%
+% \begin{macro}{\makesavenoteenv}
+%
+% The |\makesavenoteenv| command makes an environment save footnotes around
+% itself.
+%
+% It would also be nice to make |\parbox| work with footnotes.  I'll do this
+% later.
+%
+%    \begin{macrocode}
+\def\makesavenoteenv{\@ifnextchar[\fn@msne@ii\fn@msne@i}
+%    \end{macrocode}
+%
+% We're meant to redefine the environment.  We'll copy it (using |\let|) to
+% a magic name, and then pass it on to stage~2.
+%
+%    \begin{macrocode}
+\def\fn@msne@i#1{%
+  \expandafter\let\csname msne$#1\expandafter\endcsname%
+                  \csname #1\endcsname%
+  \expandafter\let\csname endmsne$#1\expandafter\endcsname%
+                  \csname end#1\endcsname%
+  \fn@msne@ii[#1]{msne$#1}%
+}
+%    \end{macrocode}
+%
+% Now we'll define the new environment.  The start is really easy, since we
+% just need to insert a |\savenotes|.  The end is more complex, since we
+% need to preserve the |\if@endpe| flag so that |\end| can pick it up.  I
+% reckon that proper hooks should be added to |\begin| and |\end| so that
+% environments can define things to be done outside the main group as
+% well as within it; still, we can't all have what we want, can we?
+%
+%    \begin{macrocode}
+\def\fn@msne@ii[#1]#2{%
+  \expandafter\edef\csname#1\endcsname{%
+    \noexpand\savenotes%
+    \expandafter\noexpand\csname#2\endcsname%
+  }%
+  \expandafter\edef\csname end#1\endcsname{%
+    \expandafter\noexpand\csname end#2\endcsname%
+    \noexpand\expandafter%
+    \noexpand\spewnotes%
+    \noexpand\if@endpe\noexpand\@endpetrue\noexpand\fi%
+  }%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{environment}{minipage*}
+%
+% Let's define a \env{minipage$*$} environment which handles footnotes
+% nicely.  Really easy:
+%
+%    \begin{macrocode}
+\makesavenoteenv[minipage*]{minipage}
+%    \end{macrocode}
+%
+% \end{environment}
+%
+% \begin{macro}{\parbox}
+%
+% Now to alter |\parbox| slightly, so that it handles footnotes properly.
+% I'm going to do this fairly inefficiently, because I'm going to try and
+% change it as little as possible.
+%
+% First, I'll save the old |\parbox| command.  If I don't find a \lit{*},
+% I'll just call this command.
+%
+%    \begin{macrocode}
+\let\fn@parbox\parbox
+%    \end{macrocode}
+%
+% This is the clever bit: I don't know how many optional arguments
+% Mr~Mittelbach and his chums will add to |\parbox|, so I'll handle any
+% number.  I'll store them all up in my first argument and call myself
+% every time I find a new one.  If I run out of optional arguments,
+% I'll call the original |\parbox| command, surrounding it with |\savenotes|
+% and |\spewnotes|.
+%
+%    \begin{macrocode}
+\def\parbox{\@ifnextchar[{\fn@parbox@i{}}{\fn@parbox@ii{}}}
+\def\fn@parbox@i#1[#2]{%
+  \@ifnextchar[{\fn@parbox@i{#1[#2]}}{\fn@parbox@ii{#1[#2]}}%
+}
+\long\def\fn@parbox@ii#1#2#3{\savenotes\fn@parbox#1{#2}{#3}\spewnotes}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% Done!
+%
+%    \begin{macrocode}
+%</package>
+%    \end{macrocode}
+%
+% \hfill Mark Wooding, \today
+%
+% \Finale
+%
+\endinput

+ 447 - 0
docs/packages/mdwtools/gpl.tex

@@ -0,0 +1,447 @@
+% \iffalse <meta-comment>
+%
+% $Id$
+%
+% The GNU General Public Licence as a LaTeX section
+%
+% (c) 1989, 1991 Free Software Foundation, Inc.
+%   LaTeX markup and minor formatting changes by Mark Wooding
+%
+
+%----- Revision history -----------------------------------------------------
+%
+% $Log$
+% Revision 1.1  1998-09-21 10:19:01  michael
+% Initial implementation
+%
+% Revision 1.1  1996/11/19 20:51:14  mdw
+% Initial revision
+%
+
+% --- Chapter heading ---
+%
+% We don't know whether this ought to be a section or a chapter.  Easy.
+% We'll see if chapters are possible.
+%
+% \fi
+
+\begingroup
+\makeatletter
+
+\edef\next#1#2#3{\relax
+  \ifx\chapter\@@undefined
+    \ifx\documentclass\@notprerr#2\else#3\fi
+  \else#1\fi
+}
+
+\expandafter\endgroup\next
+{
+  \let\gpltoplevel\chapter
+  \let\gplsec\section
+  \let\gplend\endinput
+}{
+  \let\gpltoplevel\section
+  \let\gplsec\subsection
+  \let\gplend\endinput
+}{
+  \documentclass[a4paper]{article}
+  \def\gpltoplevel#1{%
+    \vspace*{1in}%
+    \hbox to\hsize{\hfil\LARGE\bfseries#1\hfil}%
+    \vspace{1in}%
+  }
+  \let\gplsec\section
+  \def\gplend{\end{document}}
+  \advance\textwidth1in
+  \advance\oddsidemargin-.5in
+  \sloppy
+  \begin{document}
+}
+
+%^^A-------------------------------------------------------------------------
+\gpltoplevel{The GNU General Public Licence}
+
+
+The following is the text of the GNU General Public Licence, under the terms
+of which this software is distrubuted.
+
+\vspace{12pt}
+
+\begin{center}
+\textbf{GNU GENERAL PUBLIC LICENSE} \\
+Version 2, June 1991
+\end{center}
+
+\begin{center}
+Copyright (C) 1989, 1991 Free Software Foundation, Inc. \\
+675 Mass Ave, Cambridge, MA 02139, USA
+
+Everyone is permitted to copy and distribute verbatim copies \\
+of this license document, but changing it is not allowed.
+\end{center}
+
+
+\gplsec{Preamble}
+
+The licenses for most software are designed to take away your freedom to
+share and change it.  By contrast, the GNU General Public License is intended
+to guarantee your freedom to share and change free software---to make sure
+the software is free for all its users.  This General Public License applies
+to most of the Free Software Foundation's software and to any other program
+whose authors commit to using it.  (Some other Free Software Foundation
+software is covered by the GNU Library General Public License instead.)  You
+can apply it to your programs, too.
+
+When we speak of free software, we are referring to freedom, not price.  Our
+General Public Licenses are designed to make sure that you have the freedom
+to distribute copies of free software (and charge for this service if you
+wish), that you receive source code or can get it if you want it, that you
+can change the software or use pieces of it in new free programs; and that
+you know you can do these things.
+
+To protect your rights, we need to make restrictions that forbid anyone to
+deny you these rights or to ask you to surrender the rights.  These
+restrictions translate to certain responsibilities for you if you distribute
+copies of the software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether gratis or
+for a fee, you must give the recipients all the rights that you have.  You
+must make sure that they, too, receive or can get the source code.  And you
+must show them these terms so they know their rights.
+
+We protect your rights with two steps: (1) copyright the software, and (2)
+offer you this license which gives you legal permission to copy, distribute
+and/or modify the software.
+
+Also, for each author's protection and ours, we want to make certain that
+everyone understands that there is no warranty for this free software.  If
+the software is modified by someone else and passed on, we want its
+recipients to know that what they have is not the original, so that any
+problems introduced by others will not reflect on the original authors'
+reputations.
+
+Finally, any free program is threatened constantly by software patents.  We
+wish to avoid the danger that redistributors of a free program will
+individually obtain patent licenses, in effect making the program
+proprietary.  To prevent this, we have made it clear that any patent must be
+licensed for everyone's free use or not licensed at all.
+
+The precise terms and conditions for copying, distribution and modification
+follow.
+
+
+\gplsec{Terms and conditions for copying, distribution and modification}
+
+\begin{enumerate}
+
+\makeatletter \setcounter{\@listctr}{-1} \makeatother
+
+\item [0.] This License applies to any program or other work which contains a
+      notice placed by the copyright holder saying it may be distributed
+      under the terms of this General Public License.  The ``Program'',
+      below, refers to any such program or work, and a ``work based on the
+      Program'' means either the Program or any derivative work under
+      copyright law: that is to say, a work containing the Program or a
+      portion of it, either verbatim or with modifications and/or translated
+      into another language.  (Hereinafter, translation is included without
+      limitation in the term ``modification''.)  Each licensee is addressed
+      as ``you''.
+
+      Activities other than copying, distribution and modification are not
+      covered by this License; they are outside its scope.  The act of
+      running the Program is not restricted, and the output from the Program
+      is covered only if its contents constitute a work based on the Program
+      (independent of having been made by running the Program).  Whether that
+      is true depends on what the Program does.
+
+\item [1.] You may copy and distribute verbatim copies of the Program's
+      source code as you receive it, in any medium, provided that you
+      conspicuously and appropriately publish on each copy an appropriate
+      copyright notice and disclaimer of warranty; keep intact all the
+      notices that refer to this License and to the absence of any warranty;
+      and give any other recipients of the Program a copy of this License
+      along with the Program.
+
+      You may charge a fee for the physical act of transferring a copy, and
+      you may at your option offer warranty protection in exchange for a fee.
+
+\item [2.] You may modify your copy or copies of the Program or any portion
+      of it, thus forming a work based on the Program, and copy and
+      distribute such modifications or work under the terms of Section 1
+      above, provided that you also meet all of these conditions:
+
+      \begin{enumerate}
+
+      \item [(a)] You must cause the modified files to carry prominent
+            notices stating that you changed the files and the date of any
+            change.
+
+      \item [(b)] You must cause any work that you distribute or publish,
+            that in whole or in part contains or is derived from the Program
+            or any part thereof, to be licensed as a whole at no charge to
+            all third parties under the terms of this License.
+
+      \item [(c)] If the modified program normally reads commands
+            interactively when run, you must cause it, when started running
+            for such interactive use in the most ordinary way, to print or
+            display an announcement including an appropriate copyright notice
+            and a notice that there is no warranty (or else, saying that you
+            provide a warranty) and that users may redistribute the program
+            under these conditions, and telling the user how to view a copy
+            of this License.  (Exception: if the Program itself is
+            interactive but does not normally print such an announcement,
+            your work based on the Program is not required to print an
+            announcement.)
+
+      \end{enumerate}
+
+      These requirements apply to the modified work as a whole.  If
+      identifiable sections of that work are not derived from the Program,
+      and can be reasonably considered independent and separate works in
+      themselves, then this License, and its terms, do not apply to those
+      sections when you distribute them as separate works.  But when you
+      distribute the same sections as part of a whole which is a work based
+      on the Program, the distribution of the whole must be on the terms of
+      this License, whose permissions for other licensees extend to the
+      entire whole, and thus to each and every part regardless of who wrote
+      it.
+
+      Thus, it is not the intent of this section to claim rights or contest
+      your rights to work written entirely by you; rather, the intent is to
+      exercise the right to control the distribution of derivative or
+      collective works based on the Program.
+
+      In addition, mere aggregation of another work not based on the Program
+      with the Program (or with a work based on the Program) on a volume of a
+      storage or distribution medium does not bring the other work under the
+      scope of this License.
+
+\item [3.] You may copy and distribute the Program (or a work based on it,
+      under Section 2) in object code or executable form under the terms of
+      Sections 1 and 2 above provided that you also do one of the following:
+
+      \begin{enumerate}
+
+      \item [(a)] Accompany it with the complete corresponding
+            machine-readable source code, which must be distributed under the
+            terms of Sections 1 and 2 above on a medium customarily used for
+            software interchange; or,
+
+      \item [(b)] Accompany it with a written offer, valid for at least three
+            years, to give any third party, for a charge no more than your
+            cost of physically performing source distribution, a complete
+            machine-readable copy of the corresponding source code, to be
+            distributed under the terms of Sections 1 and 2 above on a medium
+            customarily used for software interchange; or,
+
+      \item [(c)] Accompany it with the information you received as to the
+            offer to distribute corresponding source code.  (This alternative
+            is allowed only for noncommercial distribution and only if you
+            received the program in object code or executable form with such
+            an offer, in accord with Subsection b above.)
+
+      \end{enumerate}
+
+      The source code for a work means the preferred form of the work for
+      making modifications to it.  For an executable work, complete source
+      code means all the source code for all modules it contains, plus any
+      associated interface definition files, plus the scripts used to control
+      compilation and installation of the executable.  However, as a special
+      exception, the source code distributed need not include anything that
+      is normally distributed (in either source or binary form) with the
+      major components (compiler, kernel, and so on) of the operating system
+      on which the executable runs, unless that component itself accompanies
+      the executable.
+
+      If distribution of executable or object code is made by offering access
+      to copy from a designated place, then offering equivalent access to
+      copy the source code from the same place counts as distribution of the
+      source code, even though third parties are not compelled to copy the
+      source along with the object code.
+
+\item [4.] You may not copy, modify, sublicense, or distribute the Program
+      except as expressly provided under this License.  Any attempt otherwise
+      to copy, modify, sublicense or distribute the Program is void, and will
+      automatically terminate your rights under this License.  However,
+      parties who have received copies, or rights, from you under this
+      License will not have their licenses terminated so long as such parties
+      remain in full compliance.
+
+\item [5.] You are not required to accept this License, since you have not
+      signed it.  However, nothing else grants you permission to modify or
+      distribute the Program or its derivative works.  These actions are
+      prohibited by law if you do not accept this License.  Therefore, by
+      modifying or distributing the Program (or any work based on the
+      Program), you indicate your acceptance of this License to do so, and
+      all its terms and conditions for copying, distributing or modifying the
+      Program or works based on it.
+
+\item [6.] Each time you redistribute the Program (or any work based on the
+      Program), the recipient automatically receives a license from the
+      original licensor to copy, distribute or modify the Program subject to
+      these terms and conditions.  You may not impose any further
+      restrictions on the recipients' exercise of the rights granted herein.
+      You are not responsible for enforcing compliance by third parties to
+      this License.
+
+\item [7.] If, as a consequence of a court judgment or allegation of patent
+      infringement or for any other reason (not limited to patent issues),
+      conditions are imposed on you (whether by court order, agreement or
+      otherwise) that contradict the conditions of this License, they do not
+      excuse you from the conditions of this License.  If you cannot
+      distribute so as to satisfy simultaneously your obligations under this
+      License and any other pertinent obligations, then as a consequence you
+      may not distribute the Program at all.  For example, if a patent
+      license would not permit royalty-free redistribution of the Program by
+      all those who receive copies directly or indirectly through you, then
+      the only way you could satisfy both it and this License would be to
+      refrain entirely from distribution of the Program.
+
+      If any portion of this section is held invalid or unenforceable under
+      any particular circumstance, the balance of the section is intended to
+      apply and the section as a whole is intended to apply in other
+      circumstances.
+
+      It is not the purpose of this section to induce you to infringe any
+      patents or other property right claims or to contest validity of any
+      such claims; this section has the sole purpose of protecting the
+      integrity of the free software distribution system, which is
+      implemented by public license practices.  Many people have made
+      generous contributions to the wide range of software distributed
+      through that system in reliance on consistent application of that
+      system; it is up to the author/donor to decide if he or she is willing
+      to distribute software through any other system and a licensee cannot
+      impose that choice.
+
+      This section is intended to make thoroughly clear what is believed to
+      be a consequence of the rest of this License.
+
+\item [8.] If the distribution and/or use of the Program is restricted in
+      certain countries either by patents or by copyrighted interfaces, the
+      original copyright holder who places the Program under this License may
+      add an explicit geographical distribution limitation excluding those
+      countries, so that distribution is permitted only in or among countries
+      not thus excluded.  In such case, this License incorporates the
+      limitation as if written in the body of this License.
+
+\item [9.] The Free Software Foundation may publish revised and/or new
+      versions of the General Public License from time to time.  Such new
+      versions will be similar in spirit to the present version, but may
+      differ in detail to address new problems or concerns.
+
+      Each version is given a distinguishing version number.  If the Program
+      specifies a version number of this License which applies to it and
+      ``any later version'', you have the option of following the terms and
+      conditions either of that version or of any later version published by
+      the Free Software Foundation.  If the Program does not specify a
+      version number of this License, you may choose any version ever
+      published by the Free Software Foundation.
+
+\item [10.] If you wish to incorporate parts of the Program into other free
+      programs whose distribution conditions are different, write to the
+      author to ask for permission.  For software which is copyrighted by the
+      Free Software Foundation, write to the Free Software Foundation; we
+      sometimes make exceptions for this.  Our decision will be guided by the
+      two goals of preserving the free status of all derivatives of our free
+      software and of promoting the sharing and reuse of software generally.
+
+\begin{center}
+NO WARRANTY
+\end{center}
+
+\bfseries
+
+\item [11.] Because the Program is licensed free of charge, there is no
+      warranty for the Program, to the extent permitted by applicable law.
+      except when otherwise stated in writing the copyright holders and/or
+      other parties provide the program ``as is'' without warranty of any
+      kind, either expressed or implied, including, but not limited to, the
+      implied warranties of merchantability and fitness for a particular
+      purpose.  The entire risk as to the quality and performance of the
+      Program is with you.  Should the Program prove defective, you assume
+      the cost of all necessary servicing, repair or correction.
+
+\item [12.] In no event unless required by applicable law or agreed to in
+      writing will any copyright holder, or any other party who may modify
+      and/or redistribute the program as permitted above, be liable to you
+      for damages, including any general, special, incidental or
+      consequential damages arising out of the use or inability to use the
+      program (including but not limited to loss of data or data being
+      rendered inaccurate or losses sustained by you or third parties or a
+      failure of the Program to operate with any other programs), even if
+      such holder or other party has been advised of the possibility of such
+      damages.
+
+\end{enumerate}
+
+\begin{center}
+\textbf{END OF TERMS AND CONDITIONS}
+\end{center}
+
+
+\gplsec{Appendix: How to Apply These Terms to Your New Programs}
+
+If you develop a new program, and you want it to be of the greatest possible
+use to the public, the best way to achieve this is to make it free software
+which everyone can redistribute and change under these terms.
+
+To do so, attach the following notices to the program.  It is safest to
+attach them to the start of each source file to most effectively convey the
+exclusion of warranty; and each file should have at least the ``copyright''
+line and a pointer to where the full notice is found.
+
+\begin{verbatim}
+<one line to give the program's name and a brief idea of what it does.>
+Copyright (C) 19yy  <name of author>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+\end{verbatim}
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this when
+it starts in an interactive mode:
+
+\begin{verbatim}
+Gnomovision version 69, Copyright (C) 19yy name of author
+Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+This is free software, and you are welcome to redistribute it
+under certain conditions; type `show c' for details.
+\end{verbatim}
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may be
+called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a ``copyright disclaimer'' for the program, if
+necessary.  Here is a sample; alter the names:
+
+\begin{verbatim}
+Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+`Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+<signature of Ty Coon>, 1 April 1989
+Ty Coon, President of Vice
+\end{verbatim}
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General Public
+License instead of this License.
+
+\gplend

+ 212 - 0
docs/packages/mdwtools/mathenv.tex

@@ -0,0 +1,212 @@
+\documentclass{article}
+\usepackage{mdwtab}
+
+\errorcontextlines 999
+
+\showboxbreadth\maxdimen
+\showboxdepth=2
+
+\makeatletter
+
+% --- Switch allocations ---
+
+\newif\if@fleqn
+\newif\if@leqno
+
+% --- Dimen allocations ---
+
+\newdimen\eqa@thiscolwd
+\newdimen\eqa@maxcolwd
+\newdimen\eqa@maxeqwd
+\newdimen\eqa@maxcoleqwd
+
+% --- Main environments ---
+
+\def\equations{%
+  \def\eqa@defnumber{(\theequation)\stepcounter{equation}}%
+  \let\eqa@defmarker\eqa@fullmarker%
+  \eqa@equations%
+}
+
+\def\endequations{%
+    \\%
+    \noalign{\global\dimen@i\prevdepth}%
+    \multispan\tab@columns\hfill\vrule\@depth\dimen@i\cr%
+    \egroup%
+    \eqa@offsetcalc%
+  \egroup%
+  \eqa@restore%
+  {\scrollmode\showbox\z@}%
+}
+
+\def\eqa@equations#1{%
+%
+% Set up restoring of things.
+%
+  \toks@\expandafter{\eqa@number}%
+  \toks\tw@\expandafter{\eqa@marker}%
+  \edef\eqa@restore{%
+    \gdef\noexpand\eqa@number{\the\toks@}%
+    \gdef\noexpand\eqa@marker{\the\toks\tw@}%
+    \eqa@maxcolwd\the\eqa@maxcolwd%
+    \eqa@maxcoleqwd\the\eqa@maxcoleqwd%
+    \eqa@maxeqwd\the\eqa@maxeqwd%
+  }%
+%
+% Initialise numbering things.
+%
+  \global\let\eqa@number\eqa@defnumber%
+  \global\let\eqa@marker\eqa@defmarker%
+  \let\eqa@markpen\@ne%
+%
+% Parse the preamble string.  Put measuring things in the right places.
+%
+  \tab@initread%
+  \def\tab@tabtext{&\tabskip\z@skip}%
+  \if@leqno%
+    \tab@append\tab@preamble{\let\eqa@measure\eqa@domeasure}%
+  \fi%
+  \def\eqa@seteqcol##1{%
+    \def\eqa@eqcol{##1}
+    \if@leqno\let\eqa@seteqcol\relax\fi%
+  }%
+  \colset{equations}%
+  \tab@doreadpream{#1}%
+  \if@leqno\else%
+    \tab@prepend\tab@pretext{\let\eqa@measure\eqa@domeasure}%
+  \fi%
+  \tab@readpreamble{}%
+%
+% Setting the newline command and some other initialisation.
+%
+  \let\\\eqa@cr%
+  \global\eqa@maxcolwd\z@%
+  \global\eqa@maxcoleqwd\z@%
+  \global\eqa@maxeqwd\z@%
+%
+% Start the box.  Hacking to make \prevdepth work properly.
+%
+  \setbox\z@\vbox\expandafter\bgroup%
+    \expandafter\prevdepth\the\prevdepth%
+    \relax%
+%
+% And now the alignment.
+%
+    \tabskip\z@skip%
+    \halign\expandafter\bgroup\the\tab@preamble\cr%
+}
+
+% --- Column building things ---
+
+\def\eqa@aligncol#1#2#3{%
+  \eqa@seteqcol{#1}%
+  \ifx l#1\eqa@aligncol@i{#2#3}{#2\hfil}\else%
+  \ifx c#1\eqa@aligncol@i{\hfil#2#3}{#3#2\hfil}\else%
+  \ifx r#1\eqa@aligncol@i{\hfil#2}{#3#2}%
+  \fi\fi\fi%
+}
+\def\eqa@aligncol@i#1#2{%
+  \tabcoltype%
+    {\setbox\z@\hbox\bgroup#1}%
+    {#2\egroup\eqa@measure}%
+}
+
+\colpush{equations}
+
+\coldef l{\eqa@aligncol l${{}}}
+\coldef c{\eqa@aligncol c${{}}}
+\coldef r{\eqa@aligncol r${{}}}
+
+\coldef M#1{\eqa@aligncol{#1}${{}}}
+\coldef T#1{\eqa@aligncol{#1}{}{}}
+
+\colpop
+
+% --- Equation measuring macros ---
+
+\let\eqa@number\relax
+\let\eqa@marker\relax
+
+\def\eqnumber#1{%
+  \global\let\eqa@marker\eqa@fullmarker%
+  \gdef\eqa@number{#1}%
+}
+
+\def\nonumber{%
+  \global\let\eqa@marker\eqa@nonummarker%
+  \global\let\eqa@number\@empty%
+}
+
+\def\eqa@measure{\unhbox\z@}
+\def\eqa@domeasure{%
+  \global\eqa@thiscolwd\wd\z@%
+  \ifdim\eqa@maxcolwd<\eqa@thiscolwd%
+    \global\eqa@maxcolwd\eqa@thiscolwd%
+  \fi%
+  \unhbox\z@%
+}
+
+% --- The newline command ---
+
+\def\eqa@cr{\tab@cr\eqa@cr@i\z@\@M}
+\def\eqa@cr@i#1#2{%
+  \cr%
+  \noalign{%
+    \eqa@marker{#1}{#2}%
+    \global\let\eqa@number\eqa@defnumber%
+    \global\let\eqa@marker\eqa@defmarker%
+    \penalty\eqa@markpen%
+  }%
+}
+
+\def\eqa@fullmarker#1#2{%
+  \dimen@\prevdepth%
+  \vskip\eqa@thiscolwd%
+  \penalty#2%
+  \skip@#1\advance\skip@\jot%
+  \vskip\skip@%
+  \setbox\z@\hbox{\eqa@number}%
+  \dimen@\eqa@thiscolwd\advance\dimen@\wd\z@%
+  \ifdim\dimen@\eqa@maxcoleqwd<\dimen@%
+    \global\eqa@maxcoleqwd\dimen@%
+    \global\eqa@maxeqwd\wd\z@%
+  \fi%
+  \nointerlineskip\hb@xt@\z@{\hbox{\eqa@number}}%
+  \prevdepth\dimen@%
+}
+
+\def\eqa@nonummarker#1#2{%
+  \penalty#2%
+  \skip@#1\advance\skip@\jot%
+  \vskip\skip@%
+  \penalty\eqa@markpen%
+}
+
+% --- Offset calculation ---
+%
+% This stuff is sort of like the standard offset calculation, only it's
+% different.
+
+\def\eqa@offsetcalc{%
+  \setbox\z@\lastbox%
+  \unskip%
+  \csname eqa@calc:\eqa@eqcol\expandafter\noexpand\if@leqno\endcsname%
+}
+
+\@namedef{eqa@calc:l\noexpand\iffalse}{%
+  
+
+% --- Test document ---
+
+\makeatother
+
+\begin{document}
+
+\setcounter{equation}{23}
+
+\begin{equations}{rrl}
+  x &= y^2 +& z^2 \\
+x-y &= 3y^2 -& 2z^2
+\end{equations}
+
+\end{document}

+ 759 - 0
docs/packages/mdwtools/mdwlist.dtx

@@ -0,0 +1,759 @@
+% \begin{meta-comment}
+%
+% $Id$
+%
+% Various list-related things
+%
+% (c) 1996 Mark Wooding
+%
+%----- Revision history -----------------------------------------------------
+%
+% $Log$
+% Revision 1.1  1998-09-21 10:19:01  michael
+% Initial implementation
+%
+% Revision 1.1  1996/11/19 20:52:26  mdw
+% Initial revision
+%
+%
+% \end{meta-comment}
+%
+% \begin{meta-comment} <general public licence>
+%%
+%% mdwlist package -- various list-related things
+%% Copyright (c) 1996 Mark Wooding
+%%
+%% This program is free software; you can redistribute it and/or modify
+%% it under the terms of the GNU General Public License as published by
+%% the Free Software Foundation; either version 2 of the License, or
+%% (at your option) any later version.
+%%
+%% This program is distributed in the hope that it will be useful,
+%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+%% GNU General Public License for more details.
+%%
+%% You should have received a copy of the GNU General Public License
+%% along with this program; if not, write to the Free Software
+%% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+%%
+% \end{meta-comment}
+%
+% \begin{meta-comment} <Package preambles>
+%<+package>\NeedsTeXFormat{LaTeX2e}
+%<+package>\ProvidesPackage{mdwlist}
+%<+package>                [1996/05/02 1.1 Various list-related things]
+% \end{meta-comment}
+%
+% \CheckSum{179}
+%% \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{mdwlist}
+\def\defaultdesc{%
+  \desclabelwidth{80pt}%
+  \desclabelstyle\nextlinelabel%
+  \def\makelabel{\bfseries}%
+}
+\newenvironment{cmdlist}
+  {\basedescript{\let\makelabel\cmd}}
+  {\endbasedescript}
+\mdwdoc
+%</driver>
+%
+% \end{meta-comment}
+%
+% \section{User guide}
+%
+% This package provides some vaguely useful list-related commands and
+% environments:
+% \begin{itemize*}
+% \item A way of building \env{description}-like environments.
+% \item Commands for making `compacted' versions of list environments
+% \item A method for suspending and resuming enumerated lists.
+% \end{itemize*}
+%
+% \subsection{Description list handling}
+%
+% Different sorts of description-type lists require different sorts of
+% formatting: I think that's fairly obvious.  There are essentially three
+% different attributes which should be changable:
+% \begin{itemize*}
+% \item the indentation of the items being described,
+% \item the handling of labels which don't fit properly, and
+% \item the style used to typeset the label text.
+% \end{itemize*}
+% The first two items should usually be decided for all description-like
+% lists in the document, to ensure consistency of appearance.  The last
+% depends much more on the content of the labels.
+%
+% \DescribeEnv{basedescript}
+% The \env{basedescript} environment acts as a `skeleton' for description
+% environments.  It takes one argument, which contains declarations to
+% be performed while constructing the list.  I'd consider it unusual for
+% the \env{basedescript} environment to be used in the main text: it's
+% intended to be used to build other environments.
+%
+% The declarations which can be used to define description-type environments
+% include all of those which are allowed when setting up a list (see the
+% \LaTeX\ book for information here).  Some others, which apply specifically
+% to description lists, are also provided:
+%
+% \begin{itemize}
+%
+% \item \DescribeMacro{\desclabelwidth}
+%       The \syntax{"\\desclabelwidth{"<length>"}"} declaration sets labels
+%       to be left-aligned, with a standard width of \<length>; the item
+%       text is indented by \<length> plus the value of |\labelsep|.
+%
+% \item \DescribeMacro{\desclabelstyle}
+%       The label style determines how overlong labels are typeset.  A style
+%       may be set using the \syntax{"\\desclabelstyle{"<style>"}"}
+%       declaration.  The following \<style>s are provided:
+%       \begin{cmdlist}
+%       \item [\nextlinelabel] If the label is too wide to fit next to the
+%             first line of text, then it is placed on a line by itself;
+%             the main text is started on the next line with the usual
+%             indentation.
+%       \item [\multilinelabel] The label is typeset in a parbox with the
+%             appropriate width; if it won't fit on one line, then the
+%             text will be split onto subsequent lines.
+%       \item [\pushlabel] If the label is too wide to fit in the space
+%             allocated to it, the start of the item's text will be `pushed'
+%             over to the right to provide space for the label.  This is
+%             the standard \LaTeX\ \env{description} behaviour.
+%       \end{cmdlist}
+%
+% \item \DescribeMacro{\makelabel}
+%       The |\makelabel| command is responsible for typesetting a label.
+%       It is given one argument, which is the text given as an argument
+%       to the |\item| command; it should typeset it appropriately.  The
+%       text will then be arranged appropriately according to the chosen
+%       label style.  This command should be redefined using |\renewcommand|.
+%
+% \end{itemize}
+%
+% \begin{figure}
+% \begin{demo}[w]{Various labelling styles}
+%\begin{basedescript}{\desclabelstyle{\nextlinelabel}}
+%\item [Short label] This is a short item, although it has quite a
+%      lot of text attached to it.
+%\item [Slightly longer label text] This is a rather longer piece
+%      of text, with a correspondingly slightly longer label.
+%\end{basedescript}
+%\medskip
+%\begin{basedescript}{\desclabelstyle{\multilinelabel}}
+%\item [Short label] This is a short item, although it has quite a
+%      lot of text attached to it.
+%\item [Slightly longer label text] This is a rather longer piece
+%      of text, with a correspondingly slightly longer label.
+%\end{basedescript}
+%\medskip
+%\begin{basedescript}{\desclabelstyle{\pushlabel}}
+%\item [Short label] This is a short item, although it has quite a
+%      lot of text attached to it.
+%\item [Slightly longer label text] This is a rather longer piece
+%      of text, with a correspondingly slightly longer label.
+%\end{basedescript}
+% \end{demo}
+% \end{figure}
+%
+% \DescribeMacro{\defaultdesc}
+% To allow document designers to control the global appearance of description
+% lists, the |\defaultdesc| command may be redefined; it is called while
+% setting up a new \env{basedescript} list, before performing the user's
+% declarations.  By default, it attempts to emulate the standard \LaTeX\
+% \env{description} environment:\footnote{^^A
+%   This is a slightly sanitised version of the real definition, which is
+%   given in the implementation section of this document.}
+% \begin{listing}
+%\providecommand{\defaultdesc}{%
+%  \desclabelstyle{\pushlabel}%
+%  \renewcommand{\makelabel}[1]{\bfseries##1}%
+%  \setlength{\labelwidth}{0pt}%
+%}
+% \end{listing}
+% Unfortunately, \LaTeX\ doesn't provide a means for overriding a command
+% which may or may not have been defined yet; in this case, I'd probably
+% recommend using the \TeX\ primitive |\def| to redefine |\defaultdesc|.
+%
+% If you want to redefine the \env{description} environment in terms of
+% the commands in this package, the following method is recommended:
+% \begin{listing}
+%\renewenvironment{description}{%
+%  \begin{basedescript}{%
+%    \renewcommand{\makelabel}[1]{\bfseries##1}%
+%  }%
+%}{%
+%  \end{basedescript}%
+%}
+% \end{listing}
+% This ensures that labels are typeset in bold, as is usual, but other
+% properties of the list are determined by the overall document style.
+%
+% \subsection{Compacted lists}
+%
+% \LaTeX\ tends to leave a certain amount of vertical space between list
+% items.  While this is normally correct for lists in which the items are
+% several lines long, it tends to look odd if all or almost all the items
+% are only one line long.
+%
+% \DescribeMacro{\makecompactlist}
+% The command
+% \syntax{"\\makecompactlist{"<new-env-name>"}{"<old-env-name>"}"}
+% defines a new environment \<new-env-name> to be a `compacted' version of
+% the existing environment \<old-env-name>; i.e., the two environments are
+% the same except that the compacted version leaves no space between items
+% or paragraphs within the list.
+%
+% \DescribeEnv{itemize*}
+% \DescribeEnv{enumerate*}
+% \DescribeEnv{description*}
+% So that the most common cases are already handled, the package creates
+% compacted $*$-variants of the \env{itemize}, \env{enumerate} and
+% \env{description} environments.  These were created using the commands
+% \begin{listing}
+%\makecompactlist{itemize*}{itemize}
+%\makecompactlist{enumerate*}{enumerate}
+%\makecompactlist{description*}{description}
+% \end{listing}
+%
+% Some list environments accept arguments.  You can pass an argument to a
+% list environment using an optional argument to its compact variant.  For
+% example,
+% \begin{listing}
+%\begin{foolist*}[{someargument}]
+% \end{listing}
+%
+% \subsection{Suspending and resuming list environments}
+%
+% \DescribeMacro{\suspend}
+% \DescribeMacro{\resume}
+% The |\suspend| and |\resume| commands allow you to temporarily end a list
+% environment and then pick it up where you left off.  The syntax is fairly
+% simple:
+%
+% \begin{grammar}
+%
+% <suspend-cmd> ::= \[[
+%   "\\suspend"
+%   \begin{stack} \\ "[" <name> "]" \end{stack} "{" <env-name> "}"
+% \]]%
+%
+% <resume-cmd> ::= \[[
+%   "\\resume"
+%   \begin{stack} \\ "[" <name> "]" \end{stack} "{" <env-name> "}"
+%   \begin{stack} \\ "[" <text> "]" \end{stack}
+% \]]%
+%
+% \end{grammar}
+%
+% The \<env-name> is the name of the environment; this will more often than
+% not be the \env{enumerate} environment.  The \<name> is a magic name you
+% can use to identify the suspended environment; if you don't specify this,
+% the environment name is used instead.
+%
+% \begin{demo}{Suspended environments}
+%Here's some initial text.  It's
+%not very interesting.
+%\begin{enumerate*}
+%\item This is an item.
+%\item This is another.
+%\suspend{enumerate*}
+%Some more commentry text.
+%\resume{enumerate*}
+%\item Another item.
+%\end{enumerate*}
+% \end{demo}
+%
+% You can pass arguments to a resumed list environment through the second
+% optional argument of the |\resume| command.  If, for example, you're using
+% David Carlisle's \package{enumerate} package, you could say something like
+% \begin{listing}
+%\begin{enumerate}[\bfseries{Item} i]
+%\item An item
+%\item Another item
+%\suspend{enumerate}
+%Some intervening text.
+%\resume{enumerate}[{[\bfseries{Item} i]}]
+%\item Yet another item
+%\end{enumerate}
+% \end{listing}
+%
+% \implementation
+%
+% \section{Implementation}
+%
+%    \begin{macrocode}
+%<*package>
+%    \end{macrocode}
+%
+% \subsection{Description lists}
+%
+% \subsubsection{Label styles}
+%
+% \begin{macro}{\nextlinelabel}
+%
+% The idea here is that if the label is too long to fit in its box, we put
+% it on its own line and start the text of the item on the next.  I've
+% used |\sbox| here to capture colour changes properly, even though I have
+% deep moral objections to the use of \LaTeX\ boxing commands.  Anyway,
+% I capture the text in box~0 and compare its width to the amount of space
+% I have in the label box.  If there's enough, I can just unbox the box;
+% otherwise I build a vbox containing the label text and an empty hbox --
+% |\baselineskip| glue inserted between the two boxes makes sure we get
+% the correct spacing between the two lines, and the vboxness of the vbox
+% ensures that the baseline of my strange thing is the baseline of the
+% \emph{bottom} box.  I then bash the vbox on the nose, so as to make its
+% width zero, and leave that as the result.  Either way, I then add glue
+% to left align whatever it is I've created.
+%
+%    \begin{macrocode}
+\def\nextlinelabel#1{%
+  \sbox\z@{#1}%
+  \ifdim\wd\z@>\labelwidth%
+    \setbox\z@\vbox{\box\z@\hbox{}}%
+    \wd\z@\z@%
+    \box\z@%
+  \else%
+    \unhbox\z@%
+  \fi%
+  \hfil%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\multilinelabel}
+%
+% A different idea -- make the label text wrap around onto the next line if
+% it's too long.  This is really easy, actually.  I use a parbox to contain
+% the label text, set to be ragged right, because there won't be enough
+% space to do proper justification.  There's also a funny hskip there --
+% this is because \TeX\ only hyphenates things it finds sitting \emph{after}
+% glue items.  The parbox is top-aligned, so the label text and the item
+% run downwards together.  I put the result in box~0, and remove the depth,
+% so as not to make the top line of the item text look really strange.
+%
+% All this leaves a little problem, though: if the item text isn't very long,
+% the label might go further down the page than the main item, and possibly
+% collide with the label below.  I must confess that I'm not actually sure
+% how to deal with this possibility, so I just hope it doesn't happen.
+%
+% By the way, I don't have moral objections to |\parbox|.
+%
+%    \begin{macrocode}
+\def\multilinelabel#1{%
+  \setbox\z@\hbox{%
+    \parbox[t]\labelwidth{\raggedright\hskip\z@skip#1}%
+  }%
+  \dp\z@\z@%
+  \box\z@%
+  \hfil%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\pushlabel}
+%
+% Now we implement the old style behaviour -- if the label is too wide, we
+% just push the first line of the item further over to the right.  This
+% is really very easy indeed -- we just stick some |\hfil| space on the
+% right hand side (to left align if the label comes up too short).  The
+% `push' behaviour is handled automatically by \LaTeX's item handling.
+%
+%    \begin{macrocode}
+\def\pushlabel#1{{#1}\hfil}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \subsubsection{The main environment}
+%
+% \begin{macro}{\desclabelstyle}
+%
+% This is a declaration intended to be used only in the argument to the
+% \env{basedescript} environment.  It sets the label style for the list.
+% All we do is take the argument and assign it to a magic control sequence
+% which \env{basedescript} will understand later.
+%
+%    \begin{macrocode}
+\def\desclabelstyle#1{\def\desc@labelstyle{#1}}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\desclabelwidth}
+%
+% We set the label width and various other bits of information which will
+% make all the bits of the description line up beautifully.  We set
+% |\labelwidth| to the value we're given (using |\setlength|, so that
+% people can use the \package{calc} package if they so wish), and make
+% the |\leftmargin| equal $|\labelwidth|+|\labelsep|$.
+%
+%    \begin{macrocode}
+\def\desclabelwidth#1{%
+  \setlength\labelwidth{#1}%
+  \leftmargin\labelwidth%
+  \advance\leftmargin\labelsep%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{environment}{basedescript}
+%
+% This is the new description environment.  It does almost everything you
+% could want from a description environment, I think.  The argument is a
+% collection of declarations to be performed while setting up the list.
+%
+% This environment isn't really intended to be used by users -- it's here
+% so that you can define other description environments in terms of it,
+%
+% The environment is defined in two bits -- the `start' bit here simply
+% starts the list and inserts the user declarations in an appropriate
+% point, although sensible details will be inerted if the argument was
+% empty.
+%
+%    \begin{macrocode}
+\def\basedescript#1{%
+%    \end{macrocode}
+%
+% We must start the list.  If the |\item| command's optional argument is
+% missing, we should just leave a blank space, I think.
+%
+%    \begin{macrocode}
+  \list{}{%
+%    \end{macrocode}
+%
+% So far, so good.  Now put in some default declarations.  I'll use a
+% separate macro for this, so that the global appearance of lists can be
+% configured.
+%
+%    \begin{macrocode}
+    \defaultdesc%
+%    \end{macrocode}
+%
+% Now we do the user's declarations.
+%
+%    \begin{macrocode}
+    #1%
+%    \end{macrocode}
+%
+% Now set up the other parts of the list.  We set |\itemindent| so that the
+% label is up against the current left margin.  (The standard version
+% actually leaves the label hanging to the left of the margin by a
+% distance of |\labelsep| for a reason I can't quite comprehend -- there's
+% an |\hspace{\labelsep}| in the standard |\makelabel| to compensate for
+% this.  Strange\dots)
+%
+% To make the label start in the right place, the text of the item must
+% start a distance of $|\labelwidth|+|\labelsep|$ from the (pre-list) left
+% hand margin; this means that we must set |\itemindent| to be
+% $|\labelwidth|+|\labelsep|-|\leftmargin|$.  Time for some \TeX\ arithmetic.
+%
+%    \begin{macrocode}
+    \itemindent\labelwidth%
+    \advance\itemindent\labelsep%
+    \advance\itemindent-\leftmargin%
+%    \end{macrocode}
+%
+% Now we must set up the label typesetting.  We'll take the |\makelabel|
+% provided by the user, remember it, and then redefine |\makelabel| in
+% terms of the |\desclabelstyle| and the saved |\makelabel|.
+%
+%    \begin{macrocode}
+    \let\desc@makelabel\makelabel%
+    \def\makelabel##1{\desc@labelstyle{\desc@makelabel{##1}}}%
+%    \end{macrocode}
+%
+% I can't think of anything else which needs doing, so I'll call it a day
+% there.
+%
+%    \begin{macrocode}
+  }%
+}
+%    \end{macrocode}
+%
+% Now we define the `end-bit' of the environment.  Since all we need to do
+% is to close the list, we can be ever-so slightly clever and use |\let|.
+%
+%    \begin{macrocode}
+\let\endbasedescript\endlist
+%    \end{macrocode}
+%
+% Note that with these definitions, the standard \env{description}
+% environment can be emulated by saying simply:
+% \begin{listing}
+%\renewenvironment{description}{%
+%  \begin{basedescript}{}%
+%}{%
+%  \end{basedescript}
+%}
+% \end{listing}
+%
+% \end{environment}
+%
+% \begin{macro}{\defaultdesc}
+%
+% Now to set up the standard description appearance.  In the absence
+% of any other declarations, the label will `push' the text out the way if
+% the text is too long.  The standard |\labelsep| and |\leftmargin| are not
+% our problem.  We typeset the label text in bold by default. Also,
+% |\labelwidth| is cleared to 0\,pt, because this is what \LaTeX's usual
+% \env{description} does.
+%
+%    \begin{macrocode}
+\providecommand\defaultdesc{%
+  \desclabelstyle\pushlabel%
+  \def\makelabel##1{\bfseries##1}%
+  \labelwidth\z@%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \subsubsection{An example}
+%
+% \begin{environment}{note}
+%
+% The \env{note} environment is a simple application of the general
+% description list shown above.  It typesets the label (by default, the
+% text `\textbf{note}') at the left margin, and the note text indented by
+% the width of the label.
+%
+% The code is simple -- we take the environment's argument (which may have
+% been omitted), store it in a box (using |\sbox| again, to handle colour
+% changes correctly), set the label width from the width of the box, and
+% then create a single item containing the label text.  The text of the
+% environment then appears in exactly the desired place.
+%
+% I've not used |\newcommand| here, for the following reasons:
+% \begin{itemize}
+%
+% \item I don't like it much, to be honest.
+%
+% \item Until very recently, |\newcommand| only allowed you to define
+%       `long' commands, where new paragraphs were allowed to be started
+%       in command arguments; this removes a useful check which traps
+%       common errors like missing out `|}|' characters.  I'd prefer to
+%       be compatible with older \LaTeX s than to use the new |\newcommand|
+%       which provides a $*$-form to work around this restriction.
+%
+% \end{itemize}
+%
+%    \begin{macrocode}
+\def\note{\@ifnextchar[\note@i{\note@i[Note:]}}
+\def\note@i[#1]{%
+  \basedescript{%
+    \sbox\z@{\makelabel{#1}}%
+    \desclabelwidth{\wd\z@}%
+  }%
+  \item[\box\z@]%
+}
+\let\endnote\endbasedescript
+%    \end{macrocode}
+%
+% \end{environment}
+%
+%
+% \subsection{Compacted environments}
+%
+% Normal lists tend to have rather too much space between items if all or
+% most of the item texts are one line or less each.  We therefore define
+% a macro |\makecompactlist| whuch creates `compacted' versions of existing
+% environments.
+%
+% \begin{macro}{\makecompactlist}
+%
+% We're given two arguments: the name of the new environment to create, and
+% the name of the existing list environment to create.
+%
+% The first thing to do is to ensure that the environment we're creating is
+% actually valid (i.e., it doesn't exist already, and it has a sensible
+% name).  We can do this with the internal \LaTeX\ macro |\@ifdefinable|.
+%
+%    \begin{macrocode}
+\def\makecompactlist#1#2{%
+  \expandafter\@ifdefinable\csname#1\endcsname%
+    {\makecompactlist@i{#1}{#2}}%
+}
+%    \end{macrocode}
+%
+% We also ought to ensure that the other environment already exists.  This
+% isn't too tricky.  We'll steal \LaTeX's error and message for this.
+%
+%    \begin{macrocode}
+\def\makecompactlist@i#1#2{%
+  \@ifundefined{#2}{\me@err{Environment `#2' not defined}\@ehc}{}%
+%    \end{macrocode}
+%
+% The main work for starting a compact list is done elsewhere.
+%
+%    \begin{macrocode}
+  \@namedef{#1}{\@compact@list{#2}}%
+%    \end{macrocode}
+%
+% Now to define the end of the environment; this isn't terribly difficult.
+%
+%    \begin{macrocode}
+  \expandafter\let\csname end#1\expandafter\endcsname%
+                  \csname end#2\endcsname%
+%    \end{macrocode}
+%
+% That's a compacted environment created.  Easy, no?
+%
+%    \begin{macrocode}
+}
+%    \end{macrocode}
+%
+% The general case macro has to try slurping some arguments, calling the
+% underlying environment, and removing vertical space.
+%
+%    \begin{macrocode}
+\def\@compact@list#1{\@testopt{\@compact@list@i{#1}}{}}
+\def\@compact@list@i#1[#2]{%
+  \@nameuse{#1}#2%
+  \parskip\z@%
+  \itemsep\z@%
+}%
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{environment}{itemize*}
+% \begin{environment}{enumerate*}
+% \begin{environment}{description*}
+%
+% Let's build some compacted environments now.  These are easy now that
+% we've done all the work above.
+%
+%    \begin{macrocode}
+\makecompactlist{itemize*}{itemize}
+\makecompactlist{enumerate*}{enumerate}
+\makecompactlist{description*}{description}
+%    \end{macrocode}
+%
+% \end{environment}
+% \end{environment}
+% \end{environment}
+%
+%
+% \subsection{Suspending and resuming lists}
+%
+% This is nowhere near perfect; it relies a lot on the goodwill of the user,
+% although it seems to work fairly well.
+%
+% \begin{macro}{\suspend}
+%
+% The only thing that needs saving here is the list counter, whose name
+% is stored in |\@listctr|.  When I get a request to save the counter, I'll
+% build a macro which will restore it when the environment is restored later.
+%
+% The first thing to do is to handle the optional argument.  |\@dblarg| will
+% sort this out, giving me a copy of the mandatory argument if there's no
+% optional one provided.
+%
+%    \begin{macrocode}
+\def\suspend{\@dblarg\suspend@i}
+%    \end{macrocode}
+%
+% That's all we need to do here.
+%
+%    \begin{macrocode}
+\def\suspend@i[#1]#2{%
+%    \end{macrocode}
+%
+% Now I have a little problem; when I |\end| the environment, it will close
+% off the grouping level, and the counter value will be forgotten.  This is
+% bad.  I'll store all my definitions into a macro, and build the |\end|
+% command into it; that way, everything will be expanded correctly.  This
+% requires the use of |\edef|, which means I must be a little careful.
+%
+%    \begin{macrocode}
+  \edef\@tempa{%
+%    \end{macrocode}
+%
+% The first thing to do is to end the environment.  I don't want |\end|
+% expanded yet, so I'll use |\noexpand|.
+%
+%    \begin{macrocode}
+    \noexpand\end{#2}%
+%    \end{macrocode}
+%
+% Now I must define the `resume' macro.  I'll use |\csname| to build the
+% named identifier into the name, so it won't go wrong (maybe).  There's
+% a little fun here to make the control sequence name but not expand it
+% here.
+%
+%    \begin{macrocode}
+    \def\expandafter\noexpand\csname resume.#1\endcsname{%
+%    \end{macrocode}
+%
+% The counter name is hidden inside |\@listctr|, so the actual counter is
+% called `|\csname c@\@listctr\endcsname|'.  I'll use |\the| to read its
+% current value, and assign it to the counter when the macro is used later.
+%
+%    \begin{macrocode}
+      \csname c@\@listctr\endcsname\the\csname c@\@listctr\endcsname%
+%    \end{macrocode}
+%
+% That's all we need to do there.  Now close the macros and run them.
+%
+%    \begin{macrocode}
+    }%
+  }%
+  \@tempa%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\resume}
+%
+% Resuming environments is much easier.  Since I use |\csname| to build the
+% name, nothing happens if you try to resume environments which weren't
+% suspended.  I'll trap this and raise an error.  Provide an optional
+% argument for collecting arguments to the target list.
+%
+%    \begin{macrocode}
+\def\resume{\@dblarg\resume@i}
+\def\resume@i[#1]#2{\@testopt{\resume@ii{#1}{#2}}{}}
+\def\resume@ii#1#2[#3]{%
+  \begin{#2}#3%
+  \@ifundefined{resume.#1}{\ml@err@resume}{\@nameuse{resume.#1}}%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% That's all there is.
+%
+%    \begin{macrocode}
+%</package>
+%    \end{macrocode}
+%
+% \hfill Mark Wooding, \today
+%
+% \Finale
+%
+\endinput

+ 933 - 0
docs/packages/mdwtools/mdwmath.dtx

@@ -0,0 +1,933 @@
+% \begin{meta-comment}
+%
+% $Id$
+%
+% Various nicer mathematical things
+%
+% (c) 1996 Mark Wooding
+%
+%----- Revision history -----------------------------------------------------
+%
+% $Log$
+% Revision 1.1  1998-09-21 10:19:01  michael
+% Initial implementation
+%
+% Revision 1.1  1996/11/19 20:53:21  mdw
+% Initial revision
+%
+%
+% \end{meta-comment}
+%
+% \begin{meta-comment} <general public licence>
+%%
+%% mdwmath package -- various nicer mathematical things
+%% Copyright (c) 1996 Mark Wooding
+%%
+%% This program is free software; you can redistribute it and/or modify
+%% it under the terms of the GNU General Public License as published by
+%% the Free Software Foundation; either version 2 of the License, or
+%% (at your option) any later version.
+%%
+%% This program is distributed in the hope that it will be useful,
+%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+%% GNU General Public License for more details.
+%%
+%% You should have received a copy of the GNU General Public License
+%% along with this program; if not, write to the Free Software
+%% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+%%
+% \end{meta-comment}
+%
+% \begin{meta-comment} <Package preamble>
+%<+package>\NeedsTeXFormat{LaTeX2e}
+%<+package>\ProvidesPackage{mdwmath}
+%<+package>                [1996/04/11 1.1 Nice mathematical things]
+%<+oldeqnarray>\NeedsTeXFormat{LaTeX2e}
+%<+oldeqnarray>\ProvidesPackage{eqnarray}
+%<+oldeqnarray>                [1996/04/11 1.1 Old enhanced eqnarray]
+% \end{meta-comment}
+%
+% \CheckSum{259}
+% \begin{old-eqnarray}
+% \CheckSum{484}
+% \end{old-eqnarray}
+%% \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{mdwmath}
+% \describespackage{eqnarray}
+\ignoreenv{old-eqnarray}
+% \unignoreenv{old-eqnarray}
+\mdwdoc
+%</driver>
+%
+% \end{meta-comment}
+%
+% \section{User guide}
+%
+% \subsection{Square root typesetting}
+%
+% \DescribeMacro{\sqrt}
+% The package supplies a star variant of the |\sqrt| command which omits the
+% vinculum over the operand (the line over the top).  While this is most
+% useful in simple cases like $\sqrt*{2}$ it works for any size of operand.
+% The package also re-implements the standard square root command so that it
+% positions the root number rather better.
+%
+% \begin{figure}
+% \begin{demo}[w]{Examples of the new square root command}
+%\[ \sqrt*{2} \quad \mbox{rather than} \quad \sqrt{2} \]
+%\[ \sqrt*[3]{2} \quad \mbox{ rather than } \quad \sqrt[3]{2} \]
+%\[ \sqrt{x^3 + \sqrt*[y]{\alpha}} - \sqrt*[n+1]{a} \]
+%\[ x = \sqrt*[3]{\frac{3y}{7}} \]
+%\[ q = \frac{2\sqrt*{2}}{5}+\sqrt[\frac{n+1}{2}]{2x^2+3xy-y^2} \]
+% \end{demo}
+% \end{figure}
+%
+% [Note that omission of the vinculum was originally a cost-cutting exercise
+% because the radical symbol can just fit in next to its operand and
+% everything ends up being laid out along a line.  However, I find that the
+% square root without vinculum is less cluttered, so I tend to use it when
+% it doesn't cause ambiguity.]
+%
+% \subsection{Some maths symbols you already have}
+%
+% Having just tried to do some simple things, I've found that there are maths
+% symbols missing.  Here they are, in all their glory:
+%
+% \begin{center} \unverb\| \begin{tabular}{cl|cl|cl}
+% $\&$ & "\&"		& $\bitor$ & "\bitor"	& $\dbland$ & "\dbland" \\
+% $\bitand$ & "\bitand"	& $\dblor$ & "\dblor"	& 
+% \end{tabular} \end{center}
+%
+% \begin{ignore}
+% There used to be an eqnarray here, but that's migrated its way into the
+% \package{mdwtab} package.  Maybe the original version, without dependency
+% on \package{mdwtab} ought to be releasable separately.  I'll keep it around
+% just in case.
+%
+% The following is the documentation for the original version.  There's an
+% updated edition in \package{mdwtab}.
+% \end{ignore}
+%
+% \begin{old-eqnarray}
+%
+% \subsection{A new \env{eqnarray} environment}
+%
+% \LaTeX's built-in \env{eqnarray} is horrible -- it puts far too much space
+% between the items in the array.  This environment is rather nearer to the
+% \env{amsmath} \env{align} environments, although rather less capable.
+%
+% \bigskip
+% \DescribeEnv{eqnarray}
+% {\synshorts
+% \setbox0\hbox{"\\begin{eqnarray}["<preamble>"]" \dots "\\end{eqnarray}"}
+% \leavevmode \hskip-\parindent \fbox{\box0}
+% }
+% \smallskip
+%
+% The new version of \env{eqnarray} tries to do everything which you really
+% want it to.  The \synt{preamble} string allows you to define the column
+% types in a vaguely similar way to the wonderful \env{tabular} environment.
+% The types provided (and it's easy-ish to add more) are:
+%
+% \def\ch{\char`}
+% \begin{description} \def\makelabel{\hskip\labelsep\normalfont\ttfamily}
+% \item [r] Right aligned equation
+% \item [c] Centre-aligned equation
+% \item [l] Left aligned equation
+% \item [\textrm{\texttt{Tr}, \texttt{Tc} and \texttt{Tl}}] Right, centre and
+%       left aligned text (not maths)
+% \item [L] Left aligned zero-width equation
+% \item [x] Centred entire equation
+% \item [:] Big gap separating sets of equations
+% \item [q] Quad space
+% \item [>\ch\{\synt{text}\ch\}] Insert text before column
+% \item [<\ch\{\synt{text}\ch\}] Insert text after column
+% \end{description}
+%
+% Some others are also defined: don't use them because they do complicated
+% things which are hard to explain and they aren't much use anyway.
+%
+% 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}[rcrcrcrl]
+%  10w & + &  3x & + & 3y & + & 18z & = 1 \\
+%   6w & - & 17x &   &    & - &  5z & = 2
+%\end{eqnarray}
+% \end{demo}
+%
+% Choosing a more up-to-date example, here's one demonstrating the \lit{:}
+% column specifier from the \textit{\LaTeX\ Companion}.
+%
+% \begin{demo}[w]{Lots of equations}
+%\begin{eqnarray}[rl:rl:l]
+% 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$}  \label{eq:A} \\
+% V_j &= v_j,           & X_j &= x_j            &
+%       U_j u_j + \sum_{i \ne j} q_i u_i.
+%\end{eqnarray}
+% \end{demo}
+%
+% We can make things more interesting by adding a plain text column.  Here we
+% go:
+%
+% \begin{demo}[w]{Plain text column}
+%\begin{eqnarray}[rlqqTl]
+%     x  &= y           & by (\ref{eq:A}) \\
+%     x' &= y'          & by definition \\
+% x + x' &= y + y'      & by Axiom~1
+%\end{eqnarray}
+% \end{demo}
+%
+% 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.
+% More excitingly, you can say \syntax{"\\nonumber["<text>"]"} to choose
+% what text to display.
+%
+% A note for cheats: you can use the sparkly new \env{eqnarray} for simple
+% equations simply by specifying \lit{x} as the column description.  Who
+% needs \AmSTeX? |;-)|
+%
+% \end{old-eqnarray}
+%
+% \implementation
+%
+% \section{Implementation}
+%
+% This isn't really complicated (honest) although it is a lot hairier than I
+% think it ought to be.
+%
+%    \begin{macrocode}
+%<*package>
+%    \end{macrocode}
+%
+% \subsection{Square roots}
+%
+% \subsubsection{Where is the square root sign?}
+%
+% \LaTeX\ hides the square root sign away somewhere without telling anyone
+% where it is.  I extract it forcibly by peeking inside the |\sqrtsign| macro
+% and scrutinising the contents.  Here we go: prepare for yukkiness.
+%
+%    \begin{macrocode}
+\newcount\sq@sqrt
+\begingroup
+  \catcode`\|0 \catcode`\\12
+  |def|sq@readrad#1"#2\#3|relax{|global|sq@sqrt"#2|relax}
+  |expandafter|sq@readrad|meaning|sqrtsign|relax
+|endgroup
+\def\sq@delim{\delimiter\sq@sqrt\relax}
+%    \end{macrocode}
+%
+% \subsubsection{Drawing fake square root signs}
+%
+% \TeX\ absolutely insists on drawing square root signs with a vinculum over
+% the top.  In order to get the same effect, we have to attempt to emulate
+% \TeX's behaviour.
+%
+% \begin{macro}{\sqrtdel}
+%
+% This does the main job of typesetting a vinculum-free radical.\footnote{^^A
+%   Note for chemists: this is nothing to do with short-lived things which
+%   don't have their normal numbers of electrons.  And it won't reduce the
+%   appearance of wrinkles either.}
+% It's more or less a duplicate of what \TeX\ does internally, so it might be
+% a good plan to have a copy of Appendix~G open while you examine this.
+%
+% We start off by using |\mathpalette| to help decide how big things should
+% be.
+%
+%    \begin{macrocode}
+\def\sqrtdel{\mathpalette\sqrtdel@i}
+%    \end{macrocode}
+%
+% Read the contents of the radical into a box, so we can measure it.
+%
+%    \begin{macrocode}
+\def\sqrtdel@i#1#2{%
+  \setbox\z@\hbox{$\m@th#1#2$}% %%% Bzzzt -- uncramps the mathstyle
+%    \end{macrocode}
+%
+% Now try and sort out the values needed in this calculation.  We'll assume
+% that $\xi_8$ is 0.6\,pt, the way it usually is.  Next try to work out the
+% value of $\varphi$.
+%
+%    \begin{macrocode}
+  \ifx#1\displaystyle%
+    \@tempdima1ex%
+  \else%
+    \@tempdima.6\p@%
+  \fi%
+%    \end{macrocode}
+%
+% That was easy.  Now for $\psi$.
+%
+%    \begin{macrocode}
+  \@tempdimb.6\p@%
+  \advance\@tempdimb.25\@tempdima%
+%    \end{macrocode}
+%
+% Build the `delimiter' in a box of height $h(x)+d(x)+\psi+\xi_8$, as
+% requested.  Box~2 will do well for this purpose.
+%
+%    \begin{macrocode}
+  \[email protected]\p@%
+  \advance\dimen@\@tempdimb%
+  \advance\dimen@\ht\z@%
+  \advance\dimen@\dp\z@%
+  \setbox\tw@\hbox{%
+    $\left\sq@delim\vcenter to\dimen@{}\right.\n@space$%
+  }%
+%    \end{macrocode}
+%
+% Now we need to do some more calculating (don't you hate it?).  As far as
+% Appendix~G is concerned, $\theta=h(y)=0$, because we want no rule over the
+% top.  
+%
+%    \begin{macrocode}
+  \@tempdima\ht\tw@%
+  \advance\@tempdima\dp\tw@%
+  \advance\@tempdima-\ht\z@%
+  \advance\@tempdima-\dp\z@%
+  \ifdim\@tempdima>\@tempdimb%
+    \advance\@tempdima\@tempdimb%
+    \@tempdimb.5\@tempdima%
+  \fi%
+%    \end{macrocode}
+%
+% Work out how high to raise the radical symbol.  Remember that Appendix~G
+% thinks that the box has a very small height, although this is untrue here.
+%
+%    \begin{macrocode}
+  \@tempdima\ht\z@%
+  \advance\@tempdima\@tempdimb%
+  \advance\@tempdima-\ht\tw@%
+%    \end{macrocode}
+%
+% Build the output (finally).  The brace group is there to turn the output
+% into a mathord, one of the few times that this is actually desirable.
+%
+%    \begin{macrocode}
+  {\raise\@tempdima\box\tw@\vbox{\kern\@tempdimb\box\z@}}%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \subsubsection{The new square root command}
+%
+% This is where we reimplement all the square root stuff.  Most of this stuff
+% comes from the \PlainTeX\ macros, although some is influenced by \AmSTeX\
+% and \LaTeXe, and some is original.  I've tried to make the spacing vaguely
+% automatic, so although it's not configurable like \AmSTeX's version, the
+% output should look nice more of the time.  Maybe.
+%
+% \begin{macro}{\sqrt}
+%
+% \LaTeX\ says this must be robust, so we make it robust.  The first thing to
+% do is to see if there's a star and pass the appropriate squareroot-drawing
+% command on to the rest of the code.
+%
+%    \begin{macrocode}
+\DeclareRobustCommand\sqrt{\@ifstar{\sqrt@i\sqrtdel}{\sqrt@i\sqrtsign}}
+%    \end{macrocode}
+%
+% Now we can sort out an optional argument to be displayed on the root.
+%
+%    \begin{macrocode}
+\def\sqrt@i#1{\@ifnextchar[{\sqrt@ii{#1}}{\sqrt@iv{#1}}}
+%    \end{macrocode}
+%
+% Stages~2 and~3 below are essentially equivalents of \PlainTeX's
+% |\root|\dots|\of| and |\r@@t|.  Here we also find the first wrinkle: the
+% |\rootbox| used to store the number is spaced out on the left if necessary.
+% There's a backspace after the end so that the root can slip underneath, and
+% everything works out nicely.  Unfortunately size is fixed here, although
+% doesn't actually seem to matter.
+%
+%    \begin{macrocode}
+\def\sqrt@ii#1[#2]{%
+  \setbox\rootbox\hbox{$\m@th\scriptscriptstyle{#2}$}%
+  \ifdim\wd\rootbox<6\p@%
+    \setbox\rootbox\hb@xt@6\p@{\hfil\unhbox\rootbox}%
+  \fi%
+  \mathpalette{\sqrt@iii{#1}}%
+}
+%    \end{macrocode}
+%
+% Now we can actually build everything.  Note that the root is raised by its
+% depth -- this prevents a common problem with letters with descenders.
+%
+%    \begin{macrocode}
+\def\sqrt@iii#1#2#3{%
+  \setbox\z@\hbox{$\m@th#2#1{#3}$}%
+  \dimen@\ht\z@%
+  \advance\dimen@-\dp\z@%
+  \[email protected]\dimen@%
+  \advance\dimen@\dp\rootbox%
+  \mkern-3mu%
+  \raise\dimen@\copy\rootbox%
+  \mkern-10mu%
+  \box\z@%
+}
+%    \end{macrocode}
+%
+% Finally handle a non-numbered root.  We read the rooted text in as an
+% argument, to stop problems when people omit the braces.  (\AmSTeX\ does
+% this too.)
+%
+%    \begin{macrocode}
+\def\sqrt@iv#1#2{#1{#2}}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\root}
+%
+% We also re-implement \PlainTeX's |\root| command, just in case someone uses
+% it, and supply a star-variant.  This is all very trivial.
+%
+%    \begin{macrocode}
+\def\root{\@ifstar{\root@i\sqrtdel}{\root@i\sqrtsign}}
+\def\root@i#1#2\of{\sqrt@ii{#1}[#2]}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \subsection{Some magic new maths characters}
+%
+% This is all really easy.
+%
+%    \begin{macrocode}
+\DeclareMathSymbol{&}{\mathbin}{operators}{`\&}
+\DeclareMathSymbol{\bitand}{\mathbin}{operators}{`\&}
+\def\bitor{\mathbin\mid}
+\def\dblor{\mathbin{\mid\mid}}
+\def\dbland{\mathbin{\mathrel\bitand\mathrel\bitand}}
+%    \end{macrocode}
+%
+% \subsection{Biggles}
+%
+% Now for some user-controlled delimiter sizing.  The standard bigness of
+% plain \TeX's delimiters are all right, but it's a little limiting.
+%
+% The biggness of delimiters is based on the size of the current |\strut|,
+% which \LaTeX\ keeps up to date all the time.  This will make the various
+% delimiters grow in proportion when the text gets bigger.  Actually, I'm
+% not sure that this is exactly right -- maybe it should be nonlinear,
+%
+% \begin{macro}{\bbigg}
+% \begin{macro}{\bbiggl}
+% \begin{macro}{\bbiggr}
+% \begin{macro}{\bbiggm}
+%
+% This is where the bigness is done.  This is more similar to the plain \TeX\
+% big delimiter stuff than to the \package{amsmath} stuff, although there's
+% not really a lot of difference.
+%
+% The two arguments are a multiplier for the delimiter size, and a small
+% increment applied \emph{before} the multiplication (which is optional).
+%
+% This is actually a front for a low-level interface which can be called
+% directly for efficiency.
+%
+%    \begin{macrocode}
+\def\bbigg{\@bbigg\mathord}
+\def\bbiggl{\@bbigg\mathopen}
+\def\bbiggr{\@bbigg\mathclose}
+\def\bbiggm{\@bbigg\mathrel}
+%    \end{macrocode}
+%
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@bbigg}
+%
+% This is an optional argument parser providing a front end for the main
+% macro |\bbigg@|.
+%
+%    \begin{macrocode}
+\def\@bbigg#1{\@ifnextchar[{\@bigg@i{#1}}{\@bigg@i{#1}[\z@]}}
+\def\@bigg@i#1[#2]#3#4{#1{\bbigg@{#2}{#3}{#4}}}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\bbigg@}
+%
+% This is it, at last.  The arguments are as described above: an addition
+% to be made to the strut height, and a multiplier.  Oh, and the delimiter,
+% of course.
+%
+% This is a bit messy.  The smallest `big' delimiter, |\big|, is the same
+% height as the current strut box.  Other delimiters are~$1\frac12$, $2$
+% and~$2\frac12$ times this height.  I'll set the height of the delimiter by
+% putting in a |\vcenter| of the appropriate size.
+%
+% Given an extra height~$x$, a multiplication factor~$f$ and a strut
+% height~$h$ and depth~$d$, I'll create a vcenter with total height
+% $f(h+d+x)$.  Easy, isn't it?
+%
+%    \begin{macrocode}
+\def\bbigg@#1#2#3{%
+  \hbox{$%
+    \dimen@\ht\strutbox\advance\dimen@\dp\strutbox%
+    \advance\dimen@#1%
+    \dimen@#2\dimen@%
+    \left#3\vcenter to\dimen@{}\right.\n@space%
+  $}%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\big}
+% \begin{macro}{\Big}
+% \begin{macro}{\bigg}
+% \begin{macro}{\Bigg}
+%
+% Now for the easy macros.
+%
+%    \begin{macrocode}
+\def\big{\bbigg@\z@\@ne}
+\def\Big{\bbigg@\z@{1.5}}
+\def\bigg{\bbigg@\z@\tw@}
+\def\Bigg{\bbigg@\z@{2.5}}
+%    \end{macrocode}
+%
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% 
+%
+% \begin{ignore}
+% The following is the original definition of the enhanced eqnarray
+% environment.  It's not supported, although if you can figure out how to
+% extract it, it's all yours.
+% \end{ignore}
+%
+% \begin{old-eqnarray}
+%
+% \subsection{The sparkly new \env{eqnarray}}
+%
+% Start off by writing a different package.
+%
+%    \begin{macrocode}
+%</package>
+%<*oldeqnarray>
+%    \end{macrocode}
+%
+% \subsubsection{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}
+%
+% This is all really different to the \LaTeX\ version.  I've looked at the
+% various \env{tabular} implementations, the original \env{eqnarray} and the
+% \textit{\TeX book} to see how best to do this, and then went my own way.
+% If it doesn't work it's all my fault.
+%
+% \subsubsection{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
+%    \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}
+\if@fleqn
+  \AtBeginDocument{\eqaopenskip\leftmargini}
+\else
+  \eqaopenskip\@centering
+\fi
+\eqacloseskip\@centering
+\eqacolskip\@centering
+\eqainskip\z@
+%    \end{macrocode}
+%
+% 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\eqa@style\displaystyle
+%    \end{macrocode}
+%
+% \subsubsection{The main environments}
+%
+% We define the toplevel commands here.  They just add in default arguments
+% and then call |\@eqnarray| with a preamble string.  The only difference is
+% the last column they add in -- \env{eqnarray$*$} throws away the last
+% column by sticking it in box~0.  (I used to |\@gobble| it but that caused
+% the |\cr| to be lost.)
+%
+%    \begin{macrocode}
+\def\eqnarray{\@ifnextchar[\eqnarray@i{\eqnarray@i[rcl]}}
+\def\eqnarray@i[#1]{%
+  \@eqnarray{#1!{\hb@xt@\z@{\hss##}\tabskip\z@}}
+}
+\@namedef{eqnarray*}{\@ifnextchar[\eqnarray@s@i{\eqnarray@s@i[rcl]}}
+\def\eqnarray@s@i[#1]{%
+  \@eqnarray{#1!{\nonumber\setbox\z@\hbox{##}\tabskip\z@}}%
+}
+%    \end{macrocode}
+%
+% \subsubsection{Set up the initial display}
+%
+% \begin{macro}{\@eqnarray}
+%
+% The |\@eqnarray| command does most of the initial work.  It sets up some
+% flags and things, builds the |\halign| preamble, and returns.
+%
+%    \begin{macrocode}
+\def\@eqnarray#1{%
+%    \end{macrocode}
+%
+% Start playing with the counter here.  The original does some icky internal
+% playing, which isn't necessary.  The |\if@eqnsw| switch is |true| if the
+% user hasn't supplied an equation number.  The |\if@eqalast| switch is
+% |true| in the final equation-number column.
+%
+%    \begin{macrocode}
+  \refstepcounter{equation}%
+  \@eqalastfalse%
+  \global\@eqnswtrue%
+  \m@th%
+%    \end{macrocode}
+%
+% Set things up for the |\halign| which is coming up.
+%
+%    \begin{macrocode}
+  \openup\jot%
+  \tabskip\eqaopenskip%
+  \let\\\@eqncr%
+  \everycr{}%
+  $$%
+%    \end{macrocode}
+%
+% We'll build the real |\halign| and preamble in a token register.  All we
+% need to do is stuff the header in the token register, clear a switch
+% (that'll be explained later), parse the preamble and then expand the
+% tokens we collected.  Easy, no?
+%
+%    \begin{macrocode}
+  \toks@{\halign to\displaywidth\bgroup}%
+  \@tempswafalse%
+  \eqa@preamble#1\end%
+  \the\toks@\cr%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \subsubsection{Parsing the preamble}
+%
+% All this actually involves is reading the next character and building a
+% command from it.  That can pull off an argument if it needs it.  Just make
+% sure we don't fall off the end and we'll be OK.
+%
+%    \begin{macrocode}
+\def\eqa@preamble#1{%
+  \ifx\end#1\else\csname eqa@char@#1\expandafter\endcsname\fi%
+}
+%    \end{macrocode}
+%
+% Adding stuff to the preamble tokens is a simple matter of using
+% |\expandafter| in the correct way.\footnote{^^A
+%   I have no idea why \LaTeX\ uses \cmd\edef\ for building its preamble.  It
+%   seems utterly insane to me -- the amount of bodgery that \env{tabular}
+%   has to go through to make everything expand at the appropriate times is
+%   scary.  Maybe Messrs~Lamport and Mittelbach just forgot about token
+%   registers when they were writing the code.  Maybe I ought to rewrite the
+%   thing properly some time.  Sigh.
+%
+%   As a sort of postscript to the above, I \emph{have} rewritten the
+%   \env{tabular} environment, and made a damned fine job of it, in my
+%   oh-so-humble opinion.  All this \env{eqnarray} stuff has been remoulded
+%   in terms of the generic column-defining things in \package{mdwtab}.
+%   You're reading the documentation of the old version, which isn't
+%   supported any more, so any bugs here are your own problem.}
+%
+%    \begin{macrocode}
+\def\eqa@addraw#1{\expandafter\toks@\expandafter{\the\toks@#1}}
+%    \end{macrocode}
+%
+% Now for some cleverness again.  In order to put all the right bits of
+% |\tabskip| glue in the right places we must \emph{not} terminate each
+% column until we know what the next one is.  We set |\if@tempswa| to be
+% |true| if there's a column waiting to be closed (so it's initially
+% |false|).  The following macro adds a column correctly, assuming we're in
+% a formula.  Other column types make their own arrangements.
+%
+%    \begin{macrocode}
+\def\eqa@add#1{%
+  \if@tempswa%
+    \eqa@addraw{\tabskip\eqainskip&#1}%
+  \else%
+    \eqa@addraw{#1}%
+  \fi%
+  \@tempswatrue%
+}
+%    \end{macrocode}
+%
+% Now to defining column types.  Let's define a macro which allows us to
+% define column types:
+%
+%    \begin{macrocode}
+\def\eqa@def#1{\expandafter\def\csname eqa@char@#1\endcsname}
+%    \end{macrocode}
+%
+% Now we can define the column types.  Each column type must loop back to
+% |\eqa@preamble| once it's finished, to read the rest of the preamble
+% string.  Note the positioning of ord atoms in the stuff below.  This will
+% space out relations and binops correctly when they occur at the edges of
+% columns, and won't affect ord atoms at the edges, because ords pack
+% closely.
+%
+% First the easy onces.  Just stick |\hfil| in the right places and
+% everything will be all right.
+%
+%    \begin{macrocode}
+\eqa@def r{\eqa@add{\hfil$\eqa@style##{}$}\eqa@preamble}
+\eqa@def c{\eqa@add{\hfil$\eqa@style{}##{}$\hfil}\eqa@preamble}
+\eqa@def l{\eqa@add{$\eqa@style{}##$\hfil}\eqa@preamble}
+\eqa@def x{\eqa@add{\hfil$\eqa@style##$\hfil}\eqa@preamble}
+%    \end{macrocode}
+%
+% Now for the textual ones.  This is also fairly easy.
+%
+%    \begin{macrocode}
+\eqa@def T#1{%
+  \eqa@add{}%
+  \if#1l\else\eqa@addraw{\hfil}\fi%
+  \eqa@addraw{##}%
+  \if#1r\else\eqa@addraw{\hfil}\fi%
+  \eqa@preamble%
+}
+%    \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}
+\eqa@def L{\eqa@add{\hb@xt@\z@{$\eqa@style##$\hss}\qquad}\eqa@preamble}
+%    \end{macrocode}
+%
+% The \lit{:} column type is fairly simple.  We set |\tabskip| up to make
+% lots of space and close the current column, because there must be one.^^A
+% \footnote{This is an assumption.}
+%
+%    \begin{macrocode}
+\eqa@def :{%
+  \eqa@addraw{\tabskip\eqacolskip&}\@tempswafalse\eqa@preamble%
+}
+\eqa@def q{\eqa@add{\quad}\@tempswafalse\eqa@preamble}
+%    \end{macrocode}
+%
+% The other column types just insert given text in an appropriate way.
+%
+%    \begin{macrocode}
+\eqa@def >#1{\eqa@add{#1}\@tempswafalse\eqa@preamble}
+\eqa@def <#1{\eqa@addraw{#1}\eqa@preamble}
+%    \end{macrocode}
+%
+% Finally, the magical \lit{!} 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.
+%
+%    \begin{macrocode}
+\eqa@def !#1{%
+  \eqa@addraw{\tabskip\eqacloseskip&\@eqalasttrue#1}\eqa@preamble%
+}
+%    \end{macrocode}
+%
+% \subsubsection{Newline codes}
+%
+% Newline sequences (|\\|) get turned into calls of |\@eqncr|.  The job is
+% fairly simple, really.  However, to avoid reading `|&|' characters
+% prematurely, we set up a magic brace (from the \package{array} package --
+% this avoids creating ord atoms and other nastyness).
+%
+%    \begin{macrocode}
+\def\@eqncr{%
+  \iffalse{\fi\ifnum0=`}\fi%
+  \@ifstar{\eqacr@i{\@M}}{\eqacr@i{\interdisplaylinepenalty}}%
+}
+\def\eqacr@i#1{\@ifnextchar[{\eqacr@ii{#1}}{\eqacr@ii{#1}[\z@]}}
+\def\eqacr@ii#1[#2]{%
+  \ifnum0=`{}\fi%
+  \eqa@eqnum%
+  \noalign{\penalty#1\vskip#2\relax}%
+}
+%    \end{macrocode}
+%
+% \subsubsection{Setting equation numbers}
+%
+% Before we start, we need to generalise the flush-left number handling bits.
+% The macro |\eqa@eqpos| will put its argument in the right place.
+%
+%    \begin{macrocode}
+\if@leqno
+  \def\eqa@eqpos#1{%
+    \hb@[email protected]\p@{}\rlap{\normalfont\normalcolor\hskip-\displaywidth#1}%
+  }
+\else
+  \def\eqa@eqpos#1{\normalfont\normalcolor#1}
+\fi
+%    \end{macrocode}
+%
+% First we need to move into the right column.  Then we just set the equation
+% number appropriately.  There is some subtlety here, ish.  The |\relax| is
+% important, to delay expansion of the |\if|\dots\ until the new column has
+% been started.  The two helper macros are important too, to hide `|&|'s and
+% `|\cr|'s from \TeX's scanner until the right time.
+%
+%    \begin{macrocode}
+\def\eqa@eqnum{%
+  \relax%
+  \if@eqalast\expandafter\eqa@eqnum@i\else\expandafter\eqa@eqnum@ii\fi%
+}
+\def\eqa@eqnum@i{%
+  \if@eqnsw%
+    \eqa@eqpos{(\theequation)}\stepcounter{equation}%
+  \else%
+    \eqa@eqpos\eqa@number%
+  \fi%
+  \global\@eqnswtrue%
+  \cr%
+}
+\def\eqa@eqnum@ii{&\eqa@eqnum}
+%    \end{macrocode}
+%
+% \subsubsection{Numbering control}
+%
+% This is trivial.  We set the |\if@eqnsw| flag to be |false| and store the
+% text in a macro.
+%
+%    \begin{macrocode}
+\let\nonumber\relax
+\newcommand\nonumber[1][]{\global\@eqnswfalse\global\def\eqa@number{#1}}
+%    \end{macrocode}
+%
+% \subsubsection{Closing the environments off}
+%
+% 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%
+  \global\advance\c@equation\m@ne%
+  $$%
+  \global\@ignoretrue%
+}
+\expandafter\let\csname endeqnarray*\endcsname\endeqnarray
+%    \end{macrocode}
+%
+% Now start up the other package again.
+%
+%    \begin{macrocode}
+%</oldeqnarray>
+%<*package>
+%    \end{macrocode}
+%
+% \end{old-eqnarray}
+%
+% That's all there is.  Byebye.
+%
+%    \begin{macrocode}
+%</package>
+%    \end{macrocode}
+%
+% \hfill Mark Wooding, \today
+%
+% \Finale
+\endinput

+ 5444 - 0
docs/packages/mdwtools/mdwtab.dtx

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

+ 82 - 0
docs/packages/mdwtools/mdwtools.ins

@@ -0,0 +1,82 @@
+%
+% $Id$
+%
+% Installer for the mdwtools packages
+%
+% (c) 1996 Mark Wooding
+%
+
+%----- Revision history -----------------------------------------------------
+%
+% $Log$
+% Revision 1.1  1998-09-21 10:19:01  michael
+% Initial implementation
+%
+% Revision 1.3  1996/11/19 20:57:26  mdw
+% Entered into RCS
+%
+
+% --- Licence note ---
+%
+% mdwtools installer
+% Copyright (c) 1996 Mark Wooding
+%
+% This program is free software; you can redistribute it and/or modify
+% it under the terms of the GNU General Public License as published by
+% the Free Software Foundation; either version 2 of the License, or
+% (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+% --- Sort out how to do all this ---
+
+\def\batchfile{mdwtools.ins}
+\input docstrip
+\keepsilent
+
+\preamble
+
+IMPORTANT NOTICE
+\endpreamble
+
+{ % --- This is a group so that docstrip \reads it all in one go ---
+
+  \ifx\generate\mdwxxnotdef
+    \gdef\mdwgen#1{#1}
+    \gdef\mdwf#1#2{\generateFile{#1}{n}{#2}}
+    \gdef\needed#1{}
+  \else
+    \global\let\mdwgen\generate
+    \global\def\mdwf{\file}
+    \global\askforoverwritefalse
+  \fi
+
+}
+
+\mdwgen{\mdwf {at.sty}		{\from {at.dtx}	      {package}}
+	\mdwf {mdwlist.sty}	{\from {mdwlist.dtx}  {package}}
+	\mdwf {mdwtab.sty}	{\from {mdwtab.dtx}   {mdwtab}
+				 \needed{syntax.dtx}
+				 \from {footnote.dtx} {macro}
+				 \from {doafter.dtx}  {macro}}
+	\mdwf {syntax.sty}	{\from {syntax.dtx}   {package}
+				 \from {doafter.dtx}  {macro}}
+	\mdwf {mathenv.sty}	{\from {mdwtab.dtx}   {mathenv}}
+	\mdwf {mdwmath.sty}	{\from {mdwmath.dtx}  {package}}
+	\mdwf {sverb.sty}	{\from {sverb.dtx}    {package}}
+	\mdwf {footnote.sty}	{\from {footnote.dtx} {package}}
+	\mdwf {doafter.sty}	{\from {doafter.dtx}  {package,latex2e}}
+	\mdwf {doafter.tex}	{\from {doafter.dtx}  {package,plain}}
+	\mdwf {cmtt.sty}	{\from {cmtt.dtx}     {sty}}
+	\mdwf {mTTenc.def}	{\from {cmtt.dtx}     {def}}
+	\mdwf {mTTcmtt.fd}	{\from {cmtt.dtx}     {fd}}
+}
+
+\Msg{Done!}

+ 1215 - 0
docs/packages/mdwtools/mdwtools.tex

@@ -0,0 +1,1215 @@
+% \begin{meta-comment}
+%
+% $Id$
+%
+% Common declarations for mdwtools.dtx files
+%
+% (c) 1996 Mark Wooding
+%
+%----- Revision history -----------------------------------------------------
+%
+% $Log$
+% Revision 1.1  1998-09-21 10:19:01  michael
+% Initial implementation
+%
+% Revision 1.4  1996/11/19 20:55:55  mdw
+% Entered into RCS
+%
+%
+% \end{meta-comment}
+%
+% \begin{meta-comment} <general public licence>
+%%
+%% mdwtools common declarations
+%% Copyright (c) 1996 Mark Wooding
+%%
+%% This program is free software; you can redistribute it and/or modify
+%% it under the terms of the GNU General Public License as published by
+%% the Free Software Foundation; either version 2 of the License, or
+%% (at your option) any later version.
+%%
+%% This program is distributed in the hope that it will be useful,
+%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+%% GNU General Public License for more details.
+%%
+%% You should have received a copy of the GNU General Public License
+%% along with this program; if not, write to the Free Software
+%% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+%%
+% \end{meta-comment}
+%
+% \begin{meta-comment} <file preamble>
+%<*mdwtools>
+\ProvidesFile{mdwtools.tex}
+             [1996/05/10 1.4 Shared definitions for mdwtools .dtx files]
+%</mdwtools>
+% \end{meta-comment}
+%
+% \CheckSum{668}
+%% \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         \~}
+%%
+%
+% \section{Introduction and user guide}
+%
+% This file is really rather strange; it gets |\input| by other package
+% documentation files to set up most of the environmental gubbins for them.
+% It handles almost everything, like loading a document class, finding any
+% packages, and building and formatting the title.
+%
+% It also offers an opportunity for users to customise my nice documentation,
+% by using a |mdwtools.cfg| file (not included).
+%
+%
+% \subsection{Declarations}
+%
+% A typical documentation file contains something like
+% \begin{listinglist} \listingsize \obeylines
+% |\input{mdwtools}|
+% \<declarations>
+% |\mdwdoc|
+% \end{listinglist}
+% The initial |\input| reads in this file and sets up the various commands
+% which may be needed.  The final |\mdwdoc| actually starts the document,
+% inserting a title (which is automatically generated), a table of
+% contents etc., and reads the documentation file in (using the |\DocInput|
+% command from the \package{doc} package.
+%
+% \subsubsection{Describing packages}
+%
+% \DescribeMacro{\describespackage}
+% \DescribeMacro{\describesclass}
+% \DescribeMacro{\describesfile}
+% \DescribeMacro{\describesfile*}
+% The most important declarations are those which declare what the
+% documentation describes.  Saying \syntax{"\\describespackage{<package>}"}
+% loads the \<package> (if necessary) and adds it to the auto-generated
+% title, along with a footnote containing version information.  Similarly,
+% |\describesclass| adds a document class name to the title (without loading
+% it -- the document itself must do this, with the |\documentclass| command).
+% For files which aren't packages or classes, use the |\describesfile| or
+% |\describesfile*| command (the $*$-version won't |\input| the file, which
+% is handy for files like |mdwtools.tex|, which are already input).
+%
+% \DescribeMacro{\author}
+% \DescribeMacro{\date}
+% \DescribeMacro{\title}
+% The |\author|, |\date| and |\title| declarations work slightly differently
+% to normal -- they ensure that only the \emph{first} declaration has an
+% effect.  (Don't you play with |\author|, please, unless you're using this
+% program to document your own packages.)  Using |\title| suppresses the
+% automatic title generation.
+%
+% \DescribeMacro{\docdate}
+% The default date is worked out from the version string of the package or
+% document class whose name is the same as that of the documentation file.
+% You can choose a different `main' file by saying
+% \syntax{"\\docdate{"<file>"}"}.
+%
+% \subsubsection{Contents handling}
+%
+% \DescribeMacro{\addcontents}
+% A documentation file always has a table of contents.  Other
+% contents-like lists can be added by saying
+% \syntax{"\\addcontents{"<extension>"}{"<command>"}"}.  The \<extension>
+% is the file extension of the contents file (e.g., \lit{lot} for the
+% list of tables); the \<command> is the command to actually typeset the
+% contents file (e.g., |\listoftables|).
+%
+% \subsubsection{Other declarations}
+%
+% \DescribeMacro{\implementation}
+% The \package{doc} package wants you to say
+% \syntax{"\\StopEventually{"<stuff>"}"}' before describing the package
+% implementation.  Using |mdwtools.tex|, you just say |\implementation|, and
+% everything works.  It will automatically read in the licence text (from
+% |gpl.tex|, and wraps some other things up.
+%
+% 
+% \subsection{Other commands}
+%
+% The |mdwtools.tex| file includes the \package{syntax} and \package{sverb}
+% packages so that they can be used in documentation files.  It also defines
+% some trivial commands of its own.
+%
+% \DescribeMacro{\<}
+% Saying \syntax{"\\<"<text>">" is the same as "\\synt{"<text>"}"}; this
+% is a simple abbreviation.
+%
+% \DescribeMacro{\smallf}
+% Saying \syntax{"\\smallf" <number>"/"<number>} typesets a little fraction,
+% like this: \smallf 3/4.  It's useful when you want to say that the default
+% value of a length is 2 \smallf 1/2\,pt, or something like that.
+%
+%
+% \subsection{Customisation}
+%
+% You can customise the way that the package documentation looks by writing
+% a file called |mdwtools.cfg|.  You can redefine various commands (before
+% they're defined here, even; |mdwtools.tex| checks most of the commands that
+% it defines to make sure they haven't been defined already.
+%
+% \DescribeMacro{\indexing}
+% If you don't want the prompt about whether to generate index files, you
+% can define the |\indexing| command to either \lit{y} or \lit{n}.  I'd
+% recommend that you use |\providecommand| for this, to allow further
+% customisation from the command line.
+%
+% \DescribeMacro{\mdwdateformat}
+% If you don't like my date format (maybe you're American or something),
+% you can redefine the |\mdwdateformat| command.  It takes three arguments:
+% the year, month and date, as numbers; it should expand to something which
+% typesets the date nicely.  The default format gives something like
+% `10 May 1996'.  You can produce something rather more exotic, like
+% `10\textsuperscript{th} May \textsc{\romannumeral 1996}' by saying
+%\begin{listing}
+%\newcommand{\mdwdateformat}[3]{%
+%  \number#3\textsuperscript{\numsuffix{#3}}\ %
+%  \monthname{#2}\ %
+%  \textsc{\romannumeral #1}%
+%}
+%\end{listing}
+% \DescribeMacro{\monthname}
+% \DescribeMacro{\numsuffix}
+% Saying \syntax{"\\monthname{"<number>"}"} expands to the name of the
+% numbered month (which can be useful when doing date formats).  Saying
+% \syntax{"\\numsuffix{"<number>"}"} will expand to the appropriate suffix
+% (`th' or `rd' or whatever) for the \<number>.  You'll have to superscript
+% it yourself, if this is what you want to do.  Putting the year number
+% in roman numerals is just pretentious |;-)|.
+%
+% \DescribeMacro{\mdwhook}
+% After all the declarations in |mdwtools.tex|, the command |\mdwhook| is
+% executed, if it exists.  This can be set up by the configuration file
+% to do whatever you want.
+%
+% There are lots of other things you can play with; you should look at the
+% implementation section to see what's possible.
+%
+% \implementation
+%
+% \section{Implementation}
+%
+%    \begin{macrocode}
+%<*mdwtools>
+%    \end{macrocode}
+%
+% The first thing is that I'm not a \LaTeX\ package or anything official
+% like that, so I must enable `|@|' as a letter by hand.
+%
+%    \begin{macrocode}
+\makeatletter
+%    \end{macrocode}
+%
+% Now input the user's configuration file, if it exists.  This is fairly
+% simple stuff.
+%
+%    \begin{macrocode}
+\@input{mdwtools.cfg}
+%    \end{macrocode}
+%
+% Well, that's the easy bit done.
+%
+%
+% \subsection{Initialisation}
+%
+% Obviously the first thing to do is to obtain a document class.  Obviously,
+% it would be silly to do this if a document class has already been loaded,
+% either by the package documentation or by the configuration file.
+%
+% The only way I can think of for finding out if a document class is already
+% loaded is by seeing if the |\documentclass| command has been redefined
+% to raise an error.  This isn't too hard, really.
+%
+%    \begin{macrocode}
+\ifx\documentclass\@twoclasseserror\else
+  \documentclass[a4paper]{ltxdoc}
+  \ifx\doneclasses\mdw@undefined\else\doneclasses\fi
+\fi
+%    \end{macrocode}
+%
+% As part of my standard environment, I'll load some of my more useful
+% packages.  If they're already loaded (possibly with different options),
+% I'll not try to load them again.
+%
+%    \begin{macrocode}
+\@ifpackageloaded{doc}{}{\usepackage{doc}}
+\@ifpackageloaded{syntax}{}{\usepackage[rounded]{syntax}}
+\@ifpackageloaded{sverb}{}{\usepackage{sverb}}
+%    \end{macrocode}
+%
+%
+% \subsection{Some macros for interaction}
+%
+% I like the \LaTeX\ star-boxes, although it's a pain having to cope with
+% \TeX's space-handling rules.  I'll define a new typing-out macro which
+% makes spaces more significant, and has a $*$-version which doesn't put
+% a newline on the end, and interacts prettily with |\read|.
+%
+% First of all, I need to make spaces active, so I can define things about
+% active spaces.
+%
+%    \begin{macrocode}
+\begingroup\obeyspaces
+%    \end{macrocode}
+%
+% Now to define the main macro.  This is easy stuff.  Spaces must be
+% carefully rationed here, though.
+%
+% I'll start a group, make spaces active, and make spaces expand to ordinary
+% space-like spaces.  Then I'll look for a star, and pass either |\message|
+% (which doesn't start a newline, and interacts with |\read| well) or
+% |\immediate\write 16| which does a normal write well.
+%
+%    \begin{macrocode}
+\gdef\mdwtype{%
+\begingroup\catcode`\ \active\let \space%
+\@ifstar{\mdwtype@i{\message}}{\mdwtype@i{\immediate\write\sixt@@n}}%
+}
+\endgroup
+%    \end{macrocode}
+%
+% Now for the easy bit.  I have the thing to do, and the thing to do it to,
+% so do that and end the group.
+%
+%    \begin{macrocode}
+\def\mdwtype@i#1#2{#1{#2}\endgroup}
+%    \end{macrocode}
+%
+%
+% \subsection{Decide on indexing}
+%
+% A configuration file can decide on indexing by defining the |\indexing|
+% macro to either \lit{y} or \lit{n}.  If it's not set, then I'll prompt
+% the user.
+%
+% First of all, I want a switch to say whether I'm indexing.
+%
+%    \begin{macrocode}
+\newif\ifcreateindex
+%    \end{macrocode}
+%
+% Right: now I need to decide how to make progress.  If the macro's not set,
+% then I want to set it, and start a row of stars.
+%
+%    \begin{macrocode}
+\ifx\indexing\@@undefined
+  \mdwtype{*****************************}
+  \def\indexing{?}
+\fi
+%    \end{macrocode}
+%
+% Now enter a loop, asking the user whether to do indexing, until I get
+% a sensible answer.
+%
+%    \begin{macrocode}
+\loop
+  \@tempswafalse
+  \if y\indexing\@tempswatrue\createindextrue\fi
+  \if Y\indexing\@tempswatrue\createindextrue\fi
+  \if n\indexing\@tempswatrue\createindexfalse\fi
+  \if N\indexing\@tempswatrue\createindexfalse\fi
+  \if@tempswa\else
+  \mdwtype*{* Create index files? (y/n) *}
+  \read\sixt@@n to\indexing%
+\repeat
+%    \end{macrocode}
+%
+% Now, based on the results of that, display a message about the indexing.
+%
+%    \begin{macrocode}
+\mdwtype{*****************************}
+\ifcreateindex
+  \mdwtype{* Creating index files      *}
+  \mdwtype{* This may take some time   *}
+\else
+  \mdwtype{* Not creating index files  *}
+\fi
+\mdwtype{*****************************}
+%    \end{macrocode}
+%
+% Now I can play with the indexing commands of the \package{doc} package
+% to do whatever it is that the user wants.
+%
+%    \begin{macrocode}
+\ifcreateindex
+  \CodelineIndex
+  \EnableCrossrefs
+\else
+  \CodelineNumbered
+  \DisableCrossrefs
+\fi
+%    \end{macrocode}
+%
+% And register lots of plain \TeX\ things which shouldn't be indexed.
+% This contains lots of |\if|\dots\ things which don't fit nicely in
+% conditionals, which is a shame.  Still, it doesn't matter that much,
+% really.
+%
+%    \begin{macrocode}
+\DoNotIndex{\def,\long,\edef,\xdef,\gdef,\let,\global}
+\DoNotIndex{\if,\ifnum,\ifdim,\ifcat,\ifmmode,\ifvmode,\ifhmode,%
+            \iftrue,\iffalse,\ifvoid,\ifx,\ifeof,\ifcase,\else,\or,\fi}
+\DoNotIndex{\box,\copy,\setbox,\unvbox,\unhbox,\hbox,%
+            \vbox,\vtop,\vcenter}
+\DoNotIndex{\@empty,\immediate,\write}
+\DoNotIndex{\egroup,\bgroup,\expandafter,\begingroup,\endgroup}
+\DoNotIndex{\divide,\advance,\multiply,\count,\dimen}
+\DoNotIndex{\relax,\space,\string}
+\DoNotIndex{\csname,\endcsname,\@spaces,\openin,\openout,%
+            \closein,\closeout}
+\DoNotIndex{\catcode,\endinput}
+\DoNotIndex{\jobname,\message,\read,\the,\m@ne,\noexpand}
+\DoNotIndex{\hsize,\vsize,\hskip,\vskip,\kern,\hfil,\hfill,\hss}
+\DoNotIndex{\m@ne,\z@,\z@skip,\@ne,\tw@,\p@}
+\DoNotIndex{\dp,\wd,\ht,\vss,\unskip}
+%    \end{macrocode}
+%
+% Last bit of indexing stuff, for now: I'll typeset the index in two columns
+% (the default is three, which makes them too narrow for my tastes).
+%
+%    \begin{macrocode}
+\setcounter{IndexColumns}{2}
+%    \end{macrocode}
+%
+%
+% \subsection{Selectively defining things}
+%
+% I don't want to tread on anyone's toes if they redefine any of these
+% commands and things in a configuration file.  The following definitions
+% are fairly evil, but should do the job OK.
+%
+% \begin{macro}{\@gobbledef}
+%
+% This macro eats the following |\def|inition, leaving not a trace behind.
+%
+%    \begin{macrocode}
+\def\@gobbledef#1#{\@gobble}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\tdef}
+% \begin{macro}{\tlet}
+%
+% The |\tdef| command is a sort of `tentative' definition -- it's like
+% |\def| if the control sequence named doesn't already have a definition.
+% |\tlet| does the same thing with |\let|.
+%
+%    \begin{macrocode}
+\def\tdef#1{
+  \ifx#1\@@undefined%
+    \expandafter\def\expandafter#1%
+  \else%
+    \expandafter\@gobbledef%
+  \fi%
+}
+\def\tlet#1#2{\ifx#1\@@undefined\let#1=#2\fi}
+%    \end{macrocode}
+%
+% \end{macro}
+% \end{macro}
+%
+%
+% \subsection{General markup things}
+%
+% Now for some really simple things.  I'll define how to typeset package
+% names and environment names (both in the sans serif font, for now).
+%
+%    \begin{macrocode}
+\tlet\package\textsf
+\tlet\env\textsf
+%    \end{macrocode}
+%
+% I'll define the |\<|\dots|>| shortcut for syntax items suggested in the
+% \package{syntax} package.
+%
+%    \begin{macrocode}
+\tdef\<#1>{\synt{#1}}
+%    \end{macrocode}
+%
+% And because it's used in a few places (mainly for typesetting lengths),
+% here's a command for typesetting fractions in text.
+%
+%    \begin{macrocode}
+\tdef\smallf#1/#2{\ensuremath{^{#1}\!/\!_{#2}}}
+%    \end{macrocode}
+%
+%
+% \subsection{A table environment}
+%
+% \begin{environment}{tab}
+%
+% Most of the packages don't use the (obviously perfect) \package{mdwtab}
+% package, because it's big, and takes a while to load.  Here's an
+% environment for typesetting centred tables.  The first (optional) argument
+% is some declarations to perform.  The mandatory argument is the table
+% preamble (obviously).
+%
+%    \begin{macrocode}
+\@ifundefined{tab}{%
+  \newenvironment{tab}[2][\relax]{%
+    \par\vskip2ex%
+    \centering%
+    #1%
+    \begin{tabular}{#2}%
+  }{%
+    \end{tabular}%
+    \par\vskip2ex%
+  }
+}{}
+%    \end{macrocode}
+%
+% \end{environment}
+%
+%
+% \subsection{Commenting out of stuff}
+%
+% \begin{environment}{meta-comment}
+%
+% Using |\iffalse|\dots|\fi| isn't much fun.  I'll define a gobbling
+% environment using the \package{sverb} stuff.
+%
+%    \begin{macrocode}
+\ignoreenv{meta-comment}
+%    \end{macrocode}
+%
+% \end{environment}
+%
+%
+% \subsection{Float handling}
+%
+% This gubbins will try to avoid float pages as much as possible, and (with
+% any luck) encourage floats to be put on the same pages as text.
+%
+%    \begin{macrocode}
+\def\textfraction{0.1}
+\def\topfraction{0.9}
+\def\bottomfraction{0.9}
+\def\floatpagefraction{0.7}
+%    \end{macrocode}
+%
+% Now redefine the default float-placement parameters to allow `here' floats.
+%
+%    \begin{macrocode}
+\def\fps@figure{htbp}
+\def\fps@table{htbp}
+%    \end{macrocode}
+%
+%
+% \subsection{Other bits of parameter tweaking}
+%
+% Make \env{grammar} environments look pretty, by indenting the left hand
+% sides by a large amount.
+%
+%    \begin{macrocode}
+\grammarindent1in
+%    \end{macrocode}
+%
+% I don't like being told by \TeX\ that my paragraphs are hard to linebreak:
+% I know this already.  This lot should shut \TeX\ up about most problems.
+%
+%    \begin{macrocode}
+\sloppy
+\hbadness\@M
+\hfuzz10\p@
+%    \end{macrocode}
+%
+% Also make \TeX\ shut up in the index.  The \package{multicol} package
+% irritatingly plays with |\hbadness|.  This is the best hook I could find
+% for playing with this setting.
+%
+%    \begin{macrocode}
+\expandafter\def\expandafter\IndexParms\expandafter{%
+  \IndexParms%
+  \hbadness\@M%
+}
+%    \end{macrocode}
+%
+% The other thing I really don't like is `Marginpar moved' warnings.  This
+% will get rid of them, and lots of other \LaTeX\ warnings at the same time.
+%
+%    \begin{macrocode}
+\let\@latex@warning@no@line\@gobble
+%    \end{macrocode}
+%
+% Put some extra space between table rows, please.
+%
+%    \begin{macrocode}
+\def\arraystretch{1.2}
+%    \end{macrocode}
+%
+% Most of the code is at guard level one, so typeset that in upright text.
+%
+%    \begin{macrocode}
+\setcounter{StandardModuleDepth}{1}
+%    \end{macrocode}
+%
+%
+% \subsection{Contents handling}
+%
+% I use at least one contents file (the main table of contents) although
+% I may want more.  I'll keep a list of contents files which I need to
+% handle.
+%
+% There are two things I need to do to contents files here:
+% \begin{itemize}
+% \item I must typeset the table of contents at the beginning of the
+%       document; and
+% \item I want to typeset tables of contents in two columns (using the
+%       \package{multicol} package).
+% \end{itemize}
+%
+% The list consists of items of the form
+% \syntax{"\\do{"<extension>"}{"<command>"}"}, where \<extension> is the
+% file extension of the contents file, and \<command> is the command to
+% typeset it.
+%
+% \begin{macro}{\docontents}
+%
+% This is where I keep the list of contents files.  I'll initialise it to
+% just do the standard contents table.
+%
+%    \begin{macrocode}
+\def\docontents{\do{toc}{\tableofcontents}}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\addcontents}
+%
+% By saying \syntax{"\\addcontents{"<extension>"}{"<command>"}"}, a document
+% can register a new table of contents which gets given the two-column
+% treatment properly.  This is really easy to implement.
+%
+%    \begin{macrocode}
+\def\addcontents#1#2{%
+  \toks@\expandafter{\docontents\do{#1}{#2}}%
+  \edef\docontents{\the\toks@}%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+%
+% \subsection{Finishing it all off}
+%
+% \begin{macro}{\finalstuff}
+%
+% The |\finalstuff| macro is a hook for doing things at the end of the
+% document.  Currently, it inputs the licence agreement as an appendix.
+%
+%    \begin{macrocode}
+\tdef\finalstuff{\appendix\part*{Appendix}\input{gpl}}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\implementation}
+%
+% The |\implementation| macro starts typesetting the implementation of
+% the package(s).  If we're not doing the implementation, it just does
+% this lot and ends the input file.
+%
+% I define a macro with arguments inside the |\StopEventually|, which causes
+% problems, since the code gets put through an extra level of |\def|fing
+% depending on whether the implementation stuff gets typeset or not.  I'll
+% store the code I want to do in a separate macro.
+%
+%    \begin{macrocode}
+\def\implementation{\StopEventually{\attheend}}
+%    \end{macrocode}
+%
+% Now for the actual activity.  First, I'll do the |\finalstuff|.  Then, if
+% \package{doc}'s managed to find the \package{multicol} package, I'll add
+% the end of the environment to the end of each contents file in the list.
+% Finally, I'll read the index in from its formatted |.ind| file.
+%
+%    \begin{macrocode}
+\tdef\attheend{%
+  \finalstuff%
+  \ifhave@multicol%
+    \def\do##1##2{\addtocontents{##1}{\protect\end{multicols}}}%
+    \docontents%
+  \fi%
+  \PrintIndex%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+%
+% \subsection{File version information}
+%
+% \begin{macro}{\mdwpkginfo}
+%
+% For setting up the automatic titles, I'll need to be able to work out
+% file versions and things.  This macro will, given a file name, extract
+% from \LaTeX\ the version information and format it into a sensible string.
+%
+% First of all, I'll put the original string (direct from the
+% |\Provides|\dots\ command).  Then I'll pass it to another macro which can
+% parse up the string into its various bits, along with the original
+% filename.
+%
+%    \begin{macrocode}
+\def\mdwpkginfo#1{%
+  \edef\@tempa{\csname ver@#1\endcsname}%
+  \expandafter\mdwpkginfo@i\@tempa\@@#1\@@%
+}
+%    \end{macrocode}
+%
+% Now for the real business.  I'll store the string I build in macros called
+% \syntax{"\\"<filename>"date", "\\"<filename>"version" and
+% "\\"<filename>"info"}, which store the file's date, version and
+% `information string' respectively.  (Note that the file extension isn't
+% included in the name.)
+%
+% This is mainly just tedious playing with |\expandafter|.  The date format
+% is defined by a separate macro, which can be modified from the
+% configuration file.
+%
+%    \begin{macrocode}
+\def\mdwpkginfo@i#1/#2/#3 #4 #5\@@#6.#7\@@{%
+  \expandafter\def\csname #6date\endcsname%
+    {\protect\mdwdateformat{#1}{#2}{#3}}%
+  \expandafter\def\csname #6version\endcsname{#4}%
+  \expandafter\def\csname #6info\endcsname{#5}%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\mdwdateformat}
+%
+% Given three arguments, a year, a month and a date (all numeric), build a
+% pretty date string.  This is fairly simple really.
+%
+%    \begin{macrocode}
+\tdef\mdwdateformat#1#2#3{\number#3\ \monthname{#2}\ \number#1}
+\def\monthname#1{%
+  \ifcase#1\or%
+     January\or February\or March\or April\or May\or June\or%
+     July\or August\or September\or October\or November\or December%
+  \fi%
+}
+\def\numsuffix#1{%
+  \ifnum#1=1 st\else%
+  \ifnum#1=2 nd\else%
+  \ifnum#1=3 rd\else%
+  \ifnum#1=21 st\else%
+  \ifnum#1=22 nd\else%
+  \ifnum#1=23 rd\else%
+  \ifnum#1=31 st\else%
+  th%
+  \fi\fi\fi\fi\fi\fi\fi%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\mdwfileinfo}
+%
+% Saying \syntax{"\\mdwfileinfo{"<file-name>"}{"<info>"}"} extracts the
+% wanted item of \<info> from the version information for file \<file-name>.
+%
+%    \begin{macrocode}
+\def\mdwfileinfo#1#2{\mdwfileinfo@i{#2}#1.\@@}
+\def\mdwfileinfo@i#1#2.#3\@@{\csname#2#1\endcsname}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+%
+% \subsection{List handling}
+%
+% There are several other lists I need to build.  These macros will do
+% the necessary stuff.
+%
+% \begin{macro}{\mdw@ifitem}
+%
+% The macro \syntax{"\\mdw@ifitem"<item>"\\in"<list>"{"<true-text>"}"^^A
+% "{"<false-text>"}"} does \<true-text> if the \<item> matches any item in
+% the \<list>; otherwise it does \<false-text>.
+%
+%    \begin{macrocode}
+\def\mdw@ifitem#1\in#2{%
+  \@tempswafalse%
+  \def\@tempa{#1}%
+  \def\do##1{\def\@tempb{##1}\ifx\@tempa\@tempb\@tempswatrue\fi}%
+  #2%
+  \if@tempswa\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\mdw@append}
+%
+% Saying \syntax{"\\mdw@append"<item>"\\to"<list>} adds the given \<item>
+% to the end of the given \<list>.
+%
+%    \begin{macrocode}
+\def\mdw@append#1\to#2{%
+  \toks@{\do{#1}}%
+  \toks\tw@\expandafter{#2}%
+  \edef#2{\the\toks\tw@\the\toks@}%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\mdw@prepend}
+%
+% Saying \syntax{"\\mdw@prepend"<item>"\\to"<list>} adds the \<item> to the
+% beginning of the \<list>.
+%
+%    \begin{macrocode}
+\def\mdw@prepend#1\to#2{%
+  \toks@{\do{#1}}%
+  \toks\tw@\expandafter{#2}%
+  \edef#2{\the\toks@\the\toks\tw@}%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\mdw@add}
+%
+% Finally, saying \syntax{"\\mdw@add"<item>"\\to"<list>} adds the \<item>
+% to the list only if it isn't there already.
+%
+%    \begin{macrocode}
+\def\mdw@add#1\to#2{\mdw@ifitem#1\in#2{}{\mdw@append#1\to#2}}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+%
+% \subsection{Described file handling}
+%
+% I'l maintain lists of packages, document classes, and other files
+% described by the current documentation file.
+%
+% First of all, I'll declare the various list macros.
+%
+%    \begin{macrocode}
+\def\dopackages{}
+\def\doclasses{}
+\def\dootherfiles{}
+%    \end{macrocode}
+%
+% \begin{macro}{\describespackage}
+%
+% A document file can declare that it describes a package by saying
+% \syntax{"\\describespackage{"<package-name>"}"}.  I add the package to
+% my list, read the package into memory (so that the documentation can
+% offer demonstrations of it) and read the version information.
+%
+%    \begin{macrocode}
+\def\describespackage#1{%
+  \mdw@ifitem#1\in\dopackages{}{%
+    \mdw@append#1\to\dopackages%
+    \usepackage{#1}%
+    \mdwpkginfo{#1.sty}%
+  }%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\describesclass}
+%
+% By saying \syntax{"\\describesclass{"<class-name>"}"}, a document file
+% can declare that it describes a document class.  I'll assume that the
+% document class is already loaded, because it's much too late to load
+% it now.
+%
+%    \begin{macrocode}
+\def\describesclass#1{\mdw@add#1\to\doclasses\mdwpkginfo{#1.cls}}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\describesfile}
+%
+% Finally, other `random' files, which don't have the status of real \LaTeX\
+% packages or document classes, can be described by saying \syntax{^^A
+% "\\describesfile{"<file-name>"}" or "\\describesfile*{"<file-name>"}"}.
+% The difference is that the starred version will not |\input| the file.
+%
+%    \begin{macrocode}
+\def\describesfile{%
+  \@ifstar{\describesfile@i\@gobble}{\describesfile@i\input}%
+}
+\def\describesfile@i#1#2{%
+  \mdw@ifitem#2\in\dootherfiles{}{%
+    \mdw@add#2\to\dootherfiles%
+    #1{#2}%
+    \mdwpkginfo{#2}%
+  }%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+%
+% \subsection{Author and title handling}
+%
+% I'll redefine the |\author| and |\title| commands so that I get told
+% whether I need to do it myself.
+%
+% \begin{macro}{\author}
+%
+% This is easy: I'll save the old meaning, and then redefine |\author| to
+% do the old thing and redefine itself to then do nothing.
+%
+%    \begin{macrocode}
+\let\mdw@author\author
+\def\author{\let\author\@gobble\mdw@author}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\title}
+%
+% And oddly enough, I'll do exactly the same thing for the title, except
+% that I'll also disable the |\mdw@buildtitle| command, which constructs
+% the title automatically.
+%
+%    \begin{macrocode}
+\let\mdw@title\title
+\def\title{\let\title\@gobble\let\mdw@buildtitle\relax\mdw@title}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\date}
+%
+% This works in a very similar sort of way.
+%
+%    \begin{macrocode}
+\def\date#1{\let\date\@gobble\def\today{#1}}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\datefrom}
+%
+% Saying \syntax{"\\datefrom{"<file-name>"}"} sets the document date from
+% the given filename.
+%
+%    \begin{macrocode}
+\def\datefrom#1{%
+  \protected@edef\@tempa{\noexpand\date{\csname #1date\endcsname}}%
+  \@tempa%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\docfile}
+%
+% Saying \syntax{"\\docfile{"<file-name>"}"} sets up the file name from which
+% documentation will be read.
+%
+%    \begin{macrocode}
+\def\docfile#1{%
+  \def\@tempa##1.##2\@@{\def\@basefile{##1.##2}\def\@basename{##1}}%
+  \edef\@tempb{\noexpand\@tempa#1\noexpand\@@}%
+  \@tempb%
+}
+%    \end{macrocode}
+%
+% I'll set up a default value as well.
+%
+%    \begin{macrocode}
+\docfile{\jobname.dtx}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+%
+% \subsection{Building title strings}
+%
+% This is rather tricky.  For each list, I need to build a legible looking
+% string.
+%
+% \begin{macro}{\mdw@addtotitle}
+%
+% By saying
+%\syntax{"\\mdw@addtotitle{"<list>"}{"<command>"}{"<singular>"}{"<plural>"}"}
+% I can add the contents of a list to the current title string in the
+% |\mdw@title| macro.
+%
+%    \begin{macrocode}
+\tdef\mdw@addtotitle#1#2#3#4{%
+%    \end{macrocode}
+%
+% Now to get to work.  I need to keep one `lookahead' list item, and a count
+% of the number of items read so far.  I'll keep the lookahead item in
+% |\@nextitem| and the counter in |\count@|.
+%
+%    \begin{macrocode}
+  \count@\z@%
+%    \end{macrocode}
+%
+% Now I'll define what to do for each list item.  The |\protect| command is
+% already set up appropriately for playing with |\edef| commands.
+%
+%    \begin{macrocode}
+  \def\do##1{%
+%    \end{macrocode}
+%
+% The first job is to add the previous item to the title string.  If this
+% is the first item, though, I'll just add the appropriate \lit{The } or
+% \lit{ and the } string to the title (this is stored in the |\@prefix|
+% macro).
+%
+%    \begin{macrocode}
+    \edef\mdw@title{%
+      \mdw@title%
+      \ifcase\count@\@prefix%
+      \or\@nextitem%
+      \else, \@nextitem%
+      \fi%
+    }%
+%    \end{macrocode}
+%
+% That was rather easy.  Now I'll set up the |\@nextitem| macro for the
+% next time around the loop.
+%
+%    \begin{macrocode}
+    \edef\@nextitem{%
+      \protect#2{##1}%
+      \protect\footnote{%
+        The \protect#2{##1} #3 is currently at version %
+        \mdwfileinfo{##1}{version}, dated \mdwfileinfo{##1}{date}.%
+      }\space%
+    }%
+%    \end{macrocode}
+%
+% Finally, I need to increment the counter.
+%
+%    \begin{macrocode}
+    \advance\count@\@ne%
+  }%
+%    \end{macrocode}
+%
+% Now execute the list.
+%
+%    \begin{macrocode}
+  #1%
+%    \end{macrocode}
+%
+% I still have one item left over, unless the list was empty.  I'll add
+% that now.
+%
+%    \begin{macrocode}
+  \edef\mdw@title{%
+    \mdw@title%
+    \ifcase\count@%
+    \or\@nextitem\space#3%
+    \or\ and \@nextitem\space#4%
+    \fi%
+  }%
+%    \end{macrocode}
+%
+% Finally, if $|\count@| \ne 0$, I must set |\@prefix| to \lit{ and the }.
+%
+%    \begin{macrocode}
+  \ifnum\count@>\z@\def\@prefix{ and the }\fi%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\mdw@buildtitle}
+%
+% This macro will actually do the job of building the title string.
+%
+%    \begin{macrocode}
+\tdef\mdw@buildtitle{%
+%    \end{macrocode}
+%
+% First of all, I'll open a group to avoid polluting the namespace with
+% my gubbins (although the code is now much tidier than it has been in
+% earlier releases).
+%
+%    \begin{macrocode}
+  \begingroup%
+%    \end{macrocode}
+%
+% The title building stuff makes extensive use of |\edef|.  I'll set
+% |\protect| appropriately.  (For those not in the know,
+% |\@unexpandable@protect| expands to `|\noexpand\protect\noexpand|',
+% which prevents expansion of the following macro, and inserts a |\protect|
+% in front of it ready for the next |\edef|.)
+%
+%    \begin{macrocode}
+  \let\@@protect\protect\let\protect\@unexpandable@protect%
+%    \end{macrocode}
+%
+% Set up some simple macros ready for the main code.
+%
+%    \begin{macrocode}
+  \def\mdw@title{}%
+  \def\@prefix{The }%
+%    \end{macrocode}
+%
+% Now build the title.  This is fun.
+%
+%    \begin{macrocode}
+  \mdw@addtotitle\dopackages\package{package}{packages}%
+  \mdw@addtotitle\doclasses\package{document class}{document classes}%
+  \mdw@addtotitle\dootherfiles\texttt{file}{files}%
+%    \end{macrocode}
+%
+% Now I want to end the group and set the title from my string.  The
+% following hacking will do this.
+%
+%    \begin{macrocode}
+  \edef\next{\endgroup\noexpand\title{\mdw@title}}%
+  \next%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+%
+% \subsection{Starting the main document}
+%
+% \begin{macro}{\mdwdoc}
+%
+% Once the document preamble has done all of its stuff, it calls the
+% |\mdwdoc| command, which takes over and really starts the documentation
+% going.
+%
+%    \begin{macrocode}
+\def\mdwdoc{%
+%    \end{macrocode}
+%
+% First, I'll construct the title string.
+%
+%    \begin{macrocode}
+  \mdw@buildtitle%
+  \author{Mark Wooding}%
+%    \end{macrocode}
+%
+% Set up the date string based on the date of the package which shares
+% the same name as the current file.
+%
+%    \begin{macrocode}
+  \datefrom\@basename%
+%    \end{macrocode}
+%
+% Set up verbatim characters after all the packages have started.
+%
+%    \begin{macrocode}
+  \shortverb\|%
+  \shortverb\"%
+%    \end{macrocode}
+%
+% Start the document, and put the title in.
+%
+%    \begin{macrocode}
+  \begin{document}
+  \maketitle%
+%    \end{macrocode}
+%
+% This is nasty.  It makes maths displays work properly in demo environments.
+% \emph{The \LaTeX\ Companion} exhibits the bug which this hack fixes.  So
+% ner.
+%
+%    \begin{macrocode}
+  \abovedisplayskip\z@%
+%    \end{macrocode}
+%
+% Now start the contents tables.  After starting each one, I'll make it
+% be multicolumnar.
+%
+%    \begin{macrocode}
+  \def\do##1##2{%
+    ##2%
+    \ifhave@multicol\addtocontents{##1}{%
+      \protect\begin{multicols}{2}%
+      \hbadness\@M%
+    }\fi%
+  }%
+  \docontents%
+%    \end{macrocode}
+%
+% Input the main file now.
+%
+%    \begin{macrocode}
+  \DocInput{\@basefile}%
+%    \end{macrocode}
+%
+% That's it.  I'm done.
+%
+%    \begin{macrocode}
+  \end{document}
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+%
+% \subsection{And finally\dots}
+%
+% Right at the end I'll put a hook for the configuration file.
+%
+%    \begin{macrocode}
+\ifx\mdwhook\@@undefined\else\expandafter\mdwhook\fi
+%    \end{macrocode}
+%
+% That's all the code done now.  I'll change back to `user' mode, where
+% all the magic control sequences aren't allowed any more.
+%
+%    \begin{macrocode}
+\makeatother
+%</mdwtools>
+%    \end{macrocode}
+%
+% Oh, wait!  What if I want to typeset this documentation?  Aha.  I'll cope
+% with that by comparing |\jobname| with my filename |mdwtools|.  However,
+% there's some fun here, because |\jobname| contains category-12 letters,
+% while my letters are category-11.  Time to play with |\string| in a messy
+% way.
+%
+%    \begin{macrocode}
+%<*driver>
+\makeatletter
+\edef\@tempa{\expandafter\@gobble\string\mdwtools}
+\edef\@tempb{\jobname}
+\ifx\@tempa\@tempb
+  \describesfile*{mdwtools.tex}
+  \docfile{mdwtools.tex}
+  \makeatother
+  \expandafter\mdwdoc
+\fi
+\makeatother
+%</driver>
+%    \end{macrocode}
+%
+% That's it.  Done!
+%
+% \hfill Mark Wooding, \today
+%
+% \Finale
+%
+\endinput

+ 1189 - 0
docs/packages/mdwtools/sverb.dtx

@@ -0,0 +1,1189 @@
+% \begin{meta-comment}
+%
+% $Id$
+%
+% Verbatim typesetting done properly (ahem)
+%
+% (c) 1996 Mark Wooding
+%
+%----- Revision history -----------------------------------------------------
+%
+% $Log$
+% Revision 1.1  1998-09-21 10:19:01  michael
+% Initial implementation
+%
+% Revision 1.3  1996/11/19 21:01:18  mdw
+% Entered into RCS
+%
+%
+% \end{meta-comment}
+%
+% \begin{meta-comment} <general public licence>
+%%
+%% sverb package -- handling of verbatim text
+%% Copyright (c) 1996 Mark Wooding
+%%
+%% This program is free software; you can redistribute it and/or modify
+%% it under the terms of the GNU General Public License as published by
+%% the Free Software Foundation; either version 2 of the License, or
+%% (at your option) any later version.
+%%
+%% This program is distributed in the hope that it will be useful,
+%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+%% GNU General Public License for more details.
+%%
+%% You should have received a copy of the GNU General Public License
+%% along with this program; if not, write to the Free Software
+%% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+%%
+% \end{meta-comment}
+%
+% \begin{meta-comment} <Package preamble>
+%<+package>\NeedsTeXFormat{LaTeX2e}
+%<+package>\ProvidesPackage{sverb}
+%<+package>                [1996/05/08 1.3 Verbatim typesetting]
+% \end{meta-comment}
+%
+% \CheckSum{651}
+%% \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{sverb}
+\mdwdoc
+%</driver>
+%
+% \end{meta-comment}
+%
+% \section{User guide}
+%
+% The \package{sverb} package provides some useful commands and environments
+% for doing things with verbatim text.  I prefer this code to the standard
+% \package{verbatim} package (by Rainer Sch\"opf et al.)\ although I'm
+% biased.
+%
+% The package was written to fulfil a particular purpose: I wanted to be able
+% to typeset ARM assembler code, 77~columns wide, on A5~paper, with the
+% fields separated by \textit{tab} characters.  It's grown up fairly
+% organically from that, and I've tidied it when I've seen the code get too
+% ugly.
+%
+% The current features are:
+%
+% \begin{itemize}
+%
+% \item A `listing' environment which typesets verbatim text nicely.
+%
+% \item A command to read verbatim text from an external file.
+%
+% \item Support for arbitrary-sized chunks of text without overflowing \TeX's
+%       memory.
+%
+% \item Support for \textit{tab} characters in the verbatim text.
+%
+% \item An environment for typesetting demonstrations of \LaTeX\ markup.
+%
+% \item It all works correctly with the \package{doc} system for documenting
+%       \LaTeX\ packages.
+%
+% \item A fairly hairy but quite powerful programmer interface to the yukky
+%       bits of the package.
+%
+% \end{itemize}
+%
+% The interface is described in its own section, so that more timid readers
+% can avoid it.  That said, some of the stuff in this section gets rather
+% technical.
+%
+% Note that this package doesn't even try to do anything with short bits of
+% verbatim text (as handled by the |\verb:...:| command).  I have a separate
+% package (\package{syntax}) which does all sorts of horrible things along
+% those lines.
+%
+% \subsection{The \env{listing} environment}
+%
+% \DescribeEnv{listing}
+% The main method for typesetting verbatim text is the \env{listing}
+% environment.  This works pretty much the same as the standard
+% \env{verbatim} environment, with some exceptions, which are described
+% below.
+%
+% So that you know exactly what you're getting, here are the rules by which
+% \package{sverb} decides what the verbatim text actually is:
+%
+% \begin{itemize}
+%
+% \item If there's any text, other than spaces, on the same line as the
+%       `|\begin{listing}|', then the contents of the environment begins
+%       immediately after the closing brace (with all leading spaces
+%       preserved).  Otherwise, the text begins on the following line.
+%
+% \item If there is any text, other than spaces, before the
+%       `|\end{listing}|', but on the same line, this is considered to be the
+%       last line of the text; otherwise the text is presumed to have ended
+%       at the end of the previous line.
+%
+% \item Any text following the |\end{listing}| on the same line is thrown
+%       away.  There are good reasons for this, but they're technical.
+%       Essentially there's nothing I can do about it.
+%
+% \end{itemize}
+%
+% \begin{figure}
+% \begin{demo}[w]{The \env{listing} environment}
+%\dots in the following code:
+%
+%\begin{listing}
+%init            MOV     R0,#200         ;Version 2.00 please
+%                LDR     R1,=&4B534154   ;Magic number (`TASK')
+%                ADR     R2,appName      ;Find application name
+%                SWI     Wimp_Initialise ;Register as a WIMP task
+%\end{listing}
+%
+%The next step is to \dots
+% \end{demo}
+% \end{figure}
+%
+% Tab characters are supported within the environment: tab stops are set
+% every eighth column, although this can be modified.
+%
+% \subsubsection{Configuring the \env{listing} environment}
+%
+% The text size used in the \env{listing} environment is set by the
+% |\listingsize| command.  By default, this is set to |\small|, although you
+% can redefine it in the document preamble, or it can be set in the document
+% class.
+%
+% The amount by which the listing text is indented is controlled by the
+% |\listingindent| length parameter.  This is a fixed length, whose default
+% value is 1\,em.
+%
+% \subsubsection{Choosing a different end-text}
+%
+% \DescribeEnv{listing*}
+% The \env{listing} environment is terminated by the exact character sequence
+% `|\end{listing}|'.  This isn't too much of a problem, unless you want to
+% include this string in the text.  This is achieved by the \env{listing$*$}
+% environment, which allows you to specify the end-text to find as an
+% argument.
+%
+% For example:
+%
+% \begin{demo}{The \env{listing$*$} environment}
+%Type a listing as follows:
+%
+%\begin{listing*}{<end-listing*>}
+%\begin{listing}
+%This is a listing.  Yes.
+%\end{listing}
+%<end-listing*>
+%\end{demo}
+%
+% Don't include `special' characters in your chosen end-text unless you know
+% what you're doing.
+%
+% \subsection{Writing text to a file}
+%
+% \DescribeEnv{verbwrite}
+% You can write verbatim text to a file using the \env{verbwrite}
+% environment.  The syntax is fairly straightforward:
+%
+% \begin{quote}
+% \syntax{"\\begin{verbwrite}{"<file-name>"}" \dots "\\end{verbwrite}"}
+% \end{quote}
+%
+% The text of the environment is written to the named file.  The rules about
+% where the text actually starts and ends are the same as for the
+% \env{listing} environment.
+%
+% There is also a $*$-variant, like \env{listing$*$}, which allows you to
+% choose the end-text.  The end-text is the first argument, the filename
+% comes second.
+%
+% There is a restriction on the characters you can write to the file: they
+% must all be considered `printable' by \TeX; otherwise they will be read
+% back in as `\syntax{"^^"<chars>}' which isn't too good.  Unfortunately,
+% this includes tab characters, so you can't write them.\footnote{^^A
+%   Well, not without doing serious surgery on \TeX\ itself, anyway. }
+%
+% \iffalse [Example time...  Ho hum.  There is evilness here.] \fi
+%\begin{verbwrite*}{<end-write>}{wrdemo1.tmp}
+%\begin{verbwrite}{wrdemo.tmp}
+%This is some text written to
+%a file near the beginning of
+%the file.
+%\end{verbwrite}
+%<end-write>
+%
+% For example: \verbinput{wrdemo1.tmp}
+%
+% \input{wrdemo1.tmp} \iffalse [Now build the file ;-) ] \fi
+%
+% \subsection{The \cmd\verbinput\ command}
+%
+% \DescribeMacro{\verbinput}
+% You can input a pre-prepared text file exactly as it is in the input using
+% the |\verbinput| command.  The filename is given as an argument.  For
+% example:
+%
+% \begin{demo}{The \cmd\verbinput\ command}
+%\verbinput{wrdemo.tmp}
+% \end{demo}
+%
+% \subsection{The \env{demo} environment}
+%
+% Package authors need to document their packages, and it's common to want
+% to display examples showing the original text and the output side-by-side
+% (or, when space doesn't permit this, one above the other).  Both the
+% \LaTeX\ book and \textit{The \LaTeX\ Companion} contain such examples.
+%
+% The \env{demo} environment allows such displays to be created easily.  The
+% syntax of the environment is as follows:
+%
+% \begin{quote}
+% \syntax{"\\begin{demo}["<shape>"]{"<title>"}" \dots "\\end{demo}"}
+% \end{quote}
+%
+% The optional \synt{shape} argument can be either `|w|' (wide), or `|n|'
+% (narrow).  A `wide' shape places the input and output one above the other,
+% while the `narrow' shape puts them side-by-side.  The default shape is
+% `narrow'.  An attractive border is drawn around the display to finish it
+% off nicely.
+%
+% An example:
+%
+%\begin{demo*}{<end-demo>}[w]{The \env{demo} environment}
+%\begin{demo}{From the \textit{\TeX book}}
+%\[ \sum_{p\;\rm prime}
+%   f(p) = \int_{t>1}
+%      f(t)\,{\rm d}\pi(t) \]
+%\end{demo}
+%<end-demo>
+%
+% \DescribeEnv{demo*}
+% As with the other environments created by this package, there's a
+% $*$-variant which takes the end-text as an argument.
+%
+%
+% \section{Programmer interface}
+%
+% This section describes the publicly available routines provided by the
+% \package{sverb} package.  Routines not described here are libable to be
+% changed or even removed without warning, so don't use them.
+%
+% \subsection{Environment hooks}
+%
+% Each of the environments created here works in the same way.  For each
+% environment \env{foo}, there's a main command responsible for doing the
+% work, called |\sv@foo|.  This is given all the arguments of the normal
+% environment, and two more:
+%
+% \begin{itemize}
+%
+% \item The `end-text' to search for, which marks the end of the environment.
+%
+% \item Some actions to perform after the text has been read and processed.
+%       This allows the calling macro to do some extra actions, like closing
+%       boxes, etc.
+%
+% \end{itemize}
+%
+% All the environments do is call the main command with appropriate
+% arguments.
+%
+% \subsection{Reading the verbatim text}
+%
+% \DescribeMacro{\sv@read}
+% The main scanning routine is |\sv@read|.  It is called with three
+% arguments:
+%
+% \begin{itemize}
+%
+% \item The end-text marking the end of the environment.
+%
+% \item The name of a macro (which must be a single token) which is called
+%       with a line of text as its single argument.  This is given each
+%       line of text which is read from the environment in turn.
+%
+% \item A macro, or other sort of action, which is to be done when the text
+%       has been read and processed.
+%
+% \end{itemize}
+%
+% The macro |\sv@read| assumes that the caller has already made some
+% provision for removing the category codes of the following text, by either
+% calling |\@verbatim| or using the construction
+% \begin{listing}
+%\let\do=\@makeother
+%\dospecials
+% \end{listing}
+%
+% \DescribeMacro{\sv@safespc}
+% Note that any space characters you read using |\sv@read| will be catcoded
+% as |\active|.  Normally this is OK because |\obeyspaces| (or
+% |\@vobeyspaces|) will be in effect.  If you're doing something more exotic,
+% like writing text to a file or building a command string, you can call
+% |\sv@safespc| which defines the active-space character to be a normal
+% whitespace-space when expanded.
+%
+% \implementation
+%
+% \section{Implementation}
+%
+% This section defines several macros and environments which allow verbatim
+% typing, with a high degree of configurability.  OK, so this sort of
+% thing's been done so often before that it isn't true, but I don't really
+% care.
+%
+%    \begin{macrocode}
+%<*package>
+%    \end{macrocode}
+%
+% \subsection{Simple things}
+%
+% To help us build funny macros which involve strange and different category
+% codes, I'll write some simple macros which I can use while building my
+% complicated and clever ones.
+%
+% \begin{macro}{\@cspecials}
+%
+% This macro is used to assist the definition of some of the environments.
+% It makes `|\|', `|{|' and `|}|' into `other' characters, and replaces them
+% with `\verb"|"', `|<|' and `|>|' respectively.  Note that `|[|' and `|]|'
+% aren't used, because they make defining commands which take optional
+% arguments awkward.  Note that we open a group here.  This should be closed
+% using \verb"|endgroup" at the end of the special section.
+%
+%    \begin{macrocode}
+\def\@cspecials{%
+  \begingroup%
+  \catcode`|0%
+  \catcode`<1%
+  \catcode`>2%
+  \catcode`\{12%
+  \catcode`\}12%
+  \catcode`\\12%
+}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\sv@startlisting}
+%
+% This macro sets everything up nicely for a \env{listing}-type verbatim
+% environment.
+%
+%    \begin{macrocode}
+\def\sv@startlisting{%
+  \def\par{\@@par\penalty\interlinepenalty}%
+  \@@par%
+  \leftskip\@totalleftmargin%
+  \obeylines%
+  \@noligs%
+  \let\do\@makeother\dospecials%
+  \verbatim@font%
+  \frenchspacing%
+  \@vobeyspaces%
+  \settabwidth%
+  \catcode9\active%
+  \lccode`\~9\lowercase{\let~\sv@vtab}%
+  \lccode`\~13\lowercase{\let~\vinput@cr}%
+  \interlinepenalty500%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \subsection{Tab character handling}
+%
+% One of the things we want to do here is handle tab characters properly.
+% (Here, `properly' means `moving to the next column which is a multiple of
+% eight', the way these things were always meant to.)
+%
+% \begin{macro}{\settabwidth}
+%
+% The tabs used by our tabbed verbatim environments are set up by this
+% routine.  It sets the tab width parameter |\svtab| to 8 times the width
+% of a |\tt| space.  If you really want, you can redefine this macro.
+%
+%    \begin{macrocode}
+\newdimen\svtab
+\def\settabwidth{\setbox\z@\hbox{\texttt{\space}}\svtab8\wd\z@}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\sv@vtab}
+%
+% Here we handle tabs inside verbatim environments.  We expect each line to
+% be typeset as a box, using something like
+%
+% \begin{listing}
+%\setbox0\hbox{#1}
+%\leavevmode
+%\box0
+%\par
+% \end{listing}
+%
+% The idea is that you make tab active, and set it to this macro.  We stop
+% the current box, stretch it to the right width, and start another one
+% straight after, so nobody know the difference.  The code here is straight
+% from Appendix~D of \textit{The \TeX book}.
+%
+%    \begin{macrocode}
+\def\sv@vtab{%
+  \hfill\egroup%
+  \@tempdima\wd\z@%
+  \divide\@tempdima\svtab%
+  \multiply\@tempdima\svtab%
+  \advance\@tempdima\svtab%
+  \wd\z@\@tempdima%
+  \leavevmode\box\z@%
+  \setbox\z@\hbox\bgroup%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\verbinput}
+%
+% We allow input from a file, by the |\verbinput| command.  We display the
+% text pretty much the same as the \env{listing} environment below.
+%
+% We set tab and return active, and get them to do appropriate things.  This
+% isn't actually all that hard.
+%
+%    \begin{macrocode}
+\def\verbinput#1{%
+  \begin{listinglist}%
+  \listingsize%
+  \sv@startlisting%
+  \setbox\z@\hbox\bgroup%
+  \input{#1}%
+  \sv@stripspc%
+  \egroup%
+  \ifdim\wd\z@=\z@%
+    \ifhmode\par\fi%
+  \else%
+    \leavevmode\box\z@\par%
+  \fi%
+  \end{listinglist}%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\vinput@cr}
+%
+% This macro handles return characters while inputting text in |\verbinput|.
+% We just output our current box, and start another.
+%
+%    \begin{macrocode}
+\def\vinput@cr{%
+  \egroup%
+  \leavevmode\box\z@%
+  \par%
+  \setbox\z@\hbox\bgroup%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \subsection{Reading verbatim text}
+%
+% The traditional way of reading verbatim text is to use a delimited
+% argument, as described in the \textit{\TeX book}.  This works well-ish if
+% the text isn't very long.  A better solution would be to pick out the text
+% line-by-line and process it like that.  So this is what we do.
+%
+% \begin{macro}{\matcher}
+%
+% For long verbatim environments, we need to be able to find the end text.
+% This is rather tricky.  The solution here is rather horrible.  The
+% environment picks out each line of the text at a time, as an argument, and
+% tests to see if it contains the text we're after.  We do the test in a
+% particularly yukky way: we add the actual target text to the end of the
+% line, and inspect the text following the match to see if the match is at
+% the end.
+%
+% The |\matcher| macro creates a `matcher' which will test strings to see if
+% they contain something interesting.
+%
+% To create a matcher, say
+% \syntax{"\\matcher{"<cmd-name>"}{"<target>"}{"<process-cmd>"}"}.  The
+% command \synt{cmd-name} accepts a line of text as an argument and calls
+% the \synt{process-cmd} with the text of the line before the match, or the
+% whole lot.  It also sets |\@ifmatched| appropriately.
+%
+% (Having spent ages coming up with this cruft myself, I found some very
+% similar, but slightly better, code in Appendix~D.  So I've changed mine to
+% match Donald's.  Anyway, credit where it's due: cheers Don.)
+%
+%    \begin{macrocode}
+\newif\if@matched
+\def\matcher#1#2#3{%
+  \expandafter\def\csname\string#1$match\endcsname##1#2##2##3\end{%
+    \ifx##2\relax%
+      \@matchedfalse%
+    \else%
+      \@matchedtrue%
+    \fi%
+    #3{##1}%
+  }%
+  \expandafter\def\expandafter#1\expandafter##\expandafter1\expandafter{%
+    \csname\string#1$match\endcsname##1#2\relax\end%
+  }%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\sv@stripspc}
+%
+% This macro strips any trailing glue in the current horizontal list.  This
+% is fairly simple, actually: we just loop while glue is the last item.  It's
+% slightly complicated by penalties which \TeX\ puts into the list between
+% the glue items, but we just remove them too.
+%
+%    \begin{macrocode}
+\def\sv@stripspc{%
+  \unpenalty%
+  \ifdim\lastskip=\z@\else%
+    \unskip\expandafter\sv@stripspc%
+  \fi%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\sv@percent}
+%
+% This macro strips a single leading percent character if there is one, and
+% if the \env{doc} package is loaded.  We store the possibly stripped text in
+% |\@tempa|.
+%
+%    \begin{macrocode}
+\begingroup
+\catcode`\%=12
+\gdef\sv@percent#1#2\relax
+    {\ifx\check@percent\@@undefined
+                     \ifx#1\relax\def\@tempa{}\else
+                         \def\@tempa{#1#2}\fi\else
+                     \ifx#1\relax\def\@tempa{}\else
+                         \ifx#1%\def\@tempa{#2}\else
+                             \def\@tempa{#1#2}\fi\fi\fi}
+\endgroup
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\@isspaces}
+%
+% We want to avoid writing the first and last lines of the environment to the
+% file if there's nothing in them.  To do this, we need to know whether a
+% piece of text contains only space characters.  This macro does this, in a
+% rather nasty way.  See the other macros below for details of how this
+% works.
+%
+% We define |\sv@safespc| at the same time: this makes space active and
+% expand to a space character which is not active.  Neat, huh?
+%
+%    \begin{macrocode}
+\lccode`\~32
+\lccode`\!32
+\lowercase{%
+  \def\@isspaces#1{%
+    \ifx#1\relax%
+      \def\@tempb{\@tempswafalse}%
+    \else\ifx#1~%
+      \let\@tempb\@isspaces%
+    \else%
+      \def\@tempb##1\relax{}%
+    \fi\fi%
+    \@tempb%
+  }
+  \def\sv@safespc{%
+    \catcode32\active%
+    \def~{ }%
+  }
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\sv@read}
+%
+% This macro does the main job of reading a chunk of verbatim text.  You call
+% it like this:
+%
+% \begin{quote}
+% \syntax{"\\sv@read{"<end-text>"}{"<process-line-proc>"}{"<end-proc>"}"}
+% \end{quote}
+%
+% The \synt{end-text} is the text to find at the end of the `environment': we
+% stop when we find it.
+%
+% The \synt{process-line-proc} is a macro which is passed as an argument each
+% line which we read from the text.
+%
+% The \synt{end-proc} is a macro to call once we've finished reading all of
+% the text.  This can tidy up an environment or close a file or whatever.
+%
+% We read the text by picking out newlines using a delimited macro.  We have
+% to be a little clever, because newlines are active in verbatim text.
+%
+% We will also strip `|%|' signs off the beginning if the \package{doc}
+% package is here (\package{doc} tries to play with \LaTeX's verbatim stuff,
+% and doesn't understand the way we do things).
+%
+%    \begin{macrocode}
+\def\sv@read#1#2#3{%
+%    \end{macrocode}
+%
+% This code does all sorts of evil things, so I'll start by opening a group.
+%
+%    \begin{macrocode}
+  \begingroup%
+%    \end{macrocode}
+%
+% So that I can spot the end-text, I'll create a matcher macro.
+%
+%    \begin{macrocode}
+  \matcher\@match{#1}\sv@read@ii%
+%    \end{macrocode}
+%
+% So that I can identify line ends, I'll make them active.  I'll also make
+% spaces active so that they can expand to whatever they ought to expand
+% to (spaces in files, or funny \verb*" " characters or whatever.
+%
+%    \begin{macrocode}
+  \catcode13\active%
+  \catcode32\active%
+%    \end{macrocode}
+%
+% I'll use the |\if@tempswa| flag to tell me whether I ought to output the
+% current line.  This is a little messy, so I'll describe it later.  I'll
+% initialise it to false because this is the correct thing to do.
+%
+%    \begin{macrocode}
+  \@tempswafalse%
+%    \end{macrocode}
+%
+% Most of the job is done by two submacros.  I'll define them in terms of
+% my current arguments (to save lots of token munging).  The first just
+% extracts the next line (which ends at the next newline character) and
+% tries to match it.
+%
+%    \begin{macrocode}
+  \lccode`\~13\lowercase{%
+    \def\sv@read@i##1~{\@match{##1}}%
+  }%
+%    \end{macrocode}
+%
+% The results of the match get passed here, along with the text of the
+% line up to the matched text.
+%
+%    \begin{macrocode}
+  \def\sv@read@ii##1{%
+%    \end{macrocode}
+%
+% The first job to do is to maybe strip off percent signs from the beginning,
+% to keep \package{doc} happy.
+%
+%    \begin{macrocode}
+    \sv@percent##1\relax\relax%
+%    \end{macrocode}
+%
+% Now I need to decide whether I ought to output this line.  The method goes
+% like this: if this is the first line (|\if@tempswa| is false) or the last
+% (|\if@matched| is true), \emph{and} the text consists only of spaces, then
+% I'll ignore it.
+%
+% The first thing to do is to notice the last line -- if |\if@matched| is
+% true, then I'll make |\if@tempswa| false to make the first-line and
+% last-line cases work the same way.
+%
+%    \begin{macrocode}
+    \if@matched\@tempswafalse\fi%
+%    \end{macrocode}
+%
+% Now if this is the first or last line, I'll examine it for spaces.  This
+% is done in a separate macro.  It will set |\if@tempswa| false if the
+% text contains only spaces.
+%
+%    \begin{macrocode}
+    \if@tempswa\else\@tempswatrue\expandafter\@isspaces\@tempa\relax\fi%
+%    \end{macrocode}
+%
+% Now, if |\if@tempswa| is still true, perform the \<process-line-proc> on
+% the line of text.  I'll provide a group, so that it doesn't upset me
+% too much.
+%
+%    \begin{macrocode}
+    \if@tempswa%
+      \begingroup%
+      \expandafter#2\expandafter{\@tempa}%
+      \endgroup%
+    \fi%
+%    \end{macrocode}
+%
+% The next line won't be the first one, so I'll set the flag true in
+% readiness.
+%
+%    \begin{macrocode}
+    \@tempswatrue%
+%    \end{macrocode}
+%
+% Now, if that wasn't the last line, go round again; otherwise end the group
+% I started ages ago, and do the user's \<end-proc>.
+%
+%    \begin{macrocode}
+    \if@matched\def\@tempa{\endgroup#3}\else\let\@tempa\sv@read@i\fi%
+    \@tempa%
+  }%
+%    \end{macrocode}
+%
+% Now to start the thing up.  I'll read the first line.
+%
+%    \begin{macrocode}
+  \sv@read@i%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\sv@readenv}
+%
+% This macro works out an appropriate end-text for the current environment.
+% If you say \syntax{"\\sv@readenv{"<macro-name>"}"}, it will expand do
+% \begin{listinglist} \listingsize \synshorts
+% <macro-name>"{\\"$_{12}$"end{"$_{12}$<current-env-name>"}"$_{12}$"}"^^A
+%		"{\\end{"<current-env-name>"}}"
+% \end{listinglist}
+% Easy, no?
+%
+% This is all done with mirrors.  No, err\dots\ it's done with
+% |\expandafter|.
+%
+%    \begin{macrocode}
+\begingroup
+\lccode`\<=`\{
+\lccode`\>=`\}
+\lccode`\|=`\\
+\lowercase{\endgroup
+\def\sv@readenv#1{%
+  \expandafter\expandafter\expandafter%
+    #1\expandafter\sv@readenv@i\@currenvir\@@%
+}
+\def\sv@readenv@i#1\@@{{|end<#1>}{\end{#1}}}
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\sv@verbline}
+%
+% This macro typesets a line in a verbatim way, so you can construct a real
+% verbatim environment from it.  It's a bit tricky in the way that it catches
+% the last line.  Don't worry about this: it's easy really.  Note the
+% |\relax| after the |\par| -- this is because \package{doc} tries to do
+% clever things with |\par| to strip `|%|' signs out.
+%
+%    \begin{macrocode}
+\def\sv@verbline#1{%
+  \setbox\z@\hbox{#1\sv@stripspc}%
+  \ifdim\wd\z@=\z@%
+    \if@matched\ifhmode\par\relax\fi\else\leavevmode\par\relax\fi%
+  \else%
+    \leavevmode\box\z@\par\relax%
+  \fi%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \subsection{Listing environments}
+%
+% The \env{listing} environment is our equivalent of the standard
+% \env{verbatim} environment.  We do some slightly cleverer things, though,
+% to make sure (for example) that even text which contains |\end{listing}|
+% can be typeset.
+%
+% \begin{macro}{\listinglist}
+% \begin{environment}{listinglist}
+%
+% This defines the layout for the \env{listing} environment.  It starts a
+% list with the appropriate shape.  It's also made into an environment, so
+% that the end-paragraph-environment bits work correctly.
+%
+% The |\listingindent| length parameter sets up the indentation of the
+% listings.  If there's a |\parindent| setting, I'll line listings up with
+% that; otherwise I'll just choose something which looks right.
+%
+%    \begin{macrocode}
+\newdimen\listingindent
+\AtBeginDocument{%
+  \ifdim\parindent=\z@\listingindent1em\else\listingindent\parindent\fi%
+}
+%    \end{macrocode}
+%
+% Now to define a size hook for the environment.  This is fairly simple
+% stuff.
+%
+%    \begin{macrocode}
+\ifx\listingsize\@@undefined
+  \let\listingsize\small
+\fi
+%    \end{macrocode}
+%
+% Now to define the environment itself.  Suppress the indentation if we're
+% first thing on a new list item, so that the listing lines up with
+% everything else.
+%
+%    \begin{macrocode}
+\def\listinglist{%
+  \list{}{%
+    \if@inlabel%
+      \leftmargin\z@%
+    \else%
+      \leftmargin\listingindent%
+    \fi%
+    \rightmargin\z@%
+    \labelwidth\z@%
+    \labelsep\z@%
+    \itemindent\z@%
+    \listparindent\z@%
+    \let\makelabel\relax%
+    \parsep\z@skip%
+  }%
+  \parfillskip\@flushglue%
+  \item\relax%
+}
+\let\endlistinglist\endlist
+%    \end{macrocode}
+%
+% \end{environment}
+% \end{macro}
+%
+% \begin{environment}{listing}
+%
+% The \env{listing} environment is the only real verbatim-like environment we
+% create will all this kit, although it does the job very nicely.
+%
+% The environment indents its contents slightly, unlike \env{verbatim}, and
+% uses a smaller typeface in an attempt to fit 77-column text on an A5~page.
+% There is also a $*$-variant, which allows you to specify the terminating
+% text.  This enables you to include absolutely any text in the environment,
+% including |\end{listing}|.
+%
+% First, we must define the |\listing| command.
+%
+%    \begin{macrocode}
+\def\listing{%
+  \listinglist%
+  \listingsize%
+  \sv@readenv\sv@listing%
+}
+%    \end{macrocode}
+%
+% Now we define the |\@listing| command, which does most of the work.  We
+% base the \env{listing} environment on a \env{list}.
+%
+%    \begin{macrocode}
+\def\sv@listing#1#2{%
+  \sv@startlisting%
+  \sv@read{#1}\sv@verbline{\endlistinglist#2}%
+}
+%    \end{macrocode}
+%
+% Now we define the starred version.  The command name needs to include the
+% `|*|' character, so we must use |\csname|.  There's some hacking here to
+% allow us to read the name using the appropriate catcodes for otherwise
+% normal characters: \LaTeX\ activates some characters and makes them typeset
+% themselves to suppress some ligaturing.
+%
+%    \begin{macrocode}
+\expandafter\def\csname listing*\endcsname{%
+  \listinglist%
+  \listingsize%
+  \begingroup%
+  \@noligs%
+  \def\@tempa##1{\endgroup\sv@listing{##1}{\end{listing*}}}%
+  \@tempa%
+}
+%    \end{macrocode}
+%
+% \end{environment}
+%
+% \begin{environment}{ignore}
+%
+% The \env{ignore} environment entirely ignores its contents.  Anything at
+% all may be put into the environment: it is discarded utterly.
+%
+% We define some macros for defining ignoring environments, because this can
+% be useful for version control, possibly.
+%
+%    \begin{macrocode}
+\def\sv@ignore#1#2{%
+  \@bsphack%
+  \let\do\@makeother\dospecials%
+  \sv@read{#1}\@gobble{\@esphack#2}%
+}
+\def\ignore{\sv@readenv\sv@ignore}
+\def\ignoreenv#1{%
+  \expandafter\let\csname #1\endcsname\ignore%
+}
+\def\unignoreenv#1{%
+  \expandafter\def\csname #1\endcsname{\endgroup}%
+  \expandafter\def\csname end#1\endcsname%
+      {\begingroup\def\@currenvir{#1}}%
+}
+%    \end{macrocode}
+%
+% \end{environment}
+%
+% \subsection{The \env{verbwrite} environment}
+%
+% The \env{verbwrite} environment allows text to be written to a file in a
+% verbatim way.  Note that tab characters don't work, because \TeX\ refuses
+% to be nice.
+%
+% \begin{macro}{\sv@write}
+%
+% As seems to be traditional now, we first define a general hookable macro
+% which allows a caller to specify the end-text and what to do afterwards.
+%
+%    \begin{macrocode}
+\newwrite\sv@writefile
+\def\sv@write#1#2{%
+  \begingroup%
+  \@bsphack%
+  \let\do\@makeother\dospecials%
+  \sv@safespc%
+  \sv@read{#1}\sv@writeline{\sv@endwrite#2}%
+}
+\def\sv@writeline#1{%
+  \immediate\write\sv@writefile{#1}%
+}
+\def\sv@endwrite{%
+  \@esphack%
+  \endgroup%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{environment}{verbwrite}
+%
+% Now we can define the actual environment.  We define a $*$-variant which
+% allows the user to specify the end-text, just to make sure.
+%
+%    \begin{macrocode}
+\def\verbwrite#1{%
+  \immediate\openout\sv@writefile#1\relax%
+  \sv@readenv\sv@write%
+}
+\def\endverbwrite{\immediate\closeout\sv@writefile}
+\expandafter\def\csname verbwrite*\endcsname#1#2{%
+  \immediate\openout\sv@writefile#2\relax%
+  \sv@write{#1}{\immediate\closeout\sv@writefile\end{verbwrite*}}%
+}
+%    \end{macrocode}
+%
+% \end{environment}
+%
+% \subsection{The \env{demo} environment}
+%
+% By way of tying all of this together, I present an environment for
+% displaying demonstrations of \LaTeX\ markup.  We read the contents of the
+% environment, write it to a temporary file, and read it back twice,
+% typesetting it the first time and displaying it verbatim the second time.
+%
+% \begin{macro}{\sv@demoname}
+%
+% This macro expands to the filename to use for the temporary data.  To
+% allow the package documentation to demonstrate the \env{demo} environment
+% itself, we need to keep a nesting count.  This avoids too much hackery,
+% which unfortunately appears to plague all of my \TeX\ code.
+%
+%    \begin{macrocode}
+\newcount\sv@nestcount
+\def\sv@demoname{demo\number\[email protected]}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\sv@demo}
+%
+% As for listing, we do all the business through a private macro.  This is
+% good because it means we can leave the main macro readable.  The argument
+% is the end-text to spot.
+%
+%    \begin{macrocode}
+\def\sv@demo#1#2{%
+  \@ifnextchar[{\sv@demo@i{#1}{#2}}{\sv@demo@i{#1}{#2}[n]}%
+}
+\def\sv@demo@i#1#2[#3]#4{%
+  \advance\sv@nestcount by\@ne%
+  \immediate\openout\sv@writefile\sv@demoname\relax%
+  \sv@write{#1}{%
+    \immediate\closeout\sv@writefile%
+    \sv@dodemo{#2}{#3}{#4}%
+  }%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{environment}{demo}
+%
+% This is the real environment.  We provide \env{demo$*$} too, to allow the
+% user to choose the end-text.
+%
+%    \begin{macrocode}
+\def\demo{\sv@readenv\sv@demo}
+\expandafter\def\csname demo*\endcsname#1{\sv@demo{#1}{\end{demo*}}}
+%    \end{macrocode}
+%
+% \end{environment}
+%
+% \begin{macro}{\sv@dodemo}
+%
+% First, let's define some common bits of code in the stuff below.  The
+% minipages used to typeset the material has some clever stuff to avoid
+% strange spacing in the output.
+%
+%    \begin{macrocode}
+\def\sv@demosmp{%
+  \begin{minipage}[t]{\@tempdima}%
+  \vskip8\p@%
+  \hrule\@height\z@%
+  \raggedright%
+  \vbox\bgroup%
+}
+\def\sv@demoemp{%
+    \par\unpenalty\unskip%
+  \egroup%
+  \vskip8\p@%
+  \hrule\@height\z@%
+  \end{minipage}%
+}
+%    \end{macrocode}
+%
+% This is the macro which actually typesets the demonstration.
+%
+%    \begin{macrocode}
+\def\sv@dodemo#1#2#3{%
+%    \end{macrocode}
+%
+% Now work out some values.  We set |\hsize| to the line width leaving 2\,em
+% of space on either side.  The size of the minipages is calculated depending
+% on the shape of the demonstration.  This is all fairly simple.
+%
+%    \begin{macrocode}
+  \begingroup%
+  \@tempdima\linewidth%
+  \advance\@tempdima-2em%
+  \hsize\@tempdima%
+  \if#2w%
+    \advance\@tempdima-2em%
+  \else%
+    \advance\@tempdima-3em%
+    \divide\@tempdima2%
+  \fi%
+%    \end{macrocode}
+%
+% Now we open a big vertical box, and put in a header to mark off the
+% demonstration.
+%
+%    \begin{macrocode}
+  \par%
+  \setbox\z@\hbox{\strut\enspace#3\enspace\strut}%
+  \@tempdimb.5\dp\z@%
+  \advance\@tempdimb-.5\ht\z@%
+  \ht\z@\@tempdimb\dp\z@\@tempdimb%
+  \noindent\hskip1em\vtop{%
+    \hb@xt@\hsize{%
+      \hrulefill%
+      \raise\@tempdimb\box\z@%
+      \hrulefill%
+    }%
+    \nointerlineskip%
+    \hb@xt@\hsize{\vrule\@height5\p@\hfil\vrule\@height5\p@}%
+    \nointerlineskip%
+%    \end{macrocode}
+%
+% Now we insert the output text in the first minipage.  I'll force `|%|'
+% to be a comment character, in case something like \package{doc} has had its
+% wicked way.
+%
+%    \begin{macrocode}
+    \vskip-\parskip%
+    \noindent\hbox{}\hskip1em%
+    \sv@demosmp%
+    \catcode`\%14\relax%
+    \input{\sv@demoname}%
+    \sv@demoemp%
+%    \end{macrocode}
+%
+% Insert some kind of separation between the two.  In `wide' format, we start
+% a new line, and put a ruleoff between the two.  In `narrow' format, we just
+% leave some space.
+%
+%    \begin{macrocode}
+    \if#2w%
+      \vskip8\p@\hrule\vskip8\p@%
+      \noindent\hbox{}%
+    \fi%
+    \hskip1em%
+%    \end{macrocode}
+%
+% Now we put the verbatim copy of the text in the other minipage.
+%
+%    \begin{macrocode}
+    \sv@demosmp%
+    \listingindent\z@%
+    \verbinput\sv@demoname%
+    \sv@demoemp%
+    \par%
+    \nointerlineskip%
+    \hb@xt@\hsize{\vrule\@height5\p@\hfil\vrule\@height5\p@}%
+    \hrule%
+  }%
+  \endgroup%
+  \par%
+  \vskip\baselineskip%
+  #1%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% That's all there is.  Have fun.
+%
+%    \begin{macrocode}
+%</package>
+%    \end{macrocode}
+%
+% \hfill Mark Wooding, \today
+%
+% \Finale
+%
+\endinput

+ 2875 - 0
docs/packages/mdwtools/syntax.dtx

@@ -0,0 +1,2875 @@
+% \begin{meta-comment}
+%
+% $Id$
+%
+% Syntax typesetting package for LaTeX 2e
+%
+% (c) 1996 Mark Wooding
+%
+%----- Revision history -----------------------------------------------------
+%
+% $Log$
+% Revision 1.1  1998-09-21 10:19:01  michael
+% Initial implementation
+%
+% Revision 1.9  1996/11/28 00:19:10  mdw
+% Added abbreviations for syntax diagram constructions.  These have been
+% getting on my nerves for too long now...
+%
+% Revision 1.8  1996/11/19 21:02:15  mdw
+% Entered into RCS
+%
+%
+% \end{meta-comment}
+%
+% \begin{meta-comment} <general public licence>
+%%
+%% syntax package -- typesetting syntax descriptions
+%% Copyright (c) 1996 Mark Wooding
+%%
+%% This program is free software; you can redistribute it and/or modify
+%% it under the terms of the GNU General Public License as published by
+%% the Free Software Foundation; either version 2 of the License, or
+%% (at your option) any later version.
+%%
+%% This program is distributed in the hope that it will be useful,
+%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+%% GNU General Public License for more details.
+%%
+%% You should have received a copy of the GNU General Public License
+%% along with this program; if not, write to the Free Software
+%% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+%%
+% \end{meta-comment}
+%
+% \begin{meta-comment} <Package preamble>
+%<+package>\NeedsTeXFormat{LaTeX2e}
+%<+package>\ProvidesPackage{syntax}
+%<+package>                [1996/05/17 1.9 Syntax typesetting (MDW)]
+% \end{meta-comment}
+%
+% \CheckSum{1465}
+%% \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>
+%
+%<*driver>
+%
+% This hacking will remember the old default underscore character.  Even if
+% T1 fonts are being used, it will get the grotty version.  Why is it that
+% all of the encoding handling ends up looking like this?
+%
+\expandafter\let\expandafter\oldus\csname?\string\textunderscore\endcsname
+%
+\input{mdwtools}
+\describespackage{syntax}
+\DeclareRobustCommand\syn{\package{syntax}}
+\mdwdoc
+%</driver>
+%
+% \end{meta-comment}
+%
+% \section{User guide}
+%
+% \subsection{Introduction}
+%
+% The \syn\ package provides a number of commands and environments which
+% extend \LaTeX\ and allow you to typeset good expositions of syntax.
+%
+% The package provides several different types of features: probably not all
+% of these will be required by every document which needs the package:
+% \begin{itemize}
+% \item A system of abbreviated forms for typesetting syntactic items.
+% \item An environment for typesetting BNF-type grammars
+% \item A collection of environments for building syntax diagrams.
+% \end{itemize}
+%
+% The package also includes some other features which, while not necessarily
+% syntax-related, will probably come in handy for similar types of document:
+% \begin{itemize}
+% \item An abbreviated notation for verbatim text, similar to the
+%       \package{shortvrb} package.
+% \item A slightly different underscore character, which works as expected
+%       in text and maths modes.
+% \end{itemize}
+%
+% \subsection{The abbreviated verbatim notation}
+%
+% In documents describing programming languages and libraries, it can become
+% tedious to type "\verb|...|" every time.  Like Frank Mittelbach's
+% \package{shortvrb} package, \syn\ provides a way of setting up single-^^A
+% character abbreviations.  The only real difference between the two is that
+% the declarations provided by \syn\ obey \LaTeX's normal scoping rules.
+%
+% \DescribeMacro\shortverb
+% You can set up a character as a `verbatim shorthand' character using the
+% |\shortverb| command.  This takes a single argument, which should be a
+% single-character control sequence containing the character you want to use.
+% So, for example, the command
+% \begin{listing}
+%\shortverb{\|}
+% \end{listing}
+% would set up the `"|"' character to act as a verbatim delimiter.  While a
+% |\shortverb| declaration is in force, any text surrounded by (in this case)
+% vertical bar characters will be typeset as if using the normal |\verb|
+% command.
+%
+% \DescribeEnv{shortverb}
+% Since \LaTeX\ allows any declaration to be used as an environment, you can
+% use a \env{shortverb} environment to delimit the text over which your
+% character is active:
+% \begin{listing}
+%Some text...
+%\begin{shortverb}{\|}
+%...
+%\end{shortverb}
+% \end{listing}
+%
+% \DescribeMacro\unverb
+% If you want to disable a |\shortverb| character without ending the scope
+% of other declarations, you can use the |\unverb| command, passing it
+% a character as a control sequence, in the same way as above.
+%
+% The default \TeX/\LaTeX\ underscore character is rather too short for
+% use in identifiers.  For example:
+%
+% \begingroup \let\_=\oldus
+% \begin{demo}{Old-style underscores}
+%Typing long underscore-filled
+%names, like big\_function\_name,
+%is normally tedious.  The normal
+%positioning of the underscore
+%is wrong, too.
+% \end{demo}
+% \endgroup
+%
+% The \syn\ package redefines the |\_| command to draw a more attractive
+% underscore character.  It also allows you to use the |_|~character
+% directly to produce an underscore outside of maths mode: |_|~behaves
+% as a subscript character as usual inside maths mode.
+%
+% \begin{demo}{New \syn\ underscores}
+%You can use underscore-filled
+%names, like big_function_name,
+%simply and naturally.  Of
+%course, subscripts still work
+%normally in maths mode, e.g.,
+%$x_i$.
+% \end{demo}
+%
+% \subsection{Typesetting syntactic items}
+% \begin{synshorts}
+%
+% The \syn\ package provides some simple commands for typesetting syntactic
+% items.
+%
+% \DescribeMacro\synt
+% Typing "\\synt{"<text>"}" typesets <text> as a \lq non-terminal',
+% in italics and surrounded by angle brackets.  If you use "\\synt" a lot,
+% you can use the incantation
+% \begin{listing}
+%\def\<#1>{\synt{#1}}
+% \end{listing}
+% to allow you to type "\\<"<text>">" as an alternative to 
+% "\\synt{"<text>"}".
+%
+% \DescribeMacro\lit
+% You can also display literal text, which the reader should type directly,
+% using the "\\lit" command.
+%
+% \begin{demo}{Use of \cmd\lit}
+%Type \lit{ls} to display a
+%list of files.
+% \end{demo}
+%
+% Note that the literal text appears in quotes.  To suppress the quotes,
+% use the `*' variant.
+%
+% The "\\lit" command produces slightly better output than "\\verb" for
+% running text, since the spaces are somewhat narrower.  However, "\\verb"
+% allows you to type arbitrary characters, which are treated literally,
+% whereas you must use commands such as "\\{" to use special characters
+% within the argument to "\\lit".  Of course, you can use "\\lit" anywhere
+% in the document: "\\verb" mustn't be used inside a command argument.
+% \end{synshorts}
+%
+% \subsection{Abbreviated forms for syntactic items}
+%
+% It would be very tedious to require the use of commands like |\synt|
+% when building syntax descriptions like BNF grammars.  It would also make
+% your \LaTeX\ source hard to read.  Therefore, \syn\ provides some
+% abbreviated forms which make typesetting syntax quicker and easier.
+%
+% Since the abbreviated forms use several characters which you may want to
+% use in normal text, they aren't enabled by default.  They only work
+% with special commands and environments provided by the \syn\ package.
+%
+% The abbreviated forms are shown in the table below:
+%
+% \begin{tab}[\synshorts]{ll}                                       \hline
+% \bf Input        & \bf Output                                  \\ \hline
+% "<some text>"    & <some text>                                 \\
+% "`some text'"    & `some text'                                 \\
+% "\"some text\""  & "some text"                                 \\ \hline
+% \end{tab}
+%
+% Within one of these abbreviated forms, text is treated more-or-less
+% verbatim:
+% \begin{itemize}
+%
+% \item Any |$|, |%|, |^|, |&|, |{|, |}|, |~| or |#| characters are treated
+%       literally: their normal special meanings are ignored.
+%
+% \item Other special characters, with the exception of |\|, are also treated
+%       literally: this includes any characters made special by |\shortverb|.
+%
+% \end{itemize}
+%
+% However, the |\| character retains its meaning.  Since the brace
+% characters are not recognised, most commands can't be used within
+% abbreviated forms.  However, you can use special commands to type some
+% of the remaining special characters:
+%
+% \begin{tab}[\synshorts]{ll}                                       \hline
+% \bf Command   & \bf Result                                     \\ \hline
+% "\\\\"        & A `\\' character                               \\
+% "\\>"         & A `>' character                                \\
+% "\\'"         & A `\'' character                               \\
+% "\\\""        & A `"' character                                \\
+% "\\\ "        & A `\ ' character (not a space)                 \\ \hline
+% \end{tab}
+%
+% Note that |\\|, |\>|, |\"| and \verb*|\ | are only useful in a |\tt| font,
+% i.e., inside |`...'| and |"..."| forms, since the characters don't exist
+% in normal fonts.  The |\>|, |\"| and |\'| commands are only provided so
+% you can use these characters within |<...>|, |"..."| and |`...'| forms
+% respectively: in the other forms, there is no need to use the special
+% command.
+%
+% In addition, when the above abbreviations are enabled, the character "|"
+% is set to typeset a \syntax{|} symbol, which is conventionally used to
+% separate alternatives in syntax descriptions.
+%
+% \DescribeMacro\syntax
+% Normally, these abbreviated forms are enabled only within special
+% environments, such as \env{grammar} and \env{syntdiag}.  To use them
+% in running text, use the |\syntax| command.  The abbreviations are made
+% active within the argument of the |\syntax| command.\footnote{^^A
+%   The argument of the \cmd\syntax\ command may contain commands such
+%   as \cmd\verb, which are normally not allowed within arguments.
+% }  Note that you cannot use the |\syntax| command within the argument
+% of another command.
+%
+% \DescribeMacro\synshorts
+% \DescribeEnv{synshorts}
+% You can also enable the syntax shortcuts using the |\synshorts| declaration
+% or the \env{synshorts} environment.  This enables the syntax shortcuts
+% until the scope of the declaration ends.
+%
+% \DescribeMacro\synshortsoff
+% If syntax shortcuts are enabled, you can disable them using the
+% |\synshortsoff| declaration.
+%
+% \subsection{The \env{grammar} environment}
+%
+% \DescribeEnv{grammar}
+% For typesetting formal grammars, for example, of programming languages,
+% the \syn\ package provides a \env{grammar} environment.  Within this
+% environment, the abbreviated forms described above are enabled.
+%
+% Within the environment, separate production rules should be separated by
+% blank lines.  You can use the normal |\\| command to perform line-breaking
+% of a production rule.  Note that a production rule must begin with a
+% nonterminal name enclosed in angle brackets (|<| \dots |>|), followed by
+% whitespace, then some kind of production operator (usually `::=') and then
+% some more whitespace.  You can control how this text is actually typeset,
+% however.
+%
+% \DescribeMacro{\[[}
+% \DescribeMacro{\]]}
+% You can use syntax diagrams (see below) instead of a straight piece of BNF
+% by enclosing it in a |\[[| \dots |\]]| pair.  Note that you can't mix 
+% syntax diagrams and BNF in a production rule, and you will get something
+% which looks very strange if you try.
+%
+% \DescribeMacro\alt
+% In addition, a command |\alt| is provided for splitting long production
+% rules over several lines: the |\alt| command starts a new line and places
+% a \syntax{|} character slightly in the left margin.  This is useful when
+% a symbol has many alternative productions.
+%
+% \begin{demo}[w]{The \env{grammar} environment}
+%\begin{grammar}
+%<statement> ::= <ident> `=' <expr>
+%  \alt `for' <ident> `=' <expr> `to' <expr> `do' <statement>
+%  \alt `{' <stat-list> `}'
+%  \alt <empty>
+%
+%<stat-list> ::= <statement> `;' <stat-list> | <statement>
+%\end{grammar}
+% \end{demo}
+%
+% You can modify the appearance of grammars using three length parameters:
+%
+% \begin{description} \def\makelabel{\hskip\labelsep\cmd}
+%
+% \item [\grammarparsep] is the amount of space inserted between production
+%       rules.  It is a rubber length whose default value is 8\,pt, with
+%       1\,pt of stretch and shrink.
+%
+% \item [\grammarindent] is the amount by which the right hand side of a
+%       production rule is indented from the left margin.  It is a rigid
+%       length.  Its default value is 2\,em.
+%
+% \end{description}
+%
+% \DescribeMacro\grammarlabel
+% You can also control how the `label' is typeset by redefining the
+% |\grammarlabel| command.  The command is given two arguments: the name of
+% the nonterminal (which was enclosed in angle brackets), and the `production
+% operator'.  The command is expected to produce the label.  By default, it
+% typesets the nonterminal name using |\synt| and the operator at opposite
+% ends of the label, separated by an |\hfill|.
+%
+% \subsection{Syntax diagrams}
+%
+% A full formal BNF grammar can be somewhat overwhelming for less technical
+% readers.  Documents aimed at such readers tend to display grammatical
+% structures as \emph{syntax diagrams}.
+%
+% \DescribeEnv{syntdiag}
+% A syntax diagram is always enclosed in a \env{syntdiag} environment.  You
+% should think of the environment as enclosing a new sort of \LaTeX\ mode:
+% trying to type normal text into a syntax diagram will result in very ugly
+% output.  \LaTeX\ ignores spaces and return characters while in syntax
+% diagram mode.
+%
+% The syntax of the environment is very simple:
+%
+% \begin{grammar}
+% <synt-diag-env> ::= \[[
+%   "\\begin{syntdiag}"
+%   \begin{stack} \\ "[" <decls> "]" \end{stack}
+%   <text>
+%   "\\end{syntdiag}"
+% \]]
+% \end{grammar}
+%
+% The \<decls> contain any declarations you want to insert, to control
+% the environment.  The parameters to tweak are described below.
+%
+% Within a syntax diagram, you can include syntactic items using the
+% abbreviated forms described elsewhere.  The output from these forms is
+% modified slightly in syntax diagram mode so that the diagram looks
+% right.
+%
+% I probably ought to point out now that the syntax diagram typesetting
+% commands produce beautiful-looking diagrams with all the rules and curves
+% accurately positioned.  Some device drivers don't position these objects
+% correctly in their output.  I've had particular trouble with |dvips|.  I'll
+% say it again: it's not my fault!
+%
+% \DescribeEnv{syntdiag*}
+% The \env{syntdiag} environment only works in paragraph mode, and it acts
+% rather like a paragraph, splitting over several lines when appropriate.
+% If you just want to typeset a snippet of a syntax diagram, you can
+% use the starred environment \env{syntdiag$*$}.
+%
+% \begin{grammar}
+% <synt-diag-star-env> ::= \[[
+%   "\\begin{syntdiag*}"
+%   \begin{stack} \\ "[" <decls> "]" \end{stack}
+%   \begin{stack} \\ "[" <width> "]" \end{stack}
+%   <text>
+%   "\\end{syntdiag*}"
+% \]]
+% \end{grammar}
+%
+% When typesetting little demos like this, it's not normal to fully adorn
+% the syntax diagram with the full double arrows
+% (`\begin{syntdiag*}[\left{>>-}\right{-><}]\tok{$\cdots$}\end{syntdiag*}').
+% The two declarations \syntax{"\\left{"<arrow>"}" and "\\right{"<arrow>"}"}
+% allow you to choose the arrows on each side of the syntax diagram snippet.
+% The possible values of \<arrow> are shown in the table-ette below:
+%
+% ^^A Time to remember what I learned about tables while writing mdwtab.
+% ^^A Just for the embarassment factor, here's the number of attempts I
+% ^^A took to get the table below to look right: __6.  Hmm... not as bad
+% ^^A as I expected.  Most of them were fine-tuning things.
+%
+% \medskip					^^A Leave a vertical gap
+% \hbox to\columnwidth{\hfil\vbox{\tabskip=0pt	^^A Centre it horizontally
+% \sdsize \csname sd@setsize\endcsname		^^A Position syntdiag arrows
+% \halign to .5\columnwidth{			^^A Set the table width
+%   &\ttfamily\ignorespaces#\unskip\hfil\tabskip=0pt ^^A Typeset the name
+%   &\quad\csname sd@arr@#\endcsname\hfil	^^A Typeset the arrow
+%   &\setbox0=\hbox{#}\tabskip=0pt plus 1fil\cr	^^A Stretch between columns
+%   >>-&>>-&   &>-&>-&   &->&->\cr
+%   -><&-><&   &...&...& &-&-\cr
+% }}\hfil}					^^A Close the boxing
+% \medskip					^^A And leave another gap
+%
+% These declarations should be used only in the optional argument to the
+% \env{syntdiag$*$} command.  The second optional argument to the
+% environment, if specified, fixes the width of the syntax diagram snippet;
+% if you omit this argument, the diagram is made just wide enough to
+% fit everything in.
+%
+% \begin{figure}
+% \begin{demo}[w]{Example of \env{syntdiag$*$}}
+%\newcommand{\bs}[2]{%
+%  \begin{minipage}{1.6in}%
+%  \begin{syntdiag*}[\left{#1}\right{#2}][1.6in]%
+%}
+%\newcommand{\es}{\end{syntdiag*}\end{minipage}}
+%
+%\begin{center}
+%\begin{tabular}{cl}                                      \\ \hline
+%\bf Construction    & \bf Meaning                        \\ \hline
+%\bs {>>-} {...} \es & Start of syntax diagram            \\
+%\bs {...} {-><} \es & End of syntax diagram              \\
+%\bs {>-}  {...} \es & Continued on next line             \\
+%\bs {...} {->}  \es & Continued from previous line       \\ \hline
+%\bs {...} {...}
+%  \begin{stack} <option-a> \\ <option-b> \\ <option-c> \end{stack}
+%\es                 & Alternatives: choose any one       \\
+%\bs {...} {...}
+%  \begin{rep} <repeat-me> \\ <separator> \end{rep}
+%\es                 & One or more items, with separators \\ \hline
+%\end{tabular}
+%\end{center}
+% \end{demo}
+% \end{figure}
+%
+% \DescribeMacro\tok
+% You can also include text using the |\tok| command.  The argument of this
+% command is typeset in \LaTeX's LR~mode and inserted into the diagram. 
+% Syntax abbreviations are allowed within the argument, so you can, for
+% example, include textual descriptions like
+% \begin{listing}
+%\tok{any <char> except `"'}
+% \end{listing}
+%
+% \DescribeEnv{stack}
+% Within a syntax diagram, a choice between several different items is
+% shown by stacking the alternatives vertically.  In \LaTeX, this is done
+% by enclosing the items in a \env{stack} environment.  Each individual item
+% is separated by |\\| commands, as in the \env{array} and \env{tabular}
+% environments.  Each row may contain any syntax diagram material, including
+% |\tok| commands and other \env{stack} environments.
+%
+% Note if you end a \env{stack} environment with a |\\| command, a blank
+% row is added to the bottom of the stack, indicating that none of the items
+% need be specified.
+%
+% The commands |\(| and |\)| are abbreviations for `|\begin{stack}|' and
+% `|\end{stack}|' respectively.  Also, |\[| is `|\begin{stack}\\|' and
+% |\]| is `|\end{stack}|' -- these two are useful for stacks in which the
+% first item is blank (i.e., none of the options need be taken).
+%
+% \DescribeEnv{rep}
+% Text which can be repeated is enclosed in a \env{rep} environment: the
+% text is displayed with a backwards pointing arrow drawn over it, showing
+% that it may be repeated.  Optionally, you can specify text to be
+% displayed in the arrow, separating it from the main text with a |\\|
+% command.
+%
+% Note that items on the backwards arrow of a \env{rep} construction should
+% be displayed \emph{backwards}.  You must put the individual items in
+% reverse order when building this part of your diagrams.  \syn\ will 
+% correctly reverse the arrows on \env{rep} structures, but apart from
+% this, you must cope on your own.  You are recommended to keep these parts
+% of your diagrams as simple as possible to avoid confusing readers.
+%
+% The commands |\<| and |\>| are abbreviations for `|\begin{rep}|' and
+% `|\end{rep}|' respectively.
+%
+% \begin{demo}[w]{A syntax diagram}
+%\begin{syntdiag}
+%<ident> `('
+%  \begin{rep} \begin{stack} \\
+%    <type> \begin{stack} \\ <ident> \end{stack}
+%  \end{stack} \\ `,' \end{rep}
+%\begin{stack} \\ `...' \end{stack} `)'
+%\end{syntdiag}
+% \end{demo}
+%
+% \subsubsection{Line breaking in syntax diagrams}
+%
+% Syntax diagrams are automatically broken over lines and across pages.
+% Lines are only broken between items on the outermost level of the diagram:
+% i.e., not within \env{stack} or \env{rep} environments.
+%
+% You can force a line break at a particular place by using the |\\| command
+% as usual.  This supports all the usual \LaTeX\ features: a `|*|' variant
+% which prohibits page breaking, and an optional argument specifying the
+% extra vertical space between lines.
+%
+% \subsubsection{Customising syntax diagrams}
+%
+% There are two basic styles of syntax diagrams supported:
+%
+% \begin{description}
+%
+% \item [square] Lines in the syntax diagram join at squared-off corners.
+%       This appears to be the standard way of displaying syntax diagrams
+%       in IBM manuals, and most other documents I've seen.
+%
+% \item [rounded] Lines curve around corners.  Also, no arrows are drawn
+%       around repeating loops: the curving of the lines provides this
+%       information instead.  This style is used in various texts on
+%       Pascal, and appears to be more popular in academic circles.
+%
+% \end{description}
+%
+% You can specify the style you want to use for syntax diagrams by giving
+% the style name as an option on the |\usepackage| command.  For example,
+% to force rounded edges to be used, you could say
+%
+% \begin{listing}
+%\usepackage[rounded]{syntax}
+% \end{listing}
+%
+% \DescribeMacro\sdsize
+% \DescribeMacro\sdlengths
+% The \env{syntdiag} environment takes an option argument, which should
+% contain declarations which are obeyed while the environment is set up.
+% The default value of this argument is `|\sdsize\sdlengths|'.  The
+% |\sdsize| command sets the default type size for the environment: this is
+% normally |\small|.  |\sdlengths| sets the values of the length parameters
+% used by the environment based on the current text size.  These parameters
+% are described below.
+%
+% For example, if you wanted to reduce the type size of the diagrams still
+% further, you could use the command
+% \begin{listing}
+%\begin{syntdiag}[\tiny\sdlengths]
+% \end{listing}
+%
+% The following length parameters may be altered:
+%
+% \begin{description} \def\makelabel{\hskip\labelsep\cmd}
+%
+% \item [\sdstartspace] The length of the rule between the arrows which
+%       begin each line of the syntax diagram and the first item on the line.
+%       Note that most objects have some space on either side of them as
+%       well.  This is a rubber length.  Its default value is 1\,em, although
+%       it can shrink by up to 10\,pt.
+%
+% \item [\sdendspace] The length of the rule between the last item on a
+%       line and the arrow at the very end.  Note that the final line also
+%       has extra rubber space on the end.  This is a rubber length.  Its
+%       default value is 1\,em, although it will shrink by up to 10\,pt.
+%
+% \item [\sdmidskip] The length of the rule on either side of a large
+%       construction (either a \env{stack} or a \env{rep}).  It is a rubber
+%       length.  Its default value is \smallf 1/2\,em, with a very small
+%       amount of infinite stretch.
+%
+% \item [\sdtokskip] The length of the rule on either side of a |\tok|
+%       item or syntax abbreviation.  It is a rubber length.  Its default
+%       value is \smallf 1/4\,em, with a very small amount of inifnite
+%       stretch.
+%
+% \item [\sdfinalskip] The length of the rule which finishes the last line
+%       of a syntax diagram.  It is a rubber length.  Its default value is
+%       \smallf 1/2\,em, with 10000\,fil of stretch, which will left-align
+%       the items on the line.\footnote{^^A
+%         This is a little \TeX nical.  The idea is that if a stray 1\,fil
+%         of stretch is added to the end of the line, it won't be noticed.
+%         However, the alignment of the text on the line can still be
+%         modified using \cmd{\sd@rule}\cmd{\hfill}, if you're feeling
+%         brave.
+%       }
+%
+% \item [\sdrulewidth] Half the width of the rules used in the diagram.
+%       It is a rigid length.  Its default value is 0.2\,pt.
+%
+% \item [\sdcirclediam] The diameter of the circle from which the quadrants
+%       used in rounded-style diagrams are taken.  This must be a multiple
+%       of 4\,pt, or else the lines on the diagram won't match up.
+%
+% \end{description}
+%
+% In addition, you should call |\sdsetstrut| passing it the total height
+% (\({\rm height}+{\rm depth}\)) of a normal line of text at the current
+% size.  Normally, the value of |\baselineskip| will be appropriate.
+%
+% You can also alter the appearance of \env{stack}s and \env{rep}s by using
+% their optional positioning arguments.  By default, \env{stack}s descend
+% below the main line of the diagram, and \env{rep}s extend above it.  
+% Specifying an optional argument of |[b]| for either environment reverses
+% this, putting \env{stack}s above and \env{rep}s below the line.
+%
+% \subsection{Changing the presentation styles}
+%
+% You can change the way in which the syntax items are typeset by altering
+% some simple commands (using |\renewcommand|).  Each item (nonterminals,
+% as typeset by |\synt|, and quoted and unquoted terminals, as typeset by
+% |\lit| and |\lit*|) has two style commands associated with it, as shown
+% in the table below.
+%
+% \begin{tab}{lll}						   \hline
+% \bf Syntax item	& \bf Left command & \bf Right command	\\ \hline
+% Nonterminals		& |\syntleft|	   & |\syntright|	\\
+% Quoted terminals	& |\litleft|	   & |\litright|	\\
+% Unquoted terminals	& |\ulitleft|	   & |\ulitright|	\\ \hline
+% \end{tab}
+%
+% It's not too hard to see how this works.  For example, if you look at
+% the implementation for |\syntleft| and |\syntright| in the implementation
+% section, you'll notice that they're defined like this:
+% \begin{listing}
+%\newcommand{\syntleft}{$\langle$\normalfont\itshape}
+%\newcommand{\syntright}{$\rangle$}
+% \end{listing}
+% I think this is fairly simple, if you understand things like font changing.
+%
+% Note that changing these style commands alters the appearance of all syntax
+% objects of the appropriate types, as created by the |\synt| and |\lit|
+% commands, in \env{grammar} environments, and in syntax diagrams.
+%
+%
+% \section{Change history}
+%
+% \subsection*{Version 1.9}
+%
+% Added abbreviations for syntax diagram constructions.  These clobber some
+% common abbreviations for maths, but that's not too worrying really; it's
+% not likely for people to do maths in syntax diagrams.
+%
+% \subsection*{Version 1.8}
+%
+% Added to RCS (so changed version numbering style).
+%
+% \subsection*{Version 1.07}
+%
+% \begin{itemize}
+% \item Fixed problem with underscore hacking in a \env{tabbing} environment.
+% \end{itemize}
+%
+% \subsection*{Version 1.06}
+%
+% \begin{itemize}
+% \item Added style hooks for syntax items.
+% \item Improved colour handling in syntax diagrams, thanks to the |\doafter|
+%       package.
+% \item Fixed some nasty bugs in the \env{grammar} environment which confused
+%       other lists and ruined the spacing.  The \env{grammar} handling is
+%       now much tidier in general.
+% \end{itemize}
+%
+% \subsection*{Version 1.05}
+%
+% \begin{itemize}
+% \item Fixed `the bug' in the syntax diagram typesetting.  It now breaks
+%       lines almost psychically, and doesn't break in the wrong places.
+% \item Almost rewrote the \env{grammar} environment.  It now does lots of
+%       the list handling itself, to allow more versatile typesetting of the
+%       left hand sides.  There's lots of evil in there now.
+% \item Added some more configurability.  In particular, two new settings
+%       have been added to control \env{grammar} environments, and a neat
+%       way of adding new syntax diagram structures has been introduced.
+% \end{itemize}
+%
+% \subsection*{Version 1.04}
+%
+% \begin{itemize}
+% \item Changed the vertical positioning of the rules, to make all the text
+%       line up properly.  While the old version was elegant and simple, it
+%       had the drawback of looking nasty.
+% \item Allow line breaks at underscores, but don't if there's another one
+%       afterwards.  Also, prevent losing following space if underscore is
+%       written to a file.
+% \end{itemize}
+%
+% \subsection*{Version 1.02}
+%
+% \begin{itemize}
+% \item Added support for rounded corners in syntax diagrams.
+% \item Changed lots of |\hskip| commands to |\kern|s, to prevent possible
+%       line breaks.
+% \end{itemize}
+%
+% \subsection*{Version 1.01}
+%
+% \begin{itemize}
+% \item Allowed disabling of underscore active character, to avoid messing
+%       up filenames.
+% \item Added |\grammarparsep| and |\grammarindent| length parameters to
+%       control the appearance of grammars.
+% \end{itemize}
+%
+% \implementation
+%
+% \section{Implementation of \syn}
+%
+%    \begin{macrocode}
+%<*package>
+%    \end{macrocode}
+%
+% \subsection{Options handling}
+%
+% We define all the options we know about, and then see what's been put
+% on the usepackage line.
+%
+% The options we provide currently are as follows:
+%
+% \begin{description}
+% \item [rounded] draws neatly rounded edges on the diagram.
+% \item [square] draws squared-off edges on the diagram.  This is the
+%       default.
+% \item [nounderscore] disables the undescore active character,  The |\_|
+%       command still produces the nice version created here.
+% \end{description}
+%
+%    \begin{macrocode}
+\DeclareOption{rounded}{\sd@roundtrue}
+\DeclareOption{square}{\sd@roundfalse}
+\DeclareOption{nounderscore}{\@uscorefalse}
+%    \end{macrocode}
+%
+% Now process the options:
+%
+%    \begin{macrocode}
+\newif\ifsd@round
+\newif\if@uscore\@uscoretrue
+\ExecuteOptions{square}
+\ProcessOptions
+%    \end{macrocode}
+%
+% \subsection{Special character handling}
+%
+% A lot of the \syn\ package requires the use special active characters.
+% These must be added to two lists: |\dospecials|, which is used by |\verb|
+% and friends, and |\@sanitize|, which is used by |\index|.  The two macros
+% here, |\addspecial| and |\remspecial|, provide these registration
+% facilities.
+%
+% Two similar macros are found in Frank Mittelbach's \package{doc} package:
+% these have the disadvantage of global operation.  My macros here are based
+% on Frank's, which in turn appear to be based on Donald Knuth's list
+% handling code presented in Appendix~D of \textit{The \TeX book}.
+%
+% Both these macros take a single argument: a single-character control
+% sequence containing the special character to be added to or removed from
+% the lists.
+%
+% \begin{macro}{\addspecial}
+%
+% This is reasonably straightforward.  We remove the sequence from the lists,
+% in case it's already there, and add it in in the obvious way.  This
+% requires a little bit of fun with |\expandafter|.
+%
+%    \begin{macrocode}
+\def\addspecial#1{%
+  \remspecial{#1}%
+  \expandafter\def\expandafter\dospecials\expandafter{\dospecials\do#1}%
+  \expandafter\def\expandafter\@santize\expandafter{%
+    \@sanitize\@makeother#1}%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\remspecial}
+%
+% This is the difficult bit.  Since |\dospecials| and |\@sanitize| have the
+% form of list macros, we can redefine |\do| and |\@makeother| to do the
+% job for us.  We must be careful to put the old meaning of |\@makeother|
+% back.  The current implementation assumes it knows what |\@makeother| does.
+%
+%    \begin{macrocode}
+\def\remspecial#1{%
+  \def\do##1{\ifnum`#1=`##1 \else\noexpand\do\noexpand##1\fi}%
+  \edef\dospecials{\dospecials}%
+  \def\@makeother##1{\ifnum`#1=`##1 \else%
+    \noexpand\@makeother\noexpand##1\fi}%
+  \edef\@sanitize{\@sanitize}%
+  \def\@makeother##1{\catcode`##112}%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \subsection{Underscore handling}
+%
+% When typing a lot of identifiers, it can be irksome to have to escape
+% all `|_|' characters in the manuscript.  We make the underscore character
+% active, so that it typesets an underscore in horizontal mode, and does
+% its usual job as a subscript operator in maths mode.  Underscore must
+% already be in the special character lists, because of its use as a
+% subscript character, so this doesn't cause us a problem.
+%
+% \begin{macro}{\underscore}
+%
+% The |\underscore| macro typesets an underline character, using a horizontal
+% rule.  This is positioned slightly below the baseline, and is also slightly
+% wider than the default \TeX\ underscore.  This code is based on a similar
+% implementation found in the \package{lgrind} package.
+%
+%    \begin{macrocode}
+\def\underscore{%
+  \leavevmode%
+  \kern.06em%
+  \vbox{%
+    \hrule\@width.6em\@depth.4ex\@height-.34ex%
+  }%
+  \ifdim\fontdimen\@ne\font=\z@%
+    \kern.06em%
+  \fi%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\@foundunderscore}
+%
+% This macro is called by the `|_|' active character to sort out what to do.
+%
+% If this is maths mode, we use the |\sb| macro, which is already defined
+% to do subscripting.  Otherwise, we call |\textunderscore|, which picks the
+% nicest underscore it can find.
+%
+% There's some extra cunningness here, because I'd like to be able to
+% hyphenate after underscores usually, but not when there's another one
+% following.  And then, because \env{tabbing} redefines |\_|, there's some
+% more yukkiness to handle that: the usual |\@tabacckludge| mechanism doesn't
+% cope with this particular case.
+%
+%    \begin{macrocode}
+\let\usc@builtindischyphen\-
+\def\@uscore.{%
+  \ifmmode%
+    \expandafter\@firstoftwo%
+  \else%
+    \expandafter\@secondoftwo%
+  \fi%
+  \sb%
+  {\textunderscore\@ifnextchar_{}{\usc@builtindischyphen}}%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% Now we set up the active character.  Note the |\protect|, which makes
+% underscores work reasonably well in moving arguments.  Note also the way
+% we end with a some funny stuff to prevent spaces being lost if this is
+% written to a file.
+%
+%    \begin{macrocode}
+\if@uscore
+  \AtBeginDocument{%
+    \catcode`\_\active%
+    \begingroup%
+    \lccode`\~`\_%
+    \lowercase{\endgroup\def~{\protect\@uscore.}}%
+  }
+\fi
+%    \end{macrocode}
+%
+% Finally, we redefine the |\_| macro to use our own |\underscore|, because
+% it's prettier.  Actually, we don't: we just redefine the
+% |\?\textunderscore| command (funny name, isn't it?).
+%
+%    \begin{macrocode}
+\expandafter\let\csname?\string\textunderscore\endcsname\underscore
+%    \end{macrocode}
+%
+% \subsection{Abbreviated verbatim notation}
+%
+%  In similar style to the \package{doc} package, we allow the user to set up
+% characters which delimit verbatim text.  Unlike \package{doc}, we make
+% such changes local to the current group.  This is performed through the
+% |\shortverb| and |\unverb| commands.
+%
+% The implementations of these commands are based upon the |\MakeShortVerb|
+% and |\DeleteShortVerb| commands of the \package{doc} package, although
+% these versions have effect local to the current grouping level.  This
+% prevents their redefinition of |\dospecials| from interfering with the
+% grammar shortcuts, which require local changes only.
+%
+% The command |\shortverb| takes a single argument: a single-character
+% control sequence defining which character to make into the verbatim text
+% delimiter.  We store the old meaning of the active character in a control
+% sequence called |\mn@\|\<char>.  Note that this control sequence
+% contains a backslash character, which is a little odd.  We also define a
+% command |\cc@\|\<char> which will return everything to normal.  This
+% is used by the |\unverb| command.
+%
+% \begin{macro}{\shortverb}
+%
+% Here we build the control sequences we need to make everything work nicely.
+% The active character is defined via |\lowercase|, using the |~| character:
+% this is already made active by \TeX\@.
+%
+% The actual code requires lots of fiddling with |\expandafter| and friends.
+%
+%    \begin{macrocode}
+\def\shortverb#1{%
+%    \end{macrocode}
+%
+% First, we check to see if the command |\cc@\|\<char> has been defined.
+%
+%    \begin{macrocode}
+  \@ifundefined{cc@\string#1}{%
+%    \end{macrocode}
+%
+% If it hasn't been defined, we add the character to the specials list.
+%
+%    \begin{macrocode}
+    \addspecial#1%
+%    \end{macrocode}
+%
+% Now we set our character to be the lowercase version of |~|, which allows
+% us to use it, even though we don't know what it is.
+%
+%    \begin{macrocode}
+    \begingroup%
+    \lccode`\~`#1%
+%    \end{macrocode}
+%
+% Finally, we reach the tricky bit.  All of this is lowercased, so any
+% occurrences of |~| are replaced by the user's special character.
+%
+%    \begin{macrocode}
+    \lowercase{%
+      \endgroup%
+%    \end{macrocode}
+%
+% We remember the current meaning of the character, in case it has one.  We
+% have to use |\csname| to build the rather strange name we use for this.
+%
+%    \begin{macrocode}
+      \expandafter\let\csname mn@\string#1\endcsname~%
+%    \end{macrocode}
+%
+% Now we build |\cc@\|\<char>.  This is done with |\edef|, since more
+% of this needs to be expanded now than not.  In this way, the actual macros
+% we create end up being very short.
+%
+%    \begin{macrocode}
+      \expandafter\edef\csname cc@\string#1\endcsname{%
+%    \end{macrocode}
+%
+% First, add a command to restore the character's old catcode.
+%
+%    \begin{macrocode}
+        \catcode`\noexpand#1\the\catcode`#1%
+%    \end{macrocode}
+%
+% Now we restore the character's old meaning, using the version we saved
+% earlier.
+%
+%    \begin{macrocode}
+        \let\noexpand~\expandafter\noexpand%
+          \csname mn@\string#1\endcsname%
+%    \end{macrocode}
+%
+% Now we remove the character from the specials lists.
+%
+%    \begin{macrocode}
+        \noexpand\remspecial\noexpand#1%
+%    \end{macrocode}
+%
+% Finally, we delete this macro, so that |\unverb| will generate a warning
+% if the character is |\unverb|ed again.
+%
+%    \begin{macrocode}
+        \let\csname cc@\string#1\endcsname\relax%
+      }%
+%    \end{macrocode}
+%
+% All of that's over now.  We set up the new definition of the character,
+% in terms of |\verb|, and make the character active.  The nasty |\syn@ttspace|
+% is there to make the spacing come out right.  It's all right really.  Honest.
+%
+%    \begin{macrocode}
+      \def~{\verb~\syn@ttspace}%
+    }%
+    \catcode`#1\active%
+%    \end{macrocode}
+%
+% If our magic control sequence already existed, we can assume that the
+% character is already a verbatim delimiter, and raise a warning.
+%
+%    \begin{macrocode}
+  }{%
+    \PackageWarning{syntax}{Character `\expandafter\@gobble\string#1'
+                            is already a verbatim\MessageBreak
+                            delimiter}%
+  }%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\unverb}
+%
+% This is actually terribly easy: we just use the |\cc@\|\<char> command
+% we definied earlier, after making sure that it's been defined.
+%
+%    \begin{macrocode}
+\def\unverb#1{%
+  \@ifundefined{cc@\string#1}{%
+    \PackageWarning{syntax}{Character `\expandafter\@gobble\string#1'
+                            is not a verbatim\MessageBreak
+                            delimiter}%
+  }{%
+    \csname cc@\string#1\endcsname%
+  }%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \subsection{Style hooks for syntax forms}
+%
+% To allow the appearance of syntax things to be configured, we provide some
+% redefinable bits.
+%
+% The three types of objects (nonterminal symbols, and quoted and unquoted
+% terminals) each have two macros associated with them: one which does the
+% `left' bit of the typesetting, and one which does the `right' bit.  The
+% items are typeset as LR~boxes.  I'll be extra good while defining these
+% hooks, so that it's obvious what's going on; macho \TeX\ hacker things
+% resume after this section.
+%
+% \begin{macro}{\syntleft}
+% \begin{macro}{\syntright}
+%
+% I can't see why anyone would want to change the typesetting of
+% nonterminals, although I'll provide the hooks for symmetry's sake.
+%
+%     \begin{macrocode}
+\newcommand{\syntleft}{$\langle$\normalfont\itshape}
+\newcommand{\syntright}{$\rangle$}
+%    \end{macrocode}
+%
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\ulitleft}
+% \begin{macro}{\ulitright}
+% \begin{macro}{\litleft}
+% \begin{macro}{\litright}
+%
+% Now we can define the left and right parts of quoted and unquoted
+% terminals.  US~readers may want to put double quotes around the quoted
+% terminals, for example.
+%
+%    \begin{macrocode}
+\newcommand{\ulitleft}{\normalfont\ttfamily\syn@ttspace\frenchspacing}
+\newcommand{\ulitright}{}
+\newcommand{\litleft}{`\bgroup\ulitleft}
+\newcommand{\litright}{\ulitright\egroup'}
+%    \end{macrocode}
+%
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Simple syntax typesetting}
+%
+% In general text, we allow access to our typesetting conventions through
+% standard \LaTeX\ commands.
+%
+% \begin{macro}{\synt}
+%
+% The |\synt| macro typesets its argument as a syntactic quantity.  It puts
+% the text of the argument in italics, and sets angle brackets around it.
+% Breaking of a |\synt| object across lines is forbidden.
+%
+%    \begin{macrocode}
+\def\synt#1{\mbox{\syntleft{#1\/}\syntright}}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\lit}
+%
+% The |\lit| macro typesets its argument as literal text, to be typed in.
+% Normally, this means setting the text in |\tt| font, and putting quotes
+% around it, although the quotes can be suppressed by using the $*$-variant.
+%
+% The |\syn@ttspace| macro sets up the spacing for the text nicely: |\tt|
+% spaces tend to be a little wide.
+%
+%    \begin{macrocode}
+\def\lit{\@ifstar{\lit@i\ulitleft\ulitright}{\lit@i\litleft\litright}}
+\def\lit@i#1#2#3{\mbox{#1{#3\/}#2}}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\syn@ttspace}
+%
+% This sets up the |\spaceskip| value for |\tt| text.
+%
+%    \begin{macrocode}
+\def\syn@ttspace@{\spaceskip.35em\@plus.2em\@minus.15em\relax}
+%    \end{macrocode}
+%
+% However, this isn't always the right thing to do.
+%
+%    \begin{macrocode}
+\def\ttthinspace{\let\syn@ttspace\syn@ttspace@}
+\def\ttthickspace{\let\syn@ttspace\@empty}
+%    \end{macrocode}
+%
+% I know what I like thoough.
+%
+%    \begin{macrocode}
+\ttthinspace
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \subsubsection{The shortcuts}
+%
+% The easy part is over now.  The next job is to set up the `grammar
+% shortcuts' which allow easy changing of styles.
+%
+% We support four shortcuts:
+% \begin{itemize}
+% \item |`literal text'| typesets \syntax{`literal text'}
+% \item |<non-terminal>| typesets \syntax{<non-terminal>}
+% \item |"unquoted text"| typesets \syntax{"unquoted text"}
+% \item \verb"|" typesets a \syntax{|} character
+% \end{itemize}
+% These are all implemented through active characters, which are enabled
+% using the |\syntaxShortcuts| macro, described below.
+%
+% \begin{macro}{\readupto}
+%
+% \syntax{"\\readupto{"<char>"}{"<decls>"}{"<command>"}"} will read all
+% characters up until the next occurrence of \<char>.  Normally, all
+% special characters will be deactivated.  However, you can reactivate some
+% characters, using the \<decls> argument, which is processed before the
+% text is read.
+%
+% The code is borrowed fairly obviously from the \LaTeXe\ source for the
+% |\verb| command.
+%
+%    \begin{macrocode}
+\def\readupto#1#2#3{%
+  \bgroup%
+  \verb@eol@error%
+  \let\do\@makeother\dospecials%
+  #2%
+  \catcode`#1\active%
+  \lccode`\~`#1%
+  \gdef\verb@balance@group{\verb@egroup%
+     \@latex@error{\noexpand\verb illegal in command argument}\@ehc}%
+  \def\@vhook{\verb@egroup#3}%
+  \aftergroup\verb@balance@group%
+  \lowercase{\let~\@vhook}%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\syn@assist}
+%
+% The |\syn@assist| macro is used for defining three of the shortcuts.  It
+% is called as
+%
+% \begin{quote}
+% \syntax{"\\syn@assist{"<left-decls>"}{"<actives>"}{"<delimeter>"}" \\
+% \null \quad "{"<right-decls>"}{"<end-cmd>"}"}
+% \end{quote}
+%
+% It creates an hbox, sets up the escape sequences for quoting our magic
+% characters, and then typesets a box containing
+%
+% \begin{quote}
+% \syntax{<left-decls>"{"<delimited-text>"\\/}"<right-decls>}
+% \end{quote}
+%
+% The \<left-decls> and \<right-decls> can be |\relax| if they're not
+% required.
+%
+% The \<actives> argument is passed to |\readupto|, to allow some special
+% characters through.  By default, we re-enable |\|, and make `\verb*" "'
+% typeset some space glue, rather than a space character.  A macro
+% `\verb*"\ "' is defined to actually print a space character, which yield
+% `\verb*" "' in the `|\tt|' font. 
+%
+% Finally, it defines a |\ch| command, which, given a single-character
+% control sequence as its argument, typesets the character.  This is useful,
+% since |`| has been made active when we set up these calls, so the
+% direct |\char`\|\<char> doesn't work.
+%
+%    \begin{macrocode}
+\def\syn@assist#1#2#3#4#5{%
+%    \end{macrocode}
+%
+% First, we start the box, and open a group.  We use |\mbox| because it
+% does all the messing with |\leavevmode| which is needed.
+%
+%    \begin{macrocode}
+  \mbox\bgroup%
+%    \end{macrocode}
+%
+% Next job is to set up the escape sequences.
+%
+%    \begin{macrocode}
+  \chardef\\`\\%
+  \chardef\>`\>%
+  \chardef\'`\'%
+  \chardef\"`\"%
+  \chardef\ `\ %
+%    \end{macrocode}
+%
+% Now to define |\ch|.  This is done the obvious way.
+%
+%    \begin{macrocode}
+  \def\ch##1{\char`##1}%
+%    \end{macrocode}
+%
+% For active characters, we do some fiddling with |\lccode|s.
+%
+%    \begin{macrocode}
+  \def\act##1{%
+    \catcode`##1\active%
+    \begingroup%
+    \lccode`\~`##1%
+    \lowercase{\endgroup\def~}%
+  }%
+%    \end{macrocode}
+%
+% Finally, we do the real work of setting the text.  We use |\readupto| to
+% actually find the text we want.
+%
+%    \begin{macrocode}
+  #1%
+  \begingroup%
+  \readupto#3{%
+    \catcode`\\0%
+    \catcode`\ 10%
+    #2%
+  }{%
+    \/\endgroup#4\egroup#5%
+  }%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\syn@shorts}
+%
+% This macro actually defines the expansions for the active characters.
+% We have to do this separately because |`| must be active when we use it
+% in the |\def|, but we can't do that and use |\catcode| at the same time.
+% The arguments are commands to do before and after the actual command.
+% These are passed up from |\syntaxShortcuts|.
+%
+% All of the characters use |\syn@assist| in the obvious way except for
+% \verb"|", which drops into maths mode instead.
+%
+% Note that when changing the catcodes, we must save |`| until last.
+%
+%    \begin{macrocode}
+\begingroup
+\catcode`\<\active
+\catcode`\|\active
+\catcode`\"\active
+\catcode`\`\active
+%
+\gdef\syn@shorts#1#2{%
+%    \end{macrocode}
+%
+% The `|<|' character must typeset its argument in italics.  We make `|_|'
+% do the same as the `|\_|' command.
+%
+%    \begin{macrocode}
+  \def<{%
+    #1%
+    \syn@assist%
+      \syntleft%
+      {\act_{\@foundunderscore}}%
+      >%
+      \syntright%
+      {#2}%
+  }%
+%    \end{macrocode}
+%
+% The `|`|' and `|"|' characters should print its argument in |\tt| font.
+% We change the `|\tt|' space glue to provide nicer spacing on the line.
+%
+%    \begin{macrocode}
+  \def`{%
+    #1%
+    \syn@assist%
+      \litleft%
+      \relax%
+      '%
+      \litright%
+      {#2}%
+  }%
+  \def"{%
+    #1%
+    \syn@assist%
+      \ulitleft%
+      \relax%
+      "%
+      \ulitright%
+      {#2}%
+  }%
+%    \end{macrocode}
+%
+% Finally, the `\verb"|"' character is typeset by using the mysterious
+% |\textbar| command.
+%
+%    \begin{macrocode}
+  \def|{\textbar}%
+%    \end{macrocode}
+%
+% We're finished here now.
+%
+%    \begin{macrocode}
+}
+%
+\endgroup
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\syntaxShortcuts}
+%
+% This is a user-level command which enables the use of our shortcuts in the
+% current group.  It uses |\addspecial|, defined below, to register the
+% active characters, sets up their definitions and activates them.
+%
+% The two arguments are commands to be performed before and after the
+% handling of the abbreviation.  In this way, you can further process the
+% output.
+%
+% This command is not intended to be used directly by users: it should be
+% used by other macros and packages which wish to take advantage of the
+% facilities offered by this package.  We provide a |\synshorts| declaration
+% (which may be used as an environment, of course) which is more `user
+% palatable'.
+%
+%    \begin{macrocode}
+\def\syntaxShortcuts#1#2{%
+  \syn@shorts{#1}{#2}%
+  \addspecial\`%
+  \addspecial\<%
+  \addspecial\|%
+  \addspecial\"%
+  \catcode`\|\active%
+  \catcode`\<\active% 
+  \catcode`\"\active%
+  \catcode`\`\active%
+}
+%
+\def\synshorts{\syntaxShortcuts\relax\relax}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\synshortsoff}
+%
+% This macro can be useful occasionally: it disables the syntax shortcuts,
+% so you can type normal text for a while.
+%
+%    \begin{macrocode}
+\def\synshortsoff{%
+  \catcode`\|12%
+  \catcode`\<12%
+  \catcode`\"12%
+  \catcode`\`12%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\syntax}
+%
+% The |\syntax| macro typesets its argument, allowing the use of our
+% shortcuts within the argument.
+%
+% Actually, we go to some trouble to ensure that the argument to |\syntax|
+% \emph{isn't} a real argument so we can change catcodes as we go.  We
+% use the |\let\@let@token=| trick from \PlainTeX\ to do this.
+%
+%    \begin{macrocode}
+\def\syntax#{\bgroup\syntaxShortcuts\relax\relax\let\@let@token}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{environment}{grammar}
+%
+% The \env{grammar} environment is the final object we have to define.  It
+% allows typesetting of beautiful BNF grammars.
+%
+% First, we define the length parameters we need:
+%
+%    \begin{macrocode}
+\newskip\grammarparsep
+  \grammarparsep8\p@\@plus\p@\@minus\p@
+\newdimen\grammarindent
+  \grammarindent2em
+%    \end{macrocode}
+%
+% Now define the default label typesetting.  This macro is designed to be
+% replaced by a user, so we'll be extra-well-behaved and use genuine \LaTeX\
+% commands.  Well, almost \dots
+%
+%    \begin{macrocode}
+\newcommand{\grammarlabel}[2]{%
+  \synt{#1} \hfill#2%
+}
+%    \end{macrocode}
+%
+% Now for a bit of hacking to make the item stuff work properly.  This gets
+% done for every new paragraph that's started without an |\item| command.
+%
+% First, store the left hand side of the production in a box.  Then I'll
+% end the paragraph, and insert some nasty glue to take up all the space,
+% so no-one will ever notice that there was a paragraph break there.  The
+% strut just makes sure that I know exactly how high the line is.
+%
+%    \begin{macrocode}
+\def\gr@implitem<#1> #2 {%
+  \sbox\z@{\hskip\labelsep\grammarlabel{#1}{#2}}%
+  \strut\@@par%
+  \vskip-\parskip%
+  \vskip-\baselineskip%
+%    \end{macrocode}
+%
+% The |\item| command will notice that I've inserted these funny glues and
+% try to remove them: I'll stymie its efforts by inserting an invisible
+% rule.  Then I'll insert the label using |\item| in the normal way.
+%
+%    \begin{macrocode}
+  \hrule\@height\z@\@depth\z@\relax%
+  \item[\unhbox\z@]%
+%    \end{macrocode}
+%
+% Just before I go, I'll make \lit{<} back into an active character.
+%
+%    \begin{macrocode}
+  \catcode`\<\active%
+}
+%    \end{macrocode}
+%
+% As an abbreviation for syntax diagrams, I usurp the |\[| and |\]| commands.
+% Here are the old versions.
+%
+%    \begin{macrocode}
+\let\gr@leftsq\[
+\let\gr@rightsq\]
+\def\[{\gr@leftsq}
+\def\]{\gr@rightsq}
+%    \end{macrocode}
+%
+% Now for the environment proper.  Deep down, it's a list environment, with
+% some nasty tricks to stop anyone from noticing.
+%
+% The first job is to set up the list from the parameters I'm given.
+%
+%    \begin{macrocode}
+\newenvironment{grammar}{%
+  \list{}{%
+    \labelwidth\grammarindent%
+    \leftmargin\grammarindent%
+    \advance\grammarindent\labelsep
+    \itemindent\z@%
+    \listparindent\z@%
+    \parsep\grammarparsep%
+  }%
+%    \end{macrocode}
+%
+% We have major problems in |\raggedright| layouts, which try to use |\par|
+% to start new lines.  We go back to normal |\\| newlines to try and bodge
+% our way around these problems.
+%
+%    \begin{macrocode}
+  \let\\\@normalcr
+%    \end{macrocode}
+%
+% Now to enable the shortcuts.
+%
+%    \begin{macrocode}
+  \syntaxShortcuts\relax\relax%
+%    \end{macrocode}
+%
+% Now a little bit of magic.  The |\alt| macro moves us to a new line, and
+% typesets a vertical bar in the margin.  This allows typesetting of
+% multiline alternative productions in a pretty way.
+%
+%    \begin{macrocode}
+  \def\alt{\\\llap{\textbar\quad}}%
+%    \end{macrocode}
+%
+% Now for another bit of magic.  We set up some |\par| cleverness to spot
+% the start of each production rule and format it in some cunning and
+% user-defined way.
+%
+%    \begin{macrocode}
+  \def\gr@setpar{%
+    \def\par{%
+      \parshape\@ne\@totalleftmargin\linewidth%
+      \@@par%
+      \catcode`\<12%
+      \everypar{%
+        \everypar{}%
+        \catcode`\<\active%
+        \gr@implitem%
+      }%
+    }%
+  }%
+  \gr@setpar%
+  \par%
+%    \end{macrocode}
+%
+% Now set up the |\[[| and |\]]| commands to do the right thing.  We have
+% to check the next character to see if it's correct, otherwise we'll
+% open a maths display as usual.
+%
+%    \begin{macrocode}
+  \def\gr@endsyntdiag]{\end{syntdiag}\gr@setpar\par}%
+  \def\[{\@ifnextchar[{\begin{syntdiag}\@gobble}\gr@leftsq}%
+  \def\]{\@ifnextchar]\gr@endsyntdiag\gr@rightsq}%
+%    \end{macrocode}
+%
+% Well, that's it for this side of the environment.
+%
+%    \begin{macrocode}
+}{%
+%    \end{macrocode}
+%
+% Closing the environment is a simple matter of tidying away the list.
+%
+%    \begin{macrocode}
+  \@newlistfalse%
+  \everypar{}%
+  \endlist%
+}
+%    \end{macrocode}
+%
+% \end{environment}
+%
+% \subsection{Syntax diagrams}
+%
+% Now we come to the final and most complicated part of the package.
+%
+% Syntax diagrams are drawn using arrow characters from \LaTeX's line font,
+% used in the \env{picture} environment, and rules.  The horizontal rules
+% of the diagram are drawn along the baselines of the lines in which they
+% are placed.  The text items in the diagram are placed in boxes and lowered
+% below the main baseline.  Struts are added throughout to keep the vertical
+% spacing consistent.
+%
+% The vertical structures (stacks and loops) are all implemented with \TeX's
+% primitive |\halign| command.
+%
+% \subsubsection{User-configurable parameters}
+%
+% First, we allocate the \<dimen> and \<skip> arguments needed.  Fixed
+% lengths, as the \LaTeX book calls them, are allocated as \<dimen>s, to
+% take some of the load off of all the \<skip> registers.
+%
+%    \begin{macrocode}
+\newskip\sdstartspace
+\newskip\sdendspace
+\newskip\sdmidskip
+\newskip\sdtokskip
+\newskip\sdfinalskip
+\newdimen\sdrulewidth
+\newdimen\sdcirclediam
+\newdimen\sdindent
+%    \end{macrocode}
+%
+% We need some \TeX\ \<dimen>s for our own purposes, to get everything in
+% the right places.  We use labels for the `temporary' \TeX\ parameters
+% which we use, to avoid wasting registers.
+%
+%    \begin{macrocode}
+\dimendef\sd@lower\z@
+\dimendef\sd@upper\tw@
+\dimendef\sd@mid4
+\dimendef\sd@topcirc6
+\dimendef\sd@botcirc8
+%    \end{macrocode}
+%
+% \begin{macro}{\sd@setsize}
+% When the text size for syntax diagrams changes, it's necessary to work out
+% the height for various rules in the diagram.
+%
+%    \begin{macrocode}
+\def\sd@setsize{%
+  \sd@mid\ht\strutbox%
+  \advance\sd@mid-\dp\strutbox%
+  \[email protected]\sd@mid%
+  \sd@upper\sdrulewidth%
+    \advance\sd@upper\sd@mid%
+  \sd@lower\sdrulewidth%
+    \advance\sd@lower-\sd@mid%
+  \[email protected]\sdcirclediam%
+    \advance\sd@topcirc\sd@mid%
+  \[email protected]\sdcirclediam%
+    \advance\sd@botcirc-\sd@mid%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\sdsize}
+%
+% You can set the default type size used by syntax diagrams by redefining
+% the |\sdsize| command, using the |\renewcommand| command.
+%
+% By default, syntax diagrams are set slightly smaller than the main body
+% text.\footnote{^^A
+%   I've used pure \LaTeX\ commands for this and the \cmd\sdlengths\ macro,
+%   to try and illustrate how these values might be changed by a user.  The
+%   rest of the code is almost obfuscted in its use of raw \TeX\ features,
+%   in an attempt to dissuade more na\"\i ve users from fiddling with it.
+%   I suppose this is what you get when you let assembler hackers loose with
+%   something like \LaTeX.
+% }
+%
+%    \begin{macrocode}
+\newcommand{\sdsize}{%
+  \small%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\sdlengths}
+%
+% Finally, the default length parameters are set in the |\sdlengths| command.
+% You can redefine the command using |\renewcommand|.
+%
+% We set up the length parameters here.
+%
+%    \begin{macrocode}
+\newcommand{\sdlengths}{%
+  \setlength{\sdstartspace}{1em minus 10pt}%
+  \setlength{\sdendspace}{1em minus 10pt}%
+  \setlength{\sdmidskip}{0.5em plus 0.0001fil}%
+  \setlength{\sdtokskip}{0.25em plus 0.0001fil}%
+  \setlength{\sdfinalskip}{0.5em plus 10000fil}%
+  \setlength{\sdrulewidth}{0.2pt}%
+  \setlength{\sdcirclediam}{8pt}%
+  \setlength{\sdindent}{0pt}%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \subsubsection{Other declarations}
+%
+% We define four switches.  The table shows what they're used for.
+%
+% \begin{table}
+% \begin{tab}{lp{3in}}                                              \hline
+%
+% \bf Switch        & \bf Meaning                                \\ \hline
+%
+% |\ifsd@base|      & We are at `base level' in the diagram:
+%                     i.e., not in any other sorts of
+%                     constructions.  This is used to decide
+%                     whether to allow line breaking.            \\[2pt]
+%
+% |\ifsd@top|       & The current loop construct is being
+%                     typeset with the loop arrow above the
+%                     baseline.                                  \\[2pt]
+%
+% |\ifsd@toplayer|  & We are typesetting the top layer of
+%                     a stack.  This is used to ensure that
+%                     the vertical rules on either side are
+%                     typeset at the right height.               \\[2pt]
+%
+% |\ifsd@backwards| & We're typesetting backwards, because
+%                     we're in the middle of a loop arrow.
+%                     the only difference this makes is that
+%                     any subloops have the arrow on the
+%                     side.                                      \\ \hline
+%
+% \end{tab}
+% \caption{Syntax diagram switches}
+% \end{table}
+%
+%    \begin{macrocode}
+\newif\ifsd@base
+\newif\ifsd@top
+\newif\ifsd@toplayer
+\newif\ifsd@backwards
+%    \end{macrocode}
+%
+% \begin{macro}{\sd@err}
+%
+% We output our errors through this macro, which saves a little typing.
+%
+%    \begin{macrocode}
+\def\sd@err{\PackageError{syntax}}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \subsubsection{Arrow-drawing}
+%
+% We need to draw some arrows.  \LaTeX\ tries to make this as awkward as
+% possible, so we have to start moving the arrows around in boxes quite a
+% lot.
+%
+% The left and right pointing arrows are fairly simple: we just add some
+% horizontal spacing to prevent the width of the arrow looking odd.
+%
+%    \begin{macrocode}
+\def\sd@arrow{%
+  \ht\tw@\z@%
+  \dp\tw@\z@%
+  \raise\sd@mid\box\tw@%
+  \egroup%
+}
+\def\sd@rightarr{%
+  \bgroup%
+  \setbox\tw@\hbox{\kern-6\p@\@linefnt\char'55}%
+  \sd@arrow%
+}
+\def\sd@leftarr{%
+  \bgroup%
+  \raise\sd@mid\hbox{\@linefnt\char'33\kern-6\p@}%
+  \sd@arrow%
+}
+%    \end{macrocode}
+%
+% The up arrow is very strange.  We need to bring the arrow down to base
+% level, and smash its height.
+%
+%    \begin{macrocode}
+\def\sd@uparr{%
+  \bgroup%
+  \setbox\tw@\hb@xt@\z@{\kern-\sdrulewidth\@linefnt\char'66\hss}%
+  \setbox\tw@\hbox{\lower10\p@\box\tw@}%
+  \sd@arrow%
+}
+%    \end{macrocode}
+%
+% The down arrow is similar, although it's already at the right height.
+% Thus, we can just smash the box.
+%
+%    \begin{macrocode}
+\def\sd@downarr{%
+  \bgroup%
+  \setbox\tw@\hb@xt@\z@{\kern-\sdrulewidth\@linefnt\char'77\hss}%
+  \sd@arrow%
+}
+%    \end{macrocode}
+%
+% \subsubsection{Drawing curves}
+%
+% If the user has selected curved edges, we use the \LaTeX\ features provided
+% to obtain the curves.  These are drawn slightly oddly to make it easier
+% to fit them into the diagram.
+%
+% Some explanation about the \LaTeX\ circle font is probably called for
+% before we go any further.  The font consists of sets of four quadrants
+% of a particular size (and some other characters, which aren't important
+% at the moment).  Each collection of quadrants fit together to form a
+% perfect circle of a given diameter.  The individual quadrant characters
+% have strange bounding boxes, as described in the files \textit{lcircle.mf}
+% and \textit{ltpict.dtx}, and also in Appendix~D of \textit{The \TeX book}.
+% Our job here is to make these quadrants useful in the context of
+% drawing syntax diagrams.
+%
+% \begin{macro}{\sd@circ}
+% First, we define |\sd@circ|, which performs the common parts of the four
+% routines.  Since the characters in the circle font are grouped together,
+% we can pick out a particular corner piece by specifying its index into
+% the group for the required size.  The |\sd@circ| routine will pick out
+% the required character, given this index as an argument, and put it in
+% box~2, after fiddling with the sizes a little:
+% \begin{itemize}
+%
+% \item We clear the width to zero.  The individual routines then add a kern
+%       of the correct amount, so that the quadrant appears in the right
+%       place.
+%
+% \item The piece is lowered by half the rule width.  This positions the
+%       top and bottom pieces of the circle to be half way over the baseline,
+%       which is the correct position for the rest of the diagram.
+%
+% \end{itemize}
+%
+% Finally, we make sure we're in horizontal mode: horrific results occur
+% if this is not the case.  I'm sure I don't need to explain this any more
+% graphically.
+%
+%    \begin{macrocode}
+\def\sd@circ#1{%
+  \@getcirc\sdcirclediam%
+  \advance\@tempcnta#1%
+  \setbox\tw@\hbox{\lower\sdrulewidth%
+    \hbox{\@circlefnt\char\@tempcnta}}%
+  \wd\tw@\z@%
+  \leavevmode%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\sd@tlcirc}
+% \begin{macro}{\sd@trcirc}
+% \begin{macro}{\sd@blcirc}
+% \begin{macro}{\sd@brcirc}
+%
+% These are the macros which actually draw quadrants of circles.  They all
+% call |\sd@circ|, passing an appropriate index, and then fiddle with the
+% box sizes and apply kerning specific to the quadrant positioning.
+%
+% The exact requirements for positioning are as follows:
+%
+% \begin{itemize}
+%
+% \item The horizontal parts of the arcs must lie along the baseline (i.e.,
+%       half the line must be above the baseline, and half must be below).
+%       This is consistent with the horizontal rules used in the diagram.
+%
+% \item The vertical parts must overlap vertical rules on either side, so
+%       that a |\vrule\sd@|\textit{xx}|circ| makes the arc appear to be
+%       a real curve in the line.  The requirements are actually somewhat
+%       inconsistent; for example, the \env{stack} environment uses curves
+%       \emph{before} the |\vrule|s.  Special requirements like this are
+%       handled as special cases later.
+%
+% \item The height and width of the arc are at least roughly correct.
+%
+% \end{itemize}
+%
+%    \begin{macrocode}
+\def\sd@tlcirc{{%
+  \sd@circ3%
+  \ht\tw@\sdrulewidth%
+  \dp\[email protected]\sdcirclediam%
+  \kern-\tw@\sdrulewidth%
+  \raise\sd@mid\box\tw@%
+  \kern.5\sdcirclediam%
+}}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\def\sd@trcirc{{%
+  \sd@circ0%
+  \ht\tw@\sdrulewidth%
+  \dp\[email protected]\sdcirclediam%
+  \kern.5\sdcirclediam%
+  \raise\sd@mid\box\tw@%
+}}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\def\sd@blcirc{{%
+  \sd@circ2%
+  \ht\[email protected]\sdcirclediam%
+  \dp\tw@\sdrulewidth%
+  \kern-\tw@\sdrulewidth%
+  \raise\sd@mid\box\tw@%
+  \kern.5\sdcirclediam%
+}}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\def\sd@brcirc{{%
+  \sd@circ1%
+  \ht\[email protected]\sdcirclediam%
+  \dp\tw@\sdrulewidth%
+  \kern.5\sdcirclediam%
+  \raise\sd@mid\box\tw@%
+}}
+%    \end{macrocode}
+%
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\sd@llc}
+% \begin{macro}{\sd@rlc}
+%
+% In the \env{rep} environment, we need to be able to draw arcs with
+% horizontal lines running through them.  The two macros here do the job
+% nicely.  |\sd@llc| (which is short for left overlapping circle) is
+% analogous to |\llap|: it puts its argument in a box of zero width, sticking
+% out to the left.  However, it also draws a rule along the baseline.  This
+% is important, as it prevents text from overprinting the arc.  |\sd@rlc|
+% is very similar, just the other way around.
+%
+%    \begin{macrocode}
+\def\sd@llc#1{%
+  \hb@[email protected]\sdcirclediam{%
+    \sd@rule\hskip.5\sdcirclediam%
+    \hss%
+    #1%
+  }%
+}
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+\def\sd@rlc#1{%
+  \hb@[email protected]\sdcirclediam{%
+    #1%
+    \hss%
+    \sd@rule\hskip.5\sdcirclediam%
+  }%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+% \end{macro}
+%
+% \subsubsection{Drawing rules}
+%
+% It's important to draw the rules \emph{along} the baseline, rather than
+% above it: hence, the depth of the rule must be equal to the height.
+%
+% \begin{macro}{\sd@rule}
+%
+% We use rule leaders instead of glue through most of the syntax diagrams.
+% The command \syntax{"\\sd@rule"<skip>} draws a rule of the correct
+% dimensions, which has the behaviour of an \syntax{"\\hskip"<skip>}.
+%
+%    \begin{macrocode}
+\def\sd@rule{\leaders\hrule\@height\sd@upper\@depth\sd@lower}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\sd@gap}
+%
+% The gap between elements is added using this macro.  It will allow a
+% line break if we're at the top level of the diagram, using a rather
+% strange discretionary.
+%
+% This is called as \syntax{"\\sd@gap{"<skip-register>"}"}.
+%
+%    \begin{macrocode}
+\def\sd@gap#1{%
+%    \end{macrocode}
+%
+% First, we see if we're at the top level.  Within constructs, we avoid the
+% overhead of a |\discretionary|.  We put half of the width of the skip on
+% each side of the discretionary break.
+%
+%    \begin{macrocode}
+  \ifsd@base%
+    \skip@#1%
+      \divide\skip\z@\tw@%
+    \nobreak\sd@rule\hskip\skip@%
+    \discretionary{%
+      \sd@qarrow{->}%
+    }{%
+      \hbox{%
+        \sd@qarrow{>-}%
+        \sd@rule\hskip\sdstartspace%
+        \sd@rule\hskip3.5\p@%
+      }%
+    }{%
+    }%
+    \nobreak\sd@rule\hskip\skip@%
+%    \end{macrocode}
+%
+% If we're not at the base level, we just put in a rule of the correct
+% width.
+%
+%    \begin{macrocode}
+  \else%
+    \sd@rule\hskip#1%
+  \fi%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \subsubsection{The \protect\env{syntdiag} environment}
+%
+% All syntax diagrams are contained within a \env{syntdiag} environment.
+%
+% \begin{environment}{syntdiag}
+%
+% The only argument is a collection of declarations, which by
+% default is
+%
+% \begin{listing}
+%\sdsize\sdlengths
+% \end{listing}
+%
+% However, if the optional argument is not specified, \TeX\ reads the first
+% character of the environment, which may not be catcoded correctly.  We set
+% up the catcodes first, using the |\syntaxShortcuts| command, and then read
+% the argument.  We don't use |\newcommand|, because that would involve
+% creating yet \emph{another} macro.  Time to fiddle with |\@ifnextchar|
+% \dots
+%
+%    \begin{macrocode}
+\def\syntdiag{%
+  \syntaxShortcuts\sd@tok@i\sd@tok@ii%
+  \@ifnextchar[\syntdiag@i{\syntdiag@i[]}%
+}
+%    \end{macrocode}
+%
+% Now we actually do the job we're meant to.
+%
+%    \begin{macrocode}
+\def\syntdiag@i[#1]{%
+%    \end{macrocode}
+%
+% The first thing to do is execute the user's declarations.  We then set
+% up things for the font size.
+%
+%    \begin{macrocode}
+  \sdsize\sdlengths%
+  #1%
+  \sd@setsize%
+%    \end{macrocode}
+%
+% Next, we start a list, to change the text layout.
+%
+%    \begin{macrocode}
+  \list{}{%
+    \leftmargin\sdindent%
+    \rightmargin\leftmargin%
+    \labelsep\z@%
+    \labelwidth\z@%
+  }%
+  \item[]%
+%    \end{macrocode}
+%
+% We reconfigure the paragraph format quite a lot now.  We clear
+% |\parfillskip| to avoid any justification at the end of the paragraph.
+% We also turn off paragraph indentation.
+%
+%    \begin{macrocode}
+  \parfillskip\z@%
+  \noindent%
+%    \end{macrocode}
+%
+% Next, we add in the arrows on the beginning of the line, and a bit of
+% glue.
+%
+%    \begin{macrocode}
+  \sd@qarrow{>>-}%
+  \nobreak\sd@rule\hskip\sdstartspace%
+%    \end{macrocode}
+%
+% This is the base level of the diagram, so we enable line breaking.
+%
+%    \begin{macrocode}
+  \sd@basetrue%
+%    \end{macrocode}
+%
+% Since the objects being broken are rather large, we enable sloppy line
+% breaking.  We also try to avoid page breaks in mid-diagram, by upping the
+% |\interlinepenalty|.
+%
+%    \begin{macrocode}
+  \sloppy%
+  \interlinepenalty100%
+  \hyphenpenalty0%
+%    \end{macrocode}
+%
+% We handle all the spacing within the environment, so we make \TeX\ ignore
+% spaces and newlines.
+%
+%    \begin{macrocode}
+  \catcode`\ 9%
+  \catcode`\^^M9%
+%    \end{macrocode}
+%
+% The environment names are rather cumbersome.  I'll define some better names
+% for them here.
+%
+%    \begin{macrocode}
+  \def\gr@leftsq{\begin{stack}\\}%
+  \def\gr@rightsq{\end{stack}}%
+  \def\({\begin{stack}}%
+  \def\){\end{stack}}%
+  \def\<{\begin{rep}}%
+  \def\>{\end{rep}}%
+%    \end{macrocode}
+%
+% We now have to change the behaviour of |\\| to line-break syntax diagrams.
+%
+%    \begin{macrocode}
+  \let\\\sd@newline%
+  \ignorespaces%
+}
+%    \end{macrocode}
+%
+% When we end the diagram, we just have to add in the final fillskip, and
+% double arrow.
+%
+%    \begin{macrocode}
+\def\endsyntdiag{%
+  \unskip%
+  \nobreak\sd@rule\hskip\sdmidskip%
+  \sd@rule\hskip\sdfinalskip%
+  \sd@qarrow{-><}%
+  \endlist%
+}
+%    \end{macrocode}
+%
+% \end{environment}
+%
+% \begin{environment}{syntdiag*}
+%
+% The starred form of \env{syntdiag} typesets a syntax diagram in LR-mode;
+% this is useful if you're describing parts of syntax diagrams, for example.
+%
+% This is in fact really easy.  The first bit which checks for an optional
+% argument is almost identical to the non-$*$ version.
+%
+%    \begin{macrocode}
+\@namedef{syntdiag*}{%
+  \syntaxShortcuts\sd@tok@i\sd@tok@ii%
+  \@ifnextchar[\syntdiag@s@i{\syntdiag@s@i[]}%
+}
+%    \end{macrocode}
+%
+% Handle another optional argument giving the width of the box to fill.
+%
+%    \begin{macrocode}
+\def\syntdiag@s@i[#1]{%
+  \@ifnextchar[{\syntdiag@s@ii{#1}}{\syntdiag@s@iii{#1}{\hbox}}%
+}
+\def\syntdiag@s@ii#1[#2]{\syntdiag@s@iii{#1}{\hb@xt@#2}}
+%    \end{macrocode}
+%
+% Now to actually start the display.  This is mostly simple.  Just to make
+% sure about the LR-ness of the typesetting, I'll put everything in an hbox.
+%
+%    \begin{macrocode}
+\def\syntdiag@s@iii#1#2{%
+  \leavevmode%
+  #2\bgroup%
+%    \end{macrocode}
+%
+% Now configure the typesetting according to the user's wishes.
+%
+%    \begin{macrocode}
+  \let\@@left\left%
+  \let\@@right\right%
+  \def\left##1{\def\sd@startarr{##1}}%
+  \def\right##1{\def\sd@endarr{##1}}%
+  \left{>-}\right{->}%
+  \sdsize\sdlengths%
+  #1%
+  \sd@setsize%
+  \let\left\@@left%
+  \let\right\@@right%
+%    \end{macrocode}
+%
+% Put in the initial double-arrow.
+%
+%    \begin{macrocode}
+  \sd@qarrow\sd@startarr%
+  \sd@rule\hskip\sdmidskip%
+%    \end{macrocode}
+%
+% We're in horizontal mode, so don't bother with linebreaking.
+%
+%    \begin{macrocode}
+  \sd@basefalse%
+%    \end{macrocode}
+%
+% Finally, disable spaces and things.
+%
+%    \begin{macrocode}
+  \catcode`\ 9%
+  \catcode`\^^M9%
+  \ignorespaces%
+}
+%    \end{macrocode}
+%
+% Ending the environment is very similar.
+%
+%    \begin{macrocode}
+\@namedef{endsyntdiag*}{%
+  \unskip%
+  \sd@rule\hskip\sdmidskip%
+  \sd@rule\hskip\sdfinalskip%
+  \sd@qarrow\sd@endarr%
+  \egroup%
+}
+%    \end{macrocode}
+%
+% \end{environment}
+%
+% \begin{macro}{\sd@qarrow}
+%
+% This typesets the various left and right arrows required in syntax
+% diagrams.  The argument is one of \syntax{`>>-', `->', `>-' or `-><'}.
+%
+%    \begin{macrocode}
+\def\sd@qarrow#1{%
+  \begingroup%
+  \lccode`\~=`\<\lowercase{\def~{<}}%
+  \hbox{\csname sd@arr@#1\endcsname}%
+  \endgroup%
+}
+\@namedef{sd@arr@>>-}{\sd@rightarr\kern-.5\p@\sd@rightarr\kern-\p@}
+\@namedef{sd@arr@>-}{\sd@rightarr\kern-\p@}
+\@namedef{sd@arr@->}{\sd@rightarr}
+\@namedef{sd@arr@-><}{\sd@rightarr\kern-\p@\sd@leftarr}
+\@namedef{sd@arr@...}{$\cdots$}
+\@namedef{sd@arr@-}{}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\sd@newline}
+%
+% The line breaking within a syntax diagram is controlled by the
+% |\sd@newline| command, to which |\\| is assigned.
+%
+% We support all the standard \LaTeX\ features here.  The line breaking
+% involves adding a fill skip and arrow, moving to the next line, adding
+% an arrow and a rule, and continuing.
+%
+%    \begin{macrocode}
+\def\sd@newline{\@ifstar{\vadjust{\penalty\@M}\sd@nl@i}\sd@nl@i}
+\def\sd@nl@i{\@ifnextchar[\sd@nl@ii\sd@nl@iii}
+\def\sd@nl@ii[#1]{\vspace{#1}\sd@nl@iii}
+\def\sd@nl@iii{%
+  \nobreak\sd@rule\hskip\sdmidskip%
+  \sd@rule\hskip\sdfinalskip%
+  \kern-3\p@%
+  \sd@rightarr%
+  \newline%
+  \sd@rightarr%
+  \nobreak\sd@rule\hskip\sdstartspace%
+  \sd@rule\hskip3.5\p@%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \subsubsection{Putting things in the right place}
+%
+% Syntax diagrams have fairly stiff requirements on the positioning of text
+% relative to the diagram's rules.  To help people (and me) to write
+% extensions to the syntax diagram typesetting which automatically put things
+% in the right place, I provide some simple macros.
+%
+% \begin{environment}{sdbox}
+%
+% By placing some text in the \env{sdbox} environment, it will be read into a
+% box and then output at the correct height for the syntax diagram.  Note
+% that stuff in the box is set in horizontal (LR) mode, so you'll have to use
+% a \env{minipage} if you want formatted text.  The macro also supplies rules
+% on either side of the box, with a length given in the environment's
+% argument.
+%
+% Macro writers are given explicit permission to use this environment through
+% the |\sdbox| and |\endsdbox| commands if this makes life easier.
+%
+% The calculation in the |\endsdbox| macro works out how to centre the box
+% vertically over the baseline.  If the box's height is~$h$, and its depth
+% is~$d$, then its centre-line is $(h+d)/2$ from the bottom of the box.
+% Since the baseline is already $d$ from the bottom, we need to lower the box
+% by $(h+d)/2 - d$, or $h/2-d/2$.
+%
+%    \begin{macrocode}
+\def\sdbox#1{%
+  \@tempskipa#1\relax%
+  \sd@gap\@tempskipa%
+  \setbox\z@\hbox\bgroup%
+    \begingroup%
+    \catcode`\ 10%
+    \catcode`\^^M5%
+    \synshortsoff%
+}
+\def\endsdbox{%
+    \endgroup%
+  \egroup%
+  \@tempdima\ht\z@%
+  \advance\@tempdima-\dp\z@%
+  \advance\@tempdima-\tw@\sd@mid%
+  \lower.5\@tempdima\box\z@%
+  \sd@gap\@tempskipa%
+}
+%    \end{macrocode}
+%
+% \end{environment}
+%
+% \subsubsection{Typesetting syntactic items}
+%
+% Using the hooks built into the syntax abbreviations above, we typeset
+% the text into a box, and write it out, centred over the baseline.  A strut
+% helps to keep the actual text baselines level for short pieces of text.
+%
+% \begin{macro}{\sd@tok@i}
+%
+% The preamble for a syntax abbreviation.  We start a box, and set the
+% space and return characters to work again.  A strut is added to the box to
+% ensure correct vertical spacing for normal text.
+%
+%    \begin{macrocode}
+\def\sd@tok@i{%
+  \sdbox\sdtokskip%
+  \strut%
+  \space%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\sd@tok@ii}
+%
+%    \begin{macrocode}
+\def\sd@tok@ii{%
+  \space%
+  \endsdbox%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \subsubsection{Inserting other pieces of text}
+%
+% Arbitrary text may be put into a syntax diagram through the use of the
+% |\tok| macro.  Its `argument' is typeset in the same way as a syntactic
+% item (centred over the baseline).  The implementation goes to some effort
+% to ensure that the text is not actually an argument, to allow category
+% codes to change while the text is being typeset.
+%
+% \begin{macro}{\tok}
+%
+% We start a box, and make space and return do their normal jobs.  We use
+% |\aftergroup| to regain control once the box is finished.  |\doafter| is
+% used to get control after the group finishes.
+%
+%    \begin{macrocode}
+\def\tok#{%
+  \sdbox\sdtokskip%
+  \strut%
+  \enspace%
+  \syntaxShortcuts\relax\relax%
+  \doafter\sd@tok%
+}
+%    \end{macrocode}
+%
+% The |\sd@tok| macro is similar to |\sd@tok@ii| above.
+%
+%    \begin{macrocode}
+\def\sd@tok{%
+  \enspace%
+  \endsdbox%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \subsubsection{The \protect\env{stack} environment}
+%
+% The \env{stack} environment is used to present alternatives in a syntax
+% diagram.  The alternatives are separated by |\\| commands.
+%
+% \begin{macro}{\stack}
+%
+% The optional positioning argument is handled using \LaTeX's |\newcommand|
+% mechanism.
+%
+%    \begin{macrocode}
+\newcommand\stack[1][t]{%
+%    \end{macrocode}
+%
+% First, we add some horizontal space.
+%
+%    \begin{macrocode}
+  \sd@gap\sdmidskip%
+%    \end{macrocode}
+%
+% We're within a complex construction, so we need to clear the |\ifsd@base|
+% flag.
+%
+%    \begin{macrocode}
+  \begingroup\sd@basefalse%
+%    \end{macrocode}
+%
+% The top and bottom rows of the stack are different to the others, since
+% the vertical rules mustn't extend all the way up the side of the item.
+% The bottom row is handled separately by |\endstack| below.  The top row
+% must be handled via a flag, |\ifsd@toplayer|.
+%
+% Initially, the flag must be set true.
+%
+%    \begin{macrocode}
+  \sd@toplayertrue%
+%    \end{macrocode}
+%
+% We set the |\\| command to separate the items in the |\halign|.
+%
+%    \begin{macrocode}
+  \let\\\sd@stackcr%
+%    \end{macrocode}
+%
+% The actual structure must be set in vertical mode, so we must place it
+% in a box.  The position argument determines whether this must be a
+% |\vbox| or a |\vtop|.  We also insert a bit of rounding if the options say
+% we must.
+%
+%    \begin{macrocode}
+  \if#1t%
+    \let\@tempa\vtop%
+    \sd@toptrue%
+    \ifsd@round\llap{\sd@trcirc\kern\tw@\sdrulewidth}\fi%
+  \else\if#1b%
+    \let\@tempa\vbox%
+    \sd@topfalse%
+    \ifsd@round\llap{\sd@brcirc\kern\tw@\sdrulewidth}\fi%
+  \else%
+    \sd@err{Bad position argument passed to stack}%
+           {The positioning argument must be one of `t' or `b'.  I%
+            have^^Jassumed you meant to type `t'.}%
+    \let\@tempa\vtop%
+  \fi\fi%
+%    \end{macrocode}
+%
+% Now we start the box, which we will complete at the end of the environment.
+%
+%    \begin{macrocode}
+  \@tempa\bgroup%
+%    \end{macrocode}
+%
+% We must remove any extra space between rows of the table, since the rules
+% will not join up correctly.  We can use |\offinterlineskip| safely, since
+% each individual row contains a strut.
+%
+%    \begin{macrocode}
+  \offinterlineskip%
+%    \end{macrocode}
+%
+% Now we can start the alignment.  We actually use \PlainTeX's |\ialign|
+% macro, which also clears |\tabskip| for us.
+%
+%    \begin{macrocode}
+  \ialign\bgroup%
+%    \end{macrocode}
+%
+% The preamble is trivial, since we must do all of the work ourselves
+%
+%    \begin{macrocode}
+    ##\cr%
+%    \end{macrocode}
+%
+% We can now start putting the text into a box ready for typesetting later.
+% The strut makes the vertical spacing correct.
+%
+%    \begin{macrocode}
+  \setbox\z@\hbox\bgroup%
+    \strut%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\endstack}
+%
+% The first part of this is similar to the |\sd@stackcr| macro below, except
+% that the vertical rules are different.  We don't support rounded edges
+% on single-row stacks, although this isn't a great loss to humanity.
+%
+%    \begin{macrocode}
+\def\endstack{%
+  \egroup%
+  \ifsd@toplayer%
+    \sd@dostack\sd@upper\sd@lower\relax\relax%
+  \else%
+    \ifsd@round%
+      \ifsd@top%
+        \sd@dostack{\ht\z@}\sd@botcirc\sd@blcirc\sd@brcirc%
+      \else%
+        \sd@dostack{\ht\z@}\sd@botcirc\relax\relax%
+      \fi%
+    \else%
+      \sd@dostack{\ht\z@}\sd@lower\relax\relax%
+    \fi%
+  \fi%
+%    \end{macrocode}
+%
+% We now close the |\halign| and the vbox we created.
+%
+%    \begin{macrocode}
+  \egroup%
+  \egroup%
+%    \end{macrocode}
+%
+% Deal with any rounding we started off.
+%
+%    \begin{macrocode}
+  \ifsd@round%
+    \ifsd@top
+      \rlap{\kern\tw@\sdrulewidth\sd@tlcirc}%
+    \else%
+      \rlap{\kern\tw@\sdrulewidth\sd@blcirc}%
+    \fi%
+  \fi%
+%    \end{macrocode}
+%
+% Finally, we add some horizontal glue to space the diagram out.
+%
+%    \begin{macrocode}
+  \endgroup\sd@gap\sdmidskip%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\sd@stackcr}
+%
+% The |\\| command is set to this macro during a \env{stack} environment.
+%
+%    \begin{macrocode}
+\def\sd@stackcr{%
+%    \end{macrocode}
+%
+% The first job is to close the box containing the previous item.
+%
+%    \begin{macrocode}
+  \egroup%
+%    \end{macrocode}
+%
+% Now we typeset the vertical rules differently depending on whether this is
+% the first item in the stack.  This looks quite terrifying initially, but
+% it's just an enumeration of the possible cases for the different values
+% of |\ifsd@toplayer|, |\ifsd@top| and |\ifsd@round|, putting in appropriate
+% rules and arcs in the right places.
+%
+%    \begin{macrocode}
+  \ifsd@toplayer%
+    \ifsd@round%
+      \ifsd@top%
+        \sd@dostack\sd@topcirc{\dp\z@}\relax\relax%
+      \else%
+        \sd@dostack\sd@topcirc{\dp\z@}\sd@tlcirc\sd@trcirc%
+      \fi%
+    \else%
+      \sd@dostack\sd@upper{\dp\z@}\relax\relax%
+    \fi%
+  \else%
+    \ifsd@round%
+      \ifsd@top%
+        \sd@dostack{\ht\z@}{\dp\z@}\sd@blcirc\sd@brcirc%
+      \else%
+        \sd@dostack{\ht\z@}{\dp\z@}\sd@tlcirc\sd@trcirc%
+      \fi%
+    \else%
+      \sd@dostack{\ht\z@}{\dp\z@}\relax\relax%
+    \fi%
+  \fi%
+%    \end{macrocode}
+%
+% The next item won't be the first, so we clear the flag.
+%
+%    \begin{macrocode}
+  \sd@toplayerfalse%
+%    \end{macrocode}
+%
+% Now we have to set up the next cell.  We put the text into a box again.
+%
+%    \begin{macrocode}
+  \setbox\z@\hbox\bgroup%
+    \strut%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\sd@dostack}
+%
+% Actually typesetting the text in a cell is performed here.  The macro is
+% called as
+% \begin{quote}\synshorts
+% "\\sd@dostack{"<height>"}{"<depth>"}{"<left-arc>"}{"<right-arc>"}"
+% \end{quote}
+% where \<height> and \<depth> are the height and depth of the vertical
+% rules to put around the item, and \<left-arc> and \<right-arc> are
+% commands to draw rounded edges on the left and right hand sides of the
+% item.
+%
+% The values for the height and depth are quite often going to be the height
+% and depth of box~0.  Since we empty box~0 in the course of typesetting the
+% row, we need to cache the sizes on entry.
+%
+%    \begin{macrocode}
+\def\sd@dostack#1#2#3#4{%
+  \@tempdima#1%
+  \@tempdimb#2%
+  \kern-\tw@\sdrulewidth%
+  \vrule\@height\@tempdima\@depth\@tempdimb\@width\tw@\sdrulewidth%
+  #3%
+  \sd@rule\hfill%
+  \sd@gap\sdtokskip%
+  \unhbox\z@%
+  \sd@gap\sdtokskip%
+  \sd@rule\hfill%
+  #4%
+  \vrule\@height\@tempdima\@depth\@tempdimb\@width\tw@\sdrulewidth%
+  \kern-\tw@\sdrulewidth%
+  \cr%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \subsubsection{The \protect\env{rep} environment}
+%
+% The \env{rep} environment is used for typesetting loops in the diagram.
+% Again, we use |\halign| for the typesetting.  Loops are simpler than
+% stacks, however, since there are always two rows.  We store both rows in
+% box registers, and build the loop at the end.
+%
+% \begin{macro}{\rep}
+%
+% Again, we use |\newcommand| to process the optional argument.
+%
+%    \begin{macrocode}
+\newcommand\rep[1][t]{%
+%    \end{macrocode}
+%
+% First, leave a gap on the left side.
+%
+%    \begin{macrocode}
+  \sd@gap\sdmidskip%
+%    \end{macrocode}
+%
+% We're not at base level any more, so disable linebreaking.
+%
+%    \begin{macrocode}
+  \begingroup\sd@basefalse%
+%    \end{macrocode}
+%
+% Remember we're going backwards now.
+%
+%    \begin{macrocode}
+  \ifsd@backwards\sd@backwardsfalse\else\sd@backwardstrue\fi%
+%    \end{macrocode}
+%
+% Define |\\| to separate the two parts of the loop.
+%
+%    \begin{macrocode}
+   \let\\\sd@loop%
+%    \end{macrocode}
+%
+% Now check the argument, and use the appropriate type of box.  In addition
+% to changing the typesetting, we must remember which way up to typeset the
+% loop, since the end code must always put the first argument on the
+% baseline, with the loop either above or below.
+%
+%    \begin{macrocode}
+  \if#1t%
+    \let\@tempa\vbox%
+    \sd@toptrue%
+  \else\if#1b%
+    \let\@tempa\vtop%
+    \sd@topfalse%
+  \else%
+    \sd@err{Bad position argument passed to loop}%
+           {The positioning argument must be `t' or `b'.  I have^^J%
+            assumed you meant to type `t'.}%
+    \let\@tempa\vbox%
+    \sd@toptrue%
+  \fi\fi%
+%    \end{macrocode}
+%
+% Now we start the box.
+%
+%    \begin{macrocode}
+  \@tempa\bgroup%
+%    \end{macrocode}
+%
+% The loop is by default empty, apart from a strut.  This is put into box~1.
+%
+%    \begin{macrocode}
+  \setbox\tw@\copy\strutbox%
+%    \end{macrocode}
+%
+% Now start typesetting the main text in box~0.
+%
+%    \begin{macrocode}
+  \setbox\z@\hbox\bgroup\strut%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\endrep}
+%
+% The final code must first close whatever box was open.
+%
+%    \begin{macrocode}
+\def\endrep{%
+  \egroup%
+%    \end{macrocode}
+%
+% Now we typeset the loop, depending on which way up it was meant to be.
+% Again, this terrifying piece of code is a simple list of possibile values
+% of our various flags.
+%
+%    \begin{macrocode}
+  \ifsd@top%
+    \ifsd@round%
+      \sd@doloop\tw@\z@\relax\relax%
+        \sd@tlcirc\sd@trcirc{\sd@rlc\sd@blcirc}{\sd@llc\sd@brcirc}%
+    \else%
+      \sd@doloop\tw@\z@\relax\sd@downarr\relax\relax\relax\relax%
+    \fi%
+  \else%
+    \ifsd@round%
+      \sd@doloop\z@\tw@\relax\relax%
+        {\sd@rlc\sd@tlcirc}{\sd@llc\sd@trcirc}\sd@blcirc\sd@brcirc%
+    \else%
+      \sd@doloop\z@\tw@\sd@uparr\relax\relax\relax\relax\relax%
+    \fi%
+  \fi%
+%    \end{macrocode}
+%
+% Close the vbox we opened.
+%
+%    \begin{macrocode}
+  \egroup%
+%    \end{macrocode}
+%
+% Finally, we leave a gap before the next structure.
+%
+%    \begin{macrocode}
+  \endgroup\sd@gap\sdmidskip%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\sd@loop}
+%
+% This macro handles the |\\| command within a loop environment.  We close
+% the current box, and start filling in box~1.  We also redefine |\\| to
+% raise an error when the |\\| command is used again.
+%
+%    \begin{macrocode}
+\def\sd@loop{%
+  \egroup%
+  \def\\{\sd@err{Too many \string\\\space commands in loop}\@ehc}%
+  \setbox\tw@\hbox\bgroup\strut%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\sd@doloop}
+%
+% This is the macro which actually creates the |\halign| for the loop.  It
+% is called with four arguments, as:
+% \begin{quote}\synshorts
+% "\\sd@doloop{"<top-box>"}{"<bottom-box>"}"^^A
+%                "{"<top-arrow>"}{"<btm-arrow>"}" \\
+% \hbox{}\quad "{"<top-left-arc>"}{"<top-right-arc>"}"^^A
+%                "{"<bottom-left-arc>"}{"<btm-right-arc>"}"^^A
+% \kern-1in ^^A It may be overfull, but it looks OK to me ;-)
+% \end{quote}
+%
+% The two \<box> arguments give the numbers of boxes to extract in the top
+% and bottom rows of the alignment.  The \<arrow> arguments specify
+% characters to typeset at the end of the top and bottom rows for arrows.
+% The various \<arc> arguments are commands which typeset arcs around the
+% various parts of the items.
+%
+% We calculate the height and depth of the two boxes, and store them in
+% \<dimen> registers, because the boxes are emptied before the right-hand
+% rules are typeset.
+%
+% Actually, the two rows of the alignment are typeset in a different macro:
+% we just pass the correct information on.
+%
+%    \begin{macrocode}
+\def\sd@doloop#1#2#3#4#5#6#7#8{%
+  \@tempdima\dp#1\relax%
+  \@tempdimb\ht#2\relax%
+  \offinterlineskip%
+  \ialign{%
+    ##\cr%
+    \ifsd@round%
+      \sd@doloop@i#1#3\sd@topcirc\@tempdima{#5}{#6}%
+      \sd@doloop@i#2#4\@tempdimb\sd@botcirc{#7}{#8}%
+    \else%
+      \sd@doloop@i#1#3\sd@upper\@tempdima{#5}{#6}%
+      \sd@doloop@i#2#4\@tempdimb\sd@lower{#7}{#8}%
+    \fi%
+  }%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \begin{macro}{\sd@doloop@i}
+%
+% Here we do the actual job of typesetting the rows of a loop alignment.
+% The four arguments are:
+% \begin{quote}\synshorts
+% "\\sd@doloop@i{"<box>"}{"<arrow>"}"^^A
+%              "{"<rule-height>"}{"<rule-depth>"}" \\
+% \hbox{}\quad "{"<left-arc>"}{"<right-arc>"}"^^A
+% \end{quote}
+%
+% The arrow position is determined by the |\ifsd@backwards| flag.  The rest
+% is fairly simple.
+%
+%    \begin{macrocode}
+\def\sd@doloop@i#1#2#3#4#5#6{%
+  \ifsd@backwards#2\fi%
+  \kern-\tw@\sdrulewidth%
+  \vrule\@height#3\@depth#4\@width\tw@\sdrulewidth%
+  #5%
+  \sd@rule\hfill%
+  \sd@gap\sdtokskip%
+  \unhbox#1%
+  \sd@gap\sdtokskip%
+  \sd@rule\hfill%
+  #6%
+  \vrule\@height#3\@depth#4\@width\tw@\sdrulewidth%
+  \ifsd@backwards\else#2\fi%
+  \kern-\tw@\sdrulewidth%
+  \cr%
+}
+%    \end{macrocode}
+%
+% \end{macro}
+%
+% \subsection{The end}
+%
+% Phew!  That's all of it completed.  I hope this collection of commands
+% and environments is of some help to someone.
+%
+%    \begin{macrocode}
+%</package>
+%    \end{macrocode}
+%
+% \hfill Mark Wooding, \today
+%
+% \Finale
+%
+\endinput