From ddbf47a33aa4fba4ce23e751db78acf59895fcc3 Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Sat, 28 Jul 2007 20:41:41 +0000 Subject: Finalisation and destruction of nodes svn path=/trunk/dom/; revision=3467 --- src/core/attr.c | 47 ++++++++++++++++ src/core/attr.h | 1 + src/core/cdatasection.c | 18 ++++++ src/core/cdatasection.h | 3 + src/core/characterdata.c | 14 +++++ src/core/characterdata.h | 3 + src/core/comment.c | 18 ++++++ src/core/comment.h | 3 + src/core/doc_fragment.c | 42 ++++++++++++++ src/core/doc_fragment.h | 3 + src/core/document.c | 1 - src/core/element.c | 69 +++++++++++++++++++++++ src/core/element.h | 3 + src/core/entity_ref.c | 42 ++++++++++++++ src/core/entity_ref.h | 3 + src/core/node.c | 139 +++++++++++++++++++++++++++++++++++++++++++++-- src/core/node.h | 4 ++ src/core/pi.c | 18 ++++++ src/core/pi.h | 3 + src/core/text.c | 30 ++++++++++ src/core/text.h | 4 ++ 21 files changed, 463 insertions(+), 5 deletions(-) diff --git a/src/core/attr.c b/src/core/attr.c index ed20c93..ca6047a 100644 --- a/src/core/attr.c +++ b/src/core/attr.c @@ -79,6 +79,53 @@ dom_exception dom_attr_create(struct dom_document *doc, return DOM_NO_ERR; } +/** + * Destroy an attribute node + * + * \param doc The owning document + * \param attr The attribute to destroy + * + * The contents of ::attr will be destroyed and ::attr will be freed + */ +void dom_attr_destroy(struct dom_document *doc, struct dom_attr *attr) +{ + struct dom_node *c, *d; + + /* Destroy children of this node */ + for (c = attr->base.first_child; c != NULL; c = d) { + d = c->next; + + /* Detach child */ + c->parent = NULL; + + if (c->refcnt > 0) { + /* Something is using this child */ + + /** \todo add to list of nodes pending deletion */ + + continue; + } + + /* Detach from sibling list */ + c->previous = NULL; + c->next = NULL; + + dom_node_destroy(c); + } + + /* Now, clean up this node and destroy it */ + + if (attr->schema_type_info != NULL) { + /** \todo destroy schema type info */ + } + + attr->owner = NULL; + + dom_node_finalise(doc, &attr->base); + + dom_document_alloc(doc, attr, 0); +} + /** * Retrieve an attribute's name * diff --git a/src/core/attr.h b/src/core/attr.h index 9605926..dc73ae0 100644 --- a/src/core/attr.h +++ b/src/core/attr.h @@ -16,5 +16,6 @@ struct dom_string; dom_exception dom_attr_create(struct dom_document *doc, struct dom_string *name, struct dom_attr **result); +void dom_attr_destroy(struct dom_document *doc, struct dom_attr *attr); #endif diff --git a/src/core/cdatasection.c b/src/core/cdatasection.c index c477dd7..71d3d43 100644 --- a/src/core/cdatasection.c +++ b/src/core/cdatasection.c @@ -54,3 +54,21 @@ dom_exception dom_cdata_section_create(struct dom_document *doc, return DOM_NO_ERR; } + +/** + * Destroy a CDATA section + * + * \param doc The owning document + * \param cdata The cdata section to destroy + * + * The contents of ::cdata will be destroyed and ::cdata will be freed. + */ +void dom_cdata_section_destroy(struct dom_document *doc, + struct dom_cdata_section *cdata) +{ + /* Clean up base node contents */ + dom_text_finalise(doc, &cdata->base); + + /* Destroy the node */ + dom_document_alloc(doc, cdata, 0); +} diff --git a/src/core/cdatasection.h b/src/core/cdatasection.h index c53985b..740c7d7 100644 --- a/src/core/cdatasection.h +++ b/src/core/cdatasection.h @@ -18,4 +18,7 @@ dom_exception dom_cdata_section_create(struct dom_document *doc, struct dom_string *name, struct dom_string *value, struct dom_cdata_section **result); +void dom_cdata_section_destroy(struct dom_document *doc, + struct dom_cdata_section *cdata); + #endif diff --git a/src/core/characterdata.c b/src/core/characterdata.c index 7b38fd2..9cf3a49 100644 --- a/src/core/characterdata.c +++ b/src/core/characterdata.c @@ -31,6 +31,20 @@ dom_exception dom_characterdata_initialise(struct dom_characterdata *cdata, return dom_node_initialise(&cdata->base, doc, type, name, value); } +/** + * Finalise a character data node + * + * \param doc The owning document + * \param cdata The node to finalise + * + * The contents of ::cdata will be cleaned up. ::cdata will not be freed. + */ +void dom_characterdata_finalise(struct dom_document *doc, + struct dom_characterdata *cdata) +{ + dom_node_finalise(doc, &cdata->base); +} + /** * Retrieve data from a character data node * diff --git a/src/core/characterdata.h b/src/core/characterdata.h index 6a2b329..1351505 100644 --- a/src/core/characterdata.h +++ b/src/core/characterdata.h @@ -21,4 +21,7 @@ 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); +void dom_characterdata_finalise(struct dom_document *doc, + struct dom_characterdata *cdata); + #endif diff --git a/src/core/comment.c b/src/core/comment.c index e29edda..2e1c323 100644 --- a/src/core/comment.c +++ b/src/core/comment.c @@ -54,3 +54,21 @@ dom_exception dom_comment_create(struct dom_document *doc, return DOM_NO_ERR; } + +/** + * Destroy a comment node + * + * \param doc The owning document + * \param comment The node to destroy + * + * The contents of ::comment will be destroyed and ::comment will be freed + */ +void dom_comment_destroy(struct dom_document *doc, + struct dom_comment *comment) +{ + /* Finalise base class contents */ + dom_characterdata_finalise(doc, &comment->base); + + /* Free node */ + dom_document_alloc(doc, comment, 0); +} diff --git a/src/core/comment.h b/src/core/comment.h index 1cc7d28..38bb448 100644 --- a/src/core/comment.h +++ b/src/core/comment.h @@ -18,4 +18,7 @@ dom_exception dom_comment_create(struct dom_document *doc, struct dom_string *name, struct dom_string *value, struct dom_comment **result); +void dom_comment_destroy(struct dom_document *doc, + struct dom_comment *comment); + #endif diff --git a/src/core/doc_fragment.c b/src/core/doc_fragment.c index 0792467..eaef388 100644 --- a/src/core/doc_fragment.c +++ b/src/core/doc_fragment.c @@ -55,3 +55,45 @@ dom_exception dom_document_fragment_create(struct dom_document *doc, return DOM_NO_ERR; } + +/** + * Destroy a document fragment + * + * \param doc The owning document + * \param frag The document fragment to destroy + * + * The contents of ::frag will be destroyed and ::frag will be freed. + */ +void dom_document_fragment_destroy(struct dom_document *doc, + struct dom_document_fragment *frag) +{ + struct dom_node *c, *d; + + /* Destroy children of this node */ + for (c = frag->base.first_child; c != NULL; c = d) { + d = c->next; + + /* Detach child */ + c->parent = NULL; + + if (c->refcnt > 0) { + /* Something is using this child */ + + /** \todo add to list of nodes pending deletion */ + + continue; + } + + /* Detach from sibling list */ + c->previous = NULL; + c->next = NULL; + + dom_node_destroy(c); + } + + /* Finalise base class */ + dom_node_finalise(doc, &frag->base); + + /* Destroy fragment */ + dom_document_alloc(doc, frag, 0); +} diff --git a/src/core/doc_fragment.h b/src/core/doc_fragment.h index 9e27811..08e3422 100644 --- a/src/core/doc_fragment.h +++ b/src/core/doc_fragment.h @@ -18,4 +18,7 @@ dom_exception dom_document_fragment_create(struct dom_document *doc, struct dom_string *name, struct dom_string *value, struct dom_document_fragment **result); +void dom_document_fragment_destroy(struct dom_document *doc, + struct dom_document_fragment *frag); + #endif diff --git a/src/core/document.c b/src/core/document.c index 0495f59..ff9e5ec 100644 --- a/src/core/document.c +++ b/src/core/document.c @@ -15,7 +15,6 @@ #include "core/attr.h" #include "core/cdatasection.h" -#include "core/characterdata.h" #include "core/comment.h" #include "core/document.h" #include "core/doc_fragment.h" diff --git a/src/core/element.c b/src/core/element.c index 11b41a1..8c5ed6a 100644 --- a/src/core/element.c +++ b/src/core/element.c @@ -64,6 +64,75 @@ dom_exception dom_element_create(struct dom_document *doc, return DOM_NO_ERR; } +/** + * Destroy an element + * + * \param doc The owning document + * \param element The element to destroy + * + * The contents of ::element will be destroyed and ::element will be freed. + */ +void dom_element_destroy(struct dom_document *doc, + struct dom_element *element) +{ + struct dom_node *c, *d; + + /* Destroy children of this node */ + for (c = element->base.first_child; c != NULL; c = d) { + d = c->next; + + /* Detach child */ + c->parent = NULL; + + if (c->refcnt > 0) { + /* Something is using this child */ + + /** \todo add to list of nodes pending deletion */ + + continue; + } + + /* Detach from sibling list */ + c->previous = NULL; + c->next = NULL; + + dom_node_destroy(c); + } + + /* Destroy attributes attached to this node */ + for (c = (struct dom_node *) element->base.attributes; + c != NULL; c = d) { + d = c->next; + + /* Detach child */ + c->parent = NULL; + + if (c->refcnt > 0) { + /* Something is using this attribute */ + + /** \todo add to list of nodes pending deletion */ + + continue; + } + + /* Detach from sibling list */ + c->previous = NULL; + c->next = NULL; + + dom_node_destroy(c); + } + + if (element->schema_type_info != NULL) { + /** \todo destroy schema type info */ + } + + /* Finalise base class */ + dom_node_finalise(doc, &element->base); + + /* Free the element */ + dom_document_alloc(doc, element, 0); +} + /** * Retrieve an element's tag name * diff --git a/src/core/element.h b/src/core/element.h index 69a0b04..2a79997 100644 --- a/src/core/element.h +++ b/src/core/element.h @@ -17,4 +17,7 @@ struct dom_string; dom_exception dom_element_create(struct dom_document *doc, struct dom_string *name, struct dom_element **result); +void dom_element_destroy(struct dom_document *doc, + struct dom_element *element); + #endif diff --git a/src/core/entity_ref.c b/src/core/entity_ref.c index 7bc103e..8382249 100644 --- a/src/core/entity_ref.c +++ b/src/core/entity_ref.c @@ -55,3 +55,45 @@ dom_exception dom_entity_reference_create(struct dom_document *doc, return DOM_NO_ERR; } + +/** + * Destroy an entity reference + * + * \param doc The owning document + * \param entity The entity reference to destroy + * + * The contents of ::entity will be destroyed and ::entity will be freed. + */ +void dom_entity_reference_destroy(struct dom_document *doc, + struct dom_entity_reference *entity) +{ + struct dom_node *c, *d; + + /* Destroy children of this node */ + for (c = entity->base.first_child; c != NULL; c = d) { + d = c->next; + + /* Detach child */ + c->parent = NULL; + + if (c->refcnt > 0) { + /* Something is using this child */ + + /** \todo add to list of nodes pending deletion */ + + continue; + } + + /* Detach from sibling list */ + c->previous = NULL; + c->next = NULL; + + dom_node_destroy(c); + } + + /* Finalise base class */ + dom_node_finalise(doc, &entity->base); + + /* Destroy fragment */ + dom_document_alloc(doc, entity, 0); +} diff --git a/src/core/entity_ref.h b/src/core/entity_ref.h index b1f9dff..047ff30 100644 --- a/src/core/entity_ref.h +++ b/src/core/entity_ref.h @@ -18,4 +18,7 @@ dom_exception dom_entity_reference_create(struct dom_document *doc, struct dom_string *name, struct dom_string *value, struct dom_entity_reference **result); +void dom_entity_reference_destroy(struct dom_document *doc, + struct dom_entity_reference *entity); + #endif diff --git a/src/core/node.c b/src/core/node.c index 04a1230..db0fb05 100644 --- a/src/core/node.c +++ b/src/core/node.c @@ -8,10 +8,89 @@ #include #include +#include "core/attr.h" +#include "core/cdatasection.h" +#include "core/comment.h" #include "core/document.h" +#include "core/doc_fragment.h" +#include "core/element.h" +#include "core/entity_ref.h" #include "core/node.h" +#include "core/pi.h" +#include "core/text.h" #include "utils/utils.h" +/** + * Destroy a DOM node + * + * \param node The node to destroy + * + * ::node's parent link must be NULL and its reference count must be 0. + * + * ::node will be freed. + * + * This function should only be called from dom_node_unref or type-specific + * destructors (for destroying child nodes). Anything else should not + * be attempting to destroy nodes -- they should simply be unreferencing + * them (so destruction will occur at the appropriate time). + */ +void dom_node_destroy(struct dom_node *node) +{ + struct dom_document *owner = node->owner; + + /* This function simply acts as a central despatcher + * for type-specific destructors. It claims a reference upon the + * owning document during destruction to ensure that the document + * doesn't get destroyed before its contents. */ + + dom_node_ref((struct dom_node *) owner); + + switch (node->type) { + case DOM_ELEMENT_NODE: + dom_element_destroy(owner, (struct dom_element *) node); + break; + case DOM_ATTRIBUTE_NODE: + dom_attr_destroy(owner, (struct dom_attr *) node); + break; + case DOM_TEXT_NODE: + dom_text_destroy(owner, (struct dom_text *) node); + break; + case DOM_CDATA_SECTION_NODE: + dom_cdata_section_destroy(owner, + (struct dom_cdata_section *) node); + break; + case DOM_ENTITY_REFERENCE_NODE: + dom_entity_reference_destroy(owner, + (struct dom_entity_reference *) node); + break; + case DOM_ENTITY_NODE: + /** \todo entity node */ + break; + case DOM_PROCESSING_INSTRUCTION_NODE: + dom_processing_instruction_destroy(owner, + (struct dom_processing_instruction *) node); + break; + case DOM_COMMENT_NODE: + dom_comment_destroy(owner, (struct dom_comment *) node); + break; + case DOM_DOCUMENT_NODE: + /** \todo document node */ + break; + case DOM_DOCUMENT_TYPE_NODE: + /** \todo document type node */ + break; + case DOM_DOCUMENT_FRAGMENT_NODE: + dom_document_fragment_destroy(owner, + (struct dom_document_fragment *) node); + break; + case DOM_NOTATION_NODE: + /** \todo notation node */ + break; + } + + dom_node_unref((struct dom_node *) owner); +} + /** * Initialise a DOM node * @@ -60,6 +139,55 @@ dom_exception dom_node_initialise(struct dom_node *node, return DOM_NO_ERR; } +/** + * Finalise a DOM node + * + * \param doc The owning document + * \param node The node to finalise + * + * The contents of ::node will be cleaned up. ::node will not be freed. + * All children of ::node should have been removed prior to finalisation. + */ +void dom_node_finalise(struct dom_document *doc, struct dom_node *node) +{ + struct dom_user_data *u, *v; + + /* Destroy user data */ + for (u = node->user_data; u != NULL; u = v) { + v = u->next; + + dom_string_unref(u->key); + + dom_document_alloc(doc, u, 0); + } + + if (node->localname != NULL) + dom_string_unref(node->localname); + + if (node->prefix != NULL) + dom_string_unref(node->prefix); + + if (node->namespace != NULL) + dom_string_unref(node->namespace); + + dom_node_unref((struct dom_node *) node->owner); + node->owner = NULL; + + /* Paranoia */ + node->attributes = NULL; + node->next = NULL; + node->previous = NULL; + node->last_child = NULL; + node->first_child = NULL; + node->parent = NULL; + + if (node->value != NULL) + dom_string_unref(node->value); + + if (node->name != NULL) + dom_string_unref(node->name); +} + /** * Claim a reference on a DOM node * @@ -75,13 +203,16 @@ void dom_node_ref(struct dom_node *node) * * \param node The node to release the reference from * - * If the reference count reaches zero, any memory claimed by the - * node will be released + * If the reference count reaches zero and the node is not part of any + * document, any memory claimed by the node will be released. */ void dom_node_unref(struct dom_node *node) { - if (--node->refcnt == 0) { - /** \todo implement */ + if (node->refcnt > 0) + node->refcnt--; + + if (node->refcnt == 0 && node->parent == NULL) { + dom_node_destroy(node); } } diff --git a/src/core/node.h b/src/core/node.h index 168d2ec..beee0bd 100644 --- a/src/core/node.h +++ b/src/core/node.h @@ -52,8 +52,12 @@ struct dom_node { uint32_t refcnt; /**< Reference count */ }; +void dom_node_destroy(struct dom_node *node); + 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); +void dom_node_finalise(struct dom_document *doc, struct dom_node *node); + #endif diff --git a/src/core/pi.c b/src/core/pi.c index 55e85f7..c2b6cc9 100644 --- a/src/core/pi.c +++ b/src/core/pi.c @@ -56,3 +56,21 @@ dom_exception dom_processing_instruction_create(struct dom_document *doc, return DOM_NO_ERR; } + +/** + * Destroy a processing instruction + * + * \param doc The owning document + * \param pi The processing instruction to destroy + * + * The contents of ::pi will be destroyed and ::pi will be freed. + */ +void dom_processing_instruction_destroy(struct dom_document *doc, + struct dom_processing_instruction *pi) +{ + /* Finalise base class */ + dom_node_finalise(doc, &pi->base); + + /* Free processing instruction */ + dom_document_alloc(doc, pi, 0); +} diff --git a/src/core/pi.h b/src/core/pi.h index 1d7560f..4dca989 100644 --- a/src/core/pi.h +++ b/src/core/pi.h @@ -18,4 +18,7 @@ dom_exception dom_processing_instruction_create(struct dom_document *doc, struct dom_string *name, struct dom_string *value, struct dom_processing_instruction **result); +void dom_processing_instruction_destroy(struct dom_document *doc, + struct dom_processing_instruction *pi); + #endif diff --git a/src/core/text.c b/src/core/text.c index 05e2b7d..ec94311 100644 --- a/src/core/text.c +++ b/src/core/text.c @@ -51,6 +51,23 @@ dom_exception dom_text_create(struct dom_document *doc, return DOM_NO_ERR; } +/** + * Destroy a text node + * + * \param doc The owning document + * \param text The text node to destroy + * + * The contents of ::text will be destroyed and ::text will be freed. + */ +void dom_text_destroy(struct dom_document *doc, struct dom_text *text) +{ + /* Finalise node */ + dom_text_finalise(doc, text); + + /* Free node */ + dom_document_alloc(doc, text, 0); +} + /** * Initialise a text node * @@ -81,6 +98,19 @@ dom_exception dom_text_initialise(struct dom_text *text, return DOM_NO_ERR; } +/** + * Finalise a text node + * + * \param doc The owning document + * \param text The text node to finalise + * + * The contents of ::text will be cleaned up. ::text will not be freed. + */ +void dom_text_finalise(struct dom_document *doc, struct dom_text *text) +{ + dom_characterdata_finalise(doc, &text->base); +} + /** * Split a text node at a given character offset * diff --git a/src/core/text.h b/src/core/text.h index be927df..7af0f76 100644 --- a/src/core/text.h +++ b/src/core/text.h @@ -31,8 +31,12 @@ dom_exception dom_text_create(struct dom_document *doc, struct dom_string *name, struct dom_string *value, struct dom_text **result); +void dom_text_destroy(struct dom_document *doc, struct dom_text *text); + dom_exception dom_text_initialise(struct dom_text *text, struct dom_document *doc, dom_node_type type, struct dom_string *name, struct dom_string *value); +void dom_text_finalise(struct dom_document *doc, struct dom_text *text); + #endif -- cgit v1.2.3