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