% --------------------------------------------------------------------------- % THIS FILE BELONGS TO THE TAP PACKAGE % --------------------------------------------------------------------------- % Macros for typesetting tables in a simple manner using PostScript % for filling, hashing, etc. cells of the table. % BOP s.c., Piastowska 70, 80-363 Gda¤sk, Poland % Bogus\l{}aw Jackowski, Piotr Pianowski and Piotr Strzelczyk % internet: jacko@ipipan.gda.pl % History: % The starting point of this package was a neat package % by Michael J. Ferguson. With his kind permission we rebuilt % the package from a scratch. Some notational ``bells and whistles'' % have been added, and---which is perhaps more important---the package % has been enhanced by PostScript-oriented features (painting cells with % an arbitrary colour, drawing diagonal strokes, etc.). % The package does not use tabskip glues for imposing a desired width; % this makes the code a bit more complex, yet gives some advantages. % Version: 0.70, Friday, May 3rd, 1996 (BachoTeX 96 release) \ifx\tapmacrosareloaded\relax % anti-double loading barrier \expandafter\endinput\else\let\tapmacrosareloaded\relax \fi % =============================== Preamble ================================ \let\normalexclam! \let\normalat@ \let\normalquotes" \let\normalvbar| \def\normalundscore{_}% an exception \edef\dblquotecatcode{\the\catcode`\"} \edef\brokenbarcatcode{\the\catcode`\|} \edef\exclamcatcode{\the\catcode`\!} \edef\undscorecatcode{\the\catcode`\_} \edef\atcatcode{\the\catcode`\@} \def\tableactive{% \catcode`\|13 \catcode`\@13 \catcode`\"13 \catcode`\!13\relax} \catcode`\_=11 \catcode`\@=11 % temporarily, in a moment it will be active \let\span_\sp@n % soon @ won't be available as a letter \tableactive \def|{\ifmmode \vert\else \normalvbar \fi} % effectively undoes activeness \let!\normalexclam \let@\normalat \let"\normalquotes % ============================= Table macros ============================== % \trth = normal table rule thickness (default .4pt) % \TRTH = bold table rule thickness (default 1.2pt) \newdimen\trth \trth=.4pt \newdimen\TRTH \TRTH=1.2pt \newcount\align_state \align_state=0 % 0 -- between lines after \cr % 1 -- beginning of line in \br % 2 -- midline % 3 -- endline in \er \def\hssf{\hskip 0pt plus 1fill minus 1fill} %general math form \def\math#1{\relax $\relax#1\relax$} \def\displaymath #1{\relax$\displaystyle #1\relax$} \newtoks\everytable \everytable{\relax} \newtoks\thistable \thistable{\relax} \newdimen\desiredwidth \def\width_accuracy_limit{.01pt}% not to be changed \newdimen\widthaccuracy \widthaccuracy\width_accuracy_limit \newif\iflongcalculation \newbox\table_box \newbox\box_tmp \newdimen\innerht \newdimen\innerdp % to be used in \X, \x, \Y, and \y \newdimen\normht \newdimen\normdp % for normal rows \newdimen\extraht \newdimen\extradp % for vertically extended rows \def\defaultcellmarg{0.5em} % \cellmarg is by default set to .5em of \newdimen\cellmarg % the current font at the beginning of a table \newcount\cellnum \newcount\maxcellnum \newdimen\cellcorr \newdimen\maxcellcorr \newdimen\mincellcorr \newcount\cellstate % 0 -- aligned to left % 1 -- centered % 2 -- aligned to right \newif\ifignorecellstate % \ostrut means ``open'' strut (to be followed by height depth % , \istrut means inner strut to be used in \X, \x, \Y, and \y \def\ostrut{\vrule width0mm} \def\istrut{\ostrut height\innerht depth\innerdp\relax} \def\defaultstrut{% \setbox\box_tmp\hbox{(pl}% \settablestrut \ht\box_tmp \dp\box_tmp \ht\box_tmp \dp\box_tmp \adjusttablestrut .45ex .15ex .95ex .55ex \setstrut \normht \normdp } \def\setstrut{\afterassignment\innerdp\innerht} \def\adjuststrut{\afterassignment\adjuststrut_\advance\innerht} \def\adjuststrut_{\advance\innerdp} \def\settablestrut{\afterassignment\settablestrut_\normht} \def\settablestrut_{\afterassignment\settablestrut__\normdp} \def\settablestrut__{\afterassignment\settablestrut___\extraht} \def\settablestrut___{\extradp} \def\adjusttablestrut{\afterassignment\adjusttablestrut_\advance\normht} \def\adjusttablestrut_{\afterassignment\adjusttablestrut__\advance\normdp} \def\adjusttablestrut__{\afterassignment\adjusttablestrut___\advance\extraht} \def\adjusttablestrut___{\advance\extradp} \def\symcellcorr{\ignorecellstatetrue} \def\asymcellcorr{\ignorecellstatefalse} \symcellcorr % \leftcellside and \rightcellside will be subjected to expansion % using \edef in \begintableformat, hence no \ifnum-s can be involved; % for the same reason \noexpand-s are used in \update_mincellmarg; % \antileftcellside and \antirightcellside for the sake of symmetry % are programmed similarly; ignoring the cell state is meant as a global % setting, hence \ifignorecellstate can be subjected to \edef \newdimen\mincellmarg \def\update_mincellmarg{% \dim_tmp\cellmarg \advance\dim_tmp\cellcorr \noexpand\ifdim\dim_tmp<\mincellmarg \global\mincellmarg\dim_tmp \noexpand\fi} \def\leftcellside{% \global\advance\cellnum1\kern\cellmarg \ifignorecellstate \kern\cellcorr \update_mincellmarg \else {\multiply\cellcorr\cellstate \kern\cellcorr \update_mincellmarg }\fi } \def\antileftcellside{\hskip-\cellmarg \ifignorecellstate \kern-\cellcorr \else {\multiply\cellcorr\cellstate \kern-\cellcorr}\fi } \def\rightcellside{% \global\advance\cellnum1\kern\cellmarg \ifignorecellstate \kern\cellcorr \update_mincellmarg \else {\cellstate-\cellstate \advance\cellstate2 \multiply\cellcorr\cellstate \kern\cellcorr \update_mincellmarg }\fi } \def\antirightcellside{\hskip-\cellmarg \ifignorecellstate \kern-\cellcorr \else {\cellstate-\cellstate \advance\cellstate2 \multiply\cellcorr\cellstate \kern-\cellcorr}\fi } \def\beginflatcell{\vbox to0mm\bgroup\vss \hbox\bgroup \istrut} \def\endflatcell{\egroup\vss\egroup} \newif\ifv_squash \newbox\cell_box \def\normcellbox{\hbox\bgroup\v_squashfalse\let\v_box_or_top\vbox\cellbox_} \def\flatcellbox{\hbox\bgroup\v_squashtrue\let\v_box_or_top\vbox\cellbox_} \def\normcelltop{\hbox\bgroup\v_squashfalse\let\v_box_or_top\vtop\cellbox_} \def\flatcelltop{\hbox\bgroup\v_squashtrue\let\v_box_or_top\vtop\cellbox_} \def\cellbox_#1#{\def\cellbox_parm{#1}% \ifx\cellbox_parm\empty \expandafter \cellbox_a \else \expandafter \cellbox_p \fi} \def\cellbox_a#1{% aligned cell box \setbox\cell_box\v_box_or_top{ \let\\\cr \let@\normalat \let!\normalexclam \def\L##1{\ignorespaces ##1\unskip\hssf\null} \def\C##1{\hssf \ignorespaces ##1\unskip\hssf\null} \def\R##1{\hssf \ignorespaces ##1\unskip\null} \everycr{} \halign{% \istrut \ifnum\cellstate>0\hss\fi ##\ifnum\cellstate<2\hss\fi \cr \ignorespaces #1\crcr } }% \ifv_squash\vbox to0mm{\vss\box\cell_box\vss}\else\box\cell_box\fi \egroup } \def\cellbox_p#1{% paragraph cell box \setbox\cell_box\v_box_or_top{\parindent0mm \parfillskip0pt \def\\{\unskip\break\hskip0pt\relax\ignorespaces} \let@\normalat \let!\normalexclam \let~\ori_tilde % restore the original meaning (natural in a ``par'' mode) \let\-\ori_bsdash % ditto \let\=\ori_bsequal % ditto \def\L##1{\ignorespaces ##1\unskip\hfill\null} \def\C##1{\hfill\ignorespaces ##1\unskip\hfill\null} \def\R##1{\hfill\ignorespaces ##1\unskip\null} \hsize\cellbox_parm \normalbaselines \baselineskip\innerht \advance\baselineskip\innerdp \ifnum\cellstate>0 \leftskip0ptplus1fil \fi \ifnum\cellstate<2 \rightskip0ptplus1fil \fi \hskip0pt\relax % enable implicitly breaking of the first word \ignorespaces #1}% \ifv_squash \vbox to0mm{\vss\box\cell_box\vss}\else\box\cell_box\fi \egroup } \def\cellaction#1{\ifcase\align_state \def\cellaction_{#1}\or \def\cellaction_{#1}\or \def\cellaction_{\unskip&}\else \def\cellaction_{#1}\fi\cellaction_} \def\tablerulecmyk#1{\def\thetablerulecmyk{#1}} \def\beginrulecmyk{\ifx\thetablerulecmyk\empty\else \special{ps:gsave \thetablerulecmyk\space setcmykcolor}\fi} \def\endrulecmyk{\ifx\thetablerulecmyk\empty\else\special{ps:grestore}\fi} \def\tablefullrule#1{\noalign{\beginrulecmyk \hrule height #1\endrulecmyk}} \def\tablevrule#1{\hss\beginrulecmyk\vrule width #1\endrulecmyk\hss} \def\tablehrule#1{\antileftcellside \beginrulecmyk\leaders\hrule height #1\hfill\endrulecmyk \antirightcellside} \def\preambleleft{\cellstate0\relax \leftcellside \currtfont \begincell \ignorespaces ####\unskip\endcell \hfil \rightcellside} \def\preamblecenter{\cellstate1\relax \leftcellside \hfil \currtfont \begincell \ignorespaces ####\unskip\endcell \hfil \rightcellside} \def\preambleright{\cellstate2\relax \leftcellside \hfil \currtfont \begincell \ignorespaces ####\unskip\endcell \rightcellside} \def\tableleft#1{\omit\cellstate0\relax \leftcellside \currtfont \begincell \ignorespaces #1\endcell \hfil \rightcellside} \def\tablecenter#1{\omit\cellstate1\relax \leftcellside \hfil \currtfont \begincell \ignorespaces #1\endcell \hfil \rightcellside} \def\tableright#1{\omit\cellstate2\relax \leftcellside \hfil \currtfont \begincell \ignorespaces #1\endcell \rightcellside} \def\usecells{\omit\relax\afterassignment\usecells_\mscount} \def\usecells_{% \advance\mscount by -1\multiply\mscount by2 \loop\ifnum\mscount>1 \span_\repeat \ifnum\mscount>0 \span \else \relax \fi} \newif\ifspec_distender \spec_distenderfalse % used by macro \B \def\short_fix_cellcorr{% % \setbox\table_box... is already performed % locally \cellcorr = 1/cellmax * (desired_wd-acual_wd) \cellcorr\desiredwidth \advance\cellcorr-\wd\table_box \def\corr_sign{}% \ifdim\cellcorr<0mm\def\corr_sign{-}\cellcorr-\cellcorr\fi \resize \cellcorr{1sp}\cellcorr{\the\maxcellnum sp}% \cellcorr\corr_sign\cellcorr } \def\long_fix_cellcorr{% \ifdim\widthaccuracy<\width_accuracy_limit\relax \widthaccuracy\width_accuracy_limit\relax % moderate accuracy \fi % initial settings (\setbox\table_box... is already performed): \cellcorr0mm \dim_tmp\desiredwidth \advance\dim_tmp-\wd\table_box % each cell is ``padded'' exactly by 2\cellcorr and at least % one cell must appear in any table, hence the coefficient 1/2: \ifdim\dim_tmp<0mm \mincellcorr.5\dim_tmp \else \maxcellcorr.5\dim_tmp \fi % binary search: \loop \ifdim\dim_tmp<0mm \maxcellcorr\cellcorr \dim_tmp-\dim_tmp \else \mincellcorr\cellcorr \fi \ifdim\dim_tmp>\widthaccuracy \cellcorr\mincellcorr \advance\cellcorr\maxcellcorr \cellcorr.5\cellcorr \setbox\table_box\hbox{\curr_table}% % \immediate\write16{\the\wd\table_box, \the\cellcorr\space}% \dim_tmp\desiredwidth \advance\dim_tmp-\wd\table_box \repeat } \def\fix_cellcorr{% \iflongcalculation \long_fix_cellcorr \else \short_fix_cellcorr \fi} \def\margin_warning{% \ifdim\cellcorr<0mm \ifdim\mincellmarg<\TRTH \immediate\write16{% TAPS warning: effective cell margin = \the\mincellmarg.}% \fi \fi} \def\width_info#1{% \let\ \space % it's local \immediate\write16{% TAPS warning: Unsuccessful forcing of the desired width.}% \immediate\write16{% \ \ \ \ \ \ \ \ \ \ \ \ \ \ desired width - resulting width = \the#1}% \immediate\write16{% \ \ \ \ \ \ \ \ \ \ \ \ \ \ required accuracy = \the\widthaccuracy}} \def\width_warning{% \ifdim\desiredwidth>0mm % \setbox\table_box\hbox{\curr_table} is performed immediately prior to % calling \width_warning, i.e., \table_box registers are defined \begingroup \advance\desiredwidth-\wd\table_box % temporary settings: \ifdim\desiredwidth>\widthaccuracy \width_info\desiredwidth \fi \ifdim\desiredwidth<-\widthaccuracy \width_info\desiredwidth \fi \endgroup \fi} \def\table_setup{ \tableactive % protect the original meanings of important macros: \let\ori_tilde~ \let\ori_bsdash\- \let\ori_bsequal\= \let\ori_bsgreater\> % in plain \def\>{\mskip\medmuskip} \let\ori_bsexclam\! % " \def\!{\mskip-\thinmuskip} \everymath{\let\>\ori_bsgreater \let\!\ori_bsexclam \let@\normalat \let!\normalexclam} \let\!\normalexclam \let\>\rlap \let\<\llap \let\H\hbox % useful as a ``horizontal strut'': \H to5mm{} \let\x\flatcellbox \let\X\normcellbox \let\y\flatcelltop \let\Y\normcelltop \def\P##1{{\phantom{##1}}} % \phantom uses \box0, hence curly braces \def\V##1{{\vphantom{##1}}} % ditto \def\K{\noalign\bgroup\afterassignment\K_\dim_tmp} \def\K_{\kern\dim_tmp\egroup} \def\L{\endcell\hfill\begincell} \def\F##1{\noalign{\global\let\currtfont##1}} % sets current table font \def\-{\ifcase\align_state \tablefullrule{\trth}\else \endcell\tablehrule{\trth}\begincell\fi} \def\={\ifcase\align_state \tablefullrule{\TRTH}\else \endcell\tablehrule{\TRTH}\begincell\fi} \def|{\cellaction{\tablevrule\trth}} \def!{\cellaction{\tablevrule\TRTH}} \def\br##1{% \global\cellnum0\relax \global\align_state1\relax \ignorespaces ##1\unskip \global\align_state2\relax &% } \def\B##1##2{% % if ##2 equals to 0 - + _ ^ or : it is interpreted in a special way; % otherwise ##2 is treated as if it were equal to 0 and the token list % swallowed as ##2 parameter is put after \br{...}; in the later case, % however, surrounding curly braces may disappear; in these, hopefully, rare % situations using either explicitly suffix 0 or double bracing may help \br{##1\spec_distendertrue\D{##2}}} \def\er##1{\global\align_state=3\unskip&##1\unskip \global\align_state=0\cr} \def\E{\er} \def\D##1{% ``distender'' % if ##1 equals to 0 - + _ ^ or : it is interpreted in a special way, % namely a strut of an appropriate size is formed; otherwise ##1 is just % returned to \TeX (possibly without curly braces, however); see also % definition of \B above \ifvmode\leavevmode\fi \ifhmode\nobreak\hskip0pt\relax\fi % enable breaking of a preceding word \gdef\next_tok{}% \def\first_par{##1}% \def\null_suffix{0}% \def\flat_suffix{-}% \def\norm_suffix{+}% \edef\dn_suffix{\normalundscore}% an exception \def\up_suffix{^}% \def\updn_suffix{:}% \ostrut \ifx\first_par\null_suffix \else \ifx\first_par\norm_suffix height\normht depth\normdp \else \ifx\first_par\flat_suffix height0mm depth0mm \ifspec_distender \global\let\begincell\beginflatcell \global\let\endcell\endflatcell \fi \else \ifx\first_par\up_suffix height\extraht depth\normdp \else \ifx\first_par\dn_suffix height\normht depth\extradp \else \ifx\first_par\updn_suffix height\extraht depth\extradp \else \gdef\next_tok{##1}% unrecognized token(s) will recirculate \fi\fi\fi\fi\fi\fi \relax \ifspec_distender \expandafter \aftergroup % put \next_tok in a next alignment cell \fi \next_tok} \let@\usecells \def~{\leavevmode\phantom{0}}% invisible digit (usually, all digits have % the same width) \defaultstrut \longcalculationtrue \cellmarg\defaultcellmarg % freeze a default value \everycr{\noalign{ \ifnum\cellnum>\maxcellnum \global\maxcellnum\cellnum\fi \global\let\begincell\defaultbegincell \global\let\endcell\defaultendcell \global\align_state0 }} \let\defaultbegincell\relax \let\defaultendcell\relax \tablerulecmyk{}% no color is specified \tablebkgcmyk{0 0 0 0}% background is white by default \the\everytable\relax \the\thistable\relax} \def\begintable_{\vbox\bgroup \global\let\begincell\defaultbegincell % \begincell and \endcell \global\let\endcell\defaultendcell % are always set globally, \global\let\currtfont\relax % \currtfont too % \currtfont was introduced in order to avoid global font assignments % as well as to avoid a premature expansion % of \currtfont in \begintableformat \global\maxcellnum0 \global\cellnum0 \global\mincellmarg\maxdimen \let\cellaction_\relax % protect against premature expansions \let\ori_par\par \let\par\empty % set to original meaning at the beginning of each vbox \everyvbox\expandafter{\the\everyvbox \let\par\ori_par} } \def\endtable_{\crcr\egroup\egroup} \def\begintableformat #1\endtableformat{\offinterlineskip \tabskip = 0pt \let\left\preambleleft \let\center\preamblecenter \let\right\preambleright \def"{&########&} \edef\tbl_form{####&####\cr} \let\left\tableleft \let\center\tablecenter \let\right\tableright \def"{\cellaction\relax} \xdef\currtfont{\the\font} \edef\leftcellside{\leftcellside} \edef\rightcellside{\leftcellside} \halign\bgroup\span\tbl_form} \def\begintable{\vbox\bgroup \table_setup \midtable} \long\def\midtable #1\endtable{% \def\curr_table{\begintable_#1\endtable_}\nospecanchors \edef\currhbadness{\the\hbadness}\edef\currvbadness{\the\vbadness}% \ifdim\desiredwidth>0mm \hbadness10000 \vbadness10000 \fi \setbox\table_box\hbox{\curr_table}% \ifdim\desiredwidth>0mm \fix_cellcorr % typesetset the table for the last time with the original badnesses \hbadness\currhbadness \vbadness\currvbadness \setbox\table_box\hbox{\curr_table}% \iflongcalculation \else \width_warning\fi \margin_warning \fi \xdef\tablewidth{\the\wd\table_box}% \xdef\tablecellcorr{\the\cellcorr}% \box\table_box \egroup \thistable{\relax}} \def\deftable#1\begintable{% #1 is expected to be a valid macro header, % preferably a csname; characters in the header have ``outer'' category % codes, i.e., not ``table'' category codes \begingroup \def\table_name{#1}\tableactive \expandafter \expandafter \expandafter \gdef \expandafter \table_name \deftablecont} \long\def\deftablecont#1\endtable{{#1}\endgroup} % ====================== PostScript (anchor) macros ======================= \def\beginanchtable{\vbox\bgroup \table_setup \midanchtable} \long\def\midanchtable #1\endanchtable{% \def\curr_table{% \gdef\useanchors{}% \useanchors is defined during typesetting a table \begintable_#1\endtable_}% \edef\currhbadness{\the\hbadness}\edef\currvbadness{\the\vbadness}% % at least two table settings are necessary with anchors, as \urfullanchor % needs to know the actual table width, hence the first setting is always % temporary; if a short calculation option holds, after fixing the % cell correction the table must be set once again, for the same reason \hbadness10000 \vbadness10000 \setbox\table_box\hbox{\curr_table}% \hbox{% \ifdim\desiredwidth>0mm \fix_cellcorr \iflongcalculation \else \setbox\table_box\hbox{\curr_table}% see the previous comment \fi \fi % typesetset the table for the last time with the original badnesses \hbadness\currhbadness \vbadness\currvbadness \setbox\table_box\hbox{\curr_table}% \ifdim\desiredwidth>0mm \iflongcalculation \else \width_warning\fi \margin_warning \fi \xdef\tablewidth{\the\wd\table_box}% \xdef\tablecellcorr{\the\cellcorr}% \tbkg_patch\table_box % \useanchors is now defined, it will expand to commands that use anchors \hbadness\currhbadness \vbadness\currvbadness \useanchors \nospecanchors \llap{\curr_table}% }% \egroup \thistable{\relax}} % --- \def\tbkg_patch#1{% \tbkg_patch puts a color patch (background) on the top % of a table given by #1; #1 is a csname of a table box; hmode is on. \speccastat {-\tablebkgcorr}{-\tablebkgcorr}{\specurcast\tbkgsuffix{\wd#1}{\ht#1}}% \speccastat {\tablebkgcorr}{\tablebkgcorr}{\specllcast\tbkgsuffix{0mm}{-\dp#1}}% \box#1% cast anchors while typesetting table #1 \dotbkpatch % erase table; it seems better to use rather anchors than rules, % as rules spoil ``classic'' previewing; patching was introduced % in order to avoid the ``diffusion'' of a table contents % (1 pixel?). If you don't care, or you use high resolution, % you may wish to define \dotbkpatch as an empty command. } \def\tbkgsuffix{TbKg.SuF}% a suffix unlikely to be used by chance % \tbkgsuffix, \tablebkgcorr, and \dotbkpatch can be virtualy % exploited by a user, hence ``plain'' csnames were used; table background % colour is most likely to be used by a user, hence it is set in \table_setup \def\tablebkgcmyk#1{\def\thetablebkgcmyk{#1}}% set table background colour \def\tablebkgcorr{0mm}% tiny correction of the position of the corners % of the table background \def\dotbkpatch{\specrect\tbkgsuffix\thetablebkgcmyk} % --- \def\nospecanchors{% \def\expa_expa_##1##2##3##4{\gdef\useanchors{}}% \def\speccastat##1##2##3{}% % \def\specrect##1##2{}% % \def\specdiagboth##1##2##3{}% % \def\specdiagdown##1##2##3{}% % \def\specdiagup##1##2##3{}% % \def\spectrianne##1##2{}% % \def\spectriannw##1##2{}% % \def\spectrianse##1##2{}% % \def\spectriansw##1##2{}% } % --- \def\expa_expa_#1#2#3#4{% % #1 -- \def or \gdef, #2, #3, #4 -- csnames % performs #1#2{#3#4}, #3 and #4 expanded once; % e.g., given \def\pp{ALA} \def\qq{BELA}, % \expa_expa_\def\pp\pp\qq defines \pp as a macro {ALABELA} \expandafter\expandafter\expandafter#1% \expandafter\expandafter\expandafter#2% \expandafter\expandafter\expandafter{% \expandafter#3#4}} % {\catcode`\p12 \catcode`\t12 \gdef\gobblePT#1pt{#1}} \def\dimval#1{\expandafter\gobblePT\the#1} % \def\rectfill#1#2{% \noalign{ \edef\useanchors_{\noexpand\specrect{#2}{#1}} \expa_expa_\gdef\useanchors\useanchors\useanchors_ }} \def\trianfill#1#{\noalign\bgroup\lowercase{\def\trian_dir{#1}}\trianfill_} \def\trianfill_#1#2{% \edef\useanchors_{% \noexpand\csname pstrian\trian_dir \noexpand\endcsname{#2}{#1}}% \expa_expa_\gdef\useanchors\useanchors\useanchors_ \egroup} % \newdimen\pen_wd \def\diagstroke{\noalign\bgroup\afterassignment\diagstroke_\pen_wd} \def\diagstroke_#1#{\lowercase{\def\diag_dir{#1}}\diagstroke__} \def\diagstroke__#1#2{% \edef\useanchors_{% \noexpand\csname psdiag\diag_dir \noexpand\endcsname {#2}{#1}{\dimval\pen_wd}}% \expa_expa_\gdef\useanchors\useanchors\useanchors_ \egroup} % \expandafter\def\csname pstrianne \endcsname{\spectrianne} \expandafter\def\csname pstriannw \endcsname{\spectriannw} \expandafter\def\csname pstrianse \endcsname{\spectrianse} \expandafter\def\csname pstriansw \endcsname{\spectriansw} \expandafter\def\csname psdiagboth \endcsname{\specdiagboth} \expandafter\def\csname psdiagdown \endcsname{\specdiagdown} \expandafter\def\csname psdiagup \endcsname{\specdiagup} % --- \def\anchoffset{.5\trth}% by default depends on current rule thickness % --- \def\speccastat#1#2#3{% cast anything (presumably a \special command) % at a chosen position, not ignored in anchor tables % #1 -- xoffset, #2 -- yoffset, #3 -- contents, \vbox to0mm{\vss\hbox to0mm{\kern#1\relax#3\hss}\kern#2}} % --- \def\castat#1#2#3{% cast anything at a chosen position, never ignored % #1 -- xoffset, #2 -- yoffset, #3 -- contents, presumably a \special command \vbox to0mm{\vss\hbox to0mm{\kern#1\relax#3\hss}\kern#2}} % --- \def\specurcast#1#2#3{% cast upper right PostScript anchor % #1 -- suffix, #2 -- xoffset, #3 -- yoffset \speccastat{#2}{#3} {\special{ps: currentpoint /yur.#1 exch def /xur.#1 exch def}}} \def\specllcast#1#2#3{% cast lower left PostScript anchor % #1 -- suffix, #2 -- xoffset, #3 -- yoffset \speccastat{#2}{#3} {\special{ps: currentpoint /yll.#1 exch def /xll.#1 exch def}}} \def\specdiagboth#1#2#3{% % #1 index (suffix) of lower left and upper right corners (anchors) % #2 cmyk coordinates % #3 pen width in points, only the number (pt gobbled by, e.g., \dimval) \edef\cmyk_{#2}% \special{ps: gsave newpath \ifx\cmyk_\empty\else #2 setcmykcolor \fi #3 72.27 div Resolution mul setlinewidth 1 setlinecap xll.#1 yll.#1 moveto xur.#1 yur.#1 lineto stroke xll.#1 yur.#1 moveto xur.#1 yll.#1 lineto stroke grestore}} \def\specdiagdown#1#2#3{% % #1 index (suffix) of lower left and upper right corners (anchors) % #2 cmyk coordinates % #3 pen width in points, only the number (pt gobbled by, e.g., \dimval) \edef\cmyk_{#2}% \special{ps: gsave newpath \ifx\cmyk_\empty\else #2 setcmykcolor \fi #3 72.27 div Resolution mul setlinewidth 1 setlinecap xll.#1 yur.#1 moveto xur.#1 yll.#1 lineto stroke grestore}} \def\specdiagup#1#2#3{% % #1 index (suffix) of lower left and upper right corners (anchors) % #2 cmyk coordinates % #3 pen width in points, only the number (pt gobbled by, e.g., \dimval) \edef\cmyk_{#2}% \special{ps: gsave newpath \ifx\cmyk_\empty\else #2 setcmykcolor \fi #3 72.27 div Resolution mul setlinewidth 1 setlinecap xll.#1 yll.#1 moveto xur.#1 yur.#1 lineto stroke grestore}} \def\specrect#1#2{% % #1 index (suffix) of lower left and upper right corners (anchors) % #2 cmyk coordinates \edef\cmyk_{#2}% \special{ps: gsave newpath \ifx\cmyk_\empty\else #2 setcmykcolor \fi xll.#1 yll.#1 moveto xur.#1 yll.#1 lineto xur.#1 yur.#1 lineto xll.#1 yur.#1 lineto closepath fill grestore}} \def\spectrianne#1#2{% % #1 index (suffix) of lower left and upper right corners (anchors) % #2 cmyk coordinates \edef\cmyk_{#2}% \special{ps: gsave newpath \ifx\cmyk_\empty\else #2 setcmykcolor \fi xll.#1 yur.#1 moveto xur.#1 yll.#1 lineto xur.#1 yur.#1 lineto closepath fill grestore}} \def\spectriannw#1#2{% % #1 index (suffix) of lower left and upper right corners (anchors) % #2 cmyk coordinates \edef\cmyk_{#2}% \special{ps: gsave newpath \ifx\cmyk_\empty\else #2 setcmykcolor \fi xll.#1 yll.#1 moveto xur.#1 yur.#1 lineto xll.#1 yur.#1 lineto closepath fill grestore}} \def\spectrianse#1#2{% % #1 index (suffix) of lower left and upper right corners (anchors) % #2 cmyk coordinates \edef\cmyk_{#2}% \special{ps: gsave newpath \ifx\cmyk_\empty\else #2 setcmykcolor \fi xll.#1 yll.#1 moveto xur.#1 yll.#1 lineto xur.#1 yur.#1 lineto closepath fill grestore}} \def\spectriansw#1#2{% % #1 index (suffix) of lower left and upper right corners (anchors) % #2 cmyk coordinates \edef\cmyk_{#2}% \special{ps: gsave newpath \ifx\cmyk_\empty\else #2 setcmykcolor \fi xll.#1 yll.#1 moveto xur.#1 yll.#1 lineto xll.#1 yur.#1 lineto closepath fill grestore}} \newcount\col_num \newtoks\col_tok \def\uranchor{\noalign\bgroup \afterassignment\uranchor_ \global\col_num} \def\uranchor_{% \global\advance\col_num-1\relax \ifnum\col_num<0 \global\let\uranchor__\urfullanchor \else \global\let\uranchor__\urcellanchor \fi \egroup \uranchor__} \def\llanchor{\noalign\bgroup \afterassignment\llanchor_ \global\col_num} \def\llanchor_{% \global\advance\col_num-1\relax \ifnum\col_num<0 \global\let\llanchor__\llfullanchor \else \global\let\llanchor__\llcellanchor \fi \egroup \llanchor__} \def\urfullanchor#1{% \wd\table_box is set by \midanchtable \br{\speccastat{\wd\table_box}{0mm} {\specurcast{#1}{-\anchoffset}{\anchoffset}}}% \er{}} \def\llfullanchor#1{% \br{\speccastat{0mm}{0mm}{\specllcast{#1}{\anchoffset}{-\anchoffset}}}% \er{}} \def\urcellanchor#1{% \br{} \col_tok{}% \loop \ifnum\col_num>0 \global\advance\col_num-1 \col_tok\expandafter{\the\col_tok"}% \repeat \the\col_tok \hskip0ptplus1filll \speccastat {\ifignorecellstate 1\else\ifcase\cellstate 2\or 1\or 0\fi\fi \cellcorr}{0mm} {\speccastat {\cellmarg}{0mm}{\specurcast{#1}{\anchoffset}{\anchoffset}}% }% \er{}} \def\llcellanchor#1{% \br{} \loop \ifnum\col_num>0 \global\advance\col_num-1 \col_tok\expandafter{\the\col_tok"}% \repeat \the\col_tok \speccastat {-\ifignorecellstate 1\else\ifcase\cellstate 2\or 1\or 0\fi\fi \cellcorr}{0mm} {\speccastat {-\cellmarg}{0mm}{\specllcast{#1}{-\anchoffset}{-\anchoffset}}% }% \hskip0ptplus1filll\null \er{}} % ====== ``floating point arithmetic'' (excerpted from T. Rokicki): ======= % % ^ r y % | % | % | % | % 0-----------> t x % \def\resize % dimen registers: #1% y make y such that y/r=x/t #2% r #3% x #4% t % We have a sticky problem here: TeX doesn't do floating point arithmetic! % Our goal is to compute y = rx/t. The following loop does this reasonably % fast, with an error of at most about 16 sp (about 1/4000 pt). {% % save parameters to the internal variables: \dim_r#2\relax \dim_x#3\relax \dim_t#4\relax \dim_tmp=\dim_r \divide\dim_tmp\dim_t \dim_y=\dim_x \multiply\dim_y\dim_tmp \multiply\dim_tmp\dim_t \advance\dim_r-\dim_tmp \dim_tmp=\dim_x \loop \advance\dim_r\dim_r \divide\dim_tmp 2 \ifnum\dim_tmp>0 \ifnum\dim_r<\dim_t\else \advance\dim_r-\dim_t \advance\dim_y\dim_tmp \fi \repeat % assign result: #1\dim_y\relax} % \newdimen\dim_x % horizontal size after scaling \newdimen\dim_y % vertical size after scaling \newdimen\dim_t % horizontal size before scaling \newdimen\dim_r % vertical size before scaling \newdimen\dim_tmp % register for arithmetic manipulation % ============================== Postamble ================================ \catcode`\"\dblquotecatcode \catcode`\|\brokenbarcatcode \catcode`\!\exclamcatcode \catcode`\_=\undscorecatcode \catcode`\@=\atcatcode \endinput