2025-06-27 21:41:07 +01:00
|
|
|
#include "printf.h"
|
|
|
|
|
|
|
|
|
|
#include <blue/core/stream.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#define IDX_STDIN 0
|
|
|
|
|
#define IDX_STDOUT 1
|
|
|
|
|
#define IDX_STDERR 2
|
|
|
|
|
|
2025-07-31 11:13:18 +01:00
|
|
|
static enum b_status stdio_read(
|
2025-06-27 21:41:07 +01:00
|
|
|
struct b_stream *stream, unsigned char *out, size_t max, size_t *nr_read)
|
|
|
|
|
{
|
|
|
|
|
FILE *fp = stream->s_ptr;
|
|
|
|
|
enum b_status status = B_SUCCESS;
|
|
|
|
|
|
2025-07-30 17:49:56 +01:00
|
|
|
size_t count = fread(out, 1, max, fp);
|
2025-06-27 21:41:07 +01:00
|
|
|
|
2025-07-30 17:49:56 +01:00
|
|
|
if (ferror(fp)) {
|
|
|
|
|
status = B_ERR_IO_FAILURE;
|
2025-06-27 21:41:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*nr_read = count;
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-31 11:13:18 +01:00
|
|
|
static enum b_status stdio_write(
|
2025-06-27 21:41:07 +01:00
|
|
|
struct b_stream *stream, const unsigned char *data, size_t count,
|
|
|
|
|
size_t *nr_written)
|
|
|
|
|
{
|
|
|
|
|
FILE *fp = stream->s_ptr;
|
|
|
|
|
enum b_status status = B_SUCCESS;
|
2025-07-30 17:49:56 +01:00
|
|
|
size_t w = fwrite(data, 1, count, fp);
|
2025-06-27 21:41:07 +01:00
|
|
|
|
2025-07-30 17:49:56 +01:00
|
|
|
if (ferror(fp)) {
|
|
|
|
|
status = B_ERR_IO_FAILURE;
|
2025-06-27 21:41:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*nr_written = w;
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-31 11:13:18 +01:00
|
|
|
static enum b_status stdio_seek(
|
|
|
|
|
struct b_stream *stream, long long offset, b_stream_seek_origin origin)
|
|
|
|
|
{
|
|
|
|
|
FILE *fp = stream->s_ptr;
|
|
|
|
|
int whence = 0;
|
|
|
|
|
switch (origin) {
|
|
|
|
|
case B_STREAM_SEEK_START:
|
|
|
|
|
whence = SEEK_SET;
|
|
|
|
|
break;
|
|
|
|
|
case B_STREAM_SEEK_CURRENT:
|
|
|
|
|
whence = SEEK_CUR;
|
|
|
|
|
break;
|
|
|
|
|
case B_STREAM_SEEK_END:
|
|
|
|
|
whence = SEEK_END;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return B_ERR_INVALID_ARGUMENT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ret = fseek(fp, offset, whence);
|
|
|
|
|
if (ret != 0) {
|
|
|
|
|
return B_ERR_NOT_SUPPORTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return B_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-31 11:13:40 +01:00
|
|
|
static enum b_status stdio_tell(const struct b_stream *stream, size_t *cursor)
|
|
|
|
|
{
|
|
|
|
|
FILE *fp = stream->s_ptr;
|
|
|
|
|
long pos = ftell(fp);
|
|
|
|
|
if (pos == -1L) {
|
|
|
|
|
return B_ERR_NOT_SUPPORTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*cursor = (size_t)pos;
|
|
|
|
|
return B_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-27 21:41:07 +01:00
|
|
|
static struct b_stream stdio[] = {
|
|
|
|
|
[IDX_STDIN] = {
|
|
|
|
|
.s_mode = B_STREAM_READ,
|
|
|
|
|
.s_read = stdio_read,
|
2025-07-31 11:13:18 +01:00
|
|
|
.s_seek = stdio_seek,
|
2025-07-31 11:13:40 +01:00
|
|
|
.s_tell = stdio_tell,
|
2025-06-27 21:41:07 +01:00
|
|
|
.s_ptr = NULL, /* set to stdin (stdio.h) at runtime */
|
|
|
|
|
},
|
|
|
|
|
[IDX_STDOUT] = {
|
|
|
|
|
.s_mode = B_STREAM_WRITE,
|
|
|
|
|
.s_write = stdio_write,
|
2025-07-31 11:13:18 +01:00
|
|
|
.s_seek = stdio_seek,
|
2025-07-31 11:13:40 +01:00
|
|
|
.s_tell = stdio_tell,
|
2025-06-27 21:41:07 +01:00
|
|
|
.s_ptr = NULL, /* set to stdout (stdio.h) at runtime */
|
|
|
|
|
},
|
|
|
|
|
[IDX_STDERR] = {
|
|
|
|
|
.s_mode = B_STREAM_WRITE,
|
|
|
|
|
.s_write = stdio_write,
|
2025-07-31 11:13:18 +01:00
|
|
|
.s_seek = stdio_seek,
|
2025-07-31 11:13:40 +01:00
|
|
|
.s_tell = stdio_tell,
|
2025-06-27 21:41:07 +01:00
|
|
|
.s_ptr = NULL, /* set to stderr (stdio.h) at runtime */
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct b_stream *z__b_stream_get_stdin(void)
|
|
|
|
|
{
|
|
|
|
|
stdio[IDX_STDIN].s_ptr = stdin;
|
|
|
|
|
return &stdio[IDX_STDIN];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct b_stream *z__b_stream_get_stdout(void)
|
|
|
|
|
{
|
|
|
|
|
stdio[IDX_STDOUT].s_ptr = stdout;
|
|
|
|
|
return &stdio[IDX_STDOUT];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct b_stream *z__b_stream_get_stderr(void)
|
|
|
|
|
{
|
|
|
|
|
stdio[IDX_STDERR].s_ptr = stderr;
|
|
|
|
|
return &stdio[IDX_STDERR];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum b_status b_stream_pipeline_create(
|
|
|
|
|
size_t buffer_size, struct b_stream_pipeline **out)
|
|
|
|
|
{
|
|
|
|
|
struct b_stream_pipeline *pipeline = malloc(sizeof *pipeline);
|
|
|
|
|
if (!pipeline) {
|
|
|
|
|
return B_ERR_NO_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memset(pipeline, 0x0, sizeof *pipeline);
|
|
|
|
|
|
|
|
|
|
pipeline->p_buf = malloc(buffer_size);
|
|
|
|
|
if (!pipeline->p_buf) {
|
|
|
|
|
free(pipeline);
|
|
|
|
|
return B_ERR_NO_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pipeline->p_buf_len = buffer_size;
|
|
|
|
|
pipeline->p_flags
|
|
|
|
|
= B_STREAM_PIPELINE_F_DYNAMIC | B_STREAM_PIPELINE_F_BUF_DYNAMIC;
|
|
|
|
|
|
|
|
|
|
*out = pipeline;
|
|
|
|
|
return B_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum b_status b_stream_pipeline_init(
|
|
|
|
|
void *p, size_t len, struct b_stream_pipeline *out)
|
|
|
|
|
{
|
|
|
|
|
memset(out, 0x0, sizeof *out);
|
|
|
|
|
|
|
|
|
|
out->p_buf = p;
|
|
|
|
|
out->p_buf_len = len;
|
|
|
|
|
|
|
|
|
|
return B_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum b_status b_stream_pipeline_destroy(struct b_stream_pipeline *pipeline)
|
|
|
|
|
{
|
|
|
|
|
if (pipeline->p_flags & B_STREAM_PIPELINE_F_BUF_DYNAMIC) {
|
|
|
|
|
free(pipeline->p_buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pipeline->p_flags & B_STREAM_PIPELINE_F_DYNAMIC) {
|
|
|
|
|
free(pipeline);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return B_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-30 17:49:56 +01:00
|
|
|
struct b_stream *b_stream_open_fp(FILE *fp)
|
|
|
|
|
{
|
|
|
|
|
struct b_stream *stream = malloc(sizeof *stream);
|
|
|
|
|
if (!stream) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memset(stream, 0x0, sizeof *stream);
|
|
|
|
|
|
|
|
|
|
stream->s_mode = B_STREAM_READ | B_STREAM_WRITE;
|
|
|
|
|
stream->s_ptr = fp;
|
|
|
|
|
stream->s_read = stdio_read;
|
|
|
|
|
stream->s_write = stdio_write;
|
2025-07-31 11:13:18 +01:00
|
|
|
stream->s_seek = stdio_seek;
|
2025-07-31 11:13:40 +01:00
|
|
|
stream->s_tell = stdio_tell;
|
2025-07-30 17:49:56 +01:00
|
|
|
|
|
|
|
|
return stream;
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-27 21:41:07 +01:00
|
|
|
enum b_status b_stream_close(b_stream *stream)
|
|
|
|
|
{
|
|
|
|
|
if (stream->s_istack) {
|
|
|
|
|
free(stream->s_istack);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (stream->s_close) {
|
|
|
|
|
stream->s_close(stream);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(stream->s_mode & Z__B_STREAM_STATIC)) {
|
|
|
|
|
free(stream);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return B_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum b_status b_stream_reserve(b_stream *stream, size_t len)
|
|
|
|
|
{
|
|
|
|
|
if (!stream->s_reserve) {
|
|
|
|
|
return B_ERR_NOT_SUPPORTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return stream->s_reserve(stream, len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum b_status b_stream_seek(
|
|
|
|
|
b_stream *stream, long long offset, b_stream_seek_origin origin)
|
|
|
|
|
{
|
|
|
|
|
if (!stream->s_seek) {
|
|
|
|
|
return B_ERR_NOT_SUPPORTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return stream->s_seek(stream, offset, origin);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t b_stream_cursor(const b_stream *stream)
|
|
|
|
|
{
|
2025-07-31 11:13:40 +01:00
|
|
|
if (!stream->s_tell) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t cursor = 0;
|
|
|
|
|
enum b_status status = stream->s_tell(stream, &cursor);
|
|
|
|
|
if (!B_OK(status)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cursor;
|
2025-06-27 21:41:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum b_status b_stream_push_indent(b_stream *stream, int indent)
|
|
|
|
|
{
|
|
|
|
|
if (!(stream->s_mode & B_STREAM_WRITE)) {
|
|
|
|
|
return B_ERR_NOT_SUPPORTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (stream->s_mode & B_STREAM_BINARY) {
|
|
|
|
|
return B_ERR_NOT_SUPPORTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!stream->s_istack) {
|
|
|
|
|
stream->s_istack = calloc(4, sizeof(int));
|
|
|
|
|
stream->s_istack_size = 4;
|
|
|
|
|
stream->s_istack_ptr = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-22 10:31:53 +01:00
|
|
|
if (stream->s_istack_ptr + 1 >= stream->s_istack_size) {
|
2025-06-27 21:41:07 +01:00
|
|
|
int *buf = realloc(
|
|
|
|
|
stream->s_istack,
|
|
|
|
|
(stream->s_istack_size + 4) * sizeof(int));
|
|
|
|
|
if (!buf) {
|
|
|
|
|
return B_ERR_NO_MEMORY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
stream->s_istack = buf;
|
|
|
|
|
stream->s_istack_size += 4;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int cur_indent = stream->s_istack[stream->s_istack_ptr];
|
|
|
|
|
stream->s_istack[++stream->s_istack_ptr] = cur_indent + indent;
|
|
|
|
|
|
|
|
|
|
return B_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum b_status b_stream_pop_indent(b_stream *stream)
|
|
|
|
|
{
|
|
|
|
|
if (!(stream->s_mode & B_STREAM_WRITE)) {
|
|
|
|
|
return B_ERR_NOT_SUPPORTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (stream->s_mode & B_STREAM_BINARY) {
|
|
|
|
|
return B_ERR_NOT_SUPPORTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!stream->s_istack || !stream->s_istack_size || !stream->s_istack_ptr) {
|
|
|
|
|
return B_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
stream->s_istack_ptr--;
|
|
|
|
|
return B_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum b_status b_stream_read_char(struct b_stream *stream, int *c)
|
|
|
|
|
{
|
|
|
|
|
if (!(stream->s_mode & B_STREAM_READ)) {
|
|
|
|
|
return B_ERR_NOT_SUPPORTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum b_status status = B_ERR_NOT_SUPPORTED;
|
|
|
|
|
|
|
|
|
|
if (stream->s_getc) {
|
|
|
|
|
status = stream->s_getc(stream, c);
|
|
|
|
|
} else if (stream->s_read) {
|
|
|
|
|
size_t r;
|
|
|
|
|
unsigned char v = 0;
|
|
|
|
|
status = stream->s_read(stream, &v, 1, &r);
|
|
|
|
|
|
|
|
|
|
*c = v;
|
|
|
|
|
|
|
|
|
|
if (status == B_SUCCESS && r < 1) {
|
|
|
|
|
status = B_ERR_NO_DATA;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum b_status b_stream_read_bytes(
|
|
|
|
|
struct b_stream *stream, void *buf, size_t count, size_t *nr_read)
|
|
|
|
|
{
|
|
|
|
|
if (!(stream->s_mode & B_STREAM_READ)) {
|
|
|
|
|
return B_ERR_NOT_SUPPORTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum b_status status = B_ERR_NOT_SUPPORTED;
|
|
|
|
|
|
|
|
|
|
if (!stream->s_read) {
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return stream->s_read(stream, buf, count, nr_read);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum b_status b_stream_read_line(struct b_stream *stream, char *s, size_t max)
|
|
|
|
|
{
|
|
|
|
|
if (!(stream->s_mode & B_STREAM_READ)) {
|
|
|
|
|
return B_ERR_NOT_SUPPORTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum b_status status = B_SUCCESS;
|
|
|
|
|
|
|
|
|
|
size_t i = 0;
|
|
|
|
|
int c = 0;
|
|
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
|
if (i >= max) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
status = b_stream_read_char(stream, &c);
|
|
|
|
|
if (status != B_SUCCESS) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (c == '\n') {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s[i++] = c;
|
|
|
|
|
s[i] = '\0';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return B_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum b_status b_stream_read_line_s(struct b_stream *src, b_stream *dest)
|
|
|
|
|
{
|
|
|
|
|
if (!(src->s_mode & B_STREAM_READ)) {
|
|
|
|
|
return B_ERR_NOT_SUPPORTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(dest->s_mode & B_STREAM_WRITE)) {
|
|
|
|
|
return B_ERR_NOT_SUPPORTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum b_status status = B_SUCCESS;
|
|
|
|
|
|
|
|
|
|
size_t i = 0;
|
|
|
|
|
int c = 0;
|
|
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
|
status = b_stream_read_char(src, &c);
|
|
|
|
|
if (status != B_SUCCESS) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (c == '\n') {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
b_stream_write_char(dest, c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return B_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum b_status b_stream_read_all_bytes(
|
|
|
|
|
struct b_stream *stream, void *p, size_t max, size_t *out_nr_read)
|
|
|
|
|
{
|
|
|
|
|
if (!(stream->s_mode & B_STREAM_READ)) {
|
|
|
|
|
return B_ERR_NOT_SUPPORTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum b_status status = B_SUCCESS;
|
|
|
|
|
size_t nr_read = 0;
|
|
|
|
|
unsigned char *s = p;
|
|
|
|
|
|
|
|
|
|
while (nr_read < max) {
|
|
|
|
|
int c;
|
|
|
|
|
status = b_stream_read_char(stream, &c);
|
|
|
|
|
if (status != B_SUCCESS) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s[nr_read++] = c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (status == B_ERR_NO_DATA && nr_read > 0) {
|
|
|
|
|
status = B_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*out_nr_read = nr_read;
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum b_status b_stream_read_all_bytes_s(
|
|
|
|
|
struct b_stream *src, struct b_stream *dest,
|
|
|
|
|
struct b_stream_pipeline *pipeline, size_t *out_nr_read)
|
|
|
|
|
{
|
|
|
|
|
if (!(src->s_mode & B_STREAM_READ)) {
|
|
|
|
|
return B_ERR_NOT_SUPPORTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(dest->s_mode & B_STREAM_WRITE)) {
|
|
|
|
|
return B_ERR_NOT_SUPPORTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!pipeline) {
|
|
|
|
|
return B_ERR_INVALID_ARGUMENT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (src->s_seek && dest->s_reserve) {
|
|
|
|
|
size_t offset = b_stream_cursor(src);
|
|
|
|
|
b_stream_seek(src, 0, B_STREAM_SEEK_END);
|
|
|
|
|
size_t length = b_stream_cursor(src);
|
|
|
|
|
b_stream_seek(src, offset, B_STREAM_SEEK_START);
|
|
|
|
|
|
|
|
|
|
b_stream_reserve(dest, length);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum b_status status = B_SUCCESS;
|
|
|
|
|
size_t nr_read = 0;
|
|
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
|
size_t r = 0, w = 0;
|
|
|
|
|
status = b_stream_read_bytes(
|
|
|
|
|
src, pipeline->p_buf, pipeline->p_buf_len, &r);
|
|
|
|
|
if (status != B_SUCCESS) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
status = b_stream_write_bytes(dest, pipeline->p_buf, r, &w);
|
|
|
|
|
nr_read += w;
|
|
|
|
|
|
|
|
|
|
if (status != B_SUCCESS || w != pipeline->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 __write_char(struct b_stream *stream, char c)
|
|
|
|
|
{
|
|
|
|
|
size_t w;
|
|
|
|
|
enum b_status status = stream->s_write(stream, (unsigned char *)&c, 1, &w);
|
|
|
|
|
|
|
|
|
|
if (status == B_SUCCESS && w < 1) {
|
|
|
|
|
status = B_ERR_IO_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int current_indent(struct b_stream *stream)
|
|
|
|
|
{
|
|
|
|
|
if (!stream->s_istack || !stream->s_istack_size) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return stream->s_istack[stream->s_istack_ptr];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum b_status b_stream_write_char(struct b_stream *stream, char c)
|
|
|
|
|
{
|
|
|
|
|
if (!(stream->s_mode & B_STREAM_WRITE)) {
|
|
|
|
|
return B_ERR_NOT_SUPPORTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum b_status status = B_ERR_NOT_SUPPORTED;
|
|
|
|
|
|
|
|
|
|
if (!stream->s_write) {
|
|
|
|
|
return B_ERR_NOT_SUPPORTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (c == '\n') {
|
|
|
|
|
stream->s_add_indent = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!stream->s_istack_size) {
|
|
|
|
|
return __write_char(stream, c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (stream->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_add_indent = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
__write_char(stream, c);
|
|
|
|
|
|
|
|
|
|
if (c == '\n') {
|
|
|
|
|
stream->s_add_indent = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return B_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum b_status b_stream_write_string(
|
|
|
|
|
b_stream *stream, const char *s, size_t *nr_written)
|
|
|
|
|
{
|
|
|
|
|
size_t i;
|
|
|
|
|
enum b_status status = B_SUCCESS;
|
|
|
|
|
|
|
|
|
|
for (i = 0; s[i]; i++) {
|
|
|
|
|
status = b_stream_write_char(stream, s[i]);
|
|
|
|
|
|
|
|
|
|
if (!B_OK(status)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (nr_written) {
|
|
|
|
|
*nr_written = i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum b_status b_stream_write_bytes(
|
2025-07-30 18:23:33 +01:00
|
|
|
struct b_stream *stream, const void *buf, size_t count, size_t *nr_written)
|
2025-06-27 21:41:07 +01:00
|
|
|
{
|
|
|
|
|
if (!(stream->s_mode & B_STREAM_WRITE)) {
|
|
|
|
|
return B_ERR_NOT_SUPPORTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum b_status status = B_ERR_NOT_SUPPORTED;
|
|
|
|
|
|
|
|
|
|
if (!stream->s_write) {
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return stream->s_write(stream, buf, count, nr_written);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void fctprintf_callback(char c, void *p)
|
|
|
|
|
{
|
|
|
|
|
struct b_stream *stream = p;
|
|
|
|
|
b_stream_write_char(stream, c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum b_status b_stream_write_fmt(
|
|
|
|
|
b_stream *stream, size_t *nr_written, const char *format, ...)
|
|
|
|
|
{
|
|
|
|
|
va_list arg;
|
|
|
|
|
va_start(arg, format);
|
|
|
|
|
int w = z__b_fctprintf(fctprintf_callback, stream, format, arg);
|
|
|
|
|
va_end(arg);
|
|
|
|
|
|
|
|
|
|
if (nr_written) {
|
|
|
|
|
*nr_written = w;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return B_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum b_status b_stream_write_vfmt(
|
|
|
|
|
b_stream *stream, size_t *nr_written, const char *format, va_list arg)
|
|
|
|
|
{
|
|
|
|
|
int w = z__b_fctprintf(fctprintf_callback, stream, format, arg);
|
|
|
|
|
|
|
|
|
|
if (nr_written) {
|
|
|
|
|
*nr_written = w;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return B_SUCCESS;
|
|
|
|
|
}
|