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