1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-06-28 01:35:32 +00:00

Fix SGML parsing of processing instructions (<?xml ...?>)

It involves adding a new scanner state which is used only to generate a new
processing instruction (PI) data token. This removes some scanner specific
code from the parser and makes handling of PIs more generic. The data of
XML PIs are still parsed as attributes and added to the PI node.

The 6th test now succeeds. Hurrah!
This commit is contained in:
Jonas Fonseca 2005-12-29 18:31:49 +01:00 committed by Jonas Fonseca
parent c24c67ce59
commit 1a177491a0
3 changed files with 78 additions and 63 deletions

View File

@ -103,26 +103,17 @@ add_sgml_attribute(struct dom_stack *stack,
}
static inline struct dom_node *
add_sgml_proc_instruction(struct dom_stack *stack, struct dom_scanner_token *token)
add_sgml_proc_instruction(struct dom_stack *stack, struct dom_scanner_token *target,
struct dom_scanner_token *data)
{
struct dom_node *parent = get_dom_stack_top(stack)->node;
struct dom_string *data_str = data ? &data->string : NULL;
struct dom_node *node;
/* Split the token in two if we can find a first space separator. */
unsigned char *separator = memchr(token->string.string, ' ', token->string.length);
/* Anything before the separator becomes the target name ... */
size_t namelen = separator ? separator - token->string.string : token->string.length;
struct dom_string name = INIT_DOM_STRING(token->string.string, namelen);
/* ... and everything after the instruction value. */
unsigned char *valuestr = separator ? separator + 1 : NULL;
size_t valuelen = valuestr ? token->string.length - namelen - 1 : 0;
struct dom_string value = INIT_DOM_STRING(valuestr, valuelen);
node = add_dom_proc_instruction(parent, &name, &value);
node = add_dom_proc_instruction(parent, &target->string, data_str);
if (!node) return NULL;
switch (token->type) {
switch (target->type) {
case SGML_TOKEN_PROCESS_XML:
node->data.proc_instruction.type = DOM_PROC_INSTRUCTION_XML;
break;
@ -132,13 +123,7 @@ add_sgml_proc_instruction(struct dom_stack *stack, struct dom_scanner_token *tok
node->data.proc_instruction.type = DOM_PROC_INSTRUCTION;
}
if (!push_dom_node(stack, node))
return NULL;
if (token->type != SGML_TOKEN_PROCESS_XML)
pop_dom_node(stack);
return node;
return push_dom_node(stack, node);
}
static inline void
@ -166,9 +151,12 @@ parse_sgml_attributes(struct dom_stack *stack, struct dom_scanner *scanner)
assert(dom_scanner_has_tokens(scanner)
&& (get_dom_scanner_token(scanner)->type == SGML_TOKEN_ELEMENT_BEGIN
|| get_dom_scanner_token(scanner)->type == SGML_TOKEN_PROCESS_XML));
|| (get_dom_stack_top(stack)->node->type == DOM_NODE_PROCESSING_INSTRUCTION
&& get_dom_stack_top(stack)->node->data.proc_instruction.type
== DOM_PROC_INSTRUCTION_XML)));
skip_dom_scanner_token(scanner);
if (get_dom_scanner_token(scanner)->type == SGML_TOKEN_ELEMENT_BEGIN)
skip_dom_scanner_token(scanner);
while (dom_scanner_has_tokens(scanner)) {
struct dom_scanner_token *token = get_dom_scanner_token(scanner);
@ -220,6 +208,8 @@ parse_sgml_attributes(struct dom_stack *stack, struct dom_scanner *scanner)
static void
parse_sgml_plain(struct dom_stack *stack, struct dom_scanner *scanner)
{
struct dom_scanner_token target;
while (dom_scanner_has_tokens(scanner)) {
struct dom_scanner_token *token = get_dom_scanner_token(scanner);
@ -290,17 +280,31 @@ parse_sgml_plain(struct dom_stack *stack, struct dom_scanner *scanner)
break;
case SGML_TOKEN_PROCESS_XML:
if (!add_sgml_proc_instruction(stack, token)) {
skip_sgml_tokens(scanner, SGML_TOKEN_TAG_END);
break;
case SGML_TOKEN_PROCESS:
copy_struct(&target, token);
/* Skip the target token */
token = get_next_dom_scanner_token(scanner);
if (!token) break;
assert(token->type == SGML_TOKEN_PROCESS_DATA);
if (add_sgml_proc_instruction(stack, &target, token)
&& target.type == SGML_TOKEN_PROCESS_XML
&& token->string.length > 0) {
/* Parse the <?xml data="attributes"?>. */
struct dom_scanner attr_scanner;
init_dom_scanner_state(&attr_scanner,
&sgml_scanner_info,
&token->string,
SGML_STATE_ELEMENT);
if (dom_scanner_has_tokens(&attr_scanner))
parse_sgml_attributes(stack, &attr_scanner);
}
parse_sgml_attributes(stack, scanner);
pop_dom_node(stack);
break;
case SGML_TOKEN_PROCESS:
add_sgml_proc_instruction(stack, token);
skip_dom_scanner_token(scanner);
break;

View File

@ -17,14 +17,6 @@
/* Bitmap entries for the SGML character groups used in the scanner table */
/* The SGML tokenizer maintains a state that can be either text or element
* state. The state has only meaning while doing the actual scanning and is not
* accessible at the parsing time. */
enum sgml_scanner_state {
SGML_STATE_TEXT,
SGML_STATE_ELEMENT,
};
enum sgml_char_group {
SGML_CHAR_ENTITY = (1 << 1),
SGML_CHAR_IDENT = (1 << 2),
@ -296,27 +288,7 @@ scan_sgml_element_token(struct dom_scanner *scanner, struct dom_scanner_token *t
type = map_dom_scanner_string(scanner, pos, string, base);
/* Figure out where the processing instruction ends */
for (pos = string; skip_sgml(scanner, &pos, '>', 0); ) {
if (pos[-2] != '?') continue;
/* Set length until '?' char and move position
* beyond '>'. */
real_length = pos - token->string.string - 2;
break;
}
switch (type) {
case SGML_TOKEN_PROCESS_XML:
/* We want to parse the attributes */
assert(scanner->state != SGML_STATE_ELEMENT);
scanner->state = SGML_STATE_ELEMENT;
break;
default:
/* Just skip the whole thing */
string = pos;
}
scanner->state = SGML_STATE_PROC_INST;
} else if (*string == '/') {
string++;
@ -403,6 +375,28 @@ scan_sgml_element_token(struct dom_scanner *scanner, struct dom_scanner_token *t
}
/* Processing instruction data scanning */
static inline void
scan_sgml_proc_inst_token(struct dom_scanner *scanner, struct dom_scanner_token *token)
{
unsigned char *string = scanner->position;
token->string.string = string++;
/* Figure out where the processing instruction ends */
while (skip_sgml(scanner, &string, '>', 0))
if (string[-2] == '?')
break;
token->type = SGML_TOKEN_PROCESS_DATA;
token->string.length = string - token->string.string - 2;
token->precedence = get_sgml_precedence(token->type);
scanner->position = string;
scanner->state = SGML_STATE_TEXT;
}
/* Scanner multiplexor */
static struct dom_scanner_token *
@ -429,8 +423,13 @@ scan_sgml_tokens(struct dom_scanner *scanner)
if (current->type == SGML_TOKEN_SKIP) {
current--;
}
} else {
} else if (scanner->state == SGML_STATE_TEXT) {
scan_sgml_text_token(scanner, current);
} else {
scan_sgml(scanner, scanner->position, SGML_CHAR_WHITESPACE);
scan_sgml_proc_inst_token(scanner, current);
}
}

View File

@ -27,8 +27,9 @@ enum sgml_token_type {
SGML_TOKEN_CDATA_SECTION, /* <![CDATA[ until ]]> */
SGML_TOKEN_PROCESS, /* <?{ident} until ?> */
SGML_TOKEN_PROCESS_XML, /* <?xml until */
SGML_TOKEN_PROCESS, /* <?{ident} */
SGML_TOKEN_PROCESS_XML, /* <?xml */
SGML_TOKEN_PROCESS_DATA, /* data after <?{ident} until ?> */
SGML_TOKEN_ELEMENT, /* <{ident}> */
SGML_TOKEN_ELEMENT_BEGIN, /* <{ident} */
@ -56,6 +57,17 @@ enum sgml_token_type {
SGML_TOKEN_NONE = 0,
};
/* The SGML tokenizer maintains a state (in the scanner->state member) that can
* be either text, element, or processing instruction state. The state has only
* meaning while doing the actual scanning and should not be used at the
* parsing time. It can however be used to initialize the scanner to a specific
* state. */
enum sgml_scanner_state {
SGML_STATE_TEXT,
SGML_STATE_ELEMENT,
SGML_STATE_PROC_INST,
};
extern struct dom_scanner_info sgml_scanner_info;
/* Treat '<' as more valuable then '>' so that scanning of '<a<b>' using