diff th_ioctx.c @ 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 28fd04f43a95
children 55f429dff750
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,
+};
+