diff --git a/core/stream.c b/core/stream.c index 6cb99fd..c54c670 100644 --- a/core/stream.c +++ b/core/stream.c @@ -1,10 +1,14 @@ #include "printf.h" +#include #include #include #include #include +#define READ_MAGIC(p) (*(uint64_t *)p) +#define IS_BSTR(p) (READ_MAGIC(p) == B_BSTR_MAGIC) + #define B_TYPE_STDIO_STREAM (b_stdio_stream_get_type()) #define STREAM_DISPATCH_VIRTUAL(func, stream, ...) \ @@ -369,6 +373,39 @@ static enum b_status stream_read_line_s( return status; } +static enum b_status stream_read_line_to_bstr( + struct stream_data *src, struct b_bstr *dest) +{ + if (!(src->s_cfg->s_mode & B_STREAM_READ)) { + return B_ERR_NOT_SUPPORTED; + } + + enum b_status status = B_SUCCESS; + + size_t i = 0; + b_wchar c = 0; + + while (1) { + status = stream_read_char(src, &c); + if (status != B_SUCCESS) { + break; + } + + b_bstr_write_char(dest, c); + i++; + + if (c == '\n') { + break; + } + } + + if (status == B_ERR_NO_DATA && i > 0) { + status = B_SUCCESS; + } + + return status; +} + static enum b_status stream_write_bytes( struct stream_data *stream, const void *buf, size_t count, size_t *nr_written) { @@ -469,6 +506,57 @@ static enum b_status stream_read_all_bytes_s( return status; } +static enum b_status stream_read_all_bytes_to_bstr_s( + struct stream_data *src, struct b_bstr *dest, + struct b_stream_buffer_p *buffer, size_t *out_nr_read) +{ + if (!(src->s_cfg->s_mode & B_STREAM_READ)) { + return B_ERR_NOT_SUPPORTED; + } + + if (!buffer) { + return B_ERR_INVALID_ARGUMENT; + } + + if (src->s_ops->s_seek) { + size_t offset = stream_cursor(src); + stream_seek(src, 0, B_STREAM_SEEK_END); + size_t length = stream_cursor(src); + stream_seek(src, offset, B_STREAM_SEEK_START); + + b_bstr_reserve(dest, length); + } + + enum b_status status = B_SUCCESS; + size_t nr_read = 0; + + while (1) { + size_t r = 0, w = 0; + status = stream_read_bytes( + src, buffer->p_buf, buffer->p_buf_len, &r); + if (status != B_SUCCESS) { + break; + } + + status = b_bstr_write_chars(dest, buffer->p_buf, r, &w); + nr_read += w; + + if (status != B_SUCCESS || w != buffer->p_buf_len) { + break; + } + } + + if (status == B_ERR_NO_DATA && nr_read > 0) { + status = B_SUCCESS; + } + + if (out_nr_read) { + *out_nr_read = nr_read; + } + + return status; +} + static enum b_status stream_write_string( struct stream_data *stream, const char *s, size_t *nr_written) { @@ -642,6 +730,10 @@ b_stream *b_stream_open_fp(FILE *fp) enum b_status b_stream_reserve(b_stream *stream, size_t len) { + if (IS_BSTR(stream)) { + return B_ERR_NOT_SUPPORTED; + } + B_CLASS_DISPATCH_VIRTUAL( b_stream, B_TYPE_STREAM, B_ERR_NOT_SUPPORTED, s_reserve, stream, len); @@ -650,6 +742,10 @@ enum b_status b_stream_reserve(b_stream *stream, size_t len) enum b_status b_stream_seek( b_stream *stream, long long offset, b_stream_seek_origin origin) { + if (IS_BSTR(stream)) { + return B_ERR_NOT_SUPPORTED; + } + B_CLASS_DISPATCH_VIRTUAL( b_stream, B_TYPE_STREAM, B_ERR_NOT_SUPPORTED, s_seek, stream, offset, origin); @@ -657,37 +753,65 @@ enum b_status b_stream_seek( size_t b_stream_cursor(const b_stream *stream) { + if (IS_BSTR(stream)) { + return b_bstr_get_size((b_bstr *)stream); + } + STREAM_DISPATCH_VIRTUAL_0(stream_cursor, stream); } enum b_status b_stream_push_indent(b_stream *strp, int indent) { + if (IS_BSTR(strp)) { + return b_bstr_push_indent((b_bstr *)strp, indent); + } + STREAM_DISPATCH_VIRTUAL(stream_push_indent, strp, indent); } enum b_status b_stream_pop_indent(b_stream *strp) { + if (IS_BSTR(strp)) { + return b_bstr_pop_indent((b_bstr *)strp); + } + STREAM_DISPATCH_VIRTUAL_0(stream_pop_indent, strp); } enum b_status b_stream_read_char(b_stream *strp, int *c) { + if (IS_BSTR(strp)) { + return B_ERR_NOT_SUPPORTED; + } + STREAM_DISPATCH_VIRTUAL(stream_read_char, strp, c); } enum b_status b_stream_read_bytes( b_stream *strp, void *buf, size_t count, size_t *nr_read) { + if (IS_BSTR(strp)) { + return B_ERR_NOT_SUPPORTED; + } + STREAM_DISPATCH_VIRTUAL(stream_read_bytes, strp, buf, count, nr_read); } enum b_status b_stream_read_line(b_stream *strp, char *s, size_t max) { + if (IS_BSTR(strp)) { + return B_ERR_NOT_SUPPORTED; + } + STREAM_DISPATCH_VIRTUAL(stream_read_line, strp, s, max); } enum b_status b_stream_read_line_s(b_stream *src, b_stream *dest) { + if (IS_BSTR(src)) { + return B_ERR_NOT_SUPPORTED; + } + enum b_status status; struct stream_data src_p, dest_p; @@ -696,6 +820,10 @@ enum b_status b_stream_read_line_s(b_stream *src, b_stream *dest) return status; } + if (IS_BSTR(dest)) { + return stream_read_line_to_bstr(&src_p, (b_bstr *)dest); + } + status = stream_get_data(dest, &dest_p); if (!B_OK(status)) { return status; @@ -707,12 +835,20 @@ enum b_status b_stream_read_line_s(b_stream *src, b_stream *dest) enum b_status b_stream_read_all_bytes( b_stream *stream, void *p, size_t max, size_t *out_nr_read) { + if (IS_BSTR(stream)) { + return B_ERR_NOT_SUPPORTED; + } + STREAM_DISPATCH_VIRTUAL(stream_read_all_bytes, stream, p, max, out_nr_read); } enum b_status b_stream_read_all_bytes_s( b_stream *src, b_stream *dest, b_stream_buffer *buffer, size_t *out_nr_read) { + if (IS_BSTR(src)) { + return B_ERR_NOT_SUPPORTED; + } + enum b_status status; struct stream_data src_p, dest_p; struct b_stream_buffer_p *buffer_p; @@ -722,39 +858,66 @@ enum b_status b_stream_read_all_bytes_s( return status; } - status = stream_get_data(dest, &dest_p); - if (!B_OK(status)) { - return status; - } - buffer_p = b_object_get_private(buffer, B_TYPE_STREAM_BUFFER); if (!buffer_p) { return B_ERR_INVALID_ARGUMENT; } + if (IS_BSTR(dest)) { + return stream_read_all_bytes_to_bstr_s( + &src_p, (b_bstr *)dest, buffer_p, out_nr_read); + } + + status = stream_get_data(dest, &dest_p); + if (!B_OK(status)) { + return status; + } + return stream_read_all_bytes_s(&src_p, &dest_p, buffer_p, out_nr_read); } enum b_status b_stream_write_char(b_stream *stream, b_wchar c) { + if (IS_BSTR(stream)) { + return b_bstr_write_char((b_bstr *)stream, c); + } + STREAM_DISPATCH_VIRTUAL(stream_write_char, stream, c); } enum b_status b_stream_write_string( b_stream *stream, const char *s, size_t *nr_written) { + if (IS_BSTR(stream)) { + return b_bstr_write_cstr((b_bstr *)stream, s, nr_written); + } + STREAM_DISPATCH_VIRTUAL(stream_write_string, stream, s, nr_written); } enum b_status b_stream_write_bytes( b_stream *stream, const void *buf, size_t count, size_t *nr_written) { + if (IS_BSTR(stream)) { + return b_bstr_write_chars((b_bstr *)stream, buf, count, nr_written); + } + STREAM_DISPATCH_VIRTUAL(stream_write_bytes, stream, buf, count, nr_written); } enum b_status b_stream_write_fmt( b_stream *stream, size_t *nr_written, const char *format, ...) { + if (IS_BSTR(stream)) { + va_list arg; + va_start(arg, format); + b_status w = b_bstr_write_vfmt( + (b_bstr *)stream, nr_written, format, arg); + va_end(arg); + + return w; + } + struct stream_data p; enum b_status status = stream_get_data(stream, &p); @@ -773,6 +936,10 @@ enum b_status b_stream_write_fmt( enum b_status b_stream_write_vfmt( b_stream *stream, size_t *nr_written, const char *format, va_list arg) { + if (IS_BSTR(stream)) { + return b_bstr_write_vfmt((b_bstr *)stream, nr_written, format, arg); + } + struct stream_data p; enum b_status status = stream_get_data(stream, &p);