mirror of
https://github.com/rkd77/elinks.git
synced 2024-12-04 14:46:47 -05:00
Merge with http://elinks.cz/elinks.git
This commit is contained in:
commit
93714a3e35
@ -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@
|
||||
|
78
Makefile.lib
78
Makefile.lib
@ -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,39 @@ ifneq ($(SPARSE),)
|
||||
$(call ncmd,sparse,$(file));)
|
||||
endif
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Auto-testing infrastructure
|
||||
#
|
||||
|
||||
clean-test:
|
||||
test-default:
|
||||
|
||||
ifdef TEST_PROGS
|
||||
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 +199,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
|
||||
|
1102
Unicode/entities.lnx
1102
Unicode/entities.lnx
File diff suppressed because it is too large
Load Diff
1060
Unicode/entities.txt
Normal file
1060
Unicode/entities.txt
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
@ -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.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -150,7 +150,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.
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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 >:).
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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.
|
||||
@ -681,6 +679,3 @@ to compile or execute in one of these modes, then rework it.
|
||||
|
||||
|
||||
Happy hacking!
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -74,6 +74,3 @@ include::ecmascript.txt[]
|
||||
include::txt/import-features.conf.txt[]
|
||||
|
||||
endif::installation-webpage[]
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -359,7 +359,3 @@ everything is marked TODO!
|
||||
- Insert mode in text-input form-fields.
|
||||
|
||||
- Menu searching.
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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 03 January 06 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 \"03 January 06\"
|
||||
|
||||
.SH NAME
|
||||
elinks.conf \- ELinks configuration file
|
||||
@ -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.
|
||||
@ -782,6 +784,8 @@ in dump output.
|
||||
.TP
|
||||
\f3document.dump.separator\f2 <str>\f1 (document.dump.separator <str> (default: ")
|
||||
.TP
|
||||
\f3String\f2 Swhich\f1 (String which separates two dumps.)
|
||||
.TP
|
||||
\f3document.dump.width\f2 <num>\f1 (default: 80)
|
||||
Width of screen in characters when dumping documents.
|
||||
.PD
|
||||
@ -877,6 +881,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 +891,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 +1054,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 +1353,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,10 +2155,15 @@ 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
|
||||
for recovery after a crash.
|
||||
.TP
|
||||
\f3This\f2 Tfeature\f1 (This feature requires bookmark support.)
|
||||
.SS Window tabs (ui.tabs)
|
||||
Window tabs settings.
|
||||
.TP
|
||||
@ -2225,7 +2246,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 03 January 06 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),
|
||||
|
@ -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\&.
|
||||
|
@ -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.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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".
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -83,6 +83,3 @@ example, by running:
|
||||
|
||||
new tabs containing `slashdot.org`, `freshmeat.net` and a Google search of elinks
|
||||
will be opened.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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.
|
||||
==============================================================================
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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'.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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"
|
||||
;;
|
||||
-)
|
||||
@ -285,7 +288,7 @@ use_log=
|
||||
|
||||
$print_header
|
||||
|
||||
$command | while read line
|
||||
$command | $filter | while read line
|
||||
do
|
||||
if test -n "$parse_description"
|
||||
then
|
||||
@ -323,7 +326,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/'`"
|
||||
|
@ -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.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -12,6 +12,8 @@ PERL = perl
|
||||
# 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 "$@" -- "$<"
|
||||
|
||||
@ -46,7 +48,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)
|
||||
@ -69,7 +71,7 @@ $(srcdir)$(PACKAGE).pot: $(srcdir)$(POTFILES_ABS_LIST) $(srcdir)perl/gather-acce
|
||||
# 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 \
|
||||
|
14
po/fr.po
14
po/fr.po
@ -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-03 13:41+0100\n"
|
||||
"PO-Revision-Date: 2006-01-01 13:42+0100\n"
|
||||
"Last-Translator: Laurent Monin <zas@norz.org>\n"
|
||||
"Language-Team: French <zas@norz.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@ -4674,7 +4674,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 +4685,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 "
|
||||
@ -5983,7 +5983,7 @@ 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"
|
||||
|
||||
|
@ -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];
|
||||
|
@ -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 *
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -194,7 +194,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\".")),
|
||||
@ -731,7 +731,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. */
|
||||
|
@ -144,7 +144,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 "
|
||||
|
@ -61,11 +61,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 +115,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 +158,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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -361,7 +384,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);
|
||||
|
||||
@ -665,7 +688,6 @@ 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;
|
||||
@ -674,6 +696,7 @@ render_dom_document(struct cache_entry *cached, struct document *document,
|
||||
size_t length = strlen(string);
|
||||
struct dom_string uri = INIT_DOM_STRING(string, length);
|
||||
struct dom_string source = INIT_DOM_STRING(buffer->source, buffer->length);
|
||||
enum sgml_parser_code code;
|
||||
|
||||
assert(document->options.plain);
|
||||
|
||||
@ -707,14 +730,18 @@ render_dom_document(struct cache_entry *cached, struct document *document,
|
||||
doctype = SGML_DOCTYPE_HTML;
|
||||
}
|
||||
|
||||
parser = init_sgml_parser(SGML_PARSER_STREAM, doctype, &uri);
|
||||
parser = init_sgml_parser(SGML_PARSER_STREAM, doctype, &uri, 0);
|
||||
if (!parser) return;
|
||||
|
||||
add_dom_stack_context(&parser->stack, &renderer,
|
||||
&dom_source_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;
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
@ -360,7 +360,7 @@ done_dom_node(struct dom_node *node)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
done_dom_node_data(node);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
if (!scanner_info->initialized) {
|
||||
init_dom_scanner_info(scanner_info);
|
||||
@ -170,6 +171,8 @@ 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->lineno = scanner->count_lines;
|
||||
scanner->info->scan(scanner);
|
||||
}
|
||||
|
@ -92,7 +92,8 @@ struct dom_scanner_info {
|
||||
|
||||
/* Initializes the scanner. */
|
||||
void init_dom_scanner(struct dom_scanner *scanner, struct dom_scanner_info *scanner_info,
|
||||
struct dom_string *string, int state, int count_lines);
|
||||
struct dom_string *string, int state, int count_lines, int complete,
|
||||
int check_complete);
|
||||
|
||||
/* The number of tokens in the scanners token table:
|
||||
* At best it should be big enough to contain properties with space separated
|
||||
@ -123,8 +124,14 @@ 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 */
|
||||
|
||||
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;
|
||||
|
@ -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);
|
||||
|
||||
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: ");
|
||||
|
@ -154,7 +154,7 @@ add_sgml_node(struct dom_stack *stack, enum dom_node_type type, struct dom_scann
|
||||
|
||||
/* SGML parser main handling: */
|
||||
|
||||
static inline void
|
||||
static inline enum sgml_parser_code
|
||||
parse_sgml_attributes(struct dom_stack *stack, struct dom_scanner *scanner)
|
||||
{
|
||||
struct dom_scanner_token name;
|
||||
@ -179,22 +179,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 +214,18 @@ 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;
|
||||
|
||||
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 +247,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,7 +311,8 @@ 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;
|
||||
|
||||
assert(token->type == SGML_TOKEN_PROCESS_DATA);
|
||||
|
||||
@ -305,12 +323,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);
|
||||
|
||||
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 +347,9 @@ 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_SPACE:
|
||||
case SGML_TOKEN_TEXT:
|
||||
default:
|
||||
@ -329,30 +357,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 +400,14 @@ 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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -443,6 +478,25 @@ 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);
|
||||
|
||||
return pstate->scanner.lineno;
|
||||
}
|
||||
|
||||
|
||||
/* Parser creation and destruction: */
|
||||
|
||||
@ -486,10 +540,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 +553,20 @@ init_sgml_parser(enum sgml_parser_type type, enum sgml_document_type doctype,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
parser->type = type;
|
||||
parser->info = get_sgml_info(doctype);
|
||||
parser->type = type;
|
||||
parser->flags = flags;
|
||||
parser->info = get_sgml_info(doctype);
|
||||
|
||||
if (type == SGML_PARSER_TREE)
|
||||
flags |= DOM_STACK_KEEP_NODES;
|
||||
if (type == SGML_PARSER_STREAM)
|
||||
stack_flags |= DOM_STACK_FLAG_FREE_NODES;
|
||||
|
||||
init_dom_stack(&parser->stack, flags);
|
||||
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;
|
||||
|
@ -22,6 +22,12 @@ enum sgml_parser_type {
|
||||
SGML_PARSER_STREAM,
|
||||
};
|
||||
|
||||
enum sgml_parser_flag {
|
||||
SGML_PARSER_COUNT_LINES = 1,
|
||||
SGML_PARSER_COMPLETE = 2,
|
||||
SGML_PARSER_INCREMENTAL = 4,
|
||||
};
|
||||
|
||||
struct sgml_parser_state {
|
||||
/* Info about the properties of the node contained by state.
|
||||
* This is only meaningful to element and attribute nodes. For
|
||||
@ -34,6 +40,7 @@ struct sgml_parser_state {
|
||||
|
||||
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 */
|
||||
|
||||
@ -46,10 +53,23 @@ struct sgml_parser {
|
||||
|
||||
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);
|
||||
|
||||
void done_sgml_parser(struct sgml_parser *parser);
|
||||
|
||||
struct dom_node *parse_sgml(struct sgml_parser *parser, struct dom_string *buffer);
|
||||
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,
|
||||
};
|
||||
|
||||
enum sgml_parser_code
|
||||
parse_sgml(struct sgml_parser *parser, struct dom_string *buffer, int complete);
|
||||
|
||||
unsigned int get_sgml_parser_line_number(struct sgml_parser *parser);
|
||||
|
||||
#endif
|
||||
|
@ -98,6 +98,24 @@ 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;
|
||||
}
|
||||
|
||||
/* Text token scanning */
|
||||
|
||||
@ -119,6 +137,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 +148,24 @@ 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 (check_sgml_incomplete(scanner, string) && !complete) {
|
||||
set_sgml_incomplete(scanner, 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 +173,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 +270,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 +283,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 +291,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 +302,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 +313,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 +321,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 +342,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 +357,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 +370,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 +397,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 +407,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);
|
||||
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 +433,14 @@ 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);
|
||||
|
||||
if (is_sgml_space(string[-1])) {
|
||||
/* We found the end. */
|
||||
possibly_incomplete = 0;
|
||||
}
|
||||
|
||||
} else if (*string == '/') {
|
||||
string++;
|
||||
skip_sgml_space(scanner, &string);
|
||||
@ -371,12 +451,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 +470,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 +499,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 +537,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,11 +556,19 @@ 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 && check_sgml_incomplete(scanner, string)) {
|
||||
set_sgml_incomplete(scanner, token);
|
||||
return;
|
||||
}
|
||||
|
||||
token->type = type;
|
||||
token->string.length = real_length >= 0 ? real_length : string - token->string.string;
|
||||
token->precedence = get_sgml_precedence(type);
|
||||
@ -455,6 +582,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 +593,23 @@ 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. */
|
||||
string = scanner->end;
|
||||
|
||||
if (check_sgml_incomplete(scanner, string)) {
|
||||
set_sgml_incomplete(scanner, 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;
|
||||
@ -510,7 +648,6 @@ scan_sgml_tokens(struct dom_scanner *scanner)
|
||||
scan_sgml_text_token(scanner, current);
|
||||
|
||||
} else {
|
||||
skip_sgml_space(scanner, &scanner->position);
|
||||
scan_sgml_proc_inst_token(scanner, current);
|
||||
}
|
||||
}
|
||||
|
@ -48,6 +48,10 @@ 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,
|
||||
|
||||
/* Token type used internally when scanning to signal that the token
|
||||
* should not be recorded in the scanners token table. */
|
||||
SGML_TOKEN_SKIP,
|
||||
|
@ -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--;
|
||||
|
@ -48,8 +48,10 @@ struct dom_stack_context {
|
||||
};
|
||||
|
||||
enum dom_stack_flag {
|
||||
/* Keep nodes when popping them or call done_dom_node() on them. */
|
||||
DOM_STACK_KEEP_NODES = 1,
|
||||
DOM_STACK_FLAG_NONE = 0,
|
||||
|
||||
/* Free nodes when popping them by calling done_dom_node(). */
|
||||
DOM_STACK_FLAG_FREE_NODES = 1,
|
||||
};
|
||||
|
||||
/* The DOM stack is a convenient way to traverse DOM trees. Also it
|
||||
|
@ -11,33 +11,9 @@ 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:
|
||||
TESTDEPS-$(CONFIG_DEBUG) += $(top_builddir)/src/util/memdebug.o \
|
||||
|
||||
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))'
|
||||
|
@ -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,24 @@ 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. */
|
||||
update_number_of_lines(stack);
|
||||
|
||||
print_indent(stack);
|
||||
printf("%.*s: %.*s\n",
|
||||
name->length, name->string,
|
||||
value->length, value->string);
|
||||
}
|
||||
@ -92,12 +120,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 +141,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 +161,27 @@ 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) {
|
||||
printf("%d\n", number_of_lines);
|
||||
}
|
||||
}
|
||||
|
||||
struct dom_stack_context_info sgml_parser_test_context_info = {
|
||||
/* Object size: */ 0,
|
||||
/* Push: */
|
||||
@ -163,7 +211,7 @@ 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,
|
||||
@ -188,9 +236,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 +277,13 @@ 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, "help")) {
|
||||
die(NULL);
|
||||
|
||||
@ -235,22 +292,26 @@ 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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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]*//;
|
||||
@ -24,11 +24,27 @@ test_output_equals () {
|
||||
y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/;
|
||||
s/[^a-zA-Z0-9-]//g;')"
|
||||
|
||||
sgml-parser --uri "$URI" --src "$src" | sed 's/^ //' > output
|
||||
sgml-parser --uri "$URI" --src "$src" $@ | sed 's/^ //' > output
|
||||
echo "#document: $URI" > expected
|
||||
echo "$out" | sed -n '2,$p' >> expected
|
||||
|
||||
test_expect_success "$desc" 'cmp -b output expected'
|
||||
test_expect_success "$desc" 'cmp output expected'
|
||||
}
|
||||
|
||||
test_expect_incomplete () {
|
||||
desc="$1"; shift
|
||||
src="$1"; shift
|
||||
|
||||
URI="test:$(echo "$desc" | sed '
|
||||
s/^[ \t]*\[[^]]*\][ \t]*//;
|
||||
s/[:., \t][:., \t]*/-/g;
|
||||
s/_/-/g;
|
||||
# *cough*
|
||||
y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/;
|
||||
s/[^a-zA-Z0-9-]//g;')"
|
||||
|
||||
test_expect_code 1 "$desc" \
|
||||
"sgml-parser --uri '$URI' --src '$src' --incomplete"
|
||||
}
|
||||
|
||||
|
||||
@ -55,6 +71,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 +89,7 @@ element: root
|
||||
#comment: Hello World! '
|
||||
|
||||
test_output_equals \
|
||||
'Parse comment combinations.' \
|
||||
'Parse comment combinations. (I)' \
|
||||
'<root><!-- <!-- -- > --><!--foo--><!----></root>' \
|
||||
'
|
||||
element: root
|
||||
@ -71,12 +97,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 +210,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.' \
|
||||
@ -220,4 +263,121 @@ element: root
|
||||
attribute: ns:attr -> value
|
||||
proc-instruction: target -> data'
|
||||
|
||||
test_output_equals \
|
||||
'Check line numbers. (I)' \
|
||||
'<!-- line --> number <one />' \
|
||||
'
|
||||
1' \
|
||||
--print-lines
|
||||
|
||||
test_output_equals \
|
||||
'Check line numbers. (II)' \
|
||||
'<
|
||||
line:2
|
||||
line:3
|
||||
=
|
||||
"line:5"
|
||||
><?xml
|
||||
line:7="..."
|
||||
line:8
|
||||
=
|
||||
'\''...'\''></line:10>' \
|
||||
'
|
||||
10' \
|
||||
--print-lines
|
||||
|
||||
test_output_equals \
|
||||
'Check line numbers. (III)' \
|
||||
'1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8' \
|
||||
'
|
||||
8' \
|
||||
--print-lines
|
||||
|
||||
test_expect_incomplete \
|
||||
'Check incomplete comment. (I)' \
|
||||
'<!-'
|
||||
|
||||
test_expect_incomplete \
|
||||
'Check incomplete comment. (II)' \
|
||||
'<!-- ... '
|
||||
|
||||
test_expect_incomplete \
|
||||
'Check incomplete notation. (I)' \
|
||||
'<!'
|
||||
|
||||
test_expect_incomplete \
|
||||
'Check incomplete notation. (II)' \
|
||||
'<!D'
|
||||
|
||||
test_expect_incomplete \
|
||||
'Check incomplete cdata section. (I)' \
|
||||
'<![CDATA[ ... '
|
||||
|
||||
test_expect_incomplete \
|
||||
'Check incomplete cdata section. (II)' \
|
||||
'<![CDAT'
|
||||
|
||||
test_expect_incomplete \
|
||||
'Check incomplete element. (I)' \
|
||||
'<elem...'
|
||||
|
||||
test_expect_incomplete \
|
||||
'Check incomplete element. (II)' \
|
||||
'<'
|
||||
|
||||
test_expect_incomplete \
|
||||
'Check incomplete element end. (I)' \
|
||||
'<a></a'
|
||||
|
||||
test_expect_incomplete \
|
||||
'Check incomplete element end. (II)' \
|
||||
'<a></'
|
||||
|
||||
test_expect_incomplete \
|
||||
'Check incomplete attribute.' \
|
||||
'<element attr...'
|
||||
|
||||
test_expect_incomplete \
|
||||
'Check incomplete attribute value.' \
|
||||
'<element attr=...'
|
||||
|
||||
test_expect_incomplete \
|
||||
'Check incomplete attribute quoted value. (I)' \
|
||||
'<element attr="...'
|
||||
|
||||
test_expect_incomplete \
|
||||
'Check incomplete attribute quoted value. (II)' \
|
||||
'<element attr='\''...'
|
||||
|
||||
test_expect_incomplete \
|
||||
'Check incomplete processing instruction. (I)' \
|
||||
'<?xml'
|
||||
|
||||
test_expect_incomplete \
|
||||
'Check incomplete processing instruction. (II)' \
|
||||
'<?xml attr...'
|
||||
|
||||
test_expect_incomplete \
|
||||
'Check incomplete notation.' \
|
||||
'<!DOCTYPE html PUBLIC ...'
|
||||
|
||||
test_expect_incomplete \
|
||||
'Check incomplete reference. (I)' \
|
||||
'�'
|
||||
|
||||
test_expect_incomplete \
|
||||
'Check incomplete reference. (II)' \
|
||||
'&'
|
||||
|
||||
test_expect_incomplete \
|
||||
'Check incomplete text.' \
|
||||
'plain text is always incomplete (if incomplete)'
|
||||
|
||||
test_done
|
||||
|
2006
src/intl/entity.inc
2006
src/intl/entity.inc
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
@ -373,12 +373,12 @@ bind_to_af_unix(void)
|
||||
{
|
||||
mode_t saved_mask = umask(0177);
|
||||
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;
|
||||
|
@ -283,7 +283,7 @@ parse_optional_fields(struct mailcap_entry *entry, unsigned char *line)
|
||||
if (!field) break;
|
||||
|
||||
if (!strncasecmp(field, "needsterminal", 13)) {
|
||||
entry->needsterminal = 1;
|
||||
entry->needsterminal = 1;
|
||||
|
||||
} else if (!strncasecmp(field, "copiousoutput", 13)) {
|
||||
entry->copiousoutput = 1;
|
||||
|
@ -49,7 +49,7 @@ struct keepalive_connection {
|
||||
timeval_T timeout;
|
||||
timeval_T creation_time;
|
||||
|
||||
unsigned int protocol_family:1; /* 0 == PF_INET, 1 == PF_INET6 */
|
||||
unsigned int protocol_family:1; /* see network/socket.h, EL_PF_INET, EL_PF_INET6 */
|
||||
int socket;
|
||||
};
|
||||
|
||||
|
@ -279,7 +279,7 @@ get_pasv_socket(struct socket *ctrl_socket, struct sockaddr_storage *addr)
|
||||
#ifdef CONFIG_IPV6
|
||||
struct sockaddr_in6 bind_addr6;
|
||||
|
||||
if (ctrl_socket->protocol_family == 1) {
|
||||
if (ctrl_socket->protocol_family == EL_PF_INET6) {
|
||||
bind_addr = (struct sockaddr *) &bind_addr6;
|
||||
addrlen = sizeof(bind_addr6);
|
||||
} else
|
||||
@ -303,7 +303,7 @@ sock_error:
|
||||
|
||||
/* Get a passive socket */
|
||||
|
||||
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (sock < 0)
|
||||
goto sock_error;
|
||||
|
||||
@ -316,7 +316,7 @@ sock_error:
|
||||
|
||||
memcpy(bind_addr, pasv_addr, addrlen);
|
||||
#ifdef CONFIG_IPV6
|
||||
if (ctrl_socket->protocol_family == 1)
|
||||
if (ctrl_socket->protocol_family == EL_PF_INET6)
|
||||
bind_addr6.sin6_port = 0;
|
||||
else
|
||||
#endif
|
||||
@ -484,6 +484,10 @@ connect_socket(struct socket *csocket, enum connection_state state)
|
||||
int only_local = get_cmd_opt_bool("localhost");
|
||||
int saved_errno = 0;
|
||||
int at_least_one_remote_ip = 0;
|
||||
#ifdef CONFIG_IPV6
|
||||
int try_ipv6 = get_opt_bool("connection.try_ipv6");
|
||||
#endif
|
||||
int try_ipv4 = get_opt_bool("connection.try_ipv4");
|
||||
/* We tried something but we failed in such a way that we would rather
|
||||
* prefer the connection to retain the information about previous
|
||||
* failures. That is, we i.e. decided we are forbidden to even think
|
||||
@ -501,24 +505,20 @@ connect_socket(struct socket *csocket, enum connection_state state)
|
||||
for (i = connect_info->triedno + 1; i < connect_info->addrno; i++) {
|
||||
#ifdef CONFIG_IPV6
|
||||
struct sockaddr_in6 addr = *((struct sockaddr_in6 *) &connect_info->addr[i]);
|
||||
int family = addr.sin6_family;
|
||||
#else
|
||||
struct sockaddr_in addr = *((struct sockaddr_in *) &connect_info->addr[i]);
|
||||
int family = addr.sin_family;
|
||||
#endif
|
||||
int family;
|
||||
int pf;
|
||||
int force_family = connect_info->ip_family;
|
||||
|
||||
#ifdef CONFIG_IPV6
|
||||
family = addr.sin6_family;
|
||||
#else
|
||||
family = addr.sin_family;
|
||||
#endif
|
||||
|
||||
connect_info->triedno++;
|
||||
|
||||
if (only_local) {
|
||||
int local = 0;
|
||||
#ifdef CONFIG_IPV6
|
||||
if (addr.sin6_family == AF_INET6)
|
||||
if (family == AF_INET6)
|
||||
local = check_if_local_address6((struct sockaddr_in6 *) &addr);
|
||||
else
|
||||
#endif
|
||||
@ -532,18 +532,28 @@ connect_socket(struct socket *csocket, enum connection_state state)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IPV6
|
||||
if (family == AF_INET6 && (!get_opt_bool("connection.try_ipv6") || (force_family && force_family != 6))) {
|
||||
silent_fail = 1;
|
||||
continue;
|
||||
if (family == AF_INET6) {
|
||||
if (!try_ipv6 || (force_family && force_family != 6)) {
|
||||
silent_fail = 1;
|
||||
continue;
|
||||
}
|
||||
pf = PF_INET6;
|
||||
|
||||
} else
|
||||
#endif
|
||||
if (family == AF_INET && (!get_opt_bool("connection.try_ipv4") || (force_family && force_family != 4))) {
|
||||
silent_fail = 1;
|
||||
if (family == AF_INET) {
|
||||
if (!try_ipv4 || (force_family && force_family != 4)) {
|
||||
silent_fail = 1;
|
||||
continue;
|
||||
}
|
||||
pf = PF_INET;
|
||||
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
silent_fail = 0;
|
||||
|
||||
sock = socket(family, SOCK_STREAM, IPPROTO_TCP);
|
||||
sock = socket(pf, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (sock == -1) {
|
||||
if (errno && !saved_errno) saved_errno = errno;
|
||||
continue;
|
||||
@ -568,11 +578,11 @@ connect_socket(struct socket *csocket, enum connection_state state)
|
||||
* something else ;-). --pasky */
|
||||
|
||||
#ifdef CONFIG_IPV6
|
||||
if (addr.sin6_family == AF_INET6) {
|
||||
if (family == AF_INET6) {
|
||||
if (connect(sock, (struct sockaddr *) &addr,
|
||||
sizeof(struct sockaddr_in6)) == 0) {
|
||||
/* Success */
|
||||
csocket->protocol_family = 1;
|
||||
csocket->protocol_family = EL_PF_INET6;
|
||||
complete_connect_socket(csocket, NULL, NULL);
|
||||
return;
|
||||
}
|
||||
@ -582,7 +592,7 @@ connect_socket(struct socket *csocket, enum connection_state state)
|
||||
if (connect(sock, (struct sockaddr *) &addr,
|
||||
sizeof(struct sockaddr_in)) == 0) {
|
||||
/* Success */
|
||||
csocket->protocol_family = 0;
|
||||
csocket->protocol_family = EL_PF_INET;
|
||||
complete_connect_socket(csocket, NULL, NULL);
|
||||
return;
|
||||
}
|
||||
|
@ -94,12 +94,14 @@ struct socket {
|
||||
* lot of compilation time. --pasky */
|
||||
void *ssl;
|
||||
|
||||
unsigned int protocol_family:1; /* 0 == PF_INET, 1 == PF_INET6 */
|
||||
unsigned int protocol_family:1; /* EL_PF_INET, EL_PF_INET6 */
|
||||
unsigned int need_ssl:1; /* If the socket needs SSL support */
|
||||
unsigned int no_tls:1; /* Internal SSL flag. */
|
||||
unsigned int duplex:1; /* Allow simultaneous reads & writes. */
|
||||
};
|
||||
|
||||
#define EL_PF_INET 0
|
||||
#define EL_PF_INET6 1
|
||||
|
||||
/* Socket management: */
|
||||
|
||||
|
@ -51,9 +51,9 @@ be_close(int s)
|
||||
}
|
||||
|
||||
int
|
||||
be_socket(int af, int sock, int prot)
|
||||
be_socket(int pf, int sock, int prot)
|
||||
{
|
||||
int h = socket(af, sock, prot);
|
||||
int h = socket(pf, sock, prot);
|
||||
|
||||
if (h < 0) return h;
|
||||
return h + SHS;
|
||||
@ -122,13 +122,13 @@ be_pipe(int *fd)
|
||||
int retry_count = 0;
|
||||
|
||||
again:
|
||||
s1 = be_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
s1 = be_socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (s1 < 0) {
|
||||
/*perror("socket1");*/
|
||||
goto fatal_retry;
|
||||
}
|
||||
|
||||
s2 = be_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
s2 = be_socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (s2 < 0) {
|
||||
/*perror("socket2");*/
|
||||
be_close(s1);
|
||||
|
@ -82,13 +82,13 @@
|
||||
#include "osdep/getifaddrs.h"
|
||||
|
||||
|
||||
#if (defined(AF_INET6) && defined(SIOCGIF6CONF) && defined(SIOCGIF6FLAGS)) \
|
||||
|| (defined(AF_INET) && defined(SIOCGIFCONF) && defined(SIOCGIFFLAGS)) \
|
||||
#if (defined(PF_INET6) && defined(SIOCGIF6CONF) && defined(SIOCGIF6FLAGS)) \
|
||||
|| (defined(PF_INET) && defined(SIOCGIFCONF) && defined(SIOCGIFFLAGS)) \
|
||||
|| (defined(CONFIG_IPV6) && defined(SIOCGIFCONF))
|
||||
|
||||
static int
|
||||
getifaddrs2(struct ifaddrs **ifap,
|
||||
int af, int siocgifconf, int siocgifflags, size_t ifreq_sz)
|
||||
int pf, int siocgifconf, int siocgifflags, size_t ifreq_sz)
|
||||
{
|
||||
struct sockaddr sa_zero;
|
||||
struct ifreq *ifr;
|
||||
@ -104,7 +104,7 @@ getifaddrs2(struct ifaddrs **ifap,
|
||||
int num, j = 0;
|
||||
|
||||
memset(&sa_zero, 0, sizeof(sa_zero));
|
||||
fd = socket(af, SOCK_DGRAM, 0);
|
||||
fd = socket(pf, SOCK_DGRAM, 0);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
@ -240,19 +240,19 @@ getifaddrs(struct ifaddrs **ifap)
|
||||
|
||||
errno = ENXIO;
|
||||
|
||||
#if defined(AF_INET6) && defined(SIOCGIF6CONF) && defined(SIOCGIF6FLAGS)
|
||||
#if defined(PF_INET6) && defined(SIOCGIF6CONF) && defined(SIOCGIF6FLAGS)
|
||||
if (ret)
|
||||
ret = getifaddrs2(ifap, AF_INET6, SIOCGIF6CONF, SIOCGIF6FLAGS,
|
||||
ret = getifaddrs2(ifap, PF_INET6, SIOCGIF6CONF, SIOCGIF6FLAGS,
|
||||
sizeof(struct in6_ifreq));
|
||||
#endif
|
||||
#if defined(CONFIG_IPV6) && defined(SIOCGIFCONF)
|
||||
if (ret)
|
||||
ret = getifaddrs2(ifap, AF_INET6, SIOCGIFCONF, SIOCGIFFLAGS,
|
||||
ret = getifaddrs2(ifap, PF_INET6, SIOCGIFCONF, SIOCGIFFLAGS,
|
||||
sizeof(struct ifreq));
|
||||
#endif
|
||||
#if defined(AF_INET) && defined(SIOCGIFCONF) && defined(SIOCGIFFLAGS)
|
||||
#if defined(PF_INET) && defined(SIOCGIFCONF) && defined(SIOCGIFFLAGS)
|
||||
if (ret)
|
||||
ret = getifaddrs2(ifap, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS,
|
||||
ret = getifaddrs2(ifap, PF_INET, SIOCGIFCONF, SIOCGIFFLAGS,
|
||||
sizeof(struct ifreq));
|
||||
#endif
|
||||
|
||||
@ -322,7 +322,7 @@ main()
|
||||
{
|
||||
struct ifaddrs *a = NULL, *b;
|
||||
|
||||
getifaddrs2(&a, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS,
|
||||
getifaddrs2(&a, PF_INET, SIOCGIFCONF, SIOCGIFFLAGS,
|
||||
sizeof(struct ifreq));
|
||||
print_ifaddrs(a);
|
||||
printf("---\n");
|
||||
|
@ -347,9 +347,9 @@ win32_ioctl(int fd, long option, int *flag)
|
||||
}
|
||||
|
||||
int
|
||||
win32_socket(int family, int type, int protocol)
|
||||
win32_socket(int pf, int type, int protocol)
|
||||
{
|
||||
SOCKET s = socket(family, type, protocol);
|
||||
SOCKET s = socket(pf, type, protocol);
|
||||
int rc;
|
||||
|
||||
if (s == INVALID_SOCKET) {
|
||||
@ -359,7 +359,7 @@ win32_socket(int family, int type, int protocol)
|
||||
rc = s + SOCK_SHIFT;
|
||||
}
|
||||
|
||||
TRACE("family %d, type %d, proto %d -> rc %d", family, type, protocol, rc);
|
||||
TRACE("family %d, type %d, proto %d -> rc %d", pf, type, protocol, rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
int win32_write(int fd, const void *buf, unsigned len);
|
||||
int win32_read(int fd, void *buf, unsigned len);
|
||||
int win32_pipe(int *fds);
|
||||
int win32_socket(int af, int type, int proto);
|
||||
int win32_socket(int pf, int type, int proto);
|
||||
int win32_connect(int fd, struct sockaddr *addr, int addr_len);
|
||||
int win32_getpeername(int fd, struct sockaddr *addr, int *addr_len);
|
||||
int win32_getsockname(int fd, struct sockaddr *addr, int *addr_len);
|
||||
@ -33,7 +33,7 @@ char *win32_strerror(int err);
|
||||
#define write win32_write
|
||||
#define close win32_close
|
||||
#define pipe win32_pipe
|
||||
#define socket(af, type, prot) win32_socket(af, type, prot)
|
||||
#define socket(pf, type, prot) win32_socket(pf, type, prot)
|
||||
#define connect(fd, a, al) win32_connect(fd, a, al)
|
||||
#define getpeername(fd, a, al) win32_getpeername(fd, a, al)
|
||||
#define getsockname(fd, a, al) win32_getsockname(fd, a, al)
|
||||
|
@ -369,7 +369,7 @@ init_bittorrent_listening_socket(struct connection *conn)
|
||||
if (bittorrent_socket != -1)
|
||||
close(bittorrent_socket);
|
||||
|
||||
bittorrent_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
bittorrent_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (bittorrent_socket < 0)
|
||||
return -errno;
|
||||
|
||||
|
@ -585,28 +585,9 @@ remove_bittorrent_peer_from_piece_cache(struct bittorrent_peer_connection *peer)
|
||||
static enum bittorrent_state
|
||||
create_bittorrent_path(unsigned char *path)
|
||||
{
|
||||
int pos;
|
||||
int ret = mkalldirs(path);
|
||||
|
||||
if (!*path) return BITTORRENT_STATE_ERROR;
|
||||
|
||||
for (pos = 1; path[pos]; pos++) {
|
||||
unsigned char separator = path[pos];
|
||||
int ret;
|
||||
|
||||
if (!dir_sep(separator))
|
||||
continue;
|
||||
|
||||
path[pos] = 0;
|
||||
|
||||
ret = mkdir(path, S_IREAD | S_IWRITE | S_IEXEC);
|
||||
|
||||
path[pos] = separator;
|
||||
|
||||
if (ret < 0 && errno != EEXIST)
|
||||
return BITTORRENT_STATE_ERROR;
|
||||
}
|
||||
|
||||
return BITTORRENT_STATE_OK;
|
||||
return (ret ? BITTORRENT_STATE_ERROR : BITTORRENT_STATE_OK);
|
||||
}
|
||||
|
||||
/* Complementary to the above rmdir()s each directory in the path. */
|
||||
|
@ -3,4 +3,19 @@ include $(top_builddir)/Makefile.config
|
||||
|
||||
OBJS = ftp.o parse.o
|
||||
|
||||
TEST_PROGS = ftp-parser
|
||||
|
||||
TESTDEPS = \
|
||||
$(top_builddir)/src/osdep/stub.o \
|
||||
$(top_builddir)/src/protocol/date.o \
|
||||
$(top_builddir)/src/protocol/ftp/parse.o \
|
||||
$(top_builddir)/src/util/conv.o \
|
||||
$(top_builddir)/src/util/error.o \
|
||||
$(top_builddir)/src/util/hash.o \
|
||||
$(top_builddir)/src/util/memory.o \
|
||||
$(top_builddir)/src/util/string.o \
|
||||
$(top_builddir)/src/util/time.o
|
||||
|
||||
TESTDEPS-$(CONFIG_DEBUG) += $(top_builddir)/src/util/memdebug.o
|
||||
|
||||
include $(top_srcdir)/Makefile.lib
|
||||
|
72
src/protocol/ftp/ftp-parser.c
Normal file
72
src/protocol/ftp/ftp-parser.c
Normal file
@ -0,0 +1,72 @@
|
||||
/* Tool for testing the FTP parser */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "elinks.h"
|
||||
|
||||
#include "protocol/ftp/parse.h"
|
||||
|
||||
|
||||
void die(const char *msg, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (msg) {
|
||||
va_start(args, msg);
|
||||
vfprintf(stderr, msg, args);
|
||||
fputs("\n", stderr);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
exit(!!NULL);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct ftp_file_info ftp_info = INIT_FTP_FILE_INFO;
|
||||
unsigned char *response = "";
|
||||
int responselen = 0;
|
||||
int i;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
char *arg = argv[i];
|
||||
|
||||
if (strncmp(arg, "--", 2))
|
||||
break;
|
||||
|
||||
arg += 2;
|
||||
|
||||
if (!strncmp(arg, "response", 8)) {
|
||||
arg += 8;
|
||||
if (*arg == '=') {
|
||||
arg++;
|
||||
response = arg;
|
||||
} else {
|
||||
i++;
|
||||
if (i >= argc)
|
||||
die("--response expects a string");
|
||||
response = argv[i];
|
||||
}
|
||||
responselen = strlen(response);
|
||||
|
||||
} else {
|
||||
die("Unknown argument '%s'", arg - 2);
|
||||
}
|
||||
}
|
||||
|
||||
if (!responselen)
|
||||
die("Usage: %s --response \"string\"", argv[0]);
|
||||
|
||||
if (parse_ftp_file_info(&ftp_info, response, responselen))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
@ -592,7 +592,7 @@ get_ftp_data_socket(struct connection *conn, struct string *command)
|
||||
#ifdef CONFIG_IPV6
|
||||
ftp->use_epsv = get_opt_bool("protocol.ftp.use_epsv");
|
||||
|
||||
if (conn->socket->protocol_family == 1) {
|
||||
if (conn->socket->protocol_family == EL_PF_INET6) {
|
||||
if (ftp->use_epsv) {
|
||||
add_to_string(command, "EPSV");
|
||||
|
||||
@ -836,10 +836,10 @@ next:
|
||||
}
|
||||
|
||||
static int
|
||||
ftp_data_connect(struct connection *conn, int family, struct sockaddr_storage *sa,
|
||||
ftp_data_connect(struct connection *conn, int pf, struct sockaddr_storage *sa,
|
||||
int size_of_sockaddr)
|
||||
{
|
||||
int fd = socket(family, SOCK_STREAM, 0);
|
||||
int fd = socket(pf, SOCK_STREAM, 0);
|
||||
|
||||
if (fd < 0 || set_nonblocking_fd(fd) < 0) {
|
||||
abort_connection(conn, S_FTP_ERROR);
|
||||
@ -1140,24 +1140,6 @@ ftp_process_dirlist(struct cache_entry *cached, off_t *pos,
|
||||
int *tries, int colorize_dir, unsigned char *dircolor)
|
||||
{
|
||||
int ret = 0;
|
||||
#ifdef DEBUG_FTP_PARSER
|
||||
static int debug_ftp_parser = 1;
|
||||
int buflen_orig = buflen;
|
||||
unsigned char *response_orig = NULL;
|
||||
|
||||
if (debug_ftp_parser) {
|
||||
buffer = get_ftp_debug_parse_responses(buffer, buflen);
|
||||
buflen = strlen(buffer);
|
||||
response_orig = buffer;
|
||||
debug_ftp_parser = 0;
|
||||
}
|
||||
|
||||
#define end_ftp_dirlist_processing() do { mem_free_if(response_orig); } while (0)
|
||||
#define get_ftp_dirlist_offset(retval) int_min(retval, buflen_orig)
|
||||
#else
|
||||
#define end_ftp_dirlist_processing() /* Nothing to free */
|
||||
#define get_ftp_dirlist_offset(retval) (retval)
|
||||
#endif
|
||||
|
||||
while (1) {
|
||||
struct ftp_file_info ftp_info = INIT_FTP_FILE_INFO;
|
||||
@ -1180,8 +1162,7 @@ ftp_process_dirlist(struct cache_entry *cached, off_t *pos,
|
||||
if (bufp && buf[bufp - 1] == ASCII_CR) bufp--;
|
||||
} else {
|
||||
if (!bufp || (!last && bufl < FTP_BUF_SIZE)) {
|
||||
end_ftp_dirlist_processing();
|
||||
return get_ftp_dirlist_offset(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret += bufp;
|
||||
@ -1200,8 +1181,7 @@ ftp_process_dirlist(struct cache_entry *cached, off_t *pos,
|
||||
retv = display_dir_entry(cached, pos, tries, colorize_dir,
|
||||
dircolor, &ftp_info);
|
||||
if (retv < 0) {
|
||||
end_ftp_dirlist_processing();
|
||||
return get_ftp_dirlist_offset(ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_FTP_PARSER
|
||||
@ -1221,9 +1201,9 @@ ftp_data_accept(struct connection *conn)
|
||||
set_connection_timeout(conn);
|
||||
clear_handlers(conn->data_socket->fd);
|
||||
|
||||
if ((conn->socket->protocol_family != 1 && ftp->use_pasv)
|
||||
if ((conn->socket->protocol_family != EL_PF_INET6 && ftp->use_pasv)
|
||||
#ifdef CONFIG_IPV6
|
||||
|| (conn->socket->protocol_family == 1 && ftp->use_epsv)
|
||||
|| (conn->socket->protocol_family == EL_PF_INET6 && ftp->use_epsv)
|
||||
#endif
|
||||
) {
|
||||
newsock = conn->data_socket->fd;
|
||||
|
@ -32,6 +32,9 @@
|
||||
#include "util/time.h"
|
||||
|
||||
|
||||
/* Examples of what the FTP parser is supposed to handle (and not handle) can
|
||||
* be found in the test-ftp-parser file. */
|
||||
|
||||
#define skip_space_end(src, end) \
|
||||
do { while ((src) < (end) && *(src) == ' ') (src)++; } while (0)
|
||||
|
||||
@ -59,16 +62,7 @@ parse_ftp_number(unsigned char **src, unsigned char *end, long from, long to)
|
||||
/* Parser for the EPLF format (see http://pobox.com/~djb/proto/eplf.txt).
|
||||
*
|
||||
* Lines end with \r\n (CR-LF), but that is handled elsewhere.
|
||||
*
|
||||
* Some example EPLF response, with the filename separator (tab) displayed as a
|
||||
* space:
|
||||
*/
|
||||
#ifdef DEBUG_FTP_PARSER
|
||||
static unsigned char ftp_eplf_responses[] =
|
||||
"+i8388621.48594,m825718503,r,s280,\tdjb.html\r\n"
|
||||
"+i8388621.50690,m824255907,/,\t514\r\n"
|
||||
"+i8388621.48598,m824253270,r,s612,\t514.html\r\n";
|
||||
#endif
|
||||
|
||||
enum ftp_eplf {
|
||||
FTP_EPLF_FILENAME = ASCII_TAB, /* Filename follows */
|
||||
@ -128,27 +122,6 @@ parse_ftp_eplf_response(struct ftp_file_info *info, unsigned char *src, int len)
|
||||
|
||||
|
||||
/* Parser for UNIX-style listing: */
|
||||
#ifdef DEBUG_FTP_PARSER
|
||||
static unsigned char ftp_unix_responses[] =
|
||||
/* ftp.freebsd.org response */
|
||||
"drwxrwxr-x 3 0 0 512 Apr 17 2003 pub\r\n"
|
||||
/* UNIX-style listing, without inum and without blocks: */
|
||||
"-rw-r--r-- 1 root other 531 Jan 29 03:26 README\r\n"
|
||||
"dr-xr-xr-x 2 root other 512 Apr 8 1994 etc\r\n"
|
||||
"dr-xr-xr-x 2 root 512 Apr 8 1994 etc\r\n"
|
||||
"lrwxrwxrwx 1 root other 7 Jan 25 00:17 bin -> usr/bin\r\n"
|
||||
/* Also produced by Microsoft's FTP servers for Windows: */
|
||||
"---------- 1 owner group 1803128 Jul 10 10:18 ls-lR.Z\r\n"
|
||||
"d--------- 1 owner group 0 May 9 19:45 Softlib\r\n"
|
||||
/* Also WFTPD for MSDOS: */
|
||||
"-rwxrwxrwx 1 noone nogroup 322 Aug 19 1996 message.ftp\r\n"
|
||||
/* Also NetWare: */
|
||||
"d [R----F--] supervisor 512 Jan 16 18:53 login\r\n"
|
||||
"- [R----F--] rhesus 214059 Oct 20 15:27 cx.exe\r\n"
|
||||
/* Also NetPresenz for the Mac: */
|
||||
"-------r-- 326 1391972 1392298 Nov 22 1995 MegaPhone.sit\r\n"
|
||||
"drwxrwxr-x folder 2 May 10 1996 network\r\n";
|
||||
#endif
|
||||
|
||||
enum ftp_unix {
|
||||
FTP_UNIX_PERMISSIONS,
|
||||
@ -429,15 +402,6 @@ parse_ftp_unix_response(struct ftp_file_info *info, unsigned char *src, int len)
|
||||
|
||||
|
||||
/* Parser for VMS-style MultiNet (some spaces removed from examples): */
|
||||
#ifdef DEBUG_FTP_PARSER
|
||||
static unsigned char ftp_vms_responses[] =
|
||||
"00README.TXT;1 2 30-DEC-1996 17:44 [SYSTEM] (RWED,RWED,RE,RE)\r\n"
|
||||
"CORE.DIR;1 1 8-SEP-1996 16:09 [SYSTEM] (RWE,RWE,RE,RE)\r\n"
|
||||
/* And non-MutliNet VMS: */
|
||||
"CII-MANUAL.TEX;1 213/216 29-JAN-1996 03:33:12 [ANONYMOU,ANONYMOUS] (RWED,RWED,,)\r\n"
|
||||
/* A garbage line which should fail: */
|
||||
"EA95_0PS.GZ;1 No privilege for attempted operation\r\n";
|
||||
#endif
|
||||
|
||||
/* Converts VMS symbolic permissions to number-style ones, e.g. string
|
||||
* RWED,RWE,RE to 755. "D" (delete) is taken to be equal to "W" (write).
|
||||
@ -554,12 +518,6 @@ parse_ftp_vms_response(struct ftp_file_info *info, unsigned char *src, int len)
|
||||
|
||||
|
||||
/* Parser for the MSDOS-style format: */
|
||||
#ifdef DEBUG_FTP_PARSER
|
||||
static unsigned char ftp_winnt_responses[] =
|
||||
"04-27-00 09:09PM <DIR> licensed\r\n"
|
||||
"07-18-00 10:16AM <DIR> pub\r\n"
|
||||
"04-14-00 03:47PM 589 readme.htm\r\n";
|
||||
#endif
|
||||
|
||||
struct ftp_file_info *
|
||||
parse_ftp_winnt_response(struct ftp_file_info *info, unsigned char *src, int len)
|
||||
@ -639,26 +597,6 @@ parse_ftp_winnt_response(struct ftp_file_info *info, unsigned char *src, int len
|
||||
return info;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FTP_PARSER
|
||||
unsigned char *
|
||||
get_ftp_debug_parse_responses(unsigned char *buffer, int buflen)
|
||||
{
|
||||
struct string response;
|
||||
|
||||
if (!init_string(&response))
|
||||
return NULL;
|
||||
|
||||
add_to_string(&response, ftp_eplf_responses);
|
||||
add_to_string(&response, ftp_unix_responses);
|
||||
add_to_string(&response, ftp_vms_responses);
|
||||
add_to_string(&response, ftp_winnt_responses);
|
||||
|
||||
add_bytes_to_string(&response, buffer, buflen);
|
||||
|
||||
return response.source;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
struct ftp_file_info *
|
||||
parse_ftp_file_info(struct ftp_file_info *info, unsigned char *src, int len)
|
||||
|
@ -38,14 +38,4 @@ struct ftp_file_info {
|
||||
struct ftp_file_info *
|
||||
parse_ftp_file_info(struct ftp_file_info *info, unsigned char *src, int len);
|
||||
|
||||
/* Define to feed debug FTP responses into the parser. Then point ELinks to an
|
||||
* FTP server to run the tests. */
|
||||
#if 0
|
||||
#define DEBUG_FTP_PARSER
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_FTP_PARSER
|
||||
unsigned char *get_ftp_debug_parse_responses(unsigned char *buffer, int buflen);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
123
src/protocol/ftp/test-ftp-parser
Normal file
123
src/protocol/ftp/test-ftp-parser
Normal file
@ -0,0 +1,123 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2005 Jonas Fonseca
|
||||
#
|
||||
|
||||
test_description='Test parsing of FTP responses.
|
||||
|
||||
It tests responses from several different FTP servers.
|
||||
'
|
||||
|
||||
. "$TEST_LIB"
|
||||
|
||||
CRNL="\r\n"
|
||||
|
||||
test_ftp_response_expect_success () {
|
||||
desc="$1"; shift
|
||||
response="$1"; shift
|
||||
|
||||
response="$(echo "$response" | sed -n '2,$p')"
|
||||
|
||||
test_expect_success "$desc" \
|
||||
"ftp-parser --response \"$response\""
|
||||
}
|
||||
|
||||
test_ftp_response_expect_failure () {
|
||||
desc="$1"; shift
|
||||
response="$1"; shift
|
||||
|
||||
response="$(echo "$response" | sed -n '2,$p')"
|
||||
|
||||
test_expect_failure "$desc" \
|
||||
"ftp-parser --response \"$response\""
|
||||
}
|
||||
|
||||
#############################################################################
|
||||
#
|
||||
# Parser for UNIX-style listing:
|
||||
#
|
||||
|
||||
test_ftp_response_expect_success \
|
||||
'ftp.freebsd.org response' \
|
||||
"
|
||||
drwxrwxr-x 3 0 0 512 Apr 17 2003 pub\r\n"
|
||||
|
||||
test_ftp_response_expect_success \
|
||||
'UNIX-style listing, without inum and without blocks' \
|
||||
"
|
||||
-rw-r--r-- 1 root other 531 Jan 29 03:26 README\r\n
|
||||
dr-xr-xr-x 2 root other 512 Apr 8 1994 etc\r\n
|
||||
dr-xr-xr-x 2 root 512 Apr 8 1994 etc\r\n
|
||||
lrwxrwxrwx 1 root other 7 Jan 25 00:17 bin -> usr/bin\r\n"
|
||||
|
||||
test_ftp_response_expect_success \
|
||||
"Response produced by Microsoft's FTP servers for Windows" \
|
||||
"
|
||||
---------- 1 owner group 1803128 Jul 10 10:18 ls-lR.Z\r\n
|
||||
d--------- 1 owner group 0 May 9 19:45 Softlib\r\n"
|
||||
|
||||
test_ftp_response_expect_success \
|
||||
'Response from WFTPD for MSDOS' \
|
||||
"
|
||||
-rwxrwxrwx 1 noone nogroup 322 Aug 19 1996 message.ftp\r\n"
|
||||
|
||||
test_ftp_response_expect_success \
|
||||
'Response from NetWare' \
|
||||
"
|
||||
d[R----F--] supervisor 512 Jan 16 18:53 login\r\n
|
||||
- [R----F--] rhesus 214059 Oct 20 15:27 cx.exe\r\n"
|
||||
|
||||
test_ftp_response_expect_success \
|
||||
'Response from NetPresenz for the Mac' \
|
||||
"
|
||||
-------r-- 326 1391972 1392298 Nov 22 1995 MegaPhone.sit\r\n
|
||||
drwxrwxr-x folder 2 May 10 1996 network\r\n"
|
||||
|
||||
|
||||
#############################################################################
|
||||
#
|
||||
# EPLF response
|
||||
#
|
||||
|
||||
test_ftp_response_expect_success \
|
||||
'EPLF responses' \
|
||||
$'
|
||||
+i8388621.48594,m825718503,r,s280,\tdjb.html\r\n
|
||||
+i8388621.50690,m824255907,/,\t514\r\n
|
||||
+i8388621.48598,m824253270,r,s612,\t514.html\r\n'
|
||||
|
||||
#############################################################################
|
||||
#
|
||||
# Parser for VMS-style MultiNet (some spaces removed from examples)
|
||||
#
|
||||
|
||||
test_ftp_response_expect_success \
|
||||
'Basic VMS responses' \
|
||||
"
|
||||
00README.TXT;1 2 30-DEC-1996 17:44 [SYSTEM] (RWED,RWED,RE,RE)\r\n
|
||||
CORE.DIR;1 1 8-SEP-1996 16:09 [SYSTEM] (RWE,RWE,RE,RE)\r\n"
|
||||
|
||||
test_ftp_response_expect_success \
|
||||
'Response from non-MutliNet VMS' \
|
||||
"
|
||||
CII-MANUAL.TEX;1 213/216 29-JAN-1996 03:33:12 [ANONYMOU,ANONYMOUS] (RWED,RWED,,)\r\n"
|
||||
|
||||
test_ftp_response_expect_failure \
|
||||
'A garbage line which should fail' \
|
||||
"
|
||||
EA95_0PS.GZ;1 No privilege for attempted operation\r\n"
|
||||
|
||||
#############################################################################
|
||||
#
|
||||
# Parser for the MSDOS-style format
|
||||
#
|
||||
|
||||
test_ftp_response_expect_success \
|
||||
'Basic MSDOS-style format' \
|
||||
"
|
||||
04-27-00 09:09PM <DIR> licensed\r\n
|
||||
07-18-00 10:16AM <DIR> pub\r\n
|
||||
04-14-00 03:47PM 589 readme.htm\r\n"
|
||||
|
||||
|
||||
test_done
|
@ -20,7 +20,7 @@ static JSObject *
|
||||
smjs_get_bookmark_generic_object(struct bookmark *bookmark, JSClass *clasp)
|
||||
{
|
||||
JSObject *jsobj;
|
||||
|
||||
|
||||
jsobj = JS_NewObject(smjs_ctx, clasp, NULL, NULL);
|
||||
if (!jsobj) return NULL;
|
||||
|
||||
|
@ -138,7 +138,7 @@ cache_entry_finalize(JSContext *ctx, JSObject *obj)
|
||||
|
||||
object_unlock(cached);
|
||||
}
|
||||
|
||||
|
||||
static const JSClass cache_entry_class = {
|
||||
"cache_entry",
|
||||
JSCLASS_HAS_PRIVATE,
|
||||
@ -151,7 +151,7 @@ JSObject *
|
||||
smjs_get_cache_entry_object(struct cache_entry *cached)
|
||||
{
|
||||
JSObject *cache_entry_object;
|
||||
|
||||
|
||||
assert(smjs_ctx);
|
||||
|
||||
cache_entry_object = JS_NewObject(smjs_ctx,
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "scripting/smjs/elinks_object.h"
|
||||
#include "scripting/smjs/global_object.h"
|
||||
#include "scripting/smjs/smjs.h"
|
||||
#include "util/file.h"
|
||||
#include "util/string.h"
|
||||
|
||||
|
||||
@ -116,7 +117,8 @@ smjs_load_hooks(void)
|
||||
path = stracpy(CONFDIR "/" SMJS_HOOKS_FILENAME);
|
||||
}
|
||||
|
||||
smjs_do_file(path);
|
||||
if (file_exists(path))
|
||||
smjs_do_file(path);
|
||||
mem_free(path);
|
||||
}
|
||||
|
||||
|
@ -90,7 +90,7 @@ keymap_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
|
||||
int event_id;
|
||||
struct string event_name = NULL_STRING;
|
||||
JSObject *jsobj = JSVAL_TO_OBJECT(*vp);
|
||||
|
||||
|
||||
if (JS_FALSE == JS_ObjectIsFunction(ctx, jsobj))
|
||||
return JS_FALSE;
|
||||
|
||||
@ -148,7 +148,7 @@ smjs_get_keymap_object(enum keymap_id keymap_id)
|
||||
{
|
||||
int *data;
|
||||
JSObject *keymap_object;
|
||||
|
||||
|
||||
assert(smjs_ctx);
|
||||
|
||||
keymap_object = JS_NewObject(smjs_ctx, (JSClass *) &keymap_class,
|
||||
@ -181,7 +181,7 @@ smjs_get_keymap_hash_object(void)
|
||||
jsval val;
|
||||
enum keymap_id keymap_id;
|
||||
JSObject *keymaps_hash;
|
||||
|
||||
|
||||
keymaps_hash = JS_NewObject(smjs_ctx, (JSClass *) &keymaps_hash_class,
|
||||
NULL, NULL);
|
||||
if (!keymaps_hash) return NULL;
|
||||
|
@ -573,6 +573,9 @@ create_download_file_do(struct terminal *term, unsigned char *file, void *data,
|
||||
wd = get_cwd();
|
||||
set_cwd(term->cwd);
|
||||
|
||||
/* Create parent directories if needed. */
|
||||
mkalldirs(file);
|
||||
|
||||
/* O_APPEND means repositioning at the end of file before each write(),
|
||||
* thus ignoring seek()s and that can hide mysterious bugs. IMHO.
|
||||
* --pasky */
|
||||
|
@ -205,7 +205,7 @@ update_screen_driver(struct screen_driver *driver, struct option *term_spec)
|
||||
}
|
||||
|
||||
if (utf8_io) {
|
||||
driver->charsets[0] = get_opt_int_tree(term_spec, "charset");
|
||||
driver->charsets[0] = get_opt_codepage_tree(term_spec, "charset");
|
||||
if (driver->type == TERM_LINUX) {
|
||||
if (get_opt_bool_tree(term_spec, "restrict_852"))
|
||||
driver->frame = frame_restrict;
|
||||
|
@ -5,6 +5,7 @@
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -46,7 +47,7 @@
|
||||
#include "util/file.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/string.h"
|
||||
#include "protocol/uri.h"
|
||||
|
||||
|
||||
/* Not that these two would be so useful for portability (they are ANSI C) but
|
||||
* they encapsulate the lowlevel stuff (need for <unistd.h>) nicely. */
|
||||
@ -54,29 +55,12 @@
|
||||
int
|
||||
file_exists(const unsigned char *filename)
|
||||
{
|
||||
int result;
|
||||
unsigned char *decoded_filename;
|
||||
#ifdef HAVE_ACCESS
|
||||
|
||||
result = access(filename, F_OK);
|
||||
if (result >= 0) return 1;
|
||||
decoded_filename = stracpy((unsigned char *)filename);
|
||||
if (!decoded_filename) return 0;
|
||||
decode_uri(decoded_filename);
|
||||
result = access(decoded_filename, F_OK);
|
||||
mem_free(decoded_filename);
|
||||
return result >= 0;
|
||||
return access(filename, F_OK) >= 0;
|
||||
#else
|
||||
struct stat buf;
|
||||
|
||||
result = stat(filename, &buf);
|
||||
if (result >= 0) return 1;
|
||||
decoded_filename = stracpy((unsigned char *)filename);
|
||||
if (!decoded_filename) return 0;
|
||||
decode_uri(decoded_filename);
|
||||
result = stat(decoded_filename, &buf);
|
||||
mem_free(decoded_filename);
|
||||
return result >= 0;
|
||||
return stat(filename, &buf) >= 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -597,3 +581,40 @@ get_directory_entries(unsigned char *dirname, int get_hidden)
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
/* Recursively create directories in a path. The last element in the path is
|
||||
* taken to be a filename, and simply ignored */
|
||||
int
|
||||
mkalldirs(const unsigned char *path)
|
||||
{
|
||||
int pos, len, ret = 0;
|
||||
unsigned char *p;
|
||||
|
||||
if (!*path) return -1;
|
||||
|
||||
/* Make a copy of path, to be able to write to it. Otherwise, the
|
||||
* function is unsafe if called with a read-only char *argument. */
|
||||
len = strlen(path) + 1;
|
||||
p = fmem_alloc(len);
|
||||
if (!p) return -1;
|
||||
memcpy(p, path, len);
|
||||
|
||||
for (pos = 1; p[pos]; pos++) {
|
||||
unsigned char separator = p[pos];
|
||||
|
||||
if (!dir_sep(separator))
|
||||
continue;
|
||||
|
||||
p[pos] = 0;
|
||||
|
||||
ret = mkdir(p, S_IREAD | S_IWRITE | S_IEXEC);
|
||||
|
||||
p[pos] = separator;
|
||||
|
||||
if (ret < 0 && errno != EEXIST)
|
||||
break;
|
||||
}
|
||||
|
||||
fmem_free(p);
|
||||
return ret;
|
||||
}
|
||||
|
@ -51,4 +51,8 @@ unsigned char *file_read_line(unsigned char *line, size_t *linesize,
|
||||
* restore previous umask(). */
|
||||
int safe_mkstemp(unsigned char *template);
|
||||
|
||||
/* Recursively create directories in a path. The last element in the path is
|
||||
* taken to be a filename, and simply ignored */
|
||||
int mkalldirs(const unsigned char *path);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user