"Fossies" - the Fresh Open Source Software Archive

Member "links-1.03/html_tbl.c" (30 Sep 2011, 36644 Bytes) of archive /linux/www/links-1.03.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: 2.8_vs_1.03.

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