4
** KW Klaus Weide <kweide@enteract.com>
6
** 2 Jul 1999 KW Created.
10
#include <HTStyle.h> /* for HT_LEFT, HT_CENTER, HT_RIGHT */
13
#include <LYGlobalDefs.h>
17
#ifdef SAVE_TIME_NOT_SPACE
18
#define CELLS_GROWBY 16
19
#define ROWS_GROWBY 16
21
#define CELLS_GROWBY 2
25
#ifdef USE_CURSES_PADS
26
# define MAX_STBL_POS (LYwideLines ? MAX_COLS - 1 : LYcols-1)
28
# define MAX_STBL_POS (LYcols-1)
31
/* must be different from HT_ALIGN_NONE and HT_LEFT, HT_CENTER etc.: */
32
#define RESERVEDCELL (-2) /* cell's alignment field is overloaded, this
33
value means cell was reserved by ROWSPAN */
34
#define EOCOLG (-2) /* sumcols' Line field isn't used for line info, this
35
special value means end of COLGROUP */
36
#ifndef NO_AGGRESSIVE_NEWROW
37
# define NO_AGGRESSIVE_NEWROW 0
41
CS_invalid = -1, /* cell "before the first",
42
or empty lines after [ce]bc,
45
CS__0new, /* new, at BOL */
46
CS__0eb, /* starts at BOL, empty, break */
47
CS__eb, /* empty, break */
48
CS__0cb, /* starts at BOL, content, break */
49
CS__cb, /* content, break */
50
CS__0ef, /* starts at BOL, empty, finished */
51
CS__ef, /* empty, finished */
52
CS__0cf, /* starts at BOL, content, finished */
53
CS__cf, /* content, finished */
54
CS__ebc, /* empty, break, more content (maybe @BOL) */
55
CS__cbc /* content, break, more content (maybe @BOL) */
58
typedef struct _STable_states {
59
cellstate_t prev_state; /* Contents type of the previous cell */
60
cellstate_t state; /* Contents type of the worked-on cell */
61
int lineno; /* Start line of the current cell */
62
int icell_core; /* -1 or the 1st cell with <BR></TD> on row */
63
int x_td; /* x start pos of the current cell or -1 */
64
int pending_len; /* For multiline cells, the length of
65
the part on the first line (if
66
state is CS__0?[ec]b) (??), or 0 */
69
typedef struct _STable_cellinfo {
70
int cLine; /* lineno in doc (zero-based): -1 for
71
contentless cells (and cells we do
72
not want to measure and count?),
73
line-of-the-start otherwise. */
74
int pos; /* column where cell starts */
75
int len; /* number of character positions */
76
int colspan; /* number of columns to span */
77
int alignment; /* one of HT_LEFT, HT_CENTER, HT_RIGHT,
84
ROW_ended_by_splitline
87
#define HAS_END_OF_CELL 1
88
#define HAS_BEG_OF_CELL 2
89
#define IS_CONTINUATION_OF_CELL 4
90
#define OFFSET_IS_VALID 8
91
#define OFFSET_IS_VALID_LAST_CELL 0x10
92
#define BELIEVE_OFFSET 0x20
94
typedef struct _STable_rowinfo {
95
/* Each row may be displayed on many display lines, but we fix up
96
positions of cells on this display line only: */
97
int Line; /* lineno in doc (zero-based) */
98
int ncells; /* number of table cells */
100
/* What is the meaning of this?! It is set if:
101
[search for def of fixed_line below]
103
a1) a non-last cell is not at BOL,
104
a2) a non-last cell has something on the first line,
105
b) a >=3-lines-cell not at BOL, the first row non-empty, the 2nd empty;
106
c) a multiline cell not at BOL, the first row non-empty, the rest empty;
107
d) a multiline cell not at BOL, the first row non-empty;
108
e) a singleline non-empty cell not at BOL;
110
Summary: have seen a cell which is one of:
111
(Notation: B: at BOL; L: last; E: the first row is non-empty)
117
Or: has at least two of !B, !L, !E, or: has at most one of B,L,E.
119
REMARK: If this variable is not set, but icell_core is, Line is
120
reset to the line of icell_core.
122
BOOL fixed_line; /* if we have a 'core' line of cells */
123
enum ended_state ended; /* if we saw </tr> etc */
124
int content; /* Whether contains end-of-cell etc */
125
int offset; /* >=0 after line break in a multiline cell */
126
int allocated; /* number of table cells allocated */
127
STable_cellinfo * cells;
128
int alignment; /* global align attribute for this row */
131
struct _STable_info {
132
#ifdef EXP_NESTED_TABLES
133
struct _STable_info *enclosing; /* The table which contain us */
134
struct _TextAnchor *enclosing_last_anchor_before_stbl;
136
int startline; /* lineno where table starts (zero-based) */
137
int nrows; /* number of rows */
138
int ncols; /* number of rows */
139
int maxlen; /* sum of max. cell lengths of any row */
140
int maxpos; /* max. of max. cell pos's of any row */
141
int allocated_rows; /* number of rows allocated */
142
int allocated_sumcols; /* number of sumcols allocated */
143
int ncolinfo; /* number of COL info collected */
144
STable_cellinfo * sumcols; /* for summary (max len/pos) col info */
145
STable_rowinfo * rows;
146
STable_rowinfo rowspans2eog;
147
short alignment; /* global align attribute for this table */
148
short rowgroup_align; /* align default for current group of rows */
149
short pending_colgroup_align;
150
int pending_colgroup_next;
155
** Functions and structures in this source file keep track of positions.
156
** They don't know about the character data in those lines, or about
157
** the HText and HTLine structures. GridText.c doesn't know about our
158
** structures. It should stay that way.
160
** The basic idea: we let the code in HTML.c/GridText.c produce and format
161
** output "as usual", i.e. as without Simple Table support. We keep track
162
** of the positions in the generated output where cells and rows start (or
163
** end). If all goes well, that preliminary output (stored in HText/HTLine
164
** structures) can be fixed up when the TABLE end tag is processed, by just
165
** inserting spaces in the right places (and possibly changing alignment).
166
** If all goes not well, we already have a safe fallback.
168
** Note that positions passed to and from these functions should be
169
** in terms of screen positions, not just byte counts in a HTLine.data
170
** (cf. line->data vs. HText_TrueLineSize).
172
** Memory is allocated dynamically, so we can have tables of arbitrary
173
** length. On allocation error we just return and error indication
174
** instead of outofmem(), so caller can give up table tracking and maybe
178
** - ALIGN={left,right,center,justify} applied to individual table cells
179
** ("justify" is treated as "left")
180
** - Inheritance of horizontal alignment according to HTML 4.0
181
** - COLSPAN >1 (may work incorrectly for some tables?)
182
** - ROWSPAN >1 (reserving cells in following rows)
183
** - Line breaks at start of first cell or at end of last cell are treated
184
** as if they were not part of the cell and row. This allows us to
185
** cooperate with one way in which tables have been made friendly to
186
** browsers without any table support.
187
** Missing, but can be added:
188
** - Support for COLGROUP/COL
189
** - Tables wider than display. The limitation is not here but in GridText.c
190
** etc. If horizontal scrolling were implemented there, the mechanisms
191
** here coudl deal with wide tables (just change MAX_STBL_POS code).
192
** Missing, unlikely to add:
193
** - Support for non-LTR directionality. A general problem, support is
194
** lacking throughout the lynx code.
195
** - Support for most other table-related attributes. Most of them are
196
** for decorative purposes.
197
** Impossible or very unlikely (because it doesn't fit the model):
198
** - Any cell contents of more than one line, line breaks within cells.
199
** Anything that requires handling cell contents as paragraphs (block
200
** elements), like reflowing. Vertical alignment.
202
PRIVATE int Stbl_finishCellInRow PARAMS((
208
PRIVATE int Stbl_finishRowInTable PARAMS((
211
PRIVATE CONST char * cellstate_s ARGS1(
214
CONST char *result = "?";
217
case CS_invalid: result = "CS_invalid"; break;
218
case CS__new: result = "CS__new"; break;
219
case CS__0new: result = "CS__0new"; break;
220
case CS__0eb: result = "CS__0eb"; break;
221
case CS__eb: result = "CS__eb"; break;
222
case CS__0cb: result = "CS__0cb"; break;
223
case CS__cb: result = "CS__cb"; break;
224
case CS__0ef: result = "CS__0ef"; break;
225
case CS__ef: result = "CS__ef"; break;
226
case CS__0cf: result = "CS__0cf"; break;
227
case CS__cf: result = "CS__cf"; break;
228
case CS__ebc: result = "CS__ebc"; break;
229
case CS__cbc: result = "CS__cbc"; break;
234
PUBLIC struct _STable_info * Stbl_startTABLE ARGS1(
237
STable_info *me = typecalloc(STable_info);
240
(tfp, "TRST:Stbl_startTABLE(align=%d)\n", (int)alignment));
242
me->alignment = alignment;
243
me->rowgroup_align = HT_ALIGN_NONE;
244
me->pending_colgroup_align = HT_ALIGN_NONE;
246
me->s.icell_core = -1;
247
#ifdef EXP_NESTED_TABLES
255
PRIVATE void free_rowinfo ARGS1(
256
STable_rowinfo *, me)
258
if (me && me->allocated) {
263
PUBLIC void Stbl_free ARGS1(
267
(tfp, "TRST:Stbl_free()\n"));
268
if (me && me->allocated_rows && me->rows) {
270
for (i = 0; i < me->allocated_rows; i++)
271
free_rowinfo(me->rows + i);
274
free_rowinfo(&me->rowspans2eog);
281
* Returns -1 on error, otherwise index of just-added table cell.
283
PRIVATE int Stbl_addCellToRow ARGS9(
284
STable_rowinfo *, me,
285
STable_cellinfo *, colinfo,
294
STable_cellinfo *cells;
296
int last_colspan = me->ncells ?
297
me->cells[me->ncells - 1].colspan : 1;
298
cellstate_t newstate;
302
(tfp, "TRST:Stbl_addCellToRow, line=%d, pos=%d, colspan=%d\n",
303
lineno, *ppos, colspan));
305
(tfp, " ncells=%d, stateLine=%d, pending_len=%d, pstate=%s, state=%s\n",
306
me->ncells, s->lineno, s->pending_len,
307
cellstate_s(s->prev_state), cellstate_s(s->state)));
309
s->prev_state = CS_invalid;
310
else if (s->prev_state == CS_invalid ||
311
(s->state != CS__0new &&
312
s->state != CS__ef && s->state != CS__0ef))
313
s->prev_state = s->state;
315
if (me->ncells == 0 || *ppos == 0)
320
if (me->ncells > 0 && s->pending_len > 0) {
321
if (s->prev_state != CS__cbc)
322
me->cells[me->ncells - 1].len = s->pending_len;
327
if (lineno != s->lineno) {
328
if (!me->fixed_line) {
329
if (me->ncells == 0 || *ppos == 0) {
330
switch (s->prev_state) {
338
for (i = me->ncells + last_colspan - 2;
339
i >= me->ncells - 1; i--) {
340
me->cells[i].pos = *ppos;
341
me->cells[i].cLine = lineno;
352
*ppos = me->cells[me->ncells - 1].pos +
353
me->cells[me->ncells - 1].len;
355
} else { /* last cell multiline, ncells != 0, pos != 0 */
356
switch (s->prev_state) {
360
/* Do not fail, but do not set fixed_line either */
368
if (*ppos > me->cells[0].pos)
370
me->fixed_line = YES; /* type=a def of fixed_line i */
376
me->fixed_line = YES; /* type=e def of fixed_line ii */
383
if (me->fixed_line && lineno != me->Line) {
384
switch (s->prev_state) {
390
*ppos = me->cells[me->ncells - 1].pos /* == 0 */ +
391
me->cells[me->ncells - 1].len;
395
if (*ppos == 0 || *ppos <= me->cells[0].pos)
396
*ppos = me->cells[me->ncells - 1].pos /* == 0 */ +
397
me->cells[me->ncells - 1].len;
407
*ppos = me->cells[me->ncells - 1].pos; break;
415
} else { /* lineno == s->lineno: */
416
switch (s->prev_state) {
419
case CS__0eb: /* cannot happen */
420
case CS__0cb: /* cannot happen */
422
case CS__0cf: /* ##302?? set icell_core? or only in finish? */
424
case CS__eb: /* cannot happen */
425
case CS__cb: /* cannot happen */
428
case CS__ebc: /* should have done smth in finish */
429
case CS__cbc: /* should have done smth in finish */
433
if (me->fixed_line && me->Line != lineno) {
436
me->fixed_line = YES;
444
if (me->ncells > 0 && me->cells[me->ncells - 1].colspan > 1) {
445
me->ncells += me->cells[me->ncells-1].colspan - 1;
447
while (me->ncells < me->allocated &&
448
me->cells[me->ncells].alignment == RESERVEDCELL) {
453
while (me->ncells + colspan + 1 > me->allocated + growby)
454
growby += CELLS_GROWBY;
456
if (me->allocated == 0 && !me->cells) {
457
cells = typecallocn(STable_cellinfo, growby);
459
cells = realloc(me->cells,
460
(me->allocated + growby)
461
* sizeof(STable_cellinfo));
462
for (i = 0; cells && i < growby; i++) {
463
cells[me->allocated + i].alignment = HT_ALIGN_NONE;
467
me->allocated += growby;
475
me->cells[me->ncells].cLine = lineno;
476
me->cells[me->ncells].pos = *ppos;
477
me->cells[me->ncells].len = -1;
478
me->cells[me->ncells].colspan = colspan;
480
if (alignment != HT_ALIGN_NONE)
481
me->cells[me->ncells].alignment = alignment;
483
if (ncolinfo >= me->ncells + 1)
484
me->cells[me->ncells].alignment = colinfo[me->ncells].alignment;
486
me->cells[me->ncells].alignment = me->alignment;
487
if (me->cells[me->ncells].alignment==HT_ALIGN_NONE)
488
me->cells[me->ncells].alignment = me->alignment;
489
if (me->cells[me->ncells].alignment==HT_ALIGN_NONE)
490
me->cells[me->ncells].alignment = isheader ? HT_CENTER : HT_LEFT;
492
for (i = me->ncells + 1; i < me->ncells + colspan; i++) {
493
me->cells[i].cLine = lineno;
494
me->cells[i].pos = *ppos;
495
me->cells[i].len = -1;
496
me->cells[i].colspan = 0;
497
me->cells[i].alignment = HT_LEFT;
499
me->cells[me->ncells + colspan].pos = -1; /* not yet used */
502
ret = me->ncells - 1;
505
(tfp, " => prev_state=%s, state=%s, ret=%d\n",
506
cellstate_s(s->prev_state), cellstate_s(s->state), ret));
511
goto trace_and_return;
514
/* returns -1 on error, 0 otherwise */
515
/* assumes cells have already been allocated (but may need more) */
516
PRIVATE int Stbl_reserveCellsInRow ARGS3(
517
STable_rowinfo *, me,
521
STable_cellinfo *cells;
523
int growby = icell + colspan - me->allocated;
526
(tfp, "TRST:Stbl_reserveCellsInRow(icell=%d, colspan=%d\n",
529
cells = realloc(me->cells,
530
(me->allocated + growby)
531
* sizeof(STable_cellinfo));
533
for (i = 0; i < growby; i++) {
534
cells[me->allocated + i].alignment = HT_ALIGN_NONE;
536
me->allocated += growby;
542
for (i = icell; i < icell + colspan; i++) {
543
me->cells[i].cLine = -1;
544
me->cells[i].pos = -1;
545
me->cells[i].len = -1;
546
me->cells[i].colspan = 0;
547
me->cells[i].alignment = RESERVEDCELL;
549
me->cells[icell].colspan = colspan;
553
/* Returns -1 on failure. */
554
PRIVATE int Stbl_finishCellInRow ARGS5(
555
STable_rowinfo *, me,
561
STable_cellinfo *lastcell;
562
cellstate_t newstate = CS_invalid;
563
int multiline = NO, empty;
567
(tfp, "TRST:Stbl_finishCellInRow line=%d pos=%d end_td=%d ncells=%d pnd_len=%d\n",
568
lineno, pos, (int)end_td, me->ncells, s->pending_len));
572
lastcell = me->cells + (me->ncells - 1);
573
multiline = (lineno != lastcell->cLine || lineno != s->lineno);
574
empty = multiline ? (pos == 0) : (pos <= s->x_td);
577
(tfp, " [lines: lastCell=%d state=%d multi=%d] empty=%d (prev)state=(%s) %s\n",
578
lastcell->cLine, s->lineno, multiline, empty,
579
cellstate_s(s->prev_state), cellstate_s(s->state)));
582
if ((end_td & TRST_ENDCELL_MASK) == TRST_ENDCELL_LINEBREAK) {
585
newstate = empty ? CS_invalid : CS__cbc;
588
newstate = empty ? CS__0eb : CS__0cb;
591
newstate = empty ? CS__0eb : CS__ebc;
593
if (me->fixed_line) {
595
ret = (lastcell->len <= 0 ? 0 : lastcell->len);
597
ret = (lastcell->len <= 0 ? 0 : -1);
600
ret = (lastcell->len <= 0 ? 0 : lastcell->len);
602
ret = (lastcell->len <= 0 ? 0 : 0);
604
goto trace_and_return;
606
if (!me->fixed_line) {
608
if (s->icell_core == -1)
612
if (s->pending_len && empty) { /* First line non-empty */
613
if ((me->fixed_line && me->Line == lastcell->cLine) ||
614
s->icell_core == me->ncells - 1)
615
lastcell->len = s->pending_len;
617
} /* @@@ for empty do smth. about ->Line / ->icell_core !! */
618
newstate = empty ? CS__0cb : CS__cbc; /* ##474_needs_len!=-1? */
624
newstate = empty ? CS__eb : CS__cb;
626
case CS__eb: /* ##484_set_pending_ret_0_if_empty? */
627
newstate = empty ? CS__eb : CS__ebc;
629
if (me->fixed_line) {
631
ret = (lastcell->len <= 0 ? 0 : lastcell->len);
633
ret = (lastcell->len <= 0 ? 0 : -1);
636
ret = (lastcell->len <= 0 ? 0 : lastcell->len);
638
ret = (lastcell->len <= 0 ? 0 : -1);
640
goto trace_and_return;
642
if (s->pending_len && empty) { /* ##496: */
643
lastcell->len = s->pending_len;
645
} /* @@@ for empty do smth. about ->Line / ->icell_core !! */
648
if (!me->fixed_line) {
649
me->fixed_line = YES; /* type=b def of fixed_line i */
650
me->Line = lastcell->cLine; /* should've happened in break */
652
if (me->Line != lastcell->cLine)
653
goto trace_and_return;
656
if (!me->fixed_line) {
657
me->fixed_line = YES; /* type=b def of fixed_line ii */
658
me->Line = lastcell->cLine; /* should've happened in break */
661
goto trace_and_return;
663
newstate = empty ? CS__cb : CS__cbc;
667
goto trace_and_return;
669
ret = lastcell->len; /* ##523_change_state? */
670
goto trace_and_return;
672
if (!me->fixed_line) {
674
if (s->icell_core == -1) /* ##528??: */
676
/* lastcell->Line = lineno; */
677
} else { /* !empty */
678
if (s->icell_core == -1)
683
newstate = empty ? CS_invalid : CS__cbc;
688
} else { /* multiline cell, processing </TD>: */
692
/* ##540_return_-1_for_invalid_if_len!: */
693
if (!empty && lastcell->len > 0) {
697
goto trace_and_return;
699
/* ##541_set_len_0_Line_-1_sometimes: */
701
lastcell->cLine = -1;
702
/* fall thru ##546 really fall thru??: */
703
newstate = empty ? CS_invalid : CS__cbc; break;
705
newstate = empty ? CS__0ef : CS__0cf; break;
707
newstate = empty ? CS__0ef : CS__0cf; /* ebc?? */
709
if (me->fixed_line) {
711
ret = (lastcell->len <= 0 ? 0 : lastcell->len);
713
ret = (lastcell->len <= 0 ? 0 : -1);
716
ret = (lastcell->len <= 0 ? 0 : lastcell->len);
718
ret = (lastcell->len <= 0 ? 0 : 0);
720
goto trace_and_return;
722
if (s->pending_len) {
724
lastcell->len = s->pending_len;
729
if (!me->fixed_line) {
731
if (s->icell_core == -1)
732
/* first cell before <BR></TD> => the core cell */
733
s->icell_core = me->ncells - 1;
734
/* lastcell->cLine = lineno; */
735
} else { /* !empty */
736
if (s->icell_core == -1)
740
if (s->pending_len && empty) {
741
lastcell->len = s->pending_len;
743
} /* @@@ for empty do smth. about ->Line / ->icell_core !! */
744
newstate = empty ? CS__0cf : CS__cbc; break;
751
newstate = empty ? CS__ef : CS__cf; break;
753
newstate = empty ? CS__ef : CS__ef; /* ##579??? !!!!! */
755
if (me->fixed_line) {
757
ret = (lastcell->len <= 0 ? 0 : lastcell->len);
759
ret = (lastcell->len <= 0 ? 0 : -1);
762
ret = (lastcell->len <= 0 ? 0 : lastcell->len);
764
ret = (lastcell->len <= 0 ? 0 : -1);
766
goto trace_and_return;
768
if (s->pending_len && empty) {
769
lastcell->len = s->pending_len;
774
if (!me->fixed_line) {
775
me->fixed_line = YES; /* type=c def of fixed_line */
776
me->Line = lastcell->cLine; /* should've happened in break */
778
if (me->Line != lastcell->cLine)
779
goto trace_and_return;
782
goto trace_and_return;
784
newstate = empty ? CS__cf : CS__cbc; break;
785
case CS__ef: /* ignored error */
786
case CS__cf: /* ignored error */
788
case CS__ebc: /* ##540_handle_ebc: */
790
if (!me->fixed_line) {
792
if (s->icell_core == -1)
793
lastcell->cLine = -1;
797
newstate = empty ? CS_invalid : CS__cbc; break;
798
case CS__cbc: /* ##586 */
799
lastcell->len = 0; /* ##613 */
801
if (me->fixed_line && me->Line == lastcell->cLine)
802
goto trace_and_return;
803
if (!me->fixed_line) {
805
if (s->icell_core == -1)
809
s->pending_len = 0; /* ##629 v */
810
newstate = empty ? CS_invalid : CS__cbc; break;
813
} else { /* (!multiline) */
814
if ((end_td & TRST_ENDCELL_MASK) == TRST_ENDCELL_LINEBREAK) {
818
s->pending_len = empty ? 0 : pos - lastcell->pos;
819
newstate = empty ? CS__0eb : CS__0cb;
821
ret = 0; /* or 0 for xlen to s->pending_len?? */
822
goto trace_and_return;
823
case CS__0eb: /* cannot happen */
826
case CS__0cb: /* cannot happen */
834
if (!empty && s->prev_state == CS__cbc) /* ##609: */
835
goto trace_and_return;
837
if (!me->fixed_line) {
838
me->fixed_line = YES; /* type=d def of fixed_line */
841
if (me->Line != lineno)
842
goto trace_and_return;
845
newstate = empty ? CS__eb : CS__cb;
847
if (!me->fixed_line) {
848
s->pending_len = empty ? 0 : pos - lastcell->pos;
850
goto trace_and_return;
853
lastcell->len = empty ? 0 : pos - lastcell->pos;
855
goto trace_and_return;
857
case CS__eb: /* cannot happen */
858
newstate = empty ? CS__eb : CS__ebc; break;
859
case CS__cb: /* cannot happen */
860
newstate = empty ? CS__cb : CS__cbc; break;
863
goto trace_and_return;
866
goto trace_and_return;
867
case CS__cbc: /* ??? */
872
} else { /* !multiline, processing </TD>: */
875
case CS_invalid: /* ##691_no_lastcell_len_for_invalid: */
876
if (!(me->fixed_line && me->Line == lastcell->cLine))
880
newstate = empty ? CS__0ef : CS__0cf; break; /* ##630 */
882
newstate = empty ? CS__0ef : CS__0ef; break; /* ??? */
884
newstate = empty ? CS__0cf : CS__cbc; break; /* ??? */
886
newstate = CS__0ef; break; /* ??? */
891
if (!empty && s->prev_state == CS__cbc)
892
goto trace_and_return;
893
if (!empty) { /* ##642_set_fixed!: */
894
if (!me->fixed_line) {
895
me->fixed_line = YES; /* type=e def of fixed_line */
898
if (me->Line != lineno)
899
goto trace_and_return;
902
if (lastcell->len < 0)
903
lastcell->len = empty ? 0 : pos - lastcell->pos;
904
newstate = empty ? CS__ef : CS__cf;
906
ret = ((me->fixed_line && lineno != me->Line)
907
? -1 : lastcell->len);
908
goto trace_and_return;
910
newstate = empty ? CS__ef : CS__cf; break; /* ??? */
912
newstate = empty ? CS__cf : CS__cf; break; /* ??? */
913
case CS__ef: /* ignored error */
914
case CS__cf: /* ignored error */
918
lastcell->len = pos - lastcell->pos;
919
} /* if (!end_td) ... else */
920
} /* if (multiline) ... else */
924
#ifdef EXP_NESTED_TABLES
926
if (ret == -1 && pos == 0)
927
ret = 0; /* XXXX Hack to allow trailing <P> in multiline cells. */
931
/* lastcell->len = pos - lastcell->pos; */
934
(tfp, " => prev_state=%s, state=%s, return=%d\n",
935
cellstate_s(s->prev_state), cellstate_s(s->state), ret));
940
* Reserve cells, each of given colspan, in (rowspan-1) rows after
941
* the current row of rowspan>1. If rowspan==0, use special 'row'
942
* rowspans2eog to keep track of rowspans that are to remain in effect
943
* until the end of the row group (until next THEAD/TFOOT/TBODY) or table.
945
PRIVATE int Stbl_reserveCellsInTable ARGS4(
951
STable_rowinfo *rows, *row;
956
return -1; /* must already have at least one row */
959
(tfp, "TRST:Stbl_reserveCellsInTable(icell=%d, colspan=%d, rowspan=%d)\n",
960
icell, colspan, rowspan));
962
if (!me->rowspans2eog.cells) {
963
me->rowspans2eog.cells = typecallocn(STable_cellinfo, icell + colspan);
964
if (!me->rowspans2eog.cells)
965
return 0; /* fail silently */
967
me->rowspans2eog.allocated = icell + colspan;
969
Stbl_reserveCellsInRow(&me->rowspans2eog, icell, colspan);
972
growby = me->nrows + rowspan - 1 - me->allocated_rows;
974
rows = realloc(me->rows,
975
(me->allocated_rows + growby)
976
* sizeof(STable_rowinfo));
978
return 0; /* ignore silently, no free memory, may be recoverable */
979
for (i = 0; i < growby; i++) {
980
row = rows + me->allocated_rows + i;
984
if (!me->rowspans2eog.allocated) {
987
row->cells = typecallocn(STable_cellinfo,
988
me->rowspans2eog.allocated);
990
row->allocated = me->rowspans2eog.allocated;
991
memcpy(row->cells, me->rowspans2eog.cells,
992
row->allocated * sizeof(STable_cellinfo));
996
row->fixed_line = NO;
997
row->alignment = HT_ALIGN_NONE;
999
me->allocated_rows += growby;
1003
i < (rowspan == 0 ? me->allocated_rows : me->nrows + rowspan - 1);
1005
if (!me->rows[i].allocated) {
1006
me->rows[i].cells = typecallocn(STable_cellinfo, icell + colspan);
1007
if (!me->rows[i].cells)
1008
return 0; /* fail silently */
1010
me->rows[i].allocated = icell + colspan;
1012
Stbl_reserveCellsInRow(me->rows + i, icell, colspan);
1017
/* Remove reserved cells in trailing rows that were added for rowspan,
1018
* to be used when a THEAD/TFOOT/TBODY ends. */
1019
PRIVATE void Stbl_cancelRowSpans ARGS1(
1024
CTRACE2(TRACE_TRST, (tfp, "TRST:Stbl_cancelRowSpans()"));
1025
for (i = me->nrows; i < me->allocated_rows; i++) {
1026
if (!me->rows[i].ncells) { /* should always be the case */
1027
FREE(me->rows[i].cells);
1028
me->rows[i].allocated = 0;
1031
free_rowinfo(&me->rowspans2eog);
1032
me->rowspans2eog.allocated = 0;
1036
* Returns -1 on error, otherwise index of just-added table row.
1038
PUBLIC int Stbl_addRowToTable ARGS3(
1043
STable_rowinfo *rows, *row;
1044
STable_states * s = &me->s;
1047
(tfp, "TRST:Stbl_addRowToTable(alignment=%d, lineno=%d)\n",
1048
alignment, lineno));
1049
if (me->nrows > 0 && me->rows[me->nrows-1].ncells > 0) {
1050
if (s->pending_len > 0)
1051
me->rows[me->nrows-1].cells[me->rows[me->nrows-1].ncells - 1].len = s->pending_len;
1054
Stbl_finishRowInTable(me);
1055
if (me->nrows > 0 && me->rows[me->nrows-1].Line == lineno)
1056
me->rows[me->nrows-1].Line = -1;
1063
while (me->nrows + 2 > me->allocated_rows + growby)
1064
growby += ROWS_GROWBY;
1066
if (me->allocated_rows == 0 && !me->rows) {
1067
rows = typecallocn(STable_rowinfo, growby);
1069
rows = realloc(me->rows,
1070
(me->allocated_rows + growby)
1071
* sizeof(STable_rowinfo));
1072
for (i = 0; rows && i < growby; i++) {
1073
row = rows + me->allocated_rows + i;
1074
if (!me->rowspans2eog.allocated) {
1078
row->cells = typecallocn(STable_cellinfo,
1079
me->rowspans2eog.allocated);
1081
row->allocated = me->rowspans2eog.allocated;
1082
memcpy(row->cells, me->rowspans2eog.cells,
1083
row->allocated * sizeof(STable_cellinfo));
1090
row->fixed_line = NO;
1091
row->alignment = HT_ALIGN_NONE;
1097
me->allocated_rows += growby;
1105
me->rows[me->nrows].Line = lineno;
1107
me->startline = lineno;
1108
if (alignment != HT_ALIGN_NONE)
1109
me->rows[me->nrows].alignment = alignment;
1111
me->rows[me->nrows].alignment =
1112
(me->rowgroup_align==HT_ALIGN_NONE) ?
1113
me->alignment : me->rowgroup_align;
1115
if (me->pending_colgroup_next > me->ncolinfo) {
1116
me->ncolinfo = me->pending_colgroup_next;
1117
me->pending_colgroup_next = 0;
1119
me->rows[me->nrows].Line = -1; /* not yet used */
1120
me->rows[me->nrows].ended = ROW_not_ended; /* No </tr> yet */
1121
return (me->nrows - 1);
1125
* Returns -1 on error, otherwise current number of rows.
1127
PRIVATE int Stbl_finishRowInTable ARGS1(
1130
STable_rowinfo *lastrow;
1131
STable_states * s = &me->s;
1134
CTRACE2(TRACE_TRST, (tfp, "TRST:Stbl_finishRowInTable()\n"));
1135
if (!me->rows || !me->nrows)
1136
return -1; /* no row started! */
1137
lastrow = me->rows + (me->nrows - 1);
1138
ncells = lastrow->ncells;
1139
lastrow->ended = ROW_ended_by_endtr;
1140
if (lastrow->ncells > 0) {
1141
if (s->pending_len > 0)
1142
lastrow->cells[lastrow->ncells - 1].len = s->pending_len;
1145
s->prev_state = s->state = CS_invalid;
1148
if (s->icell_core >= 0 && !lastrow->fixed_line &&
1149
lastrow->cells[s->icell_core].cLine >= 0)
1150
lastrow->Line = lastrow->cells[s->icell_core].cLine;
1155
PRIVATE void update_sumcols0 ARGS7(
1156
STable_cellinfo *, sumcols,
1157
STable_rowinfo *, lastrow,
1162
int, allocated_sumcols)
1167
int prevsumpos = sumcols[icell + ispan].pos;
1170
if (lastrow->cells[icell].pos + len > sumpos)
1171
sumpos = lastrow->cells[icell].pos + len;
1172
if (sumcols[icell+ispan-1].pos + sumcols[icell+ispan-1].len > sumpos)
1173
sumpos = sumcols[icell+ispan-1].pos + sumcols[icell+ispan-1].len;
1175
advance = sumpos - prevsumpos;
1177
for (i = icell + ispan; i < allocated_sumcols; i++) {
1178
if (ispan > 0 && sumcols[i].colspan < -1) {
1179
if (i + sumcols[i].colspan < icell + ispan) {
1180
advance = sumpos - sumcols[i].pos;
1182
advance = HTMAX(advance,
1183
sumcols[i-1].pos + sumcols[i-1].len
1184
- (sumcols[i].pos));
1189
if (sumcols[i].pos >= 0)
1190
sumcols[i].pos += advance;
1192
sumcols[i].pos = sumpos;
1200
PRIVATE int get_remaining_colspan ARGS5(
1201
STable_rowinfo *, me,
1202
STable_cellinfo *, colinfo,
1208
int last_colspan = me->ncells ?
1209
me->cells[me->ncells - 1].colspan : 1;
1211
if (ncolinfo == 0 || me->ncells + last_colspan > ncolinfo) {
1212
colspan = HTMAX(TRST_MAXCOLSPAN,
1213
ncols_sofar - (me->ncells + last_colspan - 1));
1215
for (i = me->ncells + last_colspan - 1; i < ncolinfo - 1; i++)
1216
if (colinfo[i].cLine == EOCOLG)
1218
colspan = i - (me->ncells + last_colspan - 2);
1223
#ifdef EXP_NESTED_TABLES
1224
/* Returns -1 on failure, 1 if faking was performed, 0 if not needed. */
1225
PRIVATE int Stbl_fakeFinishCellInTable ARGS4(
1227
STable_rowinfo *, lastrow,
1229
int, finishing) /* Processing finish or start */
1231
STable_states * s = &me->s;
1234
switch (s->state) { /* We care only about trailing <BR> */
1244
/* <BR></TD> may produce these (XXXX instead of CS__cbf?). But if
1245
finishing==0, the caller already checked that we are on a
1249
break; /* Either can't happen, or may be ignored */
1258
/* The previous action we did was putting a linebreak. Now we
1259
want to put another one. Fake necessary
1260
</TD></TR><TR><TD></TD><TD> (and possibly </TD>) instead. */
1261
int ncells = lastrow->ncells;
1263
int al = lastrow->alignment;
1264
int cs = lastrow->cells[lastrow->ncells - 1].colspan;
1265
int rs = 1; /* XXXX How to find rowspan? */
1266
int ih = 0; /* XXXX How to find is_header? */
1267
int end_td = (TRST_ENDCELL_ENDTD | TRST_FAKING_CELLS);
1268
int need_reserved = 0;
1269
int prev_reserved_last = -1;
1270
STable_rowinfo *prev_row;
1271
int prev_row_n2 = lastrow - me->rows;
1274
(tfp, "TRST:Stbl_fakeFinishCellInTable(lineno=%d, finishing=%d) START FAKING\n",
1275
lineno, finishing));
1277
/* Although here we use pos=0, this may commit the previous
1278
cell which had <BR> as a last element. This may overflow
1279
the screen width, so the additional checks performed in
1280
Stbl_finishCellInTable (comparing to Stbl_finishCellInRow)
1283
/* Fake </TD> at BOL */
1284
if (Stbl_finishCellInTable(me, end_td, lineno, 0, 0) < 0) {
1289
/* Fake </TR> at BOL */
1290
/* Stbl_finishCellInTable(lineno, 0, 0);*/ /* Needed? */
1292
/* Fake <TR> at BOL */
1293
if (Stbl_addRowToTable(me, al, lineno) < 0) {
1296
lastrow = me->rows + (me->nrows - 1);
1297
lastrow->content = IS_CONTINUATION_OF_CELL;
1298
for (i = 0; i < lastrow->allocated; i++) {
1299
if (lastrow->cells[i].alignment == RESERVEDCELL) {
1305
prev_row = me->rows + prev_row_n2;
1306
for (i = ncells; i < prev_row->allocated; i++) {
1307
if (prev_row->cells[i].alignment == RESERVEDCELL)
1308
prev_reserved_last = i;
1310
if (need_reserved || prev_reserved_last >= 0) {
1311
/* Oups, we are going to stomp over a line which somebody
1312
cares about already, or the previous line had reserved
1313
cells which were not skipped over.
1315
Remember that STable_rowinfo is about logical (TR)
1316
table lines, not displayed lines. We need to duplicate
1317
the reservation structure when we fake new logical lines. */
1318
int prev_row_n = prev_row - me->rows;
1319
STable_rowinfo *rows = realloc(me->rows,
1320
(me->allocated_rows + 1)
1321
* sizeof(STable_rowinfo));
1322
int need_cells = prev_reserved_last + 1;
1326
return -1; /* ignore silently, no free memory, may be recoverable */
1329
(tfp, "TRST:Stbl_fakeFinishCellInTable REALLOC ROWSPAN\n"));
1331
lastrow = me->rows + (me->nrows - 1);
1332
prev_row = me->rows + prev_row_n;
1333
me->allocated_rows++;
1335
/* Insert a duplicate row after lastrow */
1336
for (n = me->allocated_rows - me->nrows - 1; n >= 0; --n)
1337
lastrow[n + 1] = lastrow[n];
1339
/* Ignore cells, they belong to the next row now */
1340
lastrow->allocated = 0;
1343
lastrow->cells = typecallocn(STable_cellinfo, need_cells);
1344
/* ignore silently, no free memory, may be recoverable */
1345
if (!lastrow->cells) {
1348
lastrow->allocated = need_cells;
1349
memcpy(lastrow->cells, prev_row->cells,
1350
lastrow->allocated * sizeof(STable_cellinfo));
1353
while (++i < ncells) {
1354
/* Stbl_addCellToTable grants RESERVEDCELL, but we do not
1355
want this action for fake cells.
1356
XXX Maybe always fake RESERVEDCELL instead of explicitly
1357
creating/destroying cells? */
1358
if (lastrow->cells[i].alignment == RESERVEDCELL)
1359
lastrow->cells[i].alignment = HT_LEFT;
1364
/* Fake <TD></TD>...<TD> (and maybe a </TD>) at BOL. */
1366
(tfp, "TRST:Stbl_fakeFinishCellInTable FAKE %d elts%s\n",
1367
ncells, (finishing ? ", last unfinished" : "")));
1369
while (++i <= ncells) {
1370
/* XXXX A lot of args may be wrong... */
1371
if (Stbl_addCellToTable(me, (i==ncells ? cs : 1), rs, al,
1372
ih, lineno, 0, 0) < 0) {
1375
lastrow->content &= ~HAS_BEG_OF_CELL; /* BEG_OF_CELL was fake */
1376
/* We cannot run out of width here, so it is safe to not
1377
call Stbl_finishCellInTable(), but Stbl_finishCellInRow. */
1378
if (!finishing || (i != ncells)) {
1379
if (Stbl_finishCellInRow(lastrow, s, end_td, lineno, 0) < 0) {
1385
(tfp, "TRST:Stbl_fakeFinishCellInTable(lineno=%d) FINISH FAKING\n",
1394
* Returns -1 on error, otherwise 0.
1396
PUBLIC int Stbl_addCellToTable ARGS8(
1403
int, offset_not_used_yet GCC_UNUSED,
1406
STable_states * s = &me->s;
1407
STable_rowinfo *lastrow;
1408
STable_cellinfo *sumcols, *sumcol;
1409
int i, icell, ncells, sumpos;
1412
(tfp, "TRST:Stbl_addCellToTable(lineno=%d, pos=%d, isheader=%d, cs=%d, rs=%d, al=%d)\n",
1413
lineno, pos, (int)isheader, colspan, rowspan, alignment));
1414
if (!me->rows || !me->nrows)
1415
return -1; /* no row started! */
1416
/* ##850_fail_if_fail?? */
1417
if (me->rows[me->nrows - 1].ended != ROW_not_ended)
1418
Stbl_addRowToTable(me, alignment, lineno);
1419
Stbl_finishCellInTable(me, TRST_ENDCELL_ENDTD, lineno, 0, pos);
1420
lastrow = me->rows + (me->nrows - 1);
1422
#ifdef EXP_NESTED_TABLES
1423
if (nested_tables) {
1424
/* If the last cell was finished by <BR></TD>, we need to fake an
1425
appropriate amount of cells */
1426
if (!NO_AGGRESSIVE_NEWROW && pos == 0 && lastrow->ncells > 0
1427
&& lastrow->cells[lastrow->ncells-1].cLine != lineno) {
1428
int rc = Stbl_fakeFinishCellInTable(me, lastrow, lineno, 0);
1433
lastrow = me->rows + (me->nrows - 1);
1438
colspan = get_remaining_colspan(lastrow, me->sumcols, me->ncolinfo,
1439
colspan, me->ncols);
1441
ncells = lastrow->ncells; /* remember what it was before adding cell. */
1442
icell = Stbl_addCellToRow(lastrow, me->sumcols, me->ncolinfo, s,
1443
colspan, alignment, isheader,
1447
if (me->nrows == 1 && me->startline < lastrow->Line)
1448
me->startline = lastrow->Line;
1451
Stbl_reserveCellsInTable(me, icell, colspan, rowspan);
1452
/* me->rows may now have been realloc'd, make lastrow valid pointer */
1453
lastrow = me->rows + (me->nrows - 1);
1455
lastrow->content |= HAS_BEG_OF_CELL;
1459
while (icell + colspan + 1 > me->allocated_sumcols + growby)
1460
growby += CELLS_GROWBY;
1462
if (me->allocated_sumcols == 0 && !me->sumcols) {
1463
sumcols = typecallocn(STable_cellinfo, growby);
1465
sumcols = realloc(me->sumcols,
1466
(me->allocated_sumcols + growby)
1467
* sizeof(STable_cellinfo));
1468
for (i = 0; sumcols && i < growby; i++) {
1469
sumcol = sumcols + me->allocated_sumcols + i;
1470
sumcol->pos = sumcols[me->allocated_sumcols-1].pos;
1472
sumcol->colspan = 0;
1474
sumcol->alignment = HT_ALIGN_NONE;
1478
me->allocated_sumcols += growby;
1479
me->sumcols = sumcols;
1485
if (icell + 1 > me->ncols) {
1486
me->ncols = icell + 1;
1488
if (colspan > 1 && colspan + me->sumcols[icell + colspan].colspan > 0)
1489
me->sumcols[icell + colspan].colspan = -colspan;
1492
sumpos += me->sumcols[ncells-1].pos - lastrow->cells[ncells-1].pos;
1493
update_sumcols0(me->sumcols, lastrow, sumpos,
1494
sumpos - (ncells > 0 ? me->sumcols[icell].pos : me->sumcols[icell].pos),
1495
icell, 0, me->allocated_sumcols);
1497
me->maxpos = me->sumcols[me->allocated_sumcols-1].pos;
1498
if (me->maxpos > /* @@@ max. line length we can accept */ MAX_STBL_POS)
1504
* Returns -1 on error, otherwise 0.
1506
PUBLIC int Stbl_finishCellInTable ARGS5(
1513
STable_states * s = &me->s;
1514
STable_rowinfo *lastrow;
1515
int len, xlen, icell;
1519
(tfp, "TRST:Stbl_finishCellInTable(lineno=%d, pos=%d, off=%d, end_td=%d)\n",
1520
lineno, pos, offset, (int)end_td));
1523
lastrow = me->rows + (me->nrows - 1);
1524
icell = lastrow->ncells - 1;
1527
if (s->x_td == -1) { /* Stray </TD> or just-in-case, as on </TR> */
1528
if ((end_td & TRST_ENDCELL_MASK) == TRST_ENDCELL_LINEBREAK)
1529
lastrow->ended = ROW_ended_by_splitline;
1533
#ifdef EXP_NESTED_TABLES
1534
if (nested_tables) {
1535
if (!NO_AGGRESSIVE_NEWROW && !(end_td & TRST_FAKING_CELLS)) {
1536
int rc = Stbl_fakeFinishCellInTable(me, lastrow, lineno, 1);
1541
lastrow = me->rows + (me->nrows - 1);
1542
icell = lastrow->ncells - 1;
1547
len = Stbl_finishCellInRow(lastrow, s, end_td, lineno, pos);
1550
xlen = (len > 0) ? len : s->pending_len; /* ##890 use xlen if fixed_line?: */
1551
if (lastrow->Line == lineno)
1553
if (lastrow->cells[icell].colspan > 1) {
1555
* @@@ This is all a too-complicated mess; do we need
1556
* sumcols len at all, or is pos enough??
1557
* Answer: sumcols len is at least used for center/right
1558
* alignment, and should probably continue to be used there;
1559
* all other uses are probably not necessary.
1561
int spanlen = 0, spanlend = 0;
1562
for (i = icell; i < icell + lastrow->cells[icell].colspan; i++) {
1563
if (me->sumcols[i].len > 0) {
1564
spanlen += me->sumcols[i].len;
1568
spanlend = HTMAX(spanlend,
1569
me->sumcols[i+1].pos - me->sumcols[icell].pos);
1573
if (spanlend > spanlen)
1575
/* @@@ could overcount? */
1577
me->maxlen += (len - spanlen);
1578
} else if (len > me->sumcols[icell].len) {
1579
if (me->sumcols[icell + 1].colspan >= -1)
1580
me->maxlen += (len - me->sumcols[icell].len);
1581
me->sumcols[icell].len = len;
1585
update_sumcols0(me->sumcols, lastrow, pos, len,
1586
icell, lastrow->cells[icell].colspan,
1587
me->allocated_sumcols);
1588
me->maxpos = me->sumcols[me->allocated_sumcols-1].pos;
1591
if ((end_td & TRST_ENDCELL_MASK) == TRST_ENDCELL_LINEBREAK) {
1592
lastrow->ended = ROW_ended_by_splitline;
1593
lastrow->content |= BELIEVE_OFFSET;
1594
lastrow->offset = offset;
1597
#ifdef EXP_NESTED_TABLES /* maxlen may already include contribution of a cell in this column */
1598
if (nested_tables) {
1599
if (me->maxlen > MAX_STBL_POS)
1604
if (me->maxlen + (xlen - len) > MAX_STBL_POS)
1607
if (me->maxpos > /* @@@ max. line length we can accept */ MAX_STBL_POS)
1610
if (lineno != lastrow->Line) {
1611
/* @@@ Do something here? Or is it taken care of in
1612
Stbl_finishCellInRow ? */
1619
* Returns -1 on error, otherwise 0.
1621
PUBLIC int Stbl_addColInfo ARGS4(
1627
STable_cellinfo *sumcols, *sumcol;
1631
(tfp, "TRST:Stbl_addColInfo(cs=%d, al=%d, isgroup=%d)\n",
1632
colspan, alignment, (int)isgroup));
1634
if (me->pending_colgroup_next > me->ncolinfo)
1635
me->ncolinfo = me->pending_colgroup_next;
1636
me->pending_colgroup_next = me->ncolinfo + colspan;
1637
if (me->ncolinfo > 0)
1638
me->sumcols[me->ncolinfo - 1].cLine = EOCOLG;
1639
me->pending_colgroup_align = alignment;
1641
for (i = me->pending_colgroup_next - 1;
1642
i >= me->ncolinfo + colspan; i--)
1643
me->sumcols[i].alignment = HT_ALIGN_NONE;
1644
me->pending_colgroup_next = me->ncolinfo + colspan;
1646
icolinfo = me->ncolinfo;
1648
me->ncolinfo += colspan;
1652
while (icolinfo + colspan + 1 > me->allocated_sumcols + growby)
1653
growby += CELLS_GROWBY;
1655
if (me->allocated_sumcols == 0) {
1656
sumcols = typecallocn(STable_cellinfo, growby);
1658
sumcols = realloc(me->sumcols,
1659
(me->allocated_sumcols + growby)
1660
* sizeof(STable_cellinfo));
1661
for (i = 0; sumcols && i < growby; i++) {
1662
sumcol = sumcols + me->allocated_sumcols + i;
1663
sumcol->pos = sumcols[me->allocated_sumcols-1].pos;
1665
sumcol->colspan = 0;
1670
me->allocated_sumcols += growby;
1671
me->sumcols = sumcols;
1678
if (alignment==HT_ALIGN_NONE)
1679
alignment = me->pending_colgroup_align;
1680
for (i = icolinfo; i < icolinfo + colspan; i++) {
1681
me->sumcols[i].alignment = alignment;
1687
* Returns -1 on error, otherwise 0.
1689
PUBLIC int Stbl_finishColGroup ARGS1(
1692
CTRACE2(TRACE_TRST, (tfp, "TRST:Stbl_finishColGroup()\n"));
1693
if (me->pending_colgroup_next >= me->ncolinfo) {
1694
me->ncolinfo = me->pending_colgroup_next;
1695
if (me->ncolinfo > 0)
1696
me->sumcols[me->ncolinfo - 1].cLine = EOCOLG;
1698
me->pending_colgroup_next = 0;
1699
me->pending_colgroup_align = HT_ALIGN_NONE;
1703
PUBLIC int Stbl_addRowGroup ARGS2(
1707
CTRACE2(TRACE_TRST, (tfp, "TRST:Stbl_addRowGroup()\n"));
1708
Stbl_cancelRowSpans(me);
1709
me->rowgroup_align = alignment;
1710
return 0; /* that's all! */
1713
PUBLIC int Stbl_finishTABLE ARGS1(
1716
STable_states * s = &me->s;
1720
CTRACE2(TRACE_TRST, (tfp, "TRST:Stbl_finishTABLE()\n"));
1721
if (!me || me->nrows <= 0 || me->ncols <= 0) {
1724
if (me->nrows > 0 && me->rows[me->nrows-1].ncells > 0) {
1725
if (s->pending_len > 0)
1726
me->rows[me->nrows-1].cells[me->rows[me->nrows-1].ncells - 1].len = s->pending_len;
1729
Stbl_finishRowInTable(me);
1730
/* take into account offsets on multi-line cells.
1731
XXX We cannot do it honestly, since two cells on the same row may
1732
participate in multi-line table entries, and we preserve only
1733
one offset per row. This implementation may ignore
1734
horizontal offsets for the last row of a multirow table entry. */
1735
for (i = 0; i < me->nrows - 1; i++) {
1736
int j = i + 1, leading = i, non_empty = 0;
1737
STable_rowinfo *nextrow = me->rows + j;
1738
int minoffset, have_offsets;
1739
int foundcell = -1, max_width;
1741
if ((nextrow->content & (IS_CONTINUATION_OF_CELL | HAS_BEG_OF_CELL | BELIEVE_OFFSET))
1742
!= (IS_CONTINUATION_OF_CELL | BELIEVE_OFFSET))
1743
continue; /* Not a continuation line */
1744
minoffset = nextrow[-1].offset; /* Line before first continuation */
1745
CTRACE2(TRACE_TRST, (tfp, "TRST:Stbl_finishTABLE, l=%d, offset=%d, ended=%d.\n",
1746
i, nextrow[-1].offset, nextrow[-1].ended));
1748
/* Find the common part of the requested offsets */
1749
while (j < me->nrows
1750
&& ((nextrow->content & (IS_CONTINUATION_OF_CELL | HAS_BEG_OF_CELL | BELIEVE_OFFSET))
1751
== (IS_CONTINUATION_OF_CELL | BELIEVE_OFFSET))) {
1752
if (minoffset > nextrow->offset)
1753
minoffset = nextrow->offset;
1754
CTRACE2(TRACE_TRST, (tfp, "TRST:Stbl_finishTABLE, l=%d, offset=%d, ended=%d.\n",
1755
j, nextrow->offset, nextrow[-1].ended));
1759
i = j - 1; /* Continue after this line */
1760
/* Cancel the common part of offsets */
1761
j = leading; /* Restart */
1762
nextrow = me->rows + j; /* Line before first continuation */
1764
nextrow->content |= OFFSET_IS_VALID_LAST_CELL;
1765
while (j <= i) { /* A continuation line */
1766
nextrow->offset -= minoffset;
1767
nextrow->content |= OFFSET_IS_VALID;
1768
if (nextrow->offset)
1774
continue; /* No offsets to deal with */
1776
/* Find the cell number */
1778
j = leading + 1; /* Restart */
1779
nextrow = me->rows + j; /* First continuation line */
1780
while (foundcell == -1 && j <= i) { /* A continuation line */
1783
while (foundcell == -1 && ++curcell < nextrow->ncells)
1784
if (nextrow->cells[curcell].len)
1785
foundcell = curcell, non_empty = j;
1789
if (foundcell == -1) /* Can it happen? */
1791
/* Find the max width */
1793
j = leading; /* Restart */
1794
nextrow = me->rows + j; /* Include the pre-continuation line */
1795
while (j <= i) { /* A continuation line */
1796
if (nextrow->ncells > foundcell) {
1797
int curwid = nextrow->cells[foundcell].len + nextrow->offset;
1799
if (curwid > max_width)
1805
/* Update the widths */
1806
j = non_empty; /* Restart from the first nonempty */
1807
nextrow = me->rows + j;
1808
/* Register the increase of the width */
1809
update_sumcols0(me->sumcols, me->rows + non_empty,
1810
0 /* width only */, max_width,
1811
foundcell, nextrow->cells[foundcell].colspan,
1812
me->allocated_sumcols);
1813
j = leading; /* Restart from pre-continuation */
1814
nextrow = me->rows + j;
1815
while (j <= i) { /* A continuation line */
1816
if (nextrow->ncells > foundcell)
1817
nextrow->cells[foundcell].len = max_width;
1821
} /* END of Offsets processing */
1823
for (i = 0; i < me->ncols; i++) {
1824
if (me->sumcols[i].pos < curpos) {
1825
me->sumcols[i].pos = curpos;
1827
curpos = me->sumcols[i].pos;
1829
if (me->sumcols[i].len > 0) {
1830
curpos += me->sumcols[i].len;
1833
/* need to recheck curpos: though it is checked each time a cell
1834
is added, sometimes the result is ignored, as in split_line(). */
1835
return (curpos > MAX_STBL_POS ? -1 : me->ncols);
1838
PUBLIC short Stbl_getAlignment ARGS1(
1841
return (short)(me ? me->alignment : HT_ALIGN_NONE);
1844
PRIVATE int get_fixup_positions ARGS4(
1845
STable_rowinfo *, me,
1848
STable_cellinfo *, sumcols)
1856
while (i < me->ncells) {
1859
next_i = i + HTMAX(1, me->cells[i].colspan);
1860
if (me->cells[i].cLine != me->Line) {
1861
if (me->cells[i].cLine > me->Line)
1866
oldpos[ip] = me->cells[i].pos;
1867
if ((me->content & OFFSET_IS_VALID)
1868
&& (i == me->ncells - 1
1869
|| !((me->content & OFFSET_IS_VALID_LAST_CELL))))
1870
offset = me->offset;
1873
newpos[ip] = sumcols[i].pos + offset;
1874
if ((me->cells[i].alignment == HT_CENTER ||
1875
me->cells[i].alignment == HT_RIGHT) &&
1876
me->cells[i].len > 0) {
1877
newlen = sumcols[next_i].pos - newpos[ip] - 1;
1878
newlen = HTMAX(newlen, sumcols[i].len);
1879
if (me->cells[i].len < newlen) {
1880
if (me->cells[i].alignment == HT_RIGHT) {
1881
newpos[ip] += newlen - me->cells[i].len;
1883
newpos[ip] += (newlen - me->cells[i].len) / 2;
1895
* Returns -1 if we have no row for this lineno, or for other error,
1896
* 0 or greater (number of oldpos/newpos pairs) if we have
1899
PUBLIC int Stbl_getFixupPositions ARGS4(
1905
STable_rowinfo * row;
1908
if (!me || !me->nrows)
1910
for (j = 0; j < me->nrows; j++) {
1912
if (row->Line == lineno) {
1913
ninserts = get_fixup_positions(row, oldpos, newpos,
1921
PUBLIC int Stbl_getStartLine ARGS1(
1927
return me->startline;
1930
#ifdef EXP_NESTED_TABLES
1932
PUBLIC int Stbl_getStartLineDeep ARGS1(
1937
while (me->enclosing)
1939
return me->startline;
1942
PUBLIC void Stbl_update_enclosing ARGS3(
1949
if (!me || !me->enclosing || !max_width)
1951
CTRACE2(TRACE_TRST, (tfp, "TRST:Stbl_update_enclosing, width=%d, lines=%d...%d.\n",
1952
max_width, me->startline, last_lineno));
1953
for (l = me->startline; l <= last_lineno; l++) {
1954
/* Fake <BR> in appropriate positions */
1955
if (Stbl_finishCellInTable(me->enclosing, TRST_ENDCELL_LINEBREAK, l, 0, max_width) < 0) {
1956
/* It is not handy to let the caller delete me->enclosing,
1957
and it does not buy us anything. Do it directly. */
1958
STable_info *stbl = me->enclosing;
1960
CTRACE2(TRACE_TRST, (tfp, "TRST:Stbl_update_enclosing: width too large, aborting enclosing\n"));
1963
STable_info *enclosing = stbl->enclosing;
1973
PUBLIC void Stbl_set_enclosing ARGS3(
1975
STable_info *, enclosing,
1976
struct _TextAnchor*,enclosing_last_anchor_before_stbl)
1980
me->enclosing = enclosing;
1981
me->enclosing_last_anchor_before_stbl = enclosing_last_anchor_before_stbl;
1984
PUBLIC STable_info * Stbl_get_enclosing ARGS1(
1989
return me->enclosing;
1992
PUBLIC struct _TextAnchor * Stbl_get_last_anchor_before ARGS1(
1997
return me->enclosing_last_anchor_before_stbl;