Rudimentary output to json

This commit is contained in:
rexy712 2018-11-25 16:19:14 -08:00
parent cfab198821
commit 9eaa734fbb
2 changed files with 339 additions and 58 deletions

View File

@ -64,7 +64,6 @@ struct JSON_array{
//hold any json data type //hold any json data type
struct JSON_value{ struct JSON_value{
enum JSON_type type;
union{ union{
long integer; long integer;
double dfloat; double dfloat;
@ -74,6 +73,7 @@ struct JSON_value{
struct JSON_array array; struct JSON_array array;
}; };
struct JSON_value* parent; struct JSON_value* parent;
enum JSON_type type;
}; };
struct JSON_array_element{ struct JSON_array_element{
@ -105,20 +105,10 @@ enum JSON_type rjp_get_value_type(struct JSON_value* j);
//initialize an empty json handle (outputting to string would result in '{}') //initialize an empty json handle (outputting to string would result in '{}')
struct JSON_value* rjp_init_json(void); struct JSON_value* rjp_init_json(void);
//initialize an empty json object
struct JSON_object* rjp_init_object(void);
//initialize an empty json array
struct JSON_array* rjp_init_array(void);
//add a member to a json object //add a member to a json object
struct JSON_value* rjp_add_member(struct JSON_object* dest, const char* key, size_t keylen, struct JSON_value* value); struct JSON_value* rjp_add_member(struct JSON_object* dest, int alloc_key, char* key, size_t keylen, struct JSON_value value);
//add an element to a json array //add an element to a json array
struct JSON_value* rjp_add_element(struct JSON_array* dest, struct JSON_value* value); struct JSON_value* rjp_add_element(struct JSON_array* dest, struct JSON_value value);
struct JSON_value* rjp_init_integer(long i);
struct JSON_value* rjp_init_dfloat(double d);
struct JSON_value* rjp_init_boolean(char b);
struct JSON_value* rjp_init_string(const char* str, size_t len);
/*struct JSON_value* root = rjp_init_json(); /*struct JSON_value* root = rjp_init_json();
rjp_add_member(root, "intel_backlight", 15, rjp_init_integer(100)); rjp_add_member(root, "intel_backlight", 15, rjp_init_integer(100));

381
src/rjp.c
View File

@ -47,48 +47,51 @@ enum json_search_target{
static int is_whitespace(char c){ static int is_whitespace(char c){
return c == ' ' || c == '\n' || c == '\r' || c == '\t'; return c == ' ' || c == '\n' || c == '\r' || c == '\t';
} }
//allocate a member of the object as a linked list member and assign a name
MAYBE_UNUSED static void add_member(struct JSON_value* j, const char* str, size_t len){
++j->object.num_members;
struct JSON_object_member* prev = j->object.members;
j->object.members = calloc(1, sizeof(struct JSON_object_member));
j->object.members->name.value = malloc(len + 1);
j->object.members->name.length = len;
strncpy(j->object.members->name.value, str, len);
j->object.members->name.value[len] = 0;
j->object.members->next = prev;
}
//add an element to an array //add an element to an array
static void add_element(struct JSON_value* j){ static void add_element(struct JSON_array* j){
++j->array.num_elements; ++j->num_elements;
if(!j->array.elements){ if(!j->elements){
j->array.elements = calloc(1, sizeof(struct JSON_array_element)); j->elements = calloc(1, sizeof(struct JSON_array_element));
j->array.last = j->array.elements; j->last = j->elements;
}else{ }else{
j->array.last->next = calloc(1, sizeof(struct JSON_array_element)); j->last->next = calloc(1, sizeof(struct JSON_array_element));
j->array.last = j->array.last->next; j->last = j->last->next;
} }
} }
//create member of the object as a linked list member and assign a name with no name allocation //create member of the object as a linked list member and assign a name with no name allocation
static void add_member_no_alloc(struct JSON_value* j, char* str, size_t len){ static void add_member(struct JSON_object* j, char* str, size_t len){
++j->object.num_members; ++j->num_members;
if(!j->object.members){ if(!j->members){
j->object.members = calloc(1, sizeof(struct JSON_object_member)); j->members = calloc(1, sizeof(struct JSON_object_member));
j->object.last = j->object.members; j->last = j->members;
}else{ }else{
j->object.last->next = calloc(1, sizeof(struct JSON_object_member)); j->last->next = calloc(1, sizeof(struct JSON_object_member));
j->object.last = j->object.last->next; j->last = j->last->next;
} }
j->object.last->name.value = str; j->last->name.value = malloc(len + 1);
j->object.last->name.length = len; strncpy(j->last->name.value, str, len);
j->last->name.value[len] = 0;
j->last->name.length = len;
}
static void add_member_no_alloc(struct JSON_object* j, char* str, size_t len){
++j->num_members;
if(!j->members){
j->members = calloc(1, sizeof(struct JSON_object_member));
j->last = j->members;
}else{
j->last->next = calloc(1, sizeof(struct JSON_object_member));
j->last = j->last->next;
}
j->last->name.value = str;
j->last->name.length = len;
} }
static struct JSON_value* add_element_to_array(struct JSON_value* curr, struct JSON_state* state, struct JSON_value* element){ static struct JSON_value* add_element_to_array(struct JSON_value* curr, struct JSON_state* state, struct JSON_value* element){
struct JSON_value* tmp = &curr->object.members->value; struct JSON_value* tmp = &curr->object.members->value;
for(int i = state->in_array-1;i > 0;--i, tmp = &tmp->array.last->value); for(int i = state->in_array-1;i > 0;--i, tmp = &tmp->array.last->value);
add_element(tmp); add_element(&tmp->array);
tmp->array.elements->value = *element; tmp->array.last->value = *element;
return &tmp->array.elements->value; return &tmp->array.last->value;
} }
//Assign object characteristics to previously allocated JSON_value //Assign object characteristics to previously allocated JSON_value
@ -101,54 +104,54 @@ static struct JSON_value* add_object(struct JSON_value* curr, struct JSON_state*
struct JSON_value new_object = {.type = json_object, .integer = 0, .parent = curr}; struct JSON_value new_object = {.type = json_object, .integer = 0, .parent = curr};
if(state->in_array) if(state->in_array)
return add_element_to_array(curr, state, &new_object); return add_element_to_array(curr, state, &new_object);
curr->object.members->value = new_object; curr->object.last->value = new_object;
return &curr->object.members->value; return &curr->object.last->value;
} }
//Assign array characteristics to previously allocated JSON_value //Assign array characteristics to previously allocated JSON_value
static struct JSON_value* add_array(struct JSON_value* curr, struct JSON_state* state){ static struct JSON_value* add_array(struct JSON_value* curr, struct JSON_state* state){
struct JSON_value new_array = {.type = json_array, .array = {.num_elements = 0, .elements = NULL}, .parent = curr}; struct JSON_value new_array = {.type = json_array, .array = {.num_elements = 0, .elements = NULL}, .parent = curr};
if(state->in_array) if(state->in_array)
return add_element_to_array(curr, state, &new_array); return add_element_to_array(curr, state, &new_array);
curr->object.members->value = new_array; curr->object.last->value = new_array;
return &curr->object.members->value; return &curr->object.last->value;
} }
//Assign string characteristics to previously allocated JSON_value with no string allocation //Assign string characteristics to previously allocated JSON_value with no string allocation
static struct JSON_value* add_string_no_alloc(struct JSON_value* curr, char* str, int len, struct JSON_state* state){ static struct JSON_value* add_string_no_alloc(struct JSON_value* curr, char* str, int len, struct JSON_state* state){
struct JSON_value new_string = {.type = json_string, .string = {.value = str, .length = len}, .parent = curr}; struct JSON_value new_string = {.type = json_string, .string = {.value = str, .length = len}, .parent = curr};
if(state->in_array) if(state->in_array)
return add_element_to_array(curr, state, &new_string); return add_element_to_array(curr, state, &new_string);
curr->object.members->value = new_string; curr->object.last->value = new_string;
return &curr->object.members->value; return &curr->object.last->value;
} }
//Assign double characteristics to previously allocated JSON_value //Assign double characteristics to previously allocated JSON_value
static struct JSON_value* add_double(struct JSON_value* curr, double value, struct JSON_state* state){ static struct JSON_value* add_double(struct JSON_value* curr, double value, struct JSON_state* state){
struct JSON_value new_double = {.type = json_dfloat, .dfloat = value, .parent = curr}; struct JSON_value new_double = {.type = json_dfloat, .dfloat = value, .parent = curr};
if(state->in_array) if(state->in_array)
return add_element_to_array(curr, state, &new_double); return add_element_to_array(curr, state, &new_double);
curr->object.members->value = new_double; curr->object.last->value = new_double;
return &curr->object.members->value; return &curr->object.last->value;
} }
//Assign integer characteristics to previously allocated JSON_value //Assign integer characteristics to previously allocated JSON_value
static struct JSON_value* add_integer(struct JSON_value* curr, long value, struct JSON_state* state){ static struct JSON_value* add_integer(struct JSON_value* curr, long value, struct JSON_state* state){
struct JSON_value new_integer = {.type = json_integer, .integer = value, .parent = curr}; struct JSON_value new_integer = {.type = json_integer, .integer = value, .parent = curr};
if(state->in_array) if(state->in_array)
return add_element_to_array(curr, state, &new_integer); return add_element_to_array(curr, state, &new_integer);
curr->object.members->value = new_integer; curr->object.last->value = new_integer;
return &curr->object.members->value; return &curr->object.last->value;
} }
static struct JSON_value* add_boolean(struct JSON_value* curr, int value, struct JSON_state* state){ static struct JSON_value* add_boolean(struct JSON_value* curr, int value, struct JSON_state* state){
struct JSON_value new_boolean = {.type = json_boolean, .boolean = value, .parent = curr}; struct JSON_value new_boolean = {.type = json_boolean, .boolean = value, .parent = curr};
if(state->in_array) if(state->in_array)
return add_element_to_array(curr, state, &new_boolean); return add_element_to_array(curr, state, &new_boolean);
curr->object.members->value = new_boolean; curr->object.last->value = new_boolean;
return &curr->object.members->value; return &curr->object.last->value;
} }
static struct JSON_value* add_null(struct JSON_value* curr, struct JSON_state* state){ static struct JSON_value* add_null(struct JSON_value* curr, struct JSON_state* state){
struct JSON_value new_null = {.type = json_null, .integer = 0, .parent = curr}; struct JSON_value new_null = {.type = json_null, .integer = 0, .parent = curr};
if(state->in_array) if(state->in_array)
return add_element_to_array(curr, state, &new_null); return add_element_to_array(curr, state, &new_null);
curr->object.members->value = new_null; curr->object.last->value = new_null;
return &curr->object.members->value; return &curr->object.last->value;
} }
static void free_json_recurse(struct JSON_value* root); static void free_json_recurse(struct JSON_value* root);
@ -316,7 +319,7 @@ struct JSON_value* rjp_parse(const char* str){
syntax_error("Cannot have empty key name!", row, column); syntax_error("Cannot have empty key name!", row, column);
return NULL; return NULL;
} }
add_member_no_alloc(curr, new_string, keylen); add_member(&curr->object, new_string, keylen);
str += keylen; str += keylen;
top->search_target = json_colon; top->search_target = json_colon;
//end of this object (object is empty) //end of this object (object is empty)
@ -475,3 +478,291 @@ enum JSON_type rjp_get_member_type(struct JSON_object_member* j){
enum JSON_type rjp_get_value_type(struct JSON_value* j){ enum JSON_type rjp_get_value_type(struct JSON_value* j){
return j->type; return j->type;
} }
struct JSON_value* rjp_init_json(void){
return add_object(NULL, NULL);
}
struct JSON_value* rjp_add_member(struct JSON_object* dest, int alloc_key, char* key, size_t keylen, struct JSON_value value){
if(!keylen && alloc_key)
keylen = strlen(key);
if(alloc_key)
add_member(dest, key, keylen);
else
add_member_no_alloc(dest, key, keylen);
dest->last->value = value;
dest->last->value.parent = (struct JSON_value*)dest;
return &dest->last->value;
}
struct JSON_value* rjp_add_element(struct JSON_array* dest, struct JSON_value value){
add_element(dest);
dest->last->value = value;
dest->last->value.parent = (struct JSON_value*)dest;
return &dest->last->value;
}
struct JSON_value rjp_integer(long i){
return (struct JSON_value){.integer = i, .type = json_integer};
}
struct JSON_value rjp_boolean(char b){
return (struct JSON_value){.boolean = b, .type = json_boolean};
}
struct JSON_value rjp_double(double d){
return (struct JSON_value){.dfloat = d, .type = json_dfloat};
}
struct JSON_value rjp_string(char* c, size_t len){
return (struct JSON_value){.string = {.value = c, .length = len}, .type = json_string};
}
struct JSON_value rjp_null(void){
return (struct JSON_value){.integer = 0, .type = json_null};
}
struct JSON_value rjp_object(void){
return (struct JSON_value){.object = {0}, .type = json_object};
}
struct JSON_value rjp_array(void){
return (struct JSON_value){.array = {0}, .type = json_array};
}
size_t escape_strcpy(char* dest, const char* src){
size_t j = 0;
for(size_t i = 0;src[i];++i){
switch(src[i]){
case '"':
dest[j++] = '\\';
dest[j++] = '"';
break;
case '\n':
dest[j++] = '\\';
dest[j++] = 'n';
break;
case '\r':
dest[j++] = '\\';
dest[j++] = 'r';
break;
case '\b':
dest[j++] = '\\';
dest[j++] = 'b';
break;
case '\\':
dest[j++] = '\\';
dest[j++] = '\\';
break;
case '\t':
dest[j++] = '\\';
dest[j++] = 't';
break;
case '\f':
dest[j++] = '\\';
dest[j++] = 'f';
break;
default:
dest[j++] = src[i];
break;
};
}
return j;
}
size_t escape_strlen(const char* str){
size_t count = 0;
for(size_t i = 0;str[i];++i){
switch(str[i]){
case '"':
case '\n':
case '\r':
case '\b':
case '\\':
case '\t':
case '\f':
++count;
//fallthrough
default:
++count;
};
}
return count;
}
size_t dump_json(struct JSON_value* root, char* dest);
size_t dump_array(struct JSON_value* arr, char* dest){
struct JSON_array* array = &arr->array;
struct JSON_array_element* element_list = array->elements;
size_t pos = 0;
for(;element_list;element_list = element_list->next){
switch(element_list->value.type){
case json_integer:
pos += sprintf(dest+pos, "%li", element_list->value.integer);
break;
case json_dfloat:
pos += sprintf(dest+pos, "%lf", element_list->value.dfloat);
break;
case json_boolean:
pos += sprintf(dest+pos, element_list->value.boolean ? "true" : "false");
break;
case json_null:
pos +=sprintf(dest+pos, "null");
break;
case json_string:
//TODO escape characters
pos += sprintf(dest+pos, "\"");
pos += escape_strcpy(dest+pos, element_list->value.string.value);
pos += sprintf(dest+pos, "\"");
break;
case json_array:
pos += sprintf(dest+pos, "[");
pos += dump_array(&element_list->value, dest+pos);
pos += sprintf(dest+pos, "]");
break;
case json_object:
pos += sprintf(dest+pos, "{");
pos += dump_json(&element_list->value, dest+pos);
pos += sprintf(dest+pos, "}");
break;
};
if(element_list->next)
pos += sprintf(dest+pos, ",");
else
break;
}
return pos;
}
size_t dump_json(struct JSON_value* root, char* dest){
struct JSON_object* root_obj = &root->object;
struct JSON_object_member* member_list = root_obj->members;
size_t pos = 0;
for(;member_list;member_list = member_list->next){
pos += sprintf(dest+pos, "\"");
pos += escape_strcpy(dest+pos, member_list->name.value);
pos += sprintf(dest+pos, "\":");
switch(member_list->value.type){
case json_integer:
pos += sprintf(dest+pos, "%li", member_list->value.integer);
break;
case json_dfloat:
pos += sprintf(dest+pos, "%lf", member_list->value.dfloat);
break;
case json_boolean:
pos += sprintf(dest+pos, member_list->value.boolean ? "true" : "false");
break;
case json_null:
pos += sprintf(dest+pos, "null");
break;
case json_string:;
pos += sprintf(dest+pos, "\"");
pos += escape_strcpy(dest+pos, member_list->value.string.value);
pos += sprintf(dest+pos, "\"");
break;
case json_array:
pos += sprintf(dest+pos, "[");
pos += dump_array(&member_list->value, dest+pos);
pos += sprintf(dest+pos, "]");
break;
case json_object:
pos += sprintf(dest+pos, "{");
pos += dump_json(&member_list->value, dest+pos);
pos += sprintf(dest+pos, "}");
break;
};
if(member_list->next)
pos += sprintf(dest+pos, ",");
else
break;
}
return pos;
}
size_t count_json(struct JSON_value* root);
size_t count_array(struct JSON_value* arr){
size_t count = 2; //[]
struct JSON_array* array = &arr->array;
struct JSON_array_element* element_list = array->elements;
for(;element_list;element_list = element_list->next){
switch(element_list->value.type){
case json_integer:
count += snprintf(NULL, 0, "%li", element_list->value.integer);
break;
case json_dfloat:
count += snprintf(NULL, 0, "%lf", element_list->value.dfloat);
break;
case json_boolean:
count += element_list->value.boolean ? 4 : 5;
break;
case json_null:
count += 4;
break;
case json_string:
count += escape_strlen(element_list->value.string.value) + 2;
break;
case json_array:
count += count_array(&element_list->value);
break;
case json_object:
count += count_json(&element_list->value);
break;
};
if(element_list->next)
++count;
else
break;
}
return count;
}
size_t count_json(struct JSON_value* root){
size_t count = 2; //{}
struct JSON_object* root_obj = &root->object;
struct JSON_object_member* member_list = root_obj->members;
for(;member_list;member_list = member_list->next){
count += escape_strlen(member_list->name.value) + 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 += escape_strlen(member_list->value.string.value) + 2;
break;
case json_array:
count += count_array(&member_list->value);
break;
case json_object:
count += count_json(&member_list->value);
break;
};
if(member_list->next)
++count;
else
break;
}
return count;
}
void rjp_dump(struct JSON_value* root){
size_t len = count_json(root);
char* tmp = malloc(len + 1);
tmp[len] = 0;
size_t pos = 1;
sprintf(tmp, "{");
pos += dump_json(root, tmp+pos);
sprintf(tmp+pos, "}");
printf("%s\n", tmp);
free(tmp);
}
int main(){
struct JSON_value* root = rjp_init_json();
rjp_add_member(&root->object, 1, "intel_backlight", 0, (struct JSON_value){.integer = 4, .type = json_integer});
rjp_add_member(&root->object, 1, "other_backlight", 0, (struct JSON_value){.integer = 14, .type = json_integer});
struct JSON_value sub_object = rjp_object();
rjp_add_member(&sub_object.object, 1, "sub_item", 0, rjp_array());
rjp_add_member(&root->object, 1, "object", 0, sub_object);
printf("%d\n", snprintf(NULL, 0, "%lf", 100.0));
printf("%lf\n", 100.0);
rjp_dump(root);
printf("\n");
printf("%lu\n", count_json(root));
rjp_free(root);
}