From a5762e537b8a4ef253f613a59e9f5c1264e43631 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Fri, 24 Oct 2025 12:32:54 +0100 Subject: [PATCH] core: stringstream: convert to a b_object type inheriting from b_stream --- core/include/blue/core/stringstream.h | 41 +-- core/stringstream.c | 358 +++++++++++++------------- 2 files changed, 208 insertions(+), 191 deletions(-) diff --git a/core/include/blue/core/stringstream.h b/core/include/blue/core/stringstream.h index 86ef69a..51d9d06 100644 --- a/core/include/blue/core/stringstream.h +++ b/core/include/blue/core/stringstream.h @@ -1,27 +1,36 @@ -#ifndef BLUELIB_CORE_STRINGSTREAM_H_ -#define BLUELIB_CORE_STRINGSTREAM_H_ +#ifndef BLUE_CORE_STRINGSTREAM_H_ +#define BLUE_CORE_STRINGSTREAM_H_ +#include #include #include #include #include -typedef struct b_stringstream { - b_stream ss_base; - char *ss_buf; - size_t ss_len; - size_t ss_max; - unsigned char ss_alloc; - int *ss_istack; - int ss_add_indent; - size_t ss_istack_ptr, ss_istack_size; -} b_stringstream; +B_DECLS_BEGIN; -BLUE_API void b_stringstream_begin(b_stringstream *strv, char *buf, size_t max); -BLUE_API void b_stringstream_begin_dynamic(b_stringstream *strv); +#define B_TYPE_STRINGSTREAM (b_stringstream_get_type()) + +B_DECLARE_TYPE(b_stringstream); + +B_TYPE_CLASS_DECLARATION_BEGIN(b_stringstream) +B_TYPE_CLASS_DECLARATION_END(b_stringstream) + +BLUE_API b_type b_stringstream_get_type(void); + +BLUE_API b_stringstream *b_stringstream_create(void); +BLUE_API b_stringstream *b_stringstream_create_with_buffer(char *buf, size_t max); + +BLUE_API b_status b_stringstream_reset(b_stringstream *strv); +BLUE_API b_status b_stringstream_reset_with_buffer( + b_stringstream *strv, char *buf, size_t max); + +BLUE_API const char *b_stringstream_ptr(const b_stringstream *strv); +BLUE_API char *b_stringstream_steal(b_stringstream *strv); BLUE_API size_t b_stringstream_get_length(const b_stringstream *strv); +#if 0 BLUE_API void b_stringstream_push_indent(b_stringstream *strv, int indent); BLUE_API void b_stringstream_pop_indent(b_stringstream *strv); @@ -33,6 +42,8 @@ BLUE_API b_status b_stringstream_addvf( BLUE_API b_status b_stringstream_addvl( b_stringstream *strv, const char **strs, size_t count); BLUE_API b_status b_stringstream_add_many(b_stringstream *strv, ...); -BLUE_API char *b_stringstream_end(b_stringstream *strv); +#endif + +B_DECLS_END; #endif diff --git a/core/stringstream.c b/core/stringstream.c index 5542921..a535da1 100644 --- a/core/stringstream.c +++ b/core/stringstream.c @@ -4,223 +4,229 @@ #include #include -static b_status ss_builder_push_string( - b_stringstream *ss, const char *s, size_t len); +#define DEFAULT_CAPACITY 15 -enum b_status stream_write( - struct b_stream *stream, const unsigned char *buf, size_t count, - size_t *nr_written) +/*** PRIVATE DATA *************************************************************/ + +struct b_stringstream_p { + char *ss_buf; + size_t ss_len; + size_t ss_max; + unsigned char ss_alloc; +}; + +/*** PRIVATE FUNCTIONS ********************************************************/ + +static enum b_status __puts( + struct b_stringstream_p *ss, const char *s, size_t len, size_t *nr_written) { - struct b_stringstream *s = (struct b_stringstream *)stream; + size_t available = ss->ss_max - ss->ss_len; + size_t to_copy = len; - enum b_status status = ss_builder_push_string(s, (const char *)buf, count); + if (to_copy > available && ss->ss_alloc == 1) { + char *new_buf = realloc(ss->ss_buf, ss->ss_len + to_copy + 1); + if (!new_buf) { + return B_ERR_NO_MEMORY; + } - stream->s_cursor += *nr_written; + ss->ss_buf = new_buf; + ss->ss_max = ss->ss_len + to_copy; + available = ss->ss_max - ss->ss_len; + } - return status; + if (available < to_copy) { + to_copy = available; + } + + memcpy(ss->ss_buf + ss->ss_len, s, to_copy); + + /* increment the length by the full string length, even if only a + * portion was copied */ + ss->ss_len += len; + + if (nr_written) { + *nr_written = to_copy; + } + + return B_SUCCESS; } -void b_stringstream_begin(struct b_stringstream *ss, char *buf, size_t max) +static enum b_status stringstream_reset(struct b_stringstream_p *ss) { - memset(ss, 0x0, sizeof *ss); + ss->ss_len = 0; - ss->ss_base.s_mode = B_STREAM_WRITE | Z__B_STREAM_STATIC; - ss->ss_base.s_write = stream_write; + if (ss->ss_buf) { + *ss->ss_buf = 0; + } + + return B_SUCCESS; +} + +static enum b_status stringstream_reset_with_buffer( + struct b_stringstream_p *ss, char *buf, size_t max) +{ + ss->ss_len = 0; + + if (ss->ss_buf && ss->ss_alloc) { + free(ss->ss_buf); + } ss->ss_buf = buf; ss->ss_max = max; - ss->ss_len = 0; ss->ss_alloc = 0; + + return B_SUCCESS; } -void b_stringstream_begin_dynamic(struct b_stringstream *ss) -{ - memset(ss, 0x0, sizeof *ss); - - ss->ss_base.s_mode = B_STREAM_WRITE | Z__B_STREAM_STATIC; - ss->ss_base.s_write = stream_write; - - ss->ss_buf = NULL; - ss->ss_max = 0; - ss->ss_len = 0; - ss->ss_alloc = 1; -} - -size_t b_stringstream_get_length(const struct b_stringstream *strv) +static size_t stringstream_get_length(const struct b_stringstream_p *strv) { return strv->ss_len; } -static int current_indent(struct b_stringstream *ss) +static const char *stringstream_ptr(const struct b_stringstream_p *ss) { - if (!ss->ss_istack || !ss->ss_istack_size) { - return 0; - } - - return ss->ss_istack[ss->ss_istack_ptr]; + return ss->ss_buf; } -static void __formatter_putchar(struct b_stringstream *ss, char c) +static char *stringstream_steal(struct b_stringstream_p *ss) { - if (ss->ss_len + 1 >= ss->ss_max && ss->ss_alloc == 1) { - char *new_buf = realloc(ss->ss_buf, ss->ss_len + 8); - if (!new_buf) { - return; - } + char *out = ss->ss_buf; - ss->ss_buf = new_buf; - ss->ss_max = ss->ss_len + 8; - } + memset(ss, 0x0, sizeof *ss); - if (ss->ss_len < ss->ss_max - 1) { - ss->ss_buf[ss->ss_len] = c; - ss->ss_buf[ss->ss_len + 1] = '\0'; - } + ss->ss_alloc = 1; - ss->ss_len++; + return out; } -static void formatter_putchar(struct b_stringstream *f, char c) -{ - if (f->ss_add_indent && c != '\n') { - int indent = current_indent(f); - for (int i = 0; i < indent; i++) { - __formatter_putchar(f, ' '); - __formatter_putchar(f, ' '); - } +/*** PUBLIC FUNCTIONS *********************************************************/ - f->ss_add_indent = 0; +b_stringstream *b_stringstream_create_with_buffer(char *buf, size_t max) +{ + b_stringstream *s = b_object_create(B_TYPE_STRINGSTREAM); + if (!s) { + return NULL; } - __formatter_putchar(f, c); + b_stream_cfg *cfg = b_object_get_protected(s, B_TYPE_STREAM); + struct b_stringstream_p *p = b_object_get_private(s, B_TYPE_STRINGSTREAM); - if (c == '\n') { - f->ss_add_indent = 1; + cfg->s_mode = B_STREAM_WRITE | Z__B_STREAM_STATIC; + + p->ss_buf = buf; + p->ss_max = max; + p->ss_len = 0; + p->ss_alloc = 0; + + return s; +} + +b_stringstream *b_stringstream_create(void) +{ + b_stringstream *s = b_object_create(B_TYPE_STRINGSTREAM); + if (!s) { + return NULL; + } + + b_stream_cfg *cfg = b_object_get_protected(s, B_TYPE_STREAM); + struct b_stringstream_p *p = b_object_get_private(s, B_TYPE_STRINGSTREAM); + + cfg->s_mode = B_STREAM_WRITE | Z__B_STREAM_STATIC; + + p->ss_buf = malloc(DEFAULT_CAPACITY + 1); + if (!p->ss_buf) { + b_stringstream_unref(s); + return NULL; + } + + memset(p->ss_buf, 0x0, DEFAULT_CAPACITY + 1); + p->ss_max = DEFAULT_CAPACITY; + p->ss_len = 0; + p->ss_alloc = 1; + + return s; +} + +size_t b_stringstream_get_length(const b_stringstream *strv) +{ + B_CLASS_DISPATCH_STATIC_0( + B_TYPE_STRINGSTREAM, stringstream_get_length, strv); +} + +enum b_status b_stringstream_reset(b_stringstream *strv) +{ + B_CLASS_DISPATCH_STATIC_0(B_TYPE_STRINGSTREAM, stringstream_reset, strv); +} + +enum b_status b_stringstream_reset_with_buffer( + b_stringstream *strv, char *buf, size_t max) +{ + B_CLASS_DISPATCH_STATIC( + B_TYPE_STRINGSTREAM, stringstream_reset_with_buffer, strv, buf, + max); +} + +const char *b_stringstream_ptr(const b_stringstream *ss) +{ + B_CLASS_DISPATCH_STATIC_0(B_TYPE_STRINGSTREAM, stringstream_ptr, ss); +} + +char *b_stringstream_steal(b_stringstream *ss) +{ + B_CLASS_DISPATCH_STATIC_0(B_TYPE_STRINGSTREAM, stringstream_steal, ss); +} + +/*** PUBLIC ALIAS FUNCTIONS ***************************************************/ +/*** VIRTUAL FUNCTIONS ********************************************************/ + +static void stringstream_init(b_object *obj, void *priv) +{ + struct b_stringstream_p *stream = priv; +} + +static void stringstream_fini(b_object *obj, void *priv) +{ + struct b_stringstream_p *stream = priv; + + if (stream->ss_alloc && stream->ss_buf) { + free(stream->ss_buf); } } -static b_status ss_builder_push_string(b_stringstream *ss, const char *s, size_t len) +enum b_status stream_write( + b_stream *stream, const unsigned char *buf, size_t count, size_t *nr_written) { - for (size_t i = 0; i < len; i++) { - formatter_putchar(ss, s[i]); - } + struct b_stringstream_p *s + = b_object_get_private(stream, B_TYPE_STRINGSTREAM); - return B_SUCCESS; -} - -void b_stringstream_push_indent(struct b_stringstream *ss, int indent) -{ - if (!ss->ss_istack) { - ss->ss_istack = calloc(4, sizeof(int)); - ss->ss_istack_size = 4; - ss->ss_istack_ptr = 0; - } - - if (ss->ss_istack_ptr + 1 > ss->ss_istack_size) { - int *buf = realloc( - ss->ss_istack, (ss->ss_istack_size + 4) * sizeof(int)); - if (!buf) { - return; - } - - ss->ss_istack = buf; - ss->ss_istack_size += 4; - } - - int cur_indent = ss->ss_istack[ss->ss_istack_ptr]; - ss->ss_istack[++ss->ss_istack_ptr] = cur_indent + indent; -} - -void b_stringstream_pop_indent(b_stringstream *strv) -{ - if (!strv->ss_istack || !strv->ss_istack_size || !strv->ss_istack_ptr) { - return; - } - - strv->ss_istack_ptr--; -} - -b_status b_stringstream_add(struct b_stringstream *ss, const char *str) -{ - return ss_builder_push_string(ss, str, strlen(str)); -} - -b_status b_stringstream_addf(struct b_stringstream *ss, const char *format, ...) -{ - char str[1024]; - va_list arg; - va_start(arg, format); - enum b_status status = b_stringstream_addvf(ss, format, arg); - va_end(arg); + enum b_status status = __puts(s, (const char *)buf, count, nr_written); return status; } -b_status b_stringstream_addvf( - struct b_stringstream *ss, const char *format, va_list arg) -{ - char str[1024]; - size_t len = vsnprintf(str, sizeof str, format, arg); +/*** CLASS DEFINITION *********************************************************/ - return ss_builder_push_string(ss, str, len); -} +B_TYPE_CLASS_DEFINITION_BEGIN(b_stringstream) + B_TYPE_CLASS_INTERFACE_BEGIN(b_object, B_TYPE_OBJECT) + B_INTERFACE_ENTRY(to_string) = NULL; + B_TYPE_CLASS_INTERFACE_END(b_object, B_TYPE_OBJECT) -b_status b_stringstream_addv(b_stringstream *ss, const char **strs) -{ - for (size_t i = 0; strs[i]; i++) { - size_t len = strlen(strs[i]); - b_status status = ss_builder_push_string(ss, strs[i], len); - if (B_ERR(status)) { - return status; - } - } + B_TYPE_CLASS_INTERFACE_BEGIN(b_stream, B_TYPE_STREAM) + B_INTERFACE_ENTRY(s_close) = NULL; + B_INTERFACE_ENTRY(s_seek) = NULL; + B_INTERFACE_ENTRY(s_tell) = NULL; + B_INTERFACE_ENTRY(s_getc) = NULL; + B_INTERFACE_ENTRY(s_read) = NULL; + B_INTERFACE_ENTRY(s_write) = stream_write; + B_INTERFACE_ENTRY(s_reserve) = NULL; + B_TYPE_CLASS_INTERFACE_END(b_stream, B_TYPE_STREAM) +B_TYPE_CLASS_DEFINITION_END(b_stringstream) - return B_SUCCESS; -} - -b_status b_stringstream_addvl(b_stringstream *ss, const char **strs, size_t count) -{ - for (size_t i = 0; i < count; i++) { - if (!strs[i]) { - continue; - } - - size_t len = strlen(strs[i]); - b_status status = ss_builder_push_string(ss, strs[i], len); - if (B_ERR(status)) { - return status; - } - } - - return B_SUCCESS; -} - -b_status b_stringstream_add_many(b_stringstream *ss, ...) -{ - va_list arg; - va_start(arg, ss); - const char *s = NULL; - - while ((s = va_arg(arg, const char *))) { - size_t len = strlen(s); - b_status status = ss_builder_push_string(ss, s, len); - if (B_ERR(status)) { - return status; - } - } - - return B_SUCCESS; -} - -char *b_stringstream_end(b_stringstream *ss) -{ - char *out = ss->ss_buf; - - if (ss->ss_istack) { - free(ss->ss_istack); - } - - memset(ss, 0x0, sizeof *ss); - - return out; -} +B_TYPE_DEFINITION_BEGIN(b_stringstream) + B_TYPE_ID(0x508a609a, 0xfac5, 0x4d31, 0x843a, 0x44b68ad329f3); + B_TYPE_EXTENDS(B_TYPE_STREAM); + B_TYPE_CLASS(b_stringstream_class); + B_TYPE_INSTANCE_PRIVATE(struct b_stringstream_p); + B_TYPE_INSTANCE_INIT(stringstream_init); + B_TYPE_INSTANCE_FINI(stringstream_fini); +B_TYPE_DEFINITION_END(b_stringstream)