mirror of
https://github.com/rkd77/elinks.git
synced 2024-12-04 14:46:47 -05:00
Merge with git+ssh://pasky.or.cz/srv/git/elinks.git
This commit is contained in:
commit
41e8570e64
@ -1,5 +1,9 @@
|
||||
/* DOM Configuration */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "elinks.h"
|
||||
|
||||
#include "dom/configuration.h"
|
||||
|
@ -190,7 +190,8 @@ dom_node_list_bsearch(struct dom_node_search *search, struct dom_node_list *list
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int get_dom_node_map_index(struct dom_node_list *list, struct dom_node *node)
|
||||
int
|
||||
get_dom_node_map_index(struct dom_node_list *list, struct dom_node *node)
|
||||
{
|
||||
struct dom_node_search search = INIT_DOM_NODE_SEARCH(node, list);
|
||||
struct dom_node *match = dom_node_list_bsearch(&search, list);
|
||||
@ -267,6 +268,24 @@ get_dom_node_prev(struct dom_node *node)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct dom_node *
|
||||
get_dom_node_next(struct dom_node *node)
|
||||
{
|
||||
struct dom_node_list **list;
|
||||
int index;
|
||||
|
||||
assert(node->parent);
|
||||
|
||||
list = get_dom_node_list(node->parent, node);
|
||||
if (!list) return NULL;
|
||||
|
||||
index = get_dom_node_list_pos(*list, node);
|
||||
if (index + 1 < (*list)->size)
|
||||
return (*list)->entries[index + 1];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct dom_node *
|
||||
get_dom_node_child(struct dom_node *parent, enum dom_node_type type,
|
||||
int16_t subtype)
|
||||
@ -327,6 +346,23 @@ init_dom_node_(unsigned char *file, int line,
|
||||
node->type = type;
|
||||
node->parent = parent;
|
||||
|
||||
/* Make it possible to add a node to a parent without allocating the
|
||||
* strings. */
|
||||
if (allocated >= 0) {
|
||||
node->allocated = !!allocated;
|
||||
} else if (parent) {
|
||||
node->allocated = parent->allocated;
|
||||
}
|
||||
|
||||
if (node->allocated) {
|
||||
if (!init_dom_string(&node->string, string->string, string->length)) {
|
||||
done_dom_node(node);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
copy_dom_string(&node->string, string);
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
struct dom_node_list **list = get_dom_node_list(parent, node);
|
||||
int sort = (type == DOM_NODE_ATTRIBUTE);
|
||||
@ -342,22 +378,6 @@ init_dom_node_(unsigned char *file, int line,
|
||||
done_dom_node(node);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Make it possible to add a node to a parent without
|
||||
* allocating the strings. */
|
||||
node->allocated = allocated < 0 ? parent->allocated : !!allocated;
|
||||
|
||||
} else if (allocated >= 0) {
|
||||
node->allocated = !!allocated;
|
||||
}
|
||||
|
||||
if (node->allocated) {
|
||||
if (!init_dom_string(&node->string, string->string, string->length)) {
|
||||
done_dom_node(node);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
copy_dom_string(&node->string, string);
|
||||
}
|
||||
|
||||
return node;
|
||||
|
@ -111,6 +111,9 @@ struct dom_attribute_node {
|
||||
* to reduce string comparing and only do one fast find mapping. */
|
||||
uint16_t type;
|
||||
|
||||
/* The attribute value is delimited by quotes. Can be NUL, ' or ". */
|
||||
unsigned char quoted;
|
||||
|
||||
/* Was the attribute specified in the DTD as a default attribute or was
|
||||
* it added from the document source. */
|
||||
unsigned int specified:1;
|
||||
@ -124,9 +127,6 @@ struct dom_attribute_node {
|
||||
|
||||
/* The attribute value references some other resource */
|
||||
unsigned int reference:1;
|
||||
|
||||
/* The attribute value is delimited by quotes */
|
||||
unsigned int quoted:1;
|
||||
};
|
||||
|
||||
struct dom_text_node {
|
||||
@ -242,6 +242,9 @@ int get_dom_node_map_index(struct dom_node_list *list, struct dom_node *node);
|
||||
/* Returns the previous sibling to the node. */
|
||||
struct dom_node *get_dom_node_prev(struct dom_node *node);
|
||||
|
||||
/* Returns the next sibling to the node. */
|
||||
struct dom_node *get_dom_node_next(struct dom_node *node);
|
||||
|
||||
/* Returns first text node of the element or NULL. */
|
||||
struct dom_node *
|
||||
get_dom_node_child(struct dom_node *node, enum dom_node_type child_type,
|
||||
|
@ -2,6 +2,6 @@ top_builddir=../../..
|
||||
include $(top_builddir)/Makefile.config
|
||||
|
||||
SUBDIRS = docbook html rss xbel
|
||||
OBJS = sgml.o parser.o scanner.o
|
||||
OBJS = dump.o parser.o scanner.o sgml.o
|
||||
|
||||
include $(top_srcdir)/Makefile.lib
|
||||
|
170
src/dom/sgml/dump.c
Normal file
170
src/dom/sgml/dump.c
Normal file
@ -0,0 +1,170 @@
|
||||
/* SGML generics */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "elinks.h"
|
||||
|
||||
#include "dom/node.h"
|
||||
#include "dom/sgml/dump.h"
|
||||
#include "dom/stack.h"
|
||||
#include "dom/string.h"
|
||||
|
||||
|
||||
static enum dom_stack_code
|
||||
sgml_file_dumper_element_push(struct dom_stack *stack, struct dom_node *node, void *data)
|
||||
{
|
||||
FILE *file = stack->current->data;
|
||||
struct dom_string *string = &node->string;
|
||||
|
||||
fprintf(file, "<%.*s", string->length, string->string);
|
||||
if (!node->data.element.map
|
||||
|| node->data.element.map->size == 0)
|
||||
fprintf(file, ">");
|
||||
|
||||
return DOM_STACK_CODE_OK;
|
||||
}
|
||||
|
||||
static enum dom_stack_code
|
||||
sgml_file_dumper_element_pop(struct dom_stack *stack, struct dom_node *node, void *data)
|
||||
{
|
||||
FILE *file = stack->current->data;
|
||||
struct dom_string *string = &node->string;
|
||||
|
||||
fprintf(file, "</%.*s>", string->length, string->string);
|
||||
|
||||
return DOM_STACK_CODE_OK;
|
||||
}
|
||||
|
||||
static enum dom_stack_code
|
||||
sgml_file_dumper_attribute_push(struct dom_stack *stack, struct dom_node *node, void *data)
|
||||
{
|
||||
FILE *file = stack->current->data;
|
||||
struct dom_string *name = &node->string;
|
||||
struct dom_string *value = &node->data.attribute.value;
|
||||
|
||||
if (node->parent->type == DOM_NODE_PROCESSING_INSTRUCTION)
|
||||
return DOM_STACK_CODE_OK;
|
||||
|
||||
fprintf(file, " %.*s", name->length, name->string);
|
||||
|
||||
if (value->string) {
|
||||
if (node->data.attribute.quoted)
|
||||
fprintf(file, "=%c%.*s%c",
|
||||
node->data.attribute.quoted,
|
||||
value->length, value->string,
|
||||
node->data.attribute.quoted);
|
||||
else
|
||||
/* FIXME: 'encode' if the value contains '"'s? */
|
||||
fprintf(file, "=\"%.*s\"", value->length, value->string);
|
||||
}
|
||||
|
||||
if (!get_dom_node_next(node))
|
||||
fprintf(file, ">");
|
||||
|
||||
return DOM_STACK_CODE_OK;
|
||||
}
|
||||
|
||||
static enum dom_stack_code
|
||||
sgml_file_dumper_proc_instruction_push(struct dom_stack *stack, struct dom_node *node, void *data)
|
||||
{
|
||||
FILE *file = stack->current->data;
|
||||
struct dom_string *target = &node->string;
|
||||
struct dom_string *instruction = &node->data.proc_instruction.instruction;
|
||||
|
||||
fprintf(file, "<?%.*s %.*s?>",
|
||||
target->length, target->string,
|
||||
instruction->length, instruction->string);
|
||||
|
||||
return DOM_STACK_CODE_OK;
|
||||
}
|
||||
|
||||
static enum dom_stack_code
|
||||
sgml_file_dumper_text_push(struct dom_stack *stack, struct dom_node *node, void *data)
|
||||
{
|
||||
FILE *file = stack->current->data;
|
||||
struct dom_string *string = &node->string;
|
||||
|
||||
fprintf(file, "%.*s", string->length, string->string);
|
||||
|
||||
return DOM_STACK_CODE_OK;
|
||||
}
|
||||
|
||||
static enum dom_stack_code
|
||||
sgml_file_dumper_cdata_section_push(struct dom_stack *stack, struct dom_node *node, void *data)
|
||||
{
|
||||
FILE *file = stack->current->data;
|
||||
struct dom_string *string = &node->string;
|
||||
|
||||
fprintf(file, "<![CDATA[%.*s]]>", string->length, string->string);
|
||||
|
||||
return DOM_STACK_CODE_OK;
|
||||
}
|
||||
|
||||
static enum dom_stack_code
|
||||
sgml_file_dumper_comment_push(struct dom_stack *stack, struct dom_node *node, void *data)
|
||||
{
|
||||
FILE *file = stack->current->data;
|
||||
struct dom_string *string = &node->string;
|
||||
|
||||
fprintf(file, "<!--%.*s-->", string->length, string->string);
|
||||
|
||||
return DOM_STACK_CODE_OK;
|
||||
}
|
||||
|
||||
static enum dom_stack_code
|
||||
sgml_file_dumper_entity_ref_push(struct dom_stack *stack, struct dom_node *node, void *data)
|
||||
{
|
||||
FILE *file = stack->current->data;
|
||||
struct dom_string *string = &node->string;
|
||||
|
||||
fprintf(file, "&%.*s;", string->length, string->string);
|
||||
|
||||
return DOM_STACK_CODE_OK;
|
||||
}
|
||||
|
||||
struct dom_stack_context_info sgml_file_dumper = {
|
||||
/* Object size: */ 0,
|
||||
/* Push: */
|
||||
{
|
||||
/* */ NULL,
|
||||
/* DOM_NODE_ELEMENT */ sgml_file_dumper_element_push,
|
||||
/* DOM_NODE_ATTRIBUTE */ sgml_file_dumper_attribute_push,
|
||||
/* DOM_NODE_TEXT */ sgml_file_dumper_text_push,
|
||||
/* DOM_NODE_CDATA_SECTION */ sgml_file_dumper_cdata_section_push,
|
||||
/* DOM_NODE_ENTITY_REFERENCE */ sgml_file_dumper_entity_ref_push,
|
||||
/* DOM_NODE_ENTITY */ NULL,
|
||||
/* DOM_NODE_PROC_INSTRUCTION */ sgml_file_dumper_proc_instruction_push,
|
||||
/* DOM_NODE_COMMENT */ sgml_file_dumper_comment_push,
|
||||
/* DOM_NODE_DOCUMENT */ NULL,
|
||||
/* DOM_NODE_DOCUMENT_TYPE */ NULL,
|
||||
/* DOM_NODE_DOCUMENT_FRAGMENT */ NULL,
|
||||
/* DOM_NODE_NOTATION */ NULL,
|
||||
},
|
||||
/* Pop: */
|
||||
{
|
||||
/* */ NULL,
|
||||
/* DOM_NODE_ELEMENT */ sgml_file_dumper_element_pop,
|
||||
/* DOM_NODE_ATTRIBUTE */ NULL,
|
||||
/* DOM_NODE_TEXT */ NULL,
|
||||
/* DOM_NODE_CDATA_SECTION */ NULL,
|
||||
/* DOM_NODE_ENTITY_REFERENCE */ NULL,
|
||||
/* DOM_NODE_ENTITY */ NULL,
|
||||
/* DOM_NODE_PROC_INSTRUCTION */ NULL,
|
||||
/* DOM_NODE_COMMENT */ NULL,
|
||||
/* DOM_NODE_DOCUMENT */ NULL,
|
||||
/* DOM_NODE_DOCUMENT_TYPE */ NULL,
|
||||
/* DOM_NODE_DOCUMENT_FRAGMENT */ NULL,
|
||||
/* DOM_NODE_NOTATION */ NULL,
|
||||
}
|
||||
};
|
||||
|
||||
struct dom_stack_context *
|
||||
add_sgml_file_dumper(struct dom_stack *stack, FILE *file)
|
||||
{
|
||||
return add_dom_stack_context(stack, file, &sgml_file_dumper);
|
||||
}
|
12
src/dom/sgml/dump.h
Normal file
12
src/dom/sgml/dump.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef EL_DOM_SGML_DUMP_H
|
||||
#define EL_DOM_SGML_DUMP_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
struct dom_stack;
|
||||
struct dom_stack_context;
|
||||
|
||||
struct dom_stack_context *
|
||||
add_sgml_file_dumper(struct dom_stack *stack, FILE *file);
|
||||
|
||||
#endif
|
@ -95,7 +95,7 @@ add_sgml_attribute(struct dom_stack *stack,
|
||||
node->data.attribute.reference = !!(info->flags & SGML_ATTRIBUTE_REFERENCE);
|
||||
|
||||
if (valtoken && valtoken->type == SGML_TOKEN_STRING)
|
||||
node->data.attribute.quoted = 1;
|
||||
node->data.attribute.quoted = valtoken->string.string[-1];
|
||||
|
||||
if (!node || push_dom_node(stack, node) != DOM_STACK_CODE_OK)
|
||||
return NULL;
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include "dom/configuration.h"
|
||||
#include "dom/node.h"
|
||||
#include "dom/sgml/dump.h"
|
||||
#include "dom/sgml/parser.h"
|
||||
#include "dom/stack.h"
|
||||
|
||||
@ -265,6 +266,7 @@ main(int argc, char *argv[])
|
||||
enum sgml_parser_code code = 0;
|
||||
enum dom_config_flag normalize_flags = 0;
|
||||
int normalize = 0;
|
||||
int dump = 0;
|
||||
int complete = 1;
|
||||
size_t read_stdin = 0;
|
||||
struct dom_string uri = STATIC_DOM_STRING("dom://test");
|
||||
@ -338,6 +340,10 @@ main(int argc, char *argv[])
|
||||
flags |= SGML_PARSER_INCREMENTAL;
|
||||
complete = 0;
|
||||
|
||||
} else if (!strcmp(arg, "dump")) {
|
||||
type = SGML_PARSER_TREE;
|
||||
dump = 1;
|
||||
|
||||
} else if (!strcmp(arg, "error")) {
|
||||
flags |= SGML_PARSER_DETECT_ERRORS;
|
||||
|
||||
@ -355,7 +361,7 @@ main(int argc, char *argv[])
|
||||
parser->error_func = sgml_error_function;
|
||||
if (normalize)
|
||||
add_dom_config_normalizer(&parser->stack, normalize_flags);
|
||||
else
|
||||
else if (!dump)
|
||||
add_dom_stack_context(&parser->stack, NULL, &sgml_parser_test_context_info);
|
||||
|
||||
if (read_stdin > 0) {
|
||||
@ -402,7 +408,7 @@ main(int argc, char *argv[])
|
||||
pop_dom_node(&parser->stack);
|
||||
}
|
||||
|
||||
if (normalize) {
|
||||
if (normalize || dump) {
|
||||
struct dom_stack stack;
|
||||
|
||||
/* Note, that we cannot free nodes when walking the DOM
|
||||
@ -412,7 +418,10 @@ main(int argc, char *argv[])
|
||||
/* XXX: This context needs to be added first because it
|
||||
* assumes the parser can be accessed via
|
||||
* stack->contexts[0].data. */
|
||||
add_dom_stack_context(&stack, parser, &sgml_parser_test_context_info);
|
||||
if (normalize)
|
||||
add_dom_stack_context(&stack, parser, &sgml_parser_test_context_info);
|
||||
else if (dump)
|
||||
add_sgml_file_dumper(&stack, stdout);
|
||||
walk_dom_nodes(&stack, parser->root);
|
||||
done_dom_stack(&stack);
|
||||
done_dom_node(parser->root);
|
||||
|
173
src/dom/test/test-sgml-dump-basic
Executable file
173
src/dom/test/test-sgml-dump-basic
Executable file
@ -0,0 +1,173 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2005 Jonas Fonseca
|
||||
#
|
||||
|
||||
test_description='Test dumping of SGML documents.
|
||||
|
||||
Test that DOM documents are consistently dumped to SGML.
|
||||
Note, this also test whether attribute nodes are sorted
|
||||
correctly.
|
||||
'
|
||||
|
||||
. "$TEST_LIB"
|
||||
|
||||
test_sgml_dump_exact () {
|
||||
desc="$1"; shift
|
||||
src="$1"; shift
|
||||
|
||||
sgml-parser --dump --src "$src" > output
|
||||
echo -n "$src" > expected
|
||||
|
||||
test_expect_success "$desc" 'cmp output expected'
|
||||
}
|
||||
|
||||
test_sgml_dump_equals () {
|
||||
desc="$1"; shift
|
||||
src="$1"; shift
|
||||
out="$1"; shift
|
||||
|
||||
sgml-parser --dump --src "$src" > output
|
||||
echo -n "$out" > expected
|
||||
|
||||
test_expect_success "$desc" 'cmp output expected'
|
||||
}
|
||||
|
||||
|
||||
################################################################
|
||||
# Parse various SGML node types.
|
||||
|
||||
test_sgml_dump_exact \
|
||||
'Parse a small document.' \
|
||||
'<html><body><p>Hello World!</p></body></html>'
|
||||
|
||||
test_sgml_dump_exact \
|
||||
'Parse an enclosed comment.' \
|
||||
'<root><!-- Hello World! --></root>'
|
||||
|
||||
test_sgml_dump_exact \
|
||||
'Parse comment combinations. (I)' \
|
||||
'<root><!-- <!-- -- > --><!--foo--><!----></root>'
|
||||
|
||||
test_sgml_dump_exact \
|
||||
'Parse comment combinations. (II).' \
|
||||
'<!-- comment -->s<!-->-->t<!----->u'
|
||||
|
||||
test_sgml_dump_exact \
|
||||
'Parse empty comment.' \
|
||||
'<!---->s'
|
||||
|
||||
test_sgml_dump_exact \
|
||||
'Parse an enclosed CDATA section.' \
|
||||
'<root><![CDATA[...] ]>...]]></root>'
|
||||
|
||||
test_sgml_dump_exact \
|
||||
'Parse non-enclosed CDATA section.' \
|
||||
'<![CDATA[...]]>'
|
||||
|
||||
test_sgml_dump_exact \
|
||||
'Parse attributes.' \
|
||||
'<e a="1" b="2" c=""></e>'
|
||||
|
||||
test_sgml_dump_exact \
|
||||
'Parse XML stylesheet processing instructions.' \
|
||||
'<?xml-stylesheet type="text/xsl" href="url"?>'
|
||||
|
||||
test_sgml_dump_exact \
|
||||
'Parse entity references.' \
|
||||
'&-*'
|
||||
|
||||
#############################################################################
|
||||
# Test tidy up dumping
|
||||
|
||||
test_sgml_dump_equals \
|
||||
'Parse elements.' \
|
||||
'<root><child attr="value" /><child2></><child3 >a</></root>' \
|
||||
'<root><child attr="value"></child><child2></child2><child3>a</child3></root>'
|
||||
|
||||
test_sgml_dump_equals \
|
||||
'Parse attributes with garbage.' \
|
||||
"<root a=b c='d' e'f' g= h i = j k =></root>" \
|
||||
"<root a=\"b\" c='d' g=\"h\" i=\"j\" k></root>"
|
||||
|
||||
test_sgml_dump_equals \
|
||||
'Parse bad comment. (II)' \
|
||||
'<!--a--!>bad comment' \
|
||||
'<!--a-->bad comment'
|
||||
|
||||
test_sgml_dump_equals \
|
||||
'Parse empty notation.' \
|
||||
'<!>s' \
|
||||
's'
|
||||
|
||||
test_sgml_dump_equals \
|
||||
'Parse a bad CDATA section.' \
|
||||
'<![CDATA[...' \
|
||||
'<![CDATA[...]]>'
|
||||
|
||||
test_sgml_dump_equals \
|
||||
'Parse tag soup elements. (I)' \
|
||||
'<parent attr="value" <child:1></><child:2</>a</parent>' \
|
||||
'<parent attr="value"><child:1></child:1><child:2></child:2>a</parent>'
|
||||
|
||||
test_sgml_dump_equals \
|
||||
'Parse tag soup elements. (II)' \
|
||||
'< a >< b < c / >< / >' \
|
||||
'<a><b><c></c></b></a>'
|
||||
|
||||
test_sgml_dump_equals \
|
||||
'Parse attribute with non-quoted values.' \
|
||||
'<root color=#abc path=/to/%61-&\one";files/>...' \
|
||||
'<root color="#abc" path="/to/%61-&\one";files"></root>...'
|
||||
|
||||
# Just how these should be gracefully handled is not clear to me.
|
||||
test_sgml_dump_equals \
|
||||
'Parse badly formatted entity references.' \
|
||||
'& m33p;-&.:-copy;-&;-&#;-&#xx;' \
|
||||
'& m33p;-&.:-copy;-&;-&#;-&#xx;'
|
||||
|
||||
test_sgml_dump_equals \
|
||||
'Parse processing instructions.' \
|
||||
'<?xml encoding="UTF8"?>
|
||||
...
|
||||
<?ecmascript
|
||||
var val=2;
|
||||
?>' \
|
||||
'<?xml encoding="UTF8"?>
|
||||
...
|
||||
<?ecmascript var val=2;
|
||||
?>'
|
||||
|
||||
test_sgml_dump_equals \
|
||||
'Parse XML processing instructions.' \
|
||||
'<?xml version="1.0" />?><?xml />-' \
|
||||
'<?xml version="1.0" />?><?xml />-?>'
|
||||
|
||||
test_sgml_dump_equals \
|
||||
'Parse exotic processing instructions.' \
|
||||
'<?xml ?+>+?>-?>-<?js?>-<??>-' \
|
||||
'<?xml ?+>+?>-?>-<?js ?>-<? ?>-'
|
||||
|
||||
test_sgml_dump_equals \
|
||||
'Parse incorrect processing instructions. (I)' \
|
||||
'<?js<?>-<?<??>-<?xml <=";&?>-<?' \
|
||||
'<?js <?>-<? <??>-<?xml <=";&?>-' \
|
||||
|
||||
test_sgml_dump_equals \
|
||||
'Parse incorrect processing instructions. (II)' \
|
||||
'<?><?' \
|
||||
'<? ><??>'
|
||||
|
||||
test_sgml_dump_equals \
|
||||
'Skip spaces not inside text.' \
|
||||
'<
|
||||
root
|
||||
ns:attr
|
||||
=
|
||||
"value"
|
||||
><?
|
||||
target
|
||||
data?>< / root >' \
|
||||
'<root ns:attr="value"><?target data?></root>'
|
||||
|
||||
test_done
|
@ -225,7 +225,7 @@ proc-instruction: ->
|
||||
#text: -'
|
||||
|
||||
test_output_equals \
|
||||
'Parse incorrect processing instructions.' \
|
||||
'Parse incorrect processing instructions. (I)' \
|
||||
'<?js<?>-<?<??>-<?xml <=";&?>-<?' \
|
||||
'
|
||||
proc-instruction: js -> <
|
||||
|
@ -1,8 +1,6 @@
|
||||
top_builddir=../..
|
||||
include $(top_builddir)/Makefile.config
|
||||
|
||||
SUBDIRS = auth file http
|
||||
|
||||
SUBDIRS-$(CONFIG_BITTORRENT) += bittorrent
|
||||
SUBDIRS-$(CONFIG_FINGER) += finger
|
||||
SUBDIRS-$(CONFIG_FSP) += fsp
|
||||
@ -12,11 +10,10 @@ SUBDIRS-$(CONFIG_NNTP) += nntp
|
||||
SUBDIRS-$(CONFIG_SMB) += smb
|
||||
SUBDIRS-$(CONFIG_URI_REWRITE) += rewrite
|
||||
|
||||
OBJS = about.o date.o header.o protocol.o proxy.o uri.o user.o
|
||||
SUBDIRS = auth file http
|
||||
|
||||
OBJS-$(CONFIG_DATA) += data.o
|
||||
OBJS-$(CONFIG_CGI) += common.o
|
||||
OBJS-$(CONFIG_FSP) += common.o
|
||||
OBJS-$(CONFIG_SMB) += common.o
|
||||
|
||||
OBJS = about.o common.o date.o header.o protocol.o proxy.o uri.o user.o
|
||||
|
||||
include $(top_srcdir)/Makefile.lib
|
||||
|
@ -17,7 +17,13 @@
|
||||
|
||||
#include "elinks.h"
|
||||
|
||||
#include "config/options.h"
|
||||
#include "protocol/common.h"
|
||||
#include "protocol/protocol.h"
|
||||
#include "protocol/uri.h"
|
||||
#include "util/conv.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/string.h"
|
||||
|
||||
|
||||
/* Close all non-terminal file descriptors. */
|
||||
@ -35,3 +41,103 @@ close_all_non_term_fd(void)
|
||||
for (n = 3; n < max; n++)
|
||||
close(n);
|
||||
}
|
||||
|
||||
enum connection_state
|
||||
init_directory_listing(struct string *page, struct uri *uri)
|
||||
{
|
||||
struct string dirpath = NULL_STRING;
|
||||
struct string location = NULL_STRING;
|
||||
unsigned char *info;
|
||||
int local = (uri->protocol == PROTOCOL_FILE);
|
||||
|
||||
if (!init_string(page)
|
||||
|| !init_string(&dirpath)
|
||||
|| !init_string(&location)
|
||||
|| !add_uri_to_string(&dirpath, uri, URI_DATA)
|
||||
|| !add_uri_to_string(&location, uri, URI_DIR_LOCATION))
|
||||
goto out_of_memory;
|
||||
|
||||
if (dirpath.length > 0
|
||||
&& !dir_sep(dirpath.source[dirpath.length - 1])
|
||||
&& !add_char_to_string(&dirpath, '/'))
|
||||
goto out_of_memory;
|
||||
|
||||
if (uri->protocol == PROTOCOL_GOPHER) {
|
||||
/* A little hack to get readable Gopher names. We should find a
|
||||
* way to do it more general. */
|
||||
decode_uri_string(&dirpath);
|
||||
}
|
||||
|
||||
if (!local && !add_char_to_string(&location, '/'))
|
||||
goto out_of_memory;
|
||||
|
||||
if (!add_to_string(page, "<html>\n<head><title>"))
|
||||
goto out_of_memory;
|
||||
|
||||
if (!local && !add_string_to_string(page, &location))
|
||||
goto out_of_memory;
|
||||
|
||||
if (!add_html_to_string(page, dirpath.source, dirpath.length)
|
||||
|| !add_to_string(page, "</title>\n<base href=\"")
|
||||
|| !add_string_to_string(page, &location))
|
||||
goto out_of_memory;
|
||||
|
||||
encode_uri_string(page, dirpath.source, -1, 0);
|
||||
|
||||
if (!add_to_string(page, "\" />\n</head>\n<body>\n<h2>"))
|
||||
goto out_of_memory;
|
||||
|
||||
/* Use module names? */
|
||||
switch (uri->protocol) {
|
||||
case PROTOCOL_FILE:
|
||||
info = "Local";
|
||||
break;
|
||||
case PROTOCOL_FSP:
|
||||
info = "FSP";
|
||||
break;
|
||||
case PROTOCOL_FTP:
|
||||
info = "FTP";
|
||||
break;
|
||||
case PROTOCOL_GOPHER:
|
||||
info = "Gopher";
|
||||
break;
|
||||
default:
|
||||
info = "?";
|
||||
}
|
||||
|
||||
if (!add_to_string(page, info)
|
||||
|| !add_to_string(page, " directory "))
|
||||
goto out_of_memory;
|
||||
|
||||
if (!local && !add_string_to_string(page, &location))
|
||||
goto out_of_memory;
|
||||
|
||||
/* Make the directory path with links to each subdir. */
|
||||
{
|
||||
unsigned char *slash = dirpath.source;
|
||||
unsigned char *pslash = slash;
|
||||
|
||||
while ((slash = strchr(slash, '/'))) {
|
||||
/* FIXME: htmlesc? At least we should escape quotes. --pasky */
|
||||
if (!add_to_string(page, "<a href=\"")
|
||||
|| !add_string_to_string(page, &location)
|
||||
|| !add_bytes_to_string(page, dirpath.source, slash - dirpath.source)
|
||||
|| !add_to_string(page, "/\">")
|
||||
|| !add_html_to_string(page, pslash, slash - pslash)
|
||||
|| !add_to_string(page, "</a>/"))
|
||||
goto out_of_memory;
|
||||
|
||||
pslash = ++slash;
|
||||
}
|
||||
}
|
||||
|
||||
if (!add_to_string(page, "</h2>\n<pre>")) {
|
||||
out_of_memory:
|
||||
done_string(page);
|
||||
}
|
||||
|
||||
done_string(&dirpath);
|
||||
done_string(&location);
|
||||
|
||||
return page->length > 0 ? S_OK : S_OUT_OF_MEM;
|
||||
}
|
||||
|
@ -1,7 +1,15 @@
|
||||
#ifndef EL__PROTOCOL_COMMON_H
|
||||
#define EL__PROTOCOL_COMMON_H
|
||||
|
||||
#include "network/state.h"
|
||||
|
||||
struct string;
|
||||
struct uri;
|
||||
|
||||
/* Close all non-terminal file descriptors. */
|
||||
void close_all_non_term_fd(void);
|
||||
|
||||
enum connection_state
|
||||
init_directory_listing(struct string *page, struct uri *uri);
|
||||
|
||||
#endif
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "intl/gettext/libintl.h"
|
||||
#include "main/module.h"
|
||||
#include "network/connection.h"
|
||||
#include "protocol/common.h"
|
||||
#include "protocol/file/cgi.h"
|
||||
#include "protocol/file/file.h"
|
||||
#include "protocol/uri.h"
|
||||
@ -172,12 +173,12 @@ add_dir_entries(struct directory_entry *entries, unsigned char *dirpath,
|
||||
* @dirpath. */
|
||||
/* Returns a connection state. S_OK if all is well. */
|
||||
static inline enum connection_state
|
||||
list_directory(unsigned char *dirpath, struct string *page)
|
||||
list_directory(struct connection *conn, unsigned char *dirpath,
|
||||
struct string *page)
|
||||
{
|
||||
int show_hidden_files = get_opt_bool("protocol.file.show_hidden_files");
|
||||
unsigned char *slash = dirpath;
|
||||
unsigned char *pslash = ++slash;
|
||||
struct directory_entry *entries;
|
||||
enum connection_state state;
|
||||
|
||||
errno = 0;
|
||||
entries = get_directory_entries(dirpath, show_hidden_files);
|
||||
@ -186,30 +187,17 @@ list_directory(unsigned char *dirpath, struct string *page)
|
||||
return S_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
if (!init_string(page)) return S_OUT_OF_MEM;
|
||||
state = init_directory_listing(page, conn->uri);
|
||||
if (state != S_OK)
|
||||
return S_OUT_OF_MEM;
|
||||
|
||||
add_to_string(page, "<html>\n<head><title>");
|
||||
add_html_to_string(page, dirpath, strlen(dirpath));
|
||||
add_to_string(page, "</title>\n<base href=\"");
|
||||
encode_uri_string(page, dirpath, -1, 0);
|
||||
add_to_string(page, "\" />\n</head>\n<body>\n<h2>Directory /");
|
||||
add_dir_entries(entries, dirpath, page);
|
||||
|
||||
/* Make the directory path with links to each subdir. */
|
||||
while ((slash = strchr(slash, '/'))) {
|
||||
*slash = 0;
|
||||
add_to_string(page, "<a href=\"");
|
||||
/* FIXME: htmlesc? At least we should escape quotes. --pasky */
|
||||
add_to_string(page, dirpath);
|
||||
add_to_string(page, "/\">");
|
||||
add_html_to_string(page, pslash, strlen(pslash));
|
||||
add_to_string(page, "</a>/");
|
||||
*slash = '/';
|
||||
pslash = ++slash;
|
||||
if (!add_to_string(page, "</pre>\n<hr>\n</body>\n</html>\n")) {
|
||||
done_string(page);
|
||||
return S_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
add_to_string(page, "</h2>\n<pre>");
|
||||
add_dir_entries(entries, dirpath, page);
|
||||
add_to_string(page, "</pre>\n<hr>\n</body>\n</html>\n");
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@ -263,7 +251,7 @@ file_protocol_handler(struct connection *connection)
|
||||
redirect_location = "/";
|
||||
state = S_OK;
|
||||
} else {
|
||||
state = list_directory(name.source, &page);
|
||||
state = list_directory(connection, name.source, &page);
|
||||
type = "text/html";
|
||||
}
|
||||
|
||||
|
@ -131,21 +131,16 @@ fsp_directory(FSP_SESSION *ses, struct uri *uri)
|
||||
{
|
||||
struct string buf;
|
||||
FSP_DIR *dir;
|
||||
unsigned char *uristring = get_uri_string(uri, URI_PUBLIC);
|
||||
unsigned char *data = get_uri_string(uri, URI_DATA);
|
||||
unsigned char dircolor[8] = "";
|
||||
|
||||
if (!uristring || !data || !init_string(&buf))
|
||||
if (!data || init_directory_listing(&buf, uri) != S_OK)
|
||||
fsp_error("Out of memory");
|
||||
|
||||
fprintf(stderr, "text/html");
|
||||
fclose(stderr);
|
||||
add_html_to_string(&buf, uristring, strlen(uristring));
|
||||
|
||||
printf("<html><head><title>%s</title><base href=\"%s", buf.source,
|
||||
uristring);
|
||||
if (buf.source[buf.length - 1] != '/') printf("/");
|
||||
printf("\"></head><body><h2>FSP directory %s</h2><pre>", buf.source);
|
||||
puts(buf.source);
|
||||
|
||||
dir = fsp_opendir(ses, data);
|
||||
if (!dir) goto end;
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "osdep/osdep.h"
|
||||
#include "osdep/stat.h"
|
||||
#include "protocol/auth/auth.h"
|
||||
#include "protocol/common.h"
|
||||
#include "protocol/ftp/ftp.h"
|
||||
#include "protocol/ftp/parse.h"
|
||||
#include "protocol/uri.h"
|
||||
@ -1253,37 +1254,21 @@ out_of_mem:
|
||||
|
||||
if (ftp->dir && !conn->from) {
|
||||
struct string string;
|
||||
unsigned char *uristring;
|
||||
enum connection_state state;
|
||||
|
||||
if (!conn->uri->data) {
|
||||
abort_connection(conn, S_FTP_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
uristring = get_uri_string(conn->uri, URI_PUBLIC);
|
||||
if (!uristring) goto out_of_mem;
|
||||
|
||||
if (!init_string(&string)) {
|
||||
mem_free(uristring);
|
||||
goto out_of_mem;
|
||||
state = init_directory_listing(&string, conn->uri);
|
||||
if (state != S_OK) {
|
||||
abort_connection(conn, state);
|
||||
return;
|
||||
}
|
||||
|
||||
add_html_to_string(&string, uristring, strlen(uristring));
|
||||
mem_free(uristring);
|
||||
|
||||
#define ADD_CONST(str) { \
|
||||
add_fragment(conn->cached, conn->from, str, sizeof(str) - 1); \
|
||||
conn->from += (sizeof(str) - 1); }
|
||||
|
||||
#define ADD_STRING() { \
|
||||
add_fragment(conn->cached, conn->from, string.source, string.length); \
|
||||
conn->from += string.length; }
|
||||
|
||||
ADD_CONST("<html>\n<head><title>");
|
||||
ADD_STRING();
|
||||
ADD_CONST("</title></head>\n<body>\n<h2>FTP directory ");
|
||||
ADD_STRING();
|
||||
ADD_CONST("</h2>\n<pre>");
|
||||
add_fragment(conn->cached, conn->from, string.source, string.length);
|
||||
conn->from += string.length;
|
||||
|
||||
done_string(&string);
|
||||
|
||||
@ -1343,6 +1328,10 @@ out_of_mem:
|
||||
(unsigned char *) dircolor) == -1)
|
||||
goto out_of_mem;
|
||||
|
||||
#define ADD_CONST(str) { \
|
||||
add_fragment(conn->cached, conn->from, str, sizeof(str) - 1); \
|
||||
conn->from += (sizeof(str) - 1); }
|
||||
|
||||
if (ftp->dir) ADD_CONST("</pre>\n<hr>\n</body>\n</html>");
|
||||
|
||||
close_socket(conn->data_socket);
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "main/module.h"
|
||||
#include "network/connection.h"
|
||||
#include "network/socket.h"
|
||||
#include "protocol/common.h"
|
||||
#include "protocol/gopher/gopher.h"
|
||||
#include "protocol/protocol.h"
|
||||
#include "protocol/uri.h"
|
||||
@ -599,25 +600,15 @@ read_gopher_directory_data(struct connection *conn, struct read_buffer *rb)
|
||||
struct string buffer;
|
||||
unsigned char *end;
|
||||
|
||||
if (!init_string(&buffer))
|
||||
return S_OUT_OF_MEM;
|
||||
|
||||
if (conn->from == 0) {
|
||||
unsigned char *where = get_uri_string(conn->uri, URI_PUBLIC);
|
||||
enum connection_state state;
|
||||
|
||||
if (where) decode_uri_for_display(where);
|
||||
state = init_directory_listing(&buffer, conn->uri);
|
||||
if (state != S_OK)
|
||||
return state;
|
||||
|
||||
add_format_to_string(&buffer,
|
||||
"<html>\n"
|
||||
"<head>\n"
|
||||
"<title>Gopher menu at %s</title>\n"
|
||||
"</head>\n"
|
||||
"<body>\n"
|
||||
"<h1>Gopher menu at %s</h1>\n"
|
||||
"<pre>",
|
||||
empty_string_or_(where), empty_string_or_(where));
|
||||
|
||||
mem_free_if(where);
|
||||
} else if (!init_string(&buffer)) {
|
||||
return S_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
while ((end = get_gopher_line_end(rb->data, rb->length))) {
|
||||
|
@ -160,6 +160,9 @@ enum uri_component {
|
||||
/* Used for HTTP CONNECT method info */
|
||||
URI_HTTP_CONNECT = URI_HOST | URI_PORT | URI_DEFAULT_PORT,
|
||||
|
||||
/* Used for adding directory listing HTML header, */
|
||||
URI_DIR_LOCATION = URI_PROTOCOL | URI_HOST | URI_PORT | URI_IDN,
|
||||
|
||||
/* Used for getting the host of a DNS query. As a hidden bonus we get
|
||||
* IPv6 hostnames without the brackets because we don't ask for
|
||||
* URI_PORT. */
|
||||
|
Loading…
Reference in New Issue
Block a user