"Fossies" - the Fresh Open Source Software Archive

Member "links-1.04/html_r.c" (10 Oct 2017, 42174 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_r.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 static inline int color_distance(struct rgb *c1, struct rgb *c2)
    4 {
    5     return
    6         3 * (c1->r - c2->r) * (c1->r - c2->r) +
    7         4 * (c1->g - c2->g) * (c1->g - c2->g) +
    8         2 * (c1->b - c2->b) * (c1->b - c2->b);
    9 }
   10 
   11 struct rgb palette[] = {
   12 /*  {0x00, 0x00, 0x00, 0},
   13     {0x80, 0x00, 0x00, 0},
   14     {0x00, 0x80, 0x00, 0},
   15     {0x80, 0x80, 0x00, 0},
   16     {0x00, 0x00, 0x80, 0},
   17     {0x80, 0x00, 0x80, 0},
   18     {0x00, 0x80, 0x80, 0},
   19     {0xC0, 0xC0, 0xC0, 0},
   20     {0x80, 0x80, 0x80, 0},
   21     {0xff, 0x00, 0x00, 0},
   22     {0x00, 0xff, 0x00, 0},
   23     {0xff, 0xff, 0x00, 0},
   24     {0x00, 0x00, 0xff, 0},
   25     {0xff, 0x00, 0xff, 0},
   26     {0x00, 0xff, 0xff, 0},
   27     {0xff, 0xff, 0xff, 0},*/
   28     /*{0x00, 0x00, 0x00, 0},
   29     {0xaa, 0x00, 0x00, 0},
   30     {0x00, 0xaa, 0x00, 0},
   31     {0xaa, 0x55, 0x00, 0},
   32     {0x00, 0x00, 0xaa, 0},
   33     {0xaa, 0x00, 0xaa, 0},
   34     {0x00, 0xaa, 0xaa, 0},
   35     {0xaa, 0xaa, 0xaa, 0},
   36     {0x55, 0x55, 0x55, 0},
   37     {0xff, 0x55, 0x55, 0},
   38     {0x55, 0xff, 0x55, 0},
   39     {0xff, 0xff, 0x55, 0},
   40     {0x55, 0x55, 0xff, 0},
   41     {0xff, 0x55, 0xff, 0},
   42     {0x55, 0xff, 0xff, 0},
   43     {0xff, 0xff, 0xff, 0},*/
   44     {0x00, 0x00, 0x00, 0},
   45     {0x80, 0x00, 0x00, 0},
   46     {0x00, 0x80, 0x00, 0},
   47     {0xaa, 0x55, 0x00, 0},
   48     {0x00, 0x00, 0x80, 0},
   49     {0x80, 0x00, 0x80, 0},
   50     {0x00, 0x80, 0x80, 0},
   51     {0xaa, 0xaa, 0xaa, 0},
   52     {0x55, 0x55, 0x55, 0},
   53     {0xff, 0x55, 0x55, 0},
   54     {0x55, 0xff, 0x55, 0},
   55     {0xff, 0xff, 0x55, 0},
   56     {0x55, 0x55, 0xff, 0},
   57     {0xff, 0x55, 0xff, 0},
   58     {0x55, 0xff, 0xff, 0},
   59     {0xff, 0xff, 0xff, 0},
   60     {-1, -1, -1, 0},
   61 };
   62 
   63 /*struct rgb rgbcache = {0, 0, 0};
   64 int rgbcache_c = 0;
   65 
   66 static inline int find_nearest_color(struct rgb *r, int l)
   67 {
   68     int dist, dst, min, i;
   69     if (r->r == rgbcache.r && r->g == rgbcache.g && r->b == rgbcache.b) return rgbcache_c;
   70     dist = 0xffffff;
   71     min = 0;
   72     for (i = 0; i < l; i++) if ((dst = color_distance(r, &palette[i])) < dist)
   73         dist = dst, min = i;
   74     return min;
   75 }*/
   76 
   77 struct rgb_cache_entry {
   78     int color;
   79     int l;
   80     struct rgb rgb;
   81 };
   82 
   83 #define RGB_HASH_SIZE 4096
   84 
   85 #define HASH_RGB(r, l) ((((r)->r << 3) + ((r)->g << 2) + (r)->b + (l)) & (RGB_HASH_SIZE - 1))
   86 
   87 static inline int find_nearest_color(struct rgb *r, int l)
   88 {
   89     int dist, dst, min, i;
   90     static struct rgb_cache_entry rgb_cache[RGB_HASH_SIZE];
   91     static int cache_init = 0;
   92     int h;
   93     if (!cache_init) goto initialize;
   94     back:
   95     h = HASH_RGB(r, l);
   96     if (rgb_cache[h].color != -1 && rgb_cache[h].l == l && rgb_cache[h].rgb.r == r->r && rgb_cache[h].rgb.g == r->g && rgb_cache[h].rgb.b == r->b) return rgb_cache[h].color;
   97     dist = 0xffffff;
   98     min = 0;
   99     for (i = 0; i < l; i++) if ((dst = color_distance(r, &palette[i])) < dist)
  100         dist = dst, min = i;
  101     rgb_cache[h].color = min;
  102     rgb_cache[h].l = l;
  103     rgb_cache[h].rgb.r = r->r;
  104     rgb_cache[h].rgb.g = r->g;
  105     rgb_cache[h].rgb.b = r->b;
  106     return min;
  107 
  108     initialize:
  109     for (h = 0; h < RGB_HASH_SIZE; h++) rgb_cache[h].color = -1;
  110     cache_init = 1;
  111     goto back;
  112 }
  113 
  114 static inline int fg_color(int fg, int bg)
  115 {
  116     int l = bg < fg ? bg : fg;
  117     int h = bg < fg ? fg : bg;
  118     if (l == h || (!l && (h == 4 || h == 8 || h == 12)) ||
  119        (l == 1 && (h == 3 || h == 5 || h == 8 || h == 12)) ||
  120        (l == 2 && h == 6) || (l == 3 && (h == 5 || h == 12)) ||
  121        (l == 4 && (h == 8 || h == 12)) || (l == 5 && (h == 8 || h == 12)))
  122         return (fg == 4 || fg == 12) && (bg == 0 || bg == 8) ? 6 : (7 - 7 * (bg == 2 || bg == 6 || bg == 7));
  123     return fg;
  124 }
  125 
  126 #define XALIGN(x) (((x)+0x7f)&~0x7f)
  127 
  128 int nowrap = 0;
  129 
  130 static inline void xpand_lines(struct part *p, int y)
  131 {
  132     /*if (y >= p->y) p->y = y + 1;*/
  133     if (!p->data) return;
  134     if (XALIGN((unsigned)y + (unsigned)p->yp) > MAXINT) overalloc();
  135     y += p->yp;
  136     if (y >= p->data->y) {          /* !!! FIXME: out of inline */
  137         int i;
  138         if (XALIGN(y + 1) > XALIGN(p->data->y)) {
  139             if (XALIGN((unsigned)y + 1) > MAXINT / sizeof(struct line)) overalloc();
  140             p->data->data = mem_realloc(p->data->data, XALIGN(y+1)*sizeof(struct line));
  141         }
  142         for (i = p->data->y; i <= y; i++) {
  143             p->data->data[i].l = 0;
  144             p->data->data[i].c = p->bgcolor;
  145             p->data->data[i].d = DUMMY;
  146         }
  147         p->data->y = i;
  148     }
  149 }
  150 
  151 static inline void xpand_line(struct part *p, int y, int x)
  152 {
  153     if (!p->data) return; /* !!! FIXME: p->x (?) */
  154     if (XALIGN((unsigned)x + (unsigned)p->xp) > MAXINT) overalloc();
  155     x += p->xp;
  156     y += p->yp;
  157 #ifdef DEBUG
  158     if (y >= p->data->y) {
  159         internal("line does not exist");
  160         return;
  161     }
  162 #endif
  163     if (x >= p->data->data[y].l) {      /* !!! FIXME: out of inline */
  164         int i;
  165         if (XALIGN(x+1) > XALIGN(p->data->data[y].l)) {
  166             if (XALIGN((unsigned)x + 1) > MAXINT / sizeof(chr)) overalloc();
  167             p->data->data[y].d = mem_realloc(p->data->data[y].d, XALIGN(x+1)*sizeof(chr));
  168         }
  169         for (i = p->data->data[y].l; i <= x; i++)
  170             p->data->data[y].d[i] = (p->data->data[y].c << 11) | 0x700 | ' ';
  171         p->data->data[y].c = p->bgcolor;
  172         p->data->data[y].l = i;
  173     }
  174 }
  175 
  176 void r_xpand_spaces(struct part *p, int l)
  177 {
  178     unsigned char *c;
  179     if ((unsigned)l >= MAXINT) overalloc();
  180     c = mem_realloc(p->spaces, l + 1);
  181     memset(c + p->spl, 0, l - p->spl + 1);
  182     p->spl = l + 1;
  183     p->spaces = c;
  184 }
  185 
  186 static inline void xpand_spaces(struct part *p, int l)
  187 {
  188     if ((unsigned)l >= (unsigned)p->spl) r_xpand_spaces(p, l);
  189 }
  190 
  191 #define POS(x, y) (p->data->data[p->yp + (y)].d[p->xp + (x)])
  192 #define LEN(y) (p->data->data[p->yp + (y)].l - p->xp < 0 ? 0 : p->data->data[p->yp + (y)].l - p->xp)
  193 #define SLEN(y, x) p->data->data[p->yp + (y)].l = p->xp + x;
  194 #define X(x) (p->xp + (x))
  195 #define Y(y) (p->yp + (y))
  196 
  197 static inline void set_hchar(struct part *p, int x, int y, unsigned c)
  198 {
  199     xpand_lines(p, y);
  200     xpand_line(p, y, x);
  201     POS(x, y) = c;
  202 }
  203 
  204 static inline void set_hchars(struct part *p, int x, int y, int xl, unsigned c)
  205 {
  206     xpand_lines(p, y);
  207     xpand_line(p, y, x+xl-1);
  208     for (; xl; xl--, x++) POS(x, y) = c;
  209 }
  210 
  211 void xset_hchar(struct part *p, int x, int y, unsigned c)
  212 {
  213     set_hchar(p, x, y, c);
  214 }
  215 
  216 void xset_hchars(struct part *p, int x, int y, int xl, unsigned c)
  217 {
  218     set_hchars(p, x, y, xl, c);
  219 }
  220 
  221 void xxpand_lines(struct part *p, int y)
  222 {
  223     xpand_lines(p, y);
  224 }
  225 
  226 void xxpand_line(struct part *p, int y, int x)
  227 {
  228     xpand_line(p, y, x);
  229 }
  230 
  231 static inline void set_hline(struct part *p, int x, int y, int xl, unsigned char *d, unsigned c, int spc)
  232 {
  233     xpand_lines(p, y);
  234     xpand_line(p, y, x+xl-1);
  235     if (spc) xpand_spaces(p, x+xl-1);
  236     for (; xl; xl--, x++, d++) {
  237         if (spc) p->spaces[x] = *d == ' ';
  238         if (p->data) POS(x, y) = *d | c;
  239     }
  240 }
  241 
  242 int last_link_to_move;
  243 struct tag *last_tag_to_move;
  244 struct tag *last_tag_for_newline;
  245 
  246 static inline void move_links(struct part *p, int xf, int yf, int xt, int yt)
  247 {
  248     int n;
  249     struct tag *t;
  250     int w = 0;
  251     if (!p->data) return;
  252     xpand_lines(p, yt);
  253     for (n = last_link_to_move; n < p->data->nlinks; n++) {
  254         int i;
  255         struct link *link = &p->data->links[n];
  256             /*printf("ml: %d %d %d %d",link->pos[0].x,link->pos[0].y,X(xf),Y(yf));fflush(stdout);sleep(1);*/
  257         /*for (i = 0; i < link->n; i++) fprintf(stderr, "%d.%d -> %d.%d: %d.%d : %d %d\n", X(xf), Y(yf), X(xt), yt != -1 ? Y(yt) : -1, n, i, link->pos[i].x, link->pos[i].y);*/
  258         for (i = 0; i < link->n; i++) if (link->pos[i].y >= Y(yf)) {
  259             w = 1;
  260             if (link->pos[i].y == Y(yf) && link->pos[i].x >= X(xf)) {
  261                 if (yt >= 0) link->pos[i].y = Y(yt), link->pos[i].x += -xf + xt;
  262                 else memmove(&link->pos[i], &link->pos[i+1], (link->n-i-1) * sizeof(struct point)), link->n--, i--;
  263             }
  264         }
  265         /*if (!link->n) {
  266             if (link->where) mem_free(link->where);
  267             if (link->target) mem_free(link->target);
  268             if (link->where_img) mem_free(link->where_img);
  269             if (link->pos) mem_free(link->pos);
  270             memmove(link, link + 1, (p->data->nlinks - n - 1) * sizeof(struct link));
  271             p->data->nlinks --;
  272             n--;
  273         }*/
  274         if (!w /*&& n >= 0*/) last_link_to_move = n;
  275     }
  276     w = 0;
  277     if (yt >= 0) for (t = last_tag_to_move->next; (void *)t != &p->data->tags; t = t->next) {
  278         if (t->y == Y(yf)) {
  279             w = 1;
  280             if (t->x >= X(xf)) {
  281                 t->y = Y(yt), t->x += -xf + xt;
  282             }
  283         }
  284         if (!w) last_tag_to_move = t;
  285     }
  286 }
  287 
  288 static inline void copy_chars(struct part *p, int x, int y, int xl, chr *d)
  289 {
  290     if (xl <= 0) return;
  291     xpand_lines(p, y);
  292     xpand_line(p, y, x+xl-1);
  293     for (; xl; xl--, x++, d++) POS(x, y) = *d;
  294 }
  295 
  296 static inline void move_chars(struct part *p, int x, int y, int nx, int ny)
  297 {
  298     if (LEN(y) - x <= 0) return;
  299     copy_chars(p, nx, ny, LEN(y) - x, &POS(x, y));
  300     SLEN(y, x);
  301     move_links(p, x, y, nx, ny);
  302 }
  303 
  304 static inline void shift_chars(struct part *p, int y, int s)
  305 {
  306     chr *a;
  307     int l = LEN(y);
  308     if ((unsigned)l > MAXINT / sizeof(chr)) overalloc();
  309     a = mem_alloc(l * sizeof(chr));
  310     memcpy(a, &POS(0, y), l * sizeof(chr));
  311     set_hchars(p, 0, y, s, (p->data->data[y].c << 11) | ' ');
  312     copy_chars(p, s, y, l, a);
  313     mem_free(a);
  314     move_links(p, 0, y, s, y);
  315 }
  316 
  317 static inline void del_chars(struct part *p, int x, int y)
  318 {
  319     SLEN(y, x);
  320     move_links(p, x, y, -1, -1);
  321 }
  322 
  323 #define rm(x) ((x).width - (x).rightmargin > 0 ? (x).width - (x).rightmargin : 0)
  324 
  325 void line_break(struct part *);
  326 
  327 int split_line(struct part *p)
  328 {
  329     int i;
  330     for (i = rm(par_format); i >= par_format.leftmargin; i--)
  331         if (i < p->spl && p->spaces[i]) goto split;
  332     for (i = par_format.leftmargin; i < p->cx ; i++)
  333         if (i < p->spl && p->spaces[i]) goto split;
  334     if (p->cx + par_format.rightmargin > p->x) p->x = p->cx + par_format.rightmargin;
  335     return 0;
  336     split:
  337     if (i + par_format.rightmargin > p->x) p->x = i + par_format.rightmargin;
  338     if (p->data) {
  339 #ifdef DEBUG
  340         if ((POS(i, p->cy) & 0xff) != ' ') internal("bad split: %c", (char)POS(i, p->cy));
  341 #endif
  342         move_chars(p, i+1, p->cy, par_format.leftmargin, p->cy+1);
  343         del_chars(p, i, p->cy);
  344     }
  345     memmove(p->spaces, p->spaces + i + 1, p->spl - i - 1);
  346     memset(p->spaces + p->spl - i - 1, 0, i + 1);
  347     memmove(p->spaces + par_format.leftmargin, p->spaces, p->spl - par_format.leftmargin);
  348     p->cy++; p->cx -= i - par_format.leftmargin + 1;
  349     if (p->cx == par_format.leftmargin) p->cx = -1;
  350     if (p->y < p->cy + (p->cx != -1)) p->y = p->cy + (p->cx != -1);
  351     return 1 + (p->cx == -1);
  352 }
  353 
  354 void align_line(struct part *p, int y)
  355 {
  356     int na;
  357     if (!p->data) return;
  358     if (!LEN(y) || par_format.align == AL_LEFT || par_format.align == AL_NO || par_format.align == AL_BLOCK /* !!! fixme! */) return;
  359     na = rm(par_format) - LEN(y);
  360     if (par_format.align == AL_CENTER) na /= 2;
  361     if (na > 0) shift_chars(p, y, na);
  362 }
  363 
  364 struct link *new_link(struct f_data *f)
  365 {
  366     if (!f) return NULL;
  367     if (!(f->nlinks & (ALLOC_GR - 1))) {
  368         if ((unsigned)f->nlinks > MAXINT / sizeof(struct link) - ALLOC_GR) overalloc();
  369         f->links = mem_realloc(f->links, (f->nlinks + ALLOC_GR) * sizeof(struct link));
  370     }
  371     memset(&f->links[f->nlinks], 0, sizeof(struct link));
  372     return &f->links[f->nlinks++];
  373 }
  374 
  375 void html_tag(struct f_data *f, unsigned char *t, int x, int y)
  376 {
  377     struct tag *tag;
  378     unsigned char *tt;
  379     int ll;
  380     if (!f) return;
  381     tt = init_str();
  382     ll = 0;
  383     add_conv_str(&tt, &ll, t, strlen(t), -2);
  384     tag = mem_alloc(sizeof(struct tag) + strlen(tt) + 1);
  385     tag->x = x;
  386     tag->y = y;
  387     strcpy(tag->name, tt);
  388     add_to_list(f->tags, tag);
  389     if ((void *)last_tag_for_newline == &f->tags) last_tag_for_newline = tag;
  390     mem_free(tt);
  391 }
  392 
  393 unsigned char *last_link;
  394 unsigned char *last_target;
  395 unsigned char *last_image;
  396 struct form_control *last_form;
  397 
  398 int nobreak;
  399 
  400 struct conv_table *convert_table;
  401 
  402 void put_chars(struct part *, unsigned char *, int);
  403 
  404 #define CH_BUF  256
  405 
  406 int put_chars_conv(struct part *p, unsigned char *c, int l)
  407 {
  408     static char buffer[CH_BUF];
  409     int bp = 0;
  410     int pp = 0;
  411     int total = 0;
  412     if (format_.attr & AT_GRAPHICS) {
  413         put_chars(p, c, l);
  414         return l;
  415     }
  416     if (!l) put_chars(p, NULL, 0);
  417     while (pp < l) {
  418         unsigned char *e;
  419         if (c[pp] < 128 && c[pp] != '&') {
  420             put_c:
  421             buffer[bp++] = c[pp++];
  422             if (bp < CH_BUF) continue;
  423             goto flush;
  424         }
  425         if (c[pp] != '&') {
  426             struct conv_table *t;
  427             int i;
  428             if (!convert_table) goto put_c;
  429             t = convert_table;
  430             i = pp;
  431             decode:
  432             if (!t[c[i]].t) {
  433                 e = t[c[i]].u.str;
  434             } else {
  435                 t = t[c[i++]].u.tbl;
  436                 if (i >= l) goto put_c;
  437                 goto decode;
  438             }
  439             pp = i + 1;
  440         } else {
  441             int i = pp + 1;
  442             if (d_opt->plain) goto put_c;
  443             while (i < l && c[i] != ';' && c[i] != '&' && c[i] > ' ') i++;
  444             if (!(e = get_entity_string(&c[pp + 1], i - pp - 1, d_opt->cp))) goto put_c;
  445             pp = i + (i < l && c[i] == ';');
  446         }
  447         if (!e[0]) continue;
  448         if (!e[1]) {
  449             buffer[bp++] = e[0];
  450             if (bp < CH_BUF) continue;
  451             flush:
  452             e = "";
  453             goto flush1;
  454         }
  455         while (*e) {
  456             buffer[bp++] = *(e++);
  457             if (bp < CH_BUF) continue;
  458             flush1:
  459             put_chars(p, buffer, bp);
  460             total += bp;
  461             bp = 0;
  462         }
  463     }
  464     if (bp) put_chars(p, buffer, bp);
  465     total += bp;
  466     return total;
  467 }
  468 
  469 void put_chars(struct part *p, unsigned char *c, int l)
  470 {
  471     static struct text_attrib_beginning ta_cache = { -1, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } };
  472     static int bg_cache;
  473     static int fg_cache;
  474 
  475     int bg, fg;
  476     int i;
  477     struct link *link;
  478     struct point *pt;
  479     if (l < 0) overalloc();
  480     /*printf("%d-", p->cx);for (i=0; i<l; i++) printf("%c", c[i]); printf("-\n");sleep(1);*/
  481     while (par_format.align != AL_NO && p->cx == -1 && l && *c == ' ') c++, l--;
  482     if (!l) return;
  483     if (c[0] != ' ' || (c[1] && c[1] != ' ')) {
  484         last_tag_for_newline = (void *)&p->data->tags;
  485     }
  486     if (p->cx < par_format.leftmargin) p->cx = par_format.leftmargin;
  487     if (last_link || last_image || last_form || format_.link || format_.image || format_.form) goto process_link;
  488     no_l:
  489     /*printf("%d %d\n",p->cx, p->cy);*/
  490     if (memcmp(&ta_cache, &format_, sizeof(struct text_attrib_beginning))) goto format_change;
  491     bg = bg_cache, fg = fg_cache;
  492     end_format_change:
  493     if (p->cx == par_format.leftmargin && *c == ' ' && par_format.align != AL_NO) c++, l--;
  494     if (p->y < p->cy + 1) p->y = p->cy + 1;
  495     if (nowrap && p->cx + l > rm(par_format)) return;
  496     set_hline(p, p->cx, p->cy, l, c, (((fg&0x08)<<3)|(bg<<3)|(fg&0x07))<<8, par_format.align != AL_NO);
  497     p->cx += l;
  498     nobreak = 0;
  499     if (par_format.align != AL_NO)
  500         while (p->cx > rm(par_format) && p->cx > par_format.leftmargin) {
  501             int x;
  502             /*if (p->cx > p->x) {
  503                 p->x = p->cx + par_format.rightmargin;
  504                 if (c[l - 1] == ' ') p->x--;
  505             }*/
  506             if (!(x = split_line(p))) break;
  507             /*if (LEN(p->cy-1) > p->x) p->x = LEN(p->cy-1);*/
  508             align_line(p, p->cy - 1);
  509             nobreak = x - 1;
  510         }
  511     if ((p->xa += l) - (c[l-1] == ' ' && par_format.align != AL_NO) + par_format.leftmargin + par_format.rightmargin > p->xmax) p->xmax = p->xa - (c[l-1] == ' ' && par_format.align != AL_NO) + par_format.leftmargin + par_format.rightmargin;
  512     return;
  513     process_link:
  514     if ((last_link /*|| last_target*/ || last_image || last_form) &&
  515         !xstrcmp(format_.link, last_link) && !xstrcmp(format_.target, last_target) &&
  516         !xstrcmp(format_.image, last_image) && format_.form == last_form) {
  517         if (!p->data) goto x;
  518         link = &p->data->links[p->data->nlinks - 1];
  519         if (!p->data->nlinks) {
  520             internal("no link");
  521             goto no_l;
  522         }
  523         goto set_link;
  524         x:;
  525     } else {
  526         if (last_link) mem_free(last_link); /* !!! FIXME: optimize */
  527         if (last_target) mem_free(last_target);
  528         if (last_image) mem_free(last_image);
  529         last_link = last_target = last_image = NULL;
  530         last_form = NULL;
  531         if (!(format_.link || format_.image || format_.form)) goto no_l;
  532         if (d_opt->num_links) {
  533             unsigned char s[64];
  534             unsigned char *fl = format_.link, *ft = format_.target, *fi = format_.image;
  535             struct form_control *ff = format_.form;
  536             format_.link = format_.target = format_.image = NULL;
  537             format_.form = NULL;
  538             s[0] = '[';
  539             snzprint(s + 1, 62, p->link_num);
  540             strcat(s, "]");
  541             put_chars(p, s, strlen(s));
  542             if (ff && ff->type == FC_TEXTAREA) line_break(p);
  543             if (p->cx == -1) p->cx = par_format.leftmargin;
  544             format_.link = fl, format_.target = ft, format_.image = fi;
  545             format_.form = ff;
  546         }
  547         p->link_num++;
  548         last_link = stracpy(format_.link);
  549         last_target = stracpy(format_.target);
  550         last_image = stracpy(format_.image);
  551         last_form = format_.form;
  552         if (!p->data) goto no_l;
  553         if (!(link = new_link(p->data))) goto no_l;
  554         link->num = p->link_num - 1;
  555         link->pos = DUMMY;
  556         if (!last_form) {
  557             link->type = L_LINK;
  558             link->where = stracpy(last_link);
  559             link->target = stracpy(last_target);
  560         } else {
  561             link->type = last_form->type == FC_TEXT || last_form->type == FC_PASSWORD || last_form->type == FC_FILE ? L_FIELD : last_form->type == FC_TEXTAREA ? L_AREA : last_form->type == FC_CHECKBOX || last_form->type == FC_RADIO ? L_CHECKBOX : last_form->type == FC_SELECT ? L_SELECT : L_BUTTON;
  562             link->form = last_form;
  563             link->target = stracpy(last_form->target);
  564         }
  565         link->where_img = stracpy(last_image);
  566         if (link->type != L_FIELD && link->type != L_AREA) {
  567             bg = find_nearest_color(&format_.clink, 8);
  568             fg = find_nearest_color(&format_.bg, 8);
  569             fg = fg_color(fg, bg);
  570         } else {
  571             fg = find_nearest_color(&format_.fg, 8);
  572             bg = find_nearest_color(&format_.bg, 8);
  573             fg = fg_color(fg, bg);
  574         }
  575         link->sel_color = ((fg & 8) << 3) | (fg & 7) | (bg << 3);
  576         link->n = 0;
  577         set_link:
  578         if ((unsigned)link->n + (unsigned)l > MAXINT / sizeof(struct point)) overalloc();
  579         pt = mem_realloc(link->pos, (link->n + l) * sizeof(struct point));
  580         link->pos = pt;
  581         for (i = 0; i < l; i++) pt[link->n + i].x = X(p->cx) + i,
  582                     pt[link->n + i].y = Y(p->cy);
  583         link->n += l;
  584     }
  585     goto no_l;
  586 
  587         format_change:
  588         bg = find_nearest_color(&format_.bg, 8);
  589         fg = find_nearest_color(&format_.fg, 16);
  590         fg = fg_color(fg, bg);
  591         if (format_.attr & AT_ITALIC) fg = fg ^ 0x01;
  592         if (format_.attr & AT_UNDERLINE) fg = (fg ^ 0x04) | 0x08;
  593         if (format_.attr & AT_BOLD) fg = fg | 0x08;
  594         fg = fg_color(fg, bg);
  595         if (format_.attr & AT_GRAPHICS) bg = bg | 0x10;
  596         memcpy(&ta_cache, &format_, sizeof(struct text_attrib_beginning));
  597         fg_cache = fg; bg_cache = bg;
  598         goto end_format_change;
  599 }
  600 
  601 void line_break(struct part *p)
  602 {
  603     struct tag *t;
  604     /*printf("-break-\n");*/
  605     if (p->cx + par_format.rightmargin > p->x) p->x = p->cx + par_format.rightmargin;
  606     if (nobreak) {
  607         /*if (p->y < p->cy) p->y = p->cy;*/
  608         nobreak = 0;
  609         p->cx = -1;
  610         p->xa = 0;
  611         return;
  612     }
  613     if (!p->data) goto e;
  614     /*move_links(p, p->cx, p->cy, 0, p->cy + 1);*/
  615     xpand_lines(p, p->cy + 1);
  616     if (p->cx > par_format.leftmargin && LEN(p->cy) > p->cx - 1 && (POS(p->cx-1, p->cy) & 0xff) == ' ') del_chars(p, p->cx-1, p->cy), p->cx--;
  617     /*if (LEN(p->cy) > p->x) p->x = LEN(p->cy);*/
  618     if (p->cx > 0) align_line(p, p->cy);
  619     if (p->data) for (t = last_tag_for_newline; t && (void *)t != &p->data->tags; t = t->prev) {
  620         t->x = X(0);
  621         t->y = Y(p->cy + 1);
  622     }
  623     e:
  624     p->cy++; p->cx = -1; p->xa = 0; /*if (p->y < p->cy) p->y = p->cy;*/
  625     if (p->spl > d_opt->xw) p->spl = d_opt->xw;
  626     memset(p->spaces, 0, p->spl);
  627 }
  628 
  629 int g_ctrl_num;
  630 
  631 void html_form_control(struct part *p, struct form_control *fc)
  632 {
  633     if (!p->data) {
  634         /*destroy_fc(fc);
  635         mem_free(fc);*/
  636         add_to_list(p->uf, fc);
  637         return;
  638     }
  639     fc->g_ctrl_num = g_ctrl_num++;
  640     if (fc->type == FC_TEXT || fc->type == FC_PASSWORD || fc->type == FC_TEXTAREA) {
  641         unsigned char *dv = convert_string(convert_table, fc->default_value, strlen(fc->default_value));
  642         if (dv) {
  643             mem_free(fc->default_value);
  644             fc->default_value = dv;
  645         }
  646         /*
  647         for (i = 0; i < fc->nvalues; i++) if ((dv = convert_string(convert_table, fc->values[i], strlen(fc->values[i])))) {
  648             mem_free(fc->values[i]);
  649             fc->values[i] = dv;
  650         }
  651         */
  652     }
  653     if (fc->type == FC_TEXTAREA) {
  654         unsigned char *p;
  655         for (p = fc->default_value; p[0]; p++) if (p[0] == '\r') {
  656             if (p[1] == '\n') memmove(p, p + 1, strlen(p)), p--;
  657             else p[0] = '\n';
  658         }
  659     }
  660     add_to_list(p->data->forms, fc);
  661 }
  662 
  663 void add_frameset_entry(struct frameset_desc *fsd, struct frameset_desc *subframe, unsigned char *name, unsigned char *url)
  664 {
  665     if (fsd->yp >= fsd->y) return;
  666     fsd->f[fsd->xp + fsd->yp * fsd->x].subframe = subframe;
  667     fsd->f[fsd->xp + fsd->yp * fsd->x].name = stracpy(name);
  668     fsd->f[fsd->xp + fsd->yp * fsd->x].url = stracpy(url);
  669     if (++fsd->xp >= fsd->x) fsd->xp = 0, fsd->yp++;
  670 }
  671 
  672 struct frameset_desc *create_frameset(struct f_data *fda, struct frameset_param *fp)
  673 {
  674     int i;
  675     struct frameset_desc *fd;
  676     if (!fp->x || !fp->y) {
  677         internal("zero size of frameset");
  678         return NULL;
  679     }
  680     if (fp->x && (unsigned)fp->x * (unsigned)fp->y / (unsigned)fp->x != (unsigned)fp->y) overalloc();
  681     if ((unsigned)fp->x * (unsigned)fp->y > (MAXINT - sizeof(struct frameset_desc)) / sizeof(struct frame_desc)) overalloc();
  682     fd = mem_alloc(sizeof(struct frameset_desc) + fp->x * fp->y * sizeof(struct frame_desc));
  683     memset(fd, 0, sizeof(struct frameset_desc) + fp->x * fp->y * sizeof(struct frame_desc));
  684     fd->n = fp->x * fp->y;
  685     fd->x = fp->x;
  686     fd->y = fp->y;
  687     for (i = 0; i < fd->n; i++) {
  688         fd->f[i].xw = fp->xw[i % fp->x];
  689         fd->f[i].yw = fp->yw[i / fp->x];
  690     }
  691     if (fp->parent) add_frameset_entry(fp->parent, fd, NULL, NULL);
  692     else if (!fda->frame_desc) fda->frame_desc = fd;
  693          else mem_free(fd), fd = NULL;
  694     return fd;
  695 }
  696 
  697 void create_frame(struct frame_param *fp)
  698 {
  699     add_frameset_entry(fp->parent, NULL, fp->name, fp->url);
  700 }
  701 
  702 void *html_special(struct part *p, int c, ...)
  703 {
  704     va_list l;
  705     unsigned char *t;
  706     struct form_control *fc;
  707     struct frameset_param *fsp;
  708     struct frame_param *fp;
  709     va_start(l, c);
  710     switch (c) {
  711         case SP_TAG:
  712             t = va_arg(l, unsigned char *);
  713             va_end(l);
  714             html_tag(p->data, t, X(p->cx), Y(p->cy));
  715             break;
  716         case SP_CONTROL:
  717             fc = va_arg(l, struct form_control *);
  718             va_end(l);
  719             html_form_control(p, fc);
  720             break;
  721         case SP_TABLE:
  722             va_end(l);
  723             return convert_table;
  724         case SP_USED:
  725             va_end(l);
  726             return (void *)(my_uintptr_t)!!p->data;
  727         case SP_FRAMESET:
  728             fsp = va_arg(l, struct frameset_param *);
  729             va_end(l);
  730             return create_frameset(p->data, fsp);
  731         case SP_FRAME:
  732             fp = va_arg(l, struct frame_param *);
  733             va_end(l);
  734             create_frame(fp);
  735             break;
  736         case SP_NOWRAP:
  737             nowrap = va_arg(l, int);
  738             va_end(l);
  739             break;
  740         default:
  741             internal("html_special: unknown code %d", c);
  742             va_end(l);
  743     }
  744     return NULL;
  745 }
  746 
  747 void do_format(char *start, char *end, struct part *part, unsigned char *head)
  748 {
  749     parse_html(start, end, (int (*)(void *, unsigned char *, int)) put_chars_conv, (void (*)(void *)) line_break, (void *(*)(void *, int, ...)) html_special, part, head);
  750     /*if ((part->y -= line_breax) < 0) part->y = 0;*/
  751 }
  752 
  753 int margin;
  754 
  755 struct table_cache_entry {
  756     struct table_cache_entry *next;
  757     struct table_cache_entry *prev;
  758     struct table_cache_entry *hash_next;
  759     unsigned char *start;
  760     unsigned char *end;
  761     int align;
  762     int m;
  763     int width;
  764     int xs;
  765     int link_num;
  766     struct part p;
  767 };
  768 
  769 struct list_head table_cache = { &table_cache, &table_cache };
  770 
  771 #define TC_HASH_SIZE    4096
  772 
  773 struct table_cache_entry *table_cache_hash[TC_HASH_SIZE];
  774 
  775 void free_table_cache()
  776 {
  777     struct table_cache_entry *tce;
  778     foreach(tce, table_cache) {
  779         int hash = ((int)(unsigned long)tce->start + tce->xs) & (TC_HASH_SIZE - 1);
  780         table_cache_hash[hash] = NULL;
  781     }
  782     free_list(table_cache);
  783 }
  784 
  785 struct part *format_html_part(unsigned char *start, unsigned char *end, int align, int m, int width, struct f_data *data, int xs, int ys, unsigned char *head, int link_num)
  786 {
  787     struct part *p;
  788     struct html_element *e;
  789     int llm = last_link_to_move;
  790     struct tag *ltm = last_tag_to_move;
  791     /*struct tag *ltn = last_tag_for_newline;*/
  792     int lm = margin;
  793     int ef = empty_format;
  794     struct form_control *fc;
  795     struct table_cache_entry *tce;
  796     if (!data) {
  797         tce = table_cache_hash[((int)(unsigned long)start + xs) & (TC_HASH_SIZE - 1)];
  798         while (tce) {
  799             if (tce->start == start && tce->end == end && tce->align == align && tce->m == m && tce->width == width && tce->xs == xs && tce->link_num == link_num) {
  800                 p = mem_alloc(sizeof(struct part));
  801                 memcpy(p, &tce->p, sizeof(struct part));
  802                 return p;
  803             }
  804             tce = tce->hash_next;
  805         }
  806     }
  807     if (ys < 0) {
  808         internal("format_html_part: ys == %d", ys);
  809         return NULL;
  810     }
  811     if (data) {
  812         struct node *n;
  813         n = mem_alloc(sizeof(struct node));
  814         n->x = xs;
  815         n->y = ys;
  816         n->xw = !table_level ? MAXINT : width;
  817         add_to_list(data->nodes, n);
  818         /*sdbg(data);*/
  819     }
  820     last_link_to_move = data ? data->nlinks : 0;
  821     last_tag_to_move = data ? (void *)&data->tags : NULL;
  822     last_tag_for_newline = data ? (void *)&data->tags: NULL;
  823     margin = m;
  824     empty_format = !data;
  825     if (last_link) mem_free(last_link);
  826     if (last_image) mem_free(last_image);
  827     if (last_target) mem_free(last_target);
  828     last_link = last_image = last_target = NULL;
  829     last_form = NULL;
  830     nobreak = 1;
  831     p = mem_alloc(sizeof(struct part));
  832     p->x = p->y = 0;
  833     p->data = data;
  834     p->xp = xs; p->yp = ys;
  835     p->xmax = p->xa = 0;
  836     p->bgcolor = find_nearest_color(&par_format.bgcolor, 8);
  837     p->spaces = DUMMY;
  838     p->spl = 0;
  839     p->link_num = link_num;
  840     init_list(p->uf);
  841     html_stack_dup();
  842     e = &html_top;
  843     html_top.dontkill = 2;
  844     html_top.namelen = 0;
  845     par_format.align = align;
  846     par_format.leftmargin = m;
  847     par_format.rightmargin = m;
  848     par_format.width = width;
  849     par_format.list_level = 0;
  850     par_format.list_number = 0;
  851     par_format.dd_margin = 0;
  852     p->cx = -1;
  853     p->cy = 0;
  854     do_format(start, end, p, head);
  855     if (p->xmax < p->x) p->xmax = p->x;
  856     nobreak = 0;
  857     line_breax = 1;
  858     if (last_link) mem_free(last_link);
  859     if (last_image) mem_free(last_image);
  860     if (last_target) mem_free(last_target);
  861     while (&html_top != e) {
  862         kill_html_stack_item(&html_top);
  863         if (!&html_top || (void *)&html_top == (void *)&html_stack) {
  864             internal("html stack trashed");
  865             break;
  866         }
  867     }
  868     html_top.dontkill = 0;
  869     kill_html_stack_item(&html_top);
  870     mem_free(p->spaces);
  871     if (data) {
  872         struct node *n = data->nodes.next;
  873         n->yw = ys - n->y + p->y;
  874     }
  875     foreach(fc, p->uf) destroy_fc(fc);
  876     free_list(p->uf);
  877     last_link_to_move = llm;
  878     last_tag_to_move = ltm;
  879     /*last_tag_for_newline = ltn;*/
  880     margin = lm;
  881     empty_format = ef;
  882     last_link = last_image = last_target = NULL;
  883     last_form = NULL;
  884     if (table_level > 1 && !data) {
  885         int hash;
  886         tce = mem_alloc(sizeof(struct table_cache_entry));
  887         tce->start = start;
  888         tce->end = end;
  889         tce->align = align;
  890         tce->m = m;
  891         tce->width = width;
  892         tce->xs = xs;
  893         tce->link_num = link_num;
  894         memcpy(&tce->p, p, sizeof(struct part));
  895         add_to_list(table_cache, tce);
  896         hash = ((int)(unsigned long)start + xs) & (TC_HASH_SIZE - 1);
  897         tce->hash_next = table_cache_hash[hash];
  898         table_cache_hash[hash] = tce;
  899     }
  900     return p;
  901 }
  902 
  903 void push_base_format(unsigned char *url, struct document_options *opt)
  904 {
  905     struct html_element *e;
  906     if (html_stack.next != &html_stack) {
  907         internal("something on html stack");
  908         init_list(html_stack);
  909     }
  910     e = mem_alloc(sizeof(struct html_element));
  911     memset(e, 0, sizeof(struct html_element));
  912     add_to_list(html_stack, e);
  913     format_.attr = 0;
  914     format_.fontsize = 3;
  915     format_.link = format_.target = format_.image = format_.select = NULL;
  916     format_.form = NULL;
  917     memcpy(&format_.fg, &opt->default_fg, sizeof(struct rgb));
  918     memcpy(&format_.bg, &opt->default_bg, sizeof(struct rgb));
  919     memcpy(&format_.clink, &opt->default_link, sizeof(struct rgb));
  920     memcpy(&format_.vlink, &opt->default_vlink, sizeof(struct rgb));
  921     format_.href_base = stracpy(url);
  922     format_.target_base = stracpy(opt->framename);
  923     par_format.align = opt->plain ? AL_NO : AL_LEFT;
  924     par_format.leftmargin = opt->plain ? 0 : opt->margin;
  925     par_format.rightmargin = opt->plain ? 0 : opt->margin;
  926     par_format.width = opt->xw;
  927     par_format.list_level = par_format.list_number = 0;
  928     par_format.dd_margin = opt->margin;
  929     par_format.flags = 0;
  930     memcpy(&par_format.bgcolor, &opt->default_bg, sizeof(struct rgb));
  931     html_top.invisible = 0;
  932     html_top.name = NULL; html_top.namelen = 0; html_top.options = NULL;
  933     html_top.linebreak = 1;
  934     html_top.dontkill = 1;
  935 }
  936 
  937 struct conv_table *get_convert_table(unsigned char *head, int to, int def, int *frm, int *aa, int hard)
  938 {
  939     int from = -1;
  940     unsigned char *a, *b;
  941     unsigned char *p = head;
  942     while (from == -1 && p && (a = parse_http_header(p, "Content-Type", &p))) {
  943         if ((b = parse_header_param(a, "charset"))) {
  944             from = get_cp_index(b);
  945             mem_free(b);
  946         }
  947         mem_free(a);
  948     }
  949     if (from == -1 && head && (a = parse_http_header(head, "Content-Charset", NULL))) {
  950         from = get_cp_index(a);
  951         mem_free(a);
  952     }
  953     if (from == -1 && head && (a = parse_http_header(head, "Charset", NULL))) {
  954         from = get_cp_index(a);
  955         mem_free(a);
  956     }
  957     if (aa) {
  958         *aa = from == -1;
  959         if (hard && !*aa) *aa = 2;
  960     }
  961     if (hard || from == -1) from = def;
  962     if (frm) *frm = from;
  963     return get_translation_table(from, to);
  964 }
  965 
  966 struct document_options *d_opt;
  967 
  968 void format_html(struct cache_entry *ce, struct f_data *screen)
  969 {
  970     unsigned char *url = ce->url;
  971     struct fragment *fr;
  972     struct part *rp;
  973     unsigned char *start, *end;
  974     unsigned char *head, *t;
  975     int hdl;
  976     int i;
  977     memset(table_cache_hash, 0, sizeof(table_cache_hash));
  978     d_opt = &screen->opt;
  979     screen->use_tag = ce->count;
  980     defrag_entry(ce);
  981     fr = ce->frag.next;
  982     if ((void *)fr == &ce->frag || fr->offset || !fr->length) start = NULL, end = NULL;
  983     else start = fr->data, end = fr->data + fr->length;
  984     startf = start;
  985     eofff = end;
  986     head = init_str(), hdl = 0;
  987     if (ce->head) add_to_str(&head, &hdl, ce->head);
  988     scan_http_equiv(start, end, &head, &hdl, &t);
  989     convert_table = get_convert_table(head, screen->opt.cp, screen->opt.assume_cp, &screen->cp, &screen->ass, screen->opt.hard_assume);
  990     screen->opt.real_cp = screen->cp;
  991     i = d_opt->plain; d_opt->plain = 0;
  992     screen->title = convert_string(convert_table, t, strlen(t));
  993     d_opt->plain = i;
  994     mem_free(t);
  995     push_base_format(url, &screen->opt);
  996     table_level = 0;
  997     g_ctrl_num = 0;
  998     last_form_tag = NULL;
  999     last_form_attr = NULL;
 1000     last_input_tag = NULL;
 1001     if ((rp = format_html_part(start, end, par_format.align, par_format.leftmargin, screen->opt.xw, screen, 0, 0, head, 1))) mem_free(rp);
 1002     mem_free(head);
 1003     screen->x = 0;
 1004     for (i = screen->y - 1; i >= 0; i--) {
 1005         if (!screen->data[i].l) mem_free(screen->data[i].d), screen->y--;
 1006         else break;
 1007     }
 1008     for (i = 0; i < screen->y; i++) if (screen->data[i].l > screen->x) screen->x = screen->data[i].l;
 1009     if (form.action) mem_free(form.action), form.action = NULL;
 1010     if (form.target) mem_free(form.target), form.target = NULL;
 1011     kill_html_stack_item(html_stack.next);
 1012     if (html_stack.next != &html_stack) {
 1013         internal("html stack not empty after operation");
 1014         init_list(html_stack);
 1015     }
 1016     screen->bg = 007 << 8; /* !!! FIXME */
 1017     sort_links(screen);
 1018     if (screen->frame_desc) screen->frame = 1;
 1019     /*{
 1020         FILE *f = fopen("forms", "a");
 1021         struct form_control *form;
 1022         unsigned char *qq;
 1023         fprintf(f,"FORM:\n");
 1024         foreach(form, screen->forms) fprintf(f, "g=%d f=%d c=%d t:%d\n", form->g_ctrl_num, form->form_num, form->ctrl_num, form->type);
 1025         fprintf(f,"fragment: \n");
 1026         for (qq = start; qq < end; qq++) fprintf(f, "%c", *qq);
 1027         fprintf(f,"----------\n\n");
 1028         fclose(f);
 1029     }*/
 1030 }
 1031 
 1032 static inline int compare_opt(struct document_options *o1, struct document_options *o2)
 1033 {
 1034     if (o1->xw == o2->xw &&
 1035         o1->yw == o2->yw &&
 1036         o1->xp == o2->xp &&
 1037         o1->yp == o2->yp &&
 1038         o1->col == o2->col &&
 1039         o1->cp == o2->cp &&
 1040         o1->assume_cp == o2->assume_cp &&
 1041         o1->hard_assume == o2->hard_assume &&
 1042         o1->tables == o2->tables &&
 1043         o1->frames == o2->frames &&
 1044         o1->images == o2->images &&
 1045         o1->margin == o2->margin &&
 1046         o1->plain == o2->plain &&
 1047         !memcmp(&o1->default_fg, &o2->default_fg, sizeof(struct rgb)) &&
 1048         !memcmp(&o1->default_bg, &o2->default_bg, sizeof(struct rgb)) &&
 1049         !memcmp(&o1->default_link, &o2->default_link, sizeof(struct rgb)) &&
 1050         !memcmp(&o1->default_vlink, &o2->default_vlink, sizeof(struct rgb)) &&
 1051         o1->num_links == o2->num_links &&
 1052         o1->table_order == o2->table_order &&
 1053         !strcasecmp(o1->framename, o2->framename)) return 0;
 1054     return 1;
 1055 }
 1056 
 1057 static inline void copy_opt(struct document_options *o1, struct document_options *o2)
 1058 {
 1059     memcpy(o1, o2, sizeof(struct document_options));
 1060     o1->framename = stracpy(o2->framename);
 1061 }
 1062 
 1063 struct list_head format_cache = {&format_cache, &format_cache};
 1064 int format_cache_entries = 0;
 1065 
 1066 void shrink_format_cache(int u)
 1067 {
 1068     struct f_data *ce;
 1069     delete_unused_format_cache_entries();
 1070     if (format_cache_entries < 0) {
 1071         internal("format_cache_entries underflow");
 1072         format_cache_entries = 0;
 1073     }
 1074     ce = format_cache.prev;
 1075     while ((u || format_cache_entries > max_format_cache_entries) && (void *)ce != &format_cache) {
 1076         if (ce->refcount) {
 1077             ce = ce->prev;
 1078             continue;
 1079         }
 1080         ce = ce->prev;
 1081         destroy_formatted(ce->next);
 1082         format_cache_entries--;
 1083     }
 1084 }
 1085 
 1086 void count_format_cache()
 1087 {
 1088     struct f_data *ce;
 1089     format_cache_entries = 0;
 1090     foreach(ce, format_cache) if (!ce->refcount) format_cache_entries++;
 1091 }
 1092 
 1093 void delete_unused_format_cache_entries()
 1094 {
 1095     struct f_data *ce;
 1096     foreach(ce, format_cache) {
 1097         struct cache_entry *cee;
 1098         if (find_in_cache(ce->url, &cee))
 1099             internal("file %s disappeared from cache", ce->url);
 1100         cee->refcount--;
 1101         if (!ce->refcount && cee->count != ce->use_tag) {
 1102             ce = ce->prev;
 1103             destroy_formatted(ce->next);
 1104             format_cache_entries--;
 1105         }
 1106     }
 1107 }
 1108 
 1109 void format_cache_reactivate(struct f_data *ce)
 1110 {
 1111     del_from_list(ce);
 1112     add_to_list(format_cache, ce);
 1113 }
 1114 
 1115 void cached_format_html(struct view_state *vs, struct f_data_c *screen, struct document_options *opt)
 1116 {
 1117     unsigned char *n;
 1118     struct f_data *ce;
 1119     struct cache_entry *cee;
 1120     if (!vs) return;
 1121     n = screen->name; screen->name = NULL;
 1122     detach_formatted(screen);
 1123     screen->name = n;
 1124     screen->link_bg = NULL;
 1125     screen->link_bg_n = 0;
 1126     screen->vs = vs;
 1127     screen->xl = screen->yl = -1;
 1128     screen->f_data = NULL;
 1129     foreach(ce, format_cache) if (!strcmp(ce->url, vs->url) && !compare_opt(&ce->opt, opt)) {
 1130         cee = NULL;
 1131         if (find_in_cache(ce->url, &cee))
 1132             internal("file %s disappeared from cache", ce->url);
 1133         cee->refcount--;
 1134         if (cee->count != ce->use_tag) {
 1135             if (!ce->refcount) {
 1136                 ce = ce->prev;
 1137                 destroy_formatted(ce->next);
 1138                 format_cache_entries--;
 1139             }
 1140             continue;
 1141         }
 1142         format_cache_reactivate(ce);
 1143         if (!ce->refcount++) format_cache_entries--;
 1144         screen->f_data = ce;
 1145         goto sx;
 1146     }
 1147     if (find_in_cache(vs->url, &cee)) {
 1148         internal("document to format not found");
 1149         return;
 1150     }
 1151     /*cee->refcount++;*/
 1152     shrink_memory(0);
 1153     ce = mem_alloc(SIZEOF_F_DATA);
 1154     init_formatted(ce);
 1155     ce->refcount = 1;
 1156     ce->url = stracpy(vs->url);
 1157     copy_opt(&ce->opt, opt);
 1158     add_to_list(format_cache, ce);
 1159     screen->f_data = ce;
 1160     ce->time_to_get = -(uttime)get_time();
 1161     format_html(cee, ce);
 1162     ce->time_to_get += (uttime)get_time();
 1163     sx:
 1164     screen->xw = ce->opt.xw;
 1165     screen->yw = ce->opt.yw;
 1166     screen->xp = ce->opt.xp;
 1167     screen->yp = ce->opt.yp;
 1168 }
 1169 
 1170 unsigned long formatted_info(int type)
 1171 {
 1172     int i = 0;
 1173     struct f_data *ce;
 1174     switch (type) {
 1175         case CI_FILES:
 1176             foreach(ce, format_cache) i++;
 1177             return i;
 1178         case CI_LOCKED:
 1179             foreach(ce, format_cache) i += !!ce->refcount;
 1180             return i;
 1181         default:
 1182             internal("formatted_info: bad request");
 1183     }
 1184     return 0;
 1185 }
 1186 
 1187 void add_frame_to_list(struct session *ses, struct f_data_c *fd)
 1188 {
 1189     struct f_data_c *f, *fp;
 1190     foreach(f, ses->scrn_frames) {
 1191         if (f->yp > fd->yp || (f->yp == fd->yp && f->xp > fd->xp)) {
 1192             add_at_pos(f->prev, fd);
 1193             return;
 1194         }
 1195     }
 1196     fp = (struct f_data_c *)ses->scrn_frames.prev;
 1197     add_at_pos(fp, fd);
 1198 }
 1199 
 1200 struct f_data_c *find_fd(struct session *ses, unsigned char *name, int depth, int x, int y)
 1201 {
 1202     struct f_data_c *fd;
 1203     foreachback(fd, ses->scrn_frames) if (!strcasecmp(fd->name, name) && !fd->used) {
 1204         fd->used = 1;
 1205         fd->depth = depth;
 1206         return fd;
 1207     }
 1208     fd = mem_alloc(sizeof(struct f_data_c));
 1209     memset(fd, 0, sizeof(struct f_data_c));
 1210     fd->used = 1;
 1211     fd->name = stracpy(name);
 1212     fd->depth = depth;
 1213     fd->xp = x, fd->yp = y;
 1214     fd->search_word = &ses->search_word;
 1215     /*add_to_list(ses->scrn_frames, fd);*/
 1216     add_frame_to_list(ses, fd);
 1217     return fd;
 1218 }
 1219 
 1220 struct f_data_c *format_frame(struct session *ses, unsigned char *name, unsigned char *url, struct document_options *o, int depth)
 1221 {
 1222     struct cache_entry *ce;
 1223     struct view_state *vs;
 1224     struct f_data_c *fd;
 1225     struct frame *fr;
 1226     repeat:
 1227     if (!(fr = ses_find_frame(ses, name))) return NULL;
 1228     vs = &fr->vs;
 1229     if (find_in_cache(vs->url, &ce)) return NULL;
 1230     ce->refcount--;
 1231     if (ce->redirect && fr->redirect_cnt < MAX_REDIRECTS) {
 1232         unsigned char *u;
 1233         if ((u = join_urls(vs->url, ce->redirect))) {
 1234             fr->redirect_cnt++;
 1235             ses_change_frame_url(ses, name, u);
 1236             mem_free(u);
 1237             goto repeat;
 1238         }
 1239     }
 1240     if (!(fd = find_fd(ses, name, depth, o->xp, o->yp))) return NULL;
 1241     cached_format_html(vs, fd, o);
 1242     return fd;
 1243 }
 1244 
 1245 void format_frames(struct session *ses, struct frameset_desc *fsd, struct document_options *op, int depth)
 1246 {
 1247     int i, j, n;
 1248     struct document_options o;
 1249     if (depth > HTML_MAX_FRAME_DEPTH) return;
 1250     memcpy(&o, op, sizeof(struct document_options));
 1251     if (o.margin) o.margin = 1;
 1252     n = 0;
 1253     for (j = 0; j < fsd->y; j++) {
 1254         o.xp = op->xp;
 1255         for (i = 0; i < fsd->x; i++) {
 1256             struct f_data_c *fdc;
 1257             o.xw = fsd->f[n].xw;
 1258             o.yw = fsd->f[n].yw;
 1259             o.framename = fsd->f[n].name;
 1260             if (fsd->f[n].subframe) format_frames(ses, fsd->f[n].subframe, &o, depth + 1);
 1261             else if (fsd->f[n].name) {
 1262                 fdc = format_frame(ses, fsd->f[n].name, fsd->f[n].url, &o, depth);
 1263                 if (fdc && fdc->f_data && fdc->f_data->frame) format_frames(ses, fdc->f_data->frame_desc, &o, depth + 1);
 1264             }
 1265             o.xp += o.xw + 1;
 1266             n++;
 1267         }
 1268         o.yp += o.yw + 1;
 1269     }
 1270             
 1271     /*for (i = 0; i < fsd->n; i++) {
 1272         if (!fsd->horiz) o.xw = fsd->f[i].width;
 1273         else o.yw = fsd->f[i].width;
 1274         o.framename = fsd->f[i].name;
 1275         if (fsd->f[i].subframe) format_frames(ses, fsd->f[i].subframe, &o);
 1276         else format_frame(ses, fsd->f[i].name, fsd->f[i].url, &o);
 1277         if (!fsd->horiz) o.xp += fsd->f[i].width + 1;
 1278         else o.yp += fsd->f[i].width + 1;
 1279     }*/
 1280 }
 1281 
 1282 void html_interpret(struct session *ses)
 1283 {
 1284     struct view_state *l;
 1285     struct document_options o;
 1286     struct f_data_c *fd, *cf = NULL;
 1287     /*debug("I");*/
 1288     memset(&o, 0, sizeof(struct document_options));
 1289     if (!ses->screen) {
 1290         ses->screen = mem_alloc(sizeof(struct f_data_c));
 1291         memset(ses->screen, 0, sizeof(struct f_data_c));
 1292         ses->screen->search_word = &ses->search_word;
 1293     }
 1294     if (!list_empty(ses->history)) l = &cur_loc(ses)->vs;
 1295     else l = NULL;
 1296     o.xp = 0;
 1297     o.yp = 1;
 1298     o.xw = ses->term->x;
 1299     if (ses->term->y < 2) o.yw = 0;
 1300     else o.yw = ses->term->y - 2;
 1301     o.col = ses->term->spec->col;
 1302     o.cp = ses->term->spec->charset;
 1303     ds2do(&ses->ds, &o);
 1304     if ((o.plain = l ? l->plain : 1) == -1) o.plain = 0;
 1305     if (l) l->plain = o.plain;
 1306     memcpy(&o.default_fg, &default_fg, sizeof(struct rgb));
 1307     memcpy(&o.default_bg, &default_bg, sizeof(struct rgb));
 1308     memcpy(&o.default_link, &default_link, sizeof(struct rgb));
 1309     memcpy(&o.default_vlink, &default_vlink, sizeof(struct rgb));
 1310     o.framename = "";
 1311     foreach(fd, ses->scrn_frames) fd->used = 0;
 1312     cached_format_html(l, ses->screen, &o);
 1313     if (ses->screen->f_data && ses->screen->f_data->frame) {
 1314         cf = current_frame(ses);
 1315         format_frames(ses, ses->screen->f_data->frame_desc, &o, 0);
 1316     }
 1317     foreach(fd, ses->scrn_frames) if (!fd->used) {
 1318         struct f_data_c *fdp = fd->prev;
 1319         detach_formatted(fd);
 1320         del_from_list(fd);
 1321         mem_free(fd);
 1322         fd = fdp;
 1323     }
 1324     if (cf) {
 1325         int n = 0;
 1326         foreach(fd, ses->scrn_frames) {
 1327             if (fd->f_data && fd->f_data->frame) continue;
 1328             if (fd == cf) {
 1329                 cur_loc(ses)->vs.current_link = n;
 1330                 break;
 1331             }
 1332             n++;
 1333         }
 1334     }
 1335 }
 1336 
 1337 struct link *get_link_at_location(struct f_data *f, int x, int y)
 1338 {
 1339     struct link *l1, *l2, *l;
 1340     if (y < 0 || y >= f->y) return NULL;
 1341     l1 = f->lines1[y];
 1342     l2 = f->lines2[y];
 1343     if (!l1 || !l2) return NULL;
 1344     for (l = l1; l <= l2; l++) {
 1345         int i;
 1346         for (i = 0; i < l->n; i++) if (l->pos[i].x == x && l->pos[i].y == y) return l;
 1347     }
 1348     return NULL;
 1349 }
 1350 
 1351 void add_srch_chr(struct f_data *f, unsigned char c, int x, int y, int nn)
 1352 {
 1353     int n = f->nsearch;
 1354     if (c == ' ' && (!n || f->search[n - 1].c == ' ')) return;
 1355     if (c == '_') {
 1356         struct link *l = get_link_at_location(f, x, y);
 1357         if (l && (l->type == L_SELECT || l->type == L_FIELD || l->type == L_AREA))
 1358             return;
 1359     }
 1360     f->search[n].c = c;
 1361     f->search[n].x = x;
 1362     f->search[n].y = y;
 1363     f->search[n].n = nn;
 1364     f->nsearch++;
 1365 }
 1366 
 1367 /*void sdbg(struct f_data *f)
 1368 {
 1369     struct node *n;
 1370     foreachback(n, f->nodes) {
 1371         int xm = n->x + n->xw, ym = n->y + n->yw;
 1372         printf("%d %d - %d %d\n", n->x, n->y, xm, ym);
 1373         fflush(stdout);
 1374     }
 1375     debug("!");
 1376 }*/
 1377 
 1378 void sort_srch(struct f_data *f)
 1379 {
 1380     int i;
 1381     int *min, *max;
 1382     if ((unsigned)f->y > MAXINT / sizeof(struct search *)) overalloc();
 1383     if ((unsigned)f->y > MAXINT / sizeof(int)) overalloc();
 1384     f->slines1 = mem_alloc(f->y * sizeof(struct search *));
 1385     f->slines2 = mem_alloc(f->y * sizeof(struct search *));
 1386     min = mem_alloc(f->y * sizeof(int));
 1387     max = mem_alloc(f->y * sizeof(int));
 1388     memset(f->slines1, 0, f->y * sizeof(struct search *));
 1389     memset(f->slines2, 0, f->y * sizeof(struct search *));
 1390     for (i = 0; i < f->y; i++) min[i] = MAXINT, max[i] = 0;
 1391     for (i = 0; i < f->nsearch; i++) {
 1392         struct search *s = &f->search[i];
 1393         if (s->x < min[s->y]) min[s->y] = s->x, f->slines1[s->y] = s;
 1394         if (s->x + s->n > max[s->y]) max[s->y] = s->x + s->n, f->slines2[s->y] = s;
 1395     }
 1396     mem_free(min);
 1397     mem_free(max);
 1398 }
 1399 
 1400 static inline int is_spc(chr c)
 1401 {
 1402     return (unsigned char)c <= ' ' || c & ATTR_FRAME;
 1403 }
 1404 
 1405 int get_srch(struct f_data *f)
 1406 {
 1407     struct node *n;
 1408     int cnt = 0;
 1409     int cc = !f->search;
 1410 #define add_srch(c_, x_, y_, n_)        \
 1411 do {                        \
 1412     if (!cc) {              \
 1413         add_srch_chr(f, c_, x_, y_, n_);\
 1414     } else {                \
 1415         if (cnt == MAXINT) overalloc(); \
 1416         cnt++;              \
 1417     }                   \
 1418 } while (0)
 1419     foreachback(n, f->nodes) {
 1420         int x, y;
 1421         int xm = n->x + n->xw, ym = n->y + n->yw;
 1422         /*printf("%d %d - %d %d\n", n->x, n->y, xm, ym);
 1423         fflush(stdout);*/
 1424         for (y = n->y; y < ym && y < f->y; y++) {
 1425             int ns = 1;
 1426             for (x = n->x; x < xm && x < f->data[y].l; x++) {
 1427                 unsigned char c = f->data[y].d[x];
 1428                 if (is_spc(f->data[y].d[x])) c = ' ';
 1429                 if (c == ' ' && ns) continue;
 1430                 c = charset_upcase(c, f->opt.cp);
 1431                 if (ns) {
 1432                     add_srch(c, x, y, 1);
 1433                     ns = 0;
 1434                     continue;
 1435                 }
 1436                 if (c != ' ') {
 1437                     add_srch(c, x, y, 1);
 1438                 } else {
 1439                     int xx;
 1440                     for (xx = x + 1; xx < xm && xx < f->data[y].l; xx++) if (!is_spc(f->data[y].d[xx])) goto ja_uz_z_toho_programovani_asi_zcvoknu;
 1441                     xx = x;
 1442                     ja_uz_z_toho_programovani_asi_zcvoknu:
 1443                 /* uz jsem zcvoknul, trpim poruchou osobnosti */
 1444                     add_srch(' ', x, y, xx - x);
 1445                     if (xx == x) goto uz_jsem_zcvoknul__jsem_psychopat__trpim_poruchou_osobnosti;
 1446                     x = xx - 1;
 1447                 }
 1448             }
 1449             uz_jsem_zcvoknul__jsem_psychopat__trpim_poruchou_osobnosti:
 1450             add_srch(' ', x, y, 0);
 1451         }
 1452     }
 1453 #undef add_srch
 1454     return cnt;
 1455     
 1456 }
 1457 
 1458 void get_search_data(struct f_data *f)
 1459 {
 1460     int n;
 1461     if (f->search) return;
 1462     n = get_srch(f);
 1463     f->nsearch = 0;
 1464     if ((unsigned)n > MAXINT / sizeof(struct search)) overalloc();
 1465     f->search = mem_alloc(n * sizeof(struct search));
 1466     get_srch(f);
 1467     while (f->nsearch && f->search[f->nsearch - 1].c == ' ') f->nsearch--;
 1468     f->search = mem_realloc(f->search, f->nsearch * sizeof(struct search));
 1469     /*debug("!");*/
 1470     sort_srch(f);
 1471 }