html_r.c (41981B)
1 /* html_r.c 2 * (c) 2002 Mikulas Patocka 3 * This file is a part of the Links program, released under GPL. 4 */ 5 6 #include <limits.h> 7 8 #include "links.h" 9 10 struct f_data * 11 init_formatted(struct document_options *opt) 12 { 13 struct f_data *scr; 14 scr = mem_calloc(sizeof(struct f_data)); 15 copy_opt(&scr->opt, opt); 16 scr->data = NULL; 17 scr->nlinks = 0; 18 scr->links = NULL; 19 init_list(scr->forms); 20 init_list(scr->tags); 21 init_list(scr->nodes); 22 return scr; 23 } 24 25 void 26 destroy_fc(struct form_control *fc) 27 { 28 int i; 29 free(fc->action); 30 free(fc->target); 31 free(fc->form_name); 32 free(fc->onsubmit); 33 free(fc->name); 34 free(fc->alt); 35 free(fc->default_value); 36 for (i = 0; i < fc->nvalues; i++) { 37 free(fc->values[i]); 38 free(fc->labels[i]); 39 } 40 free(fc->values); 41 free(fc->labels); 42 if (fc->menu) 43 free_menu(fc->menu); 44 } 45 46 void 47 free_frameset_desc(struct frameset_desc *fd) 48 { 49 int i; 50 for (i = 0; i < fd->n; i++) { 51 if (fd->f[i].subframe) 52 free_frameset_desc(fd->f[i].subframe); 53 free(fd->f[i].name); 54 free(fd->f[i].url); 55 } 56 free(fd); 57 } 58 59 struct frameset_desc * 60 copy_frameset_desc(struct frameset_desc *fd) 61 { 62 int i; 63 struct frameset_desc *neww; 64 if ((unsigned)fd->n > INT_MAX / sizeof(struct frame_desc)) 65 overalloc(); 66 neww = xmalloc(sizeof(struct frameset_desc) 67 + fd->n * sizeof(struct frame_desc)); 68 memcpy(neww, fd, 69 sizeof(struct frameset_desc) 70 + fd->n * sizeof(struct frame_desc)); 71 for (i = 0; i < neww->n; i++) { 72 if (neww->f[i].subframe) 73 neww->f[i].subframe = 74 copy_frameset_desc(neww->f[i].subframe); 75 if (neww->f[i].name) 76 neww->f[i].name = stracpy(neww->f[i].name); 77 if (neww->f[i].url) 78 neww->f[i].url = stracpy(neww->f[i].url); 79 } 80 return neww; 81 } 82 83 void 84 free_additional_files(struct additional_files **a) 85 { 86 struct additional_file *af = NULL; 87 struct list_head *laf; 88 if (!*a) 89 return; 90 if (--(*a)->refcount) { 91 *a = NULL; 92 return; 93 } 94 foreach (struct additional_file, af, laf, (*a)->af) 95 release_object(&af->rq); 96 free_list(struct additional_file, (*a)->af); 97 free(*a); 98 *a = NULL; 99 } 100 101 static void 102 clear_formatted(struct f_data *scr) 103 { 104 int n; 105 int y; 106 struct form_control *fc = NULL; 107 struct list_head *lfc; 108 if (!scr) 109 return; 110 111 free(scr->search_chr); 112 free(scr->search_pos); 113 free(scr->slines1); 114 free(scr->slines2); 115 116 release_object(&scr->rq); 117 free_additional_files(&scr->af); 118 free(scr->title); 119 if (scr->frame_desc) { 120 free_frameset_desc(scr->frame_desc); 121 } 122 for (n = 0; n < scr->nlinks; n++) { 123 struct link *l = &scr->links[n]; 124 free(l->where); 125 free(l->target); 126 free(l->where_img); 127 free(l->img_alt); 128 free(l->pos); 129 } 130 free(scr->links); 131 for (y = 0; y < scr->y; y++) 132 free(scr->data[y].d); 133 free(scr->data); 134 free(scr->lines1); 135 free(scr->lines2); 136 free(scr->opt.framename); 137 foreach (struct form_control, fc, lfc, scr->forms) { 138 destroy_fc(fc); 139 } 140 free_list(struct form_control, scr->forms); 141 free_list(struct tag, scr->tags); 142 free_list(struct node, scr->nodes); 143 free(scr->refresh); 144 } 145 146 void 147 destroy_formatted(struct f_data *scr) 148 { 149 if (scr->fd) { 150 internal("trying to free locked formatted data"); 151 return; 152 } 153 clear_formatted(scr); 154 free(scr); 155 } 156 157 static inline int 158 color_distance(struct rgb *c1, struct rgb *c2) 159 { 160 return 3 * (c1->r - c2->r) * (c1->r - c2->r) 161 + 4 * (c1->g - c2->g) * (c1->g - c2->g) 162 + 2 * (c1->b - c2->b) * (c1->b - c2->b); 163 } 164 165 struct rgb palette_16_colors[16] = { 166 {0x00, 0x00, 0x00, 0}, 167 { 0x80, 0x00, 0x00, 0}, 168 { 0x00, 0x80, 0x00, 0}, 169 { 0xaa, 0x55, 0x00, 0}, 170 { 0x00, 0x00, 0x80, 0}, 171 { 0x80, 0x00, 0x80, 0}, 172 { 0x00, 0x80, 0x80, 0}, 173 { 0xaa, 0xaa, 0xaa, 0}, 174 { 0x55, 0x55, 0x55, 0}, 175 { 0xff, 0x55, 0x55, 0}, 176 { 0x55, 0xff, 0x55, 0}, 177 { 0xff, 0xff, 0x55, 0}, 178 { 0x55, 0x55, 0xff, 0}, 179 { 0xff, 0x55, 0xff, 0}, 180 { 0x55, 0xff, 0xff, 0}, 181 { 0xff, 0xff, 0xff, 0}, 182 }; 183 184 struct rgb_cache_entry { 185 int color; 186 int l; 187 struct rgb rgb; 188 }; 189 190 #define RGB_HASH_SIZE 4096 191 192 #define HASH_RGB(r, l) \ 193 ((((r)->r << 3) + ((r)->g << 2) + (r)->b + (l)) & (RGB_HASH_SIZE - 1)) 194 195 int 196 find_nearest_color(struct rgb *r, int l) 197 { 198 int dist, dst, min, i; 199 static struct rgb_cache_entry rgb_cache[RGB_HASH_SIZE]; 200 static int cache_init = 0; 201 int h; 202 if ((size_t)l > array_elements(palette_16_colors)) 203 internal("invalid length %d", l); 204 if (!cache_init) 205 goto initialize; 206 back: 207 h = HASH_RGB(r, l); 208 if (rgb_cache[h].color != -1 && rgb_cache[h].l == l 209 && rgb_cache[h].rgb.r == r->r && rgb_cache[h].rgb.g == r->g 210 && rgb_cache[h].rgb.b == r->b) 211 return rgb_cache[h].color; 212 dist = 0xffffff; 213 min = 0; 214 for (i = 0; i < l; i++) 215 if ((dst = color_distance(r, &palette_16_colors[i])) < dist) { 216 dist = dst; 217 min = i; 218 } 219 rgb_cache[h].color = min; 220 rgb_cache[h].l = l; 221 rgb_cache[h].rgb.r = r->r; 222 rgb_cache[h].rgb.g = r->g; 223 rgb_cache[h].rgb.b = r->b; 224 return min; 225 226 initialize: 227 for (h = 0; h < RGB_HASH_SIZE; h++) 228 rgb_cache[h].color = -1; 229 cache_init = 1; 230 goto back; 231 } 232 233 int 234 fg_color(int fg, int bg) 235 { 236 int l = bg < fg ? bg : fg; 237 int h = bg < fg ? fg : bg; 238 if (l == h || (!l && (h == 4 || h == 8 || h == 12)) 239 || (l == 1 && (h == 3 || h == 5 || h == 8 || h == 12)) 240 || (l == 2 && h == 6) || (l == 3 && (h == 5 || h == 12)) 241 || (l == 4 && (h == 8 || h == 12)) 242 || (l == 5 && (h == 8 || h == 12))) 243 return (fg == 4 || fg == 12) && (bg == 0 || bg == 8) 244 ? 6 245 : (7 - 7 * (bg == 2 || bg == 6 || bg == 7)); 246 return fg; 247 } 248 249 static int nowrap = 0; 250 251 static void 252 xpand_lines(struct part *p, int y) 253 { 254 if (!p->data) 255 return; 256 if (y < 0) 257 return; 258 y = safe_add(y, safe_add(p->yp, 1)); 259 if (y > p->data->y) { 260 int i; 261 if ((y ^ p->data->y) > p->data->y) { 262 unsigned s; 263 for (s = 1; s < (unsigned)y; s = s * 2 + 1) { 264 if (s > INT_MAX / sizeof(struct line)) 265 overalloc(); 266 } 267 p->data->data = 268 xrealloc(p->data->data, s * sizeof(struct line)); 269 } 270 for (i = p->data->y; i < y; i++) { 271 p->data->data[i].l = 0; 272 p->data->data[i].allocated = 0; 273 p->data->data[i].d = NULL; 274 } 275 p->data->y = y; 276 } 277 } 278 279 static void 280 xpand_line(struct part *p, int y, int x) 281 { 282 struct line *ln; 283 if (!p->data) 284 return; 285 x = safe_add(x, p->xp); 286 y = safe_add(y, p->yp); 287 ln = &p->data->data[y]; 288 if (x >= ln->l) { 289 int i; 290 if (x >= ln->allocated) { 291 if (x >= 0x4000) 292 ln->allocated = safe_add(x, x); 293 else 294 ln->allocated = safe_add(x, 0x10) & ~0xf; 295 if ((unsigned)ln->allocated > INT_MAX / sizeof(chr)) 296 overalloc(); 297 ln->d = xrealloc(ln->d, ln->allocated * sizeof(chr)); 298 } 299 for (i = ln->l; i <= x; i++) { 300 ln->d[i].at = p->attribute; 301 ln->d[i].ch = ' '; 302 } 303 ln->l = i; 304 } 305 } 306 307 static void 308 r_xpand_spaces(struct part *p, int l) 309 { 310 unsigned char *c; 311 if ((unsigned)l >= INT_MAX) 312 overalloc(); 313 c = xrealloc(p->spaces, l + 1); 314 memset(c + p->spl, 0, l - p->spl + 1); 315 p->spl = l + 1; 316 p->spaces = c; 317 } 318 319 static inline void 320 xpand_spaces(struct part *p, int l) 321 { 322 if ((unsigned)l >= (unsigned)p->spl) 323 r_xpand_spaces(p, l); 324 } 325 326 #define POS(x, y) (p->data->data[safe_add(p->yp, (y))].d[safe_add(p->xp, (x))]) 327 #define LEN(y) \ 328 (p->data->data[safe_add(p->yp, (y))].l - p->xp < 0 \ 329 ? 0 \ 330 : p->data->data[p->yp + (y)].l - p->xp) 331 #define SLEN(y, x) p->data->data[safe_add(p->yp, (y))].l = safe_add(p->xp, x) 332 #define X(x) safe_add(p->xp, (x)) 333 #define Y(y) safe_add(p->yp, (y)) 334 335 static inline void 336 set_hchar(struct part *p, int x, int y, unsigned ch, unsigned char at) 337 { 338 chr *cc; 339 xpand_lines(p, y); 340 xpand_line(p, y, x); 341 cc = &POS(x, y); 342 cc->ch = ch; 343 cc->at = at; 344 } 345 346 static inline void 347 set_hchars(struct part *p, int x, int y, int xl, unsigned ch, unsigned char at) 348 { 349 chr *cc; 350 xpand_lines(p, y); 351 xpand_line(p, y, safe_add(x, xl) - 1); 352 cc = &POS(x, y); 353 for (; xl; xl--) { 354 cc->ch = ch; 355 cc->at = at; 356 cc++; 357 } 358 } 359 360 void 361 xset_hchar(struct part *p, int x, int y, unsigned ch, unsigned char at) 362 { 363 set_hchar(p, x, y, ch, at); 364 } 365 366 void 367 xset_hchars(struct part *p, int x, int y, int xl, unsigned ch, unsigned char at) 368 { 369 set_hchars(p, x, y, xl, ch, at); 370 } 371 372 void 373 xxpand_lines(struct part *p, int y) 374 { 375 xpand_lines(p, y); 376 } 377 378 void 379 xxpand_line(struct part *p, int y, int x) 380 { 381 xpand_line(p, y, x); 382 } 383 384 static inline void 385 set_hline(struct part *p, int x, int y, int xl, unsigned char *d, 386 unsigned char at) 387 { 388 chr *cc; 389 int xp; 390 xpand_lines(p, y); 391 xpand_line(p, y, safe_add(x, xl) - 1); 392 xp = par_format.align != AL_NO; 393 if (xp) 394 xpand_spaces(p, safe_add(x, xl) - 1); 395 cc = NULL; 396 if (p->data) 397 cc = &POS(x, y); 398 for (; xl; xl--, x++, d++) { 399 if (xp) 400 p->spaces[x] = *d == ' '; 401 if (p->data) { 402 cc->ch = *d; 403 cc->at = at; 404 cc++; 405 } 406 } 407 } 408 409 static inline void 410 set_hline_uni(struct part *p, int x, int y, int xl, char_t *d, unsigned char at) 411 { 412 chr *cc; 413 int xp; 414 xpand_lines(p, y); 415 xpand_line(p, y, safe_add(x, xl) - 1); 416 xp = par_format.align != AL_NO; 417 if (xp) 418 xpand_spaces(p, safe_add(x, xl) - 1); 419 cc = NULL; 420 if (p->data) 421 cc = &POS(x, y); 422 for (; xl; xl--, x++, d++) { 423 if (xp) 424 p->spaces[x] = *d == ' '; 425 if (p->data) { 426 cc->ch = *d; 427 cc->at = at; 428 cc++; 429 } 430 } 431 } 432 433 static int last_link_to_move; 434 static struct list_head *last_tag_to_move; 435 static struct list_head *last_tag_for_newline; 436 437 static inline void 438 move_links(struct part *p, int xf, int yf, int xt, int yt) 439 { 440 int n; 441 struct tag *t = NULL; 442 struct list_head *lt; 443 int w = 0; 444 if (!p->data) 445 return; 446 xpand_lines(p, yt); 447 for (n = last_link_to_move; n < p->data->nlinks; n++) { 448 int i; 449 struct link *link = &p->data->links[n]; 450 /*printf("ml: %d %d %d 451 * %d",link->pos[0].x,link->pos[0].y,X(xf),Y(yf));fflush(stdout);portable_sleep(1000);*/ 452 for (i = link->first_point_to_move; i < link->n; i++) 453 if (link->pos[i].y >= Y(yf)) { 454 w = 1; 455 if (link->pos[i].y == Y(yf) 456 && link->pos[i].x >= X(xf)) { 457 if (yt >= 0) { 458 link->pos[i].y = Y(yt); 459 if (xt > xf) 460 link->pos[i].x = 461 safe_add( 462 link->pos[i].x, 463 -xf + xt); 464 else 465 link->pos[i].x = 466 link->pos[i].x - xf 467 + xt; 468 } else { 469 memmove( 470 &link->pos[i], 471 &link->pos[i + 1], 472 (link->n - i - 1) 473 * sizeof(struct point)); 474 link->n--; 475 i--; 476 } 477 } 478 } else { 479 link->first_point_to_move = safe_add(i, 1); 480 } 481 if (!w) 482 last_link_to_move = n; 483 } 484 w = 0; 485 if (yt >= 0) 486 foreachfrom (struct tag, t, lt, p->data->tags, 487 last_tag_to_move->next) { 488 if (t->y == Y(yf)) { 489 w = 1; 490 if (t->x >= X(xf)) { 491 t->y = Y(yt); 492 if (xt > xf) 493 t->x = safe_add(t->x, -xf + xt); 494 else 495 t->x += -xf + xt; 496 } 497 } 498 if (!w) 499 last_tag_to_move = &t->list_entry; 500 } 501 } 502 503 static inline void 504 copy_chars(struct part *p, int x, int y, int xl, chr *d) 505 { 506 if (xl <= 0) 507 return; 508 xpand_lines(p, y); 509 xpand_line(p, y, safe_add(x, xl) - 1); 510 for (; xl; xl--, x++, d++) 511 POS(x, y) = *d; 512 } 513 514 static inline void 515 move_chars(struct part *p, int x, int y, int nx, int ny) 516 { 517 if (LEN(y) - x <= 0) 518 return; 519 copy_chars(p, nx, ny, LEN(y) - x, &POS(x, y)); 520 SLEN(y, x); 521 move_links(p, x, y, nx, ny); 522 } 523 524 static inline void 525 shift_chars(struct part *p, int y, int s) 526 { 527 chr *a; 528 int l = LEN(y); 529 if ((unsigned)l > INT_MAX / sizeof(chr)) 530 overalloc(); 531 a = xmalloc(l * sizeof(chr)); 532 memcpy(a, &POS(0, y), l * sizeof(chr)); 533 set_hchars(p, 0, y, s, ' ', p->attribute); 534 copy_chars(p, s, y, l, a); 535 free(a); 536 move_links(p, 0, y, s, y); 537 } 538 539 static inline void 540 del_chars(struct part *p, int x, int y) 541 { 542 SLEN(y, x); 543 move_links(p, x, y, -1, -1); 544 } 545 546 #define rm(x) \ 547 ((x).width - (x).rightmargin > 0 ? (x).width - (x).rightmargin : 0) 548 549 static void line_break(void *); 550 551 static int 552 split_line(struct part *p) 553 { 554 int i; 555 if (rm(par_format) >= p->z_spaces) { 556 for (i = rm(par_format); i >= par_format.leftmargin; i--) 557 if (i < p->spl && p->spaces[i]) 558 goto split; 559 } 560 i = rm(par_format) + 1; 561 if (i < p->z_spaces) 562 i = p->z_spaces; 563 if (i < par_format.leftmargin) 564 i = par_format.leftmargin; 565 for (; i < p->cx; i++) 566 if (i < p->spl && p->spaces[i]) 567 goto split; 568 p->z_spaces = i; 569 if (p->cx >= 0 && safe_add(p->cx, par_format.rightmargin) > p->x) 570 p->x = p->cx + par_format.rightmargin; 571 return 0; 572 split: 573 if (safe_add(i, par_format.rightmargin) > p->x) 574 p->x = i + par_format.rightmargin; 575 if (p->data) { 576 move_chars(p, safe_add(i, 1), p->cy, par_format.leftmargin, 577 safe_add(p->cy, 1)); 578 del_chars(p, i, p->cy); 579 } 580 memmove(p->spaces, p->spaces + safe_add(i, 1), p->spl - i - 1); 581 memset(p->spaces + p->spl - i - 1, 0, i + 1); 582 memmove(p->spaces + par_format.leftmargin, p->spaces, 583 p->spl - par_format.leftmargin); 584 p->z_spaces = 0; 585 p->cy = safe_add(p->cy, 1); 586 p->cx -= i - par_format.leftmargin + 1; 587 if (p->cx == par_format.leftmargin) 588 p->cx = -1; 589 if (p->y < safe_add(p->cy, (p->cx != -1))) 590 p->y = p->cy + (p->cx != -1); 591 return 1 + (p->cx == -1); 592 } 593 594 static void 595 align_line(struct part *p, int y) 596 { 597 int na; 598 if (!p->data) 599 return; 600 if (!LEN(y) || par_format.align == AL_LEFT || par_format.align == AL_NO 601 || par_format.align == AL_NO_BREAKABLE 602 || par_format.align == AL_BLOCK /* !!! fixme! */) 603 return; 604 na = rm(par_format) - LEN(y); 605 if (par_format.align == AL_CENTER) 606 na /= 2; 607 if (na > 0) 608 shift_chars(p, y, na); 609 } 610 611 struct link * 612 new_link(struct f_data *f) 613 { 614 if (!f) 615 return NULL; 616 if (!(f->nlinks & (ALLOC_GR - 1))) { 617 if ((unsigned)f->nlinks 618 > INT_MAX / sizeof(struct link) - ALLOC_GR) 619 overalloc(); 620 f->links = xrealloc(f->links, (f->nlinks + ALLOC_GR) 621 * sizeof(struct link)); 622 } 623 memset(&f->links[f->nlinks], 0, sizeof(struct link)); 624 return &f->links[f->nlinks++]; 625 } 626 627 void 628 html_tag(struct f_data *f, unsigned char *t, int x, int y) 629 { 630 struct tag *tag; 631 size_t sl; 632 unsigned char *tt; 633 if (!f) 634 return; 635 tt = NULL; 636 add_conv_str(&tt, 0, t, (int)strlen(cast_const_char t), -2); 637 sl = strlen(cast_const_char tt); 638 if (sl > INT_MAX - sizeof(struct tag)) 639 overalloc(); 640 tag = xmalloc(sizeof(struct tag) + sl); 641 tag->x = x; 642 tag->y = y; 643 strcpy(cast_char tag->name, cast_const_char tt); 644 add_to_list(f->tags, tag); 645 if (last_tag_for_newline == &f->tags) 646 last_tag_for_newline = &tag->list_entry; 647 free(tt); 648 } 649 650 unsigned char *last_link = NULL; 651 unsigned char *last_target = NULL; 652 unsigned char *last_image = NULL; 653 struct form_control *last_form = NULL; 654 655 static int nobreak; 656 657 struct conv_table *convert_table; 658 659 static void 660 put_chars(void *p_, unsigned char *c, int l) 661 { 662 struct part *p = p_; 663 664 static struct text_attrib_beginning ta_cache = { 665 -1, {0, 0, 0, 0}, 666 { 0, 0, 0, 0}, 667 0, 0 668 }; 669 static int bg_cache; 670 static int fg_cache; 671 char_t *uni_c = NULL; 672 673 int bg, fg; 674 int i; 675 struct link *link; 676 struct point *pt; 677 int ll; 678 679 if (l < 0) 680 overalloc(); 681 682 /*printf("%d-", p->cx);for (i=0; i<l; i++) printf("%c", c[i]); 683 * printf("-\n");portable_sleep(1000);*/ 684 while (p->cx <= par_format.leftmargin && l && *c == ' ' 685 && par_format.align != AL_NO 686 && par_format.align != AL_NO_BREAKABLE) { 687 c++; 688 l--; 689 } 690 if (!l) 691 return; 692 if (p->cx < par_format.leftmargin) 693 p->cx = par_format.leftmargin; 694 if (c[0] != ' ' || (c[1] && c[1] != ' ')) { 695 if (p->data) 696 last_tag_for_newline = &p->data->tags; 697 } 698 if (!d_opt->cp && !(format_.attr & AT_GRAPHICS)) { 699 int pl; 700 unsigned char *cc; 701 if (p->utf8_part_len) { 702 unsigned char new_part[7]; 703 unsigned char *q; 704 next_utf_byte: 705 if ((*c & 0xc0) != 0x80) 706 goto bad_utf; 707 p->utf8_part[p->utf8_part_len++] = *c; 708 p->utf8_part[p->utf8_part_len] = 0; 709 c++; 710 l--; 711 q = p->utf8_part; 712 if (!get_utf_8(&q)) { 713 if (p->utf8_part_len 714 == sizeof(p->utf8_part) - 1) 715 goto bad_utf; 716 if (l) 717 goto next_utf_byte; 718 return; 719 } 720 pl = p->utf8_part_len; 721 p->utf8_part_len = 0; 722 strcpy(cast_char new_part, 723 cast_const_char p->utf8_part); 724 put_chars(p, new_part, pl); 725 } 726 bad_utf: 727 p->utf8_part_len = 0; 728 if (!l) 729 return; 730 if ((unsigned)l > (unsigned)INT_MAX / sizeof(char_t)) 731 overalloc(); 732 uni_c = xmalloc(l * sizeof(char_t)); 733 ll = 0; 734 cc = c; 735 next_utf_char: 736 pl = utf8chrlen(*cc); 737 if (safe_add((int)(cc - c), pl) > l) { 738 memcpy(p->utf8_part, cc, 739 p->utf8_part_len = l - (int)(cc - c)); 740 goto utf_done; 741 } else { 742 if (!pl) { 743 cc++; 744 } else { 745 unsigned un; 746 GET_UTF_8(cc, un); 747 if (un != 0xad) { 748 uni_c[ll] = un; 749 ll = safe_add(ll, 1); 750 } 751 } 752 if (cc < c + l) 753 goto next_utf_char; 754 } 755 utf_done: 756 if (!ll) { 757 free(uni_c); 758 return; 759 } 760 } else { 761 ll = l; 762 } 763 if (last_link || last_image || last_form || format_.link 764 || format_.image || format_.form) 765 goto process_link; 766 no_l: 767 /*printf("%d %d\n",p->cx, p->cy);*/ 768 if (memcmp(&ta_cache, &format_, sizeof(struct text_attrib_beginning))) 769 goto format_change; 770 bg = bg_cache; 771 fg = fg_cache; 772 end_format_change: 773 if (p->y < safe_add(p->cy, 1)) 774 p->y = p->cy + 1; 775 if (nowrap && safe_add(p->cx, ll) > rm(par_format)) { 776 free(uni_c); 777 return; 778 } 779 if (!d_opt->cp && !(format_.attr & AT_GRAPHICS)) { 780 set_hline_uni(p, p->cx, p->cy, ll, uni_c, 781 ((fg & 0x08) << 3) | (bg << 3) | (fg & 0x07)); 782 } else 783 set_hline(p, p->cx, p->cy, l, c, 784 ((fg & 0x08) << 3) | (bg << 3) | (fg & 0x07)); 785 p->cx += ll; 786 nobreak = 0; 787 if (par_format.align != AL_NO) 788 while (p->cx > rm(par_format) 789 && p->cx > par_format.leftmargin) { 790 int x; 791 if (!(x = split_line(p))) 792 break; 793 align_line(p, p->cy - 1); 794 nobreak = x - 1; 795 } 796 p->xa = safe_add(p->xa, ll); 797 if (safe_add(p->xa 798 - (c[l - 1] == ' ' && par_format.align != AL_NO 799 && par_format.align != AL_NO_BREAKABLE), 800 safe_add(par_format.leftmargin, par_format.rightmargin)) 801 > p->xmax) 802 p->xmax = p->xa 803 - (c[l - 1] == ' ' && par_format.align != AL_NO 804 && par_format.align != AL_NO_BREAKABLE) 805 + par_format.leftmargin + par_format.rightmargin; 806 free(uni_c); 807 return; 808 809 /* !!! WARNING: THE FOLLOWING CODE IS SHADOWED IN HTML_GR.C */ 810 811 process_link: 812 if ((last_link || last_image || last_form) 813 && !xstrcmp(format_.link, last_link) 814 && !xstrcmp(format_.target, last_target) 815 && !xstrcmp(format_.image, last_image) 816 && format_.form == last_form) { 817 if (!p->data) 818 goto x; 819 link = &p->data->links[p->data->nlinks - 1]; 820 if (!p->data->nlinks) { 821 internal("no link"); 822 goto no_l; 823 } 824 goto set_link; 825 x:; 826 } else { 827 free(last_link); 828 free(last_target); 829 free(last_image); 830 last_link = last_target = last_image = NULL; 831 last_form = NULL; 832 if (!(format_.link || format_.image || format_.form)) 833 goto no_l; 834 if (d_opt->num_links) { 835 unsigned char s[64]; 836 unsigned char *fl = format_.link, *ft = format_.target, 837 *fi = format_.image; 838 struct form_control *ff = format_.form; 839 format_.link = format_.target = format_.image = NULL; 840 format_.form = NULL; 841 if (d_opt->num_links) { 842 s[0] = '['; 843 snzprint(s + 1, 62, p->link_num); 844 strcat(cast_char s, "]"); 845 } else { 846 if (ff 847 && (ff->type == FC_TEXT 848 || ff->type == FC_PASSWORD 849 || ff->type == FC_FILE_UPLOAD 850 || ff->type == FC_TEXTAREA)) { 851 strcpy(cast_char s, ">"); 852 } else if (ff 853 && (ff->type == FC_CHECKBOX 854 || ff->type == FC_RADIO 855 || ff->type == FC_SELECT)) { 856 strcpy(cast_char s, ""); 857 } else { 858 strcpy(cast_char s, "~"); 859 } 860 } 861 put_chars(p, s, (int)strlen(cast_const_char s)); 862 if (ff && ff->type == FC_TEXTAREA) 863 line_break(p); 864 if (p->cx < par_format.leftmargin) 865 p->cx = par_format.leftmargin; 866 format_.link = fl; 867 format_.target = ft; 868 format_.image = fi; 869 format_.form = ff; 870 } 871 p->link_num++; 872 last_link = stracpy(format_.link); 873 last_target = stracpy(format_.target); 874 last_image = stracpy(format_.image); 875 last_form = format_.form; 876 if (!p->data) 877 goto no_l; 878 if (!(link = new_link(p->data))) 879 goto no_l; 880 link->num = p->link_num - 1; 881 link->pos = NULL; 882 if (!last_form) { 883 link->type = L_LINK; 884 link->where = stracpy(last_link); 885 link->target = stracpy(last_target); 886 } else { 887 link->type = 888 last_form->type == FC_TEXT 889 || last_form->type == FC_PASSWORD 890 || last_form->type == FC_FILE_UPLOAD 891 ? L_FIELD 892 : last_form->type == FC_TEXTAREA ? L_AREA 893 : last_form->type == FC_CHECKBOX 894 || last_form->type == FC_RADIO 895 ? L_CHECKBOX 896 : last_form->type == FC_SELECT ? L_SELECT 897 : L_BUTTON; 898 link->form = last_form; 899 link->target = stracpy(last_form->target); 900 } 901 link->where_img = stracpy(last_image); 902 if (link->type != L_FIELD && link->type != L_AREA) { 903 bg = find_nearest_color(&format_.clink, 8); 904 fg = find_nearest_color(&format_.bg, 8); 905 fg = fg_color(fg, bg); 906 } else { 907 fg = find_nearest_color(&format_.fg, 8); 908 bg = find_nearest_color(&format_.bg, 8); 909 fg = fg_color(fg, bg); 910 } 911 link->sel_color = get_attribute(fg, bg); 912 link->n = 0; 913 set_link: 914 if ((unsigned)link->n + (unsigned)ll 915 > INT_MAX / sizeof(struct point)) 916 overalloc(); 917 pt = xrealloc(link->pos, (link->n + ll) * sizeof(struct point)); 918 link->pos = pt; 919 for (i = 0; i < ll; i++) { 920 pt[link->n + i].x = X(p->cx) + i; 921 pt[link->n + i].y = Y(p->cy); 922 } 923 link->n += ll; 924 } 925 goto no_l; 926 927 format_change: 928 bg = find_nearest_color(&format_.bg, 8); 929 fg = find_nearest_color(&format_.fg, 16); 930 fg = fg_color(fg, bg); 931 if (format_.attr & AT_ITALIC) 932 fg = fg ^ 0x01; 933 if (format_.attr & AT_UNDERLINE) 934 fg = (fg ^ 0x04) | 0x08; 935 if (format_.attr & AT_BOLD) 936 fg = fg | 0x08; 937 fg = fg_color(fg, bg); 938 if (format_.attr & AT_GRAPHICS) 939 bg = bg | 0x10; 940 memcpy(&ta_cache, &format_, sizeof(struct text_attrib_beginning)); 941 fg_cache = fg; 942 bg_cache = bg; 943 goto end_format_change; 944 } 945 946 static void 947 line_break(void *p_) 948 { 949 struct part *p = p_; 950 struct tag *t = NULL; 951 struct list_head *lt; 952 if (p->cx >= 0 && safe_add(p->cx, par_format.rightmargin) > p->x) 953 p->x = p->cx + par_format.rightmargin; 954 if (nobreak) { 955 nobreak = 0; 956 p->cx = -1; 957 p->xa = 0; 958 return; 959 } 960 if (!p->data) 961 goto e; 962 xpand_lines(p, safe_add(p->cy, 1)); 963 if (p->cx > par_format.leftmargin && LEN(p->cy) > p->cx - 1 964 && POS(p->cx - 1, p->cy).ch == ' ') { 965 del_chars(p, p->cx - 1, p->cy); 966 p->cx--; 967 } 968 if (p->cx > 0) 969 align_line(p, p->cy); 970 if (p->data) 971 foreachbackfrom (struct tag, t, lt, p->data->tags, 972 last_tag_for_newline) { 973 t->x = X(0); 974 t->y = Y(p->cy + 1); 975 } 976 e: 977 p->cy++; 978 p->cx = -1; 979 p->xa = 0; 980 if (p->spl > d_opt->xw) 981 p->spl = d_opt->xw; 982 memset(p->spaces, 0, p->spl); 983 p->z_spaces = 0; 984 } 985 986 int g_ctrl_num; 987 988 /* SHADOWED IN g_html_form_control */ 989 static void 990 html_form_control(struct part *p, struct form_control *fc) 991 { 992 if (!p->data) { 993 add_to_list(p->uf, fc); 994 return; 995 } 996 fc->g_ctrl_num = g_ctrl_num; 997 g_ctrl_num = safe_add(g_ctrl_num, 1); 998 if (fc->type == FC_TEXT || fc->type == FC_PASSWORD 999 || fc->type == FC_TEXTAREA) { 1000 unsigned char *dv = convert_string( 1001 convert_table, fc->default_value, 1002 (int)strlen(cast_const_char fc->default_value), d_opt); 1003 if (dv) { 1004 free(fc->default_value); 1005 fc->default_value = dv; 1006 } 1007 } 1008 if (fc->type == FC_TEXTAREA) { 1009 unsigned char *p; 1010 for (p = fc->default_value; p[0]; p++) 1011 if (p[0] == '\r') { 1012 if (p[1] == '\n') { 1013 memmove(p, p + 1, 1014 strlen(cast_const_char p)); 1015 p--; 1016 } else 1017 p[0] = '\n'; 1018 } 1019 } 1020 add_to_list(p->data->forms, fc); 1021 } 1022 1023 static void 1024 add_frameset_entry(struct frameset_desc *fsd, struct frameset_desc *subframe, 1025 unsigned char *name, unsigned char *url, int marginwidth, 1026 int marginheight, unsigned char scrolling) 1027 { 1028 if (fsd->yp >= fsd->y) 1029 return; 1030 fsd->f[fsd->xp + fsd->yp * fsd->x].subframe = subframe; 1031 fsd->f[fsd->xp + fsd->yp * fsd->x].name = stracpy(name); 1032 fsd->f[fsd->xp + fsd->yp * fsd->x].url = stracpy(url); 1033 fsd->f[fsd->xp + fsd->yp * fsd->x].marginwidth = marginwidth; 1034 fsd->f[fsd->xp + fsd->yp * fsd->x].marginheight = marginheight; 1035 fsd->f[fsd->xp + fsd->yp * fsd->x].scrolling = scrolling; 1036 if (++fsd->xp >= fsd->x) { 1037 fsd->xp = 0; 1038 fsd->yp++; 1039 } 1040 } 1041 1042 struct frameset_desc * 1043 create_frameset(struct f_data *fda, struct frameset_param *fp) 1044 { 1045 int i; 1046 struct frameset_desc *fd; 1047 if (!fp->x || !fp->y) { 1048 internal("zero size of frameset"); 1049 return NULL; 1050 } 1051 if (fp->x 1052 && (unsigned)fp->x * (unsigned)fp->y / (unsigned)fp->x 1053 != (unsigned)fp->y) 1054 overalloc(); 1055 if ((unsigned)fp->x * (unsigned)fp->y 1056 > (INT_MAX - sizeof(struct frameset_desc)) 1057 / sizeof(struct frame_desc)) 1058 overalloc(); 1059 fd = mem_calloc(sizeof(struct frameset_desc) 1060 + fp->x * fp->y * sizeof(struct frame_desc)); 1061 fd->n = fp->x * fp->y; 1062 fd->x = fp->x; 1063 fd->y = fp->y; 1064 for (i = 0; i < fd->n; i++) { 1065 fd->f[i].xw = fp->xw[i % fp->x]; 1066 fd->f[i].yw = fp->yw[i / fp->x]; 1067 } 1068 if (fp->parent) 1069 add_frameset_entry(fp->parent, fd, NULL, NULL, -1, -1, 1070 SCROLLING_AUTO); 1071 else if (!fda->frame_desc) 1072 fda->frame_desc = fd; 1073 else { 1074 free(fd); 1075 fd = NULL; 1076 } 1077 return fd; 1078 } 1079 1080 void 1081 create_frame(struct frame_param *fp) 1082 { 1083 add_frameset_entry(fp->parent, NULL, fp->name, fp->url, fp->marginwidth, 1084 fp->marginheight, fp->scrolling); 1085 } 1086 1087 void 1088 process_script(struct f_data *f, unsigned char *t) 1089 { 1090 } 1091 1092 void 1093 set_base(struct f_data *f, unsigned char *t) 1094 { 1095 } 1096 1097 void 1098 html_process_refresh(struct f_data *f, unsigned char *url, int time) 1099 { 1100 if (!f) 1101 return; 1102 if (f->refresh) 1103 return; 1104 if (!url) 1105 f->refresh = stracpy(f->rq->url); 1106 else 1107 f->refresh = join_urls(f->rq->url, url); 1108 f->refresh_seconds = time; 1109 } 1110 1111 static void * 1112 html_special(void *p_, int c, ...) 1113 { 1114 struct part *p = p_; 1115 va_list l; 1116 unsigned char *t; 1117 struct form_control *fc; 1118 struct frameset_param *fsp; 1119 struct frame_param *fp; 1120 struct refresh_param *rp; 1121 va_start(l, c); 1122 switch (c) { 1123 case SP_TAG: 1124 t = va_arg(l, unsigned char *); 1125 va_end(l); 1126 html_tag(p->data, t, X(p->cx >= 0 ? p->cx : 0), Y(p->cy)); 1127 break; 1128 case SP_CONTROL: 1129 fc = va_arg(l, struct form_control *); 1130 va_end(l); 1131 html_form_control(p, fc); 1132 break; 1133 case SP_TABLE: 1134 va_end(l); 1135 return convert_table; 1136 case SP_USED: 1137 va_end(l); 1138 return (void *)(long)!!p->data; 1139 case SP_FRAMESET: 1140 fsp = va_arg(l, struct frameset_param *); 1141 va_end(l); 1142 return create_frameset(p->data, fsp); 1143 case SP_FRAME: 1144 fp = va_arg(l, struct frame_param *); 1145 va_end(l); 1146 create_frame(fp); 1147 break; 1148 case SP_NOWRAP: 1149 nowrap = va_arg(l, int); 1150 va_end(l); 1151 break; 1152 case SP_SCRIPT: 1153 t = va_arg(l, unsigned char *); 1154 va_end(l); 1155 if (p->data) 1156 process_script(p->data, t); 1157 break; 1158 case SP_REFRESH: 1159 rp = va_arg(l, struct refresh_param *); 1160 va_end(l); 1161 html_process_refresh(p->data, rp->url, rp->time); 1162 break; 1163 case SP_SET_BASE: 1164 t = va_arg(l, unsigned char *); 1165 va_end(l); 1166 if (p->data) 1167 set_base(p->data, t); 1168 break; 1169 default: 1170 va_end(l); 1171 internal("html_special: unknown code %d", c); 1172 } 1173 return NULL; 1174 } 1175 1176 static void 1177 do_format(unsigned char *start, unsigned char *end, struct part *part, 1178 unsigned char *head) 1179 { 1180 pr(parse_html(start, end, put_chars, line_break, html_special, part, 1181 head);){}; 1182 } 1183 1184 int margin; 1185 1186 struct part * 1187 format_html_part(unsigned char *start, unsigned char *end, int align, int m, 1188 int width, struct f_data *data, int xs, int ys, 1189 unsigned char *head, int link_num) 1190 { 1191 struct part *p; 1192 struct html_element *e; 1193 int llm = last_link_to_move; 1194 struct list_head *ltm = last_tag_to_move; 1195 int lm = margin; 1196 int ef = empty_format; 1197 struct form_control *fc = NULL; 1198 struct list_head *lfc; 1199 1200 if (par_format.implicit_pre_wrap) { 1201 if (width > d_opt->xw) 1202 width = d_opt->xw; 1203 } 1204 1205 if (!data) { 1206 p = find_table_cache_entry(start, end, align, m, width, xs, 1207 link_num); 1208 if (p) 1209 return p; 1210 } 1211 if (ys < 0) { 1212 internal("format_html_part: ys == %d", ys); 1213 return NULL; 1214 } 1215 if (data) { 1216 struct node *n; 1217 n = xmalloc(sizeof(struct node)); 1218 n->x = xs; 1219 n->y = ys; 1220 n->xw = !table_level ? INT_MAX - 1 : width; 1221 add_to_list(data->nodes, n); 1222 } 1223 last_link_to_move = data ? data->nlinks : 0; 1224 last_tag_to_move = data ? &data->tags : NULL; 1225 last_tag_for_newline = data ? &data->tags : NULL; 1226 margin = m; 1227 empty_format = !data; 1228 free(last_link); 1229 free(last_image); 1230 free(last_target); 1231 last_link = last_image = last_target = NULL; 1232 last_form = NULL; 1233 nobreak = align != AL_NO && align != AL_NO_BREAKABLE; 1234 p = mem_calloc(sizeof(struct part)); 1235 /*p->x = p->y = 0;*/ 1236 p->data = data; 1237 p->xp = xs; 1238 p->yp = ys; 1239 /*p->xmax = p->xa = 0;*/ 1240 p->attribute = 1241 get_attribute(find_nearest_color(&format_.fg, 16), 1242 find_nearest_color(&par_format.bgcolor, 8)); 1243 p->spaces = NULL; 1244 /*p->z_spaces = 0;*/ 1245 /*p->spl = 0;*/ 1246 p->link_num = link_num; 1247 init_list(p->uf); 1248 html_stack_dup(); 1249 e = &html_top; 1250 html_top.dontkill = 2; 1251 html_top.namelen = 0; 1252 par_format.align = align; 1253 par_format.leftmargin = m; 1254 par_format.rightmargin = m; 1255 par_format.width = width; 1256 par_format.list_level = 0; 1257 par_format.list_number = 0; 1258 par_format.dd_margin = 0; 1259 if (align == AL_NO || align == AL_NO_BREAKABLE) 1260 format_.attr |= AT_FIXED; 1261 p->cx = -1; 1262 p->cy = 0; 1263 do_format(start, end, p, head); 1264 if (p->xmax < p->x) 1265 p->xmax = p->x; 1266 if (align == AL_NO || align == AL_NO_BREAKABLE) { 1267 if (p->cy > p->y) 1268 p->y = p->cy; 1269 } 1270 nobreak = 0; 1271 line_breax = 1; 1272 free(last_link); 1273 free(last_image); 1274 free(last_target); 1275 while (&html_top != e) { 1276 kill_html_stack_item(&html_top); 1277 if (!&html_top || (void *)&html_top == (void *)&html_stack) { 1278 internal("html stack trashed"); 1279 break; 1280 } 1281 } 1282 html_top.dontkill = 0; 1283 kill_html_stack_item(&html_top); 1284 free(p->spaces); 1285 if (data) { 1286 struct node *n = list_struct(data->nodes.next, struct node); 1287 n->yw = ys - n->y + p->y; 1288 } 1289 foreach (struct form_control, fc, lfc, p->uf) 1290 destroy_fc(fc); 1291 free_list(struct form_control, p->uf); 1292 last_link_to_move = llm; 1293 last_tag_to_move = ltm; 1294 margin = lm; 1295 empty_format = ef; 1296 last_link = last_image = last_target = NULL; 1297 last_form = NULL; 1298 1299 if (table_level > 1 && !data) { 1300 add_table_cache_entry(start, end, align, m, width, xs, link_num, 1301 p); 1302 } 1303 return p; 1304 } 1305 1306 static void 1307 push_base_format(unsigned char *url, struct document_options *opt, int frame, 1308 int implicit_pre_wrap) 1309 { 1310 struct html_element *e; 1311 if (!list_empty(html_stack)) { 1312 internal("something on html stack"); 1313 init_list(html_stack); 1314 } 1315 e = mem_calloc(sizeof(struct html_element)); 1316 add_to_list(html_stack, e); 1317 format_.attr = opt->plain & 1 ? AT_FIXED : 0; 1318 format_.fontsize = 3; 1319 format_.link = format_.target = format_.image = format_.select = NULL; 1320 format_.form = NULL; 1321 memcpy(&format_.fg, &opt->default_fg, sizeof(struct rgb)); 1322 memcpy(&format_.bg, &opt->default_bg, sizeof(struct rgb)); 1323 memcpy(&format_.clink, &opt->default_link, sizeof(struct rgb)); 1324 format_.href_base = stracpy(url); 1325 format_.target_base = stracpy(opt->framename); 1326 par_format.align = !(opt->plain & 1) ? AL_LEFT 1327 : !implicit_pre_wrap ? AL_NO 1328 : AL_NO_BREAKABLE; 1329 par_format.leftmargin = opt->plain & 1 ? 0 : opt->margin; 1330 par_format.rightmargin = opt->plain & 1 ? 0 : opt->margin; 1331 if (frame && par_format.leftmargin) 1332 par_format.leftmargin = 1; 1333 if (frame && par_format.rightmargin) 1334 par_format.rightmargin = 1; 1335 par_format.width = opt->xw; 1336 par_format.list_level = par_format.list_number = 0; 1337 par_format.dd_margin = opt->margin; 1338 par_format.flags = 0; 1339 memcpy(&par_format.bgcolor, &opt->default_bg, sizeof(struct rgb)); 1340 par_format.implicit_pre_wrap = implicit_pre_wrap; 1341 html_top.invisible = 0; 1342 html_top.name = NULL; 1343 html_top.namelen = 0; 1344 html_top.options = NULL; 1345 html_top.linebreak = 1; 1346 html_top.dontkill = 1; 1347 } 1348 1349 struct conv_table * 1350 get_convert_table(unsigned char *head, int to, int def, int *frm, int *aa, 1351 int hard) 1352 { 1353 int from = -1; 1354 unsigned char *a, *b; 1355 unsigned char *p = head; 1356 while (from == -1 1357 && (a = parse_http_header(p, cast_uchar "Content-Type", &p))) { 1358 if ((b = parse_header_param(a, cast_uchar "charset", 0))) { 1359 from = 0; 1360 free(b); 1361 } 1362 free(a); 1363 } 1364 if (aa) { 1365 *aa = from == -1; 1366 if (hard && !*aa) 1367 *aa = 2; 1368 } 1369 if (hard || from == -1) 1370 from = def; 1371 if (frm) 1372 *frm = from; 1373 return get_translation_table(from, to); 1374 } 1375 1376 struct document_options dd_opt; 1377 1378 struct document_options *d_opt = &dd_opt; 1379 1380 struct f_data *current_f_data = NULL; 1381 1382 void 1383 really_format_html(struct cache_entry *ce, unsigned char *start, 1384 unsigned char *end, struct f_data *screen, int frame) 1385 { 1386 unsigned char *url = ce->url; 1387 unsigned char *head, *t; 1388 size_t hdl; 1389 int i; 1390 unsigned char *bg = NULL, *bgcolor = NULL; 1391 int implicit_pre_wrap; 1392 int bg_col, fg_col; 1393 struct part *rp; 1394 1395 current_f_data = screen; 1396 d_opt = &screen->opt; 1397 screen->use_tag = ce->count; 1398 startf = start; 1399 eofff = end; 1400 head = NULL; 1401 hdl = 0; 1402 if (ce->head) 1403 hdl = add_to_str(&head, hdl, ce->head); 1404 hdl = scan_http_equiv(start, end, &head, hdl, &t, 1405 d_opt->plain ? NULL : &bg, 1406 d_opt->plain || d_opt->col < 2 ? NULL : &bgcolor, 1407 &implicit_pre_wrap); 1408 if (d_opt->break_long_lines) 1409 implicit_pre_wrap = 1; 1410 if (d_opt->plain) 1411 *t = 0; 1412 if (screen->opt.plain == 2) { 1413 screen->cp = 0; 1414 screen->ass = -1; 1415 convert_table = get_translation_table(0, screen->opt.cp); 1416 } else { 1417 convert_table = get_convert_table( 1418 head, screen->opt.cp, screen->opt.assume_cp, &screen->cp, 1419 &screen->ass, screen->opt.hard_assume); 1420 } 1421 screen->opt.real_cp = screen->cp; 1422 i = d_opt->plain; 1423 d_opt->plain = 0; 1424 screen->title = convert_string(convert_table, t, 1425 (int)strlen(cast_const_char t), d_opt); 1426 d_opt->plain = i; 1427 free(t); 1428 push_base_format(url, &screen->opt, frame, implicit_pre_wrap); 1429 table_level = 0; 1430 g_ctrl_num = 0; 1431 last_form_tag = NULL; 1432 last_form_attr = NULL; 1433 last_input_tag = NULL; 1434 if ((rp = format_html_part(start, end, par_format.align, 1435 par_format.leftmargin, screen->opt.xw, 1436 screen, 0, 0, head, 1))) 1437 free(rp); 1438 free(head); 1439 free(bg); 1440 free(bgcolor); 1441 screen->x = 0; 1442 for (i = screen->y - 1; i >= 0; i--) { 1443 if (!screen->data[i].l) { 1444 free(screen->data[i].d); 1445 screen->y--; 1446 } else { 1447 break; 1448 } 1449 } 1450 for (i = 0; i < screen->y; i++) 1451 if (screen->data[i].l > screen->x) 1452 screen->x = screen->data[i].l; 1453 free(form.action); 1454 free(form.target); 1455 free(form.form_name); 1456 free(form.onsubmit); 1457 form.action = NULL; 1458 form.target = NULL; 1459 form.form_name = NULL; 1460 form.onsubmit = NULL; 1461 bg_col = find_nearest_color(&format_.bg, 8); 1462 fg_col = find_nearest_color(&format_.fg, 16); 1463 fg_col = fg_color(fg_col, bg_col); 1464 screen->bg = get_attribute(fg_col, bg_col); 1465 kill_html_stack_item(&html_top); 1466 if (!list_empty(html_stack)) { 1467 internal("html stack not empty after operation"); 1468 init_list(html_stack); 1469 } 1470 sort_links(screen); 1471 current_f_data = NULL; 1472 d_opt = &dd_opt; 1473 } 1474 1475 int 1476 compare_opt(struct document_options *o1, struct document_options *o2) 1477 { 1478 if (o1->xw == o2->xw && o1->yw == o2->yw && o1->xp == o2->xp 1479 && o1->yp == o2->yp && o1->scrolling == o2->scrolling 1480 && o1->col == o2->col && o1->cp == o2->cp 1481 && o1->assume_cp == o2->assume_cp 1482 && o1->hard_assume == o2->hard_assume && o1->tables == o2->tables 1483 && o1->frames == o2->frames 1484 && o1->break_long_lines == o2->break_long_lines 1485 && o1->images == o2->images && o1->image_names == o2->image_names 1486 && o1->margin == o2->margin && o1->plain == o2->plain 1487 && o1->num_links == o2->num_links 1488 && o1->table_order == o2->table_order 1489 && o1->auto_refresh == o2->auto_refresh 1490 && o1->font_size == o2->font_size 1491 && o1->display_images == o2->display_images 1492 && o1->image_scale == o2->image_scale 1493 && o1->porn_enable == o2->porn_enable 1494 && o1->gamma_stamp == o2->gamma_stamp 1495 && !memcmp(&o1->default_fg, &o2->default_fg, sizeof(struct rgb)) 1496 && !memcmp(&o1->default_bg, &o2->default_bg, sizeof(struct rgb)) 1497 && !memcmp(&o1->default_link, &o2->default_link, sizeof(struct rgb)) 1498 && ((o1->framename && o2->framename 1499 && !casestrcmp(o1->framename, o2->framename)) 1500 || (!o1->framename && !o2->framename))) 1501 return 0; 1502 return 1; 1503 } 1504 1505 void 1506 copy_opt(struct document_options *o1, struct document_options *o2) 1507 { 1508 memcpy(o1, o2, sizeof(struct document_options)); 1509 o1->framename = stracpy(o2->framename); 1510 } 1511 1512 struct link * 1513 get_link_at_location(struct f_data *f, int x, int y) 1514 { 1515 struct link *l1, *l2, *l; 1516 if (y < 0 || y >= f->y) 1517 return NULL; 1518 l1 = f->lines1[y]; 1519 l2 = f->lines2[y]; 1520 if (!l1 || !l2) 1521 return NULL; 1522 for (l = l1; l <= l2; l++) { 1523 int i; 1524 for (i = 0; i < l->n; i++) 1525 if (l->pos[i].x == x && l->pos[i].y == y) 1526 return l; 1527 } 1528 return NULL; 1529 } 1530 1531 static int 1532 sort_srch(struct f_data *f) 1533 { 1534 int i; 1535 int *min, *max; 1536 if ((unsigned)f->y > INT_MAX / sizeof(struct search *)) 1537 overalloc(); 1538 if ((unsigned)f->y > INT_MAX / sizeof(int)) 1539 overalloc(); 1540 f->slines1 = xmalloc(f->y * sizeof(int)); 1541 f->slines2 = xmalloc(f->y * sizeof(int)); 1542 min = xmalloc(f->y * sizeof(int)); 1543 max = xmalloc(f->y * sizeof(int)); 1544 if (!f->slines1 || !f->slines2 || !min || !max) { 1545 free(f->slines1); 1546 free(f->slines2); 1547 f->slines1 = NULL; 1548 f->slines2 = NULL; 1549 free(min); 1550 free(max); 1551 return -1; 1552 } 1553 for (i = 0; i < f->y; i++) 1554 f->slines1[i] = f->slines2[i] = -1; 1555 for (i = 0; i < f->y; i++) { 1556 min[i] = INT_MAX; 1557 max[i] = 0; 1558 } 1559 for (i = 0; i < f->nsearch_pos; i++) { 1560 struct search *s = &f->search_pos[i]; 1561 int xe; 1562 if (s->x < min[s->y]) { 1563 min[s->y] = s->x; 1564 f->slines1[s->y] = s->idx; 1565 } 1566 if (s->n == 1) 1567 xe = safe_add(s->x, s->co); 1568 else 1569 xe = safe_add(s->x, s->n); 1570 if (xe > max[s->y]) { 1571 max[s->y] = xe; 1572 f->slines2[s->y] = s->idx + s->co - 1; 1573 } 1574 } 1575 free(min); 1576 free(max); 1577 return 0; 1578 } 1579 1580 static inline int 1581 is_spc(chr *cc) 1582 { 1583 return cc->ch <= ' ' || cc->at & ATTR_FRAME; 1584 } 1585 1586 static int n_chr, n_pos; 1587 static char_t srch_last_chr; 1588 static int srch_last_x, srch_last_y; 1589 static int srch_cont; 1590 1591 static void 1592 get_srch_reset(void) 1593 { 1594 n_chr = n_pos = 0; 1595 srch_last_chr = ' '; 1596 srch_last_x = srch_last_y = -1; 1597 srch_cont = 0; 1598 } 1599 1600 static int 1601 add_srch_chr(struct f_data *f, unsigned c, int x, int y, int nn) 1602 { 1603 if (c == ' ' && srch_last_chr == ' ') 1604 return 0; 1605 if (c == '_') { 1606 struct link *l = get_link_at_location(f, x, y); 1607 if (l 1608 && (l->type == L_SELECT || l->type == L_FIELD 1609 || l->type == L_AREA)) 1610 return 0; 1611 } 1612 srch_last_chr = c; 1613 if (f->search_chr) 1614 f->search_chr[n_chr] = c; 1615 if (n_chr == INT_MAX) 1616 return -1; 1617 n_chr++; 1618 if (srch_cont < 0xffff && x == srch_last_x + 1 && y == srch_last_y 1619 && nn == 1) { 1620 srch_cont++; 1621 if (f->search_pos) 1622 f->search_pos[n_pos - 1].co = (unsigned short)srch_cont; 1623 } else { 1624 if (f->search_pos) { 1625 f->search_pos[n_pos].idx = n_chr - 1; 1626 f->search_pos[n_pos].x = x; 1627 f->search_pos[n_pos].y = y; 1628 f->search_pos[n_pos].n = (unsigned short)nn; 1629 if (f->search_pos[n_pos].n != nn) 1630 f->search_pos[n_pos].n = (unsigned short)~0U; 1631 f->search_pos[n_pos].co = 1; 1632 } 1633 srch_cont = 1; 1634 if (n_pos == INT_MAX) 1635 return -1; 1636 n_pos++; 1637 } 1638 if (nn == 1) { 1639 srch_last_x = x; 1640 srch_last_y = y; 1641 } else { 1642 srch_last_x = -1; 1643 srch_last_y = -1; 1644 } 1645 return 0; 1646 } 1647 1648 static int 1649 get_srch(struct f_data *f) 1650 { 1651 struct node *n = NULL; 1652 struct list_head *ln; 1653 get_srch_reset(); 1654 #define add_srch(c_, x_, y_, n_) \ 1655 do { \ 1656 if (add_srch_chr(f, c_, x_, y_, n_)) \ 1657 return -1; \ 1658 } while (0) 1659 foreachback (struct node, n, ln, f->nodes) { 1660 int x, y; 1661 int xm = safe_add(n->x, n->xw), ym = safe_add(n->y, n->yw); 1662 /*printf("%d %d - %d %d\n", n->x, n->y, xm, ym); 1663 fflush(stdout);*/ 1664 for (y = n->y; y < ym && y < f->y; y++) { 1665 int ns = 1; 1666 for (x = n->x; x < xm && x < f->data[y].l; x++) { 1667 unsigned c = f->data[y].d[x].ch; 1668 if (is_spc(&f->data[y].d[x])) 1669 c = ' '; 1670 if (c == ' ' && ns) 1671 continue; 1672 c = charset_upcase(c, f->opt.cp); 1673 if (ns) { 1674 add_srch(c, x, y, 1); 1675 ns = 0; 1676 continue; 1677 } 1678 if (c != ' ') { 1679 add_srch(c, x, y, 1); 1680 } else { 1681 int xx; 1682 for (xx = safe_add(x, 1); 1683 xx < xm && xx < f->data[y].l; xx++) 1684 if (!is_spc(&f->data[y].d[xx])) 1685 goto ja_uz_z_toho_programovani_asi_zcvoknu; 1686 xx = x; 1687 ja_uz_z_toho_programovani_asi_zcvoknu: 1688 /* uz jsem zcvoknul, trpim poruchou 1689 * osobnosti */ 1690 add_srch(' ', x, y, xx - x); 1691 if (xx == x) 1692 goto uz_jsem_zcvoknul__jsem_psychopat__trpim_poruchou_osobnosti; 1693 x = xx - 1; 1694 } 1695 } 1696 uz_jsem_zcvoknul__jsem_psychopat__trpim_poruchou_osobnosti: 1697 add_srch(' ', x, y, 0); 1698 } 1699 } 1700 #undef add_srch 1701 return 0; 1702 } 1703 1704 int 1705 get_search_data(struct f_data *f) 1706 { 1707 if (f->search_pos) 1708 return 0; 1709 if (get_srch(f)) 1710 return -1; 1711 if ((size_t)n_chr > ((size_t)-1) / sizeof(char_t) 1712 || (size_t)n_pos > ((size_t)-1) / sizeof(struct search)) 1713 return -1; 1714 f->search_chr = xmalloc(n_chr * sizeof(char_t)); 1715 if (!f->search_chr) 1716 return -1; 1717 f->search_pos = xmalloc(n_pos * sizeof(struct search)); 1718 if (!f->search_pos) { 1719 free(f->search_chr); 1720 f->search_chr = NULL; 1721 return -1; 1722 } 1723 if (get_srch(f)) 1724 internal( 1725 "get_search_data: get_srch should not fail second time"); 1726 while (n_chr && f->search_chr[n_chr - 1] == ' ') 1727 n_chr--; 1728 f->nsearch_chr = n_chr; 1729 f->nsearch_pos = n_pos; 1730 if (sort_srch(f)) { 1731 free(f->search_pos); 1732 f->search_pos = NULL; 1733 free(f->search_chr); 1734 f->search_chr = NULL; 1735 f->nsearch_chr = f->nsearch_pos = 0; 1736 return -1; 1737 } 1738 return 0; 1739 }