.\" this document requires the tmac.wrprc macros
.\"
.\" $(TROFF) $(MSMACROS) tmac.wrprc thisfile
.\"
.\" revision date - change whenever this file is edited
.ds RD 20 May 1997
.\"
.EH 'tblcvt \*- A troffcvt Preprocessor'- % -''
.OH ''- % -'tblcvt \*- A troffcvt Preprocessor'
.OF 'Revision date:\0\0\*(RD''Printed:\0\0\n(dy \*(MO 19\n(yr'
.EF 'Revision date:\0\0\*(RD''Printed:\0\0\n(dy \*(MO 19\n(yr'
.\"
.de St	\" troffcvt special text
\\&\\$3\fB@\\$1\fR\\$2
..
.de Cl	\" troffcvt control
\\&\\$3\fB\e\\$1\fR\\$2
..
.de Rq	\" troff request
\\&\\$3\fB\.\\$1\fR\\$2
..
.de Es	\" troff escape
\\&\\$3\fB\e\\$1\fR\\$2
..
.de Ac	\" action
.LP
.ta \n(LLuR
\(bu \\$1	(\fB\\$2\fR)
.br
..
.TL
.ps +2
tblcvt \*- A troffcvt Preprocessor
.ps
.AU
Paul DuBois
.H*ahref mailto:dubois@primate.wisc.edu
dubois@primate.wisc.edu
.H*aend
.AI
.H*ahref http://www.primate.wisc.edu/
Wisconsin Regional Primate Research Center
.H*aend
Revision date:\0\0\*(RD
.AB
.I tblcvt
reads
.I troff
input and converts the
.I tbl -related
parts to a format that
.I troffcvt
can understand more easily than raw
.I tbl
output.
.AE
.\"
.H*toc*title "Table of Contents"
.\"
.Ah Introduction
.\"
.LP
This document describes
.I tblcvt
(``\fItbl\fR convert''), a program that assists the process of using
.I troffcvt
to convert
.I troff
documents into other formats.
It's assumed here that you're familiar with
.I tbl .
If you don't have the standard
.I tbl
documentation
.I "Tbl \- A Program to Format Tables" , (
by M. E. Lesk), check the archive site from which you obtained the
.I troffcvt
distribution.
.LP
.I tblcvt
exists because
tables written in the
.I tbl
input language present a problem for
.I troffcvt .
.I troffcvt
understands only the
.I troff
language and knows nothing of the
.I tbl
language, so input files containing tables need to be run through
some sort of preprocessor before being given to
.I troffcvt .
In theory, you could run your
.I troff
files through
.I tbl
(since
.I tbl
generates output written in
.I troff \^),
and feed the result to
.I troffcvt
for processing.
In practice,
.I tbl
output is generally arcane and incomprehensible, and
.I troffcvt
doesn't do a very good job with it.
The purpose of
.I tblcvt
is to convert the parts of
.I troff
input files that are intended for
.I tbl
into something that's easier for
.I troffcvt
to understand.
This makes it more likely that
.I troffcvt
will generate output that its postprocessors will be able
to put back together into something that looks like a table in the
target format.
Not every table will look great, but any tables in this document are
simple enough that they should appear reasonably good if the document
is formatted with
.I troff2html ,
.I troff2rtf ,
or
.I unroff .
.LP
.I tblcvt
is intended as a drop-in replacement for
.I tbl .
Suppose you'd normally format a document using a command like this:
.Ps
% \f(CBtbl\fP \f(CIfile\fP ... \f(CB| troff\fP [\f(CIoptions\fP]
.Pe
The analogous command using
.I tblcvt
and
.I troffcvt
looks something like this:
.Ps
% \f(CBtblcvt\fP \f(CIfile\fP ... \f(CB| troffcvt\fP [\f(CIoptions\fP] \f(CB|\fP \f(CIpostprocessor\fP
.Pe
Or, if you use one of the front ends like
.I troff2html
that invoke
.I troffcvt
and the appropriate postprocessor for you, the command might look like this:
.Ps
% \f(CBtblcvt\fP \f(CIfile\fP ... \f(CB| troff2html\fP [\f(CIoptions\fP]
.Pe
If it seems that
.I troffcvt
or a front end are not reading the output from
.I tblcvt ,
specify
.B \-
after the option list to explicitly tell them to
read the standard input after processing their other options:
.Ps
% \f(CBtblcvt\fP \f(CIfile\fP ... \f(CB| troffcvt\fP [\f(CIoptions\fP] \f(CB- |\fP \f(CIpostprocessor\fP
% \f(CBtblcvt\fP \f(CIfile\fP ... \f(CB| troff2html\fP [\f(CIoptions\fP] \f(CB-\fP
.Pe
.\"
.Ah "tblcvt Output Format"
.\"
.LP
.I tblcvt
ignores its input except for those parts between corresponding pairs of
.Rq TS
(table start) and
.Rq TE
(table end) requests.
For each table,
.I tblcvt
digests its specification, figures out the table structure,
and produces
.I troff
output that indicates the structure using a special set of requests.
The output format has the property that it explicitly indicates the beginning
and end of each table, each row within a table, and each cell within a
row.
The general form of table information written by
.I tblcvt
looks like this:
.Ps
.ne 11
\&.T*table*begin [\f(CItable options\fP]
\&.T*column*info [\f(CIcolumn 1 options\fP]
\fI\&...options for remaining columns...\fP
\&.T*row*begin
\&.T*cell*info [\f(CIcell layout options\fP]
\fI\&...options for remaining cells in row...\fP
\&.T*cell*begin [\f(CIcell formatting options\fP]
\fI\&...cell contents...\fP
\&.T*cell*end
\fI\&...remaining cells in row...\fP
\&.T*row*end
\fI\&...remaining rows in table...\fP
\&.T*table*end
.Pe
Shortcut requests are used in certain circumstances.
If a cell is empty,
.I tblcvt
writes the single request
.Rq T*empty*cell
rather than
.Rq T*cell*begin ,
.Rq T*cell*end ,
and the cell data between them.
Similarly, if a cell of the table matrix is part of the area spanned by
an earlier cell,
.I tblcvt
writes
.Rq T*spanned*cell .
If an entire row consists of a table-width line,
.I tblcvt
writes the single request
.Rq T*row*line
rather than
.Rq T*row*begin ,
.Rq T*row*line ,
and the cell information between then.
.LP
Note that since
.I tblcvt
output uses long request names, you can't use compatibility
mode
.B \-C "" (
option) with
.I troffcvt
or a
.I troffcvt
front end.
.\"
.Bh "Table Beginning and Ending Requests"
.\"
.LP
Each table begins with a
.Rq T*table*begin
request, which has the following form:
.Ps
\&.T*table*begin \f(CIrows cols header-rows align expand box allbox doublebox\fP
.Pe
.I rows
and
.I cols
are the number of rows and columns in the table.
(A row that draws a line is considered a data row.)
.LP
For tables that are specified to have a header (using
.Rq TS
.B H
and
.Rq TH ),
.I tblcvt
writes
a non-zero value for the
.I header-rows
value.
Otherwise
.I header-rows
is 0.
.LP
.I align
is
.B L
or
.B C
to indicate the table is left-justified or centered.
.LP
.I expand
is
.B y
if the table is expanded to the full line width,
.B n
otherwise.
.LP
The
.I box ,
.I allbox ,
and
.I doublebox
values are each
.B y
or
.B n ,
depending on whether or not
.B box ,
.B allbox ,
and
.B doublebox
were given in the table specification.
(Note that
.B allbox
and
.B doublebox
both imply
.B box .)
.LP
Each table is terminated by a
.Rq T*table*end
request.
.\"
.Bh "Column Information Requests"
.\"
.LP
Following the
.Rq T*table*begin
request,
.I tblcvt
writes one
.Rq T*column*info
line for each column of the table, in the format:
.Ps
\&.T*column*info \f(CIwidth sep equal\fP
.Pe
The column number is not specified;
.Rq T*column*info
lines will appear in consecutive order.
.LP
.I width
is the minimum required width of the column.
The
value is non-zero if any entry in the given column specified
a
.B w
option.
If more than one entry specified
.B w ,
the last one is used.
If
.I width
is 0, no entry in the column specified
.B w
and the width is determined from the data values in the column.
.LP
.I sep
is the column separation value.
.LP
The
.I equal
value is
.B y
if any entry in the column specified the
.B e
option, and
.B n
otherwise.
All columns with an
.I equal
value of
.B y
should be made the same width.
.\"
.Bh "Row Beginning and Ending Requests"
.\"
.LP
If a table row does not consist of a table-width line, the row begins
and ends with
.Rq T*row*begin
and
.Rq T*row*end
requests.
Information for the individual cells is written between these two requests
(see
.H*ahref #cell-requests
"Cell Information Requests"\c
.H*aend
).
.LP
If a row consists of a table-width single or double line, the
.Rq T*row*begin
and
.Rq T*row*end
requests are not used.
Instead, the row is specified
completely by a single
.Rq T*row*line
request, written using one of the following forms:
.Ps
.ne 2
.ta 2i
\&.T*row*line 1	\fRTable-width single line\fP
\&.T*row*line 2	\fRTable-width double line\fP
.Pe
.\"
.H*aname cell-requests
.H*aend
.Bh "Cell Information Requests"
.\"
.LP
Between each pair of
.Rq T*row*begin
and
.Rq T*row*end
requests,
.I tblcvt
writes out the information for each cell (column) in the row.
First a set of
.Rq T*cell*info
lines is written, one for each cell.
These requests provide basic layout parameters.
Then the contents of the cells are written.
For the usual case, a cell is written using
.Rq T*cell*begin
and
.Rq T*cell*end
requests, with the cell data appearing between the requests.
Empty, spanned, or line-drawing cells are written using
.Rq T*empty*cell ,
.Rq T*spanned*cell ,
and
.Rq T*cell*line
requests.
.LP
This means that cells begin with any of
.Rq T*cell*begin ,
.Rq T*empty*cell ,
.Rq T*spanned*cell ,
or
.Rq T*cell*line ,
and end with any of
.Rq T*cell*end ,
.Rq T*empty*cell ,
.Rq T*spanned*cell ,
or
.Rq T*cell*line .
.LP
The
.Rq T*cell*info
request has the following form:
.Ps
\&.T*cell*info \f(CItype vspan hspan vadjust border\fP
.Pe
The column number of the cell is not specified;
.Rq T*cell*info
lines will appear in consecutive order.
.LP
.I type
is the cell type:
.Ps
.ne 5
.ta 1i
L	\fRLeft-justified\fP
R	\fRRight-justified\fP
C	\fRCentered\fP
N	\fRNumeric (align to decimal point)\fP
A	\fRAlphanumeric\fP
.Pe
.I vspan
and
.I hspan
are the number of rows and columns spanned by the cell, including itself.
Interpret these values as follows:
.Ls B
.Li
If a cell spans no other cells, both
.I vspan
and
.I hspan
are 1.
.Li
If a cell spans other cells vertically,
.I vspan
is greater than 1.
If a cell is spanned vertically by a cell from above,
.I vspan
is zero.
.Li
If a cell spans other cells horizontally,
.I hspan
is greater than 1.
If a cell is spanned horizontally by a cell from the left,
.I hspan
is zero.
.Le
If all you want to know is whether or not a cell is spanned, the product of
.I vspan
and
.I hspan
is zero if and only if the cell is spanned.
If you need to know whether spanning is in a particular direction, you
need to examine
.I vspan
and
.I hspan
individually.
This is summarized in the following table.
.sp .5v
.TS
l lfB lfB
lw(1i)fB lw(2i) lw(2i) .
	hspan = 0	hspan > 0
vspan = 0	spanned both ways	spanned from above
vspan > 0	spanned from left	not spanned
.TE
.sp .5v
.I vadjust
is
.B T
if the cell contents should be vertically
adjusted from the top,
.B C
if the contents should be vertically centered.
.I vadjust
is meaningful only for multiple-line cells.
.LP
.I border
is the border value.
If the value is 0, there is no border.
Otherwise, the value is a bitmap with the following fields:
.Ps
.ne 9
.ta 1i 2i
\fRBits	Value	Meaning\fP
0-1	1	\fRLeft border, single line\fP
	2	\fRLeft border, double line\fP
2-3	1	\fRRight border, single line\fP
	2	\fRRight border, double line\fP
4-5	1	\fRTop border, single line\fP
	2	\fRTop border, double line\fP
6-7	1	\fRBottom border, single line\fP
	2	\fRBottom border, double line\fP
.Pe
.LP
The
.Rq T*cell*begin
request has the following form:
.Ps
\&.T*cell*begin \f(CIfont ptsize vspace\fP
.Pe
.I font
is the font to use for formatting the cell, 0 if no font was specified.
.LP
.I ptsize
is the point size to use for formatting the cell, 0 if no size was specified.
.LP
.I vspace
is the vertical spacing to use for formatting the cell, 0 if no spacing
was specified.
.LP
The
.Rq T*cell*end
request has no arguments:
.Ps
\&.T*cell*end
.Pe
If a cell is empty or spanned or draws a line, the
.Rq T*cell*begin
and
.Rq T*cell*end
requests are not used.
Instead, the cell is specified using one of the following requests:
.Ls B
.Li
A cell that has no data is indicated by
.Rq T*empty*cell .
This is functionally equivalent to:
.Ps
.ne 2
\&.T*cell*begin
\&.T*cell*end
.Pe
except that it's not necessary to scan ahead to the second request to
find out that the cell is empty.
.Li
A cell that is spanned by a cell occurring earlier in the
table is indicated by
.Rq T*spanned*cell .
The
.Rq T*cell*info
lines written at the beginning of the row contain the information necessary
to determine whether the cell is spanned from the top or from the left or
both.
Note that that spanned cell may be spanned by a cell with data in it,
an empty cell, or a line-drawing cell.
.Li
A cell that draws a line is indicated by the
.Rq T*cell*line
request, written using one of the following forms:
.Ps
.ne 3
.ta 2i
\&.T*cell*line 0	\fRColumn-data-width single line\fP
\&.T*cell*line 1	\fRColumn-width single line\fP
\&.T*cell*line 2	\fRColumn-width double line\fP
.Pe
A column-data-width line
is a single line as wide as the contents of the column.
It does not extend the full width of the column.
This type of cell results from a
.B \e_
data value in the table specification.
.Le
.\"
.Ah "troffcvt Handling of tblcvt Output"
.\"
.LP
The
.Rq T* \f(BIxxx\fP
requests are defined in the default
.I actions
file that
.I troffcvt
reads when it starts up.
The actions for the requests cause
.I troffcvt
to perform a relatively simple mapping:
.Ps
.ne 12
.ta 3i
\fBtblcvt output	troffcvt output\fP
\&.T*table*begin \f(CIarguments\fP	\etable-begin \f(CIarguments\fP
\&.T*table*end	\etable-end
\&.T*column*info \f(CIarguments\fP	\etable-column-info \f(CIarguments\fP
\&.T*row*begin	\etable-row-begin
\&.T*row*end	\etable-row-end
\&.T*cell*info \f(CIarguments\fP	\etable-cell-info \f(CIarguments\fP
\&.T*cell*begin \f(CIarguments\fP	\etable-cell-begin
\&.T*cell*end	\etable-cell-end
\&.T*row*line \f(CIargument\fP	\etable-row-line \f(CIargument\fP
\&.T*cell*line \f(CIargument\fP	\etable-cell-line \f(CIargument\fP
\&.T*spanned*cell	\etable-spanned-cell
\&.T*empty*cell	\etable-empty-cell
.Pe
When a request written by
.I tblcvt
has arguments, the corresponding control written by
.I troffcvt
is written with arguments that are similar to, but not necessarily
exactly the same.
The primary exception is that the
.I font ,
.I ptsize ,
and
.I vspace
arguments to
.Rq T*cell*begin
are converted directly by the
.I troffcvt
actions file into font and size
.I troff
directives, then translated into the
.I troffcvt
intermediate language.
The font and size controls appear in
.I troffcvt
output immediately following the
.Cl table-cell-begin
control.
See
.H*ahref output.html
.I "troffcvt Output Format and PostProcessor Writing"
.H*aend
for the exact format of the
.Cl table-
controls.
.LP
In addition to the
.Rq T* \f(BIxxx\fP
request names used by
.I tblcvt ,
.I troffcvt
uses the register names
.B T*cell*ft ,
.B T*cell*ps ,
and
.B T*cell*vs
for internal purposes.
.\"
.Ah "Calculating Spans"
.\"
.LP
Table specifications may indicate that
a table element spans multiple rows or columns, or
both.
However, not all spanning specifications are legal, and
.I tblcvt
tries to catch those that are malformed.
The spanning constraints enforced by
.I tblcvt
are:
.Ls B
.Li
A cell cannot span left if there is no column to span into, so the
.B s
format
cannot be used in the first table column.
.Li
A cell cannot span upward if there is no row to span into, so the
.B ^
format
cannot be used in the first table row.
.I tblcvt "" (
does allow
.B ^
to be used on the first format line following
.Rq T& ,
since the column entry can span up into the last row of the previous section.)
.Li
A spanned area must comprise a rectangular block of cells.
.Le
The smallest illegal table specifications that include spans are shown below;
each of them violates one of the first two spanning constraints:
.Ps
.ne 4
.ta 2i
\&.TS	.TS
s .	^ .
\fIdata\fP	\fIdata\fP
\&.TE	.TE
.Pe
Assuming the first two constraints are satisfied, the smallest illegal
table specifications that include spans are shown below
.B l "" (
is used here, but any non-spanning column type may be substituted):
.Ps
.ne 5
.ta 2i
\&.TS	.TS
l l	l s
^ s .	l ^ .
\fIdata\fP	\fIdata\fP
\&.TE	.TE
.Pe
The first table is illegal by the following reasoning.
The cells in the first column form a single vertically-spanned element.
The second column could be part of that element if both cells spanned to
the left, since the resulting spanned area would be rectangular.
However, since only one of the cells spans to the left, the spanned area is
L-shaped, which is illegal.
The second table is illegal by similar reasoning.
The top two cells form a single element.
The bottom two cells could be part of that element if they both spanned
upward, but only one of them does.
.LP
.I tblcvt
uses the strategy outlined below
to determine the extent of spanned elements and to
discover non-rectangularies in cell spanning.
The strategy works by operating on a matrix with one column for each column
specified in the format section of the table specification, and one
row for each row of table
data given in the data section of the specification.
Working from left to right and top to bottom, each cell of the matrix
is visited and the following checks are applied:
.Ls B
.Li
If the current cell format is
.B s
or
.B ^ ,
it's illegal, because it should have been found to be part of
some spanning block to the left or above.
(This check also discovers
.B s
in the first table column and
.B ^
in the first row.)
.Li
If the current cell is not
.B s
or
.B ^ ,
determine how far it spans other cells vertically and horizontally.
The vertical span includes the cell itself and as many consecutive
.B ^ -format
cells that lie below the cell.
The horizontal span is similar, but is determined by the number of consecutive
.B s -format
cells lying to the right of the cell.
Denote the vertical and horizontal span count by
.I vspan
and
.I hspan .
.Li
If
.I vspan
and
.I hspan
are both one, the cell stands alone and doesn't span any other cells.
A standalone cell forms a 1\ \(mu\ 1 rectangle, so the cell is okay.
Mark it as visited and go to the next unvisited cell.
.Li
If
.I vspan
or
.I hspan
(or both) are greater than one, then for the span to be rectangular, the cell
must span a block of
.I vspan\ \(mu\ hspan
cells.
We know that the cells directly to the right of and below the upper left
corner cell are spanned properly, since they determine the span extents.
Therefore,
it's necessary only to examine the
(\fIvspan\fP\^\-1)\ \(mu\ (\fIhspan\fP\^\-1)
block of cells to the immediate lower right of the corner cell.
These cells must span into the left column or top row of the block.
This condition is satisfied if all the cells are of type
.B s
or type
.B ^ ,
in any combination.
(Proof left as an exercise for the reader.\^.\^.)
If the condition is not satisfied, the table specification is illegal.
Otherwise mark the cells in the spanned block as visited and
proceed to the next unvisited cell.
.Le
Some tables are examined below to illustrate the strategy just described.
.LP
.B "Example 1:"
The table shown below is illegal.
.Ps
.ne 5
\&.TS
l s s l
^ s s s .
\fIdata\fP
\&.TE
.Pe
Beginning at the upper left, we see that the vertical and horizontal
spans are 2 and 3.
The remaining cells in this 2\ \(mu\ 3 block are the
second and third cells in the second row.
They both span into the first cell of the second
row, so they are part of the span block.
Therefore, the upper 2\ \(mu\ 3 block is okay.
The next unvisited cell is
the fourth cell in the first row.
This cell is a standalone cell, so it's okay.
The last unvisited cell is
the fourth cell of the second row.
This cell is a spanned cell, but it can't span into the block to the left
without forming a non-rectangular block.
The table specification is bad.
.LP
.B "Example 2:"
Here's a table that appears at first glance as though it may be illegal.
Is it?
.Ps
.ne 6
\&.TS
l s s s
^ s ^ ^
^ ^ s s .
\fIdata\fP
\&.TE
.Pe
Beginning at the upper left, we see that the vertical and horizontal
spans are 3 and 4.
This means 12 cells should be in the span block.
We know that the three
.B s
cells to the right of the corner cell and the two
.B ^
cells below the corner cell are part of the block, so the next step
is to examine the remaining 2\ \(mu\ 3 block at the lower right.
In the second row of the block, the second cell spans left into the first
column (and is thus part of the span block), and the third and fourth
cells span up into the first row (and are thus part of the span block).
In the third row, the second cell spans up into the second row (and is thus
part of the span block since that row has already been determined to be part of
the block), and the third and fourth cells span into the third cell (which,
since that cell has just been determined to be part of the block, makes
the last two cells part of the block as well).
.LP
Therefore, in spite of its unusual specification, the table is legal.
It consists of a single 3\ \(mu\ 4 spanned entry.
.LP
.B "Example 3:"
Span calculations are performed with separate
matrices for vertical and horizontal
spans that initially assume all spans are 1.
Suppose we have a table specification that looks like this:
.Ps
\&.TS
l s l
l s l
^ s l .
a1	a2
b1	b2
c
d
\&.TE
.Pe
There are three format columns.
There are three format rows but four data rows, so the last format line
is used for the third and fourth data rows.
The vertical and horizontal span matrices
are 4\ \(mu\ 3, and start out like this:
.Ps
1  1  1       1  1  1
1  1  1       1  1  1
1  1  1       1  1  1
1  1  1       1  1  1
.Pe
After calculating spans, the matrices end up like this:
.Ps
1  1  1       2  0  1
3  3  1       2  0  1
0  0  1       2  0  1
0  0  1       2  0  1
.Pe
