view dmlib.c @ 510:43ea59887c69

Start work on making C64 formats encoding possible by changing DMDecodeOps to DMEncDecOps and adding fields and op enums for custom encode functions, renaming, etc. Split generic op sanity checking into a separate function in preparation for its use in generic encoding function.
author Matti Hamalainen <ccr@tnsp.org>
date Mon, 19 Nov 2012 15:06:01 +0200
parents dd9809a93425
children 3c5ebe88e52f
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;

    if (author)
        dmProgAuthor = author;
    else
        dmProgAuthor = DM_PROG_AUTHOR;

    if (license)
        dmProgLicense = license;
    else
        dmProgLicense = DM_PROG_LICENSE;

}


void dmPrintBanner(FILE *outFile, const char *name, const char *usage)
{
    fprintf(outFile,
            "\n%s v%s (%s)\n"
            "%s\n"
            "%s\n"
            "Usage: %s %s\n",
            dmProgName, dmProgVersion, dmProgDesc,
            dmProgAuthor, dmProgLicense, 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 dmErrorVA(const char *fmt, va_list ap)
{
    fprintf(stderr, "%s: ", dmProgName);
    vfprintf(stderr, fmt, ap);
}


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

    va_start(ap, fmt);
    dmErrorVA(fmt, ap);
    va_end(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 l)
{
    return malloc(l);
}


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


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


void *dmRealloc(void *p, size_t l)
{
    return realloc(p, l);
}


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


BOOL dmGetIntVal(const char *s, int *i)
{
    if (s[0] == '$')
    {
        if (sscanf(&s[1], "%x", i) < 1)
            return FALSE;
    }
    else if (s[0] == '0' && s[1] == 'x')
    {
        if (sscanf(&s[2], "%x", i) < 1)
            return FALSE;
    }
    else
    {
        if (sscanf(s, "%u", i) < 1)
            return FALSE;
    }
    return TRUE;
}


/* Error handling
 */
#define DM_SYSTEM_ERRORS 100000

int dmGetErrno()
{
    return DM_SYSTEM_ERRORS + errno;
}


const char *dmErrorStr(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_NOTPACK:        return "File is not a PACK";
        case DMERR_VERSION:        return "Unsupported PACK version";
        case DMERR_INVALID:        return "Invalid data, corrupted file";
        case DMERR_COMPRESSION:    return "Error in compression";

        default:                   return "Unknown error";
    }
}


#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