2026-06-13 13:46:29 +01:00
|
|
|
#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 void write_iterable(struct bshell_value_writer *w, const fx_value *value)
|
|
|
|
|
{
|
|
|
|
|
fx_array *array = NULL;
|
|
|
|
|
fx_value_get_object(value, &array);
|
|
|
|
|
|
|
|
|
|
const fx_iterator *it = fx_iterator_begin(array);
|
|
|
|
|
fx_foreach(v, it)
|
|
|
|
|
{
|
|
|
|
|
bshell_value_writer_write(w, v);
|
|
|
|
|
}
|
|
|
|
|
fx_iterator_unref(it);
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-14 19:40:27 +01:00
|
|
|
static bool string_has_trailing_newline(const char *s)
|
|
|
|
|
{
|
|
|
|
|
long len = strlen(s);
|
|
|
|
|
if (len == 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return s[len - 1] == '\n';
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-13 13:46:29 +01:00
|
|
|
static void write_string(struct bshell_value_writer *w, const fx_value *value)
|
|
|
|
|
{
|
|
|
|
|
const char *str = NULL;
|
|
|
|
|
fx_value_get_cstr(value, &str);
|
|
|
|
|
fx_stream_write_cstr(w->w_dest, str, NULL);
|
2026-06-14 19:40:27 +01:00
|
|
|
|
|
|
|
|
if (!string_has_trailing_newline(str)) {
|
|
|
|
|
fx_stream_write_char(w->w_dest, '\n');
|
|
|
|
|
}
|
2026-06-13 13:46:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void 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)) {
|
|
|
|
|
write_string(w, value);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fx_type_get_interface(ty, FX_TYPE_ITERABLE)) {
|
|
|
|
|
write_iterable(w, value);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fx_type_is_value_type(value->v_type)) {
|
|
|
|
|
fx_value_to_string(value, w->w_dest, NULL);
|
|
|
|
|
fx_stream_write_char(w->w_dest, '\n');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!w->w_table_initialised) {
|
|
|
|
|
initialise_table(w, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bshell_table_ctx_print_record(&w->w_table_ctx, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void bshell_value_writer_init(struct bshell_value_writer *w, fx_stream *dest)
|
|
|
|
|
{
|
|
|
|
|
memset(w, 0x00, sizeof *w);
|
|
|
|
|
w->w_dest = dest;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void bshell_value_writer_write(
|
|
|
|
|
struct bshell_value_writer *w,
|
|
|
|
|
const fx_value *value)
|
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
w->w_table_initialised = false;
|
|
|
|
|
}
|