view th_ioctx.c @ 699:3707a823aa02

Fix to the previous commit. strdup the mode string since the argument is const.
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 10 Mar 2020 16:51:55 +0200
parents 29d9083dff1c
children ec8fe89576ff
line wrap: on
line source

/*
 * Simple I/O abstraction and context handling layer
 * Programmed and designed by Matti 'ccr' Hamalainen
 * (C) Copyright 2012-2020 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"


static void th_io_update_atime(th_ioctx *ctx)
{
    ctx->atime = time(NULL);
}


static void th_io_init(th_ioctx *ctx)
{
    memset(ctx, 0, sizeof(th_ioctx));
    ctx->line = 1;
}


void th_io_init_stdio(th_ioctx *ctx, FILE *fh)
{
    th_io_init(ctx);

    ctx->fops = &th_stdio_io_ops;
    ctx->data = (void *) fh;
}


th_ioctx * th_io_new(const th_ioctx_ops *fops, const char *filename)
{
    th_ioctx *ctx = th_malloc(sizeof(th_ioctx));
    if (ctx == NULL)
        return NULL;

    th_io_init(ctx);

    ctx->allocated = TRUE;
    ctx->fops = fops;

    ctx->filename = th_strdup(filename);
    ctx->fallocated = TRUE;
    if (filename != NULL && ctx->filename == NULL)
        goto err;

    return ctx;

err:
    th_io_close(ctx);
    return NULL;
}


int th_io_open(th_ioctx *ctx, const char *mode)
{
    if (ctx == NULL)
        return THERR_NULLPTR;

    if (mode != NULL && (ctx->mode = th_strdup(mode)) == NULL)
        return THERR_MALLOC;

    ctx->mallocated = TRUE;

    ctx->status = thfopen(ctx);

    return ctx->status;
}


int th_io_fopen(th_ioctx **pctx, const th_ioctx_ops *fops, const char *filename, const char *mode)
{
    th_ioctx *ctx;
    int res;

    if ((*pctx = ctx = th_io_new(fops, filename)) == NULL)
        return THERR_MALLOC;

    if ((res = th_io_open(ctx, mode)) != THERR_OK)
        goto err;

    return THERR_OK;

err:
    th_io_close(ctx);
    *pctx = NULL;
    return res;
}


int th_io_reopen(th_ioctx *ctx, const char *mode)
{
    if (ctx == NULL)
        return THERR_NULLPTR;

    thfclose(ctx);

    if (ctx->mallocated)
    {
        if ((ctx->status = th_pstr_cpy(&ctx->mode, mode)) != THERR_OK)
            return ctx->status;
    }
    else
    {
        ctx->mallocated = TRUE;
        if ((ctx->mode = th_strdup(mode)) == NULL)
            return THERR_MALLOC;
    }

    return (ctx->status = thfopen(ctx));
}


void th_io_close(th_ioctx *ctx)
{
    if (ctx != NULL)
    {
        thfclose(ctx);

        if (ctx->fallocated)
            th_free_r(&ctx->filename);

        if (ctx->mallocated)
            th_free_r(&ctx->mode);

        if (ctx->allocated)
            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;

    ctx->error = error;
    ctx->msg = msg;

    return TRUE;
}


int th_io_error_v(th_ioctx *ctx, const int err, const char *fmt, va_list ap)
{
    char *msg = th_strdup_vprintf(fmt, ap);

    if (ctx->error != NULL)
        ctx->error((struct th_ioctx *) ctx, err, msg);
    else
        THERR("'%s' #%" PRIu_SIZE_T ": %s\n", ctx->filename, ctx->line, msg);

    th_free(msg);
    return err;
}


int 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);
    return err;
}


void th_io_msg_v(th_ioctx *ctx, const int level, const char *fmt, va_list ap)
{
    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);
}


// thfopen() and thfclose() implementations are allowed to be NULL
int thfopen(th_ioctx *ctx)
{
    if (ctx == NULL || ctx->fops == NULL)
        return THERR_NULLPTR;

    if (ctx->fops->fopen == NULL)
        return THERR_OK;

    return ctx->fops->fopen(ctx);
}


void thfclose(th_ioctx *ctx)
{
    if (ctx == NULL || ctx->fops == NULL)
        return;

    if (ctx->fops->fclose != NULL)
        ctx->fops->fclose(ctx);
}


int thfreset(th_ioctx *ctx)
{
    th_io_update_atime(ctx);
    return ctx->fops->freset(ctx);
}


int thferror(th_ioctx *ctx)
{
    th_io_update_atime(ctx);
    return ctx->fops->ferror(ctx);
}


int thfseek(th_ioctx *ctx, const off_t offset, int whence)
{
    th_io_update_atime(ctx);
    return ctx->fops->fseek(ctx, offset, whence);
}


off_t thfsize(th_ioctx *ctx)
{
    th_io_update_atime(ctx);
    return ctx->fops->fsize(ctx);
}


off_t thftell(th_ioctx *ctx)
{
    th_io_update_atime(ctx);
    return ctx->fops->ftell(ctx);
}


BOOL thfeof(th_ioctx *ctx)
{
    th_io_update_atime(ctx);
    return ctx->fops->feof(ctx);
}


int thfgetc(th_ioctx *ctx)
{
    th_io_update_atime(ctx);
    return ctx->fops->fgetc(ctx);
}


int thfputc(int v, th_ioctx *ctx)
{
    th_io_update_atime(ctx);
    return ctx->fops->fputc(v, ctx);
}


size_t thfread(void *ptr, size_t size, size_t nmemb, th_ioctx *ctx)
{
    th_io_update_atime(ctx);
    return ctx->fops->fread(ptr, size, nmemb, ctx);
}


size_t thfwrite(const void *ptr, size_t size, size_t nmemb, th_ioctx *ctx)
{
    th_io_update_atime(ctx);
    return ctx->fops->fwrite(ptr, size, nmemb, ctx);
}


char *thfgets(char *str, int size, th_ioctx *ctx)
{
    char *ptr = str, *end = str + size - 1;
    int c;

    if (size <= 0)
        return NULL;

    while (ptr < end && (c = ctx->fops->fgetc(ctx)) != EOF)
    {
        *ptr++ = c;
        if (c == '\n')
            break;
    }
    *ptr = 0;

    return (ptr > str) ? str : NULL;
}


int thfputs(const char *ptr, th_ioctx *ctx)
{
    if (ctx->fops->fputs != NULL)
        return ctx->fops->fputs(ptr, ctx);

    const char *p = ptr;
    int rval = 0;
    while (*p && (rval = ctx->fops->fputc(*p, ctx)) != EOF) p++;
    return rval;
}


int thvfprintf(th_ioctx *ctx, const char *fmt, va_list ap)
{
    if (ctx->fops->vfprintf != NULL)
        return ctx->fops->vfprintf(ctx, fmt, ap);
    else
    {
        char *msg = th_strdup_printf(fmt, ap);
        int rval = thfputs(msg, ctx);
        th_free(msg);
        return rval;
    }
}


int thfprintf(th_ioctx *ctx, const char *fmt, ...)
{
    int rval;
    va_list ap;
    va_start(ap, fmt);
    rval = thvfprintf(ctx, fmt, ap);
    va_end(ap);
    return rval;
}


BOOL thfread_str(th_ioctx *ctx, void *ptr, const size_t len)
{
    return thfread(ptr, sizeof(uint8_t), len, ctx) == len;
}


BOOL thfread_u8(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_u8(th_ioctx *ctx, const uint8_t val)
{
    return thfwrite(&val, sizeof(uint8_t), 1, ctx) == 1;
}


//
// 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)

TH_DEFINE_FUNC(le64, uint64_t, LE64)
TH_DEFINE_FUNC(be64, uint64_t, BE64)

#undef TH_DEFINE_FUNC