~ubuntu-branches/ubuntu/warty/lynx/warty-security

« back to all changes in this revision

Viewing changes to src/TRSTable.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2004-09-16 12:14:10 UTC
  • Revision ID: james.westby@ubuntu.com-20040916121410-cz1gu92c4nqfeyrg
Tags: upstream-2.8.5
ImportĀ upstreamĀ versionĀ 2.8.5

Show diffs side-by-side

added added

removed removed

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