Bladeren bron

Defined malloc and free as macros, also small refractoring.

And changes to the readme file.
Krzysztof Gabis 13 jaren geleden
bovenliggende
commit
120f5a08da
3 gewijzigde bestanden met toevoegingen van 93 en 96 verwijderingen
  1. 13 10
      README.md
  2. 67 62
      parson.c
  3. 13 24
      tests.c

+ 13 - 10
README.md

@@ -1,8 +1,8 @@
 ##About
-Parson is a small [json](http://json.org) parser and reader written in C.  
+Parson is a lighweight [json](http://json.org) parser and reader written in C.  
 
 ##Features
-* Small (only 2 files)
+* Lightweight (only 2 files)
 * Simple API
 * Addressing json values with dot notation (similiar to C structs or objects in most OO languages, e.g. "objectA.objectB.value")
 * C89 compatible
@@ -15,10 +15,12 @@ git clone https://github.com/kgabis/parson.git
 ```
 and copy parson.h and parson.c to you source code tree.
 
+Run tests.sh to compile and run tests.
+
 ##Example
 Here is a function, which prints basic commit info (date, sha and author) from a github repository.  It's also included in tests.c file, you can just uncomment and run it.
 ```c
-void print_commit_info(const char *username, const char * repo) {
+void print_commit_info(const char *username, const char *repo) {
     JSON_Value *root_value;
     JSON_Array *commits;
     JSON_Object *commit;
@@ -26,21 +28,21 @@ void print_commit_info(const char *username, const char * repo) {
     
     char curl_command[512];
     char cleanup_command[256];
-    char *output_filename = "commits.json";
+    char output_filename[] = "commits.json";
     
     /* it ain't pretty, but it's not a libcurl tutorial */
-    sprintf(curl_command, "curl \"https://api.github.com/repos/%s/%s/commits\"\
-            > %s 2> /dev/null", username, repo, output_filename);
+    sprintf(curl_command, "curl -s \"https://api.github.com/repos/%s/%s/commits\"\
+            > %s", username, repo, output_filename);
     sprintf(cleanup_command, "rm -f %s", output_filename);
     system(curl_command);
     
     /* parsing json and validating output */
-    root_value = json_parse_file(output_filename);    
-    if (root_value == NULL || json_value_get_type(root_value) != JSONArray) {        
+    root_value = json_parse_file(output_filename);
+    if (root_value == NULL || json_value_get_type(root_value) != JSONArray) {
         system(cleanup_command);
         return;
     }
-        
+    
     /* getting array from root value and printing commit info */
     commits = json_value_get_array(root_value);
     printf("%-10.10s %-10.10s %s\n", "Date", "SHA", "Author");
@@ -56,8 +58,9 @@ void print_commit_info(const char *username, const char * repo) {
     json_value_free(root_value);
     system(cleanup_command);
 }
+
 ```
-Calling ```print_commit_info("torvalds", "linux");``` prints:  
+Calling ```print_commits_info("torvalds", "linux");``` prints:  
 ```
 Date       SHA        Author
 2012-10-15 dd8e8c4a2c David Rientjes

+ 67 - 62
parson.c

@@ -31,6 +31,9 @@
 #define MAX_NESTING 19
 #define sizeof_token(a) (sizeof(a) - 1)
 
+#define parson_malloc(a) malloc(a)
+#define parson_free(a) free(a)
+
 /* Type definitions */
 union json_value_value {
     const char * string;
@@ -95,12 +98,14 @@ static JSON_Value * parse_value(const char **string, size_t depth);
 
 /* JSON Object */
 static JSON_Object * json_object_init(void) {
-    JSON_Object *new_obj = (JSON_Object*)malloc(sizeof(JSON_Object));
+    JSON_Object *new_obj = (JSON_Object*)parson_malloc(sizeof(JSON_Object));
     if (!new_obj) { return NULL; }
-    new_obj->names = (const char**)malloc(sizeof(char*) * STARTING_CAPACITY);
-    if (!new_obj->names) { free(new_obj); return NULL; }
-    new_obj->values = (JSON_Value**)malloc(sizeof(JSON_Value*) * STARTING_CAPACITY);
-    if (!new_obj->names) { free(new_obj->names); free(new_obj); return NULL; }
+    new_obj->names = (const char**)parson_malloc(sizeof(char*) *
+                                                            STARTING_CAPACITY);
+    if (!new_obj->names) { parson_free(new_obj); return NULL; }
+    new_obj->values = (JSON_Value**)parson_malloc(sizeof(JSON_Value*) *
+                                                            STARTING_CAPACITY);
+    if (!new_obj->names) { parson_free(new_obj->names); parson_free(new_obj); return NULL; }
     new_obj->capacity = STARTING_CAPACITY;
     new_obj->count = 0;
     return new_obj;
@@ -111,8 +116,10 @@ static int json_object_add(JSON_Object *object, const char *name, JSON_Value *va
     if (object->count >= object->capacity) {
         size_t new_capacity = object->capacity * 2;
         if (new_capacity > MAX_CAPACITY) { return 0; }
-        object->names = (const char**)realloc((void*)object->names, new_capacity * sizeof(char*));
-        object->values = (JSON_Value**)realloc(object->values, new_capacity * sizeof(JSON_Value*));
+        object->names = (const char**)realloc((void*)object->names,
+                                              new_capacity * sizeof(char*));
+        object->values = (JSON_Value**)realloc(object->values,
+                                               new_capacity * sizeof(JSON_Value*));
         object->capacity = new_capacity;
     }    
     if (json_object_get_value(object, name) != NULL) { return 0; }    
@@ -126,20 +133,21 @@ static int json_object_add(JSON_Object *object, const char *name, JSON_Value *va
 static void json_object_free(JSON_Object *object) {
     size_t i;
     for (i = 0; i < object->count; i++) {
-        free((void*)object->names[i]);
+        parson_free((void*)object->names[i]);
         json_value_free(object->values[i]);
     }
-    free((void*)object->names);
-    free(object->values);
-    free(object);
+    parson_free((void*)object->names);
+    parson_free(object->values);
+    parson_free(object);
 }
 
 /* JSON Array */
 static JSON_Array * json_array_init(void) {
-    JSON_Array *new_array = (JSON_Array*)malloc(sizeof(JSON_Array));
+    JSON_Array *new_array = (JSON_Array*)parson_malloc(sizeof(JSON_Array));
     if (!new_array) { return NULL; }
-    new_array->items = (JSON_Value**)malloc(STARTING_CAPACITY * sizeof(JSON_Value*));
-    if (!new_array->items) { free(new_array); return NULL; }
+    new_array->items = (JSON_Value**)parson_malloc(STARTING_CAPACITY *
+                                                          sizeof(JSON_Value*));
+    if (!new_array->items) { parson_free(new_array); return NULL; }
     new_array->capacity = STARTING_CAPACITY;
     new_array->count = 0;
     return new_array;
@@ -149,7 +157,8 @@ static int json_array_add(JSON_Array *array, JSON_Value *value) {
     if (array->count >= array->capacity) {
         size_t new_capacity = array->capacity * 2;
         if (new_capacity > MAX_CAPACITY) { return 0; }
-        array->items = (JSON_Value**)realloc(array->items, new_capacity * sizeof(JSON_Value*));
+        array->items = (JSON_Value**)realloc(array->items,
+                                             new_capacity * sizeof(JSON_Value*));
         array->capacity = new_capacity;
     }
     array->items[array->count] = value;
@@ -162,31 +171,31 @@ static void json_array_free(JSON_Array *array) {
     for (i = 0; i < array->count; i++) {
         json_value_free(array->items[i]);
     }
-    free(array->items);
-    free(array);
+    parson_free(array->items);
+    parson_free(array);
 }
 
 /* JSON Value */
 static JSON_Value * json_value_init_object(void) {
-    JSON_Value *new_value = (JSON_Value*)malloc(sizeof(JSON_Value));
+    JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
     if (!new_value) { return NULL; }
     new_value->type = JSONObject;
     new_value->value.object = json_object_init();
-    if (!new_value->value.object) { free(new_value); return NULL; }
+    if (!new_value->value.object) { parson_free(new_value); return NULL; }
     return new_value;
 }
 
 static JSON_Value * json_value_init_array(void) {
-    JSON_Value *new_value = (JSON_Value*)malloc(sizeof(JSON_Value));
+    JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
     if (!new_value) { return NULL; }
     new_value->type = JSONArray;
     new_value->value.array = json_array_init();
-    if (!new_value->value.array) { free(new_value); return NULL; }
+    if (!new_value->value.array) { parson_free(new_value); return NULL; }
     return new_value;
 }
 
 static JSON_Value * json_value_init_string(const char *string) {
-    JSON_Value *new_value = (JSON_Value*)malloc(sizeof(JSON_Value));
+    JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
     if (!new_value) { return NULL; }
     new_value->type = JSONString;
     new_value->value.string = string;
@@ -194,7 +203,7 @@ static JSON_Value * json_value_init_string(const char *string) {
 }
 
 static JSON_Value * json_value_init_number(double number) {
-    JSON_Value *new_value = (JSON_Value*)malloc(sizeof(JSON_Value));
+    JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
     if (!new_value) { return NULL; }
     new_value->type = JSONNumber;
     new_value->value.number = number;
@@ -202,7 +211,7 @@ static JSON_Value * json_value_init_number(double number) {
 }
 
 static JSON_Value * json_value_init_boolean(int boolean) {
-    JSON_Value *new_value = (JSON_Value*)malloc(sizeof(JSON_Value));
+    JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
     if (!new_value) { return NULL; }
     new_value->type = JSONBoolean;
     new_value->value.boolean = boolean;
@@ -210,7 +219,7 @@ static JSON_Value * json_value_init_boolean(int boolean) {
 }
 
 static JSON_Value * json_value_init_null(void) {
-    JSON_Value *new_value = (JSON_Value*)malloc(sizeof(JSON_Value));
+    JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value));
     if (!new_value) { return NULL; }
     new_value->type = JSONNull;
     return new_value;
@@ -218,7 +227,7 @@ static JSON_Value * json_value_init_null(void) {
 
 /* Parser */
 char * parson_strndup(const char *string, size_t n) {
-    char *output_string = (char*)malloc(n + 1);
+    char *output_string = (char*)parson_malloc(n + 1);
     if (!output_string) { return NULL; }
     output_string[n] = '\0';
     strncpy(output_string, string, n);
@@ -239,8 +248,8 @@ static const char * skip_string(const char *string) {
     return string + 1;
 }
 
-static char *copy_and_remove_whitespaces(const char *string) {
-    char *output_string = (char*)malloc(strlen(string) + 1);
+static char * copy_and_remove_whitespaces(const char *string) {
+    char *output_string = (char*)parson_malloc(strlen(string) + 1);
     char *output_string_ptr = output_string;
     const char *string_ptr = string;
     const char *skipped_string = NULL;
@@ -254,7 +263,7 @@ static char *copy_and_remove_whitespaces(const char *string) {
                 break;
             case '\"':
                 skipped_string = skip_string(string_ptr);
-                if (skipped_string == NULL) { free(output_string); return NULL; }
+                if (!skipped_string) { parson_free(output_string); return NULL; }
                 strncpy(output_string_ptr, string_ptr, skipped_string - string_ptr);
                 output_string_ptr = output_string_ptr + (skipped_string - string_ptr);
                 string_ptr = skipped_string;
@@ -279,7 +288,7 @@ static int is_utf_string(const char *string) {
 }
 
 static const char * parse_escaped_characters(const char *string) {
-    char *output_string = (char*)malloc(strlen(string) + 1);
+    char *output_string = (char*)parson_malloc(strlen(string) + 1);
     char *output_string_ptr = output_string;
     const char *string_ptr = string;
     char current_char;
@@ -301,7 +310,7 @@ static const char * parse_escaped_characters(const char *string) {
                     string_ptr++;
                     if (!is_utf_string(string_ptr) ||
                             sscanf(string_ptr, "%4x", &utf_val) == EOF) {
-                        free(output_string); return NULL;
+                        parson_free(output_string); return NULL;
                     }
                     if (utf_val < 0x80) {
                         current_char = utf_val;
@@ -316,12 +325,12 @@ static const char * parse_escaped_characters(const char *string) {
                     string_ptr += 3;
  					break;
                 default:
-                    free(output_string);
+                    parson_free(output_string);
                     return NULL;
                     break;
             }
         } else if (iscntrl(current_char)) { /* no control characters allowed */
-            free(output_string); 
+            parson_free(output_string); 
             return NULL;
         }                   
         *output_string_ptr = current_char;
@@ -340,11 +349,11 @@ static const char * get_string(const char **string) {
     char *quote_contents;
     const char *parsed_string;
     const char *after_closing_quote_ptr = skip_string(*string);    
-    if (after_closing_quote_ptr == NULL) { return NULL; }
+    if (!after_closing_quote_ptr) { return NULL; }
     quote_contents = parson_strndup(*string + 1, after_closing_quote_ptr - *string - 2);
     *string = after_closing_quote_ptr;
     parsed_string = parse_escaped_characters(quote_contents);
-    free(quote_contents);
+    parson_free(quote_contents);
     return (const char*)parsed_string;
 }
 
@@ -395,17 +404,17 @@ static JSON_Value * parse_object_value(const char **string, size_t depth) {
         (*string)++;
         new_value = parse_value(string, depth);
         if (!new_value) {
-            free((void*)new_key);
+            parson_free((void*)new_key);
             json_value_free(output_value);
             return NULL;
         }
         if(!json_object_add(json_value_get_object(output_value), new_key, new_value)) {
-            free((void*)new_key);
-            free(new_value);
+            parson_free((void*)new_key);
+            parson_free(new_value);
             json_value_free(output_value);
             return NULL;
         }
-        free((void*)new_key);        
+        parson_free((void*)new_key);        
         if (**string != ',') { break; }
         (*string)++;
     }
@@ -425,12 +434,12 @@ static JSON_Value * parse_array_value(const char **string, size_t depth) {
     }
     while (**string != '\0') {
         new_array_value = parse_value(string, depth);
-        if (new_array_value == NULL) {
+        if (!new_array_value) {
             json_value_free(output_value);
             return NULL;
         }
         if(!json_array_add(json_value_get_array(output_value), new_array_value)) {
-            free(new_array_value);
+            parson_free(new_array_value);
             json_value_free(output_value);
             return NULL;
         }
@@ -447,7 +456,7 @@ static JSON_Value * parse_array_value(const char **string, size_t depth) {
 
 static JSON_Value * parse_string_value(const char **string) {
     const char *new_string = get_string(string);
-    if (new_string == NULL) { return NULL; }
+    if (!new_string) { return NULL; }
     return json_value_init_string(new_string);
 }
 
@@ -487,13 +496,13 @@ JSON_Value * json_parse_file(const char *filename) {
     fseek(fp, 0L, SEEK_END);
     file_size = ftell(fp);
     rewind(fp);
-    file_contents = (char*)malloc(sizeof(char) * (file_size + 1));
+    file_contents = (char*)parson_malloc(sizeof(char) * (file_size + 1));
     if (!file_contents) { fclose(fp); return NULL; }
     fread(file_contents, file_size, 1, fp);
     fclose(fp);
     file_contents[file_size] = '\0';
     output_value = json_parse_string(file_contents);
-    free(file_contents);
+    parson_free(file_contents);
     return output_value;
 }
 
@@ -505,14 +514,14 @@ JSON_Value * json_parse_string(const char *string) {
     if (*json_string == '{' || *json_string == '[') {
         output_value = parse_value((const char**)&json_string_ptr, 0);
     }
-    free((void*)json_string);
+    parson_free((void*)json_string);
     return output_value;
 }
 
 /* JSON Object API */
 JSON_Value * json_object_get_value(const JSON_Object *object, const char *name) {
     size_t i;
-    if (object == NULL) { return NULL; }
+    if (!object) { return NULL; }
     for (i = 0; i < object->count; i++) {
         if (strcmp(object->names[i], name) == 0) { return object->values[i]; }
     }
@@ -542,11 +551,11 @@ int json_object_get_boolean(const JSON_Object *object, const char *name) {
 JSON_Value * json_object_dotget_value(const JSON_Object *object, const char *name) {
     const char *object_name, *dot_position = strchr(name, '.');
     JSON_Value *output_value;
-    if (dot_position == NULL) { return json_object_get_value(object, name); }
+    if (!dot_position) { return json_object_get_value(object, name); }
     object_name = parson_strndup(name, dot_position - name);
     output_value = json_object_dotget_value(json_object_get_object(object, object_name),
                                     dot_position + 1);
-    free((void*)object_name);
+    parson_free((void*)object_name);
     return output_value;
 }
 
@@ -602,41 +611,37 @@ size_t json_array_get_count(const JSON_Array *array) {
 
 /* JSON Value API */
 enum json_value_type json_value_get_type(const JSON_Value *value) {
-    return value != NULL ? value->type : JSONError;
+    return value ? value->type : JSONError;
 }
 
 JSON_Object * json_value_get_object(const JSON_Value *value) {
-    if (value == NULL || value->type != JSONObject) { return NULL; }
-    return value->value.object;
+    return json_value_get_type(value) == JSONObject ? value->value.object : NULL;
 }
 
 JSON_Array * json_value_get_array(const JSON_Value *value) {
-    if (value == NULL || value->type != JSONArray) { return NULL; }
-    return value->value.array;
+    return json_value_get_type(value) == JSONArray ? value->value.array : NULL;
+
 }
 
 const char * json_value_get_string(const JSON_Value *value) {
-    if (value == NULL || value->type != JSONString) { return NULL; }
-    return value->value.string;
+    return json_value_get_type(value) == JSONString ? value->value.string : NULL;
 }
 
 double json_value_get_number(const JSON_Value *value) {
-    if (value == NULL || value->type != JSONNumber) { return 0; }
-    return value->value.number;
+    return json_value_get_type(value) == JSONNumber ? value->value.number : 0;
 }
 
 int json_value_get_boolean(const JSON_Value *value) {
-    if (value == NULL || value->type != JSONBoolean) { return -1; }
-    return value->value.boolean;
+    return json_value_get_type(value) == JSONBoolean ? value->value.boolean : -1;
 }
 
 void json_value_free(JSON_Value *value) {
-    switch (value->type) {
+    switch (json_value_get_type(value)) {
         case JSONObject:
             json_object_free(value->value.object);
             break;
         case JSONString:
-            if (value->value.string != NULL) { free((void*)value->value.string); }
+            if (value->value.string) { parson_free((void*)value->value.string); }
             break;
         case JSONArray:
             json_array_free(value->value.array);
@@ -644,5 +649,5 @@ void json_value_free(JSON_Value *value) {
         default:
             break;
     }
-    free(value);
+    parson_free(value);
 }

+ 13 - 24
tests.c

@@ -33,14 +33,14 @@ void test_suite_1(void);
 void test_suite_2(void);
 void test_suite_3(void);
 
-void print_commit_info(const char *username, const char *repo);
+void print_commits_info(const char *username, const char *repo);
 
 static int tests_passed;
 static int tests_failed;
 
 int main(int argc, const char * argv[]) {
-    /* Example function from readme file:      */
-    /* print_commit_info("torvalds", "linux"); */
+    /* Example function from readme file:       */
+    /* print_commits_info("torvalds", "linux"); */
     test_suite_1();
     test_suite_2();
     test_suite_3();
@@ -67,22 +67,11 @@ void test_suite_2(void) {
     JSON_Array *array;
     int i;
     const char *filename = "tests/test_2.txt";
-    
+    printf("Testing %s:\n", filename); 
     root_value = json_parse_file(filename);
-    if(root_value == NULL) {
-        tests_failed++;
-        return;
-    }
-    if (json_value_get_type(root_value) != JSONObject) {
-        printf("Root is not a JSON object.\n");
-        tests_failed++;
-        json_value_free(root_value);
-        return;
-    }
-
-    object = json_value_get_object(root_value);
-    printf("Testing %s:\n", filename);
-    
+    TEST(root_value);
+    TEST(json_value_get_type(root_value) == JSONObject);    
+    object = json_value_get_object(root_value);       
     TEST(STREQ(json_object_get_string(object, "string"), "lorem ipsum"));
     TEST(STREQ(json_object_get_string(object, "utf string"), "lorem ipsum"));
     TEST(json_object_get_number(object, "positive one") == 1.0);
@@ -111,8 +100,8 @@ void test_suite_2(void) {
     
     TEST(json_object_get_array(object, "non existent array") == NULL);
     TEST(STREQ(json_object_dotget_string(object, "object.nested string"), "str"));
-    TEST(json_object_dotget_boolean(object, "object.nested true"));
-    TEST(!json_object_dotget_boolean(object, "object.nested false"));
+    TEST(json_object_dotget_boolean(object, "object.nested true") == 1);
+    TEST(json_object_dotget_boolean(object, "object.nested false") == 0);
     TEST(json_object_dotget_value(object, "object.nested null") != NULL);
     TEST(json_object_dotget_number(object, "object.nested number") == 123);
     
@@ -135,7 +124,7 @@ void test_suite_2(void) {
 
 /* Testing values, on which parsing should fail */
 void test_suite_3(void) {
-    const char nested_20x[] = "[[[[[[[[[[[[[[[[[[[[\"hi\"]]]]]]]]]]]]]]]]]]]]";
+    char nested_20x[] = "[[[[[[[[[[[[[[[[[[[[\"hi\"]]]]]]]]]]]]]]]]]]]]";
     TEST(json_parse_string(NULL) == NULL);
     TEST(json_parse_string("") == NULL); /* empty string */
     TEST(json_parse_string("[\"lorem\",]") == NULL);
@@ -167,7 +156,7 @@ void test_suite_3(void) {
     TEST(json_parse_string(nested_20x) == NULL); /* too deep */
 }
 
-void print_commit_info(const char *username, const char *repo) {
+void print_commits_info(const char *username, const char *repo) {
     JSON_Value *root_value;
     JSON_Array *commits;
     JSON_Object *commit;
@@ -178,8 +167,8 @@ void print_commit_info(const char *username, const char *repo) {
     char output_filename[] = "commits.json";
     
     /* it ain't pretty, but it's not a libcurl tutorial */
-    sprintf(curl_command, "curl \"https://api.github.com/repos/%s/%s/commits\"\
-            > %s 2> /dev/null", username, repo, output_filename);
+    sprintf(curl_command, "curl -s \"https://api.github.com/repos/%s/%s/commits\"\
+            > %s", username, repo, output_filename);
     sprintf(cleanup_command, "rm -f %s", output_filename);
     system(curl_command);