diff options
author | Akinori Ito <aito@eie.yz.yamagata-u.ac.jp> | 2001-11-08 05:14:08 +0000 |
---|---|---|
committer | Akinori Ito <aito@eie.yz.yamagata-u.ac.jp> | 2001-11-08 05:14:08 +0000 |
commit | 68a07bf03b7624c9924065cce9ffa45497225834 (patch) | |
tree | c2adb06a909a8594445e4a3f8587c4bad46e3ecd /table.c.0 | |
download | w3m-68a07bf03b7624c9924065cce9ffa45497225834.tar.gz w3m-68a07bf03b7624c9924065cce9ffa45497225834.zip |
Initial revision
Diffstat (limited to '')
-rw-r--r-- | table.c.0 | 2878 |
1 files changed, 2878 insertions, 0 deletions
diff --git a/table.c.0 b/table.c.0 new file mode 100644 index 0000000..f3cacb1 --- /dev/null +++ b/table.c.0 @@ -0,0 +1,2878 @@ +/* -*- mode: c; c-basic-offset: 4; tab-width: 8; -*- */ +/* $Id: table.c.0,v 1.1 2001/11/08 05:15:52 a-ito Exp $ */ +/* + * HTML table + */ +#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <math.h> +#ifdef __EMX__ +#include <strings.h> +#endif /* __EMX__ */ + +#include "fm.h" +#include "html.h" +#include "parsetag.h" +#include "Str.h" +#include "myctype.h" + +#ifdef KANJI_SYMBOLS +static char *rule[] = +{"¨«", "¨§", "¨¨", "¨£", "¨©", "¨¢", "¨¤", "07", "¨ª", "¨¦", "¨¡", "0B", "¨¥", "0D", "0E", " "}; +static char *ruleB[] = +{"00", "¨·", "¨¸", "¨®", "¨¹", "¨", "¨¯", "07", "¨º", "¨±", "¨¬", "0B", "¨°", "0D", "0E", " "}; +#define TN_VERTICALBAR "¨¢" +#define HORIZONTALBAR "¨¬" +#define RULE_WIDTH 2 +#else /* not KANJI_SYMBOLS */ +static char *rule[] = +{ + "<_RULE TYPE=0>+</_RULE>", + "<_RULE TYPE=1>+</_RULE>", + "<_RULE TYPE=2>+</_RULE>", + "<_RULE TYPE=3>+</_RULE>", + "<_RULE TYPE=4>+</_RULE>", + "<_RULE TYPE=5>|</_RULE>", + "<_RULE TYPE=6>+</_RULE>", + "<_RULE TYPE=7>07</_RULE>", + "<_RULE TYPE=8>+</_RULE>", + "<_RULE TYPE=9>+</_RULE>", + "<_RULE TYPE=10>-</_RULE>", + "<_RULE TYPE=11>0B</_RULE>", + "<_RULE TYPE=12>+</_RULE>", + "<_RULE TYPE=13>0D</_RULE>", + "<_RULE TYPE=14>0E</_RULE>", + "<_RULE TYPE=15> </_RULE>"}; +static char **ruleB = rule; +#define TN_VERTICALBAR "<_RULE TYPE=5>|</_RULE>" +#define HORIZONTALBAR "<_RULE TYPE=10>-</_RULE>" +#define RULE_WIDTH 1 +#endif /* not KANJI_SYMBOLS */ + +#define RULE(mode) (((mode)==BORDER_THICK)?ruleB:rule) +#define TK_VERTICALBAR(mode) (RULE(mode)[5]) + +#define BORDERWIDTH 2 +#define BORDERHEIGHT 1 +#define NOBORDERWIDTH 1 +#define NOBORDERHEIGHT 0 + +#define HTT_X 1 +#define HTT_Y 2 +#define HTT_ALIGN 0x30 +#define HTT_LEFT 0x00 +#define HTT_CENTER 0x10 +#define HTT_RIGHT 0x20 +#define HTT_TRSET 0x40 +#ifdef NOWRAP +#define HTT_NOWRAP 4 +#endif /* NOWRAP */ +#define TAG_IS(s,tag,len) (strncasecmp(s,tag,len)==0&&(s[len] == '>' || IS_SPACE((int)s[len]))) + +#ifndef max +#define max(a,b) ((a) > (b) ? (a) : (b)) +#endif /* not max */ +#ifndef min +#define min(a,b) ((a) > (b) ? (b) : (a)) +#endif /* not min */ +#ifndef abs +#define abs(a) ((a) >= 0. ? (a) : -(a)) +#endif /* not abs */ + +#ifdef MATRIX +#ifndef MESCHACH +#include "matrix.c" +#endif /* not MESCHACH */ +#endif /* MATRIX */ + +#ifdef MATRIX +int correct_table_matrix(struct table *, int, int, int, double); +void set_table_matrix(struct table *, int); +#endif /* MATRIX */ + +#ifdef MATRIX +static double +weight(int x) +{ + + if (x < COLS) + return (double) x; + else + return COLS * (log((double) x / COLS) + 1.); +} + +static double +weight2(int a) +{ + return (double) a / COLS * 4 + 1.; +} + +#define sigma_td(a) (0.5*weight2(a)) /* <td width=...> */ +#define sigma_td_nw(a) (32*weight2(a)) /* <td ...> */ +#define sigma_table(a) (0.25*weight2(a)) /* <table width=...> */ +#define sigma_table_nw(a) (2*weight2(a)) /* <table...> */ +#else /* not MATRIX */ +#define LOG_MIN 1.0 +static double +weight3(int x) +{ + if (x < 0.1) + return 0.1; + if (x < LOG_MIN) + return (double) x; + else + return LOG_MIN * (log((double) x / LOG_MIN) + 1.); +} +#endif /* not MATRIX */ + +static int +dsort_index(short e1, short *ent1, short e2, short *ent2, int base, + char *index, int nent) +{ + int n = nent; + int k = 0; + + int e = e1 * base + e2; + while (n > 0) { + int nn = n / 2; + int idx = index[k + nn]; + int ne = ent1[idx] * base + ent2[idx]; + if (ne == e) { + k += nn; + break; + } + else if (ne < e) { + n -= nn + 1; + k += nn + 1; + } + else { + n = nn; + } + } + return k; +} + +static int +fsort_index(double e, double *ent, char *index, int nent) +{ + int n = nent; + int k = 0; + + while (n > 0) { + int nn = n / 2; + int idx = index[k + nn]; + double ne = ent[idx]; + if (ne == e) { + k += nn; + break; + } + else if (ne > e) { + n -= nn + 1; + k += nn + 1; + } + else { + n = nn; + } + } + return k; +} + +static void +dv2sv(double *dv, short *iv, int size) +{ + int i, k, iw; + char *index; + double *edv; + double w = 0., x; + + index = NewAtom_N(char, size); + edv = NewAtom_N(double, size); + for (i = 0; i < size; i++) { + iv[i] = ceil(dv[i]); + edv[i] = (double) iv[i] - dv[i]; + } + + w = 0.; + for (k = 0; k < size; k++) { + x = edv[k]; + w += x; + i = fsort_index(x, edv, index, k); + if (k > i) + bcopy(index + i, index + i + 1, k - i); + index[i] = k; + } + iw = min((int) (w + 0.5), size); + if (iw == 0) + return; + x = edv[(int) index[iw - 1]]; + for (i = 0; i < size; i++) { + k = index[i]; + if (i >= iw && abs(edv[k] - x) > 1e-6) + break; + iv[k]--; + } +} + +static int +table_colspan(struct table *t, int row, int col) +{ + int i; + for (i = col + 1; i <= t->maxcol && (t->tabattr[row][i] & HTT_X); i++); + return i - col; +} + +static int +table_rowspan(struct table *t, int row, int col) +{ + int i; + if (!t->tabattr[row]) + return 0; + for (i = row + 1; i <= t->maxrow && t->tabattr[i] && + (t->tabattr[i][col] & HTT_Y); i++); + return i - row; +} + +static int +minimum_cellspacing(int border_mode) +{ + switch (border_mode) { + case BORDER_THIN: + case BORDER_THICK: + case BORDER_NOWIN: + return RULE_WIDTH; + case BORDER_NONE: + return 1; + default: + /* not reached */ + return 0; + } +} + +static int +table_border_width(struct table *t) +{ + switch (t->border_mode) { + case BORDER_THIN: + case BORDER_THICK: + return t->maxcol * t->cellspacing + 2 * (RULE_WIDTH + t->cellpadding); + case BORDER_NOWIN: + case BORDER_NONE: + return t->maxcol * t->cellspacing; + default: + /* not reached */ + return 0; + } +} + +struct table * +newTable() +{ + struct table *t; + int i, j; + + t = New(struct table); + t->max_rowsize = MAXROW; + t->tabdata = New_N(TextList **, MAXROW); + t->tabattr = New_N(table_attr *, MAXROW); + t->tabheight = NewAtom_N(short, MAXROW); +#ifdef ID_EXT + t->tabidvalue = New_N(Str *, MAXROW); + t->tridvalue = New_N(Str, MAXROW); +#endif /* ID_EXT */ + + for (i = 0; i < MAXROW; i++) { + t->tabdata[i] = NULL; + t->tabattr[i] = 0; + t->tabheight[i] = 0; +#ifdef ID_EXT + t->tabidvalue[i] = NULL; + t->tridvalue[i] = NULL; +#endif /* ID_EXT */ + } + for (j = 0; j < MAXCOL; j++) { + t->tabwidth[j] = 0; + t->minimum_width[j] = 0; + t->fixed_width[j] = 0; + } + t->cell.maxcell = -1; + t->cell.icell = -1; + t->tabcontentssize = 0; + t->indent = 0; + t->ntable = 0; + t->tables_size = 0; + t->tables = NULL; +#ifdef MATRIX + t->matrix = NULL; + t->vector = NULL; +#endif /* MATRIX */ + t->linfo.prev_ctype = PC_ASCII; + t->linfo.prev_spaces = -1; + t->linfo.prevchar = ' '; + t->trattr = 0; + + t->status = R_ST_NORMAL; + t->suspended_input = Strnew(); + t->caption = Strnew(); +#ifdef ID_EXT + t->id = NULL; +#endif + return t; +} + +static void +check_row(struct table *t, int row) +{ + int i, r; + TextList ***tabdata; + table_attr **tabattr; + short *tabheight; +#ifdef ID_EXT + Str **tabidvalue; + Str *tridvalue; +#endif /* ID_EXT */ + + if (row >= t->max_rowsize) { + r = max(t->max_rowsize * 2, row + 1); + tabdata = New_N(TextList **, r); + tabattr = New_N(table_attr *, r); + tabheight = New_N(short, r); +#ifdef ID_EXT + tabidvalue = New_N(Str *, r); + tridvalue = New_N(Str, r); +#endif /* ID_EXT */ + for (i = 0; i < t->max_rowsize; i++) { + tabdata[i] = t->tabdata[i]; + tabattr[i] = t->tabattr[i]; + tabheight[i] = t->tabheight[i]; +#ifdef ID_EXT + tabidvalue[i] = t->tabidvalue[i]; + tridvalue[i] = t->tridvalue[i]; +#endif /* ID_EXT */ + } + for (; i < r; i++) { + tabdata[i] = NULL; + tabattr[i] = NULL; + tabheight[i] = 0; +#ifdef ID_EXT + tabidvalue[i] = NULL; + tridvalue[i] = NULL; +#endif /* ID_EXT */ + } + t->tabdata = tabdata; + t->tabattr = tabattr; + t->tabheight = tabheight; +#ifdef ID_EXT + t->tabidvalue = tabidvalue; + t->tridvalue = tridvalue; +#endif /* ID_EXT */ + t->max_rowsize = r; + } + + if (t->tabdata[row] == NULL) { + t->tabdata[row] = New_N(TextList *, MAXCOL); + t->tabattr[row] = NewAtom_N(table_attr, MAXCOL); +#ifdef ID_EXT + t->tabidvalue[row] = New_N(Str, MAXCOL); +#endif /* ID_EXT */ + for (i = 0; i < MAXCOL; i++) { + t->tabdata[row][i] = NULL; + t->tabattr[row][i] = 0; +#ifdef ID_EXT + t->tabidvalue[row][i] = NULL; +#endif /* ID_EXT */ + } + } +} + +void +pushdata(struct table *t, int row, int col, char *data) +{ + check_row(t, row); + if (t->tabdata[row][col] == NULL) + t->tabdata[row][col] = newTextList(); + + pushText(t->tabdata[row][col], data); +} + +int visible_length_offset = 0; +int +visible_length(char *str) +{ + int len = 0; + int status = R_ST_NORMAL; + int prev_status = status; + Str tagbuf = Strnew(); + char *t, *r2; + struct parsed_tagarg *t_arg, *tt; + int amp_len; + + t = str; + while (*str) { + prev_status = status; + len += next_status(*str, &status); + if (status == R_ST_TAG0) { + Strclear(tagbuf); + Strcat_char(tagbuf, *str); + } + else if (status == R_ST_TAG || status == R_ST_DQUOTE || status == R_ST_QUOTE || status == R_ST_EQL) { + Strcat_char(tagbuf, *str); + } + else if (status == R_ST_AMP) { + if (prev_status == R_ST_NORMAL) { + Strclear(tagbuf); + amp_len = 0; + } + else { + Strcat_char(tagbuf, *str); + len++; + amp_len++; + } + } + else if (status == R_ST_NORMAL && prev_status == R_ST_AMP) { + Strcat_char(tagbuf, *str); + r2 = tagbuf->ptr; + t = getescapecmd(&r2); + len += strlen(t) - 1 - amp_len; + if (*r2 != '\0') { + str -= strlen(r2); + } + } + else if (status == R_ST_NORMAL && ST_IS_REAL_TAG(prev_status)) { + Strcat_char(tagbuf, *str); + if (TAG_IS(tagbuf->ptr, "<img", 4)) { + int anchor_len = 0; + t_arg = parse_tag(tagbuf->ptr + 5); + for (tt = t_arg; tt; tt = tt->next) { + if (strcasecmp(tt->arg, "src") == 0 && tt->value && anchor_len == 0) { + r2 = tt->value + strlen(tt->value) - 1; + while (tt->value < r2 && *r2 != '/') + r2--; + if (*r2 == '/') + r2++; + while (*r2 && *r2 != '.') { + r2++; + anchor_len++; + } + anchor_len += 2; + } + else if (strcasecmp(tt->arg, "alt") == 0 && tt->value) { + anchor_len = strlen(tt->value) + 1; + break; + } + } + len += anchor_len; + } + else if (TAG_IS(tagbuf->ptr, "<input", 6)) { + int width = 20; + int valuelen = 1; + int input_type = FORM_INPUT_TEXT; + t_arg = parse_tag(tagbuf->ptr + 7); + for (tt = t_arg; tt; tt = tt->next) { + if (strcasecmp(tt->arg, "type") == 0 && tt->value) { + input_type = formtype(tt->value); + } + else if (strcasecmp(tt->arg, "value") == 0 && tt->value) { + valuelen = strlen(tt->value); + } + else if (strcasecmp(tt->arg, "width") == 0 && tt->value) { + width = atoi(tt->value); + } + } + switch (input_type) { + case FORM_INPUT_TEXT: + case FORM_INPUT_FILE: + case FORM_INPUT_PASSWORD: + len += width + 2; + break; + case FORM_INPUT_SUBMIT: + case FORM_INPUT_RESET: + case FORM_INPUT_IMAGE: + case FORM_INPUT_BUTTON: + len += valuelen + 2; + break; + case FORM_INPUT_CHECKBOX: + case FORM_INPUT_RADIO: + len += 3; + } + } + else if (TAG_IS(tagbuf->ptr, "<textarea", 9)) { + int width = 20; + t_arg = parse_tag(tagbuf->ptr + 7); + for (tt = t_arg; tt; tt = tt->next) { + if (strcasecmp(tt->arg, "cols") == 0 && tt->value) { + width = atoi(tt->value); + } + } + len += width + 2; + } + else if (TAG_IS(tagbuf->ptr, "<option", 7)) + len += 3; + } + else if (*str == '\t') { + len--; + do { + len++; + } while ((visible_length_offset + len) % Tabstop != 0); + } + str++; + } + if (status == R_ST_AMP) { + r2 = tagbuf->ptr; + t = getescapecmd(&r2); + len += strlen(t) - 1 - amp_len; + if (*r2 != '\0') { + len += strlen(r2); + } + } + return len; +} + +int +maximum_visible_length(char *str) +{ + int maxlen, len; + char *p; + + for (p = str; *p && *p != '\t'; p++); + + visible_length_offset = 0; + maxlen = visible_length(str); + + if (*p == '\0') + return maxlen; + + for (visible_length_offset = 1; visible_length_offset < Tabstop; + visible_length_offset++) { + len = visible_length(str); + if (maxlen < len) { + maxlen = len; + break; + } + } + return maxlen; +} + +char * +align(char *str, int width, int mode) +{ + int i, l, l1, l2; + Str buf = Strnew(); + + if (str == NULL || *str == '\0') { + for (i = 0; i < width; i++) + Strcat_char(buf, ' '); + return buf->ptr; + } + l = width - visible_length(str); + switch (mode) { + case ALIGN_CENTER: + l1 = l / 2; + l2 = l - l1; + for (i = 0; i < l1; i++) + Strcat_char(buf, ' '); + Strcat_charp(buf, str); + for (i = 0; i < l2; i++) + Strcat_char(buf, ' '); + return buf->ptr; + case ALIGN_LEFT: + Strcat_charp(buf, str); + for (i = 0; i < l; i++) + Strcat_char(buf, ' '); + return buf->ptr; + case ALIGN_RIGHT: + for (i = 0; i < l; i++) + Strcat_char(buf, ' '); + Strcat_charp(buf, str); + return buf->ptr; + } + return Strnew_charp(str)->ptr; +} + +void +print_item(struct table *t, + int row, int col, int width, + Str buf) +{ + int alignment; + char *p; + + if (t->tabdata[row]) + p = popText(t->tabdata[row][col]); + else + p = NULL; + + if (p != NULL) { + check_row(t, row); + alignment = ALIGN_CENTER; + if ((t->tabattr[row][col] & HTT_ALIGN) == HTT_LEFT) + alignment = ALIGN_LEFT; + else if ((t->tabattr[row][col] & HTT_ALIGN) == HTT_RIGHT) + alignment = ALIGN_RIGHT; + else if ((t->tabattr[row][col] & HTT_ALIGN) == HTT_CENTER) + alignment = ALIGN_CENTER; + Strcat_charp(buf, align(p, width, alignment)); + } + else + Strcat_charp(buf, align(NULL, width, ALIGN_CENTER)); +} + + +#define T_TOP 0 +#define T_MIDDLE 1 +#define T_BOTTOM 2 + +void +print_sep(struct table *t, + int row, int type, int maxcol, + Str buf) +{ + int forbid; + char **rulep; + int i, j, k, l, m; + +#if defined(__EMX__)&&!defined(JP_CHARSET) + if(CodePage==850){ + ruleB = ruleB850; + rule = rule850; + } +#endif + if (row >= 0) + check_row(t, row); + check_row(t, row + 1); + if ((type == T_TOP || type == T_BOTTOM) && t->border_mode == BORDER_THICK) { + rulep = ruleB; + } + else { + rulep = rule; + } + forbid = 1; + if (type == T_TOP) + forbid |= 2; + else if (type == T_BOTTOM) + forbid |= 8; + else if (t->tabattr[row + 1][0] & HTT_Y) { + forbid |= 4; + } + if (t->border_mode != BORDER_NOWIN) + Strcat_charp(buf, RULE(t->border_mode)[forbid]); + for (i = 0; i <= maxcol; i++) { + forbid = 10; + if (type != T_BOTTOM && (t->tabattr[row + 1][i] & HTT_Y)) { + if (t->tabattr[row + 1][i] & HTT_X) { + goto do_last_sep; + } + else { + for (k = row; k >= 0 && t->tabattr[k] && (t->tabattr[k][i] & HTT_Y); k--); + m = t->tabwidth[i] + 2 * t->cellpadding; + for (l = i + 1; l <= t->maxcol && (t->tabattr[row][l] & HTT_X); l++) + m += t->tabwidth[l] + t->cellspacing; + print_item(t, k, i, m, buf); + } + } + else { + for (j = 0; j < t->tabwidth[i] + 2 * t->cellpadding; j += RULE_WIDTH) { + Strcat_charp(buf, rulep[forbid]); + } + } + do_last_sep: + if (i < maxcol) { + forbid = 0; + if (type == T_TOP) + forbid |= 2; + else if (t->tabattr[row][i + 1] & HTT_X) { + forbid |= 2; + } + if (type == T_BOTTOM) + forbid |= 8; + else { + if (t->tabattr[row + 1][i + 1] & HTT_X) { + forbid |= 8; + } + if (t->tabattr[row + 1][i + 1] & HTT_Y) { + forbid |= 4; + } + if (t->tabattr[row + 1][i] & HTT_Y) { + forbid |= 1; + } + } + if (forbid != 15) /* forbid==15 means 'no rule at all' */ + Strcat_charp(buf, rulep[forbid]); + } + } + forbid = 4; + if (type == T_TOP) + forbid |= 2; + if (type == T_BOTTOM) + forbid |= 8; + if (t->tabattr[row + 1][maxcol] & HTT_Y) { + forbid |= 1; + } + if (t->border_mode != BORDER_NOWIN) + Strcat_charp(buf, RULE(t->border_mode)[forbid]); + Strcat_charp(buf, "<eol>"); +} + +static int +get_spec_cell_width(struct table *tbl, int row, int col) +{ + int i, w; + + w = tbl->tabwidth[col]; + for (i = col + 1; i <= tbl->maxcol; i++) { + check_row(tbl, row); + if (tbl->tabattr[row][i] & HTT_X) + w += tbl->tabwidth[i] + tbl->cellspacing; + else + break; + } + return w; +} + +void +do_refill(struct table *tbl, int row, int col) +{ + TextList *orgdata; + TextListItem *l; + struct readbuffer obuf; + struct html_feed_environ h_env; + struct environment envs[MAX_ENV_LEVEL]; + + if (tbl->tabdata[row] == NULL || + tbl->tabdata[row][col] == NULL) + return; + orgdata = tbl->tabdata[row][col]; + tbl->tabdata[row][col] = newTextList(); + + init_henv(&h_env, &obuf, envs, MAX_ENV_LEVEL, tbl->tabdata[row][col], + tbl->tabwidth[col], 0); + h_env.limit = get_spec_cell_width(tbl, row, col); + for (l = orgdata->first; l != NULL; l = l->next) { + if (TAG_IS(l->ptr, "<dummy_table", 12)) { + struct parsed_tagarg *t_arg, *t; + int id = -1; + t_arg = parse_tag(l->ptr + 12); + for (t = t_arg; t; t = t->next) { + if (!strcasecmp(t->arg, "id") && t->value) { + id = atoi(t->value); + break; + } + } + if (id >= 0) { + int alignment; + TextListItem *ti; + save_fonteffect(&h_env, h_env.obuf); + flushline(&h_env, &obuf, 0, 0, h_env.limit); + + if (RB_GET_ALIGN(h_env.obuf) == RB_CENTER) + alignment = ALIGN_CENTER; + else if (RB_GET_ALIGN(h_env.obuf) == RB_RIGHT) + alignment = ALIGN_RIGHT; + else + alignment = ALIGN_LEFT; + + if (alignment == ALIGN_LEFT) { + appendTextList(h_env.buf, tbl->tables[id].buf); + } + else { + for (ti = tbl->tables[id].buf->first; ti != NULL; ti = ti->next) { + pushText(h_env.buf, align(ti->ptr, h_env.limit, alignment)); + } + } + restore_fonteffect(&h_env, h_env.obuf); + } + } + else + HTMLlineproc1(l->ptr, &h_env); + } + flushline(&h_env, &obuf, 0, 0, h_env.limit); +} + +static void +check_cell_width(short *tabwidth, short *cellwidth, + short *col, short *colspan, short maxcell, + char *index, int space, int dir) +{ + int i, j, k, bcol, ecol; + int swidth, width; + + for (k = 0; k <= maxcell; k++) { + j = index[k]; + if (cellwidth[j] <= 0) + continue; + bcol = col[j]; + ecol = bcol + colspan[j]; + swidth = 0; + for (i = bcol; i < ecol; i++) + swidth += tabwidth[i]; + + width = cellwidth[j] - (colspan[j] - 1) * space; + if (width > swidth) { + int w = (width - swidth) / colspan[j]; + int r = (width - swidth) % colspan[j]; + for (i = bcol; i < ecol; i++) + tabwidth[i] += w; + /* dir {0: horizontal, 1: vertical} */ + if (dir == 1 && r > 0) + r = colspan[j]; + for (i = 1; i <= r; i++) + tabwidth[ecol - i]++; + } + } +} + +void +check_minimum_width(struct table *t, short *tabwidth) +{ + int i; + struct table_cell *cell = &t->cell; + + for (i = 0; i <= t->maxcol; i++) { + if (tabwidth[i] < t->minimum_width[i]) + tabwidth[i] = t->minimum_width[i]; + } + + check_cell_width(tabwidth, cell->minimum_width, cell->col, cell->colspan, + cell->maxcell, cell->index, t->cellspacing, 0); +} + +void +check_maximum_width(struct table *t) +{ + struct table_cell *cell = &t->cell; +#ifdef MATRIX + int i, j, bcol, ecol; + int swidth, width; + + cell->necell = 0; + for (j = 0; j <= cell->maxcell; j++) { + bcol = cell->col[j]; + ecol = bcol + cell->colspan[j]; + swidth = 0; + for (i = bcol; i < ecol; i++) + swidth += t->tabwidth[i]; + + width = cell->width[j] - (cell->colspan[j] - 1) * t->cellspacing; + if (width > swidth) { + cell->eindex[cell->necell] = j; + cell->necell++; + } + } +#else /* not MATRIX */ + check_cell_width(t->tabwidth, cell->width, cell->col, cell->colspan, + cell->maxcell, cell->index, t->cellspacing, 0); + check_minimum_width(t, t->tabwidth); +#endif /* not MATRIX */ +} + + +#ifdef MATRIX +static int +recalc_width(int old, int delta, double rat) +{ + double w = rat * old; + double ww = (double) delta; + if (w > 0.) { + if (ww < 0.) + ww = 0.; + ww += 0.2; + } + else { + if (ww > 0.) + ww = 0.; + ww -= 1.0; + } + if (w > ww) + return (int) (ww / rat); + return old; +} + +static int +check_compressible_cell(struct table *t, MAT * minv, + short *newwidth, short *swidth, short *cwidth, + int totalwidth, + int icol, int icell, double sxx, int corr) +{ + struct table_cell *cell = &t->cell; + int i, j, k, m, bcol, ecol; + int delta, dmax, dmin, owidth; + double sxy; + + if (sxx < 10.) + return corr; + + if (icol >= 0) { + owidth = newwidth[icol]; + delta = newwidth[icol] - t->tabwidth[icol]; + bcol = icol; + ecol = bcol + 1; + } + else if (icell >= 0) { + owidth = swidth[icell]; + delta = swidth[icell] - cwidth[icell]; + bcol = cell->col[icell]; + ecol = bcol + cell->colspan[icell]; + } + else { + owidth = totalwidth; + delta = totalwidth; + bcol = 0; + ecol = t->maxcol + 1; + } + + dmin = delta; + dmax = 0; + for (k = 0; k <= cell->maxcell; k++) { + int bcol1, ecol1; + if (dmin <= 0) + return corr; + j = cell->index[k]; + if (icol < 0 && j == icell) + continue; + bcol1 = cell->col[j]; + ecol1 = bcol1 + cell->colspan[j]; + sxy = 0.; + for (m = bcol1; m < ecol1; m++) { + for (i = bcol; i < ecol; i++) + sxy += m_entry(minv, i, m); + } + if (fabs(delta * sxy / sxx) < 0.5) + continue; + if (sxy > 0.) + dmin = recalc_width(dmin, swidth[j] - cwidth[j], sxy / sxx); + else + dmax = recalc_width(dmax, swidth[j] - cwidth[j], sxy / sxx); + } + for (m = 0; m <= t->maxcol; m++) { + if (dmin <= 0) + return corr; + if (icol >= 0 && m == icol) + continue; + sxy = 0.; + for (i = bcol; i < ecol; i++) + sxy += m_entry(minv, i, m); + if (fabs(delta * sxy / sxx) < 0.5) + continue; + if (sxy > 0.) + dmin = recalc_width(dmin, newwidth[m] - t->tabwidth[m], sxy / sxx); + else + dmax = recalc_width(dmax, newwidth[m] - t->tabwidth[m], sxy / sxx); + } + if (dmax > 0 && dmin > dmax) + dmin = dmax; + if (dmin > 1) { + correct_table_matrix(t, bcol, ecol - bcol, owidth - dmin, 1.); + corr++; + } + return corr; +} + +#define MAX_ITERATION 3 +int +check_table_width(struct table *t, short *newwidth, MAT * minv, int itr) +{ + int i, j, k, m, bcol, ecol; + int corr = 0; + struct table_cell *cell = &t->cell; +#ifdef __GNUC__ + short orgwidth[t->maxcol + 1]; + short cwidth[cell->maxcell + 1], swidth[cell->maxcell + 1]; +#else /* __GNUC__ */ + short orgwidth[MAXCOL]; + short cwidth[MAXCELL], swidth[MAXCELL]; +#endif /* __GNUC__ */ + int twidth; + double sxy, *Sxx, stotal; + + twidth = 0; + stotal = 0.; + for (i = 0; i <= t->maxcol; i++) { + twidth += newwidth[i]; + stotal += m_entry(minv, i, i); + for (m = 0; m < i; m++) { + stotal += 2 * m_entry(minv, i, m); + } + } + + Sxx = NewAtom_N(double, cell->maxcell + 1); + for (k = 0; k <= cell->maxcell; k++) { + j = cell->index[k]; + bcol = cell->col[j]; + ecol = bcol + cell->colspan[j]; + swidth[j] = 0; + for (i = bcol; i < ecol; i++) + swidth[j] += newwidth[i]; + cwidth[j] = cell->width[j] - (cell->colspan[j] - 1) * t->cellspacing; + Sxx[j] = 0.; + for (i = bcol; i < ecol; i++) { + Sxx[j] += m_entry(minv, i, i); + for (m = bcol; m <= ecol; m++) { + if (m < i) + Sxx[j] += 2 * m_entry(minv, i, m); + } + } + } + + /* compress table */ + corr = check_compressible_cell(t, minv, newwidth, swidth, cwidth, twidth, + -1, -1, stotal, corr); + if (itr < MAX_ITERATION && corr > 0) + return corr; + + /* compress multicolumn cell */ + for (k = cell->maxcell; k >= 0; k--) { + j = cell->index[k]; + corr = check_compressible_cell(t, minv, newwidth, swidth, cwidth, twidth, + -1, j, Sxx[j], corr); + if (itr < MAX_ITERATION && corr > 0) + return corr; + } + + /* compress single column cell */ + for (i = 0; i <= t->maxcol; i++) { + corr = check_compressible_cell(t, minv, newwidth, swidth, cwidth, twidth, + i, -1, m_entry(minv, i, i), corr); + if (itr < MAX_ITERATION && corr > 0) + return corr; + } + + + for (i = 0; i <= t->maxcol; i++) + orgwidth[i] = newwidth[i]; + + check_minimum_width(t, newwidth); + + for (i = 0; i <= t->maxcol; i++) { + double sx = sqrt(m_entry(minv, i, i)); + if (sx < 0.1) + continue; + if (orgwidth[i] < t->minimum_width[i] && + newwidth[i] == t->minimum_width[i]) { + double w = (sx > 0.5) ? 0.5 : sx * 0.2; + sxy = 0.; + for (m = 0; m <= t->maxcol; m++) { + if (m == i) + continue; + sxy += m_entry(minv, i, m); + } + if (sxy <= 0.) { + correct_table_matrix(t, i, 1, t->minimum_width[i], w); + corr++; + } + } + } + + for (k = 0; k <= cell->maxcell; k++) { + int nwidth = 0, mwidth; + double sx; + + j = cell->index[k]; + sx = sqrt(Sxx[j]); + if (sx < 0.1) + continue; + bcol = cell->col[j]; + ecol = bcol + cell->colspan[j]; + for (i = bcol; i < ecol; i++) + nwidth += newwidth[i]; + mwidth = cell->minimum_width[j] - (cell->colspan[j] - 1) * t->cellspacing; + if (mwidth > swidth[j] && mwidth == nwidth) { + double w = (sx > 0.5) ? 0.5 : sx * 0.2; + + sxy = 0.; + for (i = bcol; i < ecol; i++) { + for (m = 0; m <= t->maxcol; m++) { + if (m >= bcol && m < ecol) + continue; + sxy += m_entry(minv, i, m); + } + } + if (sxy <= 0.) { + correct_table_matrix(t, bcol, cell->colspan[j], mwidth, w); + corr++; + } + } + } + + if (itr >= MAX_ITERATION) + return 0; + else + return corr; +} + +#else /* not MATRIX */ +void +set_table_width(struct table *t, short *newwidth, int maxwidth) +{ + int i, j, k, bcol, ecol; + struct table_cell *cell = &t->cell; + char *fixed; + int swidth, fwidth, width, nvar; + double s; + double *dwidth; + int try_again; + + fixed = NewAtom_N(char, t->maxcol + 1); + bzero(fixed, t->maxcol + 1); + dwidth = NewAtom_N(double, t->maxcol + 1); + + for (i = 0; i <= t->maxcol; i++) { + dwidth[i] = 0.0; + if (t->fixed_width[i] < 0) { + t->fixed_width[i] = -t->fixed_width[i] * maxwidth / 100; + } + if (t->fixed_width[i] > 0) { + newwidth[i] = t->fixed_width[i]; + fixed[i] = 1; + } + else + newwidth[i] = 0; + if (newwidth[i] < t->minimum_width[i]) + newwidth[i] = t->minimum_width[i]; + } + + for (k = 0; k <= cell->maxcell; k++) { + j = cell->index[k]; + bcol = cell->col[j]; + ecol = bcol + cell->colspan[j]; + + if (cell->fixed_width[j] < 0) + cell->fixed_width[j] = -cell->fixed_width[j] * maxwidth / 100; + + swidth = 0; + fwidth = 0; + nvar = 0; + for (i = bcol; i < ecol; i++) { + if (fixed[i]) { + fwidth += newwidth[i]; + } + else { + swidth += newwidth[i]; + nvar++; + } + } + width = max(cell->fixed_width[j], cell->minimum_width[j]) + - (cell->colspan[j] - 1) * t->cellspacing; + if (nvar > 0 && width > fwidth + swidth) { + s = 0.; + for (i = bcol; i < ecol; i++) { + if (!fixed[i]) + s += weight3(t->tabwidth[i]); + } + for (i = bcol; i < ecol; i++) { + if (!fixed[i]) + dwidth[i] = (width - fwidth) * weight3(t->tabwidth[i]) / s; + else + dwidth[i] = (double) newwidth[i]; + } + dv2sv(dwidth, newwidth, cell->colspan[j]); + if (cell->fixed_width[j] > 0) { + for (i = bcol; i < ecol; i++) + fixed[i] = 1; + } + } + } + + do { + nvar = 0; + swidth = 0; + fwidth = 0; + for (i = 0; i <= t->maxcol; i++) { + if (fixed[i]) { + fwidth += newwidth[i]; + } + else { + swidth += newwidth[i]; + nvar++; + } + } + width = maxwidth - t->maxcol * t->cellspacing; + if (nvar == 0 || width <= fwidth + swidth) + break; + + s = 0.; + for (i = 0; i <= t->maxcol; i++) { + if (!fixed[i]) + s += weight3(t->tabwidth[i]); + } + for (i = 0; i <= t->maxcol; i++) { + if (!fixed[i]) + dwidth[i] = (width - fwidth) * weight3(t->tabwidth[i]) / s; + else + dwidth[i] = (double) newwidth[i]; + } + dv2sv(dwidth, newwidth, t->maxcol + 1); + + try_again = 0; + for (i = 0; i <= t->maxcol; i++) { + if (!fixed[i]) { + if (newwidth[i] > t->tabwidth[i]) { + newwidth[i] = t->tabwidth[i]; + fixed[i] = 1; + try_again = 1; + } + else if (newwidth[i] < t->minimum_width[i]) { + newwidth[i] = t->minimum_width[i]; + fixed[i] = 1; + try_again = 1; + } + } + } + } while (try_again); +} +#endif /* not MATRIX */ + +void +check_table_height(struct table *t) +{ + int i, j, k; + struct { + short row[MAXCELL]; + short rowspan[MAXCELL]; + char index[MAXCELL]; + short maxcell; + short height[MAXCELL]; + } cell; + int space; + + cell.maxcell = -1; + + for (j = 0; j <= t->maxrow; j++) { + if (!t->tabattr[j]) + continue; + for (i = 0; i <= t->maxcol; i++) { + int t_dep, rowspan; + if (t->tabattr[j][i] & (HTT_X | HTT_Y)) + continue; + + if (t->tabdata[j][i] == NULL) + t_dep = 0; + else + t_dep = t->tabdata[j][i]->nitem; + + rowspan = table_rowspan(t, j, i); + if (rowspan > 1) { + int c = cell.maxcell + 1; + k = dsort_index(rowspan, cell.rowspan, + j, cell.row, t->maxrow + 1, + cell.index, c); + if (k <= cell.maxcell) { + int idx = cell.index[k]; + if (cell.row[idx] == j && + cell.rowspan[idx] == rowspan) + c = idx; + } + if (c > cell.maxcell && c < MAXCELL) { + cell.maxcell++; + cell.row[cell.maxcell] = j; + cell.rowspan[cell.maxcell] = rowspan; + cell.height[cell.maxcell] = 0; + if (cell.maxcell > k) + bcopy(cell.index + k, cell.index + k + 1, cell.maxcell - k); + cell.index[k] = cell.maxcell; + } + if (c <= cell.maxcell && c >= 0 && + cell.height[c] < t_dep) { + cell.height[c] = t_dep; + continue; + } + } + if (t->tabheight[j] < t_dep) + t->tabheight[j] = t_dep; + } + } + + switch (t->border_mode) { + case BORDER_THIN: + case BORDER_THICK: + case BORDER_NOWIN: + space = 1; + break; + case BORDER_NONE: + space = 0; + } + check_cell_width(t->tabheight, cell.height, cell.row, cell.rowspan, + cell.maxcell, cell.index, space, 1); +} + +int +get_table_width(struct table *t, short *orgwidth, short *cellwidth, + int check_minimum) +{ +#ifdef __GNUC__ + short newwidth[t->maxcol + 1]; +#else /* not __GNUC__ */ + short newwidth[MAXCOL]; +#endif /* not __GNUC__ */ + int i; + int swidth; + struct table_cell *cell = &t->cell; + + for (i = 0; i <= t->maxcol; i++) + newwidth[i] = max(orgwidth[i], 0); + + check_cell_width(newwidth, cellwidth, cell->col, cell->colspan, + cell->maxcell, cell->index, t->cellspacing, 0); + if (check_minimum) + check_minimum_width(t, newwidth); + + swidth = 0; + for (i = 0; i <= t->maxcol; i++) { + swidth += newwidth[i]; + } + swidth += table_border_width(t); + return swidth; +} + +#define minimum_table_width(t)\ +(get_table_width(t,t->minimum_width,t->cell.minimum_width,0)) +#define maximum_table_width(t)\ + (get_table_width(t,t->tabwidth,t->cell.width,0)) +#define fixed_table_width(t)\ + (get_table_width(t,t->fixed_width,t->cell.fixed_width,1)) + +void +renderCoTable(struct table *tbl) +{ + struct readbuffer obuf; + struct html_feed_environ h_env; + struct environment envs[MAX_ENV_LEVEL]; + struct table *t; + int i, j, col, row, b_width; + int width, nwidth, indent, maxwidth; +#ifdef __GNUC__ + short newwidth[tbl->maxcol + 1]; +#else /* not __GNUC__ */ + short newwidth[MAXCOL]; +#endif /* not __GNUC__ */ + + for (i = 0; i <= tbl->maxcol; i++) + newwidth[i] = tbl->tabwidth[i]; + + for (i = 0; i < tbl->ntable; i++) { + t = tbl->tables[i].ptr; + col = tbl->tables[i].col; + row = tbl->tables[i].row; + indent = tbl->tables[i].indent; + + init_henv(&h_env, &obuf, envs, MAX_ENV_LEVEL, tbl->tables[i].buf, + tbl->tabwidth[col], indent); + nwidth = newwidth[col]; + check_row(tbl, row); + b_width = 0; + for (j = col + 1; j <= tbl->maxcol; j++) { + if (tbl->tabattr[row][j] & HTT_X) { + h_env.limit += tbl->tabwidth[j]; + nwidth += newwidth[j]; + b_width += tbl->cellspacing; + } + else + break; + } + h_env.limit += b_width; +#ifndef TABLE_EXPAND + if (t->total_width == 0) + maxwidth = h_env.limit - indent; + else if (t->total_width > 0) + maxwidth = t->total_width; + else + maxwidth = t->total_width = -t->total_width * + get_spec_cell_width(tbl, row, col) / 100; +#else + maxwidth = h_env.limit - indent; + if (t->total_width > 0) { + double r = ((double) maxwidth) / t->total_width; + struct table_cell *cell = &t->cell; + + for (j = 0; j <= t->maxcol; j++) { + if (t->fixed_width[j] > 0) + t->fixed_width[j] = (int) (r * t->fixed_width[j]); + } + for (j = 0; j <= cell->maxcell; j++) { + if (cell->fixed_width[j] > 0) + cell->fixed_width[j] = (int) (r * cell->fixed_width[j]); + } + t->total_width = maxwidth; + } +#endif /* TABLE_EXPAND */ + renderTable(t, maxwidth, &h_env); + width = t->total_width - b_width + indent; + if (width > nwidth) { + int cell = tbl->tables[i].cell; + if (cell < 0) { + newwidth[col] = width; + } + else { + int ecol = col + tbl->cell.colspan[cell]; + int w = (width - nwidth) / tbl->cell.colspan[cell]; + int r = (width - nwidth) % tbl->cell.colspan[cell]; + for (j = col; j < ecol; j++) + newwidth[j] += w; + for (j = 1; j <= r; j++) + newwidth[ecol - j]++; + } + } + t = NULL; + } + for (i = 0; i <= tbl->maxcol; i++) + tbl->tabwidth[i] = newwidth[i]; +} + +static void +make_caption(struct table *t, struct html_feed_environ *h_env) +{ + struct html_feed_environ henv; + struct readbuffer obuf; + struct environment envs[MAX_ENV_LEVEL]; + TextList *tl; + Str tmp; + + if (t->caption->length <= 0) + return; + + if (t->total_width <= 0) + t->total_width = h_env->limit; + + init_henv(&henv, &obuf, envs, MAX_ENV_LEVEL, newTextList(), t->total_width, + h_env->envs[h_env->envc].indent); + HTMLlineproc1("<center>", &henv); + HTMLlineproc1(t->caption->ptr, &henv); + HTMLlineproc1("</center>", &henv); + + tl = henv.buf; + + if (tl->nitem > 0) { + TextListItem *ti; + tmp = Strnew_charp("<pre for_table>"); + for (ti = tl->first; ti != NULL; ti = ti->next) { + Strcat_charp(tmp, ti->ptr); + Strcat_char(tmp, '\n'); + } + Strcat_charp(tmp, "</pre>"); + HTMLlineproc1(tmp->ptr, h_env); + } +} + +void +renderTable(struct table *t, + int max_width, + struct html_feed_environ *h_env) +{ + int i, j, w, r, h; + Str renderbuf = Strnew(); + short new_tabwidth[MAXCOL]; +#ifdef MATRIX + int itr; + VEC *newwidth; + MAT *mat, *minv; + PERM *pivot; +#endif /* MATRIX */ + int maxheight = 0; + Str vrulea, vruleb, vrulec; +#ifdef ID_EXT + Str idtag; +#endif /* ID_EXT */ + + if (t->maxcol < 0) { + make_caption(t, h_env); + return; + } + + max_width -= table_border_width(t); + + if (max_width <= 0) + max_width = 1; + + check_maximum_width(t); + +#ifdef MATRIX + if (t->maxcol == 0) { + if (t->tabwidth[0] > max_width) + t->tabwidth[0] = max_width; + if (t->total_width > 0) + t->tabwidth[0] = max_width; + else if (t->fixed_width[0] > 0) + t->tabwidth[0] = t->fixed_width[0]; + if (t->tabwidth[0] < t->minimum_width[0]) + t->tabwidth[0] = t->minimum_width[0]; + } + else { + set_table_matrix(t, max_width); + + itr = 0; + mat = m_get(t->maxcol + 1, t->maxcol + 1); + pivot = px_get(t->maxcol + 1); + newwidth = v_get(t->maxcol + 1); + minv = m_get(t->maxcol + 1, t->maxcol + 1); + do { + m_copy(t->matrix, mat); + LUfactor(mat, pivot); + LUsolve(mat, pivot, t->vector, newwidth); + dv2sv(newwidth->ve, new_tabwidth, t->maxcol + 1); + LUinverse(mat, pivot, minv); +#ifdef TABLE_DEBUG + fprintf(stderr, "max_width=%d\n", max_width); + fprintf(stderr, "minimum : "); + for (i = 0; i <= t->maxcol; i++) + fprintf(stderr, "%2d ", t->minimum_width[i]); + fprintf(stderr, "\ndecided : "); + for (i = 0; i <= t->maxcol; i++) + fprintf(stderr, "%2d ", new_tabwidth[i]); + fprintf(stderr, "\n"); +#endif /* TABLE_DEBUG */ + itr++; + + } while (check_table_width(t, new_tabwidth, minv, itr)); + v_free(newwidth); + px_free(pivot); + m_free(mat); + m_free(minv); + m_free(t->matrix); + v_free(t->vector); + for (i = 0; i <= t->maxcol; i++) { + t->tabwidth[i] = new_tabwidth[i]; + } + } +#else /* not MATRIX */ + set_table_width(t, new_tabwidth, max_width); + for (i = 0; i <= t->maxcol; i++) { + t->tabwidth[i] = new_tabwidth[i]; + } +#endif /* not MATRIX */ + + renderCoTable(t); + check_minimum_width(t, t->tabwidth); + + t->total_width = 0; + for (i = 0; i <= t->maxcol; i++) { + if (t->border_mode != BORDER_NONE && t->tabwidth[i] % RULE_WIDTH == 1) + t->tabwidth[i]++; + t->total_width += t->tabwidth[i]; + } + + t->total_width += table_border_width(t); + + for (i = 0; i <= t->maxcol; i++) { + for (j = 0; j <= t->maxrow; j++) { + check_row(t, j); + if (t->tabattr[j][i] & HTT_Y) + continue; + do_refill(t, j, i); + } + } + + check_table_height(t); + + /* table output */ + make_caption(t, h_env); + + HTMLlineproc1("<pre for_table>", h_env); +#ifdef ID_EXT + if (t->id != NULL) { + idtag = Sprintf("<_id id=\"%s\">", (t->id)->ptr); + HTMLlineproc1(idtag->ptr, h_env); + } +#endif /* ID_EXT */ + switch (t->border_mode) { + case BORDER_THIN: + case BORDER_THICK: + renderbuf = Strnew(); + print_sep(t, -1, T_TOP, t->maxcol, renderbuf); + HTMLlineproc1(renderbuf->ptr, h_env); + maxheight += 1; + break; + } + vruleb = Strnew(); + switch (t->border_mode) { + case BORDER_THIN: + case BORDER_THICK: + vrulea = Strnew(); + vrulec = Strnew(); + Strcat_charp(vrulea, TK_VERTICALBAR(t->border_mode)); + for (i = 0; i < t->cellpadding; i++) { + Strcat_char(vrulea, ' '); + Strcat_char(vruleb, ' '); + Strcat_char(vrulec, ' '); + } + Strcat_charp(vrulec, TK_VERTICALBAR(t->border_mode)); + case BORDER_NOWIN: +#if defined(__EMX__)&&!defined(JP_CHARSET) + Strcat_charp(vruleb, CodePage==850?"³":TN_VERTICALBAR); +#else + Strcat_charp(vruleb, TN_VERTICALBAR); +#endif + for (i = 0; i < t->cellpadding; i++) + Strcat_char(vruleb, ' '); + break; + case BORDER_NONE: + for (i = 0; i < t->cellspacing; i++) + Strcat_char(vruleb, ' '); + } + + for (r = 0; r <= t->maxrow; r++) { + for (h = 0; h < t->tabheight[r]; h++) { + renderbuf = Strnew(); + if (t->border_mode == BORDER_THIN || t->border_mode == BORDER_THICK) + Strcat(renderbuf, vrulea); +#ifdef ID_EXT + if (t->tridvalue[r] != NULL && h == 0) { + idtag = Sprintf("<_id id=\"%s\">", (t->tridvalue[r])->ptr); + Strcat(renderbuf, idtag); + } +#endif /* ID_EXT */ + for (i = 0; i <= t->maxcol; i++) { + check_row(t, r); +#ifdef ID_EXT + if (t->tabidvalue[r][i] != NULL && h == 0) { + idtag = Sprintf("<_id id=\"%s\">", (t->tabidvalue[r][i])->ptr); + Strcat(renderbuf, idtag); + } +#endif /* ID_EXT */ + if (!(t->tabattr[r][i] & HTT_X)) { + w = t->tabwidth[i]; + for (j = i + 1; + j <= t->maxcol && (t->tabattr[r][j] & HTT_X); + j++) + w += t->tabwidth[j] + t->cellspacing; + if (t->tabattr[r][i] & HTT_Y) { + for (j = r - 1; + j >= 0 && t->tabattr[j] && (t->tabattr[j][i] & HTT_Y); + j--); + print_item(t, j, i, w, renderbuf); + } + else + print_item(t, r, i, w, renderbuf); + } + if (i < t->maxcol && !(t->tabattr[r][i + 1] & HTT_X)) + Strcat(renderbuf, vruleb); + } + switch (t->border_mode) { + case BORDER_THIN: + case BORDER_THICK: + Strcat(renderbuf, vrulec); + Strcat_charp(renderbuf, "<eol>"); + maxheight += 1; + break; + case BORDER_NONE: + case BORDER_NOWIN: + Strcat_charp(renderbuf, "<eol>"); + break; + } + HTMLlineproc1(renderbuf->ptr, h_env); + } + if (r < t->maxrow && t->border_mode != BORDER_NONE) { + renderbuf = Strnew(); + print_sep(t, r, T_MIDDLE, t->maxcol, renderbuf); + HTMLlineproc1(renderbuf->ptr, h_env); + } + maxheight += t->tabheight[r]; + } + if (t->border_mode == BORDER_THIN || t->border_mode == BORDER_THICK) { + renderbuf = Strnew(); + print_sep(t, t->maxrow, T_BOTTOM, t->maxcol, renderbuf); + HTMLlineproc1(renderbuf->ptr, h_env); + maxheight += 1; + } + if (maxheight == 0) + HTMLlineproc1(" <eol>", h_env); + HTMLlineproc1("</pre>", h_env); +} + + +struct table * +begin_table(int border, int spacing, int padding) +{ + struct table *t; + int mincell = minimum_cellspacing(border); + + t = newTable(); + t->row = t->col = -1; + t->maxcol = -1; + t->maxrow = -1; + t->border_mode = border; + t->flag = 0; + if (border == BORDER_NOWIN) + t->flag |= TBL_EXPAND_OK; + t->cellspacing = max(spacing, mincell); + switch (border) { + case BORDER_THIN: + case BORDER_THICK: + case BORDER_NOWIN: + t->cellpadding = (t->cellspacing - mincell) / 2; + break; + case BORDER_NONE: + t->cellpadding = t->cellspacing - mincell; + } + + if (padding > t->cellpadding) + t->cellpadding = padding; + + switch (border) { + case BORDER_THIN: + case BORDER_THICK: + case BORDER_NOWIN: + t->cellspacing = 2 * t->cellpadding + mincell; + break; + case BORDER_NONE: + t->cellspacing = t->cellpadding + mincell; + } + return t; +} + +static void +check_minimum0(struct table *t, int min) +{ + int i, w, ww; + struct table_cell *cell; + + if (t->col < 0) + return; + if (t->tabwidth[t->col] < 0) + return; + check_row(t, t->row); + w = table_colspan(t, t->row, t->col); + min += t->indent; + if (w == 1) + ww = min; + else { + cell = &t->cell; + ww = 0; + if (cell->icell >= 0 && cell->minimum_width[cell->icell] < min) + cell->minimum_width[cell->icell] = min; + } + for (i = t->col; + i <= t->maxcol && (i == t->col || (t->tabattr[t->row][i] & HTT_X)); + i++) { + if (t->minimum_width[i] < ww) + t->minimum_width[i] = ww; + } +} + +static int +setwidth0(struct table *t, struct table_mode *mode) +{ + int w; + int width = t->tabcontentssize; + struct table_cell *cell = &t->cell; + + if (t->col < 0) + return -1; + if (t->tabwidth[t->col] < 0) + return -1; + check_row(t, t->row); + if (t->linfo.prev_spaces > 0) + width -= t->linfo.prev_spaces; + w = table_colspan(t, t->row, t->col); + if (w == 1) { + if (t->tabwidth[t->col] < width) + t->tabwidth[t->col] = width; + } + else if (cell->icell >= 0) { + if (cell->width[cell->icell] < width) + cell->width[cell->icell] = width; + } + return width; +} + +static void +setwidth(struct table *t, struct table_mode *mode) +{ + int width = setwidth0(t, mode); + if (width < 0) + return; +#ifdef NOWRAP + if (t->tabattr[t->row][t->col] & HTT_NOWRAP) + check_minimum0(t, width); +#endif /* NOWRAP */ + if (mode->pre_mode & (TBLM_NOBR | TBLM_PRE | TBLM_PRE_INT) && + mode->nobr_offset >= 0) + check_minimum0(t, width - mode->nobr_offset); +} + +static void +addcontentssize(struct table *t, int width) +{ + + if (t->col < 0) + return; + if (t->tabwidth[t->col] < 0) + return; + check_row(t, t->row); + t->tabcontentssize += width; +} + +static void +clearcontentssize(struct table *t, struct table_mode *mode) +{ + mode->nobr_offset = 0; + t->linfo.prev_spaces = -1; + t->linfo.prevchar = ' '; + t->tabcontentssize = 0; +} + +void +check_rowcol(struct table *tbl) +{ + if (!(tbl->flag & TBL_IN_ROW)) { + tbl->flag |= TBL_IN_ROW; + tbl->row++; + if (tbl->row > tbl->maxrow) + tbl->maxrow = tbl->row; + tbl->col = -1; + } + if (tbl->row == -1) + tbl->row = 0; + if (tbl->col == -1) + tbl->col = 0; + + for (;; tbl->row++) { + check_row(tbl, tbl->row); + for (; tbl->col < MAXCOL && + tbl->tabattr[tbl->row][tbl->col] & (HTT_X | HTT_Y); + tbl->col++); + if (tbl->col < MAXCOL) + break; + tbl->col = 0; + } + if (tbl->row > tbl->maxrow) + tbl->maxrow = tbl->row; + if (tbl->col > tbl->maxcol) + tbl->maxcol = tbl->col; + + tbl->flag |= TBL_IN_COL; +} + +int +skip_space(struct table *t, char *line, struct table_linfo *linfo, + int checkminimum) +{ + int skip = 0, s = linfo->prev_spaces; + Lineprop ctype = linfo->prev_ctype, prev_ctype; + char prevchar = linfo->prevchar; + int w = (linfo->prev_spaces == -1) ? 0 : linfo->length; + int min = 1; + + if (*line == '<' && line[strlen(line) - 1] == '>') { + if (checkminimum) + check_minimum0(t, visible_length(line)); + return 0; + } + + while (*line) { + char c = *line, *save = line; + int ec = '\0', len = 1, wlen = 1; + prev_ctype = ctype; + ctype = get_ctype(c, prev_ctype); + if (min < w) + min = w; + if (ctype == PC_ASCII && IS_SPACE(c)) { + w = 0; + s++; + } + else { + if (c == '&') { + ec = getescapechar(&line); + if (ec) { + c = ec; + if (IS_CNTRL(ec)) + ctype = PC_CTRL; + else + ctype = PC_ASCII; + len = strlen(conv_latin1(ec)); + wlen = line - save; + } + } + if (prevchar && is_boundary(prevchar, prev_ctype, c, ctype)) { + w = len; + } + else { + w += len; + } + if (s > 0) { +#ifdef JP_CHARSET + if (ctype == PC_KANJI1 && prev_ctype == PC_KANJI2) + skip += s; + else +#endif /* JP_CHARSET */ + skip += s - 1; + } + s = 0; + } + prevchar = c; + line = save + wlen; + } + if (s > 1) { + skip += s - 1; + linfo->prev_spaces = 1; + } + else { + linfo->prev_spaces = s; + } + linfo->prev_ctype = ctype; + linfo->prevchar = prevchar; + + if (checkminimum) { + if (min < w) + min = w; + linfo->length = w; + check_minimum0(t, min); + } + return skip; +} + +#define TAG_ACTION_NONE 0 +#define TAG_ACTION_FEED 1 +#define TAG_ACTION_TABLE 2 +#define TAG_ACTION_N_TABLE 3 + +static int +feed_table_tag(struct table *tbl, char *line, struct table_mode *mode, int width) +{ + int cmd; + char *s_line; + struct table_cell *cell = &tbl->cell; + struct parsed_tagarg *t_arg, *t; + int colspan, rowspan; + int col, prev_col; + int i, j, k, v, v0, w, id, status; + Str tok, tmp, anchor; + table_attr align; + + s_line = line; + cmd = gethtmlcmd(&s_line, &status); + + if (mode->pre_mode & TBLM_IGNORE) { + switch (cmd) { + case HTML_N_STYLE: + mode->pre_mode &= ~TBLM_STYLE; + case HTML_N_SCRIPT: + mode->pre_mode &= ~TBLM_SCRIPT; + default: + return TAG_ACTION_NONE; + } + } + +#ifdef MENU_SELECT + /* failsafe: a tag other than <option></option>and </select> in * + * <select> environment is regarded as the end of <select>. */ + if (mode->pre_mode & TBLM_INSELECT) { + switch (cmd) { + case HTML_TABLE: + case HTML_N_TABLE: + case HTML_TR: + case HTML_N_TR: + case HTML_TD: + case HTML_N_TD: + case HTML_TH: + case HTML_N_TH: + case HTML_THEAD: + case HTML_N_THEAD: + case HTML_TBODY: + case HTML_N_TBODY: + case HTML_TFOOT: + case HTML_N_TFOOT: + case HTML_COLGROUP: + case HTML_N_COLGROUP: + case HTML_COL: + mode->pre_mode &= ~TBLM_INSELECT; + tmp = process_n_select(); + feed_table1(tbl, tmp, mode, width); + } + } +#endif /* MENU_SELECT */ + + switch (cmd) { + case HTML_TABLE: + return TAG_ACTION_TABLE; + case HTML_N_TABLE: + return TAG_ACTION_N_TABLE; + case HTML_TR: + if (tbl->col >= 0 && tbl->tabcontentssize > 0) + setwidth(tbl, mode); + clearcontentssize(tbl, mode); + mode->caption = 0; + mode->indent_level = 0; + mode->nobr_level = 0; + mode->mode_level = 0; + mode->pre_mode = 0; + tbl->col = -1; + tbl->row++; + tbl->flag |= TBL_IN_ROW; + tbl->indent = 0; + align = 0; + t_arg = parse_tag(line + 3); + for (t = t_arg; t; t = t->next) { + if (!strcasecmp(t->arg, "align") && t->value) { + if (!strcasecmp(t->value, "left")) + align = (HTT_LEFT | HTT_TRSET); + else if (!strcasecmp(t->value, "right")) + align = (HTT_RIGHT | HTT_TRSET); + else if (!strcasecmp(t->value, "center")) + align = (HTT_CENTER | HTT_TRSET); + } +#ifdef ID_EXT + if (!strcasecmp(t->arg, "id") && t->value) { + tbl->tridvalue[tbl->row] = Strnew_charp(t->value); + } +#endif /* ID_EXT */ + } + tbl->trattr = align; + break; + case HTML_TH: + case HTML_TD: + prev_col = tbl->col; + if (tbl->col >= 0 && tbl->tabcontentssize > 0) + setwidth(tbl, mode); + clearcontentssize(tbl, mode); + mode->caption = 0; + mode->indent_level = 0; + mode->nobr_level = 0; + mode->mode_level = 0; + mode->pre_mode = 0; + tbl->flag |= TBL_IN_COL; + tbl->linfo.prev_spaces = -1; + tbl->linfo.prevchar = ' '; + tbl->linfo.prev_ctype = PC_ASCII; + tbl->indent = 0; + if (tbl->row == -1) { + /* for broken HTML... */ + tbl->row = -1; + tbl->col = -1; + tbl->maxrow = tbl->row; + } + if (tbl->col == -1) { + if (!(tbl->flag & TBL_IN_ROW)) { + tbl->row++; + tbl->flag |= TBL_IN_ROW; + } + if (tbl->row > tbl->maxrow) + tbl->maxrow = tbl->row; + } + tbl->col++; + check_row(tbl, tbl->row); + while (tbl->tabattr[tbl->row][tbl->col]) { + tbl->col++; + } + if (tbl->col > MAXCOL - 1) { + tbl->col = prev_col; + return TAG_ACTION_NONE; + } + if (tbl->col > tbl->maxcol) { + tbl->maxcol = tbl->col; + } + tbl->height = 0; + t_arg = parse_tag(line + 3); + colspan = rowspan = 1; + v = 0; + if (tbl->trattr & HTT_TRSET) + align = (tbl->trattr & HTT_ALIGN); + else if (cmd == HTML_TH) + align = HTT_CENTER; + else + align = HTT_LEFT; + for (t = t_arg; t; t = t->next) { + if (!strcasecmp(t->arg, "rowspan") && t->value) { + rowspan = atoi(t->value); + if ((tbl->row + rowspan) >= tbl->max_rowsize) + check_row(tbl, tbl->row + rowspan); + } + else if (!strcasecmp(t->arg, "colspan") && t->value) { + colspan = atoi(t->value); + if ((tbl->col + colspan) >= MAXCOL) { + /* Can't expand column */ + colspan = MAXCOL - tbl->col; + } + } + else if (!strcasecmp(t->arg, "align") && t->value) { + if (!strcasecmp(t->value, "left")) + align = HTT_LEFT; + else if (!strcasecmp(t->value, "right")) + align = HTT_RIGHT; + else if (!strcasecmp(t->value, "center")) + align = HTT_CENTER; + } +#ifdef NOWRAP + else if (!strcasecmp(t->arg, "nowrap")) + tbl->tabattr[tbl->row][tbl->col] |= HTT_NOWRAP; +#endif /* NOWRAP */ + else if (!strcasecmp(t->arg, "width") && t->value) { + if (IS_DIGIT(*t->value)) { + v = atoi(t->value); + if (v == 0) + v = 1; + else if (v < 0) + v = 0; + if (t->value[strlen(t->value) - 1] == '%') { + v = -v; + } + else { +#ifdef TABLE_EXPAND + v = max(v / tbl->ppc, 1); +#else /* not TABLE_EXPAND */ + v = v / PIXEL_PER_CHAR; +#endif /* not TABLE_EXPAND */ + } + } + else + continue; +#ifdef ID_EXT + } + else if (!strcasecmp(t->arg, "id") && t->value) { + tbl->tabidvalue[tbl->row][tbl->col] = Strnew_charp(t->value); +#endif /* ID_EXT */ + } + } +#ifdef NOWRAP + if (v != 0) { + /* NOWRAP and WIDTH= conflicts each other */ + tbl->tabattr[tbl->row][tbl->col] &= ~HTT_NOWRAP; + } +#endif /* NOWRAP */ + tbl->tabattr[tbl->row][tbl->col] &= ~HTT_ALIGN; + tbl->tabattr[tbl->row][tbl->col] |= align; + if (colspan > 1) { + col = tbl->col; + + cell->icell = cell->maxcell + 1; + k = dsort_index(colspan, cell->colspan, col, cell->col, MAXCOL, + cell->index, cell->icell); + if (k <= cell->maxcell) { + i = cell->index[k]; + if (cell->col[i] == col && + cell->colspan[i] == colspan) + cell->icell = i; + } + if (cell->icell > cell->maxcell && cell->icell < MAXCELL) { + cell->maxcell++; + cell->col[cell->maxcell] = col; + cell->colspan[cell->maxcell] = colspan; + cell->width[cell->maxcell] = 0; + cell->minimum_width[cell->maxcell] = 0; + cell->fixed_width[cell->maxcell] = 0; + if (cell->maxcell > k) + bcopy(cell->index + k, cell->index + k + 1, cell->maxcell - k); + cell->index[k] = cell->maxcell; + } + if (cell->icell > cell->maxcell) + cell->icell = -1; + } + if (v != 0) { + if (colspan == 1) { + v0 = tbl->fixed_width[tbl->col]; + if (v0 == 0 || (v0 > 0 && v > v0) || (v0 < 0 && v < v0)) { +#ifdef TABLE_DEBUG + fprintf(stderr, "width(%d) = %d\n", tbl->col, v); +#endif /* TABLE_DEBUG */ + tbl->fixed_width[tbl->col] = v; + } + } + else if (cell->icell >= 0) { + v0 = cell->fixed_width[cell->icell]; + if (v0 == 0 || (v0 > 0 && v > v0) || (v0 < 0 && v < v0)) + cell->fixed_width[cell->icell] = v; + } + } + for (i = 0; i < rowspan; i++) { + check_row(tbl, tbl->row + i); + for (j = 0; j < colspan; j++) { + tbl->tabattr[tbl->row + i][tbl->col + j] &= ~(HTT_X | HTT_Y); + tbl->tabattr[tbl->row + i][tbl->col + j] |= + ((i > 0) ? HTT_Y : 0) | ((j > 0) ? HTT_X : 0); + if (tbl->col + j > tbl->maxcol) { + tbl->maxcol = tbl->col + j; + } + } + if (tbl->row + i > tbl->maxrow) { + tbl->maxrow = tbl->row + i; + } + } + break; + case HTML_N_TR: + setwidth(tbl, mode); + tbl->col = -1; + tbl->flag &= ~(TBL_IN_ROW | TBL_IN_COL); + return TAG_ACTION_NONE; + case HTML_N_TH: + case HTML_N_TD: + setwidth(tbl, mode); + tbl->flag &= ~TBL_IN_COL; +#ifdef TABLE_DEBUG + { + TextListItem *it; + int i = tbl->col, j = tbl->row; + fprintf(stderr, "(a) row,col: %d, %d\n", j, i); + if (tbl->tabdata[j] && tbl->tabdata[j][i]) { + for (it = tbl->tabdata[j][i]->first; it; it = it->next) + fprintf(stderr, " [%s] \n", it->ptr); + } + } +#endif + return TAG_ACTION_NONE; + case HTML_P: + case HTML_BR: + case HTML_DT: + case HTML_DD: + case HTML_CENTER: + case HTML_N_CENTER: + case HTML_DIV: + case HTML_N_DIV: + case HTML_H: + case HTML_N_H: + check_rowcol(tbl); + pushdata(tbl, tbl->row, tbl->col, line); + setwidth(tbl, mode); + clearcontentssize(tbl, mode); + if (cmd == HTML_DD) + addcontentssize(tbl, tbl->indent); + break; + case HTML_DL: + case HTML_BLQ: + case HTML_OL: + case HTML_UL: + check_rowcol(tbl); + pushdata(tbl, tbl->row, tbl->col, line); + setwidth(tbl, mode); + clearcontentssize(tbl, mode); + mode->indent_level++; + if (mode->indent_level <= MAX_INDENT_LEVEL) + tbl->indent += INDENT_INCR; + if (cmd == HTML_BLQ) { + check_minimum0(tbl, 0); + addcontentssize(tbl, tbl->indent); + } + break; + case HTML_N_DL: + case HTML_N_BLQ: + case HTML_N_OL: + case HTML_N_UL: + if (mode->indent_level > 0) { + check_rowcol(tbl); + pushdata(tbl, tbl->row, tbl->col, line); + setwidth(tbl, mode); + clearcontentssize(tbl, mode); + mode->indent_level--; + if (mode->indent_level < MAX_INDENT_LEVEL) + tbl->indent -= INDENT_INCR; + } + break; + case HTML_LI: + check_rowcol(tbl); + pushdata(tbl, tbl->row, tbl->col, line); + setwidth(tbl, mode); + clearcontentssize(tbl, mode); + check_minimum0(tbl, 0); + addcontentssize(tbl, tbl->indent); + break; + case HTML_PRE: + case HTML_LISTING: + case HTML_XMP: + setwidth(tbl, mode); + check_rowcol(tbl); + clearcontentssize(tbl, mode); + pushdata(tbl, tbl->row, tbl->col, line); + mode->pre_mode |= TBLM_PRE; + mode->mode_level++; + break; + case HTML_N_PRE: + case HTML_N_LISTING: + case HTML_N_XMP: + setwidth(tbl, mode); + check_rowcol(tbl); + clearcontentssize(tbl, mode); + pushdata(tbl, tbl->row, tbl->col, line); + if (mode->mode_level > 0) + mode->mode_level--; + if (mode->mode_level == 0) + mode->pre_mode &= ~TBLM_PRE; + tbl->linfo.prev_spaces = 0; + tbl->linfo.prevchar = '\0'; + tbl->linfo.prev_ctype = PC_ASCII; + break; + case HTML_NOBR: + check_rowcol(tbl); + pushdata(tbl, tbl->row, tbl->col, line); + if (!(mode->pre_mode & TBLM_NOBR)) { + mode->nobr_offset = -1; + mode->pre_mode |= TBLM_NOBR; + } + mode->nobr_level++; + break; + case HTML_WBR: + check_rowcol(tbl); + pushdata(tbl, tbl->row, tbl->col, line); + mode->nobr_offset = -1; + break; + case HTML_N_NOBR: + if (mode->nobr_level > 0) + mode->nobr_level--; + check_rowcol(tbl); + pushdata(tbl, tbl->row, tbl->col, line); + if (mode->nobr_level == 0) + mode->pre_mode &= ~TBLM_NOBR; + break; + case HTML_PRE_INT: + check_rowcol(tbl); + pushdata(tbl, tbl->row, tbl->col, line); + if (!(mode->pre_mode & TBLM_PRE_INT)) { + mode->nobr_offset = -1; + mode->pre_mode |= TBLM_PRE_INT; + } + tbl->linfo.prev_spaces = 0; + break; + case HTML_N_PRE_INT: + check_rowcol(tbl); + pushdata(tbl, tbl->row, tbl->col, line); + mode->pre_mode &= ~TBLM_PRE_INT; + break; + case HTML_IMG: + tok = process_img(parse_tag(line + 3)); + feed_table1(tbl, tok, mode, width); + break; +#ifdef NEW_FORM + case HTML_FORM: + process_form(parse_tag(line)); + break; + case HTML_N_FORM: + process_n_form(); + break; +#else /* not NEW_FORM */ + case HTML_FORM: + case HTML_N_FORM: + check_rowcol(tbl); + pushdata(tbl, tbl->row, tbl->col, "<br>"); + setwidth(tbl, mode); + clearcontentssize(tbl, mode); + if (line[1] == '/') { + tok = Strnew_charp("</form_int "); + Strcat_charp(tok, line + 6); + } + else { + tok = Strnew_charp("<form_int "); + Strcat_charp(tok, line + 5); + } + pushdata(tbl, tbl->row, tbl->col, tok->ptr); + break; +#endif /* not NEW_FORM */ + case HTML_INPUT: + tmp = process_input(parse_tag(line + 6)); + feed_table1(tbl, tmp, mode, width); + break; + case HTML_SELECT: + t_arg = parse_tag(line + 7); + tmp = process_select(t_arg); + feed_table1(tbl, tmp, mode, width); +#ifdef MENU_SELECT + if (!tag_exists(t_arg, "multiple")) /* non-multiple select */ + mode->pre_mode |= TBLM_INSELECT; +#endif /* MENU_SELECT */ + break; + case HTML_N_SELECT: +#ifdef MENU_SELECT + mode->pre_mode &= ~TBLM_INSELECT; +#endif /* MENU_SELECT */ + tmp = process_n_select(); + feed_table1(tbl, tmp, mode, width); + break; + case HTML_OPTION: + tmp = process_option(parse_tag(line + 7)); + if (tmp) + feed_table1(tbl, tmp, mode, width); +#ifdef MENU_SELECT + else + feed_select(line); +#endif /* MENU_SELECT */ + break; + case HTML_TEXTAREA: + w = 0; + check_rowcol(tbl); + if (tbl->col + 1 <= tbl->maxcol && + tbl->tabattr[tbl->row][tbl->col + 1] & HTT_X) { + if (cell->icell >= 0 && cell->fixed_width[cell->icell] > 0) + w = cell->fixed_width[cell->icell]; + } + else { + if (tbl->fixed_width[tbl->col] > 0) + w = tbl->fixed_width[tbl->col]; + } + tmp = process_textarea(parse_tag(line + 9), w); + feed_table1(tbl, tmp, mode, width); + mode->pre_mode |= TBLM_INTXTA; + break; + case HTML_N_TEXTAREA: + mode->pre_mode &= ~TBLM_INTXTA; + tmp = process_n_textarea(); + feed_table1(tbl, tmp, mode, width); + break; + case HTML_A: + anchor = NULL; + check_rowcol(tbl); + t_arg = parse_tag(line + 2); + i = 0; + for (t = t_arg; t; t = t->next) { + if (strcasecmp(t->arg, "href") == 0 && t->value) { + anchor = Strnew_charp(t->value); + } + else if (strcasecmp(t->arg, "hseq") == 0 && t->value) { + i = atoi(t->value); + } + } + if (i == 0 && anchor) { + Str tmp = process_anchor(line); + pushdata(tbl, tbl->row, tbl->col, tmp->ptr); + if (mode->pre_mode & (TBLM_PRE | TBLM_NOBR)) + addcontentssize(tbl, 1); + else + check_minimum0(tbl, 1); + setwidth(tbl, mode); + } + else { + pushdata(tbl, tbl->row, tbl->col, line); + } + break; + case HTML_DEL: + case HTML_N_DEL: + case HTML_INS: + case HTML_N_INS: + pushdata(tbl, tbl->row, tbl->col, line); + i = 5; + check_minimum0(tbl, i); + addcontentssize(tbl, i); + setwidth(tbl, mode); + break; + case HTML_DUMMY_TABLE: + id = -1; + w = 0; + t_arg = parse_tag(line + 12); + for (t = t_arg; t; t = t->next) { + if (!strcasecmp(t->arg, "id") && t->value) { + id = atoi(t->value); + } + else if (!strcasecmp(t->arg, "width") && t->value) { + w = atoi(t->value); + } + } + if (id >= 0) { + setwidth(tbl, mode); + check_rowcol(tbl); + pushdata(tbl, tbl->row, tbl->col, line); + clearcontentssize(tbl, mode); + addcontentssize(tbl, maximum_table_width(tbl->tables[id].ptr)); + check_minimum0(tbl, minimum_table_width(tbl->tables[id].ptr)); + if (w > 0) + check_minimum0(tbl, w); + else + check_minimum0(tbl, fixed_table_width(tbl->tables[id].ptr)); + setwidth0(tbl, mode); + clearcontentssize(tbl, mode); + } + break; + case HTML_CAPTION: + mode->caption = 1; + break; + case HTML_N_CAPTION: + mode->caption = 0; + break; + case HTML_THEAD: + case HTML_N_THEAD: + case HTML_TBODY: + case HTML_N_TBODY: + case HTML_TFOOT: + case HTML_N_TFOOT: + case HTML_COLGROUP: + case HTML_N_COLGROUP: + case HTML_COL: + break; + case HTML_SCRIPT: + mode->pre_mode |= TBLM_SCRIPT; + break; + case HTML_STYLE: + mode->pre_mode |= TBLM_STYLE; + break; + default: + /* unknown tag: put into table */ + return TAG_ACTION_FEED; + } + return TAG_ACTION_NONE; +} + + +int +feed_table(struct table *tbl, char **tline, struct table_mode *mode, int width) +{ + int i; + char *line; + char *p; + Str tok, tmp; + struct table_linfo *linfo = &tbl->linfo; + + if (*tline == NULL || **tline == '\0') + return -1; + + tok = Strnew(); + if (tbl->suspended_input->length > 0) { + Strcat_charp(tbl->suspended_input, *tline); + *tline = tbl->suspended_input->ptr; + tbl->suspended_input = Strnew(); + tbl->status = R_ST_NORMAL; + } + while (read_token(tok, tline, &tbl->status, mode->pre_mode & TBLM_PREMODE, 0)) { + if (ST_IS_COMMENT(tbl->status)) { + continue; + } + else if (tbl->status != R_ST_NORMAL) { + /* line ended within tag */ + int l = tok->length; + if (tok->ptr[l - 1] == '\n') { + Strchop(tok); + if (ST_IS_REAL_TAG(tbl->status)) + Strcat_char(tok, ' '); + } + tbl->suspended_input = Strdup(tok); + return -1; + } + line = tok->ptr; + if (mode->caption && !TAG_IS(line, "</caption", 9)) { + Strcat(tbl->caption, tok); + continue; + } + if (*line == '<') { + int action = feed_table_tag(tbl, line, mode, width); + if (action == TAG_ACTION_NONE) + continue; + else if (action == TAG_ACTION_N_TABLE) + return 0; + else if (action == TAG_ACTION_TABLE) { + *tline -= tok->length; + return 1; + } + } + if (mode->pre_mode & TBLM_IGNORE) + continue; + if (mode->pre_mode & TBLM_INTXTA) { + feed_textarea(line); + continue; + } +#ifdef MENU_SELECT + if (mode->pre_mode & TBLM_INSELECT) { + feed_select(line); + continue; + } +#endif /* MENU_SELECT */ + /* convert &...; if it is latin-1 character */ + if (!(*line == '<' && line[strlen(line) - 1] == '>') && + strchr(line, '&') != NULL) { + tmp = Strnew(); + for (p = line; *p;) { + char *q, *r; + if (*p == '&') { + if (!strncasecmp(p, "&", 5) || + !strncasecmp(p, ">", 4) || + !strncasecmp(p, "<", 4)) { + /* do not convert */ + Strcat_char(tmp, *p); + p++; + } + else { + q = p; + r = getescapecmd(&p); + if (r != NULL && ((*r & 0x80) || IS_CNTRL(*r))) { + /* latin-1 character */ + Strcat_charp(tmp, r); + } + else { + Strcat_char(tmp, *q); + p = q + 1; + } + } + } + else { + Strcat_char(tmp, *p); + p++; + } + } + line = tmp->ptr; + } + if (!(mode->pre_mode & (TBLM_PRE | TBLM_PRE_INT))) { + if (!(tbl->flag & TBL_IN_COL)) { + linfo->prev_spaces = -1; + linfo->prev_ctype = PC_ASCII; + } + if (linfo->prev_spaces != 0) + while (IS_SPACE(*line)) + line++; + if (*line == '\0') + continue; + check_rowcol(tbl); + if (mode->pre_mode & TBLM_NOBR && mode->nobr_offset < 0) + mode->nobr_offset = tbl->tabcontentssize; + + /* count of number of spaces skipped in normal mode */ + i = skip_space(tbl, line, linfo, !(mode->pre_mode & TBLM_NOBR)); + addcontentssize(tbl, visible_length(line) - i); + setwidth(tbl, mode); + } + else { + /* <pre> mode or something like it */ + check_rowcol(tbl); + if (mode->pre_mode & TBLM_PRE_INT && mode->nobr_offset < 0) + mode->nobr_offset = tbl->tabcontentssize; + i = maximum_visible_length(line); + addcontentssize(tbl, i); + setwidth(tbl, mode); + if (!(mode->pre_mode & TBLM_PRE_INT)) { + p = line + strlen(line) - 1; + if (*p == '\r' || *p == '\n') + clearcontentssize(tbl, mode); + } + } + pushdata(tbl, tbl->row, tbl->col, line); + } + if (ST_IS_COMMENT(tbl->status)) + return 2; + else + return -1; +} + +void +feed_table1(struct table *tbl, Str tok, struct table_mode *mode, int width) +{ + char *p; + if (!tok) + return; + p = tok->ptr; + feed_table(tbl, &p, mode, width); +} + +void +pushTable(struct table *tbl, struct table *tbl1) +{ + int col; + int row; + + check_rowcol(tbl); + col = tbl->col; + row = tbl->row; + + if (tbl->ntable >= tbl->tables_size) { + struct table_in *tmp; + tbl->tables_size += MAX_TABLE_N; + tmp = New_N(struct table_in, tbl->tables_size); + if (tbl->tables) +#ifdef __CYGWIN__ + bcopy((const char *) tbl->tables, (char *) tmp, (size_t) tbl->ntable * sizeof(struct table_in)); +#else /* not __CYGWIN__ */ + bcopy(tbl->tables, tmp, tbl->ntable * sizeof(struct table_in)); +#endif /* not __CYGWIN__ */ + tbl->tables = tmp; + } + + tbl->tables[tbl->ntable].ptr = tbl1; + tbl->tables[tbl->ntable].col = col; + tbl->tables[tbl->ntable].row = row; + tbl->tables[tbl->ntable].indent = tbl->indent; + tbl->tables[tbl->ntable].buf = newTextList(); + check_row(tbl, row); + if (col + 1 <= tbl->maxcol && + tbl->tabattr[row][col + 1] & HTT_X) + tbl->tables[tbl->ntable].cell = tbl->cell.icell; + else + tbl->tables[tbl->ntable].cell = -1; + tbl->ntable++; +} + +#ifdef MATRIX +int +correct_table_matrix(struct table *t, int col, int cspan, int a, double b) +{ + int i, j; + int ecol = col + cspan; + double w = 1. / (b * b); + + for (i = col; i < ecol; i++) { + v_add_val(t->vector, i, w * a); + for (j = i; j < ecol; j++) { + m_add_val(t->matrix, i, j, w); + m_set_val(t->matrix, j, i, m_entry(t->matrix, i, j)); + } + } + return i; +} + +static void +correct_table_matrix2(struct table *t, int col, int cspan, double s, double b) +{ + int i, j; + int ecol = col + cspan; + int size = t->maxcol + 1; + double w = 1. / (b * b); + double ss; + + for (i = 0; i < size; i++) { + for (j = i; j < size; j++) { + if (i >= col && i < ecol && j >= col && j < ecol) + ss = (1. - s) * (1. - s); + else if ((i >= col && i < ecol) || (j >= col && j < ecol)) + ss = -(1. - s) * s; + else + ss = s * s; + m_add_val(t->matrix, i, j, w * ss); + } + } +} + +static void +correct_table_matrix3(struct table *t, int col, char *flags, double s, double b) +{ + int i, j; + double ss; + int size = t->maxcol + 1; + double w = 1. / (b * b); + int flg = (flags[col] == 0); + + for (i = 0; i < size; i++) { + if (!((flg && flags[i] == 0) || (!flg && flags[i] != 0))) + continue; + for (j = i; j < size; j++) { + if (!((flg && flags[j] == 0) || (!flg && flags[j] != 0))) + continue; + if (i == col && j == col) + ss = (1. - s) * (1. - s); + else if (i == col || j == col) + ss = -(1. - s) * s; + else + ss = s * s; + m_add_val(t->matrix, i, j, w * ss); + } + } +} + +static void +set_table_matrix0(struct table *t, int maxwidth) +{ + int size = t->maxcol + 1; + int i, j, k, bcol, ecol; + int swidth, width, a; + double w0, w1, w, s, b; +#ifdef __GNUC__ + double we[size]; + char expand[size]; +#else /* not __GNUC__ */ + double we[MAXCOL]; + char expand[MAXCOL]; +#endif /* not __GNUC__ */ + struct table_cell *cell = &t->cell; + + w0 = 0.; + for (i = 0; i < size; i++) { + we[i] = weight(t->tabwidth[i]); + w0 += we[i]; + } + if (w0 <= 0.) + w0 = 1.; + + if (cell->necell == 0) { + for (i = 0; i < size; i++) { + s = we[i] / w0; + b = sigma_td_nw((int) (s * maxwidth)); + correct_table_matrix2(t, i, 1, s, b); + } + return; + } + + bzero(expand, size); + + for (k = 0; k < cell->necell; k++) { + j = cell->eindex[k]; + bcol = cell->col[j]; + ecol = bcol + cell->colspan[j]; + swidth = 0; + for (i = bcol; i < ecol; i++) { + swidth += t->tabwidth[i]; + expand[i]++; + } + width = cell->width[j] - (cell->colspan[j] - 1) * t->cellspacing; + w = weight(width); + w1 = 0.; + for (i = bcol; i < ecol; i++) + w1 += we[i]; + s = w / (w0 + w - w1); + a = (int) (s * maxwidth); + b = sigma_td_nw(a); + correct_table_matrix2(t, bcol, cell->colspan[j], s, b); + } + + w1 = 0.; + for (i = 0; i < size; i++) + if (expand[i] == 0) + w1 += we[i]; + for (i = 0; i < size; i++) { + if (expand[i] == 0) { + s = we[i] / max(w1, 1.); + b = sigma_td_nw((int) (s * maxwidth)); + } + else { + s = we[i] / max(w0 - w1, 1.); + b = sigma_td_nw(maxwidth); + } + correct_table_matrix3(t, i, expand, s, b); + } +} + +void +set_table_matrix(struct table *t, int width) +{ + int size = t->maxcol + 1; + int i, j; + double b, s; + int a; + struct table_cell *cell = &t->cell; + + if (size < 1) + return; + + t->matrix = m_get(size, size); + t->vector = v_get(size); + for (i = 0; i < size; i++) { + for (j = i; j < size; j++) + m_set_val(t->matrix, i, j, 0.); + v_set_val(t->vector, i, 0.); + } + + for (i = 0; i < size; i++) { + if (t->fixed_width[i] > 0) { + a = max(t->fixed_width[i], t->minimum_width[i]); + b = sigma_td(a); + correct_table_matrix(t, i, 1, a, b); + } + else if (t->fixed_width[i] < 0) { + s = -(double) t->fixed_width[i] / 100.; + b = sigma_td((int) (s * width)); + correct_table_matrix2(t, i, 1, s, b); + } + } + + for (j = 0; j <= cell->maxcell; j++) { + if (cell->fixed_width[j] > 0) { + a = max(cell->fixed_width[j], cell->minimum_width[j]); + b = sigma_td(a); + correct_table_matrix(t, cell->col[j], + cell->colspan[j], a, b); + } + else if (cell->fixed_width[j] < 0) { + s = -(double) cell->fixed_width[j] / 100.; + b = sigma_td((int) (s * width)); + correct_table_matrix2(t, cell->col[j], + cell->colspan[j], s, b); + } + } + + set_table_matrix0(t, width); + + if (t->total_width > 0) { + b = sigma_table(width); + } + else { + b = sigma_table_nw(width); + } + correct_table_matrix(t, 0, size, width, b); +} +#endif /* MATRIX */ |