diff --git a/docs/Melon Developer Guide.txt b/docs/Melon Developer Guide.txt index 7cbea07d..cf989317 100644 --- a/docs/Melon Developer Guide.txt +++ b/docs/Melon Developer Guide.txt @@ -1598,139 +1598,142 @@ Their definitions can be found in melon/include/mln_types.h. 22) JSON Melon, now, support JSON without relying on any json libraries. Here are the functions: - a) mln_json_t *mln_json_new(void); - Initialize a JSON object. + a) mln_json_init(j); + Initialize JSON object 'j'. - b) void mln_json_free(void *json); + b) mln_json_string_init(j, s); + Initialize a String JSON object. 's' will be taken. + + c) mln_json_number_init(j, n); + Initialize a number JSON object. + + d) mln_json_true_init(j); + Initialize a 'true' JSON object. + + e) mln_json_false_init(j); + Initialize a 'false' JSON object. + + f) mln_json_null_init(j); + Initialize a 'null' JSON object. + + g) int mln_json_obj_init(mln_json_t *j); + Initialize a 'object' JSON object. + + h) int mln_json_array_init(mln_json_t *j); + Initialize an 'array' JSON object. + + i) void mln_json_destroy(mln_json_t *j); Destroy a JSON object. - c) mln_json_t *mln_json_parse(mln_string_t *jstr); - Parse JSON string. + j) int mln_json_decode(mln_string_t *jstr, mln_json_t *out); + Decode JSON string, the result is stored in 'out'. - d) mln_string_t *mln_json_generate(mln_json_t *j); - Generate a JSON string. + k) mln_string_t *mln_json_encode(mln_json_t *j); + Encode JSON to a string. - e) mln_json_t *mln_json_value_search(mln_json_t *j, mln_string_t *key); - Search the JSON object value via 'key'. + l) mln_json_t *mln_json_obj_search(mln_json_t *j, mln_string_t *key); + Search value by 'key' in the JSON object 'j'. - f) mln_json_t *mln_json_element_search(mln_json_t *j, mln_uauto_t index); - Search the element from a JSON array. + m) mln_json_t *mln_json_array_search(mln_json_t *j, mln_uauto_t index); + Search the array element located by 'index' from the JSON array 'j'. - g) mln_uauto_t mln_json_array_length(mln_json_t *j); + n) mln_uauto_t mln_json_array_length(mln_json_t *j); Get JSON array length. - h) int mln_json_obj_update(mln_json_t *j, mln_json_t *key, mln_json_t *val); + o) int mln_json_obj_update(mln_json_t *j, mln_json_t *key, mln_json_t *val); Update JSON object key-value. - If 'key' is existent, the old value will be replaced by 'val' and freed. - The type of 'j' should be M_JSON_OBJECT or M_JSON_NONE. + If 'key' is existent, the old key and value will be replaced by the given arguments and freed. + The type of 'j' must be M_JSON_OBJECT. - i) int mln_json_element_add(mln_json_t *j, mln_json_t *value); - Add an element into a JSON array. - The type of 'j' should be M_JSON_ARRAY or M_JSON_NONE. + p) int mln_json_array_append(mln_json_t *j, mln_json_t *value); + Add an array element to a JSON array. + The type of 'j' must be M_JSON_ARRAY. - j) int mln_json_element_update(mln_json_t *j, mln_json_t *value, mln_uauto_t index); + q) int mln_json_array_update(mln_json_t *j, mln_json_t *value, mln_uauto_t index); Update JSON array element. - The old value where is located by 'index' will be replaced by 'value' and free if it is existent. + The old value located by 'index' will be replaced by 'value' and free if it is existent. The type of 'j' must be M_JSON_ARRAY. - k) void mln_json_reset(mln_json_t *j); + r) void mln_json_reset(mln_json_t *j); Reset a JSON object. - l) mln_json_t *mln_json_obj_remove(mln_json_t *j, mln_string_t *key); + s) void mln_json_obj_remove(mln_json_t *j, mln_string_t *key); Remove a key-value couple from a JSON object. The type of 'j' must be M_JSON_OBJECT. - m) mln_json_t *mln_json_element_remove(mln_json_t *j, mln_uauto_t index); + t) void mln_json_array_remove(mln_json_t *j, mln_uauto_t index); Remove an element from a JSON object. The type of 'j' must be M_JSON_ARRAY. - n) M_JSON_IS_OBJECT(json); + u) M_JSON_IS_OBJECT(json); Test whether the type of 'json' is M_JSON_OBJECT. - o) M_JSON_IS_ARRAY(json); + v) M_JSON_IS_ARRAY(json); Test whether the type of 'json' is M_JSON_ARRAY. - p) M_JSON_IS_STRING(json); + w) M_JSON_IS_STRING(json); Test whether the type of 'json' is M_JSON_STRING. - q) M_JSON_IS_NUMBER(json); + x) M_JSON_IS_NUMBER(json); Test whether the type of 'json' is M_JSON_NUM. - r) M_JSON_IS_TRUE(json); + y) M_JSON_IS_TRUE(json); Test whether the type of 'json' is M_JSON_TRUE. - s) M_JSON_IS_FALSE(json); + z) M_JSON_IS_FALSE(json); Test whether the type of 'json' is M_JSON_FALSE. - t) M_JSON_IS_NULL(json); + aa) M_JSON_IS_NULL(json); Test whether the type of 'json' is M_JSON_NULL. - u) M_JSON_IS_NONE(json); + ab) M_JSON_IS_NONE(json); Test whether the type of 'json' is M_JSON_NONE. - v) M_JSON_GET_DATA_OBJECT(json); + ac) M_JSON_GET_DATA_OBJECT(json); Get the object hash table if the type of 'json' is M_JSON_OBJECT. - w) M_JSON_GET_DATA_ARRAY(json); + ad) M_JSON_GET_DATA_ARRAY(json); Get the array red-black tree if the type of 'json' is M_JSON_ARRAY. - x) M_JSON_GET_DATA_STRING(json); + ae) M_JSON_GET_DATA_STRING(json); Get the string if the type of 'json' is M_JSON_STRING. - y) M_JSON_GET_DATA_NUMBER(json); + af) M_JSON_GET_DATA_NUMBER(json); Get the number if the type of 'json' is M_JSON_NUM. - z) M_JSON_GET_DATA_TRUE(json); + ag) M_JSON_GET_DATA_TRUE(json); Get the binary flag of TRUE if the type of 'json' is M_JSON_TRUE. - aa) M_JSON_GET_DATA_FALSE(json); + ah) M_JSON_GET_DATA_FALSE(json); Get the binary flag of FALSE if the type of 'json' is M_JSON_FALSE. - ab) M_JSON_GET_DATA_NULL(json); + ai) M_JSON_GET_DATA_NULL(json); Get the variable of NULL if the type of 'json' is M_JSON_NULL. - ac) M_JSON_SET_INDEX(json,i); - Set the index of 'json' to be 'i'. - - ad) M_JSON_SET_TYPE_NONE(json); + aj) M_JSON_SET_TYPE_NONE(json); Set the type of 'json' to be M_JSON_NONE. - ae) M_JSON_SET_TYPE_OBJECT(json); + ak) M_JSON_SET_TYPE_OBJECT(json); Set the type of 'json' to be M_JSON_OBJECT. - af) M_JSON_SET_TYPE_ARRAY(json); + al) M_JSON_SET_TYPE_ARRAY(json); Set the type of 'json' to be M_JSON_ARRAY. - ag) M_JSON_SET_TYPE_STRING(json); + am) M_JSON_SET_TYPE_STRING(json); Set the type of 'json' to be M_JSON_STRING. - ah) M_JSON_SET_TYPE_NUMBER(json); + an) M_JSON_SET_TYPE_NUMBER(json); Set the type of 'json' to be M_JSON_NUM. - ai) M_JSON_SET_TYPE_TRUE(json); + ao) M_JSON_SET_TYPE_TRUE(json); Set the type of 'json' to be M_JSON_TRUE. - aj) M_JSON_SET_TYPE_FALSE(json); + ap) M_JSON_SET_TYPE_FALSE(json); Set the type of 'json' to be M_JSON_FALSE. - ak) M_JSON_SET_TYPE_NULL(json); + aq) M_JSON_SET_TYPE_NULL(json); Set the type of 'json' to be M_JSON_NULL. - al) M_JSON_SET_DATA_STRING(json,str); - Set the string value of 'json' to be 'str'. - - am) M_JSON_SET_DATA_NUMBER(json,num); - Set the number of 'json' to be 'num'. - - an) M_JSON_SET_DATA_TRUE(json); - Set the binary flag of TRUE in 'json'. - - ao) M_JSON_SET_DATA_FALSE(json); - Set the binary flag of FALSE in 'json'. - - ap) M_JSON_SET_DATA_NULL(json); - Set the variable of NULL in 'json'. - 23) Big Number For now, big number only can represent the number which is smaller than 2048-bit number. diff --git a/docs/book/cn/json.md b/docs/book/cn/json.md index 7ffc8a95..78e1988d 100644 --- a/docs/book/cn/json.md +++ b/docs/book/cn/json.md @@ -14,37 +14,130 @@ -#### mln_json_new +#### mln_json_init ```c -mln_json_t *mln_json_new(void); +mln_json_init(j) ``` -描述:新建json节点,用于生成json字符串之用。 +描述:初始化JSON类型结点`j`,该结点类型为`NONE`. -返回值:成功则返回`mln_json_t`指针,否则返回`NULL` +返回值:无 + + + +#### mln_json_string_init + +```c +mln_json_string_init(j, s) +``` + +描述:将JSON类型结点`j`初始化为字符串类型,并赋予`mln_string_t *`类型的值`s`。`s`会被JSON结构接管,调用方需要保证`s`的内存生命周期以及不可修改`s`的内容。 + +返回值:无 + + + +#### mln_json_number_init + +```c +mln_json_number_init(j, n) +``` + +描述:将JSON类型结点`j`初始化为数字类型,并赋予`double`类型的值`n`。 + +返回值:无 + + + +#### mln_json_true_init + +```c +mln_json_true_init(j) +``` + +描述:将JSON类型结点`j`初始化为`true`类型。 + +返回值:无 -#### mln_json_parse +#### mln_json_false_init ```c -mln_json_t *mln_json_parse(mln_string_t *jstr); +mln_json_false_init(j) ``` -描述:将JSON字符串`jstr`解析成数据结构。 +描述:将JSON类型结点`j`初始化为`false`类型。 -返回值:成功则返回`mln_json_t`指针,否则返回`NULL` +返回值:无 -#### mln_json_free +#### mln_json_null_init ```c -void mln_json_free(void *json); +mln_json_null_init(j) ``` -描述:释放`mln_json_t`类型的`json`节点内存。 +描述:将JSON类型结点`j`初始化为`null`类型。 + +返回值:无 + + + +#### mln_json_obj_init + +```c +int mln_json_obj_init(mln_json_t *j); +``` + +描述:将JSON类型结点`j`初始化为对象类型。 + +返回值: + +- `0` - 成功 +- `-1` - 失败 + + + +#### mln_json_array_init + +```c +int mln_json_array_init(mln_json_t *j); +``` + +描述:将JSON类型结点`j`初始化为数组类型。 + +返回值: + +- `0` - 成功 +- `-1` - 失败 + + + +#### mln_json_decode + +```c +int mln_json_decode(mln_string_t *jstr, mln_json_t *out); +``` + +描述:将JSON字符串`jstr`解析成数据结构,结果会被放入参数`out`中。 + +返回值: + +- `0` - 成功 +- `-1` - 失败 + + + +#### mln_json_destroy + +```c +void mln_json_destroy(mln_json_t *j; +``` + +描述:释放`mln_json_t`类型的`j`节点内存。 返回值:无 @@ -62,37 +155,37 @@ void mln_json_dump(mln_json_t *j, int n_space, char *prefix); -#### mln_json_generate +#### mln_json_encode ```c -mln_string_t *mln_json_generate(mln_json_t *j); +mln_string_t *mln_json_encode(mln_json_t *j); ``` -描述:由`mln_json_t`节点结构生成JSON字符串。 +描述:由`mln_json_t`节点结构生成JSON字符串。返回值使用后需要调用`mln_string_free`进行释放。 返回值:成功返回`mln_string_t`字符串指针,否则返回`NULL` -#### mln_json_value_search +#### mln_json_obj_search ```c -mln_json_t *mln_json_value_search(mln_json_t *j, mln_string_t *key); +mln_json_t *mln_json_obj_search(mln_json_t *j, mln_string_t *key); ``` -描述:从节点`j`中搜索key为`key`的value内容。此时,`j`必须为对象类型(有key: value对的字典)。 +描述:从对象类型结点`j`中搜索key为`key`的value内容。 返回值:成功则返回`mln_json_t`类型的value,否则返回`NULL` -#### mln_json_element_search +#### mln_json_array_search ```c -mln_json_t *mln_json_element_search(mln_json_t *j, mln_uauto_t index); +mln_json_t *mln_json_array_search(mln_json_t *j, mln_uauto_t index); ``` -描述:从节点`j`中搜索下标为`index`的元素内容。此时,`j`必须为数组类型。 +描述:从数组类型结点`j`中搜索下标为`index`的元素内容。 返回值:成功则返回`mln_json_t`类型的元素节点,否则返回`NULL` @@ -116,16 +209,16 @@ mln_uauto_t mln_json_array_length(mln_json_t *j); int mln_json_obj_update(mln_json_t *j, mln_json_t *key, mln_json_t *val); ``` -描述:将`key`与`val`对添加到`j` JSON节点中。此时,`j`需为对象类型。若`key`已经存在,则将原本value替换为`val`。 +描述:将`key`与`val`对添加到`j` JSON节点中。此时,`j`需为对象类型。若`key`已经存在,则将原本`key`和`value`将会被新参数替换。因此参数`key`和`val`在调用后将被`j`接管。 返回值:成功则返回`0`,否则返回`-1` -#### mln_json_element_add +#### mln_json_array_append ```c -int mln_json_element_add(mln_json_t *j, mln_json_t *value); +int mln_json_array_append(mln_json_t *j, mln_json_t *value); ``` 描述:将`value`加入到数组类型的JSON结构`j`中。 @@ -134,13 +227,13 @@ int mln_json_element_add(mln_json_t *j, mln_json_t *value); -#### mln_json_element_update +#### mln_json_array_update ```c -int mln_json_element_update(mln_json_t *j, mln_json_t *value, mln_uauto_t index); +int mln_json_array_update(mln_json_t *j, mln_json_t *value, mln_uauto_t index); ``` -描述:将`value`更新到数组类型JSON结构`j`的下标为`index`的位置上。 +描述:将`value`更新到数组类型JSON结构`j`的下标为`index`的位置上。若下标不存在,则会失败。 返回值:成功则返回`0`,否则返回`-1` @@ -152,7 +245,7 @@ int mln_json_element_update(mln_json_t *j, mln_json_t *value, mln_uauto_t index) void mln_json_reset(mln_json_t *j); ``` -描述:重置JSON节点`j`数据结构,将其内存进行释放。 +描述:重置JSON节点`j`数据结构,将其原有数据释放。 返回值:无 @@ -161,22 +254,22 @@ void mln_json_reset(mln_json_t *j); #### mln_json_obj_remove ```c -mln_json_t *mln_json_obj_remove(mln_json_t *j, mln_string_t *key); +void mln_json_obj_remove(mln_json_t *j, mln_string_t *key); ``` -描述:将key值为`key`的键值对从对象类型的JSON结构`j`中删除,并将相应value返回。 +描述:将key值为`key`的键值对从对象类型的JSON结构`j`中删除并释放。 返回值:存在则返回对应value部分的JSON节点,否则返回`NULL` -#### mln_json_element_remove +#### mln_json_array_remove ```c -mln_json_t *mln_json_element_remove(mln_json_t *j, mln_uauto_t index); +void mln_json_array_remove(mln_json_t *j, mln_uauto_t index); ``` -描述:将下标为`index`的元素从数组类型JSON节点上删除并返回。 +描述:将下标为`index`的元素从数组类型JSON节点上删除并释放。 返回值:存在则返回元素指针,否则返回`NULL` @@ -246,100 +339,36 @@ M_JSON_GET_DATA_NULL(json) -#### set_data - -```c -M_JSON_SET_DATA_STRING(json,str) -M_JSON_SET_DATA_NUMBER(json,num) -M_JSON_SET_DATA_TRUE(json) -M_JSON_SET_DATA_FALSE(json) -M_JSON_SET_DATA_NULL(json) -``` - -描述:给不同类型的JSON节点`json`设置数据值。对象和数组类型分别使用哈希表和红黑树函数进行操作,其余类型用上述宏进行设置。 - -**注意**:这里设置的字符串必须是从内存池或堆中分配的内存,栈中内存会出现段错误,因为赋值时不会在宏内自动复制一份而是直接使用。 - -返回值:无 - - - -#### M_JSON_SET_INDEX - -```c -M_JSON_SET_INDEX(json,i) -``` - -描述:设置`mln_json_t`类型节点`json`的下标为`index`。该宏用于生成JSON字符串中数组的部分。 - -返回值:无 - - - ### 示例 ```c #include -#include #include "mln_string.h" #include "mln_json.h" int main(int argc, char *argv[]) { - mln_json_t *j = NULL, *key = NULL, *val = NULL; - mln_string_t s1 = mln_string("name"); - mln_string_t s2 = mln_string("Tom"); + mln_json_t j; mln_string_t *res; + mln_string_t tmp = mln_string("{\"paths\":[\"/mock\"],\"methods\":null,\"sources\":null,\"destinations\":null,\"name\":\"example_route\",\"headers\":null,\"hosts\":null,\"preserve_host\":false,\"regex_priority\":0,\"snis\":null,\"https_redirect_status_code\":426,\"tags\":null,\"protocols\":[\"http\",\"https\"],\"path_handling\":\"v0\",\"id\":\"52d58293-ae25-4c69-acc8-6dd729718a61\",\"updated_at\":1661345592,\"service\":{\"id\":\"c1e98b2b-6e77-476c-82ca-a5f1fb877e07\"},\"response_buffering\":true,\"strip_path\":true,\"request_buffering\":true,\"created_at\":1661345592}"); - key = mln_json_new(); - if (key == NULL) { - fprintf(stderr, "init key failed\n"); - goto err; + if (mln_json_decode(&tmp, &j) < 0) { + fprintf(stderr, "decode error\n"); + return -1; } - M_JSON_SET_TYPE_STRING(key); - M_JSON_SET_DATA_STRING(key, mln_string_dup(&s1));//注意,一定是要自行分配内存,不可直接使用栈中内存 + mln_json_dump(&j, 0, NULL); - val = mln_json_new(); - if (val == NULL) { - fprintf(stderr, "init val failed\n"); - goto err; - } - M_JSON_SET_TYPE_STRING(val); - M_JSON_SET_DATA_STRING(val, mln_string_dup(&s2));//注意,一定是要自行分配内存,不可直接使用栈中内存 - - j = mln_json_new(); - if (j == NULL) { - fprintf(stderr, "init object failed\n"); - goto err; - } - if (mln_json_obj_update(j, key, val) < 0) { - fprintf(stderr, "update object failed\n"); - goto err; - } - key = val = NULL; - - res = mln_json_generate(j); - mln_json_free(j); + res = mln_json_encode(&j); + mln_json_destroy(&j); if (res == NULL) { - fprintf(stderr, "generate failed\n"); - goto err; + fprintf(stderr, "encode failed\n"); + return -1; } write(STDOUT_FILENO, res->data, res->len); write(STDOUT_FILENO, "\n", 1); - - j = mln_json_parse(res); mln_string_free(res); - mln_json_dump(j, 0, NULL); - - mln_json_free(j); return 0; - -err: - if (j != NULL) mln_json_free(j); - if (key != NULL) mln_json_free(key); - if (val != NULL) mln_json_free(val); - return -1; } ``` diff --git a/docs/book/en/json.md b/docs/book/en/json.md index 1f264ace..78ab0ccb 100644 --- a/docs/book/en/json.md +++ b/docs/book/en/json.md @@ -2,7 +2,7 @@ -### Header +### Header file ```c #include "mln_json.h" @@ -14,39 +14,132 @@ -#### mln_json_new +#### mln_json_init ```c -mln_json_t *mln_json_new(void); +mln_json_init(j) ``` -Description: Create a new json node for generating json strings. +Description: Initialize JSON type node `j`, the node type is `NONE`. -Return value: return `mln_json_t` pointer if successful, otherwise return `NULL` +Return value: None -#### mln_json_parse +#### mln_json_string_init ```c -mln_json_t *mln_json_parse(mln_string_t *jstr); +mln_json_string_init(j, s) ``` -Description: Parse the JSON string `jstr` into a data structure. +Description: Initialize JSON type node `j` to string type and assign value `s` of type `mln_string_t *`. `s` will be taken over by the JSON structure. The caller needs to ensure the memory life cycle of `s` and cannot modify the content of `s`. -Return value: return `mln_json_t` pointer if successful, otherwise return `NULL` +Return value: None -#### mln_json_free +#### mln_json_number_init ```c -void mln_json_free(void *json); +mln_json_number_init(j, n) ``` -Description: Free `json` node memory of type `mln_json_t`. +Description: Initialize the JSON type node `j` to a numeric type and assign a value `n` of type `double`. -Return value: none +Return value: None + + + +#### mln_json_true_init + +```c +mln_json_true_init(j) +``` + +Description: Initialize JSON type node `j` to type `true`. + +Return value: None + + + +#### mln_json_false_init + +```c +mln_json_false_init(j) +``` + +Description: Initialize the JSON type node `j` to the `false` type. + +Return value: None + + + +#### mln_json_null_init + +```c +mln_json_null_init(j) +``` + +Description: Initialize JSON type node `j` to `null` type. + +Return value: None + + + +#### mln_json_obj_init + +```c +int mln_json_obj_init(mln_json_t *j); +``` + +Description: Initialize JSON type node `j` to object type. + +Return value: + +- `0` - Success +- `-1` - failed + + + +#### mln_json_array_init + +```c +int mln_json_array_init(mln_json_t *j); +``` + +Description: Initialize JSON type node `j` to array type. + +Return value: + +- `0` - Success +- `-1` - failed + + + +#### mln_json_decode + +```c +int mln_json_decode(mln_string_t *jstr, mln_json_t *out); +``` + +Description: Parse the JSON string `jstr` into a data structure, and the result will be put into the parameter `out`. + +Return value: + +- `0` - Success +- `-1` - failed + + + +#### mln_json_destroy + +```c +void mln_json_destroy(mln_json_t *j; +``` + +Description: Release the `j` node memory of type `mln_json_t`. + +Return value: None @@ -56,45 +149,45 @@ Return value: none void mln_json_dump(mln_json_t *j, int n_space, char *prefix); ``` -Description: Print the details of the json node `j` to standard output. `n_space` indicates the current number of indented spaces, and `prefix` is the prefix of the output content. +Description: Output the details of json node `j` to standard output. `n_space` represents the current number of indented spaces, and `prefix` is the prefix of the output content. -Return value: none +Return value: None -#### mln_json_generate +#### mln_json_encode ```c -mln_string_t *mln_json_generate(mln_json_t *j); +mln_string_t *mln_json_encode(mln_json_t *j); ``` -Description: Generate JSON string from `mln_json_t` node structure. +Description: Generate a JSON string from the `mln_json_t` node structure. The return value needs to be released by calling `mln_string_free` after use. -Return value: return `mln_string_t` string pointer successfully, otherwise return `NULL` +Return value: `mln_string_t` string pointer is returned successfully, otherwise `NULL` is returned -#### mln_json_value_search +#### mln_json_obj_search ```c -mln_json_t *mln_json_value_search(mln_json_t *j, mln_string_t *key); +mln_json_t *mln_json_obj_search(mln_json_t *j, mln_string_t *key); ``` -Description: Search the value content of key `key` from node `j`. In this case, `j` must be of type object (dictionary with key:value pairs). +Description: Search the value content with key `key` from object type node `j`. -Return value: return value of type `mln_json_t` if successful, otherwise return `NULL` +Return value: If successful, return a value of type `mln_json_t`, otherwise return `NULL` -#### mln_json_element_search +#### mln_json_array_search ```c -mln_json_t *mln_json_element_search(mln_json_t *j, mln_uauto_t index); +mln_json_t *mln_json_array_search(mln_json_t *j, mln_uauto_t index); ``` -Description: Search for the element content with subscript `index` from node `j`. In this case, `j` must be an array type. +Description: Search the element content with subscript `index` from array type node `j`. -Return value: If successful, return an element node of type `mln_json_t`, otherwise return `NULL` +Return value: If successful, an element node of type `mln_json_t` is returned, otherwise `NULL` is returned. @@ -104,9 +197,9 @@ Return value: If successful, return an element node of type `mln_json_t`, otherw mln_uauto_t mln_json_array_length(mln_json_t *j); ``` -Description: Get the length of the array. In this case `j` must be an array type. +Description: Get the length of the array. At this time `j` must be of array type. -Return value: Array length +Return value: array length @@ -116,33 +209,33 @@ Return value: Array length int mln_json_obj_update(mln_json_t *j, mln_json_t *key, mln_json_t *val); ``` -Description: Add `key` and `val` pairs to the `j` JSON node. In this case, `j` needs to be an object type. If `key` already exists, replace the original value with `val`. +Description: Add the `key` and `val` pairs to the `j` JSON node. At this time, `j` needs to be an object type. If `key` already exists, the original `key` and `value` will be replaced by the new parameters. Therefore the parameters `key` and `val` will be taken over by `j` after the call. -Return value: return `0` if successful, otherwise return `-1` +Return value: Returns `0` on success, otherwise returns `-1` -#### mln_json_element_add +#### mln_json_array_append ```c -int mln_json_element_add(mln_json_t *j, mln_json_t *value); +int mln_json_array_append(mln_json_t *j, mln_json_t *value); ``` -Description: Add `value` to JSON structure `j` of array type. +Description: Add `value` to the JSON structure `j` of array type. -Return value: return `0` if successful, otherwise return `-1` +Return value: Returns `0` on success, otherwise returns `-1` -#### mln_json_element_update +#### mln_json_array_update ```c -int mln_json_element_update(mln_json_t *j, mln_json_t *value, mln_uauto_t index); +int mln_json_array_update(mln_json_t *j, mln_json_t *value, mln_uauto_t index); ``` -Description: Update `value` to the position indexed `index` of the array type JSON structure `j`. +Description: Update `value` to the position where the index is `index` of the array type JSON structure `j`. If the subscript does not exist, it will fail. -Return value: return `0` if successful, otherwise return `-1` +Return value: Returns `0` on success, otherwise returns `-1` @@ -152,31 +245,31 @@ Return value: return `0` if successful, otherwise return `-1` void mln_json_reset(mln_json_t *j); ``` -Description: Reset the JSON node `j` data structure, freeing its memory. +Description: Reset the JSON node `j` data structure and release its original data. -Return value: none +Return value: None #### mln_json_obj_remove ```c -mln_json_t *mln_json_obj_remove(mln_json_t *j, mln_string_t *key); +void mln_json_obj_remove(mln_json_t *j, mln_string_t *key); ``` -Description: Remove the key-value pair whose key value is `key` from the JSON structure `j` of the object type, and return the corresponding value. +Description: Delete and release the key-value pair with key value `key` from the JSON structure `j` of the object type. -Return value: if exists, return the JSON node corresponding to the value part, otherwise return `NULL` +Return value: If it exists, return the JSON node corresponding to the value part, otherwise return `NULL` -#### mln_json_element_remove +#### mln_json_array_remove ```c -mln_json_t *mln_json_element_remove(mln_json_t *j, mln_uauto_t index); +void mln_json_array_remove(mln_json_t *j, mln_uauto_t index); ``` -Description: Remove the element with subscript `index` from the array type JSON node and return it. +Description: Delete and release the element with index `index` from the array type JSON node. Return value: Returns the element pointer if it exists, otherwise returns `NULL` @@ -195,9 +288,9 @@ M_JSON_IS_NULL(json) M_JSON_IS_NONE(json) ``` -Description: Determine the `json` type of the `mln_json_t` structure, in order: object, array, string, number, boolean true, boolean false, NULL, no type. +Description: Determine the `json` type of the `mln_json_t` structure, which are: object, array, string, number, Boolean true, Boolean false, NULL, and no type. -Return value: return `not 0` if the condition is met, otherwise return `0` +Return value: Returns `non-0` if the conditions are met, otherwise returns `0` @@ -214,9 +307,9 @@ M_JSON_SET_TYPE_FALSE(json) M_JSON_SET_TYPE_NULL(json) ``` -Description: Set the type for the `json` node of type `mln_json_t`, in order: no type, object, array, string, number, boolean true, boolean false, NULL. +Description: Set the type for the `json` node of type `mln_json_t`, in order: no type, object, array, string, number, Boolean true, Boolean false, NULL. -Return value: none +Return value: None @@ -232,114 +325,50 @@ M_JSON_GET_DATA_FALSE(json) M_JSON_GET_DATA_NULL(json) ``` -Description: Get the data part of the corresponding type in the `json` node of type `mln_json_t`. The types are: object, array, string, number, boolean true, boolean false, NULL. +Description: Get the data part of the corresponding type in the `json` node of type `mln_json_t`. The types are: object, array, string, number, Boolean true, Boolean false, and NULL. -return value: +Return value: -- the object type is a pointer of type `mln_hash_t` -- The array type is a pointer of type `mln_rbtree_t` -- The string type is a pointer of type `mln_string_t` -- the numeric type is a value of type `double` -- boolean true value of type `mln_u8_t` -- boolean false for a value of type `mln_u8_t` +- The object type is `mln_hash_t` type pointer +- The array type is `mln_rbtree_t` type pointer +- The string type is `mln_string_t` type pointer +- The number type is a `double` type value +- Boolean true for `mln_u8_t` type value +- Boolean false for `mln_u8_t` type value - NULL type is a NULL value of type `mln_u8ptr_t` -#### set_data - -```c -M_JSON_SET_DATA_STRING(json,str) -M_JSON_SET_DATA_NUMBER(json,num) -M_JSON_SET_DATA_TRUE(json) -M_JSON_SET_DATA_FALSE(json) -M_JSON_SET_DATA_NULL(json) -``` - -Description: Set data values for different types of JSON nodes `json`. Object and array types are manipulated using hash table and red-black tree functions, respectively, and the rest of the types are set with the above macros. - -**Note**: The string set here must be the memory allocated from the memory pool or the heap. The memory in the stack will have a segmentation fault, because the assignment will not automatically copy a copy in the macro but use it directly. - -Return value: none - - - -#### M_JSON_SET_INDEX - -```c -M_JSON_SET_INDEX(json,i) -``` - -Description: Set the subscript of `mln_json_t` type node `json` to `index`. This macro is used to generate part of an array in a JSON string. - -Return value: none - - - ### Example ```c #include -#include #include "mln_string.h" #include "mln_json.h" int main(int argc, char *argv[]) { - mln_json_t *j = NULL, *key = NULL, *val = NULL; - mln_string_t s1 = mln_string("name"); - mln_string_t s2 = mln_string("Tom"); + mln_json_t j; mln_string_t *res; + mln_string_t tmp = mln_string("{\"paths\":[\"/mock\"],\"methods\":null,\"sources\":null,\"destinations\":null,\"name\":\"example_route\",\"headers\":null,\"hosts\":null,\"preserve_host\":false,\"regex_priority\":0,\"snis\":null,\"https_redirect_status_code\":426,\"tags\":null,\"protocols\":[\"http\",\"https\"],\"path_handling\":\"v0\",\"id\":\"52d58293-ae25-4c69-acc8-6dd729718a61\",\"updated_at\":1661345592,\"service\":{\"id\":\"c1e98b2b-6e77-476c-82ca-a5f1fb877e07\"},\"response_buffering\":true,\"strip_path\":true,\"request_buffering\":true,\"created_at\":1661345592}"); - key = mln_json_new(); - if (key == NULL) { - fprintf(stderr, "init key failed\n"); - goto err; - } - M_JSON_SET_TYPE_STRING(key); - M_JSON_SET_DATA_STRING(key, mln_string_dup(&s1));//注意,一定是要自行分配内存,不可直接使用栈中内存 - - val = mln_json_new(); - if (val == NULL) { - fprintf(stderr, "init val failed\n"); - goto err; - } - M_JSON_SET_TYPE_STRING(val); - M_JSON_SET_DATA_STRING(val, mln_string_dup(&s2));//注意,一定是要自行分配内存,不可直接使用栈中内存 - - j = mln_json_new(); - if (j == NULL) { - fprintf(stderr, "init object failed\n"); - goto err; - } - if (mln_json_obj_update(j, key, val) < 0) { - fprintf(stderr, "update object failed\n"); - goto err; + if (mln_json_decode(&tmp, &j) < 0) { + fprintf(stderr, "decode error\n"); + return -1; } - key = val = NULL; + mln_json_dump(&j, 0, NULL); - res = mln_json_generate(j); - mln_json_free(j); + res = mln_json_encode(&j); + mln_json_destroy(&j); if (res == NULL) { - fprintf(stderr, "generate failed\n"); - goto err; + fprintf(stderr, "encode failed\n"); + return -1; } write(STDOUT_FILENO, res->data, res->len); write(STDOUT_FILENO, "\n", 1); - - j = mln_json_parse(res); mln_string_free(res); - mln_json_dump(j, 0, NULL); - - mln_json_free(j); return 0; - -err: - if (j != NULL) mln_json_free(j); - if (key != NULL) mln_json_free(key); - if (val != NULL) mln_json_free(val); - return -1; } ``` diff --git a/include/mln_hash.h b/include/mln_hash.h index 74b86ccb..6c49fed3 100644 --- a/include/mln_hash.h +++ b/include/mln_hash.h @@ -68,11 +68,13 @@ struct mln_hash_s { mln_u32_t calc_prime:1; }; - +extern int +mln_hash_init(mln_hash_t *h, struct mln_hash_attr *attr) __NONNULL2(1,2); +extern void mln_hash_destroy(mln_hash_t *h, mln_hash_flag_t flg); extern mln_hash_t * mln_hash_new(struct mln_hash_attr *attr) __NONNULL1(1); extern void -mln_hash_free(mln_hash_t *h, mln_hash_flag_t flg) __NONNULL1(1); +mln_hash_free(mln_hash_t *h, mln_hash_flag_t flg); extern void * mln_hash_search(mln_hash_t *h, void *key) __NONNULL2(1,2); extern void * diff --git a/include/mln_json.h b/include/mln_json.h index e551ef81..65d65baf 100644 --- a/include/mln_json.h +++ b/include/mln_json.h @@ -6,12 +6,12 @@ #ifndef __MLN_JSON_H #define __MLN_JSON_H +#include #include "mln_string.h" -#include "mln_alloc.h" #include "mln_hash.h" -#include "mln_rbtree.h" +#include "mln_array.h" -#define M_JSON_HASH_LEN 31 +#define M_JSON_LEN 31 #define M_JSON_V_FALSE 0 #define M_JSON_V_TRUE 1 @@ -30,17 +30,11 @@ enum json_type { M_JSON_NULL }; -typedef struct { - mln_json_t *key; - mln_json_t *val; -} mln_json_obj_t; - struct mln_json_s { - mln_uauto_t index; enum json_type type; union { - mln_hash_t *m_j_obj; - mln_rbtree_t *m_j_array; + mln_hash_t m_j_obj; + mln_array_t m_j_array; mln_string_t *m_j_string; double m_j_number; mln_u8_t m_j_true; @@ -49,6 +43,11 @@ struct mln_json_s { } data; }; +typedef struct { + mln_json_t key; + mln_json_t val; +} mln_json_kv_t; + #define M_JSON_IS_OBJECT(json) ((json)->type == M_JSON_OBJECT) #define M_JSON_IS_ARRAY(json) ((json)->type == M_JSON_ARRAY) #define M_JSON_IS_STRING(json) ((json)->type == M_JSON_STRING) @@ -66,8 +65,6 @@ struct mln_json_s { #define M_JSON_GET_DATA_FALSE(json) ((json)->data.m_j_false) #define M_JSON_GET_DATA_NULL(json) ((json)->data.m_j_null) -#define M_JSON_SET_INDEX(json,i) (json)->index = (i) - #define M_JSON_SET_TYPE_NONE(json) (json)->type = M_JSON_NONE #define M_JSON_SET_TYPE_OBJECT(json) (json)->type = M_JSON_OBJECT #define M_JSON_SET_TYPE_ARRAY(json) (json)->type = M_JSON_ARRAY @@ -77,26 +74,51 @@ struct mln_json_s { #define M_JSON_SET_TYPE_FALSE(json) (json)->type = M_JSON_FALSE #define M_JSON_SET_TYPE_NULL(json) (json)->type = M_JSON_NULL -#define M_JSON_SET_DATA_STRING(json,str) (json)->data.m_j_string = (str) -#define M_JSON_SET_DATA_NUMBER(json,num) (json)->data.m_j_number = (num) -#define M_JSON_SET_DATA_TRUE(json) (json)->data.m_j_true = 1 -#define M_JSON_SET_DATA_FALSE(json) (json)->data.m_j_false = 1 -#define M_JSON_SET_DATA_NULL(json) (json)->data.m_j_null = NULL - -extern mln_json_t *mln_json_new(void); -extern mln_json_t *mln_json_parse(mln_string_t *jstr); -extern void mln_json_free(void *json); +#define mln_json_init(j) M_JSON_SET_TYPE_NONE(j) +#define mln_json_string_init(j, s) ({\ + mln_json_t *json = (j);\ + M_JSON_SET_TYPE_STRING(json);\ + json->data.m_j_string = (s);\ +}) +#define mln_json_number_init(j, n) ({\ + mln_json_t *json = (j);\ + M_JSON_SET_TYPE_NUMBER(json);\ + json->data.m_j_number = (double)(n);\ +}) +#define mln_json_true_init(j) ({\ + mln_json_t *json = (j);\ + M_JSON_SET_TYPE_TRUE(json);\ + json->data.m_j_true = 1;\ +}) +#define mln_json_false_init(j) ({\ + mln_json_t *json = (j);\ + M_JSON_SET_TYPE_FALSE(json);\ + json->data.m_j_false = 1;\ +}) +#define mln_json_null_init(j) ({\ + mln_json_t *json = (j);\ + M_JSON_SET_TYPE_NULL(json);\ + json->data.m_j_null = NULL;\ +}) +extern int mln_json_obj_init(mln_json_t *j) __NONNULL1(1); +extern int mln_json_array_init(mln_json_t *j) __NONNULL1(1); +extern void mln_json_destroy(mln_json_t *j); +#define mln_json_reset(j) ({\ + mln_json_t *json = (j);\ + mln_json_destroy(json);\ + M_JSON_SET_TYPE_NONE((json));\ +}) extern void mln_json_dump(mln_json_t *j, int n_space, char *prefix); -extern mln_string_t *mln_json_generate(mln_json_t *j); -extern mln_json_t *mln_json_value_search(mln_json_t *j, mln_string_t *key); -extern mln_json_t *mln_json_element_search(mln_json_t *j, mln_uauto_t index); -extern mln_uauto_t mln_json_array_length(mln_json_t *j); -extern int mln_json_obj_update(mln_json_t *j, mln_json_t *key, mln_json_t *val); -extern int mln_json_element_add(mln_json_t *j, mln_json_t *value); -extern int mln_json_element_update(mln_json_t *j, mln_json_t *value, mln_uauto_t index); -extern void mln_json_reset(mln_json_t *j); -extern mln_json_t *mln_json_obj_remove(mln_json_t *j, mln_string_t *key); -extern mln_json_t *mln_json_element_remove(mln_json_t *j, mln_uauto_t index); +extern int mln_json_obj_update(mln_json_t *j, mln_json_t *key, mln_json_t *val) __NONNULL3(1,2,3); +extern mln_json_t *mln_json_obj_search(mln_json_t *j, mln_string_t *key) __NONNULL2(1,2); +extern void mln_json_obj_remove(mln_json_t *j, mln_string_t *key) __NONNULL2(1,2); +extern mln_json_t *mln_json_array_search(mln_json_t *j, mln_uauto_t index) __NONNULL1(1); +extern mln_uauto_t mln_json_array_length(mln_json_t *j) __NONNULL1(1); +extern int mln_json_array_append(mln_json_t *j, mln_json_t *value) __NONNULL2(1,2); +extern int mln_json_array_update(mln_json_t *j, mln_json_t *value, mln_uauto_t index) __NONNULL2(1,2); +extern void mln_json_array_remove(mln_json_t *j, mln_uauto_t index); +extern int mln_json_decode(mln_string_t *jstr, mln_json_t *out); +extern mln_string_t *mln_json_encode(mln_json_t *j); #endif diff --git a/src/mln_fork.c b/src/mln_fork.c index aed4e498..76a4523e 100644 --- a/src/mln_fork.c +++ b/src/mln_fork.c @@ -91,14 +91,14 @@ int mln_fork_prepare(void) rbattr.pool_free = NULL; rbattr.cmp = mln_fork_rbtree_cmp; rbattr.data_free = (rbtree_free_data)mln_ipc_handler_free; - if ((master_ipc_tree = mln_rbtree_new(&rbattr)) != NULL) { + if ((master_ipc_tree = mln_rbtree_new(&rbattr)) == NULL) { mln_log(error, "No memory.\n"); if (mln_tcp_conn_fd_get(&master_conn) >= 0) mln_socket_close(mln_tcp_conn_fd_get(&master_conn)); mln_tcp_conn_destroy(&master_conn); return -1; } - if ((worker_ipc_tree = mln_rbtree_new(&rbattr)) != NULL) { + if ((worker_ipc_tree = mln_rbtree_new(&rbattr)) == NULL) { mln_log(error, "No memory.\n"); mln_rbtree_free(master_ipc_tree); master_ipc_tree = NULL; diff --git a/src/mln_hash.c b/src/mln_hash.c index 1f322a3b..839df438 100644 --- a/src/mln_hash.c +++ b/src/mln_hash.c @@ -23,6 +23,42 @@ mln_hash_expand(mln_hash_t *h) __NONNULL1(1); static inline void mln_move_hash_entry(mln_hash_t *h, mln_hash_mgr_t *old_tbl, mln_u32_t old_len) __NONNULL2(1,2); +int mln_hash_init(mln_hash_t *h, struct mln_hash_attr *attr) +{ + h->pool = attr->pool; + h->pool_alloc = attr->pool_alloc; + h->pool_free = attr->pool_free; + h->hash = attr->hash; + h->cmp = attr->cmp; + h->free_key = attr->free_key; + h->free_val = attr->free_val; + h->len = attr->calc_prime? mln_prime_generate(attr->len_base): attr->len_base; + if (h->pool != NULL) { + h->tbl = (mln_hash_mgr_t *)h->pool_alloc(h->pool, h->len*sizeof(mln_hash_mgr_t)); + memset(h->tbl, 0, h->len*sizeof(mln_hash_mgr_t)); + } else { + h->tbl = (mln_hash_mgr_t *)calloc(h->len, sizeof(mln_hash_mgr_t)); + } + if (h->tbl == NULL) return -1; + + h->nr_nodes = 0; + h->threshold = attr->calc_prime? mln_prime_generate(h->len << 1): h->len << 1; + h->expandable = attr->expandable; + h->calc_prime = attr->calc_prime; + if (h->len == 0 || \ + h->hash == NULL || \ + h->cmp == NULL) + { + if (h->pool != NULL) { + h->pool_free(h->tbl); + } else { + free(h->tbl); + } + return -1; + } + return 0; +} + mln_hash_t * mln_hash_new(struct mln_hash_attr *attr) { @@ -73,9 +109,28 @@ mln_hash_new(struct mln_hash_attr *attr) return h; } -void -mln_hash_free(mln_hash_t *h, mln_hash_flag_t flg) +void mln_hash_destroy(mln_hash_t *h, mln_hash_flag_t flg) { + if (h == NULL) return; + + mln_hash_entry_t *he, *fr; + mln_hash_mgr_t *mgr, *mgr_end = h->tbl + h->len; + for (mgr = h->tbl; mgr < mgr_end; ++mgr) { + he = mgr->head; + while (he != NULL) { + fr = he; + he = he->next; + mln_hash_entry_free(h, fr, flg); + } + } + if (h->pool != NULL) h->pool_free(h->tbl); + else free(h->tbl); +} + +void mln_hash_free(mln_hash_t *h, mln_hash_flag_t flg) +{ + if (h == NULL) return; + mln_hash_entry_t *he, *fr; mln_hash_mgr_t *mgr, *mgr_end = h->tbl + h->len; for (mgr = h->tbl; mgr < mgr_end; ++mgr) { @@ -170,7 +225,7 @@ static inline void mln_hash_expand(mln_hash_t *h) { mln_hash_mgr_t *old_tbl = h->tbl; mln_u32_t len = h->len; - h->len = h->calc_prime? mln_prime_generate(len + (len >> 1)): (len + (len >> 1)); + h->len = h->calc_prime? mln_prime_generate(len << 1): ((len << 1) - 1); if (h->pool != NULL) { h->tbl = (mln_hash_mgr_t *)h->pool_alloc(h->pool, h->len*sizeof(mln_hash_mgr_t)); memset(h->tbl, 0, h->len*sizeof(mln_hash_mgr_t)); @@ -182,8 +237,8 @@ static inline void mln_hash_expand(mln_hash_t *h) h->len = len; return; } - h->threshold = h->calc_prime? mln_prime_generate(h->threshold + (h->threshold >> 1)): \ - (h->threshold + (h->threshold >> 1)); + h->threshold = h->calc_prime? mln_prime_generate(h->threshold << 1): \ + ((h->threshold << 1) - 1); mln_move_hash_entry(h, old_tbl, len); if (h->pool != NULL) h->pool_free(old_tbl); else free(old_tbl); diff --git a/src/mln_json.c b/src/mln_json.c index 090bef73..71986895 100644 --- a/src/mln_json.c +++ b/src/mln_json.c @@ -3,19 +3,11 @@ * Copyright (C) Niklaus F.Schen. */ -#include #include #include #include "mln_json.h" -static inline mln_json_obj_t *mln_json_obj_new(void); -static void mln_json_encode_utf8(unsigned int u, mln_u8ptr_t *b, int *count); -static inline int mln_json_get_char(mln_u8ptr_t *s, int *len, unsigned int *hex); -static mln_u64_t mln_json_hash_calc(mln_hash_t *h, void *key); -static int mln_json_hash_cmp(mln_hash_t *h, void *key1, void *key2); -static void mln_json_obj_free(void *data); -static int mln_json_rbtree_cmp(const void *data1, const void *data2); -static inline void mln_json_jumpoff_blank(char **jstr, int *len); +static int mln_json_dump_hash_iterate_handler(void *key, void *val, void *data); static inline int mln_json_parse_json(mln_json_t *j, char *jstr, int len, mln_uauto_t index); static inline int @@ -26,6 +18,8 @@ static inline int mln_json_parse_string(mln_json_t *j, char *jstr, int len, mln_uauto_t index); static mln_u8ptr_t mln_json_parse_string_fetch(mln_u8ptr_t jstr, int *len); +static void mln_json_encode_utf8(unsigned int u, mln_u8ptr_t *b, int *count); +static inline int mln_json_get_char(mln_u8ptr_t *s, int *len, unsigned int *hex); static int mln_json_parse_digit(mln_json_t *j, char *jstr, int len, mln_uauto_t index); static inline int @@ -36,64 +30,190 @@ static inline int mln_json_parse_false(mln_json_t *j, char *jstr, int len, mln_uauto_t index); static inline int mln_json_parse_null(mln_json_t *j, char *jstr, int len, mln_uauto_t index); - -static int mln_json_dump_hash_iterate_handler(void *key, void *val, void *data); -static int mln_json_dump_rbtree_iterate_handler(mln_rbtree_node_t *node, void *udata); +static inline void mln_json_jumpoff_blank(char **jstr, int *len); static inline mln_size_t mln_json_get_length(mln_json_t *j); static int mln_json_get_length_hash_iterate_handler(void *key, void *val, void *data); -static int -mln_json_get_length_rbtree_iterate_handler(mln_rbtree_node_t *node, void *data); static inline mln_size_t mln_json_write_content(mln_json_t *j, mln_s8ptr_t buf); static int mln_json_write_content_hash_iterate_handler(void *key, void *val, void *data); -static int -mln_json_write_content_rbtree_iterate_handler(mln_rbtree_node_t *node, void *data); -mln_json_t *mln_json_parse(mln_string_t *jstr) + +static mln_u64_t mln_json_kv_calc(mln_hash_t *h, mln_string_t *str) { - if (jstr == NULL) { - return NULL; - } + mln_u8ptr_t s, end = str->data + str->len; + mln_u64_t index = 0, tbl_len = h->len; - mln_json_t *j = mln_json_new(); - if (j == NULL) { - return NULL; + for (s = str->data; s < end; ++s) { + index += (((mln_u64_t)(*s)) * 65599); + index %= tbl_len; } - if (mln_json_parse_json(j, (char *)(jstr->data), jstr->len, 0) != 0) { - mln_json_free(j); - return NULL; - } - if (j->type != M_JSON_OBJECT && j->type != M_JSON_ARRAY) { - mln_json_free(j); - return NULL; + return index; +} + +static int mln_json_kv_cmp(mln_hash_t *h, mln_string_t *key1, mln_string_t *key2) +{ + return !mln_string_strcmp(key1, key2); +} + +static void mln_json_kv_free(mln_json_kv_t *kv) +{ + if (kv == NULL) return; + + mln_json_destroy(&(kv->key)); + mln_json_destroy(&(kv->val)); + free(kv); +} + + +int mln_json_obj_init(mln_json_t *j) +{ + struct mln_hash_attr hattr; + + mln_json_init(j); + M_JSON_SET_TYPE_OBJECT(j); + hattr.pool = NULL; + hattr.pool_alloc = NULL; + hattr.pool_free = NULL; + hattr.hash = (hash_calc_handler)mln_json_kv_calc; + hattr.cmp = (hash_cmp_handler)mln_json_kv_cmp; + hattr.free_key = NULL; + hattr.free_val = (hash_free_handler)mln_json_kv_free; + hattr.len_base = M_JSON_LEN; + hattr.expandable = 1; + hattr.calc_prime = 0; + return mln_hash_init(&(j->data.m_j_obj), &hattr); +} + +int mln_json_obj_update(mln_json_t *j, mln_json_t *key, mln_json_t *val) +{ + mln_json_kv_t *kv; + + if (!M_JSON_IS_STRING(key) || !M_JSON_IS_OBJECT(j)) return -1; + + kv = (mln_json_kv_t *)mln_hash_search(&(j->data.m_j_obj), key->data.m_j_string); + if (kv == NULL) { + kv = (mln_json_kv_t *)malloc(sizeof(mln_json_kv_t)); + if (kv == NULL) return -1; + + kv->key = *key; + kv->val = *val; + if (mln_hash_insert(&(j->data.m_j_obj), key->data.m_j_string, kv) < 0) { + mln_json_kv_free(kv); + return -1; + } + } else { + mln_json_destroy(&(kv->key)); + mln_json_destroy(&(kv->val)); + kv->key = *key; + kv->val = *val; } - return j; + return 0; +} + +mln_json_t *mln_json_obj_search(mln_json_t *j, mln_string_t *key) +{ + if (!M_JSON_IS_OBJECT(j)) return NULL; + + mln_hash_t *h = &(j->data.m_j_obj); + mln_json_kv_t *kv = (mln_json_kv_t *)mln_hash_search(h, key); + return &(kv->val); +} + +void mln_json_obj_remove(mln_json_t *j, mln_string_t *key) +{ + if (!M_JSON_IS_OBJECT(j)) return; + + mln_json_kv_t *kv; + mln_hash_t *h = &(j->data.m_j_obj); + + kv = (mln_json_kv_t *)mln_hash_search(h, key); + if (kv == NULL) return; + + mln_hash_remove(h, key, M_HASH_F_VAL); +} + + +int mln_json_array_init(mln_json_t *j) +{ + struct mln_array_attr attr; + + mln_json_init(j); + M_JSON_SET_TYPE_ARRAY(j); + attr.pool = NULL; + attr.pool_alloc = NULL; + attr.pool_free = NULL; + attr.free = (array_free)mln_json_destroy; + attr.size = sizeof(mln_json_t); + attr.nalloc = M_JSON_LEN; + return mln_array_init(&(j->data.m_j_array), &attr); +} + +mln_json_t *mln_json_array_search(mln_json_t *j, mln_uauto_t index) +{ + if (!M_JSON_IS_ARRAY(j)) return NULL; + + mln_array_t *arr = &(j->data.m_j_array); + + if (index >= mln_array_nelts(arr)) return NULL; + + return &(((mln_json_t *)mln_array_elts(arr))[index]); +} + +mln_uauto_t mln_json_array_length(mln_json_t *j) +{ + if (!M_JSON_IS_ARRAY(j)) return 0; + return mln_array_nelts(&(j->data.m_j_array)); +} + +int mln_json_array_append(mln_json_t *j, mln_json_t *value) +{ + mln_json_t *elem; + + if (!M_JSON_IS_ARRAY(j)) return -1; + + if ((elem = (mln_json_t *)mln_array_push(&(j->data.m_j_array))) == NULL) + return -1; + *elem = *value; + return 0; +} + +int mln_json_array_update(mln_json_t *j, mln_json_t *value, mln_uauto_t index) +{ + if (!M_JSON_IS_ARRAY(j)) return -1; + + mln_array_t *arr = &(j->data.m_j_array); + if (index >= mln_array_nelts(arr)) return -1; + + mln_json_destroy(&(((mln_json_t *)mln_array_elts(arr))[index])); + ((mln_json_t *)mln_array_elts(arr))[index] = *value; + return 0; } -mln_json_t *mln_json_new(void) +void mln_json_array_remove(mln_json_t *j, mln_uauto_t index) { - return (mln_json_t *)calloc(1, sizeof(mln_json_t)); + if (j == NULL || !M_JSON_IS_ARRAY(j)) return; + + mln_array_t *arr = &(j->data.m_j_array); + + ASSERT(index == mln_array_nelts(arr) - 1); + + mln_array_pop(arr); } -void mln_json_free(void *json) +void mln_json_destroy(mln_json_t *j) { - mln_json_t *j = (mln_json_t *)json; if (j == NULL) return; switch (j->type) { case M_JSON_OBJECT: - if (j->data.m_j_obj != NULL) { - mln_hash_free(j->data.m_j_obj, M_HASH_F_VAL); - } + mln_hash_destroy(&(j->data.m_j_obj), M_HASH_F_VAL); break; case M_JSON_ARRAY: - if (j->data.m_j_array != NULL) { - mln_rbtree_free(j->data.m_j_array); - } + mln_array_destroy(&(j->data.m_j_array)); break; case M_JSON_STRING: if (j->data.m_j_string != NULL) { @@ -108,8 +228,95 @@ void mln_json_free(void *json) default: break; } +} + + +/* + * dump + */ +void mln_json_dump(mln_json_t *j, int n_space, char *prefix) +{ + if (j == NULL) return; + + int i, space = n_space + 2; + for (i = 0; i < n_space; ++i) + printf(" "); + + if (prefix != NULL) { + printf("%s ", prefix); + } + switch (j->type) { + case M_JSON_OBJECT: + printf("type:object\n"); + mln_hash_iterate(&(j->data.m_j_obj), mln_json_dump_hash_iterate_handler, &space); + break; + case M_JSON_ARRAY: + { + printf("type:array\n"); + mln_json_t *elem = mln_array_elts(&(j->data.m_j_array)); + mln_json_t *end = elem + mln_array_nelts(&(j->data.m_j_array)); + for (; elem < end; ++elem) { + mln_json_dump(elem, space, "Array member:"); + } + break; + } + case M_JSON_STRING: + if (j->data.m_j_string != NULL && j->data.m_j_string->data != NULL) + printf("type:string val:[%s]\n", (char *)(j->data.m_j_string->data)); + break; + case M_JSON_NUM: + printf("type:number val:[%f]\n", j->data.m_j_number); + break; + case M_JSON_TRUE: + printf("type:true val:[true]\n"); + break; + case M_JSON_FALSE: + printf("type:false val:[false]\n"); + break; + case M_JSON_NULL: + printf("type:NULL val:[NULL]\n"); + break; + default: + printf("type:none\n"); + break; + } +} + +static int mln_json_dump_hash_iterate_handler(void *key, void *val, void *data) +{ + int *space = (int *)data; + mln_json_kv_t *kv = (mln_json_kv_t *)val; + + if (kv == NULL) return 0; + + if (!M_JSON_IS_NONE(&(kv->key))) mln_json_dump(&(kv->key), *space, "Object key:"); + if (!M_JSON_IS_NONE(&(kv->val))) mln_json_dump(&(kv->val), *space, "Object value:"); + + return 0; +} + + +/* + * decode + */ +int mln_json_decode(mln_string_t *jstr, mln_json_t *out) +{ + if (jstr == NULL || out == NULL) { + return -1; + } + + mln_json_init(out); + + if (mln_json_parse_json(out, (char *)(jstr->data), jstr->len, 0) != 0) { + mln_json_destroy(out); + return -1; + } + if (!M_JSON_IS_OBJECT(out) && !M_JSON_IS_ARRAY(out)) { + mln_json_destroy(out); + return -1; + } - free(j); + return 0; } static inline int @@ -150,8 +357,7 @@ static inline int mln_json_parse_obj(mln_json_t *val, char *jstr, int len, mln_uauto_t index) { int left; - struct mln_hash_attr hattr; - mln_json_obj_t *obj; + mln_json_t key, v; /*jump off '{'*/ ++jstr; @@ -159,76 +365,56 @@ mln_json_parse_obj(mln_json_t *val, char *jstr, int len, mln_uauto_t index) return -1; } - val->index = index; - val->type = M_JSON_OBJECT; - hattr.pool = NULL; - hattr.pool_alloc = NULL; - hattr.pool_free = NULL; - hattr.hash = mln_json_hash_calc; - hattr.cmp = mln_json_hash_cmp; - hattr.free_key = NULL; - hattr.free_val = mln_json_obj_free; - hattr.len_base = M_JSON_HASH_LEN; - hattr.expandable = 1; - hattr.calc_prime = 0; - val->data.m_j_obj = mln_hash_new(&hattr); - if (val->data.m_j_obj == NULL) { - return -1; - } + if (mln_json_obj_init(val) < 0) return -1; again: - obj = mln_json_obj_new(); - if (obj == NULL) { - return -1; - } - - obj->key = mln_json_new(); - if (obj->key == NULL) { - mln_json_obj_free(obj); - return -1; - } + mln_json_init(&key); + mln_json_init(&v); mln_json_jumpoff_blank(&jstr, &len); if (jstr[0] != '}') { - left = mln_json_parse_json(obj->key, jstr, len, 0); + left = mln_json_parse_json(&key, jstr, len, 0); if (left <= 0) { - mln_json_obj_free(obj); + mln_json_destroy(&key); + mln_json_destroy(&v); return -1; } - if (obj->key->type != M_JSON_STRING) { - mln_json_obj_free(obj); + if (!M_JSON_IS_STRING(&key)) { + mln_json_destroy(&key); + mln_json_destroy(&v); return -1; } jstr += (len - left); len = left; if (len <= 0) { - return -1; - } - - if (mln_hash_insert(val->data.m_j_obj, obj->key->data.m_j_string, obj) < 0) { - mln_json_obj_free(obj); + mln_json_destroy(&key); + mln_json_destroy(&v); return -1; } mln_json_jumpoff_blank(&jstr, &len); if (len <= 0) { + mln_json_destroy(&key); + mln_json_destroy(&v); return -1; } /*jump off ':'*/ if (jstr[0] != ':') { + mln_json_destroy(&key); + mln_json_destroy(&v); return -1; } ++jstr; if (--len <= 0) { + mln_json_destroy(&key); + mln_json_destroy(&v); return -1; } - obj->val = mln_json_new(); - if (obj->val == NULL) { - return -1; - } - left = mln_json_parse_json(obj->val, jstr, len, 0); + left = mln_json_parse_json(&v, jstr, len, 0); if (left <= 0) { + mln_json_destroy(&key); + mln_json_destroy(&v); return -1; } jstr += (len - left); @@ -236,6 +422,14 @@ mln_json_parse_obj(mln_json_t *val, char *jstr, int len, mln_uauto_t index) mln_json_jumpoff_blank(&jstr, &len); if (len <= 0) { + mln_json_destroy(&key); + mln_json_destroy(&v); + return -1; + } + + if (mln_json_obj_update(val, &key, &v) < 0) { + mln_json_destroy(&key); + mln_json_destroy(&v); return -1; } } @@ -260,22 +454,10 @@ static inline int mln_json_parse_array(mln_json_t *val, char *jstr, int len, mln_uauto_t index) { int left; - mln_json_t *j; + mln_json_t j; mln_uauto_t cnt = 0; - mln_rbtree_node_t *rn; - struct mln_rbtree_attr rbattr; - - rbattr.pool = NULL; - rbattr.pool_alloc = NULL; - rbattr.pool_free = NULL; - rbattr.cmp = mln_json_rbtree_cmp; - rbattr.data_free = mln_json_free; - val->index = index; - val->type = M_JSON_ARRAY; - val->data.m_j_array = mln_rbtree_new(&rbattr); - if (val->data.m_j_array == NULL) { - return -1; - } + + if (mln_json_array_init(val) < 0) return -1; ++jstr; if (--len <= 0) { @@ -283,30 +465,25 @@ mln_json_parse_array(mln_json_t *val, char *jstr, int len, mln_uauto_t index) } again: - j = mln_json_new(); - if (j == NULL) { - return -1; - } + mln_json_init(&j); if (jstr[0] != ']') { - left = mln_json_parse_json(j, jstr, len, ++cnt); + left = mln_json_parse_json(&j, jstr, len, ++cnt); if (left <= 0) { - mln_json_free(j); + mln_json_destroy(&j); return -1; } jstr += (len - left); len = left; if (len <= 0) { - mln_json_free(j); + mln_json_destroy(&j); return -1; } } - rn = mln_rbtree_node_new(val->data.m_j_array, j); - if (rn == NULL) { - mln_json_free(j); + if (mln_json_array_append(val, &j) < 0) { + mln_json_destroy(&j); return -1; } - mln_rbtree_insert(val->data.m_j_array, rn); mln_json_jumpoff_blank(&jstr, &len); if (len <= 0) { @@ -367,9 +544,7 @@ mln_json_parse_string(mln_json_t *j, char *jstr, int len, mln_uauto_t index) return -1; } - j->index = index; - j->type = M_JSON_STRING; - j->data.m_j_string = str; + mln_json_string_init(j, str); return --plen; /* jump off " */ } @@ -519,9 +694,7 @@ mln_json_parse_digit(mln_json_t *j, char *jstr, int len, mln_uauto_t index) return -1; } - j->index = index; - j->type = M_JSON_NUM; - j->data.m_j_number = sub_flag? -val: val; + mln_json_number_init(j, sub_flag? -val: val); return left; } @@ -601,10 +774,7 @@ mln_json_parse_true(mln_json_t *j, char *jstr, int len, mln_uauto_t index) if (strncasecmp(jstr, "true", 4)) { return -1; } - - j->index = index; - j->type = M_JSON_TRUE; - j->data.m_j_true = 1; + mln_json_true_init(j); return len - 4; } @@ -619,10 +789,7 @@ mln_json_parse_false(mln_json_t *j, char *jstr, int len, mln_uauto_t index) if (strncasecmp(jstr, "false", 5)) { return -1; } - - j->index = index; - j->type = M_JSON_FALSE; - j->data.m_j_false = 1; + mln_json_false_init(j); return len - 5; } @@ -637,15 +804,21 @@ mln_json_parse_null(mln_json_t *j, char *jstr, int len, mln_uauto_t index) if (strncasecmp(jstr, "null", 4)) { return -1; } - - j->index = index; - j->type = M_JSON_NULL; - j->data.m_j_null = NULL; + mln_json_null_init(j); return len - 4; } -mln_string_t *mln_json_generate(mln_json_t *j) +static inline void mln_json_jumpoff_blank(char **jstr, int *len) +{ + for (; \ + *len > 0 && (*jstr[0] == ' ' || *jstr[0] == '\t' || *jstr[0] == '\r' || *jstr[0] == '\n'); \ + ++(*jstr), --(*len)) + ; +} + + +mln_string_t *mln_json_encode(mln_json_t *j) { mln_u32_t size = mln_json_get_length(j), n; mln_s8ptr_t buf; @@ -664,107 +837,51 @@ mln_string_t *mln_json_generate(mln_json_t *j) return s; } -struct mln_json_tmp_s { - mln_size_t *length; - mln_s8ptr_t *buf; -}; - -static inline mln_size_t -mln_json_write_content(mln_json_t *j, mln_s8ptr_t buf) +static inline mln_size_t mln_json_get_length(mln_json_t *j) { if (j == NULL) return 0; - int n; - mln_size_t length = 0, save; - mln_string_t *s; - struct mln_json_tmp_s tmp; + char num_str[512] = {0}; + mln_size_t length = 1; mln_u8ptr_t p, end; switch (j->type) { case M_JSON_OBJECT: - *buf++ = '{'; - ++length; - tmp.length = &length; - tmp.buf = &buf; - save = length; - if (j->data.m_j_obj != NULL) - mln_hash_iterate(j->data.m_j_obj, \ - mln_json_write_content_hash_iterate_handler, \ - &tmp); - if (save < length) { - --buf; - --length; - *buf = 0; - } - *buf++ = '}'; - ++length; + length += 2; + mln_hash_iterate(&(j->data.m_j_obj), mln_json_get_length_hash_iterate_handler, &length); break; case M_JSON_ARRAY: - *buf++ = '['; - ++length; - tmp.length = &length; - tmp.buf = &buf; - save = length; - if (j->data.m_j_array != NULL) - mln_rbtree_iterate(j->data.m_j_array, \ - mln_json_write_content_rbtree_iterate_handler, \ - &tmp); - if (save < length) { - --buf; - --length; - *buf = 0; + { + mln_json_t *el = (mln_json_t *)mln_array_elts(&(j->data.m_j_array)); + mln_json_t *elend = el + mln_array_nelts(&(j->data.m_j_array)); + length += 2; + for (; el < elend; ++el) { + length += (mln_json_get_length(el) + 1); } - *buf++ = ']'; - ++length; break; + } case M_JSON_STRING: - *buf++ = '\"'; - ++length; - if ((s = j->data.m_j_string) != NULL) { + length += 2; + if (j->data.m_j_string != NULL) { p = j->data.m_j_string->data; end = p + j->data.m_j_string->len; - for (; p < end; ) { - if (*p == '\"' || *p == '\\') { - *buf++ = '\\'; + for (; p < end; ++p) { + if (*p == '\"' || *p == '\\') ++length; - } - *buf++ = *p++; - ++length; } + length += j->data.m_j_string->len; } - *buf++ = '\"'; - ++length; break; case M_JSON_NUM: - { - mln_s64_t i = (mln_s64_t)(j->data.m_j_number); - if (i == j->data.m_j_number) -#if defined(WIN32) - n = snprintf(buf, 512, "%I64d", i); -#elif defined(i386) || defined(__arm__) || defined(__wasm__) - n = snprintf(buf, 512, "%lld", i); -#else - n = snprintf(buf, 512, "%ld", i); -#endif - else - n = snprintf(buf, 512, "%f", j->data.m_j_number); - buf += n; - length += n; + length += snprintf(num_str, sizeof(num_str), "%f", j->data.m_j_number); break; - } case M_JSON_TRUE: - memcpy(buf, "true", 4); - buf += 4; length += 4; break; case M_JSON_FALSE: - memcpy(buf, "false", 5); - buf += 5; length += 5; break; case M_JSON_NULL: - memcpy(buf, "null", 4); - buf += 4; length += 4; break; default: @@ -775,98 +892,124 @@ mln_json_write_content(mln_json_t *j, mln_s8ptr_t buf) } static int -mln_json_write_content_hash_iterate_handler(void *key, void *val, void *data) +mln_json_get_length_hash_iterate_handler(void *key, void *val, void *data) { - mln_json_obj_t *obj = (mln_json_obj_t *)val; - struct mln_json_tmp_s *tmp = (struct mln_json_tmp_s *)data; - mln_s8ptr_t *buf = tmp->buf; - mln_size_t *length = tmp->length; - mln_size_t n; - - if (obj == NULL) return 0; + mln_json_kv_t *kv = (mln_json_kv_t *)val; + mln_size_t *length = (mln_size_t *)data; - if (obj->key != NULL) { - n = mln_json_write_content(obj->key, *buf); - (*buf) += n; - (*length) += n; - } - *(*buf)++ = ':'; - ++(*length); - if (obj->val != NULL) { - n = mln_json_write_content(obj->val, *buf); - (*buf) += n; - (*length) += n; - } - - *(*buf)++ = ','; - (*length) += 1; + if (kv == NULL) return 0; + (*length) += (mln_json_get_length(&(kv->key)) + mln_json_get_length(&(kv->val)) + 2); return 0; } -static int -mln_json_write_content_rbtree_iterate_handler(mln_rbtree_node_t *node, void *data) -{ - mln_json_t *j = (mln_json_t *)mln_rbtree_node_data_get(node); - struct mln_json_tmp_s *tmp = (struct mln_json_tmp_s *)data; - mln_size_t *length = tmp->length, n; - mln_s8ptr_t *buf = tmp->buf; - - if (j == NULL) return 0; - - n = mln_json_write_content(j, *buf); - (*buf) += n; - (*length) += n; - - *(*buf)++ = ','; - (*length) += 1; - - return 0; -} +struct mln_json_tmp_s { + mln_size_t *length; + mln_s8ptr_t *buf; +}; -static inline mln_size_t mln_json_get_length(mln_json_t *j) +static inline mln_size_t +mln_json_write_content(mln_json_t *j, mln_s8ptr_t buf) { if (j == NULL) return 0; - char num_str[512] = {0}; - mln_size_t length = 1; + int n; + mln_size_t length = 0, save; + mln_string_t *s; + struct mln_json_tmp_s tmp; mln_u8ptr_t p, end; switch (j->type) { case M_JSON_OBJECT: - length += 2; - if (j->data.m_j_obj != NULL) - mln_hash_iterate(j->data.m_j_obj, mln_json_get_length_hash_iterate_handler, &length); + *buf++ = '{'; + ++length; + tmp.length = &length; + tmp.buf = &buf; + save = length; + mln_hash_iterate(&(j->data.m_j_obj), \ + mln_json_write_content_hash_iterate_handler, \ + &tmp); + if (save < length) { + --buf; + --length; + *buf = 0; + } + *buf++ = '}'; + ++length; break; case M_JSON_ARRAY: - length += 2; - if (j->data.m_j_array != NULL) - mln_rbtree_iterate(j->data.m_j_array, \ - mln_json_get_length_rbtree_iterate_handler, \ - &length); + { + mln_json_t *el = (mln_json_t *)mln_array_elts(&(j->data.m_j_array)); + mln_json_t *elend = el + mln_array_nelts(&(j->data.m_j_array)); + + *buf++ = '['; + ++length; + save = length; + for (; el < elend; ++el) { + n = mln_json_write_content(el, buf); + buf += n; + length += n; + + *buf++ = ','; + length += 1; + } + if (save < length) { + --buf; + --length; + *buf = 0; + } + *buf++ = ']'; + ++length; break; + } case M_JSON_STRING: - length += 2; - if (j->data.m_j_string != NULL) { + *buf++ = '\"'; + ++length; + if ((s = j->data.m_j_string) != NULL) { p = j->data.m_j_string->data; end = p + j->data.m_j_string->len; - for (; p < end; ++p) { - if (*p == '\"' || *p == '\\') + for (; p < end; ) { + if (*p == '\"' || *p == '\\') { + *buf++ = '\\'; ++length; + } + *buf++ = *p++; + ++length; } - length += j->data.m_j_string->len; } + *buf++ = '\"'; + ++length; break; case M_JSON_NUM: - length += snprintf(num_str, sizeof(num_str), "%f", j->data.m_j_number); + { + mln_s64_t i = (mln_s64_t)(j->data.m_j_number); + if (i == j->data.m_j_number) +#if defined(WIN32) + n = snprintf(buf, 512, "%I64d", i); +#elif defined(i386) || defined(__arm__) || defined(__wasm__) + n = snprintf(buf, 512, "%lld", i); +#else + n = snprintf(buf, 512, "%ld", i); +#endif + else + n = snprintf(buf, 512, "%f", j->data.m_j_number); + buf += n; + length += n; break; + } case M_JSON_TRUE: + memcpy(buf, "true", 4); + buf += 4; length += 4; break; case M_JSON_FALSE: + memcpy(buf, "false", 5); + buf += 5; length += 5; break; case M_JSON_NULL: + memcpy(buf, "null", 4); + buf += 4; length += 4; break; default: @@ -877,419 +1020,28 @@ static inline mln_size_t mln_json_get_length(mln_json_t *j) } static int -mln_json_get_length_hash_iterate_handler(void *key, void *val, void *data) +mln_json_write_content_hash_iterate_handler(void *key, void *val, void *data) { - mln_json_obj_t *obj = (mln_json_obj_t *)val; - mln_size_t *length = (mln_size_t *)data; - - if (obj == NULL) return 0; - - if (obj->key != NULL) { - (*length) += mln_json_get_length(obj->key); - } - if (obj->val != NULL) { - (*length) += mln_json_get_length(obj->val); - } - - (*length) += 2; - - return 0; -} + mln_json_kv_t *kv = (mln_json_kv_t *)val; + struct mln_json_tmp_s *tmp = (struct mln_json_tmp_s *)data; + mln_s8ptr_t *buf = tmp->buf; + mln_size_t *length = tmp->length; + mln_size_t n; -static int -mln_json_get_length_rbtree_iterate_handler(mln_rbtree_node_t *node, void *data) -{ - mln_json_t *j = (mln_json_t *)mln_rbtree_node_data_get(node); - mln_size_t *length = (mln_size_t *)data; + if (kv == NULL) return 0; - if (j == NULL) return 0; + n = mln_json_write_content(&(kv->key), *buf); + (*buf) += n; + (*length) += n; + *(*buf)++ = ':'; + ++(*length); + n = mln_json_write_content(&(kv->val), *buf); + (*buf) += n; + (*length) += n; - (*length) += mln_json_get_length(j); + *(*buf)++ = ','; (*length) += 1; return 0; } -/* - * tools - */ -static inline mln_json_obj_t *mln_json_obj_new(void) -{ - return (mln_json_obj_t *)calloc(1, sizeof(mln_json_obj_t)); -} - -static mln_u64_t mln_json_hash_calc(mln_hash_t *h, void *key) -{ - mln_string_t *str = (mln_string_t *)key; - mln_u8ptr_t s, end = str->data + str->len; - mln_u64_t index = 0, tbl_len = h->len; - - for (s = str->data; s < end; ++s) { - index += (((mln_u64_t)(*s)) * 65599); - index %= tbl_len; - } - - return index; -} - -static int mln_json_hash_cmp(mln_hash_t *h, void *key1, void *key2) -{ - return !mln_string_strcmp((mln_string_t *)key1, (mln_string_t *)key2); -} - -static void mln_json_obj_free(void *data) -{ - mln_json_obj_t *obj = (mln_json_obj_t *)data; - if (obj == NULL) return; - - if (obj->key != NULL) { - mln_json_free(obj->key); - } - - if (obj->val != NULL) { - mln_json_free(obj->val); - } - - free(obj); -} - -static int mln_json_rbtree_cmp(const void *data1, const void *data2) -{ - mln_json_t *j1 = (mln_json_t *)data1; - mln_json_t *j2 = (mln_json_t *)data2; - - if (j1 == NULL && j1 == j2) return 0; - if (j1 == NULL) return -1; - if (j2 == NULL) return 1; - - if (j1->index > j2->index) return 1; - if (j1->index == j2->index) return 0; - return -1; -} - -static inline void mln_json_jumpoff_blank(char **jstr, int *len) -{ - for (; \ - *len > 0 && (*jstr[0] == ' ' || *jstr[0] == '\t' || *jstr[0] == '\r' || *jstr[0] == '\n'); \ - ++(*jstr), --(*len)) - ; -} - -/* - * dump - */ -void mln_json_dump(mln_json_t *j, int n_space, char *prefix) -{ - if (j == NULL) return; - - int i, space = n_space + 2; - for (i = 0; i < n_space; ++i) - printf(" "); - - if (prefix != NULL) { - printf("%s ", prefix); - } - printf("index:%lu ", j->index); - switch (j->type) { - case M_JSON_OBJECT: - printf("type:object\n"); - if (j->data.m_j_obj != NULL) - mln_hash_iterate(j->data.m_j_obj, mln_json_dump_hash_iterate_handler, &space); - break; - case M_JSON_ARRAY: - printf("type:array\n"); - if (j->data.m_j_array != NULL) - mln_rbtree_iterate(j->data.m_j_array, \ - mln_json_dump_rbtree_iterate_handler, \ - &space); - break; - case M_JSON_STRING: - if (j->data.m_j_string != NULL && j->data.m_j_string->data != NULL) - printf("type:string val:[%s]\n", (char *)(j->data.m_j_string->data)); - break; - case M_JSON_NUM: - printf("type:number val:[%f]\n", j->data.m_j_number); - break; - case M_JSON_TRUE: - printf("type:true val:[true]\n"); - break; - case M_JSON_FALSE: - printf("type:false val:[false]\n"); - break; - case M_JSON_NULL: - printf("type:NULL val:[NULL]\n"); - break; - default: - printf("type:none\n"); - break; - } -} - -static int mln_json_dump_hash_iterate_handler(void *key, void *val, void *data) -{ - int *space = (int *)data; - mln_json_obj_t *obj = (mln_json_obj_t *)val; - - if (obj == NULL) return 0; - - if (obj->key != NULL) mln_json_dump(obj->key, *space, "Object key:"); - if (obj->val != NULL) mln_json_dump(obj->val, *space, "Object value:"); - - return 0; -} - -static int mln_json_dump_rbtree_iterate_handler(mln_rbtree_node_t *node, void *udata) -{ - mln_json_t *j = (mln_json_t *)mln_rbtree_node_data_get(node); - int *space = (int *)udata; - - mln_json_dump(j, *space, "Array member:"); - - return 0; -} - -/* - * search - */ -mln_json_t *mln_json_value_search(mln_json_t *j, mln_string_t *key) -{ - if (j == NULL || key == NULL) return NULL; - - if (!M_JSON_IS_OBJECT(j)) return NULL; - - mln_hash_t *h = j->data.m_j_obj; - if (h == NULL) return NULL; - - mln_json_obj_t *obj = (mln_json_obj_t *)mln_hash_search(h, key); - - return obj->val; -} - -mln_json_t *mln_json_element_search(mln_json_t *j, mln_uauto_t index) -{ - if (j == NULL) return NULL; - - if (!M_JSON_IS_ARRAY(j)) return NULL; - - mln_rbtree_t *t = j->data.m_j_array; - if (t == NULL) return NULL; - - mln_json_t json; - mln_rbtree_node_t *rn; - json.index = index; - rn = mln_rbtree_search(t, &json); - if (mln_rbtree_null(rn, t)) return NULL; - - return (mln_json_t *)mln_rbtree_node_data_get(rn); -} - -mln_uauto_t mln_json_array_length(mln_json_t *j) -{ - if (j == NULL) return 0; - - if (!M_JSON_IS_ARRAY(j)) return 0; - - mln_rbtree_t *t = j->data.m_j_array; - if (t == NULL) return 0; - - return mln_rbtree_node_num(t); -} - -/* - * add & update - */ -int mln_json_obj_update(mln_json_t *j, mln_json_t *key, mln_json_t *val) -{ - if (j == NULL || key == NULL) return -1; - if (!M_JSON_IS_STRING(key)) return -1; - - int is_new = 0; - mln_json_obj_t *obj; - - if (M_JSON_IS_NONE(j)) { - is_new = 1; - M_JSON_SET_TYPE_OBJECT(j); - struct mln_hash_attr hattr; - hattr.pool = NULL; - hattr.pool_alloc = NULL; - hattr.pool_free = NULL; - hattr.hash = mln_json_hash_calc; - hattr.cmp = mln_json_hash_cmp; - hattr.free_key = NULL; - hattr.free_val = mln_json_obj_free; - hattr.len_base = M_JSON_HASH_LEN; - hattr.expandable = 1; - hattr.calc_prime = 0; - j->data.m_j_obj = mln_hash_new(&hattr); - if (j->data.m_j_obj == NULL) { - return -1; - } - } - - if (!M_JSON_IS_OBJECT(j)) return -1; - - obj = mln_hash_search(j->data.m_j_obj, key->data.m_j_string); - if (obj == NULL) { - obj = mln_json_obj_new(); - if (obj == NULL) { - if (is_new) { - M_JSON_SET_TYPE_NONE(j); - mln_hash_free(j->data.m_j_obj, M_HASH_F_VAL); - j->data.m_j_obj = NULL; - return -1; - } - } - if (mln_hash_insert(j->data.m_j_obj, key->data.m_j_string, obj) < 0) { - mln_json_obj_free(obj); - if (is_new) { - M_JSON_SET_TYPE_NONE(j); - mln_hash_free(j->data.m_j_obj, M_HASH_F_VAL); - j->data.m_j_obj = NULL; - return -1; - } - } - } - - if (obj->key != NULL) mln_json_free(obj->key); - if (obj->val != NULL) mln_json_free(obj->val); - obj->key = key; - obj->val = val; - - return 0; -} - -int mln_json_element_add(mln_json_t *j, mln_json_t *value) -{ - if (j == NULL || value == NULL) return -1; - - int is_new = 0; - mln_rbtree_node_t *rn; - if (M_JSON_IS_NONE(j) || (M_JSON_IS_ARRAY(j) && j->data.m_j_array == NULL)) { - is_new = 1; - struct mln_rbtree_attr rbattr; - rbattr.pool = NULL; - rbattr.pool_alloc = NULL; - rbattr.pool_free = NULL; - rbattr.cmp = mln_json_rbtree_cmp; - rbattr.data_free = mln_json_free; - j->data.m_j_array = mln_rbtree_new(&rbattr); - if (j->data.m_j_array == NULL) return -1; - M_JSON_SET_TYPE_ARRAY(j); - } - - if (!M_JSON_IS_ARRAY(j)) return -1; - - M_JSON_SET_INDEX(value, mln_rbtree_node_num(j->data.m_j_array)); - rn = mln_rbtree_node_new(j->data.m_j_array, value); - if (rn == NULL) { - if (is_new) { - M_JSON_SET_TYPE_NONE(j); - mln_rbtree_free(j->data.m_j_array); - j->data.m_j_array = NULL; - return -1; - } - } - mln_rbtree_insert(j->data.m_j_array, rn); - - return 0; -} - -int mln_json_element_update(mln_json_t *j, mln_json_t *value, mln_uauto_t index) -{ - if (j == NULL || value == NULL) return -1; - if (!M_JSON_IS_ARRAY(j)) return -1; - if (M_JSON_GET_DATA_ARRAY(j) == NULL) return -1; - - mln_json_t tmp, *elem; - mln_rbtree_node_t *rn; - mln_rbtree_t *t = j->data.m_j_array; - - tmp.index = index; - rn = mln_rbtree_search(t, &tmp); - if (mln_rbtree_null(rn, t)) { - M_JSON_SET_INDEX(value, index); - rn = mln_rbtree_node_new(t, value); - if (rn == NULL) return -1; - mln_rbtree_insert(t, rn); - } - - elem = (mln_json_t *)mln_rbtree_node_data_get(rn); - mln_json_free(elem); - M_JSON_SET_INDEX(value, index); - rn->data = value; - - return 0; -} - -/* - * remove - */ -void mln_json_reset(mln_json_t *j) -{ - if (j == NULL) return; - - switch (j->type) { - case M_JSON_OBJECT: - if (j->data.m_j_obj != NULL) { - mln_hash_free(j->data.m_j_obj, M_HASH_F_VAL); - } - break; - case M_JSON_ARRAY: - if (j->data.m_j_array != NULL) { - mln_rbtree_free(j->data.m_j_array); - } - break; - case M_JSON_STRING: - if (j->data.m_j_string != NULL) { - mln_string_free(j->data.m_j_string); - } - break; - default: - break; - } - - memset(j, 0, sizeof(mln_json_t)); -} - -mln_json_t *mln_json_obj_remove(mln_json_t *j, mln_string_t *key) -{ - if (j == NULL || key == NULL) return NULL; - if (!M_JSON_IS_OBJECT(j)) return NULL; - - mln_json_t *val; - mln_json_obj_t *obj; - mln_hash_t *h = j->data.m_j_obj; - if (h == NULL) return NULL; - - obj = (mln_json_obj_t *)mln_hash_search(h, key); - if (obj == NULL) return NULL; - mln_hash_remove(h, key, M_HASH_F_NONE); - val = obj->val; - obj->val = NULL; - mln_json_obj_free(obj); - - return val; -} - -mln_json_t *mln_json_element_remove(mln_json_t *j, mln_uauto_t index) -{ - if (j == NULL) return NULL; - if (!M_JSON_IS_ARRAY(j)) return NULL; - - mln_json_t *val, tmp; - mln_rbtree_node_t *rn; - mln_rbtree_t *t = j->data.m_j_array; - if (t == NULL) return NULL; - - tmp.index = index; - rn = mln_rbtree_search(t, &tmp); - if (mln_rbtree_null(rn, t)) return NULL; - - mln_rbtree_delete(t, rn); - val = (mln_json_t *)mln_rbtree_node_data_get(rn); - rn->data = NULL; - mln_rbtree_node_free(t, rn); - - return val; -} -