add various json routines into single functions.

- add `json_encode` for object creation functions, using `printf` like formats.
- add `json_for` for array creation functions, using `printf` like formats.
- add `is_json` basic check not NULL and type not JSONError.
- add `json_decode`  combines` json_parse_string_with_comments` and `json_parse_string`
- add `json_serialize` combines `json_serialize_to_string_pretty` and `json_serialize_to_string`
- add `encode_decode_example()` to readme, show shorter syntax to `serialization_example()`
- add/enable `encode_decode_example()` into tests.c

Note: This library is embed into https://github.com/zelang-dev/c-coroutine/blob/main/src/json.c and https://github.com/zelang-dev/c-coroutine/blob/main/examples/co_json.c where all memory and I/O is managed difference.
pull/211/head
TheTechsTech 9 months ago
parent ba29f4eda9
commit adefffe1b0
  1. 29
      README.md
  2. 230
      parson.c
  3. 53
      parson.h
  4. 24
      tests.c

@ -135,6 +135,35 @@ Output:
}
```
The above can also be achieved using `json_encode("printf like format", ...)` for objects, and `json_for("printf like format", ...)` for arrays.
```c
// #ifndef kv
// #define kv(key, value) (key), (value)
// #endif
void encode_decode_example(void) {
// JSON_Value *value = json_for("ss", "email@example.com", "email2@example.com"); // same as "[\"email@example.com\",\"email2@example.com\"]"
// char *serialized_for = json_serialize(value, false);
char *serialized_string = NULL;
JSON_Value *root_value = json_encode("si.s.v",
kv("name", "John Smith"),
kv("age", 25),
kv("address.city", "Cupertino"),
kv("contact.emails", json_decode("[\"email@example.com\",\"email2@example.com\"]", false)));
//if (is_json(root_value)) {
serialized_string = json_serialize(root_value, true);
puts(serialized_string);
// }
// json_free_serialized_string(serialized_for);
json_free_serialized_string(serialized_string);
json_value_free(root_value);
// json_value_free(value);
}
```
## Contributing
I will always merge *working* bug fixes. However, if you want to add something new to the API, please create an "issue" on github for this first so we can discuss if it should end up in the library before you start implementing it.

@ -2484,3 +2484,233 @@ void json_set_float_serialization_format(const char *format) {
void json_set_number_serialization_function(JSON_Number_Serialization_Function func) {
parson_number_serialization_function = func;
}
bool is_json(JSON_Value *schema) {
return (schema == NULL || json_value_get_type(schema) == JSONError) ? false : true;
}
char *json_serialize(JSON_Value *value, bool is_pretty) {
char *json_string = NULL;
if (value != NULL) {
if (is_pretty)
json_string = json_serialize_to_string_pretty(value);
else
json_string = json_serialize_to_string(value);
}
return json_string;
}
JSON_Value *json_decode(const char *text, bool is_commented) {
if (is_commented)
return json_parse_string_with_comments(text);
else
return json_parse_string(text);
}
JSON_Value *json_encode(const char *desc, ...) {
int count = (int)strlen(desc);
JSON_Value *json_root = json_value_init_object();
JSON_Object *json_object = json_value_get_object(json_root);
va_list argp;
char *key, *value_char;
int value_bool;
JSON_Status status = JSONSuccess;
void *value_any = NULL;
JSON_Array *value_array = NULL;
double value_float = 0;
long value_int = 0;
size_t value_max = 0;
bool is_dot = false, is_array = false, is_double = false, is_int = false, is_max = false;
va_start(argp, desc);
for (int i = 0; i < count; i++) {
if (status == JSONFailure)
return NULL;
switch (*desc++) {
case '.':
is_dot = true;
break;
case 'e':
if (is_array) {
is_array = false;
value_array = NULL;
is_dot = false;
}
break;
case 'a':
if (!is_array) {
key = va_arg(argp, char *);
status = json_object_set_value(json_object, key, json_value_init_array());
value_array = json_object_get_array(json_object, key);
is_array = true;
is_dot = false;
}
break;
case 'n':
if (!is_array)
key = va_arg(argp, char *);
if (is_array)
status = json_array_append_null(value_array);
else if (is_dot)
status = json_object_dotset_null(json_object, key);
else
status = json_object_set_null(json_object, key);
is_dot = false;
break;
case 'd':
is_int = true;
case 'f':
if (!is_int)
is_double = true;
case 'i':
if (!is_double && !is_int)
is_max = true;
if (!is_array)
key = va_arg(argp, char *);
if (is_double)
value_float = va_arg(argp, double);
else if (is_int)
value_int = va_arg(argp, long);
else
value_max = va_arg(argp, size_t);
if (is_array)
status = json_array_append_number(value_array, (is_double ? value_float
: is_int ? (int)value_int
: (unsigned long)value_max));
else if (is_dot)
status = json_object_dotset_number(json_object, key, (is_double ? value_float
: is_int ? (int)value_int
: (unsigned long)value_max));
else
status = json_object_set_number(json_object, key, (is_double ? value_float
: is_int ? (int)value_int
: (unsigned long)value_max));
is_dot = false;
is_double = false;
is_int = false;
is_max = false;
break;
case 'b':
if (!is_array)
key = va_arg(argp, char *);
value_bool = va_arg(argp, int);
if (is_array)
status = json_array_append_boolean(value_array, value_bool);
else if (is_dot)
status = json_object_dotset_boolean(json_object, key, value_bool);
else
status = json_object_set_boolean(json_object, key, value_bool);
is_dot = false;
break;
case 's':
if (!is_array)
key = va_arg(argp, char *);
value_char = va_arg(argp, char *);
if (is_array)
status = json_array_append_string(value_array, value_char);
else if (is_dot)
status = json_object_dotset_string(json_object, key, value_char);
else
status = json_object_set_string(json_object, key, value_char);
is_dot = false;
break;
case 'v':
if (!is_array)
key = va_arg(argp, char *);
value_any = va_arg(argp, void *);
if (is_array)
status = json_array_append_value(value_array, value_any);
else if (is_dot)
status = json_object_dotset_value(json_object, key, value_any);
else
status = json_object_set_value(json_object, key, value_any);
is_dot = false;
break;
default:
break;
}
}
va_end(argp);
return json_root;
}
JSON_Value *json_for(const char *desc, ...) {
int count = (int)strlen(desc);
JSON_Value *json_root = json_value_init_object();
JSON_Object *json_object = json_value_get_object(json_root);
JSON_Status status = json_object_set_value(json_object, "array", json_value_init_array());
JSON_Array *value_array = json_object_get_array(json_object, "array");
va_list argp;
char *value_char;
int value_bool;
void *value_any = NULL;
double value_float = 0;
long value_int = 0;
size_t value_max = 0;
bool is_double = false, is_int = false, is_max = false;
va_start(argp, desc);
for (int i = 0; i < count; i++) {
if (status == JSONFailure)
return NULL;
switch (*desc++) {
case 'n':
status = json_array_append_null(value_array);
break;
case 'd':
is_int = true;
case 'f':
if (!is_int)
is_double = true;
case 'i':
if (!is_double && !is_int)
is_max = true;
if (is_double)
value_float = va_arg(argp, double);
else if (is_int)
value_int = va_arg(argp, long);
else
value_max = va_arg(argp, size_t);
status = json_array_append_number(value_array, (is_double ? value_float
: is_int ? (int)value_int
: (unsigned long)value_max));
is_double = false;
is_int = false;
is_max = false;
break;
case 'b':
value_bool = va_arg(argp, int);
status = json_array_append_boolean(value_array, value_bool);
break;
case 's':
value_char = va_arg(argp, char *);
status = json_array_append_string(value_array, value_char);
break;
case 'v':
value_any = va_arg(argp, void *);
status = json_array_append_value(value_array, value_any);
break;
default:
break;
}
}
va_end(argp);
return json_array_get_wrapping_value(value_array);
}

@ -41,6 +41,7 @@ extern "C"
#define PARSON_VERSION_STRING "1.5.3"
#include <stddef.h> /* size_t */
#include <stdbool.h> /* bool */
/* Types and enums */
typedef struct json_object_t JSON_Object;
@ -267,6 +268,58 @@ size_t json_string_len(const JSON_Value *value); /* doesn't account for
double json_number (const JSON_Value *value);
int json_boolean(const JSON_Value *value);
/* Check if schema validated by json type */
bool is_json(JSON_Value *schema);
/**
* @param value Serialization of value to string.
* @param is_pretty Pretty serialization, if set `true`.
*/
char *json_serialize(JSON_Value *value, bool is_pretty);
/**
* @param text Parses first JSON value in a text, returns NULL in case of error.
* @param is_commented Ignores comments (/ * * / and //), if set `true`.
*/
JSON_Value *json_decode(const char *text, bool is_commented);
/**
* Creates json value `object` using a format like `printf` for each value to key.
*
* @param desc format string:
* * '`.`' indicate next format character will use dot function to record value for key name with dot,
* * '`a`' begin array encoding, every item `value` will be appended, until '`e`' is place in format desc,
* * '`e`' end array encoding,
* * '`n`' record `null` value for key, *DO NOT PLACE `NULL` IN ARGUMENTS*,
* * '`f`' record `float/double` number for key,
* * '`d`' record `signed` number for key,
* * '`i`' record `unsigned` number for key,
* * '`b`' record `boolean` value for key,
* * '`s`' record `string` value for key,
* * '`v`' record `JSON_Value` for key,
* @param arguments use `kv(key,value)` for pairs, *DO NOT PROVIDE FOR NULL, ONLY KEY*
*/
JSON_Value *json_encode(const char *desc, ...);
/**
* Creates json value `array` using a format like `printf` for each value to index.
*
* @param desc format string:
* * '`n`' record `null` value for index, *DO NOT PLACE `NULL` IN ARGUMENTS*,
* * '`f`' record `float/double` number for index,
* * '`d`' record `signed` number for index,
* * '`i`' record `unsigned` number for index,
* * '`b`' record `boolean` value for index,
* * '`s`' record `string` value for index,
* * '`v`' record `JSON_Value` for index,
* @param arguments indexed by `desc` format order, *DO NOT PROVIDE FOR NULL*
*/
JSON_Value *json_for(const char *desc, ...);
#ifndef kv
#define kv(key, value) (key), (value)
#endif
#ifdef __cplusplus
}
#endif

@ -73,6 +73,7 @@ void test_object_clear(void);
void print_commits_info(const char *username, const char *repo);
void persistence_example(void);
void serialization_example(void);
void encode_decode_example(void);
static const char *g_tests_path = "tests";
@ -113,6 +114,8 @@ int tests_main(int argc, char *argv[]) {
/* serialization_example(); */
/* persistence_example(); */
encode_decode_example();
puts("################################################################################");
puts("Running parson tests");
@ -830,6 +833,27 @@ void serialization_example(void) {
json_value_free(root_value);
}
void encode_decode_example(void) {
JSON_Value *value = json_for("ss", "email@example.com", "email2@example.com");
char *serialized_for = json_serialize(value, false);
char *serialized_string = NULL;
JSON_Value *encoded = json_encode("si.s.v",
kv("name", "John Smith"),
kv("age", 25),
kv("address.city", "Cupertino"),
kv("contact.emails", json_decode(serialized_for, false)));
if (is_json(encoded)) {
serialized_string = json_serialize(encoded, true);
puts(serialized_string);
}
json_free_serialized_string(serialized_for);
json_free_serialized_string(serialized_string);
json_value_free(encoded);
json_value_free(value);
}
static char * read_file(const char * file_path) {
FILE *fp = NULL;
size_t size_to_read = 0;

Loading…
Cancel
Save