2024-08-03 07:54:28 +01:00
|
|
|
#include <blue/core/stringstream.h>
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
2025-06-27 21:42:53 +01:00
|
|
|
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)
|
2024-08-03 07:54:28 +01:00
|
|
|
{
|
2024-10-24 21:36:40 +01:00
|
|
|
memset(ss, 0x0, sizeof *ss);
|
|
|
|
|
|
2025-06-27 21:42:53 +01:00
|
|
|
ss->ss_base.s_mode = B_STREAM_WRITE | Z__B_STREAM_STATIC;
|
|
|
|
|
ss->ss_base.s_write = stream_write;
|
|
|
|
|
|
2024-08-03 07:54:28 +01:00
|
|
|
ss->ss_buf = buf;
|
|
|
|
|
ss->ss_max = max;
|
|
|
|
|
ss->ss_len = 0;
|
|
|
|
|
ss->ss_alloc = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-27 21:42:53 +01:00
|
|
|
void b_stringstream_begin_dynamic(struct b_stringstream *ss)
|
2024-08-03 07:54:28 +01:00
|
|
|
{
|
2024-10-24 21:36:40 +01:00
|
|
|
memset(ss, 0x0, sizeof *ss);
|
|
|
|
|
|
2025-06-27 21:42:53 +01:00
|
|
|
ss->ss_base.s_mode = B_STREAM_WRITE | Z__B_STREAM_STATIC;
|
|
|
|
|
ss->ss_base.s_write = stream_write;
|
|
|
|
|
|
2024-08-03 07:54:28 +01:00
|
|
|
ss->ss_buf = NULL;
|
|
|
|
|
ss->ss_max = 0;
|
|
|
|
|
ss->ss_len = 0;
|
|
|
|
|
ss->ss_alloc = 1;
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-27 21:42:53 +01:00
|
|
|
size_t b_stringstream_get_length(const struct b_stringstream *strv)
|
|
|
|
|
{
|
|
|
|
|
return strv->ss_len;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-24 19:24:54 +01:00
|
|
|
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)
|
2024-08-03 07:54:28 +01:00
|
|
|
{
|
2024-10-24 19:24:54 +01:00
|
|
|
if (ss->ss_len + 1 >= ss->ss_max && ss->ss_alloc == 1) {
|
|
|
|
|
char *new_buf = realloc(ss->ss_buf, ss->ss_len + 8);
|
2024-08-03 07:54:28 +01:00
|
|
|
if (!new_buf) {
|
2024-10-24 19:24:54 +01:00
|
|
|
return;
|
2024-08-03 07:54:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ss->ss_buf = new_buf;
|
2024-10-24 19:24:54 +01:00
|
|
|
ss->ss_max = ss->ss_len + 8;
|
2024-08-03 07:54:28 +01:00
|
|
|
}
|
|
|
|
|
|
2025-06-27 21:42:53 +01:00
|
|
|
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++;
|
2024-10-24 19:24:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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, ' ');
|
2024-08-03 07:54:28 +01:00
|
|
|
}
|
2024-10-24 19:24:54 +01:00
|
|
|
|
|
|
|
|
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]);
|
2024-08-03 07:54:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return B_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-24 19:24:54 +01:00
|
|
|
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--;
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-03 07:54:28 +01:00
|
|
|
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);
|
|
|
|
|
size_t len = vsnprintf(str, sizeof str, format, arg);
|
|
|
|
|
va_end(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;
|
|
|
|
|
|
2024-10-24 19:24:54 +01:00
|
|
|
if (ss->ss_istack) {
|
|
|
|
|
free(ss->ss_istack);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memset(ss, 0x0, sizeof *ss);
|
2024-08-03 07:54:28 +01:00
|
|
|
|
|
|
|
|
return out;
|
|
|
|
|
}
|