Working json output and split source into multiple files
This commit is contained in:
parent
9eaa734fbb
commit
e70b0833e6
@ -12,7 +12,7 @@ configure_file(
|
||||
)
|
||||
include_directories("${INCLUDE_PATH}")
|
||||
|
||||
add_library (rjp STATIC src/rjp.c)
|
||||
add_library (rjp STATIC src/input.c src/output.c src/strings.c)
|
||||
set_target_properties(rjp PROPERTIES PUBLIC_HEADER ${INCLUDE_PATH}/rjp.h)
|
||||
|
||||
install(TARGETS rjp
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
#endif
|
||||
|
||||
//type of data
|
||||
enum JSON_type{
|
||||
json_object,
|
||||
@ -110,11 +111,21 @@ struct JSON_value* rjp_add_member(struct JSON_object* dest, int alloc_key, char*
|
||||
//add an element to a json array
|
||||
struct JSON_value* rjp_add_element(struct JSON_array* dest, struct JSON_value value);
|
||||
|
||||
/*struct JSON_value* root = rjp_init_json();
|
||||
rjp_add_member(root, "intel_backlight", 15, rjp_init_integer(100));
|
||||
rjp_free(root);
|
||||
//{intel_backlight:100}
|
||||
*/
|
||||
struct JSON_value rjp_integer(long i);
|
||||
struct JSON_value rjp_boolean(char b);
|
||||
struct JSON_value rjp_dfloat(double d);
|
||||
struct JSON_value rjp_string(char* c, size_t len);
|
||||
struct JSON_value rjp_null(void);
|
||||
struct JSON_value rjp_object(void);
|
||||
struct JSON_value rjp_array(void);
|
||||
|
||||
size_t rjp_escape_strcpy(char* dest, const char* src);
|
||||
size_t rjp_escape_strlen(const char* str);
|
||||
|
||||
size_t rjp_dump_object(struct JSON_value* root, char* dest);
|
||||
size_t rjp_dump_array(struct JSON_value* arr, char* dest);
|
||||
char* rjp_to_json(struct JSON_value* root);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
13
include/rjp_internal.h
Normal file
13
include/rjp_internal.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef RJP_INTERNAL_H
|
||||
#define RJP_INTERNAL_H
|
||||
|
||||
#include "rjp.h"
|
||||
|
||||
char* _rjp__parse_string(struct JSON_value* root, const char* str, int* len, int* row, int* column);
|
||||
size_t _rjp__object_strlen(struct JSON_value* root);
|
||||
void _rjp__add_member(struct JSON_object* j, char* str, size_t len);
|
||||
void _rjp__add_member_no_alloc(struct JSON_object* j, char* str, size_t len);
|
||||
void _rjp__add_element(struct JSON_array* j);
|
||||
size_t _rjp__object_strlen(struct JSON_value* root);
|
||||
|
||||
#endif
|
||||
@ -20,8 +20,9 @@
|
||||
//TODO: \e escape sequence in strings
|
||||
|
||||
#include "rjp.h"
|
||||
#include "rjp_internal.h"
|
||||
#include <string.h> //strncpy
|
||||
#include <stdlib.h> //malloc, calloc
|
||||
#include <stdlib.h> //malloc, calloc, free
|
||||
#include <stdio.h> //fprintf, stderr
|
||||
|
||||
#ifdef __GNUC__
|
||||
@ -44,11 +45,11 @@ enum json_search_target{
|
||||
};
|
||||
|
||||
//Determine if the character is valid whitespace
|
||||
static int is_whitespace(char c){
|
||||
static int _rjp__is_whitespace(char c){
|
||||
return c == ' ' || c == '\n' || c == '\r' || c == '\t';
|
||||
}
|
||||
//add an element to an array
|
||||
static void add_element(struct JSON_array* j){
|
||||
void _rjp__add_element(struct JSON_array* j){
|
||||
++j->num_elements;
|
||||
if(!j->elements){
|
||||
j->elements = calloc(1, sizeof(struct JSON_array_element));
|
||||
@ -59,7 +60,7 @@ static void add_element(struct JSON_array* j){
|
||||
}
|
||||
}
|
||||
//create member of the object as a linked list member and assign a name with no name allocation
|
||||
static void add_member(struct JSON_object* j, char* str, size_t len){
|
||||
void _rjp__add_member(struct JSON_object* j, char* str, size_t len){
|
||||
++j->num_members;
|
||||
if(!j->members){
|
||||
j->members = calloc(1, sizeof(struct JSON_object_member));
|
||||
@ -73,7 +74,7 @@ static void add_member(struct JSON_object* j, char* str, size_t 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){
|
||||
void _rjp__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));
|
||||
@ -86,16 +87,16 @@ static void add_member_no_alloc(struct JSON_object* j, char* str, size_t len){
|
||||
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* _rjp__add_element_to_array(struct JSON_value* curr, struct JSON_state* state, struct JSON_value* element){
|
||||
struct JSON_value* tmp = &curr->object.members->value;
|
||||
for(int i = state->in_array-1;i > 0;--i, tmp = &tmp->array.last->value);
|
||||
add_element(&tmp->array);
|
||||
_rjp__add_element(&tmp->array);
|
||||
tmp->array.last->value = *element;
|
||||
return &tmp->array.last->value;
|
||||
}
|
||||
|
||||
//Assign object characteristics to previously allocated JSON_value
|
||||
static struct JSON_value* add_object(struct JSON_value* curr, struct JSON_state* state){
|
||||
static struct JSON_value* _rjp__add_object(struct JSON_value* curr, struct JSON_state* state){
|
||||
if(!curr){
|
||||
curr = calloc(1, sizeof(struct JSON_value));
|
||||
curr->type = json_object;
|
||||
@ -103,67 +104,67 @@ 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};
|
||||
if(state->in_array)
|
||||
return add_element_to_array(curr, state, &new_object);
|
||||
return _rjp__add_element_to_array(curr, state, &new_object);
|
||||
curr->object.last->value = new_object;
|
||||
return &curr->object.last->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* _rjp__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};
|
||||
if(state->in_array)
|
||||
return add_element_to_array(curr, state, &new_array);
|
||||
return _rjp__add_element_to_array(curr, state, &new_array);
|
||||
curr->object.last->value = new_array;
|
||||
return &curr->object.last->value;
|
||||
}
|
||||
//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* _rjp__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};
|
||||
if(state->in_array)
|
||||
return add_element_to_array(curr, state, &new_string);
|
||||
return _rjp__add_element_to_array(curr, state, &new_string);
|
||||
curr->object.last->value = new_string;
|
||||
return &curr->object.last->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* _rjp__add_dfloat(struct JSON_value* curr, double value, struct JSON_state* state){
|
||||
struct JSON_value new_double = {.type = json_dfloat, .dfloat = value, .parent = curr};
|
||||
if(state->in_array)
|
||||
return add_element_to_array(curr, state, &new_double);
|
||||
return _rjp__add_element_to_array(curr, state, &new_double);
|
||||
curr->object.last->value = new_double;
|
||||
return &curr->object.last->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* _rjp__add_integer(struct JSON_value* curr, long value, struct JSON_state* state){
|
||||
struct JSON_value new_integer = {.type = json_integer, .integer = value, .parent = curr};
|
||||
if(state->in_array)
|
||||
return add_element_to_array(curr, state, &new_integer);
|
||||
return _rjp__add_element_to_array(curr, state, &new_integer);
|
||||
curr->object.last->value = new_integer;
|
||||
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* _rjp__add_boolean(struct JSON_value* curr, int value, struct JSON_state* state){
|
||||
struct JSON_value new_boolean = {.type = json_boolean, .boolean = value, .parent = curr};
|
||||
if(state->in_array)
|
||||
return add_element_to_array(curr, state, &new_boolean);
|
||||
return _rjp__add_element_to_array(curr, state, &new_boolean);
|
||||
curr->object.last->value = new_boolean;
|
||||
return &curr->object.last->value;
|
||||
}
|
||||
static struct JSON_value* add_null(struct JSON_value* curr, struct JSON_state* state){
|
||||
static struct JSON_value* _rjp__add_null(struct JSON_value* curr, struct JSON_state* state){
|
||||
struct JSON_value new_null = {.type = json_null, .integer = 0, .parent = curr};
|
||||
if(state->in_array)
|
||||
return add_element_to_array(curr, state, &new_null);
|
||||
return _rjp__add_element_to_array(curr, state, &new_null);
|
||||
curr->object.last->value = new_null;
|
||||
return &curr->object.last->value;
|
||||
}
|
||||
|
||||
static void free_json_recurse(struct JSON_value* root);
|
||||
static void _rjp__free_object_recurse(struct JSON_value* root);
|
||||
|
||||
static void free_json_array(struct JSON_value* root){
|
||||
static void _rjp__free_array(struct JSON_value* root){
|
||||
struct JSON_array_element* arr = root->array.elements;
|
||||
for(struct JSON_array_element* i = arr;i != NULL;i = arr){
|
||||
arr = arr->next;
|
||||
if(i->value.type == json_object){
|
||||
free_json_recurse(&i->value);
|
||||
_rjp__free_object_recurse(&i->value);
|
||||
}else if(i->value.type == json_array){
|
||||
free_json_array(&i->value);
|
||||
_rjp__free_array(&i->value);
|
||||
}else if(i->value.type == json_string){
|
||||
free(i->value.string.value);
|
||||
}
|
||||
@ -171,16 +172,16 @@ static void free_json_array(struct JSON_value* root){
|
||||
}
|
||||
}
|
||||
//Recursively free JSON objects
|
||||
static void free_json_recurse(struct JSON_value* root){
|
||||
static void _rjp__free_object_recurse(struct JSON_value* root){
|
||||
struct JSON_object_member* next;
|
||||
for(struct JSON_object_member* m = root->object.members;m;m = next){
|
||||
next = m->next;
|
||||
if(m->value.type == json_object)
|
||||
free_json_recurse(&m->value);
|
||||
_rjp__free_object_recurse(&m->value);
|
||||
else if(m->value.type == json_string)
|
||||
free(m->value.string.value);
|
||||
else if(m->value.type == json_array)
|
||||
free_json_array(&m->value);
|
||||
_rjp__free_array(&m->value);
|
||||
if(m->name.value)
|
||||
free(m->name.value);
|
||||
free(m);
|
||||
@ -190,11 +191,11 @@ static void free_json_recurse(struct JSON_value* root){
|
||||
void rjp_free(struct JSON_value* root){
|
||||
if(!root)
|
||||
return;
|
||||
free_json_recurse(root);
|
||||
_rjp__free_object_recurse(root);
|
||||
free(root);
|
||||
}
|
||||
|
||||
MAYBE_UNUSED static int is_array_empty(struct JSON_value* curr){
|
||||
MAYBE_UNUSED static int _rjp__is_array_empty(struct JSON_value* curr){
|
||||
if(curr->object.members->value.type != json_array)
|
||||
return 0;
|
||||
return curr->object.members->value.array.num_elements == 0;
|
||||
@ -203,63 +204,6 @@ MAYBE_UNUSED static int is_array_empty(struct JSON_value* curr){
|
||||
#define syntax_error(msg, row, column)\
|
||||
do{fprintf(stderr, "Syntax error! %s (%i:%i)\n", msg, row, column);rjp_free(root);return NULL;}while(0)
|
||||
|
||||
//Convert escape sequences in strings
|
||||
static char* parse_string(struct JSON_value* root, const char* str, int* len, int* row, int* column){
|
||||
char* new_string;
|
||||
++(*column); //account for starting quotation mark
|
||||
for(*len = 0;*(str+*len) != '"';++(*len), ++(*column)){
|
||||
if(*(str+*len) == '\\'){
|
||||
++(*len);
|
||||
++(*column);
|
||||
}else if(*(str+*len) == '\0'){
|
||||
*len = 1;
|
||||
syntax_error("Unexpected EOF in string!", *row, *column);
|
||||
}else if(*(str+*len) == '\n'){
|
||||
++(*row);
|
||||
*column = 0;
|
||||
}
|
||||
}
|
||||
if(*len == 0){
|
||||
return NULL;
|
||||
}
|
||||
new_string = malloc(*len + 1);
|
||||
new_string[*len] = 0;
|
||||
for(int i = 0;*str != '"';++i,++str){
|
||||
if(*str == '\\'){
|
||||
++str;
|
||||
switch(*str){
|
||||
case '"':
|
||||
new_string[i] = '"';
|
||||
break;
|
||||
case 'n':
|
||||
new_string[i] = '\n';
|
||||
break;
|
||||
case 'r':
|
||||
new_string[i] = '\r';
|
||||
break;
|
||||
case 'b':
|
||||
new_string[i] = '\b';
|
||||
break;
|
||||
case '\\':
|
||||
new_string[i] = '\\';
|
||||
break;
|
||||
case 't':
|
||||
new_string[i] = '\t';
|
||||
break;
|
||||
case 'f':
|
||||
new_string[i] = '\f';
|
||||
break;
|
||||
default:
|
||||
new_string[i] = *str;
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
new_string[i] = *str;
|
||||
}
|
||||
}
|
||||
return new_string;
|
||||
}
|
||||
|
||||
#define MAX_DEPTH 16
|
||||
struct JSON_value* rjp_parse(const char* str){
|
||||
struct JSON_value* root = 0;
|
||||
@ -313,13 +257,13 @@ struct JSON_value* rjp_parse(const char* str){
|
||||
syntax_error("Key found outside of object definition!", row, column);
|
||||
|
||||
int keylen;
|
||||
char* new_string = parse_string(root, ++str, &keylen, &row, &column);
|
||||
char* new_string = _rjp__parse_string(root, ++str, &keylen, &row, &column);
|
||||
if(!new_string){
|
||||
if(!keylen)
|
||||
syntax_error("Cannot have empty key name!", row, column);
|
||||
return NULL;
|
||||
}
|
||||
add_member(&curr->object, new_string, keylen);
|
||||
_rjp__add_member(&curr->object, new_string, keylen);
|
||||
str += keylen;
|
||||
top->search_target = json_colon;
|
||||
//end of this object (object is empty)
|
||||
@ -329,7 +273,7 @@ struct JSON_value* rjp_parse(const char* str){
|
||||
--top;
|
||||
|
||||
//unrecognized character
|
||||
}else if(!is_whitespace(c)){
|
||||
}else if(!_rjp__is_whitespace(c)){
|
||||
syntax_error("Unexpected character, expected '\"'!", row, column);
|
||||
}
|
||||
}
|
||||
@ -338,7 +282,7 @@ struct JSON_value* rjp_parse(const char* str){
|
||||
if(c == ':'){
|
||||
top->search_target = json_value;
|
||||
//unrecognized character
|
||||
}else if(!is_whitespace(c)){
|
||||
}else if(!_rjp__is_whitespace(c)){
|
||||
syntax_error( "Unexpected character, expected ':'!", row, column);
|
||||
}
|
||||
}
|
||||
@ -359,7 +303,7 @@ struct JSON_value* rjp_parse(const char* str){
|
||||
}else if(c == ']' && top->in_array){
|
||||
--top->in_array;
|
||||
//unrecognized character
|
||||
}else if(!is_whitespace(c)){
|
||||
}else if(!_rjp__is_whitespace(c)){
|
||||
syntax_error("Unexpected character, expected ','!", row, column);
|
||||
}
|
||||
}
|
||||
@ -367,11 +311,11 @@ struct JSON_value* rjp_parse(const char* str){
|
||||
//object
|
||||
if(c == '{'){
|
||||
if(!root){
|
||||
root = add_object(NULL, top);
|
||||
root = _rjp__add_object(NULL, top);
|
||||
curr = root;
|
||||
top->search_target = json_key;
|
||||
}else{
|
||||
curr = add_object(curr, top);
|
||||
curr = _rjp__add_object(curr, top);
|
||||
top->search_target = json_comma;
|
||||
++top;
|
||||
top->in_array = 0;
|
||||
@ -384,7 +328,7 @@ struct JSON_value* rjp_parse(const char* str){
|
||||
}
|
||||
//arrays
|
||||
else if(c == '['){
|
||||
add_array(curr, top);
|
||||
_rjp__add_array(curr, top);
|
||||
++top->in_array;
|
||||
}
|
||||
else if(c == ']' && top->in_array){ //empty array
|
||||
@ -395,7 +339,7 @@ struct JSON_value* rjp_parse(const char* str){
|
||||
else if(c == '"'){
|
||||
int vallen;
|
||||
++str;
|
||||
char* new_string = parse_string(root, str, &vallen, &row, &column);
|
||||
char* new_string = _rjp__parse_string(root, str, &vallen, &row, &column);
|
||||
if(!new_string){
|
||||
if(vallen == 0){
|
||||
new_string = calloc(1, 1);
|
||||
@ -403,7 +347,7 @@ struct JSON_value* rjp_parse(const char* str){
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
add_string_no_alloc(curr, new_string, vallen, top);
|
||||
_rjp__add_string_no_alloc(curr, new_string, vallen, top);
|
||||
str += vallen;
|
||||
top->search_target = json_comma;
|
||||
}
|
||||
@ -427,9 +371,9 @@ struct JSON_value* rjp_parse(const char* str){
|
||||
syntax_error("Missing numerals ofter '-' sign!", row, column);
|
||||
}
|
||||
if(floating){
|
||||
add_double(curr, strtod(str, NULL), top);
|
||||
_rjp__add_dfloat(curr, strtod(str, NULL), top);
|
||||
}else{
|
||||
add_integer(curr, strtol(str, NULL, 10), top);
|
||||
_rjp__add_integer(curr, strtol(str, NULL, 10), top);
|
||||
}
|
||||
str += (numlen-1);
|
||||
column += numlen;
|
||||
@ -437,20 +381,20 @@ struct JSON_value* rjp_parse(const char* str){
|
||||
}
|
||||
//booleans and null
|
||||
else if(!strncmp(str, "true", 4)){
|
||||
add_boolean(curr, 1, top);
|
||||
_rjp__add_boolean(curr, 1, top);
|
||||
str += 3;
|
||||
top->search_target = json_comma;
|
||||
}else if(!strncmp(str, "false", 5)){
|
||||
add_boolean(curr, 0, top);
|
||||
_rjp__add_boolean(curr, 0, top);
|
||||
str += 4;
|
||||
top->search_target = json_comma;
|
||||
}else if(!strncmp(str, "null", 4)){
|
||||
add_null(curr, top);
|
||||
_rjp__add_null(curr, top);
|
||||
str += 3;
|
||||
top->search_target = json_comma;
|
||||
}
|
||||
//unrecognized character
|
||||
else if(!is_whitespace(c)){
|
||||
else if(!_rjp__is_whitespace(c)){
|
||||
syntax_error("Unexpected character!", row, column);
|
||||
}
|
||||
}
|
||||
@ -460,6 +404,7 @@ struct JSON_value* rjp_parse(const char* str){
|
||||
|
||||
#undef syntax_error
|
||||
|
||||
//TODO
|
||||
struct JSON_object_member* rjp_get_members(struct JSON_object* j){
|
||||
return j->members;
|
||||
}
|
||||
@ -479,279 +424,6 @@ enum JSON_type rjp_get_value_type(struct JSON_value* j){
|
||||
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});
|
||||
@ -761,8 +433,10 @@ int main(){
|
||||
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);
|
||||
char* out = rjp_to_json(root);
|
||||
printf("%s\n", out);
|
||||
free(out);
|
||||
printf("\n");
|
||||
printf("%lu\n", count_json(root));
|
||||
printf("%lu\n", _rjp__object_strlen(root));
|
||||
rjp_free(root);
|
||||
}
|
||||
145
src/output.c
Normal file
145
src/output.c
Normal file
@ -0,0 +1,145 @@
|
||||
#include "rjp.h"
|
||||
#include "rjp_internal.h"
|
||||
|
||||
#include <string.h> //strlen
|
||||
#include <stdlib.h> //malloc, calloc, free
|
||||
#include <stdio.h> //sprintf
|
||||
|
||||
struct JSON_value* rjp_init_json(void){
|
||||
struct JSON_value* ret = calloc(1, sizeof(struct JSON_value));
|
||||
ret->type = json_object;
|
||||
return ret;
|
||||
}
|
||||
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)
|
||||
_rjp__add_member(dest, key, keylen);
|
||||
else
|
||||
_rjp__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){
|
||||
_rjp__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_dfloat(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 rjp_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:
|
||||
pos += sprintf(dest+pos, "\"%s\"", element_list->value.string.value);
|
||||
break;
|
||||
case json_array:
|
||||
pos += sprintf(dest+pos, "[");
|
||||
pos += rjp_dump_array(&element_list->value, dest+pos);
|
||||
pos += sprintf(dest+pos, "]");
|
||||
break;
|
||||
case json_object:
|
||||
pos += sprintf(dest+pos, "{");
|
||||
pos += rjp_dump_object(&element_list->value, dest+pos);
|
||||
pos += sprintf(dest+pos, "}");
|
||||
break;
|
||||
};
|
||||
if(element_list->next)
|
||||
pos += sprintf(dest+pos, ",");
|
||||
else
|
||||
break;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
size_t rjp_dump_object(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, "\"%s\":", member_list->name.value);
|
||||
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, "\"%s\"", member_list->value.string.value);
|
||||
break;
|
||||
case json_array:
|
||||
pos += sprintf(dest+pos, "[");
|
||||
pos += rjp_dump_array(&member_list->value, dest+pos);
|
||||
pos += sprintf(dest+pos, "]");
|
||||
break;
|
||||
case json_object:
|
||||
pos += sprintf(dest+pos, "{");
|
||||
pos += rjp_dump_object(&member_list->value, dest+pos);
|
||||
pos += sprintf(dest+pos, "}");
|
||||
break;
|
||||
};
|
||||
if(member_list->next)
|
||||
pos += sprintf(dest+pos, ",");
|
||||
else
|
||||
break;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
char* rjp_to_json(struct JSON_value* root){
|
||||
size_t len = _rjp__object_strlen(root);
|
||||
char* tmp = malloc(len + 1);
|
||||
tmp[len] = 0;
|
||||
size_t pos = 1;
|
||||
|
||||
sprintf(tmp, "{");
|
||||
pos += rjp_dump_object(root, tmp+pos);
|
||||
sprintf(tmp+pos, "}");
|
||||
return tmp;
|
||||
}
|
||||
|
||||
196
src/strings.c
Normal file
196
src/strings.c
Normal file
@ -0,0 +1,196 @@
|
||||
#include "rjp.h"
|
||||
#include "rjp_internal.h"
|
||||
|
||||
#include <stdio.h> //fprintf
|
||||
#include <stdlib.h> //malloc, free
|
||||
|
||||
//Convert escape sequences in strings
|
||||
char* _rjp__parse_string(struct JSON_value* root, const char* str, int* len, int* row, int* column){
|
||||
char* new_string;
|
||||
++(*column); //account for starting quotation mark
|
||||
for(*len = 0;*(str+*len) != '"';++(*len), ++(*column)){
|
||||
if(*(str+*len) == '\\'){
|
||||
++(*len);
|
||||
++(*column);
|
||||
}else if(*(str+*len) == '\0'){
|
||||
*len = 1;
|
||||
fprintf(stderr, "Syntax error! %s (%i:%i)\n", "Unexpected EOF in string!", *row, *column);
|
||||
rjp_free(root);
|
||||
return NULL;
|
||||
}else if(*(str+*len) == '\n'){
|
||||
++(*row);
|
||||
*column = 0;
|
||||
}
|
||||
}
|
||||
if(*len == 0){
|
||||
return NULL;
|
||||
}
|
||||
new_string = malloc(*len + 1);
|
||||
new_string[*len] = 0;
|
||||
for(int i = 0;*str != '"';++i,++str){
|
||||
if(*str == '\\'){
|
||||
++str;
|
||||
switch(*str){
|
||||
case '"':
|
||||
new_string[i] = '"';
|
||||
break;
|
||||
case 'n':
|
||||
new_string[i] = '\n';
|
||||
break;
|
||||
case 'r':
|
||||
new_string[i] = '\r';
|
||||
break;
|
||||
case 'b':
|
||||
new_string[i] = '\b';
|
||||
break;
|
||||
case '\\':
|
||||
new_string[i] = '\\';
|
||||
break;
|
||||
case 't':
|
||||
new_string[i] = '\t';
|
||||
break;
|
||||
case 'f':
|
||||
new_string[i] = '\f';
|
||||
break;
|
||||
default:
|
||||
new_string[i] = *str;
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
new_string[i] = *str;
|
||||
}
|
||||
}
|
||||
return new_string;
|
||||
}
|
||||
|
||||
size_t rjp_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 rjp_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 _rjp__array_strlen(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 += element_list->value.string.length;
|
||||
break;
|
||||
case json_array:
|
||||
count += _rjp__array_strlen(&element_list->value);
|
||||
break;
|
||||
case json_object:
|
||||
count += _rjp__object_strlen(&element_list->value);
|
||||
break;
|
||||
};
|
||||
if(element_list->next)
|
||||
++count;
|
||||
else
|
||||
break;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
size_t _rjp__object_strlen(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 += 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:
|
||||
count += _rjp__object_strlen(&member_list->value);
|
||||
break;
|
||||
};
|
||||
if(member_list->next)
|
||||
++count; //,
|
||||
else
|
||||
break;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user