Files
fx/core/stream.c
2026-03-16 10:35:43 +00:00

1135 lines
25 KiB
C

#include "printf.h"
#include <fx/core/bstr.h>
#include <fx/core/stream.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define READ_MAGIC(p) (*(uint64_t *)p)
#define IS_BSTR(p) (READ_MAGIC(p) == FX_BSTR_MAGIC)
#define FX_TYPE_STDIO_STREAM (fx_stdio_stream_get_type())
#define STREAM_DISPATCH_VIRTUAL(func, stream, ...) \
do { \
struct stream_data _stream; \
enum fx_status status = stream_get_data(stream, &_stream); \
if (!FX_OK(status)) { \
return status; \
} \
return func(&_stream, __VA_ARGS__); \
} while (0)
#define STREAM_DISPATCH_VIRTUAL_0(func, stream) \
do { \
struct stream_data _stream; \
enum fx_status status = stream_get_data(stream, &_stream); \
if (!FX_OK(status)) { \
return status; \
} \
return func(&_stream); \
} while (0)
#define IDX_STDIN 0
#define IDX_STDOUT 1
#define IDX_STDERR 2
FX_DECLARE_TYPE(fx_stdio_stream);
FX_TYPE_CLASS_DECLARATION_BEGIN(fx_stdio_stream)
FX_TYPE_CLASS_DECLARATION_END(fx_stdio_stream)
/*** PRIVATE DATA *************************************************************/
typedef enum fx_stream_buffer_flags {
FX_STREAM_BUFFER_F_NONE = 0x00u,
FX_STREAM_BUFFER_F_DYNAMIC = 0x01u,
} fx_stream_buffer_flags;
struct fx_stream_p {
int *s_istack;
int s_add_indent;
size_t s_istack_ptr, s_istack_size;
void *s_ptr0, *s_ptr1;
};
struct fx_stdio_stream_p {
FILE *s_fp;
};
struct fx_stream_buffer_p {
fx_stream_buffer_flags p_flags;
void *p_buf;
size_t p_buf_len;
};
struct stream_data {
fx_stream *s_obj;
struct fx_stream_p *s_private;
struct fx_stream_cfg *s_cfg;
fx_stream_class *s_ops;
};
static fx_stream *stdio[] = {
[IDX_STDIN] = NULL,
[IDX_STDOUT] = NULL,
[IDX_STDERR] = NULL,
};
/*** PRIVATE FUNCTIONS ********************************************************/
fx_type fx_stdio_stream_get_type(void);
static enum fx_status stdio_read(fx_stream *, void *, size_t, size_t *);
static enum fx_status stdio_write(fx_stream *, const void *, size_t, size_t *);
static enum fx_status stdio_seek(fx_stream *, long long, fx_stream_seek_origin);
static enum fx_status stdio_tell(const fx_stream *, size_t *);
static enum fx_status stream_get_data(const fx_stream *strp, struct stream_data *out)
{
out->s_obj = (fx_stream *)strp;
return fx_object_get_data(
strp, FX_TYPE_STREAM, (void **)&out->s_private,
(void **)&out->s_cfg, (void **)&out->s_ops);
}
static int current_indent(struct stream_data *stream)
{
if (!stream->s_private->s_istack || !stream->s_private->s_istack_size) {
return 0;
}
return stream->s_private->s_istack[stream->s_private->s_istack_ptr];
}
static size_t stream_cursor(const struct stream_data *stream)
{
if (!stream || !stream->s_ops || !stream->s_ops->s_tell) {
return FX_NPOS;
}
size_t p = FX_NPOS;
fx_status status = stream->s_ops->s_tell(stream->s_obj, &p);
if (!FX_OK(status)) {
return FX_NPOS;
}
return p;
}
static enum fx_status stream_seek(
struct stream_data *stream, long long offset, fx_stream_seek_origin origin)
{
if (!stream || !stream->s_ops || !stream->s_ops->s_seek) {
return FX_ERR_NOT_SUPPORTED;
}
return stream->s_ops->s_seek(stream->s_obj, offset, origin);
}
static enum fx_status stream_reserve(struct stream_data *stream, size_t len)
{
if (!stream || !stream->s_ops || !stream->s_ops->s_reserve) {
return FX_ERR_NOT_SUPPORTED;
}
return stream->s_ops->s_reserve(stream->s_obj, len);
}
static enum fx_status read_char_binary(struct stream_data *stream, fx_wchar *c)
{
size_t r;
unsigned char v = 0;
enum fx_status status = stream->s_ops->s_read(stream->s_obj, &v, 1, &r);
*c = v;
if (status == FX_SUCCESS && r < 1) {
status = FX_ERR_NO_DATA;
}
return status;
}
static enum fx_status read_char_utf8(struct stream_data *stream, fx_wchar *c)
{
size_t r;
unsigned char s[4];
unsigned int len = 0;
enum fx_status status = stream->s_ops->s_read(stream->s_obj, s, 1, &r);
if (!FX_OK(status)) {
return status;
}
if (r < 1) {
return FX_ERR_NO_DATA;
}
len = fx_wchar_utf8_header_decode(s[0]);
if (len <= 0 || len > 4) {
return FX_ERR_BAD_FORMAT;
}
if (len == 1) {
*c = s[0];
return FX_SUCCESS;
}
status = stream->s_ops->s_read(stream->s_obj, s + 1, len - 1, &r);
if (!FX_OK(status)) {
return status;
}
if (r != len - 1) {
return FX_ERR_BAD_FORMAT;
}
fx_wchar result = fx_wchar_utf8_codepoint_decode((char *)s);
if (result == FX_WCHAR_INVALID) {
return FX_ERR_BAD_FORMAT;
}
*c = result;
return FX_SUCCESS;
}
static enum fx_status stream_read_char(struct stream_data *stream, fx_wchar *c)
{
if (!(stream->s_cfg->s_mode & FX_STREAM_READ)) {
return FX_ERR_NOT_SUPPORTED;
}
enum fx_status status = FX_ERR_NOT_SUPPORTED;
#if 0
if (stream->s_ops->s_getc) {
return stream->s_ops->s_getc(stream->s_obj, c);
}
#endif
if (!stream->s_ops->s_read) {
return FX_ERR_NOT_SUPPORTED;
}
if (stream->s_cfg->s_mode & FX_STREAM_BINARY) {
return read_char_binary(stream, c);
}
return read_char_utf8(stream, c);
}
static enum fx_status __write_char(struct stream_data *stream, fx_wchar c)
{
size_t w, len;
enum fx_status status;
char s[4];
if (stream->s_cfg->s_mode & FX_STREAM_BINARY) {
s[0] = c & 0xFF;
len = 1;
} else {
len = fx_wchar_utf8_codepoint_encode(c, s);
if (len == 0 || len > 4) {
return FX_ERR_INVALID_ARGUMENT;
}
}
status = stream->s_ops->s_write(stream->s_obj, (unsigned char *)s, len, &w);
if (!FX_OK(status)) {
return status;
}
if (status == FX_SUCCESS && w < len) {
status = FX_ERR_IO_FAILURE;
}
return status;
}
static enum fx_status stream_write_char(struct stream_data *stream, fx_wchar c)
{
if (!(stream->s_cfg->s_mode & FX_STREAM_WRITE)) {
return FX_ERR_NOT_SUPPORTED;
}
enum fx_status status = FX_ERR_NOT_SUPPORTED;
if (!stream->s_ops->s_write) {
return FX_ERR_NOT_SUPPORTED;
}
if (c == '\n') {
stream->s_private->s_add_indent = 1;
}
if (!stream->s_private->s_istack_size) {
return __write_char(stream, c);
}
if (stream->s_private->s_add_indent && c != '\n') {
int indent = current_indent(stream);
for (int i = 0; i < indent; i++) {
__write_char(stream, ' ');
__write_char(stream, ' ');
}
stream->s_private->s_add_indent = 0;
}
__write_char(stream, c);
if (c == '\n') {
stream->s_private->s_add_indent = 1;
}
return FX_SUCCESS;
}
static enum fx_status stream_read_bytes(
struct stream_data *stream, void *buf, size_t count, size_t *nr_read)
{
if (!(stream->s_cfg->s_mode & FX_STREAM_READ)) {
return FX_ERR_NOT_SUPPORTED;
}
enum fx_status status = FX_ERR_NOT_SUPPORTED;
if (!stream->s_ops->s_read) {
return status;
}
return stream->s_ops->s_read(stream->s_obj, buf, count, nr_read);
}
static enum fx_status stream_read_line(struct stream_data *stream, char *s, size_t max)
{
if (!(stream->s_cfg->s_mode & FX_STREAM_READ)) {
return FX_ERR_NOT_SUPPORTED;
}
enum fx_status status = FX_SUCCESS;
size_t i = 0;
fx_wchar c = 0;
while (1) {
if (i >= max) {
break;
}
status = stream_read_char(stream, &c);
if (status != FX_SUCCESS) {
break;
}
if (c == '\n') {
break;
}
s[i++] = c;
s[i] = '\0';
}
return FX_SUCCESS;
}
static enum fx_status stream_read_line_s(
struct stream_data *src, struct stream_data *dest)
{
if (!(src->s_cfg->s_mode & FX_STREAM_READ)) {
return FX_ERR_NOT_SUPPORTED;
}
if (!(dest->s_cfg->s_mode & FX_STREAM_WRITE)) {
return FX_ERR_NOT_SUPPORTED;
}
enum fx_status status = FX_SUCCESS;
size_t i = 0;
fx_wchar c = 0;
while (1) {
status = stream_read_char(src, &c);
if (status != FX_SUCCESS) {
break;
}
stream_write_char(dest, c);
i++;
if (c == '\n') {
break;
}
}
if (status == FX_ERR_NO_DATA && i > 0) {
status = FX_SUCCESS;
}
return status;
}
static enum fx_status stream_read_line_to_bstr(
struct stream_data *src, struct fx_bstr *dest)
{
if (!(src->s_cfg->s_mode & FX_STREAM_READ)) {
return FX_ERR_NOT_SUPPORTED;
}
enum fx_status status = FX_SUCCESS;
size_t i = 0;
fx_wchar c = 0;
while (1) {
status = stream_read_char(src, &c);
if (status != FX_SUCCESS) {
break;
}
fx_bstr_write_char(dest, c);
i++;
if (c == '\n') {
break;
}
}
if (status == FX_ERR_NO_DATA && i > 0) {
status = FX_SUCCESS;
}
return status;
}
static enum fx_status stream_write_bytes(
struct stream_data *stream, const void *buf, size_t count, size_t *nr_written)
{
if (!(stream->s_cfg->s_mode & FX_STREAM_WRITE)) {
return FX_ERR_NOT_SUPPORTED;
}
enum fx_status status = FX_ERR_NOT_SUPPORTED;
if (!stream->s_ops->s_write) {
return status;
}
return stream->s_ops->s_write(stream->s_obj, buf, count, nr_written);
}
static enum fx_status stream_read_all_bytes(
struct stream_data *stream, void *p, size_t max, size_t *out_nr_read)
{
if (!(stream->s_cfg->s_mode & FX_STREAM_READ)) {
return FX_ERR_NOT_SUPPORTED;
}
enum fx_status status = FX_SUCCESS;
size_t nr_read = 0;
unsigned char *s = p;
while (nr_read < max) {
int c;
status = stream_read_char(stream, &c);
if (status != FX_SUCCESS) {
break;
}
s[nr_read++] = c;
}
if (status == FX_ERR_NO_DATA && nr_read > 0) {
status = FX_SUCCESS;
}
*out_nr_read = nr_read;
return status;
}
static enum fx_status stream_read_all_bytes_s(
struct stream_data *src, struct stream_data *dest,
struct fx_stream_buffer_p *buffer, size_t *out_nr_read)
{
if (!(src->s_cfg->s_mode & FX_STREAM_READ)) {
return FX_ERR_NOT_SUPPORTED;
}
if (!(dest->s_cfg->s_mode & FX_STREAM_WRITE)) {
return FX_ERR_NOT_SUPPORTED;
}
if (!buffer) {
return FX_ERR_INVALID_ARGUMENT;
}
if (src->s_ops->s_seek && dest->s_ops->s_reserve) {
size_t offset = stream_cursor(src);
stream_seek(src, 0, FX_STREAM_SEEK_END);
size_t length = stream_cursor(src);
stream_seek(src, offset, FX_STREAM_SEEK_START);
stream_reserve(dest, length);
}
enum fx_status status = FX_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 != FX_SUCCESS) {
break;
}
status = stream_write_bytes(dest, buffer->p_buf, r, &w);
nr_read += w;
if (status != FX_SUCCESS || w != buffer->p_buf_len) {
break;
}
}
if (status == FX_ERR_NO_DATA && nr_read > 0) {
status = FX_SUCCESS;
}
if (out_nr_read) {
*out_nr_read = nr_read;
}
return status;
}
static enum fx_status stream_read_all_bytes_to_bstr_s(
struct stream_data *src, struct fx_bstr *dest,
struct fx_stream_buffer_p *buffer, size_t *out_nr_read)
{
if (!(src->s_cfg->s_mode & FX_STREAM_READ)) {
return FX_ERR_NOT_SUPPORTED;
}
if (!buffer) {
return FX_ERR_INVALID_ARGUMENT;
}
if (src->s_ops->s_seek) {
size_t offset = stream_cursor(src);
stream_seek(src, 0, FX_STREAM_SEEK_END);
size_t length = stream_cursor(src);
stream_seek(src, offset, FX_STREAM_SEEK_START);
fx_bstr_reserve(dest, length);
}
enum fx_status status = FX_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 != FX_SUCCESS) {
break;
}
status = fx_bstr_write_chars(dest, buffer->p_buf, r, &w);
nr_read += w;
if (status != FX_SUCCESS || w != buffer->p_buf_len) {
break;
}
}
if (status == FX_ERR_NO_DATA && nr_read > 0) {
status = FX_SUCCESS;
}
if (out_nr_read) {
*out_nr_read = nr_read;
}
return status;
}
static enum fx_status stream_write_string(
struct stream_data *stream, const char *s, size_t *nr_written)
{
size_t i;
enum fx_status status = FX_SUCCESS;
for (i = 0; s[i]; i++) {
status = stream_write_char(stream, s[i]);
if (!FX_OK(status)) {
break;
}
}
if (nr_written) {
*nr_written = i;
}
return status;
}
static fx_stream *init_stdio_stream(FILE *fp, fx_stream_mode mode)
{
fx_stdio_stream *stream = fx_object_create(FX_TYPE_STDIO_STREAM);
if (!stream) {
return NULL;
}
struct fx_stdio_stream_p *p
= fx_object_get_private(stream, FX_TYPE_STDIO_STREAM);
fx_stream_cfg *cfg = fx_object_get_protected(stream, FX_TYPE_STREAM);
p->s_fp = fp;
cfg->s_mode = mode;
return stream;
}
static enum fx_status stream_push_indent(struct stream_data *stream, int indent)
{
if (!(stream->s_cfg->s_mode & FX_STREAM_WRITE)) {
return FX_ERR_NOT_SUPPORTED;
}
if (stream->s_cfg->s_mode & FX_STREAM_BINARY) {
return FX_ERR_NOT_SUPPORTED;
}
if (!stream->s_private->s_istack) {
stream->s_private->s_istack = calloc(4, sizeof(int));
stream->s_private->s_istack_size = 4;
stream->s_private->s_istack_ptr = 0;
}
if (stream->s_private->s_istack_ptr + 1 >= stream->s_private->s_istack_size) {
int *buf = realloc(
stream->s_private->s_istack,
(stream->s_private->s_istack_size + 4) * sizeof(int));
if (!buf) {
return FX_ERR_NO_MEMORY;
}
stream->s_private->s_istack = buf;
stream->s_private->s_istack_size += 4;
}
int cur_indent
= stream->s_private->s_istack[stream->s_private->s_istack_ptr];
stream->s_private->s_istack[++stream->s_private->s_istack_ptr]
= cur_indent + indent;
return FX_SUCCESS;
}
static enum fx_status stream_pop_indent(struct stream_data *stream)
{
if (!(stream->s_cfg->s_mode & FX_STREAM_WRITE)) {
return FX_ERR_NOT_SUPPORTED;
}
if (stream->s_cfg->s_mode & FX_STREAM_BINARY) {
return FX_ERR_NOT_SUPPORTED;
}
if (!stream->s_private->s_istack || !stream->s_private->s_istack_size
|| !stream->s_private->s_istack_ptr) {
return FX_SUCCESS;
}
stream->s_private->s_istack_ptr--;
return FX_SUCCESS;
}
static void fctprintf_callback(char c, void *p)
{
struct stream_data *stream = p;
stream_write_char(stream, c);
}
/*** PUBLIC FUNCTIONS *********************************************************/
fx_stream *z__fx_stream_get_stdin(void)
{
if (!stdio[IDX_STDIN]) {
stdio[IDX_STDIN] = init_stdio_stream(stdin, FX_STREAM_READ);
}
return stdio[IDX_STDIN];
}
fx_stream *z__fx_stream_get_stdout(void)
{
if (!stdio[IDX_STDOUT]) {
stdio[IDX_STDOUT] = init_stdio_stream(stdout, FX_STREAM_WRITE);
}
return stdio[IDX_STDOUT];
}
fx_stream *z__fx_stream_get_stderr(void)
{
if (!stdio[IDX_STDERR]) {
stdio[IDX_STDERR] = init_stdio_stream(stderr, FX_STREAM_WRITE);
}
return stdio[IDX_STDERR];
}
fx_stream_buffer *fx_stream_buffer_create_dynamic(size_t buffer_size)
{
fx_stream_buffer *buffer = fx_object_create(FX_TYPE_STREAM_BUFFER);
if (!buffer) {
return NULL;
}
struct fx_stream_buffer_p *p
= fx_object_get_private(buffer, FX_TYPE_STREAM_BUFFER);
p->p_buf = malloc(buffer_size);
if (!p->p_buf) {
fx_stream_buffer_unref(buffer);
return NULL;
}
p->p_buf_len = buffer_size;
p->p_flags = FX_STREAM_BUFFER_F_DYNAMIC;
return buffer;
}
fx_stream_buffer *fx_stream_buffer_create(void *buf, size_t len)
{
fx_stream_buffer *buffer = fx_object_create(FX_TYPE_STREAM_BUFFER);
if (!buffer) {
return NULL;
}
struct fx_stream_buffer_p *p
= fx_object_get_private(buffer, FX_TYPE_STREAM_BUFFER);
p->p_buf = buf;
p->p_buf_len = len;
p->p_flags = 0;
return buffer;
}
fx_stream *fx_stream_open_fp(FILE *fp)
{
return init_stdio_stream(fp, FX_STREAM_READ | FX_STREAM_WRITE);
}
enum fx_status fx_stream_reserve(fx_stream *stream, size_t len)
{
if (IS_BSTR(stream)) {
return FX_ERR_NOT_SUPPORTED;
}
FX_CLASS_DISPATCH_VIRTUAL(
fx_stream, FX_TYPE_STREAM, FX_ERR_NOT_SUPPORTED, s_reserve, stream,
len);
}
enum fx_status fx_stream_seek(
fx_stream *stream, long long offset, fx_stream_seek_origin origin)
{
if (IS_BSTR(stream)) {
return FX_ERR_NOT_SUPPORTED;
}
FX_CLASS_DISPATCH_VIRTUAL(
fx_stream, FX_TYPE_STREAM, FX_ERR_NOT_SUPPORTED, s_seek, stream,
offset, origin);
}
size_t fx_stream_cursor(const fx_stream *stream)
{
if (IS_BSTR(stream)) {
return fx_bstr_get_size((fx_bstr *)stream);
}
STREAM_DISPATCH_VIRTUAL_0(stream_cursor, stream);
}
enum fx_status fx_stream_push_indent(fx_stream *strp, int indent)
{
if (IS_BSTR(strp)) {
return fx_bstr_push_indent((fx_bstr *)strp, indent);
}
STREAM_DISPATCH_VIRTUAL(stream_push_indent, strp, indent);
}
enum fx_status fx_stream_pop_indent(fx_stream *strp)
{
if (IS_BSTR(strp)) {
return fx_bstr_pop_indent((fx_bstr *)strp);
}
STREAM_DISPATCH_VIRTUAL_0(stream_pop_indent, strp);
}
enum fx_status fx_stream_read_char(fx_stream *strp, int *c)
{
if (IS_BSTR(strp)) {
return FX_ERR_NOT_SUPPORTED;
}
STREAM_DISPATCH_VIRTUAL(stream_read_char, strp, c);
}
enum fx_status fx_stream_read_bytes(
fx_stream *strp, void *buf, size_t count, size_t *nr_read)
{
if (IS_BSTR(strp)) {
return FX_ERR_NOT_SUPPORTED;
}
STREAM_DISPATCH_VIRTUAL(stream_read_bytes, strp, buf, count, nr_read);
}
enum fx_status fx_stream_read_line(fx_stream *strp, char *s, size_t max)
{
if (IS_BSTR(strp)) {
return FX_ERR_NOT_SUPPORTED;
}
STREAM_DISPATCH_VIRTUAL(stream_read_line, strp, s, max);
}
enum fx_status fx_stream_read_line_s(fx_stream *src, fx_stream *dest)
{
if (IS_BSTR(src)) {
return FX_ERR_NOT_SUPPORTED;
}
enum fx_status status;
struct stream_data src_p, dest_p;
status = stream_get_data(src, &src_p);
if (!FX_OK(status)) {
return status;
}
if (IS_BSTR(dest)) {
return stream_read_line_to_bstr(&src_p, (fx_bstr *)dest);
}
status = stream_get_data(dest, &dest_p);
if (!FX_OK(status)) {
return status;
}
return stream_read_line_s(&src_p, &dest_p);
}
enum fx_status fx_stream_read_all_bytes(
fx_stream *stream, void *p, size_t max, size_t *out_nr_read)
{
if (IS_BSTR(stream)) {
return FX_ERR_NOT_SUPPORTED;
}
STREAM_DISPATCH_VIRTUAL(stream_read_all_bytes, stream, p, max, out_nr_read);
}
enum fx_status fx_stream_read_all_bytes_s(
fx_stream *src, fx_stream *dest, fx_stream_buffer *buffer, size_t *out_nr_read)
{
if (IS_BSTR(src)) {
return FX_ERR_NOT_SUPPORTED;
}
enum fx_status status;
struct stream_data src_p, dest_p;
struct fx_stream_buffer_p *buffer_p;
status = stream_get_data(src, &src_p);
if (!FX_OK(status)) {
return status;
}
buffer_p = fx_object_get_private(buffer, FX_TYPE_STREAM_BUFFER);
if (!buffer_p) {
return FX_ERR_INVALID_ARGUMENT;
}
if (IS_BSTR(dest)) {
return stream_read_all_bytes_to_bstr_s(
&src_p, (fx_bstr *)dest, buffer_p, out_nr_read);
}
status = stream_get_data(dest, &dest_p);
if (!FX_OK(status)) {
return status;
}
return stream_read_all_bytes_s(&src_p, &dest_p, buffer_p, out_nr_read);
}
enum fx_status fx_stream_write_char(fx_stream *stream, fx_wchar c)
{
if (IS_BSTR(stream)) {
return fx_bstr_write_char((fx_bstr *)stream, c);
}
STREAM_DISPATCH_VIRTUAL(stream_write_char, stream, c);
}
enum fx_status fx_stream_write_string(
fx_stream *stream, const char *s, size_t *nr_written)
{
if (IS_BSTR(stream)) {
return fx_bstr_write_cstr((fx_bstr *)stream, s, nr_written);
}
STREAM_DISPATCH_VIRTUAL(stream_write_string, stream, s, nr_written);
}
enum fx_status fx_stream_write_bytes(
fx_stream *stream, const void *buf, size_t count, size_t *nr_written)
{
if (IS_BSTR(stream)) {
return fx_bstr_write_chars((fx_bstr *)stream, buf, count, nr_written);
}
STREAM_DISPATCH_VIRTUAL(stream_write_bytes, stream, buf, count, nr_written);
}
enum fx_status fx_stream_write_fmt(
fx_stream *stream, size_t *nr_written, const char *format, ...)
{
if (IS_BSTR(stream)) {
va_list arg;
va_start(arg, format);
fx_status w = fx_bstr_write_vfmt(
(fx_bstr *)stream, nr_written, format, arg);
va_end(arg);
return w;
}
struct stream_data p;
enum fx_status status = stream_get_data(stream, &p);
va_list arg;
va_start(arg, format);
int w = z__fx_fctprintf(fctprintf_callback, &p, format, arg);
va_end(arg);
if (nr_written) {
*nr_written = w;
}
return FX_SUCCESS;
}
enum fx_status fx_stream_write_vfmt(
fx_stream *stream, size_t *nr_written, const char *format, va_list arg)
{
if (IS_BSTR(stream)) {
return fx_bstr_write_vfmt((fx_bstr *)stream, nr_written, format, arg);
}
struct stream_data p;
enum fx_status status = stream_get_data(stream, &p);
int w = z__fx_fctprintf(fctprintf_callback, &p, format, arg);
if (nr_written) {
*nr_written = w;
}
return FX_SUCCESS;
}
/*** VIRTUAL FUNCTIONS ********************************************************/
static void stream_init(fx_object *obj, void *priv)
{
struct fx_stream_p *stream = priv;
}
static void stream_fini(fx_object *obj, void *priv)
{
struct fx_stream_p *stream = priv;
fx_stream_class *ops = fx_object_get_interface(obj, FX_TYPE_STREAM);
if (stream->s_istack) {
free(stream->s_istack);
}
if (ops->s_close) {
ops->s_close(obj);
}
}
static void stream_buffer_init(fx_object *obj, void *priv)
{
struct fx_stream_buffer_p *buffer = priv;
}
static void stream_buffer_fini(fx_object *obj, void *priv)
{
struct fx_stream_buffer_p *buffer = priv;
if (buffer->p_flags & FX_STREAM_BUFFER_F_DYNAMIC) {
free(buffer->p_buf);
}
}
static void stdio_stream_init(fx_object *obj, void *priv)
{
struct fx_stdio_stream_p *stream = priv;
}
static void stdio_stream_fini(fx_object *obj, void *priv)
{
struct fx_stdio_stream_p *stream = priv;
}
static enum fx_status stdio_read(
fx_stream *stream, void *out, size_t max, size_t *nr_read)
{
struct fx_stdio_stream_p *p
= fx_object_get_private(stream, FX_TYPE_STDIO_STREAM);
enum fx_status status = FX_SUCCESS;
size_t count = fread(out, 1, max, p->s_fp);
if (ferror(p->s_fp)) {
status = FX_ERR_IO_FAILURE;
}
*nr_read = count;
return status;
}
static enum fx_status stdio_write(
fx_stream *stream, const void *data, size_t count, size_t *nr_written)
{
struct fx_stdio_stream_p *p
= fx_object_get_private(stream, FX_TYPE_STDIO_STREAM);
enum fx_status status = FX_SUCCESS;
size_t w = fwrite(data, 1, count, p->s_fp);
if (ferror(p->s_fp)) {
status = FX_ERR_IO_FAILURE;
}
*nr_written = w;
return status;
}
static enum fx_status stdio_seek(
fx_stream *stream, long long offset, fx_stream_seek_origin origin)
{
struct fx_stdio_stream_p *p
= fx_object_get_private(stream, FX_TYPE_STDIO_STREAM);
int whence = 0;
switch (origin) {
case FX_STREAM_SEEK_START:
whence = SEEK_SET;
break;
case FX_STREAM_SEEK_CURRENT:
whence = SEEK_CUR;
break;
case FX_STREAM_SEEK_END:
whence = SEEK_END;
break;
default:
return FX_ERR_INVALID_ARGUMENT;
}
int ret = fseek(p->s_fp, offset, whence);
if (ret != 0) {
return FX_ERR_NOT_SUPPORTED;
}
return FX_SUCCESS;
}
static enum fx_status stdio_tell(const fx_stream *stream, size_t *cursor)
{
struct fx_stdio_stream_p *p
= fx_object_get_private(stream, FX_TYPE_STDIO_STREAM);
long pos = ftell(p->s_fp);
if (pos == -1L) {
return FX_ERR_NOT_SUPPORTED;
}
*cursor = (size_t)pos;
return FX_SUCCESS;
}
/*** CLASS DEFINITION *********************************************************/
// ---- fx_stream DEFINITION
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_stream)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
FX_INTERFACE_ENTRY(to_string) = NULL;
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
FX_TYPE_CLASS_DEFINITION_END(fx_stream)
FX_TYPE_DEFINITION_BEGIN(fx_stream)
FX_TYPE_ID(0xa2c98988, 0x30e5, 0x47c7, 0x88cd, 0x6c8ea79f69cd);
FX_TYPE_CLASS(fx_stream_class);
FX_TYPE_INSTANCE_PRIVATE(struct fx_stream_p);
FX_TYPE_INSTANCE_PROTECTED(fx_stream_cfg);
FX_TYPE_INSTANCE_INIT(stream_init);
FX_TYPE_INSTANCE_FINI(stream_fini);
FX_TYPE_DEFINITION_END(fx_stream)
// ---- fx_stream_buffer DEFINITION
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_stream_buffer)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
FX_INTERFACE_ENTRY(to_string) = NULL;
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
FX_TYPE_CLASS_DEFINITION_END(fx_stream_buffer)
FX_TYPE_DEFINITION_BEGIN(fx_stream_buffer)
FX_TYPE_ID(0x575c7be1, 0x665f, 0x41f8, 0xbfed, 0x6269a2985be0);
FX_TYPE_CLASS(fx_stream_buffer_class);
FX_TYPE_INSTANCE_PRIVATE(struct fx_stream_buffer_p);
FX_TYPE_INSTANCE_INIT(stream_buffer_init);
FX_TYPE_INSTANCE_FINI(stream_buffer_fini);
FX_TYPE_DEFINITION_END(fx_stream_buffer)
// ---- fx_stdio_stream DEFINITION
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_stdio_stream)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
FX_INTERFACE_ENTRY(to_string) = NULL;
FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
FX_TYPE_CLASS_INTERFACE_BEGIN(fx_stream, FX_TYPE_STREAM)
FX_INTERFACE_ENTRY(s_close) = NULL;
FX_INTERFACE_ENTRY(s_seek) = stdio_seek;
FX_INTERFACE_ENTRY(s_tell) = stdio_tell;
FX_INTERFACE_ENTRY(s_getc) = NULL;
FX_INTERFACE_ENTRY(s_read) = stdio_read;
FX_INTERFACE_ENTRY(s_write) = stdio_write;
FX_INTERFACE_ENTRY(s_reserve) = NULL;
FX_TYPE_CLASS_INTERFACE_END(fx_stream, FX_TYPE_STREAM)
FX_TYPE_CLASS_DEFINITION_END(fx_stdio_stream)
FX_TYPE_DEFINITION_BEGIN(fx_stdio_stream)
FX_TYPE_ID(0x67678926, 0xd0b7, 0x4f99, 0xb83c, 0x790927597645);
FX_TYPE_EXTENDS(FX_TYPE_STREAM);
FX_TYPE_CLASS(fx_stdio_stream_class);
FX_TYPE_INSTANCE_PRIVATE(struct fx_stdio_stream_p);
FX_TYPE_INSTANCE_INIT(stdio_stream_init);
FX_TYPE_INSTANCE_FINI(stdio_stream_fini);
FX_TYPE_DEFINITION_END(fx_stdio_stream)