.ig

hdtbl.tmac

This file is part of groff, the GNU roff type-setting system.

Copyright (C) 2005-2020 Free Software Foundation, Inc.
written by Joachim Walsdorff <Joachim.Walsdorff@urz.uni-heidelberg.de>.

groff is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or
(at your option) any later version.

groff is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

..
.
.
.\"	*****************************************************************
.\"	*		hdtbl - Heidelberger table macros		*
.\"	*			Vers. 0.91 December 2005		*
.\"	*****************************************************************
.
.if d TBL \
.  nx
.
.mso hdmisc.tmac
.mso 62bit.tmac
.
.
.\"	*****************************************************************
.\"	*		default values for some arguments		*
.\"	*****************************************************************
.
.ds t*hl s\"
.ds t*vl s\"
.ds t*tal l\"
.ds t*hal b\"
.ds t*val t\"
.ds t*ff \\n[.fam]\"
.ds t*fst \\n[.f]\"
.ds t*fsz 1 1\"
.ds t*fgc red4\"
.ds t*bgc bisque\"
.ds t*bc red4\"
.nr t*cpd .5n
.nr t*csp .5n
.nr t*b .1n
.nr t*cols 1
.nr t*v \n[.v]
.nr t*s \n[.ps]
.nr t*hy \n[.hy]
.nr t*l \n[.ll]
.
.
.\"			defaults for table captions
.nr t*cptn 0 1
.ds t*cptn "".sp .4" \
            ".t*pv 1.0 1.0" \
            ".ad l" \
            "\m[\\*[t*fgc]]Table \\n+[t*cptn]:\0\k*\c"\"
.
.
.\" for better error messages
.ds nth-1 st\"
.ds nth-2 nd\"
.ds nth-3 rd\"
.
.\" initialization of various registers
.nr t*# 0	\"	table nesting level
.nr t*numb 0 1	\"	held table diversion #
.
.ds *#trc*
.
.
.\"	*****************************************************************
.\"	*	The four base macros and the two optional macros	*
.\"	*****************************************************************
.
.ie n \
.  ds g tty:\"
.el \
.  ds g ps: exec\"
.
.\"	TBL:	table start
.\"		predecessor: 	text, TD or ETB
.\"		successor:	CPTN or TR
.de TBL
.  ds t*m\\n[t*#] \\n[.m]\"
.  ie \\n[t*#] \
.    br
.  el \{\
.    ds * \\n[.ev]\"
.    ev t*tbl
.    evc \\*[*]
.    di t*tbl0
.    sp .4				\" XXX: hard-coded value
.    nr t*i \\n[.i]
.    ll -\\n[.i]u
.    in 0
.  \}
.  nr t*# +1
.
.  \" Save current location for error checking at end
.  ds t*FN \\[.F]\"
.  ds t*LN \\[.c]\"
.
.  t*getarg cols \\$@\"	from here string 'args' contains the rest of \\$@
.  ie "\\*[cols]"" \
.    nr t*cols\\n[t*#] \\n[t*cols]
.  el \{\
.    ie \B\\*[cols] \
.      nr t*cols\\n[t*#] \\*[cols]
.    el \
.      tm \\n[.F]:\\n[.c]: Invalid number of columns value '\\*[cols]'.
.  \}
.
.  t*getarg cpd \\*[args]                 \"	cell padding
.  ie "\\*[cpd]"" \
.    nr t*cpd\\n[t*#] \\n[t*cpd]
.  el \{\
.    ie \B\\*[cpd] \
.      nr t*cpd\\n[t*#] \\*[cpd]
.    el \
.      tm \\n[.F]:\\n[.c]: Invalid cell padding value '\\*[cpd]'.
.  \}
.
.  t*getarg csp \\*[args]                 \"	cell spacing
.  ie "\\*[csp]"" \
.    nr t*csp\\n[t*#] \\n[t*csp]
.  el \{\
.    ie \B\\*[csp] \
.      nr t*csp\\n[t*#] \\*[csp]
.    el \
.      tm \\n[.F]:\\n[.c]: Invalid cell spacing value '\\*[csp]'.
.  \}
.
.  t*getarg border \\*[args]              \"	border thickness
.  ie "\\*[border]"=" \
.    nr t*b\\n[t*#] 0-1
.  el \{\
.    ie "\\*[border]"" \
.      nr t*b\\n[t*#] \\n[t*b]
.    el \{\
.      ie \B\\*[border] \
.        nr t*b\\n[t*#] \\*[border]
.      el \
.        tm \\n[.F]:\\n[.c]: Invalid border thickness value '\\*[border]'.
.  \}\}
.
.  t*getarg bc \\*[args]                  \"	border color
.  ds t*bc\\n[t*#] \\*[t*bc]\"
.  if !"\\*[bc]"" \{\
.    ie m\\*[bc] \
.      ds t*bc\\n[t*#] \\*[bc]\"
.    el \{\
.      ie "\\*[bc]"=" \
.        ds t*bc\\n[t*#] =\"
.      el \
.        tm \\n[.F]:\\n[.c]: Invalid border color '\\*[bc]'.
.  \}\}
.  ie "\\*[bc]"=" \
.    ds t*bc\\n[t*#]
.  el \{\
.    ie "\\*[bc]"" \
.      ds t*bc\\n[t*#] \\*[t*bc]\"
.    el \
.      ds t*bc\\n[t*#] \\*[bc]\"
.  \}
.
.  t*getarg width \\*[args]               \"	table/col widths
.  if "\\*[width]"=" \
.    ds width
.
.  nr b/2\\n[t*#] (\\n[t*b\\n[t*#]] / 2)\"	shortcut
.  nr cscp\\n[t*#] (\\n[t*csp\\n[t*#]] + \\n[t*cpd\\n[t*#]])\"  aux. register
.
.  t*getarg height \\*[args]              \"	table outline height
.  ie "\\*[height]"" \
.    nr t*height\\n[t*#] 0
.  el \{\
.    ie \B\\*[height] \
.      nr t*height\\n[t*#] (\\*[height] \
                            - ((2 * \\n[cscp\\n[t*#]]) \
                                + (3 * \\n[b/2\\n[t*#]])))
.    el \
.      tm \\n[.F]:\\n[.c]: Invalid height value '\\*[height]'.
.  \}
.
.  t*cl \\*[width]                      \"	get cell widths and offsets
.  t*args \\n[t*#]                      \"	look for common arguments
.
.  t*getarg tal \\*[args]                 \"	table horizontal alignment
.  if "\\*[tal]"" \
.    ds tal \\*[t*tal]\"
.  ie "\\*[tal]"l" \
.    nr in\\n[t*#] \\n[.i]
.  el \{\
.    ie "\\*[tal]"c" \
.      nr in\\n[t*#] (\\n[.l] - \\n[ll\\n[t*#]]/2 + \\n[.i])
.    el \{\
.      ie "\\*[tal]"r" \
.        nr in\\n[t*#] (\\n[.l] - \\n[ll\\n[t*#]] + \\n[.i])
.      el \{\
.        tmc \\n[.F]:\\n[.c]: Invalid horizontal table alignment '\\*[tal]':
.        tm1 " must be 'l', 'c' or 'r'.
.  \}\}\}
.
.  nr t*r#\\n[t*#] 0		        \"	initialize row index
.  mk toptbl\\n[t*#]
.
.  t*P1 \\*[args]
..
.
.
.\"	CPTN:	optional table caption
.\"		predecessor:	TBL
.\"		successor:	TR
.de CPTN
.  ft 1
.
.  if "\\$0"CPTN" \
.    if \\n[t*r#\\n[t*#]] \{\
.      tmc \\n[.F]:\\n[.c]: Invalid placement of '.CPTN';
.      tm1 " must be called immediately after '.TBL'.
.      return
.    \}
.
.  t*getarg val \\$@
.  ds args\\n[t*#] "\\*[args]\"
.
.  t*index "\\*[args]" .TR
.  ie \\n[t*index] \{\
.    ds *a\\n[t*#] "\\*[args]\"
.    substring args\\n[t*#] 0 \\n[t*index]
.    substring *a\\n[t*#] \\n[t*index]-2 -1
.  \}
.  el \
.    ds *a\\n[t*#]
.
.  ie "\\*[val]"b" \{\
.    de t*cptn\\n[t*#]
.      *CPTN \\*[args\\n[t*#]]
.      rm t*cptn\\n[t*#]
\\..
.  \}
.  el \{\
.    ll (\\n[ll\\n[t*#]]u + \\n[in\\n[t*#]]u)
.    in \\n[in\\n[t*#]]u
.    t*P1 \\*[t*cptn]
'    in +\\n[*]u
.    t*P1 \\*[args\\n[t*#]]
.    t*pv 1 1
.    in
.    mk toptbl\\n[t*#]
.  \}
.
.  t*P1 \\*[*a\\n[t*#]]
..
.
.als *CPTN CPTN
.
.
.\"	TR:	table row
.\"		predecessor:	TBL, CPTN, text, TD or ETB
.\"		successor:	TD
.de TR
.  ft 1
.  if !\\n[t*#] \{\
.    tm \\n[.F]:\\n[.c]: Table row (.TR) without preceding table start (.TBL).
.    return
.  \}
.
.  \" finish previous data cell, if any
.  if \\n[t*r#\\n[t*#]] \
.    t*dntr 1 \\n[c#\\*[#t#r]] \\n[t*cols\\n[t*#]] \\*[*#trc*]
.
.  nr t*r#\\n[t*#] +1			\"	row number in this table
.  ds #t#r \\n[t*#]*\\n[t*r#\\n[t*#]]\"		table row identifier
.					\"	(<level>*<row>)
.  nr c#\\*[#t#r] 0 1			\"	clear cell counter
.  nr dntr\\*[#t#r] 0 1			\"	clear accumulated row height
.
.  t*getarg height \\$@
.  ie "\\*[height]"" \
.    nr t*height\\*[#t#r] 0
.  el \{\
.    ie \B\\*[height] \
.      nr t*height\\*[#t#r] \\*[height]
.    el \
.      tm \\n[.F]:\\n[.c]: Invalid table row height '\\*[height]'.
.  \}
.
.  \"	If there is a TR with height 'height', the total height of the table
.  \"	is too high by 3/2 b, independent of the number of TR with 'height'.
.  t*args \\*[#t#r] \\n[t*#]            \"	look for common arguments
.
.  t*P1 \\*[args]
..
.
.
.\"	TH:	optional table header cell
.\"		predecessor:	text, TD or TR
.\"		successor:	text, TD, TR, TBL or ETB
.\"								
.\"		cell content bolded and horizontally and vertically centered,
.\"		else like .TD
.de TH
.  ft 1
.  t*getarg hal \\$@
.  if "\\*[hal]"" \
.    ds hal c\"
.
.  t*getarg val \\*[args]
.  if "\\*[val]"" \
.    ds val m\"
.
.  t*getarg fst \\*[args]
.  if "\\*[fst]"" \
.    ds fst B\"
.
.  TD hal=\\*[hal] val=\\*[val] fst=\\*[fst] \\*[args]
..
.
.
.\"	TD:	table data cell
.\"		predecessor:	text, TD or TR
.\"		successor:	text, TD, TR, TBL or ETB
.de TD
.  ft 1
.  \" finish previous data cell -- note the use of \E
.  t*dntr 0 \\n[c#\\*[#t#r]]-1 \En[c#\\*[#t#r]] \\*[*#trc*]
.
.  ds *#trc* \\*[#t#r]*\\n[c#\\*[#t#r]]\"	table cell identifier
.					\"	(<level>*<row>*<column>)
.
.  t*getarg rowspan \\$@
.  nr rowspan 1
.  if !"\\*[rowspan]"" \{\
.    ie \B\\*[rowspan] \{\
.      nr rowspan (\\*[rowspan] >? 1)
.      nr *rsp*\\*[*#trc*] (\\n[rowspan] - 1)
.    \}
.    el \
.      tm \\n[.F]:\\n[.c]: Invalid value of 'rowspan' keyword.
.  \}
.
.  t*getarg colspan \\*[args]
.  nr colspan 1
.  if !"\\*[colspan]"" \{\
.    ie \B\\*[colspan] \
.      nr colspan (\\*[colspan] >? 1)
.    el \
.      tm \\n[.F]:\\n[.c]: Invalid value of 'colspan' keyword.
.  \}
.
.  t*args \\*[#trc] \\*[#t#r]           \"  look for common arguments
.
.  nr in\\*[#trc] \\n[in\\n[t*#]*\\n[c#\\*[#t#r]]]
.  nr *cl \\n[cll\\n[t*#]*\\n[c#\\*[#t#r]]]
.  nr * 0 1
.  nr *r \\n[t*r#\\n[t*#]]
.
.  if (\\n[rowspan] - 1) \
.    while (\\n+[*] <= \\n[rowspan]) \{\
.      nr rspan\\n[t*#]*\\n[*r]*\\n[c#\\*[#t#r]] \\n[colspan]
.      if (\\n[*] > 1) \
.        nr cspan\\n[t*#]*\\n[*r]*\\n[c#\\*[#t#r]] \\n[colspan]
.      nr *r +1
.    \}
.
.  nr * 1 1
.  nr *c \\n[c#\\*[#t#r]]
.
.  if (\\n[colspan] - 1) \{\
.    nr vline\\*[*#trc*] 0-1		\"	set 'no vl' flag
.
.    while (\\n+[*] <= \\n[colspan]) \{\
.      nr *c +1
.      nr *cl +(2 * \\n[cscp\\n[t*#]] \
                + \\n[b/2\\n[t*#]] \
                + \\n[cll\\n[t*#]*\\n[*c]])
.      nr c#\\*[#t#r] +1
.    \}
.  \}
.
.  if (\\n[c#\\n[t*#]*\\n[t*r#\\n[t*#]]] > \\n[t*cols\\n[t*#]]) \{\
.    ds * are\"
.    ds ** columns\"
.    if (\\n[c#\\*[#t#r]] == 1) \{\
.      ds * is\"
.      ds ** column\"
.    \}
.    tmc \\n[.F]:\\n[.c]: There \\*[*] \\n[c#\\*[#t#r]] table \\*[**] (.TD)
.
.    ds * are\"
.    if (\\n[t*cols\\n[t*#]] == 1) \
.      ds * is\"
.    tm1 " but only \\n[t*cols\\n[t*#]] \\*[*] expected.
.
.    ds *
.    length * \\n[.F]:\\n[.c]:
.
.    while \\n-[*] \
.      ds * " \\*[*]\"
.
.    tm1 "\\*[*] Remaining .TDs and its contents are ignored.
.
.    di *t*dummy*                \"	bypass superfluous input
.    return
.  \}
.
.  di t*\\*[#trc]                \"	open cell diversion and set locals
.  in 0
.  nr cll\\*[#trc] \\n[*cl]
.  ll \\n[*cl]u
.  nr *cl\\n[t*#] \\n[.l]
.  gcolor \\*[t*fgc\\*[#trc]]
.  ad \\*[t*hal\\*[#trc]]
.  fam \\*[t*ff\\*[#trc]]
.  ft \\*[t*fst\\*[#trc]]
.  t*pv \\*[t*fsz\\*[#trc]]
.
.  t*P1 \\*[args]
..
.
.
.\"	ETB:	end of table
.\"		predecessor:	text, TD or ETB
.\"		successor:	text, TD, TR or TBL
.de ETB
.  ie \\n[t*#] \
.    if !\\n[t*r#\\n[t*#]] \{\
.      tmc \\n[.F]:\\n[.c]: Each table (.TBL)
.      tm1 " should contain at least one table row (.TR)!
.    \}
.  el \{\
.    tmc \\n[.F]:\\n[.c]: Table end (.ETB)
.    tm1 " without corresponding table start (.TBL)!
.  \}
.
.  ds #t#r \\n[t*#]*\\n[t*r#\\n[t*#]]\"		refresh table row identifier
.  t*dntr 2 \\n[c#\\*[#t#r]] \\n[t*cols\\n[t*#]] \\*[*#trc*]
.
.  t*divs                        \"	print this table
.
.  sp \\n[b/2\\n[t*#]]u
.  t*cptn\\n[t*#]
.  nr t*# -1
.
.  ll \\n[*cl\\n[t*#]]u          \"	restore ll outside this table
.  in 0                          \"	reset indent
.  gcolor \\*[t*m\\n[t*#]]       \"	reset previous fgc
.
.  t*getarg hold \\$@
.  if !\\n[t*#] \{\
.    sp .5
.    di
.    in \\n[t*i]u
.    ie "\\*[hold]"" \{\
.      ie (\\n[.t] - \\n[dn]) \
.        t*DI t*tbl0
.      el \{\
.        rn t*tbl0 t*tbl\\n+[t*numb]
.        ds t*kept \\*[t*kept] t*tbl\\n[t*numb] \\n[dn]\"
.      \}
.    \}
.    el \{\
.      rn t*tbl0 t*hold\\n+[t*numb]
.      tm \\n[.F]:\\n[.c]: Table t*hold\\n[t*numb] held.
.      ds t*held \\*[t*held] t*hold\\n[t*numb] \\n[dn]\"
.    \}
.
.    ev				\"	restore previous environment
.  \}
.
.  t*P1 \\*[args]
..
.
.
.\"	*****************************************************************
.\"	*	Following the definition of five utility macros		*
.\"	*	special to hdtbl.					*
.\"	*	Other utility macros common to hdtbl and hdgroff	*
.\"	*	are defined in the file hdmisc.tmac.			*
.\"	*****************************************************************
.
.
.\"	.t*free [n]
.\"		print the next [n] held table[s].
.\"             Don't call it within a table!
.\"		If the table is higher than the remaining space
.\"		on the page, the table is printed on the next page.
.de t*free
.  if "\\$0"CPTN" \
.    if \\n[t*r#\\n[t*#]] \{\
.      tmc \\n[.F]:\\n[.c]: Invalid placement of '.t*free' within a table;
.      tm1 " it must be called outside of any table.
.      return
.    \}
.
.  if "\\*[t*held]"" \{\
.    tm \\n[.F]:\\n[.c]: No held tables.
.    return
.  \}
.
.  nr ** (\\$1 >? 1) 1
.  while !""\\*[t*held]" \{\
.    pops * t*held
.    popr * t*held
.
.    ie (\\n[.t] - \\n[*]) \{\
.      ev t*tbl
.      t*DI \\*[*]
.      ev
.    \}
.    el \{\
.      rn \\*[*] t*tbl\\n+[t*numb]
.      ds t*kept \\*[t*kept] t*tbl\\n[t*numb] \\n[*]\"
.    \}
.
.    if !(\\n-[**] - 1) \
.      return
.  \}
..
.
.
.\"	The main utility macro for tables:
.\"		If a table is closed by ETB, this macro is called.  It
.\"		processes one complete table, i.e., all the table cell
.\"		diversions, paints the cell backgrounds, draws
.\"		horizontal and vertical table lines and the table border.
.\"
.\"		Nested tables are processed from inside to outside.
.
.de t*divs
.  ll (\\n[t*l]u + 1c)			\"	avoid warning 'can't break line'
.  nf
.
.  nr b/2 \\n[b/2\\n[t*#]]		\"	some abbreviations
.  nr cscp \\n[cscp\\n[t*#]]
.  nr cscpb (\\n[b/2] + \\n[cscp])
.
.  nr topdiv (\\n[.d] + \\n[b/2] - \\n[cscp])\"	top of cell diversion
.  nr cscpb2 (\\n[b/2] / 2 + \\n[cscp])
.
.  nr #r 0 1
.  \" outer loop for rows
.  while (\\n+[#r] <= \\n[t*r#\\n[t*#]]) \{\
.    \" TODO: insert code here for multipage tables
.    nr * (\\n[#r] - 1)
.    nr topdiv +(\\n[dntr\\n[t*#]*\\n[*]] + \\n[cscp] + \\n[cscpb])
.
.    \" if table still smaller than specified table height, increase it
.    if ((\\n[#r] == \\n[t*r#\\n[t*#]]) & \\n[t*height\\n[t*#]]) \
.      nr dntr\\n[t*#]*\\n[#r] (\\n[cscpb] \
                                + \\n[toptbl\\n[t*#]] \
                                + \\n[t*height\\n[t*#]] \
                                - (\\n[topdiv] >? \\n[dntr\\n[t*#]*\\n[#r]]))
.
.    nr #c 0 1
.    \" inner loop for cells
.    while (\\n+[#c] <= \\n[t*cols\\n[t*#]]) \{\
.      ds #trc \\n[t*#]*\\n[#r]*\\n[#c]\"
.      \" continue if the diversion is empty
.      if !d t*\\*[#trc] \
.        continue
.
.      sp |\\n[topdiv]u
.      in (\\n[in\\n[t*#]]u + \\n[in\\*[#trc]]u)\"	cell offset
.      nr $1 \\n[dntr\\n[t*#]*\\n[#r]]	\"	cell height
.
.      \" if we have spanned rows, calculate resulting row height
.      \" and position of lower horizontal line
.      if \\n[*rsp*\\*[#trc]] \{\
.        nr * \\n[#r] 1
.        nr rspan\\*[#trc] 0-1		\"	set 'no hl' flag
.        nr corr (\\n[dn\\*[#trc]] - \\n[dntr\\n[t*#]*\\n[#r]])
.
.        \" clear row span flags in following rows and update row height
.        while \\n[*rsp*\\*[#trc]] \{\
.          nr *rsp*\\*[#trc] -1
.          nr rspan\\n[t*#]*\\n+[*]*\\n[#c] 0
.          nr ** (\\n[dntr\\n[t*#]*\\n[*]] + \\n[cscp] + \\n[cscpb])
.          nr corr -\\n[**]
.          nr $1 +\\n[**]
.        \}
.
.        if (\\n-[*] == \\n[t*r#\\n[t*#]]) \
.          nr $1 ((\\n[t*height\\n[t*#]] \
                   - \\n[.d] \
                   + \\n[toptbl\\n[t*#]] \
                   + \\n[cscpb]) \
                     >? \\n[$1])
.        nr dntr\\n[t*#]*\\n[*] +(\\n[corr] >? 0)
.      \}
.
.      \" paint cell background
.      nr * (2 * \\n[t*cpd\\n[t*#]] + \\n[cll\\*[#trc]])\"	background width
.      nr $1 (\\n[$1] >? \\n[dn\\*[#trc]])\"	cell height
.
.      if !"\\*[t*bgc\\*[#trc]]"=" \{\
.        nop \h'\\n[t*csp\\n[t*#]]u'\
\M[\\*[t*bgc\\*[#trc]]]\
\v'(-.67v - \\n[t*cpd\\n[t*#]]u)'\
\D'P \\n[*]u 0 \
     0 (2u * \\n[t*cpd\\n[t*#]]u + \\n[$1]u) \
     -\\n[*]u 0'\
\M[]
.        sp -1
.      \}
.
.      \" ***   horizontal and vertical single or double lines   ***
.      \" double and single lines have the same thickness;
.      \" the double lines' distance is the line thickness.
.      \"
.      \" 'border=x': horizontal/vertical lines x/2 thick, minimum .1n
.      \" 'border=0': no border; horizontal/vertical lines .1n thick
.      \" 'border=': neither border nor horizontal/vertical lines
.
.      nr *t (.1n >? \\n[b/2])		\"	thickness of hl/vl; min. .1n
.      in +\\n[cscp]u
.
.      \" check for vertical and horizontal lines
.      if (1 + \\n[t*b\\n[t*#]]) \{\
.        if !"\\*[t*bc\\n[t*#]]"=" \{\
.          \" draw horizontal line between this cell and the one below
.          if (\\n[t*r#\\n[t*#]] - \\n[#r] + \\n[rspan\\*[#trc]]) \{\
.            if !"\\*[t*hl\\*[#trc]]"=" \{\
.              sp \\n[$1]u
.              nr * (\\n[cscp] + \\n[cscpb] + \\n[cll\\*[#trc]])
.              nop \X'\*[g] 1 setlinecap'\
\h'(-\\n[cscpb2]u - \\n[*t]u)'\
\v'(\\n[cscpb2]u - .67v)'\
\m[\\*[t*bc\\n[t*#]]]\
\D't \\n[*t]u'\c
.
.              ie "\\*[t*hl\\*[#trc]]"d" \
.                nop \v'-\\n[*t]u'\
\D'l \\n[*]u 0'\
\v'(2u * \\n[*t]u)'\
\D'l -\\n[*]u 0'\
\D't 0'
.              el \
.                nop \D'l \\n[*]u 0'\
\D't 0'
.
.              sp (-\\n[$1]u - 1v)
.          \}\}
.
.          nr rspan\\*[#trc] 0
.
.          \" draw vertical line between this cell and the one to the right
.          if (\\n[t*cols\\n[t*#]] - \\n[#c] + \\n[vline\\*[#trc]]) \{\
.            if !"\\*[t*vl\\*[#trc]]"=" \{\
.              nop \X'\*[g] 1 setlinecap'\
\v'(-\\n[cscpb2]u - .67v)'\
\m[\\*[t*bc\\n[t*#]]]\
\h'(\\n[cscpb2]u - \\n[*t]u + \\n[cll\\*[#trc]]u)'\c
.
.              ie "\\*[t*vl\\*[#trc]]"d" \
.                nop \h'-\\n[*t]u'\
\D't \\n[*t]u'\
\D'l 0 (2u * \\n[cscp]u + \\n[$1]u + (\\n[*t]u / 2u))'\
\h'(2u * \\n[*t]u)'\
\D'l 0 -(2u * \\n[cscp]u + \\n[$1]u + (\\n[*t]u / 2u))'\
\D't 0'
.              el \
.                nop \D't \\n[*t]u'\
\D'l 0 (2u * \\n[cscp]u + \\n[$1]u + (\\n[*t]u / 2u))'\
\D't 0'
.              sp -1
.      \}\}\}\}
.
.      nr vline\\*[#trc] 0
.
.      \" vert. cell content alignment
.      nr ** 0
.
.      ie "\\*[t*val\\*[#trc]]"m" \
.        nr ** ((\\n[$1] - \\n[dn\\*[#trc]]) / 2)\"	val=m
.      el \
.        if "\\*[t*val\\*[#trc]]"b" \
.          nr ** (\\n[$1] - \\n[dn\\*[#trc]])\"	val=b
.
.      sp \\n[**]u			\"	vertical content position
.
.      \" finally output the diversion
.      t*\\*[#trc]
.      rm t*\\*[#trc]
.    \}
.  \}
.
.  \" draw the box border
.  in \\n[in\\n[t*#]]u
.  nr ** (\\n[topdiv] + \\n[dntr\\n[t*#]*\\n-[#r]])
.
.  if \\n[t*b\\n[t*#]] \{\
.    sp |(\\n[toptbl\\n[t*#]]u + \\n[b/2]u)
.    nr $1 (\\n[toptbl\\n[t*#]] - \\n[**] - \\n[cscp])
.    nr * (\\n[ll\\n[t*#]] - \\n[t*b\\n[t*#]])
.
.    if !"\\*[t*bc\\n[t*#]]"=" \
.      nop \X'\*[g] 0 setlinejoin 2 setlinecap'\
\v'-.67v'\
\h'-\\n[b/2]u'\
\m[\\*[t*bc\\n[t*#]]]\
\D't \\n[t*b\\n[t*#]]u'\
\D'l \\n[*]u 0'\
\D'l 0 -\\n[$1]u'\
\D'l -\\n[*]u 0'\
\D'l 0 \\n[$1]u'\
\D't 0'
.  \}
.
.  sp |(\\n[**]u + \\n[cscpb]u)
.  fi
..
.
.
.\"	Utility macro:	.t*cl [width1 [width2 [...]]]
.\"
.\"		Calculate cell widths, table width, and cell offsets.
.de t*cl
.  nr t*cols\\n[t*#] (\\n[.$] >? \\n[t*cols\\n[t*#]])
.  nr ll\\n[t*#] 0			\"	accumulated cell widths
.  nr ** (\\n[.l] / \\n[t*cols\\n[t*#]])\"	width for remaining cells
.  nr * 0 1				\"	counter
.
.  \" while-loop: Parse user arguments to get each cell's width.
.  while (\\n[t*cols\\n[t*#]] >= \\n+[*]) \{\
.    nr $\\n[*] \\n[**]
.    if !"\\$[\\n[*]]"" \{\
.      \" check for '%' pseudo scaling indicator
.      ds * \\$\\n[*]\"
.      substring * -1 -1
.      ie "\\*[*]"%" \{\
.        ds ** \\$[\\n[*]]\"
.        substring ** 0 -2
.        ie \B\\*[**] \
.          nr $\\n[*] (\\*[**] * \\n[.l] / 100)
.        el \
.          tm \\n[.F]:\\n[.c]: Invalid relative cell width '\\*[**]%'.
.      \}
.      el \{\
.        ie \B\\$[\\n[*]] \
.          nr $\\n[*] \\$[\\n[*]]
.        el \
.          tm \\n[.F]:\\n[.c]: Invalid cell width '\\$[\\n[*]]'.
.    \}\}
.
.    nr ll\\n[t*#] +\\n[$\\n[*]]
.    nr ** \\n[$\\n[*]]
.  \}
.
.  if (\\n[ll\\n[t*#]] > \\n[.l]) \
.    tm \\n[.F]:\\n[.c]: Table width larger than column width.
.
.  nr ** (0 >? \\n[t*b\\n[t*#]])
.  nr * 0 1
.
.  \" second while loop: Compute final cell widths.
.  while (\\n[t*cols\\n[t*#]] >= \\n+[*]) \{\
.    \" Remove border width, if any.
.    if \\n[t*b\\n[t*#]] \{\
.      \" cell_width := cell_width * (length - 1.5*border) / length
.      nr #* (\\n[ll\\n[t*#]] - (3 * \\n[t*b\\n[t*#]] / 2))
.      nr *** (\\n[ll\\n[t*#]] / 2)
.      \" avoid multiplication overflow
.      mult31by31 $\\n[*] #* ****
.      add31to62 *** **** ****
.      div62by31 **** ll\\n[t*#] $\\n[*]
.    \}
.
.    \" Get cell widths without padding, spacing, and separator line.
.    nr cll\\n[t*#]*\\n[*] (\\n[$\\n[*]] \
                            - (2 * \\n[cscp\\n[t*#]]) \
                            - \\n[b/2\\n[t*#]])
.
.    \" Check whether value is non-positive.
.    if !\\n[cll\\n[t*#]*\\n[*]] \{\
.      nr #* (\\n[ll\\n[t*#]] - (3 * \\n[t*b\\n[t*#]] / 2))
.      nr *** (\\n[#*] / 2)
.      nr *h (2 * \\n[cscp\\n[t*#]] + \\n[b/2\\n[t*#]])
.      mult31by31 *h ll\\n[t*#] ****
.      add31to62 *** **** ****
.      div62by31 **** #* *h
.      ds * \\n[*]th\"
.      nr *** (\\n[*] % 10)
.      if d nth-\\n[***] \
.        ds * \\n[*]\\*[nth-\\n[***]]\"
.      tmc \\n[.F]:\\n[.c]: The \\*[*] width value (\\$\\n[*]) is too small.
.      tm1 " It should be greater than \\n[*h].
.    \}
.
.    nr in\\n[t*#]*\\n[*] \\n[**]	\"	cell offset
.    nr ** +\\n[$\\n[*]]
.  \}
..
.
.
.\"	Utility macro:	.t*dntr <origin> <cell position> ? <cell ID>
.\"
.\"		Close TD diversion, make some calculations, and set
.\"		some help strings and registers.  <origin> is 0, 1,
.\"		or 2 if the call of .t*dntr occurs in .TD, .TR, or
.\"		.ETB, respectively.
.de t*dntr
.  nr dn 0				\"	reset diversion height
.  br					\"	finish cell data
.
.  if "\\n[.z]"*t*dummy*" \
.    return
.
.  ds #t#r \\n[t*#]*\\n[t*r#\\n[t*#]]\"		refresh table row identifier
.
.  if \\n[c#\\*[#t#r]] \{\
.    di					\"	close diversion
.    nr dn\\$4 \\n[dn]			\"	save height of this cell
.    if !\\n[rspan\\*[#trc]] \{\
.      \" update row height if not in a row span
.      nr dntr\\*[#t#r] (\\n[dntr\\*[#t#r]] >? \\n[dn])
.      if \\$2 \
.        nr dntr\\*[#t#r] ((\\n[t*height\\*[#t#r]] \
                            - (2 * \\n[cscp\\n[t*#]] + \\n[b/2\\n[t*#]])) \
                            >? \\n[dntr\\*[#t#r]])
.  \}\}
.
.  nr c#\\*[#t#r] +1
.  nr * \\$2
.
.  \" update column span registers
.  while (\\n+[*] <= \\$3) \{\
.    if r cspan\\*[#t#r]*\\n[*] \
.      nr c#\\*[#t#r] +\\n[cspan\\*[#t#r]*\\n[*]]
.    nr cspan\\*[#t#r]*\\n[*] 0
.  \}
.
.  ds #trc \\*[#t#r]*\\n[c#\\*[#t#r]]\"
.
.  \" only check for cell underflow if called by .TR or .ETB
.  if (\\$1 & (\\n[c#\\*[#t#r]] <= \\n[t*cols\\n[t*#]])) \{\
.    ds * are\"
.    ds ** columns\"
.    if (\\n-[c#\\*[#t#r]] == 1) \{\
.      ds * is\"
.      ds ** column\"
.    \}
.    tmc \\n[.F]:\\n[.c]: There \\*[*] only \\n[c#\\*[#t#r]] \\*[**]
.
.    nr * \\n[t*r#\\n[t*#]]
.    ds * \\n[*]th\"
.    nr *** (\\n[*] % 10)
.    if d nth-\\n[***] \
.      ds * \\n[*]\\*[nth-\\n[***]]\"
.    tmc " in the \\*[*] row
.
.    ds * are\"
.    if (\\n[t*cols\\n[t*#]] == 1) \
.      ds * is\"
.    tm1 " but \\n[t*cols\\n[t*#]] \\*[*] expected.
.  \}
..
.
.
.\"	Utility-macro:	.t*args level_1 [level_2]
.\"
.\"		Get the arguments common to TBL, TR, and TD for the level
.\"		in argument 1, using default values from the level in
.\"		argument 2.  If argument 2 is missing, use the global
.\"		default values.
.\"
.de t*args
.  ds t*bgc\\$1 \\*[t*bgc\\$2]\"
.  ds t*fgc\\$1 \\*[t*fgc\\$2]\"
.  ds t*hl\\$1 \\*[t*hl\\$2]\"
.  ds t*vl\\$1 \\*[t*vl\\$2]\"
.  ds t*hal\\$1 \\*[t*hal\\$2]\"
.  ds t*val\\$1 \\*[t*val\\$2]\"
.  ds t*ff\\$1 \\*[t*ff\\$2]\"
.  ds t*fst\\$1 \\*[t*fst\\$2]\"
.  ds t*fsz\\$1 \\*[t*fsz\\$2]\"
.
.  if "\\*[args]"" \
.    return
.
.  t*getarg bgc \\*[args]         \"	background color
.  if !"\\*[bgc]"" \{\
.    ie m\\*[bgc] \
.      ds t*bgc\\$1 \\*[bgc]\"
.    el \{\
.      ie "\\*[bgc]"=" \
.        ds t*bgc\\$1 =\"
.      el \
.        tm \\n[.F]:\\n[.c]: Invalid background color '\\*[bgc]'.
.  \}\}
.  if "\\*[args]"" \
.    return
.
.  t*getarg fgc \\*[args]         \"	foreground color
.  if !"\\*[fgc]"" \{\
.    ie m\\*[fgc] \
.      ds t*fgc\\$1 \\*[fgc]\"
.    el \{\
.      ie "\\*[fgc]"=" \
.        ds t*fgc\\$1 =\"
.      el \
.        tm \\n[.F]:\\n[.c]: Invalid foreground color '\\*[fgc]'.
.  \}\}
.  if "\\*[args]"" \
.    return
.
.  t*getarg hl \\*[args]          \"	horizontal line between cells
.  if !"\\*[hl]"" \
.    ds t*hl\\$1 \\*[hl]\"
.  if "\\*[args]"" \
.    return
.
.  t*getarg vl \\*[args]          \"	vertical line between cells
.  if !"\\*[vl]"" \
.    ds t*vl\\$1 \\*[vl]\"
.  if "\\*[args]"" \
.    return
.
.  t*getarg hal \\*[args]         \"	horizontal table cell alignment
.  if !"\\*[hal]"" \{\
.    t*index bcrl \\*[hal]
.    ie \\n[t*index] \
.      ds t*hal\\$1 \\*[hal]\"
.    el \{\
.      tmc \\n[.F]:\\n[.c]: Invalid horizontal alignment '\\*[hal]':
.      tm1 " must be 'b', 'c', 'l' or 'r'.
.  \}\}
.  if "\\*[args]"" \
.    return
.
.  t*getarg val \\*[args]         \"	vertical table cell alignment
.  if !"\\*[val]"" \{\
.    t*index tmb \\*[val]
.    ie \\n[t*index] \
.      ds t*val\\$1 \\*[val]\"
.    el \{\
.      tmc \\n[.F]:\\n[.c]: Invalid vertical alignment '\\*[val]':
.      tm1 " must be 't', 'm' or 'b'.
.  \}\}
.  if "\\*[args]"" \
.    return
.
.  t*getarg ff \\*[args]          \"	font family
.  if !"\\*[ff]"" \
.    ds t*ff\\$1 \\*[ff]\"
.  if "\\*[args]"" \
.    return
.
.  t*getarg fst \\*[args]         \"	font style
.  if !"\\*[fst]"" \
.    ds t*fst\\$1 \\*[fst]\"
.  if "\\*[args]"" \
.    return
.
.  t*getarg fsz \\*[args]         \"	font size and spacing factor
.  if !"\\*[fsz]"" \
.    ds t*fsz\\$1 \\*[fsz]\"
..
.
.
.\" Append to your page header macro ('pg@top' for MS)
.\" to enable tables to span pages.
.de t*hm
.  ev t*tbl
.  nr ** \\n[.t]
.  while !""\\*[t*kept]" \{\
.    pops * t*kept
.    popr * t*kept
.    if (\\n[*] - \\n[**]) \{\
.      tm \\n[.F]:\\n[.c]: Table \\*[*] higher than page -- ignored!
.      break
.    \}
.
.    if (\\n[*] - \\n[.t]) \{\
.      ds t*kept \\n[*] \\*[t*kept]\"
.      ds t*kept \\*[*] \\*[t*kept]\"
.      tmc \\n[.F]:\\n[.c]: Remaining table(s),
.      tm1 " because not all fit onto this page.
.      break
.    \}
.
.    t*DI \\*[*]
.  \}
.  ev
..
.
.\" Local Variables:
.\" mode: nroff
.\" End:
.\" vim: filetype=groff:
