parser.c
来自「elinks下lynx是最重要的二个文本浏览器, 在linux下非常实用, el」· C语言 代码 · 共 819 行 · 第 1/2 页
C
819 行
/* HTML parser */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <errno.h>#include <stdarg.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include "elinks.h"#include "bfu/listmenu.h"#include "bfu/menu.h"#include "document/css/apply.h"#include "document/css/css.h"#include "document/css/stylesheet.h"#include "document/html/frames.h"#include "document/html/parser/link.h"#include "document/html/parser/stack.h"#include "document/html/parser/parse.h"#include "document/html/parser.h"#include "document/html/renderer.h"#include "document/options.h"#include "document/renderer.h"#include "intl/charsets.h"#include "protocol/date.h"#include "protocol/header.h"#include "protocol/uri.h"#include "session/task.h"#include "terminal/draw.h"#include "util/align.h"#include "util/box.h"#include "util/color.h"#include "util/conv.h"#include "util/error.h"#include "util/memdebug.h"#include "util/memlist.h"#include "util/memory.h"#include "util/string.h"/* Unsafe macros */#include "document/html/internal.h"/* TODO: This needs rewrite. Yes, no kidding. */intget_color(struct html_context *html_context, unsigned char *a, unsigned char *c, color_T *rgb){ unsigned char *at; int r; if (!use_document_fg_colors(html_context->options)) return -1; at = get_attr_val(a, c, html_context->options); if (!at) return -1; r = decode_color(at, strlen(at), rgb); mem_free(at); return r;}intget_bgcolor(struct html_context *html_context, unsigned char *a, color_T *rgb){ if (!use_document_bg_colors(html_context->options)) return -1; return get_color(html_context, a, "bgcolor", rgb);}unsigned char *get_target(struct document_options *options, unsigned char *a){ unsigned char *v = get_attr_val(a, "target", options); if (!v) return NULL; if (!*v || !strcasecmp(v, "_self")) { mem_free_set(&v, stracpy(options->framename)); } return v;}voidln_break(struct html_context *html_context, int n){ if (!n || html_top.invisible) return; while (n > html_context->line_breax) { html_context->line_breax++; html_context->line_break_f(html_context); } html_context->position = 0; html_context->putsp = HTML_SPACE_SUPPRESS;}voidput_chrs(struct html_context *html_context, unsigned char *start, int len){ if (html_is_preformatted()) html_context->putsp = HTML_SPACE_NORMAL; if (!len || html_top.invisible) return; switch (html_context->putsp) { case HTML_SPACE_NORMAL: break; case HTML_SPACE_ADD: html_context->put_chars_f(html_context, " ", 1); html_context->position++; html_context->putsp = HTML_SPACE_SUPPRESS; /* Fall thru. */ case HTML_SPACE_SUPPRESS: html_context->putsp = HTML_SPACE_NORMAL; if (isspace(start[0])) { start++, len--; if (!len) { html_context->putsp = HTML_SPACE_SUPPRESS; return; } } break; } if (isspace(start[len - 1]) && !html_is_preformatted()) html_context->putsp = HTML_SPACE_SUPPRESS; html_context->was_br = 0; html_context->put_chars_f(html_context, start, len); html_context->position += len; html_context->line_breax = 0; if (html_context->was_li > 0) html_context->was_li--;}voidset_fragment_identifier(struct html_context *html_context, unsigned char *attr_name, unsigned char *attr){ unsigned char *id_attr; id_attr = get_attr_val(attr_name, attr, html_context->options); if (id_attr) { html_context->special_f(html_context, SP_TAG, id_attr); mem_free(id_attr); }}voidadd_fragment_identifier(struct html_context *html_context, struct part *part, unsigned char *attr){ struct part *saved_part = html_context->part; html_context->part = part; html_context->special_f(html_context, SP_TAG, attr); html_context->part = saved_part;}#ifdef CONFIG_CSSvoidimport_css_stylesheet(struct css_stylesheet *css, struct uri *base_uri, unsigned char *url, int len){ struct html_context *html_context = css->import_data; unsigned char *import_url; struct uri *uri; assert(html_context); assert(base_uri); if (!html_context->options->css_enable || !html_context->options->css_import) return; url = memacpy(url, len); if (!url) return; /* HTML <head> urls should already be fine but we can.t detect them. */ import_url = join_urls(base_uri, url); mem_free(url); if (!import_url) return; uri = get_uri(import_url, URI_BASE); mem_free(import_url); if (!uri) return; /* Request the imported stylesheet as part of the document ... */ html_context->special_f(html_context, SP_STYLESHEET, uri); /* ... and then attempt to import from the cache. */ import_css(css, uri); done_uri(uri);}#endif/* Extract the extra information that is available for elements which can * receive focus. Call this from each element which supports tabindex or * accesskey. *//* Note that in ELinks, we support those attributes (I mean, we call this * function) while processing any focusable element (otherwise it'd have zero * tabindex, thus messing up navigation between links), thus we support these * attributes even near tags where we're not supposed to (like IFRAME, FRAME or * LINK). I think this doesn't make any harm ;). --pasky */voidhtml_focusable(struct html_context *html_context, unsigned char *a){ struct document_options *options; unsigned char *accesskey; int tabindex; format.accesskey = 0; format.tabindex = 0x80000000; if (!a) return; options = html_context->options; accesskey = get_attr_val(a, "accesskey", options); if (accesskey) { format.accesskey = accesskey_string_to_unicode(accesskey); mem_free(accesskey); } tabindex = get_num(a, "tabindex", options); if (0 < tabindex && tabindex < 32767) { format.tabindex = (tabindex & 0x7fff) << 16; } mem_free_set(&format.onclick, get_attr_val(a, "onclick", options)); mem_free_set(&format.ondblclick, get_attr_val(a, "ondblclick", options)); mem_free_set(&format.onmouseover, get_attr_val(a, "onmouseover", options)); mem_free_set(&format.onhover, get_attr_val(a, "onhover", options)); mem_free_set(&format.onfocus, get_attr_val(a, "onfocus", options)); mem_free_set(&format.onmouseout, get_attr_val(a, "onmouseout", options)); mem_free_set(&format.onblur, get_attr_val(a, "onblur", options));}voidhtml_skip(struct html_context *html_context, unsigned char *a){ html_top.invisible = 1; html_top.type = ELEMENT_DONT_KILL;}voidprocess_head(struct html_context *html_context, unsigned char *head){ unsigned char *refresh, *url; refresh = parse_header(head, "Refresh", NULL); if (!refresh) return; url = parse_header_param(refresh, "URL"); if (!url) { /* If the URL parameter is missing assume that the * document being processed should be refreshed. */ url = get_uri_string(html_context->base_href, URI_ORIGINAL); } if (url) { /* Extraction of refresh time. */ unsigned long seconds = 0; int valid = 1; /* We try to extract the refresh time, and to handle weird things * in an elegant way. Among things we can have negative values, * too big ones, just ';' (we assume 0 seconds in that case) and * more. */ if (*refresh != ';') { if (isdigit(*refresh)) { unsigned long max_seconds = HTTP_REFRESH_MAX_DELAY; errno = 0; seconds = strtoul(refresh, NULL, 10); if (errno == ERANGE || seconds > max_seconds) { /* Too big refresh value, limit it. */ seconds = max_seconds; } else if (errno) { /* Bad syntax */ valid = 0; } } else { /* May be a negative number, or some bad syntax. */ valid = 0; } } if (valid) { unsigned char *joined_url = join_urls(html_context->base_href, url); html_focusable(html_context, NULL); put_link_line("Refresh: ", url, joined_url, html_context->options->framename, html_context); html_context->special_f(html_context, SP_REFRESH, seconds, joined_url); mem_free(joined_url); } mem_free(url); } mem_free(refresh); if (!get_opt_bool("document.cache.ignore_cache_control")) { unsigned char *d; int no_cache = 0; time_t expires = 0; /* XXX: Code duplication with HTTP protocol backend. */ /* I am not entirely sure in what order we should process these * headers and if we should still process Cache-Control max-age * if we already set max age to date mentioned in Expires. * --jonas */ if ((d = parse_header(head, "Pragma", NULL))) { if (strstr(d, "no-cache")) { no_cache = 1; } mem_free(d); } if (!no_cache && (d = parse_header(head, "Cache-Control", NULL))) { if (strstr(d, "no-cache") || strstr(d, "must-revalidate")) { no_cache = 1; } else { unsigned char *pos = strstr(d, "max-age="); assert(!no_cache); if (pos) { /* Grab the number of seconds. */ timeval_T max_age, seconds; timeval_from_seconds(&seconds, atol(pos + 8)); timeval_now(&max_age); timeval_add_interval(&max_age, &seconds); expires = timeval_to_seconds(&max_age); } } mem_free(d); } if (!no_cache && (d = parse_header(head, "Expires", NULL))) { /* Convert date to seconds. */ if (strstr(d, "now")) { timeval_T now; timeval_now(&now); expires = timeval_to_seconds(&now); } else { expires = parse_date(&d, NULL, 0, 1); } mem_free(d); } if (no_cache) html_context->special_f(html_context, SP_CACHE_CONTROL); else if (expires) html_context->special_f(html_context, SP_CACHE_EXPIRES, expires); }}static intlook_for_map(unsigned char **pos, unsigned char *eof, struct uri *uri, struct document_options *options){ unsigned char *al, *attr, *name; int namelen; while (*pos < eof && **pos != '<') { (*pos)++; } if (*pos >= eof) return 0; if (*pos + 2 <= eof && ((*pos)[1] == '!' || (*pos)[1] == '?')) { *pos = skip_comment(*pos, eof); return 1; } if (parse_element(*pos, eof, &name, &namelen, &attr, pos)) { (*pos)++;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?