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:
@@ -10,6 +10,7 @@
|
||||
|
||||
struct b_stringstream_p {
|
||||
char *ss_buf;
|
||||
size_t ss_ptr;
|
||||
size_t ss_len;
|
||||
size_t ss_max;
|
||||
unsigned char ss_alloc;
|
||||
@@ -17,6 +18,50 @@ struct b_stringstream_p {
|
||||
|
||||
/*** 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(
|
||||
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);
|
||||
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_max = max;
|
||||
@@ -131,7 +176,7 @@ b_stringstream *b_stringstream_create(void)
|
||||
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;
|
||||
cfg->s_mode = B_STREAM_READ | B_STREAM_WRITE | Z__B_STREAM_STATIC;
|
||||
|
||||
p->ss_buf = malloc(DEFAULT_CAPACITY + 1);
|
||||
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(
|
||||
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_seek) = NULL;
|
||||
B_INTERFACE_ENTRY(s_tell) = NULL;
|
||||
B_INTERFACE_ENTRY(s_getc) = NULL;
|
||||
B_INTERFACE_ENTRY(s_read) = NULL;
|
||||
B_INTERFACE_ENTRY(s_getc) = stream_getc;
|
||||
B_INTERFACE_ENTRY(s_read) = stream_read;
|
||||
B_INTERFACE_ENTRY(s_write) = stream_write;
|
||||
B_INTERFACE_ENTRY(s_reserve) = NULL;
|
||||
B_TYPE_CLASS_INTERFACE_END(b_stream, B_TYPE_STREAM)
|
||||
|
||||
Reference in New Issue
Block a user