core: stringstream: added read-support
any characters written to a stringstream can be optionally read back again using the b_stream read API. this functions similar to a ringbuffer, with two key differences: 1) the buffer is not circular, and will continuously expand to accomodate all incoming data. 2) reading data from the stringstream does not remove it from the buffer.
This commit is contained in:
@@ -30,20 +30,6 @@ BLUE_API char *b_stringstream_steal(b_stringstream *strv);
|
|||||||
|
|
||||||
BLUE_API size_t b_stringstream_get_length(const 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);
|
|
||||||
|
|
||||||
BLUE_API b_status b_stringstream_add(b_stringstream *strv, const char *str);
|
|
||||||
BLUE_API b_status b_stringstream_addf(b_stringstream *strv, const char *format, ...);
|
|
||||||
BLUE_API b_status b_stringstream_addv(b_stringstream *strv, const char **strs);
|
|
||||||
BLUE_API b_status b_stringstream_addvf(
|
|
||||||
b_stringstream *strv, const char *format, va_list arg);
|
|
||||||
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, ...);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
B_DECLS_END;
|
B_DECLS_END;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
struct b_stringstream_p {
|
struct b_stringstream_p {
|
||||||
char *ss_buf;
|
char *ss_buf;
|
||||||
|
size_t ss_ptr;
|
||||||
size_t ss_len;
|
size_t ss_len;
|
||||||
size_t ss_max;
|
size_t ss_max;
|
||||||
unsigned char ss_alloc;
|
unsigned char ss_alloc;
|
||||||
@@ -17,6 +18,50 @@ struct b_stringstream_p {
|
|||||||
|
|
||||||
/*** PRIVATE FUNCTIONS ********************************************************/
|
/*** PRIVATE FUNCTIONS ********************************************************/
|
||||||
|
|
||||||
|
static enum b_status __getc(struct b_stringstream_p *ss, b_wchar *out)
|
||||||
|
{
|
||||||
|
size_t available = ss->ss_len - ss->ss_ptr;
|
||||||
|
|
||||||
|
const char *p = ss->ss_buf + ss->ss_ptr;
|
||||||
|
|
||||||
|
size_t to_copy = b_wchar_utf8_codepoint_stride(p);
|
||||||
|
if (to_copy > available) {
|
||||||
|
return B_ERR_BAD_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
b_wchar c = b_wchar_utf8_codepoint_decode(p);
|
||||||
|
*out = c;
|
||||||
|
|
||||||
|
if (c == B_WCHAR_INVALID) {
|
||||||
|
return B_ERR_BAD_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ss->ss_ptr += to_copy;
|
||||||
|
|
||||||
|
return B_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum b_status __gets(
|
||||||
|
struct b_stringstream_p *ss, char *s, size_t len, size_t *nr_read)
|
||||||
|
{
|
||||||
|
size_t available = ss->ss_len - ss->ss_ptr;
|
||||||
|
size_t to_copy = len;
|
||||||
|
|
||||||
|
if (available < to_copy) {
|
||||||
|
to_copy = available;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(s, ss->ss_buf + ss->ss_ptr, to_copy);
|
||||||
|
|
||||||
|
ss->ss_ptr += to_copy;
|
||||||
|
|
||||||
|
if (nr_read) {
|
||||||
|
*nr_read = to_copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static enum b_status __puts(
|
static enum b_status __puts(
|
||||||
struct b_stringstream_p *ss, const char *s, size_t len, size_t *nr_written)
|
struct b_stringstream_p *ss, const char *s, size_t len, size_t *nr_written)
|
||||||
{
|
{
|
||||||
@@ -111,7 +156,7 @@ b_stringstream *b_stringstream_create_with_buffer(char *buf, size_t max)
|
|||||||
b_stream_cfg *cfg = b_object_get_protected(s, B_TYPE_STREAM);
|
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);
|
struct b_stringstream_p *p = b_object_get_private(s, B_TYPE_STRINGSTREAM);
|
||||||
|
|
||||||
cfg->s_mode = B_STREAM_WRITE | Z__B_STREAM_STATIC;
|
cfg->s_mode = B_STREAM_READ | B_STREAM_WRITE | Z__B_STREAM_STATIC;
|
||||||
|
|
||||||
p->ss_buf = buf;
|
p->ss_buf = buf;
|
||||||
p->ss_max = max;
|
p->ss_max = max;
|
||||||
@@ -131,7 +176,7 @@ b_stringstream *b_stringstream_create(void)
|
|||||||
b_stream_cfg *cfg = b_object_get_protected(s, B_TYPE_STREAM);
|
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);
|
struct b_stringstream_p *p = b_object_get_private(s, B_TYPE_STRINGSTREAM);
|
||||||
|
|
||||||
cfg->s_mode = B_STREAM_WRITE | Z__B_STREAM_STATIC;
|
cfg->s_mode = B_STREAM_READ | B_STREAM_WRITE | Z__B_STREAM_STATIC;
|
||||||
|
|
||||||
p->ss_buf = malloc(DEFAULT_CAPACITY + 1);
|
p->ss_buf = malloc(DEFAULT_CAPACITY + 1);
|
||||||
if (!p->ss_buf) {
|
if (!p->ss_buf) {
|
||||||
@@ -193,6 +238,26 @@ static void stringstream_fini(b_object *obj, void *priv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum b_status stream_getc(b_stream *stream, b_wchar *c)
|
||||||
|
{
|
||||||
|
struct b_stringstream_p *s
|
||||||
|
= b_object_get_private(stream, B_TYPE_STRINGSTREAM);
|
||||||
|
|
||||||
|
enum b_status status = __getc(s, c);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum b_status stream_read(b_stream *stream, void *buf, size_t count, size_t *nr_read)
|
||||||
|
{
|
||||||
|
struct b_stringstream_p *s
|
||||||
|
= b_object_get_private(stream, B_TYPE_STRINGSTREAM);
|
||||||
|
|
||||||
|
enum b_status status = __gets(s, buf, count, nr_read);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
enum b_status stream_write(
|
enum b_status stream_write(
|
||||||
b_stream *stream, const void *buf, size_t count, size_t *nr_written)
|
b_stream *stream, const void *buf, size_t count, size_t *nr_written)
|
||||||
{
|
{
|
||||||
@@ -215,8 +280,8 @@ B_TYPE_CLASS_DEFINITION_BEGIN(b_stringstream)
|
|||||||
B_INTERFACE_ENTRY(s_close) = NULL;
|
B_INTERFACE_ENTRY(s_close) = NULL;
|
||||||
B_INTERFACE_ENTRY(s_seek) = NULL;
|
B_INTERFACE_ENTRY(s_seek) = NULL;
|
||||||
B_INTERFACE_ENTRY(s_tell) = NULL;
|
B_INTERFACE_ENTRY(s_tell) = NULL;
|
||||||
B_INTERFACE_ENTRY(s_getc) = NULL;
|
B_INTERFACE_ENTRY(s_getc) = stream_getc;
|
||||||
B_INTERFACE_ENTRY(s_read) = NULL;
|
B_INTERFACE_ENTRY(s_read) = stream_read;
|
||||||
B_INTERFACE_ENTRY(s_write) = stream_write;
|
B_INTERFACE_ENTRY(s_write) = stream_write;
|
||||||
B_INTERFACE_ENTRY(s_reserve) = NULL;
|
B_INTERFACE_ENTRY(s_reserve) = NULL;
|
||||||
B_TYPE_CLASS_INTERFACE_END(b_stream, B_TYPE_STREAM)
|
B_TYPE_CLASS_INTERFACE_END(b_stream, B_TYPE_STREAM)
|
||||||
|
|||||||
Reference in New Issue
Block a user