From d8866e3acdb41e913e2f82e1c0cb10c11f14ed62 Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Thu, 26 Jul 2007 22:19:48 +0000 Subject: Implement type-specific node constructors and veneer the appropriate Document APIs onto them. svn path=/trunk/dom/; revision=3463 --- include/dom/core/node.h | 5 ++- src/core/attr.c | 48 ++++++++++++++++++++ src/core/attr.h | 20 +++++++++ src/core/characterdata.c | 59 +++++++++++++++++++++++++ src/core/characterdata.h | 8 ++++ src/core/document.c | 92 ++++++++++++++++++++------------------- src/core/document.h | 4 +- src/core/element.c | 45 +++++++++++++++++++ src/core/element.h | 20 +++++++++ src/core/namednodemap.h | 4 +- src/core/node.c | 111 ++++++++++++++++++++++++++++++++++------------- src/core/node.h | 6 ++- src/core/nodelist.h | 4 +- src/core/text.c | 47 ++++++++++++++++++++ src/core/text.h | 23 ++++++++++ 15 files changed, 413 insertions(+), 83 deletions(-) create mode 100644 src/core/attr.h create mode 100644 src/core/element.h create mode 100644 src/core/text.h diff --git a/include/dom/core/node.h b/include/dom/core/node.h index 7db34f6..e566622 100644 --- a/include/dom/core/node.h +++ b/include/dom/core/node.h @@ -64,7 +64,10 @@ typedef enum { DOM_DOCUMENT_NODE = 9, DOM_DOCUMENT_TYPE_NODE = 10, DOM_DOCUMENT_FRAGMENT_NODE = 11, - DOM_NOTATION_NODE = 12 + DOM_NOTATION_NODE = 12, + + /* And a count of the number of node types */ + DOM_NODE_TYPE_COUNT = DOM_NOTATION_NODE } dom_node_type; diff --git a/src/core/attr.c b/src/core/attr.c index bcdc0ce..ed20c93 100644 --- a/src/core/attr.c +++ b/src/core/attr.c @@ -9,6 +9,8 @@ #include +#include "core/attr.h" +#include "core/document.h" #include "core/node.h" #include "utils/utils.h" @@ -31,6 +33,52 @@ struct dom_attr { bool is_id; /**< Attribute is of type ID */ }; +/** + * Create an attribute node + * + * \param doc The owning document + * \param name The name of the node to create + * \param result Pointer to location to receive created attribute + * \return DOM_NO_ERR on success, + * DOM_INVALID_CHARACTER_ERR if ::name is invalid, + * DOM_NO_MEM_ERR on memory exhaustion. + * + * ::doc and ::name will have their reference counts increased. + * + * The returned attribute will already be referenced. + */ +dom_exception dom_attr_create(struct dom_document *doc, + struct dom_string *name, struct dom_attr **result) +{ + struct dom_attr *a; + dom_exception err; + + /** \todo Sanity check the attribute name */ + + /* Allocate the element */ + a = dom_document_alloc(doc, NULL, sizeof(struct dom_attr)); + if (a == NULL) + return DOM_NO_MEM_ERR; + + /* Initialise the base class */ + err = dom_node_initialise(&a->base, doc, DOM_ATTRIBUTE_NODE, + name, NULL); + if (err != DOM_NO_ERR) { + dom_document_alloc(doc, a, 0); + return err; + } + + /* Perform our type-specific initialisation */ + a->specified = false; + a->owner = NULL; + a->schema_type_info = NULL; + a->is_id = false; + + *result = a; + + return DOM_NO_ERR; +} + /** * Retrieve an attribute's name * diff --git a/src/core/attr.h b/src/core/attr.h new file mode 100644 index 0000000..9605926 --- /dev/null +++ b/src/core/attr.h @@ -0,0 +1,20 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2007 John-Mark Bell + */ + +#ifndef dom_internal_core_attr_h_ +#define dom_internal_core_attr_h_ + +#include + +struct dom_document; +struct dom_attr; +struct dom_string; + +dom_exception dom_attr_create(struct dom_document *doc, + struct dom_string *name, struct dom_attr **result); + +#endif diff --git a/src/core/characterdata.c b/src/core/characterdata.c index bfcf6a1..61275b5 100644 --- a/src/core/characterdata.c +++ b/src/core/characterdata.c @@ -9,8 +9,67 @@ #include #include "core/characterdata.h" +#include "core/document.h" #include "utils/utils.h" +/** + * Create a character data node of the given type + * + * \param doc The owning document + * \param type The type of node to create + * \param name The node name, or NULL + * \param value The node value, or NULL + * \param result Pointer to location to receive created node + * \return DOM_NO_ERR on success, appropriate error otherwise + * + * ::doc, ::name and ::value will have their reference counts increased. + * + * The created node will already be referenced. + */ +dom_exception dom_characterdata_create(struct dom_document *doc, + dom_node_type type, struct dom_string *name, + struct dom_string *value, struct dom_characterdata **result) +{ + struct dom_characterdata *cdata; + dom_exception err; + + /* Allocate object */ + cdata = dom_document_alloc(doc, NULL, + sizeof(struct dom_characterdata)); + if (cdata == NULL) + return DOM_NO_MEM_ERR; + + /* Initialise node contents */ + err = dom_characterdata_initialise(cdata, doc, type, name, value); + if (err != DOM_NO_ERR) { + dom_document_alloc(doc, cdata, 0); + return err; + } + + *result = cdata; + + return DOM_NO_ERR; +} + +/** + * Initialise a character data node + * + * \param node The node to initialise + * \param doc The document which owns the node + * \param type The node type required + * \param name The node name, or NULL + * \param value The node value, or NULL + * \return DOM_NO_ERR on success. + * + * ::doc, ::name and ::value will have their reference counts increased. + */ +dom_exception dom_characterdata_initialise(struct dom_characterdata *cdata, + struct dom_document *doc, dom_node_type type, + struct dom_string *name, struct dom_string *value) +{ + return dom_node_initialise(&cdata->base, doc, type, name, value); +} + /** * Retrieve data from a character data node * diff --git a/src/core/characterdata.h b/src/core/characterdata.h index d6809c3..cde3969 100644 --- a/src/core/characterdata.h +++ b/src/core/characterdata.h @@ -17,4 +17,12 @@ struct dom_characterdata { struct dom_node base; /**< Base node */ }; +dom_exception dom_characterdata_create(struct dom_document *doc, + dom_node_type type, struct dom_string *name, + struct dom_string *value, struct dom_characterdata **result); + +dom_exception dom_characterdata_initialise(struct dom_characterdata *cdata, + struct dom_document *doc, dom_node_type type, + struct dom_string *name, struct dom_string *value); + #endif diff --git a/src/core/document.c b/src/core/document.c index 0552c22..b5a712e 100644 --- a/src/core/document.c +++ b/src/core/document.c @@ -9,13 +9,18 @@ #include #include +#include "core/attr.h" #include "core/characterdata.h" #include "core/document.h" +#include "core/element.h" #include "core/namednodemap.h" #include "core/node.h" #include "core/nodelist.h" +#include "core/text.h" #include "utils/utils.h" +struct dom_document_type; + /** * Item in list of active nodelists */ @@ -42,10 +47,15 @@ struct dom_doc_nnm { struct dom_document { struct dom_node base; /**< Base node */ + struct dom_document_type *type; /**< Associated doctype */ + struct dom_doc_nl *nodelists; /**< List of active nodelists */ struct dom_doc_nnm *maps; /**< List of active namednodemaps */ + /** Interned node name strings, indexed by node type */ + struct dom_string *nodenames[DOM_NODE_TYPE_COUNT]; + dom_alloc alloc; /**< Memory (de)allocation function */ void *pw; /**< Pointer to client data */ }; @@ -64,10 +74,12 @@ struct dom_document { dom_exception dom_document_get_doctype(struct dom_document *doc, struct dom_document_type **result) { - UNUSED(doc); - UNUSED(result); + if (doc->type != NULL) + dom_node_ref((struct dom_node *) doc->type); - return DOM_NOT_SUPPORTED_ERR; + *result = doc->type; + + return DOM_NO_ERR; } /** @@ -100,10 +112,20 @@ dom_exception dom_document_get_implementation(struct dom_document *doc, dom_exception dom_document_get_document_element(struct dom_document *doc, struct dom_element **result) { - UNUSED(doc); - UNUSED(result); + struct dom_node *root; - return DOM_NOT_SUPPORTED_ERR; + /* Find first element node in child list */ + for (root = doc->base.first_child; root != NULL; root = root->next) { + if (root->type == DOM_ELEMENT_NODE) + break; + } + + if (root != NULL) + dom_node_ref(root); + + *result = (struct dom_element *) root; + + return DOM_NO_ERR; } /** @@ -115,6 +137,8 @@ dom_exception dom_document_get_document_element(struct dom_document *doc, * \return DOM_NO_ERR on success, * DOM_INVALID_CHARACTER_ERR if ::tag_name is invalid. * + * ::doc and ::tag_name will have their reference counts increased. + * * The returned node will have its reference count increased. It is * the responsibility of the caller to unref the node once it has * finished with it. @@ -122,11 +146,7 @@ dom_exception dom_document_get_document_element(struct dom_document *doc, dom_exception dom_document_create_element(struct dom_document *doc, struct dom_string *tag_name, struct dom_element **result) { - UNUSED(doc); - UNUSED(tag_name); - UNUSED(result); - - return DOM_NOT_SUPPORTED_ERR; + return dom_element_create(doc, tag_name, result); } /** @@ -143,10 +163,9 @@ dom_exception dom_document_create_element(struct dom_document *doc, dom_exception dom_document_create_document_fragment(struct dom_document *doc, struct dom_node **result) { - UNUSED(doc); - UNUSED(result); - - return DOM_NOT_SUPPORTED_ERR; + return dom_node_create(doc, DOM_DOCUMENT_FRAGMENT_NODE, + doc->nodenames[DOM_DOCUMENT_FRAGMENT_NODE], + NULL, result); } /** @@ -164,11 +183,8 @@ dom_exception dom_document_create_document_fragment(struct dom_document *doc, dom_exception dom_document_create_text_node(struct dom_document *doc, struct dom_string *data, struct dom_text **result) { - UNUSED(doc); - UNUSED(data); - UNUSED(result); - - return DOM_NOT_SUPPORTED_ERR; + return dom_text_create(doc, DOM_TEXT_NODE, + doc->nodenames[DOM_TEXT_NODE], data, result); } /** @@ -186,11 +202,8 @@ dom_exception dom_document_create_text_node(struct dom_document *doc, dom_exception dom_document_create_comment(struct dom_document *doc, struct dom_string *data, struct dom_characterdata **result) { - UNUSED(doc); - UNUSED(data); - UNUSED(result); - - return DOM_NOT_SUPPORTED_ERR; + return dom_characterdata_create(doc, DOM_COMMENT_NODE, + doc->nodenames[DOM_COMMENT_NODE], data, result); } /** @@ -209,11 +222,9 @@ dom_exception dom_document_create_comment(struct dom_document *doc, dom_exception dom_document_create_cdata_section(struct dom_document *doc, struct dom_string *data, struct dom_text **result) { - UNUSED(doc); - UNUSED(data); - UNUSED(result); - - return DOM_NOT_SUPPORTED_ERR; + return dom_text_create(doc, DOM_CDATA_SECTION_NODE, + doc->nodenames[DOM_CDATA_SECTION_NODE], + data, result); } /** @@ -236,12 +247,10 @@ dom_exception dom_document_create_processing_instruction( struct dom_string *data, struct dom_node **result) { - UNUSED(doc); - UNUSED(target); - UNUSED(data); - UNUSED(result); + /** \todo is the use of target as the node name correct? */ - return DOM_NOT_SUPPORTED_ERR; + return dom_node_create(doc, DOM_PROCESSING_INSTRUCTION_NODE, + target, data, result); } /** @@ -260,11 +269,7 @@ dom_exception dom_document_create_processing_instruction( dom_exception dom_document_create_attribute(struct dom_document *doc, struct dom_string *name, struct dom_attr **result) { - UNUSED(doc); - UNUSED(name); - UNUSED(result); - - return DOM_NOT_SUPPORTED_ERR; + return dom_attr_create(doc, name, result); } /** @@ -284,11 +289,8 @@ dom_exception dom_document_create_attribute(struct dom_document *doc, dom_exception dom_document_create_entity_reference(struct dom_document *doc, struct dom_string *name, struct dom_node **result) { - UNUSED(doc); - UNUSED(name); - UNUSED(result); - - return DOM_NOT_SUPPORTED_ERR; + return dom_node_create(doc, DOM_ENTITY_REFERENCE_NODE, + name, NULL, result); } /** diff --git a/src/core/document.h b/src/core/document.h index 7238456..6561035 100644 --- a/src/core/document.h +++ b/src/core/document.h @@ -5,8 +5,8 @@ * Copyright 2007 John-Mark Bell */ -#ifndef dom_internal_document_h_ -#define dom_internal_document_h_ +#ifndef dom_internal_core_document_h_ +#define dom_internal_core_document_h_ #include #include diff --git a/src/core/element.c b/src/core/element.c index 57260cf..11b41a1 100644 --- a/src/core/element.c +++ b/src/core/element.c @@ -7,6 +7,8 @@ #include +#include "core/document.h" +#include "core/element.h" #include "core/node.h" #include "utils/utils.h" @@ -19,6 +21,49 @@ struct dom_element { struct dom_type_info *schema_type_info; /**< Type information */ }; +/** + * Create an element node + * + * \param doc The owning document + * \param name The name of the node to create + * \param result Pointer to location to receive created element + * \return DOM_NO_ERR on success, + * DOM_INVALID_CHARACTER_ERR if ::name is invalid, + * DOM_NO_MEM_ERR on memory exhaustion. + * + * ::doc and ::name will have their reference counts increased. + * + * The returned element will already be referenced. + */ +dom_exception dom_element_create(struct dom_document *doc, + struct dom_string *name, struct dom_element **result) +{ + struct dom_element *el; + dom_exception err; + + /** \todo Sanity check the tag name */ + + /* Allocate the element */ + el = dom_document_alloc(doc, NULL, sizeof(struct dom_element)); + if (el == NULL) + return DOM_NO_MEM_ERR; + + /* Initialise the base class */ + err = dom_node_initialise(&el->base, doc, DOM_ELEMENT_NODE, + name, NULL); + if (err != DOM_NO_ERR) { + dom_document_alloc(doc, el, 0); + return err; + } + + /* Perform our type-specific initialisation */ + el->schema_type_info = NULL; + + *result = el; + + return DOM_NO_ERR; +} + /** * Retrieve an element's tag name * diff --git a/src/core/element.h b/src/core/element.h new file mode 100644 index 0000000..69a0b04 --- /dev/null +++ b/src/core/element.h @@ -0,0 +1,20 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2007 John-Mark Bell + */ + +#ifndef dom_internal_core_element_h_ +#define dom_internal_core_element_h_ + +#include + +struct dom_document; +struct dom_element; +struct dom_string; + +dom_exception dom_element_create(struct dom_document *doc, + struct dom_string *name, struct dom_element **result); + +#endif diff --git a/src/core/namednodemap.h b/src/core/namednodemap.h index a2705e4..99b1a35 100644 --- a/src/core/namednodemap.h +++ b/src/core/namednodemap.h @@ -5,8 +5,8 @@ * Copyright 2007 John-Mark Bell */ -#ifndef dom_internal_namednodemap_h_ -#define dom_internal_namednodemap_h_ +#ifndef dom_internal_core_namednodemap_h_ +#define dom_internal_core_namednodemap_h_ #include diff --git a/src/core/node.c b/src/core/node.c index d4d0519..4f15617 100644 --- a/src/core/node.c +++ b/src/core/node.c @@ -5,6 +5,7 @@ * Copyright 2007 John-Mark Bell */ +#include #include #include "core/document.h" @@ -12,58 +13,108 @@ #include "utils/utils.h" /** - * Create a DOM node + * Create a DOM node of the given type * - * \param doc The document which owns the node - * \param type The node type required - * \param name The node name, or NULL - * \param value The node value, or NULL - * \param node Pointer to location to receive created node - * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion + * \param doc The owning document + * \param type The type of node to create + * \param name The node name, or NULL + * \param value The node value, or NULL + * \param result Pointer to location to receive created node + * \return DOM_NO_ERR on success, appropriate error otherwise + * + * ::doc, ::name and ::value will have their reference counts increased. * - * The returned node will be referenced, so there is no need for the caller - * to explicitly reference it. + * The created node will already be referenced. */ dom_exception dom_node_create(struct dom_document *doc, dom_node_type type, struct dom_string *name, struct dom_string *value, - struct dom_node **node) + struct dom_node **result) { - struct dom_node *n; + struct dom_node *node; + dom_exception err; + + /* If there's a type-specific constructor, use that */ + switch (type) { + case DOM_ELEMENT_NODE: + return dom_document_create_element(doc, name, + (struct dom_element **) result); + case DOM_ATTRIBUTE_NODE: + return dom_document_create_attribute(doc, name, + (struct dom_attr **) result); + case DOM_TEXT_NODE: + return dom_document_create_text_node(doc, value, + (struct dom_text **) result); + case DOM_CDATA_SECTION_NODE: + return dom_document_create_cdata_section(doc, value, + (struct dom_text **) result); + case DOM_COMMENT_NODE: + return dom_document_create_comment(doc, value, + (struct dom_characterdata **) result); + default: + break; + } - n = dom_document_alloc(doc, NULL, sizeof(struct dom_node)); - if (n == NULL) + /* Otherwise, this is a generic node, so build it ourselves */ + node = dom_document_alloc(doc, NULL, sizeof(struct dom_node)); + if (node == NULL) return DOM_NO_MEM_ERR; + /* Initialise node contents */ + err = dom_node_initialise(node, doc, type, name, value); + if (err != DOM_NO_ERR) { + dom_document_alloc(doc, node, 0); + return err; + } + + *result = node; + + return DOM_NO_ERR; +} + +/** + * Initialise a DOM node + * + * \param node The node to initialise + * \param doc The document which owns the node + * \param type The node type required + * \param name The node name, or NULL + * \param value The node value, or NULL + * \return DOM_NO_ERR on success. + * + * ::doc, ::name and ::value will have their reference counts increased. + */ +dom_exception dom_node_initialise(struct dom_node *node, + struct dom_document *doc, dom_node_type type, + struct dom_string *name, struct dom_string *value) +{ if (name != NULL) dom_string_ref(name); - n->name = name; + node->name = name; if (value != NULL) dom_string_ref(value); - n->value = value; + node->value = value; - n->type = type; + node->type = type; - n->parent = NULL; - n->first_child = NULL; - n->last_child = NULL; - n->previous = NULL; - n->next = NULL; - n->attributes = NULL; + node->parent = NULL; + node->first_child = NULL; + node->last_child = NULL; + node->previous = NULL; + node->next = NULL; + node->attributes = NULL; dom_node_ref((struct dom_node *) doc); - n->owner = doc; + node->owner = doc; /** \todo Namespace handling */ - n->namespace = NULL; - n->prefix = NULL; - n->localname = NULL; - - n->user_data = NULL; + node->namespace = NULL; + node->prefix = NULL; + node->localname = NULL; - n->refcnt = 1; + node->user_data = NULL; - *node = n; + node->refcnt = 1; return DOM_NO_ERR; } diff --git a/src/core/node.h b/src/core/node.h index d8982f6..6a72efd 100644 --- a/src/core/node.h +++ b/src/core/node.h @@ -54,6 +54,10 @@ struct dom_node { dom_exception dom_node_create(struct dom_document *doc, dom_node_type type, struct dom_string *name, struct dom_string *value, - struct dom_node **node); + struct dom_node **result); + +dom_exception dom_node_initialise(struct dom_node *node, + struct dom_document *doc, dom_node_type type, + struct dom_string *name, struct dom_string *value); #endif diff --git a/src/core/nodelist.h b/src/core/nodelist.h index 1e96f8d..e80c0ba 100644 --- a/src/core/nodelist.h +++ b/src/core/nodelist.h @@ -5,8 +5,8 @@ * Copyright 2007 John-Mark Bell */ -#ifndef dom_internal_nodelist_h_ -#define dom_internal_nodelist_h_ +#ifndef dom_internal_core_nodelist_h_ +#define dom_internal_core_nodelist_h_ #include diff --git a/src/core/text.c b/src/core/text.c index dd85bfe..5c2308a 100644 --- a/src/core/text.c +++ b/src/core/text.c @@ -9,8 +9,13 @@ #include #include "core/characterdata.h" +#include "core/document.h" +#include "core/text.h" #include "utils/utils.h" +/** + * A DOM text node + */ struct dom_text { struct dom_characterdata base; /**< Base node */ @@ -18,6 +23,48 @@ struct dom_text { * content whitespace */ }; +/** + * Create a text node + * + * \param doc The owning document + * \param type The type of text node to create + * \param name The name of the node to create + * \param value The text content of the node + * \param result Pointer to location to receive created node + * \return DOM_NO_ERR on success, + * DOM_NO_MEM_ERR on memory exhaustion. + * + * ::doc, ::name and ::value will have their reference counts increased. + * + * The returned node will already be referenced. + */ +dom_exception dom_text_create(struct dom_document *doc, dom_node_type type, + struct dom_string *name, struct dom_string *value, + struct dom_text **result) +{ + struct dom_text *t; + dom_exception err; + + /* Allocate the element */ + t = dom_document_alloc(doc, NULL, sizeof(struct dom_text)); + if (t == NULL) + return DOM_NO_MEM_ERR; + + /* Initialise the base class */ + err = dom_characterdata_initialise(&t->base, doc, type, name, value); + if (err != DOM_NO_ERR) { + dom_document_alloc(doc, t, 0); + return err; + } + + /* Perform our type-specific initialisation */ + t->element_content_whitespace = false; + + *result = t; + + return DOM_NO_ERR; +} + /** * Split a text node at a given character offset * diff --git a/src/core/text.h b/src/core/text.h new file mode 100644 index 0000000..97ab900 --- /dev/null +++ b/src/core/text.h @@ -0,0 +1,23 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2007 John-Mark Bell + */ + +#ifndef dom_internal_core_text_h_ +#define dom_internal_core_text_h_ + +#include + +#include "core/node.h" + +struct dom_document; +struct dom_string; +struct dom_text; + +dom_exception dom_text_create(struct dom_document *doc, dom_node_type type, + struct dom_string *name, struct dom_string *value, + struct dom_text **result); + +#endif -- cgit v1.2.3