tables.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* Copyright 1993 Open Software Foundation, Inc., Cambridge, Massachusetts.
* All rights reserved.
*/
/*
#pragma ident "%Z%%M% %I% %E% SMI"
* Copyright (c) 1994
* Open Software Foundation, Inc.
*
* Permission is hereby granted to use, copy, modify and freely distribute
* the software in this file and its documentation for any purpose without
* fee, provided that the above copyright notice appears in all copies and
* that both the copyright notice and this permission notice appear in
* supporting documentation. Further, provided that the name of Open
* Software Foundation, Inc. ("OSF") not be used in advertising or
* publicity pertaining to distribution of the software without prior
* written permission from OSF. OSF makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*/
/*
* Copyright (c) 1996 X Consortium
* Copyright (c) 1995, 1996 Dalrymple Consulting
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the names of the X Consortium and
* Dalrymple Consulting shall not be used in advertising or otherwise to
* promote the sale, use or other dealings in this Software without prior
* written authorization.
*/
/* ________________________________________________________________________
*
* Program to manipulate SGML instances.
*
* Originally coded for OSF DTD tables, now recoded (fld 3/27/95)
* for CALS-type tables (fragment taken from the DocBook DTD). Then,
* *really* upgraded to CALS tables by FLD on 5/28/96.
*
* This module is for handling table markup, printing TeX or tbl
* (tbl) markup to the output stream. Also, table markup checking is
* done here. Yes, this depends on the DTD, but it makes translation
* specs much cleaner (and makes some things possible).
*
* Incomplete / not implemented / limitations / notes:
* vertical alignment (valign attr)
* vertical spanning
* row separators are for the whole line, not per cell (the prog looks
* at rowsep for the 1st cell and applies it to the whole row)
* trusts that units in colwidths are acceptable to LaTeX and tbl
* "s" is an acceptable shorthand for "span" in model attributes
*
* A note on use of OutputString(): Strings with backslashes (\) need lots
* of backslashes. You have to escape them for the C compiler, and escape
* them again for OutputString() itself.
* ________________________________________________________________________
*/
#ifndef lint
static char *RCSid =
#endif
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <memory.h>
#include <errno.h>
#include <tptregexp.h>
#include "general.h"
#include "translate.h"
/* text width of page, in inches */
#define TEXTWIDTH 5.5
#define MAXCOLS 100
#define SPAN_NOT 0
#define SPAN_START 1
#define SPAN_CONT 2
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/*table parameters */
* generating a block of filled text */
/* handy declarations */
/* table line format information structures */
struct tblcolspec {
short num; /* column number */
char alignchar; /* character for alignment */
short aligncharoff; /* offset for alignment */
bool colsep; /* separator to right of column? */
bool rowsep; /* separator to bottom of column? */
short moreRows; /* value for Morerows */
};
struct tblspanspec {
char alignchar; /* character for alignment */
short aligncharoff; /* offset for alignment */
bool colsep; /* separator to right of column? */
bool rowsep; /* separator to bottom of column? */
};
struct tblformat {
short count; /* count of rows matching this spec */
short cols; /* # of columns */
short rowNum; /* row number */
};
/* table state info */
static short tblcols = 0; /* number of columns in the table */
static short tblrow = 0; /* the current row in the table */
static char * tblFrame; /* table frame info */
static bool tblgcolsep; /* global colsep (in table) */
static bool tblgrowsep; /* global rowsep (in table) */
static int tblBOFTCount = 0; /* count of bofts that we've created
* (per table) */
int BOFTTextThresh = BOFTTHRESHOLD;
/* length of text before we
* call it a BOFT */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
/* these cover the attributes on the Table, TGroup, Colspec elements */
typedef struct {
char *cols;
char *colwidth, **colwidth_v;
char *frame;
char *orient;
int pgwide;
int nc;
} TableInfo;
/* some flags, set when the table tag is processed, used later */
/* forward references */
void FreeTabAtts(TableInfo *);
void ClearTable(TableInfo *);
void CheckTable(Element_t *);
int TblCountContent(Element_t *);
/* ______________________________________________________________________ */
/* Hard-coded stuff for CALS-style DTD tables.
* Here are the TABLE attributes (for handy reference):
*
* Colsep NUMBER separate all columns in table?
* Frame (Top|Bottom|Topbot|All|Sides|None) frame style
* Orient (Port | Land) orientation
* Pgwide NUMBER wide table?
* Rowsep NUMBER separate all rows in the table?
* Tabstyle NMTOKEN FOSI table style
*
* TGroup:
* Align (Left|Right|Center|Justify|Char) alignment of cols
* Char CDATA Alignment specifier
* Charoff NUTOKEN "" ""
* Cols NUMBER number of columns
* Colsep NUMBER separate all columns in tgroup?
* Rowsep NUMBER separate all rows in tgroup?
* TGroupstyle NMTOKEN FOSI table group style
*
* Colspec:
* Align (Left|Right|Center|Justify|Char) entry align
* Char CDATA Alignment specifier
* Charoff NUTOKEN "" ""
* Colname NMTOKEN Column identifier
* Colnum NUMBER number of column
* Colsep NUMBER separate this col from next?
* Colwidth CDATA width spec
* Rowsep NUMBER serarate entry from following row?
*
* SpanSpec:
* Align (Left|Right|Center|Justify|Char) entry align
* Char CDATA Alignment specifier
* Charoff NUTOKEN "" ""
* Colsep NUMBER separate this col from next?
* Nameend NMTOKEN name of rightmost col of a span
* Namest NMTOKEN name of leftmost col of a span
* Rowsep NUMBER serarate entry from following row?
* Spanname NMTOKEN name of a horiz. span
*
* VAlign (Top | Middle | Bottom) group placement
*
* Row:
* Rowsep NUMBER separate this row from next?
* VAlign (Top | Middle | Bottom) row placement
*
* Entry:
* Align (Left|Right|Center|Justify|Char) entry align
* Char CDATA Alignment specifier
* Charoff NUTOKEN "" ""
* Colname NMTOKEN Column identifier
* Colsep NUMBER separate this col from next?
* Morerows NUMBER number of addn'l rows in vert straddle
* Nameend NMTOKEN name of rightmost col of a span
* Namest NMTOKEN name of leftmost col of a span
* Rotate NUMBER 90 degree rotation counterclockwise to table?
* Rowsep NUMBER serarate entry from following row?
* Spanname NMTOKEN name of a horiz. span
* VAlign (Top | Middle | Bottom) text vert alignment
*
*
** OBSOLETE OSF DTD FORM (still used for TeX form):
** Usage in transpec: _calstable [tex|check|clear] ['aspect']
** where 'aspect' is:
** rowstart stuff to do at start of a row (tests for spanning)
** rowend stuff to do at end of a row (eg, rules, etc.)
** cellstart stuff to do at start of a cell (eg, handle actual
** spanning instructions, etc.)
** cellend stuff to do at end of a cell (eg, cell separator)
** top stuff to do at top of the table
** (like whether or not it needs a starting horiz rule)
** bottom stuff to do at bottom of the table
** (like whether or not it needs an ending horiz rule)
** (nothing) the 'cols' param to LaTeX's \begin{tabular}[pos]{cols}
** or 'options' and 'formats' part in tbl
*
*
* New tbl form:
* Usage in transpec: _calstable [tbl] ['aspect']
* where 'aspect' is:
* tablestart start a table and do style info
* tableend end the table and clean up
* tablegroup table TGroup (.T& if not 1st, line format info)
* tablegroupend end a TGroup
* tablefoot TFoot within a TGroup
* rowstart start of a row
* rowend end of a row
* entrystart start of an entry (block of filled text, if
* appropriate)
* entryend end of a cell (eg, cell separator)
*/
/* Procedure to
* Arguments:
* Pointer to element under consideration.
* FILE pointer to where to write output.
* Vector of args to _osftable
* Count of args to _osftable
*/
void
Element_t *e,
char **av,
int ac
)
{
/* Check params and dispatch to appropriate routine */
if (ac > 2) {
}
else {
}
}
else
if (ac > 2) {
}
}
}
/* ClearTable -- start a new table process
*
*/
void
ClearTable( TableInfo * t )
{
}
/* ______________________________________________________________________ */
/* Set values of the our internal table structure based on the table's
* attributes. (This is called for tables, tgroups, colspecs, and rows,
* since tables and rows share many of the same attributes.)
* Arguments:
* Pointer to element under consideration.
* Pointer table info structure which will be filled in.
* Flag saying whether or not to set global variables based on attrs.
*/
void
Element_t *e,
TableInfo *t,
int set_globals
)
{
char *at;
/* remember values of attributes */
/* Set some things for later when processing this table */
if (set_globals) {
rowsep = 1;
/* For now we look at the first number of rowsep - it controls the
* horiz rule for then entire row. (not easy to specify lines that
* span only some columns in tex or tbl. */
}
if (t->frame) {
/* Top|Bottom|Topbot|All|Sides|None */
}
/* tbl and tex like lower case for units. convert. */
if (t->colwidth) {
char *cp;
}
/* Now, split (space-separated) strings into vectors. Hopefully, the
* number of elements in each vector matches the number of columns.
*/
/* Determin the _numeric_ number of columns, "nc". MUST be specified
* in Cols attribute of TGroup element.
*/
}
/* ______________________________________________________________________ */
/* Free the storage of info use by the table info structure. (not the
* structure itself, but the strings its elements point to)
* Arguments:
* Pointer table info structure to be freed.
*/
void
TableInfo *t
)
{
if (!t) return;
}
/* ______________________________________________________________________ */
/* Check the attributes and children of the table pointed to by e.
* Report problems and inconsistencies to stderr.
* Arguments:
* Pointer to element (table) under consideration.
*/
void
Element_t *e
)
{
int pr_loc=0; /* flag to say if we printed location */
int i, r, c;
float wt;
char *ncolchk =
"Table Check: %s ('%s') has wrong number of tokens. Expecting %d.\n";
return;
}
#if FALSE
/* NCOLS attribute set? */
pr_loc++;
}
/* ALIGN attribute set? */
pr_loc++;
}
/* See if the number of cells in each row matches */
continue;
pr_loc++;
}
}
}
}
#endif
/* Check ALIGN */
pr_loc++;
}
else { /* values OK? */
pr_loc++;
}
}
}
}
/* check COLWIDTH */
pr_loc++;
}
else { /* values OK? */
/* check that the units after the numbers are OK
we want "in", "cm".
*/
}
}
}
/* check COLSEP */
pr_loc++;
}
else { /* values OK? */
}
}
}
if (pr_loc) {
PrintLocation(e, stderr);
}
}
/* ______________________________________________________________________ */
/* Look at colspec attribute for spanning. If set, remember info for when
* doing the cells. Called by TblTableRowStart() and TexTableRowStart().
* Arguments:
* Pointer to element (row) under consideration.
*/
int
Element_t *e
)
{
char *at;
char **spans;
int n, i, inspan;
#if FALSE /* NOT IMPLEMENTED RIGHT NOW */
/* See if COLSPEC element present */
for (i=0; i < e->necont; i++) {
}
/* Split into tokens, then look at each for the word "span" */
/* Mark columns as start-of-span, in-span, or not spanned. Remember
* in at list, "spaningo". (Span does not make sense in 1st column.)
*/
for (i=1,inspan=0; i<n; i++) {
inspan = 1;
}
else {
inspan = 0;
}
}
return 1;
}
/* if model not set, mark all as not spanning */
else
#endif /* NOT CURRENTLY IMPLEMENTED */
return 0;
}
/* ______________________________________________________________________ */
/* Do the "right thing" for the table spec for TeX tables. This will
* generate the arg to \begin{tabular}[xxx].
* Arguments:
* Pointer to element (table) under consideration.
* FILE pointer to where to write output.
*/
void
Element_t *e,
)
{
int i, n;
float tot;
/* Figure out the widths, based either on "colwidth".
*/
}
siderules = 1;
siderules = 0;
/* If width specified, use it; else if align set, use it; else left. */
}
}
else
/* See if we want column separators. */
}
}
}
}
}
}
/*
* Arguments:
* Pointer to element (cell) under consideration.
* FILE pointer to where to write output.
*/
void
Element_t *e,
)
{
int n, i;
else break;
}
}
#ifdef New
/* no span, but user wants to change the alignment */
OutputString("\\\\multicolumn{1}{%sc%s}", n,
fp, 1);
}
#endif
}
/*
* Arguments:
* Pointer to element (cell) under consideration.
* FILE pointer to where to write output.
*/
void
Element_t *e,
)
{
}
}
/* Look at model for spanning. If set, remember it for when doing the cells.
* Arguments:
* Pointer to element (row) under consideration.
* FILE pointer to where to write output.
*/
void
Element_t *e,
)
{
check_for_spans(e);
}
/*
* Arguments:
* Pointer to element (row) under consideration.
* FILE pointer to where to write output.
*/
void
Element_t *e,
)
{
char *at;
/* check this row's attributes */
}
else
}
/*
* Arguments:
* Pointer to element (table) under consideration.
* FILE pointer to where to write output.
*/
void
{
}
void
{
}
/* ______________________________________________________________________ */
/* ______________________________________________________________________ */
/* ______________________________________________________________________ */
/* ______________________________________________________________________ */
/* ______________________________________________________________________ */
/* ___________________________| |____________________________ */
/* ___________________________| TBL STUFF |____________________________ */
/* ___________________________| |____________________________ */
/* ___________________________|_____________|____________________________ */
/* ______________________________________________________________________ */
/* ______________________________________________________________________ */
/* ______________________________________________________________________ */
/* ______________________________________________________________________ */
/* TblTStart() -- start a table and do style information
*
* TO DO:
*
* do .TS
* find global rowsep and colsep
*/
void
{
register char * cp;
tblBOFTCount = 0; /* count of Blocks of Filled Text that
* we've created */
}
/* TblTEnd() -- end a table and do any cleanup
*
* TO DO:
*
* do .TE
*
* deallocate format line info
*/
void
{
/* defed out since this message does not apply to SunOS and errors are
* passed on to tbl
*/
#ifdef notdef
if ( tblBOFTCount > 31 ) {
}
#endif
}
formP = 0;
}
/* TblTTGroup() -- do body work (row format info)
*
* TO DO:
*
* set number of columns
*
* if this is the first TGroup of this table, do style info:
* a. alignment
* b. defaults: tab
* c. box vx allbox
*
* do format info:
* a. generate tableformat structure
* b. output it
*
* prepare structures for colspecs and spanspecs
*
*/
void
{
register int i, j, k;
tblColSpec = 0; /* make sure they're clear */
tblSpanSpec = 0;
/* set the number of columns */
/* do colspecs */
/* do TGroup first -- it becomes the default */
}
}
}
}
}
}
}
}
}
}
}
/* do spanspecs */
/* do TGroup first -- it becomes the default */
}
}
/* if this is the first TGroup in this table, do style stuff */
if ( ! tblTGroupSeen ) {
tblFrame = "";
else
}
}
}
/* do format stuff -- step through all THead rows then all TBody
* rows. Build a list of tblformats that describe all of them.
* then output the resulting list.
*/
/* add in those rows */
break;
}
}
/* add in those rows */
break;
}
}
tblrow = 0; /* the current row within this format */
}
/* TblTGroupEnd() -- end a TGroup
*
* TO DO:
*
* deallocate colspecs and spanspecs
*/
void
{
}
}
}
/* TblTTFoot() -- do body foot work (row format info)
*
* TO DO:
*
* do format info:
* a. generate tableformat structure
* i. if it is only 1 line long and matches the
* prevailing format, just output rows.
* ii. else, output a .T& and the new format specs
*/
void
{
;
}
}
tblrow = 0; /* the current row within this format */
}
/* TblBuildFormat() -- build a format structure out of a set of
* rows and columns
*
*/
void
* building */
{
register int i;
; /* find end of format list */
break; /* find where rows start */
/* do one row */
if ( !lfp )
else
else {
}
}
}
/* TblBuild1Format() -- build one row's worth of format information
*
*/
struct tblformat *
bool addinRowsep, /* insert rowsep into model? */
{
register int i;
register bool allProp;
float totalProp;
totalProp = 0;
for ( i=1; i <= tblcols; i++ ) {
if ( allProp ) {
}
if ( addinRowsep )
}
}
/* turn proportional widths into real widths */
if ( allProp ) {
for ( i=1; i <= tblcols; i++ ) {
}
}
return tfp;
}
/* TblGetAlign() -- get alignment spec for a entry
*
*/
char
{
register struct tblcolspec * tcsp;
register struct tblspanspec * tssp;
} else
} else {
return 'l';
}
switch ( talign ) {
case Left: return 'l';
case Right: return 'r';
case Center: return 'c';
case Justify: return 'l';
case Char: return 'd';
case Span: return 's';
}
}
/* TblGetWidth() -- get width spec, if any, for a entry
*
*/
char *
bool literal, /* literal (or proportional) */
{
register struct tblcolspec * tcsp;
register struct tblspanspec * tssp;
colWidth[0] = 0;
if ( entry &&
if ( literal )
} else {
if ( ! literal )
}
}
return colWidth;
}
/* TblGetFont() -- get font spec, if any, for a entry
*
*/
char *
{
register struct tblcolspec * tcsp;
register struct tblspanspec * tssp;
return "";
}
/* TblGetColSep() -- get column separater spec, if any, for a entry
*
*/
bool
{
register struct tblcolspec * tcsp;
register struct tblspanspec * tssp;
register bool colsep;
} else
} else
return colsep;
}
/* TblGetRowSep() -- get row separater spec, if any, for a entry
*
*/
bool
{
register struct tblcolspec * tcsp;
register struct tblspanspec * tssp;
register bool rowsep;
} else
} else {
}
return rowsep;
}
/* TblGetmoreRows() -- get moreRows value
*
*/
bool
{
register char * cp;
else
return 0;
}
/* TblColAdv() -- advance pointer to next entry, if appropriate
*
*/
bool
{
register bool bump;
register struct tblspanspec * tssp;
}
return bump;
}
/* TblEntryColSpec() -- get a completely localized colspec for an entry
*
*/
struct tblcolspec *
{
register int i;
register bool throwAway;
register char * cp;
}
}
}
if ( throwAway )
return tcsp2;
}
/* TblEntrySpanSpec() -- get a completely localized spanspec for an entry
*
*/
struct tblspanspec *
{
tssp2 = 0;
return 0;
}
}
return tssp;
}
/* TblFormatMatch() -- compare two format rows for consistency
*
*/
bool
{
register int i;
return FALSE;
}
return FALSE;
}
return FALSE;
}
return FALSE;
}
return FALSE;
}
return FALSE;
}
return FALSE;
}
}
return TRUE;
}
/* TblPrintFormat() -- print a tbl format structure
*
*/
void
{
register int i;
if ( i > 1 )
else {
}
}
}
}
}
/* TblTRowStart() -- start a row (not much to do)
*
* TO DO:
*
* nothing..
*
*/
void
{
/* nothing to do */
tblrow++; /* except note that we're within a new row */
}
/* TblTRowEnd() -- end a row
*
* TO DO:
*
* output a row end character (newline)
* if the current row had a rowsep, then output a "fake" row
* with underlines in the proper place(s).
*/
void
{
register int i, k;
register bool startedRow, didSep;
/* get the format for this row */
else
else
startedRow = FALSE;
if ( ! startedRow ) {
for ( k=1; k < i; k++ )
startedRow = TRUE;
}
} else {
if ( startedRow )
}
}
if ( startedRow )
}
/* TblTEntryStart() -- start an entry (block of filled text if
* appropriate)
*
* TO DO:
*
* if text length > BOFTTextThresh or there is PI,
* then output "T{\n", else do nothing
*
*/
void
{
register int i;
register bool sawPIorPara;
(i &&
sawPIorPara = TRUE;
break;
}
}
tblBOFTCount++;
}
}
/* TblCountContent() -- count all content below the given element
*
*
*/
int
{
register int i, count;
register char * cp;
count = 0;
if ( *cp == -1 )
return BOFTTextThresh + 1;
} else
}
}
return count;
}
/* TblTEntryEnd() -- end an entry
*
* TO DO:
*
* if within BOFT, output "T}"
* if not last entry, output tab character
*
*/
void
{
if ( tblinBOFT ) {
}
break;
}
break;
}
}
/* TblDoColSpec() -- process one element to create a new colspec
*
*
*/
struct tblcolspec *
{
register char * cp;
register struct tblcolspec * tcsp;
} else
else
else
else
else
else
return tcsp;
}
/* TblDoSpanSpec() -- process one element to create a new spanspec
*
* Note that there's a hack inside here... NameSt and NameEnd are
* supposed to point at colnames, but if no colname is found, this
* code will look for a colnum by the same value.
*/
struct tblspanspec *
{
register char * cp;
register struct tblspanspec * tssp;
register struct tblcolspec * tcsp;
} else {
}
} else {
}
}
} else {
}
} else {
}
}
} else {
if ( pssp )
}
else {
if ( pssp )
}
else {
if ( pssp )
}
else {
if ( pssp )
}
else {
if ( pssp )
}
return tssp;
}
/* TblFindColSpec() -- find a table colspec by name (colname)
*
*/
struct tblcolspec *
{
register struct tblcolspec * tcsp;
/* first, try to find the one in the right "source" */
return tcsp;
}
/* else, try to find one from a TGroup.. */
return tcsp;
}
/* else not found.. */
return 0;
}
/* TblFindColNum() -- find a table colspec by number
*
*/
struct tblcolspec *
{
register struct tblcolspec * tcsp;
/* first, try to find the one in the right "source" */
return tcsp;
}
/* else, try to find one from a TGroup.. */
return tcsp;
}
/* else not found.. */
return 0;
}
/* TblFindSpanSpec() -- find a table spanspec by name (spanname)
*
*/
struct tblspanspec *
{
register struct tblspanspec * tssp;
/* first, try to find the one in the right "source" */
return tssp;
}
/* else not found.. */
return 0;
}