Add stringify functionality

This commit is contained in:
Gregory Lirent 2022-08-26 10:09:54 +03:00
parent d1f9622cd2
commit 34171aa795
2 changed files with 427 additions and 0 deletions

234
src/dump.c Normal file
View File

@ -0,0 +1,234 @@
/* This software is licensed by the MIT License, see LICENSE file */
/* Copyright © 2022 Gregory Lirent */
#include <stdlib.h>
#include "../modules/libcdsb/include/map.h"
#include "../modules/libcdsb/include/dict.h"
#include "../modules/libcdsb/include/list.h"
#include "../modules/libcdsb/include/array.h"
#include "../modules/libcdsb/include/set.h"
#include "../modules/libcdsb/modules/libunic/include.h"
#include "buffer.h"
typedef struct {
FILE* stream;
indent_t* indent;
size_t level;
bool first_el;
} data_t;
#define dict_callback (map_access_callback) libcjsonp_builtin_dict_callback
#define list_callback (list_access_callback)libcjsonp_builtin_list_callback
#define set_callback (vset_access_callback)libcjsonp_builtin_set_callback
#define write_indent libcjsonp_builtin_write_indent
#define write_and_wrap libcjsonp_builtin_write_and_wrap
#define write_iterable libcjsonp_builtin_write_iterable
#define write_value libcjsonp_builtin_write_value
#define write_char(x, v) fputc(v ,x)
#define write(x, v) fputs(v, x)
static int libcjsonp_builtin_dict_callback(const void* k, vtype kt, const void* v, vtype vt, data_t* data);
static int libcjsonp_builtin_list_callback(const void* v, ssize_t index, vtype vt, data_t* data);
static int libcjsonp_builtin_set_callback (const void* v, vtype vt, data_t* data);
/*#####################################################################################################################*/
static int libcjsonp_builtin_write_indent (FILE* x, indent_t* indent, size_t level) {
int ret = 0;
while (ret >= 0 && level--) ret = write(x, indent->indent);
return (ret < 0) ? ret : 0;
}
static int libcjsonp_builtin_write_iterable(FILE* x, const void* s, vtype t, indent_t* indent, size_t level) {
data_t data;
char bracket;
int ret;
data.stream = x;
data.indent = indent;
data.level = level + 1;
data.first_el = true;
switch (t) { default:
#ifndef NDEBUG
abort();
#endif
case VTYPE_DICT: ret = write_char(x, bracket = '{');
if (ret >= 0) ret = libcdsb_dict_foreach((void*)s, &data, dict_callback, false);
break;
case VTYPE_LIST: ret = write_char(x, bracket = '[');
if (ret >= 0) ret = libcdsb_list_foreach((void*)s, &data, list_callback, false);
break;
case VTYPE_ARRAY: ret = write_char(x, bracket = '[');
if (ret >= 0) ret = libcdsb_array_foreach((void*)s, &data, list_callback, false);
break;
case VTYPE_MAP: ret = write_char(x, bracket = '{');
if (ret >= 0) ret = libcdsb_map_foreach((void*)s, &data, dict_callback, RBFOREACH_INORDER, false);
break;
case VTYPE_SET: ret = write_char(x, bracket = '[');
if (ret >= 0) ret = libcdsb_vset_foreach((void*)s, &data, set_callback, RBFOREACH_INORDER, false);
break;
}
if (indent->nmemb) {
if (ret >= 0) ret = write_char (x, '\n');
if (ret >= 0) ret = write_indent(x, indent, level);
}
if (ret >= 0) ret = write_char (x, bracket + 2);
return (ret < 0) ? ret : 0;
}
static int libcjsonp_builtin_write_and_wrap(FILE* x, const char* v) {
char s[7] = { '\\', 'u', '0', '0', 0, 0, 0 };
int ret = write_char(x, '"');
while (ret >= 0 && *v) {
if (*v <= 0x20 || *v == 0x7f) switch (*v) {
case 0x09 : ret = write(x, "\\t"); break;
case 0x0a : ret = write(x, "\\n"); break;
case 0x0d : ret = write(x, "\\r"); break;
default : if ((*v&0xf0) < 0xa0) {
s[4] = 0x30 + (*v>>4);
} else s[4] = 0x57 + (*v>>4);
if ((*v&0x0f) < 0x0a) {
s[5] = 0x30 + (*v&0x0f);
} else s[5] = 0x57 + (*v&0x0f);
ret = write(x, s);
break;
} else if (*v == '\\') ret = write(x, "\\\\");
else if (*v == '"') ret = write(x, "\\\"");
else ret = write_char(x, *v);
++v;
}
if (ret >= 0) ret = write_char(x, '"');
return (ret < 0) ? ret : 0;
}
static int libcjsonp_builtin_write_value (FILE* x, const void* v, vtype t, indent_t* indent, size_t level) {
if (t < VTYPE_STRING) return write(x, libcdsb_vtype_stringify(v, t));
else if (t > VTYPE_STRING) return write_iterable(x, v, t, indent, level);
else return write_and_wrap(x, *(void**)v);
}
/*#####################################################################################################################*/
static int libcjsonp_builtin_dict_callback(const void* k, vtype kt, const void* v, vtype vt, data_t* data) {
void* key = 0;
int ret = 0;
if (!data->first_el) {
ret = write_char(data->stream, ',');
} else data->first_el = false;
if (data->indent->nmemb) {
if (ret >= 0) ret = write_char (data->stream, '\n');
if (ret >= 0) ret = write_indent(data->stream, data->indent, data->level);
}
if (kt > VTYPE_STRING) {
key = libcjsonp_json_stringify(k, kt, 0, 0).buffer;
k = key;
} else k = (kt < VTYPE_STRING) ? libcdsb_vtype_stringify(k, kt) : *(void**)k;
if (ret >= 0) ret = write_and_wrap(data->stream, k);
if (ret >= 0) ret = write_char (data->stream, ':');
libcdsb_free(key);
if (data->indent->nmemb && ret >= 0) {
write_char(data->stream, ' ');
}
if (ret >= 0) ret = write_value(data->stream, v, vt, data->indent, data->level);
return (ret < 0) ? ret : 0;
}
static int libcjsonp_builtin_list_callback(const void* v, ssize_t index, vtype vt, data_t* data) {
int ret = 0;
if (!data->first_el) {
ret = write_char(data->stream, ',');
} else data->first_el = false;
if (data->indent->nmemb) {
if (ret >= 0) ret = write_char (data->stream, '\n');
if (ret >= 0) ret = write_indent(data->stream, data->indent, data->level);
}
if (ret >= 0) ret = write_value(data->stream, v, vt, data->indent, data->level);
return (ret < 0) ? ret : 0;
}
static int libcjsonp_builtin_set_callback (const void* v, vtype vt, data_t* data) {
int ret = 0;
if (!data->first_el) {
ret = write_char(data->stream, ',');
} else data->first_el = false;
if (data->indent->nmemb) {
if (ret >= 0) ret = write_char (data->stream, '\n');
if (ret >= 0) ret = write_indent(data->stream, data->indent, data->level);
}
if (ret >= 0) ret = write_value(data->stream, v, vt, data->indent, data->level);
return (ret < 0) ? ret : 0;
}
/*#####################################################################################################################*/
bool libcjsonp_json_dump(FILE* x, const void* v, vtype t, size_t n, int c) {
int ret;
indent_t indent;
if (t < VTYPE_STRING) {
return write(x, libcdsb_vtype_stringify(v, t)) >= 0;
} else if (t == VTYPE_STRING) {
return write_and_wrap(x, *(char**)v) >= 0;
} else if (n) {
char *ptr, chr[4];
if (!c || !(ptr = tochar_unicode(chr, c))) {
*chr = ' ';
ptr = chr + 1;
}
indent.nmemb = ptr - chr;
indent.indent = libcdsb_malloc(n * indent.nmemb);
ptr = indent.indent;
while (n--) {
memcpy(ptr, chr, indent.nmemb);
ptr += indent.nmemb;
}
} else indent = *LIBCJSONP_BUILTIN_WITHOUT_INDENT;
ret = write_iterable(x, v, t, &indent, 0);
libcdsb_free(indent.indent);
return ret >= 0;
}

193
src/stringify.c Normal file
View File

@ -0,0 +1,193 @@
/* This software is licensed by the MIT License, see LICENSE file */
/* Copyright © 2022 Gregory Lirent */
#include <string.h>
#include <stdlib.h>
#include "../modules/libcdsb/include/map.h"
#include "../modules/libcdsb/include/dict.h"
#include "../modules/libcdsb/include/list.h"
#include "../modules/libcdsb/include/array.h"
#include "../modules/libcdsb/include/set.h"
#include "../modules/libcdsb/modules/libunic/include.h"
#include "buffer.h"
typedef struct {
buffer_t* buffer;
indent_t* indent;
size_t level;
} data_t;
#define dict_callback (map_access_callback) libcjsonp_builtin_dict_callback
#define list_callback (list_access_callback)libcjsonp_builtin_list_callback
#define set_callback (vset_access_callback)libcjsonp_builtin_set_callback
#define write_indent buffer_write_indent
#define write_and_wrap buffer_write_and_wrap
#define write_iterable libcjsonp_builtin_write_iterable
#define write_value libcjsonp_builtin_write_value
#define write_char buffer_write_char
#define write buffer_write
static int libcjsonp_builtin_dict_callback(const void* k, vtype kt, const void* v, vtype vt, data_t* data);
static int libcjsonp_builtin_list_callback(const void* v, ssize_t index, vtype vt, data_t* data);
static int libcjsonp_builtin_set_callback (const void* v, vtype vt, data_t* data);
/*#####################################################################################################################*/
static void libcjsonp_builtin_write_iterable(buffer_t* x, const void* s, vtype t, indent_t* indent, size_t level) {
data_t data;
char* ptr;
char bracket;
data.buffer = x;
data.indent = indent;
data.level = level + 1;
buffer_check_size(x, 1);
ptr = x->ptr + 1;
--x->c;
switch (t) { default:
#ifndef NDEBUG
abort();
#endif
case VTYPE_DICT: *(x->ptr++) = bracket = '{';
libcdsb_dict_foreach((void*)s, &data, dict_callback, false);
break;
case VTYPE_LIST: *(x->ptr++) = bracket = '[';
libcdsb_list_foreach((void*)s, &data, list_callback, false);
break;
case VTYPE_ARRAY: *(x->ptr++) = bracket = '[';
libcdsb_array_foreach((void*)s, &data, list_callback, false);
break;
case VTYPE_MAP: *(x->ptr++) = bracket = '{';
libcdsb_map_foreach((void*)s, &data, dict_callback, RBFOREACH_INORDER, false);
break;
case VTYPE_SET: *(x->ptr++) = bracket = '[';
libcdsb_vset_foreach((void*)s, &data, set_callback, RBFOREACH_INORDER, false);
break;
}
if (ptr == x->ptr) {
write_char(x, bracket + 2);
} else if (indent->nmemb) {
(x->ptr)[-1] = '\n';
write_indent(x, indent, level);
write_char(x, bracket + 2);
} else x->ptr[-1] = bracket + 2;
}
static void libcjsonp_builtin_write_value(buffer_t* x, const void* v, vtype t, indent_t* indent, size_t level) {
if (t < VTYPE_STRING) write(x, libcdsb_vtype_stringify(v, t));
else if (t > VTYPE_STRING) write_iterable(x, v, t, indent, level);
else write_and_wrap(x, *(void**)v);
write_char(x, ',');
}
/*#####################################################################################################################*/
static int libcjsonp_builtin_dict_callback(const void* k, vtype kt, const void* v, vtype vt, data_t* data) {
buffer_t key;
memset(&key, 0, sizeof(key));
if (data->indent->nmemb) {
write_char (data->buffer, '\n');
write_indent(data->buffer, data->indent, data->level);
}
if (kt > VTYPE_STRING) {
write_iterable(&key, k, kt, LIBCJSONP_BUILTIN_WITHOUT_INDENT, 0);
write_char (&key, 0);
k = key.mem;
} else k = (kt < VTYPE_STRING) ? libcdsb_vtype_stringify(k, kt) : *(void**)k;
write_and_wrap(data->buffer, k);
write_char (data->buffer, ':');
libcdsb_free (key.mem);
if (data->indent->nmemb) {
write_char(data->buffer, ' ');
}
write_value(data->buffer, v, vt, data->indent, data->level);
return 0;
}
static int libcjsonp_builtin_set_callback (const void* v, vtype vt, data_t* data) {
if (data->indent->nmemb) {
write_char (data->buffer, '\n');
write_indent(data->buffer, data->indent, data->level);
}
write_value(data->buffer, v, vt, data->indent, data->level);
return 0;
}
static int libcjsonp_builtin_list_callback(const void* v, ssize_t index, vtype vt, data_t* data) {
if (data->indent->nmemb) {
write_char (data->buffer, '\n');
write_indent(data->buffer, data->indent, data->level);
}
write_value(data->buffer, v, vt, data->indent, data->level);
return 0;
}
/*#####################################################################################################################*/
vtype_string libcjsonp_json_stringify(const void* v, vtype t, size_t n, int c) {
buffer_t buffer;
indent_t indent;
if (t < VTYPE_STRING) {
v = libcdsb_strdup(libcdsb_vtype_stringify(v, t));
return *(vtype_string*)&v;
}
memset(&buffer, 0, sizeof(buffer));
if (t == VTYPE_STRING) {
write_and_wrap(&buffer, *(char**)v);
write_char (&buffer, 0);
return *(vtype_string*)&buffer;
} else if (n) {
char *ptr, chr[4];
if (!c || !(ptr = tochar_unicode(chr, c))) {
*chr = ' ';
ptr = chr + 1;
}
indent.nmemb = ptr - chr;
indent.indent = malloc(n * indent.nmemb);
ptr = indent.indent;
for (size_t i = 0; i < n; ++i) {
memcpy(ptr, chr, indent.nmemb);
ptr += indent.nmemb;
}
indent.nmemb *= n;
} else indent = *LIBCJSONP_BUILTIN_WITHOUT_INDENT;
write_iterable(&buffer, v, t, &indent, 0);
write_char (&buffer, 0);
free(indent.indent);
return *(vtype_string*)&buffer;
}