Bug 784: Add html_context->doc_cp and parse attributes with it.
[elinks.git] / src / document / html / parser / general.c
blob0dbff5e9ad626c0c4abf81faac9be6e39224083d
1 /* General element handlers */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #ifndef _GNU_SOURCE
8 #define _GNU_SOURCE /* strcasestr() */
9 #endif
11 #include <ctype.h>
12 #include <errno.h>
13 #include <stdlib.h>
14 #include <string.h>
16 #include "elinks.h"
18 #include "config/options.h"
19 #include "document/css/apply.h"
20 #include "document/html/frames.h"
21 #include "document/html/parser/general.h"
22 #include "document/html/parser/link.h"
23 #include "document/html/parser/stack.h"
24 #include "document/html/parser/parse.h"
25 #include "document/html/parser.h"
26 #include "document/html/renderer.h"
27 #include "document/html/tables.h"
28 #include "document/options.h"
29 #include "intl/charsets.h"
30 #include "protocol/uri.h"
31 #include "terminal/draw.h"
32 #include "util/align.h"
33 #include "util/box.h"
34 #include "util/color.h"
35 #include "util/conv.h"
36 #include "util/error.h"
37 #include "util/memdebug.h"
38 #include "util/memory.h"
39 #include "util/string.h"
41 /* Unsafe macros */
42 #include "document/html/internal.h"
45 void
46 html_span(struct html_context *html_context, unsigned char *a,
47 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
51 void
52 html_bold(struct html_context *html_context, unsigned char *a,
53 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
55 format.style.attr |= AT_BOLD;
58 void
59 html_italic(struct html_context *html_context, unsigned char *a,
60 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
62 format.style.attr |= AT_ITALIC;
65 void
66 html_underline(struct html_context *html_context, unsigned char *a,
67 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
69 format.style.attr |= AT_UNDERLINE;
72 void
73 html_fixed(struct html_context *html_context, unsigned char *a,
74 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
76 format.style.attr |= AT_FIXED;
79 void
80 html_subscript(struct html_context *html_context, unsigned char *a,
81 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
83 put_chrs(html_context, "[", 1);
86 void
87 html_subscript_close(struct html_context *html_context, unsigned char *a,
88 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
90 put_chrs(html_context, "]", 1);
93 void
94 html_superscript(struct html_context *html_context, unsigned char *a,
95 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
97 put_chrs(html_context, "^", 1);
100 /* TODO: Add more languages. */
101 static unsigned char *quote_char[2] = { "\"", "'" };
103 void
104 html_quote(struct html_context *html_context, unsigned char *a,
105 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
107 /* An HTML document containing extremely many repetitions of
108 * "<q>" could cause @html_context->quote_level to overflow.
109 * Because it is unsigned, it then wraps around to zero, and
110 * we don't get a negative array index here. If the document
111 * then tries to close the quotes with "</q>", @html_quote_close
112 * won't let the quote level wrap back, so it will render the
113 * quotes incorrectly, but such a document probably doesn't
114 * make sense anyway. */
115 unsigned char *q = quote_char[html_context->quote_level++ % 2];
117 put_chrs(html_context, q, 1);
120 void
121 html_quote_close(struct html_context *html_context, unsigned char *a,
122 unsigned char *xxx3, unsigned char *xxx4,
123 unsigned char **xxx5)
125 unsigned char *q;
127 if (html_context->quote_level > 0)
128 html_context->quote_level--;
130 q = quote_char[html_context->quote_level % 2];
132 put_chrs(html_context, q, 1);
135 void
136 html_font(struct html_context *html_context, unsigned char *a,
137 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
139 unsigned char *al = get_attr_val(a, "size", html_context->doc_cp);
141 if (al) {
142 int p = 0;
143 unsigned s;
144 unsigned char *nn = al;
145 unsigned char *end;
147 if (*al == '+') p = 1, nn++;
148 else if (*al == '-') p = -1, nn++;
150 errno = 0;
151 s = strtoul(nn, (char **) &end, 10);
152 if (!errno && *nn && !*end) {
153 if (s > 7) s = 7;
154 if (!p) format.fontsize = s;
155 else format.fontsize += p * s;
156 if (format.fontsize < 1) format.fontsize = 1;
157 else if (format.fontsize > 7) format.fontsize = 7;
159 mem_free(al);
161 get_color(html_context, a, "color", &format.style.fg);
164 void
165 html_body(struct html_context *html_context, unsigned char *a,
166 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
168 get_color(html_context, a, "text", &format.style.fg);
169 get_color(html_context, a, "link", &format.clink);
170 get_color(html_context, a, "vlink", &format.vlink);
172 if (get_bgcolor(html_context, a, &format.style.bg) != -1)
173 html_context->was_body_background = 1;
175 html_context->was_body = 1; /* this will be used by "meta inside body" */
176 html_apply_canvas_bgcolor(html_context);
179 void
180 html_apply_canvas_bgcolor(struct html_context *html_context)
182 #ifdef CONFIG_CSS
183 /* If there are any CSS twaks regarding bgcolor, make sure we will get
184 * it _and_ prefer it over bgcolor attribute. */
185 if (html_context->options->css_enable)
186 css_apply(html_context, html_top, &html_context->css_styles,
187 &html_context->stack);
188 #endif
190 if (par_format.bgcolor != format.style.bg) {
191 /* Modify the root HTML element - format_html_part() will take
192 * this from there. */
193 struct html_element *e = html_bottom;
195 html_context->was_body_background = 1;
196 e->parattr.bgcolor = e->attr.style.bg = par_format.bgcolor = format.style.bg;
199 if (html_context->has_link_lines
200 && par_format.bgcolor != html_context->options->default_bg
201 && !search_html_stack(html_context, "BODY")) {
202 html_context->special_f(html_context, SP_COLOR_LINK_LINES);
206 void
207 html_script(struct html_context *html_context, unsigned char *a,
208 unsigned char *html, unsigned char *eof, unsigned char **end)
210 #ifdef CONFIG_ECMASCRIPT
211 /* TODO: <noscript> processing. Well, same considerations apply as to
212 * CSS property display: none processing. */
213 /* TODO: Charsets for external scripts. */
214 unsigned char *type, *language, *src;
215 int in_comment = 0;
216 #endif
218 html_skip(html_context, a);
220 #ifdef CONFIG_ECMASCRIPT
221 /* We try to process nested <script> if we didn't process the parent
222 * one. That's why's all the fuzz. */
223 /* Ref:
224 * http://www.ietf.org/internet-drafts/draft-hoehrmann-script-types-03.txt
226 type = get_attr_val(a, "type", html_context->doc_cp);
227 if (type) {
228 unsigned char *pos = type;
230 if (!strncasecmp(type, "text/", 5)) {
231 pos += 5;
233 } else if (!strncasecmp(type, "application/", 12)) {
234 pos += 12;
236 } else {
237 mem_free(type);
238 not_processed:
239 /* Permit nested scripts and retreat. */
240 html_top->invisible++;
241 return;
244 if (!strncasecmp(pos, "javascript", 10)) {
245 int len = strlen(pos);
247 if (len > 10 && !isdigit(pos[10])) {
248 mem_free(type);
249 goto not_processed;
252 } else if (strcasecmp(pos, "ecmascript")
253 && strcasecmp(pos, "jscript")
254 && strcasecmp(pos, "livescript")
255 && strcasecmp(pos, "x-javascript")
256 && strcasecmp(pos, "x-ecmascript")) {
257 mem_free(type);
258 goto not_processed;
261 mem_free(type);
264 /* Check that the script content is ecmascript. The value of the
265 * language attribute can be JavaScript with optional version digits
266 * postfixed (like: ``JavaScript1.1'').
267 * That attribute is deprecated in favor of type by HTML 4.01 */
268 language = get_attr_val(a, "language", html_context->doc_cp);
269 if (language) {
270 int languagelen = strlen(language);
272 if (languagelen < 10
273 || (languagelen > 10 && !isdigit(language[10]))
274 || strncasecmp(language, "javascript", 10)) {
275 mem_free(language);
276 goto not_processed;
279 mem_free(language);
282 if (html_context->part->document
283 && (src = get_attr_val(a, "src", html_context->doc_cp))) {
284 /* External reference. */
286 unsigned char *import_url;
287 struct uri *uri;
289 if (!get_opt_bool("ecmascript.enable")) {
290 mem_free(src);
291 goto not_processed;
294 /* HTML <head> urls should already be fine but we can.t detect them. */
295 import_url = join_urls(html_context->base_href, src);
296 mem_free(src);
297 if (!import_url) goto imported;
299 uri = get_uri(import_url, URI_BASE);
300 if (!uri) goto imported;
302 /* Request the imported script as part of the document ... */
303 html_context->special_f(html_context, SP_SCRIPT, uri);
304 done_uri(uri);
306 /* Create URL reference onload snippet. */
307 insert_in_string(&import_url, 0, "^", 1);
308 add_to_string_list(&html_context->part->document->onload_snippets,
309 import_url, -1);
311 imported:
312 /* Retreat. Do not permit nested scripts, tho'. */
313 if (import_url) mem_free(import_url);
314 return;
317 /* Positive, grab the rest and interpret it. */
319 /* First position to the real script start. */
320 while (html < eof && *html <= ' ') html++;
321 if (eof - html > 4 && !strncmp(html, "<!--", 4)) {
322 in_comment = 1;
323 /* We either skip to the end of line or to -->. */
324 for (; *html != '\n' && *html != '\r' && eof - html >= 3; html++) {
325 if (!strncmp(html, "-->", 3)) {
326 /* This means the document is probably broken.
327 * We will now try to process the rest of
328 * <script> contents, which is however likely
329 * to be empty. Should we try to process the
330 * comment too? Currently it seems safer but
331 * less tolerant to broken pages, if there are
332 * any like this. */
333 html += 3;
334 in_comment = 0;
335 break;
340 *end = html;
342 /* Now look ahead for the script end. The <script> contents is raw
343 * CDATA, so we just look for the ending tag and need not care for
344 * any quote marks counting etc - YET, we are more tolerant and permit
345 * </script> stuff inside of the script if the whole <script> element
346 * contents is wrapped in a comment. See i.e. Mozilla bug 26857 for fun
347 * reading regarding this. */
348 for (; *end < eof; (*end)++) {
349 unsigned char *name;
350 int namelen;
352 if (in_comment) {
353 /* TODO: If we ever get some standards-quirk mode
354 * distinction, this should be disabled in the
355 * standards mode (and we should just look for CDATA
356 * end, which is "</"). --pasky */
357 if (eof - *end >= 3 && !strncmp(*end, "-->", 3)) {
358 /* Next iteration will jump passed the ending '>' */
359 (*end) += 2;
360 in_comment = 0;
362 continue;
363 /* XXX: Scan for another comment? That's admittelly
364 * already stretching things a little bit to an
365 * extreme ;-). */
368 if (**end != '<')
369 continue;
370 /* We want to land before the closing element, that's why we
371 * don't pass @end also as the appropriate parse_element()
372 * argument. */
373 if (parse_element(*end, eof, &name, &namelen, NULL, NULL))
374 continue;
375 if (strlcasecmp(name, namelen, "/script", 7))
376 continue;
377 /* We have won! */
378 break;
380 if (*end >= eof) {
381 /* Either the document is not completely loaded yet or it's
382 * broken. At any rate, run away screaming. */
383 *end = eof; /* Just for sanity. */
384 return;
387 if (html_context->part->document && *html != '^') {
388 add_to_string_list(&html_context->part->document->onload_snippets,
389 html, *end - html);
391 #endif
394 void
395 html_style(struct html_context *html_context, unsigned char *a,
396 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
398 html_context->was_style = 1;
399 html_skip(html_context, a);
402 void
403 html_style_close(struct html_context *html_context, unsigned char *a,
404 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
406 html_context->was_style = 0;
409 void
410 html_html(struct html_context *html_context, unsigned char *a,
411 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
413 /* This is here just to get CSS stuff applied. */
415 /* Modify the root HTML element - format_html_part() will take
416 * this from there. */
417 struct html_element *e = html_bottom;
419 if (par_format.bgcolor != format.style.bg)
420 e->parattr.bgcolor = e->attr.style.bg = par_format.bgcolor = format.style.bg;
423 void
424 html_html_close(struct html_context *html_context, unsigned char *a,
425 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
427 if (html_top->type >= ELEMENT_KILLABLE
428 && !html_context->was_body_background)
429 html_apply_canvas_bgcolor(html_context);
432 void
433 html_head(struct html_context *html_context, unsigned char *a,
434 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
436 /* This makes sure it gets to the stack and helps tame down unclosed
437 * <title>. */
440 void
441 html_meta(struct html_context *html_context, unsigned char *a,
442 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
444 /* html_handle_body_meta() does all the work. */
447 /* Handles meta tags in the HTML body. */
448 void
449 html_handle_body_meta(struct html_context *html_context, unsigned char *meta,
450 unsigned char *eof)
452 struct string head;
454 if (!init_string(&head)) return;
456 scan_http_equiv(meta, eof, &head, NULL, html_context->options);
457 process_head(html_context, head.source);
458 done_string(&head);
461 void
462 html_title(struct html_context *html_context, unsigned char *a,
463 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
465 html_top->invisible = 1;
466 html_top->type = ELEMENT_WEAK;
469 void
470 html_center(struct html_context *html_context, unsigned char *a,
471 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
473 par_format.align = ALIGN_CENTER;
474 if (!html_context->table_level)
475 par_format.leftmargin = par_format.rightmargin = 0;
478 void
479 html_linebrk(struct html_context *html_context, unsigned char *a,
480 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
482 unsigned char *al = get_attr_val(a, "align", html_context->doc_cp);
484 if (al) {
485 if (!strcasecmp(al, "left")) par_format.align = ALIGN_LEFT;
486 else if (!strcasecmp(al, "right")) par_format.align = ALIGN_RIGHT;
487 else if (!strcasecmp(al, "center")) {
488 par_format.align = ALIGN_CENTER;
489 if (!html_context->table_level)
490 par_format.leftmargin = par_format.rightmargin = 0;
491 } else if (!strcasecmp(al, "justify")) par_format.align = ALIGN_JUSTIFY;
492 mem_free(al);
496 void
497 html_br(struct html_context *html_context, unsigned char *a,
498 unsigned char *html, unsigned char *eof, unsigned char **end)
500 html_linebrk(html_context, a, html, eof, end);
501 if (html_context->was_br)
502 ln_break(html_context, 2);
503 else
504 html_context->was_br = 1;
507 void
508 html_p(struct html_context *html_context, unsigned char *a,
509 unsigned char *html, unsigned char *eof, unsigned char **end)
511 int_lower_bound(&par_format.leftmargin, html_context->margin);
512 int_lower_bound(&par_format.rightmargin, html_context->margin);
513 /*par_format.align = ALIGN_LEFT;*/
514 html_linebrk(html_context, a, html, eof, end);
517 void
518 html_address(struct html_context *html_context, unsigned char *a,
519 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
521 par_format.leftmargin++;
522 par_format.align = ALIGN_LEFT;
525 void
526 html_blockquote(struct html_context *html_context, unsigned char *a,
527 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
529 par_format.leftmargin += 2;
530 par_format.align = ALIGN_LEFT;
533 void
534 html_h(int h, unsigned char *a,
535 enum format_align default_align, struct html_context *html_context,
536 unsigned char *html, unsigned char *eof, unsigned char **end)
538 if (!par_format.align) par_format.align = default_align;
539 html_linebrk(html_context, a, html, eof, end);
541 h -= 2;
542 if (h < 0) h = 0;
544 switch (par_format.align) {
545 case ALIGN_LEFT:
546 par_format.leftmargin = h * 2;
547 par_format.rightmargin = 0;
548 break;
549 case ALIGN_RIGHT:
550 par_format.leftmargin = 0;
551 par_format.rightmargin = h * 2;
552 break;
553 case ALIGN_CENTER:
554 par_format.leftmargin = par_format.rightmargin = 0;
555 break;
556 case ALIGN_JUSTIFY:
557 par_format.leftmargin = par_format.rightmargin = h * 2;
558 break;
562 void
563 html_h1(struct html_context *html_context, unsigned char *a,
564 unsigned char *html, unsigned char *eof, unsigned char **end)
566 format.style.attr |= AT_BOLD;
567 html_h(1, a, ALIGN_CENTER, html_context, html, eof, end);
570 void
571 html_h2(struct html_context *html_context, unsigned char *a,
572 unsigned char *html, unsigned char *eof, unsigned char **end)
574 html_h(2, a, ALIGN_LEFT, html_context, html, eof, end);
577 void
578 html_h3(struct html_context *html_context, unsigned char *a,
579 unsigned char *html, unsigned char *eof, unsigned char **end)
581 html_h(3, a, ALIGN_LEFT, html_context, html, eof, end);
584 void
585 html_h4(struct html_context *html_context, unsigned char *a,
586 unsigned char *html, unsigned char *eof, unsigned char **end)
588 html_h(4, a, ALIGN_LEFT, html_context, html, eof, end);
591 void
592 html_h5(struct html_context *html_context, unsigned char *a,
593 unsigned char *html, unsigned char *eof, unsigned char **end)
595 html_h(5, a, ALIGN_LEFT, html_context, html, eof, end);
598 void
599 html_h6(struct html_context *html_context, unsigned char *a,
600 unsigned char *html, unsigned char *eof, unsigned char **end)
602 html_h(6, a, ALIGN_LEFT, html_context, html, eof, end);
605 void
606 html_pre(struct html_context *html_context, unsigned char *a,
607 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
609 format.style.attr |= AT_PREFORMATTED;
610 par_format.leftmargin = (par_format.leftmargin > 1);
611 par_format.rightmargin = 0;
614 void
615 html_xmp(struct html_context *html_context, unsigned char *a,
616 unsigned char *html, unsigned char *eof, unsigned char **end)
618 html_context->was_xmp = 1;
619 html_pre(html_context, a, html, eof, end);
622 void
623 html_xmp_close(struct html_context *html_context, unsigned char *a,
624 unsigned char *html, unsigned char *eof, unsigned char **end)
626 html_context->was_xmp = 0;
629 void
630 html_hr(struct html_context *html_context, unsigned char *a,
631 unsigned char *html, unsigned char *eof, unsigned char **end)
633 int i/* = par_format.width - 10*/;
634 unsigned char r = (unsigned char) BORDER_DHLINE;
635 int q = get_num(a, "size", html_context->doc_cp);
637 if (q >= 0 && q < 2) r = (unsigned char) BORDER_SHLINE;
638 html_stack_dup(html_context, ELEMENT_KILLABLE);
639 par_format.align = ALIGN_CENTER;
640 mem_free_set(&format.link, NULL);
641 format.form = NULL;
642 html_linebrk(html_context, a, html, eof, end);
643 if (par_format.align == ALIGN_JUSTIFY) par_format.align = ALIGN_CENTER;
644 par_format.leftmargin = par_format.rightmargin = html_context->margin;
646 i = get_width(a, "width", 1, html_context);
647 if (i == -1) i = get_html_max_width();
648 format.style.attr = AT_GRAPHICS;
649 html_context->special_f(html_context, SP_NOWRAP, 1);
650 while (i-- > 0) {
651 put_chrs(html_context, &r, 1);
653 html_context->special_f(html_context, SP_NOWRAP, 0);
654 ln_break(html_context, 2);
655 pop_html_element(html_context);
658 void
659 html_table(struct html_context *html_context, unsigned char *attr,
660 unsigned char *html, unsigned char *eof, unsigned char **end)
662 if (html_context->options->tables
663 && html_context->table_level < HTML_MAX_TABLE_LEVEL) {
664 format_table(attr, html, eof, end, html_context);
665 ln_break(html_context, 2);
667 return;
670 par_format.leftmargin = par_format.rightmargin = html_context->margin;
671 par_format.align = ALIGN_LEFT;
672 html_linebrk(html_context, attr, html, eof, end);
673 format.style.attr = 0;
676 void
677 html_tt(struct html_context *html_context, unsigned char *a,
678 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
682 void
683 html_tr(struct html_context *html_context, unsigned char *a,
684 unsigned char *html, unsigned char *eof, unsigned char **end)
686 html_linebrk(html_context, a, html, eof, end);
689 void
690 html_th(struct html_context *html_context, unsigned char *a,
691 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
693 /*html_linebrk(html_context, a, html, eof, end);*/
694 kill_html_stack_until(html_context, 1,
695 "TD", "TH", "", "TR", "TABLE", NULL);
696 format.style.attr |= AT_BOLD;
697 put_chrs(html_context, " ", 1);
700 void
701 html_td(struct html_context *html_context, unsigned char *a,
702 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
704 /*html_linebrk(html_context, a, html, eof, end);*/
705 kill_html_stack_until(html_context, 1,
706 "TD", "TH", "", "TR", "TABLE", NULL);
707 format.style.attr &= ~AT_BOLD;
708 put_chrs(html_context, " ", 1);
711 void
712 html_base(struct html_context *html_context, unsigned char *a,
713 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
715 unsigned char *al;
717 al = get_url_val(a, "href", html_context->doc_cp);
718 if (al) {
719 unsigned char *base = join_urls(html_context->base_href, al);
720 struct uri *uri = base ? get_uri(base, 0) : NULL;
722 mem_free(al);
723 mem_free_if(base);
725 if (uri) {
726 done_uri(html_context->base_href);
727 html_context->base_href = uri;
731 al = get_target(html_context->options, a);
732 if (al) mem_free_set(&html_context->base_target, al);
735 void
736 html_ul(struct html_context *html_context, unsigned char *a,
737 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
739 unsigned char *al;
741 /* dump_html_stack(html_context); */
742 par_format.list_level++;
743 par_format.list_number = 0;
744 par_format.flags = P_STAR;
746 al = get_attr_val(a, "type", html_context->doc_cp);
747 if (al) {
748 if (!strcasecmp(al, "disc") || !strcasecmp(al, "circle"))
749 par_format.flags = P_O;
750 else if (!strcasecmp(al, "square"))
751 par_format.flags = P_PLUS;
752 mem_free(al);
754 par_format.leftmargin += 2 + (par_format.list_level > 1);
755 if (!html_context->table_level)
756 int_upper_bound(&par_format.leftmargin, par_format.width / 2);
758 par_format.align = ALIGN_LEFT;
759 html_top->type = ELEMENT_DONT_KILL;
762 void
763 html_ol(struct html_context *html_context, unsigned char *a,
764 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
766 unsigned char *al;
767 int st;
769 par_format.list_level++;
770 st = get_num(a, "start", html_context->doc_cp);
771 if (st == -1) st = 1;
772 par_format.list_number = st;
773 par_format.flags = P_NUMBER;
775 al = get_attr_val(a, "type", html_context->doc_cp);
776 if (al) {
777 if (*al && !al[1]) {
778 if (*al == '1') par_format.flags = P_NUMBER;
779 else if (*al == 'a') par_format.flags = P_alpha;
780 else if (*al == 'A') par_format.flags = P_ALPHA;
781 else if (*al == 'r') par_format.flags = P_roman;
782 else if (*al == 'R') par_format.flags = P_ROMAN;
783 else if (*al == 'i') par_format.flags = P_roman;
784 else if (*al == 'I') par_format.flags = P_ROMAN;
786 mem_free(al);
789 par_format.leftmargin += (par_format.list_level > 1);
790 if (!html_context->table_level)
791 int_upper_bound(&par_format.leftmargin, par_format.width / 2);
793 par_format.align = ALIGN_LEFT;
794 html_top->type = ELEMENT_DONT_KILL;
797 static struct {
798 int n;
799 unsigned char *s;
800 } roman_tbl[] = {
801 {1000, "m"},
802 {999, "im"},
803 {990, "xm"},
804 {900, "cm"},
805 {500, "d"},
806 {499, "id"},
807 {490, "xd"},
808 {400, "cd"},
809 {100, "c"},
810 {99, "ic"},
811 {90, "xc"},
812 {50, "l"},
813 {49, "il"},
814 {40, "xl"},
815 {10, "x"},
816 {9, "ix"},
817 {5, "v"},
818 {4, "iv"},
819 {1, "i"},
820 {0, NULL}
823 static void
824 roman(unsigned char *p, unsigned n)
826 int i = 0;
828 if (n >= 4000) {
829 strcpy(p, "---");
830 return;
832 if (!n) {
833 strcpy(p, "o");
834 return;
836 p[0] = 0;
837 while (n) {
838 while (roman_tbl[i].n <= n) {
839 n -= roman_tbl[i].n;
840 strcat(p, roman_tbl[i].s);
842 i++;
843 assertm(!(n && !roman_tbl[i].n),
844 "BUG in roman number convertor");
845 if_assert_failed break;
849 void
850 html_li(struct html_context *html_context, unsigned char *a,
851 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
853 /* When handling the code <li><li> @was_li will be 1 and it means we
854 * have to insert a line break since no list item content has done it
855 * for us. */
856 if (html_context->was_li) {
857 html_context->line_breax = 0;
858 ln_break(html_context, 1);
861 /*kill_html_stack_until(html_context, 0
862 "", "UL", "OL", NULL);*/
863 if (!par_format.list_number) {
864 unsigned char x[7] = "*&nbsp;";
865 int t = par_format.flags & P_LISTMASK;
867 if (t == P_O) x[0] = 'o';
868 if (t == P_PLUS) x[0] = '+';
869 put_chrs(html_context, x, 7);
870 par_format.leftmargin += 2;
871 par_format.align = ALIGN_LEFT;
873 } else {
874 unsigned char c = 0;
875 unsigned char n[32];
876 int nlen;
877 int t = par_format.flags & P_LISTMASK;
878 int s = get_num(a, "value", html_context->doc_cp);
880 if (s != -1) par_format.list_number = s;
882 if (t == P_ALPHA || t == P_alpha) {
883 put_chrs(html_context, "&nbsp;", 6);
884 c = 1;
885 n[0] = par_format.list_number
886 ? (par_format.list_number - 1) % 26
887 + (t == P_ALPHA ? 'A' : 'a')
888 : 0;
889 n[1] = 0;
891 } else if (t == P_ROMAN || t == P_roman) {
892 roman(n, par_format.list_number);
893 if (t == P_ROMAN) {
894 unsigned char *x;
896 for (x = n; *x; x++) *x = toupper(*x);
899 } else {
900 if (par_format.list_number < 10) {
901 put_chrs(html_context, "&nbsp;", 6);
902 c = 1;
905 ulongcat(n, NULL, par_format.list_number, (sizeof(n) - 1), 0);
908 nlen = strlen(n);
909 put_chrs(html_context, n, nlen);
910 put_chrs(html_context, ".&nbsp;", 7);
911 par_format.leftmargin += nlen + c + 2;
912 par_format.align = ALIGN_LEFT;
915 struct html_element *element;
917 element = search_html_stack(html_context, "ol");
918 if (element)
919 element->parattr.list_number = par_format.list_number + 1;
922 par_format.list_number = 0;
925 html_context->putsp = HTML_SPACE_SUPPRESS;
926 html_context->line_breax = 2;
927 html_context->was_li = 1;
930 void
931 html_dl(struct html_context *html_context, unsigned char *a,
932 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
934 par_format.flags &= ~P_COMPACT;
935 if (has_attr(a, "compact", html_context->doc_cp))
936 par_format.flags |= P_COMPACT;
937 if (par_format.list_level) par_format.leftmargin += 5;
938 par_format.list_level++;
939 par_format.list_number = 0;
940 par_format.align = ALIGN_LEFT;
941 par_format.dd_margin = par_format.leftmargin;
942 html_top->type = ELEMENT_DONT_KILL;
943 if (!(par_format.flags & P_COMPACT)) {
944 ln_break(html_context, 2);
945 html_top->linebreak = 2;
949 void
950 html_dt(struct html_context *html_context, unsigned char *a,
951 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
953 kill_html_stack_until(html_context, 0, "", "DL", NULL);
954 par_format.align = ALIGN_LEFT;
955 par_format.leftmargin = par_format.dd_margin;
956 if (!(par_format.flags & P_COMPACT)
957 && !has_attr(a, "compact", html_context->doc_cp))
958 ln_break(html_context, 2);
961 void
962 html_dd(struct html_context *html_context, unsigned char *a,
963 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
965 kill_html_stack_until(html_context, 0, "", "DL", NULL);
967 par_format.leftmargin = par_format.dd_margin + 3;
969 if (!html_context->table_level) {
970 par_format.leftmargin += 5;
971 int_upper_bound(&par_format.leftmargin, par_format.width / 2);
973 par_format.align = ALIGN_LEFT;
978 void
979 html_noframes(struct html_context *html_context, unsigned char *a,
980 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
982 struct html_element *element;
984 if (!html_context->options->frames) return;
986 element = search_html_stack(html_context, "frameset");
987 if (element && !element->frameset) return;
989 html_skip(html_context, a);
992 void
993 html_frame(struct html_context *html_context, unsigned char *a,
994 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
996 unsigned char *name, *src, *url;
998 src = get_url_val(a, "src", html_context->doc_cp);
999 if (!src) {
1000 url = stracpy("about:blank");
1001 } else {
1002 url = join_urls(html_context->base_href, src);
1003 mem_free(src);
1005 if (!url) return;
1007 name = get_attr_val(a, "name", html_context->doc_cp);
1008 if (!name) {
1009 name = stracpy(url);
1010 } else if (!name[0]) {
1011 /* When name doesn't have a value */
1012 mem_free(name);
1013 name = stracpy(url);
1015 if (!name) return;
1017 if (!html_context->options->frames || !html_top->frameset) {
1018 html_focusable(html_context, a);
1019 put_link_line("Frame: ", name, url, "", html_context);
1021 } else {
1022 if (html_context->special_f(html_context, SP_USED, NULL)) {
1023 html_context->special_f(html_context, SP_FRAME,
1024 html_top->frameset, name, url);
1028 mem_free(name);
1029 mem_free(url);
1032 void
1033 html_frameset(struct html_context *html_context, unsigned char *a,
1034 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
1036 struct frameset_param fp;
1037 unsigned char *cols, *rows;
1038 int width, height;
1040 /* XXX: This is still not 100% correct. We should also ignore the
1041 * frameset when we encountered anything 3v1l (read as: non-whitespace
1042 * text/element/anything) in the document outside of <head>. Well, this
1043 * is still better than nothing and it should heal up the security
1044 * concerns at least because sane sites should enclose the documents in
1045 * <body> elements ;-). See also bug 171. --pasky */
1046 if (search_html_stack(html_context, "BODY")
1047 || !html_context->options->frames
1048 || !html_context->special_f(html_context, SP_USED, NULL))
1049 return;
1051 cols = get_attr_val(a, "cols", html_context->doc_cp);
1052 if (!cols) {
1053 cols = stracpy("100%");
1054 if (!cols) return;
1057 rows = get_attr_val(a, "rows", html_context->doc_cp);
1058 if (!rows) {
1059 rows = stracpy("100%");
1060 if (!rows) {
1061 mem_free(cols);
1062 return;
1066 if (!html_top->frameset) {
1067 width = html_context->options->box.width;
1068 height = html_context->options->box.height;
1069 html_context->options->needs_height = 1;
1070 } else {
1071 struct frameset_desc *frameset_desc = html_top->frameset;
1072 int offset;
1074 if (frameset_desc->box.y >= frameset_desc->box.height)
1075 goto free_and_return;
1076 offset = frameset_desc->box.x
1077 + frameset_desc->box.y * frameset_desc->box.width;
1078 width = frameset_desc->frame_desc[offset].width;
1079 height = frameset_desc->frame_desc[offset].height;
1082 fp.width = fp.height = NULL;
1084 parse_frame_widths(cols, width, HTML_FRAME_CHAR_WIDTH,
1085 &fp.width, &fp.x);
1086 parse_frame_widths(rows, height, HTML_FRAME_CHAR_HEIGHT,
1087 &fp.height, &fp.y);
1089 fp.parent = html_top->frameset;
1090 if (fp.x && fp.y) {
1091 html_top->frameset = html_context->special_f(html_context, SP_FRAMESET, &fp);
1093 mem_free_if(fp.width);
1094 mem_free_if(fp.height);
1096 free_and_return:
1097 mem_free(cols);
1098 mem_free(rows);
1101 void
1102 html_noscript(struct html_context *html_context, unsigned char *a,
1103 unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
1105 /* We shouldn't throw <noscript> away until our ECMAScript support is
1106 * halfway decent. */
1107 #ifdef CONFIG_ECMASCRIPT
1108 if (get_opt_bool("ecmascript.enable")
1109 && get_opt_bool("ecmascript.ignore_noscript"))
1110 html_skip(html_context, a);
1111 #endif