Add stringify functionality
This commit is contained in:
parent
d1f9622cd2
commit
34171aa795
234
src/dump.c
Normal file
234
src/dump.c
Normal 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
193
src/stringify.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user