diff options
| author | 2026-04-27 01:45:33 +0200 | |
|---|---|---|
| committer | 2026-04-27 01:45:33 +0200 | |
| commit | d35b31d0a2661b6346a1592a5eb7b70e66b2a141 (patch) | |
| tree | a65156248dfd4df7c9301daf2a786a3469586147 | |
| parent | dddb76d74a646a7ec41cfa6b9f7772830b7acbd2 (diff) | |
| download | libplist-d35b31d0a2661b6346a1592a5eb7b70e66b2a141.tar.gz libplist-d35b31d0a2661b6346a1592a5eb7b70e66b2a141.tar.bz2 | |
Add error handling to all modification functions
Convert all array/dict modification functions from void to plist_err_t return type:
- plist_array_set_item: replace at index n
- plist_array_append_item: append to end
- plist_array_insert_item: insert at position n
- plist_array_remove_item: remove item at index n
- plist_array_item_remove: remove item from its array parent
- plist_dict_set_item: replace or insert key/value
- plist_dict_remove_item: remove key/value pair
- plist_dict_merge: merge source dict into target
Returns:
- PLIST_ERR_SUCCESS on success
- PLIST_ERR_INVALID_ARG for invalid arguments (NULL, wrong type, out of range, etc.)
- PLIST_ERR_NO_MEM on memory allocation failure
- PLIST_ERR_UNKNOWN on unexpected internal errors
Header documentation updated with full error code semantics for each function.
| -rw-r--r-- | include/plist/plist.h | 81 | ||||
| -rw-r--r-- | src/plist.c | 174 |
2 files changed, 163 insertions, 92 deletions
diff --git a/include/plist/plist.h b/include/plist/plist.h index 94930b8..e720aac 100644 --- a/include/plist/plist.h +++ b/include/plist/plist.h | |||
| @@ -347,43 +347,77 @@ extern "C" | |||
| 347 | * | 347 | * |
| 348 | * @param node the node of type #PLIST_ARRAY | 348 | * @param node the node of type #PLIST_ARRAY |
| 349 | * @param item the new item at index n. The array is responsible for freeing item when it is no longer needed. | 349 | * @param item the new item at index n. The array is responsible for freeing item when it is no longer needed. |
| 350 | * @param n the index of the item to get. Range is [0, array_size[. Assert if n is not in range. | 350 | * @param n the index of the item to get. Range is [0, array_size[. |
| 351 | * | ||
| 352 | * @return | ||
| 353 | * - PLIST_ERR_SUCCESS on success. | ||
| 354 | * - PLIST_ERR_INVALID_ARG if node is not an array, item is NULL, item is already | ||
| 355 | * attached to a parent, or n is outside the valid range. | ||
| 356 | * - PLIST_ERR_NO_MEM if replacing the item fails due to memory allocation failure | ||
| 357 | * and the original array element was restored successfully. | ||
| 358 | * - PLIST_ERR_UNKNOWN if an unexpected internal error occurred, including failure | ||
| 359 | * to restore the original array element after insertion of the replacement failed. | ||
| 351 | */ | 360 | */ |
| 352 | PLIST_API void plist_array_set_item(plist_t node, plist_t item, uint32_t n); | 361 | PLIST_API plist_err_t plist_array_set_item(plist_t node, plist_t item, uint32_t n); |
| 353 | 362 | ||
| 354 | /** | 363 | /** |
| 355 | * Append a new item at the end of a #PLIST_ARRAY node. | 364 | * Append a new item at the end of a #PLIST_ARRAY node. |
| 356 | * | 365 | * |
| 357 | * @param node the node of type #PLIST_ARRAY | 366 | * @param node the node of type #PLIST_ARRAY |
| 358 | * @param item the new item. The array is responsible for freeing item when it is no longer needed. | 367 | * @param item the new item. The array is responsible for freeing item when it is no longer needed. |
| 368 | * | ||
| 369 | * @return | ||
| 370 | * - PLIST_ERR_SUCCESS on success. | ||
| 371 | * - PLIST_ERR_INVALID_ARG if node is not an array, item is NULL, or item is | ||
| 372 | * already attached to a parent. | ||
| 373 | * - PLIST_ERR_NO_MEM if memory allocation failed while appending the item. | ||
| 374 | * - PLIST_ERR_UNKNOWN if an unexpected internal error occurred. | ||
| 359 | */ | 375 | */ |
| 360 | PLIST_API void plist_array_append_item(plist_t node, plist_t item); | 376 | PLIST_API plist_err_t plist_array_append_item(plist_t node, plist_t item); |
| 361 | 377 | ||
| 362 | /** | 378 | /** |
| 363 | * Insert a new item at position n in a #PLIST_ARRAY node. | 379 | * Insert a new item at position n in a #PLIST_ARRAY node. |
| 364 | * | 380 | * |
| 365 | * @param node the node of type #PLIST_ARRAY | 381 | * @param node the node of type #PLIST_ARRAY |
| 366 | * @param item the new item to insert. The array is responsible for freeing item when it is no longer needed. | 382 | * @param item the new item to insert. The array is responsible for freeing item when it is no longer needed. |
| 367 | * @param n The position at which the node will be stored. Range is [0, array_size[. Assert if n is not in range. | 383 | * @param n The position at which the node will be stored. Range is [0, array_size[. |
| 384 | * | ||
| 385 | * @return | ||
| 386 | * - PLIST_ERR_SUCCESS on success. | ||
| 387 | * - PLIST_ERR_INVALID_ARG if node is not an array, item is NULL, item is already | ||
| 388 | * attached to a parent, or n is outside the valid insertion range. | ||
| 389 | * - PLIST_ERR_NO_MEM if memory allocation failed while inserting the item. | ||
| 390 | * - PLIST_ERR_UNKNOWN if an unexpected internal error occurred. | ||
| 368 | */ | 391 | */ |
| 369 | PLIST_API void plist_array_insert_item(plist_t node, plist_t item, uint32_t n); | 392 | PLIST_API plist_err_t plist_array_insert_item(plist_t node, plist_t item, uint32_t n); |
| 370 | 393 | ||
| 371 | /** | 394 | /** |
| 372 | * Remove an existing position in a #PLIST_ARRAY node. | 395 | * Remove an existing position in a #PLIST_ARRAY node. |
| 373 | * Removed position will be freed using #plist_free. | 396 | * Removed position will be freed using #plist_free. |
| 374 | * | 397 | * |
| 375 | * @param node the node of type #PLIST_ARRAY | 398 | * @param node the node of type #PLIST_ARRAY |
| 376 | * @param n The position to remove. Range is [0, array_size[. Assert if n is not in range. | 399 | * @param n The position to remove. Range is [0, array_size[. |
| 400 | * | ||
| 401 | * @return | ||
| 402 | * - PLIST_ERR_SUCCESS on success. | ||
| 403 | * - PLIST_ERR_INVALID_ARG if node is not an array or n is outside the valid range. | ||
| 404 | * - PLIST_ERR_UNKNOWN if an unexpected internal error occurred while removing | ||
| 405 | * the item. | ||
| 377 | */ | 406 | */ |
| 378 | PLIST_API void plist_array_remove_item(plist_t node, uint32_t n); | 407 | PLIST_API plist_err_t plist_array_remove_item(plist_t node, uint32_t n); |
| 379 | 408 | ||
| 380 | /** | 409 | /** |
| 381 | * Remove a node that is a child node of a #PLIST_ARRAY node. | 410 | * Remove a node that is a child node of a #PLIST_ARRAY node. |
| 382 | * node will be freed using #plist_free. | 411 | * node will be freed using #plist_free. |
| 383 | * | 412 | * |
| 384 | * @param node The node to be removed from its #PLIST_ARRAY parent. | 413 | * @param node The node to be removed from its #PLIST_ARRAY parent. |
| 414 | * | ||
| 415 | * @return | ||
| 416 | * - PLIST_ERR_SUCCESS on success. | ||
| 417 | * - PLIST_ERR_INVALID_ARG if item is NULL or not a child of a #PLIST_ARRAY | ||
| 418 | * - PLIST_ERR_UNKNOWN if an unexpected internal error occurred. | ||
| 385 | */ | 419 | */ |
| 386 | PLIST_API void plist_array_item_remove(plist_t node); | 420 | PLIST_API plist_err_t plist_array_item_remove(plist_t item); |
| 387 | 421 | ||
| 388 | /** | 422 | /** |
| 389 | * Create an iterator of a #PLIST_ARRAY node. | 423 | * Create an iterator of a #PLIST_ARRAY node. |
| @@ -489,17 +523,32 @@ extern "C" | |||
| 489 | * @param node the node of type #PLIST_DICT | 523 | * @param node the node of type #PLIST_DICT |
| 490 | * @param item the new item associated to key | 524 | * @param item the new item associated to key |
| 491 | * @param key the identifier of the item to set. | 525 | * @param key the identifier of the item to set. |
| 526 | * | ||
| 527 | * @return | ||
| 528 | * - PLIST_ERR_SUCCESS on success. | ||
| 529 | * - PLIST_ERR_INVALID_ARG if node is not a dictionary, key is NULL, item is NULL, | ||
| 530 | * or item is already attached to a parent. | ||
| 531 | * - PLIST_ERR_NO_MEM if memory allocation failed while creating or inserting the | ||
| 532 | * key/value pair. | ||
| 533 | * - PLIST_ERR_UNKNOWN if an unexpected internal error occurred. | ||
| 492 | */ | 534 | */ |
| 493 | PLIST_API void plist_dict_set_item(plist_t node, const char* key, plist_t item); | 535 | PLIST_API plist_err_t plist_dict_set_item(plist_t node, const char* key, plist_t item); |
| 494 | 536 | ||
| 495 | /** | 537 | /** |
| 496 | * Remove an existing position in a #PLIST_DICT node. | 538 | * Remove an existing position in a #PLIST_DICT node. |
| 497 | * Removed position will be freed using #plist_free | 539 | * Removed position will be freed using #plist_free |
| 498 | * | 540 | * |
| 499 | * @param node the node of type #PLIST_DICT | 541 | * @param node the node of type #PLIST_DICT |
| 500 | * @param key The identifier of the item to remove. Assert if identifier is not present. | 542 | * @param key The identifier of the item to remove |
| 543 | * | ||
| 544 | * @return | ||
| 545 | * - PLIST_ERR_SUCCESS on success. | ||
| 546 | * - PLIST_ERR_INVALID_ARG if node is not a dictionary, key is NULL, or no item | ||
| 547 | * with the given key exists. | ||
| 548 | * - PLIST_ERR_UNKNOWN if an unexpected internal error occurred while removing | ||
| 549 | * the item. | ||
| 501 | */ | 550 | */ |
| 502 | PLIST_API void plist_dict_remove_item(plist_t node, const char* key); | 551 | PLIST_API plist_err_t plist_dict_remove_item(plist_t node, const char* key); |
| 503 | 552 | ||
| 504 | /** | 553 | /** |
| 505 | * Merge a dictionary into another. This will add all key/value pairs | 554 | * Merge a dictionary into another. This will add all key/value pairs |
| @@ -508,8 +557,16 @@ extern "C" | |||
| 508 | * | 557 | * |
| 509 | * @param target pointer to an existing node of type #PLIST_DICT | 558 | * @param target pointer to an existing node of type #PLIST_DICT |
| 510 | * @param source node of type #PLIST_DICT that should be merged into target | 559 | * @param source node of type #PLIST_DICT that should be merged into target |
| 560 | * | ||
| 561 | * @return | ||
| 562 | * - PLIST_ERR_SUCCESS on success. | ||
| 563 | * - PLIST_ERR_INVALID_ARG if target is NULL, source is NULL, source is not a | ||
| 564 | * dictionary, or *target is not NULL and does not point to a dictionary. | ||
| 565 | * - PLIST_ERR_NO_MEM if memory allocation failed while creating the target | ||
| 566 | * dictionary or copying items from source. | ||
| 567 | * - PLIST_ERR_UNKNOWN if an unexpected internal error occurred. | ||
| 511 | */ | 568 | */ |
| 512 | PLIST_API void plist_dict_merge(plist_t *target, plist_t source); | 569 | PLIST_API plist_err_t plist_dict_merge(plist_t *target, plist_t source); |
| 513 | 570 | ||
| 514 | /** | 571 | /** |
| 515 | * Get a boolean value from a given #PLIST_DICT entry. | 572 | * Get a boolean value from a given #PLIST_DICT entry. |
diff --git a/src/plist.c b/src/plist.c index 2ad1b0a..7def2b6 100644 --- a/src/plist.c +++ b/src/plist.c | |||
| @@ -953,8 +953,7 @@ plist_t plist_copy(plist_t node) | |||
| 953 | uint32_t plist_array_get_size(plist_t node) | 953 | uint32_t plist_array_get_size(plist_t node) |
| 954 | { | 954 | { |
| 955 | uint32_t ret = 0; | 955 | uint32_t ret = 0; |
| 956 | if (node && PLIST_ARRAY == plist_get_node_type(node)) | 956 | if (PLIST_IS_ARRAY(node)) { |
| 957 | { | ||
| 958 | ret = node_n_children((node_t)node); | 957 | ret = node_n_children((node_t)node); |
| 959 | } | 958 | } |
| 960 | return ret; | 959 | return ret; |
| @@ -963,8 +962,7 @@ uint32_t plist_array_get_size(plist_t node) | |||
| 963 | plist_t plist_array_get_item(plist_t node, uint32_t n) | 962 | plist_t plist_array_get_item(plist_t node, uint32_t n) |
| 964 | { | 963 | { |
| 965 | plist_t ret = NULL; | 964 | plist_t ret = NULL; |
| 966 | if (node && PLIST_ARRAY == plist_get_node_type(node) && n < INT_MAX) | 965 | if (PLIST_IS_ARRAY(node) && n < INT_MAX) { |
| 967 | { | ||
| 968 | ptrarray_t *pa = (ptrarray_t*)((plist_data_t)((node_t)node)->data)->hashtable; | 966 | ptrarray_t *pa = (ptrarray_t*)((plist_data_t)((node_t)node)->data)->hashtable; |
| 969 | if (pa) { | 967 | if (pa) { |
| 970 | ret = (plist_t)ptr_array_index(pa, n); | 968 | ret = (plist_t)ptr_array_index(pa, n); |
| @@ -977,10 +975,9 @@ plist_t plist_array_get_item(plist_t node, uint32_t n) | |||
| 977 | 975 | ||
| 978 | uint32_t plist_array_get_item_index(plist_t node) | 976 | uint32_t plist_array_get_item_index(plist_t node) |
| 979 | { | 977 | { |
| 980 | plist_t father = plist_get_parent(node); | 978 | plist_t parent = plist_get_parent(node); |
| 981 | if (PLIST_ARRAY == plist_get_node_type(father)) | 979 | if (PLIST_IS_ARRAY(parent)) { |
| 982 | { | 980 | return node_child_position((node_t)parent, (node_t)node); |
| 983 | return node_child_position((node_t)father, (node_t)node); | ||
| 984 | } | 981 | } |
| 985 | return UINT_MAX; | 982 | return UINT_MAX; |
| 986 | } | 983 | } |
| @@ -1039,25 +1036,25 @@ static void _plist_array_post_set(plist_t node, plist_t item, long n) | |||
| 1039 | } | 1036 | } |
| 1040 | } | 1037 | } |
| 1041 | 1038 | ||
| 1042 | void plist_array_set_item(plist_t node, plist_t item, uint32_t n) | 1039 | plist_err_t plist_array_set_item(plist_t node, plist_t item, uint32_t n) |
| 1043 | { | 1040 | { |
| 1044 | if (!PLIST_IS_ARRAY(node) || !item || n >= INT_MAX) { | 1041 | if (!PLIST_IS_ARRAY(node) || !item || n >= INT_MAX) { |
| 1045 | PLIST_ERR("invalid argument passed to %s (node=%p, item=%p, n=%u)\n", __func__, node, item, n); | 1042 | PLIST_ERR("invalid argument passed to %s (node=%p, item=%p, n=%u)\n", __func__, node, item, n); |
| 1046 | return; | 1043 | return PLIST_ERR_INVALID_ARG; |
| 1047 | } | 1044 | } |
| 1048 | node_t it = (node_t)item; | 1045 | node_t it = (node_t)item; |
| 1049 | if (it->parent != NULL) { | 1046 | if (it->parent != NULL) { |
| 1050 | assert(it->parent == NULL && "item already has a parent; use plist_copy() or detach first"); | 1047 | assert(it->parent == NULL && "item already has a parent; use plist_copy() or detach first"); |
| 1051 | PLIST_ERR("%s: item already has a parent; use plist_copy() or detach first\n", __func__); | 1048 | PLIST_ERR("%s: item already has a parent; use plist_copy() or detach first\n", __func__); |
| 1052 | return; | 1049 | return PLIST_ERR_INVALID_ARG; |
| 1053 | } | 1050 | } |
| 1054 | plist_t old_item = plist_array_get_item(node, n); | 1051 | plist_t old_item = plist_array_get_item(node, n); |
| 1055 | if (!old_item) return; | 1052 | if (!old_item) return PLIST_ERR_INVALID_ARG; |
| 1056 | 1053 | ||
| 1057 | int idx = node_detach((node_t)node, (node_t)old_item); | 1054 | int idx = node_detach((node_t)node, (node_t)old_item); |
| 1058 | if (idx < 0) { | 1055 | if (idx < 0) { |
| 1059 | PLIST_ERR("%s: Failed to detach old item (err=%d)\n", __func__, idx); | 1056 | PLIST_ERR("%s: Failed to detach old item (err=%d)\n", __func__, idx); |
| 1060 | return; | 1057 | return PLIST_ERR_UNKNOWN; |
| 1061 | } | 1058 | } |
| 1062 | 1059 | ||
| 1063 | int r = node_insert((node_t)node, (unsigned)idx, (node_t)item); | 1060 | int r = node_insert((node_t)node, (unsigned)idx, (node_t)item); |
| @@ -1066,87 +1063,99 @@ void plist_array_set_item(plist_t node, plist_t item, uint32_t n) | |||
| 1066 | if (rb == NODE_ERR_SUCCESS) { | 1063 | if (rb == NODE_ERR_SUCCESS) { |
| 1067 | _plist_array_post_set(node, old_item, idx); // restore cache correctly | 1064 | _plist_array_post_set(node, old_item, idx); // restore cache correctly |
| 1068 | PLIST_ERR("%s: failed to insert replacement (idx=%d err=%d); rollback succeeded\n", __func__, idx, r); | 1065 | PLIST_ERR("%s: failed to insert replacement (idx=%d err=%d); rollback succeeded\n", __func__, idx, r); |
| 1066 | return (r == NODE_ERR_NO_MEM) ? PLIST_ERR_NO_MEM : PLIST_ERR_UNKNOWN; | ||
| 1069 | } else { | 1067 | } else { |
| 1070 | PLIST_ERR("%s: insert failed (err=%d) and rollback failed (err=%d); array now missing element at idx=%d\n", __func__, r, rb, idx); | 1068 | PLIST_ERR("%s: insert failed (err=%d) and rollback failed (err=%d); array now missing element at idx=%d\n", __func__, r, rb, idx); |
| 1069 | return PLIST_ERR_UNKNOWN; | ||
| 1071 | } | 1070 | } |
| 1072 | return; | ||
| 1073 | } | 1071 | } |
| 1074 | 1072 | ||
| 1075 | _plist_array_post_set(node, item, idx); // update cache | 1073 | _plist_array_post_set(node, item, idx); // update cache |
| 1076 | plist_free_node((node_t)old_item); | 1074 | plist_free_node((node_t)old_item); |
| 1075 | |||
| 1076 | return PLIST_ERR_SUCCESS; | ||
| 1077 | } | 1077 | } |
| 1078 | 1078 | ||
| 1079 | void plist_array_append_item(plist_t node, plist_t item) | 1079 | plist_err_t plist_array_append_item(plist_t node, plist_t item) |
| 1080 | { | 1080 | { |
| 1081 | if (!PLIST_IS_ARRAY(node) || !item) { | 1081 | if (!PLIST_IS_ARRAY(node) || !item) { |
| 1082 | PLIST_ERR("invalid argument passed to %s (node=%p, item=%p)\n", __func__, node, item); | 1082 | PLIST_ERR("invalid argument passed to %s (node=%p, item=%p)\n", __func__, node, item); |
| 1083 | return; | 1083 | return PLIST_ERR_INVALID_ARG; |
| 1084 | } | 1084 | } |
| 1085 | node_t it = (node_t)item; | 1085 | node_t it = (node_t)item; |
| 1086 | if (it->parent != NULL) { | 1086 | if (it->parent != NULL) { |
| 1087 | assert(it->parent == NULL && "item already has a parent; use plist_copy() or detach first"); | 1087 | assert(it->parent == NULL && "item already has a parent; use plist_copy() or detach first"); |
| 1088 | PLIST_ERR("%s: item already has a parent; use plist_copy() or detach first\n", __func__); | 1088 | PLIST_ERR("%s: item already has a parent; use plist_copy() or detach first\n", __func__); |
| 1089 | return; | 1089 | return PLIST_ERR_INVALID_ARG; |
| 1090 | } | 1090 | } |
| 1091 | 1091 | ||
| 1092 | int r = node_attach((node_t)node, (node_t)item); | 1092 | int r = node_attach((node_t)node, (node_t)item); |
| 1093 | if (r != NODE_ERR_SUCCESS) { | 1093 | if (r != NODE_ERR_SUCCESS) { |
| 1094 | PLIST_ERR("%s: failed to append item (err=%d)\n", __func__, r); | 1094 | PLIST_ERR("%s: failed to append item (err=%d)\n", __func__, r); |
| 1095 | return; | 1095 | return PLIST_ERR_UNKNOWN; |
| 1096 | } | 1096 | } |
| 1097 | _plist_array_post_insert(node, item, -1); | 1097 | _plist_array_post_insert(node, item, -1); |
| 1098 | |||
| 1099 | return PLIST_ERR_SUCCESS; | ||
| 1098 | } | 1100 | } |
| 1099 | 1101 | ||
| 1100 | void plist_array_insert_item(plist_t node, plist_t item, uint32_t n) | 1102 | plist_err_t plist_array_insert_item(plist_t node, plist_t item, uint32_t n) |
| 1101 | { | 1103 | { |
| 1102 | if (!PLIST_IS_ARRAY(node) || !item || n >= INT_MAX) { | 1104 | if (!PLIST_IS_ARRAY(node) || !item || n >= INT_MAX) { |
| 1103 | PLIST_ERR("invalid argument passed to %s (node=%p, item=%p, n=%u)\n", __func__, node, item, n); | 1105 | PLIST_ERR("invalid argument passed to %s (node=%p, item=%p, n=%u)\n", __func__, node, item, n); |
| 1104 | return; | 1106 | return PLIST_ERR_INVALID_ARG; |
| 1105 | } | 1107 | } |
| 1106 | node_t it = (node_t)item; | 1108 | node_t it = (node_t)item; |
| 1107 | if (it->parent != NULL) { | 1109 | if (it->parent != NULL) { |
| 1108 | assert(it->parent == NULL && "item already has a parent; use plist_copy() or detach first"); | 1110 | assert(it->parent == NULL && "item already has a parent; use plist_copy() or detach first"); |
| 1109 | PLIST_ERR("%s: item already has a parent; use plist_copy() or detach first\n", __func__); | 1111 | PLIST_ERR("%s: item already has a parent; use plist_copy() or detach first\n", __func__); |
| 1110 | return; | 1112 | return PLIST_ERR_INVALID_ARG; |
| 1111 | } | 1113 | } |
| 1112 | 1114 | ||
| 1113 | int r = node_insert((node_t)node, n, (node_t)item); | 1115 | int r = node_insert((node_t)node, n, (node_t)item); |
| 1114 | if (r != NODE_ERR_SUCCESS) { | 1116 | if (r != NODE_ERR_SUCCESS) { |
| 1115 | PLIST_ERR("%s: Failed to insert item at index %u (err=%d)\n", __func__, n, r); | 1117 | PLIST_ERR("%s: Failed to insert item at index %u (err=%d)\n", __func__, n, r); |
| 1116 | return; | 1118 | return PLIST_ERR_UNKNOWN; |
| 1117 | } | 1119 | } |
| 1118 | _plist_array_post_insert(node, item, (long)n); | 1120 | _plist_array_post_insert(node, item, (long)n); |
| 1121 | |||
| 1122 | return PLIST_ERR_SUCCESS; | ||
| 1119 | } | 1123 | } |
| 1120 | 1124 | ||
| 1121 | void plist_array_remove_item(plist_t node, uint32_t n) | 1125 | plist_err_t plist_array_remove_item(plist_t node, uint32_t n) |
| 1122 | { | 1126 | { |
| 1123 | if (node && PLIST_ARRAY == plist_get_node_type(node) && n < INT_MAX) | 1127 | if (!PLIST_IS_ARRAY(node) || n >= INT_MAX || n > plist_array_get_size(node)) { |
| 1124 | { | 1128 | PLIST_ERR("invalid argument passed to %s (node=%p, n=%u)\n", __func__, node, n); |
| 1125 | plist_t old_item = plist_array_get_item(node, n); | 1129 | return PLIST_ERR_INVALID_ARG; |
| 1126 | if (old_item) | 1130 | } |
| 1127 | { | 1131 | |
| 1128 | ptrarray_t* pa = (ptrarray_t*)((plist_data_t)((node_t)node)->data)->hashtable; | 1132 | plist_t old_item = plist_array_get_item(node, n); |
| 1129 | if (pa) { | 1133 | if (!old_item) { |
| 1130 | ptr_array_remove(pa, n); | 1134 | PLIST_ERR("item not found at index %u\n", n); |
| 1131 | } | 1135 | return PLIST_ERR_INVALID_ARG; |
| 1132 | plist_free(old_item); | 1136 | } |
| 1133 | } | 1137 | ptrarray_t* pa = (ptrarray_t*)((plist_data_t)((node_t)node)->data)->hashtable; |
| 1138 | if (pa) { | ||
| 1139 | ptr_array_remove(pa, n); | ||
| 1134 | } | 1140 | } |
| 1141 | plist_free(old_item); | ||
| 1142 | |||
| 1143 | return PLIST_ERR_SUCCESS; | ||
| 1135 | } | 1144 | } |
| 1136 | 1145 | ||
| 1137 | void plist_array_item_remove(plist_t node) | 1146 | plist_err_t plist_array_item_remove(plist_t item) |
| 1138 | { | 1147 | { |
| 1139 | plist_t father = plist_get_parent(node); | 1148 | plist_t parent = plist_get_parent(item); |
| 1140 | if (PLIST_ARRAY == plist_get_node_type(father)) | 1149 | if (PLIST_IS_ARRAY(parent)) { |
| 1141 | { | 1150 | int n = node_child_position((node_t)parent, (node_t)item); |
| 1142 | int n = node_child_position((node_t)father, (node_t)node); | 1151 | if (n < 0) return PLIST_ERR_INVALID_ARG; |
| 1143 | if (n < 0) return; | 1152 | ptrarray_t* pa = (ptrarray_t*)((plist_data_t)((node_t)parent)->data)->hashtable; |
| 1144 | ptrarray_t* pa = (ptrarray_t*)((plist_data_t)((node_t)father)->data)->hashtable; | ||
| 1145 | if (pa) { | 1153 | if (pa) { |
| 1146 | ptr_array_remove(pa, n); | 1154 | ptr_array_remove(pa, n); |
| 1147 | } | 1155 | } |
| 1148 | plist_free(node); | 1156 | plist_free(item); |
| 1149 | } | 1157 | } |
| 1158 | return PLIST_ERR_SUCCESS; | ||
| 1150 | } | 1159 | } |
| 1151 | 1160 | ||
| 1152 | typedef struct { | 1161 | typedef struct { |
| @@ -1189,8 +1198,7 @@ void plist_array_free_iter(plist_array_iter iter) | |||
| 1189 | uint32_t plist_dict_get_size(plist_t node) | 1198 | uint32_t plist_dict_get_size(plist_t node) |
| 1190 | { | 1199 | { |
| 1191 | uint32_t ret = 0; | 1200 | uint32_t ret = 0; |
| 1192 | if (node && PLIST_DICT == plist_get_node_type(node)) | 1201 | if (PLIST_IS_DICT(node)) { |
| 1193 | { | ||
| 1194 | ret = node_n_children((node_t)node) / 2; | 1202 | ret = node_n_children((node_t)node) / 2; |
| 1195 | } | 1203 | } |
| 1196 | return ret; | 1204 | return ret; |
| @@ -1253,9 +1261,8 @@ void plist_dict_free_iter(plist_dict_iter iter) | |||
| 1253 | 1261 | ||
| 1254 | void plist_dict_get_item_key(plist_t node, char **key) | 1262 | void plist_dict_get_item_key(plist_t node, char **key) |
| 1255 | { | 1263 | { |
| 1256 | plist_t father = plist_get_parent(node); | 1264 | plist_t parent = plist_get_parent(node); |
| 1257 | if (PLIST_DICT == plist_get_node_type(father)) | 1265 | if (PLIST_IS_DICT(parent)) { |
| 1258 | { | ||
| 1259 | plist_get_key_val( (plist_t) node_prev_sibling((node_t)node), key); | 1266 | plist_get_key_val( (plist_t) node_prev_sibling((node_t)node), key); |
| 1260 | } | 1267 | } |
| 1261 | } | 1268 | } |
| @@ -1263,9 +1270,8 @@ void plist_dict_get_item_key(plist_t node, char **key) | |||
| 1263 | plist_t plist_dict_item_get_key(plist_t node) | 1270 | plist_t plist_dict_item_get_key(plist_t node) |
| 1264 | { | 1271 | { |
| 1265 | plist_t ret = NULL; | 1272 | plist_t ret = NULL; |
| 1266 | plist_t father = plist_get_parent(node); | 1273 | plist_t parent = plist_get_parent(node); |
| 1267 | if (PLIST_DICT == plist_get_node_type(father)) | 1274 | if (PLIST_IS_DICT(parent)) { |
| 1268 | { | ||
| 1269 | ret = (plist_t)node_prev_sibling((node_t)node); | 1275 | ret = (plist_t)node_prev_sibling((node_t)node); |
| 1270 | } | 1276 | } |
| 1271 | return ret; | 1277 | return ret; |
| @@ -1311,17 +1317,17 @@ plist_t plist_dict_get_item(plist_t node, const char* key) | |||
| 1311 | return ret; | 1317 | return ret; |
| 1312 | } | 1318 | } |
| 1313 | 1319 | ||
| 1314 | void plist_dict_set_item(plist_t node, const char* key, plist_t item) | 1320 | plist_err_t plist_dict_set_item(plist_t node, const char* key, plist_t item) |
| 1315 | { | 1321 | { |
| 1316 | if (!PLIST_IS_DICT(node) || !key || !item) { | 1322 | if (!PLIST_IS_DICT(node) || !key || !item) { |
| 1317 | PLIST_ERR("invalid argument passed to %s (node=%p, key=%p, item=%p)\n", __func__, node, key, item); | 1323 | PLIST_ERR("invalid argument passed to %s (node=%p, key=%p, item=%p)\n", __func__, node, key, item); |
| 1318 | return; | 1324 | return PLIST_ERR_INVALID_ARG; |
| 1319 | } | 1325 | } |
| 1320 | node_t it = (node_t)item; | 1326 | node_t it = (node_t)item; |
| 1321 | if (it->parent != NULL) { | 1327 | if (it->parent != NULL) { |
| 1322 | assert(it->parent == NULL && "item already has a parent"); | 1328 | assert(it->parent == NULL && "item already has a parent"); |
| 1323 | PLIST_ERR("%s: item already has a parent\n", __func__); | 1329 | PLIST_ERR("%s: item already has a parent\n", __func__); |
| 1324 | return; | 1330 | return PLIST_ERR_INVALID_ARG; |
| 1325 | } | 1331 | } |
| 1326 | 1332 | ||
| 1327 | hashtable_t *ht = (hashtable_t*)((plist_data_t)((node_t)node)->data)->hashtable; | 1333 | hashtable_t *ht = (hashtable_t*)((plist_data_t)((node_t)node)->data)->hashtable; |
| @@ -1335,18 +1341,18 @@ void plist_dict_set_item(plist_t node, const char* key, plist_t item) | |||
| 1335 | node_t old_key = node_prev_sibling(old_val); | 1341 | node_t old_key = node_prev_sibling(old_val); |
| 1336 | if (!old_key) { | 1342 | if (!old_key) { |
| 1337 | PLIST_ERR("%s: corrupt dict (value without key)\n", __func__); | 1343 | PLIST_ERR("%s: corrupt dict (value without key)\n", __func__); |
| 1338 | return; | 1344 | return PLIST_ERR_UNKNOWN; |
| 1339 | } | 1345 | } |
| 1340 | if (!PLIST_IS_KEY((plist_t)old_key)) { | 1346 | if (!PLIST_IS_KEY((plist_t)old_key)) { |
| 1341 | PLIST_ERR("%s: corrupt dict ('key' node is not PLIST_KEY\n", __func__); | 1347 | PLIST_ERR("%s: corrupt dict ('key' node is not PLIST_KEY\n", __func__); |
| 1342 | return; | 1348 | return PLIST_ERR_UNKNOWN; |
| 1343 | } | 1349 | } |
| 1344 | 1350 | ||
| 1345 | // detach old value (do NOT free yet) | 1351 | // detach old value (do NOT free yet) |
| 1346 | int idx = node_detach((node_t)node, old_val); | 1352 | int idx = node_detach((node_t)node, old_val); |
| 1347 | if (idx < 0) { | 1353 | if (idx < 0) { |
| 1348 | PLIST_ERR("%s: failed to detach old value (err=%d)\n", __func__, idx); | 1354 | PLIST_ERR("%s: failed to detach old value (err=%d)\n", __func__, idx); |
| 1349 | return; | 1355 | return PLIST_ERR_UNKNOWN; |
| 1350 | } | 1356 | } |
| 1351 | 1357 | ||
| 1352 | // insert new value at same position | 1358 | // insert new value at same position |
| @@ -1358,7 +1364,7 @@ void plist_dict_set_item(plist_t node, const char* key, plist_t item) | |||
| 1358 | hash_table_insert(ht, ((node_t)old_key)->data, old_item); | 1364 | hash_table_insert(ht, ((node_t)old_key)->data, old_item); |
| 1359 | } | 1365 | } |
| 1360 | PLIST_ERR("%s: failed to replace dict value (err=%d)\n", __func__, r); | 1366 | PLIST_ERR("%s: failed to replace dict value (err=%d)\n", __func__, r); |
| 1361 | return; | 1367 | return PLIST_ERR_UNKNOWN; |
| 1362 | } | 1368 | } |
| 1363 | key_node = old_key; | 1369 | key_node = old_key; |
| 1364 | 1370 | ||
| @@ -1372,13 +1378,13 @@ void plist_dict_set_item(plist_t node, const char* key, plist_t item) | |||
| 1372 | } else { | 1378 | } else { |
| 1373 | // --- INSERT NEW KEY/VALUE PAIR --- | 1379 | // --- INSERT NEW KEY/VALUE PAIR --- |
| 1374 | key_node = plist_new_key(key); | 1380 | key_node = plist_new_key(key); |
| 1375 | if (!key_node) return; | 1381 | if (!key_node) return PLIST_ERR_NO_MEM; |
| 1376 | 1382 | ||
| 1377 | int r = node_attach((node_t)node, (node_t)key_node); | 1383 | int r = node_attach((node_t)node, (node_t)key_node); |
| 1378 | if (r != NODE_ERR_SUCCESS) { | 1384 | if (r != NODE_ERR_SUCCESS) { |
| 1379 | plist_free_node((node_t)key_node); | 1385 | plist_free_node((node_t)key_node); |
| 1380 | PLIST_ERR("%s: failed to attach dict key (err=%d)\n", __func__, r); | 1386 | PLIST_ERR("%s: failed to attach dict key (err=%d)\n", __func__, r); |
| 1381 | return; | 1387 | return PLIST_ERR_UNKNOWN; |
| 1382 | } | 1388 | } |
| 1383 | r = node_attach((node_t)node, (node_t)item); | 1389 | r = node_attach((node_t)node, (node_t)item); |
| 1384 | if (r != NODE_ERR_SUCCESS) { | 1390 | if (r != NODE_ERR_SUCCESS) { |
| @@ -1386,7 +1392,7 @@ void plist_dict_set_item(plist_t node, const char* key, plist_t item) | |||
| 1386 | node_detach((node_t)node, (node_t)key_node); | 1392 | node_detach((node_t)node, (node_t)key_node); |
| 1387 | plist_free_node((node_t)key_node); | 1393 | plist_free_node((node_t)key_node); |
| 1388 | PLIST_ERR("%s: failed to attach dict value (err=%d)\n", __func__, r); | 1394 | PLIST_ERR("%s: failed to attach dict value (err=%d)\n", __func__, r); |
| 1389 | return; | 1395 | return PLIST_ERR_UNKNOWN; |
| 1390 | } | 1396 | } |
| 1391 | 1397 | ||
| 1392 | if (ht) { | 1398 | if (ht) { |
| @@ -1406,37 +1412,44 @@ void plist_dict_set_item(plist_t node, const char* key, plist_t item) | |||
| 1406 | ((plist_data_t)((node_t)node)->data)->hashtable = ht; | 1412 | ((plist_data_t)((node_t)node)->data)->hashtable = ht; |
| 1407 | } | 1413 | } |
| 1408 | } | 1414 | } |
| 1415 | return PLIST_ERR_SUCCESS; | ||
| 1409 | } | 1416 | } |
| 1410 | 1417 | ||
| 1411 | void plist_dict_remove_item(plist_t node, const char* key) | 1418 | plist_err_t plist_dict_remove_item(plist_t node, const char* key) |
| 1412 | { | 1419 | { |
| 1413 | if (node && PLIST_DICT == plist_get_node_type(node)) | 1420 | if (!PLIST_IS_DICT(node) || !key) { |
| 1414 | { | 1421 | PLIST_ERR("invalid argument passed to %s (node=%p, key=%p)\n", __func__, node, key); |
| 1415 | plist_t old_item = plist_dict_get_item(node, key); | 1422 | return PLIST_ERR_INVALID_ARG; |
| 1416 | if (old_item) | 1423 | } |
| 1417 | { | 1424 | |
| 1418 | plist_t key_node = node_prev_sibling((node_t)old_item); | 1425 | plist_t old_item = plist_dict_get_item(node, key); |
| 1419 | hashtable_t* ht = (hashtable_t*)((plist_data_t)((node_t)node)->data)->hashtable; | 1426 | if (!old_item) { |
| 1420 | if (ht) { | 1427 | PLIST_ERR("item not found for key '%s'\n", key); |
| 1421 | hash_table_remove(ht, ((node_t)key_node)->data); | 1428 | return PLIST_ERR_INVALID_ARG; |
| 1422 | } | 1429 | } |
| 1423 | plist_free(key_node); | 1430 | |
| 1424 | plist_free(old_item); | 1431 | plist_t key_node = node_prev_sibling((node_t)old_item); |
| 1425 | } | 1432 | hashtable_t* ht = (hashtable_t*)((plist_data_t)((node_t)node)->data)->hashtable; |
| 1433 | if (ht) { | ||
| 1434 | hash_table_remove(ht, ((node_t)key_node)->data); | ||
| 1426 | } | 1435 | } |
| 1436 | plist_free(key_node); | ||
| 1437 | plist_free(old_item); | ||
| 1438 | |||
| 1439 | return PLIST_ERR_SUCCESS; | ||
| 1427 | } | 1440 | } |
| 1428 | 1441 | ||
| 1429 | void plist_dict_merge(plist_t *target, plist_t source) | 1442 | plist_err_t plist_dict_merge(plist_t *target, plist_t source) |
| 1430 | { | 1443 | { |
| 1431 | if (!target || !*target || (plist_get_node_type(*target) != PLIST_DICT) || !source || (plist_get_node_type(source) != PLIST_DICT)) | 1444 | if (!target || !PLIST_IS_DICT(*target) || !PLIST_IS_DICT(source)) |
| 1432 | return; | 1445 | return PLIST_ERR_INVALID_ARG; |
| 1433 | 1446 | ||
| 1434 | char* key = NULL; | 1447 | char* key = NULL; |
| 1435 | plist_dict_iter it = NULL; | 1448 | plist_dict_iter it = NULL; |
| 1436 | plist_t subnode = NULL; | 1449 | plist_t subnode = NULL; |
| 1437 | plist_dict_new_iter(source, &it); | 1450 | plist_dict_new_iter(source, &it); |
| 1438 | if (!it) | 1451 | if (!it) |
| 1439 | return; | 1452 | return PLIST_ERR_NO_MEM; |
| 1440 | 1453 | ||
| 1441 | do { | 1454 | do { |
| 1442 | plist_dict_next_item(source, it, &key, &subnode); | 1455 | plist_dict_next_item(source, it, &key, &subnode); |
| @@ -1448,6 +1461,7 @@ void plist_dict_merge(plist_t *target, plist_t source) | |||
| 1448 | key = NULL; | 1461 | key = NULL; |
| 1449 | } while (1); | 1462 | } while (1); |
| 1450 | free(it); | 1463 | free(it); |
| 1464 | return PLIST_ERR_SUCCESS; | ||
| 1451 | } | 1465 | } |
| 1452 | 1466 | ||
| 1453 | uint8_t plist_dict_get_bool(plist_t dict, const char *key) | 1467 | uint8_t plist_dict_get_bool(plist_t dict, const char *key) |
| @@ -2010,8 +2024,8 @@ static plist_err_t plist_set_element_val(plist_t node, plist_type type, const vo | |||
| 2010 | 2024 | ||
| 2011 | void plist_set_key_val(plist_t node, const char *val) | 2025 | void plist_set_key_val(plist_t node, const char *val) |
| 2012 | { | 2026 | { |
| 2013 | plist_t father = plist_get_parent(node); | 2027 | plist_t parent = plist_get_parent(node); |
| 2014 | plist_t item = plist_dict_get_item(father, val); | 2028 | plist_t item = plist_dict_get_item(parent, val); |
| 2015 | if (item) { | 2029 | if (item) { |
| 2016 | return; | 2030 | return; |
| 2017 | } | 2031 | } |
