1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-09-27 02:56:18 -04:00

Merge with git+ssh://pasky.or.cz/srv/git/elinks.git

This commit is contained in:
Adam Golebiowski 2006-01-11 00:29:10 +01:00 committed by Adam Golebiowski
commit f15c0a2677
139 changed files with 8462 additions and 3216 deletions

View File

@ -48,6 +48,9 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
INSTALL_DATA = @INSTALL_DATA@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
TEST_LIB=$(top_srcdir)/test/libtest.sh
export TEST_LIB
host = @host@
ASCIIDOC = @ASCIIDOC@
@ -139,6 +142,7 @@ CONFIG_RISCOS = @CONFIG_RISCOS@
CONFIG_RUBY = @CONFIG_RUBY@
CONFIG_SCANNER = @CONFIG_SCANNER@
CONFIG_SCRIPTING = @CONFIG_SCRIPTING@
CONFIG_SEE = @CONFIG_SEE@
CONFIG_SHA1 = @CONFIG_SHA1@
CONFIG_SMALL = @CONFIG_SMALL@
CONFIG_SMB = @CONFIG_SMB@

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)$@"
@ -43,7 +43,7 @@ quiet_cmd_ld_objs = " [$(LD_COLOR)LD$(END_COLOR)] $(RELPATH)$@"
`test -e $(subdir)/lib.o && echo $(subdir)/lib.o`)
quiet_cmd_link = ' [$(LINK_COLOR)LINK$(END_COLOR)] $(RELPATH)$@'
cmd_link = $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
cmd_link = $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(2) $(LIBS)
quiet_cmd_sparse = ' [SPARSE] $(RELPATH)$(2)'
cmd_sparse = $(SPARSE) $(DEFS) $(INCLUDES) $(AM_CFLAGS) $(CFLAGS) $(SPARSE_FLAGS) $(2)
@ -125,12 +125,15 @@ CLEAN += $(PROG)
all-default: $(LIB_O) $(PROGS) $(MAN1) $(MAN5)
# Ensure that Makefiles in subdirs are created before we recursive into them
init-recursive: init-default
init-default:
@$(foreach subdir,$(sort $(SUBDIRS)), \
$(MKINSTALLDIRS) $(subdir) >/dev/null; \
echo 'include $(SRC)/$(RELPATH)/$(subdir)/Makefile' > $(subdir)/Makefile;)
clean-default:
clean-default: clean-test
@-test -z "$(CLEAN)" || $(RM) $(CLEAN)
cleanall-default: clean-default
@ -141,6 +144,40 @@ ifneq ($(SPARSE),)
$(call ncmd,sparse,$(file));)
endif
##############################################################################
#
# Auto-testing infrastructure
#
clean-test:
test-default:
ifdef TEST_PROGS
TESTDEPS-$(CONFIG_DEBUG) += $(top_builddir)/src/util/memdebug.o
TESTDEPS += $(TESTDEPS-yes)
TESTS = $(wildcard $(srcdir)test-*)
$(TEST_PROGS): $(TESTDEPS)
$(call cmd,link,$@.o)
# We cannot use $$@.o in the rule above so ensure that all test programs are
# built before linking.
$(TESTS): $(addsuffix .o,$(TEST_PROGS)) $(TEST_PROGS)
@echo "*** $(notdir $@) ***"; \
$(call shellquote,$(SHELL)) $@ $(TEST_OPTS)
test-default: $(TESTS)
clean-test:
@rm -fr trash
CLEAN += $(TEST_PROGS) $(addsuffix .o,$(TEST_PROGS))
endif
.PHONY: $(TESTS)
.NOPARALLEL:
# sparse is architecture-neutral, which means that we need to tell it
# explicitly what architecture to check for. Fix this up for yours..
SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
@ -163,29 +200,41 @@ endif
# Recursion:
.PHONY: all-recursive install-recursive clean-recursive cleanall-recursive init-recursive check-recursive
RULES = all install clean cleanall init check test
RECRULES = $(addsuffix -recursive,$(RULES))
all-recursive install-recursive clean-recursive cleanall-recursive init-recursive check-recursive:
.PHONY: $(RECRULES)
# The -recursive rules decend all subdirs.
$(RECRULES):
ifdef SUBDIRS
@$(foreach subdir,$(sort $(SUBDIRS)), \
$(call ncmd,recmake,$(subdir),$(subst -recursive,,$@)) || exit 1;)
endif
all: all-recursive all-default all-local
install: install-recursive install-default install-local
check: check-recursive check-default check-local
clean: clean-recursive clean-default clean-local
# Setup the default sub commands dependency. First decend subdirs then do all
# the default stuff and finally do any local hooks.
recdeps = $1-recursive $1-default $1-local
all: $(call recdeps,all)
check: $(call recdeps,check)
cleanall: $(call recdeps,cleanall)
clean: $(call recdeps,clean)
init: $(call recdeps,init)
install: $(call recdeps,install)
test: $(call recdeps,test)
cleanall: cleanall-recursive cleanall-default
init: init-default init-recursive
all-local:
install-local:
clean-local:
check-local:
# Dummy rules for local hooks
$(addsuffix -local,$(RULES)):
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
# Shell quote;
# Result of this needs to be placed inside ''
# XXX: Placed here because Vim cannot highlight things right afterwards
shq = $(subst ','\'',$(1))
# This has surrounding ''
shellquote = '$(call shq,$(1))'
# vim:syntax=make

File diff suppressed because it is too large Load Diff

1060
Unicode/entities.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@ -2,18 +2,27 @@
echo
echo Generating entity table.
(
cat entities.lnx | grep '^[ ]*{"' | sort >tmp
sed -n '/^[^#]/,$p' < entities.txt | while read line; do \
name=$(echo "$line" | cut -f 1); \
code=$(echo "$line" | cut -f 3); \
desc=$(echo "$line" | cut -f 4 | sed 's/# //'); \
test "$code" = "0x????" && continue
printf "\t{ %-12s %s }, /* %-46s */\n" \
"\"$name\"," "$code" "$desc"; \
done | LC_ALL=C sort > tmp
N=`cat tmp | wc -l`
echo '/* Automatically generated by gen-ent */'
echo
echo 'struct entity { char *s; unicode_val_T c; } entities ['`expr $N + 1`'] = {'
cat tmp
echo ' {NULL, 0}'
echo '};'
echo
echo '#define N_ENTITIES' $N
) > ../src/intl/entity.inc
cat > ../src/intl/entity.inc <<EOF
/* Automatically generated by gen-ent */
struct entity { char *s; unicode_val_T c; } entities [$(expr $N + 1)] = {
$(cat tmp)
{ NULL, 0 }
};
#define N_ENTITIES $N
EOF
rm -f tmp
echo Done.
echo

View File

@ -496,6 +496,55 @@ if test "$CONFIG_WIN32" = yes; then
EL_CONFIG_WIN32
fi
dnl ===================================================================
dnl Check for SEE (Simple Ecmascript Engine)
dnl ===================================================================
AC_ARG_WITH(see, [ --with-see enable Simple Ecmascript Engine (SEE) support],
[ if test "x$withval" != xno; then enable_see=yes; fi ])
# The following is probably bad, ugly and so on. Stolen from Guile's (1.4)
# SEE_FLAGS but I really don't want to require people to have Guile in order
# to compile CVS. Also, the macro seems to be really stupid regarding searching
# for Guile in $PATH etc. --pasky
AC_MSG_CHECKING([for SEE])
if test "$enable_see" = "yes"; then
AC_MSG_RESULT(yes);
## Based on the SEE_FLAGS macro.
if test -d "$withval"; then
SEE_PATH="$withval:$PATH"
else
SEE_PATH="$PATH"
fi
AC_PATH_PROG(SEE_CONFIG, libsee-config, no, $SEE_PATH)
## First, let's just see if we can find Guile at all.
if test "$SEE_CONFIG" != no; then
cf_result="yes";
SEE_LIBS="`$SEE_CONFIG --libs`"
SEE_CFLAGS="`$SEE_CONFIG --cppflags`"
LIBS="$SEE_LIBS $LIBS"
CPPFLAGS="$CPPFLAGS $SEE_CFLAGS"
EL_CONFIG(CONFIG_SEE, [SEE])
AC_SUBST(SEE_CFLAGS)
AC_SUBST(CONFIG_SEE)
disable_spidermonkey=yes
else
if test -n "$withval" && test "x$withval" != xno; then
AC_MSG_ERROR([SEE not found])
else
AC_MSG_WARN([SEE support disabled])
fi
fi
else
AC_MSG_RESULT(no);
fi
dnl ===================================================================
dnl Check for SpiderMonkey, optional even if installed.
dnl ===================================================================
@ -550,7 +599,7 @@ fi
AC_SUBST(CONFIG_SPIDERMONKEY)
EL_CONFIG_DEPENDS(CONFIG_ECMASCRIPT, [CONFIG_SPIDERMONKEY], [ECMAScript (JavaScript)])
EL_CONFIG_DEPENDS(CONFIG_ECMASCRIPT, [CONFIG_SEE CONFIG_SPIDERMONKEY], [ECMAScript (JavaScript)])
dnl ===================================================================

View File

@ -934,8 +934,6 @@ B<dia> <I<dialect>> <I<URL>> (or current url)
Dialects: I<redneck>, I<jive>, I<cockney>, I<fudd>, I<bork>, I<moron>, I<piglatin>, or I<hacker>
=back
=cut
############################################################################
# the Dialectizer (dia <dialect> <url>)
@ -1070,6 +1068,8 @@ using the search engine defined by the 'search' configuration option if
}
=back
=head1 FOLLOW URL HOOK
@ -1081,8 +1081,6 @@ I<Developer's usage>: The function I<follow_url_hook> is called when the hook
is triggered, taking the target URL as its only argument. It returns the final
target URL.
=back
=cut
################################################################################
### follow_url_hook ############################################################
@ -1133,6 +1131,8 @@ Translates any I<nntp:> or I<news:> URLs to Google Groups HTTP URLs.
}
=back
=head1 PRE FORMAT HTML HOOK
@ -1151,8 +1151,6 @@ I<Developer's usage>: The function I<pre_format_html_hook> is called when the
hook is triggered, taking the document's URL and the HTML source as its two
arguments. It returns the rewritten HTML code.
=back
=cut
################################################################################
### pre_format_html_hook #######################################################
@ -1242,6 +1240,8 @@ content-type:text/html.
}
=back
=head1 PROXY FOR HOOK
@ -1256,8 +1256,6 @@ I<Developer's usage>: The function I<proxy_for_hook> is called when the hook is
triggered, taking the target URL as its only argument. It returns the proxy
URL, empty string to use no proxy or I<undef> to use the default proxy URL.
=back
=cut
################################################################################
### proxy_for_hook #############################################################
@ -1281,6 +1279,8 @@ Prevents proxy usage for local files and C<http://localhost>.
}
=back
=head1 QUIT HOOK
@ -1294,8 +1294,6 @@ I<Developer's usage>: The function I<quit_hook> is called when the hook is
triggered, taking no arguments nor returning anything. ('cause, you know, what
would be the point?)
=back
=cut
################################################################################
### quit_hook ##################################################################
@ -1367,6 +1365,8 @@ A few words of wisdom from ELinks the Sage.
}
=back
=head1 SEE ALSO

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) \
@ -48,77 +49,51 @@ ELINKS = $(top_builddir)/src/elinks
KBDBIND = $(top_srcdir)/src/config/kbdbind.c
FEATURES = $(top_srcdir)/features.conf
### Locale env vars to override system one to ensure commands
# using elinks binary will generate texts in english
#
LOCALES = LC_ALL=C LANGUAGE=en
### 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.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 +110,40 @@ 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)
$(MAKE_ELINKS_MANPAGE) $@ $(ELINKS) $(HELP2DOC) > $@
$(TXT_DIR)/elinks.1.%.txt: $(MAKE_ELINKS_MANPAGE) $(ELINKS) $(HELP2DOC) Makefile
$(LOCALES) $(MAKE_ELINKS_MANPAGE) $@ $(ELINKS) $(HELP2DOC) > $@
$(TXT_DIR)/elinkskeys.5.%.txt: $(MAKE_ELINKSKEYS_MANPAGE) doc-dirs $(KBDBIND)
$(MAKE_ELINKSKEYS_MANPAGE) $@ $(KBDBIND) > $@
$(TXT_DIR)/elinkskeys.5.%.txt: $(MAKE_ELINKSKEYS_MANPAGE) $(KBDBIND) Makefile
$(LOCALES) $(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 $@
sed 's/^\.TH "ELINKS" 1 .*/.TH "ELINKS" 1 "The ELinks text-browser" "$(shell date -I)" "The ELinks text-browser"/' \
< $(MAN_DIR)/man1/elinks.1 > $@
rm $(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 $@
sed 's/^\.TH "ELINKSKEYS" 5 .*/.TH "ELINKSKEYS" 5 "ELinks keybindings" "$(shell date -I)" "ELinks keybindings"/' \
< $@.tmp > $@
rm $@.tmp
$(MAN_DIR)/man5/elinks.conf.5: doc-dirs $(ELINKS)
$(HELP2DOC) --elinks=$(ELINKS) --elinksconf > $@
$(MAN_DIR)/man5/elinks.conf.5: $(ELINKS) $(HELP2DOC) Makefile
$(LOCALES) $(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 +153,39 @@ 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
#
DOM_API = \
$(top_srcdir)/src/dom/scanner.h \
$(top_srcdir)/src/dom/stack.h \
$(top_srcdir)/src/dom/sgml/parser.h
$(HTML_DIR)/api/dom.html: $(DOM_API)
$(CODE2DOC) $(DOM_API) | $(ASCIIDOC) -f code2doc.conf -b xhtml11 -d book -o $@ -n -
include $(top_srcdir)/Makefile.lib

View File

@ -220,6 +220,3 @@ in the future. So far, we have had no reports from our users that anyone wants
to switch their bookmarks format frequently, so this is not too high on our
TODO list. So be sure to tell us if you would like this process to be
simplified rather sooner than later.
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

55
doc/code2doc.conf Normal file
View File

@ -0,0 +1,55 @@
[specialwords]
emphasizedwords=\bAsciiDoc\b
monospacedwords=\basciidoc\(1\)
[id-inlinemacro]
<a id="{0}" href="#{0}">{0}</a>
[enum-inlinemacro]
<a id="{target}">enum {target}: {0}</a>
[func-inlinemacro]
<a id="{target}">{target}(): {0}</a>
[struct-inlinemacro]
<a id="{target}">struct {target}: {0}</a>
[macro-inlinemacro]
<a id="{target}">struct {target}: {0}</a>
[typedef-inlinemacro]
<a id="{target}">typedef {target}: {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>

View File

@ -120,6 +120,3 @@ that there are no SpiderMonkey references outside of
ECMAScript backend, go ahead - you will just need to write an autoconf
detection for it and tie it to `src/ecmascript/ecmascript.c`, which should be
easy. We await your patches eagerly.
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

View File

@ -99,6 +99,3 @@ Also, perhaps wider scale of commands should be implemented in ex-mode. The
code is extremely flexible and it is very trivial to make another ex-mode
command handler, it's just that no one has done it yet ;-). Also, more actions
should be able to take arguments.
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

View File

@ -101,14 +101,6 @@ One mebibyte 1 MiB = 2^20 B = 1 048 576 B
-------------------------------------------------------------------------------
[[Christmas]]
Why are stable releases made at Christmas?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
It is suspected that this yearly present has become a tradition because pasky
worships the Christmas spirit. ;-)
[[get-256-colours]]
How can I get 256 colors?
~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -150,7 +142,3 @@ The new ELinks versions (from 0.9.0 on) send:
You should therefore check against something like /^ELinks[\/ ]/, since more
fields can be added inside the parenthesis in subsequent versions. Note that
users can change their User-Agent through the options system.
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

View File

@ -31,8 +31,3 @@ pizza, some close location of yourself recommended), we accept drinks, nice
books, CDs with interesting things, computer equipment and accessories, PDAs,
pens + pencils + erasers, and last but not least money. Contact the maintainer,
he'll split the stuff properly amongst himself and other developers >:).
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

View File

@ -5,8 +5,6 @@ Welcome, mere mortal, to the realm of evil unindented code, heaps of one or
two-letter variables, seas of gotos accompanied with 30-letters labels in Czech
language with absolutely no meaning, welcome to the realm of ELinks code!
[We're going to extend this file slowly, basing on daily practice ;]
Don't take this file as a law. We may or may not be right in these issues.
Motto: I didn't expect someone to look at the source, so it's unreadable.
@ -620,6 +618,22 @@ typedef int (some_func_T)(void *);
typedef long long our_long_T;
-------------------------------------------------------------------------------
Please use mode_t and S_I???? macros instead of numeric modes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.Use:
-------------------------------------------------------------------------------
mode_t mode = S_IRWXU | S_IRGRP | S_IROTH;
-------------------------------------------------------------------------------
.Instead of:
-------------------------------------------------------------------------------
int mode = 0744;
-------------------------------------------------------------------------------
Note that S_IREAD, S_IWRITE and S_IEXEC are obsolete, you should use S_IRUSR,
S_IWUSR, S_IXUSR instead.
Patches
~~~~~~~
@ -681,6 +695,3 @@ to compile or execute in one of these modes, then rework it.
Happy hacking!
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

View File

@ -74,6 +74,3 @@ include::ecmascript.txt[]
include::txt/import-features.conf.txt[]
endif::installation-webpage[]
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

View File

@ -359,7 +359,3 @@ everything is marked TODO!
- Insert mode in text-input form-fields.
- Menu searching.
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

View File

@ -559,6 +559,3 @@ More ideas
- More things are possible, I'm sure. If you have an idea that requires
another hook or function, contact me (Peter Wang) and I'll see what I can
do.
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

View File

@ -124,6 +124,3 @@ audio/mpeg; xmms '%s'; test=test -n "$DISPLAY";
application/pdf; xpdf '%s'; test=test -n "$DISPLAY";
application/postscript; ps2ascii %s ; copiousoutput
-------------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

View File

@ -17,7 +17,7 @@
.el .ne 3
.IP "\\$1" \\$2
..
.TH "ELINKS" 1 "" "" ""
.TH "ELINKS" 1 "The ELinks text-browser" "2006-01-10" "The ELinks text-browser"
.SH NAME
elinks \- lynx-like alternative character mode WWW browser
.SH "SYNOPSIS"

View File

@ -1,6 +1,6 @@
.\" elinks.conf.5
.\"
.\" Generated by help2doc (Revision: 1.19) on 09 August 05 using output from ELinks version 0.11.CVS.
.\" Generated by help2doc (Revision: 1.19) on 2006-01-10 using output from ELinks version 0.12.GIT.
.\"
.\" Copyleft (c) 2002-2004 The ELinks project
.\"
@ -8,7 +8,7 @@
.\" General Public License. <www.gnu.org/licenses/gpl.html>
.\"
.\" Process this file with groff -man -Tascii elinks.conf.5
.TH ELINKS.CONF 5 \"09 August 05\"
.TH ELINKS.CONF 5 "ELinks configuration file" "2006-01-10" "ELinks configuration file"
.SH NAME
elinks.conf \- ELinks configuration file
@ -50,7 +50,7 @@ set document.browse.margin_width = 3
# Default document codepage.
set document.codepage.assume = "ISO-8859-1"
# User defined protocol handlers
set protocol.user.mailto.unix = "mutt %h -s \"%s\""
set protocol.user.mailto.unix = "mutt %h -s \e\*(lq%s\e\*(rq"
.SH OPTIONS
.SS Bookmarks (bookmarks)
@ -313,8 +313,8 @@ are always inserted into a selected text field.
\f3document.browse.forms.editor\f2 <str>\f1 (default: "")
Path to the executable that ELinks should launch when the user
requests to edit a textarea with an external editor.
.TP
\f3variable\f2 $EDITOR.\f1 (variable $EDITOR. If $EDITOR is empty or not set, ELinks will then)
If this is blank, ELinks will use the value of the environmental
variable $EDITOR. If $EDITOR is empty or not set, ELinks will then
default to "vi".
.TP
\f3document.browse.forms.show_formhist\f2 [0|1]\f1 (default: 0)
@ -459,6 +459,9 @@ The TABINDEX attribute in HTML elements specifies the order
in which links should receive focus when using the keyboard
to navigating the document.
.TP
\f3document.browse.links.missing_fragment\f2 [0|1]\f1 (default: 1)
Open a message box when document has no tag with given id.
.TP
\f3document.browse.links.number_keys_select_link\f2 <num>\f1 (default: 1)
Number keys select links rather than specify command prefixes. This
is a tristate:
@ -675,11 +678,10 @@ Default directory color.
See document.browse.links.color_dirs option.
.TP
\f3document.colors.increase_contrast\f2 [0|1]\f1 (default: 1)
Setting this option to 0 will increase the contrast
between the foreground and background colors to ensure
readability. For example it disallows dark colors on a
black background. Note, this is different from ensuring
the contrast with the ensure_contrast option.
Increase the contrast between the foreground and background colors
to ensure readability. For example it disallows dark colors on a
black background. Note, this is different from ensuring the contrast
with the ensure_contrast option.
.TP
\f3document.colors.ensure_contrast\f2 [0|1]\f1 (default: 1)
Makes sure that the back- and foreground color are never equal.
@ -877,6 +879,7 @@ A rule for passing URI to an external command.
The format is:
%c in the string means the current URL
%% in the string means '%'
Do _not_ put single- or double-quotes around %c.
.SS ECMAScript (ecmascript)
ECMAScript options.
.TP
@ -886,6 +889,10 @@ Whether to run those scripts inside of documents.
\f3ecmascript.error_reporting\f2 [0|1]\f1 (default: 0)
Open a message box when a script reports an error.
.TP
\f3ecmascript.ignore_noscript\f2 [0|1]\f1 (default: 0)
Whether to ignore content enclosed by the <noscript> tag
when ECMAScript is enabled.
.TP
\f3ecmascript.max_exec_time\f2 <num>\f1 (default: 5)
Maximum execution time in seconds for a script.
.PD
@ -1045,6 +1052,13 @@ What IP address to report to the tracker. If set to ""
no IP address will be sent and the tracker will automatically
determine an appropriate IP address.
.TP
\f3protocol.bittorrent.tracker.key\f2 <str>\f1 (default: "")
An additional identification that is not shared with any users.
It is intended to allow a client to prove their identity should
their IP address change. It is an optional parameter, but some
trackers require this parameter. If set to "" no user key will
be sent to the tracker.
.TP
\f3protocol.bittorrent.tracker.numwant\f2 <num>\f1 (default: 50)
The maximum number of peers to request from the tracker.
Set to 0 to use the server default.
@ -1337,7 +1351,7 @@ disable use of the default template rewrite rule.
Enable dumb prefixes - simple URI abbreviations which can
be written to the Goto URL dialog instead of actual URIs - i.e.
if you write 'elinks' there, you are directed to
http://elinks.or.cz/.
http://elinks.cz/.
.TP
\f3protocol.rewrite.enable-smart\f2 [0|1]\f1 (default: 1)
Enable smart prefixes - URI templates triggered by writing
@ -2139,6 +2153,9 @@ on the command line or when requested by the goto-url-home action.
Set to "" if the environment variable WWW_HOME should be used
as homepage URI instead.
.TP
\f3ui.sessions.keep_session_active\f2 [0|1]\f1 (default: 0)
Keep the session active even if the last terminal exits.
.TP
\f3ui.sessions.snapshot\f2 [0|1]\f1 (default: 0)
Automatically save a snapshot of all tabs periodically.
This will periodically bookmark the tabs of each terminal in a separate folder
@ -2225,7 +2242,7 @@ in an xterm-like terminal. This way the document's title is
shown on the window titlebar.
.SH "DOCUMENT INFO"
.PP
Generated by help2doc (Revision: 1.19) on 09 August 05 using output from ELinks version 0.11.CVS.
Generated by help2doc (Revision: 1.19) on 2006-01-10 using output from ELinks version 0.12.GIT.
help2doc is distributed with ELinks under the terms of the GPL.
.SH "SEE ALSO"
.BR elinks (1),

View File

@ -17,7 +17,7 @@
.el .ne 3
.IP "\\$1" \\$2
..
.TH "ELINKSKEYS" 5 "" "" ""
.TH "ELINKSKEYS" 5 "ELinks keybindings" "2006-01-10" "ELinks keybindings"
.SH NAME
elinkskeys \- keybindings for ELinks
.SH "SYNOPSIS"
@ -258,6 +258,10 @@ Follow the current link, forcing reload of the target\&.
link\-menu
Open the link context menu\&.
.TP
link\-form\-menu
Open the form fields menu\&.
.TP
lua\-console
Open a Lua console\&.

View File

@ -84,6 +84,3 @@ did not quit your ELinks _completely_ --- if you run multiple ELinks
instances under a single user on a single system, they "join" together and
you must quit (or kill) them all to get rid of the damn thing. But that's a
different story.
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

View File

@ -178,6 +178,3 @@ Just enter set mime.type.class.name = "handler", replacing class with the
class for the mime type, name with the specific name within that class, and
handler with the name for the handler you want to assign to the MIME type.
E.g. you may want to have set mime.type.image.jpeg = "image_viewer".
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

View File

@ -83,6 +83,3 @@ example, by running:
new tabs containing `slashdot.org`, `freshmeat.net` and a Google search of elinks
will be opened.
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

View File

@ -90,6 +90,3 @@ Whow ! Around 200kb :)
- it disables fastfind feature, reducing performance, but also reducing a lot
memory usage, and a bit the executable size.
==============================================================================
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

View File

@ -110,6 +110,3 @@ bookmark therein the currently displayed document of each tab:
- As a mean of crash protection, tabs can periodically be saved so that it is
later possible to reconstruct opened tabs. In case of a clean shutdown
periodically saved tabs will be removed.
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

View File

@ -163,6 +163,3 @@ GNU Screen is VT100-compatible, so select 'VT 100 frames'. GNU Screen also
supports colors just fine, so select '16 colors', or, if you are running Screen
within a terminal emulator that supports 256 colors and you have compiled both
Screen and ELinks to support it, choose '256 colors'.
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

112
doc/tools/code2doc Executable file
View File

@ -0,0 +1,112 @@
#!/usr/bin/perl -w
use strict;
use warnings;
use diagnostics;
use Getopt::Std;
my $HELP = "Usage: $0 [FILE]...
Parses [FILE], outputing the result to stdout.";
sub usage {
print "@_\n";
exit;
}
our($opt_h, $opt_v, $title, $body, $indent, $idpath, $inblock);
getopts("hv") or usage($HELP);
$opt_v and usage("Copyleft (c) 2006, Russ Rowan (See `COPYING')");
usage($HELP) if $opt_h or @ARGV < 1;
sub put_section {
if ($title) {
print "\n$title\n";
$_ = $title;
s/[^-]/-/g;
print "$_\n" if not $indent;
}
if ($body) {
$_ = $body;
s/#newline#/$indent/g;
print "$_\n";
}
$title = $body = undef;
}
$idpath = $title = $body = "";
while (<>)
{
my $end = s/\s*\*+\//\n/ ? 'yes' : undef;
if ($end and /[^=]*[\s*](\w+)[\s:,;].*\/\*:\s*(.*)/) {
# Implicit id for enum values and struct members.
print "\nid:[$idpath$1]::\n\t$2\n";
} elsif ($inblock) {
# Redo the indentation, preserve empty lines.
s/^(\s|\*)*//;
s/^$/\n/;
$body .= "#newline#" . $_;
} elsif (s/\s*\/\*\*+\s*(.*)/$1/) {
# Found magic header; flush, record title and set indentation.
put_section;
$title = "$1";
$indent = /::/ ? "\t" : "";
} else {
next if not ($title or $body) or /^\s$/;
my $orig_title = $title;
if (not /^#define\s/) {
while (not /(struct|enum|typedef|[^=])*[\s*](\w+).*[\[:,;{]/) {
$_ .= <>;
}
}
if (/struct\s+(\w+)\s*{/) {
$title = "struct:$1" . "[$title]";
$idpath = "$1.";
} elsif (/enum\s+(\w+)\s*{/) {
$title = "enum:$1" . "[$title]";
$idpath = "";
} elsif (/#define\s+(\w+)[(]/) {
$title = "func:$1" . "[$title]";
$idpath = "";
} elsif (/#define\s+(\w+)/) {
$title = "macro:$1" . "[$title]";
$idpath = "";
} else {
if (/typedef/) {
if (/.*\(\*(\w+)\)\(/) {
$title = "typedef:$1" . "[$title]";
} elsif (/typedef.*\s(\w+);/) {
$title = "typedef:$1" . "[$title]";
}
$idpath = "";
} else {
if (/.*[\s*](\w+)\(/) {
$title = "func:$1" . "[$title]";
$idpath = "";
} elsif (/.*\(\*(\w+)\)\(/) {
$body = "#newline#" . $title if not $body;
$title = "id:[$idpath$1]::";
$indent = "\t";
} elsif (/[^=]*[\s*](\w+)[\[\s,:;]/) {
$body = "#newline#" . $title if not $body;
$title = "id:[$idpath$1]::";
$indent = "\t";
}
}
}
put_section if $orig_title ne $title;
next;
}
$inblock = $end ? undef : 'yes';
}

View File

@ -27,6 +27,7 @@ END_OF_USAGE
# Option handling {{{1
command=
filter=cat
prev_option=
for option
@ -41,10 +42,12 @@ do
case "$option" in
--cmdoptions)
command="$elinks -long-help"
filter="sed 0,/^Options:/d"
backend="cmdoptions"
;;
--elinksconf)
command="$elinks -config-help"
filter="sed 0,/^Configuration/d"
backend="elinksconf"
;;
-)
@ -64,7 +67,7 @@ then
usage "No backend defined"
fi
date_string=`date +"%d %B %y"`
date_string=`date -I`
script_version=`echo "\\$Revision: 1.19 $" | sed -e 's/\\$\(.*\) \\$/\1/'`
elinks_version="`$elinks -version | head -n 1 | sed -e 's/ELinks \([0-9][^ ]*\).*/\1/'`"
script_info="Generated by `basename $0` ($script_version) on $date_string"
@ -168,7 +171,7 @@ print_elinksconf_header()
.\" General Public License. <www.gnu.org/licenses/gpl.html>
.\"
.\" Process this file with groff -man -Tascii elinks.conf.5
.TH ELINKS.CONF 5 \"$date_string\"
.TH ELINKS.CONF 5 "ELinks configuration file" "$date_string" "ELinks configuration file"
.SH NAME
elinks.conf \- ELinks configuration file
@ -210,7 +213,7 @@ set document.browse.margin_width = 3
# Default document codepage.
set document.codepage.assume = "ISO-8859-1"
# User defined protocol handlers
set protocol.user.mailto.unix = "mutt %h -s \"%s\""
set protocol.user.mailto.unix = "mutt %h -s \e\*(lq%s\e\*(rq"
.SH OPTIONS
__END__
@ -227,7 +230,6 @@ print_elinksconf_footer()
echo "$dist_info"
echo ".SH \"SEE ALSO\""
echo ".BR elinks (1),"
echo ".BR elinksmanual (1),"
echo ".BR elinkskeys (5)"
}
@ -285,7 +287,7 @@ use_log=
$print_header
$command | while read line
$command | $filter | while read line
do
if test -n "$parse_description"
then
@ -323,7 +325,7 @@ do
case "$line" in
Features:*)
;;
[A-Z]*:*[a-z]*)
[A-Z]*:" ("*[a-z]*)
parse_description=1
title="`echo $line | sed -e 's/\([A-Z]*\):.*/\1/'`"
path="`echo $line | sed -e 's/.*: (\([a-z_].*\))/\1/'`"

View File

@ -87,6 +87,3 @@ advanced CVSweb and Debian package database URI prefixes implemented in the
sample Lua hooks file. The one disadvantage to this is that you must have Lua
scripting enabled in order to make use of it, and many users don't have Lua
installed.
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

View File

@ -11,6 +11,8 @@ MSGMERGE = msgmerge
# xgettext)
POTFILES_ABS_LIST = potfiles.list
POTFILES_REL = $(shell find $(top_srcdir)/src/ -name '*.[ch]' -o -name options.inc -o -name 'actions-*.inc' | sort)
quiet_cmd_gmsgfmt = ' [$(PO_COLOR)GMSGFMT$(END_COLOR)] $(RELPATH)$(@)'
cmd_gmsgfmt = rm -f -- "$@" && $(GMSGFMT) --statistics -o "$@" -- "$<"
@ -45,7 +47,7 @@ all-local: $(CATALOGS)
# This pulls in _all_ .c and .h files in the src directory. Even files that has
# not been added to the git repo. Beware of junk entries!
$(srcdir)$(POTFILES_ABS_LIST):
$(srcdir)$(POTFILES_ABS_LIST): $(POTFILES_REL)
@( cd $(top_srcdir); \
find src/ -type f -name '*.[ch]' -o -name options.inc -o -name 'actions-*.inc' | sort ) \
> $(srcdir)$(POTFILES_ABS_LIST)
@ -67,7 +69,7 @@ $(srcdir)$(PACKAGE).pot: $(srcdir)$(POTFILES_ABS_LIST)
# either <lang> or <lang>.po when calling make. Example: make update-po PO=is
update-po: Makefile $(srcdir)$(PACKAGE).pot
@test -n "$(srcdir)" && cd $(srcdir)
@test -z "$(srcdir)" || cd $(srcdir)
@$(foreach lang,$(basename $(if $(strip $(PO)),$(PO),$(GMOFILES))), \
echo -n "$(lang): "; \
if $(MSGMERGE) $(srcdir)$(lang).po $(srcdir)$(PACKAGE).pot -o $(lang).new.po; then \

144
po/fr.po
View File

@ -1,13 +1,13 @@
# French ELinks translation.
# Fabrice Haberer-Proust <fric@gmx.li>
# Laurent Monin <zas@norz.org>, 2001 - 2005
# Laurent Monin <zas@norz.org>, 2001 - 2006
#
msgid ""
msgstr ""
"Project-Id-Version: ELinks 0.11.GIT\n"
"Project-Id-Version: ELinks 0.12.GIT\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2006-01-01 17:49+0100\n"
"PO-Revision-Date: 2006-01-01 17:50+0100\n"
"POT-Creation-Date: 2006-01-10 23:00+0100\n"
"PO-Revision-Date: 2006-01-10 23:01+0100\n"
"Last-Translator: Laurent Monin <zas@norz.org>\n"
"Language-Team: French <zas@norz.org>\n"
"MIME-Version: 1.0\n"
@ -15,21 +15,21 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n>1;\n"
#: src/bfu/hierbox.c:329
#: src/bfu/hierbox.c:338
msgid "Close"
msgstr "Fermer"
#. | MSGBOX_SCROLLABLE
#: src/bfu/hierbox.c:425 src/bfu/hierbox.c:434 src/dialogs/document.c:43
#: src/bfu/hierbox.c:434 src/bfu/hierbox.c:443 src/dialogs/document.c:43
#: src/dialogs/document.c:240
msgid "Info"
msgstr "Info"
#: src/bfu/hierbox.c:426
#: src/bfu/hierbox.c:435
msgid "Press space to expand this folder."
msgstr "Pressez espace pour déployer le dossier."
#: src/bfu/hierbox.c:437 src/bfu/inpfield.c:254 src/bfu/msgbox.c:172
#: src/bfu/hierbox.c:446 src/bfu/inpfield.c:254 src/bfu/msgbox.c:172
#: src/bfu/msgbox.c:189 src/config/dialogs.c:57 src/config/dialogs.c:391
#: src/cookies/dialogs.c:354 src/dialogs/edit.c:97 src/dialogs/info.c:133
#: src/dialogs/options.c:210 src/dialogs/options.c:290 src/mime/dialogs.c:129
@ -40,57 +40,57 @@ msgid "~OK"
msgstr "~OK"
#. cant_delete_item
#: src/bfu/hierbox.c:548
#: src/bfu/hierbox.c:557
#, c-format
msgid "Sorry, but the item \"%s\" cannot be deleted."
msgstr "Désolé, mais l'item \"%s\" ne peut être supprimé."
#. cant_delete_used_item
#: src/bfu/hierbox.c:551
#: src/bfu/hierbox.c:560
#, c-format
msgid "Sorry, but the item \"%s\" is being used by something else."
msgstr "Désolé, mais l'item \"%s\" est actuellement utilisé ailleurs."
#. cant_delete_folder
#: src/bfu/hierbox.c:554 src/bookmarks/dialogs.c:119
#: src/bfu/hierbox.c:563 src/bookmarks/dialogs.c:119
#, c-format
msgid "Sorry, but the folder \"%s\" cannot be deleted."
msgstr "Désolé, mais le dossier \"%s\" ne peut être supprimé."
#. cant_delete_used_folder
#: src/bfu/hierbox.c:557 src/bookmarks/dialogs.c:121
#: src/bfu/hierbox.c:566 src/bookmarks/dialogs.c:121
#, c-format
msgid "Sorry, but the folder \"%s\" is being used by something else."
msgstr "Désolé, mais le dossier \"%s\" est actuellement utilisé ailleurs."
#. delete_marked_items_title
#: src/bfu/hierbox.c:560
#: src/bfu/hierbox.c:569
msgid "Delete marked items"
msgstr "Supprimer les items marqués"
#. delete_marked_items
#: src/bfu/hierbox.c:563
#: src/bfu/hierbox.c:572
msgid "Delete marked items?"
msgstr "Supprimer les items marqués ?"
#. delete_folder_title
#: src/bfu/hierbox.c:566 src/bookmarks/dialogs.c:127
#: src/bfu/hierbox.c:575 src/bookmarks/dialogs.c:127
msgid "Delete folder"
msgstr "Supprimer un dossier"
#. delete_folder
#: src/bfu/hierbox.c:569
#: src/bfu/hierbox.c:578
#, c-format
msgid "Delete the folder \"%s\" and its content?"
msgstr "Supprimer le dossier \"%s\" et son contenu ?"
#. delete_item_title
#: src/bfu/hierbox.c:572
#: src/bfu/hierbox.c:581
msgid "Delete item"
msgstr "Supprimer un item"
#. delete_item
#: src/bfu/hierbox.c:575
#: src/bfu/hierbox.c:584
#, c-format
msgid ""
"Delete \"%s\"?\n"
@ -102,45 +102,45 @@ msgstr ""
"%s"
#. clear_all_items_title
#: src/bfu/hierbox.c:578
#: src/bfu/hierbox.c:587
msgid "Clear all items"
msgstr "Effacer tous les items"
#. clear_all_items
#: src/bfu/hierbox.c:581
#: src/bfu/hierbox.c:590
msgid "Do you really want to remove all items?"
msgstr "Êtes-vous sûr de vouloir effacer tous les items ?"
#: src/bfu/hierbox.c:638
#: src/bfu/hierbox.c:647
msgid "Delete error"
msgstr "Erreur de suppression"
#: src/bfu/hierbox.c:741 src/bfu/hierbox.c:770 src/bfu/hierbox.c:783
#: src/bfu/hierbox.c:848 src/config/dialogs.c:832 src/dialogs/menu.c:126
#: src/bfu/hierbox.c:750 src/bfu/hierbox.c:779 src/bfu/hierbox.c:792
#: src/bfu/hierbox.c:857 src/config/dialogs.c:832 src/dialogs/menu.c:126
#: src/formhist/formhist.c:418 src/mime/dialogs.c:69 src/session/task.c:272
#: src/terminal/tab.c:191 src/terminal/tab.c:227
msgid "~Yes"
msgstr "~Oui"
#: src/bfu/hierbox.c:742 src/bfu/hierbox.c:771 src/bfu/hierbox.c:784
#: src/bfu/hierbox.c:849 src/config/dialogs.c:833 src/dialogs/menu.c:127
#: src/bfu/hierbox.c:751 src/bfu/hierbox.c:780 src/bfu/hierbox.c:793
#: src/bfu/hierbox.c:858 src/config/dialogs.c:833 src/dialogs/menu.c:127
#: src/formhist/formhist.c:419 src/mime/dialogs.c:70 src/session/task.c:273
#: src/terminal/tab.c:192 src/terminal/tab.c:228
msgid "~No"
msgstr "~Non"
#: src/bfu/hierbox.c:917 src/bfu/hierbox.c:948 src/viewer/text/search.c:1013
#: src/bfu/hierbox.c:926 src/bfu/hierbox.c:957 src/viewer/text/search.c:1013
#: src/viewer/text/search.c:1021 src/viewer/text/search.c:1037
#: src/viewer/text/search.c:1612
msgid "Search"
msgstr "Chercher"
#: src/bfu/hierbox.c:919 src/viewer/text/search.c:1014
#: src/bfu/hierbox.c:928 src/viewer/text/search.c:1014
#, c-format
msgid "Search string '%s' not found"
msgstr "Chaîne recherchée '%s' introuvable"
#: src/bfu/hierbox.c:948 src/config/dialogs.c:168 src/config/dialogs.c:357
#: src/bfu/hierbox.c:957 src/config/dialogs.c:168 src/config/dialogs.c:357
#: src/config/dialogs.c:504 src/cookies/dialogs.c:34 src/cookies/dialogs.c:348
#: src/dialogs/edit.c:91 src/dialogs/edit.c:93 src/scripting/lua/core.c:373
#: src/scripting/lua/core.c:374 src/scripting/lua/core.c:454
@ -173,7 +173,7 @@ msgstr "Cha
#: src/dialogs/options.c:291 src/mime/dialogs.c:130
#: src/protocol/auth/dialogs.c:111 src/protocol/bittorrent/dialogs.c:801
#: src/scripting/lua/core.c:378 src/scripting/lua/core.c:458
#: src/session/download.c:544 src/session/download.c:1121
#: src/session/download.c:544 src/session/download.c:1143
#: src/viewer/text/search.c:1594
msgid "~Cancel"
msgstr "~Annuler"
@ -187,7 +187,7 @@ msgid "Digital clock in the status bar."
msgstr "Horloge digitale dans la barre de status."
#: src/bfu/leds.c:77 src/bfu/leds.c:94 src/config/options.inc:1118
#: src/config/options.inc:1125 src/ecmascript/ecmascript.c:40
#: src/config/options.inc:1125 src/ecmascript/ecmascript.c:39
#: src/globhist/globhist.c:63 src/mime/backend/mailcap.c:93
#: src/mime/backend/mimetypes.c:52 src/network/ssl/ssl.c:80
msgid "Enable"
@ -1837,7 +1837,7 @@ msgstr "Impossible d'ajouter une option ici."
#: src/config/dialogs.c:531 src/config/dialogs.c:943 src/cookies/dialogs.c:424
#: src/dialogs/options.c:212 src/formhist/dialogs.c:213
#: src/protocol/bittorrent/dialogs.c:788 src/session/download.c:1105
#: src/protocol/bittorrent/dialogs.c:788 src/session/download.c:1127
msgid "Sa~ve"
msgstr "Enre~gistrer"
@ -2305,14 +2305,12 @@ msgstr "Editeur externe"
msgid ""
"Path to the executable that ELinks should launch when the user\n"
"requests to edit a textarea with an external editor.\n"
"\n"
"If this is blank, ELinks will use the value of the environmental\n"
"variable $EDITOR. If $EDITOR is empty or not set, ELinks will then\n"
"default to \"vi\"."
msgstr ""
"Chemin du programme qu'ELinks doit lancer quand l'utilisateur\n"
"demande à éditer un champ de texte avec un éditeur externe.\n"
"\n"
"Si vide, ELinks utilisera la valeur de la variable d'environnement\n"
"$EDITOR. Si $EDITOR est vide ou non configurée, ELinks utilisera\n"
"\"vi\" par défaut."
@ -3357,15 +3355,13 @@ msgid ""
"The format is:\n"
"%c in the string means the current URL\n"
"%% in the string means '%'\n"
"\n"
"Do _not_ put single- or double-quotes around %c."
msgstr ""
"Règle de passage d'URI à une commande externe.\n"
"Le format est:\n"
"%c dans la chaîne signifie URL courante\n"
"%% dans la chaîne signifie '%'\n"
"\n"
"Ne mettez pas de simples ou doubles quotes autour de %c."
"Ne mettez pas de simples ou doubles guillemets autour de %c."
#. Keep options in alphabetical order.
#: src/config/options.inc:740
@ -4674,7 +4670,7 @@ msgid ""
"\n"
"(C) 1999 - 2002 Mikulas Patocka\n"
"(C) 2001 - 2004 Petr Baudis\n"
"(C) 2002 - 2005 Jonas Fonseca\n"
"(C) 2002 - 2006 Jonas Fonseca\n"
"and others\n"
"\n"
"This program is free software; you can redistribute it and/or modify it "
@ -4685,7 +4681,7 @@ msgstr ""
"\n"
"(C) 1999 - 2002 Mikulas Patocka\n"
"(C) 2001 - 2004 Petr Baudis\n"
"(C) 2002 - 2005 Jonas Fonseca\n"
"(C) 2002 - 2006 Jonas Fonseca\n"
"et d'autres\n"
"\n"
"Ce programme est un logiciel libre; vous pouvez le redistribuer et/ou le "
@ -5362,31 +5358,31 @@ msgstr ""
"Laisser à \"\" pour utiliser le style initial du document."
#. name:
#: src/ecmascript/ecmascript.c:36 src/ecmascript/ecmascript.c:201
#: src/ecmascript/ecmascript.c:35 src/ecmascript/ecmascript.c:137
msgid "ECMAScript"
msgstr "ECMAScript"
#: src/ecmascript/ecmascript.c:38
#: src/ecmascript/ecmascript.c:37
msgid "ECMAScript options."
msgstr "Options d'ECMAScript."
#: src/ecmascript/ecmascript.c:42
#: src/ecmascript/ecmascript.c:41
msgid "Whether to run those scripts inside of documents."
msgstr "Exécuter ou non ces scripts présents dans les documents."
#: src/ecmascript/ecmascript.c:44
#: src/ecmascript/ecmascript.c:43
msgid "Script error reporting"
msgstr "Rapport d'erreur de script"
#: src/ecmascript/ecmascript.c:46
#: src/ecmascript/ecmascript.c:45
msgid "Open a message box when a script reports an error."
msgstr "Ouvrir une boîte de message quand un script produit une erreur."
#: src/ecmascript/ecmascript.c:48
#: src/ecmascript/ecmascript.c:47
msgid "Ignore <noscript> content"
msgstr "Ignorer le contenu de <noscript>"
#: src/ecmascript/ecmascript.c:50
#: src/ecmascript/ecmascript.c:49
msgid ""
"Whether to ignore content enclosed by the <noscript> tag\n"
"when ECMAScript is enabled."
@ -5394,38 +5390,29 @@ msgstr ""
"Ignorer ou non le contenu du tag <noscript> quand ECMAScript\n"
"est actif."
#: src/ecmascript/ecmascript.c:53
#: src/ecmascript/ecmascript.c:52
msgid "Maximum execution time"
msgstr "Temps maximal d'exécution"
#: src/ecmascript/ecmascript.c:55
#: src/ecmascript/ecmascript.c:54
msgid "Maximum execution time in seconds for a script."
msgstr "Temps maximal pour l'exécution d'un script, en secondes."
#: src/ecmascript/ecmascript.c:57
#: src/ecmascript/ecmascript.c:56
msgid "Pop-up window blocking"
msgstr "Blocage des fenêtres Javascript (popups)"
#: src/ecmascript/ecmascript.c:59
#: src/ecmascript/ecmascript.c:58
msgid "Whether to disallow scripts to open new windows or tabs."
msgstr ""
"Interdire ou non l'ouverture de fenêtres ou d'onglets\n"
"par les scripts."
#: src/ecmascript/spidermonkey.c:92
#, c-format
msgid "A script embedded in the current document raised the following%s%s%s%s"
msgstr "Un script contenu dans le document courant a provoqué%s%s%s%s"
#: src/ecmascript/spidermonkey.c:108
msgid "JavaScript Error"
msgstr "Erreur Javascript"
#: src/ecmascript/spidermonkey.c:127
#: src/ecmascript/ecmascript.c:126
msgid "JavaScript Emergency"
msgstr "Alerte JavaScript"
#: src/ecmascript/spidermonkey.c:129
#: src/ecmascript/ecmascript.c:128
#, c-format
msgid ""
"A script embedded in the current document was running\n"
@ -5438,10 +5425,19 @@ msgstr ""
"qu'il y a un bogue dans ce script et que cela aurait pû\n"
"bloquer ELinks, l'exécution du script a donc été interrompue."
#: src/ecmascript/spidermonkey/window.c:286
#: src/ecmascript/see/window.c:242 src/ecmascript/spidermonkey/window.c:286
msgid "JavaScript Alert"
msgstr "Alerte JavaScript"
#: src/ecmascript/spidermonkey.c:162
#, c-format
msgid "A script embedded in the current document raised the following%s%s%s%s"
msgstr "Un script contenu dans le document courant a provoqué%s%s%s%s"
#: src/ecmascript/spidermonkey.c:178
msgid "JavaScript Error"
msgstr "Erreur Javascript"
#: src/formhist/dialogs.c:67
msgid "Forms are never saved for this URL."
msgstr "Les formulaires ne sont jamais sauvés pour cette URL."
@ -5983,12 +5979,12 @@ msgstr ""
"ici à la place de '.')."
#. name:
#: src/mime/backend/default.c:227
#: src/mime/backend/default.c:228
msgid "Option system"
msgstr "Système de configuration"
#. name:
#: src/mime/backend/mailcap.c:89 src/mime/backend/mailcap.c:668
#: src/mime/backend/mailcap.c:89 src/mime/backend/mailcap.c:674
msgid "Mailcap"
msgstr "Mailcap"
@ -7128,7 +7124,7 @@ msgstr "Que voulez-vous faire avec le fichier '%s' ?"
msgid "Information about the torrent"
msgstr "Informations sur le torrent"
#: src/protocol/bittorrent/dialogs.c:763 src/session/download.c:1017
#: src/protocol/bittorrent/dialogs.c:763 src/session/download.c:1039
msgid "What to do?"
msgstr "Que faire ?"
@ -7136,11 +7132,11 @@ msgstr "Que faire ?"
msgid "Down~load"
msgstr "Té~lécharger"
#: src/protocol/bittorrent/dialogs.c:791 src/session/download.c:1111
#: src/protocol/bittorrent/dialogs.c:791 src/session/download.c:1133
msgid "~Display"
msgstr "A~fficher"
#: src/protocol/bittorrent/dialogs.c:795 src/session/download.c:1115
#: src/protocol/bittorrent/dialogs.c:795 src/session/download.c:1137
msgid "Show ~header"
msgstr "~Montrer les en-têtes"
@ -7840,11 +7836,11 @@ msgid "Scripting"
msgstr "Scripting"
#: src/session/download.c:234 src/session/download.c:331
#: src/session/download.c:498 src/session/download.c:590
#: src/session/download.c:498 src/session/download.c:593
msgid "Download error"
msgstr "Erreur de téléchargement"
#: src/session/download.c:235 src/session/download.c:591
#: src/session/download.c:235 src/session/download.c:594
#, c-format
msgid ""
"Could not create file '%s':\n"
@ -7900,30 +7896,30 @@ msgstr "Ecraser le fichier ~original"
msgid "~Resume download of the original file"
msgstr "~Reprendre le téléchargement du fichier original"
#: src/session/download.c:1020
#: src/session/download.c:1042
msgid "Unknown type"
msgstr "Type inconnu"
#: src/session/download.c:1037
#: src/session/download.c:1059
#, c-format
msgid "What would you like to do with the file '%s' (type: %s%s%s)?"
msgstr "Que voulez-vous faire avec le fichier '%s' (type: %s%s%s) ?"
#: src/session/download.c:1067
#: src/session/download.c:1089
#, no-c-format
msgid "Program ('%' will be replaced by the filename)"
msgstr "Programme ('%' sera remplacé par le nom du fichier)"
#: src/session/download.c:1071
#: src/session/download.c:1093
msgid "Block the terminal"
msgstr "Bloquer le terminal"
#: src/session/download.c:1077
#: src/session/download.c:1099
#, c-format
msgid "The file will be opened with the program '%s'."
msgstr "Le fichier sera ouvert avec le programme '%s'."
#: src/session/download.c:1098
#: src/session/download.c:1120
msgid "~Open"
msgstr "~Ouvrir"

View File

@ -157,13 +157,15 @@ hierbox_ev_kbd(struct dialog_data *dlg_data)
selected = box->sel;
action_id = kbd_action(KEYMAP_MENU, ev, NULL);
if (action_id == ACT_MENU_SELECT) {
switch (action_id) {
case ACT_MENU_SELECT:
if (!selected) return EVENT_PROCESSED;
if (selected->type != BI_FOLDER)
return EVENT_NOT_PROCESSED;
selected->expanded = !selected->expanded;
break;
} else if (action_id == ACT_MENU_UNEXPAND) {
case ACT_MENU_UNEXPAND:
/* Recursively unexpand all folders */
if (!selected) return EVENT_PROCESSED;
@ -173,8 +175,9 @@ hierbox_ev_kbd(struct dialog_data *dlg_data)
* whole parent folder will be closed. */
if (list_empty(selected->child)
|| !selected->expanded) {
struct listbox_item *root = box->ops->get_root(selected);
struct listbox_item *root;
root = box->ops->get_root(selected);
if (root) {
listbox_sel(widget_data, root);
}
@ -182,23 +185,25 @@ hierbox_ev_kbd(struct dialog_data *dlg_data)
} else if (selected->type == BI_FOLDER) {
recursively_set_expanded(selected, 0);
}
break;
} else if (action_id == ACT_MENU_EXPAND) {
case ACT_MENU_EXPAND:
/* Recursively expand all folders */
if (!selected || selected->type != BI_FOLDER)
return EVENT_PROCESSED;
recursively_set_expanded(selected, 1);
break;
} else if (action_id == ACT_MENU_SEARCH) {
case ACT_MENU_SEARCH:
if (!box->ops->match)
return EVENT_NOT_PROCESSED;
push_hierbox_search_button(dlg_data, NULL);
return EVENT_PROCESSED;
} else {
default:
return EVENT_NOT_PROCESSED;
}
@ -230,7 +235,9 @@ hierbox_ev_init(struct dialog_data *dlg_data)
litem->visible = 1;
}
return EVENT_NOT_PROCESSED; /* FIXME: is this correct ? --Zas */
/* Return this so that the generic dialog code will run and initialise
* the widgets and stuff. */
return EVENT_NOT_PROCESSED;
}
static widget_handler_status_T
@ -254,7 +261,9 @@ hierbox_ev_abort(struct dialog_data *dlg_data)
}
}
return EVENT_NOT_PROCESSED; /* FIXME: is this correct ? --Zas */
/* Return this so that the generic dialog code will run and initialise
* the widgets and stuff. */
return EVENT_NOT_PROCESSED;
}
@ -312,7 +321,7 @@ hierbox_browser(struct hierbox_browser *browser, struct session *ses)
dlg->udata = ses;
dlg->udata2 = browser;
add_dlg_listbox(dlg, 12, listbox_data);
add_dlg_listbox(dlg, listbox_data);
for (button = 0; button < browser->buttons_size; button++) {
struct hierbox_browser_button *but = &browser->buttons[button];

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

@ -321,7 +321,7 @@ save_input_history(struct input_history *history, unsigned char *filename)
history_file = straconcat(elinks_home, filename, NULL);
if (!history_file) return -1;
ssi = secure_open(history_file, 0177);
ssi = secure_open(history_file);
mem_free(history_file);
if (!ssi) return -1;

View File

@ -24,14 +24,12 @@
#define VERTICAL_LISTBOX_MARGIN 3
void
add_dlg_listbox(struct dialog *dlg, int height, void *box_data)
add_dlg_listbox(struct dialog *dlg, void *box_data)
{
struct widget *widget = &dlg->widgets[dlg->number_of_widgets++];
widget->type = WIDGET_LISTBOX;
widget->data = box_data;
widget->info.listbox.height = height;
}
struct listbox_data *

View File

@ -11,12 +11,8 @@ struct terminal;
struct uri;
struct widget_data;
struct widget_info_listbox {
int height;
};
void add_dlg_listbox(struct dialog *dlg, int height, void *box_data);
void add_dlg_listbox(struct dialog *dlg, void *box_data);
enum listbox_match {
LISTBOX_MATCH_OK,

View File

@ -42,7 +42,6 @@ struct widget {
union {
struct widget_info_checkbox checkbox;
struct widget_info_field field;
struct widget_info_listbox listbox;
struct widget_info_button button;
struct widget_info_text text;
} info;

View File

@ -94,7 +94,7 @@ bookmarks_write(struct list_head *bookmarks_list)
file_name = straconcat(elinks_home, file_name, NULL);
if (!file_name) return;
ssi = secure_open(file_name, 0177);
ssi = secure_open(file_name);
mem_free(file_name);
if (!ssi) return;

View File

@ -805,7 +805,7 @@ write_config_file(unsigned char *prefix, unsigned char *name,
config_file = straconcat(prefix, slash, name, NULL);
if (!config_file) goto free_cfg_str;
ssi = secure_open(config_file, 0177);
ssi = secure_open(config_file);
if (ssi) {
secure_fputs(ssi, cfg_str);
ret = secure_close(ssi);

View File

@ -193,7 +193,7 @@ static struct option_info config_options_info[] = {
INIT_OPT_STRING("document.browse.forms", N_("External editor"),
"editor", 0, "",
N_("Path to the executable that ELinks should launch when the user\n"
"requests to edit a textarea with an external editor.\n\n"
"requests to edit a textarea with an external editor.\n"
"If this is blank, ELinks will use the value of the environmental\n"
"variable $EDITOR. If $EDITOR is empty or not set, ELinks will then\n"
"default to \"vi\".")),
@ -730,7 +730,7 @@ static struct option_info config_options_info[] = {
N_("A rule for passing URI to an external command.\n"
"The format is:\n"
"%c in the string means the current URL\n"
"%% in the string means '%'\n\n"
"%% in the string means '%'\n"
"Do _not_ put single- or double-quotes around %c.")),
/* Keep options in alphabetical order. */

View File

@ -775,7 +775,7 @@ save_cookies(void) {
cookfile = straconcat(elinks_home, COOKIES_FILENAME, NULL);
if (!cookfile) return;
ssi = secure_open(cookfile, 0177); /* rw for user only */
ssi = secure_open(cookfile);
mem_free(cookfile);
if (!ssi) return;

View File

@ -143,7 +143,7 @@ menu_copying(struct terminal *term, void *xxx, void *xxxx)
"\n"
"(C) 1999 - 2002 Mikulas Patocka\n"
"(C) 2001 - 2004 Petr Baudis\n"
"(C) 2002 - 2005 Jonas Fonseca\n"
"(C) 2002 - 2006 Jonas Fonseca\n"
"and others\n"
"\n"
"This program is free software; you can redistribute it "

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])*)*"
@ -61,11 +69,11 @@ struct dom_renderer {
static void
init_template(struct screen_char *template, struct document_options *options,
color_T background, color_T foreground)
color_T background, color_T foreground, enum screen_char_attr attr)
{
struct color_pair colors = INIT_COLOR_PAIR(background, foreground);
template->attr = 0;
template->attr = attr;
template->data = ' ';
set_term_color(template, &colors,
options->color_flags, options->color_mode);
@ -115,6 +123,7 @@ init_dom_renderer(struct dom_renderer *renderer, struct document *document,
struct screen_char *template = &renderer->styles[type];
color_T background = document->options.default_bg;
color_T foreground = document->options.default_fg;
enum screen_char_attr attr = 0;
static int i_want_struct_module_for_dom;
struct dom_string *name = get_dom_node_type_name(type);
@ -157,9 +166,31 @@ init_dom_renderer(struct dom_renderer *renderer, struct document *document,
property = get_css_property(properties, CSS_PT_COLOR);
if (property) foreground = property->value.color;
property = get_css_property(properties, CSS_PT_FONT_WEIGHT);
if (property) {
if (property->value.font_attribute.add & AT_BOLD)
attr |= SCREEN_ATTR_BOLD;
}
property = get_css_property(properties, CSS_PT_FONT_STYLE);
if (property) {
if (property->value.font_attribute.add & AT_UNDERLINE)
attr |= SCREEN_ATTR_UNDERLINE;
if (property->value.font_attribute.add & AT_ITALIC)
attr |= SCREEN_ATTR_ITALIC;
}
property = get_css_property(properties, CSS_PT_TEXT_DECORATION);
if (property) {
if (property->value.font_attribute.add & AT_UNDERLINE)
attr |= SCREEN_ATTR_UNDERLINE;
}
}
init_template(template, &document->options, background, foreground);
init_template(template, &document->options, background, foreground, attr);
}
}
@ -311,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;
@ -320,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))
@ -332,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;
@ -361,7 +392,7 @@ add_dom_link(struct dom_renderer *renderer, unsigned char *string, int length)
link->number = document->nlinks;
init_template(&template, &document->options,
link->color.background, link->color.foreground);
link->color.background, link->color.foreground, 0);
render_dom_text(renderer, &template, string, length);
@ -456,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;
@ -578,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;
@ -659,23 +691,298 @@ 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)) {
if (item == renderer->channel) {
unsigned char *str;
str = convert_string(renderer->convert_table,
title->string, title->length,
renderer->document->options.cp,
CSM_DEFAULT, NULL, NULL, NULL);
if (str)
renderer->document->title = str;
}
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,
struct string *buffer)
{
unsigned char *head = empty_string_or_(cached->head);
struct dom_node *root;
struct dom_renderer renderer;
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);
assert(document->options.plain);
enum sgml_parser_code code;
convert_table = get_convert_table(head, document->options.cp,
document->options.assume_cp,
@ -687,6 +994,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;
@ -707,14 +1019,24 @@ render_dom_document(struct cache_entry *cached, struct document *document,
doctype = SGML_DOCTYPE_HTML;
}
parser = init_sgml_parser(SGML_PARSER_STREAM, doctype, &uri);
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);
}
root = parse_sgml(parser, &source);
if (root) {
/* 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
* incrementally parse new data. This will require the parser to live
* during the fetching of data. */
code = parse_sgml(parser, &source, 1);
if (parser->root) {
assert(parser->stack.depth == 1);
get_dom_stack_top(&parser->stack)->immutable = 0;

View File

@ -114,9 +114,10 @@ struct html_context {
void *(*special_f)(struct html_context *, enum html_special_type, ...);
};
#define format (((struct html_element *) html_context->stack.next)->attr)
#define par_format (((struct html_element *) html_context->stack.next)->parattr)
#define html_top (*(struct html_element *) html_context->stack.next)
#define html_top ((struct html_element *) html_context->stack.next)
#define html_bottom ((struct html_element *) html_context->stack.prev)
#define format (html_top->attr)
#define par_format (html_top->parattr)
#define html_is_preformatted() (format.style.attr & AT_PREFORMATTED)

View File

@ -93,7 +93,7 @@ get_target(struct document_options *options, unsigned char *a)
void
ln_break(struct html_context *html_context, int n)
{
if (!n || html_top.invisible) return;
if (!n || html_top->invisible) return;
while (n > html_context->line_breax) {
html_context->line_breax++;
html_context->line_break_f(html_context);
@ -108,7 +108,7 @@ put_chrs(struct html_context *html_context, unsigned char *start, int len)
if (html_is_preformatted())
html_context->putsp = HTML_SPACE_NORMAL;
if (!len || html_top.invisible)
if (!len || html_top->invisible)
return;
switch (html_context->putsp) {
@ -258,8 +258,8 @@ html_focusable(struct html_context *html_context, unsigned char *a)
void
html_skip(struct html_context *html_context, unsigned char *a)
{
html_top.invisible = 1;
html_top.type = ELEMENT_DONT_KILL;
html_top->invisible = 1;
html_top->type = ELEMENT_DONT_KILL;
}
void
@ -663,10 +663,7 @@ init_html_parser_state(struct html_context *html_context,
enum html_element_type type,
int align, int margin, int width)
{
struct html_element *element;
html_stack_dup(html_context, type);
element = &html_top;
par_format.align = align;
@ -677,10 +674,10 @@ init_html_parser_state(struct html_context *html_context,
par_format.list_level = 0;
par_format.list_number = 0;
par_format.dd_margin = 0;
html_top.namelen = 0;
html_top->namelen = 0;
}
return element;
return html_top;
}
@ -691,20 +688,20 @@ done_html_parser_state(struct html_context *html_context,
{
html_context->line_breax = 1;
while (&html_top != element) {
kill_html_stack_item(html_context, &html_top);
while (html_top != element) {
pop_html_element(html_context);
#if 0
/* I've preserved this bit to show an example of the Old Code
* of the Mikulas days (I _HOPE_ it's by Mikulas, at least ;-).
* I think this assert() can never fail, for one. --pasky */
assertm(&html_top && (void *) &html_top != (void *) &html_stack,
assertm(html_top && (void *) html_top != (void *) &html_stack,
"html stack trashed");
if_assert_failed break;
#endif
}
html_top.type = ELEMENT_KILLABLE;
kill_html_stack_item(html_context, &html_top);
html_top->type = ELEMENT_KILLABLE;
pop_html_element(html_context);
}
@ -777,12 +774,12 @@ init_html_parser(struct uri *uri, struct document_options *options,
par_format.bgcolor = options->default_bg;
html_top.invisible = 0;
html_top.name = NULL;
html_top.namelen = 0;
html_top.options = NULL;
html_top.linebreak = 1;
html_top.type = ELEMENT_DONT_KILL;
html_top->invisible = 0;
html_top->name = NULL;
html_top->namelen = 0;
html_top->options = NULL;
html_top->linebreak = 1;
html_top->type = ELEMENT_DONT_KILL;
html_context->has_link_lines = 0;
html_context->table_level = 0;

View File

@ -254,7 +254,7 @@ html_input_format(struct html_context *html_context, unsigned char *a,
case FC_HIDDEN:
INTERNAL("bad control type");
}
kill_html_stack_item(html_context, &html_top);
pop_html_element(html_context);
put_chrs(html_context, " ", 1);
}
@ -498,7 +498,7 @@ end_parse:
for (i = 0; i < max_width; i++)
put_chrs(html_context, "_", 1);
kill_html_stack_item(html_context, &html_top);
pop_html_element(html_context);
put_chrs(html_context, "]", 1);
html_context->special_f(html_context, SP_CONTROL, fc);
}
@ -513,7 +513,7 @@ do_html_select_multiple(struct html_context *html_context, unsigned char *a,
if (!al) return;
html_focusable(html_context, a);
html_top.type = ELEMENT_DONT_KILL;
html_top->type = ELEMENT_DONT_KILL;
mem_free_set(&format.select, al);
format.select_disabled = has_attr(a, "disabled", html_context->options)
? FORM_MODE_DISABLED
@ -574,10 +574,10 @@ sp:
goto se;
}
if (parse_element(r, html_context->eoff, &name, &namelen, NULL, &p)) goto sp;
if (namelen < 6) goto se;
if (name[0] == '/') name++, namelen--;
if (strlcasecmp(name, namelen, "OPTION", 6)
&& strlcasecmp(name, namelen, "SELECT", 6)
&& strlcasecmp(name, namelen, "OPTGROUP", 8))
@ -603,7 +603,7 @@ end_parse:
format.form = fc;
format.style.attr |= AT_BOLD;
put_chrs(html_context, "[ ]", 3);
kill_html_stack_item(html_context, &html_top);
pop_html_element(html_context);
put_chrs(html_context, " ", 1);
html_context->special_f(html_context, SP_CONTROL, fc);
}
@ -709,7 +709,7 @@ pp:
ln_break(html_context, 1);
}
kill_html_stack_item(html_context, &html_top);
pop_html_element(html_context);
if (rows > 1)
ln_break(html_context, 1);
else

View File

@ -141,14 +141,14 @@ html_apply_canvas_bgcolor(struct html_context *html_context)
/* If there are any CSS twaks regarding bgcolor, make sure we will get
* it _and_ prefer it over bgcolor attribute. */
if (html_context->options->css_enable)
css_apply(html_context, &html_top, &html_context->css_styles,
css_apply(html_context, html_top, &html_context->css_styles,
&html_context->stack);
#endif
if (par_format.bgcolor != format.style.bg) {
/* Modify the root HTML element - format_html_part() will take
* this from there. */
struct html_element *e = html_context->stack.prev;
struct html_element *e = html_bottom;
html_context->was_body_background = 1;
e->parattr.bgcolor = e->attr.style.bg = par_format.bgcolor = format.style.bg;
@ -195,7 +195,7 @@ html_script(struct html_context *html_context, unsigned char *a,
mem_free(type);
not_processed:
/* Permit nested scripts and retreat. */
html_top.invisible++;
html_top->invisible++;
return;
}
@ -364,7 +364,7 @@ html_html(struct html_context *html_context, unsigned char *a,
/* Modify the root HTML element - format_html_part() will take
* this from there. */
struct html_element *e = html_context->stack.prev;
struct html_element *e = html_bottom;
if (par_format.bgcolor != format.style.bg)
e->parattr.bgcolor = e->attr.style.bg = par_format.bgcolor = format.style.bg;
@ -403,8 +403,8 @@ void
html_title(struct html_context *html_context, unsigned char *a,
unsigned char *xxx3, unsigned char *xxx4, unsigned char **xxx5)
{
html_top.invisible = 1;
html_top.type = ELEMENT_WEAK;
html_top->invisible = 1;
html_top->type = ELEMENT_WEAK;
}
void
@ -586,7 +586,7 @@ html_hr(struct html_context *html_context, unsigned char *a,
}
html_context->special_f(html_context, SP_NOWRAP, 0);
ln_break(html_context, 2);
kill_html_stack_item(html_context, &html_top);
pop_html_element(html_context);
}
void
@ -690,7 +690,7 @@ html_ul(struct html_context *html_context, unsigned char *a,
int_upper_bound(&par_format.leftmargin, par_format.width / 2);
par_format.align = ALIGN_LEFT;
html_top.type = ELEMENT_DONT_KILL;
html_top->type = ELEMENT_DONT_KILL;
}
void
@ -725,7 +725,7 @@ html_ol(struct html_context *html_context, unsigned char *a,
int_upper_bound(&par_format.leftmargin, par_format.width / 2);
par_format.align = ALIGN_LEFT;
html_top.type = ELEMENT_DONT_KILL;
html_top->type = ELEMENT_DONT_KILL;
}
static struct {
@ -873,10 +873,10 @@ html_dl(struct html_context *html_context, unsigned char *a,
par_format.list_number = 0;
par_format.align = ALIGN_LEFT;
par_format.dd_margin = par_format.leftmargin;
html_top.type = ELEMENT_DONT_KILL;
html_top->type = ELEMENT_DONT_KILL;
if (!(par_format.flags & P_COMPACT)) {
ln_break(html_context, 2);
html_top.linebreak = 2;
html_top->linebreak = 2;
}
}
@ -948,14 +948,14 @@ html_frame(struct html_context *html_context, unsigned char *a,
}
if (!name) return;
if (!html_context->options->frames || !html_top.frameset) {
if (!html_context->options->frames || !html_top->frameset) {
html_focusable(html_context, a);
put_link_line("Frame: ", name, url, "", html_context);
} else {
if (html_context->special_f(html_context, SP_USED, NULL)) {
html_context->special_f(html_context, SP_FRAME,
html_top.frameset, name, url);
html_top->frameset, name, url);
}
}
@ -997,12 +997,12 @@ html_frameset(struct html_context *html_context, unsigned char *a,
}
}
if (!html_top.frameset) {
if (!html_top->frameset) {
width = html_context->options->box.width;
height = html_context->options->box.height;
html_context->options->needs_height = 1;
} else {
struct frameset_desc *frameset_desc = html_top.frameset;
struct frameset_desc *frameset_desc = html_top->frameset;
int offset;
if (frameset_desc->box.y >= frameset_desc->box.height)
@ -1020,9 +1020,9 @@ html_frameset(struct html_context *html_context, unsigned char *a,
parse_frame_widths(rows, height, HTML_FRAME_CHAR_HEIGHT,
&fp.height, &fp.y);
fp.parent = html_top.frameset;
fp.parent = html_top->frameset;
if (fp.x && fp.y) {
html_top.frameset = html_context->special_f(html_context, SP_FRAMESET, &fp);
html_top->frameset = html_context->special_f(html_context, SP_FRAMESET, &fp);
}
mem_free_if(fp.width);
mem_free_if(fp.height);

View File

@ -67,20 +67,20 @@ html_a(struct html_context *html_context, unsigned char *a,
#ifdef CONFIG_GLOBHIST
} else if (get_global_history_item(format.link)) {
format.style.fg = format.vlink;
html_top.pseudo_class &= ~ELEMENT_LINK;
html_top.pseudo_class |= ELEMENT_VISITED;
html_top->pseudo_class &= ~ELEMENT_LINK;
html_top->pseudo_class |= ELEMENT_VISITED;
#endif
#ifdef CONFIG_BOOKMARKS
} else if (get_bookmark(format.link)) {
format.style.fg = format.bookmark_link;
html_top.pseudo_class &= ~ELEMENT_VISITED;
html_top->pseudo_class &= ~ELEMENT_VISITED;
/* XXX: Really set ELEMENT_LINK? --pasky */
html_top.pseudo_class |= ELEMENT_LINK;
html_top->pseudo_class |= ELEMENT_LINK;
#endif
} else {
format.style.fg = format.clink;
html_top.pseudo_class &= ~ELEMENT_VISITED;
html_top.pseudo_class |= ELEMENT_LINK;
html_top->pseudo_class &= ~ELEMENT_VISITED;
html_top->pseudo_class |= ELEMENT_LINK;
}
mem_free_set(&format.title,
@ -89,7 +89,7 @@ html_a(struct html_context *html_context, unsigned char *a,
html_focusable(html_context, a);
} else {
kill_html_stack_item(html_context, &html_top);
pop_html_element(html_context);
}
set_fragment_identifier(html_context, a, "name");
@ -269,7 +269,7 @@ html_img_do(unsigned char *a, unsigned char *object_src,
* If not, just exit now. */
if (!options->images && !format.link) {
mem_free_if(src);
if (usemap) kill_html_stack_item(html_context, &html_top);
if (usemap) pop_html_element(html_context);
return;
}
@ -332,7 +332,7 @@ html_img_do(unsigned char *a, unsigned char *object_src,
put_image_label(a, label, html_context);
if (ismap) kill_html_stack_item(html_context, &html_top);
if (ismap) pop_html_element(html_context);
mem_free_set(&format.image, NULL);
mem_free_set(&format.title, NULL);
}
@ -341,7 +341,7 @@ html_img_do(unsigned char *a, unsigned char *object_src,
}
mem_free_if(src);
if (usemap) kill_html_stack_item(html_context, &html_top);
if (usemap) pop_html_element(html_context);
}
void
@ -369,7 +369,7 @@ put_link_line(unsigned char *prefix, unsigned char *linkname,
format.style.fg = format.clink;
put_chrs(html_context, linkname, strlen(linkname));
ln_break(html_context, 1);
kill_html_stack_item(html_context, &html_top);
pop_html_element(html_context);
}

View File

@ -714,7 +714,7 @@ next_break:
element:
endingtag = *name == '/'; name += endingtag; namelen -= endingtag;
if (!endingtag && html_context->putsp == HTML_SPACE_ADD && !html_top.invisible)
if (!endingtag && html_context->putsp == HTML_SPACE_ADD && !html_top->invisible)
put_chrs(html_context, " ", 1);
put_chrs(html_context, base_pos, html - base_pos);
if (!html_is_preformatted() && !endingtag && html_context->putsp == HTML_SPACE_NORMAL) {
@ -766,14 +766,14 @@ start_element(struct element_info *ei,
struct css_selector *selector = NULL;
#endif
if (html_top.type == ELEMENT_WEAK) {
kill_html_stack_item(html_context, &html_top);
if (html_top->type == ELEMENT_WEAK) {
pop_html_element(html_context);
}
/* We try to process nested <script> if we didn't process the parent
* one. */
if (html_top.invisible
&& (ei->func != html_script || html_top.invisible < 2)) {
if (html_top->invisible
&& (ei->func != html_script || html_top->invisible < 2)) {
ELEMENT_RENDER_PROLOGUE
return html;
}
@ -803,11 +803,14 @@ start_element(struct element_info *ei,
if (e->type < ELEMENT_KILLABLE) break;
if (is_block_element(e) || is_inline_element(ei)) break;
}
} else foreach (e, html_context->stack) {
if (is_block_element(e) && is_inline_element(ei)) break;
if (e->type < ELEMENT_KILLABLE) break;
if (!strlcasecmp(e->name, e->namelen, name, namelen)) break;
} else {
foreach (e, html_context->stack) {
if (is_block_element(e) && is_inline_element(ei)) break;
if (e->type < ELEMENT_KILLABLE) break;
if (!strlcasecmp(e->name, e->namelen, name, namelen)) break;
}
}
if (!strlcasecmp(e->name, e->namelen, name, namelen)) {
while (e->prev != (void *) &html_context->stack)
kill_html_stack_item(html_context, e->prev);
@ -819,10 +822,10 @@ start_element(struct element_info *ei,
if (ei->type != ELEMENT_TYPE_NON_PAIRABLE) {
html_stack_dup(html_context, ELEMENT_KILLABLE);
html_top.name = name;
html_top.namelen = namelen;
html_top.options = attr;
html_top.linebreak = ei->linebreak;
html_top->name = name;
html_top->namelen = namelen;
html_top->options = attr;
html_top->linebreak = ei->linebreak;
#ifdef CONFIG_ECMASCRIPT
if (has_attr(attr, "onClick", html_context->options)) {
@ -830,7 +833,7 @@ start_element(struct element_info *ei,
mem_free_set(&format.link, stracpy("javascript:void(0);"));
mem_free_set(&format.target, stracpy(html_context->base_target));
format.style.fg = format.clink;
html_top.pseudo_class = ELEMENT_LINK;
html_top->pseudo_class = ELEMENT_LINK;
mem_free_set(&format.title, stracpy("onClick placeholder"));
/* Er. I know. Well, double html_focusable()s shouldn't
* really hurt. */
@ -840,7 +843,7 @@ start_element(struct element_info *ei,
}
#ifdef CONFIG_CSS
if (html_top.options && html_context->options->css_enable) {
if (html_top->options && html_context->options->css_enable) {
/* XXX: We should apply CSS otherwise as well, but that'll need
* some deeper changes in order to have options filled etc.
* Probably just applying CSS from more places, since we
@ -852,12 +855,12 @@ start_element(struct element_info *ei,
/* FIXME: The caching of the CSS selector is broken, since t can
* lead to wrong styles being applied to following elements, so
* disabled for now. */
selector = get_css_selector_for_element(html_context, &html_top,
selector = get_css_selector_for_element(html_context, html_top,
&html_context->css_styles,
&html_context->stack);
if (selector) {
apply_css_selector_style(html_context, &html_top, selector);
apply_css_selector_style(html_context, html_top, selector);
done_css_selector(selector);
}
}
@ -868,14 +871,14 @@ start_element(struct element_info *ei,
ELEMENT_RENDER_PROLOGUE
if (ei->func) ei->func(html_context, attr, html, eof, &html);
#ifdef CONFIG_CSS
if (selector && html_top.options) {
if (selector && html_top->options) {
/* Call it now to override default colors of the elements. */
selector = get_css_selector_for_element(html_context, &html_top,
selector = get_css_selector_for_element(html_context, html_top,
&html_context->css_styles,
&html_context->stack);
if (selector) {
apply_css_selector_style(html_context, &html_top, selector);
apply_css_selector_style(html_context, html_top, selector);
done_css_selector(selector);
}
}
@ -909,7 +912,7 @@ end_element(struct element_info *ei,
/* Apply background color from the <HTML> element. (bug 696) */
if (ei->func == html_html
&& html_top.type >= ELEMENT_KILLABLE
&& html_top->type >= ELEMENT_KILLABLE
&& !html_context->was_body_background)
html_apply_canvas_bgcolor(html_context);

View File

@ -60,7 +60,7 @@ search_html_stack(struct html_context *html_context, unsigned char *name)
#endif
foreach (element, html_context->stack) {
if (element == &html_top)
if (element == html_top)
continue; /* skip the top element */
if (strlcasecmp(element->name, element->namelen, name, namelen))
continue;
@ -189,7 +189,7 @@ kill_element(struct html_context *html_context, int ls, struct html_element *e)
void
kill_html_stack_until(struct html_context *html_context, int ls, ...)
{
struct html_element *e = &html_top;
struct html_element *e = html_top;
if (ls) e = e->next;

View File

@ -14,6 +14,8 @@ void html_stack_dup(struct html_context *html_context,
void kill_html_stack_item(struct html_context *html_context,
struct html_element *e);
#define pop_html_element(html_context) \
kill_html_stack_item(html_context, html_top)
void kill_html_stack_until(struct html_context *html_context, int ls, ...);
/* void dump_html_stack(struct html_context *html_context); */

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

@ -6,7 +6,4 @@ OBJS = node.o select.o stack.o scanner.o
SUBDIRS-$(CONFIG_DEBUG) += test
test: all
make test -C test
include $(top_srcdir)/Makefile.lib

View File

@ -360,7 +360,7 @@ done_dom_node(struct dom_node *node)
break;
}
}
done_dom_node_data(node);
}

View File

@ -154,7 +154,8 @@ 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)
struct dom_string *string, int state, int count_lines, int complete,
int check_complete, int detect_errors)
{
if (!scanner_info->initialized) {
init_dom_scanner_info(scanner_info);
@ -170,6 +171,9 @@ init_dom_scanner(struct dom_scanner *scanner, struct dom_scanner_info *scanner_i
scanner->info = scanner_info;
scanner->state = state;
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

@ -7,27 +7,32 @@
/* Define if you want a talking scanner */
/* #define DEBUG_DOM_SCANNER */
/* The {struct dom_scanner_token} describes one scanner state. There are two
* kinds of tokens: char and non-char tokens. Char tokens contains only one
* char and simply have their char value as type. They are tokens having
* special control meaning in the code, like ':', ';', '{', '}' and '*'. Non
* char tokens has one or more chars and contain stuff like number or
* indentifier strings. */
/** DOM scanner token
*
* This struct describes one scanner state. There are two kinds of tokens: char
* and non-char tokens. Char tokens contains only one char and simply have
* their char value as type. They are tokens having special control meaning in
* the code, like ':', ';', '{', '}' and '*'. Non-char tokens have one or more
* chars and contain stuff like number or indentifier strings. */
struct dom_scanner_token {
/* The type the token */
/** The type the token. */
int type;
/* Some precedence value */
/** Some precedence value. */
int precedence;
/* The start of the token string and the token length */
/** The line number; used for error tokens. */
unsigned int lineno;
/** The start of the token string and the token length. */
struct dom_string string;
};
/** Skip the first charector of a token */
#define skip_dom_scanner_token_char(token) \
do { (token)->string.string++; (token)->string.length--; } while (0)
/* Compare the string of @token with the "static" string in @str. */
/** Compare the token string to a "static" string */
#define dom_scanner_token_contains(token, str) \
((token)->string.length == (sizeof(str) - 1) \
&& !strncasecmp((token)->string.string, str, sizeof(str) - 1))
@ -67,54 +72,72 @@ struct dom_scanner_string_mapping {
struct dom_scanner;
/** DOM scanner info
*
* Backend-specific information used during the actual scanning and
* by the front end to fill the token table on-demand, etc.
*/
struct dom_scanner_info {
/* Table containing how to map strings to token types */
/** Table containing how to map strings to token types */
const struct dom_scanner_string_mapping *mappings;
/* Information for how to initialize the scanner table */
/** Information for how to initialize the scanner table */
const struct dom_scan_table_info *scan_table_info;
/* Fills the scanner with tokens. Already scanned tokens which have not
/**
* Fills the scanner with tokens. Already scanned tokens which have not
* been requested remain and are moved to the start of the scanners
* token table. */
/* Returns the current token or NULL if there are none. */
* token table. Returns the current token or NULL if there are none. */
struct dom_scanner_token *(*scan)(struct dom_scanner *scanner);
/* The scanner table */
/* Contains bitmaps for the various characters groups.
* Idea sync'ed from mozilla browser. */
/**
* The scanner table. Contains bitmaps for the various characters
* groups. Idea sync'ed from mozilla browser. */
int scan_table[DOM_SCAN_TABLE_SIZE];
/* Has the scanner info been initialized? */
/** Has the scanner info been initialized? */
unsigned int initialized:1;
};
/* Initializes the scanner. */
/** Initializes a DOM scanner
*
* See struct ref:[dom_scanner] for a description of the `int` flags. */
void init_dom_scanner(struct dom_scanner *scanner, struct dom_scanner_info *scanner_info,
struct dom_string *string, int state, int count_lines);
struct dom_string *string, int state, int count_lines, int complete,
int check_complete, int detect_error);
/* The number of tokens in the scanners token table:
/** The number of tokens in the scanners token table
*
* At best it should be big enough to contain properties with space separated
* values and function calls with up to 3 variables like rgb(). At worst it
* should be no less than 2 in order to be able to peek at the next token in
* the scanner. */
#define DOM_SCANNER_TOKENS 10
/* The {struct dom_scanner} describes the current state of the scanner. */
/** DOM scanner
*
* Holds the current state of the scanner. */
struct dom_scanner {
/* The very start of the scanned string, the position in the string
* where to scan next and the end of the string. If position is NULL it
* means that no more tokens can be retrieved from the string. */
unsigned char *string, *position, *end;
/** The start of the scanned string. */
unsigned char *string;
/** The end of the scanned string. */
unsigned char *end;
/**
* The position in the string where to scan next and the end of the
* string. If position is NULL it means that no more tokens can be
* retrieved from the string. */
unsigned char *position;
/* The current token and number of scanned tokens in the table.
* If the number of scanned tokens is less than DOM_SCANNER_TOKENS it
* is because there are no more tokens in the string. */
/**
* The current token. If the number of scanned tokens is less than
* ref:[DOM_SCANNER_TOKENS] it is because there are no more tokens in
* the string. */
struct dom_scanner_token *current;
/** The number of scanned tokens left in the table. */
int tokens;
/* The 'meta' scanner information */
/** The 'meta' scanner information */
struct dom_scanner_info *info;
#ifdef DEBUG_SCANNER
@ -123,19 +146,30 @@ struct dom_scanner {
int line;
#endif
unsigned int count_lines:1;
unsigned int lineno;
/* The following two flags are used when parsing is incremental and
* the scanner must ensure that only tokens that are complete are
* generated. */
unsigned int check_complete:1; /*: Only generate complete tokens */
unsigned int incomplete:1; /*: The scanned string is incomplete */
/* Some state indicator only meaningful to the scanner internals */
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 */
/** Some state indicator only meaningful to the scanner internals */
int state;
/* The table contain already scanned tokens. It is maintained in
/**
* The table contain already scanned tokens. It is maintained in
* order to optimize the scanning a bit and make it possible to look
* ahead at the next token. You should always use the accessors
* (defined below) for getting tokens from the scanner. */
struct dom_scanner_token table[DOM_SCANNER_TOKENS];
};
/** Check if there are more tokens */
#define dom_scanner_has_tokens(scanner) \
((scanner)->tokens > 0 && (scanner)->current < (scanner)->table + (scanner)->tokens)
@ -149,22 +183,24 @@ struct dom_scanner {
/* Scanner table accessors and mutators */
/* Checks the type of the next token */
/** Check the type of the next token */
#define check_next_dom_scanner_token(scanner, token_type) \
(scanner_has_tokens(scanner) \
&& ((scanner)->current + 1 < (scanner)->table + (scanner)->tokens) \
&& (scanner)->current[1].type == (token_type))
/* Access current and next token. Getting the next token might cause
* a rescan so any token pointers that has been stored in a local variable
* might not be valid after the call. */
/** Get the current token */
static inline struct dom_scanner_token *
get_dom_scanner_token(struct dom_scanner *scanner)
{
return dom_scanner_has_tokens(scanner) ? scanner->current : NULL;
}
/* Do a scanning if we do not have also have access to next token. */
/** Get the next token
*
* Getting the next token might cause a rescan so any token pointers that has
* been stored in a local variable might not be valid after the call. */
/* Do a scanning if we do not also have access to next token. */
static inline struct dom_scanner_token *
get_next_dom_scanner_token(struct dom_scanner *scanner)
{
@ -173,16 +209,20 @@ get_next_dom_scanner_token(struct dom_scanner *scanner)
? scanner->info->scan(scanner) : get_dom_scanner_token(scanner));
}
/* This should just make the code more understandable .. hopefully */
/** Skip the current token */
#define skip_dom_scanner_token(scanner) get_next_dom_scanner_token(scanner)
/* Removes tokens from the scanner until it meets a token of the given type.
/** Conditionally skip tokens
*
* Removes tokens from the scanner until it meets a token of the given type.
* This token will then also be skipped. */
struct dom_scanner_token *
skip_dom_scanner_tokens(struct dom_scanner *scanner, int skipto, int precedence);
/* Looks up the string from @ident to @end to in the scanners string mapping
* table */
/** Map a string to internal ID
*
* Looks up the string from @ident to @end to in the scanners string mapping
* table. */
int
map_dom_scanner_string(struct dom_scanner *scanner,
unsigned char *ident, unsigned char *end, int base_type);

View File

@ -158,13 +158,13 @@ parse_dom_select_attribute(struct dom_select_node *sel, struct dom_scanner *scan
/* Parse:
*
* 0n+1 / 1
* 2n+0 / 2n
* 2n+1
* -0n+2
* -0n+1 / -1
* 1n+0 / n+0 / n
* 0n+0
* 0n+1 / 1
* 2n+0 / 2n
* 2n+1
* -0n+2
* -0n+1 / -1
* 1n+0 / n+0 / n
* 0n+0
*/
/* FIXME: Move somewhere else? dom/scanner.h? */
@ -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);
init_dom_scanner(&scanner, &dom_css_scanner_info, string, 0, 0, 1, 0, 0);
memset(&sel, 0, sizeof(sel));
@ -441,8 +441,8 @@ parse_dom_select(struct dom_select *select, struct dom_stack *stack,
sel.node.type = DOM_NODE_ATTRIBUTE;
sel.match.attribute |= DOM_SELECT_ATTRIBUTE_SPACE_LIST;
set_dom_string(&sel.node.string, "class", -1);
copy_dom_string(&sel.node.data.attribute.value, &token->string);
set_dom_string(&sel.node.string, "class", -1);
copy_dom_string(&sel.node.data.attribute.value, &token->string);
break;
case ':':
@ -530,7 +530,7 @@ init_dom_select(enum dom_select_syntax syntax, struct dom_string *string)
struct dom_stack stack;
enum dom_exception_code code;
init_dom_stack(&stack, DOM_STACK_KEEP_NODES);
init_dom_stack(&stack, DOM_STACK_FLAG_NONE);
add_dom_stack_tracer(&stack, "init-select: ");
code = parse_dom_select(select, &stack, string);
@ -1060,12 +1060,12 @@ select_dom_nodes(struct dom_select *select, struct dom_node *root)
select_data.select = select;;
init_dom_stack(&stack, DOM_STACK_KEEP_NODES);
init_dom_stack(&stack, DOM_STACK_FLAG_NONE);
add_dom_stack_context(&stack, &select_data,
&dom_select_context_info);
add_dom_stack_tracer(&stack, "select-tree: ");
init_dom_stack(&select_data.stack, DOM_STACK_KEEP_NODES);
init_dom_stack(&select_data.stack, DOM_STACK_FLAG_NONE);
add_dom_stack_context(&select_data.stack, &select_data,
&dom_select_data_context_info);
add_dom_stack_tracer(&select_data.stack, "select-match: ");

View File

@ -154,7 +154,18 @@ add_sgml_node(struct dom_stack *stack, enum dom_node_type type, struct dom_scann
/* SGML parser main handling: */
static inline void
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)
{
struct dom_scanner_token name;
@ -179,22 +190,30 @@ parse_sgml_attributes(struct dom_stack *stack, struct dom_scanner *scanner)
case SGML_TOKEN_ELEMENT_BEGIN:
case SGML_TOKEN_ELEMENT_END:
case SGML_TOKEN_ELEMENT_EMPTY_END:
return;
return SGML_PARSER_CODE_OK;
case SGML_TOKEN_IDENT:
copy_struct(&name, token);
/* Skip the attribute name token */
token = get_next_dom_scanner_token(scanner);
if (token && token->type == '=') {
/* If the token is not a valid value token
* ignore it. */
token = get_next_dom_scanner_token(scanner);
if (token && token->type == SGML_TOKEN_INCOMPLETE)
return SGML_PARSER_CODE_INCOMPLETE;
if (token
&& token->type != SGML_TOKEN_IDENT
&& token->type != SGML_TOKEN_ATTRIBUTE
&& token->type != SGML_TOKEN_STRING)
token = NULL;
} else if (token && token->type == SGML_TOKEN_INCOMPLETE) {
return SGML_PARSER_CODE_INCOMPLETE;
} else {
token = NULL;
}
@ -206,14 +225,29 @@ parse_sgml_attributes(struct dom_stack *stack, struct dom_scanner *scanner)
skip_dom_scanner_token(scanner);
break;
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);
}
}
return SGML_PARSER_CODE_OK;
}
static void
static enum sgml_parser_code
parse_sgml_plain(struct dom_stack *stack, struct dom_scanner *scanner)
{
struct dom_scanner_token target;
@ -235,7 +269,12 @@ parse_sgml_plain(struct dom_stack *stack, struct dom_scanner *scanner)
}
if (token->type == SGML_TOKEN_ELEMENT_BEGIN) {
parse_sgml_attributes(stack, scanner);
enum sgml_parser_code code;
code = parse_sgml_attributes(stack, scanner);
if (code != SGML_PARSER_CODE_OK)
return code;
} else {
skip_dom_scanner_token(scanner);
}
@ -294,10 +333,16 @@ parse_sgml_plain(struct dom_stack *stack, struct dom_scanner *scanner)
/* Skip the target token */
token = get_next_dom_scanner_token(scanner);
if (!token) break;
if (!token || token->type == SGML_TOKEN_INCOMPLETE)
return SGML_PARSER_CODE_INCOMPLETE;
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)
@ -305,12 +350,19 @@ parse_sgml_plain(struct dom_stack *stack, struct dom_scanner *scanner)
/* Parse the <?xml data="attributes"?>. */
struct dom_scanner attr_scanner;
/* The attribute souce is complete. */
init_dom_scanner(&attr_scanner, &sgml_scanner_info,
&token->string, SGML_STATE_ELEMENT,
scanner->count_lines);
scanner->count_lines, 1, 0, 0);
if (dom_scanner_has_tokens(&attr_scanner))
if (dom_scanner_has_tokens(&attr_scanner)) {
/* Ignore parser codes from this
* enhanced parsing of attributes. It
* is really just a simple way to try
* and support xml and xml-stylesheet
* instructions. */
parse_sgml_attributes(stack, &attr_scanner);
}
}
pop_dom_node(stack);
@ -322,6 +374,20 @@ parse_sgml_plain(struct dom_stack *stack, struct dom_scanner *scanner)
skip_dom_scanner_token(scanner);
break;
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:
@ -329,30 +395,34 @@ parse_sgml_plain(struct dom_stack *stack, struct dom_scanner *scanner)
skip_dom_scanner_token(scanner);
}
}
return SGML_PARSER_CODE_OK;
}
struct dom_node *
parse_sgml(struct sgml_parser *parser, struct dom_string *buffer)
enum sgml_parser_code
parse_sgml(struct sgml_parser *parser, struct dom_string *buffer, int complete)
{
struct sgml_parsing_state *parsing;
enum sgml_parser_code code;
if (complete)
parser->flags |= SGML_PARSER_COMPLETE;
if (!parser->root) {
parser->root = add_sgml_document(&parser->stack, &parser->uri);
if (!parser->root)
return NULL;
return SGML_PARSER_CODE_MEM_ALLOC;
get_dom_stack_top(&parser->stack)->immutable = 1;
}
parsing = init_sgml_parsing_state(parser, buffer);
if (!parsing) return NULL;
if (!parsing) return SGML_PARSER_CODE_MEM_ALLOC;
/* FIXME: Make parse_sgml_plain() return something (error code or if
* can be guarenteed a root node). */
parse_sgml_plain(&parser->stack, &parsing->scanner);
code = parse_sgml_plain(&parser->stack, &parsing->scanner);
pop_dom_node(&parser->parsing);
return parser->root;
return code;
}
@ -368,11 +438,16 @@ sgml_parsing_push(struct dom_stack *stack, struct dom_node *node, void *data)
{
struct sgml_parser *parser = get_sgml_parser(stack);
struct sgml_parsing_state *parsing = 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, 0);
SGML_STATE_TEXT, count_lines, complete, incremental,
detect_errors);
}
static void
@ -443,6 +518,30 @@ init_sgml_parsing_state(struct sgml_parser *parser, struct dom_string *buffer)
return get_dom_stack_state_data(parser->parsing.contexts[0], state);
}
unsigned int
get_sgml_parser_line_number(struct sgml_parser *parser)
{
struct dom_stack_state *state;
struct sgml_parsing_state *pstate;
assert(parser->flags & SGML_PARSER_COUNT_LINES);
if (dom_stack_is_empty(&parser->parsing))
return 0;
state = get_dom_stack_top(&parser->parsing);
pstate = get_dom_stack_state_data(parser->parsing.contexts[0], state);
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;
}
/* Parser creation and destruction: */
@ -486,10 +585,10 @@ static struct dom_stack_context_info sgml_parser_context_info = {
struct sgml_parser *
init_sgml_parser(enum sgml_parser_type type, enum sgml_document_type doctype,
struct dom_string *uri)
struct dom_string *uri, enum sgml_parser_flag flags)
{
struct sgml_parser *parser;
enum dom_stack_flag flags = 0;
enum dom_stack_flag stack_flags = 0;
parser = mem_calloc(1, sizeof(*parser));
if (!parser) return NULL;
@ -499,19 +598,23 @@ init_sgml_parser(enum sgml_parser_type type, enum sgml_document_type doctype,
return NULL;
}
parser->type = type;
parser->info = get_sgml_info(doctype);
if (flags & SGML_PARSER_DETECT_ERRORS)
flags |= SGML_PARSER_COUNT_LINES;
if (type == SGML_PARSER_TREE)
flags |= DOM_STACK_KEEP_NODES;
parser->type = type;
parser->flags = flags;
parser->info = get_sgml_info(doctype);
init_dom_stack(&parser->stack, flags);
if (type == SGML_PARSER_STREAM)
stack_flags |= DOM_STACK_FLAG_FREE_NODES;
init_dom_stack(&parser->stack, stack_flags);
/* FIXME: Some sgml backend specific callbacks? Handle HTML script tags,
* and feed document.write() data back to the parser. */
add_dom_stack_context(&parser->stack, parser, &sgml_parser_context_info);
/* Don't keep the 'fake' text nodes that holds the parsing data. */
init_dom_stack(&parser->parsing, 0);
init_dom_stack(&parser->parsing, DOM_STACK_FLAG_FREE_NODES);
add_dom_stack_context(&parser->parsing, parser, &sgml_parsing_context_info);
return parser;

View File

@ -7,49 +7,150 @@
#include "dom/sgml/sgml.h"
#include "dom/scanner.h"
struct sgml_parser;
struct string;
struct uri;
/** 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
/**
* 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,
/**
* 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,
};
/** SGML parser flags
*
* These flags control how the parser behaves.
*/
enum sgml_parser_flag {
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. */
};
/** SGML parser state
*
* The SGML parser has only little state.
*/
struct sgml_parser_state {
/* Info about the properties of the node contained by state.
/**
* 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
/**
* 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 */
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 */
/** (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 */
/**
* FIXME: For when we will add support for requiring stricter parsing
* or even a validator. */
SGML_PARSER_CODE_ERROR,
};
/** 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);
/** The SGML parser
*
* This struct hold info used while parsing SGML data.
*
* NOTE: The only variable the user should set is ref:[sgml_parser.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 */
};
/** 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);
struct dom_string *uri, enum sgml_parser_flag flags);
/** Release an SGML parser
*
* Deallocates all resources, _expect_ the root node.
*
* parser:: The parser being released.
*/
void done_sgml_parser(struct sgml_parser *parser);
struct dom_node *parse_sgml(struct sgml_parser *parser, struct dom_string *buffer);
/** 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);
/** 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 recorded in the scanner tokens.
*/
unsigned int get_sgml_parser_line_number(struct sgml_parser *parser);
#endif

View File

@ -98,6 +98,104 @@ skip_sgml_space(struct dom_scanner *scanner, unsigned char **string)
*string = pos;
}
#define check_sgml_incomplete(scanner, string) \
((scanner)->check_complete \
&& (scanner)->incomplete \
&& (string) == (scanner)->end)
static void
set_sgml_incomplete(struct dom_scanner *scanner, struct dom_scanner_token *token)
{
size_t left = scanner->end - scanner->position;
assert(left > 0);
token->type = SGML_TOKEN_INCOMPLETE;
set_dom_string(&token->string, scanner->position, left);
/* Stop the scanning. */
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 */
@ -119,6 +217,8 @@ scan_sgml_text_token(struct dom_scanner *scanner, struct dom_scanner_token *toke
token->string.string = string++;
if (first_char == '&') {
int complete = 0;
if (is_sgml_entity(*string)) {
scan_sgml(scanner, string, SGML_CHAR_ENTITY);
type = SGML_TOKEN_ENTITY;
@ -128,13 +228,32 @@ scan_sgml_text_token(struct dom_scanner *scanner, struct dom_scanner_token *toke
foreach_sgml_cdata (scanner, string) {
if (*string == ';') {
complete = 1;
string++;
break;
}
}
/* We want the biggest possible text token. */
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 {
if (is_sgml_space(first_char)) {
if (scanner->count_lines
&& is_sgml_newline(first_char))
scanner->lineno++;
skip_sgml_space(scanner, &string);
type = string < scanner->end && is_sgml_text(*string)
? SGML_TOKEN_TEXT : SGML_TOKEN_SPACE;
@ -142,8 +261,21 @@ scan_sgml_text_token(struct dom_scanner *scanner, struct dom_scanner_token *toke
type = SGML_TOKEN_TEXT;
}
foreach_sgml_cdata (scanner, string) {
/* m33p */;
if (scanner->count_lines) {
foreach_sgml_cdata (scanner, string) {
if (is_sgml_newline(*string))
scanner->lineno++;
}
} else {
foreach_sgml_cdata (scanner, string) {
/* m33p */;
}
}
/* We want the biggest possible text token. */
if (check_sgml_incomplete(scanner, string)) {
set_sgml_incomplete(scanner, token);
return;
}
}
@ -226,7 +358,8 @@ skip_sgml(struct dom_scanner *scanner, unsigned char **string, unsigned char ski
}
static inline int
skip_sgml_comment(struct dom_scanner *scanner, unsigned char **string)
skip_sgml_comment(struct dom_scanner *scanner, unsigned char **string,
int *possibly_incomplete)
{
unsigned char *pos = *string;
int length = 0;
@ -238,6 +371,7 @@ skip_sgml_comment(struct dom_scanner *scanner, unsigned char **string)
* preceeding '-'. */
if (pos[-2] == '-' && pos[-1] == '-' && &pos[-2] >= *string) {
length = pos - *string - 2;
*possibly_incomplete = 0;
pos++;
break;
}
@ -245,6 +379,9 @@ skip_sgml_comment(struct dom_scanner *scanner, unsigned char **string)
if (!pos) {
pos = scanner->end;
/* The token is incomplete but set the length to handle tag
* tag soup graciously. */
*possibly_incomplete = 1;
length = pos - *string;
}
@ -253,7 +390,8 @@ skip_sgml_comment(struct dom_scanner *scanner, unsigned char **string)
}
static inline int
skip_sgml_cdata_section(struct dom_scanner *scanner, unsigned char **string)
skip_sgml_cdata_section(struct dom_scanner *scanner, unsigned char **string,
int *possibly_incomplete)
{
unsigned char *pos = *string;
int length = 0;
@ -263,6 +401,7 @@ skip_sgml_cdata_section(struct dom_scanner *scanner, unsigned char **string)
* are supposed to have '<![CDATA[' before this is called. */
if (pos[-2] == ']' && pos[-1] == ']') {
length = pos - *string - 2;
*possibly_incomplete = 0;
pos++;
break;
}
@ -270,6 +409,9 @@ skip_sgml_cdata_section(struct dom_scanner *scanner, unsigned char **string)
if (!pos) {
pos = scanner->end;
/* The token is incomplete but set the length to handle tag
* soup graciously. */
*possibly_incomplete = 1;
length = pos - *string;
}
@ -288,6 +430,7 @@ scan_sgml_element_token(struct dom_scanner *scanner, struct dom_scanner_token *t
unsigned char first_char = *string;
enum sgml_token_type type = SGML_TOKEN_GARBAGE;
int real_length = -1;
int possibly_incomplete = 1;
token->string.string = string++;
@ -302,6 +445,9 @@ scan_sgml_element_token(struct dom_scanner *scanner, struct dom_scanner_token *t
type = SGML_TOKEN_TAG_END;
scanner->state = SGML_STATE_TEXT;
/* We are creating a 'virtual' that has no source. */
possibly_incomplete = 0;
} else if (is_sgml_ident(*string)) {
token->string.string = string;
scan_sgml(scanner, string, SGML_CHAR_IDENT);
@ -312,7 +458,16 @@ scan_sgml_element_token(struct dom_scanner *scanner, struct dom_scanner_token *t
if (*string == '>') {
type = SGML_TOKEN_ELEMENT;
string++;
/* We found the end. */
possibly_incomplete = 0;
} else {
/* Was any space skipped? */
if (is_sgml_space(string[-1])) {
/* We found the end. */
possibly_incomplete = 0;
}
scanner->state = SGML_STATE_ELEMENT;
type = SGML_TOKEN_ELEMENT_BEGIN;
}
@ -330,7 +485,8 @@ scan_sgml_element_token(struct dom_scanner *scanner, struct dom_scanner_token *t
string += 2;
type = SGML_TOKEN_NOTATION_COMMENT;
token->string.string = string;
real_length = skip_sgml_comment(scanner, &string);
real_length = skip_sgml_comment(scanner, &string,
&possibly_incomplete);
assert(real_length >= 0);
} else if (string + 6 < scanner->end
@ -339,13 +495,17 @@ scan_sgml_element_token(struct dom_scanner *scanner, struct dom_scanner_token *t
string += 7;
type = SGML_TOKEN_CDATA_SECTION;
token->string.string = string;
real_length = skip_sgml_cdata_section(scanner, &string);
real_length = skip_sgml_cdata_section(scanner, &string,
&possibly_incomplete);
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);
skip_sgml(scanner, &string, '>', 0);
if (skip_sgml(scanner, &string, '>', 0)) {
/* We found the end. */
possibly_incomplete = 0;
}
}
} else if (*string == '?') {
@ -361,6 +521,16 @@ scan_sgml_element_token(struct dom_scanner *scanner, struct dom_scanner_token *t
scanner->state = SGML_STATE_PROC_INST;
real_length = string - token->string.string;
skip_sgml_space(scanner, &string);
/* Make '<?xml ' cause the right kind of error. */
if (is_sgml_space(string[-1])
&& string < scanner->end) {
/* We found the end. */
possibly_incomplete = 0;
}
} else if (*string == '/') {
string++;
skip_sgml_space(scanner, &string);
@ -371,12 +541,18 @@ scan_sgml_element_token(struct dom_scanner *scanner, struct dom_scanner_token *t
real_length = string - token->string.string;
type = SGML_TOKEN_ELEMENT_END;
skip_sgml(scanner, &string, '>', 1);
if (skip_sgml(scanner, &string, '>', 1)) {
/* We found the end. */
possibly_incomplete = 0;
}
} else if (*string == '>') {
string++;
real_length = 0;
type = SGML_TOKEN_ELEMENT_END;
/* We found the end. */
possibly_incomplete = 0;
}
if (type != SGML_TOKEN_GARBAGE)
@ -384,15 +560,28 @@ scan_sgml_element_token(struct dom_scanner *scanner, struct dom_scanner_token *t
} else {
/* Alien < > stuff so ignore it */
skip_sgml(scanner, &string, '>', 0);
if (skip_sgml(scanner, &string, '>', 0)) {
/* We found the end. */
possibly_incomplete = 0;
}
}
} else if (first_char == '=') {
type = '=';
/* We found the end. */
possibly_incomplete = 0;
} else if (first_char == '?' || first_char == '>') {
if (first_char == '?') {
skip_sgml(scanner, &string, '>', 0);
if (skip_sgml(scanner, &string, '>', 0)) {
/* We found the end. */
possibly_incomplete = 0;
}
} else {
assert(first_char == '>');
/* We found the end. */
possibly_incomplete = 0;
}
type = SGML_TOKEN_TAG_END;
@ -400,17 +589,33 @@ scan_sgml_element_token(struct dom_scanner *scanner, struct dom_scanner_token *t
scanner->state = SGML_STATE_TEXT;
} else if (first_char == '/') {
/* We allow '/' inside elements and only consider it as an end
* tag if immediately preceeds the '>' char. This is to allow
*
* '<form action=/ >' where '/' is part of a path and
* '<form action=a />' where '/>' is truely a tag end
*
* For stricter parsing we should always require attribute
* values to be quoted.
*/
if (*string == '>') {
string++;
real_length = 0;
type = SGML_TOKEN_ELEMENT_EMPTY_END;
assert(scanner->state == SGML_STATE_ELEMENT);
scanner->state = SGML_STATE_TEXT;
/* We found the end. */
possibly_incomplete = 0;
} else if (is_sgml_attribute(*string)) {
scan_sgml_attribute(scanner, string);
type = SGML_TOKEN_ATTRIBUTE;
if (string[-1] == '/' && string[0] == '>')
if (string[-1] == '/' && string[0] == '>') {
string--;
/* We found the end. */
possibly_incomplete = 0;
}
}
} else if (isquote(first_char)) {
@ -422,6 +627,10 @@ scan_sgml_element_token(struct dom_scanner *scanner, struct dom_scanner_token *t
real_length = string_end - token->string.string;
string = string_end + 1;
type = SGML_TOKEN_STRING;
/* We found the end. */
possibly_incomplete = 0;
} else if (is_sgml_attribute(*string)) {
token->string.string++;
scan_sgml_attribute(scanner, string);
@ -437,8 +646,27 @@ scan_sgml_element_token(struct dom_scanner *scanner, struct dom_scanner_token *t
if (is_sgml_attribute(*string)) {
scan_sgml_attribute(scanner, string);
type = SGML_TOKEN_ATTRIBUTE;
if (string[-1] == '/' && string[0] == '>')
if (string[-1] == '/' && string[0] == '>') {
/* We found the end. */
possibly_incomplete = 0;
string--;
}
}
}
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;
}
}
@ -455,6 +683,8 @@ static inline void
scan_sgml_proc_inst_token(struct dom_scanner *scanner, struct dom_scanner_token *token)
{
unsigned char *string = scanner->position;
/* The length can be empty for '<??>'. */
size_t length = -1;
token->string.string = string;
@ -464,14 +694,30 @@ scan_sgml_proc_inst_token(struct dom_scanner *scanner, struct dom_scanner_token
for ( ; (string = skip_sgml_chars(scanner, string, '>')); string++) {
if (string[-1] == '?') {
string++;
length = string - token->string.string - 2;
break;
}
}
if (!string) string = scanner->end;
if (!string) {
/* 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;
token->string.length = string - token->string.string - 2;
token->string.length = length >= 0 ? length : string - token->string.string;
token->precedence = get_sgml_precedence(token->type);
scanner->position = string;
scanner->state = SGML_STATE_TEXT;
@ -484,36 +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 {
skip_sgml_space(scanner, &scanner->position);
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

@ -48,6 +48,14 @@ enum sgml_token_type {
/* A special token for unrecognized strings */
SGML_TOKEN_GARBAGE,
/* A special token for marking that it is assummed that the token is
* 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

@ -213,7 +213,7 @@ pop_dom_node(struct dom_stack *stack)
call_dom_stack_callbacks(stack, state, DOM_STACK_POP);
if (!(stack->flags & DOM_STACK_KEEP_NODES))
if (stack->flags & DOM_STACK_FLAG_FREE_NODES)
done_dom_node(state->node);
stack->depth--;

View File

@ -7,73 +7,110 @@
struct dom_stack;
/** DOM stack callback
*
* Used by contexts, for 'hooking' into the node traversing. */
typedef void (*dom_stack_callback_T)(struct dom_stack *, struct dom_node *, void *);
#define DOM_STACK_MAX_DEPTH 4096
/** DOM stack state
*
* This state records what node and where it is placed. */
struct dom_stack_state {
/** The node assiciated with the state */
struct dom_node *node;
/* The depth of the state in the stack. This is amongst other things
/**
* The depth of the state in the stack. This is amongst other things
* used to get the state object data. */
unsigned int depth;
/* Wether this stack state can be popped with pop_dom_*() family. */
/** Whether this stack state can be popped with pop_dom_*() family. */
unsigned int immutable:1;
};
/** DOM stack context info
*
* To add a DOM stack context define this struct either statically or on the
* stack. */
struct dom_stack_context_info {
/* The @object_size member tells whether the stack should allocate
* objects for each state to be assigned to the state's @data member.
* Zero means no state data should be allocated. */
/**
* This member tells whether the stack should allocate objects for each
* state to be assigned to the state's @data member. Zero means no
* state data should be allocated. */
size_t object_size;
/* Callbacks to be called when pushing and popping nodes. */
/** Callbacks to be called when pushing nodes. */
dom_stack_callback_T push[DOM_NODES];
/** Callbacks to be called when popping nodes. */
dom_stack_callback_T pop[DOM_NODES];
};
/** DOM stack context
*
* This holds 'runtime' data for the stack context. */
struct dom_stack_context {
/* Data specific to the context. */
/** Data specific to the context. */
void *data;
/* This is one big array of context specific objects. */
/* For the SGML parser this holds DTD-oriented info about the node
* (recorded in struct sgml_node_info). E.g. whether an element node
* is optional. */
/**
* This is one big array of context specific objects. For the SGML
* parser this holds DTD-oriented info about the node (recorded in
* struct sgml_node_info). E.g. whether an element node is optional.
*/
unsigned char *state_objects;
/* Info about node callbacks and such. */
/** Info about node callbacks and such. */
struct dom_stack_context_info *info;
};
/** Flags for controlling the DOM stack */
enum dom_stack_flag {
/* Keep nodes when popping them or call done_dom_node() on them. */
DOM_STACK_KEEP_NODES = 1,
/** No flag needed. */
DOM_STACK_FLAG_NONE = 0,
/** Free nodes when popping by calling ref:[done_dom_node]. */
DOM_STACK_FLAG_FREE_NODES = 1,
};
/* The DOM stack is a convenient way to traverse DOM trees. Also it
/** The DOM stack
*
* The DOM stack is a convenient way to traverse DOM trees. Also it
* maintains needed state info and is therefore also a holder of the current
* context since the stack is used to when the DOM tree is manipulated. */
struct dom_stack {
/* The stack of nodes */
/** The states currently on the stack. */
struct dom_stack_state *states;
/** The depth of the stack. */
size_t depth;
/** Flags given to ref:[init_dom_stack]. */
enum dom_stack_flag flags;
/* Contexts for the pushed and popped nodes. */
/** Contexts for the pushed and popped nodes. */
struct dom_stack_context **contexts;
/** The number of active contexts. */
size_t contexts_size;
/* The current context. */
/* XXX: Only meaningful within dom_stack_callback_T functions. */
/**
* The current context. Only meaningful within
* ref:[dom_stack_callback_T] functions. */
struct dom_stack_context *current;
};
/** Check whether stack is empty or not
*
* stack:: The stack to check.
*
* Returns non-zero if stack is empty. */
#define dom_stack_is_empty(stack) \
(!(stack)->states || (stack)->depth == 0)
/** Access state by offset from top
*
* stack:: The stack to fetch the state from.
* top_offset:: The offset from the stack top, zero is the top.
*
* Returns the requested state. */
static inline struct dom_stack_state *
get_dom_stack_state(struct dom_stack *stack, int top_offset)
{
@ -82,8 +119,24 @@ get_dom_stack_state(struct dom_stack *stack, int top_offset)
return &stack->states[stack->depth - 1 - top_offset];
}
#define get_dom_stack_top(stack) get_dom_stack_state(stack, 0)
/** Access the stack top
*
* stack:: The stack to get the top state from.
*
* Returns the top state. */
#define get_dom_stack_top(stack) \
get_dom_stack_state(stack, 0)
/** Access context specific state data
*
* Similar to ref:[get_dom_stack_state], this will fetch the data
* associated with the state for the given context.
*
* context:: The context to get data from.
* state:: The stack state to get data from.
*
* Returns the state data or NULL if ref:[dom_stack_context_info.object_size]
* was zero. */
static inline void *
get_dom_stack_state_data(struct dom_stack_context *context,
struct dom_stack_state *state)
@ -97,25 +150,36 @@ get_dom_stack_state_data(struct dom_stack_context *context,
return (void *) &context->state_objects[state->depth * object_size];
}
/* Define to have debug info about the nodes added printed to the log.
* Run as: ELINKS_LOG=/tmp/dom-dump.txt ./elinks -no-connect <url>
* to have the debug dumped into a file. */
/*#define DOM_STACK_TRACE*/
#ifdef DOM_STACK_TRACE
extern struct dom_stack_context_info dom_stack_trace_context_info;
/** Get debug info from the DOM stack
*
* Define `DOM_STACK_TRACE` to have debug info about the nodes added printed to
* the log. It will define add_dom_stack_tracer() to not be a no-op.
*
* Run as:
*
* ELINKS_LOG=/tmp/dom-dump.txt ./elinks -no-connect <url>
*
* to have the debug dumped into a file. */
#define add_dom_stack_tracer(stack, name) \
add_dom_stack_context(stack, name, &dom_stack_trace_context_info)
#else
#define add_dom_stack_tracer(stack, name) /* Nada */
#endif
/* The state iterators do not include the bottom state */
/** The state iterators
*
* To safely iterate through the stack state iterators. */
/** Iterate the stack from bottom to top. */
#define foreach_dom_stack_state(stack, state, pos) \
for ((pos) = 0; (pos) < (stack)->depth; (pos)++) \
if (((state) = &(stack)->states[(pos)]))
/** Iterate the stack from top to bottom. */
#define foreachback_dom_stack_state(stack, state, pos) \
for ((pos) = (stack)->depth - 1; (pos) >= 0; (pos)--) \
if (((state) = &(stack)->states[(pos)]))
@ -123,41 +187,96 @@ extern struct dom_stack_context_info dom_stack_trace_context_info;
/* Life cycle functions. */
/** Initialise a DOM stack
* stack:: Pointer to a (preallocated) stack.
* flags:: Any flags needed for controlling the behaviour of the stack.
*/
void init_dom_stack(struct dom_stack *stack, enum dom_stack_flag flags);
/** Release a DOM stack
*
* Free all resources collected by the stack.
*
* stack:: The stack to release. */
void done_dom_stack(struct dom_stack *stack);
/* Add a context to the stack. This is needed if either you want to have the
* stack allocated objects for created states and/or if you want to install
* callbacks for pushing or popping. . */
/** Add a context to the stack
*
* This is needed if either you want to have the stack allocated objects for
* created states and/or if you want to install callbacks for pushing or
* popping.
*
* stack:: The stack where the context should be created.
* data:: Private data to be stored in ref:[dom_stack_context.data].
* context_info:: Information about state objects and node callbacks.
*
* Returns a pointer to the newly created context or NULL. */
struct dom_stack_context *
add_dom_stack_context(struct dom_stack *stack, void *data,
struct dom_stack_context_info *context_info);
/* Unregister a stack @context. This should be done especially for temporary
* stack contexts (without any callbacks) so that they do not increasing the
* memory usage. */
/** Unregister a stack context
* This should be done especially for temporary stack contexts (without any
* callbacks) so that they do not increasing the memory usage. */
void done_dom_stack_context(struct dom_stack *stack, struct dom_stack_context *context);
/* Decends down to the given node making it the current parent */
/* If an error occurs the node is free()d and NULL is returned */
/** Push a node onto the stack
*
* Makes the pushed node the new top of the stack.
*
* stack:: The stack to push onto.
* node:: The node to push onto the stack.
*
* If an error occurs the node is released with ref:[done_dom_node] and NULL is
* returned. Else the pushed node is returned. */
struct dom_node *push_dom_node(struct dom_stack *stack, struct dom_node *node);
/* Ascends the stack to the current parent */
/** Pop the top stack state
*
* stack:: The stack to pop from. */
void pop_dom_node(struct dom_stack *stack);
/* Ascends the stack looking for specific parent */
/** Conditionally pop the stack states
*
* Searches the stack (using ref:[search_dom_stack]) for a specific node and
* pops all states until that particular state is met.
*
* NOTE: The popping is stopped if an immutable state is encountered. */
void pop_dom_nodes(struct dom_stack *stack, enum dom_node_type type,
struct dom_string *string);
/* Pop all stack states until a specific state is reached. */
/** Pop all states until target state
*
* Pop all stack states until a specific state is reached. The target state
* is also popped.
*
* stack:: The stack to pop from.
* target:: The state to pop until and including. */
void pop_dom_state(struct dom_stack *stack, struct dom_stack_state *target);
/* Dive through the stack states in search for the specified match. */
/** Search the stack states
*
* The string comparison is done against the ref:[dom_node.string] member of
* the of the state nodes.
*
* stack:: The stack to search in.
* type:: The type of node to match against.
* string:: The string to match against.
*
* Returns a state that matched the type and string or NULL. */
struct dom_stack_state *
search_dom_stack(struct dom_stack *stack, enum dom_node_type type,
struct dom_string *string);
/* Visit each node in the tree rooted at @root pre-order */
/** Walk all nodes reachable from a given node
*
* Visits each node in the DOM tree rooted at a given node, pre-order style.
*
* stack:: The stack to use for walking the nodes.
* root:: The root node to start from.
*
* It is assummed that the given stack has been initialised with
* ref:[init_dom_stack] and that the caller already added one or more
* context to the stack. */
void walk_dom_nodes(struct dom_stack *stack, struct dom_node *root);
#endif

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

@ -11,33 +11,7 @@ TESTDEPS = \
$(top_builddir)/src/util/error.o \
$(top_builddir)/src/osdep/stub.o \
$(top_builddir)/src/util/hash.o \
$(top_builddir)/src/util/memdebug.o \
$(top_builddir)/src/util/string.o \
$(top_builddir)/src/util/memory.o
$(TEST_PROGS): $(TESTDEPS) $$@.o
$(call cmd,link)
TESTS = $(wildcard test-*)
$(TESTS): $(TEST_PROGS)
@echo "*** $@ ***"; $(call shellquote,$(SHELL)) $@ $(TEST_OPTS)
test: $(TESTS)
clean-local:
@rm -fr trash
CLEAN += $(TEST_PROGS) $(patsubst %,%.o,$(TEST_PROGS))
.PHONY: $(TESTS)
.NOPARALLEL:
include $(top_srcdir)/Makefile.lib
# Shell quote;
# Result of this needs to be placed inside ''
# XXX: Placed here because Vim cannot highlight things right afterwards
shq = $(subst ','\'',$(1))
# This has surrounding ''
shellquote = '$(call shq,$(1))'

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

@ -16,6 +16,24 @@
#include "dom/stack.h"
unsigned int number_of_lines = 0;
static int
update_number_of_lines(struct dom_stack *stack)
{
struct sgml_parser *parser = stack->contexts[0]->data;
int lines;
if (!(parser->flags & SGML_PARSER_COUNT_LINES))
return 0;
lines = get_sgml_parser_line_number(parser);
if (number_of_lines < lines)
number_of_lines = lines;
return 1;
}
/* Print the string in a compressed form: a single line with newlines etc.
* replaced with "\\n" sequence. */
static void
@ -72,14 +90,25 @@ static unsigned char indent_string[] =
#define get_indent_offset(stack) \
(((stack)->depth < sizeof(indent_string)/2 ? (stack)->depth * 2 : sizeof(indent_string)) - 2)
static void
print_indent(struct dom_stack *stack)
{
printf("%.*s", get_indent_offset(stack), indent_string);
}
static void
sgml_parser_test_tree(struct dom_stack *stack, struct dom_node *node, void *data)
{
struct dom_string *value = &node->string;
struct dom_string *name = get_dom_node_name(node);
printf("%.*s%.*s: %.*s\n",
get_indent_offset(stack), indent_string,
/* Always print the URI for identification. */
if (update_number_of_lines(stack))
return;
print_indent(stack);
printf("%.*s: %.*s\n",
name->length, name->string,
value->length, value->string);
}
@ -92,12 +121,16 @@ sgml_parser_test_id_leaf(struct dom_stack *stack, struct dom_node *node, void *d
assert(node);
if (update_number_of_lines(stack))
return;
name = get_dom_node_name(node);
id = get_dom_node_type_name(node->type);
printf("%.*s%.*s: %.*s -> ",
get_indent_offset(stack), indent_string,
id->length, id->string, name->length, name->string);
print_indent(stack);
printf("%.*s: %.*s -> ",
id->length, id->string,
name->length, name->string);
print_dom_node_value(node);
printf("\n");
}
@ -109,10 +142,13 @@ sgml_parser_test_leaf(struct dom_stack *stack, struct dom_node *node, void *data
assert(node);
if (update_number_of_lines(stack))
return;
name = get_dom_node_name(node);
printf("%.*s%.*s: ",
get_indent_offset(stack), indent_string,
print_indent(stack);
printf("%.*s: ",
name->length, name->string);
print_dom_node_value(node);
printf("\n");
@ -126,14 +162,28 @@ sgml_parser_test_branch(struct dom_stack *stack, struct dom_node *node, void *da
assert(node);
if (update_number_of_lines(stack))
return;
name = get_dom_node_name(node);
id = get_dom_node_type_name(node->type);
printf("%.*s%.*s: %.*s\n",
get_indent_offset(stack), indent_string,
print_indent(stack);
printf("%.*s: %.*s\n",
id->length, id->string, name->length, name->string);
}
static void
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)
&& !(parser->flags & SGML_PARSER_DETECT_ERRORS)) {
printf("%d\n", number_of_lines);
}
}
struct dom_stack_context_info sgml_parser_test_context_info = {
/* Object size: */ 0,
/* Push: */
@ -163,13 +213,22 @@ struct dom_stack_context_info sgml_parser_test_context_info = {
/* DOM_NODE_ENTITY */ NULL,
/* DOM_NODE_PROC_INSTRUCTION */ NULL,
/* DOM_NODE_COMMENT */ NULL,
/* DOM_NODE_DOCUMENT */ NULL,
/* DOM_NODE_DOCUMENT */ sgml_parser_test_end,
/* DOM_NODE_DOCUMENT_TYPE */ NULL,
/* DOM_NODE_DOCUMENT_FRAGMENT */ NULL,
/* DOM_NODE_NOTATION */ NULL,
}
};
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, ...)
{
@ -188,9 +247,11 @@ void die(const char *msg, ...)
int
main(int argc, char *argv[])
{
struct dom_node *root;
struct sgml_parser *parser;
enum sgml_document_type doctype = SGML_DOCTYPE_HTML;
enum sgml_parser_flag flags = 0;
enum sgml_parser_code code = 0;
int complete = 1;
struct dom_string uri = INIT_DOM_STRING("dom://test", -1);
struct dom_string source = INIT_DOM_STRING("(no source)", -1);
int i;
@ -227,6 +288,16 @@ main(int argc, char *argv[])
set_dom_string(&source, argv[i], strlen(argv[i]));
}
} else if (!strcmp(arg, "print-lines")) {
flags |= SGML_PARSER_COUNT_LINES;
} else if (!strcmp(arg, "incomplete")) {
flags |= SGML_PARSER_INCREMENTAL;
complete = 0;
} else if (!strcmp(arg, "error")) {
flags |= SGML_PARSER_DETECT_ERRORS;
} else if (!strcmp(arg, "help")) {
die(NULL);
@ -235,22 +306,27 @@ main(int argc, char *argv[])
}
}
parser = init_sgml_parser(SGML_PARSER_STREAM, doctype, &uri);
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);
root = parse_sgml(parser, &source);
if (root) {
assert(parser->stack.depth == 1);
code = parse_sgml(parser, &source, complete);
if (parser->root) {
size_t root_offset = parser->stack.depth - 1;
assert(!complete || root_offset == 0);
get_dom_stack_state(&parser->stack, root_offset)->immutable = 0;
get_dom_stack_top(&parser->stack)->immutable = 0;
/* For SGML_PARSER_STREAM this will free the DOM
* root node. */
pop_dom_node(&parser->stack);
while (!dom_stack_is_empty(&parser->stack))
pop_dom_node(&parser->stack);
}
done_sgml_parser(parser);
return 0;
return code;
}

View File

@ -9,12 +9,12 @@ This test runs very basic features, like checking that nodes are placed
correctly in the DOM tree.
'
. ./libtest
. "$TEST_LIB"
test_output_equals () {
desc="$1"
src="$2"
out="$3"
desc="$1"; shift
src="$1"; shift
out="$1"; shift
URI="test:$(echo "$desc" | sed '
s/^[ \t]*\[[^]]*\][ \t]*//;
@ -28,7 +28,7 @@ test_output_equals () {
echo "#document: $URI" > expected
echo "$out" | sed -n '2,$p' >> expected
test_expect_success "$desc" 'cmp -b output expected'
test_expect_success "$desc" 'cmp output expected'
}
@ -55,6 +55,16 @@ element: root
element: child3
#text: a'
test_output_equals \
'Parse tag soup elements.' \
'<parent attr="value" <child:1></><child:2</>a</parent>' \
'
element: parent
attribute: attr -> value
element: child:1
element: child:2
#text: a'
test_output_equals \
'Parse an enclosed comment.' \
'<root><!-- Hello World! --></root>' \
@ -63,7 +73,7 @@ element: root
#comment: Hello World! '
test_output_equals \
'Parse comment combinations.' \
'Parse comment combinations. (I)' \
'<root><!-- <!-- -- > --><!--foo--><!----></root>' \
'
element: root
@ -71,12 +81,29 @@ element: root
#comment: foo
#comment: '
test_output_equals \
'Parse comment combinations. (II).' \
'<! -- comment -->s<!-->-->t<!----->u' \
'
#comment: comment
#text: s
#comment: >
#text: t
#comment: -
#text: u'
test_output_equals \
'Parse bad comment.' \
'<!--->s' \
'
#comment: ->s'
test_output_equals \
'Parse empty notation.' \
'<!>s' \
'
#text: s'
test_output_equals \
'Parse an enclosed CDATA section.' \
'<root><![CDATA[...] ]>...]]></root>' \
@ -167,7 +194,7 @@ test_output_equals \
'
proc-instruction: xml -> version="1.0" />
attribute: version -> 1.0
proc-instruction: xml -> /'
proc-instruction: xml -> />-'
test_output_equals \
'Parse XML stylesheet processing instructions.' \

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

@ -2,7 +2,10 @@ top_builddir=../..
include $(top_builddir)/Makefile.config
INCLUDES += $(SPIDERMONKEY_CFLAGS)
SUBDIRS = spidermonkey
OBJS = ecmascript.o spidermonkey.o
SUBDIRS-$(CONFIG_SPIDERMONKEY) += spidermonkey
SUBDIRS-$(CONFIG_SEE) += see
OBJS-$(CONFIG_SPIDERMONKEY) += spidermonkey.o
OBJS-$(CONFIG_SEE) += see.o
OBJS = ecmascript.o
include $(top_srcdir)/Makefile.lib

View File

@ -12,7 +12,6 @@
#include "document/document.h"
#include "document/view.h"
#include "ecmascript/ecmascript.h"
#include "ecmascript/spidermonkey.h"
#include "intl/gettext/libintl.h"
#include "main/module.h"
#include "protocol/uri.h"
@ -61,49 +60,6 @@ static struct option_info ecmascript_options[] = {
NULL_OPTION_INFO,
};
#define get_ecmascript_enable() get_opt_bool("ecmascript.enable")
static void
ecmascript_init(struct module *module)
{
spidermonkey_init();
}
static void
ecmascript_done(struct module *module)
{
spidermonkey_done();
}
struct ecmascript_interpreter *
ecmascript_get_interpreter(struct view_state *vs)
{
struct ecmascript_interpreter *interpreter;
assert(vs);
interpreter = mem_calloc(1, sizeof(*interpreter));
if (!interpreter)
return NULL;
interpreter->vs = vs;
init_list(interpreter->onload_snippets);
spidermonkey_get_interpreter(interpreter);
return interpreter;
}
void
ecmascript_put_interpreter(struct ecmascript_interpreter *interpreter)
{
assert(interpreter);
spidermonkey_put_interpreter(interpreter);
free_string_list(&interpreter->onload_snippets);
mem_free(interpreter);
}
void
ecmascript_reset_state(struct view_state *vs)
{
@ -124,40 +80,6 @@ ecmascript_reset_state(struct view_state *vs)
vs->ecmascript_fragile = 1;
}
void
ecmascript_eval(struct ecmascript_interpreter *interpreter,
struct string *code)
{
if (!get_ecmascript_enable())
return;
assert(interpreter);
spidermonkey_eval(interpreter, code);
}
unsigned char *
ecmascript_eval_stringback(struct ecmascript_interpreter *interpreter,
struct string *code)
{
if (!get_ecmascript_enable())
return NULL;
assert(interpreter);
return spidermonkey_eval_stringback(interpreter, code);
}
int
ecmascript_eval_boolback(struct ecmascript_interpreter *interpreter,
struct string *code)
{
if (!get_ecmascript_enable())
return -1;
assert(interpreter);
return spidermonkey_eval_boolback(interpreter, code);
}
void
ecmascript_protocol_handler(struct session *ses, struct uri *uri)
{
@ -197,6 +119,20 @@ ecmascript_protocol_handler(struct session *ses, struct uri *uri)
}
void
ecmascript_timeout_dialog(struct terminal *term, int max_exec_time)
{
info_box(term, MSGBOX_FREE_TEXT,
N_("JavaScript Emergency"), ALIGN_LEFT,
msg_text(term,
N_("A script embedded in the current document was running\n"
"for more than %d seconds. This probably means there is\n"
"a bug in the script and it could have halted the whole\n"
"ELinks, so the script execution was interrupted."),
max_exec_time));
}
struct module ecmascript_module = struct_module(
/* name: */ N_("ECMAScript"),
/* options: */ ecmascript_options,

View File

@ -9,9 +9,12 @@
#include "util/time.h"
struct string;
struct terminal;
struct uri;
struct view_state;
#define get_ecmascript_enable() get_opt_bool("ecmascript.enable")
struct ecmascript_interpreter {
struct view_state *vs;
void *backend_data;
@ -63,6 +66,11 @@ int ecmascript_eval_boolback(struct ecmascript_interpreter *interpreter, struct
* follows a link with this synstax. */
void ecmascript_protocol_handler(struct session *ses, struct uri *uri);
void ecmascript_init(struct module *);
void ecmascript_done(struct module *);
void ecmascript_timeout_dialog(struct terminal *term, int max_exec_time);
extern struct module ecmascript_module;
#endif

243
src/ecmascript/see.c Normal file
View File

@ -0,0 +1,243 @@
/* The SEE ECMAScript backend. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "elinks.h"
#include <see/see.h>
#include "bfu/dialog.h"
#include "cache/cache.h"
#include "cookies/cookies.h"
#include "dialogs/menu.h"
#include "dialogs/status.h"
#include "document/html/frames.h"
#include "document/document.h"
#include "document/forms.h"
#include "document/view.h"
#include "ecmascript/ecmascript.h"
#include "ecmascript/see.h"
#include "ecmascript/see/document.h"
#include "ecmascript/see/form.h"
#include "ecmascript/see/input.h"
#include "ecmascript/see/location.h"
#include "ecmascript/see/navigator.h"
#include "ecmascript/see/strings.h"
#include "ecmascript/see/unibar.h"
#include "ecmascript/see/window.h"
#include "intl/gettext/libintl.h"
#include "main/select.h"
#include "osdep/newwin.h"
#include "osdep/sysname.h"
#include "protocol/http/http.h"
#include "protocol/uri.h"
#include "session/history.h"
#include "session/location.h"
#include "session/session.h"
#include "session/task.h"
#include "terminal/tab.h"
#include "terminal/terminal.h"
#include "util/conv.h"
#include "util/string.h"
#include "viewer/text/draw.h"
#include "viewer/text/form.h"
#include "viewer/text/link.h"
#include "viewer/text/vs.h"
/*** Global methods */
/* TODO? Are there any which need to be implemented? */
/*** The ELinks interface */
void
ecmascript_init(struct module *module)
{
see_init();
}
void
ecmascript_done(struct module *module)
{
see_done();
}
struct ecmascript_interpreter *
ecmascript_get_interpreter(struct view_state *vs)
{
struct ecmascript_interpreter *interpreter;
assert(vs);
interpreter = mem_calloc(1, sizeof(*interpreter));
if (!interpreter)
return NULL;
interpreter->vs = vs;
init_list(interpreter->onload_snippets);
see_get_interpreter(interpreter);
return interpreter;
}
void
ecmascript_put_interpreter(struct ecmascript_interpreter *interpreter)
{
assert(interpreter);
see_put_interpreter(interpreter);
free_string_list(&interpreter->onload_snippets);
mem_free(interpreter);
}
void
ecmascript_eval(struct ecmascript_interpreter *interpreter,
struct string *code)
{
if (!get_ecmascript_enable())
return;
assert(interpreter);
see_eval(interpreter, code);
}
unsigned char *
ecmascript_eval_stringback(struct ecmascript_interpreter *interpreter,
struct string *code)
{
if (!get_ecmascript_enable())
return NULL;
assert(interpreter);
return see_eval_stringback(interpreter, code);
}
int
ecmascript_eval_boolback(struct ecmascript_interpreter *interpreter,
struct string *code)
{
if (!get_ecmascript_enable())
return -1;
assert(interpreter);
return see_eval_boolback(interpreter, code);
}
void
see_init(void)
{
init_intern_strings();
}
void
see_done(void)
{
}
void *
see_get_interpreter(struct ecmascript_interpreter *interpreter)
{
struct global_object *g = SEE_NEW(NULL, struct global_object);
struct SEE_interpreter *interp = &g->interp;
interpreter->backend_data = g;
g->max_exec_time = get_opt_int("ecmascript.max_exec_time");
g->exec_start = time(NULL);
SEE_interpreter_init(interp);
init_js_window_object(interpreter);
init_js_menubar_object(interpreter);
init_js_statusbar_object(interpreter);
init_js_navigator_object(interpreter);
init_js_history_object(interpreter);
init_js_location_object(interpreter);
init_js_document_object(interpreter);
init_js_forms_object(interpreter);
return interp;
}
void
see_put_interpreter(struct ecmascript_interpreter *interpreter)
{
interpreter->backend_data = NULL;
}
void
see_eval(struct ecmascript_interpreter *interpreter,
struct string *code)
{
struct SEE_interpreter *interp = interpreter->backend_data;
struct global_object *g = (struct global_object *)interp;
struct SEE_input *input = SEE_input_elinks(interp, code->source);
SEE_try_context_t try_ctxt;
struct SEE_value result;
struct SEE_value v;
g->exec_start = time(NULL);
SEE_TRY(interp, try_ctxt) {
SEE_Global_eval(interp, input, &result);
}
SEE_INPUT_CLOSE(input);
SEE_CAUGHT(try_ctxt);
}
unsigned char *
see_eval_stringback(struct ecmascript_interpreter *interpreter,
struct string *code)
{
struct SEE_interpreter *interp = interpreter->backend_data;
struct global_object *g = (struct global_object *)interp;
struct SEE_input *input = SEE_input_elinks(interp, code->source);
SEE_try_context_t try_ctxt;
struct SEE_value result;
unsigned char *string = NULL;
g->exec_start = time(NULL);
SEE_TRY(interp, try_ctxt) {
SEE_Global_eval(interp, input, &result);
if (SEE_VALUE_GET_TYPE(&result) != SEE_NULL)
string = SEE_value_to_unsigned_char(interp, &result);
}
SEE_INPUT_CLOSE(input);
if (SEE_CAUGHT(try_ctxt)) {
return NULL;
}
return string;
}
int
see_eval_boolback(struct ecmascript_interpreter *interpreter,
struct string *code)
{
struct SEE_interpreter *interp = interpreter->backend_data;
struct global_object *g = (struct global_object *)interp;
struct SEE_input *input = SEE_input_elinks(interp, code->source);
SEE_try_context_t try_ctxt;
struct SEE_value result;
SEE_int32_t res = 0;
g->exec_start = time(NULL);
SEE_TRY(interp, try_ctxt) {
SEE_Global_eval(interp, input, &result);
/* history.back() returns SEE_NULL */
if (SEE_VALUE_GET_TYPE(&result) == SEE_NULL)
res = 0;
else
res = SEE_ToInt32(interp, &result);
}
SEE_INPUT_CLOSE(input);
if (SEE_CAUGHT(try_ctxt)) {
return -1;
}
return res;
}

17
src/ecmascript/see.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef EL__ECMASCRIPT_SEE_H
#define EL__ECMASCRIPT_SEE_H
struct ecmascript_interpreter;
struct string;
void see_init();
void see_done();
void *see_get_interpreter(struct ecmascript_interpreter *interpreter);
void see_put_interpreter(struct ecmascript_interpreter *interpreter);
void see_eval(struct ecmascript_interpreter *interpreter, struct string *code);
unsigned char *see_eval_stringback(struct ecmascript_interpreter *interpreter, struct string *code);
int see_eval_boolback(struct ecmascript_interpreter *interpreter, struct string *code);
#endif

View File

@ -0,0 +1,6 @@
top_builddir=../../..
include $(top_builddir)/Makefile.config
OBJS = document.o form.o input.o location.o navigator.o strings.o unibar.o window.o
include $(top_srcdir)/Makefile.lib

View File

@ -0,0 +1,257 @@
/* The SEE document object implementation. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include "elinks.h"
#include <see/see.h>
#include "bfu/dialog.h"
#include "cache/cache.h"
#include "cookies/cookies.h"
#include "dialogs/menu.h"
#include "dialogs/status.h"
#include "document/html/frames.h"
#include "document/document.h"
#include "document/forms.h"
#include "document/view.h"
#include "ecmascript/ecmascript.h"
#include "ecmascript/see/document.h"
#include "ecmascript/see/form.h"
#include "ecmascript/see/input.h"
#include "ecmascript/see/strings.h"
#include "ecmascript/see/window.h"
#include "intl/gettext/libintl.h"
#include "main/select.h"
#include "osdep/newwin.h"
#include "osdep/sysname.h"
#include "protocol/http/http.h"
#include "protocol/uri.h"
#include "session/history.h"
#include "session/location.h"
#include "session/session.h"
#include "session/task.h"
#include "terminal/tab.h"
#include "terminal/terminal.h"
#include "util/conv.h"
#include "util/memory.h"
#include "util/string.h"
#include "viewer/text/draw.h"
#include "viewer/text/form.h"
#include "viewer/text/link.h"
#include "viewer/text/vs.h"
static void document_get(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *);
static void document_put(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *, int);
static int document_canput(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *);
static int document_hasproperty(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *);
static void js_document_write(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
void location_goto(struct document_view *, unsigned char *);
struct SEE_objectclass js_document_object_class = {
NULL,
document_get,
document_put,
document_canput,
document_hasproperty,
SEE_no_delete,
SEE_no_defaultvalue,
NULL,
NULL,
NULL,
NULL
};
static void
document_get(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p, struct SEE_value *res)
{
struct global_object *g = (struct global_object *)interp;
struct js_window_object *win = g->win;
struct view_state *vs = win->vs;
struct document_view *doc_view = vs->doc_view;
struct document *document = doc_view->document;
struct js_document_object *doc = (struct js_document_object *)o;
struct session *ses = doc_view->session;
struct SEE_string *str;
unsigned char *string;
checktime(interp);
SEE_SET_UNDEFINED(res);
if (p == s_cookie) {
#ifdef CONFIG_COOKIES
struct string *cookies = send_cookies(vs->uri);
if (cookies) {
static unsigned char cookiestr[1024];
strncpy(cookiestr, cookies->source, 1024);
done_string(cookies);
str = string_to_SEE_string(interp, cookiestr);
} else {
str = string_to_SEE_string(interp, "");
}
SEE_SET_STRING(res, str);
#endif
} else if (p == s_title) {
str = string_to_SEE_string(interp, document->title);
SEE_SET_STRING(res, str);
} else if (p == s_url) {
string = get_uri_string(document->uri, URI_ORIGINAL);
str = string_to_SEE_string(interp, string);
mem_free_if(string);
SEE_SET_STRING(res, str);
} else if (p == s_location) {
SEE_OBJECT_GET(interp, interp->Global, s_location, res);
} else if (p == s_referrer) {
switch (get_opt_int("protocol.http.referer.policy")) {
case REFERER_NONE:
SEE_SET_UNDEFINED(res);
break;
case REFERER_FAKE:
str = string_to_SEE_string(interp,
get_opt_str("protocol.http.referer.fake"));
SEE_SET_STRING(res, str);
break;
case REFERER_TRUE:
if (ses->referrer) {
string = get_uri_string(ses->referrer, URI_HTTP_REFERRER);
str = string_to_SEE_string(interp, string);
mem_free_if(string);
SEE_SET_STRING(res, str);
}
break;
case REFERER_SAME_URL:
string = get_uri_string(document->uri, URI_HTTP_REFERRER);
str = string_to_SEE_string(interp, string);
mem_free_if(string);
SEE_SET_STRING(res, str);
break;
}
} else if (p == s_forms) {
SEE_SET_OBJECT(res, doc->forms);
} else {
struct form *form;
unsigned char *string = SEE_string_to_unsigned_char(p);
struct form_view *form_view;
struct js_form *form_object;
foreach (form, document->forms) {
if (!form->name || strcasecmp(string, form->name))
continue;
mem_free_if(string);
form_view = find_form_view(doc_view, form);
form_object = js_get_form_object(interp, doc, form_view);
SEE_SET_OBJECT(res, (struct SEE_object *)form_object);
break;
}
}
}
static void
document_put(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p, struct SEE_value *val, int attr)
{
struct global_object *g = (struct global_object *)interp;
struct view_state *vs = g->win->vs;
struct document_view *doc_view = vs->doc_view;
struct document *document = doc_view->document;
struct js_document_object *doc = (struct js_document_object *)o;
struct SEE_value res;
unsigned char *string;
checktime(interp);
if (p == s_forms) {
SEE_ToObject(interp, val, &res);
doc->forms = res.u.object;
} else if (p == s_title) {
string = SEE_value_to_unsigned_char(interp, val);
mem_free_set(&document->title, string);
print_screen_status(doc_view->session);
} else if (p == s_location || p == s_url) {
/* According to the specs this should be readonly but some
* broken sites still assign to it (i.e.
* http://www.e-handelsfonden.dk/validering.asp?URL=www.polyteknisk.dk).
* So emulate window.location. */
string = SEE_value_to_unsigned_char(interp, val);
location_goto(doc_view, string);
mem_free_if(string);
} else if (p == s_cookie) {
#ifdef CONFIG_COOKIES
string = SEE_value_to_unsigned_char(interp, val);
set_cookie(vs->uri, string);
mem_free_if(string);
#endif
}
}
static void
js_document_write(struct SEE_interpreter *interp, struct SEE_object *self,
struct SEE_object *thisobj, int argc, struct SEE_value **argv,
struct SEE_value *res)
{
#ifdef CONFIG_LEDS
struct global_object *g = (struct global_object *)interp;
struct view_state *vs = g->win->vs;
/* XXX: I don't know about you, but I have *ENOUGH* of those 'Undefined
* function' errors, I want to see just the useful ones. So just
* lighting a led and going away, no muss, no fuss. --pasky */
/* TODO: Perhaps we can introduce ecmascript.error_report_unsupported
* -> "Show information about the document using some valid,
* nevertheless unsupported methods/properties." --pasky too */
set_led_value(vs->doc_view->session->status.ecmascript_led, 'J');
#endif
checktime(interp);
SEE_SET_BOOLEAN(res, 0);
}
static int
document_canput(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p)
{
checktime(interp);
if (p == s_location || p == s_url || p == s_cookie)
return 1;
return 0;
}
static int
document_hasproperty(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p)
{
checktime(interp);
/* all unknown properties return UNDEFINED value */
return 1;
}
void
init_js_document_object(struct ecmascript_interpreter *interpreter)
{
struct global_object *g = interpreter->backend_data;
struct SEE_interpreter *interp = &g->interp;
struct SEE_value v;
struct js_document_object *doc = SEE_NEW(interp,
struct js_document_object);
doc->object.objectclass = &js_document_object_class;
doc->object.objectclass->Class = s_document;
doc->object.Prototype = NULL;
SEE_SET_OBJECT(&v, (struct SEE_object *)doc);
SEE_OBJECT_PUT(interp, interp->Global, s_document, &v, 0);
doc->write = SEE_cfunction_make(interp, js_document_write, s_write, 1);
}

View File

@ -0,0 +1,14 @@
#ifndef EL__ECMASCRIPT_SEE_DOCUMENT_H
#define EL__ECMASCRIPT_SEE_DOCUMENT_H
struct ecmascript_interpreter;
struct js_document_object {
struct SEE_object object;
struct SEE_object *write;
struct SEE_object *forms;
};
void init_js_document_object(struct ecmascript_interpreter *);
#endif

964
src/ecmascript/see/form.c Normal file
View File

@ -0,0 +1,964 @@
/* The SEE form object implementation. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "elinks.h"
#include <see/see.h>
#include "bfu/dialog.h"
#include "cache/cache.h"
#include "cookies/cookies.h"
#include "dialogs/menu.h"
#include "dialogs/status.h"
#include "document/html/frames.h"
#include "document/document.h"
#include "document/forms.h"
#include "document/view.h"
#include "ecmascript/ecmascript.h"
#include "ecmascript/see/document.h"
#include "ecmascript/see/form.h"
#include "ecmascript/see/input.h"
#include "ecmascript/see/strings.h"
#include "ecmascript/see/window.h"
#include "intl/gettext/libintl.h"
#include "main/select.h"
#include "osdep/newwin.h"
#include "osdep/sysname.h"
#include "protocol/http/http.h"
#include "protocol/uri.h"
#include "session/history.h"
#include "session/location.h"
#include "session/session.h"
#include "session/task.h"
#include "terminal/tab.h"
#include "terminal/terminal.h"
#include "util/conv.h"
#include "util/memory.h"
#include "util/string.h"
#include "viewer/text/draw.h"
#include "viewer/text/form.h"
#include "viewer/text/link.h"
#include "viewer/text/vs.h"
static void input_get(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *);
static void input_put(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *, int);
static void js_input_blur(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
static void js_input_click(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
static void js_input_focus(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
static void js_input_select(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
static int input_canput(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *);
static int input_hasproperty(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *);
static struct js_input *js_get_input_object(struct SEE_interpreter *, struct js_form *, struct form_state *);
static struct js_input *js_get_form_control_object(struct SEE_interpreter *, struct js_form *, enum form_type, struct form_state *);
static void js_form_elems_item(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
static void js_form_elems_namedItem(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
static void form_elems_get(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *);
static int form_elems_hasproperty(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *);
static void js_forms_item(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
static void js_forms_namedItem(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
static void forms_get(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *);
static int forms_hasproperty(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *);
static void form_get(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *);
static void form_put(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *, int);
static int form_canput(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *);
static int form_hasproperty(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *);
static void js_form_reset(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
static void js_form_submit(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
struct SEE_objectclass js_input_object_class = {
NULL,
input_get,
input_put,
input_canput,
input_hasproperty,
SEE_no_delete,
SEE_no_defaultvalue,
NULL,
NULL,
NULL,
NULL
};
struct SEE_objectclass js_form_elems_class = {
NULL,
form_elems_get,
SEE_no_put,
SEE_no_canput,
form_elems_hasproperty,
SEE_no_delete,
SEE_no_defaultvalue,
NULL,
NULL,
NULL,
NULL
};
struct SEE_objectclass js_forms_object_class = {
NULL,
forms_get,
SEE_no_put,
SEE_no_canput,
forms_hasproperty,
SEE_no_delete,
SEE_no_defaultvalue,
NULL,
NULL,
NULL,
NULL
};
struct SEE_objectclass js_form_class = {
NULL,
form_get,
form_put,
form_canput,
form_hasproperty,
SEE_no_delete,
SEE_no_defaultvalue,
NULL,
NULL,
NULL,
NULL
};
struct js_input {
struct SEE_object object;
struct js_form *parent;
struct form_state *fs;
struct SEE_object *blur;
struct SEE_object *click;
struct SEE_object *focus;
struct SEE_object *select;
};
struct js_forms_object {
struct SEE_object object;
struct js_document_object *parent;
struct SEE_object *item;
struct SEE_object *namedItem;
};
struct js_form_elems {
struct SEE_object object;
struct js_form *parent;
struct SEE_object *item;
struct SEE_object *namedItem;
};
static void
input_get(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p, struct SEE_value *res)
{
struct global_object *g = (struct global_object *)interp;
struct view_state *vs = g->win->vs;
struct document_view *doc_view = vs->doc_view;
struct document *document = doc_view->document;
struct js_input *input = (struct js_input *)o;
struct js_form *parent = input->parent;
struct form_state *fs = input->fs;
struct form_control *fc = find_form_control(document, fs);
int linknum;
struct link *link = NULL;
struct SEE_string *str;
assert(fc);
assert(fc->form && fs);
checktime(interp);
linknum = get_form_control_link(document, fc);
/* Hiddens have no link. */
if (linknum >= 0) link = &document->links[linknum];
SEE_SET_UNDEFINED(res);
if (p == s_accessKey) {
struct string keystr;
if (!link)
return;
init_string(&keystr);
add_accesskey_to_string(&keystr, link->accesskey);
str = string_to_SEE_string(interp, keystr.source);
SEE_SET_STRING(res, str);
done_string(&keystr);
} else if (p == s_alt) {
str = string_to_SEE_string(interp, fc->alt);
SEE_SET_STRING(res, str);
} else if (p == s_checked) {
SEE_SET_BOOLEAN(res, fs->state);
} else if (p == s_defaultChecked) {
SEE_SET_BOOLEAN(res, fc->default_state);
} else if (p == s_defaultValue) {
str = string_to_SEE_string(interp, fc->default_value);
SEE_SET_STRING(res, str);
} else if (p == s_disabled) {
/* FIXME: <input readonly disabled> --pasky */
SEE_SET_BOOLEAN(res, fc->mode == FORM_MODE_DISABLED);
} else if (p == s_form) {
SEE_SET_OBJECT(res, (struct SEE_object *)parent);
} else if (p == s_maxLength) {
SEE_SET_NUMBER(res, fc->maxlength);
} else if (p == s_name) {
str = string_to_SEE_string(interp, fc->name);
SEE_SET_STRING(res, str);
} else if (p == s_readonly) {
/* FIXME: <input readonly disabled> --pasky */
SEE_SET_BOOLEAN(res, fc->mode == FORM_MODE_READONLY);
} else if (p == s_size) {
SEE_SET_NUMBER(res, fc->size);
} else if (p == s_src) {
if (link && link->where_img) {
str = string_to_SEE_string(interp, link->where_img);
SEE_SET_STRING(res, str);
}
} else if (p == s_tabindex) {
if (link) {
/* FIXME: This is WRONG. --pasky */
SEE_SET_NUMBER(res, link->number);
}
} else if (p == s_type) {
switch (fc->type) {
case FC_TEXT: str = s_text; break;
case FC_PASSWORD: str = s_password; break;
case FC_FILE: str = s_file; break;
case FC_CHECKBOX: str = s_checkbox; break;
case FC_RADIO: str = s_radio; break;
case FC_SUBMIT: str = s_submit; break;
case FC_IMAGE: str = s_image; break;
case FC_RESET: str = s_reset; break;
case FC_BUTTON: str = s_button; break;
case FC_HIDDEN: str = s_hidden; break;
default: str = NULL;
}
if (str) {
SEE_SET_STRING(res, str);
}
} else if (p == s_value) {
str = string_to_SEE_string(interp, fs->value);
SEE_SET_STRING(res, str);
}
}
static void
input_put(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p, struct SEE_value *val, int attr)
{
struct global_object *g = (struct global_object *)interp;
struct view_state *vs = g->win->vs;
struct document_view *doc_view = vs->doc_view;
struct document *document = doc_view->document;
struct js_input *input = (struct js_input *)o;
struct form_state *fs = input->fs;
struct form_control *fc = find_form_control(document, fs);
int linknum;
struct link *link = NULL;
unsigned char *string = NULL;
assert(fc);
assert(fc->form && fs);
checktime(interp);
linknum = get_form_control_link(document, fc);
/* Hiddens have no link. */
if (linknum >= 0) link = &document->links[linknum];
if (p == s_accessKey) {
if (link) {
string = SEE_value_to_unsigned_char(interp, val);
if (!string)
return;
link->accesskey = accesskey_string_to_unicode(string);
mem_free(string);
}
} else if (p == s_alt) {
string = SEE_value_to_unsigned_char(interp, val);
mem_free_set(&fc->alt, string);
} else if (p == s_checked) {
if (fc->type != FC_CHECKBOX && fc->type != FC_RADIO)
return;
fs->state = SEE_ToUint32(interp, val);
} else if (p == s_disabled) {
/* FIXME: <input readonly disabled> --pasky */
SEE_uint32_t boo = SEE_ToUint32(interp, val);
fc->mode = (boo ? FORM_MODE_DISABLED
: (fc->mode == FORM_MODE_READONLY ? FORM_MODE_READONLY
: FORM_MODE_NORMAL));
} else if (p == s_maxLength) {
string = SEE_value_to_unsigned_char(interp, val);
if (!string)
return;
fc->maxlength = atol(string);
mem_free(string);
} else if (p == s_name) {
string = SEE_value_to_unsigned_char(interp, val);
mem_free_set(&fc->name, string);
} else if (p == s_readonly) {
SEE_uint32_t boo = SEE_ToUint32(interp, val);
fc->mode = (boo ? FORM_MODE_READONLY
: fc->mode == FORM_MODE_DISABLED ? FORM_MODE_DISABLED
: FORM_MODE_NORMAL);
} else if (p == s_src) {
if (link) {
string = SEE_value_to_unsigned_char(interp, val);
mem_free_set(&link->where_img, string);
}
} else if (p == s_value) {
if (fc->type == FC_FILE)
return;
string = SEE_value_to_unsigned_char(interp, val);
mem_free_set(&fs->value, string);
if (fc->type == FC_TEXT || fc->type == FC_PASSWORD)
fs->state = strlen(fs->value);
}
}
static void
js_input_blur(struct SEE_interpreter *interp, struct SEE_object *self,
struct SEE_object *thisobj, int argc, struct SEE_value **argv,
struct SEE_value *res)
{
/* We are a text-mode browser and there *always* has to be something
* selected. So we do nothing for now. (That was easy.) */
}
static void
js_input_click(struct SEE_interpreter *interp, struct SEE_object *self,
struct SEE_object *thisobj, int argc, struct SEE_value **argv,
struct SEE_value *res)
{
struct global_object *g = (struct global_object *)interp;
struct view_state *vs = g->win->vs;
struct document_view *doc_view = vs->doc_view;
struct document *document = doc_view->document;
struct session *ses = doc_view->session;
struct js_input *input = (struct js_input *)thisobj;
struct form_state *fs = input->fs;
struct form_control *fc;
int linknum;
checktime(interp);
SEE_SET_BOOLEAN(res, 0);
assert(fs);
fc = find_form_control(document, fs);
assert(fc);
linknum = get_form_control_link(document, fc);
/* Hiddens have no link. */
if (linknum < 0)
return;
/* Restore old current_link afterwards? */
jump_to_link_number(ses, doc_view, linknum);
if (enter(ses, doc_view, 0) == FRAME_EVENT_REFRESH)
refresh_view(ses, doc_view, 0);
else
print_screen_status(ses);
}
static void
js_input_focus(struct SEE_interpreter *interp, struct SEE_object *self,
struct SEE_object *thisobj, int argc, struct SEE_value **argv,
struct SEE_value *res)
{
struct global_object *g = (struct global_object *)interp;
struct view_state *vs = g->win->vs;
struct document_view *doc_view = vs->doc_view;
struct document *document = doc_view->document;
struct session *ses = doc_view->session;
struct js_input *input = (struct js_input *)thisobj;
struct form_state *fs = input->fs;
struct form_control *fc;
int linknum;
checktime(interp);
assert(fs);
fc = find_form_control(document, fs);
assert(fc);
linknum = get_form_control_link(document, fc);
/* Hiddens have no link. */
if (linknum < 0)
return;
jump_to_link_number(ses, doc_view, linknum);
}
static void
js_input_select(struct SEE_interpreter *interp, struct SEE_object *self,
struct SEE_object *thisobj, int argc, struct SEE_value **argv,
struct SEE_value *res)
{
checktime(interp);
/* We support no text selecting yet. So we do nothing for now.
* (That was easy, too.) */
}
static int
input_canput(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p)
{
checktime(interp);
return 1;
}
static int
input_hasproperty(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p)
{
/* all unknown properties return UNDEFINED value */
checktime(interp);
return 1;
}
static struct js_input *
js_get_input_object(struct SEE_interpreter *interp, struct js_form *jsform,
struct form_state *fs)
{
struct js_input *jsinput;
checktime(interp);
if (fs->ecmascript_obj)
return fs->ecmascript_obj;
/* jsform ('form') is input's parent */
/* FIXME: That is NOT correct since the real containing element
* should be its parent, but gimme DOM first. --pasky */
jsinput = SEE_NEW(interp, struct js_input);
jsinput->object.objectclass = &js_input_object_class;
jsinput->object.objectclass->Class = s_input;
jsinput->object.Prototype = NULL;
jsinput->blur = SEE_cfunction_make(interp, js_input_blur, s_blur, 0);
jsinput->click = SEE_cfunction_make(interp, js_input_click, s_click, 0);
jsinput->focus = SEE_cfunction_make(interp, js_input_focus, s_focus, 0);
jsinput->select = SEE_cfunction_make(interp, js_input_select, s_select, 0);
jsinput->fs = fs;
jsinput->parent = jsform;
fs->ecmascript_obj = jsinput;
return jsinput;
}
static struct js_input *
js_get_form_control_object(struct SEE_interpreter *interp, struct js_form *jsform,
enum form_type type, struct form_state *fs)
{
checktime(interp);
switch (type) {
case FC_TEXT:
case FC_PASSWORD:
case FC_FILE:
case FC_CHECKBOX:
case FC_RADIO:
case FC_SUBMIT:
case FC_IMAGE:
case FC_RESET:
case FC_BUTTON:
case FC_HIDDEN:
return js_get_input_object(interp, jsform, fs);
case FC_TEXTAREA:
case FC_SELECT:
/* TODO */
return NULL;
default:
INTERNAL("Weird fc->type %d", type);
return NULL;
}
}
static void
js_form_elems_item(struct SEE_interpreter *interp, struct SEE_object *self,
struct SEE_object *thisobj, int argc, struct SEE_value **argv,
struct SEE_value *res)
{
struct global_object *g = (struct global_object *)interp;
struct view_state *vs = g->win->vs;
struct document_view *doc_view = vs->doc_view;
struct document *document = doc_view->document;
struct js_form_elems *jsfe = (struct js_form_elems *)thisobj;
struct js_form *parent_form = jsfe->parent;
struct form_view *fv = parent_form->fv;
struct form *form = find_form_by_form_view(document, fv);
struct form_control *fc;
unsigned char *string;
int counter = -1;
int index;
checktime(interp);
SEE_SET_UNDEFINED(res);
if (argc < 1)
return;
string = SEE_value_to_unsigned_char(interp, argv[0]);
if (!string)
return;
index = atol(string);
mem_free(string);
foreach (fc, form->items) {
counter++;
if (counter == index) {
struct js_input *fcobj = js_get_form_control_object(interp, parent_form, fc->type, find_form_state(doc_view, fc));
if (fcobj) {
SEE_SET_OBJECT(res, (struct SEE_object *)fcobj);
}
break;
}
}
}
static void
js_form_elems_namedItem(struct SEE_interpreter *interp, struct SEE_object *self,
struct SEE_object *thisobj, int argc, struct SEE_value **argv,
struct SEE_value *res)
{
struct global_object *g = (struct global_object *)interp;
struct view_state *vs = g->win->vs;
struct document_view *doc_view = vs->doc_view;
struct document *document = doc_view->document;
struct js_form_elems *jsfe = (struct js_form_elems *)thisobj;
struct js_form *parent_form = jsfe->parent;
struct form_view *fv = parent_form->fv;
struct form *form = find_form_by_form_view(document, fv);
struct form_control *fc;
unsigned char *string;
checktime(interp);
SEE_SET_UNDEFINED(res);
if (argc < 1)
return;
string = SEE_value_to_unsigned_char(interp, argv[0]);
if (!string)
return;
foreach (fc, form->items) {
if (fc->name && !strcasecmp(string, fc->name)) {
struct js_input *fcobj = js_get_form_control_object(interp, parent_form, fc->type, find_form_state(doc_view, fc));
if (fcobj) {
SEE_SET_OBJECT(res, (struct SEE_object *)fcobj);
}
break;
}
}
mem_free(string);
}
static void
form_elems_get(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p, struct SEE_value *res)
{
struct global_object *g = (struct global_object *)interp;
struct view_state *vs = g->win->vs;
struct document_view *doc_view = vs->doc_view;
struct document *document = doc_view->document;
struct js_form_elems *jsfe = (struct js_form_elems *)o;
struct js_form *parent_form = jsfe->parent;
struct form_view *fv = parent_form->fv;
struct form *form = find_form_by_form_view(document, fv);
checktime(interp);
if (p == s_length) {
SEE_number_t length = list_size(&form->items);
SEE_SET_NUMBER(res, length);
} else {
unsigned char *string = SEE_string_to_unsigned_char(p);
struct SEE_value argv;
if (!string) {
SEE_SET_UNDEFINED(res);
return;
}
SEE_SET_STRING(&argv, p);
if (string[0] >= '0' && string[1] <= '9') {
js_form_elems_item(interp, o, NULL, 1,
(struct SEE_value **)&argv, res);
} else {
js_form_elems_namedItem(interp, o, NULL, 1,
(struct SEE_value **)&argv, res);
}
mem_free(string);
}
}
static int
form_elems_hasproperty(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p)
{
checktime(interp);
/* all unknown properties return UNDEFINED value */
return 1;
}
static void
js_forms_item(struct SEE_interpreter *interp, struct SEE_object *self,
struct SEE_object *thisobj, int argc, struct SEE_value **argv,
struct SEE_value *res)
{
struct global_object *g = (struct global_object *)interp;
struct view_state *vs = g->win->vs;
struct js_forms_object *fo = (struct js_forms_object *)thisobj;
struct js_document_object *doc = fo->parent;
struct form_view *fv;
unsigned char *string;
int counter = -1;
int index;
checktime(interp);
SEE_SET_UNDEFINED(res);
if (argc < 1)
return;
string = SEE_value_to_unsigned_char(interp, argv[0]);
if (!string)
return;
index = atol(string);
mem_free(string);
foreach (fv, vs->forms) {
counter++;
if (counter == index) {
struct js_form *obj = js_get_form_object(interp, doc, fv);
SEE_SET_OBJECT(res, (struct SEE_object *)obj);
break;
}
}
}
static void
js_forms_namedItem(struct SEE_interpreter *interp, struct SEE_object *self,
struct SEE_object *thisobj, int argc, struct SEE_value **argv,
struct SEE_value *res)
{
struct global_object *g = (struct global_object *)interp;
struct view_state *vs = g->win->vs;
struct document_view *doc_view = vs->doc_view;
struct document *document = doc_view->document;
struct js_forms_object *fo = (struct js_forms_object *)thisobj;
struct js_document_object *doc = fo->parent;
struct form *form;
unsigned char *string;
checktime(interp);
SEE_SET_UNDEFINED(res);
if (argc < 1)
return;
string = SEE_value_to_unsigned_char(interp, argv[0]);
if (!string)
return;
foreach (form, document->forms) {
if (form->name && !strcasecmp(string, form->name)) {
struct form_view *fv = find_form_view(doc_view, form);
struct js_form *obj = js_get_form_object(interp,
doc, fv);
SEE_SET_OBJECT(res, (struct SEE_object *)obj);
break;
}
}
mem_free(string);
}
static void
forms_get(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p, struct SEE_value *res)
{
struct global_object *g = (struct global_object *)interp;
struct view_state *vs = g->win->vs;
struct document_view *doc_view = vs->doc_view;
struct document *document = doc_view->document;
checktime(interp);
if (p == s_length) {
SEE_number_t length = list_size(&document->forms);
SEE_SET_NUMBER(res, length);
} else {
unsigned char *string = SEE_string_to_unsigned_char(p);
struct SEE_value argv;
if (!string) {
SEE_SET_UNDEFINED(res);
return;
}
SEE_SET_STRING(&argv, p);
if (string[0] >= '0' && string[1] <= '9') {
js_forms_item(interp, o, NULL, 1,
(struct SEE_value **)&argv, res);
} else {
js_forms_namedItem(interp, o, NULL, 1,
(struct SEE_value **)&argv, res);
}
mem_free(string);
}
}
static int
forms_hasproperty(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p)
{
checktime(interp);
/* all unknown properties return UNDEFINED value */
return 1;
}
static void
form_get(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p, struct SEE_value *res)
{
struct global_object *g = (struct global_object *)interp;
struct view_state *vs = g->win->vs;
struct document_view *doc_view = vs->doc_view;
struct js_form *js_form = (struct js_form *)o;
struct form_view *fv = js_form->fv;
struct form *form = find_form_by_form_view(doc_view->document, fv);
struct SEE_string *str;
checktime(interp);
SEE_SET_UNDEFINED(res);
if (p == s_action) {
str = string_to_SEE_string(interp, form->action);
SEE_SET_STRING(res, str);
} else if (p == s_encoding) {
switch (form->method) {
case FORM_METHOD_GET:
case FORM_METHOD_POST:
/* "application/x-www-form-urlencoded" */
SEE_SET_STRING(res, s_application_);
break;
case FORM_METHOD_POST_MP:
/* "multipart/form-data" */
SEE_SET_STRING(res, s_multipart_);
break;
case FORM_METHOD_POST_TEXT_PLAIN:
/* "text/plain") */
SEE_SET_STRING(res, s_textplain);
break;
}
} else if (p == s_length) {
SEE_number_t num = list_size(&form->items);
SEE_SET_NUMBER(res, num);
} else if (p == s_method) {
switch (form->method) {
case FORM_METHOD_GET:
SEE_SET_STRING(res, s_GET);
break;
case FORM_METHOD_POST:
case FORM_METHOD_POST_MP:
case FORM_METHOD_POST_TEXT_PLAIN:
SEE_SET_STRING(res, s_POST);
break;
}
} else if (p == s_name) {
str = string_to_SEE_string(interp, form->name);
SEE_SET_STRING(res, str);
} else if (p == s_target) {
str = string_to_SEE_string(interp, form->target);
SEE_SET_STRING(res, str);
} else if (p == s_elements) {
struct js_form_elems *jsfe = SEE_NEW(interp, struct js_form_elems);
jsfe->object.objectclass = &js_form_elems_class;
jsfe->object.objectclass->Class = s_elements;
jsfe->object.Prototype = NULL;
jsfe->parent = js_form;
jsfe->item = SEE_cfunction_make(interp, js_form_elems_item, s_item, 1);
jsfe->namedItem = SEE_cfunction_make(interp, js_form_elems_namedItem, s_namedItem, 1);
SEE_SET_OBJECT(res, (struct SEE_object *)jsfe);
} else if (p == s_submit) {
SEE_SET_OBJECT(res, js_form->submit);
} else if (p == s_reset) {
SEE_SET_OBJECT(res, js_form->reset);
} else {
unsigned char *string = SEE_string_to_unsigned_char(p);
struct form_control *fc;
if (!string)
return;
foreach(fc, form->items) {
struct js_input *fcobj = NULL;
if (!fc->name || strcasecmp(string, fc->name))
continue;
fcobj = js_get_form_control_object(interp, js_form, fc->type, find_form_state(doc_view, fc));
if (fcobj) {
SEE_SET_OBJECT(res, (struct SEE_object *)fcobj);
}
break;
}
mem_free(string);
}
}
static void
form_put(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p, struct SEE_value *val, int attr)
{
struct global_object *g = (struct global_object *)interp;
struct view_state *vs = g->win->vs;
struct document_view *doc_view = vs->doc_view;
struct js_form *js_form = (struct js_form *)o;
struct form_view *fv = js_form->fv;
struct form *form = find_form_by_form_view(doc_view->document, fv);
unsigned char *string = SEE_value_to_unsigned_char(interp, val);
checktime(interp);
if (!string)
return;
if (p == s_action) {
mem_free_set(&form->action, string);
} else if (p == s_encoding) {
if (!strcasecmp(string, "application/x-www-form-urlencoded")) {
form->method = form->method == FORM_METHOD_GET ? FORM_METHOD_GET
: FORM_METHOD_POST;
} else if (!strcasecmp(string, "multipart/form-data")) {
form->method = FORM_METHOD_POST_MP;
} else if (!strcasecmp(string, "text/plain")) {
form->method = FORM_METHOD_POST_TEXT_PLAIN;
}
mem_free(string);
} else if (p == s_method) {
if (!strcasecmp(string, "GET")) {
form->method = FORM_METHOD_GET;
} else if (!strcasecmp(string, "POST")) {
form->method = FORM_METHOD_POST;
}
mem_free(string);
} else if (p == s_name) {
mem_free_set(&form->name, string);
} else if (p == s_target) {
mem_free_set(&form->target, string);
}
}
static int
form_canput(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p)
{
checktime(interp);
return 1;
}
static int
form_hasproperty(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p)
{
checktime(interp);
return 1;
}
static void
js_form_reset(struct SEE_interpreter *interp, struct SEE_object *self,
struct SEE_object *thisobj, int argc, struct SEE_value **argv,
struct SEE_value *res)
{
struct global_object *g = (struct global_object *)interp;
struct view_state *vs = g->win->vs;
struct document_view *doc_view = vs->doc_view;
struct js_form *js_form = (struct js_form *)thisobj;
struct form_view *fv = js_form->fv;
struct form *form = find_form_by_form_view(doc_view->document, fv);
assert(form);
checktime(interp);
do_reset_form(doc_view, form);
draw_forms(doc_view->session->tab->term, doc_view);
SEE_SET_BOOLEAN(res, 0);
}
static void
js_form_submit(struct SEE_interpreter *interp, struct SEE_object *self,
struct SEE_object *thisobj, int argc, struct SEE_value **argv,
struct SEE_value *res)
{
struct global_object *g = (struct global_object *)interp;
struct view_state *vs = g->win->vs;
struct document_view *doc_view = vs->doc_view;
struct session *ses = doc_view->session;
struct js_form *js_form = (struct js_form *)thisobj;
struct form_view *fv = js_form->fv;
struct form *form = find_form_by_form_view(doc_view->document, fv);
assert(form);
checktime(interp);
submit_given_form(ses, doc_view, form);
SEE_SET_BOOLEAN(res, 0);
}
struct js_form *js_get_form_object(struct SEE_interpreter *interp,
struct js_document_object *doc, struct form_view *fv)
{
struct js_form *js_form;
checktime(interp);
if (fv->ecmascript_obj)
return fv->ecmascript_obj;
/* jsdoc ('document') is fv's parent */
/* FIXME: That is NOT correct since the real containing element
* should be its parent, but gimme DOM first. --pasky */
js_form = SEE_NEW(interp, struct js_form);
js_form->object.objectclass = &js_form_class;
js_form->object.objectclass->Class = s_form;
js_form->object.Prototype = NULL; /* TODO: use prototype for form */
js_form->parent = doc;
js_form->reset = SEE_cfunction_make(interp, js_form_reset, s_reset, 0);
js_form->submit = SEE_cfunction_make(interp, js_form_submit, s_submit, 0);
js_form->fv = fv;
fv->ecmascript_obj = js_form;
return js_form;
}
void
init_js_forms_object(struct ecmascript_interpreter *interpreter)
{
struct global_object *g = interpreter->backend_data;
struct SEE_interpreter *interp = &g->interp;
struct SEE_value v, document;
struct js_forms_object *forms = SEE_NEW(interp,
struct js_forms_object);
forms->object.objectclass = &js_forms_object_class;
forms->object.objectclass->Class = s_forms;
forms->object.Prototype = NULL;
SEE_OBJECT_GET(interp, interp->Global, s_document, &document);
SEE_SET_OBJECT(&v, (struct SEE_object *)forms);
SEE_OBJECT_PUT(interp, document.u.object, s_forms, &v, 0);
forms->item = SEE_cfunction_make(interp, js_forms_item, s_item, 1);
forms->namedItem = SEE_cfunction_make(interp, js_forms_namedItem,
s_namedItem, 1);
forms->parent = (struct js_document_object *)document.u.object;
}

19
src/ecmascript/see/form.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef EL__ECMASCRIPT_SEE_FORM_H
#define EL__ECMASCRIPT_SEE_FORM_H
struct js_document_object;
struct ecmascript_interpreter;
struct form_view;
struct js_form {
struct SEE_object object;
struct js_document_object *parent;
struct form_view *fv;
struct SEE_object *reset;
struct SEE_object *submit;
};
struct js_form *js_get_form_object(struct SEE_interpreter *, struct js_document_object*, struct form_view *);
void init_js_forms_object(struct ecmascript_interpreter *);
#endif

100
src/ecmascript/see/input.c Normal file
View File

@ -0,0 +1,100 @@
/* Input for SEE */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <see/see.h>
#include <string.h>
#include "ecmascript/see/input.h"
#include "util/memory.h"
static SEE_unicode_t input_elinks_next(struct SEE_input *);
static void input_elinks_close(struct SEE_input *);
static struct SEE_inputclass input_elinks_class = {
input_elinks_next,
input_elinks_close
};
struct input_elinks {
struct SEE_input inp;
unsigned char *s;
};
static SEE_unicode_t
input_elinks_next(struct SEE_input *inp)
{
struct input_elinks *input = (struct input_elinks*)inp;
SEE_unicode_t next;
next = input->inp.lookahead;
if (*input->s == '\0') {
input->inp.eof = 1;
} else {
input->inp.lookahead = *input->s++;
input->inp.eof = 0;
}
return next;
}
static void
input_elinks_close(struct SEE_input *inp)
{
/* nothing */
}
struct SEE_input *
SEE_input_elinks(struct SEE_interpreter *interp, unsigned char *s)
{
struct input_elinks *input;
input = SEE_NEW(interp, struct input_elinks);
input->inp.interpreter = interp;
input->inp.inputclass = &input_elinks_class;
input->inp.filename = NULL;
input->inp.first_lineno = 1;
input->s = s;
SEE_INPUT_NEXT((struct SEE_input *)input); /* prime */
return (struct SEE_input *)input;
}
unsigned char *
SEE_string_to_unsigned_char(struct SEE_string *S)
{
int i;
unsigned char *str = mem_alloc(S->length + 1);
if (!str)
return NULL;
for (i = 0; i < S->length; i++)
str[i] = (unsigned char)S->data[i];
str[S->length] = '\0';
return str;
}
unsigned char *
SEE_value_to_unsigned_char(struct SEE_interpreter *interp, struct SEE_value *val)
{
struct SEE_value result;
SEE_ToString(interp, val, &result);
return SEE_string_to_unsigned_char(result.u.string);
}
struct SEE_string *
string_to_SEE_string(struct SEE_interpreter *interp, unsigned char *s)
{
unsigned int len;
unsigned int i;
struct SEE_string *str;
len = s ? strlen(s) : 0;
str = SEE_string_new(interp, len);
str->length = len;
for (i = 0; i < len; i++)
str->data[i] = s[i];
return str;
}

View File

@ -0,0 +1,11 @@
#ifndef EL__ECMASCRIPT_SEE_INPUT_H
#define EL__ECMASCRIPT_SEE_INPUT_H
#include <see/see.h>
struct SEE_input *SEE_input_elinks(struct SEE_interpreter *, unsigned char *);
unsigned char *SEE_string_to_unsigned_char(struct SEE_string *);
unsigned char *SEE_value_to_unsigned_char(struct SEE_interpreter *, struct SEE_value *);
struct SEE_string *string_to_SEE_string(struct SEE_interpreter *, unsigned char *);
#endif

View File

@ -0,0 +1,363 @@
/* The SEE location and history objects implementation. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "elinks.h"
#include <see/see.h>
#include "bfu/dialog.h"
#include "cache/cache.h"
#include "cookies/cookies.h"
#include "dialogs/menu.h"
#include "dialogs/status.h"
#include "document/html/frames.h"
#include "document/document.h"
#include "document/forms.h"
#include "document/view.h"
#include "ecmascript/ecmascript.h"
#include "ecmascript/see/input.h"
#include "ecmascript/see/location.h"
#include "ecmascript/see/strings.h"
#include "ecmascript/see/window.h"
#include "intl/gettext/libintl.h"
#include "main/select.h"
#include "osdep/newwin.h"
#include "osdep/sysname.h"
#include "protocol/http/http.h"
#include "protocol/uri.h"
#include "session/history.h"
#include "session/location.h"
#include "session/session.h"
#include "session/task.h"
#include "terminal/tab.h"
#include "terminal/terminal.h"
#include "util/conv.h"
#include "util/memory.h"
#include "util/string.h"
#include "viewer/text/draw.h"
#include "viewer/text/form.h"
#include "viewer/text/link.h"
#include "viewer/text/vs.h"
static void delayed_goto(void *);
static void history_get(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *);
static int history_hasproperty(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *);
static void js_history_back(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
static void js_history_forward(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
static void js_history_go(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
static void js_location_toString(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
static void location_get(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *);
static void location_put(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *, int);
static int location_hasproperty(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *);
static int location_canput(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *);
void location_goto(struct document_view *, unsigned char *);
struct js_history_object {
struct SEE_object object;
struct SEE_object *back;
struct SEE_object *forward;
struct SEE_object *go;
};
struct js_location_object {
struct SEE_object object;
struct SEE_object *toString;
};
struct delayed_goto {
/* It might look more convenient to pass doc_view around but it could
* disappear during wild dances inside of frames or so. */
struct view_state *vs;
struct uri *uri;
};
struct SEE_objectclass js_history_object_class = {
NULL,
history_get,
SEE_no_put,
SEE_no_canput,
history_hasproperty,
SEE_no_delete,
SEE_no_defaultvalue,
NULL,
NULL,
NULL,
NULL
};
struct SEE_objectclass js_location_object_class = {
NULL,
location_get,
location_put,
location_canput,
location_hasproperty,
SEE_no_delete,
SEE_no_defaultvalue,
NULL,
NULL,
NULL,
NULL
};
static void
delayed_goto(void *data)
{
struct delayed_goto *deg = data;
assert(deg);
if (deg->vs->doc_view
&& deg->vs->doc_view == deg->vs->doc_view->session->doc_view) {
goto_uri_frame(deg->vs->doc_view->session, deg->uri,
deg->vs->doc_view->name,
CACHE_MODE_NORMAL);
}
done_uri(deg->uri);
mem_free(deg);
}
void
location_goto(struct document_view *doc_view, unsigned char *url)
{
unsigned char *new_abs_url;
struct uri *new_uri;
struct delayed_goto *deg;
/* Workaround for bug 611. Does not crash, but may lead to infinite loop.*/
if (!doc_view) return;
new_abs_url = join_urls(doc_view->document->uri,
trim_chars(url, ' ', 0));
if (!new_abs_url)
return;
new_uri = get_uri(new_abs_url, 0);
mem_free(new_abs_url);
if (!new_uri)
return;
deg = mem_calloc(1, sizeof(*deg));
if (!deg) {
done_uri(new_uri);
return;
}
assert(doc_view->vs);
deg->vs = doc_view->vs;
deg->uri = new_uri;
/* It does not seem to be very safe inside of frames to
* call goto_uri() right away. */
register_bottom_half(delayed_goto, deg);
}
static void
history_get(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p, struct SEE_value *res)
{
struct js_history_object *history = (struct js_history_object *)o;
checktime(interp);
if (p == s_back) {
SEE_SET_OBJECT(res, history->back);
} else if (p == s_forward) {
SEE_SET_OBJECT(res, history->forward);
} else if (p == s_go) {
SEE_SET_OBJECT(res, history->go);
} else {
SEE_SET_UNDEFINED(res);
}
}
static int
history_hasproperty(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p)
{
checktime(interp);
if (p == s_back || p == s_forward || p == s_go)
return 1;
return 0;
}
static void
js_history_back(struct SEE_interpreter *interp, struct SEE_object *self,
struct SEE_object *thisobj, int argc, struct SEE_value **argv,
struct SEE_value *res)
{
struct global_object *g = (struct global_object *)interp;
struct view_state *vs = g->win->vs;
struct document_view *doc_view = vs->doc_view;
struct session *ses = doc_view->session;
SEE_SET_NULL(res);
go_back(ses);
}
static void
js_history_forward(struct SEE_interpreter *interp, struct SEE_object *self,
struct SEE_object *thisobj, int argc, struct SEE_value **argv,
struct SEE_value *res)
{
struct global_object *g = (struct global_object *)interp;
struct view_state *vs = g->win->vs;
struct document_view *doc_view = vs->doc_view;
struct session *ses = doc_view->session;
checktime(interp);
SEE_SET_NULL(res);
go_unback(ses);
}
static void
js_history_go(struct SEE_interpreter *interp, struct SEE_object *self,
struct SEE_object *thisobj, int argc, struct SEE_value **argv,
struct SEE_value *res)
{
struct global_object *g = (struct global_object *)interp;
struct view_state *vs = g->win->vs;
struct document_view *doc_view = vs->doc_view;
struct session *ses = doc_view->session;
unsigned char *str;
int index;
struct location *loc;
checktime(interp);
SEE_SET_NULL(res);
if (argc < 1)
return;
str = SEE_value_to_unsigned_char(interp, argv[0]);
if (!str)
return;
index = atol(str);
mem_free(str);
for (loc = cur_loc(ses);
loc != (struct location *) &ses->history.history;
loc = index > 0 ? loc->next : loc->prev) {
if (!index) {
go_history(ses, loc);
break;
}
index += index > 0 ? -1 : 1;
}
}
static void
js_location_toString(struct SEE_interpreter *interp, struct SEE_object *self,
struct SEE_object *thisobj, int argc, struct SEE_value **argv,
struct SEE_value *res)
{
struct global_object *g = (struct global_object *)interp;
struct view_state *vs = g->win->vs;
unsigned char *string = get_uri_string(vs->uri, URI_ORIGINAL);
struct SEE_string *str = string_to_SEE_string(interp, string);
mem_free_if(string);
checktime(interp);
SEE_SET_STRING(res, str);
}
static void
location_get(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p, struct SEE_value *res)
{
struct js_location_object *loc = (struct js_location_object *)o;
checktime(interp);
if (p == s_toString || p == s_toLocaleString) {
SEE_SET_OBJECT(res, loc->toString);
} else if (p == s_href) {
struct global_object *g = (struct global_object *)interp;
struct view_state *vs = g->win->vs;
unsigned char *string = get_uri_string(vs->uri, URI_ORIGINAL);
struct SEE_string *str = string_to_SEE_string(interp, string);
mem_free_if(string);
SEE_SET_STRING(res, str);
} else {
SEE_SET_UNDEFINED(res);
}
}
static void
location_put(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p, struct SEE_value *val, int attr)
{
checktime(interp);
if (p == s_href) {
struct global_object *g = (struct global_object *)interp;
struct view_state *vs = g->win->vs;
struct document_view *doc_view = vs->doc_view;
unsigned char *url = SEE_value_to_unsigned_char(interp, val);
location_goto(doc_view, url);
mem_free(url);
}
}
static int
location_hasproperty(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p)
{
checktime(interp);
if (p == s_toString || p == s_toLocaleString || p == s_href)
return 1;
return 0;
}
static int
location_canput(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p)
{
checktime(interp);
if (p == s_href)
return 1;
return 0;
}
void
init_js_history_object(struct ecmascript_interpreter *interpreter)
{
struct global_object *g = interpreter->backend_data;
struct SEE_interpreter *interp = &g->interp;
struct SEE_value v;
struct js_history_object *history = SEE_NEW(interp,
struct js_history_object);
history->object.objectclass = &js_history_object_class;
history->object.objectclass->Class = s_history;
history->object.Prototype = NULL;
SEE_SET_OBJECT(&v, (struct SEE_object *)history);
SEE_OBJECT_PUT(interp, interp->Global, s_history, &v, 0);
history->back = SEE_cfunction_make(interp, js_history_back, s_back, 0);
history->forward = SEE_cfunction_make(interp, js_history_forward, s_forward, 0);
history->go = SEE_cfunction_make(interp, js_history_go, s_go, 1);
}
void
init_js_location_object(struct ecmascript_interpreter *interpreter)
{
struct global_object *g = interpreter->backend_data;
struct SEE_interpreter *interp = &g->interp;
struct SEE_value v;
struct js_location_object *loc = SEE_NEW(interp,
struct js_location_object);
loc->object.objectclass = &js_location_object_class;
loc->object.objectclass->Class = s_location;
loc->object.Prototype = NULL;
SEE_SET_OBJECT(&v, (struct SEE_object *)loc);
SEE_OBJECT_PUT(interp, interp->Global, s_location, &v, 0);
loc->toString = SEE_cfunction_make(interp, js_location_toString, s_toString, 0);
}

View File

@ -0,0 +1,9 @@
#ifndef EL__ECMASCRIPT_SEE_LOCATION_H
#define EL__ECMASCRIPT_SEE_LOCATION_H
struct ecmascript_interpreter;
void init_js_history_object(struct ecmascript_interpreter *);
void init_js_location_object(struct ecmascript_interpreter *);
#endif

View File

@ -0,0 +1,150 @@
/* The SEE navigator objects implementation. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "elinks.h"
#include <see/see.h>
#include "bfu/dialog.h"
#include "cache/cache.h"
#include "cookies/cookies.h"
#include "dialogs/menu.h"
#include "dialogs/status.h"
#include "document/html/frames.h"
#include "document/document.h"
#include "document/forms.h"
#include "document/view.h"
#include "ecmascript/ecmascript.h"
#include "ecmascript/see/input.h"
#include "ecmascript/see/navigator.h"
#include "ecmascript/see/strings.h"
#include "ecmascript/see/window.h"
#include "intl/gettext/libintl.h"
#include "main/select.h"
#include "osdep/newwin.h"
#include "osdep/sysname.h"
#include "protocol/http/http.h"
#include "protocol/uri.h"
#include "session/history.h"
#include "session/location.h"
#include "session/session.h"
#include "session/task.h"
#include "terminal/tab.h"
#include "terminal/terminal.h"
#include "util/conv.h"
#include "util/memory.h"
#include "util/string.h"
#include "viewer/text/draw.h"
#include "viewer/text/form.h"
#include "viewer/text/link.h"
#include "viewer/text/vs.h"
static void navigator_get(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *);
static int navigator_hasproperty(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *);
struct SEE_objectclass js_navigator_object_class = {
NULL,
navigator_get,
SEE_no_put,
SEE_no_canput,
navigator_hasproperty,
SEE_no_delete,
SEE_no_defaultvalue,
NULL,
NULL,
NULL,
NULL
};
static void
navigator_get(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p, struct SEE_value *res)
{
struct SEE_string *str;
checktime(interp);
SEE_SET_UNDEFINED(res);
if (p == s_appCodeName) {
SEE_SET_STRING(res, s_Mozilla);
} else if (p == s_appName) {
SEE_SET_STRING(res, s_ELinks_);
} else if (p == s_appVersion) {
str = string_to_SEE_string(interp, VERSION);
SEE_SET_STRING(res, str);
} else if (p == s_language) {
#ifdef CONFIG_NLS
if (get_opt_bool("protocol.http.accept_ui_language")) {
str = string_to_SEE_string(interp,
language_to_iso639(current_language));
SEE_SET_STRING(res, str);
}
#endif
} else if (p == s_platform) {
str = string_to_SEE_string(interp, system_name);
SEE_SET_STRING(res, str);
} else if (p == s_userAgent) {
/* FIXME: Code duplication. */
unsigned char *optstr = get_opt_str("protocol.http.user_agent");
if (*optstr && strcmp(optstr, " ")) {
unsigned char *ustr, ts[64] = "";
static unsigned char custr[256];
if (!list_empty(terminals)) {
unsigned int tslen = 0;
struct terminal *term = terminals.prev;
ulongcat(ts, &tslen, term->width, 3, 0);
ts[tslen++] = 'x';
ulongcat(ts, &tslen, term->height, 3, 0);
}
ustr = subst_user_agent(optstr, VERSION_STRING, system_name, ts);
if (ustr) {
safe_strncpy(custr, ustr, 256);
mem_free(ustr);
str = string_to_SEE_string(interp, custr);
SEE_SET_STRING(res, str);
}
}
}
}
static int
navigator_hasproperty(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p)
{
checktime(interp);
if (p == s_appCodeName || p == s_appName || p == s_appVersion
|| p == s_language || p == s_platform || p == s_userAgent)
return 1;
return 0;
}
void
init_js_navigator_object(struct ecmascript_interpreter *interpreter)
{
struct global_object *g = interpreter->backend_data;
struct SEE_interpreter *interp = &g->interp;
struct SEE_value v;
struct SEE_object *navigator;
navigator = SEE_NEW(interp, struct SEE_object);
navigator->objectclass = &js_navigator_object_class;
navigator->objectclass->Class = s_navigator;
navigator->Prototype = NULL;
SEE_SET_OBJECT(&v, navigator);
SEE_OBJECT_PUT(interp, interp->Global, s_navigator, &v, 0);
}

View File

@ -0,0 +1,8 @@
#ifndef EL__ECMASCRIPT_SEE_NAVIGATOR_H
#define EL__ECMASCRIPT_SEE_NAVIGATOR_H
struct ecmascript_interpreter;
void init_js_navigator_object(struct ecmascript_interpreter *);
#endif

View File

@ -0,0 +1,379 @@
#include <see/see.h>
struct SEE_string *s_window;
struct SEE_string *s_closed;
struct SEE_string *s_parent;
struct SEE_string *s_self;
struct SEE_string *s_top;
struct SEE_string *s_alert;
struct SEE_string *s_open;
struct SEE_string *s_menubar;
struct SEE_string *s_statusbar;
struct SEE_string *s_visible;
struct SEE_string *s_navigator;
struct SEE_string *s_appCodeName;
struct SEE_string *s_appName;
struct SEE_string *s_appVersion;
struct SEE_string *s_language;
struct SEE_string *s_platform;
struct SEE_string *s_userAgent;
struct SEE_string *s_history;
struct SEE_string *s_back;
struct SEE_string *s_forward;
struct SEE_string *s_go;
struct SEE_string *s_location;
struct SEE_string *s_href;
struct SEE_string *s_toString;
struct SEE_string *s_toLocaleString;
struct SEE_string *s_input;
struct SEE_string *s_accessKey;
struct SEE_string *s_alt;
struct SEE_string *s_checked;
struct SEE_string *s_defaultChecked;
struct SEE_string *s_defaultValue;
struct SEE_string *s_disabled;
struct SEE_string *s_form;
struct SEE_string *s_maxLength;
struct SEE_string *s_name;
struct SEE_string *s_readonly;
struct SEE_string *s_size;
struct SEE_string *s_src;
struct SEE_string *s_tabindex;
struct SEE_string *s_type;
struct SEE_string *s_value;
struct SEE_string *s_blur;
struct SEE_string *s_click;
struct SEE_string *s_focus;
struct SEE_string *s_select;
struct SEE_string *s_elements;
struct SEE_string *s_item;
struct SEE_string *s_namedItem;
struct SEE_string *s_length;
struct SEE_string *s_action;
struct SEE_string *s_encoding;
struct SEE_string *s_method;
struct SEE_string *s_target;
struct SEE_string *s_reset;
struct SEE_string *s_submit;
struct SEE_string *s_forms;
struct SEE_string *s_document;
struct SEE_string *s_referrer;
struct SEE_string *s_title;
struct SEE_string *s_url;
struct SEE_string *s_write;
struct SEE_string *s_Mozilla;
struct SEE_string *s_ELinks_;
struct SEE_string *s_cookie;
struct SEE_string *s_GET;
struct SEE_string *s_POST;
struct SEE_string *s_application_;
struct SEE_string *s_multipart_;
struct SEE_string *s_textplain;
struct SEE_string *s_text;
struct SEE_string *s_password;
struct SEE_string *s_file;
struct SEE_string *s_checkbox;
struct SEE_string *s_radio;
struct SEE_string *s_image;
struct SEE_string *s_button;
struct SEE_string *s_hidden;
struct SEE_string *s_timeout;
void
init_intern_strings(void)
{
static SEE_char_t SA_window[] = {'w','i','n','d','o','w'};
static struct SEE_string S_window = SEE_STRING_DECL(SA_window);
static SEE_char_t SA_closed[] = {'c','l','o','s','e','d'};
static struct SEE_string S_closed = SEE_STRING_DECL(SA_closed);
static SEE_char_t SA_parent[] = {'p','a','r','e','n','t'};
static struct SEE_string S_parent = SEE_STRING_DECL(SA_parent);
static SEE_char_t SA_self[] = {'s','e','l','f'};
static struct SEE_string S_self = SEE_STRING_DECL(SA_self);
static SEE_char_t SA_top[] = {'t','o','p'};
static struct SEE_string S_top = SEE_STRING_DECL(SA_top);
static SEE_char_t SA_alert[] ={'a','l','e','r','t'};
static struct SEE_string S_alert = SEE_STRING_DECL(SA_alert);
static SEE_char_t SA_open[] ={'o','p','e','n'};
static struct SEE_string S_open = SEE_STRING_DECL(SA_open);
static SEE_char_t SA_menubar[] = {'m','e','n','u','b','a','r'};
static struct SEE_string S_menubar = SEE_STRING_DECL(SA_menubar);
static SEE_char_t SA_statusbar[] = {'s','t','a','t','u','s','b','a','r'};
static struct SEE_string S_statusbar = SEE_STRING_DECL(SA_statusbar);
static SEE_char_t SA_visible[] = {'v','i','s','i','b','l','e'};
static struct SEE_string S_visible = SEE_STRING_DECL(SA_visible);
static SEE_char_t SA_navigator[] ={'n','a','v','i','g','a','t','o','r'};
static struct SEE_string S_navigator = SEE_STRING_DECL(SA_navigator);
static SEE_char_t SA_appCodeName[] ={'a','p','p','C','o','d','e','N','a','m','e'};
static struct SEE_string S_appCodeName = SEE_STRING_DECL(SA_appCodeName);
static SEE_char_t SA_appName[] ={'a','p','p','N','a','m','e'};
static struct SEE_string S_appName = SEE_STRING_DECL(SA_appName);
static SEE_char_t SA_appVersion[] ={'a','p','p','V','e','r','s','i','o','n'};
static struct SEE_string S_appVersion = SEE_STRING_DECL(SA_appVersion);
static SEE_char_t SA_language[] ={'l','a','n','g','u','a','g','e'};
static struct SEE_string S_language = SEE_STRING_DECL(SA_language);
static SEE_char_t SA_platform[] ={'p','l','a','t','f','o','r','m'};
static struct SEE_string S_platform = SEE_STRING_DECL(SA_platform);
static SEE_char_t SA_userAgent[] ={'u','s','e','r','A','g','e','n','t'};
static struct SEE_string S_userAgent = SEE_STRING_DECL(SA_userAgent);
static SEE_char_t SA_history[] ={'h','i','s','t','o','r','y'};
static struct SEE_string S_history = SEE_STRING_DECL(SA_history);
static SEE_char_t SA_back[] ={'b','a','c','k'};
static struct SEE_string S_back = SEE_STRING_DECL(SA_back);
static SEE_char_t SA_forward[] ={'f','o','r','w','a','r','d'};
static struct SEE_string S_forward = SEE_STRING_DECL(SA_forward);
static SEE_char_t SA_go[] ={'g','o'};
static struct SEE_string S_go = SEE_STRING_DECL(SA_go);
static SEE_char_t SA_location[] ={'l','o','c','a','t','i','o','n'};
static struct SEE_string S_location = SEE_STRING_DECL(SA_location);
static SEE_char_t SA_href[] ={'h','r','e','f'};
static struct SEE_string S_href = SEE_STRING_DECL(SA_href);
static SEE_char_t SA_toString[] ={'t','o','S','t','r','i','n','g'};
static struct SEE_string S_toString = SEE_STRING_DECL(SA_toString);
static SEE_char_t SA_toLocaleString[] ={'t','o','L','o','c','a','l','e','S','t','r','i','n','g'};
static struct SEE_string S_toLocaleString = SEE_STRING_DECL(SA_toLocaleString);
static SEE_char_t SA_input[] ={'i','n','p','u','t'};
static struct SEE_string S_input = SEE_STRING_DECL(SA_input);
static SEE_char_t SA_accessKey[] ={'a','c','c','e','s','s','K','e','y'};
static struct SEE_string S_accessKey = SEE_STRING_DECL(SA_accessKey);
static SEE_char_t SA_alt[] ={'a','l','t'};
static struct SEE_string S_alt = SEE_STRING_DECL(SA_alt);
static SEE_char_t SA_checked[] ={'c','h','e','c','k','e','d'};
static struct SEE_string S_checked = SEE_STRING_DECL(SA_checked);
static SEE_char_t SA_defaultChecked[] ={'d','e','f','a','u','l','t','C','h','e','c','k','e','d'};
static struct SEE_string S_defaultChecked = SEE_STRING_DECL(SA_defaultChecked);
static SEE_char_t SA_defaultValue[] ={'d','e','f','a','u','l','t','V','a','l','u','e'};
static struct SEE_string S_defaultValue = SEE_STRING_DECL(SA_defaultValue);
static SEE_char_t SA_disabled[] ={'d','i','s','a','b','l','e','d'};
static struct SEE_string S_disabled = SEE_STRING_DECL(SA_disabled);
static SEE_char_t SA_form[] ={'f','o','r','m'};
static struct SEE_string S_form = SEE_STRING_DECL(SA_form);
static SEE_char_t SA_maxLength[] ={'m','a','x','L','e','n','g','t','h'};
static struct SEE_string S_maxLength = SEE_STRING_DECL(SA_maxLength);
static SEE_char_t SA_name[] ={'n','a','m','e'};
static struct SEE_string S_name = SEE_STRING_DECL(SA_name);
static SEE_char_t SA_readonly[] ={'r','e','a','d','o','n','l','y'};
static struct SEE_string S_readonly = SEE_STRING_DECL(SA_readonly);
static SEE_char_t SA_size[] ={'s','i','z','e'};
static struct SEE_string S_size = SEE_STRING_DECL(SA_size);
static SEE_char_t SA_src[] ={'s','r','c'};
static struct SEE_string S_src = SEE_STRING_DECL(SA_src);
static SEE_char_t SA_tabindex[] ={'t','a','b','i','n','d','e','x'};
static struct SEE_string S_tabindex = SEE_STRING_DECL(SA_tabindex);
static SEE_char_t SA_type[] ={'t','y','p','e'};
static struct SEE_string S_type = SEE_STRING_DECL(SA_type);
static SEE_char_t SA_value[] ={'v','a','l','u','e'};
static struct SEE_string S_value = SEE_STRING_DECL(SA_value);
static SEE_char_t SA_blur[] ={'b','l','u','r'};
static struct SEE_string S_blur = SEE_STRING_DECL(SA_blur);
static SEE_char_t SA_click[] ={'c','l','i','c','k'};
static struct SEE_string S_click = SEE_STRING_DECL(SA_click);
static SEE_char_t SA_focus[] ={'f','o','c','u','s'};
static struct SEE_string S_focus = SEE_STRING_DECL(SA_focus);
static SEE_char_t SA_select[] ={'s','e','l','e','c','t'};
static struct SEE_string S_select = SEE_STRING_DECL(SA_select);
static SEE_char_t SA_elements[] ={'e','l','e','m','e','n','t','s'};
static struct SEE_string S_elements = SEE_STRING_DECL(SA_elements);
static SEE_char_t SA_item[] ={'i','t','e','m'};
static struct SEE_string S_item = SEE_STRING_DECL(SA_item);
static SEE_char_t SA_namedItem[] ={'n','a','m','e','d','I','t','e','m'};
static struct SEE_string S_namedItem = SEE_STRING_DECL(SA_namedItem);
static SEE_char_t SA_length[] ={'l','e','n','g','t','h'};
static struct SEE_string S_length = SEE_STRING_DECL(SA_length);
static SEE_char_t SA_action[] ={'a','c','t','i','o','n'};
static struct SEE_string S_action = SEE_STRING_DECL(SA_action);
static SEE_char_t SA_encoding[] ={'e','n','c','o','d','i','g'};
static struct SEE_string S_encoding = SEE_STRING_DECL(SA_encoding);
static SEE_char_t SA_method[] ={'m','e','t','h','o','d'};
static struct SEE_string S_method = SEE_STRING_DECL(SA_method);
static SEE_char_t SA_target[] ={'t','a','r','g','e','t'};
static struct SEE_string S_target = SEE_STRING_DECL(SA_target);
static SEE_char_t SA_reset[] ={'r','e','s','e','t'};
static struct SEE_string S_reset = SEE_STRING_DECL(SA_reset);
static SEE_char_t SA_submit[] ={'s','u','b','m','i','t'};
static struct SEE_string S_submit = SEE_STRING_DECL(SA_submit);
static SEE_char_t SA_forms[] ={'f','o','r','m','s'};
static struct SEE_string S_forms = SEE_STRING_DECL(SA_forms);
static SEE_char_t SA_document[] = {'d','o','c','u','m','e','n','t'};
static struct SEE_string S_document = SEE_STRING_DECL(SA_document);
static SEE_char_t SA_referrer[] ={'r','e','f','e','r','r','e','r'};
static struct SEE_string S_referrer = SEE_STRING_DECL(SA_referrer);
static SEE_char_t SA_title[] ={'t','i','t','l','e'};
static struct SEE_string S_title = SEE_STRING_DECL(SA_title);
static SEE_char_t SA_url[] ={'u','r','l'};
static struct SEE_string S_url = SEE_STRING_DECL(SA_url);
static SEE_char_t SA_write[] = {'w','r','i','t','e'};
static struct SEE_string S_write = SEE_STRING_DECL(SA_write);
static SEE_char_t SA_Mozilla[] = {'M','o','z','i','l','l','a'};
static struct SEE_string S_Mozilla = SEE_STRING_DECL(SA_Mozilla);
static SEE_char_t SA_ELinks_[] = {'E','L','i','n','k','s',' ','(',
'r','o','u','g','h','l','y',' ','c','o','m','p','a','t','i','b','l','e',
' ','w','i','t','h',' ','N','e','t','s','c','a','p','e',' ',
'N','a','v','i','g','a','t','o','r',',',' ','M','o','z','i','l','l','a',
' ','a','n','d',' ','M','i','c','r','o','s','o','f','t',' ',
'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r',')'};
static struct SEE_string S_ELinks_ = SEE_STRING_DECL(SA_ELinks_);
static SEE_char_t SA_cookie[] = {'c','o','o','k','i','e'};
static struct SEE_string S_cookie = SEE_STRING_DECL(SA_cookie);
static SEE_char_t SA_GET[] = {'G','E','T'};
static struct SEE_string S_GET = SEE_STRING_DECL(SA_GET);
static SEE_char_t SA_POST[] = {'P','O','S','T'};
static struct SEE_string S_POST = SEE_STRING_DECL(SA_POST);
static SEE_char_t SA_application_[] = {'a','p','p','l','i','c','a','t',
'i','o','n','/','x','-','w','w','w','-','f','o','r','m','-','u','r','l',
'e','n','c','o','d','e','d'};
static struct SEE_string S_application_ = SEE_STRING_DECL(SA_application_);
static SEE_char_t SA_multipart_[] = {'m','u','l','t','i','p','a','r','t','/',
'f','o','r','m','-','d','a','t','a'};
static struct SEE_string S_multipart_ = SEE_STRING_DECL(SA_multipart_);
static SEE_char_t SA_textplain[] = {'t','e','x','t','/','p','l','a','i','n'};
static struct SEE_string S_textplain = SEE_STRING_DECL(SA_textplain);
static SEE_char_t SA_text[] = {'t','e','x','t'};
static struct SEE_string S_text = SEE_STRING_DECL(SA_text);
static SEE_char_t SA_password[] = {'p','a','s','s','w','o','r','d'};
static struct SEE_string S_password = SEE_STRING_DECL(SA_password);
static SEE_char_t SA_file[] = {'f','i','l','e'};
static struct SEE_string S_file = SEE_STRING_DECL(SA_file);
static SEE_char_t SA_checkbox[] = {'c','h','e','c','k','b','o','x'};
static struct SEE_string S_checkbox = SEE_STRING_DECL(SA_checkbox);
static SEE_char_t SA_radio[] = {'r','a','d','i','o'};
static struct SEE_string S_radio = SEE_STRING_DECL(SA_radio);
static SEE_char_t SA_image[] = {'i','m','a','g','e'};
static struct SEE_string S_image = SEE_STRING_DECL(SA_image);
static SEE_char_t SA_button[] = {'b','u','t','t','o','n'};
static struct SEE_string S_button = SEE_STRING_DECL(SA_button);
static SEE_char_t SA_hidden[] = {'h','i','d','d','e','n'};
static struct SEE_string S_hidden = SEE_STRING_DECL(SA_hidden);
static SEE_char_t SA_timeout[] = {'t','i','m','e','o','u','t'};
static struct SEE_string S_timeout = SEE_STRING_DECL(SA_timeout);
SEE_intern_global(s_window = &S_window);
SEE_intern_global(s_closed = &S_closed);
SEE_intern_global(s_parent = &S_parent);
SEE_intern_global(s_self = &S_self);
SEE_intern_global(s_top = &S_top);
SEE_intern_global(s_alert = &S_alert);
SEE_intern_global(s_open = &S_open);
SEE_intern_global(s_menubar = &S_menubar);
SEE_intern_global(s_statusbar = &S_statusbar);
SEE_intern_global(s_visible = &S_visible);
SEE_intern_global(s_navigator = &S_navigator);
SEE_intern_global(s_appCodeName = &S_appCodeName);
SEE_intern_global(s_appName = &S_appName);
SEE_intern_global(s_appVersion = &S_appVersion);
SEE_intern_global(s_language = &S_language);
SEE_intern_global(s_platform = &S_platform);
SEE_intern_global(s_userAgent = &S_userAgent);
SEE_intern_global(s_history = &S_history);
SEE_intern_global(s_back = &S_back);
SEE_intern_global(s_forward = &S_forward);
SEE_intern_global(s_go = &S_go);
SEE_intern_global(s_location = &S_location);
SEE_intern_global(s_href = &S_href);
SEE_intern_global(s_toString = &S_toString);
SEE_intern_global(s_toLocaleString = &S_toLocaleString);
SEE_intern_global(s_input = &S_input);
SEE_intern_global(s_accessKey = &S_accessKey);
SEE_intern_global(s_alt = &S_alt);
SEE_intern_global(s_checked = &S_checked);
SEE_intern_global(s_defaultChecked = &S_defaultChecked);
SEE_intern_global(s_defaultValue = &S_defaultValue);
SEE_intern_global(s_disabled = &S_disabled);
SEE_intern_global(s_form = &S_form);
SEE_intern_global(s_maxLength = &S_maxLength);
SEE_intern_global(s_name = &S_name);
SEE_intern_global(s_readonly = &S_readonly);
SEE_intern_global(s_size = &S_size);
SEE_intern_global(s_src = &S_src);
SEE_intern_global(s_tabindex = &S_tabindex);
SEE_intern_global(s_type = &S_type);
SEE_intern_global(s_value = &S_value);
SEE_intern_global(s_blur = &S_blur);
SEE_intern_global(s_click = &S_click);
SEE_intern_global(s_focus = &S_focus);
SEE_intern_global(s_select = &S_select);
SEE_intern_global(s_elements = &S_elements);
SEE_intern_global(s_item = &S_item);
SEE_intern_global(s_namedItem = &S_namedItem);
SEE_intern_global(s_length = &S_length);
SEE_intern_global(s_action = &S_action);
SEE_intern_global(s_encoding = &S_encoding);
SEE_intern_global(s_method = &S_method);
SEE_intern_global(s_target = &S_target);
SEE_intern_global(s_reset = &S_reset);
SEE_intern_global(s_submit = &S_submit);
SEE_intern_global(s_forms = &S_forms);
SEE_intern_global(s_document = &S_document);
SEE_intern_global(s_referrer = &S_referrer);
SEE_intern_global(s_title = &S_title);
SEE_intern_global(s_url = &S_url);
SEE_intern_global(s_write = &S_write);
SEE_intern_global(s_Mozilla = &S_Mozilla);
SEE_intern_global(s_ELinks_ = &S_ELinks_);
SEE_intern_global(s_cookie = &S_cookie);
SEE_intern_global(s_GET = &S_GET);
SEE_intern_global(s_POST = &S_POST);
SEE_intern_global(s_application_ = &S_application_);
SEE_intern_global(s_multipart_ = &S_multipart_);
SEE_intern_global(s_textplain = &S_textplain);
SEE_intern_global(s_text = &S_text);
SEE_intern_global(s_password = &S_password);
SEE_intern_global(s_file = &S_file);
SEE_intern_global(s_checkbox = &S_checkbox);
SEE_intern_global(s_radio = &S_radio);
SEE_intern_global(s_image = &S_image);
SEE_intern_global(s_button = &S_button);
SEE_intern_global(s_hidden = &S_hidden);
SEE_intern_global(s_timeout = &S_timeout);
}

View File

@ -0,0 +1,101 @@
#ifndef EL__ECMASCRIPT_SEE_STRINGS_H
#define EL__ECMASCRIPT_SEE_STRINGS_H
#include <see/see.h>
void init_intern_strings(void);
extern struct SEE_string *s_window;
extern struct SEE_string *s_closed;
extern struct SEE_string *s_parent;
extern struct SEE_string *s_self;
extern struct SEE_string *s_top;
extern struct SEE_string *s_alert;
extern struct SEE_string *s_open;
extern struct SEE_string *s_menubar;
extern struct SEE_string *s_statusbar;
extern struct SEE_string *s_visible;
extern struct SEE_string *s_navigator;
extern struct SEE_string *s_appCodeName;
extern struct SEE_string *s_appName;
extern struct SEE_string *s_appVersion;
extern struct SEE_string *s_language;
extern struct SEE_string *s_platform;
extern struct SEE_string *s_userAgent;
extern struct SEE_string *s_history;
extern struct SEE_string *s_back;
extern struct SEE_string *s_forward;
extern struct SEE_string *s_go;
extern struct SEE_string *s_location;
extern struct SEE_string *s_href;
extern struct SEE_string *s_toString;
extern struct SEE_string *s_toLocaleString;
extern struct SEE_string *s_input;
extern struct SEE_string *s_accessKey;
extern struct SEE_string *s_alt;
extern struct SEE_string *s_checked;
extern struct SEE_string *s_defaultChecked;
extern struct SEE_string *s_defaultValue;
extern struct SEE_string *s_disabled;
extern struct SEE_string *s_form;
extern struct SEE_string *s_maxLength;
extern struct SEE_string *s_name;
extern struct SEE_string *s_readonly;
extern struct SEE_string *s_size;
extern struct SEE_string *s_src;
extern struct SEE_string *s_tabindex;
extern struct SEE_string *s_type;
extern struct SEE_string *s_value;
extern struct SEE_string *s_blur;
extern struct SEE_string *s_click;
extern struct SEE_string *s_focus;
extern struct SEE_string *s_select;
extern struct SEE_string *s_elements;
extern struct SEE_string *s_item;
extern struct SEE_string *s_namedItem;
extern struct SEE_string *s_length;
extern struct SEE_string *s_action;
extern struct SEE_string *s_encoding;
extern struct SEE_string *s_method;
extern struct SEE_string *s_target;
extern struct SEE_string *s_reset;
extern struct SEE_string *s_submit;
extern struct SEE_string *s_forms;
extern struct SEE_string *s_document;
extern struct SEE_string *s_referrer;
extern struct SEE_string *s_title;
extern struct SEE_string *s_url;
extern struct SEE_string *s_write;
extern struct SEE_string *s_Mozilla;
extern struct SEE_string *s_ELinks_;
extern struct SEE_string *s_cookie;
extern struct SEE_string *s_GET;
extern struct SEE_string *s_POST;
extern struct SEE_string *s_application_;
extern struct SEE_string *s_multipart_;
extern struct SEE_string *s_textplain;
extern struct SEE_string *s_text;
extern struct SEE_string *s_password;
extern struct SEE_string *s_file;
extern struct SEE_string *s_checkbox;
extern struct SEE_string *s_radio;
extern struct SEE_string *s_image;
extern struct SEE_string *s_button;
extern struct SEE_string *s_hidden;
extern struct SEE_string *s_timeout;
#endif

206
src/ecmascript/see/unibar.c Normal file
View File

@ -0,0 +1,206 @@
/* The SEE location and history objects implementation. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "elinks.h"
#include <see/see.h>
#include "bfu/dialog.h"
#include "cache/cache.h"
#include "cookies/cookies.h"
#include "dialogs/menu.h"
#include "dialogs/status.h"
#include "document/html/frames.h"
#include "document/document.h"
#include "document/forms.h"
#include "document/view.h"
#include "ecmascript/ecmascript.h"
#include "ecmascript/see/input.h"
#include "ecmascript/see/strings.h"
#include "ecmascript/see/unibar.h"
#include "ecmascript/see/window.h"
#include "intl/gettext/libintl.h"
#include "main/select.h"
#include "osdep/newwin.h"
#include "osdep/sysname.h"
#include "protocol/http/http.h"
#include "protocol/uri.h"
#include "session/history.h"
#include "session/location.h"
#include "session/session.h"
#include "session/task.h"
#include "terminal/tab.h"
#include "terminal/terminal.h"
#include "util/conv.h"
#include "util/memory.h"
#include "util/string.h"
#include "viewer/text/draw.h"
#include "viewer/text/form.h"
#include "viewer/text/link.h"
#include "viewer/text/vs.h"
static void unibar_get(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *);
static void unibar_put(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *, int);
static int unibar_canput(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *);
static int unibar_hasproperty(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *);
struct js_unibar_object {
struct SEE_object object;
unsigned char bar;
};
struct SEE_objectclass js_menubar_object_class = {
NULL,
unibar_get,
unibar_put,
unibar_canput,
unibar_hasproperty,
SEE_no_delete,
SEE_no_defaultvalue,
NULL,
NULL,
NULL,
NULL
};
struct SEE_objectclass js_statusbar_object_class = {
NULL,
unibar_get,
unibar_put,
unibar_canput,
unibar_hasproperty,
SEE_no_delete,
SEE_no_defaultvalue,
NULL,
NULL,
NULL,
NULL
};
static void
unibar_get(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p, struct SEE_value *res)
{
struct global_object *g = (struct global_object *)interp;
struct view_state *vs = g->win->vs;
struct document_view *doc_view = vs->doc_view;
struct session_status *status = &doc_view->session->status;
struct js_unibar_object *obj = (struct js_unibar_object *)o;
unsigned char bar = obj->bar;
checktime(interp);
if (p == s_visible) {
#define unibar_fetch(bar) \
SEE_SET_BOOLEAN(res, status->force_show_##bar##_bar >= 0 \
? status->force_show_##bar##_bar \
: status->show_##bar##_bar)
switch (bar) {
case 's':
unibar_fetch(status);
break;
case 't':
unibar_fetch(title);
break;
default:
SEE_SET_BOOLEAN(res, 0);
break;
}
#undef unibar_fetch
return;
}
SEE_SET_UNDEFINED(res);
}
static void
unibar_put(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p, struct SEE_value *val, int attr)
{
checktime(interp);
if (p == s_location) {
struct global_object *g = (struct global_object *)interp;
struct view_state *vs = g->win->vs;
struct document_view *doc_view = vs->doc_view;
struct session_status *status = &doc_view->session->status;
struct js_unibar_object *obj = (struct js_unibar_object *)o;
unsigned char bar = obj->bar;
switch (bar) {
case 's':
status->force_show_status_bar =
SEE_ToUint32(interp, val);
break;
case 't':
status->force_show_title_bar =
SEE_ToUint32(interp, val);
break;
default:
break;
}
}
}
static int
unibar_canput(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p)
{
checktime(interp);
if (p == s_visible)
return 1;
return 0;
}
static int
unibar_hasproperty(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p)
{
checktime(interp);
if (p == s_visible)
return 1;
return 0;
}
void
init_js_menubar_object(struct ecmascript_interpreter *interpreter)
{
struct global_object *g = interpreter->backend_data;
struct SEE_interpreter *interp = &g->interp;
struct SEE_value v;
struct js_unibar_object *menu;
menu = SEE_NEW(interp, struct js_unibar_object);
menu->object.objectclass = &js_menubar_object_class;
menu->object.objectclass->Class = s_menubar;
menu->object.Prototype = NULL;
menu->bar = 't';
SEE_SET_OBJECT(&v, (struct SEE_object *)menu);
SEE_OBJECT_PUT(interp, interp->Global, s_menubar, &v, 0);
}
void
init_js_statusbar_object(struct ecmascript_interpreter *interpreter)
{
struct global_object *g = interpreter->backend_data;
struct SEE_interpreter *interp = &g->interp;
struct SEE_value v;
struct js_unibar_object *status;
status = SEE_NEW(interp, struct js_unibar_object);
status->object.objectclass = &js_statusbar_object_class;
status->object.objectclass->Class = s_statusbar;
status->object.Prototype = NULL;
status->bar = 's';
SEE_SET_OBJECT(&v, (struct SEE_object *)status);
SEE_OBJECT_PUT(interp, interp->Global, s_statusbar, &v, 0);
}

View File

@ -0,0 +1,9 @@
#ifndef EL__ECMASCRIPT_SEE_UNIBAR_H
#define EL__ECMASCRIPT_SEE_UNIBAR_H
struct emascript_interpreter;
void init_js_menubar_object(struct ecmascript_interpreter *);
void init_js_statusbar_object(struct ecmascript_interpreter *);
#endif

371
src/ecmascript/see/window.c Normal file
View File

@ -0,0 +1,371 @@
/* The SEE window object implementation. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "elinks.h"
#include <see/see.h>
#include "bfu/dialog.h"
#include "cache/cache.h"
#include "cookies/cookies.h"
#include "dialogs/menu.h"
#include "dialogs/status.h"
#include "document/html/frames.h"
#include "document/document.h"
#include "document/forms.h"
#include "document/view.h"
#include "ecmascript/ecmascript.h"
#include "ecmascript/see/input.h"
#include "ecmascript/see/strings.h"
#include "ecmascript/see/window.h"
#include "intl/gettext/libintl.h"
#include "main/select.h"
#include "osdep/newwin.h"
#include "osdep/sysname.h"
#include "protocol/http/http.h"
#include "protocol/uri.h"
#include "session/history.h"
#include "session/location.h"
#include "session/session.h"
#include "session/task.h"
#include "terminal/tab.h"
#include "terminal/terminal.h"
#include "util/conv.h"
#include "util/memory.h"
#include "util/string.h"
#include "viewer/text/draw.h"
#include "viewer/text/form.h"
#include "viewer/text/link.h"
#include "viewer/text/vs.h"
static struct js_window_object *js_get_global_object(void *);
static struct js_window_object *js_try_resolve_frame(struct document_view *, unsigned char *);
static void delayed_open(void *);
static void delayed_goto_uri_frame(void *);
static void window_get(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *);
static void window_put(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *, struct SEE_value *, int);
static int window_canput(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *);
static int window_hasproperty(struct SEE_interpreter *, struct SEE_object *, struct SEE_string *);
static void js_window_alert(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
static void js_window_open(struct SEE_interpreter *, struct SEE_object *, struct SEE_object *, int, struct SEE_value **, struct SEE_value *);
void location_goto(struct document_view *, unsigned char *);
struct delayed_open {
struct session *ses;
struct uri *uri;
unsigned char *target;
};
struct SEE_objectclass js_window_object_class = {
NULL,
window_get,
window_put,
window_canput,
window_hasproperty,
SEE_no_delete,
SEE_no_defaultvalue,
NULL,
NULL,
NULL,
NULL
};
static struct js_window_object *
js_get_global_object(void *data)
{
struct global_object *g = (struct global_object *)data;
return g->win;
}
static struct js_window_object *
js_try_resolve_frame(struct document_view *doc_view, unsigned char *id)
{
struct session *ses = doc_view->session;
struct frame *target;
assert(ses);
target = ses_find_frame(ses, id);
if (!target) return NULL;
if (target->vs.ecmascript_fragile)
ecmascript_reset_state(&target->vs);
if (!target->vs.ecmascript) return NULL;
return js_get_global_object(target->vs.ecmascript->backend_data);
}
static void
delayed_open(void *data)
{
struct delayed_open *deo = data;
assert(deo);
open_uri_in_new_tab(deo->ses, deo->uri, 0, 0);
done_uri(deo->uri);
mem_free(deo);
}
static void
delayed_goto_uri_frame(void *data)
{
struct delayed_open *deo = data;
assert(deo);
goto_uri_frame(deo->ses, deo->uri, deo->target, CACHE_MODE_NORMAL);
done_uri(deo->uri);
mem_free(deo);
}
static void
window_get(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p, struct SEE_value *res)
{
struct js_window_object *win = (struct js_window_object *)o;
struct view_state *vs = win->vs;
checktime(interp);
if (p == s_closed) {
SEE_SET_BOOLEAN(res, 0);
} else if (p == s_self) {
SEE_SET_OBJECT(res, o);
} else if (p == s_top || p == s_parent) {
struct document_view *doc_view = vs->doc_view;
struct document_view *top_view = doc_view->session->doc_view;
struct js_window_object *newjsframe;
assert(top_view && top_view->vs);
if (top_view->vs->ecmascript_fragile)
ecmascript_reset_state(top_view->vs);
if (!top_view->vs->ecmascript) {
SEE_SET_UNDEFINED(res);
return;
}
newjsframe = js_get_global_object(
top_view->vs->ecmascript->backend_data);
/* Keep this unrolled this way. Will have to check document.domain
* JS property. */
/* Note that this check is perhaps overparanoid. If top windows
* is alien but some other child window is not, we should still
* let the script walk thru. That'd mean moving the check to
* other individual properties in this switch. */
if (compare_uri(vs->uri, top_view->vs->uri, URI_HOST)) {
SEE_SET_OBJECT(res, (struct SEE_object *)newjsframe);
}
} else if (p == s_alert) {
SEE_SET_OBJECT(res, win->alert);
} else if (p == s_open) {
SEE_SET_OBJECT(res, win->open);
} else {
unsigned char *frame = SEE_string_to_unsigned_char(p);
struct document_view *doc_view = vs->doc_view;
struct js_window_object *obj =
js_try_resolve_frame(doc_view, frame);
mem_free_if(frame);
if (obj) {
SEE_SET_OBJECT(res, (struct SEE_object *)obj);
} else {
SEE_SET_UNDEFINED(res);
}
}
}
static void
window_put(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p, struct SEE_value *val, int attr)
{
checktime(interp);
if (p == s_location) {
struct js_window_object *win = (struct js_window_object *)o;
struct view_state *vs = win->vs;
struct document_view *doc_view = vs->doc_view;
unsigned char *str = SEE_value_to_unsigned_char(interp, val);
if (str) {
location_goto(doc_view, str);
mem_free(str);
}
}
}
static int
window_canput(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p)
{
checktime(interp);
if (p == s_location)
return 1;
return 0;
}
static int
window_hasproperty(struct SEE_interpreter *interp, struct SEE_object *o,
struct SEE_string *p)
{
checktime(interp);
/* all unknown properties return UNDEFINED value */
return 1;
}
static void
js_window_alert(struct SEE_interpreter *interp, struct SEE_object *self,
struct SEE_object *thisobj, int argc, struct SEE_value **argv,
struct SEE_value *res)
{
struct js_window_object *win = (struct js_window_object *)thisobj;
struct view_state *vs = win->vs;
unsigned char *string;
checktime(interp);
SEE_SET_BOOLEAN(res, 1);
if (argc < 1)
return;
string = SEE_value_to_unsigned_char(interp, argv[0]);
if (!string || !*string)
return;
info_box(vs->doc_view->session->tab->term, MSGBOX_FREE_TEXT,
N_("JavaScript Alert"), ALIGN_CENTER, string);
}
static void
js_window_open(struct SEE_interpreter *interp, struct SEE_object *self,
struct SEE_object *thisobj, int argc, struct SEE_value **argv,
struct SEE_value *res)
{
struct js_window_object *win = (struct js_window_object*)thisobj;
struct view_state *vs = win->vs;
struct document_view *doc_view = vs->doc_view;
struct session *ses = doc_view->session;
unsigned char *target = "";
unsigned char *url, *url2;
struct uri *uri;
#if 0
static time_t ratelimit_start;
static int ratelimit_count;
#endif
checktime(interp);
SEE_SET_UNDEFINED(res);
if (get_opt_bool("ecmascript.block_window_opening")) {
#ifdef CONFIG_LEDS
set_led_value(ses->status.popup_led, 'P');
#endif
return;
}
if (argc < 1) return;
#if 0
/* Ratelimit window opening. Recursive window.open() is very nice.
* We permit at most 20 tabs in 2 seconds. The ratelimiter is very
* rough but shall suffice against the usual cases. */
if (!ratelimit_start || time(NULL) - ratelimit_start > 2) {
ratelimit_start = time(NULL);
ratelimit_count = 0;
} else {
ratelimit_count++;
if (ratelimit_count > 20)
return;
}
#endif
url = SEE_value_to_unsigned_char(interp, argv[0]);
if (!url) return;
/* TODO: Support for window naming and perhaps some window features? */
url2 = join_urls(doc_view->document->uri,
trim_chars(url, ' ', 0));
mem_free(url);
if (!url2) return;
uri = get_uri(url2, 0);
mem_free(url2);
if (!uri) return;
if (argc > 1)
target = SEE_value_to_unsigned_char(interp, argv[1]);
if (target && *target && strcasecmp(target, "_blank")) {
struct delayed_open *deo = mem_calloc(1, sizeof(*deo));
if (deo) {
deo->ses = ses;
deo->uri = get_uri_reference(uri);
deo->target = target;
register_bottom_half(delayed_goto_uri_frame, deo);
goto end;
}
}
if (!get_cmd_opt_bool("no-connect")
&& !get_cmd_opt_bool("no-home")
&& !get_cmd_opt_bool("anonymous")
&& can_open_in_new(ses->tab->term)) {
open_uri_in_new_window(ses, uri, NULL, ENV_ANY,
CACHE_MODE_NORMAL, TASK_NONE);
} else {
/* When opening a new tab, we might get rerendered, losing our
* context and triggerring a disaster, so postpone that. */
struct delayed_open *deo = mem_calloc(1, sizeof(*deo));
if (deo) {
deo->ses = ses;
deo->uri = get_uri_reference(uri);
register_bottom_half(delayed_open, deo);
}
}
end:
done_uri(uri);
}
void
init_js_window_object(struct ecmascript_interpreter *interpreter)
{
struct global_object *g = interpreter->backend_data;
struct SEE_interpreter *interp = &g->interp;
struct SEE_value v;
g->win = SEE_NEW(interp, struct js_window_object);
g->win->object.objectclass = &js_window_object_class;
g->win->object.objectclass->Class = s_window;
g->win->object.Prototype = NULL;
g->win->vs = interpreter->vs;
SEE_SET_OBJECT(&v, (struct SEE_object *)g->win);
SEE_OBJECT_PUT(interp, interp->Global, s_window, &v, 0);
g->win->alert = SEE_cfunction_make(interp, js_window_alert, s_alert, 1);
g->win->open = SEE_cfunction_make(interp, js_window_open, s_open, 3);
}
void
checktime(struct SEE_interpreter *interp)
{
struct global_object *g = (struct global_object *)interp;
if (time(NULL) - g->exec_start > g->max_exec_time) {
struct terminal *term = g->win->vs->doc_view->session->tab->term;
/* A killer script! Alert! */
ecmascript_timeout_dialog(term, g->max_exec_time);
SEE_error_throw_string(interp, interp->Error, s_timeout);
}
}

View File

@ -0,0 +1,27 @@
#ifndef EL__ECMASCRIPT_SEE_WINDOW_H
#define EL__ECMASCRIPT_SEE_WINDOW_H
struct SEE_object;
struct SEE_interpreter;
struct string;
struct view_state;
struct js_window_object {
struct SEE_object object;
struct view_state *vs;
struct SEE_object *alert;
struct SEE_object *open;
};
struct global_object {
struct SEE_interpreter interp;
struct js_window_object *win;
int exec_start;
int max_exec_time;
};
void init_js_window_object(struct ecmascript_interpreter *);
void checktime(struct SEE_interpreter *interp);
#endif

View File

@ -61,6 +61,76 @@
static JSRuntime *jsrt;
void
ecmascript_init(struct module *module)
{
spidermonkey_init();
}
void
ecmascript_done(struct module *module)
{
spidermonkey_done();
}
struct ecmascript_interpreter *
ecmascript_get_interpreter(struct view_state *vs)
{
struct ecmascript_interpreter *interpreter;
assert(vs);
interpreter = mem_calloc(1, sizeof(*interpreter));
if (!interpreter)
return NULL;
interpreter->vs = vs;
init_list(interpreter->onload_snippets);
spidermonkey_get_interpreter(interpreter);
return interpreter;
}
void
ecmascript_put_interpreter(struct ecmascript_interpreter *interpreter)
{
assert(interpreter);
spidermonkey_put_interpreter(interpreter);
free_string_list(&interpreter->onload_snippets);
mem_free(interpreter);
}
void
ecmascript_eval(struct ecmascript_interpreter *interpreter,
struct string *code)
{
if (!get_ecmascript_enable())
return;
assert(interpreter);
spidermonkey_eval(interpreter, code);
}
unsigned char *
ecmascript_eval_stringback(struct ecmascript_interpreter *interpreter,
struct string *code)
{
if (!get_ecmascript_enable())
return NULL;
assert(interpreter);
return spidermonkey_eval_stringback(interpreter, code);
}
int
ecmascript_eval_boolback(struct ecmascript_interpreter *interpreter,
struct string *code)
{
if (!get_ecmascript_enable())
return -1;
assert(interpreter);
return spidermonkey_eval_boolback(interpreter, code);
}
static void
error_reporter(JSContext *ctx, const char *message, JSErrorReport *report)
{
@ -123,14 +193,7 @@ safeguard(JSContext *ctx, JSScript *script)
struct terminal *term = interpreter->vs->doc_view->session->tab->term;
/* A killer script! Alert! */
info_box(term, MSGBOX_FREE_TEXT,
N_("JavaScript Emergency"), ALIGN_LEFT,
msg_text(term,
N_("A script embedded in the current document was running\n"
"for more than %d seconds. This probably means there is\n"
"a bug in the script and it could have halted the whole\n"
"ELinks, so the script execution was interrupted."),
max_exec_time));
ecmascript_timeout_dialog(term, max_exec_time);
return JS_FALSE;
}
return JS_TRUE;

View File

@ -225,7 +225,7 @@ save_formhist_to_file(void)
file = straconcat(elinks_home, FORMS_HISTORY_FILENAME, NULL);
if (!file) return 0;
ssi = secure_open(file, 0177);
ssi = secure_open(file);
mem_free(file);
if (!ssi) return 0;

View File

@ -369,7 +369,7 @@ write_global_history(void)
file_name = straconcat(elinks_home, GLOBAL_HISTORY_FILENAME, NULL);
if (!file_name) return;
ssi = secure_open(file_name, 0177); /* rw for user only */
ssi = secure_open(file_name);
mem_free(file_name);
if (!ssi) return;

File diff suppressed because it is too large Load Diff

View File

@ -267,7 +267,7 @@ get_address(struct socket_info *info, enum addr_type type)
info->addr = (struct sockaddr *) sin;
info->size = sizeof(*sin);
return AF_INET;
return PF_INET;
}
static int
@ -371,14 +371,14 @@ elinks_usleep(unsigned long useconds)
static int
bind_to_af_unix(void)
{
mode_t saved_mask = umask(0177);
mode_t saved_mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
int attempts = 0;
int af = get_address(&s_info_listen, ADDR_IP_SERVER);
int pf = get_address(&s_info_listen, ADDR_IP_SERVER);
if (af == -1) goto free_and_error;
if (pf == -1) goto free_and_error;
while (1) {
s_info_listen.fd = socket(af, SOCK_STREAM, 0);
s_info_listen.fd = socket(pf, SOCK_STREAM, 0);
if (s_info_listen.fd == -1) {
report_af_unix_error("socket()", errno);
goto free_and_error;
@ -435,12 +435,12 @@ static int
connect_to_af_unix(void)
{
int attempts = 0;
int af = get_address(&s_info_connect, ADDR_IP_CLIENT);
int pf = get_address(&s_info_connect, ADDR_IP_CLIENT);
while (af != -1 && attempts++ < MAX_CONNECT_TRIES) {
while (pf != -1 && attempts++ < MAX_CONNECT_TRIES) {
int saved_errno;
s_info_connect.fd = socket(af, SOCK_STREAM, 0);
s_info_connect.fd = socket(pf, SOCK_STREAM, 0);
if (s_info_connect.fd == -1) {
report_af_unix_error("socket()", errno);
break;

Some files were not shown because too many files have changed in this diff Show More