% \iffalse meta-comment % % Copyright (C) 1993-2024 % % The LaTeX Project and any individual authors listed elsewhere % in this file. % % This file is part of the Standard LaTeX `Tools Bundle'. % ------------------------------------------------------- % % It may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3c % of this license or (at your option) any later version. % The latest version of this license is in % https://www.latex-project.org/lppl.txt % and version 1.3c or later is part of all distributions of LaTeX % version 2005/12/01 or later. % % The list of all files belonging to the LaTeX `Tools Bundle' is % given in the file `manifest.txt'. % % \fi %\iffalse % this is a METACOMMENT ! % %% Package `array' to use with LaTeX 2e %% Copyright (C) 1989-1998 Frank Mittelbach, all rights reserved. %<+package>\NeedsTeXFormat{LaTeX2e}[1995/06/01] %<+package> % For anything before 2016-10-06 we load the 2016 version and hope for the best: %<+package>\DeclareRelease{}{1994-06-01}{array-2016-10-06.sty} % %<+package>\DeclareRelease{}{2016-10-06}{array-2016-10-06.sty} %<+package>\DeclareRelease{v2.4}{2020-02-10}{array-2020-02-10.sty} %<+package>\DeclareRelease{v2.5}{2023-11-01}{array-2023-11-01.sty} %<+package>\DeclareCurrentRelease{}{2024-06-01} %<+package> % \end{macrocode} % Current version needs a new kernel. % \begin{macrocode} %<+package>\NeedsTeXFormat{LaTeX2e}[2024/06/01] %<+package>\ProvidesPackage{array} %<+package> [2024/10/17 v2.6g Tabular extension package (FMi)] % % \fi % %% % % % \changes{v2.4g}{2018/04/07}{Renamed internal \cs{mcell@box} to % \cs{ar@mcellbox} and \cs{align@mcell} to \cs{ar@align@mcell} % to avoid conflict with makecell package} % % \changes{v2.4c}{2008/09/09}{(WR) Typo fix in documentation} % % \changes{v2.3c}{1995/11/02}{(DPC) minor doc changes} % % \changes{v2.3a}{1994/10/16}{Added code for \cs{firsthline} and % friends} % % \changes{v2.2c}{1994/03/14}{removed check for \cs{@tfor} bug} % % \changes{v1.0b}{1987/06/04}{`@classi (faster), % `@classvi (new) A in preamble means % \&\& in `halign.} % % \changes{v1.1a}{1987/07/05}{New concept: % preamblechar: c,l,r,C,L,R,A,p,t,{\tt !|},@,!!} % \changes{v1.1b}{1987/09/21}{Again p like original \LaTeX{} and z for % centered `parbox.} % % \changes{v1.2a}{1987/09/27}{Completely new implementation.} % \changes{v1.2b}{1987/10/06}{{\tt !|} does no longer generate space at % start or end of the preamble. Otherwise `hline % is too long.} % \changes{v1.2b}{1987/10/06}{Enlarged `@arstrutbox by 1pt (Test-Impl) % with dimen `@strutheight.} % \changes{v1.2c}{1987/10/22}{New dimen parameter `extrarowheight % (default: 0pt).} % \changes{v1.2c}{1987/10/22}{Enlarged `@arstrutbox by `extrarowheight. % Thus you may avoid large characters to % overprint a `hline.} % \changes{v1.2c}{1987/10/22}{Introduced `m@th in `@array to allow % non-zero values of `mathsurround.} % \changes{v1.2d}{1987/11/02}{Completed the documentation.} % \changes{v1.2e}{1987/11/03}{Bug fixed: A at start of preamble resulted % in an error since `@mkpream generated % `@arstrut \& ... as a preamble.} % \changes{v1.2f}{1987/11/09}{`@testpach documented.} % % \changes{v1.3a}{1987/11/11}{Again a new implementation, with a new % concept (cf. the documentation).} % \changes{v1.3b}{1988/03/17}{`@decl expands now into `@empty, i.e., it % disappears when the preamble is generated, % except when the user specifies A\{\} or % B\{\}.} % % \changes{v1.4a}{1988/03/18}{Test implementation of use of token % registers in order to do without `protect.} % \changes{v1.4b}{1988/03/19}{Changed erroneous class numbers: % 5 -!> 6 % 6 -!> 7 % 7 -!> 5 % Corresponding changes in the macros.} % \changes{v1.4c}{1988/03/19}{Everything except p,z now works with token % registers.} % % \changes{v1.9a}{1988/03/20}{Last (so I hope) major change: 1) Options % B,A now called !>,<. These options now point % to the column they modify.} % \changes{v1.9a}{1988/03/20}{2) `protect is no longer necessary. But % still the macro `@expast needs top be % modified. `multicolumn still does not work.} % \changes{v1.9b}{1988/04/29}{inserted missing `fi in `@testpach. % Corrected \LaTeX bug in `@tfor.} % \changes{v1.9c}{1988/05/07}{Re-introduced `@endpbox. % `multicolumn now works!! Version number still % 1.9 since the documentation is still not % finished.} % \changes{v1.9c}{1988/05/07}{1) `def `the@toks \{`the ...\} remaining % only in `@mkpream. 2) Removed `@classiii and % replaced by `save@decl.} % \changes{v1.9c}{1988/05/07}{3) `insert@column contains only `@tempcnta % and `count@ counters. 4) `@@startpbox and % `@@endpbox now totally obsolete.} % \changes{v1.9d}{1988/05/10}{Replaced `number by `the where the `toks % registers' contents are used.} % \changes{v1.9e}{1988/05/11}{Re-introduced `@xargarraycr and % `@yargarraycr, since `endtemplate seems to % be `outer.} % \changes{v1.9f}{1988/05/20}{Small changes finally carried out: % 1) `par!=`@empty. % 2) \{..ifnum0!=!`\}... $\to$ `bgroup and % analogously `egroup.} % \changes{v1.9g}{1988/02/24}{Inserted again \{..ifnum0!=!`\}.., % c.f. Appendix D of the \protect\TeX{}book.} % \changes{v1.9h}{1988/06/28}{No longer necessary to read in the file % twice.} % \changes{v1.9i}{1988/06/28}{Corrected typo in german version.} % \changes{v1.9j}{1988/11/23}{In a `r' column an extra `kern`z@ is % needed.} % \changes{v1.9j}{1988/11/23}{Otherwise the `hfil on the left side % will be removed by the `unskip in % `insert@column if the entry is empty.} % \changes{v1.9k}{1988/06/28}{Corrected typo in german version.} % \changes{v1.9k}{1989/01/16}{`begin{Macro} changed to `begin{macro} in % documentation.} % % \changes{v2.0a}{1989/05/12}{{\tt\textbackslash @thetoks} changed to % {\tt\textbackslash the@toks}.} % \changes{v2.0a}{1989/05/12}{source changed to reflect new doc.sty % conventions.} % \changes{v2.0a}{1989/05/12}{t option renamed to p to be compatible to % the original.} % \changes{v2.0a}{1989/05/12}{File renamed from arraye.sty to % array.sty.} % \changes{v2.0b}{1989/05/17}{Three forgotten end macro added.} % \changes{v2.0b}{1989/05/17}{All lines shortened to 72 or less.} % \changes{v2.2a}{1994/02/03}{Upgrade to \LaTeXe} % % \DoNotIndex{\@depth,\@ehc,\@fortmp,\@height,\@ifnextchar,\@ifstar} % \DoNotIndex{\@ifundefined,\@ne,\@nil,\@tempa,\@tempb} % \DoNotIndex{\@tempcnta,\@tempd,\@tempdima,\@whilenum,\@width,\\} % \DoNotIndex{\@tforloop} % \DoNotIndex{\advance} % \DoNotIndex{\baselineskip,\begingroup,\bgroup} % \DoNotIndex{\cr,\crcr,\csname} % \DoNotIndex{\def,\do,\docdate,\dp} % \DoNotIndex{\edef,\egroup,\else,\endcsname,\endinput,\expandafter} % \DoNotIndex{\fi,\filedate,\fileversion} % \DoNotIndex{\gdef} % \DoNotIndex{\hbox,\hfil,\hsize,\hskip,\ht} % \DoNotIndex{\if,\ifcase,\ifdim,\ifnum,\ifx,\ignorespaces} % \DoNotIndex{\kern} % \DoNotIndex{\leavevmode,\let,\lineskip} % \DoNotIndex{\m@ne,\multispan} % \DoNotIndex{\newcount,\newdimen,\noalign} % \DoNotIndex{\or} % \DoNotIndex{\relax} % \DoNotIndex{\setbox,\space,\strutbox} % \DoNotIndex{\tabskip,\thr@@,\the,\toks,\toks@,\tw@,\typeout} % \DoNotIndex{\unhcopy,\unskip} % \DoNotIndex{\vbox,\vcenter,\vline,\vrule,\vtop,\vskip} % \DoNotIndex{\xdef} % \DoNotIndex{\z@} % % % \providecommand\env[1]{\texttt{#1}} % % \providecommand\hook[1]{\texttt{#1\DescribeHook[noprint]{#1}}} % \providecommand\socket[1]{\texttt{#1\DescribeSocket[noprint]{#1}}} % \providecommand\plug[1]{\texttt{#1\DescribePlug[noprint]{#1}}} % % \NewDocElement[printtype=\textit{socket},idxtype=socket,idxgroup=Sockets]{Socket}{socketdecl} % \NewDocElement[printtype=\textit{hook},idxtype=hook,idxgroup=Hooks]{Hook}{hookdecl} % \NewDocElement[printtype=\textit{plug},idxtype=plug,idxgroup=Plugs]{Plug}{plugdecl} % % % \GetFileInfo{array.sty} % % \title{A new implementation of \LaTeX's \textsf{tabular} % and \textsf{array} environment\thanks{This file % has version number \fileversion, last % revised \filedate.}} % \author{Frank Mittelbach % \and % David Carlisle\thanks{David kindly agreed on the inclusion % of the \texttt{\textbackslash{}newcolumntype} implementation, % formerly in % \texttt{newarray.sty} into this package.}} % % \date{Printed \today} % % \MaintainedByLaTeXTeam{tools} % \maketitle % % % % \MakeShortVerb{\=} % % \begin{abstract} % This article describes an extended implementation of the \LaTeX\ % \textsf{array}-- and \textsf{tabular}--environments. The special % merits of this implementation are further options to format columns % and the fact that fragile \LaTeX--commands don't have to be % =\protect='ed any more within those environments. % % The major part of the code for this package dates back to 1988---so % does some of its documentation. % \end{abstract} % % % % \section{Introduction} % % This new implementation of the \textsf{array}-- and % \textsf{tabular}--environments is part of a larger project in which % we are trying to improve the \LaTeX\--code in some aspects and to % make \LaTeX\ even easier to handle. % % The reader should be familiar with the general structure of the % environments % mentioned above. Further information can be found in % \cite{bk:lamport} and \cite{bk:GMS94}. % The additional options which can be used in the % preamble as well as those which now have a slightly different meaning % are described in table~\ref{tab:opt}. % % \DescribeMacro\extrarowheight % Additionally we introduce a new % parameter called =\extrarowheight=. If it takes a positive % length, the value of the parameter is added to the normal height of % every row of the table, while % the depth will remain the same. This is important for tables % with horizontal lines because those lines normally touch the % capital letters. % For example, we used =\setlength{\extrarowheight}{1pt}= % in table~\ref{tab:opt}. % % \begin{table}[!t] % \begin{center} % \setlength{\extrarowheight}{1pt} % \begin{tabular}{|>{\ttfamily}c|m{9cm}|} % \hline % \multicolumn{2}{|c|}{Unchanged options}\\ % \hline % l & Left adjusted column. \\ % c & Centered adjusted column. \\ % r & Right adjusted column. \\ % p\{width\} & Equivalent to =\parbox[t]{width}=. \\ % @\{decl.\} & Suppresses inter-column space and inserts % \texttt{decl.}\ instead. \\ % \hline % \multicolumn{2}{|c|}{New options}\\ % \hline % m\{width\} & Defines a column of width \texttt{width}. % Every entry will be centered in proportion to % the rest of the line. It is somewhat like % =\parbox{width}=. \\ % \hline % b\{width\} & Coincides with =\parbox[b]{width}=. \\ % \hline % >\{decl.\} & Can be used before an \texttt{l}, \texttt{r}, % \texttt{c}, \texttt{p}, \texttt{m} or a % \texttt{b} option. It inserts \texttt{decl.}\ % directly in front of the entry of the column. % \\ % \hline % <\{decl.\} & Can be used after an \texttt{l}, \texttt{r}, % \texttt{c}, =p{..}=, =m{..}= or a =b{..}= % option. It inserts \texttt{decl.}\ right % after the entry of the column. \\ % \hline % | & Inserts a vertical line. The distance between % two columns will be enlarged by the width of % the line % in contrast to the original definition of % \LaTeX. \\ % \hline % !\{decl.\} & Can be used anywhere and corresponds with the % \texttt{|} option. The difference is that % \texttt{decl.} is inserted instead of a % vertical line, so this option doesn't % suppress the normally inserted space between % columns in contrast to =@{...}=.\\ % \hline\hline % w\{align\}\{width\} & Sets the cell content in a box of the % specified \texttt{width} aligned according to % the \texttt{align} parameter which could be % either \texttt{l}, \texttt{c} or % \texttt{r}. Works essentially like % =\makebox[=width=][=align=]{=cell=}= so % silently overprints if the cell content is % wider than the specified width. If that is % not desired use \texttt{W} instead.\\ % \hline % W\{align\}\{width\} & Like \texttt{w} but spits out an overfull % box warning (and an overfullrule marker in % draft mode) when the cell content is too wide % to fit. This also means that the alignment is % different if there is too much material, % because it then always protrudes to the right!\\ % \hline % \end{tabular} % \end{center} % \caption{The preamble options.} \label{tab:opt} % \end{table} % % % We will discuss a few examples using the new preamble options before % dealing with the implementation. % \begin{itemize} % \item % If you want to use a special font (for example =\bfseries=) in a % flushed left column, this can be done with =>{\bfseries}l=. You % do not have to begin every entry of the column with =\bfseries= % any more. % \item % In columns which have been generated with \texttt{p}, \texttt{m} % or \texttt{b}, the default value of =\parindent= is % \textsf{0pt}. % This can be changed with \\ % =>{\setlength{\parindent}{1cm}}p=. % \item % The \texttt{>}-- and \texttt{<}--options were originally % developed for the following application: % =>{$}c<{$}= generates a column in math % mode in a \textsf{tabular}--environment. If you use this type % of a preamble in an \textsf{array}--environment, you get a % column in LR mode because the additional \$'s cancel the % existing \$'s. % \item % One can also think of more complex applications. A problem % which has % been mentioned several times in \TeX{}hax can be solved with % =>{\centerdots}c=\linebreak[0]=<{\endcenterdots}=. % To center decimals at their % decimal points you (only?) have to define the following macros: % \begin{verbatim} %{\catcode`\.\active\gdef.{\egroup\setbox2\hbox\bgroup}} %\def\centerdots{\catcode`\.\active\setbox0\hbox\bgroup} %\def\endcenterdots{\egroup\ifvoid2 \setbox2\hbox{0}\fi % \ifdim \wd0>\wd2 \setbox2\hbox to\wd0{\unhbox2\hfill}\else % \setbox0\hbox to\wd2{\hfill\unhbox0}\fi % \catcode`\.12 \box0.\box2} %\end{verbatim} % Warning: The code is bad, it doesn't work with more than one % dot in a cell and doesn't work when the tabular is used in the % argument of some other command. A much better version is % provided in the \texttt{dcolumn.sty} by David Carlisle. % \item % Using =c!{\hspace{1cm}}c= you get space between two % columns which is enlarged by one centimeter, while % =c@{\hspace{1cm}}c= gives you exactly one centimeter % space between two columns. % % \item % A declaration like =w{l}{3cm}= (or even shorter =wl{3cm}=) % works like an =l= column except that the width will always be % =3cm= regardless of the cell content. Same with =w{c}= or % =w{r}=. This means that it is easy to set up tables in which all % columns have predefined widths. % \end{itemize} % % % % \subsection{A note on the allowed content of \texttt{>\{...\}} and % \texttt{<\{...\}}} % % These specifiers are meant to hold declarations, such as % \verb=>{\itshape}=. They cannot end in commands that take arguments % without providing these arguments as part of the \verb={...}=. It % would be a mistaken assumption that they pick up all or parts of the % alignment entry data if their argument is not provided. E.g., % \verb=>{\textbf}= would not make the whole column bold nor would it % make the first character bold (technically it would try to % bolden \cs{ignorespaces}). Thus, it would not fail with an error, % but effectively the output would be wrong and not as expected. % % \subsection{The behavior of the \texttt{\string\\} command} % % In the basic \texttt{tabular} implementation of \LaTeX{} the \cs{\bslash} % command ending the rows of the \texttt{tabular} or \texttt{array} has % a somewhat inconsistent behavior if its optional argument is used. The % result then depends on the type of rightmost column and as remarked in % Leslie Lamport's \LaTeX{} manual~\cite{bk:lamport} may not always produce the % expected extra space. % % % Without the \textsf{array} package the extra space requested by the % optional argument of \cs{\bslash} is measured from the last baseline of % the rightmost column (indicated by ``x'' in the following % example). As a result, swapping the column will give different % results: % \begin{verbatim} % \begin{tabular}[t]{lp{1cm}} % 1 & 1\newline x \\[20pt] 2 & 2 \end{tabular} % \begin{tabular}[t]{p{1cm}l} % 1\newline 1 & x \\[20pt] 2 & 2 \end{tabular} % \end{verbatim} % \pagebreak % If you run this without the \textsf{array} package you will get the % following result: % \begin{center} % \begin{tabular}[t]{lp{1cm}} % 1 & 1\newline x \\[32pt] 2 & 2 \end{tabular} % \begin{tabular}[t]{p{1cm}l} % 1\newline 1 & x \\[20pt] 2 & 2 \end{tabular} % \end{center} % In contrast, when the \textsf{array} package is loaded, the requested % space in the optional argument is always measured from the baseline of % the whole row and not from the last baseline of the rightmost column, thus % swapping columns doesn't change the spacing and we same table height % with an effective 8pt of extra space (as the second line already takes % up 12pt of the requested 20pt): % \begin{center} % \begin{tabular}[t]{lp{1cm}} % 1 & 1\newline x \\[20pt] 2 & 2 \end{tabular} % \begin{tabular}[t]{p{1cm}l} % 1\newline 1 & x \\[20pt] 2 & 2 \end{tabular} % \end{center} % % This correction of behavior only makes a difference if the rightmost column % is a \texttt{p}-column. Thus if you add the \textsf{array} % package to an existing document, you should verify the spacing in all % tables that have this kind of structure. % % % \subsection{Defining new column specifiers} % % \DeleteShortVerb{\=} % \MakeShortVerb{\"} % \DescribeMacro{\newcolumntype} % Whilst it is handy to be able to type % \begin{quote} % ">{"\meta{some declarations}"}{c}<{"\meta{some more % declarations}"}" % \end{quote} % if you have a one-off column in a table, it is rather inconvenient % if you often use columns of this form. The new version allows you % to define a new column specifier, say \texttt{x}, which will expand to % the primitives column specifiers.\footnote{This command was named % \texttt{\textbackslash{}newcolumn} in the \texttt{newarray.sty}. % At the moment \texttt{\textbackslash{}newcolumn} is still supported % (but gives a warning). In later releases it will vanish.} Thus we % may define % \begin{quote} % "\newcolumntype{x}{>{"\meta{some declarations}"}{c}<{"\meta{some % more declarations}"}}"\hspace*{-3cm} ^^A no overfull from this line % \end{quote} % One can then use the \texttt{x} column specifier in the preamble % arguments of all \texttt{array} or \texttt{tabular} environments in % which you want columns of this form. % % It is common to need math-mode and LR-mode columns in the same % alignment. If we define: % \begin{quote} % "\newcolumntype{C}{>{$}c<{$}}" \\ % "\newcolumntype{L}{>{$}l<{$}}" \\ % "\newcolumntype{R}{>{$}r<{$}}" % \end{quote} % Then we can use \texttt{C} to get centered LR-mode in an % \texttt{array}, or centered math-mode in a \texttt{tabular}. % % The example given above for `center decimal points' could be % assigned to a \texttt{d} specifier with the following command. % \begin{quote} % "\newcolumntype{d}{>{\centerdots}c<{\endcenterdots}}" % \end{quote} % % The above solution always centers the dot in the % column. This does not look too good if the column consists of large % numbers, but to only a few decimal places. An alternative definition % of a \texttt{d} column is % \begin{quote} % "\newcolumntype{d}[1]{>{\rightdots{#1}}r<{\endrightdots}}" % \end{quote} % where the appropriate macros in this case are:\footnote{The package % \texttt{dcolumn.sty} contains more robust macros based on these % ideas.} % \begin{verbatim} % \def\coldot{.}% Or if you prefer, \def\coldot{\cdot} % {\catcode`\.=\active % \gdef.{$\egroup\setbox2=\hbox to \dimen0 \bgroup$\coldot}} % \def\rightdots#1{% % \setbox0=\hbox{$1$}\dimen0=#1\wd0 % \setbox0=\hbox{$\coldot$}\advance\dimen0 \wd0 % \setbox2=\hbox to \dimen0 {}% % \setbox0=\hbox\bgroup\mathcode`\.="8000 $} % \def\endrightdots{$\hfil\egroup\box0\box2} %\end{verbatim} % Note that "\newcolumntype" takes the same optional argument as % "\newcommand" which declares the number of arguments of the column % specifier being defined. Now we can specify "d{2}" in our preamble % for a column of figures to at most two decimal places. % % A rather different use of the "\newcolumntype" system takes % advantage of the fact that the replacement text in the % "\newcolumntype" command may refer to more than one column. Suppose % that a document contains a lot of \texttt{tabular} environments that % require the same preamble, but you wish to experiment with different % preambles. Lamport's original definition allowed you to do the % following (although it was probably a mis-use of the system). % \begin{quote} % "\newcommand{\X}{clr}"\\ % "\begin{tabular}{\X}" \ldots % \end{quote} % \texttt{array.sty} takes great care \textbf{not} to expand the % preamble, and so the above does not work with the new scheme. With % the new version this functionality is returned: % \begin{quote} % "\newcolumntype{X}{clr}"\\ % "\begin{tabular}{X}" \ldots % \end{quote} % % The replacement text in a "\newcolumntype" command may refer to any of % the primitives of \texttt{array.sty} see table \ref{tab:opt} on page % \pageref{tab:opt}, or to any new letters defined in other % "\newcolumntype" commands. % % % \DescribeMacro{\showcols}A list of all the currently active % "\newcolumntype" definitions is sent to the terminal and log file if % the "\showcols" command is given. % % % \subsection{Special variations of \texttt{\textbackslash hline}} % % The family of \texttt{tabular} environments allows % vertical positioning with respect to the baseline of % the text in which the environment appears. By default the % environment appears centered, but this can be changed to % align with the first or last line in the environment by % supplying a \texttt{t} or \texttt{b} value to the % optional position argument. However, this does not work % when the first or last element in the environment is a % "\hline" command---in that case the environment is % aligned at the horizontal rule. % % \pagebreak[3] % % Here is an example: % \begin{center} % \begin{minipage}[t]{.4\linewidth} % Tables % \begin{tabular}[t]{l} % with no\\ hline \\ commands \\ used % \end{tabular} versus \\ tables % \begin{tabular}[t]{|l|} % \hline % with some \\ hline \\ commands \\ % \hline % \end{tabular} used. % \end{minipage} % \begin{minipage}[t]{.5\linewidth} % \begin{verbatim} % Tables % \begin{tabular}[t]{l} % with no\\ hline \\ commands \\ used % \end{tabular} versus tables % \begin{tabular}[t]{|l|} % \hline % with some \\ hline \\ commands \\ % \hline % \end{tabular} used. % \end{verbatim} % \end{minipage} % \end{center} % % \DescribeMacro\firsthline % \DescribeMacro\lasthline % Using "\firsthline" and "\lasthline" will % cure the problem, and the tables will align properly as long % as their first or last line does not contain extremely large % objects. % \begin{center} % \begin{minipage}[t]{.4\linewidth} % Tables % \begin{tabular}[t]{l} % with no\\ line \\ commands \\ used % \end{tabular} versus \\ tables % \begin{tabular}[t]{|l|} % \firsthline % with some \\ line \\ commands \\ % \lasthline % \end{tabular} used. % \end{minipage} % \begin{minipage}[t]{.5\linewidth} % \begin{verbatim} % Tables % \begin{tabular}[t]{l} % with no\\ line \\ commands \\ used % \end{tabular} versus tables % \begin{tabular}[t]{|l|} % \firsthline % with some \\ line \\ commands \\ % \lasthline % \end{tabular} used. % \end{verbatim} % \end{minipage} % \end{center} % \DescribeMacro\extratabsurround % The implementation of these two commands contains an extra % dimension, which is called "\extratabsurround", to add some % additional space at the top and the bottom of such an environment. % This is useful if such tables are nested. % % \section{Final Comments} % % \subsection{Handling of rules} % % There are two possible approaches to the handling of horizontal and % vertical rules in tables: % \begin{enumerate} % \item rules can be placed into the available space without % enlarging the table, or % \item rules can be placed between columns or rows thereby enlarging % the table. % \end{enumerate} % For vertical rules \texttt{array.sty} implements the second % possibility while the default implementation in the \LaTeX{} kernel % implements the first concept. % Both concepts have their merits but % one has to be aware of the individual implications. % \begin{itemize} % \item % With standard \LaTeX{} adding vertical rules to a table will % not affect the % width of the table (unless double rules are used), e.g., % changing a preamble from \verb=lll= to \verb=l|l|l= does not % affect the document other than adding rules to the table. In % contrast, with \texttt{array.sty} a table that just fit the % \verb=\textwidth= might now produce an overfull box. % \item % With standard \LaTeX{} modifying the width of rules could result % in ugly looking tables because without adjusting the % \verb=\tabcolsep=, etc.\ the space between rule and column could % get too small (or too large). In fact even overprinting of text is % possible. In contrast, with \texttt{array.sty} modifying any such % length usually works well as the actual visual white space (from % \verb=\tabcolsep=, etc.) does not depend on the width of the % rules. % \item % With standard \LaTeX{} boxed tabulars actually have strange % corners because the horizontal rules end in the middle of the % vertical ones. This looks very unpleasant when a large % \verb=\arrayrulewidth= is chosen. In that case a simple table like %\begin{verbatim} %\setlength{\arrayrulewidth}{5pt} %\begin{tabular}{|l|} % \hline A \\ \hline %\end{tabular} %\end{verbatim} % will produce something like % \begin{center} %\setlength{\arrayrulewidth}{5pt} %\begin{tabular}{@{}l@{}} % \hline \null\hskip-.5\arrayrulewidth\vline % \hskip\tabcolsep % A\hskip\tabcolsep % \vline\hskip-.5\arrayrulewidth\null \\ \hline %\end{tabular} % \quad % instead of % \quad %\begin{tabular}{|l|} % \hline A \\ \hline %\end{tabular} % \end{center} % \end{itemize} % % Horizontal rules produced with \cs{hline} add to the table height in % both implementations but they differ in handling double \cs{hline}s. % In contrast a \cs{cline} does not change the table % height.\footnote{All a bit inconsistent, but nothing that can be % changed after being 30+ years in existence.} % % \subsection{Comparisons with older versions of \texttt{array.sty}} % % There are some differences in the way version 2.1 treats incorrect % input, even if the source file does not appear to use any of the % extra features of the new version. % \begin{itemize} % \item A preamble of the form "{wx*{0}{abc}yz}" was treated by % versions prior to 2.1 as "{wx}". Version 2.1 treats it as "{wxyz}" % \item An incorrect positional argument such as \texttt{[Q]} was % treated as \texttt{[c]} by \texttt{array.sty}, but is now treated as % \texttt{[t]}. % \item A preamble such as "{cc*{2}}" with an error in % a $*$-form will generate different errors in the new version. In % both cases the error message is not particularly helpful to the % casual user. % \item Repeated \texttt{<} or \texttt{>} constructions % generated an error in earlier versions, but are now allowed in % this package. ">{"\meta{decs1}"}>{"\meta{decs2}"}" is treated the % same as ">{"\meta{decs2}\meta{decs1}"}". % \item The "\extracolsep" % command does not work with the old versions of \texttt{array.sty}, % see the comments in \texttt{array.bug}. With version 2.1 % "\extracolsep" may again be used in \texttt{@}-expressions as in % standard \LaTeX, and also in \texttt{!}-expressions (but see the % note below). % \end{itemize} % % Prior to version 2.4f the space added by the optional argument to "\\" % was added inside an m-cell if the last column was of type % \texttt{m}. As a result that cell was vertically centered with that % space inside, resulting in a strange offset. Since 2.4f, this space % is now added after centering the cell. % % A similar problem happened when "\extrarowheight" was used. For that % reason m-cells now manually position the cell content which % allows to ignore this extra space request during the vertical alignment. % % % \subsection{Bugs and Features} % % \begin{itemize} % \item Error messages generated when parsing the column specification % refer to the preamble argument \textbf{after} it has been re-written % by the "\newcolumntype" system, not to the preamble entered by the % user. This seems inevitable with any system based on % pre-processing and so is classed as a \textbf{feature}. % % \item The treatment of multiple \texttt{<} or \texttt{>} % declarations may seem strange at first. Earlier implementations % treated ">{"\meta{decs1}"}>{"\meta{decs2}"}" the same as % ">{"\meta{decs1}\meta{decs2}"}". However this did not give the % user the opportunity of overriding the settings of a % "\newcolumntype" defined using these declarations. For example, % suppose in an \texttt{array} environment we use a \texttt{C} % column defined as above. The \texttt{C} specifies a centered text % column, however ">{\bfseries}C", which re-writes to % ">{\bfseries}>{$}c<{$}" would not specify a bold column as might % be expected, as the preamble would essentially expand to % "\hfil$\bfseries$#$ $\hfil" and so the column entry would not be in the % scope of the "\bfseries"\,! The present version switches the order % of repeated declarations, and so the above example now produces a % preamble of the form "\hfil$" "$\bfseries#$" "$\hfil", and the % dollars cancel each other out without limiting the scope of the % "\bfseries". % % \item The use of "\extracolsep" has been subject to the following % two restrictions. There must be at most one "\extracolsep" % command per "@", or "!" expression and the command must be % directly entered into the "@" expression, not as part of a macro % definition. Thus "\newcommand{\ef}{\extracolsep{\fill}}" \ldots % "@{\ef}" does not work with this package. However you can use % something like % "\newcolumntype{e}{@{\extracolsep{\fill}}" instead. % % \item As noted by the \LaTeX{} book, for the purpose of % "\multicolumn" each column with the exception of the first one % consists of the entry and the \emph{following} inter-column % material. This means that in a tabular with the preamble % "|l|l|l|l|" input such as "\multicolumn{2}{|c|}" in % anything other than the first column is incorrect. % In the standard array/tabular implementation this error is not so % noticeable as that version contains negative spacing so that each % "|" takes up no horizontal space. But since in this package the % vertical lines take up their natural width one sees two lines if % two are specified. % % \end{itemize} % % % \section{Support for tagged PDF} % % With version 2.6a the package is made tagging aware, which means that % it will automatically produce tagged tables (necessary, for example, for % accessibility) if tagging is requested via \cs{DocumentMetadata}. % % More granular control, e.g., explicitly deciding which cells are % header cells, etc., is currently under development, but syntax for % this will not appear in this package. Instead it will become % available across all tabular-generating packages and then % automatically apply here as well. % % Enabling \LaTeX{} to automatically produce tagged PDF is a long-term % project and this is a tiny step in this puzzle. For more information % on the project and already available functionality, see % \url{https://latex-project.org/publications/indexbytopic/pdf} and % \url{https://github.com/latex3/tagging-project}. % % % % \changes{v2.2b}{1994/02/04}{Removed interactive prompt} % % \MaybeStop{ % \begin{thebibliography}{1} % \bibitem{bk:GMS94} \textsc{M.~Goossens}, \textsc{F.~Mittelbach} % and \textsc{A.~Samarin}. % \newblock The \LaTeX{} Companion. % \newblock % Addison-Wesley, Reading, Massachusetts, 1994. % \bibitem{bk:knuth} \textsc{D. E. Knuth}. % \newblock The \TeX{}book (Computers \& Typesetting Volume A). % \newblock % Addison-Wesley, Reading, Massachusetts, 1986. % \bibitem{bk:lamport} \textsc{L. Lamport}. % \newblock % \LaTeX\ --- A Document Preparation System. % \newblock % Addison-Wesley, Reading, Massachusetts, 1986. % \end{thebibliography} % } ^^A end of \MaybeStop % % % % % \section{The documentation driver file} % % The first bit of code contains the documentation driver file for % \TeX{}, i.e., the file that will produce the documentation you are % currently reading. It will be extracted from this file by the % \texttt{docstrip} program. % \begin{macrocode} %<*driver> \NeedsTeXFormat{LaTeX2e}[2024/06/01] % \end{macrocode} % % We switched from \cls{ltxdoc} to \cls{l3doc} to get support for % code written in the L3 programming layer. The first is that we % are currently missing \cs{MaintainedByLaTeXTeam}, so we have to % provide that for now. % \begin{macrocode} \documentclass{l3doc} % currently missing in l3doc \makeatletter \def\MaintainedBy#1{\gdef\@maintainedby{#1}} \let\@maintainedby\@empty \def\MaintainedByLaTeXTeam#1{% {\gdef\@maintainedby{% This file is maintained by the \LaTeX{} Project team.\\% Bug reports can be opened (category \texttt{#1}) at\\% \url{https://latex-project.org/bugs.html}.}}} \def\@maketitle{% \newpage \null \vskip 2em% \begin{center}% \let \footnote \thanks {\LARGE \@title \par}% \vskip 1.5em% {\large \lineskip .5em% \begin{tabular}[t]{c}% \@author \end{tabular}\par}% \vskip 1em% {\large \@date}% \ifx\@maintainedby\@empty \else \vskip 1em% \fbox{\fbox{\begin{tabular}{@{}l@{}}\@maintainedby\end{tabular}}}% \fi \end{center}% \par \vskip 1.5em} \makeatother % undo the default is not used: \IfFormatAtLeastTF {2020/10/01} {\AtBeginDocument[ltxdoc]{\DeleteShortVerb{\|}} } {\AtBeginDocument{\DeleteShortVerb{\|}} } \usepackage{array} % Allow large table at bottom \renewcommand{\bottomfraction}{0.7} \EnableCrossrefs %\DisableCrossrefs % Say \DisableCrossrefs if index is ready \RecordChanges % Gather update information \CodelineIndex % Index code by line number %\OnlyDescription % comment out for implementation details %\OldMakeindex % use if your MakeIndex is pre-v2.9 \begin{document} \DocInput{array.dtx} \end{document} % % \end{macrocode} % % % \section{A note on the updates done December 2023} % % We introduced support for tagged PDF and at the same time we added % code to determine row and column numbers for each cell in % preparation for supporting formatting or type specifications for individual % cells (or group of cells) from the outside, e.g., \enquote{rows 1, % 2, and 10 are header rows} (syntax to be decided). % % This new code is already written with L3 programming layer conventions % while most of the legacy code is still as it was before. This make the code % currently somewhat clattered, unfortunately. Eventually this will all move to L3 % programming layer but this will take time. % % % \begin{macrocode} %<@@=tbl> \ExplSyntaxOn % \end{macrocode} % % % % % % \section{The construction of the preamble} % % \DeleteShortVerb{\"} % \MakeShortVerb{\=} % % It is obvious that those environments will consist mainly of an % =\halign=, because \TeX\ typesets tables using this primitive. % That is why we will now take a look at the algorithm which determines % a preamble for a =\halign= starting with a given user preamble % using the options mentioned above. % % % The current version is defined at the top of the file looking % something like this % \begin{macrocode} %<*package> %\NeedsTeXFormat{LaTeX2e}[1994/05/13] %\ProvidesPackage{array}[\filedate\space version\fileversion] % \end{macrocode} % % The most interesting macros of this implementation are without doubt % those which are responsible for the construction of the preamble for % the =\halign=. The underlying algorithm was developed by % \textsc{Lamport} (resp.\ \textsc{Knuth}, see texhax V87\#??), and it % has been extended and improved. % % The user preamble will be read \textsf{token} by \textsf{token}. A % \textsf{token} is a single character like \texttt{c} or a block % enclosed in ={...}=. For example the preamble of % =\begin{tabular}=\linebreak[0]={lc||c@{\hspace{1cm}}}= consists of % the \textsf{token} \texttt{l}, \texttt{c}, \texttt{|}, \texttt{|}, % \texttt{@} and =\hspace{1cm}=. % % The currently used \textsf{token} and the one, used before, are needed % to decide on how the construction of the preamble has to be % continued. % In the example mentioned above the \texttt{l} causes the preamble % to begin with =\hskip\tabcolsep=. Furthermore % =# \hfil= would be appended to define a flush left column. % The next \textsf{token} is a \texttt{c}. Because it was preceded by an % \texttt{l} it generates a new column. This is done with % =\hskip \tabcolsep & \hskip \tabcolsep=. The column which is to % be centered will be appended with =\hfil # \hfil=. % The \textsf{token} \texttt{|} would then add a space of % =\hskip \tabcolsep= % and a vertical line because the last % \textsf{tokens} was a \texttt{c}. % The following \textsf{token} \texttt{|} would only add a space % =\hskip \doublerulesep= because it was preceded by the % \textsf{token} \texttt{|}. We will not discuss our example further but % rather take a look at the general case of constructing preambles. % % The example shows that the desired preamble for the % =\halign= can be constructed as soon as the action of all % combinations % of the preamble \textsf{tokens} are specified. There are 18 such % \textsf{tokens} % so we have $19 \cdot 18 \string= 342$ combinations if we count the % beginning of % the preamble as a special \textsf{token}. Fortunately, there are many % combinations which generate the same spaces, so we can define % \textsf{token} classes. We will identify a % \textsf{token} within a class with a number, so we can insert the % formatting (for example of a column). % Table~\ref{tab:Klassen} lists all \textsf{token} classes and % their corresponding numbers. % \begin{table}[ht] % \begin{center} % \begin{tabular}[t]{>{\ttfamily}ccc} % \textsf{token} & =\@chclass= & =\@chnum= \\[2mm] % c & 0 & 0 \\ % l & 0 & 1 \\ % r & 0 & 2 \\ % m-arg & 0 & 3 \\ % p-arg & 0 & 4 \\ % b-arg & 0 & 5 \\ % | & 1 & 0 \\ % !-arg & 1 & 1 \\ % <-arg & 2 & --- \\ % >-arg & 3 & --- % \end{tabular} % \kern3mm \vrule \kern3mm% % \begin{tabular}[t]{>{\ttfamily}ccc} % \textsf{token} & =\@chclass= & =\@chnum= \\[2mm] % Start & 4 & --- \\ % @-arg & 5 & --- \\ % ! & 6 & --- \\ % @ & 7 & --- \\ % < & 8 & --- \\ % > & 9 & --- \\ % m & 10 & 3 \\ % p & 10 & 4 \\ % b & 10 & 5 % \end{tabular} % \end{center} % \caption{Classes of preamble \textsf{tokens}} % \label{tab:Klassen} % \end{table} % % % \begin{macro}{\@chclass} % \begin{macro}{\@chnum} % \begin{macro}{\@lastchclass} % The class and the number of the current \textsf{token} are saved in % the % \textsf{count} registers =\@chclass= % and =\@chnum=, while the class of the previous % \textsf{token} is stored in the % \textsf{count} register =\@lastchclass=. % All of the mentioned registers are already allocated in % the \LaTeX{} format, % which is the reason why the following three lines of code are % commented out. % Later throughout the text I will not mention it again explicitly % whenever I use a =%= sign. These parts are already defined in % the \LaTeX{} format. % \begin{macrocode} % \newcount \@chclass % \newcount \@chnum % \newcount \@lastchclass % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % % % \begin{macro}{\@addtopreamble} % We will save the already constructed preamble for % the =\halign= % in the global macro =\@preamble=. This will then be % enlarged with % the command =\@addtopreamble=. % \begin{macrocode} \def\@addtopreamble#1{\xdef\@preamble{\@preamble #1}} % \end{macrocode} % \end{macro} % % % % % % \subsection{The character class of a \textsf{token}} % % \begin{macro}{\@testpach} % \changes{v2.0a}{1989/05/12}{p option renamed to m (middle).} % \changes{v2.0a}{1989/05/12}{t option renamed to p to be compatible to % the original.} % With the help of =\@lastchclass= we can now define a macro % which determines the class and the number of a given preamble % \textsf{token} % and assigns them to the registers % =\@chclass= and =\@chnum=. % \changes{v2.0f}{1992/02/29}{Argument removed since implicitly known} % \begin{macrocode} \ExplSyntaxOff \def\@testpach{\@chclass % \end{macrocode} % First we deal with the cases in which the \textsf{token} % (=#1=) is the argument of \texttt{!}, \texttt{@}, \texttt{<} or % \texttt{>}. We can see this from the value of =\@lastchclass=: % \begin{macrocode} \ifnum \@lastchclass=6 \@ne \@chnum \@ne \else \ifnum \@lastchclass=7 5 \else \ifnum \@lastchclass=8 \tw@ \else \ifnum \@lastchclass=9 \thr@@@@ % \end{macrocode} % Otherwise we will assume that the \textsf{token} belongs to the % class $0$ % and assign the corresponding number to =\@chnum= if our % assumption is correct. % \begin{macrocode} \else \z@ % \end{macrocode} % If the last \textsf{token} was a \texttt{p}, \texttt{m} or a % \texttt{b}, =\@chnum= already has the right value. This is the % reason for the somewhat curious choice of the \textsf{token} % numbers in class $10$. % \begin{macrocode} \ifnum \@lastchclass = 10 \else % \end{macrocode} % Otherwise we will check if =\@nextchar= is either a \texttt{c}, % \texttt{l} or an \texttt{r}. Some applications change the % catcodes of certain characters like ``\texttt{@}'' in % \texttt{amstex.sty}. As a result the tests below would fail since % they assume non-active character tokens. Therefore we evaluate % =\@nextchar= once thereby turning the first token of its % replacement text into a char. At this point here this should have % been the only char present in =\@nextchar= which put into via a % =\def=. % \changes{v2.0f}{1992/02/29}{Ensure to test a char which is not active} % \begin{macrocode} \edef\@nextchar{\expandafter\string\@nextchar}% \@chnum \if \@nextchar c\z@ \else \if \@nextchar l\@ne \else \if \@nextchar r\tw@ \else % \end{macrocode} % If it is a different \textsf{token}, we know that the class was % not $0$. We assign the value $0$ to =\@chnum= because this value % is needed for the \texttt{|}--\textsf{token}. Now we must check % the remaining classes. Note that the value of =\@chnum= is % insignificant here for most classes. % \begin{macrocode} \z@ \@chclass \if\@nextchar |\@ne \else \if \@nextchar !6 \else \if \@nextchar @7 \else \if \@nextchar <8 \else \if \@nextchar >9 \else % \end{macrocode} % The remaining permitted \textsf{tokens} are \texttt{p}, % \texttt{m} and \texttt{b} (class $10$). % \begin{macrocode} 10 \@chnum \if \@nextchar m\thr@@@@ \else \if \@nextchar p4 \else \if \@nextchar b5 \else % \end{macrocode} % Now the only remaining possibility is a forbidden \textsf{token}, % so we choose class $0$ and number $0$ and give an error message. % Then we finish the macro by closing all =\if='s. % \begin{macrocode} \z@ \@chclass \z@ \@preamerr \z@ \fi \fi \fi \fi \fi \fi \fi \fi \fi \fi \fi \fi \fi \fi \fi \fi} \ExplSyntaxOn % \end{macrocode} % \end{macro} % % % % % % \subsection{Multiple columns ($*$--form)} % % \begin{macro}{\@xexpast} % \begin{macro}{\the@toks} % \begin{macro}{\the@toksz} % \label{@xexpast} Now we discuss the macro that deletes all forms % of type =*{=\textit{N\/}=}{=\textit{String\/}=}= from a user % preamble and replaces them with \textit{N} copies of % \textit{String}. Nested $*$--expressions are dealt with % correctly, that means $*$--expressions are not substituted if % they are in explicit braces, as in =@{*}=. % % This macro is called via % =\@xexpast=\meta{preamble}=*0x\@@@@=. % The $*$--expression =*0x= is being used to terminate the % recursion, % as we shall see later, and =\@@@@= serves as an argument % delimiter. =\@xexpast= has four arguments. The first % one is the part of the % user preamble before the first $*$--expression while the second % and third ones are the arguments of the first $*$--expression % (that is \textit{N} and \textit{String} in the notation mentioned % above). % The fourth argument is the rest of the preamble. % \begin{macrocode} \def\@xexpast#1*#2#3#4\@@@@{% % \end{macrocode} % The number of copies of \textit{String} (=#2=) that are to be % produced will be saved in a \textsf{count} register. % \begin{macrocode} \@tempcnta #2 % \end{macrocode} % We save the part of the preamble which does not % contain a $*$--form (=#1=) % in a \PlainTeX\ \textsf{token} register. % We also save \textit{String} (=#3=) using a \LaTeX\ % \textsf{token} register. % \begin{macrocode} \toks@={#1}\@temptokena={#3}% % \end{macrocode} % Now we have to use a little trick to produce \textit{N} copies of % \textit{String}. % We could try =\def\@tempa{#1}= and then % \textit{N} times =\edef\@tempa{\@tempa#3}=. This would have the % undesired effect that all macros within =#1= and =#3= % would be expanded, although, for example, constructions like % =@{..}= are not supposed to be changed. % That is why we =\let= two control sequences to % be equivalent to =\relax=. % \begin{macrocode} \let\the@toksz\relax \let\the@toks\relax % \end{macrocode} % Then we ensure that =\@tempa= contains % ={\the@toksz\the@toks...\the@toks}= (the macro % =\the@toks= exactly \textit{N\/} times) as substitution text. % \begin{macrocode} \def\@tempa{\the@toksz}% \ifnum\@tempcnta >0 \@whilenum\@tempcnta >0\do {\edef\@tempa{\@tempa\the@toks}\advance \@tempcnta \m@ne}% % \end{macrocode} % If \textit{N\/} was greater than zero we prepare for another call % of =\@xexpast=. Otherwise we assume we have reached the end of % the user preamble, because we had appended =*0x\@@@@= when we first % called =\@xexpast=. In other words: if the user inserts % =*{0}{..}= in his preamble, \LaTeX\ ignores the rest of it. % \begin{macrocode} \let \@tempb \@xexpast \else \let \@tempb \@xexnoop \fi % \end{macrocode} % Now we will make sure that the part of the user preamble, which % was already dealt with, will be saved again in =\@tempa=. % \begin{macrocode} \def\the@toksz{\the\toks@}\def\the@toks{\the\@temptokena}% \edef\@tempa{\@tempa}% % \end{macrocode} % We have now evaluated the first $*$--expression, and the user % preamble up to this point % is saved in =\@tempa=. We will put the contents of % =\@tempa= and the rest of the user preamble together and work % on the result with =\@tempb=. This macro either corresponds % to =\@xexpast=, so that the next % $*$--expression is handled, or to the macro =\@xexnoop=, % which only ends the recursion by deleting its argument. % \begin{macrocode} \expandafter \@tempb \@tempa #4\@@@@} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\@xexnoop} % So the first big problem is solved. Now it is easy to % specify =\@xexnoop=. % Its argument is delimited by =\@@@@= and it simply expands to % nothing. % \begin{macrocode} % \def\@xexnoop#1\@@@@{} % \end{macrocode} % \end{macro} % % % % % \section{The insertion of declarations % (\texttt{>}, \texttt{<}, \texttt{!}, \texttt{@})} % % % The preamble will be enlarged with the help of =\xdef=, but the % arguments of \texttt{>}, \texttt{<},~\texttt{!}\ and \texttt{@} are % not supposed to be expanded during the construction (we want an % implementation that doesn't need a =\protect=). So we have to find a % way to inhibit the expansion of those arguments. % % We will solve this problem with \textsf{token} registers. We need % one register for every \texttt{!}\ and \texttt{@}, while we need two % for every \texttt{c}, \texttt{l}, \texttt{r}, \texttt{m}, \texttt{p} % or \texttt{b}. This limits the number of columns of a table because % there are only 256 \textsf{token} registers. But then, who needs % tables with more than 100 columns? % % One could also find a solution which only needs two or three % \textsf{token} registers by proceeding similarly as in the macro % =\@xexpast= (see page \pageref{@xexpast}). The advantage of our % approach is the fact that we avoid some of the problems that arise % with the other method\footnote{Maybe there are also historical % reasons.}. % % So how do we proceed? Let us assume that we had =!{foo}= in the % user preamble and say we saved \texttt{foo} in % \textsf{token} register $5$. Then we call % =\@addtopreamble{\the@toks5}= where % =\the@toks= is defined in a way that it does not expand % (for example it could be equivalent to =\relax=). Every % following call % of =\@addtopreamble= leaves =\the@toks5= unchanged in % =\@preamble=. If the construction of the preamble is completed % we change the definition of =\the@toks= to % =\the\toks= and expand =\@preamble= for the last time. % During this process all parts of the form % =\the@toks=\meta{Number} % will be substituted by the contents of the respective \textsf{token} % registers. % % As we can see from this informal discussion the construction of the % preamble has to take place within a group, so that the % \textsf{token} registers we use will be freed later on. For that % reason we keep all assignments to =\@preamble= global; therefore the % replacement text of this macro will remain the same after we leave % the group. % % \begin{macro}{\count@} % We further need a \textsf{count} register to remember which % \textsf{token} register is to be used next. This will be % initialized with $-1$ if we want to begin with the \textsf{token} % register $0$. We use the \PlainTeX\ scratch register =\count@= % because everything takes place locally. All we have to do is % insert =\the@toks= =\the= =\count@= into the preamble. % =\the@toks= will remain unchanged and =\the\count@= expands into % the saved number. % \end{macro} % % \begin{macro}{\prepnext@tok} % The macro =\prepnext@tok= is in charge of preparing the next % \textsf{token} register. For that purpose we increase % =\count@= by $1$: % \begin{macrocode} \def\prepnext@tok{\advance \count@ \@ne % \end{macrocode} % Then we locally delete any contents the % \textsf{token} register might have. % \begin{macrocode} \toks\count@{}} % \end{macrocode} % \end{macro} % % \begin{macro}{\save@decl} % During the construction of the preamble the current % \textsf{token} is always saved in the macro =\@nextchar= (see the % definition of =\@mkpream= on page \pageref{@mkpream}). The macro % =\save@decl= saves it into the next free \textsf{token} register, % i.e.\ in =\toks\count@=. % \changes{v2.0c}{1990/08/14}{\cs{relax} removed and added elsewhere.} % \begin{macrocode} \def\save@decl{\toks\count@ \expandafter{\@nextchar}} % \end{macrocode} % The reason for the use of =\relax= is the following % hypothetical situation in the preamble: % \quad =..\the\toks1\the\toks2..= \quad \TeX\ expands % =\the\toks2= first in order to find out if the digit =1= % is followed by other digits. E.g.\ a =5= saved in the % \textsf{token} register $2$ would lead \TeX\ to insert the contents % of \textsf{token} register $15$ instead of $1$ later on. % % The example above referred to an older version of =\save@decl= which % inserted a =\relax= inside the token register. This is now moved to % the places where the actual token registers are inserted (look for % =\the@toks=) because the old version would still make =@= % expressions to moving arguments since after expanding the second % register while looking for the end of the number the contents of the % token register is added so that later on the whole register will be % expanded. This serious bug was found after nearly two years % international use of this package by Johannes Braams. % \end{macro} % % % % How does the situation look like, if we want to add another column % to the preamble, i.e.\ if we have found a \texttt{c}, \texttt{l}, % \texttt{r}, \texttt{p}, \texttt{m} or \texttt{b} in the user % preamble? In this case we have the problem of the \textsf{token} % register from =>{..}= and =<{..}= having to be inserted at this % moment because formatting instructions like =\hfil= have to be set % around them. On the other hand it is not known yet, if any =<{..}= % instruction will appear in the user preamble at all. % % We solve this problem by adding two \textsf{token} registers at a % time. This explains, why we have freed the \textsf{token} registers % in =\prepnext@tok=. % % \begin{macro}{\insert@column} % \begin{macro}{\@sharp} % \begin{macro}{\textonly@unskip} % \begin{macro}{\@protected@firstofone} % We now define the macro =\insert@column= which will do % this work for us. % \begin{macrocode} \def\insert@column{% % \end{macrocode} % % For tagging we insert as special socket, that adds the necessary % PDF tag at the beginning of the cell if tagging is enabled. % \changes{v2.6a}{2023/12/11}{Support for tagged PDF} % \begin{macrocode} \UseTaggingSocket{tbl/cell/begin}% % \end{macrocode} % Next we have to insert the toks register holding the content of % \verb=>{...}=. Here, we assume that the \textsf{count} register % =\@tempcnta= has saved the value $=\count@= - 1$. % % To keep \TeX{} happy if there is a look ahead in the tabular % preamble, i.e., starting in \verb=>{...}=, which uses the % Appendix~D trick (for example, anything with a trailing optional % argument defined by \pkg{ltcmd}), we wrap everything here in a % protected version of \cs{@firstofone}. \TeX{} otherwise can get % confused about the value of the master counter, and we get some % strange errors. We suspected that there was an underlying issue % is the \TeX{} engine, but it turned out to be rather hard to get % to the bottom of it, because the master counter is not accessible % through \TeX{}'s tracing tools. Thus, all we could do was % producing various example documents, observing results, as well % as staring at a printout of the \TeX{} program. As an example, % without this approach, something like % \begin{verbatim} % \NewDocumentCommand\foo{o}{x} % \begin{tabular}{>{\foo}l} % Foo % \end{tabular} % \end{verbatim} % failed. That can be fixed by adding a \cs{relax} after the % \cs{@tempcnta}, but that then leads to issues if you are % collecting whole cells (tagging code or \pkg{collcell}), where % you can no longer alter the meaning of \cs{cr} as the master % counter goes wrong due to an obscure bug (or perhaps, say, an % undocumented feature of \TeX{}). Eventually, we were able to pin % down the root cause and really understand why % \cs{@protected@firstofone} solves the problem, even though it % looks like a nonsense addition to the code that does nothing % useful.\footnote{So it is a \TeX{} engine bug that was in there % from day one, or if you like, it is a hidden feature that is not % explained; neither in the \TeX{}book nor in the program code. We % don't really expect this to change in \TeX{} after such a long % time, other than perhaps documenting it as a feature, so this is % a proper solution to the problem and not just a workaround.} % % The problem is that \TeX{} tries to conserve stack space, and % when the last token of an existing token list is a macro, then % this token list is \emph{first} removed from memory (reducing the % stack) \emph{before} the macro replacement text (as a new % token list) is given to the parser adding a new stack level. This % is done using the routine \texttt{end\_token\_list} in the \TeX{} % program and ending the u-part of an \cs{halign} column with this % routine immediately sets the \emph{master counter} used by alignments to % zero (see chapter~22 and Appendix~D of the \TeX{}book). This % means that technically the expansion of the last token in the u-part (if it % is a macro) is not executed in the context of the u-part, but in % the context of the alignment entry in the document. That normally % doesn't make any difference whatsoever --- unless you play % around (as we sometimes have to) with tricks like those from % Appendix~D. % % To illustrate the issue we show a bit of strange low-level plain % \TeX{} code.\footnote{If all of this looks mighty strange to you, % don't worry. You will be unlikely to need to know about it. It is % just there so that programmers at some point in the future do not % have to wonder too much why there is this odd % \cs{@protected@firstofone} that apparently does nothing % useful. It took us several nights of head scratching to come up % with these minimal examples and then some more time to understand % what the heck is going on inside \TeX{}---thanks to Bruno for the % right ideas on the latter.} Below are two very special grouping % commands that are like \cs{bgroup} and \cs{egroup} but also % affect the alignment master counter when expanded (see % \TeX{}book p.385). If one of them is used as the % last macro in the u-part of a column, then you get strange errors % that you shouldn't get. % \begin{verbatim} % \def\bbgroup{{\ifnum0=`}\fi} % \def\eegroup{\ifnum0=`{\fi}} % % % Fails with an error message, but there should be none: % \halign{% % \message{u-part^^J}% % \bbgroup % <-- in the u-part % \eegroup % <-- in the u-part % #% % \message{v-part^^J}% % \hfill\cr % \message{body^^J}x % \cr % } % % % Fails but should work, the v-part is never reached: % \halign{% % \message{u-part^^J}% % \bbgroup % <-- in the u-part % #% % \message{v-part^^JJ}% % \eegroup % <-- in the v-part % \hfill\cr % \message{body^^J}x % \cr % } % \end{verbatim} % % So the trick we use now is making \cs{@protected@firstofone} the % last macro in the u-part, i.e., before the \cs{@sharp}. That way % its argument is always fully expanded as part of the alignment % entry and not as part of the u-part and this way we know exactly % what the master counter value is at this point, regardless of the content of % \verb=>{...}=. % % \changes{v2.6f}{2024/09/13}{Stop parsing for optional argument (gh/1468)} % \changes{v2.6g}{2024/10/12}{Further work to support optional args in preamble (gh/1468)} % \begin{macrocode} \@protected@firstofone { \the@toks \the \@tempcnta \ignorespaces } % \end{macrocode} % Next follows the =#= sign which specifies the place % where the text of the column shall be inserted. To avoid % errors during the expansions in % =\@addtopreamble= we hide this sign in the command % =\@sharp= which is temporarily occupied with % =\relax= during the build-up of the preamble. % To remove unwanted spaces before and after the column in text mode, % we set an =\ignorespaces= in front (see above) and a =\unskip= % afterwards; in math mode, the latter is suppressed while the % \cs{ignorespaces} makes no difference. % \changes{v2.0e}{1991/02/07}{Added \{\} around \cs{@sharp} for new ftsel} % \changes{v2.0h}{1992/06/22}{Removed \{\} again in favor of % \cs{d@llarbegin}} % \changes{v2.6b}{2024/04/08}{Do not \cs{unskip} if in math mode (gh/1323)} % \begin{macrocode} \@sharp \textonly@unskip % \end{macrocode} % Then the second \textsf{token} register follows whose number should % be saved in =\count@=. % We make sure that there will be no further expansion after reading % the number, by finishing with =\relax=. The case above is not % critical since it is ended by =\ignorespaces=. % \changes{v2.0c}{1990/08/14}{\cs{relax} added to avoid problem % \cs{the}\cs{toks0}\cs{the}\cs{toks1}.} % \begin{macrocode} \the@toks \the \count@ \relax % \end{macrocode} % % And another socket for tagging that adds the necessary closing tag % if enabled. % \changes{v2.6a}{2023/12/11}{Support for tagged PDF} % \begin{macrocode} \UseTaggingSocket{tbl/cell/end}% } % \end{macrocode} % Do the unskip only if we are in hmode: % \changes{v2.6b}{2024/04/08}{Do not \cs{unskip} if in math mode (gh/1323)} % \begin{macrocode} \protected\def\textonly@unskip{\ifhmode\unskip\fi} % \end{macrocode} % \changes{v2.6g}{2024/10/12}{Further work to support optional args in preamble (gh/1468)} % We need an engine-protected function that is just \cs{@firstofone}: % \begin{macrocode} \protected\long\def\@protected@firstofone#1{#1} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\insert@pcolumn} % Handling pcolumn-cells needs slightly different handling when % doing tagging. Rather than changing the plugs in % \cs{insert@column} back and forth, we simply use a different % version of \cs{insert@column} that has its own sockets. % \changes{v2.6a}{2023/12/11}{Support for tagged PDF} % \begin{macrocode} \def\insert@pcolumn{% \UseTaggingSocket{tbl/pcell/begin}% % \end{macrocode} % \changes{v2.6f}{2024/09/13}{Stop parsing for optional argument (gh/1468)} % \begin{macrocode} \the@toks \the \@tempcnta \relax \ignorespaces \@sharp \unskip \the@toks \the \count@ \relax \UseTaggingSocket{tbl/pcell/end}% } % \end{macrocode} % \end{macro} % % % \subsection{The separation of columns} % % \begin{macro}{\@addamp} % In the preamble a =&= has to be inserted between any two columns; % before the first column there should not be a =&=. As the user % preamble may start with a \texttt{|} we have to remember somehow % if we have already inserted a =#= (i.e.\ a column). This is done % with the boolean variable =\if@firstamp= that we test in % =\@addamp=, the macro that inserts the =&=. % \begin{macrocode} % \newif \@iffirstamp \def\@addamp { \if@firstamp \@firstampfalse \else % \end{macrocode} % If we are after the first column we have to insert a \verb=&= and % also update the cell data. % \changes{v2.6a}{2023/12/11}{Managing cell indexes} % \begin{macrocode} \edef\@preamble{\@preamble & \noexpand\tbl_update_cell_data: } \fi } % \end{macrocode} % \end{macro} % % % % \begin{macro}{\@acol} % \begin{macro}{\@acolampacol} % \begin{macro}{\col@sep} % We will now define some abbreviations for the extensions, % appearing most often in the preamble build-up. % Here =\col@sep= is a \textsf{dimen} register which is set % equivalent to =\arraycolsep= in an \textsf{array}--environment, % otherwise it is set equivalent to =\tabcolsep=. % \begin{macrocode} \newdimen\col@sep \def\@acol{\@addtopreamble{\hskip\col@sep}} % \def\@acolampacol{\@acol\@addamp\@acol} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % % \subsection{The macro \texttt{\textbackslash @mkpream}} % % \begin{macro}{\@mkpream} % \emph{The code below has been replaced long time ago by an % extended version further down but the code and its documentation % was left here for reference. It is now commented out to avoid % confusion.} % \begin{macro}{\the@toks} % \label{@mkpream} % Now we can define the macro which builds up the preamble for the % =\halign=. % First we initialize =\@preamble=, =\@lastchclass= % and the boolean variable =\if@firstamp=. % \begin{macrocode} %\def\@mkpream#1{\gdef\@preamble{}\@lastchclass 4 \@firstamptrue % \end{macrocode} % During the build-up of the preamble we cannot directly use the % =#= sign; this would lead to an error message in the next % =\@addtopreamble= call. % Instead, we use the command =\@sharp= at places where later % a =#= will be. % This command is at first given the meaning =\relax=; % therefore it will not be expanded when the preamble % is extended. % In the macro =\@array=, shortly before the =\halign= % is carried out, =\@sharp= is given its final meaning. % % In a similar way, % we deal with the commands =\@startpbox= and % =\@endpbox=, although the reason is different here: these % macros expand in many \textsf{tokens} which would delay the % build-up of the preamble. % \begin{macrocode} % \let\@sharp\relax\let\@startpbox\relax\let\@endpbox\relax % \end{macrocode} % Two more are needed to deal with the code that handles struts % for extra space after a row from =\\[]= % (=\do@row@strut=) and code that manages m-cells depending on % their heights (=\ar@align@mcell=). % \changes{v2.4e}{2016/10/07}{Fixing SX68732} % \changes{v2.4f}{2017/11/04}{Managing m-cells without \cs{vcenter}} % \begin{macrocode} % \let\do@row@strut\relax % \let\ar@align@mcell\relax % \end{macrocode} % Now we remove possible $*$-forms in the user preamble with the % command =\@xexpast=. As we already know, this command saves % its result in the macro =\@tempa=. % \begin{macrocode} % \@xexpast #1*0x\@@@@ % \end{macrocode} % Afterwards we initialize all registers and macros, that we need % for the build-up of the preamble. % Since we want to start with the \textsf{token} register $0$, % =\count@= has to contain the value $-1$. % \begin{macrocode} % \count@\m@ne % \let\the@toks\relax % \end{macrocode} % Then we call up =\prepnext@tok= in order to prepare the % \textsf{token} register $0$ for use. % \begin{macrocode} % \prepnext@tok % \end{macrocode} % To evaluate the user preamble (without stars) saved in % =\@tempa= we use the \LaTeX--macro =\@tfor=. % The strange appearing construction with =\expandafter= is % based on the fact that we have to put the replacement text of % =\@tempa= and not the macro =\@tempa= to this % \LaTeX--macro. % \begin{macrocode} % \expandafter \@tfor \expandafter \@nextchar % \expandafter :\expandafter =\@tempa \do % \end{macrocode} % The body of this loop (the group after the =\do=) % is executed for one \textsf{token} at a time, whereas % the current \textsf{token} is saved in =\@nextchar=. % At first we evaluate the current \textsf{token} with the already % defined macro =\@testpach=, i.e.\ we assign to % =\@chclass= the character class and to =\@chnum= % the character number of this \textsf{token}. % \changes{v2.0f}{1992/02/29}{\cs{@testpach} now without arg} % \begin{macrocode} % {\@testpach % \end{macrocode} % Then we branch out depending on the value of =\@chclass= into % different macros that extend the preamble respectively. % \begin{macrocode} % \ifcase \@chclass \@classz \or \@classi \or \@classii % \or \save@decl \or \or \@classv \or \@classvi % \or \@classvii \or \@classviii \or \@classix % \or \@classx \fi % \end{macrocode} % Two cases deserve our special attention: Since the current % \textsf{token} cannot have the character class $4$ (start) we % have skipped this possibility. If the character class is $3$, % only the content of =\@nextchar= has to be saved into the current % \textsf{token} register; therefore we call up =\save@decl= % directly and save a macro name. After the preamble has been % extended we assign the value of =\@chclass= to the counter % =\@lastchclass= to assure that this information will be available % during the next run of the loop. % \begin{macrocode} % \@lastchclass\@chclass}% % \end{macrocode} % After the loop has been finished space must still be added to % the created preamble, depending on the last \textsf{token}. % Depending on the value of =\@lastchclass= we perform % the necessary operations. % \begin{macrocode} % \ifcase\@lastchclass % \end{macrocode} % If the last class equals $0$ we add a % =\hskip \col@sep=. % \begin{macrocode} % \@acol \or % \end{macrocode} % If it equals $1$ we do not add any additional space so that the % horizontal lines do not exceed the vertical ones. % \begin{macrocode} % \or % \end{macrocode} % Class $2$ is treated like class $0$ because a =<{...}= can % only directly follow after class $0$. % \begin{macrocode} % \@acol \or % \end{macrocode} % Most of the other possibilities can only appear if the user % preamble was defective. Class $3$ is not allowed since after a % =>{..}= there must always follow a \texttt{c}, \texttt{l}, % \texttt{r}, \texttt{p},\texttt{m} or \texttt{b}. We report an % error and ignore the declaration given by ={..}=. % \begin{macrocode} % \@preamerr \thr@@@@ \or % \end{macrocode} % If =\@lastchclass= is $4$ the user preamble has been empty. % To continue, we insert a =#= in the preamble. % \begin{macrocode} % \@preamerr \tw@ \@addtopreamble\@sharp \or % \end{macrocode} % Class $5$ is allowed again. In this case % (the user preamble ends with =@{..}=) we need not % do anything. % \begin{macrocode} % \or % \end{macrocode} % Any other case means that the arguments to =@=, \texttt{!}, % \texttt{<}, \texttt{>}, \texttt{p}, \texttt{m} or \texttt{b} have % been forgotten. So we report an error and ignore the last % \textsf{token}. % \begin{macrocode} % \else \@preamerr \@ne \fi % \end{macrocode} % Now that the build-up of the preamble is almost finished we can % insert the \textsf{token} registers and therefore redefine % =\the@toks=. The actual insertion, though, is performed % later. % \begin{macrocode} % \def\the@toks{\the\toks}} % \end{macrocode} % \end{macro} % \end{macro} % % % % \section{The macros \texttt{\textbackslash @classz} % to \texttt{\textbackslash @classx}} % % The preamble is extended by the macros =\@classz= to % =\@classx= which are called by =\@mkpream= % depending on =\@lastchclass= % (i.e. the character class of the last \textsf{token}). % \begin{macro}{\@classx} % First we define =\@classx= because of its important r\^ole. % When it is called we find that the current % \textsf{token} is \texttt{p}, \texttt{m} or \texttt{b}. % That means that a new column has to start. % \begin{macrocode} \def\@classx{% % \end{macrocode} % Depending on the value of =\@lastchclass= different actions % must take place: % \begin{macrocode} \ifcase \@lastchclass % \end{macrocode} % If the last character class was $0$ we separate the columns by % =\hskip\col@sep= followed by =&= and another % =\hskip\col@sep=. % \begin{macrocode} \@acolampacol \or % \end{macrocode} % If the last class was class $1$ --- that means that a vertical % line was % drawn, --- before this line a =\hskip\col@sep= was inserted. % Therefore there has to be only a =&= followed by % =\hskip\col@sep=. But this =&= may be inserted only % if this is not the first column. This process is controlled % by =\if@firstamp= in the macro =\addamp=. % \begin{macrocode} \@addamp \@acol \or % \end{macrocode} % Class $2$ is treated like class $0$ because =<{...}= can only % follow after class $0$. % \begin{macrocode} \@acolampacol \or % \end{macrocode} % Class $3$ requires no actions because all things necessary have % been done by the preamble \textsf{token} \texttt{>}. % \begin{macrocode} \or % \end{macrocode} % Class $4$ means that we are at the beginning of the preamble. % Therefore we start the preamble with =\hskip\col@sep= and % then call =\@firstampfalse=. This makes sure that a later % =\@addamp= inserts the character % =&= into the preamble. % \begin{macrocode} \@acol \@firstampfalse \or % \end{macrocode} % For class $5$ \textsf{tokens} only the character =&= is inserted % as a column separator. Therefore we call =\@addamp=. % \begin{macrocode} \@addamp % \end{macrocode} % Other cases are impossible. For an example % $=\@lastchclass= \string= 6$---as it might appear in a % preamble of the form =...!p...=---\texttt{p} would have % been taken as an argument of \texttt{!}\ by =\@testpach=. % \begin{macrocode} \fi} % \end{macrocode} % \end{macro} % % % \begin{macro}{\@classz} % If the character class of the last \textsf{token} is $0$ we have % \texttt{c}, \texttt{l}, \texttt{r} or an argument of \texttt{m}, % \texttt{b} or\ \texttt{p}. In the first three cases the preamble % must be extended the same way as if we had class $10$. The % remaining two cases do not require any action because the space % needed was generated by the last \textsf{token} (i.e.\ % \texttt{m}, \texttt{b} or \texttt{p}). Since =\@lastchclass= has % the value $10$ at this point nothing happens when =\@classx= is % called. So the macro =\@chlassz= may start like this: % \begin{macrocode} \def\@classz{\@classx % \end{macrocode} % According to the definition of =\insert@column= we must store % the number of the \textsf{token} register in which a preceding % =>{..}= might have stored its argument into % =\@tempcnta=. % \begin{macrocode} \@tempcnta \count@ % \end{macrocode} % To have $=\count@= \string= =\@tmpcnta= + 1$ we prepare % the next \textsf{token} register. % \begin{macrocode} \prepnext@tok % \end{macrocode} % Now the preamble must be extended with the column whose format % can be determined by =\@chnum=. % \begin{macrocode} \@addtopreamble{\ifcase \@chnum % \end{macrocode} % If =\@chnum= has the value $0$ a centered column has to be % generated. % So we begin with stretchable space. % \begin{macrocode} \hfil % \end{macrocode} % We also add a space of 1sp just in case the first thing in the % cell is a command doing an =\unskip=. % \changes{v2.4k}{2018/12/30}{Add extra \cs{hskip} to guard against an % \cs{unskip} at the start of a c-column cell (gh/102)} % \begin{macrocode} \hskip1sp% % \end{macrocode} % The command =\d@llarbegin= follows expanding into =\begingroup= % (in the \textsf{tabular}--environment) or into =$=. Doing this % (provided an appropriate setting of =\d@llarbegin=) we achieve % that the contents of the columns of an \textsf{array}--environment % are set in math mode while those of a \textsf{tabular}--environment % are set in LR mode. % \begin{macrocode} \d@llarbegin % \end{macrocode} % Now we insert the contents of the two \textsf{token} registers % and the symbol % for the column entry (i.e.\ =#= or % more precise =\@sharp=) using =\insert@column=. % \begin{macrocode} \insert@column % \end{macrocode} % We end this case with =\d@llarend= and =\hfil= where =\d@llarend= % again is either =$= or =\endgroup=. % The strut to enforce a regular row height is placed between the two. % \changes{v2.4e}{2016/10/07}{Fixing SX68732} % \begin{macrocode} \d@llarend \do@row@strut \hfil \or % \end{macrocode} % The templates for \texttt{l} and \texttt{r} (i.e.\ =\@chnum= $1$ % or $2$) are generated the same way. Since one =\hfil= is % missing the text is moved to the relevant side. % The =\kern\z@= is needed in case of an empty column % entry. Otherwise % the =\unskip= in =\insert@column= removes the % =\hfil=. Changed to =\hskip1sp= so that it interacts better with % =\@bsphack=. % \changes{v2.3f}{1996/04/22} % {(DPC) Extra \cs{kern} keeps tabcolsep in empty l columns % internal/2122} % \changes{v2.3i}{1996/06/14} % {Change both \cs{kern}\cs{z@} to \cs{hskip}1sp for latex/2160} % \changes{v2.4e}{2016/10/07}{Fixing SX68732} % \begin{macrocode} \hskip1sp\d@llarbegin \insert@column \d@llarend \do@row@strut \hfil \or \hfil\hskip1sp\d@llarbegin \insert@column \d@llarend \do@row@strut \or % \end{macrocode} % The templates for \texttt{p}, \texttt{m} and \texttt{b} mainly % consist of a \textsf{box}. In case of \texttt{m} it is generated % by =\vcenter=. This command is allowed only in math % mode. Therefore we start with a~=$=. % \changes{v2.4f}{2017/11/04}{Managing m-cells without \cs{vcenter}} % \begin{macrocode} \setbox\ar@mcellbox\vbox % \end{macrocode} % The part of the templates which is the same in all three cases % (\texttt{p}, \texttt{m} and \texttt{b}) is built by the macros % =\@startpbox= and =\@endpbox=. =\@startpbox= has an argument: the % width of the column which is stored in the current \textsf{token} % (i.e.\ =\@nextchar=). Between these two macros we find the well % known =\insert@column= or rather the variant for tagging: % \cs{insert@pcolumn}. The strut is placed after the box. % \changes{v2.4e}{2016/10/07}{Fixing SX68732} % \changes{v2.4f}{2017/11/04}{Managing m-cells without \cs{vcenter}} % \changes{v2.6a}{2023/12/11}{Support for tagged PDF} % \begin{macrocode} \@startpbox{\@nextchar}\insert@pcolumn \@endpbox \ar@align@mcell \do@row@strut \or % \end{macrocode} % The templates for \texttt{p} and \texttt{b} are generated in the % same way though we do not need the =$= characters because we use % =\vtop= or =\vbox=. % \changes{v2.4e}{2016/10/07}{Fixing SX68732} % \changes{v2.6a}{2023/12/11}{Support for tagged PDF} % \begin{macrocode} \vtop \@startpbox{\@nextchar}\insert@pcolumn \@endpbox\do@row@strut \or \vbox \@startpbox{\@nextchar}\insert@pcolumn \@endpbox\do@row@strut % \end{macrocode} % Other values for =\@chnum= are impossible. Therefore we % end the arguments to =\@addtopreamble= and =\ifcase=. % Before we come to the end of =\@classz= we have to % prepare the next \textsf{token} register. % \begin{macrocode} \fi}\prepnext@tok} % \end{macrocode} % \end{macro} % % % \begin{macro}{\ar@mcellbox} % When dealing with m-cells we need a box to measure the cell % height. % \changes{v2.4f}{2017/11/04}{Managing m-cells without \cs{vcenter}} % \begin{macrocode} \newbox\ar@mcellbox % \end{macrocode} % \end{macro} % % % \begin{macro}{\ar@align@mcell} % M-cells are supposed to be vertically centered within the table % row. In the original implementation that was done using % =\vcenter= but the issue with that approach is that it centers % the material based on the math-axis. In most situations that % comes out quit right, but if, for example, an m-cell has only a % single line worth of material inside it will be positioned % differently to a =l=, =c= or =r= cell or to a =p= or =b= cell % with the same content. % % For that reason the new implementation does the centering % manually: First we check the height of the cell and if that is % less or equal to =\ht\strutbox= we assume that this is a % single line cell. In that case we don't do any vertical maneuver % and simply output the box, i.e., make it behave like a single % line p-cell. % % We use the height of \cs{strutbox} not \cs{@arstrutbox} in the comparison, % because \cs{box}\cs{ar@mcellbox} does not have any strut % incorporated and if \cs{arraystretch} is made very % small the test would otherwise incorrectly assume a multi-line cell. % \changes{v2.4f}{2017/11/04}{Managing m-cells without \cs{vcenter}} % \changes{v2.5g}{2022/09/04}{Test against \cs{strutbox} height (gh/766)} % \begin{macrocode} \def\ar@align@mcell{% \ifdim \ht\ar@mcellbox > \ht\strutbox % \end{macrocode} % Otherwise we realign vertically by lowering the box. The question % is how much do we need to move down? If there is any % =\arraystretch= in place then the first line will have some % unusual height and we don't want to consider that when finding % the middle point. So we subtract from the cell height the height % of that strut. But of course we want to include the normal height % of the first line (which would be something like =\ht\strutbox=) % so we need to add that. On the other hand, when centering around % the mid-point of the cell, we also need to account for the depth % of the last line (which is nominally something like % =\dp\strutbox=). Both together equals =\baselineskip= so that is % what we add and then lower the cell by half of the resulting value. % \begin{macrocode} \begingroup \dimen@\ht\ar@mcellbox \advance\dimen@-\ht\@arstrutbox \advance\dimen@\baselineskip \lower.5\dimen@\box\ar@mcellbox \endgroup \else % assume one line and align at baseline \box\ar@mcellbox \fi} % \end{macrocode} % \end{macro} % % % \begin{macro}{\@classix} % \emph{The code below has been replaced long time ago by an % extended version further down but the code and its documentation % was left here for reference. It is now commented out to avoid % confusion.} % % In case of class $9$ (\texttt{>}--\textsf{token}) we first check % if the character class of the last % \textsf{token} was $3$. In this case we have a % user preamble of the form =..>{...}>{...}..= which % is not allowed. We only give an error message and continue. % So the declarations defined by the first =>{...}= % are ignored. % \begin{macrocode} %\def\@classix{\ifnum \@lastchclass = \thr@@@@ % \@preamerr \thr@@@@ \fi % \end{macrocode} % Furthermore, we call up =\@class10= because afterwards always a % new column is started by \texttt{c}, \texttt{l}, \texttt{r}, % \texttt{p}, \texttt{m} or \texttt{b}. % \begin{macrocode} % \@classx} % \end{macrocode} % \end{macro} % % % % \begin{macro}{\@classviii} % \emph{The code below has been replaced long time ago by an % extended version further down but the code and its documentation % was left here for reference. It is now commented out to avoid % confusion.} % % If the current \textsf{token} is a \texttt{<} the last character % class must be $0$. In this case it is not necessary to extend the % preamble. Otherwise we output an error message, set =\@chclass= % to $6$ and call =\@classvi=. By doing this we achieve that % \texttt{<} is treated like \texttt{!}. % \begin{macrocode} %\def\@classviii{\ifnum \@lastchclass >\z@ % \@preamerr 4\@chclass 6 \@classvi \fi} % \end{macrocode} % \end{macro} % % \begin{macro}{\@arrayrule} % There is only one incompatibility with the original definition: % the definition of =\@arrayrule=. In the original a line without % width\footnote{So the space between \texttt{cc} and \texttt{c|c} % is equal.} is created by multiple insertions of % =\hskip .5\arrayrulewidth=. % We only insert a vertical line into the % preamble. This is done to prevent problems with \TeX's main % memory when generating tables with many vertical lines in them % (especially in the case of \textsf{floats}). % \begin{macrocode} \def\@arrayrule{\@addtopreamble \vline} % \end{macrocode} % \end{macro} % % \begin{macro}{\@classvii} % As a consequence it follows that in case of class $7$ % (=@= \textsf{token}) the preamble need not to be extended. % In the original definition $=\@lastchclass= \string= 1$ % is treated by inserting =\hskip .5\arrayrulewidth=. % We only check if the last \textsf{token} was of class $3$ which is % forbidden. % \begin{macrocode} \def\@classvii{\ifnum \@lastchclass = \thr@@@@ % \end{macrocode} % If this is true we output an error message and % ignore the declarations stored % by the last =>{...}=, because these are overwritten % by the argument of \texttt{@}. % \begin{macrocode} \@preamerr \thr@@@@ \fi} % \end{macrocode} % \end{macro} % % % \begin{macro}{\@classvi} % If the current \textsf{token} is a regular \texttt{!}\ and the % last class was $0$ or $2$ we extend the preamble with % =\hskip\col@sep=. If the last \textsf{token} was of class $1$ % (for instance \texttt{|}) we extend with =\hskip \doublerulesep= % because the construction =!{...}= has to be treated like % \texttt{|}. % \begin{macrocode} \def\@classvi{\ifcase \@lastchclass \@acol \or \@addtopreamble{\hskip \doublerulesep}\or \@acol \or % \end{macrocode} % Now =\@preamerr...= should follow because a % user preamble of the form =..>{..}!.= is not allowed. % To save memory we call =\@classvii= instead which also % does what we want. % \begin{macrocode} \@classvii % \end{macrocode} % If =\@lastchclass= is $4$ or $5$ nothing has to be done. % Class $6$ to $10$ are not possible. % So we finish the macro. % \begin{macrocode} \fi} % \end{macrocode} % \end{macro} % % \begin{macro}{\@classii} % \begin{macro}{\@classiii} % In the case of character classes $2$ and $3$ (i.e.\ the argument % of \texttt{<} or \texttt{>}) we only have to store the current % \textsf{token} (=\@nextchar=) into the corresponding % \textsf{token} register since the preparation and % insertion of these registers % are done by the macro =\@classz=. % This is equivalent to calling =\save@decl= in the case of % class $3$. To save command identifiers we do this call up % in the macro =\@mkpream=. % % Class $2$ exhibits a more complicated situation: the % \textsf{token} registers have already been inserted by % =\@classz=. So the value of =\count@= is too high % by one. Therefore we decrease =\count@= by $1$. % \begin{macrocode} \def\@classii{\advance \count@ \m@ne % \end{macrocode} % Next we store the current \textsf{token} into the correct % \textsf{token} register by calling =\save@decl= and then % increase the value of =\count@= again. At this point we % can save memory once more (at the cost of time) if we use the % macro =\prepnext@tok=. % \begin{macrocode} \save@decl\prepnext@tok} % \end{macrocode} % \end{macro} % \end{macro} % % % \begin{macro}{\@classv} % \emph{The code below has been replaced long time ago by an % extended version further down but the code and its documentation % was left here for reference. It is now commented out to avoid % confusion.} % % If the current \textsf{token} is of class $5$ then it is an % argument of a \texttt{@} \textsf{token}. It must be stored into a % \textsf{token} register. % \begin{macrocode} %\def\@classv{\save@decl % \end{macrocode} % We extend the preamble with a command which inserts this % \textsf{token} register into the preamble when its construction % is finished. The user expects that this argument is worked out in % math mode if it was used in an % \textsf{array}--environment. Therefore we surround it with % =\d@llar...='s. % \changes{v2.0c}{1990/08/14}{\cs{relax} added to avoid problem % `the`toks0`the`toks1.} % \begin{macrocode} % \@addtopreamble{\d@llarbegin\the@toks\the\count@\relax\d@llarend}% % \end{macrocode} % Finally we must prepare the next \textsf{token} register. % \begin{macrocode} % \prepnext@tok} % \end{macrocode} % \end{macro} % % \begin{macro}{\@classi} % In the case of class $0$ we were able to generate the necessary % space between columns by using the macro =\@classx=. % Analogously the macro =\@classvi= can be used for class $1$. % \begin{macrocode} \def\@classi{\@classvi % \end{macrocode} % Depending on =\@chnum= a vertical line % \begin{macrocode} \ifcase \@chnum \@arrayrule \or % \end{macrocode} % or (in case of =!{...}=) the current \textsf{token} --- stored % in =\@nextchar= --- has to be inserted into the preamble. % This corresponds to calling =\@classv=. % \begin{macrocode} \@classv \fi} % \end{macrocode} % \end{macro} % % % % \begin{macro}{\@startpbox} % In =\@classz= the macro =\@startpbox= is used. % The width of the \textsf{parbox} is passed as an argument. % =\vcenter=, =\vtop= or =\vbox= are already in the % preamble. So we start with the braces for the wanted box. % \changes{v2.4i}{2018/09/13}{Add group to prevent color leak (gh/72)} % \begin{macrocode} \def\@startpbox#1{\bgroup \color@begingroup % \end{macrocode} % The argument is the width of the box. This information has to be % assigned to =\hsize=. % Then we assign default values to several parameters used in a % \textsf{parbox}. % \changes{v2.3k}{1998/05/12}{Use \cs{setlength} to set \cs{hsize}, % so that the calc package can be applied here (pr/2793)} % \begin{macrocode} \setlength\hsize{#1}\@arrayparboxrestore % \end{macrocode} % Our main problem is to obtain the same distance between succeeding % lines of the \textsf{parbox}. % We have to remember that the distance between two \textsf{parboxes} % should be defined by =\@arstrut=. That means that it can be % greater than the distance in a \textsf{parbox}. % Therefore it is not enough to set a =\@arstrut= at the % beginning and at the end of the \textsf{parbox}. This would % dimension the distance % between first and second line and the distance between the two % last lines of the \textsf{parbox} wrongly. % To prevent this we set an invisible rule of height % =\@arstrutbox= % at the beginning of the \textsf{parbox}. This has no effect on the % depth of the first line. At the end of the \textsf{parbox} we set % analogously another invisible rule which only affects the depth % of the last line. It is necessary to wait inserting this strut % until the paragraph actually starts to allow for things like % =\parindent= changes via =>{...}=. % \changes{v2.1c}{1992/12/14}{Use `everypar to insert strut} % \begin{macrocode} \everypar{% \vrule \@height \ht\@arstrutbox \@width \z@ \everypar{}}% } % \end{macrocode} % \end{macro} % % \begin{macro}{\@endpbox} % If there are any declarations defined by =>{...}= % and =<{...}= % they now follow in the macro =\@classz= --- the contents % of the column in between. % So the macro =\@endpbox= must insert the \textsf{specialstrut} % mentioned earlier and then close the group opened by % =\@startpbox=. % \changes{v2.2d}{1994/05/16}{Use \LaTeXe \cs{@finalstrut}} % \changes{v2.3g}{1996/05/07}{Add \cs{hfil} for tools/2120} % \changes{v2.4i}{2018/09/13}{Add group to prevent color leak (gh/72)} % \changes{v2.5d}{2021/02/10}{Explicitly run \cs{par} at the end of pboxes} % \begin{macrocode} \def\@endpbox{\@finalstrut\@arstrutbox \par \color@endgroup \egroup\hfil} % \end{macrocode} % \end{macro} % % % \section{Building and calling \texttt{\textbackslash halign}} % % \begin{macro}{\@array} % After we have discussed the macros needed for the evaluation % of the user preamble we can define the macro =\@array= % which uses these macros to create a =\halign=. % It has two arguments. The first one is a position argument % which can be \texttt{t}, \texttt{b} or \texttt{c}; the % second one describes the wanted preamble, % e.g.\ it has the form =|c|c|c|=. % \begin{macrocode} \def\@array[#1]#2{ % \end{macrocode} % First we define a \textsf{strut} whose size basically corresponds % to a normal \textsf{strut} multiplied by the factor % =\arraystretch=. % This \textsf{strut} is then inserted into every row and enforces % a minimal distance between two rows. % Nevertheless, when using horizontal lines, large letters % (like accented capital letters) still collide with such lines. % Therefore at first we add to the height of a normal \textsf{strut} % the value of the parameter =\extrarowheight=. % \begin{macrocode} \@tempdima \ht \strutbox \advance \@tempdima by\extrarowheight \setbox \@arstrutbox \hbox{\vrule \@height \arraystretch \@tempdima \@depth \arraystretch \dp \strutbox \@width \z@}% % \end{macrocode} % The total number of table columns of the current table is % determined in \cs{tbl_count_table_cols:} but this is called in % a group, so local settings do not survive. Thus, to save away the % outer value of \cs{g_@@_table_cols_tl} we do it before the group. % \changes{v2.6a}{2023/12/11}{Support for tagged PDF} % \begin{macrocode} \tbl_save_outer_table_cols: % \end{macrocode} % Then we open a group, in which the user preamble is evaluated by % the macro =\@mkpream=. As we know this must happen locally. % This macro creates a preamble for a =\halign= and saves % its result globally in the control sequence =\@preamble=. % \begin{macrocode} \begingroup \@mkpream{#2}% % \end{macrocode} % Figure out how many columns this table has: % \changes{v2.6a}{2023/12/11}{Managing cell indexes} % \begin{macrocode} \tbl_count_table_cols: % \end{macrocode} % We again redefine =\@preamble= so that a call up of =\@preamble= % now starts the =\halign=. Thus also the arguments of \texttt{>}, % \texttt{<}, \texttt{@} and \texttt{!}, saved in the % \textsf{token} registers are inserted into the preamble. The % =\tabskip= at the beginning and end of the preamble is set to % \textsf{0pt} (in the beginning by the use of =\ialign=). Also the % command =\@arstrut= is build in, which inserts the % =\@arstrutbox=, defined above. Of course, the opening brace after % =\ialign= has to be implicit as it will be closed in =\endarray= % or another macro. % \changes{v2.3m}{1998/12/31}{Added \cs{noexpand} in front of \cs{ialign} % to guard against interesting :-) changes to \cs{halign} done to support % text glyphs in math} % % The =\noexpand= in front of =\ialign= does no harm in standard \LaTeX{} % and was added since some experimental support for using text glyphs in math % redefines =\halign= with the result that is becomes expandable with % disastrous results in cases like this. % In the kernel definition for this macro the problem does % not surface because there =\protect= is set (which is not necessary in this % implementation as there is no arbitrary user input that can get expanded) and % the experimental code made the redefinition robust. Whether this is the right % approach is open to question; consider the =\noexpand= a courtesy to allow an % unsupported redefinition of a \TeX{} primitive for the moment (as people rely % on that experimental code). % \begin{macrocode} \xdef\@preamble{ % \end{macrocode} % \cs{ialign} in the original definition is replaced by % \cs{ar@ialign} defined below. This does what \cs{ialign} does but % additionally handles the tagging structure for the whole table if necessary. % \changes{v2.6a}{2023/12/11}{Support for tagged PDF} % \begin{macrocode} \noexpand \ar@ialign \@halignto \bgroup \@arstrut % \end{macrocode} % What we have not explained yet is the macro =\@halignto= % that was just used. Depending on its replacement text the % =\halign= becomes a =\halign= \texttt{to} \meta{dimen}. % % Next, a tagging support socket is inserted adding the start row tag. % \changes{v2.6a}{2023/12/11}{Support for tagged PDF} % \begin{macrocode} \UseTaggingSocket{tbl/row/begin} % \end{macrocode} % At the start of the preamble for the first column we call % \cs{tbl_init_cell_data_for_row:} to initialize the cell index data. In % later columns this data is updated via \cs{tbl_update_cell_data:}. % \changes{v2.6a}{2023/12/11}{Managing cell indexes} % \begin{macrocode} \tbl_init_cell_data_for_row: % \end{macrocode} % % \begin{macrocode} \@preamble \tabskip \z@ \cr} % \end{macrocode} % Now we close the group again. Thus % =\@startpbox= and =\@endpbox= as well as all % \textsf{token} registers get their former meaning back. % \begin{macrocode} \endgroup % \end{macrocode} % To support the \texttt{delarray.sty} package we include a hook % into this part of the code which is a no-op in the main package. % \changes{v2.1a}{1992/07/03}{Hook for delarray added} % \begin{macrocode} \@arrayleft % \end{macrocode} % Now we decide depending on the position argument in which % \textsf{box} the =\halign= is to be put. (=\vcenter= may be used % because we are in math mode.) % \changes{v2.1a}{1992/07/03}{Wrong spec is now equiv to [t]} % \begin{macrocode} \if #1t\vtop \else \if#1b\vbox \else \vcenter \fi \fi % \end{macrocode} % Now another implicit opening brace appears; then definitions % which shall stay local follow. While constructing the % =\@preamble= in =\@mkpream= the =#= sign must be % hidden in the macro =\@sharp= which is =\let= to % =\relax= at that moment (see definition of =\@mkpream= % on page~\pageref{@mkpream}). % All these now get their actual meaning. % \begin{macrocode} \bgroup \let \@sharp ##\let \protect \relax % \end{macrocode} % With the above defined \textsf{struts} we fix down the distance % between rows by setting =\lineskip= and =\baselineskip= % to \textsf{0pt}. Since there have to be set =$='s % around every column in the \textsf{array}--environment % the parameter =\mathsurround= should % also be set to \textsf{0pt}. This prevents additional space between % the rows. % \begin{macrocode} \lineskip \z@ \baselineskip \z@ % \end{macrocode} % Don't use \cs{m@th} here as that signals to the math tagging % code that this is fake math that should not be tagged. % \changes{v2.6a}{2023/12/11}{Support for tagged PDF} % \begin{macrocode} \mathsurround \z@ % \end{macrocode} % Beside, we have to assign a special meaning (which we still have % to specify) to the line separator =\\=. We also have to % redefine the command =\par= in such a way that empty lines in % =\halign= cannot do any damage. We succeed in doing so % by choosing something that will disappear when expanding. % After that we only have to call up =\@preamble= to % start the wanted =\halign=. % \changes{1994/12/08}{v2.3b}{add \cs{tabularnewline}} % \begin{macrocode} \let\\\@arraycr \let\tabularnewline\\\let\par\@empty % \end{macrocode} % Another socket for tagging. TODO: what about \cs{arrayleft} above? % \begin{macrocode} \UseTaggingSocket{tbl/init} % \end{macrocode} % % \begin{macrocode} \@preamble } % \end{macrocode} % \end{macro} % % % % \begin{macro}{\ar@ialign} % A new command that replaces \cs{ialign} used previously. \cs{everycr} is % also applied to the \cs{cr} ending the preamble so we have to % program around that. % \changes{v2.6a}{2023/12/11}{Support for tagged PDF} % \begin{macrocode} \def\ar@ialign{% % \end{macrocode} % Before starting a table we have to initialize the variables % holding row and column information for cells. We also have % locally store the information related to the current cell (if we % are already inside a table) so that we can restore it once the % inner table is finished. % \changes{v2.6a}{2023/12/11}{Managing cell indexes} % \begin{macrocode} \tbl_init_cell_data_for_table: % \end{macrocode} % % \begin{macrocode} \everycr{% \noalign{% % \end{macrocode} % If this \cs{cr} was at the end of a real row (e.g., not at the % end of the table preamble) we have add a row end tag. % \begin{macrocode} \tbl_if_row_was_started:T { \UseTaggingSocket{tbl/row/end} } % \end{macrocode} % The we prepare for the next row. % \begin{macrocode} \tbl_update_cell_data_for_next_row: }% }% \tabskip\z@skip\halign} % \end{macrocode} % \end{macro} % % % % % % \begin{macro}{\arraybackslash} % \changes{v2.4a}{2003/12/17}{(DPC) Macro added (from tabularx)} % Restore =\\= for use in array and tabular environment (after % =\raggedright= etc.). % \begin{macrocode} \def\arraybackslash{\let\\\tabularnewline} % \end{macrocode} % \end{macro} % % \begin{macro}{\extrarowheight} % The \textsf{dimen} parameter used above also needs to be % allocated. As a default value we use \textsf{0pt}, to ensure % compatibility with standard \LaTeX. % \begin{macrocode} \newdimen \extrarowheight \extrarowheight=0pt % \end{macrocode} % \end{macro} % % \begin{macro}{\@arstrut} % Now the insertion of =\@arstrutbox= through =\@arstut= % is easy since we know exactly in which mode \TeX\ is while working % on the =\halign= preamble. % \begin{macrocode} \def\@arstrut{\unhcopy\@arstrutbox} % \end{macrocode} % \end{macro} % % % \section{The line separator \texttt{\textbackslash\textbackslash}} % % \begin{macro}{\@arraycr} % In the macro =\@array= the line separator =\\= is % =\let= to the command =\@arraycr=. % \changes{v2.3c}{1995/04/23}{Avoid adding an ord atom in math} % \changes{v2.5e}{2021/04/20}{Use \cs{protected} for \cs{\bslash} variant (gh/548)} % \begin{macrocode} \protected\def\@arraycr { % \end{macrocode} % Add code that figures out if the current table row is incomplete % (not enough \verb=&=s). It can then do extra actions, such as % inserting missing cell tags. % \changes{v2.6a}{2023/12/11}{Managing cell indexes} % \begin{macrocode} \tbl_count_missing_cells:n {@arraycr} % \end{macrocode} % TODO: maybe this is also the right place to add a socket that % could be used to actually enter missing cells instead of just % adding tagging structures for them later. This would be optional % but in many cases it would be the right thing to do (for example % if tables contain vertical lines or similar visual structures % that require fully specified rows. % % % We then start a special brace which I have directly % copied from the original definition. It is % necessary, because the =\futurelet= in =\@ifnextchar= % might % expand a following =&= \textsf{token} in a construction like % =\\ &=. This would otherwise end the alignment template at a % wrong time. On the other hand we have to be careful to avoid % producing a real group, i.e.\ ={}=, because the command will also % be used for the array environment, i.e.\ in math mode. In that % case an extra ={}= would produce an ord atom which could mess up % the spacing. For this reason we use a combination that does not % really produce a group at all but modifies the master counter so % that a =&= will not be considered belonging to the current % =\halign= while we are looking for a =*= or =[=. % For further information see % \cite[Appendix~D]{bk:knuth}. % \begin{macrocode} \iffalse{\fi\ifnum 0=`}\fi % \end{macrocode} % Then we test whether the user is using the star form and ignore % a possible star (I also disagree with this procedure, because a % star does not make any sense here). % \begin{macrocode} \@ifstar \@xarraycr \@xarraycr} % \end{macrocode} % \end{macro} % % \begin{macro}{\@xarraycr} % In the command =\@xarraycr= we test if an optional argument % exists. % \begin{macrocode} \def\@xarraycr{\@ifnextchar [% % \end{macrocode} % If it does, we branch out into the macro =\@argarraycr= if % not we close the special brace (mentioned above) and end the row % of the =\halign= with a =\cr=. % \changes{v2.3c}{1995/04/23}{Avoid adding an ord atom in math} % \begin{macrocode} \@argarraycr {\ifnum 0=`{}\fi\cr}} % \end{macrocode} % \end{macro} % % % \begin{macro}{\@argarraycr} % If additional space is requested by the user this case is treated % in the macro =\@argarraycr=. First we close the special brace % and then we test if the additional space is positive. % \changes{v2.3c}{1995/04/23}{Avoid adding an ord atom in math} % \begin{macrocode} \def\@argarraycr[#1]{\ifnum0=`{}\fi\ifdim #1>\z@ % \end{macrocode} % If this is the case we create an invisible vertical rule with % depth =\dp\@arstutbox=${}+{}$\meta{wanted\ space}. % Thus we achieve that all vertical lines specified % in the user preamble by a \texttt{|} are now % generally drawn. % Then the row ends with a =\cr=. % % If the space is negative we end the row at once with a =\cr= % and move back up with a =\vskip=. % % While testing these macros I found out that the % =\endtemplate= % created by =\cr= and =&= is something like an % =\outer= primitive and therefore it should not appear in % incomplete =\if= statements. Thus the following solution was % chosen which hides the =\cr= in other macros when \TeX\ % is skipping conditional text. % \changes{v2.3c}{1995/04/23}{Use \cs{expandafter}'s in conditional} % \begin{macrocode} \expandafter\@xargarraycr\else \expandafter\@yargarraycr\fi{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\@xargarraycr} % \begin{macro}{\@yargarraycr} % The following macros were already explained above. % \changes{v2.4e}{2016/10/07}{Fixing SX68732} % \begin{macrocode} \def\@xargarraycr#1{\unskip\gdef\do@row@strut {\@tempdima #1\advance\@tempdima \dp\@arstrutbox \vrule \@depth\@tempdima \@width\z@\global\let\do@row@strut\relax}% % \end{macrocode} % If the last column is a =\multicolumn= cell then we need to % insert the row strut now as it isn't inside the template (as that % got =\omit=ted). % \changes{v2.4h}{2018/04/30}{Fixing issue 42} % \begin{macrocode} \ifnum\@multicnt >\z@ \do@row@strut \fi \cr} \let\do@row@strut\relax % \end{macrocode} % % \cs{@yargarraycr} is the same as in the \LaTeX{} kernel % (depending on the date of the kernel with one of the two % definitions below). We therefore do not define it again. % \changes{v2.5b}{2020/04/22}{Don't define \cs{@yargarraycr} unnecessarily} % \begin{macrocode} %\def\@yargarraycr#1{\cr\noalign{\@vspace@calcify{#1}}} % 2020-10-01 %\def\@yargarraycr#1{\cr\noalign{\vskip #1}} % \end{macrocode} % \end{macro} % \end{macro} % % % % % \section{Spanning several columns} % % \begin{macro}{\multicolumn} % If several columns should be held together with a special format % the command =\multicolumn= must be used. It has three % arguments: the number of columns to be covered; the format for % the result column and the actual column entry. % \changes{v2.3j}{1998/01/29}{Command made \cs{long} to match % kernel change for pr/2180} % \changes{v2.6a}{2023/12/11}{Support for tagged PDF} % \begin{macrocode} \long\def\multicolumn#1#2#3{% % \end{macrocode} % First we combine the given number of columns into a single one; % then we start a new block so that the following definition is kept % local. % \begin{macrocode} \multispan{#1}\begingroup % \end{macrocode} % For tagging support we have to solve two problems: % \cs{multicolumn} must handle the row begin if it is used there, % and it must save the numbers of cells it spans so that we can add % a suitable ColSpan attribute. We do this in the next macro % (which in turn calls the \texttt{tbl/row/begin} socket, if % necessary). % \changes{v2.6a}{2023/12/11}{Managing cell indexes} % \begin{macrocode} \tbl_update_multicolumn_cell_data:n {#1} % \end{macrocode} % Since a =\multicolumn= should only describe the format of a % result column, we redefine =\@addamp= in such a way that one gets % an error message if one uses more than one \texttt{c}, % \texttt{l}, \texttt{r}, \texttt{p}, \texttt{m} or \texttt{b} in % the second argument. One should consider that this definition is % local to the build-up of the preamble; an \textsf{array}-- or % \textsf{tabular}--environment in the third argument of the % =\multicolumn= is therefore worked through correctly as well. % \begin{macrocode} \def\@addamp{\if@firstamp \@firstampfalse \else \@preamerr 5\fi}% % \end{macrocode} % Then we evaluate the second argument with the help of % =\@mkpream=. % Now we still have to insert the contents of the \textsf{token} % register into the =\@preamble=, i.e.\ we have to say % =\xdef\@preamble{\@preamble}=. This is achieved shorter by % writing: % \begin{macrocode} \@mkpream{#2}\@addtopreamble\@empty % \end{macrocode} % After the =\@preamble= is created we forget all local % definitions and occupations of the \textsf{token} registers. % \begin{macrocode} \endgroup % \end{macrocode} % Now we update the colspan attribute. This needs setting after % the group as it is hidden inside the plug in \cs{insert@column}. % \changes{v2.6a}{2023/12/11}{Support for tagged PDF} % \begin{macrocode} \UseTaggingSocket{tbl/colspan}{#1}% % \end{macrocode} % In the special situation of =\multicolumn= =\@preamble= % is not needed as preamble for a =\halign= but it is directly % inserted into our table. Thus instead of =\sharp= % there has to be the column entry (=#3=) wanted by the user. % \begin{macrocode} \def\@sharp{#3}% % \end{macrocode} % Now we can pass the =\@preamble= to \TeX\ . For safety % we start with an =\@arstrut=. This should usually be in the % template for the first column however we do not know if this % template was overwritten by our =\multicolumn=. % We also add a =\null= at the right end to prevent any following % =\unskip= (for example from =\\[..]=) to remove the =\tabcolsep=. % \changes{v2.2e}{1994/06/01}{Added \cs{null}} % \begin{macrocode} \@arstrut \@preamble \null \ignorespaces} % \end{macrocode} % \end{macro} % % % % \section{The Environment Definitions} % % After these preparations we are able to define the environments. They % only differ in the initializations of =\d@llar...=, =\col@sep= % and =\@halignto=. % % \begin{macro}{\@halignto} % \begin{macro}{\d@llarbegin} % \begin{macro}{\d@llarend} % =\d@llar= has to be % locally assigned since otherwise nested \textsf{tabular} and \textsf{array} % environments (via =\multicolumn=) are impossible. % For 25 years or so =\@halignto= was set globally (to save space on the % save stack, but that was a mistake: if there is a tabular in the % output routine (e.g., in the running header) then that tabular is % able overwrite the =\@halignto= % setting of a tabular in the main text resulting in a very weird error. % \changes{v2.4d}{2016/10/06}{\cs{@halignto} set locally (pr/4488)} % \changes{v2.0g}{1992/06/18}{`d@llarbegin defined on top-level.} % When the new font selection scheme is in force we have to % we surround all =\halign= entries % with braces. See remarks in TUGboat 10\#2. Actually we are going % to use =\begingroup= and =\endgroup=. However, this is only % necessary when we are in text mode. In math the surrounding % dollar signs will already serve as the necessary extra grouping % level. Therefore we switch the settings of =\d@llarbegin= and % =\d@llarend= between groups and dollar signs. % \begin{macrocode} \let\d@llarbegin\begingroup \let\d@llarend\endgroup % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % % \begin{macro}{\array} % Our new definition of =\array= then reads: % \changes{v2.0d}{1990/08/20}{`d@llar local to preamble.} % \changes{v2.4d}{2016/10/06}{\cs{@halignto} set locally (pr/4488)} % \begin{macrocode} \def\array{\col@sep\arraycolsep \def\d@llarbegin{$}\let\d@llarend\d@llarbegin\def\@halignto{}% % \end{macrocode} % Since there might be an optional argument we call another % macro which is also used by the other environments. % \begin{macrocode} \@tabarray} % \end{macrocode} % \end{macro} % % \begin{macro}{\@tabarray} % \emph{The code below has been replaced long time ago by an % extended version further down but the code and its documentation % was left here for reference. It is now commented out to avoid % confusion.} % % This macro tests for a optional bracket and then calls up % =\@array= or =\@array[c]= (as default). % \begin{macrocode} %\def\@tabarray{\@ifnextchar[{\@array}{\@array[c]}} % \end{macrocode} % \end{macro} % % % \begin{macro}{\tabular} % \begin{macro}{\tabular*} % The environments \textsf{tabular} and \textsf{tabular$*$} differ % only in the initialization of the command =\@halignto=. Therefore % we define % \changes{v2.4d}{2016/10/06}{\cs{@halignto} set locally (pr/4488)} % \begin{macrocode} \def\tabular{\def\@halignto{}\@tabular} % \end{macrocode} % and analogously for the star form. We evaluate the argument first % using =\setlength= so that users of the \texttt{calc} package can % write code like\\ =\begin{tabular*}{(\columnwidth-1cm)/2}...= % \changes{v2.3l}{1998/05/13}{Use \cs{setlength} evaluate arg % so that the calc package can be applied here (pr/2793)} % \changes{v2.4d}{2016/10/06}{\cs{@halignto} set locally (pr/4488)} % \begin{macrocode} \expandafter\def\csname tabular*\endcsname#1{% \setlength\dimen@{#1}% \edef\@halignto{to\the\dimen@}\@tabular} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\@tabular} % The rest of the job is carried out by the =\@tabular= macro: % \begin{macrocode} \def\@tabular{% % \end{macrocode} % First of all we have to make sure that we start out in % \textsf{hmode}. Otherwise we might find our table dangling by % itself on a line. % \begin{macrocode} \leavevmode % \end{macrocode} % Now that we know we are in hmode we can add the start tag for the % whole table. % \changes{v2.6a}{2023/12/11}{Support for tagged PDF} % \begin{macrocode} \UseTaggingSocket{tbl/hmode/begin}% % \end{macrocode} % It should be taken into consideration that the macro =\@array= % must be called in math mode. Therefore we open a \textsf{box}, % insert a =$= and then assign the correct values to =\col@sep= and % =\d@llar...=. % \changes{v2.0d}{1990/08/20}{`d@llar local to preamble.} % \begin{macrocode} \hbox \bgroup $\col@sep\tabcolsep \let\d@llarbegin\begingroup \let\d@llarend\endgroup % \end{macrocode} % Now everything \textsf{tabular} specific is done and we are able to % call the =\@tabarray= macro. % \begin{macrocode} \@tabarray} % \end{macrocode} % \end{macro} % % \begin{macro}{\endarray} % \emph{The code below has been replaced long time ago by an % extended version further down but the code and its documentation % was left here for reference. It is now commented out to avoid % confusion.} % % When the processing of \textsf{array} is finished we have to % close the =\halign= % and afterwards the surrounding \textsf{box} selected by % =\@array=. To save \textsf{token} space we then redefine % =\@preamble= % because its replacement text isn't longer needed. % % To handle cell indexes, we do not use \cs{crcr} but a variant % that also handles missing cells as necessary. % \changes{v2.6a}{2023/12/11}{Support for tagged PDF} % \begin{macrocode} \def\endarray { \tbl_crcr:n{endarray} \egroup \UseTaggingSocket{tbl/finalize} % \end{macrocode} % % If tables are nested into another then it is necessary to % restore information about the cell the inner table started % in. Otherwise, the cell index data structures reflect the % status in the outer table as they % are globally manipulated. We restore in all cases even if we are % not in a nesting situation as that makes the code simpler (and % probably faster). % % \cs{endtabular} and \cs{endtabular*} inherit from \cs{endarray} % so we only need to change that. \texttt{tabularx} uses a similar method. % \changes{v2.6a}{2023/12/11}{Managing cell indexes} % \begin{macrocode} \tbl_restore_outer_cell_data: % \end{macrocode} % % \begin{macrocode} \egroup \@arrayright \gdef\@preamble{}% } % \end{macrocode} % \end{macro} % % % % % \begin{macro}{\endtabular} % \begin{macro}{\endtabular*} % To end a \textsf{tabular} or \textsf{tabular$*$} environment we % call up =\endarray=, close the math mode and then the surrounding % =\hbox=. This math mode around the tabular should not be surrounded by % any =\mathsurround= so we cancel that with =\m@th=. % \changes{v2.5f}{2021/07/12}{Cancel any outside \cs{mathsurround} (gh/614)} % \begin{macrocode} \def\endtabular{\endarray\m@th $\egroup % \end{macrocode} % % \changes{v2.6a}{2023/12/11}{Support for tagged PDF} % \begin{macrocode} \UseTaggingSocket{tbl/hmode/end}% } \expandafter\let\csname endtabular*\endcsname=\endtabular % \end{macrocode} % \end{macro} % \end{macro} % % % % \section{Last minute definitions} % % % If this file is used as a package file we should =\let= all macros % to =\relax= that were used in the original but are no longer % necessary. % \begin{macrocode} \let\@ampacol=\relax \let\@expast=\relax \let\@arrayclassiv=\relax \let\@arrayclassz=\relax \let\@tabclassiv=\relax \let\@tabclassz=\relax \let\@arrayacol=\relax \let\@tabacol=\relax \let\@tabularcr=\relax \let\@@@@endpbox=\relax \let\@argtabularcr=\relax \let\@xtabularcr=\relax % \end{macrocode} % % \begin{macro}{\@preamerr} % \changes{v2.6d}{2024/06/14}{Keep message sources out of L3 code (gh/1378)} % We also have to redefine the error routine =\@preamerr= since % new kind of errors are possible. % The code for this macro is not perfect yet; % it still needs too much memory. % \begin{macrocode} \ExplSyntaxOff \def\@preamerr#1{\def\@tempd{{..} at wrong position: }% \PackageError{array}{% \ifcase #1 Illegal pream-token (\@nextchar): `c' used\or %0 Missing arg: token ignored\or %1 Empty preamble: `l' used\or %2 >\@tempd token ignored\or %3 <\@tempd changed to !{..}\or %4 Only one column-spec. allowed.\fi}\@ehc} %5 % \end{macrocode} % \end{macro} % % % % \section % [Defining your own column specifiers] % {Defining your own column specifiers\footnotemark} % % \footnotetext{The code and the documentation in this section was % written by David. So far only the code from newarray was plugged % into array so that some parts of the documentation still claim % that this is newarray and even worse, some parts of the code are % unnecessarily doubled. This will go away in a future release. For % the moment we thought it would be more important to bring both % packages together.} % \changes{v2.1a}{1992/07/03}{Newcolumn stuff added} % % \DeleteShortVerb{\=} % \MakeShortVerb{\"} % % \begin{macro}{\newcolumn} % In \texttt{newarray.sty} the macro for specifying new columns was % named "\newcolumn". When the functionality was added to % \texttt{array.sty} the command was renamed "\newcolumntype". % Initially both names were supported, but now (In versions of this % package distributed for \LaTeXe) the old name is not defined. % \changes{v2.2a}{1994/02/03}{Now made `newcolumn an error} % \changes{v2.2a}{1994/02/04}{Removed `newcolumn} % \begin{macrocode} %<*ncols> % \end{macrocode} % \end{macro} % % \begin{macro}{\newcolumntype} % \changes{v2.1b}{1992/06/07}{Macro renamed from `newcolumn} As % described above, the "\newcolumntype" macro gives users the chance % to define letters, to be used in the same way as the primitive % column specifiers, `c' `p' etc. % \begin{macrocode} \def\newcolumntype#1{% % \end{macrocode} % "\NC@char" was added in V2.01 so that active characters, like "@" in % AMS\LaTeX\ may be used. This trick was stolen from \texttt{array.sty} % 2.0h. Note that we need to use the possibly active token, % "#1", in several places, as that is the token that actually % appears in the preamble argument. % \begin{macrocode} \edef\NC@char{\string#1}% % \end{macrocode} % First we check whether there is already a definition for this column. % Unlike "\newcommand" we give a warning rather than an error if it is % defined. If it is a new column, add "\NC@do" \meta{column} to % the list "\NC@list". % \begin{macrocode} \@ifundefined{NC@find@\NC@char}% {\@tfor\next:=<>clrmbp@!|\do {% % \end{macrocode} % We use \cs{noexpand} on the tokens from the list in case one or % the other (typically \texttt{@}, \texttt{!} or \texttt{|}) has % been made active. % \changes{v2.4l}{2019/08/31}{Add a necessary \cs{expandafter} (github/148)} % \begin{macrocode} \if\expandafter\noexpand\next\NC@char \PackageWarning{array}% {Redefining primitive column \NC@char}\fi}% \NC@list\expandafter{\the\NC@list\NC@do#1}}% {\PackageWarning{array}{Column \NC@char\space is already defined}}% % \end{macrocode} % Now we define a macro with an argument delimited by the new column % specifier, this is used to find occurrences of this specifier in the % user preamble. % \begin{macrocode} \@namedef{NC@find@\NC@char}##1#1{\NC@{##1}}% % \end{macrocode} % If an optional argument was not given, give a default argument of 0. % \begin{macrocode} \@ifnextchar[{\newcol@{\NC@char}}{\newcol@{\NC@char}[0]}} \ExplSyntaxOn % \end{macrocode} % \end{macro} % \begin{macro}{\newcol@} % We can now define the macro which does the rewriting, % "\@reargdef" takes the same arguments as "\newcommand", but % does not check that the command is new. For a column, say `D' with % one argument, define a command "\NC@rewrite@D" with one % argument, which recursively calls "\NC@find" on the user preamble % after replacing the first token or group with the replacement text % specified in the "\newcolumntype" command. "\NC@find" will find the % next occurrence of `D' as it will be "\let" equal to % "\NC@find@D" by "\NC@do". % \begin{macrocode} \def\newcol@#1[#2]#3{\expandafter\@reargdef \csname NC@rewrite@#1\endcsname[#2]{\NC@find#3}} % \end{macrocode} % \end{macro} % \begin{macro}{\NC@} % Having found an occurrence of the new column, save the preamble % before the column in "\@temptokena", then check to see if we % are at the end of the preamble. (A dummy occurrence of the column % specifier will be placed at the end of the preamble by "\NC@do". % \begin{macrocode} \def\NC@#1{% \@temptokena\expandafter{\the\@temptokena#1}\futurelet\next\NC@ifend} % \end{macrocode} % \end{macro} % \begin{macro}{\NC@ifend} % We can tell that we are at the end as "\NC@do" will place a "\relax" % after the dummy column. % \begin{macrocode} \def\NC@ifend{% % \end{macrocode} % If we are at the end, do nothing. (The whole preamble will now be in % "\@temptokena".) % \begin{macrocode} \ifx\next\relax % \end{macrocode} % Otherwise set the flag "\if@tempswa", and rewrite the column. % "\expandafter" introduced 1n V2.01 % \begin{macrocode} \else\@tempswatrue\expandafter\NC@rewrite\fi} % \end{macrocode} % \end{macro} % \begin{macro}{\NC@do} % If the user has specified `C' and `L' as new columns, the list of % rewrites (in the token register "\NC@list") will look like % "\NC@do *" "\NC@do C" "\NC@do L". % So we need to define "\NC@do" as a one argument macro which % initializes the rewriting of the specified column. Let us assume that % `C' is the argument. % \begin{macrocode} \def\NC@do#1{% % \end{macrocode} % First we let "\NC@rewrite" and "\NC@find" be % "\NC@rewrite@C" and "\NC@find@C" respectively. % \begin{macrocode} \expandafter\let\expandafter\NC@rewrite \csname NC@rewrite@\string#1\endcsname \expandafter\let\expandafter\NC@find \csname NC@find@\string#1\endcsname % \end{macrocode} % Clear the token register "\@temptokena" after putting the present % contents of the register in front of the token "\NC@find". At the % end we place the tokens `"C\relax"' which "\NC@ifend" will use % to detect the end of the user preamble. % \begin{macrocode} \expandafter\@temptokena\expandafter{\expandafter}% \expandafter\NC@find\the\@temptokena#1\relax} % \end{macrocode} % \end{macro} % % \begin{macro}{\showcols} % This macro is useful for debugging "\newcolumntype" specifications, % it is the equivalent of the primitive "\show" command for macro % definitions. All we need to do is locally redefine "\NC@do" to take % its argument (say `C') and then "\show" the (slightly modified) % definition of "\NC@rewrite@C". Actually as the list always % starts off with "\NC@do *" and we do not want to print the % definition of the $*$-form, define "\NC@do" to throw away the first % item in the list, and then redefine itself to print the rest of the % definitions. % \begin{macrocode} \def\showcols{{\def\NC@do##1{\let\NC@do\NC@show}\the\NC@list}} % \end{macrocode} % \end{macro} % \begin{macro}{\NC@show} % If the column `C' is defined as above, then % "\show\NC@rewrite@C" would output\\ % "\long macro: ->\NC@find >{$}c<{$}". % We want to strip the "long macro: ->" and the "\NC@find". So first we % use "\meaning" and then apply the macro "\NC@strip" to the tokens so % produced and then "\typeout" the required string. % \begin{macrocode} \def\NC@show#1{% \typeout{Column~ #1\expandafter\expandafter\expandafter\NC@strip \expandafter\meaning\csname NC@rewrite@#1\endcsname\@@@@}} % \end{macrocode} % \end{macro} % \begin{macro}{\NC@strip} % Delimit the arguments to "\NC@strip" with `\texttt{:}', `\texttt{->}', % a space, and "\@@@@" to pull out the required parts of the output from % "\meaning". % \begin{macrocode} \ExplSyntaxOff \def\NC@strip#1:#2->#3 #4\@@@@{#2 -> #4} \ExplSyntaxOn % \end{macrocode} % \end{macro} % \begin{macro}{\NC@list} % Allocate the token register used for the rewrite list. % \begin{macrocode} \newtoks\NC@list % \end{macrocode} % \end{macro} % % \subsection{The $*$--form} % We view the $*$-form as a slight generalization of the system % described in the previous subsection. The idea is to define a $*$ % column by a command of the form: % \begin{verbatim} % \newcolumntype{*}[2]{% % \count@=#1\ifnum\count@>0 % \advance\count@ by -1 #2*{\count@}{#2}\fi} % \end{verbatim} % \begin{macro}{\NC@rewrite@*}\label{NC@rewrite@*} % \changes{v2.4b}{2005/08/23}{Fix occasional spurious space (PR/3755)} % This does not work however as "\newcolumntype" takes great care not % to expand anything in the preamble, and so the "\if" is never % expanded. "\newcolumntype" sets up various other parts of the % rewrite correctly though so we can define: % \begin{macrocode} \newcolumntype{*}[2]{} % \end{macrocode} % Now we must correct the definition of "\NC@rewrite@*". The % following is probably more efficient than a direct translation of % the idea sketched above, we do not need to put a $*$ in the preamble % and call the rewrite recursively, we can just put "#1" copies of % "#2" into "\@temptokena". (Nested $*$ forms will be expanded % when the whole rewrite list is expanded again, see "\@mkpream") % \begin{macrocode} \long\@namedef{NC@rewrite@*}#1#2{% % \end{macrocode} % Store the number. % \begin{macrocode} \count@#1\relax % \end{macrocode} % Put "#1" copies of "#2" in the token register. % \begin{macrocode} \loop \ifnum\count@>\z@ \advance\count@\m@ne \@temptokena\expandafter{\the\@temptokena#2}% \repeat % \end{macrocode} % "\NC@do" will ensure that "\NC@find" is "\let" equal % to "\NC@find@*". % \begin{macrocode} \NC@find} % \end{macrocode} % \end{macro} % % \subsection{Modifications to internal macros of \texttt{array.sty}} % % \begin{macro}{\@xexpast} % \begin{macro}{\@xexnoop} % These macros are used to expand $*$-forms in % \texttt{array.sty}. "\let" them to "\relax" to save space. % \begin{macrocode} \let\@xexpast\relax \let\@xexnoop\relax % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\save@decl} % We do not assume that the token register is free, we add the new % declarations to the front of the register. This is to allow user % preambles of the form, ">{foo}>{bar}..". Users are not encouraged to % enter such expressions directly, but they may result from the % rewriting of "\newcolumntype"'s. % \begin{macrocode} \def\save@decl{\toks \count@ = \expandafter\expandafter\expandafter {\expandafter\@nextchar\the\toks\count@}} % \end{macrocode} % \end{macro} % % \begin{macro}{\@mkpream} % The main modification to "\@mkpream" is to replace the call to % "\@xexpast" (which expanded $*$-forms) by a loop which expands % all "\newcolumntype" specifiers. % \changes{v2.4e}{2016/10/07}{Fixing SX68732} % \changes{v2.4f}{2017/11/04}{Managing m-cells without \cs{vcenter}} % \begin{macrocode} \ExplSyntaxOff % really oldstyle using \@tfor := \def\@mkpream#1{\gdef\@preamble{}\@lastchclass 4 \@firstamptrue \let\@sharp\relax % \end{macrocode} % % \changes{v2.4j}{2018/11/13}{Do not expand argument of % \cs{@startpbox} while building the tabular preamble (sx/459285)} % The "\@startpbox" (which is called for "p", "m" or "b" columns) % receives a user supplied argument: the width of the % paragraph-column. Normally that is something harmless like a length or a % simple length expression, but with the calc package involved it % could break under an "\edef" operation, which is how the preamble % is constructed. We now make use of "\unexpanded" here to prevent that. The % "\expandafter" gymnastics is necessary to expand the "#1" at least % once (since it will get "\@nextchar" as its value and need its % content! % \begin{macrocode} \def\@startpbox##1{\unexpanded\expandafter{\expandafter \@startpbox\expandafter{##1}}}\let\@endpbox\relax \let\do@row@strut\relax \let\ar@align@mcell\relax % \end{macrocode} % Now we remove possible $*$-forms and user-defined column % specifiers in the user preamble by repeatedly executing the list % "\NC@list" until the re-writes have no more effect. The % expanded preamble will then be in the token register % "\@temptokena". Actually we need to know at this point that % this is not "\toks0". % \begin{macrocode} \@temptokena{#1}\@tempswatrue \@whilesw\if@tempswa\fi{\@tempswafalse\the\NC@list}% % \end{macrocode} % Afterwards we initialize all registers and macros, that we need % for the build-up of the preamble. % \begin{macrocode} \count@\m@ne \let\the@toks\relax \prepnext@tok % \end{macrocode} % Having expanded all tokens defined using "\newcolumntype" (including % "*"), we evaluate the remaining tokens, which are saved in % "\@temptokena". We use the \LaTeX--macro "\@tfor" to inspect each % token in turn. % \begin{macrocode} \expandafter \@tfor \expandafter \@nextchar \expandafter :\expandafter =\the\@temptokena \do % \end{macrocode} % "\@testpatch" does not take an argument since \texttt{array.sty} 2.0h. % \begin{macrocode} {\@testpach \ifcase \@chclass \@classz \or \@classi \or \@classii \or \save@decl \or \or \@classv \or \@classvi \or \@classvii \or \@classviii % \end{macrocode} % In \texttt{newarray.sty} class 9 is equivalent to class 10. % \begin{macrocode} \or \@classx \or \@classx \fi \@lastchclass\@chclass}% \ifcase\@lastchclass \@acol \or \or \@acol \or \@preamerr \thr@@@@ \or \@preamerr \tw@ \@addtopreamble\@sharp \or \or \else \@preamerr \@ne \fi \def\the@toks{\the\toks}} \ExplSyntaxOn % \end{macrocode} % \end{macro} % % \begin{macro}{\@classix} % \texttt{array.sty} does not allow repeated \texttt{>} % declarations for the same column. This is allowed in % \texttt{newarray.sty} as documented in the introduction. Removing % the test for this case makes class 9 equivalent to class 10, and % so this macro is redundant. It is "\let" to "\relax" to save % space. % \begin{macrocode} \let\@classix\relax % \end{macrocode} % \end{macro} % % \begin{macro}{\@classviii} % In \texttt{newarray.sty} explicitly allow class 2, as repeated % \texttt{<} expressions are accepted by this package. % \begin{macrocode} \def\@classviii{\ifnum \@lastchclass >\z@\ifnum\@lastchclass=\tw@\else \@preamerr 4\@chclass 6 \@classvi \fi\fi} % \end{macrocode} % \end{macro} % % \begin{macro}{\@classv} % Class 5 is \texttt{@}-expressions (and is also called by class 1) % This macro was incorrect in Version~1. Now we do not expand the % "@"-expression, but instead explicitly replace an % "\extracolsep" command by an assignment to "\tabskip" by a % method similar to the "\newcolumntype" system described above. % "\d@llarbegin" "\d@llarend" were introduced in V2.01 to match % \texttt{array.sty} 2.0h. % \begin{macrocode} \def\@classv{\save@decl \expandafter\NC@ecs\@nextchar\extracolsep{}\extracolsep\@@@@@@ \@addtopreamble{\d@llarbegin\the@toks\the\count@\relax\d@llarend}% \prepnext@tok} % \end{macrocode} % \end{macro} % % \begin{macro}{\NC@ecs} % Rewrite the first occurrence of "\extracolsep{1in}" to % "\tabskip1in\relax". As a side effect discard any tokens after a % second "\extracolsep", there is no point in the user entering two of % these commands anyway, so this is not really a restriction. % \begin{macrocode} \def\NC@ecs#1\extracolsep#2#3\extracolsep#4\@@@@@@{\def\@tempa{#2}% \ifx\@tempa\@empty\else\toks\count@={#1\tabskip#2\relax#3}\fi} % % \end{macrocode} % \end{macro} % % % \subsection{Support for the \texttt{delarray.sty}} % % The \texttt{delarray.sty} package extends the array syntax by % supporting the notation of delimiters. To this end we extend the % array parsing mechanism to include a hook which can be used by this % (or another) package to do some additional parsing. % % \begin{macro}{\@tabarray} % This macro tests for an optional bracket and then calls up % "\@@@@array" or "\@@@@array[c]" (as default). % \begin{macrocode} %<*package> \def\@tabarray{\@ifnextchar[{\@@@@array}{\@@@@array[c]}} % \end{macrocode} % \end{macro} % \begin{macro}{\@@@@array} % This macro tests could then test an optional delimiter before the % left brace of the main preamble argument. Here in the main package % it simply is let to be "\@array". % \begin{macrocode} \let\@@@@array\@array % \end{macrocode} % \end{macro} % % \begin{macro}{\@arrrayleft} % \begin{macro}{\@arrayright} % We have to declare the hook we put into "\@array" above. % A similar hook \cs{@arrayright} will be inserted into the % "\endarray" to gain control. Both defaults to empty. % \begin{macrocode} \let\@arrayleft\@empty \let\@arrayright\@empty % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Support for \texttt{\textbackslash firsthline} and % \texttt{\textbackslash lasthline}} % % The Companion~\cite[p.137]{bk:GMS94} suggests two additional % commands to control the alignments in case of tabulars with % horizontal lines. They are now added to this package. % % \begin{macro}{\extratabsurround} % The extra space around a table when "\firsthline" or "\lasthline" % are used. % \begin{macrocode} \newlength{\extratabsurround} \setlength{\extratabsurround}{2pt} % \end{macrocode} % \end{macro} % % \begin{macro}{\backup@length} % This register will be used internally by "\firsthline" and % "\lasthline". % \begin{macrocode} \newlength{\backup@length} % \end{macrocode} % \end{macro} % % \begin{macro}{\firsthline} % \changes{v2.3h}{1996/05/25}{Complete reimplementation} % This code can probably be improved but for the moment it should % serve. % % We start by producing a single tabular row without any visible % content that will produce the external reference point in case % "[t]" is used. We need to suppress the \cs{tabcolsep} in the % \cs{multicolumn} in case there wasn't any in the real column. % % \changes{v2.5c}{2020/07/20}{Suppress all column space (gh/322)} % \begin{macrocode} \newcommand{\firsthline}{% \multicolumn1{@{}c@{}}{% % \end{macrocode} % Within this row we calculate "\backup@length" to be the height % plus depth of a standard line. In addition we have to add the % width of the "\hline", something that was forgotten in the % original definition. % \begin{macrocode} \global\backup@length\ht\@arstrutbox \global\advance\backup@length\dp\@arstrutbox \global\advance\backup@length\arrayrulewidth % \end{macrocode} % Finally we do want to make the height of this first line be a bit % larger than usual, for this we place the standard array strut % into it but raised by "\extratabsurround" % \begin{macrocode} \raise\extratabsurround\copy\@arstrutbox % \end{macrocode} % And we should also cancel the guard otherwise we end up with two. % \begin{macrocode} \kern-1sp% % \end{macrocode} % Having done all this we end the line and back up by the value of % "\backup@length" and then finally place our "\hline". This should % place the line exactly at the right place but keep the reference % point of the whole tabular at the baseline of the first row. % \begin{macrocode} }\\[-\backup@length]\hline } % \end{macrocode} % \end{macro} % % \begin{macro}{\lasthline} % \changes{v2.3h}{1996/05/25}{Complete reimplementation} % For "\lasthline" the situation is even worse and I got it % completely wrong initially. % % The problem in this case is that if the optional argument "[b]" % is used we do want the reference point of the tabular be at the % baseline of the last row but at the same time do want the % depth of this last line increased by "\extratabsurround" without % changing the placement "\hline". % % We start by placing the rule followed by an invisible row. We % need to suppress the \cs{tabcolsep} in the multicol in case there % wasn't any in the real column. % \changes{v2.5c}{2020/07/20}{Suppress all column space (gh/322)} % \begin{macrocode} \newcommand{\lasthline}{\hline\multicolumn1{@{}c@{}}{% % \end{macrocode} % We now calculate "\backup@length" to be the height and depth of % two lines plus the width of the rule. % \begin{macrocode} \global\backup@length2\ht\@arstrutbox \global\advance\backup@length2\dp\@arstrutbox \global\advance\backup@length\arrayrulewidth % \end{macrocode} % This will bring us back to the baseline of the second last row: % \begin{macrocode} }\\[-\backup@length]% % \end{macrocode} % Thus if we now add another invisible row the reference point of % that row will be at the baseline of the last row (and will be the % reference for the whole tabular). Since this row is invisible we % can enlarge its depth by the desired amount. % \begin{macrocode} \multicolumn1{@{}c@{}}{% \lower\extratabsurround\copy\@arstrutbox \kern-1sp% }% } % \end{macrocode} % \end{macro} % % % \subsection{Getting the spacing around rules right} % % Beside a larger functionality \texttt{array.sty} has one % important difference to the standard \texttt{tabular} and % \texttt{array} environments: horizontal and vertical rules make a % table larger or wider, e.g., \verb=\doublerulesep= really denotes % the space between two rules and isn't measured from the middle of % the rules. % % \begin{macro}{\@xhline} % For vertical rules this is implemented by the definitions above, % for horizontal rules we have to take out the backspace. % \changes{v2.3d}{1995/11/19}{fix space between double rules pr/1945} % \begin{macrocode} \CheckCommand*\@xhline{\ifx\reserved@a\hline \vskip\doublerulesep \vskip-\arrayrulewidth \fi \ifnum0=`{\fi}} \renewcommand*\@xhline{\ifx\reserved@a\hline \vskip\doublerulesep \fi \ifnum0=`{\fi}} % % \end{macrocode} % \end{macro} % \subsection{Implementing column types \texttt{w} and \texttt{W}} % % In TugBoat 38/2 an extension was presented that implemented two % additional column types \texttt{w} and \texttt{W}. These have now % been added to the package itself. % % % \begin{macro}{\ar@cellbox} % For \texttt{w} and \texttt{W} column types we need a box to % temporarily hold the cell content. % \changes{v2.4f}{2017/11/07}{Macro added} % \begin{macrocode} \newsavebox\ar@cellbox % \end{macrocode} % \end{macro} % % % \begin{macro}{\newcolumntype w} % The \texttt{w} column type has two arguments: the first holds the % alignment which is either "l", "c", or "r" and the second is the % nominal width of the column. % \changes{v2.4f}{2017/11/07}{Column type added} % \changes{v2.5a}{2020/04/06}{Use \cs{d@llarbegin} and \cs{d@llarend} so % that cell is typeset in math mode inside \texttt{array} (gh/297)} % \begin{macrocode} \newcolumntype{w}[2]{% % \end{macrocode} % Before the cell content we start an "lrbox"-environment to % collect the cell material into the previously allocated box % "\ar@cellbox". We add \cs{d@llarbegin} (and later \cs{d@llarend}) % so that the content is typeset in math mode if we are in an % \texttt{array} environment. % \begin{macrocode} >{\begin{lrbox}\ar@cellbox\d@llarbegin}% % \end{macrocode} % Then comes a specifier for the cell content. We use "c", but % that doesn't matter as in the end we will always put a box of a % specific width ("#2") into the cells of that column, so "l" or % "r" would give the same result. There is only a difference if % there are also very wide "\multicolumn" rows overwriting the % setting in which case "c" seems to be slightly better. % \begin{macrocode} c% % \end{macrocode} % At the end of the cell we end the "lrbox" environment so that all % of the cell content is now in box "\ar@cellbox". As a final step we % put that box into a "\makebox" using the optional arguments of % that command to achieve the correct width and the desired % alignment within that width. We unbox the collected material so % that any stretchable glue inside can interact with the alignment. % \changes{v2.4m}{2020/02/10}{Unbox collected material so that % stretchable glue inside can act (gh/270)} % \begin{macrocode} <{\d@llarend \end{lrbox}% \makebox[#2][#1]{\unhbox\ar@cellbox}}} % \end{macrocode} % \end{macro} % % % \begin{macro}{\newcolumntype W} % The \texttt{W} is similar but in this case we want a warning if % the cell content is too wide. % \changes{v2.4f}{2017/11/07}{Column type added} % \changes{v2.5a}{2020/04/06}{Use \cs{d@llarbegin} and \cs{d@llarend} so % that cell is typeset in math mode inside \texttt{array} (gh/297)} % \begin{macrocode} \newcolumntype{W}[2] {>{\begin{lrbox}\ar@cellbox\d@llarbegin}% c% <{\d@llarend\end{lrbox}% \let\hss\hfil \makebox[#2][#1]{\unhbox\ar@cellbox}}} % \end{macrocode} % This is a bit sneaky, as it temporarily disables "\hss", but % given that we know what goes into that box it should be % sufficient. % \end{macro} % % % \subsection{Handling \cs{cline}} % % In the past \pkg{array} did not have to concern itself with % \cs{cline} but simply used the definition already provided in the % kernel. However, for tagged PDF output this definition is % insufficient, because it causes incorrect row counting and the rules % it generates would need to be marked as artifacts. % We therefore update it here. % % % \begin{macro}{\@cline} % Tagging support for \cs{cline} % \changes{v2.6e}{2024/07/13}{Support for tagging \cs{cline} (tagging/134)} % \begin{macrocode} \ExplSyntaxOn \def\@cline#1-#2\@nil{ \omit \@multicnt#1 \advance\@multispan\m@ne \ifnum\@multicnt=\@ne\@firstofone{&\omit}\fi \@multicnt#2 \advance\@multicnt-#1 \advance\@multispan\@ne % \end{macrocode} % The rule needs artifact tagging in tagged PDF. % \begin{macrocode} \UseTaggingSocket{tbl/leaders/begin} \leaders\hrule\@height\arrayrulewidth\hfill \UseTaggingSocket{tbl/leaders/end} % \end{macrocode} % To the row counting the above appears like an extra row, so we % have to correct the count. % \begin{macrocode} \tbl_gdecr_row_count: \cr \noalign{\vskip-\arrayrulewidth} } \ExplSyntaxOff % \end{macrocode} % \end{macro} % % % \begin{macrocode} \ExplSyntaxOff % \end{macrocode} % % % \PrintIndex % \PrintChanges % % \Finale % \endinput