diff --git a/object/array.c b/object/array.c index 1fea953..b8cf20c 100644 --- a/object/array.c +++ b/object/array.c @@ -1,12 +1,14 @@ #include "array.h" #include +#include #include #include #include #include static void array_release(struct b_object *obj); +static void array_to_string(struct b_object *obj, struct b_stream *out); static struct b_object_type array_type = { .t_flags = B_OBJECT_FUNDAMENTAL, @@ -14,6 +16,7 @@ static struct b_object_type array_type = { .t_name = "corelib::array", .t_instance_size = sizeof(struct b_array), .t_release = array_release, + .t_to_string = array_to_string, }; struct b_array *b_array_create(void) @@ -218,7 +221,47 @@ size_t b_array_capacity(const struct b_array *array) return array->ar_cap; } -void array_release(struct b_object *obj) +static void array_to_string(struct b_object *obj, struct b_stream *out) +{ + struct b_array *array = B_ARRAY(obj); + + if (!array->ar_len) { + b_stream_write_string(out, "[]", NULL); + return; + } + + b_stream_write_string(out, "[\n", NULL); + + b_stream_push_indent(out, 1); + size_t len = b_array_size(array); + + b_array_iterator it; + b_array_foreach(&it, array) + { + bool is_string = b_typeid(it.value) == B_OBJECT_TYPE_STRING; + + if (is_string) { + b_stream_write_char(out, '"'); + } + + b_to_string(it.value, out); + + if (is_string) { + b_stream_write_char(out, '"'); + } + + if (it.i < len - 1) { + b_stream_write_string(out, ",", NULL); + } + + b_stream_write_char(out, '\n'); + } + + b_stream_pop_indent(out); + b_stream_write_char(out, ']'); +} + +static void array_release(struct b_object *obj) { struct b_array *array = B_ARRAY(obj); diff --git a/object/array.h b/object/array.h index 1236e45..028fe2a 100644 --- a/object/array.h +++ b/object/array.h @@ -4,12 +4,12 @@ #include "../object.h" struct b_array { - struct b_object ar_base; - /* number of items in array */ - unsigned int ar_len; - /* maximum number of items that can currently be stored in array */ - unsigned int ar_cap; - struct b_object **ar_data; + struct b_object ar_base; + /* number of items in array */ + unsigned int ar_len; + /* maximum number of items that can currently be stored in array */ + unsigned int ar_cap; + struct b_object **ar_data; }; #endif diff --git a/object/dict.c b/object/dict.c index 5953c18..c6711ea 100644 --- a/object/dict.c +++ b/object/dict.c @@ -1,7 +1,7 @@ #include "dict.h" #include -#include +#include #include #include #include @@ -24,7 +24,7 @@ uint64_t b_cstr_hash(const char *s) } static void dict_release(struct b_object *obj); -static void dict_to_string(struct b_object *obj, struct b_stringstream *out); +static void dict_to_string(struct b_object *obj, struct b_stream *out); static struct b_object_type dict_type = { .t_name = "corelib::dict", @@ -186,35 +186,46 @@ bool b_dict_is_empty(const b_dict *dict) return false; } -static void dict_to_string(struct b_object *obj, struct b_stringstream *out) +static void dict_to_string(struct b_object *obj, struct b_stream *out) { struct b_dict *dict = B_DICT(obj); if (b_dict_is_empty(dict)) { - b_stringstream_add(out, "{}"); + b_stream_write_string(out, "{}", NULL); return; } - b_stringstream_add(out, "{\n"); + b_stream_write_string(out, "{\n", NULL); - b_stringstream_push_indent(out, 1); + b_stream_push_indent(out, 1); size_t len = b_dict_get_size(dict); b_dict_iterator it; b_dict_foreach(&it, dict) { - b_stringstream_addf(out, "%s: ", it.key); - b_to_string(it.value, out); + b_stream_write_fmt(out, NULL, "%s: ", it.key); - if (it.i < len - 1) { - b_stringstream_add(out, ","); + bool is_string = b_typeid(it.value) == B_OBJECT_TYPE_STRING; + + if (is_string) { + b_stream_write_char(out, '"'); } - b_stringstream_add(out, "\n"); + b_to_string(it.value, out); + + if (is_string) { + b_stream_write_char(out, '"'); + } + + if (it.i < len - 1) { + b_stream_write_string(out, ",", NULL); + } + + b_stream_write_char(out, '\n'); } - b_stringstream_pop_indent(out); - b_stringstream_add(out, "}"); + b_stream_pop_indent(out); + b_stream_write_char(out, '}'); } static bool dict_iterator_next(struct b_iterator *it) diff --git a/object/include/blue/object/object.h b/object/include/blue/object/object.h index dac24ed..5632be9 100644 --- a/object/include/blue/object/object.h +++ b/object/include/blue/object/object.h @@ -12,7 +12,7 @@ #define B_RVT(t, p) ((t *)(b_make_rvalue(B_OBJECT(p)))) struct b_string; -struct b_stringstream; +struct b_stream; typedef enum b_comparison_result { B_LESS = -1, @@ -30,7 +30,7 @@ BLUE_API b_object *b_make_rvalue(b_object *obj); BLUE_API b_object *b_retain(b_object *obj); BLUE_API void b_release(b_object *obj); -BLUE_API void b_to_string(b_object *obj, struct b_stringstream *out); +BLUE_API void b_to_string(b_object *obj, struct b_stream *out); BLUE_API b_object_type_id b_typeid(const b_object *obj); BLUE_API b_comparison_result_t b_compare(const b_object *a, const b_object *b); diff --git a/object/include/blue/object/string.h b/object/include/blue/object/string.h index 9c23086..fe83bda 100644 --- a/object/include/blue/object/string.h +++ b/object/include/blue/object/string.h @@ -5,6 +5,8 @@ #include #include +struct b_stream; + #define B_STRING(p) ((b_string *)(p)) #define B_CSTR(s) (b_string_create_from_cstr(s)) @@ -33,6 +35,7 @@ static inline void b_string_release(b_string *str) BLUE_API char *b_string_steal(b_string *str); BLUE_API b_status b_string_reserve(b_string *str, size_t capacity); BLUE_API b_status b_string_replace_all(b_string *str, const char *new_data); +BLUE_API b_status b_string_open_stream(b_string *str, struct b_stream **out); BLUE_API void b_string_append_s(b_string *dest, const b_string *src); BLUE_API void b_string_append_cstr(b_string *dest, const char *src); diff --git a/object/include/blue/object/type.h b/object/include/blue/object/type.h index 0b35340..b45c200 100644 --- a/object/include/blue/object/type.h +++ b/object/include/blue/object/type.h @@ -10,7 +10,7 @@ #define B_NPOS ((size_t)INTPTR_MAX) struct b_object; -struct b_stringstream; +struct b_stream; typedef uintptr_t b_object_type_id; @@ -44,7 +44,7 @@ typedef struct b_object_type { b_queue_entry t_entry; void (*t_init)(struct b_object *); void (*t_release)(struct b_object *); - void (*t_to_string)(struct b_object *, struct b_stringstream *); + void (*t_to_string)(struct b_object *, struct b_stream *); } b_object_type; BLUE_API b_status b_object_type_register(b_object_type *type); diff --git a/object/number.c b/object/number.c index 134e9b9..ca18f6c 100644 --- a/object/number.c +++ b/object/number.c @@ -1,6 +1,6 @@ #include "number.h" -#include +#include #include #include #include @@ -10,7 +10,7 @@ typedef int (*number_converter_t)(const struct b_number *, void *); static number_converter_t converters[B_NUMBER_TYPE_COUNT][B_NUMBER_TYPE_COUNT]; -static void number_to_string(struct b_object *obj, struct b_stringstream *out); +static void number_to_string(struct b_object *obj, struct b_stream *out); static struct b_object_type number_type = { .t_name = "corelib::number", @@ -175,55 +175,55 @@ size_t b_number_data_size(const struct b_number *number) } } -static void number_to_string(struct b_object *obj, struct b_stringstream *out) +static void number_to_string(struct b_object *obj, struct b_stream *out) { struct b_number *number = B_NUMBER(obj); switch (number->n_type) { case B_NUMBER_INT8: - b_stringstream_addf(out, "%" PRIu8, number->n_value.v_int8); + b_stream_write_fmt(out, NULL, "%" PRIu8, number->n_value.v_int8); break; case B_NUMBER_INT16: - b_stringstream_addf(out, "%" PRIu16, number->n_value.v_int16); + b_stream_write_fmt(out, NULL, "%" PRIu16, number->n_value.v_int16); break; case B_NUMBER_INT32: - b_stringstream_addf(out, "%" PRIu32, number->n_value.v_int32); + b_stream_write_fmt(out, NULL, "%" PRIu32, number->n_value.v_int32); break; case B_NUMBER_INT64: - b_stringstream_addf(out, "%" PRIu64, number->n_value.v_int64); + b_stream_write_fmt(out, NULL, "%" PRIu64, number->n_value.v_int64); break; case B_NUMBER_FLOAT32: - b_stringstream_addf(out, "%f", number->n_value.v_float32); + b_stream_write_fmt(out, NULL, "%f", number->n_value.v_float32); break; case B_NUMBER_FLOAT64: - b_stringstream_addf(out, "%lf", number->n_value.v_float64); + b_stream_write_fmt(out, NULL, "%lf", number->n_value.v_float64); break; case B_NUMBER_CHAR: - b_stringstream_addf(out, "%d", number->n_value.v_char); + b_stream_write_fmt(out, NULL, "%d", number->n_value.v_char); break; case B_NUMBER_SHORT: - b_stringstream_addf(out, "%d", number->n_value.v_short); + b_stream_write_fmt(out, NULL, "%d", number->n_value.v_short); break; case B_NUMBER_INT: - b_stringstream_addf(out, "%d", number->n_value.v_int); + b_stream_write_fmt(out, NULL, "%d", number->n_value.v_int); break; case B_NUMBER_LONG: - b_stringstream_addf(out, "%ld", number->n_value.v_long); + b_stream_write_fmt(out, NULL, "%ld", number->n_value.v_long); break; case B_NUMBER_LONGLONG: - b_stringstream_addf(out, "%lld", number->n_value.v_longlong); + b_stream_write_fmt(out, NULL, "%lld", number->n_value.v_longlong); break; case B_NUMBER_FLOAT: - b_stringstream_addf(out, "%f", number->n_value.v_float); + b_stream_write_fmt(out, NULL, "%f", number->n_value.v_float); break; case B_NUMBER_DOUBLE: - b_stringstream_addf(out, "%lf", number->n_value.v_double); + b_stream_write_fmt(out, NULL, "%lf", number->n_value.v_double); break; case B_NUMBER_SIZE_T: - b_stringstream_addf(out, "%zu", number->n_value.v_size_t); + b_stream_write_fmt(out, NULL, "%zu", number->n_value.v_size_t); break; case B_NUMBER_HANDLE: - b_stringstream_addf( - out, "%016" PRIx64, number->n_value.v_size_t); + b_stream_write_fmt( + out, NULL, "%016" PRIx64, number->n_value.v_size_t); break; default: break; diff --git a/object/object.c b/object/object.c index e00a288..812e9c4 100644 --- a/object/object.c +++ b/object/object.c @@ -1,10 +1,11 @@ #include "object.h" + +#include #include -#include #include -#include -#include +#include #include +#include void b_object_init(struct b_object *obj, struct b_object_type *type) { @@ -40,7 +41,7 @@ void b_release(struct b_object *obj) free(obj); } -void b_to_string(struct b_object *obj, struct b_stringstream *out) +void b_to_string(struct b_object *obj, struct b_stream *out) { if (obj->ob_type->t_to_string) { obj->ob_type->t_to_string(obj, out); @@ -52,7 +53,7 @@ void b_to_string(struct b_object *obj, struct b_stringstream *out) name = obj->ob_type->t_name; } - b_stringstream_addf(out, "<%s@%p>", name, obj); + b_stream_write_fmt(out, NULL, "<%s@%p>", name, obj); } b_object_type_id b_typeid(const struct b_object *obj) diff --git a/object/string.c b/object/string.c index e1ab6e0..8d41f0f 100644 --- a/object/string.c +++ b/object/string.c @@ -1,5 +1,6 @@ #include "string.h" +#include #include #include #include @@ -11,7 +12,7 @@ #include static void string_release(struct b_object *obj); -static void string_to_string(struct b_object *obj, struct b_stringstream *out); +static void string_to_string(struct b_object *obj, struct b_stream *out); static struct b_object_type string_type = { .t_name = "corelib::string", @@ -176,6 +177,7 @@ char *b_string_steal(struct b_string *str) if (string_is_inline(str)) { dest = b_strdup(src); + src[0] = 0; } else { dest = src; str->s_data.d_external = NULL; @@ -209,6 +211,132 @@ b_status b_string_replace_all(b_string *str, const char *new_data) return B_SUCCESS; } +enum b_status stream_close(struct b_stream *stream) +{ + struct b_string *str = stream->s_ptr; + b_string_release(str); + + return B_SUCCESS; +} + +enum b_status stream_getc(struct b_stream *stream, int *out) +{ + struct b_string *str = stream->s_ptr; + if (stream->s_cursor >= str->s_len) { + return B_ERR_NO_DATA; + } + + char *s = string_ptr(str); + *out = s[stream->s_cursor]; + stream->s_cursor++; + + return B_SUCCESS; +} + +enum b_status stream_read( + struct b_stream *stream, unsigned char *buf, size_t count, size_t *nr_read) +{ + struct b_string *str = stream->s_ptr; + if (stream->s_cursor >= str->s_len) { + *nr_read = 0; + return B_SUCCESS; + } + + size_t available = str->s_len - stream->s_cursor; + size_t to_read = b_min(size_t, count, available); + + char *s = string_ptr(str) + stream->s_cursor; + + memcpy(buf, s, to_read); + + *nr_read = to_read; + + return B_SUCCESS; +} + +enum b_status stream_write( + struct b_stream *stream, const unsigned char *buf, size_t count, + size_t *nr_written) +{ + struct b_string *str = stream->s_ptr; + enum b_status status = B_SUCCESS; + + if (stream->s_cursor + count > str->s_max) { + status = b_string_reserve(str, stream->s_cursor + count); + } + + if (!B_OK(status)) { + return status; + } + + char *s = string_ptr(str) + stream->s_cursor; + memcpy(s, buf, count); + s[str->s_max] = '\0'; + stream->s_cursor += count; + str->s_len = b_max(size_t, str->s_len, stream->s_cursor + count); + + *nr_written = count; + + return B_SUCCESS; +} + +enum b_status stream_seek( + struct b_stream *stream, long long offset, b_stream_seek_origin origin) +{ + struct b_string *str = stream->s_ptr; + + size_t abs_offset; + switch (origin) { + case B_STREAM_SEEK_START: + abs_offset = offset; + break; + case B_STREAM_SEEK_CURRENT: + abs_offset = stream->s_cursor + offset; + break; + case B_STREAM_SEEK_END: + abs_offset = str->s_len + offset; + break; + default: + return B_ERR_INVALID_ARGUMENT; + } + + stream->s_cursor = abs_offset; + + return B_SUCCESS; +} + +enum b_status stream_reserve(struct b_stream *stream, size_t len) +{ + struct b_string *str = stream->s_ptr; + + size_t new_capacity = str->s_len + len; + return b_string_reserve(str, new_capacity); +} + +enum b_status b_string_open_stream(struct b_string *str, struct b_stream **out) +{ + struct b_stream *stream = malloc(sizeof *stream); + if (!stream) { + return B_ERR_NO_MEMORY; + } + + memset(stream, 0x0, sizeof *stream); + + stream->s_mode |= B_STREAM_READ | B_STREAM_WRITE; + + stream->s_ptr = b_string_retain(str); + stream->s_close = stream_close; + stream->s_getc = stream_getc; + stream->s_read = stream_read; + stream->s_write = stream_write; + stream->s_seek = stream_seek; + stream->s_reserve = stream_reserve; + + *out = stream; + + return B_SUCCESS; +} + static void string_insert( struct b_string *dest, const char *src, size_t len, size_t at) { @@ -395,10 +523,10 @@ static void string_release(struct b_object *obj) } } -static void string_to_string(struct b_object *obj, struct b_stringstream *out) +static void string_to_string(struct b_object *obj, struct b_stream *out) { b_string *str = B_STRING(obj); - b_stringstream_add(out, b_string_ptr(str)); + b_stream_write_fmt(out, NULL, "%s", b_string_ptr(str)); } char *b_strdup(const char *s)