mirror of
https://github.com/rkd77/elinks.git
synced 2024-12-04 14:46:47 -05:00
Merge with http://elinks.cz/elinks.git
This commit is contained in:
commit
2cfd0a9bb4
@ -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-*)
|
||||
|
122
doc/Makefile
122
doc/Makefile
@ -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
52
doc/code2doc.conf
Normal 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
46
doc/tools/code2doc
Executable 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;
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
if (document->options.plain) {
|
||||
add_dom_stack_context(&parser->stack, &renderer,
|
||||
&dom_source_renderer_context_info);
|
||||
|
||||
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
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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) == '\'')
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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)' \
|
||||
'�'
|
||||
|
||||
test_expect_incomplete \
|
||||
'Check incomplete reference. (II)' \
|
||||
'&'
|
||||
|
||||
test_expect_incomplete \
|
||||
'Check incomplete text.' \
|
||||
'plain text is always incomplete (if incomplete)'
|
||||
|
||||
test_done
|
||||
|
164
src/dom/test/test-sgml-parser-error
Executable file
164
src/dom/test/test-sgml-parser-error
Executable 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&
|
||||
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)' \
|
||||
'�' \
|
||||
'
|
||||
error on line 1: �'
|
||||
|
||||
test_output_error \
|
||||
'Check incomplete reference. (II)' \
|
||||
'&' \
|
||||
'
|
||||
error on line 1: &'
|
||||
|
||||
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
|
107
src/dom/test/test-sgml-parser-incomplete
Executable file
107
src/dom/test/test-sgml-parser-incomplete
Executable 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)' \
|
||||
'�'
|
||||
|
||||
test_expect_incomplete \
|
||||
'Check incomplete reference. (II)' \
|
||||
'&'
|
||||
|
||||
test_expect_incomplete \
|
||||
'Check incomplete text.' \
|
||||
'plain text is always incomplete (if incomplete)'
|
||||
|
||||
test_done
|
59
src/dom/test/test-sgml-parser-lines
Executable file
59
src/dom/test/test-sgml-parser-lines
Executable 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
|
@ -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
|
||||
|
@ -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 */
|
||||
|
95
src/mime/backend/test-mailcap-cache
Executable file
95
src/mime/backend/test-mailcap-cache
Executable 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
|
@ -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. */
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 },
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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. */
|
||||
|
@ -162,4 +162,4 @@ test_done () {
|
||||
test=trash
|
||||
rm -fr "$test"
|
||||
mkdir "$test"
|
||||
cd "$test"
|
||||
cd "$test" || error "Cannot setup test environment"
|
||||
|
Loading…
Reference in New Issue
Block a user