"Fossies" - the Fresh Open Source Software Archive

Member "links-1.04/html_tbl.c" (12 Oct 2018, 36622 Bytes) of package /linux/www/links-1.04.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "html_tbl.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.03_vs_1.04.

    1 #include "links.h"
    2 
    3 #define AL_TR       -1
    4 
    5 #define VAL_TR      -1
    6 #define VAL_TOP     0
    7 #define VAL_MIDDLE  1
    8 #define VAL_BOTTOM  2
    9 
   10 #define W_AUTO      -1
   11 #define W_REL       -2
   12 
   13 #define F_VOID      0
   14 #define F_ABOVE     1
   15 #define F_BELOW     2
   16 #define F_HSIDES    3
   17 #define F_LHS       4
   18 #define F_RHS       8
   19 #define F_VSIDES    12
   20 #define F_BOX       15
   21 
   22 #define R_NONE      0
   23 #define R_ROWS      1
   24 #define R_COLS      2
   25 #define R_ALL       3
   26 #define R_GROUPS    4
   27 
   28 void get_align(char *attr, int *a)
   29 {
   30     char *al;
   31     if ((al = get_attr_val(attr, "align"))) {
   32         if (!(strcasecmp(al, "left"))) *a = AL_LEFT;
   33         if (!(strcasecmp(al, "right"))) *a = AL_RIGHT;
   34         if (!(strcasecmp(al, "center"))) *a = AL_CENTER;
   35         if (!(strcasecmp(al, "justify"))) *a = AL_BLOCK;
   36         if (!(strcasecmp(al, "char"))) *a = AL_RIGHT; /* NOT IMPLEMENTED */
   37         mem_free(al);
   38     }
   39 }
   40 
   41 void get_valign(char *attr, int *a)
   42 {
   43     char *al;
   44     if ((al = get_attr_val(attr, "valign"))) {
   45         if (!(strcasecmp(al, "top"))) *a = VAL_TOP;
   46         if (!(strcasecmp(al, "middle"))) *a = VAL_MIDDLE;
   47         if (!(strcasecmp(al, "bottom"))) *a = VAL_BOTTOM;
   48         if (!(strcasecmp(al, "baseline"))) *a = VAL_TOP; /* NOT IMPLEMENTED */
   49         mem_free(al);
   50     }
   51 }
   52 
   53 void get_c_width(char *attr, int *w, int sh)
   54 {
   55     char *al;
   56     if ((al = get_attr_val(attr, "width"))) {
   57         if (*al && al[strlen(al) - 1] == '*') {
   58             char *en;
   59             unsigned long n;
   60             al[strlen(al) - 1] = 0;
   61             n = strtoul(al, &en, 10);
   62             if (n < 10000 && !*en) *w = W_REL - n;
   63         } else {
   64             int p = get_width(attr, "width", sh);
   65             if (p >= 0) *w = p;
   66         }
   67         mem_free(al);
   68     }
   69 }
   70 
   71 #define INIT_X      8
   72 #define INIT_Y      8
   73 
   74 struct table_cell {
   75     int used;
   76     int spanned;
   77     int mx, my;
   78     unsigned char *start;
   79     unsigned char *end;
   80     int align;
   81     int valign;
   82     int b;
   83     struct rgb bgcolor;
   84     int group;
   85     int colspan;
   86     int rowspan;
   87     int min_width;
   88     int max_width;
   89     int x_width;
   90     int height;
   91     int xpos, ypos, xw, yw;
   92     int link_num;
   93 };
   94 
   95 struct table_column {
   96     int group;
   97     int align;
   98     int valign;
   99     int width;
  100 };
  101 
  102 struct table {
  103     struct part *p;
  104     int x, y;
  105     int rx, ry;
  106     int border, cellpd, vcellpd, cellsp;
  107     int frame, rules, width, wf;
  108     int *min_c, *max_c;
  109     int *w_c;
  110     int rw;
  111     int min_t, max_t;
  112     struct table_cell *cells;
  113     int c, rc;
  114     struct table_column *cols;
  115     int xc;
  116     int *xcols;
  117     int *r_heights;
  118     int rh;
  119     int link_num;
  120 };
  121 
  122 #define CELL(t, x, y) (&(t)->cells[(y) * (t)->rx + (x)])
  123 
  124 unsigned char frame_table[81] = {
  125     0x00, 0xb3, 0xba,   0xc4, 0xc0, 0xd3,   0xcd, 0xd4, 0xc8,
  126     0xc4, 0xd9, 0xbd,   0xc4, 0xc1, 0xd0,   0xcd, 0xd4, 0xc8,
  127     0xcd, 0xbe, 0xbc,   0xcd, 0xbe, 0xbc,   0xcd, 0xcf, 0xca,
  128 
  129     0xb3, 0xb3, 0xba,   0xda, 0xc3, 0xd3,   0xd5, 0xc6, 0xc8,
  130     0xbf, 0xb4, 0xbd,   0xc2, 0xc5, 0xd0,   0xd5, 0xc6, 0xc8,
  131     0xb8, 0xb5, 0xbc,   0xb8, 0xb5, 0xbc,   0xd1, 0xd8, 0xca,
  132 
  133     0xba, 0xba, 0xba,   0xd6, 0xd6, 0xc7,   0xc9, 0xc9, 0xcc,
  134     0xb7, 0xb7, 0xb6,   0xd2, 0xd2, 0xd7,   0xc9, 0xc9, 0xcc,
  135     0xbb, 0xbb, 0xb9,   0xbb, 0xbb, 0xb9,   0xcb, 0xcb, 0xce,
  136 };
  137 
  138 unsigned char hline_table[3] = { 0x20, 0xc4, 0xcd };
  139 unsigned char vline_table[3] = { 0x20, 0xb3, 0xba };
  140 
  141 struct table *new_table()
  142 {
  143     struct table *t;
  144     t = mem_alloc(sizeof(struct table));
  145     memset(t, 0, sizeof(struct table));
  146     t->p = NULL;
  147     t->x = t->y = 0;
  148     t->rx = INIT_X;
  149     t->ry = INIT_Y;
  150     t->cells = mem_alloc(INIT_X * INIT_Y * sizeof(struct table_cell));
  151     memset(t->cells, 0, INIT_X * INIT_Y * sizeof(struct table_cell));
  152     t->c = 0;
  153     t->rc = INIT_X;
  154     t->cols = mem_alloc(INIT_X * sizeof(struct table_column));
  155     memset(t->cols, 0, INIT_X * sizeof(struct table_column));
  156     t->xcols = DUMMY;
  157     t->xc = 0;
  158     t->r_heights = DUMMY;
  159     return t;
  160 }
  161 
  162 void free_table(struct table *t)
  163 {
  164     if (t->min_c) mem_free(t->min_c);
  165     if (t->max_c) mem_free(t->max_c);
  166     if (t->w_c) mem_free(t->w_c);
  167     mem_free(t->r_heights);
  168     mem_free(t->cols);
  169     mem_free(t->xcols);
  170     mem_free(t->cells);
  171     mem_free(t);
  172 }
  173 
  174 void expand_cells(struct table *t, int x, int y)
  175 {
  176     int i, j;
  177     if (x >= t->x) {
  178         if (t->x) {
  179             for (i = 0; i < t->y; i++) if (CELL(t, t->x - 1, i)->colspan == -1) {
  180                 for (j = t->x; j <= x; j++) {
  181                     CELL(t, j, i)->used = 1;
  182                     CELL(t, j, i)->spanned = 1;
  183                     CELL(t, j, i)->rowspan = CELL(t, t->x - 1, i)->rowspan;
  184                     CELL(t, j, i)->colspan = -1;
  185                     CELL(t, j, i)->mx = CELL(t, t->x - 1, i)->mx;
  186                     CELL(t, j, i)->my = CELL(t, t->x - 1, i)->my;
  187                 }
  188             }
  189         }
  190         t->x = x + 1;
  191     }
  192     if (y >= t->y) {
  193         if (t->y) {
  194             for (i = 0; i < t->x; i++) if (CELL(t, i, t->y - 1)->rowspan == -1) {
  195                 for (j = t->y; j <= y; j++) {
  196                     CELL(t, i, j)->used = 1;
  197                     CELL(t, i, j)->spanned = 1;
  198                     CELL(t, i, j)->rowspan = -1;
  199                     CELL(t, i, j)->colspan = CELL(t, i, t->y - 1)->colspan;
  200                     CELL(t, i, j)->mx = CELL(t, i, t->y - 1)->mx;
  201                     CELL(t, i, j)->my = CELL(t, i, t->y - 1)->my;
  202                 }
  203             }
  204         }
  205         t->y = y + 1;
  206     }
  207 }
  208 
  209 struct table_cell *new_cell(struct table *t, int x, int y)
  210 {
  211     struct table nt;
  212     int i, j;
  213     if (x < t->x && y < t->y) goto ret;
  214     rep:
  215     if (x < t->rx && y < t->ry) {
  216         expand_cells(t, x, y);
  217         goto ret;
  218     }
  219     nt.rx = t->rx;
  220     nt.ry = t->ry;
  221     while (x >= nt.rx) {
  222         if ((unsigned)nt.rx > MAXINT / 2) overalloc();
  223         nt.rx *= 2;
  224     }
  225     while (y >= nt.ry) {
  226         if ((unsigned)nt.ry > MAXINT / 2) overalloc();
  227         nt.ry *= 2;
  228     }
  229     if ((unsigned)nt.rx * (unsigned)nt.ry / (unsigned)nt.rx != (unsigned)nt.ry) overalloc();
  230     if ((unsigned)nt.rx * (unsigned)nt.ry > MAXINT / sizeof(struct table_cell)) overalloc();
  231     nt.cells = mem_alloc(nt.rx * nt.ry * sizeof(struct table_cell));
  232     memset(nt.cells, 0, nt.rx * nt.ry * sizeof(struct table_cell));
  233     for (i = 0; i < t->x; i++)
  234         for (j = 0; j < t->y; j++)
  235             memcpy(CELL(&nt, i, j), CELL(t, i, j), sizeof(struct table_cell));
  236     mem_free(t->cells);
  237     t->cells = nt.cells;
  238     t->rx = nt.rx;
  239     t->ry = nt.ry;
  240     goto rep;
  241 
  242     ret:
  243     return CELL(t, x, y);
  244 }
  245 
  246 void new_columns(struct table *t, int span, int width, int align, int valign, int group)
  247 {
  248     if ((unsigned)t->c + (unsigned)span > MAXINT) overalloc();
  249     if (t->c + span > t->rc) {
  250         int n = t->rc;
  251         struct table_column *nc;
  252         while (t->c + span > n) {
  253             if ((unsigned)n > MAXINT / 2) overalloc();
  254             n *= 2;
  255         }
  256         if ((unsigned)n > MAXINT / sizeof(struct table_column)) overalloc();
  257         nc = mem_realloc(t->cols, n * sizeof(struct table_column));
  258         t->rc = n;
  259         t->cols = nc;
  260     }
  261     while (span--) {
  262         t->cols[t->c].align = align;
  263         t->cols[t->c].valign = valign;
  264         t->cols[t->c].width = width;
  265         t->cols[t->c++].group = group;
  266         group = 0;
  267     }
  268 }
  269 
  270 void set_td_width(struct table *t, int x, int width, int f)
  271 {
  272     if (x >= t->xc) {
  273         int n = t->xc ? t->xc : 1;
  274         int i;
  275         int *nc;
  276         while (x >= n) {
  277             if ((unsigned)n > MAXINT / 2) overalloc();
  278             n *= 2;
  279         }
  280         if ((unsigned)n > MAXINT / sizeof(int)) overalloc();
  281         nc = mem_realloc(t->xcols, n * sizeof(int));
  282         for (i = t->xc; i < n; i++) nc[i] = W_AUTO;
  283         t->xc = n;
  284         t->xcols = nc;
  285     }
  286     if (t->xcols[x] == W_AUTO || f) {
  287         set:
  288         t->xcols[x] = width;
  289         return;
  290     }
  291     if (width == W_AUTO) return;
  292     if (width < 0 && t->xcols[x] >= 0) goto set;
  293     if (width >= 0 && t->xcols[x] < 0) return;
  294     t->xcols[x] = (t->xcols[x] + width) / 2;
  295 }
  296 
  297 unsigned char *skip_table(unsigned char *html, unsigned char *eof)
  298 {
  299     int level = 1;
  300     unsigned char *name;
  301     int namelen;
  302     r:
  303     while (html < eof && (*html != '<' || parse_element(html, eof, &name, &namelen, NULL, &html))) html++;
  304     if (html >= eof) return eof;
  305     if (namelen == 5 && !casecmp(name, "TABLE", 5)) level++;
  306     if (namelen == 6 && !casecmp(name, "/TABLE", 6)) if (!--level) return html;
  307     goto r;
  308 }
  309 
  310 struct s_e {
  311     unsigned char *s, *e;
  312 };
  313 
  314 struct table *parse_table(unsigned char *html, unsigned char *eof, unsigned char **end, struct rgb *bgcolor, int sh, struct s_e **bad_html, int *bhp)
  315 {
  316     int qqq;
  317     struct table *t;
  318     struct table_cell *cell;
  319     unsigned char *t_name, *t_attr, *en;
  320     int t_namelen;
  321     int x = 0, y = -1;
  322     int p = 0;
  323     unsigned char *lbhp = NULL;
  324     int l_al = AL_LEFT;
  325     int l_val = VAL_MIDDLE;
  326     int csp, rsp;
  327     int group = 0;
  328     int i, j, k;
  329     struct rgb l_col;
  330     int c_al = AL_TR, c_val = VAL_TR, c_width = W_AUTO, c_span = 0;
  331     memcpy(&l_col, bgcolor, sizeof(struct rgb));
  332     *end = html;
  333     if (bad_html) {
  334         *bad_html = DUMMY;
  335         *bhp = 0;
  336     }
  337     if (!(t = new_table())) return NULL;
  338     se:
  339     en = html;
  340     see:
  341     html = en;
  342     if (bad_html && !p && !lbhp) {
  343         if (!(*bhp & (ALLOC_GR-1))) {
  344             if ((unsigned)*bhp > MAXINT / sizeof(struct s_e) - ALLOC_GR) overalloc();
  345             *bad_html = mem_realloc(*bad_html, (*bhp + ALLOC_GR) * sizeof(struct s_e));
  346         }
  347         lbhp = (*bad_html)[(*bhp)++].s = html;
  348     }
  349     while (html < eof && *html != '<') html++;
  350     if (html >= eof) {
  351         if (p) CELL(t, x, y)->end = html;
  352         if (lbhp) (*bad_html)[*bhp-1].e = html;
  353         goto scan_done;
  354     }
  355     if (eof - html >= 2 && (html[1] == '!' || html[1] == '?')) {
  356         html = skip_comment(html, eof);
  357         goto se;
  358     }
  359     if (parse_element(html, eof, &t_name, &t_namelen, &t_attr, &en)) {
  360         html++;
  361         goto se;
  362     }
  363     if (t_namelen == 5 && !casecmp(t_name, "TABLE", 5)) {
  364         en = skip_table(en, eof);
  365         goto see;
  366     }
  367     if (t_namelen == 6 && !casecmp(t_name, "/TABLE", 6)) {
  368         if (c_span) new_columns(t, c_span, c_width, c_al, c_val, 1);
  369         if (p) CELL(t, x, y)->end = html;
  370         if (lbhp) (*bad_html)[*bhp-1].e = html;
  371         goto scan_done;
  372     }
  373     if (t_namelen == 8 && !casecmp(t_name, "COLGROUP", 8)) {
  374         if (c_span) new_columns(t, c_span, c_width, c_al, c_val, 1);
  375         if (lbhp) (*bad_html)[*bhp-1].e = html, lbhp = NULL;
  376         c_al = AL_TR;
  377         c_val = VAL_TR;
  378         c_width = W_AUTO;
  379         get_align(t_attr, &c_al);
  380         get_valign(t_attr, &c_val);
  381         get_c_width(t_attr, &c_width, sh);
  382         if ((c_span = get_num(t_attr, "span")) == -1) c_span = 1;
  383         goto see;
  384     }
  385     if (t_namelen == 9 && !casecmp(t_name, "/COLGROUP", 9)) {
  386         if (c_span) new_columns(t, c_span, c_width, c_al, c_val, 1);
  387         if (lbhp) (*bad_html)[*bhp-1].e = html, lbhp = NULL;
  388         c_span = 0;
  389         c_al = AL_TR;
  390         c_val = VAL_TR;
  391         c_width = W_AUTO;
  392         goto see;
  393     }
  394     if (t_namelen == 3 && !casecmp(t_name, "COL", 3)) {
  395         int sp, wi, al, val;
  396         if (lbhp) (*bad_html)[*bhp-1].e = html, lbhp = NULL;
  397         if ((sp = get_num(t_attr, "span")) == -1) sp = 1;
  398         wi = c_width;
  399         al = c_al;
  400         val = c_val;
  401         get_align(t_attr, &al);
  402         get_valign(t_attr, &val);
  403         get_c_width(t_attr, &wi, sh);
  404         new_columns(t, sp, wi, al, val, !!c_span);
  405         c_span = 0;
  406         goto see;
  407     }
  408     if (t_namelen == 3 && (!casecmp(t_name, "/TR", 3) || !casecmp(t_name, "/TD", 3) || !casecmp(t_name, "/TH", 3))) {
  409         if (c_span) new_columns(t, c_span, c_width, c_al, c_val, 1);
  410         if (p) CELL(t, x, y)->end = html, p = 0;
  411         if (lbhp) (*bad_html)[*bhp-1].e = html, lbhp = NULL;
  412     }
  413     if (t_namelen == 2 && !casecmp(t_name, "TR", 2)) {
  414         if (c_span) new_columns(t, c_span, c_width, c_al, c_val, 1);
  415         if (p) CELL(t, x, y)->end = html, p = 0;
  416         if (lbhp) (*bad_html)[*bhp-1].e = html, lbhp = NULL;
  417         if (group) group--;
  418         l_al = AL_LEFT;
  419         l_val = VAL_MIDDLE;
  420         memcpy(&l_col, bgcolor, sizeof(struct rgb));
  421         get_align(t_attr, &l_al);
  422         get_valign(t_attr, &l_val);
  423         get_bgcolor(t_attr, &l_col);
  424         y++, x = 0;
  425         goto see;
  426     }
  427     if (t_namelen == 5 && ((!casecmp(t_name, "THEAD", 5)) || (!casecmp(t_name, "TBODY", 5)) || (!casecmp(t_name, "TFOOT", 5)))) {
  428         if (c_span) new_columns(t, c_span, c_width, c_al, c_val, 1);
  429         if (lbhp) (*bad_html)[*bhp-1].e = html, lbhp = NULL;
  430         group = 2;
  431     }
  432     if (t_namelen != 2 || (casecmp(t_name, "TD", 2) && casecmp(t_name, "TH", 2))) goto see;
  433     if (c_span) new_columns(t, c_span, c_width, c_al, c_val, 1);
  434     if (lbhp) (*bad_html)[*bhp-1].e = html, lbhp = NULL;
  435     if (p) CELL(t, x, y)->end = html, p = 0;
  436     if (y == -1) y = 0, x = 0;
  437     nc:
  438     cell = new_cell(t, x, y);
  439     if (cell->used) {
  440         if (cell->colspan == -1) goto see;
  441         x++;
  442         goto nc;
  443     }
  444     cell->mx = x;
  445     cell->my = y;
  446     cell->used = 1;
  447     cell->start = en;
  448     p = 1;
  449     cell->align = l_al;
  450     cell->valign = l_val;
  451     if ((cell->b = upcase(t_name[1]) == 'H')) cell->align = AL_CENTER;
  452     if (group == 1) cell->group = 1;
  453     if (x < t->c) {
  454         if (t->cols[x].align != AL_TR) cell->align = t->cols[x].align;
  455         if (t->cols[x].valign != VAL_TR) cell->valign = t->cols[x].valign;
  456     }
  457     memcpy(&cell->bgcolor, &l_col, sizeof(struct rgb));
  458     get_align(t_attr, &cell->align);
  459     get_valign(t_attr, &cell->valign);
  460     get_bgcolor(t_attr, &cell->bgcolor);
  461     if ((csp = get_num(t_attr, "colspan")) == -1) csp = 1;
  462     if (!csp) csp = -1;
  463     if ((rsp = get_num(t_attr, "rowspan")) == -1) rsp = 1;
  464     if (!rsp) rsp = -1;
  465     if (csp >= 0 && rsp >= 0 && csp * rsp > 100000) {
  466         if (csp > 10) csp = -1;
  467         if (rsp > 10) rsp = -1;
  468     }
  469     cell->colspan = csp;
  470     cell->rowspan = rsp;
  471     if (csp == 1) {
  472         int w = W_AUTO;
  473         get_c_width(t_attr, &w, sh);
  474         if (w != W_AUTO) set_td_width(t, x, w, 0);
  475     }
  476     qqq = t->x;
  477     for (i = 1; csp != -1 ? i < csp : x + i < qqq; i++) {
  478         struct table_cell *sc = new_cell(t, x + i, y);
  479         if (sc->used) {
  480             csp = i;
  481             for (k = 0; k < i; k++) CELL(t, x + k, y)->colspan = csp;
  482             break;
  483         }
  484         sc->used = sc->spanned = 1;
  485         sc->rowspan = rsp;
  486         sc->colspan = csp;
  487         sc->mx = x;
  488         sc->my = y;
  489     }
  490     qqq = t->y;
  491     for (j = 1; rsp != -1 ? j < rsp : y + j < qqq; j++) {
  492         for (k = 0; k < i; k++) {
  493             struct table_cell *sc = new_cell(t, x + k, y + j);
  494             if (sc->used) {
  495                 int l, m;
  496                 if (sc->mx == x && sc->my == y) continue;
  497                 /*internal("boo");*/
  498                 for (l = 0; l < k; l++) memset(CELL(t, x + l, y + j), 0, sizeof(struct table_cell));
  499                 rsp = j;
  500                 for (l = 0; l < i; l++) for (m = 0; m < j; m++) CELL(t, x + l, y + m)->rowspan = j;
  501                 goto brk;
  502             }
  503             sc->used = sc->spanned = 1;
  504             sc->rowspan = rsp;
  505             sc->colspan = csp;
  506             sc->mx = x;
  507             sc->my = y;
  508         }
  509     }
  510     brk:
  511     goto see;
  512 
  513     scan_done:
  514     *end = html;
  515 
  516     for (x = 0; x < t->x; x++) for (y = 0; y < t->y; y++) {
  517         struct table_cell *c = CELL(t, x, y);
  518         if (!c->spanned) {
  519             if (c->colspan == -1) c->colspan = t->x - x;
  520             if (c->rowspan == -1) c->rowspan = t->y - y;
  521         }
  522     }
  523 
  524     if ((unsigned)t->y > MAXINT / sizeof(int)) overalloc();
  525     t->r_heights = mem_alloc(t->y * sizeof(int));
  526     memset(t->r_heights, 0, t->y * sizeof(int));
  527 
  528     for (x = 0; x < t->c; x++) if (t->cols[x].width != W_AUTO) set_td_width(t, x, t->cols[x].width, 1);
  529     set_td_width(t, t->x, W_AUTO, 0);
  530 
  531     return t;
  532 }
  533 
  534 void get_cell_width(char *start, char *end, int cellpd, int w, int a, int *min, int *max, int n_link, int *n_links)
  535 {
  536     struct part *p;
  537     if (min) *min = -1;
  538     if (max) *max = -1;
  539     if (n_links) *n_links = n_link;
  540     if (!(p = format_html_part(start, end, AL_LEFT, cellpd, w, NULL, !!a, !!a, NULL, n_link))) return;
  541     if (min) *min = p->x;
  542     if (max) *max = p->xmax;
  543     if (n_links) *n_links = p->link_num;
  544     /*if (min && max && *min > *max) internal("get_cell_width: %d > %d", *min, *max);*/
  545     mem_free(p);
  546 }
  547 
  548 static inline void check_cell_widths(struct table *t)
  549 {
  550     int i, j;
  551     for (j = 0; j < t->y; j++) for (i = 0; i < t->x; i++) {
  552         int min, max;
  553         struct table_cell *c = CELL(t, i, j);
  554         if (!c->start) continue;
  555         get_cell_width(c->start, c->end, t->cellpd, 0, 0, &min, &max, c->link_num, NULL);
  556         /*if (min != c->min_width || max < c->max_width) internal("check_cell_widths failed");*/
  557     }
  558 }
  559 
  560 #define g_c_w(cc)                           \
  561 do {                                    \
  562         struct table_cell *c = cc;              \
  563         if (!c->start) continue;                \
  564         c->link_num = nl;                   \
  565         get_cell_width(c->start, c->end, t->cellpd, 0, 0, &c->min_width, &c->max_width, nl, &nl);\
  566 } while (0)
  567 
  568 void get_cell_widths(struct table *t)
  569 {
  570     int nl = t->p->link_num;
  571     int i, j;
  572     if (!d_opt->table_order)
  573         for (j = 0; j < t->y; j++) for (i = 0; i < t->x; i++) g_c_w(CELL(t, i, j));
  574     else
  575         for (i = 0; i < t->x; i++) for (j = 0; j < t->y; j++) g_c_w(CELL(t, i, j));
  576     t->link_num = nl;
  577 }
  578 
  579 void dst_width(int *p, int n, int w, int *lim)
  580 {
  581     int i, s = 0, d, r;
  582     for (i = 0; i < n; i++) s += p[i];
  583     if (s >= w) return;
  584     if (!n) return;
  585     again:
  586     d = (w - s) / n;
  587     r = (w - s) % n;
  588     w = 0;
  589     for (i = 0; i < n; i++) {
  590         p[i] += d + (i < r);
  591         if (lim && p[i] > lim[i]) w += p[i] - lim[i], p[i] = lim[i];
  592     }
  593     if (w) {
  594         /*if (!lim) internal("bug in dst_width");*/
  595         lim = NULL;
  596         s = 0;
  597         goto again;
  598     }
  599 }
  600 
  601 int get_vline_width(struct table *t, int col)
  602 {           /* return: -1 none, 0, space, 1 line, 2 double */
  603     int w = 0;
  604     if (!col) return -1;
  605     if (t->rules == R_COLS || t->rules == R_ALL) w = t->cellsp;
  606     else if (t->rules == R_GROUPS) w = col < t->c && t->cols[col].group;
  607     if (!w && t->cellpd) w = -1;
  608     return w;
  609 }
  610 
  611 int get_hline_width(struct table *t, int row)
  612 {
  613     int w = 0;
  614     if (!row) return -1;
  615     if (t->rules == R_ROWS || t->rules == R_ALL) {
  616         x:
  617         if (t->cellsp || t->vcellpd) return t->cellsp;
  618         return -1;
  619     }
  620     else if (t->rules == R_GROUPS) {
  621         int q;
  622         for (q = 0; q < t->x; q++) if (CELL(t, q, row)->group) goto x;
  623         return t->vcellpd ? 0 : -1;
  624     }
  625     if (!w && !t->vcellpd) w = -1;
  626     return w;
  627 }
  628     
  629 int get_column_widths(struct table *t)
  630 {
  631     int i, j, s, ns;
  632     if ((unsigned)t->x > MAXINT / sizeof(int)) overalloc();
  633     if (!t->min_c) t->min_c = mem_alloc(t->x * sizeof(int));
  634     if (!t->max_c) t->max_c = mem_alloc(t->x * sizeof(int));
  635     if (!t->w_c) t->w_c = mem_alloc(t->x * sizeof(int));
  636     memset(t->min_c, 0, t->x * sizeof(int));
  637     memset(t->max_c, 0, t->x * sizeof(int));
  638     s = 1;
  639     do {
  640         ns = MAXINT;
  641         for (i = 0; i < t->x; i++) for (j = 0; j < t->y; j++) {
  642             struct table_cell *c = CELL(t, i, j);
  643             if (c->spanned || !c->used) continue;
  644             if (c->colspan + i > t->x) {
  645                 /*internal("colspan out of table");
  646                 return -1;*/
  647                 continue;
  648             }
  649             if (c->colspan == s) {
  650                 int k, p = 0;
  651                 /*int pp = t->max_c[i];*/
  652                 int m = 0;
  653                 for (k = 1; k < s; k++) {
  654                     p += get_vline_width(t, i + k) >= 0;
  655                     /*pp += t->max_c[i + k];*/
  656                 }
  657                 /*if (0 && s > 1 && (t->p->data || t->p->xp)) {
  658                     int d, cc = (!!(t->frame & F_LHS) + !!(t->frame & F_RHS)) * !!t->border;
  659                     for (d = 0; d < t->c; c++) {
  660                         cc += t->max_c[d];
  661                         if (d > 0) d += get_vline_width(t, d) >= 0;
  662                     }
  663                     if (cc >= t->width) goto nd;
  664                     if (cc + c->max_width - p - pp >= t->width) {
  665                         m = cc + c->max_width - p - pp - t->width;
  666                     }
  667                 }*/
  668                 dst_width(t->min_c + i, s, c->min_width - p, t->max_c + i);
  669                 dst_width(t->max_c + i, s, c->max_width - p - m, NULL);
  670                 for (k = 0; k < s; k++) if (t->min_c[i + k] > t->max_c[i + k]) t->max_c[i + k] = t->min_c[i + k];
  671             } else if (c->colspan > s && c->colspan < ns) ns = c->colspan;
  672         }
  673     } while ((s = ns) != MAXINT);
  674     return 0;
  675 }
  676 
  677 void get_table_width(struct table *t)
  678 {
  679     int i, vl;
  680     int min = 0, max = 0;
  681     for (i = 0; i < t->x; i++) {
  682         vl = get_vline_width(t, i) >= 0;
  683         min += vl, max += vl;
  684         min += t->min_c[i];
  685         if (t->xcols[i] > t->max_c[i]) max += t->xcols[i];
  686         max += t->max_c[i];
  687     }
  688     vl = (!!(t->frame & F_LHS) + !!(t->frame & F_RHS)) * !!t->border;
  689     min += vl, max += vl;
  690     t->min_t = min;
  691     t->max_t = max;
  692     /*if (min > max) internal("min(%d) > max(%d)", min, max);*/
  693 }
  694 
  695 void distribute_widths(struct table *t, int width)
  696 {
  697     int i;
  698     int d = width - t->min_t;
  699     int om = 0;
  700     char *u;
  701     int *w, *mx;
  702     int mmax_c = 0;
  703     if (!t->x) return;
  704     if (d < 0) {
  705         /*internal("too small width %d, required %d", width, t->min_t);*/
  706         return;
  707     }
  708     for (i = 0; i < t->x; i++) if (t->max_c[i] > mmax_c) mmax_c = t->max_c[i];
  709     memcpy(t->w_c, t->min_c, t->x * sizeof(int));
  710     t->rw = width;
  711     if ((unsigned)t->x > MAXINT / sizeof(int)) overalloc();
  712     u = mem_alloc(t->x);
  713     w = mem_alloc(t->x * sizeof(int));
  714     mx = mem_alloc(t->x * sizeof(int));
  715     while (d) {
  716         int mss, mii;
  717         int p = 0;
  718         int wq;
  719         int dd;
  720         memset(w, 0, t->x * sizeof(int));
  721         memset(mx, 0, t->x * sizeof(int));
  722         for (i = 0; i < t->x; i++) {
  723             switch (om) {
  724                 case 0:
  725                     if (t->w_c[i] < t->xcols[i]) {
  726                         w[i] = 1, mx[i] = (t->xcols[i] > t->max_c[i] ? t->max_c[i] : t->xcols[i]) - t->w_c[i];
  727                         if (mx[i] <= 0) w[i] = 0;
  728                     }
  729                     break;
  730                 case 1:
  731                     if (t->xcols[i] < -1 && t->xcols[i] != -2) {
  732                         w[i] = t->xcols[i] <= -2 ? -2 - t->xcols[i] : 1;
  733                         mx[i] = t->max_c[i] - t->w_c[i];
  734                         if (mx[i] <= 0) w[i] = 0;
  735                     }
  736                     break;
  737                 case 2:
  738                 case 3:
  739                     if (t->w_c[i] < t->max_c[i] && (om == 3 || t->xcols[i] == W_AUTO)) {
  740                         mx[i] = t->max_c[i] - t->w_c[i];
  741                         if (mmax_c) w[i] = 5 + t->max_c[i] * 10 / mmax_c;
  742                         else w[i] = 1;
  743                     }
  744                     break;
  745                 case 4:
  746                     if (t->xcols[i] >= 0) {
  747                         w[i] = 1, mx[i] = t->xcols[i] - t->w_c[i];
  748                         if (mx[i] <= 0) w[i] = 0;
  749                     }
  750                     break;
  751                 case 5:
  752                     if (t->xcols[i] < 0) w[i] = t->xcols[i] <= -2 ? -2 - t->xcols[i] : 1, mx[i] = MAXINT;
  753                     break;
  754                 case 6:
  755                     w[i] = 1, mx[i] = MAXINT;
  756                     break;
  757                 default:
  758                     /*internal("could not expand table");*/
  759                     goto end2;
  760             }
  761             p += w[i];
  762         }
  763         if (!p) {
  764             om++;
  765             continue;
  766         }
  767         wq = 0;
  768         if (u) memset(u, 0, t->x);
  769         dd = d;
  770         a:
  771         mss = 0; mii = -1;
  772         for (i = 0; i < t->x; i++) if (w[i]) {
  773             int ss;
  774             if (u && u[i]) continue;
  775             if (!(ss = dd * w[i] / p)) ss = 1;
  776             if (ss > mx[i]) ss = mx[i];
  777             if (ss > mss) mss = ss, mii = i;
  778         }
  779         if (mii != -1) {
  780             int q = t->w_c[mii];
  781             if (u) u[mii] = 1;
  782             t->w_c[mii] += mss;
  783             d -= t->w_c[mii] - q;
  784             while (d < 0) t->w_c[mii]--, d++;
  785             if (t->w_c[mii] < q) {
  786                 /*internal("shrinking cell");*/
  787                 t->w_c[mii] = q;
  788             }
  789             wq = 1;
  790             if (d) goto a;
  791         } else if (!wq) om++;
  792     }
  793     end2:
  794     mem_free(mx);
  795     mem_free(w);
  796     if (u) mem_free(u);
  797 }
  798 
  799 #ifdef HTML_TABLE_2ND_PASS
  800 void check_table_widths(struct table *t)
  801 {
  802     int *w;
  803     int i, j;
  804     int s, ns;
  805     int m, mi = 0; /* go away, warning! */
  806     if ((unsigned)t->x > MAXINT / sizeof(int)) overalloc();
  807     w = mem_alloc(t->x * sizeof(int));
  808     memset(w, 0, t->x * sizeof(int));
  809     for (j = 0; j < t->y; j++) for (i = 0; i < t->x; i++) {
  810         struct table_cell *c = CELL(t, i, j);
  811         int k, p = 0;
  812         if (!c->start) continue;
  813         for (k = 1; k < c->colspan; k++) p += get_vline_width(t, i + k) >= 0;
  814         for (k = 0; k < c->colspan; k++) p += t->w_c[i + k];
  815         get_cell_width(c->start, c->end, t->cellpd, p, 1, &c->x_width, NULL, c->link_num, NULL);
  816         if (c->x_width > p) {
  817             /*int min, max;
  818             get_cell_width(c->start, c->end, t->cellpd, 0, 0, &min, &max, c->link_num, NULL);
  819             internal("cell is now wider (%d > %d) min = %d, max = %d, now_min = %d, now_max = %d", c->x_width, p, t->min_c[i], t->max_c[i], min, max);*/
  820             /* sbohem, internale. chytl jsi mi spoustu chyb v tabulkovaci, ale ted je proste cas jit ... ;-( */
  821             c->x_width = p;
  822         }
  823     }
  824     s = 1;
  825     do {
  826         ns = MAXINT;
  827         for (i = 0; i < t->x; i++) for (j = 0; j < t->y; j++) {
  828             struct table_cell *c = CELL(t, i, j);
  829             if (!c->start) continue;
  830             if (c->colspan + i > t->x) {
  831                 /*internal("colspan out of table");*/
  832                 mem_free(w);
  833                 return;
  834             }
  835             if (c->colspan == s) {
  836                 int k, p = 0;
  837                 for (k = 1; k < s; k++) p += get_vline_width(t, i + k) >= 0;
  838                 dst_width(w + i, s, c->x_width - p, t->max_c + i);
  839                 /*for (k = i; k < i + s; k++) if (w[k] > t->w_c[k]) {
  840                     int l;
  841                     int c;
  842                     ag:
  843                     c = 0;
  844                     for (l = i; l < i + s; l++) if (w[l] < t->w_c[k]) w[l]++, w[k]--, c = 1;
  845                     if (w[k] > t->w_c[k]) {
  846                         if (!c) internal("can't shrink cell");
  847                         else goto ag;
  848                     }
  849                 }*/
  850             } else if (c->colspan > s && c->colspan < ns) ns = c->colspan;
  851         }
  852     } while ((s = ns) != MAXINT);
  853 
  854     s = 0; ns = 0;
  855     for (i = 0; i < t->x; i++) {
  856         s += t->w_c[i], ns += w[i];
  857         /*if (w[i] > t->w_c[i]) {
  858             int k;
  859             for (k = 0; k < t->x; k++) debug("%d, %d", t->w_c[k], w[k]);
  860             debug("column %d: new width(%d) is larger than previous(%d)", i, w[i], t->w_c[i]);
  861         }*/
  862     }
  863     if (ns > s) {
  864         /*internal("new width(%d) is larger than previous(%d)", ns, s);*/
  865         mem_free(w);
  866         return;
  867     }
  868     m = -1;
  869     for (i = 0; i < t->x; i++) {
  870         /*if (table_level == 1) debug("%d: %d %d %d %d", i, t->max_c[i], t->min_c[i], t->w_c[i], w[i]);*/
  871         if (t->max_c[i] > m) m = t->max_c[i], mi = i;
  872     }
  873     /*if (table_level == 1) debug("%d %d", mi, s - ns);*/
  874     if (m != -1) {
  875         w[mi] += s - ns;
  876         if (w[mi] <= t->max_c[mi]) {
  877             mem_free(t->w_c);
  878             t->w_c = w;
  879             return;
  880         }
  881     }
  882     mem_free(w);
  883 }
  884 #endif
  885 
  886 void get_table_heights(struct table *t)
  887 {
  888     int s, ns;
  889     int i, j;
  890     for (j = 0; j < t->y; j++) {
  891         for (i = 0; i < t->x; i++) {
  892             struct table_cell *cell = CELL(t, i, j);
  893             struct part *p;
  894             int xw = 0, sp;
  895             if (!cell->used || cell->spanned) continue;
  896             for (sp = 0; sp < cell->colspan; sp++) {
  897                 xw += t->w_c[i + sp];
  898                 if (sp < cell->colspan - 1) xw += get_vline_width(t, i + sp + 1) >= 0;
  899             }
  900             if (!(p = format_html_part(cell->start, cell->end, cell->align, t->cellpd, xw, NULL, 2, 2, NULL, cell->link_num))) return;
  901             cell->height = p->y;
  902                 /*debug("%d, %d.",xw, cell->height);*/
  903             mem_free(p);
  904         }
  905     }
  906     s = 1;
  907     do {
  908         ns = MAXINT;
  909         for (j = 0; j < t->y; j++) {
  910             for (i = 0; i < t->x; i++) {
  911                 struct table_cell *cell = CELL(t, i, j);
  912                 if (!cell->used || cell->spanned) continue;
  913                 if (cell->rowspan == s) {
  914                     int k, p = 0;
  915                     for (k = 1; k < s; k++) p += get_hline_width(t, j + k) >= 0;
  916                     dst_width(t->r_heights + j, s, cell->height - p, NULL);
  917                 } else if (cell->rowspan > s && cell->rowspan < ns) ns = cell->rowspan;
  918             }
  919         }
  920     } while ((s = ns) != MAXINT);
  921     t->rh = (!!(t->frame & F_ABOVE) + !!(t->frame & F_BELOW)) * !!t->border;
  922     for (j = 0; j < t->y; j++) {
  923         t->rh += t->r_heights[j];
  924         if (j) t->rh += get_hline_width(t, j) >= 0;
  925     }
  926 }
  927 
  928 void display_complicated_table(struct table *t, int x, int y, int *yy)
  929 {
  930     int i, j;
  931     struct f_data *f = t->p->data;
  932     int yp, xp = x + ((t->frame & F_LHS) && t->border);
  933     for (i = 0; i < t->x; i++) {
  934         yp = y + ((t->frame & F_ABOVE) && t->border);
  935         for (j = 0; j < t->y; j++) {
  936             struct table_cell *cell = CELL(t, i, j);
  937             if (cell->start) {
  938                 int yt;
  939                 struct part *p = NULL;
  940                 int xw = 0, yw = 0, s;
  941                 for (s = 0; s < cell->colspan; s++) {
  942                     xw += t->w_c[i + s];
  943                     if (s < cell->colspan - 1) xw += get_vline_width(t, i + s + 1) >= 0;
  944                 }
  945                 for (s = 0; s < cell->rowspan; s++) {
  946                     yw += t->r_heights[j + s];
  947                     if (s < cell->rowspan - 1) yw += get_hline_width(t, j + s + 1) >= 0;
  948                 }
  949                 html_stack_dup();
  950                 html_top.dontkill = 1;
  951                 if (cell->b) format_.attr |= AT_BOLD;
  952                 memcpy(&format_.bg, &cell->bgcolor, sizeof(struct rgb));
  953                 memcpy(&par_format.bgcolor, &cell->bgcolor, sizeof(struct rgb));
  954                 p = format_html_part(cell->start, cell->end, cell->align, t->cellpd, xw, f, t->p->xp + xp, t->p->yp + yp + (cell->valign != VAL_MIDDLE && cell->valign != VAL_BOTTOM ? 0 : (yw - cell->height) / (cell->valign == VAL_MIDDLE ? 2 : 1)), NULL, cell->link_num);
  955                 cell->xpos = xp;
  956                 cell->ypos = yp;
  957                 cell->xw = xw;
  958                 cell->yw = yw;
  959                 for (yt = 0; yt < p->y; yt++) {
  960                     xxpand_lines(t->p, yp + yt);
  961                     xxpand_line(t->p, yp + yt, xp + t->w_c[i]);
  962                 }
  963                 kill_html_stack_item(&html_top);
  964                 mem_free(p);
  965             }
  966             cell->xpos = xp;
  967             cell->ypos = yp;
  968             cell->xw = t->w_c[i];
  969             yp += t->r_heights[j];
  970             if (j < t->y - 1) yp += (get_hline_width(t, j + 1) >= 0);
  971         }
  972         if (i < t->x - 1) xp += t->w_c[i] + (get_vline_width(t, i + 1) >= 0);
  973     }
  974     yp = y;
  975     for (j = 0; j < t->y; j++) {
  976         yp += t->r_heights[j];
  977         if (j < t->y - 1) yp += (get_hline_width(t, j + 1) >= 0);
  978     }
  979     *yy = yp + (!!(t->frame & F_ABOVE) + !!(t->frame & F_BELOW)) * !!t->border;
  980 }
  981 
  982 /* !!! FIXME: background */
  983 #define draw_frame_point(xx, yy, ii, jj)    \
  984 if (H_LINE_X((ii-1), (jj)) >= 0 || H_LINE_X((ii), (jj)) >= 0 || V_LINE_X((ii), (jj-1)) >= 0 || V_LINE_X((ii), (jj)) >= 0) xset_hchar(t->p, (xx), (yy), frame_table[V_LINE((ii),(jj)-1)+3*H_LINE((ii),(jj))+9*H_LINE((ii)-1,(jj))+27*V_LINE((ii),(jj))] | ATTR_FRAME)
  985 
  986 #define draw_frame_hline(xx, yy, ll, ii, jj)    \
  987 if (H_LINE_X((ii), (jj)) >= 0) xset_hchars(t->p, (xx), (yy), (ll), hline_table[H_LINE((ii), (jj))] | ATTR_FRAME)
  988 
  989 #define draw_frame_vline(xx, yy, ll, ii, jj)    \
  990 {                       \
  991     int qq;                 \
  992     if (V_LINE_X((ii), (jj)) >= 0) for (qq = 0; qq < (ll); qq++) xset_hchar(t->p, (xx), (yy) + qq, vline_table[V_LINE((ii), (jj))] | ATTR_FRAME); }
  993 
  994 void display_table_frames(struct table *t, int x, int y)
  995 {
  996     signed char *fh, *fv;
  997     int i, j;
  998     int cx, cy;
  999     if ((unsigned)t->x > MAXINT) overalloc();
 1000     if ((unsigned)t->y > MAXINT) overalloc();
 1001     if (((unsigned)t->x + 2) * ((unsigned)t->y + 2) / ((unsigned)t->x + 2) != ((unsigned)t->y + 2)) overalloc();
 1002     if (((unsigned)t->x + 2) * ((unsigned)t->y + 2) > MAXINT) overalloc();
 1003     fh = mem_alloc((t->x + 2) * (t->y + 1));
 1004     memset(fh, -1, (t->x + 2) * (t->y + 1));
 1005     fv = mem_alloc((t->x + 1) * (t->y + 2));
 1006     memset(fv, -1, (t->x + 1) * (t->y + 2));
 1007 #ifndef DEBUG
 1008 #define H_LINE_X(xx, yy) fh[(xx) + 1 + (t->x + 2) * (yy)]
 1009 #define V_LINE_X(xx, yy) fv[(yy) + 1 + (t->y + 2) * (xx)]
 1010 #else
 1011 #define H_LINE_X(xx, yy) (*(xx < -1 || xx > t->x + 1 || yy < 0 || yy > t->y ? (signed char *)NULL : &fh[(xx) + 1 + (t->x + 2) * (yy)]))
 1012 #define V_LINE_X(xx, yy) (*(xx < 0 || xx > t->x || yy < -1 || yy > t->y + 1 ? (signed char *)NULL : &fv[(yy) + 1 + (t->y + 2) * (xx)]))
 1013 #endif
 1014 #define H_LINE(xx, yy) (H_LINE_X((xx), (yy)) == -1 ? 0 : H_LINE_X((xx), (yy)))
 1015 #define V_LINE(xx, yy) (V_LINE_X((xx), (yy)) == -1 ? 0 : V_LINE_X((xx), (yy)))
 1016     for (j = 0; j < t->y; j++) for (i = 0; i < t->x; i++) {
 1017         int x, y;
 1018         int xsp, ysp;
 1019         struct table_cell *cell = CELL(t, i, j);
 1020         if (!cell->used || cell->spanned) continue;
 1021         if ((xsp = cell->colspan) == 0) xsp = t->x - i;
 1022         if ((ysp = cell->rowspan) == 0) ysp = t->y - j;
 1023         if (t->rules != R_NONE && t->rules != R_COLS) for (x = 0; x < xsp; x++) {H_LINE_X(i + x, j) = t->cellsp; H_LINE_X(i + x, j + ysp) = t->cellsp;}
 1024         if (t->rules != R_NONE && t->rules != R_ROWS) for (y = 0; y < ysp; y++) {V_LINE_X(i, j + y) = t->cellsp; V_LINE_X(i + xsp, j + y) = t->cellsp;}
 1025     }
 1026     if (t->rules == R_GROUPS) {
 1027         for (i = 1; i < t->x; i++) {
 1028             if (/*i < t->xc &&*/ t->xcols[i]) continue;
 1029             for (j = 0; j < t->y; j++) V_LINE_X(i, j) = 0;
 1030         }
 1031         for (j = 1; j < t->y; j++) {
 1032             for (i = 0; i < t->x; i++) if (CELL(t, i, j)->group) goto c;
 1033             for (i = 0; i < t->x; i++) H_LINE_X(i, j) = 0;
 1034             c:;
 1035         }
 1036     }
 1037     for (i = 0; i < t->x; i++) {
 1038         H_LINE_X(i, 0) = t->border * !!(t->frame & F_ABOVE);
 1039         H_LINE_X(i, t->y) = t->border * !!(t->frame & F_BELOW);
 1040     }
 1041     for (j = 0; j < t->y; j++) {
 1042         V_LINE_X(0, j) = t->border * !!(t->frame & F_LHS);
 1043         V_LINE_X(t->x, j) = t->border * !!(t->frame & F_RHS);
 1044     }
 1045 
 1046     cy = y;
 1047     for (j = 0; j <= t->y; j++) {
 1048         cx = x;
 1049         if ((j > 0 && j < t->y && get_hline_width(t, j) >= 0) || (j == 0 && t->border && (t->frame & F_ABOVE)) || (j == t->y && t->border && (t->frame & F_BELOW))) {
 1050             for (i = 0; i < t->x; i++) {
 1051                 int w;
 1052                 if (i > 0) w = get_vline_width(t, i);
 1053                 else w = t->border && (t->frame & F_LHS) ? t->border : -1;
 1054                 if (w >= 0) {
 1055                     draw_frame_point(cx, cy, i, j);
 1056                     if (j < t->y) draw_frame_vline(cx, cy + 1, t->r_heights[j], i, j);
 1057                     cx++;
 1058                 }
 1059                 w = t->w_c[i];
 1060                 draw_frame_hline(cx, cy, w, i, j);
 1061                 cx += w;
 1062             }
 1063             if (t->border && (t->frame & F_RHS)) {
 1064                 draw_frame_point(cx, cy, i, j);
 1065                 if (j < t->y) draw_frame_vline(cx, cy + 1, t->r_heights[j], i, j);
 1066                 cx++;
 1067             }
 1068             cy++;
 1069         } else if (j < t->y) {
 1070             for (i = 0; i <= t->x; i++) {
 1071                 if ((i > 0 && i < t->x && get_vline_width(t, i) >= 0) || (i == 0 && t->border && (t->frame & F_LHS)) || (i == t->x && t->border && (t->frame & F_RHS))) {
 1072                     draw_frame_vline(cx, cy, t->r_heights[j], i, j);
 1073                     cx++;
 1074                 }
 1075                 if (i < t->x) cx += t->w_c[i];
 1076             }
 1077         }
 1078         if (j < t->y) cy += t->r_heights[j];
 1079         /*for (cyy = cy1; cyy < cy; cyy++) xxpand_line(t->p, cyy, cx - 1);*/
 1080     }
 1081     mem_free(fh);
 1082     mem_free(fv);
 1083 }
 1084 
 1085 void format_table(unsigned char *attr, unsigned char *html, unsigned char *eof, unsigned char **end, void *f)
 1086 {
 1087     struct part *p = f;
 1088     int border, cellsp, vcellpd, cellpd, align;
 1089     int frame, rules, width, wf;
 1090     struct rgb bgcolor;
 1091     struct table *t;
 1092     char *al;
 1093     int cye;
 1094     int x;
 1095     int i;
 1096     /*int llm = last_link_to_move;*/
 1097     struct s_e *bad_html;
 1098     int bad_html_n;
 1099     struct node *n, *nn;
 1100     int cpd_pass, cpd_width, cpd_last;
 1101     /*if (!p->data) {
 1102         debug("nested tables not supported");
 1103         return;
 1104     }*/
 1105     table_level++;
 1106     memcpy(&bgcolor, &par_format.bgcolor, sizeof(struct rgb));
 1107     get_bgcolor(attr, &bgcolor);
 1108     if ((border = get_num(attr, "border")) == -1) border = has_attr(attr, "border") || has_attr(attr, "rules") || has_attr(attr, "frame");
 1109     /*if (!border) border = 1;*/
 1110 
 1111     if ((cellsp = get_num(attr, "cellspacing")) == -1) cellsp = 1;
 1112     if ((cellpd = get_num(attr, "cellpadding")) == -1) {
 1113         vcellpd = 0;
 1114         cellpd = !!border;
 1115     } else {
 1116         vcellpd = cellpd >= HTML_CHAR_HEIGHT / 2 + 1;
 1117         cellpd = cellpd >= HTML_CHAR_WIDTH / 2 + 1;
 1118     }
 1119     if (!border) cellsp = 0;
 1120     else if (!cellsp) cellsp = 1;
 1121     if (border > 2) border = 2;
 1122     if (cellsp > 2) cellsp = 2;
 1123     align = par_format.align;
 1124     if (align == AL_NO || align == AL_BLOCK) align = AL_LEFT;
 1125     if ((al = get_attr_val(attr, "align"))) {
 1126         if (!strcasecmp(al, "left")) align = AL_LEFT;
 1127         if (!strcasecmp(al, "center")) align = AL_CENTER;
 1128         if (!strcasecmp(al, "right")) align = AL_RIGHT;
 1129         mem_free(al);
 1130     }
 1131     frame = F_BOX;
 1132     if ((al = get_attr_val(attr, "frame"))) {
 1133         if (!strcasecmp(al, "void")) frame = F_VOID;
 1134         if (!strcasecmp(al, "above")) frame = F_ABOVE;
 1135         if (!strcasecmp(al, "below")) frame = F_BELOW;
 1136         if (!strcasecmp(al, "hsides")) frame = F_HSIDES;
 1137         if (!strcasecmp(al, "vsides")) frame = F_VSIDES;
 1138         if (!strcasecmp(al, "lhs")) frame = F_LHS;
 1139         if (!strcasecmp(al, "rhs")) frame = F_RHS;
 1140         if (!strcasecmp(al, "box")) frame = F_BOX;
 1141         if (!strcasecmp(al, "border")) frame = F_BOX;
 1142         mem_free(al);
 1143     }
 1144     rules = border ? R_ALL : R_NONE;
 1145     if ((al = get_attr_val(attr, "rules"))) {
 1146         if (!strcasecmp(al, "none")) rules = R_NONE;
 1147         if (!strcasecmp(al, "groups")) rules = R_GROUPS;
 1148         if (!strcasecmp(al, "rows")) rules = R_ROWS;
 1149         if (!strcasecmp(al, "cols")) rules = R_COLS;
 1150         if (!strcasecmp(al, "all")) rules = R_ALL;
 1151         mem_free(al);
 1152     }
 1153     if (!border) frame = F_VOID;
 1154     wf = 0;
 1155     if ((width = get_width(attr, "width", p->data || p->xp)) == -1) {
 1156         width = par_format.width - par_format.leftmargin - par_format.rightmargin;
 1157         if (width < 0) width = 0;
 1158         wf = 1;
 1159     }
 1160     if (!(t = parse_table(html, eof, end, &bgcolor, p->data || p->xp, &bad_html, &bad_html_n))) {
 1161         mem_free(bad_html);
 1162         goto ret0;
 1163     }
 1164     for (i = 0; i < bad_html_n; i++) {
 1165         while (bad_html[i].s < bad_html[i].e && WHITECHAR(*bad_html[i].s)) bad_html[i].s++;
 1166         while (bad_html[i].s < bad_html[i].e && WHITECHAR(bad_html[i].e[-1])) bad_html[i].e--;
 1167         if (bad_html[i].s < bad_html[i].e) parse_html(bad_html[i].s, bad_html[i].e, put_chars_f, line_break_f, special_f, p, NULL);
 1168     }
 1169     mem_free(bad_html);
 1170     html_stack_dup();
 1171     html_top.dontkill = 1;
 1172     par_format.align = AL_LEFT;
 1173     t->p = p;
 1174     t->border = border;
 1175     t->cellpd = cellpd;
 1176     t->vcellpd = vcellpd;
 1177     t->cellsp = cellsp;
 1178     t->frame = frame;
 1179     t->rules = rules;
 1180     t->width = width;
 1181     t->wf = wf;
 1182     cpd_pass = 0;
 1183     cpd_last = t->cellpd;
 1184     cpd_width = 0;  /* not needed, but let the warning go away */
 1185     again:
 1186     get_cell_widths(t);
 1187     if (get_column_widths(t)) goto ret2;
 1188     get_table_width(t);
 1189     if (!p->data && !p->xp) {
 1190         if (!wf && t->max_t > width) t->max_t = width;
 1191         if (t->max_t < t->min_t) t->max_t = t->min_t;
 1192         if (t->max_t + par_format.leftmargin + par_format.rightmargin > p->xmax) p->xmax = t->max_t + par_format.leftmargin + par_format.rightmargin;
 1193         if (t->min_t + par_format.leftmargin + par_format.rightmargin > p->x) p->x = t->min_t + par_format.leftmargin + par_format.rightmargin;
 1194         goto ret2;
 1195     }
 1196     if (!cpd_pass && t->min_t > width && t->cellpd) {
 1197         t->cellpd = 0;
 1198         cpd_pass = 1;
 1199         cpd_width = t->min_t;
 1200         goto again;
 1201     }
 1202     if (cpd_pass == 1 && t->min_t > cpd_width) {
 1203         t->cellpd = cpd_last;
 1204         cpd_pass = 2;
 1205         goto again;
 1206     }
 1207     /*debug("%d %d %d", t->min_t, t->max_t, width);*/
 1208     if (t->min_t >= width) distribute_widths(t, t->min_t);
 1209     else if (t->max_t < width && wf) distribute_widths(t, t->max_t);
 1210     else distribute_widths(t, width);
 1211     if (!p->data && p->xp == 1) {
 1212         int ww = t->rw + par_format.leftmargin + par_format.rightmargin;
 1213         if (ww > par_format.width) ww = par_format.width;
 1214         if (ww < t->rw) ww = t->rw;
 1215         if (ww > p->x) p->x = ww;
 1216         p->cy += t->rh;
 1217         goto ret2;
 1218     }
 1219 #ifdef HTML_TABLE_2ND_PASS
 1220     check_table_widths(t);
 1221 #endif
 1222     x = par_format.leftmargin;
 1223     if (align == AL_CENTER) x = (par_format.width + par_format.leftmargin - par_format.rightmargin - t->rw) / 2;
 1224     if (align == AL_RIGHT) x = par_format.width - par_format.rightmargin - t->rw;
 1225     if (x + t->rw > par_format.width) x = par_format.width - t->rw;
 1226     if (x < 0) x = 0;
 1227     /*display_table(t, x, p->cy, &cye);*/
 1228     get_table_heights(t);
 1229     if (!p->data) {
 1230         if (t->rw + par_format.leftmargin + par_format.rightmargin > p->x) p->x = t->rw + par_format.leftmargin + par_format.rightmargin;
 1231         p->cy += t->rh;
 1232         goto ret2;
 1233     }
 1234     n = p->data->nodes.next;
 1235     n->yw = p->yp - n->y + p->cy;
 1236     display_complicated_table(t, x, p->cy, &cye);
 1237     display_table_frames(t, x, p->cy);
 1238     nn = mem_alloc(sizeof(struct node));
 1239     nn->x = n->x;
 1240     nn->y = p->yp + cye;
 1241     nn->xw = n->xw;
 1242     add_to_list(p->data->nodes, nn);
 1243     /*sdbg(p->data);*/
 1244     /*for (y = p->cy; y < cye; y++) {
 1245         last_link_to_move = llm;
 1246         align_line(p, y);
 1247     }*/
 1248     /*if (p->cy + t->rh != cye) internal("size does not match; 1:%d, 2:%d", p->cy + t->rh, cye);*/
 1249     p->cy = cye;
 1250     p->cx = -1;
 1251 
 1252     ret2:
 1253     p->link_num = t->link_num;
 1254     if (p->cy > p->y) p->y = p->cy;
 1255     /*ret1:*/
 1256     free_table(t);
 1257     kill_html_stack_item(&html_top);
 1258     ret0:
 1259     /*ret:*/
 1260     table_level--;
 1261     if (!table_level) free_table_cache();
 1262 }