rjp/src/output.c

194 lines
5.1 KiB
C

/**
rjp
Copyright (C) 2018-2019 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/>.
*/
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include "rjp.h"
#include "rjp_internal.h"
#include "memory.h"
#include "strings.h"
#include <string.h> //strlen
#include <stdio.h> //sprintf
RJP_value* rjp_init_json(void){
RJP_value* ret = rjp_calloc(1, sizeof(RJP_value));
return ret;
}
RJP_value* rjp_init_json_as(RJP_value value){
RJP_value* ret = rjp_alloc(sizeof(RJP_value));
*ret = value;
return ret;
}
static size_t irjp_write_value(char* dest, const RJP_value* val){
size_t ret;
switch(val->type){
case rjp_json_integer:
ret = sprintf(dest, "%" PRId64, val->integer);
break;
case rjp_json_dfloat:
ret = sprintf(dest, "%lf", val->dfloat);
break;
case rjp_json_boolean:
ret = sprintf(dest, val->boolean ? "true" : "false");
break;
case rjp_json_null:
ret = sprintf(dest, "null");
break;
case rjp_json_string:;
ret = sprintf(dest, "\"%s\"", val->string.value);
break;
case rjp_json_array:
ret = rjp_dump_array(val, dest);
break;
case rjp_json_object:
ret = rjp_dump_object(val, dest);
break;
default:
ret = 0;
break;
};
return ret;
}
static size_t irjp_write_value_pretty(char* dest, const RJP_value* val, int depth);
static size_t irjp_dump_array_pretty(const RJP_value* arr, char* dest, int depth){
const RJP_array* array = &arr->array;
const RJP_array_element* element_list = array->elements;
size_t pos = 2;
sprintf(dest, "[\n");
for(;element_list;element_list = element_list->next){
for(int i = 0;i < (depth+1);++i)
pos += sprintf(dest+pos, "\t");
pos += irjp_write_value_pretty(dest+pos, &element_list->value, depth+1);
if(element_list->next)
pos += sprintf(dest+pos, ",");
pos += sprintf(dest+pos, "\n");
}
for(int i = 0;i < depth;++i)
pos += sprintf(dest+pos, "\t");
pos += sprintf(dest+pos, "]");
return pos;
}
static size_t irjp_dump_object_pretty(const RJP_value* root, char* dest, int depth){
const RJP_object* root_obj = &root->object;
const RJP_object_member* member_list = root_obj->members;
size_t pos = 2;
sprintf(dest, "{\n");
for(;member_list;member_list = member_list->next){
for(int i = 0;i < (depth+1);++i)
pos += sprintf(dest+pos, "\t");
pos += sprintf(dest+pos, "\"%s\": ", member_list->name.value);
pos += irjp_write_value_pretty(dest+pos, &member_list->value, depth+1);
if(member_list->next)
pos += sprintf(dest+pos, ",");
pos += sprintf(dest+pos, "\n");
}
for(int i = 0;i < depth;++i)
pos += sprintf(dest+pos, "\t");
pos += sprintf(dest+pos, "}");
return pos;
}
static size_t irjp_write_value_pretty(char* dest, const RJP_value* val, int depth){
size_t ret;
switch(val->type){
case rjp_json_integer:
ret = sprintf(dest, "%" PRId64, val->integer);
break;
case rjp_json_dfloat:
ret = sprintf(dest, "%lf", val->dfloat);
break;
case rjp_json_boolean:
ret = sprintf(dest, val->boolean ? "true" : "false");
break;
case rjp_json_null:
ret = sprintf(dest, "null");
break;
case rjp_json_string:;
ret = sprintf(dest, "\"%s\"", val->string.value);
break;
case rjp_json_array:
ret = irjp_dump_array_pretty(val, dest, depth);
break;
case rjp_json_object:
ret = irjp_dump_object_pretty(val, dest, depth);
break;
default:
ret = 0;
break;
};
return ret;
}
size_t rjp_dump_array(const RJP_value* arr, char* dest){
const RJP_array* array = &arr->array;
const RJP_array_element* element_list = array->elements;
size_t pos = 1;
sprintf(dest, "[");
for(;element_list;element_list = element_list->next){
pos += irjp_write_value(dest+pos, &element_list->value);
if(element_list->next)
pos += sprintf(dest+pos, ",");
else
break;
}
pos += sprintf(dest+pos, "]");
return pos;
}
size_t rjp_dump_object(const RJP_value* root, char* dest){
const RJP_object* root_obj = &root->object;
const RJP_object_member* member_list = root_obj->members;
size_t pos = 1;
sprintf(dest, "{");
for(;member_list;member_list = member_list->next){
pos += sprintf(dest+pos, "\"%s\":", member_list->name.value);
pos += irjp_write_value(dest+pos, &member_list->value);
if(member_list->next)
pos += sprintf(dest+pos, ",");
else
break;
}
pos += sprintf(dest+pos, "}");
return pos;
}
char* rjp_to_json(const RJP_value* root, int pretty){
if(!root)
return NULL;
size_t len = pretty ? irjp_value_strlen_pretty(root, 0) : irjp_value_strlen(root);
if(!len)
return NULL;
char* tmp = rjp_alloc(len + 1);
tmp[len] = 0;
if(pretty)
irjp_write_value_pretty(tmp, root, 0);
else
irjp_write_value(tmp, root);
return tmp;
}