tabl-ntb.mkii / last modification: 2019-12-06 19:53
%D \module
%D   [       file=core-ntb,
%D        version=2000.04.18,
%D          title=\CONTEXT\ Table Macros,
%D       subtitle=Natural Tables,
%D         author=Hans Hagen,
%D           date=\currentdate,
%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
%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. Ugly code.

% todo: special parsetb for argless variant
% todo: protect \tbl...
% todo: tblnx also count
% todo: get rid of recurse
% todo: fast if
% todo: avoid halign (just do it manual) and thereby globals

% optie=rek beschrijven

\writestatus{loading}{ConTeXt Table 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).

% shapebox fails here in mkii
%
% \setupcolors[state=start]
% \bTABLE
% \bTR [align=middle]\bTH Range\eTH{}\bTH Value\eTH{}\eTR
% \bTR \bTD \type{<} 12\eTD{}\bTD 3\eTD{}\eTR
% \bTR \bTD 12--16\eTD{}\bTD 2\eTD{}\eTR
% \bTR \bTD \type{>}16\eTD{}\bTD 1\eTD{}\eTR
% \eTABLE

% \starttext
%     \placefigure[left]{}{}
%     \startlinecorrection \dontleavehmode \bTABLE
%         \bTR  \bTD oeps \eTD  \eTR
%         \eTABLE
%     \stoplinecorrection
%     \placefigure[right]{}{}
%     \startlinecorrection \dontleavehmode \bTABLE
%         \bTR  \bTD oeps \eTD  \eTR
%         \eTABLE
%     \stoplinecorrection
% \stoptext

%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}

%D \startbuffer
%D \bTABLE[left={(},right={)},top=\startnarrower,bottom=\stopnarrower]
%D \bTR \bTD something \eTD \eTR
%D \eTABLE
%D \stopbuffer
%D
%D \typebuffer \getbuffer

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

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

\newcount\currenttbl

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

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

%D This should be done more efficient: soon

% \let as well as \expandafter\edef's

\newcounter\TBLlevel

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

% \def\tblsetprefix % not yet used, figure out when .. may interfere with setup
%   {\edef\@@tblprefix{\@@tbl:\ifnum\TBLlevel>1 :\TBLlevel:\fi}}

\def\settblnob#1{\expandafter\let\csname\@@tblprefix\number#1:b\endcsname\plusone}
\def\gettblnob#1{\ifcsname\@@tblprefix\number#1:b\endcsname\plusone\else\zerocount\fi}

\def\settbltag#1#2{\expandafter\edef\csname\@@tblprefix\number#1:\number#2:s\endcsname}
\def\settblcol#1#2{\expandafter\edef\csname\@@tblprefix\number#1:\number#2:c\endcsname}
\def\settblrow#1#2{\expandafter\edef\csname\@@tblprefix\number#1:\number#2:r\endcsname}

\def\lettbltag#1#2{\expandafter\let\csname\@@tblprefix\number#1:\number#2:s\endcsname}
\def\lettblcol#1#2{\expandafter\let\csname\@@tblprefix\number#1:\number#2:c\endcsname}
\def\lettblrow#1#2{\expandafter\let\csname\@@tblprefix\number#1:\number#2:r\endcsname}

\def\settblwd#1#2{\expandafter\xdef\csname\@@tblprefix\number#1:\number#2:wd\endcsname} % global !
\def\settblht#1#2{\expandafter\xdef\csname\@@tblprefix\number#1:\number#2:ht\endcsname} % global !
\def\lettblwd#1#2{\global\expandafter\let\csname\@@tblprefix\number#1:\number#2:wd\endcsname} % global !
\def\lettblht#1#2{\global\expandafter\let\csname\@@tblprefix\number#1:\number#2:ht\endcsname} % global !

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

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

\def\settblwid#1{\expandafter\xdef\csname\@@tblprefix\number#1:w\endcsname} % {#2} global !
\def\settblhei#1{\expandafter\xdef\csname\@@tblprefix\number#1:h\endcsname} % {#2} global !
\def\settbldis#1{\expandafter\xdef\csname\@@tblprefix\number#1:d\endcsname} % {#2} global !
\def\settblaut#1{\expandafter\xdef\csname\@@tblprefix\number#1:a\endcsname} % {#2} global !

\def\lettblwid#1{\global\expandafter\let\csname\@@tblprefix\number#1:w\endcsname} % {#2} global !
\def\lettblhei#1{\global\expandafter\let\csname\@@tblprefix\number#1:h\endcsname} % {#2} global !
\def\lettbldis#1{\global\expandafter\let\csname\@@tblprefix\number#1:d\endcsname} % {#2} global !
\def\lettblaut#1{\global\expandafter\let\csname\@@tblprefix\number#1:a\endcsname} % {#2} global !

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

\def\doiftbltag    #1#2{\ifcsname\@@tblprefix\number#1:\number#2:s\endcsname\@EA\firstofoneargument \else\@EA\gobbleoneargument   \fi}
\def\doifnottbltag #1#2{\ifcsname\@@tblprefix\number#1:\number#2:s\endcsname\@EA\gobbleoneargument  \else\@EA\firstofoneargument  \fi}
\def\doifelsetbltag#1#2{\ifcsname\@@tblprefix\number#1:\number#2:s\endcsname\@EA\firstoftwoarguments\else\@EA\secondoftwoarguments\fi}
\def\doiftblrow    #1#2{\ifcsname\@@tblprefix\number#1:\number#2:r\endcsname\@EA\firstofoneargument \else\@EA\gobbleoneargument   \fi}
\def\doiftblcol    #1#2{\ifcsname\@@tblprefix\number#1:\number#2:c\endcsname\@EA\firstofoneargument \else\@EA\gobbleoneargument   \fi}
\def\doifnottblcol #1#2{\ifcsname\@@tblprefix\number#1:\number#2:c\endcsname\@EA\gobbleoneargument  \else\@EA\firstofoneargument  \fi}

\def\tbltagstate#1#2{\ifcsname\@@tblprefix\number#1:\number#2:s\endcsname\zerocount\else\plusone\fi}
\def\tblrowstate#1#2{\ifcsname\@@tblprefix\number#1:\number#2:r\endcsname\zerocount\else\plusone\fi}
\def\tblcolstate#1#2{\ifcsname\@@tblprefix\number#1:\number#2:c\endcsname\zerocount\else\plusone\fi}

\def\settblspn     #1{\expandafter\let\csname\@@tblprefix\number#1:s\endcsname \!!plusone}
\def\doifelsetblspn#1{\doifelse      {\csname\@@tblprefix\number#1:s\endcsname}\!!plusone}
% \def\doifelsetblspn#1{\@EA\ifx\csname\@@tblprefix\number#1:s\endcsname\plusone\@EA\firstoftwoarguments\else\@EA\secondoftwoarguments\fi}

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

% \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}}

\long\def\settbltxt#1#2#3%
  {\long\@EA\def\csname\@@tblprefix\number#1:\number#2:t\@EA\endcsname\@EA{\@EA\def\@EA\TBLlevel\@EA{\TBLlevel}#3}}

\def\gettbltxt#1#2%
  {\csname\@@tblprefix\number#1:\number#2:t\endcsname}

\newtoks\tbltoks
\newtoks\tblrowtoks

\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

% % \setupTABLE [y]    [first][background=color,backgroundcolor=blue,frame=off,bottomframe=on,topframe=on,framecolor=white]
% \setupTABLE [first][first][backgroundcorner=2,corner=10,frame=on]
% \setupTABLE [last] [first][backgroundcorner=4,corner=12,frame=on]
%
% \setupTABLE [row]  [each] [background=color,backgroundcolor=blue,frame=on,framecolor=white]
% \setupTABLE [first][2]    [corner=8]
% \setupTABLE [last] [2]    [corner=5]
% \setupTABLE [first][last] [corner=7]
% \setupTABLE [last] [last] [corner=6]
%
% \startTEXpage
% \bTABLE[frame=off,align=middle]
% \bTR \bTD one   \eTD \bTD two    \eTD \bTD three \eTD \eTR
% \bTR \bTD first \eTD \bTD second \eTD \bTD third \eTD \eTR
% \bTR \bTD alpha \eTD \bTD beta   \eTD \bTD gamma \eTD \eTR
% \eTABLE
% \stopTEXpage
%
% \setupTABLE [first] [two][corner=2] % special case
% \setupTABLE [last]  [two][corner=4] % special case
%
% % % \setupTABLE [one] [first] ... special case of span
%
% \startTEXpage
% \bTABLE[frame=off,align=middle]
% \bTR \bTD one   \eTD \bTD two    \eTD \bTD three \eTD \eTR
% \bTR \bTD first \eTD \bTD second \eTD \bTD third \eTD \eTR
% \eTABLE
% \stopTEXpage

\def\setupTBLcell#1#2% cell over col over row
  {\setupTBLsection % already forgotten
   \edef\positiverow{\number#1}%
   \edef\positivecol{\number#2}%
   \edef\negativerow{\the\numexpr-\maximumrow+#1+\minusone\relax}%
   \edef\negativecol{\the\numexpr-\maximumcol+#2+\minusone\relax}%
   % each each
   \csname\@@tblprefix\c!x\v!each\c!y\v!each\endcsname
   \csname\@@tblprefix\c!y\v!each\endcsname
   \csname\@@tblprefix\c!x\v!each\endcsname
   % odd even
   \csname\@@tblprefix\c!y\v!oddeven\positiverow\endcsname
   \csname\@@tblprefix\c!x\v!oddeven\positivecol\endcsname
   \csname\@@tblprefix\c!x\v!oddeven\positivecol\c!y\v!oddeven\positiverow\endcsname
   % row/col number combinations
   \ifcsname\@@tblprefix\c!y\positiverow\endcsname\csname\@@tblprefix\c!y\positiverow\endcsname\fi
   \ifcsname\@@tblprefix\c!y\negativerow\endcsname\csname\@@tblprefix\c!y\negativerow\endcsname\fi
   \csname\@@tbl\@@tbl\c!extras\endcsname
   \@EA\let\csname\@@tbl\@@tbl\c!extras\endcsname\relax % new, see x-fo
   \ifcsname\@@tblprefix\c!x\positivecol\endcsname\csname\@@tblprefix\c!x\positivecol\endcsname\fi
   \ifcsname\@@tblprefix\c!x\negativecol\endcsname\csname\@@tblprefix\c!x\negativecol\endcsname\fi
   \csname\@@tbl\@@tbl\c!extras\endcsname
   \@EA\let\csname\@@tbl\@@tbl\c!extras\endcsname\relax % new, see x-fo
   % first/last combinations
   \ifnum\positiverow=\plusone
     \csname\@@tblprefix\c!y\v!first\endcsname
     \ifcsname\@@tblprefix\c!x\positivecol\c!y\v!first\endcsname\csname\@@tblprefix\c!x\positivecol\c!y\v!first\endcsname\fi
   \fi
   \ifnum\positivecol=\plusone
     \csname\@@tblprefix\c!x\v!first\endcsname
     \ifcsname\@@tblprefix\c!x\v!first\c!y\positiverow\endcsname\csname\@@tblprefix\c!x\v!first\c!y\positiverow\endcsname\fi
   \fi
   \ifnum\positiverow=\maximumrow\relax
     \csname\@@tblprefix\c!y\v!last\endcsname
     \ifcsname\@@tblprefix\c!x\positivecol\c!y\v!last\endcsname\csname\@@tblprefix\c!x\positivecol\c!y\v!last\endcsname\fi
   \fi
   \ifnum\positivecol=\maximumcol\relax
     \csname\@@tblprefix\c!x\v!last\endcsname
     \ifcsname\@@tblprefix\c!x\v!last\c!y\positiverow\endcsname\csname\@@tblprefix\c!x\v!last\c!y\positiverow\endcsname\fi
   \fi
   \ifnum\positiverow=\maximumrow\relax \ifnum\positivecol=\maximumcol\relax
     \csname\@@tblprefix\c!x\v!last\c!y\v!last\endcsname
   \fi\fi
   \ifnum\positiverow=\plusone \ifnum\positivecol=\plusone
     \csname\@@tblprefix\c!x\v!first\c!y\v!first\endcsname
   \fi\fi
   \ifnum\positiverow=\plusone \ifnum\positivecol=\maximumcol\relax
     \csname\@@tblprefix\c!x\v!last\c!y\v!first\endcsname
   \fi\fi
   \ifnum\positiverow=\maximumrow\relax \ifnum\positivecol=\plusone
     \csname\@@tblprefix\c!x\v!first\c!y\v!last\endcsname
   \fi\fi
   % special case: two rows and last row : two&first and two&last (round corners)
   \ifnum\maximumrow=\plustwo\relax
     \ifnum\positiverow=\maximumrow\relax \ifnum\positivecol=\plusone
       \csname\@@tblprefix\c!x\v!first\c!y\v!two\endcsname
     \fi\fi
     \ifnum\positiverow=\maximumrow\relax \ifnum\positivecol=\maximumcol\relax
       \csname\@@tblprefix\c!x\v!last\c!y\v!two\endcsname
     \fi\fi
   \fi
   \ifnum\gettblcol\positiverow\positivecol=\maximumcol\relax % top span over whole width
     \ifnum\positiverow=\plusone
       \csname\@@tblprefix\c!x\v!one\c!y\v!first\endcsname
     \fi
     \ifnum\positiverow=\maximumrow\relax
       \csname\@@tblprefix\c!x\v!one\c!y\v!last\endcsname
     \fi
   \fi
   % header things
   \ifnum#1>\noftblhdnxlines\else
     \ifcsname\@@tblprefix\v!header\v!each     \endcsname\csname\@@tblprefix\v!header\v!each     \endcsname\fi
     \ifcsname\@@tblprefix\v!header\positivecol\endcsname\csname\@@tblprefix\v!header\positivecol\endcsname\fi
   \fi
   % explicit cells
   \ifcsname\@@tblprefix\c!x\positivecol\c!y\positiverow\endcsname\csname\@@tblprefix\c!x\positivecol\c!y\positiverow\endcsname\fi
   \ifcsname\@@tblprefix\c!x\negativecol\c!y\negativerow\endcsname\csname\@@tblprefix\c!x\negativecol\c!y\negativerow\endcsname\fi
   % done
   \global\letcscsname\@@tblsplitafter   \csname\@@tbl\@@tbl\c!after   \endcsname
   \global\letcscsname\@@tblsplitbefore  \csname\@@tbl\@@tbl\c!before  \endcsname
   \global\letcscsname\@@tblsplitsamepage\csname\@@tbl\@@tbl\c!samepage\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
\globallet\@@tblsplitbefore  \relax
\globallet\@@tblsplitsamepage\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

% todo: protect counters

\newcount\row        \newcount\col
\newcount\xrow       \newcount\xcol
\newcount\xxrow      \newcount\xxcol
\newcount\maximumrow \newcount\maximumcol \newcount\maximumrowspan
                     \newcount\currentcol
\newcount\tblspn

\def\parseTR[#1][#2]% [#2] is dummy that kills spaces / no #3 argument
  {\currentcol\zerocount
   \advance\maximumrow\plusone
   \iffirstargument\setTABLEparameters[\c!y\number\maximumrow][#1]\fi}

\def\settblref#1#2{\expandafter\xdef\csname\@@tblprefix\number#1:\number#2:x\endcsname}
\def\gettblref#1#2{\ifcsname\@@tblprefix\number#1:\number#2:x\endcsname\csname\@@tblprefix\number#1:\number#2:x\endcsname\fi}

\long\def\parseTD[#1][#2]#3\eTD % [#2] is dummy that kills spaces
  {\def\tblny{\tblnr}%
   \def\tblnx{\tblnc}%
   \let\tblnc\plusone
   \let\tblnr\plusone
   \let\tbln\currentcol
   \let\tblm\empty
   \iffirstargument
     \getparameters[\@@tbl][#1]%
   \fi
   % goto first cell % NEW, n/m=cellnumber
   \edef\@@tblnindeed{\csname\@@tbl\c!n\endcsname}%
   \ifx\@@tblnindeed\empty
     \global\advance\tblspn\tblnx\relax
   \else\ifnum\@@tblnindeed=\currentcol\else
      \scratchcounter\numexpr\@@tblnindeed-\currentcol+\minusone-\tblspn\relax
      \ifnum\scratchcounter>\zerocount
        \expanded{\parseTD[\c!nx=\the\scratchcounter,\c!n=,\c!m=,*sq=\v!no][]}\eTD
      \fi
      % can also be made faster
      \getparameters[\@@tbl][\c!ny=\tblnr,\c!nx=\tblnc,nc=1,nr=1,#1,\c!n=,\c!m=]%
   \fi\fi
   \edef\@@tblmindeed{\csname\@@tbl\c!m\endcsname}%
   \ifx\@@tblmindeed\empty \else
     \ifnum\@@tblmindeed=\currentcol \else
       \scratchcounter\numexpr\@@tblmindeed-\currentcol+\minusone-\tblspn\relax
       \dorecurse\scratchcounter{\expanded{\parseTD[\c!n=,\c!m=][]}\eTD}%
       % can be sped up
       \getparameters[\@@tbl][\c!ny=\tblnr,\c!nx=\tblnc,nc=1,nr=1,#1,\c!n=,\c!m=]%
     \fi
   \fi
   \doloop % skip over columns that result from earlier span
     {\advance\currentcol\plusone
      \doifnottbltag\maximumrow\currentcol\exitloop}%
   % == \def\next{\advance\currentcol\plusone\doiftbltag\maximumrow\currentcol\next}\next
   % fill r*c cells and set span
   \ifnum\tblnx=\plusone
     \ifnum\tblny=\plusone
       \ifnum\currentcol>\maximumcol\relax
         \maximumcol\currentcol
       \fi
     \else
       \presetTBLcell
     \fi
   \else
     \presetTBLcell
   \fi
   % set values
   \lettbltag\maximumrow\currentcol\tblcell
   \settblcol\maximumrow\currentcol{\number\tblnx}%
   \settblrow\maximumrow\currentcol{\number\tblny}%
   \settblref\maximumrow\currentcol{\ifcsname\@@tbl\c!action\endcsname\csname\@@tbl\c!action\endcsname\fi}%
   % save text
   \edef\celltag{{\number\maximumrow}{\number\currentcol}}%
   \@EA\settbltxt\@EA\maximumrow\@EA\currentcol\@EA{\@EA\handleTBLcell\celltag[#1]{#3}}}

\def\presetTBLcell
  {\row\maximumrow
   \col\currentcol
   \dorecurse\tblny
     {\col\currentcol
      \settblcol\row\col{\number\tblnx}%
      \ifnum\tblnx>\maximumrowspan\relax
        \maximumrowspan\tblnx
      \fi
      \dorecurse\tblnx
        {\lettbltag\row\col\tblnone
         \advance\col\plusone}%
      \advance\row\plusone}%
   % check max column
   \advance\col\minusone
   \ifnum\col>\maximumcol\relax
     \maximumcol\col
   \fi}

%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

\unexpanded\def\bTABLEhead{\dosingleempty\doTABLEhead} \let\eTABLEhead\relax
\unexpanded\def\bTABLEnext{\dosingleempty\doTABLEnext} \let\eTABLEnext\relax
\unexpanded\def\bTABLEbody{\dosingleempty\doTABLEbody} \let\eTABLEbody\relax
\unexpanded\def\bTABLEfoot{\dosingleempty\doTABLEfoot} \let\eTABLEfoot\relax

\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 / can be sped up but only once per table
  {\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
   \TBLhead\emptytoks
   \TBLnext\emptytoks
   \TBLbody\emptytoks
   \TBLfoot\emptytoks
   \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,
          \v!auto=>\ifinsidesplitfloat\enableTBLbreaktrue\fi]
   \processaction
     [\tbltblheader]
     [\v!repeat=>\multipleTBLheadstrue]%
   \localcolortrue
   \presetallTABLEparameters
   \ExpandFirstAfter\processallactionsinset
     [\tbltbloption]
     [\v!stretch=>\autoTBLspreadtrue]%
   \linewidth\tbltblrulethickness % needs to be frozen
   \dontcomplain
   \currentcol\zerocount
   \maximumrowspan\plusone
   \maximumcol\zerocount
   \maximumrow\zerocount
   \let\bTR\dobTR
   \let\bTD\dobTD
   \let\bTH\dobTH
   \let\bTN\dobTN}

\unexpanded\def\dobTR{\dodoubleempty\parseTR}
\unexpanded\def\dobTD{\dodoubleempty\parseTD}
\unexpanded\def\dobTH{\dodoubleempty\parseTH}
\unexpanded\def\dobTN{\dodoubleempty\parseTN}

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

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

\def\eTABLE % beware, we need to get rid of spurious spaces when in hmode
  {% tricky and dirty order -)
   \doifsometokselse\TBLhead % slow, better a flag
     {\the\TBLhead
      \edef\noftblheadlines{\number\maximumrow}%
      \doifsometokselse\TBLnext
        {\the\TBLnext
         \edef\noftblnextlines{\number\numexpr\maximumrow-\noftblheadlines\relax}}%
        {\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
     {\row\recurselevel\relax
      \dorecurse\maximumcol
        {\col\recurselevel\relax
         \doifnottbltag\row\col
           {\xxcol\col
            \xxrow\row
            \xrow\row
            \doloop
              {\xcol\col
               \doloop
                 {\doifelsetbltag\xrow\xcol \exitloop
                    {\advance\xcol\plusone
                     \ifnum\xcol>\maximumcol\relax \exitloop \fi}}%
               \doifelsetbltag\xrow\xcol \exitloop
                 {\xxrow\xrow \xxcol\xcol \advance\xrow\plusone
                  \ifnum\xrow>\maximumrow \exitloop \fi}}%
            \ifnum\xxrow>\maximumrow\xxrow\maximumrow\fi
            \ifnum\xxcol>\maximumcol\xxcol\maximumcol\fi
            \xxrow\numexpr\xxrow-\row+\plusone\relax
            \xxcol\numexpr\xxcol-\col+\plusone\relax
            \xrow\row
            \dorecurse\xxrow
              {\xcol\col \settblcol\xrow\xcol{\number\xxcol}%
            \dorecurse\xxcol
              {\lettbltag\xrow\xcol\tblnone \advance\xcol\plusone}%
            \advance\xrow\plusone}%
         \lettbltag\row\col\tblcell
         \settblcol\row\col{\the\xxcol}%
         \settblrow\row\col{\the\xxrow}%
         \ifautoTBLemptycell
           \edef\celltag{{\number\row}{\number\col}}%
           \@EA\settbltxt\@EA\row\@EA\col\@EA{\@EA\handleTBLcell\celltag[]{\strut}}%
         \fi}}}%
   % to be sure
   \dorecurse\maximumrow
     {\row\recurselevel\relax
      \dorecurse\maximumcol
        {\col\recurselevel\relax
         \doiftblrow\row\col
           {\scratchcounter\numexpr\maximumrow-\row+\plusone\relax
            \ifnum\gettblrow\row\col>\scratchcounter
              \settblrow\row\col{\the\scratchcounter}%
            \fi}%
         \lettblht\row\col\zeropoint
         \lettblwd\row\col\zeropoint
         \doifnottblcol\row\col{\lettblcol\row\col\zerocount}%
         \doifnottbltag\row\col{\lettbltag\row\col\tblnone}}}%
   % check and do
   \ifcase\maximumcol\else
     \startTBLprocessing
       \begTBL
         \dorecurse\maximumrow
           {\bTBL
              \row\recurselevel\relax
              \dorecurse\maximumcol
                {\col\recurselevel\relax
                 \expanded{\doTBL{\number\row}{\number\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

\newcount\prelocatedTBLrows % \prelocateTBLrows{1000} may speed up large tables

\def\bTBL{\tblrowtoks\emptytoks}
\def\eTBL{\tbltoks\@EA\@EA\@EA{\@EA\the\@EA\tbltoks\@EA\begintblrow\the\tblrowtoks\endtblrow}}%

\def\prelocateTBLerror
  {\writestatus\m!systems{fatal error: use \string\prelocateTBLrows\space to increase table memory (now: \number\prelocatedTBLrows)}}

\def\prelocateTBLrows#1% we start at zero so we have one to much, better play safe anyway
  {\dostepwiserecurse\prelocatedTBLrows{#1}\plusone{\expandafter\newtoks\csname tbl:\recurselevel\endcsname}%
   \def\bTBL
     {\ifnum\tblrow<\prelocatedTBLrows\relax
        \@EA\let\@EA\tblrowtoks\csname  tbl:\the\tblrow\endcsname\tblrowtoks\emptytoks
      \else
        \prelocateTBLerror
      \fi}%
   \def\eTBL
     {\tbltoks\@EA\@EA\@EA{\@EA\the\@EA\tbltoks\@EA\begintblrow\@EA\the\csname tbl:\the\tblrow\endcsname\endtblrow}}%
   \global\prelocatedTBLrows#1\relax}

% \prelocateTBLrows{1000} % may speed up large tables

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

\def\skiptblcol
  {\global\advance\tblcol\plusone}

\def\nexttblcol
  {\global\advance\tblcol\plusone
   \kern\tbltblcolumndistance
   &}

\def\spantblcol
  {\span}

\newcount\tblrow
\newcount\tblcol

\let\savedtblrow\!!zerocount
\let\savedtblcol\!!zerocount

\def\begintblrow
  {\noalign
     {\global\advance\tblrow\plusone
      \global\tblcol\zerocount
      \global\tblspn\zerocount
      \bgroup % protect local vars
        \@@tblsplitbefore
      \egroup
      \ifx\@@tblsplitsamepage\v!before
        \unpenalty
        \nobreak
      \else\ifx\@@tblsplitsamepage\v!both
        \unpenalty
        \nobreak
      \fi\fi}%
   \nexttblcol
   \kern\dimexpr\tbltblleftmargindistance-\tbltblcolumndistance\relax}

\def\endtblrow
  {\kern\dimexpr\tbltblrightmargindistance-\tbltblcolumndistance\relax
   \crcr
   \noalign
     {\nointerlineskip
      \ifnum\tblrow>\noftblheadlines
        \ifnum\gettblnob\tblrow=\zerocount
          \unpenalty
          \ifx\@@tblsplitsamepage\v!after
            \nobreak
          \else\ifx\@@tblsplitsamepage\v!both
            \nobreak
          \else
            \allowbreak
          \fi\fi
        \fi
      \else
        \allowbreak % else no proper head split off
      \fi
      \bgroup % protect local vars
        \@@tblsplitafter
      \egroup
      \bgroup % protect local vars
        \scratchcounter\numexpr\tblrow+\plusone\relax
        \ifnum\scratchcounter>\noftblhdnxlines\relax
          \ifnum\scratchcounter<\maximumrow\relax
            \doifsomething\tbltblspaceinbetween{\blank[\tbltblspaceinbetween]}%
          \fi
        \fi
      \egroup}}

\def\begintbl
  {\global\tblspn\zerocount
   \global\tblcol\zerocount
   \global\tblrow\zerocount
   \global\advance\tblrow\minusone
   \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%
  {\tblrowtoks\expandafter{\the\tblrowtoks\makeTBL #1 #2 }% space delimited -> less tokens
   \spanTBL{#1}{#2}}

\def\spanTBL#1#2%
  {\scratchcounter\gettblcol{#1}{#2}\relax
   \ifnum\scratchcounter>\zerocount
     \advance\scratchcounter \minusone
     \dorecurse\scratchcounter{\tblrowtoks\expandafter{\the\tblrowtoks\spantblcol}}%
     \dorecurse\scratchcounter{\tblrowtoks\expandafter{\the\tblrowtoks\skiptblcol}}%
                               \tblrowtoks\expandafter{\the\tblrowtoks\nexttblcol}%
   \fi}

\def\doTBL#1#2%
  {\csname\gettbltag{#1}{#2}TBL\endcsname{#1}{#2}}

\def\begTBL
  {\global\tblspn\zerocount
   \global\tblrow\zerocount
   \global\tblcol\zerocount
   \chardef\tblpass\zerocount
   \tbltoks\emptytoks}

\def\flushtbltoks{\begintbl\the\tbltoks\endtbl}

\def\domakeTBLone#1 #2 %
  {\gettbltxt{#1}{#2}}%

\def\domakeTBLtwo#1 #2 % meer in cellD
  {\scratchdimen\zeropoint
   \scratchcounter\tblcol
   \!!counta\gettblcol{#1}{#2}\relax
   \dorecurse\!!counta
     {\advance\scratchdimen\dimexpr\gettblwid\scratchcounter+\tbltblcolumndistance\relax
      \ifnum\recurselevel<\!!counta \advance\scratchdimen \gettbldis\scratchcounter\fi
      \advance\scratchcounter\plusone}%
   \edef\widthTBL{\the\dimexpr\scratchdimen-\tbltblcolumndistance\relax}%
   \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}%

\def\domakeTBLthree#1 #2 %
  {% height
   \!!counta \gettblcol{#1}{#2}\relax
   \!!countb \gettblrow{#1}{#2}\relax
   \!!heighta\gettblht {#1}{#2}\relax
   \scratchdimen\zeropoint
   \ifnum\!!counta=\maximumcol\relax
     % case: nc=maxcolumns
   \else
     \scratchcounter#1\relax
     \dorecurse\!!countb
       {\advance\scratchdimen
        \gettblhei\scratchcounter
        \advance\scratchcounter\plusone}%
     \ifdim\scratchdimen<\!!heighta\relax
       \scratchdimen\!!heighta
     \fi
   \fi
   \edef\heightTBL{\the\scratchdimen}%
   % width
   \scratchdimen\zeropoint
   \scratchcounter\tblcol
   \dorecurse\!!counta
     {\advance\scratchdimen\dimexpr\gettblwid\scratchcounter+\tbltblcolumndistance\relax
      \ifnum\recurselevel<\!!counta \advance\scratchdimen \gettbldis\scratchcounter\fi
      \advance\scratchcounter\plusone}%
   \edef\widthTBL{\the\dimexpr\scratchdimen-\tbltblcolumndistance\relax}%
   % cell
   \setbox\scratchbox\hbox{\gettbltxt{#1}{#2}}%
   \ifnum\!!counta=\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
   \edef\!!stringa{\gettblref{#1}{#2}}%
   \ifx\!!stringa\empty
     \box\scratchbox
   \else
     \expanded{\gotobox{\box\scratchbox}[\!!stringa]}%
   \fi
   \box\scratchbox}

\def\inTBLcell#1#2% hm, do we need #1 #2 ? we use tblcol anyway
  {\ExpandBothAfter\doifinsetelse\localwidth{\v!fit,\v!broad} % user set
     {}
     {\scratchdimen\gettblaut\tblcol\relax
      \ifdim\localwidth>\scratchdimen
        \settblaut\tblcol{\the\dimexpr\localwidth\relax}%
      \fi}}%

\def\endTBL
  {\setbox\scratchbox\hbox
     {\localframed
        [\@@tbl\@@tbl]
        [\c!frame=\v!off,\c!background=,\c!align=\v!no]
        {\strut}}%
   \edef\minimalcellheight{\the\ht\scratchbox}%
   \dorecurse\maximumcol
     {\lettblaut\recurselevel\zeropoint
      % new
      \xcol\recurselevel\relax
      \dorecurse\maximumrow
        {\lettblwd\recurselevel\xcol\zeropoint
         \lettblht\recurselevel\xcol\zeropoint}%
      % till here
      \lettblwid\recurselevel\zeropoint
      \lettbldis\recurselevel\zeropoint}%
   \dorecurse\maximumrow
     {\lettblhei\recurselevel\maxdimen}%
   \chardef\tblpass\plusone
   \let\makeTBL\domakeTBLone
   \let\handleTBLcell\dohandleTBLcellA
   \setbox0\vbox{\trialtypesettingtrue \flushtbltoks}%
%    \setbox\scratchbox\vbox{\trialtypesettingtrue \flushtbltoks}%
   \lettbldis\maximumcol\zeropoint
   \ifautoTBLspread
     % experimental, stretch non fixed cells to \hsize
     \checktblwidthsone   % trial run
     \checktblwidthstwo   % real run
     \stretchtblwidths
     \let\handleTBLcell\dohandleTBLcellB
     \setbox\scratchbox\vbox{\trialtypesettingtrue \flushtbltoks}%
   \else\ifdim\wd0>\hsize
     \ifautoTBLhsize
       \checktblwidthsone % trial run
       \checktblwidthstwo % real run
       \let\handleTBLcell\dohandleTBLcellB
       \setbox\scratchbox\vbox{\trialtypesettingtrue \flushtbltoks}%
     \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 \flushtbltoks}%
   \fi\fi\fi\fi
   \let\handleTBLcell\dohandleTBLcellD
   \chardef\tblpass\plustwo
   \let\makeTBL\domakeTBLtwo
   \setbox\scratchbox\vbox{\trialtypesettingtrue \flushtbltoks}%
   \checktblheightsone
   \checktblheightstwo
   \let\handleTBLcell\dohandleTBLcellE
   \chardef\tblpass\plusthree
   \let\makeTBL\domakeTBLthree
   \ifnum\TBLlevel>\plusone
     \@EA\notsplittblbox
   \else\ifenableTBLbreak
     \@EAEAEA\splittblbox
   \else
     \@EAEAEA\notsplittblbox
   \fi\fi{\flushtbltoks}}

\def\stretchtblwidths % more variants, e.g. a max to \dimend
  {\ifcase\maximumcol\else % else division by zero
     \!!dimend\zeropoint
     \!!dimene\hsize
     \dorecurse\maximumcol
       {\advance\!!dimend\dimexpr\gettblwid\recurselevel+\tbltblcolumndistance\relax
        \advance\!!dimene-\gettbldis\recurselevel}%
     \advance\!!dimend\dimexpr-\tbltblcolumndistance+\tbltblleftmargindistance+\tbltblrightmargindistance\relax
     % distribute width (stretch)
     \ifdim\!!dimend<\!!dimene
       \advance\!!dimend-\!!dimene
       \!!dimend-\!!dimend
       \divide\!!dimend\maximumcol
       \dorecurse\maximumcol
         {\settblwid\recurselevel{\the\dimexpr\gettblwid\recurselevel+\!!dimend\relax}}%
     \fi
   \fi}

\newbox\finaltblbox

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

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

\newbox\TABLEsplitbox % public, don't change

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

\def\dosplittblbox#1%
  {\resettsplit
   \def\tsplitminimumfreelines{2}%
   \def\tsplitminimumfreespace{\dimexpr\extratblsplitheight+\tbltblsplitoffset\relax}%
   \def\tsplitbeforeresult    {\beforeTABLEsplitbox}%
   \def\tsplitafterresult     {\afterTABLEsplitbox}%
   \def\tsplitafter           {\@@tblsplitafter}%
   \setbox\tsplitcontent\vbox{#1}%
   \ifmultipleTBLheads
     \dorecurse\noftblheadlines
       {\setbox\scratchbox\vsplit\tsplitcontent to \lineheight
        \setbox\tsplithead\vbox{\unvcopy\tsplithead\unvcopy\scratchbox}}%
     \dorecurse\noftblnextlines
       {\setbox\scratchbox\vsplit\tsplitcontent to \lineheight
        \setbox\tsplitnext\vbox{\unvcopy\tsplitnext\unvcopy\scratchbox}}%
   \fi
   \doifsomething\tbltblspaceinbetween
     {\def\tsplitinbetween{\blank[\tbltblspaceinbetween]}}%
   \def\postprocesstsplit{\postprocessTABLEsplitbox{\box\tsplitresult}}%
   \handletsplit}

% ! ! ! ! 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
   \!!counta\zerocount
   \!!dimena\dimexpr\hsize-\tbltblleftmargindistance-\tbltblrightmargindistance-\tbltblcolumndistance\relax
   \dorecurse\maximumcol
     {\scratchdimen\gettblaut\recurselevel\relax
      \advance\!!dimena-\gettbldis\recurselevel\relax
      \ifdim\scratchdimen>\zeropoint\relax
        \advance\!!dimena -\scratchdimen
      \else
        \scratchdimen\gettblwid\recurselevel\relax
        \ifdim\scratchdimen>\tbltblmaxwidth\relax
          \ifcase#1\else\lettblwid\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}

\newcount\xrowTBL
\newcount\xcolTBL
\newcount\xxrowTBL

% dikke arg naar recurse wegwerken

\def\dochecktblheightsone
  {\!!countb\gettblrow\xrowTBL\xcolTBL\relax
    % check row span
   \ifnum\!!countb>\plusone
     % current height in row
     \dimen0=\gettblht\xrowTBL\xcolTBL
     % find nearest height in row
     \dimen2=\zeropoint
     \dorecurse\maximumcol
       {\ifnum\recurselevel=\xcolTBL\else
          \doiftblrow\xrowTBL\recurselevel
            {\!!countc=\gettblrow\xrowTBL\recurselevel\relax
             \ifnum\!!countc=\plusone
               \dimen4=\gettblht\xrowTBL\recurselevel\relax
               \ifdim\dimen2<\dimen4
                 \dimen2=\dimen4
               \fi
             \fi}%
        \fi}%
     \xxrowTBL\xrowTBL
     % calculate cummulative height
     \dimen4=\dimen2
     \!!countc\xrowTBL
     \advance\!!countc\minusone
     \dorecurse\!!countb
       {\ifnum\xxrowTBL=\xrowTBL\else
          \advance\dimen4 \gettblhei\xxrowTBL
        \fi
        \ifnum\recurselevel=\!!countb\else
          \settblnob\!!countc
          \advance\!!countc\plusone
       \fi
        \advance\xxrowTBL\plusone}%
     % distribute overshoot equally
\ifdim\dimen2>\zeropoint % see natural-003
     \ifdim\dimen4<\dimen0
       \advance\dimen0 -\dimen4
       \divide\dimen0 \!!countb
       \xxrowTBL\xrowTBL
       \settblhei\xrowTBL{\the\dimen2}%
       \dorecurse\!!countb
         {\dorecurse\maximumcol
            {\ifnum\recurselevel=\xcolTBL\else
               \scratchdimen\dimexpr\gettblht\xxrowTBL\recurselevel+\dimen0\relax
               \settblht\xxrowTBL\recurselevel{\the\scratchdimen}%
               \ifdim\gettblhei\xxrowTBL<\scratchdimen
                 \settblhei\xxrowTBL{\the\scratchdimen}%
               \fi
             \fi}%
          \advance\xxrowTBL\plusone}%
     \else\ifdim\dimen4>\dimen0
       \settblhei\xrowTBL{\the\dimen2}%
     \fi\fi
\fi
   \fi}

\def\checktblheightsone
  {\dorecurse\maximumrow
     {\xrowTBL\recurselevel\relax
      \dorecurse\maximumcol
        {\xcolTBL\recurselevel\relax
         \doiftblrow\xrowTBL\xcolTBL\dochecktblheightsone}}}

\def\checktblheightstwo
  {}

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

\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\tblcol\relax
   \ifdim\wd\scratchbox>\scratchdimen
     \ifsqueezeTBLspan
       \ifautosqueezeTBLspan
         \doifinsetelse\tbltblwidth{\v!fit,\v!fixed,\v!broad,\v!local}
           \donetrue \donefalse
       \else
         \donetrue
       \fi
       \ifdone % brr, 0
         \ifnum\number\gettblcol{#1}{#2}>\plusone \settblspn\tblcol\fi
       \fi
     \fi
     \doifelsetblspn\tblcol
       \donothing
       {\ifdim\gettblwid\tblcol<\wd\scratchbox
          \settblwid\tblcol{\the\wd\scratchbox}%
        \fi}% auto set
   \fi
   \scratchcounter\numexpr\tblrow+\plusone\relax
   \scratchdimen\gettblhei\scratchcounter\relax
   \ifdim\ht\scratchbox<\scratchdimen
     \settblhei\scratchcounter{\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\tblcol\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\tblcol{\the\scratchdimen}%
         \else\ifdim\wd\scratchbox>\scratchdimen
           % unless span
           \settblaut\tblcol{\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
     \scratchcounter\numexpr\tblrow+\plusone\relax
     \doiftblrow\scratchcounter\tblcol
       {\scratchdimen\gettblhei\scratchcounter\relax % moved inside test
        \ifnum\gettblrow\scratchcounter\tblcol>\plusone \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\tblcol\relax
    \ifdim\scratchdimen>\zeropoint\relax
      \let\tblwidthkey\c!width
      \edef\tblwidth{\the\scratchdimen}%
    \else
      \scratchdimen\gettblwid\tblcol\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!auto,
   \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!left=,
   \c!right=,
   \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 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
     \global\advance\currenttbl\plusone
   \fi
   \doglobal\increment\TBLlevel\relax
   \ifnum\TBLlevel>\plusone
     \resetallTABLEparameters
     % we need a proper count push/pop
     \xdef\savedtblrow{\the\tblrow}\globalpushmacro\savedtblrow
     \xdef\savedtblcol{\the\tblcol}\globalpushmacro\savedtblcol
   \else
     \global\intabletrue
   \fi}

\def\popTBL
  {\ifnum\TBLlevel>\plusone
     \globalpopmacro\savedtblrow\global\tblrow\savedtblrow
     \globalpopmacro\savedtblcol\global\tblcol\savedtblcol
   \else
     \global\intablefalse
   \fi
   \doglobal\decrement\TBLlevel\relax}

% \bgroup
% \setupTABLE[column][1][aligncharacter=yes, alignmentcharacter={,}]
% \bTABLE
%     \bTR  \bTD  1,2 \eTD  \bTD 2 \eTD \eTR
%     \bTR  \bTD 11,2 \eTD  \bTD
%         {\setupTABLE[column][1][aligncharacter=yes, alignmentcharacter={,}]
%          \bTABLE
%             \bTR  \bTD 1,2 \eTD  \bTD 2 \eTD \eTR
%             \bTR  \bTD  11,22 \eTD  \bTD 2 \eTD \eTR
%             \bTR  \bTD 11,2 \eTD  \bTD 2 \eTD \eTR \eTABLE} \eTD \eTR
%     \bTR  \bTD  11,22 \eTD  \bTD 2 \eTD \eTR
% \eTABLE
% \egroup

\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!width=fit,
          \c!height=fit,
\c!autowidth=\v!yes,
% \c!rulethickness=\linewidth,
% \c!strut=\v!no,
\c!strut=\v!yes, % needed for mathml, but ... maybe we need another resetTABLEmode
\c!autostrut=\v!no,
          \c!color=,
          \c!style=,
          \c!headstyle=,
          \c!headcolor=,
          \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

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