📄 html.c
字号:
a_Dw_page_add_space(DW_PAGE (html->dw), html->stack[html->stack_top].style); /* actually white-space entities inside the word could be * collapsed (except ), but that's too much overhead * for a very rare case of ill-formed HTML --Jcid */ Pword = Html_parse_entities(html, word, size); g_strdelimit(Pword, "\t\f\n\r", ' '); a_Dw_page_add_text(DW_PAGE (html->dw), Pword, html->stack[html->stack_top].style); } html->PrevWasOpenTag = FALSE; html->SPCPending = FALSE;}/* * Does the tag in tagstr (e.g. "p") match the tag in the tag, tagsize * structure, with the initial < skipped over (e.g. "P align=center>") */static gboolean Html_match_tag(const char *tagstr, char *tag, int tagsize){ int i; for (i = 0; i < tagsize && tagstr[i] != '\0'; i++) { if (tolower(tagstr[i]) != tolower(tag[i])) return FALSE; } /* The test for '/' is for xml compatibility: "empty/>" will be matched. */ if (i < tagsize && (isspace(tag[i]) || tag[i] == '>' || tag[i] == '/')) return TRUE; return FALSE;}/* * This function is called by Html_cleanup_tag and Html_pop_tag, to * handle nested DwPage widgets. */static void Html_eventually_pop_dw(DilloHtml *html){ /* This function is called after popping from the stack, so the * relevant hand_over_break is at html->stack_top + 1. */ if (html->dw != html->stack[html->stack_top].page) { if (html->stack[html->stack_top + 1].hand_over_break) a_Dw_page_hand_over_break(DW_PAGE(html->dw), html->stack[(html)->stack_top].style); a_Dw_page_flush(DW_PAGE(html->dw)); html->dw = html->stack[html->stack_top].page; }}/* * Push the tag (copying attributes from the top of the stack) */static void Html_push_tag(DilloHtml *html, int tag_idx){ char *tagstr; int n_items; /* Save the element's name (no parameters) into tagstr. */ tagstr = g_strdup(Tags[tag_idx].name); n_items = html->stack_top + 1; a_List_add(html->stack, n_items, html->stack_max); /* We'll copy the former stack item and just change the tag and its index * instead of copying all fields except for tag. --Jcid */ html->stack[n_items] = html->stack[n_items - 1]; html->stack[n_items].tag_name = tagstr; html->stack[n_items].tag_idx = tag_idx; html->stack_top = n_items; /* proper memory management, may be unref'd later */ a_Dw_style_ref (html->stack[html->stack_top].style); if (html->stack[html->stack_top].table_cell_style) a_Dw_style_ref (html->stack[html->stack_top].table_cell_style); html->dw = html->stack[html->stack_top].page;}/* * Push the tag (used to force en element with optional open into the stack) * Note: now it's the same as Html_push_tag(), but things may change... */static void Html_force_push_tag(DilloHtml *html, gint tag_idx){ Html_push_tag(html, tag_idx);}/* * Pop the top tag in the stack */static void Html_real_pop_tag(DilloHtml *html){ a_Dw_style_unref (html->stack[html->stack_top].style); if (html->stack[html->stack_top].table_cell_style) a_Dw_style_unref (html->stack[html->stack_top].table_cell_style); g_free(html->stack[html->stack_top--].tag_name); Html_eventually_pop_dw(html);}/* * Default close function for tags. * (conditional cleanup of the stack) * There're 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 the first tag that requires a close tag. * 2.- If it matches, clean all the optional-close tags in between. * 3.- Cleanup the matching tag. (on error, give a warning message) * * If 'w3c_mode' is NOT enabled: * 1.- Search the stack for a matching tag based on tag level. * 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, gint TagIdx){ gint w3c_mode = !prefs.w3c_plus_heuristics; gint stack_idx, cmp = 1; gint new_idx = TagIdx; if (html->CloseOneTag) { Html_real_pop_tag(html); html->CloseOneTag = FALSE; return; } /* Look for the candidate tag to close */ stack_idx = html->stack_top; while (stack_idx && (cmp = (new_idx != html->stack[stack_idx].tag_idx)) && ((w3c_mode && Tags[html->stack[stack_idx].tag_idx].EndTag == 'O') || (!w3c_mode && Tags[html->stack[stack_idx].tag_idx].TagLevel < Tags[new_idx].TagLevel))) { --stack_idx; } /* clean, up to the matching tag */ if (cmp == 0 && stack_idx > 0) { /* There's a valid matching tag in the stack */ while (html->stack_top >= stack_idx) { gint toptag_idx = html->stack[html->stack_top].tag_idx; /* Warn when we decide to close an open tag (for !w3c_mode) */ if (html->stack_top > stack_idx && Tags[toptag_idx].EndTag != 'O') MSG_HTML(" - forcing close of open tag: <%s>\n", Tags[toptag_idx].name); /* Close this and only this tag */ html->CloseOneTag = TRUE; Tags[toptag_idx].close (html, toptag_idx); } } else { MSG_HTML("unexpected closing tag: </%s>. -- expected </%s>\n", Tags[new_idx].name, html->stack[stack_idx].tag_name); }}#if 0/* * Remove the stack's topmost tag (only if it matches) * If it matches, TRUE is returned. */static gboolean Html_cleanup_tag(DilloHtml *html, char *tag){ if (html->stack_top && Html_match_tag(html->stack[html->stack_top].tag, tag, strlen(tag))) { a_Dw_style_unref (html->stack[html->stack_top].style); if (html->stack[html->stack_top].table_cell_style) a_Dw_style_unref (html->stack[html->stack_top].table_cell_style); g_free(html->stack[html->stack_top--].tag); Html_eventually_pop_dw(html); return TRUE; } else return FALSE;}#endif/* * Cleanup (conditional), and Pop the tag (if it matches) */static void Html_pop_tag(DilloHtml *html, gint TagIdx){ Html_tag_cleanup_at_close(html, TagIdx);}#if 0/* * Do a paragraph break and push the tag. This pops unclosed <p> tags * off the stack, if there are any. */static void Html_par_push_tag (DilloHtml *html, char *tag, int tagsize){ Html_push_tag (html, tag, tagsize); a_Dw_page_add_parbreak (DW_PAGE (html->dw), 9, html->stack[(html)->stack_top].style);}#endif/* * Some parsing routines. *//* * Used by Html_parse_length and Html_parse_multi_length_list. */static DwStyleLength Html_parse_length_or_multi_length (const char *attr, char **endptr){ DwStyleLength l; double v; char *end; v = (double)strtol (attr, &end, 10); switch (*end) { case '%': end++; l = DW_STYLE_CREATE_PER_LENGTH (v / 100); break; case '*': end++; l = DW_STYLE_CREATE_REL_LENGTH (v); break; default: l = DW_STYLE_CREATE_ABS_LENGTH ((int)v); break; } if (endptr) *endptr = end; return l;}/* * Returns a length or a percentage, or DW_STYLE_UNDEF_LENGTH in case * of an error, or if attr is NULL. */static DwStyleLength Html_parse_length (DilloHtml *html, const char *attr){ DwStyleLength l; char *end; l = Html_parse_length_or_multi_length (attr, &end); if (DW_STYLE_IS_REL_LENGTH (l)) /* not allowed as &Length; */ return DW_STYLE_LENGTH_AUTO; else { /* allow only whitespaces */ if (*end && !isspace (*end)) { MSG_HTML("Garbage after length: %s\n", attr); return DW_STYLE_LENGTH_AUTO; } } return l;}/* * Returns a vector of lenghts/percentages. The caller has to g_free the * result when it is not longer used. *//*static DwStyleLength *Html_parse_multi_length_list (const char *attr){ DwStyleLength *l; int n, max_n; char *end; n = 0; max_n = 8; l = g_malloc0 (max_n, sizeof (DwStyleLength)); while (TRUE) { l[n] = Html_parse_length_or_multi_length (attr, &end); n++; a_List_add (l, n, max_n); while (isspace (*end)) end++; if (*end == ',') attr = end + 1; else // error or end break; } l[n] = DW_STYLE_LENGTH_AUTO; return l;}*//* * Parse a color attribute. * Return value: parsed color, or default_color (+ error msg) on error. */static gint32 Html_color_parse(DilloHtml *html, const char *subtag, gint32 default_color){ int err = 1; gint32 color = a_Color_parse (subtag, default_color, &err); if (err) { MSG_HTML("color is not in \"#RRGGBB\" format\n"); } return color;}/* * Check that 'val' is composed of characters inside [A-Za-z0-9:_.-] * Note: ID can't have entities, but this check is enough (no '&'). * Return value: 1 if OK, 0 otherwise. */static gint Html_check_name_val(DilloHtml *html, const char *val, const char *attrname){ gint i; for (i = 0; val[i]; ++i) if (!(isalnum(val[i]) || strchr(":_.-", val[i]))) break; if (val[i] || !isalpha(val[0])) MSG_HTML("'%s' value is not of the form " "[A-Za-z][A-Za-z0-9:_.-]*\n", attrname); return !(val[i]);}/* * Handle open HTML element */static void Html_tag_open_html(DilloHtml *html, char *tag, gint tagsize){ if (!(html->InFlags & IN_HTML)) html->InFlags |= IN_HTML; ++html->Num_HTML; if (html->Num_HTML > 1) { MSG_HTML("HTML element was already open\n"); }}/* * Handle close HTML element */static void Html_tag_close_html(DilloHtml *html, gint TagIdx){ /* todo: may add some checks here */ html->InFlags &= ~IN_HTML; Html_pop_tag(html, TagIdx);}/* * Handle open HEAD element */static void Html_tag_open_head(DilloHtml *html, char *tag, int tagsize){ if (html->InFlags & IN_BODY) { MSG_HTML("HEAD element must go before the BODY section\n"); html->ReqTagClose = TRUE; return; } if (!(html->InFlags & IN_HEAD)) html->InFlags |= IN_HEAD; ++html->Num_HEAD; if (html->Num_HEAD > 1) { MSG_HTML("HEAD element was already open\n"); }}/* * Handle close HEAD element */static void Html_tag_close_head(DilloHtml *html, int TagIdx){ if (html->InFlags & IN_HEAD) { if (html->Num_TITLE == 0) MSG_HTML("HEAD section lacks the TITLE element\n"); html->InFlags &= ~IN_HEAD; } Html_pop_tag(html, TagIdx);}/* * Handle open TITLE * calls stash init, where the title string will be stored */static void Html_tag_open_title(DilloHtml *html, char *tag, int tagsize){ ++html->Num_TITLE; Html_stash_init(html);}/* * Handle close TITLE * set page-title in the browser window and in the history. */static void Html_tag_close_title(DilloHtml *html, int TagIdx){ if (html->InFlags & IN_HEAD) { /* title is only valid inside HEAD */ a_Interface_set_page_title(html->linkblock->bw, html->Stash->str); a_History_set_title(NAV_TOP(html->linkblock->bw), html->Stash->str); } else { MSG_HTML("the TITLE element must be inside the HEAD section\n"); } Html_pop_tag(html, TagIdx);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -