duchier@cs.yale.edu (Denys Duchier) (08/08/90)
There was some interest in my implementation of \Tabular which extended LaTeX's \tabular environment to allow it to be automatically split across pages. Here is a new implementation which folds this code back into LaTeX, supports the Mittelbach's extensions, and fixes bugs both in his code and in my earlier version. I wrote this new code over the weekend, and I expect there must still be a few interesting bugs lurking in it. Be kind... Be specific! In the new regime the array / tabular environments recognize `x' as an additional positioning option (e.g. \begin{tabular}[x]...); it means that once the table has been typeset, it should be unboxed to allow the rows to be split across pages. \hline attempts to do the right thing so that if the table is split at a \hline, the line appears both at the bottom of the page and at the top of the next page. The array environment is no longer constrained to appear only in math mode. The `x' option is incompatible with the `*' variants. Also, it cannot appear in math mode; however, since the array environment no longer has to appear in math mode, it too can be split (for example, just put it in a \center environment and use the `x' option). --Denys %% array.sty %% Denys Duchier, Yale University, August 1990 \newif\if@arraystart \@arraystarttrue % true at beginning of preamble \newif\if@arrayleftskip \@arrayleftskiptrue % cancelled by @ option \newif\if@arrayrightskip \@arrayrightskiptrue % cancelled by @ option \newif\if@arrayleftfil \@arrayleftfilfalse % column justification \newif\if@arrayrightfil \@arrayrightfilfalse % column justification \newif\if@arraymath \@arraymathfalse % entries in math mode? (local) \let\@preambletoks\toks@ \let\@preamblecontext\count@ \newcount\@arraycolnum \@arraycolnum\z@ \newdimen\extrarowheight \extrarowheight\z@ \def\@arrayleftinsert{} \def\@arrayrightinsert{} \def\@arrayleftbracket{} \def\@arrayrightbracket{} %% \@preamblecontext %% 0 -> before > option %% 1 -> after > option %% 2 -> after column specifier %% 3 -> after < option \def\@defarrayoption#1{\@namedef{@array@option@#1}} \def\@arrayerror#1{\@latexerr {misplaced #1 option (missing column specifier?)}\@ehd} \def\@addtopreamble#1{\expandafter\global \expandafter\@preambletoks\expandafter{\the\@preambletoks#1}} \def\@xaddtopreamble#1{\expandafter\@addtopreamble\expandafter{#1}} % one level expansion \def\@eaddtopreamble#1{\edef\@tempa{#1}\@xaddtopreamble{\@tempa}} % full expansion \def\@arraydollar{\futurelet\@tempc\@@arraydollar} \def\@@arraydollar{\ifx\@tempc\@arraydollar\else\if@arraymath$\fi\fi} \@defarrayoption{@}#1{% \ifcase\@preamblecontext \global\@arrayleftskipfalse \or \@arrayerror{@}% \or \global\@preamblecontext\thr@@ \global\@arrayrightskipfalse \else \global\@arrayrightskipfalse\fi \@addtopreamble{\@arraydollar#1\@arraydollar}\@arraycontinue} \@defarrayoption{>}#1{% \ifcase\@preamblecontext \or \@arrayerror{#1}% \else \@arrayflushcolumn\fi \global\@preamblecontext\@ne \gdef\@arrayleftinsert{#1}\@arraycontinue} \@defarrayoption{<}#1{% \ifnum\@preamblecontext=\tw@\else\@arrayerror{<}\fi \global\@preamblecontext\thr@@ \gdef\@arrayrightinsert{#1}\@arraycontinue} \def\@arrayintercol#1#2{% \ifcase\@preamblecontext \if@arraystart\else\if@arrayleftskip \@addtopreamble{\hskip\doublerulesep}\fi\fi \or \@arrayerror{#1}% \else \@arrayflushcolumn\global\@preamblecontext\z@\fi \@addtopreamble{#2}\@arraycontinue} \@defarrayoption{!}{\@arrayintercol{!}} \@defarrayoption{|}{\@arrayintercol{|}{\vline}} \def\@arraycolspec#1#2#3#4{% \ifnum\@preamblecontext>\@ne\@arrayflushcolumn\fi \global\@preamblecontext\tw@ \global\let\if@arrayleftfil#1% \global\let\if@arrayrightfil#2% \gdef\@arrayleftbracket{#3}% \gdef\@arrayrightbracket{#4}\@arraycontinue} \def\@arraystartpbox#1{\bgroup\hsize#1\@arrayparboxrestore \vrule\@height\ht\@arstrutbox\@width\z@} \def\@arrayendpbox{\vrule\@width\z@\@depth\dp\@arstrutbox\egroup} \@defarrayoption{c}{\@arraycolspec{\iftrue}{\iftrue}{}{}} \@defarrayoption{l}{\@arraycolspec{\iffalse}{\iftrue}{}{}} \@defarrayoption{r}{\@arraycolspec{\iftrue}{\iffalse}{}{}} \@defarrayoption{p}#1{\@arraycolspec{\iffalse}{\iffalse} {\vtop\@arraystartpbox{#1}}{\@arrayendpbox}} \@defarrayoption{m}#1{\@arraycolspec{\iffalse}{\iffalse} {\@arraydollar\vcenter\@arraystartpbox{#1}} {\@arrayendpbox\@arraydollar}} \@defarrayoption{b}#1{\@arraycolspec{\iffalse}{\iffalse} {\vbox\@arraystartpbox{#1}}{\@arrayendpbox}} \@defarrayoption{*}#1#2{\@tempcnta#1 \ifnum\@tempcnta>\z@ \advance\@tempcnta\m@ne \def\@tempa##1{\def\@tempa{\@arraycontinue#2*{##1}{##2}}}% \expandafter\@tempa\expandafter{\the\@tempcnta}% \else \let\@tempa\@arraycontinue\fi \@tempa} \@defarrayoption{.}{% \ifcase\@preamblecontext \or \@latexerr{unexpected end of preamble (missing column specifier?)}\@ehd \else \@arrayflushcolumn\fi} \def\@@arraycontinue#1{\@ifundefined{@array@option@#1} {\let\@tempa\@arraycontinue\@latexerr{unrecognized option `#1'}\@ehd} {\expandafter\let\expandafter\@tempa \csname @array@option@#1\endcsname}% \@tempa} \def\@arraycontinue{\global\@arraystartfalse\@@arraycontinue} \def\@arraysharp{##} \def\@arrayflushcolumn{% \@eaddtopreamble{% \ifnum\@arraycolnum>\z@&\fi \if@arrayleftskip\hskip\@arraycolsep\fi \if@arrayleftfil\hfil\fi \kern\z@}% \@addtopreamble{\@arraydollar}% \@xaddtopreamble{\@arrayleftbracket}% \@xaddtopreamble{\@arrayleftinsert}% \@addtopreamble{\ignorespaces}% \@xaddtopreamble{\@arraysharp}% \@addtopreamble{\unskip}% \@xaddtopreamble{\@arrayrightinsert}% \@xaddtopreamble{\@arrayrightbracket}% \@addtopreamble{\@arraydollar}% \@eaddtopreamble{% \if@arrayrightfil\hfil\fi \if@arrayrightskip\hskip\@arraycolsep\fi}% \global\@arrayleftskiptrue \global\@arrayrightskiptrue \gdef\@arrayleftinsert{}% \gdef\@arrayrightinsert{}% \gdef\@arrayleftbracket{}% \gdef\@arrayrightbracket{}% \advance\@arraycolnum\@ne} \def\@arraymakepreamble#1{% \global\@preambletoks{}% \global\@preamblecontext\z@ \global\@arraystarttrue \global\@arrayleftskiptrue \global\@arrayrightskiptrue \global\@arrayleftfiltrue \global\@arrayrightfiltrue \gdef\@arrayleftinsert{}% \gdef\@arrayrightinsert{}% \gdef\@arrayleftbracket{}% \gdef\@arrayrightbracket{}% \@arraycolnum\z@ \@@arraycontinue#1.} \newif\if@arrayunbox \@arrayunboxfalse % (local) \newif\if@arrayunmath \@arrayunmathfalse % (local) \def\hline{\noalign{\ifnum0=`}\fi \if@arrayunbox\let\@tempa\@unboxhline\else\let\@tempa\@latexhline\fi\@tempa} \def\@latexhline{\hrule\@height\arrayrulewidth\futurelet\@tempa\@latexxhline} \def\@latexxhline{\ifx\@tempa\hline\vskip\doublerulesep\fi\ifnum0=`{\fi}} \def\@@unboxhline{\multispan{\@arraycolnum}% \unskip\leaders\hrule\@height\arrayrulewidth\hfill\cr} \def\@unboxhline{\nopagebreak\ifnum0=`{\fi}% \@@unboxhline \noalign{\vskip-\arrayrulewidth\pagebreak[2]}% \@@unboxhline \noalign{\ifnum0=`}\fi\nopagebreak\futurelet\@tempa\@latexxhline} \def\@array[#1]#2{% \@tempdima\ht\strutbox \advance\@tempdima\extrarowheight \setbox\@arstrutbox\hbox{\vrule \@height\arraystretch\@tempdima \@depth\arraystretch\dp\strutbox \@width\z@}% \@arraymakepreamble{#2}% \@arrayunmathfalse \if #1x \ifmmode\@latexerr{cannot use tabular or array with x option in math mode}\@ehd\fi \@tempskipa\leftskip \@tempskipb\rightskip \skip@\parfillskip \trivlist \leftskip\@tempskipa \rightskip\@tempskipb \parfillskip\skip@ \lineskip\z@\baselineskip\z@ \if@arraymath\mathsurround\z@\fi \item[]\noindent \@arrayunboxtrue \ifx\@halignto\@empty\else \@latexerr{cannot use tabular* or array* with x option}\@ehd\fi \gdef\@halignto{to\linewidth}% \setbox\@tempboxa\vbox \else\if #1c \ifmmode\else\@arrayunmathtrue$\fi \vcenter \else\if #1t \vtop \else \vbox\fi\fi\fi \bgroup \edef\@tempa{\everycr{}\tabskip\if@arrayunbox\leftskip\else\z@\fi \halign\@halignto\bgroup\tabskip\z@\@arstrut\the\@preambletoks \tabskip\if@arrayunbox\rightskip\else\z@\fi\cr}% \lineskip\z@\baselineskip\z@ \if@arraymath\mathsurround\z@\fi \let\\\@arraycr \let\par\@empty \@tempa} \def\@endarray{\crcr\egroup\egroup \if@arrayunmath$\fi \if@arrayunbox\unvbox\@tempboxa\endtrivlist\fi} \newif\if@arraybreak \@arraybreakfalse \def\@arraybreak{\if@arraybreak\pagebreak[1]\else\nopagebreak\fi} \def\@arraycrbreak{\if@arrayunbox \def\@tempa{\cr\noalign{\@arraybreak}}\else \def\@tempa{\cr}\fi\@tempa} \def\@arraycr{{\ifnum0=`}\fi\@ifnextchar* {\global\@arraybreakfalse\@arraycrarg} {\global\@arraybreaktrue\@arraycrarg}} \def\@arraycrarg{\@ifnextchar[ {\ifnum0=`{\fi}\@xarraycrarg} {\ifnum0=`{\fi}\@arraycrbreak}} \def\@xarraycrarg[#1]{\ifdim#1>\z@\@arraycrpos{#1}\else\@arraycrneg{#1}\fi} \def\@arraycrpos#1{\unskip \@tempdima#1 \advance\@tempdima \dp\@arstrutbox \vrule\@depth\@tempdima\@width\z@\@arraycrbreak} \def\@arraycrneg#1{\cr\noalign{\if@arrayunbox\@arraybreak\fi\vskip#1}} \def\multicolumn#1#2#3{\multispan{#1}\begingroup \def\@arraysharp{#3}\@arraymakepreamble{#2}% \ifnum\@arraycolnum>\@ne \@latexerr{only one column specifier allowed in \noexpand\multicolumn}\@ehd\fi \endgroup \@arstrut\the\@preambletoks\ignorespaces} \def\@tabarray{\@ifnextchar[{\@array}{\@array[c]}} \def\array{\let\@arraycolsep\arraycolsep\@arraymathtrue\gdef\@halignto{}\@tabarray} \def\tabular{\let\@arraycolsep\tabcolsep\@arraymathfalse\gdef\@halignto{}\@tabarray} \@namedef{array*}#1{\let\@arraycolsep\arraycolsep\@arraymathtrue\gdef\@halignto{to#1}\@tabarray} \@namedef{tabular*}#1{\let\@arraycolsep\tabcolsep\@arraymathfalse\gdef\@halignto{to#1}\@tabarray} \let\endarray\@endarray \let\endtabular\@endarray \expandafter\let\csname endarray*\endcsname\@endarray \expandafter\let\csname endtabular*\endcsname\@endarray