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