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 + -
显示快捷键?