%D \module
%D   [       file=core-ntb,
%D        version=2000.04.18,
%D          title=\CONTEXT\ Core Macros,
%D       subtitle=Natural Tables,
%D         author=Hans Hagen,
%D           date=\currentdate,
%D      copyright={PRAGMA / Hans Hagen \& Ton Otten}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.

%D This is an unfinished, preliminary module. At least two
%D runs are needed to get the table fixed.

% optie=rek beschrijven

\writestatus{loading}{Context Core Macros / Natural Tables}

%D As always, this is the nth version. Much time went in
%D trying to speed up the many cell calculations, some
%D optimizations were rejected in order not to complicate this
%D module too much (and in order to prevail extensibility).

%D To Do:
%D
%D \starttyping
%D splitsen = ja | herhaal => als nofTH>1 then ja als herhaal
%D \stoptyping

%D To Do:
%D
%D \starttyping
%D break over pagina
%D kop herhalen
%D reset settings
%D
%D \setupTABLE [c|column|x]            [nx|odd|even|first|last][a=b]
%D \setupTABLE [r|row   |y]            [nx|odd|even|first|last][a=b]
%D \setupTABLE [nx|odd|even|first|last][ny|odd|even|first|last][a=b]
%D \setupTABLE [nx|odd|even|first|last]                        [a=b]
%D \setupTABLE                                                 [a=b]
%D
%D \bTH \eTH
%D \stoptyping

% the section setup does not work yet, data needs to be stored,
% i.e.each row should know if it's a head/body/foot, and there
% should be \setupTABLE[head]... and alike

\unprotect

%D A simple way to force equal line spacing is to say:
%D
%D \starttyping
%D \def\bTBLCELL{\begstrut}
%D \def\eTBLCELL{\endstrut}
%D \stoptyping

%D However, the next alternative also takes care of preceding
%D and following white space.

\def\bTBLCELL % why not \doinhibitblank
  {\inhibitblank\doconvertfont\tbltblstyle\empty\everypar{\delayedbegstrut}}

\def\eTBLCELL
  {\ifhmode
     \delayedendstrut
     \par % added 13/4/2006
   \else
     \par
     \ifdim\prevdepth<\zeropoint % =-1000pt ?
       \vskip-\strutdp
     \else
       \removebottomthings
     \fi
   \fi}

\newcounter\currenttbl

\def\@@tbl{tbl}  \def\tblcell{1}  \def\tblnone{2}

\def\@@tblprefix{tbl:} \let\@@rawtblprefix\@@tblprefix

%D This should be done more efficient:

\def\settbltag#1#2#3{\setevalue{\@@tblprefix#1:#2:s}{#3}} % \number#3
\def\settblcol#1#2#3{\setevalue{\@@tblprefix#1:#2:c}{#3}}
\def\settblrow#1#2#3{\setevalue{\@@tblprefix#1:#2:r}{#3}}

\def\settblwd #1#2#3{\setxvalue{\@@tblprefix#1:#2:wd}{#3}} % global !
\def\settblht #1#2#3{\setxvalue{\@@tblprefix#1:#2:ht}{#3}} % global !

\def\gettbltag#1#2{\csname\@@tblprefix#1:#2:s\endcsname}
\def\gettblcol#1#2{\csname\@@tblprefix#1:#2:c\endcsname}
\def\gettblrow#1#2{\csname\@@tblprefix#1:#2:r\endcsname}

\def\gettblwd #1#2{\csname\@@tblprefix#1:#2:wd\endcsname}
\def\gettblht #1#2{\csname\@@tblprefix#1:#2:ht\endcsname}

\def\settblwid#1#2{\setxvalue{\@@tblprefix#1:w}{#2}} % global !
\def\settblhei#1#2{\setxvalue{\@@tblprefix#1:h}{#2}} % global !
\def\settbldis#1#2{\setxvalue{\@@tblprefix#1:d}{#2}} % global !
\def\settblaut#1#2{\setxvalue{\@@tblprefix#1:a}{#2}} % global !

\def\gettblwid#1{\executeifdefined{\@@tblprefix#1:w}\zeropoint}
\def\gettblhei#1{\executeifdefined{\@@tblprefix#1:h}\zeropoint}
\def\gettbldis#1{\executeifdefined{\@@tblprefix#1:d}\zeropoint}
\def\gettblaut#1{\csname\@@tblprefix#1:a\endcsname}

\def\doiftbltag    #1#2{\doifdefined    {\@@tblprefix#1:#2:s}}
\def\doifnottbltag #1#2{\doifundefined  {\@@tblprefix#1:#2:s}}
\def\doifelsetbltag#1#2{\doifdefinedelse{\@@tblprefix#1:#2:s}}
\def\doiftblrow    #1#2{\doifdefined    {\@@tblprefix#1:#2:r}}
\def\doiftblcol    #1#2{\doifdefined    {\@@tblprefix#1:#2:c}}
\def\doifnottblcol #1#2{\doifundefined  {\@@tblprefix#1:#2:c}}

% \def\settblspn#1#2{\setvalue     {\@@tblprefix#1:s}{#2}}
% \def\doiftblspn #1{\doifelsevalue{\@@tblprefix#1:s}{1}}

\def\settblspn     #1{\setvalue     {\@@tblprefix#1:s}{1}}
\def\doifelsetblspn#1{\doifelsevalue{\@@tblprefix#1:s}{1}}

\def\settbltxt#1#2{\long\setvalue{\@@tblprefix:#1:#2:t}}
\def\gettbltxt#1#2{\csname\@@tblprefix:#1:#2:t\endcsname}

%\def\doiftbl      #1#2#3{\ifcase0\getvalue{\@@tblprefix#1:#2:s}\relax  \else#3\fi}
%\def\doifnottbl   #1#2#3{\ifcase0\getvalue{\@@tblprefix#1:#2:s}\relax       #3\fi}
%\def\doifelsetbl#1#2#3#4{\ifcase0\getvalue{\@@tblprefix#1:#2:s}\relax#4\else#3\fi}
%
%\let\doiftbltag    \doiftbl
%\let\doifnottbltag \doifnottbl
%\let\doifelsetbltag\doifelsetbl

\newtoks\tbltoks

\let\pushTBLparameters\relax
\let\popTBLparameters \relax

\newif\ifsqueezeTBLspan     \squeezeTBLspantrue % spans one column cell over multi column par cells
\newif\ifautosqueezeTBLspan \autosqueezeTBLspantrue % unless explicit widths are given
\newif\ifautoTBLspread      \autoTBLspreadfalse
\newif\ifautoTBLhsize       \autoTBLhsizetrue
\newif\ifautoTBLrowspan     \autoTBLrowspantrue
\newif\ifautoTBLemptycell   \autoTBLemptycelltrue
\newif\ifautoTBLcheckwidth  \autoTBLcheckwidthtrue
\newif\ifappendTBLsetups    \appendTBLsetupstrue
\newif\ifenableTBLbreak     \enableTBLbreakfalse
\newif\ifmultipleTBLheads   \multipleTBLheadsfalse

\newif\iftraceTABLE         \traceTABLEfalse

\def\noftblheadlines{0}
\def\noftblnextlines{0}
\def\noftblhdnxlines{0}

\presetlocalframed[\@@tbl\@@tbl]

\long\def\handleTBLcell#1#2[#3]{}

\long\def\bTC#1\eTC{\bTD#1\eTD}
\long\def\bTX#1\eTX{\bTD#1\eTD}
\long\def\bTY#1\eTY{\bTR#1\eTR}

\let\getTABLEparameters\getparameters

\unexpanded\def\setupTABLE
  {\dotripleempty\dosetupTABLE}

\def\dosetupTABLE[#1][#2][#3]%
  {\ifthirdargument
     \processaction
       [#1]
       [  \v!row=>{\dosetupTABLExy[\c!y][#2][#3]},%
       \v!column=>{\dosetupTABLExy[\c!x][#2][#3]},%
               r=>{\dosetupTABLExy[\c!y][#2][#3]},%
               c=>{\dosetupTABLExy[\c!x][#2][#3]},%
               y=>{\dosetupTABLExy[\c!y][#2][#3]},%
               x=>{\dosetupTABLExy[\c!x][#2][#3]},%
        \v!start=>{\dosetupTABLExy[#1][#2][#3]},%
       \v!header=>{\dosetupTABLExy[#1][#2][#3]},%
      \s!unknown=>{\dosetupTABLEzz[#1][#2][#3]}]%
   \else\ifsecondargument
     \processaction
       [#1]
       [  \v!row=>{\dosetupTABLExy[\c!y][\v!each][#2]},%
       \v!column=>{\dosetupTABLExy[\c!x][\v!each][#2]},%
               r=>{\dosetupTABLExy[\c!y][\v!each][#2]},%
               c=>{\dosetupTABLExy[\c!x][\v!each][#2]},%
               y=>{\dosetupTABLExy[\c!y][\v!each][#2]},%
               x=>{\dosetupTABLExy[\c!x][\v!each][#2]},%
        \v!start=>{\dosetupTABLExy[#1][\v!each][#2]},%
       \v!header=>{\dosetupTABLExy[#1][\v!each][#2]},%
      \s!unknown=>{\dosetupTABLEzz[\c!x][#1][#2]}]%
   \else
     \getparameters[\@@tbl\@@tbl][#1]%
   \fi\fi}

\def\dosetupTABLExy[#1][#2][#3]%
  {\def\dodosetupTABLE##1{\setTABLEparameters[#1##1][#3]}%
   \processcommalist[#2]\dodosetupTABLE}

\def\dosetupTABLEzz[#1][#2][#3]%
  {\def\dodosetupTABLE##1%
     {\def\dododosetupTABLE####1{\setTABLEparameters[\c!x##1\c!y####1][#3]}%
      \processcommalist[#2]\dododosetupTABLE}%
   \processcommalist[#1]\dodosetupTABLE}

\def\nopTABLEparameters[#1][#2]%
  {\letvalue{\@@tblprefix#1}\empty}

\def\setTABLEparameters[#1][#2]%
  {\pushTBLparameters
   \ifappendTBLsetups
     \doifdefinedelse{\@@tblprefix#1}
       {\def\getTABLEparameters[##1][##2]%
          {\setvalue{\@@tblprefix#1}{\getTABLEparameters[\@@tbl\@@tbl][##2,#2]}}%
        \getvalue{\@@tblprefix#1}%
        \let\getTABLEparameters\getparameters}
       {\setvalue{\@@tblprefix#1}{\getTABLEparameters[\@@tbl\@@tbl][#2]}}%
   \else
     \setvalue{\@@tblprefix#1}{\getTABLEparameters[\@@tbl\@@tbl][#2]}%
   \fi
   \popTBLparameters}

\let\setupTBLsection\relax

% \def\setupTBLcell#1#2% cell over col over row
%   {\setupTBLsection % already forgotten
%    \getvalue{\@@tblprefix\v!each\v!each}%
%    \getvalue{\@@tblprefix\c!y\v!each}%
%    \getvalue{\@@tblprefix\c!x\v!each}%
%    \getvalue{\@@tblprefix\c!y\v!oddeven{#1}}%
%    \getvalue{\@@tblprefix\c!x\v!oddeven{#2}}%
%    \getvalue{\@@tblprefix\c!x\v!oddeven{#2}\c!y\v!oddeven{#1}}%
%    \ifnum#1=\plusone
%      \getvalue{\@@tblprefix\c!y\v!first}%
%      \executeifdefined{\@@tblprefix\c!x#2\c!y\v!first}\donothing
%    \fi
%    \ifnum#2=\plusone
%      \getvalue{\@@tblprefix\c!x\v!first}%
%      \executeifdefined{\@@tblprefix\c!x\v!first\c!y#1}\donothing
%    \fi
%    \ifnum#1=\maximumrow\relax
%      \getvalue{\@@tblprefix\c!y\v!last}%
%      \executeifdefined{\@@tblprefix\c!x#2\c!y\v!last}\donothing
%    \fi
%    \ifnum#2=\maximumcol\relax
%      \getvalue{\@@tblprefix\c!x\v!last}%
%      \executeifdefined{\@@tblprefix\c!x\v!last\c!y#1}\donothing
%    \fi
%    \ifnum#1=\maximumrow\relax\ifnum#2=\maximumcol\relax
%      \getvalue{\@@tblprefix\c!x\v!last\c!y\v!last}%
%    \fi\fi
%    \ifnum#1=\plusone \ifnum#2=\plusone
%      \getvalue{\@@tblprefix\c!x\v!first\c!y\v!first}%
%    \fi\fi
%    \ifnum#1>\noftblhdnxlines\else
%      \executeifdefined{\@@tblprefix\v!header\v!each}\donothing
%      \executeifdefined{\@@tblprefix\v!header#2}\donothing
%    \fi
%    \executeifdefined{\@@tblprefix\c!y#1}\donothing
%    \getvalue{\@@tbl\@@tbl\c!extras}\letvalue{\@@tbl\@@tbl\c!extras}\relax % new, see x-fo
%    \executeifdefined{\@@tblprefix\c!x#2}\donothing
%    \getvalue{\@@tbl\@@tbl\c!extras}\letvalue{\@@tbl\@@tbl\c!extras}\relax % new, see x-fo
%    \executeifdefined{\@@tblprefix\c!x#2\c!y#1}\donothing
%    \global\letcscsname\@@tblsplitafter\csname\@@tbl\@@tbl\c!after\endcsname
%    \relax}


\def\setupTBLcell#1#2% cell over col over row
  {\setupTBLsection % already forgotten
\edef\positiverow{\number#1}%
\edef\positivecol{\number#2}%
\scratchcounter-\maximumrow\advance\scratchcounter#1\advance\scratchcounter\minusone
\edef\negativerow{\number\scratchcounter}%
\scratchcounter-\maximumcol\advance\scratchcounter#2\advance\scratchcounter\minusone
\edef\negativecol{\number\scratchcounter}%
   \getvalue{\@@tblprefix\v!each\v!each}%
   \getvalue{\@@tblprefix\c!y\v!each}%
   \getvalue{\@@tblprefix\c!x\v!each}%
   \getvalue{\@@tblprefix\c!y\v!oddeven\positiverow}%
   \getvalue{\@@tblprefix\c!x\v!oddeven\positivecol}%
   \getvalue{\@@tblprefix\c!x\v!oddeven\positivecol\c!y\v!oddeven\positiverow}%
   \ifnum\positiverow=\plusone
     \getvalue{\@@tblprefix\c!y\v!first}%
     \executeifdefined{\@@tblprefix\c!x\positivecol\c!y\v!first}\donothing
   \fi
   \ifnum\positivecol=\plusone
     \getvalue{\@@tblprefix\c!x\v!first}%
     \executeifdefined{\@@tblprefix\c!x\v!first\c!y\positiverow}\donothing
   \fi
   \ifnum\positiverow=\maximumrow\relax
     \getvalue{\@@tblprefix\c!y\v!last}%
     \executeifdefined{\@@tblprefix\c!x\positivecol\c!y\v!last}\donothing
   \fi
   \ifnum\positivecol=\maximumcol\relax
     \getvalue{\@@tblprefix\c!x\v!last}%
     \executeifdefined{\@@tblprefix\c!x\v!last\c!y\positiverow}\donothing
   \fi
   \ifnum\positiverow=\maximumrow\relax\ifnum\positivecol=\maximumcol\relax
     \getvalue{\@@tblprefix\c!x\v!last\c!y\v!last}%
   \fi\fi
   \ifnum\positiverow=\plusone \ifnum\positivecol=\plusone
     \getvalue{\@@tblprefix\c!x\v!first\c!y\v!first}%
   \fi\fi
   \ifnum#1>\noftblhdnxlines\else
     \executeifdefined{\@@tblprefix\v!header\v!each}\donothing
     \executeifdefined{\@@tblprefix\v!header\positivecol}\donothing
   \fi
   \executeifdefined{\@@tblprefix\c!y\positiverow}\donothing
\executeifdefined{\@@tblprefix\c!y\negativerow}\donothing
   \getvalue{\@@tbl\@@tbl\c!extras}\letvalue{\@@tbl\@@tbl\c!extras}\relax % new, see x-fo
   \executeifdefined{\@@tblprefix\c!x\positivecol}\donothing
\executeifdefined{\@@tblprefix\c!x\negativecol}\donothing
   \getvalue{\@@tbl\@@tbl\c!extras}\letvalue{\@@tbl\@@tbl\c!extras}\relax % new, see x-fo
   \executeifdefined{\@@tblprefix\c!x\positivecol\c!y\positiverow}\donothing
\executeifdefined{\@@tblprefix\c!x\negativecol\c!y\negativerow}\donothing
   \global\letcscsname\@@tblsplitafter\csname\@@tbl\@@tbl\c!after\endcsname
   \relax}

% we cannot use +n (checking on number/last/first would slow down too much)
%
% \setupTABLE[r]  [2][color=red]
% \setupTABLE[r] [-2][color=red]
% \setupTABLE[c]  [2][color=green]
% \setupTABLE[c] [-2][color=green]
% \setupTABLE[4]  [4][color=blue]
% \setupTABLE[-4][-4][color=blue]
%
% \bTABLE
% \dorecurse{10}{\bTR \dorecurse{6}{\bTD xxx \eTD} \eTR}
% \eTABLE

\globallet\@@tblsplitafter\relax

% split + page:
%
% \bTABLE[split=yes]
% \bTR \bTD left \eTD\bTD right \eTD\eTR
% \bTR[after=\page] \bTD left \eTD\bTD right \eTD\eTR
% \bTR \bTD left \eTD\bTD right \eTD\eTR
% \eTABLE

% \long\def\parseTR[#1][#2]#3\eTR% [#2] is dummy that kills spaces
%   {\def\currentcol{0}\increment\maximumrow#3}

\def\parseTR[#1][#2]% [#2] is dummy that kills spaces / no #3 argument
  {\def\currentcol{0}\increment\maximumrow
   \let\currentcolpos\currentcol
   \let\eTR\relax % handy in \expanded
   \setupTABLE[\v!row][\maximumrow][#1]}

\long\def\parseTD[#1][#2]#3\eTD % [#2] is dummy that kills spaces
  {\getparameters[\@@tbl][\c!ny=\tblnr,\c!nx=\tblnc,nc=1,nr=1,\c!n=\currentcol,\c!m=,#1]%
   % goto first cell % NEW, n/m=cellnumber
   \increment\currentcolpos
   \doifelsevaluenothing{\@@tbl\c!n}
     {\increment(\spnTBL,\tblnx)\relax}
     {\ifnum\getvalue{\@@tbl\c!n}=\currentcol\else
        \scratchcounter\getvalue{\@@tbl\c!n}%
        \advance\scratchcounter-\currentcol
        \advance\scratchcounter\minusone
\advance\scratchcounter-\spnTBL
        \ifnum\scratchcounter>\zerocount
          \expanded{\parseTD[\c!nx=\the\scratchcounter,\c!n=,\c!m=,*sq=\v!no][]}\eTD
        \fi
        \getparameters[\@@tbl][\c!ny=\tblnr,\c!nx=\tblnc,nc=1,nr=1,#1,\c!n=,\c!m=]%
      \fi}%
   \doifvaluesomething{\@@tbl\c!m}
     {\ifnum\getvalue{\@@tbl\c!m}=\currentcol\else
        \scratchcounter\getvalue{\@@tbl\c!m}%
        \advance\scratchcounter-\currentcol
        \advance\scratchcounter\minusone
% \advance\scratchcounter-\spnTBL
        \dorecurse\scratchcounter{\expanded{\parseTD[\c!n=,\c!m=][]}\eTD}%
        \getparameters[\@@tbl][\c!ny=\tblnr,\c!nx=\tblnc,nc=1,nr=1,#1,\c!n=,\c!m=]%
      \fi}%
   \doloop
     {\increment\currentcol
      \doifnottbltag\maximumrow\currentcol\exitloop}%
   % fill r*c cells and set span
   \let\row\maximumrow
   \let\col\currentcol
   \dorecurse\tblny
     {\let\col\currentcol
      \settblcol\row\col\tblnx
      \ifnum\tblnx>\maximumrowspan\relax
        \let\maximumrowspan\tblnx
      \fi
      \dorecurse\tblnx
        {\settbltag\row\col\tblnone
         \increment\col}%
      \increment\row}%
   % check max column
   \decrement\col\relax
   \ifnum\col>\maximumcol\relax
     \let\maximumcol\col
   \fi
   % set values
   \settbltag\maximumrow\currentcol\tblcell
   \settblcol\maximumrow\currentcol\tblnx
   \settblrow\maximumrow\currentcol\tblny
   % save text
   \edef\celltag{{\maximumrow}{\currentcol}}%
   \@EA\settbltxt\@EA\maximumrow\@EA\currentcol\@EA
     {\@EA\handleTBLcell\celltag[#1]{#3}}}

%D The usage of n and m:
%D
%D \startbuffer
%D \bTABLE[width=3em]
%D \bTR\bTD d1 \eTD\bTD[n=2] d2 \eTD\bTD[n=5] d5 \eTD\bTD[n=7] d7 \eTD\eTR
%D \bTR\bTD f1 \eTD\bTD[n=4] f4 \eTD\bTD[n=5] f5 \eTD\bTD[n=7] f7 \eTD\eTR
%D \eTABLE
%D \stopbuffer
%D
%D \typebuffer \getbuffer
%D
%D \startbuffer
%D \bTABLE[width=3em]
%D \bTR\bTD d1 \eTD\bTD[m=2] d2 \eTD\bTD[m=5] d5 \eTD\bTD[m=7] d7 \eTD\eTR
%D \bTR\bTD f1 \eTD\bTD[m=4] f4 \eTD\bTD[m=5] f5 \eTD\bTD[m=7] f7 \eTD\eTR
%D \eTABLE
%D \stopbuffer
%D
%D \typebuffer \getbuffer
%D
%D \startbuffer
%D \bTABLE[frame=on]
%D \bTR \bTH[nc=3] One \eTH \bTH[m=4] Four \eTH\eTR
%D \bTR \bTD a \eTD\bTD b \eTD\bTD c \eTD\bTD d \eTD\eTR
%D \eTABLE
%D
%D \bTABLE[frame=on]
%D \bTR \bTH[nr=2] One \eTH \bTH[m=3] Three \eTH\eTR
%D \bTR \bTD[m=3] a \eTD\bTD b \eTD\bTD c \eTD\bTD d \eTD\eTR
%D \bTR \bTD[m=3] a \eTD\bTD b \eTD\bTD c \eTD\bTD d \eTD\eTR
%D \eTABLE
%D \stopbuffer
%D
%D \typebuffer \getbuffer

\long\def\parseTH[#1]#2\eTH
  {\parseTD[#1,\c!color=\tbltblheadcolor,\c!style=\tbltblheadstyle,\c!aligncharacter=\v!no]#2\eTD}

%D new

\long\def\parseTN[#1]#2\eTN
  {\parseTD[#1]\digits#2\relax\eTD}

%D Vit Zyka needed the option to create a distance between columns, so I
%D added support for individual column distances.
%D
%D \startbuffer
%D % \setupTABLE[c][each][distance=2em]
%D \setupTABLE[c][1][distance=2em]
%D \setupTABLE[c][2][distance=3em]
%D
%D \bTABLE
%D \bTR \bTD test \eTD  \bTD test \eTD  \bTD test \eTD \eTR
%D \bTR \bTD[nx=2] test \eTD  \bTD test \eTD \eTR
%D \bTR \bTD test \eTD  \bTD[nx=2] test \eTD \eTR
%D \eTABLE
%D
%D \bTABLE[option=stretch]
%D \bTR \bTD test \eTD  \bTD test \eTD  \bTD test \eTD \eTR
%D \bTR \bTD[nx=2] test \eTD  \bTD test \eTD \eTR
%D \bTR \bTD test \eTD  \bTD[nx=2] test \eTD \eTR
%D \eTABLE
%D \stopbuffer
%D
%D \typebuffer \startlinecorrection \getbuffer \stoplinecorrection
%D
%D and he provided patches for the global left and right margin distances
%D as well as the columndistance (although i changed the names -). Here
%D is his testcase:
%D
%D \startbuffer
%D \framed[offset=overlay]\bgroup
%D     \setupTABLE[column][2][align=left]%
%D     \setupTABLE[column][3][align=right]%
%D     \bTABLE[columndistance=2cm,leftmargindistance=.3cm,rightmargindistance=.5cm]
%D         \bTR \bTH[nc=3] Table head\eTH \eTR
%D         \bTR \bTD[nc=2] AB\eTD \bTD C\eTD \eTR
%D         \bTR \bTD[nc=2,align=left] AB\eTD \bTD C\eTD \eTR
%D         \bTR \bTD[nc=2,align=middle] AB\eTD \bTD C\eTD \eTR
%D         \bTR \bTD A\eTD \bTD B\eTD \bTD C\eTD \eTR
%D         \bTR \bTD Aa\eTD \bTD Bb\eTD \bTD Cccc\eTD \eTR
%D         \bTR \bTD[nc=3,align=middle] ABC\eTD \eTR
%D     \eTABLE
%D \egroup
%D \stopbuffer
%D
%D \typebuffer \startlinecorrection \getbuffer \stoplinecorrection

\newtoks\TBLhead
\newtoks\TBLnext
\newtoks\TBLbody
\newtoks\TBLfoot

% to be done: head <raw> foot, dus state var

\long\def\bTABLEhead{\dosingleempty\doTABLEhead}
\long\def\bTABLEnext{\dosingleempty\doTABLEnext}
\long\def\bTABLEbody{\dosingleempty\doTABLEbody}
\long\def\bTABLEfoot{\dosingleempty\doTABLEfoot}

\long\def\doTABLEhead[#1]#2\eTABLEhead{\appendtoks\doTABLEsection[#1]{#2}\to\TBLhead}
\long\def\doTABLEnext[#1]#2\eTABLEnext{\appendtoks\doTABLEsection[#1]{#2}\to\TBLnext}
\long\def\doTABLEbody[#1]#2\eTABLEbody{\appendtoks\doTABLEsection[#1]{#2}\to\TBLbody}
\long\def\doTABLEfoot[#1]#2\eTABLEfoot{\appendtoks\doTABLEsection[#1]{#2}\to\TBLfoot}

\long\def\doTABLEsection[#1]#2%
  {\def\setupTBLsection{\getparameters[\@@tbl\@@tbl][#1]}%
   #2%
   \let\setupTBLsection\relax}

\let\pushTBL\relax
\let\popTBL \relax

\chardef\TBLpass=0

\def\presetallTABLEparameters% each odd|even level
  {\executeifdefined{\@@rawtblprefix\v!start\v!each}\relax
   \executeifdefined{\@@rawtblprefix\v!start\v!oddeven\TBLlevel}\relax
   \executeifdefined{\@@rawtblprefix\v!start\number\TBLlevel}\relax}

\def\bTABLE
  {\dosingleempty\dobTABLE}

\def\dobTABLE[#1]%
  {\pushTBL
   % box not here
   \bgroup
   \ifhmode\kern\zeropoint\fi  % blocks \removeunwantedspaces: check this on icare handelingsschema
   \resetcharacteralign % new
   \getparameters
     [\@@tbl\@@tbl]
     [\c!align={\v!right,\v!broad,\v!high},#1]%
   \hsize\tbltbltextwidth
   \processaction
     [\tbltblsplit]
     [     \v!yes=>\enableTBLbreaktrue,
        \v!repeat=>\enableTBLbreaktrue\multipleTBLheadstrue]%
   \processaction
     [\tbltblheader]
     [\v!repeat=>\multipleTBLheadstrue]%
%    \ifnum\TBLlevel>\plusone
%      \vbox
%    \else\ifenableTBLbreak
%      % no \vbox
%    \else
%      \vbox
%    \fi\fi
%   \bgroup
   \localcolortrue
   \presetallTABLEparameters
   \ExpandFirstAfter\processallactionsinset
     [\tbltbloption]
     [\v!stretch=>\autoTBLspreadtrue]%
   \linewidth\tbltblrulethickness % needs to be frozen
   \dontcomplain
   \let\currentcol\!!zerocount
   \let\maximumrowspan\!!plusone
   \let\maximumcol\currentcol
   \let\maximumrow\currentcol
   \def\bTR{\dodoubleempty\parseTR}%
   \def\bTD{\dodoubleempty\parseTD}%
   \def\bTH{\dodoubleempty\parseTH}%
   \def\bTN{\dodoubleempty\parseTN}}

% permits \expanded{\bTD ... \eTD}

\unexpanded\def\eTR{}
\unexpanded\def\eTD{}
\unexpanded\def\eTH{}
\unexpanded\def\eTN{}

\def\eTABLE % beware, we need to get rid of spurious spaces when in hmode
  {% tricky and dirty order -)
   \doifsometokselse\TBLhead
     {\the\TBLhead
      \edef\noftblheadlines{\number\maximumrow}%
      \doifsometokselse\TBLnext
        {\the\TBLnext
         \scratchcounter\maximumrow \advance\scratchcounter-\noftblheadlines
         \edef\noftblnextlines{\number\scratchcounter}}%
        {\let\noftblnextlines\!!zerocount}% was 1
      \edef\noftblhdnxlines{\number\maximumrow}}
     {\let\noftblheadlines\!!zerocount % was 1
      \let\noftblnextlines\!!zerocount
      \let\noftblhdnxlines\!!zerocount}%
   \the\TBLbody
   \the\TBLfoot
   \removeunwantedspaces % only if hmode
   % finish cells
   \dorecurse\maximumrow
     {\let\row\recurselevel
      \dorecurse\maximumcol
        {\let\col\recurselevel \let\xxcol\col \let\xxrow\row
         \doifnottbltag\row\col
           {\let\xrow\row
            \doloop
              {\let\xcol\col
               \doloop
                 {\doifelsetbltag\xrow\xcol
                    {\exitloop}
                    {\increment\xcol \relax
                     \ifnum\xcol>\maximumcol\relax \exitloop \fi}}%
               \doifelsetbltag\xrow\xcol
                 {\exitloop}
                 {\let\xxrow\xrow \let\xxcol\xcol \increment\xrow \relax
                  \ifnum\xrow>\maximumrow \exitloop \fi}}}%
      \ifnum\xxrow>\maximumrow\let\xxrow\maximumrow\fi
      \ifnum\xxcol>\maximumcol\let\xxcol\maximumcol\fi
      \decrement(\xxrow,\row)\increment\xxrow
      \decrement(\xxcol,\col)\increment\xxcol
      \doifnottbltag\row\col
        {\let\xrow\row
         \dorecurse\xxrow
           {\let\xcol\col \settblcol\xrow\xcol\xxcol
            \dorecurse\xxcol
              {\settbltag\xrow\xcol\tblnone \increment\xcol}%
            \increment\xrow}%
         \settbltag\row\col\tblcell
         \settblcol\row\col\xxcol
         \settblrow\row\col\xxrow
         \ifautoTBLemptycell
           \edef\celltag{{\row}{\col}}%
           \@EA\settbltxt\@EA\row\@EA\col\@EA
             {\@EA\handleTBLcell\celltag[]{\strut}}%
         \fi}}}%
   % to be sure
   \dorecurse\maximumrow
     {\let\row\recurselevel
      \dorecurse\maximumcol
        {\let\col\recurselevel
         \doiftblrow\row\col
           {\scratchcounter\maximumrow
            \advance\scratchcounter -\row
            \advance\scratchcounter \plusone
            \ifnum\gettblrow\row\col>\scratchcounter
              \settblrow\row\col{\the\scratchcounter}%
            \fi}%
         \settblht\row\col\!!zeropoint
         \settblwd\row\col\!!zeropoint
         \doifnottblcol\row\col{\settblcol\row\col\!!zerocount}%
         \doifnottbltag\row\col{\settbltag\row\col\tblnone}}}%
   % check and do
   \ifcase\maximumcol\else
     \startTBLprocessing
       \begTBL
         \dorecurse\maximumrow
           {\bTBL
              \let\row\recurselevel
              \dorecurse\maximumcol
                {\let\col\recurselevel
                 \expanded{\doTBL{\row}{\col}}}%
            \eTBL}%
         \removeunwantedspaces % only if hmode
       \endTBL
     \stopTBLprocessing
     % wrong ! ! ! better to have an auto-offset-overlay
     % \ifnum\TBLlevel>1
     %   \vskip-\strutdp
     % \fi
   \fi
   \egroup
   \popTBL}

\let\startTBLprocessing\relax
\let\stopTBLprocessing \relax

% \def\processTBL
%   {\begTBL
%    \dorecurse\maximumrow
%      {\bTBL
%       \let\row\recurselevel
%       \dorecurse\maximumcol
%         {\let\col\recurselevel
%          \expanded{\doTBL{\row}{\col}}}%
%       \eTBL}%
%    \removeunwantedspaces % only if hmode
%    \endTBL}

\def\spanTBL#1#2%
  {\scratchcounter\gettblcol{#1}{#2}\relax
   \ifnum\scratchcounter>\zerocount
     \advance\scratchcounter \minusone
     \dorecurse\scratchcounter{\appendtoks\spantblcol\to\tbltoks}%
     \dorecurse\scratchcounter{\appendtoks\skiptblcol\to\tbltoks}%
                               \appendtoks\nexttblcol\to\tbltoks
   \fi}

\def\bTBL{\appendtoks\begintblrow\to\tbltoks}
\def\eTBL{\appendtoks\endtblrow  \to\tbltoks}

% We use aligments to handle the empty (skipped) columns, so
% that we don't have to (re|)|calculate these.

\def\skiptblcol
  {\doglobal\increment\colTBL}

\def\nexttblcol
  {\doglobal\increment\colTBL
   \kern\tbltblcolumndistance
   &}

\def\spantblcol
  {\span}

\newcounter\rowTBL
\newcounter\colTBL
\newcounter\spnTBL

\def\begintblrow
  {\noalign
     {\doglobal\increment \rowTBL
      \doglobal\newcounter\spnTBL
      \doglobal\newcounter\colTBL}%
   \nexttblcol
   \kern\tbltblleftmargindistance
   \kern-\tbltblcolumndistance}

\def\endtblrow
  {\kern-\tbltblcolumndistance
   \kern\tbltblrightmargindistance
   \crcr
   \noalign
     {\nointerlineskip
      \allowbreak
      \bgroup % protect local vars
        \@@tblsplitafter
      \egroup
      \bgroup % protect local vars
        \increment\rowTBL\relax
        \ifnum\rowTBL>\noftblhdnxlines\relax
          \ifnum\rowTBL<\maximumrow\relax
            \doifsomething\tbltblspaceinbetween{\blank[\tbltblspaceinbetween]}%
          \fi
        \fi
      \egroup}}

%\def\begintbl
%  {\doglobal\newcounter\colTBL
%   \doglobal\newcounter\rowTBL
%   \doglobal\decrement\rowTBL
%   \tabskip\zeropoint
%   \halign\bgroup\ignorespaces##\unskip&&\ignorespaces##\unskip\cr}

\def\begintbl
  {\doglobal\newcounter\colTBL
   \doglobal\newcounter\rowTBL
   \doglobal\newcounter\spnTBL
   \doglobal\decrement\rowTBL
   \tabskip\zeropoint
   \halign\bgroup
   \registerparoptions %  new
   \ignorespaces##\unskip&&\ignorespaces##\unskip\cr}

\def\endtbl
  {\egroup}

\setvalue{\tblnone TBL}#1#2%
  {\spanTBL{#1}{#2}}

\setvalue{\tblcell TBL}#1#2%
  {\appendtoks
     \makeTBL{#1}{#2}%    % append nog isoleren
   \to\tbltoks
   \spanTBL{#1}{#2}}

\def\doTBL#1#2%
  {\getvalue{\gettbltag{#1}{#2}TBL}{#1}{#2}}

\def\begTBL
  {\doglobal\newcounter\rowTBL
   \doglobal\newcounter\colTBL
   \doglobal\newcounter\spnTBL
   \chardef\TBLpass\zerocount
   \tbltoks\emptytoks
   \appendtoks
     \begintbl
   \to\tbltoks}

\def\endTBL
  {\appendtoks
     \endtbl
   \to\tbltoks
   \setbox\scratchbox\hbox
     {\localframed
        [\@@tbl\@@tbl]
        [\c!frame=\v!off,\c!background=,\c!align=\v!no]
        {\strut}}%
   \edef\minimalcellheight{\the\ht\scratchbox}%
   \dorecurse\maximumcol
     {\settblaut\recurselevel\!!zeropoint % \zeropoint etc
      % new
      \let\xcol\recurselevel
      \dorecurse\maximumrow
        {\settblwd \recurselevel\xcol\!!zeropoint
         \settblht \recurselevel\xcol\!!zeropoint}%
      % till here
      \settblwid\recurselevel\!!zeropoint
      \settbldis\recurselevel\!!zeropoint}%
   \dorecurse\maximumrow
     {\settblhei\recurselevel\maxdimen}%
   \chardef\TBLpass\plusone
   \let\handleTBLcell\dohandleTBLcellA
   \def\makeTBL##1##2%
     {\gettbltxt{##1}{##2}}%
   \def\inTBLcell##1##2%
     {\ExpandBothAfter\doifinsetelse\localwidth{\v!fit,\v!broad} % user set
        {}
        {\scratchdimen\gettblaut\colTBL\relax
         \ifdim\localwidth>\scratchdimen
           \settblaut\colTBL\localwidth
         \fi}}%
   \setbox0\vbox{\trialtypesettingtrue \the\tbltoks}%
\settbldis\maximumcol{\zeropoint}%
   \ifautoTBLspread
     % experimental, stretch non fixed cells to \hsize
     \checktblwidthsone   % trial run
     \checktblwidthstwo   % real run
     \stretchtblwidths
     \let\handleTBLcell\dohandleTBLcellB
     \setbox\scratchbox\vbox{\trialtypesettingtrue \the\tbltoks}%
   \else\ifdim\wd0>\hsize
     \ifautoTBLhsize
       \checktblwidthsone % trial run
       \checktblwidthstwo % real run
       \let\handleTBLcell\dohandleTBLcellB
       \setbox\scratchbox\vbox{\trialtypesettingtrue \the\tbltoks}%
     \fi
   \else\ifautoTBLrowspan\ifnum\maximumrowspan>1 % max ?
     % added jan 2002 because nx=* did no longer work
\edef\savedhsize{\the\hsize}%
\hsize\wd0\relax % new per 17/04/2006
     \checktblwidthsone % trial run
     \checktblwidthstwo % real run
\hsize\savedhsize
     %
     \let\handleTBLcell\dohandleTBLcellC
     \setbox\scratchbox\vbox{\trialtypesettingtrue \the\tbltoks}%
   \fi\fi\fi\fi
   \let\handleTBLcell\dohandleTBLcellD
   \chardef\TBLpass\plustwo
   \def\makeTBL##1##2% meer in cellD
     {\dimen2\zeropoint
      \globalpushmacro\colTBL
      \dorecurse{\gettblcol{##1}{##2}}
        {\advance\dimen2 \gettblwid\colTBL
         \advance\dimen2 \tbltblcolumndistance
\ifnum\recurselevel<\gettblcol{##1}{##2}\relax \advance\dimen2  \gettbldis\colTBL\fi
         \increment\colTBL}%
      \advance\dimen2 -\tbltblcolumndistance
      \edef\widthTBL{\the\dimen2}%
      \globalpopmacro\colTBL
      \setbox\scratchbox\hbox{\gettbltxt{##1}{##2}}%
      \settblht{##1}{##2}{\the\ht\scratchbox}%
      \settblwd{##1}{##2}{\the\wd\scratchbox}%
      \ifdim\ht\scratchbox>\gettblhei{##1}\relax
        \settblhei{##1}{\the\ht\scratchbox}%
      \fi}%
   \setbox\scratchbox\vbox{\trialtypesettingtrue \the\tbltoks}%
   \checktblheightsone
   \checktblheightstwo
   \let\handleTBLcell\dohandleTBLcellE
   \chardef\TBLpass\plusthree
   \def\makeTBL##1##2%
     {% height
      \globalpushmacro\rowTBL
      \scratchdimen\zeropoint
      \def\rowTBL{##1}%
      \ifnum\gettblcol{##1}{##2}=\maximumcol\relax
        % case: nc=maxcolumns
      \else
        \dorecurse{\gettblrow{##1}{##2}}
          {\advance\scratchdimen \gettblhei\rowTBL
           \increment\rowTBL}%
        \ifdim\scratchdimen<\gettblht{##1}{##2}\relax
          \scratchdimen\gettblht{##1}{##2}\relax
        \fi
      \fi
      \edef\heightTBL{\the\scratchdimen}%
      \globalpopmacro\rowTBL
      % width
      \globalpushmacro\colTBL
      \scratchdimen\zeropoint
      \dorecurse{\gettblcol{##1}{##2}}
        {\advance\scratchdimen \gettblwid\colTBL
         \advance\scratchdimen \tbltblcolumndistance
\ifnum\recurselevel<\gettblcol{##1}{##2}\relax \advance\scratchdimen  \gettbldis\colTBL\fi
         \increment\colTBL}%
      \advance\scratchdimen -\tbltblcolumndistance
      \edef\widthTBL{\the\scratchdimen}%
      \globalpopmacro\colTBL
      % cell
      \setbox\scratchbox\hbox{\gettbltxt{##1}{##2}}%
      \ifnum\gettblcol{##1}{##2}=\maximumcol\relax
        % case: nc=maxcolumns
      \else
        \scratchdimen\gettblhei{##1}%
        \setbox\scratchbox\hbox
          {\lower\ht\scratchbox\hbox{\raise\scratchdimen\box\scratchbox}}%
        \ht\scratchbox\scratchdimen
      \fi
      \dp\scratchbox\zeropoint
      \box\scratchbox}%
    \iftraceTABLE\showtbltoks\fi
    \ifnum\TBLlevel>\plusone
      \@EA\notsplittblbox
    \else\ifenableTBLbreak
      \@EAEAEA\splittblbox
    \else
      \@EAEAEA\notsplittblbox
    \fi\fi{\the\tbltoks}}

\def\stretchtblwidths
  {\ifcase\maximumcol\else % else division by zero
     \!!dimend\zeropoint
     \!!dimene\hsize
     \dorecurse\maximumcol
       {\advance\!!dimend \gettblwid\recurselevel
        \advance\!!dimend \tbltblcolumndistance
        \advance\!!dimene-\gettbldis\recurselevel}%
     \advance\!!dimend-\tbltblcolumndistance
     \advance\!!dimend\tbltblleftmargindistance
     \advance\!!dimend\tbltblrightmargindistance
     % distribute width (stretch)
     \ifdim\!!dimend<\!!dimene
       \advance\!!dimend-\!!dimene
       \!!dimend-\!!dimend
       \divide\!!dimend\maximumcol
       \dorecurse\maximumcol
         {\scratchdimen\gettblwid\recurselevel
          \advance\scratchdimen\!!dimend
          \settblwid\recurselevel{\the\scratchdimen}}%
     \fi
   \fi}

\newbox\finaltblbox

\def\notsplittblbox#1%
  {\setbox\finaltblbox\vbox{#1}%
   \postprocessTABLEbox\finaltblbox
   \beforeTABLEbox
   \box\finaltblbox
   \afterTABLEbox}

% \def\splittblbox#1%
%   {\ifinsidefloat
%      \notsplittblbox{#1}%
%    \else
%      \executeifdefined{splittblbox\tbltblsplitmethod}\splittblboxa{#1}%
%    \fi}

\def\splittblbox#1%
  {\ifinsidesplitfloat
     \donetrue
   \else\ifinsidefloat
     \donefalse
   \else
     \donetrue
   \fi\fi
   \ifdone
     \executeifdefined{splittblbox\tbltblsplitmethod}\splittblboxa{#1}%
   \else
     \notsplittblbox{#1}%
   \fi}

\newbox\TABLEsplitbox % public, don't change

% todo: mode: first|next (of niets)

\def\splittblboxa#1% spacing between rows gets lost in split
  {\setbox\TABLEsplitbox\vbox{#1}%
   \setbox8\vbox{\doifsomething\tbltblspaceinbetween{\blank[\tbltblspaceinbetween]}}%
   \ifmultipleTBLheads
     \setbox2\vbox{}%
     \setbox4\vbox{}%
     \dorecurse\noftblheadlines
       {\setbox0\vsplit\TABLEsplitbox to \lineheight
        \setbox2\vbox{\unvcopy2\unvcopy0}}%
     \dorecurse\noftblnextlines
       {\setbox0\vsplit\TABLEsplitbox to \lineheight
        \setbox4\vbox{\unvcopy4\unvcopy0}}%
     \ifcase\noftblheadlines\else
       \ifdim\pagegoal<\maxdimen
         \dimen0\ht2
         \advance\dimen0\ht8
         \advance\dimen0\pagetotal\relax
         \ifdim\dimen0>\pagegoal
           \bgroup\page\egroup % make sure that local vars are kept
         \fi
       \fi
       \unvcopy2
       \ifcase\noftblnextlines\else
         \setbox2\box4
       \fi
     \fi
   \fi
   \donefalse
   \!!doneafalse
   \doloop
     {\setbox0\vsplit\TABLEsplitbox to \lineheight
      \if!!donea
        \ifdim\pagegoal<\maxdimen
          \setbox0\vbox{\unvbox0}%
          \ifdim\ht0>\zeropoint
            \dimen0\ht0
            \advance\dimen0\ht8
            \advance\dimen0\pagetotal\relax
            \ifdim\dimen0>\pagegoal
              \bgroup\page\egroup % make sure that local vars are kept
              \ifmultipleTBLheads
                \ifcase\noftblheadlines\else\unvcopy2\fi
              \fi
            \fi
          \fi
        \fi
      \fi
      \!!doneatrue
      \ifdone
        \doifsomething\tbltblspaceinbetween{\blank[\tbltblspaceinbetween]}%
      \fi
      \unvbox0
      %\allowbreak
      \bgroup
        % todo: what if tblnextlines ?
        \scratchcounter\recurselevel
        \ifmultipleTBLheads
          \advance\scratchcounter\noftblheadlines
        \fi
        \setupTBLcell{\number\scratchcounter}1
        \ifx\@@tblsplitafter\relax
          \allowbreak
        \else
          \doifelsenothing\@@tblsplitafter
             \allowbreak
            {\scratchcounter\realpageno
             \@@tblsplitafter
             \ifmultipleTBLheads
               \ifnum\scratchcounter<\realpageno
                 \ifcase\noftblheadlines\else\unvcopy2\fi
               \fi
             \fi}%
        \fi
      \egroup
      \ifvoid\TABLEsplitbox \exitloop \else \donetrue \fi}}

\let\extratblsplitheight\zeropoint % additional space taken by before/afterTABLEsplitbox

% \def\splittblboxb#1%
%   {\testpage[2]% quite save since a row is > 1 lineheight and we don't want one-liners
%    \setbox\TABLEsplitbox\vbox{#1}%
%    \setbox8\vbox{\doifsomething\tbltblspaceinbetween{\blank[\tbltblspaceinbetween]}}%
%    \ifmultipleTBLheads
%      \setbox2\vbox{}%
%      \setbox4\vbox{}%
%      \dorecurse\noftblheadlines
%        {\setbox0\vsplit\TABLEsplitbox to \lineheight
%         \setbox2\vbox{\unvcopy2\unvcopy0}}%
%      \dorecurse\noftblnextlines
%        {\setbox0\vsplit\TABLEsplitbox to \lineheight
%         \setbox4\vbox{\unvcopy4\unvcopy0}}%
%    \fi
%    \!!doneafalse
%    \doloop
%      {\ifdim\pagegoal<\maxdimen
%         \scratchdimen\pagegoal
%         \advance\scratchdimen-\pagetotal
%       \else
%         \scratchdimen\textheight
%       \fi
%       \ifmultipleTBLheads
%         \ifcase\noftblheadlines\else
%           \advance\scratchdimen-\ht2
%         \fi
%       \fi
%       \advance\scratchdimen-\ht8
%       \getnoflines\scratchdimen
%       \ifdim\noflines\lineheight>\scratchdimen
%         \advance\scratchdimen-\lineheight
%       \fi
%       \advance\scratchdimen-\extratblsplitheight
%       \setbox\finaltblbox\vbox
%         {\ifmultipleTBLheads
%            \ifcase\noftblheadlines\else
%              \unvcopy2
%              \doifsomething\tbltblspaceinbetween{\blank[\tbltblspaceinbetween]}%
%            \fi
%          \fi
%          \setbox0\vsplit\TABLEsplitbox to\scratchdimen
%          \unvbox0}%
%       \if!!donea\else\ifcase\noftblnextlines\else
%         \setbox2\box4
%       \fi\fi
%       \!!doneatrue
%       \postprocessTABLEsplitbox\finaltblbox
%       \ifvoid\TABLEsplitbox
%         \beforeTABLEsplitbox
%         \box\finaltblbox
%         \afterTABLEsplitbox
%         \@@tblsplitafter
%         \exitloop
%       \else
%        % hack
%         \scratchdimen\pagegoal
%         \ifdim\scratchdimen<\maxdimen
%           \advance\scratchdimen \lineheight
%           \global\pagegoal\scratchdimen
%         \fi
%         % brrr
%         \beforeTABLEsplitbox
%         \box\finaltblbox
%         \afterTABLEsplitbox
%         \@@tblsplitafter
%         \page
%       \fi}}

\def\splittblboxb#1%
  {\scratchdimen-\extratblsplitheight
   \advance\scratchdimen-\tbltblsplitoffset
   \expanded{\testpage[2][\the\scratchdimen]}% quite save since a row is > 1 lineheight and we don't want one-liners
   \setbox\TABLEsplitbox\vbox{#1}%
   \setbox8\vbox{\doifsomething\tbltblspaceinbetween{\blank[\tbltblspaceinbetween]}}%
   \dimen8\ht8\advance\dimen8\dp8
   \ifmultipleTBLheads
     \setbox2\vbox{}%
     \setbox4\vbox{}%
     \dorecurse\noftblheadlines
       {\setbox0\vsplit\TABLEsplitbox to \lineheight
        \setbox2\vbox{\unvcopy2\unvcopy0}}%
     \dorecurse\noftblnextlines
       {\setbox0\vsplit\TABLEsplitbox to \lineheight
        \setbox4\vbox{\unvcopy4\unvcopy0}}%
   \fi
   \!!doneafalse
   \doloop
     {\ifdim\pagegoal<\maxdimen
        \scratchdimen\pagegoal
        \advance\scratchdimen-\pagetotal
        \!!donecfalse
      \else
        \scratchdimen\textheight
        \!!donectrue
      \fi
      \advance\scratchdimen-\dimen8
      \advance\scratchdimen-\extratblsplitheight
      \advance\scratchdimen-\tbltblsplitoffset
      \setbox\finaltblbox\vbox
        {\ifmultipleTBLheads
           \ifcase\noftblheadlines\else
             \unvcopy2 \doifsomething\tbltblspaceinbetween{\blank[\tbltblspaceinbetween]}%
           \fi
         \fi}%
      \if!!donea\else\ifcase\noftblnextlines\else
        \setbox2\box4
      \fi\fi
      \!!doneatrue
      % alternatively we could use a kind of balancing like splitter
      % first to scratchdimen and then smaller etc; more code and copy -)
      \!!counta\zerocount
      \doloop
        {\setbox\scratchbox\vsplit\TABLEsplitbox to \onepoint
         \setbox\scratchbox\vbox{\unvbox\scratchbox}%
         \bgroup
         \advance\scratchdimen-\ht\scratchbox
         \advance\scratchdimen-\dp\scratchbox
         \advance\scratchdimen-\ht\finaltblbox
         \advance\scratchdimen-\dp\finaltblbox\relax
         \ifdim\scratchdimen>\zeropoint
           \egroup
           \setbox\finaltblbox\vbox
              {\unvbox\finaltblbox
               \unvbox\scratchbox}%
           \ifvoid\TABLEsplitbox \exitloop \fi
         \else\if!!donec
           % we have text height available, but the (one) cell is too
           % large to fit, so, in order to avoid loops/deadcycles we do:
           \egroup
           \setbox\finaltblbox\vbox
              {\unvbox\finaltblbox
               \unvbox\scratchbox}%
           \exitloop
         \else
           \egroup
           \setbox\TABLEsplitbox\vbox
              {\unvbox\scratchbox
               \ifvoid\TABLEsplitbox\else\unvbox\TABLEsplitbox\allowbreak\fi}%
           \exitloop
         \fi\fi}%
      %
      \postprocessTABLEsplitbox\finaltblbox
      \ifvoid\TABLEsplitbox
        \beforeTABLEsplitbox
        \box\finaltblbox
        \afterTABLEsplitbox
        \@@tblsplitafter
        \exitloop
      \else
        % hack
        \ifdim\pagegoal<\maxdimen
          \scratchdimen\pagegoal
          \advance\scratchdimen \lineheight
          \global\pagegoal\scratchdimen
        \fi
        % brrr
        \ifdim\ht\finaltblbox>\zeropoint
          \beforeTABLEsplitbox
          \box\finaltblbox
          \afterTABLEsplitbox
          \@@tblsplitafter
        \fi
        \page
      \fi}}

% ! ! ! ! TODO: naast \postprocessTABLEsplitbox ook evt \postprocessTABLEbox voor niet split

\let\postprocessTABLEsplitbox\gobbleoneargument
\let\postprocessTABLEbox     \gobbleoneargument

\let\beforeTABLEsplitbox\relax
\let\afterTABLEsplitbox \relax
\let\beforeTABLEbox     \relax
\let\afterTABLEbox      \relax

\def\checktblwidthsone{\dochecktblwidths0} % 0 = trial run
\def\checktblwidthstwo{\dochecktblwidths1} % 1 = real run

\def\dochecktblwidths#1%
  {\iftraceTABLE\showtblwids{B#1}\fi
   \!!dimena\hsize
   \!!counta\zerocount
   \dorecurse\maximumcol
     {\scratchdimen\gettblaut\recurselevel\relax
% test: \advance\!!dimena-\gettbldis\recurselevel\relax
      \ifdim\scratchdimen>\zeropoint\relax
        \advance\!!dimena -\scratchdimen
      \else
        \scratchdimen\gettblwid\recurselevel\relax
        \ifdim\scratchdimen>\tbltblmaxwidth\relax
          \ifcase#1\else\settblwid\recurselevel\!!zeropoint\fi
          \advance\!!counta \plusone
        \else
          \ifdim\scratchdimen>\zeropoint\relax
            \advance\!!dimena -\scratchdimen
          \else
            % eigenlijk moet dit alleen als de kolom wordt overspannen door een
            % vorige, maw extra dubbele loop en status var
            \advance\!!counta \plusone
          \fi
        \fi
      \fi}%
   \ifcase\!!counta \else \divide\!!dimena \!!counta \fi
   \dorecurse\maximumcol
     {\scratchdimen\gettblwid\recurselevel\relax
      \ifcase#1\relax
        \ifdim\scratchdimen<\!!dimena  % take natural width
          \settblaut\recurselevel{\the\scratchdimen}%
        \fi
      \else
        \ifdim\scratchdimen=\zeropoint % auto set width
          \settblwid\recurselevel{\the\!!dimena}%
        \fi
      \fi}%
   \iftraceTABLE\showtblwids{E#1}\fi}

\def\checktblheightsone
  {\dorecurse\maximumrow
     {\let\xrowTBL\recurselevel
      \dorecurse\maximumcol
        {\let\xcolTBL\recurselevel
         \!!countb=0\gettblrow\xrowTBL\xcolTBL\relax
         % check row span
         \ifnum\!!countb>1
           % current height in row
           \dimen0=\gettblht\xrowTBL\xcolTBL
           % find nearest height in row
           \dimen2=\zeropoint
           \dorecurse\maximumcol
             {\ifnum\recurselevel=\xcolTBL\else
                \!!countc=0\gettblrow\xrowTBL\recurselevel\relax
                \ifnum\!!countc=\plusone
                  \dimen4=\gettblht\xrowTBL\recurselevel\relax
                  \ifdim\dimen2<\dimen4
                    \dimen2=\dimen4
                  \fi
                \fi
              \fi}%
           \let\xxrowTBL\xrowTBL
           % calculate cummulative height
           \dimen4=\dimen2
           \dorecurse\!!countb
             {\ifnum\xxrowTBL=\xrowTBL\else
                \advance\dimen4 \gettblhei\xxrowTBL
              \fi
              \increment\xxrowTBL}%
           % distribute overshoot equally
           \ifdim\dimen4<\dimen0
             \advance\dimen0 -\dimen4
             \divide\dimen0 \!!countb
             \let\xxrowTBL\xrowTBL
             \settblhei\xrowTBL{\the\dimen2}%
             \dorecurse\!!countb
               {\dorecurse\maximumcol
                  {\ifnum\recurselevel=\xcolTBL\else
                     \scratchdimen\gettblht\xxrowTBL\recurselevel
                     \advance\scratchdimen \dimen0
                     \settblht\xxrowTBL\recurselevel{\the\scratchdimen}%
                     \ifdim\gettblhei\xxrowTBL<\scratchdimen
                       \settblhei\xxrowTBL{\the\scratchdimen}%
                     \fi
                   \fi}%
                \increment\xxrowTBL}%
           \else\ifdim\dimen4>\dimen0
             \settblhei\xrowTBL{\the\dimen2}%
           \fi\fi
         \fi}}}

\def\checktblheightstwo
  {}

\def\showtblwids#1%
  {\vbox
     {\forgetall\tttf[#1]\dorecurse\maximumcol
        {\scratchdimen\gettblwid\recurselevel
         [\recurselevel:\the\scratchdimen]}}}

\def\showtbltoks
  {\vbox
     {\forgetall\tttf
      \let\begintbl   \relax  \let\endtbl    \relax
      \let\begintblrow\par    \let\endtblrow \par
      \def\nexttblcol {[next]}\def\spantblcol{[span]}
      \def\makeTBL##1##2{[##1,##2]}
      \the\tbltoks}}

\def\TBLcharalign
  {\doifelse\tbltblaligncharacter\v!yes
     \doTBLcharalign\gobbleoneargument}

\long\def\doTBLcharalign#1#2% column data
  {\edef\alignmentclass{#1}%
   \edef\alignmentcharacter{\tbltblalignmentcharacter}%
   \ifcase\TBLpass\or
     \setfirstpasscharacteralign\checkalignment{#2}% {\strut#2\unskip}%
   \fi % force hsize, so always a second
   \setsecondpasscharacteralign \checkalignment{#2}% {\strut#2\unskip}%
   \ignorespaces}

% new, needed for icare first col of 'doeltabel', experimental

\long\def\dohandleTBLcellA#1#2[#3]#4% grouping added ! ! !
  {\bgroup
   \setupTBLcell{#1}{#2}%
   \setbox\scratchbox\hbox
     {\scratchdimen\tbltbldistance\relax
      \ifdim\scratchdimen>\gettbldis{#2}\relax
        \settbldis{#2}{\the\scratchdimen}%
      \fi
      \localframed
        [\@@tbl\@@tbl]
        [#3,\c!background=,\c!frame=\v!off]% 25% faster
        {\bTBLCELL\TBLcharalign{#2}{#4}\eTBLCELL\inTBLcell{#1}{#2}}}%
   \scratchdimen\gettblwid\colTBL\relax
   \ifdim\wd\scratchbox>\scratchdimen
     \ifsqueezeTBLspan
       \ifautosqueezeTBLspan
         \doifinsetelse\tbltblwidth{\v!fit,\v!fixed,\v!broad,\v!local}
           \donetrue \donefalse
       \else
         \donetrue
       \fi
       \ifdone
         \ifnum0\number\gettblcol{#1}{#2}>1\relax \settblspn\colTBL \fi
       \fi
     \fi
     \doifelsetblspn\colTBL
       \donothing
       {\ifdim\gettblwid\colTBL<\wd\scratchbox
          \settblwid\colTBL{\the\wd\scratchbox}%
        \fi}% auto set
   \fi
   \let\rowTBLx\rowTBL\increment\rowTBLx
   \scratchdimen\gettblhei\rowTBLx\relax
   \ifdim\ht\scratchbox<\scratchdimen
     \settblhei\rowTBLx{\the\ht\scratchbox}% auto set
   \fi
   \settblht{#1}{#2}{\the\ht\scratchbox}%
   \settblwd{#1}{#2}{\the\wd\scratchbox}%
   \ifautoTBLcheckwidth
     \ifdim\wd\scratchbox<.75\hsize
       \ifdim\ht\scratchbox>2\openlineheight % honor width since this
         \scratchdimen\gettblaut\colTBL\relax % can be a figure or so
         \ifdim\scratchdimen=\zeropoint
           % side effect: when width is set to 0pt,
           % we can force a span that fits the sum of spans widths
           \settblaut\colTBL{\the\scratchdimen}%
         \else\ifdim\wd\scratchbox>\scratchdimen
           % unless span
           \settblaut\colTBL{\the\wd\scratchbox}%
           % to be translated
           \writestatus\m!TABLE
             {no auto width in (\number#1,\number#2)\space\the\wd\scratchbox/\the\hsize}%
         \fi\fi
       \fi
     \fi
   \fi
   \setbox2\null
   \wd2\wd\scratchbox \ht2\ht\scratchbox \dp2\dp\scratchbox
   \box2
   \egroup}

\long\def\dohandleTBLcellBC#1#2#3[#4]#5%
  {\setbox\scratchbox\hbox
     {\setupTBLcell{#2}{#3}%
      \localframed
        [\@@tbl\@@tbl]
        [#4,#1,\c!frame=\v!off,\c!background=]
        {\bTBLCELL#5\eTBLCELL}}%
   \setbox2\null
   \wd2\wd\scratchbox \ht2\ht\scratchbox \dp2\dp\scratchbox
   \ifautoTBLrowspan
     \let\rowTBLx\rowTBL\increment\rowTBLx
     \scratchdimen\gettblhei\rowTBLx\relax
     \ifnum\gettblrow\rowTBLx\colTBL>1 \ifdim\ht\scratchbox>\scratchdimen
       \scratchdimen-\scratchdimen \advance\scratchdimen -\ht\scratchbox
       \ht2\scratchdimen
     \fi \fi
   \fi
   \box2 }

\long\def\dohandleTBLcellB#1#2[#3]#4%
   {\scratchdimen\gettblaut\colTBL\relax
    \ifdim\scratchdimen>\zeropoint\relax
      \let\tblwidthkey\c!width \edef\tblwidth{\the\scratchdimen}%
    \else
      \scratchdimen\gettblwid\colTBL\relax
      \ifdim\scratchdimen>\zeropoint\relax
        \ifnum\gettblcol{#1}{#2}=\maximumcol\relax
          \scratchdimen\hsize
        \fi
        \let\tblwidthkey\c!width \edef\tblwidth{\the\scratchdimen}%
      \else
        \let\tblwidthkey\s!unknown \let \tblwidth \!!zeropoint
      \fi
    \fi
    \dohandleTBLcellBC{\tblwidthkey=\tblwidth}{#1}{#2}[#3]{\TBLcharalign{#2}{#4}}}

\long\def\dohandleTBLcellC
  {\dohandleTBLcellBC{}}

\long\def\dohandleTBLcellD#1#2[#3]#4%
  {\setupTBLcell{#1}{#2}%
   \bgroup
   \localframed
     [\@@tbl\@@tbl]
     [#3,\c!width=\widthTBL,\c!background=,\c!frame=\v!off]% 25% faster
     {\bTBLCELL\TBLcharalign{#2}{#4}\eTBLCELL}%
   \egroup}

\long\def\dohandleTBLcellE#1#2[#3]#4%
  {\setupTBLcell{#1}{#2}%
   \getparameters[\@@tbl\@@tbl][#3]% to get the color right, the way we
   \color % handle color here prevents interference due to whatsit nodes
     [\tbltblcolor] % as well as permits local colors to take precedence
     {\ifdim\heightTBL=\zeropoint\relax % case: nc=maxcolumns
        \localframed
          [\@@tbl\@@tbl]
          [\c!color=,\c!width=\widthTBL]
          {\bTBLCELL\TBLcharalign{#2}{#4}\eTBLCELL}%
      \else
        \localframed
          [\@@tbl\@@tbl]
          [\c!color=,\c!width=\widthTBL,\c!height=\heightTBL]
          {\bTBLCELL\TBLcharalign{#2}{#4}\eTBLCELL}%
      \fi}%
   \hskip\gettbldis{#2}}

\setupTABLE
  [\c!frameoffset=.5\linewidth,
   \c!backgroundoffset=\v!frame,
   \c!framecolor=\s!black,
   \c!color=,
   \c!style=,
   \c!headstyle=\v!bold,
   \c!headcolor=,
   \c!strut=\v!yes,
   \c!autostrut=\v!no,
   \c!aligncharacter=\v!no,
   \c!alignmentcharacter={,},
   \c!option=, % \v!stretch
   \c!header=,
   \c!spaceinbetween=,
   \c!maxwidth=8em,
   \c!textwidth=\hsize,
   \c!split=\v!no,
   \c!splitoffset=0pt,
   \c!distance=\zeropoint,           % individual column
   \c!columndistance=\zeropoint,     % each column (whole table)
   \c!leftmargindistance=\zeropoint, % whole table
   \c!rightmargindistance=\zeropoint,% whole table
   \c!splitmethod=a]

%D We have already prepared the previous macros for nesting,
%D so we only have to pop in the right ones:

%D Redefined:

\newcounter\TBLlevel

\def\@@tblprefix{\@@tbl:\ifnum\TBLlevel>1 :\TBLlevel:\fi}

\long\def\settbltxt#1#2#3%
  {\setxvalue{\@@tblprefix#1:#2:l}{\TBLlevel}%
   \long\setvalue{\@@tblprefix#1:#2:t}%
     {\doifdefined{\@@tblprefix#1:#2:l}
        {\edef\TBLlevel{\getvalue{\@@tblprefix#1:#2:l}}}%
      #3}}

\def\gettbltxt#1#2%
  {\getvalue{\@@tblprefix#1:#2:t}}

%D New:

\def\pushTBLparameters
  {\globalpushmacro\TBLlevel
   \ifcase\TBLpass
     % we're just after \bTABLE
   \else\ifnum\TBLlevel>\zerocount
     \doglobal\increment\TBLlevel\relax
   \fi\fi}

\def\popTBLparameters
  {\globalpopmacro\TBLlevel}

\def\pushTBL
  {\ifnum\TBLlevel=\zerocount
     \doglobal\increment\currenttbl\relax
   \fi
   \doglobal\increment\TBLlevel\relax
   \ifnum\TBLlevel>\plusone
     \resetallTABLEparameters
     \globalpushmacro\colTBL
     \globalpushmacro\rowTBL
   \else
     \global\intabletrue
   \fi}

\def\popTBL
  {\ifnum\TBLlevel>\plusone
     \globalpopmacro\rowTBL
     \globalpopmacro\colTBL
   \else
     \global\intablefalse
   \fi
   \doglobal\decrement\TBLlevel\relax}

\newconditional\resetTABLEmode \settrue\resetTABLEmode

\def\resetallTABLEparameters% moet genest wel werken
  {\ifnum\TBLlevel>\plusone % in ieder geval
     \ifconditional\resetTABLEmode
       \presetlocalframed   % breedte hoogte diepte offset
         [\@@tbl\@@tbl]%    % achtergrond, achtergrondraster, achtergrondkleur
       % not ok yet
       \setupTABLE
         [\c!frameoffset=.5\linewidth,
          \c!backgroundoffset=\v!frame,
          \c!framecolor=\s!black,
          \c!color=,
          \c!style=,
          \c!headstyle=,
          \c!headcolor=,
          \c!strut=\v!no,
          \c!aligncharacter=\v!no,
          \c!alignmentcharacter={,},
          \c!maxwidth=8em]%
     \else
       \setupTABLE
         [\c!width=\v!fit,
          \c!height=\v!fit]%
     \fi
  \fi}

%D Spacing:
%
% \starttabulate
% \NC text \NC text \NC \NR
% \TB[small]
% \NC text \NC text \NC \NR
% \TB[4*big]
% \NC text \NC text \NC \NR
% \stoptabulate
%
% \starttable[|||]
% \VL text \VL text \VL \AR
% \TB[small]
% \VL text \VL text \VL \AR
% \TB[4*big]
% \VL text \VL text \VL \AR
% \stoptable

\def\complexTableTB[#1]{\TABLEnoalign{\blank[#1]}}
\def\simpleTableTB     {\TABLEnoalign{\blank}}

\def\TabulateTB
  {\complexorsimpleTable{TB}}

\def\doTableinterline% #1
  {\ifnum\currentTABLEcolumn>\maxTABLEcolumn
     \chuckTABLEautorow
   \else\ifnum\currentTABLEcolumn=\zerocount
     \TABLEnoalign
       {\globalletempty\checkTABLEautorow
        \globalletempty\chuckTABLEautorow}%
   \else
     \setTABLEerror\TABLEmissingcolumn
     \handleTABLEerror
   \fi\fi
   \complexorsimpleTable} % {#1}

\def\TableHL{\doTableinterline{HL}}
\def\TableTB{\doTableinterline{TB}}

\appendtoks\let\TB\TableTB   \to\everytable
\appendtoks\let\TB\TabulateTB\to\everytabulate % strange place

\appendtoks \chardef\recodeverbatimmode\plustwo \to \everytable

% new (for Olivier Turlier)
%
% \defineTABLEsetup [xx] [foregroundcolor=red]
%
% \bTABLE
%     \bTR      \bTD      oeps \eTD  \bTD oeps \eTD \eTR
%     \bTR      \bTDs[xx] oeps \eTDs \bTD oeps \eTD \eTR
%     \bTRs[xx] \bTD      oeps \eTD  \bTD oeps \eTD \eTRs
% \eTABLE

\def\defineTABLEsetup
  {\dodoubleargument\dodefineTABLEsetup}

\def\dodefineTABLEsetup[#1][#2]%
  {\setvalue{\@@tbl:set:#1}{#2}}

\long\def\bTDs[#1]#2\eTDs
  {\doifdefinedelse{\@@tbl:set:#1}
     {\@EA\@EA\@EA\bTD\@EA\@EA\@EA[\csname\@@tbl:set:#1\endcsname]#2\eTD}
     {\bTD[]#2\eTD}}

\long\def\bTRs[#1]#2\eTRs
  {\doifdefinedelse{\@@tbl:set:#1}
     {\@EA\@EA\@EA\bTR\@EA\@EA\@EA[\csname\@@tbl:set:#1\endcsname]#2\eTR}
     {\bTR[]#2\eTR}}

\protect \endinput
