2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
24 * Copyright 1993 Open Software Foundation, Inc., Cambridge, Massachusetts.
25 * All rights reserved.
29 * Open Software Foundation, Inc.
31 * Permission is hereby granted to use, copy, modify and freely distribute
32 * the software in this file and its documentation for any purpose without
33 * fee, provided that the above copyright notice appears in all copies and
34 * that both the copyright notice and this permission notice appear in
35 * supporting documentation. Further, provided that the name of Open
36 * Software Foundation, Inc. ("OSF") not be used in advertising or
37 * publicity pertaining to distribution of the software without prior
38 * written permission from OSF. OSF makes no representations about the
39 * suitability of this software for any purpose. It is provided "as is"
40 * without express or implied warranty.
42 /* ________________________________________________________________________
44 * Program to manipulate SGML instances.
46 * This module is for handling OSF table markup, printing TeX or tbl
47 * (tbl) markup to the output stream. Also, table markup checking is
48 * done here. Yes, this depends on the DTD, but it makes translation
49 * specs much cleaner (and makes some things possible.
51 * Incomplete / not implemented / limitations / notes:
52 * vertical alignment (valign attr)
54 * 'wrap hint' attribute
55 * row separators are for the whole line, not per cell (the prog looks
56 * at rowsep for the 1st cell and applies it to the whole row)
57 * trusts that units if colwidths are acceptable to LaTeX and tbl
58 * "s" is an acceptable shorthand for "span" in model attributes
60 * A note on use of OutputString(): Strings with backslashes (\) need lots
61 * of backslashes. You have to escape them for the C compiler, and escape
62 * them again for OutputString() itself.
63 * ________________________________________________________________________
68 "$XConsortium: tables.c /main/3 1996/06/19 17:13:17 drk $";
76 #include <sys/types.h>
79 #include <tptregexp.h>
81 #include "translate.h"
83 /* text width of page, in inches */
90 /* these cover the attributes on the table element */
93 char *halign, **halign_v;
94 char *model, **model_v;
95 char *colwidth, **colwidth_v;
96 char *colsep, **colsep_v;
97 char *colweight, **colweight_v;
99 int n_halign, n_model, n_colwidth, n_colsep, n_colweight;
105 /* some flags, set when the table tag is processed, used later */
106 static int rowsep, siderules;
107 static int frametop, framebot, frameall;
108 static char basemodel[128]; /* model for table (in formatting language) */
109 static int spaninfo[MAXCOLS]; /* 100 columns, max */
110 static TableInfo TheTab;
112 /* forward references */
113 void SetTabAtts(Element_t *, TableInfo *, int);
114 void FreeTabAtts(TableInfo *);
115 void CheckTable(Element_t *);
116 void TblTable(Element_t *, FILE *);
117 void TblTableCellStart(Element_t *, FILE *);
118 void TblTableCellEnd(Element_t *, FILE *);
119 void TblTableRowStart(Element_t *, FILE *);
120 void TblTableRowEnd(Element_t *, FILE *);
121 void TblTableTop(Element_t *, FILE *);
122 void TblTableBottom(Element_t *, FILE *);
123 void TexTable(Element_t *, FILE *);
124 void TexTableCellStart(Element_t *, FILE *);
125 void TexTableCellEnd(Element_t *, FILE *);
126 void TexTableRowStart(Element_t *, FILE *);
127 void TexTableRowEnd(Element_t *, FILE *);
128 void TexTableTop(Element_t *, FILE *);
129 void TexTableBottom(Element_t *, FILE *);
131 /* ______________________________________________________________________ */
132 /* Hard-coded stuff for OSF DTD tables.
133 * Here are the TABLE attributes (for handy reference):
134 * ncols NUMBER num of cells/row should match
135 * model CDATA column prototypes for this table
136 * colwidth NUTOKENS absolute widths of cols
137 * colweight NUMBERS column weights
138 * halign CDATA horiz alignment for columns
139 * valign CDATA vertical alignment for columns
140 * colsep NUMBERS use col separators (lines)?
141 * rowsep NUMBERS use row separators (lines)?
142 * wrap NUMBERS wrap hints for columns
143 * repeathead NUMBER carry title rows to other pages
144 * frame (top|bottom|topbot|all|sides|none) frame style
146 * The 'wrap' attribute is never used.
148 * Usage in transpec: _osftable [tex|tbl|check] ['aspect']
150 * rowstart stuff to do at start of a row (tests for spanning)
151 * rowend stuff to do at end of a row (eg, rules, etc.)
152 * cellstart stuff to do at start of a cell (eg, handle actual
153 * spanning instructions, etc.)
154 * cellend stuff to do at end of a cell (eg, cell separator)
155 * top stuff to do at top of the table
156 * (like whether or not it needs a starting horiz rule)
157 * bottom stuff to do at bottom of the table
158 * (like whether or not it needs an ending horiz rule)
159 * (nothing) the 'cols' param to LaTeX's \begin{tabular}[pos]{cols}
160 * or 'options' and 'formats' part in tbl
165 * Pointer to element under consideration.
166 * FILE pointer to where to write output.
167 * Vector of args to _osftable
168 * Count of args to _osftable
178 /* Check params and dispatch to appropriate routine */
180 if (ac > 1 && !strcmp(av[1], "check")) CheckTable(e);
182 else if (!strcmp(av[1], "tbl")) {
184 if (!strcmp(av[2], "cellstart")) TblTableCellStart(e, fp);
185 else if (!strcmp(av[2], "cellend")) TblTableCellEnd(e, fp);
186 else if (!strcmp(av[2], "rowstart")) TblTableRowStart(e, fp);
187 else if (!strcmp(av[2], "rowend")) TblTableRowEnd(e, fp);
188 else if (!strcmp(av[2], "top")) TblTableTop(e, fp);
189 else if (!strcmp(av[2], "bottom")) TblTableBottom(e, fp);
190 else fprintf(stderr, "Unknown %s table instruction: %s\n",
193 else TblTable(e, fp);
196 else if (!strcmp(av[1], "tex")) {
198 if (!strcmp(av[2], "cellstart")) TexTableCellStart(e, fp);
199 else if (!strcmp(av[2], "cellend")) TexTableCellEnd(e, fp);
200 else if (!strcmp(av[2], "rowstart")) TexTableRowStart(e, fp);
201 else if (!strcmp(av[2], "rowend")) TexTableRowEnd(e, fp);
202 else if (!strcmp(av[2], "top")) TexTableTop(e, fp);
203 else if (!strcmp(av[2], "bottom")) TexTableBottom(e, fp);
204 else fprintf(stderr, "Unknown %s table instruction: %s\n",
207 else TexTable(e, fp);
210 else fprintf(stderr, "Unknown table type: %s\n", av[1]);
214 /* ______________________________________________________________________ */
215 /* Set values of the our internal table structure based on the table's
216 * attributes. (This is also called for rows, since tables and rows
217 * share many of the same attributes.)
219 * Pointer to element under consideration.
220 * Pointer table info structure which will be filled in.
221 * Flag saying whether or not to set global variables based on attrs.
232 memset(t, 0, sizeof(TableInfo));
234 /* remember values of attributes */
235 if ((at = FindAttValByName(e, "HALIGN"))) t->halign = at;
236 if ((at = FindAttValByName(e, "MODEL"))) t->model = at;
237 if ((at = FindAttValByName(e, "COLWIDTH"))) t->colwidth = at;
238 if ((at = FindAttValByName(e, "COLSEP"))) t->colsep = at;
239 if ((at = FindAttValByName(e, "COLWEIGHT"))) t->colweight = at;
240 if ((at = FindAttValByName(e, "FRAME"))) t->frame = at;
241 if ((at = FindAttValByName(e, "REPEATHEAD"))) t->repeathead = atoi(at);
242 if ((at = FindAttValByName(e, "NCOLS"))) t->ncols = at;
244 /* Set some things for later when processing this table */
248 frametop = framebot = 1; /* default style */
250 /* For now we look at the first number of rowsep - it controls the
251 * horiz rule for then entire row. (not easy to specify lines that
252 * span only some columns in tex or tbl. */
253 if ((at = FindAttValByName(e, "ROWSEP"))) rowsep = atoi(at);
257 /* top|bottom|topbot|all|sides|none */
258 if (!strcmp(t->frame, "NONE") || !strcmp(t->frame, "SIDES"))
259 frametop = framebot = 0;
260 else if (!strcmp(t->frame, "TOP")) framebot = 0;
261 else if (!strcmp(t->frame, "BOTTOM")) frametop = 0;
264 /* tbl and tex like lower case for units. convert. */
267 for (cp=t->colwidth; *cp; cp++)
268 if (isupper(*cp)) *cp = tolower(*cp);
271 /* Now, split (space-separated) strings into vectors. Hopefully, the
272 * number of elements in each vector matches the number of columns.
274 t->halign_v = Split(t->halign, &t->n_halign, S_STRDUP|S_ALVEC);
275 t->model_v = Split(t->model, &t->n_model, S_STRDUP|S_ALVEC);
276 t->colwidth_v = Split(t->colwidth, &t->n_colwidth, S_STRDUP|S_ALVEC);
277 t->colweight_v = Split(t->colweight, &t->n_colweight, S_STRDUP|S_ALVEC);
278 t->colsep_v = Split(t->colsep, &t->n_colsep, S_STRDUP|S_ALVEC);
280 /* Determin the _numeric_ number of columns, "nc". The order in which we
281 * check things to set nc is: NCOLS attribute, # of child element of 1st
282 * row, number of tokens in the various attr lists.
284 if (t->ncols) t->nc = atoi(t->ncols);
286 /* If ncols attribute not set, see how many children first child has.
287 * I can't see how this can be non-zero (unless there are no rows, or
288 * no rows have any cells).
290 if (!t->nc && e->necont) t->nc = e->econt[0]->necont;
292 /* If ncols still not set, guess it from other attrs. Last resort. */
294 if (t->n_halign) t->nc = t->n_halign;
295 else if (t->n_model) t->nc = t->n_model;
296 else if (t->n_colwidth) t->nc = t->n_colwidth;
297 else if (t->n_colweight) t->nc = t->n_colweight;
298 else if (t->n_colsep) t->nc = t->n_colsep;
302 /* ______________________________________________________________________ */
304 /* Free the storage of info use by the table info structure. (not the
305 * structure itself, but the strings its elements point to)
307 * Pointer table info structure to be freed.
315 if (t->halign_v) free(*t->halign_v);
316 if (t->model_v) free(*t->model_v);
317 if (t->colwidth_v) free(*t->colwidth_v);
318 if (t->colweight_v) free(*t->colweight_v);
319 if (t->colsep_v) free(*t->colsep_v);
322 /* ______________________________________________________________________ */
323 /* Check the attributes and children of the table pointed to by e.
324 * Report problems and inconsistencies to stderr.
326 * Pointer to element (table) under consideration.
334 int pr_loc=0; /* flag to say if we printed location */
337 char *tpref = "Table Check"; /* prefix for err messages */
339 "Table Check: %s ('%s') has wrong number of tokens. Expecting %d.\n";
341 if (strcmp(e->gi, "TABLE")) {
342 fprintf(stderr, "%s: Not pointing to a table!\n", tpref);
346 FreeTabAtts(&TheTab); /* free storage, if allocated earlier */
347 SetTabAtts(e, &TheTab, 1); /* look at attributes */
349 /* NCOLS attribute set? */
352 fprintf(stderr, "%s: NCOLS attribute missing. Inferred as %d.\n",
356 /* HALIGN attribute set? */
357 if (!TheTab.halign) {
359 fprintf(stderr, "%s: HALIGN attribute missing.\n", tpref);
362 /* See if the number of cells in each row matches */
363 for (r=0; r<e->necont; r++) {
364 if (e->econt[r]->necont != TheTab.nc) {
366 fprintf(stderr, "%s: NCOLS (%d) differs from actual number of cells (%d) in row %d.\n",
367 tpref, TheTab.nc, e->econt[r]->necont, r);
373 if (TheTab.nc != TheTab.n_halign) { /* number of tokens OK? */
375 fprintf(stderr, ncolchk, "HALIGN", TheTab.halign, TheTab.nc);
377 else { /* values OK? */
378 for (i=0; i<TheTab.nc; i++) {
379 if (*TheTab.halign_v[i] != 'c' && *TheTab.halign_v[i] != 'l' &&
380 *TheTab.halign_v[i] != 'r') {
382 fprintf(stderr, "%s: HALIGN (%d) value wrong: %s\n",
383 tpref, i, TheTab.halign_v[i]);
390 if (TheTab.colwidth) {
391 if (TheTab.nc != TheTab.n_colwidth) { /* number of tokens OK? */
393 fprintf(stderr, ncolchk, "COLWIDTH", TheTab.colwidth, TheTab.nc);
395 else { /* values OK? */
396 for (i=0; i<TheTab.nc; i++) {
398 /* check that the units after the numbers are OK
405 /* check COLWEIGHT */
406 if (TheTab.colweight) {
407 if (TheTab.nc != TheTab.n_colweight) { /* number of tokens OK? */
409 fprintf(stderr, ncolchk, "COLWEIGHT", TheTab.colweight, TheTab.nc);
411 else { /* values OK? */
412 for (i=0; i<TheTab.nc; i++) { /* check that magitude is reasonable */
413 wt = atof(TheTab.colweight_v[i]);
416 fprintf(stderr, "%s: unreasonable COLWEIGHT value: %f.\n",
425 if (TheTab.nc != TheTab.n_colsep) { /* number of tokens OK? */
427 fprintf(stderr, ncolchk, "COLSEP", TheTab.colsep, TheTab.nc);
429 else { /* values OK? */
430 for (i=0; i<TheTab.nc; i++) {
435 /* See if MODEL has the same number of tokens as NCOLS. Then do model. */
437 if (TheTab.nc != TheTab.n_model) {
439 fprintf(stderr, ncolchk, "MODEL", TheTab.model, TheTab.nc);
442 for (r=0; r<e->necont; r++) {
443 /* only check normal rows */
444 if (strcmp(e->econt[r]->gi, "ROW")) continue;
445 for (c=0; c<e->econt[r]->necont; c++) {
446 if (!strcmp(TheTab.model_v[c], "text") ||
447 !strcmp(TheTab.model_v[c], "-")) continue;
448 if (e->econt[r]->econt[c]->necont &&
449 strcmp(e->econt[r]->econt[c]->econt[0]->gi, TheTab.model_v[c])) {
450 fprintf(stderr, "%s: MODEL wants %s, but cell contains %s: row %d, cell %d.\n",
451 tpref, TheTab.model_v[c],
452 e->econt[r]->econt[c]->econt[0]->gi, r, c);
460 fprintf(stderr, "%s: Above problem in table located at:\n", tpref);
461 PrintLocation(e, stderr);
465 /* ______________________________________________________________________ */
466 /* Do the "right thing" for the table spec for tbl (troff) tables. This will
467 * generate the "center,box,tab(@)..." and the column justification stuff.
469 * Pointer to element (table) under consideration.
470 * FILE pointer to where to write output.
481 char *cp, wbuf[1500], **widths=0, **widths_v=0, *mp;
483 FreeTabAtts(&TheTab); /* free storage, if allocated earlier */
484 SetTabAtts(e, &TheTab, 1); /* look at attributes */
486 fr = "box"; /* default framing */
490 if (!strcmp(TheTab.frame, "ALL")) {
492 frametop = framebot = 0;
498 if (!strcmp(TheTab.frame, "SIDES")) siderules = 1;
500 else frametop = framebot = 0; /* because 'box' is default */
501 fprintf(fp, "center, %s%s tab(@);\n", fr, ((*fr)?",":""));
503 /* Figure out the widths, based either on "colwidth" or "colweight".
504 * (we pick width over weight if both are specified). */
505 if (TheTab.colwidth && TheTab.nc == TheTab.n_colwidth) {
506 widths = TheTab.colwidth_v;
508 else if (TheTab.colweight && TheTab.nc == TheTab.n_colweight) {
509 for (n=0,i=0; i<TheTab.nc; i++) n += atoi(TheTab.colweight_v[i]);
512 for (i=0; i<TheTab.nc; i++) {
513 sprintf(cp, "%5.3fin", atof(TheTab.colweight_v[i])*(TEXTWIDTH/tot));
518 widths_v = Split(wbuf, 0, S_ALVEC);
522 /* Remember the base model in case we do spans later. We write it
523 * into a static buffer, then output it at once. */
525 if (siderules) *mp++ = '|';
526 for (i=0; i<TheTab.nc; i++) {
527 /* If width specified, use it; else if halign set, use it; else left. */
528 if (widths && widths[i][0] != '0' && widths[i][1] != EOS) {
530 strcpy(mp, TheTab.halign_v[i]);
534 strcpy(mp, widths[i]);
538 else if (TheTab.halign && TheTab.nc == TheTab.n_halign) {
540 strcpy(mp, TheTab.halign_v[i]);
547 /* See if we want column separators. */
550 if ( (i+1) < TheTab.nc ) {
551 if ( *TheTab.colsep_v[i] == '1' )
553 if ( *TheTab.colsep_v[i] == '2') {
560 if (siderules) *mp++ = '|';
564 OutputString(basemodel, fp, 1);
565 OutputString(".^", fp, 1);
567 if (widths_v) free(widths_v);
572 * Pointer to element (cell) under consideration.
573 * FILE pointer to where to write output.
581 /* nothing to do at start of cell */
586 * Pointer to element (cell) under consideration.
587 * FILE pointer to where to write output.
595 /* do cell/col separators */
596 if (e->my_eorder < (TheTab.nc-1)) {
597 if (spaninfo[e->my_eorder] == SPAN_NOT ||
598 spaninfo[e->my_eorder+1] != SPAN_CONT)
599 OutputString("@", fp, 1);
603 /* Look at model attribute for spanning. If set, remember info for when
604 * doing the cells. Called by TblTableRowStart() and TexTableRowStart().
606 * Pointer to element (row) under consideration.
617 /* See if MODEL attr is set */
618 if ((at = FindAttValByName(e, "MODEL"))) {
620 /* Split into tokens, then look at each for the word "span" */
622 spans = Split(at, &n, S_STRDUP|S_ALVEC);
624 /* Mark columns as start-of-span, in-span, or not spanned. Remember
625 * in at list, "spaningo". (Span does not make sense in 1st column.)
627 for (i=1,inspan=0; i<n; i++) {
628 if (StrEq(spans[i], "span") || StrEq(spans[i], "s")) {
629 if (inspan == 0) spaninfo[i-1] = SPAN_START;
630 spaninfo[i] = SPAN_CONT;
634 spaninfo[i] = SPAN_NOT;
638 free(*spans); /* free string */
639 free(spans); /* free vector */
640 spaninfo[TheTab.nc] = SPAN_NOT; /* after last cell */
643 /* if model not set, mark all as not spanning */
645 for (i=0; i<MAXCOLS; i++) spaninfo[i] = SPAN_NOT;
649 /* Output format for cell. Called from TblTableRowStart().
651 * Pointer to table info structure (for this row)
652 * Which cell/column we're considering
653 * Flag saying whether we're on last column
654 * Default format of col, if none is set for this row or table
655 * FILE pointer to where to write output.
667 if (t->halign) OutputString(t->halign_v[i], fp, 1);
668 else if (TheTab.halign) OutputString(TheTab.halign_v[i], fp, 1);
669 else OutputString(def_fmt, fp, 1);
671 if (!lastcol && spaninfo[i+1] != SPAN_CONT) {
673 if (*t->colsep_v[i] == '1')
674 OutputString("|", fp, 1);
675 if (*t->colsep_v[i] == '2')
676 OutputString("||", fp, 1);
678 else if (TheTab.colsep) {
679 if (*TheTab.colsep_v[i] == '1')
680 OutputString("|", fp, 1);
681 if (*TheTab.colsep_v[i] == '2')
682 OutputString("||", fp, 1);
684 else OutputString("|", fp, 1);
686 OutputString(" ", fp, 1);
691 * Pointer to element (row) under consideration.
692 * FILE pointer to where to write output.
701 int i, lastcol, stayhere;
705 /* check if we're spanning, or if HALIGN set */
707 if (check_for_spans(e)) stayhere = 1;
708 SetTabAtts(e, &RowInfo, 0);
709 if (RowInfo.halign) stayhere = 1;
711 if (!stayhere) return;
713 /* Change table layout because we have a span, or the row has HALIGN. */
714 OutputString("^.T&^", fp, 1);
715 basev = Split(basemodel, 0, S_ALVEC|S_STRDUP);
717 for (i=0; i<TheTab.nc; i++) {
719 lastcol = !(i < TheTab.nc-1);
720 if (spaninfo[i] == SPAN_START) {
721 tbl_cell_fmt(&RowInfo, i, lastcol, "c ", fp);
723 else if (spaninfo[i] == SPAN_CONT) {
724 /* See if next col is NOT spanned, and we're not in last col */
725 OutputString("s", fp, 1);
726 if (!lastcol && spaninfo[i+1] != SPAN_CONT) {
727 if (RowInfo.colsep) cp = RowInfo.colsep_v[i];
728 else if (TheTab.colsep) cp = TheTab.colsep_v[i];
732 OutputString("|", fp, 1);
734 OutputString("||", fp, 1);
736 OutputString(" ", fp, 1);
739 tbl_cell_fmt(&RowInfo, i, lastcol, "l ", fp);
741 OutputString("^", fp, 1);
742 OutputString(basemodel, fp, 1);
743 OutputString(".^", fp, 1);
746 FreeTabAtts(&RowInfo);
751 * Pointer to element (row) under consideration.
752 * FILE pointer to where to write output.
762 /* See if we're on the last row, then if we're putting a frame
763 * around the whole table. If so, we need no bottom separator. */
764 if ((e->parent->necont-1) == e->my_eorder) {
765 if (frameall || framebot) return;
767 /* check this row's attributes */
768 if ((at = FindAttValByName(e, "ROWSEP"))) {
769 if (at[0] == '1') fprintf(fp, "_\n");
771 else if (rowsep) /* fprintf(fp, "_\n") */ ;
776 * Pointer to element (table) under consideration.
777 * FILE pointer to where to write output.
780 TblTableTop(Element_t *e, FILE *fp)
782 if (frametop) OutputString("^_^", fp, 1);
786 TblTableBottom(Element_t *e, FILE *fp)
788 if (framebot) OutputString("^_^", fp, 1);
791 /* ______________________________________________________________________ */
792 /* Do the "right thing" for the table spec for TeX tables. This will
793 * generate the arg to \begin{tabular}[xxx].
795 * Pointer to element (table) under consideration.
796 * FILE pointer to where to write output.
806 char *cp, wbuf[1500], **widths=0, **widths_v=0;
808 FreeTabAtts(&TheTab); /* free storage, if allocated earlier */
809 SetTabAtts(e, &TheTab, 1); /* look at attributes */
811 /* Figure out the widths, based either on "colwidth" or "colweight".
812 * (we pick width over weight if both are specified). */
813 if (TheTab.colwidth && TheTab.nc == TheTab.n_colwidth) {
814 widths = TheTab.colwidth_v;
816 else if (TheTab.colweight && TheTab.nc == TheTab.n_colweight) {
817 for (n=0,i=0; i<TheTab.nc; i++) n += atoi(TheTab.colweight_v[i]);
820 for (i=0; i<TheTab.nc; i++) {
821 sprintf(cp, "%5.3fin", atof(TheTab.colweight_v[i])*(TEXTWIDTH/tot));
826 widths_v = Split(wbuf, 0, S_ALVEC);
831 if (strcmp(TheTab.frame, "ALL") && strcmp(TheTab.frame, "SIDES"))
834 if (siderules) OutputString("|", fp, 1);
835 for (i=0; i<TheTab.nc; i++) {
836 /* If width specified, use it; else if halign set, use it; else left. */
837 if (widths && widths[i][0] != '0' && widths[i][1] != EOS) {
838 fprintf(fp, "%sp{%s}", (i?" ":""), widths[i]);
840 else if (TheTab.halign && TheTab.nc == TheTab.n_halign) {
841 fprintf(fp, "%s%s", (i?" ":""), TheTab.halign_v[i]);
844 fprintf(fp, "%sl", (i?" ":""));
845 /* See if we want column separators. */
848 if ( (i+1) < TheTab.nc ) {
849 if ( *TheTab.colsep_v[i] == '1' ) {
852 if ( *TheTab.colsep_v[i] == '2' ) {
859 if (siderules) OutputString("|", fp, 1);
861 if (widths_v) free(widths_v);
866 * Pointer to element (cell) under consideration.
867 * FILE pointer to where to write output.
878 if (spaninfo[e->my_eorder] == SPAN_START) {
879 for (i=e->my_eorder+1,n=1; ; i++) {
880 if (spaninfo[i] == SPAN_CONT) n++;
883 sprintf(buf, "\\\\multicolumn{%d}{%sc%s}", n,
884 (siderules?"|":""), (siderules?"|":""));
885 OutputString(buf, fp, 1);
888 if ((at = FindAttValByName(e->parent, "HALIGN"))) {
889 /* no span, but user wants to change the alignment */
890 h_v = Split(wbuf, 0, S_ALVEC|S_STRDUP);
891 OutputString("\\\\multicolumn{1}{%sc%s}", n,
896 if (spaninfo[e->my_eorder] != SPAN_CONT) OutputString("{", fp, 1);
901 * Pointer to element (cell) under consideration.
902 * FILE pointer to where to write output.
910 if (spaninfo[e->my_eorder] != SPAN_CONT) OutputString("} ", fp, 1);
912 /* do cell/col separators */
913 if (e->my_eorder < (TheTab.nc-1)) {
914 if (spaninfo[e->my_eorder] == SPAN_NOT ||
915 spaninfo[e->my_eorder+1] != SPAN_CONT)
916 OutputString("& ", fp, 1);
920 /* Look at model for spanning. If set, remember it for when doing the cells.
922 * Pointer to element (row) under consideration.
923 * FILE pointer to where to write output.
936 * Pointer to element (row) under consideration.
937 * FILE pointer to where to write output.
947 /* check this row's attributes */
948 if ((at = FindAttValByName(e, "ROWSEP"))) {
949 if (at[0] == '1') OutputString("\\\\\\\\[2mm] \\\\hline ", fp, 1);
951 else if (rowsep) OutputString("\\\\\\\\ ", fp, 1);
953 OutputString("\\\\\\\\ ", fp, 1);
959 * Pointer to element (table) under consideration.
960 * FILE pointer to where to write output.
963 TexTableTop(Element_t *e, FILE *fp)
965 if (frametop) OutputString("\\\\hline", fp, 1);
969 TexTableBottom(Element_t *e, FILE *fp)
971 if (framebot) OutputString("\\\\hline", fp, 1);
974 /* ______________________________________________________________________ */