Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd3bfb49e9 | ||
|
|
af9b0b837e | ||
|
|
cd5ddd950b | ||
|
|
d68bea08f4 | ||
|
|
1445d668a5 |
@@ -4,7 +4,7 @@ include(GNUInstallDirs)
|
||||
cmake_minimum_required(VERSION 3.0.2)
|
||||
project(rjp)
|
||||
set(rjp_VERSION_MAJOR 0)
|
||||
set(rjp_VERSION_MINOR 2)
|
||||
set(rjp_VERSION_MINOR 4)
|
||||
set(INCLUDE_PATH ${CMAKE_SOURCE_DIR}/include)
|
||||
configure_file(
|
||||
"${INCLUDE_PATH}/config.h.in"
|
||||
|
||||
@@ -27,7 +27,7 @@ extern "C"{
|
||||
|
||||
//type of data
|
||||
typedef enum RJP_type{
|
||||
json_object,
|
||||
json_object = 0,
|
||||
json_string,
|
||||
json_integer,
|
||||
json_dfloat,
|
||||
@@ -89,11 +89,15 @@ RJP_value* rjp_parse(const char* str);
|
||||
|
||||
//deallocate a json handle
|
||||
void rjp_free_json(char* json);
|
||||
void rjp_free(RJP_value* root);
|
||||
void rjp_free_value(RJP_value* root);
|
||||
|
||||
//initialize an empty json handle (outputting to string would result in '{}')
|
||||
//initialize an empty json handle
|
||||
RJP_value* rjp_init_json(void);
|
||||
|
||||
void* rjp_alloc(size_t nbytes);
|
||||
void* rjp_calloc(size_t num, size_t nbytes);
|
||||
void rjp_free(void* dest);
|
||||
|
||||
//add a member to a json object
|
||||
RJP_value* rjp_add_member(RJP_value* dest, int alloc_key, char* key, size_t keylen, RJP_value value);
|
||||
//add an element to a json array
|
||||
@@ -132,6 +136,7 @@ size_t rjp_value_string_length(RJP_value* value);
|
||||
|
||||
//copy input string and add json escape sequences
|
||||
size_t rjp_escape_strcpy(char* dest, const char* src);
|
||||
|
||||
//length of string including escape sequences
|
||||
size_t rjp_escape_strlen(const char* str);
|
||||
|
||||
|
||||
@@ -9,5 +9,6 @@ void _rjp__add_member(RJP_object* j, char* str, size_t len);
|
||||
void _rjp__add_member_no_alloc(RJP_object* j, char* str, size_t len);
|
||||
void _rjp__add_element(RJP_array* j);
|
||||
size_t _rjp__object_strlen(RJP_value* root);
|
||||
size_t _rjp__value_strlen(RJP_value* root);
|
||||
|
||||
#endif
|
||||
|
||||
153
src/input.c
153
src/input.c
@@ -47,7 +47,8 @@ typedef enum json_search_target{
|
||||
json_key,
|
||||
json_colon,
|
||||
json_comma,
|
||||
json_value
|
||||
json_value,
|
||||
json_none
|
||||
}json_search_target;
|
||||
|
||||
//Determine if the character is valid whitespace
|
||||
@@ -58,10 +59,10 @@ static int _rjp__is_whitespace(char c){
|
||||
void _rjp__add_element(RJP_array* j){
|
||||
++j->num_elements;
|
||||
if(!j->elements){
|
||||
j->elements = calloc(1, sizeof(RJP_array_element));
|
||||
j->elements = rjp_calloc(1, sizeof(RJP_array_element));
|
||||
j->last = j->elements;
|
||||
}else{
|
||||
j->last->next = calloc(1, sizeof(RJP_array_element));
|
||||
j->last->next = rjp_calloc(1, sizeof(RJP_array_element));
|
||||
j->last = j->last->next;
|
||||
}
|
||||
}
|
||||
@@ -69,13 +70,13 @@ void _rjp__add_element(RJP_array* j){
|
||||
void _rjp__add_member(RJP_object* j, char* str, size_t len){
|
||||
++j->num_members;
|
||||
if(!j->members){
|
||||
j->members = calloc(1, sizeof(RJP_object_member));
|
||||
j->members = rjp_calloc(1, sizeof(RJP_object_member));
|
||||
j->last = j->members;
|
||||
}else{
|
||||
j->last->next = calloc(1, sizeof(RJP_object_member));
|
||||
j->last->next = rjp_calloc(1, sizeof(RJP_object_member));
|
||||
j->last = j->last->next;
|
||||
}
|
||||
j->last->name.value = malloc(len + 1);
|
||||
j->last->name.value = rjp_alloc(len + 1);
|
||||
strncpy(j->last->name.value, str, len);
|
||||
j->last->name.value[len] = 0;
|
||||
j->last->name.length = len;
|
||||
@@ -83,10 +84,10 @@ void _rjp__add_member(RJP_object* j, char* str, size_t len){
|
||||
void _rjp__add_member_no_alloc(RJP_object* j, char* str, size_t len){
|
||||
++j->num_members;
|
||||
if(!j->members){
|
||||
j->members = calloc(1, sizeof(RJP_object_member));
|
||||
j->members = rjp_calloc(1, sizeof(RJP_object_member));
|
||||
j->last = j->members;
|
||||
}else{
|
||||
j->last->next = calloc(1, sizeof(RJP_object_member));
|
||||
j->last->next = rjp_calloc(1, sizeof(RJP_object_member));
|
||||
j->last = j->last->next;
|
||||
}
|
||||
j->last->name.value = str;
|
||||
@@ -101,64 +102,54 @@ static RJP_value* _rjp__add_element_to_array(RJP_value* curr, RJP_state* state,
|
||||
return &tmp->array.last->value;
|
||||
}
|
||||
|
||||
//Assign object characteristics to previously allocated RJP_value
|
||||
static RJP_value* _rjp__add_object(RJP_value* curr, RJP_state* state){
|
||||
static RJP_value* _rjp__add_value(RJP_value* curr, RJP_value* new_val, RJP_state* state){
|
||||
if(!curr){
|
||||
curr = calloc(1, sizeof(RJP_value));
|
||||
curr->type = json_object;
|
||||
curr = rjp_calloc(1, sizeof(RJP_value));
|
||||
*curr = *new_val;
|
||||
return curr;
|
||||
}
|
||||
RJP_value new_object = {.type = json_object, .integer = 0, .parent = curr};
|
||||
if(curr->type == json_array){
|
||||
_rjp__add_element(&curr->array);
|
||||
curr->array.last->value = *new_val;
|
||||
return &curr->array.last->value;
|
||||
}
|
||||
if(state->in_array)
|
||||
return _rjp__add_element_to_array(curr, state, &new_object);
|
||||
curr->object.last->value = new_object;
|
||||
return _rjp__add_element_to_array(curr, state, new_val);
|
||||
curr->object.last->value = *new_val;
|
||||
return &curr->object.last->value;
|
||||
}
|
||||
//Assign object characteristics to previously allocated RJP_value
|
||||
static RJP_value* _rjp__add_object(RJP_value* curr, RJP_state* state){
|
||||
RJP_value new_object = {.type = json_object, .integer = 0, .parent = curr};
|
||||
return _rjp__add_value(curr, &new_object, state);
|
||||
}
|
||||
//Assign array characteristics to previously allocated RJP_value
|
||||
static RJP_value* _rjp__add_array(RJP_value* curr, RJP_state* state){
|
||||
RJP_value new_array = {.type = json_array, .array = {.num_elements = 0, .elements = NULL}, .parent = curr};
|
||||
if(state->in_array)
|
||||
return _rjp__add_element_to_array(curr, state, &new_array);
|
||||
curr->object.last->value = new_array;
|
||||
return &curr->object.last->value;
|
||||
return _rjp__add_value(curr, &new_array, state);
|
||||
}
|
||||
//Assign string characteristics to previously allocated RJP_value with no string allocation
|
||||
static RJP_value* _rjp__add_string_no_alloc(RJP_value* curr, char* str, int len, RJP_state* state){
|
||||
RJP_value new_string = {.type = json_string, .string = {.value = str, .length = len}, .parent = curr};
|
||||
if(state->in_array)
|
||||
return _rjp__add_element_to_array(curr, state, &new_string);
|
||||
curr->object.last->value = new_string;
|
||||
return &curr->object.last->value;
|
||||
return _rjp__add_value(curr, &new_string, state);
|
||||
}
|
||||
//Assign double characteristics to previously allocated RJP_value
|
||||
static RJP_value* _rjp__add_dfloat(RJP_value* curr, double value, RJP_state* state){
|
||||
RJP_value new_double = {.type = json_dfloat, .dfloat = value, .parent = curr};
|
||||
if(state->in_array)
|
||||
return _rjp__add_element_to_array(curr, state, &new_double);
|
||||
curr->object.last->value = new_double;
|
||||
return &curr->object.last->value;
|
||||
return _rjp__add_value(curr, &new_double, state);
|
||||
}
|
||||
//Assign integer characteristics to previously allocated RJP_value
|
||||
static RJP_value* _rjp__add_integer(RJP_value* curr, long value, RJP_state* state){
|
||||
RJP_value new_integer = {.type = json_integer, .integer = value, .parent = curr};
|
||||
if(state->in_array)
|
||||
return _rjp__add_element_to_array(curr, state, &new_integer);
|
||||
curr->object.last->value = new_integer;
|
||||
return &curr->object.last->value;
|
||||
return _rjp__add_value(curr, &new_integer, state);
|
||||
}
|
||||
static RJP_value* _rjp__add_boolean(RJP_value* curr, int value, RJP_state* state){
|
||||
RJP_value new_boolean = {.type = json_boolean, .boolean = value, .parent = curr};
|
||||
if(state->in_array)
|
||||
return _rjp__add_element_to_array(curr, state, &new_boolean);
|
||||
curr->object.last->value = new_boolean;
|
||||
return &curr->object.last->value;
|
||||
return _rjp__add_value(curr, &new_boolean, state);
|
||||
}
|
||||
static RJP_value* _rjp__add_null(RJP_value* curr, RJP_state* state){
|
||||
RJP_value new_null = {.type = json_null, .integer = 0, .parent = curr};
|
||||
if(state->in_array)
|
||||
return _rjp__add_element_to_array(curr, state, &new_null);
|
||||
curr->object.last->value = new_null;
|
||||
return &curr->object.last->value;
|
||||
return _rjp__add_value(curr, &new_null, state);
|
||||
}
|
||||
|
||||
static void _rjp__free_object_recurse(RJP_value* root);
|
||||
@@ -193,14 +184,19 @@ static void _rjp__free_object_recurse(RJP_value* root){
|
||||
free(m);
|
||||
}
|
||||
}
|
||||
void rjp_free_json(char* json){
|
||||
void rjp_free_value_json(char* json){
|
||||
free(json);
|
||||
}
|
||||
//Same as recurse but also frees root node
|
||||
void rjp_free(RJP_value* root){
|
||||
void rjp_free_value(RJP_value* root){
|
||||
if(!root)
|
||||
return;
|
||||
_rjp__free_object_recurse(root);
|
||||
|
||||
if((root->type) == json_object)
|
||||
_rjp__free_object_recurse(root);
|
||||
else if((root->type) == json_array)
|
||||
_rjp__free_array(root);
|
||||
|
||||
free(root);
|
||||
}
|
||||
|
||||
@@ -211,7 +207,7 @@ MAYBE_UNUSED static int _rjp__is_array_empty(RJP_value* curr){
|
||||
}
|
||||
|
||||
#define syntax_error(msg, row, column)\
|
||||
do{DIAG_PRINT(stderr, "Syntax error! %s (%i:%i)\n", msg, row, column);rjp_free(root);return NULL;}while(0)
|
||||
do{DIAG_PRINT(stderr, "Syntax error! %s (%i:%i)\n", msg, row, column);rjp_free_value(root);return NULL;}while(0)
|
||||
|
||||
#define MAX_DEPTH 16
|
||||
RJP_value* rjp_parse(const char* str){
|
||||
@@ -331,14 +327,21 @@ RJP_value* rjp_parse(const char* str){
|
||||
top->search_target = json_key;
|
||||
}
|
||||
}
|
||||
//something outside of any object
|
||||
/* //something outside of any object
|
||||
else if(!curr){
|
||||
syntax_error("Unexpected character outside of object definition!", row, column);
|
||||
}
|
||||
//arrays
|
||||
*/ //arrays
|
||||
else if(c == '['){
|
||||
_rjp__add_array(curr, top);
|
||||
++top->in_array;
|
||||
if(!root){
|
||||
root = _rjp__add_array(NULL, top);
|
||||
curr = root;
|
||||
++top->in_array;
|
||||
|
||||
}else{
|
||||
_rjp__add_array(curr, top);
|
||||
++top->in_array;
|
||||
}
|
||||
}
|
||||
else if(c == ']' && top->in_array){ //empty array
|
||||
--top->in_array;
|
||||
@@ -351,7 +354,7 @@ RJP_value* rjp_parse(const char* str){
|
||||
char* new_string = _rjp__parse_string(root, str, &vallen, &row, &column);
|
||||
if(!new_string){
|
||||
if(vallen == 0){
|
||||
new_string = calloc(1, 1);
|
||||
new_string = rjp_calloc(1, 1);
|
||||
}else{
|
||||
return NULL;
|
||||
}
|
||||
@@ -362,6 +365,10 @@ RJP_value* rjp_parse(const char* str){
|
||||
}
|
||||
//numbers
|
||||
else if((c >= '0' && c <= '9') || c == '-'){
|
||||
if(!curr)
|
||||
top->search_target = json_none;
|
||||
else
|
||||
top->search_target = json_comma;
|
||||
int numlen;
|
||||
int floating = 0; //is an int or a double
|
||||
for(numlen = 1;*(str+numlen) >= '0' && *(str+numlen) <= '9';++numlen);
|
||||
@@ -373,39 +380,63 @@ RJP_value* rjp_parse(const char* str){
|
||||
}
|
||||
floating = 1;
|
||||
}
|
||||
if(*(str+numlen) == '\0'){ //hit EOF early
|
||||
if(*(str+numlen) == '\0' && curr){ //hit EOF early
|
||||
syntax_error("Unexpected EOF before end of object!", row, column);
|
||||
}
|
||||
if(c == '-' && numlen == 1){ //only have a '-' with no numbers
|
||||
syntax_error("Missing numerals ofter '-' sign!", row, column);
|
||||
}
|
||||
if(floating){
|
||||
_rjp__add_dfloat(curr, strtod(str, NULL), top);
|
||||
if(!root){
|
||||
root = curr = _rjp__add_dfloat(NULL, strtod(str, NULL), top);
|
||||
}else{
|
||||
_rjp__add_dfloat(curr, strtod(str, NULL), top);
|
||||
}
|
||||
}else{
|
||||
_rjp__add_integer(curr, strtol(str, NULL, 10), top);
|
||||
if(!root){
|
||||
root = curr = _rjp__add_integer(NULL, strtol(str, NULL, 10), top);
|
||||
}else{
|
||||
_rjp__add_integer(curr, strtol(str, NULL, 10), top);
|
||||
}
|
||||
}
|
||||
str += (numlen-1);
|
||||
column += numlen;
|
||||
top->search_target = json_comma;
|
||||
}
|
||||
//booleans and null
|
||||
else if(!strncmp(str, "true", 4)){
|
||||
_rjp__add_boolean(curr, 1, top);
|
||||
str += 3;
|
||||
top->search_target = json_comma;
|
||||
if(!curr){
|
||||
top->search_target = json_none;
|
||||
root = curr = _rjp__add_boolean(curr, 1, top);
|
||||
}else{
|
||||
top->search_target = json_comma;
|
||||
_rjp__add_boolean(curr, 1, top);
|
||||
}
|
||||
str += 3;column += 3;
|
||||
}else if(!strncmp(str, "false", 5)){
|
||||
_rjp__add_boolean(curr, 0, top);
|
||||
str += 4;
|
||||
top->search_target = json_comma;
|
||||
if(!curr){
|
||||
top->search_target = json_none;
|
||||
root = curr = _rjp__add_boolean(curr, 0, top);
|
||||
}else{
|
||||
top->search_target = json_comma;
|
||||
_rjp__add_boolean(curr, 0, top);
|
||||
}
|
||||
str += 4;column += 4;
|
||||
}else if(!strncmp(str, "null", 4)){
|
||||
_rjp__add_null(curr, top);
|
||||
str += 3;
|
||||
top->search_target = json_comma;
|
||||
if(!curr){
|
||||
top->search_target = json_none;
|
||||
root = curr = _rjp__add_null(curr, top);
|
||||
}else{
|
||||
top->search_target = json_comma;
|
||||
_rjp__add_null(curr, top);
|
||||
}
|
||||
str += 3;column += 3;
|
||||
}
|
||||
//unrecognized character
|
||||
else if(!_rjp__is_whitespace(c)){
|
||||
syntax_error("Unexpected character!", row, column);
|
||||
}
|
||||
}else if(top->search_target == json_none && !_rjp__is_whitespace(c)){
|
||||
syntax_error("Unexpected character!", row, column);
|
||||
}
|
||||
}
|
||||
return root;
|
||||
|
||||
41
src/output.c
41
src/output.c
@@ -6,12 +6,20 @@
|
||||
#include <stdio.h> //sprintf
|
||||
|
||||
RJP_value* rjp_init_json(void){
|
||||
RJP_value* ret = calloc(1, sizeof(RJP_value));
|
||||
ret->type = json_object;
|
||||
RJP_value* ret = rjp_calloc(1, sizeof(RJP_value));
|
||||
return ret;
|
||||
}
|
||||
void* rjp_alloc(size_t nbytes){
|
||||
return malloc(nbytes);
|
||||
}
|
||||
void* rjp_calloc(size_t num, size_t nbytes){
|
||||
return calloc(num, nbytes);
|
||||
}
|
||||
void rjp_free(void* data){
|
||||
free(data);
|
||||
}
|
||||
RJP_value* rjp_add_member(RJP_value* dest, int alloc_key, char* key, size_t keylen, RJP_value value){
|
||||
if(!keylen && alloc_key)
|
||||
if(!keylen)
|
||||
keylen = strlen(key);
|
||||
if(alloc_key)
|
||||
_rjp__add_member(&dest->object, key, keylen);
|
||||
@@ -114,14 +122,10 @@ static size_t _rjp__write_value(char* dest, RJP_value* val){
|
||||
ret = sprintf(dest, "\"%s\"", val->string.value);
|
||||
break;
|
||||
case json_array:
|
||||
ret = sprintf(dest, "[");
|
||||
ret += rjp_dump_array(val, dest+ret);
|
||||
ret += sprintf(dest+ret, "]");
|
||||
ret = rjp_dump_array(val, dest);
|
||||
break;
|
||||
case json_object:
|
||||
ret = sprintf(dest, "{");
|
||||
ret += rjp_dump_object(val, dest+ret);
|
||||
ret += sprintf(dest+ret, "}");
|
||||
ret = rjp_dump_object(val, dest);
|
||||
break;
|
||||
default:
|
||||
ret = 0;
|
||||
@@ -133,7 +137,8 @@ static size_t _rjp__write_value(char* dest, RJP_value* val){
|
||||
size_t rjp_dump_array(RJP_value* arr, char* dest){
|
||||
RJP_array* array = &arr->array;
|
||||
RJP_array_element* element_list = array->elements;
|
||||
size_t pos = 0;
|
||||
size_t pos = 1;
|
||||
sprintf(dest, "[");
|
||||
for(;element_list;element_list = element_list->next){
|
||||
pos += _rjp__write_value(dest+pos, &element_list->value);
|
||||
|
||||
@@ -142,13 +147,16 @@ size_t rjp_dump_array(RJP_value* arr, char* dest){
|
||||
else
|
||||
break;
|
||||
}
|
||||
pos += sprintf(dest+pos, "]");
|
||||
return pos;
|
||||
}
|
||||
|
||||
size_t rjp_dump_object(RJP_value* root, char* dest){
|
||||
RJP_object* root_obj = &root->object;
|
||||
RJP_object_member* member_list = root_obj->members;
|
||||
size_t pos = 0;
|
||||
size_t pos = 1;
|
||||
sprintf(dest, "{");
|
||||
|
||||
for(;member_list;member_list = member_list->next){
|
||||
pos += sprintf(dest+pos, "\"%s\":", member_list->name.value);
|
||||
pos += _rjp__write_value(dest+pos, &member_list->value);
|
||||
@@ -158,22 +166,21 @@ size_t rjp_dump_object(RJP_value* root, char* dest){
|
||||
else
|
||||
break;
|
||||
}
|
||||
pos += sprintf(dest+pos, "}");
|
||||
return pos;
|
||||
}
|
||||
|
||||
char* rjp_to_json(RJP_value* root){
|
||||
if(!root)
|
||||
return NULL;
|
||||
size_t len = _rjp__object_strlen(root);
|
||||
size_t len = _rjp__value_strlen(root);
|
||||
if(!len)
|
||||
return NULL;
|
||||
char* tmp = malloc(len + 1);
|
||||
char* tmp = rjp_alloc(len + 1);
|
||||
tmp[len] = 0;
|
||||
size_t pos = 1;
|
||||
size_t pos = 0;
|
||||
|
||||
sprintf(tmp, "{");
|
||||
pos += rjp_dump_object(root, tmp+pos);
|
||||
sprintf(tmp+pos, "}");
|
||||
_rjp__write_value(tmp, root);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ char* _rjp__parse_string(RJP_value* root, const char* str, int* len, int* row, i
|
||||
}else if(*(str+*len) == '\0'){
|
||||
*len = 1;
|
||||
fprintf(stderr, "Syntax error! %s (%i:%i)\n", "Unexpected EOF in string!", *row, *column);
|
||||
rjp_free(root);
|
||||
rjp_free_value(root);
|
||||
return NULL;
|
||||
}else if(*(str+*len) == '\n'){
|
||||
++(*row);
|
||||
@@ -25,7 +25,7 @@ char* _rjp__parse_string(RJP_value* root, const char* str, int* len, int* row, i
|
||||
if(*len == 0){
|
||||
return NULL;
|
||||
}
|
||||
new_string = malloc(*len + 1);
|
||||
new_string = rjp_alloc(*len + 1);
|
||||
new_string[*len] = 0;
|
||||
for(int i = 0;*str != '"';++i,++str){
|
||||
if(*str == '\\'){
|
||||
@@ -100,6 +100,7 @@ size_t rjp_escape_strcpy(char* dest, const char* src){
|
||||
break;
|
||||
};
|
||||
}
|
||||
dest[j] = 0;
|
||||
return j;
|
||||
}
|
||||
size_t rjp_escape_strlen(const char* str){
|
||||
@@ -165,32 +166,7 @@ size_t _rjp__object_strlen(RJP_value* root){
|
||||
if(member_list->name.length == 0 || member_list->name.value[0] == 0)
|
||||
return 0;
|
||||
count += member_list->name.length + 3; //"":
|
||||
switch(member_list->value.type){
|
||||
case json_integer:
|
||||
count += snprintf(NULL, 0, "%li", member_list->value.integer);
|
||||
break;
|
||||
case json_dfloat:
|
||||
count += snprintf(NULL, 0, "%lf", member_list->value.dfloat);
|
||||
break;
|
||||
case json_boolean:
|
||||
count += member_list->value.boolean ? 4 : 5; //true, false
|
||||
break;
|
||||
case json_null:
|
||||
count += 4; //null
|
||||
break;
|
||||
case json_string:
|
||||
count += member_list->value.string.length;
|
||||
break;
|
||||
case json_array:
|
||||
count += _rjp__array_strlen(&member_list->value);
|
||||
break;
|
||||
case json_object:;
|
||||
size_t new_count = _rjp__object_strlen(&member_list->value);
|
||||
if(!new_count)
|
||||
return 0;
|
||||
count += new_count;
|
||||
break;
|
||||
};
|
||||
count += _rjp__value_strlen(&member_list->value);
|
||||
if(member_list->next)
|
||||
++count; //,
|
||||
else
|
||||
@@ -199,3 +175,23 @@ size_t _rjp__object_strlen(RJP_value* root){
|
||||
return count;
|
||||
}
|
||||
|
||||
size_t _rjp__value_strlen(RJP_value* root){
|
||||
switch(root->type){
|
||||
case json_integer:
|
||||
return snprintf(NULL, 0, "%li", root->integer);
|
||||
case json_dfloat:
|
||||
return snprintf(NULL, 0, "%lf", root->dfloat);
|
||||
case json_boolean:
|
||||
return root->boolean ? 4 : 5; //true, false
|
||||
case json_null:
|
||||
return 4;
|
||||
case json_string:
|
||||
return root->string.length;
|
||||
case json_array:
|
||||
return _rjp__array_strlen(root);
|
||||
case json_object:
|
||||
return _rjp__object_strlen(root);
|
||||
default:
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user