%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Module:    ZzTeX Tabular Facilities, version 3
%
% Synopsis:  This module contains all the facilities for producing
%            tabular material. This is the third major version.
%
% Author:    Paul C. Anagnostopoulos
% Created:   4 June 2004
%
% Copyright 1989--2020 by Paul C. Anagnostopoulos
% under The MIT License (opensource.org/licenses/MIT)
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%                       Tabular Block
%                       ------- -----


\defineblock{\tabular}{\endtabular}{\false}{}

%~block tabular Type
% \abovepenalty = integer               % Penalty above text.
% \aboveskip = glue                     % Space b/b above text.
% \belowpenalty = integer               % Penalty below text.
% \belowskip = glue                     % Space b/b below text.
% \bodyfont = {font}                    % Body font.
% \columngutter = glue                  % Width of column gutter.
% \colheadbelowskip = dimen             % Space b/b below column heads.
% \colheadcolor = {color}               % Color of Column heads.
% \colheadfont = {font}                 % Column head font.
% \interrowskip = dimen                 % Extra space between rows.
% \leftindent = glue                    % Left indentation.
% \parhang = dimen                      % Paragraph column hang.
% \parrag = dimen                       % Paragraph raggedness.
% \parskip = skip                       % Paragraph skip.
% \rightindent = glue                   % Right indentation.
% \rulecolcolor = {color}               % Color of table rules.
% \rulecolwidth = dimen                 % Width of column rules.
% \sideheadaboveskip = dimen            % Space b/b above side heads.
% \sideheadbelowskip = dimen            % Space b/b below side heads.
% \sideheadcolor = {color}              % Color of side heads.
% \sideheadfont = {font}                % Side head font.
% \spannerheadcolor = {color}           % Color of spanner heads.
% \spannerheadfont = {font}             % Spanner head font.
% \spannerruleaboveskip = dimen         % Space b/b above spanner rules.
% \spannerrulebelowskip = dimen         % Space b/b below spanner rules.
% \spannerrulecolor = {color}           % Color of spanner rules.
% \spannerruleheight = dimen            % Spanner rule thickness.
% \style = {...}                        % Style description.
% \tabbottomruleaboveskip = dimen       % Space b/b above bottom rules.
% \tabheadrulebelowskip = dimen         % Space b/b below head rules.
% \def \tabnoteformat ##1{...}          % Format of table note references.
% \tabrulecolor = {color}               % Color of table rules.
% \tabruleheight = dimen                % Table rule thickness.
% \tabtoprulebelowskip = dimen          % Space b/b below top rules.
% \width = dimen                        % Width of tabular material.
%~end

\defineskip{\colheadbelowskip}{0pt}
\definetoks{\colheadcolor}
\definetoks{\colheadfont}
\definetoks{\rulecolcolor}
\definedimen{\rulecolwidth}{0pt}
\definedimen{\sideheadaboveskip}{0pt}
\definedimen{\sideheadbelowskip}{0pt}
\definetoks{\sideheadcolor}
\definetoks{\sideheadfont}
\definetoks{\spannerheadcolor}
\definetoks{\spannerheadfont}
\definedimen{\spannerruleaboveskip}{0pt}
\definedimen{\spannerrulebelowskip}{0pt}
\definetoks{\spannerrulecolor}
\definedimen{\spannerruleheight}{0pt}
\definedimen{\tabbottomruleaboveskip}{0pt}
\definedimen{\tabheadrulebelowskip}{0pt}
\definetoks{\tabrulecolor}
\definedimen{\tabruleheight}{0pt}
\definedimen{\tabtoprulebelowskip}{0pt}


\def \tabular #1#2{%                            {type}{template}
  \endgraf
  \beginblockscope{tabular}%
  \global\increment \tabulardepth
  \abovepenalty = \breakgood                    %~default hard
  \belowpenalty = \breakbetter                  %~default hard
  \processdesign{\tabular}{#1}%
  \global\increment \tabularnumber
  \zsetuptabular{#2}%
  \tabularformat
  \defineatsigncommand @A{\adjustcolrule}%
  \defineatsigncommand @C{\closeuprows}%
  \defineatsigncommand @N{\nocolrule}%
  \defineatsigncommand @S{\skipabovespannerrule}%
  \defineatsigncommand @T{\skipbelowspannerrule}%
  \offinterlineskip
  \nobreak
  \tabskip=\leftskip
  \halign \if \dimneqlp{\width}{\naturalwidth}to \width \fi \bgroup
    \span\the\zpreamble \tabskip=\rightskip \cr}

\def \endtabular {%
    \crcr
  \egroup % \halign
  \if \posp{\prevdepth}%                % Does the last line have a strut?
    \kern -.5\interrowskip              % Yes, eliminate extra depth from
    \prevdepth = \dp\strutbox           % \interrowskip.
  \else
    \prevdepth = \tabruleheight         % No, compensate for bottom rule.
  \fi
  \futurelet\nexttoken \zendtabular}

\def \zendtabular {%
  \endtabularformat
  \global\decrement \tabulardepth
  \endblockscope{tabular}%
  \parnext}

\def \tabularformat {%
  \bbskipabove{\abovepenalty}{\aboveskip}%
  \fakepar                                      % This empty paragraph allows
  \hbox{}%                                      % the \bbskipabove to work.
  \kern
    \if \dimzerop{\tabtoprulebelowskip}-\ht\zrowstrut \else -\tabruleheight \fi
  \alterindentation{\leftindent}{\rightindent}}

\def \endtabularformat{%
  \bbskipbelowblockpar{\nexttoken}{\belowpenalty}{\belowskip}}

\def \adjustcolumngutter #1{%                   {amount} %^tabular
  \with{\advance\columngutter by #1}}

\def \adjustinterrowskip #1{%                   {amount} %^tabular
  \with{\advance\interrowskip by #1}}

%                       Set Up Tabular
%                       --- -- -------


\definecount{\tabcolcount}{0}           % Number of columns in table.
\definetoks{\zpreamble}                 % Preamble for \halign.
\definetoks{\ztabspacerow}              % Special row for vertical spacing.
\definebox{\zrowstrut}                  % Strut for table rows.
\definebox{\zparcelltopstrut}           % Strut for first line of par cell.
\definebox{\zparcellbotstrut}           % Strut for last line of par cell.

\def \zsetuptabular #1{%                                {template}
  \zanaltemplate{#1}%
  \the\bodyfont
  \calculate \tdimena = {\interrowskip,/,2,+,\ht\strutbox}%
  \calculate \tdimenb = {\interrowskip,/,2,+,\dp\strutbox}%
  \setbox \zrowstrut = \hbox{\vrule width 0pt
                                    height \tdimena depth \tdimenb}%
  \setbox \zparcelltopstrut = \hbox{\vrule width 0pt
                                           height \tdimena depth 0pt}%
  \setbox \zparcellbotstrut = \hbox{\vrule width 0pt
                                           height 0pt depth \tdimenb}%
  \global\zprevrowclass = \zrcpream
  \global\zcurrowclass = \zrcpream
  \gdef \zcolrulegate {}%
  \global\setflag \zcolrulesenabled = \false
  \everycr = {\noalign{\ztabcr}}}

%                       Analyze Template
%                       ------- --------


\defineskip{\zpendgutter}{0pt}


\def \zanaltemplate #1{%                                {template}
  \setbox\zboxa = \hbox{%
    \defineatsigncommand @!{\zcustomrulecol}%
    \defineatsigncommand @>{\zgutterspec}%
    \defineatsigncommand @c{\zcentercol}%
    \defineatsigncommand @C{\zcenternumbercol}%
    \defineatsigncommand @e{\zemptycol}%
    \defineatsigncommand @l{\zleftcol}%
    \defineatsigncommand @L{\zleftnumbercol}%
    \defineatsigncommand @p{\zparcol}%
    \defineatsigncommand @r{\zrightcol}%
    \defineatsigncommand @R{\zrightnumbercol}%
    \defineatsigncommand @s{\zspecialcol}%
    \defineatsigncommand @|{\zrulecol}%
    \global\tabcolcount = 0
    \global\zpreamble = {}%
    \global\ztabspacerow = {}%
    #1}%
  \tabcolcount = \tabcolcount
  \zpreamble = \zpreamble
  \ztabspacerow = \ztabspacerow}

\def \zcentercol {%
  \zstartcol{\false}%
  \zappendpreamble{\hfil ##\rowstrut \hfil}}

\def \zcenternumbercol #1{%
  \zstartcol{\false}%
  \zmeasuredanumber #1..\zmark
  \edef \znext {%
    \noexpand\zappendpreamble{%
      \hfil \noexpand\zsetnumbercell{\the\tdimena}{\the\tdimenb}{####}\hfil}}%
  \znext}

\def \zcustomrulecol #1#2{%                             {color}{width}
  \if \dimeqlp{\zpendgutter}{\mindimen}\zpendgutter = .5\columngutter \fi
  \zstartcol{\true}%
  \zappendpreamble{\zsetcolrule{#1}{#2}{##}}%
  \zpendgutter = .5\columngutter}

\def \zemptycol #1{%                                    {width}
  \zstartcol{\false}%
  \zappendpreamble{##\rowstrut \hspace{#1}}}

\def \zgutterspec #1{%                                  {width}
  \zparsegutterspec #1*\zmark}

\def \zparsegutterspec #1*#2\zmark{%
  \zpendgutter = #1\relax
  \if \notp{\emptyargp{#2}}%
    \advance \zpendgutter by \columngutter
    \advance \zpendgutter by -1\columngutter
  \fi}

\def \zleftcol {%
  \zstartcol{\false}%
  \zappendpreamble{##\rowstrut \hfil}}

\def \zleftnumbercol #1{%
  \zstartcol{\false}%
  \zmeasuredanumber #1..\zmark
  \edef \znext {%
    \noexpand\zappendpreamble{%
      \noexpand\zsetnumbercell{\the\tdimena}{\the\tdimenb}{####}\hfil}}%
  \znext}

\def \zparcol #1{%                                      {width}
  \zstartcol{\false}%
  \zappendpreamble{\zsetparcol{#1}{##}}}

\def \zrightcol {%
  \zstartcol{\false}%
  \zappendpreamble{\hfil ##\rowstrut}}

\def \zrightnumbercol #1{%
  \zstartcol{\false}%
  \zmeasuredanumber #1..\zmark
  \edef \znext {%
    \noexpand\zappendpreamble{%
      \hfil \noexpand\zsetnumbercell{\the\tdimena}{\the\tdimenb}{####}}}%
  \znext}

\def \zrulecol {%
  \if \dimeqlp{\zpendgutter}{\mindimen}\zpendgutter = .5\columngutter\relax \fi
  \zstartcol{\true}%
  \zappendpreamble{\zsetcolrule{}{}{##}}%
  \zpendgutter = .5\columngutter\relax}

\def \zspecialcol #1{%                                  {template}
  \zstartcol{\false}%
  \zappendpreamble{#1\rowstrut}}

\def \zstartcol #1{%                                    {rule-column?}
  \if \posp{\tabcolcount}%
    \if \dimeqlp{\zpendgutter}{\mindimen}\zpendgutter = \columngutter \fi
    \edef \znext {\noexpand\zappendpreamble{\tabskip=\the\zpendgutter &}}%
    \znext
    \global\ztabspacerow = \expandafter{\the\ztabspacerow &}%
  \fi
  \global\increment \tabcolcount
  \if \notp{#1}%
    \global\ztabspacerow = \expandafter{\the\ztabspacerow
                                        \omit \copy \ztabvspacebox}%
  \fi
  \zpendgutter = \mindimen}

\def \zappendpreamble #1{%                                 {preamble stuff}
  \global\zpreamble = \expandafter{\the\zpreamble #1}}

%                       Preamble Helpers
%                       -------- -------


\def \zmeasuredanumber #1.#2.#3\zmark{%
  \measuretextwidth{\tdimena}{#1}%
  \measuretextwidth{\tdimenb}{.#2}%
  \if \andp{\emptyargp{#2}}{\emptyargp{#3}}\tdimenb = 0pt\fi}

\def \zsetcolrule #1#2#3{%                      {color}{width}{adjustment}
  \if \emptyargp{#1}\color{\the\tabrulecolor}\else \color{#1}\fi
  \vrule width \if \emptyargp{#2}\rulecolwidth \else #2\fi
         \zcolrulegate #3%
  \endcolor}

\def \zsetnumbercell #1#2#3{%                   {pre-width}{post-width}{text}
  \gdef \zcellstyle {}%
  \zsplitdanumber #3..\zmark
  \if \dimzerop{#2}%
    \if \emptytoksp{\ztoksb}%
      \hbox to #1{\hfil \the\ztoksa}%
    \else
      \error{celldecpt}{Template picture did not include a decimal point}%
    \fi
  \else
    \hbox to #1{\hfil \the\ztoksa}%
    \hbox to #2{\zcellstyle \the\ztoksb \hfil}%
  \fi
  \rowstrut}

\long\def \zsetparcol #1#2{%                    {width}{text}
  \vtop{%
    \zpushvcontext
    \baselineskip = \normalbaselineskip
    \lineskiplimit = 0pt \lineskip = 0pt
%%%    \setindentation{0pt}{0pt}%
    \settextwidth{#1}%
    \setparrag{\parrag}%
    \leftskip = \parhang
    \parindent = -\parhang
    \parfillskip = \normalparfillskip
    \unhcopy \zparcelltopstrut
    #2%
    \if \hmodep \unhcopy \zparcellbotstrut \par \fi
    \zpopvcontext}}

\def \zsplitdanumber #1.#2.#3\zmark{%
  \ztoksa = {#1}%
  \ztoksb = {.#2}%
  \if \andp{\emptyargp{#2}}{\emptyargp{#3}}\ztoksb = {}\fi}

%                       Row Class
%                       --- -----


\definecount{\zprevrowclass}{0}
\definecount{\zcurrowclass}{0}

\chardef \zrcpream  = 0
\chardef \zrcdata   = 1
\chardef \zrchead   = 2
\chardef \zrcrule   = 3
\chardef \zrcvspace = 4
\chardef \zrcbbskip = 5

\def \zsetrowclass #1{%
  \if \gtrp{#1}{\zcurrowclass}\global\zcurrowclass = #1\relax \fi}

\def \ztabcr {%
  \global\zprevrowclass = \zcurrowclass
  \global\zcurrowclass = \zrcdata
  \global\setflag \zcolrulesenabled = \false}

%                       Cell Facilities
%                       ---- ----------


%~ This command produces a phantom zero, which is useful for aligning
%~ numbers when decimal-aligned columns are not being used.

\def \0{\phantom{0}}                                    %^tabular

\zremovePlaindef \hideskip
\defineskip{\hideskip}{-1000pt plus 1fill}

%~ This command "hides" the width of the cell from the column width calculation
%~ process. The cell does not participate in determining the widest cell of
%~ the column. If the cell is wider than the calculated column width, it will
%~ stick into the left or right column gutter, depending on the position of the
%~ |\hidewidth| command.

\def \hidewidth {\hskip \hideskip}                      %^tabular

%~ This command discards the templates for the specified number of columns and
%~ creates one cell that spans them all. The content of the cell is specified
%~ immediately following the command. This spanning cell has no template, so
%~ you must include all the required commands in the cell text. This is usually done
%~ using one of the cell override commands such as |\leftcell|.

\def \multispan #1{%                                    {columns} %^tabular
  \omit
  \tcounta = #1%
  \loop \ifnum \tcounta > 1 \zspan \repeat
  \let \omit = \relax % In case the next thing is a \leftcell or whatever.
  \ignorespaces}

\def \zspan {\span\omit \decrement \tcounta}

\def \rowstrut {%
  \unhcopy \zrowstrut}

\def \zcellstyle {}

\def \setcellstyle #1{%
  #1%
  \gdef \zcellstyle {#1}%
  \ignorespaces}

%~ This command sets a table note reference, usually a lowercase
%~ letter. The format of the reference is determined by the design.

\def \tabnote #1{%                                      {note-mark} %^tabular
  {\tabnoteformat{#1}}}

%                       Cell Overrides
%                       ---- ---------


%~ This command overrides the template for the column and sets
%~ a centered cell. It must appear immediately after the
%~ ampersand (|&&|) that begins the cell.

\def \centercell #1{%                                   {text} %^tabular
  \omit
  \hfil #1\rowstrut \hfil}

%~ This command overrides the template for the column and sets
%~ a flush left cell. It must appear immediately after the
%~ ampersand (|&&|) that begins the cell.

\def \leftcell #1{%                                     {text} %^tabular
  \omit
  #1\rowstrut \hfil}

%~ This command overrides the template for the column and sets
%~ a paragraph cell. It must appear immediately after the
%~ ampersand (|&&|) that begins the cell.

\def \parcell #1#2{%                                    {width}{text} %^tabular
  \omit
  \zsetparcol{#1}{#2}}

%~ This command overrides the template for the column and sets
%~ a flush right cell. It must appear immediately after the
%~ ampersand (|&&|) that begins the cell.

\def \rightcell #1{%                                    {text} %^tabular
  \omit
  \hfil #1\rowstrut}

%                       Column Heads
%                       ------ -----


%~ This column head command produces a centered head.

\def \centerhead #1{%                                   {heading} %^tabular
  \centercell{%
    \the\colheadfont \colortext{\the\colheadcolor}{#1}%
    \zchkadjheads}}

%~ This column head command produces a flush left head.

\def \lefthead #1{%                                     {heading} %^tabular
  \leftcell{%
    \the\colheadfont \colortext{\the\colheadcolor}{#1}%
    \zchkadjheads}}

%~ This column head command produces a flush right head.

\def \righthead #1{%                                    {heading} %^tabular
  \rightcell{%
    \the\colheadfont \colortext{\the\colheadcolor}{#1}%
    \zchkadjheads}}

%~ This command produces a spanner head that spans the specified
%~ number of columns.

\def \spannerhead #1#2{%                                {columns}{heading} %^tabular
  \multispan{#1}%
  \centercell{\the\spannerheadfont \colortext{\the\spannerheadcolor}{#2}}%
  \zsetrowclass{\zrchead}}

\def \zchkadjheads {%
  \if \andp{\eqlp{\zprevrowclass}{\zrchead}}{\posp{\interrowskip}}%
    \warning{adjheads}{Two adjacent rows of heads need to be closed up}%
    \global\zprevrowclass = \zrcdata
  \fi
  \zsetrowclass{\zrchead}}

%                       Side Heads
%                       ---- -----

%~ This command is a shorthand for producing a cut-in head that spans the
%~ entire width of the table. It is equivalent to:
%~
%~ | \skipabovesidehead
%~ | \sidehead{*all-columns*}{*heading*}\cr
%~ | \skipbelowsidehead

\def \cutinhead #1{%                                    {heading} %^tabular
  \skipabovesidehead
  \sidehead{\tabcolcount}{#1}\cr
  \skipbelowsidehead}

%~ This command produces a side head that spans the specified number of
%~ columns. It is similar to |\spannerhead|. It is almost always the case that a
%~ |\sidehead| row should be preceded by a |\skipabovesidehead| and followed by a
%~ |\skipbelowsidehead|.

\def \sidehead #1#2{%                                   {columns}{heading} %^tabular
  \multispan{#1}%
  \leftcell{\the\sideheadfont \colortext{\the\sideheadcolor}{#2}}}

%                       Vertical Spacing
%                       -------- -------


%~ This command eliminates the inter-row space between two rows. It must be
%~ used between two consective rows of table heads. Shorthand: |@C|.

\def \closeuprows {%                                    %^tabular
  \tabvspace{-\interrowskip}}

%~ This command adds extra space between column heads and the first data row.
%~ It must be used in tables that do not have head rules.

\def \skipbelowcolhead {%                               %^tabular
  \zchkbelowhead
  \tabbbskip{\colheadbelowskip}}

%~ This command produces the appropriate vertical space above
%~ a spanner rule. Shorthand: |@S|. See also |\skipbelowspannerrule|.

\def \skipabovespannerrule {%                           %^tabular
  \tabbbskip{\spannerruleaboveskip}}

%~ This command produces the appropriate vertical space below
%~ a spanner rule. Shorthand: |@T|. See also |\skipabovespannerrule|.

\def \skipbelowspannerrule {%                           %^tabular
  \tabbbskip{\spannerrulebelowskip}}

%~ This command produces the appropriate vertical space above
%~ a side head. See also |\skipbelowsidehead|.

\def \skipabovesidehead {%                              %^tabular
  \tabbbskip{\sideheadaboveskip}}

%~ This command produces the appropriate vertical space below
%~ a side head. See also |\skiabovewsidehead|.

\def \skipbelowsidehead {%                              %^tabular
  \tabbbskip{\sideheadbelowskip}}

%~ This command produces extra vertical space so that the base-to-base space
%~ between the preceding and following rows is as specified.

\def \tabbbskip #1{%                                    {amount} %^tabular
  \ztabbbskip{#1,-,\dp\zrowstrut,-,\ht\zrowstrut}%
  \the\ztabspacerow\cr}

%~ This command produces extra vertical space between a row and a rule.
%~ It must be used instead of |\tabbbskip| to obtain the desired results when
%~ spacing above horizontal rules. See also |\tabbbskipbelowrule|.

\def \tabbbskipaboverule #1{%                           {amount} %^tabular
  \noalign{\nobreak}%
  \ztabbbskip{#1,-,\dp\zrowstrut,-,\tabruleheight}%
  \noalign{\if \zcolrulesenabled \zsuppresscolrules \fi}%
  \the\ztabspacerow \if \zcolrulesenabled \zallowcolrules \fi\cr
  \noalign{\nobreak}}

%~ This command produces extra vertical space between a rule and a row.
%~ It must be used instead of |\tabbbskip| to obtain the desired results when
%~ spacing below horizontal rules. See also |\tabbbskipaboverule|.

\def \tabbbskipbelowrule #1{%                           {amount} %^tabular
  \ztabbbskip{#1,-,\ht\zrowstrut}%
  \the\ztabspacerow\cr}

%~ This command produces the specified amount of extra vertical space
%~ between two rows of the table.

\def \tabvspace #1{%                                    {amount} %^tabular
  \noalign{%
    \zsetrowclass{\zrcvspace}%
    \zsetvspacebox{#1}}%
  \the\ztabspacerow\cr}

\def \ztabbbskip #1{%
  \noalign{%
    \zsetrowclass{\zrcbbskip}%
    \if \eqlp{\zprevrowclass}{\zrcbbskip}%
      \tdimena = 0pt\relax
    \else
      \calculate \tdimena = {#1}%
    \fi
    \zsetvspacebox{\tdimena}}}

\definebox{\ztabvspacebox}
\setbox \ztabvspacebox = \hbox{}%

\def \zsetvspacebox #1{%
  \if \dimnegp{#1}%
    \vskip #1\relax
    \dp\ztabvspacebox = 0pt
  \else
    \dp\ztabvspacebox = #1\relax
  \fi}

\def \zchkbelowhead {%
  \noalign{%
    \if \neqlp{\zprevrowclass}{\zrchead}%
      \warning{needheads}{The previous row should be a row of column heads}%
    \fi}}

%                       Horizontal Rules
%                       ---------- -----


%~ This command produces a custom version of the partial table rule
%~ (|\partialtabrule|). The color and thickness of the rules is specified
%~ explicitly.

\def \custompartialtabrule #1#2#3{%             {color}{thickness}{columns} %^tabular
  \multispan{#3}%
  \color{#1}%
  \ruleleaders{\hrule height #2 depth 0pt}%
  \endcolor}

%~ This command produces a custom version of the table spanner rule
%~ (|\spannerrule|). The color and thickness of the rules is specified
%~ explicitly.

\def \customspannerrule #1#2#3{%                {color}{thickness}{columns} %^tabular
  \multispan{#3}%
  \rowstrut
  \color{#1}%
  \ruleleaders{\hrule height #2 depth 0pt}%
  \endcolor}

%~ This command produces a custom version of the table rule
%~ (|\tabrule|). The color and thickness of the rules is specified
%~ explicitly.

\def \customtabrule #1#2{%                              {color}{thickness} %^tabular
  \multispan{\tabcolcount}%
  \color{#1}%
  \ruleleaders{\hrule height #2 depth 0pt}%
  \endcolor\cr}

%~ This command produces a table rule across the specified number of columns.
%~ It is similar to |\spannerrule| but sets a rule of the same thickness
%~ as |\tabrule|.

\def \partialtabrule #1{%                                       {columns} %^tabular
  \custompartialtabrule{\the\tabrulecolor}{\tabruleheight}{#1}}

%~ This command produces a spanner rule across the specified number of columns.
%~ The color and thickness of the rule are determined by the design. A row with
%~ spanner rules is usually preceded and followed by |\skipabovespannerrule| and
%~ |\skipbelowspannerrule|.

\def \spannerrule #1{%                                          {columns} %^tabular
  \customspannerrule{\the\spannerrulecolor}{\spannerruleheight}{#1}}

%~ This command produces the standard bottom rule in a table. Which rules are
%~ required is specified in the |\style| parameter of the |\tabular| design.
%~ This command is not followed by |\cr|.

\def \tabbottomrule {%                                          %^tabular
  \tabbbskipaboverule{\tabbottomruleaboveskip}%
  \tabrule}

%~ This command produces the standard head rule in a table. Which rules are
%~ required is specified in the |\style| parameter of the |\tabular| design.
%~ This command is not followed by |\cr|.

\def \tabheadrule {%                                            %^tabular
  \zchkbelowhead
  \tabbbskipaboverule{\colheadbelowskip}%
  \tabrule
  \tabbbskipbelowrule{\tabheadrulebelowskip}}

%~ This command produces a table rule across the entire width of the table. The
%~ color and thickness of the rule are determined by the design. This command
%~ is not followed by |\cr|.

\def \tabrule {%                                                %^tabular
  \customtabrule{\the\tabrulecolor}{\tabruleheight}}

%~ This command produces the standard top rule in a table. Which rules are
%~ required is specified in the |\style| parameter of the |\tabular| design.
%~ This command is not followed by |\cr|.

\def \tabtoprule {%                                             %^tabular
  \tabrule
  \noalign{\nobreak}%
  \tabbbskipbelowrule{\tabtoprulebelowskip}}

%                       Vertical Rules
%                       -------- -----


%~ This command is used in the normally empty cell corresponding to a vertical
%~ rule column. It adjusts the width, height, and/or depth of the rule in that
%~ cell. To adjust one of those dimensions, specify the new dimension in
%~ points, without the usual |pt|, in the appropriate argument position.
%~ Omitted dimensions will have their standard values. You must specify both
%~ commas and the semicolon. Shorthand: |@A*width*,*height*,*depth*;|

\def \adjustcolrule #1,#2,#3;{%                         width,height,depth; %^tabular
  \if \notp{\emptyargp{#1}}width #1pt\fi
  \if \notp{\emptyargp{#2}}height #2pt\fi
  \if \notp{\emptyargp{#3}}depth #3pt\fi\relax}

%~ This command can be used between rows of a table to allow all vertical
%~ rules. This is typically done after the column head portion of a table. If
%~ |\allowcolrules| appears just before |\tabheadrule|, it is deferred until
%~ after the vertical space above the horizontal rule, so that the vertical
%~ rules recommence precisely at the horizontal rule. See also
%~ |\suppresscolrules|.

\def \allowcolrules {%                                  %^tabular
  \noalign{%
    \zallowcolrules
    \global\setflag \zcolrulesenabled = \true}}

\def \zallowcolrules {%
  \gdef \zcolrulegate {}}

%~ This command can be used between rows of a table to suppress all vertical
%~ rules. This is typically done for the column head portion of a table.
%~ See also |\allowcolrules|.

\def \suppresscolrules {%                               %^tabular
  \noalign{\zsuppresscolrules}}

\def \zsuppresscolrules {%
  \gdef \zcolrulegate {\nocolrule}}

%~ This command is used in the normally empty cell corresponding to a vertical
%~ rule column. It suppresses the vertical rule in that cell. Shorthand: |@N|.

\def \nocolrule {%                                      %^tabular
  width 0pt }

%                       Inter-Row Facilities
%                       --------- ----------


%~ This command can be used between rows of a table to insert vertical material
%~ that is independent of the rows themselves. It is rarely needed.

\def \adjusttabular #1{%                                {commands} %^tabular
  \noalign{#1}}

\let \adjusttab = \adjusttabular

%                       Low-Level Alignment Facilities
%                       --------- --------- ----------


\let \completerow = \cr

\def \ialign {\everycr = {}\tabskip=0pt \halign}

\def \oalign #1{%                                       {row...}
  \ensurepar
  \vtop{\baselineskip = 0pt
        \lineskip = .25ex
        \ialign{##\cr #1\crcr}}}

\def \ooalign {%
  \lineskiplimit = -\maxdimen
  \oalign}

\def \ozalign {%
  \lineskiplimit = 0pt\relax
  \oalign}
