#include <string.h>

#define SDL_isupperhex(X)   (((X) >= 'A') && ((X) <= 'F'))
#define SDL_islowerhex(X)   (((X) >= 'a') && ((X) <= 'f'))

typedef unsigned long long Uint64;

void * _System SDL_revcpy(void *dst, const void *src, size_t len)
{
    char *srcp = (char *)src;
    char *dstp = (char *)dst;
    srcp += len-1;
    dstp += len-1;
    while ( len-- ) {
        *dstp-- = *srcp--;
    }
    return dst;
}

static size_t SDL_ScanUnsignedLong(const char *text, int radix, unsigned long *valuep)
{
    const char *textstart = text;
    unsigned long value = 0;

    if ( radix == 16 && strncmp(text, "0x", 2) == 0 ) {
        text += 2;
    }
    for ( ; ; ) {
        int v;
        if ( isdigit((unsigned char) *text) ) {
            v = *text - '0';
        } else if ( radix == 16 && SDL_isupperhex(*text) ) {
            v = 10 + (*text - 'A');
        } else if ( radix == 16 && SDL_islowerhex(*text) ) {
            v = 10 + (*text - 'a');
        } else {
            break;
        }
        value *= radix;
        value += v;
        ++text;
    }
    if ( valuep ) {
        *valuep = value;
    }
    return (text - textstart);
}

static size_t SDL_ScanUnsignedLongLong(const char *text, int radix, Uint64 *valuep)
{
    const char *textstart = text;
    Uint64 value = 0;

    if ( radix == 16 && strncmp(text, "0x", 2) == 0 ) {
        text += 2;
    }
    for ( ; ; ) {
        int v;
        if ( isdigit((unsigned char) *text) ) {
            v = *text - '0';
        } else if ( radix == 16 && SDL_isupperhex(*text) ) {
            v = 10 + (*text - 'A');
        } else if ( radix == 16 && SDL_islowerhex(*text) ) {
            v = 10 + (*text - 'a');
        } else {
            break;
        }
        value *= radix;
        value += v;
        ++text;
    }
    if ( valuep ) {
        *valuep = value;
    }
    return (text - textstart);
}

unsigned long _System SDL_strtoul(const char *string, char **endp, int base)
{
    size_t len;
    unsigned long value;

    if ( !base ) {
        if ( (strlen(string) > 2) && (strncmp(string, "0x", 2) == 0) ) {
            base = 16;
        } else {
            base = 10;
        }
    }

    len = SDL_ScanUnsignedLong(string, base, &value);
    if ( endp ) {
        *endp = (char *)string + len;
    }
    return value;
}

Uint64 _System SDL_strtoull(const char *string, char **endp, int base)
{
    size_t len;
    Uint64 value;

    if ( !base ) {
        if ( (strlen(string) > 2) && (strncmp(string, "0x", 2) == 0) ) {
            base = 16;
        } else {
            base = 10;
        }
    }

    len = SDL_ScanUnsignedLongLong(string, base, &value);
    if ( endp ) {
        *endp = (char *)string + len;
    }
    return value;
}

int _System SDL_strncasecmp(const char *str1, const char *str2, size_t maxlen)
{
    char a = 0;
    char b = 0;
    while ( *str1 && *str2 && maxlen ) {
        a = tolower((unsigned char) *str1);
        b = tolower((unsigned char) *str2);
        if ( a != b )
            break;
        ++str1;
        ++str2;
        --maxlen;
    }
    return (int)((unsigned char)a - (unsigned char)b);
}
