#include #include #include #include #include static b_status ss_builder_push_string( b_stringstream *ss, const char *s, size_t len); enum b_status stream_write( struct b_stream *stream, const unsigned char *buf, size_t count, size_t *nr_written) { struct b_stringstream *s = (struct b_stringstream *)stream; enum b_status status = ss_builder_push_string(s, (const char *)buf, count); stream->s_cursor += *nr_written; return status; } void b_stringstream_begin(struct b_stringstream *ss, char *buf, size_t max) { 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 = buf; ss->ss_max = max; ss->ss_len = 0; ss->ss_alloc = 0; } 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) { return strv->ss_len; } static int current_indent(struct b_stringstream *ss) { if (!ss->ss_istack || !ss->ss_istack_size) { return 0; } return ss->ss_istack[ss->ss_istack_ptr]; } static void __formatter_putchar(struct b_stringstream *ss, char c) { 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; } ss->ss_buf = new_buf; ss->ss_max = ss->ss_len + 8; } 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_len++; } 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, ' '); } f->ss_add_indent = 0; } __formatter_putchar(f, c); if (c == '\n') { f->ss_add_indent = 1; } } static b_status ss_builder_push_string(b_stringstream *ss, const char *s, size_t len) { for (size_t i = 0; i < len; i++) { formatter_putchar(ss, s[i]); } 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); 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); return ss_builder_push_string(ss, str, len); } 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; } } 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; }