Mercurial > hg > th-libs
changeset 202:b392293047da
Refactor I/O contexts. Breaks API and all that.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Thu, 11 Feb 2016 22:27:56 +0200 |
parents | e6a278f140c4 |
children | 7acdd3ab6900 |
files | th_ioctx.c th_ioctx.h |
diffstat | 2 files changed, 487 insertions(+), 79 deletions(-) [+] |
line wrap: on
line diff
--- a/th_ioctx.c Thu Feb 11 21:38:52 2016 +0200 +++ b/th_ioctx.c Thu Feb 11 22:27:56 2016 +0200 @@ -1,74 +1,90 @@ /* * Standard I/O context helpers * Programmed and designed by Matti 'ccr' Hamalainen - * (C) Copyright 2012 Tecnic Software productions (TNSP) + * (C) Copyright 2012,2016 Tecnic Software productions (TNSP) * * Please read file 'COPYING' for information on license and distribution. */ #include "th_ioctx.h" #include "th_string.h" +#include "th_endian.h" +#include <stdio.h> -/* Simple STD I/O contexts - */ -BOOL th_ioctx_init(th_ioctx_t *ctx, const char *filename, - void (*error)(struct _th_ioctx_t *, const int, const char *msg), - void (*msg)(struct _th_ioctx_t *, const char *msg)) +th_ioctx *th_io_new(const th_ioctx_ops *fops) { - if (ctx == NULL || filename == NULL) - return FALSE; + th_ioctx *ctx = th_malloc0(sizeof(th_ioctx)); + if (ctx == NULL) + return NULL; + + ctx->fops = fops; + + return ctx; +} + - memset(ctx, 0, sizeof(*ctx)); - ctx->error = error; - ctx->msg = msg; - ctx->line = 1; +int th_io_open(th_ioctx *ctx, const char *filename, const char *mode) +{ + if (ctx == NULL) + return THERR_NULLPTR; + + th_free_r(&ctx->filename); + th_free_r(&ctx->mode); - if ((ctx->filename = th_strdup(filename)) == NULL) - return FALSE; - - return TRUE; + ctx->filename = th_strdup(filename); + ctx->mode = th_strdup(mode); + + if (ctx->fops->fopen != NULL) + ctx->errno = ctx->fops->fopen(ctx); + + return ctx->errno; } -BOOL th_ioctx_open(th_ioctx_t *ctx, const char *filename, const char *mode, - void (*error)(struct _th_ioctx_t *, const int, const char *msg), - void (*msg)(struct _th_ioctx_t *, const char *msg)) +void th_io_close(th_ioctx *ctx) +{ + if (ctx != NULL) + { + if (ctx->fops->fclose != NULL) + ctx->fops->fclose(ctx); + } +} + + +void th_io_free(th_ioctx *ctx) { - if (!th_ioctx_init(ctx, filename, error, msg) || mode == NULL) + if (ctx != NULL) + { + th_io_close(ctx); + + th_free_r(&ctx->filename); + th_free_r(&ctx->mode); + + th_free(ctx); + } +} + + +BOOL th_io_set_handlers(th_ioctx *ctx, + void (*error)(th_ioctx *, const int, const char *msg), + void (*msg)(th_ioctx *, const int, const char *msg)) +{ + if (ctx == NULL) return FALSE; - if ((ctx->fp = fopen(filename, mode)) == NULL) - return FALSE; + ctx->error = error; + ctx->msg = msg; return TRUE; } -void th_ioctx_close(th_ioctx_t *ctx) +void th_io_error_v(th_ioctx *ctx, const int err, const char *fmt, va_list ap) { - if (ctx != NULL) - { - th_free(ctx->filename); - ctx->filename = NULL; - - if (ctx->fp != NULL) - fclose(ctx->fp); - ctx->fp = NULL; - } -} - - -void th_ioctx_error(th_ioctx_t *ctx, const int err, const char *fmt, ...) -{ - char *msg; - va_list ap; - - va_start(ap, fmt); - msg = th_strdup_vprintf(fmt, ap); - va_end(ap); + char *msg = th_strdup_vprintf(fmt, ap); if (ctx->error != NULL) - ctx->error(ctx, err, msg); + ctx->error((struct th_ioctx *) ctx, err, msg); else THERR("'%s' #%" TH_PRIu_SIZE_T ": %s\n", ctx->filename, ctx->line, msg); @@ -76,24 +92,334 @@ } -th_ioctx_t *th_ioctx_new(const char *filename, - void (*error)(struct _th_ioctx_t *, const int, const char *msg), - void (*msg)(struct _th_ioctx_t *, const char *msg)) +void th_io_error(th_ioctx *ctx, const int err, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + th_io_error_v(ctx, err, fmt, ap); + va_end(ap); +} + + +void th_io_msg_v(th_ioctx *ctx, const int level, const char *fmt, va_list ap) { - th_ioctx_t *ctx = th_malloc0(sizeof(th_ioctx_t)); + if (ctx->msg != NULL) + { + char *msg = th_strdup_vprintf(fmt, ap); + ctx->msg((struct th_ioctx *) ctx, level, msg); + th_free(msg); + } + else + THMSG_V(level, fmt, ap); +} + + +void th_io_msg(th_ioctx *ctx, const int level, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + th_io_msg_v(ctx, level, fmt, ap); + va_end(ap); +} + + +int thfreset(th_ioctx *ctx) +{ if (ctx == NULL) + return THERR_NULLPTR; + + if (ctx->fops == NULL || ctx->fops->freset == NULL) + return THERR_OK; + + return ctx->fops->freset(ctx); +} + + +int thferror(th_ioctx *ctx) +{ + ctx->atime = time(NULL); + return ctx->fops->ferror(ctx); +} + + +int thfseek(th_ioctx *ctx, const off_t offset, int whence) +{ + ctx->atime = time(NULL); + return ctx->fops->fseek(ctx, offset, whence); +} + + +off_t thfsize(th_ioctx *ctx) +{ + ctx->atime = time(NULL); + return ctx->fops->fsize(ctx); +} + + +off_t thftell(th_ioctx *ctx) +{ + ctx->atime = time(NULL); + return ctx->fops->ftell(ctx); +} + + +BOOL thfeof(th_ioctx *ctx) +{ + ctx->atime = time(NULL); + return ctx->fops->feof(ctx); +} + + +int thfgetc(th_ioctx *ctx) +{ + ctx->atime = time(NULL); + return ctx->fops->fgetc(ctx); +} + + +int thfputc(int v, th_ioctx *ctx) +{ + ctx->atime = time(NULL); + return ctx->fops->fputc(v, ctx); +} + + +size_t thfread(void *ptr, size_t size, size_t nmemb, th_ioctx *ctx) +{ + ctx->atime = time(NULL); + return ctx->fops->fread(ptr, size, nmemb, ctx); +} + + +size_t thfwrite(const void *ptr, size_t size, size_t nmemb, th_ioctx *ctx) +{ + ctx->atime = time(NULL); + return ctx->fops->fwrite(ptr, size, nmemb, ctx); +} + + +char *thfgets(char *str, int size, th_ioctx *ctx) +{ + char *ptr = str, *end = str + size - 1, c; + + if (size <= 0) return NULL; - - th_ioctx_init(ctx, filename, error, msg); - ctx->allocated = TRUE; - return ctx; + + while (ptr < end && (c = ctx->fops->fgetc(ctx)) != EOF) + { + *ptr++ = c; + if (c == '\n') + break; + } + *ptr++ = 0; + + return (ptr > str) ? str : NULL; +} + + +BOOL thfread_str(th_ioctx *ctx, void *ptr, const size_t len) +{ + return (thfread(ptr, sizeof(uint8_t), len, ctx) == len); +} + + +BOOL thfread_byte(th_ioctx *ctx, uint8_t *val) +{ + return (thfread(val, sizeof(uint8_t), 1, ctx) == 1); +} + + +BOOL thfwrite_str(th_ioctx *ctx, const void *ptr, const size_t len) +{ + return (thfwrite(ptr, sizeof(uint8_t), len, ctx) == len); +} + + +BOOL thfwrite_byte(th_ioctx *ctx, const uint8_t val) +{ + return (thfwrite(&val, sizeof(uint8_t), 1, ctx) == 1); } -void th_ioctx_free(th_ioctx_t *ctx) +// +// File routines for endian-dependant data +// +#define TH_DEFINE_FUNC(xname, xtype, xmacro) \ +BOOL thfread_ ## xname (th_ioctx *ctx, xtype *v) \ +{ \ + xtype result; \ + if (thfread(&result, sizeof( xtype ), 1, ctx) != 1) \ + return FALSE; \ + *v = TH_ ## xmacro ## _TO_NATIVE (result); \ + return TRUE; \ +} \ + \ +BOOL thfwrite_ ## xname (th_ioctx *ctx, const xtype v) \ +{ \ + xtype result = TH_NATIVE_TO_ ## xmacro (v); \ + if (thfwrite(&result, sizeof( xtype ), 1, ctx) != 1) \ + return FALSE; \ + return TRUE; \ +} + + +TH_DEFINE_FUNC(le16, uint16_t, LE16) +TH_DEFINE_FUNC(le32, uint32_t, LE32) + +TH_DEFINE_FUNC(be16, uint16_t, BE16) +TH_DEFINE_FUNC(be32, uint32_t, BE32) + +#ifdef TH_HAVE_64BIT +TH_DEFINE_FUNC(le64, uint64_t, LE64) +TH_DEFINE_FUNC(be64, uint64_t, BE64) +#endif + +#undef TH_DEFINE_FUNC + + +// +// stdio wrappers for I/O contexts +// +#define CTX_FH ((FILE *) ctx->data) + + +static int th_stdio_fopen(th_ioctx *ctx) { - th_ioctx_close(ctx); + ctx->data = (void *) fopen(ctx->filename, ctx->mode); + ctx->errno = th_get_error(); + return (CTX_FH != NULL) ? THERR_OK : THERR_FOPEN; +} + + +static void th_stdio_fclose(th_ioctx *ctx) +{ + if (CTX_FH != NULL) + { + fclose(CTX_FH); + ctx->data = NULL; + } +} + + +static int th_stdio_ferror(th_ioctx *ctx) +{ + return ctx->errno; +} + + +static off_t th_stdio_ftell(th_ioctx *ctx) +{ + return ftello(CTX_FH); +} + + +static int th_stdio_fseek(th_ioctx *ctx, const off_t pos, const int whence) +{ + int ret = fseeko(CTX_FH, pos, whence); + ctx->errno = th_get_error(); + return ret; +} + + +static int th_stdio_freset(th_ioctx *ctx) +{ + if (CTX_FH != NULL) + return th_stdio_fseek(ctx, 0, SEEK_SET); + else + return THERR_OK; +} + - if (ctx->allocated) - th_free(ctx); +static off_t th_stdio_fsize(th_ioctx *ctx) +{ + off_t savePos, fileSize; + + // Check if the size is cached + if (ctx->size != 0) + return ctx->size; + + // Get file size + if ((savePos = th_stdio_ftell(ctx)) < 0) + return -1; + + if (th_stdio_fseek(ctx, 0, SEEK_END) != 0) + return -1; + + if ((fileSize = th_stdio_ftell(ctx)) < 0) + return -1; + + if (th_stdio_fseek(ctx, savePos, SEEK_SET) != 0) + return -1; + + ctx->size = fileSize; + return fileSize; +} + + +static BOOL th_stdio_feof(th_ioctx *ctx) +{ + return feof(CTX_FH); +} + + +static int th_stdio_fgetc(th_ioctx *ctx) +{ + int ret = fgetc(CTX_FH); + ctx->errno = th_get_error(); + return ret; +} + + +static int th_stdio_fputc(int v, th_ioctx *ctx) +{ + int ret = fputc(v, CTX_FH); + ctx->errno = th_get_error(); + return ret; } + + +static size_t th_stdio_fread(void *ptr, size_t size, size_t nmemb, th_ioctx *ctx) +{ + size_t ret = fread(ptr, size, nmemb, CTX_FH); + ctx->errno = th_get_error(); + return ret; +} + + +static size_t th_stdio_fwrite(const void *ptr, size_t size, size_t nmemb, th_ioctx *ctx) +{ + size_t ret = fwrite(ptr, size, nmemb, CTX_FH); + ctx->errno = th_get_error(); + return ret; +} + + +static int th_stdio_vfprintf(th_ioctx *ctx, const char *format, va_list ap) +{ + int ret = vfprintf(CTX_FH, format, ap); + ctx->errno = th_get_error(); + return ret; +} + + +const th_ioctx_ops th_stdio_io_ops = +{ + "stdio", + + th_stdio_fopen, + th_stdio_fclose, + + th_stdio_freset, + th_stdio_ferror, + th_stdio_fseek, + th_stdio_fsize, + th_stdio_ftell, + th_stdio_feof, + th_stdio_fgetc, + th_stdio_fputc, + th_stdio_fread, + th_stdio_fwrite, + + th_stdio_vfprintf, +}; +
--- a/th_ioctx.h Thu Feb 11 21:38:52 2016 +0200 +++ b/th_ioctx.h Thu Feb 11 22:27:56 2016 +0200 @@ -1,7 +1,7 @@ /* - * Standard I/O context helpers + * Simple I/O abstraction and context handling layer * Programmed and designed by Matti 'ccr' Hamalainen - * (C) Copyright 2012 Tecnic Software productions (TNSP) + * (C) Copyright 2012,2016 Tecnic Software productions (TNSP) * * Please read file 'COPYING' for information on license and distribution. */ @@ -9,7 +9,7 @@ #define TH_IOCTX_H #include "th_util.h" -#include <stdio.h> +#include <time.h> #ifdef __cplusplus @@ -17,35 +17,117 @@ #endif -/* Simple STD I/O contexts - */ -typedef struct _th_ioctx_t +// Typedefs and structures +// +struct th_ioctx; +struct th_ioctx_ops; + + +typedef struct th_ioctx { - BOOL allocated; char *filename; - FILE *fp; + char *mode; + void *data; + time_t atime; + int64_t size; + int errno; size_t line; - void (*error)(struct _th_ioctx_t *, const int, const char *msg); - void (*msg)(struct _th_ioctx_t *, const char *msg); -} th_ioctx_t; + void (*error)(struct th_ioctx *, const int err, const char *msg); + void (*msg)(struct th_ioctx *, const int level, const char *msg); + + const struct th_ioctx_ops *fops; +} th_ioctx; + + +typedef struct th_ioctx_ops +{ + char *name; + + int (*fopen)(th_ioctx *ctx); + void (*fclose)(th_ioctx *ctx); + + int (*freset)(th_ioctx *ctx); + int (*ferror)(th_ioctx *ctx); + int (*fseek)(th_ioctx *ctx, const off_t, const int whence); + off_t (*fsize)(th_ioctx *ctx); + off_t (*ftell)(th_ioctx *ctx); + BOOL (*feof)(th_ioctx *ctx); + int (*fgetc)(th_ioctx *ctx); + int (*fputc)(int, th_ioctx *ctx); + size_t (*fread)(void *ptr, const size_t, const size_t, th_ioctx *ctx); + size_t (*fwrite)(const void *ptr, const size_t, const size_t, th_ioctx *ctx); + int (*vfprintf)(th_ioctx *ctx, const char *format, va_list ap); + +} th_ioctx_ops; + + +// +// Some basic iops +// +extern const th_ioctx_ops th_stdio_io_ops; + -BOOL th_ioctx_init(th_ioctx_t *ctx, const char *filename, - void (*error)(struct _th_ioctx_t *, const int, const char *msg), - void (*msg)(struct _th_ioctx_t *, const char *msg)); +// +// I/O context management functions +// +th_ioctx * th_io_new(const th_ioctx_ops *fops); +int th_io_open(th_ioctx *ctx, const char *filename, const char *mode); +void th_io_close(th_ioctx *ctx); +void th_io_free(th_ioctx *ctx); -BOOL th_ioctx_open(th_ioctx_t *ctx, const char *filename, const char *mode, - void (*error)(struct _th_ioctx_t *, const int, const char *msg), - void (*msg)(struct _th_ioctx_t *, const char *msg)); +BOOL th_io_set_handlers(th_ioctx *ctx, + void (*error)(th_ioctx *, const int, const char *msg), + void (*msg)(th_ioctx *, const int, const char *msg)); + +void th_io_error_v(th_ioctx *ctx, const int err, const char *fmt, va_list ap); +void th_io_msg_v(th_ioctx *ctx, const int level, const char *fmt, va_list ap); +void th_io_error(th_ioctx *ctx, const int err, const char *fmt, ...); +void th_io_msg(th_ioctx *ctx, const int level, const char *fmt, ...); + -void th_ioctx_close(th_ioctx_t *ctx); -void th_ioctx_error(th_ioctx_t *ctx, const int err, const char *fmt, ...); +// +// Basic I/O operations +// +int thfreset(th_ioctx *ctx); +int thferror(th_ioctx *ctx); +int thfseek(th_ioctx *ctx, const off_t, const int whence); +off_t thfsize(th_ioctx *ctx); +off_t thftell(th_ioctx *ctx); +BOOL thfeof(th_ioctx *ctx); +int thfgetc(th_ioctx *ctx); +int thfputc(int ch, th_ioctx *ctx); +size_t thfread(void *ptr, const size_t, const size_t, th_ioctx *ctx); +size_t thfwrite(const void *, const size_t, const size_t, th_ioctx *ctx); +char * thfgets(char *ptr, int size, th_ioctx *ctx); + +int thvfprintf(th_ioctx *ctx, const char *fmt, va_list ap); +int thfprintf(th_ioctx *ctx, const char *fmt, ...); -th_ioctx_t * th_ioctx_new(const char *filename, - void (*error)(struct _th_ioctx_t *, const int, const char *msg), - void (*msg)(struct _th_ioctx_t *, const char *msg)); -void th_ioctx_free(th_ioctx_t *ctx); +int thfread_str(th_ioctx *ctx, void *ptr, const size_t len); +BOOL thfread_byte(th_ioctx *ctx, uint8_t *); +int thfwrite_str(th_ioctx *ctx, const void *ptr, const size_t len); +BOOL thfwrite_byte(th_ioctx *ctx, const uint8_t); + + +// +// Endian-handling file read/write routines +// +#define TH_DEFINE_HEADER(xname, xtype) \ +BOOL thfread_ ## xname (th_ioctx *ctx, xtype *v); \ +BOOL thfwrite_ ## xname (th_ioctx *ctx, const xtype v); + +TH_DEFINE_HEADER(le16, uint16_t) +TH_DEFINE_HEADER(le32, uint32_t) + +TH_DEFINE_HEADER(be16, uint16_t) +TH_DEFINE_HEADER(be32, uint32_t) + +TH_DEFINE_HEADER(be64, uint64_t) +TH_DEFINE_HEADER(le64, uint64_t) + +#undef TH_DEFINE_HEADER #ifdef __cplusplus