Reorganized file structure
This commit is contained in:
parent
6d89e4dc5a
commit
4b5586ffed
@ -16,7 +16,7 @@ include_directories("${INCLUDE_PATH}")
|
|||||||
option(ENABLE_DIAGNOSTICS "Print diagnostic messages when parsing json to help identify issues" ON)
|
option(ENABLE_DIAGNOSTICS "Print diagnostic messages when parsing json to help identify issues" ON)
|
||||||
option(ENABLE_SHARED "Build shared library" OFF)
|
option(ENABLE_SHARED "Build shared library" OFF)
|
||||||
|
|
||||||
set(SOURCE_LIST "src/input.c" "src/output.c" "src/strings.c" "src/memory.c")
|
set(SOURCE_LIST "src/input.c" "src/output.c" "src/strings.c" "src/memory.c" "src/rjp.c")
|
||||||
if(ENABLE_SHARED)
|
if(ENABLE_SHARED)
|
||||||
add_library(rjp SHARED ${SOURCE_LIST})
|
add_library(rjp SHARED ${SOURCE_LIST})
|
||||||
else()
|
else()
|
||||||
|
|||||||
@ -75,17 +75,17 @@ typedef struct RJP_value{
|
|||||||
enum RJP_type type; //flag to determine active member of union
|
enum RJP_type type; //flag to determine active member of union
|
||||||
}RJP_value;
|
}RJP_value;
|
||||||
|
|
||||||
//Convert C string consisting of json data into RJP's format
|
//Convert C string consisting of json data into RJP's format
|
||||||
RJP_value* rjp_parse(const char* str);
|
RJP_value* rjp_parse(const char* str);
|
||||||
|
|
||||||
|
|
||||||
//Free an RJP_value and all members/elements
|
|
||||||
void rjp_free_value(RJP_value* root);
|
|
||||||
|
|
||||||
//Initialize a root RJP_value to NULL
|
//Initialize a root RJP_value to NULL
|
||||||
RJP_value* rjp_init_json(void);
|
RJP_value* rjp_init_json(void);
|
||||||
//Initialize a root RJP_value to copy of value
|
//Initialize a root RJP_value to copy of value
|
||||||
RJP_value* rjp_init_json_as(RJP_value value);
|
RJP_value* rjp_init_json_as(RJP_value value);
|
||||||
|
//Free an RJP_value and all members/elements
|
||||||
|
void rjp_free_value(RJP_value* root);
|
||||||
|
//Deep copy RJP_value
|
||||||
|
void rjp_copy_value(RJP_value* dest, const RJP_value* src);
|
||||||
|
|
||||||
|
|
||||||
//Allocate heap space for rjp to use. Use if the memory is to be freed by rjp
|
//Allocate heap space for rjp to use. Use if the memory is to be freed by rjp
|
||||||
@ -95,8 +95,6 @@ void* rjp_calloc(size_t num, size_t nbytes);
|
|||||||
//Free memory allocated by rjp_alloc or rjp_calloc
|
//Free memory allocated by rjp_alloc or rjp_calloc
|
||||||
void rjp_free(void* dest);
|
void rjp_free(void* dest);
|
||||||
|
|
||||||
//Deep copy an RJP_value
|
|
||||||
void rjp_copy_value(RJP_value* dest, const RJP_value* src);
|
|
||||||
//add a member to a json object, allocating a copy of the key
|
//add a member to a json object, allocating a copy of the key
|
||||||
RJP_value* rjp_add_member(RJP_value* dest, const char* key, size_t keylen, RJP_value value);
|
RJP_value* rjp_add_member(RJP_value* dest, const char* key, size_t keylen, RJP_value value);
|
||||||
//add a member to a json object without allocation. key must be allocated using rjp_alloc/rjp_calloc
|
//add a member to a json object without allocation. key must be allocated using rjp_alloc/rjp_calloc
|
||||||
|
|||||||
@ -21,6 +21,19 @@
|
|||||||
|
|
||||||
#include "rjp.h"
|
#include "rjp.h"
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define MAYBE_UNUSED __attribute__((unused))
|
||||||
|
#else
|
||||||
|
#define MAYBE_UNUSED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef RJP_DIAGNOSTICS
|
||||||
|
#include <stdio.h>
|
||||||
|
#define DIAG_PRINT(...) fprintf(__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define DIAG_PRINT(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
//
|
//
|
||||||
typedef struct RJP_array_element{
|
typedef struct RJP_array_element{
|
||||||
struct RJP_value value;
|
struct RJP_value value;
|
||||||
@ -33,12 +46,8 @@ typedef struct RJP_object_member{
|
|||||||
struct RJP_object_member* next;
|
struct RJP_object_member* next;
|
||||||
}RJP_object_member;
|
}RJP_object_member;
|
||||||
|
|
||||||
char* _rjp__parse_string(RJP_value* root, const char* str, int* len, int* row, int* column);
|
void _rjp__add_element(RJP_array* j);
|
||||||
size_t _rjp__object_strlen(RJP_value* root);
|
|
||||||
void _rjp__add_member(RJP_object* j, const char* str, size_t len);
|
void _rjp__add_member(RJP_object* j, const char* str, size_t len);
|
||||||
void _rjp__add_member_no_alloc(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
|
#endif
|
||||||
|
|||||||
32
include/strings.h
Normal file
32
include/strings.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
rjp
|
||||||
|
Copyright (C) 2018 rexy712
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STRINGS_H
|
||||||
|
#define STRINGS_H
|
||||||
|
|
||||||
|
#include "rjp.h"
|
||||||
|
#include <stddef.h> //size_t
|
||||||
|
|
||||||
|
int _rjp__is_whitespace(char c);
|
||||||
|
char* _rjp__parse_string(RJP_value* root, const char* str, int* len, int* row, int* column);
|
||||||
|
size_t _rjp__array_strlen(RJP_value* arr);
|
||||||
|
size_t _rjp__object_strlen(RJP_value* root);
|
||||||
|
size_t _rjp__value_strlen(RJP_value* root);
|
||||||
|
void _rjp__strcpy(RJP_string* dest, const RJP_string* src);
|
||||||
|
|
||||||
|
#endif
|
||||||
187
src/input.c
187
src/input.c
@ -20,22 +20,11 @@
|
|||||||
|
|
||||||
#include "rjp.h"
|
#include "rjp.h"
|
||||||
#include "rjp_internal.h"
|
#include "rjp_internal.h"
|
||||||
#include <string.h> //strncpy
|
#include "strings.h"
|
||||||
#include <stdlib.h> //malloc, calloc, free
|
#include "memory.h"
|
||||||
|
#include <stdlib.h> //strtod, strtol
|
||||||
#include <stdio.h> //fprintf, stderr
|
#include <stdio.h> //fprintf, stderr
|
||||||
|
|
||||||
#ifdef __GNUC__
|
|
||||||
#define MAYBE_UNUSED __attribute__((unused))
|
|
||||||
#else
|
|
||||||
#define MAYBE_UNUSED
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef RJP_DIAGNOSTICS
|
|
||||||
#define DIAG_PRINT(...) fprintf(__VA_ARGS__)
|
|
||||||
#else
|
|
||||||
#define DIAG_PRINT(...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//types of searches in the text
|
//types of searches in the text
|
||||||
typedef enum json_search_target{
|
typedef enum json_search_target{
|
||||||
json_key,
|
json_key,
|
||||||
@ -45,151 +34,21 @@ typedef enum json_search_target{
|
|||||||
json_none
|
json_none
|
||||||
}json_search_target;
|
}json_search_target;
|
||||||
|
|
||||||
//Determine if the character is valid whitespace
|
static RJP_value* _rjp__add_value(RJP_value* curr, RJP_value new_val){
|
||||||
static int _rjp__is_whitespace(char c){
|
new_val.parent = curr;
|
||||||
return c == ' ' || c == '\n' || c == '\r' || c == '\t';
|
|
||||||
}
|
|
||||||
//add an element to an array
|
|
||||||
void _rjp__add_element(RJP_array* j){
|
|
||||||
++j->num_elements;
|
|
||||||
if(!j->elements){
|
|
||||||
j->elements = rjp_calloc(1, sizeof(RJP_array_element));
|
|
||||||
j->last = j->elements;
|
|
||||||
}else{
|
|
||||||
j->last->next = rjp_calloc(1, sizeof(RJP_array_element));
|
|
||||||
j->last = j->last->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//create member of the object as a linked list member and assign a name with name allocation
|
|
||||||
void _rjp__add_member(RJP_object* j, const char* str, size_t len){
|
|
||||||
++j->num_members;
|
|
||||||
if(!j->members){
|
|
||||||
j->members = rjp_calloc(1, sizeof(RJP_object_member));
|
|
||||||
j->last = j->members;
|
|
||||||
}else{
|
|
||||||
j->last->next = rjp_calloc(1, sizeof(RJP_object_member));
|
|
||||||
j->last = j->last->next;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
void _rjp__add_member_no_alloc(RJP_object* j, char* str, size_t len){
|
|
||||||
++j->num_members;
|
|
||||||
if(!j->members){
|
|
||||||
j->members = rjp_calloc(1, sizeof(RJP_object_member));
|
|
||||||
j->last = j->members;
|
|
||||||
}else{
|
|
||||||
j->last->next = rjp_calloc(1, sizeof(RJP_object_member));
|
|
||||||
j->last = j->last->next;
|
|
||||||
}
|
|
||||||
j->last->name.value = str;
|
|
||||||
j->last->name.length = len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static RJP_value* _rjp__add_value(RJP_value* curr, RJP_value* new_val){
|
|
||||||
if(!curr){
|
if(!curr){
|
||||||
curr = rjp_calloc(1, sizeof(RJP_value));
|
curr = rjp_calloc(1, sizeof(RJP_value));
|
||||||
*curr = *new_val;
|
*curr = new_val;
|
||||||
return curr;
|
return curr;
|
||||||
}
|
}
|
||||||
if(curr->type == json_array){
|
if(curr->type == json_array){
|
||||||
_rjp__add_element(&curr->array);
|
_rjp__add_element(&curr->array);
|
||||||
curr->array.last->value = *new_val;
|
curr->array.last->value = new_val;
|
||||||
return &curr->array.last->value;
|
return &curr->array.last->value;
|
||||||
}
|
}
|
||||||
curr->object.last->value = *new_val;
|
curr->object.last->value = new_val;
|
||||||
return &curr->object.last->value;
|
return &curr->object.last->value;
|
||||||
}
|
}
|
||||||
//Assign object characteristics to previously allocated RJP_value
|
|
||||||
static RJP_value* _rjp__add_object(RJP_value* curr){
|
|
||||||
RJP_value new_object = {.type = json_object, .integer = 0, .parent = curr};
|
|
||||||
return _rjp__add_value(curr, &new_object);
|
|
||||||
}
|
|
||||||
//Assign array characteristics to previously allocated RJP_value
|
|
||||||
static RJP_value* _rjp__add_array(RJP_value* curr){
|
|
||||||
RJP_value new_array = {.type = json_array, .array = {.num_elements = 0, .elements = NULL}, .parent = curr};
|
|
||||||
return _rjp__add_value(curr, &new_array);
|
|
||||||
}
|
|
||||||
//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_value new_string = {.type = json_string, .string = {.value = str, .length = len}, .parent = curr};
|
|
||||||
return _rjp__add_value(curr, &new_string);
|
|
||||||
}
|
|
||||||
//Assign double characteristics to previously allocated RJP_value
|
|
||||||
static RJP_value* _rjp__add_dfloat(RJP_value* curr, double value){
|
|
||||||
RJP_value new_double = {.type = json_dfloat, .dfloat = value, .parent = curr};
|
|
||||||
return _rjp__add_value(curr, &new_double);
|
|
||||||
}
|
|
||||||
//Assign integer characteristics to previously allocated RJP_value
|
|
||||||
static RJP_value* _rjp__add_integer(RJP_value* curr, long value){
|
|
||||||
RJP_value new_integer = {.type = json_integer, .integer = value, .parent = curr};
|
|
||||||
return _rjp__add_value(curr, &new_integer);
|
|
||||||
}
|
|
||||||
static RJP_value* _rjp__add_boolean(RJP_value* curr, int value){
|
|
||||||
RJP_value new_boolean = {.type = json_boolean, .boolean = value, .parent = curr};
|
|
||||||
return _rjp__add_value(curr, &new_boolean);
|
|
||||||
}
|
|
||||||
static RJP_value* _rjp__add_null(RJP_value* curr){
|
|
||||||
RJP_value new_null = {.type = json_null, .integer = 0, .parent = curr};
|
|
||||||
return _rjp__add_value(curr, &new_null);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _rjp__free_object_recurse(RJP_value* root);
|
|
||||||
|
|
||||||
static void _rjp__free_array(RJP_value* root){
|
|
||||||
RJP_array_element* arr = root->array.elements;
|
|
||||||
for(RJP_array_element* i = arr;i != NULL;i = arr){
|
|
||||||
arr = arr->next;
|
|
||||||
if(i->value.type == json_object){
|
|
||||||
_rjp__free_object_recurse(&i->value);
|
|
||||||
}else if(i->value.type == json_array){
|
|
||||||
_rjp__free_array(&i->value);
|
|
||||||
}else if(i->value.type == json_string){
|
|
||||||
free(i->value.string.value);
|
|
||||||
}
|
|
||||||
free(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Recursively free JSON objects
|
|
||||||
static void _rjp__free_object_recurse(RJP_value* root){
|
|
||||||
RJP_object_member* next;
|
|
||||||
for(RJP_object_member* m = root->object.members;m;m = next){
|
|
||||||
next = m->next;
|
|
||||||
if(m->value.type == json_object)
|
|
||||||
_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)
|
|
||||||
_rjp__free_array(&m->value);
|
|
||||||
if(m->name.value)
|
|
||||||
free(m->name.value);
|
|
||||||
free(m);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void rjp_free_value_json(char* json){
|
|
||||||
free(json);
|
|
||||||
}
|
|
||||||
//Same as recurse but also frees root node
|
|
||||||
void rjp_free_value(RJP_value* root){
|
|
||||||
if(!root)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if((root->type) == json_object)
|
|
||||||
_rjp__free_object_recurse(root);
|
|
||||||
else if((root->type) == json_array)
|
|
||||||
_rjp__free_array(root);
|
|
||||||
|
|
||||||
free(root);
|
|
||||||
}
|
|
||||||
|
|
||||||
MAYBE_UNUSED static int _rjp__is_array_empty(RJP_value* curr){
|
|
||||||
if(curr->object.members->value.type != json_array)
|
|
||||||
return 0;
|
|
||||||
return curr->object.members->value.array.num_elements == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define syntax_error(msg, row, column)\
|
#define syntax_error(msg, row, column)\
|
||||||
do{DIAG_PRINT(stderr, "Syntax error! %s (%i:%i)\n", msg, row, column);rjp_free_value(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)
|
||||||
|
|
||||||
@ -299,11 +158,11 @@ RJP_value* rjp_parse(const char* str){
|
|||||||
//object
|
//object
|
||||||
if(c == '{'){
|
if(c == '{'){
|
||||||
if(!root){
|
if(!root){
|
||||||
root = _rjp__add_object(NULL);
|
root = _rjp__add_value(NULL, rjp_object());
|
||||||
curr = root;
|
curr = root;
|
||||||
*top = json_key;
|
*top = json_key;
|
||||||
}else{
|
}else{
|
||||||
curr = _rjp__add_object(curr);
|
curr = _rjp__add_value(curr, rjp_object());
|
||||||
*top = json_comma;
|
*top = json_comma;
|
||||||
++top;
|
++top;
|
||||||
*top = json_key;
|
*top = json_key;
|
||||||
@ -311,11 +170,11 @@ RJP_value* rjp_parse(const char* str){
|
|||||||
}
|
}
|
||||||
else if(c == '['){
|
else if(c == '['){
|
||||||
if(!root){
|
if(!root){
|
||||||
root = _rjp__add_array(NULL);
|
root = _rjp__add_value(NULL, rjp_array());
|
||||||
curr = root;
|
curr = root;
|
||||||
|
|
||||||
}else{
|
}else{
|
||||||
curr = _rjp__add_array(curr);
|
curr = _rjp__add_value(curr, rjp_array());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(c == ']' && curr->type == json_array){ //empty array
|
else if(c == ']' && curr->type == json_array){ //empty array
|
||||||
@ -334,7 +193,7 @@ RJP_value* rjp_parse(const char* str){
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_rjp__add_string_no_alloc(curr, new_string, vallen);
|
_rjp__add_value(curr, rjp_string(new_string, vallen));
|
||||||
str += vallen;
|
str += vallen;
|
||||||
*top = json_comma;
|
*top = json_comma;
|
||||||
}
|
}
|
||||||
@ -363,15 +222,15 @@ RJP_value* rjp_parse(const char* str){
|
|||||||
}
|
}
|
||||||
if(floating){
|
if(floating){
|
||||||
if(!root){
|
if(!root){
|
||||||
root = curr = _rjp__add_dfloat(NULL, strtod(str, NULL));
|
root = curr = _rjp__add_value(NULL, rjp_dfloat(strtod(str, NULL)));
|
||||||
}else{
|
}else{
|
||||||
_rjp__add_dfloat(curr, strtod(str, NULL));
|
_rjp__add_value(curr, rjp_dfloat(strtod(str, NULL)));
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
if(!root){
|
if(!root){
|
||||||
root = curr = _rjp__add_integer(NULL, strtol(str, NULL, 10));
|
root = curr = _rjp__add_value(NULL, rjp_integer(strtol(str, NULL, 10)));
|
||||||
}else{
|
}else{
|
||||||
_rjp__add_integer(curr, strtol(str, NULL, 10));
|
_rjp__add_value(curr, rjp_integer(strtol(str, NULL, 10)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
str += (numlen-1);
|
str += (numlen-1);
|
||||||
@ -381,28 +240,28 @@ RJP_value* rjp_parse(const char* str){
|
|||||||
else if(!strncmp(str, "true", 4)){
|
else if(!strncmp(str, "true", 4)){
|
||||||
if(!curr){
|
if(!curr){
|
||||||
*top = json_none;
|
*top = json_none;
|
||||||
root = curr = _rjp__add_boolean(curr, 1);
|
root = curr = _rjp__add_value(curr, rjp_boolean(1));
|
||||||
}else{
|
}else{
|
||||||
*top = json_comma;
|
*top = json_comma;
|
||||||
_rjp__add_boolean(curr, 1);
|
_rjp__add_value(curr, rjp_boolean(1));
|
||||||
}
|
}
|
||||||
str += 3;column += 3;
|
str += 3;column += 3;
|
||||||
}else if(!strncmp(str, "false", 5)){
|
}else if(!strncmp(str, "false", 5)){
|
||||||
if(!curr){
|
if(!curr){
|
||||||
*top = json_none;
|
*top = json_none;
|
||||||
root = curr = _rjp__add_boolean(curr, 0);
|
root = curr = _rjp__add_value(curr, rjp_boolean(0));
|
||||||
}else{
|
}else{
|
||||||
*top = json_comma;
|
*top = json_comma;
|
||||||
_rjp__add_boolean(curr, 0);
|
_rjp__add_value(curr, rjp_boolean(0));
|
||||||
}
|
}
|
||||||
str += 4;column += 4;
|
str += 4;column += 4;
|
||||||
}else if(!strncmp(str, "null", 4)){
|
}else if(!strncmp(str, "null", 4)){
|
||||||
if(!curr){
|
if(!curr){
|
||||||
*top = json_none;
|
*top = json_none;
|
||||||
root = curr = _rjp__add_null(curr);
|
root = curr = _rjp__add_value(curr, rjp_null());
|
||||||
}else{
|
}else{
|
||||||
*top = json_comma;
|
*top = json_comma;
|
||||||
_rjp__add_null(curr);
|
_rjp__add_value(curr, rjp_null());
|
||||||
}
|
}
|
||||||
str += 3;column += 3;
|
str += 3;column += 3;
|
||||||
}
|
}
|
||||||
|
|||||||
70
src/memory.c
70
src/memory.c
@ -1,3 +1,21 @@
|
|||||||
|
/**
|
||||||
|
rjp
|
||||||
|
Copyright (C) 2018 rexy712
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "rjp_internal.h"
|
#include "rjp_internal.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -13,13 +31,6 @@ void rjp_free(void* data){
|
|||||||
free(data);
|
free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _rjp__strcpy(RJP_string* dest, const RJP_string* src){
|
|
||||||
dest->value = rjp_alloc(src->length + 1);
|
|
||||||
strcpy(dest->value, src->value);
|
|
||||||
dest->value[src->length] = 0;
|
|
||||||
dest->length = src->length;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _rjp__copy_object(RJP_value* dest, const RJP_value* src){
|
static void _rjp__copy_object(RJP_value* dest, const RJP_value* src){
|
||||||
dest->object.members = dest->object.last = 0;
|
dest->object.members = dest->object.last = 0;
|
||||||
for(RJP_value* curr = rjp_get_member(src);curr;curr = rjp_next_member(curr)){
|
for(RJP_value* curr = rjp_get_member(src);curr;curr = rjp_next_member(curr)){
|
||||||
@ -63,3 +74,48 @@ void rjp_copy_value(RJP_value* dest, const RJP_value* src){
|
|||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _rjp__free_object_recurse(RJP_value* root);
|
||||||
|
static void _rjp__free_array(RJP_value* root){
|
||||||
|
RJP_array_element* arr = root->array.elements;
|
||||||
|
for(RJP_array_element* i = arr;i != NULL;i = arr){
|
||||||
|
arr = arr->next;
|
||||||
|
if(i->value.type == json_object){
|
||||||
|
_rjp__free_object_recurse(&i->value);
|
||||||
|
}else if(i->value.type == json_array){
|
||||||
|
_rjp__free_array(&i->value);
|
||||||
|
}else if(i->value.type == json_string){
|
||||||
|
free(i->value.string.value);
|
||||||
|
}
|
||||||
|
free(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Recursively free JSON objects
|
||||||
|
static void _rjp__free_object_recurse(RJP_value* root){
|
||||||
|
RJP_object_member* next;
|
||||||
|
for(RJP_object_member* m = root->object.members;m;m = next){
|
||||||
|
next = m->next;
|
||||||
|
if(m->value.type == json_object)
|
||||||
|
_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)
|
||||||
|
_rjp__free_array(&m->value);
|
||||||
|
if(m->name.value)
|
||||||
|
free(m->name.value);
|
||||||
|
free(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Same as recurse but also frees root node
|
||||||
|
void rjp_free_value(RJP_value* root){
|
||||||
|
if(!root)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if((root->type) == json_object)
|
||||||
|
_rjp__free_object_recurse(root);
|
||||||
|
else if((root->type) == json_array)
|
||||||
|
_rjp__free_array(root);
|
||||||
|
|
||||||
|
free(root);
|
||||||
|
}
|
||||||
|
|||||||
96
src/output.c
96
src/output.c
@ -18,9 +18,9 @@
|
|||||||
|
|
||||||
#include "rjp.h"
|
#include "rjp.h"
|
||||||
#include "rjp_internal.h"
|
#include "rjp_internal.h"
|
||||||
|
#include "memory.h"
|
||||||
|
|
||||||
#include <string.h> //strlen
|
#include <string.h> //strlen
|
||||||
#include <stdlib.h> //malloc, calloc, free
|
|
||||||
#include <stdio.h> //sprintf
|
#include <stdio.h> //sprintf
|
||||||
|
|
||||||
RJP_value* rjp_init_json(void){
|
RJP_value* rjp_init_json(void){
|
||||||
@ -32,100 +32,6 @@ RJP_value* rjp_init_json_as(RJP_value value){
|
|||||||
*ret = value;
|
*ret = value;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
RJP_value* rjp_add_member(RJP_value* dest, const char* key, size_t keylen, RJP_value value){
|
|
||||||
if(!keylen)
|
|
||||||
keylen = strlen(key);
|
|
||||||
_rjp__add_member(&dest->object, key, keylen);
|
|
||||||
dest->object.last->value = value;
|
|
||||||
dest->object.last->value.parent = dest;
|
|
||||||
return &dest->object.last->value;
|
|
||||||
}
|
|
||||||
RJP_value* rjp_add_member_no_alloc(RJP_value* dest, char* key, size_t keylen, RJP_value value){
|
|
||||||
if(!keylen)
|
|
||||||
keylen = strlen(key);
|
|
||||||
_rjp__add_member_no_alloc(&dest->object, key, keylen);
|
|
||||||
dest->object.last->value = value;
|
|
||||||
dest->object.last->value.parent = dest;
|
|
||||||
return &dest->object.last->value;
|
|
||||||
}
|
|
||||||
RJP_value* rjp_add_element(RJP_value* dest, RJP_value value){
|
|
||||||
_rjp__add_element(&dest->array);
|
|
||||||
dest->array.last->value = value;
|
|
||||||
dest->array.last->value.parent = dest;
|
|
||||||
return &dest->array.last->value;
|
|
||||||
}
|
|
||||||
void rjp_set_value(RJP_value* dest, RJP_value value){
|
|
||||||
struct RJP_value* p = dest->parent;
|
|
||||||
*dest = value;
|
|
||||||
dest->parent = p;
|
|
||||||
}
|
|
||||||
RJP_value rjp_integer(long i){
|
|
||||||
return (RJP_value){.integer = i, .type = json_integer};
|
|
||||||
}
|
|
||||||
RJP_value rjp_boolean(char b){
|
|
||||||
return (RJP_value){.boolean = b, .type = json_boolean};
|
|
||||||
}
|
|
||||||
RJP_value rjp_dfloat(double d){
|
|
||||||
return (RJP_value){.dfloat = d, .type = json_dfloat};
|
|
||||||
}
|
|
||||||
RJP_value rjp_string(char* c, size_t len){
|
|
||||||
return (RJP_value){.string = {.value = c, .length = len}, .type = json_string};
|
|
||||||
}
|
|
||||||
RJP_value rjp_null(void){
|
|
||||||
return (RJP_value){.integer = 0, .type = json_null};
|
|
||||||
}
|
|
||||||
RJP_value rjp_object(void){
|
|
||||||
return (RJP_value){.object = {0}, .type = json_object};
|
|
||||||
}
|
|
||||||
RJP_value rjp_array(void){
|
|
||||||
return (RJP_value){.array = {0}, .type = json_array};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
RJP_value* rjp_get_member(const RJP_value* object){
|
|
||||||
return &object->object.members->value;
|
|
||||||
}
|
|
||||||
RJP_value* rjp_next_member(const RJP_value* member){
|
|
||||||
//polymorphism
|
|
||||||
return (RJP_value*)(((RJP_object_member*)member)->next);
|
|
||||||
}
|
|
||||||
RJP_value* rjp_get_element(const RJP_value* array){
|
|
||||||
return &array->array.elements->value;
|
|
||||||
}
|
|
||||||
RJP_value* rjp_next_element(const RJP_value* element){
|
|
||||||
return (RJP_value*)(((RJP_array_element*)element)->next);
|
|
||||||
}
|
|
||||||
|
|
||||||
char* rjp_member_name(const RJP_value* member){
|
|
||||||
return ((RJP_object_member*)member)->name.value;
|
|
||||||
}
|
|
||||||
size_t rjp_member_name_length(RJP_value* member){
|
|
||||||
return ((RJP_object_member*)member)->name.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
RJP_value* rjp_value_parent(RJP_value* value){
|
|
||||||
return value->parent;
|
|
||||||
}
|
|
||||||
RJP_type rjp_value_type(RJP_value* value){
|
|
||||||
return value->type;
|
|
||||||
}
|
|
||||||
double rjp_value_dfloat(RJP_value* value){
|
|
||||||
return value->dfloat;
|
|
||||||
}
|
|
||||||
int rjp_value_integer(RJP_value* value){
|
|
||||||
return value->integer;
|
|
||||||
}
|
|
||||||
char rjp_value_boolean(RJP_value* value){
|
|
||||||
return value->boolean;
|
|
||||||
}
|
|
||||||
char* rjp_value_string(RJP_value* value){
|
|
||||||
return value->string.value;
|
|
||||||
}
|
|
||||||
size_t rjp_value_string_length(RJP_value* value){
|
|
||||||
return value->string.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static size_t _rjp__write_value(char* dest, RJP_value* val){
|
static size_t _rjp__write_value(char* dest, RJP_value* val){
|
||||||
size_t ret;
|
size_t ret;
|
||||||
|
|||||||
155
src/rjp.c
Normal file
155
src/rjp.c
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
/**
|
||||||
|
rjp
|
||||||
|
Copyright (C) 2018 rexy712
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "rjp_internal.h"
|
||||||
|
|
||||||
|
#include <string.h> //strncpy, strlen
|
||||||
|
|
||||||
|
void _rjp__add_element(RJP_array* j){
|
||||||
|
++j->num_elements;
|
||||||
|
if(!j->elements){
|
||||||
|
j->elements = rjp_calloc(1, sizeof(RJP_array_element));
|
||||||
|
j->last = j->elements;
|
||||||
|
}else{
|
||||||
|
j->last->next = rjp_calloc(1, sizeof(RJP_array_element));
|
||||||
|
j->last = j->last->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//create member of the object as a linked list member and assign a name with name allocation
|
||||||
|
void _rjp__add_member(RJP_object* j, const char* str, size_t len){
|
||||||
|
++j->num_members;
|
||||||
|
if(!j->members){
|
||||||
|
j->members = rjp_calloc(1, sizeof(RJP_object_member));
|
||||||
|
j->last = j->members;
|
||||||
|
}else{
|
||||||
|
j->last->next = rjp_calloc(1, sizeof(RJP_object_member));
|
||||||
|
j->last = j->last->next;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
void _rjp__add_member_no_alloc(RJP_object* j, char* str, size_t len){
|
||||||
|
++j->num_members;
|
||||||
|
if(!j->members){
|
||||||
|
j->members = rjp_calloc(1, sizeof(RJP_object_member));
|
||||||
|
j->last = j->members;
|
||||||
|
}else{
|
||||||
|
j->last->next = rjp_calloc(1, sizeof(RJP_object_member));
|
||||||
|
j->last = j->last->next;
|
||||||
|
}
|
||||||
|
j->last->name.value = str;
|
||||||
|
j->last->name.length = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
RJP_value* rjp_add_member(RJP_value* dest, const char* key, size_t keylen, RJP_value value){
|
||||||
|
if(!keylen)
|
||||||
|
keylen = strlen(key);
|
||||||
|
_rjp__add_member(&dest->object, key, keylen);
|
||||||
|
dest->object.last->value = value;
|
||||||
|
dest->object.last->value.parent = dest;
|
||||||
|
return &dest->object.last->value;
|
||||||
|
}
|
||||||
|
RJP_value* rjp_add_member_no_alloc(RJP_value* dest, char* key, size_t keylen, RJP_value value){
|
||||||
|
if(!keylen)
|
||||||
|
keylen = strlen(key);
|
||||||
|
_rjp__add_member_no_alloc(&dest->object, key, keylen);
|
||||||
|
dest->object.last->value = value;
|
||||||
|
dest->object.last->value.parent = dest;
|
||||||
|
return &dest->object.last->value;
|
||||||
|
}
|
||||||
|
RJP_value* rjp_add_element(RJP_value* dest, RJP_value value){
|
||||||
|
_rjp__add_element(&dest->array);
|
||||||
|
dest->array.last->value = value;
|
||||||
|
dest->array.last->value.parent = dest;
|
||||||
|
return &dest->array.last->value;
|
||||||
|
}
|
||||||
|
void rjp_set_value(RJP_value* dest, RJP_value value){
|
||||||
|
struct RJP_value* p = dest->parent;
|
||||||
|
*dest = value;
|
||||||
|
dest->parent = p;
|
||||||
|
}
|
||||||
|
RJP_value rjp_integer(long i){
|
||||||
|
return (RJP_value){.integer = i, .type = json_integer};
|
||||||
|
}
|
||||||
|
RJP_value rjp_boolean(char b){
|
||||||
|
return (RJP_value){.boolean = b, .type = json_boolean};
|
||||||
|
}
|
||||||
|
RJP_value rjp_dfloat(double d){
|
||||||
|
return (RJP_value){.dfloat = d, .type = json_dfloat};
|
||||||
|
}
|
||||||
|
RJP_value rjp_string(char* c, size_t len){
|
||||||
|
return (RJP_value){.string = {.value = c, .length = len}, .type = json_string};
|
||||||
|
}
|
||||||
|
RJP_value rjp_null(void){
|
||||||
|
return (RJP_value){.integer = 0, .type = json_null};
|
||||||
|
}
|
||||||
|
RJP_value rjp_object(void){
|
||||||
|
return (RJP_value){.object = {0}, .type = json_object};
|
||||||
|
}
|
||||||
|
RJP_value rjp_array(void){
|
||||||
|
return (RJP_value){.array = {0}, .type = json_array};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
RJP_value* rjp_get_member(const RJP_value* object){
|
||||||
|
return &object->object.members->value;
|
||||||
|
}
|
||||||
|
RJP_value* rjp_next_member(const RJP_value* member){
|
||||||
|
//polymorphism
|
||||||
|
return (RJP_value*)(((RJP_object_member*)member)->next);
|
||||||
|
}
|
||||||
|
RJP_value* rjp_get_element(const RJP_value* array){
|
||||||
|
return &array->array.elements->value;
|
||||||
|
}
|
||||||
|
RJP_value* rjp_next_element(const RJP_value* element){
|
||||||
|
return (RJP_value*)(((RJP_array_element*)element)->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* rjp_member_name(const RJP_value* member){
|
||||||
|
return ((RJP_object_member*)member)->name.value;
|
||||||
|
}
|
||||||
|
size_t rjp_member_name_length(RJP_value* member){
|
||||||
|
return ((RJP_object_member*)member)->name.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
RJP_value* rjp_value_parent(RJP_value* value){
|
||||||
|
return value->parent;
|
||||||
|
}
|
||||||
|
RJP_type rjp_value_type(RJP_value* value){
|
||||||
|
return value->type;
|
||||||
|
}
|
||||||
|
double rjp_value_dfloat(RJP_value* value){
|
||||||
|
return value->dfloat;
|
||||||
|
}
|
||||||
|
int rjp_value_integer(RJP_value* value){
|
||||||
|
return value->integer;
|
||||||
|
}
|
||||||
|
char rjp_value_boolean(RJP_value* value){
|
||||||
|
return value->boolean;
|
||||||
|
}
|
||||||
|
char* rjp_value_string(RJP_value* value){
|
||||||
|
return value->string.value;
|
||||||
|
}
|
||||||
|
size_t rjp_value_string_length(RJP_value* value){
|
||||||
|
return value->string.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -16,12 +16,18 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "rjp.h"
|
#include "strings.h"
|
||||||
#include "rjp_internal.h"
|
#include "rjp_internal.h"
|
||||||
|
|
||||||
#include <stdio.h> //fprintf
|
#include <stdio.h> //fprintf
|
||||||
#include <stdlib.h> //malloc, free
|
#include <stdlib.h> //malloc, free
|
||||||
#include <stdint.h>
|
#include <stdint.h> //uintN_t
|
||||||
|
#include <string.h> //strcpy
|
||||||
|
|
||||||
|
//Determine if the character is valid whitespace
|
||||||
|
int _rjp__is_whitespace(char c){
|
||||||
|
return c == ' ' || c == '\n' || c == '\r' || c == '\t';
|
||||||
|
}
|
||||||
|
|
||||||
static uint32_t utf_strtol_4(const char* c){
|
static uint32_t utf_strtol_4(const char* c){
|
||||||
uint32_t ret = 0;
|
uint32_t ret = 0;
|
||||||
@ -261,6 +267,13 @@ size_t rjp_escape_strcpy(char* dest, const char* src){
|
|||||||
dest[j] = 0;
|
dest[j] = 0;
|
||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
|
void _rjp__strcpy(RJP_string* dest, const RJP_string* src){
|
||||||
|
dest->value = rjp_alloc(src->length + 1);
|
||||||
|
strcpy(dest->value, src->value);
|
||||||
|
dest->value[src->length] = 0;
|
||||||
|
dest->length = src->length;
|
||||||
|
}
|
||||||
|
|
||||||
size_t rjp_escape_strlen(const char* str){
|
size_t rjp_escape_strlen(const char* str){
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
for(size_t i = 0;str[i];++i){
|
for(size_t i = 0;str[i];++i){
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user