%D \module %D [ file=core-tab, %D version=1997.10.10, %D title=\CONTEXT\ Table Macros, %D subtitle=\TABLE\ Embedding, %D author=Hans Hagen with copied and patched code from MJ Wichura, %D date=\currentdate] %C %C This module is part of the \CONTEXT\ macro||package and is %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. \writestatus{loading}{ConTeXt Table Macros / TaBlE Embedding} % Todo: consistent namespace and get rid of not used code % In \MKIV\ the old table macros are sort of obsolete. The color extensions % have been removed and some code is stripped. For practical reasons the % \TABLE\ macros that are used are embedded in this file. % % The following code is based on TABLE 1.0 by Michael J. Wichura (August 1988. % We used a patched version with many overloads and extensions. The documented % (and larger) source can be found in \type {thrd-tab.tex}. % % Some code has been stripped. Some color has been added. Some macros have % been renamed. Registers have been replaces. And probably much more can be % cleaned up. We also need to use \tabl_tab_ prefixes here. \unprotect \newconditional\tablehasleftspacing \newconditional\tablehasrightspacing \newdimen\tablelinethicknessunit \newdimen\tablestrutunit \newskip \tableintercolumnspaceunit \newdimen\tablecolumnwidthunit \newdimen\tablekernunit \def\tablestrutheightfactor {8} \def\tablestrutdepthfactor {3} \def\tableintercolumnspacefactor {3} \def\tablecolumnwidthfactor {10} \def\tablevspacefactor {2} \def\tablekernfactor {1} \def\tablelinethicknessfactor {4} \newtoks\everytable \newtoks\everytableparbox \unexpanded\def\dotablebeginparbox#1% {\setbox\scratchbox\vtop\bgroup % \setbox added \hsize#1\relax \dontcomplain \dorestoretablelineskips \normalbaselines \let~\fixedspace \blank[\v!disable]% % added \the\everytableparbox} \unexpanded\def\dotableendparbox {\removelastskip % itemize or so \endgraf \ifnum\prevgraf>\zerocount % we want at least \verticalstrut \nowhitespace \vskip-\struttotal % one line of text \egroup \ifdim\dp\scratchbox>\lineheight % see (*) for an \getnoflines{\dp\scratchbox}% % example of where \dp\scratchbox\zeropoint % saving can go \setbox\scratchbox % terrible wrong \vtop to \noflines\lineheight{\box\scratchbox}% \fi % esp between rows \else % of paragraphs \egroup \fi \box\scratchbox} \appendtoks \parindent\zeropoint \raggedright \rightskip\zeropoint \s!plus 4em \relax \to \everytableparbox \newskip \tablelefttabskip \newskip \tablerighttabskip \newcount\!taColumnNumber \newcount\!taRecursionLevel % (Initially 0) \newdimen\!taDimenA % used by \Enlarge \newdimen\!taDimenB % used by \Enlarge \newdimen\!taDimenC % used by numeric.tex \newdimen\!taMinimumColumnWidth \newtoks \!taTableSpread \newtoks \!taPreamble \newtoks \!taDataColumnTemplate \newtoks \!taRuleColumnTemplate \newtoks \!taOldRuleColumnTemplate \newtoks \!taLeftGlue \newtoks \!taRightGlue \newskip \!taLastRegularTabskip \newif \if!taBeginFormat \newif \if!taOnceOnlyTabskip \def\!thToksEdef#1#2% {\edef\!ttemp{#2}% #1\expandafter{\!ttemp}% \ignorespaces} \def\!thLoop#1\repeat {\def\!thIterate{#1\expandafter \!thIterate\fi}% \!thIterate \let\!thIterate\relax} \def\dobegintableformat {\!taPreamble\emptytoks \!taColumnNumber\zerocount \scratchskip\tableintercolumnspaceunit \multiply\scratchskip\tableintercolumnspacefactor \divide\scratchskip\plustwo \!taRuleColumnTemplate\expandafter{\expandafter\tabskip\the\scratchskip}% \!taLastRegularTabskip\scratchskip \!taOnceOnlyTabskipfalse \!taBeginFormattrue \let\!tfRowOfWidths\empty \doreadtableformatkeys} \def\!tfSetWidth {\ifx\!tfRowOfWidths\empty % true if no prior "w" keys \ifnum\!taColumnNumber>\zerocount % true if "w" key is to right of first "|" \begingroup % RowOfWidths={&\omit || n copies of &\omit&\omit}, where n = number of column to the left of this one \scratchcounter\plusone \aftergroup \edef \aftergroup \!tfRowOfWidths \aftergroup {% \aftergroup &\aftergroup \omit \!thLoop \ifnum \scratchcounter<\!taColumnNumber \advance\scratchcounter\plusone \aftergroup \!tfAOAO \repeat \aftergroup}% \endgroup \fi \fi \ifx[\!ttemp % \!tgGetValue sets \!ttemp = token after w \expandafter\!tfSetWidthText \else \expandafter\!tfSetWidthValue \fi} \def\!tfAOAO{&\omit&\omit} \def\!tfSetWidthText[#1]% {\def\!tfWidthText{#1}% \doreadtableformatkeys} \def\!tfSetWidthValue {\!taMinimumColumnWidth= \ifnum\!tgCode=\plusone \ifx\!tgValue\empty \tablecolumnwidthfactor \else \!tgValue \fi \tablecolumnwidthunit \else \!tgValue \fi \let\!tfWidthText\empty % Override possible prior `w[sample entry]' \doreadtableformatkeys} \def\!tfSetTabskip {\ifnum\!tgCode=\plusone \scratchskip\tableintercolumnspaceunit \multiply\scratchskip \ifx\!tgValue\empty\tableintercolumnspacefactor\else\!tgValue\fi \else \scratchskip\!tgValue \fi \divide\scratchskip\plustwo \ifnum\!taColumnNumber=\zerocount %\!thToksEdef\!taRuleColumnTemplate{\the\!taRuleColumnTemplate\tabskip\the\scratchskip}% \normalexpanded{\!taRuleColumnTemplate{\the\!taRuleColumnTemplate\tabskip\the\scratchskip}}% \else %\!thToksEdef\!taDataColumnTemplate{\the\!taDataColumnTemplate\tabskip\the\scratchskip}% \normalexpanded{\!taDataColumnTemplate{\the\!taDataColumnTemplate\tabskip\the\scratchskip}}% \fi \if!taOnceOnlyTabskip\else \!taLastRegularTabskip\scratchskip % Remember this Tabskip, for possible \fi % restoration after a subsequent"OnceOnly" \doreadtableformatkeys} \def\!tfSetVrule {\!thToksEdef\!taRuleColumnTemplate {\hfil \vrule \noexpand\!!width \ifnum\!tgCode=\plusone \ifx\!tgValue\empty \tablevrulethicknessfactor \else \!tgValue \fi \tablelinethicknessunit \else \!tgValue \fi ####% \hfil \the\!taRuleColumnTemplate}% \!tfAdjoinPriorColumn} \def\!tfSetAlternateVrule {\afterassignment\!tfSetAlternateA \scratchtoks} \def\!tfSetAlternateA {\!thToksEdef\!taRuleColumnTemplate{\the\scratchtoks\the\!taRuleColumnTemplate}% \!tfAdjoinPriorColumn} \def\!tfAdjoinPriorColumn {\ifnum \!taColumnNumber=0 \!taPreamble=\!taRuleColumnTemplate % New \tabskip may have been added \else \ifx\!tfRowOfWidths\empty % no "w" keys specified yet, not even this col \else \!tfUpdateRowOfWidths \fi \!thToksEdef\!taDataColumnTemplate{\the\!taLeftGlue\the\!taDataColumnTemplate\the\!taRightGlue}% \!thToksEdef\!taPreamble{\the\!taPreamble&\the\!taDataColumnTemplate&\the\!taRuleColumnTemplate}% \fi \advance \!taColumnNumber \plusone \if!taOnceOnlyTabskip \!thToksEdef\!taDataColumnTemplate{####\tabskip \the\!taLastRegularTabskip}% \else \!taDataColumnTemplate{##}% \fi \!taRuleColumnTemplate\emptytoks \!taLeftGlue{\hfil}% \!taRightGlue{\hfil}% \!taMinimumColumnWidth\zeropoint \let\!tfWidthText\empty \!taOnceOnlyTabskipfalse \doreadtableformatkeys} \def\!tfUpdateRowOfWidths {\ifx\!tfWidthText\empty \else \!tfComputeMinColWidth \fi \edef\!tfRowOfWidths {\!tfRowOfWidths &% \omit \ifdim \!taMinimumColumnWidth>\zeropoint \hskip \the\!taMinimumColumnWidth \fi & \omit}} \def\!tfComputeMinColWidth {\setbox0\vbox {\ialign{% Plain's initialized \halign; \tabskip=0pt \everycr={} \span\the\!taDataColumnTemplate\cr \!tfWidthText\cr}}% \!taMinimumColumnWidth=\wd0 } \def\!tfFinishFormat {\!thToksEdef\!taPreamble{####\tabskip\tablelefttabskip&\the\!taPreamble \tabskip\tablerighttabskip&####\tabskip\zeropoint\cr} \!taBeginFormatfalse \!ttDoHalign} \def\dotablereformat[#1]% will become local {\omit \!taDataColumnTemplate{##}% \!taLeftGlue\emptytoks \!taRightGlue\emptytoks \begingroup \@@useotherbar \expanded{\endgroup\noexpand\doreadtableformatkeys#1]}}% appear in a \dotablereformat cmd; this is here as a safeguard. \appendtoks \let\ReFormat\dotablereformat \to \everytable \def\!tfEndReFormat {\!tfReFormat} \appendtoks \dotableparalignment \to \everytableparbox \def\!tfReFormat#1% {\the \!taLeftGlue \vbox{\forgetall\ialign{\span\the\!taDataColumnTemplate\cr#1\cr}}% \the \!taRightGlue \kern\zeropoint} % prevents \unskip / really needed \def\!tgGetValue#1% {\def\!tgReturn{#1}% \futurelet\!ttemp\!tgCheckForParen} \def\!tgCheckForParen% {\ifx\!ttemp (% \expandafter \!tgDoParen \else \expandafter \!tgCheckForSpace \fi} \def\!tgDoParen(#1)% {\def\!tgCode{2}% will be expanded \def\!tgValue{#1}% \!tgReturn} \def\!tgCheckForSpace {\def\!tgCode{1}% \let\!tgValue\empty \ifx\!ttemp\!thSpaceToken \expandafter \!tgReturn \else \expandafter \!tgCheckForDigit \fi} % \def\!tgCheckForDigit % {\donefalse % \ifx 0\!ttemp \donetrue % \else\ifx 1\!ttemp \donetrue % \else\ifx 2\!ttemp \donetrue % \else\ifx 3\!ttemp \donetrue % \else\ifx 4\!ttemp \donetrue % \else\ifx 5\!ttemp \donetrue % \else\ifx 6\!ttemp \donetrue % \else\ifx 7\!ttemp \donetrue % \else\ifx 8\!ttemp \donetrue % \else\ifx 9\!ttemp \donetrue % \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi % \ifdone % \expandafter \!tgGetNumber % \else % \expandafter \!tgReturn % \fi} \def\!tgCheckForDigit % less tokens: {\donetrue \ifx 0\!ttemp \else \ifx 1\!ttemp \else \ifx 2\!ttemp \else \ifx 3\!ttemp \else \ifx 4\!ttemp \else \ifx 5\!ttemp \else \ifx 6\!ttemp \else \ifx 7\!ttemp \else \ifx 8\!ttemp \else \ifx 9\!ttemp \else \donefalse \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi \ifdone \expandafter \!tgGetNumber \else \expandafter \!tgReturn \fi} % \def\!tgCheckForDigit % does not work % {\relax\doifnumberelse\!ttemp\!tgGetNumber\!tgReturn} \def\!tgGetNumber {\afterassignment\!tgGetNumberA\scratchcounter=} \def\!tgGetNumberA{\edef\!tgValue{\the\scratchcounter}\!tgReturn} \def\!tgSetUpParBox {\normalexpanded {\noexpand \doreadtableformatkeys b{\dotablebeginparbox {\ifnum\!tgCode=\plusone \ifx\!tgValue\empty \tablecolumnwidthfactor \else \!tgValue \fi \tablecolumnwidthunit \else \!tgValue \fi}}% a{\dotableendparbox}}} \def\!tgInsertKern {\edef\!ttemp {\kern \ifnum \!tgCode=\plusone \ifx \!tgValue\empty \tablekernfactor \else \!tgValue \fi \tablekernunit \else \!tgValue \fi}% \edef\!ttemp {\noexpand\doreadtableformatkeys \ifconditional\tablehasleftspacing b{\!ttemp} \fi \ifconditional\tablehasrightspacing a{\!ttemp} \fi}% \!ttemp} \def\newtableformatkey #1{\setvalue{!tk<\string#1>}} \def\doreadtableformatkeys#1{\getvalue{!tk<\string#1>}} % Key "b": b{TOKENS} adds TOKENS to the left of (before) the template \newtableformatkey b#1% {\expandafter\!tkJoin\expandafter{\the\!taDataColumnTemplate}{#1}% \doreadtableformatkeys} \def\!tkJoin#1#2% {\!taDataColumnTemplate{#2#1}}% % Key "a": a{TOKENS} adds TOKENS to the right of (after) the template \newtableformatkey a#1% {\!taDataColumnTemplate\expandafter{\the\!taDataColumnTemplate #1}% \doreadtableformatkeys} % Key "\{": Enclose template in braces. \newtableformatkey \{% {\!taDataColumnTemplate=\expandafter{\expandafter{\the\!taDataColumnTemplate}}% \doreadtableformatkeys} % Key "*": "*{N}{KEY LETTERS}" is equivalent to specifying % N times. % KEY LETTERS may contain further * specifications \newtableformatkey *#1#2% {\scratchcounter=#1\relax \scratchtoks\emptytoks \!thLoop \ifnum\scratchcounter>\zerocount \scratchtoks\expandafter{\the\scratchtoks#2}% \advance\scratchcounter\minusone \repeat \expandafter\doreadtableformatkeys\the\scratchtoks} % Key "\LeftGlue": Specifies the glue (usually \hfil, or nothing) to be % added to extreme left of the template to position a column \newtableformatkey \LeftGlue#1% {\!taLeftGlue{#1}% \doreadtableformatkeys} \newtableformatkey \RightGlue#1% {\!taRightGlue{#1}% \doreadtableformatkeys} \newtableformatkey c% {\prependtoks\raggedcenter\to\!taDataColumnTemplate \doreadtableformatkeys \LeftGlue\hfil \RightGlue\hfil} \newtableformatkey l% {\prependtoks\raggedright\to\!taDataColumnTemplate \doreadtableformatkeys \LeftGlue\empty \RightGlue\hfil} \newtableformatkey r% {\prependtoks\raggedleft\to\!taDataColumnTemplate \doreadtableformatkeys \LeftGlue\hfil \RightGlue\empty} \newtableformatkey x% {\prependtoks\notragged\to\!taDataColumnTemplate \doreadtableformatkeys \LeftGlue\hfil \RightGlue\empty} % Key "k": Adds kerns to left and right of "#" % This key and the two below use Plain TeX's \if@h as if it were \if@left, % and \if@v as if it were \if@right. Table making goes on in a group, % so even in the unlikely circumstance that a \phantom is currently under % construction, there's no problem. \newtableformatkey k% {\settrue\tablehasleftspacing \settrue\tablehasrightspacing \!tgGetValue{\!tgInsertKern}} % Key "i": Adds a kern to the left of "#" \newtableformatkey i% {\settrue\tablehasleftspacing \setfalse\tablehasrightspacing \!tgGetValue{\!tgInsertKern}} % Key "j": Adds a kern to the right of "#" \newtableformatkey j% {\setfalse\tablehasleftspacing \settrue\tablehasrightspacing \!tgGetValue{\!tgInsertKern}} % Key "n": numeric item , non-math mode. \newtableformatkey n% {\def\!tnStyle{}% \futurelet\!tnext\!tnTestForBracket} % Key "N": numeric item, math mode. \newtableformatkey N% {\def\!tnStyle{$}% \futurelet\!tnext\!tnTestForBracket} % Key "m": Math mode. \newtableformatkey m% {\doreadtableformatkeys b$ a$} % Key "M": Displaymath mode. \newtableformatkey M% {\doreadtableformatkeys \{ b{$\displaystyle} a$} % Key "\m": Template ${}#\hfil$ \newtableformatkey \m% {\doreadtableformatkeys l b{{}} m} % Key "\M": Template $\displaystyle{{}#\hfil}$ \newtableformatkey \M% {\doreadtableformatkeys l b{{}} M} % Key "f": Set font (E.g., f\it sets up italic font (assuming \it % has its usual meaning) \newtableformatkey f#1% {\doreadtableformatkeys b{#1}} \newtableformatkey B{\doreadtableformatkeys f\bf} % Key "B": abbreviation for f\bf \newtableformatkey I{\doreadtableformatkeys f\it} % Key "I": abbreviation for f\it \newtableformatkey S{\doreadtableformatkeys f\sl} % Key "S": abbreviation for f\sl \newtableformatkey R{\doreadtableformatkeys f\rm} % Key "R": abbreviation for f\rm \newtableformatkey T{\doreadtableformatkeys f\tt} % Key "T": abbreviation for f\tt % Key "p": ParBox \newtableformatkey p% {\!tgGetValue{\!tgSetUpParBox}} % Key "w": minimum column width \newtableformatkey w% {\!tkTestForBeginFormat w{\!tgGetValue{\!tfSetWidth}}} % Key "s": Set tabskip for the inter-column space to the right % of the current column, and all subsequent spaces, until overriden % by a new "s" or "o" key. \newtableformatkey s% {\!taOnceOnlyTabskipfalse % in case same column has a prior "o" key \!tkTestForBeginFormat t{\!tgGetValue{\!tfSetTabskip}}} % Key "o": Apply the \tabskip stated for this column ONLY to the % inter-column space just to the right of this column; restore the % the previous \tabskip for subsequent columns. \newtableformatkey o% {\!taOnceOnlyTabskiptrue \!tkTestForBeginFormat o{\!tgGetValue{\!tfSetTabskip}}} % Key "|": Standard rule column designator \newtableformatkey |% {\!tkTestForBeginFormat |{\!tgGetValue{\!tfSetVrule}}} % Key "\|": Non-standard rule column designator \newtableformatkey \|% {\!tkTestForBeginFormat \|{\!tfSetAlternateVrule}} % Key ".": PERIOD -- end of \dobegintableformat section. \newtableformatkey .% {\!tkTestForBeginFormat.{\!tfFinishFormat}} % Key "\doendtableformat": Equivalent to "." \newtableformatkey \doendtableformat {\!tkTestForBeginFormat\doendtableformat{\!tfFinishFormat}} % Key "]": End of \dotablereformat section \newtableformatkey ]% {\!tkTestForReFormat ] \!tfEndReFormat} % TEST FOR BEGIN FORMAT{}{Intended Action}: This test is run % on keys that can only be used by \dobegintableformat --- "s", "o", % "|", "\|", "w", ".", and "\doendtableformat". \def\!tkTestForBeginFormat#1#2% {\if!taBeginFormat \def\!ttemp{#2}% \expandafter\!ttemp \else \toks0={#1}% \toks2=\expandafter{\string\dotablereformat}% \expandafter\!tkImproperUse \fi} % TEST FOR RE FORMAT{}{Intended Action}: This test is run % on the key "]", which can only be used by \dotablereformat. \def\!tkTestForReFormat#1#2% {\if!taBeginFormat \toks0={#1}% \toks2=\expandafter{\string\dobegintableformat}% \expandafter\!tkImproperUse \else \def\!ttemp{#2}% \expandafter\!ttemp \fi} % NOTE: THE SPACE BETWEEN A NUMERIC ENTRY AND THE FOLLOWING '|', '"', % OR '\|' IS MANDATORY. % EMPTY NUMERIC ENTRIES ARE NOT ALLOWED: USE '{}' OR '\omit' INSTEAD. \def\!tnTestForBracket {\ifx[\!tnext \expandafter\!tnGetArgument \else \expandafter\!tnGetCode \fi} % GET CODE: E.g. "4", or "4.0", "0.4", or "10.2" \def\!tnGetCode#1 % {\!tnConvertCode #1..!} % CONVERT CODE: E.g. converts above to [0000], [0000.], [.0000], % [0000000000.00] \def\!tnConvertCode #1.#2.#3!% {\begingroup \aftergroup\edef \aftergroup\!ttemp \aftergroup{% \aftergroup[% \scratchcounter#1\relax \!thLoop \ifnum \scratchcounter>\zerocount \advance\scratchcounter\minusone \aftergroup0 \repeat \def\!ttemp{#3}% \ifx\!ttemp \empty \else \aftergroup. \scratchcounter#2\relax \!thLoop \ifnum \scratchcounter>\zerocount \advance\scratchcounter\minusone \aftergroup0 \repeat \fi \aftergroup]\aftergroup}% \endgroup\relax \expandafter\!tnGetArgument\!ttemp} % GET ARGUMENT: [ > \def\!tnGetArgument[#1]% {\!tnMakeNumericTemplate\!tnStyle#1..!} % MAKE NUMERIC TEMPLATE \def\!tnMakeNumericTemplate#1#2.#3.#4!% #1= or $ {\def\!ttemp{#4}% \ifx\!ttemp\empty \!taDimenC\zeropoint \else \setbox\scratchbox=\hbox{\mathsurround\zeropoint #1.#3#1}% \!taDimenC\wd\scratchbox \fi \setbox\scratchbox\hbox{\mathsurround\zeropoint #1#2#1}% \!thToksEdef\!taDataColumnTemplate {\noexpand\!tnSetNumericItem{\the\wd\scratchbox}{\the\!taDimenC}{#1}% \the\!taDataColumnTemplate}% Might have tabskip glue in here \doreadtableformatkeys} % SET NUMERIC ITEM \def\!tnSetNumericItem #1#2#3#4 % {\!tnSetNumericItemA {#1}{#2}{#3}#4..!} \def\!tnSetNumericItemA #1#2#3#4.#5.#6!% {\def\!ttemp{#6}% \hbox to #1{\hss \mathsurround\zeropoint #3#4#3}% \hbox to #2{\ifx\!ttemp\empty\else\mathsurround\zeropoint #3.#5#3\fi\hss}} % extensions \newtableformatkey q% {\letempty\!tqStyle \futurelet\!tnext\!tqTestForBracket} \newtableformatkey Q% {\def\!tqStyle{$}% \futurelet\!tnext\!tqTestForBracket} \def\!tqTestForBracket {\ifx[\!tnext \!thx\!tqGetArgument \else \!thx\!tqGetCode \fi} \def\!tqGetCode#1 % note the blank {\!tqConvertCode #1,,!} \def\!tqConvertCode #1,#2,#3!% {\begingroup \aftergroup\edef \aftergroup\!ttemp \aftergroup{% \aftergroup[% \scratchcounter#1\relax \!thLoop \ifnum \scratchcounter>\zerocount \advance\scratchcounter\minusone \aftergroup0 \repeat \def\!ttemp{#3}% \ifx\!ttemp\empty \else \aftergroup, \scratchcounter#2\relax \!thLoop \ifnum\scratchcounter>\zerocount \advance\scratchcounter\minusone \aftergroup0 \repeat \fi \aftergroup]\aftergroup}% \endgroup\relax \!thx\!tqGetArgument\!ttemp} \def\!tqGetArgument[#1]% {\!tqMakeQuantityTemplate\!tqStyle#1,,!} \def\!tqMakeQuantityTemplate#1#2,#3,#4!% #1= or $ {\def\!ttemp{#4}% \ifx\!ttemp\empty \!taDimenC\zeropoint \else \setbox\scratchbox\hbox{\mathsurround\zeropoint #1,#3#1}% \!taDimenC\wd\scratchbox \fi \setbox\scratchbox\hbox{\mathsurround\zeropoint #1#2#1}% \!thToksEdef\!taDataColumnTemplate {\noexpand\!tqSetQuantityItem{\the\wd\scratchbox}{\the\!taDimenC}{#1}% \the\!taDataColumnTemplate}% \doreadtableformatkeys} \def\!tqSetQuantityItem #1#2#3#4 % {\!tqSetQuantityItemA{#1}{#2}{#3}#4,,!} \def\!tqSetQuantityItemA #1#2#3#4,#5,#6!% {\def\!ttemp{#6}% \hbox to #1{\hss\mathsurround\zeropoint#3#4#3}% \hbox to #2{\ifx\!ttemp\empty\else\mathsurround\zeropoint#3,#5#3\fi\hss}} % \Enlarge % \enlarge \def\dotableEnlarge#1#2% {% 3rd argument is picked up later % #1=extra height % #2=extra depth \!taDimenA=#1\relax \!taDimenB=#2\relax \let\!TsSpaceFactor\empty \ifmmode \expandafter\mathpalette \expandafter\!TsEnlargeMath \else \expandafter\!TsEnlargeOther \fi} \def\!TsEnlargeOther#1% {\ifhmode \setbox\scratchbox\hbox{#1\xdef\!TsSpaceFactor{\spacefactor\the\spacefactor}}% \else \setbox\scratchbox\hbox{#1}% \fi \!TsFinishEnlarge} \def\!TsEnlargeMath#1#2% {\setbox\scratchbox\hbox{$\mathsurround\zeropoint#1{#2}$}% \!TsFinishEnlarge} \def\!TsFinishEnlarge {\ht\scratchbox\dimexpr\ht\scratchbox+\!taDimenA\relax \dp\scratchbox\dimexpr\dp\scratchbox+\!taDimenB\relax \box\scratchbox \!TsSpaceFactor\relax} \def\dotableenlarge#1#2% 3rd argument is picked up later {\dotableEnlarge{#1\tablestrutunit}{#2\tablestrutunit}} \appendtoks \let\enlarge\dotableenlarge \let\Enlarge\dotableEnlarge \to \everytable % BEGIN TABLE \let\dotablestandardend\relax \def\dotablestandardbegin[#1]% \!ttBeginTable (always argument) {\if#1u% unboxed table \ifmmode \let\dotablestandardend\relax % user had better be in display math mode and have only one table at the outer level \else % user had better be in vertical mode \bgroup \let\dotablestandardend\egroup \fi \else \hbox\bgroup \def\dotablestandardend{\egroup\egroup}% \if#1t% \vtop \else\if#1b% \vbox \else \def\dotablestandardend{\egroup$\egroup}% %$\vcenter \scratchtoks\everymath\everymath\emptytoks$\everymath\scratchtoks\vcenter \fi\fi \bgroup % for the \vtop, \vbox, or \vcenter \fi \advance\!taRecursionLevel\plusone \let\!ttRightGlue\relax \everycr\emptytoks \ifnum\!taRecursionLevel=\plusone \the\everytable \fi} \bgroup \catcode\tildeasciicode\activecatcode \appendtoks \catcode\barasciicode\activecatcode \def~{\kern.5em}% \def\\{\ifhmode\space\else\par\fi}% \to \everytable \egroup \let\!ttRightGlue\relax % This may be changed, in a group, by \JustCenter, etc % DO HALIGN: Invoked by END FORMAT (or the key ".") \def\!ttDoHalign {\edef\dorestoretablelineskips {\baselineskip \the\baselineskip \lineskiplimit\the\lineskiplimit \lineskip \the\lineskip \tabskip \the\tabskip \relax}% \baselineskip \zeropoint \lineskiplimit\zeropoint \lineskip \zeropoint \tabskip \zeropoint \edef\p_tabl_table_textwidth{\directtablesparameter\c!textwidth}% \halign \ifx\p_tabl_table_textwidth\empty \else to \ifx\p_tabl_table_textwidth\v!max \hsize \else \p_tabl_table_textwidth \fi\fi % \the\!taTableSpread \bgroup \span \the\!taPreamble \ifx\!tfRowOfWidths\empty\else \!tfRowOfWidths\cr \fi} % END TABLE \def\dotablenormalend {\egroup % finishes the \halign \dotablestandardend} % closes off the table envirnoment set up by \tablestandardbegin \def\donormaltablelineending {\cr} \def\donormaltablelineformat#1#2% {\vrule \s!width \zeropoint \s!height\dimexpr\tablestrutheightfactor\tablestrutunit+#1\tablestrutunit\relax \s!depth \dimexpr\tablestrutdepthfactor \tablestrutunit+#2\tablestrutunit\relax \relax \cr} % INSERT VRULE \newcount\noftablevrules \noftablevrules\plusone \let\tablecurrentvrulecolor\empty \let\tablecurrenthrulecolor\empty \def\@VLd{.125em} \def\do!ttInsertVrule {\vrule\!!width \ifnum\!tgCode=\plusone \ifx\!tgValue\empty \tablevrulethicknessfactor \else \!tgValue \fi \tablelinethicknessunit \else \!tgValue \fi \hskip\@VLd} \def\donormaltablesimplebar {\unskip\!ttRightGlue&&} \def\donormaltablecomplexbar {\unskip\!ttRightGlue&\omit \hfil \ifx\tablecurrentvrulecolor\empty\else \switchtocolor[\tablecurrentvrulecolor]% \fi \ifcase\noftablevrules\or \do!ttInsertVrule \unskip \else \dorecurse\noftablevrules\do!ttInsertVrule \global\noftablevrules\plusone \unskip \fi \global\let\tablecurrentvrulecolor\empty \hfil &} \def\donormaltablenobar {\unskip\!ttRightGlue&\omit&} \def\donormaltablesinglerule {&\donormaltablelongrule&} \def\donormaltablemultirule {&\!ttuse\tabledrulespan\donormaltablelongrule&} % USE \def\!ttuse#1% {\ifnum#1>\plusone \omit \global\setfalse\istabledivision % added \scratchcounter\currenttablecolumn % added \advance\scratchcounter #1% % added \advance\scratchcounter \minusone % added \def\next % added {\global\advance\currenttablecolumn #1% % added \global\advance\currenttablecolumn \minusone % added \scratchcounter#1% \advance\scratchcounter \minusone \advance\scratchcounter \scratchcounter \!thLoop \ifnum\scratchcounter>\plusone \spanomit \advance\scratchcounter\minusone \repeat \span}% \else % added \def\next % conflicts with possible next \omit % added {\global\advance\currenttablecolumn \plusone}%% added \fi \next} % added \def\!ttUse#1[% {\!ttuse{#1}% \dotablereformat[} \appendtoks \let\use\!ttuse \let\Use\!ttUse \to \everytable % rules \def\donormaltablefullrule {\starttablenoalign \!ttGetHalfRuleThickness \hrule\s!height\scratchdimen\s!depth\scratchdimen \stoptablenoalign} \def\donormaltableshortrule % was: \!ttShortHrule {\omit \!ttGetHalfRuleThickness \ifx\tablecurrenthrulecolor\empty\else \switchtocolor[\tablecurrenthrulecolor]% see *DL* \fi \leaders\hrule\s!height\scratchdimen\s!depth\scratchdimen\hfill \emptyhbox \ignorespaces} \def\donormaltablelongrule % was: \!ttLongHrule {\omit\span \omit\span \donormaltableshortrule} \def\!ttGetHalfRuleThickness {\scratchdimen\dimexpr \ifnum\!tgCode=\plusone \ifx\!tgValue\empty \tablehrulethicknessfactor \else \!tgValue % user-specified integer \fi \tablelinethicknessunit \else \!tgValue % user-specified dimension \fi \divide\scratchdimen\plustwo} % \emptyhbox prevents \unskip \def\dotableLeft #1{#1\hfill\emptyhbox} \def\dotableCenter#1{\hfill#1\hfill\emptyhbox} \def\dotableRight #1{\hfill#1} \def\dotableOpenUp#1#2% {\edef\tablestrutheightfactor{\withoutpt\the\dimexpr\tablestrutheightfactor\points+#1\points}% \edef\tablestrutdepthfactor {\withoutpt\the\dimexpr\tablestrutdepthfactor \points+#2\points}} % SetTableToWidth -> textwidth=dimension [to dimension] % Expand -> textwidth=max [to \hsize] % WidenTableBy -> [spread #1] % \tablelefttabskip\zeropoint\s!plus1\s!fill % \tablerighttabskip\tablelefttabskip % LongLines -> [spread \hsize] \def\dotableJustLeft {\omit\let\!ttRightGlue\hfill} \def\dotableJustCenter{\omit\hfill\emptyhbox\let\!ttRightGlue\hfill} \def\dotableJustRight {\omit\hfill\emptyhbox} \def\dotableSmash {\relax \ifmmode \expandafter\mathpalette \expandafter\!thDoMathVCS \else \expandafter\!thDoVCS \fi} \def\!thDoVCS#1% {\setbox\zerocount\hbox{#1}% \!thFinishVCS} \def\!thDoMathVCS#1#2% {\setbox\zerocount\hbox{$\mathsurround\zeropoint#1{#2}$}% \!thFinishVCS} \def\!thFinishVCS {\vbox to\zeropoint{\vss\box\zerocount\vss}} \def\dotableRaise {\def\!thSign{+}% \!tgGetValue\!thSetDimen} \def\dotableLower {\def\!thSign{-}% \!tgGetValue\!thSetDimen} \def\!thSetDimen {\ifnum\!tgCode=\plusone \ifx\!tgValue\empty \!taDimenA\tablestrutheightfactor\tablestrutunit \advance\!taDimenA\tablestrutdepthfactor\tablestrutunit \divide\!taDimenA\plustwo \else \!taDimenA\!tgValue\tablestrutunit \fi \else \!taDimenA\!tgValue \fi \!taDimenA\!thSign\!taDimenA\relax \ifmmode \expandafter\mathpalette \expandafter\!thDoMathRaise \else \expandafter\!thDoSimpleRaise \fi} \def\!thDoSimpleRaise#1% {\setbox\zerocount\hbox{\raise \!taDimenA\hbox{#1}}% \!thFinishRaise} % From Plain TeX: \ht0=0pt \dp0=0pt \box0 \def\!thDoMathRaise#1#2% {\setbox\zerocount\hbox{\raise \!taDimenA\hbox{$\mathsurround\zeropoint#1{#2}$}}% \!thFinishRaise} \def\!thFinishRaise {\ht\zerocount\zeropoint \dp\zerocount\zeropoint \box\zerocount} \def\dotableBackSpace {\!tgGetValue\!thKernBack} \def\!thKernBack {\kern - \ifnum\!tgCode=\plusone \ifx\!tgValue\empty \tablekernfactor \else \!tgValue % user-specified integer \fi \tablekernunit \else \!tgValue % user-specified dimension \fi \ignorespaces} \def\dotableVspace {\noalign \bgroup \!tgGetValue\!thVspace} \def\!thVspace {\vskip \ifnum\!tgCode=\plusone \ifx\!tgValue\empty \tablevspacefactor \else \!tgValue % user-specified integer \fi \tablestrutunit \else \!tgValue % user-specified skip \fi \egroup} % Ends the \noalign \appendtoks \let\JustLeft \dotableJustLeft \let\JustCenter \dotableJustCenter \let\JustRight \dotableJustRight \let\Smash \dotableSmash \let\Raise \dotableRaise \let\Lower \dotableLower \let\BackSpace \dotableBackSpace \let\Vspace \dotableVspace \let\OpenUp \dotableOpenUp \let\TableLeft \dotableLeft \let\TableCenter \dotableCenter \let\TableRight \dotableRight \to \everytable %D \macros %D {inintable, ifsplittables} %D %D First we declare some variables. These show a bit what we %D are dealing with. First we introdoce some booleans that %D enable us, inside as well as outside this module, to %D determine in what mode we are. \newif\ifintable \newif\ifsplittables %D We show this feature in an example that also shows some of %D the basic table typesetting commands. %D %D \startbuffer %D \starttable[|||] %D \HL %D \VL first \VL second \VL\AR %D \HL %D \VL alfa \VL 1 \VL\AR %D \VL beta \VL 2 \VL\AR %D \VL gamma \VL 3 \VL\AR %D \HL %D \stoptable %D \stopbuffer %D %D \startlinecorrection %D \getbuffer %D \stoplinecorrection %D %D This table is specified as: %D %D \typebuffer %D %D This examples shows about the minimum of commands needed to %D typeset such a table. In this table, the \type {\AR} is %D automatically translated into the more primitive (but more %D verbose) commands \type {\SR}, \type {\FR}, \type {\MR} and %D \type {\LR} commands. %D %D \startbuffer %D \starttables[|||] %D \HL %D \VL first \VL second \VL\AR %D \HL %D \VL alfa \VL 1 \VL\AR %D \VL beta \VL 2 \VL\AR %D \VL gamma \VL 3 \VL\AR %D \HL %D \stoptables %D \stopbuffer %D %D \getbuffer %D %D Some simple color support is provided: %D %D \startbuffer %D \starttable[|c|c|] %D \HL %D \VL test \VL test \VL \SR %D \HL[green,5] %D \VL[red] test \VL test \VL \FR %D \VL test \VL[10,red] test \VL \MR %D \VL test \VL test \VL[10] \LR %D \HL %D \stoptable %D \stopbuffer %D %D \typebuffer \getbuffer \installcorenamespace{tabletemplate} \def\m!TABLE{TABLE} %D We already saw that the table macros report errors and %D provide automatic spacing. These features can only be %D implemented by keeping track of the state, often the last %D command on a row. \newconstant\tableforcestate \newconstant\tableactionstate \setnewconstant\tableunknownstate 0 \setnewconstant\tableseparaterowstate 1 \setnewconstant\tablefirstrowstate 2 \setnewconstant\tablemidrowstate 3 \setnewconstant\tablelastrowstate 4 \setnewconstant\tablerulestate 5 %setnewconstant\tableskipstate 6 %setnewconstant\tableautorowstate 7 \setnewconstant\tableforcefirstrowstate 1 \setnewconstant\tableforcelastrowstate 2 \newconstant\tablerowfactor \newconstant\TABLEendofrowdepth \newconstant\TABLEendofrowheight \newconstant\TABLEcr \newconstant\tablerowzero \newconstant\TABLEn %D We store these states using \type {constants}'s and %D like most variables, these are global ones. When needed, %D especially when we flush the backgrounds, we can temporary %D disable the assignment. \newconditional\tableactionstatepermitted \def\dosettableaction#1{\ifconditional\tableactionstatepermitted\global\tableactionstate#1\fi} \def\dosettableforce #1{\ifconditional\tableactionstatepermitted\global\tableforcestate #1\fi} %D To give an impression of what the (well documented) source %D of \TABLE\ looks like, we first implement an alternative for %D the numeric keys. The quantity keys (\type{q} and \type{Q}) %D support the more european way of writing numbers: %D %D \startnarrower %D 100.000.000,00 instead of 100,000,000.00 %D \stopnarrower %D %D The next table shows how to use these keys. We use braces %D instead of brackets because we need brackets to specify the %D format. %D %D \starttyping %D \starttable{|q[00,000]|Q[00,00]|} %D \HL %D \VL -1,2 \VL 12,35 \VL\FR %D \VL 11,203 \VL 2,4 \VL\LR %D \HL %D \stoptable %D \stoptyping %D %D Although a more efficient implementation is possible |<|we %D can for instance share common macros|>| we just adapt a copy %D of the numeric ones. To permit double loading of this %D module, we check for the existence of one of the macros. %D To be compatible with the tabulate environment, we also %D support the \type {l}, \type {c} and \type {r} keys for %D paragraph entries. %D All commands that are executed between rows are to be put in %D \type {\noalign}. We can however not verify if we (that is %D \TABLE) does or did not enter this mode. A moderate dirty %D but useful trick is using our own alternative:\footnote{Once %D one has entered the stage of redefining \TEX\ primitives, %D such hacks become a second nature. However, redefining \type %D {\omit} and \type{\span} is not that easy.} \def\tablenoalign {\noalign \bgroup \let\noalign\relax \let\tablenoalign\relax \let\next=} \def\starttablenoalign {\tablenoalign\bgroup} \let\stoptablenoalign\egroup %D \macros %D {starttable} %D %D The rest of this module is not easy to comprehend, mainly %D because we have to take care of: %D %D \startitemize[packed] %D \item \type{\startitemize[template]} %D \item \type{\startitemize{template}} %D \item \type{\startitemize[predefined]} %D \stopitemize %D %D as well as: %D %D \startitemize[continue] %D \item restart after table break %D \stopitemize %D %D The official specification of the start command is: %D %D \showsetup{starttable} \newconditional\tablerepeathead \newconditional\tablerepeattail \unexpanded\def\starttable {\bgroup \dodoubleempty\dostarttable} \unexpanded\def\dostarttable[#1][#2]% preamble optional-settings {\ifsecondargument \setupcurrenttables[#2]% \fi \let\stoptable\dostoptable \edef\p_tabl_table_split{\directtablesparameter\c!split}% \edef\p_tabl_table_frame{\directtablesparameter\c!frame}% \ifx\p_tabl_table_split\v!auto \ifinsidesplitfloat \let\p_tabl_table_split\v!yes \lettablesparameter\c!split\v!yes % might be used later, best make a proper mode \fi \fi \ifx\p_tabl_table_split\v!yes \def\stoptable{\dostoptables\egroup}% not \unexpanded as we look ahead \expandafter\starttables \else\ifx\p_tabl_table_split\v!repeat \def\stoptable{\dostoptables\egroup}% not \unexpanded as we look ahead \doubleexpandafter\starttables \else \ifx\p_tabl_table_frame\empty \ifinsidefloat\else\startbaselinecorrection\fi \else \startframedcontent[\p_tabl_table_frame]% \fi \postponenotes \doubleexpandafter\firststagestarttable \fi\fi [#1]} % We cannot define \unexpanded\def\dostoptable a ssomehow lookahead % in alignments fail then, so we relax it and define it locally. \let\stoptable\relax \def\dostoptable {\dochucktableautorow % before the tail, else noalign problem \doinserttabletail \starttablenoalign \global\let\dotablehead\empty \global\let\dotabletail\empty \stoptablenoalign \dofinishtable \ifx\p_tabl_table_frame\empty \ifinsidefloat\else \stopbaselinecorrection \goodbreak % compensates all the nobreaks \fi \else \stopframedcontent \fi \egroup} %D Before we can grab the argument, we have to make sure that %D the \CATCODES\ are set. The first stage takes care of that. \def\firststagestarttable {\bgroup \global\intabletrue \secondstagestarttable} %D \macros %D {definetabletemplate} %D %D The complex (and main) start macro first takes care of the %D predefined case. Such a predefined setup looks like: %D %D \starttyping %D \definetabletemplate[test][|||] %D %D \starttable[test] %D \VL test \VL test \VL\AR %D \VL test \VL test \VL\AR %D \VL test \VL test \VL\AR %D \stoptable %D \stoptyping %D %D The implementation of the definition macro is not that %D complicated: \installcorenamespace{tablehead} \installcorenamespace{tabletail} \unexpanded\def\definetabletemplate % to be redone {\bgroup \catcode\barasciicode\othercatcode \doquadrupleempty\dodefinetabletemplate} \def\dodefinetabletemplate[#1][#2][#3][#4]% {\ifsecondargument \setgvalue{\??tabletemplate#1}{\dousetabletemplate{#2}{#3}{#4}}% \fi \egroup} \def\dousetabletemplate#1#2#3% {\gdef\dotablehead{\executeifdefined{\??tablehead#2}\empty}% \gdef\dotabletail{\executeifdefined{\??tabletail#3}\empty}% \secondstagestarttable[#1]} %D The optional third and fourth arguments define which table %D head and tail to use. %D %D \starttyping %D \definetabletemplate[test][|||][before][after] %D \stoptyping %D %D This also means that one can define table heads and tails %D by name! %D %D \starttyping %D \starttablehead[before] %D \HL \VL first \VL second \VL \SR \HL %D \stoptablehead %D \stoptyping %D %D Templates defined this way get protected names, that cannot %D conflict with existing commands. %D %D \showsetup{definetabletemplate} %D %D The second half of the next macro prepares table %D splitting. \def\doinserttablehead {\starttablenoalign \global\settrue\preventtablebreak \global\setfalse\hassometablehead \stoptablenoalign \dotablehead \starttablenoalign \global\setfalse\preventtablebreak \stoptablenoalign} \def\doinserttabletail {\starttablenoalign \global\settrue\preventtablebreak \global\setfalse\hassometabletail \stoptablenoalign \dotabletail \starttablenoalign \global\setfalse\preventtablebreak \stoptablenoalign} % \def\doverysimpletableHL % todo % {\starttablenoalign % \normalexpanded{\noexpand\donormaltablefullrule\m_tabl_table_HLheight}% % \stoptablenoalign} \def\dorestarttable#1% {\gdef\restarttable{#1}% \restarttable % \starttablenoalign % \globalpushmacro\simpletableHL % \global\let\simpletableHL\doverysimpletableHL % \stoptablenoalign \doinserttablehead \ifsplittables \ifconditional \tablerepeattail \tablenoalign{\goodbreak}% \doinserttabletail \tablenoalign{\goodbreak}% \fi \fi % \starttablenoalign % \globalpopmacro\simpletableHL % \stoptablenoalign } \bgroup \catcode\barasciicode\othercatcode \gdef\secondstagestarttable[#1]% brr nested mess {\bgroup \@@useotherbar \global\setfalse\tableactionstatepermitted \global\setfalse\hassometablehead \global\setfalse\hassometabletail \expanded{\doifelseinstring{|}{#1}} {\xdef\restarttable{\noexpand\dorestarttable{\noexpand\thirdstagestarttable{#1}}}} {\doifelsedefined{\??tabletemplate#1} {\gdef\restarttable{\getvalue{\??tabletemplate#1}}} {\gdef\restarttable{\dorestarttable{\getvalue{#1}}}}}% \egroup \restarttable} \egroup %D The third stage involves a lot of (re)sets, which we will %D explain later. \appendtoks \fixedspaces \let\_\normalunderscore \to \everytable %D Now we can start the table. \newtoks \localtabledefinitions \def\thirdstagestarttable#1% {\global\settrue\tableactionstatepermitted \dosettableaction\tableunknownstate \dosettableforce\tableunknownstate \dotableresetVLvalues \appendtoks\dolocaltablesetup\to\everytable \dotablestandardbegin[\ifsplittables u\else b\fi]% \the\localtabledefinitions \forgetall % added \edef\currenttableformat{#1}% \doifsomething\currenttableformat {\dogettablenofcolumns\currenttableformat % more modern is to use catcode tables \expandafter\dobegintableformat\currenttableformat\doendtableformat}} \def\dofinishtable {\dochucktableautorow \unskip\crcr \dotablenormalend \global\intablefalse \egroup} %D \macros %D {starttables} %D %D Split tables are specified using the plural form of the %D start and stop commands. %D %D \showsetup{starttables} %D %D For example: %D %D \starttyping %D \starttables[|||] %D \HL %D \VL element \VL atom weight \VL\AR %D \HL %D \VL ....... \VL ........... \VL\AR %D \VL ....... \VL ........... \VL\AR %D \HL %D \stoptables %D \stoptyping \newbox\tablecontentbox \unexpanded\def\starttables {\bgroup \let\stoptables\dostoptables \splittablestrue \edef\p_tabl_table_split{\directtablesparameter\c!split}% \ifx\p_tabl_table_split\v!repeat \settrue\tablerepeathead \settrue\tablerepeattail \else \setfalse\tablerepeathead \setfalse\tablerepeattail \fi \flushnotes \setbox\tablecontentbox\vbox\bgroup \forgetall \firststagestarttable} \let\stoptables\relax % needed for \noalign \def\dostoptables % not \unexpanded as we need the lookahead (brrr) {\dochucktableautorow % AM: before the tail, else noalign problem \ifconditional\tablerepeattail\else\doinserttabletail\fi \dofinishtable \egroup \dontcomplain \dosplittablebox\tablecontentbox \global\let\dotablehead\empty % new here \global\let\dotabletail\empty % new here \flushnotes \egroup} \def\dosplittablebox#1% {\resettsplit \def\tsplitminimumfreelines{2}% \def\tsplitminimumfreespace{\zeropoint}% \setbox\tsplitcontent\box#1% \ifconditional\tablerepeathead \ifconditional\hassometablehead \setbox\tsplithead\vsplit\tsplitcontent to \lineheight \setbox\tsplithead\vbox{\unvbox\tsplithead}% \fi \fi \ifconditional\tablerepeattail \ifconditional\hassometabletail \setbox\tsplittail\vsplit\tsplitcontent to \lineheight \setbox\tsplittail\vbox{\unvbox\tsplittail}% \fi \fi \ifinsidefloat\else \def\tsplitbeforeresult{\startbaselinecorrection}% \def\tsplitafterresult {\stopbaselinecorrection}% \fi \handletsplit} %D When the table in the previous example is split across %D pages, only the first gets a head. We could have said %D something like: %D %D \starttyping %D \starttablehead %D \HL %D \VL element \VL atom weight \VL\AR %D \HL %D \stoptablehead %D %D \starttabletail %D \HL %D \stoptabletail %D %D \starttables[|||] %D \VL ....... \VL ........... \VL\AR %D \VL ....... \VL ........... \VL\AR %D \stoptables %D \stoptyping %D %D This time each split table gets a head line and ends with %D a rule. Keep in mind that such heads also apply to the %D unbroken ones and should be defined local (grouped) if %D needed. The rather complicated definition below is due to %D the fact that the stopcondition is interface language %D dependant. \let\dotablehead\empty % needs checking \let\dotabletail\empty % needs checking \letvalue{\e!start\v!tablehead}\relax \letvalue{\e!stop \v!tablehead}\relax \letvalue{\e!start\v!tabletail}\relax \letvalue{\e!stop \v!tabletail}\relax %D The second argument is a dummy one, by scanning for it, we %D get rid of interfering spaces. \newconditional\preventtablebreak \newconditional\hassometablehead \newconditional\hassometabletail \unexpanded\def\settablehead{\dodoubleempty\dosettablehead} \unexpanded\def\settabletail{\dodoubleempty\dosettabletail} % \def\dosettablehead[#1][#2]#3\end{\setvalue{\??tablehead#1}{\tablenoalign{\global\settrue\hassometablehead}#3}} % \def\dosettabletail[#1][#2]#3\end{\setvalue{\??tabletail#1}{\tablenoalign{\global\settrue\hassometabletail}#3}} \def\dosettablehead[#1][#2]#3\end {\gdef\dotablehead{\executeifdefined{\??tablehead#1}\empty}% new \setvalue{\??tablehead#1}{\tablenoalign{\global\settrue\hassometablehead}#3}} \def\dosettabletail[#1][#2]#3\end {\gdef\dotabletail{\executeifdefined{\??tabletail#1}\empty}% new \setvalue{\??tabletail#1}{\tablenoalign{\global\settrue\hassometabletail}#3}} \normalexpanded {\def\csname\e!start\v!tablehead\endcsname#1\csname\e!stop\v!tablehead\endcsname% {\settablehead#1\noexpand\end}} \normalexpanded {\def\csname\e!start\v!tabletail\endcsname#1\csname\e!stop\v!tabletail\endcsname% {\settabletail#1\noexpand\end}} %D Redundant \type{\HL}'s are removed automatically, so %D mid||lines can be used without problems. %D The order of the next macros is more or less random. First %D we implement error recovery. Errors are reported to the %D screen and log file as well as visualized in the table in %D teletype. \def\dofinishtablerow {\crcr \starttablenoalign \nobreak \dosettableaction\tableunknownstate \globalletempty\dochecktableautorow \globalletempty\dochucktableautorow \global\currenttablecolumn\zerocount \stoptablenoalign} %D Next we enter the more complicated area of column and row %D switching. I won't go into much detail from now on, but just %D mention the general principles. %D %D \startitemize[3*ruim] %D \sym{\type{\SR}} end a separate row (between rules) %D \sym{\type{\FR}} end a first row (after a rule) %D \sym{\type{\MR}} end a mid row (between text lines) %D \sym{\type{\LR}} end a last row (before a rule) %D \stopitemize %D %D and best of all: %D %D \startitemize[continue] %D \sym{\type{\AR}} end a row with automatic spacing %D \stopitemize %D %D As far as possible, we report confusing situations. In %D most cases one can use \type{\AR}, which transfigurates %D itself into one of the other types. %D %D \starttyping %D \starttable[||] %D \HL %D \VL a separate row \VL\SR %D \HL %D \VL a first row \VL\FR %D \VL a mid row \VL\MR %D \VL a last row \VL\LR %D \HL %D \stoptable %D \stoptyping %D %D In this example we could have used \type{\AR} without %D problems. %D %D Color or gray scale backgrounds precede the content. They %D are passed over horizontal (division) lines when needed. %D Errors in the color template are traced elsewhere. Here we %D only check for inconsistent spacing. Due to the way \TEX\ %D handles alignments, we cannot automate spacing for colored %D rows and columns. \setnewconstant\tablerowzero\zerocount \appendtoks \let\SR\dotableSR \let\FR\dotableFR \let\MR\dotableMR \let\LR\dotableLR \let\AR\dotableAR \to \localtabledefinitions \unexpanded\def\dotableSR {\ifnum\tableactionstate=\tablefirstrowstate \writestatus\m!TABLE{change \string\SR\space into \string\MR/\string\LR}% \else\ifnum\tableactionstate=\tablemidrowstate \writestatus\m!TABLE{change \string\SR\space into \string\MR/\string\LR}% \else\ifnum\tableactionstate=\tablemidrowstate \writestatus\m!TABLE{change \string\SR\space into \string\MR/\string\LR}% \fi\fi\fi \doendtablerow\tableseparaterowstate\tablerowfactor\tablerowfactor} \unexpanded\def\dotableFR {\ifnum\tableactionstate=\tablemidrowstate \writestatus\m!TABLE{change \string\FR\space into \string\MR/\string\LR}% \else\ifnum\tableactionstate=\tablelastrowstate \writestatus\m!TABLE{change \string\FR\space into \string\MR/\string\LR}% \fi\fi \doendtablerow\tablefirstrowstate\tablerowfactor\tablerowzero} \unexpanded\def\dotableMR {\ifnum\tableactionstate=\tablerulestate \writestatus\m!TABLE{change \string\MR\space into \string\FR/\string\SR}% \else\ifnum\tableactionstate=\tablelastrowstate \writestatus\m!TABLE{change \string\MR\space into \string\FR}% \fi\fi \doendtablerow\tablemidrowstate00} \unexpanded\def\dotableLR {\ifnum\tableactionstate=\tablerulestate \writestatus\m!TABLE{change \string\LR\space into \string\FR/\string\SR}% \fi \doendtablerow\tablelastrowstate\tablerowzero\tablerowfactor} %D \macros %D {ifcheckTABLEcolums} %D %D %D The next macros handle the actual row ending. This macro %D also take care of space corrections due to table splitting %D when \type{\MR} and collegues are used. When tracing is %D enabled, the corrections as well as the values used to %D determine the available space are shown (in color). By default %D checking is off. \def\doendtablerow#1#2#3% {\dosettableaction#1% \ifcase#1\relax % unknown \or \doendoftableline\SR\SR\tablerowfactor\tablerowfactor \or \doendoftableline\FR\FR\tablerowfactor\tablerowzero \or\ifnum\tableforcestate=\tableforcelastrowstate \doendoftableline\MR\LR\tablerowzero\tablerowfactor \else\ifnum\tableforcestate=\tableforcefirstrowstate \doendoftableline\MR\FR\tablerowfactor\tablerowzero \else \doendoftableline\MR\MR\tablerowzero\tablerowzero \fi\fi\or \doendoftableline\LR\LR\tablerowzero\tablerowfactor \fi \starttablenoalign \dosettableforce\tableunknownstate \global\currenttablecolumn\zerocount \ifconditional\preventtablebreak \nobreak \else \goodbreak \fi \stoptablenoalign} %D Handling \type{\AR} is postponed till the next row. The %D check takes care of the first and mid rows, the chuck macro %D |<|how about that name|>| handles the last row. \unexpanded\def\dotableAR {\globallet\dochecktableautorow\dodochecktableautorow \globallet\dochucktableautorow\dodochucktableautorow} \let\dochecktableautorow\empty \let\dochucktableautorow\empty \def\dodochecktableautorow {\globallet\dochecktableautorow\empty \ifnum\tableactionstate=\tablerulestate \FR\else \ifnum\tableactionstate=\tableunknownstate\FR\else \MR\fi\fi} \def\dodochucktableautorow {\globalletempty\dochecktableautorow \globalletempty\dochucktableautorow \ifnum\tableactionstate=\tablerulestate \SR\else \ifnum\tableactionstate=\tableunknownstate\SR\else \LR\fi\fi} %D When a table is split, we also add a tail and when present %D we repeat the table head. %D When tables are split, the spacing before and after a %D horizontal rule is corrected according to what we expect. \def\doendoftableline#1#2#3#4% {\ifx#1#2\else \writestatus\m!TABLE{\string#1\space changed into \string#2}% \fi \expandafter\donormaltablelineformat#3#4\crcr % \crcr nodig ? \tablenoalign{\nobreak\global\settrue\tableactionstatepermitted}} %D In order to prevent (as good as possible) alignment overflow %D and therefore \TEX\ error messages, we check the maximum %D number of columns. We keep track of the current column and %D maximum column by means of two \COUNTERS. Keep in mind that %D the number of \type{|}'s and \type{\VL}'s or alike is always %D one more than the number of columns. \newcount\currenttablecolumn %D While defining this macro we change the \CATCODE\ of %D \type{|}. When counting the bars, we use a non active %D representation of the bar, simply because we cannot be sure %D if the bar is active or not.\footnote{Normally it is, but %D \TABLE\ changes the catcode when needed.} \bgroup \catcode\barasciicode\othercatcode \gdef\@@otherbar {|} \catcode\barasciicode\activecatcode \gdef\@@useotherbar {\let|\@@otherbar} \egroup \bgroup \catcode\barasciicode\othercatcode \gdef\dogettablenofcolumns#1% todo: also divert this to lua as with tabulate {\bgroup \cleanupfeatures % needed ! \@@useotherbar \egroup} \egroup %D \startitemize[3*ruim] %D \sym{\type{\VL}} a vertical line %D \sym{\type{\VC}} a vertical colored line %D \sym{\type{\HL}} a horizontal line %D \sym{\type{\HC}} a horizontal colored line %D \stopitemize \newcount\tablevrulethicknessfactor \newcount\tablehrulethicknessfactor \newcount\tabledrulespan \let \tablecurrentvrulecolor \empty \let \tablecurrenthrulecolor \empty \appendtoks \let\VL\dotableVL \let\VC\dotableVC \let\HL\dotableHL \let\HC\dotableHC \let\VS\dotableVS \let\VD\dotableVD \let\VT\dotableVT \let\VN\dotableVN \to \localtabledefinitions \def\dotableresetVLvalues {\global\currenttablecolumn\zerocount} \def\dotablevrulecommand#1% global assignments {\doifelsenumber{#1} {\global\tablevrulethicknessfactor#1\relax \global\multiply\tablevrulethicknessfactor\m_tabl_table_VLwidth\relax} {\xdef\tablecurrentvrulecolor{#1}}} \unexpanded\def\dotableVL {\dochecktableautorow \global\advance\currenttablecolumn\plusone \dosingleempty\dodotableVL} \def\dodotableVL[#1]% {\global\let\tablecurrentvrulecolor\empty \global\tablevrulethicknessfactor\m_tabl_table_VLwidth\relax \iffirstargument \rawprocesscommalist[#1]\dotablevrulecommand \fi \donormaltablecomplexbar}% \relax breaks \use \let\dotableVC\dotableVL % for mojca % \starttable[|||] % \HL % \VL test \VS test \VL \FR % \VL test \VD test \VL \MR % \VL test \VT test \VL \LR % \HL % \stoptable \unexpanded\def\dotableVS {\VN1} \unexpanded\def\dotableVD {\VN2} \unexpanded\def\dotableVT {\VN3} \unexpanded\def\dotableVN#1{\global\noftablevrules#1\relax\VL} \def\dotablehrulecommand#1% global assignments {\doifelsenumber{#1} {\global\tablehrulethicknessfactor#1\relax \global\multiply\tablehrulethicknessfactor\m_tabl_table_HLheight\relax} {\xdef\tablecurrenthrulecolor{#1}}} \unexpanded\def\dotableHL {\dochucktableautorow \dofinishtablerow \starttablenoalign \dosingleempty\dodotableHL} \def\dodotableHL[#1]% {\nobreak \ifnum\tableactionstate=\tablerulestate \writestatus\m!TABLE{skipping \string\HL}% \statusmessage \else \ifnum\tableactionstate=\tablemidrowstate \writestatus\m!TABLE{change \string\MR\space into \string\LR/\string\SR}% \else\ifnum\tableactionstate=\tablefirstrowstate \writestatus\m!TABLE{change \string\MR\space into \string\SR}% \fi\fi \bgroup \global\tablehrulethicknessfactor\m_tabl_table_HLheight\relax \iffirstargument \global\let\tablecurrenthrulecolor\empty \rawprocesscommalist[#1]\dotablehrulecommand \ifx\tablecurrenthrulecolor\empty\else \switchtocolor[\tablecurrenthrulecolor]% \fi \fi \donormaltablefullrule \egroup \doaccounttablelinewidth \fi \dosettableaction\tablerulestate \nobreak \stoptablenoalign} \let\dotableHC\dotableHL % for mojca %D \startitemize[3*ruim] %D \sym{\type{\NL}} a vertical skip %D \sym{\type{\NR}} goto the next row %D \sym{\type{\NC}} goto the next column %D \sym{\type{\FC}} a first column %D \sym{\type{\MC}} a mid column %D \sym{\type{\LC}} a last column %D \stopitemize % \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 % n+1 uitleggen \appendtoks \let\TB\dotableTB \let\NL\dotableNL % old \let\NR\dotableNR \let\NC\dotableNC \let\FC\dotableNC \let\MC\dotableNC \let\LC\dotableNC \to \localtabledefinitions \unexpanded\def\dotableTB {\dochucktableautorow \dofinishtablerow \starttablenoalign \dosingleempty\dodotableTB} \def\dodotableTB[#1]% {\blank[\iffirstargument#1\else\directtablesparameter\c!NL\fi]% \nobreak \stoptablenoalign} \let\dotableNL\dotableTB \unexpanded\def\dotableNR {\global\currenttablecolumn\zerocount \donormaltablelineending \starttablenoalign \nobreak \dosettableaction\tableunknownstate \stoptablenoalign} \unexpanded\def\dotableNC {\dochecktableautorow \global\advance\currenttablecolumn \plusone \donormaltablenobar} %D \startitemize[3*broad] %D \sym{\type{\DL}} %D \sym{\type{\DV}} (\type{\VD}) %D \sym{\type{\DC}} %D \sym{\type{\DR}} %D \stopitemize \newconditional\istabledivision \appendtoks \global\setfalse\istabledivision \let\DL\dotableDL \let\DC\dotableDC \let\DV\dotableDV \let\DR\dotableDR \to \localtabledefinitions \def\dochecktabledivision {\ifconditional\istabledivision\else \dochucktableautorow \global\currenttablecolumn\zerocount \global\settrue\istabledivision \fi} \def\dotabledrulecommand#1% global assignments {\doifelsenumber{#1} {\ifcase\tabledrulespan \global\tabledrulespan#1\relax \else \global\tablehrulethicknessfactor#1\relax \global\multiply\tablehrulethicknessfactor\m_tabl_table_VLwidth\relax \fi} {\xdef\tablecurrenthrulecolor{#1}}} \unexpanded\def\dotableDL {\dochecktabledivision \dosingleempty\dodotableDL} \def\dodotableDL[#1]% {\ifnum\tableactionstate=\tablerulestate \writestatus\m!TABLE{skipping \string\DL}% \else \ifnum\tableactionstate=\tablemidrowstate \writestatus\m!TABLE{change \string\MR\space into \string\LR/\string\SR}% \else\ifnum\tableactionstate=\tablefirstrowstate \writestatus\m!TABLE{change \string\MR\space into \string\SR}% \fi\fi \dosettableaction\tableunknownstate \global\tablehrulethicknessfactor\m_tabl_table_HLheight\relax \global\tabledrulespan\zerocount \iffirstargument \global\let\tablecurrenthrulecolor\empty \rawprocesscommalist[#1]\dotabledrulecommand % \ifx\tablecurrenthrulecolor\empty\else % \switchtocolor[\tablecurrenthrulecolor]% see *DL* % \fi \fi \ifcase\tabledrulespan \global\advance\currenttablecolumn \plusone \donormaltablesinglerule \or \global\advance\currenttablecolumn \plustwo \donormaltablesinglerule \else \global\advance\currenttablecolumn \plusone \donormaltablemultirule \fi \fi} \unexpanded\def\dotableDV {\dotableDCV\donormaltablesimplebar} \unexpanded\def\dotableDC {\dotableDCV\donormaltablenobar} \unexpanded\def\dotableDCV#1% {\dochecktabledivision \dochecktableautorow \global\advance\currenttablecolumn \plusone #1} \unexpanded\def\dotableDR {\global\currenttablecolumn\zerocount % nog check \donormaltablelineending \starttablenoalign \nobreak \global\setfalse\istabledivision \doaccounttablelinewidth % temporary solution \dosettableaction\tablerulestate \stoptablenoalign} \def\doaccounttablelinewidth {\scratchdimen\tablelinethicknessunit} \def\dotableTWO {\use\plustwo} \def\dotableTHREE {\use\plusthree} \def\dotableFOUR {\use\plusfour} \def\dotableFIVE {\use\plusfive} \def\dotableSIX {\use\plussix} \appendtoks \let\TWO \dotableTWO \let\THREE\dotableTHREE \let\FOUR \dotableFOUR \let\FIVE \dotableFIVE \let\SIX \dotableSIX \let\SPAN \use \let\REF \dotablereformat \to \localtabledefinitions \installcorenamespace{tables} \installcorenamespace{tabledistance} \installcorenamespace{tablealign} \installsetuponlycommandhandler \??tables {tables} % some day we can have named tables \setvalue{\??tabledistance\v!none }{\dotableOpenUp00\def\LOW{\Lower6 }} \setvalue{\??tabledistance\v!small }{\dotableOpenUp00\def\LOW{\Lower6 }} % == baseline \setvalue{\??tabledistance\v!medium}{\dotableOpenUp11\def\LOW{\Lower7 }} \setvalue{\??tabledistance\v!big }{\dotableOpenUp22\def\LOW{\Lower8 }} \appendtoks \expandnamespaceparameter\??tabledistance\directtablesparameter\c!distance\v!medium \to \localtabledefinitions \setvalue{\??tablealign\v!right }{\def\dotableparalignment{\raggedright}} \setvalue{\??tablealign\v!left }{\def\dotableparalignment{\raggedleft}} \setvalue{\??tablealign\v!middle }{\def\dotableparalignment{\raggedcenter}} \setvalue{\??tablealign\s!unknown}{\def\dotableparalignment{\notragged}} \appendtoks \doifelse{\directtablesparameter\c!distance}\v!none {\tablerowfactor\zerocount} {\tablerowfactor\plustwo }% \to \localtabledefinitions \def\dohandlebar % here ? {\ifmmode \@EA\domathmodebar \else\ifintable \@EAEAEA\domathmodebar \else \@EAEAEA\dotextmodebar \fi\fi} \appendtoks \expandnamespaceparameter\??tablealign\directtablesparameter\c!align\s!unknown \assignalfadimension{\directtablesparameter\c!VL}\m_tabl_table_VLwidth 246% \assignalfadimension{\directtablesparameter\c!HL}\m_tabl_table_HLheight246% \to \everysetuptables \def\dolocaltablesetup {\directtablesparameter\c!commands\relax \usebodyfontparameter\directtablesparameter \tablelinethicknessunit\dimexpr\directtablesparameter\c!rulethickness/\tablelinethicknessfactor\relax \edef\p_tabl_table_height{\directtablesparameter\c!height}% \edef\p_tabl_table_depth{\directtablesparameter\c!depth}% \ifx\p_tabl_table_height\v!strut \let\tablestrutheightfactor\tablestrutheightfactor \else \let\tablestrutheightfactor\p_tabl_table_height \fi \ifx\p_tabl_table_depth\v!strut \let\tablestrutdepthfactor\tablestrutdepthfactor \else \let\tablestrutdepthfactor\p_tabl_table_depth \fi \edef\tablestrutheightfactor{\withoutpt\the\dimexpr10\dimexpr\tablestrutheightfactor\points}% \edef\tablestrutdepthfactor {\withoutpt\the\dimexpr10\dimexpr\tablestrutdepthfactor \points}% \tablestrutunit\dimexpr\normalbaselineskip/12\relax % 12 is default bodyfont \tableintercolumnspaceunit.5em plus 1fil minus .25em\relax \tablecolumnwidthunit .5em\relax \tablekernunit .5em\relax} %D As one can see, we didn't only add color, but also more %D control over spacing. %D %D \startbuffer[a] %D \starttable[|c|] %D \HL %D \VL \strut test \VL \FR %D \VL \strut test \VL \MR %D \VL \strut test \VL \MR %D \VL \strut test \VL \LR %D \HL %D \stoptable %D \stopbuffer %D %D \startbuffer[b] %D \starttabulate[|c|] %D \HL %D \NC test \NC \NR %D \NC test \NC \NR %D \NC test \NC \NR %D \NC test \NC \NR %D \HL %D \stoptabulate %D \stopbuffer %D %D In the next example, the first table is defined as: %D %D \typebuffer[a] %D %D and the second one as: %D %D \typebuffer[b] %D %D The first table is typeset using the default height and %D depth factors .8 and .4. The second table has both factors %D set to \type {strut}, and the third table shows what %D happens when we set the values to zero. The rightmost table %D is typeset using the tabulate environment. %D %D \startcombination[4*1] %D {$\vcenter{\getbuffer[a]}$} %D {\hbox{h=.8 d=.4}} %D {\setuptables[height=strut,depth=strut]$\vcenter{\getbuffer[a]}$} %D {\hbox{h=d=\type{strut}}} %D {\setuptables[height=0,depth=0]$\vcenter{\getbuffer[a]}$} %D {\hbox{h=d=0}} %D {$\vcenter{\getbuffer[b]}$} %D {\hbox{tabulate}} %D \stopcombination \setuptables [\c!HL=\v!medium, \c!VL=\v!medium, \c!NL=\v!small, \c!frame=, \c!align=\v!right, \c!depth=.40, % \v!strut \c!height=.80, % \v!strut \c!textwidth=, \c!rulethickness=\linewidth, \c!rulecolor=, \c!distance=\v!medium, \c!bodyfont=, \c!commands=, \c!background=, \c!backgroundcolor=, \c!split=\v!auto] \protect \endinput