From e70b0833e69c62e36498cc41eadab24b2ecb3f47 Mon Sep 17 00:00:00 2001 From: rexy712 Date: Thu, 29 Nov 2018 14:26:20 -0800 Subject: [PATCH] Working json output and split source into multiple files --- CMakeLists.txt | 2 +- include/rjp.h | 21 +- include/rjp_internal.h | 13 ++ src/{rjp.c => input.c} | 430 +++++------------------------------------ src/output.c | 145 ++++++++++++++ src/strings.c | 196 +++++++++++++++++++ 6 files changed, 423 insertions(+), 384 deletions(-) create mode 100644 include/rjp_internal.h rename src/{rjp.c => input.c} (50%) create mode 100644 src/output.c create mode 100644 src/strings.c diff --git a/CMakeLists.txt b/CMakeLists.txt index f4e0109..6d36c51 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/include/rjp.h b/include/rjp.h index e7a9c09..a0debcf 100644 --- a/include/rjp.h +++ b/include/rjp.h @@ -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 diff --git a/include/rjp_internal.h b/include/rjp_internal.h new file mode 100644 index 0000000..fbeee6c --- /dev/null +++ b/include/rjp_internal.h @@ -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 diff --git a/src/rjp.c b/src/input.c similarity index 50% rename from src/rjp.c rename to src/input.c index 8daa146..a054ca4 100644 --- a/src/rjp.c +++ b/src/input.c @@ -20,8 +20,9 @@ //TODO: \e escape sequence in strings #include "rjp.h" +#include "rjp_internal.h" #include //strncpy -#include //malloc, calloc +#include //malloc, calloc, free #include //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); } diff --git a/src/output.c b/src/output.c new file mode 100644 index 0000000..eb29b4c --- /dev/null +++ b/src/output.c @@ -0,0 +1,145 @@ +#include "rjp.h" +#include "rjp_internal.h" + +#include //strlen +#include //malloc, calloc, free +#include //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; +} + diff --git a/src/strings.c b/src/strings.c new file mode 100644 index 0000000..94b29e5 --- /dev/null +++ b/src/strings.c @@ -0,0 +1,196 @@ +#include "rjp.h" +#include "rjp_internal.h" + +#include //fprintf +#include //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; +} +