069f9ce51ea6754a100a394bd617f625e3d22bc7
[platform/upstream/groff.git] / contrib / hdtbl / hdtbl.tmac
1 .\"     -*- nroff -*-
2 .ig
3
4 hdtbl.tmac
5
6 This file is part of groff, the GNU roff type-setting system.
7
8 Copyright (C) 2005-2014  Free Software Foundation, Inc.
9 written by Joachim Walsdorff <Joachim.Walsdorff@urz.uni-heidelberg.de>.
10
11 groff is free software; you can redistribute it and/or modify it under
12 the terms of the GNU General Public License as published by the Free
13 Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
15
16 groff is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19 for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
23
24 ..
25 .
26 .
27 .\"     *****************************************************************
28 .\"     *               hdtbl - Heidelberger table macros               *
29 .\"     *                       Vers. 0.91 December 2005                *
30 .\"     *****************************************************************
31 .
32 .if d TBL \
33 .  nx
34 .
35 .mso hdmisc.tmac
36 .mso 62bit.tmac
37 .
38 .
39 .\"     *****************************************************************
40 .\"     *               default values for some arguments               *
41 .\"     *****************************************************************
42 .
43 .ds t*hl s\"
44 .ds t*vl s\"
45 .ds t*tal l\"
46 .ds t*hal b\"
47 .ds t*val t\"
48 .ds t*ff \\n[.fam]\"
49 .ds t*fst \\n[.f]\"
50 .ds t*fsz 1 1\"
51 .ds t*fgc red4\"
52 .ds t*bgc bisque\"
53 .ds t*bc red4\"
54 .nr t*cpd .5n
55 .nr t*csp .5n
56 .nr t*b .1n
57 .nr t*cols 1
58 .nr t*v \n[.v]
59 .nr t*s \n[.ps]
60 .nr t*hy \n[.hy]
61 .nr t*l \n[.ll]
62 .
63 .
64 .\"                     defaults for table captions
65 .nr t*cptn 0 1
66 .ds t*cptn "".sp .4" \
67             ".t*pv 1.0 1.0" \
68             ".ad l" \
69             "\m[\\*[t*fgc]]Table \\n+[t*cptn]:\0\c\k*"\"
70 .
71 .
72 .\" %beginstrip%
73 .
74 .\" for better error messages
75 .ds nth-1 st\"
76 .ds nth-2 nd\"
77 .ds nth-3 rd\"
78 .
79 .\" initialization of various registers
80 .nr t*# 0       \"      table nesting level
81 .nr t*numb 0 1  \"      held table diversion #
82 .
83 .ds *#trc*
84 .
85 .
86 .\"     *****************************************************************
87 .\"     *       The four base macros and the two optional macros        *
88 .\"     *****************************************************************
89 .
90 .ie n \
91 .  ds g tty:\"
92 .el \
93 .  ds g ps: exec\"
94 .
95 .\"     TBL:    table start
96 .\"             predecessor:    text, TD or ETB
97 .\"             successor:      CPTN or TR
98 .de TBL
99 .  ds t*m\\n[t*#] \\n[.m]\"
100 .  ie \\n[t*#] \
101 .    br
102 .  el \{\
103 .    ds * \\n[.ev]\"
104 .    ev t*tbl
105 .    evc \\*[*]
106 .    di t*tbl0
107 .    sp .4                              \" XXX: hard-coded value
108 .    nr t*i \\n[.i]
109 .    ll -\\n[.i]u
110 .    in 0
111 .  \}
112 .  nr t*# +1
113 .
114 .  \" Save current location for error checking at end
115 .  ds t*FN \\[.F]
116 .  ds t*LN \\[.c]
117 .
118 .  t*getarg cols \\$@\" from here string `args' contains the rest of \\$@
119 .  ie "\\*[cols]"" \
120 .    nr t*cols\\n[t*#] \\n[t*cols]
121 .  el \{\
122 .    ie \B\a\\*[cols]\a \
123 .      nr t*cols\\n[t*#] \\*[cols]
124 .    el \
125 .      tm \\n[.F]:\\n[.c]: Invalid number of columns value `\\*[cols]'.
126 .  \}
127 .
128 .  t*getarg cpd \\*[args]                 \"    cell padding
129 .  ie "\\*[cpd]"" \
130 .    nr t*cpd\\n[t*#] \\n[t*cpd]
131 .  el \{\
132 .    ie \B\a\\*[cpd]\a \
133 .      nr t*cpd\\n[t*#] \\*[cpd]
134 .    el \
135 .      tm \\n[.F]:\\n[.c]: Invalid cell padding value `\\*[cpd]'.
136 .  \}
137 .
138 .  t*getarg csp \\*[args]                 \"    cell spacing
139 .  ie "\\*[csp]"" \
140 .    nr t*csp\\n[t*#] \\n[t*csp]
141 .  el \{\
142 .    ie \B\a\\*[csp]\a \
143 .      nr t*csp\\n[t*#] \\*[csp]
144 .    el \
145 .      tm \\n[.F]:\\n[.c]: Invalid cell spacing value `\\*[csp]'.
146 .  \}
147 .
148 .  t*getarg border \\*[args]              \"    border thickness
149 .  ie "\\*[border]"=" \
150 .    nr t*b\\n[t*#] 0-1
151 .  el \{\
152 .    ie "\\*[border]"" \
153 .      nr t*b\\n[t*#] \\n[t*b]
154 .    el \{\
155 .      ie \B\a\\*[border]\a \
156 .        nr t*b\\n[t*#] \\*[border]
157 .      el \
158 .        tm \\n[.F]:\\n[.c]: Invalid border thickness value `\\*[border]'.
159 .  \}\}
160 .
161 .  t*getarg bc \\*[args]                  \"    border color
162 .  ds t*bc\\n[t*#] \\*[t*bc]\"
163 .  if !"\\*[bc]"" \{\
164 .    ie m\\*[bc] \
165 .      ds t*bc\\n[t*#] \\*[bc]\"
166 .    el \{\
167 .      ie "\\*[bc]"=" \
168 .        ds t*bc\\n[t*#] =\"
169 .      el \
170 .        tm \\n[.F]:\\n[.c]: Invalid border color `\\*[bc]'.
171 .  \}\}
172 .  ie "\\*[bc]"=" \
173 .    ds t*bc\\n[t*#]
174 .  el \{\
175 .    ie "\\*[bc]"" \
176 .      ds t*bc\\n[t*#] \\*[t*bc]\"
177 .    el \
178 .      ds t*bc\\n[t*#] \\*[bc]\"
179 .  \}
180 .
181 .  t*getarg width \\*[args]               \"    table/col widths
182 .  if "\\*[width]"=" \
183 .    ds width
184 .
185 .  nr b/2\\n[t*#] (\\n[t*b\\n[t*#]] / 2)\"      shortcut
186 .  nr cscp\\n[t*#] (\\n[t*csp\\n[t*#]] + \\n[t*cpd\\n[t*#]])\"  aux. register
187 .
188 .  t*getarg height \\*[args]              \"    table outline height
189 .  ie "\\*[height]"" \
190 .    nr t*height\\n[t*#] 0
191 .  el \{\
192 .    ie \B\a\\*[height]\a \
193 .      nr t*height\\n[t*#] (\\*[height] \
194                             - ((2 * \\n[cscp\\n[t*#]]) \
195                                 + (3 * \\n[b/2\\n[t*#]])))
196 .    el \
197 .      tm \\n[.F]:\\n[.c]: Invalid height value `\\*[height]'.
198 .  \}
199 .
200 .  t*cl \\*[width]                      \"      get cell widths and offsets
201 .  t*args \\n[t*#]                      \"      look for common arguments
202 .
203 .  t*getarg tal \\*[args]                 \"    table horizontal alignment
204 .  if "\\*[tal]"" \
205 .    ds tal \\*[t*tal]\"
206 .  ie "\\*[tal]"l" \
207 .    nr in\\n[t*#] \\n[.i]
208 .  el \{\
209 .    ie "\\*[tal]"c" \
210 .      nr in\\n[t*#] (\\n[.l] - \\n[ll\\n[t*#]]/2 + \\n[.i])
211 .    el \{\
212 .      ie "\\*[tal]"r" \
213 .        nr in\\n[t*#] (\\n[.l] - \\n[ll\\n[t*#]] + \\n[.i])
214 .      el \{\
215 .        tmc \\n[.F]:\\n[.c]: Invalid horizontal table alignment `\\*[tal]':
216 .        tm1 " must be `l', `c' or `r'.
217 .  \}\}\}
218 .
219 .  nr t*r#\\n[t*#] 0                    \"      initialize row index
220 .  mk toptbl\\n[t*#]
221 .
222 .  t*P1 \\*[args]
223 ..
224 .
225 .
226 .\"     CPTN:   optional table caption
227 .\"             predecessor:    TBL
228 .\"             successor:      TR
229 .de CPTN
230 .  ft 1
231 .
232 .  if "\\$0"CPTN" \
233 .    if \\n[t*r#\\n[t*#]] \{\
234 .      tmc \\n[.F]:\\n[.c]: Invalid placement of `.CPTN';
235 .      tm1 " must be called immediately after `.TBL'.
236 .      return
237 .    \}
238 .
239 .  t*getarg val \\$@
240 .  ds args\\n[t*#] "\\*[args]\"
241 .
242 .  t*index "\\*[args]" .TR
243 .  ie \\n[t*index] \{\
244 .    ds *a\\n[t*#] "\\*[args]\"
245 .    substring args\\n[t*#] 0 \\n[t*index]
246 .    substring *a\\n[t*#] \\n[t*index]-2 -1
247 .  \}
248 .  el \
249 .    ds *a\\n[t*#]
250 .
251 .  ie "\\*[val]"b" \{\
252 .    de t*cptn\\n[t*#]
253 .      *CPTN \\*[args\\n[t*#]]
254 .      rm t*cptn\\n[t*#]
255 \\..
256 .  \}
257 .  el \{\
258 .    ll (\\n[ll\\n[t*#]]u + \\n[in\\n[t*#]]u)
259 .    in \\n[in\\n[t*#]]u
260 .    t*P1 \\*[t*cptn]
261 '    in +\\n[*]u
262 .    t*P1 \\*[args\\n[t*#]]
263 .    t*pv 1 1
264 .    in
265 .    mk toptbl\\n[t*#]
266 .  \}
267 .
268 .  t*P1 \\*[*a\\n[t*#]]
269 ..
270 .
271 .als *CPTN CPTN
272 .
273 .
274 .\"     TR:     table row
275 .\"             predecessor:    TBL, CPTN, text, TD or ETB
276 .\"             successor:      TD
277 .de TR
278 .  ft 1
279 .  if !\\n[t*#] \{\
280 .    tm \\n[.F]:\\n[.c]: Table row (.TR) without preceding table start (.TBL).
281 .    return
282 .  \}
283 .
284 .  \" finish previous data cell, if any
285 .  if \\n[t*r#\\n[t*#]] \
286 .    t*dntr 1 \\n[c#\\*[#t#r]] \\n[t*cols\\n[t*#]] \\*[*#trc*]
287 .
288 .  nr t*r#\\n[t*#] +1                   \"      row number in this table
289 .  ds #t#r \\n[t*#]*\\n[t*r#\\n[t*#]]\"         table row identifier
290 .                                       \"      (<level>*<row>)
291 .  nr c#\\*[#t#r] 0 1                   \"      clear cell counter
292 .  nr dntr\\*[#t#r] 0 1                 \"      clear accumulated row height
293 .
294 .  t*getarg height \\$@
295 .  ie "\\*[height]"" \
296 .    nr t*height\\*[#t#r] 0
297 .  el \{\
298 .    ie \B\a\\*[height]\a \
299 .      nr t*height\\*[#t#r] \\*[height]
300 .    el \
301 .      tm \\n[.F]:\\n[.c]: Invalid table row height `\\*[height]'.
302 .  \}
303 .
304 .  \"   If there is a TR with height `height', the total height of the table
305 .  \"   is too high by 3/2 b, independent of the number of TR with `height'.
306 .  t*args \\*[#t#r] \\n[t*#]            \"      look for common arguments
307 .
308 .  t*P1 \\*[args]
309 ..
310 .
311 .
312 .\"     TH:     optional table header cell
313 .\"             predecessor:    text, TD or TR
314 .\"             successor:      text, TD, TR, TBL or ETB
315 .\"                                                             
316 .\"             cell content bolded and horizontally and vertically centered,
317 .\"             else like .TD
318 .de TH
319 .  ft 1
320 .  t*getarg hal \\$@
321 .  if "\\*[hal]"" \
322 .    ds hal c\"
323 .
324 .  t*getarg val \\*[args]
325 .  if "\\*[val]"" \
326 .    ds val m\"
327 .
328 .  t*getarg fst \\*[args]
329 .  if "\\*[fst]"" \
330 .    ds fst B\"
331 .
332 .  TD hal=\\*[hal] val=\\*[val] fst=\\*[fst] \\*[args]
333 ..
334 .
335 .
336 .\"     TD:     table data cell
337 .\"             predecessor:    text, TD or TR
338 .\"             successor:      text, TD, TR, TBL or ETB
339 .de TD
340 .  ft 1
341 .  \" finish previous data cell -- note the use of \E
342 .  t*dntr 0 \\n[c#\\*[#t#r]]-1 \En[c#\\*[#t#r]] \\*[*#trc*]
343 .
344 .  ds *#trc* \\*[#t#r]*\\n[c#\\*[#t#r]]\"       table cell identifier
345 .                                       \"      (<level>*<row>*<column>)
346 .
347 .  t*getarg rowspan \\$@
348 .  nr rowspan 1
349 .  if !"\\*[rowspan]"" \{\
350 .    ie \B\a\\*[rowspan]\a \{\
351 .      nr rowspan (\\*[rowspan] >? 1)
352 .      nr *rsp*\\*[*#trc*] (\\n[rowspan] - 1)
353 .    \}
354 .    el \
355 .      tm \\n[.F]:\\n[.c]: Invalid value of `rowspan' keyword.
356 .  \}
357 .
358 .  t*getarg colspan \\*[args]
359 .  nr colspan 1
360 .  if !"\\*[colspan]"" \{\
361 .    ie \B\a\\*[colspan]\a \
362 .      nr colspan (\\*[colspan] >? 1)
363 .    el \
364 .      tm \\n[.F]:\\n[.c]: Invalid value of `colspan' keyword.
365 .  \}
366 .
367 .  t*args \\*[#trc] \\*[#t#r]           \"  look for common arguments
368 .
369 .  nr in\\*[#trc] \\n[in\\n[t*#]*\\n[c#\\*[#t#r]]]
370 .  nr *cl \\n[cll\\n[t*#]*\\n[c#\\*[#t#r]]]
371 .  nr * 0 1
372 .  nr *r \\n[t*r#\\n[t*#]]
373 .
374 .  if (\\n[rowspan] - 1) \
375 .    while (\\n+[*] <= \\n[rowspan]) \{\
376 .      nr rspan\\n[t*#]*\\n[*r]*\\n[c#\\*[#t#r]] \\n[colspan]
377 .      if (\\n[*] > 1) \
378 .        nr cspan\\n[t*#]*\\n[*r]*\\n[c#\\*[#t#r]] \\n[colspan]
379 .      nr *r +1
380 .    \}
381 .
382 .  nr * 1 1
383 .  nr *c \\n[c#\\*[#t#r]]
384 .
385 .  if (\\n[colspan] - 1) \{\
386 .    nr vline\\*[*#trc*] 0-1            \"      set `no vl' flag
387 .
388 .    while (\\n+[*] <= \\n[colspan]) \{\
389 .      nr *c +1
390 .      nr *cl +(2 * \\n[cscp\\n[t*#]] \
391                 + \\n[b/2\\n[t*#]] \
392                 + \\n[cll\\n[t*#]*\\n[*c]])
393 .      nr c#\\*[#t#r] +1
394 .    \}
395 .  \}
396 .
397 .  if (\\n[c#\\n[t*#]*\\n[t*r#\\n[t*#]]] > \\n[t*cols\\n[t*#]]) \{\
398 .    ds * are\"
399 .    ds ** columns\"
400 .    if (\\n[c#\\*[#t#r]] == 1) \{\
401 .      ds * is\"
402 .      ds ** column\"
403 .    \}
404 .    tmc \\n[.F]:\\n[.c]: There \\*[*] \\n[c#\\*[#t#r]] table \\*[**] (.TD)
405 .
406 .    ds * are\"
407 .    if (\\n[t*cols\\n[t*#]] == 1) \
408 .      ds * is\"
409 .    tm1 " but only \\n[t*cols\\n[t*#]] \\*[*] expected.
410 .
411 .    ds *
412 .    length * \\n[.F]:\\n[.c]:
413 .
414 .    while \\n-[*] \
415 .      ds * " \\*[*]\"
416 .
417 .    tm1 "\\*[*] Remaining .TDs and its contents are ignored.
418 .
419 .    di *t*dummy*                \"     bypass superfluous input
420 .    return
421 .  \}
422 .
423 .  di t*\\*[#trc]                \"     open cell diversion and set locals
424 .  in 0
425 .  nr cll\\*[#trc] \\n[*cl]
426 .  ll \\n[*cl]u
427 .  nr *cl\\n[t*#] \\n[.l]
428 .  gcolor \\*[t*fgc\\*[#trc]]
429 .  ad \\*[t*hal\\*[#trc]]
430 .  fam \\*[t*ff\\*[#trc]]
431 .  ft \\*[t*fst\\*[#trc]]
432 .  t*pv \\*[t*fsz\\*[#trc]]
433 .
434 .  t*P1 \\*[args]
435 ..
436 .
437 .
438 .\"     ETB:    end of table
439 .\"             predecessor:    text, TD or ETB
440 .\"             successor:      text, TD, TR or TBL
441 .de ETB
442 .  ie \\n[t*#] \
443 .    if !\\n[t*r#\\n[t*#]] \{\
444 .      tmc \\n[.F]:\\n[.c]: Each table (.TBL)
445 .      tm1 " should contain at least one table row (.TR)!
446 .    \}
447 .  el \{\
448 .    tmc \\n[.F]:\\n[.c]: Table end (.ETB)
449 .    tm1 " without corresponding table start (.TBL)!
450 .  \}
451 .
452 .  ds #t#r \\n[t*#]*\\n[t*r#\\n[t*#]]\"         refresh table row identifier
453 .  t*dntr 2 \\n[c#\\*[#t#r]] \\n[t*cols\\n[t*#]] \\*[*#trc*]
454 .
455 .  t*divs                        \"     print this table
456 .
457 .  sp \\n[b/2\\n[t*#]]u
458 .  t*cptn\\n[t*#]
459 .  nr t*# -1
460 .
461 .  ll \\n[*cl\\n[t*#]]u          \"     restore ll outside this table
462 .  in 0                          \"     reset indent
463 .  gcolor \\*[t*m\\n[t*#]]       \"     reset previous fgc
464 .
465 .  t*getarg hold \\$@
466 .  if !\\n[t*#] \{\
467 .    sp .5
468 .    di
469 .    in \\n[t*i]u
470 .    ie "\\*[hold]"" \{\
471 .      ie (\\n[.t] - \\n[dn]) \
472 .        t*DI t*tbl0
473 .      el \{\
474 .        rn t*tbl0 t*tbl\\n+[t*numb]
475 .        ds t*kept \\*[t*kept] t*tbl\\n[t*numb] \\n[dn]\"
476 .      \}
477 .    \}
478 .    el \{\
479 .      rn t*tbl0 t*hold\\n+[t*numb]
480 .      tm \\n[.F]:\\n[.c]: Table t*hold\\n[t*numb] held.
481 .      ds t*held \\*[t*held] t*hold\\n[t*numb] \\n[dn]\"
482 .    \}
483 .
484 .    ev                         \"      restore previous environment
485 .  \}
486 .
487 .  t*P1 \\*[args]
488 ..
489 .
490 .
491 .\"     *****************************************************************
492 .\"     *       Following the definition of five utility macros         *
493 .\"     *       special to hdtbl.                                       *
494 .\"     *       Other utility macros common to hdtbl and hdgroff        *
495 .\"     *       are defined in the file hdmisc.tmac.                    *
496 .\"     *****************************************************************
497 .
498 .
499 .\"     .t*free [n]
500 .\"             print the next [n] held table[s].
501 .\"             Don't call it within a table!
502 .\"             If the table is higher than the remaining space
503 .\"             on the page, the table is printed on the next page.
504 .de t*free
505 .  if "\\$0"CPTN" \
506 .    if \\n[t*r#\\n[t*#]] \{\
507 .      tmc \\n[.F]:\\n[.c]: Invalid placement of `.t*free' within a table;
508 .      tm1 " it must be called outside of any table.
509 .      return
510 .    \}
511 .
512 .  if "\\*[t*held]"" \{\
513 .    tm \\n[.F]:\\n[.c]: No held tables.
514 .    return
515 .  \}
516 .
517 .  nr ** (\\$1 >? 1) 1
518 .  while !""\\*[t*held]" \{\
519 .    pops * t*held
520 .    popr * t*held
521 .
522 .    ie (\\n[.t] - \\n[*]) \{\
523 .      ev t*tbl
524 .      t*DI \\*[*]
525 .      ev
526 .    \}
527 .    el \{\
528 .      rn \\*[*] t*tbl\\n+[t*numb]
529 .      ds t*kept \\*[t*kept] t*tbl\\n[t*numb] \\n[*]\"
530 .    \}
531 .
532 .    if !(\\n-[**] - 1) \
533 .      return
534 .  \}
535 ..
536 .
537 .
538 .\"     The main utility macro for tables:
539 .\"             If a table is closed by ETB, this macro is called.  It
540 .\"             processes one complete table, i.e., all the table cell
541 .\"             diversions, paints the cell backgrounds, draws
542 .\"             horizontal and vertical table lines and the table border.
543 .\"
544 .\"             Nested tables are processed from inside to outside.
545 .
546 .de t*divs
547 .  ll (\\n[t*l]u + 1c)                  \"      avoid warning `can't break line'
548 .  nf
549 .
550 .  nr b/2 \\n[b/2\\n[t*#]]              \"      some abbreviations
551 .  nr cscp \\n[cscp\\n[t*#]]
552 .  nr cscpb (\\n[b/2] + \\n[cscp])
553 .
554 .  nr topdiv (\\n[.d] + \\n[b/2] - \\n[cscp])\" top of cell diversion
555 .  nr cscpb2 (\\n[b/2] / 2 + \\n[cscp])
556 .
557 .  nr #r 0 1
558 .  \" outer loop for rows
559 .  while (\\n+[#r] <= \\n[t*r#\\n[t*#]]) \{\
560 .    \" TODO: insert code here for multipage tables
561 .    nr * (\\n[#r] - 1)
562 .    nr topdiv +(\\n[dntr\\n[t*#]*\\n[*]] + \\n[cscp] + \\n[cscpb])
563 .
564 .    \" if table still smaller than specified table height, increase it
565 .    if ((\\n[#r] == \\n[t*r#\\n[t*#]]) & \\n[t*height\\n[t*#]]) \
566 .      nr dntr\\n[t*#]*\\n[#r] (\\n[cscpb] \
567                                 + \\n[toptbl\\n[t*#]] \
568                                 + \\n[t*height\\n[t*#]] \
569                                 - (\\n[topdiv] >? \\n[dntr\\n[t*#]*\\n[#r]]))
570 .
571 .    nr #c 0 1
572 .    \" inner loop for cells
573 .    while (\\n+[#c] <= \\n[t*cols\\n[t*#]]) \{\
574 .      ds #trc \\n[t*#]*\\n[#r]*\\n[#c]\"
575 .      \" continue if the diversion is empty
576 .      if !d t*\\*[#trc] \
577 .        continue
578 .
579 .      sp |\\n[topdiv]u
580 .      in (\\n[in\\n[t*#]]u + \\n[in\\*[#trc]]u)\"      cell offset
581 .      nr $1 \\n[dntr\\n[t*#]*\\n[#r]]  \"      cell height
582 .
583 .      \" if we have spanned rows, calculate resulting row height
584 .      \" and position of lower horizontal line
585 .      if \\n[*rsp*\\*[#trc]] \{\
586 .        nr * \\n[#r] 1
587 .        nr rspan\\*[#trc] 0-1          \"      set `no hl' flag
588 .        nr corr (\\n[dn\\*[#trc]] - \\n[dntr\\n[t*#]*\\n[#r]])
589 .
590 .        \" clear row span flags in following rows and update row height
591 .        while \\n[*rsp*\\*[#trc]] \{\
592 .          nr *rsp*\\*[#trc] -1
593 .          nr rspan\\n[t*#]*\\n+[*]*\\n[#c] 0
594 .          nr ** (\\n[dntr\\n[t*#]*\\n[*]] + \\n[cscp] + \\n[cscpb])
595 .          nr corr -\\n[**]
596 .          nr $1 +\\n[**]
597 .        \}
598 .
599 .        if (\\n-[*] == \\n[t*r#\\n[t*#]]) \
600 .          nr $1 ((\\n[t*height\\n[t*#]] \
601                    - \\n[.d] \
602                    + \\n[toptbl\\n[t*#]] \
603                    + \\n[cscpb]) \
604                      >? \\n[$1])
605 .        nr dntr\\n[t*#]*\\n[*] +(\\n[corr] >? 0)
606 .      \}
607 .
608 .      \" paint cell background
609 .      nr * (2 * \\n[t*cpd\\n[t*#]] + \\n[cll\\*[#trc]])\"      background width
610 .      nr $1 (\\n[$1] >? \\n[dn\\*[#trc]])\"    cell height
611 .
612 .      if !"\\*[t*bgc\\*[#trc]]"=" \{\
613 .        nop \h'\\n[t*csp\\n[t*#]]u'\
614 \M[\\*[t*bgc\\*[#trc]]]\
615 \v'(-.67v - \\n[t*cpd\\n[t*#]]u)'\
616 \D'P \\n[*]u 0 \
617      0 (2u * \\n[t*cpd\\n[t*#]]u + \\n[$1]u) \
618      -\\n[*]u 0'\
619 \M[]
620 .        sp -1
621 .      \}
622 .
623 .      \" ***   horizontal and vertical single or double lines   ***
624 .      \" double and single lines have the same thickness;
625 .      \" the double lines' distance is the line thickness.
626 .      \"
627 .      \" `border=x': horizontal/vertical lines x/2 thick, minimum .1n
628 .      \" `border=0': no border; horizontal/vertical lines .1n thick
629 .      \" `border=': neither border nor horizontal/vertical lines
630 .
631 .      nr *t (.1n >? \\n[b/2])          \"      thickness of hl/vl; min. .1n
632 .      in +\\n[cscp]u
633 .
634 .      \" check for vertical and horizontal lines
635 .      if (1 + \\n[t*b\\n[t*#]]) \{\
636 .        if !"\\*[t*bc\\n[t*#]]"=" \{\
637 .          \" draw horizontal line between this cell and the one below
638 .          if (\\n[t*r#\\n[t*#]] - \\n[#r] + \\n[rspan\\*[#trc]]) \{\
639 .            if !"\\*[t*hl\\*[#trc]]"=" \{\
640 .              sp \\n[$1]u
641 .              nr * (\\n[cscp] + \\n[cscpb] + \\n[cll\\*[#trc]])
642 .              nop \X'\*[g] 1 setlinecap'\
643 \h'(-\\n[cscpb2]u - \\n[*t]u)'\
644 \v'(\\n[cscpb2]u - .67v)'\
645 \m[\\*[t*bc\\n[t*#]]]\
646 \D't \\n[*t]u'\c
647 .
648 .              ie "\\*[t*hl\\*[#trc]]"d" \
649 .                nop \v'-\\n[*t]u'\
650 \D'l \\n[*]u 0'\
651 \v'(2u * \\n[*t]u)'\
652 \D'l -\\n[*]u 0'\
653 \D't 0'
654 .              el \
655 .                nop \D'l \\n[*]u 0'\
656 \D't 0'
657 .
658 .              sp (-\\n[$1]u - 1v)
659 .          \}\}
660 .
661 .          nr rspan\\*[#trc] 0
662 .
663 .          \" draw vertical line between this cell and the one to the right
664 .          if (\\n[t*cols\\n[t*#]] - \\n[#c] + \\n[vline\\*[#trc]]) \{\
665 .            if !"\\*[t*vl\\*[#trc]]"=" \{\
666 .              nop \X'\*[g] 1 setlinecap'\
667 \v'(-\\n[cscpb2]u - .67v)'\
668 \m[\\*[t*bc\\n[t*#]]]\
669 \h'(\\n[cscpb2]u - \\n[*t]u + \\n[cll\\*[#trc]]u)'\c
670 .
671 .              ie "\\*[t*vl\\*[#trc]]"d" \
672 .                nop \h'-\\n[*t]u'\
673 \D't \\n[*t]u'\
674 \D'l 0 (2u * \\n[cscp]u + \\n[$1]u + (\\n[*t]u / 2u))'\
675 \h'(2u * \\n[*t]u)'\
676 \D'l 0 -(2u * \\n[cscp]u + \\n[$1]u + (\\n[*t]u / 2u))'\
677 \D't 0'
678 .              el \
679 .                nop \D't \\n[*t]u'\
680 \D'l 0 (2u * \\n[cscp]u + \\n[$1]u + (\\n[*t]u / 2u))'\
681 \D't 0'
682 .              sp -1
683 .      \}\}\}\}
684 .
685 .      nr vline\\*[#trc] 0
686 .
687 .      \" vert. cell content alignment
688 .      nr ** 0
689 .
690 .      ie "\\*[t*val\\*[#trc]]"m" \
691 .        nr ** ((\\n[$1] - \\n[dn\\*[#trc]]) / 2)\"     val=m
692 .      el \
693 .        if "\\*[t*val\\*[#trc]]"b" \
694 .          nr ** (\\n[$1] - \\n[dn\\*[#trc]])\" val=b
695 .
696 .      sp \\n[**]u                      \"      vertical content position
697 .
698 .      \" finally output the diversion
699 .      t*\\*[#trc]
700 .      rm t*\\*[#trc]
701 .    \}
702 .  \}
703 .
704 .  \" draw the box border
705 .  in \\n[in\\n[t*#]]u
706 .  nr ** (\\n[topdiv] + \\n[dntr\\n[t*#]*\\n-[#r]])
707 .
708 .  if \\n[t*b\\n[t*#]] \{\
709 .    sp |(\\n[toptbl\\n[t*#]]u + \\n[b/2]u)
710 .    nr $1 (\\n[toptbl\\n[t*#]] - \\n[**] - \\n[cscp])
711 .    nr * (\\n[ll\\n[t*#]] - \\n[t*b\\n[t*#]])
712 .
713 .    if !"\\*[t*bc\\n[t*#]]"=" \
714 .      nop \X'\*[g] 0 setlinejoin 2 setlinecap'\
715 \v'-.67v'\
716 \h'-\\n[b/2]u'\
717 \m[\\*[t*bc\\n[t*#]]]\
718 \D't \\n[t*b\\n[t*#]]u'\
719 \D'l \\n[*]u 0'\
720 \D'l 0 -\\n[$1]u'\
721 \D'l -\\n[*]u 0'\
722 \D'l 0 \\n[$1]u'\
723 \D't 0'
724 .  \}
725 .
726 .  sp |(\\n[**]u + \\n[cscpb]u)
727 .  fi
728 ..
729 .
730 .
731 .\"     Utility macro:  .t*cl [width1 [width2 [...]]]
732 .\"
733 .\"             Calculate cell widths, table width, and cell offsets.
734 .de t*cl
735 .  nr t*cols\\n[t*#] (\\n[.$] >? \\n[t*cols\\n[t*#]])
736 .  nr ll\\n[t*#] 0                      \"      accumulated cell widths
737 .  nr ** (\\n[.l] / \\n[t*cols\\n[t*#]])\"      width for remaining cells
738 .  nr * 0 1                             \"      counter
739 .
740 .  \" while-loop: Parse user arguments to get each cell's width.
741 .  while (\\n[t*cols\\n[t*#]] >= \\n+[*]) \{\
742 .    nr $\\n[*] \\n[**]
743 .    if !"\\$[\\n[*]]"" \{\
744 .      \" check for `%' pseudo scaling indicator
745 .      ds * \\$\\n[*]\"
746 .      substring * -1 -1
747 .      ie "\\*[*]"%" \{\
748 .        ds ** \\$[\\n[*]]\"
749 .        substring ** 0 -2
750 .        ie \B\a\\*[**]\a \
751 .          nr $\\n[*] (\\*[**] * \\n[.l] / 100)
752 .        el \
753 .          tm \\n[.F]:\\n[.c]: Invalid relative cell width `\\*[**]%'.
754 .      \}
755 .      el \{\
756 .        ie \B\a\\$[\\n[*]]\a \
757 .          nr $\\n[*] \\$[\\n[*]]
758 .        el \
759 .          tm \\n[.F]:\\n[.c]: Invalid cell width `\\$[\\n[*]]'.
760 .    \}\}
761 .
762 .    nr ll\\n[t*#] +\\n[$\\n[*]]
763 .    nr ** \\n[$\\n[*]]
764 .  \}
765 .
766 .  if (\\n[ll\\n[t*#]] > \\n[.l]) \
767 .    tm \\n[.F]:\\n[.c]: Table width larger than column width.
768 .
769 .  nr ** (0 >? \\n[t*b\\n[t*#]])
770 .  nr * 0 1
771 .
772 .  \" second while loop: Compute final cell widths.
773 .  while (\\n[t*cols\\n[t*#]] >= \\n+[*]) \{\
774 .    \" Remove border width, if any.
775 .    if \\n[t*b\\n[t*#]] \{\
776 .      \" cell_width := cell_width * (length - 1.5*border) / length
777 .      nr #* (\\n[ll\\n[t*#]] - (3 * \\n[t*b\\n[t*#]] / 2))
778 .      nr *** (\\n[ll\\n[t*#]] / 2)
779 .      \" avoid multiplication overflow
780 .      mult31by31 $\\n[*] #* ****
781 .      add31to62 *** **** ****
782 .      div62by31 **** ll\\n[t*#] $\\n[*]
783 .    \}
784 .
785 .    \" Get cell widths without padding, spacing, and separator line.
786 .    nr cll\\n[t*#]*\\n[*] (\\n[$\\n[*]] \
787                             - (2 * \\n[cscp\\n[t*#]]) \
788                             - \\n[b/2\\n[t*#]])
789 .
790 .    \" Check whether value is non-positive.
791 .    if !\\n[cll\\n[t*#]*\\n[*]] \{\
792 .      nr #* (\\n[ll\\n[t*#]] - (3 * \\n[t*b\\n[t*#]] / 2))
793 .      nr *** (\\n[#*] / 2)
794 .      nr *h (2 * \\n[cscp\\n[t*#]] + \\n[b/2\\n[t*#]])
795 .      mult31by31 *h ll\\n[t*#] ****
796 .      add31to62 *** **** ****
797 .      div62by31 **** #* *h
798 .      ds * \\n[*]th\"
799 .      nr *** (\\n[*] % 10)
800 .      if d nth-\\n[***] \
801 .        ds * \\n[*]\\*[nth-\\n[***]]\"
802 .      tmc \\n[.F]:\\n[.c]: The \\*[*] width value (\\$\\n[*]) is too small.
803 .      tm1 " It should be greater than \\n[*h].
804 .    \}
805 .
806 .    nr in\\n[t*#]*\\n[*] \\n[**]       \"      cell offset
807 .    nr ** +\\n[$\\n[*]]
808 .  \}
809 ..
810 .
811 .
812 .\"     Utility macro:  .t*dntr <origin> <cell position> ? <cell ID>
813 .\"
814 .\"             Close TD diversion, make some calculations, and set
815 .\"             some help strings and registers.  <origin> is 0, 1,
816 .\"             or 2 if the call of .t*dntr occurs in .TD, .TR, or
817 .\"             .ETB, respectively.
818 .de t*dntr
819 .  nr dn 0                              \"      reset diversion height
820 .  br                                   \"      finish cell data
821 .
822 .  if "\\n[.z]"*t*dummy*" \
823 .    return
824 .
825 .  ds #t#r \\n[t*#]*\\n[t*r#\\n[t*#]]\"         refresh table row identifier
826 .
827 .  if \\n[c#\\*[#t#r]] \{\
828 .    di                                 \"      close diversion
829 .    nr dn\\$4 \\n[dn]                  \"      save height of this cell
830 .    if !\\n[rspan\\*[#trc]] \{\
831 .      \" update row height if not in a row span
832 .      nr dntr\\*[#t#r] (\\n[dntr\\*[#t#r]] >? \\n[dn])
833 .      if \\$2 \
834 .        nr dntr\\*[#t#r] ((\\n[t*height\\*[#t#r]] \
835                             - (2 * \\n[cscp\\n[t*#]] + \\n[b/2\\n[t*#]])) \
836                             >? \\n[dntr\\*[#t#r]])
837 .  \}\}
838 .
839 .  nr c#\\*[#t#r] +1
840 .  nr * \\$2
841 .
842 .  \" update column span registers
843 .  while (\\n+[*] <= \\$3) \{\
844 .    if r cspan\\*[#t#r]*\\n[*] \
845 .      nr c#\\*[#t#r] +\\n[cspan\\*[#t#r]*\\n[*]]
846 .    nr cspan\\*[#t#r]*\\n[*] 0
847 .  \}
848 .
849 .  ds #trc \\*[#t#r]*\\n[c#\\*[#t#r]]\"
850 .
851 .  \" only check for cell underflow if called by .TR or .ETB
852 .  if (\\$1 & (\\n[c#\\*[#t#r]] <= \\n[t*cols\\n[t*#]])) \{\
853 .    ds * are\"
854 .    ds ** columns\"
855 .    if (\\n-[c#\\*[#t#r]] == 1) \{\
856 .      ds * is\"
857 .      ds ** column\"
858 .    \}
859 .    tmc \\n[.F]:\\n[.c]: There \\*[*] only \\n[c#\\*[#t#r]] \\*[**]
860 .
861 .    nr * \\n[t*r#\\n[t*#]]
862 .    ds * \\n[*]th\"
863 .    nr *** (\\n[*] % 10)
864 .    if d nth-\\n[***] \
865 .      ds * \\n[*]\\*[nth-\\n[***]]\"
866 .    tmc " in the \\*[*] row
867 .
868 .    ds * are\"
869 .    if (\\n[t*cols\\n[t*#]] == 1) \
870 .      ds * is\"
871 .    tm1 " but \\n[t*cols\\n[t*#]] \\*[*] expected.
872 .  \}
873 ..
874 .
875 .
876 .\"     Utility-macro:  .t*args level_1 [level_2]
877 .\"
878 .\"             Get the arguments common to TBL, TR, and TD for the level
879 .\"             in argument 1, using default values from the level in
880 .\"             argument 2.  If argument 2 is missing, use the global
881 .\"             default values.
882 .\"
883 .de t*args
884 .  ds t*bgc\\$1 \\*[t*bgc\\$2]\"
885 .  ds t*fgc\\$1 \\*[t*fgc\\$2]\"
886 .  ds t*hl\\$1 \\*[t*hl\\$2]\"
887 .  ds t*vl\\$1 \\*[t*vl\\$2]\"
888 .  ds t*hal\\$1 \\*[t*hal\\$2]\"
889 .  ds t*val\\$1 \\*[t*val\\$2]\"
890 .  ds t*ff\\$1 \\*[t*ff\\$2]\"
891 .  ds t*fst\\$1 \\*[t*fst\\$2]\"
892 .  ds t*fsz\\$1 \\*[t*fsz\\$2]\"
893 .
894 .  if "\\*[args]"" \
895 .    return
896 .
897 .  t*getarg bgc \\*[args]         \"    background color
898 .  if !"\\*[bgc]"" \{\
899 .    ie m\\*[bgc] \
900 .      ds t*bgc\\$1 \\*[bgc]\"
901 .    el \{\
902 .      ie "\\*[bgc]"=" \
903 .        ds t*bgc\\$1 =\"
904 .      el \
905 .        tm \\n[.F]:\\n[.c]: Invalid background color `\\*[bgc]'.
906 .  \}\}
907 .  if "\\*[args]"" \
908 .    return
909 .
910 .  t*getarg fgc \\*[args]         \"    foreground color
911 .  if !"\\*[fgc]"" \{\
912 .    ie m\\*[fgc] \
913 .      ds t*fgc\\$1 \\*[fgc]\"
914 .    el \{\
915 .      ie "\\*[fgc]"=" \
916 .        ds t*fgc\\$1 =\"
917 .      el \
918 .        tm \\n[.F]:\\n[.c]: Invalid foreground color `\\*[fgc]'.
919 .  \}\}
920 .  if "\\*[args]"" \
921 .    return
922 .
923 .  t*getarg hl \\*[args]          \"    horizontal line between cells
924 .  if !"\\*[hl]"" \
925 .    ds t*hl\\$1 \\*[hl]\"
926 .  if "\\*[args]"" \
927 .    return
928 .
929 .  t*getarg vl \\*[args]          \"    vertical line between cells
930 .  if !"\\*[vl]"" \
931 .    ds t*vl\\$1 \\*[vl]\"
932 .  if "\\*[args]"" \
933 .    return
934 .
935 .  t*getarg hal \\*[args]         \"    horizontal table cell alignment
936 .  if !"\\*[hal]"" \{\
937 .    t*index bcrl \\*[hal]
938 .    ie \\n[t*index] \
939 .      ds t*hal\\$1 \\*[hal]\"
940 .    el \{\
941 .      tmc \\n[.F]:\\n[.c]: Invalid horizontal alignment `\\*[hal]':
942 .      tm1 " must be `b', `c', `l' or `r'.
943 .  \}\}
944 .  if "\\*[args]"" \
945 .    return
946 .
947 .  t*getarg val \\*[args]         \"    vertical table cell alignment
948 .  if !"\\*[val]"" \{\
949 .    t*index tmb \\*[val]
950 .    ie \\n[t*index] \
951 .      ds t*val\\$1 \\*[val]\"
952 .    el \{\
953 .      tmc \\n[.F]:\\n[.c]: Invalid vertical alignment `\\*[val]':
954 .      tm1 " must be `t', `m' or `b'.
955 .  \}\}
956 .  if "\\*[args]"" \
957 .    return
958 .
959 .  t*getarg ff \\*[args]          \"    font family
960 .  if !"\\*[ff]"" \
961 .    ds t*ff\\$1 \\*[ff]\"
962 .  if "\\*[args]"" \
963 .    return
964 .
965 .  t*getarg fst \\*[args]         \"    font style
966 .  if !"\\*[fst]"" \
967 .    ds t*fst\\$1 \\*[fst]\"
968 .  if "\\*[args]"" \
969 .    return
970 .
971 .  t*getarg fsz \\*[args]         \"    font size and spacing factor
972 .  if !"\\*[fsz]"" \
973 .    ds t*fsz\\$1 \\*[fsz]\"
974 ..
975 .
976 .
977 .\" Append to your page header macro ('pg@top' for MS)
978 .\" to enable tables to span pages.
979 .de t*hm
980 .  ev t*tbl
981 .  nr ** \\n[.t]
982 .  while !""\\*[t*kept]" \{\
983 .    pops * t*kept
984 .    popr * t*kept
985 .    if (\\n[*] - \\n[**]) \{\
986 .      tm \\n[.F]:\\n[.c]: Table \\*[*] higher than page -- ignored!
987 .      break
988 .    \}
989 .
990 .    if (\\n[*] - \\n[.t]) \{\
991 .      ds t*kept \\n[*] \\*[t*kept]\"
992 .      ds t*kept \\*[*] \\*[t*kept]\"
993 .      tmc \\n[.F]:\\n[.c]: Remaining table(s),
994 .      tm1 " because not all fit onto this page.
995 .      break
996 .    \}
997 .
998 .    t*DI \\*[*]
999 .  \}
1000 .  ev
1001 ..
1002 .
1003 .\" EOF