% TABLE 1.0 % Copyright Michael J. Wichura August 1988 % The TABLE macros are divided into sections, roughly according to % function: % Section Name Function % a Allocation Allocates storage registers for parameters. % f Format Reads format section; builds preamble for \halign; % processes \ReFormat command. % g Get Value Converts "spec"'s (as in spec_{LT}) to % corresponding "values"'s (as in value_{LT}). % h Hacks Utility macros; error messages; miscellaneous commands. % k Keys Definition and scanning of format keys. % n Numeric Macros for TABLE's numeric format. % s Struts Macros for struts. % t Tables Sets up \halign for table; end-of-row processing; % alternate vertical rules; spanning; horizontal % lines; stretching and shrinking; repositioning % commands. % The name of each internal macro begins with the prefix "\!t", the % "!" having category code 11, followed by the letter of the section % in which the macro is defined. For example, a macro beginning "\!th" % is defined in Section h (Hacks). There a few exceptions: % the general purpose macros "\!ttemp", "\!ttempa", "\!ttempb", and % "\!tnext" are repeatedly defined on the spot as the need arises. % External macros (and active characters) are defined in the following % sections: % Macro Section % " t % \- t % \= t % \ActivateBarAndQuote h % \AugmentedTableStrut s % \BackSpace h % \BeginFormat f % \BeginTable t % \BeginTableParBox a % \Center t % \ColumnWidthFactor a % \ColumnWidthUnit a % \DQuote h % \EndFormat k (\EndFormat is actually a key) % \EndTable t % \EndTableParBox a % \Enlarge s % \enlarge s % \EveryTable a % \EveryTableParBox a % \Expand t % \InterColumnSpaceFactor a % \InterColumnSpaceUnit a % \JustCenter t % \JustLeft t % \JustRight t % \KernFactor a % \KernUnit a % \Left t % \LeftTabskip a % \LineThicknessFactor a % \LineThicknessUnit a % \LongLines t % \Lower h % \MakeStrut s % \NewFormatKey k % \NormalCWU a % \NormalICSU a % \NormalKU a % \NormalLTU a % \NormalSU a % \NormalTableUnits a % \OpenUp s % \PseudoVrule t % \Raise h % \ReadFormatKeys k % \ReFormat f % \Right t % \RightTabskip a % \SetTableToWidth t % \Smash h % \StandardTableStrut s % \StrutDepthFactor a % \StrutHeightFactor a % \StrutUnit a % \TaBlE h % \TracingFormats a % \TracingKeys a % \Use t % \use t % \VBar h % \Vspace h % \VspaceFactor a % \WidenTableBy t % \\ t % \_ t % \| t % | t % ~ t % \catcode `\!=11 \catcode `\@=11 % Don't try to read the TABLE macros until after you've read the % TABLE manual. The internal documentation of the macros is % sketchy; you need the manual to understand what's going on. % You should also review the material on \halign s in the TeXbook, % since TABLE uses an \halign to perform its alignments. % In studying the TABLE macros, you should start by skimming the % macros in the "miscellaneous hacks", "error messages", and "loops" % subsections of Section h, as well as the "\GetValue" macro in % Section g; these macros are called many times by the other macros. % To continue with a "bottom-up" approach, read next Sections k, % f, and t. (Top-downers should reverse the order.) The other % Sections can be looked at as the need arises. % ********************************************************************* % SECTION A: ALLOCATION % ********************************************************************* \let\!tacr=\\ % Save meaning of \\ (Needed if TABLE is used with LaTeX % ********************************************************************* % TABLE PARAMETERS: Units % ********************************************************************* \newdimen\LineThicknessUnit \newdimen\StrutUnit \newskip \InterColumnSpaceUnit \newdimen\ColumnWidthUnit \newdimen\KernUnit \let\!taLTU=\LineThicknessUnit % Used in preamble \let\!taCWU=\ColumnWidthUnit % Used in preamble \let\!taKU =\KernUnit % Used in preamble \newtoks\NormalTLTU \newtoks\NormalTSU \newtoks\NormalTICSU \newtoks\NormalTCWU \newtoks\NormalTKU % NOTE: The user should modify the following DEFAULTS to suit his/her % taste, and output device: %\def\PixelsPerInch{300} \NormalTLTU={1in \divide \LineThicknessUnit by 300 } \NormalTSU ={\normalbaselineskip \divide \StrutUnit by 11 } % 11 = 8+3 = NormalT Height+Depth Factors \NormalTICSU={.5em plus 1fil minus .25em} % .5em = width of a digit \NormalTCWU ={.5em} \NormalTKU ={.5em} \def\NormalTableUnits{% \LineThicknessUnit =\the\NormalTLTU \StrutUnit =\the\NormalTSU \InterColumnSpaceUnit=\the\NormalTICSU \ColumnWidthUnit =\the\NormalTCWU \KernUnit =\the\NormalTKU} \NormalTableUnits % The user should issue \NormalTableUnits when setting a table % in a different point size, since the Table...Units themselves % are static while the Normal...Units vary with the point size. % ********************************************************************* % TABLE PARAMETERS: Factors % ********************************************************************* \newcount\LineThicknessFactor \newcount\StrutHeightFactor \newcount\StrutDepthFactor \newcount\InterColumnSpaceFactor \newcount\ColumnWidthFactor \newcount\KernFactor \newcount\VspaceFactor % DEFAULTS: \LineThicknessFactor =2 \StrutHeightFactor =8 \StrutDepthFactor =3 \InterColumnSpaceFactor =3 \ColumnWidthFactor =10 \KernFactor =1 \VspaceFactor =2 % ********************************************************************* % DIAGNOSTIC PARAMETERS % ********************************************************************* \newcount\TracingKeys % >=1 reports new keys, >=2 reports key usage \newcount\TracingFormats % >=1 reports templates for columns % >=2 reports \halign preamble % ********************************************************************* % PARBLOCK PARAMETERS % ********************************************************************* \def\BeginTableParBox#1{% \vtop\bgroup \hsize=#1 \normalbaselines \let~=\!ttTie \let\-=\!ttDH \the\EveryTableParBox} \def\EndTableParBox{% \MakeStrut{0pt}{\StrutDepthFactor\StrutUnit} \egroup} % finishes the \vtop begun by \BeginTableParbox \newtoks\EveryTableParBox \EveryTableParBox={% \parindent=0pt \raggedright \rightskip=0pt plus 4em % Provide more stretch \relax} % ********************************************************************* % EVERY TABLE TOKENS % ********************************************************************* \newtoks\EveryTable \newtoks\!taTableSpread % ********************************************************************* % Extreme left- and right- tabskips % ********************************************************************* \newskip\LeftTabskip \newskip\RightTabskip % ********************************************************************* % INTERNAL VARIABLES % ********************************************************************* \newcount\!taCountA \newcount\!taColumnNumber \newcount\!taRecursionLevel % (Initially 0) \newcount\!ttmscount % like plain TeX's \mscount, only private \newdimen\!taDimenA % used by \Enlarge \newdimen\!taDimenB % used by \Enlarge \newdimen\!taDimenC % used by numeric.tex \newdimen\!taMinimumColumnWidth \newtoks\!taToksA \newtoks\!taPreamble \newtoks\!taDataColumnTemplate \newtoks\!taRuleColumnTemplate \newtoks\!taOldRuleColumnTemplate \newtoks\!taLeftGlue \newtoks\!taRightGlue \newskip\!taLastRegularTabskip \newif\if!taDigit \newif\if!taBeginFormat \newif\if!taOnceOnlyTabskip % ********************************************************************* % SECTION H: HACKS % ********************************************************************* % **************************************************************** % TABLE LOGO % **************************************************************** \def\TaBlE{% T\kern-.27em\lower.5ex\hbox{A}\kern-.18em B\kern-.1em \lower.5ex\hbox{L}\kern-.075em E} % **************************************************************** % ACTIVE CHARACTERS % **************************************************************** % ACTIVATE BAR AND QUOTE: Makes | and " active if they aren't % already active (in which case the user will probably have given % them special meanings); definitions are provided which effectively % undoes the activeness outside a Table. {\catcode`\|=13 \catcode`\"=13 \gdef\ActivateBarAndQuote{% \ifnum \catcode`\|=13 \else \catcode`\|=13 \def|{% \ifmmode \vert \else \char`\| \fi}% \fi \ifnum \catcode`\"=13 \else \catcode`\"=13 \def"{\char`\"}% \fi}} % **************************************************************** % Macros for | and " having category code 12. % **************************************************************** {\catcode `\|=12 \catcode `\"=12 \gdef\VBar{|} \gdef\DQuote{"}} % **************************************************************** % MISCELANEOUS HACKS % **************************************************************** % MESSAGE : Writes out to terminal and log file. \def\!thMessage#1{\immediate\write16{#1}\ignorespaces} % X: Abbreviation for expandafter \let\!thx=\expandafter % GOBBLE: Eats next token \def\!thGobble#1{} % SPACE TOKEN \def\\{\let\!thSpaceToken= }\\ % HEIGHT, DEPTH, AND WIDTH \def\!thHeight{height} \def\!thDepth{depth} \def\!thWidth{width} % TOKSEDEF =: Places , fully expanded a la \edef, in the specified . \def\!thToksEdef#1=#2{% \edef\!ttemp{#2}% #1\!thx{\!ttemp}% \ignorespaces} % **************************************************************** % ERROR MESSAGES % **************************************************************** % STORE ERROR MSG % Replacement text of is a macro with Message % as its name. E.g., after \StoreErrorMsg\Help{Type }, % \Help expands to "\Type " \def\!thStoreErrorMsg#1#2{% \toks0 =\!thx{\csname #2\endcsname}% \edef#1{\the\toks0 }} % READ ERROR MSG % Continuing the above example, \ReadErrorMsg\Help produces "Type " \def\!thReadErrorMsg#1{% \!thx\!thx\!thx\!thGobble\!thx\string #1} % ERROR \def\!thError#1#2{% \begingroup \newlinechar=`\^^J% \edef\!ttemp{#2}% \errhelp=\!thx{\!ttemp}% \!thMessage{% ^^J\!thReadErrorMsg\!thErrorMsgA ^^J\!thReadErrorMsg\!thErrorMsgB}% \errmessage{#1}% \endgroup} % TEXT FOR ERROR MESSAGE \!thStoreErrorMsg\!thErrorMsgA{% TABLE error; see manual for explanation.} \!thStoreErrorMsg\!thErrorMsgB{% Type \space H \space for immediate help.} % GET REPLACEMENT % must be a control sequence \def\!thGetReplacement#1#2{% \begingroup \!thMessage{#1} \endlinechar=-1 \global\read16 to#2% \endgroup} % **************************************************************** % LOOP MACRO % **************************************************************** % LOOP ... REPEAT macro from TUGboat Vol 8 #2: 1987 % Syntax is like that of plain TeX's \loop ... \repeat macro \def\!thLoop#1\repeat{% \def\!thIterate{% #1% \!thx \!thIterate \fi}% \!thIterate \let\!thIterate\relax} % *************************************************************** % VERTICALLY-CENTERED SMASH % *************************************************************** % SMASH: Like TeX's \smash, only the argument % is centered vertically before its height and depth are smashed to 0pt. \def\Smash{% \relax \ifmmode \expandafter\mathpalette \expandafter\!thDoMathVCS \else \expandafter\!thDoVCS \fi} % DO VCS \def\!thDoVCS#1{% \setbox\z@\hbox{#1}% \!thFinishVCS} % DO MATH VCS \def\!thDoMathVCS#1#2{% \setbox\z@\hbox{$\m@th#1{#2}$}% \!thFinishVCS} % FINISH VCS \def\!thFinishVCS{% \vbox to\z@{\vss\box\z@\vss}} % *************************************************************** % RAISE AND LOWER % *************************************************************** % Like TeX's \raise and \lower, except: (1) The first argument % to these commands is a dimension expressed in TABLE's usual conventions; % the default is (StrutHeightFactor+StrutDepthFactor)*StrutUnit/2 % (2) like \smash, these commands function in math mode as well % as horizontal mode; (3) again like \smash, the result is declared % to have height and depth 0pt % Examples \Raise2{Stuff}: "Stuff" is raised 2*StrutUnit % \Raise {Stuff}: "Stuff" is raised a half-line % $\Lower(10pt){\alpha}$: "$\alpha$" is lowered 10 points % RAISE \def\Raise{% \def\!thSign{+}% \!tgGetValue\!thSetDimen} % LOWER \def\Lower{% \def\!thSign{-}% \!tgGetValue\!thSetDimen} % SET DIMEN \def\!thSetDimen{% \ifnum \!tgCode=1 \ifx \!tgValue\empty \!taDimenA \StrutHeightFactor\StrutUnit \advance \!taDimenA \StrutDepthFactor\StrutUnit \divide \!taDimenA 2 \else \!taDimenA \!tgValue\StrutUnit \fi \else \!taDimenA \!tgValue \fi \!taDimenA=\!thSign\!taDimenA\relax % % BRANCH ON MODE \ifmmode \expandafter\mathpalette \expandafter\!thDoMathRaise \else \expandafter\!thDoSimpleRaise \fi} % DO SIMPLE RAISE \def\!thDoSimpleRaise#1{% \setbox\z@\hbox{\raise \!taDimenA\hbox{#1}}% \!thFinishRaise} % From Plain TeX: \ht0=0pt \dp0=0pt \box0 % DO MATH RAISE \def\!thDoMathRaise#1#2{% \setbox\z@\hbox{\raise \!taDimenA\hbox{$\m@th#1{#2}$}}% \!thFinishRaise} % FINISH RAISE. This is the same as Plain's \finsm@sh; some macro % packages redefine \finsm@sh. \def\!thFinishRaise{% \ht\z@\z@ \dp\z@\z@ \box\z@} % *************************************************************** % BACK SPACE % *************************************************************** \def\BackSpace{% \!tgGetValue\!thKernBack} \def\!thKernBack{% \kern - \ifnum \!tgCode=1 \ifx \!tgValue\empty \the\KernFactor \else \!tgValue % user-specified integer \fi \KernUnit \else \!tgValue % user-specified dimension \fi \ignorespaces}% % *************************************************************** % Vspace % *************************************************************** \def\Vspace{% \noalign \bgroup \!tgGetValue\!thVspace} \def\!thVspace{% \vskip \ifnum \!tgCode=1 \ifx \!tgValue\empty \the\VspaceFactor \else \!tgValue % user-specified integer \fi \StrutUnit \else \!tgValue % user-specified skip \fi \egroup} % Ends the \noalign % ********************************************************************* % SECTION F: FORMAT % ********************************************************************* % As explained in Section 3.3 of the manual, TABLE alternates each % of the user's "data" columns with a "rule" column; moreover, TABLE % places a "dummy data" column at the left and right of a table. % A table with n nominal data columns therefore actually has a % total of % n (nominal data columns) % +(n+1) (rule columns) % + 2 (dummy data columns) % ____ % 2n+3 % columns. % FORMATs job is to create an \halign preamble for the alignment % of these (2n+3) columns. The preamble consists of templates % for the various columns, strung together with &'s and interlaced % with \tabskip glue specifications. % FORMAT constructs the template for a nomimal data column according % to the user-specified format keys. As the keys are read from left % to right, the template is built up "from the inside out" (as % illustrated in Section 3.1.9 of the manual), the inner-most part % being the "#" sign. A "|" in the format terminates template % building; the completed template is adjoined to preamble along % with the template for the following rule column. % Minimum column widths, if specified, are implemented by creating % an "artificial row" with data entries of the form % \hskip . % This row has zero height and depth and is completely invisible. % BEGIN FORMAT \def\BeginFormat{% \catcode`\|=12 % Inhibit expansion if | immediately follows a \catcode`\"=12 % read by \getvalue. \!taPreamble={}% \!taColumnNumber=0 \skip0 =\InterColumnSpaceUnit \multiply\skip0 \InterColumnSpaceFactor \divide\skip0 2 \!taRuleColumnTemplate=\!thx{% \!thx\tabskip\the\skip0 }% \!taLastRegularTabskip=\skip0 \!taOnceOnlyTabskipfalse \!taBeginFormattrue % Used to intercept key "]" \def\!tfRowOfWidths{}% Artificial Table Row with horizontal struts % to enforce specified minimum column widths \ReadFormatKeys} % SET (MINIMUM COLUMN) WIDTH: Invoked by the key "w". \def\!tfSetWidth{% \ifx \!tfRowOfWidths \empty % true if no prior "w" keys \ifnum \!taColumnNumber>0 % true if "w" key is to right of first "|" \begingroup % RowOfWidths={&\omit || n copies of % &\omit&\omit}, where n = number of columns \!taCountA=1 % to the left of this one \aftergroup \edef \aftergroup \!tfRowOfWidths \aftergroup {% \aftergroup &\aftergroup \omit \!thLoop \ifnum \!taCountA<\!taColumnNumber \advance\!taCountA 1 \aftergroup \!tfAOAO \repeat \aftergroup }% \endgroup \fi \fi \ifx [\!ttemp % \!tgGetValue sets \!ttemp = token after w \!thx\!tfSetWidthText \else \!thx\!tfSetWidthValue \fi} % AOAO = (Apersand Omit Ampersand Omit) \def\!tfAOAO{% &\omit&\omit} % SET WIDTH TEXT \def\!tfSetWidthText [#1]{% #1 = specified text \def\!tfWidthText{#1}% \ReadFormatKeys} % SET WIDTH VALUE \def\!tfSetWidthValue{% \!taMinimumColumnWidth = \ifnum \!tgCode=1 \ifx\!tgValue\empty % Use default multiplier if user didn't specify one \ColumnWidthFactor \else \!tgValue \fi \ColumnWidthUnit \else \!tgValue \fi \def\!tfWidthText{}% Override possible prior `w[sample entry]' \ReadFormatKeys} % SET TABSKIP: Invoked by the tabskip keys "t" and "o" \def\!tfSetTabskip{% \ifnum \!tgCode=1 \skip0 =\InterColumnSpaceUnit \multiply\skip0 \ifx \!tgValue\empty \InterColumnSpaceFactor % Default integer \else \!tgValue % User-specified integer \fi \else \skip0 =\!tgValue % User-specified \fi \divide\skip0 by 2 \ifnum\!taColumnNumber=0 \!thToksEdef\!taRuleColumnTemplate={% \the\!taRuleColumnTemplate \tabskip \the\skip0 } \else \!thToksEdef\!taDataColumnTemplate={% \the\!taDataColumnTemplate \tabskip \the\skip0 } \fi \if!taOnceOnlyTabskip % % Tabskip used at right of this col only \else \!taLastRegularTabskip=\skip0 % Remember this Tabskip, for possible \fi % restoration after a subsequent"OnceOnly" \ReadFormatKeys} % SET VRULE: Invoked by the key "|" \def\!tfSetVrule{% \!thToksEdef\!taRuleColumnTemplate={% \noexpand\hfil \noexpand\vrule \noexpand\!thWidth \ifnum \!tgCode=1 \ifx \!tgValue\empty \the\LineThicknessFactor % Default integer \else \!tgValue % User-specified integer \fi \!taLTU % \LineThicknessUnit \else \!tgValue % User-specified dimension \fi ####% \noexpand\hfil \the\!taRuleColumnTemplate} % has \tabskips, when column number=0 \!tfAdjoinPriorColumn} % SET ALTERNATE VRULE: Invoked by the key "\|", in the form % \|{