Files

185 lines
4.0 KiB
C

#include <bshell/format.h>
#include <fx/collections/array.h>
#include <fx/string.h>
#include <fx/type.h>
#include <fx/value-type.h>
static void initialise_table(
struct bshell_value_writer *w,
const fx_value *first_record)
{
bshell_table_ctx_init(&w->w_table_ctx, w->w_dest);
const fx_type *ty = fx_type_get_by_id(first_record->v_type);
bshell_table_ctx_prepare_columns_from_format(&w->w_table_ctx, ty, NULL);
bshell_table_ctx_print_headers(&w->w_table_ctx);
w->w_table_initialised = true;
}
static size_t write_iterable(
struct bshell_value_writer *w,
const fx_value *value)
{
size_t written = 0;
fx_array *array = NULL;
fx_value_get_object(value, &array);
const fx_iterator *it = fx_iterator_begin(array);
fx_foreach(v, it)
{
written += bshell_value_writer_write(w, v);
}
fx_iterator_unref(it);
return written;
}
static bool string_has_trailing_newline(const char *s)
{
long len = strlen(s);
if (len == 0) {
return false;
}
return s[len - 1] == '\n';
}
static size_t write_control_char(struct bshell_value_writer *w, fx_wchar c)
{
bool oneline = (w->w_flags & BSHELL_VALUE_WRITER_ONELINE) != 0;
size_t written = 1;
switch (c) {
case '\n':
if (oneline) {
fx_stream_write_cstr(w->w_dest, "\\n", &written);
} else {
fx_stream_write_char(w->w_dest, '\n');
}
break;
case '\r':
fx_stream_write_cstr(w->w_dest, "\\r", NULL);
break;
case '\t':
fx_stream_write_cstr(w->w_dest, "\\t", NULL);
break;
case '\b':
fx_stream_write_cstr(w->w_dest, "\\b", NULL);
break;
default:
written = 0;
break;
}
return written;
}
static size_t write_string(struct bshell_value_writer *w, const fx_value *value)
{
const char *s = NULL;
size_t written = 0;
fx_value_get_cstr(value, &s);
bool trailing_newline = string_has_trailing_newline(s);
bool inhibit_newline
= (w->w_flags & BSHELL_VALUE_WRITER_NO_NEWLINE) != 0;
bool truncate = (w->w_flags & BSHELL_VALUE_WRITER_TRUNCATE) != 0;
for (written = 0; *s;) {
if (truncate && written == w->w_max_width - 1) {
fx_stream_write_char(w->w_dest, L'');
written++;
break;
}
fx_wchar c = fx_wchar_utf8_codepoint_decode(s);
unsigned int stride = fx_wchar_utf8_codepoint_size(c);
if (stride == 0) {
break;
}
if (!fx_wchar_is_graph(c)) {
written += write_control_char(w, c);
goto next;
}
char cs[5] = {0};
fx_wchar_utf8_codepoint_encode(c, cs);
size_t n = 0;
fx_stream_write_cstr(w->w_dest, cs, &n);
written += n;
next:
s += stride;
}
if (!trailing_newline && !inhibit_newline) {
fx_stream_write_char(w->w_dest, '\n');
written++;
}
return written;
}
static size_t write_value(struct bshell_value_writer *w, const fx_value *value)
{
const fx_type *ty = fx_type_get_by_id(value->v_type);
if (fx_value_is_type(value, FX_TYPE_STRING)
|| fx_value_is_type(value, FX_TYPE_CSTR)) {
return write_string(w, value);
}
if (fx_type_get_interface(ty, FX_TYPE_ITERABLE)) {
return write_iterable(w, value);
}
if (fx_type_is_value_type(value->v_type)) {
fx_stringstream_reset(w->w_tmp);
fx_value_to_string(value, w->w_tmp, NULL);
fx_stream_write_char(w->w_tmp, '\n');
size_t result = fx_stringstream_get_length(w->w_tmp);
fx_stream_write_cstr(
w->w_dest,
fx_stringstream_get_cstr(w->w_tmp),
NULL);
return result;
}
if (!w->w_table_initialised) {
initialise_table(w, value);
}
bshell_table_ctx_print_record(&w->w_table_ctx, value);
return 0;
}
void bshell_value_writer_init(
struct bshell_value_writer *w,
enum bshell_value_writer_flags flags,
size_t max_width,
fx_stream *dest)
{
memset(w, 0x00, sizeof *w);
w->w_dest = dest;
w->w_flags = flags;
w->w_max_width = max_width;
w->w_tmp = fx_stringstream_create();
}
size_t bshell_value_writer_write(
struct bshell_value_writer *w,
const fx_value *value)
{
return write_value(w, value);
}
void bshell_value_writer_cleanup(struct bshell_value_writer *w)
{
if (w->w_table_initialised) {
bshell_table_ctx_cleanup(&w->w_table_ctx);
}
fx_stringstream_unref(w->w_tmp);
w->w_table_initialised = false;
}