1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-12-04 14:46:47 -05:00
This commit is contained in:
Kalle Olavi Niemitalo 2006-01-06 02:13:11 +02:00 committed by Kalle Olavi Niemitalo
commit 93714a3e35
76 changed files with 3142 additions and 2559 deletions

View File

@ -48,6 +48,9 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
INSTALL_DATA = @INSTALL_DATA@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
TEST_LIB=$(top_srcdir)/test/libtest.sh
export TEST_LIB
host = @host@
ASCIIDOC = @ASCIIDOC@

View File

@ -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

File diff suppressed because it is too large Load Diff

1060
Unicode/entities.txt Normal file

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -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.
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

View File

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

View File

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

View File

@ -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.
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

View File

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

View File

@ -5,8 +5,6 @@ Welcome, mere mortal, to the realm of evil unindented code, heaps of one or
two-letter variables, seas of gotos accompanied with 30-letters labels in Czech
language with absolutely no meaning, welcome to the realm of ELinks code!
[We're going to extend this file slowly, basing on daily practice ;]
Don't take this file as a law. We may or may not be right in these issues.
Motto: I didn't expect someone to look at the source, so it's unreadable.
@ -681,6 +679,3 @@ to compile or execute in one of these modes, then rework it.
Happy hacking!
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

View File

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

View File

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

View File

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

View File

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

View File

@ -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),

View File

@ -258,6 +258,10 @@ Follow the current link, forcing reload of the target\&.
link\-menu
Open the link context menu\&.
.TP
link\-form\-menu
Open the form fields menu\&.
.TP
lua\-console
Open a Lua console\&.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -27,6 +27,7 @@ END_OF_USAGE
# Option handling {{{1
command=
filter=cat
prev_option=
for option
@ -41,10 +42,12 @@ do
case "$option" in
--cmdoptions)
command="$elinks -long-help"
filter="sed 0,/^Options:/d"
backend="cmdoptions"
;;
--elinksconf)
command="$elinks -config-help"
filter="sed 0,/^Configuration/d"
backend="elinksconf"
;;
-)
@ -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/'`"

View File

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

View File

@ -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 \

View File

@ -1,13 +1,13 @@
# French ELinks translation.
# Fabrice Haberer-Proust <fric@gmx.li>
# Laurent Monin <zas@norz.org>, 2001 - 2005
# Laurent Monin <zas@norz.org>, 2001 - 2006
#
msgid ""
msgstr ""
"Project-Id-Version: ELinks 0.11.GIT\n"
"Project-Id-Version: ELinks 0.12.GIT\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2006-01-01 17:49+0100\n"
"PO-Revision-Date: 2006-01-01 17:50+0100\n"
"POT-Creation-Date: 2006-01-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"

View File

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

View File

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

View File

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

View File

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

View File

@ -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. */

View File

@ -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 "

View File

@ -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;

View File

@ -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))

View File

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

View File

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

View File

@ -154,7 +154,8 @@ init_dom_scanner_info(struct dom_scanner_info *scanner_info)
void
init_dom_scanner(struct dom_scanner *scanner, struct dom_scanner_info *scanner_info,
struct dom_string *string, int state, int count_lines)
struct dom_string *string, int state, int count_lines, int complete,
int check_complete)
{
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);
}

View File

@ -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;

View File

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

View File

@ -154,7 +154,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;

View File

@ -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

View File

@ -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);
}
}

View File

@ -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,

View File

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

View File

@ -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

View File

@ -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))'

View File

@ -16,6 +16,24 @@
#include "dom/stack.h"
unsigned int number_of_lines = 0;
static int
update_number_of_lines(struct dom_stack *stack)
{
struct sgml_parser *parser = stack->contexts[0]->data;
int lines;
if (!(parser->flags & SGML_PARSER_COUNT_LINES))
return 0;
lines = get_sgml_parser_line_number(parser);
if (number_of_lines < lines)
number_of_lines = lines;
return 1;
}
/* Print the string in a compressed form: a single line with newlines etc.
* replaced with "\\n" sequence. */
static void
@ -72,14 +90,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;
}

View File

@ -9,12 +9,12 @@ This test runs very basic features, like checking that nodes are placed
correctly in the DOM tree.
'
. ./libtest
. "$TEST_LIB"
test_output_equals () {
desc="$1"
src="$2"
out="$3"
desc="$1"; shift
src="$1"; shift
out="$1"; shift
URI="test:$(echo "$desc" | sed '
s/^[ \t]*\[[^]]*\][ \t]*//;
@ -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)' \
'&#123456789'
test_expect_incomplete \
'Check incomplete reference. (II)' \
'&amp'
test_expect_incomplete \
'Check incomplete text.' \
'plain text is always incomplete (if incomplete)'
test_done

File diff suppressed because it is too large Load Diff

View File

@ -267,7 +267,7 @@ get_address(struct socket_info *info, enum addr_type type)
info->addr = (struct sockaddr *) sin;
info->size = sizeof(*sin);
return AF_INET;
return PF_INET;
}
static int
@ -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;

View File

@ -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;

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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: */

View File

@ -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);

View File

@ -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");

View File

@ -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;
}

View File

@ -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)

View File

@ -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;

View File

@ -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. */

View File

@ -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

View 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;
}

View File

@ -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;

View File

@ -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)

View File

@ -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

View 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

View File

@ -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;

View File

@ -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,

View File

@ -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);
}

View File

@ -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;

View File

@ -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 */

View File

@ -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;

View File

@ -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;
}

View File

@ -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