1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-09-28 03:06:20 -04:00

Rename DOM navigator -> stack

This is really a much more appropriate word since it never ended up being
more than just a stack. The rename also changes the symbol names to use the
much shorter "stack".
This commit is contained in:
Jonas Fonseca 2005-11-15 10:43:52 +01:00 committed by Jonas Fonseca
parent a0fb29bcd5
commit bccfbf8647
10 changed files with 383 additions and 382 deletions

View File

@ -1,6 +1,6 @@
top_builddir=../../..
include $(top_builddir)/Makefile.config
OBJS = navigator.o node.o renderer.o
OBJS = node.o renderer.o stack.o
include $(top_srcdir)/Makefile.lib

View File

@ -1,258 +0,0 @@
/* The DOM tree navigation interface */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include "elinks.h"
#include "document/dom/navigator.h"
#include "document/dom/node.h"
#include "util/memory.h"
#include "util/string.h"
/* Navigator states */
#define DOM_NAVIGATOR_STATE_GRANULARITY 0x7
#define DOM_NAVIGATOR_CALLBACKS_SIZE (sizeof(dom_navigator_callback_T) * DOM_NODES)
static inline struct dom_navigator_state *
realloc_dom_navigator_states(struct dom_navigator_state **states, size_t size)
{
return mem_align_alloc(states, size, size + 1,
struct dom_navigator_state,
DOM_NAVIGATOR_STATE_GRANULARITY);
}
static inline unsigned char *
realloc_dom_navigator_state_objects(struct dom_navigator *navigator)
{
#ifdef DEBUG_MEMLEAK
return mem_align_alloc__(__FILE__, __LINE__, (void **) &navigator->state_objects,
navigator->depth, navigator->depth + 1,
navigator->object_size,
DOM_NAVIGATOR_STATE_GRANULARITY);
#else
return mem_align_alloc__((void **) &navigator->state_objects,
navigator->depth, navigator->depth + 1,
navigator->object_size,
DOM_NAVIGATOR_STATE_GRANULARITY);
#endif
}
void
init_dom_navigator(struct dom_navigator *navigator, void *data,
dom_navigator_callback_T callbacks[DOM_NODES],
size_t object_size)
{
assert(navigator);
memset(navigator, 0, sizeof(*navigator));
navigator->data = data;
navigator->object_size = object_size;
if (callbacks)
memcpy(navigator->callbacks, callbacks, DOM_NAVIGATOR_CALLBACKS_SIZE);
}
void
done_dom_navigator(struct dom_navigator *navigator)
{
assert(navigator);
mem_free_if(navigator->states);
mem_free_if(navigator->state_objects);
memset(navigator, 0, sizeof(*navigator));
}
struct dom_node *
push_dom_node(struct dom_navigator *navigator, struct dom_node *node)
{
dom_navigator_callback_T callback;
struct dom_navigator_state *state;
assert(navigator && node);
assert(0 < node->type && node->type < DOM_NODES);
if (navigator->depth > DOM_NAVIGATOR_MAX_DEPTH) {
return NULL;
}
state = realloc_dom_navigator_states(&navigator->states, navigator->depth);
if (!state) {
done_dom_node(node);
return NULL;
}
state += navigator->depth;
if (navigator->object_size) {
unsigned char *state_objects;
size_t offset = navigator->depth * navigator->object_size;
state_objects = realloc_dom_navigator_state_objects(navigator);
if (!state_objects) {
done_dom_node(node);
return NULL;
}
state->data = (void *) &state_objects[offset];
}
state->node = node;
/* Grow the state array to the new depth so the state accessors work
* in the callbacks */
navigator->depth++;
callback = navigator->callbacks[node->type];
if (callback) {
node = callback(navigator, node, state->data);
/* If the callback returned NULL pop the state immediately */
if (!node) {
memset(state, 0, sizeof(*state));
navigator->depth--;
assert(navigator->depth >= 0);
}
}
return node;
}
static int
do_pop_dom_node(struct dom_navigator *navigator, struct dom_navigator_state *parent)
{
struct dom_navigator_state *state;
assert(navigator);
if (!dom_navigator_has_parents(navigator)) return 0;
state = get_dom_navigator_top(navigator);
if (state->callback) {
/* Pass the node we are popping to and _not_ the state->node */
state->callback(navigator, parent->node, state->data);
}
navigator->depth--;
assert(navigator->depth >= 0);
if (navigator->object_size && state->data) {
size_t offset = navigator->depth * navigator->object_size;
/* I tried to use item->data here but it caused a memory
* corruption bug on fm. This is also less trustworthy in that
* the state->data pointer could have been mangled. --jonas */
memset(&navigator->state_objects[offset], 0, navigator->object_size);
}
memset(state, 0, sizeof(*state));
return state == parent;
}
void
pop_dom_node(struct dom_navigator *navigator)
{
assert(navigator);
if (!dom_navigator_has_parents(navigator)) return;
do_pop_dom_node(navigator, get_dom_navigator_parent(navigator));
}
void
pop_dom_nodes(struct dom_navigator *navigator, enum dom_node_type type,
unsigned char *string, uint16_t length)
{
struct dom_navigator_state *state, *parent;
unsigned int pos;
if (!dom_navigator_has_parents(navigator)) return;
parent = search_dom_navigator(navigator, type, string, length);
if (!parent) return;
foreachback_dom_state (navigator, state, pos) {
if (do_pop_dom_node(navigator, parent))
break;;
}
}
void
walk_dom_nodes(struct dom_navigator *navigator, struct dom_node *root)
{
assert(root && navigator);
push_dom_node(navigator, root);
while (dom_navigator_has_parents(navigator)) {
struct dom_navigator_state *state = get_dom_navigator_top(navigator);
struct dom_node_list *list = state->list;
struct dom_node *node = state->node;
switch (node->type) {
case DOM_NODE_DOCUMENT:
if (!list) list = node->data.document.children;
break;
case DOM_NODE_ELEMENT:
if (!list) list = node->data.element.map;
if (list == node->data.element.children) break;
if (is_dom_node_list_member(list, state->index)
&& list == node->data.element.map)
break;
list = node->data.element.children;
break;
case DOM_NODE_PROCESSING_INSTRUCTION:
if (!list) list = node->data.proc_instruction.map;
break;
case DOM_NODE_DOCUMENT_TYPE:
if (!list) list = node->data.document_type.entities;
if (list == node->data.document_type.notations) break;
if (is_dom_node_list_member(list, state->index)
&& list == node->data.document_type.entities)
break;
list = node->data.document_type.notations;
break;
case DOM_NODE_ATTRIBUTE:
case DOM_NODE_TEXT:
case DOM_NODE_CDATA_SECTION:
case DOM_NODE_COMMENT:
case DOM_NODE_NOTATION:
case DOM_NODE_DOCUMENT_FRAGMENT:
case DOM_NODE_ENTITY_REFERENCE:
case DOM_NODE_ENTITY:
default:
break;
}
/* Reset list state if it is a new list */
if (list != state->list) {
state->list = list;
state->index = 0;
}
/* If we have next child node */
if (is_dom_node_list_member(list, state->index)) {
struct dom_node *child = list->entries[state->index++];
if (push_dom_node(navigator, child))
continue;
}
pop_dom_node(navigator);
}
}

View File

@ -16,9 +16,9 @@
#include "document/css/stylesheet.h"
#include "document/docdata.h"
#include "document/document.h"
#include "document/dom/navigator.h"
#include "document/dom/node.h"
#include "document/dom/renderer.h"
#include "document/dom/stack.h"
#include "document/renderer.h"
#include "document/sgml/parser.h"
#include "intl/charsets.h"
@ -389,9 +389,9 @@ add_dom_link(struct dom_renderer *renderer, unsigned char *string, int length)
#ifdef DOM_TREE_RENDERER
static struct dom_node *
render_dom_tree(struct dom_navigator *navigator, struct dom_node *node, void *data)
render_dom_tree(struct dom_stack *stack, struct dom_node *node, void *data)
{
struct dom_renderer *renderer = navigator->data;
struct dom_renderer *renderer = stack->data;
struct screen_char *template = &renderer->styles[node->type];
unsigned char *name, *value;
@ -409,9 +409,9 @@ render_dom_tree(struct dom_navigator *navigator, struct dom_node *node, void *da
}
static struct dom_node *
render_dom_tree_id_leaf(struct dom_navigator *navigator, struct dom_node *node, void *data)
render_dom_tree_id_leaf(struct dom_stack *stack, struct dom_node *node, void *data)
{
struct dom_renderer *renderer = navigator->data;
struct dom_renderer *renderer = stack->data;
struct document *document = renderer->document;
struct screen_char *template = &renderer->styles[node->type];
unsigned char *name, *value, *id;
@ -422,7 +422,7 @@ render_dom_tree_id_leaf(struct dom_navigator *navigator, struct dom_node *node,
value = get_dom_node_value(node, document->options.cp);
id = get_dom_node_type_name(node->type);
renderer->canvas_x += navigator->depth;
renderer->canvas_x += stack->depth;
render_dom_printf(renderer, template, "%-16s: %s -> %s\n", id, name, value);
mem_free_if(name);
@ -432,9 +432,9 @@ render_dom_tree_id_leaf(struct dom_navigator *navigator, struct dom_node *node,
}
static struct dom_node *
render_dom_tree_leaf(struct dom_navigator *navigator, struct dom_node *node, void *data)
render_dom_tree_leaf(struct dom_stack *stack, struct dom_node *node, void *data)
{
struct dom_renderer *renderer = navigator->data;
struct dom_renderer *renderer = stack->data;
struct document *document = renderer->document;
struct screen_char *template = &renderer->styles[node->type];
unsigned char *name, *value;
@ -444,7 +444,7 @@ render_dom_tree_leaf(struct dom_navigator *navigator, struct dom_node *node, voi
name = get_dom_node_name(node);
value = get_dom_node_value(node, document->options.cp);
renderer->canvas_x += navigator->depth;
renderer->canvas_x += stack->depth;
render_dom_printf(renderer, template, "%-16s: %s\n", name, value);
mem_free_if(name);
@ -454,9 +454,9 @@ render_dom_tree_leaf(struct dom_navigator *navigator, struct dom_node *node, voi
}
static struct dom_node *
render_dom_tree_branch(struct dom_navigator *navigator, struct dom_node *node, void *data)
render_dom_tree_branch(struct dom_stack *stack, struct dom_node *node, void *data)
{
struct dom_renderer *renderer = navigator->data;
struct dom_renderer *renderer = stack->data;
struct document *document = renderer->document;
struct screen_char *template = &renderer->styles[node->type];
unsigned char *name, *id;
@ -466,7 +466,7 @@ render_dom_tree_branch(struct dom_navigator *navigator, struct dom_node *node, v
name = get_dom_node_name(node);
id = get_dom_node_type_name(node->type);
renderer->canvas_x += navigator->depth;
renderer->canvas_x += stack->depth;
render_dom_printf(renderer, template, "%-16s: %s\n", id, name);
mem_free_if(name);
@ -474,7 +474,7 @@ render_dom_tree_branch(struct dom_navigator *navigator, struct dom_node *node, v
return node;
}
static dom_navigator_callback_T dom_tree_renderer_callbacks[DOM_NODES] = {
static dom_stack_callback_T dom_tree_renderer_callbacks[DOM_NODES] = {
/* */ NULL,
/* DOM_NODE_ELEMENT */ render_dom_tree_branch,
/* DOM_NODE_ATTRIBUTE */ render_dom_tree_id_leaf,
@ -538,9 +538,9 @@ render_dom_node_text(struct dom_renderer *renderer, struct screen_char *template
}
static struct dom_node *
render_dom_node_source(struct dom_navigator *navigator, struct dom_node *node, void *data)
render_dom_node_source(struct dom_stack *stack, struct dom_node *node, void *data)
{
struct dom_renderer *renderer = navigator->data;
struct dom_renderer *renderer = stack->data;
assert(node && renderer && renderer->document);
@ -552,9 +552,9 @@ render_dom_node_source(struct dom_navigator *navigator, struct dom_node *node, v
}
static struct dom_node *
render_dom_proc_instr_source(struct dom_navigator *navigator, struct dom_node *node, void *data)
render_dom_proc_instr_source(struct dom_stack *stack, struct dom_node *node, void *data)
{
struct dom_renderer *renderer = navigator->data;
struct dom_renderer *renderer = stack->data;
unsigned char *value;
int valuelen;
@ -579,9 +579,9 @@ render_dom_proc_instr_source(struct dom_navigator *navigator, struct dom_node *n
}
static struct dom_node *
render_dom_element_source(struct dom_navigator *navigator, struct dom_node *node, void *data)
render_dom_element_source(struct dom_stack *stack, struct dom_node *node, void *data)
{
struct dom_renderer *renderer = navigator->data;
struct dom_renderer *renderer = stack->data;
assert(node && renderer && renderer->document);
@ -591,10 +591,10 @@ render_dom_element_source(struct dom_navigator *navigator, struct dom_node *node
}
static struct dom_node *
render_dom_attribute_source(struct dom_navigator *navigator, struct dom_node *node, void *data)
render_dom_attribute_source(struct dom_stack *stack, struct dom_node *node, void *data)
{
struct dom_navigator_state *state = get_dom_navigator_parent(navigator);
struct dom_renderer *renderer = navigator->data;
struct dom_stack_state *state = get_dom_stack_parent(stack);
struct dom_renderer *renderer = stack->data;
struct screen_char *template = &renderer->styles[node->type];
struct dom_node *attribute = NULL;
int i;
@ -672,7 +672,7 @@ render_dom_attribute_source(struct dom_navigator *navigator, struct dom_node *no
return node;
}
static dom_navigator_callback_T dom_source_renderer_callbacks[DOM_NODES] = {
static dom_stack_callback_T dom_source_renderer_callbacks[DOM_NODES] = {
/* */ NULL,
/* DOM_NODE_ELEMENT */ render_dom_element_source,
/* DOM_NODE_ATTRIBUTE */ render_dom_attribute_source,
@ -698,8 +698,8 @@ render_dom_document(struct cache_entry *cached, struct document *document,
struct dom_node *root = parse_sgml(cached, document, buffer);
struct dom_renderer renderer;
struct conv_table *convert_table;
dom_navigator_callback_T *callbacks = dom_source_renderer_callbacks;
struct dom_navigator navigator;
dom_stack_callback_T *callbacks = dom_source_renderer_callbacks;
struct dom_stack stack;
assert(document->options.plain);
if (!root) return;
@ -711,11 +711,11 @@ render_dom_document(struct cache_entry *cached, struct document *document,
document->options.hard_assume);
init_dom_renderer(&renderer, document, buffer, root, convert_table);
init_dom_navigator(&navigator, &renderer, callbacks, 0);
init_dom_stack(&stack, &renderer, callbacks, 0);
document->bgcolor = document->options.default_bg;
walk_dom_nodes(&navigator, root);
walk_dom_nodes(&stack, root);
/* If there are no non-element nodes after the last element node make
* sure that we flush to the end of the cache entry source including
* the '>' of the last element tag if it has one. (bug 519) */
@ -724,5 +724,5 @@ render_dom_document(struct cache_entry *cached, struct document *document,
}
done_dom_node(root);
done_dom_navigator(&navigator);
done_dom_stack(&stack);
}

258
src/document/dom/stack.c Normal file
View File

@ -0,0 +1,258 @@
/* The DOM tree navigation interface */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include "elinks.h"
#include "document/dom/node.h"
#include "document/dom/stack.h"
#include "util/memory.h"
#include "util/string.h"
/* Navigator states */
#define DOM_STACK_STATE_GRANULARITY 0x7
#define DOM_STACK_CALLBACKS_SIZE (sizeof(dom_stack_callback_T) * DOM_NODES)
static inline struct dom_stack_state *
realloc_dom_stack_states(struct dom_stack_state **states, size_t size)
{
return mem_align_alloc(states, size, size + 1,
struct dom_stack_state,
DOM_STACK_STATE_GRANULARITY);
}
static inline unsigned char *
realloc_dom_stack_state_objects(struct dom_stack *stack)
{
#ifdef DEBUG_MEMLEAK
return mem_align_alloc__(__FILE__, __LINE__, (void **) &stack->state_objects,
stack->depth, stack->depth + 1,
stack->object_size,
DOM_STACK_STATE_GRANULARITY);
#else
return mem_align_alloc__((void **) &stack->state_objects,
stack->depth, stack->depth + 1,
stack->object_size,
DOM_STACK_STATE_GRANULARITY);
#endif
}
void
init_dom_stack(struct dom_stack *stack, void *data,
dom_stack_callback_T callbacks[DOM_NODES],
size_t object_size)
{
assert(stack);
memset(stack, 0, sizeof(*stack));
stack->data = data;
stack->object_size = object_size;
if (callbacks)
memcpy(stack->callbacks, callbacks, DOM_STACK_CALLBACKS_SIZE);
}
void
done_dom_stack(struct dom_stack *stack)
{
assert(stack);
mem_free_if(stack->states);
mem_free_if(stack->state_objects);
memset(stack, 0, sizeof(*stack));
}
struct dom_node *
push_dom_node(struct dom_stack *stack, struct dom_node *node)
{
dom_stack_callback_T callback;
struct dom_stack_state *state;
assert(stack && node);
assert(0 < node->type && node->type < DOM_NODES);
if (stack->depth > DOM_STACK_MAX_DEPTH) {
return NULL;
}
state = realloc_dom_stack_states(&stack->states, stack->depth);
if (!state) {
done_dom_node(node);
return NULL;
}
state += stack->depth;
if (stack->object_size) {
unsigned char *state_objects;
size_t offset = stack->depth * stack->object_size;
state_objects = realloc_dom_stack_state_objects(stack);
if (!state_objects) {
done_dom_node(node);
return NULL;
}
state->data = (void *) &state_objects[offset];
}
state->node = node;
/* Grow the state array to the new depth so the state accessors work
* in the callbacks */
stack->depth++;
callback = stack->callbacks[node->type];
if (callback) {
node = callback(stack, node, state->data);
/* If the callback returned NULL pop the state immediately */
if (!node) {
memset(state, 0, sizeof(*state));
stack->depth--;
assert(stack->depth >= 0);
}
}
return node;
}
static int
do_pop_dom_node(struct dom_stack *stack, struct dom_stack_state *parent)
{
struct dom_stack_state *state;
assert(stack);
if (!dom_stack_has_parents(stack)) return 0;
state = get_dom_stack_top(stack);
if (state->callback) {
/* Pass the node we are popping to and _not_ the state->node */
state->callback(stack, parent->node, state->data);
}
stack->depth--;
assert(stack->depth >= 0);
if (stack->object_size && state->data) {
size_t offset = stack->depth * stack->object_size;
/* I tried to use item->data here but it caused a memory
* corruption bug on fm. This is also less trustworthy in that
* the state->data pointer could have been mangled. --jonas */
memset(&stack->state_objects[offset], 0, stack->object_size);
}
memset(state, 0, sizeof(*state));
return state == parent;
}
void
pop_dom_node(struct dom_stack *stack)
{
assert(stack);
if (!dom_stack_has_parents(stack)) return;
do_pop_dom_node(stack, get_dom_stack_parent(stack));
}
void
pop_dom_nodes(struct dom_stack *stack, enum dom_node_type type,
unsigned char *string, uint16_t length)
{
struct dom_stack_state *state, *parent;
unsigned int pos;
if (!dom_stack_has_parents(stack)) return;
parent = search_dom_stack(stack, type, string, length);
if (!parent) return;
foreachback_dom_state (stack, state, pos) {
if (do_pop_dom_node(stack, parent))
break;;
}
}
void
walk_dom_nodes(struct dom_stack *stack, struct dom_node *root)
{
assert(root && stack);
push_dom_node(stack, root);
while (dom_stack_has_parents(stack)) {
struct dom_stack_state *state = get_dom_stack_top(stack);
struct dom_node_list *list = state->list;
struct dom_node *node = state->node;
switch (node->type) {
case DOM_NODE_DOCUMENT:
if (!list) list = node->data.document.children;
break;
case DOM_NODE_ELEMENT:
if (!list) list = node->data.element.map;
if (list == node->data.element.children) break;
if (is_dom_node_list_member(list, state->index)
&& list == node->data.element.map)
break;
list = node->data.element.children;
break;
case DOM_NODE_PROCESSING_INSTRUCTION:
if (!list) list = node->data.proc_instruction.map;
break;
case DOM_NODE_DOCUMENT_TYPE:
if (!list) list = node->data.document_type.entities;
if (list == node->data.document_type.notations) break;
if (is_dom_node_list_member(list, state->index)
&& list == node->data.document_type.entities)
break;
list = node->data.document_type.notations;
break;
case DOM_NODE_ATTRIBUTE:
case DOM_NODE_TEXT:
case DOM_NODE_CDATA_SECTION:
case DOM_NODE_COMMENT:
case DOM_NODE_NOTATION:
case DOM_NODE_DOCUMENT_FRAGMENT:
case DOM_NODE_ENTITY_REFERENCE:
case DOM_NODE_ENTITY:
default:
break;
}
/* Reset list state if it is a new list */
if (list != state->list) {
state->list = list;
state->index = 0;
}
/* If we have next child node */
if (is_dom_node_list_member(list, state->index)) {
struct dom_node *child = list->entries[state->index++];
if (push_dom_node(stack, child))
continue;
}
pop_dom_node(stack);
}
}

View File

@ -1,13 +1,13 @@
#ifndef EL__DOCUMENT_DOM_NAVIGATOR_H
#define EL__DOCUMENT_DOM_NAVIGATOR_H
#ifndef EL__DOCUMENT_DOM_STACK_H
#define EL__DOCUMENT_DOM_STACK_H
#include "document/document.h"
#include "document/dom/node.h"
#include "util/error.h"
#include "util/hash.h"
struct dom_navigator;
struct dom_stack;
enum dom_exception_code {
DOM_ERR_NONE = 0,
@ -31,26 +31,26 @@ enum dom_exception_code {
};
typedef struct dom_node *
(*dom_navigator_callback_T)(struct dom_navigator *, struct dom_node *, void *);
(*dom_stack_callback_T)(struct dom_stack *, struct dom_node *, void *);
#define DOM_NAVIGATOR_MAX_DEPTH 4096
#define DOM_STACK_MAX_DEPTH 4096
struct dom_navigator_state {
struct dom_stack_state {
struct dom_node *node;
struct dom_node_list *list;
size_t index;
dom_navigator_callback_T callback;
dom_stack_callback_T callback;
void *data;
};
/* The DOM navigator is a convenient way to traverse DOM trees. Also it
/* The DOM stack is a convenient way to traverse DOM trees. Also it
* maintains needed state info and is therefore also a holder of the current
* context since the navigator is used to when the DOM tree is manipulated. */
struct dom_navigator {
* context since the stack is used to when the DOM tree is manipulated. */
struct dom_stack {
/* The stack of nodes */
struct dom_navigator_state *states;
struct dom_stack_state *states;
size_t depth;
unsigned char *state_objects;
@ -60,23 +60,23 @@ struct dom_navigator {
enum dom_exception_code exception;
/* Parser and document specific stuff */
dom_navigator_callback_T callbacks[DOM_NODES];
dom_stack_callback_T callbacks[DOM_NODES];
void *data;
};
#define dom_navigator_has_parents(nav) \
#define dom_stack_has_parents(nav) \
((nav)->states && (nav)->depth > 0)
static inline struct dom_navigator_state *
get_dom_navigator_state(struct dom_navigator *navigator, int top_offset)
static inline struct dom_stack_state *
get_dom_stack_state(struct dom_stack *stack, int top_offset)
{
assertm(navigator->depth - 1 - top_offset >= 0,
assertm(stack->depth - 1 - top_offset >= 0,
"Attempting to access invalid state");
return &navigator->states[navigator->depth - 1 - top_offset];
return &stack->states[stack->depth - 1 - top_offset];
}
#define get_dom_navigator_parent(nav) get_dom_navigator_state(nav, 1)
#define get_dom_navigator_top(nav) get_dom_navigator_state(nav, 0)
#define get_dom_stack_parent(nav) get_dom_stack_state(nav, 1)
#define get_dom_stack_top(nav) get_dom_stack_state(nav, 0)
/* The state iterators do not include the bottom state */
@ -88,15 +88,15 @@ get_dom_navigator_state(struct dom_navigator *navigator, int top_offset)
for ((pos) = (nav)->depth - 1; (pos) > 0; (pos)--) \
if (((item) = &(nav)->states[(pos)]))
/* Dive through the navigator states in search for the specified match. */
static inline struct dom_navigator_state *
search_dom_navigator(struct dom_navigator *navigator, enum dom_node_type type,
unsigned char *string, uint16_t length)
/* Dive through the stack states in search for the specified match. */
static inline struct dom_stack_state *
search_dom_stack(struct dom_stack *stack, enum dom_node_type type,
unsigned char *string, uint16_t length)
{
struct dom_navigator_state *state;
struct dom_stack_state *state;
int pos;
foreachback_dom_state (navigator, state, pos) {
foreachback_dom_state (stack, state, pos) {
struct dom_node *parent = state->node;
if (parent->type == type
@ -111,24 +111,26 @@ search_dom_navigator(struct dom_navigator *navigator, enum dom_node_type type,
/* Life cycle functions. */
/* The @object_size arg tells whether the navigator should allocate objects for each
/* The @object_size arg tells whether the stack should allocate objects for each
* state to be assigned to the state's @data member. Zero means no state data should
* be allocated. */
void init_dom_navigator(struct dom_navigator *navigator, void *data, dom_navigator_callback_T callbacks[DOM_NODES], size_t object_size);
void done_dom_navigator(struct dom_navigator *navigator);
void init_dom_stack(struct dom_stack *stack, void *data,
dom_stack_callback_T callbacks[DOM_NODES],
size_t object_size);
void done_dom_stack(struct dom_stack *stack);
/* Decends down to the given node making it the current parent */
/* If an error occurs the node is free()d and NULL is returned */
struct dom_node *push_dom_node(struct dom_navigator *navigator, struct dom_node *node);
struct dom_node *push_dom_node(struct dom_stack *stack, struct dom_node *node);
/* Ascends the navigator to the current parent */
void pop_dom_node(struct dom_navigator *navigator);
/* Ascends the stack to the current parent */
void pop_dom_node(struct dom_stack *stack);
/* Ascends the navigator looking for specific parent */
void pop_dom_nodes(struct dom_navigator *navigator, enum dom_node_type type,
/* Ascends the stack looking for specific parent */
void pop_dom_nodes(struct dom_stack *stack, enum dom_node_type type,
unsigned char *string, uint16_t length);
/* Visit each node in the tree rooted at @root pre-order */
void walk_dom_nodes(struct dom_navigator *navigator, struct dom_node *root);
void walk_dom_nodes(struct dom_stack *stack, struct dom_node *root);
#endif

View File

@ -9,8 +9,8 @@
#include "elinks.h"
#include "document/dom/navigator.h"
#include "document/dom/node.h"
#include "document/dom/stack.h"
#include "document/sgml/html/html.h"
#include "document/sgml/parser.h"
#include "document/sgml/scanner.h"
@ -38,20 +38,20 @@ static struct sgml_node_info html_elements[HTML_ELEMENTS] = {
static struct dom_node *
add_html_element_end_node(struct dom_navigator *navigator, struct dom_node *node, void *data)
add_html_element_end_node(struct dom_stack *stack, struct dom_node *node, void *data)
{
struct sgml_parser *parser = navigator->data;
struct sgml_parser *parser = stack->data;
struct dom_node *parent;
struct scanner_token *token;
assert(navigator && parser && node);
assert(dom_navigator_has_parents(navigator));
assert(stack && parser && node);
assert(dom_stack_has_parents(stack));
/* Are we the actual node being popped? */
if (node != get_dom_navigator_top(navigator)->node)
if (node != get_dom_stack_top(stack)->node)
return NULL;
parent = get_dom_navigator_parent(navigator)->node;
parent = get_dom_stack_parent(stack)->node;
token = get_scanner_token(&parser->scanner);
assertm(token, "No token found in callback");
@ -65,17 +65,17 @@ add_html_element_end_node(struct dom_navigator *navigator, struct dom_node *node
/* TODO: We need to handle ascending of <br> and "<p>text1<p>text2" using data
* from sgml_node_info. */
static struct dom_node *
add_html_element_node(struct dom_navigator *navigator, struct dom_node *node, void *data)
add_html_element_node(struct dom_stack *stack, struct dom_node *node, void *data)
{
struct sgml_parser *parser = navigator->data;
struct sgml_parser *parser = stack->data;
assert(navigator && node);
assert(dom_navigator_has_parents(navigator));
assert(stack && node);
assert(dom_stack_has_parents(stack));
/* TODO: Move to SGML parser main loop and disguise these element ends
* in some internal processing instruction. */
if (parser->flags & SGML_PARSER_ADD_ELEMENT_ENDS)
get_dom_navigator_top(navigator)->callback = add_html_element_end_node;
get_dom_stack_top(stack)->callback = add_html_element_end_node;
return node;
}

View File

@ -2,7 +2,7 @@
#ifndef EL__DOCUMENT_SGML_HTML_HTML_H
#define EL__DOCUMENT_SGML_HTML_HTML_H
#include "document/dom/navigator.h"
#include "document/dom/stack.h"
#include "document/sgml/sgml.h"
extern struct sgml_info sgml_html_info;

View File

@ -11,8 +11,8 @@
#include "cache/cache.h"
#include "document/document.h"
#include "document/dom/navigator.h"
#include "document/dom/node.h"
#include "document/dom/stack.h"
#include "document/html/renderer.h" /* TODO: Move get_convert_table() */
#include "document/sgml/html/html.h"
#include "document/sgml/parser.h"
@ -29,30 +29,30 @@
/* Functions for adding new nodes to the DOM tree */
static inline struct dom_node *
add_sgml_document(struct dom_navigator *navigator, struct uri *uri)
add_sgml_document(struct dom_stack *stack, struct uri *uri)
{
unsigned char *string = struri(uri);
int length = strlen(string);
struct dom_node *node = init_dom_node(DOM_NODE_DOCUMENT, string, length);
return node ? push_dom_node(navigator, node) : node;
return node ? push_dom_node(stack, node) : node;
}
static inline struct dom_node *
add_sgml_element(struct dom_navigator *navigator, struct scanner_token *token)
add_sgml_element(struct dom_stack *stack, struct scanner_token *token)
{
struct sgml_parser *parser = navigator->data;
struct dom_node *parent = get_dom_navigator_top(navigator)->node;
struct dom_navigator_state *state;
struct sgml_parser *parser = stack->data;
struct dom_node *parent = get_dom_stack_top(stack)->node;
struct dom_stack_state *state;
struct sgml_parser_state *pstate;
struct dom_node *node;
node = add_dom_element(parent, token->string, token->length);
if (!node || !push_dom_node(navigator, node))
if (!node || !push_dom_node(stack, node))
return NULL;
state = get_dom_navigator_top(navigator);
state = get_dom_stack_top(stack);
assert(node == state->node && state->data);
pstate = state->data;
@ -64,11 +64,11 @@ add_sgml_element(struct dom_navigator *navigator, struct scanner_token *token)
static inline void
add_sgml_attribute(struct dom_navigator *navigator,
add_sgml_attribute(struct dom_stack *stack,
struct scanner_token *token, struct scanner_token *valtoken)
{
struct sgml_parser *parser = navigator->data;
struct dom_node *parent = get_dom_navigator_top(navigator)->node;
struct sgml_parser *parser = stack->data;
struct dom_node *parent = get_dom_stack_top(stack)->node;
unsigned char *value = valtoken ? valtoken->string : NULL;
uint16_t valuelen = valtoken ? valtoken->length : 0;
struct sgml_node_info *info;
@ -77,7 +77,7 @@ add_sgml_attribute(struct dom_navigator *navigator,
node = add_dom_attribute(parent, token->string, token->length,
value, valuelen);
if (!node || !push_dom_node(navigator, node))
if (!node || !push_dom_node(stack, node))
return;
info = get_sgml_node_info(parser->info->attributes, node);
@ -89,13 +89,13 @@ add_sgml_attribute(struct dom_navigator *navigator,
if (valtoken && valtoken->type == SGML_TOKEN_STRING)
node->data.attribute.quoted = 1;
pop_dom_node(navigator);
pop_dom_node(stack);
}
static inline struct dom_node *
add_sgml_proc_instruction(struct dom_navigator *navigator, struct scanner_token *token)
add_sgml_proc_instruction(struct dom_stack *stack, struct scanner_token *token)
{
struct dom_node *parent = get_dom_navigator_top(navigator)->node;
struct dom_node *parent = get_dom_stack_top(stack)->node;
struct dom_node *node;
/* Split the token in two if we can find a first space separator. */
unsigned char *separator = memchr(token->string, ' ', token->length);
@ -121,19 +121,19 @@ add_sgml_proc_instruction(struct dom_navigator *navigator, struct scanner_token
node->data.proc_instruction.type = DOM_PROC_INSTRUCTION;
}
if (!push_dom_node(navigator, node))
if (!push_dom_node(stack, node))
return NULL;
if (token->type != SGML_TOKEN_PROCESS_XML)
pop_dom_node(navigator);
pop_dom_node(stack);
return node;
}
static inline void
add_sgml_node(struct dom_navigator *navigator, enum dom_node_type type, struct scanner_token *token)
add_sgml_node(struct dom_stack *stack, enum dom_node_type type, struct scanner_token *token)
{
struct dom_node *parent = get_dom_navigator_top(navigator)->node;
struct dom_node *parent = get_dom_stack_top(stack)->node;
struct dom_node *node = add_dom_node(parent, type, token->string, token->length);
if (!node) return;
@ -141,16 +141,16 @@ add_sgml_node(struct dom_navigator *navigator, enum dom_node_type type, struct s
if (token->type == SGML_TOKEN_SPACE)
node->data.text.only_space = 1;
if (push_dom_node(navigator, node))
pop_dom_node(navigator);
if (push_dom_node(stack, node))
pop_dom_node(stack);
}
#define add_sgml_entityref(nav, t) add_sgml_node(nav, DOM_NODE_ENTITY_REFERENCE, t)
#define add_sgml_text(nav, t) add_sgml_node(nav, DOM_NODE_TEXT, t)
#define add_sgml_comment(nav, t) add_sgml_node(nav, DOM_NODE_COMMENT, t)
#define add_sgml_entityref(stack, t) add_sgml_node(stack, DOM_NODE_ENTITY_REFERENCE, t)
#define add_sgml_text(stack, t) add_sgml_node(stack, DOM_NODE_TEXT, t)
#define add_sgml_comment(stack, t) add_sgml_node(stack, DOM_NODE_COMMENT, t)
static inline void
parse_sgml_attributes(struct dom_navigator *navigator, struct scanner *scanner)
parse_sgml_attributes(struct dom_stack *stack, struct scanner *scanner)
{
struct scanner_token name;
@ -193,7 +193,7 @@ parse_sgml_attributes(struct dom_navigator *navigator, struct scanner *scanner)
token = NULL;
}
add_sgml_attribute(navigator, &name, token);
add_sgml_attribute(stack, &name, token);
/* Skip the value token */
if (token)
@ -208,7 +208,7 @@ parse_sgml_attributes(struct dom_navigator *navigator, struct scanner *scanner)
}
void
parse_sgml_document(struct dom_navigator *navigator, struct scanner *scanner)
parse_sgml_document(struct dom_stack *stack, struct scanner *scanner)
{
while (scanner_has_tokens(scanner)) {
struct scanner_token *token = get_scanner_token(scanner);
@ -216,7 +216,7 @@ parse_sgml_document(struct dom_navigator *navigator, struct scanner *scanner)
switch (token->type) {
case SGML_TOKEN_ELEMENT:
case SGML_TOKEN_ELEMENT_BEGIN:
if (!add_sgml_element(navigator, token)) {
if (!add_sgml_element(stack, token)) {
if (token->type == SGML_TOKEN_ELEMENT) {
skip_scanner_token(scanner);
break;
@ -227,7 +227,7 @@ parse_sgml_document(struct dom_navigator *navigator, struct scanner *scanner)
}
if (token->type == SGML_TOKEN_ELEMENT_BEGIN) {
parse_sgml_attributes(navigator, scanner);
parse_sgml_attributes(stack, scanner);
} else {
skip_scanner_token(scanner);
}
@ -235,22 +235,22 @@ parse_sgml_document(struct dom_navigator *navigator, struct scanner *scanner)
break;
case SGML_TOKEN_ELEMENT_EMPTY_END:
pop_dom_node(navigator);
pop_dom_node(stack);
skip_scanner_token(scanner);
break;
case SGML_TOKEN_ELEMENT_END:
if (!token->length) {
pop_dom_node(navigator);
pop_dom_node(stack);
} else {
pop_dom_nodes(navigator, DOM_NODE_ELEMENT,
pop_dom_nodes(stack, DOM_NODE_ELEMENT,
token->string, token->length);
}
skip_scanner_token(scanner);
break;
case SGML_TOKEN_NOTATION_COMMENT:
add_sgml_comment(navigator, token);
add_sgml_comment(stack, token);
skip_scanner_token(scanner);
break;
@ -263,29 +263,29 @@ parse_sgml_document(struct dom_navigator *navigator, struct scanner *scanner)
break;
case SGML_TOKEN_PROCESS_XML:
if (!add_sgml_proc_instruction(navigator, token)) {
if (!add_sgml_proc_instruction(stack, token)) {
skip_sgml_tokens(scanner, SGML_TOKEN_TAG_END);
break;
}
parse_sgml_attributes(navigator, scanner);
pop_dom_node(navigator);
parse_sgml_attributes(stack, scanner);
pop_dom_node(stack);
break;
case SGML_TOKEN_PROCESS:
add_sgml_proc_instruction(navigator, token);
add_sgml_proc_instruction(stack, token);
skip_scanner_token(scanner);
break;
case SGML_TOKEN_ENTITY:
add_sgml_entityref(navigator, token);
add_sgml_entityref(stack, token);
skip_scanner_token(scanner);
break;
case SGML_TOKEN_SPACE:
case SGML_TOKEN_TEXT:
default:
add_sgml_text(navigator, token);
add_sgml_text(stack, token);
skip_scanner_token(scanner);
}
}
@ -316,19 +316,19 @@ struct dom_node *
parse_sgml(struct cache_entry *cached, struct document *document,
struct string *buffer)
{
struct dom_navigator navigator;
struct dom_stack stack;
struct sgml_parser parser;
size_t obj_size = sizeof(struct sgml_parser_state);
init_sgml_parser(&parser, document, cached, &sgml_html_info, buffer);
init_dom_navigator(&navigator, &parser, parser.info->callbacks, obj_size);
init_dom_stack(&stack, &parser, parser.info->callbacks, obj_size);
parser.root = add_sgml_document(&navigator, document->uri);
parser.root = add_sgml_document(&stack, document->uri);
if (parser.root) {
parse_sgml_document(&navigator, &parser.scanner);
parse_sgml_document(&stack, &parser.scanner);
}
done_dom_navigator(&navigator);
done_dom_stack(&stack);
return parser.root;
}

View File

@ -9,7 +9,6 @@
#include "elinks.h"
#include "document/dom/navigator.h"
#include "document/dom/node.h"
#include "document/sgml/sgml.h"
#include "util/error.h"

View File

@ -4,7 +4,7 @@
#include <stdlib.h>
#include "document/dom/navigator.h"
#include "document/dom/stack.h"
/* The flags stored in the attribute sgml node info data */
/* TODO: Other potential flags (there can be only 16)
@ -76,7 +76,7 @@ get_sgml_node_info(struct sgml_node_info list[], struct dom_node *node)
struct sgml_info {
struct sgml_node_info *attributes;
struct sgml_node_info *elements;
dom_navigator_callback_T callbacks[DOM_NODES];
dom_stack_callback_T callbacks[DOM_NODES];
};
#endif