view src/dmlib.c @ 2208:90ec1ec89c56

Revamp the palette handling in lib64gfx somewhat, add helper functions to lib64util for handling external palette file options and add support for specifying one of the "internal" palettes or external (.act) palette file to gfxconv and 64vw.
author Matti Hamalainen <ccr@tnsp.org>
date Fri, 14 Jun 2019 05:01:12 +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