Bläddra i källkod

Merge pull request #158 from DaveGamble/case-sensitive

Provide case sensitive versions of all functions
Max Bruckner 8 år sedan
förälder
incheckning
a1a860cd31
4 ändrade filer med 192 tillägg och 84 borttagningar
  1. 3 3
      README.md
  2. 95 80
      cJSON.c
  3. 6 1
      cJSON.h
  4. 88 0
      tests/misc_tests.c

+ 3 - 3
README.md

@@ -138,8 +138,8 @@ This is an object. We're in C. We don't have objects. But we do have structs.
 What's the framerate?
 
 ```c
-cJSON *format = cJSON_GetObjectItem(root, "format");
-cJSON *framerate_item = cJSON_GetObjectItem(format, "frame rate");
+cJSON *format = cJSON_GetObjectItemCaseSensitive(root, "format");
+cJSON *framerate_item = cJSON_GetObjectItemCaseSensitive(format, "frame rate");
 double framerate = 0;
 if (cJSON_IsNumber(framerate_item))
 {
@@ -150,7 +150,7 @@ if (cJSON_IsNumber(framerate_item))
 Want to change the framerate?
 
 ```c
-cJSON *framerate_item = cJSON_GetObjectItem(format, "frame rate");
+cJSON *framerate_item = cJSON_GetObjectItemCaseSensitive(format, "frame rate");
 cJSON_SetNumberValue(framerate_item, 25);
 ```
 

+ 95 - 80
cJSON.c

@@ -1665,16 +1665,33 @@ CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array)
     return (int)i;
 }
 
-CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int item)
+static cJSON* get_array_item(const cJSON *array, size_t index)
 {
-    cJSON *c = array ? array->child : NULL;
-    while (c && item > 0)
+    cJSON *current_child = NULL;
+
+    if (array == NULL)
     {
-        item--;
-        c = c->next;
+        return NULL;
+    }
+
+    current_child = array->child;
+    while ((current_child != NULL) && (index > 0))
+    {
+        index--;
+        current_child = current_child->next;
+    }
+
+    return current_child;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index)
+{
+    if (index < 0)
+    {
+        return NULL;
     }
 
-    return c;
+    return get_array_item(array, (size_t)index);
 }
 
 static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive)
@@ -1814,37 +1831,36 @@ CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *str
     cJSON_AddItemToObject(object, string, create_reference(item, &global_hooks));
 }
 
-static cJSON *DetachItemFromArray(cJSON *array, size_t which)
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item)
 {
-    cJSON *c = array->child;
-    while (c && (which > 0))
+    if ((parent == NULL) || (item == NULL))
     {
-        c = c->next;
-        which--;
-    }
-    if (!c)
-    {
-        /* item doesn't exist */
         return NULL;
     }
-    if (c->prev)
+
+    if (item->prev != NULL)
     {
         /* not the first element */
-        c->prev->next = c->next;
+        item->prev->next = item->next;
     }
-    if (c->next)
+    if (item->next != NULL)
     {
-        c->next->prev = c->prev;
+        /* not the last element */
+        item->next->prev = item->prev;
     }
-    if (c==array->child)
+
+    if (item == parent->child)
     {
-        array->child = c->next;
+        /* first element */
+        parent->child = item->next;
     }
     /* make sure the detached item doesn't point anywhere anymore */
-    c->prev = c->next = NULL;
+    item->prev = NULL;
+    item->next = NULL;
 
-    return c;
+    return item;
 }
+
 CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which)
 {
     if (which < 0)
@@ -1852,7 +1868,7 @@ CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which)
         return NULL;
     }
 
-    return DetachItemFromArray(array, (size_t)which);
+    return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which));
 }
 
 CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which)
@@ -1862,19 +1878,16 @@ CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which)
 
 CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string)
 {
-    size_t i = 0;
-    cJSON *c = object->child;
-    while (c && (case_insensitive_strcmp((unsigned char*)c->string, (const unsigned char*)string) != 0))
-    {
-        i++;
-        c = c->next;
-    }
-    if (c)
-    {
-        return DetachItemFromArray(object, i);
-    }
+    cJSON *to_detach = cJSON_GetObjectItem(object, string);
 
-    return NULL;
+    return cJSON_DetachItemViaPointer(object, to_detach);
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string)
+{
+    cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string);
+
+    return cJSON_DetachItemViaPointer(object, to_detach);
 }
 
 CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string)
@@ -1882,24 +1895,32 @@ CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string)
     cJSON_Delete(cJSON_DetachItemFromObject(object, string));
 }
 
+CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string)
+{
+    cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string));
+}
+
 /* Replace array/object items with new ones. */
 CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem)
 {
-    cJSON *c = array->child;
-    while (c && (which > 0))
+    cJSON *after_inserted = NULL;
+
+    if (which < 0)
     {
-        c = c->next;
-        which--;
+        return;
     }
-    if (!c)
+
+    after_inserted = get_array_item(array, (size_t)which);
+    if (after_inserted == NULL)
     {
         cJSON_AddItemToArray(array, newitem);
         return;
     }
-    newitem->next = c;
-    newitem->prev = c->prev;
-    c->prev = newitem;
-    if (c == array->child)
+
+    newitem->next = after_inserted;
+    newitem->prev = after_inserted->prev;
+    after_inserted->prev = newitem;
+    if (after_inserted == array->child)
     {
         array->child = newitem;
     }
@@ -1909,35 +1930,41 @@ CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newit
     }
 }
 
-static void ReplaceItemInArray(cJSON *array, size_t which, cJSON *newitem)
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement)
 {
-    cJSON *c = array->child;
-    while (c && (which > 0))
+    if ((parent == NULL) || (replacement == NULL))
     {
-        c = c->next;
-        which--;
+        return false;
     }
-    if (!c)
+
+    if (replacement == item)
     {
-        return;
+        return true;
     }
-    newitem->next = c->next;
-    newitem->prev = c->prev;
-    if (newitem->next)
+
+    replacement->next = item->next;
+    replacement->prev = item->prev;
+
+    if (replacement->next != NULL)
     {
-        newitem->next->prev = newitem;
+        replacement->next->prev = replacement;
     }
-    if (c == array->child)
+    if (replacement->prev != NULL)
     {
-        array->child = newitem;
+        replacement->prev->next = replacement;
     }
-    else
+    if (parent->child == item)
     {
-        newitem->prev->next = newitem;
+        parent->child = replacement;
     }
-    c->next = c->prev = NULL;
-    cJSON_Delete(c);
+
+    item->next = NULL;
+    item->prev = NULL;
+    cJSON_Delete(item);
+
+    return true;
 }
+
 CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)
 {
     if (which < 0)
@@ -1945,29 +1972,17 @@ CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newi
         return;
     }
 
-    ReplaceItemInArray(array, (size_t)which, newitem);
+    cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem);
 }
 
 CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)
 {
-    size_t i = 0;
-    cJSON *c = object->child;
-    while(c && (case_insensitive_strcmp((unsigned char*)c->string, (const unsigned char*)string) != 0))
-    {
-        i++;
-        c = c->next;
-    }
-    if(c)
-    {
-        /* free the old string if not const */
-        if (!(newitem->type & cJSON_StringIsConst) && newitem->string)
-        {
-             global_hooks.deallocate(newitem->string);
-        }
+    cJSON_ReplaceItemViaPointer(object, cJSON_GetObjectItem(object, string), newitem);
+}
 
-        newitem->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
-        ReplaceItemInArray(object, i, newitem);
-    }
+CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem)
+{
+    cJSON_ReplaceItemViaPointer(object, cJSON_GetObjectItemCaseSensitive(object, string), newitem);
 }
 
 /* Create basic types: */

+ 6 - 1
cJSON.h

@@ -153,7 +153,7 @@ CJSON_PUBLIC(void) cJSON_Delete(cJSON *c);
 /* Returns the number of items in an array (or object). */
 CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
 /* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
-CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int item);
+CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
 /* Get item "string" from object. Case insensitive. */
 CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON *object, const char *string);
 CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
@@ -203,15 +203,20 @@ CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
 CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
 
 /* Remove/Detatch items from Arrays/Objects. */
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
 CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
 CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
 CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
 CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
+CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
 
 /* Update array items. */
 CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
 CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
 CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
+CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
 
 /* Duplicate a cJSON item */
 CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);

+ 88 - 0
tests/misc_tests.c

@@ -218,6 +218,92 @@ static void cjson_set_number_value_should_set_numbers(void)
     TEST_ASSERT_EQUAL_DOUBLE(-1 + (double)INT_MIN, number->valuedouble);
 }
 
+static void cjson_detach_item_via_pointer_should_detach_items(void)
+{
+    cJSON list[4];
+    cJSON parent[1];
+
+    memset(list, '\0', sizeof(list));
+
+    /* link the list */
+    list[0].next = &(list[1]);
+    list[1].next = &(list[2]);
+    list[2].next = &(list[3]);
+
+    list[3].prev = &(list[2]);
+    list[2].prev = &(list[1]);
+    list[1].prev = &(list[0]);
+
+    parent->child = &list[0];
+
+    /* detach in the middle (list[1]) */
+    TEST_ASSERT_TRUE_MESSAGE(cJSON_DetachItemViaPointer(parent, &(list[1])) == &(list[1]), "Failed to detach in the middle.");
+    TEST_ASSERT_TRUE_MESSAGE((list[1].prev == NULL) && (list[1].next == NULL), "Didn't set pointers of detached item to NULL.");
+    TEST_ASSERT_TRUE((list[0].next == &(list[2])) && (list[2].prev == &(list[0])));
+
+    /* detach beginning (list[0]) */
+    TEST_ASSERT_TRUE_MESSAGE(cJSON_DetachItemViaPointer(parent, &(list[0])) == &(list[0]), "Failed to detach beginning.");
+    TEST_ASSERT_TRUE_MESSAGE((list[0].prev == NULL) && (list[0].next == NULL), "Didn't set pointers of detached item to NULL.");
+    TEST_ASSERT_TRUE_MESSAGE((list[2].prev == NULL) && (parent->child == &(list[2])), "Didn't set the new beginning.");
+
+    /* detach end (list[3])*/
+    TEST_ASSERT_TRUE_MESSAGE(cJSON_DetachItemViaPointer(parent, &(list[3])) == &(list[3]), "Failed to detach end.");
+    TEST_ASSERT_TRUE_MESSAGE((list[3].prev == NULL) && (list[3].next == NULL), "Didn't set pointers of detached item to NULL.");
+    TEST_ASSERT_TRUE_MESSAGE((list[2].next == NULL) && (parent->child == &(list[2])), "Didn't set the new end");
+
+    /* detach single item (list[2]) */
+    TEST_ASSERT_TRUE_MESSAGE(cJSON_DetachItemViaPointer(parent, &list[2]) == &list[2], "Failed to detach single item.");
+    TEST_ASSERT_TRUE_MESSAGE((list[2].prev == NULL) && (list[2].next == NULL), "Didn't set pointers of detached item to NULL.");
+    TEST_ASSERT_NULL_MESSAGE(parent->child, "Child of the parent wasn't set to NULL.");
+}
+
+static void cjson_replace_item_via_pointer_should_replace_items(void)
+{
+    cJSON replacements[3];
+    cJSON *beginning = NULL;
+    cJSON *middle = NULL;
+    cJSON *end = NULL;
+    cJSON *array = NULL;
+
+    beginning = cJSON_CreateNull();
+    TEST_ASSERT_NOT_NULL(beginning);
+    middle = cJSON_CreateNull();
+    TEST_ASSERT_NOT_NULL(middle);
+    end = cJSON_CreateNull();
+    TEST_ASSERT_NOT_NULL(end);
+
+    array = cJSON_CreateArray();
+    TEST_ASSERT_NOT_NULL(array);
+
+    cJSON_AddItemToArray(array, beginning);
+    cJSON_AddItemToArray(array, middle);
+    cJSON_AddItemToArray(array, end);
+
+
+    memset(replacements, '\0', sizeof(replacements));
+
+    /* replace beginning */
+    TEST_ASSERT_TRUE(cJSON_ReplaceItemViaPointer(array, beginning, &(replacements[0])));
+    TEST_ASSERT_NULL(replacements[0].prev);
+    TEST_ASSERT_TRUE(replacements[0].next == middle);
+    TEST_ASSERT_TRUE(middle->prev == &(replacements[0]));
+    TEST_ASSERT_TRUE(array->child == &(replacements[0]));
+
+    /* replace middle */
+    TEST_ASSERT_TRUE(cJSON_ReplaceItemViaPointer(array, middle, &(replacements[1])));
+    TEST_ASSERT_TRUE(replacements[1].prev == &(replacements[0]));
+    TEST_ASSERT_TRUE(replacements[1].next == end);
+    TEST_ASSERT_TRUE(end->prev == &(replacements[1]));
+
+    /* replace end */
+    TEST_ASSERT_TRUE(cJSON_ReplaceItemViaPointer(array, end, &(replacements[2])));
+    TEST_ASSERT_TRUE(replacements[2].prev == &(replacements[1]));
+    TEST_ASSERT_NULL(replacements[2].next);
+    TEST_ASSERT_TRUE(replacements[1].next == &(replacements[2]));
+
+    cJSON_free(array);
+}
+
 int main(void)
 {
     UNITY_BEGIN();
@@ -229,6 +315,8 @@ int main(void)
     RUN_TEST(typecheck_functions_should_check_type);
     RUN_TEST(cjson_should_not_parse_to_deeply_nested_jsons);
     RUN_TEST(cjson_set_number_value_should_set_numbers);
+    RUN_TEST(cjson_detach_item_via_pointer_should_detach_items);
+    RUN_TEST(cjson_replace_item_via_pointer_should_replace_items);
 
     return UNITY_END();
 }