mirror of
https://github.com/utkumaden/libmx.git
synced 2025-01-23 05:56:33 +01:00
Stream IO library.
This commit is contained in:
parent
8204780245
commit
c36b0ac253
53
include/mx/io/stream.h
Normal file
53
include/mx/io/stream.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#ifndef _MX_IO_STREAM_H_
|
||||||
|
#define _MX_IO_STREAM_H_
|
||||||
|
|
||||||
|
#include "mx/base.h"
|
||||||
|
|
||||||
|
typedef enum mx_open_flags
|
||||||
|
{
|
||||||
|
MX_OPEN_READ = 1 << 0,
|
||||||
|
MX_OPEN_WRITE = 1 << 1,
|
||||||
|
MX_OPEN_APPEND = 1 << 2,
|
||||||
|
MX_OPEN_NEW = 1 << 3,
|
||||||
|
} mx_open_flags;
|
||||||
|
|
||||||
|
typedef enum mx_seek_origin
|
||||||
|
{
|
||||||
|
MX_SEEK_START,
|
||||||
|
MX_SEEK_CURRENT,
|
||||||
|
MX_SEEK_END,
|
||||||
|
} mx_seek_origin;
|
||||||
|
|
||||||
|
typedef enum mx_stream_flags
|
||||||
|
{
|
||||||
|
MX_STREAM_OPEN = 1 << 0,
|
||||||
|
MX_STREAM_EOF = 1 << 1,
|
||||||
|
} mx_stream_flags;
|
||||||
|
|
||||||
|
typedef struct mx_stream_base_t
|
||||||
|
{
|
||||||
|
mx_stream_flags (*flags)(mx_stream_t str);
|
||||||
|
mx_len_t (*read)(mx_stream_t str, void *dst, mx_len_t size);
|
||||||
|
mx_len_t (*write)(mx_stream_t str, const void *src, mx_len_t size);
|
||||||
|
mx_len_t (*seek)(mx_stream_t str, mx_len_t offset, mx_seek_origin origin);
|
||||||
|
void (*close)(mx_stream_t str);
|
||||||
|
|
||||||
|
} mx_stream_base_t;
|
||||||
|
typedef const mx_stream_base_t* mx_stream_t;
|
||||||
|
|
||||||
|
MX_API mx_stream_t mx_get_stdin(void);
|
||||||
|
MX_API mx_stream_t mx_get_stdout(void);
|
||||||
|
MX_API mx_stream_t mx_get_stderr(void);
|
||||||
|
MX_API mx_stream_t mx_open(const char *file, mx_open_flags flags);
|
||||||
|
MX_API mx_stream_flags mx_sflags(mx_stream_t str);
|
||||||
|
MX_API mx_len_t mx_read(mx_stream_t str, void *dst, mx_len_t size);
|
||||||
|
MX_API mx_len_t mx_write(mx_stream_t str, const void *dst, mx_len_t size);
|
||||||
|
MX_API mx_len_t mx_seek(mx_stream_t str, mx_len_t offset, mx_seek_origin origin);
|
||||||
|
MX_API void mx_close(mx_stream_t str);
|
||||||
|
|
||||||
|
#define mx_stdin (mx_get_stdin())
|
||||||
|
#define mx_stdout (mx_get_stdout())
|
||||||
|
#define mx_stderr (mx_get_stderr())
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
217
src/stream.stdc.c
Normal file
217
src/stream.stdc.c
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
#include "mx/io/stream.h"
|
||||||
|
#include "mx/assert.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static mx_stream_flags mx_stdin_flags(mx_stream_t str)
|
||||||
|
{
|
||||||
|
return MX_STREAM_OPEN | (feof(stdin) ? MX_STREAM_EOF : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static mx_len_t mx_stdin_read(mx_stream_t str, void *dst, mx_len_t size)
|
||||||
|
{
|
||||||
|
return (mx_len_t)fread(dst, 1, (size_t)size, stdin);
|
||||||
|
}
|
||||||
|
|
||||||
|
MX_IMPL mx_stream_t mx_get_stdin(void)
|
||||||
|
{
|
||||||
|
const static mx_stream_base_t str = {
|
||||||
|
.flags = mx_stdin_flags,
|
||||||
|
.read = mx_stdin_read,
|
||||||
|
.write = NULL,
|
||||||
|
.seek = NULL,
|
||||||
|
.close = NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
return &str;
|
||||||
|
}
|
||||||
|
|
||||||
|
static mx_stream_flags mx_stdxxx_flags(mx_stream_t str)
|
||||||
|
{
|
||||||
|
return MX_STREAM_OPEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static mx_len_t mx_stdout_write(mx_stream_t str, const void *src, mx_len_t size)
|
||||||
|
{
|
||||||
|
return (mx_len_t)fwrite(src, 1, (size_t)size, stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static mx_len_t mx_stderr_write(mx_stream_t str, const void *src, mx_len_t size)
|
||||||
|
{
|
||||||
|
return (mx_len_t)fwrite(src, 1, (size_t)size, stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
MX_IMPL mx_stream_t mx_get_stdout(void)
|
||||||
|
{
|
||||||
|
const static mx_stream_base_t str = {
|
||||||
|
.flags = mx_stdxxx_flags,
|
||||||
|
.write = mx_stdout_write,
|
||||||
|
.read = NULL,
|
||||||
|
.seek = NULL,
|
||||||
|
.close = NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
return &str;
|
||||||
|
}
|
||||||
|
|
||||||
|
MX_IMPL mx_stream_t mx_get_stderr(void)
|
||||||
|
{
|
||||||
|
const static mx_stream_base_t str = {
|
||||||
|
.flags = mx_stdxxx_flags,
|
||||||
|
.write = mx_stderr_write,
|
||||||
|
.read = NULL,
|
||||||
|
.seek = NULL,
|
||||||
|
.close = NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
return &str;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct mx_stdc_stream_t
|
||||||
|
{
|
||||||
|
mx_stream_base_t base;
|
||||||
|
FILE *file;
|
||||||
|
} mx_stdc_stream_t;
|
||||||
|
|
||||||
|
#define THIS_FILE(x) (((mx_stdc_stream_t*)(str))->file)
|
||||||
|
|
||||||
|
static mx_stream_flags mx_stdc_flags(mx_stream_t str)
|
||||||
|
{
|
||||||
|
mx_stream_flags flags = 0;
|
||||||
|
FILE *f = THIS_FILE(str);
|
||||||
|
|
||||||
|
if (fileno(f) != -1)
|
||||||
|
flags |= MX_STREAM_OPEN;
|
||||||
|
if (feoff(f))
|
||||||
|
flags |= MX_STREAM_EOF;
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
static mx_len_t mx_stdc_read(mx_stream_t str, void *dst, mx_len_t size)
|
||||||
|
{
|
||||||
|
FILE *f = THIS_FILE(str);
|
||||||
|
return (mx_len_t)fread(dst, 1, (size_t)size, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static mx_len_t mx_stdc_write(mx_stream_t str, const void *src, mx_len_t size)
|
||||||
|
{
|
||||||
|
FILE *f = THIS_FILE(str);
|
||||||
|
return (mx_len_t)fwrite(src, 1, (size_t)size, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static mx_len_t mx_stdc_seek(mx_stream_t str, mx_len_t offset, mx_seek_origin origin)
|
||||||
|
{
|
||||||
|
FILE *f = THIS_FILE(str);
|
||||||
|
int stdc_origin;
|
||||||
|
|
||||||
|
switch (origin)
|
||||||
|
{
|
||||||
|
case MX_SEEK_START: stdc_origin = SEEK_SET; break;
|
||||||
|
case MX_SEEK_CURRENT: stdc_origin = SEEK_CUR; break;
|
||||||
|
case MX_SEEK_END: stdc_origin = SEEK_END; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(f, offset, stdc_origin);
|
||||||
|
return (mx_len_t)ftell(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mx_stdc_close(mx_stream_t str)
|
||||||
|
{
|
||||||
|
FILE *f = THIS_FILE(str);
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
free((void*)str);
|
||||||
|
}
|
||||||
|
|
||||||
|
const static mx_stream_base_t mx_stdc_stream_base =
|
||||||
|
{
|
||||||
|
.flags = mx_stdc_flags,
|
||||||
|
.read = mx_stdc_read,
|
||||||
|
.write = mx_stdc_write,
|
||||||
|
.seek = mx_stdc_seek,
|
||||||
|
.close = mx_stdc_close
|
||||||
|
};
|
||||||
|
|
||||||
|
MX_API mx_stream_t mx_open(const char *file, mx_open_flags flags)
|
||||||
|
{
|
||||||
|
MX_ASSERT_PTR(file, "File path cannot be null.");
|
||||||
|
|
||||||
|
char mode[16] = "b";
|
||||||
|
|
||||||
|
if (flags & MX_OPEN_READ)
|
||||||
|
{
|
||||||
|
strcat(mode, "r");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & MX_OPEN_WRITE)
|
||||||
|
{
|
||||||
|
strcat(mode, "w");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & MX_OPEN_APPEND)
|
||||||
|
{
|
||||||
|
strcat(mode, "a");
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *f = fopen(file, mode);
|
||||||
|
|
||||||
|
if (f == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
mx_stdc_stream_t *str = malloc(sizeof(*str));
|
||||||
|
memcpy(&str->base, &mx_stdc_stream_base, sizeof mx_stdc_stream_base);
|
||||||
|
|
||||||
|
if (!(flags & (MX_OPEN_APPEND|MX_OPEN_WRITE)))
|
||||||
|
{
|
||||||
|
str->base.write = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
MX_IMPL mx_len_t mx_read(mx_stream_t str, void *dst, mx_len_t size)
|
||||||
|
{
|
||||||
|
MX_ASSERT_SELFPTR(str);
|
||||||
|
MX_ASSERT_PTR(dst, "Destination cannot be null");
|
||||||
|
MX_ASSERT(size >= 0, "Must be non-negative.");
|
||||||
|
MX_ASSERT(str->read, "Stream has no reader.");
|
||||||
|
return str->read(str, dst, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
MX_IMPL mx_len_t mx_write(mx_stream_t str, void *dst, mx_len_t size)
|
||||||
|
{
|
||||||
|
MX_ASSERT_SELFPTR(str);
|
||||||
|
MX_ASSERT_PTR(dst, "Source cannot be null");
|
||||||
|
MX_ASSERT(size >= 0, "Must be non-negative.");
|
||||||
|
MX_ASSERT(str->write, "Stream has no writer.");
|
||||||
|
return str->write(str, dst, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
MX_IMPL mx_len_t mx_seek(mx_stream_t str, mx_len_t offset, mx_seek_origin origin)
|
||||||
|
{
|
||||||
|
MX_ASSERT_SELFPTR(str);
|
||||||
|
MX_ASSERT(str->seek, "Stream has no seeker.");
|
||||||
|
return str->seek(str, offset, origin);
|
||||||
|
}
|
||||||
|
|
||||||
|
MX_IMPL mx_stream_flags mx_sflags(mx_stream_t str)
|
||||||
|
{
|
||||||
|
MX_ASSERT_SELFPTR(str);
|
||||||
|
if (str->flags)
|
||||||
|
{
|
||||||
|
return str->flags(str);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MX_IMPL void mx_close(mx_stream_t str)
|
||||||
|
{
|
||||||
|
if (!str) return;
|
||||||
|
if (!str->close) return;
|
||||||
|
str->close(str);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user