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, "&amp;", 5) ||
3254 		    !strncasecmp(p, "&gt;", 4) || !strncasecmp(p, "&lt;", 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, "&lt;");
3265 			break;
3266 		    case '>':
3267 			Strcat_charp(tmp, "&gt;");
3268 			break;
3269 		    case '&':
3270 			Strcat_charp(tmp, "&amp;");
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