Mac and Linux SDL2 binary snapshots
Edward Rudd
2020-05-02 03f8528315fa46c95991a34f3325d7b33ae5538c
source/src/stdlib/SDL_string.c
@@ -1,6 +1,6 @@
/*
  Simple DirectMedia Layer
  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
  Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
  This software is provided 'as-is', without any express or implied
  warranty.  In no event will the authors be held liable for any damages
@@ -18,8 +18,7 @@
     misrepresented as being the original software.
  3. This notice may not be removed or altered from any source distribution.
*/
#if defined(__clang_analyzer__) && !defined(SDL_DISABLE_ANALYZE_MACROS)
#if defined(__clang_analyzer__)
#define SDL_DISABLE_ANALYZE_MACROS 1
#endif
@@ -29,9 +28,10 @@
#include "SDL_stdinc.h"
#if !defined(HAVE_VSSCANF) || !defined(HAVE_STRTOL) || !defined(HAVE_STRTOUL)  || !defined(HAVE_STRTOLL) || !defined(HAVE_STRTOULL) || !defined(HAVE_STRTOD)
#define SDL_isupperhex(X)   (((X) >= 'A') && ((X) <= 'F'))
#define SDL_islowerhex(X)   (((X) >= 'a') && ((X) <= 'f'))
#endif
#define UTF8_IsLeadByte(c) ((c) >= 0xC0 && (c) <= 0xF4)
#define UTF8_IsTrailingByte(c) ((c) >= 0x80 && (c) <= 0xBF)
@@ -78,7 +78,7 @@
        value += v;
        ++text;
    }
    if (valuep) {
    if (valuep && text > textstart) {
        if (negative && value) {
            *valuep = -value;
        } else {
@@ -114,7 +114,7 @@
        value += v;
        ++text;
    }
    if (valuep) {
    if (valuep && text > textstart) {
        *valuep = value;
    }
    return (text - textstart);
@@ -146,7 +146,7 @@
        value += v;
        ++text;
    }
    if (valuep) {
    if (valuep && text > textstart) {
        *valuep = value;
    }
    return (text - textstart);
@@ -183,7 +183,7 @@
        value += v;
        ++text;
    }
    if (valuep) {
    if (valuep && text > textstart) {
        if (negative && value) {
            *valuep = -value;
        } else {
@@ -219,7 +219,7 @@
        value += v;
        ++text;
    }
    if (valuep) {
    if (valuep && text > textstart) {
        *valuep = value;
    }
    return (text - textstart);
@@ -251,7 +251,7 @@
            ++text;
        }
    }
    if (valuep) {
    if (valuep && text > textstart) {
        if (negative && value) {
            *valuep = -value;
        } else {
@@ -271,12 +271,16 @@
    size_t left;
    Uint32 *dstp4;
    Uint8 *dstp1 = (Uint8 *) dst;
    Uint32 value4 = (c | (c << 8) | (c << 16) | (c << 24));
    Uint8 value1 = (Uint8) c;
    Uint8 value1;
    Uint32 value4;
    /* The value used in memset() is a byte, passed as an int */
    c &= 0xff;
    /* The destination pointer needs to be aligned on a 4-byte boundary to
     * execute a 32-bit set. Set first bytes manually if needed until it is
     * aligned. */
    value1 = (Uint8)c;
    while ((intptr_t)dstp1 & 0x3) {
        if (len--) {
            *dstp1++ = value1;
@@ -285,6 +289,7 @@
        }
    }
    value4 = (c | (c << 8) | (c << 16) | (c << 24));
    dstp4 = (Uint32 *) dstp1;
    left = (len % 4);
    len /= 4;
@@ -461,6 +466,66 @@
#endif /* HAVE_WCSLCAT */
}
wchar_t *
SDL_wcsdup(const wchar_t *string)
{
    size_t len = ((SDL_wcslen(string) + 1) * sizeof(wchar_t));
    wchar_t *newstr = (wchar_t *)SDL_malloc(len);
    if (newstr) {
        SDL_memcpy(newstr, string, len);
    }
    return newstr;
}
wchar_t *
SDL_wcsstr(const wchar_t *haystack, const wchar_t *needle)
{
#if defined(HAVE_WCSSTR)
    return SDL_const_cast(wchar_t*,wcsstr(haystack, needle));
#else
    size_t length = SDL_wcslen(needle);
    while (*haystack) {
        if (SDL_wcsncmp(haystack, needle, length) == 0) {
            return (wchar_t *)haystack;
        }
        ++haystack;
    }
    return NULL;
#endif /* HAVE_WCSSTR */
}
int
SDL_wcscmp(const wchar_t *str1, const wchar_t *str2)
{
#if defined(HAVE_WCSCMP)
    return wcscmp(str1, str2);
#else
    while (*str1 && *str2) {
        if (*str1 != *str2)
            break;
        ++str1;
        ++str2;
    }
    return (int)(*str1 - *str2);
#endif /* HAVE_WCSCMP */
}
int
SDL_wcsncmp(const wchar_t *str1, const wchar_t *str2, size_t maxlen)
{
#if defined(HAVE_WCSNCMP)
    return wcsncmp(str1, str2, maxlen);
#else
    while (*str1 && *str2) {
        if (*str1 != *str2)
            break;
        ++str1;
        ++str2;
    }
    return (int)(*str1 - *str2);
#endif /* HAVE_WCSNCMP */
}
size_t
SDL_strlcpy(SDL_OUT_Z_CAP(maxlen) char *dst, const char *src, size_t maxlen)
{
@@ -477,7 +542,8 @@
#endif /* HAVE_STRLCPY */
}
size_t SDL_utf8strlcpy(SDL_OUT_Z_CAP(dst_bytes) char *dst, const char *src, size_t dst_bytes)
size_t
SDL_utf8strlcpy(SDL_OUT_Z_CAP(dst_bytes) char *dst, const char *src, size_t dst_bytes)
{
    size_t src_bytes = SDL_strlen(src);
    size_t bytes = SDL_min(src_bytes, dst_bytes - 1);
@@ -510,6 +576,23 @@
}
size_t
SDL_utf8strlen(const char *str)
{
    size_t retval = 0;
    const char *p = str;
    char ch;
    while ((ch = *(p++)) != 0) {
        /* if top two bits are 1 and 0, it's a continuation byte. */
        if ((ch & 0xc0) != 0x80) {
            retval++;
        }
    }
    return retval;
}
size_t
SDL_strlcat(SDL_INOUT_Z_CAP(maxlen) char *dst, const char *src, size_t maxlen)
{
#if defined(HAVE_STRLCAT)
@@ -527,16 +610,12 @@
char *
SDL_strdup(const char *string)
{
#if defined(HAVE_STRDUP)
    return strdup(string);
#else
    size_t len = SDL_strlen(string) + 1;
    char *newstr = SDL_malloc(len);
    char *newstr = (char *)SDL_malloc(len);
    if (newstr) {
        SDL_strlcpy(newstr, string, len);
        SDL_memcpy(newstr, string, len);
    }
    return newstr;
#endif /* HAVE_STRDUP */
}
char *
@@ -772,7 +851,7 @@
double SDL_atof(const char *string)
{
#ifdef HAVE_ATOF
    return (double) atof(string);
    return atof(string);
#else
    return SDL_strtod(string, NULL);
#endif /* HAVE_ATOF */
@@ -785,7 +864,7 @@
    return strtol(string, endp, base);
#else
    size_t len;
    long value;
    long value = 0;
    if (!base) {
        if ((SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0)) {
@@ -810,7 +889,7 @@
    return strtoul(string, endp, base);
#else
    size_t len;
    unsigned long value;
    unsigned long value = 0;
    if (!base) {
        if ((SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0)) {
@@ -835,7 +914,7 @@
    return strtoll(string, endp, base);
#else
    size_t len;
    Sint64 value;
    Sint64 value = 0;
    if (!base) {
        if ((SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0)) {
@@ -860,7 +939,7 @@
    return strtoull(string, endp, base);
#else
    size_t len;
    Uint64 value;
    Uint64 value = 0;
    if (!base) {
        if ((SDL_strlen(string) > 2) && (SDL_strncmp(string, "0x", 2) == 0)) {
@@ -885,7 +964,7 @@
    return strtod(string, endp);
#else
    size_t len;
    double value;
    double value = 0.0;
    len = SDL_ScanFloat(string, &value);
    if (endp) {
@@ -907,7 +986,7 @@
        ++str1;
        ++str2;
    }
    return (int) ((unsigned char) *str1 - (unsigned char) *str2);
    return (int)((unsigned char) *str1 - (unsigned char) *str2);
#endif /* HAVE_STRCMP */
}
@@ -1007,6 +1086,10 @@
{
    int retval = 0;
    if (!text || !*text) {
        return -1;
    }
    while (*fmt) {
        if (*fmt == ' ') {
            while (SDL_isspace((unsigned char) *text)) {
@@ -1026,6 +1109,7 @@
                DO_LONG,
                DO_LONGLONG
            } inttype = DO_INT;
            size_t advance;
            SDL_bool suppress = SDL_FALSE;
            ++fmt;
@@ -1105,16 +1189,18 @@
                case 'd':
                    if (inttype == DO_LONGLONG) {
                        Sint64 value;
                        text += SDL_ScanLongLong(text, radix, &value);
                        if (!suppress) {
                        advance = SDL_ScanLongLong(text, radix, &value);
                        text += advance;
                        if (advance && !suppress) {
                            Sint64 *valuep = va_arg(ap, Sint64 *);
                            *valuep = value;
                            ++retval;
                        }
                    } else {
                        long value;
                        text += SDL_ScanLong(text, radix, &value);
                        if (!suppress) {
                        advance = SDL_ScanLong(text, radix, &value);
                        text += advance;
                        if (advance && !suppress) {
                            switch (inttype) {
                            case DO_SHORT:
                                {
@@ -1156,17 +1242,19 @@
                    /* Fall through to unsigned handling */
                case 'u':
                    if (inttype == DO_LONGLONG) {
                        Uint64 value;
                        text += SDL_ScanUnsignedLongLong(text, radix, &value);
                        if (!suppress) {
                        Uint64 value = 0;
                        advance = SDL_ScanUnsignedLongLong(text, radix, &value);
                        text += advance;
                        if (advance && !suppress) {
                            Uint64 *valuep = va_arg(ap, Uint64 *);
                            *valuep = value;
                            ++retval;
                        }
                    } else {
                        unsigned long value;
                        text += SDL_ScanUnsignedLong(text, radix, &value);
                        if (!suppress) {
                        unsigned long value = 0;
                        advance = SDL_ScanUnsignedLong(text, radix, &value);
                        text += advance;
                        if (advance && !suppress) {
                            switch (inttype) {
                            case DO_SHORT:
                                {
@@ -1197,9 +1285,10 @@
                    break;
                case 'p':
                    {
                        uintptr_t value;
                        text += SDL_ScanUintPtrT(text, 16, &value);
                        if (!suppress) {
                        uintptr_t value = 0;
                        advance = SDL_ScanUintPtrT(text, 16, &value);
                        text += advance;
                        if (advance && !suppress) {
                            void **valuep = va_arg(ap, void **);
                            *valuep = (void *) value;
                            ++retval;
@@ -1210,8 +1299,9 @@
                case 'f':
                    {
                        double value;
                        text += SDL_ScanFloat(text, &value);
                        if (!suppress) {
                        advance = SDL_ScanFloat(text, &value);
                        text += advance;
                        if (advance && !suppress) {
                            float *valuep = va_arg(ap, float *);
                            *valuep = (float) value;
                            ++retval;
@@ -1278,7 +1368,18 @@
    return retval;
}
#ifdef HAVE_VSNPRINTF
#if defined(HAVE_LIBC) && defined(__WATCOMC__)
/* _vsnprintf() doesn't ensure nul termination */
int SDL_vsnprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, const char *fmt, va_list ap)
{
    int retval;
    if (!fmt) fmt = "";
    retval = _vsnprintf(text, maxlen, fmt, ap);
    if (maxlen > 0) text[maxlen-1] = '\0';
    if (retval < 0) retval = (int) maxlen;
    return retval;
}
#elif defined(HAVE_VSNPRINTF)
int SDL_vsnprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, const char *fmt, va_list ap)
{
    if (!fmt) {
@@ -1297,9 +1398,9 @@
typedef struct
{
    SDL_bool left_justify;
    SDL_bool left_justify; /* for now: ignored. */
    SDL_bool force_sign;
    SDL_bool force_type;
    SDL_bool force_type;   /* for now: used only by float printer, ignored otherwise. */
    SDL_bool pad_zeroes;
    SDL_letter_case force_case;
    int width;
@@ -1311,20 +1412,39 @@
SDL_PrintString(char *text, size_t maxlen, SDL_FormatInfo *info, const char *string)
{
    size_t length = 0;
    size_t slen, sz;
    if (info && info->width && (size_t)info->width > SDL_strlen(string)) {
        char fill = info->pad_zeroes ? '0' : ' ';
        size_t width = info->width - SDL_strlen(string);
        while (width-- > 0 && maxlen > 0) {
            *text++ = fill;
            ++length;
            --maxlen;
        }
    if (string == NULL) {
        string = "(null)";
    }
    length += SDL_strlcpy(text, string, maxlen);
    sz = SDL_strlen(string);
    if (info && info->width > 0 && (size_t)info->width > sz) {
        const char fill = info->pad_zeroes ? '0' : ' ';
        size_t width = info->width - sz;
        size_t filllen;
        if (info->precision >= 0 && (size_t)info->precision < sz)
            width += sz - (size_t)info->precision;
        filllen = SDL_min(width, maxlen);
        SDL_memset(text, fill, filllen);
        text += filllen;
        length += filllen;
        maxlen -= filllen;
    }
    slen = SDL_strlcpy(text, string, maxlen);
    length += SDL_min(slen, maxlen);
    if (info) {
        if (info->precision >= 0 && (size_t)info->precision < sz) {
            slen = (size_t)info->precision;
            if (slen < maxlen) {
                text[slen] = 0;
                length -= (sz - slen);
            }
        }
        if (info->force_case == SDL_CASE_LOWER) {
            SDL_strlwr(text);
        } else if (info->force_case == SDL_CASE_UPPER) {
@@ -1334,12 +1454,54 @@
    return length;
}
static void
SDL_IntPrecisionAdjust(char *num, size_t maxlen, SDL_FormatInfo *info)
{/* left-pad num with zeroes. */
    size_t sz, pad, have_sign;
    if (!info)
        return;
    have_sign = 0;
    if (*num == '-' || *num == '+') {
        have_sign = 1;
        ++num;
        --maxlen;
    }
    sz = SDL_strlen(num);
    if (info->precision > 0 && sz < (size_t)info->precision) {
        pad = (size_t)info->precision - sz;
        if (pad + sz + 1 <= maxlen) { /* otherwise ignore the precision */
            SDL_memmove(num + pad, num, sz + 1);
            SDL_memset(num, '0', pad);
        }
    }
    info->precision = -1;/* so that SDL_PrintString() doesn't make a mess. */
    if (info->pad_zeroes && info->width > 0 && (size_t)info->width > sz + have_sign) {
    /* handle here: spaces are added before the sign
       but zeroes must be placed _after_ the sign. */
    /* sz hasn't changed: we ignore pad_zeroes if a precision is given. */
        pad = (size_t)info->width - sz - have_sign;
        if (pad + sz + 1 <= maxlen) {
            SDL_memmove(num + pad, num, sz + 1);
            SDL_memset(num, '0', pad);
        }
        info->width = 0; /* so that SDL_PrintString() doesn't make a mess. */
    }
}
static size_t
SDL_PrintLong(char *text, size_t maxlen, SDL_FormatInfo *info, long value)
{
    char num[130];
    char num[130], *p = num;
    SDL_ltoa(value, num, info ? info->radix : 10);
    if (info->force_sign && value >= 0L) {
        *p++ = '+';
    }
    SDL_ltoa(value, p, info ? info->radix : 10);
    SDL_IntPrecisionAdjust(num, maxlen, info);
    return SDL_PrintString(text, maxlen, info, num);
}
@@ -1349,15 +1511,21 @@
    char num[130];
    SDL_ultoa(value, num, info ? info->radix : 10);
    SDL_IntPrecisionAdjust(num, maxlen, info);
    return SDL_PrintString(text, maxlen, info, num);
}
static size_t
SDL_PrintLongLong(char *text, size_t maxlen, SDL_FormatInfo *info, Sint64 value)
{
    char num[130];
    char num[130], *p = num;
    SDL_lltoa(value, num, info ? info->radix : 10);
    if (info->force_sign && value >= (Sint64)0) {
        *p++ = '+';
    }
    SDL_lltoa(value, p, info ? info->radix : 10);
    SDL_IntPrecisionAdjust(num, maxlen, info);
    return SDL_PrintString(text, maxlen, info, num);
}
@@ -1367,6 +1535,7 @@
    char num[130];
    SDL_ulltoa(value, num, info ? info->radix : 10);
    SDL_IntPrecisionAdjust(num, maxlen, info);
    return SDL_PrintString(text, maxlen, info, num);
}
@@ -1398,10 +1567,11 @@
        }
        value = (unsigned long) arg;
        len = SDL_PrintUnsignedLong(text, left, NULL, value);
        text += len;
        if (len >= left) {
            text += (left > 1) ? left - 1 : 0;
            left = SDL_min(left, 1);
        } else {
            text += len;
            left -= len;
        }
        arg -= value;
@@ -1418,10 +1588,11 @@
            while (info->precision-- > 0) {
                value = (unsigned long) (arg * mult);
                len = SDL_PrintUnsignedLong(text, left, NULL, value);
                text += len;
                if (len >= left) {
                    text += (left > 1) ? left - 1 : 0;
                    left = SDL_min(left, 1);
                } else {
                    text += len;
                    left -= len;
                }
                arg -= (double) value / mult;
@@ -1445,7 +1616,7 @@
    width = info->width - (int)(text - textstart);
    if (width > 0) {
        char fill = info->pad_zeroes ? '0' : ' ';
        const char fill = info->pad_zeroes ? '0' : ' ';
        char *end = text+left-1;
        len = (text - textstart);
        for (len = (text - textstart); len--; ) {
@@ -1454,16 +1625,17 @@
            }
        }
        len = (size_t)width;
        text += len;
        if (len >= left) {
            text += (left > 1) ? left - 1 : 0;
            left = SDL_min(left, 1);
        } else {
            text += len;
            left -= len;
        }
        while (len--) {
            if (textstart+len < end) {
                textstart[len] = fill;
            }
        if (end != textstart) {
            const size_t filllen = SDL_min(len, ((size_t) (end - textstart)) - 1);
            SDL_memset(textstart, fill, filllen);
        }
    }
@@ -1479,7 +1651,7 @@
    if (!fmt) {
        fmt = "";
    }
    while (*fmt) {
    while (*fmt && left > 1) {
        if (*fmt == '%') {
            SDL_bool done = SDL_FALSE;
            size_t len = 0;
@@ -1521,12 +1693,22 @@
            if (*fmt >= '0' && *fmt <= '9') {
                info.width = SDL_strtol(fmt, (char **)&fmt, 0);
            }
            else if (*fmt == '*') {
                ++fmt;
                info.width = va_arg(ap, int);
            }
            if (*fmt == '.') {
                ++fmt;
                if (*fmt >= '0' && *fmt <= '9') {
                    info.precision = SDL_strtol(fmt, (char **)&fmt, 0);
                } else if (*fmt == '*') {
                    ++fmt;
                    info.precision = va_arg(ap, int);
                } else {
                    info.precision = 0;
                }
                if (info.precision < 0) {
                    info.precision = 0;
                }
            }
@@ -1564,6 +1746,9 @@
                    break;
                case 'i':
                case 'd':
                    if (info.precision >= 0) {
                        info.pad_zeroes = SDL_FALSE;
                    }
                    switch (inttype) {
                    case DO_INT:
                        len = SDL_PrintLong(text, left, &info,
@@ -1601,7 +1786,10 @@
                    }
                    /* Fall through to unsigned handling */
                case 'u':
                    info.pad_zeroes = SDL_TRUE;
                    info.force_sign = SDL_FALSE;
                    if (info.precision >= 0) {
                        info.pad_zeroes = SDL_FALSE;
                    }
                    switch (inttype) {
                    case DO_INT:
                        len = SDL_PrintUnsignedLong(text, left, &info,
@@ -1623,7 +1811,19 @@
                    len = SDL_PrintFloat(text, left, &info, va_arg(ap, double));
                    done = SDL_TRUE;
                    break;
                case 'S':
                    {
                        /* In practice this is used on Windows for WCHAR strings */
                        wchar_t *wide_arg = va_arg(ap, wchar_t *);
                        char *arg = SDL_iconv_string("UTF-8", "UTF-16LE", (char *)(wide_arg), (SDL_wcslen(wide_arg)+1)*sizeof(*wide_arg));
                        info.pad_zeroes = SDL_FALSE;
                        len = SDL_PrintString(text, left, &info, arg);
                        SDL_free(arg);
                        done = SDL_TRUE;
                    }
                    break;
                case 's':
                    info.pad_zeroes = SDL_FALSE;
                    len = SDL_PrintString(text, left, &info, va_arg(ap, char *));
                    done = SDL_TRUE;
                    break;
@@ -1633,19 +1833,16 @@
                }
                ++fmt;
            }
            text += len;
            if (len >= left) {
                text += (left > 1) ? left - 1 : 0;
                left = SDL_min(left, 1);
            } else {
                text += len;
                left -= len;
            }
        } else {
            if (left > 1) {
                *text = *fmt;
                --left;
            }
            ++fmt;
            ++text;
            *text++ = *fmt++;
            --left;
        }
    }
    if (left > 0) {