tabl-tab.mkiv /size: 66 Kb    last modification: 2021-10-28 13:50
1%D \module
2%D   [       file=core-tab,
3%D        version=1997.10.10,
4%D          title=\CONTEXT\ Table Macros,
5%D       subtitle=\TABLE\ Embedding,
6%D         author=Hans Hagen with copied and patched code from MJ Wichura,
7%D           date=\currentdate]
8%C
9%C This module is part of the \CONTEXT\ macro||package and is
10%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
11%C details.
12
13\writestatus{loading}{ConTeXt Table Macros / TaBlE Embedding}
14
15% Todo: a bitmore namespace protection ... although we want to keep some of the
16% original flavour.
17%
18% In \MKIV\ the old table macros are sort of obsolete. The color extensions have
19% been removed and some code is stripped. For practical reasons the \TABLE\ macros
20% that are used are embedded in this file.
21%
22% The following code is based on TABLE 1.0 by Michael J. Wichura (August 1988. We
23% used a patched version with many overloads and extensions. The documented (and
24% larger) source can be found in \type {thrd-tab.tex}.
25%
26% Some code has been stripped. Some color has been added. Some macros have been
27% renamed. Registers have been replaces. And probably much more can be cleaned up.
28% We also need to use \tabl_tab_ prefixes here.
29
30\unprotect
31
32\newconditional\c_tabl_table_spacing_left
33\newconditional\c_tabl_table_spacing_right
34
35\newdimen      \d_tabl_table_line_thickness_unit
36\newdimen      \d_tabl_table_strut_unit
37\newskip       \s_tabl_table_inter_column_space_unit
38\newdimen      \d_tabl_table_column_width_unit
39\newdimen      \d_tabl_table_kern_unit
40
41\def\tablestrutheightfactor      {8}
42\def\tablestrutdepthfactor       {3}
43\def\tableintercolumnspacefactor {3}
44\def\tablecolumnwidthfactor     {10}
45\def\tablevspacefactor           {2}
46\def\tablekernfactor             {1}
47\def\tablelinethicknessfactor    {4}
48
49\newtoks\everytable
50\newtoks\everytableparbox
51
52\unexpanded\def\tabl_table_begin_par_box#1%
53  {\setbox\scratchbox\vtop\bgroup % \setbox added
54     \hsize#1\relax
55     \dontcomplain
56     \tabl_table_restore_lineskips
57     \normalbaselines
58     \let~\fixedspace
59     \inhibitblank % \blank[\v!disable]% % added
60     \the\everytableparbox}
61
62\unexpanded\def\tabl_table_end_par_box
63  {\removelastskip                                     % itemize or so
64   \endgraf
65   \ifnum\prevgraf>\zerocount                          % we want at least
66     \verticalstrut \nowhitespace \vskip-\struttotal   % one line of text
67     \egroup
68     \ifdim\dp\scratchbox>\lineheight                  % see (*) for an
69       \getnoflines{\dp\scratchbox}%                   % example of where
70       \dp\scratchbox\zeropoint                        % saving can go
71       \setbox\scratchbox                              % terrible wrong
72         \vtop to \noflines\lineheight{\box\scratchbox}%
73     \fi                                               % esp between rows
74   \else                                               % of paragraphs
75     \egroup
76   \fi
77   \box\scratchbox}
78
79\appendtoks
80    \parindent\zeropoint
81    \raggedright
82    \rightskip\zeropoint \s!plus 4em \relax
83\to \everytableparbox
84
85\newskip \tablelefttabskip
86\newskip \tablerighttabskip
87
88\newcount\!taColumnNumber
89\newcount\!taRecursionLevel % (Initially 0)
90
91\newdimen\!taDimenA  % used by \Enlarge
92\newdimen\!taDimenB  % used by \Enlarge
93\newdimen\!taDimenC  % used by numeric.tex
94\newdimen\!taMinimumColumnWidth
95
96\newtoks \!taTableSpread
97\newtoks \!taPreamble
98\newtoks \!taDataColumnTemplate
99\newtoks \!taRuleColumnTemplate
100\newtoks \!taOldRuleColumnTemplate
101\newtoks \!taLeftGlue
102\newtoks \!taRightGlue
103
104\newskip \!taLastRegularTabskip
105
106\newif   \if!taBeginFormat
107\newif   \if!taOnceOnlyTabskip
108
109\def\!thToksEdef#1#2%
110  {\edef\tempstring{#2}%
111   #1\expandafter{\tempstring}%
112   \ignorespaces}
113
114\def\!thLoop#1\repeat
115  {\def\!thIterate{#1\expandafter \!thIterate\fi}%
116   \!thIterate
117   \let\!thIterate\relax}
118
119\def\tabl_table_begin_format
120  {\!taPreamble\emptytoks
121   \!taColumnNumber\zerocount
122   \scratchskip\s_tabl_table_inter_column_space_unit
123   \multiply\scratchskip\tableintercolumnspacefactor
124   \divide\scratchskip\plustwo
125   \!taRuleColumnTemplate\expandafter{\expandafter\tabskip\the\scratchskip}%
126   \!taLastRegularTabskip\scratchskip
127   \!taOnceOnlyTabskipfalse
128   \!taBeginFormattrue
129   \let\!tfRowOfWidths\empty
130   \doreadtableformatkeys}
131
132\def\!tfSetWidth
133  {\ifx\!tfRowOfWidths\empty            % true if no prior "w" keys
134     \ifnum\!taColumnNumber>\zerocount  % true if "w" key is to right of first "|"
135       \begingroup                      % RowOfWidths={\aligntab\omit || n copies of \aligntab\omit\aligntab#\omit}, where n = number of column to the left of this one
136         \scratchcounter\plusone
137         \aftergroup\edef
138         \aftergroup\!tfRowOfWidths
139         \aftergroup{%
140         \aftergroup\aligntab
141         \aftergroup\omit
142         \!thLoop
143           \ifnum \scratchcounter<\!taColumnNumber
144             \advance\scratchcounter\plusone
145             \aftergroup\!tfAOAO
146         \repeat
147         \aftergroup}%
148       \endgroup
149     \fi
150   \fi
151   \ifx[\tempstring % \!tgGetValue sets \tempstring = token after w
152     \expandafter\!tfSetWidthText
153   \else
154     \expandafter\!tfSetWidthValue
155   \fi}
156
157\def\!tfAOAO{\aligntab\omit\aligntab\omit}
158
159\def\!tfSetWidthText[#1]%
160  {\def\!tfWidthText{#1}%
161   \doreadtableformatkeys}
162
163\def\!tfSetWidthValue
164  {\!taMinimumColumnWidth=
165     \ifnum\!tgCode=\plusone
166       \ifx\!tgValue\empty \tablecolumnwidthfactor \else \!tgValue \fi \d_tabl_table_column_width_unit
167     \else
168       \!tgValue
169     \fi
170   \let\!tfWidthText\empty %      Override possible prior `w[sample entry]'
171   \doreadtableformatkeys}
172
173\def\!tfSetTabskip
174  {\ifnum\!tgCode=\plusone
175     \scratchskip\s_tabl_table_inter_column_space_unit
176     \multiply\scratchskip \ifx\!tgValue\empty\tableintercolumnspacefactor\else\!tgValue\fi
177  \else
178    \scratchskip\!tgValue
179  \fi
180  \divide\scratchskip\plustwo
181  \ifnum\!taColumnNumber=\zerocount
182   %\!thToksEdef\!taRuleColumnTemplate{\the\!taRuleColumnTemplate\tabskip\the\scratchskip}%
183    \normalexpanded{\!taRuleColumnTemplate{\the\!taRuleColumnTemplate\tabskip\the\scratchskip}}%
184  \else
185   %\!thToksEdef\!taDataColumnTemplate{\the\!taDataColumnTemplate\tabskip\the\scratchskip}%
186    \normalexpanded{\!taDataColumnTemplate{\the\!taDataColumnTemplate\tabskip\the\scratchskip}}%
187  \fi
188  \if!taOnceOnlyTabskip\else
189    \!taLastRegularTabskip\scratchskip % Remember this Tabskip, for possible
190  \fi                                  % restoration after a subsequent"OnceOnly"
191  \doreadtableformatkeys}
192
193\def\!tfSetVrule
194  {\!thToksEdef\!taRuleColumnTemplate
195     {\hfil
196      \vrule
197      \noexpand\s!width
198      \ifnum\!tgCode=\plusone
199        \ifx\!tgValue\empty
200          \c_tabl_table_vrule_thickness_factor
201        \else
202          \!tgValue
203        \fi
204        \d_tabl_table_line_thickness_unit
205      \else
206        \!tgValue
207      \fi
208      \alignmark\alignmark\alignmark\alignmark
209      \hfil
210      \the\!taRuleColumnTemplate}%
211  \!tfAdjoinPriorColumn}
212
213\def\!tfSetAlternateVrule
214  {\afterassignment\!tfSetAlternateA
215   \scratchtoks}
216
217\def\!tfSetAlternateA
218  {\!thToksEdef\!taRuleColumnTemplate{\the\scratchtoks\the\!taRuleColumnTemplate}%
219   \!tfAdjoinPriorColumn}
220
221\def\!tfAdjoinPriorColumn
222  {\ifnum \!taColumnNumber=0
223     \!taPreamble=\!taRuleColumnTemplate % New \tabskip may have been added
224   \else
225     \ifx\!tfRowOfWidths\empty  % no "w" keys specified yet, not even this col
226     \else
227       \!tfUpdateRowOfWidths
228     \fi
229     \!thToksEdef\!taDataColumnTemplate{\the\!taLeftGlue\the\!taDataColumnTemplate\the\!taRightGlue}%
230     \!thToksEdef\!taPreamble{\the\!taPreamble\aligntab\the\!taDataColumnTemplate\aligntab\the\!taRuleColumnTemplate}%
231  \fi
232  \advance \!taColumnNumber \plusone
233  \if!taOnceOnlyTabskip
234    \!thToksEdef\!taDataColumnTemplate{\alignmark\alignmark\alignmark\alignmark\tabskip\the\!taLastRegularTabskip}%
235  \else
236    \!taDataColumnTemplate{\alignmark\alignmark}%
237  \fi
238  \!taRuleColumnTemplate\emptytoks
239  \!taLeftGlue{\hfil}%
240  \!taRightGlue{\hfil}%
241  \!taMinimumColumnWidth\zeropoint
242  \let\!tfWidthText\empty
243  \!taOnceOnlyTabskipfalse
244  \doreadtableformatkeys}
245
246\def\!tfUpdateRowOfWidths
247  {\ifx\!tfWidthText\empty \else
248     \!tfComputeMinColWidth
249   \fi
250   \edef\!tfRowOfWidths
251     {\!tfRowOfWidths
252      \aligntab
253      \omit
254      \ifdim \!taMinimumColumnWidth>\zeropoint
255        \hskip \the\!taMinimumColumnWidth
256      \fi
257      \aligntab
258      \omit}}
259
260\def\!tfComputeMinColWidth
261  {\setbox0\vbox
262     {\ialign{% Plain's initialized \halign; \tabskip=0pt \everycr={}
263      \span\the\!taDataColumnTemplate\cr
264      \!tfWidthText\cr}}%
265   \!taMinimumColumnWidth=\wd0 }
266
267\def\!tfFinishFormat
268  {\!thToksEdef\!taPreamble{%
269     \alignmark\alignmark\alignmark\alignmark\tabskip\tablelefttabskip
270     \aligntab
271     \the\!taPreamble\tabskip\tablerighttabskip
272     \aligntab
273     \alignmark\alignmark\alignmark\alignmark\tabskip\zeropoint\cr}
274   \!taBeginFormatfalse
275   \!ttDoHalign}
276
277\def\tabl_table_reformat[#1]% will become local
278  {\omit
279   \!taDataColumnTemplate{\alignmark\alignmark}%
280   \!taLeftGlue\emptytoks
281   \!taRightGlue\emptytoks
282   \begingroup
283   \tabl_table_use_bar
284   \expanded{\endgroup\noexpand\doreadtableformatkeys#1]}}% appear in a \tabl_table_reformat cmd; this is here as a safeguard.
285
286\appendtoks
287    \let\ReFormat\tabl_table_reformat
288\to \everytable
289
290\def\!tfEndReFormat
291  {\!tfReFormat}
292
293\appendtoks \tabl_table_paralignment \to \everytableparbox
294
295\def\!tfReFormat#1%
296  {\the \!taLeftGlue
297   \vbox{\forgetall\ialign{\span\the\!taDataColumnTemplate\cr#1\cr}}%
298   \the \!taRightGlue
299   \kern\zeropoint} % prevents \unskip / really needed
300
301\def\!tgGetValue#1%
302  {\def\!tgReturn{#1}%
303   \futurelet\tempstring\!tgCheckForParen}
304
305\def\!tgCheckForParen%
306  {\ifx\tempstring (%
307     \expandafter \!tgDoParen
308   \else
309     \expandafter \!tgCheckForSpace
310   \fi}
311
312\def\!tgDoParen(#1)%
313  {\def\!tgCode{2}% will be expanded
314   \def\!tgValue{#1}%
315   \!tgReturn}
316
317\def\!tgCheckForSpace
318  {\def\!tgCode{1}%
319   \let\!tgValue\empty
320   \ifx\tempstring\!thSpaceToken
321     \expandafter \!tgReturn
322   \else
323     \expandafter \!tgCheckForDigit
324   \fi}
325
326% \def\!tgCheckForDigit
327%   {\donefalse
328%         \ifx 0\tempstring \donetrue
329%    \else\ifx 1\tempstring \donetrue
330%    \else\ifx 2\tempstring \donetrue
331%    \else\ifx 3\tempstring \donetrue
332%    \else\ifx 4\tempstring \donetrue
333%    \else\ifx 5\tempstring \donetrue
334%    \else\ifx 6\tempstring \donetrue
335%    \else\ifx 7\tempstring \donetrue
336%    \else\ifx 8\tempstring \donetrue
337%    \else\ifx 9\tempstring \donetrue
338%    \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
339%    \ifdone
340%      \expandafter \!tgGetNumber
341%    \else
342%      \expandafter \!tgReturn
343%    \fi}
344
345\def\!tgCheckForDigit % less tokens: (could be an ifcsname)
346  {\donetrue
347   \ifx 0\tempstring \else \ifx 1\tempstring \else
348   \ifx 2\tempstring \else \ifx 3\tempstring \else
349   \ifx 4\tempstring \else \ifx 5\tempstring \else
350   \ifx 6\tempstring \else \ifx 7\tempstring \else
351   \ifx 8\tempstring \else \ifx 9\tempstring \else
352     \donefalse
353   \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
354   \ifdone
355     \expandafter \!tgGetNumber
356   \else
357     \expandafter \!tgReturn
358   \fi}
359
360% \def\!tgCheckForDigit % does not work
361%   {\relax\doifnumberelse\tempstring\!tgGetNumber\!tgReturn}
362
363\def\!tgGetNumber {\afterassignment\!tgGetNumberA\scratchcounter=}
364\def\!tgGetNumberA{\edef\!tgValue{\the\scratchcounter}\!tgReturn}
365
366\def\!tgSetUpParBox
367  {\normalexpanded
368     {\noexpand \doreadtableformatkeys
369        b{\tabl_table_begin_par_box
370            {\ifnum\!tgCode=\plusone
371               \ifx\!tgValue\empty
372                 \tablecolumnwidthfactor
373               \else
374                 \!tgValue
375               \fi
376               \d_tabl_table_column_width_unit
377             \else
378               \!tgValue
379             \fi}}%
380        a{\tabl_table_end_par_box}}}
381
382\def\!tgInsertKern
383  {\edef\tempstring
384     {\kern
385      \ifnum \!tgCode=\plusone
386        \ifx \!tgValue\empty
387          \tablekernfactor
388        \else
389          \!tgValue
390        \fi
391        \d_tabl_table_kern_unit
392      \else
393        \!tgValue
394      \fi}%
395   \edef\tempstring
396     {\noexpand\doreadtableformatkeys
397      \ifconditional\c_tabl_table_spacing_left
398         b{\tempstring}
399      \fi
400      \ifconditional\c_tabl_table_spacing_right
401        a{\tempstring}
402      \fi}%
403   \tempstring}
404
405\def\newtableformatkey    #1{\setvalue{!tk<\string#1>}}
406\def\doreadtableformatkeys#1{\getvalue{!tk<\string#1>}}
407
408% Key "b":  b{TOKENS} adds TOKENS to the left of (before) the template
409
410\newtableformatkey b#1%
411  {\expandafter\!tkJoin\expandafter{\the\!taDataColumnTemplate}{#1}%
412   \doreadtableformatkeys}
413
414\def\!tkJoin#1#2%
415  {\!taDataColumnTemplate{#2#1}}%
416
417% Key "a":  a{TOKENS} adds TOKENS to the right of (after) the template
418
419\newtableformatkey a#1%
420  {\toksapp\!taDataColumnTemplate{#1}%
421   \doreadtableformatkeys}
422
423% Key "\{": Enclose template in braces.
424
425\newtableformatkey \{%
426  {\!taDataColumnTemplate=\expandafter{\expandafter{\the\!taDataColumnTemplate}}%
427   \doreadtableformatkeys}
428
429% Key "*":  "*{N}{KEY LETTERS}" is equivalent to specifying
430% <KEY LETTERS>  N  times.
431% KEY LETTERS may contain further * specifications
432
433\newtableformatkey *#1#2%
434  {\scratchcounter=#1\relax
435   \scratchtoks\emptytoks
436   \!thLoop
437     \ifnum\scratchcounter>\zerocount
438     \toksapp\scratchtoks{#2}%
439     \advance\scratchcounter\minusone
440   \repeat
441   \expandafter\doreadtableformatkeys\the\scratchtoks}
442
443% Key "\LeftGlue": Specifies the glue (usually \hfil, or nothing) to be
444% added to extreme left of the template to position a column
445
446\newtableformatkey \LeftGlue#1%
447  {\!taLeftGlue{#1}%
448   \doreadtableformatkeys}
449
450\newtableformatkey \RightGlue#1%
451  {\!taRightGlue{#1}%
452   \doreadtableformatkeys}
453
454\newtableformatkey c%
455  {\prependtoks\raggedcenter\to\!taDataColumnTemplate
456   \doreadtableformatkeys \LeftGlue\hfil \RightGlue\hfil}
457
458\newtableformatkey l%
459  {\prependtoks\raggedright\to\!taDataColumnTemplate
460   \doreadtableformatkeys \LeftGlue\empty \RightGlue\hfil}
461
462\newtableformatkey r%
463  {\prependtoks\raggedleft\to\!taDataColumnTemplate
464   \doreadtableformatkeys \LeftGlue\hfil \RightGlue\empty}
465
466\newtableformatkey x%
467  {\prependtoks\notragged\to\!taDataColumnTemplate
468   \doreadtableformatkeys \LeftGlue\hfil \RightGlue\empty}
469
470% Key "k": Adds kerns to left and right of "#" This key and the two below use Plain
471% TeX's \if@h as if it were \if@left, and \if@v as if it were \if@right. Table
472% making goes on in a group, so even in the unlikely circumstance that a \phantom
473% is currently under construction, there's no problem.
474
475\newtableformatkey k%
476  {\settrue\c_tabl_table_spacing_left
477   \settrue\c_tabl_table_spacing_right
478   \!tgGetValue{\!tgInsertKern}}
479
480% Key "i": Adds a kern to the left of "#"
481
482\newtableformatkey i%
483  {\settrue\c_tabl_table_spacing_left
484   \setfalse\c_tabl_table_spacing_right
485   \!tgGetValue{\!tgInsertKern}}
486
487% Key "j": Adds a kern to the right of "#"
488
489\newtableformatkey j%
490  {\setfalse\c_tabl_table_spacing_left
491   \settrue\c_tabl_table_spacing_right
492   \!tgGetValue{\!tgInsertKern}}
493
494% Key "n": numeric item , non-math mode.
495
496\newtableformatkey n%
497  {\def\!tnStyle{}%
498   \futurelet\!tnext\!tnTestForBracket}
499
500% Key "N": numeric item, math mode.
501
502\newtableformatkey N%
503  {\def\!tnStyle{$}%
504   \futurelet\!tnext\!tnTestForBracket}
505
506% Key "m": Math mode.
507
508\newtableformatkey m%
509  {\doreadtableformatkeys b{\normalstartimath} a{\normalstopimath}}
510
511% Key "M": Displaymath mode.
512
513\newtableformatkey M%
514  {\doreadtableformatkeys \{ b{\normalstartimath\displaystyle} a{\normalstopimath}}
515
516% Key "\m": Template ${}#\hfil$
517
518\newtableformatkey \m%
519  {\doreadtableformatkeys l b{{}} m}
520
521% Key "\M": Template $\displaystyle{{}#\hfil}$
522
523\newtableformatkey \M%
524  {\doreadtableformatkeys l b{{}} M}
525
526% Key "f":  Set font  (E.g., f\it sets up italic font (assuming \it
527% has its usual meaning)
528
529\newtableformatkey f#1%
530  {\doreadtableformatkeys b{#1}}
531
532\newtableformatkey B{\doreadtableformatkeys f\bf} % Key "B": abbreviation for f\bf
533\newtableformatkey I{\doreadtableformatkeys f\it} % Key "I": abbreviation for f\it
534\newtableformatkey S{\doreadtableformatkeys f\sl} % Key "S": abbreviation for f\sl
535\newtableformatkey R{\doreadtableformatkeys f\rm} % Key "R": abbreviation for f\rm
536\newtableformatkey T{\doreadtableformatkeys f\tt} % Key "T": abbreviation for f\tt
537
538% Key "p": ParBox
539
540\newtableformatkey p%
541  {\!tgGetValue{\!tgSetUpParBox}}
542
543% Key "w": minimum column width
544
545\newtableformatkey w%
546  {\!tkTestForBeginFormat w{\!tgGetValue{\!tfSetWidth}}}
547
548% Key "s": Set tabskip for the inter-column space to the right of the current
549% column, and all subsequent spaces, until overriden by a new "s" or "o" key.
550
551\newtableformatkey s%
552  {\!taOnceOnlyTabskipfalse    % in case same column has a prior "o" key
553   \!tkTestForBeginFormat t{\!tgGetValue{\!tfSetTabskip}}}
554
555% Key "o": Apply the \tabskip stated for this column ONLY to the inter-column space
556% just to the right of this column; restore the the previous \tabskip for
557% subsequent columns.
558
559\newtableformatkey o%
560  {\!taOnceOnlyTabskiptrue
561   \!tkTestForBeginFormat o{\!tgGetValue{\!tfSetTabskip}}}
562
563% Key "|": Standard rule column designator
564
565\newtableformatkey |%
566  {\!tkTestForBeginFormat |{\!tgGetValue{\!tfSetVrule}}}
567
568% Key "\|": Non-standard rule column designator
569
570\newtableformatkey \|%
571  {\!tkTestForBeginFormat \|{\!tfSetAlternateVrule}}
572
573% Key ".":  PERIOD -- end of \tabl_table_begin_format section.
574
575\newtableformatkey .%
576  {\!tkTestForBeginFormat.{\!tfFinishFormat}}
577
578% Key "\doendtableformat": Equivalent to "."
579
580\newtableformatkey \doendtableformat
581  {\!tkTestForBeginFormat\doendtableformat{\!tfFinishFormat}}
582
583% Key "]": End of \tabl_table_reformat section
584
585\newtableformatkey ]%
586  {\!tkTestForReFormat ] \!tfEndReFormat}
587
588% TEST FOR BEGIN FORMAT{<Key>}{Intended Action}: This test is run on keys that can
589% only be used by \tabl_table_begin_format --- "s", "o", "|", "\|", "w", ".", and
590% "\doendtableformat".
591
592\def\!tkTestForBeginFormat#1#2%
593  {\if!taBeginFormat
594     \def\tempstring{#2}%
595     \expandafter\tempstring
596   \else
597     \toks0={#1}%
598     \toks2=\expandafter{\string\tabl_table_reformat}%
599     \expandafter\!tkImproperUse
600   \fi}
601
602% TEST FOR RE FORMAT{<Key>}{Intended Action}: This test is run on the key "]",
603% which can only be used by \tabl_table_reformat.
604
605\def\!tkTestForReFormat#1#2%
606  {\if!taBeginFormat
607     \toks0={#1}%
608     \toks2=\expandafter{\string\tabl_table_begin_format}%
609     \expandafter\!tkImproperUse
610   \else
611     \def\tempstring{#2}%
612     \expandafter\tempstring
613   \fi}
614
615% NOTE: THE SPACE BETWEEN A NUMERIC ENTRY AND THE FOLLOWING '|', '"', OR '\|' IS
616% MANDATORY. EMPTY NUMERIC ENTRIES ARE NOT ALLOWED: USE '{}' OR '\omit' INSTEAD.
617
618\def\!tnTestForBracket
619  {\ifx[\!tnext
620     \expandafter\!tnGetArgument
621   \else
622     \expandafter\!tnGetCode
623   \fi}
624
625% GET CODE: E.g. "4", or "4.0", "0.4", or "10.2"
626
627\def\!tnGetCode#1 %
628  {\!tnConvertCode #1..!}
629
630% CONVERT CODE: E.g. converts above to [0000], [0000.], [.0000], [0000000000.00]
631
632\def\!tnConvertCode #1.#2.#3!%
633  {\begingroup
634   \aftergroup\edef \aftergroup\tempstring \aftergroup{%
635     \aftergroup[%
636     \scratchcounter#1\relax
637     \!thLoop
638       \ifnum \scratchcounter>\zerocount
639         \advance\scratchcounter\minusone
640         \aftergroup0
641     \repeat
642     \def\tempstring{#3}%
643     \ifx\tempstring \empty
644     \else
645       \aftergroup.
646       \scratchcounter#2\relax
647       \!thLoop
648         \ifnum \scratchcounter>\zerocount
649         \advance\scratchcounter\minusone
650         \aftergroup0
651       \repeat
652     \fi
653     \aftergroup]\aftergroup}%
654   \endgroup\relax
655   \expandafter\!tnGetArgument\tempstring}
656
657% GET ARGUMENT: [<sample left field> <optional .<sample right field>>
658
659\def\!tnGetArgument[#1]%
660  {\!tnMakeNumericTemplate\!tnStyle#1..!}
661
662% MAKE NUMERIC TEMPLATE
663
664\def\!tnMakeNumericTemplate#1#2.#3.#4!% #1=<empty> or $
665  {\def\tempstring{#4}%
666   \ifx\tempstring\empty
667     \!taDimenC\zeropoint
668   \else
669     \setbox\scratchbox\hbox{\mathsurround\zeropoint #1.#3#1}%
670     \!taDimenC\wd\scratchbox
671   \fi
672   \setbox\scratchbox\hbox{\mathsurround\zeropoint #1#2#1}%
673   \!thToksEdef\!taDataColumnTemplate
674     {\noexpand\!tnSetNumericItem{\the\wd\scratchbox}{\the\!taDimenC}{#1}%
675      \the\!taDataColumnTemplate}% Might have tabskip glue in here
676   \doreadtableformatkeys}
677
678% SET NUMERIC ITEM
679
680\def\!tnSetNumericItem #1#2#3#4 %
681  {\!tnSetNumericItemA {#1}{#2}{#3}#4..!}
682
683\def\!tnSetNumericItemA #1#2#3#4.#5.#6!%
684  {\def\tempstring{#6}%
685   \hbox to #1{\hss \mathsurround\zeropoint #3#4#3}%
686   \hbox to #2{\ifx\tempstring\empty\else\mathsurround\zeropoint #3.#5#3\fi\hss}}
687
688% extensions
689
690\newtableformatkey q%
691  {\let\!tqStyle\empty
692   \futurelet\!tnext\!tqTestForBracket}
693
694\newtableformatkey Q%
695  {\def\!tqStyle{$}%
696   \futurelet\!tnext\!tqTestForBracket}
697
698\def\!tqTestForBracket
699  {\ifx[\!tnext
700     \!thx\!tqGetArgument
701   \else
702     \!thx\!tqGetCode
703   \fi}
704
705\def\!tqGetCode#1 % note the blank
706  {\!tqConvertCode #1,,!}
707
708\def\!tqConvertCode #1,#2,#3!%
709  {\begingroup
710   \aftergroup\edef
711   \aftergroup\tempstring
712   \aftergroup{%
713   \aftergroup[%
714   \scratchcounter#1\relax
715   \!thLoop
716     \ifnum \scratchcounter>\zerocount
717       \advance\scratchcounter\minusone
718       \aftergroup0
719   \repeat
720   \def\tempstring{#3}%
721   \ifx\tempstring\empty
722   \else
723     \aftergroup,
724     \scratchcounter#2\relax
725     \!thLoop
726       \ifnum\scratchcounter>\zerocount
727         \advance\scratchcounter\minusone
728         \aftergroup0
729     \repeat
730   \fi
731   \aftergroup]\aftergroup}%
732   \endgroup\relax
733   \!thx\!tqGetArgument\tempstring}
734
735\def\!tqGetArgument[#1]%
736  {\!tqMakeQuantityTemplate\!tqStyle#1,,!}
737
738\def\!tqMakeQuantityTemplate#1#2,#3,#4!%  #1=<empty> or $
739  {\def\tempstring{#4}%
740   \ifx\tempstring\empty
741     \!taDimenC\zeropoint
742   \else
743     \setbox\scratchbox\hbox{\mathsurround\zeropoint #1,#3#1}%
744     \!taDimenC\wd\scratchbox
745   \fi
746   \setbox\scratchbox\hbox{\mathsurround\zeropoint #1#2#1}%
747   \!thToksEdef\!taDataColumnTemplate
748      {\noexpand\!tqSetQuantityItem{\the\wd\scratchbox}{\the\!taDimenC}{#1}%
749       \the\!taDataColumnTemplate}%
750  \doreadtableformatkeys}
751
752\def\!tqSetQuantityItem #1#2#3#4 %
753  {\!tqSetQuantityItemA{#1}{#2}{#3}#4,,!}
754
755\def\!tqSetQuantityItemA #1#2#3#4,#5,#6!%
756  {\def\tempstring{#6}%
757   \hbox to #1{\hss\mathsurround\zeropoint#3#4#3}%
758   \hbox to #2{\ifx\tempstring\empty\else\mathsurround\zeropoint#3,#5#3\fi\hss}}
759
760% \Enlarge<extra height><extra depth><original>
761% \enlarge<multiple for extra height><multiple for extra depth><original>
762
763\def\tabl_table_Enlarge#1#2%
764  {%  3rd argument is picked up later
765   % #1=extra height
766   % #2=extra depth
767   \!taDimenA=#1\relax
768   \!taDimenB=#2\relax
769   \let\!TsSpaceFactor\empty
770   \ifmmode
771     \expandafter\mathpalette
772     \expandafter\!TsEnlargeMath
773   \else
774     \expandafter\!TsEnlargeOther
775   \fi}
776
777\def\!TsEnlargeOther#1%
778  {\ifhmode
779     \setbox\scratchbox\hbox{#1\xdef\!TsSpaceFactor{\spacefactor\the\spacefactor}}%
780   \else
781     \setbox\scratchbox\hbox{#1}%
782   \fi
783   \!TsFinishEnlarge}
784
785\def\!TsEnlargeMath#1#2%
786  {\setbox\scratchbox\hbox{\normalstartimath\mathsurround\zeropoint#1{#2}\normalstopimath}%
787   \!TsFinishEnlarge}
788
789\def\!TsFinishEnlarge
790  {\ht\scratchbox\dimexpr\ht\scratchbox+\!taDimenA\relax
791   \dp\scratchbox\dimexpr\dp\scratchbox+\!taDimenB\relax
792   \box\scratchbox
793   \!TsSpaceFactor\relax}
794
795\def\tabl_table_enlarge#1#2%  3rd argument is picked up later
796  {\tabl_table_Enlarge{#1\d_tabl_table_strut_unit}{#2\d_tabl_table_strut_unit}}
797
798\appendtoks
799    \let\enlarge\tabl_table_enlarge
800    \let\Enlarge\tabl_table_Enlarge
801\to \everytable
802
803% BEGIN TABLE
804
805\let\tabl_table_standard_end\relax
806
807\def\tabl_table_standard_begin[#1]% \!ttBeginTable (always argument)
808  {\if#1u% unboxed table
809     \ifmmode
810       \let\tabl_table_standard_end\relax % user had better be in display math mode and have only one table at the outer level
811     \else                                % user had better be in vertical mode
812       \bgroup
813       \let\tabl_table_standard_end\egroup
814     \fi
815   \else
816     \hbox\bgroup
817     \def\tabl_table_standard_end{\egroup\egroup}%
818     \if#1t%
819       \vtop
820     \else\if#1b%
821       \vbox
822     \else
823       \def\tabl_table_standard_end{\egroup\normalstopimath\egroup}%
824       \scratchtoks\everymath
825       \everymath\emptytoks
826       \normalstartimath
827       \everymath\scratchtoks
828       \vcenter
829     \fi\fi
830     \bgroup % for the \vtop, \vbox, or \vcenter
831   \fi
832   \advance\!taRecursionLevel\plusone
833   \let\!ttRightGlue\relax
834   \everycr\emptytoks
835   \ifnum\!taRecursionLevel=\plusone
836     \the\everytable
837   \fi}
838
839\bgroup \catcode\tildeasciicode\activecatcode
840
841    \appendtoks
842        \catcode\barasciicode\activecatcode
843        \def~{\kern.5em}%
844        \def\\{\ifhmode\space\else\par\fi}%
845    \to \everytable
846
847\egroup
848
849\let\!ttRightGlue\relax  % This may be changed, in a group, by \JustCenter, etc
850
851% DO HALIGN: Invoked by END FORMAT (or the key ".")
852
853\let\tabl_table_restore_lineskips\relax
854
855\def\!ttDoHalign
856  {\edef\tabl_table_restore_lineskips
857     {\baselineskip \the\baselineskip
858      \lineskiplimit\the\lineskiplimit
859      \lineskip     \the\lineskip
860      \tabskip      \the\tabskip
861      \relax}%
862   \baselineskip \zeropoint
863   \lineskiplimit\zeropoint
864   \lineskip     \zeropoint
865   \tabskip      \zeropoint
866   \edef\p_tabl_table_textwidth{\directtablesparameter\c!textwidth}%
867   % we are not in sync so:
868   \synchronizedisplaydirection
869   \synchronizeinlinedirection
870   \halign
871     \usedirectionparameterreverse\directtablesparameter
872     \ifx\p_tabl_table_textwidth\empty \else to \ifx\p_tabl_table_textwidth\v!max \hsize \else \p_tabl_table_textwidth \fi\fi
873    %\the\!taTableSpread
874     \bgroup
875     \span
876     \the\!taPreamble
877     \ifx\!tfRowOfWidths\empty\else
878       \!tfRowOfWidths\cr
879     \fi}
880
881% END TABLE
882
883\def\tabl_table_normal_end
884  {\egroup                   % finishes the \halign
885   \tabl_table_standard_end} % closes off the table envirnoment set up by \tablestandardbegin
886
887\def\tabl_table_normal_line_ending
888  {\cr}
889
890\def\tabl_table_normal_line_format#1#2%
891  {\vrule
892     \s!width \zeropoint
893     \s!height\dimexpr\tablestrutheightfactor\d_tabl_table_strut_unit+#1\d_tabl_table_strut_unit\relax
894     \s!depth \dimexpr\tablestrutdepthfactor \d_tabl_table_strut_unit+#2\d_tabl_table_strut_unit\relax
895   \relax
896   \cr}
897
898% INSERT VRULE
899
900\newcount\c_tabl_table_n_of_vrules \c_tabl_table_n_of_vrules\plusone
901
902\let\m_tabl_table_vrule_color\empty
903\let\m_tabl_table_hrule_color\empty
904
905\def\do!ttInsertVrule
906  {\vrule\s!width
907     \ifnum\!tgCode=\plusone
908       \ifx\!tgValue\empty
909         \c_tabl_table_vrule_thickness_factor
910       \else
911         \!tgValue
912       \fi
913       \d_tabl_table_line_thickness_unit
914     \else
915       \!tgValue
916     \fi
917   \hskip.125\emwidth\relax}
918
919\def\tabl_table_normal_line_simple_bar
920  {\unskip\!ttRightGlue\aligntab\aligntab}
921
922\def\tabl_table_normal_line_complex_bar
923  {\unskip\!ttRightGlue\aligntab\omit
924   \hfil
925   \ifx\m_tabl_table_vrule_color\empty\else
926     \switchtocolor[\m_tabl_table_vrule_color]%
927   \fi
928   \ifcase\c_tabl_table_n_of_vrules\or
929     \do!ttInsertVrule
930     \unskip
931   \else
932     \dorecurse\c_tabl_table_n_of_vrules\do!ttInsertVrule
933     \global\c_tabl_table_n_of_vrules\plusone
934     \unskip
935   \fi
936   \glet\m_tabl_table_vrule_color\empty
937   \hfil
938   \aligntab}
939
940\def\tabl_table_normal_no_bar
941  {\unskip\!ttRightGlue\aligntab\omit\aligntab}
942
943\def\tabl_table_normal_single_rule
944  {\aligntab\tabl_table_normal_long_rule\aligntab}
945
946\def\tabl_table_normal_multi_rule
947  {\aligntab\tabl_table_use\c_tabl_table_drule_span\tabl_table_normal_long_rule\aligntab}
948
949% USE
950
951\def\tabl_table_use#1%
952  {\ifnum#1>\plusone
953     \omit
954     \global\setfalse\c_tabl_table_is_division       % added
955     \scratchcounter\currenttablecolumn              % added
956     \advance\scratchcounter #1%                     % added
957     \advance\scratchcounter \minusone               % added
958     \def\next                                       % added
959       {\global\advance\currenttablecolumn #1%       % added
960        \global\advance\currenttablecolumn \minusone % added
961        \scratchcounter#1%
962        \advance\scratchcounter \minusone
963        \advance\scratchcounter \scratchcounter
964        \!thLoop
965          \ifnum\scratchcounter>\plusone
966            \spanomit \advance\scratchcounter\minusone
967        \repeat
968        \span}%
969   \else                                             % added
970     \def\next % conflicts with possible next \omit  % added
971       {\global\advance\currenttablecolumn \plusone}%% added
972   \fi
973   \next}                                            % added
974
975\def\tabl_table_Use#1[%
976  {\tabl_table_use{#1}%
977   \tabl_table_reformat[}
978
979\appendtoks
980    \let\use\tabl_table_use
981    \let\Use\tabl_table_Use
982\to \everytable
983
984% rules
985
986\def\tabl_table_normal_full_rule
987  {\starttablenoalign
988   \!ttGetHalfRuleThickness
989   \scratchdistance\directtablesparameter\c!openup
990   \ifzeropt\scratchdistance\else\kern\scratchdistance\fi
991   \hrule\s!height\scratchdimen\s!depth\scratchdimen
992   \ifzeropt\scratchdistance\else\kern\scratchdistance\fi
993   \stoptablenoalign}
994
995\def\tabl_table_normal_short_rule % was: \!ttShortHrule
996  {\omit
997   \!ttGetHalfRuleThickness
998   \ifx\m_tabl_table_hrule_color\empty\else
999     \switchtocolor[\m_tabl_table_hrule_color]% see *DL*
1000   \fi
1001   \leaders\hrule\s!height\scratchdimen\s!depth\scratchdimen\hfill
1002   \emptyhbox
1003   \ignorespaces}
1004
1005\def\tabl_table_normal_long_rule % was: \!ttLongHrule
1006  {\omit\span
1007   \omit\span
1008   \tabl_table_normal_short_rule}
1009
1010\def\!ttGetHalfRuleThickness
1011  {\scratchdimen\dimexpr
1012     \ifnum\!tgCode=\plusone
1013       \ifx\!tgValue\empty
1014         \c_tabl_table_hrule_thickness_factor
1015       \else
1016         \!tgValue    % user-specified integer
1017       \fi
1018       \d_tabl_table_line_thickness_unit
1019     \else
1020       \!tgValue      % user-specified dimension
1021     \fi
1022  \divide\scratchdimen\plustwo}
1023
1024% \emptyhbox prevents \unskip
1025
1026\def\tabl_table_Left  #1{#1\hfill\emptyhbox}
1027\def\tabl_table_Center#1{\hfill#1\hfill\emptyhbox}
1028\def\tabl_table_Right #1{\hfill#1}
1029
1030\def\tabl_table_OpenUp#1#2%
1031  {\edef\tablestrutheightfactor{\withoutpt\the\dimexpr\tablestrutheightfactor\points+#1\points}%
1032   \edef\tablestrutdepthfactor {\withoutpt\the\dimexpr\tablestrutdepthfactor \points+#2\points}}
1033
1034% SetTableToWidth -> textwidth=dimension [to dimension]
1035% Expand          -> textwidth=max       [to \hsize]
1036% WidenTableBy    ->                     [spread #1]
1037%                                        \tablelefttabskip\zeropoint\s!plus1\s!fill
1038%                                        \tablerighttabskip\tablelefttabskip
1039% LongLines       ->                     [spread \hsize]
1040
1041\def\tabl_table_JustLeft  {\omit\let\!ttRightGlue\hfill}
1042\def\tabl_table_JustCenter{\omit\hfill\emptyhbox\let\!ttRightGlue\hfill}
1043\def\tabl_table_JustRight {\omit\hfill\emptyhbox}
1044
1045\def\tabl_table_Smash
1046  {\relax
1047   \ifmmode
1048     \expandafter\mathpalette
1049     \expandafter\!thDoMathVCS
1050   \else
1051     \expandafter\!thDoVCS
1052   \fi}
1053
1054\def\!thDoVCS#1%
1055  {\setbox\zerocount\hbox{#1}%
1056   \!thFinishVCS}
1057
1058\def\!thDoMathVCS#1#2%
1059  {\setbox\zerocount\hbox{\normalstartimath\mathsurround\zeropoint#1{#2}\normalstopimath}%
1060   \!thFinishVCS}
1061
1062\def\!thFinishVCS
1063  {\vpack to\zeropoint{\vss\box\zerocount\vss}}
1064
1065\def\tabl_table_Raise
1066  {\def\!thSign{+}%
1067   \!tgGetValue\!thSetDimen}
1068
1069\def\tabl_table_Lower
1070  {\def\!thSign{-}%
1071   \!tgGetValue\!thSetDimen}
1072
1073\def\!thSetDimen
1074  {\ifnum\!tgCode=\plusone
1075     \ifx\!tgValue\empty
1076       \!taDimenA\tablestrutheightfactor\d_tabl_table_strut_unit
1077       \advance\!taDimenA\tablestrutdepthfactor\d_tabl_table_strut_unit
1078       \divide\!taDimenA\plustwo
1079     \else
1080       \!taDimenA\!tgValue\d_tabl_table_strut_unit
1081     \fi
1082   \else
1083     \!taDimenA\!tgValue
1084   \fi
1085   \!taDimenA\!thSign\!taDimenA\relax
1086   \ifmmode
1087     \expandafter\mathpalette
1088     \expandafter\!thDoMathRaise
1089   \else
1090     \expandafter\!thDoSimpleRaise
1091   \fi}
1092
1093\def\!thDoSimpleRaise#1%
1094  {\setbox\zerocount\hbox{\raise \!taDimenA\hbox{#1}}%
1095   \!thFinishRaise} % From Plain TeX: \ht0=0pt \dp0=0pt \box0
1096
1097\def\!thDoMathRaise#1#2%
1098  {\setbox\zerocount\hbox{\raise \!taDimenA\hbox{\normalstartimath\mathsurround\zeropoint#1{#2}\normalstopimath}}%
1099   \!thFinishRaise}
1100
1101\def\!thFinishRaise
1102  {\ht\zerocount\zeropoint
1103   \dp\zerocount\zeropoint
1104   \box\zerocount}
1105
1106\def\tabl_table_BackSpace
1107  {\!tgGetValue\!thKernBack}
1108
1109\def\!thKernBack
1110  {\kern -
1111   \ifnum\!tgCode=\plusone
1112     \ifx\!tgValue\empty
1113       \tablekernfactor
1114     \else
1115       \!tgValue    % user-specified integer
1116     \fi
1117     \d_tabl_table_kern_unit
1118   \else
1119     \!tgValue      % user-specified dimension
1120   \fi
1121   \ignorespaces}
1122
1123\def\tabl_table_Vspace
1124  {\noalign
1125   \bgroup
1126   \!tgGetValue\!thVspace}
1127
1128\def\!thVspace
1129  {\vskip
1130     \ifnum\!tgCode=\plusone
1131       \ifx\!tgValue\empty
1132         \tablevspacefactor
1133       \else
1134         \!tgValue    % user-specified integer
1135       \fi
1136       \d_tabl_table_strut_unit
1137     \else
1138       \!tgValue      % user-specified skip
1139     \fi
1140   \egroup} % Ends the \noalign
1141
1142\appendtoks
1143    \let\JustLeft       \tabl_table_JustLeft
1144    \let\JustCenter     \tabl_table_JustCenter
1145    \let\JustRight      \tabl_table_JustRight
1146    \let\Smash          \tabl_table_Smash
1147    \let\Raise          \tabl_table_Raise
1148    \let\Lower          \tabl_table_Lower
1149    \let\BackSpace      \tabl_table_BackSpace
1150    \let\Vspace         \tabl_table_Vspace
1151    \let\OpenUp         \tabl_table_OpenUp
1152    \let\TableLeft      \tabl_table_Left
1153    \let\TableCenter    \tabl_table_Center
1154    \let\TableRight     \tabl_table_Right
1155\to \everytable
1156
1157%D \macros
1158%D   {inintable, ifsplittables}
1159%D
1160%D First we declare some variables. These show a bit what we are dealing with. First
1161%D we introdoce some booleans that enable us, inside as well as outside this module,
1162%D to determine in what mode we are.
1163
1164\newif\ifintable
1165\newif\ifsplittables
1166
1167%D We show this feature in an example that also shows some of the basic table
1168%D typesetting commands.
1169%D
1170%D \startbuffer
1171%D \starttable[|||]
1172%D \HL
1173%D \VL first \VL second \VL\AR
1174%D \HL
1175%D \VL alfa  \VL 1      \VL\AR
1176%D \VL beta  \VL 2      \VL\AR
1177%D \VL gamma \VL 3      \VL\AR
1178%D \HL
1179%D \stoptable
1180%D \stopbuffer
1181%D
1182%D \startlinecorrection
1183%D \getbuffer
1184%D \stoplinecorrection
1185%D
1186%D This table is specified as:
1187%D
1188%D \typebuffer
1189%D
1190%D This examples shows about the minimum of commands needed to typeset such a table.
1191%D In this table, the \type {\AR} is automatically translated into the more
1192%D primitive (but more verbose) commands \type {\SR}, \type {\FR}, \type {\MR} and
1193%D \type {\LR} commands.
1194%D
1195%D \startbuffer
1196%D \starttables[|||]
1197%D \HL
1198%D \VL first \VL second \VL\AR
1199%D \HL
1200%D \VL alfa  \VL 1      \VL\AR
1201%D \VL beta  \VL 2      \VL\AR
1202%D \VL gamma \VL 3      \VL\AR
1203%D \HL
1204%D \stoptables
1205%D \stopbuffer
1206%D
1207%D \getbuffer
1208%D
1209%D Some simple color support is provided:
1210%D
1211%D \startbuffer
1212%D \starttable[|c|c|]
1213%D \HL
1214%D \VL test      \VL test         \VL     \SR
1215%D \HL[green,5]
1216%D \VL[red] test \VL test         \VL     \FR
1217%D \VL test      \VL[10,red] test \VL     \MR
1218%D \VL test      \VL test         \VL[10] \LR
1219%D \HL
1220%D \stoptable
1221%D \stopbuffer
1222%D
1223%D \typebuffer \getbuffer
1224
1225\installcorenamespace{tabletemplate}
1226
1227\def\m!TABLE{TABLE}
1228
1229%D We already saw that the table macros report errors and provide automatic spacing.
1230%D These features can only be implemented by keeping track of the state, often the
1231%D last command on a row.
1232
1233\newconstant\tableforcestate
1234\newconstant\tableactionstate
1235
1236\setnewconstant\tableunknownstate       0
1237
1238\setnewconstant\tableseparaterowstate   1
1239\setnewconstant\tablefirstrowstate      2
1240\setnewconstant\tablemidrowstate        3
1241\setnewconstant\tablelastrowstate       4
1242\setnewconstant\tablerulestate          5
1243%setnewconstant\tableskipstate          6
1244%setnewconstant\tableautorowstate       7
1245
1246\setnewconstant\tableforcefirstrowstate 1
1247\setnewconstant\tableforcelastrowstate  2
1248
1249\newconstant\tablerowfactor
1250\newconstant\TABLEendofrowdepth
1251\newconstant\TABLEendofrowheight
1252\newconstant\TABLEcr
1253\newconstant\tablerowzero
1254\newconstant\TABLEn
1255
1256%D We store these states using \type {constants}'s and like most variables, these
1257%D are global ones. When needed, especially when we flush the backgrounds, we can
1258%D temporary disable the assignment.
1259
1260\newconditional\tableactionstatepermitted
1261
1262\def\tabl_table_set_action#1{\ifconditional\tableactionstatepermitted\global\tableactionstate#1\fi}
1263\def\tabl_table_set_force #1{\ifconditional\tableactionstatepermitted\global\tableforcestate #1\fi}
1264
1265%D To give an impression of what the (well documented) source of \TABLE\ looks like,
1266%D we first implement an alternative for the numeric keys. The quantity keys
1267%D (\type{q} and \type{Q}) support the more european way of writing numbers:
1268%D
1269%D \startnarrower
1270%D 100.000.000,00 instead of 100,000,000.00
1271%D \stopnarrower
1272%D
1273%D The next table shows how to use these keys. We use braces instead of brackets because
1274%D we need brackets to specify the format.
1275%D
1276%D \starttyping
1277%D \starttable{|q[00,000]|Q[00,00]|}
1278%D \HL
1279%D \VL -1,2   \VL 12,35 \VL\FR
1280%D \VL 11,203 \VL  2,4  \VL\LR
1281%D \HL
1282%D \stoptable
1283%D \stoptyping
1284%D
1285%D Although a more efficient implementation is possible |<|we can for instance share
1286%D common macros|>| we just adapt a copy of the numeric ones. To permit double
1287%D loading of this module, we check for the existence of one of the macros.
1288%D
1289%D To be compatible with the tabulate environment, we also support the \type {l},
1290%D \type {c} and \type {r} keys for paragraph entries.
1291%D
1292%D All commands that are executed between rows are to be put in \type {\noalign}. We
1293%D can however not verify if we (that is \TABLE) does or did not enter this mode. A
1294%D moderate dirty but useful trick is using our own alternative:\footnote{Once one
1295%D has entered the stage of redefining \TEX\ primitives, such hacks become a second
1296%D nature. However, redefining \type {\omit} and \type{\span} is not that easy.}
1297
1298\def\tablenoalign
1299  {\noalign
1300   \bgroup
1301   \let\noalign\relax
1302   \let\tablenoalign\relax
1303   \let\next=}
1304
1305\def\starttablenoalign
1306  {\tablenoalign\bgroup}
1307
1308\let\stoptablenoalign\egroup
1309
1310%D \macros
1311%D   {starttable}
1312%D
1313%D The rest of this module is not easy to comprehend, mainly because we have to take
1314%D care of:
1315%D
1316%D \startitemize[packed]
1317%D \item  \type{\startitemize[template]}
1318%D \item  \type{\startitemize{template}}
1319%D \item  \type{\startitemize[predefined]}
1320%D \stopitemize
1321%D
1322%D as well as:
1323%D
1324%D \startitemize[continue]
1325%D \item  restart after table break
1326%D \stopitemize
1327%D
1328%D The official specification of the start command is:
1329%D
1330%D \showsetup{starttable}
1331
1332\newconditional\c_tabl_table_repeat_head
1333\newconditional\c_tabl_table_repeat_tail
1334
1335\unexpanded\def\starttable
1336  {\bgroup
1337   \dodoubleempty\table_table_start}
1338
1339\unexpanded\def\table_table_start[#1][#2]% preamble optional-settings
1340  {\ifsecondargument
1341     \setupcurrenttables[#2]%
1342   \fi
1343   \let\stoptable\table_table_stop
1344   \edef\p_tabl_table_split{\directtablesparameter\c!split}%
1345   \edef\p_tabl_table_frame{\directtablesparameter\c!frame}%
1346   \ifx\p_tabl_table_split\v!auto
1347     \ifinsidesplitfloat
1348       \let\p_tabl_table_split\v!yes
1349       \lettablesparameter\c!split\v!yes % might be used later, best make a proper mode
1350     \fi
1351   \fi
1352   \ifx\p_tabl_table_split\v!yes
1353     \def\stoptable{\table_table_stop_s\egroup}%  not \unexpanded as we look ahead
1354     \expandafter\starttables
1355   \else\ifx\p_tabl_table_split\v!repeat
1356     \def\stoptable{\table_table_stop_s\egroup}%  not \unexpanded as we look ahead
1357     \doubleexpandafter\starttables
1358   \else
1359     \ifx\p_tabl_table_frame\empty
1360       \ifinsidefloat\else\startbaselinecorrection\fi
1361     \else
1362       \startframedcontent[\p_tabl_table_frame]%
1363     \fi
1364     \postponenotes
1365     \doubleexpandafter\tabl_table_first_stage
1366   \fi\fi
1367   [#1]}
1368
1369% We cannot define the stopper as \type {\unexpanded} because lookahead in
1370% alignments fail then, so we relax it and define it locally.
1371
1372\let\stoptable\relax
1373
1374\def\table_table_stop
1375  {\tabl_tables_chuck_auto_row % before the tail, else noalign problem
1376   \tabl_table_insert_tail
1377   \starttablenoalign
1378     \glet\tabl_table_head\empty
1379     \glet\tabl_table_tail\empty
1380   \stoptablenoalign
1381   \tabl_table_finish
1382   \ifx\p_tabl_table_frame\empty
1383     \ifinsidefloat\else
1384        \stopbaselinecorrection
1385        \goodbreak % compensates all the nobreaks
1386     \fi
1387   \else
1388     \stopframedcontent
1389   \fi
1390   \egroup}
1391
1392%D Before we can grab the argument, we have to make sure that the \CATCODES\ are
1393%D set. The first stage takes care of that.
1394
1395\def\tabl_table_first_stage
1396  {\bgroup
1397   \global\intabletrue
1398   \tabl_table_second_stage}
1399
1400%D \macros
1401%D   {definetabletemplate}
1402%D
1403%D The complex (and main) start macro first takes care of the predefined case. Such
1404%D a predefined setup looks like:
1405%D
1406%D \starttyping
1407%D \definetabletemplate[test][|||]
1408%D
1409%D \starttable[test]
1410%D \VL test \VL test \VL\AR
1411%D \VL test \VL test \VL\AR
1412%D \VL test \VL test \VL\AR
1413%D \stoptable
1414%D \stoptyping
1415%D
1416%D The implementation of the definition macro is not that complicated:
1417
1418\installcorenamespace{tablehead}
1419\installcorenamespace{tabletail}
1420
1421\unexpanded\def\definetabletemplate % to be redone
1422  {\bgroup
1423   \catcode\barasciicode\othercatcode
1424   \doquadrupleempty\tabl_table_define_template}
1425
1426\def\tabl_table_define_template[#1][#2][#3][#4]%
1427  {\ifsecondargument
1428     \setgvalue{\??tabletemplate#1}{\tabl_table_use_template{#2}{#3}{#4}}%
1429   \fi
1430   \egroup}
1431
1432\def\tabl_table_use_template#1#2#3%
1433  {\gdef\tabl_table_head{\begincsname\??tablehead#2\endcsname}%
1434   \gdef\tabl_table_tail{\begincsname\??tabletail#3\endcsname}%
1435   \tabl_table_second_stage[#1]}
1436
1437%D The optional third and fourth arguments define which table head and tail to use.
1438%D
1439%D \starttyping
1440%D \definetabletemplate[test][|||][before][after]
1441%D \stoptyping
1442%D
1443%D This also means that one can define table heads and tails by name!
1444%D
1445%D \starttyping
1446%D \starttablehead[before]
1447%D \HL \VL first \VL second \VL \SR \HL
1448%D \stoptablehead
1449%D \stoptyping
1450%D
1451%D Templates defined this way get protected names, that cannot conflict with
1452%D existing commands.
1453%D
1454%D \showsetup{definetabletemplate}
1455%D
1456%D The second half of the next macro prepares table
1457%D splitting.
1458
1459\def\tabl_table_insert_head
1460  {\starttablenoalign
1461     \global\settrue\preventtablebreak
1462     \global\setfalse\hassometablehead
1463   \stoptablenoalign
1464   \tabl_table_head
1465   \starttablenoalign
1466     \global\setfalse\preventtablebreak
1467   \stoptablenoalign}
1468
1469\def\tabl_table_insert_tail
1470  {\starttablenoalign
1471     \global\settrue\preventtablebreak
1472     \global\setfalse\hassometabletail
1473   \stoptablenoalign
1474   \tabl_table_tail
1475   \starttablenoalign
1476     \global\setfalse\preventtablebreak
1477   \stoptablenoalign}
1478
1479% \def\doverysimpletableHL % todo
1480%   {\starttablenoalign
1481%      \normalexpanded{\noexpand\tabl_table_normal_full_rule\m_tabl_table_HLheight}%
1482%    \stoptablenoalign}
1483
1484\def\tabl_table_restart_indeed#1%
1485  {\gdef\tabl_table_restart{#1}%
1486   \tabl_table_restart
1487%    \starttablenoalign
1488%      \globalpushmacro\simpletableHL
1489%      \glet\simpletableHL\doverysimpletableHL
1490%    \stoptablenoalign
1491   \tabl_table_insert_head
1492   \ifsplittables \ifconditional \c_tabl_table_repeat_tail
1493     \tablenoalign{\goodbreak}%
1494     \tabl_table_insert_tail
1495     \tablenoalign{\goodbreak}%
1496   \fi \fi
1497%    \starttablenoalign
1498%      \globalpopmacro\simpletableHL
1499%    \stoptablenoalign
1500   }
1501
1502\bgroup \catcode\barasciicode\othercatcode
1503
1504\gdef\tabl_table_second_stage[#1]% brr nested mess
1505  {\bgroup
1506   \tabl_table_use_bar
1507   \global\setfalse\tableactionstatepermitted
1508   \global\setfalse\hassometablehead
1509   \global\setfalse\hassometabletail
1510   \expanded{\doifelseinstring{|}{#1}}
1511     {\xdef\tabl_table_restart{\noexpand\tabl_table_restart_indeed{\noexpand\tabl_table_third_stage{#1}}}}
1512     {\doifelsedefined{\??tabletemplate#1}
1513        {\gdef\tabl_table_restart{\getvalue{\??tabletemplate#1}}}
1514        {\gdef\tabl_table_restart{\tabl_table_restart_indeed{\getvalue{#1}}}}}%
1515   \egroup
1516   \tabl_table_restart}
1517
1518\egroup
1519
1520%D The third stage involves a lot of (re)sets, which we will explain later.
1521
1522\appendtoks
1523    \fixedspaces
1524    \let\_\normalunderscore
1525\to \everytable
1526
1527%D Now we can start the table.
1528
1529\newtoks\localtabledefinitions
1530
1531\def\tabl_table_third_stage#1%
1532  {\global\settrue\tableactionstatepermitted
1533   \tabl_table_set_action\tableunknownstate
1534   \tabl_table_set_force\tableunknownstate
1535   \tabl_table_resetVLvalues
1536   \appendtoks\tabl_table_local_setups\to\everytable
1537   \tabl_table_standard_begin[\ifsplittables u\else b\fi]%
1538   \the\localtabledefinitions
1539   \forgetall % added
1540   \edef\currenttableformat{#1}%
1541   \doifsomething\currenttableformat
1542     {\dogettablenofcolumns\currenttableformat
1543      % more modern is to use catcode tables
1544      \expandafter\tabl_table_begin_format\currenttableformat\doendtableformat}}
1545
1546\def\tabl_table_finish
1547  {\tabl_tables_chuck_auto_row
1548   \unskip\crcr
1549   \tabl_table_normal_end
1550   \global\intablefalse
1551   \egroup}
1552
1553%D \macros
1554%D   {starttables}
1555%D
1556%D Split tables are specified using the plural form of the start and stop commands.
1557%D
1558%D \showsetup{starttables}
1559%D
1560%D For example:
1561%D
1562%D \starttyping
1563%D \starttables[|||]
1564%D \HL
1565%D \VL element \VL atom weight \VL\AR
1566%D \HL
1567%D \VL ....... \VL ........... \VL\AR
1568%D \VL ....... \VL ........... \VL\AR
1569%D \HL
1570%D \stoptables
1571%D \stoptyping
1572
1573\newbox\tablecontentbox
1574
1575\unexpanded\def\starttables
1576  {\bgroup
1577   \let\stoptables\table_table_stop_s
1578   \splittablestrue
1579   \edef\p_tabl_table_split{\directtablesparameter\c!split}%
1580   \ifx\p_tabl_table_split\v!repeat
1581     \settrue\c_tabl_table_repeat_head
1582     \settrue\c_tabl_table_repeat_tail
1583   \else
1584     \setfalse\c_tabl_table_repeat_head
1585     \setfalse\c_tabl_table_repeat_tail
1586   \fi
1587   \flushnotes
1588   \setbox\tablecontentbox\vbox\bgroup
1589   \forgetall
1590   \tabl_table_first_stage}
1591
1592\let\stoptables\relax % needed for \noalign
1593
1594\def\table_table_stop_s % not \unexpanded as we need the lookahead (brrr)
1595  {\tabl_tables_chuck_auto_row % AM: before the tail, else noalign problem
1596   \ifconditional\c_tabl_table_repeat_tail\else\tabl_table_insert_tail\fi
1597   \tabl_table_finish
1598   \egroup
1599   \dontcomplain
1600   \tabl_table_split_box\tablecontentbox
1601   \glet\tabl_table_head\empty % new here
1602   \glet\tabl_table_tail\empty % new here
1603   \flushnotes
1604   \egroup}
1605
1606\def\tabl_table_split_box#1%
1607  {\resettsplit
1608   \def\tsplitminimumfreelines{2}%
1609   \def\tsplitminimumfreespace{\zeropoint}%
1610   \setbox\tsplitcontent\box#1%
1611   \ifconditional\c_tabl_table_repeat_head \ifconditional\hassometablehead
1612     \setbox\tsplithead\vsplit\tsplitcontent to \lineheight
1613     \setbox\tsplithead\vbox{\unvbox\tsplithead}% \vpack ?
1614   \fi \fi
1615   \ifconditional\c_tabl_table_repeat_tail \ifconditional\hassometabletail
1616     \setbox\tsplittail\vsplit\tsplitcontent to \lineheight
1617     \setbox\tsplittail\vbox{\unvbox\tsplittail}% \vpack ?
1618   \fi \fi
1619   \ifinsidefloat\else
1620     \def\tsplitbeforeresult{\startbaselinecorrection}%
1621     \def\tsplitafterresult {\stopbaselinecorrection}%
1622   \fi
1623   \handletsplit}
1624
1625%D When the table in the previous example is split across pages, only the first gets
1626%D a head. We could have said something like:
1627%D
1628%D \starttyping
1629%D \starttablehead
1630%D \HL
1631%D \VL element \VL atom weight \VL\AR
1632%D \HL
1633%D \stoptablehead
1634%D
1635%D \starttabletail
1636%D \HL
1637%D \stoptabletail
1638%D
1639%D \starttables[|||]
1640%D \VL ....... \VL ........... \VL\AR
1641%D \VL ....... \VL ........... \VL\AR
1642%D \stoptables
1643%D \stoptyping
1644%D
1645%D This time each split table gets a head line and ends with a rule. Keep in mind
1646%D that such heads also apply to the unbroken ones and should be defined local
1647%D (grouped) if needed. The rather complicated definition below is due to the fact
1648%D that the stopcondition is interface language dependant.
1649
1650\let\tabl_table_head\empty % needs checking
1651\let\tabl_table_tail\empty % needs checking
1652
1653\letvalue{\e!start\v!tablehead}\relax
1654\letvalue{\e!stop \v!tablehead}\relax
1655\letvalue{\e!start\v!tabletail}\relax
1656\letvalue{\e!stop \v!tabletail}\relax
1657
1658%D The second argument is a dummy one, by scanning for it, we get rid of
1659%D interfering spaces.
1660
1661\newconditional\preventtablebreak
1662\newconditional\hassometablehead
1663\newconditional\hassometabletail
1664
1665\unexpanded\def\settablehead{\dodoubleempty\tabl_table_set_head}
1666\unexpanded\def\settabletail{\dodoubleempty\tabl_table_set_tail}
1667
1668% \def\tabl_table_set_head[#1][#2]#3\end{\setvalue{\??tablehead#1}{\tablenoalign{\global\settrue\hassometablehead}#3}}
1669% \def\tabl_table_set_tail[#1][#2]#3\end{\setvalue{\??tabletail#1}{\tablenoalign{\global\settrue\hassometabletail}#3}}
1670
1671\def\tabl_table_set_head[#1][#2]#3\end
1672  {\gdef\tabl_table_head{\begincsname\??tablehead#1\endcsname}% new
1673   \setvalue{\??tablehead#1}{\tablenoalign{\global\settrue\hassometablehead}#3}}
1674
1675\def\tabl_table_set_tail[#1][#2]#3\end
1676  {\gdef\tabl_table_tail{\begincsname\??tabletail#1\endcsname}% new
1677   \setvalue{\??tabletail#1}{\tablenoalign{\global\settrue\hassometabletail}#3}}
1678
1679\normalexpanded
1680  {\def\csname\e!start\v!tablehead\endcsname#1\csname\e!stop\v!tablehead\endcsname%
1681     {\settablehead#1\noexpand\end}}
1682
1683\normalexpanded
1684  {\def\csname\e!start\v!tabletail\endcsname#1\csname\e!stop\v!tabletail\endcsname%
1685     {\settabletail#1\noexpand\end}}
1686
1687%D Redundant \type{\HL}'s are removed automatically, so mid||lines can be used
1688%D without problems.
1689%D
1690%D The order of the next macros is more or less random. First we implement error
1691%D recovery. Errors are reported to the screen and log file as well as visualized in
1692%D the table in teletype.
1693
1694\def\tabl_table_finish_row
1695  {\crcr
1696   \starttablenoalign
1697     \nobreak
1698     \tabl_table_set_action\tableunknownstate
1699     \glet\tabl_tables_check_auto_row\empty
1700     \glet\tabl_tables_chuck_auto_row\empty
1701     \global\currenttablecolumn\zerocount
1702   \stoptablenoalign}
1703
1704%D Next we enter the more complicated area of column and row switching. I won't go
1705%D into much detail from now on, but just mention the general principles.
1706%D
1707%D \startitemize[3*ruim]
1708%D \sym{\type{\SR}} end a separate row (between rules)
1709%D \sym{\type{\FR}} end a first row (after a rule)
1710%D \sym{\type{\MR}} end a mid row (between text lines)
1711%D \sym{\type{\LR}} end a last row (before a rule)
1712%D \stopitemize
1713%D
1714%D and best of all:
1715%D
1716%D \startitemize[continue]
1717%D \sym{\type{\AR}} end a row with automatic spacing
1718%D \stopitemize
1719%D
1720%D As far as possible, we report confusing situations. In most cases one can use
1721%D \type{\AR}, which transfigurates itself into one of the other types.
1722%D
1723%D \starttyping
1724%D \starttable[||]
1725%D \HL
1726%D \VL a separate row \VL\SR
1727%D \HL
1728%D \VL a first row    \VL\FR
1729%D \VL a mid row      \VL\MR
1730%D \VL a last row     \VL\LR
1731%D \HL
1732%D \stoptable
1733%D \stoptyping
1734%D
1735%D In this example we could have used \type{\AR} without problems.
1736%D
1737%D Color or gray scale backgrounds precede the content. They are passed over
1738%D horizontal (division) lines when needed. Errors in the color template are traced
1739%D elsewhere. Here we only check for inconsistent spacing. Due to the way \TEX\
1740%D handles alignments, we cannot automate spacing for colored rows and columns.
1741
1742\tablerowzero\zerocount
1743
1744\appendtoks
1745  \let\SR\tabl_table_SR
1746  \let\FR\tabl_table_FR
1747  \let\MR\tabl_table_MR
1748  \let\LR\tabl_table_LR
1749  \let\AR\tabl_table_AR
1750\to \localtabledefinitions
1751
1752\unexpanded\def\tabl_table_SR
1753  {\ifnum\tableactionstate=\tablefirstrowstate
1754     \writestatus\m!TABLE{change \string\SR\space into \string\MR/\string\LR}%
1755   \else\ifnum\tableactionstate=\tablemidrowstate
1756     \writestatus\m!TABLE{change \string\SR\space into \string\MR/\string\LR}%
1757   \else\ifnum\tableactionstate=\tablemidrowstate
1758     \writestatus\m!TABLE{change \string\SR\space into \string\MR/\string\LR}%
1759   \fi\fi\fi
1760   \tabl_table_end_row_indeed\tableseparaterowstate\tablerowfactor\tablerowfactor}
1761
1762\unexpanded\def\tabl_table_FR
1763  {\ifnum\tableactionstate=\tablemidrowstate
1764     \writestatus\m!TABLE{change \string\FR\space into \string\MR/\string\LR}%
1765   \else\ifnum\tableactionstate=\tablelastrowstate
1766     \writestatus\m!TABLE{change \string\FR\space into \string\MR/\string\LR}%
1767   \fi\fi
1768   \tabl_table_end_row_indeed\tablefirstrowstate\tablerowfactor\tablerowzero}
1769
1770\unexpanded\def\tabl_table_MR
1771  {\ifnum\tableactionstate=\tablerulestate
1772     \writestatus\m!TABLE{change \string\MR\space into \string\FR/\string\SR}%
1773   \else\ifnum\tableactionstate=\tablelastrowstate
1774     \writestatus\m!TABLE{change \string\MR\space into \string\FR}%
1775   \fi\fi
1776   \tabl_table_end_row_indeed\tablemidrowstate00}
1777
1778\unexpanded\def\tabl_table_LR
1779  {\ifnum\tableactionstate=\tablerulestate
1780     \writestatus\m!TABLE{change \string\LR\space into \string\FR/\string\SR}%
1781   \fi
1782   \tabl_table_end_row_indeed\tablelastrowstate\tablerowzero\tablerowfactor}
1783
1784%D \macros
1785%D   {ifcheckTABLEcolums}
1786%D
1787%D The next macros handle the actual row ending. This macro also take care of space
1788%D corrections due to table splitting when \type{\MR} and collegues are used. When
1789%D tracing is enabled, the corrections as well as the values used to determine the
1790%D available space are shown (in color). By default checking is off.
1791
1792\def\tabl_table_end_row_indeed#1#2#3%
1793  {\tabl_table_set_action#1%
1794   \ifcase#1\relax
1795     % unknown
1796   \or
1797     \tabl_tables_end_line\SR\SR\tablerowfactor\tablerowfactor
1798   \or
1799     \tabl_tables_end_line\FR\FR\tablerowfactor\tablerowzero
1800   \or\ifnum\tableforcestate=\tableforcelastrowstate
1801     \tabl_tables_end_line\MR\LR\tablerowzero\tablerowfactor
1802   \else\ifnum\tableforcestate=\tableforcefirstrowstate
1803     \tabl_tables_end_line\MR\FR\tablerowfactor\tablerowzero
1804   \else
1805     \tabl_tables_end_line\MR\MR\tablerowzero\tablerowzero
1806   \fi\fi\or
1807     \tabl_tables_end_line\LR\LR\tablerowzero\tablerowfactor
1808   \fi
1809   \starttablenoalign
1810     \tabl_table_set_force\tableunknownstate
1811     \global\currenttablecolumn\zerocount
1812     \ifconditional\preventtablebreak
1813       \nobreak
1814     \else
1815       \goodbreak
1816     \fi
1817   \stoptablenoalign}
1818
1819%D Handling \type{\AR} is postponed till the next row. The check takes care of
1820%D the first and mid rows, the chuck macro |<|how about that name|>| handles
1821%D the last row.
1822
1823\unexpanded\def\tabl_table_AR
1824  {\glet\tabl_tables_check_auto_row\tabl_tables_check_auto_row_indeed
1825   \glet\tabl_tables_chuck_auto_row\tabl_tables_chuck_auto_row_indeed}
1826
1827\let\tabl_tables_check_auto_row\empty
1828\let\tabl_tables_chuck_auto_row\empty
1829
1830\def\tabl_tables_check_auto_row_indeed
1831  {\glet\tabl_tables_check_auto_row\empty
1832   \ifnum\tableactionstate=\tablerulestate   \FR\else
1833   \ifnum\tableactionstate=\tableunknownstate\FR\else
1834                                             \MR\fi\fi}
1835
1836\def\tabl_tables_chuck_auto_row_indeed
1837  {\glet\tabl_tables_check_auto_row\empty
1838   \glet\tabl_tables_chuck_auto_row\empty
1839   \ifnum\tableactionstate=\tablerulestate   \SR\else
1840   \ifnum\tableactionstate=\tableunknownstate\SR\else
1841                                             \LR\fi\fi}
1842
1843%D When a table is split, we also add a tail and when present we repeat the table
1844%D head. If a gets split indeed, the spacing before and after a horizontal rule is
1845%D corrected according to what we expect.
1846
1847\def\tabl_tables_end_line#1#2#3#4%
1848  {\ifx#1#2\else
1849     \writestatus\m!TABLE{\string#1\space changed into \string#2}%
1850   \fi
1851   \expandafter\tabl_table_normal_line_format#3#4\crcr % \crcr nodig ?
1852   \tablenoalign{\nobreak\global\settrue\tableactionstatepermitted}}
1853
1854%D In order to prevent (as good as possible) alignment overflow and therefore \TEX\
1855%D error messages, we check the maximum number of columns. We keep track of the
1856%D current column and maximum column by means of two \COUNTERS. Keep in mind that
1857%D the number of \type{|}'s and \type{\VL}'s or alike is always one more than the
1858%D number of columns.
1859
1860\newcount\currenttablecolumn
1861
1862% DWhile defining this macro we change the \CATCODE\ of \type{|}. When counting the
1863% Dbars, we use a non active representation of the bar, simply because we cannot be
1864% Dsure if the bar is active or not.\footnote{Normally it is, but \TABLE\ changes
1865% Dthe catcode when needed.}
1866
1867\bgroup
1868    \catcode\barasciicode\othercatcode  \gdef\tabl_table_bar    {|}
1869    \catcode\barasciicode\activecatcode \gdef\tabl_table_use_bar{\let|\tabl_table_bar}
1870\egroup
1871
1872\bgroup \catcode\barasciicode\othercatcode
1873
1874\gdef\dogettablenofcolumns#1% todo: also divert this to lua as with tabulate
1875  {\bgroup
1876   \cleanupfeatures % needed !
1877   \tabl_table_use_bar
1878   \egroup}
1879
1880\egroup
1881
1882%D \startitemize[3*ruim]
1883%D \sym{\type{\VL}} a vertical line
1884%D \sym{\type{\VC}} a vertical colored line
1885%D \sym{\type{\HL}} a horizontal line
1886%D \sym{\type{\HC}} a horizontal colored line
1887%D \stopitemize
1888
1889\newcount\c_tabl_table_vrule_thickness_factor
1890\newcount\c_tabl_table_hrule_thickness_factor
1891\newcount\c_tabl_table_drule_span
1892
1893\let\m_tabl_table_vrule_color\empty
1894\let\m_tabl_table_hrule_color\empty
1895
1896\appendtoks
1897  \let\VL\tabl_table_VL
1898  \let\VC\tabl_table_VC
1899  \let\HL\tabl_table_HL
1900  \let\HC\tabl_table_HC
1901  \let\VS\tabl_table_VS
1902  \let\VD\tabl_table_VD
1903  \let\VT\tabl_table_VT
1904  \let\VN\tabl_table_VN
1905\to \localtabledefinitions
1906
1907\def\tabl_table_resetVLvalues
1908  {\global\currenttablecolumn\zerocount}
1909
1910\def\tabl_table_vrulecommand#1% global assignments
1911  {\doifelsenumber{#1}
1912     {\global\c_tabl_table_vrule_thickness_factor#1\relax
1913      \global\multiply\c_tabl_table_vrule_thickness_factor\m_tabl_table_VLwidth\relax}
1914     {\xdef\m_tabl_table_vrule_color{#1}}}
1915
1916\unexpanded\def\tabl_table_VL
1917  {\tabl_tables_check_auto_row
1918   \global\advance\currenttablecolumn\plusone
1919   \dosingleempty\table_tabl_VL_indeed}
1920
1921\def\table_tabl_VL_indeed[#1]%
1922  {\glet\m_tabl_table_vrule_color\empty
1923   \global\c_tabl_table_vrule_thickness_factor\m_tabl_table_VLwidth\relax
1924   \iffirstargument
1925     \rawprocesscommalist[#1]\tabl_table_vrulecommand
1926   \fi
1927   \tabl_table_normal_line_complex_bar}% \relax breaks \use
1928
1929\let\tabl_table_VC\tabl_table_VL % for mojca
1930
1931% \starttable[|||]
1932% \HL
1933% \VL test \VS test \VL \FR
1934% \VL test \VD test \VL \MR
1935% \VL test \VT test \VL \LR
1936% \HL
1937% \stoptable
1938
1939\unexpanded\def\tabl_table_VS  {\VN1}
1940\unexpanded\def\tabl_table_VD  {\VN2}
1941\unexpanded\def\tabl_table_VT  {\VN3}
1942\unexpanded\def\tabl_table_VN#1{\global\c_tabl_table_n_of_vrules#1\relax\VL}
1943
1944\def\tabl_table_hrulecommand#1% global assignments
1945  {\doifelsenumber{#1}
1946     {\global\c_tabl_table_hrule_thickness_factor#1\relax
1947      \global\multiply\c_tabl_table_hrule_thickness_factor\m_tabl_table_HLheight\relax}
1948     {\xdef\m_tabl_table_hrule_color{#1}}}
1949
1950\unexpanded\def\tabl_table_HL
1951  {\tabl_tables_chuck_auto_row
1952   \tabl_table_finish_row
1953   \starttablenoalign
1954   \dosingleempty\table_tabl_HL_indeed}
1955
1956\def\table_tabl_HL_indeed[#1]%
1957  {\nobreak
1958   \ifnum\tableactionstate=\tablerulestate
1959     \writestatus\m!TABLE{skipping \string\HL}% \statusmessage
1960   \else
1961     \ifnum\tableactionstate=\tablemidrowstate
1962       \writestatus\m!TABLE{change \string\MR\space into \string\LR/\string\SR}%
1963     \else\ifnum\tableactionstate=\tablefirstrowstate
1964       \writestatus\m!TABLE{change \string\MR\space into \string\SR}%
1965     \fi\fi
1966     \bgroup
1967       \global\c_tabl_table_hrule_thickness_factor\m_tabl_table_HLheight\relax
1968       \iffirstargument
1969         \glet\m_tabl_table_hrule_color\empty
1970         \rawprocesscommalist[#1]\tabl_table_hrulecommand
1971         \ifx\m_tabl_table_hrule_color\empty\else
1972           \switchtocolor[\m_tabl_table_hrule_color]%
1973         \fi
1974       \fi
1975       \tabl_table_normal_full_rule
1976     \egroup
1977     \tabl_table_account_width
1978   \fi
1979   \tabl_table_set_action\tablerulestate
1980   \nobreak
1981   \stoptablenoalign}
1982
1983\let\tabl_table_HC\tabl_table_HL % for mojca
1984
1985%D \startitemize[3*ruim]
1986%D \sym{\type{\NL}} a vertical skip
1987%D \sym{\type{\NR}} goto the next row
1988%D \sym{\type{\NC}} goto the next column
1989%D \sym{\type{\FC}} a first column
1990%D \sym{\type{\MC}} a mid column
1991%D \sym{\type{\LC}} a last column
1992%D \stopitemize
1993
1994% \starttable[|||]
1995% \VL text \VL text \VL \AR
1996% \TB[small]
1997% \VL text \VL text \VL \AR
1998% \TB[4*big]
1999% \VL text \VL text \VL \AR
2000% \stoptable
2001
2002% n+1 uitleggen
2003
2004\appendtoks
2005  \let\TB\tabl_table_TB
2006  \let\NL\tabl_table_NL % old
2007  \let\NR\tabl_table_NR
2008  \let\NC\tabl_table_NC
2009  \let\FC\tabl_table_NC
2010  \let\MC\tabl_table_NC
2011  \let\LC\tabl_table_NC
2012\to \localtabledefinitions
2013
2014\unexpanded\def\tabl_table_TB
2015  {\tabl_tables_chuck_auto_row
2016   \tabl_table_finish_row
2017   \starttablenoalign
2018   \dosingleempty\table_tabl_TB_indeed}
2019
2020\def\table_tabl_TB_indeed[#1]%
2021  {\blank[\iffirstargument#1\else\directtablesparameter\c!NL\fi]%
2022   \nobreak
2023   \stoptablenoalign}
2024
2025\let\tabl_table_NL\tabl_table_TB
2026
2027\unexpanded\def\tabl_table_NR
2028  {\global\currenttablecolumn\zerocount
2029   \tabl_table_normal_line_ending
2030   \starttablenoalign
2031     \nobreak
2032     \tabl_table_set_action\tableunknownstate
2033   \stoptablenoalign}
2034
2035\unexpanded\def\tabl_table_NC
2036  {\tabl_tables_check_auto_row
2037   \global\advance\currenttablecolumn \plusone
2038   \tabl_table_normal_no_bar}
2039
2040%D \startitemize[3*broad]
2041%D \sym{\type{\DL}}
2042%D \sym{\type{\DV}} (\type{\VD})
2043%D \sym{\type{\DC}}
2044%D \sym{\type{\DR}}
2045%D \stopitemize
2046
2047\newconditional\c_tabl_table_is_division
2048
2049\appendtoks
2050    \global\setfalse\c_tabl_table_is_division
2051    \let\DL\tabl_table_DL
2052    \let\DC\tabl_table_DC
2053    \let\DV\tabl_table_DV
2054    \let\DR\tabl_table_DR
2055\to \localtabledefinitions
2056
2057\def\tabl_table_check_division
2058  {\ifconditional\c_tabl_table_is_division\else
2059     \tabl_tables_chuck_auto_row
2060     \global\currenttablecolumn\zerocount
2061     \global\settrue\c_tabl_table_is_division
2062   \fi}
2063
2064\def\tabl_table_drulecommand#1% global assignments
2065  {\doifelsenumber{#1}
2066     {\ifcase\c_tabl_table_drule_span
2067        \global\c_tabl_table_drule_span#1\relax
2068      \else
2069        \global\c_tabl_table_hrule_thickness_factor#1\relax
2070        \global\multiply\c_tabl_table_hrule_thickness_factor\m_tabl_table_VLwidth\relax
2071      \fi}
2072     {\xdef\m_tabl_table_hrule_color{#1}}}
2073
2074\unexpanded\def\tabl_table_DL
2075  {\tabl_table_check_division
2076   \dosingleempty\table_tabl_DL_indeed}
2077
2078\def\table_tabl_DL_indeed[#1]%
2079  {\ifnum\tableactionstate=\tablerulestate
2080     \writestatus\m!TABLE{skipping \string\DL}%
2081   \else
2082     \ifnum\tableactionstate=\tablemidrowstate
2083       \writestatus\m!TABLE{change \string\MR\space into \string\LR/\string\SR}%
2084     \else\ifnum\tableactionstate=\tablefirstrowstate
2085       \writestatus\m!TABLE{change \string\MR\space into \string\SR}%
2086     \fi\fi
2087     \tabl_table_set_action\tableunknownstate
2088     \global\c_tabl_table_hrule_thickness_factor\m_tabl_table_HLheight\relax
2089     \global\c_tabl_table_drule_span\zerocount
2090     \iffirstargument
2091       \glet\m_tabl_table_hrule_color\empty
2092       \rawprocesscommalist[#1]\tabl_table_drulecommand
2093     % \ifx\m_tabl_table_hrule_color\empty\else
2094     %   \switchtocolor[\m_tabl_table_hrule_color]% see *DL*
2095     % \fi
2096     \fi
2097     \ifcase\c_tabl_table_drule_span
2098       \global\advance\currenttablecolumn \plusone
2099       \tabl_table_normal_single_rule
2100     \or
2101       \global\advance\currenttablecolumn \plustwo
2102       \tabl_table_normal_single_rule
2103     \else
2104       \global\advance\currenttablecolumn \plusone
2105       \tabl_table_normal_multi_rule
2106     \fi
2107   \fi}
2108
2109\unexpanded\def\tabl_table_DV
2110  {\tabl_table_DCV\tabl_table_normal_line_simple_bar}
2111
2112\unexpanded\def\tabl_table_DC
2113  {\tabl_table_DCV\tabl_table_normal_no_bar}
2114
2115\unexpanded\def\tabl_table_DCV#1%
2116  {\tabl_table_check_division
2117   \tabl_tables_check_auto_row
2118   \global\advance\currenttablecolumn \plusone
2119   #1}
2120
2121\unexpanded\def\tabl_table_DR
2122  {\global\currenttablecolumn\zerocount    % nog check
2123   \tabl_table_normal_line_ending
2124   \starttablenoalign
2125     \nobreak
2126     \global\setfalse\c_tabl_table_is_division
2127     \tabl_table_account_width % temporary solution
2128     \tabl_table_set_action\tablerulestate
2129   \stoptablenoalign}
2130
2131\def\tabl_table_account_width
2132  {\scratchdimen\d_tabl_table_line_thickness_unit}
2133
2134\def\tabl_table_TWO   {\use\plustwo}
2135\def\tabl_table_THREE {\use\plusthree}
2136\def\tabl_table_FOUR  {\use\plusfour}
2137\def\tabl_table_FIVE  {\use\plusfive}
2138\def\tabl_table_SIX   {\use\plussix}
2139
2140\appendtoks
2141  \let\TWO  \tabl_table_TWO
2142  \let\THREE\tabl_table_THREE
2143  \let\FOUR \tabl_table_FOUR
2144  \let\FIVE \tabl_table_FIVE
2145  \let\SIX  \tabl_table_SIX
2146  \let\SPAN \use
2147  \let\REF  \tabl_table_reformat
2148\to \localtabledefinitions
2149
2150\installcorenamespace{tables}
2151\installcorenamespace{tabledistance}
2152\installcorenamespace{tablealign}
2153
2154\installsetuponlycommandhandler \??tables {tables} % some day we can have named tables
2155
2156\setvalue{\??tabledistance\v!none  }{\tabl_table_OpenUp00\def\LOW{\Lower6 }}
2157\setvalue{\??tabledistance\v!small }{\tabl_table_OpenUp00\def\LOW{\Lower6 }} % == baseline
2158\setvalue{\??tabledistance\v!medium}{\tabl_table_OpenUp11\def\LOW{\Lower7 }}
2159\setvalue{\??tabledistance\v!big   }{\tabl_table_OpenUp22\def\LOW{\Lower8 }}
2160
2161\appendtoks
2162    \expandnamespaceparameter\??tabledistance\directtablesparameter\c!distance\v!medium
2163\to \localtabledefinitions
2164
2165\setvalue{\??tablealign\v!right  }{\def\tabl_table_paralignment{\raggedright}}
2166\setvalue{\??tablealign\v!left   }{\def\tabl_table_paralignment{\raggedleft}}
2167\setvalue{\??tablealign\v!middle }{\def\tabl_table_paralignment{\raggedcenter}}
2168\setvalue{\??tablealign\s!unknown}{\def\tabl_table_paralignment{\notragged}}
2169
2170\appendtoks
2171  \doifelse{\directtablesparameter\c!distance}\v!none
2172    {\tablerowfactor\zerocount}
2173    {\tablerowfactor\plustwo  }%
2174\to \localtabledefinitions
2175
2176\def\dohandlebar % here ?
2177  {\ifmmode
2178     \expandafter\domathmodebar
2179   \else\ifintable
2180     \doubleexpandafter\domathmodebar
2181   \else
2182     \doubleexpandafter\dotextmodebar
2183   \fi\fi}
2184
2185\appendtoks
2186   \expandnamespaceparameter\??tablealign\directtablesparameter\c!align\s!unknown
2187   \assignalfadimension{\directtablesparameter\c!VL}\m_tabl_table_VLwidth 246%
2188   \assignalfadimension{\directtablesparameter\c!HL}\m_tabl_table_HLheight246%
2189\to \everysetuptables
2190
2191\def\tabl_table_local_setups
2192  {\directtablesparameter\c!commands\relax
2193   \usebodyfontparameter\directtablesparameter
2194   \d_tabl_table_line_thickness_unit\dimexpr\directtablesparameter\c!rulethickness/\tablelinethicknessfactor\relax
2195   \edef\p_tabl_table_height{\directtablesparameter\c!height}%
2196   \edef\p_tabl_table_depth{\directtablesparameter\c!depth}%
2197   \ifx\p_tabl_table_height\v!strut
2198     \let\tablestrutheightfactor\tablestrutheightfactor
2199   \else
2200     \let\tablestrutheightfactor\p_tabl_table_height
2201   \fi
2202   \ifx\p_tabl_table_depth\v!strut
2203     \let\tablestrutdepthfactor\tablestrutdepthfactor
2204   \else
2205     \let\tablestrutdepthfactor\p_tabl_table_depth
2206   \fi
2207   \edef\tablestrutheightfactor{\withoutpt\the\dimexpr10\dimexpr\tablestrutheightfactor\points}%
2208   \edef\tablestrutdepthfactor {\withoutpt\the\dimexpr10\dimexpr\tablestrutdepthfactor \points}%
2209   \d_tabl_table_strut_unit             \dimexpr\normalbaselineskip/12\relax % 12 is default bodyfont
2210   \d_tabl_table_kern_unit              .5em\relax
2211   \s_tabl_table_inter_column_space_unit.5em plus 1fil minus .25em\relax
2212   \d_tabl_table_column_width_unit      \d_tabl_table_kern_unit
2213   \d_tabl_table_kern_unit              \d_tabl_table_kern_unit}
2214
2215%D As one can see, we didn't only add color, but also more control over spacing.
2216%D
2217%D \startbuffer[a]
2218%D \starttable[|c|]
2219%D \HL
2220%D \VL \strut test \VL \FR
2221%D \VL \strut test \VL \MR
2222%D \VL \strut test \VL \MR
2223%D \VL \strut test \VL \LR
2224%D \HL
2225%D \stoptable
2226%D \stopbuffer
2227%D
2228%D \startbuffer[b]
2229%D \starttabulate[|c|]
2230%D \HL
2231%D \NC test \NC \NR
2232%D \NC test \NC \NR
2233%D \NC test \NC \NR
2234%D \NC test \NC \NR
2235%D \HL
2236%D \stoptabulate
2237%D \stopbuffer
2238%D
2239%D In the next example, the first table is defined as:
2240%D
2241%D \typebuffer[a]
2242%D
2243%D and the second one as:
2244%D
2245%D \typebuffer[b]
2246%D
2247%D The first table is typeset using the default height and depth factors .8 and .4.
2248%D The second table has both factors set to \type {strut}, and the third table shows
2249%D what happens when we set the values to zero. The rightmost table is typeset using
2250%D the tabulate environment.
2251%D
2252%D \startcombination[4*1]
2253%D   {$\vcenter{\getbuffer[a]}$}
2254%D     {\hbox{h=.8 d=.4}}
2255%D   {\setuptables[height=strut,depth=strut]$\vcenter{\getbuffer[a]}$}
2256%D     {\hbox{h=d=\type{strut}}}
2257%D   {\setuptables[height=0,depth=0]$\vcenter{\getbuffer[a]}$}
2258%D     {\hbox{h=d=0}}
2259%D   {$\vcenter{\getbuffer[b]}$}
2260%D     {\hbox{tabulate}}
2261%D \stopcombination
2262
2263\setuptables
2264  [\c!HL=\v!medium,
2265   \c!VL=\v!medium,
2266   \c!NL=\v!small,
2267   \c!frame=,
2268   \c!align=\v!right,
2269   \c!depth=.40, % \v!strut
2270   \c!height=.80, % \v!strut
2271   \c!textwidth=,
2272   \c!rulethickness=\linewidth,
2273   \c!rulecolor=,
2274   \c!distance=\v!medium,
2275   \c!bodyfont=,
2276   \c!commands=,
2277   \c!background=,
2278   \c!backgroundcolor=,
2279   \c!split=\v!auto,
2280   \c!openup=\zeropoint]
2281
2282\protect \endinput
2283