2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: tables.c /main/3 1996/12/07 13:15:23 rws $ */
25 * Copyright 1993 Open Software Foundation, Inc., Cambridge, Massachusetts.
26 * All rights reserved.
30 * Open Software Foundation, Inc.
32 * Permission is hereby granted to use, copy, modify and freely distribute
33 * the software in this file and its documentation for any purpose without
34 * fee, provided that the above copyright notice appears in all copies and
35 * that both the copyright notice and this permission notice appear in
36 * supporting documentation. Further, provided that the name of Open
37 * Software Foundation, Inc. ("OSF") not be used in advertising or
38 * publicity pertaining to distribution of the software without prior
39 * written permission from OSF. OSF makes no representations about the
40 * suitability of this software for any purpose. It is provided "as is"
41 * without express or implied warranty.
44 * Copyright (c) 1996 X Consortium
45 * Copyright (c) 1995, 1996 Dalrymple Consulting
47 * Permission is hereby granted, free of charge, to any person obtaining a copy
48 * of this software and associated documentation files (the "Software"), to deal
49 * in the Software without restriction, including without limitation the rights
50 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
51 * copies of the Software, and to permit persons to whom the Software is
52 * furnished to do so, subject to the following conditions:
54 * The above copyright notice and this permission notice shall be included in
55 * all copies or substantial portions of the Software.
57 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
58 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
59 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
60 * X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
61 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
62 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
63 * OTHER DEALINGS IN THE SOFTWARE.
65 * Except as contained in this notice, the names of the X Consortium and
66 * Dalrymple Consulting shall not be used in advertising or otherwise to
67 * promote the sale, use or other dealings in this Software without prior
68 * written authorization.
70 /* ________________________________________________________________________
72 * Program to manipulate SGML instances.
74 * Originally coded for OSF DTD tables, now recoded (fld 3/27/95)
75 * for CALS-type tables (fragment taken from the DocBook DTD). Then,
76 * *really* upgraded to CALS tables by FLD on 5/28/96.
78 * This module is for handling table markup, printing TeX or tbl
79 * (tbl) markup to the output stream. Also, table markup checking is
80 * done here. Yes, this depends on the DTD, but it makes translation
81 * specs much cleaner (and makes some things possible).
83 * Incomplete / not implemented / limitations / notes:
84 * vertical alignment (valign attr)
86 * row separators are for the whole line, not per cell (the prog looks
87 * at rowsep for the 1st cell and applies it to the whole row)
88 * trusts that units in colwidths are acceptable to LaTeX and tbl
89 * "s" is an acceptable shorthand for "span" in model attributes
91 * A note on use of OutputString(): Strings with backslashes (\) need lots
92 * of backslashes. You have to escape them for the C compiler, and escape
93 * them again for OutputString() itself.
94 * ________________________________________________________________________
102 #include <sys/types.h>
105 #include <tptregexp.h>
107 #include "translate.h"
109 /* text width of page, in inches */
110 #define TEXTWIDTH 5.5
116 /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
117 /*table parameters */
119 #define TBLMAXCOL 30 /* max number of columns in tbl table */
120 #define NAMELEN 40 /* max length of a name */
121 #define BOFTTHRESHOLD 35 /* text length over which to consider
122 * generating a block of filled text */
125 /* handy declarations */
127 typedef enum { Left, Right, Center, Justify, Char, Span } tblalign;
129 typedef enum { TGroup, THead, TFoot, TBody } tblsource; /* source of a spec */
132 /* table line format information structures */
136 char name[NAMELEN]; /* colspec's name */
137 short num; /* column number */
138 tblsource source; /* where defined */
140 tblalign align; /* column's alignment */
141 char alignchar; /* character for alignment */
142 short aligncharoff; /* offset for alignment */
143 char colwidth[10]; /* width for column */
144 char colpwidth[10]; /* proportional widths for column */
145 bool colsep; /* separator to right of column? */
146 bool rowsep; /* separator to bottom of column? */
147 short moreRows; /* value for Morerows */
149 struct tblcolspec * next; /* next colspec */
154 char name[NAMELEN]; /* spanspec's name */
155 tblsource source; /* where defined */
157 struct tblcolspec * start; /* start column */
158 struct tblcolspec * end; /* end column */
159 tblalign align; /* span's alignment */
160 char alignchar; /* character for alignment */
161 short aligncharoff; /* offset for alignment */
162 bool colsep; /* separator to right of column? */
163 bool rowsep; /* separator to bottom of column? */
165 struct tblspanspec * next; /* next spanspec */
169 short count; /* count of rows matching this spec */
171 short cols; /* # of columns */
172 short rowNum; /* row number */
173 char colformat[TBLMAXCOL]; /* per-column formats */
174 char colwidth[TBLMAXCOL][10]; /* per-column widths */
175 char colpwidth[TBLMAXCOL][10]; /* per-column proportional widths */
176 char font[TBLMAXCOL][3]; /* column fonts (headers) */
177 bool colsep[TBLMAXCOL]; /* column separators */
178 bool rowsep[TBLMAXCOL]; /* row separators */
179 short moreRows[TBLMAXCOL]; /* moreRows indicator */
181 struct tblformat * next; /* for the next row */
185 /* table state info */
187 static short tblcols = 0; /* number of columns in the table */
188 static short tblrow = 0; /* the current row in the table */
190 static bool tblTGroupSeen = FALSE; /* seen a TGroup in this table yet? */
192 static char * tblFrame; /* table frame info */
193 static bool tblgcolsep; /* global colsep (in table) */
194 static bool tblgrowsep; /* global rowsep (in table) */
196 static int tblBOFTCount = 0; /* count of bofts that we've created
198 int BOFTTextThresh = BOFTTHRESHOLD;
199 /* length of text before we
201 static bool tblboft = FALSE; /* within a block of filled text? */
202 static bool tblinBOFT = FALSE; /* within a boft now? */
204 static struct tblformat * formP = 0; /* THead/TBody format lines */
206 static struct tblcolspec * tblColSpec = 0; /* colspec structure for table */
207 static struct tblspanspec * tblSpanSpec = 0; /* spanspec structure for table */
209 /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
211 /* these cover the attributes on the Table, TGroup, Colspec elements */
214 char *align, **align_v;
215 char *colwidth, **colwidth_v;
216 char *colsep, **colsep_v;
217 char *rowsep, **rowsep_v;
221 int n_align, n_model, n_colwidth, n_colsep;
226 /* some flags, set when the table tag is processed, used later */
227 static int rowsep, siderules;
228 static int frametop, framebot, frameall;
229 static char basemodel[128]; /* model for table (in formatting language) */
230 static int spaninfo[MAXCOLS]; /* 100 columns, max */
231 static TableInfo TheTab;
233 /* forward references */
234 void SetTabAtts(Element_t *, TableInfo *, int);
235 void FreeTabAtts(TableInfo *);
236 void ClearTable(TableInfo *);
237 void CheckTable(Element_t *);
238 void TblTStart(Element_t *, FILE *);
239 void TblTEnd(Element_t *, FILE *);
240 void TblTGroup(Element_t *, FILE *);
241 void TblTGroupEnd(Element_t *, FILE *);
242 void TblTFoot(Element_t *, FILE *);
243 void TblBuildFormat(Element_t *, struct tblformat **, tblsource);
244 struct tblformat * TblBuild1Format(Element_t *, bool, tblsource);
245 char TblGetAlign(short, Element_t *, tblsource);
246 char * TblGetWidth(short, Element_t *, bool, tblsource);
247 char * TblGetFont(short, Element_t *, tblsource);
248 bool TblGetColSep(short, Element_t *, tblsource);
249 bool TblGetRowSep(short, Element_t *, tblsource);
250 short TblGetMoreRows(short, Element_t *, tblsource);
251 bool TblColAdv(short, Element_t *, struct tblformat *, tblsource);
252 struct tblcolspec * TblEntryColSpec(short, Element_t *, tblsource);
253 struct tblspanspec * TblEntrySpanSpec(short, Element_t *, tblsource);
254 bool TblFormatMatch(struct tblformat *, struct tblformat *);
255 void TblPrintFormat(FILE *, struct tblformat *);
256 void TblTRowStart(Element_t *, FILE *);
257 void TblTRowEnd(Element_t *, FILE *);
258 void TblTCellStart(Element_t *, FILE *);
259 int TblCountContent(Element_t *);
260 void TblTCellEnd(Element_t *, FILE *);
261 struct tblcolspec * TblDoColSpec(short, Element_t *, struct tblcolspec *, tblsource);
262 struct tblspanspec * TblDoSpanSpec(Element_t *, struct tblspanspec *, tblsource);
263 struct tblcolspec * TblFindColSpec(char *, tblsource);
264 struct tblcolspec * TblFindColNum(short, tblsource);
265 struct tblspanspec * TblFindSpanSpec(char *, tblsource);
266 void TexTable(Element_t *, FILE *);
267 void TexTableCellStart(Element_t *, FILE *);
268 void TexTableCellEnd(Element_t *, FILE *);
269 void TexTableRowStart(Element_t *, FILE *);
270 void TexTableRowEnd(Element_t *, FILE *);
271 void TexTableTop(Element_t *, FILE *);
272 void TexTableBottom(Element_t *, FILE *);
274 /* ______________________________________________________________________ */
275 /* Hard-coded stuff for CALS-style DTD tables.
276 * Here are the TABLE attributes (for handy reference):
278 * Table/InformalTable:
279 * Colsep NUMBER separate all columns in table?
280 * Frame (Top|Bottom|Topbot|All|Sides|None) frame style
281 * Orient (Port | Land) orientation
282 * Pgwide NUMBER wide table?
283 * Rowsep NUMBER separate all rows in the table?
284 * Tabstyle NMTOKEN FOSI table style
287 * Align (Left|Right|Center|Justify|Char) alignment of cols
288 * Char CDATA Alignment specifier
289 * Charoff NUTOKEN "" ""
290 * Cols NUMBER number of columns
291 * Colsep NUMBER separate all columns in tgroup?
292 * Rowsep NUMBER separate all rows in tgroup?
293 * TGroupstyle NMTOKEN FOSI table group style
296 * Align (Left|Right|Center|Justify|Char) entry align
297 * Char CDATA Alignment specifier
298 * Charoff NUTOKEN "" ""
299 * Colname NMTOKEN Column identifier
300 * Colnum NUMBER number of column
301 * Colsep NUMBER separate this col from next?
302 * Colwidth CDATA width spec
303 * Rowsep NUMBER serarate entry from following row?
306 * Align (Left|Right|Center|Justify|Char) entry align
307 * Char CDATA Alignment specifier
308 * Charoff NUTOKEN "" ""
309 * Colsep NUMBER separate this col from next?
310 * Nameend NMTOKEN name of rightmost col of a span
311 * Namest NMTOKEN name of leftmost col of a span
312 * Rowsep NUMBER serarate entry from following row?
313 * Spanname NMTOKEN name of a horiz. span
316 * VAlign (Top | Middle | Bottom) group placement
319 * Rowsep NUMBER separate this row from next?
320 * VAlign (Top | Middle | Bottom) row placement
323 * Align (Left|Right|Center|Justify|Char) entry align
324 * Char CDATA Alignment specifier
325 * Charoff NUTOKEN "" ""
326 * Colname NMTOKEN Column identifier
327 * Colsep NUMBER separate this col from next?
328 * Morerows NUMBER number of addn'l rows in vert straddle
329 * Nameend NMTOKEN name of rightmost col of a span
330 * Namest NMTOKEN name of leftmost col of a span
331 * Rotate NUMBER 90 degree rotation counterclockwise to table?
332 * Rowsep NUMBER serarate entry from following row?
333 * Spanname NMTOKEN name of a horiz. span
334 * VAlign (Top | Middle | Bottom) text vert alignment
337 ** OBSOLETE OSF DTD FORM (still used for TeX form):
338 ** Usage in transpec: _calstable [tex|check|clear] ['aspect']
339 ** where 'aspect' is:
340 ** rowstart stuff to do at start of a row (tests for spanning)
341 ** rowend stuff to do at end of a row (eg, rules, etc.)
342 ** cellstart stuff to do at start of a cell (eg, handle actual
343 ** spanning instructions, etc.)
344 ** cellend stuff to do at end of a cell (eg, cell separator)
345 ** top stuff to do at top of the table
346 ** (like whether or not it needs a starting horiz rule)
347 ** bottom stuff to do at bottom of the table
348 ** (like whether or not it needs an ending horiz rule)
349 ** (nothing) the 'cols' param to LaTeX's \begin{tabular}[pos]{cols}
350 ** or 'options' and 'formats' part in tbl
354 * Usage in transpec: _calstable [tbl] ['aspect']
356 * tablestart start a table and do style info
357 * tableend end the table and clean up
358 * tablegroup table TGroup (.T& if not 1st, line format info)
359 * tablegroupend end a TGroup
360 * tablefoot TFoot within a TGroup
361 * rowstart start of a row
362 * rowend end of a row
363 * entrystart start of an entry (block of filled text, if
365 * entryend end of a cell (eg, cell separator)
370 * Pointer to element under consideration.
371 * FILE pointer to where to write output.
372 * Vector of args to _osftable
373 * Count of args to _osftable
383 /* Check params and dispatch to appropriate routine */
385 if (!strcmp(av[1], "tbl")) {
388 if (!strcmp(av[2], "tablestart")) TblTStart(e, fp);
389 else if (!strcmp(av[2], "tableend")) TblTEnd(e, fp);
390 else if (!strcmp(av[2], "tablegroup")) TblTGroup(e, fp);
391 else if (!strcmp(av[2], "tablegroupend")) TblTGroupEnd(e, fp);
392 else if (!strcmp(av[2], "tablefoot")) TblTFoot(e, fp);
393 else if (!strcmp(av[2], "rowstart")) TblTRowStart(e, fp);
394 else if (!strcmp(av[2], "rowend")) TblTRowEnd(e, fp);
395 else if (!strcmp(av[2], "entrystart")) TblTCellStart(e, fp);
396 else if (!strcmp(av[2], "entryend")) TblTCellEnd(e, fp);
397 else fprintf(stderr, "Unknown %s table instruction: %s\n",
401 fprintf(stderr, "Incomplete %s table instruction\n", av[1]);
405 else if (!strcmp(av[1], "tex")) {
407 if (ac > 1 && !strcmp(av[1], "check")) CheckTable(e);
410 if (ac > 1 && !strcmp(av[1], "clear")) ClearTable(&TheTab);
413 if (!strcmp(av[2], "cellstart")) TexTableCellStart(e, fp);
414 else if (!strcmp(av[2], "cellend")) TexTableCellEnd(e, fp);
415 else if (!strcmp(av[2], "rowstart")) TexTableRowStart(e, fp);
416 else if (!strcmp(av[2], "rowend")) TexTableRowEnd(e, fp);
417 else if (!strcmp(av[2], "top")) TexTableTop(e, fp);
418 else if (!strcmp(av[2], "bottom")) TexTableBottom(e, fp);
419 else fprintf(stderr, "Unknown %s table instruction: %s\n",
422 else TexTable(e, fp);
425 else fprintf(stderr, "Unknown table type: %s\n", av[1]);
429 /* ClearTable -- start a new table process
435 ClearTable( TableInfo * t )
437 memset(t, 0, sizeof(TableInfo));
441 /* ______________________________________________________________________ */
442 /* Set values of the our internal table structure based on the table's
443 * attributes. (This is called for tables, tgroups, colspecs, and rows,
444 * since tables and rows share many of the same attributes.)
446 * Pointer to element under consideration.
447 * Pointer table info structure which will be filled in.
448 * Flag saying whether or not to set global variables based on attrs.
460 /* remember values of attributes */
461 if ((at = FindAttValByName(e, "ALIGN"))) t->align = at;
462 if ((at = FindAttValByName(e, "COLWIDTH"))) t->colwidth = at;
463 if ((at = FindAttValByName(e, "COLSEP"))) t->colsep = at;
464 if ((at = FindAttValByName(e, "FRAME"))) t->frame = at;
465 if ((at = FindAttValByName(e, "COLS"))) t->cols = at;
467 /* Set some things for later when processing this table */
471 frametop = framebot = 1; /* default style */
473 /* For now we look at the first number of rowsep - it controls the
474 * horiz rule for then entire row. (not easy to specify lines that
475 * span only some columns in tex or tbl. */
476 if ((at = FindAttValByName(e, "ROWSEP"))) rowsep = atoi(at);
480 /* Top|Bottom|Topbot|All|Sides|None */
481 if (!strcmp(t->frame, "NONE") || !strcmp(t->frame, "SIDES"))
482 frametop = framebot = 0;
483 else if (!strcmp(t->frame, "TOP")) framebot = 0;
484 else if (!strcmp(t->frame, "BOTTOM")) frametop = 0;
487 /* tbl and tex like lower case for units. convert. */
490 for (cp=t->colwidth; *cp; cp++)
491 if (isupper(*cp)) *cp = tolower(*cp);
494 /* Now, split (space-separated) strings into vectors. Hopefully, the
495 * number of elements in each vector matches the number of columns.
497 t->align_v = Split(t->align, &t->n_align, S_STRDUP|S_ALVEC);
498 t->colwidth_v = Split(t->colwidth, &t->n_colwidth, S_STRDUP|S_ALVEC);
499 t->colsep_v = Split(t->colsep, &t->n_colsep, S_STRDUP|S_ALVEC);
501 /* Determin the _numeric_ number of columns, "nc". MUST be specified
502 * in Cols attribute of TGroup element.
504 if (t->cols) t->nc = atoi(t->cols);
507 /* ______________________________________________________________________ */
509 /* Free the storage of info use by the table info structure. (not the
510 * structure itself, but the strings its elements point to)
512 * Pointer table info structure to be freed.
520 if (t->align_v) free(*t->align_v);
521 if (t->colwidth_v) free(*t->colwidth_v);
522 if (t->colsep_v) free(*t->colsep_v);
525 /* ______________________________________________________________________ */
526 /* Check the attributes and children of the table pointed to by e.
527 * Report problems and inconsistencies to stderr.
529 * Pointer to element (table) under consideration.
537 int pr_loc=0; /* flag to say if we printed location */
541 char *tpref = "Table Check"; /* prefix for err messages */
543 "Table Check: %s ('%s') has wrong number of tokens. Expecting %d.\n";
545 if (strcmp(e->gi, "TABLE") &&
546 strcmp(e->gi, "INFORMALTABLE") &&
547 strcmp(e->gi, "TGROUP") &&
548 strcmp(e->gi, "COLSPEC") &&
549 strcmp(e->gi, "ROW") ) {
550 fprintf(stderr, "%s: Not pointing to a table element(%s)!\n",
555 FreeTabAtts(&TheTab); /* free storage, if allocated earlier */
556 SetTabAtts(e, &TheTab, 1); /* look at attributes */
559 /* NCOLS attribute set? */
562 fprintf(stderr, "%s: NCOLS attribute missing. Inferred as %d.\n",
566 /* ALIGN attribute set? */
569 fprintf(stderr, "%s: ALIGN attribute missing.\n", tpref);
572 /* See if the number of cells in each row matches */
573 for (r=0; r<e->necont && (ep=e->econt[r]); r++) { /* each TGroup */
574 for (i=0; i<ep->necont && (ep2=ep->econt[i]); i++) {
575 if ( strcmp(ep2->gi, "TBODY") ) /* only TBodys */
578 for (c=0; c<ep2->necont; c++) {
579 if (ep2->econt[c]->necont != TheTab.nc) {
581 fprintf(stderr, "%s: COLS (%d) differs from actual number of cells (%d) in row %d.\n",
582 tpref, TheTab.nc, ep2->econt[c]->necont, c);
591 if (TheTab.nc != TheTab.n_align) { /* number of tokens OK? */
593 fprintf(stderr, ncolchk, "ALIGN", TheTab.align, TheTab.nc);
595 else { /* values OK? */
596 for (i=0; i<TheTab.nc; i++) {
597 if (*TheTab.align_v[i] != 'C' && *TheTab.align_v[i] != 'L' &&
598 *TheTab.align_v[i] != 'R') {
600 fprintf(stderr, "%s: ALIGN (%d) value wrong: %s\n",
601 tpref, i, TheTab.align_v[i]);
608 if (TheTab.colwidth) {
609 if (TheTab.nc != TheTab.n_colwidth) { /* number of tokens OK? */
611 fprintf(stderr, ncolchk, "COLWIDTH", TheTab.colwidth, TheTab.nc);
613 else { /* values OK? */
614 for (i=0; i<TheTab.nc; i++) {
616 /* check that the units after the numbers are OK
625 if (TheTab.nc != TheTab.n_colsep) { /* number of tokens OK? */
627 fprintf(stderr, ncolchk, "COLSEP", TheTab.colsep, TheTab.nc);
629 else { /* values OK? */
630 for (i=0; i<TheTab.nc; i++) {
636 fprintf(stderr, "%s: Above problem in table located at:\n", tpref);
637 PrintLocation(e, stderr);
641 /* ______________________________________________________________________ */
643 /* Look at colspec attribute for spanning. If set, remember info for when
644 * doing the cells. Called by TblTableRowStart() and TexTableRowStart().
646 * Pointer to element (row) under consideration.
657 #if FALSE /* NOT IMPLEMENTED RIGHT NOW */
659 /* See if COLSPEC element present */
660 for (i=0; i < e->necont; i++) {
665 if ((at = FindAttValByName(e, "MODEL"))) {
667 /* Split into tokens, then look at each for the word "span" */
669 spans = Split(at, &n, S_STRDUP|S_ALVEC);
671 /* Mark columns as start-of-span, in-span, or not spanned. Remember
672 * in at list, "spaningo". (Span does not make sense in 1st column.)
674 for (i=1,inspan=0; i<n; i++) {
675 if (StrEq(spans[i], "span") || StrEq(spans[i], "s")) {
676 if (inspan == 0) spaninfo[i-1] = SPAN_START;
677 spaninfo[i] = SPAN_CONT;
681 spaninfo[i] = SPAN_NOT;
685 free(*spans); /* free string */
686 free(spans); /* free vector */
687 spaninfo[TheTab.nc] = SPAN_NOT; /* after last cell */
690 /* if model not set, mark all as not spanning */
693 #endif /* NOT CURRENTLY IMPLEMENTED */
695 for (i=0; i<MAXCOLS; i++) spaninfo[i] = SPAN_NOT;
699 /* ______________________________________________________________________ */
700 /* Do the "right thing" for the table spec for TeX tables. This will
701 * generate the arg to \begin{tabular}[xxx].
703 * Pointer to element (table) under consideration.
704 * FILE pointer to where to write output.
714 char *cp, wbuf[1500], **widths=0, **widths_v=0;
716 FreeTabAtts(&TheTab); /* free storage, if allocated earlier */
717 SetTabAtts(e, &TheTab, 1); /* look at attributes */
718 SetTabAtts(e->econt[0], &TheTab, 1); /* attrs of TGroup */
720 /* Figure out the widths, based either on "colwidth".
722 if (TheTab.colwidth && TheTab.nc == TheTab.n_colwidth) {
723 widths = TheTab.colwidth_v;
728 if (strcmp(TheTab.frame, "ALL") && strcmp(TheTab.frame, "SIDES"))
731 if (siderules) OutputString("|", fp, 1);
732 for (i=0; i<TheTab.nc; i++) {
733 /* If width specified, use it; else if align set, use it; else left. */
734 if (widths && widths[i][0] != '0' && widths[i][1] != EOS) {
735 fprintf(fp, "%sp{%s}", (i?" ":""), widths[i]);
737 else if (TheTab.align && TheTab.nc == TheTab.n_align) {
738 fprintf(fp, "%s%s", (i?" ":""), TheTab.align_v[i]);
741 fprintf(fp, "%sl", (i?" ":""));
742 /* See if we want column separators. */
745 if ( (i+1) < TheTab.nc ) {
746 if ( *TheTab.colsep_v[i] == '1' ) {
749 if ( *TheTab.colsep_v[i] == '2' ) {
756 if (siderules) OutputString("|", fp, 1);
758 if (widths_v) free(widths_v);
763 * Pointer to element (cell) under consideration.
764 * FILE pointer to where to write output.
775 if (spaninfo[e->my_eorder] == SPAN_START) {
776 for (i=e->my_eorder+1,n=1; ; i++) {
777 if (spaninfo[i] == SPAN_CONT) n++;
780 sprintf(buf, "\\\\multicolumn{%d}{%sc%s}", n,
781 (siderules?"|":""), (siderules?"|":""));
782 OutputString(buf, fp, 1);
785 if ((at = FindAttValByName(e->parent, "ALIGN"))) {
786 /* no span, but user wants to change the alignment */
787 h_v = Split(wbuf, 0, S_ALVEC|S_STRDUP);
788 OutputString("\\\\multicolumn{1}{%sc%s}", n,
793 if (spaninfo[e->my_eorder] != SPAN_CONT) OutputString("{", fp, 1);
798 * Pointer to element (cell) under consideration.
799 * FILE pointer to where to write output.
807 if (spaninfo[e->my_eorder] != SPAN_CONT) OutputString("} ", fp, 1);
809 /* do cell/col separators */
810 if (e->my_eorder < (TheTab.nc-1)) {
811 if (spaninfo[e->my_eorder] == SPAN_NOT ||
812 spaninfo[e->my_eorder+1] != SPAN_CONT)
813 OutputString("& ", fp, 1);
817 /* Look at model for spanning. If set, remember it for when doing the cells.
819 * Pointer to element (row) under consideration.
820 * FILE pointer to where to write output.
833 * Pointer to element (row) under consideration.
834 * FILE pointer to where to write output.
844 /* check this row's attributes */
845 if ((at = FindAttValByName(e, "ROWSEP"))) {
846 if (at[0] == '1') OutputString("\\\\\\\\[2mm] \\\\hline ", fp, 1);
848 else if (rowsep) OutputString("\\\\\\\\ ", fp, 1);
850 OutputString("\\\\\\\\ ", fp, 1);
856 * Pointer to element (table) under consideration.
857 * FILE pointer to where to write output.
860 TexTableTop(Element_t *e, FILE *fp)
862 if (frametop) OutputString("\\\\hline", fp, 1);
866 TexTableBottom(Element_t *e, FILE *fp)
868 if (framebot) OutputString("\\\\hline", fp, 1);
871 /* ______________________________________________________________________ */
872 /* ______________________________________________________________________ */
873 /* ______________________________________________________________________ */
874 /* ______________________________________________________________________ */
875 /* ______________________________________________________________________ */
876 /* ___________________________| |____________________________ */
877 /* ___________________________| TBL STUFF |____________________________ */
878 /* ___________________________| |____________________________ */
879 /* ___________________________|_____________|____________________________ */
880 /* ______________________________________________________________________ */
881 /* ______________________________________________________________________ */
882 /* ______________________________________________________________________ */
883 /* ______________________________________________________________________ */
887 /* TblTStart() -- start a table and do style information
892 * find global rowsep and colsep
897 TblTStart(Element_t * ep,
901 struct Element_t * ep2;
905 OutputString("^.TS^", fP, 1);
907 tblTGroupSeen = FALSE;
908 tblinBOFT = FALSE; /* within a boft? */
909 tblBOFTCount = 0; /* count of Blocks of Filled Text that
912 tblgcolsep = (cp = FindAttValByName(ep, "COLSEP")) && !strcmp(cp, "1");
913 tblgrowsep = (cp = FindAttValByName(ep, "ROWSEP")) && !strcmp(cp, "1");
916 /* TblTEnd() -- end a table and do any cleanup
922 * deallocate format line info
928 TblTEnd(Element_t * ep,
931 struct tblformat * ffp, * ffp2;
934 if ( tblBOFTCount > 31 ) {
935 fprintf(stderr, "# warning, line %d: created %d blocks of filled text in one table\n",
936 ep->lineno, tblBOFTCount);
937 fprintf(stderr, "#\t\t(31 is the limit in some systems)\n");
940 OutputString("^.TE^", fP, 1);
942 for ( ffp=formP; ffp; ffp=ffp2 ) {
944 free(ffp); /* clear entire list */
949 /* TblTTGroup() -- do body work (row format info)
953 * set number of columns
955 * if this is the first TGroup of this table, do style info:
961 * a. generate tableformat structure
964 * prepare structures for colspecs and spanspecs
971 TblTGroup(Element_t * ep,
976 Element_t * ep2, ep3;
977 struct tblcolspec * tcsp, * tcsp2;
978 struct tblspanspec * tssp, * tssp2;
981 tblColSpec = 0; /* make sure they're clear */
984 /* set the number of columns */
986 tblcols = atoi(FindAttValByName(ep, "COLS"));
990 tblColSpec = tcsp = TblDoColSpec(0, ep, 0, TGroup);
991 /* do TGroup first -- it becomes the default */
993 for ( i=0, k=1; i < ep->necont; i++ ) {
995 if ( !strcmp(ep->econt[i]->gi, "COLSPEC") ) {
996 tcsp2 = TblDoColSpec(k, ep->econt[i], tblColSpec, TGroup);
997 tcsp->next = tcsp2; /* put into list */
999 k = tcsp2->num + 1; /* next column number */
1002 if ( !strcmp(ep->econt[i]->gi, "THEAD") ) {
1004 for ( j=0, k=1; j < ep2->necont; j++ ) {
1005 if ( !strcmp(ep2->econt[j]->gi, "COLSPEC") ) {
1006 tcsp2 = TblDoColSpec(k, ep2->econt[j], tblColSpec, THead);
1007 tcsp->next = tcsp2; /* put into list */
1009 k = tcsp2->num + 1; /* next column number */
1014 if ( !strcmp(ep->econt[i]->gi, "TFOOT") ) {
1016 for ( j=0, k=1; j < ep2->necont; j++ ) {
1017 if ( !strcmp(ep2->econt[j]->gi, "COLSPEC") ) {
1018 tcsp2 = TblDoColSpec(k, ep2->econt[j], tblColSpec, TFoot);
1019 tcsp->next = tcsp2; /* put into list */
1021 k = tcsp2->num + 1; /* next column number */
1026 if ( !strcmp(ep->econt[i]->gi, "TBODY") ) {
1028 for ( j=0, k=1; j < ep2->necont; j++ ) {
1029 if ( !strcmp(ep2->econt[j]->gi, "COLSPEC") ) {
1030 tcsp2 = TblDoColSpec(k, ep2->econt[j], tblColSpec, TBody);
1031 tcsp->next = tcsp2; /* put into list */
1033 k = tcsp2->num + 1; /* next column number */
1041 tblSpanSpec = tssp = TblDoSpanSpec(ep, 0, TGroup);
1042 /* do TGroup first -- it becomes the default */
1044 for ( i=0; i < ep->necont; i++ ) {
1045 if ( !strcmp(ep->econt[i]->gi, "SPANSPEC") ) {
1046 tssp2 = TblDoSpanSpec(ep->econt[i], tblSpanSpec, TGroup);
1047 tssp->next = tssp2; /* put into list */
1053 /* if this is the first TGroup in this table, do style stuff */
1055 if ( ! tblTGroupSeen ) {
1057 OutputString("tab(\007)", fP, 1);
1060 if ( ! (tblFrame = FindAttValByName(ep2, "FRAME")) )
1063 if ( !strcmp(tblFrame, "ALL") ) {
1064 if ( tcsp->colsep && tcsp->rowsep )
1065 OutputString(" allbox", fP, 1);
1067 OutputString(" box", fP, 1);
1070 if ( (cp = FindAttValByName(ep, "ALIGN")) &&
1071 !strcmp(cp, "CENTER") ) {
1072 OutputString(" center", fP, 1);
1075 OutputString(";\n", fP, 1);
1077 tblTGroupSeen = TRUE;
1081 /* do format stuff -- step through all THead rows then all TBody
1082 * rows. Build a list of tblformats that describe all of them.
1083 * then output the resulting list.
1086 for ( i=0; i < ep->necont; i++ ) {
1087 if ( !strcmp(ep->econt[i]->gi, "THEAD") ) {
1088 TblBuildFormat(ep->econt[i], &formP, THead);
1089 /* add in those rows */
1094 for ( i=0; i < ep->necont; i++ ) {
1095 if ( !strcmp(ep->econt[i]->gi, "TBODY") ) {
1096 TblBuildFormat(ep->econt[i], &formP, TBody);
1097 /* add in those rows */
1102 TblPrintFormat(fP, formP);
1104 tblrow = 0; /* the current row within this format */
1107 /* TblTGroupEnd() -- end a TGroup
1111 * deallocate colspecs and spanspecs
1116 TblTGroupEnd(Element_t * ep,
1119 struct tblcolspec * tcsp, * tcsp2;
1120 struct tblspanspec * tssp, * tssp2;
1123 for ( tcsp=tblColSpec; tcsp; tcsp=tcsp2 ) {
1127 for ( tssp=tblSpanSpec; tssp; tssp=tssp2 ) {
1133 /* TblTTFoot() -- do body foot work (row format info)
1138 * a. generate tableformat structure
1139 * i. if it is only 1 line long and matches the
1140 * prevailing format, just output rows.
1141 * ii. else, output a .T& and the new format specs
1147 TblTFoot(Element_t * ep,
1150 struct tblformat * ffp, * ffp2;
1151 static struct tblformat * tfp, * tfp2;
1154 TblBuildFormat(ep, &tfp, TFoot); /* gen format for the foot */
1156 for ( tfp2=formP; tfp2 && tfp2->next; tfp2=tfp2->next )
1159 if ( tfp->next || !TblFormatMatch(tfp, tfp2) ) {
1161 for ( ffp=formP; ffp; ffp=ffp2 ) {
1163 free(ffp); /* clear entire list */
1166 formP = tfp; /* this becomes the prevailing format */
1168 OutputString("^.T&^", fP, 1);
1169 TblPrintFormat(fP, formP);
1172 tblrow = 0; /* the current row within this format */
1175 /* TblBuildFormat() -- build a format structure out of a set of
1182 TblBuildFormat(Element_t * ep, /* parent of rows.. */
1183 struct tblformat ** fp, /* pointer to head of struct we're
1185 tblsource source) /* type of record */
1188 struct tblformat * lfp; /* "current" format */
1189 struct tblformat * nfp; /* the next format */
1192 for ( lfp= *fp; lfp && lfp->next; lfp=lfp->next )
1193 ; /* find end of format list */
1195 for ( i=0; i < ep->necont; i++ )
1196 if ( !strcmp(ep->econt[i]->gi, "ROW") )
1197 break; /* find where rows start */
1199 for ( ; i < ep->necont; i++ ) {
1201 nfp = TblBuild1Format(ep->econt[i], FALSE, source);
1205 lfp = *fp = nfp; /* first one */
1207 if ( TblFormatMatch(lfp, nfp) )
1208 lfp->count++; /* matches */
1210 lfp->count = 1; /* only 1 so far */
1211 lfp->next = nfp; /* new one */
1217 /* TblBuild1Format() -- build one row's worth of format information
1224 TblBuild1Format(Element_t * rp, /* the row to deal with */
1225 bool addinRowsep, /* insert rowsep into model? */
1226 tblsource source) /* type type of row */
1231 struct tblformat * tfp;
1232 Element_t * ep; /* entry pointer */
1235 Calloc(1, tfp, struct tblformat);
1236 tfp->cols = tblcols;
1237 ep = (rp->necont) ? rp->econt[0] : 0; /* first entry */
1241 for ( i=1; i <= tblcols; i++ ) {
1242 tfp->colformat[i] = TblGetAlign(i, ep, source);
1243 strcpy(tfp->colwidth[i], TblGetWidth(i, ep, TRUE, source));
1244 strcpy(tfp->colpwidth[i], TblGetWidth(i, ep, FALSE, source));
1246 allProp = tfp->colpwidth[i][0];
1247 totalProp += atof(tfp->colpwidth[i]);
1249 strcpy(tfp->font[i], TblGetFont(i, ep, source));
1250 tfp->colsep[i] = tblgcolsep || TblGetColSep(i, ep, source);
1252 tfp->rowsep[i] = tblgrowsep || TblGetRowSep(i, ep, source);
1253 tfp->moreRows[i] = TblGetMoreRows(i, ep, source);
1255 if ( (i < rp->necont) && TblColAdv(i, ep, tfp, source) ) {
1260 /* turn proportional widths into real widths */
1263 for ( i=1; i <= tblcols; i++ ) {
1264 sprintf(tfp->colwidth[i], "%fi",
1265 (atof(tfp->colpwidth[i]) / totalProp) * TEXTWIDTH);
1272 /* TblGetAlign() -- get alignment spec for a entry
1278 TblGetAlign(short col, /* column number */
1279 Element_t * entry, /* the entry */
1280 tblsource source) /* context */
1282 struct tblcolspec * tcsp;
1283 struct tblspanspec * tssp;
1287 if ( entry && (tssp = TblEntrySpanSpec(col, entry, source)) ) {
1288 talign = tssp->align;
1291 if ( entry && (tcsp = TblEntryColSpec(col, entry, source)) ) {
1292 talign = tcsp->align;
1299 case Left: return 'l';
1300 case Right: return 'r';
1301 case Center: return 'c';
1302 case Justify: return 'l';
1303 case Char: return 'd';
1304 case Span: return 's';
1308 /* TblGetWidth() -- get width spec, if any, for a entry
1314 TblGetWidth(short col, /* column number */
1315 Element_t * entry, /* the entry */
1316 bool literal, /* literal (or proportional) */
1317 tblsource source) /* context */
1319 struct tblcolspec * tcsp;
1320 struct tblspanspec * tssp;
1321 static char colWidth[10];
1327 (tcsp = TblEntryColSpec(col, entry, source)) &&
1328 tcsp->colwidth[0] ) {
1330 if ( !strstr(tcsp->colwidth, "*") ) {
1332 strcpy(colWidth, tcsp->colwidth);
1335 strcpy(colWidth, tcsp->colwidth);
1343 /* TblGetFont() -- get font spec, if any, for a entry
1349 TblGetFont(short col, /* column number */
1350 Element_t * entry, /* the entry */
1351 tblsource source) /* context */
1353 struct tblcolspec * tcsp;
1354 struct tblspanspec * tssp;
1360 /* TblGetColSep() -- get column separater spec, if any, for a entry
1366 TblGetColSep(short col, /* column number */
1367 Element_t * entry, /* the entry */
1368 tblsource source) /* context */
1370 struct tblcolspec * tcsp;
1371 struct tblspanspec * tssp;
1375 if ( entry && (tssp = TblEntrySpanSpec(col, entry, source)) ) {
1376 colsep = tssp->colsep;
1379 if ( entry && (tcsp = TblEntryColSpec(col, entry, source)) ) {
1380 colsep = tcsp->colsep;
1388 /* TblGetRowSep() -- get row separater spec, if any, for a entry
1394 TblGetRowSep(short col, /* column number */
1395 Element_t * entry, /* the entry */
1396 tblsource source) /* context */
1398 struct tblcolspec * tcsp;
1399 struct tblspanspec * tssp;
1402 if ( entry && (tssp = TblEntrySpanSpec(col, entry, source)) ) {
1403 rowsep = tssp->rowsep;
1406 if ( entry && (tcsp = TblEntryColSpec(col, entry, source)) ) {
1407 rowsep = tcsp->rowsep;
1416 /* TblGetmoreRows() -- get moreRows value
1422 TblGetMoreRows(short col, /* column number */
1423 Element_t * entry, /* the entry */
1424 tblsource source) /* context */
1429 if ( cp = FindAttValByName(entry, "MOREROWS") )
1435 /* TblColAdv() -- advance pointer to next entry, if appropriate
1441 TblColAdv(short col, /* the current column */
1442 Element_t *ep, /* pointer to entry */
1443 struct tblformat * tfp, /* pointer to prevailing format */
1444 tblsource source) /* context */
1447 struct tblspanspec * tssp;
1452 if ( tssp = TblEntrySpanSpec(col, ep, source) ) {
1453 bump = tssp->align != Span;
1460 /* TblEntryColSpec() -- get a completely localized colspec for an entry
1466 TblEntryColSpec(short num, /* column number */
1467 Element_t * ep, /* entry */
1468 tblsource source) /* context */
1473 struct tblcolspec * tcsp, * tcsp2;
1479 if ( (cp = FindAttValByName(ep, "COLNAME")) ) {
1480 if ( ! (tcsp = TblFindColSpec(cp, source)) ) {
1481 fprintf(stderr, "? can't find column name '%s'\n", cp);
1485 if ( tcsp2 = TblFindColNum(num, source) ) {
1486 tcsp = TblDoColSpec(num, ep, tcsp2, source);
1490 tcsp2 = TblDoColSpec(num, ep, tcsp, source);
1498 /* TblEntrySpanSpec() -- get a completely localized spanspec for an entry
1503 struct tblspanspec *
1504 TblEntrySpanSpec(short num, /* column number */
1505 Element_t * ep, /* entry */
1506 tblsource source) /* context */
1509 struct tblspanspec * tssp, * tssp2;
1514 if ( !(cp = FindAttValByName(ep, "SPANNAME")) ||
1515 !(tssp2 = TblFindSpanSpec(cp, source)) ) {
1517 if ( !FindAttValByName(ep, "NAMEST") )
1521 tssp = TblDoSpanSpec(ep, tssp2, source);
1523 if ( tssp->start && tssp->end &&
1524 (tssp->start->num < num) && (tssp->end->num >= num) ) {
1531 /* TblFormatMatch() -- compare two format rows for consistency
1537 TblFormatMatch(struct tblformat * tf1, /* one row */
1538 struct tblformat * tf2) /* the other */
1542 if ( tf1->cols != tf2->cols ) {
1546 for ( i=0; i < tf1->cols; i++ ) {
1548 if ( tf1->colformat[i] != tf2->colformat[i] ) {
1551 if ( strcmp(tf1->colwidth[i], tf2->colwidth[i]) ) {
1554 if ( strcmp(tf1->font[i], tf2->font[i]) ) {
1557 if ( tf1->colsep[i] != tf2->colsep[i] ) {
1560 if ( tf1->rowsep[i] != tf2->rowsep[i] ) {
1563 if ( tf1->moreRows[i] || tf2->moreRows[i] ) {
1571 /* TblPrintFormat() -- print a tbl format structure
1577 TblPrintFormat(FILE * fP, /* where to print */
1578 struct tblformat * tfp) /* the structure */
1581 struct tblformat * tfp2, * tfp3;
1582 static char buf[3] = "\000\000";
1585 for ( tfp2=tfp, tfp3=0; tfp2; tfp2=tfp2->next ) {
1586 for ( i=1; i <= tfp->cols; i++ ) {
1588 OutputString(" ", fP, 1);
1589 if ( tfp3 && tfp3->moreRows[i] )
1590 OutputString("\\^", fP, 1);
1592 buf[0] = tfp2->colformat[i];
1593 OutputString(buf, fP, 1);
1595 if ( tfp2->colwidth[i][0] ) {
1596 OutputString("w(", fP, 1);
1597 OutputString(tfp2->colwidth[i], fP, 1);
1598 OutputString(")", fP, 1);
1600 if ( tfp2->font[i][0] )
1601 OutputString(tfp2->font[i], fP, 1);
1602 if ( tfp2->colsep[i] )
1603 OutputString("|", fP, 1);
1606 OutputString(".", fP, 1);
1607 OutputString("^", fP, 1);
1612 /* TblTRowStart() -- start a row (not much to do)
1623 TblTRowStart(Element_t * ep,
1629 tblrow++; /* except note that we're within a new row */
1633 /* TblTRowEnd() -- end a row
1637 * output a row end character (newline)
1638 * if the current row had a rowsep, then output a "fake" row
1639 * with underlines in the proper place(s).
1645 TblTRowEnd(Element_t * ep,
1650 bool startedRow, didSep;
1651 struct tblformat * rfp;
1654 OutputString("^", fP, 1);
1656 /* get the format for this row */
1658 if ( !strcmp(ep->parent->gi, "TFoot") )
1661 if ( !strcmp(ep->parent->gi, "THead") )
1666 rfp = TblBuild1Format(ep, TRUE, source);
1670 for ( i=1; i <= formP->cols; i++ ) {
1671 if ( rfp->rowsep[i] ||
1672 (didSep && (rfp->colformat[i] == 's')) ) {
1673 if ( ! startedRow ) {
1674 OutputString("^", fP, 1);
1675 for ( k=1; k < i; k++ )
1676 OutputString("\007", fP, 1);
1679 OutputString("_\007", fP, 1);
1683 OutputString("\007", fP, 1);
1687 free(rfp); /* clear that row.. */
1690 OutputString("^", fP, 1);
1693 /* TblTEntryStart() -- start an entry (block of filled text if
1698 * if text length > BOFTTextThresh or there is PI,
1699 * then output "T{\n", else do nothing
1706 TblTCellStart(Element_t * ep,
1714 for ( i=0, sawPIorPara=FALSE; i < ep->ncont; i++ ) {
1715 if ( (ep->cont[i].type == '?') ||
1717 (ep->cont[i].type == '(') &&
1718 !strcmp(ep->cont[i].ch.elem->gi, "PARA")) ) {
1724 if ( sawPIorPara || (TblCountContent(ep) > BOFTTextThresh) ) {
1726 OutputString("T{^", fP, 1);
1727 tblinBOFT = TRUE; /* within a boft now */
1731 /* TblCountContent() -- count all content below the given element
1739 TblCountContent(Element_t * ep) /* the element to look under */
1747 for ( i=0; i < ep->ncont; i++ ) {
1748 if ( ep->cont[i].type == '-' ) {
1749 for ( cp=ep->cont[i].ch.data; *cp; cp++, count++ )
1751 return BOFTTextThresh + 1;
1753 if ( ep->cont[i].type == '(' ) {
1754 count += TblCountContent(ep->cont[i].ch.elem);
1761 /* TblTEntryEnd() -- end an entry
1765 * if within BOFT, output "T}"
1766 * if not last entry, output tab character
1773 TblTCellEnd(Element_t * ep,
1780 OutputString("^T}", fP, 1);
1781 tblinBOFT = FALSE; /* back out again */
1784 for ( ep2=ep->next; ep2; ep2=ep2->next ) {
1785 if ( !strcmp(ep2->gi, "ENTRY") || !strcmp(ep2->gi, "ENTRYTBL") ) {
1786 OutputString("\007", fP, 1);
1789 if ( !strcmp(ep2->gi, "ROW") )
1794 /* TblDoColSpec() -- process one element to create a new colspec
1802 TblDoColSpec(short number, /* this column number */
1803 Element_t * ep, /* element containing colspec stuff */
1804 struct tblcolspec * pcsp, /* prevailing colspec (with defaults) */
1805 tblsource source) /* precedence level of the resulting spec */
1808 struct tblcolspec * tcsp;
1811 Calloc(1, tcsp, struct tblcolspec);
1813 if ( cp = FindAttValByName(ep, "COLNAME") )
1814 strcpy(tcsp->name, cp);
1817 tcsp->source = source;
1819 if ( cp = FindAttValByName(ep, "ALIGN") ) {
1820 if ( !strcmp(cp, "LEFT") ) tcsp->align = Left;
1821 else if ( !strcmp(cp, "RIGHT") ) tcsp->align = Right;
1822 else if ( !strcmp(cp, "CENTER") ) tcsp->align = Center;
1823 else if ( !strcmp(cp, "JUSTIFY") ) tcsp->align = Justify;
1824 else if ( !strcmp(cp, "CHAR") ) tcsp->align = Char;
1826 tcsp->align = ( pcsp ) ? pcsp->align : Left;
1828 if ( cp = FindAttValByName(ep, "CHAR") )
1829 tcsp->alignchar = cp[0];
1831 tcsp->alignchar = ( pcsp ) ? pcsp->alignchar : 0;
1833 if ( cp = FindAttValByName(ep, "CHAROFF") )
1834 tcsp->aligncharoff = atoi(cp);
1836 tcsp->aligncharoff = ( pcsp ) ? pcsp->aligncharoff : 0;
1838 if ( cp = FindAttValByName(ep, "COLWIDTH") )
1839 strcpy(tcsp->colwidth, cp);
1841 strcpy(tcsp->colwidth, ( pcsp ) ? pcsp->colwidth : "");
1843 if ( cp = FindAttValByName(ep, "COLSEP") )
1844 tcsp->colsep = !strcmp(cp, "1");
1846 tcsp->colsep = ( pcsp ) ? pcsp->colsep : FALSE;
1848 if ( cp = FindAttValByName(ep, "ROWSEP") )
1849 tcsp->rowsep = !strcmp(cp, "1");
1851 tcsp->rowsep = ( pcsp ) ? pcsp->rowsep : FALSE;
1856 /* TblDoSpanSpec() -- process one element to create a new spanspec
1858 * Note that there's a hack inside here... NameSt and NameEnd are
1859 * supposed to point at colnames, but if no colname is found, this
1860 * code will look for a colnum by the same value.
1865 struct tblspanspec *
1866 TblDoSpanSpec(Element_t * ep, /* element containing spanspec stuff */
1867 struct tblspanspec * pssp, /* prevailing spanspec (with defaults) */
1868 tblsource source) /* precedence level of the resulting spec */
1871 struct tblspanspec * tssp;
1872 struct tblcolspec * tcsp;
1875 Calloc(1, tssp, struct tblspanspec);
1877 if ( cp = FindAttValByName(ep, "SPANNAME") ) {
1878 snprintf(tssp->name, sizeof(tssp->name), "%s", cp);
1880 tssp->source = source;
1882 if ( cp = FindAttValByName(ep, "NAMEST") ) {
1883 if ( (tcsp = TblFindColSpec(cp, source)) ||
1884 (tcsp = TblFindColNum(atoi(cp), source)) ) {
1887 fprintf(stderr, "? spanspec namest points to unknown column '%s'\n", cp);
1891 if ( pssp && pssp->start ) {
1892 tssp->start = pssp->start;
1896 if ( cp = FindAttValByName(ep, "NAMEEND") ) {
1897 if ( (tcsp = TblFindColSpec(cp, source)) ||
1898 (tcsp = TblFindColNum(atoi(cp), source)) ) {
1901 fprintf(stderr, "? spanspec nameend points to unknown column '%s'\n", cp);
1905 if ( pssp && pssp->end ) {
1906 tssp->end = pssp->end;
1910 if ( cp = FindAttValByName(ep, "ALIGN") ) {
1911 if ( !strcmp(cp, "LEFT") ) tssp->align = Left;
1912 else if ( !strcmp(cp, "RIGHT") ) tssp->align = Right;
1913 else if ( !strcmp(cp, "CENTER") ) tssp->align = Center;
1914 else if ( !strcmp(cp, "JUSTIFY") ) tssp->align = Justify;
1915 else if ( !strcmp(cp, "CHAR") ) tssp->align = Char;
1918 tssp->align = pssp->align;
1921 if ( cp = FindAttValByName(ep, "CHAR") )
1922 tssp->alignchar = cp[0];
1925 tssp->alignchar = pssp->alignchar;
1927 if ( cp = FindAttValByName(ep, "CHAROFF") )
1928 tssp->aligncharoff = atoi(cp);
1931 tssp->alignchar = pssp->alignchar;
1934 if ( cp = FindAttValByName(ep, "COLSEP") )
1935 tssp->colsep = !strcmp(cp, "1");
1938 tssp->colsep = pssp->colsep;
1940 if ( cp = FindAttValByName(ep, "ROWSEP") )
1941 tssp->rowsep = !strcmp(cp, "1");
1944 tssp->rowsep = pssp->rowsep;
1950 /* TblFindColSpec() -- find a table colspec by name (colname)
1957 TblFindColSpec(char * name, /* the name we're looking for */
1958 tblsource source) /* the context in which to find it */
1960 struct tblcolspec * tcsp;
1963 /* first, try to find the one in the right "source" */
1965 for ( tcsp=tblColSpec; tcsp; tcsp=tcsp->next ) {
1966 if ( (tcsp->source == source) && !strcmp(tcsp->name, name) )
1970 /* else, try to find one from a TGroup.. */
1972 for ( tcsp=tblColSpec; tcsp; tcsp=tcsp->next ) {
1973 if ( (tcsp->source == TGroup) && !strcmp(tcsp->name, name) )
1977 /* else not found.. */
1982 /* TblFindColNum() -- find a table colspec by number
1989 TblFindColNum(short number, /* the number we're looking for */
1990 tblsource source) /* the context in which to find it */
1992 struct tblcolspec * tcsp;
1996 /* first, try to find the one in the right "source" */
1998 for ( tcsp=tblColSpec; tcsp; tcsp=tcsp->next ) {
1999 if ( (tcsp->num == number) &&
2000 ((tcsp->source == source) ||
2001 ((source == THead) && (tcsp->source == TGroup))) )
2005 /* else, try to find one from a TGroup.. */
2007 for ( tcsp=tblColSpec; tcsp; tcsp=tcsp->next ) {
2008 if ( (tcsp->source == TGroup) && (tcsp->num == number) )
2012 /* else not found.. */
2017 /* TblFindSpanSpec() -- find a table spanspec by name (spanname)
2023 struct tblspanspec *
2024 TblFindSpanSpec(char * name, /* the name we're looking for */
2025 tblsource source) /* the context in which to find it */
2027 struct tblspanspec * tssp;
2030 /* first, try to find the one in the right "source" */
2032 for ( tssp=tblSpanSpec; tssp; tssp=tssp->next ) {
2033 if ( !strcmp(tssp->name, name) &&
2034 ((tssp->source == source) ||
2035 ((source == THead) && (tssp->source == TGroup))) )
2039 /* else not found.. */