aboutsummaryrefslogtreecommitdiff
path: root/src/html.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/html.cc')
-rw-r--r--src/html.cc249
1 files changed, 124 insertions, 125 deletions
diff --git a/src/html.cc b/src/html.cc
index 0945d6f9..3f7861d7 100644
--- a/src/html.cc
+++ b/src/html.cc
@@ -119,7 +119,6 @@ typedef struct {
TagOpenFunct content; /* Content function */
TagCloseFunct close; /* Close function */
} TagInfo;
-extern const TagInfo Tags[];
/* Some element indexes required in scattered places */
static int
@@ -1373,129 +1372,6 @@ static void Html_real_pop_tag(DilloHtml *html)
Html_eventually_pop_dw(html, hand_over_break);
}
-/*
- * Check nesting and cross-nesting between BUTTON, SELECT, TEXTAREA and A.
- * The cleanup process will close any of them before opening another.
- * This is not an HTML SPEC restriction , but it avoids lots of trouble
- * inside dillo (concurrent inputs), and makes almost no sense to have.
- * return: index of the open element, -1 if none.
- */
-static inline int Html_forbids_cross_nesting(const int InFlags,
- const int new_idx)
-{
- int f = InFlags, ni = new_idx, oi = -1;
- if (f & (IN_A | IN_BUTTON | IN_SELECT | IN_TEXTAREA) &&
- (ni == i_A || ni == i_BUTTON || ni == i_SELECT || ni == i_TEXTAREA))
- oi = (f & IN_A ? i_A : f & IN_BUTTON ? i_BUTTON : f & IN_SELECT ?
- i_SELECT : f & IN_TEXTAREA ? i_TEXTAREA : 0);
- return oi;
-}
-
-/*
- * Cleanup the stack to a given index.
- *
- * 's_idx' stack index to clean up to.
- * 'new_idx' is the tag index that triggered the cleanup.
- * 'fi' forbidden tag index. -1 if allowed (most of the time).
- * 'op' cleanup operation. {'o' = open, 'c' = close}.
- */
-static void Html_tag_cleanup_to_idx(DilloHtml *html, int s_idx,
- int new_idx, int fi, char op)
-{
- int s_top, ni = new_idx;
- while ((s_top = html->stack->size() - 1) >= s_idx) {
- int toptag_idx = S_TOP(html)->tag_idx;
- TagInfo toptag = Tags[toptag_idx];
-
- if (fi >= 0) {
- // forbidden nesting
- if (toptag_idx != fi)
- BUG_MSG(" Nesting cleanup - forcing close of open tag: <%s>.",
- toptag.name);
- } else if (s_top == s_idx && op == 'c') {
- // target tag, no bug when closing.
- } else if (toptag.EndTag == 'O') {
- // optional close, that's OK
- } else if ((!(toptag.Flags & 4) &&
- (Tags[ni].Flags & 4 || !(Tags[ni].Flags & 1))) ||
- (Tags[ni].Flags & 1 && !(toptag.Flags & 2))) {
- // block {element, container} in non block container or
- // inline element in non inline container
- BUG_MSG((op == 'o') ?
- "Bad nesting: <%s> can't contain <%s>. -- closing <%s>." :
- "<%s> must have been closed before </%s>. -- closing <%s>.",
- toptag.name, Tags[ni].name, toptag.name);
- } else {
- BUG_MSG(
- "<%s> should have been closed before </%s>. -- closing <%s>.",
- toptag.name, Tags[ni].name, toptag.name);
- }
- _MSG("op(%c): %s s_top=%d s_idx=%d\n", op, toptag.name, s_top, s_idx);
- if (toptag_idx == i_BODY &&
- !((html->InFlags & IN_EOF) || html->ReqTagClose)) {
- (s_idx == 1 ? html->PrevWasHtmlClose : html->PrevWasBodyClose) = true;
- break; // only pop {BODY,HTML} upon EOF or redundancy
- }
- if (toptag.close)
- toptag.close(html);
- Html_real_pop_tag(html);
- }
-}
-
-/*
- * Conditional cleanup of the stack, called before closing any tag.
- *
- * There are several ways of doing it. Considering the HTML 4.01 spec
- * which defines optional close tags, and the will to deliver useful diagnose
- * messages for bad-formed HTML, it'll go as follows:
- *
- * 1.- Search the stack for a matching tag by closing elements that:
- * have optional close | are inline in a block container | force closing.
- * 2.- If it exists, clean all the tags in between.
- * 3.- Cleanup the matching tag. (on error, give a warning message)
- */
-static void Html_tag_cleanup_at_close(DilloHtml *html, int new_idx)
-{
- int stack_idx, tag_idx, matched = 0, expected = 0;
- TagInfo new_tag = Tags[new_idx];
-
- /* Look for the candidate tag to close */
- stack_idx = html->stack->size();
- while (--stack_idx) {
- tag_idx = html->stack->getRef(stack_idx)->tag_idx;
- if (tag_idx == new_idx) {
- /* matching tag found */
- matched = 1;
- break;
- } else if (Tags[tag_idx].EndTag == 'O') {
- /* close elements with optional close */
- continue;
- } else if ((new_idx == i_A && html->InFlags & IN_A) ||
- (new_idx == i_BUTTON && html->InFlags & IN_BUTTON) ||
- (new_idx == i_SELECT && html->InFlags & IN_SELECT) ||
- (new_idx == i_TEXTAREA && html->InFlags & IN_TEXTAREA)) {
- /* Let these elements close anything left open inside them */
- continue;
- } else if (Tags[new_idx].Flags & 4 && // Block container
- Tags[stack_idx].Flags & 3) { // Inline element or container
- /* Let a block container close inline elements left open inside it. */
- continue;
- } else {
- /* this is the tag that should have been closed */
- expected = 1;
- break;
- }
- }
-
- if (matched) {
- Html_tag_cleanup_to_idx(html, stack_idx, new_idx, -1, 'c');
- } else if (expected) {
- BUG_MSG("Unexpected closing tag: </%s> -- expected </%s>.",
- new_tag.name, Tags[tag_idx].name);
- } else {
- BUG_MSG("Unexpected closing tag: </%s>.", new_tag.name);
- }
-}
/*
@@ -3562,7 +3438,7 @@ static void Html_tag_content_wbr(DilloHtml *html, const char *tag, int tagsize)
* (flow have both set)
*/
-const TagInfo Tags[] = {
+static const TagInfo Tags[] = {
{"a", B8(01011),'R',2, Html_tag_open_a, NULL, Html_tag_close_a},
{"abbr", B8(01011),'R',2, Html_tag_open_abbr, NULL, NULL},
/* acronym 010101 -- obsolete in HTML5 */
@@ -3768,6 +3644,74 @@ static int Html_triggers_optional_close(int old_idx, int cur_idx)
return 0;
}
+/*
+ * Check nesting and cross-nesting between BUTTON, SELECT, TEXTAREA and A.
+ * The cleanup process will close any of them before opening another.
+ * This is not an HTML SPEC restriction , but it avoids lots of trouble
+ * inside dillo (concurrent inputs), and makes almost no sense to have.
+ * return: index of the open element, -1 if none.
+ */
+static inline int Html_forbids_cross_nesting(const int InFlags,
+ const int new_idx)
+{
+ int f = InFlags, ni = new_idx, oi = -1;
+ if (f & (IN_A | IN_BUTTON | IN_SELECT | IN_TEXTAREA) &&
+ (ni == i_A || ni == i_BUTTON || ni == i_SELECT || ni == i_TEXTAREA))
+ oi = (f & IN_A ? i_A : f & IN_BUTTON ? i_BUTTON : f & IN_SELECT ?
+ i_SELECT : f & IN_TEXTAREA ? i_TEXTAREA : 0);
+ return oi;
+}
+
+/*
+ * Cleanup the stack to a given index.
+ *
+ * 's_idx' stack index to clean up to.
+ * 'new_idx' is the tag index that triggered the cleanup.
+ * 'fi' forbidden tag index. -1 if allowed (most of the time).
+ * 'op' cleanup operation. {'o' = open, 'c' = close}.
+ */
+static void Html_tag_cleanup_to_idx(DilloHtml *html, int s_idx,
+ int new_idx, int fi, char op)
+{
+ int s_top, ni = new_idx;
+ while ((s_top = html->stack->size() - 1) >= s_idx) {
+ int toptag_idx = S_TOP(html)->tag_idx;
+ TagInfo toptag = Tags[toptag_idx];
+
+ if (fi >= 0) {
+ // forbidden nesting
+ if (toptag_idx != fi)
+ BUG_MSG(" Nesting cleanup - forcing close of open tag: <%s>.",
+ toptag.name);
+ } else if (s_top == s_idx && op == 'c') {
+ // target tag, no bug when closing.
+ } else if (toptag.EndTag == 'O') {
+ // optional close, that's OK
+ } else if ((!(toptag.Flags & 4) &&
+ (Tags[ni].Flags & 4 || !(Tags[ni].Flags & 1))) ||
+ (Tags[ni].Flags & 1 && !(toptag.Flags & 2))) {
+ // block {element, container} in non block container or
+ // inline element in non inline container
+ BUG_MSG((op == 'o') ?
+ "Bad nesting: <%s> can't contain <%s>. -- closing <%s>." :
+ "<%s> must have been closed before </%s>. -- closing <%s>.",
+ toptag.name, Tags[ni].name, toptag.name);
+ } else {
+ BUG_MSG(
+ "<%s> should have been closed before </%s>. -- closing <%s>.",
+ toptag.name, Tags[ni].name, toptag.name);
+ }
+ _MSG("op(%c): %s s_top=%d s_idx=%d\n", op, toptag.name, s_top, s_idx);
+ if (toptag_idx == i_BODY &&
+ !((html->InFlags & IN_EOF) || html->ReqTagClose)) {
+ (s_idx == 1 ? html->PrevWasHtmlClose : html->PrevWasBodyClose) = true;
+ break; // only pop {BODY,HTML} upon EOF or redundancy
+ }
+ if (toptag.close)
+ toptag.close(html);
+ Html_real_pop_tag(html);
+ }
+}
/*
* Conditional cleanup of the stack (at open time). Handles:
@@ -3815,6 +3759,61 @@ static void Html_stack_cleanup_at_open(DilloHtml *html, int ni)
}
/*
+ * Conditional cleanup of the stack, called before closing any tag.
+ *
+ * There are several ways of doing it. Considering the HTML 4.01 spec
+ * which defines optional close tags, and the will to deliver useful diagnose
+ * messages for bad-formed HTML, it'll go as follows:
+ *
+ * 1.- Search the stack for a matching tag by closing elements that:
+ * have optional close | are inline in a block container | force closing.
+ * 2.- If it exists, clean all the tags in between.
+ * 3.- Cleanup the matching tag. (on error, give a warning message)
+ */
+static void Html_tag_cleanup_at_close(DilloHtml *html, int new_idx)
+{
+ int stack_idx, tag_idx, matched = 0, expected = 0;
+ TagInfo new_tag = Tags[new_idx];
+
+ /* Look for the candidate tag to close */
+ stack_idx = html->stack->size();
+ while (--stack_idx) {
+ tag_idx = html->stack->getRef(stack_idx)->tag_idx;
+ if (tag_idx == new_idx) {
+ /* matching tag found */
+ matched = 1;
+ break;
+ } else if (Tags[tag_idx].EndTag == 'O') {
+ /* close elements with optional close */
+ continue;
+ } else if ((new_idx == i_A && html->InFlags & IN_A) ||
+ (new_idx == i_BUTTON && html->InFlags & IN_BUTTON) ||
+ (new_idx == i_SELECT && html->InFlags & IN_SELECT) ||
+ (new_idx == i_TEXTAREA && html->InFlags & IN_TEXTAREA)) {
+ /* Let these elements close anything left open inside them */
+ continue;
+ } else if (Tags[new_idx].Flags & 4 && // Block container
+ Tags[stack_idx].Flags & 3) { // Inline element or container
+ /* Let a block container close inline elements left open inside it. */
+ continue;
+ } else {
+ /* this is the tag that should have been closed */
+ expected = 1;
+ break;
+ }
+ }
+
+ if (matched) {
+ Html_tag_cleanup_to_idx(html, stack_idx, new_idx, -1, 'c');
+ } else if (expected) {
+ BUG_MSG("Unexpected closing tag: </%s> -- expected </%s>.",
+ new_tag.name, Tags[tag_idx].name);
+ } else {
+ BUG_MSG("Unexpected closing tag: </%s>.", new_tag.name);
+ }
+}
+
+/*
* HTML, HEAD and BODY elements have optional open and close tags.
* Handle this "magic" here.
*/