1 /*
2 * Copyright 1993 Open Software Foundation, Inc., Cambridge, Massachusetts.
3 * All rights reserved.
4 */
5 /*
6 * Copyright (c) 1994
7 * Open Software Foundation, Inc.
8 *
9 * Permission is hereby granted to use, copy, modify and freely distribute
10 * the software in this file and its documentation for any purpose without
11 * fee, provided that the above copyright notice appears in all copies and
12 * that both the copyright notice and this permission notice appear in
13 * supporting documentation. Further, provided that the name of Open
14 * Software Foundation, Inc. ("OSF") not be used in advertising or
15 * publicity pertaining to distribution of the software without prior
16 * written permission from OSF. OSF makes no representations about the
17 * suitability of this software for any purpose. It is provided "as is"
18 * without express or implied warranty.
19 */
20 /*
21 * Copyright (c) 1996 X Consortium
22 * Copyright (c) 1995, 1996 Dalrymple Consulting
23 *
24 * Permission is hereby granted, free of charge, to any person obtaining a copy
25 * of this software and associated documentation files (the "Software"), to deal
26 * in the Software without restriction, including without limitation the rights
27 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
28 * copies of the Software, and to permit persons to whom the Software is
29 * furnished to do so, subject to the following conditions:
30 *
31 * The above copyright notice and this permission notice shall be included in
32 * all copies or substantial portions of the Software.
33 *
34 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
37 * X CONSORTIUM OR DALRYMPLE CONSULTING BE LIABLE FOR ANY CLAIM, DAMAGES OR
38 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
39 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
40 * OTHER DEALINGS IN THE SOFTWARE.
41 *
42 * Except as contained in this notice, the names of the X Consortium and
43 * Dalrymple Consulting shall not be used in advertising or otherwise to
44 * promote the sale, use or other dealings in this Software without prior
45 * written authorization.
46 */
47 /* ________________________________________________________________________
48 *
49 * Program to manipulate SGML instances.
50 *
51 * Originally coded for OSF DTD tables, now recoded (fld 3/27/95)
52 * for CALS-type tables (fragment taken from the DocBook DTD). Then,
53 * *really* upgraded to CALS tables by FLD on 5/28/96.
54 *
55 * This module is for handling table markup, printing TeX or tbl
56 * (tbl) markup to the output stream. Also, table markup checking is
57 * done here. Yes, this depends on the DTD, but it makes translation
58 * specs much cleaner (and makes some things possible).
59 *
60 * Incomplete / not implemented / limitations / notes:
61 * vertical alignment (valign attr)
62 * vertical spanning
63 * row separators are for the whole line, not per cell (the prog looks
64 * at rowsep for the 1st cell and applies it to the whole row)
65 * trusts that units in colwidths are acceptable to LaTeX and tbl
66 * "s" is an acceptable shorthand for "span" in model attributes
67 *
68 * A note on use of OutputString(): Strings with backslashes (\) need lots
69 * of backslashes. You have to escape them for the C compiler, and escape
70 * them again for OutputString() itself.
71 * ________________________________________________________________________
72 */
73
74 #ifndef lint
75 static char *RCSid =
76 "$Header: /usr/src/docbook-to-man/Instant/RCS/tables.c,v 1.11 1996/06/15 03:45:02 fld Exp $";
77 #endif
78
79 #include <stdio.h>
80 #include <stdlib.h>
81 #include <ctype.h>
82 #include <string.h>
83 #include <memory.h>
84 #include <sys/types.h>
85 #include <errno.h>
86
87 #include <tptregexp.h>
88 #include "general.h"
89 #include "translate.h"
90
91 /* text width of page, in inches */
92 #define TEXTWIDTH 5.5
93 #define MAXCOLS 100
94 #define SPAN_NOT 0
95 #define SPAN_START 1
96 #define SPAN_CONT 2
97
98 /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
99 /*table parameters */
100
101 #define TBLMAXCOL 30 /* max number of columns in tbl table */
102 #define NAMELEN 40 /* max length of a name */
103 #define BOFTTHRESHOLD 35 /* text length over which to consider
104 * generating a block of filled text */
105
106
107 /* handy declarations */
108
109 typedef enum { Left, Right, Center, Justify, Char, Span } tblalign;
110
111 typedef enum { TGroup, THead, TFoot, TBody } tblsource; /* source of a spec */
112
113
114 /* table line format information structures */
115
116 struct tblcolspec {
117
118 char name[NAMELEN]; /* colspec's name */
119 short num; /* column number */
120 tblsource source; /* where defined */
121
122 tblalign align; /* column's alignment */
123 char alignchar; /* character for alignment */
124 short aligncharoff; /* offset for alignment */
125 char colwidth[10]; /* width for column */
126 char colpwidth[10]; /* proportional widths for column */
127 bool colsep; /* separator to right of column? */
128 bool rowsep; /* separator to bottom of column? */
129 short moreRows; /* value for Morerows */
130
131 struct tblcolspec * next; /* next colspec */
132 };
133
134 struct tblspanspec {
135
136 char name[NAMELEN]; /* spanspec's name */
137 tblsource source; /* where defined */
138
139 struct tblcolspec * start; /* start column */
140 struct tblcolspec * end; /* end column */
141 tblalign align; /* span's alignment */
142 char alignchar; /* character for alignment */
143 short aligncharoff; /* offset for alignment */
144 bool colsep; /* separator to right of column? */
145 bool rowsep; /* separator to bottom of column? */
146
147 struct tblspanspec * next; /* next spanspec */
148 };
149
150 struct tblformat {
151 short count; /* count of rows matching this spec */
152
153 short cols; /* # of columns */
154 short rowNum; /* row number */
155 char colformat[TBLMAXCOL]; /* per-column formats */
156 char colwidth[TBLMAXCOL][10]; /* per-column widths */
157 char colpwidth[TBLMAXCOL][10]; /* per-column proportional widths */
158 char font[TBLMAXCOL][3]; /* column fonts (headers) */
159 bool colsep[TBLMAXCOL]; /* column separators */
160 bool rowsep[TBLMAXCOL]; /* row separators */
161 short moreRows[TBLMAXCOL]; /* moreRows indicator */
162
163 struct tblformat * next; /* for the next row */
164 };
165
166
167 /* table state info */
168
169 static short tblcols = 0; /* number of columns in the table */
170 static short tblrow = 0; /* the current row in the table */
171
172 static bool tblTGroupSeen = FALSE; /* seen a TGroup in this table yet? */
173
174 static char * tblFrame; /* table frame info */
175 static bool tblgcolsep; /* global colsep (in table) */
176 static bool tblgrowsep; /* global rowsep (in table) */
177
178 static int tblBOFTCount = 0; /* count of bofts that we've created
179 * (per table) */
180 int BOFTTextThresh = BOFTTHRESHOLD;
181 /* length of text before we
182 * call it a BOFT */
183 static bool tblboft = FALSE; /* within a block of filled text? */
184 static bool tblinBOFT = FALSE; /* within a boft now? */
185
186 static struct tblformat * formP = 0; /* THead/TBody format lines */
187
188 static struct tblcolspec * tblColSpec = 0; /* colspec structure for table */
189 static struct tblspanspec * tblSpanSpec = 0; /* spanspec structure for table */
190
191 /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
192
193 /* these cover the attributes on the Table, TGroup, Colspec elements */
194 typedef struct {
195 char *cols;
196 char *align, **align_v;
197 char *colwidth, **colwidth_v;
198 char *colsep, **colsep_v;
199 char *rowsep, **rowsep_v;
200 char *frame;
201 char *orient;
202 int pgwide;
203 int n_align, n_model, n_colwidth, n_colsep;
204 int nc;
205 } TableInfo;
206
207
208 /* some flags, set when the table tag is processed, used later */
209 static int rowsep, siderules;
210 static int frametop, framebot, frameall;
211 static char basemodel[128]; /* model for table (in formatting language) */
212 static int spaninfo[MAXCOLS]; /* 100 columns, max */
213 static TableInfo TheTab;
214
215 /* forward references */
216 void SetTabAtts(Element_t *, TableInfo *, int);
217 void FreeTabAtts(TableInfo *);
218 void ClearTable(TableInfo *);
219 void CheckTable(Element_t *);
220 void TblTStart(Element_t *, FILE *);
221 void TblTEnd(Element_t *, FILE *);
222 void TblTGroup(Element_t *, FILE *);
223 void TblTGroupEnd(Element_t *, FILE *);
224 void TblTFoot(Element_t *, FILE *);
225 void TblBuildFormat(Element_t *, struct tblformat **, tblsource);
226 struct tblformat * TblBuild1Format(Element_t *, bool, tblsource);
227 char TblGetAlign(short, Element_t *, tblsource);
228 char * TblGetWidth(short, Element_t *, bool, tblsource);
229 char * TblGetFont(short, Element_t *, tblsource);
230 bool TblGetColSep(short, Element_t *, tblsource);
231 bool TblGetRowSep(short, Element_t *, tblsource);
232 short TblGetMoreRows(short, Element_t *, tblsource);
233 bool TblColAdv(short, Element_t *, struct tblformat *, tblsource);
234 struct tblcolspec * TblEntryColSpec(short, Element_t *, tblsource);
235 struct tblspanspec * TblEntrySpanSpec(short, Element_t *, tblsource);
236 bool TblFormatMatch(struct tblformat *, struct tblformat *);
237 void TblPrintFormat(FILE *, struct tblformat *);
238 void TblTRowStart(Element_t *, FILE *);
239 void TblTRowEnd(Element_t *, FILE *);
240 void TblTCellStart(Element_t *, FILE *);
241 int TblCountContent(Element_t *);
242 void TblTCellEnd(Element_t *, FILE *);
243 struct tblcolspec * TblDoColSpec(short, Element_t *, struct tblcolspec *, tblsource);
244 struct tblspanspec * TblDoSpanSpec(Element_t *, struct tblspanspec *, tblsource);
245 struct tblcolspec * TblFindColSpec(char *, tblsource);
246 struct tblcolspec * TblFindColNum(short, tblsource);
247 struct tblspanspec * TblFindSpanSpec(char *, tblsource);
248 void TexTable(Element_t *, FILE *);
249 void TexTableCellStart(Element_t *, FILE *);
250 void TexTableCellEnd(Element_t *, FILE *);
251 void TexTableRowStart(Element_t *, FILE *);
252 void TexTableRowEnd(Element_t *, FILE *);
253 void TexTableTop(Element_t *, FILE *);
254 void TexTableBottom(Element_t *, FILE *);
255
256 /* ______________________________________________________________________ */
257 /* Hard-coded stuff for CALS-style DTD tables.
258 * Here are the TABLE attributes (for handy reference):
259 *
260 * Table/InformalTable:
261 * Colsep NUMBER separate all columns in table?
262 * Frame (Top|Bottom|Topbot|All|Sides|None) frame style
263 * Orient (Port | Land) orientation
264 * Pgwide NUMBER wide table?
265 * Rowsep NUMBER separate all rows in the table?
266 * Tabstyle NMTOKEN FOSI table style
267 *
268 * TGroup:
269 * Align (Left|Right|Center|Justify|Char) alignment of cols
270 * Char CDATA Alignment specifier
271 * Charoff NUTOKEN "" ""
272 * Cols NUMBER number of columns
273 * Colsep NUMBER separate all columns in tgroup?
274 * Rowsep NUMBER separate all rows in tgroup?
275 * TGroupstyle NMTOKEN FOSI table group style
276 *
277 * Colspec:
278 * Align (Left|Right|Center|Justify|Char) entry align
279 * Char CDATA Alignment specifier
280 * Charoff NUTOKEN "" ""
281 * Colname NMTOKEN Column identifier
282 * Colnum NUMBER number of column
283 * Colsep NUMBER separate this col from next?
284 * Colwidth CDATA width spec
285 * Rowsep NUMBER serarate entry from following row?
286 *
287 * SpanSpec:
288 * Align (Left|Right|Center|Justify|Char) entry align
289 * Char CDATA Alignment specifier
290 * Charoff NUTOKEN "" ""
291 * Colsep NUMBER separate this col from next?
292 * Nameend NMTOKEN name of rightmost col of a span
293 * Namest NMTOKEN name of leftmost col of a span
294 * Rowsep NUMBER serarate entry from following row?
295 * Spanname NMTOKEN name of a horiz. span
296 *
297 * THead/TFoot/TBody:
298 * VAlign (Top | Middle | Bottom) group placement
299 *
300 * Row:
301 * Rowsep NUMBER separate this row from next?
302 * VAlign (Top | Middle | Bottom) row placement
303 *
304 * Entry:
305 * Align (Left|Right|Center|Justify|Char) entry align
306 * Char CDATA Alignment specifier
307 * Charoff NUTOKEN "" ""
308 * Colname NMTOKEN Column identifier
309 * Colsep NUMBER separate this col from next?
310 * Morerows NUMBER number of addn'l rows in vert straddle
311 * Nameend NMTOKEN name of rightmost col of a span
312 * Namest NMTOKEN name of leftmost col of a span
313 * Rotate NUMBER 90 degree rotation counterclockwise to table?
314 * Rowsep NUMBER serarate entry from following row?
315 * Spanname NMTOKEN name of a horiz. span
316 * VAlign (Top | Middle | Bottom) text vert alignment
317 *
318 *
319 ** OBSOLETE OSF DTD FORM (still used for TeX form):
320 ** Usage in transpec: _calstable [tex|check|clear] ['aspect']
321 ** where 'aspect' is:
322 ** rowstart stuff to do at start of a row (tests for spanning)
323 ** rowend stuff to do at end of a row (eg, rules, etc.)
324 ** cellstart stuff to do at start of a cell (eg, handle actual
325 ** spanning instructions, etc.)
326 ** cellend stuff to do at end of a cell (eg, cell separator)
327 ** top stuff to do at top of the table
328 ** (like whether or not it needs a starting horiz rule)
329 ** bottom stuff to do at bottom of the table
330 ** (like whether or not it needs an ending horiz rule)
331 ** (nothing) the 'cols' param to LaTeX's \begin{tabular}[pos]{cols}
332 ** or 'options' and 'formats' part in tbl
333 *
334 *
335 * New tbl form:
336 * Usage in transpec: _calstable [tbl] ['aspect']
337 * where 'aspect' is:
338 * tablestart start a table and do style info
339 * tableend end the table and clean up
340 * tablegroup table TGroup (.T& if not 1st, line format info)
341 * tablegroupend end a TGroup
342 * tablefoot TFoot within a TGroup
343 * rowstart start of a row
344 * rowend end of a row
345 * entrystart start of an entry (block of filled text, if
346 * appropriate)
347 * entryend end of a cell (eg, cell separator)
348 */
349
350 /* Procedure to
351 * Arguments:
352 * Pointer to element under consideration.
353 * FILE pointer to where to write output.
354 * Vector of args to _osftable
355 * Count of args to _osftable
356 */
357 void
CALStable(Element_t * e,FILE * fp,char ** av,int ac)358 CALStable(
359 Element_t *e,
360 FILE *fp,
361 char **av,
362 int ac
363 )
364 {
365 /* Check params and dispatch to appropriate routine */
366
367 if (!strcmp(av[1], "tbl")) {
368
369 if (ac > 2) {
370 if (!strcmp(av[2], "tablestart")) TblTStart(e, fp);
371 else if (!strcmp(av[2], "tableend")) TblTEnd(e, fp);
372 else if (!strcmp(av[2], "tablegroup")) TblTGroup(e, fp);
373 else if (!strcmp(av[2], "tablegroupend")) TblTGroupEnd(e, fp);
374 else if (!strcmp(av[2], "tablefoot")) TblTFoot(e, fp);
375 else if (!strcmp(av[2], "rowstart")) TblTRowStart(e, fp);
376 else if (!strcmp(av[2], "rowend")) TblTRowEnd(e, fp);
377 else if (!strcmp(av[2], "entrystart")) TblTCellStart(e, fp);
378 else if (!strcmp(av[2], "entryend")) TblTCellEnd(e, fp);
379 else fprintf(stderr, "Unknown %s table instruction: %s\n",
380 av[1], av[2]);
381 }
382 else {
383 fprintf(stderr, "Incomplete %s table instruction\n");
384 }
385 }
386
387 else if (!strcmp(av[1], "tex")) {
388
389 if (ac > 1 && !strcmp(av[1], "check")) CheckTable(e);
390
391 else
392 if (ac > 1 && !strcmp(av[1], "clear")) ClearTable(&TheTab);
393
394 if (ac > 2) {
395 if (!strcmp(av[2], "cellstart")) TexTableCellStart(e, fp);
396 else if (!strcmp(av[2], "cellend")) TexTableCellEnd(e, fp);
397 else if (!strcmp(av[2], "rowstart")) TexTableRowStart(e, fp);
398 else if (!strcmp(av[2], "rowend")) TexTableRowEnd(e, fp);
399 else if (!strcmp(av[2], "top")) TexTableTop(e, fp);
400 else if (!strcmp(av[2], "bottom")) TexTableBottom(e, fp);
401 else fprintf(stderr, "Unknown %s table instruction: %s\n",
402 av[1], av[2]);
403 }
404 else TexTable(e, fp);
405 }
406
407 else fprintf(stderr, "Unknown table type: %s\n", av[1]);
408
409 }
410
411 /* ClearTable -- start a new table process
412 *
413 */
414
415
416 void
ClearTable(TableInfo * t)417 ClearTable( TableInfo * t )
418 {
419 memset(t, 0, sizeof(TableInfo));
420 }
421
422
423 /* ______________________________________________________________________ */
424 /* Set values of the our internal table structure based on the table's
425 * attributes. (This is called for tables, tgroups, colspecs, and rows,
426 * since tables and rows share many of the same attributes.)
427 * Arguments:
428 * Pointer to element under consideration.
429 * Pointer table info structure which will be filled in.
430 * Flag saying whether or not to set global variables based on attrs.
431 */
432 void
SetTabAtts(Element_t * e,TableInfo * t,int set_globals)433 SetTabAtts(
434 Element_t *e,
435 TableInfo *t,
436 int set_globals
437 )
438 {
439 char *at;
440 Element_t * ep;
441
442 /* remember values of attributes */
443 if ((at = FindAttValByName(e, "ALIGN"))) t->align = at;
444 if ((at = FindAttValByName(e, "COLWIDTH"))) t->colwidth = at;
445 if ((at = FindAttValByName(e, "COLSEP"))) t->colsep = at;
446 if ((at = FindAttValByName(e, "FRAME"))) t->frame = at;
447 if ((at = FindAttValByName(e, "COLS"))) t->cols = at;
448
449 /* Set some things for later when processing this table */
450 if (set_globals) {
451
452 rowsep = 1;
453 frametop = framebot = 1; /* default style */
454
455 /* For now we look at the first number of rowsep - it controls the
456 * horiz rule for then entire row. (not easy to specify lines that
457 * span only some columns in tex or tbl. */
458 if ((at = FindAttValByName(e, "ROWSEP"))) rowsep = atoi(at);
459 }
460
461 if (t->frame) {
462 /* Top|Bottom|Topbot|All|Sides|None */
463 if (!strcmp(t->frame, "NONE") || !strcmp(t->frame, "SIDES"))
464 frametop = framebot = 0;
465 else if (!strcmp(t->frame, "TOP")) framebot = 0;
466 else if (!strcmp(t->frame, "BOTTOM")) frametop = 0;
467 }
468
469 /* tbl and tex like lower case for units. convert. */
470 if (t->colwidth) {
471 char *cp;
472 for (cp=t->colwidth; *cp; cp++)
473 if (isupper(*cp)) *cp = tolower(*cp);
474 }
475
476 /* Now, split (space-separated) strings into vectors. Hopefully, the
477 * number of elements in each vector matches the number of columns.
478 */
479 t->align_v = Split(t->align, &t->n_align, S_STRDUP|S_ALVEC);
480 t->colwidth_v = Split(t->colwidth, &t->n_colwidth, S_STRDUP|S_ALVEC);
481 t->colsep_v = Split(t->colsep, &t->n_colsep, S_STRDUP|S_ALVEC);
482
483 /* Determin the _numeric_ number of columns, "nc". MUST be specified
484 * in Cols attribute of TGroup element.
485 */
486 if (t->cols) t->nc = atoi(t->cols);
487 }
488
489 /* ______________________________________________________________________ */
490
491 /* Free the storage of info use by the table info structure. (not the
492 * structure itself, but the strings its elements point to)
493 * Arguments:
494 * Pointer table info structure to be freed.
495 */
496 void
FreeTabAtts(TableInfo * t)497 FreeTabAtts(
498 TableInfo *t
499 )
500 {
501 if (!t) return;
502 if (t->align_v) free(*t->align_v);
503 if (t->colwidth_v) free(*t->colwidth_v);
504 if (t->colsep_v) free(*t->colsep_v);
505 }
506
507 /* ______________________________________________________________________ */
508 /* Check the attributes and children of the table pointed to by e.
509 * Report problems and inconsistencies to stderr.
510 * Arguments:
511 * Pointer to element (table) under consideration.
512 */
513
514 void
CheckTable(Element_t * e)515 CheckTable(
516 Element_t *e
517 )
518 {
519 int pr_loc=0; /* flag to say if we printed location */
520 int i, r, c;
521 Element_t *ep, *ep2;
522 float wt;
523 char *tpref = "Table Check"; /* prefix for err messages */
524 char *ncolchk =
525 "Table Check: %s ('%s') has wrong number of tokens. Expecting %d.\n";
526
527 if (strcmp(e->gi, "TABLE") &&
528 strcmp(e->gi, "INFORMALTABLE") &&
529 strcmp(e->gi, "TGROUP") &&
530 strcmp(e->gi, "COLSPEC") &&
531 strcmp(e->gi, "ROW") ) {
532 fprintf(stderr, "%s: Not pointing to a table element(%s)!\n",
533 tpref, e->gi);
534 return;
535 }
536
537 FreeTabAtts(&TheTab); /* free storage, if allocated earlier */
538 SetTabAtts(e, &TheTab, 1); /* look at attributes */
539
540 #if FALSE
541 /* NCOLS attribute set? */
542 if (!TheTab.ncols) {
543 pr_loc++;
544 fprintf(stderr, "%s: NCOLS attribute missing. Inferred as %d.\n",
545 tpref, TheTab.nc);
546 }
547
548 /* ALIGN attribute set? */
549 if (!TheTab.align) {
550 pr_loc++;
551 fprintf(stderr, "%s: ALIGN attribute missing.\n", tpref);
552 }
553
554 /* See if the number of cells in each row matches */
555 for (r=0; r<e->necont && (ep=e->econt[r]); r++) { /* each TGroup */
556 for (i=0; i<ep->necont && (ep2=ep->econt[i]); i++) {
557 if ( strcmp(ep2->gi, "TBODY") ) /* only TBodys */
558 continue;
559
560 for (c=0; c<ep2->necont; c++) {
561 if (ep2->econt[c]->necont != TheTab.nc) {
562 pr_loc++;
563 fprintf(stderr, "%s: COLS (%d) differs from actual number of cells (%d) in row %d.\n",
564 tpref, TheTab.nc, ep2->econt[c]->necont, c);
565 }
566 }
567 }
568 }
569 #endif
570
571 /* Check ALIGN */
572 if (TheTab.align) {
573 if (TheTab.nc != TheTab.n_align) { /* number of tokens OK? */
574 pr_loc++;
575 fprintf(stderr, ncolchk, "ALIGN", TheTab.align, TheTab.nc);
576 }
577 else { /* values OK? */
578 for (i=0; i<TheTab.nc; i++) {
579 if (*TheTab.align_v[i] != 'C' && *TheTab.align_v[i] != 'L' &&
580 *TheTab.align_v[i] != 'R') {
581 pr_loc++;
582 fprintf(stderr, "%s: ALIGN (%d) value wrong: %s\n",
583 tpref, i, TheTab.align_v[i]);
584 }
585 }
586 }
587 }
588
589 /* check COLWIDTH */
590 if (TheTab.colwidth) {
591 if (TheTab.nc != TheTab.n_colwidth) { /* number of tokens OK? */
592 pr_loc++;
593 fprintf(stderr, ncolchk, "COLWIDTH", TheTab.colwidth, TheTab.nc);
594 }
595 else { /* values OK? */
596 for (i=0; i<TheTab.nc; i++) {
597
598 /* check that the units after the numbers are OK
599 we want "in", "cm".
600 */
601 }
602 }
603 }
604
605 /* check COLSEP */
606 if (TheTab.colsep) {
607 if (TheTab.nc != TheTab.n_colsep) { /* number of tokens OK? */
608 pr_loc++;
609 fprintf(stderr, ncolchk, "COLSEP", TheTab.colsep, TheTab.nc);
610 }
611 else { /* values OK? */
612 for (i=0; i<TheTab.nc; i++) {
613 }
614 }
615 }
616
617 if (pr_loc) {
618 fprintf(stderr, "%s: Above problem in table located at:\n", tpref);
619 PrintLocation(e, stderr);
620 }
621 }
622
623 /* ______________________________________________________________________ */
624
625 /* Look at colspec attribute for spanning. If set, remember info for when
626 * doing the cells. Called by TblTableRowStart() and TexTableRowStart().
627 * Arguments:
628 * Pointer to element (row) under consideration.
629 */
630 int
check_for_spans(Element_t * e)631 check_for_spans(
632 Element_t *e
633 )
634 {
635 char *at;
636 char **spans;
637 int n, i, inspan;
638
639 #if FALSE /* NOT IMPLEMENTED RIGHT NOW */
640
641 /* See if COLSPEC element present */
642 for (i=0; i < e->necont; i++) {
643
644 }
645
646
647 if ((at = FindAttValByName(e, "MODEL"))) {
648
649 /* Split into tokens, then look at each for the word "span" */
650 n = TheTab.nc;
651 spans = Split(at, &n, S_STRDUP|S_ALVEC);
652
653 /* Mark columns as start-of-span, in-span, or not spanned. Remember
654 * in at list, "spaningo". (Span does not make sense in 1st column.)
655 */
656 for (i=1,inspan=0; i<n; i++) {
657 if (StrEq(spans[i], "span") || StrEq(spans[i], "s")) {
658 if (inspan == 0) spaninfo[i-1] = SPAN_START;
659 spaninfo[i] = SPAN_CONT;
660 inspan = 1;
661 }
662 else {
663 spaninfo[i] = SPAN_NOT;
664 inspan = 0;
665 }
666 }
667 free(*spans); /* free string */
668 free(spans); /* free vector */
669 spaninfo[TheTab.nc] = SPAN_NOT; /* after last cell */
670 return 1;
671 }
672 /* if model not set, mark all as not spanning */
673 else
674
675 #endif /* NOT CURRENTLY IMPLEMENTED */
676
677 for (i=0; i<MAXCOLS; i++) spaninfo[i] = SPAN_NOT;
678 return 0;
679 }
680
681 /* ______________________________________________________________________ */
682 /* Do the "right thing" for the table spec for TeX tables. This will
683 * generate the arg to \begin{tabular}[xxx].
684 * Arguments:
685 * Pointer to element (table) under consideration.
686 * FILE pointer to where to write output.
687 */
688 void
TexTable(Element_t * e,FILE * fp)689 TexTable(
690 Element_t *e,
691 FILE *fp
692 )
693 {
694 int i, n;
695 float tot;
696 char *cp, wbuf[1500], **widths=0, **widths_v=0;
697
698 FreeTabAtts(&TheTab); /* free storage, if allocated earlier */
699 SetTabAtts(e, &TheTab, 1); /* look at attributes */
700 SetTabAtts(e->econt[0], &TheTab, 1); /* attrs of TGroup */
701
702 /* Figure out the widths, based either on "colwidth".
703 */
704 if (TheTab.colwidth && TheTab.nc == TheTab.n_colwidth) {
705 widths = TheTab.colwidth_v;
706 }
707
708 siderules = 1;
709 if (TheTab.frame)
710 if (strcmp(TheTab.frame, "ALL") && strcmp(TheTab.frame, "SIDES"))
711 siderules = 0;
712
713 if (siderules) OutputString("|", fp, 1);
714 for (i=0; i<TheTab.nc; i++) {
715 /* If width specified, use it; else if align set, use it; else left. */
716 if (widths && widths[i][0] != '0' && widths[i][1] != EOS) {
717 fprintf(fp, "%sp{%s}", (i?" ":""), widths[i]);
718 }
719 else if (TheTab.align && TheTab.nc == TheTab.n_align) {
720 fprintf(fp, "%s%s", (i?" ":""), TheTab.align_v[i]);
721 }
722 else
723 fprintf(fp, "%sl", (i?" ":""));
724 /* See if we want column separators. */
725 if (TheTab.colsep) {
726
727 if ( (i+1) < TheTab.nc ) {
728 if ( *TheTab.colsep_v[i] == '1' ) {
729 fprintf(fp, " |");
730 }
731 if ( *TheTab.colsep_v[i] == '2' ) {
732 fprintf(fp, " ||");
733 }
734 }
735
736 }
737 }
738 if (siderules) OutputString("|", fp, 1);
739
740 if (widths_v) free(widths_v);
741 }
742
743 /*
744 * Arguments:
745 * Pointer to element (cell) under consideration.
746 * FILE pointer to where to write output.
747 */
748 void
TexTableCellStart(Element_t * e,FILE * fp)749 TexTableCellStart(
750 Element_t *e,
751 FILE *fp
752 )
753 {
754 int n, i;
755 char buf[50], *at;
756
757 if (spaninfo[e->my_eorder] == SPAN_START) {
758 for (i=e->my_eorder+1,n=1; ; i++) {
759 if (spaninfo[i] == SPAN_CONT) n++;
760 else break;
761 }
762 sprintf(buf, "\\\\multicolumn{%d}{%sc%s}", n,
763 (siderules?"|":""), (siderules?"|":""));
764 OutputString(buf, fp, 1);
765 }
766 #ifdef New
767 if ((at = FindAttValByName(e->parent, "ALIGN"))) {
768 /* no span, but user wants to change the alignment */
769 h_v = Split(wbuf, 0, S_ALVEC|S_STRDUP);
770 OutputString("\\\\multicolumn{1}{%sc%s}", n,
771 fp, 1);
772 }
773 #endif
774
775 if (spaninfo[e->my_eorder] != SPAN_CONT) OutputString("{", fp, 1);
776 }
777
778 /*
779 * Arguments:
780 * Pointer to element (cell) under consideration.
781 * FILE pointer to where to write output.
782 */
783 void
TexTableCellEnd(Element_t * e,FILE * fp)784 TexTableCellEnd(
785 Element_t *e,
786 FILE *fp
787 )
788 {
789 if (spaninfo[e->my_eorder] != SPAN_CONT) OutputString("} ", fp, 1);
790
791 /* do cell/col separators */
792 if (e->my_eorder < (TheTab.nc-1)) {
793 if (spaninfo[e->my_eorder] == SPAN_NOT ||
794 spaninfo[e->my_eorder+1] != SPAN_CONT)
795 OutputString("& ", fp, 1);
796 }
797 }
798
799 /* Look at model for spanning. If set, remember it for when doing the cells.
800 * Arguments:
801 * Pointer to element (row) under consideration.
802 * FILE pointer to where to write output.
803 */
804 void
TexTableRowStart(Element_t * e,FILE * fp)805 TexTableRowStart(
806 Element_t *e,
807 FILE *fp
808 )
809 {
810 check_for_spans(e);
811 }
812
813 /*
814 * Arguments:
815 * Pointer to element (row) under consideration.
816 * FILE pointer to where to write output.
817 */
818 void
TexTableRowEnd(Element_t * e,FILE * fp)819 TexTableRowEnd(
820 Element_t *e,
821 FILE *fp
822 )
823 {
824 char *at;
825
826 /* check this row's attributes */
827 if ((at = FindAttValByName(e, "ROWSEP"))) {
828 if (at[0] == '1') OutputString("\\\\\\\\[2mm] \\\\hline ", fp, 1);
829 }
830 else if (rowsep) OutputString("\\\\\\\\ ", fp, 1);
831 else
832 OutputString("\\\\\\\\ ", fp, 1);
833
834 }
835
836 /*
837 * Arguments:
838 * Pointer to element (table) under consideration.
839 * FILE pointer to where to write output.
840 */
841 void
TexTableTop(Element_t * e,FILE * fp)842 TexTableTop(Element_t *e, FILE *fp)
843 {
844 if (frametop) OutputString("\\\\hline", fp, 1);
845 }
846
847 void
TexTableBottom(Element_t * e,FILE * fp)848 TexTableBottom(Element_t *e, FILE *fp)
849 {
850 if (framebot) OutputString("\\\\hline", fp, 1);
851 }
852
853 /* ______________________________________________________________________ */
854 /* ______________________________________________________________________ */
855 /* ______________________________________________________________________ */
856 /* ______________________________________________________________________ */
857 /* ______________________________________________________________________ */
858 /* ___________________________| |____________________________ */
859 /* ___________________________| TBL STUFF |____________________________ */
860 /* ___________________________| |____________________________ */
861 /* ___________________________|_____________|____________________________ */
862 /* ______________________________________________________________________ */
863 /* ______________________________________________________________________ */
864 /* ______________________________________________________________________ */
865 /* ______________________________________________________________________ */
866
867
868
869 /* TblTStart() -- start a table and do style information
870 *
871 * TO DO:
872 *
873 * do .TS
874 * find global rowsep and colsep
875 */
876
877
878 void
TblTStart(Element_t * ep,FILE * fP)879 TblTStart(Element_t * ep,
880 FILE * fP)
881 {
882 register char * cp;
883 register struct Element_t * ep2;
884
885
886
887 OutputString("^.TS^", fP, 1);
888
889 tblTGroupSeen = FALSE;
890 tblinBOFT = FALSE; /* within a boft? */
891 tblBOFTCount = 0; /* count of Blocks of Filled Text that
892 * we've created */
893
894 tblgcolsep = (cp = FindAttValByName(ep, "COLSEP")) && !strcmp(cp, "1");
895 tblgrowsep = (cp = FindAttValByName(ep, "ROWSEP")) && !strcmp(cp, "1");
896 }
897
898 /* TblTEnd() -- end a table and do any cleanup
899 *
900 * TO DO:
901 *
902 * do .TE
903 *
904 * deallocate format line info
905 */
906
907
908
909 void
TblTEnd(Element_t * ep,FILE * fP)910 TblTEnd(Element_t * ep,
911 FILE * fP)
912 {
913 register struct tblformat * ffp, * ffp2;
914
915
916 if ( tblBOFTCount > 31 ) {
917 fprintf(stderr, "# warning, line %d: created %d blocks of filled text in one table\n",
918 ep->lineno, tblBOFTCount);
919 fprintf(stderr, "#\t\t(31 is the limit in some systems)\n");
920 }
921
922 OutputString("^.TE^", fP, 1);
923
924 for ( ffp=formP; ffp; ffp=ffp2 ) {
925 ffp2 = ffp->next;
926 free(ffp); /* clear entire list */
927 }
928 formP = 0;
929 }
930
931 /* TblTTGroup() -- do body work (row format info)
932 *
933 * TO DO:
934 *
935 * set number of columns
936 *
937 * if this is the first TGroup of this table, do style info:
938 * a. alignment
939 * b. defaults: tab
940 * c. box vx allbox
941 *
942 * do format info:
943 * a. generate tableformat structure
944 * b. output it
945 *
946 * prepare structures for colspecs and spanspecs
947 *
948 */
949
950
951
952 void
TblTGroup(Element_t * ep,FILE * fP)953 TblTGroup(Element_t * ep,
954 FILE * fP)
955 {
956 register int i, j, k;
957 register char * cp, * cp2;
958 register Element_t * ep2, ep3;
959 register struct tblcolspec * tcsp, * tcsp2;
960 register struct tblspanspec * tssp, * tssp2;
961
962
963 tblColSpec = 0; /* make sure they're clear */
964 tblSpanSpec = 0;
965
966 /* set the number of columns */
967
968 tblcols = atoi(FindAttValByName(ep, "COLS"));
969
970 /* do colspecs */
971
972 tblColSpec = tcsp = TblDoColSpec(0, ep, 0, TGroup);
973 /* do TGroup first -- it becomes the default */
974
975 for ( i=0, k=1; i < ep->necont; i++ ) {
976
977 if ( !strcmp(ep->econt[i]->gi, "COLSPEC") ) {
978 tcsp2 = TblDoColSpec(k, ep->econt[i], tblColSpec, TGroup);
979 tcsp->next = tcsp2; /* put into list */
980 tcsp = tcsp2;
981 k = tcsp2->num + 1; /* next column number */
982 }
983
984 if ( !strcmp(ep->econt[i]->gi, "THEAD") ) {
985 ep2 = ep->econt[i];
986 for ( j=0, k=1; j < ep2->necont; j++ ) {
987 if ( !strcmp(ep2->econt[j]->gi, "COLSPEC") ) {
988 tcsp2 = TblDoColSpec(k, ep2->econt[j], tblColSpec, THead);
989 tcsp->next = tcsp2; /* put into list */
990 tcsp = tcsp2;
991 k = tcsp2->num + 1; /* next column number */
992 }
993 }
994 }
995
996 if ( !strcmp(ep->econt[i]->gi, "TFOOT") ) {
997 ep2 = ep->econt[i];
998 for ( j=0, k=1; j < ep2->necont; j++ ) {
999 if ( !strcmp(ep2->econt[j]->gi, "COLSPEC") ) {
1000 tcsp2 = TblDoColSpec(k, ep2->econt[j], tblColSpec, TFoot);
1001 tcsp->next = tcsp2; /* put into list */
1002 tcsp = tcsp2;
1003 k = tcsp2->num + 1; /* next column number */
1004 }
1005 }
1006 }
1007
1008 if ( !strcmp(ep->econt[i]->gi, "TBODY") ) {
1009 ep2 = ep->econt[i];
1010 for ( j=0, k=1; j < ep2->necont; j++ ) {
1011 if ( !strcmp(ep2->econt[j]->gi, "COLSPEC") ) {
1012 tcsp2 = TblDoColSpec(k, ep2->econt[j], tblColSpec, TBody);
1013 tcsp->next = tcsp2; /* put into list */
1014 tcsp = tcsp2;
1015 k = tcsp2->num + 1; /* next column number */
1016 }
1017 }
1018 }
1019 }
1020
1021 /* do spanspecs */
1022
1023 tblSpanSpec = tssp = TblDoSpanSpec(ep, 0, TGroup);
1024 /* do TGroup first -- it becomes the default */
1025
1026 for ( i=0; i < ep->necont; i++ ) {
1027 if ( !strcmp(ep->econt[i]->gi, "SPANSPEC") ) {
1028 tssp2 = TblDoSpanSpec(ep->econt[i], tblSpanSpec, TGroup);
1029 tssp->next = tssp2; /* put into list */
1030 tssp = tssp2;
1031 }
1032 }
1033
1034
1035 /* if this is the first TGroup in this table, do style stuff */
1036
1037 if ( ! tblTGroupSeen ) {
1038
1039 OutputString("tab(\007)", fP, 1);
1040
1041 ep2 = ep->parent;
1042 if ( ! (tblFrame = FindAttValByName(ep2, "FRAME")) )
1043 tblFrame = "";
1044
1045 if ( !strcmp(tblFrame, "ALL") ) {
1046 if ( tcsp->colsep && tcsp->rowsep )
1047 OutputString(" allbox", fP, 1);
1048 else
1049 OutputString(" box", fP, 1);
1050 }
1051
1052 if ( (cp = FindAttValByName(ep, "ALIGN")) &&
1053 !strcmp(cp, "CENTER") ) {
1054 OutputString(" center", fP, 1);
1055 }
1056
1057 OutputString(";\n", fP, 1);
1058
1059 tblTGroupSeen = TRUE;
1060 }
1061
1062
1063 /* do format stuff -- step through all THead rows then all TBody
1064 * rows. Build a list of tblformats that describe all of them.
1065 * then output the resulting list.
1066 */
1067
1068 for ( i=0; i < ep->necont; i++ ) {
1069 if ( !strcmp(ep->econt[i]->gi, "THEAD") ) {
1070 TblBuildFormat(ep->econt[i], &formP, THead);
1071 /* add in those rows */
1072 break;
1073 }
1074 }
1075
1076 for ( i=0; i < ep->necont; i++ ) {
1077 if ( !strcmp(ep->econt[i]->gi, "TBODY") ) {
1078 TblBuildFormat(ep->econt[i], &formP, TBody);
1079 /* add in those rows */
1080 break;
1081 }
1082 }
1083
1084 TblPrintFormat(fP, formP);
1085
1086 tblrow = 0; /* the current row within this format */
1087 }
1088
1089 /* TblTGroupEnd() -- end a TGroup
1090 *
1091 * TO DO:
1092 *
1093 * deallocate colspecs and spanspecs
1094 */
1095
1096
1097 void
TblTGroupEnd(Element_t * ep,FILE * fP)1098 TblTGroupEnd(Element_t * ep,
1099 FILE * fP)
1100 {
1101 register struct tblcolspec * tcsp, * tcsp2;
1102 register struct tblspanspec * tssp, * tssp2;
1103
1104
1105 for ( tcsp=tblColSpec; tcsp; tcsp=tcsp2 ) {
1106 tcsp2 = tcsp->next;
1107 free(tcsp);
1108 }
1109 for ( tssp=tblSpanSpec; tssp; tssp=tssp2 ) {
1110 tssp2 = tssp->next;
1111 free(tssp);
1112 }
1113 }
1114
1115 /* TblTTFoot() -- do body foot work (row format info)
1116 *
1117 * TO DO:
1118 *
1119 * do format info:
1120 * a. generate tableformat structure
1121 * i. if it is only 1 line long and matches the
1122 * prevailing format, just output rows.
1123 * ii. else, output a .T& and the new format specs
1124 */
1125
1126
1127
1128 void
TblTFoot(Element_t * ep,FILE * fP)1129 TblTFoot(Element_t * ep,
1130 FILE * fP)
1131 {
1132 register struct tblformat * ffp, * ffp2;
1133 static struct tblformat * tfp, * tfp2;
1134
1135
1136 TblBuildFormat(ep, &tfp, TFoot); /* gen format for the foot */
1137
1138 for ( tfp2=formP; tfp2 && tfp2->next; tfp2=tfp2->next )
1139 ;
1140
1141 if ( tfp->next || !TblFormatMatch(tfp, tfp2) ) {
1142
1143 for ( ffp=formP; ffp; ffp=ffp2 ) {
1144 ffp2 = ffp->next;
1145 free(ffp); /* clear entire list */
1146 }
1147
1148 formP = tfp; /* this becomes the prevailing format */
1149
1150 OutputString("^.T&^", fP, 1);
1151 TblPrintFormat(fP, formP);
1152 }
1153
1154 tblrow = 0; /* the current row within this format */
1155 }
1156
1157 /* TblBuildFormat() -- build a format structure out of a set of
1158 * rows and columns
1159 *
1160 */
1161
1162
1163 void
TblBuildFormat(Element_t * ep,struct tblformat ** fp,tblsource source)1164 TblBuildFormat(Element_t * ep, /* parent of rows.. */
1165 struct tblformat ** fp, /* pointer to head of struct we're
1166 * building */
1167 tblsource source) /* type of record */
1168 {
1169 register int i;
1170 register struct tblformat * lfp; /* "current" format */
1171 register struct tblformat * nfp; /* the next format */
1172
1173
1174 for ( lfp= *fp; lfp && lfp->next; lfp=lfp->next )
1175 ; /* find end of format list */
1176
1177 for ( i=0; i < ep->necont; i++ )
1178 if ( !strcmp(ep->econt[i]->gi, "ROW") )
1179 break; /* find where rows start */
1180
1181 for ( ; i < ep->necont; i++ ) {
1182
1183 nfp = TblBuild1Format(ep->econt[i], FALSE, source);
1184 /* do one row */
1185
1186 if ( !lfp )
1187 lfp = *fp = nfp; /* first one */
1188 else
1189 if ( TblFormatMatch(lfp, nfp) )
1190 lfp->count++; /* matches */
1191 else {
1192 lfp->count = 1; /* only 1 so far */
1193 lfp->next = nfp; /* new one */
1194 lfp = nfp;
1195 }
1196 }
1197 }
1198
1199 /* TblBuild1Format() -- build one row's worth of format information
1200 *
1201 */
1202
1203
1204
1205 struct tblformat *
TblBuild1Format(Element_t * rp,bool addinRowsep,tblsource source)1206 TblBuild1Format(Element_t * rp, /* the row to deal with */
1207 bool addinRowsep, /* insert rowsep into model? */
1208 tblsource source) /* type type of row */
1209 {
1210 register int i;
1211 register bool allProp;
1212 float totalProp;
1213 register struct tblformat * tfp;
1214 register Element_t * ep; /* entry pointer */
1215
1216
1217 Calloc(1, tfp, struct tblformat);
1218 tfp->cols = tblcols;
1219 ep = (rp->necont) ? rp->econt[0] : 0; /* first entry */
1220 allProp = TRUE;
1221 totalProp = 0;
1222
1223 for ( i=1; i <= tblcols; i++ ) {
1224 tfp->colformat[i] = TblGetAlign(i, ep, source);
1225 strcpy(tfp->colwidth[i], TblGetWidth(i, ep, TRUE, source));
1226 strcpy(tfp->colpwidth[i], TblGetWidth(i, ep, FALSE, source));
1227 if ( allProp ) {
1228 allProp = tfp->colpwidth[i][0];
1229 totalProp += atof(tfp->colpwidth[i]);
1230 }
1231 strcpy(tfp->font[i], TblGetFont(i, ep, source));
1232 tfp->colsep[i] = tblgcolsep || TblGetColSep(i, ep, source);
1233 if ( addinRowsep )
1234 tfp->rowsep[i] = tblgrowsep || TblGetRowSep(i, ep, source);
1235 tfp->moreRows[i] = TblGetMoreRows(i, ep, source);
1236
1237 if ( (i < rp->necont) && TblColAdv(i, ep, tfp, source) ) {
1238 ep = rp->econt[i];
1239 }
1240 }
1241
1242 /* turn proportional widths into real widths */
1243
1244 if ( allProp ) {
1245 for ( i=1; i <= tblcols; i++ ) {
1246 sprintf(tfp->colwidth[i], "%fi",
1247 (atof(tfp->colpwidth[i]) / totalProp) * TEXTWIDTH);
1248 }
1249 }
1250
1251 return tfp;
1252 }
1253
1254 /* TblGetAlign() -- get alignment spec for a entry
1255 *
1256 */
1257
1258
1259 char
TblGetAlign(short col,Element_t * entry,tblsource source)1260 TblGetAlign(short col, /* column number */
1261 Element_t * entry, /* the entry */
1262 tblsource source) /* context */
1263 {
1264 register struct tblcolspec * tcsp;
1265 register struct tblspanspec * tssp;
1266 register tblalign talign;
1267
1268
1269 if ( entry && (tssp = TblEntrySpanSpec(col, entry, source)) ) {
1270 talign = tssp->align;
1271 free(tssp);
1272 } else
1273 if ( entry && (tcsp = TblEntryColSpec(col, entry, source)) ) {
1274 talign = tcsp->align;
1275 free(tcsp);
1276 } else {
1277 return 'l';
1278 }
1279
1280 switch ( talign ) {
1281 case Left: return 'l';
1282 case Right: return 'r';
1283 case Center: return 'c';
1284 case Justify: return 'l';
1285 case Char: return 'd';
1286 case Span: return 's';
1287 }
1288 }
1289
1290 /* TblGetWidth() -- get width spec, if any, for a entry
1291 *
1292 */
1293
1294
1295 char *
TblGetWidth(short col,Element_t * entry,bool literal,tblsource source)1296 TblGetWidth(short col, /* column number */
1297 Element_t * entry, /* the entry */
1298 bool literal, /* literal (or proportional) */
1299 tblsource source) /* context */
1300 {
1301 register struct tblcolspec * tcsp;
1302 register struct tblspanspec * tssp;
1303 static char colWidth[10];
1304
1305
1306 colWidth[0] = 0;
1307
1308 if ( entry &&
1309 (tcsp = TblEntryColSpec(col, entry, source)) &&
1310 tcsp->colwidth[0] ) {
1311
1312 if ( !strstr(tcsp->colwidth, "*") ) {
1313 if ( literal )
1314 strcpy(colWidth, tcsp->colwidth);
1315 } else {
1316 if ( ! literal )
1317 strcpy(colWidth, tcsp->colwidth);
1318 }
1319 free(tcsp);
1320 }
1321
1322 return colWidth;
1323 }
1324
1325 /* TblGetFont() -- get font spec, if any, for a entry
1326 *
1327 */
1328
1329
1330 char *
TblGetFont(short col,Element_t * entry,tblsource source)1331 TblGetFont(short col, /* column number */
1332 Element_t * entry, /* the entry */
1333 tblsource source) /* context */
1334 {
1335 register struct tblcolspec * tcsp;
1336 register struct tblspanspec * tssp;
1337
1338
1339 return "";
1340 }
1341
1342 /* TblGetColSep() -- get column separater spec, if any, for a entry
1343 *
1344 */
1345
1346
1347 bool
TblGetColSep(short col,Element_t * entry,tblsource source)1348 TblGetColSep(short col, /* column number */
1349 Element_t * entry, /* the entry */
1350 tblsource source) /* context */
1351 {
1352 register struct tblcolspec * tcsp;
1353 register struct tblspanspec * tssp;
1354 register bool colsep;
1355
1356
1357 if ( entry && (tssp = TblEntrySpanSpec(col, entry, source)) ) {
1358 colsep = tssp->colsep;
1359 free(tssp);
1360 } else
1361 if ( entry && (tcsp = TblEntryColSpec(col, entry, source)) ) {
1362 colsep = tcsp->colsep;
1363 free(tcsp);
1364 } else
1365 colsep = FALSE;
1366
1367 return colsep;
1368 }
1369
1370 /* TblGetRowSep() -- get row separater spec, if any, for a entry
1371 *
1372 */
1373
1374
1375 bool
TblGetRowSep(short col,Element_t * entry,tblsource source)1376 TblGetRowSep(short col, /* column number */
1377 Element_t * entry, /* the entry */
1378 tblsource source) /* context */
1379 {
1380 register struct tblcolspec * tcsp;
1381 register struct tblspanspec * tssp;
1382 register bool rowsep;
1383
1384 if ( entry && (tssp = TblEntrySpanSpec(col, entry, source)) ) {
1385 rowsep = tssp->rowsep;
1386 free(tssp);
1387 } else
1388 if ( entry && (tcsp = TblEntryColSpec(col, entry, source)) ) {
1389 rowsep = tcsp->rowsep;
1390 free(tcsp);
1391 } else {
1392 rowsep = FALSE;
1393 }
1394
1395 return rowsep;
1396 }
1397
1398 /* TblGetmoreRows() -- get moreRows value
1399 *
1400 */
1401
1402
1403 bool
TblGetMoreRows(short col,Element_t * entry,tblsource source)1404 TblGetMoreRows(short col, /* column number */
1405 Element_t * entry, /* the entry */
1406 tblsource source) /* context */
1407 {
1408 register char * cp;
1409
1410
1411 if ( cp = FindAttValByName(entry, "MOREROWS") )
1412 return atoi(cp);
1413 else
1414 return 0;
1415 }
1416
1417 /* TblColAdv() -- advance pointer to next entry, if appropriate
1418 *
1419 */
1420
1421
1422 bool
TblColAdv(short col,Element_t * ep,struct tblformat * tfp,tblsource source)1423 TblColAdv(short col, /* the current column */
1424 Element_t *ep, /* pointer to entry */
1425 struct tblformat * tfp, /* pointer to prevailing format */
1426 tblsource source) /* context */
1427 {
1428 register bool bump;
1429 register struct tblspanspec * tssp;
1430
1431
1432 bump = TRUE;
1433
1434 if ( tssp = TblEntrySpanSpec(col, ep, source) ) {
1435 bump = tssp->align != Span;
1436 free(tssp);
1437 }
1438
1439 return bump;
1440 }
1441
1442 /* TblEntryColSpec() -- get a completely localized colspec for an entry
1443 *
1444 */
1445
1446
1447 struct tblcolspec *
TblEntryColSpec(short num,Element_t * ep,tblsource source)1448 TblEntryColSpec(short num, /* column number */
1449 Element_t * ep, /* entry */
1450 tblsource source) /* context */
1451 {
1452 register int i;
1453 register bool throwAway;
1454 register char * cp;
1455 register struct tblcolspec * tcsp, * tcsp2;
1456
1457
1458 tcsp = tcsp2 = 0;
1459 throwAway = FALSE;
1460
1461 if ( (cp = FindAttValByName(ep, "COLNAME")) ) {
1462 if ( ! (tcsp = TblFindColSpec(cp, source)) ) {
1463 fprintf(stderr, "? can't find column name '%s'\n", cp);
1464 }
1465 }
1466
1467 if ( tcsp2 = TblFindColNum(num, source) ) {
1468 tcsp = TblDoColSpec(num, ep, tcsp2, source);
1469 throwAway = TRUE;
1470 }
1471
1472 tcsp2 = TblDoColSpec(num, ep, tcsp, source);
1473
1474 if ( throwAway )
1475 free(tcsp);
1476
1477 return tcsp2;
1478 }
1479
1480 /* TblEntrySpanSpec() -- get a completely localized spanspec for an entry
1481 *
1482 */
1483
1484
1485 struct tblspanspec *
TblEntrySpanSpec(short num,Element_t * ep,tblsource source)1486 TblEntrySpanSpec(short num, /* column number */
1487 Element_t * ep, /* entry */
1488 tblsource source) /* context */
1489 {
1490 register char * cp, * cp2;
1491 register struct tblspanspec * tssp, * tssp2;
1492
1493
1494 tssp2 = 0;
1495
1496 if ( !(cp = FindAttValByName(ep, "SPANNAME")) ||
1497 !(tssp2 = TblFindSpanSpec(cp, source)) ) {
1498
1499 if ( !FindAttValByName(ep, "NAMEST") )
1500 return 0;
1501 }
1502
1503 tssp = TblDoSpanSpec(ep, tssp2, source);
1504
1505 if ( tssp->start && tssp->end &&
1506 (tssp->start->num < num) && (tssp->end->num >= num) ) {
1507 tssp->align = Span;
1508 }
1509
1510 return tssp;
1511 }
1512
1513 /* TblFormatMatch() -- compare two format rows for consistency
1514 *
1515 */
1516
1517
1518 bool
TblFormatMatch(struct tblformat * tf1,struct tblformat * tf2)1519 TblFormatMatch(struct tblformat * tf1, /* one row */
1520 struct tblformat * tf2) /* the other */
1521 {
1522 register int i;
1523
1524 if ( tf1->cols != tf2->cols ) {
1525 return FALSE;
1526 }
1527
1528 for ( i=0; i < tf1->cols; i++ ) {
1529
1530 if ( tf1->colformat[i] != tf2->colformat[i] ) {
1531 return FALSE;
1532 }
1533 if ( strcmp(tf1->colwidth[i], tf2->colwidth[i]) ) {
1534 return FALSE;
1535 }
1536 if ( strcmp(tf1->font[i], tf2->font[i]) ) {
1537 return FALSE;
1538 }
1539 if ( tf1->colsep[i] != tf2->colsep[i] ) {
1540 return FALSE;
1541 }
1542 if ( tf1->rowsep[i] != tf2->rowsep[i] ) {
1543 return FALSE;
1544 }
1545 if ( tf1->moreRows[i] || tf2->moreRows[i] ) {
1546 return FALSE;
1547 }
1548 }
1549
1550 return TRUE;
1551 }
1552
1553 /* TblPrintFormat() -- print a tbl format structure
1554 *
1555 */
1556
1557
1558 void
TblPrintFormat(FILE * fP,struct tblformat * tfp)1559 TblPrintFormat(FILE * fP, /* where to print */
1560 struct tblformat * tfp) /* the structure */
1561 {
1562 register int i;
1563 register struct tblformat * tfp2, * tfp3;
1564 static char buf[3] = "\000\000";
1565
1566
1567 for ( tfp2=tfp, tfp3=0; tfp2; tfp2=tfp2->next ) {
1568 for ( i=1; i <= tfp->cols; i++ ) {
1569 if ( i > 1 )
1570 OutputString(" ", fP, 1);
1571 if ( tfp3 && tfp3->moreRows[i] )
1572 OutputString("\\^", fP, 1);
1573 else {
1574 buf[0] = tfp2->colformat[i];
1575 OutputString(buf, fP, 1);
1576 }
1577 if ( tfp2->colwidth[i][0] ) {
1578 OutputString("w(", fP, 1);
1579 OutputString(tfp2->colwidth[i], fP, 1);
1580 OutputString(")", fP, 1);
1581 }
1582 if ( tfp2->font[i][0] )
1583 OutputString(tfp2->font[i], fP, 1);
1584 if ( tfp2->colsep[i] )
1585 OutputString("|", fP, 1);
1586 }
1587 if ( ! tfp2->next )
1588 OutputString(".", fP, 1);
1589 OutputString("^", fP, 1);
1590 tfp3 = tfp2;
1591 }
1592 }
1593
1594 /* TblTRowStart() -- start a row (not much to do)
1595 *
1596 * TO DO:
1597 *
1598 * nothing..
1599 *
1600 */
1601
1602
1603
1604 void
TblTRowStart(Element_t * ep,FILE * fP)1605 TblTRowStart(Element_t * ep,
1606 FILE * fP)
1607 {
1608
1609 /* nothing to do */
1610
1611 tblrow++; /* except note that we're within a new row */
1612
1613 }
1614
1615 /* TblTRowEnd() -- end a row
1616 *
1617 * TO DO:
1618 *
1619 * output a row end character (newline)
1620 * if the current row had a rowsep, then output a "fake" row
1621 * with underlines in the proper place(s).
1622 */
1623
1624
1625
1626 void
TblTRowEnd(Element_t * ep,FILE * fP)1627 TblTRowEnd(Element_t * ep,
1628 FILE * fP)
1629 {
1630 register int i, k;
1631 register tblsource source;
1632 register bool startedRow, didSep;
1633 register struct tblformat * rfp;
1634
1635
1636 OutputString("^", fP, 1);
1637
1638 /* get the format for this row */
1639
1640 if ( !strcmp(ep->parent->gi, "TFoot") )
1641 source = TFoot;
1642 else
1643 if ( !strcmp(ep->parent->gi, "THead") )
1644 source = THead;
1645 else
1646 source = TBody;
1647
1648 rfp = TblBuild1Format(ep, TRUE, source);
1649 startedRow = FALSE;
1650 didSep = FALSE;
1651
1652 for ( i=1; i <= formP->cols; i++ ) {
1653 if ( rfp->rowsep[i] ||
1654 (didSep && (rfp->colformat[i] == 's')) ) {
1655 if ( ! startedRow ) {
1656 OutputString("^", fP, 1);
1657 for ( k=1; k < i; k++ )
1658 OutputString("\007", fP, 1);
1659 startedRow = TRUE;
1660 }
1661 OutputString("_\007", fP, 1);
1662 didSep = TRUE;
1663 } else {
1664 if ( startedRow )
1665 OutputString("\007", fP, 1);
1666 }
1667 didSep = FALSE;
1668 }
1669 free(rfp); /* clear that row.. */
1670
1671 if ( startedRow )
1672 OutputString("^", fP, 1);
1673 }
1674
1675 /* TblTEntryStart() -- start an entry (block of filled text if
1676 * appropriate)
1677 *
1678 * TO DO:
1679 *
1680 * if text length > BOFTTextThresh or there is PI,
1681 * then output "T{\n", else do nothing
1682 *
1683 */
1684
1685
1686
1687 void
TblTCellStart(Element_t * ep,FILE * fP)1688 TblTCellStart(Element_t * ep,
1689 FILE * fP)
1690 {
1691 register int i;
1692 register Element_t * ep2;
1693 register bool sawPI;
1694
1695
1696 for ( i=0, sawPI=FALSE; (i < ep->ncont) && !sawPI; i++ )
1697 if ( ep->cont[i].type == '?' )
1698 sawPI = TRUE;
1699
1700 if ( sawPI || (TblCountContent(ep) > BOFTTextThresh) ) {
1701 tblBOFTCount++;
1702 OutputString("T{^", fP, 1);
1703 tblinBOFT = TRUE; /* within a boft now */
1704 }
1705 }
1706
1707 /* TblCountContent() -- count all content below the given element
1708 *
1709 *
1710 */
1711
1712
1713
1714 int
TblCountContent(Element_t * ep)1715 TblCountContent(Element_t * ep) /* the element to look under */
1716 {
1717 register int i, count;
1718
1719
1720 count = 0;
1721
1722 for ( i=0; i < ep->ncont; i++ ) {
1723 if ( ep->cont[i].type == '-' ) {
1724 count += strlen(ep->cont[i].ch.data);
1725 } else
1726 if ( ep->cont[i].type == '(' ) {
1727 count += TblCountContent(ep->cont[i].ch.elem);
1728 }
1729 }
1730
1731 return count;
1732 }
1733
1734 /* TblTEntryEnd() -- end an entry
1735 *
1736 * TO DO:
1737 *
1738 * if within BOFT, output "T}"
1739 * if not last entry, output tab character
1740 *
1741 */
1742
1743
1744
1745 void
TblTCellEnd(Element_t * ep,FILE * fP)1746 TblTCellEnd(Element_t * ep,
1747 FILE * fP)
1748 {
1749 register Element_t * ep2;
1750
1751
1752 if ( tblinBOFT ) {
1753 OutputString("^T}", fP, 1);
1754 tblinBOFT = FALSE; /* back out again */
1755 }
1756
1757 for ( ep2=ep->next; ep2; ep2=ep2->next ) {
1758 if ( !strcmp(ep2->gi, "ENTRY") || !strcmp(ep2->gi, "ENTRYTBL") ) {
1759 OutputString("\007", fP, 1);
1760 break;
1761 }
1762 if ( !strcmp(ep2->gi, "ROW") )
1763 break;
1764 }
1765 }
1766
1767 /* TblDoColSpec() -- process one element to create a new colspec
1768 *
1769 *
1770 */
1771
1772
1773
1774 struct tblcolspec *
TblDoColSpec(short number,Element_t * ep,struct tblcolspec * pcsp,tblsource source)1775 TblDoColSpec(short number, /* this column number */
1776 Element_t * ep, /* element containing colspec stuff */
1777 struct tblcolspec * pcsp, /* prevailing colspec (with defaults) */
1778 tblsource source) /* precedence level of the resulting spec */
1779 {
1780 register char * cp;
1781 register struct tblcolspec * tcsp;
1782
1783
1784 Calloc(1, tcsp, struct tblcolspec);
1785
1786 if ( cp = FindAttValByName(ep, "COLNAME") )
1787 strcpy(tcsp->name, cp);
1788
1789 tcsp->num = number;
1790 tcsp->source = source;
1791
1792 if ( cp = FindAttValByName(ep, "ALIGN") ) {
1793 if ( !strcmp(cp, "LEFT") ) tcsp->align = Left;
1794 else if ( !strcmp(cp, "RIGHT") ) tcsp->align = Right;
1795 else if ( !strcmp(cp, "CENTER") ) tcsp->align = Center;
1796 else if ( !strcmp(cp, "JUSTIFY") ) tcsp->align = Justify;
1797 else if ( !strcmp(cp, "CHAR") ) tcsp->align = Char;
1798 } else
1799 tcsp->align = ( pcsp ) ? pcsp->align : Left;
1800
1801 if ( cp = FindAttValByName(ep, "CHAR") )
1802 tcsp->alignchar = cp[0];
1803 else
1804 tcsp->alignchar = ( pcsp ) ? pcsp->alignchar : 0;
1805
1806 if ( cp = FindAttValByName(ep, "CHAROFF") )
1807 tcsp->aligncharoff = atoi(cp);
1808 else
1809 tcsp->aligncharoff = ( pcsp ) ? pcsp->aligncharoff : 0;
1810
1811 if ( cp = FindAttValByName(ep, "COLWIDTH") )
1812 strcpy(tcsp->colwidth, cp);
1813 else
1814 strcpy(tcsp->colwidth, ( pcsp ) ? pcsp->colwidth : "");
1815
1816 if ( cp = FindAttValByName(ep, "COLSEP") )
1817 tcsp->colsep = !strcmp(cp, "1");
1818 else
1819 tcsp->colsep = ( pcsp ) ? pcsp->colsep : FALSE;
1820
1821 if ( cp = FindAttValByName(ep, "ROWSEP") )
1822 tcsp->rowsep = !strcmp(cp, "1");
1823 else
1824 tcsp->rowsep = ( pcsp ) ? pcsp->rowsep : FALSE;
1825
1826 return tcsp;
1827 }
1828
1829 /* TblDoSpanSpec() -- process one element to create a new spanspec
1830 *
1831 * Note that there's a hack inside here... NameSt and NameEnd are
1832 * supposed to point at colnames, but if no colname is found, this
1833 * code will look for a colnum by the same value.
1834 */
1835
1836
1837
1838 struct tblspanspec *
TblDoSpanSpec(Element_t * ep,struct tblspanspec * pssp,tblsource source)1839 TblDoSpanSpec(Element_t * ep, /* element containing spanspec stuff */
1840 struct tblspanspec * pssp, /* prevailing spanspec (with defaults) */
1841 tblsource source) /* precedence level of the resulting spec */
1842 {
1843 register char * cp;
1844 register struct tblspanspec * tssp;
1845 register struct tblcolspec * tcsp;
1846
1847
1848 Calloc(1, tssp, struct tblspanspec);
1849
1850 if ( cp = FindAttValByName(ep, "SPANNAME") ) strcpy(tssp->name, cp);
1851 tssp->source = source;
1852
1853 if ( cp = FindAttValByName(ep, "NAMEST") ) {
1854 if ( (tcsp = TblFindColSpec(cp, source)) ||
1855 (tcsp = TblFindColNum(atoi(cp), source)) ) {
1856 tssp->start = tcsp;
1857 } else {
1858 fprintf(stderr, "? spanspec namest points to unknown column '%s'\n", cp);
1859 tssp->start = 0;
1860 }
1861 } else {
1862 if ( pssp && pssp->start ) {
1863 tssp->start = pssp->start;
1864 }
1865 }
1866
1867 if ( cp = FindAttValByName(ep, "NAMEEND") ) {
1868 if ( (tcsp = TblFindColSpec(cp, source)) ||
1869 (tcsp = TblFindColNum(atoi(cp), source)) ) {
1870 tssp->end = tcsp;
1871 } else {
1872 fprintf(stderr, "? spanspec nameend points to unknown column '%s'\n", cp);
1873 tssp->end = 0;
1874 }
1875 } else {
1876 if ( pssp && pssp->end ) {
1877 tssp->end = pssp->end;
1878 }
1879 }
1880
1881 if ( cp = FindAttValByName(ep, "ALIGN") ) {
1882 if ( !strcmp(cp, "LEFT") ) tssp->align = Left;
1883 else if ( !strcmp(cp, "RIGHT") ) tssp->align = Right;
1884 else if ( !strcmp(cp, "CENTER") ) tssp->align = Center;
1885 else if ( !strcmp(cp, "JUSTIFY") ) tssp->align = Justify;
1886 else if ( !strcmp(cp, "CHAR") ) tssp->align = Char;
1887 } else {
1888 if ( pssp )
1889 tssp->align = pssp->align;
1890 }
1891
1892 if ( cp = FindAttValByName(ep, "CHAR") )
1893 tssp->alignchar = cp[0];
1894 else {
1895 if ( pssp )
1896 tssp->alignchar = pssp->alignchar;
1897 }
1898 if ( cp = FindAttValByName(ep, "CHAROFF") )
1899 tssp->aligncharoff = atoi(cp);
1900 else {
1901 if ( pssp )
1902 tssp->alignchar = pssp->alignchar;
1903 }
1904
1905 if ( cp = FindAttValByName(ep, "COLSEP") )
1906 tssp->colsep = !strcmp(cp, "1");
1907 else {
1908 if ( pssp )
1909 tssp->colsep = pssp->colsep;
1910 }
1911 if ( cp = FindAttValByName(ep, "ROWSEP") )
1912 tssp->rowsep = !strcmp(cp, "1");
1913 else {
1914 if ( pssp )
1915 tssp->rowsep = pssp->rowsep;
1916 }
1917
1918 return tssp;
1919 }
1920
1921 /* TblFindColSpec() -- find a table colspec by name (colname)
1922 *
1923 */
1924
1925
1926
1927 struct tblcolspec *
TblFindColSpec(char * name,tblsource source)1928 TblFindColSpec(char * name, /* the name we're looking for */
1929 tblsource source) /* the context in which to find it */
1930 {
1931 register struct tblcolspec * tcsp;
1932
1933
1934 /* first, try to find the one in the right "source" */
1935
1936 for ( tcsp=tblColSpec; tcsp; tcsp=tcsp->next ) {
1937 if ( (tcsp->source == source) && !strcmp(tcsp->name, name) )
1938 return tcsp;
1939 }
1940
1941 /* else, try to find one from a TGroup.. */
1942
1943 for ( tcsp=tblColSpec; tcsp; tcsp=tcsp->next ) {
1944 if ( (tcsp->source == TGroup) && !strcmp(tcsp->name, name) )
1945 return tcsp;
1946 }
1947
1948 /* else not found.. */
1949
1950 return 0;
1951 }
1952
1953 /* TblFindColNum() -- find a table colspec by number
1954 *
1955 */
1956
1957
1958
1959 struct tblcolspec *
TblFindColNum(short number,tblsource source)1960 TblFindColNum(short number, /* the number we're looking for */
1961 tblsource source) /* the context in which to find it */
1962 {
1963 register struct tblcolspec * tcsp;
1964
1965
1966
1967 /* first, try to find the one in the right "source" */
1968
1969 for ( tcsp=tblColSpec; tcsp; tcsp=tcsp->next ) {
1970 if ( (tcsp->num == number) &&
1971 ((tcsp->source == source) ||
1972 ((source == THead) && (tcsp->source == TGroup))) )
1973 return tcsp;
1974 }
1975
1976 /* else, try to find one from a TGroup.. */
1977
1978 for ( tcsp=tblColSpec; tcsp; tcsp=tcsp->next ) {
1979 if ( (tcsp->source == TGroup) && (tcsp->num == number) )
1980 return tcsp;
1981 }
1982
1983 /* else not found.. */
1984
1985 return 0;
1986 }
1987
1988 /* TblFindSpanSpec() -- find a table spanspec by name (spanname)
1989 *
1990 */
1991
1992
1993
1994 struct tblspanspec *
TblFindSpanSpec(char * name,tblsource source)1995 TblFindSpanSpec(char * name, /* the name we're looking for */
1996 tblsource source) /* the context in which to find it */
1997 {
1998 register struct tblspanspec * tssp;
1999
2000
2001 /* first, try to find the one in the right "source" */
2002
2003 for ( tssp=tblSpanSpec; tssp; tssp=tssp->next ) {
2004 if ( !strcmp(tssp->name, name) &&
2005 ((tssp->source == source) ||
2006 ((source == THead) && (tssp->source == TGroup))) )
2007 return tssp;
2008 }
2009
2010 /* else not found.. */
2011
2012 return 0;
2013 }
2014