1 /*
2 * $LynxId: TRSTable.c,v 1.31 2013/05/01 01:00:38 tom Exp $
3 * Simple table object
4 * ===================
5 * Authors
6 * KW Klaus Weide <kweide@enteract.com>
7 * History:
8 * 2 Jul 1999 KW Created.
9 */
10
11 #include <HTUtils.h>
12 #include <HTStyle.h> /* for HT_LEFT, HT_CENTER, HT_RIGHT */
13 #include <LYCurses.h>
14 #include <TRSTable.h>
15 #include <LYGlobalDefs.h>
16
17 #include <LYLeaks.h>
18
19 #ifdef SAVE_TIME_NOT_SPACE
20 #define CELLS_GROWBY 16
21 #define ROWS_GROWBY 16
22 #else
23 #define CELLS_GROWBY 2
24 #define ROWS_GROWBY 2
25 #endif
26
27 #ifdef USE_CURSES_PADS
28 # define MAX_STBL_POS (LYwideLines ? MAX_COLS - 1 : LYcolLimit)
29 #else
30 # define MAX_STBL_POS (LYcolLimit)
31 #endif
32
33 /* must be different from HT_ALIGN_NONE and HT_LEFT, HT_CENTER etc.: */
34 #define RESERVEDCELL (-2) /* cell's alignment field is overloaded, this
35 value means cell was reserved by ROWSPAN */
36 #define EOCOLG (-2) /* sumcols' Line field isn't used for line info, this
37 special value means end of COLGROUP */
38 #ifndef NO_AGGRESSIVE_NEWROW
39 # define NO_AGGRESSIVE_NEWROW 0
40 #endif
41
42 typedef enum {
43 CS_invalid = -1, /* cell "before the first",
44 or empty lines after [ce]bc,
45 or TRST aborted */
46 CS__new = 0,
47 CS__0new, /* new, at BOL */
48 CS__0eb, /* starts at BOL, empty, break */
49 CS__eb, /* empty, break */
50 CS__0cb, /* starts at BOL, content, break */
51 CS__cb, /* content, break */
52 CS__0ef, /* starts at BOL, empty, finished */
53 CS__ef, /* empty, finished */
54 CS__0cf, /* starts at BOL, content, finished */
55 CS__cf, /* content, finished */
56 CS__ebc, /* empty, break, more content (maybe @BOL) */
57 CS__cbc /* content, break, more content (maybe @BOL) */
58 } cellstate_t;
59
60 typedef struct _STable_states {
61 cellstate_t prev_state; /* Contents type of the previous cell */
62 cellstate_t state; /* Contents type of the worked-on cell */
63 int lineno; /* Start line of the current cell */
64 int icell_core; /* -1 or the 1st cell with <BR></TD> on row */
65 int x_td; /* x start pos of the current cell or -1 */
66 int pending_len; /* For multiline cells, the length of
67 the part on the first line (if
68 state is CS__0?[ec]b) (??), or 0 */
69 } STable_states;
70
71 typedef struct _STable_cellinfo {
72 int cLine; /* lineno in doc (zero-based): -1 for
73 contentless cells (and cells we do
74 not want to measure and count?),
75 line-of-the-start otherwise. */
76 int pos; /* column where cell starts */
77 int len; /* number of character positions */
78 int colspan; /* number of columns to span */
79 int alignment; /* one of HT_LEFT, HT_CENTER, HT_RIGHT,
80 or RESERVEDCELL */
81 } STable_cellinfo;
82
83 enum ended_state {
84 ROW_not_ended,
85 ROW_ended_by_endtr,
86 ROW_ended_by_splitline
87 };
88
89 #define HAS_END_OF_CELL 1
90 #define HAS_BEG_OF_CELL 2
91 #define IS_CONTINUATION_OF_CELL 4
92 #define OFFSET_IS_VALID 8
93 #define OFFSET_IS_VALID_LAST_CELL 0x10
94 #define BELIEVE_OFFSET 0x20
95
96 typedef struct _STable_rowinfo {
97 /* Each row may be displayed on many display lines, but we fix up
98 positions of cells on this display line only: */
99 int Line; /* lineno in doc (zero-based) */
100 int ncells; /* number of table cells */
101
102 /* What is the meaning of this?! It is set if:
103 [search for def of fixed_line below]
104
105 a1) a non-last cell is not at BOL,
106 a2) a non-last cell has something on the first line,
107 b) a >=3-lines-cell not at BOL, the first row non-empty, the 2nd empty;
108 c) a multiline cell not at BOL, the first row non-empty, the rest empty;
109 d) a multiline cell not at BOL, the first row non-empty;
110 e) a singleline non-empty cell not at BOL;
111
112 Summary: have seen a cell which is one of:
113 (Notation: B: at BOL; L: last; E: the first row is non-empty)
114
115 bcde: !B && !E
116 a1: !L && !B
117 a2: !L && !E
118
119 Or: has at least two of !B, !L, !E, or: has at most one of B,L,E.
120
121 REMARK: If this variable is not set, but icell_core is, Line is
122 reset to the line of icell_core.
123 */
124 BOOL fixed_line; /* if we have a 'core' line of cells */
125 enum ended_state ended; /* if we saw </tr> etc */
126 int content; /* Whether contains end-of-cell etc */
127 int offset; /* >=0 after line break in a multiline cell */
128 int allocated; /* number of table cells allocated */
129 STable_cellinfo *cells;
130 int alignment; /* global align attribute for this row */
131 } STable_rowinfo;
132
133 struct _STable_info {
134 #ifdef EXP_NESTED_TABLES
135 struct _STable_info *enclosing; /* The table which contain us */
136 struct _TextAnchor *enclosing_last_anchor_before_stbl;
137 #endif
138 int startline; /* lineno where table starts (zero-based) */
139 int nrows; /* number of rows */
140 int ncols; /* number of rows */
141 int maxlen; /* sum of max. cell lengths of any row */
142 int maxpos; /* max. of max. cell pos of any row */
143 int allocated_rows; /* number of rows allocated */
144 int allocated_sumcols; /* number of sumcols allocated */
145 int ncolinfo; /* number of COL info collected */
146 STable_cellinfo *sumcols; /* for summary (max len/pos) col info */
147 STable_rowinfo *rows;
148 STable_rowinfo rowspans2eog;
149 short alignment; /* global align attribute for this table */
150 short rowgroup_align; /* align default for current group of rows */
151 short pending_colgroup_align;
152 int pending_colgroup_next;
153 STable_states s;
154 };
155
156 /*
157 * Functions and structures in this source file keep track of positions.
158 * They don't know about the character data in those lines, or about
159 * the HText and HTLine structures. GridText.c doesn't know about our
160 * structures. It should stay that way.
161 *
162 * The basic idea: we let the code in HTML.c/GridText.c produce and format
163 * output "as usual", i.e. as without Simple Table support. We keep track
164 * of the positions in the generated output where cells and rows start (or
165 * end). If all goes well, that preliminary output (stored in HText/HTLine
166 * structures) can be fixed up when the TABLE end tag is processed, by just
167 * inserting spaces in the right places (and possibly changing alignment).
168 * If all goes not well, we already have a safe fallback.
169 *
170 * Note that positions passed to and from these functions should be
171 * in terms of screen positions, not just byte counts in a HTLine.data
172 * (cf. line->data vs. HText_TrueLineSize).
173 *
174 * Memory is allocated dynamically, so we can have tables of arbitrary
175 * length. On allocation error we just return and error indication
176 * instead of outofmem(), so caller can give up table tracking and maybe
177 * recover memory.
178 *
179 * Implemented:
180 * - ALIGN={left,right,center,justify} applied to individual table cells
181 * ("justify" is treated as "left")
182 * - Inheritance of horizontal alignment according to HTML 4.0
183 * - COLSPAN >1 (may work incorrectly for some tables?)
184 * - ROWSPAN >1 (reserving cells in following rows)
185 * - Line breaks at start of first cell or at end of last cell are treated
186 * as if they were not part of the cell and row. This allows us to
187 * cooperate with one way in which tables have been made friendly to
188 * browsers without any table support.
189 * Missing, but can be added:
190 * - Support for COLGROUP/COL
191 * - Tables wider than display. The limitation is not here but in GridText.c
192 * etc. If horizontal scrolling were implemented there, the mechanisms
193 * here coudl deal with wide tables (just change MAX_STBL_POS code).
194 * Missing, unlikely to add:
195 * - Support for non-LTR directionality. A general problem, support is
196 * lacking throughout the lynx code.
197 * - Support for most other table-related attributes. Most of them are
198 * for decorative purposes.
199 * Impossible or very unlikely (because it doesn't fit the model):
200 * - Any cell contents of more than one line, line breaks within cells.
201 * Anything that requires handling cell contents as paragraphs (block
202 * elements), like reflowing. Vertical alignment.
203 */
204 static int Stbl_finishCellInRow(STable_rowinfo *me, STable_states *s, int end_td,
205 int lineno,
206 int pos);
207 static int Stbl_finishRowInTable(STable_info *me);
208
cellstate_s(cellstate_t state)209 static const char *cellstate_s(cellstate_t state)
210 {
211 const char *result = "?";
212 /* *INDENT-OFF* */
213 switch (state) {
214 case CS_invalid: result = "CS_invalid"; break;
215 case CS__new: result = "CS__new"; break;
216 case CS__0new: result = "CS__0new"; break;
217 case CS__0eb: result = "CS__0eb"; break;
218 case CS__eb: result = "CS__eb"; break;
219 case CS__0cb: result = "CS__0cb"; break;
220 case CS__cb: result = "CS__cb"; break;
221 case CS__0ef: result = "CS__0ef"; break;
222 case CS__ef: result = "CS__ef"; break;
223 case CS__0cf: result = "CS__0cf"; break;
224 case CS__cf: result = "CS__cf"; break;
225 case CS__ebc: result = "CS__ebc"; break;
226 case CS__cbc: result = "CS__cbc"; break;
227 }
228 /* *INDENT-ON* */
229
230 return result;
231 }
232
Stbl_startTABLE(int alignment)233 struct _STable_info *Stbl_startTABLE(int alignment)
234 {
235 STable_info *me = typecalloc(STable_info);
236
237 CTRACE2(TRACE_TRST,
238 (tfp, "TRST:Stbl_startTABLE(align=%d)\n", (int) alignment));
239 if (me) {
240 me->alignment = (short) alignment;
241 me->rowgroup_align = HT_ALIGN_NONE;
242 me->pending_colgroup_align = HT_ALIGN_NONE;
243 me->s.x_td = -1;
244 me->s.icell_core = -1;
245 #ifdef EXP_NESTED_TABLES
246 if (nested_tables)
247 me->enclosing = 0;
248 #endif
249 }
250 return me;
251 }
252
free_rowinfo(STable_rowinfo * me)253 static void free_rowinfo(STable_rowinfo *me)
254 {
255 if (me && me->allocated) {
256 FREE(me->cells);
257 }
258 }
259
Stbl_free(STable_info * me)260 void Stbl_free(STable_info *me)
261 {
262 CTRACE2(TRACE_TRST,
263 (tfp, "TRST:Stbl_free()\n"));
264 if (me && me->allocated_rows && me->rows) {
265 int i;
266
267 for (i = 0; i < me->allocated_rows; i++)
268 free_rowinfo(me->rows + i);
269 FREE(me->rows);
270 }
271 free_rowinfo(&me->rowspans2eog);
272 if (me)
273 FREE(me->sumcols);
274 FREE(me);
275 }
276
277 /*
278 * Returns -1 on error, otherwise index of just-added table cell.
279 */
Stbl_addCellToRow(STable_rowinfo * me,STable_cellinfo * colinfo,int ncolinfo,STable_states * s,int colspan,int alignment,int isheader,int lineno,int * ppos)280 static int Stbl_addCellToRow(STable_rowinfo *me, STable_cellinfo *colinfo, int ncolinfo,
281 STable_states *s,
282 int colspan,
283 int alignment,
284 int isheader,
285 int lineno,
286 int *ppos)
287 {
288 STable_cellinfo *cells;
289 int i;
290 int last_colspan = me->ncells ?
291 me->cells[me->ncells - 1].colspan : 1;
292 cellstate_t newstate;
293 int ret;
294
295 CTRACE2(TRACE_TRST,
296 (tfp, "TRST:Stbl_addCellToRow, line=%d, pos=%d, colspan=%d\n",
297 lineno, *ppos, colspan));
298 CTRACE2(TRACE_TRST,
299 (tfp,
300 " ncells=%d, stateLine=%d, pending_len=%d, pstate=%s, state=%s\n",
301 me->ncells, s->lineno, s->pending_len,
302 cellstate_s(s->prev_state), cellstate_s(s->state)));
303 if (me->ncells == 0)
304 s->prev_state = CS_invalid;
305 else if (s->prev_state == CS_invalid ||
306 (s->state != CS__0new &&
307 s->state != CS__ef && s->state != CS__0ef))
308 s->prev_state = s->state;
309
310 if (me->ncells == 0 || *ppos == 0)
311 newstate = CS__0new;
312 else
313 newstate = CS__new;
314
315 if (me->ncells > 0 && s->pending_len > 0) {
316 if (s->prev_state != CS__cbc)
317 me->cells[me->ncells - 1].len = s->pending_len;
318 s->pending_len = 0;
319 }
320 s->x_td = *ppos;
321
322 if (lineno != s->lineno) {
323 if (!me->fixed_line) {
324 if (me->ncells == 0 || *ppos == 0) {
325 switch (s->prev_state) {
326 case CS_invalid:
327 case CS__0new:
328 case CS__0eb:
329 case CS__0cb:
330 case CS__0ef:
331 case CS__0cf:
332 if (me->ncells > 0)
333 for (i = me->ncells + last_colspan - 2;
334 i >= me->ncells - 1; i--) {
335 me->cells[i].pos = *ppos;
336 me->cells[i].cLine = lineno;
337 }
338 me->Line = lineno;
339 break;
340 case CS__new:
341 case CS__eb:
342 case CS__ef:
343 case CS__cf:
344 default:
345 break;
346 case CS__cb:
347 *ppos = me->cells[me->ncells - 1].pos +
348 me->cells[me->ncells - 1].len;
349 }
350 } else { /* last cell multiline, ncells != 0, pos != 0 */
351 switch (s->prev_state) {
352 case CS__0new:
353 case CS__0eb:
354 case CS__0ef:
355 /* Do not fail, but do not set fixed_line either */
356 break;
357 case CS__cb:
358 goto trace_and_fail;
359 case CS__cf:
360 goto trace_and_fail;
361 case CS__0cb:
362 case CS__0cf:
363 if (*ppos > me->cells[0].pos)
364 me->Line = lineno;
365 me->fixed_line = YES; /* type=a def of fixed_line i */
366 break;
367 case CS__new:
368 case CS__eb:
369 case CS__ef:
370 default:
371 me->fixed_line = YES; /* type=e def of fixed_line ii */
372 break;
373 case CS__cbc:
374 goto trace_and_fail;
375 }
376 }
377 }
378 if (me->fixed_line && lineno != me->Line) {
379 switch (s->prev_state) {
380 case CS__cb:
381 case CS__cf:
382 if (*ppos > 0)
383 goto trace_and_fail;
384 else
385 *ppos = me->cells[me->ncells - 1].pos /* == 0 */ +
386 me->cells[me->ncells - 1].len;
387 break;
388 case CS__0cf:
389 case CS__0cb:
390 if (*ppos == 0 || *ppos <= me->cells[0].pos)
391 *ppos = me->cells[me->ncells - 1].pos /* == 0 */ +
392 me->cells[me->ncells - 1].len;
393 break;
394 case CS__0new:
395 case CS__0ef:
396 case CS__0eb:
397 break;
398 case CS__new:
399 case CS__eb:
400 case CS__ef:
401 default:
402 *ppos = me->cells[me->ncells - 1].pos;
403 break;
404 case CS__cbc:
405 break;
406 case CS_invalid:
407 break;
408 }
409 }
410 s->lineno = lineno;
411 } else { /* lineno == s->lineno: */
412 switch (s->prev_state) {
413 case CS_invalid:
414 case CS__0new:
415 case CS__0eb: /* cannot happen */
416 case CS__0cb: /* cannot happen */
417 case CS__0ef:
418 case CS__0cf: /* ##302?? set icell_core? or only in finish? */
419 break;
420 case CS__eb: /* cannot happen */
421 case CS__cb: /* cannot happen */
422 case CS__ef:
423 break;
424 case CS__ebc: /* should have done smth in finish */
425 case CS__cbc: /* should have done smth in finish */
426 break;
427 case CS__new:
428 case CS__cf:
429 if (me->fixed_line && me->Line != lineno) {
430 goto trace_and_fail;
431 } else {
432 me->fixed_line = YES;
433 me->Line = lineno;
434 }
435 }
436 }
437
438 s->state = newstate;
439
440 if (me->ncells > 0 && me->cells[me->ncells - 1].colspan > 1) {
441 me->ncells += me->cells[me->ncells - 1].colspan - 1;
442 }
443 while (me->ncells < me->allocated &&
444 me->cells[me->ncells].alignment == RESERVEDCELL) {
445 me->ncells++;
446 }
447 {
448 int growby = 0;
449
450 while (me->ncells + colspan + 1 > me->allocated + growby)
451 growby += CELLS_GROWBY;
452 if (growby) {
453 if (me->allocated == 0 && !me->cells) {
454 cells = typecallocn(STable_cellinfo, (unsigned) growby);
455 } else {
456 cells = typeRealloc(STable_cellinfo, me->cells,
457 (unsigned) (me->allocated + growby));
458
459 for (i = 0; cells && i < growby; i++) {
460 cells[me->allocated + i].alignment = HT_ALIGN_NONE;
461 }
462 }
463 if (cells) {
464 me->allocated += growby;
465 me->cells = cells;
466 } else {
467 goto trace_and_fail;
468 }
469 }
470 }
471
472 me->cells[me->ncells].cLine = lineno;
473 me->cells[me->ncells].pos = *ppos;
474 me->cells[me->ncells].len = -1;
475 me->cells[me->ncells].colspan = colspan;
476
477 if (alignment != HT_ALIGN_NONE)
478 me->cells[me->ncells].alignment = alignment;
479 else {
480 if (ncolinfo >= me->ncells + 1)
481 me->cells[me->ncells].alignment = colinfo[me->ncells].alignment;
482 else
483 me->cells[me->ncells].alignment = me->alignment;
484 if (me->cells[me->ncells].alignment == HT_ALIGN_NONE)
485 me->cells[me->ncells].alignment = me->alignment;
486 if (me->cells[me->ncells].alignment == HT_ALIGN_NONE)
487 me->cells[me->ncells].alignment = isheader ? HT_CENTER : HT_LEFT;
488 }
489 for (i = me->ncells + 1; i < me->ncells + colspan; i++) {
490 me->cells[i].cLine = lineno;
491 me->cells[i].pos = *ppos;
492 me->cells[i].len = -1;
493 me->cells[i].colspan = 0;
494 me->cells[i].alignment = HT_LEFT;
495 }
496 me->cells[me->ncells + colspan].pos = -1; /* not yet used */
497 me->ncells++;
498
499 ret = me->ncells - 1;
500 trace_and_return:
501 CTRACE2(TRACE_TRST,
502 (tfp, " => prev_state=%s, state=%s, ret=%d\n",
503 cellstate_s(s->prev_state), cellstate_s(s->state), ret));
504 return (ret);
505
506 trace_and_fail:
507 ret = -1;
508 goto trace_and_return;
509 }
510
511 /* returns -1 on error, 0 otherwise */
512 /* assumes cells have already been allocated (but may need more) */
Stbl_reserveCellsInRow(STable_rowinfo * me,int icell,int colspan)513 static int Stbl_reserveCellsInRow(STable_rowinfo *me, int icell,
514 int colspan)
515 {
516 STable_cellinfo *cells;
517 int i;
518 int growby = 1 + icell + colspan - me->allocated;
519
520 CTRACE2(TRACE_TRST,
521 (tfp, "TRST:Stbl_reserveCellsInRow(icell=%d, colspan=%d\n",
522 icell, colspan));
523 if (growby > 0) {
524 cells = typeRealloc(STable_cellinfo, me->cells,
525 (unsigned) (me->allocated + growby));
526
527 if (cells) {
528 for (i = 0; i < growby; i++) {
529 cells[me->allocated + i].alignment = HT_ALIGN_NONE;
530 }
531 me->allocated += growby;
532 me->cells = cells;
533 } else {
534 return -1;
535 }
536 }
537 for (i = icell; i < icell + colspan; i++) {
538 me->cells[i].cLine = -1;
539 me->cells[i].pos = -1;
540 me->cells[i].len = -1;
541 me->cells[i].colspan = 0;
542 me->cells[i].alignment = RESERVEDCELL;
543 }
544 me->cells[icell].colspan = colspan;
545 return 0;
546 }
547
548 /* Returns -1 on failure. */
Stbl_finishCellInRow(STable_rowinfo * me,STable_states * s,int end_td,int lineno,int pos)549 static int Stbl_finishCellInRow(STable_rowinfo *me, STable_states *s, int end_td,
550 int lineno,
551 int pos)
552 {
553 STable_cellinfo *lastcell;
554 cellstate_t newstate = CS_invalid;
555 int multiline = NO, empty;
556 int ret;
557
558 CTRACE2(TRACE_TRST,
559 (tfp,
560 "TRST:Stbl_finishCellInRow line=%d pos=%d end_td=%d ncells=%d pnd_len=%d\n",
561 lineno, pos, (int) end_td, me->ncells, s->pending_len));
562
563 if (me->ncells <= 0)
564 return -1;
565 lastcell = me->cells + (me->ncells - 1);
566 multiline = (lineno != lastcell->cLine || lineno != s->lineno);
567 empty = multiline ? (pos == 0) : (pos <= s->x_td);
568
569 CTRACE2(TRACE_TRST,
570 (tfp,
571 " [lines: lastCell=%d state=%d multi=%d] empty=%d (prev)state=(%s) %s\n",
572 lastcell->cLine, s->lineno, multiline, empty,
573 cellstate_s(s->prev_state), cellstate_s(s->state)));
574
575 if (multiline) {
576 if ((end_td & TRST_ENDCELL_MASK) == TRST_ENDCELL_LINEBREAK) {
577 switch (s->state) {
578 case CS_invalid:
579 newstate = empty ? CS_invalid : CS__cbc;
580 break;
581 case CS__0new:
582 newstate = empty ? CS__0eb : CS__0cb;
583 break;
584 case CS__0eb:
585 newstate = empty ? CS__0eb : CS__ebc;
586 s->state = newstate;
587 if (me->fixed_line) {
588 if (empty)
589 ret = (lastcell->len <= 0 ? 0 : lastcell->len);
590 else
591 ret = (lastcell->len <= 0 ? 0 : -1);
592 } else {
593 if (empty)
594 ret = (lastcell->len <= 0 ? 0 : lastcell->len);
595 else
596 ret = (lastcell->len <= 0 ? 0 : 0);
597 }
598 goto trace_and_return;
599 case CS__0cb:
600 if (!me->fixed_line) {
601 if (!empty) {
602 if (s->icell_core == -1)
603 me->Line = -1;
604 }
605 }
606 if (s->pending_len && empty) { /* First line non-empty */
607 if ((me->fixed_line && me->Line == lastcell->cLine) ||
608 s->icell_core == me->ncells - 1)
609 lastcell->len = s->pending_len;
610 s->pending_len = 0;
611 } /* @@@ for empty do smth. about ->Line / ->icell_core !! */
612 newstate = empty ? CS__0cb : CS__cbc; /* ##474_needs_len!=-1? */
613 break;
614 case CS__0ef:
615 case CS__0cf:
616 break;
617 case CS__new:
618 newstate = empty ? CS__eb : CS__cb;
619 break;
620 case CS__eb: /* ##484_set_pending_ret_0_if_empty? */
621 newstate = empty ? CS__eb : CS__ebc;
622 s->state = newstate;
623 if (me->fixed_line) {
624 if (empty)
625 ret = (lastcell->len <= 0 ? 0 : lastcell->len);
626 else
627 ret = (lastcell->len <= 0 ? 0 : -1);
628 } else {
629 if (empty)
630 ret = (lastcell->len <= 0 ? 0 : lastcell->len);
631 else
632 ret = (lastcell->len <= 0 ? 0 : -1);
633 }
634 goto trace_and_return;
635 case CS__cb:
636 if (s->pending_len && empty) { /* ##496: */
637 lastcell->len = s->pending_len;
638 s->pending_len = 0;
639 } /* @@@ for empty do smth. about ->Line / ->icell_core !! */
640 ret = -1;
641 if (empty) {
642 if (!me->fixed_line) {
643 me->fixed_line = YES; /* type=b def of fixed_line i */
644 me->Line = lastcell->cLine; /* should've happened in break */
645 } else {
646 if (me->Line != lastcell->cLine)
647 goto trace_and_return;
648 }
649 newstate = CS__cb;
650 } else {
651 if (!me->fixed_line) {
652 me->fixed_line = YES; /* type=b def of fixed_line ii */
653 me->Line = lastcell->cLine; /* should've happened in break */
654 }
655 s->state = CS__cbc;
656 goto trace_and_return;
657 }
658 break;
659 case CS__ef:
660 ret = 0;
661 goto trace_and_return;
662 case CS__cf:
663 ret = lastcell->len; /* ##523_change_state? */
664 goto trace_and_return;
665 case CS__cbc:
666 if (!me->fixed_line) {
667 if (empty) {
668 if (s->icell_core == -1) /* ##528??: */
669 me->Line = lineno;
670 /* lastcell->Line = lineno; */
671 } else { /* !empty */
672 if (s->icell_core == -1)
673 me->Line = -1;
674 }
675 }
676 s->pending_len = 0;
677 newstate = empty ? CS_invalid : CS__cbc;
678 break;
679 default:
680 break;
681 }
682 } else { /* multiline cell, processing </TD>: */
683 s->x_td = -1;
684 switch (s->state) {
685 case CS_invalid:
686 /* ##540_return_-1_for_invalid_if_len!: */
687 if (!empty && lastcell->len > 0) {
688 newstate = CS__0cf;
689 s->state = newstate;
690 ret = -1;
691 goto trace_and_return;
692 }
693 /* ##541_set_len_0_Line_-1_sometimes: */
694 lastcell->len = 0;
695 lastcell->cLine = -1;
696 /* fall thru ##546 really fall thru??: */
697 newstate = empty ? CS_invalid : CS__cbc;
698 break;
699 case CS__0new:
700 newstate = empty ? CS__0ef : CS__0cf;
701 break;
702 case CS__0eb:
703 newstate = empty ? CS__0ef : CS__0cf; /* ebc?? */
704 s->state = newstate;
705 if (me->fixed_line) {
706 if (empty)
707 ret = (lastcell->len <= 0 ? 0 : lastcell->len);
708 else
709 ret = (lastcell->len <= 0 ? 0 : -1);
710 } else {
711 if (empty)
712 ret = (lastcell->len <= 0 ? 0 : lastcell->len);
713 else
714 ret = (lastcell->len <= 0 ? 0 : 0);
715 }
716 goto trace_and_return;
717 case CS__0cb:
718 if (s->pending_len) {
719 if (empty)
720 lastcell->len = s->pending_len;
721 else
722 lastcell->len = 0;
723 s->pending_len = 0;
724 }
725 if (!me->fixed_line) {
726 if (empty) {
727 if (s->icell_core == -1)
728 /* first cell before <BR></TD> => the core cell */
729 s->icell_core = me->ncells - 1;
730 /* lastcell->cLine = lineno; */
731 } else { /* !empty */
732 if (s->icell_core == -1)
733 me->Line = -1;
734 }
735 }
736 if (s->pending_len && empty) {
737 lastcell->len = s->pending_len;
738 s->pending_len = 0;
739 } /* @@@ for empty do smth. about ->Line / ->icell_core !! */
740 newstate = empty ? CS__0cf : CS__cbc;
741 break;
742 case CS__0ef:
743 newstate = CS__0ef;
744 /* FALLTHRU */
745 case CS__0cf:
746 break;
747 case CS__new:
748 newstate = empty ? CS__ef : CS__cf;
749 break;
750 case CS__eb:
751 newstate = empty ? CS__ef : CS__ef; /* ##579??? !!!!! */
752 s->state = newstate;
753 if (me->fixed_line) {
754 if (empty)
755 ret = (lastcell->len <= 0 ? 0 : lastcell->len);
756 else
757 ret = (lastcell->len <= 0 ? 0 : -1);
758 } else {
759 if (empty)
760 ret = (lastcell->len <= 0 ? 0 : lastcell->len);
761 else
762 ret = (lastcell->len <= 0 ? 0 : -1);
763 }
764 goto trace_and_return;
765 case CS__cb:
766 if (s->pending_len && empty) {
767 lastcell->len = s->pending_len;
768 s->pending_len = 0;
769 }
770 ret = -1;
771 if (empty) {
772 if (!me->fixed_line) {
773 me->fixed_line = YES; /* type=c def of fixed_line */
774 me->Line = lastcell->cLine; /* should've happened in break */
775 } else {
776 if (me->Line != lastcell->cLine)
777 goto trace_and_return;
778 }
779 newstate = CS__cf;
780 } else {
781 goto trace_and_return;
782 }
783 break;
784 case CS__ef: /* ignored error */
785 case CS__cf: /* ignored error */
786 break;
787 case CS__ebc: /* ##540_handle_ebc: */
788 lastcell->len = 0;
789 if (!me->fixed_line) {
790 if (!empty) {
791 if (s->icell_core == -1)
792 lastcell->cLine = -1;
793 }
794 }
795 s->pending_len = 0;
796 newstate = empty ? CS_invalid : CS__cbc;
797 break;
798 case CS__cbc: /* ##586 */
799 lastcell->len = 0; /* ##613 */
800 ret = -1;
801 if (me->fixed_line && me->Line == lastcell->cLine)
802 goto trace_and_return;
803 if (!me->fixed_line) {
804 if (empty) {
805 if (s->icell_core == -1)
806 me->Line = lineno;
807 }
808 }
809 s->pending_len = 0; /* ##629 v */
810 newstate = empty ? CS_invalid : CS__cbc;
811 break;
812 }
813 }
814 } else { /* (!multiline) */
815 if ((end_td & TRST_ENDCELL_MASK) == TRST_ENDCELL_LINEBREAK) {
816 switch (s->state) {
817 case CS_invalid:
818 case CS__0new:
819 s->pending_len = empty ? 0 : pos - lastcell->pos;
820 newstate = empty ? CS__0eb : CS__0cb;
821 s->state = newstate;
822 ret = 0; /* or 0 for xlen to s->pending_len?? */
823 goto trace_and_return;
824 case CS__0eb: /* cannot happen */
825 newstate = CS__eb;
826 break;
827 case CS__0cb: /* cannot happen */
828 newstate = CS__cb;
829 break;
830 case CS__0ef:
831 case CS__0cf:
832 break;
833 case CS__new:
834 ret = -1;
835 if (!empty && s->prev_state == CS__cbc) /* ##609: */
836 goto trace_and_return;
837 if (!empty) {
838 if (!me->fixed_line) {
839 me->fixed_line = YES; /* type=d def of fixed_line */
840 me->Line = lineno;
841 } else {
842 if (me->Line != lineno)
843 goto trace_and_return;
844 }
845 }
846 newstate = empty ? CS__eb : CS__cb;
847 s->state = newstate;
848 if (!me->fixed_line) {
849 s->pending_len = empty ? 0 : pos - lastcell->pos;
850 ret = 0;
851 goto trace_and_return;
852 } else {
853 s->pending_len = 0;
854 lastcell->len = empty ? 0 : pos - lastcell->pos;
855 ret = lastcell->len;
856 goto trace_and_return;
857 }
858 case CS__eb: /* cannot happen */
859 newstate = empty ? CS__eb : CS__ebc;
860 break;
861 case CS__cb: /* cannot happen */
862 newstate = empty ? CS__cb : CS__cbc;
863 break;
864 case CS__ef:
865 ret = 0;
866 goto trace_and_return;
867 case CS__cf:
868 ret = lastcell->len;
869 goto trace_and_return;
870 case CS__cbc: /* ??? */
871 break;
872 default:
873 break;
874 }
875 } else { /* !multiline, processing </TD>: */
876 s->x_td = -1;
877 switch (s->state) {
878 case CS_invalid: /* ##691_no_lastcell_len_for_invalid: */
879 if (!(me->fixed_line && me->Line == lastcell->cLine))
880 lastcell->len = 0;
881 /* FALLTHRU */
882 case CS__0new:
883 newstate = empty ? CS__0ef : CS__0cf;
884 break; /* ##630 */
885 case CS__0eb:
886 newstate = empty ? CS__0ef : CS__0ef;
887 break; /* ??? */
888 case CS__0cb:
889 newstate = empty ? CS__0cf : CS__cbc;
890 break; /* ??? */
891 case CS__0ef:
892 newstate = CS__0ef;
893 break; /* ??? */
894 case CS__0cf:
895 break; /* ??? */
896 case CS__new:
897 ret = -1;
898 if (!empty && s->prev_state == CS__cbc)
899 goto trace_and_return;
900 if (!empty) { /* ##642_set_fixed!: */
901 if (!me->fixed_line) {
902 me->fixed_line = YES; /* type=e def of fixed_line */
903 me->Line = lineno;
904 } else {
905 if (me->Line != lineno)
906 goto trace_and_return;
907 }
908 }
909 if (lastcell->len < 0)
910 lastcell->len = empty ? 0 : pos - lastcell->pos;
911 newstate = empty ? CS__ef : CS__cf;
912 s->state = newstate;
913 ret = ((me->fixed_line && lineno != me->Line)
914 ? -1 : lastcell->len);
915 goto trace_and_return;
916 case CS__eb:
917 newstate = empty ? CS__ef : CS__cf;
918 break; /* ??? */
919 case CS__cb:
920 newstate = empty ? CS__cf : CS__cf;
921 break; /* ??? */
922 case CS__ef: /* ignored error */
923 case CS__cf: /* ignored error */
924 default:
925 break;
926 }
927 lastcell->len = pos - lastcell->pos;
928 } /* if (!end_td) ... else */
929 } /* if (multiline) ... else */
930
931 s->state = newstate;
932 ret = lastcell->len;
933 #ifdef EXP_NESTED_TABLES
934 if (nested_tables) {
935 if (ret == -1 && pos == 0)
936 ret = 0; /* XXXX Hack to allow trailing <P> in multiline cells. */
937 }
938 #endif
939
940 /* lastcell->len = pos - lastcell->pos; */
941 trace_and_return:
942 CTRACE2(TRACE_TRST,
943 (tfp, " => prev_state=%s, state=%s, return=%d\n",
944 cellstate_s(s->prev_state), cellstate_s(s->state), ret));
945 return ret;
946 }
947
948 /*
949 * Reserve cells, each of given colspan, in (rowspan-1) rows after the current
950 * row of rowspan>1. If rowspan==0, use special 'row' rowspans2eog to keep
951 * track of rowspans that are to remain in effect until the end of the row
952 * group (until next THEAD/TFOOT/TBODY) or table.
953 */
Stbl_reserveCellsInTable(STable_info * me,int icell,int colspan,int rowspan)954 static int Stbl_reserveCellsInTable(STable_info *me, int icell,
955 int colspan,
956 int rowspan)
957 {
958 STable_rowinfo *rows, *row;
959 int growby;
960 int i;
961
962 if (colspan > TRST_MAXCOLSPAN) {
963 CTRACE2(TRACE_TRST,
964 (tfp,
965 "TRST:*** COLSPAN=%d is too large, ignored!\n",
966 colspan));
967 return -1;
968 }
969 if (rowspan > TRST_MAXROWSPAN) {
970 CTRACE2(TRACE_TRST,
971 (tfp,
972 "TRST:*** ROWSPAN=%d is too large, ignored!\n",
973 rowspan));
974 return -1;
975 }
976 if (me->nrows <= 0)
977 return -1; /* must already have at least one row */
978
979 CTRACE2(TRACE_TRST,
980 (tfp,
981 "TRST:Stbl_reserveCellsInTable(icell=%d, colspan=%d, rowspan=%d)\n",
982 icell, colspan, rowspan));
983 if (rowspan == 0) {
984 if (!me->rowspans2eog.cells) {
985 me->rowspans2eog.cells = typecallocn(STable_cellinfo,
986 (unsigned) HTMAX(1, icell + colspan));
987
988 if (!me->rowspans2eog.cells)
989 return 0; /* fail silently */
990 else
991 me->rowspans2eog.allocated = icell + colspan;
992 }
993 Stbl_reserveCellsInRow(&me->rowspans2eog, icell, colspan);
994 }
995
996 growby = me->nrows + rowspan - 1 - me->allocated_rows;
997 if (growby > 0) {
998 rows = typeRealloc(STable_rowinfo, me->rows,
999 (unsigned) (me->allocated_rows + growby));
1000
1001 if (!rows)
1002 return 0; /* ignore silently, no free memory, may be recoverable */
1003 for (i = 0; i < growby; i++) {
1004 row = rows + me->allocated_rows + i;
1005 row->allocated = 0;
1006 row->offset = 0;
1007 row->content = 0;
1008 if (!me->rowspans2eog.allocated) {
1009 row->cells = NULL;
1010 } else {
1011 row->cells = typecallocn(STable_cellinfo,
1012 (unsigned) me->rowspans2eog.allocated);
1013
1014 if (row->cells) {
1015 row->allocated = me->rowspans2eog.allocated;
1016 memcpy(row->cells, me->rowspans2eog.cells,
1017 ((unsigned) row->allocated * sizeof(STable_cellinfo)));
1018 }
1019 }
1020 row->ncells = 0;
1021 row->fixed_line = NO;
1022 row->alignment = HT_ALIGN_NONE;
1023 }
1024 me->allocated_rows += growby;
1025 me->rows = rows;
1026 }
1027 for (i = me->nrows;
1028 i < (rowspan == 0 ? me->allocated_rows : me->nrows + rowspan - 1);
1029 i++) {
1030 if (!me->rows[i].allocated) {
1031 me->rows[i].cells = typecallocn(STable_cellinfo,
1032 (unsigned) HTMAX(1,
1033 icell
1034 + colspan));
1035
1036 if (!me->rows[i].cells)
1037 return 0; /* fail silently */
1038 else
1039 me->rows[i].allocated = icell + colspan;
1040 }
1041 Stbl_reserveCellsInRow(me->rows + i, icell, colspan);
1042 }
1043 return 0;
1044 }
1045
1046 /* Remove reserved cells in trailing rows that were added for rowspan,
1047 * to be used when a THEAD/TFOOT/TBODY ends. */
Stbl_cancelRowSpans(STable_info * me)1048 static void Stbl_cancelRowSpans(STable_info *me)
1049 {
1050 int i;
1051
1052 CTRACE2(TRACE_TRST, (tfp, "TRST:Stbl_cancelRowSpans()"));
1053 for (i = me->nrows; i < me->allocated_rows; i++) {
1054 if (!me->rows[i].ncells) { /* should always be the case */
1055 FREE(me->rows[i].cells);
1056 me->rows[i].allocated = 0;
1057 }
1058 }
1059 free_rowinfo(&me->rowspans2eog);
1060 me->rowspans2eog.allocated = 0;
1061 }
1062
1063 /*
1064 * Returns -1 on error, otherwise index of just-added table row.
1065 */
Stbl_addRowToTable(STable_info * me,int alignment,int lineno)1066 int Stbl_addRowToTable(STable_info *me, int alignment,
1067 int lineno)
1068 {
1069 STable_rowinfo *rows, *row;
1070 STable_states *s = &me->s;
1071
1072 CTRACE2(TRACE_TRST,
1073 (tfp, "TRST:Stbl_addRowToTable(alignment=%d, lineno=%d)\n",
1074 alignment, lineno));
1075 if (me->nrows > 0 && me->rows[me->nrows - 1].ncells > 0) {
1076 if (s->pending_len > 0)
1077 me->rows[me->nrows - 1].cells[
1078 me->rows[me->nrows - 1].ncells - 1
1079 ].len =
1080 s->pending_len;
1081 s->pending_len = 0;
1082 }
1083 Stbl_finishRowInTable(me);
1084 if (me->nrows > 0 && me->rows[me->nrows - 1].Line == lineno)
1085 me->rows[me->nrows - 1].Line = -1;
1086 s->pending_len = 0;
1087 s->x_td = -1;
1088
1089 {
1090 int i;
1091 int growby = 0;
1092
1093 while (me->nrows + 2 > me->allocated_rows + growby)
1094 growby += ROWS_GROWBY;
1095 if (growby) {
1096 if (me->allocated_rows == 0 && !me->rows) {
1097 rows = typecallocn(STable_rowinfo, (unsigned) growby);
1098 } else {
1099 rows = typeRealloc(STable_rowinfo, me->rows,
1100 (unsigned) (me->allocated_rows + growby));
1101
1102 for (i = 0; rows && i < growby; i++) {
1103 row = rows + me->allocated_rows + i;
1104 if (!me->rowspans2eog.allocated) {
1105 row->allocated = 0;
1106 row->cells = NULL;
1107 } else {
1108 row->cells = typecallocn(STable_cellinfo,
1109 (unsigned) me->rowspans2eog.allocated);
1110
1111 if (row->cells) {
1112 row->allocated = me->rowspans2eog.allocated;
1113 memcpy(row->cells, me->rowspans2eog.cells,
1114 (unsigned) row->allocated * sizeof(STable_cellinfo));
1115 } else {
1116 FREE(rows);
1117 break;
1118 }
1119 }
1120 row->ncells = 0;
1121 row->fixed_line = NO;
1122 row->alignment = HT_ALIGN_NONE;
1123 row->offset = 0;
1124 row->content = 0;
1125 }
1126 }
1127 if (rows) {
1128 me->allocated_rows += growby;
1129 me->rows = rows;
1130 } else {
1131 return -1;
1132 }
1133 }
1134 }
1135
1136 me->rows[me->nrows].Line = lineno;
1137 if (me->nrows == 0)
1138 me->startline = lineno;
1139 if (alignment != HT_ALIGN_NONE)
1140 me->rows[me->nrows].alignment = alignment;
1141 else
1142 me->rows[me->nrows].alignment =
1143 (me->rowgroup_align == HT_ALIGN_NONE) ?
1144 me->alignment : me->rowgroup_align;
1145 me->nrows++;
1146 if (me->pending_colgroup_next > me->ncolinfo) {
1147 me->ncolinfo = me->pending_colgroup_next;
1148 me->pending_colgroup_next = 0;
1149 }
1150 me->rows[me->nrows].Line = -1; /* not yet used */
1151 me->rows[me->nrows].ended = ROW_not_ended; /* No </tr> yet */
1152 return (me->nrows - 1);
1153 }
1154
1155 /*
1156 * Returns -1 on error, otherwise current number of rows.
1157 */
Stbl_finishRowInTable(STable_info * me)1158 static int Stbl_finishRowInTable(STable_info *me)
1159 {
1160 STable_rowinfo *lastrow;
1161 STable_states *s = &me->s;
1162
1163 CTRACE2(TRACE_TRST, (tfp, "TRST:Stbl_finishRowInTable()\n"));
1164 if (!me->rows || !me->nrows)
1165 return -1; /* no row started! */
1166 lastrow = me->rows + (me->nrows - 1);
1167 lastrow->ended = ROW_ended_by_endtr;
1168 if (lastrow->ncells > 0) {
1169 if (s->pending_len > 0)
1170 lastrow->cells[lastrow->ncells - 1].len = s->pending_len;
1171 s->pending_len = 0;
1172 }
1173 s->prev_state = s->state = CS_invalid;
1174 s->lineno = -1;
1175
1176 if (s->icell_core >= 0 && !lastrow->fixed_line &&
1177 lastrow->cells[s->icell_core].cLine >= 0)
1178 lastrow->Line = lastrow->cells[s->icell_core].cLine;
1179 s->icell_core = -1;
1180 return (me->nrows);
1181 }
1182
update_sumcols0(STable_cellinfo * sumcols,STable_rowinfo * lastrow,int pos,int len,int icell,int ispan,int allocated_sumcols)1183 static void update_sumcols0(STable_cellinfo *sumcols,
1184 STable_rowinfo *lastrow,
1185 int pos,
1186 int len,
1187 int icell,
1188 int ispan,
1189 int allocated_sumcols)
1190 {
1191 int i;
1192
1193 if (len > 0) {
1194 int sumpos = pos;
1195 int prevsumpos = sumcols[icell + ispan].pos;
1196 int advance;
1197
1198 if (ispan > 0) {
1199 if (lastrow->cells[icell].pos + len > sumpos)
1200 sumpos = lastrow->cells[icell].pos + len;
1201 if (sumcols[icell + ispan - 1].pos +
1202 sumcols[icell + ispan - 1].len >
1203 sumpos)
1204 sumpos = sumcols[icell + ispan - 1].pos +
1205 sumcols[icell + ispan - 1].len;
1206 }
1207 advance = sumpos - prevsumpos;
1208 if (advance > 0) {
1209 for (i = icell + ispan; i < allocated_sumcols; i++) {
1210 if (ispan > 0 && sumcols[i].colspan < -1) {
1211 if (i + sumcols[i].colspan < icell + ispan) {
1212 advance = sumpos - sumcols[i].pos;
1213 if (i > 0)
1214 advance = HTMAX(advance,
1215 sumcols[i - 1].pos +
1216 sumcols[i - 1].len
1217 - (sumcols[i].pos));
1218 if (advance <= 0)
1219 break;
1220 }
1221 }
1222 if (sumcols[i].pos >= 0)
1223 sumcols[i].pos += advance;
1224 else {
1225 sumcols[i].pos = sumpos;
1226 break;
1227 }
1228 }
1229 }
1230 }
1231 }
1232
get_remaining_colspan(STable_rowinfo * me,STable_cellinfo * colinfo,int ncolinfo,int colspan,int ncols_sofar)1233 static int get_remaining_colspan(STable_rowinfo *me,
1234 STable_cellinfo *colinfo,
1235 int ncolinfo,
1236 int colspan,
1237 int ncols_sofar)
1238 {
1239 int i;
1240 int last_colspan = me->ncells ?
1241 me->cells[me->ncells - 1].colspan : 1;
1242
1243 if (ncolinfo == 0 || me->ncells + last_colspan > ncolinfo) {
1244 colspan = HTMIN(TRST_MAXCOLSPAN,
1245 ncols_sofar - (me->ncells + last_colspan - 1));
1246 } else {
1247 for (i = me->ncells + last_colspan - 1; i < ncolinfo - 1; i++)
1248 if (colinfo[i].cLine == EOCOLG)
1249 break;
1250 colspan = i - (me->ncells + last_colspan - 2);
1251 }
1252 CTRACE2(TRACE_TRST,
1253 (tfp, "TRST:get_remaining_colspan; colspan = %d\n",
1254 colspan));
1255 return colspan;
1256 }
1257
1258 #ifdef EXP_NESTED_TABLES
1259 /* Returns -1 on failure, 1 if faking was performed, 0 if not needed. */
Stbl_fakeFinishCellInTable(STable_info * me,STable_rowinfo * lastrow,int lineno,int finishing)1260 static int Stbl_fakeFinishCellInTable(STable_info *me,
1261 STable_rowinfo *lastrow,
1262 int lineno,
1263 int finishing) /* Processing finish or start */
1264 {
1265 STable_states *s = &me->s;
1266 int fake = 0;
1267
1268 switch (s->state) { /* We care only about trailing <BR> */
1269 case CS_invalid:
1270 case CS__0new:
1271 case CS__0ef:
1272 case CS__0cf:
1273 case CS__new:
1274 case CS__cbc:
1275 case CS__ef:
1276 case CS__cf:
1277 default:
1278 /* <BR></TD> may produce these (XXXX instead of CS__cbf?). But if
1279 finishing==0, the caller already checked that we are on a
1280 different line. */
1281 if (finishing == 0)
1282 fake = 1;
1283 break; /* Either can't happen, or may be ignored */
1284 case CS__eb:
1285 case CS__0eb:
1286 case CS__0cb:
1287 case CS__cb:
1288 fake = 1;
1289 break;
1290 }
1291 if (fake) {
1292 /* The previous action we did was putting a linebreak. Now we
1293 want to put another one. Fake necessary
1294 </TD></TR><TR><TD></TD><TD> (and possibly </TD>) instead. */
1295 int ncells = lastrow->ncells;
1296 int i;
1297 int al = lastrow->alignment;
1298 int cs = lastrow->cells[lastrow->ncells - 1].colspan;
1299 int rs = 1; /* XXXX How to find rowspan? */
1300 int ih = 0; /* XXXX How to find is_header? */
1301 int end_td = (TRST_ENDCELL_ENDTD | TRST_FAKING_CELLS);
1302 int need_reserved = 0;
1303 int prev_reserved_last = -1;
1304 STable_rowinfo *prev_row;
1305 int prev_row_n2 = (int) (lastrow - me->rows);
1306
1307 CTRACE2(TRACE_TRST,
1308 (tfp,
1309 "TRST:Stbl_fakeFinishCellInTable(lineno=%d, finishing=%d) START FAKING\n",
1310 lineno, finishing));
1311
1312 /* Although here we use pos=0, this may commit the previous
1313 cell which had <BR> as a last element. This may overflow
1314 the screen width, so the additional checks performed in
1315 Stbl_finishCellInTable (comparing to Stbl_finishCellInRow)
1316 are needed. */
1317 if (finishing) {
1318 /* Fake </TD> at BOL */
1319 if (Stbl_finishCellInTable(me, end_td, lineno, 0, 0) < 0) {
1320 return -1;
1321 }
1322 }
1323
1324 /* Fake </TR> at BOL */
1325 /* Stbl_finishCellInTable(lineno, 0, 0); */
1326 /* Needed? */
1327
1328 /* Fake <TR> at BOL */
1329 if (Stbl_addRowToTable(me, al, lineno) < 0) {
1330 return -1;
1331 }
1332 lastrow = me->rows + (me->nrows - 1);
1333 lastrow->content = IS_CONTINUATION_OF_CELL;
1334 for (i = 0; i < lastrow->allocated; i++) {
1335 if (lastrow->cells[i].alignment == RESERVEDCELL) {
1336 need_reserved = 1;
1337 break;
1338 }
1339 }
1340
1341 prev_row = me->rows + prev_row_n2;
1342 for (i = ncells; i < prev_row->allocated; i++) {
1343 if (prev_row->cells[i].alignment == RESERVEDCELL)
1344 prev_reserved_last = i;
1345 }
1346 if (need_reserved || prev_reserved_last >= 0) {
1347 /* Oups, we are going to stomp over a line which somebody
1348 cares about already, or the previous line had reserved
1349 cells which were not skipped over.
1350
1351 Remember that STable_rowinfo is about logical (TR)
1352 table lines, not displayed lines. We need to duplicate
1353 the reservation structure when we fake new logical lines. */
1354 int prev_row_n = (int) (prev_row - me->rows);
1355 STable_rowinfo *rows = typeRealloc(STable_rowinfo, me->rows,
1356 (unsigned) (me->allocated_rows
1357 + 1));
1358 int need_cells = prev_reserved_last + 1;
1359 int n;
1360
1361 if (!rows)
1362 return -1; /* ignore silently, no free memory, may be recoverable */
1363
1364 CTRACE2(TRACE_TRST,
1365 (tfp, "TRST:Stbl_fakeFinishCellInTable REALLOC ROWSPAN\n"));
1366 me->rows = rows;
1367 lastrow = me->rows + (me->nrows - 1);
1368 prev_row = me->rows + prev_row_n;
1369 me->allocated_rows++;
1370
1371 /* Insert a duplicate row after lastrow */
1372 for (n = me->allocated_rows - me->nrows - 1; n >= 0; --n)
1373 lastrow[n + 1] = lastrow[n];
1374
1375 /* Ignore cells, they belong to the next row now */
1376 lastrow->allocated = 0;
1377 lastrow->cells = 0;
1378 if (need_cells) {
1379 lastrow->cells = typecallocn(STable_cellinfo, (unsigned) need_cells);
1380
1381 /* ignore silently, no free memory, may be recoverable */
1382 if (!lastrow->cells) {
1383 return -1;
1384 }
1385 lastrow->allocated = need_cells;
1386 memcpy(lastrow->cells, prev_row->cells,
1387 (unsigned) lastrow->allocated * sizeof(STable_cellinfo));
1388
1389 i = -1;
1390 while (++i < ncells) {
1391 /* Stbl_addCellToTable grants RESERVEDCELL, but we do not
1392 want this action for fake cells.
1393 XXX Maybe always fake RESERVEDCELL instead of explicitly
1394 creating/destroying cells? */
1395 if (lastrow->cells[i].alignment == RESERVEDCELL)
1396 lastrow->cells[i].alignment = HT_LEFT;
1397 }
1398 }
1399 }
1400
1401 /* Fake <TD></TD>...<TD> (and maybe a </TD>) at BOL. */
1402 CTRACE2(TRACE_TRST,
1403 (tfp, "TRST:Stbl_fakeFinishCellInTable FAKE %d elts%s\n",
1404 ncells, (finishing ? ", last unfinished" : "")));
1405 i = 0;
1406 while (++i <= ncells) {
1407 /* XXXX A lot of args may be wrong... */
1408 if (Stbl_addCellToTable(me, (i == ncells ? cs : 1), rs, al,
1409 ih, lineno, 0, 0) < 0) {
1410 return -1;
1411 }
1412 lastrow->content &= ~HAS_BEG_OF_CELL; /* BEG_OF_CELL was fake */
1413 /* We cannot run out of width here, so it is safe to not
1414 call Stbl_finishCellInTable(), but Stbl_finishCellInRow. */
1415 if (!finishing || (i != ncells)) {
1416 if (Stbl_finishCellInRow(lastrow, s, end_td, lineno, 0) < 0) {
1417 return -1;
1418 }
1419 }
1420 }
1421 CTRACE2(TRACE_TRST,
1422 (tfp,
1423 "TRST:Stbl_fakeFinishCellInTable(lineno=%d) FINISH FAKING\n",
1424 lineno));
1425 return 1;
1426 }
1427 return 0;
1428 }
1429 #endif
1430
1431 /*
1432 * Returns -1 on error, otherwise 0.
1433 */
Stbl_addCellToTable(STable_info * me,int colspan,int rowspan,int alignment,int isheader,int lineno,int offset_not_used_yet GCC_UNUSED,int pos)1434 int Stbl_addCellToTable(STable_info *me, int colspan,
1435 int rowspan,
1436 int alignment,
1437 int isheader,
1438 int lineno,
1439 int offset_not_used_yet GCC_UNUSED,
1440 int pos)
1441 {
1442 STable_states *s = &me->s;
1443 STable_rowinfo *lastrow;
1444 STable_cellinfo *sumcols, *sumcol;
1445 int i, icell, ncells, sumpos;
1446
1447 CTRACE2(TRACE_TRST,
1448 (tfp,
1449 "TRST:Stbl_addCellToTable(lineno=%d, pos=%d, isheader=%d, cs=%d, rs=%d, al=%d)\n",
1450 lineno, pos, (int) isheader, colspan, rowspan, alignment));
1451 if (!me->rows || !me->nrows)
1452 return -1; /* no row started! */
1453 /* ##850_fail_if_fail?? */
1454 if (me->rows[me->nrows - 1].ended != ROW_not_ended)
1455 Stbl_addRowToTable(me, alignment, lineno);
1456 Stbl_finishCellInTable(me, TRST_ENDCELL_ENDTD, lineno, 0, pos);
1457 lastrow = me->rows + (me->nrows - 1);
1458
1459 #ifdef EXP_NESTED_TABLES
1460 if (nested_tables) {
1461 /* If the last cell was finished by <BR></TD>, we need to fake an
1462 appropriate amount of cells */
1463 if (!NO_AGGRESSIVE_NEWROW && pos == 0 && lastrow->ncells > 0
1464 && lastrow->cells[lastrow->ncells - 1].cLine != lineno) {
1465 int rc = Stbl_fakeFinishCellInTable(me, lastrow, lineno, 0);
1466
1467 if (rc < 0)
1468 return -1;
1469 if (rc)
1470 lastrow = me->rows + (me->nrows - 1);
1471 }
1472 }
1473 #endif
1474 if (colspan == 0) {
1475 colspan = get_remaining_colspan(lastrow, me->sumcols, me->ncolinfo,
1476 colspan, me->ncols);
1477 }
1478 ncells = lastrow->ncells; /* remember what it was before adding cell. */
1479 icell = Stbl_addCellToRow(lastrow, me->sumcols, me->ncolinfo, s,
1480 colspan, alignment, isheader,
1481 lineno, &pos);
1482 if (icell < 0)
1483 return icell;
1484 if (me->nrows == 1 && me->startline < lastrow->Line)
1485 me->startline = lastrow->Line;
1486
1487 if (rowspan != 1) {
1488 Stbl_reserveCellsInTable(me, icell, colspan, rowspan);
1489 /* me->rows may now have been realloc'd, make lastrow valid pointer */
1490 lastrow = me->rows + (me->nrows - 1);
1491 }
1492 lastrow->content |= HAS_BEG_OF_CELL;
1493
1494 {
1495 int growby = 0;
1496
1497 while (icell + colspan + 1 > me->allocated_sumcols + growby)
1498 growby += CELLS_GROWBY;
1499 if (growby) {
1500 if (me->allocated_sumcols == 0 && !me->sumcols) {
1501 sumcols = typecallocn(STable_cellinfo, (unsigned) growby);
1502 } else {
1503 sumcols = typeRealloc(STable_cellinfo, me->sumcols,
1504 (unsigned) (me->allocated_sumcols + growby));
1505
1506 for (i = 0; sumcols && i < growby; i++) {
1507 sumcol = sumcols + me->allocated_sumcols + i;
1508 sumcol->pos = sumcols[me->allocated_sumcols - 1].pos;
1509 sumcol->len = 0;
1510 sumcol->colspan = 0;
1511 sumcol->cLine = 0;
1512 sumcol->alignment = HT_ALIGN_NONE;
1513 }
1514 }
1515 if (sumcols) {
1516 me->allocated_sumcols += growby;
1517 me->sumcols = sumcols;
1518 } else {
1519 return -1;
1520 }
1521 }
1522 }
1523 if (icell + 1 > me->ncols) {
1524 me->ncols = icell + 1;
1525 }
1526 if (colspan > 1 && colspan + me->sumcols[icell + colspan].colspan > 0)
1527 me->sumcols[icell + colspan].colspan = -colspan;
1528 sumpos = pos;
1529 if (ncells > 0)
1530 sumpos += me->sumcols[ncells - 1].pos - lastrow->cells[ncells - 1].pos;
1531 update_sumcols0(me->sumcols, lastrow, sumpos,
1532 sumpos - ((ncells > 0)
1533 ? me->sumcols[icell].pos
1534 : me->sumcols[icell].pos),
1535 icell, 0, me->allocated_sumcols);
1536
1537 me->maxpos = me->sumcols[me->allocated_sumcols - 1].pos;
1538 if (me->maxpos > /* @@@ max. line length we can accept */ MAX_STBL_POS)
1539 return -1;
1540 return 0;
1541 }
1542
1543 /*
1544 * Returns -1 on error, otherwise 0.
1545 */
Stbl_finishCellInTable(STable_info * me,int end_td,int lineno,int offset,int pos)1546 int Stbl_finishCellInTable(STable_info *me, int end_td,
1547 int lineno,
1548 int offset,
1549 int pos)
1550 {
1551 STable_states *s = &me->s;
1552 STable_rowinfo *lastrow;
1553 int len, xlen, icell;
1554 int i;
1555
1556 CTRACE2(TRACE_TRST,
1557 (tfp,
1558 "TRST:Stbl_finishCellInTable(lineno=%d, pos=%d, off=%d, end_td=%d)\n",
1559 lineno, pos, offset, (int) end_td));
1560 if (me->nrows == 0)
1561 return -1;
1562 lastrow = me->rows + (me->nrows - 1);
1563 icell = lastrow->ncells - 1;
1564 if (icell < 0)
1565 return icell;
1566 if (s->x_td == -1) { /* Stray </TD> or just-in-case, as on </TR> */
1567 if ((end_td & TRST_ENDCELL_MASK) == TRST_ENDCELL_LINEBREAK)
1568 lastrow->ended = ROW_ended_by_splitline;
1569 return 0;
1570 }
1571 #ifdef EXP_NESTED_TABLES
1572 if (nested_tables) {
1573 if (!NO_AGGRESSIVE_NEWROW && !(end_td & TRST_FAKING_CELLS)) {
1574 int rc = Stbl_fakeFinishCellInTable(me, lastrow, lineno, 1);
1575
1576 if (rc) {
1577 if (rc < 0)
1578 return -1;
1579 lastrow = me->rows + (me->nrows - 1);
1580 icell = lastrow->ncells - 1;
1581 }
1582 }
1583 }
1584 #endif
1585 len = Stbl_finishCellInRow(lastrow, s, end_td, lineno, pos);
1586 if (len == -1)
1587 return len;
1588 xlen = (len > 0) ? len : s->pending_len; /* ##890 use xlen if fixed_line?: */
1589 if (lastrow->Line == lineno)
1590 len = xlen;
1591 if (lastrow->cells[icell].colspan > 1) {
1592 /*
1593 * @@@ This is all a too-complicated mess; do we need
1594 * sumcols len at all, or is pos enough??
1595 * Answer: sumcols len is at least used for center/right
1596 * alignment, and should probably continue to be used there;
1597 * all other uses are probably not necessary.
1598 */
1599 int spanlen = 0, spanlend = 0;
1600
1601 for (i = icell; i < icell + lastrow->cells[icell].colspan; i++) {
1602 if (me->sumcols[i].len > 0) {
1603 spanlen += me->sumcols[i].len;
1604 if (i > icell)
1605 spanlen++;
1606 }
1607 spanlend = HTMAX(spanlend,
1608 me->sumcols[i + 1].pos - me->sumcols[icell].pos);
1609 }
1610 if (spanlend)
1611 spanlend--;
1612 if (spanlend > spanlen)
1613 spanlen = spanlend;
1614 /* @@@ could overcount? */
1615 if (len > spanlen)
1616 me->maxlen += (len - spanlen);
1617 } else if (len > me->sumcols[icell].len) {
1618 if (me->sumcols[icell + 1].colspan >= -1)
1619 me->maxlen += (len - me->sumcols[icell].len);
1620 me->sumcols[icell].len = len;
1621 }
1622
1623 if (len > 0) {
1624 update_sumcols0(me->sumcols, lastrow, pos, len,
1625 icell, lastrow->cells[icell].colspan,
1626 me->allocated_sumcols);
1627 me->maxpos = me->sumcols[me->allocated_sumcols - 1].pos;
1628 }
1629
1630 if ((end_td & TRST_ENDCELL_MASK) == TRST_ENDCELL_LINEBREAK) {
1631 lastrow->ended = ROW_ended_by_splitline;
1632 lastrow->content |= BELIEVE_OFFSET;
1633 lastrow->offset = offset;
1634 }
1635 #ifdef EXP_NESTED_TABLES /* maxlen may already include contribution of a cell in this column */
1636 if (nested_tables) {
1637 if (me->maxlen > MAX_STBL_POS)
1638 return -1;
1639 } else
1640 #endif
1641 {
1642 if (me->maxlen + (xlen - len) > MAX_STBL_POS)
1643 return -1;
1644 }
1645 if (me->maxpos > /* @@@ max. line length we can accept */ MAX_STBL_POS)
1646 return -1;
1647
1648 if (lineno != lastrow->Line) {
1649 /* @@@ Do something here? Or is it taken care of in
1650 Stbl_finishCellInRow ? */
1651 }
1652
1653 return 0;
1654 }
1655
1656 /*
1657 * Returns -1 on error, otherwise 0.
1658 */
Stbl_addColInfo(STable_info * me,int colspan,int alignment,int isgroup)1659 int Stbl_addColInfo(STable_info *me,
1660 int colspan,
1661 int alignment,
1662 int isgroup)
1663 {
1664 STable_cellinfo *sumcols, *sumcol;
1665 int i, icolinfo;
1666
1667 CTRACE2(TRACE_TRST,
1668 (tfp, "TRST:Stbl_addColInfo(cs=%d, al=%d, isgroup=%d)\n",
1669 colspan, alignment, (int) isgroup));
1670 if (isgroup) {
1671 if (me->pending_colgroup_next > me->ncolinfo)
1672 me->ncolinfo = me->pending_colgroup_next;
1673 me->pending_colgroup_next = me->ncolinfo + colspan;
1674 if (me->ncolinfo > 0)
1675 me->sumcols[me->ncolinfo - 1].cLine = EOCOLG;
1676 me->pending_colgroup_align = (short) alignment;
1677 } else {
1678 for (i = me->pending_colgroup_next - 1;
1679 i >= me->ncolinfo + colspan; i--)
1680 me->sumcols[i].alignment = HT_ALIGN_NONE;
1681 me->pending_colgroup_next = me->ncolinfo + colspan;
1682 }
1683 icolinfo = me->ncolinfo;
1684 if (!isgroup)
1685 me->ncolinfo += colspan;
1686
1687 {
1688 int growby = 0;
1689
1690 while (icolinfo + colspan + 1 > me->allocated_sumcols + growby)
1691 growby += CELLS_GROWBY;
1692 if (growby) {
1693 if (me->allocated_sumcols == 0) {
1694 sumcols = typecallocn(STable_cellinfo, (unsigned) growby);
1695 } else {
1696 sumcols = typeRealloc(STable_cellinfo, me->sumcols,
1697 (unsigned) (me->allocated_sumcols + growby));
1698
1699 for (i = 0; sumcols && i < growby; i++) {
1700 sumcol = sumcols + me->allocated_sumcols + i;
1701 sumcol->pos = sumcols[me->allocated_sumcols - 1].pos;
1702 sumcol->len = 0;
1703 sumcol->colspan = 0;
1704 sumcol->cLine = 0;
1705 }
1706 }
1707 if (sumcols) {
1708 me->allocated_sumcols += growby;
1709 me->sumcols = sumcols;
1710 } else {
1711 return -1;
1712 }
1713 }
1714 }
1715
1716 if (alignment == HT_ALIGN_NONE)
1717 alignment = me->pending_colgroup_align;
1718 for (i = icolinfo; i < icolinfo + colspan; i++) {
1719 me->sumcols[i].alignment = alignment;
1720 }
1721 return 0;
1722 }
1723
1724 /*
1725 * Returns -1 on error, otherwise 0.
1726 */
Stbl_finishColGroup(STable_info * me)1727 int Stbl_finishColGroup(STable_info *me)
1728 {
1729 CTRACE2(TRACE_TRST, (tfp, "TRST:Stbl_finishColGroup()\n"));
1730 if (me->pending_colgroup_next >= me->ncolinfo) {
1731 me->ncolinfo = me->pending_colgroup_next;
1732 if (me->ncolinfo > 0)
1733 me->sumcols[me->ncolinfo - 1].cLine = EOCOLG;
1734 }
1735 me->pending_colgroup_next = 0;
1736 me->pending_colgroup_align = HT_ALIGN_NONE;
1737 return 0;
1738 }
1739
Stbl_addRowGroup(STable_info * me,int alignment)1740 int Stbl_addRowGroup(STable_info *me, int alignment)
1741 {
1742 CTRACE2(TRACE_TRST, (tfp, "TRST:Stbl_addRowGroup()\n"));
1743 Stbl_cancelRowSpans(me);
1744 me->rowgroup_align = (short) alignment;
1745 return 0; /* that's all! */
1746 }
1747
Stbl_finishTABLE(STable_info * me)1748 int Stbl_finishTABLE(STable_info *me)
1749 {
1750 STable_states *s = &me->s;
1751 int i;
1752 int curpos = 0;
1753
1754 CTRACE2(TRACE_TRST, (tfp, "TRST:Stbl_finishTABLE()\n"));
1755 if (!me || me->nrows <= 0 || me->ncols <= 0) {
1756 return -1;
1757 }
1758 if (me->nrows > 0 && me->rows[me->nrows - 1].ncells > 0) {
1759 if (s->pending_len > 0)
1760 me->rows[me->nrows - 1].cells[
1761 me->rows[me->nrows - 1].ncells - 1
1762 ].len = s->pending_len;
1763 s->pending_len = 0;
1764 }
1765 Stbl_finishRowInTable(me);
1766 /* take into account offsets on multi-line cells.
1767 XXX We cannot do it honestly, since two cells on the same row may
1768 participate in multi-line table entries, and we preserve only
1769 one offset per row. This implementation may ignore
1770 horizontal offsets for the last row of a multirow table entry. */
1771 for (i = 0; i < me->nrows - 1; i++) {
1772 int j = i + 1, leading = i, non_empty = 0;
1773 STable_rowinfo *nextrow = me->rows + j;
1774 int minoffset, have_offsets;
1775 int foundcell = -1, max_width;
1776
1777 if ((nextrow->content & (IS_CONTINUATION_OF_CELL | HAS_BEG_OF_CELL | BELIEVE_OFFSET))
1778 != (IS_CONTINUATION_OF_CELL | BELIEVE_OFFSET))
1779 continue; /* Not a continuation line */
1780 minoffset = nextrow[-1].offset; /* Line before first continuation */
1781 CTRACE2(TRACE_TRST, (tfp,
1782 "TRST:Stbl_finishTABLE, l=%d, offset=%d, ended=%u.\n",
1783 i, nextrow[-1].offset, nextrow[-1].ended));
1784
1785 /* Find the common part of the requested offsets */
1786 while (j < me->nrows
1787 && ((nextrow->content &
1788 (IS_CONTINUATION_OF_CELL
1789 | HAS_BEG_OF_CELL
1790 | BELIEVE_OFFSET))
1791 == (IS_CONTINUATION_OF_CELL | BELIEVE_OFFSET))) {
1792 if (minoffset > nextrow->offset)
1793 minoffset = nextrow->offset;
1794 CTRACE2(TRACE_TRST,
1795 (tfp,
1796 "TRST:Stbl_finishTABLE, l=%d, offset=%d, ended=%u.\n",
1797 j, nextrow->offset, nextrow[-1].ended));
1798 nextrow++;
1799 j++;
1800 }
1801 i = j - 1; /* Continue after this line */
1802 /* Cancel the common part of offsets */
1803 j = leading; /* Restart */
1804 nextrow = me->rows + j; /* Line before first continuation */
1805 have_offsets = 0;
1806 nextrow->content |= OFFSET_IS_VALID_LAST_CELL;
1807 while (j <= i) { /* A continuation line */
1808 nextrow->offset -= minoffset;
1809 nextrow->content |= OFFSET_IS_VALID;
1810 if (nextrow->offset)
1811 have_offsets = 1;
1812 nextrow++;
1813 j++;
1814 }
1815 if (!have_offsets)
1816 continue; /* No offsets to deal with */
1817
1818 /* Find the cell number */
1819 foundcell = -1;
1820 j = leading + 1; /* Restart */
1821 nextrow = me->rows + j; /* First continuation line */
1822 while (foundcell == -1 && j <= i) { /* A continuation line */
1823 int curcell = -1;
1824
1825 while (foundcell == -1 && ++curcell < nextrow->ncells)
1826 if (nextrow->cells[curcell].len)
1827 foundcell = curcell, non_empty = j;
1828 nextrow++;
1829 j++;
1830 }
1831 if (foundcell == -1) /* Can it happen? */
1832 continue;
1833 /* Find the max width */
1834 max_width = 0;
1835 j = leading; /* Restart */
1836 nextrow = me->rows + j; /* Include the pre-continuation line */
1837 while (j <= i) { /* A continuation line */
1838 if (nextrow->ncells > foundcell) {
1839 int curwid = nextrow->cells[foundcell].len + nextrow->offset;
1840
1841 if (curwid > max_width)
1842 max_width = curwid;
1843 }
1844 nextrow++;
1845 j++;
1846 }
1847 /* Update the widths */
1848 j = non_empty; /* Restart from the first nonempty */
1849 nextrow = me->rows + j;
1850 /* Register the increase of the width */
1851 update_sumcols0(me->sumcols, me->rows + non_empty,
1852 0 /* width only */ , max_width,
1853 foundcell, nextrow->cells[foundcell].colspan,
1854 me->allocated_sumcols);
1855 j = leading; /* Restart from pre-continuation */
1856 nextrow = me->rows + j;
1857 while (j <= i) { /* A continuation line */
1858 if (nextrow->ncells > foundcell)
1859 nextrow->cells[foundcell].len = max_width;
1860 nextrow++;
1861 j++;
1862 }
1863 } /* END of Offsets processing */
1864
1865 for (i = 0; i < me->ncols; i++) {
1866 if (me->sumcols[i].pos < curpos) {
1867 me->sumcols[i].pos = curpos;
1868 } else {
1869 curpos = me->sumcols[i].pos;
1870 }
1871 if (me->sumcols[i].len > 0) {
1872 curpos += me->sumcols[i].len;
1873 }
1874 }
1875 /* need to recheck curpos: though it is checked each time a cell
1876 is added, sometimes the result is ignored, as in split_line(). */
1877 return (curpos > MAX_STBL_POS ? -1 : me->ncols);
1878 }
1879
Stbl_getAlignment(STable_info * me)1880 short Stbl_getAlignment(STable_info *me)
1881 {
1882 return (short) (me ? me->alignment : HT_ALIGN_NONE);
1883 }
1884
get_fixup_positions(STable_rowinfo * me,int * oldpos,int * newpos,STable_cellinfo * sumcols)1885 static int get_fixup_positions(STable_rowinfo *me, int *oldpos,
1886 int *newpos,
1887 STable_cellinfo *sumcols)
1888 {
1889 int i = 0, ip = 0;
1890 int next_i, newlen;
1891 int ninserts;
1892
1893 if (!me)
1894 return -1;
1895 while (i < me->ncells) {
1896 int offset;
1897
1898 next_i = i + HTMAX(1, me->cells[i].colspan);
1899 if (me->cells[i].cLine != me->Line) {
1900 if (me->cells[i].cLine > me->Line)
1901 break;
1902 i = next_i;
1903 continue;
1904 }
1905 oldpos[ip] = me->cells[i].pos;
1906 if ((me->content & OFFSET_IS_VALID)
1907 && (i == me->ncells - 1
1908 || !((me->content & OFFSET_IS_VALID_LAST_CELL))))
1909 offset = me->offset;
1910 else
1911 offset = 0;
1912 newpos[ip] = sumcols[i].pos + offset;
1913 if ((me->cells[i].alignment == HT_CENTER ||
1914 me->cells[i].alignment == HT_RIGHT) &&
1915 me->cells[i].len > 0) {
1916 newlen = sumcols[next_i].pos - newpos[ip] - 1;
1917 newlen = HTMAX(newlen, sumcols[i].len);
1918 if (me->cells[i].len < newlen) {
1919 if (me->cells[i].alignment == HT_RIGHT) {
1920 newpos[ip] += newlen - me->cells[i].len;
1921 } else {
1922 newpos[ip] += (newlen - me->cells[i].len) / 2;
1923 }
1924 }
1925 }
1926 ip++;
1927 i = next_i;
1928 }
1929 ninserts = ip;
1930 return ninserts;
1931 }
1932
1933 /*
1934 * Returns -1 if we have no row for this lineno, or for other error,
1935 * 0 or greater (number of oldpos/newpos pairs) if we have
1936 * a table row.
1937 */
Stbl_getFixupPositions(STable_info * me,int lineno,int * oldpos,int * newpos)1938 int Stbl_getFixupPositions(STable_info *me, int lineno,
1939 int *oldpos,
1940 int *newpos)
1941 {
1942 STable_rowinfo *row;
1943 int j;
1944 int ninserts = -1;
1945
1946 if (!me || !me->nrows)
1947 return -1;
1948 for (j = 0; j < me->nrows; j++) {
1949 row = me->rows + j;
1950 if (row->Line == lineno) {
1951 ninserts = get_fixup_positions(row, oldpos, newpos,
1952 me->sumcols);
1953 break;
1954 }
1955 }
1956 return ninserts;
1957 }
1958
Stbl_getStartLine(STable_info * me)1959 int Stbl_getStartLine(STable_info *me)
1960 {
1961 if (!me)
1962 return -1;
1963 else
1964 return me->startline;
1965 }
1966
1967 #ifdef EXP_NESTED_TABLES
1968
Stbl_getStartLineDeep(STable_info * me)1969 int Stbl_getStartLineDeep(STable_info *me)
1970 {
1971 if (!me)
1972 return -1;
1973 while (me->enclosing)
1974 me = me->enclosing;
1975 return me->startline;
1976 }
1977
Stbl_update_enclosing(STable_info * me,int max_width,int last_lineno)1978 void Stbl_update_enclosing(STable_info *me, int max_width,
1979 int last_lineno)
1980 {
1981 int l;
1982
1983 if (!me || !me->enclosing || !max_width)
1984 return;
1985 CTRACE2(TRACE_TRST,
1986 (tfp, "TRST:Stbl_update_enclosing, width=%d, lines=%d...%d.\n",
1987 max_width, me->startline, last_lineno));
1988 for (l = me->startline; l <= last_lineno; l++) {
1989 /* Fake <BR> in appropriate positions */
1990 if (Stbl_finishCellInTable(me->enclosing,
1991 TRST_ENDCELL_LINEBREAK,
1992 l,
1993 0,
1994 max_width) < 0) {
1995 /* It is not handy to let the caller delete me->enclosing,
1996 and it does not buy us anything. Do it directly. */
1997 STable_info *stbl = me->enclosing;
1998
1999 CTRACE2(TRACE_TRST, (tfp,
2000 "TRST:Stbl_update_enclosing: width too large, aborting enclosing\n"));
2001 me->enclosing = 0;
2002 while (stbl) {
2003 STable_info *enclosing = stbl->enclosing;
2004
2005 Stbl_free(stbl);
2006 stbl = enclosing;
2007 }
2008 break;
2009 }
2010 }
2011 return;
2012 }
2013
Stbl_set_enclosing(STable_info * me,STable_info * enclosing,struct _TextAnchor * enclosing_last_anchor_before_stbl)2014 void Stbl_set_enclosing(STable_info *me, STable_info *enclosing, struct _TextAnchor *enclosing_last_anchor_before_stbl)
2015 {
2016 if (!me)
2017 return;
2018 me->enclosing = enclosing;
2019 me->enclosing_last_anchor_before_stbl = enclosing_last_anchor_before_stbl;
2020 }
2021
Stbl_get_enclosing(STable_info * me)2022 STable_info *Stbl_get_enclosing(STable_info *me)
2023 {
2024 if (!me)
2025 return 0;
2026 return me->enclosing;
2027 }
2028
Stbl_get_last_anchor_before(STable_info * me)2029 struct _TextAnchor *Stbl_get_last_anchor_before(STable_info *me)
2030 {
2031 if (!me)
2032 return 0;
2033 return me->enclosing_last_anchor_before_stbl;
2034 }
2035 #endif
2036