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