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