~ubuntu-branches/debian/squeeze/links2/squeeze

« back to all changes in this revision

Viewing changes to .pc/CVE-2013-6050.diff/html_tbl.c

  • Committer: Package Import Robot
  • Author(s): Axel Beckert
  • Date: 2013-11-28 16:42:44 UTC
  • Revision ID: package-import@ubuntu.com-20131128164244-0ax8l7jnpraecyxu
Tags: 2.3~pre1-1+squeeze2
Add patch against integer overflow in graphics mode (CVE-2013-6050)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* html_tbl.c
 
2
 * Tables in HTML
 
3
 * (c) 2002 Mikulas Patocka
 
4
 * This file is a part of the Links program, released under GPL.
 
5
 */
 
6
 
 
7
#include "links.h"
 
8
 
 
9
#define format format_
 
10
 
 
11
#ifdef DEBUG
 
12
#undef DEBUG
 
13
#endif
 
14
 
 
15
/*#define DEBUG*/
 
16
 
 
17
#define RECT_BOUND_BITS 10      /* --- bound at 1024 pixels */
 
18
 
 
19
#define AL_TR           -1
 
20
 
 
21
#define VAL_TR          -1
 
22
#define VAL_TOP         0
 
23
#define VAL_MIDDLE      1
 
24
#define VAL_BOTTOM      2
 
25
 
 
26
#define W_AUTO          -1
 
27
#define W_REL           -2
 
28
 
 
29
#define F_VOID          0
 
30
#define F_ABOVE         1
 
31
#define F_BELOW         2
 
32
#define F_HSIDES        3
 
33
#define F_LHS           4
 
34
#define F_RHS           8
 
35
#define F_VSIDES        12
 
36
#define F_BOX           15
 
37
 
 
38
#define R_NONE          0
 
39
#define R_ROWS          1
 
40
#define R_COLS          2
 
41
#define R_ALL           3
 
42
#define R_GROUPS        4
 
43
 
 
44
void get_align(char *, int *);
 
45
void get_valign(char *, int *);
 
46
void get_c_width(char *, int *, int);
 
47
 
 
48
void get_align(char *attr, int *a)
 
49
{
 
50
        char *al;
 
51
        if ((al = get_attr_val(attr, "align"))) {
 
52
                if (!(strcasecmp(al, "left"))) *a = AL_LEFT;
 
53
                if (!(strcasecmp(al, "right"))) *a = AL_RIGHT;
 
54
                if (!(strcasecmp(al, "center"))) *a = AL_CENTER;
 
55
                if (!(strcasecmp(al, "justify"))) *a = AL_BLOCK;
 
56
                if (!(strcasecmp(al, "char"))) *a = AL_RIGHT; /* NOT IMPLEMENTED */
 
57
                mem_free(al);
 
58
        }
 
59
}
 
60
 
 
61
void get_valign(char *attr, int *a)
 
62
{
 
63
        char *al;
 
64
        if ((al = get_attr_val(attr, "valign"))) {
 
65
                if (!(strcasecmp(al, "top"))) *a = VAL_TOP;
 
66
                if (!(strcasecmp(al, "middle"))) *a = VAL_MIDDLE;
 
67
                if (!(strcasecmp(al, "bottom"))) *a = VAL_BOTTOM;
 
68
                if (!(strcasecmp(al, "baseline"))) *a = VAL_TOP; /* NOT IMPLEMENTED */
 
69
                mem_free(al);
 
70
        }
 
71
}
 
72
 
 
73
void get_c_width(char *attr, int *w, int sh)
 
74
{
 
75
        char *al;
 
76
        if ((al = get_attr_val(attr, "width"))) {
 
77
                if (*al && al[strlen(al) - 1] == '*') {
 
78
                        char *en;
 
79
                        unsigned long n;
 
80
                        al[strlen(al) - 1] = 0;
 
81
                        n = strtoul(al, &en, 10);
 
82
                        if (n < 10000 && !*en) *w = W_REL - n;
 
83
                } else {
 
84
                        int p = get_width(attr, "width", sh);
 
85
                        if (p >= 0) *w = p;
 
86
                }
 
87
                mem_free(al);
 
88
        }
 
89
}
 
90
 
 
91
#define INIT_X          8
 
92
#define INIT_Y          8
 
93
 
 
94
struct table_cell {
 
95
        int used;
 
96
        int spanned;
 
97
        int mx, my;
 
98
        unsigned char *start;
 
99
        unsigned char *end;
 
100
        int align;
 
101
        int valign;
 
102
        int b;
 
103
        struct rgb bgcolor;
 
104
        int group;
 
105
        int colspan;
 
106
        int rowspan;
 
107
        int min_width;
 
108
        int max_width;
 
109
        int x_width;
 
110
        int height;
 
111
        int xpos, ypos, xw, yw;
 
112
        int link_num;
 
113
#ifdef G
 
114
        unsigned char bgcolor_str[8];
 
115
        struct g_object_area *root;
 
116
        struct rect_set *brd;
 
117
        int g_width;
 
118
        struct rect rect;
 
119
        int dgen;
 
120
#endif
 
121
};
 
122
 
 
123
struct table_column {
 
124
        int group;
 
125
        int align;
 
126
        int valign;
 
127
        int width;
 
128
};
 
129
 
 
130
struct table {
 
131
        struct part *p;
 
132
#ifdef G
 
133
        struct g_part *gp;
 
134
#endif
 
135
        int x, y;
 
136
        int rx, ry;
 
137
        int align;
 
138
        int border, cellpd, vcellpd, cellsp;
 
139
        int frame, rules, width, wf;
 
140
        unsigned char *bordercolor;
 
141
        int *min_c, *max_c;
 
142
        int *w_c;
 
143
        int rw;
 
144
        int min_t, max_t;
 
145
        struct table_cell *cells;
 
146
        int c, rc;
 
147
        struct table_column *cols;
 
148
        int xc;
 
149
        int *xcols;
 
150
        int *r_heights;
 
151
        int rh;
 
152
        int link_num;
 
153
        struct rgb bgcolor;
 
154
#ifdef G
 
155
        struct background *bg;
 
156
        struct background *frame_bg;
 
157
        struct rect_set **r_bg;
 
158
        int nr_bg;
 
159
        struct rect_set **r_frame;
 
160
        int nr_frame;
 
161
        struct table_cell ***r_cells;
 
162
        int *w_cells;
 
163
        int nr_cells;
 
164
#endif
 
165
};
 
166
 
 
167
/* prototype */
 
168
void free_table(struct table *);
 
169
void expand_cells(struct table *, int, int);
 
170
struct table_cell *new_cell(struct table *, int, int);
 
171
void new_columns(struct table *, int, int, int, int, int);
 
172
void set_td_width(struct table *, int, int, int);
 
173
void get_cell_widths(struct table *);
 
174
void dst_width(int *, int, int, int *);
 
175
int get_vline_width(struct table *, int);
 
176
int get_hline_width(struct table *, int);
 
177
int g_get_vline_pad(struct table *, int, int *, int *);
 
178
int g_get_hline_pad(struct table *, int, int *, int *);
 
179
int get_column_widths(struct table *);
 
180
void get_table_width(struct table *);
 
181
void distribute_widths(struct table *, int);
 
182
void check_table_widths(struct table *);
 
183
void get_table_heights(struct table *);
 
184
void display_complicated_table(struct table *, int, int, int *);
 
185
void get_table_frame(struct table *, signed char *, signed char *);
 
186
void display_table_frames(struct table *, int, int);
 
187
#ifdef G
 
188
void add_to_rect_sets(struct rect_set ***, int *, struct rect *);
 
189
void add_to_cell_sets(struct table_cell ****, int **, int *, struct rect *, struct table_cell *);
 
190
void table_mouse_event(struct f_data_c *, struct g_object_table *, int, int, int);
 
191
void draw_rect_set(struct graphics_device *, struct background *, struct rect_set *, int, int);
 
192
void draw_rect_sets(struct graphics_device *, struct background *, struct rect_set **, int, int, int);
 
193
void table_draw(struct f_data_c *, struct g_object_table *, int, int);
 
194
void table_destruct(struct g_object_table *);
 
195
void table_get_list(struct g_object_table *, void (*)(struct g_object *, struct g_object *));
 
196
#endif
 
197
struct table *new_table(void);
 
198
 
 
199
void get_cell_width(char *, char *, int, int, int, int *, int *, int, int *, unsigned char *);
 
200
 
 
201
 
 
202
#ifdef DEBUG
 
203
#define CELL(t, x, y) (((x) < 0 || (x) >= (t)->rx || (y) < 0 || (y) >= (t)->ry) ? (internal("accessing cell out of table (%d,%d) - limit (%d,%d)", (x), (y), (t)->rx, (t)->ry), (t)->cells) : &(t)->cells[(y) * (t)->rx + (x)])
 
204
#else
 
205
#define CELL(t, x, y) (&(t)->cells[(y) * (t)->rx + (x)])
 
206
#endif
 
207
 
 
208
unsigned char frame_table[81] = {
 
209
        0x00, 0xb3, 0xba,       0xc4, 0xc0, 0xd3,       0xcd, 0xd4, 0xc8,
 
210
        0xc4, 0xd9, 0xbd,       0xc4, 0xc1, 0xd0,       0xcd, 0xd4, 0xc8,
 
211
        0xcd, 0xbe, 0xbc,       0xcd, 0xbe, 0xbc,       0xcd, 0xcf, 0xca,
 
212
 
 
213
        0xb3, 0xb3, 0xba,       0xda, 0xc3, 0xd3,       0xd5, 0xc6, 0xc8,
 
214
        0xbf, 0xb4, 0xbd,       0xc2, 0xc5, 0xd0,       0xd5, 0xc6, 0xc8,
 
215
        0xb8, 0xb5, 0xbc,       0xb8, 0xb5, 0xbc,       0xd1, 0xd8, 0xca,
 
216
 
 
217
        0xba, 0xba, 0xba,       0xd6, 0xd6, 0xc7,       0xc9, 0xc9, 0xcc,
 
218
        0xb7, 0xb7, 0xb6,       0xd2, 0xd2, 0xd7,       0xc9, 0xc9, 0xcc,
 
219
        0xbb, 0xbb, 0xb9,       0xbb, 0xbb, 0xb9,       0xcb, 0xcb, 0xce,
 
220
};
 
221
 
 
222
unsigned char hline_table[3] = { 0x20, 0xc4, 0xcd };
 
223
unsigned char vline_table[3] = { 0x20, 0xb3, 0xba };
 
224
 
 
225
struct table *new_table(void)
 
226
{
 
227
        struct table *t;
 
228
        t = mem_calloc(sizeof(struct table));
 
229
        t->p = NULL;
 
230
#ifdef G
 
231
        t->gp = NULL;
 
232
        t->r_frame = DUMMY;
 
233
        t->nr_frame = 0;
 
234
        t->r_bg = DUMMY;
 
235
        t->nr_bg = 0;
 
236
        t->r_cells = DUMMY;
 
237
        t->w_cells = DUMMY;
 
238
        t->nr_cells = 0;
 
239
#endif
 
240
        t->x = t->y = 0;
 
241
        t->rx = INIT_X;
 
242
        t->ry = INIT_Y;
 
243
        t->cells = mem_calloc(INIT_X * INIT_Y * sizeof(struct table_cell));
 
244
        t->c = 0;
 
245
        t->rc = INIT_X;
 
246
        t->cols = mem_calloc(INIT_X * sizeof(struct table_column));
 
247
        t->xcols = DUMMY;
 
248
        t->xc = 0;
 
249
        t->r_heights = DUMMY;
 
250
        return t;
 
251
}
 
252
 
 
253
void free_table(struct table *t)
 
254
{
 
255
#ifdef G
 
256
        if (F) {
 
257
                int i, j;
 
258
                for (j = 0; j < t->y; j++) for (i = 0; i < t->x; i++) {
 
259
                        struct table_cell *c = CELL(t, i, j);
 
260
                        if (c->root) c->root->destruct(c->root);
 
261
                        if (c->brd) mem_free(c->brd);
 
262
                }
 
263
                for (i = 0; i < t->nr_frame; i++) mem_free(t->r_frame[i]);
 
264
                if (t->r_frame) mem_free(t->r_frame);
 
265
                for (i = 0; i < t->nr_bg; i++) mem_free(t->r_bg[i]);
 
266
                if (t->r_bg) mem_free(t->r_bg);
 
267
                for (i = 0; i < t->nr_cells; i++) mem_free(t->r_cells[i]);
 
268
                mem_free(t->r_cells), mem_free(t->w_cells);
 
269
                if (t->frame_bg) g_release_background(t->frame_bg);
 
270
        }
 
271
#endif
 
272
        if (t->bordercolor) mem_free(t->bordercolor);
 
273
        if (t->min_c) mem_free(t->min_c);
 
274
        if (t->max_c) mem_free(t->max_c);
 
275
        if (t->w_c) mem_free(t->w_c);
 
276
        mem_free(t->r_heights);
 
277
        mem_free(t->cols);
 
278
        mem_free(t->xcols);
 
279
        mem_free(t->cells);
 
280
        mem_free(t);
 
281
}
 
282
 
 
283
void expand_cells(struct table *t, int x, int y)
 
284
{
 
285
        int i, j;
 
286
        if (x >= t->x) {
 
287
                if (t->x) {
 
288
                        for (i = 0; i < t->y; i++) if (CELL(t, t->x - 1, i)->colspan == -1) {
 
289
                                for (j = t->x; j <= x; j++) {
 
290
                                        CELL(t, j, i)->used = 1;
 
291
                                        CELL(t, j, i)->spanned = 1;
 
292
                                        CELL(t, j, i)->rowspan = CELL(t, t->x - 1, i)->rowspan;
 
293
                                        CELL(t, j, i)->colspan = -1;
 
294
                                        CELL(t, j, i)->mx = CELL(t, t->x - 1, i)->mx;
 
295
                                        CELL(t, j, i)->my = CELL(t, t->x - 1, i)->my;
 
296
                                }
 
297
                        }
 
298
                }
 
299
                t->x = x + 1;
 
300
        }
 
301
        if (y >= t->y) {
 
302
                if (t->y) {
 
303
                        for (i = 0; i < t->x; i++) if (CELL(t, i, t->y - 1)->rowspan == -1) {
 
304
                                for (j = t->y; j <= y; j++) {
 
305
                                        CELL(t, i, j)->used = 1;
 
306
                                        CELL(t, i, j)->spanned = 1;
 
307
                                        CELL(t, i, j)->rowspan = -1;
 
308
                                        CELL(t, i, j)->colspan = CELL(t, i, t->y - 1)->colspan;
 
309
                                        CELL(t, i, j)->mx = CELL(t, i, t->y - 1)->mx;
 
310
                                        CELL(t, i, j)->my = CELL(t, i, t->y - 1)->my;
 
311
                                }
 
312
                        }
 
313
                }
 
314
                t->y = y + 1;
 
315
        }
 
316
}
 
317
 
 
318
struct table_cell *new_cell(struct table *t, int x, int y)
 
319
{
 
320
        struct table nt;
 
321
        int i, j;
 
322
        if (x < t->x && y < t->y) goto ret;
 
323
        rep:
 
324
        if (x < t->rx && y < t->ry) {
 
325
                expand_cells(t, x, y);
 
326
                goto ret;
 
327
        }
 
328
        nt.rx = t->rx;
 
329
        nt.ry = t->ry;
 
330
        while (x >= nt.rx) {
 
331
                if ((unsigned)nt.rx > MAXINT / 2) overalloc();
 
332
                nt.rx *= 2;
 
333
        }
 
334
        while (y >= nt.ry) {
 
335
                if ((unsigned)nt.ry > MAXINT / 2) overalloc();
 
336
                nt.ry *= 2;
 
337
        }
 
338
        if ((unsigned)nt.rx * (unsigned)nt.ry / (unsigned)nt.rx != (unsigned)nt.ry) overalloc();
 
339
        if ((unsigned)nt.rx * (unsigned)nt.ry > MAXINT / sizeof(struct table_cell)) overalloc();
 
340
        nt.cells = mem_calloc(nt.rx * nt.ry * sizeof(struct table_cell));
 
341
        for (i = 0; i < t->x; i++)
 
342
                for (j = 0; j < t->y; j++)
 
343
                        memcpy(CELL(&nt, i, j), CELL(t, i, j), sizeof(struct table_cell));
 
344
        mem_free(t->cells);
 
345
        t->cells = nt.cells;
 
346
        t->rx = nt.rx;
 
347
        t->ry = nt.ry;
 
348
        goto rep;
 
349
 
 
350
        ret:
 
351
        return CELL(t, x, y);
 
352
}
 
353
 
 
354
void new_columns(struct table *t, int span, int width, int align, int valign, int group)
 
355
{
 
356
        if ((unsigned)t->c + (unsigned)span > MAXINT) overalloc();
 
357
        if (t->c + span > t->rc) {
 
358
                int n = t->rc;
 
359
                struct table_column *nc;
 
360
                while (t->c + span > n) {
 
361
                        if ((unsigned)n > MAXINT / 2) overalloc();
 
362
                        n *= 2;
 
363
                }
 
364
                if ((unsigned)n > MAXINT / sizeof(struct table_column)) overalloc();
 
365
                nc = mem_realloc(t->cols, n * sizeof(struct table_column));
 
366
                t->rc = n;
 
367
                t->cols = nc;
 
368
        }
 
369
        while (span--) {
 
370
                t->cols[t->c].align = align;
 
371
                t->cols[t->c].valign = valign;
 
372
                t->cols[t->c].width = width;
 
373
                t->cols[t->c++].group = group;
 
374
                group = 0;
 
375
        }
 
376
}
 
377
 
 
378
void set_td_width(struct table *t, int x, int width, int f)
 
379
{
 
380
        if (x >= t->xc) {
 
381
                int n = t->xc ? t->xc : 1;
 
382
                int i;
 
383
                int *nc;
 
384
                while (x >= n) {
 
385
                        if ((unsigned)n > MAXINT / 2) overalloc();
 
386
                        n *= 2;
 
387
                }
 
388
                if ((unsigned)n > MAXINT / sizeof(int)) overalloc();
 
389
                nc = mem_realloc(t->xcols, n * sizeof(int));
 
390
                for (i = t->xc; i < n; i++) nc[i] = W_AUTO;
 
391
                t->xc = n;
 
392
                t->xcols = nc;
 
393
        }
 
394
        if (t->xcols[x] == W_AUTO || f) {
 
395
                set:
 
396
                t->xcols[x] = width;
 
397
                return;
 
398
        }
 
399
        if (width == W_AUTO) return;
 
400
        if (width < 0 && t->xcols[x] >= 0) goto set;
 
401
        if (width >= 0 && t->xcols[x] < 0) return;
 
402
        t->xcols[x] = (t->xcols[x] + width) / 2;
 
403
}
 
404
 
 
405
unsigned char *skip_element(unsigned char *html, unsigned char *eof, unsigned char *what, int sub)
 
406
{
 
407
        int l = strlen(what);
 
408
        int level = 1;
 
409
        unsigned char *name;
 
410
        int namelen;
 
411
        r:
 
412
        while (html < eof && (*html != '<')) rr:html++;
 
413
        if (html + 2 <= eof && (html[1] == '!' || html[1] == '?')) {
 
414
                html = skip_comment(html, eof);
 
415
                goto r;
 
416
        }
 
417
        if (html >= eof) return eof;
 
418
        if (parse_element(html, eof, &name, &namelen, NULL, &html)) goto rr;
 
419
        if (namelen == l && !casecmp(name, what, l) && sub) level++;
 
420
        if (namelen == l + 1 && name[0] == '/' && !casecmp(name + 1, what, l)) if (!--level) return html;
 
421
        goto r;
 
422
}
 
423
 
 
424
struct s_e {
 
425
        unsigned char *s, *e;
 
426
};
 
427
 
 
428
struct table *parse_table(unsigned char *, unsigned char *, unsigned char **, struct rgb *, int, struct s_e **, int *);  /* prototype */
 
429
 
 
430
struct table *parse_table(unsigned char *html, unsigned char *eof, unsigned char **end, struct rgb *bgcolor, int sh, struct s_e **bad_html, int *bhp)
 
431
{
 
432
        int qqq;
 
433
        struct table *t;
 
434
        struct table_cell *cell;
 
435
        unsigned char *t_name, *t_attr, *en;
 
436
        int t_namelen;
 
437
        int x = 0, y = -1;
 
438
        int p = 0;
 
439
        unsigned char *lbhp = NULL;
 
440
        int l_al = AL_LEFT;
 
441
        int l_val = VAL_MIDDLE;
 
442
        int csp, rsp;
 
443
        int group = 0;
 
444
        int i, j, k;
 
445
        struct rgb l_col;
 
446
        int c_al = AL_TR, c_val = VAL_TR, c_width = W_AUTO, c_span = 0;
 
447
        memcpy(&l_col, bgcolor, sizeof(struct rgb));
 
448
        *end = html;
 
449
        if (bad_html) {
 
450
                *bad_html = DUMMY;
 
451
                *bhp = 0;
 
452
        }
 
453
        if (!(t = new_table())) return NULL;
 
454
        memcpy(&t->bgcolor, bgcolor, sizeof(struct rgb));
 
455
        se:
 
456
        en = html;
 
457
        see:
 
458
        html = en;
 
459
        if (bad_html && !p && !lbhp) {
 
460
                if (!(*bhp & (ALLOC_GR-1))) {
 
461
                        if ((unsigned)*bhp > MAXINT / sizeof(struct s_e) - ALLOC_GR) overalloc();
 
462
                        *bad_html = mem_realloc(*bad_html, (*bhp + ALLOC_GR) * sizeof(struct s_e));
 
463
                }
 
464
                lbhp = (*bad_html)[(*bhp)++].s = html;
 
465
        }
 
466
        while (html < eof && *html != '<') html++;
 
467
        if (html >= eof) {
 
468
                if (p) CELL(t, x, y)->end = html;
 
469
                if (lbhp) (*bad_html)[*bhp-1].e = html;
 
470
                goto scan_done;
 
471
        }
 
472
        if (html + 2 <= eof && (html[1] == '!' || html[1] == '?')) {
 
473
                html = skip_comment(html, eof);
 
474
                goto se;
 
475
        }
 
476
        if (parse_element(html, eof, &t_name, &t_namelen, &t_attr, &en)) {
 
477
                html++;
 
478
                goto se;
 
479
        }
 
480
        if (t_namelen == 5 && !casecmp(t_name, "TABLE", 5)) {
 
481
                en = skip_element(en, eof, "TABLE", 1);
 
482
                goto see;
 
483
        }
 
484
        if (t_namelen == 6 && !casecmp(t_name, "SCRIPT", 5)) {
 
485
                en = skip_element(en, eof, "SCRIPT", 0);
 
486
                goto see;
 
487
        }
 
488
        if (t_namelen == 6 && !casecmp(t_name, "/TABLE", 6)) {
 
489
                if (c_span) new_columns(t, c_span, c_width, c_al, c_val, 1);
 
490
                if (p) CELL(t, x, y)->end = html;
 
491
                if (lbhp) (*bad_html)[*bhp-1].e = html;
 
492
                goto scan_done;
 
493
        }
 
494
        if (t_namelen == 8 && !casecmp(t_name, "COLGROUP", 8)) {
 
495
                if (c_span) new_columns(t, c_span, c_width, c_al, c_val, 1);
 
496
                if (lbhp) (*bad_html)[*bhp-1].e = html, lbhp = NULL;
 
497
                c_al = AL_TR;
 
498
                c_val = VAL_TR;
 
499
                c_width = W_AUTO;
 
500
                get_align(t_attr, &c_al);
 
501
                get_valign(t_attr, &c_val);
 
502
                get_c_width(t_attr, &c_width, sh);
 
503
                if ((c_span = get_num(t_attr, "span")) == -1) c_span = 1;
 
504
                goto see;
 
505
        }
 
506
        if (t_namelen == 9 && !casecmp(t_name, "/COLGROUP", 9)) {
 
507
                if (c_span) new_columns(t, c_span, c_width, c_al, c_val, 1);
 
508
                if (lbhp) (*bad_html)[*bhp-1].e = html, lbhp = NULL;
 
509
                c_span = 0;
 
510
                c_al = AL_TR;
 
511
                c_val = VAL_TR;
 
512
                c_width = W_AUTO;
 
513
                goto see;
 
514
        }
 
515
        if (t_namelen == 3 && !casecmp(t_name, "COL", 3)) {
 
516
                int sp, wi, al, val;
 
517
                if (lbhp) (*bad_html)[*bhp-1].e = html, lbhp = NULL;
 
518
                if ((sp = get_num(t_attr, "span")) == -1) sp = 1;
 
519
                wi = c_width;
 
520
                al = c_al;
 
521
                val = c_val;
 
522
                get_align(t_attr, &al);
 
523
                get_valign(t_attr, &val);
 
524
                get_c_width(t_attr, &wi, sh);
 
525
                new_columns(t, sp, wi, al, val, !!c_span);
 
526
                c_span = 0;
 
527
                goto see;
 
528
        }
 
529
        if (t_namelen == 3 && (!casecmp(t_name, "/TR", 3) || !casecmp(t_name, "/TD", 3) || !casecmp(t_name, "/TH", 3))) {
 
530
                if (c_span) new_columns(t, c_span, c_width, c_al, c_val, 1);
 
531
                if (p) CELL(t, x, y)->end = html, p = 0;
 
532
                if (lbhp) (*bad_html)[*bhp-1].e = html, lbhp = NULL;
 
533
        }
 
534
        if (t_namelen == 2 && !casecmp(t_name, "TR", 2)) {
 
535
                if (c_span) new_columns(t, c_span, c_width, c_al, c_val, 1);
 
536
                if (p) CELL(t, x, y)->end = html, p = 0;
 
537
                if (lbhp) (*bad_html)[*bhp-1].e = html, lbhp = NULL;
 
538
                if (group) group--;
 
539
                l_al = AL_LEFT;
 
540
                l_val = VAL_MIDDLE;
 
541
                memcpy(&l_col, bgcolor, sizeof(struct rgb));
 
542
                get_align(t_attr, &l_al);
 
543
                get_valign(t_attr, &l_val);
 
544
                get_bgcolor(t_attr, &l_col);
 
545
                y++, x = 0;
 
546
                goto see;
 
547
        }
 
548
        if (t_namelen == 5 && ((!casecmp(t_name, "THEAD", 5)) || (!casecmp(t_name, "TBODY", 5)) || (!casecmp(t_name, "TFOOT", 5)))) {
 
549
                if (c_span) new_columns(t, c_span, c_width, c_al, c_val, 1);
 
550
                if (lbhp) (*bad_html)[*bhp-1].e = html, lbhp = NULL;
 
551
                group = 2;
 
552
        }
 
553
        if (t_namelen != 2 || (casecmp(t_name, "TD", 2) && casecmp(t_name, "TH", 2))) goto see;
 
554
        if (c_span) new_columns(t, c_span, c_width, c_al, c_val, 1);
 
555
        if (lbhp) (*bad_html)[*bhp-1].e = html, lbhp = NULL;
 
556
        if (p) CELL(t, x, y)->end = html, p = 0;
 
557
        if (y == -1) y = 0, x = 0;
 
558
        nc:
 
559
        if (!(cell = new_cell(t, x, y))) goto see;
 
560
        if (cell->used) {
 
561
                if (cell->colspan == -1) goto see;
 
562
                x++;
 
563
                goto nc;
 
564
        }
 
565
        cell->mx = x;
 
566
        cell->my = y;
 
567
        cell->used = 1;
 
568
        cell->start = en;
 
569
        p = 1;
 
570
        cell->align = l_al;
 
571
        cell->valign = l_val;
 
572
        cell->b = 0;
 
573
#if 0
 
574
        if (upcase(t_name[1]) == 'H') {
 
575
                unsigned char *e = en;
 
576
                while (e < eof && WHITECHAR(*e)) e++;
 
577
                if (eof - e > 6 && !casecmp(e, "<TABLE", 6)) goto no_th; /* hack for www.root.cz */
 
578
                cell->b = 1;
 
579
                cell->align = AL_CENTER;
 
580
                no_th:;
 
581
        }
 
582
#endif
 
583
        if (group == 1) cell->group = 1;
 
584
        if (x < t->c) {
 
585
                if (t->cols[x].align != AL_TR) cell->align = t->cols[x].align;
 
586
                if (t->cols[x].valign != VAL_TR) cell->valign = t->cols[x].valign;
 
587
        }
 
588
        memcpy(&cell->bgcolor, &l_col, sizeof(struct rgb));
 
589
        get_align(t_attr, &cell->align);
 
590
        get_valign(t_attr, &cell->valign);
 
591
        get_bgcolor(t_attr, &cell->bgcolor);
 
592
#ifdef G
 
593
        sprintf(cell->bgcolor_str, "#%02x%02x%02x", cell->bgcolor.r & 0xff, cell->bgcolor.g & 0xff, cell->bgcolor.b & 0xff);
 
594
#endif
 
595
        if ((csp = get_num(t_attr, "colspan")) == -1) csp = 1;
 
596
        if (!csp) csp = -1;
 
597
        if ((rsp = get_num(t_attr, "rowspan")) == -1) rsp = 1;
 
598
        if (!rsp) rsp = -1;
 
599
        if (csp >= 0 && rsp >= 0 && csp * rsp > 100000) {
 
600
                if (csp > 10) csp = -1;
 
601
                if (rsp > 10) rsp = -1;
 
602
        }
 
603
        cell->colspan = csp;
 
604
        cell->rowspan = rsp;
 
605
        if (csp == 1) {
 
606
                int w = W_AUTO;
 
607
                get_c_width(t_attr, &w, sh);
 
608
                if (w != W_AUTO) set_td_width(t, x, w, 0);
 
609
        }
 
610
        qqq = t->x;
 
611
        for (i = 1; csp != -1 ? i < csp : x + i < qqq; i++) {
 
612
                struct table_cell *sc;
 
613
                if (!(sc = new_cell(t, x + i, y)) || sc->used) {
 
614
                        csp = i;
 
615
                        for (k = 0; k < i; k++) CELL(t, x + k, y)->colspan = csp;
 
616
                        break;
 
617
                }
 
618
                sc->used = sc->spanned = 1;
 
619
                sc->rowspan = rsp;
 
620
                sc->colspan = csp;
 
621
                sc->mx = x;
 
622
                sc->my = y;
 
623
        }
 
624
        qqq = t->y;
 
625
        for (j = 1; rsp != -1 ? j < rsp : y + j < qqq; j++) {
 
626
                for (k = 0; k < i; k++) {
 
627
                        struct table_cell *sc;
 
628
                        if (!(sc = new_cell(t, x + k, y + j)) || sc->used) {
 
629
                                int l, m;
 
630
                                if (sc->mx == x && sc->my == y) continue;
 
631
                                /*internal("boo");*/
 
632
                                for (l = 0; l < k; l++) memset(CELL(t, x + l, y + j), 0, sizeof(struct table_cell));
 
633
                                rsp = j;
 
634
                                for (l = 0; l < i; l++) for (m = 0; m < j; m++) CELL(t, x + l, y + m)->rowspan = j;
 
635
                                goto brk;
 
636
                        }
 
637
                        sc->used = sc->spanned = 1;
 
638
                        sc->rowspan = rsp;
 
639
                        sc->colspan = csp;
 
640
                        sc->mx = x;
 
641
                        sc->my = y;
 
642
                }
 
643
        }
 
644
        brk:
 
645
        goto see;
 
646
 
 
647
        scan_done:
 
648
        *end = html;
 
649
 
 
650
        for (x = 0; x < t->x; x++) for (y = 0; y < t->y; y++) {
 
651
                struct table_cell *c = CELL(t, x, y);
 
652
                if (!c->spanned) {
 
653
                        if (c->colspan == -1) c->colspan = t->x - x;
 
654
                        if (c->rowspan == -1) c->rowspan = t->y - y;
 
655
                }
 
656
        }
 
657
 
 
658
        if ((unsigned)t->y > MAXINT / sizeof(int)) overalloc();
 
659
        t->r_heights = mem_calloc(t->y * sizeof(int));
 
660
 
 
661
        for (x = 0; x < t->c; x++) if (t->cols[x].width != W_AUTO) set_td_width(t, x, t->cols[x].width, 1);
 
662
        set_td_width(t, t->x, W_AUTO, 0);
 
663
 
 
664
        return t;
 
665
}
 
666
 
 
667
void get_cell_width(char *start, char *end, int cellpd, int w, int a, int *min, int *max, int n_link, int *n_links, unsigned char *bgc)
 
668
{
 
669
        struct part *p;
 
670
#ifdef G
 
671
        struct g_part *gp;
 
672
#endif
 
673
        if (min) *min = -1;
 
674
        if (max) *max = -1;
 
675
        if (n_links) *n_links = n_link;
 
676
        if (!F) {
 
677
                if (!(p = format_html_part(start, end, AL_LEFT, cellpd, w, NULL, !!a, !!a, NULL, n_link))) return;
 
678
                if (min) *min = p->x;
 
679
                if (max) *max = p->xmax;
 
680
                if (n_links) *n_links = p->link_num;
 
681
                mem_free(p);
 
682
#ifdef G
 
683
        } else {
 
684
                if (!(gp = g_format_html_part(start, end, AL_LEFT, 0, w, NULL, n_link, NULL, bgc, NULL))) return;
 
685
                if (min) *min = gp->x;
 
686
                if (max) *max = gp->xmax;
 
687
                if (n_links) *n_links = gp->link_num;
 
688
                mem_free(gp);
 
689
#endif
 
690
        }
 
691
        /*debug("get_cell_width: %d < %d", *min, *max);*/
 
692
        /*if (min && max && *min > *max) internal("get_cell_width: %d > %d", *min, *max);*/
 
693
}
 
694
 
 
695
static inline void check_cell_widths(struct table *t)
 
696
{
 
697
        int i, j;
 
698
        for (j = 0; j < t->y; j++) for (i = 0; i < t->x; i++) {
 
699
                int min, max;
 
700
                struct table_cell *c = CELL(t, i, j);
 
701
                if (!c->start) continue;
 
702
                get_cell_width(c->start, c->end, t->cellpd, 0, 0, &min, &max, c->link_num, NULL, gf_val(NULL, c->bgcolor_str));
 
703
                /*if (min != c->min_width || max < c->max_width) internal("check_cell_widths failed");*/
 
704
        }
 
705
}
 
706
 
 
707
#define g_c_w(cc)                                                       \
 
708
do {                                                                    \
 
709
                struct table_cell *c = cc;                              \
 
710
                if (!c->start) continue;                                \
 
711
                c->link_num = nl;                                       \
 
712
                get_cell_width(c->start, c->end, t->cellpd, 0, 0, &c->min_width, &c->max_width, nl, &nl, gf_val(NULL, c->bgcolor_str));\
 
713
} while (0)
 
714
 
 
715
void get_cell_widths(struct table *t)
 
716
{
 
717
        int nl = gf_val(t->p->link_num, t->gp->link_num);
 
718
        int i, j;
 
719
        if (!d_opt->table_order)
 
720
                for (j = 0; j < t->y; j++) for (i = 0; i < t->x; i++) g_c_w(CELL(t, i, j));
 
721
        else
 
722
                for (i = 0; i < t->x; i++) for (j = 0; j < t->y; j++) g_c_w(CELL(t, i, j));
 
723
        t->link_num = nl;
 
724
}
 
725
 
 
726
void dst_width(int *p, int n, int w, int *lim)
 
727
{
 
728
        int i, s = 0, d, r;
 
729
        for (i = 0; i < n; i++) s += p[i];
 
730
        if (s >= w) return;
 
731
        if (!n) return;
 
732
        again:
 
733
        d = (w - s) / n;
 
734
        r = (w - s) % n;
 
735
        w = 0;
 
736
        for (i = 0; i < n; i++) {
 
737
                p[i] += d + (i < r);
 
738
                if (lim && p[i] > lim[i]) w += p[i] - lim[i], p[i] = lim[i];
 
739
        }
 
740
        if (w) {
 
741
                /*if (!lim) internal("bug in dst_width");*/
 
742
                lim = NULL;
 
743
                s = 0;
 
744
                goto again;
 
745
        }
 
746
}
 
747
 
 
748
int get_vline_width(struct table *t, int col)
 
749
{                       /* return: -1 none, 0, space, 1 line, 2 double */
 
750
        int w = 0;
 
751
        NO_GFX;
 
752
        if (!col) return -1;
 
753
        if (t->rules == R_COLS || t->rules == R_ALL) w = t->cellsp;
 
754
        else if (t->rules == R_GROUPS) w = col < t->c && t->cols[col].group;
 
755
        if (!w && t->cellpd) w = -1;
 
756
        return w;
 
757
}
 
758
 
 
759
int get_hline_width(struct table *t, int row)
 
760
{
 
761
        int w = 0;
 
762
        NO_GFX;
 
763
        if (!row) return -1;
 
764
        if (t->rules == R_ROWS || t->rules == R_ALL) {
 
765
                x:
 
766
                if (t->cellsp || t->vcellpd) return t->cellsp;
 
767
                return -1;
 
768
        }
 
769
        else if (t->rules == R_GROUPS) {
 
770
                int q;
 
771
                for (q = 0; q < t->x; q++) if (CELL(t, q, row)->group) goto x;
 
772
                return t->vcellpd ? 0 : -1;
 
773
        }
 
774
        if (!w && !t->vcellpd) w = -1;
 
775
        return w;
 
776
}
 
777
 
 
778
#ifdef G
 
779
int g_get_vline_pad(struct table *t, int col, int *plpos, int *plsize)
 
780
{
 
781
        int pad, lpos, lsize;
 
782
        int border;
 
783
        NO_TXT;
 
784
        if (!col || col == t->x) {
 
785
                border = (!col && t->frame & F_LHS) || (col == t->x && t->frame & F_RHS) ? t->border : 0;
 
786
                pad = border + t->cellsp + t->cellpd;
 
787
                if (!col) lpos = 0, lsize = border + t->cellsp;
 
788
                else lpos = pad - border - t->cellsp, lsize = border + t->cellsp;
 
789
        } else {
 
790
                border = t->rules == R_COLS || t->rules == R_ALL || (t->rules == R_GROUPS && col < t->c && t->cols[col].group) ? t->border : 0;
 
791
                pad = 2 * t->cellpd + t->cellsp;
 
792
                lpos = t->cellpd;
 
793
                lsize = t->cellsp;
 
794
        }
 
795
        if (!border) {
 
796
                lsize = 0;
 
797
                if (!col) lpos = 0;
 
798
                else if (col == t->x) lpos = pad;
 
799
                else lpos = pad / 2;
 
800
        }
 
801
        if (plpos) *plpos = lpos;
 
802
        if (plsize) *plsize = lsize;
 
803
        return pad;
 
804
}
 
805
 
 
806
int g_get_hline_pad(struct table *t, int row, int *plpos, int *plsize)
 
807
{
 
808
        int pad, lpos, lsize;
 
809
        int border;
 
810
        NO_TXT;
 
811
        if (!row || row == t->y) {
 
812
                border = (!row && t->frame & F_ABOVE) || (row == t->y && t->frame & F_BELOW) ? t->border : 0;
 
813
                pad = border + t->cellsp + t->cellpd;
 
814
                if (!row) lpos = 0, lsize = border + t->cellsp;
 
815
                else lpos = pad - border - t->cellsp, lsize = border + t->cellsp;
 
816
        } else {
 
817
                border = t->rules == R_ROWS || t->rules == R_ALL ? t->border : 0;
 
818
                if (t->rules == R_GROUPS) {
 
819
                        int q;
 
820
                        for (q = 0; q < t->x; q++) if (CELL(t, q, row)->group) {
 
821
                                border = t->border;
 
822
                                break;
 
823
                        }
 
824
                }
 
825
                pad = 2 * t->cellpd + t->cellsp;
 
826
                lpos = t->cellpd;
 
827
                lsize = t->cellsp;
 
828
        }
 
829
        if (!border) {
 
830
                lsize = 0;
 
831
                if (!row) lpos = 0;
 
832
                else if (row == t->y) lpos = pad;
 
833
                else lpos = pad / 2;
 
834
        }
 
835
        if (plpos) *plpos = lpos;
 
836
        if (plsize) *plsize = lsize;
 
837
        return pad;
 
838
}
 
839
#endif
 
840
        
 
841
int get_column_widths(struct table *t)
 
842
{
 
843
        int i, j, s, ns;
 
844
        if ((unsigned)t->x > MAXINT / sizeof(int)) overalloc();
 
845
        if (!t->min_c) t->min_c = mem_alloc(t->x * sizeof(int));
 
846
        if (!t->max_c) t->max_c = mem_alloc(t->x * sizeof(int));
 
847
        if (!t->w_c) t->w_c = mem_alloc(t->x * sizeof(int));
 
848
        memset(t->min_c, 0, t->x * sizeof(int));
 
849
        memset(t->max_c, 0, t->x * sizeof(int));
 
850
        s = 1;
 
851
        do {
 
852
                ns = MAXINT;
 
853
                for (i = 0; i < t->x; i++) for (j = 0; j < t->y; j++) {
 
854
                        struct table_cell *c = CELL(t, i, j);
 
855
                        if (c->spanned || !c->used) continue;
 
856
                        if (c->colspan + i > t->x) {
 
857
                                /*internal("colspan out of table");
 
858
                                return -1;*/
 
859
                                continue;
 
860
                        }
 
861
                        if (c->colspan == s) {
 
862
                                int k, p = 0;
 
863
                                /*int pp = t->max_c[i];*/
 
864
                                int m = 0;
 
865
                                for (k = 1; k < s; k++) {
 
866
                                        if (!F) p += get_vline_width(t, i + k) >= 0;
 
867
#ifdef G
 
868
                                        else p += g_get_vline_pad(t, i + k, NULL, NULL);
 
869
#endif
 
870
                                }
 
871
                                dst_width(t->min_c + i, s, c->min_width - p, t->max_c + i);
 
872
                                dst_width(t->max_c + i, s, c->max_width - p - m, NULL);
 
873
                                for (k = 0; k < s; k++) if (t->min_c[i + k] > t->max_c[i + k]) t->max_c[i + k] = t->min_c[i + k];
 
874
                        } else if (c->colspan > s && c->colspan < ns) ns = c->colspan;
 
875
                }
 
876
        } while ((s = ns) != MAXINT);
 
877
        return 0;
 
878
}
 
879
 
 
880
void get_table_width(struct table *t)
 
881
{
 
882
        int i, vl;
 
883
        int min = 0, max = 0;
 
884
        for (i = 0; i < t->x; i++) {
 
885
                if (!F) vl = get_vline_width(t, i) >= 0;
 
886
#ifdef G
 
887
                else if (i) {
 
888
                        vl = g_get_vline_pad(t, i, NULL, NULL);
 
889
                } else vl = 0;
 
890
#endif
 
891
                min += vl, max += vl;
 
892
                min += t->min_c[i];
 
893
                if (t->xcols[i] > t->max_c[i]) max += t->xcols[i];
 
894
                max += t->max_c[i];
 
895
        }
 
896
        if (!F) {
 
897
                vl = (!!(t->frame & F_LHS) + !!(t->frame & F_RHS)) * !!t->border;
 
898
                min += vl, max += vl;
 
899
#ifdef G
 
900
        } else {
 
901
                vl = g_get_vline_pad(t, 0, NULL, NULL);
 
902
                min += vl, max += vl;
 
903
                vl = g_get_vline_pad(t, t->x, NULL, NULL);
 
904
                min += vl, max += vl;
 
905
#endif
 
906
        }
 
907
        t->min_t = min;
 
908
        t->max_t = max;
 
909
        /*if (min > max) internal("min(%d) > max(%d)", min, max);*/
 
910
}
 
911
 
 
912
void distribute_widths(struct table *t, int width)
 
913
{
 
914
        int i;
 
915
        int d = width - t->min_t;
 
916
        int om = 0;
 
917
        char *u;
 
918
        int *w, *mx;
 
919
        int mmax_c = 0;
 
920
        t->rw = 0;
 
921
        if (!t->x) return;
 
922
        if (d < 0) {
 
923
                /*internal("too small width %d, required %d", width, t->min_t);*/
 
924
                return;
 
925
        }
 
926
        for (i = 0; i < t->x; i++) if (t->max_c[i] > mmax_c) mmax_c = t->max_c[i];
 
927
        memcpy(t->w_c, t->min_c, t->x * sizeof(int));
 
928
        t->rw = width;
 
929
        if ((unsigned)t->x > MAXINT / sizeof(int)) overalloc();
 
930
        u = mem_alloc(t->x);
 
931
        w = mem_alloc(t->x * sizeof(int));
 
932
        mx = mem_alloc(t->x * sizeof(int));
 
933
        while (d) {
 
934
                int mss, mii;
 
935
                int p = 0;
 
936
                int wq;
 
937
                int dd;
 
938
                memset(w, 0, t->x * sizeof(int));
 
939
                memset(mx, 0, t->x * sizeof(int));
 
940
                for (i = 0; i < t->x; i++) {
 
941
                        switch (om) {
 
942
                                case 0:
 
943
                                        if (t->w_c[i] < t->xcols[i]) {
 
944
                                                w[i] = 1, mx[i] = (t->xcols[i] > t->max_c[i] ? t->max_c[i] : t->xcols[i]) - t->w_c[i];
 
945
                                                if (mx[i] <= 0) w[i] = 0;
 
946
                                        }
 
947
                                        break;
 
948
                                case 1:
 
949
                                        if (t->xcols[i] < -1 && t->xcols[i] != -2) {
 
950
                                                w[i] = t->xcols[i] <= -2 ? -2 - t->xcols[i] : 1;
 
951
                                                mx[i] = t->max_c[i] - t->w_c[i];
 
952
                                                if (mx[i] <= 0) w[i] = 0;
 
953
                                        }
 
954
                                        break;
 
955
                                case 2:
 
956
                                case 3:
 
957
                                        if (t->w_c[i] < t->max_c[i] && (om == 3 || t->xcols[i] == W_AUTO)) {
 
958
                                                mx[i] = t->max_c[i] - t->w_c[i];
 
959
                                                if (mmax_c) w[i] = gf_val(5, 5 * HTML_CHAR_WIDTH) + t->max_c[i] * 10 / mmax_c;
 
960
                                                else w[i] = 1;
 
961
                                        }
 
962
                                        break;
 
963
                                case 4:
 
964
                                        if (t->xcols[i] >= 0) {
 
965
                                                w[i] = 1, mx[i] = t->xcols[i] - t->w_c[i];
 
966
                                                if (mx[i] <= 0) w[i] = 0;
 
967
                                        }
 
968
                                        break;
 
969
                                case 5:
 
970
                                        if (t->xcols[i] < 0) w[i] = t->xcols[i] <= -2 ? -2 - t->xcols[i] : 1, mx[i] = MAXINT;
 
971
                                        break;
 
972
                                case 6:
 
973
                                        w[i] = 1, mx[i] = MAXINT;
 
974
                                        break;
 
975
                                default:
 
976
                                        /*internal("could not expand table");*/
 
977
                                        goto end2;
 
978
                        }
 
979
                        p += w[i];
 
980
                }
 
981
                if (!p) {
 
982
                        om++;
 
983
                        continue;
 
984
                }
 
985
                wq = 0;
 
986
                if (u) memset(u, 0, t->x);
 
987
                dd = d;
 
988
                a:
 
989
                mss = 0; mii = -1;
 
990
                for (i = 0; i < t->x; i++) if (w[i]) {
 
991
                        int ss;
 
992
                        if (u && u[i]) continue;
 
993
                        if (!(ss = dd * w[i] / p)) ss = 1;
 
994
                        if (ss > mx[i]) ss = mx[i];
 
995
                        if (ss > mss) mss = ss, mii = i;
 
996
                }
 
997
                if (mii != -1) {
 
998
                        int q = t->w_c[mii];
 
999
                        if (u) u[mii] = 1;
 
1000
                        t->w_c[mii] += mss;
 
1001
                        d -= t->w_c[mii] - q;
 
1002
                        while (d < 0) t->w_c[mii]--, d++;
 
1003
                        if (t->w_c[mii] < q) {
 
1004
                                /*internal("shrinking cell");*/
 
1005
                                t->w_c[mii] = q;
 
1006
                        }
 
1007
                        wq = 1;
 
1008
                        if (d) goto a;
 
1009
                } else if (!wq) om++;
 
1010
        }
 
1011
        end2:
 
1012
        mem_free(mx);
 
1013
        mem_free(w);
 
1014
        if (u) mem_free(u);
 
1015
}
 
1016
 
 
1017
#ifdef HTML_TABLE_2ND_PASS
 
1018
void check_table_widths(struct table *t)
 
1019
{
 
1020
        int *w;
 
1021
        int i, j;
 
1022
        int s, ns;
 
1023
        int m, mi = 0; /* go away, warning! */
 
1024
        if ((unsigned)t->x > MAXINT / sizeof(int)) overalloc();
 
1025
        w = mem_calloc(t->x * sizeof(int));
 
1026
        for (j = 0; j < t->y; j++) for (i = 0; i < t->x; i++) {
 
1027
                struct table_cell *c = CELL(t, i, j);
 
1028
                int k, p = 0;
 
1029
                if (!c->start) continue;
 
1030
                for (k = 1; k < c->colspan; k++) p += get_vline_width(t, i + k) >= 0;
 
1031
                for (k = 0; k < c->colspan; k++) p += t->w_c[i + k];
 
1032
                get_cell_width(c->start, c->end, t->cellpd, p, 1, &c->x_width, NULL, c->link_num, NULL, NULL);
 
1033
                if (c->x_width > p) {
 
1034
                        /*int min, max;
 
1035
                        get_cell_width(c->start, c->end, t->cellpd, 0, 0, &min, &max, c->link_num, NULL, NULL);
 
1036
                        internal("cell is now wider (%d > %d) min = %d, max = %d, now_min = %d, now_max = %d", c->x_width, p, t->min_c[i], t->max_c[i], min, max);*/
 
1037
                        /* sbohem, internale. chytl jsi mi spoustu chyb v tabulkovaci, ale ted je proste cas jit ... ;-( */
 
1038
                        c->x_width = p;
 
1039
                }
 
1040
        }
 
1041
        s = 1;
 
1042
        do {
 
1043
                ns = MAXINT;
 
1044
                for (i = 0; i < t->x; i++) for (j = 0; j < t->y; j++) {
 
1045
                        struct table_cell *c = CELL(t, i, j);
 
1046
                        if (!c->start) continue;
 
1047
                        if (c->colspan + i > t->x) {
 
1048
                                /*internal("colspan out of table");*/
 
1049
                                mem_free(w);
 
1050
                                return;
 
1051
                        }
 
1052
                        if (c->colspan == s) {
 
1053
                                int k, p = 0;
 
1054
                                for (k = 1; k < s; k++) p += get_vline_width(t, i + k) >= 0;
 
1055
                                dst_width(w + i, s, c->x_width - p, t->max_c + i);
 
1056
                                /*for (k = i; k < i + s; k++) if (w[k] > t->w_c[k]) {
 
1057
                                        int l;
 
1058
                                        int c;
 
1059
                                        ag:
 
1060
                                        c = 0;
 
1061
                                        for (l = i; l < i + s; l++) if (w[l] < t->w_c[k]) w[l]++, w[k]--, c = 1;
 
1062
                                        if (w[k] > t->w_c[k]) {
 
1063
                                                if (!c) internal("can't shrink cell");
 
1064
                                                else goto ag;
 
1065
                                        }
 
1066
                                }*/
 
1067
                        } else if (c->colspan > s && c->colspan < ns) ns = c->colspan;
 
1068
                }
 
1069
        } while ((s = ns) != MAXINT);
 
1070
 
 
1071
        s = 0; ns = 0;
 
1072
        for (i = 0; i < t->x; i++) {
 
1073
                s += t->w_c[i], ns += w[i];
 
1074
                /*if (w[i] > t->w_c[i]) {
 
1075
                        int k;
 
1076
                        for (k = 0; k < t->x; k++) debug("%d, %d", t->w_c[k], w[k]);
 
1077
                        debug("column %d: new width(%d) is larger than previous(%d)", i, w[i], t->w_c[i]);
 
1078
                }*/
 
1079
        }
 
1080
        if (ns > s) {
 
1081
                /*internal("new width(%d) is larger than previous(%d)", ns, s);*/
 
1082
                mem_free(w);
 
1083
                return;
 
1084
        }
 
1085
        m = -1;
 
1086
        for (i = 0; i < t->x; i++) {
 
1087
                /*if (table_level == 1) debug("%d: %d %d %d %d", i, t->max_c[i], t->min_c[i], t->w_c[i], w[i]);*/
 
1088
                if (t->max_c[i] > m) m = t->max_c[i], mi = i;
 
1089
        }
 
1090
        /*if (table_level == 1) debug("%d %d", mi, s - ns);*/
 
1091
        if (m != -1) {
 
1092
                w[mi] += s - ns;
 
1093
                if (w[mi] <= t->max_c[mi]) {
 
1094
                        mem_free(t->w_c);
 
1095
                        t->w_c = w;
 
1096
                        return;
 
1097
                }
 
1098
        }
 
1099
        mem_free(w);
 
1100
}
 
1101
#endif
 
1102
 
 
1103
void get_table_heights(struct table *t)
 
1104
{
 
1105
        int s, ns;
 
1106
        int i, j;
 
1107
        for (j = 0; j < t->y; j++) {
 
1108
                for (i = 0; i < t->x; i++) {
 
1109
                        struct table_cell *cell = CELL(t, i, j);
 
1110
                        struct part *p;
 
1111
#ifdef G
 
1112
                        struct g_part *gp;
 
1113
#endif
 
1114
                        int xw = 0, sp;
 
1115
                        if (!cell->used || cell->spanned) continue;
 
1116
                        /*
 
1117
                        fprintf(stderr, "i==%d, w_c[i]==%d, min_c[i]==%d, max_c[i]==%d\n", i, t->w_c[i], t->min_c[i], t->max_c[i]);
 
1118
                        */
 
1119
                        for (sp = 0; sp < cell->colspan; sp++) {
 
1120
                                xw += t->w_c[i + sp];
 
1121
                                if (sp < cell->colspan - 1) {
 
1122
                                        if (!F) xw += get_vline_width(t, i + sp + 1) >= 0;
 
1123
#ifdef G
 
1124
                                        else xw += g_get_vline_pad(t, i + sp + 1, NULL, NULL);
 
1125
#endif
 
1126
                                }
 
1127
                        }
 
1128
                        if (!F) {
 
1129
                                if (!(p = format_html_part(cell->start, cell->end, cell->align, t->cellpd, xw, NULL, 2, 2, NULL, cell->link_num))) return;
 
1130
                                cell->height = p->y;
 
1131
                                mem_free(p);
 
1132
#ifdef G
 
1133
                        } else {
 
1134
                                if (!(gp = g_format_html_part(cell->start, cell->end, cell->align, 0, xw, NULL, cell->link_num, NULL /* FIX: background image */, cell->bgcolor_str, t->gp->data))) return;
 
1135
                                /*if (gp->root->xw > xw) internal("vono to neumi formatovat... buuuu (%d > %d)", gp->root->xw, xw);*/
 
1136
                                cell->root = gp->root;
 
1137
                                gp->root = NULL;
 
1138
                                cell->height = gp->y;
 
1139
                                cell->g_width = xw;
 
1140
                                g_release_part(gp);
 
1141
                                mem_free(gp);
 
1142
#endif
 
1143
                        }
 
1144
                                /*debug("%d, %d.",xw, cell->height);*/
 
1145
                }
 
1146
        }
 
1147
        s = 1;
 
1148
        do {
 
1149
                ns = MAXINT;
 
1150
                for (j = 0; j < t->y; j++) {
 
1151
                        for (i = 0; i < t->x; i++) {
 
1152
                                struct table_cell *cell = CELL(t, i, j);
 
1153
                                if (!cell->used || cell->spanned) continue;
 
1154
                                if (cell->rowspan == s) {
 
1155
                                        int k, p = 0;
 
1156
                                        for (k = 1; k < s; k++) {
 
1157
                                                if (!F) p += get_hline_width(t, j + k) >= 0;
 
1158
#ifdef G
 
1159
                                                else p += g_get_hline_pad(t, j + k, NULL, NULL);
 
1160
#endif
 
1161
                                        }
 
1162
                                        dst_width(t->r_heights + j, s, cell->height - p, NULL);
 
1163
                                } else if (cell->rowspan > s && cell->rowspan < ns) ns = cell->rowspan;
 
1164
                        }
 
1165
                }
 
1166
        } while ((s = ns) != MAXINT);
 
1167
        if (!F) {
 
1168
                t->rh = (!!(t->frame & F_ABOVE) + !!(t->frame & F_BELOW)) * !!t->border;
 
1169
                for (j = 0; j < t->y; j++) {
 
1170
                        t->rh += t->r_heights[j];
 
1171
                        if (j) t->rh += get_hline_width(t, j) >= 0;
 
1172
                }
 
1173
#ifdef G
 
1174
        } else {
 
1175
                t->rh = 0;
 
1176
                for (j = 0; j <= t->y; j++) {
 
1177
                        t->rh += g_get_hline_pad(t, j, NULL, NULL);
 
1178
                        if (j < t->y) t->rh += t->r_heights[j];
 
1179
                }
 
1180
#endif
 
1181
        }
 
1182
}
 
1183
 
 
1184
void display_complicated_table(struct table *t, int x, int y, int *yy)
 
1185
{
 
1186
        int i, j;
 
1187
        struct f_data *f = t->p->data;
 
1188
        int yp, xp = x + ((t->frame & F_LHS) && t->border);
 
1189
        for (i = 0; i < t->x; i++) {
 
1190
                yp = y + ((t->frame & F_ABOVE) && t->border);
 
1191
                for (j = 0; j < t->y; j++) {
 
1192
                        struct table_cell *cell = CELL(t, i, j);
 
1193
                        if (cell->start) {
 
1194
                                int yt;
 
1195
                                struct part *p = NULL;
 
1196
                                int xw = 0, yw = 0, s;
 
1197
                                for (s = 0; s < cell->colspan; s++) {
 
1198
                                        xw += t->w_c[i + s];
 
1199
                                        if (s < cell->colspan - 1) xw += get_vline_width(t, i + s + 1) >= 0;
 
1200
                                }
 
1201
                                for (s = 0; s < cell->rowspan; s++) {
 
1202
                                        yw += t->r_heights[j + s];
 
1203
                                        if (s < cell->rowspan - 1) yw += get_hline_width(t, j + s + 1) >= 0;
 
1204
                                }
 
1205
                                html_stack_dup();
 
1206
                                html_top.dontkill = 1;
 
1207
                                if (cell->b) format.attr |= AT_BOLD;
 
1208
                                memcpy(&format.bg, &cell->bgcolor, sizeof(struct rgb));
 
1209
                                memcpy(&par_format.bgcolor, &cell->bgcolor, sizeof(struct rgb));
 
1210
                                p = format_html_part(cell->start, cell->end, cell->align, t->cellpd, xw, f, t->p->xp + xp, t->p->yp + yp + (cell->valign != VAL_MIDDLE && cell->valign != VAL_BOTTOM ? 0 : (yw - cell->height) / (cell->valign == VAL_MIDDLE ? 2 : 1)), NULL, cell->link_num);
 
1211
                                cell->xpos = xp;
 
1212
                                cell->ypos = yp;
 
1213
                                cell->xw = xw;
 
1214
                                cell->yw = yw;
 
1215
                                for (yt = 0; yt < p->y; yt++) {
 
1216
                                        xxpand_lines(t->p, yp + yt);
 
1217
                                        xxpand_line(t->p, yp + yt, xp + t->w_c[i]);
 
1218
                                }
 
1219
                                kill_html_stack_item(&html_top);
 
1220
                                mem_free(p);
 
1221
                        }
 
1222
                        cell->xpos = xp;
 
1223
                        cell->ypos = yp;
 
1224
                        cell->xw = t->w_c[i];
 
1225
                        yp += t->r_heights[j];
 
1226
                        if (j < t->y - 1) yp += (get_hline_width(t, j + 1) >= 0);
 
1227
                }
 
1228
                if (i < t->x - 1) xp += t->w_c[i] + (get_vline_width(t, i + 1) >= 0);
 
1229
        }
 
1230
        yp = y;
 
1231
        for (j = 0; j < t->y; j++) {
 
1232
                yp += t->r_heights[j];
 
1233
                if (j < t->y - 1) yp += (get_hline_width(t, j + 1) >= 0);
 
1234
        }
 
1235
        *yy = yp + (!!(t->frame & F_ABOVE) + !!(t->frame & F_BELOW)) * !!t->border;
 
1236
}
 
1237
 
 
1238
/* !!! FIXME: background */
 
1239
#define draw_frame_point(xx, yy, ii, jj)        \
 
1240
if (H_LINE_X((ii-1), (jj)) >= 0 || H_LINE_X((ii), (jj)) >= 0 || V_LINE_X((ii), (jj-1)) >= 0 || V_LINE_X((ii), (jj)) >= 0) xset_hchar(t->p, (xx), (yy), frame_table[V_LINE((ii),(jj)-1)+3*H_LINE((ii),(jj))+9*H_LINE((ii)-1,(jj))+27*V_LINE((ii),(jj))], ATTR_FRAME)
 
1241
 
 
1242
#define draw_frame_hline(xx, yy, ll, ii, jj)    \
 
1243
if (H_LINE_X((ii), (jj)) >= 0) xset_hchars(t->p, (xx), (yy), (ll), hline_table[H_LINE((ii), (jj))], ATTR_FRAME)
 
1244
 
 
1245
#define draw_frame_vline(xx, yy, ll, ii, jj)    \
 
1246
{                                               \
 
1247
        int qq;                                 \
 
1248
        if (V_LINE_X((ii), (jj)) >= 0) for (qq = 0; qq < (ll); qq++) xset_hchar(t->p, (xx), (yy) + qq, vline_table[V_LINE((ii), (jj))], ATTR_FRAME); }
 
1249
 
 
1250
#ifndef DEBUG
 
1251
#define H_LINE_X(xx, yy) fh[(xx) + 1 + (t->x + 2) * (yy)]
 
1252
#define V_LINE_X(xx, yy) fv[(yy) + 1 + (t->y + 2) * (xx)]
 
1253
#else
 
1254
#define H_LINE_X(xx, yy) (*(xx < -1 || xx > t->x + 1 || yy < 0 || yy > t->y ? (signed char *)NULL : &fh[(xx) + 1 + (t->x + 2) * (yy)]))
 
1255
#define V_LINE_X(xx, yy) (*(xx < 0 || xx > t->x || yy < -1 || yy > t->y + 1 ? (signed char *)NULL : &fv[(yy) + 1 + (t->y + 2) * (xx)]))
 
1256
#endif
 
1257
#define H_LINE(xx, yy) (H_LINE_X((xx), (yy)) < 0 ? 0 : H_LINE_X((xx), (yy)))
 
1258
#define V_LINE(xx, yy) (V_LINE_X((xx), (yy)) < 0 ? 0 : V_LINE_X((xx), (yy)))
 
1259
 
 
1260
void get_table_frame(struct table *t, signed char *fv, signed char *fh)
 
1261
{
 
1262
        int i, j;
 
1263
        memset(fh, -1, (t->x + 2) * (t->y + 1));
 
1264
        memset(fv, -1, (t->x + 1) * (t->y + 2));
 
1265
        for (j = 0; j < t->y; j++) for (i = 0; i < t->x; i++) {
 
1266
                int x, y;
 
1267
                int xsp, ysp;
 
1268
                struct table_cell *cell = CELL(t, i, j);
 
1269
                if (!cell->used || cell->spanned) continue;
 
1270
                if ((xsp = cell->colspan) == 0) xsp = t->x - i;
 
1271
                if ((ysp = cell->rowspan) == 0) ysp = t->y - j;
 
1272
                if (t->rules != R_NONE && t->rules != R_COLS) for (x = 0; x < xsp; x++) {H_LINE_X(i + x, j) = t->cellsp; H_LINE_X(i + x, j + ysp) = t->cellsp;}
 
1273
                if (t->rules != R_NONE && t->rules != R_ROWS) for (y = 0; y < ysp; y++) {V_LINE_X(i, j + y) = t->cellsp; V_LINE_X(i + xsp, j + y) = t->cellsp;}
 
1274
                if (F) {
 
1275
                        for (x = 0; x < xsp; x++) for (y = 1; y < ysp; y++)
 
1276
                                H_LINE_X(i + x, j + y) = -2;
 
1277
                        for (x = 1; x < xsp; x++) for (y = 0; y < ysp; y++)
 
1278
                                V_LINE_X(i + x, j + y) = -2;
 
1279
                }
 
1280
        }
 
1281
        if (t->rules == R_GROUPS) {
 
1282
                for (i = 1; i < t->x; i++) {
 
1283
                        if (/*i < t->xc &&*/ t->xcols[i]) continue;
 
1284
                        for (j = 0; j < t->y; j++) V_LINE_X(i, j) = 0;
 
1285
                }
 
1286
                for (j = 1; j < t->y; j++) {
 
1287
                        for (i = 0; i < t->x; i++) if (CELL(t, i, j)->group) goto c;
 
1288
                        for (i = 0; i < t->x; i++) H_LINE_X(i, j) = 0;
 
1289
                        c:;
 
1290
                }
 
1291
        }
 
1292
        for (i = 0; i < t->x; i++) {
 
1293
                H_LINE_X(i, 0) = t->border * !!(t->frame & F_ABOVE);
 
1294
                H_LINE_X(i, t->y) = t->border * !!(t->frame & F_BELOW);
 
1295
        }
 
1296
        for (j = 0; j < t->y; j++) {
 
1297
                V_LINE_X(0, j) = t->border * !!(t->frame & F_LHS);
 
1298
                V_LINE_X(t->x, j) = t->border * !!(t->frame & F_RHS);
 
1299
        }
 
1300
}
 
1301
 
 
1302
void display_table_frames(struct table *t, int x, int y)
 
1303
{
 
1304
        signed char *fh, *fv;
 
1305
        int i, j;
 
1306
        int cx, cy;
 
1307
        if ((unsigned)t->x > MAXINT) overalloc();
 
1308
        if ((unsigned)t->y > MAXINT) overalloc();
 
1309
        if (((unsigned)t->x + 2) * ((unsigned)t->y + 2) / ((unsigned)t->x + 2) != ((unsigned)t->y + 2)) overalloc();
 
1310
        if (((unsigned)t->x + 2) * ((unsigned)t->y + 2) > MAXINT) overalloc();
 
1311
        fh = mem_alloc((t->x + 2) * (t->y + 1));
 
1312
        fv = mem_alloc((t->x + 1) * (t->y + 2));
 
1313
        get_table_frame(t, fv, fh);
 
1314
 
 
1315
        cy = y;
 
1316
        for (j = 0; j <= t->y; j++) {
 
1317
                cx = x;
 
1318
                if ((j > 0 && j < t->y && get_hline_width(t, j) >= 0) || (j == 0 && t->border && (t->frame & F_ABOVE)) || (j == t->y && t->border && (t->frame & F_BELOW))) {
 
1319
                        for (i = 0; i < t->x; i++) {
 
1320
                                int w;
 
1321
                                if (i > 0) w = get_vline_width(t, i);
 
1322
                                else w = t->border && (t->frame & F_LHS) ? t->border : -1;
 
1323
                                if (w >= 0) {
 
1324
                                        draw_frame_point(cx, cy, i, j);
 
1325
                                        if (j < t->y) draw_frame_vline(cx, cy + 1, t->r_heights[j], i, j);
 
1326
                                        cx++;
 
1327
                                }
 
1328
                                w = t->w_c[i];
 
1329
                                draw_frame_hline(cx, cy, w, i, j);
 
1330
                                cx += w;
 
1331
                        }
 
1332
                        if (t->border && (t->frame & F_RHS)) {
 
1333
                                draw_frame_point(cx, cy, i, j);
 
1334
                                if (j < t->y) draw_frame_vline(cx, cy + 1, t->r_heights[j], i, j);
 
1335
                                cx++;
 
1336
                        }
 
1337
                        cy++;
 
1338
                } else if (j < t->y) {
 
1339
                        for (i = 0; i <= t->x; i++) {
 
1340
                                if ((i > 0 && i < t->x && get_vline_width(t, i) >= 0) || (i == 0 && t->border && (t->frame & F_LHS)) || (i == t->x && t->border && (t->frame & F_RHS))) {
 
1341
                                        draw_frame_vline(cx, cy, t->r_heights[j], i, j);
 
1342
                                        cx++;
 
1343
                                }
 
1344
                                if (i < t->x) cx += t->w_c[i];
 
1345
                        }
 
1346
                }
 
1347
                if (j < t->y) cy += t->r_heights[j];
 
1348
                /*for (cyy = cy1; cyy < cy; cyy++) xxpand_line(t->p, cyy, cx - 1);*/
 
1349
        }
 
1350
        mem_free(fh);
 
1351
        mem_free(fv);
 
1352
}
 
1353
 
 
1354
#ifdef G
 
1355
void process_g_table(struct g_part *gp, struct table *t);
 
1356
#endif
 
1357
 
 
1358
void format_table(unsigned char *attr, unsigned char *html, unsigned char *eof, unsigned char **end, void *f)
 
1359
{
 
1360
        struct part *p = !F ? f : NULL;
 
1361
#ifdef G
 
1362
        struct g_part *gp = F ? f : NULL;
 
1363
#endif
 
1364
        int border, cellsp, vcellpd, cellpd, align;
 
1365
        int frame, rules, width, wf;
 
1366
        struct rgb bgcolor;
 
1367
        struct table *t;
 
1368
        char *al;
 
1369
        int cye;
 
1370
        int x;
 
1371
        int i;
 
1372
        /*int llm = last_link_to_move;*/
 
1373
        struct s_e *bad_html = NULL;
 
1374
        int bad_html_n;
 
1375
        struct node *n, *nn;
 
1376
        int cpd_pass, cpd_width, cpd_last;
 
1377
        table_level++;
 
1378
        memcpy(&bgcolor, &par_format.bgcolor, sizeof(struct rgb));
 
1379
        get_bgcolor(attr, &bgcolor);
 
1380
        if ((border = get_num(attr, "border")) == -1) border = has_attr(attr, "border") || has_attr(attr, "rules") || has_attr(attr, "frame");
 
1381
        /*if (!border) border = 1;*/
 
1382
        if ((cellsp = get_num(attr, "cellspacing")) == -1) cellsp = gf_val(1, 2);
 
1383
        if ((cellpd = get_num(attr, "cellpadding")) == -1) {
 
1384
                vcellpd = gf_val(0, 1);
 
1385
                cellpd = gf_val(!!border, 1);
 
1386
        } else {
 
1387
                if (!F) {
 
1388
                        vcellpd = cellpd >= HTML_CHAR_HEIGHT / 2 + 1;
 
1389
                        cellpd = cellpd >= HTML_CHAR_WIDTH / 2 + 1;
 
1390
                } else vcellpd = cellpd;
 
1391
        }
 
1392
        if (!F && !border) cellsp = 0;
 
1393
        else if (!F && !cellsp) cellsp = 1;
 
1394
        /* Sparc gcc-2.7.2.1 miscompiles this */
 
1395
        do_not_optimize_here(&cellsp);
 
1396
        if (!F && border > 2) border = 2;
 
1397
        if (!F && cellsp > 2) cellsp = 2;
 
1398
        if (F && !cellsp && border) cellsp = 1;
 
1399
        align = par_format.align;
 
1400
        if (align == AL_NO || align == AL_BLOCK) align = AL_LEFT;
 
1401
        if ((al = get_attr_val(attr, "align"))) {
 
1402
                if (!strcasecmp(al, "left")) align = AL_LEFT;
 
1403
                if (!strcasecmp(al, "center")) align = AL_CENTER;
 
1404
                if (!strcasecmp(al, "right")) align = AL_RIGHT;
 
1405
                mem_free(al);
 
1406
        }
 
1407
        frame = F_BOX;
 
1408
        if ((al = get_attr_val(attr, "frame"))) {
 
1409
                if (!strcasecmp(al, "void")) frame = F_VOID;
 
1410
                if (!strcasecmp(al, "above")) frame = F_ABOVE;
 
1411
                if (!strcasecmp(al, "below")) frame = F_BELOW;
 
1412
                if (!strcasecmp(al, "hsides")) frame = F_HSIDES;
 
1413
                if (!strcasecmp(al, "vsides")) frame = F_VSIDES;
 
1414
                if (!strcasecmp(al, "lhs")) frame = F_LHS;
 
1415
                if (!strcasecmp(al, "rhs")) frame = F_RHS;
 
1416
                if (!strcasecmp(al, "box")) frame = F_BOX;
 
1417
                if (!strcasecmp(al, "border")) frame = F_BOX;
 
1418
                mem_free(al);
 
1419
        }
 
1420
        rules = border ? R_ALL : R_NONE;
 
1421
        if ((al = get_attr_val(attr, "rules"))) {
 
1422
                if (!strcasecmp(al, "none")) rules = R_NONE;
 
1423
                if (!strcasecmp(al, "groups")) rules = R_GROUPS;
 
1424
                if (!strcasecmp(al, "rows")) rules = R_ROWS;
 
1425
                if (!strcasecmp(al, "cols")) rules = R_COLS;
 
1426
                if (!strcasecmp(al, "all")) rules = R_ALL;
 
1427
                mem_free(al);
 
1428
        }
 
1429
        if (!border) frame = F_VOID;
 
1430
        wf = 0;
 
1431
        if ((width = get_width(attr, "width", gf_val(p->data || p->xp, !!gp->data))) == -1) {
 
1432
                width = par_format.width - (par_format.leftmargin + par_format.rightmargin) * gf_val(1, G_HTML_MARGIN);
 
1433
                if (width < 0) width = 0;
 
1434
                wf = 1;
 
1435
        }
 
1436
        if (!(t = parse_table(html, eof, end, &bgcolor, gf_val(p->data || p->xp, !!gp->data), &bad_html, &bad_html_n))) {
 
1437
                if (bad_html) mem_free(bad_html);
 
1438
                goto ret0;
 
1439
        }
 
1440
        for (i = 0; i < bad_html_n; i++) {
 
1441
                while (bad_html[i].s < bad_html[i].e && WHITECHAR(*bad_html[i].s)) bad_html[i].s++;
 
1442
                while (bad_html[i].s < bad_html[i].e && WHITECHAR(bad_html[i].e[-1])) bad_html[i].e--;
 
1443
                if (bad_html[i].s < bad_html[i].e) parse_html(bad_html[i].s, bad_html[i].e, put_chars_f, line_break_f, special_f, gf_val((void *)p, (void *)gp), NULL);
 
1444
        }
 
1445
        mem_free(bad_html);
 
1446
        html_stack_dup();
 
1447
        html_top.dontkill = 1;
 
1448
        par_format.align = AL_LEFT;
 
1449
#ifdef G
 
1450
        if (F) {
 
1451
                t->gp = gp;
 
1452
        } else
 
1453
#endif
 
1454
        {
 
1455
                t->p = p;
 
1456
        }
 
1457
        t->bordercolor = get_attr_val(attr, "bordercolor");
 
1458
        t->align = align;
 
1459
        t->border = border;
 
1460
        t->cellpd = cellpd;
 
1461
        t->vcellpd = vcellpd;
 
1462
        t->cellsp = cellsp;
 
1463
        t->frame = frame;
 
1464
        t->rules = rules;
 
1465
        t->width = width;
 
1466
        t->wf = wf;
 
1467
        cpd_pass = 0;
 
1468
        cpd_last = t->cellpd;
 
1469
        cpd_width = 0;  /* not needed, but let the warning go away */
 
1470
        again:
 
1471
        get_cell_widths(t);
 
1472
        if (get_column_widths(t)) goto ret2;
 
1473
        get_table_width(t);
 
1474
        if (gf_val(!p->data && !p->xp, !gp->data)) {
 
1475
                if (!wf && t->max_t > width) t->max_t = width;
 
1476
                if (t->max_t < t->min_t) t->max_t = t->min_t;
 
1477
                if (t->max_t + (par_format.leftmargin + par_format.rightmargin) * gf_val(1, G_HTML_MARGIN) > gf_val(p->xmax, gp->xmax)) *gf_val(&p->xmax, &gp->xmax) = t->max_t + (par_format.leftmargin + par_format.rightmargin) * gf_val(1, G_HTML_MARGIN);
 
1478
                if (t->min_t + (par_format.leftmargin + par_format.rightmargin) * gf_val(1, G_HTML_MARGIN) > gf_val(p->x, gp->x)) *gf_val(&p->x, &gp->x) = t->min_t + (par_format.leftmargin + par_format.rightmargin) * gf_val(1, G_HTML_MARGIN);
 
1479
                goto ret2;
 
1480
        }
 
1481
        if (!F && !cpd_pass && t->min_t > width && t->cellpd) {
 
1482
                t->cellpd = 0;
 
1483
                cpd_pass = 1;
 
1484
                cpd_width = t->min_t;
 
1485
                goto again;
 
1486
        }
 
1487
        if (cpd_pass == 1 && t->min_t > cpd_width) {
 
1488
                t->cellpd = cpd_last;
 
1489
                cpd_pass = 2;
 
1490
                goto again;
 
1491
        }
 
1492
        /*debug("%d %d %d", t->min_t, t->max_t, width);*/
 
1493
        if (t->min_t >= width) distribute_widths(t, t->min_t);
 
1494
        else if (t->max_t < width && wf) distribute_widths(t, t->max_t);
 
1495
        else distribute_widths(t, width);
 
1496
        if (!F && !p->data && p->xp == 1) {
 
1497
                int ww = t->rw + par_format.leftmargin + par_format.rightmargin;
 
1498
                if (ww > par_format.width) ww = par_format.width;
 
1499
                if (ww < t->rw) ww = t->rw;
 
1500
                if (ww > p->x) p->x = ww;
 
1501
                p->cy += t->rh;
 
1502
                goto ret2;
 
1503
        }
 
1504
#ifdef HTML_TABLE_2ND_PASS
 
1505
        if (!F) check_table_widths(t);
 
1506
#endif
 
1507
        get_table_heights(t);
 
1508
#ifdef G
 
1509
        if (F) {
 
1510
                gp->link_num = t->link_num;
 
1511
                process_g_table(gp, t);
 
1512
                t = NULL;
 
1513
                goto ret3;
 
1514
        }
 
1515
#endif
 
1516
 
 
1517
        x = par_format.leftmargin;
 
1518
        if (align == AL_CENTER) x = (par_format.width + par_format.leftmargin - par_format.rightmargin - t->rw) / 2;
 
1519
        if (align == AL_RIGHT) x = par_format.width - par_format.rightmargin - t->rw;
 
1520
        if (x + t->rw > par_format.width) x = par_format.width - t->rw;
 
1521
        if (x < 0) x = 0;
 
1522
        /*display_table(t, x, p->cy, &cye);*/
 
1523
        if (!p->data) {
 
1524
                if (t->rw + par_format.leftmargin + par_format.rightmargin > p->x) p->x = t->rw + par_format.leftmargin + par_format.rightmargin;
 
1525
                p->cy += t->rh;
 
1526
                goto ret2;
 
1527
        }
 
1528
 
 
1529
        n = p->data->nodes.next;
 
1530
        n->yw = p->yp - n->y + p->cy;
 
1531
        display_complicated_table(t, x, p->cy, &cye);
 
1532
        display_table_frames(t, x, p->cy);
 
1533
        nn = mem_alloc(sizeof(struct node));
 
1534
        nn->x = n->x;
 
1535
        nn->y = p->yp + cye;
 
1536
        nn->xw = n->xw;
 
1537
        add_to_list(p->data->nodes, nn);
 
1538
        /*if (p->cy + t->rh != cye) internal("size does not match; 1:%d, 2:%d", p->cy + t->rh, cye);*/
 
1539
        p->cy = cye;
 
1540
 
 
1541
        ret2:
 
1542
        *gf_val(&p->link_num, &gp->link_num) = t->link_num;
 
1543
#ifdef G
 
1544
        ret3:
 
1545
#endif
 
1546
        if (!F) if (p->cy > p->y) p->y = p->cy;
 
1547
        if (t) free_table(t);
 
1548
        kill_html_stack_item(&html_top);
 
1549
        ret0:
 
1550
        table_level--;
 
1551
        if (!table_level) {
 
1552
                if (!F) free_table_cache();
 
1553
#ifdef G
 
1554
                else g_free_table_cache();
 
1555
#endif
 
1556
        }
 
1557
}
 
1558
 
 
1559
#ifdef G
 
1560
 
 
1561
void add_to_rect_sets(struct rect_set ***s, int *n, struct rect *r)
 
1562
{
 
1563
        int i, j;
 
1564
        for (i = r->y1 >> RECT_BOUND_BITS; i <= (r->y2 - 1) >> RECT_BOUND_BITS; i++) {
 
1565
                if (i >= *n) {
 
1566
                        struct rect_set **ns;
 
1567
                        if ((unsigned)i > MAXINT / sizeof(struct rect_set *) - 1) overalloc();
 
1568
                        ns = mem_realloc(*s, (i + 1) * sizeof(struct rect_set *));
 
1569
                        for (j = *n; j < i + 1; j++) ns[j] = init_rect_set();
 
1570
                        *s = ns;
 
1571
                        *n = i + 1;
 
1572
                }
 
1573
                add_to_rect_set(&(*s)[i], r);
 
1574
        }
 
1575
}
 
1576
 
 
1577
void add_to_cell_sets(struct table_cell ****s, int **nn, int *n, struct rect *r, struct table_cell *c)
 
1578
{
 
1579
        int i, j;
 
1580
        for (i = r->y1 >> RECT_BOUND_BITS; i <= (r->y2 - 1) >> RECT_BOUND_BITS; i++) {
 
1581
                if (i >= *n) {
 
1582
                        struct table_cell ***ns;
 
1583
                        int *nnn;
 
1584
                        if ((unsigned)i > MAXINT / sizeof(struct table_cell ***) - 1) overalloc();
 
1585
                        if ((unsigned)i > MAXINT / sizeof(int *) - 1) overalloc();
 
1586
                        ns = mem_realloc(*s, (i + 1) * sizeof(struct table_cell ***));
 
1587
                        nnn = mem_realloc(*nn, (i + 1) * sizeof(int *));
 
1588
                        for (j = *n; j < i + 1; j++) ns[j] = DUMMY, nnn[j] = 0;
 
1589
                        *s = ns;
 
1590
                        *nn = nnn;
 
1591
                        *n = i + 1;
 
1592
                }
 
1593
                {
 
1594
                        struct table_cell **nc;
 
1595
                        if ((unsigned)(*nn)[i]  > MAXINT / sizeof(struct table_cell *) - 1) overalloc();
 
1596
                        nc = mem_realloc((*s)[i], ((*nn)[i] + 1) * sizeof(struct table_cell *));
 
1597
                        nc[(*nn)[i]] = c;
 
1598
                        (*s)[i] = nc;
 
1599
                        (*nn)[i]++;
 
1600
                }
 
1601
        }
 
1602
}
 
1603
 
 
1604
void table_mouse_event(struct f_data_c *fd, struct g_object_table *o, int x, int y, int b)
 
1605
{
 
1606
        struct table *t = o->t;
 
1607
        int i, j;
 
1608
        for (j = 0; j < t->y; j++) for (i = 0; i < t->x; i++) {
 
1609
                struct table_cell *c = CELL(t, i, j);
 
1610
                if (c->root) if (g_forward_mouse(fd, (struct g_object *)c->root, x, y, b)) return;
 
1611
        }
 
1612
}
 
1613
 
 
1614
void draw_rect_set(struct graphics_device *dev, struct background *bg, struct rect_set *rs, int x, int y)
 
1615
{
 
1616
        int i;
 
1617
        for (i = 0; i < rs->m; i++) {
 
1618
                struct rect *r = &rs->r[i];
 
1619
                if (is_rect_valid(r))
 
1620
                        g_draw_background(dev, bg, x + r->x1, y + r->y1, r->x2 - r->x1, r->y2 - r->y1);
 
1621
        }
 
1622
}
 
1623
 
 
1624
void draw_rect_sets(struct graphics_device *dev, struct background *bg, struct rect_set **rs, int nrs, int x, int y)
 
1625
{
 
1626
        int i;
 
1627
        for (i = (dev->clip.y1 - y) >> RECT_BOUND_BITS; i <= (dev->clip.y2 - y - 1) >> RECT_BOUND_BITS; i++) if (i >= 0 && i < nrs) {
 
1628
                draw_rect_set(dev, bg, rs[i], x, y);
 
1629
        }
 
1630
}
 
1631
 
 
1632
void table_draw(struct f_data_c *fd, struct g_object_table *o, int x, int y)
 
1633
{
 
1634
        static int dgen = 1;
 
1635
        int i, j;
 
1636
        struct table *t = o->t;
 
1637
        struct graphics_device *dev = fd->ses->term->dev;
 
1638
        dgen++;
 
1639
        /*
 
1640
        for (j = 0; j < t->y; j++) for (i = 0; i < t->x; i++) {
 
1641
                struct table_cell *c = CELL(t, i, j);*/
 
1642
        /*
 
1643
        fprintf(stderr, "Y: %d %d\n", x, y);
 
1644
        fprintf(stderr, "bounds: %d %d\n", dev->clip.y1 + y, dev->clip.y2 + y);
 
1645
        */
 
1646
        for (i = (dev->clip.y1 - y) >> RECT_BOUND_BITS; i <= (dev->clip.y2 - y - 1) >> RECT_BOUND_BITS; i++) if (i >= 0 && i < t->nr_cells) for (j = 0; j < t->w_cells[i]; j++) {
 
1647
                struct table_cell *c = t->r_cells[i][j];
 
1648
                /*fprintf(stderr, "draw: %d %d\n", i, j);*/
 
1649
                if (c->root && c->dgen != dgen) {
 
1650
                        struct rect clip;
 
1651
                        memcpy(&clip, &c->rect, sizeof(struct rect));
 
1652
                        clip.x1 += x;
 
1653
                        clip.x2 += x;
 
1654
                        clip.y1 += y;
 
1655
                        clip.y2 += y;
 
1656
                        if (!do_rects_intersect(&clip, &dev->clip)) continue;
 
1657
                        draw_rect_set(dev, c->root->bg, c->brd, x, y);
 
1658
                        restrict_clip_area(dev, &clip, x + c->root->x, y + c->root->y, x + c->root->x + c->root->xw/*c->g_width*/, y + c->root->y + c->root->yw);
 
1659
                        c->root->draw(fd, c->root, x + c->root->x, y + c->root->y);
 
1660
                        drv->set_clip_area(dev, &clip);
 
1661
                        c->dgen = dgen;
 
1662
                }
 
1663
        }
 
1664
        draw_rect_sets(dev, t->bg, t->r_bg, t->nr_bg, x, y);
 
1665
        draw_rect_sets(dev, t->frame_bg, t->r_frame, t->nr_frame, x, y);
 
1666
}
 
1667
 
 
1668
void table_destruct(struct g_object_table *o)
 
1669
{
 
1670
        free_table(o->t);
 
1671
        mem_free(o);
 
1672
}
 
1673
 
 
1674
void table_get_list(struct g_object_table *o, void (*fn)(struct g_object *parent, struct g_object *child))
 
1675
{
 
1676
        struct table *t = o->t;
 
1677
        int i, j;
 
1678
        for (j = 0; j < t->y; j++) for (i = 0; i < t->x; i++) {
 
1679
                struct table_cell *c = CELL(t, i, j);
 
1680
                if (c->root) fn((struct g_object *)o, (struct g_object *)c->root);
 
1681
        }
 
1682
}
 
1683
 
 
1684
void table_bg(struct text_attrib *ta, unsigned char bgstr[8])
 
1685
{
 
1686
        if (ta->bg.r + ta->bg.g * 3 + ta->bg.b * 5 > 9 * 128) strcpy(bgstr, "#000000");
 
1687
        else if (ta->fg.r > G_HTML_TABLE_FRAME_COLOR && ta->fg.g > G_HTML_TABLE_FRAME_COLOR && ta->fg.b > G_HTML_TABLE_FRAME_COLOR) {
 
1688
                unsigned char max = ta->fg.r;
 
1689
                if (ta->fg.g > max) max = ta->fg.g;
 
1690
                if (ta->fg.b > max) max = ta->fg.b;
 
1691
                max &= 0xff;
 
1692
                sprintf(bgstr, "#%02x%02x%02x", max, max, max);
 
1693
        } else sprintf(bgstr, "#%02x%02x%02x", G_HTML_TABLE_FRAME_COLOR, G_HTML_TABLE_FRAME_COLOR, G_HTML_TABLE_FRAME_COLOR);
 
1694
}
 
1695
 
 
1696
void process_g_table(struct g_part *gp, struct table *t)
 
1697
{
 
1698
        int i, j;
 
1699
        int x, y;
 
1700
        struct g_object_table *o;
 
1701
        signed char *fv, *fh;
 
1702
        unsigned char bgstr[8];
 
1703
        struct text_attrib *ta;
 
1704
        struct rgb dummy;
 
1705
        y = 0;
 
1706
        for (j = 0; j < t->y; j++) {
 
1707
                x = 0;
 
1708
                y += g_get_hline_pad(t, j, NULL, NULL);
 
1709
                for (i = 0; i < t->x; i++) {
 
1710
                        struct table_cell *c;
 
1711
                        x += g_get_vline_pad(t, i, NULL, NULL);
 
1712
                        c = CELL(t, i, j);
 
1713
                        if (c->root) {
 
1714
                                int s;
 
1715
                                int yw = 0;
 
1716
                                for (s = 0; s < c->rowspan; s++) {
 
1717
                                        yw += t->r_heights[j + s];
 
1718
                                        if (s < c->rowspan - 1) yw += g_get_hline_pad(t, j + s + 1, NULL, NULL);
 
1719
                                }
 
1720
                                c->root->x = x, c->root->y = y;
 
1721
                                c->root->y += c->valign != VAL_MIDDLE && c->valign != VAL_BOTTOM ? 0 : (yw - c->root->yw) / (c->valign == VAL_MIDDLE ? 2 : 1);
 
1722
                        }
 
1723
                        x += t->w_c[i];
 
1724
                }
 
1725
                y += t->r_heights[j];
 
1726
        }
 
1727
 
 
1728
        if (html_top.next != (struct html_element *)(void *)&html_stack) ta = &html_top.next->attr;
 
1729
        else ta = &format;
 
1730
 
 
1731
        if (t->bordercolor && !decode_color(t->bordercolor, &dummy)) {
 
1732
                if (!(t->frame_bg = get_background(NULL, t->bordercolor))) {
 
1733
                        free_table(t);
 
1734
                        return;
 
1735
                }
 
1736
        } else {
 
1737
                table_bg(ta, bgstr);
 
1738
                if (!(t->frame_bg = get_background(NULL, bgstr))) {
 
1739
                        free_table(t);
 
1740
                        return;
 
1741
                }
 
1742
        }
 
1743
 
 
1744
        if ((unsigned)t->x > MAXINT) overalloc();
 
1745
        if ((unsigned)t->y > MAXINT) overalloc();
 
1746
        if (((unsigned)t->x + 2) * ((unsigned)t->y + 2) / ((unsigned)t->x + 2) != ((unsigned)t->y + 2)) overalloc();
 
1747
        if (((unsigned)t->x + 2) * ((unsigned)t->y + 2) > MAXINT) overalloc();
 
1748
        fh = mem_alloc((t->x + 2) * (t->y + 1));
 
1749
        fv = mem_alloc((t->x + 1) * (t->y + 2));
 
1750
        get_table_frame(t, fv, fh);
 
1751
        y = 0;
 
1752
        for (j = 0; j <= t->y; j++) {
 
1753
                int ypad, ypos, ysize;
 
1754
                ypad = g_get_hline_pad(t, j, &ypos, &ysize);
 
1755
                x = 0;
 
1756
                for (i = 0; i <= t->x; i++) {
 
1757
                        struct rect r;
 
1758
                        int xpad, xpos, xsize;
 
1759
                        xpad = g_get_vline_pad(t, i, &xpos, &xsize);
 
1760
                        if (i < t->x && j < t->y) {
 
1761
                                CELL(t, i, j)->xpos = x + xpos + xsize;
 
1762
                                CELL(t, i, j)->ypos = y + ypos + ysize;
 
1763
                        }
 
1764
                        if (i > 0 && j > 0) {
 
1765
                                struct table_cell *c = CELL(t, i - 1, j - 1);
 
1766
                                c->xw = x + xpos - c->xpos;
 
1767
                                c->yw = y + ypos - c->ypos;
 
1768
                                /*debug("C: %d %d %d %d", c->xpos, c->ypos, c->xw, c->yw);*/
 
1769
                                /*debug("%d %d %d", y, ypos, c->ypos);*/
 
1770
                                if (!c->used && !c->spanned) {
 
1771
                                        r.x1 = c->xpos, r.x2 = c->xpos + c->xw;
 
1772
                                        r.y1 = c->ypos, r.y2 = c->ypos + c->yw;
 
1773
                                        add_to_rect_sets(&t->r_bg, &t->nr_bg, &r);
 
1774
                                }
 
1775
                        }
 
1776
                        r.x1 = x + xpos, r.x2 = x + xpos + xsize;
 
1777
                        r.y1 = y + ypos, r.y2 = y + ypos + ysize;
 
1778
                        if (H_LINE(i-1,j) || H_LINE(i,j) || V_LINE(i,j-1) || V_LINE(i,j))
 
1779
                                add_to_rect_sets(&t->r_frame, &t->nr_frame, &r);
 
1780
                        else if (H_LINE_X(i-1,j) != -2 || H_LINE_X(i,j) != -2 || V_LINE_X(i,j-1) != -2 || V_LINE_X(i,j) != -2) add_to_rect_sets(&t->r_bg, &t->nr_bg, &r);
 
1781
                        if (i < t->x) {
 
1782
                                int l;
 
1783
                                int b;
 
1784
                                g_get_vline_pad(t, i + 1, &b, NULL);
 
1785
                                r.x1 = r.x2;
 
1786
                                r.x2 = x + xpad + t->w_c[i] + b;
 
1787
                                l = H_LINE_X(i,j);
 
1788
                                if (l == -2) ;
 
1789
                                else if (l > 0) add_to_rect_sets(&t->r_frame, &t->nr_frame, &r);
 
1790
                                else add_to_rect_sets(&t->r_bg, &t->nr_bg, &r);
 
1791
                        }
 
1792
                        r.x1 = x + xpos, r.x2 = x + xpos + xsize;
 
1793
                        if (j < t->y) {
 
1794
                                int l;
 
1795
                                int b;
 
1796
                                g_get_hline_pad(t, j + 1, &b, NULL);
 
1797
                                r.y1 = r.y2;
 
1798
                                r.y2 = y + ypad + t->r_heights[j] + b;
 
1799
                                l = V_LINE_X(i,j);
 
1800
                                if (l == -2) ;
 
1801
                                else if (l > 0) add_to_rect_sets(&t->r_frame, &t->nr_frame, &r);
 
1802
                                else add_to_rect_sets(&t->r_bg, &t->nr_bg, &r);
 
1803
                        }
 
1804
                        if (i < t->x) x += xpad + t->w_c[i];
 
1805
                }
 
1806
                if (j < t->y) y += ypad + t->r_heights[j];
 
1807
        }
 
1808
 
 
1809
        for (j = 0; j < t->y; j++) for (i = 0; i < t->x; i++) {
 
1810
                struct table_cell *c = CELL(t, i, j);
 
1811
                if (c->used && !c->spanned && c->root) {
 
1812
                        struct table_cell *d = CELL(t, i + c->colspan - 1, j + c->rowspan - 1);
 
1813
                        struct rect r;
 
1814
                        r.x1 = c->xpos;
 
1815
                        r.y1 = c->ypos;
 
1816
                        r.x2 = d->xpos + d->xw;
 
1817
                        r.y2 = d->ypos + d->yw;
 
1818
                        add_to_cell_sets(&t->r_cells, &t->w_cells, &t->nr_cells, &r, c);
 
1819
                        memcpy(&c->rect, &r, sizeof(struct rect));
 
1820
                        c->brd = init_rect_set();
 
1821
                        /*debug("%d,%d %d,%d", r.x1, r.y1, r.x2, r.y2);*/
 
1822
                        add_to_rect_set(&c->brd, &r);
 
1823
                        r.x1 = c->root->x;
 
1824
                        r.y1 = c->root->y;
 
1825
                        r.x2 = c->root->x + c->root->xw;
 
1826
                        r.y2 = c->root->y + c->root->yw;
 
1827
                        exclude_rect_from_set(&c->brd, &r);
 
1828
                        /*debug("%d,%d %d,%d", r.x1, r.y1, r.x2, r.y2);*/
 
1829
                }
 
1830
        }
 
1831
 
 
1832
        mem_free(fh);
 
1833
        mem_free(fv);
 
1834
 
 
1835
        o = mem_calloc(sizeof(struct g_object_table));
 
1836
        o->mouse_event = table_mouse_event;
 
1837
        o->draw = table_draw;
 
1838
        o->destruct = table_destruct;
 
1839
        o->get_list = table_get_list;
 
1840
        o->xw = t->rw;
 
1841
        o->yw = t->rh;
 
1842
        o->t = t;
 
1843
        t->bg = gp->root->bg;
 
1844
        flush_pending_text_to_line(gp);
 
1845
        flush_pending_line_to_obj(gp, 0);
 
1846
        gp->cx = -1;
 
1847
        gp->cx_w = 0;
 
1848
        add_object_to_line(gp, &gp->line, (struct g_object *)o);
 
1849
        flush_pending_text_to_line(gp);
 
1850
        par_format.align = t->align;
 
1851
        flush_pending_line_to_obj(gp, 0);
 
1852
        gp->cx = -1;
 
1853
        gp->cx_w = 0;
 
1854
}
 
1855
 
 
1856
#endif