table.c (85799B)
1 /* $Id$ */ 2 /* 3 * HTML table 4 */ 5 #include <sys/types.h> 6 #include <stdio.h> 7 #include <string.h> 8 #include <math.h> 9 #include "fm.h" 10 #include "html.h" 11 #include "parsetagx.h" 12 #include "Str.h" 13 #include "myctype.h" 14 15 int symbol_width = 0; 16 int symbol_width0 = 0; 17 18 #define RULE_WIDTH symbol_width 19 #define RULE(mode,n) (((mode) == BORDER_THICK) ? ((n) + 16) : (n)) 20 #define TK_VERTICALBAR(mode) RULE(mode,5) 21 22 #define BORDERWIDTH 2 23 #define BORDERHEIGHT 1 24 #define NOBORDERWIDTH 1 25 #define NOBORDERHEIGHT 0 26 27 #define HTT_X 1 28 #define HTT_Y 2 29 #define HTT_ALIGN 0x30 30 #define HTT_LEFT 0x00 31 #define HTT_CENTER 0x10 32 #define HTT_RIGHT 0x20 33 #define HTT_TRSET 0x40 34 #define HTT_VALIGN 0x700 35 #define HTT_TOP 0x100 36 #define HTT_MIDDLE 0x200 37 #define HTT_BOTTOM 0x400 38 #define HTT_VTRSET 0x800 39 #ifdef NOWRAP 40 #define HTT_NOWRAP 4 41 #endif /* NOWRAP */ 42 #define TAG_IS(s,tag,len) (strncasecmp(s,tag,len)==0&&(s[len] == '>' || IS_SPACE((int)s[len]))) 43 44 #ifndef max 45 #define max(a,b) ((a) > (b) ? (a) : (b)) 46 #endif /* not max */ 47 #ifndef min 48 #define min(a,b) ((a) > (b) ? (b) : (a)) 49 #endif /* not min */ 50 #ifndef abs 51 #define abs(a) ((a) >= 0. ? (a) : -(a)) 52 #endif /* not abs */ 53 54 #define set_prevchar(x,y,n) Strcopy_charp_n((x),(y),(n)) 55 #define set_space_to_prevchar(x) Strcopy_charp_n((x)," ",1) 56 57 #ifdef MATRIX 58 #ifndef MESCHACH 59 #include "matrix.c" 60 #endif /* not MESCHACH */ 61 #endif /* MATRIX */ 62 63 #ifdef MATRIX 64 int correct_table_matrix(struct table *, int, int, int, double); 65 void set_table_matrix(struct table *, int); 66 #endif /* MATRIX */ 67 68 #ifdef MATRIX 69 static double 70 weight(int x) 71 { 72 73 if (x < COLS) 74 return (double)x; 75 else 76 return COLS * (log((double)x / COLS) + 1.); 77 } 78 79 static double 80 weight2(int a) 81 { 82 return (double)a / COLS * 4 + 1.; 83 } 84 85 #define sigma_td(a) (0.5*weight2(a)) /* <td width=...> */ 86 #define sigma_td_nw(a) (32*weight2(a)) /* <td ...> */ 87 #define sigma_table(a) (0.25*weight2(a)) /* <table width=...> */ 88 #define sigma_table_nw(a) (2*weight2(a)) /* <table...> */ 89 #else /* not MATRIX */ 90 #define LOG_MIN 1.0 91 static double 92 weight3(int x) 93 { 94 if (x < 0.1) 95 return 0.1; 96 if (x < LOG_MIN) 97 return (double)x; 98 else 99 return LOG_MIN * (log((double)x / LOG_MIN) + 1.); 100 } 101 #endif /* not MATRIX */ 102 103 static int 104 bsearch_2short(short e1, short *ent1, short e2, short *ent2, int base, 105 short *indexarray, int nent) 106 { 107 int n = nent; 108 int k = 0; 109 110 int e = e1 * base + e2; 111 while (n > 0) { 112 int nn = n / 2; 113 int idx = indexarray[k + nn]; 114 int ne = ent1[idx] * base + ent2[idx]; 115 if (ne == e) { 116 k += nn; 117 break; 118 } 119 else if (ne < e) { 120 n -= nn + 1; 121 k += nn + 1; 122 } 123 else { 124 n = nn; 125 } 126 } 127 return k; 128 } 129 130 static int 131 bsearch_double(double e, double *ent, short *indexarray, int nent) 132 { 133 int n = nent; 134 int k = 0; 135 136 while (n > 0) { 137 int nn = n / 2; 138 int idx = indexarray[k + nn]; 139 double ne = ent[idx]; 140 if (ne == e) { 141 k += nn; 142 break; 143 } 144 else if (ne > e) { 145 n -= nn + 1; 146 k += nn + 1; 147 } 148 else { 149 n = nn; 150 } 151 } 152 return k; 153 } 154 155 static int 156 ceil_at_intervals(int x, int step) 157 { 158 int mo = x % step; 159 if (mo > 0) 160 x += step - mo; 161 else if (mo < 0) 162 x -= mo; 163 return x; 164 } 165 166 static int 167 floor_at_intervals(int x, int step) 168 { 169 int mo = x % step; 170 if (mo > 0) 171 x -= mo; 172 else if (mo < 0) 173 x += step - mo; 174 return x; 175 } 176 177 #define round(x) ((int)floor((x)+0.5)) 178 179 #ifndef MATRIX 180 static void 181 dv2sv(double *dv, short *iv, int size) 182 { 183 int i, k, iw; 184 short *indexarray; 185 double *edv; 186 double w = 0., x; 187 188 indexarray = NewAtom_N(short, size); 189 edv = NewAtom_N(double, size); 190 for (i = 0; i < size; i++) { 191 iv[i] = ceil(dv[i]); 192 edv[i] = (double)iv[i] - dv[i]; 193 } 194 195 w = 0.; 196 for (k = 0; k < size; k++) { 197 x = edv[k]; 198 w += x; 199 i = bsearch_double(x, edv, indexarray, k); 200 if (k > i) { 201 int ii; 202 for (ii = k; ii > i; ii--) 203 indexarray[ii] = indexarray[ii - 1]; 204 } 205 indexarray[i] = k; 206 } 207 iw = min((int)(w + 0.5), size); 208 if (iw == 0) 209 return; 210 x = edv[(int)indexarray[iw - 1]]; 211 for (i = 0; i < size; i++) { 212 k = indexarray[i]; 213 if (i >= iw && abs(edv[k] - x) > 1e-6) 214 break; 215 iv[k]--; 216 } 217 } 218 #endif 219 220 static int 221 table_colspan(struct table *t, int row, int col) 222 { 223 int i; 224 for (i = col + 1; i <= t->maxcol && (t->tabattr[row][i] & HTT_X); i++) ; 225 return i - col; 226 } 227 228 static int 229 table_rowspan(struct table *t, int row, int col) 230 { 231 int i; 232 if (!t->tabattr[row]) 233 return 0; 234 for (i = row + 1; i <= t->maxrow && t->tabattr[i] && 235 (t->tabattr[i][col] & HTT_Y); i++) ; 236 return i - row; 237 } 238 239 static int 240 minimum_cellspacing(int border_mode) 241 { 242 switch (border_mode) { 243 case BORDER_THIN: 244 case BORDER_THICK: 245 case BORDER_NOWIN: 246 return RULE_WIDTH; 247 case BORDER_NONE: 248 return 1; 249 default: 250 /* not reached */ 251 return 0; 252 } 253 } 254 255 static int 256 table_border_width(struct table *t) 257 { 258 switch (t->border_mode) { 259 case BORDER_THIN: 260 case BORDER_THICK: 261 return t->maxcol * t->cellspacing + 2 * (RULE_WIDTH + t->cellpadding); 262 case BORDER_NOWIN: 263 case BORDER_NONE: 264 return t->maxcol * t->cellspacing; 265 default: 266 /* not reached */ 267 return 0; 268 } 269 } 270 271 struct table * 272 newTable() 273 { 274 struct table *t; 275 int i, j; 276 277 t = New(struct table); 278 t->max_rowsize = MAXROW; 279 t->tabdata = New_N(GeneralList **, MAXROW); 280 t->tabattr = New_N(table_attr *, MAXROW); 281 t->tabheight = NewAtom_N(short, MAXROW); 282 #ifdef ID_EXT 283 t->tabidvalue = New_N(Str *, MAXROW); 284 t->tridvalue = New_N(Str, MAXROW); 285 #endif /* ID_EXT */ 286 287 for (i = 0; i < MAXROW; i++) { 288 t->tabdata[i] = NULL; 289 t->tabattr[i] = 0; 290 t->tabheight[i] = 0; 291 #ifdef ID_EXT 292 t->tabidvalue[i] = NULL; 293 t->tridvalue[i] = NULL; 294 #endif /* ID_EXT */ 295 } 296 for (j = 0; j < MAXCOL; j++) { 297 t->tabwidth[j] = 0; 298 t->minimum_width[j] = 0; 299 t->fixed_width[j] = 0; 300 } 301 t->cell.maxcell = -1; 302 t->cell.icell = -1; 303 t->ntable = 0; 304 t->tables_size = 0; 305 t->tables = NULL; 306 #ifdef MATRIX 307 t->matrix = NULL; 308 t->vector = NULL; 309 #endif /* MATRIX */ 310 #if 0 311 t->tabcontentssize = 0; 312 t->indent = 0; 313 t->linfo.prev_ctype = PC_ASCII; 314 t->linfo.prev_spaces = -1; 315 #endif 316 t->linfo.prevchar = Strnew_size(8); 317 set_prevchar(t->linfo.prevchar, "", 0); 318 t->trattr = 0; 319 320 t->caption = Strnew(); 321 t->suspended_data = NULL; 322 #ifdef ID_EXT 323 t->id = NULL; 324 #endif 325 return t; 326 } 327 328 static void 329 check_row(struct table *t, int row) 330 { 331 int i, r; 332 GeneralList ***tabdata; 333 table_attr **tabattr; 334 short *tabheight; 335 #ifdef ID_EXT 336 Str **tabidvalue; 337 Str *tridvalue; 338 #endif /* ID_EXT */ 339 340 if (row >= t->max_rowsize) { 341 r = max(t->max_rowsize * 2, row + 1); 342 tabdata = New_N(GeneralList **, r); 343 tabattr = New_N(table_attr *, r); 344 tabheight = NewAtom_N(short, r); 345 #ifdef ID_EXT 346 tabidvalue = New_N(Str *, r); 347 tridvalue = New_N(Str, r); 348 #endif /* ID_EXT */ 349 for (i = 0; i < t->max_rowsize; i++) { 350 tabdata[i] = t->tabdata[i]; 351 tabattr[i] = t->tabattr[i]; 352 tabheight[i] = t->tabheight[i]; 353 #ifdef ID_EXT 354 tabidvalue[i] = t->tabidvalue[i]; 355 tridvalue[i] = t->tridvalue[i]; 356 #endif /* ID_EXT */ 357 } 358 for (; i < r; i++) { 359 tabdata[i] = NULL; 360 tabattr[i] = NULL; 361 tabheight[i] = 0; 362 #ifdef ID_EXT 363 tabidvalue[i] = NULL; 364 tridvalue[i] = NULL; 365 #endif /* ID_EXT */ 366 } 367 t->tabdata = tabdata; 368 t->tabattr = tabattr; 369 t->tabheight = tabheight; 370 #ifdef ID_EXT 371 t->tabidvalue = tabidvalue; 372 t->tridvalue = tridvalue; 373 #endif /* ID_EXT */ 374 t->max_rowsize = r; 375 } 376 377 if (t->tabdata[row] == NULL) { 378 t->tabdata[row] = New_N(GeneralList *, MAXCOL); 379 t->tabattr[row] = NewAtom_N(table_attr, MAXCOL); 380 #ifdef ID_EXT 381 t->tabidvalue[row] = New_N(Str, MAXCOL); 382 #endif /* ID_EXT */ 383 for (i = 0; i < MAXCOL; i++) { 384 t->tabdata[row][i] = NULL; 385 t->tabattr[row][i] = 0; 386 #ifdef ID_EXT 387 t->tabidvalue[row][i] = NULL; 388 #endif /* ID_EXT */ 389 } 390 } 391 } 392 393 void 394 pushdata(struct table *t, int row, int col, char *data) 395 { 396 check_row(t, row); 397 if (t->tabdata[row][col] == NULL) 398 t->tabdata[row][col] = newGeneralList(); 399 400 pushText(t->tabdata[row][col], data ? data : ""); 401 } 402 403 void 404 suspend_or_pushdata(struct table *tbl, char *line) 405 { 406 if (tbl->flag & TBL_IN_COL) 407 pushdata(tbl, tbl->row, tbl->col, line); 408 else { 409 if (!tbl->suspended_data) 410 tbl->suspended_data = newTextList(); 411 pushText(tbl->suspended_data, line ? line : ""); 412 } 413 } 414 415 #ifdef USE_M17N 416 #define PUSH_TAG(str,n) Strcat_charp_n(tagbuf, str, n) 417 #else 418 #define PUSH_TAG(str,n) Strcat_char(tagbuf, *str) 419 #endif 420 421 int visible_length_offset = 0; 422 int 423 visible_length(char *str) 424 { 425 int len = 0, n, max_len = 0; 426 int status = R_ST_NORMAL; 427 int prev_status = status; 428 Str tagbuf = Strnew(); 429 char *t, *r2; 430 int amp_len = 0; 431 432 t = str; 433 while (*str) { 434 prev_status = status; 435 if (next_status(*str, &status)) { 436 #ifdef USE_M17N 437 len += get_mcwidth(str); 438 n = get_mclen(str); 439 } 440 else { 441 n = 1; 442 } 443 #else 444 len++; 445 } 446 #endif 447 if (status == R_ST_TAG0) { 448 Strclear(tagbuf); 449 PUSH_TAG(str, n); 450 } 451 else if (status == R_ST_TAG || status == R_ST_DQUOTE 452 || status == R_ST_QUOTE || status == R_ST_EQL 453 || status == R_ST_VALUE) { 454 PUSH_TAG(str, n); 455 } 456 else if (status == R_ST_AMP) { 457 if (prev_status == R_ST_NORMAL) { 458 Strclear(tagbuf); 459 len--; 460 amp_len = 0; 461 } 462 else { 463 PUSH_TAG(str, n); 464 amp_len++; 465 } 466 } 467 else if (status == R_ST_NORMAL && prev_status == R_ST_AMP) { 468 PUSH_TAG(str, n); 469 r2 = tagbuf->ptr; 470 t = getescapecmd(&r2); 471 if (!*r2 && (*t == '\r' || *t == '\n')) { 472 if (len > max_len) 473 max_len = len; 474 len = 0; 475 } 476 else 477 len += get_strwidth(t) + get_strwidth(r2); 478 } 479 else if (status == R_ST_NORMAL && ST_IS_REAL_TAG(prev_status)) { 480 ; 481 } 482 else if (*str == '\t') { 483 len--; 484 do { 485 len++; 486 } while ((visible_length_offset + len) % Tabstop != 0); 487 } 488 else if (*str == '\r' || *str == '\n') { 489 len--; 490 if (len > max_len) 491 max_len = len; 492 len = 0; 493 } 494 #ifdef USE_M17N 495 str += n; 496 #else 497 str++; 498 #endif 499 } 500 if (status == R_ST_AMP) { 501 r2 = tagbuf->ptr; 502 t = getescapecmd(&r2); 503 if (*t != '\r' && *t != '\n') 504 len += get_strwidth(t) + get_strwidth(r2); 505 } 506 return len > max_len ? len : max_len; 507 } 508 509 int 510 visible_length_plain(char *str) 511 { 512 int len = 0, max_len = 0; 513 514 while (*str) { 515 if (*str == '\t') { 516 do { 517 len++; 518 } while ((visible_length_offset + len) % Tabstop != 0); 519 str++; 520 } 521 else if (*str == '\r' || *str == '\n') { 522 if (len > max_len) 523 max_len = len; 524 len = 0; 525 str++; 526 } 527 else { 528 #ifdef USE_M17N 529 len += get_mcwidth(str); 530 str += get_mclen(str); 531 #else 532 len++; 533 str++; 534 #endif 535 } 536 } 537 return len > max_len ? len : max_len; 538 } 539 540 static int 541 maximum_visible_length(char *str, int offset) 542 { 543 visible_length_offset = offset; 544 return visible_length(str); 545 } 546 547 static int 548 maximum_visible_length_plain(char *str, int offset) 549 { 550 visible_length_offset = offset; 551 return visible_length_plain(str); 552 } 553 554 void 555 align(TextLine *lbuf, int width, int mode) 556 { 557 int i, l, l1, l2; 558 Str buf, line = lbuf->line; 559 560 if (line->length == 0) { 561 for (i = 0; i < width; i++) 562 Strcat_char(line, ' '); 563 lbuf->pos = width; 564 return; 565 } 566 buf = Strnew(); 567 l = width - lbuf->pos; 568 switch (mode) { 569 case ALIGN_CENTER: 570 l1 = l / 2; 571 l2 = l - l1; 572 for (i = 0; i < l1; i++) 573 Strcat_char(buf, ' '); 574 Strcat(buf, line); 575 for (i = 0; i < l2; i++) 576 Strcat_char(buf, ' '); 577 break; 578 case ALIGN_LEFT: 579 Strcat(buf, line); 580 for (i = 0; i < l; i++) 581 Strcat_char(buf, ' '); 582 break; 583 case ALIGN_RIGHT: 584 for (i = 0; i < l; i++) 585 Strcat_char(buf, ' '); 586 Strcat(buf, line); 587 break; 588 default: 589 return; 590 } 591 lbuf->line = buf; 592 if (lbuf->pos < width) 593 lbuf->pos = width; 594 } 595 596 void 597 print_item(struct table *t, int row, int col, int width, Str buf) 598 { 599 int alignment; 600 TextLine *lbuf; 601 602 if (t->tabdata[row]) 603 lbuf = popTextLine(t->tabdata[row][col]); 604 else 605 lbuf = NULL; 606 607 if (lbuf != NULL) { 608 check_row(t, row); 609 alignment = ALIGN_CENTER; 610 if ((t->tabattr[row][col] & HTT_ALIGN) == HTT_LEFT) 611 alignment = ALIGN_LEFT; 612 else if ((t->tabattr[row][col] & HTT_ALIGN) == HTT_RIGHT) 613 alignment = ALIGN_RIGHT; 614 else if ((t->tabattr[row][col] & HTT_ALIGN) == HTT_CENTER) 615 alignment = ALIGN_CENTER; 616 align(lbuf, width, alignment); 617 Strcat(buf, lbuf->line); 618 } 619 else { 620 lbuf = newTextLine(NULL, 0); 621 align(lbuf, width, ALIGN_CENTER); 622 Strcat(buf, lbuf->line); 623 } 624 } 625 626 627 #define T_TOP 0 628 #define T_MIDDLE 1 629 #define T_BOTTOM 2 630 631 void 632 print_sep(struct table *t, int row, int type, int maxcol, Str buf) 633 { 634 int forbid; 635 int rule_mode; 636 int i, k, l, m; 637 638 if (row >= 0) 639 check_row(t, row); 640 check_row(t, row + 1); 641 if ((type == T_TOP || type == T_BOTTOM) && t->border_mode == BORDER_THICK) { 642 rule_mode = BORDER_THICK; 643 } 644 else { 645 rule_mode = BORDER_THIN; 646 } 647 forbid = 1; 648 if (type == T_TOP) 649 forbid |= 2; 650 else if (type == T_BOTTOM) 651 forbid |= 8; 652 else if (t->tabattr[row + 1][0] & HTT_Y) { 653 forbid |= 4; 654 } 655 if (t->border_mode != BORDER_NOWIN) { 656 push_symbol(buf, RULE(t->border_mode, forbid), symbol_width, 1); 657 } 658 for (i = 0; i <= maxcol; i++) { 659 forbid = 10; 660 if (type != T_BOTTOM && (t->tabattr[row + 1][i] & HTT_Y)) { 661 if (t->tabattr[row + 1][i] & HTT_X) { 662 goto do_last_sep; 663 } 664 else { 665 for (k = row; 666 k >= 0 && t->tabattr[k] && (t->tabattr[k][i] & HTT_Y); 667 k--) ; 668 m = t->tabwidth[i] + 2 * t->cellpadding; 669 for (l = i + 1; l <= t->maxcol && (t->tabattr[row][l] & HTT_X); 670 l++) 671 m += t->tabwidth[l] + t->cellspacing; 672 print_item(t, k, i, m, buf); 673 } 674 } 675 else { 676 int w = t->tabwidth[i] + 2 * t->cellpadding; 677 if (RULE_WIDTH == 2) 678 w = (w + 1) / RULE_WIDTH; 679 push_symbol(buf, RULE(rule_mode, forbid), symbol_width, w); 680 } 681 do_last_sep: 682 if (i < maxcol) { 683 forbid = 0; 684 if (type == T_TOP) 685 forbid |= 2; 686 else if (t->tabattr[row][i + 1] & HTT_X) { 687 forbid |= 2; 688 } 689 if (type == T_BOTTOM) 690 forbid |= 8; 691 else { 692 if (t->tabattr[row + 1][i + 1] & HTT_X) { 693 forbid |= 8; 694 } 695 if (t->tabattr[row + 1][i + 1] & HTT_Y) { 696 forbid |= 4; 697 } 698 if (t->tabattr[row + 1][i] & HTT_Y) { 699 forbid |= 1; 700 } 701 } 702 if (forbid != 15) /* forbid==15 means 'no rule at all' */ 703 push_symbol(buf, RULE(rule_mode, forbid), symbol_width, 1); 704 } 705 } 706 forbid = 4; 707 if (type == T_TOP) 708 forbid |= 2; 709 if (type == T_BOTTOM) 710 forbid |= 8; 711 if (t->tabattr[row + 1][maxcol] & HTT_Y) { 712 forbid |= 1; 713 } 714 if (t->border_mode != BORDER_NOWIN) 715 push_symbol(buf, RULE(t->border_mode, forbid), symbol_width, 1); 716 } 717 718 static int 719 get_spec_cell_width(struct table *tbl, int row, int col) 720 { 721 int i, w; 722 723 w = tbl->tabwidth[col]; 724 for (i = col + 1; i <= tbl->maxcol; i++) { 725 check_row(tbl, row); 726 if (tbl->tabattr[row][i] & HTT_X) 727 w += tbl->tabwidth[i] + tbl->cellspacing; 728 else 729 break; 730 } 731 return w; 732 } 733 734 void 735 do_refill(struct table *tbl, int row, int col, int maxlimit) 736 { 737 TextList *orgdata; 738 TextListItem *l; 739 struct readbuffer obuf; 740 struct html_feed_environ h_env; 741 struct environment envs[MAX_ENV_LEVEL]; 742 int colspan, icell; 743 744 if (tbl->tabdata[row] == NULL || tbl->tabdata[row][col] == NULL) 745 return; 746 orgdata = (TextList *)tbl->tabdata[row][col]; 747 tbl->tabdata[row][col] = newGeneralList(); 748 749 init_henv(&h_env, &obuf, envs, MAX_ENV_LEVEL, 750 (TextLineList *)tbl->tabdata[row][col], 751 get_spec_cell_width(tbl, row, col), 0); 752 obuf.flag |= RB_INTABLE; 753 if (h_env.limit > maxlimit) 754 h_env.limit = maxlimit; 755 if (tbl->border_mode != BORDER_NONE && tbl->vcellpadding > 0) 756 do_blankline(&h_env, &obuf, 0, 0, h_env.limit); 757 for (l = orgdata->first; l != NULL; l = l->next) { 758 if (TAG_IS(l->ptr, "<table_alt", 10)) { 759 int id = -1; 760 char *p = l->ptr; 761 struct parsed_tag *tag; 762 if ((tag = parse_tag(&p, TRUE)) != NULL) 763 parsedtag_get_value(tag, ATTR_TID, &id); 764 if (id >= 0 && id < tbl->ntable) { 765 int alignment; 766 TextLineListItem *ti; 767 struct table *t = tbl->tables[id].ptr; 768 int limit = tbl->tables[id].indent + t->total_width; 769 tbl->tables[id].ptr = NULL; 770 save_fonteffect(&h_env, h_env.obuf); 771 flushline(&h_env, &obuf, 0, 2, h_env.limit); 772 if (t->vspace > 0 && !(obuf.flag & RB_IGNORE_P)) 773 do_blankline(&h_env, &obuf, 0, 0, h_env.limit); 774 if (RB_GET_ALIGN(h_env.obuf) == RB_CENTER) 775 alignment = ALIGN_CENTER; 776 else if (RB_GET_ALIGN(h_env.obuf) == RB_RIGHT) 777 alignment = ALIGN_RIGHT; 778 else 779 alignment = ALIGN_LEFT; 780 781 if (alignment != ALIGN_LEFT) { 782 for (ti = tbl->tables[id].buf->first; 783 ti != NULL; ti = ti->next) 784 align(ti->ptr, h_env.limit, alignment); 785 } 786 appendTextLineList(h_env.buf, tbl->tables[id].buf); 787 if (h_env.maxlimit < limit) 788 h_env.maxlimit = limit; 789 restore_fonteffect(&h_env, h_env.obuf); 790 obuf.flag &= ~RB_IGNORE_P; 791 h_env.blank_lines = 0; 792 if (t->vspace > 0) { 793 do_blankline(&h_env, &obuf, 0, 0, h_env.limit); 794 obuf.flag |= RB_IGNORE_P; 795 } 796 } 797 } 798 else 799 HTMLlineproc1(l->ptr, &h_env); 800 } 801 if (obuf.status != R_ST_NORMAL) { 802 obuf.status = R_ST_EOL; 803 HTMLlineproc1("\n", &h_env); 804 } 805 completeHTMLstream(&h_env, &obuf); 806 flushline(&h_env, &obuf, 0, 2, h_env.limit); 807 if (tbl->border_mode == BORDER_NONE) { 808 int rowspan = table_rowspan(tbl, row, col); 809 if (row + rowspan <= tbl->maxrow) { 810 if (tbl->vcellpadding > 0 && !(obuf.flag & RB_IGNORE_P)) 811 do_blankline(&h_env, &obuf, 0, 0, h_env.limit); 812 } 813 else { 814 if (tbl->vspace > 0) 815 purgeline(&h_env); 816 } 817 } 818 else { 819 if (tbl->vcellpadding > 0) { 820 if (!(obuf.flag & RB_IGNORE_P)) 821 do_blankline(&h_env, &obuf, 0, 0, h_env.limit); 822 } 823 else 824 purgeline(&h_env); 825 } 826 if ((colspan = table_colspan(tbl, row, col)) > 1) { 827 struct table_cell *cell = &tbl->cell; 828 int k; 829 k = bsearch_2short(colspan, cell->colspan, col, cell->col, MAXCOL, 830 cell->index, cell->maxcell + 1); 831 icell = cell->index[k]; 832 if (cell->minimum_width[icell] < h_env.maxlimit) 833 cell->minimum_width[icell] = h_env.maxlimit; 834 } 835 else { 836 if (tbl->minimum_width[col] < h_env.maxlimit) 837 tbl->minimum_width[col] = h_env.maxlimit; 838 } 839 } 840 841 static int 842 table_rule_width(struct table *t) 843 { 844 if (t->border_mode == BORDER_NONE) 845 return 1; 846 return RULE_WIDTH; 847 } 848 849 static void 850 check_cell_width(short *tabwidth, short *cellwidth, 851 short *col, short *colspan, short maxcell, 852 short *indexarray, int space, int dir) 853 { 854 int i, j, k, bcol, ecol; 855 int swidth, width; 856 857 for (k = 0; k <= maxcell; k++) { 858 j = indexarray[k]; 859 if (cellwidth[j] <= 0) 860 continue; 861 bcol = col[j]; 862 ecol = bcol + colspan[j]; 863 swidth = 0; 864 for (i = bcol; i < ecol; i++) 865 swidth += tabwidth[i]; 866 867 width = cellwidth[j] - (colspan[j] - 1) * space; 868 if (width > swidth) { 869 int w = (width - swidth) / colspan[j]; 870 int r = (width - swidth) % colspan[j]; 871 for (i = bcol; i < ecol; i++) 872 tabwidth[i] += w; 873 /* dir {0: horizontal, 1: vertical} */ 874 if (dir == 1 && r > 0) 875 r = colspan[j]; 876 for (i = 1; i <= r; i++) 877 tabwidth[ecol - i]++; 878 } 879 } 880 } 881 882 void 883 check_minimum_width(struct table *t, short *tabwidth) 884 { 885 int i; 886 struct table_cell *cell = &t->cell; 887 888 for (i = 0; i <= t->maxcol; i++) { 889 if (tabwidth[i] < t->minimum_width[i]) 890 tabwidth[i] = t->minimum_width[i]; 891 } 892 893 check_cell_width(tabwidth, cell->minimum_width, cell->col, cell->colspan, 894 cell->maxcell, cell->index, t->cellspacing, 0); 895 } 896 897 void 898 check_maximum_width(struct table *t) 899 { 900 struct table_cell *cell = &t->cell; 901 #ifdef MATRIX 902 int i, j, bcol, ecol; 903 int swidth, width; 904 905 cell->necell = 0; 906 for (j = 0; j <= cell->maxcell; j++) { 907 bcol = cell->col[j]; 908 ecol = bcol + cell->colspan[j]; 909 swidth = 0; 910 for (i = bcol; i < ecol; i++) 911 swidth += t->tabwidth[i]; 912 913 width = cell->width[j] - (cell->colspan[j] - 1) * t->cellspacing; 914 if (width > swidth) { 915 cell->eindex[cell->necell] = j; 916 cell->necell++; 917 } 918 } 919 #else /* not MATRIX */ 920 check_cell_width(t->tabwidth, cell->width, cell->col, cell->colspan, 921 cell->maxcell, cell->index, t->cellspacing, 0); 922 check_minimum_width(t, t->tabwidth); 923 #endif /* not MATRIX */ 924 } 925 926 927 #ifdef MATRIX 928 static void 929 set_integered_width(struct table *t, double *dwidth, short *iwidth) 930 { 931 int i, j, k, n, bcol, ecol, step; 932 short *indexarray; 933 char *fixed; 934 double *mod; 935 double sum = 0., x = 0.; 936 struct table_cell *cell = &t->cell; 937 int rulewidth = table_rule_width(t); 938 939 indexarray = NewAtom_N(short, t->maxcol + 1); 940 mod = NewAtom_N(double, t->maxcol + 1); 941 for (i = 0; i <= t->maxcol; i++) { 942 iwidth[i] = ceil_at_intervals(ceil(dwidth[i]), rulewidth); 943 mod[i] = (double)iwidth[i] - dwidth[i]; 944 } 945 946 sum = 0.; 947 for (k = 0; k <= t->maxcol; k++) { 948 x = mod[k]; 949 sum += x; 950 i = bsearch_double(x, mod, indexarray, k); 951 if (k > i) { 952 int ii; 953 for (ii = k; ii > i; ii--) 954 indexarray[ii] = indexarray[ii - 1]; 955 } 956 indexarray[i] = k; 957 } 958 959 fixed = NewAtom_N(char, t->maxcol + 1); 960 bzero(fixed, t->maxcol + 1); 961 for (step = 0; step < 2; step++) { 962 for (i = 0; i <= t->maxcol; i += n) { 963 int nn; 964 char *idx; 965 double nsum; 966 if (sum < 0.5) 967 return; 968 for (n = 0; i + n <= t->maxcol; n++) { 969 int ii = indexarray[i + n]; 970 if (n == 0) 971 x = mod[ii]; 972 else if (fabs(mod[ii] - x) > 1e-6) 973 break; 974 } 975 for (k = 0; k < n; k++) { 976 int ii = indexarray[i + k]; 977 if (fixed[ii] < 2 && 978 iwidth[ii] - rulewidth < t->minimum_width[ii]) 979 fixed[ii] = 2; 980 if (fixed[ii] < 1 && 981 iwidth[ii] - rulewidth < t->tabwidth[ii] && 982 (double)rulewidth - mod[ii] > 0.5) 983 fixed[ii] = 1; 984 } 985 idx = NewAtom_N(char, n); 986 for (k = 0; k < cell->maxcell; k++) { 987 int kk, w, width, m; 988 j = cell->index[k]; 989 bcol = cell->col[j]; 990 ecol = bcol + cell->colspan[j]; 991 m = 0; 992 for (kk = 0; kk < n; kk++) { 993 int ii = indexarray[i + kk]; 994 if (ii >= bcol && ii < ecol) { 995 idx[m] = ii; 996 m++; 997 } 998 } 999 if (m == 0) 1000 continue; 1001 width = (cell->colspan[j] - 1) * t->cellspacing; 1002 for (kk = bcol; kk < ecol; kk++) 1003 width += iwidth[kk]; 1004 w = 0; 1005 for (kk = 0; kk < m; kk++) { 1006 if (fixed[(int)idx[kk]] < 2) 1007 w += rulewidth; 1008 } 1009 if (width - w < cell->minimum_width[j]) { 1010 for (kk = 0; kk < m; kk++) { 1011 if (fixed[(int)idx[kk]] < 2) 1012 fixed[(int)idx[kk]] = 2; 1013 } 1014 } 1015 w = 0; 1016 for (kk = 0; kk < m; kk++) { 1017 if (fixed[(int)idx[kk]] < 1 && 1018 (double)rulewidth - mod[(int)idx[kk]] > 0.5) 1019 w += rulewidth; 1020 } 1021 if (width - w < cell->width[j]) { 1022 for (kk = 0; kk < m; kk++) { 1023 if (fixed[(int)idx[kk]] < 1 && 1024 (double)rulewidth - mod[(int)idx[kk]] > 0.5) 1025 fixed[(int)idx[kk]] = 1; 1026 } 1027 } 1028 } 1029 nn = 0; 1030 for (k = 0; k < n; k++) { 1031 int ii = indexarray[i + k]; 1032 if (fixed[ii] <= step) 1033 nn++; 1034 } 1035 nsum = sum - (double)(nn * rulewidth); 1036 if (nsum < 0. && fabs(sum) <= fabs(nsum)) 1037 return; 1038 for (k = 0; k < n; k++) { 1039 int ii = indexarray[i + k]; 1040 if (fixed[ii] <= step) { 1041 iwidth[ii] -= rulewidth; 1042 fixed[ii] = 3; 1043 } 1044 } 1045 sum = nsum; 1046 } 1047 } 1048 } 1049 1050 static double 1051 correlation_coefficient(double sxx, double syy, double sxy) 1052 { 1053 double coe, tmp; 1054 tmp = sxx * syy; 1055 if (tmp < Tiny) 1056 tmp = Tiny; 1057 coe = sxy / sqrt(tmp); 1058 if (coe > 1.) 1059 return 1.; 1060 if (coe < -1.) 1061 return -1.; 1062 return coe; 1063 } 1064 1065 static double 1066 correlation_coefficient2(double sxx, double syy, double sxy) 1067 { 1068 double coe, tmp; 1069 tmp = (syy + sxx - 2 * sxy) * sxx; 1070 if (tmp < Tiny) 1071 tmp = Tiny; 1072 coe = (sxx - sxy) / sqrt(tmp); 1073 if (coe > 1.) 1074 return 1.; 1075 if (coe < -1.) 1076 return -1.; 1077 return coe; 1078 } 1079 1080 static double 1081 recalc_width(double old, double swidth, int cwidth, 1082 double sxx, double syy, double sxy, int is_inclusive) 1083 { 1084 double delta = swidth - (double)cwidth; 1085 double rat = sxy / sxx, 1086 coe = correlation_coefficient(sxx, syy, sxy), w, ww; 1087 if (old < 0.) 1088 old = 0.; 1089 if (fabs(coe) < 1e-5) 1090 return old; 1091 w = rat * old; 1092 ww = delta; 1093 if (w > 0.) { 1094 double wmin = 5e-3 * sqrt(syy * (1. - coe * coe)); 1095 if (swidth < 0.2 && cwidth > 0 && is_inclusive) { 1096 double coe1 = correlation_coefficient2(sxx, syy, sxy); 1097 if (coe > 0.9 || coe1 > 0.9) 1098 return 0.; 1099 } 1100 if (wmin > 0.05) 1101 wmin = 0.05; 1102 if (ww < 0.) 1103 ww = 0.; 1104 ww += wmin; 1105 } 1106 else { 1107 double wmin = 5e-3 * sqrt(syy) * fabs(coe); 1108 if (rat > -0.001) 1109 return old; 1110 if (wmin > 0.01) 1111 wmin = 0.01; 1112 if (ww > 0.) 1113 ww = 0.; 1114 ww -= wmin; 1115 } 1116 if (w > ww) 1117 return ww / rat; 1118 return old; 1119 } 1120 1121 static int 1122 check_compressible_cell(struct table *t, MAT * minv, 1123 double *newwidth, double *swidth, short *cwidth, 1124 double totalwidth, double *Sxx, 1125 int icol, int icell, double sxx, int corr) 1126 { 1127 struct table_cell *cell = &t->cell; 1128 int i, j, k, m, bcol, ecol, span; 1129 double delta, owidth; 1130 double dmax, dmin, sxy; 1131 int rulewidth = table_rule_width(t); 1132 1133 if (sxx < 10.) 1134 return corr; 1135 1136 if (icol >= 0) { 1137 owidth = newwidth[icol]; 1138 delta = newwidth[icol] - (double)t->tabwidth[icol]; 1139 bcol = icol; 1140 ecol = bcol + 1; 1141 } 1142 else if (icell >= 0) { 1143 owidth = swidth[icell]; 1144 delta = swidth[icell] - (double)cwidth[icell]; 1145 bcol = cell->col[icell]; 1146 ecol = bcol + cell->colspan[icell]; 1147 } 1148 else { 1149 owidth = totalwidth; 1150 delta = totalwidth; 1151 bcol = 0; 1152 ecol = t->maxcol + 1; 1153 } 1154 1155 dmin = delta; 1156 dmax = -1.; 1157 for (k = 0; k <= cell->maxcell; k++) { 1158 int bcol1, ecol1; 1159 int is_inclusive = 0; 1160 if (dmin <= 0.) 1161 goto _end; 1162 j = cell->index[k]; 1163 if (j == icell) 1164 continue; 1165 bcol1 = cell->col[j]; 1166 ecol1 = bcol1 + cell->colspan[j]; 1167 sxy = 0.; 1168 for (m = bcol1; m < ecol1; m++) { 1169 for (i = bcol; i < ecol; i++) 1170 sxy += m_entry(minv, i, m); 1171 } 1172 if (bcol1 >= bcol && ecol1 <= ecol) { 1173 is_inclusive = 1; 1174 } 1175 if (sxy > 0.) 1176 dmin = recalc_width(dmin, swidth[j], cwidth[j], 1177 sxx, Sxx[j], sxy, is_inclusive); 1178 else 1179 dmax = recalc_width(dmax, swidth[j], cwidth[j], 1180 sxx, Sxx[j], sxy, is_inclusive); 1181 } 1182 for (m = 0; m <= t->maxcol; m++) { 1183 int is_inclusive = 0; 1184 if (dmin <= 0.) 1185 goto _end; 1186 if (m == icol) 1187 continue; 1188 sxy = 0.; 1189 for (i = bcol; i < ecol; i++) 1190 sxy += m_entry(minv, i, m); 1191 if (m >= bcol && m < ecol) { 1192 is_inclusive = 1; 1193 } 1194 if (sxy > 0.) 1195 dmin = recalc_width(dmin, newwidth[m], t->tabwidth[m], 1196 sxx, m_entry(minv, m, m), sxy, is_inclusive); 1197 else 1198 dmax = recalc_width(dmax, newwidth[m], t->tabwidth[m], 1199 sxx, m_entry(minv, m, m), sxy, is_inclusive); 1200 } 1201 _end: 1202 if (dmax > 0. && dmin > dmax) 1203 dmin = dmax; 1204 span = ecol - bcol; 1205 if ((span == t->maxcol + 1 && dmin >= 0.) || 1206 (span != t->maxcol + 1 && dmin > rulewidth * 0.5)) { 1207 int nwidth = ceil_at_intervals(round(owidth - dmin), rulewidth); 1208 correct_table_matrix(t, bcol, ecol - bcol, nwidth, 1.); 1209 corr++; 1210 } 1211 return corr; 1212 } 1213 1214 #define MAX_ITERATION 10 1215 int 1216 check_table_width(struct table *t, double *newwidth, MAT * minv, int itr) 1217 { 1218 int i, j, k, m, bcol, ecol; 1219 int corr = 0; 1220 struct table_cell *cell = &t->cell; 1221 #ifdef __GNUC__ 1222 short orgwidth[t->maxcol + 1], corwidth[t->maxcol + 1]; 1223 short cwidth[cell->maxcell + 1]; 1224 double swidth[cell->maxcell + 1]; 1225 #else /* __GNUC__ */ 1226 short orgwidth[MAXCOL], corwidth[MAXCOL]; 1227 short cwidth[MAXCELL]; 1228 double swidth[MAXCELL]; 1229 #endif /* __GNUC__ */ 1230 double twidth, sxy, *Sxx, stotal; 1231 1232 twidth = 0.; 1233 stotal = 0.; 1234 for (i = 0; i <= t->maxcol; i++) { 1235 twidth += newwidth[i]; 1236 stotal += m_entry(minv, i, i); 1237 for (m = 0; m < i; m++) { 1238 stotal += 2 * m_entry(minv, i, m); 1239 } 1240 } 1241 1242 Sxx = NewAtom_N(double, cell->maxcell + 1); 1243 for (k = 0; k <= cell->maxcell; k++) { 1244 j = cell->index[k]; 1245 bcol = cell->col[j]; 1246 ecol = bcol + cell->colspan[j]; 1247 swidth[j] = 0.; 1248 for (i = bcol; i < ecol; i++) 1249 swidth[j] += newwidth[i]; 1250 cwidth[j] = cell->width[j] - (cell->colspan[j] - 1) * t->cellspacing; 1251 Sxx[j] = 0.; 1252 for (i = bcol; i < ecol; i++) { 1253 Sxx[j] += m_entry(minv, i, i); 1254 for (m = bcol; m <= ecol; m++) { 1255 if (m < i) 1256 Sxx[j] += 2 * m_entry(minv, i, m); 1257 } 1258 } 1259 } 1260 1261 /* compress table */ 1262 corr = check_compressible_cell(t, minv, newwidth, swidth, 1263 cwidth, twidth, Sxx, -1, -1, stotal, corr); 1264 if (itr < MAX_ITERATION && corr > 0) 1265 return corr; 1266 1267 /* compress multicolumn cell */ 1268 for (k = cell->maxcell; k >= 0; k--) { 1269 j = cell->index[k]; 1270 corr = check_compressible_cell(t, minv, newwidth, swidth, 1271 cwidth, twidth, Sxx, 1272 -1, j, Sxx[j], corr); 1273 if (itr < MAX_ITERATION && corr > 0) 1274 return corr; 1275 } 1276 1277 /* compress single column cell */ 1278 for (i = 0; i <= t->maxcol; i++) { 1279 corr = check_compressible_cell(t, minv, newwidth, swidth, 1280 cwidth, twidth, Sxx, 1281 i, -1, m_entry(minv, i, i), corr); 1282 if (itr < MAX_ITERATION && corr > 0) 1283 return corr; 1284 } 1285 1286 1287 for (i = 0; i <= t->maxcol; i++) 1288 corwidth[i] = orgwidth[i] = round(newwidth[i]); 1289 1290 check_minimum_width(t, corwidth); 1291 1292 for (i = 0; i <= t->maxcol; i++) { 1293 double sx = sqrt(m_entry(minv, i, i)); 1294 if (sx < 0.1) 1295 continue; 1296 if (orgwidth[i] < t->minimum_width[i] && 1297 corwidth[i] == t->minimum_width[i]) { 1298 double w = (sx > 0.5) ? 0.5 : sx * 0.2; 1299 sxy = 0.; 1300 for (m = 0; m <= t->maxcol; m++) { 1301 if (m == i) 1302 continue; 1303 sxy += m_entry(minv, i, m); 1304 } 1305 if (sxy <= 0.) { 1306 correct_table_matrix(t, i, 1, t->minimum_width[i], w); 1307 corr++; 1308 } 1309 } 1310 } 1311 1312 for (k = 0; k <= cell->maxcell; k++) { 1313 int nwidth = 0, mwidth; 1314 double sx; 1315 1316 j = cell->index[k]; 1317 sx = sqrt(Sxx[j]); 1318 if (sx < 0.1) 1319 continue; 1320 bcol = cell->col[j]; 1321 ecol = bcol + cell->colspan[j]; 1322 for (i = bcol; i < ecol; i++) 1323 nwidth += corwidth[i]; 1324 mwidth = 1325 cell->minimum_width[j] - (cell->colspan[j] - 1) * t->cellspacing; 1326 if (mwidth > swidth[j] && mwidth == nwidth) { 1327 double w = (sx > 0.5) ? 0.5 : sx * 0.2; 1328 1329 sxy = 0.; 1330 for (i = bcol; i < ecol; i++) { 1331 for (m = 0; m <= t->maxcol; m++) { 1332 if (m >= bcol && m < ecol) 1333 continue; 1334 sxy += m_entry(minv, i, m); 1335 } 1336 } 1337 if (sxy <= 0.) { 1338 correct_table_matrix(t, bcol, cell->colspan[j], mwidth, w); 1339 corr++; 1340 } 1341 } 1342 } 1343 1344 if (itr >= MAX_ITERATION) 1345 return 0; 1346 else 1347 return corr; 1348 } 1349 1350 #else /* not MATRIX */ 1351 void 1352 set_table_width(struct table *t, short *newwidth, int maxwidth) 1353 { 1354 int i, j, k, bcol, ecol; 1355 struct table_cell *cell = &t->cell; 1356 char *fixed; 1357 int swidth, fwidth, width, nvar; 1358 double s; 1359 double *dwidth; 1360 int try_again; 1361 1362 fixed = NewAtom_N(char, t->maxcol + 1); 1363 bzero(fixed, t->maxcol + 1); 1364 dwidth = NewAtom_N(double, t->maxcol + 1); 1365 1366 for (i = 0; i <= t->maxcol; i++) { 1367 dwidth[i] = 0.0; 1368 if (t->fixed_width[i] < 0) { 1369 t->fixed_width[i] = -t->fixed_width[i] * maxwidth / 100; 1370 } 1371 if (t->fixed_width[i] > 0) { 1372 newwidth[i] = t->fixed_width[i]; 1373 fixed[i] = 1; 1374 } 1375 else 1376 newwidth[i] = 0; 1377 if (newwidth[i] < t->minimum_width[i]) 1378 newwidth[i] = t->minimum_width[i]; 1379 } 1380 1381 for (k = 0; k <= cell->maxcell; k++) { 1382 j = cell->indexarray[k]; 1383 bcol = cell->col[j]; 1384 ecol = bcol + cell->colspan[j]; 1385 1386 if (cell->fixed_width[j] < 0) 1387 cell->fixed_width[j] = -cell->fixed_width[j] * maxwidth / 100; 1388 1389 swidth = 0; 1390 fwidth = 0; 1391 nvar = 0; 1392 for (i = bcol; i < ecol; i++) { 1393 if (fixed[i]) { 1394 fwidth += newwidth[i]; 1395 } 1396 else { 1397 swidth += newwidth[i]; 1398 nvar++; 1399 } 1400 } 1401 width = max(cell->fixed_width[j], cell->minimum_width[j]) 1402 - (cell->colspan[j] - 1) * t->cellspacing; 1403 if (nvar > 0 && width > fwidth + swidth) { 1404 s = 0.; 1405 for (i = bcol; i < ecol; i++) { 1406 if (!fixed[i]) 1407 s += weight3(t->tabwidth[i]); 1408 } 1409 for (i = bcol; i < ecol; i++) { 1410 if (!fixed[i]) 1411 dwidth[i] = (width - fwidth) * weight3(t->tabwidth[i]) / s; 1412 else 1413 dwidth[i] = (double)newwidth[i]; 1414 } 1415 dv2sv(dwidth, newwidth, cell->colspan[j]); 1416 if (cell->fixed_width[j] > 0) { 1417 for (i = bcol; i < ecol; i++) 1418 fixed[i] = 1; 1419 } 1420 } 1421 } 1422 1423 do { 1424 nvar = 0; 1425 swidth = 0; 1426 fwidth = 0; 1427 for (i = 0; i <= t->maxcol; i++) { 1428 if (fixed[i]) { 1429 fwidth += newwidth[i]; 1430 } 1431 else { 1432 swidth += newwidth[i]; 1433 nvar++; 1434 } 1435 } 1436 width = maxwidth - t->maxcol * t->cellspacing; 1437 if (nvar == 0 || width <= fwidth + swidth) 1438 break; 1439 1440 s = 0.; 1441 for (i = 0; i <= t->maxcol; i++) { 1442 if (!fixed[i]) 1443 s += weight3(t->tabwidth[i]); 1444 } 1445 for (i = 0; i <= t->maxcol; i++) { 1446 if (!fixed[i]) 1447 dwidth[i] = (width - fwidth) * weight3(t->tabwidth[i]) / s; 1448 else 1449 dwidth[i] = (double)newwidth[i]; 1450 } 1451 dv2sv(dwidth, newwidth, t->maxcol + 1); 1452 1453 try_again = 0; 1454 for (i = 0; i <= t->maxcol; i++) { 1455 if (!fixed[i]) { 1456 if (newwidth[i] > t->tabwidth[i]) { 1457 newwidth[i] = t->tabwidth[i]; 1458 fixed[i] = 1; 1459 try_again = 1; 1460 } 1461 else if (newwidth[i] < t->minimum_width[i]) { 1462 newwidth[i] = t->minimum_width[i]; 1463 fixed[i] = 1; 1464 try_again = 1; 1465 } 1466 } 1467 } 1468 } while (try_again); 1469 } 1470 #endif /* not MATRIX */ 1471 1472 void 1473 check_table_height(struct table *t) 1474 { 1475 int i, j, k; 1476 struct { 1477 short *row; 1478 short *rowspan; 1479 short *indexarray; 1480 short maxcell; 1481 short size; 1482 short *height; 1483 } cell; 1484 int space = 0; 1485 1486 cell.size = 0; 1487 cell.maxcell = -1; 1488 1489 for (j = 0; j <= t->maxrow; j++) { 1490 if (!t->tabattr[j]) 1491 continue; 1492 for (i = 0; i <= t->maxcol; i++) { 1493 int t_dep, rowspan; 1494 if (t->tabattr[j][i] & (HTT_X | HTT_Y)) 1495 continue; 1496 1497 if (t->tabdata[j][i] == NULL) 1498 t_dep = 0; 1499 else 1500 t_dep = t->tabdata[j][i]->nitem; 1501 1502 rowspan = table_rowspan(t, j, i); 1503 if (rowspan > 1) { 1504 int c = cell.maxcell + 1; 1505 k = bsearch_2short(rowspan, cell.rowspan, 1506 j, cell.row, t->maxrow + 1, cell.indexarray, 1507 c); 1508 if (k <= cell.maxcell) { 1509 int idx = cell.indexarray[k]; 1510 if (cell.row[idx] == j && cell.rowspan[idx] == rowspan) 1511 c = idx; 1512 } 1513 if (c >= MAXROWCELL) 1514 continue; 1515 if (c >= cell.size) { 1516 if (cell.size == 0) { 1517 cell.size = max(MAXCELL, c + 1); 1518 cell.row = NewAtom_N(short, cell.size); 1519 cell.rowspan = NewAtom_N(short, cell.size); 1520 cell.indexarray = NewAtom_N(short, cell.size); 1521 cell.height = NewAtom_N(short, cell.size); 1522 } 1523 else { 1524 cell.size = max(cell.size + MAXCELL, c + 1); 1525 cell.row = New_Reuse(short, cell.row, cell.size); 1526 cell.rowspan = New_Reuse(short, cell.rowspan, 1527 cell.size); 1528 cell.indexarray = New_Reuse(short, cell.indexarray, 1529 cell.size); 1530 cell.height = New_Reuse(short, cell.height, cell.size); 1531 } 1532 } 1533 if (c > cell.maxcell) { 1534 cell.maxcell++; 1535 cell.row[cell.maxcell] = j; 1536 cell.rowspan[cell.maxcell] = rowspan; 1537 cell.height[cell.maxcell] = 0; 1538 if (cell.maxcell > k) { 1539 int ii; 1540 for (ii = cell.maxcell; ii > k; ii--) 1541 cell.indexarray[ii] = cell.indexarray[ii - 1]; 1542 } 1543 cell.indexarray[k] = cell.maxcell; 1544 } 1545 1546 if (cell.height[c] < t_dep) 1547 cell.height[c] = t_dep; 1548 continue; 1549 } 1550 if (t->tabheight[j] < t_dep) 1551 t->tabheight[j] = t_dep; 1552 } 1553 } 1554 1555 switch (t->border_mode) { 1556 case BORDER_THIN: 1557 case BORDER_THICK: 1558 case BORDER_NOWIN: 1559 space = 1; 1560 break; 1561 case BORDER_NONE: 1562 space = 0; 1563 } 1564 check_cell_width(t->tabheight, cell.height, cell.row, cell.rowspan, 1565 cell.maxcell, cell.indexarray, space, 1); 1566 } 1567 1568 #define CHECK_MINIMUM 1 1569 #define CHECK_FIXED 2 1570 1571 int 1572 get_table_width(struct table *t, short *orgwidth, short *cellwidth, int flag) 1573 { 1574 #ifdef __GNUC__ 1575 short newwidth[t->maxcol + 1]; 1576 #else /* not __GNUC__ */ 1577 short newwidth[MAXCOL]; 1578 #endif /* not __GNUC__ */ 1579 int i; 1580 int swidth; 1581 struct table_cell *cell = &t->cell; 1582 int rulewidth = table_rule_width(t); 1583 1584 for (i = 0; i <= t->maxcol; i++) 1585 newwidth[i] = max(orgwidth[i], 0); 1586 1587 if (flag & CHECK_FIXED) { 1588 #ifdef __GNUC__ 1589 short ccellwidth[cell->maxcell + 1]; 1590 #else /* not __GNUC__ */ 1591 short ccellwidth[MAXCELL]; 1592 #endif /* not __GNUC__ */ 1593 for (i = 0; i <= t->maxcol; i++) { 1594 if (newwidth[i] < t->fixed_width[i]) 1595 newwidth[i] = t->fixed_width[i]; 1596 } 1597 for (i = 0; i <= cell->maxcell; i++) { 1598 ccellwidth[i] = cellwidth[i]; 1599 if (ccellwidth[i] < cell->fixed_width[i]) 1600 ccellwidth[i] = cell->fixed_width[i]; 1601 } 1602 check_cell_width(newwidth, ccellwidth, cell->col, cell->colspan, 1603 cell->maxcell, cell->index, t->cellspacing, 0); 1604 } 1605 else { 1606 check_cell_width(newwidth, cellwidth, cell->col, cell->colspan, 1607 cell->maxcell, cell->index, t->cellspacing, 0); 1608 } 1609 if (flag & CHECK_MINIMUM) 1610 check_minimum_width(t, newwidth); 1611 1612 swidth = 0; 1613 for (i = 0; i <= t->maxcol; i++) { 1614 swidth += ceil_at_intervals(newwidth[i], rulewidth); 1615 } 1616 swidth += table_border_width(t); 1617 return swidth; 1618 } 1619 1620 #define minimum_table_width(t)\ 1621 (get_table_width(t,t->minimum_width,t->cell.minimum_width,0)) 1622 #define maximum_table_width(t)\ 1623 (get_table_width(t,t->tabwidth,t->cell.width,CHECK_FIXED)) 1624 #define fixed_table_width(t)\ 1625 (get_table_width(t,t->fixed_width,t->cell.fixed_width,CHECK_MINIMUM)) 1626 1627 void 1628 renderCoTable(struct table *tbl, int maxlimit) 1629 { 1630 struct readbuffer obuf; 1631 struct html_feed_environ h_env; 1632 struct environment envs[MAX_ENV_LEVEL]; 1633 struct table *t; 1634 int i, col, row; 1635 int indent, maxwidth; 1636 1637 for (i = 0; i < tbl->ntable; i++) { 1638 t = tbl->tables[i].ptr; 1639 col = tbl->tables[i].col; 1640 row = tbl->tables[i].row; 1641 indent = tbl->tables[i].indent; 1642 1643 init_henv(&h_env, &obuf, envs, MAX_ENV_LEVEL, tbl->tables[i].buf, 1644 get_spec_cell_width(tbl, row, col), indent); 1645 check_row(tbl, row); 1646 if (h_env.limit > maxlimit) 1647 h_env.limit = maxlimit; 1648 if (t->total_width == 0) 1649 maxwidth = h_env.limit - indent; 1650 else if (t->total_width > 0) 1651 maxwidth = t->total_width; 1652 else 1653 maxwidth = t->total_width = -t->total_width * h_env.limit / 100; 1654 renderTable(t, maxwidth, &h_env); 1655 } 1656 } 1657 1658 static void 1659 make_caption(struct table *t, struct html_feed_environ *h_env) 1660 { 1661 struct html_feed_environ henv; 1662 struct readbuffer obuf; 1663 struct environment envs[MAX_ENV_LEVEL]; 1664 int limit; 1665 1666 if (t->caption->length <= 0) 1667 return; 1668 1669 if (t->total_width > 0) 1670 limit = t->total_width; 1671 else 1672 limit = h_env->limit; 1673 init_henv(&henv, &obuf, envs, MAX_ENV_LEVEL, newTextLineList(), 1674 limit, h_env->envs[h_env->envc].indent); 1675 HTMLlineproc1("<center>", &henv); 1676 HTMLlineproc0(t->caption->ptr, &henv, FALSE); 1677 HTMLlineproc1("</center>", &henv); 1678 1679 if (t->total_width < henv.maxlimit) 1680 t->total_width = henv.maxlimit; 1681 limit = h_env->limit; 1682 h_env->limit = t->total_width; 1683 HTMLlineproc1("<center>", h_env); 1684 HTMLlineproc0(t->caption->ptr, h_env, FALSE); 1685 HTMLlineproc1("</center>", h_env); 1686 h_env->limit = limit; 1687 } 1688 1689 void 1690 renderTable(struct table *t, int max_width, struct html_feed_environ *h_env) 1691 { 1692 int i, j, w, r, h; 1693 Str renderbuf; 1694 short new_tabwidth[MAXCOL]; 1695 #ifdef MATRIX 1696 int itr; 1697 VEC *newwidth; 1698 MAT *mat, *minv; 1699 PERM *pivot; 1700 #endif /* MATRIX */ 1701 int width; 1702 int rulewidth; 1703 Str vrulea = NULL, vruleb = NULL, vrulec = NULL; 1704 #ifdef ID_EXT 1705 Str idtag; 1706 #endif /* ID_EXT */ 1707 1708 t->total_height = 0; 1709 if (t->maxcol < 0) { 1710 make_caption(t, h_env); 1711 return; 1712 } 1713 1714 if (t->sloppy_width > max_width) 1715 max_width = t->sloppy_width; 1716 1717 rulewidth = table_rule_width(t); 1718 1719 max_width -= table_border_width(t); 1720 1721 if (rulewidth > 1) 1722 max_width = floor_at_intervals(max_width, rulewidth); 1723 1724 if (max_width < rulewidth) 1725 max_width = rulewidth; 1726 1727 check_maximum_width(t); 1728 1729 #ifdef MATRIX 1730 if (t->maxcol == 0) { 1731 if (t->tabwidth[0] > max_width) 1732 t->tabwidth[0] = max_width; 1733 if (t->total_width > 0) 1734 t->tabwidth[0] = max_width; 1735 else if (t->fixed_width[0] > 0) 1736 t->tabwidth[0] = t->fixed_width[0]; 1737 if (t->tabwidth[0] < t->minimum_width[0]) 1738 t->tabwidth[0] = t->minimum_width[0]; 1739 } 1740 else { 1741 set_table_matrix(t, max_width); 1742 1743 itr = 0; 1744 mat = m_get(t->maxcol + 1, t->maxcol + 1); 1745 pivot = px_get(t->maxcol + 1); 1746 newwidth = v_get(t->maxcol + 1); 1747 minv = m_get(t->maxcol + 1, t->maxcol + 1); 1748 do { 1749 m_copy(t->matrix, mat); 1750 LUfactor(mat, pivot); 1751 LUsolve(mat, pivot, t->vector, newwidth); 1752 LUinverse(mat, pivot, minv); 1753 #ifdef TABLE_DEBUG 1754 set_integered_width(t, newwidth->ve, new_tabwidth); 1755 fprintf(stderr, "itr=%d\n", itr); 1756 fprintf(stderr, "max_width=%d\n", max_width); 1757 fprintf(stderr, "minimum : "); 1758 for (i = 0; i <= t->maxcol; i++) 1759 fprintf(stderr, "%2d ", t->minimum_width[i]); 1760 fprintf(stderr, "\nfixed : "); 1761 for (i = 0; i <= t->maxcol; i++) 1762 fprintf(stderr, "%2d ", t->fixed_width[i]); 1763 fprintf(stderr, "\ndecided : "); 1764 for (i = 0; i <= t->maxcol; i++) 1765 fprintf(stderr, "%2d ", new_tabwidth[i]); 1766 fprintf(stderr, "\n"); 1767 #endif /* TABLE_DEBUG */ 1768 itr++; 1769 1770 } while (check_table_width(t, newwidth->ve, minv, itr)); 1771 set_integered_width(t, newwidth->ve, new_tabwidth); 1772 check_minimum_width(t, new_tabwidth); 1773 v_free(newwidth); 1774 px_free(pivot); 1775 m_free(mat); 1776 m_free(minv); 1777 m_free(t->matrix); 1778 v_free(t->vector); 1779 for (i = 0; i <= t->maxcol; i++) { 1780 t->tabwidth[i] = new_tabwidth[i]; 1781 } 1782 } 1783 #else /* not MATRIX */ 1784 set_table_width(t, new_tabwidth, max_width); 1785 for (i = 0; i <= t->maxcol; i++) { 1786 t->tabwidth[i] = new_tabwidth[i]; 1787 } 1788 #endif /* not MATRIX */ 1789 1790 check_minimum_width(t, t->tabwidth); 1791 for (i = 0; i <= t->maxcol; i++) 1792 t->tabwidth[i] = ceil_at_intervals(t->tabwidth[i], rulewidth); 1793 1794 renderCoTable(t, h_env->limit); 1795 1796 for (i = 0; i <= t->maxcol; i++) { 1797 for (j = 0; j <= t->maxrow; j++) { 1798 check_row(t, j); 1799 if (t->tabattr[j][i] & HTT_Y) 1800 continue; 1801 do_refill(t, j, i, h_env->limit); 1802 } 1803 } 1804 1805 check_minimum_width(t, t->tabwidth); 1806 t->total_width = 0; 1807 for (i = 0; i <= t->maxcol; i++) { 1808 t->tabwidth[i] = ceil_at_intervals(t->tabwidth[i], rulewidth); 1809 t->total_width += t->tabwidth[i]; 1810 } 1811 1812 t->total_width += table_border_width(t); 1813 1814 check_table_height(t); 1815 1816 for (i = 0; i <= t->maxcol; i++) { 1817 for (j = 0; j <= t->maxrow; j++) { 1818 TextLineList *l; 1819 int k; 1820 if ((t->tabattr[j][i] & HTT_Y) || 1821 (t->tabattr[j][i] & HTT_TOP) || (t->tabdata[j][i] == NULL)) 1822 continue; 1823 h = t->tabheight[j]; 1824 for (k = j + 1; k <= t->maxrow; k++) { 1825 if (!(t->tabattr[k][i] & HTT_Y)) 1826 break; 1827 h += t->tabheight[k]; 1828 switch (t->border_mode) { 1829 case BORDER_THIN: 1830 case BORDER_THICK: 1831 case BORDER_NOWIN: 1832 h += 1; 1833 break; 1834 } 1835 } 1836 h -= t->tabdata[j][i]->nitem; 1837 if (t->tabattr[j][i] & HTT_MIDDLE) 1838 h /= 2; 1839 if (h <= 0) 1840 continue; 1841 l = newTextLineList(); 1842 for (k = 0; k < h; k++) 1843 pushTextLine(l, newTextLine(NULL, 0)); 1844 t->tabdata[j][i] = appendGeneralList((GeneralList *)l, 1845 t->tabdata[j][i]); 1846 } 1847 } 1848 1849 /* table output */ 1850 width = t->total_width; 1851 1852 make_caption(t, h_env); 1853 1854 HTMLlineproc1("<pre for_table>", h_env); 1855 #ifdef ID_EXT 1856 if (t->id != NULL) { 1857 idtag = Sprintf("<_id id=\"%s\">", html_quote((t->id)->ptr)); 1858 HTMLlineproc1(idtag->ptr, h_env); 1859 } 1860 #endif /* ID_EXT */ 1861 switch (t->border_mode) { 1862 case BORDER_THIN: 1863 case BORDER_THICK: 1864 renderbuf = Strnew(); 1865 print_sep(t, -1, T_TOP, t->maxcol, renderbuf); 1866 push_render_image(renderbuf, width, t->total_width, h_env); 1867 t->total_height += 1; 1868 break; 1869 } 1870 vruleb = Strnew(); 1871 switch (t->border_mode) { 1872 case BORDER_THIN: 1873 case BORDER_THICK: 1874 vrulea = Strnew(); 1875 vrulec = Strnew(); 1876 push_symbol(vrulea, TK_VERTICALBAR(t->border_mode), symbol_width, 1); 1877 for (i = 0; i < t->cellpadding; i++) { 1878 Strcat_char(vrulea, ' '); 1879 Strcat_char(vruleb, ' '); 1880 Strcat_char(vrulec, ' '); 1881 } 1882 push_symbol(vrulec, TK_VERTICALBAR(t->border_mode), symbol_width, 1); 1883 case BORDER_NOWIN: 1884 push_symbol(vruleb, TK_VERTICALBAR(BORDER_THIN), symbol_width, 1); 1885 for (i = 0; i < t->cellpadding; i++) 1886 Strcat_char(vruleb, ' '); 1887 break; 1888 case BORDER_NONE: 1889 for (i = 0; i < t->cellspacing; i++) 1890 Strcat_char(vruleb, ' '); 1891 } 1892 1893 for (r = 0; r <= t->maxrow; r++) { 1894 for (h = 0; h < t->tabheight[r]; h++) { 1895 renderbuf = Strnew(); 1896 if (t->border_mode == BORDER_THIN 1897 || t->border_mode == BORDER_THICK) 1898 Strcat(renderbuf, vrulea); 1899 #ifdef ID_EXT 1900 if (t->tridvalue[r] != NULL && h == 0) { 1901 idtag = Sprintf("<_id id=\"%s\">", 1902 html_quote((t->tridvalue[r])->ptr)); 1903 Strcat(renderbuf, idtag); 1904 } 1905 #endif /* ID_EXT */ 1906 for (i = 0; i <= t->maxcol; i++) { 1907 check_row(t, r); 1908 #ifdef ID_EXT 1909 if (t->tabidvalue[r][i] != NULL && h == 0) { 1910 idtag = Sprintf("<_id id=\"%s\">", 1911 html_quote((t->tabidvalue[r][i])->ptr)); 1912 Strcat(renderbuf, idtag); 1913 } 1914 #endif /* ID_EXT */ 1915 if (!(t->tabattr[r][i] & HTT_X)) { 1916 w = t->tabwidth[i]; 1917 for (j = i + 1; 1918 j <= t->maxcol && (t->tabattr[r][j] & HTT_X); j++) 1919 w += t->tabwidth[j] + t->cellspacing; 1920 if (t->tabattr[r][i] & HTT_Y) { 1921 for (j = r - 1; j >= 0 && t->tabattr[j] 1922 && (t->tabattr[j][i] & HTT_Y); j--) ; 1923 print_item(t, j, i, w, renderbuf); 1924 } 1925 else 1926 print_item(t, r, i, w, renderbuf); 1927 } 1928 if (i < t->maxcol && !(t->tabattr[r][i + 1] & HTT_X)) 1929 Strcat(renderbuf, vruleb); 1930 } 1931 switch (t->border_mode) { 1932 case BORDER_THIN: 1933 case BORDER_THICK: 1934 Strcat(renderbuf, vrulec); 1935 t->total_height += 1; 1936 break; 1937 } 1938 push_render_image(renderbuf, width, t->total_width, h_env); 1939 } 1940 if (r < t->maxrow && t->border_mode != BORDER_NONE) { 1941 renderbuf = Strnew(); 1942 print_sep(t, r, T_MIDDLE, t->maxcol, renderbuf); 1943 push_render_image(renderbuf, width, t->total_width, h_env); 1944 } 1945 t->total_height += t->tabheight[r]; 1946 } 1947 switch (t->border_mode) { 1948 case BORDER_THIN: 1949 case BORDER_THICK: 1950 renderbuf = Strnew(); 1951 print_sep(t, t->maxrow, T_BOTTOM, t->maxcol, renderbuf); 1952 push_render_image(renderbuf, width, t->total_width, h_env); 1953 t->total_height += 1; 1954 break; 1955 } 1956 if (t->total_height == 0) { 1957 renderbuf = Strnew_charp(" "); 1958 t->total_height++; 1959 t->total_width = 1; 1960 push_render_image(renderbuf, 1, t->total_width, h_env); 1961 } 1962 HTMLlineproc1("</pre>", h_env); 1963 } 1964 1965 #ifdef TABLE_NO_COMPACT 1966 #define THR_PADDING 2 1967 #else 1968 #define THR_PADDING 4 1969 #endif 1970 1971 struct table * 1972 begin_table(int border, int spacing, int padding, int vspace) 1973 { 1974 struct table *t; 1975 int mincell = minimum_cellspacing(border); 1976 int rcellspacing; 1977 int mincell_pixels = round(mincell * pixel_per_char); 1978 int ppc = round(pixel_per_char); 1979 1980 t = newTable(); 1981 t->row = t->col = -1; 1982 t->maxcol = -1; 1983 t->maxrow = -1; 1984 t->border_mode = border; 1985 t->flag = 0; 1986 if (border == BORDER_NOWIN) 1987 t->flag |= TBL_EXPAND_OK; 1988 1989 rcellspacing = spacing + 2 * padding; 1990 switch (border) { 1991 case BORDER_THIN: 1992 case BORDER_THICK: 1993 case BORDER_NOWIN: 1994 t->cellpadding = padding - (mincell_pixels - 4) / 2; 1995 break; 1996 case BORDER_NONE: 1997 t->cellpadding = rcellspacing - mincell_pixels; 1998 } 1999 if (t->cellpadding >= ppc) 2000 t->cellpadding /= ppc; 2001 else if (t->cellpadding > 0) 2002 t->cellpadding = 1; 2003 else 2004 t->cellpadding = 0; 2005 2006 switch (border) { 2007 case BORDER_THIN: 2008 case BORDER_THICK: 2009 case BORDER_NOWIN: 2010 t->cellspacing = 2 * t->cellpadding + mincell; 2011 break; 2012 case BORDER_NONE: 2013 t->cellspacing = t->cellpadding + mincell; 2014 } 2015 2016 if (border == BORDER_NONE) { 2017 if (rcellspacing / 2 + vspace <= 1) 2018 t->vspace = 0; 2019 else 2020 t->vspace = 1; 2021 } 2022 else { 2023 if (vspace < ppc) 2024 t->vspace = 0; 2025 else 2026 t->vspace = 1; 2027 } 2028 2029 if (border == BORDER_NONE) { 2030 if (rcellspacing <= THR_PADDING) 2031 t->vcellpadding = 0; 2032 else 2033 t->vcellpadding = 1; 2034 } 2035 else { 2036 if (padding < 2 * ppc - 2) 2037 t->vcellpadding = 0; 2038 else 2039 t->vcellpadding = 1; 2040 } 2041 2042 return t; 2043 } 2044 2045 void 2046 end_table(struct table *tbl) 2047 { 2048 struct table_cell *cell = &tbl->cell; 2049 int i, rulewidth = table_rule_width(tbl); 2050 if (rulewidth > 1) { 2051 if (tbl->total_width > 0) 2052 tbl->total_width = ceil_at_intervals(tbl->total_width, rulewidth); 2053 for (i = 0; i <= tbl->maxcol; i++) { 2054 tbl->minimum_width[i] = 2055 ceil_at_intervals(tbl->minimum_width[i], rulewidth); 2056 tbl->tabwidth[i] = ceil_at_intervals(tbl->tabwidth[i], rulewidth); 2057 if (tbl->fixed_width[i] > 0) 2058 tbl->fixed_width[i] = 2059 ceil_at_intervals(tbl->fixed_width[i], rulewidth); 2060 } 2061 for (i = 0; i <= cell->maxcell; i++) { 2062 cell->minimum_width[i] = 2063 ceil_at_intervals(cell->minimum_width[i], rulewidth); 2064 cell->width[i] = ceil_at_intervals(cell->width[i], rulewidth); 2065 if (cell->fixed_width[i] > 0) 2066 cell->fixed_width[i] = 2067 ceil_at_intervals(cell->fixed_width[i], rulewidth); 2068 } 2069 } 2070 tbl->sloppy_width = fixed_table_width(tbl); 2071 if (tbl->total_width > tbl->sloppy_width) 2072 tbl->sloppy_width = tbl->total_width; 2073 } 2074 2075 static void 2076 check_minimum0(struct table *t, int min) 2077 { 2078 int i, w, ww; 2079 struct table_cell *cell; 2080 2081 if (t->col < 0) 2082 return; 2083 if (t->tabwidth[t->col] < 0) 2084 return; 2085 check_row(t, t->row); 2086 w = table_colspan(t, t->row, t->col); 2087 min += t->indent; 2088 if (w == 1) 2089 ww = min; 2090 else { 2091 cell = &t->cell; 2092 ww = 0; 2093 if (cell->icell >= 0 && cell->minimum_width[cell->icell] < min) 2094 cell->minimum_width[cell->icell] = min; 2095 } 2096 for (i = t->col; 2097 i <= t->maxcol && (i == t->col || (t->tabattr[t->row][i] & HTT_X)); 2098 i++) { 2099 if (t->minimum_width[i] < ww) 2100 t->minimum_width[i] = ww; 2101 } 2102 } 2103 2104 static int 2105 setwidth0(struct table *t, struct table_mode *mode) 2106 { 2107 int w; 2108 int width = t->tabcontentssize; 2109 struct table_cell *cell = &t->cell; 2110 2111 if (t->col < 0) 2112 return -1; 2113 if (t->tabwidth[t->col] < 0) 2114 return -1; 2115 check_row(t, t->row); 2116 if (t->linfo.prev_spaces > 0) 2117 width -= t->linfo.prev_spaces; 2118 w = table_colspan(t, t->row, t->col); 2119 if (w == 1) { 2120 if (t->tabwidth[t->col] < width) 2121 t->tabwidth[t->col] = width; 2122 } 2123 else if (cell->icell >= 0) { 2124 if (cell->width[cell->icell] < width) 2125 cell->width[cell->icell] = width; 2126 } 2127 return width; 2128 } 2129 2130 static void 2131 setwidth(struct table *t, struct table_mode *mode) 2132 { 2133 int width = setwidth0(t, mode); 2134 if (width < 0) 2135 return; 2136 #ifdef NOWRAP 2137 if (t->tabattr[t->row][t->col] & HTT_NOWRAP) 2138 check_minimum0(t, width); 2139 #endif /* NOWRAP */ 2140 if (mode->pre_mode & (TBLM_NOBR | TBLM_PRE | TBLM_PRE_INT) && 2141 mode->nobr_offset >= 0) 2142 check_minimum0(t, width - mode->nobr_offset); 2143 } 2144 2145 static void 2146 addcontentssize(struct table *t, int width) 2147 { 2148 2149 if (t->col < 0) 2150 return; 2151 if (t->tabwidth[t->col] < 0) 2152 return; 2153 check_row(t, t->row); 2154 t->tabcontentssize += width; 2155 } 2156 2157 static void table_close_anchor0(struct table *tbl, struct table_mode *mode); 2158 2159 static void 2160 clearcontentssize(struct table *t, struct table_mode *mode) 2161 { 2162 table_close_anchor0(t, mode); 2163 mode->nobr_offset = 0; 2164 t->linfo.prev_spaces = -1; 2165 set_space_to_prevchar(t->linfo.prevchar); 2166 t->linfo.prev_ctype = PC_ASCII; 2167 t->linfo.length = 0; 2168 t->tabcontentssize = 0; 2169 } 2170 2171 static void 2172 begin_cell(struct table *t, struct table_mode *mode) 2173 { 2174 clearcontentssize(t, mode); 2175 mode->indent_level = 0; 2176 mode->nobr_level = 0; 2177 mode->pre_mode = 0; 2178 t->indent = 0; 2179 t->flag |= TBL_IN_COL; 2180 2181 if (t->suspended_data) { 2182 check_row(t, t->row); 2183 if (t->tabdata[t->row][t->col] == NULL) 2184 t->tabdata[t->row][t->col] = newGeneralList(); 2185 appendGeneralList(t->tabdata[t->row][t->col], 2186 (GeneralList *)t->suspended_data); 2187 t->suspended_data = NULL; 2188 } 2189 } 2190 2191 void 2192 check_rowcol(struct table *tbl, struct table_mode *mode) 2193 { 2194 int row = tbl->row, col = tbl->col; 2195 2196 if (!(tbl->flag & TBL_IN_ROW)) { 2197 tbl->flag |= TBL_IN_ROW; 2198 tbl->row++; 2199 if (tbl->row > tbl->maxrow) 2200 tbl->maxrow = tbl->row; 2201 tbl->col = -1; 2202 } 2203 if (tbl->row == -1) 2204 tbl->row = 0; 2205 if (tbl->col == -1) 2206 tbl->col = 0; 2207 2208 for (;; tbl->row++) { 2209 check_row(tbl, tbl->row); 2210 for (; tbl->col < MAXCOL && 2211 tbl->tabattr[tbl->row][tbl->col] & (HTT_X | HTT_Y); tbl->col++) ; 2212 if (tbl->col < MAXCOL) 2213 break; 2214 tbl->col = 0; 2215 } 2216 if (tbl->row > tbl->maxrow) 2217 tbl->maxrow = tbl->row; 2218 if (tbl->col > tbl->maxcol) 2219 tbl->maxcol = tbl->col; 2220 2221 if (tbl->row != row || tbl->col != col) 2222 begin_cell(tbl, mode); 2223 tbl->flag |= TBL_IN_COL; 2224 } 2225 2226 int 2227 skip_space(struct table *t, char *line, struct table_linfo *linfo, 2228 int checkminimum) 2229 { 2230 int skip = 0, s = linfo->prev_spaces; 2231 Lineprop ctype, prev_ctype = linfo->prev_ctype; 2232 Str prevchar = linfo->prevchar; 2233 int w = linfo->length; 2234 int min = 1; 2235 2236 if (*line == '<' && line[strlen(line) - 1] == '>') { 2237 if (checkminimum) 2238 check_minimum0(t, visible_length(line)); 2239 return 0; 2240 } 2241 2242 while (*line) { 2243 char *save = line, *c = line; 2244 int ec, len, wlen, plen; 2245 ctype = get_mctype(line); 2246 len = get_mcwidth(line); 2247 wlen = plen = get_mclen(line); 2248 2249 if (min < w) 2250 min = w; 2251 if (ctype == PC_ASCII && IS_SPACE(*c)) { 2252 w = 0; 2253 s++; 2254 } 2255 else { 2256 if (*c == '&') { 2257 ec = getescapechar(&line); 2258 if (ec >= 0) { 2259 c = conv_entity(ec); 2260 ctype = get_mctype(c); 2261 len = get_strwidth(c); 2262 wlen = line - save; 2263 plen = get_mclen(c); 2264 } 2265 } 2266 if (prevchar->length && is_boundary((unsigned char *)prevchar->ptr, 2267 (unsigned char *)c)) { 2268 w = len; 2269 } 2270 else { 2271 w += len; 2272 } 2273 if (s > 0) { 2274 #ifdef USE_M17N 2275 if (ctype == PC_KANJI1 && prev_ctype == PC_KANJI1) 2276 skip += s; 2277 else 2278 #endif 2279 skip += s - 1; 2280 } 2281 s = 0; 2282 prev_ctype = ctype; 2283 } 2284 set_prevchar(prevchar, c, plen); 2285 line = save + wlen; 2286 } 2287 if (s > 1) { 2288 skip += s - 1; 2289 linfo->prev_spaces = 1; 2290 } 2291 else { 2292 linfo->prev_spaces = s; 2293 } 2294 linfo->prev_ctype = prev_ctype; 2295 linfo->prevchar = prevchar; 2296 2297 if (checkminimum) { 2298 if (min < w) 2299 min = w; 2300 linfo->length = w; 2301 check_minimum0(t, min); 2302 } 2303 return skip; 2304 } 2305 2306 static void 2307 feed_table_inline_tag(struct table *tbl, 2308 char *line, struct table_mode *mode, int width) 2309 { 2310 check_rowcol(tbl, mode); 2311 pushdata(tbl, tbl->row, tbl->col, line); 2312 if (width >= 0) { 2313 check_minimum0(tbl, width); 2314 addcontentssize(tbl, width); 2315 setwidth(tbl, mode); 2316 } 2317 } 2318 2319 static void 2320 feed_table_block_tag(struct table *tbl, 2321 char *line, struct table_mode *mode, int indent, int cmd) 2322 { 2323 int offset; 2324 if (mode->indent_level <= 0 && indent == -1) 2325 return; 2326 setwidth(tbl, mode); 2327 feed_table_inline_tag(tbl, line, mode, -1); 2328 clearcontentssize(tbl, mode); 2329 if (indent == 1) { 2330 mode->indent_level++; 2331 if (mode->indent_level <= MAX_INDENT_LEVEL) 2332 tbl->indent += INDENT_INCR; 2333 } 2334 else if (indent == -1) { 2335 mode->indent_level--; 2336 if (mode->indent_level < MAX_INDENT_LEVEL) 2337 tbl->indent -= INDENT_INCR; 2338 } 2339 offset = tbl->indent; 2340 if (cmd == HTML_DT) { 2341 if (mode->indent_level > 0 && mode->indent_level <= MAX_INDENT_LEVEL) 2342 offset -= INDENT_INCR; 2343 } 2344 if (tbl->indent > 0) { 2345 check_minimum0(tbl, 0); 2346 addcontentssize(tbl, offset); 2347 } 2348 } 2349 2350 static void 2351 table_close_select(struct table *tbl, struct table_mode *mode, int width) 2352 { 2353 Str tmp = process_n_select(); 2354 mode->pre_mode &= ~TBLM_INSELECT; 2355 mode->end_tag = 0; 2356 feed_table1(tbl, tmp, mode, width); 2357 } 2358 2359 static void 2360 table_close_textarea(struct table *tbl, struct table_mode *mode, int width) 2361 { 2362 Str tmp = process_n_textarea(); 2363 mode->pre_mode &= ~TBLM_INTXTA; 2364 mode->end_tag = 0; 2365 feed_table1(tbl, tmp, mode, width); 2366 } 2367 2368 static void 2369 table_close_anchor0(struct table *tbl, struct table_mode *mode) 2370 { 2371 if (!(mode->pre_mode & TBLM_ANCHOR)) 2372 return; 2373 mode->pre_mode &= ~TBLM_ANCHOR; 2374 if (tbl->tabcontentssize == mode->anchor_offset) { 2375 check_minimum0(tbl, 1); 2376 addcontentssize(tbl, 1); 2377 setwidth(tbl, mode); 2378 } 2379 else if (tbl->linfo.prev_spaces > 0 && 2380 tbl->tabcontentssize - 1 == mode->anchor_offset) { 2381 if (tbl->linfo.prev_spaces > 0) 2382 tbl->linfo.prev_spaces = -1; 2383 } 2384 } 2385 2386 #define TAG_ACTION_NONE 0 2387 #define TAG_ACTION_FEED 1 2388 #define TAG_ACTION_TABLE 2 2389 #define TAG_ACTION_N_TABLE 3 2390 #define TAG_ACTION_PLAIN 4 2391 2392 #define CASE_TABLE_TAG \ 2393 case HTML_TABLE:\ 2394 case HTML_N_TABLE:\ 2395 case HTML_TR:\ 2396 case HTML_N_TR:\ 2397 case HTML_TD:\ 2398 case HTML_N_TD:\ 2399 case HTML_TH:\ 2400 case HTML_N_TH:\ 2401 case HTML_THEAD:\ 2402 case HTML_N_THEAD:\ 2403 case HTML_TBODY:\ 2404 case HTML_N_TBODY:\ 2405 case HTML_TFOOT:\ 2406 case HTML_N_TFOOT:\ 2407 case HTML_COLGROUP:\ 2408 case HTML_N_COLGROUP:\ 2409 case HTML_COL 2410 2411 #define ATTR_ROWSPAN_MAX 32766 2412 2413 static int 2414 feed_table_tag(struct table *tbl, char *line, struct table_mode *mode, 2415 int width, struct parsed_tag *tag) 2416 { 2417 int cmd; 2418 #ifdef ID_EXT 2419 char *p; 2420 #endif 2421 struct table_cell *cell = &tbl->cell; 2422 int colspan, rowspan; 2423 int col, prev_col; 2424 int i, j, k, v, v0, w, id; 2425 Str tok, tmp, anchor; 2426 table_attr align, valign; 2427 2428 cmd = tag->tagid; 2429 2430 if (mode->pre_mode & TBLM_PLAIN) { 2431 if (mode->end_tag == cmd) { 2432 mode->pre_mode &= ~TBLM_PLAIN; 2433 mode->end_tag = 0; 2434 feed_table_block_tag(tbl, line, mode, 0, cmd); 2435 return TAG_ACTION_NONE; 2436 } 2437 return TAG_ACTION_PLAIN; 2438 } 2439 if (mode->pre_mode & TBLM_INTXTA) { 2440 switch (cmd) { 2441 CASE_TABLE_TAG: 2442 case HTML_N_TEXTAREA: 2443 table_close_textarea(tbl, mode, width); 2444 if (cmd == HTML_N_TEXTAREA) 2445 return TAG_ACTION_NONE; 2446 break; 2447 default: 2448 return TAG_ACTION_FEED; 2449 } 2450 } 2451 if (mode->pre_mode & TBLM_SCRIPT) { 2452 if (mode->end_tag == cmd) { 2453 mode->pre_mode &= ~TBLM_SCRIPT; 2454 mode->end_tag = 0; 2455 return TAG_ACTION_NONE; 2456 } 2457 return TAG_ACTION_PLAIN; 2458 } 2459 if (mode->pre_mode & TBLM_STYLE) { 2460 if (mode->end_tag == cmd) { 2461 mode->pre_mode &= ~TBLM_STYLE; 2462 mode->end_tag = 0; 2463 return TAG_ACTION_NONE; 2464 } 2465 return TAG_ACTION_PLAIN; 2466 } 2467 /* failsafe: a tag other than <option></option>and </select> in * 2468 * <select> environment is regarded as the end of <select>. */ 2469 if (mode->pre_mode & TBLM_INSELECT) { 2470 switch (cmd) { 2471 CASE_TABLE_TAG: 2472 case HTML_N_FORM: 2473 case HTML_N_SELECT: /* mode->end_tag */ 2474 table_close_select(tbl, mode, width); 2475 if (cmd == HTML_N_SELECT) 2476 return TAG_ACTION_NONE; 2477 break; 2478 default: 2479 return TAG_ACTION_FEED; 2480 } 2481 } 2482 if (mode->caption) { 2483 switch (cmd) { 2484 CASE_TABLE_TAG: 2485 case HTML_N_CAPTION: 2486 mode->caption = 0; 2487 if (cmd == HTML_N_CAPTION) 2488 return TAG_ACTION_NONE; 2489 break; 2490 default: 2491 return TAG_ACTION_FEED; 2492 } 2493 } 2494 2495 if (mode->pre_mode & TBLM_PRE) { 2496 switch (cmd) { 2497 case HTML_NOBR: 2498 case HTML_N_NOBR: 2499 case HTML_PRE_INT: 2500 case HTML_N_PRE_INT: 2501 return TAG_ACTION_NONE; 2502 } 2503 } 2504 2505 switch (cmd) { 2506 case HTML_TABLE: 2507 check_rowcol(tbl, mode); 2508 return TAG_ACTION_TABLE; 2509 case HTML_N_TABLE: 2510 if (tbl->suspended_data) 2511 check_rowcol(tbl, mode); 2512 return TAG_ACTION_N_TABLE; 2513 case HTML_TR: 2514 if (tbl->col >= 0 && tbl->tabcontentssize > 0) 2515 setwidth(tbl, mode); 2516 tbl->col = -1; 2517 tbl->row++; 2518 tbl->flag |= TBL_IN_ROW; 2519 tbl->flag &= ~TBL_IN_COL; 2520 align = 0; 2521 valign = 0; 2522 if (parsedtag_get_value(tag, ATTR_ALIGN, &i)) { 2523 switch (i) { 2524 case ALIGN_LEFT: 2525 align = (HTT_LEFT | HTT_TRSET); 2526 break; 2527 case ALIGN_RIGHT: 2528 align = (HTT_RIGHT | HTT_TRSET); 2529 break; 2530 case ALIGN_CENTER: 2531 align = (HTT_CENTER | HTT_TRSET); 2532 break; 2533 } 2534 } 2535 if (parsedtag_get_value(tag, ATTR_VALIGN, &i)) { 2536 switch (i) { 2537 case VALIGN_TOP: 2538 valign = (HTT_TOP | HTT_VTRSET); 2539 break; 2540 case VALIGN_MIDDLE: 2541 valign = (HTT_MIDDLE | HTT_VTRSET); 2542 break; 2543 case VALIGN_BOTTOM: 2544 valign = (HTT_BOTTOM | HTT_VTRSET); 2545 break; 2546 } 2547 } 2548 #ifdef ID_EXT 2549 if (parsedtag_get_value(tag, ATTR_ID, &p)) 2550 tbl->tridvalue[tbl->row] = Strnew_charp(p); 2551 #endif /* ID_EXT */ 2552 tbl->trattr = align | valign; 2553 break; 2554 case HTML_TH: 2555 case HTML_TD: 2556 prev_col = tbl->col; 2557 if (tbl->col >= 0 && tbl->tabcontentssize > 0) 2558 setwidth(tbl, mode); 2559 if (tbl->row == -1) { 2560 /* for broken HTML... */ 2561 tbl->row = -1; 2562 tbl->col = -1; 2563 tbl->maxrow = tbl->row; 2564 } 2565 if (tbl->col == -1) { 2566 if (!(tbl->flag & TBL_IN_ROW)) { 2567 tbl->row++; 2568 tbl->flag |= TBL_IN_ROW; 2569 } 2570 if (tbl->row > tbl->maxrow) 2571 tbl->maxrow = tbl->row; 2572 } 2573 tbl->col++; 2574 check_row(tbl, tbl->row); 2575 while (tbl->tabattr[tbl->row][tbl->col]) { 2576 tbl->col++; 2577 } 2578 if (tbl->col > MAXCOL - 1) { 2579 tbl->col = prev_col; 2580 return TAG_ACTION_NONE; 2581 } 2582 if (tbl->col > tbl->maxcol) { 2583 tbl->maxcol = tbl->col; 2584 } 2585 colspan = rowspan = 1; 2586 if (tbl->trattr & HTT_TRSET) 2587 align = (tbl->trattr & HTT_ALIGN); 2588 else if (cmd == HTML_TH) 2589 align = HTT_CENTER; 2590 else 2591 align = HTT_LEFT; 2592 if (tbl->trattr & HTT_VTRSET) 2593 valign = (tbl->trattr & HTT_VALIGN); 2594 else 2595 valign = HTT_MIDDLE; 2596 if (parsedtag_get_value(tag, ATTR_ROWSPAN, &rowspan)) { 2597 if(rowspan > ATTR_ROWSPAN_MAX) { 2598 rowspan = ATTR_ROWSPAN_MAX; 2599 } 2600 if ((tbl->row + rowspan) >= tbl->max_rowsize) 2601 check_row(tbl, tbl->row + rowspan); 2602 } 2603 if (parsedtag_get_value(tag, ATTR_COLSPAN, &colspan)) { 2604 if ((tbl->col + colspan) >= MAXCOL) { 2605 /* Can't expand column */ 2606 colspan = MAXCOL - tbl->col; 2607 } 2608 } 2609 if (parsedtag_get_value(tag, ATTR_ALIGN, &i)) { 2610 switch (i) { 2611 case ALIGN_LEFT: 2612 align = HTT_LEFT; 2613 break; 2614 case ALIGN_RIGHT: 2615 align = HTT_RIGHT; 2616 break; 2617 case ALIGN_CENTER: 2618 align = HTT_CENTER; 2619 break; 2620 } 2621 } 2622 if (parsedtag_get_value(tag, ATTR_VALIGN, &i)) { 2623 switch (i) { 2624 case VALIGN_TOP: 2625 valign = HTT_TOP; 2626 break; 2627 case VALIGN_MIDDLE: 2628 valign = HTT_MIDDLE; 2629 break; 2630 case VALIGN_BOTTOM: 2631 valign = HTT_BOTTOM; 2632 break; 2633 } 2634 } 2635 #ifdef NOWRAP 2636 if (parsedtag_exists(tag, ATTR_NOWRAP)) 2637 tbl->tabattr[tbl->row][tbl->col] |= HTT_NOWRAP; 2638 #endif /* NOWRAP */ 2639 v = 0; 2640 if (parsedtag_get_value(tag, ATTR_WIDTH, &v)) { 2641 #ifdef TABLE_EXPAND 2642 if (v > 0) { 2643 if (tbl->real_width > 0) 2644 v = -(v * 100) / (tbl->real_width * pixel_per_char); 2645 else 2646 v = (int)(v / pixel_per_char); 2647 } 2648 #else 2649 v = RELATIVE_WIDTH(v); 2650 #endif /* not TABLE_EXPAND */ 2651 } 2652 #ifdef ID_EXT 2653 if (parsedtag_get_value(tag, ATTR_ID, &p)) 2654 tbl->tabidvalue[tbl->row][tbl->col] = Strnew_charp(p); 2655 #endif /* ID_EXT */ 2656 #ifdef NOWRAP 2657 if (v != 0) { 2658 /* NOWRAP and WIDTH= conflicts each other */ 2659 tbl->tabattr[tbl->row][tbl->col] &= ~HTT_NOWRAP; 2660 } 2661 #endif /* NOWRAP */ 2662 tbl->tabattr[tbl->row][tbl->col] &= ~(HTT_ALIGN | HTT_VALIGN); 2663 tbl->tabattr[tbl->row][tbl->col] |= (align | valign); 2664 if (colspan > 1) { 2665 col = tbl->col; 2666 2667 cell->icell = cell->maxcell + 1; 2668 k = bsearch_2short(colspan, cell->colspan, col, cell->col, MAXCOL, 2669 cell->index, cell->icell); 2670 if (k <= cell->maxcell) { 2671 i = cell->index[k]; 2672 if (cell->col[i] == col && cell->colspan[i] == colspan) 2673 cell->icell = i; 2674 } 2675 if (cell->icell > cell->maxcell && cell->icell < MAXCELL) { 2676 cell->maxcell++; 2677 cell->col[cell->maxcell] = col; 2678 cell->colspan[cell->maxcell] = colspan; 2679 cell->width[cell->maxcell] = 0; 2680 cell->minimum_width[cell->maxcell] = 0; 2681 cell->fixed_width[cell->maxcell] = 0; 2682 if (cell->maxcell > k) { 2683 int ii; 2684 for (ii = cell->maxcell; ii > k; ii--) 2685 cell->index[ii] = cell->index[ii - 1]; 2686 } 2687 cell->index[k] = cell->maxcell; 2688 } 2689 if (cell->icell > cell->maxcell) 2690 cell->icell = -1; 2691 } 2692 if (v != 0) { 2693 if (colspan == 1) { 2694 v0 = tbl->fixed_width[tbl->col]; 2695 if (v0 == 0 || (v0 > 0 && v > v0) || (v0 < 0 && v < v0)) { 2696 #ifdef FEED_TABLE_DEBUG 2697 fprintf(stderr, "width(%d) = %d\n", tbl->col, v); 2698 #endif /* TABLE_DEBUG */ 2699 tbl->fixed_width[tbl->col] = v; 2700 } 2701 } 2702 else if (cell->icell >= 0) { 2703 v0 = cell->fixed_width[cell->icell]; 2704 if (v0 == 0 || (v0 > 0 && v > v0) || (v0 < 0 && v < v0)) 2705 cell->fixed_width[cell->icell] = v; 2706 } 2707 } 2708 for (i = 0; i < rowspan; i++) { 2709 check_row(tbl, tbl->row + i); 2710 for (j = 0; j < colspan; j++) { 2711 #if 0 2712 tbl->tabattr[tbl->row + i][tbl->col + j] &= ~(HTT_X | HTT_Y); 2713 #endif 2714 if (!(tbl->tabattr[tbl->row + i][tbl->col + j] & 2715 (HTT_X | HTT_Y))) { 2716 tbl->tabattr[tbl->row + i][tbl->col + j] |= 2717 ((i > 0) ? HTT_Y : 0) | ((j > 0) ? HTT_X : 0); 2718 } 2719 if (tbl->col + j > tbl->maxcol) { 2720 tbl->maxcol = tbl->col + j; 2721 } 2722 } 2723 if (tbl->row + i > tbl->maxrow) { 2724 tbl->maxrow = tbl->row + i; 2725 } 2726 } 2727 begin_cell(tbl, mode); 2728 break; 2729 case HTML_N_TR: 2730 setwidth(tbl, mode); 2731 tbl->col = -1; 2732 tbl->flag &= ~(TBL_IN_ROW | TBL_IN_COL); 2733 return TAG_ACTION_NONE; 2734 case HTML_N_TH: 2735 case HTML_N_TD: 2736 setwidth(tbl, mode); 2737 tbl->flag &= ~TBL_IN_COL; 2738 #ifdef FEED_TABLE_DEBUG 2739 { 2740 TextListItem *it; 2741 int i = tbl->col, j = tbl->row; 2742 fprintf(stderr, "(a) row,col: %d, %d\n", j, i); 2743 if (tbl->tabdata[j] && tbl->tabdata[j][i]) { 2744 for (it = ((TextList *)tbl->tabdata[j][i])->first; 2745 it; it = it->next) 2746 fprintf(stderr, " [%s] \n", it->ptr); 2747 } 2748 } 2749 #endif 2750 return TAG_ACTION_NONE; 2751 case HTML_P: 2752 case HTML_BR: 2753 case HTML_CENTER: 2754 case HTML_N_CENTER: 2755 case HTML_DIV: 2756 case HTML_N_DIV: 2757 if (!(tbl->flag & TBL_IN_ROW)) 2758 break; 2759 case HTML_DT: 2760 case HTML_DD: 2761 case HTML_H: 2762 case HTML_N_H: 2763 case HTML_LI: 2764 case HTML_PRE: 2765 case HTML_N_PRE: 2766 case HTML_HR: 2767 case HTML_LISTING: 2768 case HTML_XMP: 2769 case HTML_PLAINTEXT: 2770 case HTML_PRE_PLAIN: 2771 case HTML_N_PRE_PLAIN: 2772 feed_table_block_tag(tbl, line, mode, 0, cmd); 2773 switch (cmd) { 2774 case HTML_PRE: 2775 case HTML_PRE_PLAIN: 2776 mode->pre_mode |= TBLM_PRE; 2777 break; 2778 case HTML_N_PRE: 2779 case HTML_N_PRE_PLAIN: 2780 mode->pre_mode &= ~TBLM_PRE; 2781 break; 2782 case HTML_LISTING: 2783 mode->pre_mode |= TBLM_PLAIN; 2784 mode->end_tag = HTML_N_LISTING; 2785 break; 2786 case HTML_XMP: 2787 mode->pre_mode |= TBLM_PLAIN; 2788 mode->end_tag = HTML_N_XMP; 2789 break; 2790 case HTML_PLAINTEXT: 2791 mode->pre_mode |= TBLM_PLAIN; 2792 mode->end_tag = MAX_HTMLTAG; 2793 break; 2794 } 2795 break; 2796 case HTML_DL: 2797 case HTML_BLQ: 2798 case HTML_OL: 2799 case HTML_UL: 2800 feed_table_block_tag(tbl, line, mode, 1, cmd); 2801 break; 2802 case HTML_N_DL: 2803 case HTML_N_BLQ: 2804 case HTML_N_OL: 2805 case HTML_N_UL: 2806 feed_table_block_tag(tbl, line, mode, -1, cmd); 2807 break; 2808 case HTML_NOBR: 2809 case HTML_WBR: 2810 if (!(tbl->flag & TBL_IN_ROW)) 2811 break; 2812 case HTML_PRE_INT: 2813 feed_table_inline_tag(tbl, line, mode, -1); 2814 switch (cmd) { 2815 case HTML_NOBR: 2816 mode->nobr_level++; 2817 if (mode->pre_mode & TBLM_NOBR) 2818 return TAG_ACTION_NONE; 2819 mode->pre_mode |= TBLM_NOBR; 2820 break; 2821 case HTML_PRE_INT: 2822 if (mode->pre_mode & TBLM_PRE_INT) 2823 return TAG_ACTION_NONE; 2824 mode->pre_mode |= TBLM_PRE_INT; 2825 tbl->linfo.prev_spaces = 0; 2826 break; 2827 } 2828 mode->nobr_offset = -1; 2829 if (tbl->linfo.length > 0) { 2830 check_minimum0(tbl, tbl->linfo.length); 2831 tbl->linfo.length = 0; 2832 } 2833 break; 2834 case HTML_N_NOBR: 2835 if (!(tbl->flag & TBL_IN_ROW)) 2836 break; 2837 feed_table_inline_tag(tbl, line, mode, -1); 2838 if (mode->nobr_level > 0) 2839 mode->nobr_level--; 2840 if (mode->nobr_level == 0) 2841 mode->pre_mode &= ~TBLM_NOBR; 2842 break; 2843 case HTML_N_PRE_INT: 2844 feed_table_inline_tag(tbl, line, mode, -1); 2845 mode->pre_mode &= ~TBLM_PRE_INT; 2846 break; 2847 case HTML_IMG: 2848 check_rowcol(tbl, mode); 2849 w = tbl->fixed_width[tbl->col]; 2850 if (w < 0) { 2851 if (tbl->total_width > 0) 2852 w = -tbl->total_width * w / 100; 2853 else if (width > 0) 2854 w = -width * w / 100; 2855 else 2856 w = 0; 2857 } 2858 else if (w == 0) { 2859 if (tbl->total_width > 0) 2860 w = tbl->total_width; 2861 else if (width > 0) 2862 w = width; 2863 } 2864 tok = process_img(tag, w); 2865 feed_table1(tbl, tok, mode, width); 2866 break; 2867 case HTML_FORM: 2868 feed_table_block_tag(tbl, "", mode, 0, cmd); 2869 tmp = process_form(tag); 2870 if (tmp) 2871 feed_table1(tbl, tmp, mode, width); 2872 break; 2873 case HTML_N_FORM: 2874 feed_table_block_tag(tbl, "", mode, 0, cmd); 2875 process_n_form(); 2876 break; 2877 case HTML_INPUT: 2878 tmp = process_input(tag); 2879 feed_table1(tbl, tmp, mode, width); 2880 break; 2881 case HTML_SELECT: 2882 tmp = process_select(tag); 2883 if (tmp) 2884 feed_table1(tbl, tmp, mode, width); 2885 mode->pre_mode |= TBLM_INSELECT; 2886 mode->end_tag = HTML_N_SELECT; 2887 break; 2888 case HTML_N_SELECT: 2889 case HTML_OPTION: 2890 /* nothing */ 2891 break; 2892 case HTML_TEXTAREA: 2893 w = 0; 2894 check_rowcol(tbl, mode); 2895 if (tbl->col + 1 <= tbl->maxcol && 2896 tbl->tabattr[tbl->row][tbl->col + 1] & HTT_X) { 2897 if (cell->icell >= 0 && cell->fixed_width[cell->icell] > 0) 2898 w = cell->fixed_width[cell->icell]; 2899 } 2900 else { 2901 if (tbl->fixed_width[tbl->col] > 0) 2902 w = tbl->fixed_width[tbl->col]; 2903 } 2904 tmp = process_textarea(tag, w); 2905 if (tmp) 2906 feed_table1(tbl, tmp, mode, width); 2907 mode->pre_mode |= TBLM_INTXTA; 2908 mode->end_tag = HTML_N_TEXTAREA; 2909 break; 2910 case HTML_A: 2911 table_close_anchor0(tbl, mode); 2912 anchor = NULL; 2913 i = 0; 2914 parsedtag_get_value(tag, ATTR_HREF, &anchor); 2915 parsedtag_get_value(tag, ATTR_HSEQ, &i); 2916 if (anchor) { 2917 check_rowcol(tbl, mode); 2918 if (i == 0) { 2919 Str tmp = process_anchor(tag, line); 2920 if (displayLinkNumber) 2921 { 2922 Str t = getLinkNumberStr(-1); 2923 feed_table_inline_tag(tbl, NULL, mode, t->length); 2924 Strcat(tmp, t); 2925 } 2926 pushdata(tbl, tbl->row, tbl->col, tmp->ptr); 2927 } 2928 else 2929 pushdata(tbl, tbl->row, tbl->col, line); 2930 if (i >= 0) { 2931 mode->pre_mode |= TBLM_ANCHOR; 2932 mode->anchor_offset = tbl->tabcontentssize; 2933 } 2934 } 2935 else 2936 suspend_or_pushdata(tbl, line); 2937 break; 2938 case HTML_DEL: 2939 switch (displayInsDel) { 2940 case DISPLAY_INS_DEL_SIMPLE: 2941 mode->pre_mode |= TBLM_DEL; 2942 break; 2943 case DISPLAY_INS_DEL_NORMAL: 2944 feed_table_inline_tag(tbl, line, mode, 5); /* [DEL: */ 2945 break; 2946 case DISPLAY_INS_DEL_FONTIFY: 2947 feed_table_inline_tag(tbl, line, mode, -1); 2948 break; 2949 } 2950 break; 2951 case HTML_N_DEL: 2952 switch (displayInsDel) { 2953 case DISPLAY_INS_DEL_SIMPLE: 2954 mode->pre_mode &= ~TBLM_DEL; 2955 break; 2956 case DISPLAY_INS_DEL_NORMAL: 2957 feed_table_inline_tag(tbl, line, mode, 5); /* :DEL] */ 2958 break; 2959 case DISPLAY_INS_DEL_FONTIFY: 2960 feed_table_inline_tag(tbl, line, mode, -1); 2961 break; 2962 } 2963 break; 2964 case HTML_S: 2965 switch (displayInsDel) { 2966 case DISPLAY_INS_DEL_SIMPLE: 2967 mode->pre_mode |= TBLM_S; 2968 break; 2969 case DISPLAY_INS_DEL_NORMAL: 2970 feed_table_inline_tag(tbl, line, mode, 3); /* [S: */ 2971 break; 2972 case DISPLAY_INS_DEL_FONTIFY: 2973 feed_table_inline_tag(tbl, line, mode, -1); 2974 break; 2975 } 2976 break; 2977 case HTML_N_S: 2978 switch (displayInsDel) { 2979 case DISPLAY_INS_DEL_SIMPLE: 2980 mode->pre_mode &= ~TBLM_S; 2981 break; 2982 case DISPLAY_INS_DEL_NORMAL: 2983 feed_table_inline_tag(tbl, line, mode, 3); /* :S] */ 2984 break; 2985 case DISPLAY_INS_DEL_FONTIFY: 2986 feed_table_inline_tag(tbl, line, mode, -1); 2987 break; 2988 } 2989 break; 2990 case HTML_INS: 2991 case HTML_N_INS: 2992 switch (displayInsDel) { 2993 case DISPLAY_INS_DEL_SIMPLE: 2994 break; 2995 case DISPLAY_INS_DEL_NORMAL: 2996 feed_table_inline_tag(tbl, line, mode, 5); /* [INS:, :INS] */ 2997 break; 2998 case DISPLAY_INS_DEL_FONTIFY: 2999 feed_table_inline_tag(tbl, line, mode, -1); 3000 break; 3001 } 3002 break; 3003 case HTML_SUP: 3004 case HTML_SUB: 3005 case HTML_N_SUB: 3006 if (!(mode->pre_mode & (TBLM_DEL | TBLM_S))) 3007 feed_table_inline_tag(tbl, line, mode, 1); /* ^, [, ] */ 3008 break; 3009 case HTML_N_SUP: 3010 break; 3011 case HTML_TABLE_ALT: 3012 id = -1; 3013 w = 0; 3014 parsedtag_get_value(tag, ATTR_TID, &id); 3015 if (id >= 0 && id < tbl->ntable) { 3016 struct table *tbl1 = tbl->tables[id].ptr; 3017 feed_table_block_tag(tbl, line, mode, 0, cmd); 3018 addcontentssize(tbl, maximum_table_width(tbl1)); 3019 check_minimum0(tbl, tbl1->sloppy_width); 3020 #ifdef TABLE_EXPAND 3021 w = tbl1->total_width; 3022 v = 0; 3023 colspan = table_colspan(tbl, tbl->row, tbl->col); 3024 if (colspan > 1) { 3025 if (cell->icell >= 0) 3026 v = cell->fixed_width[cell->icell]; 3027 } 3028 else 3029 v = tbl->fixed_width[tbl->col]; 3030 if (v < 0 && tbl->real_width > 0 && tbl1->real_width > 0) 3031 w = -(tbl1->real_width * 100) / tbl->real_width; 3032 else 3033 w = tbl1->real_width; 3034 if (w > 0) 3035 check_minimum0(tbl, w); 3036 else if (w < 0 && v < w) { 3037 if (colspan > 1) { 3038 if (cell->icell >= 0) 3039 cell->fixed_width[cell->icell] = w; 3040 } 3041 else 3042 tbl->fixed_width[tbl->col] = w; 3043 } 3044 #endif 3045 setwidth0(tbl, mode); 3046 clearcontentssize(tbl, mode); 3047 } 3048 break; 3049 case HTML_CAPTION: 3050 mode->caption = 1; 3051 break; 3052 case HTML_N_CAPTION: 3053 case HTML_THEAD: 3054 case HTML_N_THEAD: 3055 case HTML_TBODY: 3056 case HTML_N_TBODY: 3057 case HTML_TFOOT: 3058 case HTML_N_TFOOT: 3059 case HTML_COLGROUP: 3060 case HTML_N_COLGROUP: 3061 case HTML_COL: 3062 break; 3063 case HTML_SCRIPT: 3064 mode->pre_mode |= TBLM_SCRIPT; 3065 mode->end_tag = HTML_N_SCRIPT; 3066 break; 3067 case HTML_STYLE: 3068 mode->pre_mode |= TBLM_STYLE; 3069 mode->end_tag = HTML_N_STYLE; 3070 break; 3071 case HTML_N_A: 3072 table_close_anchor0(tbl, mode); 3073 case HTML_FONT: 3074 case HTML_N_FONT: 3075 case HTML_NOP: 3076 suspend_or_pushdata(tbl, line); 3077 break; 3078 case HTML_INTERNAL: 3079 case HTML_N_INTERNAL: 3080 case HTML_FORM_INT: 3081 case HTML_N_FORM_INT: 3082 case HTML_INPUT_ALT: 3083 case HTML_N_INPUT_ALT: 3084 case HTML_SELECT_INT: 3085 case HTML_N_SELECT_INT: 3086 case HTML_OPTION_INT: 3087 case HTML_TEXTAREA_INT: 3088 case HTML_N_TEXTAREA_INT: 3089 case HTML_IMG_ALT: 3090 case HTML_SYMBOL: 3091 case HTML_N_SYMBOL: 3092 default: 3093 /* unknown tag: put into table */ 3094 return TAG_ACTION_FEED; 3095 } 3096 return TAG_ACTION_NONE; 3097 } 3098 3099 3100 int 3101 feed_table(struct table *tbl, char *line, struct table_mode *mode, 3102 int width, int internal) 3103 { 3104 int i; 3105 char *p; 3106 Str tmp; 3107 struct table_linfo *linfo = &tbl->linfo; 3108 3109 if (*line == '<' && line[1] && REALLY_THE_BEGINNING_OF_A_TAG(line)) { 3110 struct parsed_tag *tag; 3111 p = line; 3112 tag = parse_tag(&p, internal); 3113 if (tag) { 3114 switch (feed_table_tag(tbl, line, mode, width, tag)) { 3115 case TAG_ACTION_NONE: 3116 return -1; 3117 case TAG_ACTION_N_TABLE: 3118 return 0; 3119 case TAG_ACTION_TABLE: 3120 return 1; 3121 case TAG_ACTION_PLAIN: 3122 break; 3123 case TAG_ACTION_FEED: 3124 default: 3125 if (parsedtag_need_reconstruct(tag)) 3126 line = parsedtag2str(tag)->ptr; 3127 } 3128 } 3129 else { 3130 if (!(mode->pre_mode & (TBLM_PLAIN | TBLM_INTXTA | TBLM_INSELECT | 3131 TBLM_SCRIPT | TBLM_STYLE))) 3132 return -1; 3133 } 3134 } 3135 else { 3136 if (mode->pre_mode & (TBLM_DEL | TBLM_S)) 3137 return -1; 3138 } 3139 if (mode->caption) { 3140 Strcat_charp(tbl->caption, line); 3141 return -1; 3142 } 3143 if (mode->pre_mode & TBLM_SCRIPT) 3144 return -1; 3145 if (mode->pre_mode & TBLM_STYLE) 3146 return -1; 3147 if (mode->pre_mode & TBLM_INTXTA) { 3148 feed_textarea(line); 3149 return -1; 3150 } 3151 if (mode->pre_mode & TBLM_INSELECT) { 3152 feed_select(line); 3153 return -1; 3154 } 3155 if (!(mode->pre_mode & TBLM_PLAIN) && 3156 !(*line == '<' && line[strlen(line) - 1] == '>') && 3157 strchr(line, '&') != NULL) { 3158 tmp = Strnew(); 3159 for (p = line; *p;) { 3160 char *q, *r; 3161 if (*p == '&') { 3162 if (!strncasecmp(p, "&", 5) || 3163 !strncasecmp(p, ">", 4) || !strncasecmp(p, "<", 4)) { 3164 /* do not convert */ 3165 Strcat_char(tmp, *p); 3166 p++; 3167 } 3168 else { 3169 int ec; 3170 q = p; 3171 switch (ec = getescapechar(&p)) { 3172 case '<': 3173 Strcat_charp(tmp, "<"); 3174 break; 3175 case '>': 3176 Strcat_charp(tmp, ">"); 3177 break; 3178 case '&': 3179 Strcat_charp(tmp, "&"); 3180 break; 3181 case '\r': 3182 Strcat_char(tmp, '\n'); 3183 break; 3184 default: 3185 r = conv_entity(ec); 3186 if (r != NULL && strlen(r) == 1 && 3187 ec == (unsigned char)*r) { 3188 Strcat_char(tmp, *r); 3189 break; 3190 } 3191 case -1: 3192 Strcat_char(tmp, *q); 3193 p = q + 1; 3194 break; 3195 } 3196 } 3197 } 3198 else { 3199 Strcat_char(tmp, *p); 3200 p++; 3201 } 3202 } 3203 line = tmp->ptr; 3204 } 3205 if (!(mode->pre_mode & (TBLM_SPECIAL & ~TBLM_NOBR))) { 3206 if (!(tbl->flag & TBL_IN_COL) || linfo->prev_spaces != 0) 3207 while (IS_SPACE(*line)) 3208 line++; 3209 if (*line == '\0') 3210 return -1; 3211 check_rowcol(tbl, mode); 3212 if (mode->pre_mode & TBLM_NOBR && mode->nobr_offset < 0) 3213 mode->nobr_offset = tbl->tabcontentssize; 3214 3215 /* count of number of spaces skipped in normal mode */ 3216 i = skip_space(tbl, line, linfo, !(mode->pre_mode & TBLM_NOBR)); 3217 addcontentssize(tbl, visible_length(line) - i); 3218 setwidth(tbl, mode); 3219 pushdata(tbl, tbl->row, tbl->col, line); 3220 } 3221 else if (mode->pre_mode & TBLM_PRE_INT) { 3222 check_rowcol(tbl, mode); 3223 if (mode->nobr_offset < 0) 3224 mode->nobr_offset = tbl->tabcontentssize; 3225 addcontentssize(tbl, maximum_visible_length(line, tbl->tabcontentssize)); 3226 setwidth(tbl, mode); 3227 pushdata(tbl, tbl->row, tbl->col, line); 3228 } 3229 else { 3230 /* <pre> mode or something like it */ 3231 check_rowcol(tbl, mode); 3232 while (*line) { 3233 int nl = FALSE; 3234 if ((p = strchr(line, '\r')) || (p = strchr(line, '\n'))) { 3235 if (*p == '\r' && p[1] == '\n') 3236 p++; 3237 if (p[1]) { 3238 p++; 3239 tmp = Strnew_charp_n(line, p - line); 3240 line = p; 3241 p = tmp->ptr; 3242 } 3243 else { 3244 p = line; 3245 line = ""; 3246 } 3247 nl = TRUE; 3248 } 3249 else { 3250 p = line; 3251 line = ""; 3252 } 3253 if (mode->pre_mode & TBLM_PLAIN) 3254 i = maximum_visible_length_plain(p, tbl->tabcontentssize); 3255 else 3256 i = maximum_visible_length(p, tbl->tabcontentssize); 3257 addcontentssize(tbl, i); 3258 setwidth(tbl, mode); 3259 if (nl) 3260 clearcontentssize(tbl, mode); 3261 pushdata(tbl, tbl->row, tbl->col, p); 3262 } 3263 } 3264 return -1; 3265 } 3266 3267 void 3268 feed_table1(struct table *tbl, Str tok, struct table_mode *mode, int width) 3269 { 3270 Str tokbuf; 3271 int status; 3272 char *line; 3273 if (!tok) 3274 return; 3275 tokbuf = Strnew(); 3276 status = R_ST_NORMAL; 3277 line = tok->ptr; 3278 while (read_token 3279 (tokbuf, &line, &status, mode->pre_mode & TBLM_PREMODE, 0)) 3280 feed_table(tbl, tokbuf->ptr, mode, width, TRUE); 3281 } 3282 3283 void 3284 pushTable(struct table *tbl, struct table *tbl1) 3285 { 3286 int col; 3287 int row; 3288 3289 col = tbl->col; 3290 row = tbl->row; 3291 3292 if (tbl->ntable >= tbl->tables_size) { 3293 struct table_in *tmp; 3294 tbl->tables_size += MAX_TABLE_N; 3295 tmp = New_N(struct table_in, tbl->tables_size); 3296 if (tbl->tables) 3297 bcopy(tbl->tables, tmp, tbl->ntable * sizeof(struct table_in)); 3298 tbl->tables = tmp; 3299 } 3300 3301 tbl->tables[tbl->ntable].ptr = tbl1; 3302 tbl->tables[tbl->ntable].col = col; 3303 tbl->tables[tbl->ntable].row = row; 3304 tbl->tables[tbl->ntable].indent = tbl->indent; 3305 tbl->tables[tbl->ntable].buf = newTextLineList(); 3306 check_row(tbl, row); 3307 if (col + 1 <= tbl->maxcol && tbl->tabattr[row][col + 1] & HTT_X) 3308 tbl->tables[tbl->ntable].cell = tbl->cell.icell; 3309 else 3310 tbl->tables[tbl->ntable].cell = -1; 3311 tbl->ntable++; 3312 } 3313 3314 #ifdef MATRIX 3315 int 3316 correct_table_matrix(struct table *t, int col, int cspan, int a, double b) 3317 { 3318 int i, j; 3319 int ecol = col + cspan; 3320 double w = 1. / (b * b); 3321 3322 for (i = col; i < ecol; i++) { 3323 v_add_val(t->vector, i, w * a); 3324 for (j = i; j < ecol; j++) { 3325 m_add_val(t->matrix, i, j, w); 3326 m_set_val(t->matrix, j, i, m_entry(t->matrix, i, j)); 3327 } 3328 } 3329 return i; 3330 } 3331 3332 static void 3333 correct_table_matrix2(struct table *t, int col, int cspan, double s, double b) 3334 { 3335 int i, j; 3336 int ecol = col + cspan; 3337 int size = t->maxcol + 1; 3338 double w = 1. / (b * b); 3339 double ss; 3340 3341 for (i = 0; i < size; i++) { 3342 for (j = i; j < size; j++) { 3343 if (i >= col && i < ecol && j >= col && j < ecol) 3344 ss = (1. - s) * (1. - s); 3345 else if ((i >= col && i < ecol) || (j >= col && j < ecol)) 3346 ss = -(1. - s) * s; 3347 else 3348 ss = s * s; 3349 m_add_val(t->matrix, i, j, w * ss); 3350 } 3351 } 3352 } 3353 3354 static void 3355 correct_table_matrix3(struct table *t, int col, char *flags, double s, 3356 double b) 3357 { 3358 int i, j; 3359 double ss; 3360 int size = t->maxcol + 1; 3361 double w = 1. / (b * b); 3362 int flg = (flags[col] == 0); 3363 3364 for (i = 0; i < size; i++) { 3365 if (!((flg && flags[i] == 0) || (!flg && flags[i] != 0))) 3366 continue; 3367 for (j = i; j < size; j++) { 3368 if (!((flg && flags[j] == 0) || (!flg && flags[j] != 0))) 3369 continue; 3370 if (i == col && j == col) 3371 ss = (1. - s) * (1. - s); 3372 else if (i == col || j == col) 3373 ss = -(1. - s) * s; 3374 else 3375 ss = s * s; 3376 m_add_val(t->matrix, i, j, w * ss); 3377 } 3378 } 3379 } 3380 3381 static void 3382 correct_table_matrix4(struct table *t, int col, int cspan, char *flags, 3383 double s, double b) 3384 { 3385 int i, j; 3386 double ss; 3387 int ecol = col + cspan; 3388 int size = t->maxcol + 1; 3389 double w = 1. / (b * b); 3390 3391 for (i = 0; i < size; i++) { 3392 if (flags[i] && !(i >= col && i < ecol)) 3393 continue; 3394 for (j = i; j < size; j++) { 3395 if (flags[j] && !(j >= col && j < ecol)) 3396 continue; 3397 if (i >= col && i < ecol && j >= col && j < ecol) 3398 ss = (1. - s) * (1. - s); 3399 else if ((i >= col && i < ecol) || (j >= col && j < ecol)) 3400 ss = -(1. - s) * s; 3401 else 3402 ss = s * s; 3403 m_add_val(t->matrix, i, j, w * ss); 3404 } 3405 } 3406 } 3407 3408 static void 3409 set_table_matrix0(struct table *t, int maxwidth) 3410 { 3411 int size = t->maxcol + 1; 3412 int i, j, k, bcol, ecol; 3413 int width; 3414 double w0, w1, w, s, b; 3415 #ifdef __GNUC__ 3416 double we[size]; 3417 char expand[size]; 3418 #else /* not __GNUC__ */ 3419 double we[MAXCOL]; 3420 char expand[MAXCOL]; 3421 #endif /* not __GNUC__ */ 3422 struct table_cell *cell = &t->cell; 3423 3424 w0 = 0.; 3425 for (i = 0; i < size; i++) { 3426 we[i] = weight(t->tabwidth[i]); 3427 w0 += we[i]; 3428 } 3429 if (w0 <= 0.) 3430 w0 = 1.; 3431 3432 if (cell->necell == 0) { 3433 for (i = 0; i < size; i++) { 3434 s = we[i] / w0; 3435 b = sigma_td_nw((int)(s * maxwidth)); 3436 correct_table_matrix2(t, i, 1, s, b); 3437 } 3438 return; 3439 } 3440 3441 bzero(expand, size); 3442 3443 for (k = 0; k < cell->necell; k++) { 3444 j = cell->eindex[k]; 3445 bcol = cell->col[j]; 3446 ecol = bcol + cell->colspan[j]; 3447 width = cell->width[j] - (cell->colspan[j] - 1) * t->cellspacing; 3448 w1 = 0.; 3449 for (i = bcol; i < ecol; i++) { 3450 w1 += t->tabwidth[i] + 0.1; 3451 expand[i]++; 3452 } 3453 for (i = bcol; i < ecol; i++) { 3454 w = weight(width * (t->tabwidth[i] + 0.1) / w1); 3455 if (w > we[i]) 3456 we[i] = w; 3457 } 3458 } 3459 3460 w0 = 0.; 3461 w1 = 0.; 3462 for (i = 0; i < size; i++) { 3463 w0 += we[i]; 3464 if (expand[i] == 0) 3465 w1 += we[i]; 3466 } 3467 if (w0 <= 0.) 3468 w0 = 1.; 3469 3470 for (k = 0; k < cell->necell; k++) { 3471 j = cell->eindex[k]; 3472 bcol = cell->col[j]; 3473 width = cell->width[j] - (cell->colspan[j] - 1) * t->cellspacing; 3474 w = weight(width); 3475 s = w / (w1 + w); 3476 b = sigma_td_nw((int)(s * maxwidth)); 3477 correct_table_matrix4(t, bcol, cell->colspan[j], expand, s, b); 3478 } 3479 3480 for (i = 0; i < size; i++) { 3481 if (expand[i] == 0) { 3482 s = we[i] / max(w1, 1.); 3483 b = sigma_td_nw((int)(s * maxwidth)); 3484 } 3485 else { 3486 s = we[i] / max(w0 - w1, 1.); 3487 b = sigma_td_nw(maxwidth); 3488 } 3489 correct_table_matrix3(t, i, expand, s, b); 3490 } 3491 } 3492 3493 void 3494 check_relative_width(struct table *t, int maxwidth) 3495 { 3496 int i; 3497 double rel_total = 0; 3498 int size = t->maxcol + 1; 3499 double *rcolwidth = New_N(double, size); 3500 struct table_cell *cell = &t->cell; 3501 int n_leftcol = 0; 3502 3503 for (i = 0; i < size; i++) 3504 rcolwidth[i] = 0; 3505 3506 for (i = 0; i < size; i++) { 3507 if (t->fixed_width[i] < 0) 3508 rcolwidth[i] = -(double)t->fixed_width[i] / 100.0; 3509 else if (t->fixed_width[i] > 0) 3510 rcolwidth[i] = (double)t->fixed_width[i] / maxwidth; 3511 else 3512 n_leftcol++; 3513 } 3514 for (i = 0; i <= cell->maxcell; i++) { 3515 if (cell->fixed_width[i] < 0) { 3516 double w = -(double)cell->fixed_width[i] / 100.0; 3517 double r; 3518 int j, k; 3519 int n_leftcell = 0; 3520 k = cell->col[i]; 3521 r = 0.0; 3522 for (j = 0; j < cell->colspan[i]; j++) { 3523 if (rcolwidth[j + k] > 0) 3524 r += rcolwidth[j + k]; 3525 else 3526 n_leftcell++; 3527 } 3528 if (n_leftcell == 0) { 3529 /* w must be identical to r */ 3530 if (w != r) 3531 cell->fixed_width[i] = -100 * r; 3532 } 3533 else { 3534 if (w <= r) { 3535 /* make room for the left(width-unspecified) cell */ 3536 /* the next formula is an estimation of required width */ 3537 w = r * cell->colspan[i] / (cell->colspan[i] - n_leftcell); 3538 cell->fixed_width[i] = -100 * w; 3539 } 3540 for (j = 0; j < cell->colspan[i]; j++) { 3541 if (rcolwidth[j + k] == 0) 3542 rcolwidth[j + k] = (w - r) / n_leftcell; 3543 } 3544 } 3545 } 3546 else if (cell->fixed_width[i] > 0) { 3547 /* todo */ 3548 } 3549 } 3550 /* sanity check */ 3551 for (i = 0; i < size; i++) 3552 rel_total += rcolwidth[i]; 3553 3554 if ((n_leftcol == 0 && rel_total < 0.9) || 1.1 < rel_total) { 3555 for (i = 0; i < size; i++) { 3556 rcolwidth[i] /= rel_total; 3557 } 3558 for (i = 0; i < size; i++) { 3559 if (t->fixed_width[i] < 0) 3560 t->fixed_width[i] = -rcolwidth[i] * 100; 3561 } 3562 for (i = 0; i <= cell->maxcell; i++) { 3563 if (cell->fixed_width[i] < 0) { 3564 double r; 3565 int j, k; 3566 k = cell->col[i]; 3567 r = 0.0; 3568 for (j = 0; j < cell->colspan[i]; j++) 3569 r += rcolwidth[j + k]; 3570 cell->fixed_width[i] = -r * 100; 3571 } 3572 } 3573 } 3574 } 3575 3576 void 3577 set_table_matrix(struct table *t, int width) 3578 { 3579 int size = t->maxcol + 1; 3580 int i, j; 3581 double b, s; 3582 int a; 3583 struct table_cell *cell = &t->cell; 3584 3585 if (size < 1) 3586 return; 3587 3588 t->matrix = m_get(size, size); 3589 t->vector = v_get(size); 3590 for (i = 0; i < size; i++) { 3591 for (j = i; j < size; j++) 3592 m_set_val(t->matrix, i, j, 0.); 3593 v_set_val(t->vector, i, 0.); 3594 } 3595 3596 check_relative_width(t, width); 3597 3598 for (i = 0; i < size; i++) { 3599 if (t->fixed_width[i] > 0) { 3600 a = max(t->fixed_width[i], t->minimum_width[i]); 3601 b = sigma_td(a); 3602 correct_table_matrix(t, i, 1, a, b); 3603 } 3604 else if (t->fixed_width[i] < 0) { 3605 s = -(double)t->fixed_width[i] / 100.; 3606 b = sigma_td((int)(s * width)); 3607 correct_table_matrix2(t, i, 1, s, b); 3608 } 3609 } 3610 3611 for (j = 0; j <= cell->maxcell; j++) { 3612 if (cell->fixed_width[j] > 0) { 3613 a = max(cell->fixed_width[j], cell->minimum_width[j]); 3614 b = sigma_td(a); 3615 correct_table_matrix(t, cell->col[j], cell->colspan[j], a, b); 3616 } 3617 else if (cell->fixed_width[j] < 0) { 3618 s = -(double)cell->fixed_width[j] / 100.; 3619 b = sigma_td((int)(s * width)); 3620 correct_table_matrix2(t, cell->col[j], cell->colspan[j], s, b); 3621 } 3622 } 3623 3624 set_table_matrix0(t, width); 3625 3626 if (t->total_width > 0) { 3627 b = sigma_table(width); 3628 } 3629 else { 3630 b = sigma_table_nw(width); 3631 } 3632 correct_table_matrix(t, 0, size, width, b); 3633 } 3634 #endif /* MATRIX */ 3635 3636 /* Local Variables: */ 3637 /* c-basic-offset: 4 */ 3638 /* tab-width: 8 */ 3639 /* End: */