diff options
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/Makefile | 2 | ||||
-rw-r--r-- | src/core/attr.c | 4 | ||||
-rw-r--r-- | src/core/cdatasection.c | 2 | ||||
-rw-r--r-- | src/core/characterdata.c | 2 | ||||
-rw-r--r-- | src/core/characterdata.h | 2 | ||||
-rw-r--r-- | src/core/comment.c | 2 | ||||
-rw-r--r-- | src/core/doc_fragment.c | 4 | ||||
-rw-r--r-- | src/core/document.c | 4 | ||||
-rw-r--r-- | src/core/document_type.c | 4 | ||||
-rw-r--r-- | src/core/element.c | 33 | ||||
-rw-r--r-- | src/core/element.h | 2 | ||||
-rw-r--r-- | src/core/entity_ref.c | 4 | ||||
-rw-r--r-- | src/core/node.c | 27 | ||||
-rw-r--r-- | src/core/node.h | 6 | ||||
-rw-r--r-- | src/core/pi.c | 4 | ||||
-rw-r--r-- | src/core/text.c | 4 | ||||
-rw-r--r-- | src/core/text.h | 2 | ||||
-rw-r--r-- | src/core/tokenlist.c | 547 | ||||
-rw-r--r-- | src/core/tokenlist.h | 18 |
19 files changed, 632 insertions, 41 deletions
diff --git a/src/core/Makefile b/src/core/Makefile index 41fd51f..5d9c969 100644 --- a/src/core/Makefile +++ b/src/core/Makefile @@ -6,6 +6,6 @@ DIR_SOURCES := \ text.c typeinfo.c comment.c \ namednodemap.c nodelist.c \ cdatasection.c document_type.c entity_ref.c pi.c \ - doc_fragment.c document.c + doc_fragment.c document.c tokenlist.c include $(NSBUILD)/Makefile.subdir diff --git a/src/core/attr.c b/src/core/attr.c index e18e2a7..8fcaac3 100644 --- a/src/core/attr.c +++ b/src/core/attr.c @@ -49,7 +49,7 @@ struct dom_attr { }; /* The vtable for dom_attr node */ -static struct dom_attr_vtable attr_vtable = { +static const struct dom_attr_vtable attr_vtable = { { { DOM_NODE_EVENT_TARGET_VTABLE, @@ -60,7 +60,7 @@ static struct dom_attr_vtable attr_vtable = { }; /* The protected vtable for dom_attr */ -static struct dom_node_protect_vtable attr_protect_vtable = { +static const struct dom_node_protect_vtable attr_protect_vtable = { DOM_ATTR_PROTECT_VTABLE }; diff --git a/src/core/cdatasection.c b/src/core/cdatasection.c index c6812e3..efba237 100644 --- a/src/core/cdatasection.c +++ b/src/core/cdatasection.c @@ -20,7 +20,7 @@ struct dom_cdata_section { dom_text base; /**< Base node */ }; -static struct dom_node_protect_vtable cdata_section_protect_vtable = { +static const struct dom_node_protect_vtable cdata_section_protect_vtable = { DOM_CDATA_SECTION_PROTECT_VTABLE }; diff --git a/src/core/characterdata.c b/src/core/characterdata.c index ea665b3..e6f5dbe 100644 --- a/src/core/characterdata.c +++ b/src/core/characterdata.c @@ -21,7 +21,7 @@ /* The virtual functions for dom_characterdata, we make this vtable * public to each child class */ -struct dom_characterdata_vtable characterdata_vtable = { +const struct dom_characterdata_vtable characterdata_vtable = { { { DOM_NODE_EVENT_TARGET_VTABLE diff --git a/src/core/characterdata.h b/src/core/characterdata.h index 0b0889c..c8f4db3 100644 --- a/src/core/characterdata.h +++ b/src/core/characterdata.h @@ -116,7 +116,7 @@ dom_exception _dom_characterdata_copy(dom_node_internal *old, _dom_characterdata_destroy, \ _dom_characterdata_copy -extern struct dom_characterdata_vtable characterdata_vtable; +extern const struct dom_characterdata_vtable characterdata_vtable; dom_exception _dom_characterdata_copy_internal(dom_characterdata *old, dom_characterdata *new); diff --git a/src/core/comment.c b/src/core/comment.c index 0697826..b36a1be 100644 --- a/src/core/comment.c +++ b/src/core/comment.c @@ -21,7 +21,7 @@ struct dom_comment { dom_characterdata base; /**< Base node */ }; -static struct dom_node_protect_vtable comment_protect_vtable = { +static const struct dom_node_protect_vtable comment_protect_vtable = { DOM_COMMENT_PROTECT_VTABLE }; diff --git a/src/core/doc_fragment.c b/src/core/doc_fragment.c index 96cc707..9e10a1a 100644 --- a/src/core/doc_fragment.c +++ b/src/core/doc_fragment.c @@ -22,14 +22,14 @@ struct dom_document_fragment { dom_node_internal base; /**< Base node */ }; -static struct dom_node_vtable df_vtable = { +static const struct dom_node_vtable df_vtable = { { DOM_NODE_EVENT_TARGET_VTABLE }, DOM_NODE_VTABLE }; -static struct dom_node_protect_vtable df_protect_vtable = { +static const struct dom_node_protect_vtable df_protect_vtable = { DOM_DF_PROTECT_VTABLE }; diff --git a/src/core/document.c b/src/core/document.c index 7c0bcdc..40d4cd9 100644 --- a/src/core/document.c +++ b/src/core/document.c @@ -42,7 +42,7 @@ struct dom_doc_nl { }; /* The virtual functions of this dom_document */ -static struct dom_document_vtable document_vtable = { +static const struct dom_document_vtable document_vtable = { { { DOM_NODE_EVENT_TARGET_VTABLE @@ -52,7 +52,7 @@ static struct dom_document_vtable document_vtable = { DOM_DOCUMENT_VTABLE }; -static struct dom_node_protect_vtable document_protect_vtable = { +static const struct dom_node_protect_vtable document_protect_vtable = { DOM_DOCUMENT_PROTECT_VTABLE }; diff --git a/src/core/document_type.c b/src/core/document_type.c index d7b1b99..a0fafdd 100644 --- a/src/core/document_type.c +++ b/src/core/document_type.c @@ -27,7 +27,7 @@ struct dom_document_type { dom_string *system_id; /**< Doctype system ID */ }; -static struct dom_document_type_vtable document_type_vtable = { +static const struct dom_document_type_vtable document_type_vtable = { { { DOM_NODE_EVENT_TARGET_VTABLE @@ -37,7 +37,7 @@ static struct dom_document_type_vtable document_type_vtable = { DOM_DOCUMENT_TYPE_VTABLE }; -static struct dom_node_protect_vtable dt_protect_vtable = { +static const struct dom_node_protect_vtable dt_protect_vtable = { DOM_DT_PROTECT_VTABLE }; diff --git a/src/core/element.c b/src/core/element.c index 1dae60a..05dc8c6 100644 --- a/src/core/element.c +++ b/src/core/element.c @@ -32,7 +32,7 @@ #include "utils/list.h" #include "events/mutation_event.h" -struct dom_element_vtable _dom_element_vtable = { +const struct dom_element_vtable _dom_element_vtable = { { { DOM_NODE_EVENT_TARGET_VTABLE @@ -42,7 +42,7 @@ struct dom_element_vtable _dom_element_vtable = { DOM_ELEMENT_VTABLE }; -static struct dom_element_protected_vtable element_protect_vtable = { +static const struct dom_element_protected_vtable element_protect_vtable = { { DOM_NODE_PROTECT_VTABLE_ELEMENT }, @@ -1232,9 +1232,11 @@ dom_exception _dom_element_has_class(struct dom_element *element, /** * Get a named ancestor node * + * The caller is responsible for unreffing the returned node. + * * \param element Element to consider * \param name Node name to look for - * \param ancestor Pointer to location to receive node pointer + * \param ancestor Pointer to location to receive node. * \return DOM_NO_ERR. */ dom_exception dom_element_named_ancestor_node(dom_element *element, @@ -1251,7 +1253,7 @@ dom_exception dom_element_named_ancestor_node(dom_element *element, assert(node->name != NULL); if (dom_string_caseless_lwc_isequal(node->name, name)) { - *ancestor = (dom_element *)node; + *ancestor = (dom_element *)dom_node_ref(node); break; } } @@ -1262,6 +1264,8 @@ dom_exception dom_element_named_ancestor_node(dom_element *element, /** * Get a named parent node * + * The caller is responsible for unreffing the returned node. + * * \param element Element to consider * \param name Node name to look for * \param parent Pointer to location to receive node pointer @@ -1281,7 +1285,7 @@ dom_exception dom_element_named_parent_node(dom_element *element, assert(node->name != NULL); if (dom_string_caseless_lwc_isequal(node->name, name)) { - *parent = (dom_element *)node; + *parent = (dom_element *)dom_node_ref(node); } break; } @@ -1292,6 +1296,8 @@ dom_exception dom_element_named_parent_node(dom_element *element, /** * Get a named parent node * + * The caller is responsible for unreffing the returned node. + * * \param element Element to consider * \param name Node name to look for * \param parent Pointer to location to receive node pointer @@ -1308,7 +1314,7 @@ dom_exception dom_element_parent_node(dom_element *element, if (node->type != DOM_ELEMENT_NODE) continue; - *parent = (dom_element *)node; + *parent = (dom_element *)dom_node_ref(node); break; } @@ -1414,7 +1420,12 @@ dom_exception _dom_element_is_default_namespace(dom_node_internal *node, return DOM_NO_ERR; } - return dom_node_is_default_namespace(node->parent, namespace, result); + if (node->parent != NULL) { + return dom_node_is_default_namespace(node->parent, namespace, result); + } else { + *result = false; + } + return DOM_NO_ERR; } /** @@ -1661,13 +1672,13 @@ dom_exception _dom_element_set_attr(struct dom_element *element, if (err != DOM_NO_ERR) return err; - success = true; - err = _dom_dispatch_subtree_modified_event(doc, - (dom_event_target *) e, &success); + err = dom_attr_set_value(match->attr, value); if (err != DOM_NO_ERR) return err; - err = dom_attr_set_value(match->attr, value); + success = true; + err = _dom_dispatch_subtree_modified_event(doc, + (dom_event_target *) e, &success); if (err != DOM_NO_ERR) return err; } else { diff --git a/src/core/element.h b/src/core/element.h index c89ddc0..fb946b7 100644 --- a/src/core/element.h +++ b/src/core/element.h @@ -238,6 +238,6 @@ dom_exception _dom_element_copy_internal(dom_element *old, dom_exception _dom_element_get_id(struct dom_element *ele, dom_string **id); -extern struct dom_element_vtable _dom_element_vtable; +extern const struct dom_element_vtable _dom_element_vtable; #endif diff --git a/src/core/entity_ref.c b/src/core/entity_ref.c index aa32111..bc6fbab 100644 --- a/src/core/entity_ref.c +++ b/src/core/entity_ref.c @@ -20,14 +20,14 @@ struct dom_entity_reference { dom_node_internal base; /**< Base node */ }; -static struct dom_node_vtable er_vtable = { +static const struct dom_node_vtable er_vtable = { { DOM_NODE_EVENT_TARGET_VTABLE }, DOM_NODE_VTABLE }; -static struct dom_node_protect_vtable er_protect_vtable = { +static const struct dom_node_protect_vtable er_protect_vtable = { DOM_ER_PROTECT_VTABLE }; diff --git a/src/core/node.c b/src/core/node.c index 87ad837..1218742 100644 --- a/src/core/node.c +++ b/src/core/node.c @@ -55,14 +55,14 @@ static inline dom_exception _dom_node_detach_range(dom_node_internal *first, static inline void _dom_node_replace(dom_node_internal *old, dom_node_internal *replacement); -static struct dom_node_vtable node_vtable = { +static const struct dom_node_vtable node_vtable = { { DOM_NODE_EVENT_TARGET_VTABLE }, DOM_NODE_VTABLE }; -static struct dom_node_protect_vtable node_protect_vtable = { +static const struct dom_node_protect_vtable node_protect_vtable = { DOM_NODE_PROTECT_VTABLE }; @@ -1827,8 +1827,8 @@ dom_exception _dom_node_set_user_data(dom_node_internal *node, * \param result Pointer to location to receive result * \return DOM_NO_ERR. */ -dom_exception _dom_node_get_user_data(dom_node_internal *node, - dom_string *key, void **result) +dom_exception _dom_node_get_user_data(const dom_node_internal *node, + const dom_string *key, void **result) { struct dom_user_data *ud = NULL; @@ -2172,7 +2172,9 @@ dom_exception _dom_node_detach_range(dom_node_internal *first, * * This is not implemented in terms of attach/detach in case * we want to perform any special replacement-related behaviour - * at a later date. + * at a later date. If the replacement is essentially empty (either NULL + * or an empty document fragment node) then this essentially just removes + * the old node from its parent. It is up to the caller to deal with that. */ void _dom_node_replace(dom_node_internal *old, dom_node_internal *replacement) @@ -2190,6 +2192,19 @@ void _dom_node_replace(dom_node_internal *old, last = replacement; } + if (first == NULL) { + /* All we're doing is removing old */ + if (old->previous == NULL) { + old->parent->first_child = old->next; + } + if (old->next == NULL) { + old->parent->last_child = old->previous; + } + old->previous = old->next = old->parent = NULL; + return; + } + + /* We're replacing old with first-to-last */ first->previous = old->previous; last->next = old->next; @@ -2203,7 +2218,7 @@ void _dom_node_replace(dom_node_internal *old, else old->parent->last_child = last; - for (n = first; n != last->next; n = n->next) { + for (n = first; n != NULL && n != last->next; n = n->next) { n->parent = old->parent; } diff --git a/src/core/node.h b/src/core/node.h index 87f3cb3..36cdd7d 100644 --- a/src/core/node.h +++ b/src/core/node.h @@ -53,7 +53,7 @@ typedef struct dom_node_protect_vtable { */ struct dom_node_internal { struct dom_node base; /**< The vtable base */ - void *vtable; /**< The protected vtable */ + const void *vtable; /**< The protected vtable */ dom_string *name; /**< Node name (this is the local part * of a QName in the cases where a @@ -182,8 +182,8 @@ dom_exception _dom_node_get_feature(dom_node_internal *node, dom_exception _dom_node_set_user_data(dom_node_internal *node, dom_string *key, void *data, dom_user_data_handler handler, void **result); -dom_exception _dom_node_get_user_data(dom_node_internal *node, - dom_string *key, void **result); +dom_exception _dom_node_get_user_data(const dom_node_internal *node, + const dom_string *key, void **result); #define DOM_NODE_EVENT_TARGET_VTABLE \ _dom_node_add_event_listener, \ diff --git a/src/core/pi.c b/src/core/pi.c index d12f109..3e69841 100644 --- a/src/core/pi.c +++ b/src/core/pi.c @@ -20,14 +20,14 @@ struct dom_processing_instruction { dom_node_internal base; /**< Base node */ }; -static struct dom_node_vtable pi_vtable = { +static const struct dom_node_vtable pi_vtable = { { DOM_NODE_EVENT_TARGET_VTABLE }, DOM_NODE_VTABLE }; -static struct dom_node_protect_vtable pi_protect_vtable = { +static const struct dom_node_protect_vtable pi_protect_vtable = { DOM_PI_PROTECT_VTABLE }; /** diff --git a/src/core/text.c b/src/core/text.c index b73e86d..f63fabe 100644 --- a/src/core/text.c +++ b/src/core/text.c @@ -20,7 +20,7 @@ #include "utils/utils.h" /* The virtual table for dom_text */ -struct dom_text_vtable text_vtable = { +const struct dom_text_vtable text_vtable = { { { { @@ -33,7 +33,7 @@ struct dom_text_vtable text_vtable = { DOM_TEXT_VTABLE }; -static struct dom_node_protect_vtable text_protect_vtable = { +static const struct dom_node_protect_vtable text_protect_vtable = { DOM_TEXT_PROTECT_VTABLE }; diff --git a/src/core/text.h b/src/core/text.h index 26424ce..3f5739b 100644 --- a/src/core/text.h +++ b/src/core/text.h @@ -66,7 +66,7 @@ dom_exception _dom_text_copy(dom_node_internal *old, dom_node_internal **copy); __dom_text_destroy, \ _dom_text_copy -extern struct dom_text_vtable text_vtable; +extern const struct dom_text_vtable text_vtable; dom_exception _dom_text_copy_internal(dom_text *old, dom_text *new); #define dom_text_copy_internal(o, n) \ diff --git a/src/core/tokenlist.c b/src/core/tokenlist.c new file mode 100644 index 0000000..cc93a8c --- /dev/null +++ b/src/core/tokenlist.c @@ -0,0 +1,547 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2022 Daniel Silverstone <dsilvers@digital-scurf.org> + */ + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include <dom/core/element.h> +#include <dom/core/nodelist.h> +#include <dom/core/tokenlist.h> +#include <dom/core/string.h> +#include <dom/events/event.h> +#include <dom/events/event_target.h> +#include <dom/events/event_listener.h> +#include <dom/events/mutation_event.h> + +#include "core/element.h" +#include "core/document.h" + +#include "utils/utils.h" + +#define DOM_TOKENLIST_GROW_INCREMENT 4 + +struct dom_tokenlist { + uint32_t refcnt; + dom_element *ele; + dom_string *attr; + dom_event_listener *listener; + dom_string *last_set; + bool needs_parse; + /* Parsed content, for optimal access */ + dom_string **entries; + uint32_t len; + uint32_t alloc; +}; + +/* Handle a DOMAttrModified event which might be to do with our attribute */ + +static void _dom_tokenlist_handle_attrmodified(dom_event *evt, void *pw) +{ + dom_mutation_event *mutevt = (dom_mutation_event *)evt; + dom_tokenlist *list = (dom_tokenlist *)pw; + dom_exception exc; + dom_string *value; + + { + dom_event_target *target; + exc = dom_event_get_target(evt, &target); + if (exc != DOM_NO_ERR) + return; + dom_node_unref(target); + if (target != (dom_event_target *)list->ele) + return; + } + + { + dom_string *attr; + exc = dom_mutation_event_get_attr_name(mutevt, &attr); + if (exc != DOM_NO_ERR) + return; + if (!dom_string_isequal(attr, list->attr)) { + dom_string_unref(attr); + return; + } + dom_string_unref(attr); + } + + /* At this point we know that this is a mutation of our attribute on our + * node */ + + exc = dom_mutation_event_get_new_value(mutevt, &value); + if (exc != DOM_NO_ERR) + return; + + if (list->last_set != NULL && + dom_string_isequal(list->last_set, value)) { + /* We've just seen the mutation event for one of our own set + * operations */ + dom_string_unref(value); + return; + } + + /* Mark that we need to re-parse the tokenlist on the next request */ + list->needs_parse = true; + + dom_string_unref(value); +} + +static dom_exception _dom_tokenlist_make_room(dom_tokenlist *list) +{ + if (list->len == list->alloc) { + uint32_t new_alloc = list->alloc + DOM_TOKENLIST_GROW_INCREMENT; + dom_string **new_entries = realloc( + list->entries, new_alloc * sizeof(dom_string *)); + if (new_entries == NULL) + return DOM_NO_MEM_ERR; + list->alloc = new_alloc; + list->entries = new_entries; + } + + return DOM_NO_ERR; +} + +static dom_exception _dom_tokenlist_reparse(dom_tokenlist *list) +{ + dom_exception exc; + dom_string *value; + const char *pos; + uint32_t remaining, check; + uint32_t n_entries = 0; + dom_string *temp; + bool found; + + if (!list->needs_parse) + return DOM_NO_ERR; + + /* Clean down the current entries */ + while (list->len-- > 0) + dom_string_unref(list->entries[list->len]); + list->len = 0; + + /* Get the "new" attribute value */ + exc = dom_element_get_attribute(list->ele, list->attr, &value); + if (exc != DOM_NO_ERR) + return exc; + + /* If there is no value, we're an empty list and we're done */ + if (value == NULL) { + list->needs_parse = false; + return DOM_NO_ERR; + } + + /* OK, there's something here to do, so let's do it... */ + + /* Count number of entries */ + for (pos = dom_string_data(value), remaining = dom_string_length(value); + remaining > 0;) { + if (*pos != ' ') { + while (*pos != ' ' && remaining > 0) { + remaining--; + pos++; + } + n_entries++; + } else { + while (*pos == ' ' && remaining > 0) { + remaining--; + pos++; + } + } + } + + /* If there are no entries (all whitespace) just bail here */ + if (n_entries == 0) { + list->needs_parse = false; + dom_string_unref(value); + return DOM_NO_ERR; + } + + /* If we need more room, reallocate the buffer */ + if (list->alloc < n_entries) { + dom_string **new_alloc = realloc( + list->entries, n_entries * sizeof(dom_string *)); + if (new_alloc == NULL) { + dom_string_unref(value); + return DOM_NO_MEM_ERR; + } + list->entries = new_alloc; + list->alloc = n_entries; + } + + /* And now parse those entries into the buffer */ + for (pos = dom_string_data(value), + remaining = dom_string_length(value), + n_entries = 0; + remaining > 0;) { + if (*pos != ' ') { + const char *s = pos; + while (*pos != ' ' && remaining > 0) { + pos++; + remaining--; + } + exc = dom_string_create_interned((const uint8_t *)s, + pos - s, + &temp); + if (exc != DOM_NO_ERR) { + dom_string_unref(value); + return exc; + } + found = false; + for (check = 0; check < list->len; check++) { + if (dom_string_isequal(temp, + list->entries[check])) { + found = true; + break; + } + } + if (found == true) { + dom_string_unref(temp); + } else { + list->entries[list->len] = temp; + list->len++; + } + } else { + while (*pos == ' ' && remaining > 0) { + pos++; + remaining--; + } + } + } + + dom_string_unref(value); + list->needs_parse = false; + + return DOM_NO_ERR; +} + +static dom_exception _dom_tokenlist_reify(dom_tokenlist *list) +{ + dom_exception exc; + uint32_t nchars = 0, n; + char *buffer, *next; + dom_string *output; + + if (list->len == 0) { + if (list->last_set != NULL) { + dom_string_unref(list->last_set); + } + list->last_set = dom_string_ref( + list->ele->base.owner->_memo_empty); + return dom_element_set_attribute(list->ele, + list->attr, + list->last_set); + } + + for (n = 0; n < list->len; ++n) + nchars += dom_string_length(list->entries[n]); + + buffer = calloc(1, nchars + list->len); + if (buffer == NULL) + return DOM_NO_MEM_ERR; + + for (next = buffer, n = 0; n < list->len; ++n) { + uint32_t slen = dom_string_length(list->entries[n]); + memcpy(next, dom_string_data(list->entries[n]), slen); + next[slen] = ' '; + next += slen + 1; + } + + exc = dom_string_create_interned((const uint8_t *)buffer, + nchars + list->len - 1, + &output); + free(buffer); + if (exc != DOM_NO_ERR) + return exc; + + if (list->last_set != NULL) { + dom_string_unref(list->last_set); + } + list->last_set = output; + + return dom_element_set_attribute(list->ele, list->attr, list->last_set); +} + +/**********************************************************************************/ + +/** + * Create a tokenlist + * + * \param ele The element which owns the tokenlist attribute + * \param attr The name of the attribute we are treating as a tokenlist + * \param list The tokenlist output which is set on success + * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion + * + * The returned list will already be referenced, so the client need not + * do so explicitly. The client must unref the list once finished with it. + * + * This list will take its own references to ::ele and ::attr + */ +dom_exception +dom_tokenlist_create(dom_element *ele, dom_string *attr, dom_tokenlist **list) +{ + dom_tokenlist *l; + dom_exception exc; + + l = calloc(1, sizeof(dom_tokenlist)); + if (l == NULL) + return DOM_NO_MEM_ERR; + + l->refcnt = 1; + l->ele = (dom_element *)dom_node_ref(ele); + l->attr = dom_string_ref(attr); + l->needs_parse = true; + + exc = dom_event_listener_create(_dom_tokenlist_handle_attrmodified, + l, + &l->listener); + if (exc != DOM_NO_ERR) + goto fail; + + exc = dom_event_target_add_event_listener( + ele, + ele->base.owner->_memo_domattrmodified, + l->listener, + false); + + if (exc != DOM_NO_ERR) + goto fail; + + *list = l; + + return DOM_NO_ERR; + +fail: + if (l->listener != NULL) + dom_event_listener_unref(l->listener); + dom_node_unref(l->ele); + dom_string_unref(l->attr); + free(l); + return exc; +} + +/** + * Claim a ref on a tokenlist + * + * \param list The tokenlist to claim a ref on + */ +void dom_tokenlist_ref(dom_tokenlist *list) +{ + assert(list != NULL); + list->refcnt++; +} + +/** + * Release a ref on a tokenlist + * + * \param list The list to release the reference of + * + * If you release the last ref, this cleans up the tokenlist + */ +void dom_tokenlist_unref(dom_tokenlist *list) +{ + assert(list != NULL); + + if (--list->refcnt > 0) + return; + + if (list->alloc > 0) { + while (list->len-- > 0) + dom_string_unref(list->entries[list->len]); + free(list->entries); + } + + dom_event_target_remove_event_listener( + list->ele, + list->ele->base.owner->_memo_domattrmodified, + list->listener, + false); + + dom_event_listener_unref(list->listener); + + if (list->last_set != NULL) + dom_string_unref(list->last_set); + + dom_string_unref(list->attr); + dom_node_unref(list->ele); + + free(list); +} + +/** + * Get the length of the tokenlist + * + * \param list The list to get the length of + * \param length Length of the list outputs here + * \return DOM_NO_ERR on success, otherwise the failure code + */ +dom_exception dom_tokenlist_get_length(dom_tokenlist *list, uint32_t *length) +{ + dom_exception exc; + assert(list != NULL); + + exc = _dom_tokenlist_reparse(list); + if (exc != DOM_NO_ERR) + return exc; + + *length = list->len; + + return DOM_NO_ERR; +} + +/** + * Get a particular item from the tokenlist + * + * \param list The list to retrieve the item from + * \param index The index of the item to retrieve + * \param value The value of the item returns here + * \return DOM_NO_ERR on success, otherwise the failure code + */ +dom_exception +_dom_tokenlist_item(dom_tokenlist *list, uint32_t index, dom_string **value) +{ + dom_exception exc; + assert(list != NULL); + + exc = _dom_tokenlist_reparse(list); + if (exc != DOM_NO_ERR) + return exc; + + if (index >= list->len) { + *value = NULL; + return DOM_NO_ERR; + } + + *value = dom_string_ref(list->entries[index]); + return DOM_NO_ERR; +} + +/** + * Retrieve the value of the tokenlist as a string + * + * \param list The list to retrieve the value of + * \param value The value of the list returns here + * \return DOM_NO_ERR on success, otherwise the failure code + */ +dom_exception dom_tokenlist_get_value(dom_tokenlist *list, dom_string **value) +{ + assert(list != NULL); + + return dom_element_get_attribute(list->ele, list->attr, value); +} + +/** + * Set the value of the tokenlist as a string + * + * \param list The list to set the value of + * \param value The value to set + * \return DOM_NO_ERR on success, otherwise the failure code + * + */ +dom_exception dom_tokenlist_set_value(dom_tokenlist *list, dom_string *value) +{ + assert(list != NULL); + + return dom_element_set_attribute(list->ele, list->attr, value); +} + +/** + * Check if the given value is in the tokenlist + * + * \param list The list to scan for the given value + * \param value The value to look for in the token list + * \param contains This will be set based on whether or not the value is present + * \return DOM_NO_ERR on success, otherwise the failure code + */ +dom_exception +dom_tokenlist_contains(dom_tokenlist *list, dom_string *value, bool *contains) +{ + dom_exception exc; + uint32_t n; + + assert(list != NULL); + + exc = _dom_tokenlist_reparse(list); + if (exc != DOM_NO_ERR) + return exc; + + *contains = false; + + for (n = 0; n < list->len; n++) { + if (dom_string_isequal(value, list->entries[n])) { + *contains = true; + break; + } + } + + return DOM_NO_ERR; +} + +/** + * Add the given value to the tokenlist + * + * \param list The list to add to + * \param value The value to add + * \return DOM_NO_ERR on success, otherwise the failure code + */ +dom_exception dom_tokenlist_add(dom_tokenlist *list, dom_string *value) +{ + dom_exception exc; + bool present = false; + + assert(list != NULL); + + exc = dom_tokenlist_contains(list, value, &present); + if (exc != DOM_NO_ERR) + return exc; + + if (present == true) + return DOM_NO_ERR; + + exc = _dom_tokenlist_make_room(list); + if (exc != DOM_NO_ERR) + return exc; + + list->entries[list->len++] = dom_string_ref(value); + + exc = _dom_tokenlist_reify(list); + + return exc; +} + +/** + * Remove the given value from the tokenlist + * + * \param list The list to remove from + * \param value The value to remove + * \return DOM_NO_ERR on success, otherwise the failure code + */ +dom_exception dom_tokenlist_remove(dom_tokenlist *list, dom_string *value) +{ + dom_exception exc; + uint32_t n, m; + + assert(list != NULL); + + exc = _dom_tokenlist_reparse(list); + if (exc != DOM_NO_ERR) + return false; + + for (n = 0; n < list->len; ++n) { + if (dom_string_isequal(value, list->entries[n])) { + dom_string_unref(list->entries[n]); + for (m = n + 1; m < list->len; ++m) { + list->entries[m - 1] = list->entries[m]; + } + list->len--; + break; + } + } + + exc = _dom_tokenlist_reify(list); + + return exc; +} diff --git a/src/core/tokenlist.h b/src/core/tokenlist.h new file mode 100644 index 0000000..325d726 --- /dev/null +++ b/src/core/tokenlist.h @@ -0,0 +1,18 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org> + */ + +#ifndef dom_internal_core_tokenlist_h_ +#define dom_internal_core_tokenlist_h_ + +#include <stdbool.h> + +#include <dom/core/tokenlist.h> + +struct dom_element; +struct dom_string; + +#endif |