view src/dmlib.c @ 2298:b5abfff07ca9

Add new DMGrowBuf helper functions dmGrowBufCopyOffsSize() and dmGrowBufConstCopyOffsSize().
author Matti Hamalainen <ccr@tnsp.org>
date Thu, 04 Jul 2019 10:54:16 +0300
parents 3d40a6767a4e
children 69a5af2eb1ea
line wrap: on
line source

#include "dmlib.h"
#include <errno.h>


int      dmVerbosity = 0;
char     *dmProgName = NULL,
         *dmProgDesc = NULL,
         *dmProgVersion = NULL,
         *dmProgAuthor = NULL,
         *dmProgLicense = NULL;


void dmInitProg(char *name, char *desc, char *version, char *author, char *license)
{
    dmProgName     = name;
    dmProgDesc     = desc;
    dmProgVersion  = version;
    dmProgAuthor   = author != NULL ? author : DM_PROG_AUTHOR;
    dmProgLicense  = license != NULL ? license : DM_PROG_LICENSE;
}


void dmPrintBanner(FILE *outFile, const char *name, const char *usage)
{
    fprintf(outFile, "%s", dmProgName);
    if (dmProgVersion != NULL)
        fprintf(outFile, " v%s", dmProgVersion);
    if (dmProgDesc != NULL)
        fprintf(outFile, " (%s)", dmProgDesc);
    fprintf(outFile, "\n");

    if (dmProgAuthor != NULL)
        fprintf(outFile, "%s\n", dmProgAuthor);

    if (dmProgLicense != NULL)
        fprintf(outFile, "%s\n", dmProgLicense);

    fprintf(outFile, "Usage: %s %s\n", name, usage);
}


void dmMsgVA(int level, const char *fmt, va_list ap)
{
    if (dmVerbosity >= level)
    {
        fprintf(stderr, "%s: ", dmProgName);
        vfprintf(stderr, fmt, ap);
    }
}


void dmPrintVA(int level, const char *fmt, va_list ap)
{
    if (dmVerbosity >= level)
    {
        vfprintf(stderr, fmt, ap);
    }
}


void dmMsg(int level, const char *fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);
    dmMsgVA(level, fmt, ap);
    va_end(ap);
}


void dmPrint(int level, const char *fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);
    dmPrintVA(level, fmt, ap);
    va_end(ap);
}


/* Memory handling routines
 */
void *dmMalloc(size_t len)
{
    return malloc(len);
}


void *dmMalloc0(size_t len)
{
    return calloc(1, len);
}


void *dmCalloc(size_t n, size_t len)
{
    return calloc(n, len);
}


void *dmRealloc(void *ptr, size_t len)
{
    return realloc(ptr, len);
}


void dmFree(void *ptr)
{
    /* Check for NULL pointers for portability due to some libc
     * implementations not handling free(NULL) too well.
     */
    if (ptr) free(ptr);
}


void dmFreeRReal(void **ptr)
{
    if (ptr != NULL)
    {
        dmFree(*ptr);
        *ptr = NULL;
    }
}


#ifndef DM_HAVE_MEMSET
void * dmMemset(void *ptr, const int c, size_t n)
{
    Uint8 *p = (Uint8 *) ptr;

    while (n--)
        *p++ = c;

    return ptr;
}
#endif


BOOL dmGetIntVal(const char *str, unsigned int *value, BOOL *neg)
{
    int ch;
    BOOL hex = FALSE;

    // Is the value negative?
    if (*str == '-')
    {
        if (neg == NULL)
            return FALSE;

        *neg = TRUE;
        str++;
    }
    else
    if (neg != NULL)
        *neg = FALSE;

    // Is it hexadecimal?
    if (*str == '$')
    {
        hex = TRUE;
        str++;
    }
    else
    if (str[0] == '0' && str[1] == 'x')
    {
        hex = TRUE;
        str += 2;
    }

    // Parse the value
    *value = 0;
    if (hex)
    {
        while ((ch = *str++))
        {
            if (ch >= '0' && ch <= '9')
            {
                *value <<= 4;
                *value |= ch - '0';
            }
            else
            if (ch >= 'A' && ch <= 'F')
            {
                *value <<= 4;
                *value |= ch - 'A' + 10;
            }
            else
            if (ch >= 'a' && ch <= 'f')
            {
                *value <<= 4;
                *value |= ch - 'a' + 10;
            }
            else
                return FALSE;
        }
    }
    else
    {
        while ((ch = *str++))
        {
            if (ch >= '0' && ch <= '9')
            {
                *value *= 10;
                *value += ch - '0';
            }
            else
                return FALSE;
        }
    }
    return TRUE;
}


/*
 * Error handling and messages
 */
#define DM_SYSTEM_ERRORS 100000


int dmGetErrno()
{
    return DM_SYSTEM_ERRORS + errno;
}


const char *dmErrorStr(const int error)
{
    if (error >= DM_SYSTEM_ERRORS)
        return strerror(error - DM_SYSTEM_ERRORS);

    switch (error)
    {
        case DMERR_OK:             return "No error";
        case DMERR_FOPEN:          return "File open error";
        case DMERR_FREAD:          return "Read error";
        case DMERR_FWRITE:         return "Write error";
        case DMERR_FSEEK:          return "Seek error";
        case DMERR_NOT_FOUND:      return "Resource not found";

        case DMERR_INVALID_DATA:   return "Invalid data";
        case DMERR_MALLOC:         return "Memory allocation failure";
        case DMERR_ALREADY_INIT:   return "Already initialized";
        case DMERR_INIT_FAIL:      return "Initialization failed";
        case DMERR_INVALID_ARGS:   return "Invalid arguments";

        case DMERR_NULLPTR:        return "NULL pointer";
        case DMERR_NOT_SUPPORTED:  return "Operation not supported";
        case DMERR_OUT_OF_DATA:    return "Out of data";
        case DMERR_EXTRA_DATA:     return "Extra data";
        case DMERR_BOUNDS:         return "Bounds check failed";

        case DMERR_DATA_ERROR:     return "Data decoding/encoding/parsing error";

        case DMERR_VERSION:        return "Unsupported file format version";

        case DMERR_NOTPACK:        return "File is not a PACK";
        case DMERR_PACK_VERSION:   return "Unsupported PACK version";
        case DMERR_INVALID:        return "Invalid data, corrupted file";
        case DMERR_COMPRESSION:    return "Error in compression";

        default:                   return "Unknown error";
    }
}


int dmErrorVA(const int error, const char *fmt, va_list ap)
{
    if (dmProgName != NULL)
        fprintf(stderr, "%s: ", dmProgName);

    vfprintf(stderr, fmt, ap);
    return error;
}


int dmError(const int error, const char *fmt, ...)
{
    int ret;
    va_list ap;

    va_start(ap, fmt);
    ret = dmErrorVA(error, fmt, ap);
    va_end(ap);
    return ret;
}


void dmErrorMsg(const char *fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);
    dmErrorVA(DMERR_INTERNAL, fmt, ap);
    va_end(ap);
}


/*
 * Mutex debugging
 */
#ifdef DM_MUTEX_DEBUG

static DMMutexLock * dmGetMutexThreadIDLock(DMMutex *mutex)
{
    Uint32 id = SDL_ThreadID();
    int i;
    for (i = 0; i < 8; i++)
    {
        DMMutexLock *lock = &(mutex->locks[i]);
        if (lock->used && lock->id == id)
            return lock;
    }
    return NULL;
}

static void dmPrintMutexLocks(DMMutex *mutex, const char *state, const char *file, const int line)
{
    int i;

    fprintf(stderr,
    "----------------------\n"
    "%s --> %p @ %s:%d\n"
    "Current thread: %d\n"
    "Mutex         : %p (created @ %s:%d)\n",
    state, mutex, file, line,
    SDL_ThreadID(), mutex, mutex->cr_file, mutex->cr_line);

    for (i = 0; i < 8; i++)
    {
        DMMutexLock *lock = &(mutex->locks[i]);
        if (lock->used)
        {
            fprintf(stderr,
            "Lock #%d: thread=%d, state=%d\n",
            i, lock->id, lock->state);
        }
    }
}

int dmDOMutexLock(DMMutex *mutex, const char *file, const int line)
{
    if (mutex != NULL)
    {
        dmPrintMutexLocks(mutex, "LOCKING", file, line);

        DMMutexLock *lock = dmGetMutexThreadIDLock(mutex);
        if (lock != NULL)
        {
            int res;
            if (lock->state == 0)
                res = SDL_mutexP(mutex->m);
            else
                res = 1;
            lock->state++;
            fprintf(stderr, "LOCKING %p @ thread=%d done [1].\n", mutex, SDL_ThreadID());
            return res;
        }
        else
        {
            int i;
            for (i = 0; i < 8; i++)
            {
                DMMutexLock *lock = &(mutex->locks[i]);
                if (!lock->used)
                {
                    int res;
                    lock->used = TRUE;
                    lock->id = SDL_ThreadID();
                    lock->state++;
                    res = SDL_mutexP(mutex->m);
                    fprintf(stderr, "LOCKING %p @ thread=%d done [2].\n", mutex, SDL_ThreadID());
                    return res;
                }
            }
            return -2;
        }
    }
    return -1;
}


int dmDOMutexUnlock(DMMutex *mutex, const char *file, const int line)
{
    if (mutex != NULL)
    {
        dmPrintMutexLocks(mutex, "UN-LOCKING", file, line);

        DMMutexLock *lock = dmGetMutexThreadIDLock(mutex);
        if (lock != NULL)
        {
            int res;
            lock->state--;
            if (lock->state == 0)
                res = SDL_mutexV(mutex->m);
            else
                res = lock->state;
            return res;
        }
        else
        {
            return -2;
        }
    }
    return -1;
}


DMMutex * dmDOCreateMutex(const char *file, const int line)
{
    DMMutex *mutex = dmMalloc0(sizeof(DMMutex));
    if (mutex == NULL)
        return NULL;
    mutex->cr_file = dm_strdup(file);
    mutex->cr_line = line;
    mutex->m = SDL_CreateMutex();
    return mutex;
}


void dmDestroyMutex(DMMutex *mutex)
{
    if (mutex != NULL)
    {
        SDL_DestroyMutex(mutex->m);
        dmFree(mutex);
    }
}

#endif