298 lines
6.8 KiB
C
298 lines
6.8 KiB
C
#include <fx/core/stringstream.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#define DEFAULT_CAPACITY 15
|
|
|
|
/*** PRIVATE DATA *************************************************************/
|
|
|
|
struct fx_stringstream_p {
|
|
char *ss_buf;
|
|
size_t ss_ptr;
|
|
size_t ss_len;
|
|
size_t ss_max;
|
|
unsigned char ss_alloc;
|
|
};
|
|
|
|
/*** PRIVATE FUNCTIONS ********************************************************/
|
|
|
|
static enum fx_status __getc(struct fx_stringstream_p *ss, fx_wchar *out)
|
|
{
|
|
size_t available = ss->ss_len - ss->ss_ptr;
|
|
|
|
const char *p = ss->ss_buf + ss->ss_ptr;
|
|
|
|
size_t to_copy = fx_wchar_utf8_codepoint_stride(p);
|
|
if (to_copy > available) {
|
|
return FX_ERR_BAD_STATE;
|
|
}
|
|
|
|
fx_wchar c = fx_wchar_utf8_codepoint_decode(p);
|
|
*out = c;
|
|
|
|
if (c == FX_WCHAR_INVALID) {
|
|
return FX_ERR_BAD_STATE;
|
|
}
|
|
|
|
ss->ss_ptr += to_copy;
|
|
|
|
return FX_SUCCESS;
|
|
}
|
|
|
|
static enum fx_status __gets(
|
|
struct fx_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 FX_SUCCESS;
|
|
}
|
|
|
|
static enum fx_status __puts(
|
|
struct fx_stringstream_p *ss, const char *s, size_t len, size_t *nr_written)
|
|
{
|
|
size_t available = ss->ss_max - ss->ss_len;
|
|
size_t to_copy = len;
|
|
|
|
if (to_copy > available && ss->ss_alloc == 1) {
|
|
char *new_buf = realloc(ss->ss_buf, ss->ss_len + to_copy + 1);
|
|
if (!new_buf) {
|
|
return FX_ERR_NO_MEMORY;
|
|
}
|
|
|
|
ss->ss_buf = new_buf;
|
|
ss->ss_max = ss->ss_len + to_copy;
|
|
available = ss->ss_max - ss->ss_len;
|
|
}
|
|
|
|
if (available < to_copy) {
|
|
to_copy = available;
|
|
}
|
|
|
|
memcpy(ss->ss_buf + ss->ss_len, s, to_copy);
|
|
|
|
/* increment the length by the full string length, even if only a
|
|
* portion was copied */
|
|
ss->ss_len += len;
|
|
|
|
if (nr_written) {
|
|
*nr_written = to_copy;
|
|
}
|
|
|
|
return FX_SUCCESS;
|
|
}
|
|
|
|
static enum fx_status stringstream_reset(struct fx_stringstream_p *ss)
|
|
{
|
|
ss->ss_len = 0;
|
|
|
|
if (ss->ss_buf) {
|
|
*ss->ss_buf = 0;
|
|
}
|
|
|
|
return FX_SUCCESS;
|
|
}
|
|
|
|
static enum fx_status stringstream_reset_with_buffer(
|
|
struct fx_stringstream_p *ss, char *buf, size_t max)
|
|
{
|
|
ss->ss_len = 0;
|
|
|
|
if (ss->ss_buf && ss->ss_alloc) {
|
|
free(ss->ss_buf);
|
|
}
|
|
|
|
ss->ss_buf = buf;
|
|
ss->ss_max = max;
|
|
ss->ss_alloc = 0;
|
|
|
|
return FX_SUCCESS;
|
|
}
|
|
|
|
static size_t stringstream_get_length(const struct fx_stringstream_p *strv)
|
|
{
|
|
return strv->ss_len;
|
|
}
|
|
|
|
static const char *stringstream_ptr(const struct fx_stringstream_p *ss)
|
|
{
|
|
return ss->ss_buf;
|
|
}
|
|
|
|
static char *stringstream_steal(struct fx_stringstream_p *ss)
|
|
{
|
|
char *out = ss->ss_buf;
|
|
|
|
memset(ss, 0x0, sizeof *ss);
|
|
|
|
ss->ss_alloc = 1;
|
|
|
|
return out;
|
|
}
|
|
|
|
/*** PUBLIC FUNCTIONS *********************************************************/
|
|
|
|
fx_stringstream *fx_stringstream_create_with_buffer(char *buf, size_t max)
|
|
{
|
|
fx_stringstream *s = fx_object_create(FX_TYPE_STRINGSTREAM);
|
|
if (!s) {
|
|
return NULL;
|
|
}
|
|
|
|
fx_stream_cfg *cfg = fx_object_get_protected(s, FX_TYPE_STREAM);
|
|
struct fx_stringstream_p *p = fx_object_get_private(s, FX_TYPE_STRINGSTREAM);
|
|
|
|
cfg->s_mode = FX_STREAM_READ | FX_STREAM_WRITE | Z__FX_STREAM_STATIC;
|
|
|
|
p->ss_buf = buf;
|
|
p->ss_max = max;
|
|
p->ss_len = 0;
|
|
p->ss_alloc = 0;
|
|
|
|
return s;
|
|
}
|
|
|
|
fx_stringstream *fx_stringstream_create(void)
|
|
{
|
|
fx_stringstream *s = fx_object_create(FX_TYPE_STRINGSTREAM);
|
|
if (!s) {
|
|
return NULL;
|
|
}
|
|
|
|
fx_stream_cfg *cfg = fx_object_get_protected(s, FX_TYPE_STREAM);
|
|
struct fx_stringstream_p *p = fx_object_get_private(s, FX_TYPE_STRINGSTREAM);
|
|
|
|
cfg->s_mode = FX_STREAM_READ | FX_STREAM_WRITE | Z__FX_STREAM_STATIC;
|
|
|
|
p->ss_buf = malloc(DEFAULT_CAPACITY + 1);
|
|
if (!p->ss_buf) {
|
|
fx_stringstream_unref(s);
|
|
return NULL;
|
|
}
|
|
|
|
memset(p->ss_buf, 0x0, DEFAULT_CAPACITY + 1);
|
|
p->ss_max = DEFAULT_CAPACITY;
|
|
p->ss_len = 0;
|
|
p->ss_alloc = 1;
|
|
|
|
return s;
|
|
}
|
|
|
|
size_t fx_stringstream_get_length(const fx_stringstream *strv)
|
|
{
|
|
FX_CLASS_DISPATCH_STATIC_0(
|
|
FX_TYPE_STRINGSTREAM, stringstream_get_length, strv);
|
|
}
|
|
|
|
enum fx_status fx_stringstream_reset(fx_stringstream *strv)
|
|
{
|
|
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_STRINGSTREAM, stringstream_reset, strv);
|
|
}
|
|
|
|
enum fx_status fx_stringstream_reset_with_buffer(
|
|
fx_stringstream *strv, char *buf, size_t max)
|
|
{
|
|
FX_CLASS_DISPATCH_STATIC(
|
|
FX_TYPE_STRINGSTREAM, stringstream_reset_with_buffer, strv, buf,
|
|
max);
|
|
}
|
|
|
|
const char *fx_stringstream_ptr(const fx_stringstream *ss)
|
|
{
|
|
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_STRINGSTREAM, stringstream_ptr, ss);
|
|
}
|
|
|
|
char *fx_stringstream_steal(fx_stringstream *ss)
|
|
{
|
|
FX_CLASS_DISPATCH_STATIC_0(FX_TYPE_STRINGSTREAM, stringstream_steal, ss);
|
|
}
|
|
|
|
/*** PUBLIC ALIAS FUNCTIONS ***************************************************/
|
|
/*** VIRTUAL FUNCTIONS ********************************************************/
|
|
|
|
static void stringstream_init(fx_object *obj, void *priv)
|
|
{
|
|
struct fx_stringstream_p *stream = priv;
|
|
}
|
|
|
|
static void stringstream_fini(fx_object *obj, void *priv)
|
|
{
|
|
struct fx_stringstream_p *stream = priv;
|
|
|
|
if (stream->ss_alloc && stream->ss_buf) {
|
|
free(stream->ss_buf);
|
|
}
|
|
}
|
|
|
|
enum fx_status stream_getc(fx_stream *stream, fx_wchar *c)
|
|
{
|
|
struct fx_stringstream_p *s
|
|
= fx_object_get_private(stream, FX_TYPE_STRINGSTREAM);
|
|
|
|
enum fx_status status = __getc(s, c);
|
|
|
|
return status;
|
|
}
|
|
|
|
enum fx_status stream_read(fx_stream *stream, void *buf, size_t count, size_t *nr_read)
|
|
{
|
|
struct fx_stringstream_p *s
|
|
= fx_object_get_private(stream, FX_TYPE_STRINGSTREAM);
|
|
|
|
enum fx_status status = __gets(s, buf, count, nr_read);
|
|
|
|
return status;
|
|
}
|
|
|
|
enum fx_status stream_write(
|
|
fx_stream *stream, const void *buf, size_t count, size_t *nr_written)
|
|
{
|
|
struct fx_stringstream_p *s
|
|
= fx_object_get_private(stream, FX_TYPE_STRINGSTREAM);
|
|
|
|
enum fx_status status = __puts(s, (const char *)buf, count, nr_written);
|
|
|
|
return status;
|
|
}
|
|
|
|
/*** CLASS DEFINITION *********************************************************/
|
|
|
|
FX_TYPE_CLASS_DEFINITION_BEGIN(fx_stringstream)
|
|
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) = NULL;
|
|
FX_INTERFACE_ENTRY(s_tell) = NULL;
|
|
FX_INTERFACE_ENTRY(s_getc) = stream_getc;
|
|
FX_INTERFACE_ENTRY(s_read) = stream_read;
|
|
FX_INTERFACE_ENTRY(s_write) = stream_write;
|
|
FX_INTERFACE_ENTRY(s_reserve) = NULL;
|
|
FX_TYPE_CLASS_INTERFACE_END(fx_stream, FX_TYPE_STREAM)
|
|
FX_TYPE_CLASS_DEFINITION_END(fx_stringstream)
|
|
|
|
FX_TYPE_DEFINITION_BEGIN(fx_stringstream)
|
|
FX_TYPE_ID(0x508a609a, 0xfac5, 0x4d31, 0x843a, 0x44b68ad329f3);
|
|
FX_TYPE_EXTENDS(FX_TYPE_STREAM);
|
|
FX_TYPE_CLASS(fx_stringstream_class);
|
|
FX_TYPE_INSTANCE_PRIVATE(struct fx_stringstream_p);
|
|
FX_TYPE_INSTANCE_INIT(stringstream_init);
|
|
FX_TYPE_INSTANCE_FINI(stringstream_fini);
|
|
FX_TYPE_DEFINITION_END(fx_stringstream)
|