1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-11-04 08:17:17 -05:00
This commit is contained in:
Kalle Olavi Niemitalo 2006-01-09 02:20:27 +02:00 committed by Kalle Olavi Niemitalo
commit 2cfd0a9bb4
32 changed files with 1531 additions and 451 deletions

View File

@ -33,8 +33,8 @@ mcmd = @$(if $($(mquiet)cmd_$(1)),echo $($(mquiet)cmd_$(1)) &&) $(cmd_$(1))
ecmd = @$(if $($(mquiet)cmd_$(1)),printf "%-38s " $($(mquiet)cmd_$(1)) &&) $(cmd_$(1))
quiet_cmd_compile = ' [$(CC_COLOR)CC$(END_COLOR)] $(RELPATH)$@'
masq_cmd_compile = $(COMPILE) -c $<
cmd_compile = $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
masq_cmd_compile = $(COMPILE) -o $(@) -c $< $(2)
cmd_compile = $(COMPILE) -o $(@) -Wp,-MD,.deps/$(*F).pp -c $< $(2)
# Rule to compile a set of .o files into one .o file
quiet_cmd_ld_objs = " [$(LD_COLOR)LD$(END_COLOR)] $(RELPATH)$@"
@ -153,6 +153,7 @@ clean-test:
test-default:
ifdef TEST_PROGS
TESTDEPS-$(CONFIG_DEBUG) += $(top_builddir)/src/util/memdebug.o
TESTDEPS += $(TESTDEPS-yes)
TESTS = $(wildcard $(srcdir)test-*)

View File

@ -14,6 +14,7 @@ TXT_DIR = $(top_srcdir)/doc/txt
DOC_DIRS = \
$(HTML_DIR) \
$(HTML_DIR)/api \
$(MAN_DIR)/man1 \
$(MAN_DIR)/man5 \
$(TXT_DIR) \
@ -51,74 +52,43 @@ FEATURES = $(top_srcdir)/features.conf
### Scripts
#
CODE2DOC = $(top_srcdir)/doc/tools/code2doc
HELP2DOC = $(top_srcdir)/doc/tools/help2doc
IMPORT_FEATURES_CONF = $(top_srcdir)/doc/tools/import-features.conf
MAKE_ELINKS_MANPAGE = $(top_srcdir)/doc/tools/make-elinks-manpage
MAKE_ELINKSKEYS_MANPAGE = $(top_srcdir)/doc/tools/make-elinkskeys-manpage
ifeq ($(CONFIG_ASCIIDOC),yes)
HTML_DOCS_WITH_ASCIIDOC = \
$(HTML_DIR)/elinks.1.html \
$(HTML_DIR)/elinkskeys.5.html \
$(HTML_DIR)/hacking.html \
$(HTML_DIR)/manual.html
endif
HTML_DOCS-$(CONFIG_ASCIIDOC) += \
api/dom-sgml-parser.html \
elinks.1.html \
elinkskeys.5.html \
hacking.html \
manual.html
HTML_DOCS-$(CONFIG_XMLTO) += \
manual.html-chunked
HTML_DOCS-$(CONFIG_POD2HTML) += \
perl.html \
perl-hooks.html
MAN_DOCS-$(CONFIG_XMLTO) += \
man1/elinks.1.in \
man5/elinkskeys.5
# Only jw is used for generating PDF.
ifeq ($(CONFIG_XMLTO),yes)
HTML_DOCS_WITH_XMLTO = \
$(HTML_DIR)/manual.html-chunked
PDF_DOCS-$(CONFIG_JW) += \
manual.pdf
MAN_DOCS_WITH_XMLTO = \
$(MAN_DIR)/man1/elinks.1.in \
$(MAN_DIR)/man5/elinkskeys.5
endif
MAN_DOCS += man5/elinks.conf.5
# Only jw is used for generating PDF.
ifeq ($(CONFIG_JW),yes)
PDF_DOCS_WITH_JW = \
$(PDF_DIR)/manual.pdf
endif
MAN_DOCS += $(MAN_DOCS-yes)
HTML_DOCS += $(HTML_DOCS-yes)
PDF_DOCS += $(PDF_DOCS-yes)
ifeq ($(CONFIG_POD2HTML),yes)
HTML_DOCS_WITH_POD2HTML = \
$(HTML_DIR)/perl.html \
$(HTML_DIR)/perl-hooks.html
endif
MAN_DOCS_WITH_SHELL = $(MAN_DIR)/man5/elinks.conf.5
MAN_DOCS = \
$(MAN_DOCS_WITH_SHELL)
$(MAN_DOCS_WITH_ASCIIDOC)
HTML_DOCS = \
$(HTML_DOCS_WITH_ASCIIDOC) \
$(HTML_DOCS_WITH_POD2HTML) \
$(HTML_DOCS_WITH_JW)
PDF_DOCS = \
$(PDF_DOCS_WITH_JW)
html-asciidoc-yes: doc-dirs $(HTML_DOCS_WITH_ASCIIDOC)
html-asciidoc-no:
html-pod2html-yes: doc-dirs $(HTML_DOCS_WITH_POD2HTML)
html-pod2html-no:
html-xmlto-yes: doc-dirs $(HTML_DOCS_WITH_XMLTO)
html-xmlto-no:
man-xmlto-yes: doc-dirs $(MAN_DOCS_WITH_XMLTO)
man-xmlto-no:
pdf-jw-yes: doc-dirs $(PDF_DOCS_WITH_JW)
pdf-jw-no:
man-docs: man-xmlto-$(CONFIG_XMLTO) $(MAN_DOCS_WITH_SHELL)
html-docs: html-asciidoc-$(CONFIG_ASCIIDOC) html-xmlto-$(CONFIG_XMLTO) html-pod2html-$(CONFIG_POD2HTML)
pdf-docs: pdf-jw-$(CONFIG_JW)
man-docs: doc-dirs $(addprefix $(MAN_DIR)/,$(MAN_DOCS))
html-docs: doc-dirs $(addprefix $(HTML_DIR)/,$(HTML_DOCS))
pdf-docs: doc-dirs $(addprefix $(PDF_DIR)/,$(PDF_DOCS))
all-docs: man-docs html-docs pdf-docs
@ -135,36 +105,36 @@ clean-local:
# Autogenerated asciidoc files.
$(TXT_DIR)/import-features.conf.txt: $(FEATURES) doc-dirs $(IMPORT_FEATURES_CONF)
$(TXT_DIR)/import-features.conf.txt: $(FEATURES) $(IMPORT_FEATURES_CONF)
$(IMPORT_FEATURES_CONF) > $@
$(TXT_DIR)/elinks.1.%.txt: $(MAKE_ELINKS_MANPAGE) doc-dirs $(ELINKS)
$(TXT_DIR)/elinks.1.%.txt: $(MAKE_ELINKS_MANPAGE) $(ELINKS)
$(MAKE_ELINKS_MANPAGE) $@ $(ELINKS) $(HELP2DOC) > $@
$(TXT_DIR)/elinkskeys.5.%.txt: $(MAKE_ELINKSKEYS_MANPAGE) doc-dirs $(KBDBIND)
$(TXT_DIR)/elinkskeys.5.%.txt: $(MAKE_ELINKSKEYS_MANPAGE) $(KBDBIND)
$(MAKE_ELINKSKEYS_MANPAGE) $@ $(KBDBIND) > $@
# Man Pages
$(XML_DIR)/%.man.xml: $(TXT_DIR)/%.man.txt doc-dirs
$(XML_DIR)/%.man.xml: $(TXT_DIR)/%.man.txt
$(ASCIIDOC) -b docbook -d manpage -o $@ $<
$(MAN_DIR)/man1/elinks.1.in: $(XML_DIR)/elinks.1.man.xml doc-dirs
$(MAN_DIR)/man1/elinks.1.in: $(XML_DIR)/elinks.1.man.xml
$(XMLTO) -o $(MAN_DIR)/man1 man $<
mv $(MAN_DIR)/man1/elinks.1 $@
$(MAN_DIR)/man5/elinkskeys.5: $(XML_DIR)/elinkskeys.5.man.xml doc-dirs
$(MAN_DIR)/man5/elinkskeys.5: $(XML_DIR)/elinkskeys.5.man.xml
$(XMLTO) -o $(MAN_DIR)/man5 man $<
sed -e 's/\\fI\\fR'\''/\\fI\\'\''\\fR/' < $@ > $@.tmp
mv $@.tmp $@
$(MAN_DIR)/man5/elinks.conf.5: doc-dirs $(ELINKS)
$(MAN_DIR)/man5/elinks.conf.5: $(ELINKS)
$(HELP2DOC) --elinks=$(ELINKS) --elinksconf > $@
# XHTML/CSS Man Pages
$(HTML_DIR)/%.html: $(TXT_DIR)/%.html.txt doc-dirs
$(HTML_DIR)/%.html: $(TXT_DIR)/%.html.txt
$(ASCIIDOC) -b xhtml11 -d manpage -o $@ $<
# The Manual
@ -174,28 +144,34 @@ MANUAL_EXTRA_FILES = \
$(TXT_DIR)/elinks.1.html.txt \
$(TXT_DIR)/elinkskeys.5.html.txt
$(HTML_DIR)/manual.html: $(MANUAL_FILES) doc-dirs $(MANUAL_EXTRA_FILES)
$(HTML_DIR)/manual.html: $(MANUAL_FILES) $(MANUAL_EXTRA_FILES)
$(ASCIIDOC) -b xhtml11 -d book -o $@ -n $<
$(HTML_DIR)/hacking.html: $(top_srcdir)/doc/hacking.txt doc-dirs
$(HTML_DIR)/hacking.html: $(top_srcdir)/doc/hacking.txt
$(ASCIIDOC) -b xhtml11 -d book -o $@ -n $<
$(HTML_DIR)/dev-intro.html: $(top_srcdir)/doc/dev-intro.txt doc-dirs
$(HTML_DIR)/dev-intro.html: $(top_srcdir)/doc/dev-intro.txt
$(ASCIIDOC) -b xhtml11 -d book -o $@ -n $<
$(XML_DIR)/manual.xml: $(MANUAL_FILES) doc-dirs $(MANUAL_EXTRA_FILES)
$(XML_DIR)/manual.xml: $(MANUAL_FILES) $(MANUAL_EXTRA_FILES)
$(ASCIIDOC) -b docbook -d book -o $@ $<
$(HTML_DIR)/manual.html-chunked: $(XML_DIR)/manual.xml doc-dirs
$(HTML_DIR)/manual.html-chunked: $(XML_DIR)/manual.xml
$(XMLTO) -o $@ html $<
$(PDF_DIR)/manual.pdf: $(XML_DIR)/manual.xml doc-dirs
$(PDF_DIR)/manual.pdf: $(XML_DIR)/manual.xml
$(JW) -o $(PDF_DIR) -b pdf $<
$(HTML_DIR)/perl.html: $(top_srcdir)/doc/perl.pod doc-dirs
$(HTML_DIR)/perl.html: $(top_srcdir)/doc/perl.pod
$(POD2HTML) --outfile=$@ < $<
$(HTML_DIR)/perl-hooks.html: $(top_srcdir)/contrib/perl/hooks.pl doc-dirs
$(HTML_DIR)/perl-hooks.html: $(top_srcdir)/contrib/perl/hooks.pl
$(POD2HTML) --outfile=$@ < $<
## API Docs
#
$(HTML_DIR)/api/dom-sgml-parser.html: $(top_srcdir)/src/dom/sgml/parser.h
$(CODE2DOC) $< | $(ASCIIDOC) -f code2doc.conf -b xhtml11 -d book -o $@ -n -
include $(top_srcdir)/Makefile.lib

52
doc/code2doc.conf Normal file
View File

@ -0,0 +1,52 @@
[specialwords]
emphasizedwords=\bAsciiDoc\b
monospacedwords=\basciidoc\(1\)
[id-inlinemacro]
<a id="{0}" href="#{0}">{0}</a>
[enum-inlinemacro]
<a id="{0}" href="#{0}">enum {0}</a>
[func-inlinemacro]
<a id="{0}" href="#{0}">{0}()</a>
[struct-inlinemacro]
<a id="{0}" href="#{0}">struct {0}</a>
[callback-inlinemacro]
<a id="{0}" href="#{0}">callback {0}</a>
[ref-inlinemacro]
<a href="{target}#{0}">{0}</a>
[replacements]
(^|[^-])--($|[^-])=\1--\2
[tags]
ilisttext=|
olisttext=|
vlisttext=|
qlisttext=|
colisttext=|
[tags]
title1=<h1>|</h1>
title2=<h2>|</h2>
title3=<h3>|</h3>
[literalparagraph]
<table border="1" class="code"><tr><td><pre>
|
</pre></td></tr></table>
[listingblock]
<p><b>{title}</b></p>
<table border="1" class="code"><tr><td><pre>
|
</pre></td></tr></table>
[noteblock]
<div><p><b>{title}</b></p>
|
</div>

46
doc/tools/code2doc Executable file
View File

@ -0,0 +1,46 @@
#!/usr/bin/perl -w
use strict;
use warnings;
use diagnostics;
print "Usage: $0 [FILE]\n\tParses [FILE], outputing the result to stdout.\n"
and exit if not @ARGV;
my ($input) = @ARGV;
my ($found, $start, $first, $gotone, $idpath);
print "Copyleft© 2006, Russ Rowan (See `COPYING')\n" and exit if $input eq '-v';
open FILEIN, "<$input" or print "File `$input' was not found.\n" and exit;
$idpath = '';
while (<FILEIN>)
{
if ($found)
{
if ($_ =~ /^\s+\*\s$/) { next if $first; $_ =~ s/\s\*// if not $first; }
if ($_ =~ /^\s\*+\/$/ or $_ !~ /^\s/) { $found = undef; next; }
$_ =~ s/^(\s*)\s\*\s/$1/;
$found = 'sorta' if $_ =~ s/\s*\*\/$/\n/; $first = undef;
}
elsif ($_ =~ /^\s*\/\*\*\s(.*)/)
{
$_ = $1; $first = 1;
print STDOUT "\n\n" if $start;
if ($_ =~ s/\s*\*\/$//) { $found = 'sorta'; } else { $found = $.; }
if ($_ =~ /struct:[[]([^\]]+)[\]]/) { $idpath = "$1."; } else { $idpath = ''; }
if ($_ =~ /::/) { $_ = "$_\n\n"; }
else
{
my $dash; for (my $x = 0; $x < length($_); $x++) { $dash .= '-'; }
$_ = "$_\n$dash\n\n";
}
}
elsif ($_ =~ /^(\s|[^\s=]+)*[\s*]([A-Za-z0-9_]+)(\s+=\s+[^,;]+)?[,;]\s*\/\*::\s*(.*)\s+\*\/$/)
{
print STDOUT "\n" if $gotone;
$_ = "\nid:[$idpath$2]::\n\t$4\n";
$found = 'sorta'; $gotone = $.;
}
print STDOUT "\n" and $gotone = undef if $gotone and $gotone < $.;
next if not $found; $found = undef if $found eq 'sorta';
print STDOUT $_ and $start = 1;
}
close FILEIN;

View File

@ -121,52 +121,9 @@ refresh_hotkeys(struct terminal *term, struct menu *menu)
#endif
}
/* Returns true if key (upcased) matches one of the hotkeys in menu */
static int
is_hotkey(struct menu_item *item, unsigned char key, struct terminal *term)
{
unsigned char *text;
int key_pos;
assert(item);
if_assert_failed return 0;
if (!mi_has_left_text(item)) return 0;
text = item->text;
if (mi_text_translate(item)) text = _(text, term);
if (!text || !*text) return 0;
key_pos = item->hotkey_pos;
#ifdef CONFIG_DEBUG
if (key_pos < 0) key_pos = -key_pos;
#endif
return (key_pos && (toupper(text[key_pos]) == key));
}
/* Returns true if key (upcased) matches first letter of menu item left text. */
static int
is_not_so_hotkey(struct menu_item *item, unsigned char key, struct terminal *term)
{
unsigned char *text;
assert(item);
if_assert_failed return 0;
if (!mi_has_left_text(item)) return 0;
text = item->text;
if (mi_text_translate(item)) text = _(text, term);
if (!text || !*text) return 0;
return (toupper(*text) == key);
}
static int
check_hotkeys_common(struct menu *menu, unsigned char hotkey, struct terminal *term,
int (*func)(struct menu_item *, unsigned char, struct terminal *))
int check_mode)
{
unsigned char key = toupper(hotkey);
int i = menu->selected;
@ -179,9 +136,37 @@ check_hotkeys_common(struct menu *menu, unsigned char hotkey, struct terminal *t
start = i;
do {
struct menu_item *item;
unsigned char *text;
int found;
if (++i == menu->size) i = 0;
if (func(&menu->items[i], key, term)) {
item = &menu->items[i];
if (!mi_has_left_text(item)) continue;
text = item->text;
if (mi_text_translate(item)) text = _(text, term);
if (!text || !*text) continue;
if (check_mode == 0) {
/* Does the key (upcased) matches one of the
* hotkeys in menu ? */
int key_pos = item->hotkey_pos;
#ifdef CONFIG_DEBUG
if (key_pos < 0) key_pos = -key_pos;
#endif
found = (key_pos && (toupper(text[key_pos]) == key));
} else {
/* Does the key (upcased) matches first letter
* of menu item left text ? */
found = (toupper(*text) == key);
}
if (found) {
menu->selected = i;
return 1;
}
@ -195,7 +180,7 @@ check_hotkeys_common(struct menu *menu, unsigned char hotkey, struct terminal *t
int
check_hotkeys(struct menu *menu, unsigned char key, struct terminal *term)
{
return check_hotkeys_common(menu, key, term, is_hotkey);
return check_hotkeys_common(menu, key, term, 0);
}
/* Search if first letter of an entry in menu matches the key (caseless comp.).
@ -205,5 +190,5 @@ check_hotkeys(struct menu *menu, unsigned char key, struct terminal *term)
int
check_not_so_hot_keys(struct menu *menu, unsigned char key, struct terminal *term)
{
return check_hotkeys_common(menu, key, term, is_not_so_hotkey);
return check_hotkeys_common(menu, key, term, 1);
}

View File

@ -24,6 +24,7 @@
#include "document/renderer.h"
#include "dom/scanner.h"
#include "dom/sgml/parser.h"
#include "dom/sgml/rss/rss.h"
#include "dom/node.h"
#include "dom/stack.h"
#include "intl/charsets.h"
@ -54,6 +55,13 @@ struct dom_renderer {
unsigned int find_url:1;
#endif
struct screen_char styles[DOM_NODES];
/* RSS renderer variables */
struct dom_node *channel;
struct dom_node_list *items;
struct dom_node *item;
struct dom_node *node;
struct dom_string text;
};
#define URL_REGEX "(file://|((f|ht|nt)tp(s)?|smb)://[[:alnum:]]+([-@:.]?[[:alnum:]])*\\.[[:alpha:]]{2,4}(:[[:digit:]]+)?)(/(%[[:xdigit:]]{2}|[-_~&=;?.a-z0-9])*)*"
@ -334,7 +342,8 @@ render_dom_text(struct dom_renderer *renderer, struct screen_char *template,
ALIGN_LINK(&(doc)->links, (doc)->nlinks, size)
static inline struct link *
add_dom_link(struct dom_renderer *renderer, unsigned char *string, int length)
add_dom_link(struct dom_renderer *renderer, unsigned char *string, int length,
unsigned char *uristring, int urilength)
{
struct document *document = renderer->document;
int x = renderer->canvas_x;
@ -343,7 +352,6 @@ add_dom_link(struct dom_renderer *renderer, unsigned char *string, int length)
struct link *link;
struct point *point;
struct screen_char template;
unsigned char *uristring;
color_T fgcolor;
if (!realloc_document_links(document, document->nlinks + 1))
@ -355,7 +363,7 @@ add_dom_link(struct dom_renderer *renderer, unsigned char *string, int length)
return NULL;
uristring = convert_string(renderer->convert_table,
string, length, document->options.cp,
uristring, urilength, document->options.cp,
CSM_DEFAULT, NULL, NULL, NULL);
if (!uristring) return NULL;
@ -479,7 +487,7 @@ render_dom_node_enhanced_text(struct dom_renderer *renderer, struct dom_node *no
string += offset;
length -= offset;
add_dom_link(renderer, string, matchlen);
add_dom_link(renderer, string, matchlen, string, matchlen);
length -= matchlen;
string += matchlen;
@ -601,7 +609,8 @@ render_dom_attribute_source(struct dom_stack *stack, struct dom_node *node, void
break;
}
add_dom_link(renderer, value, valuelen - skips);
add_dom_link(renderer, value, valuelen - skips,
value, valuelen - skips);
if (skips > 0) {
value += valuelen - skips;
@ -682,6 +691,272 @@ static struct dom_stack_context_info dom_source_renderer_context_info = {
};
/* DOM RSS Renderer */
static void
dom_rss_push_element(struct dom_stack *stack, struct dom_node *node, void *data)
{
struct dom_renderer *renderer = stack->current->data;
assert(node && renderer && renderer->document);
switch (node->data.element.type) {
case RSS_ELEMENT_CHANNEL:
/* The stack should have: #document * channel */
if (stack->depth != 3)
break;
if (!renderer->channel) {
renderer->channel = node;
}
break;
case RSS_ELEMENT_ITEM:
/* The stack should have: #document * channel item */
#if 0
/* Don't be so strict ... */
if (stack->depth != 4)
break;
#endif
/* ... but be exclusive. */
if (renderer->item)
break;
add_to_dom_node_list(&renderer->items, node, -1);
renderer->item = node;
break;
case RSS_ELEMENT_LINK:
case RSS_ELEMENT_DESCRIPTION:
case RSS_ELEMENT_TITLE:
case RSS_ELEMENT_AUTHOR:
case RSS_ELEMENT_PUBDATE:
if (!node->parent || renderer->node != node->parent)
break;
renderer->node = node;
}
}
static void
dom_rss_pop_element(struct dom_stack *stack, struct dom_node *node, void *data)
{
struct dom_renderer *renderer = stack->current->data;
struct dom_node_list **list;
assert(node && renderer && renderer->document);
switch (node->data.element.type) {
case RSS_ELEMENT_ITEM:
if (is_dom_string_set(&renderer->text))
done_dom_string(&renderer->text);
renderer->item = NULL;
break;
case RSS_ELEMENT_LINK:
case RSS_ELEMENT_DESCRIPTION:
case RSS_ELEMENT_TITLE:
case RSS_ELEMENT_AUTHOR:
case RSS_ELEMENT_PUBDATE:
if (!is_dom_string_set(&renderer->text)
|| !node->parent
|| renderer->item != node->parent
|| renderer->node != node)
break;
/* Replace any child nodes with the normalized text node. */
list = get_dom_node_list(node->parent, node);
done_dom_node_list(*list);
if (is_dom_string_set(&renderer->text)) {
if (!add_dom_node(node, DOM_NODE_TEXT, &renderer->text))
done_dom_string(&renderer->text);
}
renderer->node = NULL;
break;
default:
break;
}
}
static void
dom_rss_push_content(struct dom_stack *stack, struct dom_node *node, void *data)
{
struct dom_renderer *renderer = stack->current->data;
unsigned char *string = node->string.string;
int length = node->string.length;
assert(node && renderer && renderer->document);
if (!renderer->node)
return;
if (node->type == DOM_NODE_ENTITY_REFERENCE) {
string -= 1;
length += 2;
}
if (!is_dom_string_set(&renderer->text)) {
init_dom_string(&renderer->text, string, length);
} else {
add_to_dom_string(&renderer->text, string, length);
}
}
static struct dom_string *
get_rss_node_text(struct dom_node *node)
{
struct dom_node *child;
int index;
if (!node->data.element.children)
return NULL;
foreach_dom_node (node->data.element.children, child, index) {
if (child->type == DOM_NODE_TEXT)
return &child->string;
}
return NULL;
}
static struct dom_node *
get_rss_child(struct dom_node *parent, enum rss_element_type type)
{
struct dom_node *node;
int index;
if (!parent->data.element.children)
return NULL;
foreach_dom_node (parent->data.element.children, node, index) {
if (node->type == DOM_NODE_ELEMENT
&& type == node->data.element.type)
return node;
}
return NULL;
}
static struct dom_string *
get_rss_text(struct dom_node *node, enum rss_element_type type)
{
node = get_rss_child(node, type);
return node ? get_rss_node_text(node) : NULL;
}
static void
render_rss_item(struct dom_renderer *renderer, struct dom_node *item)
{
struct dom_string *title = get_rss_text(item, RSS_ELEMENT_TITLE);
struct dom_string *link = get_rss_text(item, RSS_ELEMENT_LINK);
struct dom_string *author = get_rss_text(item, RSS_ELEMENT_AUTHOR);
struct dom_string *date = get_rss_text(item, RSS_ELEMENT_PUBDATE);
if (title && is_dom_string_set(title)) {
render_dom_text(renderer, &renderer->styles[DOM_NODE_ELEMENT],
title->string, title->length);
}
if (link && is_dom_string_set(link)) {
X(renderer)++;
add_dom_link(renderer, "[link]", 6, link->string, link->length);
}
/* New line, and indent */
Y(renderer)++;
X(renderer) = 0;
if (author && is_dom_string_set(author)) {
render_dom_text(renderer, &renderer->styles[DOM_NODE_COMMENT],
author->string, author->length);
}
if (date && is_dom_string_set(date)) {
if (author && is_dom_string_set(author)) {
render_dom_text(renderer, &renderer->styles[DOM_NODE_COMMENT],
" - ", 3);
}
render_dom_text(renderer, &renderer->styles[DOM_NODE_COMMENT],
date->string, date->length);
}
if ((author && is_dom_string_set(author))
|| (date && is_dom_string_set(date))) {
/* New line, and indent */
Y(renderer)++;
X(renderer) = 0;
}
}
static void
dom_rss_pop_document(struct dom_stack *stack, struct dom_node *root, void *data)
{
struct dom_renderer *renderer = stack->current->data;
if (!renderer->channel)
return;
render_rss_item(renderer, renderer->channel);
if (renderer->items) {
struct dom_node *node;
int index;
foreach_dom_node (renderer->items, node, index) {
Y(renderer)++;
X(renderer) = 0;
render_rss_item(renderer, node);
}
}
if (is_dom_string_set(&renderer->text))
done_dom_string(&renderer->text);
mem_free_if(renderer->items);
done_dom_node(root);
}
static struct dom_stack_context_info dom_rss_renderer_context_info = {
/* Object size: */ 0,
/* Push: */
{
/* */ NULL,
/* DOM_NODE_ELEMENT */ dom_rss_push_element,
/* DOM_NODE_ATTRIBUTE */ NULL,
/* DOM_NODE_TEXT */ dom_rss_push_content,
/* DOM_NODE_CDATA_SECTION */ dom_rss_push_content,
/* DOM_NODE_ENTITY_REFERENCE */ dom_rss_push_content,
/* DOM_NODE_ENTITY */ NULL,
/* DOM_NODE_PROC_INSTRUCTION */ NULL,
/* DOM_NODE_COMMENT */ NULL,
/* DOM_NODE_DOCUMENT */ NULL,
/* DOM_NODE_DOCUMENT_TYPE */ NULL,
/* DOM_NODE_DOCUMENT_FRAGMENT */ NULL,
/* DOM_NODE_NOTATION */ NULL,
},
/* Pop: */
{
/* */ NULL,
/* DOM_NODE_ELEMENT */ dom_rss_pop_element,
/* DOM_NODE_ATTRIBUTE */ NULL,
/* DOM_NODE_TEXT */ NULL,
/* DOM_NODE_CDATA_SECTION */ NULL,
/* DOM_NODE_ENTITY_REFERENCE */ NULL,
/* DOM_NODE_ENTITY */ NULL,
/* DOM_NODE_PROC_INSTRUCTION */ NULL,
/* DOM_NODE_COMMENT */ NULL,
/* DOM_NODE_DOCUMENT */ dom_rss_pop_document,
/* DOM_NODE_DOCUMENT_TYPE */ NULL,
/* DOM_NODE_DOCUMENT_FRAGMENT */ NULL,
/* DOM_NODE_NOTATION */ NULL,
}
};
/* Shared multiplexor between renderers */
void
render_dom_document(struct cache_entry *cached, struct document *document,
@ -692,14 +967,13 @@ render_dom_document(struct cache_entry *cached, struct document *document,
struct conv_table *convert_table;
struct sgml_parser *parser;
enum sgml_document_type doctype;
enum sgml_parser_type parser_type;
unsigned char *string = struri(cached->uri);
size_t length = strlen(string);
struct dom_string uri = INIT_DOM_STRING(string, length);
struct dom_string source = INIT_DOM_STRING(buffer->source, buffer->length);
enum sgml_parser_code code;
assert(document->options.plain);
convert_table = get_convert_table(head, document->options.cp,
document->options.assume_cp,
&document->cp,
@ -710,6 +984,11 @@ render_dom_document(struct cache_entry *cached, struct document *document,
document->bgcolor = document->options.default_bg;
if (document->options.plain)
parser_type = SGML_PARSER_STREAM;
else
parser_type = SGML_PARSER_TREE;
/* FIXME: Refactor the doctype lookup. */
if (!strcasecmp("application/rss+xml", cached->content_type)) {
doctype = SGML_DOCTYPE_RSS;
@ -730,11 +1009,17 @@ render_dom_document(struct cache_entry *cached, struct document *document,
doctype = SGML_DOCTYPE_HTML;
}
parser = init_sgml_parser(SGML_PARSER_STREAM, doctype, &uri, 0);
if (!parser) return;
parser = init_sgml_parser(parser_type, doctype, &uri, 0);
if (!parser) return;
add_dom_stack_context(&parser->stack, &renderer,
&dom_source_renderer_context_info);
if (document->options.plain) {
add_dom_stack_context(&parser->stack, &renderer,
&dom_source_renderer_context_info);
} else if (doctype == SGML_DOCTYPE_RSS) {
add_dom_stack_context(&parser->stack, &renderer,
&dom_rss_renderer_context_info);
}
/* FIXME: When rendering this way we don't really care about the code.
* However, it will be useful when we will be able to also

View File

@ -254,7 +254,13 @@ render_encoded_document(struct cache_entry *cached, struct document *document)
render_plain_document(cached, document, &buffer);
} else {
render_html_document(cached, document, &buffer);
#ifdef CONFIG_DOM
if (cached->content_type
&& (!strlcasecmp("application/rss+xml", 19, cached->content_type, -1)))
render_dom_document(cached, document, &buffer);
else
#endif
render_html_document(cached, document, &buffer);
}
if (encoding != ENCODING_NONE) {

View File

@ -155,7 +155,7 @@ init_dom_scanner_info(struct dom_scanner_info *scanner_info)
void
init_dom_scanner(struct dom_scanner *scanner, struct dom_scanner_info *scanner_info,
struct dom_string *string, int state, int count_lines, int complete,
int check_complete)
int check_complete, int detect_errors)
{
if (!scanner_info->initialized) {
init_dom_scanner_info(scanner_info);
@ -173,6 +173,7 @@ init_dom_scanner(struct dom_scanner *scanner, struct dom_scanner_info *scanner_i
scanner->count_lines = !!count_lines;
scanner->incomplete = !complete;
scanner->check_complete = !!check_complete;
scanner->detect_errors = !!detect_errors;
scanner->lineno = scanner->count_lines;
scanner->info->scan(scanner);
}

View File

@ -20,6 +20,9 @@ struct dom_scanner_token {
/* Some precedence value */
int precedence;
/* The line number; used for error tokens */
unsigned int lineno;
/* The start of the token string and the token length */
struct dom_string string;
};
@ -93,7 +96,7 @@ struct dom_scanner_info {
/* Initializes the scanner. */
void init_dom_scanner(struct dom_scanner *scanner, struct dom_scanner_info *scanner_info,
struct dom_string *string, int state, int count_lines, int complete,
int check_complete);
int check_complete, int detect_error);
/* The number of tokens in the scanners token table:
* At best it should be big enough to contain properties with space separated
@ -130,6 +133,9 @@ struct dom_scanner {
unsigned int check_complete:1; /* Only generate complete tokens */
unsigned int incomplete:1; /* The scanned string is incomplete */
unsigned int detect_errors:1; /* Check for markup errors */
unsigned int found_error; /* Did we already report this error? */
unsigned int count_lines:1; /* Is line counting enbaled? */
unsigned int lineno; /* Line # of the last scanned token */

View File

@ -391,7 +391,7 @@ parse_dom_select(struct dom_select *select, struct dom_stack *stack,
struct dom_scanner scanner;
struct dom_select_node sel;
init_dom_scanner(&scanner, &dom_css_scanner_info, string, 0, 0, 1, 0);
init_dom_scanner(&scanner, &dom_css_scanner_info, string, 0, 0, 1, 0, 0);
memset(&sel, 0, sizeof(sel));

View File

@ -154,6 +154,17 @@ add_sgml_node(struct dom_stack *stack, enum dom_node_type type, struct dom_scann
/* SGML parser main handling: */
static enum sgml_parser_code
call_sgml_error_function(struct dom_stack *stack, struct dom_scanner_token *token)
{
struct sgml_parser *parser = get_sgml_parser(stack);
unsigned int line = get_sgml_parser_line_number(parser);
assert(parser->error_func);
return parser->error_func(parser, &token->string, line);
}
static inline enum sgml_parser_code
parse_sgml_attributes(struct dom_stack *stack, struct dom_scanner *scanner)
{
@ -217,6 +228,17 @@ parse_sgml_attributes(struct dom_stack *stack, struct dom_scanner *scanner)
case SGML_TOKEN_INCOMPLETE:
return SGML_PARSER_CODE_INCOMPLETE;
case SGML_TOKEN_ERROR:
{
enum sgml_parser_code code;
code = call_sgml_error_function(stack, token);
if (code != SGML_PARSER_CODE_OK)
return code;
skip_dom_scanner_token(scanner);
break;
}
default:
skip_dom_scanner_token(scanner);
}
@ -314,8 +336,13 @@ parse_sgml_plain(struct dom_stack *stack, struct dom_scanner *scanner)
if (!token || token->type == SGML_TOKEN_INCOMPLETE)
return SGML_PARSER_CODE_INCOMPLETE;
assert(token->type == SGML_TOKEN_PROCESS_DATA);
if (token->type == SGML_TOKEN_ERROR)
break;
assert(token->type == SGML_TOKEN_PROCESS_DATA);
/* Fall-through */
case SGML_TOKEN_PROCESS_DATA:
if (add_sgml_proc_instruction(stack, &target, token)
&& (target.type == SGML_TOKEN_PROCESS_XML
|| target.type == SGML_TOKEN_PROCESS_XML_STYLESHEET)
@ -326,7 +353,7 @@ parse_sgml_plain(struct dom_stack *stack, struct dom_scanner *scanner)
/* The attribute souce is complete. */
init_dom_scanner(&attr_scanner, &sgml_scanner_info,
&token->string, SGML_STATE_ELEMENT,
scanner->count_lines, 1, 0);
scanner->count_lines, 1, 0, 0);
if (dom_scanner_has_tokens(&attr_scanner)) {
/* Ignore parser codes from this
@ -350,6 +377,17 @@ parse_sgml_plain(struct dom_stack *stack, struct dom_scanner *scanner)
case SGML_TOKEN_INCOMPLETE:
return SGML_PARSER_CODE_INCOMPLETE;
case SGML_TOKEN_ERROR:
{
enum sgml_parser_code code;
code = call_sgml_error_function(stack, token);
if (code != SGML_PARSER_CODE_OK)
return code;
skip_dom_scanner_token(scanner);
break;
}
case SGML_TOKEN_SPACE:
case SGML_TOKEN_TEXT:
default:
@ -403,11 +441,13 @@ sgml_parsing_push(struct dom_stack *stack, struct dom_node *node, void *data)
int count_lines = !!(parser->flags & SGML_PARSER_COUNT_LINES);
int complete = !!(parser->flags & SGML_PARSER_COMPLETE);
int incremental = !!(parser->flags & SGML_PARSER_INCREMENTAL);
int detect_errors = !!(parser->flags & SGML_PARSER_DETECT_ERRORS);
parsing->depth = parser->stack.depth;
get_dom_stack_top(&parser->stack)->immutable = 1;
init_dom_scanner(&parsing->scanner, &sgml_scanner_info, &node->string,
SGML_STATE_TEXT, count_lines, complete, incremental);
SGML_STATE_TEXT, count_lines, complete, incremental,
detect_errors);
}
static void
@ -494,6 +534,11 @@ get_sgml_parser_line_number(struct sgml_parser *parser)
assert(pstate->scanner.count_lines && pstate->scanner.lineno);
if (pstate->scanner.current
&& pstate->scanner.current < pstate->scanner.table + DOM_SCANNER_TOKENS
&& pstate->scanner.current->type == SGML_TOKEN_ERROR)
return pstate->scanner.current->lineno;
return pstate->scanner.lineno;
}
@ -553,6 +598,9 @@ init_sgml_parser(enum sgml_parser_type type, enum sgml_document_type doctype,
return NULL;
}
if (flags & SGML_PARSER_DETECT_ERRORS)
flags |= SGML_PARSER_COUNT_LINES;
parser->type = type;
parser->flags = flags;
parser->info = get_sgml_info(doctype);

View File

@ -7,69 +7,150 @@
#include "dom/sgml/sgml.h"
#include "dom/scanner.h"
struct sgml_parser;
struct string;
struct uri;
/** enum:[sgml_parser_type]: SGML parser type
*
* There are two kinds of parser types: One that optimises one-time access to
* the DOM tree and one that creates a persistent DOM tree. */
enum sgml_parser_type {
/* The first one is a DOM tree builder. */
SGML_PARSER_TREE,
/* The second one will simply push nodes on the stack, not building a
/** id:[SGML_PARSER_STREAM]::
* The first one will simply push nodes on the stack, not building a
* DOM tree. This interface is similar to that of SAX (Simple API for
* XML) where events are fired when nodes are entered and exited. It is
* useful when you are not actually interested in the DOM tree, but can
* do all processing in a stream-like manner, such as when highlighting
* HTML code. */
SGML_PARSER_STREAM,
/** id:[SGML_PARSER_TREE]::
* The second one is a DOM tree builder, that builds a persistent DOM
* tree. When using this type, it is possible to do even more
* (pre)processing than for parser streams. For example you can sort
* element child nodes, or purge various node such as text nodes that
* only contain space characters. */
SGML_PARSER_TREE,
};
/** enum:[sgml_parser_flag]: SGML parser flags
*
* These flags control how the parser behaves.
*/
enum sgml_parser_flag {
SGML_PARSER_COUNT_LINES = 1,
SGML_PARSER_COMPLETE = 2,
SGML_PARSER_INCREMENTAL = 4,
SGML_PARSER_COUNT_LINES = 1, /*:: Make line numbers available. */
SGML_PARSER_COMPLETE = 2, /*:: Used internally when incremental. */
SGML_PARSER_INCREMENTAL = 4, /*:: Parse chunks of input. */
SGML_PARSER_DETECT_ERRORS = 8, /*:: Report errors. */
};
/** struct:[sgml_parser_state]: SGML parser state
*
* The SGML parser has only little state.
*/
struct sgml_parser_state {
/* Info about the properties of the node contained by state.
/** id:[sgml_parser_state.info]::
* Info about the properties of the node contained by state.
* This is only meaningful to element and attribute nodes. For
* unknown nodes it points to the common 'unknown node' info. */
struct sgml_node_info *info;
/* This is used by the DOM source renderer for highlighting the
/** id:[sgml_parser_state.end_token]::
* This is used by the DOM source renderer for highlighting the
* end-tag of an element. */
struct dom_scanner_token end_token;
};
struct sgml_parser {
enum sgml_parser_type type; /* Stream or tree */
enum sgml_parser_flag flags; /* Flags that control the behaviour */
struct sgml_info *info; /* Backend dependent info */
struct dom_string uri; /* The URI of the DOM document */
struct dom_node *root; /* The document root node */
struct dom_stack stack; /* A stack for tracking parsed nodes */
struct dom_stack parsing; /* Used for tracking parsing states */
};
struct sgml_parser *
init_sgml_parser(enum sgml_parser_type type, enum sgml_document_type doctype,
struct dom_string *uri, enum sgml_parser_flag flags);
void done_sgml_parser(struct sgml_parser *parser);
/** enum:[sgml_parser_code]: (Error) codes for the SGML parser
*
* These enum values are used for return codes.
*/
enum sgml_parser_code {
SGML_PARSER_CODE_OK, /* The parsing was successful */
SGML_PARSER_CODE_INCOMPLETE, /* The parsing could not be completed */
SGML_PARSER_CODE_MEM_ALLOC, /* Failed to allocate memory */
SGML_PARSER_CODE_OK, /*:: The parsing was successful */
SGML_PARSER_CODE_INCOMPLETE, /*:: The parsing could not be completed */
SGML_PARSER_CODE_MEM_ALLOC, /*:: Failed to allocate memory */
/* FIXME: For when we will add support for requiring stricter parsing
/** id:[SGML_PARSER_CODE_ERROR]::
* FIXME: For when we will add support for requiring stricter parsing
* or even a validator. */
SGML_PARSER_CODE_ERROR,
};
/** callback:[sgml_error_T]: SGML error callback
*
* Called by the SGML parser when a parsing error has occurred.
*
* If the return code is not ref:[SGML_PARSER_CODE_OK] the parsing will be
* ended and that code will be returned. */
typedef enum sgml_parser_code
(*sgml_error_T)(struct sgml_parser *, struct dom_string *, unsigned int);
/** struct:[sgml_parser]: The SGML parser
*
* This struct hold info used while parsing SGML data.
*
* NOTE: The only variable the user should set is ref:[error_func]. */
struct sgml_parser {
enum sgml_parser_type type; /*:: Stream or tree */
enum sgml_parser_flag flags; /*:: Flags that control the behaviour */
struct sgml_info *info; /*:: Backend dependent info */
struct dom_string uri; /*:: The URI of the DOM document */
struct dom_node *root; /*:: The document root node */
sgml_error_T error_func; /*:: Called for detected errors */
struct dom_stack stack; /*:: A stack for tracking parsed nodes */
struct dom_stack parsing; /*:: Used for tracking parsing states */
};
/** func:[init_sgml_parser]: Initialise an SGML parser
*
* Initialise an SGML parser with the given properties.
*
* type:: Stream or tree; one-time or persistant.
* doctype:: The document type, this affects what sub type nodes are given.
* uri:: The URI of the document root.
* flags:: Flags controlling the behaviour of the parser.
*
* Returns the created parser or NULL.
*/
struct sgml_parser *
init_sgml_parser(enum sgml_parser_type type, enum sgml_document_type doctype,
struct dom_string *uri, enum sgml_parser_flag flags);
/** func:[done_sgml_parser]: Release an SGML parser
*
* Deallocates all resources, _expect_ the root node.
*
* parser:: The parser being released.
*/
void done_sgml_parser(struct sgml_parser *parser);
/** func:[parse_sgml]: Parse a chunk of SGML source
*
* Parses the given `buffer`. For incremental rendering the last buffer can be
* signals through the `complete` parameter.
*
* parser:: A parser created with ref:[init_sgml_parser].
* buffer:: A string containing the chunk to parse.
* complete:: Whether this is the last chunk to parse.
*
* The returned code is ref:[SGML_PARSER_CODE_OK] if the buffer was
* successfully parserd, else a code hinting at the error.
*/
enum sgml_parser_code
parse_sgml(struct sgml_parser *parser, struct dom_string *buffer, int complete);
/** func:[get_sgml_parser_line_number]: Get the line position in the source
*
* Returns what line number the parser is currently at or zero if there has
* been no parsing yet.
*
* NOTE: Line numbers are recoderded in the scanner tokens.
*/
unsigned int get_sgml_parser_line_number(struct sgml_parser *parser);
#endif

View File

@ -117,6 +117,86 @@ set_sgml_incomplete(struct dom_scanner *scanner, struct dom_scanner_token *token
scanner->position = scanner->end;
}
static inline int
check_sgml_error(struct dom_scanner *scanner)
{
unsigned int found_error = scanner->found_error;
/* Toggle if we found an error previously. */
scanner->found_error = 0;
return scanner->detect_errors && !found_error;
}
static unsigned char *
get_sgml_error_end(struct dom_scanner *scanner, enum sgml_token_type type,
unsigned char *end)
{
switch (type) {
case SGML_TOKEN_CDATA_SECTION:
case SGML_TOKEN_NOTATION_ATTLIST:
case SGML_TOKEN_NOTATION_DOCTYPE:
case SGML_TOKEN_NOTATION_ELEMENT:
if (scanner->position + 9 < end)
end = scanner->position + 9;
break;
case SGML_TOKEN_NOTATION_COMMENT:
/* Just include the '<!--' part. */
if (scanner->position + 4 < end)
end = scanner->position + 4;
break;
case SGML_TOKEN_NOTATION_ENTITY:
if (scanner->position + 6 < end)
end = scanner->position + 6;
break;
case SGML_TOKEN_PROCESS_XML:
if (scanner->position + 5 < end)
end = scanner->position + 5;
break;
case SGML_TOKEN_PROCESS_XML_STYLESHEET:
if (scanner->position + 16 < end)
end = scanner->position + 16;
break;
default:
break;
}
return end;
}
static struct dom_scanner_token *
set_sgml_error(struct dom_scanner *scanner, unsigned char *end)
{
struct dom_scanner_token *token = scanner->current;
struct dom_scanner_token *next;
assert(!scanner->found_error);
if (scanner->current >= scanner->table + DOM_SCANNER_TOKENS) {
scanner->found_error = 1;
next = NULL;
} else {
scanner->current++;
next = scanner->current;
copy_struct(next, token);
}
token->type = SGML_TOKEN_ERROR;
token->lineno = scanner->lineno;
set_dom_string(&token->string, scanner->position, end - scanner->position);
return next;
}
/* Text token scanning */
/* I think it is faster to not check the table here --jonas */
@ -155,9 +235,17 @@ scan_sgml_text_token(struct dom_scanner *scanner, struct dom_scanner_token *toke
}
/* We want the biggest possible text token. */
if (check_sgml_incomplete(scanner, string) && !complete) {
set_sgml_incomplete(scanner, token);
return;
if (!complete) {
if (check_sgml_incomplete(scanner, string)) {
set_sgml_incomplete(scanner, token);
return;
}
if (check_sgml_error(scanner)) {
token = set_sgml_error(scanner, string);
if (!token)
return;
}
}
} else {
@ -412,7 +500,7 @@ scan_sgml_element_token(struct dom_scanner *scanner, struct dom_scanner_token *t
assert(real_length >= 0);
} else {
skip_sgml_space(scanner, &string);
scan_sgml(scanner, string, SGML_CHAR_IDENT);
type = map_dom_scanner_string(scanner, ident, string, base);
if (skip_sgml(scanner, &string, '>', 0)) {
/* We found the end. */
@ -436,7 +524,9 @@ scan_sgml_element_token(struct dom_scanner *scanner, struct dom_scanner_token *t
real_length = string - token->string.string;
skip_sgml_space(scanner, &string);
if (is_sgml_space(string[-1])) {
/* Make '<?xml ' cause the right kind of error. */
if (is_sgml_space(string[-1])
&& string < scanner->end) {
/* We found the end. */
possibly_incomplete = 0;
}
@ -564,9 +654,20 @@ scan_sgml_element_token(struct dom_scanner *scanner, struct dom_scanner_token *t
}
}
if (possibly_incomplete && check_sgml_incomplete(scanner, string)) {
set_sgml_incomplete(scanner, token);
return;
if (possibly_incomplete) {
if (check_sgml_incomplete(scanner, string)) {
set_sgml_incomplete(scanner, token);
return;
}
if (check_sgml_error(scanner) && string == scanner->end) {
unsigned char *end;
end = get_sgml_error_end(scanner, type, string);
token = set_sgml_error(scanner, end);
if (!token)
return;
}
}
token->type = type;
@ -599,13 +700,20 @@ scan_sgml_proc_inst_token(struct dom_scanner *scanner, struct dom_scanner_token
}
if (!string) {
/* Makes the next succeed when checking for incompletion. */
/* Makes the next succeed when checking for incompletion, and
* puts the rest of the text within the token. */
string = scanner->end;
if (check_sgml_incomplete(scanner, string)) {
set_sgml_incomplete(scanner, token);
return;
}
if (check_sgml_error(scanner)) {
token = set_sgml_error(scanner, string);
if (!token)
return;
}
}
token->type = SGML_TOKEN_PROCESS_DATA;
@ -622,35 +730,34 @@ static struct dom_scanner_token *
scan_sgml_tokens(struct dom_scanner *scanner)
{
struct dom_scanner_token *table_end = scanner->table + DOM_SCANNER_TOKENS;
struct dom_scanner_token *current;
if (!begin_dom_token_scanning(scanner))
return get_dom_scanner_token(scanner);
/* Scan tokens until we fill the table */
for (current = scanner->table + scanner->tokens;
current < table_end && scanner->position < scanner->end;
current++) {
for (scanner->current = scanner->table + scanner->tokens;
scanner->current < table_end && scanner->position < scanner->end;
scanner->current++) {
if (scanner->state == SGML_STATE_ELEMENT
|| (*scanner->position == '<'
&& scanner->state != SGML_STATE_PROC_INST)) {
skip_sgml_space(scanner, &scanner->position);
if (scanner->position >= scanner->end) break;
scan_sgml_element_token(scanner, current);
scan_sgml_element_token(scanner, scanner->current);
/* Shall we scratch this token? */
if (current->type == SGML_TOKEN_SKIP) {
current--;
if (scanner->current->type == SGML_TOKEN_SKIP) {
scanner->current--;
}
} else if (scanner->state == SGML_STATE_TEXT) {
scan_sgml_text_token(scanner, current);
scan_sgml_text_token(scanner, scanner->current);
} else {
scan_sgml_proc_inst_token(scanner, current);
scan_sgml_proc_inst_token(scanner, scanner->current);
}
}
return end_dom_token_scanning(scanner, current);
return end_dom_token_scanning(scanner, scanner->current);
}

View File

@ -52,6 +52,10 @@ enum sgml_token_type {
* not complete. Only meaningful if scanner->complete is incomplete. */
SGML_TOKEN_INCOMPLETE,
/* A special token for reporting that an error in the markup was found.
* Only in effect when error checking has been requested. */
SGML_TOKEN_ERROR,
/* Token type used internally when scanning to signal that the token
* should not be recorded in the scanners token table. */
SGML_TOKEN_SKIP,

View File

@ -39,21 +39,28 @@ dom_string_ncasecmp(struct dom_string *string1, struct dom_string *string2, size
set_dom_string(string1, (string2)->string, (string2)->length)
static inline struct dom_string *
init_dom_string(struct dom_string *string, unsigned char *str, size_t len)
add_to_dom_string(struct dom_string *string, unsigned char *str, size_t len)
{
string->string = mem_alloc(len + 1);
if (!string->string)
unsigned char *newstring;
newstring = mem_realloc(string->string, string->length + len + 1);
if (!newstring)
return NULL;
memcpy(string->string, str, len);
string->string[len] = 0;
string->length = len;
string->string = newstring;
memcpy(string->string + string->length, str, len);
string->length += len;
string->string[string->length] = 0;
return string;
}
#define init_dom_string(string, str, len) add_to_dom_string(string, str, len)
#define is_dom_string_set(str) ((str)->string && (str)->length)
#define done_dom_string(str) mem_free((str)->string);
#define done_dom_string(str) \
do { mem_free_set(&(str)->string, NULL); (str)->length = 0; } while (0)
#define isquote(c) ((c) == '"' || (c) == '\'')

View File

@ -14,6 +14,4 @@ TESTDEPS = \
$(top_builddir)/src/util/string.o \
$(top_builddir)/src/util/memory.o
TESTDEPS-$(CONFIG_DEBUG) += $(top_builddir)/src/util/memdebug.o \
include $(top_srcdir)/Makefile.lib

View File

@ -1,7 +1,7 @@
Core GIT Tests
==============
ELinks testing infrastructure
=============================
This directory holdstest scripts for the DOM implementation. The first part of
This directory holds test scripts for the DOM implementation. The first part of
this short document describes how to run the tests and read their output.
When fixing the tools or adding enhancements, you are strongly encouraged to
@ -27,7 +27,7 @@ The easiest way to run tests is to say "make test". This runs all the tests.
Or you can run each test individually from command line, like this:
$ sh ./test-sgml-parser-basic
$ TEST_LIB=${path_to_top_srcdir}/test/libtest.sh sh ./test-sgml-parser-basic
* ok 1: parse a small document.
...
* ok 23: parse a CDATA section.
@ -49,6 +49,10 @@ command line argument to the test.
This causes the test to immediately exit upon the first
failed test.
Note, these options can be passed indirectly to all tests when running test using
make by setting TEST_OPTS, like this:
make test TEST_OPTS=--immediate
Naming Tests
------------
@ -91,20 +95,23 @@ The test script is written as a shell script. It should start with the standard
Source 'libtest'
--------------------
----------------
After assigning test_description, the test script should source test-lib.sh
like this:
After assigning test_description, the test script should source the shell test
library like this:
. ./libtest
. "$TEST_LIB"
This assumes that the TEST_LIB environment variable has been set and is needed
for test to run from out of tree builds.
This test harness library does the following things:
- If the script is invoked with command line argument --help (or -h), it shows
the test_description and exits.
- Creates an empty test directory. This directory is 'test/trash' if you must
know, but I do not think you care.
- Creates an empty test directory. This directory is 'trash' if you must know,
but I do not think you care.
- Defines standard test helper functions for your scripts to use. These
functions are designed to make all scripts behave consistently when command

View File

@ -104,7 +104,8 @@ sgml_parser_test_tree(struct dom_stack *stack, struct dom_node *node, void *data
struct dom_string *name = get_dom_node_name(node);
/* Always print the URI for identification. */
update_number_of_lines(stack);
if (update_number_of_lines(stack))
return;
print_indent(stack);
printf("%.*s: %.*s\n",
@ -177,7 +178,8 @@ sgml_parser_test_end(struct dom_stack *stack, struct dom_node *node, void *data)
{
struct sgml_parser *parser = stack->contexts[0]->data;
if (parser->flags & SGML_PARSER_COUNT_LINES) {
if ((parser->flags & SGML_PARSER_COUNT_LINES)
&& !(parser->flags & SGML_PARSER_DETECT_ERRORS)) {
printf("%d\n", number_of_lines);
}
}
@ -218,6 +220,15 @@ struct dom_stack_context_info sgml_parser_test_context_info = {
}
};
static enum sgml_parser_code
sgml_error_function(struct sgml_parser *parser, struct dom_string *string,
unsigned int line_number)
{
printf("error on line %d: %.*s\n",
line_number, string->length, string->string);
return SGML_PARSER_CODE_OK;
}
void die(const char *msg, ...)
{
@ -284,6 +295,9 @@ main(int argc, char *argv[])
flags |= SGML_PARSER_INCREMENTAL;
complete = 0;
} else if (!strcmp(arg, "error")) {
flags |= SGML_PARSER_DETECT_ERRORS;
} else if (!strcmp(arg, "help")) {
die(NULL);
@ -295,6 +309,7 @@ main(int argc, char *argv[])
parser = init_sgml_parser(SGML_PARSER_STREAM, doctype, &uri, flags);
if (!parser) return 1;
parser->error_func = sgml_error_function;
add_dom_stack_context(&parser->stack, NULL, &sgml_parser_test_context_info);
code = parse_sgml(parser, &source, complete);

View File

@ -24,29 +24,13 @@ test_output_equals () {
y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/;
s/[^a-zA-Z0-9-]//g;')"
sgml-parser --uri "$URI" --src "$src" $@ | sed 's/^ //' > output
sgml-parser --uri "$URI" --src "$src" | sed 's/^ //' > output
echo "#document: $URI" > expected
echo "$out" | sed -n '2,$p' >> expected
test_expect_success "$desc" 'cmp output expected'
}
test_expect_incomplete () {
desc="$1"; shift
src="$1"; shift
URI="test:$(echo "$desc" | sed '
s/^[ \t]*\[[^]]*\][ \t]*//;
s/[:., \t][:., \t]*/-/g;
s/_/-/g;
# *cough*
y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/;
s/[^a-zA-Z0-9-]//g;')"
test_expect_code 1 "$desc" \
"sgml-parser --uri '$URI' --src '$src' --incomplete"
}
################################################################
# Parse various SGML node types.
@ -263,121 +247,4 @@ element: root
attribute: ns:attr -> value
proc-instruction: target -> data'
test_output_equals \
'Check line numbers. (I)' \
'<!-- line --> number <one />' \
'
1' \
--print-lines
test_output_equals \
'Check line numbers. (II)' \
'<
line:2
line:3
=
"line:5"
><?xml
line:7="..."
line:8
=
'\''...'\''></line:10>' \
'
10' \
--print-lines
test_output_equals \
'Check line numbers. (III)' \
'1
2
3
4
5
6
7
8' \
'
8' \
--print-lines
test_expect_incomplete \
'Check incomplete comment. (I)' \
'<!-'
test_expect_incomplete \
'Check incomplete comment. (II)' \
'<!-- ... '
test_expect_incomplete \
'Check incomplete notation. (I)' \
'<!'
test_expect_incomplete \
'Check incomplete notation. (II)' \
'<!D'
test_expect_incomplete \
'Check incomplete cdata section. (I)' \
'<![CDATA[ ... '
test_expect_incomplete \
'Check incomplete cdata section. (II)' \
'<![CDAT'
test_expect_incomplete \
'Check incomplete element. (I)' \
'<elem...'
test_expect_incomplete \
'Check incomplete element. (II)' \
'<'
test_expect_incomplete \
'Check incomplete element end. (I)' \
'<a></a'
test_expect_incomplete \
'Check incomplete element end. (II)' \
'<a></'
test_expect_incomplete \
'Check incomplete attribute.' \
'<element attr...'
test_expect_incomplete \
'Check incomplete attribute value.' \
'<element attr=...'
test_expect_incomplete \
'Check incomplete attribute quoted value. (I)' \
'<element attr="...'
test_expect_incomplete \
'Check incomplete attribute quoted value. (II)' \
'<element attr='\''...'
test_expect_incomplete \
'Check incomplete processing instruction. (I)' \
'<?xml'
test_expect_incomplete \
'Check incomplete processing instruction. (II)' \
'<?xml attr...'
test_expect_incomplete \
'Check incomplete notation.' \
'<!DOCTYPE html PUBLIC ...'
test_expect_incomplete \
'Check incomplete reference. (I)' \
'&#123456789'
test_expect_incomplete \
'Check incomplete reference. (II)' \
'&amp'
test_expect_incomplete \
'Check incomplete text.' \
'plain text is always incomplete (if incomplete)'
test_done

View File

@ -0,0 +1,164 @@
#!/bin/sh
#
# Copyright (c) 2005 Jonas Fonseca
#
test_description='Test SGML parser error reporting
This test checks that the SGML parser will report errors in the source
given to it.
'
. "$TEST_LIB"
test_output_error () {
desc="$1"; shift
src="$1"; shift
out="$1"; shift
sgml-parser --src "$src" --error > output
echo "$out" | sed -n '2,$p' > expected
test_expect_success "$desc" 'cmp output expected'
}
################################################################
# Check parsing errors
test_output_error \
'Check an element error.' \
'<html' \
'
error on line 1: <html'
test_output_error \
'Check an entity reference error.' \
'a
b
&c' \
'
error on line 3: &c'
test_output_error \
'Check multiple entity reference errors.' \
'a
&b&amp;
c
&d' \
'
error on line 2: &b
error on line 4: &d'
test_output_error \
'Check incomplete comment. (I)' \
'<!-' \
'
error on line 1: <!-'
test_output_error \
'Check incomplete comment. (II)' \
'<!-- ... ' \
"
error on line 1: <!--"
test_output_error \
'Check incomplete notation. (I)' \
'<!' \
'
error on line 1: <!'
test_output_error \
'Check incomplete notation. (II)' \
'<!DOCTYPE ...' \
'
error on line 1: <!DOCTYPE'
test_output_error \
'Check incomplete cdata section. (I)' \
'<![CDATA[ ... ' \
'
error on line 1: <![CDATA['
test_output_error \
'Check incomplete cdata section. (II)' \
'<![CDAT' \
'
error on line 1: <![CDAT'
test_output_error \
'Check incomplete processing instruction. (I)' \
'<?xml ' \
'
error on line 1: <?xml'
test_output_error \
'Check incomplete processing instruction. (II)' \
'<?xml-stylesheet attr...' \
'
error on line 1: attr...'
test_output_error \
'Check incomplete reference. (I)' \
'&#123456789' \
'
error on line 1: &#123456789'
test_output_error \
'Check incomplete reference. (II)' \
'&amp' \
'
error on line 1: &amp'
test_output_error \
'Check incomplete element. (I)' \
'<elem...' \
'
error on line 1: <elem...'
test_output_error \
'Check incomplete element. (II)' \
'<' \
'
error on line 1: <'
test_output_error \
'Check incomplete element end. (I)' \
'<a></a' \
'
error on line 1: </a'
test_output_error \
'Check incomplete element end. (II)' \
'<a></' \
'
error on line 1: </'
test_output_error \
'Check incomplete attribute.' \
'<element attr...' \
'
error on line 1: attr...'
test_output_error \
'Check incomplete attribute value.' \
'<element attr=...' \
'
error on line 1: ...'
test_output_error \
'Check incomplete attribute quoted value. (I)' \
'<element attr="...' \
'
error on line 1: "...'
test_output_error \
'Check incomplete attribute quoted value. (II)' \
"<element attr='..." \
"
error on line 1: '..."
test_done

View File

@ -0,0 +1,107 @@
#!/bin/sh
#
# Copyright (c) 2005 Jonas Fonseca
#
test_description='Test that incompleteness is correctly detected
This test checks that the SGML parser correctly finds and reports
when a part of the source is incomplete.
'
. "$TEST_LIB"
test_expect_incomplete () {
desc="$1"; shift
src="$1"; shift
sgml-parser --src "$src" --incomplete >/dev/null
test_expect_success "$desc" \
"test $? = 1"
}
################################################################
# Check for incompleteness
test_expect_incomplete \
'Check incomplete comment. (I)' \
'<!-'
test_expect_incomplete \
'Check incomplete comment. (II)' \
'<!-- ... '
test_expect_incomplete \
'Check incomplete notation. (I)' \
'<!'
test_expect_incomplete \
'Check incomplete notation. (II)' \
'<!D'
test_expect_incomplete \
'Check incomplete cdata section. (I)' \
'<![CDATA[ ... '
test_expect_incomplete \
'Check incomplete cdata section. (II)' \
'<![CDAT'
test_expect_incomplete \
'Check incomplete element. (I)' \
'<elem...'
test_expect_incomplete \
'Check incomplete element. (II)' \
'<'
test_expect_incomplete \
'Check incomplete element end. (I)' \
'<a></a'
test_expect_incomplete \
'Check incomplete element end. (II)' \
'<a></'
test_expect_incomplete \
'Check incomplete attribute.' \
'<element attr...'
test_expect_incomplete \
'Check incomplete attribute value.' \
'<element attr=...'
test_expect_incomplete \
'Check incomplete attribute quoted value. (I)' \
'<element attr="...'
test_expect_incomplete \
'Check incomplete attribute quoted value. (II)' \
"<element attr='..."
test_expect_incomplete \
'Check incomplete processing instruction. (I)' \
'<?xml'
test_expect_incomplete \
'Check incomplete processing instruction. (II)' \
'<?xml attr...'
test_expect_incomplete \
'Check incomplete notation.' \
'<!DOCTYPE html PUBLIC ...'
test_expect_incomplete \
'Check incomplete reference. (I)' \
'&#123456789'
test_expect_incomplete \
'Check incomplete reference. (II)' \
'&amp'
test_expect_incomplete \
'Check incomplete text.' \
'plain text is always incomplete (if incomplete)'
test_done

View File

@ -0,0 +1,59 @@
#!/bin/sh
#
# Copyright (c) 2005 Jonas Fonseca
#
test_description='Test the SGML parsers counting of lines
Checks that the SGML parser correctly reports how many lines the
source has.
'
. "$TEST_LIB"
test_output_line_numbers () {
desc="$1"; shift
src="$1"; shift
expected_lines="$1"; shift
lines=$(sgml-parser --src "$src" --print-lines)
test_expect_success "$desc" "test $lines = $expected_lines"
}
################################################################
# Check line numbers
test_output_line_numbers \
'Check line numbers. (I)' \
'<!-- line --> number <one />' \
1
test_output_line_numbers \
'Check line numbers. (II)' \
'<
line:2
line:3
=
"line:5"
><?xml
line:7="..."
line:8
=
'\''...'\''></line:10>' \
10
test_output_line_numbers \
'Check line numbers. (III)' \
'1
2
3
4
5
6
7
8' \
8
test_done

View File

@ -6,4 +6,26 @@ OBJS-$(CONFIG_MIMETYPES) += mimetypes.o
OBJS = common.o default.o
TEST_PROGS = \
mailcap-cache
# The dependencies are a bit funny here! I don't know why. Just remember to
# make clean before making the test. --jonas
mailcap-cache.o: mailcap.c
$(call cmd,compile,-DTEST_MAILCAP)
TESTDEPS = \
common.o \
$(top_builddir)/src/osdep/osdep.o \
$(top_builddir)/src/osdep/stub.o \
$(top_builddir)/src/util/conv.o \
$(top_builddir)/src/util/error.o \
$(top_builddir)/src/util/file.o \
$(top_builddir)/src/util/hash.o \
$(top_builddir)/src/util/memory.o \
$(top_builddir)/src/util/string.o \
$(top_builddir)/src/util/time.o
TESTDEPS-$(CONFIG_DEBUG) += $(top_builddir)/src/util/memdebug.o
include $(top_srcdir)/Makefile.lib

View File

@ -443,6 +443,8 @@ done_mailcap(struct module *module)
mailcap_map_size = 0;
}
#ifndef TEST_MAILCAP
static int
change_hook_mailcap(struct session *ses, struct option *current, struct option *changed)
{
@ -469,6 +471,10 @@ init_mailcap(struct module *module)
get_mailcap_enable() = 0;
}
#else
#define init_mailcap NULL
#endif /* TEST_MAILCAP */
/* The command semantics include the following:
*
* %s is the filename that contains the mail body data
@ -673,3 +679,108 @@ struct module mailcap_mime_module = struct_module(
/* init: */ init_mailcap,
/* done: */ done_mailcap
);
#ifdef TEST_MAILCAP
/* Some ugly shortcuts for getting defined symbols to work. */
int default_mime_backend,
install_signal_handler,
mimetypes_mime_backend;
struct list_head terminals;
void die(const char *msg, ...)
{
va_list args;
if (msg) {
va_start(args, msg);
vfprintf(stderr, msg, args);
fputs("\n", stderr);
va_end(args);
}
exit(1);
}
int
main(int argc, char *argv[])
{
unsigned char *format = "description,ask,block,program";
int has_gotten = 0;
int i;
for (i = 1; i < argc; i++) {
char *arg = argv[i];
if (strncmp(arg, "--", 2))
break;
arg += 2;
if (!strncmp(arg, "path", 4)) {
arg += 4;
if (*arg == '=') {
arg++;
get_mailcap_path() = arg;
} else {
i++;
if (i >= argc)
die("--path expects a parameter");
get_mailcap_path() = argv[i];
}
done_mailcap(NULL);
} else if (!strncmp(arg, "format", 6)) {
arg += 6;
if (*arg == '=') {
arg++;
format = arg;
} else {
i++;
if (i >= argc)
die("--format expects a parameter");
format = argv[i];
}
} else if (!strncmp(arg, "get", 3)) {
struct mime_handler *handler;
arg += 3;
if (*arg == '=') {
arg++;
} else {
i++;
if (i >= argc)
die("--get expects a parameter");
arg = argv[i];
}
if (has_gotten)
printf("\n");
has_gotten = 1;
printf("type: %s\n", arg);
handler = get_mime_handler_mailcap(arg, 0);
if (!handler) continue;
if (strstr(format, "description"))
printf("description: %s\n", handler->description);
if (strstr(format, "ask"))
printf("ask: %d\n", handler->ask);
if (strstr(format, "block"))
printf("block: %d\n", handler->block);
if (strstr(format, "program"))
printf("program: %s\n", handler->program);
} else {
die("Unknown argument '%s'", arg - 2);
}
}
done_mailcap(NULL);
return 0;
}
#endif /* TEST_MAILCAP */

View File

@ -0,0 +1,95 @@
#!/bin/sh
#
# Copyright (c) 2005 Jonas Fonseca
#
test_description='Test mailcap parsing and querying
This tests the parsing of various mailcap files, if they are
"prioritised" correctly, if the test are run correctly and
if querying returns the expected mailcap entry.
'
. "$TEST_LIB"
# Set PAGER to something recognisable since it gets appended as
# "|copiousoutput_handler" to entries with copiousoutput.
export PAGER=copiousoutput_handler
################################################################
# Parse a simple mailcap file
cat > mailcap-basic <<EOF
# Mimetype Handler
text/html; elinks --force-html %s; needsterminal
text/enriched; richtext ; copiousoutput
text/*; view %s; needsterminal
application/postscript; ps2ascii %s ; copiousoutput
# Convert images to text using the netpbm tools
image/*; (anytopnm %s | pnmscale -xysize 200 150 | \
pnminvert | ppmtopgm | pgmtopbm | \
pbmtoascii -1x2 ) 2>&1 ; copiousoutput
EOF
mailcap-cache \
--path "mailcap-basic" \
--format "block,program" \
--get "text/html" \
--get "text/x-csh" \
--get "application/postscript" \
--get "application/foo" \
> output
cat > expected <<EOF
type: text/html
block: 1
program: elinks --force-html %
type: text/x-csh
block: 1
program: view %
type: application/postscript
block: 1
program: ps2ascii %|copiousoutput_handler
type: application/foo
EOF
test_expect_success \
'Parse simple mailcap file.' \
'cmp output expected' \
################################################################
# Parse a two simple mailcap files; first one with tests
touch DISPLAY
cat > mailcap-simple-with-test <<EOF
application/postscript; gv %s ; test=test -e "DISPLAY" ;
image/*; xzgv %s ; test=test -e "DISPLAY";
EOF
mailcap-cache \
--path "mailcap-simple-with-test:mailcap-simple" \
--format "block,program" \
--get "image/jpeg" \
--get "application/postscript" \
> output
cat > expected <<EOF
type: image/jpeg
block: 0
program: xzgv %
type: application/postscript
block: 0
program: gv %
EOF
test_expect_success \
'Parse two simple mailcap files; first one with tests.' \
'cmp output expected' \
test_done

View File

@ -344,14 +344,23 @@ exe(unsigned char *path)
#endif
static unsigned char *clipboard;
unsigned char *
get_clipboard_text(void) /* !!! FIXME */
get_clipboard_text(void)
{
unsigned char *ret = mem_alloc(1);
/* GNU Screen's clipboard */
if (is_gnuscreen()) {
struct string str;
if (ret) ret[0] = 0;
if (!init_string(&str)) return NULL;
return ret;
add_to_string(&str, "screen -X paste .");
if (str.length) exe(str.source);
if (str.source) done_string(&str);
}
return stracpy(empty_string_or_(clipboard));
}
void
@ -370,7 +379,9 @@ set_clipboard_text(unsigned char *data)
if (str.source) done_string(&str);
}
/* TODO: internal clipboard */
/* Shouldn't complain about leaks. */
if (clipboard) free(clipboard);
clipboard = strdup(data);
}
/* Set xterm-like term window's title. */

View File

@ -16,6 +16,4 @@ TESTDEPS = \
$(top_builddir)/src/util/string.o \
$(top_builddir)/src/util/time.o
TESTDEPS-$(CONFIG_DEBUG) += $(top_builddir)/src/util/memdebug.o
include $(top_srcdir)/Makefile.lib

View File

@ -115,28 +115,31 @@ end_with_known_tld(unsigned char *s, int slen)
return -1;
}
/* XXX: this function writes to @name. */
static int
check_whether_file_exists(unsigned char *name)
{
/* Check POST_CHAR etc ... */
static const unsigned char chars[] = POST_CHAR_S "#?";
int i;
int namelen = strlen(name);
if (file_exists(name))
return strlen(name);
return namelen;
for (i = 0; i < sizeof(chars) - 1; i++) {
unsigned char *pos = strchr(name, chars[i]);
int namelen = -1;
unsigned char *pos = memchr(name, chars[i], namelen);
int exists;
if (!pos) continue;
*pos = 0;
if (file_exists(name))
namelen = strlen(name);
exists = file_exists(name);
*pos = chars[i];
if (namelen >= 0) return namelen;
if (exists) {
return pos - name;
}
}
return -1;
@ -147,29 +150,15 @@ check_uri_file(unsigned char *name)
{
/* Check POST_CHAR etc ... */
static const unsigned char chars[] = POST_CHAR_S "#?";
int i;
for (i = 0; i < sizeof(chars) - 1; i++) {
unsigned char *pos = strchr(name, chars[i]);
int namelen;
if (!pos) continue;
*pos = 0;
namelen = strlen(name);
*pos = chars[i];
return namelen;
}
return strlen(name);
return strcspn(name, chars);
}
/* Encodes URIs without encoding stuff like fragments and query separators. */
static void
encode_file_uri_string(struct string *string, unsigned char *uristring)
{
int filenamelen = check_uri_file(uristring);
int filenamelen = check_whether_file_exists(uristring);
encode_uri_string(string, uristring, filenamelen, 0);
}

View File

@ -986,6 +986,25 @@ tp_open(struct type_query *type_query)
return;
}
if (type_query->uri->protocol == PROTOCOL_FILE) {
unsigned char *file = get_uri_string(type_query->uri, URI_PATH);
unsigned char *handler = NULL;
if (file) {
handler = subst_file(type_query->external_handler, file);
mem_free(file);
}
if (handler) {
exec_on_terminal(type_query->ses->tab->term,
handler, "", !!type_query->block);
mem_free(handler);
}
done_type_query(type_query);
return;
}
continue_download(type_query, "");
}
@ -1154,7 +1173,7 @@ struct {
{ "application/xhtml+xml", 0 }, /* RFC 3236 */
#if CONFIG_DOM
{ "application/docbook+xml", 1 },
{ "application/rss+xml", 1 },
{ "application/rss+xml", 0 },
{ "application/xbel+xml", 1 },
{ "application/xbel", 1 },
{ "application/x-xbel", 1 },

View File

@ -197,91 +197,103 @@ unblock_terminal(struct terminal *term)
textarea_edit(1, NULL, NULL, NULL, NULL);
}
static void
exec_on_master_terminal(struct terminal *term,
unsigned char *path, int plen,
unsigned char *delete, int dlen,
int fg)
{
int blockh;
int param_size = plen + dlen + 2 /* 2 null char */ + 1 /* fg */;
unsigned char *param = fmem_alloc(param_size);
if (!param) return;
param[0] = fg;
memcpy(param + 1, path, plen + 1);
memcpy(param + 1 + plen + 1, delete, dlen + 1);
if (fg == 1) block_itrm(term->fdin);
blockh = start_thread((void (*)(void *, int)) exec_thread,
param, param_size);
fmem_free(param);
if (blockh == -1) {
if (fg == 1) unblock_itrm(term->fdin);
return;
}
if (fg == 1) {
term->blocked = blockh;
set_handlers(blockh,
(select_handler_T) unblock_terminal,
NULL,
(select_handler_T) unblock_terminal,
term);
set_handlers(term->fdin, NULL, NULL,
(select_handler_T) destroy_terminal,
term);
} else {
set_handlers(blockh, close_handle, NULL,
close_handle, (void *) (long) blockh);
}
}
static void
exec_on_slave_terminal( struct terminal *term,
unsigned char *path, int plen,
unsigned char *delete, int dlen,
int fg)
{
int data_size = plen + dlen + 1 /* 0 */ + 1 /* fg */ + 2 /* 2 null char */;
unsigned char *data = fmem_alloc(data_size);
if (!data) return;
data[0] = 0;
data[1] = fg;
memcpy(data + 2, path, plen + 1);
memcpy(data + 2 + plen + 1, delete, dlen + 1);
hard_write(term->fdout, data, data_size);
fmem_free(data);
}
void
exec_on_terminal(struct terminal *term, unsigned char *path,
unsigned char *delete, int fg)
{
int plen;
int dlen = strlen(delete);
if (path && !*path) return;
if (!path) {
path = "";
plen = 0;
if (path) {
if (!*path) return;
} else {
plen = strlen(path);
path = "";
}
#ifdef NO_FG_EXEC
fg = 0;
#endif
if (term->master) {
if (!*path) dispatch_special(delete);
else {
int blockh;
unsigned char *param;
int param_size;
if (is_blocked() && fg) {
unlink(delete);
return;
}
param_size = plen + dlen + 2 /* 2 null char */ + 1 /* fg */;
param = mem_alloc(param_size);
if (!param) return;
param[0] = fg;
memcpy(param + 1, path, plen + 1);
memcpy(param + 1 + plen + 1, delete, dlen + 1);
if (fg == 1) block_itrm(term->fdin);
blockh = start_thread((void (*)(void *, int)) exec_thread,
param, param_size);
if (blockh == -1) {
if (fg == 1) unblock_itrm(term->fdin);
mem_free(param);
return;
}
mem_free(param);
if (fg == 1) {
term->blocked = blockh;
set_handlers(blockh,
(select_handler_T) unblock_terminal,
NULL,
(select_handler_T) unblock_terminal,
term);
set_handlers(term->fdin, NULL, NULL,
(select_handler_T) destroy_terminal,
term);
/* block_itrm(term->fdin); */
} else {
set_handlers(blockh, close_handle, NULL,
close_handle, (void *) (long) blockh);
}
if (!*path) {
dispatch_special(delete);
return;
}
if (fg && is_blocked()) {
unlink(delete);
return;
}
exec_on_master_terminal(term,
path, strlen(path),
delete, strlen(delete),
fg);
} else {
int data_size = plen + dlen + 1 /* 0 */ + 1 /* fg */ + 2 /* 2 null char */;
unsigned char *data = mem_alloc(data_size);
if (data) {
data[0] = 0;
data[1] = fg;
memcpy(data + 2, path, plen + 1);
memcpy(data + 2 + plen + 1, delete, dlen + 1);
hard_write(term->fdout, data, data_size);
mem_free(data);
}
#if 0
char x = 0;
hard_write(term->fdout, &x, 1);
x = fg;
hard_write(term->fdout, &x, 1);
hard_write(term->fdout, path, strlen(path) + 1);
hard_write(term->fdout, delete, strlen(delete) + 1);
#endif
exec_on_slave_terminal( term,
path, strlen(path),
delete, strlen(delete),
fg);
}
}

View File

@ -324,19 +324,20 @@ add_document_to_string(struct string *string, struct document *document)
if_assert_failed return NULL;
for (y = 0; y < document->height; y++) {
struct screen_char *pos = document->data[y].chars;
int white = 0;
int x;
for (x = 0; x < document->data[y].length; x++) {
struct screen_char *pos = &document->data[y].chars[x];
unsigned char data = pos->data;
unsigned int frame = (pos->attr & SCREEN_ATTR_FRAME);
if (!isscreensafe(data)) {
white++;
continue;
} else if (frame && data >= 176 && data < 224) {
data = frame_dumb[data - 176];
} else {
if (frame && data >= 176 && data < 224)
data = frame_dumb[data - 176];
if (data <= ' ') {
/* Count spaces. */

View File

@ -162,4 +162,4 @@ test_done () {
test=trash
rm -fr "$test"
mkdir "$test"
cd "$test"
cd "$test" || error "Cannot setup test environment"