| File: | src/core/tokenlist.c |
| Warning: | line 178, column 6 Although the value stored to 'n_entries' is used in the enclosing expression, the value is never actually read from 'n_entries' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* | |||
| 2 | * This file is part of libdom. | |||
| 3 | * Licensed under the MIT License, | |||
| 4 | * http://www.opensource.org/licenses/mit-license.php | |||
| 5 | * Copyright 2022 Daniel Silverstone <dsilvers@digital-scurf.org> | |||
| 6 | */ | |||
| 7 | ||||
| 8 | #include <assert.h> | |||
| 9 | #include <stdlib.h> | |||
| 10 | #include <string.h> | |||
| 11 | ||||
| 12 | #include <dom/core/element.h> | |||
| 13 | #include <dom/core/nodelist.h> | |||
| 14 | #include <dom/core/tokenlist.h> | |||
| 15 | #include <dom/core/string.h> | |||
| 16 | #include <dom/events/event.h> | |||
| 17 | #include <dom/events/event_target.h> | |||
| 18 | #include <dom/events/event_listener.h> | |||
| 19 | #include <dom/events/mutation_event.h> | |||
| 20 | ||||
| 21 | #include "core/element.h" | |||
| 22 | #include "core/document.h" | |||
| 23 | ||||
| 24 | #include "utils/utils.h" | |||
| 25 | ||||
| 26 | #define DOM_TOKENLIST_GROW_INCREMENT4 4 | |||
| 27 | ||||
| 28 | struct dom_tokenlist { | |||
| 29 | uint32_t refcnt; | |||
| 30 | dom_element *ele; | |||
| 31 | dom_string *attr; | |||
| 32 | dom_event_listener *listener; | |||
| 33 | dom_string *last_set; | |||
| 34 | bool_Bool needs_parse; | |||
| 35 | /* Parsed content, for optimal access */ | |||
| 36 | dom_string **entries; | |||
| 37 | uint32_t len; | |||
| 38 | uint32_t alloc; | |||
| 39 | }; | |||
| 40 | ||||
| 41 | /* Handle a DOMAttrModified event which might be to do with our attribute */ | |||
| 42 | ||||
| 43 | static void _dom_tokenlist_handle_attrmodified(dom_event *evt, void *pw) | |||
| 44 | { | |||
| 45 | dom_mutation_event *mutevt = (dom_mutation_event *)evt; | |||
| 46 | dom_tokenlist *list = (dom_tokenlist *)pw; | |||
| 47 | dom_exception exc; | |||
| 48 | dom_string *value; | |||
| 49 | ||||
| 50 | { | |||
| 51 | dom_event_target *target; | |||
| 52 | exc = dom_event_get_target(evt, &target)_dom_event_get_target((dom_event *) (evt), (dom_event_target * *) (&target)); | |||
| 53 | if (exc != DOM_NO_ERR) | |||
| 54 | return; | |||
| 55 | dom_node_unref(target)dom_node_unref((dom_node *) (target)); | |||
| 56 | if (target != (dom_event_target *)list->ele) | |||
| 57 | return; | |||
| 58 | } | |||
| 59 | ||||
| 60 | { | |||
| 61 | dom_string *attr; | |||
| 62 | exc = dom_mutation_event_get_attr_name(mutevt, &attr)_dom_mutation_event_get_attr_name((dom_mutation_event *) (mutevt ), (dom_string **) (&attr)); | |||
| 63 | if (exc != DOM_NO_ERR) | |||
| 64 | return; | |||
| 65 | if (!dom_string_isequal(attr, list->attr)) { | |||
| 66 | dom_string_unref(attr); | |||
| 67 | return; | |||
| 68 | } | |||
| 69 | dom_string_unref(attr); | |||
| 70 | } | |||
| 71 | ||||
| 72 | /* At this point we know that this is a mutation of our attribute on our | |||
| 73 | * node */ | |||
| 74 | ||||
| 75 | exc = dom_mutation_event_get_new_value(mutevt, &value)_dom_mutation_event_get_new_value((dom_mutation_event *) (mutevt ), (dom_string **) (&value)); | |||
| 76 | if (exc != DOM_NO_ERR) | |||
| 77 | return; | |||
| 78 | ||||
| 79 | if (list->last_set != NULL((void*)0) && | |||
| 80 | dom_string_isequal(list->last_set, value)) { | |||
| 81 | /* We've just seen the mutation event for one of our own set | |||
| 82 | * operations */ | |||
| 83 | dom_string_unref(value); | |||
| 84 | return; | |||
| 85 | } | |||
| 86 | ||||
| 87 | /* Mark that we need to re-parse the tokenlist on the next request */ | |||
| 88 | list->needs_parse = true1; | |||
| 89 | ||||
| 90 | dom_string_unref(value); | |||
| 91 | } | |||
| 92 | ||||
| 93 | static dom_exception _dom_tokenlist_make_room(dom_tokenlist *list) | |||
| 94 | { | |||
| 95 | if (list->len == list->alloc) { | |||
| 96 | uint32_t new_alloc = list->alloc + DOM_TOKENLIST_GROW_INCREMENT4; | |||
| 97 | dom_string **new_entries = realloc( | |||
| 98 | list->entries, new_alloc * sizeof(dom_string *)); | |||
| 99 | if (new_entries == NULL((void*)0)) | |||
| 100 | return DOM_NO_MEM_ERR; | |||
| 101 | list->alloc = new_alloc; | |||
| 102 | list->entries = new_entries; | |||
| 103 | } | |||
| 104 | ||||
| 105 | return DOM_NO_ERR; | |||
| 106 | } | |||
| 107 | ||||
| 108 | static dom_exception _dom_tokenlist_reparse(dom_tokenlist *list) | |||
| ||||
| 109 | { | |||
| 110 | dom_exception exc; | |||
| 111 | dom_string *value; | |||
| 112 | const char *pos; | |||
| 113 | uint32_t remaining, check; | |||
| 114 | uint32_t n_entries = 0; | |||
| 115 | dom_string *temp; | |||
| 116 | bool_Bool found; | |||
| 117 | ||||
| 118 | if (!list->needs_parse) | |||
| 119 | return DOM_NO_ERR; | |||
| 120 | ||||
| 121 | /* Clean down the current entries */ | |||
| 122 | while (list->len-- > 0) | |||
| 123 | dom_string_unref(list->entries[list->len]); | |||
| 124 | list->len = 0; | |||
| 125 | ||||
| 126 | /* Get the "new" attribute value */ | |||
| 127 | exc = dom_element_get_attribute(list->ele, list->attr, &value)dom_element_get_attribute( (dom_element *) (list->ele), (list ->attr), (&value)); | |||
| 128 | if (exc != DOM_NO_ERR) | |||
| 129 | return exc; | |||
| 130 | ||||
| 131 | /* If there is no value, we're an empty list and we're done */ | |||
| 132 | if (value == NULL((void*)0)) { | |||
| 133 | list->needs_parse = false0; | |||
| 134 | return DOM_NO_ERR; | |||
| 135 | } | |||
| 136 | ||||
| 137 | /* OK, there's something here to do, so let's do it... */ | |||
| 138 | ||||
| 139 | /* Count number of entries */ | |||
| 140 | for (pos = dom_string_data(value), remaining = dom_string_length(value); | |||
| 141 | remaining > 0;) { | |||
| 142 | if (*pos != ' ') { | |||
| 143 | while (*pos != ' ' && remaining > 0) { | |||
| 144 | remaining--; | |||
| 145 | pos++; | |||
| 146 | } | |||
| 147 | n_entries++; | |||
| 148 | } else { | |||
| 149 | while (*pos == ' ' && remaining > 0) { | |||
| 150 | remaining--; | |||
| 151 | pos++; | |||
| 152 | } | |||
| 153 | } | |||
| 154 | } | |||
| 155 | ||||
| 156 | /* If there are no entries (all whitespace) just bail here */ | |||
| 157 | if (n_entries == 0) { | |||
| 158 | list->needs_parse = false0; | |||
| 159 | dom_string_unref(value); | |||
| 160 | return DOM_NO_ERR; | |||
| 161 | } | |||
| 162 | ||||
| 163 | /* If we need more room, reallocate the buffer */ | |||
| 164 | if (list->alloc < n_entries) { | |||
| 165 | dom_string **new_alloc = realloc( | |||
| 166 | list->entries, n_entries * sizeof(dom_string *)); | |||
| 167 | if (new_alloc == NULL((void*)0)) { | |||
| 168 | dom_string_unref(value); | |||
| 169 | return DOM_NO_MEM_ERR; | |||
| 170 | } | |||
| 171 | list->entries = new_alloc; | |||
| 172 | list->alloc = n_entries; | |||
| 173 | } | |||
| 174 | ||||
| 175 | /* And now parse those entries into the buffer */ | |||
| 176 | for (pos = dom_string_data(value), | |||
| 177 | remaining = dom_string_length(value), | |||
| 178 | n_entries = 0; | |||
| ||||
| 179 | remaining > 0;) { | |||
| 180 | if (*pos != ' ') { | |||
| 181 | const char *s = pos; | |||
| 182 | while (*pos != ' ' && remaining > 0) { | |||
| 183 | pos++; | |||
| 184 | remaining--; | |||
| 185 | } | |||
| 186 | exc = dom_string_create_interned((const uint8_t *)s, | |||
| 187 | pos - s, | |||
| 188 | &temp); | |||
| 189 | if (exc != DOM_NO_ERR) { | |||
| 190 | dom_string_unref(value); | |||
| 191 | return exc; | |||
| 192 | } | |||
| 193 | found = false0; | |||
| 194 | for (check = 0; check < list->len; check++) { | |||
| 195 | if (dom_string_isequal(temp, | |||
| 196 | list->entries[check])) { | |||
| 197 | found = true1; | |||
| 198 | break; | |||
| 199 | } | |||
| 200 | } | |||
| 201 | if (found == true1) { | |||
| 202 | dom_string_unref(temp); | |||
| 203 | } else { | |||
| 204 | list->entries[list->len] = temp; | |||
| 205 | list->len++; | |||
| 206 | } | |||
| 207 | } else { | |||
| 208 | while (*pos == ' ' && remaining > 0) { | |||
| 209 | pos++; | |||
| 210 | remaining--; | |||
| 211 | } | |||
| 212 | } | |||
| 213 | } | |||
| 214 | ||||
| 215 | dom_string_unref(value); | |||
| 216 | list->needs_parse = false0; | |||
| 217 | ||||
| 218 | return DOM_NO_ERR; | |||
| 219 | } | |||
| 220 | ||||
| 221 | static dom_exception _dom_tokenlist_reify(dom_tokenlist *list) | |||
| 222 | { | |||
| 223 | dom_exception exc; | |||
| 224 | uint32_t nchars = 0, n; | |||
| 225 | char *buffer, *next; | |||
| 226 | dom_string *output; | |||
| 227 | ||||
| 228 | if (list->len == 0) { | |||
| 229 | if (list->last_set != NULL((void*)0)) { | |||
| 230 | dom_string_unref(list->last_set); | |||
| 231 | } | |||
| 232 | list->last_set = dom_string_ref( | |||
| 233 | list->ele->base.owner->_memo_empty); | |||
| 234 | return dom_element_set_attribute(list->ele,dom_element_set_attribute( (dom_element *) (list->ele), (list ->attr), (list->last_set)) | |||
| 235 | list->attr,dom_element_set_attribute( (dom_element *) (list->ele), (list ->attr), (list->last_set)) | |||
| 236 | list->last_set)dom_element_set_attribute( (dom_element *) (list->ele), (list ->attr), (list->last_set)); | |||
| 237 | } | |||
| 238 | ||||
| 239 | for (n = 0; n < list->len; ++n) | |||
| 240 | nchars += dom_string_length(list->entries[n]); | |||
| 241 | ||||
| 242 | buffer = calloc(1, nchars + list->len); | |||
| 243 | if (buffer == NULL((void*)0)) | |||
| 244 | return DOM_NO_MEM_ERR; | |||
| 245 | ||||
| 246 | for (next = buffer, n = 0; n < list->len; ++n) { | |||
| 247 | uint32_t slen = dom_string_length(list->entries[n]); | |||
| 248 | memcpy(next, dom_string_data(list->entries[n]), slen); | |||
| 249 | next[slen] = ' '; | |||
| 250 | next += slen + 1; | |||
| 251 | } | |||
| 252 | ||||
| 253 | exc = dom_string_create_interned((const uint8_t *)buffer, | |||
| 254 | nchars + list->len - 1, | |||
| 255 | &output); | |||
| 256 | free(buffer); | |||
| 257 | if (exc != DOM_NO_ERR) | |||
| 258 | return exc; | |||
| 259 | ||||
| 260 | if (list->last_set != NULL((void*)0)) { | |||
| 261 | dom_string_unref(list->last_set); | |||
| 262 | } | |||
| 263 | list->last_set = output; | |||
| 264 | ||||
| 265 | return dom_element_set_attribute(list->ele, list->attr, list->last_set)dom_element_set_attribute( (dom_element *) (list->ele), (list ->attr), (list->last_set)); | |||
| 266 | } | |||
| 267 | ||||
| 268 | /**********************************************************************************/ | |||
| 269 | ||||
| 270 | /** | |||
| 271 | * Create a tokenlist | |||
| 272 | * | |||
| 273 | * \param ele The element which owns the tokenlist attribute | |||
| 274 | * \param attr The name of the attribute we are treating as a tokenlist | |||
| 275 | * \param list The tokenlist output which is set on success | |||
| 276 | * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion | |||
| 277 | * | |||
| 278 | * The returned list will already be referenced, so the client need not | |||
| 279 | * do so explicitly. The client must unref the list once finished with it. | |||
| 280 | * | |||
| 281 | * This list will take its own references to ::ele and ::attr | |||
| 282 | */ | |||
| 283 | dom_exception | |||
| 284 | dom_tokenlist_create(dom_element *ele, dom_string *attr, dom_tokenlist **list) | |||
| 285 | { | |||
| 286 | dom_tokenlist *l; | |||
| 287 | dom_exception exc; | |||
| 288 | ||||
| 289 | l = calloc(1, sizeof(dom_tokenlist)); | |||
| 290 | if (l == NULL((void*)0)) | |||
| 291 | return DOM_NO_MEM_ERR; | |||
| 292 | ||||
| 293 | l->refcnt = 1; | |||
| 294 | l->ele = (dom_element *)dom_node_ref(ele)dom_node_ref((dom_node *) (ele)); | |||
| 295 | l->attr = dom_string_ref(attr); | |||
| 296 | l->needs_parse = true1; | |||
| 297 | ||||
| 298 | exc = dom_event_listener_create(_dom_tokenlist_handle_attrmodified, | |||
| 299 | l, | |||
| 300 | &l->listener); | |||
| 301 | if (exc != DOM_NO_ERR) | |||
| 302 | goto fail; | |||
| 303 | ||||
| 304 | exc = dom_event_target_add_event_listener(dom_event_target_add_event_listener((dom_event_target *) (ele ), (dom_string *) (ele->base.owner->_memo_domattrmodified ), (struct dom_event_listener *) (l->listener), (_Bool) (0 )) | |||
| 305 | ele,dom_event_target_add_event_listener((dom_event_target *) (ele ), (dom_string *) (ele->base.owner->_memo_domattrmodified ), (struct dom_event_listener *) (l->listener), (_Bool) (0 )) | |||
| 306 | ele->base.owner->_memo_domattrmodified,dom_event_target_add_event_listener((dom_event_target *) (ele ), (dom_string *) (ele->base.owner->_memo_domattrmodified ), (struct dom_event_listener *) (l->listener), (_Bool) (0 )) | |||
| 307 | l->listener,dom_event_target_add_event_listener((dom_event_target *) (ele ), (dom_string *) (ele->base.owner->_memo_domattrmodified ), (struct dom_event_listener *) (l->listener), (_Bool) (0 )) | |||
| 308 | false)dom_event_target_add_event_listener((dom_event_target *) (ele ), (dom_string *) (ele->base.owner->_memo_domattrmodified ), (struct dom_event_listener *) (l->listener), (_Bool) (0 )); | |||
| 309 | ||||
| 310 | if (exc != DOM_NO_ERR) | |||
| 311 | goto fail; | |||
| 312 | ||||
| 313 | *list = l; | |||
| 314 | ||||
| 315 | return DOM_NO_ERR; | |||
| 316 | ||||
| 317 | fail: | |||
| 318 | if (l->listener != NULL((void*)0)) | |||
| 319 | dom_event_listener_unref(l->listener); | |||
| 320 | dom_node_unref(l->ele)dom_node_unref((dom_node *) (l->ele)); | |||
| 321 | dom_string_unref(l->attr); | |||
| 322 | free(l); | |||
| 323 | return exc; | |||
| 324 | } | |||
| 325 | ||||
| 326 | /** | |||
| 327 | * Claim a ref on a tokenlist | |||
| 328 | * | |||
| 329 | * \param list The tokenlist to claim a ref on | |||
| 330 | */ | |||
| 331 | void dom_tokenlist_ref(dom_tokenlist *list) | |||
| 332 | { | |||
| 333 | assert(list != NULL)((list != ((void*)0)) ? (void) (0) : __assert_fail ("list != NULL" , "src/core/tokenlist.c", 333, __extension__ __PRETTY_FUNCTION__ )); | |||
| 334 | list->refcnt++; | |||
| 335 | } | |||
| 336 | ||||
| 337 | /** | |||
| 338 | * Release a ref on a tokenlist | |||
| 339 | * | |||
| 340 | * \param list The list to release the reference of | |||
| 341 | * | |||
| 342 | * If you release the last ref, this cleans up the tokenlist | |||
| 343 | */ | |||
| 344 | void dom_tokenlist_unref(dom_tokenlist *list) | |||
| 345 | { | |||
| 346 | assert(list != NULL)((list != ((void*)0)) ? (void) (0) : __assert_fail ("list != NULL" , "src/core/tokenlist.c", 346, __extension__ __PRETTY_FUNCTION__ )); | |||
| 347 | ||||
| 348 | if (--list->refcnt > 0) | |||
| 349 | return; | |||
| 350 | ||||
| 351 | if (list->alloc > 0) { | |||
| 352 | while (list->len-- > 0) | |||
| 353 | dom_string_unref(list->entries[list->len]); | |||
| 354 | free(list->entries); | |||
| 355 | } | |||
| 356 | ||||
| 357 | dom_event_target_remove_event_listener(dom_event_target_remove_event_listener( (dom_event_target *) ( list->ele), (dom_string *) (list->ele->base.owner-> _memo_domattrmodified), (struct dom_event_listener *) (list-> listener), (_Bool) (0)) | |||
| 358 | list->ele,dom_event_target_remove_event_listener( (dom_event_target *) ( list->ele), (dom_string *) (list->ele->base.owner-> _memo_domattrmodified), (struct dom_event_listener *) (list-> listener), (_Bool) (0)) | |||
| 359 | list->ele->base.owner->_memo_domattrmodified,dom_event_target_remove_event_listener( (dom_event_target *) ( list->ele), (dom_string *) (list->ele->base.owner-> _memo_domattrmodified), (struct dom_event_listener *) (list-> listener), (_Bool) (0)) | |||
| 360 | list->listener,dom_event_target_remove_event_listener( (dom_event_target *) ( list->ele), (dom_string *) (list->ele->base.owner-> _memo_domattrmodified), (struct dom_event_listener *) (list-> listener), (_Bool) (0)) | |||
| 361 | false)dom_event_target_remove_event_listener( (dom_event_target *) ( list->ele), (dom_string *) (list->ele->base.owner-> _memo_domattrmodified), (struct dom_event_listener *) (list-> listener), (_Bool) (0)); | |||
| 362 | ||||
| 363 | dom_event_listener_unref(list->listener); | |||
| 364 | ||||
| 365 | if (list->last_set != NULL((void*)0)) | |||
| 366 | dom_string_unref(list->last_set); | |||
| 367 | ||||
| 368 | dom_string_unref(list->attr); | |||
| 369 | dom_node_unref(list->ele)dom_node_unref((dom_node *) (list->ele)); | |||
| 370 | ||||
| 371 | free(list); | |||
| 372 | } | |||
| 373 | ||||
| 374 | /** | |||
| 375 | * Get the length of the tokenlist | |||
| 376 | * | |||
| 377 | * \param list The list to get the length of | |||
| 378 | * \param length Length of the list outputs here | |||
| 379 | * \return DOM_NO_ERR on success, otherwise the failure code | |||
| 380 | */ | |||
| 381 | dom_exception dom_tokenlist_get_length(dom_tokenlist *list, uint32_t *length) | |||
| 382 | { | |||
| 383 | dom_exception exc; | |||
| 384 | assert(list != NULL)((list != ((void*)0)) ? (void) (0) : __assert_fail ("list != NULL" , "src/core/tokenlist.c", 384, __extension__ __PRETTY_FUNCTION__ )); | |||
| 385 | ||||
| 386 | exc = _dom_tokenlist_reparse(list); | |||
| 387 | if (exc != DOM_NO_ERR) | |||
| 388 | return exc; | |||
| 389 | ||||
| 390 | *length = list->len; | |||
| 391 | ||||
| 392 | return DOM_NO_ERR; | |||
| 393 | } | |||
| 394 | ||||
| 395 | /** | |||
| 396 | * Get a particular item from the tokenlist | |||
| 397 | * | |||
| 398 | * \param list The list to retrieve the item from | |||
| 399 | * \param index The index of the item to retrieve | |||
| 400 | * \param value The value of the item returns here | |||
| 401 | * \return DOM_NO_ERR on success, otherwise the failure code | |||
| 402 | */ | |||
| 403 | dom_exception | |||
| 404 | _dom_tokenlist_item(dom_tokenlist *list, uint32_t index, dom_string **value) | |||
| 405 | { | |||
| 406 | dom_exception exc; | |||
| 407 | assert(list != NULL)((list != ((void*)0)) ? (void) (0) : __assert_fail ("list != NULL" , "src/core/tokenlist.c", 407, __extension__ __PRETTY_FUNCTION__ )); | |||
| 408 | ||||
| 409 | exc = _dom_tokenlist_reparse(list); | |||
| 410 | if (exc != DOM_NO_ERR) | |||
| 411 | return exc; | |||
| 412 | ||||
| 413 | if (index >= list->len) { | |||
| 414 | *value = NULL((void*)0); | |||
| 415 | return DOM_NO_ERR; | |||
| 416 | } | |||
| 417 | ||||
| 418 | *value = dom_string_ref(list->entries[index]); | |||
| 419 | return DOM_NO_ERR; | |||
| 420 | } | |||
| 421 | ||||
| 422 | /** | |||
| 423 | * Retrieve the value of the tokenlist as a string | |||
| 424 | * | |||
| 425 | * \param list The list to retrieve the value of | |||
| 426 | * \param value The value of the list returns here | |||
| 427 | * \return DOM_NO_ERR on success, otherwise the failure code | |||
| 428 | */ | |||
| 429 | dom_exception dom_tokenlist_get_value(dom_tokenlist *list, dom_string **value) | |||
| 430 | { | |||
| 431 | assert(list != NULL)((list != ((void*)0)) ? (void) (0) : __assert_fail ("list != NULL" , "src/core/tokenlist.c", 431, __extension__ __PRETTY_FUNCTION__ )); | |||
| 432 | ||||
| 433 | return dom_element_get_attribute(list->ele, list->attr, value)dom_element_get_attribute( (dom_element *) (list->ele), (list ->attr), (value)); | |||
| 434 | } | |||
| 435 | ||||
| 436 | /** | |||
| 437 | * Set the value of the tokenlist as a string | |||
| 438 | * | |||
| 439 | * \param list The list to set the value of | |||
| 440 | * \param value The value to set | |||
| 441 | * \return DOM_NO_ERR on success, otherwise the failure code | |||
| 442 | * | |||
| 443 | */ | |||
| 444 | dom_exception dom_tokenlist_set_value(dom_tokenlist *list, dom_string *value) | |||
| 445 | { | |||
| 446 | assert(list != NULL)((list != ((void*)0)) ? (void) (0) : __assert_fail ("list != NULL" , "src/core/tokenlist.c", 446, __extension__ __PRETTY_FUNCTION__ )); | |||
| 447 | ||||
| 448 | return dom_element_set_attribute(list->ele, list->attr, value)dom_element_set_attribute( (dom_element *) (list->ele), (list ->attr), (value)); | |||
| 449 | } | |||
| 450 | ||||
| 451 | /** | |||
| 452 | * Check if the given value is in the tokenlist | |||
| 453 | * | |||
| 454 | * \param list The list to scan for the given value | |||
| 455 | * \param value The value to look for in the token list | |||
| 456 | * \param contains This will be set based on whether or not the value is present | |||
| 457 | * \return DOM_NO_ERR on success, otherwise the failure code | |||
| 458 | */ | |||
| 459 | dom_exception | |||
| 460 | dom_tokenlist_contains(dom_tokenlist *list, dom_string *value, bool_Bool *contains) | |||
| 461 | { | |||
| 462 | dom_exception exc; | |||
| 463 | uint32_t n; | |||
| 464 | ||||
| 465 | assert(list != NULL)((list != ((void*)0)) ? (void) (0) : __assert_fail ("list != NULL" , "src/core/tokenlist.c", 465, __extension__ __PRETTY_FUNCTION__ )); | |||
| 466 | ||||
| 467 | exc = _dom_tokenlist_reparse(list); | |||
| 468 | if (exc != DOM_NO_ERR) | |||
| 469 | return exc; | |||
| 470 | ||||
| 471 | *contains = false0; | |||
| 472 | ||||
| 473 | for (n = 0; n < list->len; n++) { | |||
| 474 | if (dom_string_isequal(value, list->entries[n])) { | |||
| 475 | *contains = true1; | |||
| 476 | break; | |||
| 477 | } | |||
| 478 | } | |||
| 479 | ||||
| 480 | return DOM_NO_ERR; | |||
| 481 | } | |||
| 482 | ||||
| 483 | /** | |||
| 484 | * Add the given value to the tokenlist | |||
| 485 | * | |||
| 486 | * \param list The list to add to | |||
| 487 | * \param value The value to add | |||
| 488 | * \return DOM_NO_ERR on success, otherwise the failure code | |||
| 489 | */ | |||
| 490 | dom_exception dom_tokenlist_add(dom_tokenlist *list, dom_string *value) | |||
| 491 | { | |||
| 492 | dom_exception exc; | |||
| 493 | bool_Bool present = false0; | |||
| 494 | ||||
| 495 | assert(list != NULL)((list != ((void*)0)) ? (void) (0) : __assert_fail ("list != NULL" , "src/core/tokenlist.c", 495, __extension__ __PRETTY_FUNCTION__ )); | |||
| 496 | ||||
| 497 | exc = dom_tokenlist_contains(list, value, &present); | |||
| 498 | if (exc != DOM_NO_ERR) | |||
| 499 | return exc; | |||
| 500 | ||||
| 501 | if (present == true1) | |||
| 502 | return DOM_NO_ERR; | |||
| 503 | ||||
| 504 | exc = _dom_tokenlist_make_room(list); | |||
| 505 | if (exc != DOM_NO_ERR) | |||
| 506 | return exc; | |||
| 507 | ||||
| 508 | list->entries[list->len++] = dom_string_ref(value); | |||
| 509 | ||||
| 510 | exc = _dom_tokenlist_reify(list); | |||
| 511 | ||||
| 512 | return exc; | |||
| 513 | } | |||
| 514 | ||||
| 515 | /** | |||
| 516 | * Remove the given value from the tokenlist | |||
| 517 | * | |||
| 518 | * \param list The list to remove from | |||
| 519 | * \param value The value to remove | |||
| 520 | * \return DOM_NO_ERR on success, otherwise the failure code | |||
| 521 | */ | |||
| 522 | dom_exception dom_tokenlist_remove(dom_tokenlist *list, dom_string *value) | |||
| 523 | { | |||
| 524 | dom_exception exc; | |||
| 525 | uint32_t n, m; | |||
| 526 | ||||
| 527 | assert(list != NULL)((list != ((void*)0)) ? (void) (0) : __assert_fail ("list != NULL" , "src/core/tokenlist.c", 527, __extension__ __PRETTY_FUNCTION__ )); | |||
| 528 | ||||
| 529 | exc = _dom_tokenlist_reparse(list); | |||
| 530 | if (exc != DOM_NO_ERR) | |||
| 531 | return false0; | |||
| 532 | ||||
| 533 | for (n = 0; n < list->len; ++n) { | |||
| 534 | if (dom_string_isequal(value, list->entries[n])) { | |||
| 535 | dom_string_unref(list->entries[n]); | |||
| 536 | for (m = n + 1; m < list->len; ++m) { | |||
| 537 | list->entries[m - 1] = list->entries[m]; | |||
| 538 | } | |||
| 539 | list->len--; | |||
| 540 | break; | |||
| 541 | } | |||
| 542 | } | |||
| 543 | ||||
| 544 | exc = _dom_tokenlist_reify(list); | |||
| 545 | ||||
| 546 | return exc; | |||
| 547 | } |