1 #include "links.h"
2
3 struct list_head html_stack = {&html_stack, &html_stack};
4
atchr(unsigned char c)5 static inline int atchr(unsigned char c)
6 {
7 return /*isA(c) ||*/ (c > ' ' && c != '=' && c != '<' && c != '>');
8 }
9
parse_element(unsigned char * e,unsigned char * eof,unsigned char ** name,int * namelen,unsigned char ** attr,unsigned char ** end)10 int parse_element(unsigned char *e, unsigned char *eof, unsigned char **name, int *namelen, unsigned char **attr, unsigned char **end)
11 {
12 if (eof - e < 3 || *(e++) != '<') return -1;
13 if (name) *name = e;
14 if (*e == '/') e++;
15 if (!isA(*e)) return -1;
16 goto x1;
17 while (isA(*e) || *e == '=') {
18 x1:
19 e++;
20 if (e >= eof) return -1;
21 }
22 /*if ((!WHITECHAR(*e) && *e != '>' && *e != '<' && *e != '/' && *e != ':')) return -1;*/
23 if (name && namelen) *namelen = e - *name;
24 while ((WHITECHAR(*e) || *e == '/' || *e == ':')) {
25 e++;
26 if (e >= eof) return -1;
27 }
28 if ((!atchr(*e) && *e != '>' && *e != '<')) return -1;
29 if (attr) *attr = e;
30 nextattr:
31 while (WHITECHAR(*e)) {
32 e++;
33 if (e >= eof) return -1;
34 }
35 if ((!atchr(*e) && *e != '>' && *e != '<')) return -1;
36 if (*e == '>' || *e == '<') goto en;
37 while (atchr(*e)) {
38 e++;
39 if (e >= eof) return -1;
40 }
41 while (WHITECHAR(*e)) {
42 e++;
43 if (e >= eof) return -1;
44 }
45 if (*e != '=') goto endattr;
46 goto x2;
47 while (WHITECHAR(*e)) {
48 x2:
49 e++;
50 if (e >= eof) return -1;
51 }
52 if (U(*e)) {
53 unsigned char uu = *e;
54 /*u:*/
55 goto x3;
56 while (e < eof && *e != uu && *e /*(WHITECHAR(*e) || *e > ' ')*/) {
57 x3:
58 e++;
59 if (e >= eof) return -1;
60 }
61 if (*e < ' ') return -1;
62 e++;
63 if (e >= eof /*|| (!WHITECHAR(*e) && *e != uu && *e != '>' && *e != '<')*/) return -1;
64 /*if (*e == uu) goto u;*/
65 } else {
66 while (!WHITECHAR(*e) && *e != '>' && *e != '<') {
67 e++;
68 if (e >= eof) return -1;
69 }
70 }
71 while (WHITECHAR(*e)) {
72 e++;
73 if (e >= eof) return -1;
74 }
75 endattr:
76 if (*e != '>' && *e != '<') goto nextattr;
77 en:
78 if (end) *end = e + (*e == '>');
79 return 0;
80 }
81
82 #define add_chr(s, l, c) \
83 do { \
84 if (!((l) & (32 - 1))) { \
85 if ((unsigned)(l) > MAXINT - 32) overalloc(); \
86 (s) = mem_realloc((s), (l) + 32); \
87 } \
88 (s)[(l)++] = (c); \
89 } while (0)
90
91 int get_attr_val_nl = 0;
92
93 /* parses html element attributes */
94 /* e is attr pointer previously get from parse_element, DON'T PASS HERE ANY OTHER VALUE!!! */
95 /* name is searched attribute */
96 /* returns allocated string containing the attribute, or NULL on unsuccess */
get_attr_val(unsigned char * e,unsigned char * name)97 unsigned char *get_attr_val(unsigned char *e, unsigned char *name)
98 {
99 unsigned char *n;
100 unsigned char *a = DUMMY;
101 int l = 0;
102 int f;
103 aa:
104 while (WHITECHAR(*e)) e++;
105 if (*e == '>' || *e == '<') return NULL;
106 n = name;
107 while (*n && upcase(*e) == upcase(*n)) e++, n++;
108 f = *n;
109 while (atchr(*e)) f = 1, e++;
110 while (WHITECHAR(*e)) e++;
111 if (*e != '=') goto ea;
112 e++;
113 while (WHITECHAR(*e)) e++;
114 if (!U(*e)) {
115 while (!WHITECHAR(*e) && *e != '>' && *e != '<') {
116 if (!f) add_chr(a, l, *e);
117 e++;
118 }
119 } else {
120 char uu = *e;
121 /*a:*/
122 e++;
123 while (*e != uu) {
124 if (!*e) {
125 mem_free(a);
126 return NULL;
127 }
128 if (!f) {
129 if (get_attr_val_nl == 2) goto exact;
130 if (*e != 13) {
131 if (*e != 9 && *e != 10) exact:add_chr(a, l, *e);
132 else if (!get_attr_val_nl) add_chr(a, l, ' ');
133 }
134 }
135 e++;
136 }
137 e++;
138 /*if (*e == uu) {
139 if (!f) add_chr(a, l, *e);
140 goto a;
141 }*/
142 }
143 ea:
144 if (!f) {
145 unsigned char *b;
146 add_chr(a, l, 0);
147 if (strchr(a, '&')) {
148 unsigned char *aa = a;
149 int c = d_opt->cp;
150 d_opt->cp = d_opt->real_cp;
151 a = convert_string(NULL, aa, strlen(aa));
152 d_opt->cp = c;
153 mem_free(aa);
154 }
155 while ((b = strchr(a, 1))) *b = ' ';
156 if (get_attr_val_nl != 2) {
157 for (b = a; *b == ' '; b++);
158 if (b != a) memmove(a, b, strlen(b) + 1);
159 for (b = a + strlen(a) - 1; b >= a && *b == ' '; b--) *b = 0;
160 }
161 set_mem_comment(a, name, strlen(name));
162 return a;
163 }
164 goto aa;
165 }
166
has_attr(unsigned char * e,unsigned char * name)167 int has_attr(unsigned char *e, unsigned char *name)
168 {
169 char *a;
170 if (!(a = get_attr_val(e, name))) return 0;
171 mem_free(a);
172 return 1;
173 }
174
175 /*
176 unsigned char *get_url_val(unsigned char *e, unsigned char *name)
177 {
178 int n = 0;
179 unsigned char *p, *q, *pp;
180 if (!(pp = get_attr_val(e, name))) return NULL;
181 p = pp; q = pp;
182 while (1) {
183 if (*p == '#') n = 1;
184 if ((*p = *q) != ' ' || n) p++;
185 if (!*q) break;
186 q++;
187 }
188 return pp;
189 }
190 */
191
get_url_val(unsigned char * e,unsigned char * name)192 unsigned char *get_url_val(unsigned char *e, unsigned char *name)
193 {
194 unsigned char *a;
195 get_attr_val_nl = 1;
196 a = get_attr_val(e, name);
197 get_attr_val_nl = 0;
198 return a;
199 }
200
get_exact_attr_val(unsigned char * e,unsigned char * name)201 unsigned char *get_exact_attr_val(unsigned char *e, unsigned char *name)
202 {
203 unsigned char *a;
204 get_attr_val_nl = 2;
205 a = get_attr_val(e, name);
206 get_attr_val_nl = 0;
207 if (a) {
208 unsigned char *x1, *x2;
209 for (x1 = x2 = a; *x1; x1++, x2++) {
210 if (x1[0] == '\r') {
211 *x2 = '\n';
212 if (x1[1] == '\n') x1++;
213 } else {
214 *x2 = *x1;
215 }
216 }
217 *x2 = 0;
218 }
219 return a;
220 }
221
222 struct {
223 unsigned short int n;
224 char *s;
225 } roman_tbl[] = {
226 { 1000, "m" },
227 { 999, "im" },
228 /* { 995, "vm" },*/
229 { 990, "xm" },
230 /* { 950, "lm" },*/
231 { 900, "cm" },
232 { 500, "d" },
233 { 499, "id" },
234 /* { 495, "vd" },*/
235 { 490, "xd" },
236 /* { 450, "ld" },*/
237 { 400, "cd" },
238 { 100, "c" },
239 { 99, "ic" },
240 /* { 95, "vc" },*/
241 { 90, "xc" },
242 { 50, "l" },
243 { 49, "il" },
244 /* { 45, "vl" },*/
245 { 40, "xl" },
246 { 10, "x" },
247 { 9, "ix" },
248 { 5, "v" },
249 { 4, "iv" },
250 { 1, "i" },
251 { 0, NULL },
252 };
253
roman(char * p,unsigned n)254 void roman(char *p, unsigned n)
255 {
256 int i = 0;
257 if (n >= 4000) {
258 strcpy(p, "---");
259 return;
260 }
261 if (!n) {
262 strcpy(p, "o");
263 return;
264 }
265 p[0] = 0;
266 while (n) {
267 while (roman_tbl[i].n <= n) {
268 n -= roman_tbl[i].n;
269 strcat(p, roman_tbl[i].s);
270 }
271 i++;
272 if (n && !roman_tbl[i].n) {
273 internal("BUG in roman number convertor");
274 return;
275 }
276 }
277 }
278
279 struct color_spec {
280 char *name;
281 int rgb;
282 };
283
284 struct color_spec color_specs[] = {
285 {"aliceblue", 0xF0F8FF},
286 {"antiquewhite", 0xFAEBD7},
287 {"aqua", 0x00FFFF},
288 {"aquamarine", 0x7FFFD4},
289 {"azure", 0xF0FFFF},
290 {"beige", 0xF5F5DC},
291 {"bisque", 0xFFE4C4},
292 {"black", 0x000000},
293 {"blanchedalmond", 0xFFEBCD},
294 {"blue", 0x0000FF},
295 {"blueviolet", 0x8A2BE2},
296 {"brown", 0xA52A2A},
297 {"burlywood", 0xDEB887},
298 {"cadetblue", 0x5F9EA0},
299 {"chartreuse", 0x7FFF00},
300 {"chocolate", 0xD2691E},
301 {"coral", 0xFF7F50},
302 {"cornflowerblue", 0x6495ED},
303 {"cornsilk", 0xFFF8DC},
304 {"crimson", 0xDC143C},
305 {"cyan", 0x00FFFF},
306 {"darkblue", 0x00008B},
307 {"darkcyan", 0x008B8B},
308 {"darkgoldenrod", 0xB8860B},
309 {"darkgray", 0xA9A9A9},
310 {"darkgreen", 0x006400},
311 {"darkkhaki", 0xBDB76B},
312 {"darkmagenta", 0x8B008B},
313 {"darkolivegreen", 0x556B2F},
314 {"darkorange", 0xFF8C00},
315 {"darkorchid", 0x9932CC},
316 {"darkred", 0x8B0000},
317 {"darksalmon", 0xE9967A},
318 {"darkseagreen", 0x8FBC8F},
319 {"darkslateblue", 0x483D8B},
320 {"darkslategray", 0x2F4F4F},
321 {"darkturquoise", 0x00CED1},
322 {"darkviolet", 0x9400D3},
323 {"deeppink", 0xFF1493},
324 {"deepskyblue", 0x00BFFF},
325 {"dimgray", 0x696969},
326 {"dodgerblue", 0x1E90FF},
327 {"firebrick", 0xB22222},
328 {"floralwhite", 0xFFFAF0},
329 {"forestgreen", 0x228B22},
330 {"fuchsia", 0xFF00FF},
331 {"gainsboro", 0xDCDCDC},
332 {"ghostwhite", 0xF8F8FF},
333 {"gold", 0xFFD700},
334 {"goldenrod", 0xDAA520},
335 {"gray", 0x808080},
336 {"green", 0x008000},
337 {"greenyellow", 0xADFF2F},
338 {"honeydew", 0xF0FFF0},
339 {"hotpink", 0xFF69B4},
340 {"indianred", 0xCD5C5C},
341 {"indigo", 0x4B0082},
342 {"ivory", 0xFFFFF0},
343 {"khaki", 0xF0E68C},
344 {"lavender", 0xE6E6FA},
345 {"lavenderblush", 0xFFF0F5},
346 {"lawngreen", 0x7CFC00},
347 {"lemonchiffon", 0xFFFACD},
348 {"lightblue", 0xADD8E6},
349 {"lightcoral", 0xF08080},
350 {"lightcyan", 0xE0FFFF},
351 {"lightgoldenrodyellow", 0xFAFAD2},
352 {"lightgreen", 0x90EE90},
353 {"lightgrey", 0xD3D3D3},
354 {"lightpink", 0xFFB6C1},
355 {"lightsalmon", 0xFFA07A},
356 {"lightseagreen", 0x20B2AA},
357 {"lightskyblue", 0x87CEFA},
358 {"lightslategray", 0x778899},
359 {"lightsteelblue", 0xB0C4DE},
360 {"lightyellow", 0xFFFFE0},
361 {"lime", 0x00FF00},
362 {"limegreen", 0x32CD32},
363 {"linen", 0xFAF0E6},
364 {"magenta", 0xFF00FF},
365 {"maroon", 0x800000},
366 {"mediumaquamarine", 0x66CDAA},
367 {"mediumblue", 0x0000CD},
368 {"mediumorchid", 0xBA55D3},
369 {"mediumpurple", 0x9370DB},
370 {"mediumseagreen", 0x3CB371},
371 {"mediumslateblue", 0x7B68EE},
372 {"mediumspringgreen", 0x00FA9A},
373 {"mediumturquoise", 0x48D1CC},
374 {"mediumvioletred", 0xC71585},
375 {"midnightblue", 0x191970},
376 {"mintcream", 0xF5FFFA},
377 {"mistyrose", 0xFFE4E1},
378 {"moccasin", 0xFFE4B5},
379 {"navajowhite", 0xFFDEAD},
380 {"navy", 0x000080},
381 {"oldlace", 0xFDF5E6},
382 {"olive", 0x808000},
383 {"olivedrab", 0x6B8E23},
384 {"orange", 0xFFA500},
385 {"orangered", 0xFF4500},
386 {"orchid", 0xDA70D6},
387 {"palegoldenrod", 0xEEE8AA},
388 {"palegreen", 0x98FB98},
389 {"paleturquoise", 0xAFEEEE},
390 {"palevioletred", 0xDB7093},
391 {"papayawhip", 0xFFEFD5},
392 {"peachpuff", 0xFFDAB9},
393 {"peru", 0xCD853F},
394 {"pink", 0xFFC0CB},
395 {"plum", 0xDDA0DD},
396 {"powderblue", 0xB0E0E6},
397 {"purple", 0x800080},
398 {"red", 0xFF0000},
399 {"rosybrown", 0xBC8F8F},
400 {"royalblue", 0x4169E1},
401 {"saddlebrown", 0x8B4513},
402 {"salmon", 0xFA8072},
403 {"sandybrown", 0xF4A460},
404 {"seagreen", 0x2E8B57},
405 {"seashell", 0xFFF5EE},
406 {"sienna", 0xA0522D},
407 {"silver", 0xC0C0C0},
408 {"skyblue", 0x87CEEB},
409 {"slateblue", 0x6A5ACD},
410 {"slategray", 0x708090},
411 {"snow", 0xFFFAFA},
412 {"springgreen", 0x00FF7F},
413 {"steelblue", 0x4682B4},
414 {"tan", 0xD2B48C},
415 {"teal", 0x008080},
416 {"thistle", 0xD8BFD8},
417 {"tomato", 0xFF6347},
418 {"turquoise", 0x40E0D0},
419 {"violet", 0xEE82EE},
420 {"wheat", 0xF5DEB3},
421 {"white", 0xFFFFFF},
422 {"whitesmoke", 0xF5F5F5},
423 {"yellow", 0xFFFF00},
424 {"yellowgreen", 0x9ACD32},
425 };
426
427 #define endof(T) ((T)+sizeof(T)/sizeof(*(T)))
428
decode_color(unsigned char * str,struct rgb * col)429 int decode_color(unsigned char *str, struct rgb *col)
430 {
431 unsigned long ch;
432 if (*str != '#') {
433 struct color_spec *cs;
434 for (cs = color_specs; cs < endof(color_specs); cs++)
435 if (!strcasecmp(cs->name, str)) {
436 ch = cs->rgb;
437 goto found;
438 }
439 } else {
440 str++;
441 }
442 if (strlen(str) == 6) {
443 char *end;
444 ch = strtoul(str, &end, 16);
445 if (!*end && ch < 0x1000000) {
446 found:
447 col->r = ch / 0x10000;
448 col->g = ch / 0x100 % 0x100;
449 col->b = ch % 0x100;
450 return 0;
451 }
452 }
453 return -1;
454 }
455
get_color(unsigned char * a,unsigned char * c,struct rgb * rgb)456 int get_color(unsigned char *a, unsigned char *c, struct rgb *rgb)
457 {
458 char *at;
459 int r = -1;
460 if (d_opt->col >= 1) if ((at = get_attr_val(a, c))) {
461 r = decode_color(at, rgb);
462 mem_free(at);
463 }
464 return r;
465 }
466
get_bgcolor(unsigned char * a,struct rgb * rgb)467 int get_bgcolor(unsigned char *a, struct rgb *rgb)
468 {
469 if (d_opt->col < 2) return -1;
470 return get_color(a, "bgcolor", rgb);
471 }
472
get_target(unsigned char * a)473 unsigned char *get_target(unsigned char *a)
474 {
475 unsigned char *v = get_attr_val(a, "target");
476 if (v) {
477 if (!strcasecmp(v, "_self")) {
478 mem_free(v);
479 v = stracpy(d_opt->framename);
480 }
481 }
482 return v;
483 }
484
kill_html_stack_item(struct html_element * e)485 void kill_html_stack_item(struct html_element *e)
486 {
487 if (!e || (void *)e == &html_stack) {
488 internal("trying to free bad html element");
489 return;
490 }
491 if (e->dontkill == 2) {
492 internal("trying to kill unkillable element");
493 return;
494 }
495 if (e->attr.link) mem_free(e->attr.link);
496 if (e->attr.target) mem_free(e->attr.target);
497 if (e->attr.image) mem_free(e->attr.image);
498 if (e->attr.href_base) mem_free(e->attr.href_base);
499 if (e->attr.target_base) mem_free(e->attr.target_base);
500 if (e->attr.select) mem_free(e->attr.select);
501 del_from_list(e);
502 mem_free(e);
503 /*if ((void *)(html_stack.next) == &html_stack || !html_stack.next) {
504 debug("killing last element");
505 }*/
506 }
507
508 #ifdef DEBUG
debug_stack()509 void debug_stack()
510 {
511 struct html_element *e;
512 printf("HTML stack debug: \n");
513 foreachback(e, html_stack) {
514 int i;
515 printf("\"");
516 for (i = 0; i < e->namelen; i++) printf("%c", e->name[i]);
517 printf("\"\n");
518 }
519 printf("%c", 7);
520 fflush(stdout);
521 sleep(1);
522 }
523 #endif
524
html_stack_dup()525 void html_stack_dup()
526 {
527 struct html_element *e;
528 struct html_element *ep;
529 if ((void *)(ep = html_stack.next) == &html_stack || !html_stack.next) {
530 internal("html stack empty");
531 return;
532 }
533 e = mem_alloc(sizeof(struct html_element));
534 memcpy(e, ep, sizeof(struct html_element));
535 e->attr.link = stracpy(ep->attr.link);
536 e->attr.target = stracpy(ep->attr.target);
537 e->attr.image = stracpy(ep->attr.image);
538 e->attr.href_base = stracpy(ep->attr.href_base);
539 e->attr.target_base = stracpy(ep->attr.target_base);
540 e->attr.select = stracpy(ep->attr.select);
541 /*if (e->name) {
542 if (e->attr.link) set_mem_comment(e->attr.link, e->name, e->namelen);
543 if (e->attr.target) set_mem_comment(e->attr.target, e->name, e->namelen);
544 if (e->attr.image) set_mem_comment(e->attr.image, e->name, e->namelen);
545 if (e->attr.href_base) set_mem_comment(e->attr.href_base, e->name, e->namelen);
546 if (e->attr.target_base) set_mem_comment(e->attr.target_base, e->name, e->namelen);
547 if (e->attr.select) set_mem_comment(e->attr.select, e->name, e->namelen);
548 }*/
549 e->name = e->options = NULL;
550 e->namelen = 0;
551 e->dontkill = 0;
552 add_to_list(html_stack, e);
553 }
554
555 void *ff;
556 int (*put_chars_f)(void *, unsigned char *, int);
557 void (*line_break_f)(void *);
558 void *(*special_f)(void *, int, ...);
559
560 unsigned char *eoff;
561 unsigned char *eofff;
562 unsigned char *startf;
563
564 int line_breax;
565 int pos;
566 int putsp;
567
568 int was_br;
569 int table_level;
570 int empty_format;
571
ln_break(int n,void (* line_break)(void *),void * f)572 void ln_break(int n, void (*line_break)(void *), void *f)
573 {
574 if (!n || html_top.invisible) return;
575 while (n > line_breax) line_breax++, line_break(f);
576 pos = 0;
577 putsp = -1;
578 }
579
put_chrs(unsigned char * start,int len,int (* put_chars)(void *,unsigned char *,int),void * f)580 void put_chrs(unsigned char *start, int len, int (*put_chars)(void *, unsigned char *, int), void *f)
581 {
582 if (par_format.align == AL_NO) putsp = 0;
583 if (!len || html_top.invisible) return;
584 if (putsp == 1) pos += put_chars(f, " ", 1), putsp = -1;
585 if (putsp == -1) {
586 if (start[0] == ' ') start++, len--;
587 putsp = 0;
588 }
589 if (!len) {
590 putsp = -1;
591 if (par_format.align == AL_NO) putsp = 0;
592 return;
593 }
594 if (start[len - 1] == ' ') putsp = -1;
595 if (par_format.align == AL_NO) putsp = 0;
596 was_br = 0;
597 pos += put_chars(f, start, len);
598 line_breax = 0;
599 }
600
kill_until(int ls,...)601 void kill_until(int ls, ...)
602 {
603 int l;
604 struct html_element *e = &html_top;
605 if (ls) e = e->next;
606 while ((void *)e != &html_stack) {
607 int sk = 0;
608 va_list arg;
609 va_start(arg, ls);
610 while (1) {
611 char *s = va_arg(arg, char *);
612 if (!s) break;
613 if (!*s) sk++;
614 else if ((size_t)e->namelen == strlen(s) && !casecmp(e->name, s, strlen(s))) {
615 if (!sk) {
616 if (e->dontkill) break;
617 va_end(arg);
618 goto killll;
619 } else if (sk == 1) {
620 va_end(arg);
621 goto killl;
622 } else break;
623 }
624 }
625 va_end(arg);
626 if (e->dontkill || (e->namelen == 5 && !casecmp(e->name, "TABLE", 5))) break;
627 if (e->namelen == 2 && upcase(e->name[0]) == 'T' && (upcase(e->name[1]) == 'D' || upcase(e->name[1]) == 'H' || upcase(e->name[1]) == 'R')) break;
628 e = e->next;
629 }
630 return;
631 killl:
632 e = e->prev;
633 killll:
634 l = 0;
635 while ((void *)e != &html_stack) {
636 if (ls && e == html_stack.next) break;
637 if (e->linebreak > l) l = e->linebreak;
638 e = e->prev;
639 kill_html_stack_item(e->next);
640 }
641 ln_break(l, line_break_f, ff);
642 }
643
top_href_base(void)644 static inline unsigned char *top_href_base(void)
645 {
646 return ((struct html_element *)html_stack.prev)->attr.href_base;
647 }
648
get_num(unsigned char * a,unsigned char * n)649 int get_num(unsigned char *a, unsigned char *n)
650 {
651 char *al;
652 if ((al = get_attr_val(a, n))) {
653 char *end;
654 unsigned long s = strtoul(al, &end, 10);
655 if (!*al || *end || s > 10000) s = -1;
656 mem_free(al);
657 return s;
658 }
659 return -1;
660 }
661
parse_width(unsigned char * w,int trunc)662 int parse_width(unsigned char *w, int trunc)
663 {
664 unsigned char *end;
665 int p = 0;
666 long s;
667 int l;
668 while (WHITECHAR(*w)) w++;
669 for (l = 0; w[l] && w[l] != ','; l++) ;
670 while (l && WHITECHAR(w[l - 1])) l--;
671 if (!l) return -1;
672 if (w[l - 1] == '%') l--, p = 1;
673 while (l && WHITECHAR(w[l - 1])) l--;
674 if (!l) return -1;
675 s = strtoul((char *)w, (char **)(void *)&end, 10);
676 if (end - w < l || s < 0 || s > 10000) return -1;
677 if (p) {
678 if (trunc) s = s * (par_format.width - par_format.leftmargin - par_format.rightmargin) / 100;
679 else return -1;
680 } else s = (s + (HTML_CHAR_WIDTH - 1) / 2) / HTML_CHAR_WIDTH;
681 if (trunc && s > par_format.width - par_format.leftmargin - par_format.rightmargin) s = par_format.width - par_format.leftmargin - par_format.rightmargin;
682 if (s < 0) s = 0;
683 return s;
684 }
685
get_width(unsigned char * a,unsigned char * n,int trunc)686 int get_width(unsigned char *a, unsigned char *n, int trunc)
687 {
688 int r;
689 unsigned char *w;
690 if (!(w = get_attr_val(a, n))) return -1;
691 r = parse_width(w, trunc);
692 mem_free(w);
693 return r;
694 }
695
696 struct form form = { NULL, NULL, 0, 0 };
697
698 unsigned char *last_form_tag;
699 unsigned char *last_form_attr;
700 unsigned char *last_input_tag;
701
put_link_line(unsigned char * prefix,unsigned char * linkname,unsigned char * link,unsigned char * target)702 void put_link_line(unsigned char *prefix, unsigned char *linkname, unsigned char *link, unsigned char *target)
703 {
704 html_stack_dup();
705 ln_break(1, line_break_f, ff);
706 if (format_.link) mem_free(format_.link), format_.link = NULL;
707 if (format_.target) mem_free(format_.target), format_.target = NULL;
708 format_.form = NULL;
709 put_chrs(prefix, strlen(prefix), put_chars_f, ff);
710 format_.link = join_urls(format_.href_base, link);
711 format_.target = stracpy(target);
712 memcpy(&format_.fg, &format_.clink, sizeof(struct rgb));
713 put_chrs(linkname, strlen(linkname), put_chars_f, ff);
714 ln_break(1, line_break_f, ff);
715 kill_html_stack_item(&html_top);
716 }
717
html_span(unsigned char * a)718 void html_span(unsigned char *a) { }
html_bold(unsigned char * a)719 void html_bold(unsigned char *a) { format_.attr |= AT_BOLD; }
html_italic(unsigned char * a)720 void html_italic(unsigned char *a) { format_.attr |= AT_ITALIC; }
html_underline(unsigned char * a)721 void html_underline(unsigned char *a) { format_.attr |= AT_UNDERLINE; }
html_fixed(unsigned char * a)722 void html_fixed(unsigned char *a) { format_.attr |= AT_FIXED; }
723
html_a(unsigned char * a)724 void html_a(unsigned char *a)
725 {
726 char *al;
727 if ((al = get_url_val(a, "href"))) {
728 char *all = al;
729 while (all[0] == ' ') all++;
730 while (all[0] && all[strlen(all) - 1] == ' ') all[strlen(all) - 1] = 0;
731 if (format_.link) mem_free(format_.link);
732 format_.link = join_urls(format_.href_base, all);
733 mem_free(al);
734 if ((al = get_target(a))) {
735 if (format_.target) mem_free(format_.target);
736 format_.target = al;
737 } else {
738 if (format_.target) mem_free(format_.target);
739 format_.target = stracpy(format_.target_base);
740 }
741 /*format_.attr ^= AT_BOLD;*/
742 memcpy(&format_.fg, &format_.clink, sizeof(struct rgb));
743 } else kill_html_stack_item(&html_top);
744 if ((al = get_attr_val(a, "name"))) {
745 special_f(ff, SP_TAG, al);
746 mem_free(al);
747 }
748 }
749
html_font(unsigned char * a)750 void html_font(unsigned char *a)
751 {
752 char *al;
753 if ((al = get_attr_val(a, "size"))) {
754 int p = 0;
755 unsigned long s;
756 char *nn = al;
757 char *end;
758 if (*al == '+') p = 1, nn++;
759 if (*al == '-') p = -1, nn++;
760 s = strtoul(nn, &end, 10);
761 if (*nn && !*end) {
762 if (s > 7) s = 7;
763 if (!p) format_.fontsize = s;
764 else format_.fontsize += p * s;
765 if (format_.fontsize < 1) format_.fontsize = 1;
766 if (format_.fontsize > 7) format_.fontsize = 7;
767 }
768 mem_free(al);
769 }
770 get_color(a, "color", &format_.fg);
771 }
772
html_img(unsigned char * a)773 void html_img(unsigned char *a)
774 {
775 unsigned char *al;
776 int ismap, usemap = 0;
777 /*put_chrs(" ", 1, put_chars_f, ff);*/
778 if ((al = get_attr_val(a, "usemap"))) {
779 unsigned char *u;
780 usemap = 1;
781 html_stack_dup();
782 if (format_.link) mem_free(format_.link);
783 if (format_.form) format_.form = NULL;
784 u = join_urls(*al == '#' ? top_href_base() : format_.href_base, al);
785 format_.link = mem_alloc(strlen(u) + 5);
786 strcpy(format_.link, "MAP@");
787 strcat(format_.link, u);
788 format_.attr |= AT_BOLD;
789 mem_free(u);
790 mem_free(al);
791 }
792 ismap = format_.link && has_attr(a, "ismap") && !usemap;
793 if ((!(al = get_attr_val(a, "alt")) && !(al = get_attr_val(a, "title"))) || !*al) {
794 if (al) mem_free(al);
795 if (!d_opt->images && !format_.link) return;
796 if (usemap) al = stracpy("[USEMAP]");
797 else if (ismap) al = stracpy("[ISMAP]");
798 else al = stracpy("[IMG]");
799 }
800 if (format_.image) mem_free(format_.image), format_.image = NULL;
801 if (al) {
802 unsigned char *s;
803 if ((s = get_url_val(a, "src")) || (s = get_attr_val(a, "dynsrc"))) {
804 format_.image = join_urls(format_.href_base, s);
805 mem_free(s);
806 }
807 if (ismap) {
808 unsigned char *h;
809 html_stack_dup();
810 h = stracpy(format_.link);
811 add_to_strn(&h, "?0,0");
812 mem_free(format_.link);
813 format_.link = h;
814 }
815 put_chrs(al, strlen(al), put_chars_f, ff);
816 if (ismap) kill_html_stack_item(&html_top);
817 }
818 if (format_.image) mem_free(format_.image), format_.image = NULL;
819 mem_free(al);
820 if (usemap) kill_html_stack_item(&html_top);
821 /*put_chrs(" ", 1, put_chars_f, ff);*/
822 }
823
html_body(unsigned char * a)824 void html_body(unsigned char *a)
825 {
826 get_color(a, "text", &format_.fg);
827 get_color(a, "link", &format_.clink);
828 get_color(a, "vlink", &format_.vlink);
829 get_bgcolor(a, &format_.bg);
830 get_bgcolor(a, &par_format.bgcolor);
831 }
832
html_skip(unsigned char * a)833 void html_skip(unsigned char *a) { html_top.invisible = html_top.dontkill = 1; }
834
html_title(unsigned char * a)835 void html_title(unsigned char *a) { html_top.invisible = html_top.dontkill = 1; }
836
html_center(unsigned char * a)837 void html_center(unsigned char *a)
838 {
839 par_format.align = AL_CENTER;
840 if (!table_level) par_format.leftmargin = par_format.rightmargin = 0;
841 }
842
html_linebrk(unsigned char * a)843 void html_linebrk(unsigned char *a)
844 {
845 char *al;
846 if ((al = get_attr_val(a, "align"))) {
847 if (!strcasecmp(al, "left")) par_format.align = AL_LEFT;
848 if (!strcasecmp(al, "right")) par_format.align = AL_RIGHT;
849 if (!strcasecmp(al, "center")) {
850 par_format.align = AL_CENTER;
851 if (!table_level) par_format.leftmargin = par_format.rightmargin = 0;
852 }
853 if (!strcasecmp(al, "justify")) par_format.align = AL_BLOCK;
854 mem_free(al);
855 }
856 }
857
html_br(unsigned char * a)858 void html_br(unsigned char *a)
859 {
860 html_linebrk(a);
861 if (was_br) ln_break(2, line_break_f, ff);
862 was_br = 1;
863 }
864
html_form(unsigned char * a)865 void html_form(unsigned char *a)
866 {
867 was_br = 1;
868 }
869
html_p(unsigned char * a)870 void html_p(unsigned char *a)
871 {
872 if (par_format.leftmargin < margin) par_format.leftmargin = margin;
873 if (par_format.rightmargin < margin) par_format.rightmargin = margin;
874 /*par_format.align = AL_LEFT;*/
875 html_linebrk(a);
876 }
877
html_address(unsigned char * a)878 void html_address(unsigned char *a)
879 {
880 par_format.leftmargin += 1;
881 par_format.align = AL_LEFT;
882 }
883
html_blockquote(unsigned char * a)884 void html_blockquote(unsigned char *a)
885 {
886 par_format.leftmargin += 2;
887 par_format.align = AL_LEFT;
888 }
889
html_h(int h,char * a)890 void html_h(int h, char *a)
891 {
892 do_not_optimize_here(&h);
893 par_format.align = AL_LEFT;
894 html_linebrk(a);
895 switch (par_format.align) {
896 case AL_LEFT:
897 par_format.leftmargin = (h - 2) * 2;
898 par_format.rightmargin = 0;
899 break;
900 case AL_RIGHT:
901 par_format.leftmargin = 0;
902 par_format.rightmargin = (h - 2) * 2;
903 break;
904 case AL_CENTER:
905 par_format.leftmargin = par_format.rightmargin = 0;
906 break;
907 case AL_BLOCK:
908 par_format.leftmargin = par_format.rightmargin = (h - 2) * 2;
909 break;
910 }
911 }
912
html_h2(unsigned char * a)913 void html_h2(unsigned char *a) { html_h(2, a); }
html_h3(unsigned char * a)914 void html_h3(unsigned char *a) { html_h(3, a); }
html_h4(unsigned char * a)915 void html_h4(unsigned char *a) { html_h(4, a); }
html_h5(unsigned char * a)916 void html_h5(unsigned char *a) { html_h(5, a); }
html_h6(unsigned char * a)917 void html_h6(unsigned char *a) { html_h(6, a); }
918
html_pre(unsigned char * a)919 void html_pre(unsigned char *a)
920 {
921 par_format.align = AL_NO;
922 par_format.leftmargin = par_format.leftmargin > 1;
923 par_format.rightmargin = 0;
924 }
925
html_hr(unsigned char * a)926 void html_hr(unsigned char *a)
927 {
928 int i/* = par_format.width - 10*/;
929 unsigned char r = 205;
930 int q = get_num(a, "size");
931 if (q >= 0 && q < 2) r = 196;
932 html_stack_dup();
933 par_format.align = AL_CENTER;
934 if (format_.link) mem_free(format_.link), format_.link = NULL;
935 format_.form = NULL;
936 html_linebrk(a);
937 if (par_format.align == AL_BLOCK) par_format.align = AL_CENTER;
938 par_format.leftmargin = margin;
939 par_format.rightmargin = margin;
940 if ((i = get_width(a, "width", 1)) == -1) i = par_format.width - 2 * margin - 4;
941 format_.attr = AT_GRAPHICS;
942 special_f(ff, SP_NOWRAP, 1);
943 while (i-- > 0) put_chrs(&r, 1, put_chars_f, ff);
944 special_f(ff, SP_NOWRAP, 0);
945 ln_break(2, line_break_f, ff);
946 kill_html_stack_item(&html_top);
947 }
948
html_table(unsigned char * a)949 void html_table(unsigned char *a)
950 {
951 par_format.leftmargin = margin;
952 par_format.rightmargin = margin;
953 par_format.align = AL_LEFT;
954 html_linebrk(a);
955 format_.attr = 0;
956 }
957
html_tr(unsigned char * a)958 void html_tr(unsigned char *a)
959 {
960 html_linebrk(a);
961 }
962
html_th(unsigned char * a)963 void html_th(unsigned char *a)
964 {
965 /*html_linebrk(a);*/
966 kill_until(1, "TD", "TH", "", "TR", "TABLE", NULL);
967 format_.attr |= AT_BOLD;
968 put_chrs(" ", 1, put_chars_f, ff);
969 }
970
html_td(unsigned char * a)971 void html_td(unsigned char *a)
972 {
973 /*html_linebrk(a);*/
974 kill_until(1, "TD", "TH", "", "TR", "TABLE", NULL);
975 format_.attr &= ~AT_BOLD;
976 put_chrs(" ", 1, put_chars_f, ff);
977 }
978
html_base(unsigned char * a)979 void html_base(unsigned char *a)
980 {
981 char *al;
982 if ((al = get_url_val(a, "href"))) {
983 if (format_.href_base) mem_free(format_.href_base);
984 format_.href_base = join_urls(top_href_base(), al);
985 mem_free(al);
986 }
987 if ((al = get_target(a))) {
988 if (format_.target_base) mem_free(format_.target_base);
989 format_.target_base = al;
990 }
991 }
992
html_ul(unsigned char * a)993 void html_ul(unsigned char *a)
994 {
995 char *al;
996 /*debug_stack();*/
997 par_format.list_level++;
998 par_format.list_number = 0;
999 par_format.flags = P_STAR;
1000 if ((al = get_attr_val(a, "type"))) {
1001 if (!strcasecmp(al, "disc") || !strcasecmp(al, "circle")) par_format.flags = P_O;
1002 if (!strcasecmp(al, "square")) par_format.flags = P_PLUS;
1003 mem_free(al);
1004 }
1005 if ((par_format.leftmargin += 2 + (par_format.list_level > 1)) > par_format.width * 2 / 3 && !table_level)
1006 par_format.leftmargin = par_format.width * 2 / 3;
1007 par_format.align = AL_LEFT;
1008 html_top.dontkill = 1;
1009 }
1010
html_ol(unsigned char * a)1011 void html_ol(unsigned char *a)
1012 {
1013 char *al;
1014 int st;
1015 par_format.list_level++;
1016 st = get_num(a, "start");
1017 if (st == -1) st = 1;
1018 par_format.list_number = st;
1019 par_format.flags = P_NUMBER;
1020 if ((al = get_attr_val(a, "type"))) {
1021 if (!strcmp(al, "1")) par_format.flags = P_NUMBER;
1022 if (!strcmp(al, "a")) par_format.flags = P_alpha;
1023 if (!strcmp(al, "A")) par_format.flags = P_ALPHA;
1024 if (!strcmp(al, "r")) par_format.flags = P_roman;
1025 if (!strcmp(al, "R")) par_format.flags = P_ROMAN;
1026 if (!strcmp(al, "i")) par_format.flags = P_roman;
1027 if (!strcmp(al, "I")) par_format.flags = P_ROMAN;
1028 mem_free(al);
1029 }
1030 if ((par_format.leftmargin += (par_format.list_level > 1)) > par_format.width * 2 / 3 && !table_level)
1031 par_format.leftmargin = par_format.width * 2 / 3;
1032 par_format.align = AL_LEFT;
1033 html_top.dontkill = 1;
1034 }
1035
html_li(unsigned char * a)1036 void html_li(unsigned char *a)
1037 {
1038 /*kill_until(0, "", "UL", "OL", NULL);*/
1039 if (!par_format.list_number) {
1040 char x[7] = "* ";
1041 if ((par_format.flags & P_LISTMASK) == P_O) x[0] = 'o';
1042 if ((par_format.flags & P_LISTMASK) == P_PLUS) x[0] = '+';
1043 put_chrs(x, 7, put_chars_f, ff);
1044 par_format.leftmargin += 2;
1045 par_format.align = AL_LEFT;
1046 putsp = -1;
1047 } else {
1048 char c = 0;
1049 char n[32];
1050 int t = par_format.flags & P_LISTMASK;
1051 int s = get_num(a, "value");
1052 if (s != -1) par_format.list_number = s;
1053 if ((t != P_roman && t != P_ROMAN && par_format.list_number < 10) || t == P_alpha || t == P_ALPHA) put_chrs(" ", 6, put_chars_f, ff), c = 1;
1054 if (t == P_ALPHA || t == P_alpha) {
1055 n[0] = par_format.list_number ? (par_format.list_number - 1) % 26 + (t == P_ALPHA ? 'A' : 'a') : 0;
1056 n[1] = 0;
1057 } else if (t == P_ROMAN || t == P_roman) {
1058 roman(n, par_format.list_number);
1059 if (t == P_ROMAN) {
1060 char *x;
1061 for (x = n; *x; x++) *x = upcase(*x);
1062 }
1063 } else sprintf(n, "%d", par_format.list_number);
1064 put_chrs(n, strlen(n), put_chars_f, ff);
1065 put_chrs(". ", 7, put_chars_f, ff);
1066 par_format.leftmargin += strlen(n) + c + 2;
1067 par_format.align = AL_LEFT;
1068 html_top.next->parattr.list_number = par_format.list_number + 1;
1069 par_format.list_number = 0;
1070 putsp = -1;
1071 }
1072 line_breax = 2;
1073 }
1074
html_dl(unsigned char * a)1075 void html_dl(unsigned char *a)
1076 {
1077 par_format.flags &= ~P_COMPACT;
1078 if (has_attr(a, "compact")) par_format.flags |= P_COMPACT;
1079 if (par_format.list_level) par_format.leftmargin += 5;
1080 par_format.list_level++;
1081 par_format.list_number = 0;
1082 par_format.align = AL_LEFT;
1083 par_format.dd_margin = par_format.leftmargin;
1084 html_top.dontkill = 1;
1085 if (!(par_format.flags & P_COMPACT)) {
1086 ln_break(2, line_break_f, ff);
1087 html_top.linebreak = 2;
1088 }
1089 }
1090
html_dt(unsigned char * a)1091 void html_dt(unsigned char *a)
1092 {
1093 kill_until(0, "", "DL", NULL);
1094 par_format.align = AL_LEFT;
1095 par_format.leftmargin = par_format.dd_margin;
1096 if (!(par_format.flags & P_COMPACT) && !has_attr(a, "compact"))
1097 ln_break(2, line_break_f, ff);
1098 }
1099
html_dd(unsigned char * a)1100 void html_dd(unsigned char *a)
1101 {
1102 kill_until(0, "", "DL", NULL);
1103 if ((par_format.leftmargin = par_format.dd_margin + (table_level ? 3 : 8)) > par_format.width * 2 / 3 && !table_level)
1104 par_format.leftmargin = par_format.width * 2 / 3;
1105 par_format.align = AL_LEFT;
1106 }
1107
get_html_form(unsigned char * a,struct form * form)1108 void get_html_form(unsigned char *a, struct form *form)
1109 {
1110 unsigned char *al;
1111 unsigned char *ch;
1112 form->method = FM_GET;
1113 if ((al = get_attr_val(a, "method"))) {
1114 if (!strcasecmp(al, "post")) {
1115 char *ax;
1116 form->method = FM_POST;
1117 if ((ax = get_attr_val(a, "enctype"))) {
1118 if (!strcasecmp(ax, "multipart/form-data"))
1119 form->method = FM_POST_MP;
1120 mem_free(ax);
1121 }
1122 }
1123 mem_free(al);
1124 }
1125 if ((al = get_url_val(a, "action"))) {
1126 char *all = al;
1127 while (all[0] == ' ') all++;
1128 while (all[0] && all[strlen(all) - 1] == ' ') all[strlen(all) - 1] = 0;
1129 form->action = join_urls(format_.href_base, all);
1130 mem_free(al);
1131 } else {
1132 if ((ch = strchr(form->action = stracpy(format_.href_base), POST_CHAR))) *ch = 0;
1133 if (form->method == FM_GET && (ch = strchr(form->action, '?'))) *ch = 0;
1134 }
1135 if ((al = get_target(a))) {
1136 form->target = al;
1137 } else {
1138 form->target = stracpy(format_.target_base);
1139 }
1140 form->num = a - startf;
1141 }
1142
find_form_for_input(unsigned char * i,int when_unused)1143 void find_form_for_input(unsigned char *i, int when_unused)
1144 {
1145 unsigned char *s, *ss, *name, *attr, *lf, *la;
1146 int namelen;
1147 if (form.action) mem_free(form.action);
1148 if (form.target) mem_free(form.target);
1149 memset(&form, 0, sizeof(form));
1150 if (!when_unused && !special_f(ff, SP_USED, NULL)) return;
1151 if (last_form_tag && last_input_tag && i <= last_input_tag && i > last_form_tag) {
1152 get_html_form(last_form_attr, &form);
1153 return;
1154 }
1155 if (last_form_tag && last_input_tag && i > last_input_tag) {
1156 if (parse_element(last_form_tag, i, &name, &namelen, &la, &s))
1157 internal("couldn't parse already parsed tag");
1158 lf = last_form_tag;
1159 s = last_input_tag;
1160 } else {
1161 lf = NULL, la = NULL;
1162 s = startf;
1163 }
1164 se:
1165 while (s < i && *s != '<') sp:s++;
1166 if (s >= i) goto end_parse;
1167 if (eofff - s >= 2 && (s[1] == '!' || s[1] == '?')) {
1168 s = skip_comment(s, i);
1169 goto se;
1170 }
1171 ss = s;
1172 if (parse_element(s, i, &name, &namelen, &attr, &s)) goto sp;
1173 if (namelen != 4 || casecmp(name, "FORM", 4)) goto se;
1174 lf = ss;
1175 la = attr;
1176 goto se;
1177
1178 end_parse:
1179 if (lf) {
1180 last_form_tag = lf;
1181 last_form_attr = la;
1182 last_input_tag = i;
1183 get_html_form(la, &form);
1184 } else {
1185 memset(&form, 0, sizeof(struct form));
1186 }
1187 }
1188
html_button(unsigned char * a)1189 void html_button(unsigned char *a)
1190 {
1191 char *al;
1192 struct form_control *fc;
1193 find_form_for_input(a, 0);
1194 fc = mem_alloc(sizeof(struct form_control));
1195 memset(fc, 0, sizeof(struct form_control));
1196 if (!(al = get_attr_val(a, "type"))) {
1197 fc->type = FC_SUBMIT;
1198 goto xxx;
1199 }
1200 if (!strcasecmp(al, "submit")) fc->type = FC_SUBMIT;
1201 else if (!strcasecmp(al, "reset")) fc->type = FC_RESET;
1202 else if (!strcasecmp(al, "button")) {
1203 mem_free(al);
1204 put_chrs(" [ ", 8, put_chars_f, ff);
1205 if ((al = get_attr_val(a, "value"))) {
1206 put_chrs(al, strlen(al), put_chars_f, ff);
1207 mem_free(al);
1208 } else put_chrs("BUTTON", 6, put_chars_f, ff);
1209 put_chrs(" ] ", 8, put_chars_f, ff);
1210 mem_free(fc);
1211 return;
1212 } else {
1213 mem_free(al);
1214 mem_free(fc);
1215 return;
1216 }
1217 mem_free(al);
1218 xxx:
1219 fc->form_num = last_form_tag - startf;
1220 fc->ctrl_num = a - last_form_tag;
1221 fc->position = a - startf;
1222 fc->method = form.method;
1223 fc->action = stracpy(form.action);
1224 fc->name = get_attr_val(a, "name");
1225 fc->default_value = get_exact_attr_val(a, "value");
1226 fc->ro = has_attr(a, "disabled") ? 2 : has_attr(a, "readonly") ? 1 : 0;
1227 if (fc->type == FC_IMAGE) fc->alt = get_attr_val(a, "alt");
1228 if (fc->type == FC_SUBMIT && !fc->default_value) fc->default_value = stracpy("Submit");
1229 if (fc->type == FC_RESET && !fc->default_value) fc->default_value = stracpy("Reset");
1230 if (!fc->default_value) fc->default_value = stracpy("");
1231 special_f(ff, SP_CONTROL, fc);
1232 format_.form = fc;
1233 format_.attr |= AT_BOLD;
1234 /*put_chrs("[ ", 7, put_chars_f, ff);
1235 if (fc->default_value) put_chrs(fc->default_value, strlen(fc->default_value), put_chars_f, ff);
1236 put_chrs(" ]", 7, put_chars_f, ff);
1237 put_chrs(" ", 1, put_chars_f, ff);*/
1238 }
1239
set_max_textarea_width(int * w)1240 void set_max_textarea_width(int *w)
1241 {
1242 int limit;
1243 if (!table_level) {
1244 limit = par_format.width - (par_format.leftmargin + par_format.rightmargin);
1245 } else {
1246 limit = d_opt->xw - 2;
1247 }
1248 if (*w > limit) {
1249 *w = limit;
1250 if (*w < HTML_MINIMAL_TEXTAREA_WIDTH) *w = HTML_MINIMAL_TEXTAREA_WIDTH;
1251 }
1252 }
1253
html_input(unsigned char * a)1254 void html_input(unsigned char *a)
1255 {
1256 int i;
1257 int size;
1258 unsigned char *al;
1259 struct form_control *fc;
1260 find_form_for_input(a, 0);
1261 fc = mem_alloc(sizeof(struct form_control));
1262 memset(fc, 0, sizeof(struct form_control));
1263 if (!(al = get_attr_val(a, "type"))) {
1264 fc->type = FC_TEXT;
1265 goto xxx;
1266 }
1267 if (!strcasecmp(al, "text")) fc->type = FC_TEXT;
1268 else if (!strcasecmp(al, "password")) fc->type = FC_PASSWORD;
1269 else if (!strcasecmp(al, "checkbox")) fc->type = FC_CHECKBOX;
1270 else if (!strcasecmp(al, "radio")) fc->type = FC_RADIO;
1271 else if (!strcasecmp(al, "submit")) fc->type = FC_SUBMIT;
1272 else if (!strcasecmp(al, "reset")) fc->type = FC_RESET;
1273 else if (!strcasecmp(al, "file")) fc->type = FC_FILE;
1274 else if (!strcasecmp(al, "hidden")) fc->type = FC_HIDDEN;
1275 else if (!strcasecmp(al, "image")) fc->type = FC_IMAGE;
1276 else if (!strcasecmp(al, "button")) {
1277 mem_free(al);
1278 put_chrs(" [ ", 8, put_chars_f, ff);
1279 if ((al = get_attr_val(a, "value"))) {
1280 put_chrs(al, strlen(al), put_chars_f, ff);
1281 mem_free(al);
1282 } else put_chrs("BUTTON", 6, put_chars_f, ff);
1283 put_chrs(" ] ", 8, put_chars_f, ff);
1284 mem_free(fc);
1285 return;
1286 } else fc->type = FC_TEXT;
1287 mem_free(al);
1288 xxx:
1289 fc->form_num = last_form_tag - startf;
1290 fc->ctrl_num = a - last_form_tag;
1291 fc->position = a - startf;
1292 fc->method = form.method;
1293 fc->action = stracpy(form.action);
1294 fc->target = stracpy(form.target);
1295 fc->name = get_attr_val(a, "name");
1296 if (fc->type == FC_TEXT || fc->type == FC_PASSWORD) fc->default_value = get_attr_val(a, "value");
1297 else if (fc->type != FC_FILE) fc->default_value = get_exact_attr_val(a, "value");
1298 if (fc->type == FC_CHECKBOX && !fc->default_value) fc->default_value = stracpy("on");
1299 if ((size = get_num(a, "size")) <= 0) size = HTML_DEFAULT_INPUT_SIZE;
1300 size++;
1301 if (size > HTML_MINIMAL_TEXTAREA_WIDTH) {
1302 set_max_textarea_width(&size);
1303 }
1304 fc->size = size;
1305 if ((fc->maxlength = get_num(a, "maxlength")) == -1) fc->maxlength = MAXINT / 4;
1306 if (fc->type == FC_CHECKBOX || fc->type == FC_RADIO) fc->default_state = has_attr(a, "checked");
1307 fc->ro = has_attr(a, "disabled") ? 2 : has_attr(a, "readonly") ? 1 : 0;
1308 if (fc->type == FC_IMAGE) {
1309 fc->alt = get_attr_val(a, "alt");
1310 if (!fc->alt) fc->alt = get_attr_val(a, "title");
1311 if (!fc->alt) fc->alt = get_attr_val(a, "name");
1312 }
1313 if (fc->type == FC_SUBMIT && !fc->default_value) fc->default_value = stracpy("Submit");
1314 if (fc->type == FC_RESET && !fc->default_value) fc->default_value = stracpy("Reset");
1315 if (!fc->default_value) fc->default_value = stracpy("");
1316 if (fc->type == FC_HIDDEN) goto hid;
1317 put_chrs(" ", 1, put_chars_f, ff);
1318 html_stack_dup();
1319 format_.form = fc;
1320 switch (fc->type) {
1321 case FC_TEXT:
1322 case FC_PASSWORD:
1323 case FC_FILE:
1324 format_.attr |= AT_BOLD;
1325 for (i = 0; i < fc->size; i++) put_chrs("_", 1, put_chars_f, ff);
1326 break;
1327 case FC_CHECKBOX:
1328 case FC_RADIO:
1329 format_.attr |= AT_BOLD;
1330 put_chrs("[ ]", 8, put_chars_f, ff);
1331 break;
1332 case FC_IMAGE:
1333 if (format_.image) mem_free(format_.image), format_.image = NULL;
1334 if ((al = get_url_val(a, "src")) || (al = get_url_val(a, "dynsrc"))) {
1335 format_.image = join_urls(format_.href_base, al);
1336 mem_free(al);
1337 }
1338 format_.attr |= AT_BOLD;
1339 put_chrs("[ ", 7, put_chars_f, ff);
1340 if (fc->alt) put_chrs(fc->alt, strlen(fc->alt), put_chars_f, ff);
1341 else put_chrs("Submit", 6, put_chars_f, ff);
1342 put_chrs(" ]", 7, put_chars_f, ff);
1343 break;
1344 case FC_SUBMIT:
1345 case FC_RESET:
1346 format_.attr |= AT_BOLD;
1347 put_chrs("[ ", 7, put_chars_f, ff);
1348 if (fc->default_value) put_chrs(fc->default_value, strlen(fc->default_value), put_chars_f, ff);
1349 put_chrs(" ]", 7, put_chars_f, ff);
1350 break;
1351 default:
1352 internal("bad control type");
1353 }
1354 kill_html_stack_item(&html_top);
1355 put_chrs(" ", 1, put_chars_f, ff);
1356
1357 hid:
1358 special_f(ff, SP_CONTROL, fc);
1359 }
1360
html_select(unsigned char * a)1361 void html_select(unsigned char *a)
1362 {
1363 char *al;
1364 if (!(al = get_attr_val(a, "name"))) return;
1365 html_top.dontkill = 1;
1366 if (format_.select) mem_free(format_.select);
1367 format_.select = al;
1368 format_.select_disabled = 2 * has_attr(a, "disabled");
1369 }
1370
html_option(unsigned char * a)1371 void html_option(unsigned char *a)
1372 {
1373 struct form_control *fc;
1374 unsigned char *val;
1375 find_form_for_input(a, 0);
1376 if (!format_.select) return;
1377 fc = mem_alloc(sizeof(struct form_control));
1378 memset(fc, 0, sizeof(struct form_control));
1379 if (!(val = get_exact_attr_val(a, "value"))) {
1380 unsigned char *p, *r;
1381 unsigned char *name;
1382 int namelen;
1383 int l = 0;
1384 for (p = a - 1; *p != '<'; p--) ;
1385 val = init_str();
1386 if (parse_element(p, eoff, NULL, NULL, NULL, &p)) {
1387 internal("parse element failed");
1388 goto x;
1389 }
1390 rrrr:
1391 while (p < eoff && WHITECHAR(*p)) p++;
1392 while (p < eoff && !WHITECHAR(*p) && *p != '<') {
1393 pppp:
1394 add_chr_to_str(&val, &l, *p), p++;
1395 }
1396 r = p;
1397 while (r < eoff && WHITECHAR(*r)) r++;
1398 if (r >= eoff) goto x;
1399 if (eoff - r >= 2 && (r[1] == '!' || r[1] == '?')) {
1400 p = skip_comment(r, eoff);
1401 goto rrrr;
1402 }
1403 if (parse_element(r, eoff, &name, &namelen, NULL, &p)) goto pppp;
1404 if (!((namelen == 6 && !casecmp(name, "OPTION", 6)) ||
1405 (namelen == 7 && !casecmp(name, "/OPTION", 7)) ||
1406 (namelen == 6 && !casecmp(name, "SELECT", 6)) ||
1407 (namelen == 7 && !casecmp(name, "/SELECT", 7)) ||
1408 (namelen == 8 && !casecmp(name, "OPTGROUP", 8)) ||
1409 (namelen == 9 && !casecmp(name, "/OPTGROUP", 9)))) goto rrrr;
1410 }
1411 x:
1412 fc->form_num = last_form_tag - startf;
1413 fc->ctrl_num = a - last_form_tag;
1414 fc->position = a - startf;
1415 fc->method = form.method;
1416 fc->action = stracpy(form.action);
1417 fc->type = FC_CHECKBOX;
1418 fc->name = stracpy(format_.select);
1419 fc->default_value = val;
1420 fc->default_state = has_attr(a, "selected");
1421 fc->ro = format_.select_disabled;
1422 if (has_attr(a, "disabled")) fc->ro = 2;
1423 put_chrs(" ", 1, put_chars_f, ff);
1424 html_stack_dup();
1425 format_.form = fc;
1426 format_.attr |= AT_BOLD;
1427 put_chrs("[ ]", 3, put_chars_f, ff);
1428 kill_html_stack_item(&html_top);
1429 put_chrs(" ", 1, put_chars_f, ff);
1430 special_f(ff, SP_CONTROL, fc);
1431 }
1432
clr_spaces(unsigned char * name)1433 void clr_spaces(unsigned char *name)
1434 {
1435 unsigned char *n1, *n2;
1436 for (n1 = name; *n1; n1++)
1437 if (WHITECHAR(*n1) || *n1 == 1) *n1 = ' ';
1438 /*for (nm = name; *nm; nm++)
1439 while (nm[0] == ' ' && (nm == name || nm[1] == ' ' || !nm[1]))
1440 memmove(nm, nm + 1, strlen(nm));*/
1441 if (!strchr(name, ' ')) return;
1442 for (n1 = name, n2 = name; *n1; n1++)
1443 if (!(n1[0] == ' ' && (n2 == name || n1[1] == ' ' || !n1[1])))
1444 *n2++ = *n1;
1445 *n2 = 0;
1446 }
1447
1448 int menu_stack_size;
1449 struct menu_item **menu_stack;
1450
new_menu_item(unsigned char * name,int data,int fullname)1451 void new_menu_item(unsigned char *name, int data, int fullname)
1452 /* name == NULL - up; data == -1 - down */
1453 {
1454 struct menu_item *top, *item, *nmenu = NULL; /* no uninitialized warnings */
1455 if (name) {
1456 clr_spaces(name);
1457 if (!name[0]) mem_free(name), name = stracpy(" ");
1458 if (name[0] == 1) name[0] = ' ';
1459 }
1460 if (name && data == -1) {
1461 nmenu = mem_alloc(sizeof(struct menu_item));
1462 memset(nmenu, 0, sizeof(struct menu_item));
1463 /*nmenu->text = "";*/
1464 }
1465 if (menu_stack_size && name) {
1466 top = item = menu_stack[menu_stack_size - 1];
1467 while (item->text) item++;
1468 if ((size_t)((char *)(item + 2) - (char *)top) > MAXINT) overalloc();
1469 top = mem_realloc(top, (char *)(item + 2) - (char *)top);
1470 item = item - menu_stack[menu_stack_size - 1] + top;
1471 menu_stack[menu_stack_size - 1] = top;
1472 if (menu_stack_size >= 2) {
1473 struct menu_item *below = menu_stack[menu_stack_size - 2];
1474 while (below->text) below++;
1475 below[-1].data = top;
1476 }
1477 item->text = name;
1478 item->rtext = data == -1 ? ">" : "";
1479 item->hotkey = fullname ? "\000\001" : "\000\000"; /* dirty */
1480 item->func = data == -1 ? MENU_FUNC do_select_submenu : MENU_FUNC selected_item;
1481 item->data = data == -1 ? nmenu : (void *)(my_uintptr_t)data;
1482 item->in_m = data == -1 ? 1 : 0;
1483 item->free_i = 0;
1484 item++;
1485 memset(item, 0, sizeof(struct menu_item));
1486 /*item->text = "";*/
1487 } else if (name) mem_free(name);
1488 if (name && data == -1) {
1489 if ((unsigned)menu_stack_size > MAXINT / sizeof(struct menu_item *) - 1) overalloc();
1490 menu_stack = mem_realloc(menu_stack, (menu_stack_size + 1) * sizeof(struct menu_item *));
1491 menu_stack[menu_stack_size++] = nmenu;
1492 }
1493 if (!name) menu_stack_size--;
1494 }
1495
init_menu()1496 void init_menu()
1497 {
1498 menu_stack_size = 0;
1499 menu_stack = DUMMY;
1500 new_menu_item(stracpy(""), -1, 0);
1501 }
1502
free_menu(struct menu_item * m)1503 void free_menu(struct menu_item *m) /* Grrr. Recursion */
1504 {
1505 struct menu_item *mm;
1506 for (mm = m; mm->text; mm++) {
1507 mem_free(mm->text);
1508 if (mm->func == MENU_FUNC do_select_submenu) free_menu(mm->data);
1509 }
1510 mem_free(m);
1511 }
1512
detach_menu()1513 struct menu_item *detach_menu()
1514 {
1515 struct menu_item *i = NULL;
1516 if (menu_stack_size) i = menu_stack[0];
1517 if (menu_stack) mem_free(menu_stack);
1518 return i;
1519 }
1520
destroy_menu()1521 void destroy_menu()
1522 {
1523 if (menu_stack && menu_stack != DUMMY) free_menu(menu_stack[0]);
1524 detach_menu();
1525 }
1526
menu_labels(struct menu_item * m,unsigned char * base,unsigned char ** lbls)1527 void menu_labels(struct menu_item *m, unsigned char *base, unsigned char **lbls)
1528 {
1529 unsigned char *bs;
1530 for (; m->text; m++) {
1531 if (m->func == MENU_FUNC do_select_submenu) {
1532 if ((bs = stracpy(base))) {
1533 add_to_strn(&bs, m->text);
1534 add_to_strn(&bs, " ");
1535 menu_labels(m->data, bs, lbls);
1536 mem_free(bs);
1537 }
1538 } else {
1539 if ((bs = stracpy(m->hotkey[1] ? (unsigned char *)"" : base))) add_to_strn(&bs, m->text);
1540 lbls[(int)(my_uintptr_t)m->data] = bs;
1541 }
1542 }
1543 }
1544
menu_contains(struct menu_item * m,int f)1545 int menu_contains(struct menu_item *m, int f)
1546 {
1547 if (m->func != MENU_FUNC do_select_submenu) return (int)(my_uintptr_t)m->data == f;
1548 for (m = m->data; m->text; m++) if (menu_contains(m, f)) return 1;
1549 return 0;
1550 }
1551
do_select_submenu(struct terminal * term,struct menu_item * menu,struct session * ses)1552 void do_select_submenu(struct terminal *term, struct menu_item *menu, struct session *ses)
1553 {
1554 struct menu_item *m;
1555 int def = get_current_state(ses);
1556 int sel = 0;
1557 if (def < 0) def = 0;
1558 for (m = menu; m->text; m++, sel++) if (menu_contains(m, def)) goto f;
1559 sel = 0;
1560 f:
1561 do_menu_selected(term, menu, ses, sel, NULL, NULL);
1562 }
1563
do_html_select(unsigned char * attr,unsigned char * html,unsigned char * eof,unsigned char ** end,void * f)1564 int do_html_select(unsigned char *attr, unsigned char *html, unsigned char *eof, unsigned char **end, void *f)
1565 {
1566 struct form_control *fc;
1567 unsigned char *t_name, *t_attr, *en;
1568 int t_namelen;
1569 unsigned char *lbl;
1570 int lbl_l;
1571 unsigned char *vlbl;
1572 int vlbl_l;
1573 int nnmi = 0;
1574 struct conv_table *ct = special_f(f, SP_TABLE, NULL);
1575 unsigned char **val, **lbls;
1576 int order, preselect, group;
1577 int i, mw;
1578 if (has_attr(attr, "multiple")) return 1;
1579 find_form_for_input(attr, 0);
1580 lbl = NULL;
1581 lbl_l = 0;
1582 vlbl = NULL;
1583 vlbl_l = 0;
1584 val = DUMMY;
1585 order = 0, group = 0, preselect = -1;
1586 init_menu();
1587 se:
1588 en = html;
1589 see:
1590 html = en;
1591 while (html < eof && *html != '<') html++;
1592 if (html >= eof) {
1593 int i;
1594 abort:
1595 *end = html;
1596 if (lbl) mem_free(lbl);
1597 if (vlbl) mem_free(vlbl);
1598 for (i = 0; i < order; i++) if (val[i]) mem_free(val[i]);
1599 mem_free(val);
1600 destroy_menu();
1601 *end = en;
1602 return 0;
1603 }
1604 if (lbl) {
1605 unsigned char *q, *s = en;
1606 int l = html - en;
1607 while (l && WHITECHAR(s[0])) s++, l--;
1608 while (l && WHITECHAR(s[l-1])) l--;
1609 q = convert_string(ct, s, l);
1610 if (q) add_to_str(&lbl, &lbl_l, q), mem_free(q);
1611 add_bytes_to_str(&vlbl, &vlbl_l, s, l);
1612 }
1613 if (eof - html >= 2 && (html[1] == '!' || html[1] == '?')) {
1614 html = skip_comment(html, eof);
1615 goto se;
1616 }
1617 if (parse_element(html, eof, &t_name, &t_namelen, &t_attr, &en)) {
1618 html++;
1619 goto se;
1620 }
1621 if (t_namelen == 7 && !casecmp(t_name, "/SELECT", 7)) {
1622 if (lbl) {
1623 if (!val[order - 1]) val[order - 1] = stracpy(vlbl);
1624 if (!nnmi) new_menu_item(lbl, order - 1, 1), lbl = NULL;
1625 else mem_free(lbl), lbl = NULL;
1626 mem_free(vlbl), vlbl = NULL;
1627 }
1628 goto end_parse;
1629 }
1630 if (t_namelen == 7 && !casecmp(t_name, "/OPTION", 7)) {
1631 if (lbl) {
1632 if (!val[order - 1]) val[order - 1] = stracpy(vlbl);
1633 if (!nnmi) new_menu_item(lbl, order - 1, 1), lbl = NULL;
1634 else mem_free(lbl), lbl = NULL;
1635 mem_free(vlbl), vlbl = NULL;
1636 }
1637 goto see;
1638 }
1639 if (t_namelen == 6 && !casecmp(t_name, "OPTION", 6)) {
1640 unsigned char *v, *vx;
1641 if (lbl) {
1642 if (!val[order - 1]) val[order - 1] = stracpy(vlbl);
1643 if (!nnmi) new_menu_item(lbl, order - 1, 1), lbl = NULL;
1644 else mem_free(lbl), lbl = NULL;
1645 mem_free(vlbl), vlbl = NULL;
1646 }
1647 if (has_attr(t_attr, "disabled")) goto see;
1648 if (preselect == -1 && has_attr(t_attr, "selected")) preselect = order;
1649 v = get_exact_attr_val(t_attr, "value");
1650 if (!(order & (ALLOC_GR - 1))) {
1651 if ((unsigned)order > MAXINT / sizeof(unsigned char *) - ALLOC_GR) overalloc();
1652 if ((unsigned)order > MAXINT / sizeof(char *) - ALLOC_GR) overalloc();
1653 val = mem_realloc(val, (order + ALLOC_GR) * sizeof(unsigned char *));
1654 }
1655 val[order++] = v;
1656 if ((vx = get_attr_val(t_attr, "label"))) {
1657 new_menu_item(convert_string(ct, vx, strlen(vx)), order - 1, 0);
1658 mem_free(vx);
1659 }
1660 if (!v || !vx) {
1661 lbl = init_str(), lbl_l = 0;
1662 vlbl = init_str(), vlbl_l = 0;
1663 nnmi = !!vx;
1664 }
1665 goto see;
1666 }
1667 if ((t_namelen == 8 && !casecmp(t_name, "OPTGROUP", 8)) || (t_namelen == 9 && !casecmp(t_name, "/OPTGROUP", 9))) {
1668 if (lbl) {
1669 if (!val[order - 1]) val[order - 1] = stracpy(vlbl);
1670 if (!nnmi) new_menu_item(lbl, order - 1, 1), lbl = NULL;
1671 else mem_free(lbl), lbl = NULL;
1672 mem_free(vlbl), vlbl = NULL;
1673 }
1674 if (group) new_menu_item(NULL, -1, 0), group = 0;
1675 }
1676 if (t_namelen == 8 && !casecmp(t_name, "OPTGROUP", 8)) {
1677 char *la;
1678 if (!(la = get_attr_val(t_attr, "label"))) la = stracpy("");
1679 new_menu_item(convert_string(ct, la, strlen(la)), -1, 0);
1680 mem_free(la);
1681 group = 1;
1682 }
1683 goto see;
1684
1685 end_parse:
1686 *end = en;
1687 if (!order) goto abort;
1688 fc = mem_alloc(sizeof(struct form_control));
1689 memset(fc, 0, sizeof(struct form_control));
1690 lbls = mem_alloc(order * sizeof(char *));
1691 memset(lbls, 0, order * sizeof(char *));
1692 fc->form_num = last_form_tag - startf;
1693 fc->ctrl_num = attr - last_form_tag;
1694 fc->position = attr - startf;
1695 fc->method = form.method;
1696 fc->action = stracpy(form.action);
1697 fc->name = get_attr_val(attr, "name");
1698 fc->type = FC_SELECT;
1699 fc->default_state = preselect < 0 ? 0 : preselect;
1700 fc->default_value = order ? stracpy(val[fc->default_state]) : stracpy("");
1701 fc->ro = has_attr(attr, "disabled") ? 2 : has_attr(attr, "readonly") ? 1 : 0;
1702 fc->nvalues = order;
1703 fc->values = val;
1704 fc->menu = detach_menu();
1705 fc->labels = lbls;
1706 menu_labels(fc->menu, "", lbls);
1707 put_chrs("[", 1, put_chars_f, f);
1708 html_stack_dup();
1709 format_.form = fc;
1710 format_.attr |= AT_BOLD;
1711 mw = 0;
1712 for (i = 0; i < order; i++) if (lbls[i] && strlen(lbls[i]) > (size_t)mw) mw = strlen(lbls[i]);
1713 for (i = 0; i < mw; i++) put_chrs("_", 1, put_chars_f, f);
1714 kill_html_stack_item(&html_top);
1715 put_chrs("]", 1, put_chars_f, f);
1716 special_f(ff, SP_CONTROL, fc);
1717 return 0;
1718 }
1719
html_textarea(unsigned char * a)1720 void html_textarea(unsigned char *a)
1721 {
1722 internal("This should be never called");
1723 }
1724
do_html_textarea(unsigned char * attr,unsigned char * html,unsigned char * eof,unsigned char ** end,void * f)1725 void do_html_textarea(unsigned char *attr, unsigned char *html, unsigned char *eof, unsigned char **end, void *f)
1726 {
1727 struct form_control *fc;
1728 unsigned char *p, *t_name, *w;
1729 int t_namelen;
1730 int cols, rows;
1731 int i;
1732 find_form_for_input(attr, 1);
1733 while (html < eof && (*html == '\n' || *html == '\r')) html++;
1734 p = html;
1735 while (p < eof && *p != '<') {
1736 pp:
1737 p++;
1738 }
1739 if (p >= eof) {
1740 *end = eof;
1741 return;
1742 }
1743 if (parse_element(p, eof, &t_name, &t_namelen, NULL, end)) goto pp;
1744 if (t_namelen != 9 || casecmp(t_name, "/TEXTAREA", 9)) goto pp;
1745 if (!last_form_tag) return;
1746 fc = mem_alloc(sizeof(struct form_control));
1747 memset(fc, 0, sizeof(struct form_control));
1748 fc->form_num = last_form_tag - startf;
1749 fc->ctrl_num = attr - last_form_tag;
1750 fc->position = attr - startf;
1751 fc->method = form.method;
1752 fc->action = stracpy(form.action);
1753 fc->name = get_attr_val(attr, "name");
1754 fc->type = FC_TEXTAREA;;
1755 fc->ro = has_attr(attr, "disabled") ? 2 : has_attr(attr, "readonly") ? 1 : 0;
1756 fc->default_value = memacpy(html, p - html);
1757 if ((cols = get_num(attr, "cols")) < HTML_MINIMAL_TEXTAREA_WIDTH) cols = HTML_DEFAULT_TEXTAREA_WIDTH;
1758 cols++;
1759 set_max_textarea_width(&cols);
1760 if ((rows = get_num(attr, "rows")) <= 0) rows = HTML_DEFAULT_TEXTAREA_HEIGHT;
1761 if (rows > d_opt->yw) {
1762 rows = d_opt->yw;
1763 if (rows <= 0) rows = 1;
1764 }
1765 fc->cols = cols;
1766 fc->rows = rows;
1767 fc->wrap = 1;
1768 if ((w = get_attr_val(attr, "wrap"))) {
1769 if (!strcasecmp(w, "hard") || !strcasecmp(w, "physical")) fc->wrap = 2;
1770 else if (!strcasecmp(w, "off")) fc->wrap = 0;
1771 mem_free(w);
1772 }
1773 if ((fc->maxlength = get_num(attr, "maxlength")) == -1) fc->maxlength = MAXINT / 4;
1774 if (rows > 1) ln_break(1, line_break_f, f);
1775 else put_chrs(" ", 1, put_chars_f, f);
1776 html_stack_dup();
1777 format_.form = fc;
1778 format_.attr |= AT_BOLD;
1779 for (i = 0; i < rows; i++) {
1780 int j;
1781 for (j = 0; j < cols; j++) put_chrs("_", 1, put_chars_f, f);
1782 if (i < rows - 1) ln_break(1, line_break_f, f);
1783 }
1784 kill_html_stack_item(&html_top);
1785 if (rows > 1) ln_break(1, line_break_f, f);
1786 else put_chrs(" ", 1, put_chars_f, f);
1787 special_f(f, SP_CONTROL, fc);
1788 }
1789
html_iframe(unsigned char * a)1790 void html_iframe(unsigned char *a)
1791 {
1792 unsigned char *name, *url;
1793 if (!(url = get_url_val(a, "src"))) return;
1794 if (!(name = get_attr_val(a, "name"))) name = stracpy("");
1795 if (*name) put_link_line("IFrame: ", name, url, d_opt->framename);
1796 else put_link_line("", "IFrame", url, d_opt->framename);
1797 mem_free(name);
1798 mem_free(url);
1799 }
1800
html_noframes(unsigned char * a)1801 void html_noframes(unsigned char *a)
1802 {
1803 if (d_opt->frames) html_skip(a);
1804 }
1805
html_frame(unsigned char * a)1806 void html_frame(unsigned char *a)
1807 {
1808 unsigned char *name, *u2, *url;
1809 if (!(u2 = get_url_val(a, "src"))) {
1810 url = stracpy("");
1811 } else {
1812 url = join_urls(format_.href_base, u2);
1813 mem_free(u2);
1814 }
1815 if (!url) return;
1816 name = get_attr_val (a, "name");
1817 if (!name)
1818 name = stracpy(url);
1819 else if (!name[0]) { /* When name doesn't have a value */
1820 mem_free(name);
1821 name = stracpy(url);
1822 }
1823 if (!d_opt->frames || !html_top.frameset) put_link_line("Frame: ", name, url, "");
1824 else {
1825 struct frame_param fp;
1826 fp.name = name;
1827 fp.url = url;
1828 fp.parent = html_top.frameset;
1829 if (special_f(ff, SP_USED, NULL)) special_f(ff, SP_FRAME, &fp);
1830 }
1831 mem_free(name);
1832 mem_free(url);
1833 }
1834
parse_frame_widths(unsigned char * a,int ww,int www,int ** op,int * olp)1835 void parse_frame_widths(unsigned char *a, int ww, int www, int **op, int *olp)
1836 {
1837 unsigned char *aa;
1838 int q, qq, i, d, nn;
1839 unsigned long n;
1840 int *oo, *o;
1841 int ol;
1842 ol = 0;
1843 o = DUMMY;
1844 new_ch:
1845 while (WHITECHAR(*a)) a++;
1846 n = strtoul(a, (char **)(void *)&a, 10);
1847 if (n > 10000) n = 10000;
1848 q = n;
1849 if (*a == '%') q = q * ww / 100;
1850 else if (*a != '*') q = (q + (www - 1) / 2) / (www ? www : 1);
1851 else if (!(q = -q)) q = -1;
1852 if ((unsigned)ol > MAXINT / sizeof(int) - 1) overalloc();
1853 o = mem_realloc(o, (ol + 1) * sizeof(int));
1854 o[ol++] = q;
1855 if ((aa = strchr(a, ','))) {
1856 a = aa + 1;
1857 goto new_ch;
1858 }
1859 *op = o;
1860 *olp = ol;
1861 q = 2 * ol - 1;
1862 for (i = 0; i < ol; i++) if (o[i] > 0) q += o[i] - 1;
1863 if (q >= ww) {
1864 distribute:
1865 for (i = 0; i < ol; i++) if (o[i] < 1) o[i] = 1;
1866 q -= ww;
1867 d = 0;
1868 for (i = 0; i < ol; i++) d += o[i];
1869 qq = q;
1870 for (i = 0; i < ol; i++) {
1871 q -= o[i] - o[i] * (d - qq) / (d ? d : 1);
1872 do_not_optimize_here(&d);
1873 /* SIGH! gcc 2.7.2.* has an optimizer bug! */
1874 o[i] = o[i] * (d - qq) / (d ? d : 1);
1875 }
1876 while (q) {
1877 nn = 0;
1878 for (i = 0; i < ol; i++) {
1879 if (q < 0) o[i]++, q++, nn = 1;
1880 if (q > 0 && o[i] > 1) o[i]--, q--, nn = 1;
1881 if (!q) break;
1882 }
1883 if (!nn) break;
1884 }
1885 } else {
1886 int nn = 0;
1887 for (i = 0; i < ol; i++) if (o[i] < 0) nn = 1;
1888 if (!nn) goto distribute;
1889 if ((unsigned)ol > MAXINT / sizeof(int)) overalloc();
1890 oo = mem_alloc(ol * sizeof(int));
1891 memcpy(oo, o, ol * sizeof(int));
1892 for (i = 0; i < ol; i++) if (o[i] < 1) o[i] = 1;
1893 q = ww - q;
1894 d = 0;
1895 for (i = 0; i < ol; i++) if (oo[i] < 0) d += -oo[i];
1896 qq = q;
1897 for (i = 0; i < ol; i++) if (oo[i] < 0) {
1898 o[i] += (-oo[i] * qq / (d ? d : 1));
1899 q -= (-oo[i] * qq / (d ? d : 1));
1900 }
1901 if (q < 0) {
1902 q = 0;
1903 /*internal("parse_frame_widths: q < 0"); may happen when page contains too big values */
1904 }
1905 for (i = 0; i < ol; i++) if (oo[i] < 0) {
1906 if (q) o[i]++, q--;
1907 }
1908 if (q > 0) {
1909 q = 0;
1910 /*internal("parse_frame_widths: q > 0"); may happen when page contains too big values */
1911 }
1912 mem_free(oo);
1913 }
1914 for (i = 0; i < ol; i++) if (!o[i]) {
1915 int j;
1916 int m = 0;
1917 int mj = 0;
1918 for (j = 0; j < ol; j++) if (o[j] > m) m = o[j], mj = j;
1919 if (m) o[i] = 1, o[mj]--;
1920 }
1921 }
1922
html_frameset(unsigned char * a)1923 void html_frameset(unsigned char *a)
1924 {
1925 int x, y;
1926 struct frameset_param fp;
1927 unsigned char *c, *d;
1928 if (!d_opt->frames || !special_f(ff, SP_USED, NULL)) return;
1929 if (!(c = get_attr_val(a, "cols"))) c = stracpy("100%");
1930 if (!(d = get_attr_val(a, "rows"))) d = stracpy("100%");
1931 if (!html_top.frameset) {
1932 x = d_opt->xw;
1933 y = d_opt->yw;
1934 } else {
1935 struct frameset_desc *f = html_top.frameset;
1936 if (f->yp >= f->y) goto free_cd;
1937 x = f->f[f->xp + f->yp * f->x].xw;
1938 y = f->f[f->xp + f->yp * f->x].yw;
1939 }
1940 parse_frame_widths(c, x, HTML_FRAME_CHAR_WIDTH, &fp.xw, &fp.x);
1941 parse_frame_widths(d, y, HTML_FRAME_CHAR_HEIGHT, &fp.yw, &fp.y);
1942 fp.parent = html_top.frameset;
1943 if (fp.x && fp.y) html_top.frameset = special_f(ff, SP_FRAMESET, &fp);
1944 mem_free(fp.xw);
1945 mem_free(fp.yw);
1946 free_cd:
1947 mem_free(c);
1948 mem_free(d);
1949 }
1950
1951 /*void html_frameset(unsigned char *a)
1952 {
1953 int w;
1954 int horiz = 0;
1955 struct frameset_param *fp;
1956 unsigned char *c, *d;
1957 if (!d_opt->frames || !special_f(ff, SP_USED, NULL)) return;
1958 if (!(c = get_attr_val(a, "cols"))) {
1959 horiz = 1;
1960 if (!(c = get_attr_val(a, "rows"))) return;
1961 }
1962 fp = mem_alloc(sizeof(struct frameset_param));
1963 fp->n = 0;
1964 fp->horiz = horiz;
1965 par_format.leftmargin = par_format.rightmargin = 0;
1966 d = c;
1967 while (1) {
1968 while (WHITECHAR(*d)) d++;
1969 if (!*d) break;
1970 if (*d == ',') {
1971 d++;
1972 continue;
1973 }
1974 if ((w = parse_width(d, 1)) != -1) {
1975 if ((unsigned)fp->n > (MAXINT - sizeof(struct frameset_param)) / sizeof(int) - 1) overalloc();
1976 fp = mem_realloc(fp, sizeof(struct frameset_param) + (fp->n + 1) * sizeof(int));
1977 fp->width[fp->n++] = w;
1978 }
1979 if (!(d = strchr(d, ','))) break;
1980 d++;
1981 }
1982 fp->parent = html_top.frameset;
1983 if (fp->n) html_top.frameset = special_f(ff, SP_FRAMESET, fp);
1984 mem_free(fp);
1985 f:
1986 mem_free(c);
1987 }*/
1988
html_link(unsigned char * a)1989 void html_link(unsigned char *a)
1990 {
1991 unsigned char *name, *url, *title;
1992 if ((name = get_attr_val(a, "type"))) {
1993 if (strcasecmp(name, "text/html")) {
1994 mem_free(name);
1995 return;
1996 }
1997 mem_free(name);
1998 }
1999 if (!(url = get_url_val(a, "href"))) return;
2000 if (!(name = get_attr_val(a, "rel")))
2001 if (!(name = get_attr_val(a, "rev")))
2002 name = get_attr_val(a, "ref");
2003 if (name) {
2004 unsigned char *lang;
2005 if ((lang = get_attr_val(a, "hreflang"))) {
2006 add_to_strn(&name, " ");
2007 add_to_strn(&name, lang);
2008 mem_free(lang);
2009 }
2010 }
2011 if (!name)
2012 name = stracpy(url);
2013 if (
2014 !casecmp(name, cast_uchar "apple-touch-icon", 16) ||
2015 !casecmp(name, cast_uchar "schema", 6) ||
2016 !strcasecmp(cast_const_char name, "Edit-Time-Data") ||
2017 !strcasecmp(cast_const_char name, "File-List") ||
2018 !strcasecmp(cast_const_char name, "alternate stylesheet") ||
2019 !strcasecmp(cast_const_char name, "generator-home") ||
2020 !strcasecmp(cast_const_char name, "https://github.com/WP-API/WP-API") ||
2021 !strcasecmp(cast_const_char name, "icon") ||
2022 !strcasecmp(cast_const_char name, "made") ||
2023 !strcasecmp(cast_const_char name, "meta") ||
2024 !strcasecmp(cast_const_char name, "pingback") ||
2025 !strcasecmp(cast_const_char name, "preconnect") ||
2026 !strcasecmp(cast_const_char name, "shortcut icon") ||
2027 !strcasecmp(cast_const_char name, "stylesheet") ||
2028 !strcasecmp(cast_const_char name, "https://api.w.org/") ||
2029 !strcasecmp(cast_const_char name, "prefetch") ||
2030 !strcasecmp(cast_const_char name, "dns-prefetch") ||
2031 !strcasecmp(cast_const_char name, "prerender") ||
2032 !strcasecmp(cast_const_char name, "preload") ||
2033 0) goto skip;
2034 if ((title = get_attr_val(a, "title"))) {
2035 add_to_strn(&name, ": ");
2036 add_to_strn(&name, title);
2037 mem_free(title);
2038 }
2039 put_link_line("Link: ", name, url, format_.target_base);
2040 skip:
2041 mem_free(name);
2042 mem_free(url);
2043 }
2044
2045 struct element_info {
2046 char *name;
2047 void (*func)(unsigned char *);
2048 int linebreak;
2049 int nopair;
2050 };
2051
2052 struct element_info elements[] = {
2053 {"SPAN", html_span, 0, 0},
2054 {"B", html_bold, 0, 0},
2055 {"STRONG", html_bold, 0, 0},
2056 {"DFN", html_bold, 0, 0},
2057 {"I", html_italic, 0, 0},
2058 {"Q", html_italic, 0, 0},
2059 {"CITE", html_italic, 0, 0},
2060 {"EM", html_italic, 0, 0},
2061 {"ABBR", html_italic, 0, 0},
2062 {"U", html_underline, 0, 0},
2063 {"S", html_underline, 0, 0},
2064 {"STRIKE", html_underline, 0, 0},
2065 {"FIXED", html_fixed, 0, 0},
2066 {"CODE", html_fixed, 0, 0},
2067 {"FONT", html_font, 0, 0},
2068 {"A", html_a, 0, 2},
2069 {"IMG", html_img, 0, 1},
2070
2071 {"BASE", html_base, 0, 1},
2072 {"BASEFONT", html_font, 0, 1},
2073
2074 {"BODY", html_body, 0, 0},
2075
2076 /* {"HEAD", html_skip, 0, 0},*/
2077 {"TITLE", html_title, 0, 0},
2078 {"SCRIPT", html_skip, 0, 0},
2079 {"STYLE", html_skip, 0, 0},
2080
2081 {"BR", html_br, 1, 1},
2082 {"DIV", html_linebrk, 1, 0},
2083 {"CENTER", html_center, 1, 0},
2084 {"CAPTION", html_center, 1, 0},
2085 {"P", html_p, 2, 2},
2086 {"HR", html_hr, 2, 1},
2087 {"H1", html_center, 2, 2},
2088 {"H2", html_h2, 2, 2},
2089 {"H3", html_h3, 2, 2},
2090 {"H4", html_h4, 2, 2},
2091 {"H5", html_h5, 2, 2},
2092 {"H6", html_h6, 2, 2},
2093 {"BLOCKQUOTE", html_blockquote,2, 0},
2094 {"ADDRESS", html_address, 2, 0},
2095 {"PRE", html_pre, 2, 0},
2096 {"LISTING", html_pre, 2, 0},
2097
2098 {"UL", html_ul, 1, 0},
2099 {"DIR", html_ul, 1, 0},
2100 {"MENU", html_ul, 1, 0},
2101 {"OL", html_ol, 1, 0},
2102 {"LI", html_li, 1, 3},
2103 {"DL", html_dl, 1, 0},
2104 {"DT", html_dt, 1, 1},
2105 {"DD", html_dd, 1, 1},
2106
2107 {"TABLE", html_table, 2, 0},
2108 {"TR", html_tr, 1, 0},
2109 {"TD", html_td, 0, 0},
2110 {"TH", html_th, 0, 0},
2111
2112 {"FORM", html_form, 1, 0},
2113 {"INPUT", html_input, 0, 1},
2114 {"TEXTAREA", html_textarea, 0, 1},
2115 {"SELECT", html_select, 0, 0},
2116 {"OPTION", html_option, 1, 1},
2117 {"BUTTON", html_button, 0, 0},
2118
2119 {"LINK", html_link, 1, 1},
2120 {"IFRAME", html_iframe, 1, 1},
2121 {"FRAME", html_frame, 1, 1},
2122 {"FRAMESET", html_frameset, 1, 0},
2123 {"NOFRAMES", html_noframes, 0, 0},
2124
2125 {NULL, NULL, 0, 0},
2126 };
2127
skip_comment(unsigned char * html,unsigned char * eof)2128 unsigned char *skip_comment(unsigned char *html, unsigned char *eof)
2129 {
2130 int comm = eof - html >= 4 && html[2] == '-' && html[3] == '-';
2131 html += comm ? 4 : 2;
2132 while (html < eof) {
2133 if (!comm && html[0] == '>') return html + 1;
2134 if (comm && eof - html >= 2 && html[0] == '-' && html[1] == '-') {
2135 html += 2;
2136 while (html < eof && *html == '-') html++;
2137 while (html < eof && WHITECHAR(*html)) html++;
2138 if (html >= eof) return eof;
2139 if (*html == '>') return html + 1;
2140 continue;
2141 }
2142 html++;
2143 }
2144 return eof;
2145 }
2146
process_head(unsigned char * head)2147 void process_head(unsigned char *head)
2148 {
2149 unsigned char *r, *p;
2150 if ((r = parse_http_header(head, "Refresh", NULL))) {
2151 if ((p = parse_header_param(r, "URL")) || (p = parse_header_param(r, ""))) {
2152 put_link_line("Refresh: ", p, p, d_opt->framename);
2153 mem_free(p);
2154 }
2155 mem_free(r);
2156 }
2157 }
2158
qd(unsigned char * html,unsigned char * eof,int * len)2159 int qd(unsigned char *html, unsigned char *eof, int *len)
2160 {
2161 int l;
2162 *len = 1;
2163 if (html >= eof) {
2164 internal("qd: out of data, html == %p, eof == %p", html, eof);
2165 return -1;
2166 }
2167 if (html[0] != '&' || d_opt->plain) return html[0];
2168 if (html + 1 >= eof) return -1;
2169 if (html[1] != '#') return -1;
2170 for (l = 2; l < 10 && eof - html > l; l++) if (html[l] == ';') {
2171 int n = get_entity_number(html + 2, l - 2);
2172 if (n >= 0) {
2173 *len = l + 1;
2174 return n;
2175 }
2176 break;
2177 }
2178 return -1;
2179 }
2180
parse_html(unsigned char * html,unsigned char * eof,int (* put_chars)(void *,unsigned char *,int),void (* line_break)(void *),void * (* special)(void *,int,...),void * f,unsigned char * head)2181 void parse_html(unsigned char *html, unsigned char *eof, int (*put_chars)(void *, unsigned char *, int), void (*line_break)(void *), void *(*special)(void *, int, ...), void *f, unsigned char *head)
2182 {
2183 /*unsigned char *start = html;*/
2184 unsigned char *lt;
2185 putsp = -1;
2186 line_breax = table_level ? 2 : 1;
2187 pos = 0;
2188 was_br = 0;
2189 put_chars_f = put_chars;
2190 line_break_f = line_break;
2191 special_f = special;
2192 ff = f;
2193 eoff = eof;
2194 if (head) process_head(head);
2195 set_lt:
2196 put_chars_f = put_chars;
2197 line_break_f = line_break;
2198 special_f = special;
2199 ff = f;
2200 eoff = eof;
2201 lt = html;
2202 while (html < eof) {
2203 unsigned char *name, *attr, *end;
2204 int namelen;
2205 struct element_info *ei;
2206 int inv;
2207 if (WHITECHAR(*html) && par_format.align != AL_NO) {
2208 unsigned char *h = html;
2209 /*if (putsp == -1) {
2210 while (html < eof && WHITECHAR(*html)) html++;
2211 goto set_lt;
2212 }
2213 putsp = 0;*/
2214 while (h < eof && WHITECHAR(*h)) h++;
2215 if (eof - h > 1 && h[0] == '<' && h[1] == '/') {
2216 if (!parse_element(h, eof, &name, &namelen, &attr, &end)) {
2217 put_chrs(lt, html - lt, put_chars, f);
2218 lt = html = h;
2219 if (!html_top.invisible) putsp = 1;
2220 goto element;
2221 }
2222 }
2223 html++;
2224 if (!(pos + (html-lt-1))) goto skip_w; /* ??? */
2225 if (*(html - 1) == ' ') {
2226 if (html < eof && !WHITECHAR(*html)) continue; /* BIG performance win; not sure if it doesn't cause any bug */
2227 put_chrs(lt, html - lt, put_chars, f);
2228 } else {
2229 put_chrs(lt, html - 1 - lt, put_chars, f);
2230 put_chrs(" ", 1, put_chars, f);
2231 }
2232 skip_w:
2233 while (html < eof && WHITECHAR(*html)) html++;
2234 /*putsp = -1;*/
2235 goto set_lt;
2236 put_sp:
2237 put_chrs(" ", 1, put_chars, f);
2238 /*putsp = -1;*/
2239 }
2240 if (par_format.align == AL_NO && (*html < 32 || *html == '&')) {
2241 int l;
2242 int q = qd(html, eof, &l);
2243 putsp = 0;
2244 if (q == 9) {
2245 put_chrs(lt, html - lt, put_chars, f);
2246 put_chrs(" ", 8 - pos % 8, put_chars, f);
2247 html += l;
2248 goto set_lt;
2249 } else if (q == 13 || q == 10) {
2250 put_chrs(lt, html - lt, put_chars, f);
2251 next_break:
2252 html += l;
2253 if (q == 13 && eof - html > 1 && qd(html, eof, &l) == 10) html += l;
2254 ln_break(1, line_break, f);
2255 if (html >= eof) goto set_lt;
2256 q = qd(html, eof, &l);
2257 if (q == 13 || q == 10) {
2258 line_breax = 0;
2259 goto next_break;
2260 }
2261 goto set_lt;
2262 }
2263 }
2264 if (*html < ' ') {
2265 /*if (putsp == 1) goto put_sp;
2266 putsp = 0;*/
2267 put_chrs(lt, html - lt, put_chars, f);
2268 put_chrs(".", 1, put_chars, f);
2269 html++;
2270 goto set_lt;
2271 }
2272 if (eof - html >= 2 && html[0] == '<' && (html[1] == '!' || html[1] == '?') && !d_opt->plain) {
2273 /*if (putsp == 1) goto put_sp;
2274 putsp = 0;*/
2275 put_chrs(lt, html - lt, put_chars, f);
2276 html = skip_comment(html, eof);
2277 goto set_lt;
2278 }
2279 if (*html != '<' || d_opt->plain || parse_element(html, eof, &name, &namelen, &attr, &end)) {
2280 /*if (putsp == 1) goto put_sp;
2281 putsp = 0;*/
2282 html++;
2283 continue;
2284 }
2285 element:
2286 inv = *name == '/'; name += inv; namelen -= inv;
2287 if (!inv && putsp == 1 && !html_top.invisible) goto put_sp;
2288 put_chrs(lt, html - lt, put_chars, f);
2289 if (par_format.align != AL_NO) if (!inv && !putsp) {
2290 unsigned char *ee = end;
2291 unsigned char *nm;
2292 while (!parse_element(ee, eof, &nm, NULL, NULL, &ee))
2293 if (*nm == '/') goto ng;
2294 if (ee < eof && WHITECHAR(*ee)) {
2295 /*putsp = -1;*/
2296 put_chrs(" ", 1, put_chars, f);
2297 }
2298 ng:;
2299 }
2300 html = end;
2301 for (ei = elements; ei->name; ei++) {
2302 if (ei->name &&
2303 (strlen(ei->name) != (size_t)namelen || casecmp(ei->name, name, namelen)))
2304 continue;
2305 if (!inv) {
2306 char *a;
2307 ln_break(ei->linebreak, line_break, f);
2308 if (ei->name && ((a = get_attr_val(attr, "id")))) {
2309 special(f, SP_TAG, a);
2310 mem_free(a);
2311 }
2312 if (!html_top.invisible) {
2313 int a = par_format.align == AL_NO;
2314 struct par_attrib pa = par_format;
2315 if (ei->func == html_table && d_opt->tables && table_level < HTML_MAX_TABLE_LEVEL) {
2316 format_table(attr, html, eof, &html, f);
2317 ln_break(2, line_break, f);
2318 goto set_lt;
2319 }
2320 if (ei->func == html_select) {
2321 if (!do_html_select(attr, html, eof, &html, f))
2322 goto set_lt;
2323 }
2324 if (ei->func == html_textarea) {
2325 do_html_textarea(attr, html, eof, &html, f);
2326 goto set_lt;
2327 }
2328 if (ei->nopair == 2 || ei->nopair == 3) {
2329 struct html_element *e;
2330 if (ei->nopair == 2) {
2331 foreach(e, html_stack) {
2332 if (e->dontkill) break;
2333 if (e->linebreak || !ei->linebreak) break;
2334 }
2335 } else foreach(e, html_stack) {
2336 if (e->linebreak && !ei->linebreak) break;
2337 if (e->dontkill) break;
2338 if (e->namelen == namelen && !casecmp(e->name, name, e->namelen)) break;
2339 }
2340 if (e->namelen == namelen && !casecmp(e->name, name, e->namelen)) {
2341 while (e->prev != (void *)&html_stack) kill_html_stack_item(e->prev);
2342 if (e->dontkill != 2) kill_html_stack_item(e);
2343 }
2344 }
2345 if (ei->nopair != 1) {
2346 html_stack_dup();
2347 html_top.name = name;
2348 html_top.namelen = namelen;
2349 html_top.options = attr;
2350 html_top.linebreak = ei->linebreak;
2351 }
2352 if (ei->func) ei->func(attr);
2353 if (ei->func != html_br) was_br = 0;
2354 if (a) par_format = pa;
2355 }
2356 } else {
2357 struct html_element *e, *ff;
2358 int lnb = 0;
2359 int xxx = 0;
2360 was_br = 0;
2361 if (ei->nopair == 1 || ei->nopair == 3) break;
2362 /*debug_stack();*/
2363 foreach(e, html_stack) {
2364 if (e->linebreak && !ei->linebreak && ei->name) xxx = 1;
2365 if (e->namelen != namelen || casecmp(e->name, name, e->namelen)) {
2366 if (e->dontkill) break;
2367 else continue;
2368 }
2369 if (xxx) {
2370 kill_html_stack_item(e);
2371 break;
2372 }
2373 for (ff = e; ff != (void *)&html_stack; ff = ff->prev)
2374 if (ff->linebreak > lnb) lnb = ff->linebreak;
2375 ln_break(lnb, line_break, f);
2376 while (e->prev != (void *)&html_stack) kill_html_stack_item(e->prev);
2377 kill_html_stack_item(e);
2378 break;
2379 }
2380 /*debug_stack();*/
2381 }
2382 goto set_lt;
2383 }
2384 goto set_lt; /* unreachable */
2385 }
2386 put_chrs(lt, html - lt, put_chars, f);
2387 ln_break(1, line_break, f);
2388 putsp = -1;
2389 pos = 0;
2390 /*line_breax = 1;*/
2391 was_br = 0;
2392 }
2393
get_image_map(unsigned char * head,unsigned char * s,unsigned char * eof,unsigned char * tag,struct menu_item ** menu,struct memory_list ** ml,unsigned char * href_base,unsigned char * target_base,int to,int def,int hdef)2394 int get_image_map(unsigned char *head, unsigned char *s, unsigned char *eof, unsigned char *tag, struct menu_item **menu, struct memory_list **ml, unsigned char *href_base, unsigned char *target_base, int to, int def, int hdef)
2395 {
2396 unsigned char *name, *attr, *al, *label, *href, *target;
2397 int namelen, lblen;
2398 struct link_def *ld;
2399 struct menu_item *nm;
2400 int nmenu = 0;
2401 int i;
2402 unsigned char *hd = init_str();
2403 int hdl = 0;
2404 struct conv_table *ct;
2405 if (head) add_to_str(&hd, &hdl, head);
2406 scan_http_equiv(s, eof, &hd, &hdl, NULL);
2407 ct = get_convert_table(hd, to, def, NULL, NULL, hdef);
2408 mem_free(hd);
2409 *menu = mem_alloc(sizeof(struct menu_item));
2410 memset(*menu, 0, sizeof(struct menu_item));
2411 /*(*menu)->text = NULL;*/
2412 se:
2413 while (s < eof && *s != '<') {
2414 sp:
2415 s++;
2416 }
2417 if (s >= eof) {
2418 mem_free(*menu);
2419 return -1;
2420 }
2421 if (eof - s >= 2 && (s[1] == '!' || s[1] == '?')) {
2422 s = skip_comment(s, eof);
2423 goto se;
2424 }
2425 if (parse_element(s, eof, &name, &namelen, &attr, &s)) goto sp;
2426 if (namelen != 3 || casecmp(name, "MAP", 3)) goto se;
2427 if (tag && *tag) {
2428 if (!(al = get_attr_val(attr, "name"))) goto se;
2429 if (strcasecmp(al, tag)) {
2430 mem_free(al);
2431 goto se;
2432 }
2433 mem_free(al);
2434 }
2435 *ml = getml(NULL);
2436 se2:
2437 while (s < eof && *s != '<') {
2438 sp2:
2439 s++;
2440 }
2441 if (s >= eof) {
2442 freeml(*ml);
2443 mem_free(*menu);
2444 return -1;
2445 }
2446 if (eof - s >= 2 && (s[1] == '!' || s[1] == '?')) {
2447 s = skip_comment(s, eof);
2448 goto se2;
2449 }
2450 if (parse_element(s, eof, &name, &namelen, &attr, &s)) goto sp2;
2451 if (namelen == 1 && !casecmp(name, "A", 1)) {
2452 unsigned char *ss;
2453 label = init_str();
2454 lblen = 0;
2455 se3:
2456 ss = s;
2457 se4:
2458 while (ss < eof && *ss != '<') ss++;
2459 if (ss >= eof) {
2460 mem_free(label);
2461 freeml(*ml);
2462 mem_free(*menu);
2463 return -1;
2464 }
2465 add_bytes_to_str(&label, &lblen, s, ss - s);
2466 s = ss;
2467 if (eof - s >= 2 && (s[1] == '!' || s[1] == '?')) {
2468 s = skip_comment(s, eof);
2469 goto se3;
2470 }
2471 if (parse_element(s, eof, NULL, NULL, NULL, &ss)) {
2472 ss = s + 1;
2473 goto se4;
2474 }
2475 if (!((namelen == 1 && !casecmp(name, "A", 1)) ||
2476 (namelen == 2 && !casecmp(name, "/A", 2)) ||
2477 (namelen == 3 && !casecmp(name, "MAP", 3)) ||
2478 (namelen == 4 && !casecmp(name, "/MAP", 4)) ||
2479 (namelen == 4 && !casecmp(name, "AREA", 4)) ||
2480 (namelen == 5 && !casecmp(name, "/AREA", 5)))) {
2481 s = ss;
2482 goto se3;
2483 }
2484 } else if (namelen == 4 && !casecmp(name, "AREA", 4)) {
2485 unsigned char *l = get_attr_val(attr, "alt");
2486 if (l) label = convert_string(ct, l, strlen(l)), mem_free(l);
2487 else label = NULL;
2488 } else if (namelen == 4 && !casecmp(name, "/MAP", 4)) goto done;
2489 else goto se2;
2490 if (!(href = get_url_val(attr, "href"))) {
2491 if (label) mem_free(label);
2492 goto se2;
2493 }
2494 if (!(target = get_target(attr)) && !(target = stracpy(target_base)))
2495 target = stracpy("");
2496 ld = mem_alloc(sizeof(struct link_def));
2497 if (!(ld->link = join_urls(href_base, href))) {
2498 mem_free(href);
2499 mem_free(target);
2500 f:
2501 mem_free(ld);
2502 if (label) mem_free(label);
2503 goto se2;
2504 }
2505 mem_free(href);
2506 ld->target = target;
2507 for (i = 0; i < nmenu; i++) {
2508 struct link_def *ll = (*menu)[i].data;
2509 if (!strcmp(ll->link, ld->link) && !strcmp(ll->target, ld->target)) {
2510 mem_free(ld->link);
2511 mem_free(ld->target);
2512 goto f;
2513 }
2514 }
2515 if (label) clr_spaces(label);
2516 if (label && !*label) mem_free(label), label = NULL;
2517 if (!label) label = stracpy(ld->link);
2518 if ((unsigned)nmenu > MAXINT / sizeof(struct menu_item) - 2) overalloc();
2519 nm = mem_realloc(*menu, (nmenu + 2) * sizeof(struct menu_item));
2520 *menu = nm;
2521 memset(&nm[nmenu], 0, 2 * sizeof(struct menu_item));
2522 nm[nmenu].text = label;
2523 nm[nmenu].rtext = "";
2524 nm[nmenu].hotkey = "";
2525 nm[nmenu].func = MENU_FUNC map_selected;
2526 nm[nmenu].data = ld;
2527 nm[++nmenu].text = NULL;
2528 add_to_ml(ml, ld, ld->link, ld->target, label, NULL);
2529 goto se2;
2530 done:
2531 add_to_ml(ml, *menu, NULL);
2532 return 0;
2533 }
2534
scan_http_equiv(unsigned char * s,unsigned char * eof,unsigned char ** head,int * hdl,unsigned char ** title)2535 void scan_http_equiv(unsigned char *s, unsigned char *eof, unsigned char **head, int *hdl, unsigned char **title)
2536 {
2537 unsigned char *name, *attr, *he, *c;
2538 int namelen;
2539 int tlen = 0;
2540 if (title) *title = init_str();
2541 add_chr_to_str(head, hdl, '\n');
2542 se:
2543 while (s < eof && *s != '<') sp:s++;
2544 if (s >= eof) return;
2545 if (eof - s >= 2 && (s[1] == '!' || s[1] == '?')) {
2546 s = skip_comment(s, eof);
2547 goto se;
2548 }
2549 if (parse_element(s, eof, &name, &namelen, &attr, &s)) goto sp;
2550 ps:
2551 if (namelen == 5 && !casecmp(name, "/HEAD", 5)) return;
2552 if (title && !tlen && namelen == 5 && !casecmp(name, "TITLE", 5)) {
2553 unsigned char *s1;
2554 xse:
2555 s1 = s;
2556 while (s < eof && *s != '<') xsp:s++;
2557 add_bytes_to_str(title, &tlen, s1, s - s1);
2558 if (s >= eof) goto se;
2559 if (eof - s >= 2 && (s[1] == '!' || s[1] == '?')) {
2560 s = skip_comment(s, eof);
2561 goto xse;
2562 }
2563 if (parse_element(s, eof, &name, &namelen, &attr, &s)) {
2564 s1 = s;
2565 goto xsp;
2566 }
2567 clr_spaces(*title);
2568 goto ps;
2569 }
2570 if (namelen != 4 || casecmp(name, "META", 4)) goto se;
2571 if ((he = get_attr_val(attr, "charset"))) {
2572 add_to_str(head, hdl, "Charset: ");
2573 add_to_str(head, hdl, he);
2574 add_to_str(head, hdl, "\r\n");
2575 mem_free(he);
2576 }
2577 if (!(he = get_attr_val(attr, "http-equiv"))) goto se;
2578 c = get_attr_val(attr, "content");
2579 add_to_str(head, hdl, he);
2580 if (c) add_to_str(head, hdl, ": "), add_to_str(head, hdl, c), mem_free(c);
2581 mem_free(he);
2582 add_to_str(head, hdl, "\r\n");
2583 goto se;
2584 }
2585
2586