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